bostrat-node 1.8.4 → 1.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +179 -179
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,52 +1,52 @@
1
- var a$=Object.defineProperty;var j=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var Pd=(e,t)=>{for(var n in t)a$(e,n,{get:t[n],enumerable:!0})};import{createHash as i$,randomBytes as c$,timingSafeEqual as l$}from"node:crypto";function Ng(){return c$(32).toString("hex")}function va(e){let t=typeof e=="string"?e.trim():"";return t?i$("sha256").update(t).digest("hex"):null}function Pg(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:l$(Buffer.from(e),Buffer.from(t))}function Sa(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(Dd.set(e,(Dd.get(e)||0)+1),Bd.has(e)&&n-Bd.get(e)<u$)return!1;Bd.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=${Dd.get(e)}${o?` ${o}`:""}`),!0}async function Dg(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 $n,Rn,Dd,Bd,u$,Yo=j(()=>{$n="BOSTRAT_HOOK_TOKEN",Rn="x-bostrat-hook";Dd=new Map,Bd=new Map,u$=6e4});import It from"node:fs/promises";import Bg from"node:os";import St from"node:path";import{execFile as d$}from"node:child_process";import{promisify as f$}from"node:util";function Nc(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function p$(){return process.env.CLAUDE_CONFIG_DIR?St.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):St.join(Bg.homedir(),".claude.json")}function m$(){return process.env.CLAUDE_CONFIG_DIR?St.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):St.join(Bg.homedir(),".claude","settings.json")}async function or(e){if(!e||typeof e!="string")return;let t=St.resolve(e),n=p$(),r=m$(),o={};try{o=JSON.parse(await It.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 It.mkdir(St.dirname(n),{recursive:!0}),await It.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await It.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 "${Rn}: $${$n}" --data-binary @- >/dev/null 2>&1 || true`,u=[{hooks:[{type:"command",command:l}]}];i.hooks=i.hooks||{};for(let f of["SessionStart","UserPromptSubmit","Stop"])i.hooks[f]=u;i.hooks.PostToolUse=[{matcher:"*",hooks:[{type:"command",command:l}]}]}await It.mkdir(St.dirname(r),{recursive:!0}),await It.writeFile(r,JSON.stringify(i,null,2)),await h$(t)}async function h$(e){try{let t=St.resolve(e),n=St.join(t,".bostrat","memory","claude"),r=St.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await It.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(St.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await It.mkdir(n,{recursive:!0}),await It.mkdir(St.dirname(r),{recursive:!0}),await It.writeFile(r,JSON.stringify(o,null,2)),await w$(t,["/.claude/settings.local.json"])}catch{}}async function w$(e,t){try{let{stdout:n}=await f$(d$)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=St.resolve(e,n.trim()),o=await It.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
1
+ var c$=Object.defineProperty;var L=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var Bd=(e,t)=>{for(var n in t)c$(e,n,{get:t[n],enumerable:!0})};import{createHash as l$,randomBytes as u$,timingSafeEqual as d$}from"node:crypto";function Pg(){return u$(32).toString("hex")}function Sa(e){let t=typeof e=="string"?e.trim():"";return t?l$("sha256").update(t).digest("hex"):null}function Dg(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:d$(Buffer.from(e),Buffer.from(t))}function Ta(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(jd.set(e,(jd.get(e)||0)+1),Ld.has(e)&&n-Ld.get(e)<f$)return!1;Ld.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=${jd.get(e)}${o?` ${o}`:""}`),!0}async function Bg(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 $n,Rn,jd,Ld,f$,Yo=L(()=>{$n="BOSTRAT_HOOK_TOKEN",Rn="x-bostrat-hook";jd=new Map,Ld=new Map,f$=6e4});import It from"node:fs/promises";import jg from"node:os";import St from"node:path";import{execFile as p$}from"node:child_process";import{promisify as m$}from"node:util";function Dc(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function h$(){return process.env.CLAUDE_CONFIG_DIR?St.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):St.join(jg.homedir(),".claude.json")}function w$(){return process.env.CLAUDE_CONFIG_DIR?St.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):St.join(jg.homedir(),".claude","settings.json")}async function sr(e){if(!e||typeof e!="string")return;let t=St.resolve(e),n=h$(),r=w$(),o={};try{o=JSON.parse(await It.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 It.mkdir(St.dirname(n),{recursive:!0}),await It.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await It.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 "${Rn}: $${$n}" --data-binary @- >/dev/null 2>&1 || true`,u=[{hooks:[{type:"command",command:l}]}];i.hooks=i.hooks||{};for(let f of["SessionStart","UserPromptSubmit","Stop"])i.hooks[f]=u;i.hooks.PostToolUse=[{matcher:"*",hooks:[{type:"command",command:l}]}]}await It.mkdir(St.dirname(r),{recursive:!0}),await It.writeFile(r,JSON.stringify(i,null,2)),await g$(t)}async function g$(e){try{let t=St.resolve(e),n=St.join(t,".bostrat","memory","claude"),r=St.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await It.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(St.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await It.mkdir(n,{recursive:!0}),await It.mkdir(St.dirname(r),{recursive:!0}),await It.writeFile(r,JSON.stringify(o,null,2)),await y$(t,["/.claude/settings.local.json"])}catch{}}async function y$(e,t){try{let{stdout:n}=await m$(p$)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=St.resolve(e,n.trim()),o=await It.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
2
2
  `).includes(a));if(!s.length)return;await It.mkdir(St.dirname(r),{recursive:!0}),await It.appendFile(r,(o&&!o.endsWith(`
3
3
  `)?`
4
4
  `:"")+s.join(`
5
5
  `)+`
6
- `)}catch{}}var Ta=j(()=>{Yo()});import jd from"node:fs/promises";import g$ from"node:os";import Pc from"node:path";function y$(){let e=process.env.CODEX_HOME||Pc.join(g$.homedir(),".codex");return Pc.join(e,"config.toml")}function jg(e){return`[projects."${e}"]`}function b$(e,t){let n=jg(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 Jo(e){if(!e||typeof e!="string")return;let t=Pc.resolve(e),n=y$(),r="";try{r=await jd.readFile(n,"utf8")}catch{}if(b$(r,t))return;let o=jg(t);if(r.includes(o)){let a=r.indexOf(o)+o.length,c=r.slice(a).search(/^\s*\[/m),l=c===-1?r.length:a+c,u=r.slice(a,l),f=/trust_level\s*=/.test(u)?u.replace(/trust_level\s*=\s*"[^"]*"/,'trust_level = "trusted"'):`${u.replace(/\s*$/,"")}
6
+ `)}catch{}}var Ea=L(()=>{Yo()});import Fd from"node:fs/promises";import b$ from"node:os";import Bc from"node:path";function k$(){let e=process.env.CODEX_HOME||Bc.join(b$.homedir(),".codex");return Bc.join(e,"config.toml")}function Lg(e){return`[projects."${e}"]`}function x$(e,t){let n=Lg(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 Jo(e){if(!e||typeof e!="string")return;let t=Bc.resolve(e),n=k$(),r="";try{r=await Fd.readFile(n,"utf8")}catch{}if(x$(r,t))return;let o=Lg(t);if(r.includes(o)){let a=r.indexOf(o)+o.length,c=r.slice(a).search(/^\s*\[/m),l=c===-1?r.length:a+c,u=r.slice(a,l),f=/trust_level\s*=/.test(u)?u.replace(/trust_level\s*=\s*"[^"]*"/,'trust_level = "trusted"'):`${u.replace(/\s*$/,"")}
7
7
  trust_level = "trusted"
8
8
  `;r=r.slice(0,a)+f+r.slice(l)}else{let s=`
9
9
  ${o}
10
10
  trust_level = "trusted"
11
11
  `;r=r.trimEnd()+s+(r.length&&!r.endsWith(`
12
12
  `)?`
13
- `:"")}try{await jd.mkdir(Pc.dirname(n),{recursive:!0}),await jd.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var Dc=j(()=>{});import Lg from"node:fs/promises";import k$ from"node:os";import Ea from"node:path";function x$(e){let n=Ea.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||Ea.join(k$.homedir(),".cursor");return Ea.join(r,"projects",n)}async function Xo(e){if(!e||typeof e!="string")return;let t=Ea.resolve(e),n=x$(t),r=Ea.join(n,".workspace-trusted");await Lg.mkdir(n,{recursive:!0}),await Lg.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
14
- `,"utf8")}var Bc=j(()=>{});import Fd from"node:fs/promises";import sr from"node:path";import{execFile as v$}from"node:child_process";import{promisify as S$}from"node:util";async function $$(e){try{return(await Fd.stat(sr.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function R$(e){let t=i=>Fd.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 On(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await $$(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:sr.basename(o),branch:await R$(o)});return}if(s>=_$)return;let i;try{i=await Fd.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||I$.has(c.name)||await t(sr.join(o,c.name),s+1)}for(let o of A$)await t(sr.resolve(o),0);let n=new Set,r=[];for(let o of e.values()){let s=(await Se(o.path))?.toLowerCase();if(s){if(n.has(s))continue;n.add(s)}r.push(o)}return r.sort((o,s)=>o.name.localeCompare(s.name))}function O$(e){let t=String(e||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return t?`${t[1]}/${t[2]}`:null}async function Se(e){if(!e)return null;if(Ld.has(e))return Ld.get(e);let t=null;try{let{stdout:n}=await T$("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=O$(n)}catch{t=null}return Ld.set(e,t),t}async function Zo(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await On())if((await Se(n.path))?.toLowerCase()===t)return n.path;return null}var T$,Fg,E$,A$,_$,I$,Ld,ar=j(()=>{T$=S$(v$),Fg=process.env.HOME||"/home/globo",E$=sr.join(process.env.BOSTRAT_STATE_DIR||sr.join(Fg,".bostrat"),"repos"),A$=[...(process.env.BOSTRAT_REPOS_ROOT||sr.join(Fg,"Documents")).split(","),E$].map(e=>e.trim()).filter(Boolean),_$=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,I$=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);Ld=new Map});import C$ from"node:fs";import Ug from"node:fs/promises";import Aa from"node:path";import M$ from"node:os";import{fileURLToPath as N$}from"node:url";import{execFile as P$}from"node:child_process";import{promisify as D$}from"node:util";function Ie(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 jc(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Lc(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!Wg.test(n))throw Qo("repo must be owner/name",400);let r=Ud.get(n);if(r&&r.expiresAt-Date.now()>L$)return r;if(!jc(t))throw Qo("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await qg(`${Ie(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:Kg(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw Qo(`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 Qo(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 Ud.set(n,a),a}async function _a({env:e=process.env,force:t=!1}={}){if(!jc(e))return{configured:!1,repos:[],username:null};if(!t&&eo&&Date.now()-eo.at<F$)return eo.data;try{let n=await qg(`${Ie(e)}/v1/github/repos`,{headers:Kg(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 Gg(){Ud.clear(),eo=null}async function ln({cwd:e=null,slug:t=null,env:n=process.env}={}){try{let r=t||(e?await Se(e):null);if(!r)return{};let{token:o}=await Lc(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function Hd({env:e=process.env}={}){return(await _a({env:e})).username??null}function q$(e){let[t,n]=String(e).split("/");return Aa.join(j$,t,n)}async function Wd(e,{env:t=process.env}={}){let n=(...r)=>Hg("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${H$()}" ${W$(t)}`),await n("config","credential.useHttpPath","true")}async function Fc(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!Wg.test(String(e||"")))throw Qo(`bad repo slug "${e}"`,400);let r=q$(e);if(C$.existsSync(Aa.join(r,".git")))return r;let{token:o}=await Lc(e,{env:t});await Ug.mkdir(Aa.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await Hg("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:U$,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await Ug.rm(r,{recursive:!0,force:!0}).catch(()=>{}),Qo(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Wd(r,{env:t}),r}var Hg,B$,j$,Wg,L$,F$,U$,qg,Ud,eo,Kg,Qo,H$,W$,it=j(()=>{ar();Hg=D$(P$),B$=process.env.BOSTRAT_STATE_DIR||Aa.join(process.env.HOME||M$.tmpdir(),".bostrat"),j$=Aa.join(B$,"repos"),Wg=/^[^/\s]+\/[^/\s]+$/,L$=5*6e4,F$=6e4,U$=10*6e4,qg=fetch,Ud=new Map,eo=null;Kg=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),Qo=(e,t)=>Object.assign(new Error(e),{status:t});H$=()=>N$(new URL("../bin/bostrat-git-credential",import.meta.url)),W$=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function zg(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Jg(e,t,n,r=Vg){let o=Ie(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await G$(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function Xg(e,{env:t=process.env,force:n=!1,timeoutMs:r=Vg}={}){if(!zg(t))return{facts:[],source:"unconfigured"};let o=qd.get(e);if(!n&&o&&Date.now()-o.at<K$)return{facts:o.facts,source:"cache"};try{let s=await Jg(`/v1/memory/${encodeURIComponent(e)}`,{headers:Yg(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 qd.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 Uc(e,t,{env:n=process.env}={}){if(!zg(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await Jg(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...Yg(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 qd.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 K$,Vg,qd,G$,Yg,Zg=j(()=>{it();K$=6e4,Vg=5e3,qd=new Map,G$=(...e)=>fetch(...e);Yg=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import Kd from"node:fs/promises";import es from"node:path";import V$ from"node:os";import{EventEmitter as z$}from"node:events";import{randomUUID as Y$}from"node:crypto";function ts(e){return e?.cwd?es.join(e.cwd,".bostrat","events"):es.join(Gd,"events")}async function Q$(e,t){if(!Hc.has(t)){let o=(await F(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);Hc.set(t,o)}let n=Hc.get(t)+1;return Hc.set(t,n),n}function Vd(e,t){let n=Array.isArray(e?.epochs)?e.epochs:null;if(!(!n||n.length===0)){if(!Number.isFinite(t))return n.length-1;for(let r=n.length-1;r>=0;r--){let o=n[r].startedAt;if(o==null||o<=t)return r}return 0}}async function $(e,t){let n=typeof e=="string"?e:e?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!t||!J$.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!X$.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!Z$.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?es.join(Gd,"events"):ts(e),o=t.epoch;if(o==null&&typeof e=="object"&&t.boxId&&Array.isArray(e?.boxes)){let u=e.boxes.find(f=>f.name===t.boxId);o=Vd(u,Number(t.payload?.ts??t.ts)||Date.now())}let s=await Q$(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||Y$(),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 ey(c)&&(c=ty(c),l=JSON.parse(c)),await Kd.mkdir(r,{recursive:!0}),await Kd.appendFile(Qg(r,n),c+`
15
- `),ct.emit("event",l),ct.emit(`track:${n}`,l),l}async function F(e,t){let n,r;typeof e=="string"&&t?(n=e,r=t):(r=typeof e=="string"?e:e?.id,n=typeof e=="string"?es.join(Gd,"events"):ts(e));let o;try{o=await Kd.readFile(Qg(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
16
- `))if(a.trim())try{s.push(JSON.parse(ey(a)?ty(a):a))}catch{}return s}function ny(e,t){let n=`track:${e}`;return ct.on(n,t),()=>ct.off(n,t)}var J$,X$,Z$,ct,Gd,Qg,Hc,eR,ey,ty,me=j(()=>{J$=new Set(["session.ready","turn.user","turn.agent","turn.retracted","peer.message","provider.error","turn.interrupted","tool.called","tool.result","prompt.raised","prompt.answered","prompt.autoRejected","box.fullscreen.detected","box.fullscreen.answered","context.usage","cost.recorded","memory.seed","memory.harvested","handoff.artifact","code.pushed","code.committed","code.rework","rework.cause.offered","rework.cause.answered","handoff.started","handoff.step","handoff.done","handoff.failed","subtask.delegated","subtask.merged","job.started","pr.state.changed","pr.offered","pr.offer.answered","pr.exists.offered","pr.exists.answered","box.state.changed","view.state.changed","view.spinup.failed","mock.state.changed","flow.state.changed","runbook.state.changed","ticket.linked","ticket.sync.failed","ticket.move.offered","ticket.move.answered","ticket.state.changed","ticket.commented","ticket.flow.changed","ticket.create.offered","ticket.create.answered","ticket.created","loop.create.offered","loop.create.answered","loop.created","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","notify.raised","usage.cap.hit","usage.cap.warning","provider.connected","track.summary.recorded","track.transferred","track.recovered","track.circuit.tagged","blueprint.item.bound","decision.recorded","changelog.published","stall.detected","error"]),X$=new Set(["user","agent","orchestrator","system","peer"]),Z$=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor","cli"]),ct=new z$;ct.setMaxListeners(0);Gd=process.env.BOSTRAT_STATE_DIR||es.join(process.env.HOME||V$.tmpdir(),".bostrat");Qg=(e,t)=>es.join(e,`${t}.ndjson`),Hc=new Map;eR=/(?<!\\)((?:\\\\)*)\\u0000/g,ey=e=>e.includes("\\u0000"),ty=e=>e.replace(eR,"$1\\ufffd")});import Y from"node:fs/promises";import tR from"node:os";import we from"node:path";import{execFile as nR}from"node:child_process";import{promisify as rR}from"node:util";function qc(){return we.join(Kc,"memory","repos")}function to(e){return e===Cn?we.join(Kc,"memory",Cn):we.join(qc(),e)}async function $a(e){try{return JSON.parse(await Y.readFile(we.join(e,ly),"utf8"))}catch{return{}}}async function Yd(e,t){let n=await $a(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await Y.mkdir(e,{recursive:!0}),await Y.writeFile(we.join(e,ly),JSON.stringify(n))}function oy(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 sy(e){try{let{stdout:t}=await oR("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function Jd(e){if(!e)return[];let t=oy(await sy(e));if(t)return[t];let n=[],r=[];try{r=await Y.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=oy(await sy(we.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function Gc(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 ir(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function un(e,t=null){let n=t??await Y.readFile(e,"utf8").catch(()=>""),{fm:r}=Gc(n),o=ir(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await Y.stat(e)).mtimeMs}catch{return 0}}function uy(e,t){let n=ir(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===Cn){let o=ir(e,"trust");if(!o||/^operator/i.test(o))return Cn}return t}function Xd(e,t,n,r=new Map){let o=(e||"").split(`
13
+ `:"")}try{await Fd.mkdir(Bc.dirname(n),{recursive:!0}),await Fd.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var jc=L(()=>{});import Fg from"node:fs/promises";import v$ from"node:os";import Aa from"node:path";function S$(e){let n=Aa.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||Aa.join(v$.homedir(),".cursor");return Aa.join(r,"projects",n)}async function Xo(e){if(!e||typeof e!="string")return;let t=Aa.resolve(e),n=S$(t),r=Aa.join(n,".workspace-trusted");await Fg.mkdir(n,{recursive:!0}),await Fg.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
14
+ `,"utf8")}var Lc=L(()=>{});import Hd from"node:fs/promises";import ar from"node:path";import{execFile as T$}from"node:child_process";import{promisify as E$}from"node:util";async function O$(e){try{return(await Hd.stat(ar.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function C$(e){let t=i=>Hd.readFile(ar.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 On(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await O$(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:ar.basename(o),branch:await C$(o)});return}if(s>=$$)return;let i;try{i=await Hd.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||R$.has(c.name)||await t(ar.join(o,c.name),s+1)}for(let o of I$)await t(ar.resolve(o),0);let n=new Set,r=[];for(let o of e.values()){let s=(await Se(o.path))?.toLowerCase();if(s){if(n.has(s))continue;n.add(s)}r.push(o)}return r.sort((o,s)=>o.name.localeCompare(s.name))}function M$(e){let t=String(e||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return t?`${t[1]}/${t[2]}`:null}async function Se(e){if(!e)return null;if(Ud.has(e))return Ud.get(e);let t=null;try{let{stdout:n}=await A$("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=M$(n)}catch{t=null}return Ud.set(e,t),t}async function Zo(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await On())if((await Se(n.path))?.toLowerCase()===t)return n.path;return null}var A$,Ug,_$,I$,$$,R$,Ud,ir=L(()=>{A$=E$(T$),Ug=process.env.HOME||"/home/globo",_$=ar.join(process.env.BOSTRAT_STATE_DIR||ar.join(Ug,".bostrat"),"repos"),I$=[...(process.env.BOSTRAT_REPOS_ROOT||ar.join(Ug,"Documents")).split(","),_$].map(e=>e.trim()).filter(Boolean),$$=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,R$=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);Ud=new Map});import N$ from"node:fs";import Hg from"node:fs/promises";import _a from"node:path";import P$ from"node:os";import{fileURLToPath as D$}from"node:url";import{execFile as B$}from"node:child_process";import{promisify as j$}from"node:util";function Ie(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 Fc(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Uc(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!qg.test(n))throw Qo("repo must be owner/name",400);let r=Wd.get(n);if(r&&r.expiresAt-Date.now()>U$)return r;if(!Fc(t))throw Qo("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await Kg(`${Ie(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:Gg(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw Qo(`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 Qo(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 Wd.set(n,a),a}async function Ia({env:e=process.env,force:t=!1}={}){if(!Fc(e))return{configured:!1,repos:[],username:null};if(!t&&eo&&Date.now()-eo.at<H$)return eo.data;try{let n=await Kg(`${Ie(e)}/v1/github/repos`,{headers:Gg(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 Vg(){Wd.clear(),eo=null}async function ln({cwd:e=null,slug:t=null,env:n=process.env}={}){try{let r=t||(e?await Se(e):null);if(!r)return{};let{token:o}=await Uc(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function qd({env:e=process.env}={}){return(await Ia({env:e})).username??null}function G$(e){let[t,n]=String(e).split("/");return _a.join(F$,t,n)}async function Kd(e,{env:t=process.env}={}){let n=(...r)=>Wg("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${q$()}" ${K$(t)}`),await n("config","credential.useHttpPath","true")}async function Hc(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!qg.test(String(e||"")))throw Qo(`bad repo slug "${e}"`,400);let r=G$(e);if(N$.existsSync(_a.join(r,".git")))return r;let{token:o}=await Uc(e,{env:t});await Hg.mkdir(_a.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await Wg("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:W$,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await Hg.rm(r,{recursive:!0,force:!0}).catch(()=>{}),Qo(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Kd(r,{env:t}),r}var Wg,L$,F$,qg,U$,H$,W$,Kg,Wd,eo,Gg,Qo,q$,K$,it=L(()=>{ir();Wg=j$(B$),L$=process.env.BOSTRAT_STATE_DIR||_a.join(process.env.HOME||P$.tmpdir(),".bostrat"),F$=_a.join(L$,"repos"),qg=/^[^/\s]+\/[^/\s]+$/,U$=5*6e4,H$=6e4,W$=10*6e4,Kg=fetch,Wd=new Map,eo=null;Gg=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),Qo=(e,t)=>Object.assign(new Error(e),{status:t});q$=()=>D$(new URL("../bin/bostrat-git-credential",import.meta.url)),K$=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function Yg(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Xg(e,t,n,r=zg){let o=Ie(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await z$(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function Zg(e,{env:t=process.env,force:n=!1,timeoutMs:r=zg}={}){if(!Yg(t))return{facts:[],source:"unconfigured"};let o=Gd.get(e);if(!n&&o&&Date.now()-o.at<V$)return{facts:o.facts,source:"cache"};try{let s=await Xg(`/v1/memory/${encodeURIComponent(e)}`,{headers:Jg(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 Gd.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 Wc(e,t,{env:n=process.env}={}){if(!Yg(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await Xg(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...Jg(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 Gd.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 V$,zg,Gd,z$,Jg,Qg=L(()=>{it();V$=6e4,zg=5e3,Gd=new Map,z$=(...e)=>fetch(...e);Jg=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import Vd from"node:fs/promises";import es from"node:path";import Y$ from"node:os";import{EventEmitter as J$}from"node:events";import{randomUUID as X$}from"node:crypto";function ts(e){return e?.cwd?es.join(e.cwd,".bostrat","events"):es.join(zd,"events")}async function tR(e,t){if(!qc.has(t)){let o=(await U(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);qc.set(t,o)}let n=qc.get(t)+1;return qc.set(t,n),n}function Yd(e,t){let n=Array.isArray(e?.epochs)?e.epochs:null;if(!(!n||n.length===0)){if(!Number.isFinite(t))return n.length-1;for(let r=n.length-1;r>=0;r--){let o=n[r].startedAt;if(o==null||o<=t)return r}return 0}}async function $(e,t){let n=typeof e=="string"?e:e?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!t||!Z$.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!Q$.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!eR.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?es.join(zd,"events"):ts(e),o=t.epoch;if(o==null&&typeof e=="object"&&t.boxId&&Array.isArray(e?.boxes)){let u=e.boxes.find(f=>f.name===t.boxId);o=Yd(u,Number(t.payload?.ts??t.ts)||Date.now())}let s=await tR(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||X$(),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 ty(c)&&(c=ny(c),l=JSON.parse(c)),await Vd.mkdir(r,{recursive:!0}),await Vd.appendFile(ey(r,n),c+`
15
+ `),ct.emit("event",l),ct.emit(`track:${n}`,l),l}async function U(e,t){let n,r;typeof e=="string"&&t?(n=e,r=t):(r=typeof e=="string"?e:e?.id,n=typeof e=="string"?es.join(zd,"events"):ts(e));let o;try{o=await Vd.readFile(ey(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
16
+ `))if(a.trim())try{s.push(JSON.parse(ty(a)?ny(a):a))}catch{}return s}function ry(e,t){let n=`track:${e}`;return ct.on(n,t),()=>ct.off(n,t)}var Z$,Q$,eR,ct,zd,ey,qc,nR,ty,ny,he=L(()=>{Z$=new Set(["session.ready","turn.user","turn.agent","turn.retracted","peer.message","provider.error","turn.interrupted","tool.called","tool.result","prompt.raised","prompt.answered","prompt.autoRejected","box.fullscreen.detected","box.fullscreen.answered","context.usage","cost.recorded","memory.seed","memory.harvested","handoff.artifact","code.pushed","code.committed","code.rework","rework.cause.offered","rework.cause.answered","handoff.started","handoff.step","handoff.done","handoff.failed","subtask.delegated","subtask.merged","job.started","pr.state.changed","pr.offered","pr.offer.answered","pr.exists.offered","pr.exists.answered","box.state.changed","view.state.changed","view.spinup.failed","mock.state.changed","flow.state.changed","runbook.state.changed","ticket.linked","ticket.sync.failed","ticket.move.offered","ticket.move.answered","ticket.state.changed","ticket.commented","ticket.flow.changed","ticket.create.offered","ticket.create.answered","ticket.created","loop.create.offered","loop.create.answered","loop.created","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","notify.raised","usage.cap.hit","usage.cap.warning","provider.connected","track.summary.recorded","track.transferred","track.recovered","track.circuit.tagged","blueprint.item.bound","decision.recorded","changelog.published","stall.detected","error"]),Q$=new Set(["user","agent","orchestrator","system","peer"]),eR=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor","cli"]),ct=new J$;ct.setMaxListeners(0);zd=process.env.BOSTRAT_STATE_DIR||es.join(process.env.HOME||Y$.tmpdir(),".bostrat");ey=(e,t)=>es.join(e,`${t}.ndjson`),qc=new Map;nR=/(?<!\\)((?:\\\\)*)\\u0000/g,ty=e=>e.includes("\\u0000"),ny=e=>e.replace(nR,"$1\\ufffd")});import X from"node:fs/promises";import rR from"node:os";import ge from"node:path";import{execFile as oR}from"node:child_process";import{promisify as sR}from"node:util";function Gc(){return ge.join(Vc,"memory","repos")}function to(e){return e===Cn?ge.join(Vc,"memory",Cn):ge.join(Gc(),e)}async function Ra(e){try{return JSON.parse(await X.readFile(ge.join(e,uy),"utf8"))}catch{return{}}}async function Xd(e,t){let n=await Ra(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await X.mkdir(e,{recursive:!0}),await X.writeFile(ge.join(e,uy),JSON.stringify(n))}function sy(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 ay(e){try{let{stdout:t}=await aR("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function Zd(e){if(!e)return[];let t=sy(await ay(e));if(t)return[t];let n=[],r=[];try{r=await X.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=sy(await ay(ge.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function zc(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 cr(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function un(e,t=null){let n=t??await X.readFile(e,"utf8").catch(()=>""),{fm:r}=zc(n),o=cr(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await X.stat(e)).mtimeMs}catch{return 0}}function dy(e,t){let n=cr(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===Cn){let o=cr(e,"trust");if(!o||/^operator/i.test(o))return Cn}return t}function Qd(e,t,n,r=new Map){let o=(e||"").split(`
17
17
  `),s=new Map;for(let c of(t||"").split(`
18
18
  `)){let l=rs(c);l&&c.trim().startsWith("-")&&s.set(l,c)}let a=new Set,i=o.map(c=>{let l=rs(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 dy(e,t){let n=ir(t,"name")||e.replace(/\.md$/,""),r=ir(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function Ra(e){let t=[];try{t=await Y.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 fy(e,t){let n=we.join(e,".bostrat","memory"),r=await Ra(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=ay.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let f of r){let d=we.join(n,f);if(o)try{if((await Y.stat(d)).mtimeMs<o-aR)continue}catch{continue}let p;try{p=await Y.readFile(d,"utf8")}catch{continue}let{fm:h}=Gc(p),w=uy(h,t);if(!w)continue;let g=to(w),k=we.join(g,f),S=await un(d,p);if(l.has(g)||l.set(g,await $a(g)),(l.get(g)[f]||0)>=S)continue;let E=await un(k).catch(()=>0);if(await Y.access(k).then(()=>!0).catch(()=>!1)&&E>=S)continue;await Y.mkdir(g,{recursive:!0}),await Y.writeFile(k,p),c++;let B=a.get(g);B||a.set(g,B={won:new Set,generated:new Map}),B.won.add(f),B.generated.set(f,dy(f,h)),i.has(w)||i.set(w,new Set),i.get(w).add(f)}let u=await Y.readFile(we.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[f,d]of a){let p=we.join(f,"MEMORY.md"),h=await Y.readFile(p,"utf8").catch(()=>"");await Y.writeFile(p,Xd(h,u,d.won,d.generated))}return ay.set(e,s),{harvested:c,changedByKey:i}}async function py(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await Y.access(we.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await Jd(r),a=await fy(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 iR(){let e=we.join(Kc,"workspaces"),t=[];try{t=await Y.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return py(t.filter(n=>n.isDirectory()).map(n=>we.join(e,n.name)))}async function uR(e,t){let n=to(e),r=await $a(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!cR.test(l)||l==="MEMORY.md")continue;let u=we.join(n,l),f=await Y.access(u).then(()=>!0).catch(()=>!1),d=f?await un(u):0,p=Number(c.modified)||0;if(c.deleted){p>d&&(f&&await Y.rm(u,{force:!0}),await Yd(n,[[l,p]]),f&&(a.push(l),i++));continue}f&&d>=p||(r[l]||0)>=p||(await Y.mkdir(n,{recursive:!0}),await Y.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=we.join(n,"MEMORY.md"),l=await Y.readFile(c,"utf8").catch(()=>""),u=Xd(l,[...s.values()].join(`
21
+ `)}function fy(e,t){let n=cr(t,"name")||e.replace(/\.md$/,""),r=cr(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function Oa(e){let t=[];try{t=await X.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 py(e,t){let n=ge.join(e,".bostrat","memory"),r=await Oa(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=iy.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let f of r){let d=ge.join(n,f);if(o)try{if((await X.stat(d)).mtimeMs<o-cR)continue}catch{continue}let p;try{p=await X.readFile(d,"utf8")}catch{continue}let{fm:h}=zc(p),w=dy(h,t);if(!w)continue;let g=to(w),b=ge.join(g,f),E=await un(d,p);if(l.has(g)||l.set(g,await Ra(g)),(l.get(g)[f]||0)>=E)continue;let S=await un(b).catch(()=>0);if(await X.access(b).then(()=>!0).catch(()=>!1)&&S>=E)continue;await X.mkdir(g,{recursive:!0}),await X.writeFile(b,p),c++;let M=a.get(g);M||a.set(g,M={won:new Set,generated:new Map}),M.won.add(f),M.generated.set(f,fy(f,h)),i.has(w)||i.set(w,new Set),i.get(w).add(f)}let u=await X.readFile(ge.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[f,d]of a){let p=ge.join(f,"MEMORY.md"),h=await X.readFile(p,"utf8").catch(()=>"");await X.writeFile(p,Qd(h,u,d.won,d.generated))}return iy.set(e,s),{harvested:c,changedByKey:i}}async function my(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await X.access(ge.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await Zd(r),a=await py(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 lR(){let e=ge.join(Vc,"workspaces"),t=[];try{t=await X.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return my(t.filter(n=>n.isDirectory()).map(n=>ge.join(e,n.name)))}async function fR(e,t){let n=to(e),r=await Ra(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!uR.test(l)||l==="MEMORY.md")continue;let u=ge.join(n,l),f=await X.access(u).then(()=>!0).catch(()=>!1),d=f?await un(u):0,p=Number(c.modified)||0;if(c.deleted){p>d&&(f&&await X.rm(u,{force:!0}),await Xd(n,[[l,p]]),f&&(a.push(l),i++));continue}f&&d>=p||(r[l]||0)>=p||(await X.mkdir(n,{recursive:!0}),await X.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=ge.join(n,"MEMORY.md"),l=await X.readFile(c,"utf8").catch(()=>""),u=Qd(l,[...s.values()].join(`
22
22
  `),o);if(a.length){let f=new Set(a);u=u.split(`
23
23
  `).filter(d=>!f.has(rs(d))).join(`
24
- `)}await Y.mkdir(n,{recursive:!0}),await Y.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function Vc(e,t=null){let n=to(e),r=t?.length?t:await Ra(n);if(!r.length)return{pushed:0,source:"empty"};let o=lR(await Y.readFile(we.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=we.join(n,a),c;try{c=await Y.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await un(i,c),indexLine:o.get(a)??null})}return Uc(e,s)}async function dR(e,{timeoutMs:t}={}){let{facts:n,source:r}=await Xg(e,t?{timeoutMs:t}:{});n.length?await uR(e,n):r==="plane"&&await Vc(e)}function fR(e){let t=e.split(`
25
- `);t.length>ry&&(t=t.slice(0,ry));let n=t.join(`
26
- `);for(;Buffer.byteLength(n,"utf8")>sR&&t.length;)t.pop(),n=t.join(`
27
- `);return n}async function mR(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=we.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let f=to(u),d=await $a(f);for(let[g,k]of Object.entries(d)){let S=we.join(n,g);await Y.access(S).then(()=>!0).catch(()=>!1)&&await un(S)<=k&&(await Y.rm(S,{force:!0}),o++)}let p=await Ra(f);if(!p.length)continue;await Y.mkdir(n,{recursive:!0});for(let g of p){let k=we.join(f,g),S=we.join(n,g),E=await un(k),R=await un(S).catch(()=>0);await Y.access(S).then(()=>!0).catch(()=>!1)&&R>=E||(await Y.copyFile(k,S),r++)}let h=await Y.readFile(we.join(f,"MEMORY.md"),"utf8").catch(()=>""),w=u===Cn?"## operator memory":`## repo: ${u}`;h.trim()&&s.push(t.length>1?`${w}
24
+ `)}await X.mkdir(n,{recursive:!0}),await X.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function Yc(e,t=null){let n=to(e),r=t?.length?t:await Oa(n);if(!r.length)return{pushed:0,source:"empty"};let o=dR(await X.readFile(ge.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=ge.join(n,a),c;try{c=await X.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await un(i,c),indexLine:o.get(a)??null})}return Wc(e,s)}async function pR(e,{timeoutMs:t}={}){let{facts:n,source:r}=await Zg(e,t?{timeoutMs:t}:{});n.length?await fR(e,n):r==="plane"&&await Yc(e)}function mR(e){let t=e.split(`
25
+ `);t.length>oy&&(t=t.slice(0,oy));let n=t.join(`
26
+ `);for(;Buffer.byteLength(n,"utf8")>iR&&t.length;)t.pop(),n=t.join(`
27
+ `);return n}async function wR(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=ge.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let f=to(u),d=await Ra(f);for(let[g,b]of Object.entries(d)){let E=ge.join(n,g);await X.access(E).then(()=>!0).catch(()=>!1)&&await un(E)<=b&&(await X.rm(E,{force:!0}),o++)}let p=await Oa(f);if(!p.length)continue;await X.mkdir(n,{recursive:!0});for(let g of p){let b=ge.join(f,g),E=ge.join(n,g),S=await un(b),R=await un(E).catch(()=>0);await X.access(E).then(()=>!0).catch(()=>!1)&&R>=S||(await X.copyFile(b,E),r++)}let h=await X.readFile(ge.join(f,"MEMORY.md"),"utf8").catch(()=>""),w=u===Cn?"## operator memory":`## repo: ${u}`;h.trim()&&s.push(t.length>1?`${w}
28
28
 
29
29
  ${h.trim()}`:h.trim())}if(!s.length)return o?{materialized:!1,reason:"empty-store",cleaned:o}:{materialized:!1,reason:"empty-store"};let i="_Shared Track memory (point-in-time facts). Verify file/line citations against the current code before acting on them; correct a wrong fact in place (bump `modified`, use `supersedes`) rather than working around it._\n\n"+s.join(`
30
30
 
31
31
  `)+`
32
- `,c=fR(i);await Y.mkdir(n,{recursive:!0}),await Y.writeFile(we.join(n,"MEMORY.md"),c);let l=we.join(n,"claude");return await Y.mkdir(l,{recursive:!0}),await Y.writeFile(we.join(l,"MEMORY.md"),pR,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function my(e){try{let t=await Jd(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,Cn];return await Promise.all(n.map(r=>dR(r,{timeoutMs:hR}))),await mR(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function hy(){return{...Je,pending:ns.size,queued:zd.size}}function wy(e){if(Wc.has(e))return Wc.get(e);zd.add(e);let t=iy.then(async()=>{zd.delete(e),Wc.delete(e);let n=await Qd(e);return Je.runs++,Je.lastRunAt=Date.now(),n.error?(Je.errors++,Je.lastError=n.error):Je.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return Wc.set(e,t),iy=t.then(()=>{}),t}function zc(e,{delayMs:t=wR}={}){if(!e||typeof e!="string")return;Je.scheduled++;let n=ns.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{ns.delete(e),wy(e)},t);r.unref?.(),ns.set(e,r)}async function Zd(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await Y.access(we.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=ns.get(e);r&&(clearTimeout(r),ns.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([wy(e),s])}finally{clearTimeout(o)}}async function gy(e){return Ia||(Ia=(async()=>{try{cy||(cy=!0,await yR());let{harvested:t,changedByKey:n}=await py(e);for(let[r,o]of n)await Vc(r,[...o]);return Je.reconciles++,Je.lastReconcileAt=Date.now(),Je.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return Je.errors++,Je.lastError=t?.message||String(t),{harvested:0,error:Je.lastError}}finally{Ia=null}})(),Ia)}function gR(){return we.join(Kc,"memory",".full-sweep-done")}async function yy(){let e=gR();try{let t=JSON.parse(await Y.readFile(e,"utf8"));return Je.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...Je.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await iR();for(let[o,s]of n)await Vc(o,[...s]);let r={at:Date.now(),harvested:t};return await Y.mkdir(we.dirname(e),{recursive:!0}),await Y.writeFile(e,JSON.stringify(r)),Je.backfill=r,{ran:!0,...r}}catch(t){return Je.errors++,Je.lastError=t?.message||String(t),{ran:!1,error:Je.lastError}}}async function yR(){let e=0,t=[];try{t=await Y.readdir(qc(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=we.join(qc(),n.name),o=to(Cn),s=new Set,a=new Map;for(let p of await Ra(r)){let h=we.join(r,p),w;try{w=await Y.readFile(h,"utf8")}catch{continue}let{fm:g}=Gc(w);if(uy(g,n.name)!==Cn)continue;let k=we.join(o,p),S=await un(k).catch(()=>0),E=await un(h,w);await Y.mkdir(o,{recursive:!0}),E>S&&await Y.writeFile(k,w),await Y.rm(h,{force:!0}),s.add(p),a.set(p,dy(p,g)),e++}if(!s.size)continue;let i=Date.now();await Yd(r,[...s].map(p=>[p,i])),await Uc(n.name,[...s].map(p=>({file:p,deleted:!0,modified:i})));let c=we.join(r,"MEMORY.md"),l=await Y.readFile(c,"utf8").catch(()=>""),u=l.split(`
32
+ `,c=mR(i);await X.mkdir(n,{recursive:!0}),await X.writeFile(ge.join(n,"MEMORY.md"),c);let l=ge.join(n,"claude");return await X.mkdir(l,{recursive:!0}),await X.writeFile(ge.join(l,"MEMORY.md"),hR,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function hy(e){try{let t=await Zd(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,Cn];return await Promise.all(n.map(r=>pR(r,{timeoutMs:gR}))),await wR(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function wy(){return{...Je,pending:ns.size,queued:Jd.size}}function gy(e){if(Kc.has(e))return Kc.get(e);Jd.add(e);let t=cy.then(async()=>{Jd.delete(e),Kc.delete(e);let n=await tf(e);return Je.runs++,Je.lastRunAt=Date.now(),n.error?(Je.errors++,Je.lastError=n.error):Je.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return Kc.set(e,t),cy=t.then(()=>{}),t}function Jc(e,{delayMs:t=yR}={}){if(!e||typeof e!="string")return;Je.scheduled++;let n=ns.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{ns.delete(e),gy(e)},t);r.unref?.(),ns.set(e,r)}async function ef(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await X.access(ge.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=ns.get(e);r&&(clearTimeout(r),ns.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([gy(e),s])}finally{clearTimeout(o)}}async function yy(e){return $a||($a=(async()=>{try{ly||(ly=!0,await kR());let{harvested:t,changedByKey:n}=await my(e);for(let[r,o]of n)await Yc(r,[...o]);return Je.reconciles++,Je.lastReconcileAt=Date.now(),Je.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return Je.errors++,Je.lastError=t?.message||String(t),{harvested:0,error:Je.lastError}}finally{$a=null}})(),$a)}function bR(){return ge.join(Vc,"memory",".full-sweep-done")}async function by(){let e=bR();try{let t=JSON.parse(await X.readFile(e,"utf8"));return Je.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...Je.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await lR();for(let[o,s]of n)await Yc(o,[...s]);let r={at:Date.now(),harvested:t};return await X.mkdir(ge.dirname(e),{recursive:!0}),await X.writeFile(e,JSON.stringify(r)),Je.backfill=r,{ran:!0,...r}}catch(t){return Je.errors++,Je.lastError=t?.message||String(t),{ran:!1,error:Je.lastError}}}async function kR(){let e=0,t=[];try{t=await X.readdir(Gc(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=ge.join(Gc(),n.name),o=to(Cn),s=new Set,a=new Map;for(let p of await Oa(r)){let h=ge.join(r,p),w;try{w=await X.readFile(h,"utf8")}catch{continue}let{fm:g}=zc(w);if(dy(g,n.name)!==Cn)continue;let b=ge.join(o,p),E=await un(b).catch(()=>0),S=await un(h,w);await X.mkdir(o,{recursive:!0}),S>E&&await X.writeFile(b,w),await X.rm(h,{force:!0}),s.add(p),a.set(p,fy(p,g)),e++}if(!s.size)continue;let i=Date.now();await Xd(r,[...s].map(p=>[p,i])),await Wc(n.name,[...s].map(p=>({file:p,deleted:!0,modified:i})));let c=ge.join(r,"MEMORY.md"),l=await X.readFile(c,"utf8").catch(()=>""),u=l.split(`
33
33
  `).filter(p=>!s.has(rs(p))).join(`
34
- `);await Y.writeFile(c,u).catch(()=>{});let f=we.join(o,"MEMORY.md"),d=await Y.readFile(f,"utf8").catch(()=>"");await Y.writeFile(f,Xd(d,l,s,a))}return{moved:e}}async function by(){let e=[],t=[Cn];try{for(let n of await Y.readdir(qc(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=to(n),o=await Ra(r),s=await $a(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await Y.readFile(we.join(r,i),"utf8").catch(()=>""),{fm:l}=Gc(c);a.push({file:i,name:ir(l,"name")||i.replace(/\.md$/,""),description:ir(l,"description")||"",scope:ir(l,"scope")||null,modified:await un(we.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function ky(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=to(e),r=we.join(n,t);if(!await Y.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await Y.rm(r,{force:!0}),await Yd(n,[[t,s]]);let a=we.join(n,"MEMORY.md"),i=await Y.readFile(a,"utf8").catch(()=>"");await Y.writeFile(a,i.split(`
34
+ `);await X.writeFile(c,u).catch(()=>{});let f=ge.join(o,"MEMORY.md"),d=await X.readFile(f,"utf8").catch(()=>"");await X.writeFile(f,Qd(d,l,s,a))}return{moved:e}}async function ky(){let e=[],t=[Cn];try{for(let n of await X.readdir(Gc(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=to(n),o=await Oa(r),s=await Ra(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await X.readFile(ge.join(r,i),"utf8").catch(()=>""),{fm:l}=zc(c);a.push({file:i,name:cr(l,"name")||i.replace(/\.md$/,""),description:cr(l,"description")||"",scope:cr(l,"scope")||null,modified:await un(ge.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function xy(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=to(e),r=ge.join(n,t);if(!await X.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await X.rm(r,{force:!0}),await Xd(n,[[t,s]]);let a=ge.join(n,"MEMORY.md"),i=await X.readFile(a,"utf8").catch(()=>"");await X.writeFile(a,i.split(`
35
35
  `).filter(l=>rs(l)!==t).join(`
36
- `)).catch(()=>{});let c=await Uc(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function Qd(e){try{let t=await Jd(e),{harvested:n,changedByKey:r}=await fy(e,t[0]||null);for(let[o,s]of r)await Vc(o,[...s]);return n>0&&await kR(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function kR(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,bR)}}await $({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var oR,Kc,ry,sR,Cn,ly,rs,ay,aR,cR,lR,pR,hR,wR,ns,zd,iy,Je,Wc,cy,Ia,bR,Oa=j(()=>{Zg();me();oR=rR(nR),Kc=process.env.BOSTRAT_STATE_DIR||we.join(process.env.HOME||tR.tmpdir(),".bostrat"),ry=200,sR=25*1024;Cn="operator";ly=".tombstones.json";rs=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;ay=new Map,aR=2e3;cR=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,lR=e=>{let t=new Map;for(let n of(e||"").split(`
37
- `)){let r=rs(n);r&&n.trim().startsWith("-")&&t.set(r,n)}return t};pR=`# Track memory
36
+ `)).catch(()=>{});let c=await Wc(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function tf(e){try{let t=await Zd(e),{harvested:n,changedByKey:r}=await py(e,t[0]||null);for(let[o,s]of r)await Yc(o,[...s]);return n>0&&await vR(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function vR(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,xR)}}await $({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var aR,Vc,oy,iR,Cn,uy,rs,iy,cR,uR,dR,hR,gR,yR,ns,Jd,cy,Je,Kc,ly,$a,xR,Ca=L(()=>{Qg();he();aR=sR(oR),Vc=process.env.BOSTRAT_STATE_DIR||ge.join(process.env.HOME||rR.tmpdir(),".bostrat"),oy=200,iR=25*1024;Cn="operator";uy=".tombstones.json";rs=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;iy=new Map,cR=2e3;uR=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,dR=e=>{let t=new Map;for(let n of(e||"").split(`
37
+ `)){let r=rs(n);r&&n.trim().startsWith("-")&&t.set(r,n)}return t};hR=`# 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
- `;hR=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;wR=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,ns=new Map,zd=new Set,iy=Promise.resolve(),Je={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};Wc=new Map;cy=!1,Ia=null;bR=20});import ef from"node:fs/promises";import xR from"node:path";async function Tt(e,t,{mode:n}={}){await ef.mkdir(xR.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++vR}.tmp`;await ef.writeFile(r,JSON.stringify(t,null,2)+`
43
- `,n!=null?{mode:n}:void 0),await ef.rename(r,e)}var vR,cr=j(()=>{vR=0});import Ey from"node:fs/promises";import Ay from"node:os";import _y from"node:path";function Ne(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Na(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),SR);try{return await $R(`${Ie(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function $y(){return Jc||(tf||=Ey.readFile(Iy(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>Jc={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>tf=null),tf)}async function Xc(){await Tt(Iy(),Jc).catch(()=>{})}function Sy(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 $y(),n=Sy(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=>Sy(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>xy&&(t.ops=t.ops.slice(-xy)),await Xc()}function Ty(){Yc||(Yc=setTimeout(()=>{Yc=null,os().catch(()=>{})},RR),Yc.unref?.())}function nf(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function CR(e,t=process.env){if(e.op==="record"){let n=await Na(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...Ma(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:IR()}]})},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 Ey.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await Na(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...Ma(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 Na(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:Ma(t)},t);if(!n.ok)throw nf(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function os({env:e=process.env,log:t=console,now:n=Date.now()}={}){return Ne(e)?Ca||(Ca=(async()=>{let r=await $y();MR(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await CR(a,e)}catch(c){if(!c?.refused)return Ty(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<ER)return Ty(),await Xc(),{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>vy&&(r.parked=r.parked.slice(-vy)),s++,await Xc();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await Xc()}return{flushed:o,parked:s,pending:0}})().finally(()=>{Ca=null}),Ca):{flushed:0,source:"unconfigured"}}function MR(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=OR);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 wt(e,t,{trackId:n=null,env:r=process.env}={}){return Ne(r)?(await rf({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),os({env:r})):{queued:!1,source:"unconfigured"}}async function lr(e,t,n,r,o,{env:s=process.env}={}){return Ne(s)?(await rf({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),os({env:s})):{queued:!1,source:"unconfigured"}}async function Vt(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return Ne(r)?(await rf({op:"delete",family:e,id:t,deletedAt:n}),os({env:r})):{queued:!1,source:"unconfigured"}}async function et(e,{env:t=process.env}={}){if(!Ne(t))return{records:[],source:"unconfigured"};try{let n=await Na(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:Ma(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 Pa(e,t,n,r,{env:o=process.env}={}){if(!Ne(o))return null;try{let s=await Na(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:Ma(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 SR,TR,xy,ER,vy,AR,_R,Iy,IR,$R,RR,OR,Ma,Jc,tf,Yc,Ca,ur=j(()=>{it();cr();SR=1e4,TR=3e4,xy=2e3,ER=5,vy=100,AR=60*6e4,_R=()=>process.env.BOSTRAT_STATE_DIR||_y.join(process.env.HOME||Ay.tmpdir(),".bostrat"),Iy=()=>_y.join(_R(),"content-outbox.json"),IR=()=>process.env.BOSTRAT_NODE_ID||Ay.hostname(),$R=(...e)=>fetch(...e),RR=TR,OR=AR;Ma=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});Jc=null,tf=null,Yc=null,Ca=null});import of from"node:fs/promises";import Ry from"node:path";async function Oy(e,t,{box:n=null,agent:r=null}={}){if(!e||!Ne())return{pushed:!1};try{let o=Date.now();return await wt("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await lr("checkpoints",e,o,"md",t),Da=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function jR(){if(Da&&Date.now()-Da.at<BR)return{records:Da.records,source:"plane"};let e=await et("checkpoints");return e.source==="plane"&&(Da={at:Date.now(),records:e.records}),e}async function Zc(e){try{let t=DR(e);if(!t||!Ne())return{restored:!1};let n=Ry.join(e,NR,PR);if(await of.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await jR();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 Pa("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await of.mkdir(Ry.dirname(n),{recursive:!0}),await of.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var NR,PR,DR,BR,Da,Qc=j(()=>{ur();NR=".bostrat/handoff",PR="latest.md",DR=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;BR=6e4,Da=null});import Ba from"node:fs/promises";import LR from"node:os";import My from"node:path";function no(e){let t=String(e??"");for(let n of FR)t=t.replace(n,"\u2039redacted\u203A");return t}function el(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function UR(e){try{await Ba.mkdir(sf,{recursive:!0}),await Ba.appendFile(ss,`${JSON.stringify(e)}
44
- `,"utf8");let n=(await Ba.readFile(ss,"utf8")).split(`
45
- `).filter(Boolean);n.length>Cy&&await Ba.writeFile(ss,`${n.slice(-Cy).join(`
42
+ `;gR=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;yR=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,ns=new Map,Jd=new Set,cy=Promise.resolve(),Je={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};Kc=new Map;ly=!1,$a=null;xR=20});import nf from"node:fs/promises";import SR from"node:path";async function Tt(e,t,{mode:n}={}){await nf.mkdir(SR.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++TR}.tmp`;await nf.writeFile(r,JSON.stringify(t,null,2)+`
43
+ `,n!=null?{mode:n}:void 0),await nf.rename(r,e)}var TR,lr=L(()=>{TR=0});import Ay from"node:fs/promises";import _y from"node:os";import Iy from"node:path";function Ne(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Pa(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),ER);try{return await OR(`${Ie(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function Ry(){return Zc||(rf||=Ay.readFile($y(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>Zc={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>rf=null),rf)}async function Qc(){await Tt($y(),Zc).catch(()=>{})}function Ty(e){return e.op==="blob"?`blob ${e.family} ${e.id} ${e.v} ${e.kind}`:`${e.op} ${e.family} ${e.id}`}async function sf(e){let t=await Ry(),n=Ty(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=>Ty(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>vy&&(t.ops=t.ops.slice(-vy)),await Qc()}function Ey(){Xc||(Xc=setTimeout(()=>{Xc=null,os().catch(()=>{})},CR),Xc.unref?.())}function of(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function NR(e,t=process.env){if(e.op==="record"){let n=await Pa(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...Na(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:RR()}]})},t);if(!n.ok)throw of(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 Ay.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await Pa(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...Na(t),"content-type":"application/octet-stream"},body:n},t);if(!r.ok&&r.status!==400)throw of(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 Pa(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:Na(t)},t);if(!n.ok)throw of(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function os({env:e=process.env,log:t=console,now:n=Date.now()}={}){return Ne(e)?Ma||(Ma=(async()=>{let r=await Ry();PR(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await NR(a,e)}catch(c){if(!c?.refused)return Ey(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<_R)return Ey(),await Qc(),{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>Sy&&(r.parked=r.parked.slice(-Sy)),s++,await Qc();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await Qc()}return{flushed:o,parked:s,pending:0}})().finally(()=>{Ma=null}),Ma):{flushed:0,source:"unconfigured"}}function PR(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=MR);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 wt(e,t,{trackId:n=null,env:r=process.env}={}){return Ne(r)?(await sf({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),os({env:r})):{queued:!1,source:"unconfigured"}}async function ur(e,t,n,r,o,{env:s=process.env}={}){return Ne(s)?(await sf({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),os({env:s})):{queued:!1,source:"unconfigured"}}async function Vt(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return Ne(r)?(await sf({op:"delete",family:e,id:t,deletedAt:n}),os({env:r})):{queued:!1,source:"unconfigured"}}async function et(e,{env:t=process.env}={}){if(!Ne(t))return{records:[],source:"unconfigured"};try{let n=await Pa(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:Na(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 Da(e,t,n,r,{env:o=process.env}={}){if(!Ne(o))return null;try{let s=await Pa(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:Na(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 ER,AR,vy,_R,Sy,IR,$R,$y,RR,OR,CR,MR,Na,Zc,rf,Xc,Ma,dr=L(()=>{it();lr();ER=1e4,AR=3e4,vy=2e3,_R=5,Sy=100,IR=60*6e4,$R=()=>process.env.BOSTRAT_STATE_DIR||Iy.join(process.env.HOME||_y.tmpdir(),".bostrat"),$y=()=>Iy.join($R(),"content-outbox.json"),RR=()=>process.env.BOSTRAT_NODE_ID||_y.hostname(),OR=(...e)=>fetch(...e),CR=AR,MR=IR;Na=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});Zc=null,rf=null,Xc=null,Ma=null});import af from"node:fs/promises";import Oy from"node:path";async function Cy(e,t,{box:n=null,agent:r=null}={}){if(!e||!Ne())return{pushed:!1};try{let o=Date.now();return await wt("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await ur("checkpoints",e,o,"md",t),Ba=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function FR(){if(Ba&&Date.now()-Ba.at<LR)return{records:Ba.records,source:"plane"};let e=await et("checkpoints");return e.source==="plane"&&(Ba={at:Date.now(),records:e.records}),e}async function el(e){try{let t=jR(e);if(!t||!Ne())return{restored:!1};let n=Oy.join(e,DR,BR);if(await af.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await FR();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 Da("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await af.mkdir(Oy.dirname(n),{recursive:!0}),await af.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var DR,BR,jR,LR,Ba,tl=L(()=>{dr();DR=".bostrat/handoff",BR="latest.md",jR=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;LR=6e4,Ba=null});import ja from"node:fs/promises";import UR from"node:os";import Ny from"node:path";function no(e){let t=String(e??"");for(let n of HR)t=t.replace(n,"\u2039redacted\u203A");return t}function nl(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function WR(e){try{await ja.mkdir(cf,{recursive:!0}),await ja.appendFile(ss,`${JSON.stringify(e)}
44
+ `,"utf8");let n=(await ja.readFile(ss,"utf8")).split(`
45
+ `).filter(Boolean);n.length>My&&await ja.writeFile(ss,`${n.slice(-My).join(`
46
46
  `)}
47
- `,"utf8")}catch(t){console.warn(`[handoff-debug] failed to write ${ss}: ${t?.message||t}`)}}async function re(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&&el())try{t.paneTail=no((await Ce(t.sessionName,{lines:35})).slice(-4e3))}catch{t.paneTail=null}(el()||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 UR(t)}async function Ny({limit:e=80}={}){try{return(await Ba.readFile(ss,"utf8")).split(`
48
- `).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=no(o.paneTail)),o}catch{return{raw:no(r)}}})}catch{return[]}}var FR,sf,ss,Cy,Py,dn=j(()=>{lt();FR=[/[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||My.join(LR.homedir(),".bostrat","debug"),ss=My.join(sf,"handoff.jsonl"),Cy=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;Py={DEBUG_DIR:sf,LOG_FILE:ss}});import tl from"node:fs/promises";import af from"node:path";import HR from"node:os";async function By(e=Dy){await tl.mkdir(e,{recursive:!0});for(let t of qR){let n=t==="prepare-commit-msg"?KR:t==="post-commit"?GR:`${cf}exit 0
49
- `,r=af.join(e,t),o=null;try{o=await tl.readFile(r,"utf8")}catch{}o!==n&&await tl.writeFile(r,n,{mode:493}),await tl.chmod(r,493).catch(()=>{})}return e}function jy({nodeUrl:e,dir:t=Dy,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",`${ja}=${e}`]}function Ly(e=process.env){return e.BOSTRAT_NODE_URL||`http://127.0.0.1:${e.PORT||3362}`}var ja,WR,Dy,qR,cf,KR,GR,lf=j(()=>{Yo();ja="BOSTRAT_NODE_URL",WR=process.env.BOSTRAT_STATE_DIR||af.join(process.env.HOME||HR.tmpdir(),".bostrat"),Dy=af.join(WR,"git-hooks"),qR=["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 ${ss}: ${t?.message||t}`)}}async function se(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=no((await Ce(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 WR(t)}async function Py({limit:e=80}={}){try{return(await ja.readFile(ss,"utf8")).split(`
48
+ `).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=no(o.paneTail)),o}catch{return{raw:no(r)}}})}catch{return[]}}var HR,cf,ss,My,Dy,dn=L(()=>{lt();HR=[/[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];cf=process.env.BOSTRAT_DEBUG_DIR||Ny.join(UR.homedir(),".bostrat","debug"),ss=Ny.join(cf,"handoff.jsonl"),My=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;Dy={DEBUG_DIR:cf,LOG_FILE:ss}});import rl from"node:fs/promises";import lf from"node:path";import qR from"node:os";async function jy(e=By){await rl.mkdir(e,{recursive:!0});for(let t of GR){let n=t==="prepare-commit-msg"?VR:t==="post-commit"?zR:`${uf}exit 0
49
+ `,r=lf.join(e,t),o=null;try{o=await rl.readFile(r,"utf8")}catch{}o!==n&&await rl.writeFile(r,n,{mode:493}),await rl.chmod(r,493).catch(()=>{})}return e}function Ly({nodeUrl:e,dir:t=By,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",`${La}=${e}`]}function Fy(e=process.env){return e.BOSTRAT_NODE_URL||`http://127.0.0.1:${e.PORT||3362}`}var La,KR,By,GR,uf,VR,zR,df=L(()=>{Yo();La="BOSTRAT_NODE_URL",KR=process.env.BOSTRAT_STATE_DIR||lf.join(process.env.HOME||qR.tmpdir(),".bostrat"),By=lf.join(KR,"git-hooks"),GR=["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"],uf=`#!/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,73 +61,73 @@ esac
61
61
  if [ -x "$orig/$hook" ] && [ "$orig/$hook" != "$0" ]; then
62
62
  "$orig/$hook" "$@" || exit $?
63
63
  fi
64
- `,KR=`${cf}
64
+ `,VR=`${uf}
65
65
  # \u2500\u2500 bostrat: append provenance trailers (Layer 0). Skipped for merge commits
66
66
  # (nobody "wrote" a merge) and outside a box (no token / no node url).
67
67
  [ -z "$${$n}" ] && exit 0
68
- [ -z "$${ja}" ] && exit 0
68
+ [ -z "$${La}" ] && exit 0
69
69
  [ "$2" = "merge" ] && exit 0
70
- trailers=$(curl -sS -m 3 -H "${Rn}: $${$n}" "$${ja}/api/git/trailers" 2>/dev/null) || exit 0
70
+ trailers=$(curl -sS -m 3 -H "${Rn}: $${$n}" "$${La}/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
- `,GR=`${cf}
76
+ `,zR=`${uf}
77
77
  # \u2500\u2500 bostrat: report the commit (code.committed + rework analysis, node-side).
78
78
  [ -z "$${$n}" ] && exit 0
79
- [ -z "$${ja}" ] && exit 0
79
+ [ -z "$${La}" ] && 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 "$${ja}/api/git/committed" \\
82
+ printf '{"sha":"%s","cwd":"%s"}' "$sha" "$cwd" | curl -sS -m 5 -X POST "$${La}/api/git/committed" \\
83
83
  -H 'content-type: application/json' -H "${Rn}: $${$n}" --data-binary @- >/dev/null 2>&1 || true
84
84
  exit 0
85
- `});import{execFile as Uy}from"node:child_process";import{promisify as VR}from"node:util";import rl from"node:fs";import{randomUUID as Hy}from"node:crypto";function cs(e){return new Promise(t=>setTimeout(t,e))}function nl(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 Wy(e){return`/tmp/tmux-${e}/default`}function zR({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=Wy(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function Fa(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${La}=1`]}function Ua(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&&Pe(n)&&(s+=` --name ${n}`),s}function ro(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function dr(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function XR(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 qy(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await Ky(e,{loginShell:t});return r===ol?!0:r===as?!1:n}async function Ky(e,{loginShell:t=!1,timeoutMs:n=uf}={}){if(!e)return as;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}),ol}catch(s){return s?.killed||s?.signal?is:s?.code===1||s?.code===127?as:is}}async function sl(e,{retries:t=ZR,sleep:n=QR,probe:r=Ky}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:uf});for(let a=0;s===is&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:uf*2});return s}function V(...e){return["-S",$t,...e]}async function fr(){if(!rl.existsSync($t))return!1;try{return await $e(K,V("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function Ha(){if(await fr())return!0;try{rl.mkdirSync($t.replace(/\/[^/]+$/,""),{recursive:!0}),await $e(K,V("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await fr()}function Pe(e){return typeof e=="string"&&eO.test(e)}async function zt(){if(!rl.existsSync($t))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(K,V("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
86
- `).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,f,d,p,h]=r.split("|"),w=Number(i),g=Number(h);return{name:o,title:u||null,windows:Number(s),attached:Number(a),lastActivityMs:Number.isFinite(w)?n-w*1e3:null,cwd:c||null,isBostrat:l==="1",sessionId:f||null,agent:d||(l==="1"?"claude":null),alternateOn:p==="1",createdMs:Number.isFinite(g)&&g>0?g*1e3:null}}).filter(r=>!JR.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function ge(e){return(await zt()).find(n=>n.name===e)||null}function rO(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=nO&&tO.test(t)}function al(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function Gy(e){try{let{stdout:t}=await $e(K,V("list-sessions","-F","#{session_name}"));return t.split(`
87
- `).map(n=>n.trim()).includes(e)}catch{return!1}}function aO(e){let t=String(e||"").trim().split(/\s+/)[0]||"";if(t.includes("/"))return null;let n=[];for(let o=1;o<=t.length-3;o++)n.push(t.slice(o));if(!n.length)return null;let r=n.map(o=>o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp(`\\b(?:${r.join("|")})`)}async function iO(e,t){let n=Date.now()+Wa(),r=aO(t),o=!1,s=0;for(;;){if(await cs(oO),s+=1,!await Gy(e))return;let a=await Ce(e,{lines:15}),i=!o&&sO.test(a)&&!!r?.test(a);if(!i&&s>1&&!await Mn(e))return;if(i){o=!0,await re({flow:"spawn",phase:"launch-retry",sessionName:e,agent:dr(t),promptHead:t.slice(0,120)}).catch(()=>{}),await $e(K,V("send-keys","-t",e,"C-u")),await $e(K,V("send-keys","-t",e,"-l",t)),await $e(K,V("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await re({flow:"spawn",phase:"launch-failed",sessionName:e,agent:dr(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function pr(e,t=YR,n={}){if(!rO(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=al(r);if(!Pe(o))throw new Error("resulting tmux session name is invalid");if(!await Ha())throw new Error(`host tmux server not running on ${$t} and auto-start failed \u2014 start one: ${K} -S ${$t} new-session -d -s keeper "sleep 2147483647"`);if(await Gy(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||df,a=n.agent||dr(s),i=!!n.resumeSessionId,c=n.resumeSessionId||Hy(),l=i?s:Ua(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),f=a==="claude"&&ro(s),d=n.firstRun===!0;d||(f&&await or(t),a==="codex"&&await Jo(t),a==="cursor"&&await Xo(t),await my(t),n.freshWorkspace!==!0&&await Zc(t));let p=f&&!d?Nc():null,h=Ng(),w=["-e",`${$n}=${h}`];w.push(...jy({nodeUrl:Ly()})),p&&w.push("-e",`ANTHROPIC_API_KEY=${p}`),f&&w.push(...Fa());try{await $e(K,V("new-session","-d","-s",o,"-c",t,...w))}catch(g){throw nl(p?nl(g,p):g,h)}return await oo(o),await $e(K,V("set-option","-t",o,"@bostrat-session","1")),await $e(K,V("set-option","-t",o,"@bostrat-title",r)),await $e(K,V("set-option","-t",o,"@bostrat-sid",c)),await $e(K,V("set-option","-t",o,"@bostrat-agent",a)),await $e(K,V("send-keys","-t",o,l,"Enter")),XR(l)&&iO(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:h}}async function Yt(e){if(!Pe(e))throw new Error("invalid session name");await $e(K,V("kill-session","-t",e))}async function Vy(e,t){if(Pe(e))try{let n=t?V("set-option","-t",e,"@bostrat-sid",t):V("set-option","-u","-t",e,"@bostrat-sid");await $e(K,n)}catch{}}async function Ce(e,{lines:t=40}={}){if(!Pe(e))return"";try{let n=V("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await $e(K,n);return String(r||"")}catch{return""}}async function zy(e){if(!Pe(e))return 0;try{let{stdout:t}=await $e(K,V("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
88
- `).filter(Boolean).length}catch{return 0}}async function oo(e,{cols:t=uO,rows:n=dO}={}){if(!Pe(e))return!0;if(await zy(e))return!1;try{let r=await Yy(e);if(r.cols===t&&r.rows===n)return!0;await $e(K,V("resize-window","-t",e,"-x",String(t),"-y",String(n))),await $e(K,V("set-window-option","-t",e,"window-size","latest")),await cs(80)}catch{}return!0}async function fO(e){if(!Pe(e))return 0;try{let{stdout:t}=await $e(K,V("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function Mn(e){let t=await fO(e);if(!t)return!1;try{return await $e("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function Yy(e){if(!Pe(e))return{cols:0,rows:0};try{let{stdout:t}=await $e(K,V("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 il(e,{cols:t=cO,rows:n=lO}={}){if(Pe(e)&&!await zy(e))try{let r=await Yy(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await $e(K,V("resize-window","-t",e,"-x",String(o),"-y",String(s))),await $e(K,V("set-window-option","-t",e,"window-size","latest")),await cs(80))}catch{}}async function Nn(e){return await il(e),Ce(e,{lines:Xe})}async function Le(e,t,{settleMs:n=40,kind:r}={}){if(!Pe(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>pO.has(s));for(let s=0;s<o.length;s++)await $e(K,V("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await cs(n);return re({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function ls(e,t,{kind:n}={}){if(!Pe(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await $e(K,V("send-keys","-t",e,"-N",String(r),"BSpace")),re({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function ll(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!Pe(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await $e(K,V("send-keys","-t",e,"-l",s)),n>0&&await cs(n);re({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function mO(e,t){return new Promise((n,r)=>{let o=Uy(K,V(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function hO(e,t){let n=`bostrat-${Hy().slice(0,8)}`;await mO(["load-buffer","-b",n,"-"],t),await $e(K,V("paste-buffer","-p","-d","-b",n,"-t",e))}async function Ze(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!Pe(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await hO(e,t):await $e(K,V("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await cs(a),await $e(K,V("send-keys","-t",e,"Enter"))}re({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,K,Fy,$t,YR,df,La,ff,JR,ol,as,is,uf,ZR,QR,pf,eO,tO,nO,Wa,oO,sO,cO,lO,Xe,uO,dO,pO,cl,lt=j(()=>{Ta();Dc();Bc();Oa();Qc();dn();Yo();lf();$e=VR(Uy);K=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";Fy=typeof process.getuid=="function"?process.getuid():0,$t=zR({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return rl.existsSync(Wy(Fy))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:Fy}),YR=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",df=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",La="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";ff="bostrat-usage-probe",JR=new Set([ff]);ol="present",as="absent",is="unknown",uf=5e3,ZR=[250,1e3,3e3],QR=e=>new Promise(t=>setTimeout(t,e));pf={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"};eO=/^[A-Za-z0-9_.-]{1,64}$/;tO=/^[A-Za-z0-9 ._↻-]+$/,nO=64;Wa=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,oO=1e3,sO=/not found|Unknown command/i;cO=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,lO=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,Xe=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,uO=Number(process.env.BOSTRAT_BOX_COLS)||120,dO=Number(process.env.BOSTRAT_BOX_ROWS)||40;pO=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);cl=1600});import qa from"node:fs";import xO from"node:fs/promises";import us from"node:path";import vO from"node:os";function wf(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function gf(e){let t=us.join(hf,wf(e)),n;try{n=qa.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=us.join(t,o);try{let{mtimeMs:a}=qa.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function Jt(e,t){if(!t)return null;let n=us.join(hf,wf(e),`${t}.jsonl`);return qa.existsSync(n)?n:null}function nb(e){if(!e)return[];let t=us.join(hf,wf(e)),n;try{n=qa.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=qa.statSync(us.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function Et(e,t=131072){let n=await xO.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 TO(e){let t=e.split(`
89
- `);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 Ka(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=Jt(e,t),o=!0,!r)return null}else if(n){if(r=gf(e),o=!1,!r)return null}else return null;let s;try{s=TO(await Et(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(tb,s.model),i=tb[s.model]||SO;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 tb,SO,hf,Xt=j(()=>{tb={"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},SO=2e5,hf=process.env.BOSTRAT_CLAUDE_PROJECTS||us.join(vO.homedir(),".claude","projects")});function EO(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===`
90
- `){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function Ga(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 Va(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 Oe(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(sb(o)){t.has(o)&&r++;continue}n.push(o)}return n}function ab(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 IO(e){let t=ab(e),n=ut(Oe(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${Fe(n)}`:`Read lines ${t.from}\u2013${t.to} of ${Fe(n)}`:e.includes("-i")&&n?`Edit ${Fe(n)}`:null}function yf(e){if(e.includes("--files")){let s=ut(Oe(e,rb)[0]);return s&&s!=="."?`List files in ${ds(s)}`:"List files"}let t=Oe(e,rb),n=t[0];if(!n)return null;let r=ut(t.slice(1).find(s=>s!==".")),o=fs(n,40);return r?`Search for \u201C${o}\u201D in ${ds(r)}`:`Search for \u201C${o}\u201D`}function bf(e){let t=Oe(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 kf(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=Oe(e)[0];return n?`Run ${Fe(n)}`:null}function $O(e){let t=Oe(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 ob(e){return e.find(t=>/^https?:\/\//.test(t))||null}function CO(e){let t=Va(Ga(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(Fe(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return xf(t[2]);let n=Fe(t[0]);if(OO.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=RO[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function xf(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
91
- `,n);i!==-1&&(t=t.slice(0,i))}let r=EO(t);for(let i=0;i<r.length-1;i++){let c=Va(Ga(r[i])),l=Va(Ga(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Fe(c[0]))&&Fe(l[0])==="sed"){let u=ab(l),f=Oe(c)[0];if(u&&f)return fs(u.from===u.to?`Read line ${u.from} of ${Fe(f)}`:`Read lines ${u.from}\u2013${u.to} of ${Fe(f)}`,88)}}let o=[];for(let i of r){let c=CO(i);c&&o.push({d:c,head:Fe(Va(Ga(i))[0]||""),sub:Oe(Va(Ga(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":fs(s?s.d:o[0].d,88)}var fs,ut,Fe,ds,sb,rb,AO,_O,RO,OO,ib=j(()=>{fs=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,ut=e=>e&&!/[$`]/.test(e)?e:null,Fe=e=>e.replace(/\/+$/,"").split("/").pop()||e,ds=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},sb=e=>e.startsWith("-"),rb=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);AO={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 ${Fe(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"},_O={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"};RO={git:e=>{let t=Oe(e,new Set(["-C","-c"])),n=AO[t[0]];return n?n(t,e):null},gh:e=>{let t=Oe(e),n=_O[t[0]];return n?n(t):null},sed:IO,rg:yf,grep:yf,egrep:yf,nl:e=>{let t=ut(Oe(e)[0]);return t?`Read ${Fe(t)}`:null},cat:e=>{let t=ut(Oe(e)[0]);return t?`Read ${Fe(t)}`:null},head:e=>{let t=ut(Oe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${Fe(t)}`:null},tail:e=>{let t=ut(Oe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${Fe(t)}`:null},wc:e=>{let t=ut(Oe(e)[0]);return t?`Count lines in ${Fe(t)}`:"Count input lines"},ls:e=>{let t=ut(Oe(e)[0]);return t&&t!=="."?`List files in ${ds(t)}`:"List files"},find:e=>ut(e[1])&&!sb(e[1])&&e[1]!=="."?`Find files in ${ds(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=ut(Oe(e)[0]);return t?`Create directory ${ds(t)}`:null},touch:e=>{let t=ut(Oe(e)[0]);return t?`Create ${Fe(t)}`:null},rm:e=>{let t=ut(Oe(e)[0]);return t?`Delete ${ds(t)}`:null},mv:e=>{let t=ut(Oe(e)[0]);return t?`Move ${Fe(t)}`:null},cp:e=>{let t=ut(Oe(e)[0]);return t?`Copy ${Fe(t)}`:null},chmod:e=>{let t=ut(Oe(e)[1]);return t?`Change permissions on ${Fe(t)}`:null},diff:e=>{let t=Oe(e);return t.length>=2?`Compare ${Fe(t[0])} and ${Fe(t[1])}`:null},curl:e=>{let t=ob(e);return t?`Fetch ${fs(t,56)}`:"Fetch a URL"},wget:e=>{let t=ob(e);return t?`Fetch ${fs(t,56)}`:"Fetch a URL"},npm:bf,pnpm:bf,yarn:bf,npx:e=>{let t=Oe(e)[0];return t?`Run ${t}`:null},node:e=>kf(e,"Node"),python:e=>kf(e,"Python"),python3:e=>kf(e,"Python"),make:e=>{let t=Oe(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:$O,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=Oe(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=Oe(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=Oe(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},OO=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function ps(e){let t=e.split(`
92
- `).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||xf(e)||ps(e)}function vf(e,t){if(e){if(Array.isArray(e)){for(let n of e)vf(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&Sf.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))vf(n,t)}}}async function cb(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await Et(e,t)}catch{return[]}let o=[];for(let s of r.split(`
93
- `)){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(vf(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let f of l)o.push({...f,summary:mr(f.command,f.description),ts:u})}return o.slice(-n)}function lb(e,t){let n=t.filter(l=>l.role==="assistant"&&(l.text||"").trim()).sort((l,u)=>(l.ts||0)-(u.ts||0)),r=[...e].sort((l,u)=>(l.ts||0)-(u.ts||0)),o=[],s=0,a=0,i=l=>{let u=l.n??a+1;return u>a&&(a=u),u};for(let l of n){let u=r.findIndex((h,w)=>w>=s&&(h.ts||0)>(l.ts||0)),f=u===-1?r.length:u,d=r.slice(s,f);if(s=f,!d.length)continue;let p=d.map(h=>({...h,n:i(h)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:p,ts:Math.max(...p.map(h=>h.ts||0)),pending:!1})}let c=r.slice(s);if(c.length){let l=c.map(u=>({...u,n:i(u)}));o.push({id:`batch-pending-${l[0]?.box||"lead"}`,anchorTs:null,anchorBox:l[l.length-1]?.box??null,agent:l[l.length-1]?.agent??"claude",boxRole:l[l.length-1]?.boxRole??"lead",commands:l,ts:Math.max(...l.map(u=>u.ts||0)),pending:!0})}return o}var Sf,ms=j(()=>{Xt();ib();Sf=new Set(["Bash"])});import ub from"node:fs";import Ef from"node:fs/promises";import Tf from"node:path";import MO from"node:os";async function db(e){try{return await Ef.realpath(e)}catch{return e}}function PO(e=NO){let t=[],n=r=>{let o;try{o=ub.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=Tf.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:ub.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function DO(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(`
94
- `);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=t)break}return o}finally{await n.close()}}async function BO(e){let t=await DO(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 so(e,t){if(!e&&!t)return null;let n=PO();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await db(e);for(let o of n){let s=await BO(o.file);if(s&&(s===e||await db(s)===r))return o}return null}async function fb(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await so(e,t);if(!o)return[];let s;try{s=await Et(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,f=null;for(let d of s.split(`
95
- `)){let p=d.trim();if(!p||p[0]!=="{")continue;let h;try{h=JSON.parse(p)}catch{continue}if((h.type==="turn_context"&&h.payload?.model||h.type==="session_meta"&&h.payload?.model)&&(i=h.payload.model),h.type==="event_msg"){let S=h.payload?.type;S==="task_started"?(l=!0,u=!1,f=h.payload?.turn_id||null):S==="task_complete"&&l&&(l=!1,!u&&h.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:ao,sourceId:h.payload?.turn_id||f||void 0,ts:h.timestamp?Date.parse(h.timestamp):null,model:i}));continue}if(h.type!=="response_item")continue;let w=h.payload;if(!w)continue;if((w.type==="function_call"||w.type==="custom_tool_call")&&w.name){u=!0,Af.has(w.name)||c.push(w.name);continue}if(w.type!=="message"||w.role!=="assistant")continue;u=!0;let g=LO(w.content),k=c.length?c.slice():null;c=[],!(!g&&!k)&&a.push({role:"assistant",text:g,tools:k||void 0,ts:h.timestamp?Date.parse(h.timestamp):null,model:i})}if(i)for(let d of a)d.model||(d.model=i);return a.slice(-n)}function FO(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 UO(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+=`
96
- `;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 HO(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=UO(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function pb(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await so(e,t);if(!o)return[];let s;try{s=await Et(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
97
- `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type!=="response_item")continue;let u=l.payload;if(!u)continue;let f=[];if(u.type==="function_call"&&za.has(u.name)){let p;try{p=JSON.parse(u.arguments||"{}")}catch{continue}let h=FO(p);h&&(f=[h])}else u.type==="custom_tool_call"&&u.name==="exec"&&(f=HO(u.input));if(!f.length)continue;let d=u.call_id||u.id||null;f.forEach((p,h)=>{a.push({id:d?h?`${d}:${h}`:d:null,tool:u.name,command:p,description:"",summary:mr(p),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function mb(e,t){let n=await so(e,t);if(!n)return null;try{return Math.round((await Ef.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var NO,jO,LO,za,Af,ao,io=j(()=>{Xt();ms();NO=process.env.BOSTRAT_CODEX_SESSIONS||Tf.join(process.env.CODEX_HOME||Tf.join(MO.homedir(),".codex"),"sessions");jO=new Set(["output_text","text"]),LO=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&jO.has(t.type)).map(t=>t.text).join(`
98
- `).trim():"";za=new Set(["exec_command","shell","exec"]),Af=new Set(["wait","write_stdin"]),ao="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 Ya({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&hb.has(r))return hb.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 wb(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||Ya({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===ao?"other":Ya({text:t}),code:null,status:null,requestId:null}}return null}function gb(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:Ya({text:n}),code:null,status:WO(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function WO(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var k5,hb,dl=j(()=>{io();k5=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),hb=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 qO(e,t){return!e||!t?null:Jt(e,t)}function KO(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(`
99
- `).trim():""}function GO(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 VO(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function _f(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 yb(e,t){if(!e.uuid)return null;let n=_f(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 If(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await Et(e,t)}catch{return[]}let o=[],s=new Map;for(let a of r.split(`
100
- `)){let i=a.trim();if(!i||i[0]!=="{")continue;let c;try{c=JSON.parse(i)}catch{continue}if(c.type==="attachment"){let w=c.attachment;w?.type==="queued_command"&&w.commandMode==="task-notification"&&typeof w.prompt=="string"&&w.prompt.trim()&&o.push({role:"user",text:w.prompt.trim(),ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let l=c.message;if(!l)continue;let u=l.role||c.type;if(u!=="user"&&u!=="assistant"||u==="assistant"&&l.model==="<synthetic>"&&!c.isApiErrorMessage)continue;if(u==="assistant"&&Array.isArray(l.content))for(let w of l.content){let g=w?.type==="tool_use"?w.input?.file_path||w.input?.path:null;typeof g=="string"&&zO.test(g)&&s.set(w.id,g.split("/").pop())}if(VO(l.content)){let w=yb(c,s);w&&o.push({role:"assistant",text:"",images:w,ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let f=KO(l.content),d=u==="assistant"?GO(l.content):null,p=u==="user"?yb(c,s):null;if(!f&&!d&&!p)continue;let h=u==="assistant"&&c.isApiErrorMessage?{code:typeof c.error=="string"?c.error:null,status:Number(c.apiErrorStatus)||null,requestId:c.requestId||null,cls:Ya({error:c.error,status:c.apiErrorStatus,text:f})}:null;o.push({role:u,text:f,tools:d||void 0,images:p||void 0,ts:c.timestamp?Date.parse(c.timestamp):null,model:l.model||null,apiError:h||void 0})}return o.slice(-n)}async function bb(e,t,{turns:n=16}={}){let r=qO(e,t);if(!r)return"";let o=await If(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}:** ${YO(s.text||c,700)} ${i}`.trim()}).join(`
101
-
102
- `):""}var zO,YO,fl=j(()=>{dl();Xt();zO=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;YO=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});import JO from"node:fs/promises";import{execFile as XO}from"node:child_process";import{promisify as ZO}from"node:util";function Sb(e){Rf=typeof e=="function"?e:null}function Of(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}function Tb({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();!r||kb.has(r)||(kb.add(r),xb=xb.then(()=>eC({sessionName:e,from:t,to:r})).catch(()=>{}))}async function eC({sessionName:e,from:t,to:n}){await re({flow:"codex-update",phase:"start",sessionName:e,from:t,to:n}).catch(()=>{});try{let r=(await $f("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await JO.realpath(r),s=Of(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await $f("npm",["install","-g","@openai/codex"],{env:a,timeout:QO});let i=(await $f(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await re({flow:"codex-update",phase:"done",sessionName:e,from:t,to:n,version:i}).catch(()=>{}),await vb({sessionName:e,from:t,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await re({flow:"codex-update",phase:"failed",sessionName:e,from:t,to:n,error:o}).catch(()=>{}),await vb({sessionName:e,from:t,to:n,status:"failed",error:o})}}async function vb(e){if(Rf)try{await Rf(e)}catch{}}var $f,QO,kb,xb,Rf,pl=j(()=>{dn();$f=ZO(XO),QO=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,kb=new Set,xb=Promise.resolve(),Rf=null});function nC(e,{provider:t,box:n}){let r=String(e).replace(/\r/g,"").split(`
103
- `);if(!Eb.test(e))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(tC);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"&&Eb.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 co(e){let t=String(e??"").replace(/\r/g,""),n=t.split(`
104
- `);for(let r=n.length-1;r>=0;r--)if(Ib.test(n[r]))return n.slice(r).join(`
105
- `);return t}function rC(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 oC(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 sC(e,t=""){let n=co(e);if(Ja.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
106
- `),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(Ab);if(!u)continue;s<0&&(s=l);let f="";for(let d=l+1;d<Math.min(l+3,r.length);d++){let p=r[d].trim();if(p){if(Ab.test(r[d])||/^Press enter/.test(p))break;f=p;break}}o.push({n:Number(u[2]),cursor:!!u[1],label:u[3].trim(),desc:f})}let a=o.sort((l,u)=>l.n-u.n);if(a.length<2||a.some((l,u)=>l.n!==u+1)||!a.some(l=>/Sign in with ChatGPT/.test(l.label)))return null;let i=[];for(let l=0;l<s;l++){let u=r[l].trim();u&&!Ib.test(r[l])&&rC(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=oC(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function cC(e,t=""){let n=co(e);if(Ja.test(n)||!aC.test(n))return null;let r=n.trimEnd().split(`
107
- `).pop()||"";return iC.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 uC(e,t=""){let n=co(e);if(Ja.test(n)||!_b.test(n))return null;let r=n.split(`
108
- `),o=r.findIndex(i=>_b.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(lC);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 dC(e,t=""){let n=co(e);return Ja.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 fC(e,t=""){let n=co(e);return Ja.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 pC(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(`
109
- `).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 hC(e,t=""){let n=String(e);if(!mC.test(n)||Cf.test(n))return null;let r=n.replace(/\r/g,"").split(`
110
- `),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 wC(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 $b(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=cC(t,n)||uC(t,n)||dC(t,n)||fC(t,n)||sC(t,n);if(r)return r}if(e==="cursor"){let r=hC(t,n)||wC(t,n)||pC(t,n);if(r)return r}return nC(t,{provider:e,box:n})}function Rb(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 tC,Eb,Ja,Ib,Ab,aC,iC,_b,lC,Cf,mC,ml=j(()=>{tC=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,Eb=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;Ja=/(^|\n)\s*›/,Ib=/^\s*Welcome to Codex\b/;Ab=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;aC=/Successfully logged in\./,iC=/^\s*Press Enter to continue\.\s*$/;_b=/Enter this one-time code/,lC=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;Cf=/Run Everything|Add a follow-up|Plan, search, build anything/;mC=/click this link to log in|Signing in with the browser/});function kC(e){let t=String(e||"").replace(/\r/g,"").split(`
111
- `),n=-1;for(let s=t.length-1;s>=0;s--)if(t[s].trim()){n=s;break}if(n<0)return!1;let r=t[n];if(yC.test(r)||bC.test(r)){for(let s=n-1;s>=0&&n-s<=64;s--)if(/^\s*›/.test(t[s]))return!0}return/esc to interrupt|\bWorking \(/.test(String(e||""))}function EC(e){let t=String(e||"");if(!qe.codex.block.test(t))return null;let n=co(t);if(!qe.codex.block.test(n))return null;let r=n.match(TC);return{from:r?.[1]||null,to:r?.[2]||null}}function fn(e){return new Promise(t=>setTimeout(t,e))}function Mf(e,t){let n=Date.now(),r=AC();for(let[s,a]of wl)n-a>=r&&wl.delete(s);let o=`${e}::${t}`;return wl.has(o)?!1:(wl.set(o,n),!0)}function Nb(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
112
- `),r=-1;for(let o=n.length-1;o>=0;o--)if(Mb.test(n[o])){r=o;break}return r<0?t:n.slice(r+1).join(`
113
- `)}function IC(e){let t=0;for(let n of String(e).split(`
114
- `))Mb.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function Nf(e,t){let n=qe[e];if(!n?.busy)return{state:"idle",reason:null};if(Df(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(Nb(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=IC(t);return e==="claude"&&r>0&&r<_C?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function Pf(e,t){return Nf(e,t).state}function Pb(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
115
- `).slice(-RC).join(`
116
- `);return $C.test(n)}function ws(e,t){return Pf(e,t)==="busy"}function gl(e,t){return Pf(e,t)!=="idle"}function gs(e,t){let n=qe[e];return n?.up?n.up.test(t):!0}function OC(e,t){let n=qe[e];return n?Df(e,t)?!1:n.up.test(t)&&Pf(e,t)==="idle":!0}function Df(e,t){let n=qe[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 Bf(e,t){let n=String(t||"").trim();if(!n)return e;let r=String(e||"").split(`
85
+ `});import{execFile as Hy}from"node:child_process";import{promisify as YR}from"node:util";import sl from"node:fs";import{randomUUID as Wy}from"node:crypto";function cs(e){return new Promise(t=>setTimeout(t,e))}function ol(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 qy(e){return`/tmp/tmux-${e}/default`}function JR({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=qy(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function Ua(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${Fa}=1`]}function Ha(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&&Pe(n)&&(s+=` --name ${n}`),s}function ro(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function fr(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function QR(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 Ky(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await Gy(e,{loginShell:t});return r===al?!0:r===as?!1:n}async function Gy(e,{loginShell:t=!1,timeoutMs:n=ff}={}){if(!e)return as;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}),al}catch(s){return s?.killed||s?.signal?is:s?.code===1||s?.code===127?as:is}}async function il(e,{retries:t=eO,sleep:n=tO,probe:r=Gy}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:ff});for(let a=0;s===is&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:ff*2});return s}function Y(...e){return["-S",$t,...e]}async function pr(){if(!sl.existsSync($t))return!1;try{return await $e(G,Y("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function Wa(){if(await pr())return!0;try{sl.mkdirSync($t.replace(/\/[^/]+$/,""),{recursive:!0}),await $e(G,Y("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await pr()}function Pe(e){return typeof e=="string"&&nO.test(e)}async function zt(){if(!sl.existsSync($t))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(G,Y("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
86
+ `).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,f,d,p,h]=r.split("|"),w=Number(i),g=Number(h);return{name:o,title:u||null,windows:Number(s),attached:Number(a),lastActivityMs:Number.isFinite(w)?n-w*1e3:null,cwd:c||null,isBostrat:l==="1",sessionId:f||null,agent:d||(l==="1"?"claude":null),alternateOn:p==="1",createdMs:Number.isFinite(g)&&g>0?g*1e3:null}}).filter(r=>!ZR.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function ye(e){return(await zt()).find(n=>n.name===e)||null}function sO(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=oO&&rO.test(t)}function cl(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function Vy(e){try{let{stdout:t}=await $e(G,Y("list-sessions","-F","#{session_name}"));return t.split(`
87
+ `).map(n=>n.trim()).includes(e)}catch{return!1}}function cO(e){let t=String(e||"").trim().split(/\s+/)[0]||"";if(t.includes("/"))return null;let n=[];for(let o=1;o<=t.length-3;o++)n.push(t.slice(o));if(!n.length)return null;let r=n.map(o=>o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp(`\\b(?:${r.join("|")})`)}async function lO(e,t){let n=Date.now()+qa(),r=cO(t),o=!1,s=0;for(;;){if(await cs(aO),s+=1,!await Vy(e))return;let a=await Ce(e,{lines:15}),i=!o&&iO.test(a)&&!!r?.test(a);if(!i&&s>1&&!await Mn(e))return;if(i){o=!0,await se({flow:"spawn",phase:"launch-retry",sessionName:e,agent:fr(t),promptHead:t.slice(0,120)}).catch(()=>{}),await $e(G,Y("send-keys","-t",e,"C-u")),await $e(G,Y("send-keys","-t",e,"-l",t)),await $e(G,Y("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await se({flow:"spawn",phase:"launch-failed",sessionName:e,agent:fr(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function mr(e,t=XR,n={}){if(!sO(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=cl(r);if(!Pe(o))throw new Error("resulting tmux session name is invalid");if(!await Wa())throw new Error(`host tmux server not running on ${$t} and auto-start failed \u2014 start one: ${G} -S ${$t} new-session -d -s keeper "sleep 2147483647"`);if(await Vy(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||pf,a=n.agent||fr(s),i=!!n.resumeSessionId,c=n.resumeSessionId||Wy(),l=i?s:Ha(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),f=a==="claude"&&ro(s),d=n.firstRun===!0;d||(f&&await sr(t),a==="codex"&&await Jo(t),a==="cursor"&&await Xo(t),await hy(t),n.freshWorkspace!==!0&&await el(t));let p=f&&!d?Dc():null,h=Pg(),w=["-e",`${$n}=${h}`];w.push(...Ly({nodeUrl:Fy()})),p&&w.push("-e",`ANTHROPIC_API_KEY=${p}`),f&&w.push(...Ua());try{await $e(G,Y("new-session","-d","-s",o,"-c",t,...w))}catch(g){throw ol(p?ol(g,p):g,h)}return await oo(o),await $e(G,Y("set-option","-t",o,"@bostrat-session","1")),await $e(G,Y("set-option","-t",o,"@bostrat-title",r)),await $e(G,Y("set-option","-t",o,"@bostrat-sid",c)),await $e(G,Y("set-option","-t",o,"@bostrat-agent",a)),await $e(G,Y("send-keys","-t",o,l,"Enter")),QR(l)&&lO(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:h}}async function Yt(e){if(!Pe(e))throw new Error("invalid session name");await $e(G,Y("kill-session","-t",e))}async function zy(e,t){if(Pe(e))try{let n=t?Y("set-option","-t",e,"@bostrat-sid",t):Y("set-option","-u","-t",e,"@bostrat-sid");await $e(G,n)}catch{}}async function Ce(e,{lines:t=40}={}){if(!Pe(e))return"";try{let n=Y("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await $e(G,n);return String(r||"")}catch{return""}}async function Yy(e){if(!Pe(e))return 0;try{let{stdout:t}=await $e(G,Y("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
88
+ `).filter(Boolean).length}catch{return 0}}async function oo(e,{cols:t=fO,rows:n=pO}={}){if(!Pe(e))return!0;if(await Yy(e))return!1;try{let r=await Jy(e);if(r.cols===t&&r.rows===n)return!0;await $e(G,Y("resize-window","-t",e,"-x",String(t),"-y",String(n))),await $e(G,Y("set-window-option","-t",e,"window-size","latest")),await cs(80)}catch{}return!0}async function mO(e){if(!Pe(e))return 0;try{let{stdout:t}=await $e(G,Y("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function Mn(e){let t=await mO(e);if(!t)return!1;try{return await $e("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function Jy(e){if(!Pe(e))return{cols:0,rows:0};try{let{stdout:t}=await $e(G,Y("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 ll(e,{cols:t=uO,rows:n=dO}={}){if(Pe(e)&&!await Yy(e))try{let r=await Jy(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await $e(G,Y("resize-window","-t",e,"-x",String(o),"-y",String(s))),await $e(G,Y("set-window-option","-t",e,"window-size","latest")),await cs(80))}catch{}}async function Nn(e){return await ll(e),Ce(e,{lines:Xe})}async function Le(e,t,{settleMs:n=40,kind:r}={}){if(!Pe(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>hO.has(s));for(let s=0;s<o.length;s++)await $e(G,Y("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await cs(n);return se({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function ls(e,t,{kind:n}={}){if(!Pe(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await $e(G,Y("send-keys","-t",e,"-N",String(r),"BSpace")),se({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function dl(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!Pe(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await $e(G,Y("send-keys","-t",e,"-l",s)),n>0&&await cs(n);se({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function wO(e,t){return new Promise((n,r)=>{let o=Hy(G,Y(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function gO(e,t){let n=`bostrat-${Wy().slice(0,8)}`;await wO(["load-buffer","-b",n,"-"],t),await $e(G,Y("paste-buffer","-p","-d","-b",n,"-t",e))}async function Ze(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!Pe(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await gO(e,t):await $e(G,Y("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await cs(a),await $e(G,Y("send-keys","-t",e,"Enter"))}se({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,G,Uy,$t,XR,pf,Fa,mf,ZR,al,as,is,ff,eO,tO,hf,nO,rO,oO,qa,aO,iO,uO,dO,Xe,fO,pO,hO,ul,lt=L(()=>{Ea();jc();Lc();Ca();tl();dn();Yo();df();$e=YR(Hy);G=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";Uy=typeof process.getuid=="function"?process.getuid():0,$t=JR({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return sl.existsSync(qy(Uy))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:Uy}),XR=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",pf=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",Fa="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";mf="bostrat-usage-probe",ZR=new Set([mf]);al="present",as="absent",is="unknown",ff=5e3,eO=[250,1e3,3e3],tO=e=>new Promise(t=>setTimeout(t,e));hf={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"};nO=/^[A-Za-z0-9_.-]{1,64}$/;rO=/^[A-Za-z0-9 ._↻-]+$/,oO=64;qa=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,aO=1e3,iO=/not found|Unknown command/i;uO=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,dO=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,Xe=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,fO=Number(process.env.BOSTRAT_BOX_COLS)||120,pO=Number(process.env.BOSTRAT_BOX_ROWS)||40;hO=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);ul=1600});import Ka from"node:fs";import SO from"node:fs/promises";import us from"node:path";import TO from"node:os";function yf(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function bf(e){let t=us.join(gf,yf(e)),n;try{n=Ka.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=us.join(t,o);try{let{mtimeMs:a}=Ka.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function Jt(e,t){if(!t)return null;let n=us.join(gf,yf(e),`${t}.jsonl`);return Ka.existsSync(n)?n:null}function rb(e){if(!e)return[];let t=us.join(gf,yf(e)),n;try{n=Ka.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=Ka.statSync(us.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function Et(e,t=131072){let n=await SO.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 AO(e){let t=e.split(`
89
+ `);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 Ga(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=Jt(e,t),o=!0,!r)return null}else if(n){if(r=bf(e),o=!1,!r)return null}else return null;let s;try{s=AO(await Et(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(nb,s.model),i=nb[s.model]||EO;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 nb,EO,gf,Xt=L(()=>{nb={"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},EO=2e5,gf=process.env.BOSTRAT_CLAUDE_PROJECTS||us.join(TO.homedir(),".claude","projects")});function _O(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===`
90
+ `){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function Va(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 za(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 Oe(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(ab(o)){t.has(o)&&r++;continue}n.push(o)}return n}function ib(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 RO(e){let t=ib(e),n=ut(Oe(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${Fe(n)}`:`Read lines ${t.from}\u2013${t.to} of ${Fe(n)}`:e.includes("-i")&&n?`Edit ${Fe(n)}`:null}function kf(e){if(e.includes("--files")){let s=ut(Oe(e,ob)[0]);return s&&s!=="."?`List files in ${ds(s)}`:"List files"}let t=Oe(e,ob),n=t[0];if(!n)return null;let r=ut(t.slice(1).find(s=>s!==".")),o=fs(n,40);return r?`Search for \u201C${o}\u201D in ${ds(r)}`:`Search for \u201C${o}\u201D`}function xf(e){let t=Oe(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 vf(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=Oe(e)[0];return n?`Run ${Fe(n)}`:null}function OO(e){let t=Oe(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 sb(e){return e.find(t=>/^https?:\/\//.test(t))||null}function NO(e){let t=za(Va(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(Fe(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return Sf(t[2]);let n=Fe(t[0]);if(MO.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=CO[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function Sf(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
91
+ `,n);i!==-1&&(t=t.slice(0,i))}let r=_O(t);for(let i=0;i<r.length-1;i++){let c=za(Va(r[i])),l=za(Va(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Fe(c[0]))&&Fe(l[0])==="sed"){let u=ib(l),f=Oe(c)[0];if(u&&f)return fs(u.from===u.to?`Read line ${u.from} of ${Fe(f)}`:`Read lines ${u.from}\u2013${u.to} of ${Fe(f)}`,88)}}let o=[];for(let i of r){let c=NO(i);c&&o.push({d:c,head:Fe(za(Va(i))[0]||""),sub:Oe(za(Va(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":fs(s?s.d:o[0].d,88)}var fs,ut,Fe,ds,ab,ob,IO,$O,CO,MO,cb=L(()=>{fs=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,ut=e=>e&&!/[$`]/.test(e)?e:null,Fe=e=>e.replace(/\/+$/,"").split("/").pop()||e,ds=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},ab=e=>e.startsWith("-"),ob=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);IO={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 ${Fe(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"},$O={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"};CO={git:e=>{let t=Oe(e,new Set(["-C","-c"])),n=IO[t[0]];return n?n(t,e):null},gh:e=>{let t=Oe(e),n=$O[t[0]];return n?n(t):null},sed:RO,rg:kf,grep:kf,egrep:kf,nl:e=>{let t=ut(Oe(e)[0]);return t?`Read ${Fe(t)}`:null},cat:e=>{let t=ut(Oe(e)[0]);return t?`Read ${Fe(t)}`:null},head:e=>{let t=ut(Oe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${Fe(t)}`:null},tail:e=>{let t=ut(Oe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${Fe(t)}`:null},wc:e=>{let t=ut(Oe(e)[0]);return t?`Count lines in ${Fe(t)}`:"Count input lines"},ls:e=>{let t=ut(Oe(e)[0]);return t&&t!=="."?`List files in ${ds(t)}`:"List files"},find:e=>ut(e[1])&&!ab(e[1])&&e[1]!=="."?`Find files in ${ds(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=ut(Oe(e)[0]);return t?`Create directory ${ds(t)}`:null},touch:e=>{let t=ut(Oe(e)[0]);return t?`Create ${Fe(t)}`:null},rm:e=>{let t=ut(Oe(e)[0]);return t?`Delete ${ds(t)}`:null},mv:e=>{let t=ut(Oe(e)[0]);return t?`Move ${Fe(t)}`:null},cp:e=>{let t=ut(Oe(e)[0]);return t?`Copy ${Fe(t)}`:null},chmod:e=>{let t=ut(Oe(e)[1]);return t?`Change permissions on ${Fe(t)}`:null},diff:e=>{let t=Oe(e);return t.length>=2?`Compare ${Fe(t[0])} and ${Fe(t[1])}`:null},curl:e=>{let t=sb(e);return t?`Fetch ${fs(t,56)}`:"Fetch a URL"},wget:e=>{let t=sb(e);return t?`Fetch ${fs(t,56)}`:"Fetch a URL"},npm:xf,pnpm:xf,yarn:xf,npx:e=>{let t=Oe(e)[0];return t?`Run ${t}`:null},node:e=>vf(e,"Node"),python:e=>vf(e,"Python"),python3:e=>vf(e,"Python"),make:e=>{let t=Oe(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:OO,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=Oe(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=Oe(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=Oe(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},MO=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function ps(e){let t=e.split(`
92
+ `).map(n=>n.trim()).find(Boolean)||e;return t.length>88?`${t.slice(0,88).trimEnd()}\u2026`:t}function hr(e,t=""){let n=t.trim();return n||Sf(e)||ps(e)}function Tf(e,t){if(e){if(Array.isArray(e)){for(let n of e)Tf(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&Ef.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))Tf(n,t)}}}async function lb(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await Et(e,t)}catch{return[]}let o=[];for(let s of r.split(`
93
+ `)){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(Tf(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let f of l)o.push({...f,summary:hr(f.command,f.description),ts:u})}return o.slice(-n)}function ub(e,t){let n=t.filter(l=>l.role==="assistant"&&(l.text||"").trim()).sort((l,u)=>(l.ts||0)-(u.ts||0)),r=[...e].sort((l,u)=>(l.ts||0)-(u.ts||0)),o=[],s=0,a=0,i=l=>{let u=l.n??a+1;return u>a&&(a=u),u};for(let l of n){let u=r.findIndex((h,w)=>w>=s&&(h.ts||0)>(l.ts||0)),f=u===-1?r.length:u,d=r.slice(s,f);if(s=f,!d.length)continue;let p=d.map(h=>({...h,n:i(h)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:p,ts:Math.max(...p.map(h=>h.ts||0)),pending:!1})}let c=r.slice(s);if(c.length){let l=c.map(u=>({...u,n:i(u)}));o.push({id:`batch-pending-${l[0]?.box||"lead"}`,anchorTs:null,anchorBox:l[l.length-1]?.box??null,agent:l[l.length-1]?.agent??"claude",boxRole:l[l.length-1]?.boxRole??"lead",commands:l,ts:Math.max(...l.map(u=>u.ts||0)),pending:!0})}return o}var Ef,ms=L(()=>{Xt();cb();Ef=new Set(["Bash"])});import db from"node:fs";import _f from"node:fs/promises";import Af from"node:path";import PO from"node:os";async function fb(e){try{return await _f.realpath(e)}catch{return e}}function BO(e=DO){let t=[],n=r=>{let o;try{o=db.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:db.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function jO(e,t=1048576){let n;try{n=await _f.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(`
94
+ `);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=t)break}return o}finally{await n.close()}}async function LO(e){let t=await jO(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 so(e,t){if(!e&&!t)return null;let n=BO();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await fb(e);for(let o of n){let s=await LO(o.file);if(s&&(s===e||await fb(s)===r))return o}return null}async function pb(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await so(e,t);if(!o)return[];let s;try{s=await Et(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,f=null;for(let d of s.split(`
95
+ `)){let p=d.trim();if(!p||p[0]!=="{")continue;let h;try{h=JSON.parse(p)}catch{continue}if((h.type==="turn_context"&&h.payload?.model||h.type==="session_meta"&&h.payload?.model)&&(i=h.payload.model),h.type==="event_msg"){let E=h.payload?.type;E==="task_started"?(l=!0,u=!1,f=h.payload?.turn_id||null):E==="task_complete"&&l&&(l=!1,!u&&h.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:ao,sourceId:h.payload?.turn_id||f||void 0,ts:h.timestamp?Date.parse(h.timestamp):null,model:i}));continue}if(h.type!=="response_item")continue;let w=h.payload;if(!w)continue;if((w.type==="function_call"||w.type==="custom_tool_call")&&w.name){u=!0,If.has(w.name)||c.push(w.name);continue}if(w.type!=="message"||w.role!=="assistant")continue;u=!0;let g=UO(w.content),b=c.length?c.slice():null;c=[],!(!g&&!b)&&a.push({role:"assistant",text:g,tools:b||void 0,ts:h.timestamp?Date.parse(h.timestamp):null,model:i})}if(i)for(let d of a)d.model||(d.model=i);return a.slice(-n)}function HO(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 WO(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+=`
96
+ `;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 qO(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=WO(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function mb(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await so(e,t);if(!o)return[];let s;try{s=await Et(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
97
+ `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type!=="response_item")continue;let u=l.payload;if(!u)continue;let f=[];if(u.type==="function_call"&&Ya.has(u.name)){let p;try{p=JSON.parse(u.arguments||"{}")}catch{continue}let h=HO(p);h&&(f=[h])}else u.type==="custom_tool_call"&&u.name==="exec"&&(f=qO(u.input));if(!f.length)continue;let d=u.call_id||u.id||null;f.forEach((p,h)=>{a.push({id:d?h?`${d}:${h}`:d:null,tool:u.name,command:p,description:"",summary:hr(p),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function hb(e,t){let n=await so(e,t);if(!n)return null;try{return Math.round((await _f.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var DO,FO,UO,Ya,If,ao,io=L(()=>{Xt();ms();DO=process.env.BOSTRAT_CODEX_SESSIONS||Af.join(process.env.CODEX_HOME||Af.join(PO.homedir(),".codex"),"sessions");FO=new Set(["output_text","text"]),UO=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&FO.has(t.type)).map(t=>t.text).join(`
98
+ `).trim():"";Ya=new Set(["exec_command","shell","exec"]),If=new Set(["wait","write_stdin"]),ao="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 Ja({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&wb.has(r))return wb.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 gb(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||Ja({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===ao?"other":Ja({text:t}),code:null,status:null,requestId:null}}return null}function yb(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:Ja({text:n}),code:null,status:KO(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function KO(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var T5,wb,pl=L(()=>{io();T5=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),wb=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 GO(e,t){return!e||!t?null:Jt(e,t)}function VO(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(`
99
+ `).trim():""}function zO(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 YO(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function $f(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 bb(e,t){if(!e.uuid)return null;let n=$f(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 Rf(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await Et(e,t)}catch{return[]}let o=[],s=new Map;for(let a of r.split(`
100
+ `)){let i=a.trim();if(!i||i[0]!=="{")continue;let c;try{c=JSON.parse(i)}catch{continue}if(c.type==="attachment"){let w=c.attachment;w?.type==="queued_command"&&w.commandMode==="task-notification"&&typeof w.prompt=="string"&&w.prompt.trim()&&o.push({role:"user",text:w.prompt.trim(),ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let l=c.message;if(!l)continue;let u=l.role||c.type;if(u!=="user"&&u!=="assistant"||u==="assistant"&&l.model==="<synthetic>"&&!c.isApiErrorMessage)continue;if(u==="assistant"&&Array.isArray(l.content))for(let w of l.content){let g=w?.type==="tool_use"?w.input?.file_path||w.input?.path:null;typeof g=="string"&&JO.test(g)&&s.set(w.id,g.split("/").pop())}if(YO(l.content)){let w=bb(c,s);w&&o.push({role:"assistant",text:"",images:w,ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let f=VO(l.content),d=u==="assistant"?zO(l.content):null,p=u==="user"?bb(c,s):null;if(!f&&!d&&!p)continue;let h=u==="assistant"&&c.isApiErrorMessage?{code:typeof c.error=="string"?c.error:null,status:Number(c.apiErrorStatus)||null,requestId:c.requestId||null,cls:Ja({error:c.error,status:c.apiErrorStatus,text:f})}:null;o.push({role:u,text:f,tools:d||void 0,images:p||void 0,ts:c.timestamp?Date.parse(c.timestamp):null,model:l.model||null,apiError:h||void 0})}return o.slice(-n)}async function kb(e,t,{turns:n=16}={}){let r=GO(e,t);if(!r)return"";let o=await Rf(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}:** ${XO(s.text||c,700)} ${i}`.trim()}).join(`
101
+
102
+ `):""}var JO,XO,ml=L(()=>{pl();Xt();JO=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;XO=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});import ZO from"node:fs/promises";import{execFile as QO}from"node:child_process";import{promisify as eC}from"node:util";function Tb(e){Cf=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 Eb({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();!r||xb.has(r)||(xb.add(r),vb=vb.then(()=>nC({sessionName:e,from:t,to:r})).catch(()=>{}))}async function nC({sessionName:e,from:t,to:n}){await se({flow:"codex-update",phase:"start",sessionName:e,from:t,to:n}).catch(()=>{});try{let r=(await Of("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await ZO.realpath(r),s=Mf(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await Of("npm",["install","-g","@openai/codex"],{env:a,timeout:tC});let i=(await Of(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await se({flow:"codex-update",phase:"done",sessionName:e,from:t,to:n,version:i}).catch(()=>{}),await Sb({sessionName:e,from:t,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await se({flow:"codex-update",phase:"failed",sessionName:e,from:t,to:n,error:o}).catch(()=>{}),await Sb({sessionName:e,from:t,to:n,status:"failed",error:o})}}async function Sb(e){if(Cf)try{await Cf(e)}catch{}}var Of,tC,xb,vb,Cf,hl=L(()=>{dn();Of=eC(QO),tC=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,xb=new Set,vb=Promise.resolve(),Cf=null});function oC(e,{provider:t,box:n}){let r=String(e).replace(/\r/g,"").split(`
103
+ `);if(!Ab.test(e))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(rC);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"&&Ab.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 co(e){let t=String(e??"").replace(/\r/g,""),n=t.split(`
104
+ `);for(let r=n.length-1;r>=0;r--)if($b.test(n[r]))return n.slice(r).join(`
105
+ `);return t}function sC(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 aC(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 iC(e,t=""){let n=co(e);if(Xa.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
106
+ `),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(_b);if(!u)continue;s<0&&(s=l);let f="";for(let d=l+1;d<Math.min(l+3,r.length);d++){let p=r[d].trim();if(p){if(_b.test(r[d])||/^Press enter/.test(p))break;f=p;break}}o.push({n:Number(u[2]),cursor:!!u[1],label:u[3].trim(),desc:f})}let a=o.sort((l,u)=>l.n-u.n);if(a.length<2||a.some((l,u)=>l.n!==u+1)||!a.some(l=>/Sign in with ChatGPT/.test(l.label)))return null;let i=[];for(let l=0;l<s;l++){let u=r[l].trim();u&&!$b.test(r[l])&&sC(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=aC(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function uC(e,t=""){let n=co(e);if(Xa.test(n)||!cC.test(n))return null;let r=n.trimEnd().split(`
107
+ `).pop()||"";return lC.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 fC(e,t=""){let n=co(e);if(Xa.test(n)||!Ib.test(n))return null;let r=n.split(`
108
+ `),o=r.findIndex(i=>Ib.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(dC);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 pC(e,t=""){let n=co(e);return Xa.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 mC(e,t=""){let n=co(e);return Xa.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 hC(e,t=""){let n=String(e);if(!/Press any key to log in/.test(n)||Nf.test(n))return null;let r=n.replace(/\r/g,"").split(`
109
+ `).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 gC(e,t=""){let n=String(e);if(!wC.test(n)||Nf.test(n))return null;let r=n.replace(/\r/g,"").split(`
110
+ `),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 yC(e,t=""){let n=String(e);return!/Scan this QR code to log in/.test(n)||Nf.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 Rb(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=uC(t,n)||fC(t,n)||pC(t,n)||mC(t,n)||iC(t,n);if(r)return r}if(e==="cursor"){let r=gC(t,n)||yC(t,n)||hC(t,n);if(r)return r}return oC(t,{provider:e,box:n})}function Ob(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 rC,Ab,Xa,$b,_b,cC,lC,Ib,dC,Nf,wC,wl=L(()=>{rC=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,Ab=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;Xa=/(^|\n)\s*›/,$b=/^\s*Welcome to Codex\b/;_b=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;cC=/Successfully logged in\./,lC=/^\s*Press Enter to continue\.\s*$/;Ib=/Enter this one-time code/,dC=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;Nf=/Run Everything|Add a follow-up|Plan, search, build anything/;wC=/click this link to log in|Signing in with the browser/});function vC(e){let t=String(e||"").replace(/\r/g,"").split(`
111
+ `),n=-1;for(let s=t.length-1;s>=0;s--)if(t[s].trim()){n=s;break}if(n<0)return!1;let r=t[n];if(kC.test(r)||xC.test(r)){for(let s=n-1;s>=0&&n-s<=64;s--)if(/^\s*›/.test(t[s]))return!0}return/esc to interrupt|\bWorking \(/.test(String(e||""))}function _C(e){let t=String(e||"");if(!qe.codex.block.test(t))return null;let n=co(t);if(!qe.codex.block.test(n))return null;let r=n.match(AC);return{from:r?.[1]||null,to:r?.[2]||null}}function fn(e){return new Promise(t=>setTimeout(t,e))}function Pf(e,t){let n=Date.now(),r=IC();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 Pb(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
112
+ `),r=-1;for(let o=n.length-1;o>=0;o--)if(Nb.test(n[o])){r=o;break}return r<0?t:n.slice(r+1).join(`
113
+ `)}function RC(e){let t=0;for(let n of String(e).split(`
114
+ `))Nb.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function Df(e,t){let n=qe[e];if(!n?.busy)return{state:"idle",reason:null};if(jf(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(Pb(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=RC(t);return e==="claude"&&r>0&&r<$C?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function Bf(e,t){return Df(e,t).state}function Db(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
115
+ `).slice(-CC).join(`
116
+ `);return OC.test(n)}function ws(e,t){return Bf(e,t)==="busy"}function bl(e,t){return Bf(e,t)!=="idle"}function gs(e,t){let n=qe[e];return n?.up?n.up.test(t):!0}function MC(e,t){let n=qe[e];return n?jf(e,t)?!1:n.up.test(t)&&Bf(e,t)==="idle":!0}function jf(e,t){let n=qe[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 Lf(e,t){let n=String(t||"").trim();if(!n)return e;let r=String(e||"").split(`
117
117
  `);for(let o=r.length-1;o>=0;o--)if(r[o].includes(n))return r.slice(o+1).join(`
118
- `);return e}function Db(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function Ob(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 Cb(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=Bf(await Ce(e),o);if(OC(t,l)){await s?.(),await fn(hs);return}if(qe[t]?.up&&!qe[t].up.test(l))if(await Mn(e)){if(c??=Date.now(),Date.now()-c>=Wa()){let u=Ob(t);throw re({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"&&SC.test(l)&&!qe.claude.up.test(l)){re({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{});return}if(t==="codex"&&vC.test(l)&&!qe.codex.up.test(l)&&i<3){if(!Mf(e,"codex-trust")){await fn(hl);continue}i+=1,await re({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await Ze(e,"",{enter:!0,kind:"codex-trust-accept"}),await fn(hs);continue}if(t==="cursor"&&xC.test(l)&&!qe.cursor.up.test(l)&&i<3){if(!Mf(e,"cursor-trust")){await fn(hl);continue}i+=1,await re({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await Ze(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await fn(hs);continue}if(t==="codex"&&i<3){let u=EC(l);if(u){if(!Mf(e,`codex-update:${u.from}->${u.to}`)){await fn(hl);continue}i+=1,await re({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${u.from} -> ${u.to}`}).catch(()=>{}),await Ze(e,"3",{enter:!1,kind:"codex-update-skip"}),Tb({sessionName:e,from:u.from,to:u.to}),await fn(hs);continue}}if(Date.now()>a){if(Df(t,l)){let u=`${t} is blocked on an interactive prompt`;throw t==="codex"?u=qe.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"&&qe.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"&&qe.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"&&qe.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'),re({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u}).catch(()=>{}),new Error(u)}if(await Mn(e)){let u=Ob(t);throw re({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u.message}).catch(()=>{}),u}console.warn(`[agent-ready] ${t} readiness unconfirmed in ${e} after ${n}ms \u2014 driving the box anyway.`),re({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,paneBlocked:!!qe[t]?.block?.test(l),paneUp:!!qe[t]?.up?.test(l),paneBusy:!!qe[t]?.busy?.test(Nb(qe[t],l))}).catch(()=>{}),await fn(hs);return}await fn(hl)}}function jf({agent:e,agentCmd:t}={}){let n=t?dr(t):dr(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 Bb({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=jf({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function Xa({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}={}){let{realCodex:s,realCursor:a}=jf({agent:n,agentCmd:r});return!t||!s&&!a?null:hr({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).catch(()=>{})}async function hr({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=gC(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:f,realCursor:d}=jf({agent:r,agentCmd:o});if(u&&e&&await or(e),f&&e&&await Jo(e),d&&e&&await Xo(e),(u||f||d)&&n){await Cb(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c});return}let p=qe[r]?r:qe[l]?l:null;if(process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&p){await Cb(n,p,s,{launchEcho:i});return}await fn(hs)}var gC,hl,hs,yC,bC,qe,xC,vC,SC,TC,AC,wl,_C,Mb,$C,RC,Za=j(()=>{lt();Ta();Dc();Bc();pl();ml();dn();gC=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,hl=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,hs=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,yC=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,bC=/^\s*tab to queue message\b/;qe={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:kC},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/}},xC=/Trust this workspace|\[a\]\s*Trust/,vC=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,SC=/Resume from summary/i,TC=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;AC=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,wl=new Map;_C=68,Mb=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;$C=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,RC=15});function PC(e){return typeof e!="string"||!e?!1:e.includes(`
119
- `)?!0:Buffer.byteLength(e,"utf8")>=NC}function pn(e,t){return e==="codex"?{enter:!0,submitDelayMs:CC,...PC(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:MC}:{enter:!0}}var CC,MC,NC,Qa=j(()=>{CC=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),MC=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),NC=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function ei(e,t){if(e==="codex")return FC(t);if(e!=="claude")return null;let n=String(t).replace(/\r/g,"").split(`
120
- `).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(jb.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(jb.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(DC);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 FC(e){let t=String(e).replace(/\r/g,"").split(`
121
- `).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){(BC.test(t[o])||jC.test(t[o]))&&!Lf.test(t[o])?n=o:Lf.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(Lf);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(LC.test(s))return null;r.unshift(s)}return null}function Ff(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=We(n.replace(UC,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!We(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function We(e){return String(e||"").replace(/\s+/g," ").trim()}function Lb(e,t,{slackMs:n=2e4}={}){let r=We(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&&We(a.text).includes(r));return s>=0&&s<o.length-1}function Fb(e,t,n,{busy:r=!1}={}){let o=ei(e,n);return o&&yl(t,o)||o&&e==="codex"&&Ff(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function yl(e,t){let n=We(e),r=We(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var jb,DC,Lf,BC,jC,LC,UC,bl=j(()=>{jb=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,DC=/^❯[  ]?(.*)$/,Lf=/^\s*›[  ]?(.*)$/,BC=/\S+ · \S/,jC=/^\s*(?:\? for shortcuts|tab to queue message)\b/,LC=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;UC=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function ni({sessionName:e,agent:t,agentCmd:n=null,text:r,trackId:o=null,flow:s="say"},a={}){if(!HC.has(t))return!0;let i=a.waitForUp??Bb({agent:t,agentCmd:n}),c=a.capture||(R=>Ce(R,{lines:Xe})),l=a.pressEnter||(R=>Le(R,["Enter"],{kind:"submit-retry"})),u=a.sleep||GC,f=a.now||Date.now,d=a.log||(R=>re(R).catch(()=>{})),p=a.maxMs??KC(),h=f()+p,w={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},g=0,k=0,S=0,E=!1;for(await u(ti[0]);;){let R=await c(e).catch(()=>""),B=gs(t,R),T=ws(t,R),_=Fb(t,r,R,{busy:T});if(_==="submitted")return!0;if(i&&(!B||_==="stuck"&&T)){if(f()>=h)return _==="stuck"?(d({...w,phase:"submit-failed",reason:"stuck-at-deadline",retries:g}),!1):(d({...w,phase:"submit-unverified",reason:E?"cli-down":"cli-never-up",retries:g,waitedMs:p}),!0);await u(WC);continue}if(E=!0,_==="stuck"){if(g>=qC)return d({...w,phase:"submit-failed",retries:g}),!1;g+=1,k=0,S=0,await l(e),d({...w,phase:"submit-retry",attempt:g}),await u(ti[0]);continue}if(k+=1,k>=ti.length||f()>=h)return!0;S+=1,await u(ti[Math.min(S,ti.length-1)])}}var HC,ti,WC,qC,KC,GC,Uf=j(()=>{lt();Za();bl();dn();HC=new Set(["claude","codex"]),ti=[250,450,700],WC=500,qC=2,KC=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},GC=e=>new Promise(t=>setTimeout(t,e))});function Pn(e){let t=String(e||"").toLowerCase();if(!t.trim())return null;let n=null;for(let r of VC){let o=0;for(let s of zC[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function Ub(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))YC.has(r)&&(t+=o||0),JC.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function ri(e){return String(e||"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[-_/]+/g," ")}var VC,zC,YC,JC,kl=j(()=>{VC=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],zC={research:[/\bresearch\b/,/\binvestigat/,/\bverif/,/\bcompar(e|ing|ison)/,/\bcompetit/,/\bdeep[ -]?dive\b/,/\banaly[sz]/,/\bassess/,/\bdiligence\b/,/\bmarket\b/,/\bstrateg/,/\broadmap\b/,/\bnorth star/,/\bwhat('| i)?s the (state|status)\b/,/\bstatus of\b/,/\bexplore\b/,/\bfeasib/,/\bevaluat/,/\bscope out\b/,/\btalk through\b/],"bug-fix":[/\bfix(e[sd]|ing)?\b/,/\bbugs?\b/,/\bbroken\b/,/\bregression\b/,/\bcrash/,/\bincident\b/,/\bdebug/,/\bdoesn'?t (work|render|load|start)/,/\bnot working\b/,/\btroubleshoot/,/\bflaky?\b/,/\brepro(duce|duction)?\b/,/\brace condition\b/,/\bleak\b/],"feature-build":[/\bimplement/,/\bbuild(ing)?\b/,/\badd(ing)?\b/,/\bcreate\b/,/\bwire (it |them )?(up|in)\b/,/\bship(ping)?\b/,/\bintegrat/,/\bsupport for\b/,/\bfeature\b/,/\bendpoint\b/,/\badapter\b/,/\bprototype\b/],design:[/\bdesign/,/\bui\b/,/\bux\b/,/\bstyl(e|es|ing)\b/,/\bcss\b/,/\blayout\b/,/\bmock-?up/,/\brender(ing|s)?\b/,/\bpolish/,/\btheme\b/,/\bfonts?\b/,/\bresponsive\b/,/\banimation/,/\bvisual/,/\bpopover\b/],orchestration:[/\bhand[ -]?(off|over)/,/\bhand (it|the lead|this) (over|off)\b/,/\bdelegat/,/\bsubtask/,/\bmerge[ -]?back\b/,/\borchestrat/,/\b(switch|change) (the )?model\b/,/\bmodel switch/],"docs-writing":[/\bdocs?\b/,/\bdocument/,/\bmemo\b/,/\breadme\b/,/\bwrite-?up\b/,/\bchangelog\b/,/\bclaude\.md\b/,/\bblog/,/\bproofread/,/\bcopy(edit|writ)/],"ops-infra":[/\bdeploy/,/\bsystemd\b/,/\bdaemon\b/,/\btmux\b/,/\bdns\b/,/\bwireguard\b/,/\brestart/,/\bnginx\b/,/\bprovision/,/\binstall/,/\bupgrade/,/\bcron\b/,/\bbackups?\b/,/\bcertificat/,/\bssh\b/,/\bsecrets?\b/]};YC=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),JC=new Set(["Edit","Write","MultiEdit","NotebookEdit"])});function Kb(e){let t=ri(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||XC.has(r)||n.push(r);return n}function ZC(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(qb(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(qb(n,"assistant",o))}}return t}function qb(e,t,n){let r=Pn(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 oi(e){let t=ZC(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=Kb(a.text);r[i]=c.length,o+=c.length;let l=new Map;for(let u of c)l.set(u,(l.get(u)||0)+1);for(let[u,f]of l){let d=n.get(u);d||n.set(u,d=new Map),d.set(i,f)}});let s=t.length;return{chunks:t,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function xl(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(Kb(t))];if(!i.length)return[];let c=new Map;for(let u of i){let f=e.postings.get(u);if(!f)continue;let d=f.size,p=Math.log(1+(e.N-d+.5)/(d+.5));for(let[h,w]of f){let g=e.lengths[h],k=w+Hb*(1-Wb+Wb*(g/(e.avgdl||1))),S=p*(w*(Hb+1)/k);c.set(h,(c.get(h)||0)+S)}}let l=[];for(let[u,f]of c){let d=e.chunks[u];o&&d.role!==o||s&&!d.tags.includes(s)||a&&d.boxId!==a||l.push({chunk:d,score:f})}return l.sort((u,f)=>f.score-u.score||f.chunk.seq-u.chunk.seq),l.slice(0,r)}var Hb,Wb,XC,Hf=j(()=>{kl();Hb=1.5,Wb=.75,XC=new Set("a an and are as at be been but by for from had has have he her his i if in into is it its of on or our so than that the their them then there these they this those to was were will with would you your we".split(" "))});import vl from"node:fs/promises";import Gb from"node:path";async function QC(e){let t=Gb.join(e,".bostrat","events"),n;try{n=await vl.readdir(t)}catch{return oi([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await vl.readFile(Gb.join(t,o),"utf8");for(let a of s.split(`
122
- `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return oi(r)}function eM(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}
123
- ${o}`.trim()||t.slice(0,2e3)}function tM(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=xl(e,t,{k:n*2+4}),a=[],i=0;for(let{chunk:c}of s){if(o&&o(c))continue;let l=c.role==="user"?"Operator":`Agent${c.provider?` (${c.provider})`:""}`,u=c.text.trim(),f=u.length>800?u.slice(0,800)+"\u2026":u,d=`- **${l}:** ${f}`;if(i+d.length>r||(a.push(d),i+=d.length,a.length>=n))break}return a.length?["",`## ${Vb}, 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(`
124
- `):""}async function zb(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await vl.readFile(t,"utf8");if(a.includes(Vb))return{appended:!1,reason:"already-enriched"};let i=await QC(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=tM(i,eM(a),{k:r,maxChars:o,exclude:s});return c?(await vl.appendFile(t,`
118
+ `);return e}function Bb(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function Cb(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 Mb(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=Lf(await Ce(e),o);if(MC(t,l)){await s?.(),await fn(hs);return}if(qe[t]?.up&&!qe[t].up.test(l))if(await Mn(e)){if(c??=Date.now(),Date.now()-c>=qa()){let u=Cb(t);throw se({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"&&EC.test(l)&&!qe.claude.up.test(l)){se({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{});return}if(t==="codex"&&TC.test(l)&&!qe.codex.up.test(l)&&i<3){if(!Pf(e,"codex-trust")){await fn(gl);continue}i+=1,await se({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await Ze(e,"",{enter:!0,kind:"codex-trust-accept"}),await fn(hs);continue}if(t==="cursor"&&SC.test(l)&&!qe.cursor.up.test(l)&&i<3){if(!Pf(e,"cursor-trust")){await fn(gl);continue}i+=1,await se({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await Ze(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await fn(hs);continue}if(t==="codex"&&i<3){let u=_C(l);if(u){if(!Pf(e,`codex-update:${u.from}->${u.to}`)){await fn(gl);continue}i+=1,await se({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${u.from} -> ${u.to}`}).catch(()=>{}),await Ze(e,"3",{enter:!1,kind:"codex-update-skip"}),Eb({sessionName:e,from:u.from,to:u.to}),await fn(hs);continue}}if(Date.now()>a){if(jf(t,l)){let u=`${t} is blocked on an interactive prompt`;throw t==="codex"?u=qe.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"&&qe.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"&&qe.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"&&qe.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'),se({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u}).catch(()=>{}),new Error(u)}if(await Mn(e)){let u=Cb(t);throw se({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u.message}).catch(()=>{}),u}console.warn(`[agent-ready] ${t} readiness unconfirmed in ${e} after ${n}ms \u2014 driving the box anyway.`),se({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,paneBlocked:!!qe[t]?.block?.test(l),paneUp:!!qe[t]?.up?.test(l),paneBusy:!!qe[t]?.busy?.test(Pb(qe[t],l))}).catch(()=>{}),await fn(hs);return}await fn(gl)}}function Ff({agent:e,agentCmd:t}={}){let n=t?fr(t):fr(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 jb({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=Ff({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function Za({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}={}){let{realCodex:s,realCursor:a}=Ff({agent:n,agentCmd:r});return!t||!s&&!a?null:wr({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).catch(()=>{})}async function wr({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=bC(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:f,realCursor:d}=Ff({agent:r,agentCmd:o});if(u&&e&&await sr(e),f&&e&&await Jo(e),d&&e&&await Xo(e),(u||f||d)&&n){await Mb(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c});return}let p=qe[r]?r:qe[l]?l:null;if(process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&p){await Mb(n,p,s,{launchEcho:i});return}await fn(hs)}var bC,gl,hs,kC,xC,qe,SC,TC,EC,AC,IC,yl,$C,Nb,OC,CC,Qa=L(()=>{lt();Ea();jc();Lc();hl();wl();dn();bC=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,gl=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,hs=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,kC=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,xC=/^\s*tab to queue message\b/;qe={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:vC},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/}},SC=/Trust this workspace|\[a\]\s*Trust/,TC=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,EC=/Resume from summary/i,AC=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;IC=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,yl=new Map;$C=68,Nb=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;OC=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,CC=15});function BC(e){return typeof e!="string"||!e?!1:e.includes(`
119
+ `)?!0:Buffer.byteLength(e,"utf8")>=DC}function pn(e,t){return e==="codex"?{enter:!0,submitDelayMs:NC,...BC(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:PC}:{enter:!0}}var NC,PC,DC,ei=L(()=>{NC=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),PC=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),DC=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function ti(e,t){if(e==="codex")return HC(t);if(e!=="claude")return null;let n=String(t).replace(/\r/g,"").split(`
120
+ `).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(Lb.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(Lb.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(jC);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 HC(e){let t=String(e).replace(/\r/g,"").split(`
121
+ `).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){(LC.test(t[o])||FC.test(t[o]))&&!Uf.test(t[o])?n=o:Uf.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(Uf);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(UC.test(s))return null;r.unshift(s)}return null}function Hf(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=We(n.replace(WC,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!We(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function We(e){return String(e||"").replace(/\s+/g," ").trim()}function Fb(e,t,{slackMs:n=2e4}={}){let r=We(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&&We(a.text).includes(r));return s>=0&&s<o.length-1}function Ub(e,t,n,{busy:r=!1}={}){let o=ti(e,n);return o&&kl(t,o)||o&&e==="codex"&&Hf(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function kl(e,t){let n=We(e),r=We(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var Lb,jC,Uf,LC,FC,UC,WC,xl=L(()=>{Lb=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,jC=/^❯[  ]?(.*)$/,Uf=/^\s*›[  ]?(.*)$/,LC=/\S+ · \S/,FC=/^\s*(?:\? for shortcuts|tab to queue message)\b/,UC=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;WC=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function ri({sessionName:e,agent:t,agentCmd:n=null,text:r,trackId:o=null,flow:s="say"},a={}){if(!qC.has(t))return!0;let i=a.waitForUp??jb({agent:t,agentCmd:n}),c=a.capture||(R=>Ce(R,{lines:Xe})),l=a.pressEnter||(R=>Le(R,["Enter"],{kind:"submit-retry"})),u=a.sleep||zC,f=a.now||Date.now,d=a.log||(R=>se(R).catch(()=>{})),p=a.maxMs??VC(),h=f()+p,w={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},g=0,b=0,E=0,S=!1;for(await u(ni[0]);;){let R=await c(e).catch(()=>""),M=gs(t,R),T=ws(t,R),A=Ub(t,r,R,{busy:T});if(A==="submitted")return!0;if(i&&(!M||A==="stuck"&&T)){if(f()>=h)return A==="stuck"?(d({...w,phase:"submit-failed",reason:"stuck-at-deadline",retries:g}),!1):(d({...w,phase:"submit-unverified",reason:S?"cli-down":"cli-never-up",retries:g,waitedMs:p}),!0);await u(KC);continue}if(S=!0,A==="stuck"){if(g>=GC)return d({...w,phase:"submit-failed",retries:g}),!1;g+=1,b=0,E=0,await l(e),d({...w,phase:"submit-retry",attempt:g}),await u(ni[0]);continue}if(b+=1,b>=ni.length||f()>=h)return!0;E+=1,await u(ni[Math.min(E,ni.length-1)])}}var qC,ni,KC,GC,VC,zC,Wf=L(()=>{lt();Qa();xl();dn();qC=new Set(["claude","codex"]),ni=[250,450,700],KC=500,GC=2,VC=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},zC=e=>new Promise(t=>setTimeout(t,e))});function Hb(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function Pn(e){let t=Hb(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of YC){let o=0;for(let s of JC[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function Wb(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))XC.has(r)&&(t+=o||0),ZC.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function oi(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 qb(e){let t=Hb(e).trim();return t?eM.test(t)?!0:t.split(/\s+/).length<=QC:!1}var YC,JC,XC,ZC,QC,eM,vl=L(()=>{YC=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],JC={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/],"bug-fix":[/\bfix(e[sd]|ing)?\b/,/\bbugs?\b/,/\bbroken\b/,/\bregression\b/,/\bcrash/,/\bincident\b/,/\bdebug/,/\bdoesn'?t (work|render|load|start)/,/\bnot working\b/,/\btroubleshoot/,/\bflaky?\b/,/\brepro(duce|duction)?\b/,/\brace condition\b/,/\bleak\b/],"feature-build":[/\bimplement/,/\bbuild(ing)?\b/,/\badd(ing)?\b/,/\bcreate\b/,/\bwire (it |them )?(up|in)\b/,/\bship(ping)?\b/,/\bintegrat/,/\bsupport for\b/,/\bfeature\b/,/\bendpoint\b/,/\badapter\b/,/\bprototype\b/],design:[/\bdesign/,/\bui\b/,/\bux\b/,/\bstyl(e|es|ing)\b/,/\bcss\b/,/\blayout\b/,/\bmock-?up/,/\brender(ing|s)?\b/,/\bpolish/,/\btheme\b/,/\bfonts?\b/,/\bresponsive\b/,/\banimation/,/\bvisual/,/\bpopover\b/],orchestration:[/\bhand[ -]?(off|over)/,/\bhand (it|the lead|this) (over|off)\b/,/\bdelegat/,/\bsubtask/,/\bmerge[ -]?back\b/,/\borchestrat/,/\b(switch|change) (the )?model\b/,/\bmodel switch/],"docs-writing":[/\bdocs?\b/,/\bdocument/,/\bmemo\b/,/\breadme\b/,/\bwrite-?up\b/,/\bchangelog\b/,/\bclaude\.md\b/,/\bblog/,/\bproofread/,/\bcopy(edit|writ)/],"ops-infra":[/\bdeploy/,/\bsystemd\b/,/\bdaemon\b/,/\btmux\b/,/\bdns\b/,/\bwireguard\b/,/\brestart/,/\bnginx\b/,/\bprovision/,/\binstall/,/\bupgrade/,/\bcron\b/,/\bbackups?\b/,/\bcertificat/,/\bssh\b/,/\bsecrets?\b/]};XC=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),ZC=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);QC=12,eM=/^\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 zb(e){let t=oi(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||tM.has(r)||n.push(r);return n}function nM(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(Vb(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(Vb(n,"assistant",o))}}return t}function Vb(e,t,n){let r=Pn(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 si(e){let t=nM(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=zb(a.text);r[i]=c.length,o+=c.length;let l=new Map;for(let u of c)l.set(u,(l.get(u)||0)+1);for(let[u,f]of l){let d=n.get(u);d||n.set(u,d=new Map),d.set(i,f)}});let s=t.length;return{chunks:t,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function Sl(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(zb(t))];if(!i.length)return[];let c=new Map;for(let u of i){let f=e.postings.get(u);if(!f)continue;let d=f.size,p=Math.log(1+(e.N-d+.5)/(d+.5));for(let[h,w]of f){let g=e.lengths[h],b=w+Kb*(1-Gb+Gb*(g/(e.avgdl||1))),E=p*(w*(Kb+1)/b);c.set(h,(c.get(h)||0)+E)}}let l=[];for(let[u,f]of c){let d=e.chunks[u];o&&d.role!==o||s&&!d.tags.includes(s)||a&&d.boxId!==a||l.push({chunk:d,score:f})}return l.sort((u,f)=>f.score-u.score||f.chunk.seq-u.chunk.seq),l.slice(0,r)}var Kb,Gb,tM,qf=L(()=>{vl();Kb=1.5,Gb=.75,tM=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 Tl from"node:fs/promises";import Yb from"node:path";async function rM(e){let t=Yb.join(e,".bostrat","events"),n;try{n=await Tl.readdir(t)}catch{return si([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await Tl.readFile(Yb.join(t,o),"utf8");for(let a of s.split(`
122
+ `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return si(r)}function oM(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}
123
+ ${o}`.trim()||t.slice(0,2e3)}function sM(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=Sl(e,t,{k:n*2+4}),a=[],i=0;for(let{chunk:c}of s){if(o&&o(c))continue;let l=c.role==="user"?"Operator":`Agent${c.provider?` (${c.provider})`:""}`,u=c.text.trim(),f=u.length>800?u.slice(0,800)+"\u2026":u,d=`- **${l}:** ${f}`;if(i+d.length>r||(a.push(d),i+=d.length,a.length>=n))break}return a.length?["",`## ${Jb}, 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(`
124
+ `):""}async function Xb(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await Tl.readFile(t,"utf8");if(a.includes(Jb))return{appended:!1,reason:"already-enriched"};let i=await rM(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=sM(i,oM(a),{k:r,maxChars:o,exclude:s});return c?(await Tl.appendFile(t,`
125
125
  `+c),{appended:!0,chars:c.length,chunks:c.split(`
126
- - `).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 Vb,Yb=j(()=>{Hf();Vb="Relevant prior discussion (verbatim, retrieved"});function iM(e){return nM.test(String(e||"").trimStart())}function Zb(e){let t=String(e||"");if(!iM(t.trimStart()))return null;let n=t.replace(rM,"").trim(),r=cM(n),o=[];for(let u of sM){let f=u.from.map(d=>ys(r.get(d))).find(d=>d&&!Jb(d));f&&o.push({h:u.h,text:si(f,oM)})}let s=ys(r.get("Current Work"))||ys(r.get("Primary Request and Intent"))||uM(n),a=Tl(s),i=si(Sl(Kf(a[0]||"")),aM)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(si(Sl(Kf(l)),qf));for(let u of["Pending Tasks","Optional Next Step"]){let f=Tl(ys(r.get(u)))[0]||"";if(!(!f||Jb(f))){c.push(si(`Left to do: ${Sl(Kf(f))}`,qf));break}}if(!c.length){let u=Tl(ys(r.get("Problem Solving"))||"")[0];u&&c.push(si(Sl(u),qf))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function cM(e){let t=new Map,n=[];Wf.lastIndex=0;for(let r=Wf.exec(e);r;r=Wf.exec(e))n.push({name:lM(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 lM(e){return Xb.find(n=>n.toLowerCase()===e.toLowerCase())||e}function ys(e){return e?String(e).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
127
- `).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 uM(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return ys(t.split(/\n{2,}/).slice(0,2).join(" "))}function Tl(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 Kf(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 Sl(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function Jb(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function si(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=Tl(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 nM,Xb,Wf,rM,oM,sM,aM,qf,Qb=j(()=>{nM=/^This session is being continued from a previous conversation that ran out of context\./,Xb=["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}(${Xb.join("|")})[:*\t ]*$`,"gim"),rM=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,oM=420,sM=[{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"]}],aM=116,qf=168});function tk(e){return Gf.has(String(e||"").replace(/^\//,"").toLowerCase())}function El(e){let t=String(e||"").trim();if(!t)return null;let n=Zb(t);if(n)return n;let r=t.match(dM);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(fM);if(o)return{kind:"skill",name:o[1]};let s=t.match(pM);if(s){let i=s[1].toLowerCase();return Gf.has(i)?{kind:"suppress"}:{kind:"command",command:`/${i}`}}let a=t.match(SM);if(a&&Gf.has(a[1].toLowerCase()))return{kind:"suppress"};if(mM.test(t))return{kind:"suppress"};if(wM.test(t))return{kind:"suppress"};if(hM.test(t))return{kind:"suppress"};if(gM.test(t)){let i=l=>TM(t.match(l)?.[1].trim()||"")||null,c=i(vM);return{kind:"task",summary:i(yM)||"",taskId:i(bM),toolUseId:i(kM),status:i(xM)?.toLowerCase()||null,resultHead:c?c.length>ek?`${c.slice(0,ek).trimEnd()}\u2026`:c:null}}return null}function TM(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function nk(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 rk(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var dM,fM,pM,mM,hM,wM,gM,yM,bM,kM,xM,vM,ek,Gf,SM,Vf=j(()=>{Qb();dM=/^Base directory for this skill:\s*(\S+)/,fM=/^Run the "([^"]+)" workflow\./,pM=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,mM=/^<local-command-(?:stdout|caveat)>/i,hM=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,wM=/^Continue from where you left off\.$/,gM=/^<task-notification>/i,yM=/<summary>([\s\S]*?)<\/summary>/i,bM=/<task-id>([\s\S]*?)<\/task-id>/i,kM=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,xM=/<status>([\s\S]*?)<\/status>/i,vM=/<result>([\s\S]*?)(?:<\/result>|$)/i,ek=600,Gf=new Set(["model","clear","compact","login","exit","quit"]);SM=/^\/([a-z0-9:_-]+)$/i});import EM from"node:crypto";function $M(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,sk)){let o=ai(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,AM)){let c=ai(i?.label);if(!c)return null;let l=ai(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<_M)return null;n.push({question:o,header:ai(r?.header).slice(0,IM),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function zf(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;ok.lastIndex=0;let t=null;for(let o;o=ok.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=$M(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function Yf(e,t,n){let r=EM.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function Jf(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=sk}={}){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||zf(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=Yf(n,s.sourceId||s.id,a);return typeof r=="function"&&r(c)?null:{provider:n,box:t,promptId:c,groupId:c,answerMode:"say",source:"transcript",multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function ak(e,t,n){let r=[];(e?.questions||[]).forEach((a,i)=>{let c=(t?.[i]||[]).map(l=>a.options?.[l]?.label).filter(Boolean);c.length&&r.push({name:a.header||a.question,picks:c.join(", ")})});let o=ai(n),s;return r.length?r.length===1?s=`${r[0].name}: ${r[0].picks}`:s=`Answers:
126
+ - `).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 Jb,Zb=L(()=>{qf();Jb="Relevant prior discussion (verbatim, retrieved"});function dM(e){return aM.test(String(e||"").trimStart())}function tk(e){let t=String(e||"");if(!dM(t.trimStart()))return null;let n=t.replace(iM,"").trim(),r=fM(n),o=[];for(let u of lM){let f=u.from.map(d=>ys(r.get(d))).find(d=>d&&!Qb(d));f&&o.push({h:u.h,text:ai(f,cM)})}let s=ys(r.get("Current Work"))||ys(r.get("Primary Request and Intent"))||mM(n),a=Al(s),i=ai(El(Vf(a[0]||"")),uM)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(ai(El(Vf(l)),Gf));for(let u of["Pending Tasks","Optional Next Step"]){let f=Al(ys(r.get(u)))[0]||"";if(!(!f||Qb(f))){c.push(ai(`Left to do: ${El(Vf(f))}`,Gf));break}}if(!c.length){let u=Al(ys(r.get("Problem Solving"))||"")[0];u&&c.push(ai(El(u),Gf))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function fM(e){let t=new Map,n=[];Kf.lastIndex=0;for(let r=Kf.exec(e);r;r=Kf.exec(e))n.push({name:pM(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 pM(e){return ek.find(n=>n.toLowerCase()===e.toLowerCase())||e}function ys(e){return e?String(e).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
127
+ `).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 mM(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return ys(t.split(/\n{2,}/).slice(0,2).join(" "))}function Al(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 Vf(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 El(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function Qb(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function ai(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=Al(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 aM,ek,Kf,iM,cM,lM,uM,Gf,nk=L(()=>{aM=/^This session is being continued from a previous conversation that ran out of context\./,ek=["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"],Kf=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${ek.join("|")})[:*\t ]*$`,"gim"),iM=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,cM=420,lM=[{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"]}],uM=116,Gf=168});function ok(e){return zf.has(String(e||"").replace(/^\//,"").toLowerCase())}function bs(e){let t=String(e||"").trim();if(!t)return null;let n=tk(t);if(n)return n;let r=t.match(hM);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(wM);if(o)return{kind:"skill",name:o[1]};let s=t.match(gM);if(s){let i=s[1].toLowerCase();return zf.has(i)?{kind:"suppress"}:{kind:"command",command:`/${i}`}}let a=t.match(_M);if(a&&zf.has(a[1].toLowerCase()))return{kind:"suppress"};if(yM.test(t))return{kind:"suppress"};if(kM.test(t))return{kind:"suppress"};if(bM.test(t))return{kind:"suppress"};if(xM.test(t)){let i=l=>IM(t.match(l)?.[1].trim()||"")||null,c=i(AM);return{kind:"task",summary:i(vM)||"",taskId:i(SM),toolUseId:i(TM),status:i(EM)?.toLowerCase()||null,resultHead:c?c.length>rk?`${c.slice(0,rk).trimEnd()}\u2026`:c:null}}return null}function IM(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function sk(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 ak(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var hM,wM,gM,yM,bM,kM,xM,vM,SM,TM,EM,AM,rk,zf,_M,_l=L(()=>{nk();hM=/^Base directory for this skill:\s*(\S+)/,wM=/^Run the "([^"]+)" workflow\./,gM=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,yM=/^<local-command-(?:stdout|caveat)>/i,bM=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,kM=/^Continue from where you left off\.$/,xM=/^<task-notification>/i,vM=/<summary>([\s\S]*?)<\/summary>/i,SM=/<task-id>([\s\S]*?)<\/task-id>/i,TM=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,EM=/<status>([\s\S]*?)<\/status>/i,AM=/<result>([\s\S]*?)(?:<\/result>|$)/i,rk=600,zf=new Set(["model","clear","compact","login","exit","quit"]);_M=/^\/([a-z0-9:_-]+)$/i});import $M from"node:crypto";function MM(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,ck)){let o=ii(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,RM)){let c=ii(i?.label);if(!c)return null;let l=ii(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<OM)return null;n.push({question:o,header:ii(r?.header).slice(0,CM),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Yf(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;ik.lastIndex=0;let t=null;for(let o;o=ik.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=MM(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function Jf(e,t,n){let r=$M.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function Xf(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=ck}={}){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||Yf(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=Jf(n,s.sourceId||s.id,a);return typeof r=="function"&&r(c)?null:{provider:n,box:t,promptId:c,groupId:c,answerMode:"say",source:"transcript",multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function lk(e,t,n){let r=[];(e?.questions||[]).forEach((a,i)=>{let c=(t?.[i]||[]).map(l=>a.options?.[l]?.label).filter(Boolean);c.length&&r.push({name:a.header||a.question,picks:c.join(", ")})});let o=ii(n),s;return r.length?r.length===1?s=`${r[0].name}: ${r[0].picks}`:s=`Answers:
128
128
  ${r.map(a=>`- ${a.name}: ${a.picks}`).join(`
129
129
  `)}`:s=o,r.length&&o&&(s+=`
130
- ${o}`),s||""}var sk,AM,_M,IM,ok,ai,ik,Xf=j(()=>{sk=4,AM=4,_M=2,IM=24,ok=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,ai=e=>typeof e=="string"?e.trim():"";ik=`
130
+ ${o}`),s||""}var ck,RM,OM,CM,ik,ii,uk,Zf=L(()=>{ck=4,RM=4,OM=2,CM=24,ik=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,ii=e=>typeof e=="string"?e.trim():"";uk=`
131
131
  When you are BLOCKED on a decision only the operator can make \u2014 an ambiguous
132
132
  requirement, an irreversible choice, several valid approaches \u2014 do not bury the
133
133
  question in prose. End your message with exactly ONE fenced code block tagged
@@ -147,76 +147,76 @@ your turn. The operator sees the questions as an interactive card in their chat
147
147
  answer. Never use the block for rhetorical questions, progress updates, or
148
148
  anything you can decide yourself; keep asking in prose for questions without
149
149
  enumerable options.
150
- `});function RM(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 CM(e,t,n){let r=ck(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 wr(e){let t=[],n=new Set,r=new Set,o=new Map,s=new Map,a=new Set,i=new Map,c=new Set,l=new Map,u=new Map,f=(y,m)=>{u.set(y,m),t.push(m)},d=y=>{let m=u.get(y);m&&(m.retired=!0)},p=/^Agent "([\s\S]+)" finished$/,h=new Map;for(let y of e||[]){if(y.type!=="tool.called"||y.source!=="transcript")continue;let m=String(y.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(m))for(let b of m.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let M=b[0].split("/").pop().toLowerCase();h.has(M)||h.set(M,[]),h.get(M).push(y.payload?.ts??y.ts)}}let w=3*6e4,g=20*6e4,k=(y,m)=>!!(y?.name&&h.get(String(y.name).toLowerCase()))?.some(M=>M>=m-w&&M<=m+g);for(let y of e||[])if(y.type==="turn.retracted"){r.add(`${y.boxId}|${y.payload?.saidTs}`);let m=We(y.payload?.text);m&&(o.has(y.boxId)||o.set(y.boxId,[]),o.get(y.boxId).push(m))}else if(y.type==="turn.user"&&y.source==="orchestrator"){let m=We(y.payload?.text);m&&(s.has(y.boxId)||s.set(y.boxId,new Set),s.get(y.boxId).add(m))}else if(y.type==="job.started"&&y.payload?.id)a.add(y.payload.id),(y.payload.kind||"agent")==="agent"&&y.payload.name&&c.add(y.payload.name);else if(y.type==="turn.user"&&y.payload?.note?.kind==="task"){let m=y.payload.note,b={status:m.status||null,summary:m.summary||null,resultHead:m.resultHead??null,ts:fe(y)};m.toolUseId&&i.set(m.toolUseId,b);let M=String(m.summary||"").match(p);M&&l.set(M[1],b)}let S=new Map,E=new Map,R=null,B=new Map,T=new Map,_=new Map,O=new Map,I=new Map,U=new Map,H=new Map,ae=new Map,X=new Map,C=new Map,Q=new Map,ve=new Map,W=new Map,be=new Map,se=new Map,pe=[],ie=y=>pe.push(y),L=y=>{if(!pe.length)return;let m=fe(y);for(let b of pe){if(b.status!=="open"||b.box&&b.box!==y.boxId||(b.ts??0)>m)continue;let M=t.indexOf(b);M>=0&&t.splice(M,1),b.ts=m,t.push(b)}},ce=new Map,ue=new Map,Ae=new Map,_e=new Map,xt=new Map,je=new Map,A=()=>{for(let y of je.values())y.questions.length&&t.push(y);je.clear()},G=null,Ge=6e4,_t=new Map,at=(y,m)=>{let b=o.get(y);if(!b?.length)return!1;let M=We(m),ne=s.get(y);return b.some(de=>{if(!M.startsWith(de))return!1;let De=We(M.slice(de.length));return!!De&&!!ne?.has(De)})};for(let y of e||[]){let m=y.payload||{};switch(y.type){case"turn.user":{if(y.source==="hook"||(pe.length=0,!String(m.text||"").trim()&&!m.images?.length&&!m.attachments?.length))break;{let b=m.note||El(m.text);if(b){if(b.kind==="task"){if(b.toolUseId&&a.has(b.toolUseId))break;let M=String(b.summary||"").match(p);if(!b.toolUseId&&M&&c.has(M[1]))break}if(b.kind==="command"&&tk(b.command))break;if(b.kind==="resume-summary"){t.push({id:y.id,kind:"resume-summary",title:b.title||"Context resumed from summary",bullets:b.bullets||[],sections:b.sections||[],rawChars:b.rawChars??null,ts:fe(y),box:y.boxId,agent:y.provider});break}b.kind!=="suppress"&&t.push({id:y.id,kind:"event",type:rk(b),name:b.name??null,command:b.command??null,summary:b.summary??null,status:b.status??null,ts:fe(y),box:y.boxId,agent:y.provider});break}}if(r.has(`${y.boxId}|${fe(y)}`)||y.source==="transcript"&&at(y.boxId,m.text))break;if(m.kind==="merge-notify"||m.kind==="ship-notify"){t.push({id:y.id,kind:"event",type:m.kind==="ship-notify"?"ship-notified":"merge-notified",text:m.text,ts:fe(y),box:y.boxId,agent:y.provider});break}if(m.kind==="mock-picked"||m.kind==="ci-fix"||m.kind==="reconcile"||m.kind==="pr-go"||m.kind==="push-go"||m.kind==="spin-up-view"||m.kind==="prompt-answer"||m.kind==="followup-go"){m.kind==="prompt-answer"&&(G=null);break}for(let b of B.values())b.status="stale";B.clear();for(let b of _.values())b.status="stale";_.clear();for(let b of W.values())b.status="stale";W.clear(),G&&G.box===y.boxId&&(t.push(RM(G)),G=null),t.push({id:y.id,kind:"message",role:"user",text:m.text,ts:fe(y),box:y.boxId,agent:y.provider,boxRole:m.boxRole,...y.actor==="orchestrator"?{orchestration:m.kind||!0}:{},...m.sourceId?{sourceId:m.sourceId}:{},...m.attachments?.length?{attachments:m.attachments}:{},...m.images?.length?{images:m.images}:{}});break}case"peer.message":{let b=m.from||{};t.push({id:y.id,kind:"event",type:"peer-message",text:m.text,from:b.trackName||b.boxId||b.name||null,fromTrackId:b.trackId||null,ts:fe(y),box:y.boxId,agent:y.provider});break}case"turn.agent":{if(m.model==="<synthetic>"&&/^No response requested\.$/.test(String(m.text||"").trim()))break;let b=gb(m,{codexFailedText:ao});if(b){t.push({id:y.id,kind:"event",type:"provider-error",cls:b.cls,status:b.status??void 0,text:b.text,provider:y.provider,legacy:!0,at:fe(y),ts:fe(y),box:y.boxId,agent:y.provider});break}A();let M=(m.images||[]).filter(Re=>!k(Re,fe(y)));if(!String(m.text||"").trim()&&!M.length)break;if(y.provider==="cursor"){let Re=`${y.boxId}|${m.text}`;if(n.has(Re))break;n.add(Re)}(!G||G.box===y.boxId)&&(G=null);let ne=y.provider==="codex"?(m.tools||[]).filter(Re=>!Af.has(Re)&&!za.has(Re)):m.tools||[],de=m.text,De=null,ht=zf(String(m.text||""));ht&&(de=ht.text,De={questions:ht.questions}),t.push({id:y.id,kind:"message",role:"assistant",text:de,ts:fe(y),box:y.boxId,agent:y.provider,boxRole:m.boxRole,...De?{ask:De}:{},...ne.length?{tools:ne}:{},...m.model?{model:m.model}:{},...m.sourceId?{sourceId:m.sourceId}:{},...M.length?{images:M}:{}}),L(y),De&&(G={id:y.id,groupId:Yf(y.provider,m.sourceId||y.id,De.questions),provider:y.provider,box:y.boxId,questions:De.questions,ts:fe(y)});break}case"job.started":{if(!m.id)break;let b=fe(y),M=i.get(m.id);if(!M&&(m.kind||"agent")==="agent"&&m.name){let Re=l.get(m.name);Re&&Re.ts>=b&&(M=Re)}let ne={jobId:m.id,jobKind:m.kind||"agent",name:m.name||null,detail:m.detail||null,status:M?M.status==="killed"?"stopped":M.status&&M.status!=="completed"?"failed":"done":"running",startedTs:b,finishedTs:M?.ts??null,summary:M?.summary??null,resultHead:M?.resultHead??null},de=_t.get(y.boxId),De=de?.jobs[de.jobs.length-1]?.startedTs;if(de&&De!=null&&b-De<=Ge)de.jobs.push(ne);else{let Re={id:y.id,kind:"job-dock",dockId:m.id,ts:b,box:y.boxId,agent:y.provider,jobs:[ne]};_t.set(y.boxId,Re),t.push(Re)}break}case"handoff.done":t.push(dt(y,"lead-handoff"));break;case"subtask.delegated":t.push({...dt(y,"subtask-delegated"),to:y.boxId,toAgent:y.provider});break;case"subtask.merged":t.push(dt(y,"subtask-merged"));break;case"pr.state.changed":{if(!m.change)break;if(m.change==="opened"){for(let M of B.values())M.status="stale";B.clear();for(let M of _.values())M.status="stale";_.clear()}let b=dt(y,`pr-${m.change}`);if(b.box=y.boxId??null,OM.has(m.change)&&m.number!=null){let M=CM(S,E,m);if(S.size>=2){for(let de of E.values())for(let De of de)De.grouped=!0;b.groupPrs=[...S.values()];let ne=[b];for(let de of S.keys())E.set(de,ne)}else{let ne=E.get(M)??[];ne.push(b),E.set(M,ne)}}else if(m.change==="merged"||m.change==="closed"||m.change==="lost"){let M=ck(m),ne=R&&!R.complete||S.size>=2;if(S.has(M))S.delete(M),E.delete(M);else if(m.number!=null)for(let de of[...S.keys()])de.endsWith(`#${m.number}`)&&(S.delete(de),E.delete(de));if(ne&&m.number!=null){(!R||R.complete)&&(R={id:y.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:fe(y),ts:fe(y),box:y.boxId,agent:y.provider},t.push(R)),R.prs.push({number:m.number,url:m.url??null,title:m.title??null,repo:m.repo??null,branch:m.branch??null,change:m.change,ts:fe(y)}),R.remaining=[...S.values()],R.complete=S.size===0;break}}t.push(b);break}case"pr.offered":{if(!m.offerId)break;for(let M of B.values())M.status="stale";B.clear();for(let M of _.values())M.status="stale";_.clear();let b={id:y.id,kind:"pr-offer",offerId:m.offerId,excerpt:m.excerpt||null,branch:m.branch||null,base:m.base||null,offered:Array.isArray(m.offered)&&m.offered.length?m.offered:null,toPr:m.toPr&&typeof m.toPr=="object"?{number:m.toPr.number??null}:null,available:Array.isArray(m.available)?m.available:null,defaults:Array.isArray(m.defaults)?m.defaults:null,prState:m.prState||null,openPr:m.openPr&&typeof m.openPr=="object"?m.openPr:null,repos:Array.isArray(m.repos)&&m.repos.length?m.repos:null,status:"open",source:y.source==="cli"||m.via==="cli"?"cli":"transcript",ts:fe(y),box:y.boxId,agent:y.provider};B.set(m.offerId,b),T.set(m.offerId,b),t.push(b),b.source==="cli"&&ie(b);break}case"pr.offer.answered":{let b=T.get(m.offerId);b&&(b.status=m.action||"dismiss",b.actions=Array.isArray(m.actions)?m.actions:null,b.notify=m.notify===!0,m.existingPr&&typeof m.existingPr=="object"&&(b.existingPr={number:m.existingPr.number??null}),B.delete(m.offerId));break}case"pr.exists.offered":{if(!m.offerId)break;for(let M of _.values())M.status="stale";_.clear();let b={id:y.id,kind:"pr-exists-offer",offerId:m.offerId,srcOfferId:m.srcOfferId??null,branch:m.branch||null,base:m.base||null,pr:m.pr&&typeof m.pr=="object"?{number:m.pr.number??null,url:m.pr.url??null,title:m.pr.title??null}:null,actions:Array.isArray(m.actions)&&m.actions.length?m.actions:null,notify:m.notify===!0,status:"open",ts:fe(y),box:y.boxId,agent:y.provider};_.set(m.offerId,b),O.set(m.offerId,b),t.push(b);break}case"pr.exists.answered":{let b=O.get(m.offerId);b&&(b.status=m.choice||"dismiss",_.delete(m.offerId));break}case"box.state.changed":{let b=m.change==="model"?"model-change":m.change;if(!b)break;let M=dt(y,b);if(b==="model-change"&&(M.to=m.model),b==="node-update"&&M.latest){let ne=t.findIndex(de=>de.kind==="event"&&de.type==="node-update"&&de.latest===M.latest);if(ne>=0){let de=t[ne];t[ne]={...M,ts:de.ts,at:de.at,firstAt:de.firstAt??de.ts,updatedAt:M.ts};break}}t.push(M);break}case"track.transferred":case"track.recovered":t.push(dt(y,"track-moved"));break;case"view.state.changed":{if(m.change==="deleted"){d(`view:${m.viewId}`);break}if(m.change!=="created"||m.restarted)break;f(`view:${m.viewId}`,{id:y.id,kind:"view-card",viewId:m.viewId,name:m.name,slug:m.slug,port:m.port,origin:m.origin,ts:fe(y),box:y.boxId,agent:y.provider});break}case"view.spinup.failed":{t.push({id:y.id,kind:"view-spinup-failed",name:m.name||null,reason:m.reason||"no-view",ts:fe(y),box:y.boxId,agent:y.provider});break}case"mock.state.changed":{if(m.change==="picked"){t.push({id:y.id,kind:"mock-picked",mockId:m.mockId,name:m.name,group:m.group??null,version:m.version??null,siblings:m.siblings??[],ts:fe(y),box:y.boxId,agent:y.provider});break}if(m.change==="deleted"){d(`mock:${m.mockId}`);break}if(m.change!=="created")break;f(`mock:${m.mockId}`,{id:y.id,kind:"mock-card",mockId:m.mockId,name:m.name,group:m.group??null,ts:fe(y),box:y.boxId,agent:y.provider});break}case"flow.state.changed":{if(m.change==="deleted"){d(`flow:${m.flowId}`);break}if(m.change!=="created")break;f(`flow:${m.flowId}`,{id:y.id,kind:"flow-card",flowId:m.flowId,name:m.name,stepCount:m.stepCount??null,mockIds:m.mockIds??[],ts:fe(y),box:y.boxId,agent:y.provider});break}case"runbook.state.changed":{if(m.change==="deleted"){d(`runbook:${m.runbookId}`);break}if(m.change!=="created")break;f(`runbook:${m.runbookId}`,{id:y.id,kind:"runbook-card",runbookId:m.runbookId,name:m.name,ts:fe(y),box:y.boxId,agent:y.provider});break}case"ticket.linked":{t.push({id:y.id,kind:"ticket-card",provider:m.provider||"linear",key:m.key,url:m.url,title:m.title??null,linkSource:m.linkSource??null,ts:fe(y),box:y.boxId,agent:y.provider});break}case"box.fullscreen.detected":{if(!m.offerId)break;for(let M of H.values())M.box===(m.box||y.boxId)&&(M.status="stale",H.delete(M.offerId));let b={id:y.id,kind:"fullscreen-offer",offerId:m.offerId,status:"open",ts:fe(y),box:m.box||y.boxId,agent:m.agent||y.provider};H.set(m.offerId,b),ae.set(m.offerId,b),t.push(b);break}case"box.fullscreen.answered":{let b=ae.get(m.offerId);b&&(b.status=m.action==="restarted"?"restarted":m.action==="cleared"?"cleared":"dismiss",H.delete(m.offerId));break}case"ticket.move.offered":{if(!m.offerId)break;for(let M of I.values())M.key===m.key&&(M.status="stale",I.delete(M.offerId));let b={id:y.id,kind:"ticket-offer",offerId:m.offerId,provider:m.provider||"linear",key:m.key,url:m.url??null,phase:m.phase??null,from:m.from??null,to:m.to?.name??null,prNumber:m.prNumber??null,status:"open",ts:fe(y),box:y.boxId,agent:y.provider};I.set(m.offerId,b),U.set(m.offerId,b),t.push(b);break}case"ticket.move.answered":{let b=U.get(m.offerId);b&&(b.status=m.action==="moved"?"moved":"dismiss",I.delete(m.offerId));break}case"ticket.state.changed":{for(let b of I.values())b.key===m.key&&b.to===m.to&&(b.status="stale",I.delete(b.offerId));if(m.mode==="offer")break;t.push(dt(y,"ticket-state"));break}case"ticket.commented":{t.push({id:y.id,kind:"ticket-comment",key:m.key,url:m.url??null,excerpt:m.excerpt??null,ts:fe(y),box:y.boxId,agent:y.provider});break}case"ticket.flow.changed":t.push(dt(y,"ticket-flow"));break;case"ticket.create.offered":{if(!m.proposalId)break;for(let M of X.values())M.status="stale";X.clear();let b={id:y.id,kind:"ticket-create-offer",proposalId:m.proposalId,provider:m.provider||"linear",epic:m.epic??null,issues:Array.isArray(m.issues)?m.issues:[],team:m.team??null,needsTeam:!!m.needsTeam,linkCurrentTrack:!!m.linkCurrentTrack,status:"open",ts:fe(y),box:y.boxId,agent:y.provider};X.set(m.proposalId,b),C.set(m.proposalId,b),t.push(b),ie(b);break}case"ticket.create.answered":{let b=C.get(m.proposalId);b&&(b.status=m.action==="created"?"created":"dismiss",b.createdCount=m.createdCount??null,b.failedCount=m.failedCount??null,X.delete(m.proposalId));break}case"loop.create.offered":{if(!m.proposalId)break;for(let M of Q.values())M.status="stale";Q.clear();let b={id:y.id,kind:"loop-create-offer",proposalId:m.proposalId,name:m.name??"",schedule:m.schedule??"",prompt:m.prompt??"",expectation:m.expectation??null,notify:m.notify??"off",assignment:m.assignment??{provider:"claude"},repo:m.repo??null,nodeId:m.nodeId??null,nodeName:m.nodeName??null,status:"open",ts:fe(y),box:y.boxId,agent:y.provider};Q.set(m.proposalId,b),ve.set(m.proposalId,b),t.push(b),ie(b);break}case"loop.create.answered":{let b=ve.get(m.proposalId);b&&(b.status=m.action==="created"?"created":"dismiss",Q.delete(m.proposalId));break}case"followup.armed":{if(!m.armId)break;let b=m.replaces?se.get(m.replaces):null;b&&b.status==="armed"&&(b.status="replaced");let M={id:y.id,kind:"followup-armed",armId:m.armId,trigger:m.trigger??"now",label:m.label??"",prompt:m.prompt??"",why:m.why??null,status:"armed",ts:fe(y),box:y.boxId,agent:y.provider};se.set(m.armId,M),M.trigger!=="now"&&t.push(M);break}case"followup.armed.cancelled":{let b=se.get(m.armId);b&&b.status==="armed"&&(b.status="cancelled");break}case"followup.offered":{if(!m.offerId)break;for(let ne of W.values())ne.trigger===m.trigger&&(ne.status="stale",W.delete(ne.offerId));let b=Array.isArray(m.rows)?m.rows:[];for(let ne of b){let de=ne.armId?se.get(ne.armId):null;de&&de.status==="armed"&&(de.status="offered")}let M={id:y.id,kind:"followup-offer",offerId:m.offerId,trigger:m.trigger??"now",repo:m.repo??null,context:m.context&&typeof m.context=="object"?m.context:{},rows:b.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:fe(y),box:y.boxId,agent:y.provider};W.set(m.offerId,M),be.set(m.offerId,M),t.push(M),M.trigger==="now"&&ie(M);break}case"followup.answered":{let b=be.get(m.offerId);b&&(b.status=m.action==="sent"?"sent":m.action==="removed"?"removed":"dismiss",b.answer={followupId:m.followupId??null,armId:m.armId??null,label:m.label??null,promoted:m.promoted??null,revived:m.revived===!0},W.delete(m.offerId));break}case"followup.create.offered":{if(!m.proposalId)break;for(let M of ce.values())M.status="stale";ce.clear();let b={id:y.id,kind:"followup-create-offer",proposalId:m.proposalId,label:m.label??"",prompt:m.prompt??"",trigger:m.trigger??"pr.merged",repo:m.repo??null,why:m.why??null,status:"open",created:null,ts:fe(y),box:y.boxId,agent:y.provider};ce.set(m.proposalId,b),ue.set(m.proposalId,b),t.push(b),ie(b);break}case"followup.create.answered":{let b=ue.get(m.proposalId);b&&(b.status=m.action==="created"?"created":"dismiss",ce.delete(m.proposalId));break}case"followup.created":{let b=m.proposalId?ue.get(m.proposalId):null;b&&(b.created={followupId:m.followupId??null});break}case"loop.created":{let b=m.proposalId?ve.get(m.proposalId):null;b&&(b.created={loopId:m.loopId??null,nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),t.push(dt(y,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!m.proposalId||!m.loopId)break;for(let ne of Ae.values())ne.loopId===m.loopId&&(ne.status="stale",ne.staleReason="superseded",Ae.delete(ne.proposalId));let b=y.type==="loop.update.offered",M={id:y.id,kind:b?"loop-update-offer":"loop-delete-offer",proposalId:m.proposalId,loopId:String(m.loopId),name:m.name??m.base?.name??"",base:m.base??null,...b?{patch:m.patch??{},changed:Array.isArray(m.changed)?m.changed:Object.keys(m.patch||{})}:{reason:m.reason??""},selfEdit:!!m.selfEdit,status:"open",staleReason:null,ts:fe(y),box:y.boxId,agent:y.provider};Ae.set(m.proposalId,M),_e.set(m.proposalId,M),t.push(M),ie(M);break}case"loop.update.answered":{let b=_e.get(m.proposalId);b&&(m.action==="moved"?(b.status="stale",b.staleReason="moved"):b.status=m.action==="applied"?"applied":"dismiss",Ae.delete(m.proposalId));break}case"loop.delete.answered":{let b=_e.get(m.proposalId);b&&(m.action==="moved"?(b.status="stale",b.staleReason="moved"):b.status=m.action==="delete"?"deleted":m.action==="pause"?"paused":"keep",Ae.delete(m.proposalId));break}case"loop.updated":{let b=m.proposalId?_e.get(m.proposalId):null;b&&(b.applied={changed:Array.isArray(m.changed)?m.changed:[],nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),t.push(dt(y,"loop-updated"));break}case"loop.deleted":t.push(dt(y,"loop-deleted"));break;case"loop.paused":t.push(dt(y,"loop-paused"));break;case"rework.cause.offered":{if(!m.sha||xt.has(m.sha))break;let b={id:y.id,kind:"rework-cause-offer",sha:m.sha,subject:m.subject??"",linesReworked:Number(m.linesReworked)||0,origins:Array.isArray(m.origins)?m.origins:[],heuristic:m.heuristic??null,status:"open",cause:null,ts:fe(y),box:y.boxId,agent:y.provider};xt.set(m.sha,b),t.push(b);break}case"rework.cause.answered":{let b=m.sha?xt.get(m.sha):null;b&&(b.status="answered",b.cause=m.cause??null);break}case"ticket.created":{let b={items:Array.isArray(m.items)?m.items:[],failed:Array.isArray(m.failed)?m.failed:[],team:m.team??null},M=m.proposalId?C.get(m.proposalId):null;if(M){M.created=b;break}t.push({id:y.id,kind:"ticket-created",...b,ts:fe(y),box:y.boxId,agent:y.provider});break}case"error":{if(!m.kind)break;t.push(dt(y,m.kind));break}case"provider.error":t.push({...dt(y,"provider-error"),provider:y.provider,box:y.boxId,agent:y.provider});break;case"usage.cap.hit":t.push(dt(y,"usage-cap-hit"));break;case"usage.cap.warning":t.push(dt(y,"usage-cap-warning"));break;case"provider.connected":{t.push({id:y.id,kind:"event",type:"provider-connected",provider:m.provider||y.provider,ts:fe(y),at:fe(y),box:y.boxId,agent:y.provider});break}case"prompt.answered":{if(G=null,m.control||!m.question)break;let b=m.groupId||m.promptId;if(!b)break;let M=je.get(b);M||(M={id:y.id,kind:"prompt",groupId:b,provider:y.provider,box:y.boxId,agent:y.provider,questionTotal:m.questionTotal??1,questions:[],ts:fe(y)},je.set(b,M));let ne=m.questionIndex??0,de={index:ne,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:Array.isArray(m.chosen)?m.chosen:[]},De=M.questions.findIndex(Re=>Re.index===ne&&We(Re.question)===We(de.question));De>=0?M.questions[De]=de:M.questions.push(de),M.questions.sort((Re,ya)=>Re.index-ya.index),M.questionTotal=Math.max(M.questionTotal,m.questionTotal??1),M.questions.length>=M.questionTotal&&(t.push(M),je.delete(b));break}default:break}}let nt=u.size?t.filter(y=>!y.retired):t;return NM(nt.sort((y,m)=>(y.ts??0)-(m.ts??0)))}function NM(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<=MM){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 Zf(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:PM(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??wr(e)).filter(o=>o.kind==="message");return lb(n,r)}function PM(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==ps(e.command)?t:mr(e.command,e.description||"")}function dt(e,t){let{ts:n,change:r,...o}=e.payload||{};return{id:e.id,kind:"event",type:t,...o,at:fe(e),ts:fe(e)}}function lk(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)+DM,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&BM.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function uk(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!LM.has(r.type)||!r.box)continue;let o=(r.ts??0)+jM,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 dk(e){return(e||[]).filter(t=>FM.has(t?.kind)&&t.status==="open")}var fe,OM,ck,MM,DM,BM,jM,LM,FM,Qf=j(()=>{ms();io();dl();bl();Vf();Xf();fe=e=>e.payload?.ts??e.ts;OM=new Set(["opened","ci-fixed","reconciled","pushed"]),ck=e=>`${e.repo??""}#${e.number}`;MM=2*6e4;DM=12e4,BM=new Set(["archived","unarchived","opened"]);jM=2500,LM=new Set(["pr-opened","pr-merged","pr-auto-armed"]);FM=new Set(["pr-offer","pr-exists-offer","ticket-offer","ticket-create-offer","loop-create-offer","loop-update-offer","loop-delete-offer","fullscreen-offer","followup-create-offer"])});function KM(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 VM(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 zM(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<WM&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<qM&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function hk(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=KM(e),s=VM(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=wr(e??[]).filter(d=>d?.kind==="message"&&typeof d.text=="string"&&d.text.trim()).slice(-UM);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(mk[r]??mk.failover),l.push(""),o.lastPush?.sha){let d=pk(n,o.lastPush.ts),p=d?` (~${d} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${p}`+(o.lastPush.wip?" \u2014 a bostrat WIP snapshot (full working tree incl. uncommitted edits at push time).":"."))}else r==="in-place"?l.push("**Code state:** no push recorded \u2014 the working tree in this workspace is the only copy; commit early."):l.push("**Code state:** no push was ever recorded for this Track \u2014 work since the branch's last known state stayed on the offline node.");if(l.push(""),a){let d=pk(n,i);l.push(`## Last real checkpoint (written by the previous agent${d?`, ~${d} min before this reconstruction`:""})`),l.push(""),l.push(a.trim()),l.push("")}let u=zM(e??[],i);if((u.files.length||u.heads.length)&&(l.push(`## Work since ${a?"that checkpoint":"the start of the log"} (from the event log)`),l.push(""),u.files.length&&l.push(`Files touched (most recent first): ${u.files.map(d=>`\`${d}\``).join(", ")}`),u.heads.length&&(u.files.length&&l.push(""),l.push(`Commands run (most recent first): ${u.heads.map(d=>`\`${d}\``).join(" \xB7 ")}`)),l.push("")),c.length){l.push(`## Recent conversation (last ${c.length} message${c.length===1?"":"s"})`),l.push("");for(let d of c)l.push(`**${d.role==="user"?"operator":"agent"}:** ${GM(d.text,HM)}`),l.push("")}l.push("---"),l.push("Resume: continue the objective above from the verified repository state; ask the operator before redoing anything the log says was already done.");let f=l.join(`
151
- `);return f.length<=fk?f:`${f.slice(0,fk)}
152
-
153
- [\u2026 brief truncated]`}var UM,HM,fk,WM,qM,GM,pk,mk,wk=j(()=>{Qf();UM=12,HM=2e3,fk=48e3,WM=30,qM=10;GM=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},pk=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;mk={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 YM from"node:fs";import gr from"node:fs/promises";import yr from"node:path";function Tk(e){let t=no(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=gk?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,gk).toString("utf8").replace(/�+$/,"")}
154
-
155
- [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function oN(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(bk.test(s)){if(r.length>=Rk)continue;let a=rN(s.replace(bk,"").replace(/[.;,:]+$/,""),Ok,tN);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>yk&&(o=`${o.slice(0,yk-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function Ck(e,t,{timeoutMs:n=9e4}={}){let r=yr.join(t,QM),o=yr.join(r,eN);await gr.mkdir(r,{recursive:!0});let s=await Al(o),a=await ge(e);if(!a)throw new Error(`session "${e}" not found`);return await _l(e,a,nN(o)),await Lk(o,s,n),oN(await gr.readFile(o,"utf8"))}function Mk(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===Ak||n===$k;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(Ek)||n===JM||r.startsWith(_k)||r.startsWith(Ik)}function Nk(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-sN;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 Pk(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 Dk(e,{windows:t=[]}={}){if(Mk(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 Il(e){return ep.get(e)||null}async function Bk(e){let t=ep.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await ge(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:yr.join(n.cwd,vk,Sk)};return ep.set(e,r),cN(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function cN(e,t){e.step="summarize",await jk(e.name,t),e.step="clear";let n=await ge(e.name);await _l(e.name,n,"/clear"),await rp(aN),e.step="resume",await _l(e.name,n,ZM),e.step="done",e.finishedAt=Date.now()}async function jk(e,t,{timeoutMs:n=iN}={}){let r=yr.join(t,vk),o=yr.join(r,Sk);await gr.mkdir(r,{recursive:!0});let s=await Al(o),a=await ge(e);await re({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await _l(e,a,XM(o)),await Lk(o,s,n),await re({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await Al(o)});let i=await zb(t,o,{exclude:u=>Mk(u.role,u.text)});await re({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(c){await $({id:c,cwd:t},{type:"memory.seed",actor:"orchestrator",payload:{...i,tokensEst:i.chars?Math.round(i.chars/4):0,ts:Date.now()}}).catch(()=>{});try{let u=await gr.readFile(o,"utf8");await $({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...Tk(u),ts:Date.now()}})}catch{}}await Qd(t);let l=await lN(r,o);return c&&await Oy(c,l||o,{box:e,agent:a?.agent??null}),o}async function tp(e,{timeoutMs:t}={}){let n=await ge(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);return jk(e,n.cwd,t?{timeoutMs:t}:void 0)}async function np(e,t,{trackName:n="this Track"}={}){let r=await F({id:e,cwd:t}),o=hk(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=yr.join(t,kk);return await gr.mkdir(yr.dirname(s),{recursive:!0}),await gr.writeFile(s,o,"utf8"),await $({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...Tk(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),kk}async function Al(e){try{return(await gr.stat(e)).mtimeMs}catch{return 0}}async function Lk(e,t,n){let r=Date.now()+n;for(;;){if(await Al(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await rp(2e3)}}async function lN(e,t){try{if(!YM.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=yr.join(e,`${n}.md`);return await gr.copyFile(t,r),r}catch{return null}}function rp(e){return new Promise(t=>setTimeout(t,e))}function xk(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 _l(e,t,n){if(t){let o=xk(t.agent);await hr({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await ge(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await Le(e,["Escape"],{kind:"drive-wipe"}),await rp(150),await ls(e,cl,{kind:"drive-wipe"}),await Ze(e,n,{kind:"orchestration-drive",...pn(r.agent,n)}),await ni({sessionName:e,agent:r.agent,agentCmd:xk(r.agent),text:n,flow:"orchestration-drive"})}var vk,Sk,gk,Ek,Ak,_k,JM,XM,ZM,Ik,$k,QM,eN,yk,Rk,Ok,tN,nN,bk,rN,sN,aN,iN,ep,kk,op=j(()=>{lt();Za();dn();Qa();Uf();Yb();Oa();me();Qc();wk();vk=".bostrat/handoff",Sk="latest.md",gk=32*1024;Ek="Checkpoint: write a work-in-progress handoff",Ak="HANDOFF WRITTEN",_k="Resume from .bostrat/handoff/latest.md",JM="/clear",XM=e=>`${Ek} 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 ${Ak} and take no further action.`,ZM=`${_k}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,Ik="Beat: write a",$k="BEAT WRITTEN",QM=".bostrat/arc",eN="beat.txt",yk=200,Rk=4,Ok=5,tN=36,nN=e=>`${Ik} 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 ${Rk} further lines, each starting with "- " and naming ONE piece in at most ${Ok} 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 ${$k} and take no further action.`,bk=/^(?:[-–—*•·]|\d+[.)])\s+/,rN=(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};sN=6e5;aN=3500,iN=3e5,ep=new Map;kk=".bostrat/handoff/status-latest.md"});function kr(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!$l.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 Hk(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:kr(o.from,"from",n),toMs:kr(o.to,"to",n)}))}return t}function ap(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 dN(e){if(!e)return null;let t=String(e).trim();return br[t]?t:Fk[t]?Fk[t]:Object.keys(br).find(r=>t.startsWith(r))||null}function fN(e){if(!e||e===br)return uN;let t=Uk.get(e);return t||(t=Hk(e),Uk.set(e,t)),t}function Wk(e,t,n={}){let{table:r,speed:o}=n,s=fN(r),a=r&&r!==br?s[e]?e:null:dN(e);if(!a)return null;let i=ap(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 mn(e,t={},n,r){let o=Wk(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 pN(e=br){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:kr(a.from,"from",n),toMs:kr(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`),$l.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 hN({now:e=Date.now(),table:t=br,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...mN,...n},a=[],i=ap(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(f=>({...f,fromMs:kr(f.from,"from",c),toMs:kr(f.to,"to",c),verifiedMs:$l.test(String(f.verifiedAt??""))?Date.parse(`${f.verifiedAt}T00:00:00.000Z`):NaN}))}catch(f){a.push(String(f.message));continue}for(let f of u){if(!Number.isFinite(f.verifiedMs)){a.push(`${c}: window ${f.from??"\u2026"} \u2192 ${f.to??"now"} has no verifiedAt`);continue}let d=i>=f.fromMs&&i<=f.toMs,p=f.fromMs>i&&f.fromMs-i<=o*sp;d&&i-f.verifiedMs>r*sp&&a.push(`${c}: current rate last verified ${f.verifiedAt} (>${r}d) \u2014 re-check the vendor page and bump verifiedAt`),p&&f.fromMs-f.verifiedMs>s*sp&&a.push(`${c}: scheduled rate change on ${f.from} was last verified ${f.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=br,...n}={}){let r=ap(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=kr(l.from,"from",i),f=kr(l.to,"to",i);r>=u&&r<=f&&$l.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=[...pN(t),...hN({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var br,Fk,$l,uN,Uk,qk,mN,sp,Dn=j(()=>{br={"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:null,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)."}],"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)."}]},Fk={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"},$l=/^\d{4}-\d{2}-\d{2}$/;uN=Hk(br);Uk=new WeakMap;qk=(e,t,n)=>Wk(e,t,n)!==null;mN=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),sp=864e5});function wN(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function Gk(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Ft(e){let t=e.payload?.model||"unknown",n=wN(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=mn(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&&!qk(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function xr(e,{boxLabels:t={}}={}){let n=(e||[]).filter(d=>d.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,f=Kk();for(let d of n){let{usd:p,model:h,tokens:w,repriced:g,unpriced:k,asRecorded:S}=Ft(d);i+=S;let E=d.provider||"unknown",R=d.boxId||"unattributed";if(g&&c++,k&&(l++,u.add(h)),a+=p,Gk(f,w),r[h]||={usd:0,tokens:Kk(),events:0},r[h].usd+=p,r[h].events+=1,Gk(r[h].tokens,w),o[E]||={usd:0,events:0},o[E].usd+=p,o[E].events+=1,s[R]||={usd:0,events:0,provider:E,models:new Set,label:t[R]||R},s[R].usd+=p,s[R].events+=1,h!=="unknown"&&s[R].models.add(h),d.epoch!=null){let B=(s[R].epochs||={})[d.epoch]||={usd:0,events:0,provider:E,models:new Set};B.usd+=p,B.events+=1,B.provider=E,h!=="unknown"&&B.models.add(h)}}return{totalUsd:ks(a),asRecordedUsd:ks(i),totalTokens:f,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:Rl(r,d=>({...d,usd:ks(d.usd)})),byProvider:Rl(o,d=>({...d,usd:ks(d.usd)})),byBox:Rl(s,d=>({usd:ks(d.usd),events:d.events,provider:d.provider,label:d.label,models:[...d.models],...d.epochs?{epochs:Rl(d.epochs,p=>({usd:ks(p.usd),events:p.events,provider:p.provider,models:[...p.models]}))}:{}}))}}var Kk,ks,Rl,vr=j(()=>{Dn();Kk=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});ks=e=>Math.round(e*1e4)/1e4,Rl=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function gN(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 Vk(e,t=[]){let n=[],r=e?.events||[],o=new Map,s=0;for(let u of t){if(u.type!=="pr.state.changed")continue;let f=u.payload||{};!f.repo||f.number==null||(f.change==="merged"?o.set(`${f.repo}#${f.number}`,f):f.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(f=>{let[d,p]=f.split("#");return`${d.split("/").pop()}#${p}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(ip(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(ip(a,"subtask"));let i=r.filter(u=>u.type==="lead-handoff"&&u.fromAgent&&u.toAgent);if(i.length){let u=i.slice(0,3).map(f=>`${f.fromAgent}\u2192${f.toAgent}`).join(", ");n.push(`${ip(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=xr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?gN(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var ip,zk=j(()=>{vr();ip=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as yN}from"node:child_process";import{promisify as bN}from"node:util";import{randomUUID as kN}from"node:crypto";async function cp(e,t){let n=Date.now()+t;for(;;){if(await Mn(e))return!0;if(Date.now()>n)return!1;await ii(vN)}}async function TN(e,t){let n=Jk[t]||Jk.default;n.escape&&(await Le(e,["Escape"],{kind:"swap-exit"}),await ii(150)),n.wipe&&await ls(e,cl,{kind:"swap-exit"}),await ll(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=pn(t).submitDelayMs||0;await ii(Math.max(r,250)),await Le(e,["Enter"],{kind:"swap-exit"})}async function Xk(e,t){try{let{stdout:n}=await lo(K,V("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function Zk(e){await lo(K,V("respawn-pane","-k","-t",e))}async function lp(e,t={}){if(!Pe(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await ge(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||dr(n),a=Number(t.exitTimeoutMs)||xN;await re({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let i=!1;if(!await Mn(e)&&(await TN(e,o),!await cp(e,a)&&(i=!0,await re({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await Zk(e),!await cp(e,Yk))))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);let c=s==="claude"&&ro(n),l=c?Nc():null,u=await Xk(e,"ANTHROPIC_API_KEY"),f=!1;try{l?(await lo(K,V("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),f=!0):u&&(await lo(K,V("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),f=!0)}catch(g){throw l?nl(g,l):g}if(f&&!i&&(await Zk(e),!await cp(e,Yk)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let d=!!t.resumeSessionId,p=t.resumeSessionId||kN(),h=d?n:Ua(n,p,e),w=d?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(h);return c&&await or(r.cwd),s==="codex"&&await Jo(r.cwd),s==="cursor"&&await Xo(r.cwd),await oo(e),await lo(K,V("set-option","-t",e,"@bostrat-sid",p)),await lo(K,V("set-option","-t",e,"@bostrat-agent",s)),await ii(SN),c&&Fa().length&&(await Xk(e,La)||await lo(K,V("set-environment","-t",e,La,"1")).catch(()=>{}),await Ze(e,`export ${La}=1`,{kind:"swap-env"}),await ii(150)),await Ze(e,h,{kind:"swap-launch"}),await re({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:p,forced:i,envRespawned:f}),{name:e,cwd:r.cwd,sessionId:p,agent:s,pinned:w,forced:i,envRespawned:f,launchCmd:h}}var lo,ii,xN,Yk,vN,SN,Jk,Qk=j(()=>{lt();Ta();Dc();Bc();Qa();dn();lo=bN(yN),ii=e=>new Promise(t=>setTimeout(t,e)),xN=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,Yk=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,vN=250,SN=400,Jk={claude:{escape:!0,wipe:!0,text:"/exit"},codex:{escape:!0,wipe:!0,text:"/quit"},cursor:{escape:!0,wipe:!0,text:"/quit"},default:{escape:!1,wipe:!1,text:"exit"}}});async function e0(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await Et(e,t)}catch{return[]}let o=new Map,s=new Set;for(let i of r.split(`
156
- `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.isSidechain)continue;let u=l.message?.content;if(!Array.isArray(u))continue;let f=l.timestamp?Date.parse(l.timestamp):null;for(let d of u)if(!(!d||typeof d!="object"))if(d.type==="tool_use"&&d.id){if(d.name==="Agent"){let p=d.input||{};o.set(d.id,{id:d.id,kind:"agent",name:String(p.description||"").trim()||null,detail:String(p.subagent_type||"").trim()||null,ts:f,proven:!1})}else if(d.name==="Bash"&&d.input?.run_in_background===!0){let p=String(d.input.command||"").trim();o.set(d.id,{id:d.id,kind:"command",name:String(d.input.description||"").trim()||(p?ps(p):null),detail:p?ps(p):null,ts:f,proven:!0})}}else d.type==="tool_result"&&d.tool_use_id&&EN.test(AN(d.content))&&s.add(d.tool_use_id)}let a=[];for(let i of o.values()){if(!i.proven&&!s.has(i.id))continue;let{proven:c,...l}=i;a.push(l)}return a.slice(-n)}var EN,AN,t0=j(()=>{Xt();ms();EN=/^Async (?:agent|task) launched/i,AN=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 Sr(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 _N(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 n0(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:Zt(`read ${Sr(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${xs(r)}`:`Read ${xs(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?Sr(t.path,n):null,s=t?.glob?` --glob ${up(t.glob)}`:"",a=Zt(String(r),40);return{command:Zt(`grep ${up(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?Sr(t.target_directory,n):null;return{command:Zt(`glob ${up(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${Zt(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:Zt(`edit ${Sr(t.path,n)}`,140),description:`Edit ${xs(t.path)}`}:null;case"Write":return t?.path?{command:Zt(`write ${Sr(t.path,n)}`,140),description:`Write ${xs(t.path)}`}:null;case"Delete":return t?.path?{command:Zt(`delete ${Sr(t.path,n)}`,140),description:`Delete ${xs(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>Sr(s,n)).filter(Boolean);return{command:Zt(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=_N(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:Zt(`apply_patch ${Sr(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${xs(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:Zt(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var Ol,Zt,xs,up,r0=j(()=>{Ol=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),Zt=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,xs=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);up=e=>`"${String(e).replace(/"/g,'\\"')}"`});import ci from"node:fs";import IN from"node:fs/promises";import uo from"node:path";import $N from"node:os";import RN from"node:crypto";import ON from"node:zlib";function a0(e){let t=RN.createHash("md5").update(String(e)).digest("hex");return uo.join(CN,t)}function i0(e){try{let t=JSON.parse(ci.readFileSync(uo.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 MN(e){let t=a0(e),n;try{n=ci.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=uo.join(t,o.name),a=uo.join(s,"store.db");if(!ci.existsSync(a))continue;let i=i0(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 Cl(e,t){if(!e)return null;if(t){let n=uo.join(a0(e),t),r=uo.join(n,"store.db");if(ci.existsSync(r))return{id:t,dir:n,store:r,...i0(n)||{createdAtMs:null,updatedAtMs:null}}}return MN(e)}function o0(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function NN(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=ON.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function PN(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 DN(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!Ol.has(r.toolName))continue;let o=n0(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 dp(e,t){if(!s0)return vs;let{DatabaseSync:n}=s0,r;try{r=new n(e,{readOnly:!0})}catch{return vs}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 vs;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return vs}let a=s.lastUsedModel||null,i=s.latestRootBlobId?o0(r,s.latestRootBlobId):null;if(!i)return{...vs,model:a};let c=[],l=[],u=[],f=null,d=[];for(let p of PN(i)){let h=NN(o0(r,p));if(!h)continue;let w=h.providerOptions?.cursor;if(w?.requestId&&d.push(w.requestId),w?.modelProviderMessageId&&d.push(w.modelProviderMessageId),h.role!=="assistant")continue;if(Array.isArray(h.content))for(let S of h.content){let E=S?.providerOptions?.cursor?.modelName;E&&(f=E)}l.push(...DN(h.content,t).map((S,E)=>({...S,id:S.id||`${p}:${E}`}))),u.push(...jN(h.content));let g=BN(h.content);if(!g)continue;let k=[...new Set(u)];u=[],c.push({id:p,text:g,tools:k.length?k:void 0,commands:l,model:f}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:d}}catch{return vs}finally{try{r.close()}catch{}}}function c0(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(ci.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 l0(e,t,{limit:n=80}={}){let r=Cl(e,t);if(!r)return[];let{turns:o,model:s}=await dp(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=c0(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 u0(e,t){let n=Cl(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await dp(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 d0(e,t,{limit:n=80}={}){let r=Cl(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await dp(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=c0(r,a.length||1),l=[];a.forEach((u,f)=>{for(let d of u.commands)l.push({...d,summary:mr(d.command,d.description),ts:c(f)})});for(let u of s)l.push({...u,summary:mr(u.command,u.description),ts:i+1});return l}async function f0(e,t){let n=Cl(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await IN.stat(n.store)).mtimeMs)}catch{return null}}var CN,BN,jN,s0,vs,fp=j(()=>{ms();r0();CN=process.env.BOSTRAT_CURSOR_CHATS||uo.join($N.homedir(),".cursor","chats");BN=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(`
157
- `).trim():"",jN=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],s0=process.getBuiltinModule?.("node:sqlite"),vs={turns:[],trailingCommands:[],model:null,requestIds:[]}});import LN from"node:fs/promises";function wp(e){return p0.set(e.agent,e),e}function li(e){return p0.get(e)||FN}async function yp(e,t={}){return(await li(e.agent).readMessages(e,t)).map(gp(e))}async function m0(e,t={}){return(await li(e.agent).readCommands(e,t)).map(gp(e))}async function h0(e,t={}){return(await li(e.agent).readJobs(e,t)).map(gp(e))}var Ss,pp,mp,hp,FN,p0,gp,w0=j(()=>{Xt();fl();ms();t0();fp();io();Ss=class{constructor(t,n=new Set){this.agent=t,this.cliTools=n}async readMessages(){return[]}async readCommands(){return[]}async readJobs(){return[]}async updatedAt(){return null}},pp=class extends Ss{transcript(t){return!t?.cwd||!t?.sessionId?null:Jt(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?If(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?cb(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?e0(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await LN.stat(n)).mtimeMs)}catch{return null}}},mp=class extends Ss{async readMessages(t,n){return l0(t.cwd,t.sessionId,n)}async readCommands(t,n){return d0(t.cwd,t.sessionId,n)}async updatedAt(t){return f0(t.cwd,t.sessionId)}},hp=class extends Ss{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return fb(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return pb(t.cwd,this.sessionId(t),n)}async updatedAt(t){return mb(t.cwd,this.sessionId(t))}},FN=new Ss("unknown"),p0=new Map;wp(new pp("claude",Sf));wp(new mp("cursor",Ol));wp(new hp("codex",za));gp=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function mo(e){let t=e.search(vp);return(t>=0?e.slice(0,t):e).trim()}function UN(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function HN(e){let t=String(e).trim();return!!(!t||po.test(e)||vp.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function WN(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=qN(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function qN(e,t){let n=String(t).toLowerCase(),r=e.findIndex(c=>!c.answered),o=r>=0?r:e.length-1;if(!n)return o;let s=e.map(c=>{let l=c.label.toLowerCase(),u=l.split(/\s+/).filter(d=>d.length>3&&n.includes(d)).length;if(u)return u;let f=l.slice(0,8).trim();return f.length>=4&&n.includes(f)?1:0}),a=Math.max(...s);if(a===0||s[o]===a)return o;let i=s.flatMap((c,l)=>c===a?[l]:[]);return i.length===1?i[0]:o}function y0(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function KN(e,t=""){let n=String(e);if(!k0.test(n))return null;let r=n.replace(/\r/g,"").split(`
158
- `),o=-1;for(let u=r.length-1;u>=0;u--)if(/^\s*Switch model\?\s*$/.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[];for(let u=o+1;u<r.length;u++){let f=r[u].match(fo);if(f)s.push({cursor:!!f[1],label:f[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let d=r[u].trim();d&&!po.test(r[u])&&a.push(d)}}if(s.length<2)return null;let i=s.map(u=>({label:mo(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 VN(e,t=""){let n=String(e).replace(/\r/g,"").split(`
159
- `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!x0.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(fo);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&&!(GN.test(n[c])||po.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:mo(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 zN(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
160
- `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(fo);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 JN(e,t=""){let n=String(e);if(!bp.test(n))return null;let r=n.replace(/\r/g,"").split(`
161
- `),o=-1;for(let u=r.length-1;u>=0;u--)if(YN.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[r[o].trim()];for(let u=o+1;u<r.length;u++){let f=r[u].match(fo);if(f)s.push({cursor:!!f[1],label:f[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let d=r[u].trim();d&&!po.test(r[u])&&a.push(d)}}if(s.length<2||!s.some(u=>bp.test(u.label)))return null;let i=s.map(u=>({label:mo(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 Sp(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(fo);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 XN(e,t=""){let n=String(e);if(!v0.test(n)||!S0.test(n)||ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
162
- `),o=Sp(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:mo(s.label),description:""}))}]}:null}function ZN(e,t=""){let n=String(e);if(!T0.test(n)||ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
163
- `),o=Sp(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:mo(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 eP(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!QN.test(o)||Tp.test(e[r]))break;n+=o}return n}function tP(e,t=""){let n=String(e);if(!Tp.test(n)||ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
164
- `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=eP(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 rP(e,t=""){let n=String(e);if(!kp.test(n)||!nP.test(n)||ho.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
165
- `)].reverse().find(a=>kp.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 oP(e,t=""){let n=String(e);if(!E0.test(n)||ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
166
- `),o=Sp(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:mo(s.label),description:""}))}]}:null}function sP(e,t=""){let n=String(e);if(ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
167
- `),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(A0);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(po.test(r[l])||vp.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 aP(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(xp.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 iP(e,t=""){let n=String(e);if(!b0.test(n)||!xp.test(n))return null;let r=n.replace(/\r/g,"").split(`
168
- `),o=aP(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let O=i;O<c;O++){let I=r[O].match(fo);I&&(u<0&&(u=O),l.push({line:O,cursor:!!I[1],checked:I[3]!=null&&I[3]!==" ",hasCheckbox:I[3]!=null,label:I[4].trim(),desc:""}))}if(!l.length)return null;for(let O of l)for(let I=O.line+1;I<Math.min(r.length,O.line+4)&&!(fo.test(r[I])||po.test(r[I]));I++){let U=r[I].trim();if(!(!U||HN(r[I])||g0.test(U))){O.desc=UN(U);break}}let f=l.filter(O=>!g0.test(O.label));if(!f.length)return null;let d=f.some(O=>O.hasCheckbox),p=Math.max(0,f.findIndex(O=>O.cursor)),h=s>=0?s+1:0,w=[];for(let O=h;O<u;O++){let I=r[O].trim();I&&!po.test(r[O])&&!/[☐☒]/.test(r[O])&&w.push(I)}let g=w.join(" ")||(s>=0?y0(r[s]):"")||"The agent is asking a question",k=s>=0?WN(r[s],g):null,S=k?.currentTabLabel||(s>=0?y0(r[s]):""),E=f.map(O=>({label:mo(O.label),description:O.desc})),R=E.map(O=>O.label).join("|"),T=`claude:${k?`q${k.questionIndex+1}/${k.questionTotal}`:"q1/1"}:${S}:${g}:${R}`.slice(0,240),_=k?`claude:ask:${k.tabs.map(O=>O.label).join("|")}`.slice(0,240):T;return{provider:"claude",box:t,multiSelect:d,cursorIndex:p,promptId:T,groupId:_,...k?{questionIndex:k.questionIndex,questionTotal:k.questionTotal,currentTabLabel:k.currentTabLabel,tabs:k.tabs}:{},questions:[{question:g,header:S,multiSelect:d,options:E}]}}function wo(e,t){let n=String(t||"");return n?e==="claude"?b0.test(n)&&xp.test(n)||k0.test(n)||bp.test(n)||x0.test(n.trimEnd().split(`
169
- `).pop()||"")?!0:ho.test(n)?!1:v0.test(n)&&S0.test(n)||T0.test(n)||Tp.test(n)||kp.test(n)||E0.test(n)||A0.test(n.trimEnd().split(`
170
- `).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 Tr(e,t){return!e||!t?null:e.agent==="claude"?zN(t,e.name)||iP(t,e.name)||KN(t,e.name)||JN(t,e.name)||rP(t,e.name)||tP(t,e.name)||ZN(t,e.name)||XN(t,e.name)||oP(t,e.name)||sP(t,e.name)||VN(t,e.name):e.agent==="cursor"||e.agent==="codex"?$b(e.agent,t,e.name):null}async function Ep(e){if(!e)return null;let t=await Nn(e.name).catch(()=>"");return Tr(e,t)}function _0(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 I0(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 b0,xp,fo,g0,po,vp,k0,x0,GN,bp,YN,ho,v0,S0,T0,Tp,QN,kp,nP,E0,A0,Ap=j(()=>{lt();ml();b0=/to navigate\b.*\bEsc to cancel|Enter to select\b/,xp=/Chat about this/i,fo=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,g0=/^(type something|chat about this|submit)\b/i,po=/^[─—-]{6,}\s*$/,vp=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;k0=/^\s*Switch model\?\s*$/m;x0=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,GN=/^\s*[─—▔-]{6,}\s*$/;bp=/Resume from summary/i,YN=/^\s*This session is\b/;ho=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;v0=/Choose the text style that looks best with your terminal/,S0=/Let's get started\./;T0=/Select login method:/;Tp=/Paste code here if prompted/,QN=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;kp=/OAuth error:/,nP=/Press Enter to retry\./;E0=/Quick safety check: Is this a project you created or one you trust/;A0=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function Ml(e,t,n){if(!e||!t)return null;for(let r of cP)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function uP(e){let t=_p.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},_p.set(e,t)),t}function O0(e,t,n=Date.now()){let r=uP(e);if(r.sentAt=r.sentAt.filter(s=>n-s<R0),r.sentAt.length>=$0)return{action:"give-up"};if(n-r.last<lP)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 C0(e,t=Date.now()){let n=_p.get(e);return n?n.sentAt.filter(r=>t-r<R0).length>=$0:!1}var cP,lP,$0,R0,_p,Ip=j(()=>{cP=[{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||""}
171
- ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];lP=5e3,$0=5,R0=3600*1e3,_p=new Map});function Ts(e){return typeof e=="string"?e.trim():""}var M0=j(()=>{});import{execFile as dP}from"node:child_process";import{promisify as fP}from"node:util";async function Ue(e,t,{input:n}={}){let r=Rp("git",["-C",e,...t],{maxBuffer:N0});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function Es(e){if(!e)return!1;try{let{stdout:t}=await Ue(e,["rev-parse","--is-inside-work-tree"]);return t.trim()==="true"}catch{return!1}}async function P0(e){let{stdout:t}=await Ue(e,["rev-parse","--show-toplevel"]);return t.trim()}async function pP(e){try{return await Ue(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function As(e,t="bostrat: subtask snapshot"){let{stdout:n}=await Ue(e,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>Rp("git",["-C",e,...a],{maxBuffer:N0,env:o,...i});try{let a=await pP(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 Rp("rm",["-f",r])}catch{}}}async function Op(e,t,{trailers:n=[]}={}){let{stdout:r}=await Ue(e,["status","--porcelain"]);return r.trim()?(await Ue(e,["add","-A"]),await Ue(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",t,...n.flatMap(o=>["--trailer",o])]),!0):!1}async function ui(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await Ue(e,["status","--porcelain"]),r=n.split(`
172
- `).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 di(e,t){if(!t)return 0;try{let{stdout:n}=await Ue(e,["rev-list","--count",`${t}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function _s(e,t,n,r){return await Ue(e,["worktree","add","--no-track","-b",n,t,r]),t}async function D0(e,t){try{return await Ue(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function Nl(e,t,n){return await Ue(e,["worktree","add",t,n]),t}async function Is(e){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:t}=await Ue(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 Ue(e,["rev-parse","--verify","--quiet",t]),n}catch{}return"HEAD"}async function Cp(e){await Ue(e,["init","-q"]),await Ue(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function Rt(e,t){try{await Ue(e,["worktree","remove","--force",t])}catch{try{await Ue(e,["worktree","prune"])}catch{}}}function mP(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 Mp(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function Np(e,t,n,r){let{stdout:o}=await Ue(e,Mp(["diff","--shortstat",t,n],r));return mP(o)}async function Pp(e,t,n,r){let{stdout:o}=await Ue(e,Mp(["diff","--name-only",t,n],r));return o.split(`
173
- `).map(s=>s.trim()).filter(Boolean)}async function Dp(e,t,n,r){let{stdout:o}=await Ue(e,Mp(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await $p(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await $p(e,o,["--3way","--whitespace=nowarn"]),a=await hP(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await $p(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function $p(e,t,n){try{return await Ue(e,["apply",...n,"-"],{input:t}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function hP(e){try{let{stdout:t}=await Ue(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
174
- `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var Rp,N0,Pl=j(()=>{Rp=fP(dP),N0=64*1024*1024});function Dl(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!wP.has(o.state)&&o.state!=="stopped"&&(o.state="stopped",r=!0);let s=Array.isArray(o.epochs)?o.epochs:[],a=s[s.length-1];a&&typeof a=="object"&&a.endedAt==null&&(a.endedAt=t,a.endReason==null&&(a.endReason=n),r=!0)}return r}var Ve,wP,Bn=j(()=>{Ve=e=>!!(e&&(e.archivedAt||e.transferredTo)),wP=new Set(["merged","conflict","canceled","failed","handed-off"])});import Bp from"node:fs/promises";import j0 from"node:path";import gP from"node:os";function H0(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function W0(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function q0(e){let t=new Date(H0(e));return t.setDate(t.getDate()+7),t.getTime()}function K0(e){let t=new Date(W0(e));return t.setMonth(t.getMonth()+1),t.getTime()}function jl(e=Date.now()){for(let[t,n]of Object.entries($s)){let r=n.startOf(e);if(r!==jn[t]){jn[t]=r;for(let o of go.values())o[t]=0;for(let o of Rs)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&Rs.delete(o)}}}function G0(e,t){let n=Qt?.caps?.[e]?.[$s[t].capKey];return Number.isFinite(n)&&n>0?n:null}function yo(e,t=Date.now()){if(!e||!Lp||!Qt?.caps)return null;jl(t);let n=go.get(e);for(let r of Object.keys($s)){let o=G0(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:Bl(s),resetsAt:$s[r].nextStart(t)}}return null}function V0(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${jn[t.window]}`;return Rs.has(n)?!1:(Rs.add(n),!0)}function B0(e,t,n,r=Date.now()){if(!e||!t)return;jl(r);let o=yP(e);for(let[s,a]of Object.entries($s))n>=jn[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function bP(e,t,n=Date.now()){if(!Qt?.caps||!jp)return;let r=go.get(e);if(r)for(let[o,s]of Object.entries($s)){let a=G0(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*U0||i>=a)continue;let c=`warn:${e}:${o}:${jn[o]}`;if(!Rs.has(c)){Rs.add(c);try{let l=await jp(t);if(!l)continue;await $(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:Bl(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function z0(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 Ll(e,{source:t="local",updatedAt:n=Date.now()}={}){Qt={caps:z0(e),updatedAt:n,source:t};try{await Bp.mkdir(L0,{recursive:!0}),await Bp.writeFile(F0(),JSON.stringify(Qt,null,2))}catch{}return fi()}function fi(e=Date.now()){jl(e);let t=new Set([...go.keys(),...Object.keys(Qt?.caps||{})]),n={};for(let r of t){let o=go.get(r);n[r]={weeklyUsd:Bl(o?.weekly||0),monthlyUsd:Bl(o?.monthly||0)}}return{caps:Qt?.caps||{},configured:!!Qt,seeded:Lp,updatedAt:Qt?.updatedAt??null,spent:n,windows:{weekly:{start:jn.weekly,resetsAt:q0(e)},monthly:{start:jn.monthly,resetsAt:K0(e)}},warnPct:U0}}async function Y0({listTracks:e,getTrack:t}={}){jp=t||null,jl();try{let o=JSON.parse(await Bp.readFile(F0(),"utf8"));Qt={caps:z0(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{Qt=null}let n=Date.now();ct.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Ft(o);B0(o.provider||"unknown",s,o.ts??Date.now()),bP(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(jn.weekly,jn.monthly);for(let o of await e?.()||[]){let s;try{s=await F(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||B0(a.provider||"unknown",Ft(a).usd,i,n)}}return Lp=!0,fi()}var L0,F0,U0,$s,Qt,Lp,jn,go,Rs,jp,yP,Bl,Fl=j(()=>{me();vr();L0=process.env.BOSTRAT_STATE_DIR||j0.join(process.env.HOME||gP.tmpdir(),".bostrat"),F0=()=>j0.join(L0,"usage-caps.json"),U0=.8;$s={weekly:{startOf:H0,nextStart:q0,capKey:"weeklyUsd"},monthly:{startOf:W0,nextStart:K0,capKey:"monthlyUsd"}},Qt=null,Lp=!1,jn={weekly:0,monthly:0},go=new Map,Rs=new Set,jp=null,yP=e=>{let t=go.get(e);return t||(t={weekly:0,monthly:0},go.set(e,t)),t};Bl=e=>Math.round(e*1e4)/1e4});import kP from"node:fs/promises";import xP from"node:os";import J0 from"node:path";function rx(e){return e==="codex"?EP:e==="cursor"?nx:ex}function X0(e){let t=String(e||"").split(`
175
- `),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 Z0(e){let t=String(e||"").split(`
176
- `),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 AP(e){let t=String(e||"").split(`
177
- `);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 Q0(e){let t=String(e||"").split(`
178
- `),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 ox(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&&!tx.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=nx.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!TP.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function pi(e,t,{timeoutMs:n=vP}={}){let r=Date.now()+n;for(;;){let o=await Ce(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await Ul(SP)}}async function _P(e,t){return await Ze(e,`/model ${t.model}`,pn("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function IP(e,t){await il(e),await Ze(e,"/model",{enter:!1}),await Ul(250),await Le(e,["Enter"],{kind:"model-switch"});let n=await pi(e,X0);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await Le(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=AP(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await Ze(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await pi(e,i=>Z0(i)||!X0(i)&&o(i)&&{done:o(i)});if(!s)throw await Le(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?tx.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 Le(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await Ze(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await pi(e,i=>!Z0(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 $P(){let e=J0.join(process.env.CURSOR_CONFIG_DIR||J0.join(xP.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await kP.readFile(e,"utf8"))?.model||null}catch{return null}}async function RP(e,t){await il(e),await ll(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await pi(e,Q0),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 pi(e,Q0,{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 Le(e,["Down"],{kind:"model-switch"}),await Ul(250)}if(!n||!s||!o(s)){await Le(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await Le(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 Le(e,["Enter"],{kind:"model-switch"}),await Ul(800);let a=await $P();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 sx(e,t,n){return e==="codex"?IP(t,n):e==="cursor"?RP(t,n):_P(t,n)}var Ul,vP,SP,ex,TP,EP,tx,nx,ax=j(()=>{lt();Qa();Ul=e=>new Promise(t=>setTimeout(t,e)),vP=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,SP=300,ex=[{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"}],TP=new Set([...ex.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"]),EP=[{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"}],tx=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),nx=[{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 Wl(e){let t=e||{},n=OP(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function OP(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{text:e.text,boxRole:e.boxRole,...e.kind?{kind:e.kind}:{},...e.attachments?.length?{attachments:e.attachments}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:e.box,provider:gt(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:gt(e.agent),payload:{text:e.prompt,kind:e.kind,boxRole:e.boxRole}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:gt(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:gt(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:gt(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:gt(e.agent),payload:{...Er(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:gt(e.agent||e.toAgent),payload:{kind:"subtask-failed",...Er(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{change:"subtask-resumed",...Er(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",...Er(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...Er(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...Er(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(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:gt(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:gt(e.agent),payload:{...Er(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...Er(e)}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};default:return null}}function lx(e,t){let n=Wl(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;Up(()=>$(r,n))}async function ux(e){if(!(!e?.id||ix.has(e.id))){ix.add(e.id);try{let t=await F(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=Wl(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await $(e,o)}}catch{}}}function Er(e){let{type:t,at:n,...r}=e;return r}function dx(e,t,n){!n?.promptId||Fp.get(e.id)===n.promptId||(Fp.set(e.id,n.promptId),Up(()=>$(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:gt(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 Hp(e,t,n,r={}){Fp.delete(e.id),Up(()=>$(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:gt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var gt,Hl,Up,cx,ix,Fp,Wp=j(()=>{me();gt=e=>e||null;Hl=Promise.resolve(),Up=e=>(Hl=Hl.then(e).catch(()=>{}),Hl),cx=()=>Hl;ix=new Set;Fp=new Map});function DP(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function gx(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of DP(n).reverse()){if(!CP.test(r))continue;let o=r.endsWith("?")&&r.length<=PP&&NP.test(r);if(MP.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function bx(e){let t=String(e||""),n=[];BP.test(t)&&n.push("commit"),yx.test(t)&&n.push("rebase"),jP.test(t)&&n.push("push");let r=FP.test(t);!r&&LP.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 kx(e){return yx.test(String(e||""))}function Os(e,{branch:t=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1}={}){Array.isArray(e)||(e=e==="push"?["commit","push"]:["commit","push","pr"]);let a=new Set(e),i=Array.isArray(o)&&o.length>0,c=i?o.map(p=>`${p.name}/`).join(", "):null,l=t?` on this branch (${t})`:"",u=[];if(a.has("commit")&&u.push(i?`commit the work in each changed checkout (${c})${l} with a clear commit message per repo`:`commit the work${l} with a clear commit message`),a.has("rebase")){let p=a.has("commit")?"the branch":`this branch${t?` (${t})`:""}`;u.push(i?`rebase ${p} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${p} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`)}if(a.has("push")||a.has("pr")){let p=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",h=a.has("rebase")?" with `--force-with-lease` (the rebase rewrote history)":"";i?u.push(a.has("commit")||a.has("rebase")?`push each one to its remote${h}${p}`:`push this branch${t?` (${t})`:""} from each changed checkout (${c}) to its remote${p}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${h}${p}`:`push this branch${l} to the remote${p}`)}a.has("pr")&&u.push(i?"open a pull request in each changed repo with a concise title and a description of what changed and why (run `gh pr create` inside each checkout)":`open a pull request${n?` against ${n}`:""} with a concise title and a description of what changed and why (use \`gh pr create\`)`);let f=[];a.has("commit")||f.push("don't create any new commits \u2014 ship what's already committed"),s&&!a.has("rebase")&&f.push("don't rebase \u2014 leave the branch's history as it is"),!a.has("push")&&!a.has("pr")&&f.push("don't push"),a.has("pr")||f.push("don't open a pull request");let d=`Yes \u2014 go ahead: ${u.join(", then ")}.`;return f.length&&(d+=` ${f.join(", and ").replace(/^./,p=>p.toUpperCase())}.`),a.has("pr")&&(d+=i?" If a repo's PR for this branch is already open, just push that repo's update instead.":" If a PR for this branch is already open, just push the update instead."),d}function xx(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 vx(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<=UP&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function Sx(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+HP||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function Tx(e){let t=(Array.isArray(e)?e:[]).filter(r=>fx[r]).map(r=>fx[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 px,mx,hx,wx,CP,MP,NP,PP,Ar,BP,yx,jP,LP,FP,UP,HP,fx,bo=j(()=>{px=/(?<!\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,mx=/(?<!\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,hx=/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,wx=/(?<!\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,CP=new RegExp(`\\b(?:${px}|${mx}|${hx}|${wx})\\b`,"i"),MP=/\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,NP=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,PP=90;Ar=["commit","rebase","push","pr"],BP=new RegExp(`\\b(?:${px})\\b`,"i"),yx=new RegExp(`\\b(?:${wx})\\b`,"i"),jP=new RegExp(`\\b(?:${mx})\\b`,"i"),LP=new RegExp(`\\b(?:${hx})\\b`,"i"),FP=/\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;UP=3e4;HP=2500;fx={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import WP from"node:crypto";import ql from"node:fs/promises";import Ex from"node:path";import qP from"node:os";async function He(){return _r||(qp??=ql.readFile(Gp,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(_r=e,!t&&Ne()){let{records:n,source:r}=await et("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;_r[oe(i.repo,i.number)]=i}Object.keys(_r).length&&await Vp().catch(()=>{})}}return _r}).finally(()=>qp=null),qp)}async function Vp(){let e=JSON.stringify({links:_r},null,2),t=`${Gp}.${process.pid}.tmp`;await ql.mkdir(Ax,{recursive:!0}),await ql.writeFile(t,e),await ql.rename(t,Gp)}async function Qe(e){Kp=Kp.then(Vp,Vp),await Kp.catch(()=>{});let t=_r?.[e];t&&wt("prlinks",{id:_x(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function Ot({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 He(),c=oe(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:KP.has(a),firstSeen:Date.now()},await Qe(oe(e,t)),{link:i[c],created:!0})}async function Ln(e,t){if(!e||t==null)return null;let n=(await He())[oe(e,t)];return!n||n.announced?null:(n.announced=!0,await Qe(oe(e,t)),n)}async function tt(e,t){return!e||t==null?null:(await He())[oe(e,t)]??null}async function Ir(e,t,n){if(!e||t==null)return null;let r=(await He())[oe(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(oe(e,t)),r):null}async function Ix(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await He())[oe(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Qe(oe(e,t)),o):null}async function $x(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await He())[oe(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Qe(oe(e,t)),o):null}async function Kl(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await He())[oe(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Qe(oe(e,t)),r)}async function Gl(e,t){if(!e||t==null)return null;let n=(await He())[oe(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Qe(oe(e,t)),n)}async function Vl(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await He())[oe(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Qe(oe(e,t)),r)}async function zl(e,t){if(!e||t==null)return null;let n=(await He())[oe(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Qe(oe(e,t)),n)}async function Rx(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await He())[oe(e,t)];return r?(r.baseFoldAt=n,await Qe(oe(e,t)),r):null}async function Ox(e,t){if(!e||t==null)return null;let n=(await He())[oe(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Qe(oe(e,t)),n)}async function Cx(e,t,n){if(!e||t==null||!n)return null;let r=(await He())[oe(e,t)];return r?(r.lastHeadSha=n,await Qe(oe(e,t)),r):null}async function Mx(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await He())[oe(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(oe(e,t))),{prev:o,link:r}}async function mi(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await He())[oe(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Qe(oe(e,t)),r):null}async function ko(e,t,n=!0){if(!e||t==null)return null;let r=(await He())[oe(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Qe(oe(e,t)),r):null}async function hi(e,t,n=!0){if(!e||t==null)return null;let r=(await He())[oe(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Qe(oe(e,t)),r):null}async function Nx(e,t,n){if(!e||t==null)return null;let r=(await He())[oe(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(oe(e,t)),r}async function Px(e,t,n){if(!e||t==null)return null;let r=(await He())[oe(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(oe(e,t)),r}async function wi(e,t){if(!e||t==null)return null;let n=(await He())[oe(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(oe(e,t)),n)}async function Dx(){return Object.values(await He()).filter(e=>!GP.has(e.state))}async function xo(){return Object.values(await He()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function Bx(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await He(),r=0;for(let[o,s]of Object.entries(n))await wt("prlinks",{id:_x(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var Ax,Gp,oe,_x,_r,qp,Kp,KP,GP,Fn=j(()=>{ur();Ax=process.env.BOSTRAT_STATE_DIR||Ex.join(process.env.HOME||qP.tmpdir(),".bostrat"),Gp=Ex.join(Ax,"pr-links.json"),oe=(e,t)=>`${e}#${Number(t)}`,_x=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=WP.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},_r=null,qp=null,Kp=Promise.resolve();KP=new Set(["api","observed","reconciled"]);GP=new Set(["merged","closed","lost"])});import VP from"node:fs";import zp from"node:fs/promises";import Ux from"node:path";import zP from"node:os";function qx(e,t=!1){if(!t&&e-Lx<YP)return;Lx=e;let n=JSON.stringify({windowStart:Cs,byCaller:Object.fromEntries(Un),lastHour:$r});Fx=Fx.then(()=>zp.mkdir(Hx,{recursive:!0})).then(()=>zp.writeFile(`${Yl}.tmp`,n)).then(()=>zp.rename(`${Yl}.tmp`,Yl)).catch(()=>{})}function Kx(e){e-Cs<Wx||($r={start:Cs,total:Jl(Un),byCaller:Object.fromEntries(Un)},$r.total&&console.log(`[github] ${$r.total} calls last hour`,$r.byCaller),Cs=e,Un=new Map,qx(e,!0))}function Hn(e="other",t=Date.now()){Kx(t),Un.set(e,(Un.get(e)||0)+1),qx(t)}function Gx(e=Date.now()){return Kx(e),{windowStart:Cs,total:Jl(Un),byCaller:Object.fromEntries(Un),lastHour:$r,backoffUntil:vo>e?vo:null}}function Rr(e){return JP.test(String(e?.message||e||""))}function Or(e,t=Date.now()){return vo<=t&&console.warn(`[github] rate limited \u2014 backing off ${jx/6e4} min:`,String(e?.message||e||"").slice(0,200)),vo=Math.max(vo,t+jx),vo}function Xl(e=Date.now()){return Math.max(0,vo-e)}var Hx,Yl,Wx,jx,YP,Cs,Un,$r,vo,Lx,Jl,Fx,JP,gi=j(()=>{Hx=process.env.BOSTRAT_STATE_DIR||Ux.join(process.env.HOME||zP.tmpdir(),".bostrat"),Yl=Ux.join(Hx,"github-metrics.json"),Wx=60*6e4,jx=5*6e4,YP=6e4,Cs=Date.now(),Un=new Map,$r=null,vo=0,Lx=0,Jl=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(VP.readFileSync(Yl,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<Wx?(Cs=e.windowStart,Un=new Map(Object.entries(e.byCaller||{})),$r=e.lastHour||null):Jl(new Map(Object.entries(e.byCaller||{})))&&($r={start:e.windowStart,total:Jl(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}Fx=Promise.resolve();JP=/rate limit|too quickly|abuse detection|HTTP 429/i});import Vx from"node:fs/promises";import zx from"node:path";import XP from"node:os";function Ql({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};Zl.push(l),Zl.length>QP&&Zl.shift();let u=Yp.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)),Yp.set(e,u),eD(l),l}async function eD(e){try{await Vx.mkdir(Yx,{recursive:!0}),await Vx.appendFile(ZP,JSON.stringify(e)+`
179
- `)}catch{}}function Jx(){let e={};for(let[t,n]of Yp)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:Zl.slice(-20)}}var Yx,ZP,QP,Zl,Yp,eu=j(()=>{Yx=process.env.BOSTRAT_STATE_DIR||zx.join(process.env.HOME||XP.tmpdir(),".bostrat"),ZP=zx.join(Yx,"github-latency.ndjson"),QP=100,Zl=[],Yp=new Map});import{execFile as tD}from"node:child_process";import{promisify as nD}from"node:util";async function rD(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([Ns("git",["-C",e,"rev-parse","HEAD"]),Ns("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await $({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function Ut(e,t,n={}){let{caller:r="prs",...o}=n,s=await ln({cwd:e});Hn(r);try{let{stdout:a}=await Ns("gh",t,{cwd:e,...oD,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw Rr(a)&&Or(a),a}}async function Zp(){if(tu&&Date.now()-tu.at<6e4)return tu.data;let e;try{Hn("auth");let t=await Ns("gh",["auth","status"],{timeout:1e4});e={installed:!0,authenticated:!0,login:`${t.stdout||""}${t.stderr||""}`.match(/account\s+(\S+)/)?.[1]??null}}catch(t){e=t?.code==="ENOENT"||t?.code===127?{installed:!1,authenticated:!1,login:null}:{installed:!0,authenticated:!1,login:null}}if(e.installed&&!e.authenticated)try{let t=await _a();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return tu={at:Date.now(),data:e},e}async function sD(e){try{let{stdout:t}=await Ns("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function Zx(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 Jp(e){let t=(e||[]).map(Zx),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 em(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function ev(e,t){if(!t)return null;let n=await Se(e);if(!n)return null;try{let r=await Ut(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 tv(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 nv(e,t){let n=await ev(e,t);return n===null?{...Jp([]),unavailable:!0}:Jp(tv(n))}function nu(e,t=Jp(e.statusCheckRollup)){return{number:e.number,title:e.title,url:e.url,author:e.author?.login??null,headRefName:e.headRefName,headSha:e.headRefOid??null,baseRefName:e.baseRefName,isDraft:!!e.isDraft,reviewDecision:e.reviewDecision||null,mergeable:e.mergeable||"UNKNOWN",mergeStateStatus:e.mergeStateStatus||"UNKNOWN",additions:e.additions??0,deletions:e.deletions??0,createdAt:e.createdAt,updatedAt:e.updatedAt,checks:t,green:t.failed===0&&t.pending===0&&e.mergeStateStatus==="CLEAN",autoMergeArmed:!!e.autoMergeRequest,mergeabilityPending:!1}}function iD(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){Ms.delete(s);continue}r.add(s),Ms.has(s)||Ms.set(s,n),o.mergeabilityPending=n-Ms.get(s)<aD}for(let o of Ms.keys())o.startsWith(`${e}#`)&&!r.has(o)&&Ms.delete(o);return t}async function Ps(e,t){let n=await Wn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await Ut(n.path,["pr","view",String(r),"--json",Qp]);return nu(JSON.parse(o))}catch(o){if(!em(o))throw o;let s=await Ut(n.path,["pr","view",String(r),"--json",Qx]),a=JSON.parse(s);return nu(a,await nv(n.path,a.headRefOid))}}async function hn(e,{caller:t="prs"}={}){try{let n=await Ut(e,["pr","list","--json",Qp,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>nu(r)).sort(Xx)}catch(n){if(!em(n))throw n;let r=await Ut(e,["pr","list","--json",Qx,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>nu(o,await nv(e,o.headRefOid))))).sort(Xx)}}function gn(){yi.clear()}async function uD(e,t){if(!e)return t;for(let n of t){let r=await tt(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 Kl(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await Vl(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function rv(){let e=await Zp();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await On())await sD(a.path)&&t.push(a);let n=Date.now(),r=Xl(n)>0,o=await Promise.all(t.map(async a=>{let i=yi.get(a.path),c=i?.pending?lD:cD;if(i&&(r||n-i.at<c))return i.entry;try{let l=await Se(a.path).catch(()=>null),u=iD(a.path,await hn(a.path,{caller:"tab"}),n);if(await uD(l,u),i?.entry?.prs)for(let p of u)i.entry.prs.find(w=>w.number===p.number)?.checks?.pending>0&&p.checks.total>0&&p.checks.pending===0&&Ql({change:p.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:p.number,githubAt:p.checks.settledAt,source:"tab"});let f={name:a.name,path:a.path,prs:u},d=u.some(p=>p.mergeabilityPending||p.checks.pending>0||p.autoMergeArmed);return yi.set(a.path,{at:Date.now(),entry:f,pending:d}),f}catch(l){return i?i.entry:{name:a.name,path:a.path,prs:[],error:wn(l)}}})),s=new Set(t.map(a=>a.path));for(let a of yi.keys())s.has(a)||yi.delete(a);return{auth:e,repos:o}}async function Wn(e){let t=(await On()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function So(e){return Zo(e)}async function Ds(e,t,{method:n="squash"}={}){let r=await Wn(e);if(!bi.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 ln({cwd:r.path})).GH_TOKEN){let a=await Hd().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await Ut(r.path,s)}catch(a){throw new Error(wn(a))}finally{gn()}return{ok:!0,number:o}}async function ki(e,t){let n=await Wn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Ut(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(wn(s))}finally{gn()}let o=await Se(n.path).catch(()=>null);return o&&await Rx(o,r).catch(()=>{}),{ok:!0,number:r}}async function tm(e,t){let n=await Wn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Ut(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(wn(o))}finally{gn()}return{ok:!0,number:r}}function nm(e){return e.green&&!e.isDraft}function mD(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 ov(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:nm(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function sv(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function xi(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 av(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(xi))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function iv(){let e={};for(let[t,n]of Xp)e[t]={...n};return e}async function cv(e,{method:t="merge",onMerged:n=null}={}){let r=await Wn(e);if(!bi.has(t))throw new Error(`invalid merge method: ${t}`);if(Xp.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await hn(r.path)).filter(nm).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 Xp.set(r.path,s),wD(s,o,{listPrs:()=>hn(r.path),merge:a=>Ds(r.path,a,{method:t}),sleep:pD,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function hD(e,t){let n=Date.now()+(t.settleMaxMs??fD),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(dD)}}async function wD(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 hD(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: ${wn(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(!nm(a)){e.skipped.push({number:a.number,title:a.title,reason:mD(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:wn(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),gn()}}async function rm(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await Ns("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${wn(l)}`)}await rD(e);let o=n||"";if((await ln({cwd:e})).GH_TOKEN){let l=await Hd().catch(()=>null);l&&(o=`${o?`${o}
180
-
181
- `:""}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 Ut(e,s)}catch(l){throw new Error(wn(l))}finally{gn()}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 lv(e,t){let n=await Wn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await Ut(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(wn(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!em(i))throw i;let c=await Ut(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await ev(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(wn(i));o=tv(l).map(Zx).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=gD(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await Ut(n.path,["run","view",c,"--log-failed"]).then(u=>yD(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function gD(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function yD(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
150
+ `});function NM(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 DM(e,t,n){let r=dk(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 gr(e){let t=[],n=new Set,r=new Set,o=new Map,s=new Map,a=new Set,i=new Map,c=new Set,l=new Map,u=new Map,f=(y,m)=>{u.set(y,m),t.push(m)},d=y=>{let m=u.get(y);m&&(m.retired=!0)},p=/^Agent "([\s\S]+)" finished$/,h=new Map;for(let y of e||[]){if(y.type!=="tool.called"||y.source!=="transcript")continue;let m=String(y.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(m))for(let k of m.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let N=k[0].split("/").pop().toLowerCase();h.has(N)||h.set(N,[]),h.get(N).push(y.payload?.ts??y.ts)}}let w=3*6e4,g=20*6e4,b=(y,m)=>!!(y?.name&&h.get(String(y.name).toLowerCase()))?.some(N=>N>=m-w&&N<=m+g);for(let y of e||[])if(y.type==="turn.retracted"){r.add(`${y.boxId}|${y.payload?.saidTs}`);let m=We(y.payload?.text);m&&(o.has(y.boxId)||o.set(y.boxId,[]),o.get(y.boxId).push(m))}else if(y.type==="turn.user"&&y.source==="orchestrator"){let m=We(y.payload?.text);m&&(s.has(y.boxId)||s.set(y.boxId,new Set),s.get(y.boxId).add(m))}else if(y.type==="job.started"&&y.payload?.id)a.add(y.payload.id),(y.payload.kind||"agent")==="agent"&&y.payload.name&&c.add(y.payload.name);else if(y.type==="turn.user"&&y.payload?.note?.kind==="task"){let m=y.payload.note,k={status:m.status||null,summary:m.summary||null,resultHead:m.resultHead??null,ts:pe(y)};m.toolUseId&&i.set(m.toolUseId,k);let N=String(m.summary||"").match(p);N&&l.set(N[1],k)}let E=new Map,S=new Map,R=null,M=new Map,T=new Map,A=new Map,C=new Map,I=new Map,W=new Map,j=new Map,ee=new Map,q=new Map,O=new Map,z=new Map,te=new Map,H=new Map,ke=new Map,ie=new Map,me=[],ce=y=>me.push(y),F=y=>{if(!me.length)return;let m=pe(y);for(let k of me){if(k.status!=="open"||k.box&&k.box!==y.boxId||(k.ts??0)>m)continue;let N=t.indexOf(k);N>=0&&t.splice(N,1),k.ts=m,t.push(k)}},le=new Map,de=new Map,Ae=new Map,_e=new Map,xt=new Map,je=new Map,_=()=>{for(let y of je.values())y.questions.length&&t.push(y);je.clear()},V=null,Ge=6e4,_t=new Map,at=(y,m)=>{let k=o.get(y);if(!k?.length)return!1;let N=We(m),oe=s.get(y);return k.some(fe=>{if(!N.startsWith(fe))return!1;let De=We(N.slice(fe.length));return!!De&&!!oe?.has(De)})};for(let y of e||[]){let m=y.payload||{};switch(y.type){case"turn.user":{if(y.source==="hook"||(me.length=0,!String(m.text||"").trim()&&!m.images?.length&&!m.attachments?.length))break;{let k=m.note||bs(m.text);if(k){if(k.kind==="task"){if(k.toolUseId&&a.has(k.toolUseId))break;let N=String(k.summary||"").match(p);if(!k.toolUseId&&N&&c.has(N[1]))break}if(k.kind==="command"&&ok(k.command))break;if(k.kind==="resume-summary"){t.push({id:y.id,kind:"resume-summary",title:k.title||"Context resumed from summary",bullets:k.bullets||[],sections:k.sections||[],rawChars:k.rawChars??null,ts:pe(y),box:y.boxId,agent:y.provider});break}k.kind!=="suppress"&&t.push({id:y.id,kind:"event",type:ak(k),name:k.name??null,command:k.command??null,summary:k.summary??null,status:k.status??null,ts:pe(y),box:y.boxId,agent:y.provider});break}}if(r.has(`${y.boxId}|${pe(y)}`)||y.source==="transcript"&&at(y.boxId,m.text))break;if(m.kind==="merge-notify"||m.kind==="ship-notify"){t.push({id:y.id,kind:"event",type:m.kind==="ship-notify"?"ship-notified":"merge-notified",text:m.text,ts:pe(y),box:y.boxId,agent:y.provider});break}if(m.kind==="mock-picked"||m.kind==="ci-fix"||m.kind==="reconcile"||m.kind==="pr-go"||m.kind==="push-go"||m.kind==="spin-up-view"||m.kind==="prompt-answer"||m.kind==="followup-go"){m.kind==="prompt-answer"&&(V=null);break}for(let k of M.values())k.status="stale";M.clear();for(let k of A.values())k.status="stale";A.clear();for(let k of H.values())k.status="stale";H.clear(),V&&V.box===y.boxId&&(t.push(NM(V)),V=null),t.push({id:y.id,kind:"message",role:"user",text:m.text,ts:pe(y),box:y.boxId,agent:y.provider,boxRole:m.boxRole,...y.actor==="orchestrator"?{orchestration:m.kind||!0}:{},...m.sourceId?{sourceId:m.sourceId}:{},...m.attachments?.length?{attachments:m.attachments}:{},...m.images?.length?{images:m.images}:{}});break}case"peer.message":{let k=m.from||{};t.push({id:y.id,kind:"event",type:"peer-message",text:m.text,from:k.trackName||k.boxId||k.name||null,fromTrackId:k.trackId||null,ts:pe(y),box:y.boxId,agent:y.provider});break}case"turn.agent":{if(m.model==="<synthetic>"&&/^No response requested\.$/.test(String(m.text||"").trim()))break;let k=yb(m,{codexFailedText:ao});if(k){t.push({id:y.id,kind:"event",type:"provider-error",cls:k.cls,status:k.status??void 0,text:k.text,provider:y.provider,legacy:!0,at:pe(y),ts:pe(y),box:y.boxId,agent:y.provider});break}_();let N=(m.images||[]).filter(Re=>!b(Re,pe(y)));if(!String(m.text||"").trim()&&!N.length)break;if(y.provider==="cursor"){let Re=`${y.boxId}|${m.text}`;if(n.has(Re))break;n.add(Re)}(!V||V.box===y.boxId)&&(V=null);let oe=y.provider==="codex"?(m.tools||[]).filter(Re=>!If.has(Re)&&!Ya.has(Re)):m.tools||[],fe=m.text,De=null,ht=Yf(String(m.text||""));ht&&(fe=ht.text,De={questions:ht.questions}),t.push({id:y.id,kind:"message",role:"assistant",text:fe,ts:pe(y),box:y.boxId,agent:y.provider,boxRole:m.boxRole,...De?{ask:De}:{},...oe.length?{tools:oe}:{},...m.model?{model:m.model}:{},...m.sourceId?{sourceId:m.sourceId}:{},...N.length?{images:N}:{}}),F(y),De&&(V={id:y.id,groupId:Jf(y.provider,m.sourceId||y.id,De.questions),provider:y.provider,box:y.boxId,questions:De.questions,ts:pe(y)});break}case"job.started":{if(!m.id)break;let k=pe(y),N=i.get(m.id);if(!N&&(m.kind||"agent")==="agent"&&m.name){let Re=l.get(m.name);Re&&Re.ts>=k&&(N=Re)}let oe={jobId:m.id,jobKind:m.kind||"agent",name:m.name||null,detail:m.detail||null,status:N?N.status==="killed"?"stopped":N.status&&N.status!=="completed"?"failed":"done":"running",startedTs:k,finishedTs:N?.ts??null,summary:N?.summary??null,resultHead:N?.resultHead??null},fe=_t.get(y.boxId),De=fe?.jobs[fe.jobs.length-1]?.startedTs;if(fe&&De!=null&&k-De<=Ge)fe.jobs.push(oe);else{let Re={id:y.id,kind:"job-dock",dockId:m.id,ts:k,box:y.boxId,agent:y.provider,jobs:[oe]};_t.set(y.boxId,Re),t.push(Re)}break}case"handoff.done":t.push(dt(y,"lead-handoff"));break;case"subtask.delegated":t.push({...dt(y,"subtask-delegated"),to:y.boxId,toAgent:y.provider});break;case"subtask.merged":t.push(dt(y,"subtask-merged"));break;case"pr.state.changed":{if(!m.change)break;if(m.change==="opened"){for(let N of M.values())N.status="stale";M.clear();for(let N of A.values())N.status="stale";A.clear()}let k=dt(y,`pr-${m.change}`);if(k.box=y.boxId??null,PM.has(m.change)&&m.number!=null){let N=DM(E,S,m);if(E.size>=2){for(let fe of S.values())for(let De of fe)De.grouped=!0;k.groupPrs=[...E.values()];let oe=[k];for(let fe of E.keys())S.set(fe,oe)}else{let oe=S.get(N)??[];oe.push(k),S.set(N,oe)}}else if(m.change==="merged"||m.change==="closed"||m.change==="lost"){let N=dk(m),oe=R&&!R.complete||E.size>=2;if(E.has(N))E.delete(N),S.delete(N);else if(m.number!=null)for(let fe of[...E.keys()])fe.endsWith(`#${m.number}`)&&(E.delete(fe),S.delete(fe));if(oe&&m.number!=null){(!R||R.complete)&&(R={id:y.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:pe(y),ts:pe(y),box:y.boxId,agent:y.provider},t.push(R)),R.prs.push({number:m.number,url:m.url??null,title:m.title??null,repo:m.repo??null,branch:m.branch??null,change:m.change,ts:pe(y)}),R.remaining=[...E.values()],R.complete=E.size===0;break}}t.push(k);break}case"pr.offered":{if(!m.offerId)break;for(let N of M.values())N.status="stale";M.clear();for(let N of A.values())N.status="stale";A.clear();let k={id:y.id,kind:"pr-offer",offerId:m.offerId,excerpt:m.excerpt||null,branch:m.branch||null,base:m.base||null,offered:Array.isArray(m.offered)&&m.offered.length?m.offered:null,toPr:m.toPr&&typeof m.toPr=="object"?{number:m.toPr.number??null}:null,available:Array.isArray(m.available)?m.available:null,defaults:Array.isArray(m.defaults)?m.defaults:null,prState:m.prState||null,openPr:m.openPr&&typeof m.openPr=="object"?m.openPr:null,repos:Array.isArray(m.repos)&&m.repos.length?m.repos:null,status:"open",source:y.source==="cli"||m.via==="cli"?"cli":"transcript",ts:pe(y),box:y.boxId,agent:y.provider};M.set(m.offerId,k),T.set(m.offerId,k),t.push(k),k.source==="cli"&&ce(k);break}case"pr.offer.answered":{let k=T.get(m.offerId);k&&(k.status=m.action||"dismiss",k.actions=Array.isArray(m.actions)?m.actions:null,k.notify=m.notify===!0,m.existingPr&&typeof m.existingPr=="object"&&(k.existingPr={number:m.existingPr.number??null}),M.delete(m.offerId));break}case"pr.exists.offered":{if(!m.offerId)break;for(let N of A.values())N.status="stale";A.clear();let k={id:y.id,kind:"pr-exists-offer",offerId:m.offerId,srcOfferId:m.srcOfferId??null,branch:m.branch||null,base:m.base||null,pr:m.pr&&typeof m.pr=="object"?{number:m.pr.number??null,url:m.pr.url??null,title:m.pr.title??null}:null,actions:Array.isArray(m.actions)&&m.actions.length?m.actions:null,notify:m.notify===!0,status:"open",ts:pe(y),box:y.boxId,agent:y.provider};A.set(m.offerId,k),C.set(m.offerId,k),t.push(k);break}case"pr.exists.answered":{let k=C.get(m.offerId);k&&(k.status=m.choice||"dismiss",A.delete(m.offerId));break}case"box.state.changed":{let k=m.change==="model"?"model-change":m.change;if(!k)break;let N=dt(y,k);if(k==="model-change"&&(N.to=m.model),k==="node-update"&&N.latest){let oe=t.findIndex(fe=>fe.kind==="event"&&fe.type==="node-update"&&fe.latest===N.latest);if(oe>=0){let fe=t[oe];t[oe]={...N,ts:fe.ts,at:fe.at,firstAt:fe.firstAt??fe.ts,updatedAt:N.ts};break}}t.push(N);break}case"track.transferred":case"track.recovered":t.push(dt(y,"track-moved"));break;case"view.state.changed":{if(m.change==="deleted"){d(`view:${m.viewId}`);break}if(m.change!=="created"||m.restarted)break;f(`view:${m.viewId}`,{id:y.id,kind:"view-card",viewId:m.viewId,name:m.name,slug:m.slug,port:m.port,origin:m.origin,ts:pe(y),box:y.boxId,agent:y.provider});break}case"view.spinup.failed":{t.push({id:y.id,kind:"view-spinup-failed",name:m.name||null,reason:m.reason||"no-view",ts:pe(y),box:y.boxId,agent:y.provider});break}case"mock.state.changed":{if(m.change==="picked"){t.push({id:y.id,kind:"mock-picked",mockId:m.mockId,name:m.name,group:m.group??null,version:m.version??null,siblings:m.siblings??[],ts:pe(y),box:y.boxId,agent:y.provider});break}if(m.change==="deleted"){d(`mock:${m.mockId}`);break}if(m.change!=="created")break;f(`mock:${m.mockId}`,{id:y.id,kind:"mock-card",mockId:m.mockId,name:m.name,group:m.group??null,ts:pe(y),box:y.boxId,agent:y.provider});break}case"flow.state.changed":{if(m.change==="deleted"){d(`flow:${m.flowId}`);break}if(m.change!=="created")break;f(`flow:${m.flowId}`,{id:y.id,kind:"flow-card",flowId:m.flowId,name:m.name,stepCount:m.stepCount??null,mockIds:m.mockIds??[],ts:pe(y),box:y.boxId,agent:y.provider});break}case"runbook.state.changed":{if(m.change==="deleted"){d(`runbook:${m.runbookId}`);break}if(m.change!=="created")break;f(`runbook:${m.runbookId}`,{id:y.id,kind:"runbook-card",runbookId:m.runbookId,name:m.name,ts:pe(y),box:y.boxId,agent:y.provider});break}case"ticket.linked":{t.push({id:y.id,kind:"ticket-card",provider:m.provider||"linear",key:m.key,url:m.url,title:m.title??null,linkSource:m.linkSource??null,ts:pe(y),box:y.boxId,agent:y.provider});break}case"box.fullscreen.detected":{if(!m.offerId)break;for(let N of j.values())N.box===(m.box||y.boxId)&&(N.status="stale",j.delete(N.offerId));let k={id:y.id,kind:"fullscreen-offer",offerId:m.offerId,status:"open",ts:pe(y),box:m.box||y.boxId,agent:m.agent||y.provider};j.set(m.offerId,k),ee.set(m.offerId,k),t.push(k);break}case"box.fullscreen.answered":{let k=ee.get(m.offerId);k&&(k.status=m.action==="restarted"?"restarted":m.action==="cleared"?"cleared":"dismiss",j.delete(m.offerId));break}case"ticket.move.offered":{if(!m.offerId)break;for(let N of I.values())N.key===m.key&&(N.status="stale",I.delete(N.offerId));let k={id:y.id,kind:"ticket-offer",offerId:m.offerId,provider:m.provider||"linear",key:m.key,url:m.url??null,phase:m.phase??null,from:m.from??null,to:m.to?.name??null,prNumber:m.prNumber??null,status:"open",ts:pe(y),box:y.boxId,agent:y.provider};I.set(m.offerId,k),W.set(m.offerId,k),t.push(k);break}case"ticket.move.answered":{let k=W.get(m.offerId);k&&(k.status=m.action==="moved"?"moved":"dismiss",I.delete(m.offerId));break}case"ticket.state.changed":{for(let k of I.values())k.key===m.key&&k.to===m.to&&(k.status="stale",I.delete(k.offerId));if(m.mode==="offer")break;t.push(dt(y,"ticket-state"));break}case"ticket.commented":{t.push({id:y.id,kind:"ticket-comment",key:m.key,url:m.url??null,excerpt:m.excerpt??null,ts:pe(y),box:y.boxId,agent:y.provider});break}case"ticket.flow.changed":t.push(dt(y,"ticket-flow"));break;case"ticket.create.offered":{if(!m.proposalId)break;for(let N of q.values())N.status="stale";q.clear();let k={id:y.id,kind:"ticket-create-offer",proposalId:m.proposalId,provider:m.provider||"linear",epic:m.epic??null,issues:Array.isArray(m.issues)?m.issues:[],team:m.team??null,needsTeam:!!m.needsTeam,linkCurrentTrack:!!m.linkCurrentTrack,status:"open",ts:pe(y),box:y.boxId,agent:y.provider};q.set(m.proposalId,k),O.set(m.proposalId,k),t.push(k),ce(k);break}case"ticket.create.answered":{let k=O.get(m.proposalId);k&&(k.status=m.action==="created"?"created":"dismiss",k.createdCount=m.createdCount??null,k.failedCount=m.failedCount??null,q.delete(m.proposalId));break}case"loop.create.offered":{if(!m.proposalId)break;for(let N of z.values())N.status="stale";z.clear();let k={id:y.id,kind:"loop-create-offer",proposalId:m.proposalId,name:m.name??"",schedule:m.schedule??"",prompt:m.prompt??"",expectation:m.expectation??null,notify:m.notify??"off",assignment:m.assignment??{provider:"claude"},repo:m.repo??null,nodeId:m.nodeId??null,nodeName:m.nodeName??null,status:"open",ts:pe(y),box:y.boxId,agent:y.provider};z.set(m.proposalId,k),te.set(m.proposalId,k),t.push(k),ce(k);break}case"loop.create.answered":{let k=te.get(m.proposalId);k&&(k.status=m.action==="created"?"created":"dismiss",z.delete(m.proposalId));break}case"followup.armed":{if(!m.armId)break;let k=m.replaces?ie.get(m.replaces):null;k&&k.status==="armed"&&(k.status="replaced");let N={id:y.id,kind:"followup-armed",armId:m.armId,trigger:m.trigger??"now",label:m.label??"",prompt:m.prompt??"",why:m.why??null,status:"armed",ts:pe(y),box:y.boxId,agent:y.provider};ie.set(m.armId,N),N.trigger!=="now"&&t.push(N);break}case"followup.armed.cancelled":{let k=ie.get(m.armId);k&&k.status==="armed"&&(k.status="cancelled");break}case"followup.offered":{if(!m.offerId)break;for(let oe of H.values())oe.trigger===m.trigger&&(oe.status="stale",H.delete(oe.offerId));let k=Array.isArray(m.rows)?m.rows:[];for(let oe of k){let fe=oe.armId?ie.get(oe.armId):null;fe&&fe.status==="armed"&&(fe.status="offered")}let N={id:y.id,kind:"followup-offer",offerId:m.offerId,trigger:m.trigger??"now",repo:m.repo??null,context:m.context&&typeof m.context=="object"?m.context:{},rows:k.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:pe(y),box:y.boxId,agent:y.provider};H.set(m.offerId,N),ke.set(m.offerId,N),t.push(N),N.trigger==="now"&&ce(N);break}case"followup.answered":{let k=ke.get(m.offerId);k&&(k.status=m.action==="sent"?"sent":m.action==="removed"?"removed":"dismiss",k.answer={followupId:m.followupId??null,armId:m.armId??null,label:m.label??null,promoted:m.promoted??null,revived:m.revived===!0},H.delete(m.offerId));break}case"followup.create.offered":{if(!m.proposalId)break;for(let N of le.values())N.status="stale";le.clear();let k={id:y.id,kind:"followup-create-offer",proposalId:m.proposalId,label:m.label??"",prompt:m.prompt??"",trigger:m.trigger??"pr.merged",repo:m.repo??null,why:m.why??null,status:"open",created:null,ts:pe(y),box:y.boxId,agent:y.provider};le.set(m.proposalId,k),de.set(m.proposalId,k),t.push(k),ce(k);break}case"followup.create.answered":{let k=de.get(m.proposalId);k&&(k.status=m.action==="created"?"created":"dismiss",le.delete(m.proposalId));break}case"followup.created":{let k=m.proposalId?de.get(m.proposalId):null;k&&(k.created={followupId:m.followupId??null});break}case"loop.created":{let k=m.proposalId?te.get(m.proposalId):null;k&&(k.created={loopId:m.loopId??null,nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),t.push(dt(y,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!m.proposalId||!m.loopId)break;for(let oe of Ae.values())oe.loopId===m.loopId&&(oe.status="stale",oe.staleReason="superseded",Ae.delete(oe.proposalId));let k=y.type==="loop.update.offered",N={id:y.id,kind:k?"loop-update-offer":"loop-delete-offer",proposalId:m.proposalId,loopId:String(m.loopId),name:m.name??m.base?.name??"",base:m.base??null,...k?{patch:m.patch??{},changed:Array.isArray(m.changed)?m.changed:Object.keys(m.patch||{})}:{reason:m.reason??""},selfEdit:!!m.selfEdit,status:"open",staleReason:null,ts:pe(y),box:y.boxId,agent:y.provider};Ae.set(m.proposalId,N),_e.set(m.proposalId,N),t.push(N),ce(N);break}case"loop.update.answered":{let k=_e.get(m.proposalId);k&&(m.action==="moved"?(k.status="stale",k.staleReason="moved"):k.status=m.action==="applied"?"applied":"dismiss",Ae.delete(m.proposalId));break}case"loop.delete.answered":{let k=_e.get(m.proposalId);k&&(m.action==="moved"?(k.status="stale",k.staleReason="moved"):k.status=m.action==="delete"?"deleted":m.action==="pause"?"paused":"keep",Ae.delete(m.proposalId));break}case"loop.updated":{let k=m.proposalId?_e.get(m.proposalId):null;k&&(k.applied={changed:Array.isArray(m.changed)?m.changed:[],nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),t.push(dt(y,"loop-updated"));break}case"loop.deleted":t.push(dt(y,"loop-deleted"));break;case"loop.paused":t.push(dt(y,"loop-paused"));break;case"rework.cause.offered":{if(!m.sha||xt.has(m.sha))break;let k={id:y.id,kind:"rework-cause-offer",sha:m.sha,subject:m.subject??"",linesReworked:Number(m.linesReworked)||0,origins:Array.isArray(m.origins)?m.origins:[],heuristic:m.heuristic??null,status:"open",cause:null,ts:pe(y),box:y.boxId,agent:y.provider};xt.set(m.sha,k),t.push(k);break}case"rework.cause.answered":{let k=m.sha?xt.get(m.sha):null;k&&(k.status="answered",k.cause=m.cause??null);break}case"ticket.created":{let k={items:Array.isArray(m.items)?m.items:[],failed:Array.isArray(m.failed)?m.failed:[],team:m.team??null},N=m.proposalId?O.get(m.proposalId):null;if(N){N.created=k;break}t.push({id:y.id,kind:"ticket-created",...k,ts:pe(y),box:y.boxId,agent:y.provider});break}case"error":{if(!m.kind)break;t.push(dt(y,m.kind));break}case"provider.error":t.push({...dt(y,"provider-error"),provider:y.provider,box:y.boxId,agent:y.provider});break;case"usage.cap.hit":t.push(dt(y,"usage-cap-hit"));break;case"usage.cap.warning":t.push(dt(y,"usage-cap-warning"));break;case"provider.connected":{t.push({id:y.id,kind:"event",type:"provider-connected",provider:m.provider||y.provider,ts:pe(y),at:pe(y),box:y.boxId,agent:y.provider});break}case"prompt.answered":{if(V=null,m.control||!m.question)break;let k=m.groupId||m.promptId;if(!k)break;let N=je.get(k);N||(N={id:y.id,kind:"prompt",groupId:k,provider:y.provider,box:y.boxId,agent:y.provider,questionTotal:m.questionTotal??1,questions:[],ts:pe(y)},je.set(k,N));let oe=m.questionIndex??0,fe={index:oe,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:Array.isArray(m.chosen)?m.chosen:[]},De=N.questions.findIndex(Re=>Re.index===oe&&We(Re.question)===We(fe.question));De>=0?N.questions[De]=fe:N.questions.push(fe),N.questions.sort((Re,ba)=>Re.index-ba.index),N.questionTotal=Math.max(N.questionTotal,m.questionTotal??1),N.questions.length>=N.questionTotal&&(t.push(N),je.delete(k));break}default:break}}let nt=u.size?t.filter(y=>!y.retired):t;return jM(nt.sort((y,m)=>(y.ts??0)-(m.ts??0)))}function jM(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<=BM){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:LM(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??gr(e)).filter(o=>o.kind==="message");return ub(n,r)}function LM(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==ps(e.command)?t:hr(e.command,e.description||"")}function dt(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 fk(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)+FM,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&UM.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function pk(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!WM.has(r.type)||!r.box)continue;let o=(r.ts??0)+HM,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 mk(e){return(e||[]).filter(t=>qM.has(t?.kind)&&t.status==="open")}var pe,PM,dk,BM,FM,UM,HM,WM,qM,ep=L(()=>{ms();io();pl();xl();_l();Zf();pe=e=>e.payload?.ts??e.ts;PM=new Set(["opened","ci-fixed","reconciled","pushed"]),dk=e=>`${e.repo??""}#${e.number}`;BM=2*6e4;FM=12e4,UM=new Set(["archived","unarchived","opened"]);HM=2500,WM=new Set(["pr-opened","pr-merged","pr-auto-armed"]);qM=new Set(["pr-offer","pr-exists-offer","ticket-offer","ticket-create-offer","loop-create-offer","loop-update-offer","loop-delete-offer","fullscreen-offer","followup-create-offer"])});function YM(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 XM(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 ZM(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<VM&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<zM&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function yk(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=YM(e),s=XM(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=gr(e??[]).filter(d=>d?.kind==="message"&&typeof d.text=="string"&&d.text.trim()).slice(-KM);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(gk[r]??gk.failover),l.push(""),o.lastPush?.sha){let d=wk(n,o.lastPush.ts),p=d?` (~${d} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${p}`+(o.lastPush.wip?" \u2014 a bostrat WIP snapshot (full working tree incl. uncommitted edits at push time).":"."))}else r==="in-place"?l.push("**Code state:** no push recorded \u2014 the working tree in this workspace is the only copy; commit early."):l.push("**Code state:** no push was ever recorded for this Track \u2014 work since the branch's last known state stayed on the offline node.");if(l.push(""),a){let d=wk(n,i);l.push(`## Last real checkpoint (written by the previous agent${d?`, ~${d} min before this reconstruction`:""})`),l.push(""),l.push(a.trim()),l.push("")}let u=ZM(e??[],i);if((u.files.length||u.heads.length)&&(l.push(`## Work since ${a?"that checkpoint":"the start of the log"} (from the event log)`),l.push(""),u.files.length&&l.push(`Files touched (most recent first): ${u.files.map(d=>`\`${d}\``).join(", ")}`),u.heads.length&&(u.files.length&&l.push(""),l.push(`Commands run (most recent first): ${u.heads.map(d=>`\`${d}\``).join(" \xB7 ")}`)),l.push("")),c.length){l.push(`## Recent conversation (last ${c.length} message${c.length===1?"":"s"})`),l.push("");for(let d of c)l.push(`**${d.role==="user"?"operator":"agent"}:** ${JM(d.text,GM)}`),l.push("")}l.push("---"),l.push("Resume: continue the objective above from the verified repository state; ask the operator before redoing anything the log says was already done.");let f=l.join(`
151
+ `);return f.length<=hk?f:`${f.slice(0,hk)}
152
+
153
+ [\u2026 brief truncated]`}var KM,GM,hk,VM,zM,JM,wk,gk,bk=L(()=>{ep();KM=12,GM=2e3,hk=48e3,VM=30,zM=10;JM=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},wk=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;gk={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 QM from"node:fs";import yr from"node:fs/promises";import br from"node:path";function _k(e){let t=no(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=kk?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,kk).toString("utf8").replace(/�+$/,"")}
154
+
155
+ [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function cN(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(vk.test(s)){if(r.length>=Mk)continue;let a=iN(s.replace(vk,"").replace(/[.;,:]+$/,""),Nk,sN);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>xk&&(o=`${o.slice(0,xk-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function Pk(e,t,{timeoutMs:n=9e4}={}){let r=br.join(t,rN),o=br.join(r,oN);await yr.mkdir(r,{recursive:!0});let s=await Il(o),a=await ye(e);if(!a)throw new Error(`session "${e}" not found`);return await $l(e,a,aN(o)),await Hk(o,s,n),cN(await yr.readFile(o,"utf8"))}function Dk(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===$k||n===Ck;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(Ik)||n===eN||r.startsWith(Rk)||r.startsWith(Ok)}function Bk(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-lN;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 jk(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 Lk(e,{windows:t=[]}={}){if(Dk(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 Rl(e){return tp.get(e)||null}async function Fk(e){let t=tp.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await ye(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:br.join(n.cwd,Ek,Ak)};return tp.set(e,r),fN(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function fN(e,t){e.step="summarize",await Uk(e.name,t),e.step="clear";let n=await ye(e.name);await $l(e.name,n,"/clear"),await op(uN),e.step="resume",await $l(e.name,n,nN),e.step="done",e.finishedAt=Date.now()}async function Uk(e,t,{timeoutMs:n=dN}={}){let r=br.join(t,Ek),o=br.join(r,Ak);await yr.mkdir(r,{recursive:!0});let s=await Il(o),a=await ye(e);await se({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await $l(e,a,tN(o)),await Hk(o,s,n),await se({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await Il(o)});let i=await Xb(t,o,{exclude:u=>Dk(u.role,u.text)});await se({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(c){await $({id:c,cwd:t},{type:"memory.seed",actor:"orchestrator",payload:{...i,tokensEst:i.chars?Math.round(i.chars/4):0,ts:Date.now()}}).catch(()=>{});try{let u=await yr.readFile(o,"utf8");await $({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{..._k(u),ts:Date.now()}})}catch{}}await tf(t);let l=await pN(r,o);return c&&await Cy(c,l||o,{box:e,agent:a?.agent??null}),o}async function np(e,{timeoutMs:t}={}){let n=await ye(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);return Uk(e,n.cwd,t?{timeoutMs:t}:void 0)}async function rp(e,t,{trackName:n="this Track"}={}){let r=await U({id:e,cwd:t}),o=yk(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=br.join(t,Sk);return await yr.mkdir(br.dirname(s),{recursive:!0}),await yr.writeFile(s,o,"utf8"),await $({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{..._k(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),Sk}async function Il(e){try{return(await yr.stat(e)).mtimeMs}catch{return 0}}async function Hk(e,t,n){let r=Date.now()+n;for(;;){if(await Il(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await op(2e3)}}async function pN(e,t){try{if(!QM.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=br.join(e,`${n}.md`);return await yr.copyFile(t,r),r}catch{return null}}function op(e){return new Promise(t=>setTimeout(t,e))}function Tk(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 $l(e,t,n){if(t){let o=Tk(t.agent);await wr({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await ye(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await Le(e,["Escape"],{kind:"drive-wipe"}),await op(150),await ls(e,ul,{kind:"drive-wipe"}),await Ze(e,n,{kind:"orchestration-drive",...pn(r.agent,n)}),await ri({sessionName:e,agent:r.agent,agentCmd:Tk(r.agent),text:n,flow:"orchestration-drive"})}var Ek,Ak,kk,Ik,$k,Rk,eN,tN,nN,Ok,Ck,rN,oN,xk,Mk,Nk,sN,aN,vk,iN,lN,uN,dN,tp,Sk,sp=L(()=>{lt();Qa();dn();ei();Wf();Zb();Ca();he();tl();bk();Ek=".bostrat/handoff",Ak="latest.md",kk=32*1024;Ik="Checkpoint: write a work-in-progress handoff",$k="HANDOFF WRITTEN",Rk="Resume from .bostrat/handoff/latest.md",eN="/clear",tN=e=>`${Ik} 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 ${$k} and take no further action.`,nN=`${Rk}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,Ok="Beat: write a",Ck="BEAT WRITTEN",rN=".bostrat/arc",oN="beat.txt",xk=200,Mk=4,Nk=5,sN=36,aN=e=>`${Ok} 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 ${Mk} further lines, each starting with "- " and naming ONE piece in at most ${Nk} 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 ${Ck} and take no further action.`,vk=/^(?:[-–—*•·]|\d+[.)])\s+/,iN=(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};lN=6e5;uN=3500,dN=3e5,tp=new Map;Sk=".bostrat/handoff/status-latest.md"});function xr(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!Ol.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 Kk(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:xr(o.from,"from",n),toMs:xr(o.to,"to",n)}))}return t}function ip(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 hN(e){if(!e)return null;let t=String(e).trim();return kr[t]?t:Wk[t]?Wk[t]:Object.keys(kr).find(r=>t.startsWith(r))||null}function wN(e){if(!e||e===kr)return mN;let t=qk.get(e);return t||(t=Kk(e),qk.set(e,t)),t}function Gk(e,t,n={}){let{table:r,speed:o}=n,s=wN(r),a=r&&r!==kr?s[e]?e:null:hN(e);if(!a)return null;let i=ip(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 mn(e,t={},n,r){let o=Gk(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 gN(e=kr){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:xr(a.from,"from",n),toMs:xr(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`),Ol.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 bN({now:e=Date.now(),table:t=kr,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...yN,...n},a=[],i=ip(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(f=>({...f,fromMs:xr(f.from,"from",c),toMs:xr(f.to,"to",c),verifiedMs:Ol.test(String(f.verifiedAt??""))?Date.parse(`${f.verifiedAt}T00:00:00.000Z`):NaN}))}catch(f){a.push(String(f.message));continue}for(let f of u){if(!Number.isFinite(f.verifiedMs)){a.push(`${c}: window ${f.from??"\u2026"} \u2192 ${f.to??"now"} has no verifiedAt`);continue}let d=i>=f.fromMs&&i<=f.toMs,p=f.fromMs>i&&f.fromMs-i<=o*ap;d&&i-f.verifiedMs>r*ap&&a.push(`${c}: current rate last verified ${f.verifiedAt} (>${r}d) \u2014 re-check the vendor page and bump verifiedAt`),p&&f.fromMs-f.verifiedMs>s*ap&&a.push(`${c}: scheduled rate change on ${f.from} was last verified ${f.verifiedAt} \u2014 confirm it is still happening (vendors cancel; sonnet-5 did) and bump verifiedAt`)}}return a}function ks({now:e=Date.now(),table:t=kr,...n}={}){let r=ip(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=xr(l.from,"from",i),f=xr(l.to,"to",i);r>=u&&r<=f&&Ol.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=[...gN(t),...bN({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var kr,Wk,Ol,mN,qk,Vk,yN,ap,Dn=L(()=>{kr={"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:null,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)."}],"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)."}]},Wk={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"},Ol=/^\d{4}-\d{2}-\d{2}$/;mN=Kk(kr);qk=new WeakMap;Vk=(e,t,n)=>Gk(e,t,n)!==null;yN=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),ap=864e5});function kN(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function Yk(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Ft(e){let t=e.payload?.model||"unknown",n=kN(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=mn(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&&!Vk(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function vr(e,{boxLabels:t={}}={}){let n=(e||[]).filter(d=>d.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,f=zk();for(let d of n){let{usd:p,model:h,tokens:w,repriced:g,unpriced:b,asRecorded:E}=Ft(d);i+=E;let S=d.provider||"unknown",R=d.boxId||"unattributed";if(g&&c++,b&&(l++,u.add(h)),a+=p,Yk(f,w),r[h]||={usd:0,tokens:zk(),events:0},r[h].usd+=p,r[h].events+=1,Yk(r[h].tokens,w),o[S]||={usd:0,events:0},o[S].usd+=p,o[S].events+=1,s[R]||={usd:0,events:0,provider:S,models:new Set,label:t[R]||R},s[R].usd+=p,s[R].events+=1,h!=="unknown"&&s[R].models.add(h),d.epoch!=null){let M=(s[R].epochs||={})[d.epoch]||={usd:0,events:0,provider:S,models:new Set};M.usd+=p,M.events+=1,M.provider=S,h!=="unknown"&&M.models.add(h)}}return{totalUsd:xs(a),asRecordedUsd:xs(i),totalTokens:f,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:Cl(r,d=>({...d,usd:xs(d.usd)})),byProvider:Cl(o,d=>({...d,usd:xs(d.usd)})),byBox:Cl(s,d=>({usd:xs(d.usd),events:d.events,provider:d.provider,label:d.label,models:[...d.models],...d.epochs?{epochs:Cl(d.epochs,p=>({usd:xs(p.usd),events:p.events,provider:p.provider,models:[...p.models]}))}:{}}))}}var zk,xs,Cl,Sr=L(()=>{Dn();zk=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});xs=e=>Math.round(e*1e4)/1e4,Cl=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function xN(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 Jk(e,t=[]){let n=[],r=e?.events||[],o=new Map,s=0;for(let u of t){if(u.type!=="pr.state.changed")continue;let f=u.payload||{};!f.repo||f.number==null||(f.change==="merged"?o.set(`${f.repo}#${f.number}`,f):f.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(f=>{let[d,p]=f.split("#");return`${d.split("/").pop()}#${p}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(cp(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(cp(a,"subtask"));let i=r.filter(u=>u.type==="lead-handoff"&&u.fromAgent&&u.toAgent);if(i.length){let u=i.slice(0,3).map(f=>`${f.fromAgent}\u2192${f.toAgent}`).join(", ");n.push(`${cp(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=vr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?xN(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var cp,Xk=L(()=>{Sr();cp=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as vN}from"node:child_process";import{promisify as SN}from"node:util";import{randomUUID as TN}from"node:crypto";async function lp(e,t){let n=Date.now()+t;for(;;){if(await Mn(e))return!0;if(Date.now()>n)return!1;await ci(AN)}}async function IN(e,t){let n=Qk[t]||Qk.default;n.escape&&(await Le(e,["Escape"],{kind:"swap-exit"}),await ci(150)),n.wipe&&await ls(e,ul,{kind:"swap-exit"}),await dl(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=pn(t).submitDelayMs||0;await ci(Math.max(r,250)),await Le(e,["Enter"],{kind:"swap-exit"})}async function e0(e,t){try{let{stdout:n}=await lo(G,Y("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function t0(e){await lo(G,Y("respawn-pane","-k","-t",e))}async function up(e,t={}){if(!Pe(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await ye(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||fr(n),a=Number(t.exitTimeoutMs)||EN;await se({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let i=!1;if(!await Mn(e)&&(await IN(e,o),!await lp(e,a)&&(i=!0,await se({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await t0(e),!await lp(e,Zk))))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);let c=s==="claude"&&ro(n),l=c?Dc():null,u=await e0(e,"ANTHROPIC_API_KEY"),f=!1;try{l?(await lo(G,Y("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),f=!0):u&&(await lo(G,Y("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),f=!0)}catch(g){throw l?ol(g,l):g}if(f&&!i&&(await t0(e),!await lp(e,Zk)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let d=!!t.resumeSessionId,p=t.resumeSessionId||TN(),h=d?n:Ha(n,p,e),w=d?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(h);return c&&await sr(r.cwd),s==="codex"&&await Jo(r.cwd),s==="cursor"&&await Xo(r.cwd),await oo(e),await lo(G,Y("set-option","-t",e,"@bostrat-sid",p)),await lo(G,Y("set-option","-t",e,"@bostrat-agent",s)),await ci(_N),c&&Ua().length&&(await e0(e,Fa)||await lo(G,Y("set-environment","-t",e,Fa,"1")).catch(()=>{}),await Ze(e,`export ${Fa}=1`,{kind:"swap-env"}),await ci(150)),await Ze(e,h,{kind:"swap-launch"}),await se({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:p,forced:i,envRespawned:f}),{name:e,cwd:r.cwd,sessionId:p,agent:s,pinned:w,forced:i,envRespawned:f,launchCmd:h}}var lo,ci,EN,Zk,AN,_N,Qk,n0=L(()=>{lt();Ea();jc();Lc();ei();dn();lo=SN(vN),ci=e=>new Promise(t=>setTimeout(t,e)),EN=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,Zk=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,AN=250,_N=400,Qk={claude:{escape:!0,wipe:!0,text:"/exit"},codex:{escape:!0,wipe:!0,text:"/quit"},cursor:{escape:!0,wipe:!0,text:"/quit"},default:{escape:!1,wipe:!1,text:"exit"}}});async function r0(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await Et(e,t)}catch{return[]}let o=new Map,s=new Set;for(let i of r.split(`
156
+ `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.isSidechain)continue;let u=l.message?.content;if(!Array.isArray(u))continue;let f=l.timestamp?Date.parse(l.timestamp):null;for(let d of u)if(!(!d||typeof d!="object"))if(d.type==="tool_use"&&d.id){if(d.name==="Agent"){let p=d.input||{};o.set(d.id,{id:d.id,kind:"agent",name:String(p.description||"").trim()||null,detail:String(p.subagent_type||"").trim()||null,ts:f,proven:!1})}else if(d.name==="Bash"&&d.input?.run_in_background===!0){let p=String(d.input.command||"").trim();o.set(d.id,{id:d.id,kind:"command",name:String(d.input.description||"").trim()||(p?ps(p):null),detail:p?ps(p):null,ts:f,proven:!0})}}else d.type==="tool_result"&&d.tool_use_id&&$N.test(RN(d.content))&&s.add(d.tool_use_id)}let a=[];for(let i of o.values()){if(!i.proven&&!s.has(i.id))continue;let{proven:c,...l}=i;a.push(l)}return a.slice(-n)}var $N,RN,o0=L(()=>{Xt();ms();$N=/^Async (?:agent|task) launched/i,RN=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 Tr(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 ON(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 s0(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:Zt(`read ${Tr(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${vs(r)}`:`Read ${vs(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?Tr(t.path,n):null,s=t?.glob?` --glob ${dp(t.glob)}`:"",a=Zt(String(r),40);return{command:Zt(`grep ${dp(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?Tr(t.target_directory,n):null;return{command:Zt(`glob ${dp(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${Zt(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:Zt(`edit ${Tr(t.path,n)}`,140),description:`Edit ${vs(t.path)}`}:null;case"Write":return t?.path?{command:Zt(`write ${Tr(t.path,n)}`,140),description:`Write ${vs(t.path)}`}:null;case"Delete":return t?.path?{command:Zt(`delete ${Tr(t.path,n)}`,140),description:`Delete ${vs(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>Tr(s,n)).filter(Boolean);return{command:Zt(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=ON(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:Zt(`apply_patch ${Tr(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${vs(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:Zt(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var Ml,Zt,vs,dp,a0=L(()=>{Ml=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),Zt=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,vs=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);dp=e=>`"${String(e).replace(/"/g,'\\"')}"`});import li from"node:fs";import CN from"node:fs/promises";import uo from"node:path";import MN from"node:os";import NN from"node:crypto";import PN from"node:zlib";function l0(e){let t=NN.createHash("md5").update(String(e)).digest("hex");return uo.join(DN,t)}function u0(e){try{let t=JSON.parse(li.readFileSync(uo.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 BN(e){let t=l0(e),n;try{n=li.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=uo.join(t,o.name),a=uo.join(s,"store.db");if(!li.existsSync(a))continue;let i=u0(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 Nl(e,t){if(!e)return null;if(t){let n=uo.join(l0(e),t),r=uo.join(n,"store.db");if(li.existsSync(r))return{id:t,dir:n,store:r,...u0(n)||{createdAtMs:null,updatedAtMs:null}}}return BN(e)}function i0(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function jN(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=PN.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function LN(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 FN(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!Ml.has(r.toolName))continue;let o=s0(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 fp(e,t){if(!c0)return Ss;let{DatabaseSync:n}=c0,r;try{r=new n(e,{readOnly:!0})}catch{return Ss}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 Ss;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return Ss}let a=s.lastUsedModel||null,i=s.latestRootBlobId?i0(r,s.latestRootBlobId):null;if(!i)return{...Ss,model:a};let c=[],l=[],u=[],f=null,d=[];for(let p of LN(i)){let h=jN(i0(r,p));if(!h)continue;let w=h.providerOptions?.cursor;if(w?.requestId&&d.push(w.requestId),w?.modelProviderMessageId&&d.push(w.modelProviderMessageId),h.role!=="assistant")continue;if(Array.isArray(h.content))for(let E of h.content){let S=E?.providerOptions?.cursor?.modelName;S&&(f=S)}l.push(...FN(h.content,t).map((E,S)=>({...E,id:E.id||`${p}:${S}`}))),u.push(...HN(h.content));let g=UN(h.content);if(!g)continue;let b=[...new Set(u)];u=[],c.push({id:p,text:g,tools:b.length?b:void 0,commands:l,model:f}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:d}}catch{return Ss}finally{try{r.close()}catch{}}}function d0(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(li.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 f0(e,t,{limit:n=80}={}){let r=Nl(e,t);if(!r)return[];let{turns:o,model:s}=await fp(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=d0(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 p0(e,t){let n=Nl(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await fp(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 m0(e,t,{limit:n=80}={}){let r=Nl(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await fp(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=d0(r,a.length||1),l=[];a.forEach((u,f)=>{for(let d of u.commands)l.push({...d,summary:hr(d.command,d.description),ts:c(f)})});for(let u of s)l.push({...u,summary:hr(u.command,u.description),ts:i+1});return l}async function h0(e,t){let n=Nl(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await CN.stat(n.store)).mtimeMs)}catch{return null}}var DN,UN,HN,c0,Ss,pp=L(()=>{ms();a0();DN=process.env.BOSTRAT_CURSOR_CHATS||uo.join(MN.homedir(),".cursor","chats");UN=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(`
157
+ `).trim():"",HN=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],c0=process.getBuiltinModule?.("node:sqlite"),Ss={turns:[],trailingCommands:[],model:null,requestIds:[]}});import WN from"node:fs/promises";function gp(e){return w0.set(e.agent,e),e}function ui(e){return w0.get(e)||qN}async function bp(e,t={}){return(await ui(e.agent).readMessages(e,t)).map(yp(e))}async function g0(e,t={}){return(await ui(e.agent).readCommands(e,t)).map(yp(e))}async function y0(e,t={}){return(await ui(e.agent).readJobs(e,t)).map(yp(e))}var Ts,mp,hp,wp,qN,w0,yp,b0=L(()=>{Xt();ml();ms();o0();pp();io();Ts=class{constructor(t,n=new Set){this.agent=t,this.cliTools=n}async readMessages(){return[]}async readCommands(){return[]}async readJobs(){return[]}async updatedAt(){return null}},mp=class extends Ts{transcript(t){return!t?.cwd||!t?.sessionId?null:Jt(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?Rf(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?lb(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?r0(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await WN.stat(n)).mtimeMs)}catch{return null}}},hp=class extends Ts{async readMessages(t,n){return f0(t.cwd,t.sessionId,n)}async readCommands(t,n){return m0(t.cwd,t.sessionId,n)}async updatedAt(t){return h0(t.cwd,t.sessionId)}},wp=class extends Ts{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return pb(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return mb(t.cwd,this.sessionId(t),n)}async updatedAt(t){return hb(t.cwd,this.sessionId(t))}},qN=new Ts("unknown"),w0=new Map;gp(new mp("claude",Ef));gp(new hp("cursor",Ml));gp(new wp("codex",Ya));yp=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function mo(e){let t=e.search(Sp);return(t>=0?e.slice(0,t):e).trim()}function KN(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function GN(e){let t=String(e).trim();return!!(!t||po.test(e)||Sp.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function VN(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=zN(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function zN(e,t){let n=String(t).toLowerCase(),r=e.findIndex(c=>!c.answered),o=r>=0?r:e.length-1;if(!n)return o;let s=e.map(c=>{let l=c.label.toLowerCase(),u=l.split(/\s+/).filter(d=>d.length>3&&n.includes(d)).length;if(u)return u;let f=l.slice(0,8).trim();return f.length>=4&&n.includes(f)?1:0}),a=Math.max(...s);if(a===0||s[o]===a)return o;let i=s.flatMap((c,l)=>c===a?[l]:[]);return i.length===1?i[0]:o}function x0(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function YN(e,t=""){let n=String(e);if(!S0.test(n))return null;let r=n.replace(/\r/g,"").split(`
158
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(/^\s*Switch model\?\s*$/.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[];for(let u=o+1;u<r.length;u++){let f=r[u].match(fo);if(f)s.push({cursor:!!f[1],label:f[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let d=r[u].trim();d&&!po.test(r[u])&&a.push(d)}}if(s.length<2)return null;let i=s.map(u=>({label:mo(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 XN(e,t=""){let n=String(e).replace(/\r/g,"").split(`
159
+ `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!T0.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(fo);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&&!(JN.test(n[c])||po.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:mo(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 ZN(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
160
+ `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(fo);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 eP(e,t=""){let n=String(e);if(!kp.test(n))return null;let r=n.replace(/\r/g,"").split(`
161
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(QN.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[r[o].trim()];for(let u=o+1;u<r.length;u++){let f=r[u].match(fo);if(f)s.push({cursor:!!f[1],label:f[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let d=r[u].trim();d&&!po.test(r[u])&&a.push(d)}}if(s.length<2||!s.some(u=>kp.test(u.label)))return null;let i=s.map(u=>({label:mo(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 Tp(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(fo);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 tP(e,t=""){let n=String(e);if(!E0.test(n)||!A0.test(n)||ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
162
+ `),o=Tp(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:mo(s.label),description:""}))}]}:null}function nP(e,t=""){let n=String(e);if(!_0.test(n)||ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
163
+ `),o=Tp(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:mo(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 oP(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!rP.test(o)||Ep.test(e[r]))break;n+=o}return n}function sP(e,t=""){let n=String(e);if(!Ep.test(n)||ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
164
+ `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=oP(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 iP(e,t=""){let n=String(e);if(!xp.test(n)||!aP.test(n)||ho.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
165
+ `)].reverse().find(a=>xp.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 cP(e,t=""){let n=String(e);if(!I0.test(n)||ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
166
+ `),o=Tp(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:mo(s.label),description:""}))}]}:null}function lP(e,t=""){let n=String(e);if(ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
167
+ `),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($0);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(po.test(r[l])||Sp.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 uP(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(vp.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 dP(e,t=""){let n=String(e);if(!v0.test(n)||!vp.test(n))return null;let r=n.replace(/\r/g,"").split(`
168
+ `),o=uP(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let C=i;C<c;C++){let I=r[C].match(fo);I&&(u<0&&(u=C),l.push({line:C,cursor:!!I[1],checked:I[3]!=null&&I[3]!==" ",hasCheckbox:I[3]!=null,label:I[4].trim(),desc:""}))}if(!l.length)return null;for(let C of l)for(let I=C.line+1;I<Math.min(r.length,C.line+4)&&!(fo.test(r[I])||po.test(r[I]));I++){let W=r[I].trim();if(!(!W||GN(r[I])||k0.test(W))){C.desc=KN(W);break}}let f=l.filter(C=>!k0.test(C.label));if(!f.length)return null;let d=f.some(C=>C.hasCheckbox),p=Math.max(0,f.findIndex(C=>C.cursor)),h=s>=0?s+1:0,w=[];for(let C=h;C<u;C++){let I=r[C].trim();I&&!po.test(r[C])&&!/[☐☒]/.test(r[C])&&w.push(I)}let g=w.join(" ")||(s>=0?x0(r[s]):"")||"The agent is asking a question",b=s>=0?VN(r[s],g):null,E=b?.currentTabLabel||(s>=0?x0(r[s]):""),S=f.map(C=>({label:mo(C.label),description:C.desc})),R=S.map(C=>C.label).join("|"),T=`claude:${b?`q${b.questionIndex+1}/${b.questionTotal}`:"q1/1"}:${E}:${g}:${R}`.slice(0,240),A=b?`claude:ask:${b.tabs.map(C=>C.label).join("|")}`.slice(0,240):T;return{provider:"claude",box:t,multiSelect:d,cursorIndex:p,promptId:T,groupId:A,...b?{questionIndex:b.questionIndex,questionTotal:b.questionTotal,currentTabLabel:b.currentTabLabel,tabs:b.tabs}:{},questions:[{question:g,header:E,multiSelect:d,options:S}]}}function wo(e,t){let n=String(t||"");return n?e==="claude"?v0.test(n)&&vp.test(n)||S0.test(n)||kp.test(n)||T0.test(n.trimEnd().split(`
169
+ `).pop()||"")?!0:ho.test(n)?!1:E0.test(n)&&A0.test(n)||_0.test(n)||Ep.test(n)||xp.test(n)||I0.test(n)||$0.test(n.trimEnd().split(`
170
+ `).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 Er(e,t){return!e||!t?null:e.agent==="claude"?ZN(t,e.name)||dP(t,e.name)||YN(t,e.name)||eP(t,e.name)||iP(t,e.name)||sP(t,e.name)||nP(t,e.name)||tP(t,e.name)||cP(t,e.name)||lP(t,e.name)||XN(t,e.name):e.agent==="cursor"||e.agent==="codex"?Rb(e.agent,t,e.name):null}async function Ap(e){if(!e)return null;let t=await Nn(e.name).catch(()=>"");return Er(e,t)}function R0(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 O0(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 v0,vp,fo,k0,po,Sp,S0,T0,JN,kp,QN,ho,E0,A0,_0,Ep,rP,xp,aP,I0,$0,_p=L(()=>{lt();wl();v0=/to navigate\b.*\bEsc to cancel|Enter to select\b/,vp=/Chat about this/i,fo=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,k0=/^(type something|chat about this|submit)\b/i,po=/^[─—-]{6,}\s*$/,Sp=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;S0=/^\s*Switch model\?\s*$/m;T0=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,JN=/^\s*[─—▔-]{6,}\s*$/;kp=/Resume from summary/i,QN=/^\s*This session is\b/;ho=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;E0=/Choose the text style that looks best with your terminal/,A0=/Let's get started\./;_0=/Select login method:/;Ep=/Paste code here if prompted/,rP=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;xp=/OAuth error:/,aP=/Press Enter to retry\./;I0=/Quick safety check: Is this a project you created or one you trust/;$0=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function Pl(e,t,n){if(!e||!t)return null;for(let r of fP)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function mP(e){let t=Ip.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},Ip.set(e,t)),t}function N0(e,t,n=Date.now()){let r=mP(e);if(r.sentAt=r.sentAt.filter(s=>n-s<M0),r.sentAt.length>=C0)return{action:"give-up"};if(n-r.last<pP)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 P0(e,t=Date.now()){let n=Ip.get(e);return n?n.sentAt.filter(r=>t-r<M0).length>=C0:!1}var fP,pP,C0,M0,Ip,$p=L(()=>{fP=[{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||""}
171
+ ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];pP=5e3,C0=5,M0=3600*1e3,Ip=new Map});function Es(e){return typeof e=="string"?e.trim():""}var D0=L(()=>{});import{execFile as hP}from"node:child_process";import{promisify as wP}from"node:util";async function Ue(e,t,{input:n}={}){let r=Op("git",["-C",e,...t],{maxBuffer:B0});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function As(e){if(!e)return!1;try{let{stdout:t}=await Ue(e,["rev-parse","--is-inside-work-tree"]);return t.trim()==="true"}catch{return!1}}async function j0(e){let{stdout:t}=await Ue(e,["rev-parse","--show-toplevel"]);return t.trim()}async function gP(e){try{return await Ue(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function _s(e,t="bostrat: subtask snapshot"){let{stdout:n}=await Ue(e,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>Op("git",["-C",e,...a],{maxBuffer:B0,env:o,...i});try{let a=await gP(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 Op("rm",["-f",r])}catch{}}}async function Cp(e,t,{trailers:n=[]}={}){let{stdout:r}=await Ue(e,["status","--porcelain"]);return r.trim()?(await Ue(e,["add","-A"]),await Ue(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",t,...n.flatMap(o=>["--trailer",o])]),!0):!1}async function di(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await Ue(e,["status","--porcelain"]),r=n.split(`
172
+ `).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 fi(e,t){if(!t)return 0;try{let{stdout:n}=await Ue(e,["rev-list","--count",`${t}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function Is(e,t,n,r){return await Ue(e,["worktree","add","--no-track","-b",n,t,r]),t}async function L0(e,t){try{return await Ue(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function Dl(e,t,n){return await Ue(e,["worktree","add",t,n]),t}async function $s(e){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:t}=await Ue(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 Ue(e,["rev-parse","--verify","--quiet",t]),n}catch{}return"HEAD"}async function Mp(e){await Ue(e,["init","-q"]),await Ue(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function Rt(e,t){try{await Ue(e,["worktree","remove","--force",t])}catch{try{await Ue(e,["worktree","prune"])}catch{}}}function yP(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 Np(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function Pp(e,t,n,r){let{stdout:o}=await Ue(e,Np(["diff","--shortstat",t,n],r));return yP(o)}async function Dp(e,t,n,r){let{stdout:o}=await Ue(e,Np(["diff","--name-only",t,n],r));return o.split(`
173
+ `).map(s=>s.trim()).filter(Boolean)}async function Bp(e,t,n,r){let{stdout:o}=await Ue(e,Np(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await Rp(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await Rp(e,o,["--3way","--whitespace=nowarn"]),a=await bP(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await Rp(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function Rp(e,t,n){try{return await Ue(e,["apply",...n,"-"],{input:t}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function bP(e){try{let{stdout:t}=await Ue(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
174
+ `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var Op,B0,Bl=L(()=>{Op=wP(hP),B0=64*1024*1024});function jl(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!kP.has(o.state)&&o.state!=="stopped"&&(o.state="stopped",r=!0);let s=Array.isArray(o.epochs)?o.epochs:[],a=s[s.length-1];a&&typeof a=="object"&&a.endedAt==null&&(a.endedAt=t,a.endReason==null&&(a.endReason=n),r=!0)}return r}var Ve,kP,Bn=L(()=>{Ve=e=>!!(e&&(e.archivedAt||e.transferredTo)),kP=new Set(["merged","conflict","canceled","failed","handed-off"])});import jp from"node:fs/promises";import U0 from"node:path";import xP from"node:os";function K0(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function G0(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function V0(e){let t=new Date(K0(e));return t.setDate(t.getDate()+7),t.getTime()}function z0(e){let t=new Date(G0(e));return t.setMonth(t.getMonth()+1),t.getTime()}function Fl(e=Date.now()){for(let[t,n]of Object.entries(Rs)){let r=n.startOf(e);if(r!==jn[t]){jn[t]=r;for(let o of go.values())o[t]=0;for(let o of Os)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&Os.delete(o)}}}function Y0(e,t){let n=Qt?.caps?.[e]?.[Rs[t].capKey];return Number.isFinite(n)&&n>0?n:null}function yo(e,t=Date.now()){if(!e||!Fp||!Qt?.caps)return null;Fl(t);let n=go.get(e);for(let r of Object.keys(Rs)){let o=Y0(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:Ll(s),resetsAt:Rs[r].nextStart(t)}}return null}function J0(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${jn[t.window]}`;return Os.has(n)?!1:(Os.add(n),!0)}function F0(e,t,n,r=Date.now()){if(!e||!t)return;Fl(r);let o=vP(e);for(let[s,a]of Object.entries(Rs))n>=jn[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function SP(e,t,n=Date.now()){if(!Qt?.caps||!Lp)return;let r=go.get(e);if(r)for(let[o,s]of Object.entries(Rs)){let a=Y0(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*q0||i>=a)continue;let c=`warn:${e}:${o}:${jn[o]}`;if(!Os.has(c)){Os.add(c);try{let l=await Lp(t);if(!l)continue;await $(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:Ll(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function X0(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 Ul(e,{source:t="local",updatedAt:n=Date.now()}={}){Qt={caps:X0(e),updatedAt:n,source:t};try{await jp.mkdir(H0,{recursive:!0}),await jp.writeFile(W0(),JSON.stringify(Qt,null,2))}catch{}return pi()}function pi(e=Date.now()){Fl(e);let t=new Set([...go.keys(),...Object.keys(Qt?.caps||{})]),n={};for(let r of t){let o=go.get(r);n[r]={weeklyUsd:Ll(o?.weekly||0),monthlyUsd:Ll(o?.monthly||0)}}return{caps:Qt?.caps||{},configured:!!Qt,seeded:Fp,updatedAt:Qt?.updatedAt??null,spent:n,windows:{weekly:{start:jn.weekly,resetsAt:V0(e)},monthly:{start:jn.monthly,resetsAt:z0(e)}},warnPct:q0}}async function Z0({listTracks:e,getTrack:t}={}){Lp=t||null,Fl();try{let o=JSON.parse(await jp.readFile(W0(),"utf8"));Qt={caps:X0(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{Qt=null}let n=Date.now();ct.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Ft(o);F0(o.provider||"unknown",s,o.ts??Date.now()),SP(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(jn.weekly,jn.monthly);for(let o of await e?.()||[]){let s;try{s=await U(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||F0(a.provider||"unknown",Ft(a).usd,i,n)}}return Fp=!0,pi()}var H0,W0,q0,Rs,Qt,Fp,jn,go,Os,Lp,vP,Ll,Hl=L(()=>{he();Sr();H0=process.env.BOSTRAT_STATE_DIR||U0.join(process.env.HOME||xP.tmpdir(),".bostrat"),W0=()=>U0.join(H0,"usage-caps.json"),q0=.8;Rs={weekly:{startOf:K0,nextStart:V0,capKey:"weeklyUsd"},monthly:{startOf:G0,nextStart:z0,capKey:"monthlyUsd"}},Qt=null,Fp=!1,jn={weekly:0,monthly:0},go=new Map,Os=new Set,Lp=null,vP=e=>{let t=go.get(e);return t||(t={weekly:0,monthly:0},go.set(e,t)),t};Ll=e=>Math.round(e*1e4)/1e4});import TP from"node:fs/promises";import EP from"node:os";import Q0 from"node:path";function ax(e){return e==="codex"?$P:e==="cursor"?sx:rx}function ex(e){let t=String(e||"").split(`
175
+ `),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 tx(e){let t=String(e||"").split(`
176
+ `),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 RP(e){let t=String(e||"").split(`
177
+ `);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 nx(e){let t=String(e||"").split(`
178
+ `),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 ix(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&&!ox.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=sx.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!IP.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function mi(e,t,{timeoutMs:n=AP}={}){let r=Date.now()+n;for(;;){let o=await Ce(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await Wl(_P)}}async function OP(e,t){return await Ze(e,`/model ${t.model}`,pn("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function CP(e,t){await ll(e),await Ze(e,"/model",{enter:!1}),await Wl(250),await Le(e,["Enter"],{kind:"model-switch"});let n=await mi(e,ex);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await Le(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=RP(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await Ze(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await mi(e,i=>tx(i)||!ex(i)&&o(i)&&{done:o(i)});if(!s)throw await Le(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?ox.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 Le(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await Ze(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await mi(e,i=>!tx(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 MP(){let e=Q0.join(process.env.CURSOR_CONFIG_DIR||Q0.join(EP.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await TP.readFile(e,"utf8"))?.model||null}catch{return null}}async function NP(e,t){await ll(e),await dl(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await mi(e,nx),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 mi(e,nx,{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 Le(e,["Down"],{kind:"model-switch"}),await Wl(250)}if(!n||!s||!o(s)){await Le(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await Le(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 Le(e,["Enter"],{kind:"model-switch"}),await Wl(800);let a=await MP();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 cx(e,t,n){return e==="codex"?CP(t,n):e==="cursor"?NP(t,n):OP(t,n)}var Wl,AP,_P,rx,IP,$P,ox,sx,lx=L(()=>{lt();ei();Wl=e=>new Promise(t=>setTimeout(t,e)),AP=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,_P=300,rx=[{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"}],IP=new Set([...rx.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"]),$P=[{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"}],ox=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),sx=[{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 Kl(e){let t=e||{},n=PP(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function PP(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{text:e.text,boxRole:e.boxRole,...e.kind?{kind:e.kind}:{},...e.attachments?.length?{attachments:e.attachments}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:e.box,provider:gt(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:gt(e.agent),payload:{text:e.prompt,kind:e.kind,boxRole:e.boxRole}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:gt(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:gt(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:gt(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:gt(e.agent),payload:{...Ar(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:gt(e.agent||e.toAgent),payload:{kind:"subtask-failed",...Ar(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{change:"subtask-resumed",...Ar(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",...Ar(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...Ar(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...Ar(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(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:gt(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:gt(e.agent),payload:{...Ar(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...Ar(e)}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};default:return null}}function fx(e,t){let n=Kl(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;Hp(()=>$(r,n))}async function px(e){if(!(!e?.id||ux.has(e.id))){ux.add(e.id);try{let t=await U(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=Kl(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await $(e,o)}}catch{}}}function Ar(e){let{type:t,at:n,...r}=e;return r}function mx(e,t,n){!n?.promptId||Up.get(e.id)===n.promptId||(Up.set(e.id,n.promptId),Hp(()=>$(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:gt(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 Wp(e,t,n,r={}){Up.delete(e.id),Hp(()=>$(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:gt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var gt,ql,Hp,dx,ux,Up,qp=L(()=>{he();gt=e=>e||null;ql=Promise.resolve(),Hp=e=>(ql=ql.then(e).catch(()=>{}),ql),dx=()=>ql;ux=new Set;Up=new Map});function FP(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function kx(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of FP(n).reverse()){if(!DP.test(r))continue;let o=r.endsWith("?")&&r.length<=LP&&jP.test(r);if(BP.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function vx(e){let t=String(e||""),n=[];UP.test(t)&&n.push("commit"),xx.test(t)&&n.push("rebase"),HP.test(t)&&n.push("push");let r=qP.test(t);!r&&WP.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 Sx(e){return xx.test(String(e||""))}function Cs(e,{branch:t=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1}={}){Array.isArray(e)||(e=e==="push"?["commit","push"]:["commit","push","pr"]);let a=new Set(e),i=Array.isArray(o)&&o.length>0,c=i?o.map(p=>`${p.name}/`).join(", "):null,l=t?` on this branch (${t})`:"",u=[];if(a.has("commit")&&u.push(i?`commit the work in each changed checkout (${c})${l} with a clear commit message per repo`:`commit the work${l} with a clear commit message`),a.has("rebase")){let p=a.has("commit")?"the branch":`this branch${t?` (${t})`:""}`;u.push(i?`rebase ${p} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${p} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`)}if(a.has("push")||a.has("pr")){let p=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",h=a.has("rebase")?" with `--force-with-lease` (the rebase rewrote history)":"";i?u.push(a.has("commit")||a.has("rebase")?`push each one to its remote${h}${p}`:`push this branch${t?` (${t})`:""} from each changed checkout (${c}) to its remote${p}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${h}${p}`:`push this branch${l} to the remote${p}`)}a.has("pr")&&u.push(i?"open a pull request in each changed repo with a concise title and a description of what changed and why (run `gh pr create` inside each checkout)":`open a pull request${n?` against ${n}`:""} with a concise title and a description of what changed and why (use \`gh pr create\`)`);let f=[];a.has("commit")||f.push("don't create any new commits \u2014 ship what's already committed"),s&&!a.has("rebase")&&f.push("don't rebase \u2014 leave the branch's history as it is"),!a.has("push")&&!a.has("pr")&&f.push("don't push"),a.has("pr")||f.push("don't open a pull request");let d=`Yes \u2014 go ahead: ${u.join(", then ")}.`;return f.length&&(d+=` ${f.join(", and ").replace(/^./,p=>p.toUpperCase())}.`),a.has("pr")&&(d+=i?" If a repo's PR for this branch is already open, just push that repo's update instead.":" If a PR for this branch is already open, just push the update instead."),d}function Tx(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 Ex(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<=KP&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function Ax(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+GP||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function _x(e){let t=(Array.isArray(e)?e:[]).filter(r=>hx[r]).map(r=>hx[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 wx,gx,yx,bx,DP,BP,jP,LP,_r,UP,xx,HP,WP,qP,KP,GP,hx,bo=L(()=>{wx=/(?<!\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,gx=/(?<!\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,yx=/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,bx=/(?<!\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,DP=new RegExp(`\\b(?:${wx}|${gx}|${yx}|${bx})\\b`,"i"),BP=/\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,jP=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,LP=90;_r=["commit","rebase","push","pr"],UP=new RegExp(`\\b(?:${wx})\\b`,"i"),xx=new RegExp(`\\b(?:${bx})\\b`,"i"),HP=new RegExp(`\\b(?:${gx})\\b`,"i"),WP=new RegExp(`\\b(?:${yx})\\b`,"i"),qP=/\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;KP=3e4;GP=2500;hx={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import VP from"node:crypto";import Gl from"node:fs/promises";import Ix from"node:path";import zP from"node:os";async function He(){return Ir||(Kp??=Gl.readFile(Vp,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(Ir=e,!t&&Ne()){let{records:n,source:r}=await et("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;Ir[ae(i.repo,i.number)]=i}Object.keys(Ir).length&&await zp().catch(()=>{})}}return Ir}).finally(()=>Kp=null),Kp)}async function zp(){let e=JSON.stringify({links:Ir},null,2),t=`${Vp}.${process.pid}.tmp`;await Gl.mkdir($x,{recursive:!0}),await Gl.writeFile(t,e),await Gl.rename(t,Vp)}async function Qe(e){Gp=Gp.then(zp,zp),await Gp.catch(()=>{});let t=Ir?.[e];t&&wt("prlinks",{id:Rx(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function Ot({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 He(),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:YP.has(a),firstSeen:Date.now()},await Qe(ae(e,t)),{link:i[c],created:!0})}async function Ln(e,t){if(!e||t==null)return null;let n=(await He())[ae(e,t)];return!n||n.announced?null:(n.announced=!0,await Qe(ae(e,t)),n)}async function tt(e,t){return!e||t==null?null:(await He())[ae(e,t)]??null}async function $r(e,t,n){if(!e||t==null)return null;let r=(await He())[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 Ox(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await He())[ae(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Qe(ae(e,t)),o):null}async function Cx(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await He())[ae(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Qe(ae(e,t)),o):null}async function Vl(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await He())[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 zl(e,t){if(!e||t==null)return null;let n=(await He())[ae(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Qe(ae(e,t)),n)}async function Yl(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await He())[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 Jl(e,t){if(!e||t==null)return null;let n=(await He())[ae(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Qe(ae(e,t)),n)}async function Mx(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await He())[ae(e,t)];return r?(r.baseFoldAt=n,await Qe(ae(e,t)),r):null}async function Nx(e,t){if(!e||t==null)return null;let n=(await He())[ae(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Qe(ae(e,t)),n)}async function Px(e,t,n){if(!e||t==null||!n)return null;let r=(await He())[ae(e,t)];return r?(r.lastHeadSha=n,await Qe(ae(e,t)),r):null}async function Dx(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await He())[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 hi(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await He())[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 ko(e,t,n=!0){if(!e||t==null)return null;let r=(await He())[ae(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Qe(ae(e,t)),r):null}async function wi(e,t,n=!0){if(!e||t==null)return null;let r=(await He())[ae(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Qe(ae(e,t)),r):null}async function Bx(e,t,n){if(!e||t==null)return null;let r=(await He())[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 jx(e,t,n){if(!e||t==null)return null;let r=(await He())[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 gi(e,t){if(!e||t==null)return null;let n=(await He())[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 Lx(){return Object.values(await He()).filter(e=>!JP.has(e.state))}async function xo(){return Object.values(await He()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function Fx(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await He(),r=0;for(let[o,s]of Object.entries(n))await wt("prlinks",{id:Rx(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var $x,Vp,ae,Rx,Ir,Kp,Gp,YP,JP,Fn=L(()=>{dr();$x=process.env.BOSTRAT_STATE_DIR||Ix.join(process.env.HOME||zP.tmpdir(),".bostrat"),Vp=Ix.join($x,"pr-links.json"),ae=(e,t)=>`${e}#${Number(t)}`,Rx=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=VP.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},Ir=null,Kp=null,Gp=Promise.resolve();YP=new Set(["api","observed","reconciled"]);JP=new Set(["merged","closed","lost"])});import XP from"node:fs";import Yp from"node:fs/promises";import qx from"node:path";import ZP from"node:os";function Vx(e,t=!1){if(!t&&e-Hx<QP)return;Hx=e;let n=JSON.stringify({windowStart:Ms,byCaller:Object.fromEntries(Un),lastHour:Rr});Wx=Wx.then(()=>Yp.mkdir(Kx,{recursive:!0})).then(()=>Yp.writeFile(`${Xl}.tmp`,n)).then(()=>Yp.rename(`${Xl}.tmp`,Xl)).catch(()=>{})}function zx(e){e-Ms<Gx||(Rr={start:Ms,total:Zl(Un),byCaller:Object.fromEntries(Un)},Rr.total&&console.log(`[github] ${Rr.total} calls last hour`,Rr.byCaller),Ms=e,Un=new Map,Vx(e,!0))}function Hn(e="other",t=Date.now()){zx(t),Un.set(e,(Un.get(e)||0)+1),Vx(t)}function Yx(e=Date.now()){return zx(e),{windowStart:Ms,total:Zl(Un),byCaller:Object.fromEntries(Un),lastHour:Rr,backoffUntil:vo>e?vo:null}}function Or(e){return eD.test(String(e?.message||e||""))}function Cr(e,t=Date.now()){return vo<=t&&console.warn(`[github] rate limited \u2014 backing off ${Ux/6e4} min:`,String(e?.message||e||"").slice(0,200)),vo=Math.max(vo,t+Ux),vo}function Ql(e=Date.now()){return Math.max(0,vo-e)}var Kx,Xl,Gx,Ux,QP,Ms,Un,Rr,vo,Hx,Zl,Wx,eD,yi=L(()=>{Kx=process.env.BOSTRAT_STATE_DIR||qx.join(process.env.HOME||ZP.tmpdir(),".bostrat"),Xl=qx.join(Kx,"github-metrics.json"),Gx=60*6e4,Ux=5*6e4,QP=6e4,Ms=Date.now(),Un=new Map,Rr=null,vo=0,Hx=0,Zl=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(XP.readFileSync(Xl,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<Gx?(Ms=e.windowStart,Un=new Map(Object.entries(e.byCaller||{})),Rr=e.lastHour||null):Zl(new Map(Object.entries(e.byCaller||{})))&&(Rr={start:e.windowStart,total:Zl(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}Wx=Promise.resolve();eD=/rate limit|too quickly|abuse detection|HTTP 429/i});import Jx from"node:fs/promises";import Xx from"node:path";import tD from"node:os";function tu({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};eu.push(l),eu.length>rD&&eu.shift();let u=Jp.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)),Jp.set(e,u),oD(l),l}async function oD(e){try{await Jx.mkdir(Zx,{recursive:!0}),await Jx.appendFile(nD,JSON.stringify(e)+`
179
+ `)}catch{}}function Qx(){let e={};for(let[t,n]of Jp)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:eu.slice(-20)}}var Zx,nD,rD,eu,Jp,nu=L(()=>{Zx=process.env.BOSTRAT_STATE_DIR||Xx.join(process.env.HOME||tD.tmpdir(),".bostrat"),nD=Xx.join(Zx,"github-latency.ndjson"),rD=100,eu=[],Jp=new Map});import{execFile as sD}from"node:child_process";import{promisify as aD}from"node:util";async function iD(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([Ps("git",["-C",e,"rev-parse","HEAD"]),Ps("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await $({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function Ut(e,t,n={}){let{caller:r="prs",...o}=n,s=await ln({cwd:e});Hn(r);try{let{stdout:a}=await Ps("gh",t,{cwd:e,...cD,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw Or(a)&&Cr(a),a}}async function Qp(){if(ru&&Date.now()-ru.at<6e4)return ru.data;let e;try{Hn("auth");let t=await Ps("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 Ia();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return ru={at:Date.now(),data:e},e}async function lD(e){try{let{stdout:t}=await Ps("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function tv(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 Xp(e){let t=(e||[]).map(tv),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 tm(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function rv(e,t){if(!t)return null;let n=await Se(e);if(!n)return null;try{let r=await Ut(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 ov(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 sv(e,t){let n=await rv(e,t);return n===null?{...Xp([]),unavailable:!0}:Xp(ov(n))}function ou(e,t=Xp(e.statusCheckRollup)){return{number:e.number,title:e.title,url:e.url,author:e.author?.login??null,headRefName:e.headRefName,headSha:e.headRefOid??null,baseRefName:e.baseRefName,isDraft:!!e.isDraft,reviewDecision:e.reviewDecision||null,mergeable:e.mergeable||"UNKNOWN",mergeStateStatus:e.mergeStateStatus||"UNKNOWN",additions:e.additions??0,deletions:e.deletions??0,createdAt:e.createdAt,updatedAt:e.updatedAt,checks:t,green:t.failed===0&&t.pending===0&&e.mergeStateStatus==="CLEAN",autoMergeArmed:!!e.autoMergeRequest,mergeabilityPending:!1}}function dD(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){Ns.delete(s);continue}r.add(s),Ns.has(s)||Ns.set(s,n),o.mergeabilityPending=n-Ns.get(s)<uD}for(let o of Ns.keys())o.startsWith(`${e}#`)&&!r.has(o)&&Ns.delete(o);return t}async function Ds(e,t){let n=await Wn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await Ut(n.path,["pr","view",String(r),"--json",em]);return ou(JSON.parse(o))}catch(o){if(!tm(o))throw o;let s=await Ut(n.path,["pr","view",String(r),"--json",nv]),a=JSON.parse(s);return ou(a,await sv(n.path,a.headRefOid))}}async function hn(e,{caller:t="prs"}={}){try{let n=await Ut(e,["pr","list","--json",em,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>ou(r)).sort(ev)}catch(n){if(!tm(n))throw n;let r=await Ut(e,["pr","list","--json",nv,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>ou(o,await sv(e,o.headRefOid))))).sort(ev)}}function gn(){bi.clear()}async function mD(e,t){if(!e)return t;for(let n of t){let r=await tt(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 Vl(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await Yl(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function av(){let e=await Qp();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await On())await lD(a.path)&&t.push(a);let n=Date.now(),r=Ql(n)>0,o=await Promise.all(t.map(async a=>{let i=bi.get(a.path),c=i?.pending?pD:fD;if(i&&(r||n-i.at<c))return i.entry;try{let l=await Se(a.path).catch(()=>null),u=dD(a.path,await hn(a.path,{caller:"tab"}),n);if(await mD(l,u),i?.entry?.prs)for(let p of u)i.entry.prs.find(w=>w.number===p.number)?.checks?.pending>0&&p.checks.total>0&&p.checks.pending===0&&tu({change:p.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:p.number,githubAt:p.checks.settledAt,source:"tab"});let f={name:a.name,path:a.path,prs:u},d=u.some(p=>p.mergeabilityPending||p.checks.pending>0||p.autoMergeArmed);return bi.set(a.path,{at:Date.now(),entry:f,pending:d}),f}catch(l){return i?i.entry:{name:a.name,path:a.path,prs:[],error:wn(l)}}})),s=new Set(t.map(a=>a.path));for(let a of bi.keys())s.has(a)||bi.delete(a);return{auth:e,repos:o}}async function Wn(e){let t=(await On()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function So(e){return Zo(e)}async function Bs(e,t,{method:n="squash"}={}){let r=await Wn(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 ln({cwd:r.path})).GH_TOKEN){let a=await qd().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await Ut(r.path,s)}catch(a){throw new Error(wn(a))}finally{gn()}return{ok:!0,number:o}}async function xi(e,t){let n=await Wn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Ut(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(wn(s))}finally{gn()}let o=await Se(n.path).catch(()=>null);return o&&await Mx(o,r).catch(()=>{}),{ok:!0,number:r}}async function nm(e,t){let n=await Wn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Ut(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(wn(o))}finally{gn()}return{ok:!0,number:r}}function rm(e){return e.green&&!e.isDraft}function yD(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 iv(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:rm(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function cv(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function vi(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 lv(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(vi))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function uv(){let e={};for(let[t,n]of Zp)e[t]={...n};return e}async function dv(e,{method:t="merge",onMerged:n=null}={}){let r=await Wn(e);if(!ki.has(t))throw new Error(`invalid merge method: ${t}`);if(Zp.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await hn(r.path)).filter(rm).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 Zp.set(r.path,s),kD(s,o,{listPrs:()=>hn(r.path),merge:a=>Bs(r.path,a,{method:t}),sleep:gD,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function bD(e,t){let n=Date.now()+(t.settleMaxMs??wD),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(hD)}}async function kD(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 bD(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: ${wn(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(!rm(a)){e.skipped.push({number:a.number,title:a.title,reason:yD(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:wn(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),gn()}}async function om(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await Ps("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${wn(l)}`)}await iD(e);let o=n||"";if((await ln({cwd:e})).GH_TOKEN){let l=await qd().catch(()=>null);l&&(o=`${o?`${o}
180
+
181
+ `:""}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 Ut(e,s)}catch(l){throw new Error(wn(l))}finally{gn()}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 fv(e,t){let n=await Wn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await Ut(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(wn(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!tm(i))throw i;let c=await Ut(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await rv(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(wn(i));o=ov(l).map(tv).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=xD(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await Ut(n.path,["run","view",c,"--log-failed"]).then(u=>vD(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function xD(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function vD(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
182
182
  `);return o.length>t&&(r=`\u2026 (${o.length-t} earlier lines truncated)
183
183
  `+o.slice(-t).join(`
184
184
  `)),Buffer.byteLength(r)>n&&(r=`\u2026 (truncated)
185
185
  `+r.slice(-n)),r}function wn(e){return String(e?.stderr||e?.message||e||"").trim().split(`
186
- `).find(n=>n.trim())||"gh failed"}var Ns,oD,tu,Qp,Qx,aD,Ms,Xx,cD,lD,yi,bi,dD,fD,pD,Xp,Bs=j(()=>{ar();it();Fn();gi();eu();me();Ns=nD(tD),oD={timeout:3e4,maxBuffer:8*1024*1024};tu=null;Qp="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt",Qx=Qp.replace("statusCheckRollup,","");aD=9e4,Ms=new Map;Xx=(e,t)=>e.number-t.number;cD=3e4,lD=1500,yi=new Map;bi=new Set(["squash","merge","rebase"]);dD=2500,fD=9e4,pD=e=>new Promise(t=>setTimeout(t,e));Xp=new Map});import{execFile as bD}from"node:child_process";import{promisify as kD}from"node:util";async function vD(e,t){try{let{stdout:n}=await xD("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function SD(e,t,n,{rebase:r=!1,listPrs:o=hn}={}){let s=await ui(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await di(e.dir,n).catch(()=>0),i=t?await vD(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(w=>w.headRefName===t)||null,u=l?"open":"none"}catch{}let f=s||a>0,d=[];s&&d.push("commit"),r&&d.push("rebase"),(s||c)&&d.push("push"),f&&(u!=="open"||s||c)&&d.push("pr");let p=d.filter(h=>!(h==="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:ru.filter(h=>d.includes(h)),defaults:ru.filter(h=>p.includes(h))}}async function ou(e,{branch:t,rebase:n=!1,listPrs:r=hn}={}){let o=e?.workspace,s=o?.kind==="multi"?(o.repos||[]).filter(d=>d?.dir):o?.base&&(o.dir||e?.cwd)?[{name:o.base?.split("/").pop()??null,dir:o.dir||e.cwd,repo:o.repo??null,baseRef:o.baseRef}]:[];if(!s.length||!await Es(s[0].dir).catch(()=>!1))return null;let a=[];for(let d of s)a.push(await SD(d,t,d.baseRef||o.baseRef,{rebase:n,listPrs:r}));let i=a.filter(d=>d.dirty||d.aheadBase>0||d.openPr),c=i.length?i:a,l=ru.filter(d=>c.some(p=>p.available.includes(d))),u=ru.filter(d=>c.some(p=>p.defaults.includes(d))),f=c.filter(d=>d.openPr);return{available:l,defaults:u,prState:f.length?"open":c.every(d=>d.prState==="none")?"none":"unknown",openPr:c.length===1?c[0].openPr:null,repos:c.map(d=>({name:d.name,slug:d.slug,dirty:d.dirty,unpushed:d.unpushed,prState:d.prState,openPr:d.openPr}))}}var xD,ru,om=j(()=>{Pl();Bs();xD=kD(bD),ru=["commit","rebase","push","pr"]});function su(e,t,n){let{state:r,reason:o}=Nf(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of vi)a-c.at>=uv()&&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>=uv()?(vi.delete(e),!1):s.busy:!1}async function sm(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await Ce(e,{lines:Xe}).catch(()=>"");if(!su(e,t,r))return Pb(t,r)?{working:!0,prompted:!1}:n;if(wo(t,r)){let o=await Nn(e).catch(()=>r),s=Tr({name:e,agent:t},o);if(s)return!Ml({name:e,agent:t},s,o)||C0(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function To(e,t){return(await sm(e,t)).working}var uv,vi,Si=j(()=>{lt();Za();Ap();Ip();uv=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,vi=new Map});import{execFile as TD}from"node:child_process";import{promisify as ED}from"node:util";async function Cr(e){if(!e)return null;let t=dv.get(e);if(t&&Date.now()-t.at<_D)return t.branch;let n=null;try{let{stdout:r}=await AD("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return dv.set(e,{at:Date.now(),branch:n}),n}function fv(e){return String(e||"").match(ID)?.[1]??null}function $D(e,t){let n=fv(e);return!!n&&!!t&&n===t}function pv(e,t){let n=fv(e);return!!n&&n!==t}function RD(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 js(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of RD(e))n(await Cr(r));return t}async function au(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=>$D(t,a.id));if(s)return s;for(let a of r)if(!Ve(a)&&(await js(a)).includes(t))return a;return null}var AD,_D,dv,ID,Eo=j(()=>{Bn();AD=ED(TD),_D=5e3,dv=new Map;ID=/^track\/.+-([0-9a-f]{8})$/});import{execFile as OD}from"node:child_process";import{promisify as CD}from"node:util";async function am(e,t,{midTurn:n=To,pollMs:r=MD,capMs:o=ND}={}){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 bv(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){mv.lastIndex=n;let o=mv.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(`
187
- `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+UD(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 im(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function xv(e){let t=bv(e),n=t.match(jD);if(!n)return null;let r=im(t,n.index);return FD.test(r)?null:{repo:r.match(kv)?.[1]??null,head:r.match(HD)?.[1]??null}}function vv(e){let t=bv(e),n=t.match(LD);if(!n)return null;let r=im(t,n.index),o=im(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("-")){qD.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(kv)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function GD(e,t,{exclude:n=()=>!1}={}){let r=async i=>{Hn("observer");let{stdout:c}=await hv("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",KD],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw Rr(l)&&Or(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-PD&&!n(c)),s=await ln({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 VD(e,t){if(t)return[t];let n=[];for(let r of Sv(e)){let o=await Se(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await On().catch(()=>[])){let o=await Se(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function Sv(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 zD(e,t,n){let r=await js(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)||WD(c.headRefName,e.id),i=[];for(let c of await VD(e,t?.repo??null)){let l;try{l=await GD(c,n,{exclude:a})}catch{continue}for(let u of l){let f=await tt(c,u.number);if(s(u.headRefName)){if(f&&f.trackId===e.id&&f.announced)return{settled:!0};if(f&&f.trackId!==e.id)continue;return{slug:c,pr:u}}f&&(f.trackId!==e.id||f.announced)||i.push({slug:c,pr:u})}}return i.length?(i.sort((c,l)=>Date.parse(l.pr.createdAt)-Date.parse(c.pr.createdAt)),i[0]):null}function Tv(e,t,{delays:n=wv,turnEnd:r}={}){let o=xv(t.command);if(!o)return null;let s=!!vv(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(Mr.has(a))return null;Mr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(w=>setTimeout(w,l));let u=await zD(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:f,pr:d}=u,{link:p,created:h}=await Ot({repo:f,number:d.number,trackId:e.id,url:d.url,headRef:d.headRefName,title:d.title,source:"observed"});return!h&&!(p?.trackId===e.id&&await Ln(f,d.number))?null:(await am(t.box,t.agent,r),await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"opened",number:d.number,url:d.url,title:d.title,branch:d.headRefName,repo:f,...s?{selfMerge:!0}:{}}}),d)}return null}finally{Mr.delete(a)}})();return c.catch(()=>Mr.delete(a)),c}function Ev(e,t,{delays:n=wv,turnEnd:r,openedWait:o}={}){let s=vv(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(Mr.has(a))return null;Mr.add(a);let i=(async()=>{try{let c=s.repo,l=s.selector,u=l?.match(/github\.com\/([\w.-]+\/[\w.-]+)\/pull\/(\d+)/);u&&([,c,l]=u);let f=[];if(c)f=[c];else{let h=Sv(e);if(h.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let w of h){let g=await Se(w).catch(()=>null);g&&!f.includes(g)&&f.push(g)}}if(l||=(await js(e).catch(()=>[])).filter(h=>h!==e.workspace?.branch)[0]||e.workspace?.branch,!f.length||!l)return null;c=f[0];let d=async(h,w)=>{let g=await tt(c,h.number);return g&&g.trackId!==e.id?null:(g||await Ot({repo:c,number:h.number,trackId:e.id,url:h.url,headRef:h.headRefName,title:h.title,source:"merge-observed"}),await mi(c,h.number),w&&((await F(e).catch(()=>[])).some(E=>E.type==="pr.state.changed"&&(E.payload?.change==="auto-armed"||E.payload?.change==="merged")&&E.payload?.number===h.number)||(await am(t.box,t.agent,r),await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:h.number,url:h.url,title:h.title,branch:h.headRefName,repo:c}}))),h)},p=null;for(let h of n){await new Promise(T=>setTimeout(T,h));let w=[];for(let T of f)try{Hn("observer");let{stdout:_}=await hv("gh",["pr","view",String(l),"--repo",T,"--json",YD],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await ln({slug:T})}}),O=JSON.parse(_||"null");O?.number&&w.push({slug:T,pr:O})}catch(_){Rr(_)&&Or(_)}let g=w.find(T=>T.pr.state==="MERGED")??(w.length===1?w[0]:null);if(!g)continue;c=g.slug;let k=g.pr;if(!k?.number)continue;if(k.state==="CLOSED")return null;if(k.state!=="MERGED"){if(p=k,s.auto)return d(k,!0);continue}let S=await tt(c,k.number);if(S&&S.trackId!==e.id)return null;S||await Ot({repo:c,number:k.number,trackId:e.id,url:k.url,headRef:k.headRefName,title:k.title,source:"merge-observed"}),await am(t.box,t.agent,r);let E=await F(e).catch(()=>[]);if(E.some(T=>T.type==="pr.state.changed"&&T.payload?.change==="merged"&&T.payload?.number===k.number))return null;let R=T=>T.some(_=>_.type==="pr.state.changed"&&_.payload?.change==="opened"&&_.payload?.number===k.number),B=0;if(!R(E)){if(xv(t.command)&&await Ln(c,k.number)){let T=Date.now();B=T+1,await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:T,change:"opened",number:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c,selfMerge:!0}})}else if((await tt(c,k.number))?.announced){let T=o?.capMs??DD,_=o?.pollMs??BD,O=Date.now()+T;for(;Date.now()<O&&(await new Promise(I=>setTimeout(I,_)),!R(await F(e).catch(()=>[]))););}}return await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Math.max(Date.now(),B),change:"merged",number:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c}}),await Kn(c,k.number).catch(()=>{}),await qn(c,k.number).catch(()=>{}),await Ir(c,k.number,"merged"),k}return p?d(p,!1):null}finally{Mr.delete(a)}})();return i.catch(()=>Mr.delete(a)),i}var hv,wv,MD,ND,PD,DD,BD,gv,yv,jD,LD,FD,mv,UD,kv,HD,WD,qD,KD,Mr,YD,Av=j(()=>{me();ar();it();gi();Fn();Nr();Si();Eo();hv=CD(OD),wv=[4e3,15e3,45e3],MD=2500,ND=5*6e4;PD=15e3,DD=9e4,BD=2e3,gv=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,yv=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,jD=new RegExp(`${gv}${yv}create\\b`),LD=new RegExp(`${gv}${yv}merge\\b`),FD=/\s--web\b/,mv=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,UD=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");kv=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,HD=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,WD=pv;qD=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);KD="number,url,title,headRefName,createdAt";Mr=new Set;YD="number,url,title,headRefName,state"});import JD from"node:fs/promises";import lm from"node:path";import XD from"node:os";function cm(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function iu(e){let t=ZD.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=cm(n,"from"),s=o?o.replace(/^uds:/,""):null,a=_v(s);return{socket:s,pid:a,name:cm(n,"from-name"),mode:cm(n,"from-mode"),text:r.trim()}}function _v(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function QD(){return process.env.CLAUDE_CONFIG_DIR?lm.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):lm.join(XD.homedir(),".claude","sessions")}async function eB(e){let t=_v(e);if(!t)return null;try{let n=await JD.readFile(lm.join(QD(),`${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 Iv(e,t){let n=await eB(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 ZD,um=j(()=>{ZD=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function dm(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function fm({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!dm(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),$v);try{let a=await Rv(`${Ie(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 Ov(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(!dm(s))return{ok:!1,source:"unconfigured"};let i=cu.get(e.id)||0;if(a()-i<tB)return{ok:!1,source:"debounced"};cu.set(e.id,a());let c=await Ti({env:s}),l=c.loops.find(d=>d.trackId===e.id);if(!l)return cu.delete(e.id),{ok:!1,source:c.source==="plane"?"no-loop":c.source};let u=`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`.slice(0,500),f=await fm({loopId:l.id,outcome:"errored",note:u,env:s});return f.ok||cu.delete(e.id),{...f,loop:{id:l.id,name:l.name}}}async function Ti({env:e=process.env}={}){if(!dm(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),$v);try{let r=await Rv(`${Ie(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 $v,Rv,tB,cu,pm=j(()=>{it();$v=1e4,Rv=(...e)=>fetch(...e);tB=10*6e4,cu=new Map});function Cv(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Mv(e,t,n=mm){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await rB(`${Ie(t)}${e}`,{headers:oB(t),signal:r.signal})}finally{clearTimeout(o)}}async function Ei({env:e=process.env,force:t=!1,timeoutMs:n=mm}={}){if(!Cv(e))return{followups:[],source:"unconfigured"};if(!t&&Ao&&Date.now()-Ao.at<nB)return{followups:Ao.followups,source:"cache"};try{let r=await Mv("/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 Ao={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return Ao?{followups:Ao.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function Nv(e,{env:t=process.env,timeoutMs:n=mm}={}){if(!e)return{followup:null,source:"unconfigured"};if(!Cv(t))return{followup:null,source:"unconfigured"};try{let r=await Mv(`/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=Ao?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var nB,mm,Ao,rB,oB,Pv=j(()=>{it();nB=6e4,mm=5e3,Ao=null,rB=(...e)=>fetch(...e);oB=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import{randomUUID as Fs,createHash as sB}from"node:crypto";function Lv(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function uB(e){for(let[t,n]of lB)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 Fv(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=Ls(n.label).replace(/\s+/g," ");if(!r)throw new Error('label required (\u226460 chars, e.g. "Deploy to Pi")');if(r.length>Dv)throw new Error(`label must be \u2264${Dv} characters`);let o=Ls(n.trigger)||(n.ship?"now":""),s=t?iB:jv.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"?fB(n.ship):null,i=Ls(n.prompt);if(!a&&!i)throw new Error("prompt required \u2014 the full instruction a fresh session could execute");if(Buffer.byteLength(i,"utf8")>Bv)throw new Error(`prompt must be \u2264${Bv} bytes`);if(t){let u=uB(i);if(u)throw new Error(u)}let c=Ls(n.why).slice(0,aB)||null,l=t?dB(n.repo):null;return{label:r,prompt:i,trigger:o,why:c,...l?{repo:l}:{},...a?{ship:a}:{}}}function dB(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 fB(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):hm.slice();for(let i of n)if(!hm.includes(i))throw new Error(`ship.actions may only contain ${hm.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=Ls(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=>Ls(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function lu(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 Uv(e,t,{pull:n=Ei,ship:r={}}={}){if(ym(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=Fv(t);if(o.ship)return{kind:"ship",...await hB(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=Fs(),k=Fs();return await $(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 $(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:k,trigger:"now",repo:e.workspace?.repo||null,context:{},rows:[{armId:g,label:o.label,prompt:o.prompt,promptHash:wm(o.prompt),origin:"agent",why:o.why}]}}),{kind:"now",armId:g,offerId:k,...o}}let c=e.workspace?.repo||null,{followups:l}=await n().catch(()=>({followups:[]})),u=Lv(o.label),f=l.find(g=>g.status==="active"&&g.mode!=="off"&&g.trigger===o.trigger&&(g.repo==null||g.repo===c)&&g.dedupeKey===u);if(f)return{kind:"covered",covered:{id:f.id,label:f.label},...o};let d=await F(s),p=lu(d,{trigger:o.trigger}),h=p.length?p[p.length-1].armId:null,w=Fs();return await $(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:w,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,...h?{replaces:h}:{}}}),{kind:"armed",armId:w,replaces:h,...o}}async function Hv(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await F(n);if(!lu(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await $(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function Wv(e,t,{pull:n=Ei}={}){if(ym(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=Fv(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await F(s)).reduce((g,k)=>k.type==="followup.create.offered"?k.payload?.proposalId??g:k.type==="followup.create.answered"&&k.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=Lv(r.label),f=c.filter(g=>g.dedupeKey===u&&g.trigger===r.trigger),d=f.find(g=>g.status==="deleted"),p=f.find(g=>g.status!=="deleted");if(p)throw new Error(`"${p.label}" (${gm[p.trigger]||p.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(d){let g=d.deletedAt?new Date(d.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${d.label}" on ${g} \u2014 do not re-propose it`)}let h=Fs(),w=(e.boxes||[]).find(g=>g.name===e.leadBox)||null;return await $(s,{type:"followup.create.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:w?.agent??null,payload:{ts:Date.now(),proposalId:h,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why,origin:"agent"}}),{proposalId:h,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why}}async function qv(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await F(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 $(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 $(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 $(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 Ai(e,t,n={},{pull:r=Ei}={}){if(!e||ym(e))return null;let o={id:e.id,cwd:e.cwd},s=await F(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null,i=lu(s,{trigger:t}).map(d=>({armId:d.armId,label:d.label,prompt:d.prompt,promptHash:wm(d.prompt),origin:"agent",why:d.why??null})),c=[];if(t!=="now"){let{followups:d}=await r().catch(()=>({followups:[]}));c=d.filter(p=>p.status==="active"&&p.mode!=="off"&&p.trigger===t&&(p.repo==null||p.repo===a)).sort((p,h)=>{let w=g=>g.stats?.offered?(g.stats.accepted||0)/g.stats.offered:0;return w(h)-w(p)||(p.origin==="operator"?-1:0)-(h.origin==="operator"?-1:0)||(h.createdAt||0)-(p.createdAt||0)}).map(p=>({followupId:p.id,label:p.label,promptPreview:pB(p.prompt),promptHash:wm(p.prompt),origin:p.origin,repo:p.repo??null}))}let l=[...i,...c].slice(0,cB);if(!l.length)return null;let u=Fs(),f={ts:Date.now(),offerId:u,trigger:t,repo:a,context:{...n,repo:a},rows:l};return await $(o,{type:"followup.offered",actor:"system",source:"orchestrator",payload:f}),f}function mB(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 Kv(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null}={},s={}){let{sayToLead:a,unarchiveTrack:i,getFollowup:c=Nv}=s;if(!t)throw new Error("offerId required");let l={id:e.id,cwd:e.cwd},u=await F(l),f=u.find(E=>E.type==="followup.offered"&&E.payload?.offerId===t);if(!f)throw new Error("unknown offer");if(u.some(E=>E.type==="followup.answered"&&E.payload?.offerId===t))throw new Error("offer already answered");let d=f.payload.rows||[],p=E=>$(l,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...E}});if(!n&&!r)return await p({action:"dismiss",followupIds:d.map(E=>E.followupId).filter(Boolean),armIds:d.map(E=>E.armId).filter(Boolean)}),{offerId:t,action:"dismiss"};let h=null,w=null;if(n){if(!d.some(B=>B.followupId===n))throw new Error("that follow-up is not on this card");let{followup:E,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(!E||E.status!=="active"){await p({action:"removed",followupId:n});let B=new Error("removed in Settings since it was offered");throw B.code="removed",B}h=E.prompt,w=E.label}else{let E=d.find(B=>B.armId===r);if(!E)throw new Error("that arm is not on this card");if(h=u.find(B=>B.type==="followup.armed"&&B.payload?.armId===r)?.payload?.prompt??E.prompt,w=E.label,!h)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 k=`${mB(f.payload)}
186
+ `).find(n=>n.trim())||"gh failed"}var Ps,cD,ru,em,nv,uD,Ns,ev,fD,pD,bi,ki,hD,wD,gD,Zp,js=L(()=>{ir();it();Fn();yi();nu();he();Ps=aD(sD),cD={timeout:3e4,maxBuffer:8*1024*1024};ru=null;em="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt",nv=em.replace("statusCheckRollup,","");uD=9e4,Ns=new Map;ev=(e,t)=>e.number-t.number;fD=3e4,pD=1500,bi=new Map;ki=new Set(["squash","merge","rebase"]);hD=2500,wD=9e4,gD=e=>new Promise(t=>setTimeout(t,e));Zp=new Map});import{execFile as SD}from"node:child_process";import{promisify as TD}from"node:util";async function AD(e,t){try{let{stdout:n}=await ED("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function _D(e,t,n,{rebase:r=!1,listPrs:o=hn}={}){let s=await di(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await fi(e.dir,n).catch(()=>0),i=t?await AD(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(w=>w.headRefName===t)||null,u=l?"open":"none"}catch{}let f=s||a>0,d=[];s&&d.push("commit"),r&&d.push("rebase"),(s||c)&&d.push("push"),f&&(u!=="open"||s||c)&&d.push("pr");let p=d.filter(h=>!(h==="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:su.filter(h=>d.includes(h)),defaults:su.filter(h=>p.includes(h))}}async function au(e,{branch:t,rebase:n=!1,listPrs:r=hn}={}){let o=e?.workspace,s=o?.kind==="multi"?(o.repos||[]).filter(d=>d?.dir):o?.base&&(o.dir||e?.cwd)?[{name:o.base?.split("/").pop()??null,dir:o.dir||e.cwd,repo:o.repo??null,baseRef:o.baseRef}]:[];if(!s.length||!await As(s[0].dir).catch(()=>!1))return null;let a=[];for(let d of s)a.push(await _D(d,t,d.baseRef||o.baseRef,{rebase:n,listPrs:r}));let i=a.filter(d=>d.dirty||d.aheadBase>0||d.openPr),c=i.length?i:a,l=su.filter(d=>c.some(p=>p.available.includes(d))),u=su.filter(d=>c.some(p=>p.defaults.includes(d))),f=c.filter(d=>d.openPr);return{available:l,defaults:u,prState:f.length?"open":c.every(d=>d.prState==="none")?"none":"unknown",openPr:c.length===1?c[0].openPr:null,repos:c.map(d=>({name:d.name,slug:d.slug,dirty:d.dirty,unpushed:d.unpushed,prState:d.prState,openPr:d.openPr}))}}var ED,su,sm=L(()=>{Bl();js();ED=TD(SD),su=["commit","rebase","push","pr"]});function iu(e,t,n){let{state:r,reason:o}=Df(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of Si)a-c.at>=pv()&&Si.delete(i);Si.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=Si.get(e);return s?Date.now()-s.at>=pv()?(Si.delete(e),!1):s.busy:!1}async function am(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await Ce(e,{lines:Xe}).catch(()=>"");if(!iu(e,t,r))return Db(t,r)?{working:!0,prompted:!1}:n;if(wo(t,r)){let o=await Nn(e).catch(()=>r),s=Er({name:e,agent:t},o);if(s)return!Pl({name:e,agent:t},s,o)||P0(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function To(e,t){return(await am(e,t)).working}var pv,Si,Ti=L(()=>{lt();Qa();_p();$p();pv=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,Si=new Map});import{execFile as ID}from"node:child_process";import{promisify as $D}from"node:util";async function Mr(e){if(!e)return null;let t=mv.get(e);if(t&&Date.now()-t.at<OD)return t.branch;let n=null;try{let{stdout:r}=await RD("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return mv.set(e,{at:Date.now(),branch:n}),n}function hv(e){return String(e||"").match(CD)?.[1]??null}function MD(e,t){let n=hv(e);return!!n&&!!t&&n===t}function wv(e,t){let n=hv(e);return!!n&&n!==t}function ND(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 Ls(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of ND(e))n(await Mr(r));return t}async function cu(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=>MD(t,a.id));if(s)return s;for(let a of r)if(!Ve(a)&&(await Ls(a)).includes(t))return a;return null}var RD,OD,mv,CD,Eo=L(()=>{Bn();RD=$D(ID),OD=5e3,mv=new Map;CD=/^track\/.+-([0-9a-f]{8})$/});import{execFile as PD}from"node:child_process";import{promisify as DD}from"node:util";async function im(e,t,{midTurn:n=To,pollMs:r=BD,capMs:o=jD}={}){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 vv(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){gv.lastIndex=n;let o=gv.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(`
187
+ `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+KD(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 cm(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function Tv(e){let t=vv(e),n=t.match(HD);if(!n)return null;let r=cm(t,n.index);return qD.test(r)?null:{repo:r.match(Sv)?.[1]??null,head:r.match(GD)?.[1]??null}}function Ev(e){let t=vv(e),n=t.match(WD);if(!n)return null;let r=cm(t,n.index),o=cm(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("-")){zD.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(Sv)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function JD(e,t,{exclude:n=()=>!1}={}){let r=async i=>{Hn("observer");let{stdout:c}=await yv("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",YD],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw Or(l)&&Cr(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-LD&&!n(c)),s=await ln({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 XD(e,t){if(t)return[t];let n=[];for(let r of Av(e)){let o=await Se(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await On().catch(()=>[])){let o=await Se(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function Av(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 ZD(e,t,n){let r=await Ls(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)||VD(c.headRefName,e.id),i=[];for(let c of await XD(e,t?.repo??null)){let l;try{l=await JD(c,n,{exclude:a})}catch{continue}for(let u of l){let f=await tt(c,u.number);if(s(u.headRefName)){if(f&&f.trackId===e.id&&f.announced)return{settled:!0};if(f&&f.trackId!==e.id)continue;return{slug:c,pr:u}}f&&(f.trackId!==e.id||f.announced)||i.push({slug:c,pr:u})}}return i.length?(i.sort((c,l)=>Date.parse(l.pr.createdAt)-Date.parse(c.pr.createdAt)),i[0]):null}function _v(e,t,{delays:n=bv,turnEnd:r}={}){let o=Tv(t.command);if(!o)return null;let s=!!Ev(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(Nr.has(a))return null;Nr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(w=>setTimeout(w,l));let u=await ZD(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:f,pr:d}=u,{link:p,created:h}=await Ot({repo:f,number:d.number,trackId:e.id,url:d.url,headRef:d.headRefName,title:d.title,source:"observed"});return!h&&!(p?.trackId===e.id&&await Ln(f,d.number))?null:(await im(t.box,t.agent,r),await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"opened",number:d.number,url:d.url,title:d.title,branch:d.headRefName,repo:f,...s?{selfMerge:!0}:{}}}),d)}return null}finally{Nr.delete(a)}})();return c.catch(()=>Nr.delete(a)),c}function Iv(e,t,{delays:n=bv,turnEnd:r,openedWait:o}={}){let s=Ev(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(Nr.has(a))return null;Nr.add(a);let i=(async()=>{try{let c=s.repo,l=s.selector,u=l?.match(/github\.com\/([\w.-]+\/[\w.-]+)\/pull\/(\d+)/);u&&([,c,l]=u);let f=[];if(c)f=[c];else{let h=Av(e);if(h.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let w of h){let g=await Se(w).catch(()=>null);g&&!f.includes(g)&&f.push(g)}}if(l||=(await Ls(e).catch(()=>[])).filter(h=>h!==e.workspace?.branch)[0]||e.workspace?.branch,!f.length||!l)return null;c=f[0];let d=async(h,w)=>{let g=await tt(c,h.number);return g&&g.trackId!==e.id?null:(g||await Ot({repo:c,number:h.number,trackId:e.id,url:h.url,headRef:h.headRefName,title:h.title,source:"merge-observed"}),await hi(c,h.number),w&&((await U(e).catch(()=>[])).some(S=>S.type==="pr.state.changed"&&(S.payload?.change==="auto-armed"||S.payload?.change==="merged")&&S.payload?.number===h.number)||(await im(t.box,t.agent,r),await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:h.number,url:h.url,title:h.title,branch:h.headRefName,repo:c}}))),h)},p=null;for(let h of n){await new Promise(T=>setTimeout(T,h));let w=[];for(let T of f)try{Hn("observer");let{stdout:A}=await yv("gh",["pr","view",String(l),"--repo",T,"--json",QD],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await ln({slug:T})}}),C=JSON.parse(A||"null");C?.number&&w.push({slug:T,pr:C})}catch(A){Or(A)&&Cr(A)}let g=w.find(T=>T.pr.state==="MERGED")??(w.length===1?w[0]:null);if(!g)continue;c=g.slug;let b=g.pr;if(!b?.number)continue;if(b.state==="CLOSED")return null;if(b.state!=="MERGED"){if(p=b,s.auto)return d(b,!0);continue}let E=await tt(c,b.number);if(E&&E.trackId!==e.id)return null;E||await Ot({repo:c,number:b.number,trackId:e.id,url:b.url,headRef:b.headRefName,title:b.title,source:"merge-observed"}),await im(t.box,t.agent,r);let S=await U(e).catch(()=>[]);if(S.some(T=>T.type==="pr.state.changed"&&T.payload?.change==="merged"&&T.payload?.number===b.number))return null;let R=T=>T.some(A=>A.type==="pr.state.changed"&&A.payload?.change==="opened"&&A.payload?.number===b.number),M=0;if(!R(S)){if(Tv(t.command)&&await Ln(c,b.number)){let T=Date.now();M=T+1,await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:T,change:"opened",number:b.number,url:b.url,title:b.title,branch:b.headRefName,repo:c,selfMerge:!0}})}else if((await tt(c,b.number))?.announced){let T=o?.capMs??FD,A=o?.pollMs??UD,C=Date.now()+T;for(;Date.now()<C&&(await new Promise(I=>setTimeout(I,A)),!R(await U(e).catch(()=>[]))););}}return await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Math.max(Date.now(),M),change:"merged",number:b.number,url:b.url,title:b.title,branch:b.headRefName,repo:c}}),await Kn(c,b.number).catch(()=>{}),await qn(c,b.number).catch(()=>{}),await $r(c,b.number,"merged"),b}return p?d(p,!1):null}finally{Nr.delete(a)}})();return i.catch(()=>Nr.delete(a)),i}var yv,bv,BD,jD,LD,FD,UD,kv,xv,HD,WD,qD,gv,KD,Sv,GD,VD,zD,YD,Nr,QD,$v=L(()=>{he();ir();it();yi();Fn();Pr();Ti();Eo();yv=DD(PD),bv=[4e3,15e3,45e3],BD=2500,jD=5*6e4;LD=15e3,FD=9e4,UD=2e3,kv=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,xv=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,HD=new RegExp(`${kv}${xv}create\\b`),WD=new RegExp(`${kv}${xv}merge\\b`),qD=/\s--web\b/,gv=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,KD=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");Sv=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,GD=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,VD=wv;zD=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);YD="number,url,title,headRefName,createdAt";Nr=new Set;QD="number,url,title,headRefName,state"});import e1 from"node:fs/promises";import um from"node:path";import t1 from"node:os";function lm(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function lu(e){let t=n1.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=lm(n,"from"),s=o?o.replace(/^uds:/,""):null,a=Rv(s);return{socket:s,pid:a,name:lm(n,"from-name"),mode:lm(n,"from-mode"),text:r.trim()}}function Rv(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function r1(){return process.env.CLAUDE_CONFIG_DIR?um.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):um.join(t1.homedir(),".claude","sessions")}async function o1(e){let t=Rv(e);if(!t)return null;try{let n=await e1.readFile(um.join(r1(),`${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 Ov(e,t){let n=await o1(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 n1,dm=L(()=>{n1=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function fm(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function pm({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!fm(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),Cv);try{let a=await Mv(`${Ie(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 Nv(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(!fm(s))return{ok:!1,source:"unconfigured"};let i=uu.get(e.id)||0;if(a()-i<s1)return{ok:!1,source:"debounced"};uu.set(e.id,a());let c=await Ei({env:s}),l=c.loops.find(d=>d.trackId===e.id);if(!l)return uu.delete(e.id),{ok:!1,source:c.source==="plane"?"no-loop":c.source};let u=`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`.slice(0,500),f=await pm({loopId:l.id,outcome:"errored",note:u,env:s});return f.ok||uu.delete(e.id),{...f,loop:{id:l.id,name:l.name}}}async function Ei({env:e=process.env}={}){if(!fm(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),Cv);try{let r=await Mv(`${Ie(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 Cv,Mv,s1,uu,mm=L(()=>{it();Cv=1e4,Mv=(...e)=>fetch(...e);s1=10*6e4,uu=new Map});function Pv(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Dv(e,t,n=hm){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await i1(`${Ie(t)}${e}`,{headers:c1(t),signal:r.signal})}finally{clearTimeout(o)}}async function Ai({env:e=process.env,force:t=!1,timeoutMs:n=hm}={}){if(!Pv(e))return{followups:[],source:"unconfigured"};if(!t&&Ao&&Date.now()-Ao.at<a1)return{followups:Ao.followups,source:"cache"};try{let r=await Dv("/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 Ao={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return Ao?{followups:Ao.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function Bv(e,{env:t=process.env,timeoutMs:n=hm}={}){if(!e)return{followup:null,source:"unconfigured"};if(!Pv(t))return{followup:null,source:"unconfigured"};try{let r=await Dv(`/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=Ao?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var a1,hm,Ao,i1,c1,jv=L(()=>{it();a1=6e4,hm=5e3,Ao=null,i1=(...e)=>fetch(...e);c1=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import{randomUUID as Us,createHash as l1}from"node:crypto";function Hv(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function m1(e){for(let[t,n]of p1)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 Wv(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=Fs(n.label).replace(/\s+/g," ");if(!r)throw new Error('label required (\u226460 chars, e.g. "Deploy to Pi")');if(r.length>Lv)throw new Error(`label must be \u2264${Lv} characters`);let o=Fs(n.trigger)||(n.ship?"now":""),s=t?d1:Uv.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"?w1(n.ship):null,i=Fs(n.prompt);if(!a&&!i)throw new Error("prompt required \u2014 the full instruction a fresh session could execute");if(Buffer.byteLength(i,"utf8")>Fv)throw new Error(`prompt must be \u2264${Fv} bytes`);if(t){let u=m1(i);if(u)throw new Error(u)}let c=Fs(n.why).slice(0,u1)||null,l=t?h1(n.repo):null;return{label:r,prompt:i,trigger:o,why:c,...l?{repo:l}:{},...a?{ship:a}:{}}}function h1(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 w1(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):wm.slice();for(let i of n)if(!wm.includes(i))throw new Error(`ship.actions may only contain ${wm.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=Fs(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=>Fs(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function du(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 qv(e,t,{pull:n=Ai,ship:r={}}={}){if(bm(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=Wv(t);if(o.ship)return{kind:"ship",...await b1(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=Us(),b=Us();return await $(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 $(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:b,trigger:"now",repo:e.workspace?.repo||null,context:{},rows:[{armId:g,label:o.label,prompt:o.prompt,promptHash:gm(o.prompt),origin:"agent",why:o.why}]}}),{kind:"now",armId:g,offerId:b,...o}}let c=e.workspace?.repo||null,{followups:l}=await n().catch(()=>({followups:[]})),u=Hv(o.label),f=l.find(g=>g.status==="active"&&g.mode!=="off"&&g.trigger===o.trigger&&(g.repo==null||g.repo===c)&&g.dedupeKey===u);if(f)return{kind:"covered",covered:{id:f.id,label:f.label},...o};let d=await U(s),p=du(d,{trigger:o.trigger}),h=p.length?p[p.length-1].armId:null,w=Us();return await $(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:w,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,...h?{replaces:h}:{}}}),{kind:"armed",armId:w,replaces:h,...o}}async function Kv(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await U(n);if(!du(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await $(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function Gv(e,t,{pull:n=Ai}={}){if(bm(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=Wv(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await U(s)).reduce((g,b)=>b.type==="followup.create.offered"?b.payload?.proposalId??g:b.type==="followup.create.answered"&&b.payload?.proposalId===g?null:g,null))throw new Error("a follow-up proposal is already waiting on the operator in this Track \u2014 one at a time");let{followups:c,source:l}=await n().catch(()=>({followups:[],source:"unreachable"}));if(l==="unreachable")throw new Error("plane unreachable \u2014 standing follow-ups live in the plane; try again shortly");let u=Hv(r.label),f=c.filter(g=>g.dedupeKey===u&&g.trigger===r.trigger),d=f.find(g=>g.status==="deleted"),p=f.find(g=>g.status!=="deleted");if(p)throw new Error(`"${p.label}" (${ym[p.trigger]||p.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(d){let g=d.deletedAt?new Date(d.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${d.label}" on ${g} \u2014 do not re-propose it`)}let h=Us(),w=(e.boxes||[]).find(g=>g.name===e.leadBox)||null;return await $(s,{type:"followup.create.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:w?.agent??null,payload:{ts:Date.now(),proposalId:h,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why,origin:"agent"}}),{proposalId:h,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why}}async function Vv(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await U(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 $(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 $(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 $(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 _i(e,t,n={},{pull:r=Ai}={}){if(!e||bm(e))return null;let o={id:e.id,cwd:e.cwd},s=await U(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null,i=du(s,{trigger:t}).map(d=>({armId:d.armId,label:d.label,prompt:d.prompt,promptHash:gm(d.prompt),origin:"agent",why:d.why??null})),c=[];if(t!=="now"){let{followups:d}=await r().catch(()=>({followups:[]}));c=d.filter(p=>p.status==="active"&&p.mode!=="off"&&p.trigger===t&&(p.repo==null||p.repo===a)).sort((p,h)=>{let w=g=>g.stats?.offered?(g.stats.accepted||0)/g.stats.offered:0;return w(h)-w(p)||(p.origin==="operator"?-1:0)-(h.origin==="operator"?-1:0)||(h.createdAt||0)-(p.createdAt||0)}).map(p=>({followupId:p.id,label:p.label,promptPreview:g1(p.prompt),promptHash:gm(p.prompt),origin:p.origin,repo:p.repo??null}))}let l=[...i,...c].slice(0,f1);if(!l.length)return null;let u=Us(),f={ts:Date.now(),offerId:u,trigger:t,repo:a,context:{...n,repo:a},rows:l};return await $(o,{type:"followup.offered",actor:"system",source:"orchestrator",payload:f}),f}function y1(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 zv(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null}={},s={}){let{sayToLead:a,unarchiveTrack:i,getFollowup:c=Bv}=s;if(!t)throw new Error("offerId required");let l={id:e.id,cwd:e.cwd},u=await U(l),f=u.find(S=>S.type==="followup.offered"&&S.payload?.offerId===t);if(!f)throw new Error("unknown offer");if(u.some(S=>S.type==="followup.answered"&&S.payload?.offerId===t))throw new Error("offer already answered");let d=f.payload.rows||[],p=S=>$(l,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...S}});if(!n&&!r)return await p({action:"dismiss",followupIds:d.map(S=>S.followupId).filter(Boolean),armIds:d.map(S=>S.armId).filter(Boolean)}),{offerId:t,action:"dismiss"};let h=null,w=null;if(n){if(!d.some(M=>M.followupId===n))throw new Error("that follow-up is not on this card");let{followup:S,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(!S||S.status!=="active"){await p({action:"removed",followupId:n});let M=new Error("removed in Settings since it was offered");throw M.code="removed",M}h=S.prompt,w=S.label}else{let S=d.find(M=>M.armId===r);if(!S)throw new Error("that arm is not on this card");if(h=u.find(M=>M.type==="followup.armed"&&M.payload?.armId===r)?.payload?.prompt??S.prompt,w=S.label,!h)throw new Error("the arm's prompt is missing from the log")}let g=!1;if(e.archivedAt){if(!i)throw new Error("this Track is archived");await i(e.id,{freshSession:!0}),g=!0}if(!a)throw new Error("sayToLead unavailable");let b=`${y1(f.payload)}
188
188
 
189
- ${h}`,S=await a(e.id,k,{kind:"followup-go"});return await p({action:"sent",...n?{followupId:n}:{armId:r},label:w,...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:!!S?.queued}}async function hB(e,t,{changedRepos:n=null,probe:r=ou,branchOf:o=Cr}={}){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(()=>[]),k=s.repos?g.filter(S=>s.repos.includes(S.name)):g;l=k.length?k.map(S=>({name:S.name,slug:S.repo??null})):void 0}let u=(c?null:await o(e.cwd).catch(()=>null))||e.workspace.branch,f=s.rebase==="offered",d=await r(e,{branch:u,rebase:f}).catch(()=>null),p=[...f?["rebase"]:[],...s.actions].filter(g=>Ar.includes(g));if(d&&d.available.length===0)return{skipped:!0,reason:"nothing to ship \u2014 the tree is clean, pushed, and its PR is open",shipState:d};let h=Fs(),w=t.why?`${t.label} \u2014 ${t.why}`:t.label;return await $(a,{type:"pr.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:i?.agent??null,payload:{offerId:h,ts:Date.now(),excerpt:w,via:"cli",branch:u,base:s.base||e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:"lead",available:d?.available,defaults:d?d.defaults.filter(g=>p.includes(g)||g==="rebase"):void 0,prState:d?.prState,openPr:d?.openPr||void 0,repos:d?.repos||l,offered:d?p.filter(g=>d.available.includes(g)):p,toPr:s.toPr?{number:s.toPr}:void 0}}),{offerId:h,branch:u,offered:p,available:d?.available??null,prState:d?.prState??null}}function Gv(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 Vv(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 zv(e,{pull:t=Ei}={}){let{followups:n,source:r,error:o}=await t().catch(a=>({followups:[],source:"unreachable",error:a?.message})),s=e?await F({id:e.id,cwd:e.cwd}).catch(()=>[]):[];return{followups:n,source:r,error:o,arms:e?lu(s):[]}}var Dv,Bv,aB,jv,iB,gm,cB,hm,wm,Ls,lB,ym,pB,uu=j(()=>{me();bo();om();Eo();Pv();Dv=60,Bv=8*1024,aB=200,jv=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],iB=jv.filter(e=>e!=="now"&&e!=="track.opened"),gm={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"},cB=3,hm=["commit","push","pr"];wm=e=>sB("sha256").update(String(e)).digest("hex").slice(0,16),Ls=e=>typeof e=="string"?e.trim():"",lB=[[/(^|[^\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"]];ym=e=>String(e?.name||"").startsWith("\u21BB");pB=e=>String(e||"").split(`
189
+ ${h}`,E=await a(e.id,b,{kind:"followup-go"});return await p({action:"sent",...n?{followupId:n}:{armId:r},label:w,...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:!!E?.queued}}async function b1(e,t,{changedRepos:n=null,probe:r=au,branchOf:o=Mr}={}){let s=t.ship;if(!e.workspace?.branch)throw new Error("this Track has no branch to ship \u2014 a ship offer needs a worktree Track");let a={id:e.id,cwd:e.cwd},i=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,c=e.workspace?.kind==="multi",l;if(c&&n){let g=await n(e).catch(()=>[]),b=s.repos?g.filter(E=>s.repos.includes(E.name)):g;l=b.length?b.map(E=>({name:E.name,slug:E.repo??null})):void 0}let u=(c?null:await o(e.cwd).catch(()=>null))||e.workspace.branch,f=s.rebase==="offered",d=await r(e,{branch:u,rebase:f}).catch(()=>null),p=[...f?["rebase"]:[],...s.actions].filter(g=>_r.includes(g));if(d&&d.available.length===0)return{skipped:!0,reason:"nothing to ship \u2014 the tree is clean, pushed, and its PR is open",shipState:d};let h=Us(),w=t.why?`${t.label} \u2014 ${t.why}`:t.label;return await $(a,{type:"pr.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:i?.agent??null,payload:{offerId:h,ts:Date.now(),excerpt:w,via:"cli",branch:u,base:s.base||e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:"lead",available:d?.available,defaults:d?d.defaults.filter(g=>p.includes(g)||g==="rebase"):void 0,prState:d?.prState,openPr:d?.openPr||void 0,repos:d?.repos||l,offered:d?p.filter(g=>d.available.includes(g)):p,toPr:s.toPr?{number:s.toPr}:void 0}}),{offerId:h,branch:u,offered:p,available:d?.available??null,prState:d?.prState??null}}function Yv(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 Jv(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 Xv(e,{pull:t=Ai}={}){let{followups:n,source:r,error:o}=await t().catch(a=>({followups:[],source:"unreachable",error:a?.message})),s=e?await U({id:e.id,cwd:e.cwd}).catch(()=>[]):[];return{followups:n,source:r,error:o,arms:e?du(s):[]}}var Lv,Fv,u1,Uv,d1,ym,f1,wm,gm,Fs,p1,bm,g1,fu=L(()=>{he();bo();sm();Eo();jv();Lv=60,Fv=8*1024,u1=200,Uv=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],d1=Uv.filter(e=>e!=="now"&&e!=="track.opened"),ym={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"},f1=3,wm=["commit","push","pr"];gm=e=>l1("sha256").update(String(e)).digest("hex").slice(0,16),Fs=e=>typeof e=="string"?e.trim():"",p1=[[/(^|[^\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"]];bm=e=>String(e?.name||"").startsWith("\u21BB");g1=e=>String(e||"").split(`
190
190
  `).slice(0,3).join(`
191
- `).slice(0,400)});import{randomUUID as wB}from"node:crypto";function _i(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function Yv(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function Jv(e){return`job|${e.box}|id:${e.id}`}async function km(e){return bm.has(e.id)?bm.get(e.id):(du.has(e.id)||du.set(e.id,F(e).then(t=>{let n={keys:new Set,cmdN:0};for(let r of t)if((r.type==="turn.user"||r.type==="turn.agent"||r.type==="provider.error")&&r.payload?.text!=null){let o=r.type==="turn.user"?"user":"assistant";r.payload.sourceId&&n.keys.add(_i({role:o,sourceId:r.payload.sourceId})),n.keys.add(_i({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(_i({role:"user",sourceId:r.payload.sourceId})),n.keys.add(_i({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(Yv({id:o.id,box:r.boxId,ts:o.ts,command:o.command})),Number(o.n)>n.cmdN&&(n.cmdN=Number(o.n))}else r.type==="job.started"&&r.payload?.id&&n.keys.add(Jv({id:r.payload.id,box:r.boxId}));return bm.set(e.id,n),n}).finally(()=>du.delete(e.id))),du.get(e.id))}async function Xv(e,t){let n=new Set;try{let r=(await km(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=_i(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?iu(o.text):null;if(a){await $(e,{type:"peer.message",actor:"peer",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:a.text,ts:o.ts,keyText:String(o.text||"").slice(0,40),from:await Iv(a,Ii),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=wb(o);if(i){await $(e,{type:"provider.error",actor:"system",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{cls:i.cls,code:i.code||void 0,status:i.status||void 0,requestId:i.requestId||void 0,text:o.text,ts:o.ts,model:o.model||null,boxRole:o.boxRole,sourceId:o.sourceId||void 0}}),Ov(e,{provider:o.agent||null,cls:i.cls,status:i.status,text:o.text}).catch(()=>{});continue}if(o.role!=="user"&&o.box&&n.add(o.box),await $(e,{type:o.role==="user"?"turn.user":"turn.agent",actor:o.role==="user"?"user":"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:o.text,ts:o.ts,model:o.model||null,tools:o.tools||void 0,boxRole:o.boxRole,sourceId:o.sourceId||void 0,note:o.note||void 0,images:o.images?.length?o.images:void 0}}),o.role==="assistant"&&o.box===e.leadBox&&e.workspace?.branch){let c=gx(o.text);if(c&&Gv(await F(e).catch(()=>[])))continue;if(c){let l=kx(c),u;if(e.workspace?.kind==="multi"){let h=await _o(e).catch(()=>[]);u=h.length?h.map(w=>({name:w.name,slug:w.repo??null})):void 0}let f=(e.workspace?.kind==="multi"?null:await Cr(e.cwd).catch(()=>null))||e.workspace.branch,d=await ou(e,{branch:f,rebase:l}).catch(()=>null),p=d?null:bx(c);if(d&&d.available.length===0)continue;await $(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:wB(),ts:o.ts,excerpt:c,branch:f,base:e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:o.boxRole,available:d?.available,defaults:d?.defaults,prState:d?.prState,openPr:d?.openPr||void 0,repos:d?.repos||u,offered:d?.defaults||p?.offered||void 0,toPr:p?.toPr||void 0}})}}}}catch{}return{agentTurnBoxes:n}}async function Zv(e,t){try{let n=await km(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=Yv(o);n.keys.has(s)||(n.keys.add(s),n.cmdN+=1,await $(e,{type:"tool.called",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id??null,tool:o.tool||null,command:o.command,description:o.description||"",summary:o.summary||o.command,ts:o.ts??null,boxRole:o.boxRole,n:n.cmdN}}),Tv(e,o),Ev(e,o))}}catch{}}async function Qv(e,t){try{let n=await km(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=Jv(o);n.keys.has(s)||(n.keys.add(s),await $(e,{type:"job.started",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id,kind:o.kind||"agent",name:o.name||null,detail:o.detail||null,ts:o.ts??null,boxRole:o.boxRole}}))}}catch{}}var bm,du,eS=j(()=>{me();bo();om();Av();Eo();um();Nr();dl();pm();uu();bm=new Map,du=new Map});function gB(e){let t=[],n=null;for(let r of String(e||"").split(`
192
- `)){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 yB(e,t){let n=`${e.id}:${t.name}`;if(!xm.has(n)){let r=await F(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);xm.set(n,o)}return xm.get(n)}async function tS(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await so(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await yB(e,t),o=gB(await Et(n.file,262144)),s=o[o.length-1];for(let a of o){if(a.ts==null||r.has(a.ts))continue;r.add(a.ts);let i={input:Math.max(0,a.last.input-a.last.cachedInput),output:a.last.output,cacheRead:a.last.cachedInput,cacheWrite:0},c=a.model||t.model||"gpt-5.5";await $(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:mn(c,i),model:c,tokens:i,reasoningOutput:a.last.reasoningOutput||void 0,codexTs:a.ts,ts:a.ts}}),a===s&&a.contextWindow&&await $(e,{type:"context.usage",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{occupancy:a.occupancy,window:a.contextWindow,pct:a.occupancy!=null?a.occupancy/a.contextWindow:null,model:a.model||null,ts:a.ts}})}}catch{}}var xm,nS=j(()=>{me();io();Xt();Dn();xm=new Map});import fu from"node:fs";import Sm from"node:path";import bB from"node:os";async function vB({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(xB,{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:rS})});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<rS)break}return r}function SB(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 sS(){try{return JSON.parse(fu.readFileSync(pu(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function EB(e){try{fu.mkdirSync(Sm.dirname(pu()),{recursive:!0});let t=pu()+".tmp";fu.writeFileSync(t,JSON.stringify(e)),fu.renameSync(t,pu())}catch{}}async function _B({fetchImpl:e,now:t=Date.now()}={}){if(Pr.rows&&t-Pr.at<TB)return Pr.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=sS(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await vB({sinceMs:o,cookie:n,fetchImpl:e});Pr={at:t,rows:s.map(SB).filter(Boolean),error:null}}catch(s){Pr={at:t,rows:null,error:String(s?.message||s)}}return Pr.rows}async function IB(e,t){let n=`${e.id}:${t.name}`;if(!vm.has(n)){let r=await F(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);vm.set(n,o)}return vm.get(n)}async function aS(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!oS())return;let r=await _B({fetchImpl:n});if(!r||!r.length)return;let o=await u0(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await IB(e,t),a=sS(),i=new Set(a.seen||[]),c=a.sinceMs||0;for(let l of r){if(!l.conversationId||l.conversationId!==o.chatId||s.has(l.id)||i.has(`${e.id}:${t.name}:${l.id}`))continue;s.add(l.id),i.add(`${e.id}:${t.name}:${l.id}`),l.ts&&l.ts>c&&(c=l.ts);let u=l.model||o.models[o.models.length-1]||"cursor-unknown",f=l.tokens||null,d=l.vendorCents!=null?l.vendorCents/100:0;!d&&f&&(d=mn(u,f)),!d&&l.chargedCents!=null&&(d=l.chargedCents/100),await $(e,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:t.name,provider:"cursor",payload:{usd:d,model:u,...f?{tokens:f}:{},...l.vendorCents!=null?{vendorCents:l.vendorCents}:{},...l.chargedCents!=null?{chargedCents:l.chargedCents}:{},...l.kind?{kind:l.kind}:{},conversationId:l.conversationId,cursorEventId:l.id,ts:l.ts??void 0}})}EB({sinceMs:c,seen:[...i].slice(-AB)})}catch{}}var kB,oS,xB,rS,TB,Pr,pu,AB,Tm,vm,Em=j(()=>{me();fp();Dn();kB=process.env.BOSTRAT_STATE_DIR||Sm.join(process.env.HOME||bB.tmpdir(),".bostrat"),oS=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,xB="https://cursor.com/api/dashboard/get-filtered-usage-events",rS=100;TB=5*6e4,Pr={at:0,rows:null,error:null},pu=()=>Sm.join(kB,"cursor-usage.json");AB=5e3;Tm=()=>({enabled:oS(),lastPollAt:Pr.at||null,error:Pr.error}),vm=new Map});import{execFile as $B}from"node:child_process";import{promisify as RB}from"node:util";function Us({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function mu(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function hu({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?PB[r]:null;return a&&s.push(a),s.push(`${uS}: ${Us({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${dS}: ${String(o).trim()}`),s}function iS(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
193
- `)){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===uS.toLowerCase()&&!t.epoch)t.epoch=mu(a);else if(s===dS.toLowerCase()&&!t.model)t.model=a;else if(s===fS.toLowerCase()&&!t.cause){let i=a.toLowerCase();$i.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 DB(e,t=Dr){return e<=t?"rework":"drift"}function BB(e,{window:t=Dr,end:n=$m}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function UB({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return jB.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${fS} trailer`}:FB.test(s)&&!cS.test(s)?{cause:"style",level:"C",basis:"subject"}:cS.test(s)?{cause:"defect",level:"C",basis:"subject"}:LB.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 WB(e){return HB.some(t=>t.test(e))}function qB(e){let t=[],n=null;for(let r of String(e||"").split(`
194
- `)){if(r.startsWith("diff --git ")){n={oldPath:null,newPath:null,deleted:[],added:0,binary:!1},t.push(n);continue}if(n){if(r.startsWith("--- ")){let o=r.slice(4).trim();n.oldPath=o==="/dev/null"?null:o.replace(/^a\//,"")}else if(r.startsWith("+++ ")){let o=r.slice(4).trim();n.newPath=o==="/dev/null"?null:o.replace(/^b\//,"")}else if(r.startsWith("Binary files"))n.binary=!0;else if(r.startsWith("@@")){let o=/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(r);if(!o)continue;let s=Number(o[1]),a=o[2]==null?1:Number(o[2]),i=o[4]==null?1:Number(o[4]);a>0&&n.deleted.push([s,a]),n.added+=i}}}return t}function KB(e){let t=new Map,n=null;for(let r of String(e||"").split(`
195
- `)){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 lS(e,t){let{stdout:n}=await Im(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
191
+ `).slice(0,400)});import{randomUUID as k1}from"node:crypto";function Ii(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function Zv(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function Qv(e){return`job|${e.box}|id:${e.id}`}async function xm(e){return km.has(e.id)?km.get(e.id):(pu.has(e.id)||pu.set(e.id,U(e).then(t=>{let n={keys:new Set,cmdN:0};for(let r of t)if((r.type==="turn.user"||r.type==="turn.agent"||r.type==="provider.error")&&r.payload?.text!=null){let o=r.type==="turn.user"?"user":"assistant";r.payload.sourceId&&n.keys.add(Ii({role:o,sourceId:r.payload.sourceId})),n.keys.add(Ii({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(Ii({role:"user",sourceId:r.payload.sourceId})),n.keys.add(Ii({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(Zv({id:o.id,box:r.boxId,ts:o.ts,command:o.command})),Number(o.n)>n.cmdN&&(n.cmdN=Number(o.n))}else r.type==="job.started"&&r.payload?.id&&n.keys.add(Qv({id:r.payload.id,box:r.boxId}));return km.set(e.id,n),n}).finally(()=>pu.delete(e.id))),pu.get(e.id))}async function eS(e,t){let n=new Set;try{let r=(await xm(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=Ii(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?lu(o.text):null;if(a){await $(e,{type:"peer.message",actor:"peer",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:a.text,ts:o.ts,keyText:String(o.text||"").slice(0,40),from:await Ov(a,$i),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=gb(o);if(i){await $(e,{type:"provider.error",actor:"system",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{cls:i.cls,code:i.code||void 0,status:i.status||void 0,requestId:i.requestId||void 0,text:o.text,ts:o.ts,model:o.model||null,boxRole:o.boxRole,sourceId:o.sourceId||void 0}}),Nv(e,{provider:o.agent||null,cls:i.cls,status:i.status,text:o.text}).catch(()=>{});continue}if(o.role!=="user"&&o.box&&n.add(o.box),await $(e,{type:o.role==="user"?"turn.user":"turn.agent",actor:o.role==="user"?"user":"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:o.text,ts:o.ts,model:o.model||null,tools:o.tools||void 0,boxRole:o.boxRole,sourceId:o.sourceId||void 0,note:o.note||void 0,images:o.images?.length?o.images:void 0}}),o.role==="assistant"&&o.box===e.leadBox&&e.workspace?.branch){let c=kx(o.text);if(c&&Yv(await U(e).catch(()=>[])))continue;if(c){let l=Sx(c),u;if(e.workspace?.kind==="multi"){let h=await _o(e).catch(()=>[]);u=h.length?h.map(w=>({name:w.name,slug:w.repo??null})):void 0}let f=(e.workspace?.kind==="multi"?null:await Mr(e.cwd).catch(()=>null))||e.workspace.branch,d=await au(e,{branch:f,rebase:l}).catch(()=>null),p=d?null:vx(c);if(d&&d.available.length===0)continue;await $(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:k1(),ts:o.ts,excerpt:c,branch:f,base:e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:o.boxRole,available:d?.available,defaults:d?.defaults,prState:d?.prState,openPr:d?.openPr||void 0,repos:d?.repos||u,offered:d?.defaults||p?.offered||void 0,toPr:p?.toPr||void 0}})}}}}catch{}return{agentTurnBoxes:n}}async function tS(e,t){try{let n=await xm(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=Zv(o);n.keys.has(s)||(n.keys.add(s),n.cmdN+=1,await $(e,{type:"tool.called",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id??null,tool:o.tool||null,command:o.command,description:o.description||"",summary:o.summary||o.command,ts:o.ts??null,boxRole:o.boxRole,n:n.cmdN}}),_v(e,o),Iv(e,o))}}catch{}}async function nS(e,t){try{let n=await xm(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=Qv(o);n.keys.has(s)||(n.keys.add(s),await $(e,{type:"job.started",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id,kind:o.kind||"agent",name:o.name||null,detail:o.detail||null,ts:o.ts??null,boxRole:o.boxRole}}))}}catch{}}var km,pu,rS=L(()=>{he();bo();sm();$v();Eo();dm();Pr();pl();mm();fu();km=new Map,pu=new Map});function x1(e){let t=[],n=null;for(let r of String(e||"").split(`
192
+ `)){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 v1(e,t){let n=`${e.id}:${t.name}`;if(!vm.has(n)){let r=await U(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);vm.set(n,o)}return vm.get(n)}async function oS(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await so(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await v1(e,t),o=x1(await Et(n.file,262144)),s=o[o.length-1];for(let a of o){if(a.ts==null||r.has(a.ts))continue;r.add(a.ts);let i={input:Math.max(0,a.last.input-a.last.cachedInput),output:a.last.output,cacheRead:a.last.cachedInput,cacheWrite:0},c=a.model||t.model||"gpt-5.5";await $(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:mn(c,i),model:c,tokens:i,reasoningOutput:a.last.reasoningOutput||void 0,codexTs:a.ts,ts:a.ts}}),a===s&&a.contextWindow&&await $(e,{type:"context.usage",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{occupancy:a.occupancy,window:a.contextWindow,pct:a.occupancy!=null?a.occupancy/a.contextWindow:null,model:a.model||null,ts:a.ts}})}}catch{}}var vm,sS=L(()=>{he();io();Xt();Dn();vm=new Map});import mu from"node:fs";import Tm from"node:path";import S1 from"node:os";async function A1({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(E1,{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:aS})});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<aS)break}return r}function _1(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 cS(){try{return JSON.parse(mu.readFileSync(hu(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function $1(e){try{mu.mkdirSync(Tm.dirname(hu()),{recursive:!0});let t=hu()+".tmp";mu.writeFileSync(t,JSON.stringify(e)),mu.renameSync(t,hu())}catch{}}async function O1({fetchImpl:e,now:t=Date.now()}={}){if(Dr.rows&&t-Dr.at<I1)return Dr.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=cS(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await A1({sinceMs:o,cookie:n,fetchImpl:e});Dr={at:t,rows:s.map(_1).filter(Boolean),error:null}}catch(s){Dr={at:t,rows:null,error:String(s?.message||s)}}return Dr.rows}async function C1(e,t){let n=`${e.id}:${t.name}`;if(!Sm.has(n)){let r=await U(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);Sm.set(n,o)}return Sm.get(n)}async function lS(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!iS())return;let r=await O1({fetchImpl:n});if(!r||!r.length)return;let o=await p0(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await C1(e,t),a=cS(),i=new Set(a.seen||[]),c=a.sinceMs||0;for(let l of r){if(!l.conversationId||l.conversationId!==o.chatId||s.has(l.id)||i.has(`${e.id}:${t.name}:${l.id}`))continue;s.add(l.id),i.add(`${e.id}:${t.name}:${l.id}`),l.ts&&l.ts>c&&(c=l.ts);let u=l.model||o.models[o.models.length-1]||"cursor-unknown",f=l.tokens||null,d=l.vendorCents!=null?l.vendorCents/100:0;!d&&f&&(d=mn(u,f)),!d&&l.chargedCents!=null&&(d=l.chargedCents/100),await $(e,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:t.name,provider:"cursor",payload:{usd:d,model:u,...f?{tokens:f}:{},...l.vendorCents!=null?{vendorCents:l.vendorCents}:{},...l.chargedCents!=null?{chargedCents:l.chargedCents}:{},...l.kind?{kind:l.kind}:{},conversationId:l.conversationId,cursorEventId:l.id,ts:l.ts??void 0}})}$1({sinceMs:c,seen:[...i].slice(-R1)})}catch{}}var T1,iS,E1,aS,I1,Dr,hu,R1,Em,Sm,Am=L(()=>{he();pp();Dn();T1=process.env.BOSTRAT_STATE_DIR||Tm.join(process.env.HOME||S1.tmpdir(),".bostrat"),iS=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,E1="https://cursor.com/api/dashboard/get-filtered-usage-events",aS=100;I1=5*6e4,Dr={at:0,rows:null,error:null},hu=()=>Tm.join(T1,"cursor-usage.json");R1=5e3;Em=()=>({enabled:iS(),lastPollAt:Dr.at||null,error:Dr.error}),Sm=new Map});import{execFile as M1}from"node:child_process";import{promisify as N1}from"node:util";function Hs({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function wu(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function gu({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?L1[r]:null;return a&&s.push(a),s.push(`${pS}: ${Hs({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${mS}: ${String(o).trim()}`),s}function uS(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
193
+ `)){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===pS.toLowerCase()&&!t.epoch)t.epoch=wu(a);else if(s===mS.toLowerCase()&&!t.model)t.model=a;else if(s===hS.toLowerCase()&&!t.cause){let i=a.toLowerCase();Ri.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 F1(e,t=Br){return e<=t?"rework":"drift"}function U1(e,{window:t=Br,end:n=Rm}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function K1({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return H1.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${hS} trailer`}:q1.test(s)&&!dS.test(s)?{cause:"style",level:"C",basis:"subject"}:dS.test(s)?{cause:"defect",level:"C",basis:"subject"}:W1.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 V1(e){return G1.some(t=>t.test(e))}function z1(e){let t=[],n=null;for(let r of String(e||"").split(`
194
+ `)){if(r.startsWith("diff --git ")){n={oldPath:null,newPath:null,deleted:[],added:0,binary:!1},t.push(n);continue}if(n){if(r.startsWith("--- ")){let o=r.slice(4).trim();n.oldPath=o==="/dev/null"?null:o.replace(/^a\//,"")}else if(r.startsWith("+++ ")){let o=r.slice(4).trim();n.newPath=o==="/dev/null"?null:o.replace(/^b\//,"")}else if(r.startsWith("Binary files"))n.binary=!0;else if(r.startsWith("@@")){let o=/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(r);if(!o)continue;let s=Number(o[1]),a=o[2]==null?1:Number(o[2]),i=o[4]==null?1:Number(o[4]);a>0&&n.deleted.push([s,a]),n.added+=i}}}return t}function Y1(e){let t=new Map,n=null;for(let r of String(e||"").split(`
195
+ `)){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 fS(e,t){let{stdout:n}=await $m(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
196
196
  `);return{sha:r.trim(),parents:o.trim()?o.trim().split(" "):[],ts:Number(s)*1e3,subject:a??"",message:i.join(`
197
- `)}}async function mS(e,t,{fixKey:n=null,window:r=Dr,resolveOrigin:o=null,context:s={}}={}){let a=await lS(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=iS(a.message),l=n?mu(n):c.epoch,u=l?Us(l):null,{stdout:f}=await Im(e,["diff","-U0","--no-color","-M","-C",i,t]),d=qB(f),p=0,h=0,w=0,g=new Map;for(let B of d){if(B.binary)continue;let T=B.oldPath||B.newPath||"",_=B.deleted.reduce((I,[,U])=>I+U,0);if(WB(T)){w+=_;continue}if(p+=B.added,h+=_,!B.oldPath||!_)continue;let O;try{let I=["blame","-w","-M","-C","--line-porcelain"];for(let[U,H]of B.deleted)I.push("-L",`${U},${U+H-1}`);I.push(i,"--",B.oldPath),O=KB((await Im(e,I)).stdout)}catch{continue}for(let{sha:I,time:U}of O.values()){let H=g.get(I)??{lines:0,time:U};H.lines+=1,g.set(I,H)}}let k=[],S=0,E=new Map;for(let[B,{lines:T,time:_}]of g){let O=E.get(B);if(!O){try{O=await lS(e,B)}catch{O=null}E.set(B,O)}let I=O?iS(O.message):{epoch:null},U=I.epoch,H=I.provider,ae=I.model;if(!U&&o){let W=await o(B,O);W?.trackId&&W?.boxId!=null&&(U={trackId:W.trackId,boxId:W.boxId,epoch:W.epoch??0},H=H??W.provider??null,ae=ae??W.model??null)}if(!U){S+=T;continue}let X=Number.isFinite(_)?_:O?.ts??a.ts,C=Math.max(0,(a.ts-X)/MB),Q=Us(U),ve=Q===u?"self":DB(C,r);k.push({sha:B,key:Q,trackId:U.trackId,boxId:U.boxId,epoch:U.epoch,provider:H??null,model:ae??null,lines:T,ageDays:Math.round(C*100)/100,class:ve,decay:ve==="rework"?1:ve==="drift"?Math.round(BB(C,{window:r})*1e3)/1e3:0})}k.sort((B,T)=>T.lines-B.lines);let R=UB({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0});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:p,deleted:h,excludedDeleted:w,origins:k,unattributedLines:S,ghost:h===0&&p>0,heuristic:R}}function hS(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function _m(e){let t=e.genUsd;return{...e,genUsd:en(t),reworkChargedUsd:en(e.reworkChargedUsd),reworkPendingUsd:en(e.reworkPendingUsd),trueUsd:en(t+e.reworkChargedUsd),multiplier:t>0?en((t+e.reworkChargedUsd)/t):null}}function wS(e,{window:t=Dr,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=new Map;for(let T of r)T.type==="rework.cause.answered"&&T.payload?.sha&&T.payload?.cause&&i.set(T.payload.sha,T.payload.cause);let c=new Set;for(let T of r)T.type==="rework.cause.offered"&&T.payload?.sha&&c.add(T.payload.sha);let l={},u=(T,_,O)=>Us({trackId:T,boxId:_,epoch:O??0}),f=(T,_={})=>{if(!l[T]){let I=mu(T)||{};l[T]={key:T,...I,provider:null,model:null,...Am()}}let O=l[T];return _.provider&&!O.provider&&(O.provider=_.provider),_.model&&!O.model&&(O.model=_.model),O};for(let T of o){if(!T.boxId)continue;let _=u(T.trackId,T.boxId,T.epoch),{usd:O,model:I}=Ft(T),U=f(_,{provider:T.provider,model:I!=="unknown"?I:null});U.genUsd+=O}let d=new Map;for(let T of s){let _=`${T.trackId}/${T.boxId}`;(d.get(_)??d.set(_,[]).get(_)).push(T)}for(let T of d.values())T.sort((_,O)=>_.ts-O.ts);let p=(T,_,O,I)=>{let U=d.get(`${T}/${_}`)||[],H=-1/0;for(let C of U)C.ts<I&&(H=C.ts);let ae=0,X=0;for(let C of o)C.trackId!==T||C.boxId!==_||(C.epoch??0)===(O??0)&&(C.ts<=H||C.ts>I||(ae+=Ft(C).usd,X++));return{usd:ae,turns:X,from:Number.isFinite(H)?H:null}},h={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0},w={A:0,B:0,C:0,E:0,none:0},g=[],k=[],S={},E={},R=new Set;for(let T of a){let _=T.payload||{};if(!_.sha||R.has(_.sha))continue;R.add(_.sha);let O=mu(_.fixKey)||{trackId:T.trackId,boxId:T.boxId,epoch:T.epoch??0},{usd:I,turns:U}=p(O.trackId,O.boxId,O.epoch,_.ts??T.ts),H=null;i.has(_.sha)?H={cause:i.get(_.sha),level:"B",basis:"operator"}:(_.heuristic?.level&&_.heuristic.level!=="C"||_.heuristic)&&(H=_.heuristic);let ae=H?.level??"none";w[ae]=(w[ae]||0)+1;let X=NB.has(ae),C=Number(_.deleted)||0,Q=Array.isArray(_.origins)?_.origins:[],ve=Q.filter(be=>be.class==="rework").reduce((be,se)=>be+se.lines,0),W={sha:_.sha,subject:_.subject??"",ts:_.ts??T.ts,trackId:T.trackId,fixKey:_.fixKey??null,fixProvider:_.fixProvider??T.provider??null,fixUsd:en(I),fixTurns:U,linesReworked:ve,unattributedLines:Number(_.unattributedLines)||0,ghost:_.ghost===!0,verdict:H?{cause:H.cause,level:ae,basis:H.basis??null}:null,charged:en(0),origins:[]};if(_.ghost||C===0)h.ghost+=I;else{let be=0;for(let pe of Q){let ie=pe.lines/C,L=I*ie;if(be+=L,pe.class==="self"){h.self+=L;continue}let ce=pe.class==="rework"?1:Number(pe.decay)||0,ue=L*ce;if(h.decayed+=L-ue,ue<=0)continue;let Ae=f(pe.key,{provider:pe.provider,model:pe.model});Ae.fixes+=1,Ae.linesReworked+=pe.class==="rework"?pe.lines:0;let _e=H?.cause&&$i.includes(H.cause)?H.cause:"unclassified";Ae.causes[_e]+=1,X?(Ae.reworkChargedUsd+=ue,h.charged+=ue,W.charged=en(W.charged+ue)):(Ae.reworkPendingUsd+=ue,h.pending+=ue),W.origins.push({key:pe.key,provider:Ae.provider,model:Ae.model,lines:pe.lines,ageDays:pe.ageDays,class:pe.class,usd:en(ue)})}let se=Math.max(0,I-be);h.unattributed+=se}g.push(W),!i.has(_.sha)&&c.has(_.sha)&&k.push(_.sha)}for(let T of Object.values(l)){let _=T.provider||"unknown",O=T.model||"unknown",I=U=>{U.genUsd+=T.genUsd,U.reworkChargedUsd+=T.reworkChargedUsd,U.reworkPendingUsd+=T.reworkPendingUsd,U.linesReworked+=T.linesReworked,U.fixes+=T.fixes;for(let H of Object.keys(U.causes))U.causes[H]+=T.causes[H]};I(S[_]||=Am()),I(E[O]||=Am())}g.sort((T,_)=>_.ts-T.ts);let B=Object.values(l).map(T=>{let _=n[`${T.trackId}/${T.boxId}`]||{};return _m({...T,trackName:_.trackName??null,label:_.label??null})}).sort((T,_)=>_.reworkChargedUsd+_.reworkPendingUsd-(T.reworkChargedUsd+T.reworkPendingUsd)||_.genUsd-T.genUsd);return{window:t,basis:`rework = lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old; fix cost = the fixing box's turns since its previous commit; charged only on an authoritative / operator / self-reported cause`,byEpoch:Object.fromEntries(B.map(T=>[T.key,T])),epochs:B,byProvider:Object.fromEntries(Object.entries(S).map(([T,_])=>[T,_m(_)])),byModel:Object.fromEntries(Object.entries(E).map(([T,_])=>[T,_m(_)])),buckets:Object.fromEntries(Object.entries(h).map(([T,_])=>[T,en(_)])),fixUsdTotal:en(Object.values(h).reduce((T,_)=>T+_,0)),fixes:g,verdicts:w,pendingTaps:k,commits:s.length}}var OB,CB,Im,uS,dS,fS,MB,Dr,$m,pS,$i,NB,PB,jB,cS,LB,FB,HB,en,Am,wu=j(()=>{vr();OB=RB($B),CB=64*1024*1024,Im=(e,t)=>OB("git",["-C",e,...t],{maxBuffer:CB,timeout:6e4}),uS="Bostrat-Epoch",dS="Bostrat-Model",fS="Bostrat-Fix-Cause",MB=24*36e5,Dr=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,$m=90,pS=3,$i=Object.freeze(["defect","design","requirements","style"]),NB=new Set(["A","B","E"]);PB={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};jB=/^revert\b|^revert "/i,cS=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,LB=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,FB=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;HB=[/(^|\/)\.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)\//];en=e=>Math.round(e*1e4)/1e4,Am=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import Ci from"node:fs/promises";import At from"node:path";import GB from"node:os";import VB from"node:net";import{randomUUID as zB}from"node:crypto";import{execFile as YB}from"node:child_process";import{promisify as JB}from"node:util";function r1(e){for(let t of Dm(e))if(!vS.test(t))return t;return null}function SS(e){let t=Dm(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function o1(e,t){let n=SS(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return At.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return At.resolve(e,n[r+1])}return e}function a1(e){let t=!1,n=!1;for(let r of Dm(e)){if(!t){if(vS.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&Rm(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,Rm(r))return`serves the filesystem root ("${r}")`;continue}if(Rm(r))return`serves the filesystem root ("${r}")`;if(s1(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function c1(e,t){if(At.resolve(e)===At.resolve(t))return!0;let[n,r]=await Promise.all([gu(e),gu(t)]);return n===r}async function l1(e){let n=(await Ci.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 TS(At.join(e,o.name,Mm))?`./${o.name}`:null))).filter(Boolean)}async function u1(e,t){let[n,r]=await Promise.all([gu(e),gu(t)]),o=At.relative(n,r);if(o&&(o.startsWith("..")||At.isAbsolute(o)))throw Ri(`serve directory escapes the Track workspace: ${t}`)}async function d1(e,t){let n=a1(t);if(n)throw Ri(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await i1(e))throw Ri(`serve directory does not exist: ${e}`);let r=r1(t);if(!r)return;if(!r.includes("/")&&!await qy(r,{loginShell:!0,failOpen:!0}))throw Ri(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(e1.test(t)||t1.has(r)||!QB.has(r)||!SS(t).includes("run")||n1.test(t))return;let o=o1(e,t);if(await TS(At.join(o,Mm)))return;let s=await l1(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Ri(`no ${Mm} in ${o}${a}`)}async function zn(){return yn||(Om||=(async()=>{try{yn=JSON.parse(await Ci.readFile(xS,"utf8"))}catch{yn={views:[],adoptWatermarks:{}}}finally{Om=null}return yn.views||=[],yn.adoptWatermarks||={},yn})(),Om)}async function kn(){await Tt(xS,yn)}function Vn(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"view.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,payload:{ts:Date.now(),change:t,viewId:e.id,name:e.name,slug:e.slug,port:e.port,cmd:e.cmd||null,...n}}).catch(()=>{})}function jm(e){return Oi.get(e)||null}function AS(e,{name:t,box:n}={}){let r=Oi.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 Oi.set(e,o),o}function Nm(e,t){let n=Oi.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function yu(e,{error:t=null}={}){let n=Oi.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function _S(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 Pm(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function f1(e,t){let n=Pm(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!bS.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!bS.has(s))return s}}function Mi(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=VB.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 Lm(e){if(process.platform!=="darwin"){await bn("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await bn("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 IS(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function p1(e,t){let n=new Set(e.views.map(o=>o.port)),r=IS();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=gS;o<=yS;o++)if(!(n.has(o)||r.has(o))&&!await Mi(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${gS}-${yS}`)}async function m1(e){try{let{stdout:t}=await bn(K,V("list-sessions","-F","#{session_name}"));return t.split(`
198
- `).some(n=>n.trim()===Hs(e))}catch{return!1}}async function Ni(e){try{await bn(K,V("kill-session","-t",Hs(e)))}catch{}}async function Fm(e){if(!await Ha())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=Hs(e.slug),n=e.serveCwd??e.cwd,r=At.dirname(process.execPath);await bn(K,V("new-session","-d","-s",t,"-c",n)),await bn(K,V("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await bn(K,V("send-keys","-t",t,"Enter")),await bn(K,V("send-keys","-t",t,"-l",e.cmd)),await bn(K,V("send-keys","-t",t,"Enter"))}async function kS(e,t=12){try{let{stdout:n}=await bn(K,V("capture-pane","-t",Hs(e),"-p"));return String(n||"").trimEnd().split(`
197
+ `)}}async function gS(e,t,{fixKey:n=null,window:r=Br,resolveOrigin:o=null,context:s={}}={}){let a=await fS(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=uS(a.message),l=n?wu(n):c.epoch,u=l?Hs(l):null,{stdout:f}=await $m(e,["diff","-U0","--no-color","-M","-C",i,t]),d=z1(f),p=0,h=0,w=0,g=new Map;for(let M of d){if(M.binary)continue;let T=M.oldPath||M.newPath||"",A=M.deleted.reduce((I,[,W])=>I+W,0);if(V1(T)){w+=A;continue}if(p+=M.added,h+=A,!M.oldPath||!A)continue;let C;try{let I=["blame","-w","-M","-C","--line-porcelain"];for(let[W,j]of M.deleted)I.push("-L",`${W},${W+j-1}`);I.push(i,"--",M.oldPath),C=Y1((await $m(e,I)).stdout)}catch{continue}for(let{sha:I,time:W}of C.values()){let j=g.get(I)??{lines:0,time:W};j.lines+=1,g.set(I,j)}}let b=[],E=0,S=new Map;for(let[M,{lines:T,time:A}]of g){let C=S.get(M);if(!C){try{C=await fS(e,M)}catch{C=null}S.set(M,C)}let I=C?uS(C.message):{epoch:null},W=I.epoch,j=I.provider,ee=I.model;if(!W&&o){let H=await o(M,C);H?.trackId&&H?.boxId!=null&&(W={trackId:H.trackId,boxId:H.boxId,epoch:H.epoch??0},j=j??H.provider??null,ee=ee??H.model??null)}if(!W){E+=T;continue}let q=Number.isFinite(A)?A:C?.ts??a.ts,O=Math.max(0,(a.ts-q)/B1),z=Hs(W),te=z===u?"self":F1(O,r);b.push({sha:M,key:z,trackId:W.trackId,boxId:W.boxId,epoch:W.epoch,provider:j??null,model:ee??null,lines:T,ageDays:Math.round(O*100)/100,class:te,decay:te==="rework"?1:te==="drift"?Math.round(U1(O,{window:r})*1e3)/1e3:0})}b.sort((M,T)=>T.lines-M.lines);let R=K1({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0});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:p,deleted:h,excludedDeleted:w,origins:b,unattributedLines:E,ghost:h===0&&p>0,heuristic:R}}function yS(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function Im(e){let t=e.genUsd;return{...e,genUsd:en(t),reworkChargedUsd:en(e.reworkChargedUsd),reworkPendingUsd:en(e.reworkPendingUsd),trueUsd:en(t+e.reworkChargedUsd),multiplier:t>0?en((t+e.reworkChargedUsd)/t):null}}function bS(e,{window:t=Br,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=new Map;for(let T of r)T.type==="rework.cause.answered"&&T.payload?.sha&&T.payload?.cause&&i.set(T.payload.sha,T.payload.cause);let c=new Set;for(let T of r)T.type==="rework.cause.offered"&&T.payload?.sha&&c.add(T.payload.sha);let l={},u=(T,A,C)=>Hs({trackId:T,boxId:A,epoch:C??0}),f=(T,A={})=>{if(!l[T]){let I=wu(T)||{};l[T]={key:T,...I,provider:null,model:null,..._m()}}let C=l[T];return A.provider&&!C.provider&&(C.provider=A.provider),A.model&&!C.model&&(C.model=A.model),C};for(let T of o){if(!T.boxId)continue;let A=u(T.trackId,T.boxId,T.epoch),{usd:C,model:I}=Ft(T),W=f(A,{provider:T.provider,model:I!=="unknown"?I:null});W.genUsd+=C}let d=new Map;for(let T of s){let A=`${T.trackId}/${T.boxId}`;(d.get(A)??d.set(A,[]).get(A)).push(T)}for(let T of d.values())T.sort((A,C)=>A.ts-C.ts);let p=(T,A,C,I)=>{let W=d.get(`${T}/${A}`)||[],j=-1/0;for(let O of W)O.ts<I&&(j=O.ts);let ee=0,q=0;for(let O of o)O.trackId!==T||O.boxId!==A||(O.epoch??0)===(C??0)&&(O.ts<=j||O.ts>I||(ee+=Ft(O).usd,q++));return{usd:ee,turns:q,from:Number.isFinite(j)?j:null}},h={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0},w={A:0,B:0,C:0,E:0,none:0},g=[],b=[],E={},S={},R=new Set;for(let T of a){let A=T.payload||{};if(!A.sha||R.has(A.sha))continue;R.add(A.sha);let C=wu(A.fixKey)||{trackId:T.trackId,boxId:T.boxId,epoch:T.epoch??0},{usd:I,turns:W}=p(C.trackId,C.boxId,C.epoch,A.ts??T.ts),j=null;i.has(A.sha)?j={cause:i.get(A.sha),level:"B",basis:"operator"}:(A.heuristic?.level&&A.heuristic.level!=="C"||A.heuristic)&&(j=A.heuristic);let ee=j?.level??"none";w[ee]=(w[ee]||0)+1;let q=j1.has(ee),O=Number(A.deleted)||0,z=Array.isArray(A.origins)?A.origins:[],te=z.filter(ke=>ke.class==="rework").reduce((ke,ie)=>ke+ie.lines,0),H={sha:A.sha,subject:A.subject??"",ts:A.ts??T.ts,trackId:T.trackId,fixKey:A.fixKey??null,fixProvider:A.fixProvider??T.provider??null,fixUsd:en(I),fixTurns:W,linesReworked:te,unattributedLines:Number(A.unattributedLines)||0,ghost:A.ghost===!0,verdict:j?{cause:j.cause,level:ee,basis:j.basis??null}:null,charged:en(0),origins:[]};if(A.ghost||O===0)h.ghost+=I;else{let ke=0;for(let me of z){let ce=me.lines/O,F=I*ce;if(ke+=F,me.class==="self"){h.self+=F;continue}let le=me.class==="rework"?1:Number(me.decay)||0,de=F*le;if(h.decayed+=F-de,de<=0)continue;let Ae=f(me.key,{provider:me.provider,model:me.model});Ae.fixes+=1,Ae.linesReworked+=me.class==="rework"?me.lines:0;let _e=j?.cause&&Ri.includes(j.cause)?j.cause:"unclassified";Ae.causes[_e]+=1,q?(Ae.reworkChargedUsd+=de,h.charged+=de,H.charged=en(H.charged+de)):(Ae.reworkPendingUsd+=de,h.pending+=de),H.origins.push({key:me.key,provider:Ae.provider,model:Ae.model,lines:me.lines,ageDays:me.ageDays,class:me.class,usd:en(de)})}let ie=Math.max(0,I-ke);h.unattributed+=ie}g.push(H),!i.has(A.sha)&&c.has(A.sha)&&b.push(A.sha)}for(let T of Object.values(l)){let A=T.provider||"unknown",C=T.model||"unknown",I=W=>{W.genUsd+=T.genUsd,W.reworkChargedUsd+=T.reworkChargedUsd,W.reworkPendingUsd+=T.reworkPendingUsd,W.linesReworked+=T.linesReworked,W.fixes+=T.fixes;for(let j of Object.keys(W.causes))W.causes[j]+=T.causes[j]};I(E[A]||=_m()),I(S[C]||=_m())}g.sort((T,A)=>A.ts-T.ts);let M=Object.values(l).map(T=>{let A=n[`${T.trackId}/${T.boxId}`]||{};return Im({...T,trackName:A.trackName??null,label:A.label??null})}).sort((T,A)=>A.reworkChargedUsd+A.reworkPendingUsd-(T.reworkChargedUsd+T.reworkPendingUsd)||A.genUsd-T.genUsd);return{window:t,basis:`rework = lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old; fix cost = the fixing box's turns since its previous commit; charged only on an authoritative / operator / self-reported cause`,byEpoch:Object.fromEntries(M.map(T=>[T.key,T])),epochs:M,byProvider:Object.fromEntries(Object.entries(E).map(([T,A])=>[T,Im(A)])),byModel:Object.fromEntries(Object.entries(S).map(([T,A])=>[T,Im(A)])),buckets:Object.fromEntries(Object.entries(h).map(([T,A])=>[T,en(A)])),fixUsdTotal:en(Object.values(h).reduce((T,A)=>T+A,0)),fixes:g,verdicts:w,pendingTaps:b,commits:s.length}}var P1,D1,$m,pS,mS,hS,B1,Br,Rm,wS,Ri,j1,L1,H1,dS,W1,q1,G1,en,_m,yu=L(()=>{Sr();P1=N1(M1),D1=64*1024*1024,$m=(e,t)=>P1("git",["-C",e,...t],{maxBuffer:D1,timeout:6e4}),pS="Bostrat-Epoch",mS="Bostrat-Model",hS="Bostrat-Fix-Cause",B1=24*36e5,Br=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,Rm=90,wS=3,Ri=Object.freeze(["defect","design","requirements","style"]),j1=new Set(["A","B","E"]);L1={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};H1=/^revert\b|^revert "/i,dS=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,W1=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,q1=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;G1=[/(^|\/)\.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)\//];en=e=>Math.round(e*1e4)/1e4,_m=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import Mi from"node:fs/promises";import At from"node:path";import J1 from"node:os";import X1 from"node:net";import{randomUUID as Z1}from"node:crypto";import{execFile as Q1}from"node:child_process";import{promisify as eB}from"node:util";function iB(e){for(let t of Bm(e))if(!ES.test(t))return t;return null}function AS(e){let t=Bm(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function cB(e,t){let n=AS(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return At.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return At.resolve(e,n[r+1])}return e}function uB(e){let t=!1,n=!1;for(let r of Bm(e)){if(!t){if(ES.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&Om(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,Om(r))return`serves the filesystem root ("${r}")`;continue}if(Om(r))return`serves the filesystem root ("${r}")`;if(lB(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function fB(e,t){if(At.resolve(e)===At.resolve(t))return!0;let[n,r]=await Promise.all([bu(e),bu(t)]);return n===r}async function pB(e){let n=(await Mi.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 _S(At.join(e,o.name,Nm))?`./${o.name}`:null))).filter(Boolean)}async function mB(e,t){let[n,r]=await Promise.all([bu(e),bu(t)]),o=At.relative(n,r);if(o&&(o.startsWith("..")||At.isAbsolute(o)))throw Oi(`serve directory escapes the Track workspace: ${t}`)}async function hB(e,t){let n=uB(t);if(n)throw Oi(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await dB(e))throw Oi(`serve directory does not exist: ${e}`);let r=iB(t);if(!r)return;if(!r.includes("/")&&!await Ky(r,{loginShell:!0,failOpen:!0}))throw Oi(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(oB.test(t)||sB.has(r)||!rB.has(r)||!AS(t).includes("run")||aB.test(t))return;let o=cB(e,t);if(await _S(At.join(o,Nm)))return;let s=await pB(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Oi(`no ${Nm} in ${o}${a}`)}async function zn(){return yn||(Cm||=(async()=>{try{yn=JSON.parse(await Mi.readFile(TS,"utf8"))}catch{yn={views:[],adoptWatermarks:{}}}finally{Cm=null}return yn.views||=[],yn.adoptWatermarks||={},yn})(),Cm)}async function kn(){await Tt(TS,yn)}function Vn(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"view.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,payload:{ts:Date.now(),change:t,viewId:e.id,name:e.name,slug:e.slug,port:e.port,cmd:e.cmd||null,...n}}).catch(()=>{})}function Lm(e){return Ci.get(e)||null}function $S(e,{name:t,box:n}={}){let r=Ci.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 Ci.set(e,o),o}function Pm(e,t){let n=Ci.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function ku(e,{error:t=null}={}){let n=Ci.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function RS(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 Dm(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function wB(e,t){let n=Dm(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!vS.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!vS.has(s))return s}}function Ni(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=X1.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 Fm(e){if(process.platform!=="darwin"){await bn("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await bn("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 OS(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function gB(e,t){let n=new Set(e.views.map(o=>o.port)),r=OS();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=kS;o<=xS;o++)if(!(n.has(o)||r.has(o))&&!await Ni(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${kS}-${xS}`)}async function yB(e){try{let{stdout:t}=await bn(G,Y("list-sessions","-F","#{session_name}"));return t.split(`
198
+ `).some(n=>n.trim()===Ws(e))}catch{return!1}}async function Pi(e){try{await bn(G,Y("kill-session","-t",Ws(e)))}catch{}}async function Um(e){if(!await Wa())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=Ws(e.slug),n=e.serveCwd??e.cwd,r=At.dirname(process.execPath);await bn(G,Y("new-session","-d","-s",t,"-c",n)),await bn(G,Y("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await bn(G,Y("send-keys","-t",t,"Enter")),await bn(G,Y("send-keys","-t",t,"-l",e.cmd)),await bn(G,Y("send-keys","-t",t,"Enter"))}async function SS(e,t=12){try{let{stdout:n}=await bn(G,Y("capture-pane","-t",Ws(e),"-p"));return String(n||"").trimEnd().split(`
199
199
  `).filter(Boolean).slice(-t).join(`
200
- `)}catch{return""}}async function w1(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await m1(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await kS(e.slug)||"server exited before listening"),Gn.delete(e.id),await Vn(e,e.state,e.error?{error:e.error}:{}),!0}if(await Mi(e.port))return Gn.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await Vn(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>h1?(e.state="error",e.error=await kS(e.slug)||"never started listening",await Vn(e,"error",{error:e.error}),!0):!1;let o=(Gn.get(e.id)||0)+1;return Gn.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function bu(){if(!Cm){Cm=!0;try{let e=await zn(),t=!1;for(let n of e.views)await w1(n)&&(t=!0);t&&await kn()}finally{Cm=!1}}}async function ku({trackId:e}={}){await bu();let t=await zn();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function $S(e){let n=(await zn()).views.find(r=>r.id===e);return n?{...n}:null}function Um(e){return yn&&yn.views.find(t=>t.slug===e)||null}async function Hm({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=At.resolve(r,o??"."),f=i==="detected"?null:async()=>{await u1(r,u),await d1(u,n)},d=await zn();if(i!=="detected"){let w=Pm(t),g=String(n).trim(),k=d.views.find(S=>S.trackId===e&&(S.slug===w||Pm(S.name)===w||S.cmd===g&&At.resolve(S.serveCwd??S.cwd)===u));if(k)return g1(d,k,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:f})}if(f&&await f(),d.views.filter(w=>w.state==="live"||w.state==="starting").length>=Br)throw new Error(`view cap reached (${Br} live) \u2014 stop one first`);let h={id:zB().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:f1(d,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await p1(d,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await Fm(h),d.views.push(h),await kn(),await Vn(h,"created",{origin:i}),Nm(e,h.id),i==="detected"&&await Mi(h.port)&&(h.state="live",h.lastHealthyAt=Date.now(),await kn(),await Vn(h,"live")),{...h}}async function g1(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 c1(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await Mi(t.port))return await kn(),Nm(t.trackId,t.id),{...t,reused:!0};if(a&&await a(),e.views.filter(f=>f.id!==t.id&&(f.state==="live"||f.state==="starting")).length>=Br)throw new Error(`view cap reached (${Br} live) \u2014 stop one first`);return t.origin==="detected"?(await Lm(t.port),t.origin="agent"):await Ni(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),Gn.delete(t.id),await Fm(t),await kn(),await Vn(t,"created",{restarted:!0,reused:!0}),Nm(t.trackId,t.id),{...t,reused:!0}}async function RS(e){let n=(await zn()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await Lm(n.port):await Ni(n.slug),n.state!=="stopped"&&(n.state="stopped",Gn.delete(n.id),await kn(),await Vn(n,"stopped")),{...n}}async function OS(e){let t=await zn(),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>=Br)throw new Error(`view cap reached (${Br} live) \u2014 stop one first`);return await Ni(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),Gn.delete(n.id),await Fm(n),await kn(),await Vn(n,"created",{restarted:!0}),{...n}}async function CS(e){let t=await zn(),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 Lm(r.port):await Ni(r.slug),t.views.splice(n,1),Gn.delete(r.id),await kn(),await Vn(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function MS(e){let t=await zn(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await Ni(r.slug),Gn.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await kn()),n.length}async function NS(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await zn(),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 kn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(y1)){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(!IS().has(c)&&!n.views.some(l=>l.port===c)&&await Mi(c))try{i.push(await Hm({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 bn,XB,xS,gS,yS,Br,ZB,Hs,bS,Ri,QB,Mm,e1,t1,n1,Dm,vS,Rm,s1,i1,TS,gu,yn,Om,Oi,Bm,ES,Gn,h1,Cm,y1,xu=j(()=>{lt();me();cr();bn=JB(YB),XB=process.env.BOSTRAT_STATE_DIR||At.join(process.env.HOME||GB.tmpdir(),".bostrat"),xS=At.join(XB,"views.json"),[gS,yS]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),Br=Number(process.env.BOSTRAT_VIEW_MAX)||3,ZB="bostrat-view-",Hs=e=>`${ZB}${e}`,bS=new Set(["bostrat","www","api","views","app"]),Ri=e=>Object.assign(new Error(e),{status:400}),QB=new Set(["npm","pnpm","yarn","bun"]),Mm="package.json",e1=/[|;&`]|\$\(/,t1=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),n1=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,Dm=e=>String(e).trim().split(/\s+/).filter(Boolean),vS=/^[A-Za-z_][A-Za-z0-9_]*=/;Rm=e=>e==="/",s1=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");i1=e=>Ci.stat(e).then(t=>t.isDirectory(),()=>!1),TS=e=>Ci.stat(e).then(t=>t.isFile(),()=>!1),gu=e=>Ci.realpath(e).catch(()=>At.resolve(e));yn=null,Om=null;Oi=new Map,Bm=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,ES=12e3;Gn=new Map,h1=12e4;Cm=!1;y1=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function vu(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>k1?null:n}function x1(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function PS(e){let t=e?.workspace?.branch;if(!t)return;let n;try{n=await F(e)}catch{return}let r=vu(n);if(r==null)return;let o=(e.boxes||[]).find(u=>u.name===e.leadBox);if(await To(e.leadBox,o?.agent).catch(()=>!1))return;let s=Date.now();if(s-(Wm.get(e.id)||0)<b1)return;Wm.set(e.id,s);let a;try{a=await hn(e.cwd,{caller:"reconcile"})}catch{return}let i=await js(e).catch(()=>[t]),c=(a||[]).find(u=>i.includes(u.headRefName));if(!c)return;let l=await Se(e.cwd).catch(()=>null);if(l){let{link:u,created:f}=await Ot({repo:l,number:c.number,trackId:e.id,url:c.url,headRef:c.headRefName||t,title:c.title,source:"reconciled"});if(!f&&!(u?.trackId===e.id&&await Ln(l,c.number))){if(!x1(u,r))return;let d=await F(e).catch(()=>null);if(d&&vu(d)==null)return;await $(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"pushed",number:c.number,url:c.url,title:c.title,branch:t,repo:l}});return}}await $(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"opened",number:c.number,url:c.url,title:c.title,branch:t,...l?{repo:l}:{}}}).catch(()=>{}),Wm.delete(e.id)}var b1,Wm,k1,qm=j(()=>{me();Bs();ar();Fn();Si();Eo();b1=6e3,Wm=new Map,k1=30*6e4});import Km from"node:os";import{execFile as v1}from"node:child_process";import{promisify as S1}from"node:util";async function Su(){if(process.platform!=="darwin")return Km.freemem();try{let{stdout:e}=await T1("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:Km.freemem()}catch{return Km.freemem()}}var T1,Gm=j(()=>{T1=S1(v1)});import Ke from"node:fs/promises";import ze from"node:path";import LS from"node:os";import{randomUUID as E1}from"node:crypto";import{execFile as A1}from"node:child_process";import{promisify as _1}from"node:util";import{chromium as I1}from"playwright-core";async function Sn(){return Io||(Vm||=(async()=>{try{Io=JSON.parse(await Ke.readFile(US,"utf8"))}catch{Io={mocks:[]}}finally{Vm=null}return Io.mocks||=[],Io})(),Vm)}async function Ht(){await Tt(US,Io)}function KS(e,t){vn(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&vn(e,t.v,"png")}function yt(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"mock.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,mockId:e.id,name:e.name,...e.group?{group:e.group}:{},...e.kind==="video"?{kind:"video"}:{},...n}}).catch(()=>{})}function Wt(e,t){let n=Di(e.cwd);return{html:ze.join(n,`${e.id}.v${t}.html`),png:ze.join(n,`${e.id}.v${t}.png`)}}function Pi(e,t,n){if(!t)return null;let r=n==="html"?t.htmlRel:n==="png"?t.pngRel??t.posterRel??null:n==="video"?t.videoRel??null:null;return r?ze.join(e.cwd,r):null}function tn(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 Jm(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function Tu(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(P1)}function D1(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 B1(e){let t=Buffer.alloc(24),n=await Ke.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function j1({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 L1(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((h,w)=>{r.onload=h,r.onerror=()=>w(new Error("decode failed")),r.src=`data:image/png;base64,${n}`});let o=r.naturalWidth,s=r.naturalHeight;if(!o||!s||o*s>24e6)return null;let a=document.createElement("canvas");a.width=o,a.height=s;let i=a.getContext("2d",{willReadFrequently:!0});i.drawImage(r,0,0);let c=i.getImageData(0,0,o,s).data,l=[c[0],c[1],c[2]],u=o,f=s,d=-1,p=-1;for(let h=0;h<s;h++)for(let w=h*o*4,g=0;g<o;g++,w+=4)Math.abs(c[w]-l[0])+Math.abs(c[w+1]-l[1])+Math.abs(c[w+2]-l[2])>24&&(g<u&&(u=g),g>d&&(d=g),h<f&&(f=h),p=h);return d<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:f,right:d,bottom:p}}},t.toString("base64"))}async function F1(e,t,{bg:n,crop:r}){let o=await e.evaluate(async({b64:s,bg:a,crop:i})=>{let c=new Image;await new Promise((f,d)=>{c.onload=f,c.onerror=()=>d(new Error("decode failed")),c.src=`data:image/png;base64,${s}`});let l=document.createElement("canvas");l.width=i.outW,l.height=i.outH;let u=l.getContext("2d");return u.fillStyle=`rgb(${a[0]},${a[1]},${a[2]})`,u.fillRect(0,0,i.outW,i.outH),u.drawImage(c,i.sx,i.sy,i.sw,i.sh,i.dx,i.dy,i.sw,i.sh),l.toDataURL("image/png").split(",")[1]},{b64:t.toString("base64"),bg:n,crop:r});return Buffer.from(o,"base64")}async function U1({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await I1.launch({executablePath:HS,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:Ws})).newPage();a.setDefaultTimeout(qs),await a.goto(`file://${e}`,{waitUntil:"load",timeout:qs}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:qs});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await L1(a,i),u=l&&j1({...l,pad:O1*Ws,align:Ws});u&&(i=await F1(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<WS)throw new Ct(`capture produced a ${i.length}-byte image`);let c=Jm(i);if(!c)throw new Ct("output is not a PNG");return await Ke.writeFile(t,i),{width:Math.round(c.width/Ws),height:Math.round(c.height/Ws),dpr:Ws,renderMs:Date.now()-r}}catch(s){throw s instanceof Ct?s:new Ct(/timeout/i.test(s?.message||"")?`render timed out after ${qs}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function jS({htmlPath:e,outPath:t,width:n}){let r=await Ke.mkdtemp(ze.join(LS.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await Ym(DS,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:qs,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new Ct(`firefox not found (${DS})`,""):new Ct(c?.killed?`render timed out after ${qs}ms`:"firefox exited non-zero",s)}let a=await Ke.stat(t).catch(()=>null);if(!a||a.size<WS)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=Jm(await B1(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 Ke.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function H1(e){if($1==="firefox")return jS(e);try{return await U1(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await jS(e)}catch(n){throw/not found/.test(n?.message||"")?new Ct(`no browser installed \u2014 chromium missing at ${HS} 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 GS(e){return zm=zm.then(e,e),zm}async function VS(e,t){let n=await Sn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Ht(),await yt(r,"rendering",{version:t});try{let o=await Su();if(o<C1)throw new Ct(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=Wt(r,t),a=await W1({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await Ke.rm(s.png,{force:!0}).catch(()=>{});return}Xm(r,{v:t,source:"html",htmlRel:ze.relative(r.cwd,s.html),pngRel:ze.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Ht(),await yt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),xn(r),vn(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Ht(),await yt(r,"error",{version:t,error:r.error}),xn(r)}}}function Xm(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 q1({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?R1:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function Bi({trackId:e,group:t}={}){let n=await Sn(),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 Yn(e){let n=(await Sn()).mocks.find(r=>r.id===e);return n?{...n}:null}function zS({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&&!Tu(t))throw new Error("image must be a PNG");if(n){let o=D1(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>BS)throw new Error(`video must be ${BS/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function YS({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let f=q1({trackId:e,name:t,cwd:s,width:a}),d=typeof n=="string"&&n.trim(),p=zS({html:n,image:r,video:o}),h=await Sn(),w={id:E1().slice(0,8),trackId:e,box:c||null,agent:l||null,name:t.trim(),prompt:u?String(u).slice(0,500):null,group:i?String(i).trim():null,cwd:s,width:f,height:null,dpr:null,state:"queued",source:d?"html":o?"video":"image",kind:o?"video":"image",version:1,readyVersion:null,versions:[],error:null,renderMs:null,createdAt:Date.now(),updatedAt:Date.now()};return await Ke.mkdir(Di(s),{recursive:!0}),h.mocks.push(w),d?(await Ke.writeFile(Wt(w,1).html,n),await Ht(),await yt(w,"created"),xn(w),vn(w,1,"html"),GS(()=>VS(w.id,1))):o?(await XS(w,1,o,p),await Ht(),await yt(w,"created"),await yt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr,durationS:w.versions[0]?.durationS??null}),xn(w),KS(w,w.versions[0])):(await ZS(w,1,r),await Ht(),await yt(w,"created"),await yt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr}),xn(w),vn(w,1,"png")),{...w}}async function JS(e,{html:t,image:n,video:r,width:o}={}){let a=(await Sn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=zS({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 Ke.mkdir(Di(a.cwd),{recursive:!0}),i?(a.state="queued",await Ke.writeFile(Wt(a,l).html,t),await Ht(),await yt(a,"updated",{version:l}),xn(a),vn(a,l,"html"),GS(()=>VS(a.id,l))):r?(await XS(a,l,r,c),await Ht(),await yt(a,"updated",{version:l}),await yt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:tn(a)?.durationS??null}),xn(a),KS(a,a.versions.find(u=>u.v===l))):(await ZS(a,l,n),await Ht(),await yt(a,"updated",{version:l}),await yt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),xn(a),vn(a,l,"png")),{...a}}async function K1(e){try{let{stdout:t}=await Ym(M1,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:qS,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 G1(e,t){try{await Ym(N1,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:qS,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Ke.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function XS(e,t,n,r){let o=Di(e.cwd),s=ze.join(o,`${e.id}.v${t}.${r.ext}`),a=ze.join(o,`${e.id}.v${t}.poster.png`);await Ke.writeFile(s,n);let i=await K1(s),c=await G1(s,a);Xm(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:ze.relative(e.cwd,s),posterRel:c?ze.relative(e.cwd,a):null,mimeType:r.mime,bytes:n.length,durationS:i?.durationS??null,width:i?.width??null,height:i?.height??null,dpr:1,renderMs:null,createdAt:Date.now()}),i?.width&&(e.width=i.width)}async function ZS(e,t,n){let r=Jm(n);if(!r)throw new Error("image must be a PNG");let o=Wt(e,t);await Ke.writeFile(o.png,n),Xm(e,{v:t,source:"image",htmlRel:null,pngRel:ze.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function QS(e){let t=await Sn(),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 yt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function eT(e){let t=await Sn(),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=Wt(r,o);await Ke.rm(s.html,{force:!0}).catch(()=>{}),await Ke.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Ke.rm(ze.join(r.cwd,s),{force:!0}).catch(()=>{});return await Ht(),await yt(r,"deleted"),Vt("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function tT(e){let n=(await Sn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=ze.join(FS,"mock-archive",e.id),o=Di(e.cwd),s=ze.join(r,".bostrat","mocks");await Ke.mkdir(s,{recursive:!0});let a=await Ke.readdir(o).catch(()=>[]);for(let i of a)await Ke.copyFile(ze.join(o,i),ze.join(s,i));for(let i of n){for(let c of i.versions||[])for(let l of[c.htmlRel,c.pngRel,c.videoRel,c.posterRel]){if(!l)continue;if(!(await Ke.stat(ze.join(r,l)).catch(()=>null))?.isFile())throw new Error(`mock evacuation incomplete: ${l} missing from the archive`)}i.cwd=r,i.trackDeletedAt=Date.now(),i.trackName=e.name||e.id,i.updatedAt=Date.now(),xn(i)}return await Ht(),n.length}async function nT(e){let t=await Sn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Ht();for(let r of n)Vt("mocks",r.id).catch(()=>{})}return n.length}async function rT(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Sn();for(let r of n.mocks){await xn(r);for(let o of r.versions||[])o.htmlRel&&await vn(r,o.v,"html"),(o.pngRel||o.posterRel)&&await vn(r,o.v,"png"),o.videoRel&&await vn(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var Ym,FS,US,$1,HS,DS,R1,Ws,O1,WS,qs,C1,BS,M1,N1,qS,Ct,Io,Vm,xn,vn,Di,P1,W1,zm,Ks=j(()=>{me();cr();Gm();ur();Ym=_1(A1),FS=process.env.BOSTRAT_STATE_DIR||ze.join(process.env.HOME||LS.tmpdir(),".bostrat"),US=ze.join(FS,"mocks.json"),$1=process.env.BOSTRAT_MOCK_ENGINE||"chromium",HS=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",DS=process.env.BOSTRAT_FIREFOX_BIN||"firefox",R1=1300,Ws=2,O1=32,WS=1500,qs=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,C1=700*1024*1024,BS=100*1024*1024,M1=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",N1=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",qS=2e4,Ct=class extends Error{constructor(t,n=""){super(n?`${t}
200
+ `)}catch{return""}}async function kB(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await yB(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await SS(e.slug)||"server exited before listening"),Gn.delete(e.id),await Vn(e,e.state,e.error?{error:e.error}:{}),!0}if(await Ni(e.port))return Gn.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await Vn(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>bB?(e.state="error",e.error=await SS(e.slug)||"never started listening",await Vn(e,"error",{error:e.error}),!0):!1;let o=(Gn.get(e.id)||0)+1;return Gn.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function xu(){if(!Mm){Mm=!0;try{let e=await zn(),t=!1;for(let n of e.views)await kB(n)&&(t=!0);t&&await kn()}finally{Mm=!1}}}async function vu({trackId:e}={}){await xu();let t=await zn();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function CS(e){let n=(await zn()).views.find(r=>r.id===e);return n?{...n}:null}function Hm(e){return yn&&yn.views.find(t=>t.slug===e)||null}async function Wm({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=At.resolve(r,o??"."),f=i==="detected"?null:async()=>{await mB(r,u),await hB(u,n)},d=await zn();if(i!=="detected"){let w=Dm(t),g=String(n).trim(),b=d.views.find(E=>E.trackId===e&&(E.slug===w||Dm(E.name)===w||E.cmd===g&&At.resolve(E.serveCwd??E.cwd)===u));if(b)return xB(d,b,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:f})}if(f&&await f(),d.views.filter(w=>w.state==="live"||w.state==="starting").length>=jr)throw new Error(`view cap reached (${jr} live) \u2014 stop one first`);let h={id:Z1().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:wB(d,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await gB(d,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await Um(h),d.views.push(h),await kn(),await Vn(h,"created",{origin:i}),Pm(e,h.id),i==="detected"&&await Ni(h.port)&&(h.state="live",h.lastHealthyAt=Date.now(),await kn(),await Vn(h,"live")),{...h}}async function xB(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 fB(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await Ni(t.port))return await kn(),Pm(t.trackId,t.id),{...t,reused:!0};if(a&&await a(),e.views.filter(f=>f.id!==t.id&&(f.state==="live"||f.state==="starting")).length>=jr)throw new Error(`view cap reached (${jr} live) \u2014 stop one first`);return t.origin==="detected"?(await Fm(t.port),t.origin="agent"):await Pi(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),Gn.delete(t.id),await Um(t),await kn(),await Vn(t,"created",{restarted:!0,reused:!0}),Pm(t.trackId,t.id),{...t,reused:!0}}async function MS(e){let n=(await zn()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await Fm(n.port):await Pi(n.slug),n.state!=="stopped"&&(n.state="stopped",Gn.delete(n.id),await kn(),await Vn(n,"stopped")),{...n}}async function NS(e){let t=await zn(),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>=jr)throw new Error(`view cap reached (${jr} live) \u2014 stop one first`);return await Pi(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),Gn.delete(n.id),await Um(n),await kn(),await Vn(n,"created",{restarted:!0}),{...n}}async function PS(e){let t=await zn(),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 Fm(r.port):await Pi(r.slug),t.views.splice(n,1),Gn.delete(r.id),await kn(),await Vn(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function DS(e){let t=await zn(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await Pi(r.slug),Gn.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await kn()),n.length}async function BS(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await zn(),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 kn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(vB)){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(!OS().has(c)&&!n.views.some(l=>l.port===c)&&await Ni(c))try{i.push(await Wm({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 bn,tB,TS,kS,xS,jr,nB,Ws,vS,Oi,rB,Nm,oB,sB,aB,Bm,ES,Om,lB,dB,_S,bu,yn,Cm,Ci,jm,IS,Gn,bB,Mm,vB,Su=L(()=>{lt();he();lr();bn=eB(Q1),tB=process.env.BOSTRAT_STATE_DIR||At.join(process.env.HOME||J1.tmpdir(),".bostrat"),TS=At.join(tB,"views.json"),[kS,xS]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),jr=Number(process.env.BOSTRAT_VIEW_MAX)||3,nB="bostrat-view-",Ws=e=>`${nB}${e}`,vS=new Set(["bostrat","www","api","views","app"]),Oi=e=>Object.assign(new Error(e),{status:400}),rB=new Set(["npm","pnpm","yarn","bun"]),Nm="package.json",oB=/[|;&`]|\$\(/,sB=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),aB=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,Bm=e=>String(e).trim().split(/\s+/).filter(Boolean),ES=/^[A-Za-z_][A-Za-z0-9_]*=/;Om=e=>e==="/",lB=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");dB=e=>Mi.stat(e).then(t=>t.isDirectory(),()=>!1),_S=e=>Mi.stat(e).then(t=>t.isFile(),()=>!1),bu=e=>Mi.realpath(e).catch(()=>At.resolve(e));yn=null,Cm=null;Ci=new Map,jm=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,IS=12e3;Gn=new Map,bB=12e4;Mm=!1;vB=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function Tu(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>TB?null:n}function EB(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function jS(e){let t=e?.workspace?.branch;if(!t)return;let n;try{n=await U(e)}catch{return}let r=Tu(n);if(r==null)return;let o=(e.boxes||[]).find(u=>u.name===e.leadBox);if(await To(e.leadBox,o?.agent).catch(()=>!1))return;let s=Date.now();if(s-(qm.get(e.id)||0)<SB)return;qm.set(e.id,s);let a;try{a=await hn(e.cwd,{caller:"reconcile"})}catch{return}let i=await Ls(e).catch(()=>[t]),c=(a||[]).find(u=>i.includes(u.headRefName));if(!c)return;let l=await Se(e.cwd).catch(()=>null);if(l){let{link:u,created:f}=await Ot({repo:l,number:c.number,trackId:e.id,url:c.url,headRef:c.headRefName||t,title:c.title,source:"reconciled"});if(!f&&!(u?.trackId===e.id&&await Ln(l,c.number))){if(!EB(u,r))return;let d=await U(e).catch(()=>null);if(d&&Tu(d)==null)return;await $(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"pushed",number:c.number,url:c.url,title:c.title,branch:t,repo:l}});return}}await $(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"opened",number:c.number,url:c.url,title:c.title,branch:t,...l?{repo:l}:{}}}).catch(()=>{}),qm.delete(e.id)}var SB,qm,TB,Km=L(()=>{he();js();ir();Fn();Ti();Eo();SB=6e3,qm=new Map,TB=30*6e4});import Gm from"node:os";import{execFile as AB}from"node:child_process";import{promisify as _B}from"node:util";async function Eu(){if(process.platform!=="darwin")return Gm.freemem();try{let{stdout:e}=await IB("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:Gm.freemem()}catch{return Gm.freemem()}}var IB,Vm=L(()=>{IB=_B(AB)});import Ke from"node:fs/promises";import ze from"node:path";import HS from"node:os";import{randomUUID as $B}from"node:crypto";import{execFile as RB}from"node:child_process";import{promisify as OB}from"node:util";import{chromium as CB}from"playwright-core";async function Sn(){return Io||(zm||=(async()=>{try{Io=JSON.parse(await Ke.readFile(qS,"utf8"))}catch{Io={mocks:[]}}finally{zm=null}return Io.mocks||=[],Io})(),zm)}async function Ht(){await Tt(qS,Io)}function zS(e,t){vn(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&vn(e,t.v,"png")}function yt(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"mock.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,mockId:e.id,name:e.name,...e.group?{group:e.group}:{},...e.kind==="video"?{kind:"video"}:{},...n}}).catch(()=>{})}function Wt(e,t){let n=Bi(e.cwd);return{html:ze.join(n,`${e.id}.v${t}.html`),png:ze.join(n,`${e.id}.v${t}.png`)}}function Di(e,t,n){if(!t)return null;let r=n==="html"?t.htmlRel:n==="png"?t.pngRel??t.posterRel??null:n==="video"?t.videoRel??null:null;return r?ze.join(e.cwd,r):null}function tn(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 Xm(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function Au(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(LB)}function FB(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 UB(e){let t=Buffer.alloc(24),n=await Ke.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function HB({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 WB(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((h,w)=>{r.onload=h,r.onerror=()=>w(new Error("decode failed")),r.src=`data:image/png;base64,${n}`});let o=r.naturalWidth,s=r.naturalHeight;if(!o||!s||o*s>24e6)return null;let a=document.createElement("canvas");a.width=o,a.height=s;let i=a.getContext("2d",{willReadFrequently:!0});i.drawImage(r,0,0);let c=i.getImageData(0,0,o,s).data,l=[c[0],c[1],c[2]],u=o,f=s,d=-1,p=-1;for(let h=0;h<s;h++)for(let w=h*o*4,g=0;g<o;g++,w+=4)Math.abs(c[w]-l[0])+Math.abs(c[w+1]-l[1])+Math.abs(c[w+2]-l[2])>24&&(g<u&&(u=g),g>d&&(d=g),h<f&&(f=h),p=h);return d<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:f,right:d,bottom:p}}},t.toString("base64"))}async function qB(e,t,{bg:n,crop:r}){let o=await e.evaluate(async({b64:s,bg:a,crop:i})=>{let c=new Image;await new Promise((f,d)=>{c.onload=f,c.onerror=()=>d(new Error("decode failed")),c.src=`data:image/png;base64,${s}`});let l=document.createElement("canvas");l.width=i.outW,l.height=i.outH;let u=l.getContext("2d");return u.fillStyle=`rgb(${a[0]},${a[1]},${a[2]})`,u.fillRect(0,0,i.outW,i.outH),u.drawImage(c,i.sx,i.sy,i.sw,i.sh,i.dx,i.dy,i.sw,i.sh),l.toDataURL("image/png").split(",")[1]},{b64:t.toString("base64"),bg:n,crop:r});return Buffer.from(o,"base64")}async function KB({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await CB.launch({executablePath:KS,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:qs})).newPage();a.setDefaultTimeout(Ks),await a.goto(`file://${e}`,{waitUntil:"load",timeout:Ks}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:Ks});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await WB(a,i),u=l&&HB({...l,pad:PB*qs,align:qs});u&&(i=await qB(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<GS)throw new Ct(`capture produced a ${i.length}-byte image`);let c=Xm(i);if(!c)throw new Ct("output is not a PNG");return await Ke.writeFile(t,i),{width:Math.round(c.width/qs),height:Math.round(c.height/qs),dpr:qs,renderMs:Date.now()-r}}catch(s){throw s instanceof Ct?s:new Ct(/timeout/i.test(s?.message||"")?`render timed out after ${Ks}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function US({htmlPath:e,outPath:t,width:n}){let r=await Ke.mkdtemp(ze.join(HS.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await Jm(LS,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:Ks,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new Ct(`firefox not found (${LS})`,""):new Ct(c?.killed?`render timed out after ${Ks}ms`:"firefox exited non-zero",s)}let a=await Ke.stat(t).catch(()=>null);if(!a||a.size<GS)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=Xm(await UB(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 Ke.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function GB(e){if(MB==="firefox")return US(e);try{return await KB(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await US(e)}catch(n){throw/not found/.test(n?.message||"")?new Ct(`no browser installed \u2014 chromium missing at ${KS} 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 YS(e){return Ym=Ym.then(e,e),Ym}async function JS(e,t){let n=await Sn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Ht(),await yt(r,"rendering",{version:t});try{let o=await Eu();if(o<DB)throw new Ct(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=Wt(r,t),a=await VB({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await Ke.rm(s.png,{force:!0}).catch(()=>{});return}Zm(r,{v:t,source:"html",htmlRel:ze.relative(r.cwd,s.html),pngRel:ze.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Ht(),await yt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),xn(r),vn(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Ht(),await yt(r,"error",{version:t,error:r.error}),xn(r)}}}function Zm(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 zB({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?NB:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function ji({trackId:e,group:t}={}){let n=await Sn(),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 Yn(e){let n=(await Sn()).mocks.find(r=>r.id===e);return n?{...n}:null}function XS({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&&!Au(t))throw new Error("image must be a PNG");if(n){let o=FB(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>FS)throw new Error(`video must be ${FS/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function ZS({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let f=zB({trackId:e,name:t,cwd:s,width:a}),d=typeof n=="string"&&n.trim(),p=XS({html:n,image:r,video:o}),h=await Sn(),w={id:$B().slice(0,8),trackId:e,box:c||null,agent:l||null,name:t.trim(),prompt:u?String(u).slice(0,500):null,group:i?String(i).trim():null,cwd:s,width:f,height:null,dpr:null,state:"queued",source:d?"html":o?"video":"image",kind:o?"video":"image",version:1,readyVersion:null,versions:[],error:null,renderMs:null,createdAt:Date.now(),updatedAt:Date.now()};return await Ke.mkdir(Bi(s),{recursive:!0}),h.mocks.push(w),d?(await Ke.writeFile(Wt(w,1).html,n),await Ht(),await yt(w,"created"),xn(w),vn(w,1,"html"),YS(()=>JS(w.id,1))):o?(await eT(w,1,o,p),await Ht(),await yt(w,"created"),await yt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr,durationS:w.versions[0]?.durationS??null}),xn(w),zS(w,w.versions[0])):(await tT(w,1,r),await Ht(),await yt(w,"created"),await yt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr}),xn(w),vn(w,1,"png")),{...w}}async function QS(e,{html:t,image:n,video:r,width:o}={}){let a=(await Sn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=XS({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 Ke.mkdir(Bi(a.cwd),{recursive:!0}),i?(a.state="queued",await Ke.writeFile(Wt(a,l).html,t),await Ht(),await yt(a,"updated",{version:l}),xn(a),vn(a,l,"html"),YS(()=>JS(a.id,l))):r?(await eT(a,l,r,c),await Ht(),await yt(a,"updated",{version:l}),await yt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:tn(a)?.durationS??null}),xn(a),zS(a,a.versions.find(u=>u.v===l))):(await tT(a,l,n),await Ht(),await yt(a,"updated",{version:l}),await yt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),xn(a),vn(a,l,"png")),{...a}}async function YB(e){try{let{stdout:t}=await Jm(BB,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:VS,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 JB(e,t){try{await Jm(jB,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:VS,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Ke.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function eT(e,t,n,r){let o=Bi(e.cwd),s=ze.join(o,`${e.id}.v${t}.${r.ext}`),a=ze.join(o,`${e.id}.v${t}.poster.png`);await Ke.writeFile(s,n);let i=await YB(s),c=await JB(s,a);Zm(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:ze.relative(e.cwd,s),posterRel:c?ze.relative(e.cwd,a):null,mimeType:r.mime,bytes:n.length,durationS:i?.durationS??null,width:i?.width??null,height:i?.height??null,dpr:1,renderMs:null,createdAt:Date.now()}),i?.width&&(e.width=i.width)}async function tT(e,t,n){let r=Xm(n);if(!r)throw new Error("image must be a PNG");let o=Wt(e,t);await Ke.writeFile(o.png,n),Zm(e,{v:t,source:"image",htmlRel:null,pngRel:ze.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function nT(e){let t=await Sn(),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 yt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function rT(e){let t=await Sn(),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=Wt(r,o);await Ke.rm(s.html,{force:!0}).catch(()=>{}),await Ke.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Ke.rm(ze.join(r.cwd,s),{force:!0}).catch(()=>{});return await Ht(),await yt(r,"deleted"),Vt("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function oT(e){let n=(await Sn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=ze.join(WS,"mock-archive",e.id),o=Bi(e.cwd),s=ze.join(r,".bostrat","mocks");await Ke.mkdir(s,{recursive:!0});let a=await Ke.readdir(o).catch(()=>[]);for(let i of a)await Ke.copyFile(ze.join(o,i),ze.join(s,i));for(let i of n){for(let c of i.versions||[])for(let l of[c.htmlRel,c.pngRel,c.videoRel,c.posterRel]){if(!l)continue;if(!(await Ke.stat(ze.join(r,l)).catch(()=>null))?.isFile())throw new Error(`mock evacuation incomplete: ${l} missing from the archive`)}i.cwd=r,i.trackDeletedAt=Date.now(),i.trackName=e.name||e.id,i.updatedAt=Date.now(),xn(i)}return await Ht(),n.length}async function sT(e){let t=await Sn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Ht();for(let r of n)Vt("mocks",r.id).catch(()=>{})}return n.length}async function aT(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Sn();for(let r of n.mocks){await xn(r);for(let o of r.versions||[])o.htmlRel&&await vn(r,o.v,"html"),(o.pngRel||o.posterRel)&&await vn(r,o.v,"png"),o.videoRel&&await vn(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var Jm,WS,qS,MB,KS,LS,NB,qs,PB,GS,Ks,DB,FS,BB,jB,VS,Ct,Io,zm,xn,vn,Bi,LB,VB,Ym,Gs=L(()=>{he();lr();Vm();dr();Jm=OB(RB),WS=process.env.BOSTRAT_STATE_DIR||ze.join(process.env.HOME||HS.tmpdir(),".bostrat"),qS=ze.join(WS,"mocks.json"),MB=process.env.BOSTRAT_MOCK_ENGINE||"chromium",KS=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",LS=process.env.BOSTRAT_FIREFOX_BIN||"firefox",NB=1300,qs=2,PB=32,GS=1500,Ks=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,DB=700*1024*1024,FS=100*1024*1024,BB=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",jB=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",VS=2e4,Ct=class extends Error{constructor(t,n=""){super(n?`${t}
201
201
  ${n.trim().split(`
202
202
  `).slice(-6).join(`
203
- `)}`:t),this.name="MockRenderError"}},Io=null,Vm=null;xn=e=>wt("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),vn=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?Pi(e,r,"video"):r&&Pi(e,r,n)||(n==="html"?Wt(e,t).html:null);return o?lr("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};Di=e=>ze.join(e,".bostrat","mocks");P1=Buffer.from([137,80,78,71,13,10,26,10]);W1=H1,zm=Promise.resolve()});import V1 from"node:fs/promises";import cT from"node:path";import z1 from"node:os";import{randomUUID as lT}from"node:crypto";async function Xn(){return Jn||(Zm||=(async()=>{let e=!0;try{Jn=JSON.parse(await V1.readFile(uT,"utf8"))}catch{Jn={flows:[]},e=!1}finally{Zm=null}if(Jn.flows||=[],!e&&Ne()){let{records:t,source:n}=await et("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&Jn.flows.push(r.data);Jn.flows.length&&await Gs().catch(()=>{})}}return Jn})(),Zm)}async function Gs(){await Tt(uT,Jn)}function Qm(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"flow.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,flowId:e.id,name:e.name,stepCount:e.steps.length,mockIds:[...new Set(e.steps.map(r=>r.mockId))],...n}}).catch(()=>{})}async function dT({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>oT)throw new Error(`steps must be an array of 1-${oT}`);let r=await Bi({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>aT)throw new Error(`${l}: caption over ${aT} chars`);let f=c.title==null?null:String(c.title).trim()||null;if(f&&f.length>iT)throw new Error(`${l}: title over ${iT} chars`);let d=String(c.mock??"").trim().replace(/^mock:/,"");if(!d)throw new Error(`${l}: mock (name or id) required`);let p=r.filter(S=>S.id===d);if(p.length||(p=r.filter(S=>S.name.toLowerCase()===d.toLowerCase())),!p.length)throw new Error(`${l}: no mock matching "${d}" in this Track \u2014 see \`bostrat-mock ls\``);if(p.length>1)throw new Error(`${l}: "${d}" is ambiguous (${p.map(S=>`mock:${S.id}`).join(", ")}) \u2014 use the id`);let h=p[0],w=null;if(c.v!=null&&(w=Number(c.v),!Number.isInteger(w)||!(h.versions||[]).some(S=>S.v===w)))throw new Error(`${l}: "${h.name}" has no captured v${c.v} to pin`);let g=o.findIndex(S=>S.mockId===h.id),k=g>=0?o.splice(g,1)[0].id:lT().slice(0,8);s.push({id:k,mockId:h.id,caption:u,title:f,v:w})}let a={};for(let i of s)i.mockId in a||(a[i.mockId]=r.find(c=>c.id===i.mockId)?.readyVersion??null);return{steps:s,resolved:a}}function J1(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>sT)throw new Error(`name over ${sT} chars`);return e.trim()}async function fT({trackId:e}={}){let t=await Xn();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function X1(e){let n=(await Xn()).flows.find(r=>r.id===e);return n?{...n}:null}async function pT(e){let t=await X1(e);if(!t)return null;let n=new Map((await Bi({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=tn(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 mT({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=J1(t),i=await Xn(),c=i.flows.find(p=>p.trackId===e&&p.name.toLowerCase()===a.toLowerCase());if(c)throw new Error(`flow "${c.name}" already exists in this Track (flow:${c.id}) \u2014 revise it with \`bostrat-flow update\``);let{steps:l,resolved:u}=await dT({trackId:e,steps:n}),f=Date.now(),d={id:lT().slice(0,8),trackId:e,box:o||null,agent:s||null,name:a,cwd:r,version:1,versions:[{v:1,steps:l,resolved:u,note:null,createdAt:f}],steps:l,createdAt:f,updatedAt:f};return i.flows.push(d),await Gs(),await Qm(d,"created"),Eu(d),{...d}}async function hT(e,{steps:t,note:n}={}){let o=(await Xn()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await dT({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 Gs(),await Qm(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),Eu(o),{...o}}async function wT(e){let t=await Xn(),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 Gs(),await Qm(r,"deleted"),Vt("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function gT(e){return(await Xn()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function yT(e){let n=(await Xn()).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(),Eu(r);return n.length&&await Gs(),n.length}async function bT(e){let t=await Xn(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await Gs();for(let r of n)Vt("flows",r.id).catch(()=>{})}return n.length}async function kT(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Xn();for(let r of n.flows)await Eu(r);return{pushed:n.flows.length,source:"plane"}}var Y1,uT,oT,sT,aT,iT,Jn,Zm,Eu,eh=j(()=>{me();cr();Ks();ur();Y1=process.env.BOSTRAT_STATE_DIR||cT.join(process.env.HOME||z1.tmpdir(),".bostrat"),uT=cT.join(Y1,"flows.json"),oT=20,sT=80,aT=500,iT=80,Jn=null,Zm=null;Eu=e=>wt("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import er from"node:fs/promises";import tr from"node:path";import Z1 from"node:os";import{randomUUID as Q1}from"node:crypto";function ji(e){return ej.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function Tn(){return Zn||(th||=(async()=>{let e=!0;try{Zn=JSON.parse(await er.readFile(vT,"utf8"))}catch{Zn={runbooks:[]},e=!1}finally{th=null}return Zn.runbooks||=[],!e&&Ne()&&await tj().catch(()=>{}),Zn})(),th)}async function Ro(){await Tt(vT,Zn)}function _u(e){return Li(wt("runbooks",{...e},{trackId:e.trackId}))}async function tj(){let{records:e,source:t}=await et("runbooks");if(!(t!=="plane"||!e.length)){await er.mkdir(Au,{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 Pa("runbooks",r.id,o.v,"md");typeof s=="string"&&await er.writeFile(Qn(r,o.v),s).catch(()=>{})}Zn.runbooks.push(r)}Zn.runbooks.length&&await Ro()}}function Vs(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"runbook.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,runbookId:e.id,name:e.name,status:e.status,...n}}).catch(()=>{})}function Qn(e,t){return tr.join(Au,`${e.id}.v${t}.md`)}function ST(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 TT(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>xT)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${xT/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=ji(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 nj(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function rj({trackId:e,status:t}={}){let n=await Tn(),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 ET({trackId:e,status:t}={}){let n=await Tn(),r=await rj({trackId:e,status:t});if(!Ne())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await et("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 nh(e){let t=await oj(e);if(t)return t;if(!Ne())return null;let{records:n,source:r}=await et("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 AT(e,t){let n=await Pa("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function oj(e){let n=(await Tn()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function _T({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=TT(r),c=await Tn(),l={id:Q1().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 er.mkdir(Au,{recursive:!0}),await er.writeFile(Qn(l,1),r),l.versions.push({v:1,mdRel:tr.relative($o,Qn(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await Ro(),await Vs(l,"created",{version:1}),_u(l),Li(lr("runbooks",l.id,1,"md",Qn(l,1))),{...l}}async function IT(e,{md:t,note:n}={}){let o=(await Tn()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");nj(o,"update");let s=TT(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await er.mkdir(Au,{recursive:!0}),await er.writeFile(Qn(o,a),t),o.versions.push({v:a,mdRel:tr.relative($o,Qn(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await Ro(),await Vs(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),_u(o),Li(lr("runbooks",o.id,a,"md",Qn(o,a))),{...o}}async function $T(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await Tn()).runbooks.find(o=>o.id===e);if(!r)throw new Error("runbook not found");return r.status===t?{...r}:(r.status=t,r.updatedAt=Date.now(),await Ro(),await Vs(r,t==="done"?"done":"reopened"),_u(r),{...r})}async function RT(e){let t=await Tn(),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 er.rm(tr.join($o,o.mdRel),{force:!0}).catch(()=>{});return await Ro(),r.trackDeletedAt||await Vs(r,"deleted"),Li(Vt("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function OT(e){let n=(await Tn()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await Vs(r,"orphaned"),r.cwd=null,_u(r);return n.length&&await Ro(),n.length}async function CT(e){let t=await Tn(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await Vs(r,"deleted");for(let o of r.versions||[])await er.rm(tr.join($o,o.mdRel),{force:!0}).catch(()=>{});Li(Vt("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await Ro()),n.length}async function MT(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Tn();for(let r of n.runbooks){await wt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await lr("runbooks",r.id,o.v,"md",tr.join($o,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var $o,vT,Au,xT,ej,Zn,th,Li,Iu=j(()=>{cr();me();ur();$o=process.env.BOSTRAT_STATE_DIR||tr.join(process.env.HOME||Z1.tmpdir(),".bostrat"),vT=tr.join($o,"runbooks.json"),Au=tr.join($o,"runbooks"),xT=256*1024,ej=[{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/}];Zn=null,th=null;Li=e=>Promise.resolve(e).catch(()=>{})});import rh from"node:fs/promises";import Fi from"node:path";import{randomUUID as sj}from"node:crypto";function sh(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return aj.has(t)?"image":ij.has(t)?"doc":null}function cj(e){let r=Fi.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 DT(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>NT)throw new Error(`file too large \u2014 max ${Math.floor(NT/(1024*1024))} MB`);let r=cj(t),o=Fi.extname(r).slice(1),s=sh(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=sj().slice(0,8),i=oh(e);await rh.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await rh.writeFile(Fi.join(i,c),n,{mode:384}),await rh.chmod(Fi.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${PT}/${c}`,kind:s,size:n.length}}function BT(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function ah(e){return e.role==="user"&&lj.test((e.text||"").trim())}var PT,oh,NT,aj,ij,lj,ih=j(()=>{PT=".bostrat/uploads",oh=e=>Fi.join(e,PT),NT=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,aj=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),ij=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"]);lj=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function Oo(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}var jT=j(()=>{});import{execFile as uj}from"node:child_process";import{promisify as dj}from"node:util";function ch(e){return`refs/bostrat/wip/${e}`}function mj(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function UT(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function hj(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:pj}async function lh(e,{log:t=console,force:n=!1}={}){let{id:r,cwd:o}=e??{};if(!r||!o)return{pushed:!1,reason:"no-workspace"};try{await jr(o,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await jr(o,["remote","get-url","origin"])}catch{return LT.has(o)||(LT.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 As(o,"bostrat: wip snapshot"),{stdout:a}=await jr(o,["rev-parse",`${s}^{tree}`]),i=a.trim();if(!n&&$u.get(o)===i)return{pushed:!1,reason:"unchanged"};let c=ch(r);return await jr(o,["push","--force","origin",`${s}:${c}`],FT),$u.set(o,i),await $(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(`
204
- `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function uh(e,{log:t=console}={}){let{id:n,cwd:r}=e??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await jr(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await jr(r,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let o=await As(r,"bostrat: transfer rescue snapshot"),{stdout:s}=await jr(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if($u.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=mj(n);return await jr(r,["push","origin",`${o}:${i}`],FT),$u.set(r,a),await $(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(`
205
- `)[0]}`),{pushed:!1,reason:"push-failed"}}}function HT({listTracks:e,sweepMs:t=hj(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)Ve(i)||i?.kind==="setup"||await lh(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 fj,pj,FT,jr,$u,LT,dh=j(()=>{Pl();me();Bn();fj=dj(uj),pj=12e4,FT=6e4;jr=(e,t,n=15e3)=>fj("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),$u=new Map,LT=new Set});import wj from"node:fs";import fh from"node:fs/promises";import gj from"node:path";function xj(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function WT(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(!xj(t))return{restored:!1,reason:"plane not configured"};let s=ts(e),a=gj.join(s,`${o}.ndjson`);try{if(wj.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=Ie(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let d=new AbortController,p=setTimeout(()=>d.abort(),kj),h;try{h=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${yj}`,{headers:c,signal:d.signal})}finally{clearTimeout(p)}if(h.status===404)return{restored:!1,reason:"unknown to plane"};if(!h.ok)return{restored:!1,reason:`plane ${h.status}`};let w=await h.json();for(let g of w.events||[])l.push(JSON.stringify(g));if(l.length>bj)return{restored:!1,reason:"event count over safety cap"};if(w.next==null)break;u=w.next}if(!l.length)return{restored:!1,reason:"unknown to plane"};await fh.mkdir(s,{recursive:!0});let f=`${a}.pull-${process.pid}-${Date.now()}`;return await fh.writeFile(f,l.join(`
203
+ `)}`:t),this.name="MockRenderError"}},Io=null,zm=null;xn=e=>wt("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),vn=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?Di(e,r,"video"):r&&Di(e,r,n)||(n==="html"?Wt(e,t).html:null);return o?ur("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};Bi=e=>ze.join(e,".bostrat","mocks");LB=Buffer.from([137,80,78,71,13,10,26,10]);VB=GB,Ym=Promise.resolve()});import XB from"node:fs/promises";import dT from"node:path";import ZB from"node:os";import{randomUUID as fT}from"node:crypto";async function Xn(){return Jn||(Qm||=(async()=>{let e=!0;try{Jn=JSON.parse(await XB.readFile(pT,"utf8"))}catch{Jn={flows:[]},e=!1}finally{Qm=null}if(Jn.flows||=[],!e&&Ne()){let{records:t,source:n}=await et("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&Jn.flows.push(r.data);Jn.flows.length&&await Vs().catch(()=>{})}}return Jn})(),Qm)}async function Vs(){await Tt(pT,Jn)}function eh(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"flow.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,flowId:e.id,name:e.name,stepCount:e.steps.length,mockIds:[...new Set(e.steps.map(r=>r.mockId))],...n}}).catch(()=>{})}async function mT({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>iT)throw new Error(`steps must be an array of 1-${iT}`);let r=await ji({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>lT)throw new Error(`${l}: caption over ${lT} chars`);let f=c.title==null?null:String(c.title).trim()||null;if(f&&f.length>uT)throw new Error(`${l}: title over ${uT} chars`);let d=String(c.mock??"").trim().replace(/^mock:/,"");if(!d)throw new Error(`${l}: mock (name or id) required`);let p=r.filter(E=>E.id===d);if(p.length||(p=r.filter(E=>E.name.toLowerCase()===d.toLowerCase())),!p.length)throw new Error(`${l}: no mock matching "${d}" in this Track \u2014 see \`bostrat-mock ls\``);if(p.length>1)throw new Error(`${l}: "${d}" is ambiguous (${p.map(E=>`mock:${E.id}`).join(", ")}) \u2014 use the id`);let h=p[0],w=null;if(c.v!=null&&(w=Number(c.v),!Number.isInteger(w)||!(h.versions||[]).some(E=>E.v===w)))throw new Error(`${l}: "${h.name}" has no captured v${c.v} to pin`);let g=o.findIndex(E=>E.mockId===h.id),b=g>=0?o.splice(g,1)[0].id:fT().slice(0,8);s.push({id:b,mockId:h.id,caption:u,title:f,v:w})}let a={};for(let i of s)i.mockId in a||(a[i.mockId]=r.find(c=>c.id===i.mockId)?.readyVersion??null);return{steps:s,resolved:a}}function ej(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>cT)throw new Error(`name over ${cT} chars`);return e.trim()}async function hT({trackId:e}={}){let t=await Xn();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function tj(e){let n=(await Xn()).flows.find(r=>r.id===e);return n?{...n}:null}async function wT(e){let t=await tj(e);if(!t)return null;let n=new Map((await ji({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=tn(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 gT({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=ej(t),i=await Xn(),c=i.flows.find(p=>p.trackId===e&&p.name.toLowerCase()===a.toLowerCase());if(c)throw new Error(`flow "${c.name}" already exists in this Track (flow:${c.id}) \u2014 revise it with \`bostrat-flow update\``);let{steps:l,resolved:u}=await mT({trackId:e,steps:n}),f=Date.now(),d={id:fT().slice(0,8),trackId:e,box:o||null,agent:s||null,name:a,cwd:r,version:1,versions:[{v:1,steps:l,resolved:u,note:null,createdAt:f}],steps:l,createdAt:f,updatedAt:f};return i.flows.push(d),await Vs(),await eh(d,"created"),_u(d),{...d}}async function yT(e,{steps:t,note:n}={}){let o=(await Xn()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await mT({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 Vs(),await eh(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),_u(o),{...o}}async function bT(e){let t=await Xn(),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 Vs(),await eh(r,"deleted"),Vt("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function kT(e){return(await Xn()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function xT(e){let n=(await Xn()).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(),_u(r);return n.length&&await Vs(),n.length}async function vT(e){let t=await Xn(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await Vs();for(let r of n)Vt("flows",r.id).catch(()=>{})}return n.length}async function ST(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Xn();for(let r of n.flows)await _u(r);return{pushed:n.flows.length,source:"plane"}}var QB,pT,iT,cT,lT,uT,Jn,Qm,_u,th=L(()=>{he();lr();Gs();dr();QB=process.env.BOSTRAT_STATE_DIR||dT.join(process.env.HOME||ZB.tmpdir(),".bostrat"),pT=dT.join(QB,"flows.json"),iT=20,cT=80,lT=500,uT=80,Jn=null,Qm=null;_u=e=>wt("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import er from"node:fs/promises";import tr from"node:path";import nj from"node:os";import{randomUUID as rj}from"node:crypto";function Li(e){return oj.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function Tn(){return Zn||(nh||=(async()=>{let e=!0;try{Zn=JSON.parse(await er.readFile(ET,"utf8"))}catch{Zn={runbooks:[]},e=!1}finally{nh=null}return Zn.runbooks||=[],!e&&Ne()&&await sj().catch(()=>{}),Zn})(),nh)}async function Ro(){await Tt(ET,Zn)}function $u(e){return Fi(wt("runbooks",{...e},{trackId:e.trackId}))}async function sj(){let{records:e,source:t}=await et("runbooks");if(!(t!=="plane"||!e.length)){await er.mkdir(Iu,{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 Da("runbooks",r.id,o.v,"md");typeof s=="string"&&await er.writeFile(Qn(r,o.v),s).catch(()=>{})}Zn.runbooks.push(r)}Zn.runbooks.length&&await Ro()}}function zs(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"runbook.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,runbookId:e.id,name:e.name,status:e.status,...n}}).catch(()=>{})}function Qn(e,t){return tr.join(Iu,`${e.id}.v${t}.md`)}function AT(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 _T(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>TT)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${TT/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=Li(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 aj(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function ij({trackId:e,status:t}={}){let n=await Tn(),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 IT({trackId:e,status:t}={}){let n=await Tn(),r=await ij({trackId:e,status:t});if(!Ne())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await et("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 rh(e){let t=await cj(e);if(t)return t;if(!Ne())return null;let{records:n,source:r}=await et("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 $T(e,t){let n=await Da("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function cj(e){let n=(await Tn()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function RT({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=_T(r),c=await Tn(),l={id:rj().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 er.mkdir(Iu,{recursive:!0}),await er.writeFile(Qn(l,1),r),l.versions.push({v:1,mdRel:tr.relative($o,Qn(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await Ro(),await zs(l,"created",{version:1}),$u(l),Fi(ur("runbooks",l.id,1,"md",Qn(l,1))),{...l}}async function OT(e,{md:t,note:n}={}){let o=(await Tn()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");aj(o,"update");let s=_T(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await er.mkdir(Iu,{recursive:!0}),await er.writeFile(Qn(o,a),t),o.versions.push({v:a,mdRel:tr.relative($o,Qn(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await Ro(),await zs(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),$u(o),Fi(ur("runbooks",o.id,a,"md",Qn(o,a))),{...o}}async function CT(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await Tn()).runbooks.find(o=>o.id===e);if(!r)throw new Error("runbook not found");return r.status===t?{...r}:(r.status=t,r.updatedAt=Date.now(),await Ro(),await zs(r,t==="done"?"done":"reopened"),$u(r),{...r})}async function MT(e){let t=await Tn(),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 er.rm(tr.join($o,o.mdRel),{force:!0}).catch(()=>{});return await Ro(),r.trackDeletedAt||await zs(r,"deleted"),Fi(Vt("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function NT(e){let n=(await Tn()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await zs(r,"orphaned"),r.cwd=null,$u(r);return n.length&&await Ro(),n.length}async function PT(e){let t=await Tn(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await zs(r,"deleted");for(let o of r.versions||[])await er.rm(tr.join($o,o.mdRel),{force:!0}).catch(()=>{});Fi(Vt("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await Ro()),n.length}async function DT(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Tn();for(let r of n.runbooks){await wt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await ur("runbooks",r.id,o.v,"md",tr.join($o,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var $o,ET,Iu,TT,oj,Zn,nh,Fi,Ru=L(()=>{lr();he();dr();$o=process.env.BOSTRAT_STATE_DIR||tr.join(process.env.HOME||nj.tmpdir(),".bostrat"),ET=tr.join($o,"runbooks.json"),Iu=tr.join($o,"runbooks"),TT=256*1024,oj=[{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/}];Zn=null,nh=null;Fi=e=>Promise.resolve(e).catch(()=>{})});import oh from"node:fs/promises";import Ui from"node:path";import{randomUUID as lj}from"node:crypto";function ah(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return uj.has(t)?"image":dj.has(t)?"doc":null}function fj(e){let r=Ui.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 LT(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>BT)throw new Error(`file too large \u2014 max ${Math.floor(BT/(1024*1024))} MB`);let r=fj(t),o=Ui.extname(r).slice(1),s=ah(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=lj().slice(0,8),i=sh(e);await oh.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await oh.writeFile(Ui.join(i,c),n,{mode:384}),await oh.chmod(Ui.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${jT}/${c}`,kind:s,size:n.length}}function FT(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function ih(e){return e.role==="user"&&pj.test((e.text||"").trim())}var jT,sh,BT,uj,dj,pj,ch=L(()=>{jT=".bostrat/uploads",sh=e=>Ui.join(e,jT),BT=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,uj=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),dj=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"]);pj=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function Oo(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}var UT=L(()=>{});import{execFile as mj}from"node:child_process";import{promisify as hj}from"node:util";function lh(e){return`refs/bostrat/wip/${e}`}function yj(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function qT(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function bj(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:gj}async function uh(e,{log:t=console,force:n=!1}={}){let{id:r,cwd:o}=e??{};if(!r||!o)return{pushed:!1,reason:"no-workspace"};try{await Lr(o,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await Lr(o,["remote","get-url","origin"])}catch{return HT.has(o)||(HT.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 _s(o,"bostrat: wip snapshot"),{stdout:a}=await Lr(o,["rev-parse",`${s}^{tree}`]),i=a.trim();if(!n&&Ou.get(o)===i)return{pushed:!1,reason:"unchanged"};let c=lh(r);return await Lr(o,["push","--force","origin",`${s}:${c}`],WT),Ou.set(o,i),await $(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(`
204
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function dh(e,{log:t=console}={}){let{id:n,cwd:r}=e??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await Lr(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await Lr(r,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let o=await _s(r,"bostrat: transfer rescue snapshot"),{stdout:s}=await Lr(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if(Ou.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=yj(n);return await Lr(r,["push","origin",`${o}:${i}`],WT),Ou.set(r,a),await $(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(`
205
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}function KT({listTracks:e,sweepMs:t=bj(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)Ve(i)||i?.kind==="setup"||await uh(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 wj,gj,WT,Lr,Ou,HT,fh=L(()=>{Bl();he();Bn();wj=hj(mj),gj=12e4,WT=6e4;Lr=(e,t,n=15e3)=>wj("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),Ou=new Map,HT=new Set});import kj from"node:fs";import ph from"node:fs/promises";import xj from"node:path";function Ej(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function GT(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(!Ej(t))return{restored:!1,reason:"plane not configured"};let s=ts(e),a=xj.join(s,`${o}.ndjson`);try{if(kj.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=Ie(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let d=new AbortController,p=setTimeout(()=>d.abort(),Tj),h;try{h=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${vj}`,{headers:c,signal:d.signal})}finally{clearTimeout(p)}if(h.status===404)return{restored:!1,reason:"unknown to plane"};if(!h.ok)return{restored:!1,reason:`plane ${h.status}`};let w=await h.json();for(let g of w.events||[])l.push(JSON.stringify(g));if(l.length>Sj)return{restored:!1,reason:"event count over safety cap"};if(w.next==null)break;u=w.next}if(!l.length)return{restored:!1,reason:"unknown to plane"};await ph.mkdir(s,{recursive:!0});let f=`${a}.pull-${process.pid}-${Date.now()}`;return await ph.writeFile(f,l.join(`
206
206
  `)+`
207
- `),await fh.rename(f,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var yj,bj,kj,qT=j(()=>{it();me();yj=1e3,bj=5e5,kj=3e4});var vE={};Pd(vE,{HANDOFF_LATEST_REL:()=>Co,KNOWN_AGENTS:()=>Xi,TRACK_NAME_MAX:()=>Eh,addTrackRepo:()=>Uh,adoptTrack:()=>sw,agentAvailability:()=>Mu,announceNodeUpdate:()=>An,answerFullscreenOffer:()=>Zh,answerPrompt:()=>Pu,archiveTrack:()=>Do,archiveTrackForMergedPr:()=>qn,augmentFirstPromptAfterHandoff:()=>eE,buildAgentCmd:()=>Ih,canResumeSubtask:()=>bE,cancelQueued:()=>ec,cancelQueuedToDraft:()=>Nh,cancelStopJob:()=>tc,cancelSubtask:()=>Ku,changedRepos:()=>_o,commitTransferOut:()=>Wu,createSetupTrack:()=>qh,createTrack:()=>ju,deleteTrack:()=>Gh,demoteTransferredTracks:()=>ow,ensureLeadEpochs:()=>Qs,forceMergeSubtask:()=>lw,getHandoffJob:()=>ra,getSubtaskJob:()=>SL,getTrack:()=>te,getTransferOutJob:()=>tw,healDeadLead:()=>Yi,interruptLead:()=>Bu,isArchiving:()=>pL,isHandoffNoteEcho:()=>xh,isInterruptEcho:()=>vh,isModelSwitchEcho:()=>Sh,leadCliDead:()=>zh,listSubtaskJobs:()=>jo,listTracks:()=>le,matchTranscriptsToBoxes:()=>rE,mergeNotifyMessage:()=>hE,navigatePrompt:()=>Mh,notifyTrackForMergedPr:()=>Kn,notifyTrackForResolvedPr:()=>Lu,offerFollowupsForMergedPr:()=>Bo,pendingOffers:()=>Oh,queueShipCompleteNotify:()=>Dh,queuedMessages:()=>Mo,reapArchivedOrphans:()=>Xh,reconcileDemotedTracks:()=>Jh,reconcileHandoffOutcome:()=>wE,reconcileInterruptedHandoffs:()=>ew,reconcileInterruptedSubtasks:()=>aw,reconcileNodeUpdateNotices:()=>Rh,reconcileSubtaskOutcome:()=>yE,refreshStandingInstructions:()=>Wh,refuseIfTransferred:()=>rw,rehydrateLead:()=>rc,removeTrackRepo:()=>Hh,renameTrack:()=>Yh,reposOf:()=>Dt,resolveTrackBox:()=>Ii,resolveTrackBoxByHookToken:()=>Qi,restartLead:()=>Uu,resumeAgentCmd:()=>$h,sayToLead:()=>Pt,sendOptionsForAgent:()=>pn,setTrackDraft:()=>Lh,setTrackModel:()=>Fh,startLeadHandoff:()=>Hu,startSpinUpView:()=>Bh,startSubtask:()=>cw,startTransferOut:()=>nw,stopJobActive:()=>aE,subtaskMessages:()=>Ch,trackMessages:()=>Nu,unarchiveTrack:()=>Fu});import z from"node:fs/promises";import J from"node:path";import{randomUUID as Po}from"node:crypto";import{execFile as vj}from"node:child_process";import{promisify as Sj}from"node:util";function Ih(e,{skipPermissions:t=!0}={}){let n=Cu[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 $h(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=Cu[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&&!Jt(r,t)){let c=o&&Pe(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 na(e){let t=Cu[e];if(t)return process.env[t.envVar]||t.base}async function Mu({maxAgeMs:e=6e4}={}){if(Lr.value&&Date.now()-Lr.at<e)return Lr.value;let t=Lr.value,n=await Promise.all(Xi.map(async r=>{let o=await sl(na(r),{retries:[]});return o===is?[r,t?.[r]??!0]:[r,o===ol]}));return Lr.value=Object.fromEntries(n),Lr.at=Date.now(),Lr.value}async function Zi(e,t=!0){let n=Ih(e,{skipPermissions:t});if(await sl(n)===as){Lr.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.":pf[r]?`Install it on this node: ${pf[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 eE(e,t=Co){return`${e.trim()}
207
+ `),await ph.rename(f,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var vj,Sj,Tj,VT=L(()=>{it();he();vj=1e3,Sj=5e5,Tj=3e4});var EE={};Bd(EE,{HANDOFF_LATEST_REL:()=>Co,KNOWN_AGENTS:()=>Zi,TRACK_NAME_MAX:()=>Ah,addTrackRepo:()=>Hh,adoptTrack:()=>aw,agentAvailability:()=>Pu,announceNodeUpdate:()=>An,answerFullscreenOffer:()=>Qh,answerPrompt:()=>Bu,archiveTrack:()=>Do,archiveTrackForMergedPr:()=>qn,augmentFirstPromptAfterHandoff:()=>rE,buildAgentCmd:()=>$h,canResumeSubtask:()=>vE,cancelQueued:()=>tc,cancelQueuedToDraft:()=>Ph,cancelStopJob:()=>nc,cancelSubtask:()=>Vu,changedRepos:()=>_o,commitTransferOut:()=>Ku,createSetupTrack:()=>Kh,createTrack:()=>Fu,deleteTrack:()=>Vh,demoteTransferredTracks:()=>sw,ensureLeadEpochs:()=>ea,forceMergeSubtask:()=>uw,getHandoffJob:()=>oa,getSubtaskJob:()=>_L,getTrack:()=>re,getTransferOutJob:()=>nw,healDeadLead:()=>Ji,interruptLead:()=>Lu,isArchiving:()=>gL,isHandoffNoteEcho:()=>vh,isInterruptEcho:()=>Sh,isModelSwitchEcho:()=>Th,leadCliDead:()=>Yh,listSubtaskJobs:()=>jo,listTracks:()=>ue,matchTranscriptsToBoxes:()=>aE,mergeNotifyMessage:()=>yE,navigatePrompt:()=>Nh,notifyTrackForMergedPr:()=>Kn,notifyTrackForResolvedPr:()=>Uu,offerFollowupsForMergedPr:()=>Bo,pendingOffers:()=>Ch,queueShipCompleteNotify:()=>Bh,queuedMessages:()=>Mo,reapArchivedOrphans:()=>Zh,reconcileDemotedTracks:()=>Xh,reconcileHandoffOutcome:()=>bE,reconcileInterruptedHandoffs:()=>tw,reconcileInterruptedSubtasks:()=>iw,reconcileNodeUpdateNotices:()=>Oh,reconcileSubtaskOutcome:()=>xE,refreshStandingInstructions:()=>qh,refuseIfTransferred:()=>ow,rehydrateLead:()=>oc,removeTrackRepo:()=>Wh,renameTrack:()=>Jh,reposOf:()=>Dt,resolveTrackBox:()=>$i,resolveTrackBoxByHookToken:()=>ec,restartLead:()=>Wu,resumeAgentCmd:()=>Rh,sayToLead:()=>Pt,sendOptionsForAgent:()=>pn,setTrackDraft:()=>Fh,setTrackModel:()=>Uh,startLeadHandoff:()=>qu,startSpinUpView:()=>jh,startSubtask:()=>lw,startTransferOut:()=>rw,stopJobActive:()=>lE,subtaskMessages:()=>Mh,trackMessages:()=>Du,unarchiveTrack:()=>Hu});import J from"node:fs/promises";import Z from"node:path";import{randomUUID as Po}from"node:crypto";import{execFile as Aj}from"node:child_process";import{promisify as _j}from"node:util";function $h(e,{skipPermissions:t=!0}={}){let n=Nu[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 Rh(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=Nu[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&&!Jt(r,t)){let c=o&&Pe(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 ra(e){let t=Nu[e];if(t)return process.env[t.envVar]||t.base}async function Pu({maxAgeMs:e=6e4}={}){if(Fr.value&&Date.now()-Fr.at<e)return Fr.value;let t=Fr.value,n=await Promise.all(Zi.map(async r=>{let o=await il(ra(r),{retries:[]});return o===is?[r,t?.[r]??!0]:[r,o===al]}));return Fr.value=Object.fromEntries(n),Fr.at=Date.now(),Fr.value}async function Qi(e,t=!0){let n=$h(e,{skipPermissions:t});if(await il(n)===as){Fr.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.":hf[r]?`Install it on this node: ${hf[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 rE(e,t=Co){return`${e.trim()}
208
208
 
209
- (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 xh(e){return e.role==="user"&&Aj.test((e.text||"").trim())}async function Z(){return qt||(ph||=(async()=>{try{qt=JSON.parse(await z.readFile(ZT,"utf8"))}catch{qt={tracks:[]}}finally{ph=null}return qt})(),ph)}async function ee(){await Tt(ZT,qt)}function $j(e,t){let n=JSON.stringify({trackId:e,...t})+`
210
- `;return mh=mh.then(()=>z.mkdir(En,{recursive:!0})).then(()=>z.appendFile(Tj,n)).catch(()=>{}),mh}async function An({current:e,latest:t,min:n=null,installKind:r=null,required:o=!1,status:s="available",policy:a=null,error:i=null,reason:c=null}={}){if(!t)return{announced:0};if(s==="available"){let f=null;try{f=JSON.parse(await z.readFile(hh,"utf8"))}catch{}if(f?.latest===t&&f?.current===e)return{announced:0,deduped:!0}}let l=await Z(),u=0;for(let f of l.tracks)Ve(f)||!f.leadBox||(Te(f,"node-update",{status:s,current:e??null,latest:t,...n?{min:n}:{},...r?{installKind:r}:{},...a?{policy:a}:{},...i?{error:String(i).slice(0,400)}:{},...c?{reason:c}:{},required:o===!0}),u++);if(await ee().catch(()=>{}),s==="available")try{await z.mkdir(J.dirname(hh),{recursive:!0}),await z.writeFile(hh,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function Rh({current:e,installKind:t=null,policy:n=null}={}){if(!e)return{reconciled:!1,announced:0,targets:[]};let r=await Z(),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)||Rj(e,c)||(Te(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 ee().catch(()=>{}),{reconciled:o>0,announced:o,targets:[...s]}}function Rj(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 tE(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=>Oj.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 nE(e,t,n,{kind:r}={}){let o=await ge(t);if(!o)throw new Error(`box "${t}" is not running`);let s=na(o.agent);await hr({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s}),await Ze(t,n,{...pn(o.agent,n),kind:r||"orchestration"});let a=await ni({sessionName:t,agent:o.agent,agentCmd:s,text:n,trackId:e,flow:"orchestration"});await re({flow:"orchestration",phase:"sent",submitted:a,trackId:e,sessionName:t,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let i=await Z(),c=he(i,e);if(!c)return;let l=c.boxes.find(u=>u.name===t);Te(c,"orchestration-prompt",{box:t,agent:l?.agent||o.agent,boxRole:l?.role,prompt:n,kind:r||"orchestration"}),await ee()}async function Cj(e){let t=J.join(ts(e),`${e.id}.ndjson`),n;try{n=await z.stat(t)}catch{return null}let r=KT.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await F(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return KT.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function Mj(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:sm(n.name,n.agent)}async function Mt(e,t=null){let n=t??new Map((await zt()).map(c=>[c.name,c])),r=!!e.transferredTo,o=e.boxes.map(c=>{let l=r?null:n.get(c.name),u=Fr.has(c.state)?c.state:l?c.role==="lead"?"live":c.state:"stopped";return{...c,state:u,cwd:l?.cwd||c.cwd,agent:l?.agent||c.agent,sessionId:l?.sessionId||c.sessionId}}),[s,{working:a,prompted:i}]=await Promise.all([Cj(e),Mj(e,o)]);return{...e,boxes:o,lastResponseAt:s,working:a,prompted:i,archiving:zi.has(e.id)}}function rE(e,t,n){let r=[...e].sort((l,u)=>l.createdAt-u.createdAt),o=[...t].sort((l,u)=>l.birthMs-u.birthMs),s=new Set,a=[];for(let l of r)l.sessionId&&n(l.sessionId)&&!s.has(l.sessionId)?s.add(l.sessionId):a.push(l);let i=new Map(r.map((l,u)=>[l,u])),c=[];for(let l of a){if(l.sessionId&&n(l.sessionId)){c.push({box:l.name,sessionId:null});continue}if(!l.sessionId||l.pinned)continue;let u=i.get(l),f=l.createdAt-Nj,d=r[u+1]?.createdAt??1/0,p=o.find(h=>!s.has(h.id)&&h.birthMs>=f&&h.birthMs<d);p&&(s.add(p.id),c.push({box:l.name,sessionId:p.id}))}return c}async function oE(e){let t=new Map;for(let r of e.tracks)for(let o of r.boxes)o.agent==="claude"&&o.cwd&&(t.has(o.cwd)||t.set(o.cwd,[]),t.get(o.cwd).push({track:r,box:o}));let n=!1;for(let[r,o]of t){let s=o.map(d=>d.box.sessionId),a=nb(r),i=new Set(a.map(d=>d.id)),c=s.every(d=>d&&i.has(d)),l=new Set(s).size===s.length;if(c&&l)continue;let u=o.map(d=>d.box),f=rE(u,a,d=>i.has(d));for(let d of f){let p=u.find(h=>h.name===d.box);p&&(p.sessionId=d.sessionId),await Vy(d.box,d.sessionId),n=!0}}return n}async function le(){let e=await Z();await oE(e)&&await ee();let t=new Map((await zt()).map(n=>[n.name,n]));return Promise.all(e.tracks.map(n=>Mt(n,t)))}async function Ii(e,t){let n=await Z();if(e)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.sessionId&&s.sessionId===e);if(o)return{track:r,box:o}}if(t)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.cwd===t);if(o)return{track:r,box:o}}return null}async function Qi(e){let t=va(e);if(!t)return null;let n=await Z();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&Pg(o.hookTokenHash,t))return{track:r,box:o};return null}async function te(e){let t=await Z(),n=he(t,e);return n?(await oE(t)&&await ee(),Mt(n)):null}async function Oh(e){let t=await F(e).catch(()=>[]),n;try{n=wr(t)}catch{return[]}return dk(n).map(r=>({kind:r.kind,id:r.offerId??r.proposalId??r.id,ts:r.ts??null}))}function vh(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(Pj[e.agent]||[]).some(n=>n.test(t))}function Sh(e){let t=(e.text||"").trim();return t?Dj.some(n=>n.test(t)):!1}async function Nu(e,t={}){let n=await te(e);if(!n)return null;let r=new Set([...n.events.filter(A=>A.type==="orchestration-prompt"&&A.prompt).map(A=>String(A.prompt).trim()),...n.events.filter(A=>A.type==="said"&&A.text).map(A=>String(A.text).trim())]),o=ra(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=jm(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[..._S(n),...l],d={windows:[...Nk(n),...Pk(n,Il),...a,...u]},h=(await Promise.all(n.boxes.map(A=>yp(A,t)))).flat(),w=h.map(A=>{let G={kind:"message",...A};if(G.role==="assistant"&&(G.text||"").trim()&&G.tools?.length){let Ge=li(G.agent).cliTools,_t=G.tools.filter(at=>!Ge.has(at));return{...G,tools:_t.length?_t:void 0}}return G}).map(A=>{if(A.role!=="user")return A;let G=El(A.text);return G?G.kind==="suppress"?null:{...A,note:G,text:nk(G)}:A}).filter(Boolean).filter(A=>!(A.role==="user"&&r.has((A.text||"").trim()))).filter(A=>!vh(A)).filter(A=>!Sh(A)).filter(A=>!xh(A)).filter(A=>!ah(A)).filter(A=>A.role!=="assistant"||!!(A.text||"").trim()||!!A.images?.length).filter(A=>!Dk(A,d)),g=w.filter(A=>A.failed&&A.text===ao);if(g.length){let A=new Map;for(let G of g){if(!A.has(G.box)){let at=[...(await Ce(G.box,{lines:Xe}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(nt=>nt[1]);A.set(G.box,at.length?at[at.length-1]:null)}let Ge=A.get(G.box);Ge&&(G.text=`\u25A0 ${Ge}`)}}let k=await Promise.all(n.boxes.map(A=>h0(A,t)));await Qv(n,k.flat());let{agentTurnBoxes:S}=await Xv(n,w);for(let A of n.boxes)S.has(A.name)&&A.cwd&&zc(A.cwd);await ux(n),await NS(n,w).catch(()=>{});for(let A of n.boxes)A.agent==="codex"&&A.state==="live"&&await tS(n,A),A.agent==="cursor"&&A.state==="live"&&await aS(n,A);let E=await Promise.all(n.boxes.map(A=>m0(A,t)));await Zv(n,E.flat().filter(A=>!wh(A.box,A.ts,u)));let R=await F(n),B=c&&i.viewId?i.viewId:null,T=vx(R),_=wr(R).filter(A=>!(A.kind==="message"&&(vh(A)||Sh(A)||xh(A)||ah(A)))&&!(A.kind==="view-card"&&B&&A.viewId===B)),O=Sx(_,T),I=_.filter(A=>!(A.kind==="message"&&A.role==="assistant"&&!O.has(A)&&wh(A.box,A.ts,T))),U=Zf(R,I).map(A=>({kind:"command-batch",id:A.id,ts:A.pending?A.ts:(A.anchorTs??A.ts)-1,anchorTs:A.anchorTs,anchorBox:A.anchorBox,agent:A.agent,boxRole:A.boxRole,commands:A.commands,pending:A.pending})).filter(A=>!wh(A.anchorBox,A.anchorTs??A.ts,u)),H=lk(uk([...I,...U].filter(A=>A.ts!=null).sort((A,G)=>A.ts-G.ts))),ae=jj(n),X=ae.size?H.filter(A=>A.kind==="event"||!ae.has(A.box??A.anchorBox)):H,C=n.boxes.find(A=>A.name===n.leadBox)||null,Q=C?await Ka(C.cwd,C.sessionId,{fallbackNewest:!1}):null;if(!Q&&C){let A=[...R].reverse().find(G=>G.type==="context.usage"&&G.boxId===C.name);A?.payload?.window&&(Q={pct:A.payload.pct??(A.payload.occupancy!=null?A.payload.occupancy/A.payload.window:null),occupancy:A.payload.occupancy??null,window:A.payload.window,windowKnown:!0,model:A.payload.model||null})}let ve=[...h].reverse().find(A=>A.role==="assistant"&&A.model),W=ve?.model||null,be=[...n.events||[]].reverse().find(A=>A.type==="model-change"),se=Q?.model||W;be&&(!ve?.ts||be.at>=ve.ts)&&(se=be.to);let pe=C?await Ce(C.name,{lines:Xe}).catch(()=>""):"",ie=C&&wo(C.agent,pe)?await Nn(C.name).catch(()=>pe):pe,L=C?Tr(C,ie):null;if(L&&C){let A=Ml(C,L,ie);if(A){let G=O0(C.name,L.promptId);G.action!=="give-up"&&(G.action==="send"&&(Le(C.name,A.keys,{kind:"auto-reject"}).catch(()=>{}),G.first&&$(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:C.name,provider:C.agent,payload:{ts:Date.now(),promptId:L.promptId,rule:A.id}}).catch(()=>{})),L=null)}}!L&&C&&!ws(C.agent,pe)&&!Mo(n.id).length&&(L=Jf(X,{leadBoxId:C.name,provider:C.agent,isAnswered:A=>R.some(G=>G.type==="prompt.answered"&&G.payload?.promptId===A)})),L&&dx(n,C,L);let ce=X.filter(A=>!(A.kind==="message"&&A.role==="assistant"&&A.ask&&!String(A.text||"").trim()&&!A.images?.length)),Ae=!!C&&su(C.name,C.agent,pe)&&!L;C&&!C.readyAt&&(Ae||L||pe&&gs(C.agent,pe))&&(C.readyAt=Date.now(),await ee());let _e=!!C&&!C.readyAt&&Date.now()-(n.createdAt||0)<Bj;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&C&&gs(C.agent,pe)&&!L){let A=await Z(),G=he(A,n.id);G?.setup&&!G.setup.connectedAt&&(G.setup.connectedAt=Date.now(),n.setup.connectedAt=G.setup.connectedAt,await $(G,{type:"provider.connected",actor:"system",source:"pane",boxId:C.name,provider:C.agent,payload:{provider:C.agent,ts:G.setup.connectedAt}}).catch(()=>{}),await ee())}let xt=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,je=null;if(c){let A=Date.now()-i.startedAt;if(i.viewId&&!Ae){let G=yu(n.id);G&&(Te(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:G.finishedAt}),await ee())}else if(L||A>ES&&!Ae&&!i.viewId||A>Bm){let G=L?"needs-input":A>Bm?"timeout":"no-view";yu(n.id,{error:G})&&await $(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:C?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:G}}).catch(()=>{})}else je={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:ce,context:Q?{pct:Q.pct,occupancy:Q.occupancy,window:Q.window,windowKnown:Q.windowKnown,model:Q.model}:null,models:{current:se,options:rx(C?.agent)},pendingPrompt:L,working:Ae,stopping:aE(n.id),leadStarting:_e,handoff:xt,view:je,queued:Mo(n.id).filter(A=>A.kind!=="ship-notify"&&A.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function jj(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 Ch(e,t){let n=await te(e);if(!n)return null;let r=jo(e).find(f=>f.id===t)||null;if(!r)return null;let o=r.box||null;if(!o)return{items:[],working:!1,box:null,agent:r.agent,task:r.task};let s=await F(n),a=wr(s).filter(f=>f.box===o&&!(f.kind==="message"&&f.role==="assistant"&&f.ask&&!String(f.text||"").trim()&&!f.images?.length)),i=Zf(s.filter(f=>f.boxId===o),a.filter(f=>f.kind==="message")).map(f=>({kind:"command-batch",id:f.id,ts:f.pending?f.ts:(f.anchorTs??f.ts)-1,anchorTs:f.anchorTs,anchorBox:f.anchorBox,agent:f.agent,boxRole:f.boxRole,commands:f.commands,pending:f.pending})),c=[...a,...i].filter(f=>f.ts!=null).sort((f,d)=>f.ts-d.ts),l=n.boxes.find(f=>f.name===o)||null,u=!1;if(l&&l.state==="live"){let f=await Ce(o,{lines:Xe}).catch(()=>"");u=su(o,l.agent||r.agent,f)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}async function Pu(e,{promptId:t,answers:n,text:r}={}){let o=he(await Z(),e);if(!o)throw new Error(`track "${e}" not found`);tc(e,"prompt-answer");let s=o.boxes.find(h=>h.name===o.leadBox);if(!s)throw new Error(`track "${e}" has no lead box`);if(!await ge(o.leadBox))throw new Error(`lead box "${o.leadBox}" is not running`);let i=await Ep(s);if(i||(i=await Lj(o,s)),!i)throw new Error("no pending prompt to answer");if(t&&t!==i.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");let c;if(i.answerMode==="text"){let h=typeof r=="string"?r.trim():"";if(!h)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(h)||h.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await Ze(o.leadBox,h,{enter:!0,kind:"answer-prompt"}),c={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(i.answerMode==="esc")await Le(o.leadBox,["Escape"],{kind:"answer-prompt"}),c={mode:"keys",value:"Escape",count:1};else if(i.answerMode==="say"){let h=ak(i,n||[],typeof r=="string"?r:"");if(!h)throw new Error("no answer selected \u2014 pick an option or reply in chat");await Pt(o.id,h,{kind:"prompt-answer"}),c={mode:"say",value:h,count:1}}else if(i.provider==="claude"||i.answerMode==="keys"){let h=_0(i,n||[]);await Le(o.leadBox,h,{kind:"answer-prompt"}),c={mode:"keys",value:h.join(" "),count:h.length}}else{let h=Rb(i,n||[]);await Ze(o.leadBox,h,{enter:!0,kind:"answer-prompt"}),c={mode:"text",value:h,count:1}}if(i.answerMode==="say"){let h=i.questions||[];for(let w=0;w<h.length;w++){let g=h[w],k=new Set(Array.isArray(n?.[w])?n[w]:[]),S=[...k].map(R=>g.options?.[R]).filter(Boolean).map(R=>({label:R.label,description:R.description||""})),E=(g.options||[]).map((R,B)=>k.has(B)?null:R?.label).filter(Boolean);Hp(o,s,i,{...c,groupId:i.groupId||i.promptId,questionIndex:w,questionTotal:i.questionTotal??h.length,header:g.header||"",question:g.question||"",multiSelect:!!g.multiSelect,chosen:S,rejected:E})}return await re({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),{ok:!0,promptId:i.promptId,sent:c.count}}let l=i.questions?.[0]||{},u=new Set(Array.isArray(n?.[0])?n[0]:[]),f=[...u].map(h=>l.options?.[h]).filter(Boolean).map(h=>({label:h.label,description:h.description||""})),d=(l.options||[]).map((h,w)=>u.has(w)?null:h?.label).filter(Boolean),p=i.review?"review":/^claude:model-confirm:/.test(i.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(i.promptId||"")?"resume-confirm":void 0;return c={...c,groupId:i.groupId||i.promptId,questionIndex:i.questionIndex??0,questionTotal:i.questionTotal??1,header:l.header||"",question:l.question||"",multiSelect:!!l.multiSelect,chosen:f,rejected:d,...p?{control:p}:{}},await re({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),Hp(o,s,i,c),{ok:!0,promptId:i.promptId,sent:c.count}}async function Lj(e,t){if(!t)return null;let n=await F(e).catch(()=>[]);return Jf(wr(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function Mh(e,{promptId:t,questionIndex:n}={}){let r=he(await Z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=r.boxes.find(l=>l.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(!await ge(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await Ep(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=I0(a,n);return c.length?(await Le(r.leadBox,c,{kind:"navigate-prompt"}),await re({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 Du(e){let t=qi.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},qi.set(e,t)),t}function Mo(e){return(qi.get(e)?.items??[]).map(t=>({...t}))}function ec(e){let t=qi.get(e);if(!t)return[];let n=t.items.splice(0);return t.idleSince=null,t.timer&&(clearInterval(t.timer),t.timer=null),n}async function Nh(e){let t=ec(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=he(await Z(),e);if(o)return r=Zs(o,n),await ee(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function Ph(e){let t=Du(e);t.timer||(t.timer=setInterval(()=>Uj(e).catch(()=>{}),Fj))}async function Uj(e){let t=qi.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 Z(),e);if(!n||n.archivedAt){ec(e);return}let r=ra(e);if(r&&!r.finishedAt&&r.step!=="done"&&!r.error){Oo(t,!1);return}let o=await ge(n.leadBox),s=n.boxes.find(c=>c.name===n.leadBox);if(o&&await zh(o)&&(o=await Yi(n,s,"queue")?await ge(n.leadBox):null,await ee()),!o){Oo(t,!1);return}if(yo(s?.agent)){Oo(t,!1);return}let a=await Ce(n.leadBox,{lines:Xe}).catch(()=>"");if(gl(s?.agent,a)){Oo(t,!1);return}if(wo(s?.agent,a)){let c=await Nn(n.leadBox).catch(()=>a);if(Tr(s,c)){Oo(t,!1);return}}if(!Oo(t,!0))return;let i=t.items.shift();t.idleSince=null;try{await Th(n,s,o,i.text,i.kind??null,i.attachments??null)}catch(c){if(c?.code!=="cli-not-running")throw c;t.items.unshift(i),await Yi(n,s,"queue-gate")}await ee()}finally{t.flushing=!1}}}async function sE(e,t,n,r){let o=yo(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(Zs(e,[n]),await ee()),V0(e.id,o))try{await $(e,{type:"usage.cap.hit",actor:"system",provider:t?.agent??null,boxId:e.leadBox,payload:{...o,blockedKind:r??null}})}catch{}let s=new Error(`${t?.agent??"the lead provider"} is paused \u2014 its ${o.window} spend limit is reached ($${o.spentUsd.toFixed(2)} of $${o.limitUsd.toFixed(2)})`);throw s.usageCap=o,s}async function Hj(e,t){let n=await Ce(e.leadBox,{lines:Xe}).catch(()=>"");if(!wo(t?.agent,n))return!1;let r=await Nn(e.leadBox).catch(()=>n);return!!Tr(t,r)}async function Th(e,t,n,r,o=null,s=null){await sE(e,t,r,o);let a=Ki.get(e.id)||0,i=r,c=!1,l=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(i=eE(r,e.pendingHandoffHydrate.artifact||Co),delete e.pendingHandoffHydrate,c=!0);let u=Array.isArray(s)?s.filter(d=>d&&d.rel):[];if(u.length){let d=BT(u.map(p=>p.rel));i=i.trim()?`${i.trim()}
209
+ (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 vh(e){return e.role==="user"&&Rj.test((e.text||"").trim())}async function Q(){return qt||(mh||=(async()=>{try{qt=JSON.parse(await J.readFile(tE,"utf8"))}catch{qt={tracks:[]}}finally{mh=null}return qt})(),mh)}async function ne(){await Tt(tE,qt)}function Mj(e,t){let n=JSON.stringify({trackId:e,...t})+`
210
+ `;return hh=hh.then(()=>J.mkdir(En,{recursive:!0})).then(()=>J.appendFile(Ij,n)).catch(()=>{}),hh}async function An({current:e,latest:t,min:n=null,installKind:r=null,required:o=!1,status:s="available",policy:a=null,error:i=null,reason:c=null}={}){if(!t)return{announced:0};if(s==="available"){let f=null;try{f=JSON.parse(await J.readFile(wh,"utf8"))}catch{}if(f?.latest===t&&f?.current===e)return{announced:0,deduped:!0}}let l=await Q(),u=0;for(let f of l.tracks)Ve(f)||!f.leadBox||(Te(f,"node-update",{status:s,current:e??null,latest:t,...n?{min:n}:{},...r?{installKind:r}:{},...a?{policy:a}:{},...i?{error:String(i).slice(0,400)}:{},...c?{reason:c}:{},required:o===!0}),u++);if(await ne().catch(()=>{}),s==="available")try{await J.mkdir(Z.dirname(wh),{recursive:!0}),await J.writeFile(wh,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function Oh({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)||Nj(e,c)||(Te(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 ne().catch(()=>{}),{reconciled:o>0,announced:o,targets:[...s]}}function Nj(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 oE(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=>Pj.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 sE(e,t,n,{kind:r}={}){let o=await ye(t);if(!o)throw new Error(`box "${t}" is not running`);let s=ra(o.agent);await wr({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s}),await Ze(t,n,{...pn(o.agent,n),kind:r||"orchestration"});let a=await ri({sessionName:t,agent:o.agent,agentCmd:s,text:n,trackId:e,flow:"orchestration"});await se({flow:"orchestration",phase:"sent",submitted:a,trackId:e,sessionName:t,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let i=await Q(),c=we(i,e);if(!c)return;let l=c.boxes.find(u=>u.name===t);Te(c,"orchestration-prompt",{box:t,agent:l?.agent||o.agent,boxRole:l?.role,prompt:n,kind:r||"orchestration"}),await ne()}async function Dj(e){let t=Z.join(ts(e),`${e.id}.ndjson`),n;try{n=await J.stat(t)}catch{return null}let r=zT.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await U(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return zT.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function Bj(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:am(n.name,n.agent)}async function Mt(e,t=null){let n=t??new Map((await zt()).map(c=>[c.name,c])),r=!!e.transferredTo,o=e.boxes.map(c=>{let l=r?null:n.get(c.name),u=Ur.has(c.state)?c.state:l?c.role==="lead"?"live":c.state:"stopped";return{...c,state:u,cwd:l?.cwd||c.cwd,agent:l?.agent||c.agent,sessionId:l?.sessionId||c.sessionId}}),[s,{working:a,prompted:i}]=await Promise.all([Dj(e),Bj(e,o)]);return{...e,boxes:o,lastResponseAt:s,working:a,prompted:i,archiving:Yi.has(e.id)}}function aE(e,t,n){let r=[...e].sort((l,u)=>l.createdAt-u.createdAt),o=[...t].sort((l,u)=>l.birthMs-u.birthMs),s=new Set,a=[];for(let l of r)l.sessionId&&n(l.sessionId)&&!s.has(l.sessionId)?s.add(l.sessionId):a.push(l);let i=new Map(r.map((l,u)=>[l,u])),c=[];for(let l of a){if(l.sessionId&&n(l.sessionId)){c.push({box:l.name,sessionId:null});continue}if(!l.sessionId||l.pinned)continue;let u=i.get(l),f=l.createdAt-jj,d=r[u+1]?.createdAt??1/0,p=o.find(h=>!s.has(h.id)&&h.birthMs>=f&&h.birthMs<d);p&&(s.add(p.id),c.push({box:l.name,sessionId:p.id}))}return c}async function iE(e){let t=new Map;for(let r of e.tracks)for(let o of r.boxes)o.agent==="claude"&&o.cwd&&(t.has(o.cwd)||t.set(o.cwd,[]),t.get(o.cwd).push({track:r,box:o}));let n=!1;for(let[r,o]of t){let s=o.map(d=>d.box.sessionId),a=rb(r),i=new Set(a.map(d=>d.id)),c=s.every(d=>d&&i.has(d)),l=new Set(s).size===s.length;if(c&&l)continue;let u=o.map(d=>d.box),f=aE(u,a,d=>i.has(d));for(let d of f){let p=u.find(h=>h.name===d.box);p&&(p.sessionId=d.sessionId),await zy(d.box,d.sessionId),n=!0}}return n}async function ue(){let e=await Q();await iE(e)&&await ne();let t=new Map((await zt()).map(n=>[n.name,n]));return Promise.all(e.tracks.map(n=>Mt(n,t)))}async function $i(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 ec(e){let t=Sa(e);if(!t)return null;let n=await Q();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&Dg(o.hookTokenHash,t))return{track:r,box:o};return null}async function re(e){let t=await Q(),n=we(t,e);return n?(await iE(t)&&await ne(),Mt(n)):null}async function Ch(e){let t=await U(e).catch(()=>[]),n;try{n=gr(t)}catch{return[]}return mk(n).map(r=>({kind:r.kind,id:r.offerId??r.proposalId??r.id,ts:r.ts??null}))}function Sh(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(Lj[e.agent]||[]).some(n=>n.test(t))}function Th(e){let t=(e.text||"").trim();return t?Fj.some(n=>n.test(t)):!1}async function Du(e,t={}){let n=await re(e);if(!n)return null;let r=new Set([...n.events.filter(_=>_.type==="orchestration-prompt"&&_.prompt).map(_=>String(_.prompt).trim()),...n.events.filter(_=>_.type==="said"&&_.text).map(_=>String(_.text).trim())]),o=oa(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=Lm(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...RS(n),...l],d={windows:[...Bk(n),...jk(n,Rl),...a,...u]},h=(await Promise.all(n.boxes.map(_=>bp(_,t)))).flat(),w=h.map(_=>{let V={kind:"message",..._};if(V.role==="assistant"&&(V.text||"").trim()&&V.tools?.length){let Ge=ui(V.agent).cliTools,_t=V.tools.filter(at=>!Ge.has(at));return{...V,tools:_t.length?_t:void 0}}return V}).map(_=>{if(_.role!=="user")return _;let V=bs(_.text);return V?V.kind==="suppress"?null:{..._,note:V,text:sk(V)}:_}).filter(Boolean).filter(_=>!(_.role==="user"&&r.has((_.text||"").trim()))).filter(_=>!Sh(_)).filter(_=>!Th(_)).filter(_=>!vh(_)).filter(_=>!ih(_)).filter(_=>_.role!=="assistant"||!!(_.text||"").trim()||!!_.images?.length).filter(_=>!Lk(_,d)),g=w.filter(_=>_.failed&&_.text===ao);if(g.length){let _=new Map;for(let V of g){if(!_.has(V.box)){let at=[...(await Ce(V.box,{lines:Xe}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(nt=>nt[1]);_.set(V.box,at.length?at[at.length-1]:null)}let Ge=_.get(V.box);Ge&&(V.text=`\u25A0 ${Ge}`)}}let b=await Promise.all(n.boxes.map(_=>y0(_,t)));await nS(n,b.flat());let{agentTurnBoxes:E}=await eS(n,w);for(let _ of n.boxes)E.has(_.name)&&_.cwd&&Jc(_.cwd);await px(n),await BS(n,w).catch(()=>{});for(let _ of n.boxes)_.agent==="codex"&&_.state==="live"&&await oS(n,_),_.agent==="cursor"&&_.state==="live"&&await lS(n,_);let S=await Promise.all(n.boxes.map(_=>g0(_,t)));await tS(n,S.flat().filter(_=>!gh(_.box,_.ts,u)));let R=await U(n),M=c&&i.viewId?i.viewId:null,T=Ex(R),A=gr(R).filter(_=>!(_.kind==="message"&&(Sh(_)||Th(_)||vh(_)||ih(_)))&&!(_.kind==="view-card"&&M&&_.viewId===M)),C=Ax(A,T),I=A.filter(_=>!(_.kind==="message"&&_.role==="assistant"&&!C.has(_)&&gh(_.box,_.ts,T))),W=Qf(R,I).map(_=>({kind:"command-batch",id:_.id,ts:_.pending?_.ts:(_.anchorTs??_.ts)-1,anchorTs:_.anchorTs,anchorBox:_.anchorBox,agent:_.agent,boxRole:_.boxRole,commands:_.commands,pending:_.pending})).filter(_=>!gh(_.anchorBox,_.anchorTs??_.ts,u)),j=fk(pk([...I,...W].filter(_=>_.ts!=null).sort((_,V)=>_.ts-V.ts))),ee=Hj(n),q=ee.size?j.filter(_=>_.kind==="event"||!ee.has(_.box??_.anchorBox)):j,O=n.boxes.find(_=>_.name===n.leadBox)||null,z=O?await Ga(O.cwd,O.sessionId,{fallbackNewest:!1}):null;if(!z&&O){let _=[...R].reverse().find(V=>V.type==="context.usage"&&V.boxId===O.name);_?.payload?.window&&(z={pct:_.payload.pct??(_.payload.occupancy!=null?_.payload.occupancy/_.payload.window:null),occupancy:_.payload.occupancy??null,window:_.payload.window,windowKnown:!0,model:_.payload.model||null})}let te=[...h].reverse().find(_=>_.role==="assistant"&&_.model),H=te?.model||null,ke=[...n.events||[]].reverse().find(_=>_.type==="model-change"),ie=z?.model||H;ke&&(!te?.ts||ke.at>=te.ts)&&(ie=ke.to);let me=O?await Ce(O.name,{lines:Xe}).catch(()=>""):"",ce=O&&wo(O.agent,me)?await Nn(O.name).catch(()=>me):me,F=O?Er(O,ce):null;if(F&&O){let _=Pl(O,F,ce);if(_){let V=N0(O.name,F.promptId);V.action!=="give-up"&&(V.action==="send"&&(Le(O.name,_.keys,{kind:"auto-reject"}).catch(()=>{}),V.first&&$(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:O.name,provider:O.agent,payload:{ts:Date.now(),promptId:F.promptId,rule:_.id}}).catch(()=>{})),F=null)}}!F&&O&&!ws(O.agent,me)&&!Mo(n.id).length&&(F=Xf(q,{leadBoxId:O.name,provider:O.agent,isAnswered:_=>R.some(V=>V.type==="prompt.answered"&&V.payload?.promptId===_)})),F&&mx(n,O,F);let le=q.filter(_=>!(_.kind==="message"&&_.role==="assistant"&&_.ask&&!String(_.text||"").trim()&&!_.images?.length)),Ae=!!O&&iu(O.name,O.agent,me)&&!F;O&&!O.readyAt&&(Ae||F||me&&gs(O.agent,me))&&(O.readyAt=Date.now(),await ne());let _e=!!O&&!O.readyAt&&Date.now()-(n.createdAt||0)<Uj;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&O&&gs(O.agent,me)&&!F){let _=await Q(),V=we(_,n.id);V?.setup&&!V.setup.connectedAt&&(V.setup.connectedAt=Date.now(),n.setup.connectedAt=V.setup.connectedAt,await $(V,{type:"provider.connected",actor:"system",source:"pane",boxId:O.name,provider:O.agent,payload:{provider:O.agent,ts:V.setup.connectedAt}}).catch(()=>{}),await ne())}let xt=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,je=null;if(c){let _=Date.now()-i.startedAt;if(i.viewId&&!Ae){let V=ku(n.id);V&&(Te(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:V.finishedAt}),await ne())}else if(F||_>IS&&!Ae&&!i.viewId||_>jm){let V=F?"needs-input":_>jm?"timeout":"no-view";ku(n.id,{error:V})&&await $(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:O?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:V}}).catch(()=>{})}else je={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:le,context:z?{pct:z.pct,occupancy:z.occupancy,window:z.window,windowKnown:z.windowKnown,model:z.model}:null,models:{current:ie,options:ax(O?.agent)},pendingPrompt:F,working:Ae,stopping:lE(n.id),leadStarting:_e,handoff:xt,view:je,queued:Mo(n.id).filter(_=>_.kind!=="ship-notify"&&_.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function Hj(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 Mh(e,t){let n=await re(e);if(!n)return null;let r=jo(e).find(f=>f.id===t)||null;if(!r)return null;let o=r.box||null;if(!o)return{items:[],working:!1,box:null,agent:r.agent,task:r.task};let s=await U(n),a=gr(s).filter(f=>f.box===o&&!(f.kind==="message"&&f.role==="assistant"&&f.ask&&!String(f.text||"").trim()&&!f.images?.length)),i=Qf(s.filter(f=>f.boxId===o),a.filter(f=>f.kind==="message")).map(f=>({kind:"command-batch",id:f.id,ts:f.pending?f.ts:(f.anchorTs??f.ts)-1,anchorTs:f.anchorTs,anchorBox:f.anchorBox,agent:f.agent,boxRole:f.boxRole,commands:f.commands,pending:f.pending})),c=[...a,...i].filter(f=>f.ts!=null).sort((f,d)=>f.ts-d.ts),l=n.boxes.find(f=>f.name===o)||null,u=!1;if(l&&l.state==="live"){let f=await Ce(o,{lines:Xe}).catch(()=>"");u=iu(o,l.agent||r.agent,f)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}async function Bu(e,{promptId:t,answers:n,text:r}={}){let o=we(await Q(),e);if(!o)throw new Error(`track "${e}" not found`);nc(e,"prompt-answer");let s=o.boxes.find(h=>h.name===o.leadBox);if(!s)throw new Error(`track "${e}" has no lead box`);if(!await ye(o.leadBox))throw new Error(`lead box "${o.leadBox}" is not running`);let i=await Ap(s);if(i||(i=await Wj(o,s)),!i)throw new Error("no pending prompt to answer");if(t&&t!==i.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");let c;if(i.answerMode==="text"){let h=typeof r=="string"?r.trim():"";if(!h)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(h)||h.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await Ze(o.leadBox,h,{enter:!0,kind:"answer-prompt"}),c={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(i.answerMode==="esc")await Le(o.leadBox,["Escape"],{kind:"answer-prompt"}),c={mode:"keys",value:"Escape",count:1};else if(i.answerMode==="say"){let h=lk(i,n||[],typeof r=="string"?r:"");if(!h)throw new Error("no answer selected \u2014 pick an option or reply in chat");await Pt(o.id,h,{kind:"prompt-answer"}),c={mode:"say",value:h,count:1}}else if(i.provider==="claude"||i.answerMode==="keys"){let h=R0(i,n||[]);await Le(o.leadBox,h,{kind:"answer-prompt"}),c={mode:"keys",value:h.join(" "),count:h.length}}else{let h=Ob(i,n||[]);await Ze(o.leadBox,h,{enter:!0,kind:"answer-prompt"}),c={mode:"text",value:h,count:1}}if(i.answerMode==="say"){let h=i.questions||[];for(let w=0;w<h.length;w++){let g=h[w],b=new Set(Array.isArray(n?.[w])?n[w]:[]),E=[...b].map(R=>g.options?.[R]).filter(Boolean).map(R=>({label:R.label,description:R.description||""})),S=(g.options||[]).map((R,M)=>b.has(M)?null:R?.label).filter(Boolean);Wp(o,s,i,{...c,groupId:i.groupId||i.promptId,questionIndex:w,questionTotal:i.questionTotal??h.length,header:g.header||"",question:g.question||"",multiSelect:!!g.multiSelect,chosen:E,rejected:S})}return await se({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),{ok:!0,promptId:i.promptId,sent:c.count}}let l=i.questions?.[0]||{},u=new Set(Array.isArray(n?.[0])?n[0]:[]),f=[...u].map(h=>l.options?.[h]).filter(Boolean).map(h=>({label:h.label,description:h.description||""})),d=(l.options||[]).map((h,w)=>u.has(w)?null:h?.label).filter(Boolean),p=i.review?"review":/^claude:model-confirm:/.test(i.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(i.promptId||"")?"resume-confirm":void 0;return c={...c,groupId:i.groupId||i.promptId,questionIndex:i.questionIndex??0,questionTotal:i.questionTotal??1,header:l.header||"",question:l.question||"",multiSelect:!!l.multiSelect,chosen:f,rejected:d,...p?{control:p}:{}},await se({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),Wp(o,s,i,c),{ok:!0,promptId:i.promptId,sent:c.count}}async function Wj(e,t){if(!t)return null;let n=await U(e).catch(()=>[]);return Xf(gr(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function Nh(e,{promptId:t,questionIndex:n}={}){let r=we(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 ye(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await Ap(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=O0(a,n);return c.length?(await Le(r.leadBox,c,{kind:"navigate-prompt"}),await se({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 ju(e){let t=Ki.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},Ki.set(e,t)),t}function Mo(e){return(Ki.get(e)?.items??[]).map(t=>({...t}))}function tc(e){let t=Ki.get(e);if(!t)return[];let n=t.items.splice(0);return t.idleSince=null,t.timer&&(clearInterval(t.timer),t.timer=null),n}async function Ph(e){let t=tc(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=we(await Q(),e);if(o)return r=Qs(o,n),await ne(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function Dh(e){let t=ju(e);t.timer||(t.timer=setInterval(()=>Kj(e).catch(()=>{}),qj))}async function Kj(e){let t=Ki.get(e);if(!(!t||t.flushing)){if(!t.items.length){t.timer&&(clearInterval(t.timer),t.timer=null);return}t.flushing=!0;try{let n=we(await Q(),e);if(!n||n.archivedAt){tc(e);return}let r=oa(e);if(r&&!r.finishedAt&&r.step!=="done"&&!r.error){Oo(t,!1);return}let o=await ye(n.leadBox),s=n.boxes.find(c=>c.name===n.leadBox);if(o&&await Yh(o)&&(o=await Ji(n,s,"queue")?await ye(n.leadBox):null,await ne()),!o){Oo(t,!1);return}if(yo(s?.agent)){Oo(t,!1);return}let a=await Ce(n.leadBox,{lines:Xe}).catch(()=>"");if(bl(s?.agent,a)){Oo(t,!1);return}if(wo(s?.agent,a)){let c=await Nn(n.leadBox).catch(()=>a);if(Er(s,c)){Oo(t,!1);return}}if(!Oo(t,!0))return;let i=t.items.shift();t.idleSince=null;try{await Eh(n,s,o,i.text,i.kind??null,i.attachments??null)}catch(c){if(c?.code!=="cli-not-running")throw c;t.items.unshift(i),await Ji(n,s,"queue-gate")}await ne()}finally{t.flushing=!1}}}async function cE(e,t,n,r){let o=yo(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(Qs(e,[n]),await ne()),J0(e.id,o))try{await $(e,{type:"usage.cap.hit",actor:"system",provider:t?.agent??null,boxId:e.leadBox,payload:{...o,blockedKind:r??null}})}catch{}let s=new Error(`${t?.agent??"the lead provider"} is paused \u2014 its ${o.window} spend limit is reached ($${o.spentUsd.toFixed(2)} of $${o.limitUsd.toFixed(2)})`);throw s.usageCap=o,s}async function Gj(e,t){let n=await Ce(e.leadBox,{lines:Xe}).catch(()=>"");if(!wo(t?.agent,n))return!1;let r=await Nn(e.leadBox).catch(()=>n);return!!Er(t,r)}async function Eh(e,t,n,r,o=null,s=null){await cE(e,t,r,o);let a=Gi.get(e.id)||0,i=r,c=!1,l=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(i=rE(r,e.pendingHandoffHydrate.artifact||Co),delete e.pendingHandoffHydrate,c=!0);let u=Array.isArray(s)?s.filter(d=>d&&d.rel):[];if(u.length){let d=FT(u.map(p=>p.rel));i=i.trim()?`${i.trim()}
211
211
 
212
- ${d}`:d}let f=Te(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,...o?{kind:o}:{},...u.length?{attachments:u}:{}});o||Xs(e,null);try{if(await hr({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:na(n.agent),bailOnDialog:!0}),(Ki.get(e.id)||0)!==a){!o&&r.trim()&&(Zs(e,[r]),await ee());let d=new Error("delivery stopped \u2014 the message was handed back as the draft");throw d.interrupted=!0,d}if(await Hj(e,t)){let d=Du(e.id),p={id:Po(),text:r,ts:Date.now(),...o?{kind:o}:{},...u.length?{attachments:u}:{}};d.items.unshift(p),Ph(e.id);let h=new Error("lead is blocked on a prompt \u2014 message queued");throw h.requeued={id:p.id,position:d.items.length},h}await Ze(e.leadBox,i,{...pn(t?.agent,i),kind:c?"lead-handoff-first-prompt":"say"})}catch(d){if(l&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=l),Te(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:f.at,text:r,...d?.interrupted?{reason:"interrupted"}:{},...d?.requeued?{reason:"requeued"}:{}}),d?.requeued)return{queued:!0,...d.requeued};throw d}await nL(e,t,i)||(await iE(e.leadBox,t?.agent,i.length+8,i).catch(()=>{}),Te(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:f.at,text:r,reason:"unsubmitted"}),o||Zs(e,[r])),c&&await re({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function Dh(e,{actions:t}={}){Du(e).items.push({id:Po(),text:Tx(t),ts:Date.now(),kind:"ship-notify"}),Ph(e)}async function Pt(e,t,{kind:n=null,attachments:r=null}={}){let o=Array.isArray(r)?r.filter(p=>p&&typeof p.rel=="string"):[];if((typeof t!="string"||!Ts(t))&&!o.length)throw new Error("text (string) or an attachment required");let s=he(await Z(),e);if(!s)throw new Error(`track "${e}" not found`);if(s.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before driving it`);rw(s);let a=s.boxes.find(p=>p.name===s.leadBox),i=Ts(t);await sE(s,a,i,n),tc(e,"say");let c=await ge(s.leadBox);if(c&&await zh(c)?await Yi(s,a,"say")?(await ee(),c=await ge(s.leadBox)):c=null:!c&&await rc(s)&&(await ee(),c=await ge(s.leadBox)),!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l=Du(e),u=await Ce(s.leadBox,{lines:Xe}).catch(()=>""),f=l.items.length>0||gl(a?.agent,u);if(!f&&wo(a?.agent,u)){let p=await Nn(s.leadBox).catch(()=>u);f=!!Tr(a,p)}if(f){let p={id:Po(),text:i,ts:Date.now(),...n?{kind:n}:{},...o.length?{attachments:o}:{}};return l.items.push(p),Ph(e),n||Xs(s,null),await ee(),{ok:!0,leadBox:s.leadBox,queued:!0,id:p.id,position:l.items.length}}let d;try{d=await Th(s,a,c,i,n,o)}catch(p){if(p?.code!=="cli-not-running"||!await Yi(s,a,"say-gate")||(await ee(),c=await ge(s.leadBox),!c))throw p;d=await Th(s,a,c,i,n,o)}return await ee(),d?.queued?{ok:!0,leadBox:s.leadBox,queued:!0,id:d.id,position:d.position}:{ok:!0,leadBox:s.leadBox}}async function Bh(e,{hint:t}={}){let n=he(await Z(),e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it first`);let r=jm(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";AS(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${GT}
212
+ ${d}`:d}let f=Te(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,...o?{kind:o}:{},...u.length?{attachments:u}:{}});o||Zs(e,null);try{if(await wr({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:ra(n.agent),bailOnDialog:!0}),(Gi.get(e.id)||0)!==a){!o&&r.trim()&&(Qs(e,[r]),await ne());let d=new Error("delivery stopped \u2014 the message was handed back as the draft");throw d.interrupted=!0,d}if(await Gj(e,t)){let d=ju(e.id),p={id:Po(),text:r,ts:Date.now(),...o?{kind:o}:{},...u.length?{attachments:u}:{}};d.items.unshift(p),Dh(e.id);let h=new Error("lead is blocked on a prompt \u2014 message queued");throw h.requeued={id:p.id,position:d.items.length},h}await Ze(e.leadBox,i,{...pn(t?.agent,i),kind:c?"lead-handoff-first-prompt":"say"})}catch(d){if(l&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=l),Te(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:f.at,text:r,...d?.interrupted?{reason:"interrupted"}:{},...d?.requeued?{reason:"requeued"}:{}}),d?.requeued)return{queued:!0,...d.requeued};throw d}await aL(e,t,i)||(await uE(e.leadBox,t?.agent,i.length+8,i).catch(()=>{}),Te(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:f.at,text:r,reason:"unsubmitted"}),o||Qs(e,[r])),c&&await se({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function Bh(e,{actions:t}={}){ju(e).items.push({id:Po(),text:_x(t),ts:Date.now(),kind:"ship-notify"}),Dh(e)}async function Pt(e,t,{kind:n=null,attachments:r=null}={}){let o=Array.isArray(r)?r.filter(p=>p&&typeof p.rel=="string"):[];if((typeof t!="string"||!Es(t))&&!o.length)throw new Error("text (string) or an attachment required");let s=we(await Q(),e);if(!s)throw new Error(`track "${e}" not found`);if(s.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before driving it`);ow(s);let a=s.boxes.find(p=>p.name===s.leadBox),i=Es(t);await cE(s,a,i,n),nc(e,"say");let c=await ye(s.leadBox);if(c&&await Yh(c)?await Ji(s,a,"say")?(await ne(),c=await ye(s.leadBox)):c=null:!c&&await oc(s)&&(await ne(),c=await ye(s.leadBox)),!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l=ju(e),u=await Ce(s.leadBox,{lines:Xe}).catch(()=>""),f=l.items.length>0||bl(a?.agent,u);if(!f&&wo(a?.agent,u)){let p=await Nn(s.leadBox).catch(()=>u);f=!!Er(a,p)}if(f){let p={id:Po(),text:i,ts:Date.now(),...n?{kind:n}:{},...o.length?{attachments:o}:{}};return l.items.push(p),Dh(e),n||Zs(s,null),await ne(),{ok:!0,leadBox:s.leadBox,queued:!0,id:p.id,position:l.items.length}}let d;try{d=await Eh(s,a,c,i,n,o)}catch(p){if(p?.code!=="cli-not-running"||!await Ji(s,a,"say-gate")||(await ne(),c=await ye(s.leadBox),!c))throw p;d=await Eh(s,a,c,i,n,o)}return await ne(),d?.queued?{ok:!0,leadBox:s.leadBox,queued:!0,id:d.id,position:d.position}:{ok:!0,leadBox:s.leadBox}}async function jh(e,{hint:t}={}){let n=we(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=Lm(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";$S(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${YT}
213
213
 
214
- What to preview: ${String(t).trim()}`:GT;try{await Pt(e,a,{kind:"spin-up-view"})}catch(i){throw yu(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Bu(e){let t=he(await Z(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);Ki.set(e,(Ki.get(e)||0)+1);let n=ec(e),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=Js.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=Zs(t,r),await ee()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=zj(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,No(Wj)]);let a=he(await Z(),e)||t;return{ok:!0,interrupted:s.result!=="no-session",stopped:s.result==="stopped"||s.result==="stopped-late",stopping:!s.result,dropped:n.length,restored:s.restored,draftRev:a.draftRev||0}}function aE(e){let t=Js.get(e);return!!t&&!t.canceled}function tc(e,t){let n=Js.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function jh(e){tc(e,"track-ended"),Ki.delete(e),ec(e)}function zj(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}),Js.set(e,r),(async()=>{let s=he(await Z(),e),a=s?.boxes.find(g=>g.name===s.leadBox),i=s?await ge(s.leadBox):null,c=!1,l=!1;if(i){e:for(let g=0;g<qj&&!r.canceled;g++){await Le(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let k of Kj){await No(k);let S=await Ce(s.leadBox,{lines:Xe}).catch(()=>"");if(!ws(a?.agent,S)){c=!0;break e}}}if(!c){l=!0;for(let g=0;g<Vj&&!r.canceled&&(await No(Gj),!r.canceled);g++){let k=await Ce(s.leadBox,{lines:Xe}).catch(()=>"");if(!ws(a?.agent,k)){c=!0;break}await Le(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=he(await Z(),e)||s,f=u?.boxes.find(g=>g.name===u.leadBox)||a,d=null,p=null;u&&f&&i&&c&&!r.canceled&&(d=await Zj(u,f).catch(()=>null),d||(p=await tL(u,f).catch(()=>null)));let h=u&&i&&!r.canceled?await Jj(u).catch(()=>null):null,w=[d||p,...r.queuedTexts].filter(Boolean);u&&w.length&&(r.restored=Zs(u,w),await ee()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await Yj(u||s,f,{ts:r.startedAt,result:r.result,dropped:t,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!d,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!h,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await re({flow:"interrupt",phase:r.result==="gave-up"?"failed":"done",trackId:e,sessionName:u?.leadBox,agent:f?.agent,result:r.result,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!d,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!h}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),Js.get(e)===r&&Js.delete(e),o()}),r}async function Yj(e,t,n){await $(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function Jj(e){let t=vu(await F(e));if(!t?.offerId)return null;let n=t.offerType==="exists";return await $(e,{type:n?"pr.exists.answered":"pr.offer.answered",actor:"user",source:"orchestrator",boxId:t.box,payload:{ts:Date.now(),offerId:t.offerId,...n?{choice:"dismiss"}:{action:"dismiss",actions:null},reason:"interrupt"}}),t.offerId}async function Zj(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 Xj){await No(r);let o=await Ce(e.leadBox,{lines:Xe}).catch(()=>""),s=ei(t.agent,o);if(s&&yl(n.text,s))return await iE(e.leadBox,t.agent,n.text.length+8),Te(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function tL(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>Qj||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!We(r.text))return null;for(let s of eL){await No(s);let a;try{a=await yp(t,{})}catch{return null}if(Lb(a,r))return null;let i=await Ce(e.leadBox,{lines:Xe}).catch(()=>"");if(ei(t.agent,i))return null}return Te(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function nL(e,t,n){return ni({sessionName:e.leadBox,agent:t?.agent,agentCmd:na(t?.agent),text:n,trackId:e.id,flow:"say"})}async function iE(e,t,n,r=null){for(let o=0;o<3;o++){await ls(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await No(200);let s=await Ce(e,{lines:Xe}).catch(()=>""),a=ei(t,s);if(!a||r&&!yl(r,a)&&!(t==="codex"&&Ff(r,a)))return!0;n=a.length+8}return!1}function Xs(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 Zs(e,t){let n=[],r=o=>n.some(s=>We(s).includes(We(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?Xs(e,n.join(`
214
+ What to preview: ${String(t).trim()}`:YT;try{await Pt(e,a,{kind:"spin-up-view"})}catch(i){throw ku(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Lu(e){let t=we(await Q(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);Gi.set(e,(Gi.get(e)||0)+1);let n=tc(e),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=Xs.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=Qs(t,r),await ne()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=Zj(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,No(Vj)]);let a=we(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 lE(e){let t=Xs.get(e);return!!t&&!t.canceled}function nc(e,t){let n=Xs.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function Lh(e){nc(e,"track-ended"),Gi.delete(e),tc(e)}function Zj(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}),Xs.set(e,r),(async()=>{let s=we(await Q(),e),a=s?.boxes.find(g=>g.name===s.leadBox),i=s?await ye(s.leadBox):null,c=!1,l=!1;if(i){e:for(let g=0;g<zj&&!r.canceled;g++){await Le(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let b of Yj){await No(b);let E=await Ce(s.leadBox,{lines:Xe}).catch(()=>"");if(!ws(a?.agent,E)){c=!0;break e}}}if(!c){l=!0;for(let g=0;g<Xj&&!r.canceled&&(await No(Jj),!r.canceled);g++){let b=await Ce(s.leadBox,{lines:Xe}).catch(()=>"");if(!ws(a?.agent,b)){c=!0;break}await Le(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=we(await Q(),e)||s,f=u?.boxes.find(g=>g.name===u.leadBox)||a,d=null,p=null;u&&f&&i&&c&&!r.canceled&&(d=await nL(u,f).catch(()=>null),d||(p=await sL(u,f).catch(()=>null)));let h=u&&i&&!r.canceled?await eL(u).catch(()=>null):null,w=[d||p,...r.queuedTexts].filter(Boolean);u&&w.length&&(r.restored=Qs(u,w),await ne()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await Qj(u||s,f,{ts:r.startedAt,result:r.result,dropped:t,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!d,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!h,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await se({flow:"interrupt",phase:r.result==="gave-up"?"failed":"done",trackId:e,sessionName:u?.leadBox,agent:f?.agent,result:r.result,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!d,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!h}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),Xs.get(e)===r&&Xs.delete(e),o()}),r}async function Qj(e,t,n){await $(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function eL(e){let t=Tu(await U(e));if(!t?.offerId)return null;let n=t.offerType==="exists";return await $(e,{type:n?"pr.exists.answered":"pr.offer.answered",actor:"user",source:"orchestrator",boxId:t.box,payload:{ts:Date.now(),offerId:t.offerId,...n?{choice:"dismiss"}:{action:"dismiss",actions:null},reason:"interrupt"}}),t.offerId}async function nL(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 tL){await No(r);let o=await Ce(e.leadBox,{lines:Xe}).catch(()=>""),s=ti(t.agent,o);if(s&&kl(n.text,s))return await uE(e.leadBox,t.agent,n.text.length+8),Te(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function sL(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>rL||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!We(r.text))return null;for(let s of oL){await No(s);let a;try{a=await bp(t,{})}catch{return null}if(Fb(a,r))return null;let i=await Ce(e.leadBox,{lines:Xe}).catch(()=>"");if(ti(t.agent,i))return null}return Te(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function aL(e,t,n){return ri({sessionName:e.leadBox,agent:t?.agent,agentCmd:ra(t?.agent),text:n,trackId:e.id,flow:"say"})}async function uE(e,t,n,r=null){for(let o=0;o<3;o++){await ls(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await No(200);let s=await Ce(e,{lines:Xe}).catch(()=>""),a=ti(t,s);if(!a||r&&!kl(r,a)&&!(t==="codex"&&Hf(r,a)))return!0;n=a.length+8}return!1}function Zs(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 Qs(e,t){let n=[],r=o=>n.some(s=>We(s).includes(We(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?Zs(e,n.join(`
215
215
 
216
- `),{source:"restore"})?.text??null:null}function oL(e,t){let n=We(t);if(!n)return!1;if(Mo(e.id).some(o=>We(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>rL)break;if(!(s.type!=="said"||!s.text||We(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function Lh(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=he(await Z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=Ts(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&oL(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;We(o).includes(We(i))?Xs(r,o):Xs(r,`${i}
216
+ `),{source:"restore"})?.text??null:null}function cL(e,t){let n=We(t);if(!n)return!1;if(Mo(e.id).some(o=>We(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>iL)break;if(!(s.type!=="said"||!s.text||We(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function Fh(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=we(await Q(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=Es(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&cL(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;We(o).includes(We(i))?Zs(r,o):Zs(r,`${i}
217
217
 
218
- ${o}`,{source:"restore"})}else Xs(r,o);return await ee(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function Fh(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=he(await Z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await ge(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(f=>f.name===r.leadBox)?.agent||o.agent||"claude",i=ox(a,n),l=[...r.events||[]].reverse().find(f=>f.type==="model-change")?.to??null;l||(l=(await Ka(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await hr({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:na(o.agent)});let u=await sx(a,r.leadBox,i);return Te(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await ee(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function cE(e){for(let t of e){if(!t||!await Es(t))continue;let n=await P0(t).catch(()=>null);if(!n)continue;if((await z.stat(J.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function Dt(e){let t=e;return t?t.kind==="multi"?Array.isArray(t.repos)?t.repos.filter(Boolean):[]:t.base?[{name:J.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function _o(e){let t=[];for(let n of Dt(e?.workspace)){if(!n?.dir)continue;let r=await ui(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await di(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function lE(e){let t=e;typeof t=="string"&&!J.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await Zo(t)??await Fc(t));let n=await cE([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 sL(e,t,n,r){let o=`track/${iw(t)}-${e}`,s=[];try{await z.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await lE(i);if(s.some(p=>p.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await Se(c).catch(()=>null),u=J.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let p=2;a.has(u);p++)u=`${J.basename(c)}-${p}`;a.add(u);let f=J.join(n,u),d=await Is(c);await _s(c,f,o,d),s.push({name:u,dir:f,base:c,baseRef:d,repo:l})}return await nc(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await Rt(i.base,i.dir).catch(()=>{});throw await z.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function Uh(e,t){let n=await Z(),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 lE(typeof t=="string"?t.trim():t);if((o.repos??[]).some(d=>d?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await Se(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(d=>d?.name).filter(Boolean)]),c=J.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let d=2;i.has(c);d++)c=`${J.basename(s)}-${d}`;let l=J.join(o.dir,c),u=await Is(s);await D0(s,o.branch)?await Nl(s,l,o.branch):await _s(s,l,o.branch,u);let f={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),f],await nc(o.dir,o.repos,o.branch),Te(r,"retagged",{action:"add",repo:a??s,name:c,workspace:uE(o)}),await ee(),f}async function Hh(e,t){let n=await Z(),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 Nt.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 ui(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await di(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 Rt(s.base,s.dir).catch(()=>{}),await z.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await nc(o.dir,o.repos,o.branch),Te(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:uE(o)}),await ee(),{removed:s.name}}async function aL(e,t,{repo:n,repos:r,cwd:o}={}){await z.mkdir(Hi,{recursive:!0});let s=J.join(Hi,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return sL(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!J.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await Zo(n)??await Fc(n));let i=await cE([n,o,Ej]);if(i){let c=`track/${iw(t)}-${e}`;try{let l=await Is(i);await _s(i,s,c,l),await Vi(s);let u=await Se(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await z.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await z.mkdir(s,{recursive:!0}),await Cp(s),await Vi(s),{dir:s,base:null,branch:null,kind:"repo"}}async function Vi(e){try{await z.writeFile(J.join(e,"AGENTS.md"),Ui,{flag:"wx"})}catch{return}await uL(e,["/AGENTS.md"])}function lL(e,t){let n=e.map(r=>`- \`${r.name}/\`${r.repo?` \u2014 github.com/${r.repo}`:""}${r.baseRef?` (forked from ${r.baseRef})`:""}`).join(`
219
- `);return`${cL}
218
+ ${o}`,{source:"restore"})}else Zs(r,o);return await ne(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function Uh(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=we(await Q(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await ye(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(f=>f.name===r.leadBox)?.agent||o.agent||"claude",i=ix(a,n),l=[...r.events||[]].reverse().find(f=>f.type==="model-change")?.to??null;l||(l=(await Ga(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await wr({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:ra(o.agent)});let u=await cx(a,r.leadBox,i);return Te(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await ne(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function dE(e){for(let t of e){if(!t||!await As(t))continue;let n=await j0(t).catch(()=>null);if(!n)continue;if((await J.stat(Z.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function Dt(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 _o(e){let t=[];for(let n of Dt(e?.workspace)){if(!n?.dir)continue;let r=await di(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await fi(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function fE(e){let t=e;typeof t=="string"&&!Z.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await Zo(t)??await Hc(t));let n=await dE([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 lL(e,t,n,r){let o=`track/${cw(t)}-${e}`,s=[];try{await J.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await fE(i);if(s.some(p=>p.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await Se(c).catch(()=>null),u=Z.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let p=2;a.has(u);p++)u=`${Z.basename(c)}-${p}`;a.add(u);let f=Z.join(n,u),d=await $s(c);await Is(c,f,o,d),s.push({name:u,dir:f,base:c,baseRef:d,repo:l})}return await rc(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await Rt(i.base,i.dir).catch(()=>{});throw await J.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function Hh(e,t){let n=await Q(),r=we(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 unarchive it first");let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track \u2014 a single-repo Track's workspace IS its repo checkout; create the Track with multiple repos tagged instead");let s=await fE(typeof t=="string"?t.trim():t);if((o.repos??[]).some(d=>d?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await Se(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(d=>d?.name).filter(Boolean)]),c=Z.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let d=2;i.has(c);d++)c=`${Z.basename(s)}-${d}`;let l=Z.join(o.dir,c),u=await $s(s);await L0(s,o.branch)?await Dl(s,l,o.branch):await Is(s,l,o.branch,u);let f={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),f],await rc(o.dir,o.repos,o.branch),Te(r,"retagged",{action:"add",repo:a??s,name:c,workspace:pE(o)}),await ne(),f}async function Wh(e,t){let n=await Q(),r=we(n,e);if(!r)throw new Error(`track "${e}" not found`);let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track");let s=(o.repos??[]).find(c=>c&&(c.name===t||c.repo===t||c.base===t));if(!s)throw new Error(`repo "${t}" is not tagged on this Track`);if((o.repos??[]).filter(Boolean).length<=1)throw new Error("can't untag the last repo \u2014 archive or delete the Track instead");for(let c of Nt.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 di(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await fi(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 Rt(s.base,s.dir).catch(()=>{}),await J.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),Te(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:pE(o)}),await ne(),{removed:s.name}}async function uL(e,t,{repo:n,repos:r,cwd:o}={}){await J.mkdir(Wi,{recursive:!0});let s=Z.join(Wi,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return lL(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!Z.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await Zo(n)??await Hc(n));let i=await dE([n,o,$j]);if(i){let c=`track/${cw(t)}-${e}`;try{let l=await $s(i);await Is(i,s,c,l),await zi(s);let u=await Se(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await J.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await J.mkdir(s,{recursive:!0}),await Mp(s),await zi(s),{dir:s,base:null,branch:null,kind:"repo"}}async function zi(e){try{await J.writeFile(Z.join(e,"AGENTS.md"),Hi,{flag:"wx"})}catch{return}await mL(e,["/AGENTS.md"])}function pL(e,t){let n=e.map(r=>`- \`${r.name}/\`${r.repo?` \u2014 github.com/${r.repo}`:""}${r.baseRef?` (forked from ${r.baseRef})`:""}`).join(`
219
+ `);return`${fL}
220
220
 
221
221
  This directory is NOT a git repo. It is a bostrat Track workspace holding one
222
222
  git worktree per tagged repo, ALL on the same branch \`${t}\`:
@@ -228,20 +228,20 @@ push / open PRs) in each repo separately, always on that shared branch. Work
228
228
  only needs to land in the repos it actually touches \u2014 an untouched repo's
229
229
  branch simply stays at its fork point and never gets pushed. When asked to run
230
230
  or preview an app, run it from that app's own repo directory.
231
- `}async function nc(e,t,n){let r=lL(t,n);for(let o of["CLAUDE.md","AGENTS.md"])await z.writeFile(J.join(e,o),r).catch(()=>{})}async function fE(e){let{stdout:t}=await XT("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return J.resolve(e,t.trim())}async function uL(e,t){try{let n=await fE(e);await z.mkdir(J.dirname(n),{recursive:!0});let r=await z.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
232
- `).includes(s));o.length&&await z.appendFile(n,(r.endsWith(`
231
+ `}async function rc(e,t,n){let r=pL(t,n);for(let o of["CLAUDE.md","AGENTS.md"])await J.writeFile(Z.join(e,o),r).catch(()=>{})}async function hE(e){let{stdout:t}=await eE("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return Z.resolve(e,t.trim())}async function mL(e,t){try{let n=await hE(e);await J.mkdir(Z.dirname(n),{recursive:!0});let r=await J.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
232
+ `).includes(s));o.length&&await J.appendFile(n,(r.endsWith(`
233
233
  `)||!r?"":`
234
234
  `)+o.join(`
235
235
  `)+`
236
- `)}catch{}}async function dL(e,t){try{let n=await fE(e),r=await z.readFile(n,"utf8"),o=r.split(`
236
+ `)}catch{}}async function hL(e,t){try{let n=await hE(e),r=await J.readFile(n,"utf8"),o=r.split(`
237
237
  `).filter(s=>s!==t);o.length!==r.split(`
238
- `).length&&await z.writeFile(n,o.join(`
239
- `))}catch{}}async function Wh(){let e={refreshed:0,removed:0,codexGlobal:null};try{await z.mkdir(En,{recursive:!0}),await z.writeFile(J.join(En,"CLAUDE.md"),iL).catch(()=>{}),await z.writeFile(J.join(En,"AGENTS.md"),Ui).catch(()=>{});let t=process.env.CODEX_HOME||J.join(process.env.HOME||"/tmp",".codex");if((await z.stat(t).catch(()=>null))?.isDirectory()){let r=J.join(t,"AGENTS.md"),o=await z.readFile(r,"utf8").catch(()=>null);o===null?(await z.writeFile(r,yh,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):gh(o)&&o!==yh&&(await z.writeFile(r,yh).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[Hi,ta]){let o=await z.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=J.join(r,s.name),i=J.join(a,"AGENTS.md"),c=await z.readFile(i,"utf8").catch(()=>null);c!==null&&gh(c)&&c!==Ui&&(await z.writeFile(i,Ui).catch(()=>{}),e.refreshed++);let l=J.join(a,"CLAUDE.md"),u=await z.readFile(l,"utf8").catch(()=>null);u!==null&&gh(u)&&(await z.rm(l,{force:!0}).catch(()=>{}),await dL(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function pE(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of Dt(t))n.base&&n.dir&&await Rt(n.base,n.dir).catch(()=>{});await z.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await Rt(t.base,t.dir):await z.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function ju({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 Zi(o,s),i=await Z(),c=Po().slice(0,8),l=await aL(c,e,{repo:n,repos:r,cwd:t}),u=new Set(i.tracks.flatMap(h=>(h.boxes||[]).map(w=>w.name))),f=`${e.trim()} lead`;u.has(al(f))&&(f=`${e.trim().slice(0,50).trim()} ${c} lead`);let d=await pr(f,l.dir,{agentCmd:a,agent:o,freshWorkspace:!0}),p={id:c,name:e.trim(),cwd:d.cwd,workspace:l,leadBox:d.name,boxes:[Qh(d,"lead","live")],events:[],createdAt:Date.now()};return Te(p,"opened",{agent:o,box:d.name,skipPermissions:s,name:p.name,cwd:p.cwd,workspace:{base:l.base??null,branch:l.branch,kind:l.kind,...l.baseRef?{baseRef:l.baseRef}:{},...l.repo?{repo:l.repo}:{},...l.repos?{repos:l.repos.map(({name:h,base:w,baseRef:g,repo:k})=>({name:h,base:w,baseRef:g,repo:k}))}:{}}}),i.tracks.push(p),await ee(),Xa({cwd:d.cwd,sessionName:d.name,agent:o,agentCmd:a,onReady:async()=>{let h=p.boxes.find(w=>w.name===p.leadBox);!h||h.readyAt||(h.readyAt=Date.now(),await ee())}}),Mt(p)}async function qh({provider:e="claude",fresh:t=!1}={}){if(!fL.has(e))throw new Error(`unknown setup provider "${e}" (claude | codex | cursor)`);let r=(await Z()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===e&&!u.archivedAt);if(r){if(!t){let u=await Mt(r);if(u.boxes.find(d=>d.name===u.leadBox)?.state==="live")return u}await Do(r.id).catch(()=>{})}let o=(await Zi(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=Po().slice(0,8),a=J.join(En,"setup",s);await z.mkdir(a,{recursive:!0});let i=await pr(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&Xa({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:[Qh(i,"lead","live")],events:[],createdAt:Date.now()};return Te(c,"opened",{agent:e,box:i.name,skipPermissions:!1,trackKind:"setup",name:c.name,cwd:c.cwd,workspace:{base:null,branch:null,kind:"scratch"}}),(await Z()).tracks.push(c),await ee(),Mt(c)}async function Kh(e,t,n){await Zd(t.cwd).catch(()=>{}),await MS(e).catch(()=>{});let r=ea.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),ea.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of jo(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await uw(a).catch(()=>{}),Nt.delete(a.id);for(let a of Object.values(t.subtasks||{}))a.finishedAt||(a.step="error",a.error=n,a.canceled=!0,a.finishedAt=Date.now());let o=await Z(),s=new Set((o.tracks||[]).filter(a=>a.id!==e&&!a.archivedAt).flatMap(a=>(a.boxes||[]).map(i=>i.name)));for(let a of t.boxes)s.has(a.name)||await Yt(a.name).catch(()=>{})}async function Gh(e,{cascadeMocks:t=!0,cascadeRunbooks:n=!1}={}){let r=await Z(),o=r.tracks.findIndex(a=>a.id===e);if(o===-1)throw new Error(`track "${e}" not found`);let s=r.tracks[o];return t||await tT(s),jh(e),await Kh(e,s,"track deleted"),n?await CT(e).catch(()=>{}):await OT(e).catch(()=>{}),await cx(),await pE(s),t&&await nT(e).catch(()=>{}),t?await bT(e).catch(()=>{}):await yT(s).catch(()=>{}),Te(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await ee(),{ok:!0,id:e,name:s.name,boxes:s.boxes.length}}async function Do(e){let t=await Z(),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(),jh(e),Te(n,"archived",{boxes:n.boxes.length}),await ee(),n.kind==="setup"?(await mE(e),Mt(n)):(zi.add(e),hL(e).catch(()=>{}).finally(()=>zi.delete(e)),{...await Mt(n),archiving:!0})}async function hL(e){try{await wL(e)}catch{}await mE(e).catch(()=>{})}async function mE(e){let t=await Z(),n=he(t,e);if(!(!n||!n.archivedAt)){await Kh(e,n,"track archived");for(let r of n.boxes)Fr.has(r.state)||(r.state="stopped");await ee()}}async function wL(e){let t=await Z(),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 ge(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await Ck(n.leadBox,i.cwd,{timeoutMs:mL})),s="lead-cli"}catch{}if(r||(r=Vk(n,await F(n).catch(()=>[]))),!r)return;let c={text:r,source:s,at:Date.now()};o.length&&(c.items=o),n.beat=c,await $(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 ee()}async function qn(e,t){let n=await tt(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await Vh(n);if(r.length){for(let o of r)await ko(o.repo,o.number,!0).catch(()=>{});return!1}try{return await Do(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function Vh(e){return(await xo().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 Kn(e,t){return Lu(e,t,"merged")}async function Bo(e,t){let n=await tt(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 Vh(n);if(o.length){let c=[...n.followupPending||[],r];for(let l of o)await Px(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=he(await Z(),n.trackId);if(!a)return null;let i=s[0];return Ai(Mt(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 Lu(e,t,n="merged"){let r=await tt(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 Vh(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await Nx(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];try{return await Pt(r.trackId,hE(a),{kind:"merge-notify"}),!0}catch{return!1}}function hE(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 ${VT[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 ${VT[i.outcome]??i.outcome}`).join(`
238
+ `).length&&await J.writeFile(n,o.join(`
239
+ `))}catch{}}async function qh(){let e={refreshed:0,removed:0,codexGlobal:null};try{await J.mkdir(En,{recursive:!0}),await J.writeFile(Z.join(En,"CLAUDE.md"),dL).catch(()=>{}),await J.writeFile(Z.join(En,"AGENTS.md"),Hi).catch(()=>{});let t=process.env.CODEX_HOME||Z.join(process.env.HOME||"/tmp",".codex");if((await J.stat(t).catch(()=>null))?.isDirectory()){let r=Z.join(t,"AGENTS.md"),o=await J.readFile(r,"utf8").catch(()=>null);o===null?(await J.writeFile(r,bh,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):yh(o)&&o!==bh&&(await J.writeFile(r,bh).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[Wi,na]){let o=await J.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 J.readFile(i,"utf8").catch(()=>null);c!==null&&yh(c)&&c!==Hi&&(await J.writeFile(i,Hi).catch(()=>{}),e.refreshed++);let l=Z.join(a,"CLAUDE.md"),u=await J.readFile(l,"utf8").catch(()=>null);u!==null&&yh(u)&&(await J.rm(l,{force:!0}).catch(()=>{}),await hL(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function wE(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of Dt(t))n.base&&n.dir&&await Rt(n.base,n.dir).catch(()=>{});await J.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await Rt(t.base,t.dir):await J.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function Fu({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 Qi(o,s),i=await Q(),c=Po().slice(0,8),l=await uL(c,e,{repo:n,repos:r,cwd:t}),u=new Set(i.tracks.flatMap(h=>(h.boxes||[]).map(w=>w.name))),f=`${e.trim()} lead`;u.has(cl(f))&&(f=`${e.trim().slice(0,50).trim()} ${c} lead`);let d=await mr(f,l.dir,{agentCmd:a,agent:o,freshWorkspace:!0}),p={id:c,name:e.trim(),cwd:d.cwd,workspace:l,leadBox:d.name,boxes:[ew(d,"lead","live")],events:[],createdAt:Date.now()};return Te(p,"opened",{agent:o,box:d.name,skipPermissions:s,name:p.name,cwd:p.cwd,workspace:{base:l.base??null,branch:l.branch,kind:l.kind,...l.baseRef?{baseRef:l.baseRef}:{},...l.repo?{repo:l.repo}:{},...l.repos?{repos:l.repos.map(({name:h,base:w,baseRef:g,repo:b})=>({name:h,base:w,baseRef:g,repo:b}))}:{}}}),i.tracks.push(p),await ne(),Za({cwd:d.cwd,sessionName:d.name,agent:o,agentCmd:a,onReady:async()=>{let h=p.boxes.find(w=>w.name===p.leadBox);!h||h.readyAt||(h.readyAt=Date.now(),await ne())}}),Mt(p)}async function Kh({provider:e="claude",fresh:t=!1}={}){if(!wL.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 Mt(r);if(u.boxes.find(d=>d.name===u.leadBox)?.state==="live")return u}await Do(r.id).catch(()=>{})}let o=(await Qi(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=Po().slice(0,8),a=Z.join(En,"setup",s);await J.mkdir(a,{recursive:!0});let i=await mr(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&Za({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:[ew(i,"lead","live")],events:[],createdAt:Date.now()};return Te(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 ne(),Mt(c)}async function Gh(e,t,n){await ef(t.cwd).catch(()=>{}),await DS(e).catch(()=>{});let r=ta.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),ta.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of jo(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await dw(a).catch(()=>{}),Nt.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 Yt(a.name).catch(()=>{})}async function Vh(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 oT(s),Lh(e),await Gh(e,s,"track deleted"),n?await PT(e).catch(()=>{}):await NT(e).catch(()=>{}),await dx(),await wE(s),t&&await sT(e).catch(()=>{}),t?await vT(e).catch(()=>{}):await xT(s).catch(()=>{}),Te(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await ne(),{ok:!0,id:e,name:s.name,boxes:s.boxes.length}}async function Do(e){let t=await Q(),n=we(t,e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is already archived`);return n.archivedAt=Date.now(),Lh(e),Te(n,"archived",{boxes:n.boxes.length}),await ne(),n.kind==="setup"?(await gE(e),Mt(n)):(Yi.add(e),bL(e).catch(()=>{}).finally(()=>Yi.delete(e)),{...await Mt(n),archiving:!0})}async function bL(e){try{await kL(e)}catch{}await gE(e).catch(()=>{})}async function gE(e){let t=await Q(),n=we(t,e);if(!(!n||!n.archivedAt)){await Gh(e,n,"track archived");for(let r of n.boxes)Ur.has(r.state)||(r.state="stopped");await ne()}}async function kL(e){let t=await Q(),n=we(t,e);if(!n||!n.archivedAt)return;let r=null,o=[],s="derived",a=(n.events||[]).some(l=>l.type==="said"),i=n.leadBox?await ye(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await Pk(n.leadBox,i.cwd,{timeoutMs:yL})),s="lead-cli"}catch{}if(r||(r=Jk(n,await U(n).catch(()=>[]))),!r)return;let c={text:r,source:s,at:Date.now()};o.length&&(c.items=o),n.beat=c,await $(n,{type:"track.summary.recorded",actor:"orchestrator",source:"orchestrator",boxId:n.leadBox||null,provider:i?.agent||null,payload:o.length?{text:r,items:o,source:s}:{text:r,source:s}}).catch(()=>{}),await ne()}async function qn(e,t){let n=await tt(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await zh(n);if(r.length){for(let o of r)await ko(o.repo,o.number,!0).catch(()=>{});return!1}try{return await Do(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function zh(e){return(await xo().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 Kn(e,t){return Uu(e,t,"merged")}async function Bo(e,t){let n=await tt(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 zh(n);if(o.length){let c=[...n.followupPending||[],r];for(let l of o)await jx(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=we(await Q(),n.trackId);if(!a)return null;let i=s[0];return _i(Mt(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 Uu(e,t,n="merged"){let r=await tt(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 zh(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await Bx(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];try{return await Pt(r.trackId,yE(a),{kind:"merge-notify"}),!0}catch{return!1}}function yE(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 ${JT[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 ${JT[i.outcome]??i.outcome}`).join(`
240
240
  `),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}
241
241
  ${s}
242
- ${a}`}async function zh(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<Wa()?!1:Mn(e.name)}async function Yi(e,t,n){return!t||e.archivedAt||Fr.has(t.state)?!1:(await re({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 Yt(t.name).catch(()=>{}),t.state="stopped",rc(e))}async function rc(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=bh.get(r.name);if(o)return o;let s=gL(e,r,{freshSession:t,reason:n}).finally(()=>bh.delete(r.name));return bh.set(r.name,s),s}async function gL(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||Fr.has(t.state)||await ge(t.name))return!1;let o=n===!0,s=o?Po():null,a=o?Ua(Ih(t.agent),s,t.name):$h(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await sl(a);if(i===as)return Te(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===is&&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(Qs(t)))}:null,l=Date.now();if(o){let u=Qs(t),f=u[u.length-1];f.endedAt==null&&(f.endedAt=l),f.endReason==null&&(f.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 pr(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=va(u.hookToken),Xa({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a}),t.state="live",o&&Te(e,"lead-refreshed",{box:t.name,agent:t.agent,fromSessionId:c.sessionId,toSessionId:s,epoch:t.epochs.length-1,reason:r||"fresh-session"}),Te(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),Te(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function Fu(e,{freshSession:t=!1}={}){let n=await Z(),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,zi.delete(e),Te(r,"unarchived",{}),await rc(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await ee(),Mt(r)}async function Yh(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>Eh)throw new Error(`name too long (max ${Eh} chars)`);let r=await Z(),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 Mt(o);let s=o.name;return o.name=n,Te(o,"renamed",{from:s,to:n}),await ee(),Mt(o)}async function Jh(){let e=await Z(),t=0;for(let n of e.tracks||[])n.transferredTo&&Dl(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await ee(),t}async function Xh(){let e=await Z(),t=new Set((await zt()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!Ve(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(Ve(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await Yt(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):Te(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!Fr.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await ee(),r}async function Uu(e,{freshSession:t=!1}={}){let n=await Z(),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`);rw(r);let o=r.boxes.find(i=>i.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(Fr.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await ge(r.leadBox)){let i=await Ce(r.leadBox,{lines:Xe}).catch(()=>"");if(gl(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await Yt(r.leadBox),o.state="stopped"}let a=await rc(r,t?{freshSession:!0,reason:"loop-fire"}:{});if(await ee(),!a)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Mt(r)}async function Zh(e,t,n){let r=await te(e);if(!r)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let o=await F(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 Uu(e),await $(r,{type:"box.fullscreen.answered",actor:"user",source:"orchestrator",boxId:r.leadBox,payload:{ts:Date.now(),offerId:t,action:n?"restarted":"dismiss"}}).catch(()=>{}),{ok:!0,action:n?"restarted":"dismiss"}}function zT(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return hu({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function Qs(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 Ou(e,t){let n=await Z(),r=he(n,e);r&&(r.handoff={...r.handoff||{},...t},await ee())}function wE(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 ew(){let e=await Z(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=wE(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await ge(r.fromBox).catch(()=>null),l=n.boxes.find(u=>u.name===r.fromBox);if(c&&l&&c.agent===r.toAgent&&r.toAgent!==l.agent){let u=Date.now(),f=Qs(l),d=f[f.length-1],p=d.agent,h=d.sessionId??null;d.endedAt=u,r.reason&&(d.endReason=r.reason);let w=c.agent==="claude"&&!!c.sessionId;f.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:w,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.sessionId=c.sessionId||null,l.pinned=w,l.state="live",n.pendingHandoffHydrate={artifact:Co,at:u},Te(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:p,toAgent:r.toAgent,fromSessionId:h,toSessionId:c.sessionId||null,epoch:f.length-1,singleBox:!0,skipPermissions:r.skipPermissions,reason:r.reason??null,handoffStartedAt:r.startedAt,recovered:!0}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await re({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 re({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await Yt(i).catch(()=>{}),a&&await Yt(a).catch(()=>{})}return t&&await ee(),t}async function Hu(e,t,n=!0,r=null){let o=ea.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=he(await Z(),e);if(!s)throw new Error(`track "${e}" not found`);tc(e,"handoff");let a=await Zi(t,n),i=yo(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 ge(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:tE(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return ea.set(e,l),await Ou(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),yL(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 Ou(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),re({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),re({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function yL(e,t,n,r,o){let s=async(B,T={})=>{e.step=B,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${B}`),await Ou(e.trackId,{step:B,toBox:e.toBox}),await re({flow:"lead-handoff",phase:B,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:T.sessionName,...T})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await Z(),i=he(a,e.trackId)?.boxes.find(B=>B.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",yo(c))e.checkpoint="skipped-capped";else try{await tp(e.fromBox,{timeoutMs:QT})}catch(B){e.checkpoint="reconstructed",await re({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:B?.message||String(B)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await np(e.trackId,n.cwd,{trackName:t.name||t.id}).catch(()=>null),await s("checkpoint-degraded",{sessionName:e.fromBox,checkpoint:e.checkpoint,statusArtifact:e.statusArtifact})),await s("swap",{cwd:n.cwd,agentCmd:r});let d=await lp(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let p=Db(d.launchCmd);await hr({cwd:n.cwd,sessionId:d.sessionId,sessionName:e.fromBox,agent:o,agentCmd:na(o),launchEcho:p}).catch(B=>{if(B?.code!=="cli-not-running")throw B});let h=Bf(await Ce(e.fromBox,{lines:Xe}).catch(()=>""),p);if(!gs(o,h)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let B=$h(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await lp(e.fromBox,{agentCmd:B,agent:c,resumeSessionId:l,pinned:u});let T=await Z(),_=he(T,e.trackId);if(_){let O=_.boxes.find(I=>I.name===e.fromBox);O&&(O.state="live"),Te(_,"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 ee()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let w=await Z(),g=he(w,e.trackId);if(!g)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let k=g.boxes.find(B=>B.name===e.fromBox);if(!k)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let S=Date.now(),E=Qs(k),R=E[E.length-1];R.endedAt=S,e.reason&&(R.endReason=e.reason),E.push({agent:o,sessionId:d.sessionId,pinned:d.pinned,startedAt:S,endedAt:null}),k.agent=o,k.sessionId=d.sessionId,k.pinned=d.pinned,k.state="live",k.role="lead",g.pendingHandoffHydrate={artifact:e.statusArtifact||Co,at:S},Te(g,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:d.sessionId,epoch:E.length-1,singleBox:!0,forced:d.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint}),await ee(),await s("done",{sessionName:e.fromBox}),await Ou(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function nw(e){let t=_h.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await Z(),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=ea.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Nt.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 _h.set(e,s),bL(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 bL(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await ge(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&yo(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await tp(t.leadBox,{timeoutMs:QT})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await np(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 Dt(t.workspace)){if(!u?.dir)continue;let f={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await nn(u.dir,["push","origin",o],Ah);let{stdout:d}=await nn(u.dir,["rev-parse","HEAD"]);f.baseSha=d.trim(),f.pushed=!0}catch(d){f.error=String(d?.message||d).split(`
243
- `)[0]}s.push(f)}e.step="wip";let a=await lh({id:t.id,cwd:t.cwd},{force:!0}),i=await Z(),c=he(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&Qs(l),await ee(),e.result={name:c?.name??t.name,agent:l?.agent??null,leadBox:c?.leadBox??t.leadBox,createdAt:c?.createdAt??null,branch:o,repos:s.filter(u=>u.pushed).map(({name:u,repo:f,baseSha:d})=>({name:u,repo:f,baseSha:d})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:f,error:d})=>({name:u,repo:f,error:d})),wip:a.pushed?{ref:a.ref,sha:a.sha}:null,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function rw(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 Wu(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await Z(),o=he(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};jh(e),await Kh(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();Dl(o,{at:s,reason:n==="recover"?"node-offline":"node-transfer"});let a=await uh({id:o.id,cwd:o.cwd});return o.transferredTo=t,o.transferredAt=s,Te(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...a.pushed?{rescueRef:a.ref,rescueSha:a.sha}:{}}),await ee(),{ok:!0,toNode:t,rescue:a.pushed?{ref:a.ref,sha:a.sha}:null}}async function ow(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await Wu(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 YT(e,t,n){try{await Nl(e,t,n)}catch{await nn(e,["worktree","prune"]).catch(()=>{}),await Nl(e,t,n)}return t}async function sw(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(kh.has(t))throw new Error("an adopt is already running for this Track");kh.set(t,{startedAt:Date.now()});try{return await kL({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{kh.delete(t)}}async function kL({trackId:e,name:t,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,brief:u=null,epochs:f=[],createdAt:d=null,leadBox:p=null,reason:h=null,downSince:w=null}){let g=await Zi(n,r),k=await Z(),S=he(k,e);if(S&&!S.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);S&&(await uh({id:S.id,cwd:S.cwd}).catch(()=>{}),await pE(S),k.tracks.splice(k.tracks.indexOf(S),1),await ee()),await z.mkdir(Hi,{recursive:!0});let E=J.join(Hi,e);await z.rm(E,{recursive:!0,force:!0}).catch(()=>{});let R=null,B=!1,T=[];try{let _=[];if(i)for(let L of Array.isArray(c)?c:[]){let ce=typeof L=="string"?L:L?.repo;if(!ce||!/^[^/\s]+\/[^/\s]+$/.test(ce))continue;let ue=await Zo(ce)??await Fc(ce);await nn(ue,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],Ah),_.push({slug:ce,base:ue,name:typeof L=="object"?L?.name??null:null})}if(i&&_.length===1){let{base:L,slug:ce}=_[0];await YT(L,E,i),T.push({base:L,dir:E}),await Vi(E);let ue=await Is(L);R={dir:E,base:L,branch:i,kind:"worktree",baseRef:ue,repo:ce}}else if(i&&_.length>=2){await z.mkdir(E,{recursive:!0});let L=new Set([".bostrat"]),ce=[];for(let ue of _){let Ae=ue.name||J.basename(ue.base);L.has(Ae)&&(Ae=ue.slug.replace("/","-"));for(let je=2;L.has(Ae);je++)Ae=`${J.basename(ue.base)}-${je}`;L.add(Ae);let _e=J.join(E,Ae);await YT(ue.base,_e,i),T.push({base:ue.base,dir:_e});let xt=await Is(ue.base);ce.push({name:Ae,dir:_e,base:ue.base,baseRef:xt,repo:ue.slug})}await nc(E,ce,i),R={dir:E,kind:"multi",branch:i,repos:ce}}else B=!0,await z.mkdir(E,{recursive:!0}),await Cp(E),await Vi(E),R={dir:E,base:null,branch:null,kind:"repo"};let O=!1,I=null,U=null;if(l?.sha&&R.kind==="worktree")try{await nn(E,["fetch","origin",l.ref||ch(e)],Ah);let{stdout:L}=await nn(E,["rev-parse","FETCH_HEAD^"]),{stdout:ce}=await nn(E,["rev-parse","HEAD"]),ue=L.trim()===ce.trim();ue||await nn(E,["merge-base","--is-ancestor",ce.trim(),L.trim()]).then(()=>!0,()=>!1)&&(await nn(E,["reset","--hard",L.trim()]),U={from:ce.trim(),to:L.trim()},ue=!0),ue?(await nn(E,["read-tree","--reset","-u","FETCH_HEAD"]),await nn(E,["reset","-q"]),O=!0):I="snapshot does not parent the fetched branch head"}catch(L){I=String(L?.message||L).split(`
244
- `)[0]}else l?.sha&&(I="wip snapshots cover single-repo worktrees only");await WT({id:e,cwd:E}).catch(()=>({restored:!1}));let H=J.join(E,Co),ae=null;(await Zc(E)).restored?ae="checkpoint":typeof u=="string"&&u.trim()&&(await z.mkdir(J.dirname(H),{recursive:!0}),await z.writeFile(H,u),ae="brief");let C=new Set(k.tracks.flatMap(L=>(L.boxes||[]).map(ce=>ce.name))),Q=null;p&&!C.has(p)&&!await ge(p).catch(()=>null)?Q=p:(Q=`${t.trim()} lead`,C.has(al(Q))&&(Q=`${t.trim().slice(0,50).trim()} ${e} lead`));let ve=await pr(Q,E,{agentCmd:g,agent:n});Xa({cwd:ve.cwd,sessionName:ve.name,agent:n,agentCmd:g});let W=Date.now(),be=Qh(ve,"lead","live"),se=(Array.isArray(f)?f:[]).filter(L=>L&&typeof L=="object").map(L=>({...L})),pe=se[se.length-1];pe&&pe.endedAt==null&&(pe.endedAt=W,pe.endReason==null&&(pe.endReason=o==="recover"?"node-offline":"node-transfer")),se.push({agent:n,sessionId:ve.sessionId??null,pinned:ve.pinned===!0,startedAt:W,endedAt:null}),be.epochs=se;let ie={id:e,name:t.trim(),cwd:ve.cwd,workspace:R,leadBox:ve.name,boxes:[be],events:[],createdAt:Number.isFinite(d)?d:W,...ae?{pendingHandoffHydrate:{artifact:Co,at:W}}:{}};return Te(ie,"transferred-in",{box:ve.name,agent:n,fromNode:s,toNode:a,mode:o,reason:h,...o==="recover"?{downSince:Number.isFinite(w)?w:null}:{},branch:R.branch??null,wip:O,...U?{wipAdvanced:U}:{},epoch:se.length-1,name:ie.name,cwd:ie.cwd,workspace:{base:R.base??null,branch:R.branch??null,kind:R.kind,...R.baseRef?{baseRef:R.baseRef}:{},...R.repo?{repo:R.repo}:{},...R.repos?{repos:R.repos.map(({name:L,base:ce,baseRef:ue,repo:Ae})=>({name:L,base:ce,baseRef:ue,repo:Ae}))}:{}}}),k.tracks.push(ie),await ee(),{...await Mt(ie),adopt:{wipApplied:O,wipSkipped:I,...U?{wipAdvanced:U}:{},codeless:B,artifactSource:ae}}}catch(_){for(let O of T)await Rt(O.base,O.dir).catch(()=>{});throw await z.rm(E,{recursive:!0,force:!0}).catch(()=>{}),_}}async function gE(e,t,n){let r=await Z(),o=he(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await ee())}async function Ys(e,t){e.step=t,await oc(e)}function yE(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 bE(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function TL(e,t,n){if(!bE(n)||Nt.has(t)||!await ge(n.box).catch(()=>null))return!1;try{await z.access(n.dir)}catch{return!1}let o=await ge(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return Nt.set(t,s),xE(s,o).catch(a=>kE(s,a)),!0}async function aw(){let e=await Z(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Nt.has(r))continue;if(await TL(n,r,o)){t=!0,Te(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await re({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=yE(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!Fr.has(i.state)&&(i.state="canceled"),Te(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 re({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await JT(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||Fr.has(r.state)||Nt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?J.join(ta,`${n.id}-${r.subtaskId}`):null;await re({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await JT(n,r.name,o)}}return t=await EL(e)||t,t&&await ee(),t}async function JT(e,t,n){if(t&&await Yt(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of Dt(e.workspace)){let s=J.join(n,o.name);await Rt(o.base,s).then(()=>!0,()=>!1)||await Rt(o.dir,s).catch(()=>{})}await z.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await ge(e.leadBox).catch(()=>null);r?.cwd&&await Rt(r.cwd,n).catch(()=>{})}async function EL(e){let t;try{t=await z.readdir(ta)}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 Nt.values())o.dir&&n.add(J.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=J.join(ta,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of Dt(a.workspace))await Rt(i.base,J.join(s,i.name)).catch(()=>{});await z.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await ge(a.leadBox).catch(()=>null):null;i?.cwd?await Rt(i.cwd,s).catch(()=>{}):await z.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await re({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function cw(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!Ts(n))throw new Error("task (string) required");let s=await Zi(t,r),a=yo(t);if(a){let p=new Error(`can't delegate to ${t} \u2014 its ${a.window} spend limit is reached ($${a.spentUsd.toFixed(2)} of $${a.limitUsd.toFixed(2)})`);throw p.usageCap=a,p}let i=he(await Z(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await ge(i.leadBox);if(!c)throw new Error(`lead box "${i.leadBox}" is not running`);if(!c.cwd)throw new Error("can't resolve the lead's working directory");let l=i.workspace?.kind==="multi",u=null;if(l){let p=Dt(i.workspace);if(!p.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let h of p)if(!h?.dir||!await Es(h.dir))throw new Error(`tagged checkout "${h?.name??"?"}" is missing from the lead workspace (${h?.dir??"no dir"})`);u=p.map(h=>({name:h.name,leadDir:h.dir,base:null}))}else if(!await Es(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let f=Po().slice(0,8),d={id:f,trackId:e,trackName:i.name,agent:t,task:Ts(n),skipPermissions:r,reason:tE(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${iw(i.name)}-${f}`,base:null,repos:u,dir:J.join(ta,`${e}-${f}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Nt.set(f,d),await oc(d),AL(d,c,s).catch(p=>kE(d,p)),d}async function kE(e,t){e.failedStep=e.step,e.error=t instanceof Ji?"canceled":t?.message||String(t),e.step=t instanceof Ji?"canceled":"error",e.finishedAt=Date.now(),await uw(e).catch(()=>{}),await oc(e).catch(()=>{}),await RL(e).catch(()=>{})}function Ku(e){let t=Nt.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 lw(e){let t=Nt.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 AL(e,t,n){if(await Ys(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await As(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await oc(e)}else e.base=await As(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await Ys(e,"spawn"),await z.mkdir(ta,{recursive:!0}),e.repos){await z.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await _s(a.leadDir,J.join(e.dir,a.name),e.branch,a.base);let s=Dt((he(await Z(),e.trackId)||{}).workspace);await nc(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 _s(t.cwd,e.dir,e.branch,e.base),await Vi(e.dir);await _L(e,t);let r=e.trackName.slice(0,38).trim(),o=await pr(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await IL(e,o),await nE(e.trackId,o.name,_j(e.task,!!e.repos),{kind:"subtask"}),await xE(e,t)}async function xE(e,t){await Ys(e,"working");let n=J.join(e.dir,Ru);if(await CL(n,e),e.canceled)throw new Ji;if(await Ys(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=J.join(e.dir,l.name);await Op(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:zT({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await Np(l.leadDir,l.base,e.branch,zs),l.files=await Pp(l.leadDir,l.base,e.branch,zs);let f=await Dp(l.leadDir,l.base,e.branch,zs);l.applied=f.applied,l.conflicts=f.conflicts??[],s.files+=l.stat.files,s.insertions+=l.stat.insertions,s.deletions+=l.stat.deletions,a.push(...l.files.map(d=>J.join(l.name,d))),i.push(...l.conflicts.map(d=>d.startsWith("patch did not apply cleanly")?`${l.name}: ${d}`:J.join(l.name,d))),f.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await Op(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:zT({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await Np(t.cwd,e.base,e.branch,zs),e.files=await Pp(t.cwd,e.base,e.branch,zs);let s=await Dp(t.cwd,e.base,e.branch,zs);e.applied=s.applied,e.conflicts=s.conflicts}await oc(e);let r=await OL(e,t,n);await Ys(e,"resume"),await nE(e.trackId,e.leadBox,Ij(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await Ys(e,"reap"),await uw(e),e.step="done";let o=Date.now();await gE(e.trackId,e.id,{...qu(e),finishedAt:o}),await $L(e,o),e.finishedAt=o}async function _L(e,t){let n=J.join(e.dir,J.dirname(Wi));await z.mkdir(n,{recursive:!0});let r="";try{r=await bb(t.cwd,t.sessionId)}catch{}if(!r)try{r=await z.readFile(J.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}
242
+ ${a}`}async function Yh(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<qa()?!1:Mn(e.name)}async function Ji(e,t,n){return!t||e.archivedAt||Ur.has(t.state)?!1:(await se({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 Yt(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=kh.get(r.name);if(o)return o;let s=xL(e,r,{freshSession:t,reason:n}).finally(()=>kh.delete(r.name));return kh.set(r.name,s),s}async function xL(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||Ur.has(t.state)||await ye(t.name))return!1;let o=n===!0,s=o?Po():null,a=o?Ha($h(t.agent),s,t.name):Rh(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await il(a);if(i===as)return Te(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===is&&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(ea(t)))}:null,l=Date.now();if(o){let u=ea(t),f=u[u.length-1];f.endedAt==null&&(f.endedAt=l),f.endReason==null&&(f.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 mr(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=Sa(u.hookToken),Za({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a}),t.state="live",o&&Te(e,"lead-refreshed",{box:t.name,agent:t.agent,fromSessionId:c.sessionId,toSessionId:s,epoch:t.epochs.length-1,reason:r||"fresh-session"}),Te(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),Te(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function Hu(e,{freshSession:t=!1}={}){let n=await Q(),r=we(n,e);if(!r)throw new Error(`track "${e}" not found`);if(!r.archivedAt)throw new Error(`track "${e}" is not archived`);return delete r.archivedAt,Yi.delete(e),Te(r,"unarchived",{}),await oc(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await ne(),Mt(r)}async function Jh(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>Ah)throw new Error(`name too long (max ${Ah} chars)`);let r=await Q(),o=we(r,e);if(!o)throw new Error(`track "${e}" not found`);if(String(o.name||"").startsWith("\u21BB"))throw new Error("loop run Tracks are named by their loop \u2014 rename the loop on the Loops tab");if(n===o.name)return Mt(o);let s=o.name;return o.name=n,Te(o,"renamed",{from:s,to:n}),await ne(),Mt(o)}async function Xh(){let e=await Q(),t=0;for(let n of e.tracks||[])n.transferredTo&&jl(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await ne(),t}async function Zh(){let e=await Q(),t=new Set((await zt()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!Ve(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(Ve(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await Yt(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):Te(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!Ur.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await ne(),r}async function Wu(e,{freshSession:t=!1}={}){let n=await Q(),r=we(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before restarting the lead`);ow(r);let o=r.boxes.find(i=>i.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(Ur.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await ye(r.leadBox)){let i=await Ce(r.leadBox,{lines:Xe}).catch(()=>"");if(bl(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await Yt(r.leadBox),o.state="stopped"}let a=await oc(r,t?{freshSession:!0,reason:"loop-fire"}:{});if(await ne(),!a)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Mt(r)}async function Qh(e,t,n){let r=await re(e);if(!r)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let o=await U(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 Wu(e),await $(r,{type:"box.fullscreen.answered",actor:"user",source:"orchestrator",boxId:r.leadBox,payload:{ts:Date.now(),offerId:t,action:n?"restarted":"dismiss"}}).catch(()=>{}),{ok:!0,action:n?"restarted":"dismiss"}}function XT(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return gu({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function ea(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 Mu(e,t){let n=await Q(),r=we(n,e);r&&(r.handoff={...r.handoff||{},...t},await ne())}function bE(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 tw(){let e=await Q(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=bE(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await ye(r.fromBox).catch(()=>null),l=n.boxes.find(u=>u.name===r.fromBox);if(c&&l&&c.agent===r.toAgent&&r.toAgent!==l.agent){let u=Date.now(),f=ea(l),d=f[f.length-1],p=d.agent,h=d.sessionId??null;d.endedAt=u,r.reason&&(d.endReason=r.reason);let w=c.agent==="claude"&&!!c.sessionId;f.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:w,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.sessionId=c.sessionId||null,l.pinned=w,l.state="live",n.pendingHandoffHydrate={artifact:Co,at:u},Te(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:p,toAgent:r.toAgent,fromSessionId:h,toSessionId:c.sessionId||null,epoch:f.length-1,singleBox:!0,skipPermissions:r.skipPermissions,reason:r.reason??null,handoffStartedAt:r.startedAt,recovered:!0}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await se({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 se({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await Yt(i).catch(()=>{}),a&&await Yt(a).catch(()=>{})}return t&&await ne(),t}async function qu(e,t,n=!0,r=null){let o=ta.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=we(await Q(),e);if(!s)throw new Error(`track "${e}" not found`);nc(e,"handoff");let a=await Qi(t,n),i=yo(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 ye(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:oE(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return ta.set(e,l),await Mu(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),vL(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 Mu(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),se({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),se({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function vL(e,t,n,r,o){let s=async(M,T={})=>{e.step=M,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${M}`),await Mu(e.trackId,{step:M,toBox:e.toBox}),await se({flow:"lead-handoff",phase:M,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:T.sessionName,...T})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await Q(),i=we(a,e.trackId)?.boxes.find(M=>M.name===e.fromBox)||null,c=i?.agent||n.agent,l=i?.sessionId??n.sessionId??null,u=i?.pinned===!0;if(await s("checkpoint",{sessionName:e.fromBox}),e.checkpoint="llm",yo(c))e.checkpoint="skipped-capped";else try{await np(e.fromBox,{timeoutMs:nE})}catch(M){e.checkpoint="reconstructed",await se({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:M?.message||String(M)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await rp(e.trackId,n.cwd,{trackName:t.name||t.id}).catch(()=>null),await s("checkpoint-degraded",{sessionName:e.fromBox,checkpoint:e.checkpoint,statusArtifact:e.statusArtifact})),await s("swap",{cwd:n.cwd,agentCmd:r});let d=await up(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let p=Bb(d.launchCmd);await wr({cwd:n.cwd,sessionId:d.sessionId,sessionName:e.fromBox,agent:o,agentCmd:ra(o),launchEcho:p}).catch(M=>{if(M?.code!=="cli-not-running")throw M});let h=Lf(await Ce(e.fromBox,{lines:Xe}).catch(()=>""),p);if(!gs(o,h)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let M=Rh(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await up(e.fromBox,{agentCmd:M,agent:c,resumeSessionId:l,pinned:u});let T=await Q(),A=we(T,e.trackId);if(A){let C=A.boxes.find(I=>I.name===e.fromBox);C&&(C.state="live"),Te(A,"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 ne()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let w=await Q(),g=we(w,e.trackId);if(!g)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let b=g.boxes.find(M=>M.name===e.fromBox);if(!b)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let E=Date.now(),S=ea(b),R=S[S.length-1];R.endedAt=E,e.reason&&(R.endReason=e.reason),S.push({agent:o,sessionId:d.sessionId,pinned:d.pinned,startedAt:E,endedAt:null}),b.agent=o,b.sessionId=d.sessionId,b.pinned=d.pinned,b.state="live",b.role="lead",g.pendingHandoffHydrate={artifact:e.statusArtifact||Co,at:E},Te(g,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:d.sessionId,epoch:S.length-1,singleBox:!0,forced:d.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint}),await ne(),await s("done",{sessionName:e.fromBox}),await Mu(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function rw(e){let t=Ih.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await Q(),r=we(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 restore it before moving it");if(r.kind==="setup")throw new Error("setup boxes don't move");if(r.transferredTo)throw new Error(`track already transferred to ${r.transferredTo}`);let o=ta.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Nt.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 Ih.set(e,s),SL(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 SL(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await ye(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&yo(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await np(t.leadBox,{timeoutMs:nE})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await rp(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 Dt(t.workspace)){if(!u?.dir)continue;let f={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await nn(u.dir,["push","origin",o],_h);let{stdout:d}=await nn(u.dir,["rev-parse","HEAD"]);f.baseSha=d.trim(),f.pushed=!0}catch(d){f.error=String(d?.message||d).split(`
243
+ `)[0]}s.push(f)}e.step="wip";let a=await uh({id:t.id,cwd:t.cwd},{force:!0}),i=await Q(),c=we(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&ea(l),await ne(),e.result={name:c?.name??t.name,agent:l?.agent??null,leadBox:c?.leadBox??t.leadBox,createdAt:c?.createdAt??null,branch:o,repos:s.filter(u=>u.pushed).map(({name:u,repo:f,baseSha:d})=>({name:u,repo:f,baseSha:d})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:f,error:d})=>({name:u,repo:f,error:d})),wip:a.pushed?{ref:a.ref,sha:a.sha}:null,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function ow(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 Ku(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await Q(),o=we(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};Lh(e),await Gh(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();jl(o,{at:s,reason:n==="recover"?"node-offline":"node-transfer"});let a=await dh({id:o.id,cwd:o.cwd});return o.transferredTo=t,o.transferredAt=s,Te(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...a.pushed?{rescueRef:a.ref,rescueSha:a.sha}:{}}),await ne(),{ok:!0,toNode:t,rescue:a.pushed?{ref:a.ref,sha:a.sha}:null}}async function sw(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await Ku(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 ZT(e,t,n){try{await Dl(e,t,n)}catch{await nn(e,["worktree","prune"]).catch(()=>{}),await Dl(e,t,n)}return t}async function aw(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(xh.has(t))throw new Error("an adopt is already running for this Track");xh.set(t,{startedAt:Date.now()});try{return await TL({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{xh.delete(t)}}async function TL({trackId:e,name:t,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,brief:u=null,epochs:f=[],createdAt:d=null,leadBox:p=null,reason:h=null,downSince:w=null}){let g=await Qi(n,r),b=await Q(),E=we(b,e);if(E&&!E.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);E&&(await dh({id:E.id,cwd:E.cwd}).catch(()=>{}),await wE(E),b.tracks.splice(b.tracks.indexOf(E),1),await ne()),await J.mkdir(Wi,{recursive:!0});let S=Z.join(Wi,e);await J.rm(S,{recursive:!0,force:!0}).catch(()=>{});let R=null,M=!1,T=[];try{let A=[];if(i)for(let F of Array.isArray(c)?c:[]){let le=typeof F=="string"?F:F?.repo;if(!le||!/^[^/\s]+\/[^/\s]+$/.test(le))continue;let de=await Zo(le)??await Hc(le);await nn(de,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],_h),A.push({slug:le,base:de,name:typeof F=="object"?F?.name??null:null})}if(i&&A.length===1){let{base:F,slug:le}=A[0];await ZT(F,S,i),T.push({base:F,dir:S}),await zi(S);let de=await $s(F);R={dir:S,base:F,branch:i,kind:"worktree",baseRef:de,repo:le}}else if(i&&A.length>=2){await J.mkdir(S,{recursive:!0});let F=new Set([".bostrat"]),le=[];for(let de of A){let Ae=de.name||Z.basename(de.base);F.has(Ae)&&(Ae=de.slug.replace("/","-"));for(let je=2;F.has(Ae);je++)Ae=`${Z.basename(de.base)}-${je}`;F.add(Ae);let _e=Z.join(S,Ae);await ZT(de.base,_e,i),T.push({base:de.base,dir:_e});let xt=await $s(de.base);le.push({name:Ae,dir:_e,base:de.base,baseRef:xt,repo:de.slug})}await rc(S,le,i),R={dir:S,kind:"multi",branch:i,repos:le}}else M=!0,await J.mkdir(S,{recursive:!0}),await Mp(S),await zi(S),R={dir:S,base:null,branch:null,kind:"repo"};let C=!1,I=null,W=null;if(l?.sha&&R.kind==="worktree")try{await nn(S,["fetch","origin",l.ref||lh(e)],_h);let{stdout:F}=await nn(S,["rev-parse","FETCH_HEAD^"]),{stdout:le}=await nn(S,["rev-parse","HEAD"]),de=F.trim()===le.trim();de||await nn(S,["merge-base","--is-ancestor",le.trim(),F.trim()]).then(()=>!0,()=>!1)&&(await nn(S,["reset","--hard",F.trim()]),W={from:le.trim(),to:F.trim()},de=!0),de?(await nn(S,["read-tree","--reset","-u","FETCH_HEAD"]),await nn(S,["reset","-q"]),C=!0):I="snapshot does not parent the fetched branch head"}catch(F){I=String(F?.message||F).split(`
244
+ `)[0]}else l?.sha&&(I="wip snapshots cover single-repo worktrees only");await GT({id:e,cwd:S}).catch(()=>({restored:!1}));let j=Z.join(S,Co),ee=null;(await el(S)).restored?ee="checkpoint":typeof u=="string"&&u.trim()&&(await J.mkdir(Z.dirname(j),{recursive:!0}),await J.writeFile(j,u),ee="brief");let O=new Set(b.tracks.flatMap(F=>(F.boxes||[]).map(le=>le.name))),z=null;p&&!O.has(p)&&!await ye(p).catch(()=>null)?z=p:(z=`${t.trim()} lead`,O.has(cl(z))&&(z=`${t.trim().slice(0,50).trim()} ${e} lead`));let te=await mr(z,S,{agentCmd:g,agent:n});Za({cwd:te.cwd,sessionName:te.name,agent:n,agentCmd:g});let H=Date.now(),ke=ew(te,"lead","live"),ie=(Array.isArray(f)?f:[]).filter(F=>F&&typeof F=="object").map(F=>({...F})),me=ie[ie.length-1];me&&me.endedAt==null&&(me.endedAt=H,me.endReason==null&&(me.endReason=o==="recover"?"node-offline":"node-transfer")),ie.push({agent:n,sessionId:te.sessionId??null,pinned:te.pinned===!0,startedAt:H,endedAt:null}),ke.epochs=ie;let ce={id:e,name:t.trim(),cwd:te.cwd,workspace:R,leadBox:te.name,boxes:[ke],events:[],createdAt:Number.isFinite(d)?d:H,...ee?{pendingHandoffHydrate:{artifact:Co,at:H}}:{}};return Te(ce,"transferred-in",{box:te.name,agent:n,fromNode:s,toNode:a,mode:o,reason:h,...o==="recover"?{downSince:Number.isFinite(w)?w:null}:{},branch:R.branch??null,wip:C,...W?{wipAdvanced:W}:{},epoch:ie.length-1,name:ce.name,cwd:ce.cwd,workspace:{base:R.base??null,branch:R.branch??null,kind:R.kind,...R.baseRef?{baseRef:R.baseRef}:{},...R.repo?{repo:R.repo}:{},...R.repos?{repos:R.repos.map(({name:F,base:le,baseRef:de,repo:Ae})=>({name:F,base:le,baseRef:de,repo:Ae}))}:{}}}),b.tracks.push(ce),await ne(),{...await Mt(ce),adopt:{wipApplied:C,wipSkipped:I,...W?{wipAdvanced:W}:{},codeless:M,artifactSource:ee}}}catch(A){for(let C of T)await Rt(C.base,C.dir).catch(()=>{});throw await J.rm(S,{recursive:!0,force:!0}).catch(()=>{}),A}}async function kE(e,t,n){let r=await Q(),o=we(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await ne())}async function Js(e,t){e.step=t,await sc(e)}function xE(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 vE(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function IL(e,t,n){if(!vE(n)||Nt.has(t)||!await ye(n.box).catch(()=>null))return!1;try{await J.access(n.dir)}catch{return!1}let o=await ye(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return Nt.set(t,s),TE(s,o).catch(a=>SE(s,a)),!0}async function iw(){let e=await Q(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Nt.has(r))continue;if(await IL(n,r,o)){t=!0,Te(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await se({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=xE(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!Ur.has(i.state)&&(i.state="canceled"),Te(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 se({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await QT(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||Ur.has(r.state)||Nt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?Z.join(na,`${n.id}-${r.subtaskId}`):null;await se({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await QT(n,r.name,o)}}return t=await $L(e)||t,t&&await ne(),t}async function QT(e,t,n){if(t&&await Yt(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of Dt(e.workspace)){let s=Z.join(n,o.name);await Rt(o.base,s).then(()=>!0,()=>!1)||await Rt(o.dir,s).catch(()=>{})}await J.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await ye(e.leadBox).catch(()=>null);r?.cwd&&await Rt(r.cwd,n).catch(()=>{})}async function $L(e){let t;try{t=await J.readdir(na)}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 Nt.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(na,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of Dt(a.workspace))await Rt(i.base,Z.join(s,i.name)).catch(()=>{});await J.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await ye(a.leadBox).catch(()=>null):null;i?.cwd?await Rt(i.cwd,s).catch(()=>{}):await J.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await se({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function lw(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!Es(n))throw new Error("task (string) required");let s=await Qi(t,r),a=yo(t);if(a){let p=new Error(`can't delegate to ${t} \u2014 its ${a.window} spend limit is reached ($${a.spentUsd.toFixed(2)} of $${a.limitUsd.toFixed(2)})`);throw p.usageCap=a,p}let i=we(await Q(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await ye(i.leadBox);if(!c)throw new Error(`lead box "${i.leadBox}" is not running`);if(!c.cwd)throw new Error("can't resolve the lead's working directory");let l=i.workspace?.kind==="multi",u=null;if(l){let p=Dt(i.workspace);if(!p.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let h of p)if(!h?.dir||!await As(h.dir))throw new Error(`tagged checkout "${h?.name??"?"}" is missing from the lead workspace (${h?.dir??"no dir"})`);u=p.map(h=>({name:h.name,leadDir:h.dir,base:null}))}else if(!await As(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let f=Po().slice(0,8),d={id:f,trackId:e,trackName:i.name,agent:t,task:Es(n),skipPermissions:r,reason:oE(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${cw(i.name)}-${f}`,base:null,repos:u,dir:Z.join(na,`${e}-${f}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Nt.set(f,d),await sc(d),RL(d,c,s).catch(p=>SE(d,p)),d}async function SE(e,t){e.failedStep=e.step,e.error=t instanceof Xi?"canceled":t?.message||String(t),e.step=t instanceof Xi?"canceled":"error",e.finishedAt=Date.now(),await dw(e).catch(()=>{}),await sc(e).catch(()=>{}),await NL(e).catch(()=>{})}function Vu(e){let t=Nt.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 uw(e){let t=Nt.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 RL(e,t,n){if(await Js(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await _s(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await sc(e)}else e.base=await _s(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await Js(e,"spawn"),await J.mkdir(na,{recursive:!0}),e.repos){await J.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await Is(a.leadDir,Z.join(e.dir,a.name),e.branch,a.base);let s=Dt((we(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 Is(t.cwd,e.dir,e.branch,e.base),await zi(e.dir);await OL(e,t);let r=e.trackName.slice(0,38).trim(),o=await mr(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await CL(e,o),await sE(e.trackId,o.name,Oj(e.task,!!e.repos),{kind:"subtask"}),await TE(e,t)}async function TE(e,t){await Js(e,"working");let n=Z.join(e.dir,Cu);if(await DL(n,e),e.canceled)throw new Xi;if(await Js(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 Cp(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:XT({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await Pp(l.leadDir,l.base,e.branch,Ys),l.files=await Dp(l.leadDir,l.base,e.branch,Ys);let f=await Bp(l.leadDir,l.base,e.branch,Ys);l.applied=f.applied,l.conflicts=f.conflicts??[],s.files+=l.stat.files,s.insertions+=l.stat.insertions,s.deletions+=l.stat.deletions,a.push(...l.files.map(d=>Z.join(l.name,d))),i.push(...l.conflicts.map(d=>d.startsWith("patch did not apply cleanly")?`${l.name}: ${d}`:Z.join(l.name,d))),f.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await Cp(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:XT({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await Pp(t.cwd,e.base,e.branch,Ys),e.files=await Dp(t.cwd,e.base,e.branch,Ys);let s=await Bp(t.cwd,e.base,e.branch,Ys);e.applied=s.applied,e.conflicts=s.conflicts}await sc(e);let r=await PL(e,t,n);await Js(e,"resume"),await sE(e.trackId,e.leadBox,Cj(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await Js(e,"reap"),await dw(e),e.step="done";let o=Date.now();await kE(e.trackId,e.id,{...Gu(e),finishedAt:o}),await ML(e,o),e.finishedAt=o}async function OL(e,t){let n=Z.join(e.dir,Z.dirname(qi));await J.mkdir(n,{recursive:!0});let r="";try{r=await kb(t.cwd,t.sessionId)}catch{}if(!r)try{r=await J.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}
245
245
 
246
246
  **Delegated task:** ${e.task}
247
247
 
@@ -252,15 +252,15 @@ ${a}`}async function zh(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<
252
252
  ## Conversation so far (lead \u2192 you)
253
253
 
254
254
  ${r}
255
- `;await z.writeFile(J.join(e.dir,Wi),o)}async function IL(e,t){let n=await Z(),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:va(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),Te(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]||{},...qu(e)},await ee())}async function $L(e,t=e.finishedAt){let n=await Z(),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),Te(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 ee()}async function RL(e){let t=await Z(),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"),Te(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]||{},...qu(e)},await ee()}async function OL(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=J.join(t.cwd,r);await z.mkdir(J.dirname(o),{recursive:!0}),await z.copyFile(n,o)}catch{}return r}async function uw(e){if(e.dir&&await Zd(e.dir).catch(()=>{}),e.box&&await Yt(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await Rt(t.leadDir,J.join(e.dir,t.name)).catch(()=>{});await z.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await ge(e.leadBox).catch(()=>null))?.cwd;n&&await Rt(n,e.dir).catch(()=>{})}}async function CL(e,t){let n=(t.startedAt||Date.now())+xL;for(;;){if(t.canceled||t.forceMerge)return;try{await z.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await No(vL)}}function No(e){return new Promise(t=>setTimeout(t,e))}var XT,En,ZT,Tj,Hi,Ej,Cu,Xi,Lr,Co,QT,Aj,Ru,Wi,_j,Ij,qt,ph,he,mh,Te,hh,wh,Oj,Fr,KT,Nj,Pj,Dj,Bj,Fj,qi,GT,Wj,qj,Kj,Gj,Vj,Js,Ki,Xj,Qj,eL,rL,uE,Gi,dE,iL,Ui,gh,cL,yh,fL,zi,pL,mL,VT,bh,Eh,Qh,ea,ra,Ah,nn,_h,tw,kh,xL,vL,ta,zs,Nt,SL,jo,qu,oc,iw,Ji,Nr=j(()=>{Oa();lt();op();zk();Za();cr();pl();Qk();it();dn();Yo();fl();w0();io();Ap();Ip();M0();bl();Uf();ml();Xf();Xt();Pl();ar();Bn();Qa();Fl();ax();Wp();eS();Qf();Vf();nS();Em();me();wu();xu();Si();bo();qm();Ks();eh();Iu();ih();Fn();uu();jT();dh();qT();Qc();XT=Sj(vj),En=process.env.BOSTRAT_STATE_DIR||J.join(process.env.HOME||"/tmp",".bostrat"),ZT=J.join(En,"tracks.json"),Tj=J.join(En,"events.jsonl"),Hi=J.join(En,"workspaces"),Ej=process.env.BOSTRAT_DEFAULT_REPO||null,Cu={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"}},Xi=Object.keys(Cu);Lr={at:0,value:null};Co=".bostrat/handoff/latest.md",QT=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;Aj=/\(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\.\)$/;Ru=".bostrat/handoff/subtask-result.md",Wi=".bostrat/handoff/lead-context.md",_j=(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 ${Wi} \u2014 read that first for context. Your scoped task:
255
+ `;await J.writeFile(Z.join(e.dir,qi),o)}async function CL(e,t){let n=await Q(),r=we(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:Sa(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),Te(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]||{},...Gu(e)},await ne())}async function ML(e,t=e.finishedAt){let n=await Q(),r=we(n,e.trackId);if(!r)return;let o=r.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=e.conflicts.length?"conflict":"merged",o.stat=e.stat),Te(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 ne()}async function NL(e){let t=await Q(),n=we(t,e.trackId);if(!n)return;let r=e.canceled||e.error==="canceled",o=n.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=r?"canceled":"failed"),Te(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]||{},...Gu(e)},await ne()}async function PL(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=Z.join(t.cwd,r);await J.mkdir(Z.dirname(o),{recursive:!0}),await J.copyFile(n,o)}catch{}return r}async function dw(e){if(e.dir&&await ef(e.dir).catch(()=>{}),e.box&&await Yt(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await Rt(t.leadDir,Z.join(e.dir,t.name)).catch(()=>{});await J.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await ye(e.leadBox).catch(()=>null))?.cwd;n&&await Rt(n,e.dir).catch(()=>{})}}async function DL(e,t){let n=(t.startedAt||Date.now())+EL;for(;;){if(t.canceled||t.forceMerge)return;try{await J.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await No(AL)}}function No(e){return new Promise(t=>setTimeout(t,e))}var eE,En,tE,Ij,Wi,$j,Nu,Zi,Fr,Co,nE,Rj,Cu,qi,Oj,Cj,qt,mh,we,hh,Te,wh,gh,Pj,Ur,zT,jj,Lj,Fj,Uj,qj,Ki,YT,Vj,zj,Yj,Jj,Xj,Xs,Gi,tL,rL,oL,iL,pE,Vi,mE,dL,Hi,yh,fL,bh,wL,Yi,gL,yL,JT,kh,Ah,ew,ta,oa,_h,nn,Ih,nw,xh,EL,AL,na,Ys,Nt,_L,jo,Gu,sc,cw,Xi,Pr=L(()=>{Ca();lt();sp();Xk();Qa();lr();hl();n0();it();dn();Yo();ml();b0();io();_p();$p();D0();xl();Wf();wl();Zf();Xt();Bl();ir();Bn();ei();Hl();lx();qp();rS();ep();_l();sS();Am();he();yu();Su();Ti();bo();Km();Gs();th();Ru();ch();Fn();fu();UT();fh();VT();tl();eE=_j(Aj),En=process.env.BOSTRAT_STATE_DIR||Z.join(process.env.HOME||"/tmp",".bostrat"),tE=Z.join(En,"tracks.json"),Ij=Z.join(En,"events.jsonl"),Wi=Z.join(En,"workspaces"),$j=process.env.BOSTRAT_DEFAULT_REPO||null,Nu={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"}},Zi=Object.keys(Nu);Fr={at:0,value:null};Co=".bostrat/handoff/latest.md",nE=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;Rj=/\(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\.\)$/;Cu=".bostrat/handoff/subtask-result.md",qi=".bostrat/handoff/lead-context.md",Oj=(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 ${qi} \u2014 read that first for context. Your scoped task:
256
256
 
257
257
  ${e}
258
258
 
259
- 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 ${Ru} (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 ${Wi} \u2014 read that first for context. Your scoped task:
259
+ 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 ${Cu} (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 ${qi} \u2014 read that first for context. Your scoped task:
260
260
 
261
261
  ${e}
262
262
 
263
- 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 ${Ru} 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.`,Ij=(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."),qt=null,ph=null;he=(e,t)=>e.tracks.find(n=>n.id===t)||null,mh=Promise.resolve();Te=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),$j(e.id,r),lx(e,r),r};Sb(async({sessionName:e,from:t,to:n,version:r,status:o,error:s})=>{let i=(await Z()).tracks.find(c=>c.leadBox===e||(c.boxes||[]).some(l=>l.name===e));i&&(Te(i,"codex-update",{box:e,from:t,to:r||n,status:o,...s?{error:s}:{}}),await ee().catch(()=>{}))});hh=J.join(En,"plane-link","update-notice.json");wh=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),Oj=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);Fr=new Set(["merged","conflict","canceled","failed","handed-off"]),KT=new Map;Nj=5e3;Pj={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};Dj=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];Bj=10*6e4;Fj=1500,qi=new Map;GT="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.";Wj=4e3,qj=3,Kj=[300,350,400],Gj=1e3,Vj=12,Js=new Map,Ki=new Map;Xj=[250,400,500,600];Qj=3e4,eL=[350,650,900];rL=12e4;uE=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}))});Gi="# bostrat workspace",dE=`${Gi}
263
+ 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 ${Cu} 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.`,Cj=(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."),qt=null,mh=null;we=(e,t)=>e.tracks.find(n=>n.id===t)||null,hh=Promise.resolve();Te=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),Mj(e.id,r),fx(e,r),r};Tb(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&&(Te(i,"codex-update",{box:e,from:t,to:r||n,status:o,...s?{error:s}:{}}),await ne().catch(()=>{}))});wh=Z.join(En,"plane-link","update-notice.json");gh=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),Pj=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);Ur=new Set(["merged","conflict","canceled","failed","handed-off"]),zT=new Map;jj=5e3;Lj={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};Fj=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];Uj=10*6e4;qj=1500,Ki=new Map;YT="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.";Vj=4e3,zj=3,Yj=[300,350,400],Jj=1e3,Xj=12,Xs=new Map,Gi=new Map;tL=[250,400,500,600];rL=3e4,oL=[350,650,900];iL=12e4;pE=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}))});Vi="# bostrat workspace",mE=`${Vi}
264
264
 
265
265
  TRACK MEMORY: if \`.bostrat/memory/MEMORY.md\` exists in your workspace, read it
266
266
  before substantive work \u2014 it is the shared cross-provider memory for this repo
@@ -581,16 +581,16 @@ for the same follow-up at the same moment twice; run bostrat-followup ls first
581
581
  specifics (no PR numbers, URLs, SHAs, tags \u2014 the card supplies them), and HOLD
582
582
  HERE after proposing until the operator answers the card. Bostrat never runs a
583
583
  follow-up on its own; the operator's tap is the gate.
584
- `,iL=dE,Ui=dE+ik;gh=e=>typeof e=="string"&&(e===Gi||e.startsWith(`${Gi}
585
- `)),cL="# bostrat multi-repo workspace";yh=Ui.replace(`${Gi}
586
- `,`${Gi}
584
+ `,dL=mE,Hi=mE+uk;yh=e=>typeof e=="string"&&(e===Vi||e.startsWith(`${Vi}
585
+ `)),fL="# bostrat multi-repo workspace";bh=Hi.replace(`${Vi}
586
+ `,`${Vi}
587
587
 
588
588
  (Global copy managed by bostrat \u2014 rewritten on service start; edits will be lost.)
589
589
  SCOPE: these instructions apply ONLY when your working directory is under
590
590
  ~/.bostrat/workspaces/ or ~/.bostrat/worktrees/ \u2014 a bostrat-orchestrated box.
591
591
  When working anywhere else, ignore everything below.
592
- `);fL=new Set(["claude","codex","cursor"]);zi=new Set,pL=e=>zi.has(e);mL=9e4;VT={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};bh=new Map;Eh=120;Qh=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:va(e.hookToken),createdAt:Date.now()});ea=new Map,ra=e=>ea.get(e)||(qt?he(qt,e)?.handoff:null)||null;Ah=6e4,nn=(e,t,n=15e3)=>XT("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),_h=new Map,tw=e=>_h.get(e)||null;kh=new Map;xL=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,vL=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,ta=J.join(En,"worktrees"),zs=[Wi,Ru],Nt=new Map,SL=e=>Nt.get(e)||(qt?qt.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,jo=e=>{let t=new Map([...Nt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=qt?he(qt,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)},qu=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});oc=e=>gE(e.trackId,e.id,qu(e));iw=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",Ji=class extends Error{}});lt();import xe from"node:path";import mt from"node:fs";import XH from"node:readline";import{fileURLToPath as ZH}from"node:url";import Gt from"express";import QH from"node:http";import eW from"node:https";import _d from"node:os";import{WebSocketServer as tW}from"ws";lt();import wO from"node-pty";async function Xy(e,t,n={}){if(!Pe(t)){ul(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await fr()){ul(e,`host tmux server not running on ${$t}`),e.close(1011,"tmux server unavailable");return}if(!await ge(t)){ul(e,`session "${t}" not found`),e.close(1008,"session not found");return}let r=Jy(n.cols,120,Zy),o=Jy(n.rows,32,Qy),s;try{s=wO.spawn(K,["-S",$t,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){ul(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&mf(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(mf(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"&&kO(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{}bO(t)})}var gO=6,yO=250;async function bO(e,t=gO,n=yO){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 Zy=20,Qy=6;function kO(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=Zy&&Number(t)>=Qy}function Jy(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function mf(e,t){try{e.send(JSON.stringify(t))}catch{}}function ul(e,t){mf(e,{type:"error",message:t})}function eb(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}}Xt();fl();op();Nr();import{createRequire as nW}from"node:module";var ML=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function dw({tracks:e=[],views:t=[],queuedOf:n=()=>[]}={}){let r=[];for(let o of e)!o||o.archivedAt&&!o.archiving||o.transferredTo||(o.working&&r.push(`working:${o.id}`),o.prompted&&r.push(`prompted:${o.id}`),(n(o.id)??[]).length&&r.push(`queued:${o.id}`),(o.boxes||[]).some(s=>s?.role==="subtask"&&s?.state==="live")&&r.push(`subtask:${o.id}`),Object.values(o.subtasks||{}).some(ML)&&r.push(`merge-back:${o.id}`));return t.some(o=>o?.state==="live"||o?.state==="starting")&&r.push("views"),{busy:r.length>0,reasons:r}}import NE from"node:fs";import Hr from"node:fs/promises";import JL from"node:os";import st from"node:path";import{spawn as XL}from"node:child_process";import{createRequire as ZL}from"node:module";me();Fl();import OE from"node:fs";import ac from"node:fs/promises";import DL from"node:http";import on from"node:path";import Vu from"node:os";import{createRequire as BL}from"node:module";import pw from"ws";import NL from"node:path";import PL from"node:os";var sc=process.env.BOSTRAT_STATE_DIR||NL.join(process.env.HOME||PL.tmpdir(),".bostrat");function fw(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 SE(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=fw(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function TE(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 rn=(()=>{try{return BL(import.meta.url)("../package.json").version||null}catch{return null}})(),EE=process.env.BOSTRAT_STATE_DIR||on.join(process.env.HOME||Vu.tmpdir(),".bostrat");function Lo({env:e=process.env,pkgDir:t=on.resolve(on.dirname(new URL(import.meta.url).pathname),".."),exists:n=OE.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(on.join(t,"..",".git"))?"git-checkout":"dev"}function ic(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 Gu(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 jL({home:e=process.env.HOME||Vu.homedir(),env:t=process.env}={}){let n=r=>{try{return OE.statSync(r),!0}catch{return!1}};return{claude:n(on.join(e,".claude",".credentials.json")),codex:n(on.join(t.CODEX_HOME||on.join(e,".codex"),"auth.json"))}}var ot=1,AE=1e3,_E=3e4,LL=6e4,FL=1500,UL=500,Ur=100,HL=2e3,WL=25e3,qL=6e4,CE=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},KL=CE(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),GL=3e4,IE=10*6e4,VL=400,$E=250,zL=CE(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),mw=4,YL=6e4,RE=6e4;function ME({url:e,token:t,nodeId:n=Vu.hostname(),name:r=Vu.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,metricsMs:c=YL,onUpdateAvailable:l=null,onUpdatePolicy:u=null,onHelloRefused:f=null,updatePolicy:d=null,installKind:p=Lo(),selfUrl:h=`http://127.0.0.1:${process.env.PORT||3362}`,onDegraded:w=null,onRecovered:g=null,ingestMode:k=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:S=KL,unackedRetryMs:E=qL,pingMs:R=WL,maxInflightEvents:B=VL,httpTimeoutMs:T=zL,stallBackoffMinMs:_=GL,fetchImpl:O=globalThis.fetch,log:I=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=TE(e);let U=h.replace(/^http/,"ws"),H=new Set,ae=new Map,X=new Map,C=on.join(EE,"plane-link","cursor.json"),Q=on.join(EE,"plane-link","dead-letter.ndjson"),ve=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),W={},be={},se=new Map,pe=null,ie=null,L=0,ce=0,ue=0,Ae=Promise.resolve(),_e="ws",xt=0,je=!1,A=0,G=!1,Ge=Ur,_t=new Set,at=[],nt=null,y=null,m=!1,b=!1,M=AE,ne=null,de=null,De=null,ht=null,Re=null,ya=!1,Mc=0;async function VI(){try{W=JSON.parse(await ac.readFile(C,"utf8"))}catch{W={}}}function zI(){ya=!0,!De&&(De=setTimeout(async()=>{if(De=null,!!ya){ya=!1;try{await ac.mkdir(on.dirname(C),{recursive:!0}),await ac.writeFile(C,JSON.stringify(W))}catch(P){I.error("[plane-link] cursor flush failed:",P?.message||P)}}},HL),De.unref?.())}function rt(P){return!y||y.readyState!==pw.OPEN?!1:(y.send(JSON.stringify(P)),!0)}function ba(P){let D=Date.now();for(let{trackId:x,event:N}of P){let q=se.get(N.id);se.set(N.id,{trackId:x,seq:N.seq,event:N,sentAt:D,firstSentAt:q?.firstSentAt??D,retryAt:D+E,tries:(q?.tries??0)+1,nacks:q?.nacks??0})}return _e==="http"?(ZI(P),!0):rt({v:ot,ch:"events",type:"append",events:P})}function YI(P){let D=null;for(let x of se.values())x.trackId===P&&(D==null||x.seq<D)&&(D=x.seq);return D}function Od(P){let D=be[P];if(D==null)return;let x=YI(P),N=x==null?D:Math.min(D,x-1);N>(W[P]??0)&&(W[P]=N,zI())}function ka(){if(pe=Date.now(),ie!=null){let P=Date.now()-ie;I.log(`[plane-link] spine sync recovered after ${Math.round(P/1e3)}s degraded (${L} stall redial(s))`);let D=ie;ie=null,L=0,ce=0,je=!1,A=0;try{g?.({since:D,downMs:P})}catch(x){I.error(`[plane-link] onRecovered failed: ${x?.message||x}`)}}}function Cd(P){if(!Array.isArray(P)||!P.length)return;let D=new Set;for(let x of P){let N=se.get(x);N&&(se.delete(x),(be[N.trackId]??0)<N.seq&&(be[N.trackId]=N.seq),D.add(N.trackId))}for(let x of D)Od(x);ka()}function Eg(P,D){ue++;let x={at:Date.now(),trackId:P.trackId,seq:P.seq,id:P.event?.id??null,type:P.event?.type??null,reason:D,event:P.event??null};I.error(`[plane-link] DEAD-LETTER ${P.trackId} seq ${P.seq} (${x.type??"?"}): plane rejected it permanently (${D}) \u2014 kept in ${Q}`),Ae=Ae.then(async()=>{await ac.mkdir(on.dirname(Q),{recursive:!0}),await ac.appendFile(Q,JSON.stringify(x)+`
593
- `)}).catch(N=>I.error(`[plane-link] dead-letter write failed: ${N?.message||N}`))}function Ag(P,D,x,N=null){if(!Array.isArray(P)||!P.length)return;let q=new Set,ye=Date.now();for(let Ee of P){let Be=se.get(Ee);Be&&(x?(se.delete(Ee),Eg(Be,D),(be[Be.trackId]??0)<Be.seq&&(be[Be.trackId]=Be.seq),q.add(Be.trackId)):(Be.nacks++,Be.retryAt=ye+Math.max(1e3,Number(N)||E)))}for(let Ee of q)Od(Ee);ka()}function _g(P=Date.now()){let D=1/0;for(let x of se.values())x.firstSentAt<D&&(D=x.firstSentAt);return D===1/0?0:P-D}function Ig(){if(!m||!se.size)return;let P=Date.now(),D=_g(P);if(D<S||pe!=null&&P-pe<S||_e==="http"&&je||ce>P)return;L++;let x=Math.min(_*2**(L-1),IE);if(ie==null){ie=P-D,I.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(D/1e3)}s with ${se.size} event(s) in flight (${_e} door) \u2014 the plane is not answering appends`);try{w?.({since:ie,unacked:se.size,oldestAgeMs:D,mode:_e})}catch(N){I.error(`[plane-link] onDegraded failed: ${N?.message||N}`)}}if(_e==="http"){je=!0,A=P+x,I.error(`[plane-link] ingest circuit OPEN (stall #${L}); probing /v1/ingest/health in ${Math.round(x/1e3)}s`);return}ce=P+x,I.error(`[plane-link] closing the link and redialing in ${Math.round(x/1e3)}s (stall redial #${L})`);try{y?.terminate()}catch{}}function Md(){if(!m)return;let P=Date.now();if(_e==="http"&&je)return;let D=[...se.values()].filter(N=>N.event&&N.retryAt<=P&&!(_e==="http"&&_t.has(N.trackId)));if(!D.length)return;D.sort((N,q)=>N.trackId===q.trackId?N.seq-q.seq:N.trackId<q.trackId?-1:1),I.log(`[plane-link] re-sending ${D.length} unacked event(s) the plane never confirmed`);let x=_e==="http"?Ge:Ur;if(_e==="http"){let N=new Map;for(let q of D)(N.get(q.trackId)??N.set(q.trackId,[]).get(q.trackId)).push(q);for(let[,q]of N){if(xt>=mw)return;ba(q.slice(0,x).map(ye=>({trackId:ye.trackId,event:ye.event})))}return}for(let N=0;N<D.length;N+=x){let q=D.slice(N,N+x).map(ye=>({trackId:ye.trackId,event:ye.event}));if(!ba(q))return}}async function JI(P=null){for(;;){if(!m)return!1;let D=se.size<B,x=_e!=="http"||xt<mw&&!je&&(!P||!_t.has(P));if(D&&x)return!0;await new Promise(N=>setTimeout(N,100))}}function Nd(){if(nt=null,!m||!at.length)return;let P=at;if(at=[],_e!=="http"){for(let x=0;x<P.length;x+=Ur)ba(P.slice(x,x+Ur));return}let D=new Map;for(let x of P)(D.get(x.trackId)??D.set(x.trackId,[]).get(x.trackId)).push(x);for(let[x,N]of D){if(_t.has(x)||xt>=mw||je){at.push(...N);continue}for(let q=0;q<N.length;q+=Ge)ba(N.slice(q,q+Ge))}at.length&&!nt&&(nt=setTimeout(Nd,$E),nt.unref?.())}let XI=P=>{let D=new Map;for(let{trackId:x,event:N}of P)(D.get(x)??D.set(x,[]).get(x)).push(N);return[...D].map(([x,N])=>({trackId:x,events:N}))},zo=(P,D,x,{progress:N})=>{let q=Date.now();for(let{event:ye}of P){let Ee=se.get(ye.id);Ee&&(Ee.nacks++,Ee.retryAt=q+Math.max(1e3,x||E))}N&&ka()};async function ZI(P){let D=new Set(P.map(x=>x.trackId));for(let x of D)_t.add(x);xt++;try{let x=await O(`${ve}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:XI(P)}),signal:AbortSignal.timeout(T)}),N=(Number(x.headers.get("retry-after"))||0)*1e3;if(x.status===200){let q=await x.json();Ge=Ur;for(let ye of q.results??[]){Cd(ye.acked??[]);let Ee=(Be,vt)=>{let Lt=new Map;for(let Ye of Be??[])(Lt.get(Ye.reason)??Lt.set(Ye.reason,[]).get(Ye.reason)).push(Ye.id);for(let[Ye,Mg]of Lt)Ag(Mg,Ye,vt,q.retryAfterMs??null)};Ee(ye.rejected,!0),Ee(ye.deferred,!1)}Cd(q.discarded??[]),ka();return}if(x.status===429){zo(P,"overloaded",N||5e3,{progress:!0});return}if(x.status===413&&P.length>1){Ge=Math.max(1,Math.floor(P.length/2)),I.error(`[plane-link] ingest request too large (${P.length} events) \u2014 halving batches to ${Ge}`),zo(P,"too_large",1e3,{progress:!0});return}if(x.status===413){let q=se.get(P[0].event.id);q&&(se.delete(q.event.id),Eg(q,"too_large"),(be[q.trackId]??0)<q.seq&&(be[q.trackId]=q.seq),Od(q.trackId)),ka();return}if(x.status===401||x.status===403){if(Date.now()-Mc>=RE){Mc=Date.now();let q="";try{q=(await x.json())?.error??""}catch{}I.error(`[plane-link] plane refused ingest (HTTP ${x.status}${q?`: ${q}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}zo(P,`http_${x.status}`,6e4,{progress:!1});return}if(x.status===400){I.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${P.length} event(s) for retry; this is a bug, not data`),zo(P,"http_400",6e4,{progress:!1});return}zo(P,`http_${x.status}`,N||5e3,{progress:!1})}catch(x){let N=x?.name==="TimeoutError"||x?.name==="AbortError";N&&P.length>1&&(Ge=Math.max(1,Math.floor(P.length/2)),I.error(`[plane-link] ingest request of ${P.length} event(s) outlived its ${T} ms deadline \u2014 halving batches to ${Ge}`)),zo(P,N?"timeout":"network",5e3,{progress:!1})}finally{xt--;for(let x of D)_t.delete(x)}}async function QI(){if(_e!=="http"||!je||!m||G)return;let P=Date.now();if(!(A>P)){G=!0;try{let D=await O(`${ve}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(T)});if(!D.ok)throw new Error(`HTTP ${D.status}`);I.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),je=!1,A=0,ce=Date.now()+T+E+1e3;for(let x of se.values())x.retryAt=Math.min(x.retryAt,Date.now());Md()}catch(D){L++;let x=Math.min(_*2**(L-1),IE);A=Date.now()+x,I.error(`[plane-link] ingest door still not answering (${D?.message||D}); next probe in ${Math.round(x/1e3)}s`)}finally{G=!1}}}function $g(){let P=Date.now();return{mode:_e,unacked:se.size,oldestUnackedAgeMs:_g(P),lastProgressAt:pe,degradedSince:ie,stallRedials:L,deadLettered:ue,http:_e==="http"?{inFlight:xt,circuitOpen:je,nextProbeInMs:je?Math.max(0,A-P):0,batchCap:Ge}:null}}async function Rg(){if(!i)return;let P;try{P=await i()}catch(D){I.error("[plane-link] metrics sample failed:",D?.message||D);return}P&&rt({v:ot,ch:"ctl",type:"metrics",metrics:{...P,planeLink:$g()}})}function e$(){i&&(Re&&clearInterval(Re),Rg(),Re=setInterval(Rg,c),Re.unref?.())}async function t$(){let P;try{P=await o()}catch(D){I.error("[plane-link] backfill listTracks failed:",D?.message||D);return}rt({v:ot,ch:"ctl",type:"tracks",ids:P.filter(D=>!D.transferredTo).map(D=>D.id).filter(D=>typeof D=="string")});for(let D of P){if(!m)return;let x;try{x=await F(D)}catch{continue}let N=W[D.id]??0,q=x.filter(Ee=>Ee.seq>N&&typeof Ee.id=="string"),ye=_e==="http"?Ge:Ur;for(let Ee=0;Ee<q.length;Ee+=ye){if(!await JI(D.id))return;let Be=q.slice(Ee,Ee+Math.min(ye,_e==="http"?Ge:Ur)).map(vt=>({trackId:D.id,event:vt}));if(!ba(Be))return}}}function Og(P){!m||!P?.trackId||typeof P.id!="string"||(at.push({trackId:P.trackId,event:P}),nt||(nt=setTimeout(Nd,$E),nt.unref?.()))}let xa=new Map;async function n$(P){let{reqId:D,method:x,path:N,headers:q={},body:ye}=P,Ee=Object.fromEntries(Object.entries(q).filter(([,vt])=>vt!=null)),Be=new AbortController;xa.set(D,Be);try{if(P.host){await r$(P,Ee,Be);return}let vt=await fetch(h+N,{method:x,headers:Ee,body:ye?Buffer.from(ye,"base64"):void 0,signal:Be.signal}),Lt=Object.fromEntries(vt.headers);for(let Ye of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete Lt[Ye];if(Lt["content-type"]||(Lt["content-type"]="application/octet-stream"),rt({v:ot,ch:"control",type:"http_head",reqId:D,status:vt.status,headers:Lt}),vt.body){for await(let Ye of vt.body)if(!rt({v:ot,ch:"control",type:"http_data",reqId:D,data:Buffer.from(Ye).toString("base64")}))break}rt({v:ot,ch:"control",type:"http_end",reqId:D,error:null})}finally{xa.delete(D)}}function r$(P,D,x){let{reqId:N,method:q,path:ye,body:Ee}=P,Be=new URL(h);return new Promise(vt=>{let Lt=DL.request({host:Be.hostname,port:Be.port,method:q,path:ye,headers:{...D,host:P.host},signal:x.signal},Ye=>{let{connection:Mg,"keep-alive":kW,"transfer-encoding":xW,upgrade:vW,...o$}=Ye.headers;rt({v:ot,ch:"control",type:"http_head",reqId:N,status:Ye.statusCode||502,headers:o$}),Ye.on("data",s$=>{rt({v:ot,ch:"control",type:"http_data",reqId:N,data:Buffer.from(s$).toString("base64")})||Ye.destroy()}),Ye.on("end",()=>{rt({v:ot,ch:"control",type:"http_end",reqId:N,error:null}),vt()}),Ye.on("error",()=>{rt({v:ot,ch:"control",type:"http_end",reqId:N,error:"view upstream error"}),vt()})});Lt.on("error",Ye=>{rt({v:ot,ch:"control",type:"http_end",reqId:N,error:Ye?.message||"view request failed"}),vt()}),Ee&&Lt.write(Buffer.from(Ee,"base64")),Lt.end()})}function Cg(){if(b)return;y=new pw(e,{headers:{authorization:`Bearer ${t}`}}),y.on("open",async()=>{let D=null;try{D=await s?.()||null}catch{D=null}rt({v:ot,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:rn,installKind:p,...typeof d=="function"?{updatePolicy:d()}:d?{updatePolicy:d}:{},providers:jL(),...D?{agents:D}:{}})}),y.on("message",D=>{let x;try{x=JSON.parse(D)}catch{return}if(x.ch==="ctl"&&x.type==="hello_ok"){m=!0,M=AE,ne=null,I.log(`[plane-link] connected to plane as ${n}`),x.minNodeVersion&&rn&&ic(rn,x.minNodeVersion)&&I.error(`[plane-link] this node is bostrat-node ${rn}; the plane asks for \u2265${x.minNodeVersion} \u2014 update with: ${Gu(p)}`);try{u?.(typeof x.updatePolicy=="string"?x.updatePolicy:null)}catch{}let N=typeof x.latestNodeVersion=="string"?x.latestNodeVersion:null;if(N&&rn&&ic(rn,N)&&!H.has(N)){H.add(N),I.log(`[plane-link] bostrat-node ${N} is available (this node runs ${rn}) \u2014 ${Gu(p)}`);try{l?.({current:rn,latest:N,min:x.minNodeVersion??null,installKind:p,required:!!(x.minNodeVersion&&ic(rn,x.minNodeVersion))})}catch(ye){I.error(`[plane-link] update notice failed: ${ye?.message||ye}`)}}let q=x.ingest==="http";_e=k==="ws"?"ws":k==="http"||q?"http":"ws",k==="http"&&!q&&I.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),_e==="http"&&I.log("[plane-link] spine rides the HTTPS ingest door"),je=!1,A=0,Ge=Ur,ht&&clearInterval(ht),ht=setInterval(()=>{rt({v:ot,ch:"ctl",type:"ping"}),Ig(),QI().catch(()=>{}),Md(),at.length&&!nt&&Nd()},R),ht.unref?.(),e$(),t$().catch(ye=>I.error("[plane-link] backfill failed:",ye?.message||ye));return}if(x.ch==="ctl"&&x.type==="hello_refused"){let N=typeof x.minNodeVersion=="string"?x.minNodeVersion:null,q=typeof x.latestNodeVersion=="string"?x.latestNodeVersion:null;I.error(`[plane-link] plane REFUSED this node: bostrat-node ${rn??"?"} is below its minimum ${N??"?"} \u2014 ${x.fix||Gu(p)}`),M=_E,ne=0;try{f?.({current:rn,min:N,latest:q,fix:x.fix||Gu(p),installKind:p})}catch(ye){I.error(`[plane-link] refusal handler failed: ${ye?.message||ye}`)}return}if(x.ch==="ctl"&&x.type==="update_policy"){try{u?.(typeof x.mode=="string"?x.mode:null)}catch{}return}if(x.ch==="ctl"&&x.type==="usage_caps"){Ll(x.caps??{},{source:"plane",updatedAt:x.updatedAt??Date.now()}).then(N=>I.log(`[plane-link] spend caps ${Object.keys(N.caps).length?`updated (${Object.keys(N.caps).join(", ")})`:"cleared"} from plane`)).catch(N=>I.error("[plane-link] spend-caps push rejected:",N?.message||N));return}if(x.ch==="ctl"&&x.type==="transferred"&&Array.isArray(x.tracks)){Promise.resolve().then(()=>a?.(x.tracks)).catch(N=>I.error("[plane-link] transfer notice failed:",N?.message||N));return}if(x.ch==="events"&&x.type==="ack"&&Array.isArray(x.ids)){Cd(x.ids);return}if(x.ch==="events"&&x.type==="nack"&&Array.isArray(x.ids)){Ag(x.ids,x.reason,x.permanent===!0,x.retryAfterMs??null);return}if(x.ch==="control"&&x.type==="http_open"){n$(x).catch(N=>rt({v:ot,ch:"control",type:"http_end",reqId:x.reqId,error:N?.message||"tunnel error"}));return}if(x.ch==="control"&&x.type==="http_cancel"){xa.get(x.reqId)?.abort();return}if(x.ch==="attach"&&x.type==="open"){let N=new pw(U+x.path,Array.isArray(x.protocols)?x.protocols:[],x.host?{headers:{host:x.host}}:void 0);ae.set(x.streamId,N),X.set(x.streamId,[]),N.on("open",()=>{let ye=X.get(x.streamId)||[];X.delete(x.streamId);for(let{buf:Ee,bin:Be}of ye)N.send(Ee,{binary:Be})}),N.on("message",(ye,Ee)=>{let Be=Ee?ye:Buffer.from(String(ye));rt({v:ot,ch:"attach",type:"data",streamId:x.streamId,data:Be.toString("base64"),...Ee?{bin:!0}:{}})});let q=()=>{X.delete(x.streamId),ae.delete(x.streamId)&&rt({v:ot,ch:"attach",type:"close",streamId:x.streamId})};N.on("close",q),N.on("error",q);return}if(x.ch==="attach"&&x.type==="data"){let N=ae.get(x.streamId);if(!N)return;let q=Buffer.from(x.data,"base64"),ye=x.bin===!0,Ee=X.get(x.streamId);Ee?Ee.push({buf:q,bin:ye}):N.send(q,{binary:ye});return}if(x.ch==="attach"&&x.type==="close"){let N=ae.get(x.streamId);ae.delete(x.streamId),X.delete(x.streamId),N?.close();return}});let P=()=>{m&&I.log("[plane-link] disconnected from plane"),m=!1,ht&&(clearInterval(ht),ht=null),Re&&(clearInterval(Re),Re=null),se.clear(),be={},at=[],nt&&(clearTimeout(nt),nt=null),_t.clear();for(let N of ae.values())N.close();ae.clear(),X.clear();for(let N of xa.values())N.abort();if(xa.clear(),b||de)return;ne==null&&(ne=Date.now());let D=Date.now()-ne<LL,x=Math.max(D?FL+Math.random()*UL:M,ce-Date.now());de=setTimeout(()=>{de=null,Cg()},x),de.unref?.(),D||(M=Math.min(M*2,_E))};y.on("close",P),y.on("error",D=>{let x=/Unexpected server response: (\d+)/.exec(D?.message||"")?.[1];(x==="401"||x==="403")&&Date.now()-Mc>=RE&&(Mc=Date.now(),I.error(`[plane-link] plane refused this node's credentials (HTTP ${x}) \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)`)),P()})}return ct.on("event",Og),VI().then(Cg),{stop:()=>{b=!0,ct.off("event",Og),de&&clearTimeout(de),De&&clearTimeout(De),ht&&clearInterval(ht),Re&&clearInterval(Re),nt&&clearTimeout(nt),rt({v:ot,ch:"ctl",type:"bye",reason:"shutdown"}),y?.close()},status:()=>({connected:m,nodeId:n,cursor:{...W},inflight:se.size,...$g()}),_tick:()=>{Ig(),Md()}}}pl();var zu=(()=>{try{return ZL(import.meta.url)("../package.json").version||null}catch{return null}})(),QL=process.env.BOSTRAT_STATE_DIR||st.join(process.env.HOME||JL.tmpdir(),".bostrat"),PE=st.join(QL,"self-update"),Yu=st.join(PE,"status.json"),eF=1440*6e4,tF=6e4,cc=new Set(["npm-global","git-checkout"]);function DE({kind:e=Lo(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:cc.has(e)?e==="git-checkout"||nF(t)?"auto":"prompt":"off"}function nF(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var Bt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function rF({kind:e,to:t,from:n=zu,statusFile:r=Yu,logFile:o=st.join(PE,"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||st.resolve(st.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!cc.has(e))throw new Error(`self-update: install kind "${e}" is not actionable here`);if(!/^\d+\.\d+\.\d+$/.test(String(t)))throw new Error(`self-update: bad target version "${t}"`);if(n&&!/^\d+\.\d+\.\d+$/.test(String(n)))throw new Error(`self-update: bad current version "${n}"`);let f=(g,k="")=>`write_status ${Bt(g)} ${k}`,d=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${Bt(i)}`,p=`
592
+ `);wL=new Set(["claude","codex","cursor"]);Yi=new Set,gL=e=>Yi.has(e);yL=9e4;JT={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};kh=new Map;Ah=120;ew=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:Sa(e.hookToken),createdAt:Date.now()});ta=new Map,oa=e=>ta.get(e)||(qt?we(qt,e)?.handoff:null)||null;_h=6e4,nn=(e,t,n=15e3)=>eE("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),Ih=new Map,nw=e=>Ih.get(e)||null;xh=new Map;EL=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,AL=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,na=Z.join(En,"worktrees"),Ys=[qi,Cu],Nt=new Map,_L=e=>Nt.get(e)||(qt?qt.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,jo=e=>{let t=new Map([...Nt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=qt?we(qt,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)},Gu=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});sc=e=>kE(e.trackId,e.id,Gu(e));cw=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",Xi=class extends Error{}});lt();import ve from"node:path";import mt from"node:fs";import tW from"node:readline";import{fileURLToPath as nW}from"node:url";import Gt from"express";import rW from"node:http";import oW from"node:https";import $d from"node:os";import{WebSocketServer as sW}from"ws";lt();import yO from"node-pty";async function Zy(e,t,n={}){if(!Pe(t)){fl(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await pr()){fl(e,`host tmux server not running on ${$t}`),e.close(1011,"tmux server unavailable");return}if(!await ye(t)){fl(e,`session "${t}" not found`),e.close(1008,"session not found");return}let r=Xy(n.cols,120,Qy),o=Xy(n.rows,32,eb),s;try{s=yO.spawn(G,["-S",$t,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){fl(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&wf(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(wf(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"&&vO(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{}xO(t)})}var bO=6,kO=250;async function xO(e,t=bO,n=kO){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 Qy=20,eb=6;function vO(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=Qy&&Number(t)>=eb}function Xy(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function wf(e,t){try{e.send(JSON.stringify(t))}catch{}}function fl(e,t){wf(e,{type:"error",message:t})}function tb(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}}Xt();ml();sp();Pr();import{createRequire as aW}from"node:module";var BL=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function fw({tracks:e=[],views:t=[],queuedOf:n=()=>[]}={}){let r=[];for(let o of e)!o||o.archivedAt&&!o.archiving||o.transferredTo||(o.working&&r.push(`working:${o.id}`),o.prompted&&r.push(`prompted:${o.id}`),(n(o.id)??[]).length&&r.push(`queued:${o.id}`),(o.boxes||[]).some(s=>s?.role==="subtask"&&s?.state==="live")&&r.push(`subtask:${o.id}`),Object.values(o.subtasks||{}).some(BL)&&r.push(`merge-back:${o.id}`));return t.some(o=>o?.state==="live"||o?.state==="starting")&&r.push("views"),{busy:r.length>0,reasons:r}}import BE from"node:fs";import Wr from"node:fs/promises";import eF from"node:os";import st from"node:path";import{spawn as tF}from"node:child_process";import{createRequire as nF}from"node:module";he();Hl();import NE from"node:fs";import ic from"node:fs/promises";import FL from"node:http";import on from"node:path";import Yu from"node:os";import{createRequire as UL}from"node:module";import mw from"ws";import jL from"node:path";import LL from"node:os";var ac=process.env.BOSTRAT_STATE_DIR||jL.join(process.env.HOME||LL.tmpdir(),".bostrat");function pw(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 AE(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=pw(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function _E(e){let t=String(e||"").trim();if(!t)return"";let n=/^[a-z][a-z0-9+.-]*:\/\//i.test(t)?t:`wss://${t}`,r;try{r=new URL(n)}catch{return t}let o={"https:":"wss:","http:":"ws:","wss:":"wss:","ws:":"ws:"}[r.protocol];return o?(r.protocol=o,(r.pathname===""||r.pathname==="/")&&(r.pathname="/v1/node"),r.toString()):t}var rn=(()=>{try{return UL(import.meta.url)("../package.json").version||null}catch{return null}})(),IE=process.env.BOSTRAT_STATE_DIR||on.join(process.env.HOME||Yu.tmpdir(),".bostrat");function Lo({env:e=process.env,pkgDir:t=on.resolve(on.dirname(new URL(import.meta.url).pathname),".."),exists:n=NE.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(on.join(t,"..",".git"))?"git-checkout":"dev"}function cc(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 zu(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 HL({home:e=process.env.HOME||Yu.homedir(),env:t=process.env}={}){let n=r=>{try{return NE.statSync(r),!0}catch{return!1}};return{claude:n(on.join(e,".claude",".credentials.json")),codex:n(on.join(t.CODEX_HOME||on.join(e,".codex"),"auth.json"))}}var ot=1,$E=1e3,RE=3e4,WL=6e4,qL=1500,KL=500,Hr=100,GL=2e3,VL=25e3,zL=6e4,PE=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},YL=PE(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),JL=3e4,OE=10*6e4,XL=400,CE=250,ZL=PE(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),hw=4,QL=6e4,ME=6e4;function DE({url:e,token:t,nodeId:n=Yu.hostname(),name:r=Yu.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,metricsMs:c=QL,onUpdateAvailable:l=null,onUpdatePolicy:u=null,onHelloRefused:f=null,updatePolicy:d=null,installKind:p=Lo(),selfUrl:h=`http://127.0.0.1:${process.env.PORT||3362}`,onDegraded:w=null,onRecovered:g=null,ingestMode:b=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:E=YL,unackedRetryMs:S=zL,pingMs:R=VL,maxInflightEvents:M=XL,httpTimeoutMs:T=ZL,stallBackoffMinMs:A=JL,fetchImpl:C=globalThis.fetch,log:I=console}){if(!e||!t)throw new Error("plane-link: url and token are required");if(typeof o!="function")throw new Error("plane-link: listTracks is required");e=_E(e);let W=h.replace(/^http/,"ws"),j=new Set,ee=new Map,q=new Map,O=on.join(IE,"plane-link","cursor.json"),z=on.join(IE,"plane-link","dead-letter.ndjson"),te=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),H={},ke={},ie=new Map,me=null,ce=null,F=0,le=0,de=0,Ae=Promise.resolve(),_e="ws",xt=0,je=!1,_=0,V=!1,Ge=Hr,_t=new Set,at=[],nt=null,y=null,m=!1,k=!1,N=$E,oe=null,fe=null,De=null,ht=null,Re=null,ba=!1,Pc=0;async function YI(){try{H=JSON.parse(await ic.readFile(O,"utf8"))}catch{H={}}}function JI(){ba=!0,!De&&(De=setTimeout(async()=>{if(De=null,!!ba){ba=!1;try{await ic.mkdir(on.dirname(O),{recursive:!0}),await ic.writeFile(O,JSON.stringify(H))}catch(D){I.error("[plane-link] cursor flush failed:",D?.message||D)}}},GL),De.unref?.())}function rt(D){return!y||y.readyState!==mw.OPEN?!1:(y.send(JSON.stringify(D)),!0)}function ka(D){let B=Date.now();for(let{trackId:x,event:P}of D){let K=ie.get(P.id);ie.set(P.id,{trackId:x,seq:P.seq,event:P,sentAt:B,firstSentAt:K?.firstSentAt??B,retryAt:B+S,tries:(K?.tries??0)+1,nacks:K?.nacks??0})}return _e==="http"?(e$(D),!0):rt({v:ot,ch:"events",type:"append",events:D})}function XI(D){let B=null;for(let x of ie.values())x.trackId===D&&(B==null||x.seq<B)&&(B=x.seq);return B}function Md(D){let B=ke[D];if(B==null)return;let x=XI(D),P=x==null?B:Math.min(B,x-1);P>(H[D]??0)&&(H[D]=P,JI())}function xa(){if(me=Date.now(),ce!=null){let D=Date.now()-ce;I.log(`[plane-link] spine sync recovered after ${Math.round(D/1e3)}s degraded (${F} stall redial(s))`);let B=ce;ce=null,F=0,le=0,je=!1,_=0;try{g?.({since:B,downMs:D})}catch(x){I.error(`[plane-link] onRecovered failed: ${x?.message||x}`)}}}function Nd(D){if(!Array.isArray(D)||!D.length)return;let B=new Set;for(let x of D){let P=ie.get(x);P&&(ie.delete(x),(ke[P.trackId]??0)<P.seq&&(ke[P.trackId]=P.seq),B.add(P.trackId))}for(let x of B)Md(x);xa()}function Ag(D,B){de++;let x={at:Date.now(),trackId:D.trackId,seq:D.seq,id:D.event?.id??null,type:D.event?.type??null,reason:B,event:D.event??null};I.error(`[plane-link] DEAD-LETTER ${D.trackId} seq ${D.seq} (${x.type??"?"}): plane rejected it permanently (${B}) \u2014 kept in ${z}`),Ae=Ae.then(async()=>{await ic.mkdir(on.dirname(z),{recursive:!0}),await ic.appendFile(z,JSON.stringify(x)+`
593
+ `)}).catch(P=>I.error(`[plane-link] dead-letter write failed: ${P?.message||P}`))}function _g(D,B,x,P=null){if(!Array.isArray(D)||!D.length)return;let K=new Set,be=Date.now();for(let Ee of D){let Be=ie.get(Ee);Be&&(x?(ie.delete(Ee),Ag(Be,B),(ke[Be.trackId]??0)<Be.seq&&(ke[Be.trackId]=Be.seq),K.add(Be.trackId)):(Be.nacks++,Be.retryAt=be+Math.max(1e3,Number(P)||S)))}for(let Ee of K)Md(Ee);xa()}function Ig(D=Date.now()){let B=1/0;for(let x of ie.values())x.firstSentAt<B&&(B=x.firstSentAt);return B===1/0?0:D-B}function $g(){if(!m||!ie.size)return;let D=Date.now(),B=Ig(D);if(B<E||me!=null&&D-me<E||_e==="http"&&je||le>D)return;F++;let x=Math.min(A*2**(F-1),OE);if(ce==null){ce=D-B,I.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(B/1e3)}s with ${ie.size} event(s) in flight (${_e} door) \u2014 the plane is not answering appends`);try{w?.({since:ce,unacked:ie.size,oldestAgeMs:B,mode:_e})}catch(P){I.error(`[plane-link] onDegraded failed: ${P?.message||P}`)}}if(_e==="http"){je=!0,_=D+x,I.error(`[plane-link] ingest circuit OPEN (stall #${F}); probing /v1/ingest/health in ${Math.round(x/1e3)}s`);return}le=D+x,I.error(`[plane-link] closing the link and redialing in ${Math.round(x/1e3)}s (stall redial #${F})`);try{y?.terminate()}catch{}}function Pd(){if(!m)return;let D=Date.now();if(_e==="http"&&je)return;let B=[...ie.values()].filter(P=>P.event&&P.retryAt<=D&&!(_e==="http"&&_t.has(P.trackId)));if(!B.length)return;B.sort((P,K)=>P.trackId===K.trackId?P.seq-K.seq:P.trackId<K.trackId?-1:1),I.log(`[plane-link] re-sending ${B.length} unacked event(s) the plane never confirmed`);let x=_e==="http"?Ge:Hr;if(_e==="http"){let P=new Map;for(let K of B)(P.get(K.trackId)??P.set(K.trackId,[]).get(K.trackId)).push(K);for(let[,K]of P){if(xt>=hw)return;ka(K.slice(0,x).map(be=>({trackId:be.trackId,event:be.event})))}return}for(let P=0;P<B.length;P+=x){let K=B.slice(P,P+x).map(be=>({trackId:be.trackId,event:be.event}));if(!ka(K))return}}async function ZI(D=null){for(;;){if(!m)return!1;let B=ie.size<M,x=_e!=="http"||xt<hw&&!je&&(!D||!_t.has(D));if(B&&x)return!0;await new Promise(P=>setTimeout(P,100))}}function Dd(){if(nt=null,!m||!at.length)return;let D=at;if(at=[],_e!=="http"){for(let x=0;x<D.length;x+=Hr)ka(D.slice(x,x+Hr));return}let B=new Map;for(let x of D)(B.get(x.trackId)??B.set(x.trackId,[]).get(x.trackId)).push(x);for(let[x,P]of B){if(_t.has(x)||xt>=hw||je){at.push(...P);continue}for(let K=0;K<P.length;K+=Ge)ka(P.slice(K,K+Ge))}at.length&&!nt&&(nt=setTimeout(Dd,CE),nt.unref?.())}let QI=D=>{let B=new Map;for(let{trackId:x,event:P}of D)(B.get(x)??B.set(x,[]).get(x)).push(P);return[...B].map(([x,P])=>({trackId:x,events:P}))},zo=(D,B,x,{progress:P})=>{let K=Date.now();for(let{event:be}of D){let Ee=ie.get(be.id);Ee&&(Ee.nacks++,Ee.retryAt=K+Math.max(1e3,x||S))}P&&xa()};async function e$(D){let B=new Set(D.map(x=>x.trackId));for(let x of B)_t.add(x);xt++;try{let x=await C(`${te}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:QI(D)}),signal:AbortSignal.timeout(T)}),P=(Number(x.headers.get("retry-after"))||0)*1e3;if(x.status===200){let K=await x.json();Ge=Hr;for(let be of K.results??[]){Nd(be.acked??[]);let Ee=(Be,vt)=>{let Lt=new Map;for(let Ye of Be??[])(Lt.get(Ye.reason)??Lt.set(Ye.reason,[]).get(Ye.reason)).push(Ye.id);for(let[Ye,Ng]of Lt)_g(Ng,Ye,vt,K.retryAfterMs??null)};Ee(be.rejected,!0),Ee(be.deferred,!1)}Nd(K.discarded??[]),xa();return}if(x.status===429){zo(D,"overloaded",P||5e3,{progress:!0});return}if(x.status===413&&D.length>1){Ge=Math.max(1,Math.floor(D.length/2)),I.error(`[plane-link] ingest request too large (${D.length} events) \u2014 halving batches to ${Ge}`),zo(D,"too_large",1e3,{progress:!0});return}if(x.status===413){let K=ie.get(D[0].event.id);K&&(ie.delete(K.event.id),Ag(K,"too_large"),(ke[K.trackId]??0)<K.seq&&(ke[K.trackId]=K.seq),Md(K.trackId)),xa();return}if(x.status===401||x.status===403){if(Date.now()-Pc>=ME){Pc=Date.now();let K="";try{K=(await x.json())?.error??""}catch{}I.error(`[plane-link] plane refused ingest (HTTP ${x.status}${K?`: ${K}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}zo(D,`http_${x.status}`,6e4,{progress:!1});return}if(x.status===400){I.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${D.length} event(s) for retry; this is a bug, not data`),zo(D,"http_400",6e4,{progress:!1});return}zo(D,`http_${x.status}`,P||5e3,{progress:!1})}catch(x){let P=x?.name==="TimeoutError"||x?.name==="AbortError";P&&D.length>1&&(Ge=Math.max(1,Math.floor(D.length/2)),I.error(`[plane-link] ingest request of ${D.length} event(s) outlived its ${T} ms deadline \u2014 halving batches to ${Ge}`)),zo(D,P?"timeout":"network",5e3,{progress:!1})}finally{xt--;for(let x of B)_t.delete(x)}}async function t$(){if(_e!=="http"||!je||!m||V)return;let D=Date.now();if(!(_>D)){V=!0;try{let B=await C(`${te}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(T)});if(!B.ok)throw new Error(`HTTP ${B.status}`);I.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),je=!1,_=0,le=Date.now()+T+S+1e3;for(let x of ie.values())x.retryAt=Math.min(x.retryAt,Date.now());Pd()}catch(B){F++;let x=Math.min(A*2**(F-1),OE);_=Date.now()+x,I.error(`[plane-link] ingest door still not answering (${B?.message||B}); next probe in ${Math.round(x/1e3)}s`)}finally{V=!1}}}function Rg(){let D=Date.now();return{mode:_e,unacked:ie.size,oldestUnackedAgeMs:Ig(D),lastProgressAt:me,degradedSince:ce,stallRedials:F,deadLettered:de,http:_e==="http"?{inFlight:xt,circuitOpen:je,nextProbeInMs:je?Math.max(0,_-D):0,batchCap:Ge}:null}}async function Og(){if(!i)return;let D;try{D=await i()}catch(B){I.error("[plane-link] metrics sample failed:",B?.message||B);return}D&&rt({v:ot,ch:"ctl",type:"metrics",metrics:{...D,planeLink:Rg()}})}function n$(){i&&(Re&&clearInterval(Re),Og(),Re=setInterval(Og,c),Re.unref?.())}async function r$(){let D;try{D=await o()}catch(B){I.error("[plane-link] backfill listTracks failed:",B?.message||B);return}rt({v:ot,ch:"ctl",type:"tracks",ids:D.filter(B=>!B.transferredTo).map(B=>B.id).filter(B=>typeof B=="string")});for(let B of D){if(!m)return;let x;try{x=await U(B)}catch{continue}let P=H[B.id]??0,K=x.filter(Ee=>Ee.seq>P&&typeof Ee.id=="string"),be=_e==="http"?Ge:Hr;for(let Ee=0;Ee<K.length;Ee+=be){if(!await ZI(B.id))return;let Be=K.slice(Ee,Ee+Math.min(be,_e==="http"?Ge:Hr)).map(vt=>({trackId:B.id,event:vt}));if(!ka(Be))return}}}function Cg(D){!m||!D?.trackId||typeof D.id!="string"||(at.push({trackId:D.trackId,event:D}),nt||(nt=setTimeout(Dd,CE),nt.unref?.()))}let va=new Map;async function o$(D){let{reqId:B,method:x,path:P,headers:K={},body:be}=D,Ee=Object.fromEntries(Object.entries(K).filter(([,vt])=>vt!=null)),Be=new AbortController;va.set(B,Be);try{if(D.host){await s$(D,Ee,Be);return}let vt=await fetch(h+P,{method:x,headers:Ee,body:be?Buffer.from(be,"base64"):void 0,signal:Be.signal}),Lt=Object.fromEntries(vt.headers);for(let Ye of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete Lt[Ye];if(Lt["content-type"]||(Lt["content-type"]="application/octet-stream"),rt({v:ot,ch:"control",type:"http_head",reqId:B,status:vt.status,headers:Lt}),vt.body){for await(let Ye of vt.body)if(!rt({v:ot,ch:"control",type:"http_data",reqId:B,data:Buffer.from(Ye).toString("base64")}))break}rt({v:ot,ch:"control",type:"http_end",reqId:B,error:null})}finally{va.delete(B)}}function s$(D,B,x){let{reqId:P,method:K,path:be,body:Ee}=D,Be=new URL(h);return new Promise(vt=>{let Lt=FL.request({host:Be.hostname,port:Be.port,method:K,path:be,headers:{...B,host:D.host},signal:x.signal},Ye=>{let{connection:Ng,"keep-alive":TW,"transfer-encoding":EW,upgrade:AW,...a$}=Ye.headers;rt({v:ot,ch:"control",type:"http_head",reqId:P,status:Ye.statusCode||502,headers:a$}),Ye.on("data",i$=>{rt({v:ot,ch:"control",type:"http_data",reqId:P,data:Buffer.from(i$).toString("base64")})||Ye.destroy()}),Ye.on("end",()=>{rt({v:ot,ch:"control",type:"http_end",reqId:P,error:null}),vt()}),Ye.on("error",()=>{rt({v:ot,ch:"control",type:"http_end",reqId:P,error:"view upstream error"}),vt()})});Lt.on("error",Ye=>{rt({v:ot,ch:"control",type:"http_end",reqId:P,error:Ye?.message||"view request failed"}),vt()}),Ee&&Lt.write(Buffer.from(Ee,"base64")),Lt.end()})}function Mg(){if(k)return;y=new mw(e,{headers:{authorization:`Bearer ${t}`}}),y.on("open",async()=>{let B=null;try{B=await s?.()||null}catch{B=null}rt({v:ot,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:rn,installKind:p,...typeof d=="function"?{updatePolicy:d()}:d?{updatePolicy:d}:{},providers:HL(),...B?{agents:B}:{}})}),y.on("message",B=>{let x;try{x=JSON.parse(B)}catch{return}if(x.ch==="ctl"&&x.type==="hello_ok"){m=!0,N=$E,oe=null,I.log(`[plane-link] connected to plane as ${n}`),x.minNodeVersion&&rn&&cc(rn,x.minNodeVersion)&&I.error(`[plane-link] this node is bostrat-node ${rn}; the plane asks for \u2265${x.minNodeVersion} \u2014 update with: ${zu(p)}`);try{u?.(typeof x.updatePolicy=="string"?x.updatePolicy:null)}catch{}let P=typeof x.latestNodeVersion=="string"?x.latestNodeVersion:null;if(P&&rn&&cc(rn,P)&&!j.has(P)){j.add(P),I.log(`[plane-link] bostrat-node ${P} is available (this node runs ${rn}) \u2014 ${zu(p)}`);try{l?.({current:rn,latest:P,min:x.minNodeVersion??null,installKind:p,required:!!(x.minNodeVersion&&cc(rn,x.minNodeVersion))})}catch(be){I.error(`[plane-link] update notice failed: ${be?.message||be}`)}}let K=x.ingest==="http";_e=b==="ws"?"ws":b==="http"||K?"http":"ws",b==="http"&&!K&&I.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),_e==="http"&&I.log("[plane-link] spine rides the HTTPS ingest door"),je=!1,_=0,Ge=Hr,ht&&clearInterval(ht),ht=setInterval(()=>{rt({v:ot,ch:"ctl",type:"ping"}),$g(),t$().catch(()=>{}),Pd(),at.length&&!nt&&Dd()},R),ht.unref?.(),n$(),r$().catch(be=>I.error("[plane-link] backfill failed:",be?.message||be));return}if(x.ch==="ctl"&&x.type==="hello_refused"){let P=typeof x.minNodeVersion=="string"?x.minNodeVersion:null,K=typeof x.latestNodeVersion=="string"?x.latestNodeVersion:null;I.error(`[plane-link] plane REFUSED this node: bostrat-node ${rn??"?"} is below its minimum ${P??"?"} \u2014 ${x.fix||zu(p)}`),N=RE,oe=0;try{f?.({current:rn,min:P,latest:K,fix:x.fix||zu(p),installKind:p})}catch(be){I.error(`[plane-link] refusal handler failed: ${be?.message||be}`)}return}if(x.ch==="ctl"&&x.type==="update_policy"){try{u?.(typeof x.mode=="string"?x.mode:null)}catch{}return}if(x.ch==="ctl"&&x.type==="usage_caps"){Ul(x.caps??{},{source:"plane",updatedAt:x.updatedAt??Date.now()}).then(P=>I.log(`[plane-link] spend caps ${Object.keys(P.caps).length?`updated (${Object.keys(P.caps).join(", ")})`:"cleared"} from plane`)).catch(P=>I.error("[plane-link] spend-caps push rejected:",P?.message||P));return}if(x.ch==="ctl"&&x.type==="transferred"&&Array.isArray(x.tracks)){Promise.resolve().then(()=>a?.(x.tracks)).catch(P=>I.error("[plane-link] transfer notice failed:",P?.message||P));return}if(x.ch==="events"&&x.type==="ack"&&Array.isArray(x.ids)){Nd(x.ids);return}if(x.ch==="events"&&x.type==="nack"&&Array.isArray(x.ids)){_g(x.ids,x.reason,x.permanent===!0,x.retryAfterMs??null);return}if(x.ch==="control"&&x.type==="http_open"){o$(x).catch(P=>rt({v:ot,ch:"control",type:"http_end",reqId:x.reqId,error:P?.message||"tunnel error"}));return}if(x.ch==="control"&&x.type==="http_cancel"){va.get(x.reqId)?.abort();return}if(x.ch==="attach"&&x.type==="open"){let P=new mw(W+x.path,Array.isArray(x.protocols)?x.protocols:[],x.host?{headers:{host:x.host}}:void 0);ee.set(x.streamId,P),q.set(x.streamId,[]),P.on("open",()=>{let be=q.get(x.streamId)||[];q.delete(x.streamId);for(let{buf:Ee,bin:Be}of be)P.send(Ee,{binary:Be})}),P.on("message",(be,Ee)=>{let Be=Ee?be:Buffer.from(String(be));rt({v:ot,ch:"attach",type:"data",streamId:x.streamId,data:Be.toString("base64"),...Ee?{bin:!0}:{}})});let K=()=>{q.delete(x.streamId),ee.delete(x.streamId)&&rt({v:ot,ch:"attach",type:"close",streamId:x.streamId})};P.on("close",K),P.on("error",K);return}if(x.ch==="attach"&&x.type==="data"){let P=ee.get(x.streamId);if(!P)return;let K=Buffer.from(x.data,"base64"),be=x.bin===!0,Ee=q.get(x.streamId);Ee?Ee.push({buf:K,bin:be}):P.send(K,{binary:be});return}if(x.ch==="attach"&&x.type==="close"){let P=ee.get(x.streamId);ee.delete(x.streamId),q.delete(x.streamId),P?.close();return}});let D=()=>{m&&I.log("[plane-link] disconnected from plane"),m=!1,ht&&(clearInterval(ht),ht=null),Re&&(clearInterval(Re),Re=null),ie.clear(),ke={},at=[],nt&&(clearTimeout(nt),nt=null),_t.clear();for(let P of ee.values())P.close();ee.clear(),q.clear();for(let P of va.values())P.abort();if(va.clear(),k||fe)return;oe==null&&(oe=Date.now());let B=Date.now()-oe<WL,x=Math.max(B?qL+Math.random()*KL:N,le-Date.now());fe=setTimeout(()=>{fe=null,Mg()},x),fe.unref?.(),B||(N=Math.min(N*2,RE))};y.on("close",D),y.on("error",B=>{let x=/Unexpected server response: (\d+)/.exec(B?.message||"")?.[1];(x==="401"||x==="403")&&Date.now()-Pc>=ME&&(Pc=Date.now(),I.error(`[plane-link] plane refused this node's credentials (HTTP ${x}) \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)`)),D()})}return ct.on("event",Cg),YI().then(Mg),{stop:()=>{k=!0,ct.off("event",Cg),fe&&clearTimeout(fe),De&&clearTimeout(De),ht&&clearInterval(ht),Re&&clearInterval(Re),nt&&clearTimeout(nt),rt({v:ot,ch:"ctl",type:"bye",reason:"shutdown"}),y?.close()},status:()=>({connected:m,nodeId:n,cursor:{...H},inflight:ie.size,...Rg()}),_tick:()=>{$g(),Pd()}}}hl();var Ju=(()=>{try{return nF(import.meta.url)("../package.json").version||null}catch{return null}})(),rF=process.env.BOSTRAT_STATE_DIR||st.join(process.env.HOME||eF.tmpdir(),".bostrat"),jE=st.join(rF,"self-update"),Xu=st.join(jE,"status.json"),oF=1440*6e4,sF=6e4,lc=new Set(["npm-global","git-checkout"]);function LE({kind:e=Lo(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:lc.has(e)?e==="git-checkout"||aF(t)?"auto":"prompt":"off"}function aF(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var Bt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function iF({kind:e,to:t,from:n=Ju,statusFile:r=Xu,logFile:o=st.join(jE,"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||st.resolve(st.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!lc.has(e))throw new Error(`self-update: install kind "${e}" is not actionable here`);if(!/^\d+\.\d+\.\d+$/.test(String(t)))throw new Error(`self-update: bad target version "${t}"`);if(n&&!/^\d+\.\d+\.\d+$/.test(String(n)))throw new Error(`self-update: bad current version "${n}"`);let f=(g,b="")=>`write_status ${Bt(g)} ${b}`,d=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${Bt(i)}`,p=`
594
594
  health() {
595
595
  for i in $(seq 1 45); do
596
596
  sleep 1
@@ -613,10 +613,10 @@ write_status() { # <status> [error]
613
613
  "\${err:+,\\"error\\":\\"$err\\"}" > "$STATUS_FILE.tmp" && mv "$STATUS_FILE.tmp" "$STATUS_FILE"
614
614
  }
615
615
  ${p}
616
- `;if(e==="npm-global"){let g=a?st.join(a,"bin","npm"):"npm",k=a?`export PATH=${Bt(st.join(a,"bin"))}:"$PATH"
617
- `:"",S=a?` --prefix ${Bt(a)}`:"",E=R=>`${Bt(g)} install -g "bostrat-node@${R}" --no-audit --no-fund${S}`;return h+k+`
616
+ `;if(e==="npm-global"){let g=a?st.join(a,"bin","npm"):"npm",b=a?`export PATH=${Bt(st.join(a,"bin"))}:"$PATH"
617
+ `:"",E=a?` --prefix ${Bt(a)}`:"",S=R=>`${Bt(g)} install -g "bostrat-node@${R}" --no-audit --no-fund${E}`;return h+b+`
618
618
  ${f("updating",'"" ')}
619
- if ! ${E("$TO")}; then
619
+ if ! ${S("$TO")}; then
620
620
  ${f("failed",'"npm install failed"')}
621
621
  exit 1
622
622
  fi
@@ -631,7 +631,7 @@ if health; then
631
631
  fi
632
632
  # \u2500\u2500 rollback: the same primitive with the previous version \u2500\u2500
633
633
  ${f("rolling-back",'"agent did not answer on :'+s+' after the update"')}
634
- if [ -n "$FROM" ] && ${E("$FROM")} && ${d} && health; then
634
+ if [ -n "$FROM" ] && ${S("$FROM")} && ${d} && health; then
635
635
  ${f("rolled-back",'"agent did not answer on :'+s+' after the update; rolled back"')}
636
636
  exit 1
637
637
  fi
@@ -655,64 +655,64 @@ if [ -n "$FROM" ] && ${w("$FROM")}; then
655
655
  fi
656
656
  ${f("failed",'"deploy-pi.sh v$TO failed AND the rollback failed"')}
657
657
  exit 1
658
- `}async function lc(e=Yu){try{return JSON.parse(await Hr.readFile(e,"utf8"))}catch{return null}}var oF=new Set(["updating","restarting","rolling-back"]),Ju=e=>!!(e&&oF.has(e.status));async function Xu({to:e,from:t=zu,kind:n=Lo(),reason:r="manual",statusFile:o=Yu,spawnImpl:s=XL,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!cc.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!ic(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await lc(o);if(Ju(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 Hr.mkdir(st.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?Of(await sF())||st.resolve(st.dirname(process.execPath),".."):null,f=rF({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),d=st.join(st.dirname(o),`update-${e}.sh`),p=st.join(st.dirname(o),"last.log");await Hr.writeFile(d,f,{mode:448}),await Hr.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let h=NE.existsSync("/run/systemd/system")&&await aF("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",d]]:["setsid",["-f","bash","-c",`exec bash ${Bt(d)} >> ${Bt(p)} 2>&1`]];try{s(h[0],h[1],{detached:!0,stdio:"ignore"}).unref?.()}catch(w){return await Hr.writeFile(o,JSON.stringify({status:"failed",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a(),error:`could not spawn updater: ${w?.message||w}`})),{ok:!1,reason:`could not spawn updater: ${w?.message||w}`}}return c.log?.(`[self-update] ${t??"?"} \u2192 ${e} (${n}, ${r}) started \u2014 status ${o}`),{ok:!0,to:e,from:t,kind:n,scriptFile:d,statusFile:o}}async function sF(){try{return await Hr.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function aF(e){for(let t of String(process.env.PATH||"").split(st.delimiter))try{return await Hr.access(st.join(t,e),NE.constants.X_OK),!0}catch{}return!1}var iF=45*6e4;async function BE({statusFile:e=Yu,current:t=zu,now:n=Date.now,staleMs:r=iF}={}){let o=await lc(e);if(!o)return null;let s=a=>Hr.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Ju(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 jE({isBusy:e,start:t=Xu,onStuck:n=null,onStarted:r=null,tickMs:o=tF,stuckMs:s=eF,now:a=Date.now,setIntervalImpl:i=setInterval,clearIntervalImpl:c=clearInterval,log:l=console}={}){let u=null,f=()=>{u?.timer&&c(u.timer),u=null},d=async()=>{if(!u)return;let p=!0;try{p=await e()!==!1}catch{p=!0}if(p){if(!u.stuckFired&&a()-u.since>=s){u.stuckFired=!0;try{await n?.({to:u.to,from:u.from,since:u.since})}catch{}}return}let h=u;f();let w=await t({to:h.to,from:h.from,kind:h.kind,reason:"auto"});l.log?.(`[self-update] stasis reached \u2192 ${w.ok?"started":`not started: ${w.reason}`}`);try{await r?.({...h,result:w})}catch{}};return{arm({to:p,from:h=zu,kind:w=Lo()}){return u?.to===p?!1:(f(),u={to:p,from:h,kind:w,since:a(),stuckFired:!1,timer:i(d,o)},u.timer.unref?.(),!0)},tick:d,cancel:f,get armed(){return u?{to:u.to,from:u.from,kind:u.kind,since:u.since}:null}}}me();it();var cF=(...e)=>fetch(...e);function lF(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function hw(e=process.env){if(!lF(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 cF(`${Ie(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 oa(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await hw(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 Zu(e,t,{source:n="chat"}={}){return $(e,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:t?{circuitId:t.id,circuitName:t.name??null,source:n}:{circuitId:null,source:n}})}me();it();var uF=(...e)=>fetch(...e);async function Qu(e,t,n,r=process.env){if(!(Ie(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 uF(`${Ie(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 dF(e,t=process.env){return Qu("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function LE({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await dF(t,o):await oa(e,o),a=await Qu("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function ww(e,t=process.env){let n=await oa(e,t),r=await Qu("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function gw(e,t=process.env){return(await Qu("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function FE(e,t,n,r=process.env){let{blueprint:o,items:s}=await ww(t,r),a=new Map(s.map(c=>[c.itemId,c])),i=n.filter(c=>!a.get(c)?.bindable);if(i.length){let c=s.filter(l=>l.bindable).map(l=>l.itemId);throw new Error(`unknown/unbindable item(s): ${i.join(", ")} \u2014 bindable ids: ${c.join(", ")||"(none)"}`)}return await $(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}me();it();var fF=(...e)=>fetch(...e);async function pF(e,t,n,r=process.env){if(!(Ie(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 fF(`${Ie(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 UE=72,yw=160;async function HE(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>UE)throw new Error(`the title is the choice as a LABEL \u2014 ${UE} 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 ${yw} chars) a reader can act on without opening the record`);if(c.length>yw)throw new Error(`the summary is one sentence \u2014 ${yw} chars max (yours is ${c.length}); the full story goes in the decision text`);if(!String(r??"").trim())throw new Error("the decision itself is required (what was decided)");return await $(e,{type:"decision.recorded",actor:"orchestrator",source:"orchestrator",payload:{title:i,context:String(n??"").trim(),decision:String(r).trim(),summary:c,alternatives:(Array.isArray(s)?s:[]).map(l=>typeof l=="string"?{label:l}:l).filter(l=>l?.label),...a?{supersedesId:a}:{}}}),{title:i}}function WE(e,t=process.env){return pF("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}ih();me();import hc from"node:fs/promises";import cd from"node:path";import rU from"node:os";cr();import mF from"node:fs/promises";import qE from"node:path";import hF from"node:os";var KE=()=>qE.join(process.env.BOSTRAT_STATE_DIR||qE.join(process.env.HOME||hF.tmpdir(),".bostrat"),"integrations.json");async function nr(){try{return JSON.parse(await mF.readFile(KE(),"utf8"))||{}}catch{return{}}}var ed=["linked","prOpened","prMerged","create"],bw=["prompt","auto","off"],wF={create:["prompt","off"]},GE=e=>wF[e]??bw;function td(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of ed){let s=GE(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 Fo(){let e=await nr(),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:td(e),defaultTeam:n}:null}async function nd(){let e=await nr(),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:td(e)}}async function kw(){return td(await nr())}async function VE(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${ed.join(", ")}`);for(let[r,o]of t){if(!ed.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${ed.join(", ")}`);let s=GE(r);if(!s.includes(o))throw new Error(s.length<bw.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${bw.join(", ")}`)}let n=await nr();return n.ticketFlow={...td(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Tt(KE(),n,{mode:384}),n.ticketFlow}async function uc(){let e=(await nr()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function gF(){let e=(await nr()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var yF={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function rd(){let t=(await nr()).voiceChat||{},n=t.provider||"openai",r=yF[n];if(!r)return null;let o=n==="openai"?await gF():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function zE(){let e=(await nr()).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 Uo(){let e=(await nr()).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}}me();ur();vr();Ks();import fc from"node:fs/promises";import rA from"node:path";import WF from"node:os";import{randomUUID as oA}from"node:crypto";var vw={};Pd(vw,{createComment:()=>_F,findIssueUrl:()=>vF,issueStates:()=>RF,mdToAdf:()=>XE,moveIssue:()=>OF,parseIssueRef:()=>xF,resolveIssue:()=>SF,uploadImage:()=>IF,upsertCard:()=>TF,whoami:()=>xw});var sa=e=>String(e.baseUrl||"").replace(/\/$/,""),JE=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function Ho(e,t,n,r){let o=await fetch(`${sa(e)}${n}`,{method:t,headers:{authorization:JE(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 bF=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,kF=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function xF(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(bF);return r?r[1].toUpperCase():null}let n=t.match(kF);return n?n[1]:null}function vF(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 SF(e,t){let n;try{n=await Ho(e,"GET",`/rest/api/3/issue/${encodeURIComponent(t)}?fields=summary,status`)}catch(r){throw r.status===404?new Error(`jira: issue "${t}" not found`):r}return{issueId:n.id,key:n.key,title:n.fields?.summary??null,url:`${sa(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function TF(e,t,{url:n,title:r,subtitle:o}){await Ho(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 EF=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function AF(e){let t=[],n=0;for(let r of e.matchAll(EF)){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 XE(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
659
- `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...AF(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 _F(e,t,n){let r=await Ho(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:XE(n)});return r?.id?`${sa(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function xw(e){let t=await Ho(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(sa(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function IF(e,{issue:t,filename:n,contentType:r,buffer:o}){let s=new FormData;s.append("file",new Blob([o],{type:r}),n);let a=await fetch(`${sa(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:JE(e),"x-atlassian-token":"no-check",accept:"application/json"},body:s}),i=await a.json().catch(()=>null),c=Array.isArray(i)?i[0]:null;if(!a.ok||!c)throw new Error(`jira: attachment upload failed (HTTP ${a.status})`);return c.content??`${sa(e)}/rest/api/3/attachment/content/${c.id}`}var $F={new:"unstarted",indeterminate:"started",done:"completed"},YE=e=>$F[e?.key]??"started";async function RF(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([Ho(e,"GET",`/rest/api/3/issue/${n}?fields=status`),Ho(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:YE(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:YE(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function OF(e,t,n){await Ho(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var Aw={};Pd(Aw,{createComment:()=>LF,createIssue:()=>Ew,createProject:()=>Tw,findIssueUrl:()=>DF,issueStates:()=>UF,moveIssue:()=>HF,parseIssueRef:()=>PF,resolveIssue:()=>BF,teams:()=>aa,uploadImage:()=>FF,upsertCard:()=>jF,whoami:()=>Sw});var CF=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function _n(e,t,n={}){let r=await fetch(CF(),{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 MF=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,NF=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function PF(e){let t=String(e||"").trim(),n=t.match(MF);if(n)return n[1].toUpperCase();let r=t.match(NF);return r?r[1]:null}function DF(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 BF(e,t){let r=(await _n(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 jF(e,t,{url:n,title:r,subtitle:o}){let s=await _n(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 LF(e,t,n){let r=await _n(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 Sw(e){let t=await _n(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 FF(e,{filename:t,contentType:n,buffer:r}){let o=await _n(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
658
+ `}async function uc(e=Xu){try{return JSON.parse(await Wr.readFile(e,"utf8"))}catch{return null}}var cF=new Set(["updating","restarting","rolling-back"]),Zu=e=>!!(e&&cF.has(e.status));async function Qu({to:e,from:t=Ju,kind:n=Lo(),reason:r="manual",statusFile:o=Xu,spawnImpl:s=tF,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!lc.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!cc(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await uc(o);if(Zu(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 Wr.mkdir(st.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?Mf(await lF())||st.resolve(st.dirname(process.execPath),".."):null,f=iF({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),d=st.join(st.dirname(o),`update-${e}.sh`),p=st.join(st.dirname(o),"last.log");await Wr.writeFile(d,f,{mode:448}),await Wr.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let h=BE.existsSync("/run/systemd/system")&&await uF("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",d]]:["setsid",["-f","bash","-c",`exec bash ${Bt(d)} >> ${Bt(p)} 2>&1`]];try{s(h[0],h[1],{detached:!0,stdio:"ignore"}).unref?.()}catch(w){return await Wr.writeFile(o,JSON.stringify({status:"failed",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a(),error:`could not spawn updater: ${w?.message||w}`})),{ok:!1,reason:`could not spawn updater: ${w?.message||w}`}}return c.log?.(`[self-update] ${t??"?"} \u2192 ${e} (${n}, ${r}) started \u2014 status ${o}`),{ok:!0,to:e,from:t,kind:n,scriptFile:d,statusFile:o}}async function lF(){try{return await Wr.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function uF(e){for(let t of String(process.env.PATH||"").split(st.delimiter))try{return await Wr.access(st.join(t,e),BE.constants.X_OK),!0}catch{}return!1}var dF=45*6e4;async function FE({statusFile:e=Xu,current:t=Ju,now:n=Date.now,staleMs:r=dF}={}){let o=await uc(e);if(!o)return null;let s=a=>Wr.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Zu(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 UE({isBusy:e,start:t=Qu,onStuck:n=null,onStarted:r=null,tickMs:o=sF,stuckMs:s=oF,now:a=Date.now,setIntervalImpl:i=setInterval,clearIntervalImpl:c=clearInterval,log:l=console}={}){let u=null,f=()=>{u?.timer&&c(u.timer),u=null},d=async()=>{if(!u)return;let p=!0;try{p=await e()!==!1}catch{p=!0}if(p){if(!u.stuckFired&&a()-u.since>=s){u.stuckFired=!0;try{await n?.({to:u.to,from:u.from,since:u.since})}catch{}}return}let h=u;f();let w=await t({to:h.to,from:h.from,kind:h.kind,reason:"auto"});l.log?.(`[self-update] stasis reached \u2192 ${w.ok?"started":`not started: ${w.reason}`}`);try{await r?.({...h,result:w})}catch{}};return{arm({to:p,from:h=Ju,kind:w=Lo()}){return u?.to===p?!1:(f(),u={to:p,from:h,kind:w,since:a(),stuckFired:!1,timer:i(d,o)},u.timer.unref?.(),!0)},tick:d,cancel:f,get armed(){return u?{to:u.to,from:u.from,kind:u.kind,since:u.since}:null}}}he();it();var fF=(...e)=>fetch(...e);function pF(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function ww(e=process.env){if(!pF(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 fF(`${Ie(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 sa(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await ww(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 ed(e,t,{source:n="chat"}={}){return $(e,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:t?{circuitId:t.id,circuitName:t.name??null,source:n}:{circuitId:null,source:n}})}he();it();var mF=(...e)=>fetch(...e);async function td(e,t,n,r=process.env){if(!(Ie(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 mF(`${Ie(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 hF(e,t=process.env){return td("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function HE({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await hF(t,o):await sa(e,o),a=await td("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function gw(e,t=process.env){let n=await sa(e,t),r=await td("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function yw(e,t=process.env){return(await td("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function WE(e,t,n,r=process.env){let{blueprint:o,items:s}=await gw(t,r),a=new Map(s.map(c=>[c.itemId,c])),i=n.filter(c=>!a.get(c)?.bindable);if(i.length){let c=s.filter(l=>l.bindable).map(l=>l.itemId);throw new Error(`unknown/unbindable item(s): ${i.join(", ")} \u2014 bindable ids: ${c.join(", ")||"(none)"}`)}return await $(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}he();it();var wF=(...e)=>fetch(...e);async function gF(e,t,n,r=process.env){if(!(Ie(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 wF(`${Ie(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 qE=72,bw=160;async function KE(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>qE)throw new Error(`the title is the choice as a LABEL \u2014 ${qE} 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 ${bw} chars) a reader can act on without opening the record`);if(c.length>bw)throw new Error(`the summary is one sentence \u2014 ${bw} chars max (yours is ${c.length}); the full story goes in the decision text`);if(!String(r??"").trim())throw new Error("the decision itself is required (what was decided)");return await $(e,{type:"decision.recorded",actor:"orchestrator",source:"orchestrator",payload:{title:i,context:String(n??"").trim(),decision:String(r).trim(),summary:c,alternatives:(Array.isArray(s)?s:[]).map(l=>typeof l=="string"?{label:l}:l).filter(l=>l?.label),...a?{supersedesId:a}:{}}}),{title:i}}function GE(e,t=process.env){return gF("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}ch();he();import wc from"node:fs/promises";import ud from"node:path";import iU from"node:os";lr();import yF from"node:fs/promises";import VE from"node:path";import bF from"node:os";var zE=()=>VE.join(process.env.BOSTRAT_STATE_DIR||VE.join(process.env.HOME||bF.tmpdir(),".bostrat"),"integrations.json");async function nr(){try{return JSON.parse(await yF.readFile(zE(),"utf8"))||{}}catch{return{}}}var nd=["linked","prOpened","prMerged","create"],kw=["prompt","auto","off"],kF={create:["prompt","off"]},YE=e=>kF[e]??kw;function rd(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of nd){let s=YE(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 Fo(){let e=await nr(),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:rd(e),defaultTeam:n}:null}async function od(){let e=await nr(),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:rd(e)}}async function xw(){return rd(await nr())}async function JE(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${nd.join(", ")}`);for(let[r,o]of t){if(!nd.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${nd.join(", ")}`);let s=YE(r);if(!s.includes(o))throw new Error(s.length<kw.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${kw.join(", ")}`)}let n=await nr();return n.ticketFlow={...rd(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Tt(zE(),n,{mode:384}),n.ticketFlow}async function dc(){let e=(await nr()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function xF(){let e=(await nr()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var vF={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function sd(){let t=(await nr()).voiceChat||{},n=t.provider||"openai",r=vF[n];if(!r)return null;let o=n==="openai"?await xF():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function XE(){let e=(await nr()).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 Uo(){let e=(await nr()).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}}he();dr();Sr();Gs();import pc from"node:fs/promises";import aA from"node:path";import VF from"node:os";import{randomUUID as iA}from"node:crypto";var Sw={};Bd(Sw,{createComment:()=>OF,findIssueUrl:()=>AF,issueStates:()=>NF,mdToAdf:()=>eA,moveIssue:()=>PF,parseIssueRef:()=>EF,resolveIssue:()=>_F,uploadImage:()=>CF,upsertCard:()=>IF,whoami:()=>vw});var aa=e=>String(e.baseUrl||"").replace(/\/$/,""),QE=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function Ho(e,t,n,r){let o=await fetch(`${aa(e)}${n}`,{method:t,headers:{authorization:QE(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 SF=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,TF=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function EF(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(SF);return r?r[1].toUpperCase():null}let n=t.match(TF);return n?n[1]:null}function AF(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 _F(e,t){let n;try{n=await Ho(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:`${aa(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function IF(e,t,{url:n,title:r,subtitle:o}){await Ho(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 $F=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function RF(e){let t=[],n=0;for(let r of e.matchAll($F)){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 eA(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
659
+ `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...RF(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 OF(e,t,n){let r=await Ho(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:eA(n)});return r?.id?`${aa(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function vw(e){let t=await Ho(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(aa(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function CF(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(`${aa(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:QE(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??`${aa(e)}/rest/api/3/attachment/content/${c.id}`}var MF={new:"unstarted",indeterminate:"started",done:"completed"},ZE=e=>MF[e?.key]??"started";async function NF(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([Ho(e,"GET",`/rest/api/3/issue/${n}?fields=status`),Ho(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:ZE(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:ZE(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function PF(e,t,n){await Ho(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var _w={};Bd(_w,{createComment:()=>WF,createIssue:()=>Aw,createProject:()=>Ew,findIssueUrl:()=>FF,issueStates:()=>KF,moveIssue:()=>GF,parseIssueRef:()=>LF,resolveIssue:()=>UF,teams:()=>ia,uploadImage:()=>qF,upsertCard:()=>HF,whoami:()=>Tw});var DF=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function _n(e,t,n={}){let r=await fetch(DF(),{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 BF=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,jF=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function LF(e){let t=String(e||"").trim(),n=t.match(BF);if(n)return n[1].toUpperCase();let r=t.match(jF);return r?r[1]:null}function FF(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 UF(e,t){let r=(await _n(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 HF(e,t,{url:n,title:r,subtitle:o}){let s=await _n(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 WF(e,t,n){let r=await _n(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 Tw(e){let t=await _n(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 qF(e,{filename:t,contentType:n,buffer:r}){let o=await _n(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
660
660
  fileUpload(contentType: $contentType, filename: $filename, size: $size) {
661
661
  success
662
662
  uploadFile { uploadUrl assetUrl headers { key value } }
663
663
  }
664
- }`,{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 UF(e,t){let n=await _n(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 HF(e,t,n){if(!(await _n(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 aa(e){return((await _n(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var ZE=255;async function Tw(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>ZE,a=s?`${o.slice(0,ZE-1).trimEnd()}\u2026`:o,i=await _n(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 Ew(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await _n(e,"mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier url title } } }",{input:{teamId:t,title:n,...r?{description:r}:{},...o?{projectId:o}:{},...Number.isInteger(s)?{priority:s}:{}}}),i=a.issueCreate?.issue;if(!a.issueCreate?.success||!i)throw new Error("linear: issueCreate did not succeed");return{id:i.id,key:i.identifier,url:i.url,title:i.title}}var sA={linear:{api:Aw,config:Fo},jira:{api:vw,config:nd}};async function Mw(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(sA)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function Wo(e){let t=sA[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function Nw(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 aA=()=>process.env.BOSTRAT_STATE_DIR||rA.join(process.env.HOME||WF.tmpdir(),".bostrat"),Rw=()=>rA.join(aA(),"tickets.json"),iA=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),od=e=>`${iA()}/track/${e}`,Wr=null,_w=null,Iw=Promise.resolve();async function mc(){return Wr||(_w??=fc.readFile(Rw(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{if(Wr=e,!t&&Ne()){let{records:n,source:r}=await et("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;Wr[s]=i}Object.keys(Wr).length&&await Ow().catch(()=>{})}}return Wr}).finally(()=>_w=null),_w)}async function Ow(){let e=JSON.stringify({tickets:Wr},null,2),t=`${Rw()}.${process.pid}.tmp`;await fc.mkdir(aA(),{recursive:!0}),await fc.writeFile(t,e),await fc.rename(t,Rw())}async function qr(e=null){if(Iw=Iw.then(Ow,Ow),await Iw.catch(()=>{}),!e)return;let t=Wr?.[e];t?wt("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):Vt("tickets",e).catch(()=>{})}async function In(e){return(await mc())[e]??null}async function cA(){return{...await mc()}}async function lA(){return(await Mw()).length>0}async function ia(e,t,{source:n="api"}={}){let r=await Mw();if(!r.length)throw new Error("no ticketing integration configured \u2014 add a linear or jira entry to ~/.bostrat/integrations.json");let o=null,s=null,a=null;for(let u of r){let f=u.api.parseIssueRef(t);if(f)try{s=await u.api.resolveIssue(u.cfg,f),o=u;break}catch(d){a=d}}if(!o)throw a||new Error(`"${t}" is not a Linear or Jira issue URL or key (ABC-123)`);let i=(e.boxes||[]).find(u=>u.name===e.leadBox),c={provider:o.name,key:s.key,issueId:s.issueId,url:s.url,title:s.title,state:s.state,source:n,linkedAt:Date.now(),track:{name:e.name,branch:e.workspace?.branch??null,leadAgent:i?.agent??null,cwd:e.cwd??null,...e.workspace?.kind==="multi"?{repos:(e.workspace.repos??[]).map(u=>u?.name).filter(Boolean)}:{}},pr:null};(await mc())[e.id]=c,await qr(e.id),await $({id:e.id,cwd:e.cwd},{type:"ticket.linked",actor:"user",source:"orchestrator",payload:{ts:Date.now(),provider:c.provider,key:c.key,url:c.url,title:c.title,linkSource:n}}).catch(()=>{}),await pc(e.id,c);let l=[];return c.track.branch&&l.push(`\`${c.track.branch}\``),c.track.repos?.length&&l.push(`repos ${c.track.repos.join(" + ")}`),c.track.leadAgent&&l.push(`lead ${c.track.leadAgent}`),await dc(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await fA(e.id,c,"linked"),c}async function Pw(e){let t=await mc();return t[e]?(delete t[e],await qr(e),!0):!1}var Cw=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function uA(e,t){if(!e.track?.cwd)return null;let n=xr(await F({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function qF(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${Cw(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${Cw(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function KF(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(Cw(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function pc(e,t){let n=await Wo(t);if(!n)return;let r=await uA(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:od(e),title:`Bostrat Track: ${t.track.name}`,subtitle:KF(t,r)})}function sd(e){let t=new URL(iA());return`${t.protocol}//${e}.${t.host}/`}var GF={linked:"linked",opened:"prOpened",merged:"prMerged"};function VF(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 dA(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await qr(e),await $({id:e,cwd:t.track?.cwd},{type:"ticket.state.changed",actor:a,source:"orchestrator",payload:{ts:Date.now(),key:t.key,url:t.url,from:n??null,to:r,mode:o,...s?{phase:s}:{}}}).catch(()=>{})}async function fA(e,t,n){let r=await Wo(t);if(!r)return;let o=r.cfg.ticketFlow?.[GF[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Nw(s,a),c=VF(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 dA(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await $({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:oA(),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 pA(e){let t=await In(e);if(!t)throw new Error("no ticket linked to this Track");let n=await Wo(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=Nw(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await qr(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 Dw(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await In(e);if(!r)throw new Error("no ticket linked to this Track");let o=await Wo(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Nw(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 qr(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await dA(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function mA(e,t){let n=await In(e);if(!n)throw new Error("no ticket linked to this Track");let r=await Wo(n);if(!r)throw new Error("no ticketing integration configured");let o=String(t||"").trim();if(!o)throw new Error("comment body required");let s=await r.api.createComment(r.cfg,n,o);return await $({id:e,cwd:n.track?.cwd},{type:"ticket.commented",actor:"user",source:"orchestrator",payload:{ts:Date.now(),key:n.key,url:s??n.url,excerpt:o.length>280?`${o.slice(0,279)}\u2026`:o}}).catch(()=>{}),{key:n.key,url:s??n.url}}async function hA(e,t,n){if(!t)throw new Error("offerId required");let r=await F({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 Dw(e.id,o.payload.to?.id,{mode:"offer"})),await $({id:e.id,cwd:e.cwd},{type:"ticket.move.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,action:n?"moved":"dismiss",...s?{from:s.from,to:s.to}:{}}}),{offerId:t,action:n?"moved":"dismiss",...s??{}}}var QE=50;async function wA(){let e=await Fo();if(!e)throw new Error("no ticketing integration configured");return aa(e)}function zF(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>QE)throw new Error(`too many issues (${n.length}); cap is ${QE} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function YF(e,t,n,r){let o=r??await aa(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 In(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 gA(e,t){let n=await Fo();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=zF(t),o=await aa(n),s=await YF(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=oA();return await $({id:e.id,cwd:e.cwd},{type:"ticket.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:i,provider:"linear",epic:r.epic,issues:r.issues,team:a,needsTeam:!s,linkCurrentTrack:r.linkCurrentTrack}}),{proposalId:i,epic:r.epic,issues:r.issues,team:a,needsTeam:!s}}async function yA(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await F({id:e.id,cwd:e.cwd}),s=o.find(h=>h.type==="ticket.create.offered"&&h.payload?.proposalId===t);if(!s)throw new Error("unknown proposal");if(o.some(h=>h.type==="ticket.create.answered"&&h.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await $({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};let a=await Fo();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let h=(await aa(a)).find(w=>w.id===r);if(!h)throw new Error("unknown team");c={id:h.id,key:h.key,name:h.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],f=null;if(i.epic){let h=await Tw(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});f=h.id,l.push({kind:"epic",title:h.name,url:h.url})}for(let h of i.issues||[])try{let w=await Ew(a,{teamId:c.id,title:h.title,description:h.description,projectId:f,priority:h.priority});l.push({kind:"issue",key:w.key,title:w.title,url:w.url})}catch(w){u.push({title:h.title,message:w?.message||String(w)})}await $({id:e.id,cwd:e.cwd},{type:"ticket.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,team:{key:c.key,name:c.name},items:l,failed:u}}),await $({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",createdCount:l.length,failedCount:u.length}});let d=l.filter(h=>h.kind==="issue"),p=null;return i.linkCurrentTrack&&d.length===1&&!await In(e.id)&&(p=await ia(e,d[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:p?p.key:null}}async function dc(e,t){let n=await Wo(e);n&&await n.api.createComment(n.cfg,e,t)}async function JF(e,t,n){let r=await Wo(e);if(!r)return null;let o=await Yn(t);if(!o)return null;let s=tn(o,n);if(!s)return null;let a=await fc.readFile(Wt(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 eA=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),$w=new Map;function XF(e,t){if(eA()<=0)return pc(e,t);if($w.has(e))return;let n=setTimeout(()=>{$w.delete(e),In(e).then(r=>r?pc(e,r):null).catch(()=>{})},eA());n.unref?.(),$w.set(e,n)}var tA=new Map;async function nA(e,t,n){let r=tA.get(e)??0;Date.now()-r<600*1e3||(tA.set(e,Date.now()),await $({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function ZF(e,{resolveTrack:t=null}={}){let n=await In(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Mw())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 nA(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 qr(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await qr(e.trackId),await pc(e.trackId,n);break;case"pr.state.changed":{if(!r.change)break;if(r.number&&(n.pr={number:r.number,url:r.url??n.pr?.url??null,change:r.change}),await qr(e.trackId),await pc(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await uA(n,e.trackId).catch(()=>null):null;await dc(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
664
+ }`,{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 KF(e,t){let n=await _n(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 GF(e,t,n){if(!(await _n(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 ia(e){return((await _n(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var tA=255;async function Ew(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>tA,a=s?`${o.slice(0,tA-1).trimEnd()}\u2026`:o,i=await _n(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 Aw(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await _n(e,"mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier url title } } }",{input:{teamId:t,title:n,...r?{description:r}:{},...o?{projectId:o}:{},...Number.isInteger(s)?{priority:s}:{}}}),i=a.issueCreate?.issue;if(!a.issueCreate?.success||!i)throw new Error("linear: issueCreate did not succeed");return{id:i.id,key:i.identifier,url:i.url,title:i.title}}var cA={linear:{api:_w,config:Fo},jira:{api:Sw,config:od}};async function Nw(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(cA)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function Wo(e){let t=cA[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function Pw(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 lA=()=>process.env.BOSTRAT_STATE_DIR||aA.join(process.env.HOME||VF.tmpdir(),".bostrat"),Ow=()=>aA.join(lA(),"tickets.json"),uA=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),ad=e=>`${uA()}/track/${e}`,qr=null,Iw=null,$w=Promise.resolve();async function hc(){return qr||(Iw??=pc.readFile(Ow(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{if(qr=e,!t&&Ne()){let{records:n,source:r}=await et("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;qr[s]=i}Object.keys(qr).length&&await Cw().catch(()=>{})}}return qr}).finally(()=>Iw=null),Iw)}async function Cw(){let e=JSON.stringify({tickets:qr},null,2),t=`${Ow()}.${process.pid}.tmp`;await pc.mkdir(lA(),{recursive:!0}),await pc.writeFile(t,e),await pc.rename(t,Ow())}async function Kr(e=null){if($w=$w.then(Cw,Cw),await $w.catch(()=>{}),!e)return;let t=qr?.[e];t?wt("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):Vt("tickets",e).catch(()=>{})}async function In(e){return(await hc())[e]??null}async function dA(){return{...await hc()}}async function fA(){return(await Nw()).length>0}async function ca(e,t,{source:n="api"}={}){let r=await Nw();if(!r.length)throw new Error("no ticketing integration configured \u2014 add a linear or jira entry to ~/.bostrat/integrations.json");let o=null,s=null,a=null;for(let u of r){let f=u.api.parseIssueRef(t);if(f)try{s=await u.api.resolveIssue(u.cfg,f),o=u;break}catch(d){a=d}}if(!o)throw a||new Error(`"${t}" is not a Linear or Jira issue URL or key (ABC-123)`);let i=(e.boxes||[]).find(u=>u.name===e.leadBox),c={provider:o.name,key:s.key,issueId:s.issueId,url:s.url,title:s.title,state:s.state,source:n,linkedAt:Date.now(),track:{name:e.name,branch:e.workspace?.branch??null,leadAgent:i?.agent??null,cwd:e.cwd??null,...e.workspace?.kind==="multi"?{repos:(e.workspace.repos??[]).map(u=>u?.name).filter(Boolean)}:{}},pr:null};(await hc())[e.id]=c,await Kr(e.id),await $({id:e.id,cwd:e.cwd},{type:"ticket.linked",actor:"user",source:"orchestrator",payload:{ts:Date.now(),provider:c.provider,key:c.key,url:c.url,title:c.title,linkSource:n}}).catch(()=>{}),await mc(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 hA(e.id,c,"linked"),c}async function Dw(e){let t=await hc();return t[e]?(delete t[e],await Kr(e),!0):!1}var Mw=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function pA(e,t){if(!e.track?.cwd)return null;let n=vr(await U({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function zF(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${Mw(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${Mw(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function YF(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(Mw(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function mc(e,t){let n=await Wo(t);if(!n)return;let r=await pA(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:ad(e),title:`Bostrat Track: ${t.track.name}`,subtitle:YF(t,r)})}function id(e){let t=new URL(uA());return`${t.protocol}//${e}.${t.host}/`}var JF={linked:"linked",opened:"prOpened",merged:"prMerged"};function XF(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 mA(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await Kr(e),await $({id:e,cwd:t.track?.cwd},{type:"ticket.state.changed",actor:a,source:"orchestrator",payload:{ts:Date.now(),key:t.key,url:t.url,from:n??null,to:r,mode:o,...s?{phase:s}:{}}}).catch(()=>{})}async function hA(e,t,n){let r=await Wo(t);if(!r)return;let o=r.cfg.ticketFlow?.[JF[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Pw(s,a),c=XF(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 mA(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await $({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:iA(),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 wA(e){let t=await In(e);if(!t)throw new Error("no ticket linked to this Track");let n=await Wo(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=Pw(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await Kr(e)),{key:t.key,url:t.url,current:s?{id:s.id,name:s.name??null,type:s.type??null}:null,states:[...o].sort((a,i)=>a.position-i.position).map(({id:a,name:i,type:c,position:l})=>({id:a,name:i,type:c,position:l}))}}async function Bw(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await In(e);if(!r)throw new Error("no ticket linked to this Track");let o=await Wo(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Pw(s,a),c=a.find(u=>u.id===t);if(!c)throw new Error("unknown state for this ticket's team");let l=i?.name??r.state??null;return i?.id===c.id?(r.state!==c.name&&(r.state=c.name,await Kr(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await mA(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function gA(e,t){let n=await In(e);if(!n)throw new Error("no ticket linked to this Track");let r=await Wo(n);if(!r)throw new Error("no ticketing integration configured");let o=String(t||"").trim();if(!o)throw new Error("comment body required");let s=await r.api.createComment(r.cfg,n,o);return await $({id:e,cwd:n.track?.cwd},{type:"ticket.commented",actor:"user",source:"orchestrator",payload:{ts:Date.now(),key:n.key,url:s??n.url,excerpt:o.length>280?`${o.slice(0,279)}\u2026`:o}}).catch(()=>{}),{key:n.key,url:s??n.url}}async function yA(e,t,n){if(!t)throw new Error("offerId required");let r=await U({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 Bw(e.id,o.payload.to?.id,{mode:"offer"})),await $({id:e.id,cwd:e.cwd},{type:"ticket.move.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,action:n?"moved":"dismiss",...s?{from:s.from,to:s.to}:{}}}),{offerId:t,action:n?"moved":"dismiss",...s??{}}}var nA=50;async function bA(){let e=await Fo();if(!e)throw new Error("no ticketing integration configured");return ia(e)}function ZF(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>nA)throw new Error(`too many issues (${n.length}); cap is ${nA} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function QF(e,t,n,r){let o=r??await ia(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 In(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 kA(e,t){let n=await Fo();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=ZF(t),o=await ia(n),s=await QF(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=iA();return await $({id:e.id,cwd:e.cwd},{type:"ticket.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:i,provider:"linear",epic:r.epic,issues:r.issues,team:a,needsTeam:!s,linkCurrentTrack:r.linkCurrentTrack}}),{proposalId:i,epic:r.epic,issues:r.issues,team:a,needsTeam:!s}}async function xA(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await U({id:e.id,cwd:e.cwd}),s=o.find(h=>h.type==="ticket.create.offered"&&h.payload?.proposalId===t);if(!s)throw new Error("unknown proposal");if(o.some(h=>h.type==="ticket.create.answered"&&h.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await $({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};let a=await Fo();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let h=(await ia(a)).find(w=>w.id===r);if(!h)throw new Error("unknown team");c={id:h.id,key:h.key,name:h.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],f=null;if(i.epic){let h=await Ew(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});f=h.id,l.push({kind:"epic",title:h.name,url:h.url})}for(let h of i.issues||[])try{let w=await Aw(a,{teamId:c.id,title:h.title,description:h.description,projectId:f,priority:h.priority});l.push({kind:"issue",key:w.key,title:w.title,url:w.url})}catch(w){u.push({title:h.title,message:w?.message||String(w)})}await $({id:e.id,cwd:e.cwd},{type:"ticket.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,team:{key:c.key,name:c.name},items:l,failed:u}}),await $({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",createdCount:l.length,failedCount:u.length}});let d=l.filter(h=>h.kind==="issue"),p=null;return i.linkCurrentTrack&&d.length===1&&!await In(e.id)&&(p=await ca(e,d[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:p?p.key:null}}async function fc(e,t){let n=await Wo(e);n&&await n.api.createComment(n.cfg,e,t)}async function eU(e,t,n){let r=await Wo(e);if(!r)return null;let o=await Yn(t);if(!o)return null;let s=tn(o,n);if(!s)return null;let a=await pc.readFile(Wt(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 rA=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),Rw=new Map;function tU(e,t){if(rA()<=0)return mc(e,t);if(Rw.has(e))return;let n=setTimeout(()=>{Rw.delete(e),In(e).then(r=>r?mc(e,r):null).catch(()=>{})},rA());n.unref?.(),Rw.set(e,n)}var oA=new Map;async function sA(e,t,n){let r=oA.get(e)??0;Date.now()-r<600*1e3||(oA.set(e,Date.now()),await $({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function nU(e,{resolveTrack:t=null}={}){let n=await In(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Nw())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 ca(s,o,{source:"chat"})}catch(a){await sA(e.trackId,s.cwd,a)}return}if(!n.track.cwd&&t){let o=await t(e.trackId).catch(()=>null);o?.cwd&&(n.track.cwd=o.cwd,await Kr(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await Kr(e.trackId),await mc(e.trackId,n);break;case"pr.state.changed":{if(!r.change)break;if(r.number&&(n.pr={number:r.number,url:r.url??n.pr?.url??null,change:r.change}),await Kr(e.trackId),await mc(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await pA(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?`
665
665
 
666
- Agent cost for this Track: ${qF(o)}.`:"")),await fA(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await JF(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await dc(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
666
+ Agent cost for this Track: ${zF(o)}.`:"")),await hA(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await eU(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}\`)`:""}:
667
667
 
668
- ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await dc(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 dc(n,`**Bostrat** \u2014 live preview **${r.name}**: ${sd(r.slug)}
669
- _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await XF(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await nA(e.trackId,s?.cwd??null,o)}}function bA({resolveTrack:e}){ct.on("event",t=>{ZF(t,{resolveTrack:e}).catch(()=>{})})}async function kA(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await mc(),r=0;for(let[o,s]of Object.entries(n))await wt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}bo();Ks();import QF from"ws";var xA=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function ad(e,t,n={}){let r=await fetch(`${xA()}/${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 Bw=(e,t)=>ad("chat.postMessage",e,t),qo=(e,t)=>ad("chat.update",e,t);async function bt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function eU(e,t,n={}){let r=await fetch(`${xA()}/${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 vA(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await eU("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 ad("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var tU=2200;function SA({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 ad("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new QF(l),o.on("message",u=>{let f;try{f=JSON.parse(u)}catch{return}if(f.type==="hello"){a=1e3,n("socket connected");return}if(f.type==="disconnect"){try{o.close()}catch{}return}if(!f.envelope_id)return;let d=w=>{try{o.send(JSON.stringify(w?{envelope_id:f.envelope_id,payload:w}:{envelope_id:f.envelope_id}))}catch{}},p=!1,h=setTimeout(()=>{p=!0,d()},tU);Promise.resolve().then(()=>t(f)).then(w=>{clearTimeout(h),!p&&(p=!0,d(f.accepts_response_payload?w:void 0))},w=>{clearTimeout(h),p||(p=!0,d()),n(`envelope handler failed: ${w?.message||w}`)})}),o.on("close",c),o.on("error",u=>{n(`socket error: ${u?.message||u}`);try{o.close()}catch{}})}function c(){if(r||s)return;let l=a;a=Math.min(a*2,6e4),s=setTimeout(()=>{s=null,i()},l)}return i(),()=>{r=!0,s&&clearTimeout(s);try{o?.close()}catch{}}}var AA=()=>process.env.BOSTRAT_STATE_DIR||cd.join(process.env.HOME||rU.tmpdir(),".bostrat"),Hw=()=>cd.join(AA(),"slack.json"),id=null,jw=null,Lw=Promise.resolve();async function qw(){return id||(jw??=hc.readFile(Hw(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>id=e).finally(()=>jw=null),jw)}async function TA(){let e=JSON.stringify({threads:id},null,2),t=`${Hw()}.${process.pid}.tmp`;await hc.mkdir(AA(),{recursive:!0}),await hc.writeFile(t,e),await hc.rename(t,Hw())}async function sn(){Lw=Lw.then(TA,TA),await Lw.catch(()=>{})}async function Kw(e){return(await qw())[e]??null}async function oU(e,t){let n=await qw();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var ke=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function wc(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function sU(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return wc(n.replace(/\n+/g," "),t)}function _A(e){let t=`*${ke(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${ke(e.repoLabel)} \xB7 \`${ke(e.branch||"?")}\` \xB7 lead *${ke(e.lead)}*`,r=e.kickoff?`> ${ke(wc(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
670
- ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${od(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function Ww(e,t){await qo(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:_A(t)})}async function Gr(e,t,n,r=void 0){return Bw(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var EA=new Set;function Kr(e){EA.add(e),e.catch(()=>{}).finally(()=>EA.delete(e))}var Me=e=>({response_type:"ephemeral",text:e}),aU="*/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._",iU=["claude","cursor","codex"];function Fw(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 Uw=(e,t)=>Me(`No live Track matches \u201C${ke(t)}\u201D. Live: ${e.map(n=>`\`${ke(n.name)}\``).join(" \xB7 ")||"none"}`);async function IA(e,t,{name:n,repo:r,responseUrl:o}){let s=e.deps;try{let a=(await s.listTracks()).filter(f=>!f.archivedAt);if(a.length>=t.maxConcurrent){await bt(o,{...Me(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await bt(o,{...Me("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?cd.basename(c.base):"fresh workspace"),lead:"claude"},u=await Bw(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:_A(l),unfurl_links:!1});l.ts=u.ts,(await qw())[i.id]=l,await sn(),await bt(o,{...Me(`\u2713 *${ke(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await bt(o,{...Me(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function cU(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await Kw(n.id);s&&(s.archivedAt=Date.now(),await sn(),await Ww(t,s).catch(()=>{})),await bt(r,{...Me(`\u2713 *${ke(n.name)}* archived.`),replace_original:!0})}catch(s){await bt(r,{...Me(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function lU(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await bt(o,{...Me(`\u2713 Handing *${ke(n.name)}* to ${ke(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await bt(o,{...Me(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function uU(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 bt(r,{...Me(`\u2713 Stopped *${ke(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 bt(r,{...Me(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function dU(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:wc(`${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 *${ke(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function fU(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?cd.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 *${ke(s.name)}* \u2014 ${ke(i)}${a.branch?` \`${ke(a.branch)}\``:""} \xB7 lead ${ke(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
668
+ ![${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}**: ${id(r.slug)}
669
+ _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await tU(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await sA(e.trackId,s?.cwd??null,o)}}function vA({resolveTrack:e}){ct.on("event",t=>{nU(t,{resolveTrack:e}).catch(()=>{})})}async function SA(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await hc(),r=0;for(let[o,s]of Object.entries(n))await wt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}bo();Gs();import rU from"ws";var TA=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function cd(e,t,n={}){let r=await fetch(`${TA()}/${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 jw=(e,t)=>cd("chat.postMessage",e,t),qo=(e,t)=>cd("chat.update",e,t);async function bt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function oU(e,t,n={}){let r=await fetch(`${TA()}/${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 EA(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await oU("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 cd("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var sU=2200;function AA({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 cd("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new rU(l),o.on("message",u=>{let f;try{f=JSON.parse(u)}catch{return}if(f.type==="hello"){a=1e3,n("socket connected");return}if(f.type==="disconnect"){try{o.close()}catch{}return}if(!f.envelope_id)return;let d=w=>{try{o.send(JSON.stringify(w?{envelope_id:f.envelope_id,payload:w}:{envelope_id:f.envelope_id}))}catch{}},p=!1,h=setTimeout(()=>{p=!0,d()},sU);Promise.resolve().then(()=>t(f)).then(w=>{clearTimeout(h),!p&&(p=!0,d(f.accepts_response_payload?w:void 0))},w=>{clearTimeout(h),p||(p=!0,d()),n(`envelope handler failed: ${w?.message||w}`)})}),o.on("close",c),o.on("error",u=>{n(`socket error: ${u?.message||u}`);try{o.close()}catch{}})}function c(){if(r||s)return;let l=a;a=Math.min(a*2,6e4),s=setTimeout(()=>{s=null,i()},l)}return i(),()=>{r=!0,s&&clearTimeout(s);try{o?.close()}catch{}}}var $A=()=>process.env.BOSTRAT_STATE_DIR||ud.join(process.env.HOME||iU.tmpdir(),".bostrat"),Ww=()=>ud.join($A(),"slack.json"),ld=null,Lw=null,Fw=Promise.resolve();async function Kw(){return ld||(Lw??=wc.readFile(Ww(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>ld=e).finally(()=>Lw=null),Lw)}async function _A(){let e=JSON.stringify({threads:ld},null,2),t=`${Ww()}.${process.pid}.tmp`;await wc.mkdir($A(),{recursive:!0}),await wc.writeFile(t,e),await wc.rename(t,Ww())}async function sn(){Fw=Fw.then(_A,_A),await Fw.catch(()=>{})}async function Gw(e){return(await Kw())[e]??null}async function cU(e,t){let n=await Kw();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var xe=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function gc(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function lU(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return gc(n.replace(/\n+/g," "),t)}function RA(e){let t=`*${xe(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${xe(e.repoLabel)} \xB7 \`${xe(e.branch||"?")}\` \xB7 lead *${xe(e.lead)}*`,r=e.kickoff?`> ${xe(gc(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
670
+ ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${ad(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function qw(e,t){await qo(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:RA(t)})}async function Vr(e,t,n,r=void 0){return jw(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var IA=new Set;function Gr(e){IA.add(e),e.catch(()=>{}).finally(()=>IA.delete(e))}var Me=e=>({response_type:"ephemeral",text:e}),uU="*/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._",dU=["claude","cursor","codex"];function Uw(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 Hw=(e,t)=>Me(`No live Track matches \u201C${xe(t)}\u201D. Live: ${e.map(n=>`\`${xe(n.name)}\``).join(" \xB7 ")||"none"}`);async function OA(e,t,{name:n,repo:r,responseUrl:o}){let s=e.deps;try{let a=(await s.listTracks()).filter(f=>!f.archivedAt);if(a.length>=t.maxConcurrent){await bt(o,{...Me(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await bt(o,{...Me("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?ud.basename(c.base):"fresh workspace"),lead:"claude"},u=await jw(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:RA(l),unfurl_links:!1});l.ts=u.ts,(await Kw())[i.id]=l,await sn(),await bt(o,{...Me(`\u2713 *${xe(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await bt(o,{...Me(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function fU(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await Gw(n.id);s&&(s.archivedAt=Date.now(),await sn(),await qw(t,s).catch(()=>{})),await bt(r,{...Me(`\u2713 *${xe(n.name)}* archived.`),replace_original:!0})}catch(s){await bt(r,{...Me(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function pU(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await bt(o,{...Me(`\u2713 Handing *${xe(n.name)}* to ${xe(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await bt(o,{...Me(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function mU(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 bt(r,{...Me(`\u2713 Stopped *${xe(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 bt(r,{...Me(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function hU(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:gc(`${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 *${xe(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function wU(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?ud.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 *${xe(s.name)}* \u2014 ${xe(i)}${a.branch?` \`${xe(a.branch)}\``:""} \xB7 lead ${xe(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
671
671
  `)+(o?`
672
- _${o} archived_`:"")}async function pU(e,t){let n=await Uo();if(!n)return Me("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 Me("Usage: `/bostrat start <name> [repo]`");let i=await r.listRepos(),c=a[a.length-1]?.toLowerCase(),l=a.length>1?i.find(f=>f.name.toLowerCase()===c):null,u=(l?a.slice(0,-1):a).join(" ");return l?(Kr(IA(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),Me(`Starting *${ke(u)}* on ${ke(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:dU(u,i)}}case"archive":{if(!a.length)return Me("Usage: `/bostrat archive <track>`");let{match:i,live:c}=Fw(await r.listTracks(),a.join(" "));return i?(Kr(cU(e,n,{track:i,responseUrl:t.response_url})),Me(`Archiving *${ke(i.name)}*\u2026`)):Uw(c,a.join(" "))}case"handoff":{let i=r.knownAgents??iU,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return Me(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:f}=Fw(await r.listTracks(),l);return u?(Kr(lU(e,n,{track:u,agent:c,responseUrl:t.response_url})),Me(`Handing *${ke(u.name)}* to ${ke(c)}\u2026`)):Uw(f,l)}case"stop":{if(!a.length)return Me("Usage: `/bostrat stop <track>`");let{match:i,live:c}=Fw(await r.listTracks(),a.join(" "));return i?(Kr(uU(e,n,{track:i,responseUrl:t.response_url})),Me(`Stopping *${ke(i.name)}*\u2026`)):Uw(c,a.join(" "))}case"list":return Me(await fU(r));default:return Me(aU)}}async function mU(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await Kw(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 sn(),await qo(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ke(l||"question")}~
673
- \u2713 *${ke(a)}*`}}]}).catch(()=>{})}}catch(c){await bt(n.response_url,Me(`Couldn't answer: ${c?.message||c}`))}}async function hU(e,t,n,r){let{trackId:o,offerId:s,action:a}=r,i=e.deps;try{let c=await i.resolveTrack(o);if(!c)throw new Error("track not found");let l=await i.readEvents(c),u=l.find(d=>d.type==="pr.offered"&&d.payload?.offerId===s);if(!u)throw new Error("unknown offer");if(l.some(d=>d.type==="pr.offer.answered"&&d.payload?.offerId===s))throw new Error("offer already answered");let f=Array.isArray(r.actions)?Ar.filter(d=>r.actions.includes(d)):a==="pr"?["commit","push","pr"]:a==="push"?["commit","push"]:null;if(f?.includes("pr")&&i.divertShip&&await i.divertShip(c,u,{actions:f}))return;f&&await i.sayToLead(c.id,Os(f,{branch:u.payload.branch,base:u.payload.base}),{kind:f.includes("pr")?"pr-go":"push-go"}),await i.appendEvent({id:c.id,cwd:c.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:u.boxId,payload:{ts:Date.now(),offerId:s,action:f?a:"dismiss",actions:f}})}catch(c){await bt(n.response_url,Me(`Couldn't act on the offer: ${c?.message||c}`))}}async function wU(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 bt(n.response_url,Me(`Couldn't act on the offer: ${i?.message||i}`))}}async function gU(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await Uo();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 bt(t.response_url,{...Me(`Starting *${ke(s)}*\u2026`),replace_original:!0}),Kr(IA(e,r,{name:s,repo:a==="__fresh__"?null:a,responseUrl:t.response_url}));return}let o;try{o=JSON.parse(n.value)}catch{return}n.action_id==="bostrat-prompt"?Kr(mU(e,r,t,o)):n.action_id==="bostrat-ship"?Kr(hU(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&Kr(wU(e,r,t,o))}async function yU(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 oU(t.channel,t.thread_ts);if(!n)return;let r=await Uo();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await Gr(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function bU(e){return async t=>{if(t.type==="slash_commands")return pU(e,t.payload);if(t.type==="interactive"){await gU(e,t.payload);return}if(t.type==="events_api"){await yU(e,t.payload?.event);return}}}var kU=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 xU(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${ke(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:wc(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 vU(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await qo(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ke(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await Gr(e,t,r.question||"The lead needs an answer",xU(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await sn()}async function SU(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 sn(),await qo(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ke(s||"question")}~
674
- \u2713 _answered_`}}]})}async function TU(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=(i,c,l,u)=>({type:"button",action_id:"bostrat-ship",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,action:i,...u?{actions:u}:{}}),...l?{style:l}:{}}),s;if(!Array.isArray(r.available))s=r.toPr?[o("push",`Commit & push${r.toPr.number?` to #${r.toPr.number}`:""}`,"primary"),o("dismiss","Not now")]:[o("pr","Open PR","primary"),o("push","Just push"),o("dismiss","Not now")];else{let i=r.available,c=Array.isArray(r.defaults)&&r.defaults.length?r.defaults:i,l={commit:"Commit",rebase:"rebase",push:"push",pr:r.prState==="open"?"open new PR":"open PR"},u=c.map(f=>l[f]).filter(Boolean).join(" & ");s=[o(c.includes("pr")?"pr":"push",u||"Ship","primary",c)],i.includes("pr")&&!c.includes("pr")&&s.push(o("pr","Open new PR",void 0,["pr"])),s.push(o("dismiss","Not now"))}let a=await Gr(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${ke(wc(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await sn()}async function EU(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await sn();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 qo(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function AU(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 Gr(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${ke(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 sn()}async function _U(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await sn();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await qo(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function IU(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??$U)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await vA(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${ke(o.name)}*${a}${o.group?` (group \`${ke(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${ke(a.name)}*`).join(", ");await Gr(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${ke(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function $U(e,t){let n=await Yn(e);if(!n)return null;let r=tn(n,t);if(!r)return null;let o=await hc.readFile(Wt(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function RU(e,t){if(!kU.has(t.type))return;let n=await Kw(t.trackId);if(!n)return;let r=await Uo();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 sn(),await Ww(r,n);return;case"turn.agent":{if(!o.text)return;let s=sU(o.text);if(!s)return;await Gr(r,n,s,[{type:"section",text:{type:"mrkdwn",text:ke(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${od(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return vU(r,n,t);case"prompt.answered":return SU(r,n,t);case"pr.offered":return TU(r,n,t);case"pr.offer.answered":return EU(r,n,t);case"pr.exists.offered":return AU(r,n,t);case"pr.exists.answered":return _U(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 Gr(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 sn(),await Ww(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await Gr(r,n,`Live preview ${o.name}: ${sd(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${ke(o.name)}*: ${sd(o.slug)}
675
- _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return IU(r,n,t,e.deps)}}function $A(e){let t={deps:e};ct.on("event",s=>{RU(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await Uo()||(r&&clearInterval(r),r=null,n=SA({getToken:async()=>(await Uo())?.appToken,onEnvelope:bU(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}Xt();me();dn();um();Dn();import OU from"node:fs/promises";function CU(e){let t=new Map;for(let n of String(e||"").split(`
676
- `)){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 MU(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 NU=new Set(["Write","Edit","NotebookEdit"]),PU=220,DU=160;function BU(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(NU.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,PU)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=no(o.command.trim().replace(/\s+/g," ")).slice(0,DU));return r}function jU(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?Jt(t.cwd,t.sessionId):t?.cwd?gf(t.cwd):null}async function RA(e,t){let n=await t(e?.session_id,e?.cwd);if(!n?.track)return[];let{track:r,box:o}=n,s={boxId:o?.name||null,provider:"claude",source:"hook"},a=[],i=async c=>{a.push(await $(r,{...s,...c}))};switch(e?.hook_event_name){case"SessionStart":await i({type:"session.ready",actor:"system",payload:{sessionId:e.session_id}});break;case"UserPromptSubmit":{let c=String(e.prompt??e.user_prompt??""),l=iu(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:BU(e,o)});break;case"Stop":await LU(r,o,e,i);break;default:break}return a}async function LU(e,t,n,r){let o=[],s=jU(n,t);if(s)try{o=CU(await OU.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=MU(await F(e)),c=o.filter(u=>!i.has(u.messageId));if(c.length){let u=new Map;for(let f of c){let d=`${f.model||"unknown"}\0${f.speed||""}`,p=u.get(d)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},cacheWriteTtl:null,messageIds:[]};for(let h of Object.keys(p.tokens))p.tokens[h]+=f.tokens[h];f.cacheWriteTtl&&(p.cacheWriteTtl??={m5:0,h1:0},p.cacheWriteTtl.m5+=f.cacheWriteTtl.m5,p.cacheWriteTtl.h1+=f.cacheWriteTtl.h1),p.messageIds.push(f.messageId),p.speed=f.speed||null,u.set(d,p)}for(let[f,d]of u){let p=f.split("\0")[0];await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:p,usd:mn(p,d.tokens,void 0,d.speed?{speed:d.speed}:void 0),tokens:d.tokens,...d.speed?{speed:d.speed}:{},cacheWriteTtl:d.cacheWriteTtl,messageId:d.messageIds[d.messageIds.length-1],messageIds:d.messageIds,apiCalls:d.messageIds.length}})}}let l=a.tokens.input+a.tokens.cacheWrite+a.tokens.cacheRead;await r({type:"context.usage",actor:"system",source:"transcript",payload:{model:a.model,occupancy:l,tokens:a.tokens}})}Yo();lf();me();kl();wu();import{execFile as FU}from"node:child_process";import{promisify as UU}from"node:util";var HU=UU(FU),Gw=(e,t)=>HU("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4});function OA(e,t=Date.now()){return Vd(e,t)??0}function WU(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 CA(e,t,{now:n=Date.now()}={}){let r=OA(t,n),o=await F(e);return hu({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:WU(o,t.name,r)})}function qU(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=null;for(let c=n.length-1;c>=0;c--){let l=n[c];if(l.type==="turn.user"&&l.boxId===t.name&&l.actor==="user"){i=Pn(l.payload?.promptHead||l.payload?.text||"")?.category??null;break}}return{wallReason:a,fixerCategory:i}}async function KU(e,t){try{let{stdout:n}=await Gw(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 GU(e){try{let{stdout:t}=await Gw(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function MA(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 F(e);if(a.some(p=>p.type==="code.committed"&&p.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s;try{let{stdout:p}=await Gw(r,["show","-s","--format=%ct",n]),h=Number(p.trim())*1e3;Number.isFinite(h)&&h>0&&(i=h)}catch{return{recorded:!1,reason:"unknown-sha"}}let c=OA(t,i),l=await KU(r,n),u=await $(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:await GU(r),...l,ts:i}}),f=null,d=!1;try{let p=await mS(r,n,{fixKey:Us({trackId:e.id,boxId:t.name,epoch:c}),window:Dr,context:{...qU(e,t,a,c),provider:t.agent??null}});if(p){f=await $(e,{type:"code.rework",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:u.id,payload:p});let h=hS(p);if(h>=pS){let w=p.origins.filter(g=>g.class==="rework").slice(0,3);await $(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:f.id,payload:{sha:n,subject:p.subject,linesReworked:h,origins:w.map(g=>({key:g.key,provider:g.provider,model:g.model,lines:g.lines,ageDays:g.ageDays})),heuristic:p.heuristic,ts:i}}),d=!0}}}catch(p){o.warn?.(`[rework] ${e.id}: analysis of ${String(n).slice(0,7)} failed: ${p?.message||p}`)}return{recorded:!0,event:u,rework:f,offered:d}}async function NA(e,t,n){if(!$i.includes(n))throw new Error(`bad cause "${n}" (${$i.join("|")})`);let r=await F(e),o=r.find(s=>s.type==="rework.cause.offered"&&s.payload?.sha===t);if(!o)throw new Error("unknown rework offer");if(r.some(s=>s.type==="rework.cause.answered"&&s.payload?.sha===t))throw new Error("already answered");return $(e,{type:"rework.cause.answered",actor:"user",source:"orchestrator",boxId:o.boxId??null,causationId:o.id,payload:{sha:t,cause:n,level:"B",ts:Date.now()}})}me();me();vr();me();vr();Dn();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 PA=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),DA=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},ld=e=>Math.round(e*1e4)/1e4;async function Vw(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=PA(),f=0,d=[];for(let p of e||[]){let h=await F(p),w=xr(h,{boxLabels:gc(p)});if(w.turns===0){p.archivedAt?f++:d.push(p.name||p.id);continue}o+=w.totalUsd,s+=w.turns,a+=w.repricedTurns||0,i+=w.asRecordedUsd||0,c+=w.unpricedTurns||0;for(let g of w.unpricedModels||[])l.add(g);DA(u,w.totalTokens);for(let[g,k]of Object.entries(w.byModel))n[g]||={usd:0,events:0,tokens:PA()},n[g].usd=ld(n[g].usd+k.usd),n[g].events+=k.events,DA(n[g].tokens,k.tokens);for(let[g,k]of Object.entries(w.byProvider))r[g]||={usd:0,events:0},r[g].usd=ld(r[g].usd+k.usd),r[g].events+=k.events;t.push({id:p.id,name:p.name,usd:w.totalUsd,rollup:w})}return t.sort((p,h)=>h.usd-p.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:bs(),fleet:{totalUsd:ld(o),asRecordedUsd:ld(i),turns:s,repricedTurns:a,unpricedTurns:c,unpricedModels:[...l],totalTokens:u,byModel:n,byProvider:r,tracksWithCost:t.length,tracksSilent:f+d.length,tracksSilentArchived:f,tracksSilentLive:d},tracks:t}}var Vr=e=>`$${e.toFixed(4)}`,ca=(e,t)=>String(e).padEnd(t);function BA(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 ${Vr(t.totalUsd)} over ${t.turns} turn(s) \xB7 ${t.tracksWithCost} track(s) with cost, ${t.tracksSilentArchived??t.tracksSilent} silent (archived)`+(o.length?`, ${o.length} LIVE with no cost data: ${o.join(", ")}`:"")),t.repricedTurns&&r.push(`${t.repricedTurns} turn(s) priced at current table rates (differs from as-recorded)`),t.asRecordedUsd!=null&&Math.abs(t.asRecordedUsd-t.totalUsd)>=.005&&r.push(`as-recorded total ${Vr(t.asRecordedUsd)} \xB7 current-rates total ${Vr(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${Vr(t.totalUsd-t.asRecordedUsd)})`),t.unpricedTurns&&r.push(`\u26A0 ${t.unpricedTurns} turn(s) UNPRICED \u2014 total under-reports. Add PER_MTOK rate(s) for: ${(t.unpricedModels||[]).join(", ")}`),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(` ${ca(a,26)} ${ca(Vr(i.usd),10)} ${i.events} turn(s) \xB7 in ${c.input} out ${c.output} cacheR ${c.cacheRead} cacheW ${c.cacheCreation}`)}r.push(""),r.push("BY TRACK / TASK");for(let a of n){r.push(` ${ca(a.name||a.id,30)} ${Vr(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${ca(c.label,40)} ${ca(Vr(c.usd),10)} ${c.models.join(",")||"?"}`),c.epochs)for(let[l,u]of Object.entries(c.epochs).sort((f,d)=>Number(f[0])-Number(d[0])))r.push(` \u21B3 tenure ${l} (${u.provider||"?"})${" ".repeat(Math.max(1,24-String(u.provider||"?").length))}${ca(Vr(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
677
- `)}me();Wp();import XU from"node:fs/promises";import ZU from"node:path";kl();vr();var ud=e=>e.payload?.ts??e.ts,VU=12e4,zr=e=>Math.round(e*1e4)/1e4,zU=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},byTrack:new Map});function YU(e,{since:t}){let{track:n,events:r,brief:o}=e,s=S=>ud(S)>=t,a=Pn([ri(n?.name),ri(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let S of r)if(S.type==="subtask.delegated"&&S.boxId&&S.payload?.task){let E=Pn(S.payload.task);E&&i.set(S.boxId,E)}let c=new Map,l=S=>{let E=S||"unattributed";return c.has(E)||c.set(E,{segments:[u(null)],lastTs:null,provider:null}),c.get(E)},u=S=>({textCat:S,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),f=[...r].sort((S,E)=>ud(S)-ud(E)),d=0,p=0,h=0,w={turns:0};for(let S of f){let E=l(S.boxId),R=E.segments[E.segments.length-1],B=ud(S);switch(E.lastTs!=null&&B>E.lastTs&&s(S)&&(R.activeMs+=Math.min(B-E.lastTs,VU)),E.lastTs=B,S.provider&&(E.provider=S.provider),S.type){case"turn.user":{let T=S.payload?.text;if(S.source==="hook"||!String(T||"").trim())break;let _=u(Pn(T));E.segments.push(_),s(S)&&(_.turns+=1);break}case"peer.message":{let T=S.payload?.text;if(!String(T||"").trim())break;let _=u(Pn(T));E.segments.push(_),s(S)&&(_.turns+=1);break}case"tool.called":{if(S.source==="transcript")break;let T=S.payload?.tool;T&&(R.tools[T]=(R.tools[T]||0)+1),s(S)&&(R.toolCalls+=1);break}case"cost.recorded":{if(!s(S))break;let{usd:T,tokens:_,model:O,unpriced:I}=Ft(S);I&&(w.turns+=1),R.usd+=T,_&&(R.tokens.input+=_.input,R.tokens.output+=_.output,R.tokens.cacheRead+=_.cacheRead,R.tokens.cacheWrite+=_.cacheWrite),R.models[O]=(R.models[O]||0)+T,S.provider&&(R.provider=S.provider);break}case"handoff.done":s(S)&&(d+=1);break;case"subtask.merged":s(S)&&(p+=1);break;case"error":s(S)&&S.payload?.kind==="subtask-failed"&&(h+=1);break;default:break}}let g=new Map,k=!1;for(let[S,E]of c)for(let R of E.segments){if(!(R.usd>0||R.activeMs>0||R.turns>0||R.toolCalls>0))continue;let T=R.textCat?.category??i.get(S)?.category??Ub(R.tools)?.category??a?.category??"uncategorized";g.has(T)||g.set(T,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{}});let _=g.get(T);_.usd+=R.usd,_.activeMs+=R.activeMs,_.turns+=R.turns,_.toolCalls+=R.toolCalls;for(let[I,U]of Object.entries(R.models))_.models[I]=(_.models[I]||0)+U;let O=R.provider||E.provider;O&&(_.providers[O]=(_.providers[O]||0)+R.usd),O==="cursor"&&R.usd===0&&(k=!0)}return{perCategory:g,handoffs:d,merged:p,failed:h,sawCursorActivity:k,unpricedTurns:w.turns}}function LA(e,{windowMs:t=null,now:n=Date.now()}={}){let r=t==null?0:n-t,o=new Map,s=[],a=0,i=!1,c=0;for(let w of e||[]){let{track:g,events:k}=w;if(!k?.length){a+=1;continue}let{perCategory:S,handoffs:E,merged:R,failed:B,sawCursorActivity:T,unpricedTurns:_}=YU(w,{since:r});T&&(i=!0),c+=_;let O={trackId:g?.id,name:g?.name||g?.id,archived:!!g?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:E,subtasksMerged:R,subtasksFailed:B};for(let[I,U]of S){O.usd+=U.usd,O.activeMs+=U.activeMs,O.turns+=U.turns,O.categories[I]={usd:zr(U.usd),activeMs:U.activeMs};for(let[X,C]of Object.entries(U.models))O.models[X]=zr((O.models[X]||0)+C);for(let[X,C]of Object.entries(U.providers))O.providers[X]=zr((O.providers[X]||0)+C);o.has(I)||o.set(I,zU());let H=o.get(I);H.usd+=U.usd,H.activeMs+=U.activeMs,H.turns+=U.turns,H.toolCalls+=U.toolCalls;for(let[X,C]of Object.entries(U.models))H.models[X]=(H.models[X]||0)+C;for(let[X,C]of Object.entries(U.providers))H.providers[X]=(H.providers[X]||0)+C;let ae=H.byTrack.get(g?.id)||{usd:0,activeMs:0};ae.usd+=U.usd,ae.activeMs+=U.activeMs,H.byTrack.set(g?.id,ae)}(O.usd>0||O.activeMs>0||O.turns>0)&&(O.usd=zr(O.usd),O.dominantCategory=JU(O.categories),s.push(O))}let l=[...o.values()].reduce((w,g)=>w+g.usd,0),u=[...o.values()].reduce((w,g)=>w+g.activeMs,0),f=l>0?"usd":"time",d=f==="usd"?l:u,p=new Map((e||[]).map(w=>[w.track?.id,w.track?.name||w.track?.id])),h=[...o.entries()].map(([w,g])=>({category:w,sharePct:d>0?Math.round((f==="usd"?g.usd:g.activeMs)/d*100):0,shareBasis:f,usd:zr(g.usd),activeMs:g.activeMs,turns:g.turns,toolCalls:g.toolCalls,models:jA(g.models),providers:jA(g.providers),topWorkstreams:[...g.byTrack.entries()].sort((k,S)=>S[1].usd-k[1].usd||S[1].activeMs-k[1].activeMs).slice(0,2).map(([k,S])=>({trackId:k,name:p.get(k),usd:zr(S.usd),activeMs:S.activeMs}))})).sort((w,g)=>g.usd-w.usd||g.activeMs-w.activeMs);return s.sort((w,g)=>g.usd-w.usd||g.activeMs-w.activeMs),{since:r,capturedAt:n,totalUsd:zr(l),activeMs:u,turns:[...o.values()].reduce((w,g)=>w+g.turns,0),bullets:h,workstreams:s,gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c}}}var JU=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},jA=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,zr(n)]));var la={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function QU(e){let t=String(e||"7d");return t in la?{key:t,ms:la[t]}:{key:"7d",ms:la["7d"]}}function e4(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=Wl(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 t4(e){if(!e?.cwd)return null;try{let n=(await XU.readFile(ZU.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 FA(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}:QU(t),f=[];for(let d of e||[]){let p=await F(d),h=e4(d,p);i&&c<o&&(h=h.filter(w=>(w.ts??0)<=c)),f.push({track:d,events:h,brief:await t4(d)})}return{window:l,...LA(f,{windowMs:u,now:c})}}Dn();var Yr=36e5,qA=24*Yr,n4=400,r4=12,Ko=e=>Math.round(e*1e4)/1e4;function zw({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 la?String(e||"7d"):"7d",i=la[a];return{key:a,since:i==null?null:r-i,until:r}}var o4=(e,t)=>e!=null&&t-e<=48*Yr?Yr:qA;function UA(e,t){if(t===Yr)return Math.floor(e/Yr)*Yr;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function s4(e,t){if(t===Yr)return e+Yr;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var HA=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),WA=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},a4=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Ko(n)]));async function KA(e,t={}){let n=t.now??Date.now(),r=zw({...t,now:n}),o=r.since==null?qA:o4(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=HA(),f=0,d=0,p=0,h=0,w=0,g=0,k=new Set,S=new Map,E=[],R=[],B=[],T=null;for(let I of e||[]){let H=(await F(I)).filter(C=>C.type==="cost.recorded");if(!H.length){I.archivedAt||B.push(I.name||I.id);continue}let ae=[];for(let C of H){let Q=C.ts??0;s(Q)?ae.push(C):i(Q)&&(g+=Ft(C).usd)}if(!ae.length)continue;let X=xr(ae,{boxLabels:gc(I)});f+=X.totalUsd,d+=X.turns,p+=X.repricedTurns||0,h+=X.asRecordedUsd||0,w+=X.unpricedTurns||0;for(let C of X.unpricedModels||[])k.add(C);WA(u,X.totalTokens);for(let[C,Q]of Object.entries(X.byModel))c[C]||={usd:0,events:0,tokens:HA()},c[C].usd=Ko(c[C].usd+Q.usd),c[C].events+=Q.events,WA(c[C].tokens,Q.tokens);for(let[C,Q]of Object.entries(X.byProvider))l[C]||={usd:0,events:0},l[C].usd=Ko(l[C].usd+Q.usd),l[C].events+=Q.events;for(let C of ae){let{usd:Q}=Ft(C);if(!Q)continue;let ve=UA(C.ts??0,o),W=S.get(ve)??{t:ve,total:0,byProvider:{}};W.total+=Q;let be=C.provider||"unknown";W.byProvider[be]=(W.byProvider[be]||0)+Q,S.set(ve,W),(T==null||ve<T)&&(T=ve)}E.push({id:I.id,name:I.name||I.id,archived:!!I.archivedAt,usd:X.totalUsd,turns:X.turns,providers:Object.keys(X.byProvider)});for(let[C,Q]of Object.entries(X.byBox))R.push({trackId:I.id,trackName:I.name||I.id,boxId:C,...Q})}let _=r.since!=null?UA(r.since,o):T,O=[];for(let I=_,U=0;I!=null&&I<r.until&&U<n4;I=s4(I,o),U++){let H=S.get(I);O.push(H?{t:I,total:Ko(H.total),byProvider:a4(H.byProvider)}:{t:I,total:0,byProvider:{}})}return E.sort((I,U)=>U.usd-I.usd),R.sort((I,U)=>U.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:O,fleet:{totalUsd:Ko(f),asRecordedUsd:Ko(h),turns:d,repricedTurns:p,unpricedTurns:w,unpricedModels:[...k],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:E.length,tracksSilentLive:B},prior:a!=null?{totalUsd:Ko(g),since:r.since-a,until:r.since}:null,tracks:E.slice(0,50),boxes:R.slice(0,r4)}}wu();var i4=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),c4=20,l4=40;async function GA(e,t={}){let n=t.now??Date.now(),r=zw({...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 F(l),f=0,d=gc(l);for(let p of u){if(!i4.has(p.type))continue;let h=p.type==="code.rework"?p.payload?.ts??p.ts:p.ts;p.type!=="rework.cause.answered"&&!o(h??0)||(p.type==="code.committed"&&f++,s.push(p.trackId?p:{...p,trackId:l.id}))}f&&i++;for(let p of l.boxes||[])a[`${l.id}/${p.name}`]={trackName:l.name||l.id,label:d[p.name]||p.name}}let c=wS(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:Dr,decayEndDays:$m,basis:c.basis,commits:c.commits,tracksWithCommits:i,fixesAnalyzed:c.fixes.length,fixUsdTotal:c.fixUsdTotal,buckets:c.buckets,verdicts:c.verdicts,pendingTaps:c.pendingTaps.length,byProvider:c.byProvider,byModel:c.byModel,epochs:c.epochs.slice(0,c4),fixes:c.fixes.slice(0,l4)}}import u4 from"node:fs";import VA from"node:fs/promises";import yc from"node:os";import d4 from"node:path";Gm();lt();var f4=1024*1024,dd=e=>Math.round(e/f4);async function p4(e){try{let t=await VA.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:dd(r),diskTotalMb:dd(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function m4(){try{return(await zt()).filter(t=>t.isBostrat).length}catch{return null}}async function h4(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await VA.readdir(d4.join(sc,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function zA({stateDir:e=sc,now:t=Date.now}={}){let n=yc.totalmem(),[r,o,s,a]=await Promise.all([Su().catch(()=>null),p4(u4.existsSync(e)?e:yc.tmpdir()),m4(),h4()]),i=yc.cpus()?.length||null,c=yc.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?dd(n-r):null,memTotalMb:dd(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(yc.uptime())}}me();Hf();Oa();Dn();me();Dn();var w4=864e5;function g4(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=mn(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 YA(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*w4,s={},a=0,i=0,c=[];for(let u of e||[]){let f=await F(u);for(let d of f){if(!d.ts||d.ts<o)continue;let p=g4(d,{tolerance:n});if(!p)continue;a++;let h=p.speed?`${p.model} (${p.speed})`:p.model,w=s[h]||={rows:0,divergent:0,asRecordedUsd:0,expectedUsd:0};w.rows++,w.asRecordedUsd+=p.asRecorded,w.expectedUsd+=p.expected,p.divergent&&(i++,w.divergent++,c.length<10&&c.push({track:u.name||u.id,...p}))}}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}}Em();Fl();it();Bn();import ua from"node:fs/promises";import y4 from"node:fs";import ft from"node:path";import b4 from"node:os";import{execFile as k4}from"node:child_process";import{promisify as x4}from"node:util";var v4=x4(k4),JA=process.env.BOSTRAT_STATE_DIR||ft.join(process.env.HOME||b4.tmpdir(),".bostrat"),fd=!1,Yw=null;async function Jw(e,t){let n=await ua.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await ua.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await ua.mkdir(ft.dirname(t),{recursive:!0}),await ua.copyFile(e,t),!0)}var S4=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 pd(e,t,{skip:n=null}={}){let r=0,o=await ua.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(S4.has(s.name)||n?.has(s.name))continue;let a=ft.join(e,s.name);s.isDirectory()?r+=await pd(a,ft.join(t,s.name)):s.isFile()&&(r+=await Jw(a,ft.join(t,s.name))?1:0)}return r}async function XA({stateDir:e=JA,dest:t=process.env.BOSTRAT_SYNC_DIR||`${JA}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await ua.mkdir(t,{recursive:!0});let o=0;o+=await Jw(ft.join(e,"tracks.json"),ft.join(t,"tracks.json"))?1:0,o+=await Jw(ft.join(e,"events.jsonl"),ft.join(t,"events.jsonl"))?1:0,o+=await pd(ft.join(e,"events"),ft.join(t,"events")),o+=await pd(ft.join(e,"memory"),ft.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await pd(ft.join(u.cwd,".bostrat"),ft.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>v4("git",["-C",t,...u]);y4.existsSync(ft.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 Wd(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||fd))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,fd&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),fd=!1,Yw=null}catch(u){fd=!0;let f=(u?.stderr||u?.message||String(u)).trim().split(`
678
- `).slice(-3).join(" | ").slice(0,300);f!==Yw&&(Yw=f,console.warn(`[state-sync] PUSH FAILING (retrying each cycle; off-box copy is STALE): ${f}`))}return{staged:o,committed:i,pushed:l}}catch(o){return{staged:0,committed:!1,pushed:!1,error:o?.message||String(o)}}}dh();Xt();io();lt();Ta();import{execFile as T4}from"node:child_process";import{promisify as E4}from"node:util";import{randomUUID as A4}from"node:crypto";import _4 from"node:fs";import I4 from"node:os";import $4 from"node:path";var Xr=E4(T4),md=e=>new Promise(t=>setTimeout(t,e)),Zr=ff,Xw=process.env.BOSTRAT_USAGE_PROBE_CWD||$4.join(I4.homedir(),".bostrat","usage-probe"),R4=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,O4=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,C4=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,ZA=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,Jr=null,bc=null,kc=null;async function M4(){try{return await Xr(K,V("has-session","-t",Zr)),!0}catch{return!1}}function N4(){Jr&&clearTimeout(Jr),Jr=setTimeout(()=>P4().catch(()=>{}),R4),Jr.unref&&Jr.unref()}async function P4(){Jr&&(clearTimeout(Jr),Jr=null);try{await Xr(K,V("kill-session","-t",Zr))}catch{}}async function D4(){let e=Date.now()+C4;for(;;){let t=await Zw().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await md(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await md(500)}}async function B4(){if(await M4())return;if(!await fr())throw new Error("host tmux server not running \u2014 start globo-tmux.service");_4.mkdirSync(Xw,{recursive:!0}),await or(Xw);let e=A4();await Xr(K,V("new-session","-d","-s",Zr,"-c",Xw,"-x","200","-y","60",...Fa()));let t=`${df} --session-id ${e}`;await Xr(K,V("send-keys","-t",Zr,t,"Enter")),await D4()}async function Zw(){let{stdout:e}=await Xr(K,V("capture-pane","-t",Zr,"-p"));return e}async function j4(){await B4(),await Xr(K,V("send-keys","-t",Zr,"-l","/usage")),await Xr(K,V("send-keys","-t",Zr,"Enter"));let e=Date.now()+O4,t="";for(;await md(400),t=await Zw(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await md(900),t=await Zw(),await Xr(K,V("send-keys","-t",Zr,"Escape")).catch(()=>{}),N4(),t}function L4(e){let t=String(e||"").split(`
679
- `).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 F4(e){let t=String(e||"").split(`
680
- `).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 QA({fresh:e=!1}={}){return!e&&bc&&Date.now()-bc.at<ZA?bc.data:kc||(kc=(async()=>{try{let t=await j4(),n=L4(t),r={...n,contributors:F4(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return bc={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 bc={at:Date.now()-(ZA-3e3),data:n},n}finally{kc=null}})(),kc)}var U4=262144;function H4(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 W4=new Set([300]),q4=new Set([10080]);function K4(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:W4.has(t)?"session":q4.has(t)?"week":"other"}function G4(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 V4(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?H4((o-n)/1e3):null,resetsAt:o}}var xc=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function z4(e,t=Date.now()){let n=String(e||"").split(`
681
- `),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 xc(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=xc(r);[c.primary,c.secondary].forEach((p,h)=>{let w=V4(p,l,t);if(!w)return;let g=K4(p.window_minutes);g===null&&(g=h===0?"session":"week"),g==="session"&&!u.session?u.session=w:g==="week"&&!u.week?u.week=w:(u.other??=[]).push({label:G4(p.window_minutes),...w})}),u.planType=typeof c.plan_type=="string"?c.plan_type:null;let d=c.credits;return d&&(d.has_credits||d.unlimited)&&(u.credits={balance:String(d.balance??""),unlimited:!!d.unlimited}),u.limitReached=typeof c.rate_limit_reached_type=="string"&&c.rate_limit_reached_type||(c.spend_control_reached?"spend_control":null),u}if(c.primary_used_percent!=null||c.secondary_used_percent!=null){let l=u=>Number.isFinite(Number(u))?{pct:Math.round(Number(u)),resets:null,resetsAt:null}:null;return{...xc(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return xc(r)}return xc(r)}async function Qw(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await so(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 Et(n.file,U4),o=z4(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 e_(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 hd({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 Qw(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await Qw(null))}return n.has("cursor")&&r.push(await hd({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function hd(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?Qw(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await QA({fresh:t})}}ar();it();it();function Y4(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}var J4=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),wd=(e,t)=>Object.assign(new Error(e),{status:t});async function t_(e,t){if(!Y4(t))throw wd("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${Ie(t)}${e}`,{headers:J4(t)})}catch(o){throw wd(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw wd(r?.error||`plane replied ${n.status}`,n.status);return r}async function n_(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await t_(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function r_(e,{env:t=process.env}={}){if(!e)throw wd("message id required",400);return(await t_(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}gi();eu();function eg(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 X4(e){let[t,n]=e.split("/"),r=eg(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 o_(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(X4).filter(Boolean)}function Z4(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function s_(e){let t=o_(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:Z4,allowed(r){if(n)return!0;let o=eg((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function a_(e,t){let n=o_(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=eg(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import i_ from"node:crypto";import gd from"node:fs";import Q4 from"node:path";function c_(e=process.env,{stateDir:t=sc,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=Q4.join(t,"api-token");try{let a=gd.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=i_.randomBytes(32).toString("base64url");try{gd.mkdirSync(t,{recursive:!0}),gd.writeFileSync(o,s+`
682
- `,{mode:384}),gd.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function vc(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 l_(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:i_.timingSafeEqual(n,r)}function u_(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 e2=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/],t2=e=>e2.some(t=>t.test(e));function d_({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=u_(o);return l_(c,e)?a():t2(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||vc(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 f_(e,t,{enforce:n=!0}={}){return!n||l_(u_(e),t)?!0:vc(e)}dn();xu();xu();import n2 from"node:http";import r2 from"node:net";function yd(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 bd(e){let t=yd(e.headers.host);return t?{slug:t,view:Um(t)}:null}var o2=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),s2=e=>{let t=o2(e.name);return`<!doctype html><meta charset="utf-8">
672
+ _${o} archived_`:"")}async function gU(e,t){let n=await Uo();if(!n)return Me("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 Me("Usage: `/bostrat start <name> [repo]`");let i=await r.listRepos(),c=a[a.length-1]?.toLowerCase(),l=a.length>1?i.find(f=>f.name.toLowerCase()===c):null,u=(l?a.slice(0,-1):a).join(" ");return l?(Gr(OA(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),Me(`Starting *${xe(u)}* on ${xe(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:hU(u,i)}}case"archive":{if(!a.length)return Me("Usage: `/bostrat archive <track>`");let{match:i,live:c}=Uw(await r.listTracks(),a.join(" "));return i?(Gr(fU(e,n,{track:i,responseUrl:t.response_url})),Me(`Archiving *${xe(i.name)}*\u2026`)):Hw(c,a.join(" "))}case"handoff":{let i=r.knownAgents??dU,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return Me(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:f}=Uw(await r.listTracks(),l);return u?(Gr(pU(e,n,{track:u,agent:c,responseUrl:t.response_url})),Me(`Handing *${xe(u.name)}* to ${xe(c)}\u2026`)):Hw(f,l)}case"stop":{if(!a.length)return Me("Usage: `/bostrat stop <track>`");let{match:i,live:c}=Uw(await r.listTracks(),a.join(" "));return i?(Gr(mU(e,n,{track:i,responseUrl:t.response_url})),Me(`Stopping *${xe(i.name)}*\u2026`)):Hw(c,a.join(" "))}case"list":return Me(await wU(r));default:return Me(uU)}}async function yU(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await Gw(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 sn(),await qo(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${xe(l||"question")}~
673
+ \u2713 *${xe(a)}*`}}]}).catch(()=>{})}}catch(c){await bt(n.response_url,Me(`Couldn't answer: ${c?.message||c}`))}}async function bU(e,t,n,r){let{trackId:o,offerId:s,action:a}=r,i=e.deps;try{let c=await i.resolveTrack(o);if(!c)throw new Error("track not found");let l=await i.readEvents(c),u=l.find(d=>d.type==="pr.offered"&&d.payload?.offerId===s);if(!u)throw new Error("unknown offer");if(l.some(d=>d.type==="pr.offer.answered"&&d.payload?.offerId===s))throw new Error("offer already answered");let f=Array.isArray(r.actions)?_r.filter(d=>r.actions.includes(d)):a==="pr"?["commit","push","pr"]:a==="push"?["commit","push"]:null;if(f?.includes("pr")&&i.divertShip&&await i.divertShip(c,u,{actions:f}))return;f&&await i.sayToLead(c.id,Cs(f,{branch:u.payload.branch,base:u.payload.base}),{kind:f.includes("pr")?"pr-go":"push-go"}),await i.appendEvent({id:c.id,cwd:c.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:u.boxId,payload:{ts:Date.now(),offerId:s,action:f?a:"dismiss",actions:f}})}catch(c){await bt(n.response_url,Me(`Couldn't act on the offer: ${c?.message||c}`))}}async function kU(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 bt(n.response_url,Me(`Couldn't act on the offer: ${i?.message||i}`))}}async function xU(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await Uo();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 bt(t.response_url,{...Me(`Starting *${xe(s)}*\u2026`),replace_original:!0}),Gr(OA(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"?Gr(yU(e,r,t,o)):n.action_id==="bostrat-ship"?Gr(bU(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&Gr(kU(e,r,t,o))}async function vU(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 cU(t.channel,t.thread_ts);if(!n)return;let r=await Uo();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await Vr(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function SU(e){return async t=>{if(t.type==="slash_commands")return gU(e,t.payload);if(t.type==="interactive"){await xU(e,t.payload);return}if(t.type==="events_api"){await vU(e,t.payload?.event);return}}}var TU=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 EU(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${xe(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:gc(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 AU(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await qo(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${xe(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await Vr(e,t,r.question||"The lead needs an answer",EU(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await sn()}async function _U(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 sn(),await qo(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${xe(s||"question")}~
674
+ \u2713 _answered_`}}]})}async function IU(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=(i,c,l,u)=>({type:"button",action_id:"bostrat-ship",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,action:i,...u?{actions:u}:{}}),...l?{style:l}:{}}),s;if(!Array.isArray(r.available))s=r.toPr?[o("push",`Commit & push${r.toPr.number?` to #${r.toPr.number}`:""}`,"primary"),o("dismiss","Not now")]:[o("pr","Open PR","primary"),o("push","Just push"),o("dismiss","Not now")];else{let i=r.available,c=Array.isArray(r.defaults)&&r.defaults.length?r.defaults:i,l={commit:"Commit",rebase:"rebase",push:"push",pr:r.prState==="open"?"open new PR":"open PR"},u=c.map(f=>l[f]).filter(Boolean).join(" & ");s=[o(c.includes("pr")?"pr":"push",u||"Ship","primary",c)],i.includes("pr")&&!c.includes("pr")&&s.push(o("pr","Open new PR",void 0,["pr"])),s.push(o("dismiss","Not now"))}let a=await Vr(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${xe(gc(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await sn()}async function $U(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await sn();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 qo(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function RU(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 Vr(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${xe(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 sn()}async function OU(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await sn();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await qo(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function CU(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??MU)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await EA(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${xe(o.name)}*${a}${o.group?` (group \`${xe(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${xe(a.name)}*`).join(", ");await Vr(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${xe(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function MU(e,t){let n=await Yn(e);if(!n)return null;let r=tn(n,t);if(!r)return null;let o=await wc.readFile(Wt(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function NU(e,t){if(!TU.has(t.type))return;let n=await Gw(t.trackId);if(!n)return;let r=await Uo();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 sn(),await qw(r,n);return;case"turn.agent":{if(!o.text)return;let s=lU(o.text);if(!s)return;await Vr(r,n,s,[{type:"section",text:{type:"mrkdwn",text:xe(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${ad(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return AU(r,n,t);case"prompt.answered":return _U(r,n,t);case"pr.offered":return IU(r,n,t);case"pr.offer.answered":return $U(r,n,t);case"pr.exists.offered":return RU(r,n,t);case"pr.exists.answered":return OU(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 Vr(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 sn(),await qw(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await Vr(r,n,`Live preview ${o.name}: ${id(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${xe(o.name)}*: ${id(o.slug)}
675
+ _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return CU(r,n,t,e.deps)}}function CA(e){let t={deps:e};ct.on("event",s=>{NU(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await Uo()||(r&&clearInterval(r),r=null,n=AA({getToken:async()=>(await Uo())?.appToken,onEnvelope:SU(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}Xt();he();dn();dm();Dn();import PU from"node:fs/promises";function DU(e){let t=new Map;for(let n of String(e||"").split(`
676
+ `)){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 BU(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 jU=new Set(["Write","Edit","NotebookEdit"]),LU=220,FU=160;function UU(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(jU.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,LU)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=no(o.command.trim().replace(/\s+/g," ")).slice(0,FU));return r}function HU(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?Jt(t.cwd,t.sessionId):t?.cwd?bf(t.cwd):null}async function MA(e,t){let n=await t(e?.session_id,e?.cwd);if(!n?.track)return[];let{track:r,box:o}=n,s={boxId:o?.name||null,provider:"claude",source:"hook"},a=[],i=async c=>{a.push(await $(r,{...s,...c}))};switch(e?.hook_event_name){case"SessionStart":await i({type:"session.ready",actor:"system",payload:{sessionId:e.session_id}});break;case"UserPromptSubmit":{let c=String(e.prompt??e.user_prompt??""),l=lu(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:UU(e,o)});break;case"Stop":await WU(r,o,e,i);break;default:break}return a}async function WU(e,t,n,r){let o=[],s=HU(n,t);if(s)try{o=DU(await PU.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=BU(await U(e)),c=o.filter(u=>!i.has(u.messageId));if(c.length){let u=new Map;for(let f of c){let d=`${f.model||"unknown"}\0${f.speed||""}`,p=u.get(d)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},cacheWriteTtl:null,messageIds:[]};for(let h of Object.keys(p.tokens))p.tokens[h]+=f.tokens[h];f.cacheWriteTtl&&(p.cacheWriteTtl??={m5:0,h1:0},p.cacheWriteTtl.m5+=f.cacheWriteTtl.m5,p.cacheWriteTtl.h1+=f.cacheWriteTtl.h1),p.messageIds.push(f.messageId),p.speed=f.speed||null,u.set(d,p)}for(let[f,d]of u){let p=f.split("\0")[0];await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:p,usd:mn(p,d.tokens,void 0,d.speed?{speed:d.speed}:void 0),tokens:d.tokens,...d.speed?{speed:d.speed}:{},cacheWriteTtl:d.cacheWriteTtl,messageId:d.messageIds[d.messageIds.length-1],messageIds:d.messageIds,apiCalls:d.messageIds.length}})}}let l=a.tokens.input+a.tokens.cacheWrite+a.tokens.cacheRead;await r({type:"context.usage",actor:"system",source:"transcript",payload:{model:a.model,occupancy:l,tokens:a.tokens}})}Yo();df();he();vl();yu();import{execFile as qU}from"node:child_process";import{promisify as KU}from"node:util";var GU=KU(qU),Vw=(e,t)=>GU("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4});function NA(e,t=Date.now()){return Yd(e,t)??0}function VU(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 PA(e,t,{now:n=Date.now()}={}){let r=NA(t,n),o=await U(e);return gu({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:VU(o,t.name,r)})}function zU(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=null;for(let c=n.length-1;c>=0;c--){let l=n[c];if(l.type==="turn.user"&&l.boxId===t.name&&l.actor==="user"){i=Pn(l.payload?.promptHead||l.payload?.text||"")?.category??null;break}}return{wallReason:a,fixerCategory:i}}async function YU(e,t){try{let{stdout:n}=await Vw(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 JU(e){try{let{stdout:t}=await Vw(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function DA(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 U(e);if(a.some(p=>p.type==="code.committed"&&p.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s;try{let{stdout:p}=await Vw(r,["show","-s","--format=%ct",n]),h=Number(p.trim())*1e3;Number.isFinite(h)&&h>0&&(i=h)}catch{return{recorded:!1,reason:"unknown-sha"}}let c=NA(t,i),l=await YU(r,n),u=await $(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:await JU(r),...l,ts:i}}),f=null,d=!1;try{let p=await gS(r,n,{fixKey:Hs({trackId:e.id,boxId:t.name,epoch:c}),window:Br,context:{...zU(e,t,a,c),provider:t.agent??null}});if(p){f=await $(e,{type:"code.rework",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:u.id,payload:p});let h=yS(p);if(h>=wS){let w=p.origins.filter(g=>g.class==="rework").slice(0,3);await $(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:f.id,payload:{sha:n,subject:p.subject,linesReworked:h,origins:w.map(g=>({key:g.key,provider:g.provider,model:g.model,lines:g.lines,ageDays:g.ageDays})),heuristic:p.heuristic,ts:i}}),d=!0}}}catch(p){o.warn?.(`[rework] ${e.id}: analysis of ${String(n).slice(0,7)} failed: ${p?.message||p}`)}return{recorded:!0,event:u,rework:f,offered:d}}async function BA(e,t,n){if(!Ri.includes(n))throw new Error(`bad cause "${n}" (${Ri.join("|")})`);let r=await U(e),o=r.find(s=>s.type==="rework.cause.offered"&&s.payload?.sha===t);if(!o)throw new Error("unknown rework offer");if(r.some(s=>s.type==="rework.cause.answered"&&s.payload?.sha===t))throw new Error("already answered");return $(e,{type:"rework.cause.answered",actor:"user",source:"orchestrator",boxId:o.boxId??null,causationId:o.id,payload:{sha:t,cause:n,level:"B",ts:Date.now()}})}he();he();Sr();he();Sr();Dn();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 jA=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),LA=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},dd=e=>Math.round(e*1e4)/1e4;async function zw(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=jA(),f=0,d=[];for(let p of e||[]){let h=await U(p),w=vr(h,{boxLabels:yc(p)});if(w.turns===0){p.archivedAt?f++:d.push(p.name||p.id);continue}o+=w.totalUsd,s+=w.turns,a+=w.repricedTurns||0,i+=w.asRecordedUsd||0,c+=w.unpricedTurns||0;for(let g of w.unpricedModels||[])l.add(g);LA(u,w.totalTokens);for(let[g,b]of Object.entries(w.byModel))n[g]||={usd:0,events:0,tokens:jA()},n[g].usd=dd(n[g].usd+b.usd),n[g].events+=b.events,LA(n[g].tokens,b.tokens);for(let[g,b]of Object.entries(w.byProvider))r[g]||={usd:0,events:0},r[g].usd=dd(r[g].usd+b.usd),r[g].events+=b.events;t.push({id:p.id,name:p.name,usd:w.totalUsd,rollup:w})}return t.sort((p,h)=>h.usd-p.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:ks(),fleet:{totalUsd:dd(o),asRecordedUsd:dd(i),turns:s,repricedTurns:a,unpricedTurns:c,unpricedModels:[...l],totalTokens:u,byModel:n,byProvider:r,tracksWithCost:t.length,tracksSilent:f+d.length,tracksSilentArchived:f,tracksSilentLive:d},tracks:t}}var zr=e=>`$${e.toFixed(4)}`,la=(e,t)=>String(e).padEnd(t);function FA(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 ${zr(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 ${zr(t.asRecordedUsd)} \xB7 current-rates total ${zr(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${zr(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(` ${la(a,26)} ${la(zr(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(` ${la(a.name||a.id,30)} ${zr(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${la(c.label,40)} ${la(zr(c.usd),10)} ${c.models.join(",")||"?"}`),c.epochs)for(let[l,u]of Object.entries(c.epochs).sort((f,d)=>Number(f[0])-Number(d[0])))r.push(` \u21B3 tenure ${l} (${u.provider||"?"})${" ".repeat(Math.max(1,24-String(u.provider||"?").length))}${la(zr(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
677
+ `)}he();qp();import t4 from"node:fs/promises";import n4 from"node:path";vl();_l();Sr();var fd=e=>e.payload?.ts??e.ts,XU=12e4,rr=e=>Math.round(e*1e4)/1e4,ZU=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{},byTrack:new Map});function QU(e,{since:t}){let{track:n,events:r,brief:o}=e,s=S=>fd(S)>=t,a=Pn([oi(n?.name),oi(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let S of r)if(S.type==="subtask.delegated"&&S.boxId&&S.payload?.task){let R=Pn(S.payload.task);R&&i.set(S.boxId,R)}let c=new Map,l=S=>{let R=S||"unattributed";return c.has(R)||c.set(R,{segments:[u(null)],lastTs:null,provider:null}),c.get(R)},u=(S,{shape:R="initial",continuation:M=!1}={})=>({textCat:S,shape:R,continuation:M,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),f=[...r].sort((S,R)=>fd(S)-fd(R)),d=0,p=0,h=0,w={turns:0};for(let S of f){let R=l(S.boxId),M=R.segments[R.segments.length-1],T=fd(S);switch(R.lastTs!=null&&T>R.lastTs&&s(S)&&(M.activeMs+=Math.min(T-R.lastTs,XU)),R.lastTs=T,S.provider&&(R.provider=S.provider),S.type){case"turn.user":{let A=S.payload?.text;if(S.source==="hook"||!String(A||"").trim()||S.payload?.note||bs(A))break;let C=Pn(A),I=!!S.payload?.kind,W=I||qb(A),j=u(C,{shape:I?"injected":W?"follow-up":"novel-ask",continuation:!C&&W});R.segments.push(j),s(S)&&(j.turns+=1);break}case"peer.message":{let A=S.payload?.text;if(!String(A||"").trim())break;let C=Pn(A),I=u(C,{shape:"peer",continuation:!C});R.segments.push(I),s(S)&&(I.turns+=1);break}case"tool.called":{if(S.source==="transcript")break;let A=S.payload?.tool;A&&(M.tools[A]=(M.tools[A]||0)+1),s(S)&&(M.toolCalls+=1);break}case"cost.recorded":{if(!s(S))break;let{usd:A,tokens:C,model:I,unpriced:W}=Ft(S);W&&(w.turns+=1),M.usd+=A,C&&(M.tokens.input+=C.input,M.tokens.output+=C.output,M.tokens.cacheRead+=C.cacheRead,M.tokens.cacheWrite+=C.cacheWrite),M.models[I]=(M.models[I]||0)+A,S.provider&&(M.provider=S.provider);break}case"handoff.done":s(S)&&(d+=1);break;case"subtask.merged":s(S)&&(p+=1);break;case"error":s(S)&&S.payload?.kind==="subtask-failed"&&(h+=1);break;default:break}}let g=new Map,b={usd:0,turns:0,byShape:{}},E=!1;for(let[S,R]of c){let M=null;for(let T of R.segments){let A=null,C=null;if(T.textCat)A=T.textCat.category,C="text";else if(i.get(S))A=i.get(S).category,C="boxTask";else if(T.continuation&&M)A=M,C="inherited";else{let q=Wb(T.tools);q?(A=q.category,C="toolMix"):a&&(A=a.category,C="hint")}if(A&&(M=A),!(T.usd>0||T.activeMs>0||T.turns>0||T.toolCalls>0))continue;let W=A??"uncategorized";g.has(W)||g.set(W,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{}});let j=g.get(W);j.usd+=T.usd,j.activeMs+=T.activeMs,j.turns+=T.turns,j.toolCalls+=T.toolCalls,C&&(j.provenance[C]=(j.provenance[C]||0)+T.usd);for(let[q,O]of Object.entries(T.models))j.models[q]=(j.models[q]||0)+O;let ee=T.provider||R.provider;ee&&(j.providers[ee]=(j.providers[ee]||0)+T.usd),ee==="cursor"&&T.usd===0&&(E=!0),A||(b.usd+=T.usd,b.turns+=T.turns,b.byShape[T.shape]=(b.byShape[T.shape]||0)+T.usd)}}return{perCategory:g,uncategorized:b,handoffs:d,merged:p,failed:h,sawCursorActivity:E,unpricedTurns:w.turns}}function UA(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:{}};for(let b of e||[]){let{track:E,events:S}=b;if(!S?.length){a+=1;continue}let{perCategory:R,uncategorized:M,handoffs:T,merged:A,failed:C,sawCursorActivity:I,unpricedTurns:W}=QU(b,{since:r});I&&(i=!0),c+=W,l.usd+=M.usd,l.turns+=M.turns;for(let[ee,q]of Object.entries(M.byShape))l.byShape[ee]=(l.byShape[ee]||0)+q;let j={trackId:E?.id,name:E?.name||E?.id,archived:!!E?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:T,subtasksMerged:A,subtasksFailed:C};for(let[ee,q]of R){j.usd+=q.usd,j.activeMs+=q.activeMs,j.turns+=q.turns,j.categories[ee]={usd:rr(q.usd),activeMs:q.activeMs};for(let[te,H]of Object.entries(q.models))j.models[te]=rr((j.models[te]||0)+H);for(let[te,H]of Object.entries(q.providers))j.providers[te]=rr((j.providers[te]||0)+H);o.has(ee)||o.set(ee,ZU());let O=o.get(ee);O.usd+=q.usd,O.activeMs+=q.activeMs,O.turns+=q.turns,O.toolCalls+=q.toolCalls;for(let[te,H]of Object.entries(q.models))O.models[te]=(O.models[te]||0)+H;for(let[te,H]of Object.entries(q.providers))O.providers[te]=(O.providers[te]||0)+H;for(let[te,H]of Object.entries(q.provenance))O.provenance[te]=(O.provenance[te]||0)+H;let z=O.byTrack.get(E?.id)||{usd:0,activeMs:0};z.usd+=q.usd,z.activeMs+=q.activeMs,O.byTrack.set(E?.id,z)}(j.usd>0||j.activeMs>0||j.turns>0)&&(j.usd=rr(j.usd),j.dominantCategory=e4(j.categories),s.push(j))}let u=[...o.values()].reduce((b,E)=>b+E.usd,0),f=[...o.values()].reduce((b,E)=>b+E.activeMs,0),d=u>0?"usd":"time",p=d==="usd"?u:f,h=new Map((e||[]).map(b=>[b.track?.id,b.track?.name||b.track?.id])),w=[...o.entries()].map(([b,E])=>({category:b,sharePct:p>0?Math.round((d==="usd"?E.usd:E.activeMs)/p*100):0,shareBasis:d,usd:rr(E.usd),activeMs:E.activeMs,turns:E.turns,toolCalls:E.toolCalls,models:bc(E.models),providers:bc(E.providers),provenance:bc(E.provenance),topWorkstreams:[...E.byTrack.entries()].sort((S,R)=>R[1].usd-S[1].usd||R[1].activeMs-S[1].activeMs).slice(0,2).map(([S,R])=>({trackId:S,name:h.get(S),usd:rr(R.usd),activeMs:R.activeMs}))})).sort((b,E)=>E.usd-b.usd||E.activeMs-b.activeMs);s.sort((b,E)=>E.usd-b.usd||E.activeMs-b.activeMs);let g={};for(let b of o.values())for(let[E,S]of Object.entries(b.provenance))g[E]=(g[E]||0)+S;return{since:r,capturedAt:n,totalUsd:rr(u),activeMs:f,turns:[...o.values()].reduce((b,E)=>b+E.turns,0),bullets:w,workstreams:s,provenance:bc(g),gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c,uncategorized:{usd:rr(l.usd),turns:l.turns,sharePct:u>0?Math.round(l.usd/u*100):0,byShape:bc(l.byShape)}}}}var e4=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},bc=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,rr(n)]));var ua={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function r4(e){let t=String(e||"7d");return t in ua?{key:t,ms:ua[t]}:{key:"7d",ms:ua["7d"]}}function o4(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=Kl(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 s4(e){if(!e?.cwd)return null;try{let n=(await t4.readFile(n4.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 HA(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}:r4(t),f=[];for(let d of e||[]){let p=await U(d),h=o4(d,p);i&&c<o&&(h=h.filter(w=>(w.ts??0)<=c)),f.push({track:d,events:h,brief:await s4(d)})}return{window:l,...UA(f,{windowMs:u,now:c})}}Dn();var Yr=36e5,GA=24*Yr,a4=400,i4=12,Ko=e=>Math.round(e*1e4)/1e4;function Yw({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 ua?String(e||"7d"):"7d",i=ua[a];return{key:a,since:i==null?null:r-i,until:r}}var c4=(e,t)=>e!=null&&t-e<=48*Yr?Yr:GA;function WA(e,t){if(t===Yr)return Math.floor(e/Yr)*Yr;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function l4(e,t){if(t===Yr)return e+Yr;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var qA=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),KA=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},u4=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Ko(n)]));async function VA(e,t={}){let n=t.now??Date.now(),r=Yw({...t,now:n}),o=r.since==null?GA:c4(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=qA(),f=0,d=0,p=0,h=0,w=0,g=0,b=new Set,E=new Map,S=[],R=[],M=[],T=null;for(let I of e||[]){let j=(await U(I)).filter(O=>O.type==="cost.recorded");if(!j.length){I.archivedAt||M.push(I.name||I.id);continue}let ee=[];for(let O of j){let z=O.ts??0;s(z)?ee.push(O):i(z)&&(g+=Ft(O).usd)}if(!ee.length)continue;let q=vr(ee,{boxLabels:yc(I)});f+=q.totalUsd,d+=q.turns,p+=q.repricedTurns||0,h+=q.asRecordedUsd||0,w+=q.unpricedTurns||0;for(let O of q.unpricedModels||[])b.add(O);KA(u,q.totalTokens);for(let[O,z]of Object.entries(q.byModel))c[O]||={usd:0,events:0,tokens:qA()},c[O].usd=Ko(c[O].usd+z.usd),c[O].events+=z.events,KA(c[O].tokens,z.tokens);for(let[O,z]of Object.entries(q.byProvider))l[O]||={usd:0,events:0},l[O].usd=Ko(l[O].usd+z.usd),l[O].events+=z.events;for(let O of ee){let{usd:z}=Ft(O);if(!z)continue;let te=WA(O.ts??0,o),H=E.get(te)??{t:te,total:0,byProvider:{}};H.total+=z;let ke=O.provider||"unknown";H.byProvider[ke]=(H.byProvider[ke]||0)+z,E.set(te,H),(T==null||te<T)&&(T=te)}S.push({id:I.id,name:I.name||I.id,archived:!!I.archivedAt,usd:q.totalUsd,turns:q.turns,providers:Object.keys(q.byProvider)});for(let[O,z]of Object.entries(q.byBox))R.push({trackId:I.id,trackName:I.name||I.id,boxId:O,...z})}let A=r.since!=null?WA(r.since,o):T,C=[];for(let I=A,W=0;I!=null&&I<r.until&&W<a4;I=l4(I,o),W++){let j=E.get(I);C.push(j?{t:I,total:Ko(j.total),byProvider:u4(j.byProvider)}:{t:I,total:0,byProvider:{}})}return S.sort((I,W)=>W.usd-I.usd),R.sort((I,W)=>W.usd-I.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:ks(),window:r.key,since:r.since,until:r.until,bucketMs:o,series:C,fleet:{totalUsd:Ko(f),asRecordedUsd:Ko(h),turns:d,repricedTurns:p,unpricedTurns:w,unpricedModels:[...b],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:S.length,tracksSilentLive:M},prior:a!=null?{totalUsd:Ko(g),since:r.since-a,until:r.since}:null,tracks:S.slice(0,50),boxes:R.slice(0,i4)}}yu();var d4=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),f4=20,p4=40;async function zA(e,t={}){let n=t.now??Date.now(),r=Yw({...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 U(l),f=0,d=yc(l);for(let p of u){if(!d4.has(p.type))continue;let h=p.type==="code.rework"?p.payload?.ts??p.ts:p.ts;p.type!=="rework.cause.answered"&&!o(h??0)||(p.type==="code.committed"&&f++,s.push(p.trackId?p:{...p,trackId:l.id}))}f&&i++;for(let p of l.boxes||[])a[`${l.id}/${p.name}`]={trackName:l.name||l.id,label:d[p.name]||p.name}}let c=bS(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:Br,decayEndDays:Rm,basis:c.basis,commits:c.commits,tracksWithCommits:i,fixesAnalyzed:c.fixes.length,fixUsdTotal:c.fixUsdTotal,buckets:c.buckets,verdicts:c.verdicts,pendingTaps:c.pendingTaps.length,byProvider:c.byProvider,byModel:c.byModel,epochs:c.epochs.slice(0,f4),fixes:c.fixes.slice(0,p4)}}import m4 from"node:fs";import YA from"node:fs/promises";import kc from"node:os";import h4 from"node:path";Vm();lt();var w4=1024*1024,pd=e=>Math.round(e/w4);async function g4(e){try{let t=await YA.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:pd(r),diskTotalMb:pd(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function y4(){try{return(await zt()).filter(t=>t.isBostrat).length}catch{return null}}async function b4(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await YA.readdir(h4.join(ac,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function JA({stateDir:e=ac,now:t=Date.now}={}){let n=kc.totalmem(),[r,o,s,a]=await Promise.all([Eu().catch(()=>null),g4(m4.existsSync(e)?e:kc.tmpdir()),y4(),b4()]),i=kc.cpus()?.length||null,c=kc.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?pd(n-r):null,memTotalMb:pd(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(kc.uptime())}}he();qf();Ca();Dn();he();Dn();var k4=864e5;function x4(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=mn(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 XA(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*k4,s={},a=0,i=0,c=[];for(let u of e||[]){let f=await U(u);for(let d of f){if(!d.ts||d.ts<o)continue;let p=x4(d,{tolerance:n});if(!p)continue;a++;let h=p.speed?`${p.model} (${p.speed})`:p.model,w=s[h]||={rows:0,divergent:0,asRecordedUsd:0,expectedUsd:0};w.rows++,w.asRecordedUsd+=p.asRecorded,w.expectedUsd+=p.expected,p.divergent&&(i++,w.divergent++,c.length<10&&c.push({track:u.name||u.id,...p}))}}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}}Am();Hl();it();Bn();import da from"node:fs/promises";import v4 from"node:fs";import ft from"node:path";import S4 from"node:os";import{execFile as T4}from"node:child_process";import{promisify as E4}from"node:util";var A4=E4(T4),ZA=process.env.BOSTRAT_STATE_DIR||ft.join(process.env.HOME||S4.tmpdir(),".bostrat"),md=!1,Jw=null;async function Xw(e,t){let n=await da.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await da.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await da.mkdir(ft.dirname(t),{recursive:!0}),await da.copyFile(e,t),!0)}var _4=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 hd(e,t,{skip:n=null}={}){let r=0,o=await da.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(_4.has(s.name)||n?.has(s.name))continue;let a=ft.join(e,s.name);s.isDirectory()?r+=await hd(a,ft.join(t,s.name)):s.isFile()&&(r+=await Xw(a,ft.join(t,s.name))?1:0)}return r}async function QA({stateDir:e=ZA,dest:t=process.env.BOSTRAT_SYNC_DIR||`${ZA}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await da.mkdir(t,{recursive:!0});let o=0;o+=await Xw(ft.join(e,"tracks.json"),ft.join(t,"tracks.json"))?1:0,o+=await Xw(ft.join(e,"events.jsonl"),ft.join(t,"events.jsonl"))?1:0,o+=await hd(ft.join(e,"events"),ft.join(t,"events")),o+=await hd(ft.join(e,"memory"),ft.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await hd(ft.join(u.cwd,".bostrat"),ft.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>A4("git",["-C",t,...u]);v4.existsSync(ft.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 Kd(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||md))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,md&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),md=!1,Jw=null}catch(u){md=!0;let f=(u?.stderr||u?.message||String(u)).trim().split(`
678
+ `).slice(-3).join(" | ").slice(0,300);f!==Jw&&(Jw=f,console.warn(`[state-sync] PUSH FAILING (retrying each cycle; off-box copy is STALE): ${f}`))}return{staged:o,committed:i,pushed:l}}catch(o){return{staged:0,committed:!1,pushed:!1,error:o?.message||String(o)}}}fh();Xt();io();lt();Ea();import{execFile as I4}from"node:child_process";import{promisify as $4}from"node:util";import{randomUUID as R4}from"node:crypto";import O4 from"node:fs";import C4 from"node:os";import M4 from"node:path";var Xr=$4(I4),wd=e=>new Promise(t=>setTimeout(t,e)),Zr=mf,Zw=process.env.BOSTRAT_USAGE_PROBE_CWD||M4.join(C4.homedir(),".bostrat","usage-probe"),N4=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,P4=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,D4=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,e_=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,Jr=null,xc=null,vc=null;async function B4(){try{return await Xr(G,Y("has-session","-t",Zr)),!0}catch{return!1}}function j4(){Jr&&clearTimeout(Jr),Jr=setTimeout(()=>L4().catch(()=>{}),N4),Jr.unref&&Jr.unref()}async function L4(){Jr&&(clearTimeout(Jr),Jr=null);try{await Xr(G,Y("kill-session","-t",Zr))}catch{}}async function F4(){let e=Date.now()+D4;for(;;){let t=await Qw().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await wd(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await wd(500)}}async function U4(){if(await B4())return;if(!await pr())throw new Error("host tmux server not running \u2014 start globo-tmux.service");O4.mkdirSync(Zw,{recursive:!0}),await sr(Zw);let e=R4();await Xr(G,Y("new-session","-d","-s",Zr,"-c",Zw,"-x","200","-y","60",...Ua()));let t=`${pf} --session-id ${e}`;await Xr(G,Y("send-keys","-t",Zr,t,"Enter")),await F4()}async function Qw(){let{stdout:e}=await Xr(G,Y("capture-pane","-t",Zr,"-p"));return e}async function H4(){await U4(),await Xr(G,Y("send-keys","-t",Zr,"-l","/usage")),await Xr(G,Y("send-keys","-t",Zr,"Enter"));let e=Date.now()+P4,t="";for(;await wd(400),t=await Qw(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await wd(900),t=await Qw(),await Xr(G,Y("send-keys","-t",Zr,"Escape")).catch(()=>{}),j4(),t}function W4(e){let t=String(e||"").split(`
679
+ `).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 q4(e){let t=String(e||"").split(`
680
+ `).map(s=>s.replace(/\s+$/,"")),n=t.findIndex(s=>/What's contributing/i.test(s));if(n<0)return null;let r=/(Usage credits|Esc to cancel|d to day · w to week|^\s*d to day)/i,o=[];for(let s=n+1;s<t.length&&!r.test(t[s]);s++)t[s].trim()&&o.push(t[s].trim());return o.length?o:null}async function t_({fresh:e=!1}={}){return!e&&xc&&Date.now()-xc.at<e_?xc.data:vc||(vc=(async()=>{try{let t=await H4(),n=W4(t),r={...n,contributors:q4(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return xc={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 xc={at:Date.now()-(e_-3e3),data:n},n}finally{vc=null}})(),vc)}var K4=262144;function G4(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 V4=new Set([300]),z4=new Set([10080]);function Y4(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:V4.has(t)?"session":z4.has(t)?"week":"other"}function J4(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 X4(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?G4((o-n)/1e3):null,resetsAt:o}}var Sc=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function Z4(e,t=Date.now()){let n=String(e||"").split(`
681
+ `),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 Sc(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=Sc(r);[c.primary,c.secondary].forEach((p,h)=>{let w=X4(p,l,t);if(!w)return;let g=Y4(p.window_minutes);g===null&&(g=h===0?"session":"week"),g==="session"&&!u.session?u.session=w:g==="week"&&!u.week?u.week=w:(u.other??=[]).push({label:J4(p.window_minutes),...w})}),u.planType=typeof c.plan_type=="string"?c.plan_type:null;let d=c.credits;return d&&(d.has_credits||d.unlimited)&&(u.credits={balance:String(d.balance??""),unlimited:!!d.unlimited}),u.limitReached=typeof c.rate_limit_reached_type=="string"&&c.rate_limit_reached_type||(c.spend_control_reached?"spend_control":null),u}if(c.primary_used_percent!=null||c.secondary_used_percent!=null){let l=u=>Number.isFinite(Number(u))?{pct:Math.round(Number(u)),resets:null,resetsAt:null}:null;return{...Sc(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return Sc(r)}return Sc(r)}async function eg(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await so(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 Et(n.file,K4),o=Z4(r);return{...t,session:o.session,week:o.week,other:o.other,planType:o.planType,credits:o.credits,limitReached:o.limitReached,subscription:!!(o.session||o.week||o.other?.length),capturedAt:n.mtimeMs||Date.now()}}catch(n){return{...t,session:null,week:null,subscription:!1,error:n?.message||String(n),capturedAt:Date.now()}}}async function n_(e,{fresh:t=!1}={}){let n=new Set;for(let o of e||[])for(let s of o.boxes||[])s.agent&&n.add(s.agent);let r=[];if((n.has("claude")||n.size===0)&&r.push(await gd({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 eg(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await eg(null))}return n.has("cursor")&&r.push(await gd({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function gd(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?eg(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await t_({fresh:t})}}ir();it();it();function Q4(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}var e2=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),yd=(e,t)=>Object.assign(new Error(e),{status:t});async function r_(e,t){if(!Q4(t))throw yd("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${Ie(t)}${e}`,{headers:e2(t)})}catch(o){throw yd(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw yd(r?.error||`plane replied ${n.status}`,n.status);return r}async function o_(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await r_(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function s_(e,{env:t=process.env}={}){if(!e)throw yd("message id required",400);return(await r_(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}yi();nu();function tg(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 t2(e){let[t,n]=e.split("/"),r=tg(t);if(r==null)return null;let o=n==null?32:Number(n);if(!Number.isInteger(o)||o<0||o>32)return null;let s=o===0?0:4294967295<<32-o>>>0;return a=>(a&s)===(r&s)}function a_(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(t2).filter(Boolean)}function n2(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function i_(e){let t=a_(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:n2,allowed(r){if(n)return!0;let o=tg((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function c_(e,t){let n=a_(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=tg(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import l_ from"node:crypto";import bd from"node:fs";import r2 from"node:path";function u_(e=process.env,{stateDir:t=ac,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=r2.join(t,"api-token");try{let a=bd.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=l_.randomBytes(32).toString("base64url");try{bd.mkdirSync(t,{recursive:!0}),bd.writeFileSync(o,s+`
682
+ `,{mode:384}),bd.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function Tc(e){let t=e?.socket?.remoteAddress||"";if(!t)return!1;let n=t.replace(/^::ffff:/,"");return n==="::1"||n==="127.0.0.1"||/^127\./.test(n)}function d_(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:l_.timingSafeEqual(n,r)}function f_(e,t=null){let n=e?.headers?.["x-bostrat-token"];if(typeof n=="string"&&n.trim())return n.trim();let r=e?.headers?.authorization||"",o=/^Bearer\s+(.+)$/i.exec(r)?.[1];if(o)return o.trim();try{return(t??new URL(e.url,"http://node")).searchParams.get("token")||""}catch{return""}}var o2=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/],s2=e=>o2.some(t=>t.test(e));function p_({token:e,enforce:t=!0,log:n=console}={}){return function(o,s,a){let i=o.path||o.url||"";if(!i.startsWith("/api"))return a();let c=f_(o);return d_(c,e)?a():s2(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||Tc(o)?a():(n.log?.(`[perimeter] refused ${o.method} ${i} from ${o.socket?.remoteAddress||"?"} \u2014 no node API token`),s.status(401).json({error:"unauthorized"}))}}function m_(e,t,{enforce:n=!0}={}){return!n||d_(f_(e),t)?!0:Tc(e)}dn();Su();Su();import a2 from"node:http";import i2 from"node:net";function kd(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 xd(e){let t=kd(e.headers.host);return t?{slug:t,view:Hm(t)}:null}var c2=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),l2=e=>{let t=c2(e.name);return`<!doctype html><meta charset="utf-8">
683
683
  <meta http-equiv="refresh" content="3">
684
684
  <title>${t} \u2014 starting</title>
685
685
  <body style="font-family:system-ui;background:#0b0e14;color:#dce3f0;display:grid;place-items:center;height:100vh;margin:0">
686
686
  <div style="text-align:center"><p style="font-size:2rem;margin:0">\u23F3</p>
687
- <p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function p_(e,t,n){let r=bd(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(s2(o));if(o.state!=="live"&&o.state!=="unhealthy")return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" is ${o.state} \u2014 restart it from the Views tab`);let a={...e.headers,host:`127.0.0.1:${o.port}`,"x-forwarded-host":e.headers.host,"x-forwarded-proto":e.headers["x-forwarded-proto"]||"http"};delete a.authorization,delete a.cookie;let i=n2.request({host:"127.0.0.1",port:o.port,method:e.method,path:e.url,headers:a},c=>{t.writeHead(c.statusCode||502,c.headers),c.pipe(t)});i.on("error",()=>{t.headersSent?t.destroy():(t.statusCode=502,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" did not answer on :${o.port}`))}),e.pipe(i),e.on("aborted",()=>i.destroy())}function m_(e,t,n){let r=bd(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
687
+ <p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function h_(e,t,n){let r=xd(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(l2(o));if(o.state!=="live"&&o.state!=="unhealthy")return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" is ${o.state} \u2014 restart it from the Views tab`);let a={...e.headers,host:`127.0.0.1:${o.port}`,"x-forwarded-host":e.headers.host,"x-forwarded-proto":e.headers["x-forwarded-proto"]||"http"};delete a.authorization,delete a.cookie;let i=a2.request({host:"127.0.0.1",port:o.port,method:e.method,path:e.url,headers:a},c=>{t.writeHead(c.statusCode||502,c.headers),c.pipe(t)});i.on("error",()=>{t.headersSent?t.destroy():(t.statusCode=502,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" did not answer on :${o.port}`))}),e.pipe(i),e.on("aborted",()=>i.destroy())}function w_(e,t,n){let r=xd(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
688
688
  \r
689
689
  bostrat: no live view "${s}"\r
690
- `),t.destroy(),!0;let a=r2.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${e.url} HTTP/1.1`];for(let[l,u]of Object.entries(e.headers))l!=="host"&&(l==="authorization"||l==="cookie"||c.push(`${l}: ${Array.isArray(u)?u.join(", "):u}`));c.push(`host: 127.0.0.1:${o.port}`),a.write(c.join(`\r
690
+ `),t.destroy(),!0;let a=i2.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${e.url} HTTP/1.1`];for(let[l,u]of Object.entries(e.headers))l!=="host"&&(l==="authorization"||l==="cookie"||c.push(`${l}: ${Array.isArray(u)?u.join(", "):u}`));c.push(`host: 127.0.0.1:${o.port}`),a.write(c.join(`\r
691
691
  `)+`\r
692
692
  \r
693
- `),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 h_(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}.${a2(n.host)}/`}function a2(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 yd(t)&&Um(n[0])?n.slice(1).join("."):t}Ks();eh();Iu();pm();me();import w_ from"node:os";import{randomUUID as ng}from"node:crypto";var i2=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||w_.hostname(),nodeName:e.BOSTRAT_NODE_NAME||w_.hostname()});var g_=32768,y_=120,b_=1e3,k_=new Set(["claude","codex","cursor"]),c2=new Set(["off","transition","nag"]),l2=[[0,59],[0,23],[1,31],[1,12],[0,6]];function u2(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=l2[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 an=e=>String(e??"").trim(),Go={name(e){let t=an(e);if(!t)throw new Error("a loop needs a name");if(t.length>y_)throw new Error(`name is too long (${t.length}); cap is ${y_}`);return t},schedule(e){let t=an(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!u2(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=an(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>g_)throw new Error(`prompt is too long (${t.length} chars); cap is ${g_}`);return t},expectation(e){let t=an(e)||null;if(t&&t.length>b_)throw new Error(`expectation is too long (${t.length}); cap is ${b_}`);return t},notify(e){let t=an(e)||"off";if(!c2.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=an(typeof t=="string"?t:t?.provider)||"claude";if(!k_.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...k_].join(", ")}`);let r=typeof t=="object"&&t&&an(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 d2(e,t){let n=e&&typeof e=="object"?e:{},r=Go.name(n.name),o=Go.schedule(n.schedule),s=Go.prompt(n.prompt),a=Go.expectation(n.expectation),i=Go.notify(n.notify),c=Go.assignment(n.assignment),l=an(t?.workspace?.repo)||an(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:f}=i2();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:f||null}}async function v_(e,t){let n=d2(t,e),r=ng();return await $({id:e.id,cwd:e.cwd},{type:"loop.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:r,...n}}),{proposalId:r,...n}}async function S_(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await F({id:e.id,cwd:e.cwd}),a=s.find(c=>c.type==="loop.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="loop.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await $({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("loopId required \u2014 the loop is created on the plane before the card is answered");let i=a.payload;return await $({id:e.id,cwd:e.cwd},{type:"loop.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:String(r),name:i.name,schedule:i.schedule,provider:i.assignment?.provider??"claude",repo:i.repo??null,nodeId:i.nodeId??null,nextFireAt:Number.isFinite(Number(o))?Number(o):null}}),await $({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",loopId:String(r)}}),{proposalId:t,action:"created",loopId:String(r)}}var tg=["name","schedule","prompt","expectation","notify","assignment","enabled"],f2=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function T_(e){let t=Array.isArray(e.runs)?e.runs:[],n=t[t.length-1]??null;return{definitionUpdatedAt:Number(e.definitionUpdatedAt??e.updatedAt)||null,name:e.name??"",schedule:e.schedule??"",prompt:e.prompt??"",expectation:e.expectation??null,notify:e.notify??"off",assignment:e.assignment&&typeof e.assignment=="object"?e.assignment:{provider:String(e.assignment||"claude")},enabled:e.enabled!==!1,repo:e.repo??null,nodeId:e.nodeId??null,nodeName:e.nodeName??null,trackId:e.trackId??null,nextFireAt:Number.isFinite(Number(e.nextFireAt))?Number(e.nextFireAt):null,createdAt:Number(e.createdAt)||null,runCount:t.length,lastRun:n?{firedAt:Number(n.firedAt)||null,outcome:n.outcome??(n.error?"errored":null)}:null}}function E_(e,t){let n=an(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 p2(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=>!tg.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: ${tg.join(", ")}`)}let o={};for(let a of tg){if(!(a in n))continue;let i=Go[a](n[a]);(a==="assignment"?f2(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 A_(e,t,n){let r=T_(t),{patch:o,changed:s}=p2(n,r),a=ng(),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 $({id:e.id,cwd:e.cwd},{type:"loop.update.offered",actor:"system",source:"orchestrator",payload:i}),i}var x_=600;async function __(e,t,n){let r=an(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>x_)throw new Error(`reason is too long (${r.length}); cap is ${x_}`);let o=T_(t),s=ng(),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 $({id:e.id,cwd:e.cwd},{type:"loop.delete.offered",actor:"system",source:"orchestrator",payload:a}),a}var I_=async(e,t,n)=>{if(!n)throw new Error("proposalId required");let r=await F({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 $_(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 I_(e,"loop.update.offered",t)).payload,a={id:e.id,cwd:e.cwd};return n==="applied"&&await $(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 $(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 R_(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 I_(e,"loop.delete.offered",t)).payload,s={id:e.id,cwd:e.cwd};return(n==="delete"||n==="pause")&&await $(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 $(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}}uu();me();ur();me();Fn();Iu();var O_=10,C_=200,m2=120,h2=24,N_=/^\d{4}-\d{2}-\d{2}$/;function rg(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var w2=(e=Date.now())=>new Date(e).toISOString().slice(0,10),pt=(e,t="i")=>new RegExp(e,t),g2=[{re:pt("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:pt("\\bSPC\\b",""),reason:"business (SPC)"},{re:pt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:pt("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:pt("\\bReplicas\\b",""),reason:"competitor research"},{re:pt("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:pt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:pt("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],y2=[pt("\\bSPC\\b",""),pt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),pt("competitor|cloudcli|\\bkiro\\b"),pt("\\bReplicas\\b",""),pt("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),pt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),pt("(^|[^\\w&])#\\d+\\b"),pt("\\btrack/[\\w.-]+")];function b2({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of g2)if(o.test(n)||o.test(r))return s;return null}function M_(e){let t=String(e||"");for(let n of y2){let r=n.exec(t);if(r)return r[0].trim()}return null}function P_(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 k2=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function x2(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=ji(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(`
694
- `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,m2)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${h2}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=k2.exec(i);if(!u||!u[1].trim()||!u[2].trim())throw new Error(`bullet ${r.length+1} must be \`**Short summary** \u2014 the item, one sentence.\` (bold summary title, em dash, then the change) \u2014 got "${i.slice(0,80)}". Rewrite it and re-publish.`);i=`**${u[1].trim().replace(/[:.]\s*$/,"")}** \u2014 ${u[2].trim()}`;let f=M_(i);if(f)throw new Error(`bullet ${r.length+1} mentions "${f}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items, PR numbers, branch names or codenames; drop the bullet or rewrite it as the user-visible change and re-publish.`);if(i.length>C_)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${C_}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=M_(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>O_)throw new Error(`${r.length} bullets \u2014 over the ${O_}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function v2(e,{repos:t=rg()}={}){let n=new Set(t);return(await xo()).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:b2({title:r.title,headRef:r.headRef})}))}async function D_(e,t){let n=await v2(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function B_(e,{md:t,day:n=null}){let r=x2(t),o=n==null||n===""?w2():String(n);if(!N_.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await $({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:o,title:r.title,bullets:r.bullets}});return{day:o,title:r.title,bullets:r.bullets,eventId:s.id}}async function j_(e,{day:t}){let n=String(t||"");if(!N_.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await $({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:n,title:null,bullets:[],retract:!0}});return{day:n,retracted:!0,eventId:r.id}}Bs();Fn();Eo();me();Bs();it();Nr();Fn();gi();eu();Si();Bn();import{execFile as S2}from"node:child_process";import{promisify as T2}from"node:util";var sg=T2(S2),L_=3e4,E2=30*6e4,A2=L_,_2=10*6e4,I2=10080*6e4,$2=60*6e4,R2=8,O2=1440*6e4,C2=3,F_="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",og=60*6e4,M2=15*6e4,N2=9e4,P2=1440*6e4,kd=new Map,xd=new Map,D2=/could not resolve|not found|no pull requests?/i,B2=e=>D2.test(String(e?.message||e||""));function j2(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<og)}var U_={fast:A2,slow:_2,decay:$2};function H_(e,t){return e.armedAt&&t-e.armedAt<E2||j2(e,t)||W_(e,t,{grace:0})?"fast":t-(e.firstSeen||0)>I2?"decay":"slow"}function L2(e,t){return U_[H_(e,t)]}function Tc(e,t,n,r){let o=e.lanes?.get(oe(t.repo,t.number))||{};return Ql({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function F2(e,t){Hn("watch");try{let{stdout:n}=await sg("gh",["pr","view",String(t),"--repo",e,"--json",F_],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await ln({slug:e})}});return JSON.parse(n||"null")}catch(n){throw Rr(n)&&Or(n),n}}async function U2(e){Hn("watch");try{let{stdout:t}=await sg("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",F_],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await ln({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw Rr(t)&&Or(t),t}}async function H2(){let e=new Map;for(let t of await le().catch(()=>[]))e.set(t.id,t);return e}async function W2(e,t){await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}})}async function q2(e,t){let n=await So(e);return n?Ps(n,t):null}async function K2(e,t,n){let r=await So(e);if(!r)throw new Error(`no local checkout for ${e}`);return Ds(r,t,{method:n})}async function G2(e,t){let n=await So(e);if(!n)throw new Error(`no local checkout for ${e}`);return ki(n,t)}async function V2(e,t){await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"auto-canceled",...t}})}async function da(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 z2=10*6e4;async function Y2(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>O2){await da(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 da(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await da(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<z2)return;await da(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 da(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 da(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await q_(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function fa(e,t,n){await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function J2(e,t){try{return await sg("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function Sc(e,t,n,r=()=>!0){return(await F(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var pa=(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 W_(e,t,{grace:n=N2}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=P2}async function X2(e,t,n,r){let o=r.now??Date.now();if(!W_(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||Ve(s))return!1;let a=(s.boxes||[]).find(f=>f.name===s.leadBox);return await(r.midTurn??To)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await F(s).catch(()=>[])).some(f=>f.type==="pr.state.changed"&&f.payload?.number===Number(e.number))?(await(r.claim??Ln)(e.repo,e.number).catch(()=>null),!1):await(r.claim??Ln)(e.repo,e.number).catch(()=>null)?(await fa(s,"opened",{...pa(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 Z2(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 Kl(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await Vl(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<M2;await Cx(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await Ox(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await Sc(a,"pushed",e.number,f=>f.payload?.sha===s)&&await fa(a,"pushed",{...pa(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>og)await Gl(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 Gl(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=Tc(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await Sc(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await fa(a,"ci-fixed",{...pa(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await Gl(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>og)await zl(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await zl(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Tc(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await Sc(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await fa(a,"reconciled",{...pa(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await zl(e.repo,e.number).catch(()=>{})}}}}async function Q2(e,t,n,r){let o=Tc(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await Sc(s,"closed",e.number)&&await fa(s,"closed",{...pa(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 eH(e,t,n){Tc(n,e,"lost",null);let r=t.get(e.trackId);r&&!await Sc(r,"lost",e.number)&&await fa(r,"lost",pa(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function q_(e,t,n,r,o={}){let s=Tc(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await F(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 tH(e={}){let{now:t=Date.now(),auth:n=Zp,view:r=F2,list:o=U2,links:s=Dx,trackMap:a=H2,emitMerged:i=W2,mark:c=Ir,archiveIfArmed:l=qn,notifyIfArmed:u=Kn,notifyIfResolved:f=Lu,followupsIfMerged:d=Bo,batchThreshold:p=C2,detail:h=q2,merge:w=K2,updateBranch:g=G2,lookup:k=tt,disarm:S=wi,emitDisarmed:E=V2,localHasCommit:R=J2,claim:B=Ln,midTurn:T=To}=e;if(!(await n().catch(()=>null))?.authenticated||Xl()>0)return 0;let O=await s().catch(()=>[]),I=av(O),U=O.filter(W=>t-(kd.get(oe(W.repo,W.number))||0)>=L2(W,t));if(!U.length)return 0;let H=Date.now(),ae=new Map,X=new Map;for(let W of[...U].sort(xi)){let be=H_(W,t);ae.set(oe(W.repo,W.number),{lane:be,intervalMs:U_[be]}),kd.set(oe(W.repo,W.number),t),X.has(W.repo)||X.set(W.repo,[]),X.get(W.repo).push(W)}let C=await a().catch(()=>new Map),Q={now:t,lanes:ae,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:f,followupsIfMerged:d,detail:h,merge:w,updateBranch:g,lookup:k,disarm:S,emitDisarmed:E,localHasCommit:R,claim:B,midTurn:T};for(let[W,be]of X){let se,pe=new Set;if(be.length>p)se=await o(W).catch(()=>null);else{se=new Map;for(let ie of be)try{let L=await r(W,ie.number);L?.number!=null&&se.set(Number(L.number),L)}catch(L){B2(L)&&pe.add(oe(ie.repo,ie.number))}}if(se)for(let ie of be){let L=oe(ie.repo,ie.number),ce=se.get(Number(ie.number));if(!ce){if(pe.has(L)){let ue=(xd.get(L)||0)+1;xd.set(L,ue),ue>=R2&&(await eH(ie,C,Q),xd.delete(L),kd.delete(L))}continue}if(xd.delete(L),ce.state==="MERGED"||ce.state==="CLOSED")ce.state==="MERGED"?await q_(ie,ce,C,Q):await Q2(ie,ce,C,Q),kd.delete(L);else{await X2(ie,ce,C,Q).catch(()=>{}),await Z2(ie,ce,C,Q).catch(()=>{});let ue=!ie.trackId||I.get(ie.trackId)===L;ie.autoMerge&&ue&&await Y2(ie,C,Q).catch(()=>{})}}}let ve={};for(let{lane:W}of ae.values())ve[W]=(ve[W]||0)+1;return console.log(`[pr-watch] probed ${U.length} link(s) (${Object.entries(ve).map(([W,be])=>`${W} ${be}`).join(", ")}) in ${Date.now()-H}ms`),U.length}function K_(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{await tH()}catch{}finally{e=!1}}},L_)}me();Fn();ar();Nr();Bn();function G_(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function nH(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var rH=new Set(["merged","closed","lost"]);function oH(e,t){if(!e?.blocked)return null;let n=G_(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 sH(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function aH(e,t,n,r,o){return(await F(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 iH(e,t,n){await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function V_(e,t={}){let{now:n=Date.now(),slugOf:r=Se,lookup:o=tt,note:s=Mx,tracks:a=async()=>(await le()).filter(f=>!Ve(f)),asked:i=aH,emitChange:c=iH}=t,l=[],u=null;for(let f of e??[]){if(!f?.prs?.length)continue;let d=await r(f.path).catch(()=>null);if(d)for(let p of f.prs)try{if(!nH(p))continue;let h=await o(d,p.number).catch(()=>null);if(!h?.trackId||rH.has(h.state))continue;let{prev:w}=await s(d,p.number,{blocked:G_(p),sha:p.headSha??null,at:n});if(!w)continue;let g=oH(w,p);if(!g||sH(h,g.change))continue;u??=new Map((await a()).map(R=>[R.id,R]));let k=u.get(h.trackId);if(!k)continue;let S=p.headSha??null;if(await i(k,g.change,p.number,S,w.at||0))continue;let E={number:Number(p.number),url:p.url||h.url,title:p.title||h.title,branch:p.headRefName||h.headRef,repo:d,sha:S,delegated:!1,reason:g.reason};g.change==="ci-fixed"?E.passed=p.checks.passed:E.base=p.baseRefName||null,await c(k,g.change,E),l.push({change:g.change,number:p.number,reason:g.reason})}catch{}}return l}lt();me();Nr();Bn();import{randomUUID as cH}from"node:crypto";var lH=2e4,z_=3,ma=new Map,ag=new Set;async function Y_(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 uH(e={}){let{sessions:t=null,tracks:n=null,append:r=$,read:o=F,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await zt(),i=n??await le()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(Ve(u)||!u.leadBox)continue;let f=(u.boxes||[]).find(p=>p.name===u.leadBox);if(!f||f.agent!=="claude"||f.state!=="live")continue;let d=c.get(f.name);if(d)if(l.add(f.name),d.alternateOn){let p=(ma.get(f.name)||0)+1;ma.set(f.name,p),p===z_&&(ag.add(f.name),await Y_(u,f.name,o)||await r(u,{type:"box.fullscreen.detected",actor:"system",source:"orchestrator",boxId:f.name,provider:f.agent,payload:{ts:s,offerId:cH(),box:f.name,agent:f.agent}}).catch(()=>{}))}else{let p=(ma.get(f.name)||0)>=z_;if(ma.delete(f.name),p||!ag.has(f.name)){ag.add(f.name);let h=await Y_(u,f.name,o);h&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:f.name,provider:f.agent,payload:{ts:s,offerId:h,action:"cleared"}}).catch(()=>{})}}}for(let u of[...ma.keys()])l.has(u)||ma.delete(u)}var Ec=null,ig=!1;function J_(){return Ec?()=>{}:(Ec=setInterval(()=>{ig||(ig=!0,uH().catch(()=>{}).finally(()=>{ig=!1}))},lH),Ec.unref?.(),()=>{clearInterval(Ec),Ec=null})}bo();qm();me();Bs();Eo();bo();import{randomUUID as dH}from"node:crypto";async function fH(){let e=await Promise.resolve().then(()=>(Nr(),vE));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var cg={listRepoPrs:hn,readEvents:F,appendEvent:$,sayDeps:fH,currentBranch:Cr};async function pH(e,t=cg,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??Cr)(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 lg(e,t,{actions:n,notify:r=!1}={},o=cg){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 pH(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=dH();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 ug(e,{offerId:t,choice:n}={},r=cg){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');let o=await r.readEvents(e),s=o.find(u=>u.type==="pr.exists.offered"&&u.payload?.offerId===t);if(!s)throw new Error("unknown offer");if(o.some(u=>u.type==="pr.exists.answered"&&u.payload?.offerId===t))throw new Error("offer already answered");let a=s.payload||{},i=Array.isArray(a.actions)&&a.actions.length?a.actions:["commit","push","pr"],c=null,l=null;if(n==="push"){let{sayToLead:u}=await r.sayDeps();l=Ar.filter(f=>f!=="pr"&&(i.includes(f)||f==="push")),c=await u(e.id,Os(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,xx(i,{branch:a.branch??null,base:a.base??null,prNumber:a.pr?.number??null,offeredRebase:a.offeredRebase===!0}),{kind:"pr-go"})}if(await r.appendEvent({id:e.id,cwd:e.cwd},{type:"pr.exists.answered",actor:"user",source:"orchestrator",boxId:s.boxId,payload:{ts:Date.now(),offerId:t,choice:n}}),n!=="dismiss"&&a.notify===!0){let{queueShipCompleteNotify:u}=await r.sayDeps();u(e.id,{actions:l})}return{say:c,choice:n}}import rr from"node:fs/promises";import ha from"node:path";import rI from"node:os";import X_ from"node:fs/promises";import vd from"node:path";import{execFile as mH}from"node:child_process";import{promisify as hH}from"node:util";import{fileURLToPath as wH}from"node:url";var gH=hH(mH),Q_=vd.dirname(wH(import.meta.url)),yH=vd.resolve(Q_,"..","..","client","dist"),bH="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",kH=new Map([...bH].map((e,t)=>[e,t]));function xH(e){let t=[],n=0,r=0;for(let o of e){let s=kH.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 vH(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=xH(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 SH(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 Z_=new Map;async function TH(e){let t;try{t=await X_.stat(e)}catch{return null}let n=Z_.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await X_.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:vH(r.mappings||"")};return Z_.set(e,o),o}catch{return null}}var dg=null;function EH(){return dg||(dg=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):gH("git",["rev-parse","--short","HEAD"],{cwd:vd.resolve(Q_,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),dg}var AH=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function _H(e,{distDir:t=yH}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(AH)){let[a,i,c,l]=s,u=await TH(vd.join(t,"assets",`${i}.map`)),f=u?SH(u.lines[Number(c)-1],Number(l)-1):null;if(n.push(e.slice(r,s.index)),f&&u.sources[f[1]]){let d=u.sources[f[1]].replace(/^(\.\.\/)+/,"");n.push(`${d}:${f[2]+1}:${f[3]+1}`),o=!0}else n.push(a);r=s.index+a.length}return n.push(e.slice(r)),{stack:n.join(""),symbolicated:o}}async function eI(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await EH();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await _H(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var IH=()=>process.env.BOSTRAT_STATE_DIR||ha.join(process.env.HOME||rI.tmpdir(),".bostrat"),Qr=()=>ha.join(IH(),"telemetry"),oI=()=>ha.join(Qr(),".relay-offsets.json"),$H=50,RH=14,OH=3e4,tI=500,jt=(e,t)=>typeof e=="string"?e.slice(0,t):"";function CH(e,t){if(!e||typeof e!="object")return null;let n=jt(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:jt(e.anonId,64),sessionId:jt(e.sessionId,64),userId:jt(e.userId,64),release:jt(e.release,64),appVersion:jt(e.appVersion,32),route:jt(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:jt(e.error.kind,256),message:jt(e.error.message,8192),stack:jt(e.error.stack,32768),fingerprint:jt(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:jt(s?.n,64),r:jt(s?.r,128)}))),o}var sI=e=>new Date(e).toISOString().slice(0,10),nI=0;async function aI(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,$H):[]).map(s=>CH(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await eI(s);await rr.mkdir(Qr(),{recursive:!0});let o=ha.join(Qr(),`${sI(t)}.ndjson`);return await rr.appendFile(o,r.map(s=>JSON.stringify(s)+`
695
- `).join(""),"utf8"),t-nI>6*3600*1e3&&(nI=t,MH(t).catch(()=>{})),r.length}async function MH(e=Date.now()){let t=sI(e-RH*24*3600*1e3),n=[];try{n=await rr.readdir(Qr())}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 rr.rm(ha.join(Qr(),s),{force:!0});let o=await cI();for(let s of r)delete o[s];await lI(o)}var Sd=new Map;function iI(e,t=Date.now()){let n=e||"unknown",r=Sd.get(n);return r||(Sd.size>512&&Sd.clear(),r={tokens:40,at:t},Sd.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 cI(){try{return JSON.parse(await rr.readFile(oI(),"utf8"))||{}}catch{return{}}}async function lI(e){await rr.mkdir(Qr(),{recursive:!0}),await rr.writeFile(oI(),JSON.stringify(e),"utf8")}function NH(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||rI.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 PH({fetchImpl:e=fetch}={}){let t=await zE();if(!t)return{sent:0,disabled:!0};let n;try{n=(await rr.readdir(Qr())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await cI(),o=0;for(let s of n){let a=ha.join(Qr(),s),i=r[s]||0,c;try{let d=await rr.open(a,"r");try{let p=(await d.stat()).size;if(p<=i)continue;c=Buffer.alloc(p-i),await d.read(c,0,c.length,i)}finally{await d.close()}}catch{continue}let l=c.lastIndexOf(10);if(l<0)continue;let u=c.toString("utf8",0,l+1).split(`
696
- `).filter(Boolean),f=[];for(let d of u)try{f.push(JSON.parse(d))}catch{}for(let d=0;d<f.length;d+=tI){let p=f.slice(d,d+tI).map(w=>NH(w)),h=await e(`${t.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${t.ingestKey}`},body:JSON.stringify({events:p})}).catch(()=>null);if(!h||!h.ok)return{sent:o,disabled:!1};o+=p.length}r[s]=i+l+1,await lI(r)}return{sent:o,disabled:!1}}var fg=null,pg=!1;function uI(){fg||(fg=setInterval(async()=>{if(!pg){pg=!0;try{await PH()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{pg=!1}}},OH),fg.unref?.())}import Ed from"node:fs/promises";import hI from"node:path";import DH from"node:os";var wI=()=>process.env.BOSTRAT_STATE_DIR||hI.join(process.env.HOME||DH.tmpdir(),".bostrat"),gI=()=>hI.join(wI(),"dictation-glossary.json"),BH=100,jH=500,LH=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Ad=null,mg=null,hg=Promise.resolve();function dI(){let e={},t=Date.now();for(let n of LH)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function yI(){return Ad||(mg??=Ed.readFile(gI(),"utf8").then(e=>JSON.parse(e)?.terms??dI()).catch(()=>dI()).then(e=>Ad=e).finally(()=>mg=null),mg)}async function fI(){let e=JSON.stringify({terms:Ad},null,2),t=gI(),n=`${t}.${process.pid}.tmp`;await Ed.mkdir(wI(),{recursive:!0}),await Ed.writeFile(n,e),await Ed.rename(n,t)}function FH(){return hg=hg.then(fI,fI),hg.catch(()=>{})}async function wg(){return Object.values(await yI()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var UH=e=>Math.max(1,Math.ceil(e.length/4));async function HH(){let e=[],t=0;for(let{term:n}of await wg()){let r=UH(n);if(!(t+r>jH)&&(e.push(n),t+=r,e.length>=BH))break}return e}async function WH(e,t){let n=await yI(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var pI=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),Td=e=>e.toLowerCase();function mI(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function bI(e,t){let n=pI(e),r=pI(t);if(!n.length||!r.length)return[];let o=n.length,s=r.length,a=Array.from({length:o+1},()=>new Array(s+1).fill(0));for(let u=o-1;u>=0;u--)for(let f=s-1;f>=0;f--)a[u][f]=Td(n[u])===Td(r[f])?a[u+1][f+1]+1:Math.max(a[u+1][f],a[u][f+1]);let i=new Set,c=0,l=0;for(;c<o&&l<s;)Td(n[c])===Td(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(mI(r[l])&&i.add(r[l]),l++);for(;l<s;l++)mI(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await WH(u,"learned");return await FH(),[...i]}var Ac=null;function qH(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 kI(){if(!Ac)return null;let e=await uc();if(!e||e.apiKey.slice(-6)!==Ac.keyTail)return null;let{keyTail:t,...n}=Ac;return n}async function xI(e,t){let n=await uc();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 HH())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=qH(o.status,i);c.persistent&&(Ac={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 Ac=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}me();var gg={"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 KH(e){if(!e)return null;let t=String(e).trim();if(gg[t])return t;let n=null;for(let r of Object.keys(gg))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function GH(e,t={}){let n=gg[KH(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 VH(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 _c=null;async function zH(){if(!_c)return null;let e=await rd();if(!e||e.apiKey.slice(-6)!==_c.keyTail)return null;let{keyTail:t,...n}=_c;return n}async function YH(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=VH(t.status,o);s.persistent&&(_c={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}_c=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 JH={openai:YH};async function vI(){let e=await rd();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await zH()}:{configured:!1}}async function SI(){let e=await rd();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 JH[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function TI(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=GH(t,s),i=await $(e,{type:"cost.recorded",actor:"user",provider:"openai-realtime",payload:{model:t||"unknown",usd:a,tokens:{input:s.textIn+s.audioIn,output:s.textOut+s.audioOut,cacheRead:s.textInCached+s.audioInCached,cacheWrite:0},voice:s,seconds:Math.max(0,Math.round(Number(r)||0)),source:"voice-chat"}});return{usd:a,seq:i.seq}}Bn();var OI=xe.dirname(ZH(import.meta.url)),EI=Number(process.env.PORT)||3362,Id=fw(process.env),CI=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,wa=s_(process.env.BOSTRAT_ALLOW_IPS),vg=a_(process.env.BOSTRAT_VIEW_FRONT_CIDRS,bd),MI=c_(),NI=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",v=Gt();v.disable("x-powered-by");v.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),yd(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});v.use((e,t,n)=>{if(vc(e)||wa.allowed(wa.clientIp(e))||vg.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});v.use(p_);v.use(d_({token:MI,enforce:NI}));v.use("/api/mocks",Gt.json({limit:"1mb"}));v.use("/api/mocks",Gt.raw({type:"image/png",limit:"24mb"}));v.use("/api/mocks",Gt.raw({type:["video/mp4","video/webm"],limit:"105mb"}));v.use("/api/runbooks",Gt.json({limit:"1mb"}));v.use("/api/tracks/adopt",Gt.json({limit:"1mb"}));v.use("/api/telemetry",Gt.json({limit:"256kb"}));v.use("/api/hook",Gt.json({limit:"2mb"}));v.use("/api/dictation",Gt.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));v.use("/api/tracks/:id/upload",Gt.raw({type:()=>!0,limit:"25mb"}));v.use(Gt.json({limit:"64kb"}));v.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:$t,hostTmuxAlive:await fr(),autoTriggerPct:CI,plane:ga?ga.status():null})});v.get("/api/sessions",async(e,t)=>{t.json({sessions:await zt()})});v.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 pr(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})}});v.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!Pe(n))return t.status(400).json({error:"invalid session name"});if(!await ge(n))return t.status(404).json({error:"session not found"});try{await Yt(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});v.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!Pe(n))return t.status(400).json({error:"invalid session name"});let r=await ge(n);if(!r)return t.status(404).json({error:"session not found"});let o=await Ka(r.cwd,r.sessionId);if(!o)return t.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});t.json({available:!0,...o})});v.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!Pe(n))return t.status(400).json({error:"invalid session name"});try{let r=await Bk(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)})}});v.get("/api/handoff/:name",(e,t)=>{let n=decodeURIComponent(e.params.name),r=Il(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 AI=10;v.get("/api/idle-guard",async(e,t)=>{try{t.json(dw({tracks:await le(),views:await ku(),queuedOf:n=>Mo(n)}))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var Kt=Lo(),rW=DE({kind:Kt}),Ic=null,kt=()=>Ic&&["auto","prompt","off"].includes(Ic)?Ic:rW,xg=null,oW=cc.has(Kt),PI=async({to:e,from:t})=>!oW||Ju(await lc())?!1:($c.arm({to:e,from:t,kind:Kt}),!0);async function sW(e){let t=kt();Ic=e??null;let n=kt();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){$c.cancel();return}xg&&await PI(xg)}}var DI=(()=>{try{return nW(import.meta.url)("../package.json").version||null}catch{return null}})(),$c=jE({isBusy:async()=>dw({tracks:await le(),views:await ku(),queuedOf:e=>Mo(e)}).busy,onStuck:({to:e,from:t})=>An({current:t,latest:e,installKind:Kt,policy:kt(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?An({current:t,latest:e,installKind:Kt,policy:kt(),status:"updating",reason:"auto"}):An({current:t,latest:e,installKind:Kt,policy:kt(),status:"failed",error:n?.reason})).catch(()=>{})});v.get("/api/node/self-update",async(e,t)=>{t.json({installKind:Kt,policy:kt(),policySource:Ic?"plane":"node",current:DI,status:await lc(),armed:$c.armed})});v.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 Xu({to:n,kind:Kt,reason:"manual"});if(r.ok)return $c.cancel(),An({current:r.from,latest:n,installKind:Kt,policy:kt(),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 BI(){try{let e=await BE();e&&await An({current:e.from,latest:e.to,installKind:e.kind||Kt,policy:kt(),status:e.status,error:e.error,reason:e.reason}),await Rh({current:DI,installKind:Kt,policy:kt()})}catch{}}BI();setInterval(BI,3e4).unref();v.get("/api/tracks",async(e,t)=>{let n=(await le()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>AI){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,AI).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:Xi,agentAvailability:await Mu(),tickets:await cA()})});v.get("/api/cost",async(e,t)=>{try{let n=await le();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await Vw(n);if(r.cursorUsage=Tm(),e.query.format==="text")return t.type("text/plain").send(BA(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/usage/roundup",async(e,t)=>{try{t.json(await FA(await le(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/usage/spend",async(e,t)=>{try{let n=await KA(await le(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=Tm(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=fi(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/usage/caps",(e,t)=>{t.json(fi())});v.post("/api/usage/caps",async(e,t)=>{try{t.json(await Ll(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});v.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await e_(await le(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await Dg(e.get(Rn),{byToken:Qi,legacy:()=>Ii(e.body?.session_id,e.body?.cwd)});if(n==="refused")return Sa("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Sa("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&&Sa("mismatch",{track:r.track.id,box:r.box.name}),Sa(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 RA(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&zc(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});v.get("/api/git/trailers",async(e,t)=>{t.type("text/plain");try{let n=await Qi(e.get(Rn));if(!n?.track||!n?.box)return t.status(204).end();t.send((await CA(n.track,n.box)).join(`
693
+ `),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 g_(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}.${u2(n.host)}/`}function u2(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 kd(t)&&Hm(n[0])?n.slice(1).join("."):t}Gs();th();Ru();mm();he();import y_ from"node:os";import{randomUUID as rg}from"node:crypto";var d2=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||y_.hostname(),nodeName:e.BOSTRAT_NODE_NAME||y_.hostname()});var b_=32768,k_=120,x_=1e3,v_=new Set(["claude","codex","cursor"]),f2=new Set(["off","transition","nag"]),p2=[[0,59],[0,23],[1,31],[1,12],[0,6]];function m2(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=p2[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 an=e=>String(e??"").trim(),Go={name(e){let t=an(e);if(!t)throw new Error("a loop needs a name");if(t.length>k_)throw new Error(`name is too long (${t.length}); cap is ${k_}`);return t},schedule(e){let t=an(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!m2(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=an(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>b_)throw new Error(`prompt is too long (${t.length} chars); cap is ${b_}`);return t},expectation(e){let t=an(e)||null;if(t&&t.length>x_)throw new Error(`expectation is too long (${t.length}); cap is ${x_}`);return t},notify(e){let t=an(e)||"off";if(!f2.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=an(typeof t=="string"?t:t?.provider)||"claude";if(!v_.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...v_].join(", ")}`);let r=typeof t=="object"&&t&&an(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 h2(e,t){let n=e&&typeof e=="object"?e:{},r=Go.name(n.name),o=Go.schedule(n.schedule),s=Go.prompt(n.prompt),a=Go.expectation(n.expectation),i=Go.notify(n.notify),c=Go.assignment(n.assignment),l=an(t?.workspace?.repo)||an(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:f}=d2();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:f||null}}async function T_(e,t){let n=h2(t,e),r=rg();return await $({id:e.id,cwd:e.cwd},{type:"loop.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:r,...n}}),{proposalId:r,...n}}async function E_(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await U({id:e.id,cwd:e.cwd}),a=s.find(c=>c.type==="loop.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="loop.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await $({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("loopId required \u2014 the loop is created on the plane before the card is answered");let i=a.payload;return await $({id:e.id,cwd:e.cwd},{type:"loop.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:String(r),name:i.name,schedule:i.schedule,provider:i.assignment?.provider??"claude",repo:i.repo??null,nodeId:i.nodeId??null,nextFireAt:Number.isFinite(Number(o))?Number(o):null}}),await $({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",loopId:String(r)}}),{proposalId:t,action:"created",loopId:String(r)}}var ng=["name","schedule","prompt","expectation","notify","assignment","enabled"],w2=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function A_(e){let t=Array.isArray(e.runs)?e.runs:[],n=t[t.length-1]??null;return{definitionUpdatedAt:Number(e.definitionUpdatedAt??e.updatedAt)||null,name:e.name??"",schedule:e.schedule??"",prompt:e.prompt??"",expectation:e.expectation??null,notify:e.notify??"off",assignment:e.assignment&&typeof e.assignment=="object"?e.assignment:{provider:String(e.assignment||"claude")},enabled:e.enabled!==!1,repo:e.repo??null,nodeId:e.nodeId??null,nodeName:e.nodeName??null,trackId:e.trackId??null,nextFireAt:Number.isFinite(Number(e.nextFireAt))?Number(e.nextFireAt):null,createdAt:Number(e.createdAt)||null,runCount:t.length,lastRun:n?{firedAt:Number(n.firedAt)||null,outcome:n.outcome??(n.error?"errored":null)}:null}}function __(e,t){let n=an(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 g2(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=>!ng.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: ${ng.join(", ")}`)}let o={};for(let a of ng){if(!(a in n))continue;let i=Go[a](n[a]);(a==="assignment"?w2(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 I_(e,t,n){let r=A_(t),{patch:o,changed:s}=g2(n,r),a=rg(),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 $({id:e.id,cwd:e.cwd},{type:"loop.update.offered",actor:"system",source:"orchestrator",payload:i}),i}var S_=600;async function $_(e,t,n){let r=an(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>S_)throw new Error(`reason is too long (${r.length}); cap is ${S_}`);let o=A_(t),s=rg(),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 $({id:e.id,cwd:e.cwd},{type:"loop.delete.offered",actor:"system",source:"orchestrator",payload:a}),a}var R_=async(e,t,n)=>{if(!n)throw new Error("proposalId required");let r=await U({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 O_(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 R_(e,"loop.update.offered",t)).payload,a={id:e.id,cwd:e.cwd};return n==="applied"&&await $(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 $(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 C_(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 R_(e,"loop.delete.offered",t)).payload,s={id:e.id,cwd:e.cwd};return(n==="delete"||n==="pause")&&await $(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 $(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}}fu();he();dr();he();Fn();Ru();var M_=10,N_=200,y2=120,b2=24,D_=/^\d{4}-\d{2}-\d{2}$/;function og(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var k2=(e=Date.now())=>new Date(e).toISOString().slice(0,10),pt=(e,t="i")=>new RegExp(e,t),x2=[{re:pt("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:pt("\\bSPC\\b",""),reason:"business (SPC)"},{re:pt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:pt("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:pt("\\bReplicas\\b",""),reason:"competitor research"},{re:pt("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:pt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:pt("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],v2=[pt("\\bSPC\\b",""),pt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),pt("competitor|cloudcli|\\bkiro\\b"),pt("\\bReplicas\\b",""),pt("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),pt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),pt("(^|[^\\w&])#\\d+\\b"),pt("\\btrack/[\\w.-]+")];function S2({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of x2)if(o.test(n)||o.test(r))return s;return null}function P_(e){let t=String(e||"");for(let n of v2){let r=n.exec(t);if(r)return r[0].trim()}return null}function B_(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 T2=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function E2(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Li(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(`
694
+ `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,y2)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${b2}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=T2.exec(i);if(!u||!u[1].trim()||!u[2].trim())throw new Error(`bullet ${r.length+1} must be \`**Short summary** \u2014 the item, one sentence.\` (bold summary title, em dash, then the change) \u2014 got "${i.slice(0,80)}". Rewrite it and re-publish.`);i=`**${u[1].trim().replace(/[:.]\s*$/,"")}** \u2014 ${u[2].trim()}`;let f=P_(i);if(f)throw new Error(`bullet ${r.length+1} mentions "${f}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items, PR numbers, branch names or codenames; drop the bullet or rewrite it as the user-visible change and re-publish.`);if(i.length>N_)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${N_}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=P_(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>M_)throw new Error(`${r.length} bullets \u2014 over the ${M_}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function A2(e,{repos:t=og()}={}){let n=new Set(t);return(await xo()).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:S2({title:r.title,headRef:r.headRef})}))}async function j_(e,t){let n=await A2(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function L_(e,{md:t,day:n=null}){let r=E2(t),o=n==null||n===""?k2():String(n);if(!D_.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await $({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:o,title:r.title,bullets:r.bullets}});return{day:o,title:r.title,bullets:r.bullets,eventId:s.id}}async function F_(e,{day:t}){let n=String(t||"");if(!D_.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await $({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:n,title:null,bullets:[],retract:!0}});return{day:n,retracted:!0,eventId:r.id}}js();Fn();Eo();he();js();it();Pr();Fn();yi();nu();Ti();Bn();import{execFile as _2}from"node:child_process";import{promisify as I2}from"node:util";var ag=I2(_2),U_=3e4,$2=30*6e4,R2=U_,O2=10*6e4,C2=10080*6e4,M2=60*6e4,N2=8,P2=1440*6e4,D2=3,H_="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",sg=60*6e4,B2=15*6e4,j2=9e4,L2=1440*6e4,vd=new Map,Sd=new Map,F2=/could not resolve|not found|no pull requests?/i,U2=e=>F2.test(String(e?.message||e||""));function H2(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<sg)}var W_={fast:R2,slow:O2,decay:M2};function q_(e,t){return e.armedAt&&t-e.armedAt<$2||H2(e,t)||K_(e,t,{grace:0})?"fast":t-(e.firstSeen||0)>C2?"decay":"slow"}function W2(e,t){return W_[q_(e,t)]}function Ac(e,t,n,r){let o=e.lanes?.get(ae(t.repo,t.number))||{};return tu({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function q2(e,t){Hn("watch");try{let{stdout:n}=await ag("gh",["pr","view",String(t),"--repo",e,"--json",H_],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await ln({slug:e})}});return JSON.parse(n||"null")}catch(n){throw Or(n)&&Cr(n),n}}async function K2(e){Hn("watch");try{let{stdout:t}=await ag("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",H_],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await ln({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw Or(t)&&Cr(t),t}}async function G2(){let e=new Map;for(let t of await ue().catch(()=>[]))e.set(t.id,t);return e}async function V2(e,t){await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}})}async function z2(e,t){let n=await So(e);return n?Ds(n,t):null}async function Y2(e,t,n){let r=await So(e);if(!r)throw new Error(`no local checkout for ${e}`);return Bs(r,t,{method:n})}async function J2(e,t){let n=await So(e);if(!n)throw new Error(`no local checkout for ${e}`);return xi(n,t)}async function X2(e,t){await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"auto-canceled",...t}})}async function 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 Z2=10*6e4;async function Q2(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>P2){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<Z2)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 G_(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function pa(e,t,n){await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function eH(e,t){try{return await ag("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function Ec(e,t,n,r=()=>!0){return(await U(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var ma=(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 K_(e,t,{grace:n=j2}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=L2}async function tH(e,t,n,r){let o=r.now??Date.now();if(!K_(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||Ve(s))return!1;let a=(s.boxes||[]).find(f=>f.name===s.leadBox);return await(r.midTurn??To)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await U(s).catch(()=>[])).some(f=>f.type==="pr.state.changed"&&f.payload?.number===Number(e.number))?(await(r.claim??Ln)(e.repo,e.number).catch(()=>null),!1):await(r.claim??Ln)(e.repo,e.number).catch(()=>null)?(await pa(s,"opened",{...ma(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 nH(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 Vl(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await Yl(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<B2;await Px(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await Nx(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await Ec(a,"pushed",e.number,f=>f.payload?.sha===s)&&await pa(a,"pushed",{...ma(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>sg)await zl(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 zl(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=Ac(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await Ec(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await pa(a,"ci-fixed",{...ma(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await zl(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>sg)await Jl(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await Jl(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Ac(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await Ec(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await pa(a,"reconciled",{...ma(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await Jl(e.repo,e.number).catch(()=>{})}}}}async function rH(e,t,n,r){let o=Ac(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await Ec(s,"closed",e.number)&&await pa(s,"closed",{...ma(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 oH(e,t,n){Ac(n,e,"lost",null);let r=t.get(e.trackId);r&&!await Ec(r,"lost",e.number)&&await pa(r,"lost",ma(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function G_(e,t,n,r,o={}){let s=Ac(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await U(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 sH(e={}){let{now:t=Date.now(),auth:n=Qp,view:r=q2,list:o=K2,links:s=Lx,trackMap:a=G2,emitMerged:i=V2,mark:c=$r,archiveIfArmed:l=qn,notifyIfArmed:u=Kn,notifyIfResolved:f=Uu,followupsIfMerged:d=Bo,batchThreshold:p=D2,detail:h=z2,merge:w=Y2,updateBranch:g=J2,lookup:b=tt,disarm:E=gi,emitDisarmed:S=X2,localHasCommit:R=eH,claim:M=Ln,midTurn:T=To}=e;if(!(await n().catch(()=>null))?.authenticated||Ql()>0)return 0;let C=await s().catch(()=>[]),I=lv(C),W=C.filter(H=>t-(vd.get(ae(H.repo,H.number))||0)>=W2(H,t));if(!W.length)return 0;let j=Date.now(),ee=new Map,q=new Map;for(let H of[...W].sort(vi)){let ke=q_(H,t);ee.set(ae(H.repo,H.number),{lane:ke,intervalMs:W_[ke]}),vd.set(ae(H.repo,H.number),t),q.has(H.repo)||q.set(H.repo,[]),q.get(H.repo).push(H)}let O=await a().catch(()=>new Map),z={now:t,lanes:ee,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:f,followupsIfMerged:d,detail:h,merge:w,updateBranch:g,lookup:b,disarm:E,emitDisarmed:S,localHasCommit:R,claim:M,midTurn:T};for(let[H,ke]of q){let ie,me=new Set;if(ke.length>p)ie=await o(H).catch(()=>null);else{ie=new Map;for(let ce of ke)try{let F=await r(H,ce.number);F?.number!=null&&ie.set(Number(F.number),F)}catch(F){U2(F)&&me.add(ae(ce.repo,ce.number))}}if(ie)for(let ce of ke){let F=ae(ce.repo,ce.number),le=ie.get(Number(ce.number));if(!le){if(me.has(F)){let de=(Sd.get(F)||0)+1;Sd.set(F,de),de>=N2&&(await oH(ce,O,z),Sd.delete(F),vd.delete(F))}continue}if(Sd.delete(F),le.state==="MERGED"||le.state==="CLOSED")le.state==="MERGED"?await G_(ce,le,O,z):await rH(ce,le,O,z),vd.delete(F);else{await tH(ce,le,O,z).catch(()=>{}),await nH(ce,le,O,z).catch(()=>{});let de=!ce.trackId||I.get(ce.trackId)===F;ce.autoMerge&&de&&await Q2(ce,O,z).catch(()=>{})}}}let te={};for(let{lane:H}of ee.values())te[H]=(te[H]||0)+1;return console.log(`[pr-watch] probed ${W.length} link(s) (${Object.entries(te).map(([H,ke])=>`${H} ${ke}`).join(", ")}) in ${Date.now()-j}ms`),W.length}function V_(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{await sH()}catch{}finally{e=!1}}},U_)}he();Fn();ir();Pr();Bn();function z_(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function aH(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var iH=new Set(["merged","closed","lost"]);function cH(e,t){if(!e?.blocked)return null;let n=z_(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 lH(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function uH(e,t,n,r,o){return(await U(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 dH(e,t,n){await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function Y_(e,t={}){let{now:n=Date.now(),slugOf:r=Se,lookup:o=tt,note:s=Dx,tracks:a=async()=>(await ue()).filter(f=>!Ve(f)),asked:i=uH,emitChange:c=dH}=t,l=[],u=null;for(let f of e??[]){if(!f?.prs?.length)continue;let d=await r(f.path).catch(()=>null);if(d)for(let p of f.prs)try{if(!aH(p))continue;let h=await o(d,p.number).catch(()=>null);if(!h?.trackId||iH.has(h.state))continue;let{prev:w}=await s(d,p.number,{blocked:z_(p),sha:p.headSha??null,at:n});if(!w)continue;let g=cH(w,p);if(!g||lH(h,g.change))continue;u??=new Map((await a()).map(R=>[R.id,R]));let b=u.get(h.trackId);if(!b)continue;let E=p.headSha??null;if(await i(b,g.change,p.number,E,w.at||0))continue;let S={number:Number(p.number),url:p.url||h.url,title:p.title||h.title,branch:p.headRefName||h.headRef,repo:d,sha:E,delegated:!1,reason:g.reason};g.change==="ci-fixed"?S.passed=p.checks.passed:S.base=p.baseRefName||null,await c(b,g.change,S),l.push({change:g.change,number:p.number,reason:g.reason})}catch{}}return l}lt();he();Pr();Bn();import{randomUUID as fH}from"node:crypto";var pH=2e4,J_=3,ha=new Map,ig=new Set;async function X_(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 mH(e={}){let{sessions:t=null,tracks:n=null,append:r=$,read:o=U,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await zt(),i=n??await ue()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(Ve(u)||!u.leadBox)continue;let f=(u.boxes||[]).find(p=>p.name===u.leadBox);if(!f||f.agent!=="claude"||f.state!=="live")continue;let d=c.get(f.name);if(d)if(l.add(f.name),d.alternateOn){let p=(ha.get(f.name)||0)+1;ha.set(f.name,p),p===J_&&(ig.add(f.name),await X_(u,f.name,o)||await r(u,{type:"box.fullscreen.detected",actor:"system",source:"orchestrator",boxId:f.name,provider:f.agent,payload:{ts:s,offerId:fH(),box:f.name,agent:f.agent}}).catch(()=>{}))}else{let p=(ha.get(f.name)||0)>=J_;if(ha.delete(f.name),p||!ig.has(f.name)){ig.add(f.name);let h=await X_(u,f.name,o);h&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:f.name,provider:f.agent,payload:{ts:s,offerId:h,action:"cleared"}}).catch(()=>{})}}}for(let u of[...ha.keys()])l.has(u)||ha.delete(u)}var _c=null,cg=!1;function Z_(){return _c?()=>{}:(_c=setInterval(()=>{cg||(cg=!0,mH().catch(()=>{}).finally(()=>{cg=!1}))},pH),_c.unref?.(),()=>{clearInterval(_c),_c=null})}bo();Km();he();js();Eo();bo();import{randomUUID as hH}from"node:crypto";async function wH(){let e=await Promise.resolve().then(()=>(Pr(),EE));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var lg={listRepoPrs:hn,readEvents:U,appendEvent:$,sayDeps:wH,currentBranch:Mr};async function gH(e,t=lg,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??Mr)(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 ug(e,t,{actions:n,notify:r=!1}={},o=lg){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 gH(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=hH();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 dg(e,{offerId:t,choice:n}={},r=lg){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');let o=await r.readEvents(e),s=o.find(u=>u.type==="pr.exists.offered"&&u.payload?.offerId===t);if(!s)throw new Error("unknown offer");if(o.some(u=>u.type==="pr.exists.answered"&&u.payload?.offerId===t))throw new Error("offer already answered");let a=s.payload||{},i=Array.isArray(a.actions)&&a.actions.length?a.actions:["commit","push","pr"],c=null,l=null;if(n==="push"){let{sayToLead:u}=await r.sayDeps();l=_r.filter(f=>f!=="pr"&&(i.includes(f)||f==="push")),c=await u(e.id,Cs(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,Tx(i,{branch:a.branch??null,base:a.base??null,prNumber:a.pr?.number??null,offeredRebase:a.offeredRebase===!0}),{kind:"pr-go"})}if(await r.appendEvent({id:e.id,cwd:e.cwd},{type:"pr.exists.answered",actor:"user",source:"orchestrator",boxId:s.boxId,payload:{ts:Date.now(),offerId:t,choice:n}}),n!=="dismiss"&&a.notify===!0){let{queueShipCompleteNotify:u}=await r.sayDeps();u(e.id,{actions:l})}return{say:c,choice:n}}import or from"node:fs/promises";import wa from"node:path";import sI from"node:os";import Q_ from"node:fs/promises";import Td from"node:path";import{execFile as yH}from"node:child_process";import{promisify as bH}from"node:util";import{fileURLToPath as kH}from"node:url";var xH=bH(yH),tI=Td.dirname(kH(import.meta.url)),vH=Td.resolve(tI,"..","..","client","dist"),SH="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",TH=new Map([...SH].map((e,t)=>[e,t]));function EH(e){let t=[],n=0,r=0;for(let o of e){let s=TH.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 AH(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=EH(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 _H(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 eI=new Map;async function IH(e){let t;try{t=await Q_.stat(e)}catch{return null}let n=eI.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await Q_.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:AH(r.mappings||"")};return eI.set(e,o),o}catch{return null}}var fg=null;function $H(){return fg||(fg=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):xH("git",["rev-parse","--short","HEAD"],{cwd:Td.resolve(tI,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),fg}var RH=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function OH(e,{distDir:t=vH}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(RH)){let[a,i,c,l]=s,u=await IH(Td.join(t,"assets",`${i}.map`)),f=u?_H(u.lines[Number(c)-1],Number(l)-1):null;if(n.push(e.slice(r,s.index)),f&&u.sources[f[1]]){let d=u.sources[f[1]].replace(/^(\.\.\/)+/,"");n.push(`${d}:${f[2]+1}:${f[3]+1}`),o=!0}else n.push(a);r=s.index+a.length}return n.push(e.slice(r)),{stack:n.join(""),symbolicated:o}}async function nI(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await $H();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await OH(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var CH=()=>process.env.BOSTRAT_STATE_DIR||wa.join(process.env.HOME||sI.tmpdir(),".bostrat"),Qr=()=>wa.join(CH(),"telemetry"),aI=()=>wa.join(Qr(),".relay-offsets.json"),MH=50,NH=14,PH=3e4,rI=500,jt=(e,t)=>typeof e=="string"?e.slice(0,t):"";function DH(e,t){if(!e||typeof e!="object")return null;let n=jt(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:jt(e.anonId,64),sessionId:jt(e.sessionId,64),userId:jt(e.userId,64),release:jt(e.release,64),appVersion:jt(e.appVersion,32),route:jt(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:jt(e.error.kind,256),message:jt(e.error.message,8192),stack:jt(e.error.stack,32768),fingerprint:jt(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:jt(s?.n,64),r:jt(s?.r,128)}))),o}var iI=e=>new Date(e).toISOString().slice(0,10),oI=0;async function cI(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,MH):[]).map(s=>DH(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await nI(s);await or.mkdir(Qr(),{recursive:!0});let o=wa.join(Qr(),`${iI(t)}.ndjson`);return await or.appendFile(o,r.map(s=>JSON.stringify(s)+`
695
+ `).join(""),"utf8"),t-oI>6*3600*1e3&&(oI=t,BH(t).catch(()=>{})),r.length}async function BH(e=Date.now()){let t=iI(e-NH*24*3600*1e3),n=[];try{n=await or.readdir(Qr())}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 or.rm(wa.join(Qr(),s),{force:!0});let o=await uI();for(let s of r)delete o[s];await dI(o)}var Ed=new Map;function lI(e,t=Date.now()){let n=e||"unknown",r=Ed.get(n);return r||(Ed.size>512&&Ed.clear(),r={tokens:40,at:t},Ed.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 uI(){try{return JSON.parse(await or.readFile(aI(),"utf8"))||{}}catch{return{}}}async function dI(e){await or.mkdir(Qr(),{recursive:!0}),await or.writeFile(aI(),JSON.stringify(e),"utf8")}function jH(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||sI.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 LH({fetchImpl:e=fetch}={}){let t=await XE();if(!t)return{sent:0,disabled:!0};let n;try{n=(await or.readdir(Qr())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await uI(),o=0;for(let s of n){let a=wa.join(Qr(),s),i=r[s]||0,c;try{let d=await or.open(a,"r");try{let p=(await d.stat()).size;if(p<=i)continue;c=Buffer.alloc(p-i),await d.read(c,0,c.length,i)}finally{await d.close()}}catch{continue}let l=c.lastIndexOf(10);if(l<0)continue;let u=c.toString("utf8",0,l+1).split(`
696
+ `).filter(Boolean),f=[];for(let d of u)try{f.push(JSON.parse(d))}catch{}for(let d=0;d<f.length;d+=rI){let p=f.slice(d,d+rI).map(w=>jH(w)),h=await e(`${t.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${t.ingestKey}`},body:JSON.stringify({events:p})}).catch(()=>null);if(!h||!h.ok)return{sent:o,disabled:!1};o+=p.length}r[s]=i+l+1,await dI(r)}return{sent:o,disabled:!1}}var pg=null,mg=!1;function fI(){pg||(pg=setInterval(async()=>{if(!mg){mg=!0;try{await LH()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{mg=!1}}},PH),pg.unref?.())}import _d from"node:fs/promises";import gI from"node:path";import FH from"node:os";var yI=()=>process.env.BOSTRAT_STATE_DIR||gI.join(process.env.HOME||FH.tmpdir(),".bostrat"),bI=()=>gI.join(yI(),"dictation-glossary.json"),UH=100,HH=500,WH=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Id=null,hg=null,wg=Promise.resolve();function pI(){let e={},t=Date.now();for(let n of WH)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function kI(){return Id||(hg??=_d.readFile(bI(),"utf8").then(e=>JSON.parse(e)?.terms??pI()).catch(()=>pI()).then(e=>Id=e).finally(()=>hg=null),hg)}async function mI(){let e=JSON.stringify({terms:Id},null,2),t=bI(),n=`${t}.${process.pid}.tmp`;await _d.mkdir(yI(),{recursive:!0}),await _d.writeFile(n,e),await _d.rename(n,t)}function qH(){return wg=wg.then(mI,mI),wg.catch(()=>{})}async function gg(){return Object.values(await kI()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var KH=e=>Math.max(1,Math.ceil(e.length/4));async function GH(){let e=[],t=0;for(let{term:n}of await gg()){let r=KH(n);if(!(t+r>HH)&&(e.push(n),t+=r,e.length>=UH))break}return e}async function VH(e,t){let n=await kI(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var hI=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),Ad=e=>e.toLowerCase();function wI(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function xI(e,t){let n=hI(e),r=hI(t);if(!n.length||!r.length)return[];let o=n.length,s=r.length,a=Array.from({length:o+1},()=>new Array(s+1).fill(0));for(let u=o-1;u>=0;u--)for(let f=s-1;f>=0;f--)a[u][f]=Ad(n[u])===Ad(r[f])?a[u+1][f+1]+1:Math.max(a[u+1][f],a[u][f+1]);let i=new Set,c=0,l=0;for(;c<o&&l<s;)Ad(n[c])===Ad(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(wI(r[l])&&i.add(r[l]),l++);for(;l<s;l++)wI(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await VH(u,"learned");return await qH(),[...i]}var Ic=null;function zH(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 vI(){if(!Ic)return null;let e=await dc();if(!e||e.apiKey.slice(-6)!==Ic.keyTail)return null;let{keyTail:t,...n}=Ic;return n}async function SI(e,t){let n=await dc();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 GH())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=zH(o.status,i);c.persistent&&(Ic={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 Ic=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}he();var yg={"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 YH(e){if(!e)return null;let t=String(e).trim();if(yg[t])return t;let n=null;for(let r of Object.keys(yg))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function JH(e,t={}){let n=yg[YH(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 XH(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 $c=null;async function ZH(){if(!$c)return null;let e=await sd();if(!e||e.apiKey.slice(-6)!==$c.keyTail)return null;let{keyTail:t,...n}=$c;return n}async function QH(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=XH(t.status,o);s.persistent&&($c={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}$c=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 eW={openai:QH};async function TI(){let e=await sd();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await ZH()}:{configured:!1}}async function EI(){let e=await sd();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 eW[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function AI(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=JH(t,s),i=await $(e,{type:"cost.recorded",actor:"user",provider:"openai-realtime",payload:{model:t||"unknown",usd:a,tokens:{input:s.textIn+s.audioIn,output:s.textOut+s.audioOut,cacheRead:s.textInCached+s.audioInCached,cacheWrite:0},voice:s,seconds:Math.max(0,Math.round(Number(r)||0)),source:"voice-chat"}});return{usd:a,seq:i.seq}}Bn();var MI=ve.dirname(nW(import.meta.url)),_I=Number(process.env.PORT)||3362,Rd=pw(process.env),NI=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,ga=i_(process.env.BOSTRAT_ALLOW_IPS),Sg=c_(process.env.BOSTRAT_VIEW_FRONT_CIDRS,xd),PI=u_(),DI=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",v=Gt();v.disable("x-powered-by");v.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),kd(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});v.use((e,t,n)=>{if(Tc(e)||ga.allowed(ga.clientIp(e))||Sg.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});v.use(h_);v.use(p_({token:PI,enforce:DI}));v.use("/api/mocks",Gt.json({limit:"1mb"}));v.use("/api/mocks",Gt.raw({type:"image/png",limit:"24mb"}));v.use("/api/mocks",Gt.raw({type:["video/mp4","video/webm"],limit:"105mb"}));v.use("/api/runbooks",Gt.json({limit:"1mb"}));v.use("/api/tracks/adopt",Gt.json({limit:"1mb"}));v.use("/api/telemetry",Gt.json({limit:"256kb"}));v.use("/api/hook",Gt.json({limit:"2mb"}));v.use("/api/dictation",Gt.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));v.use("/api/tracks/:id/upload",Gt.raw({type:()=>!0,limit:"25mb"}));v.use(Gt.json({limit:"64kb"}));v.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:$t,hostTmuxAlive:await pr(),autoTriggerPct:NI,plane:ya?ya.status():null})});v.get("/api/sessions",async(e,t)=>{t.json({sessions:await zt()})});v.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 mr(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})}});v.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!Pe(n))return t.status(400).json({error:"invalid session name"});if(!await ye(n))return t.status(404).json({error:"session not found"});try{await Yt(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});v.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!Pe(n))return t.status(400).json({error:"invalid session name"});let r=await ye(n);if(!r)return t.status(404).json({error:"session not found"});let o=await Ga(r.cwd,r.sessionId);if(!o)return t.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});t.json({available:!0,...o})});v.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!Pe(n))return t.status(400).json({error:"invalid session name"});try{let r=await Fk(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)})}});v.get("/api/handoff/:name",(e,t)=>{let n=decodeURIComponent(e.params.name),r=Rl(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 II=10;v.get("/api/idle-guard",async(e,t)=>{try{t.json(fw({tracks:await ue(),views:await vu(),queuedOf:n=>Mo(n)}))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var Kt=Lo(),iW=LE({kind:Kt}),Rc=null,kt=()=>Rc&&["auto","prompt","off"].includes(Rc)?Rc:iW,vg=null,cW=lc.has(Kt),BI=async({to:e,from:t})=>!cW||Zu(await uc())?!1:(Oc.arm({to:e,from:t,kind:Kt}),!0);async function lW(e){let t=kt();Rc=e??null;let n=kt();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){Oc.cancel();return}vg&&await BI(vg)}}var jI=(()=>{try{return aW(import.meta.url)("../package.json").version||null}catch{return null}})(),Oc=UE({isBusy:async()=>fw({tracks:await ue(),views:await vu(),queuedOf:e=>Mo(e)}).busy,onStuck:({to:e,from:t})=>An({current:t,latest:e,installKind:Kt,policy:kt(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?An({current:t,latest:e,installKind:Kt,policy:kt(),status:"updating",reason:"auto"}):An({current:t,latest:e,installKind:Kt,policy:kt(),status:"failed",error:n?.reason})).catch(()=>{})});v.get("/api/node/self-update",async(e,t)=>{t.json({installKind:Kt,policy:kt(),policySource:Rc?"plane":"node",current:jI,status:await uc(),armed:Oc.armed})});v.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 Qu({to:n,kind:Kt,reason:"manual"});if(r.ok)return Oc.cancel(),An({current:r.from,latest:n,installKind:Kt,policy:kt(),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 LI(){try{let e=await FE();e&&await An({current:e.from,latest:e.to,installKind:e.kind||Kt,policy:kt(),status:e.status,error:e.error,reason:e.reason}),await Oh({current:jI,installKind:Kt,policy:kt()})}catch{}}LI();setInterval(LI,3e4).unref();v.get("/api/tracks",async(e,t)=>{let n=(await ue()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>II){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,II).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:Zi,agentAvailability:await Pu(),tickets:await dA()})});v.get("/api/cost",async(e,t)=>{try{let n=await ue();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await zw(n);if(r.cursorUsage=Em(),e.query.format==="text")return t.type("text/plain").send(FA(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/usage/roundup",async(e,t)=>{try{t.json(await HA(await ue(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/usage/spend",async(e,t)=>{try{let n=await VA(await ue(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=Em(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=pi(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/usage/caps",(e,t)=>{t.json(pi())});v.post("/api/usage/caps",async(e,t)=>{try{t.json(await Ul(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});v.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await n_(await ue(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await Bg(e.get(Rn),{byToken:ec,legacy:()=>$i(e.body?.session_id,e.body?.cwd)});if(n==="refused")return Ta("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Ta("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&&Ta("mismatch",{track:r.track.id,box:r.box.name}),Ta(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 MA(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&Jc(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});v.get("/api/git/trailers",async(e,t)=>{t.type("text/plain");try{let n=await ec(e.get(Rn));if(!n?.track||!n?.box)return t.status(204).end();t.send((await PA(n.track,n.box)).join(`
697
697
  `)+`
698
- `)}catch{t.status(204).end()}});v.post("/api/git/committed",async(e,t)=>{try{let n=await Qi(e.get(Rn));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?xe.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?xe.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+xe.sep))?s:o;MA(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)})}});v.post("/api/tracks/:id/rework-cause",async(e,t)=>{try{let n=await te(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 NA(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})}});v.get("/api/usage/rework",async(e,t)=>{try{t.json(await GA(await le(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/telemetry",async(e,t)=>{try{if(!iI(wa.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await aI(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});v.get("/api/repos",async(e,t)=>{try{let n=await On(),r=new Set((await Promise.all(n.map(a=>Se(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await _a()).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)})}});v.get("/api/github/token",async(e,t)=>{try{t.json(await Lc(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});v.get("/api/github/status",(e,t)=>{t.json({configured:jc(),calls:Gx(),latency:Jx()})});v.post("/api/github/refresh",(e,t)=>{Gg(),t.json({ok:!0})});v.get("/api/gmail/search",async(e,t)=>{try{let n=await n_(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)})}});v.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await r_(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});function Sg(e,t,n){let r=e.workspace;return r?.kind==="multi"?(r.repos??[]).some(o=>t&&o?.base===t||n&&o?.repo===n):!r?.base||!t||r.base===t||n&&r.repo===n}async function $d({repo:e=null,number:t=null,branch:n=null}){let r=e?await Se(e):null;if(r&&t!=null){let s=await tt(r,t),a=s&&await te(s.trackId);if(a)return a}if(!n)return null;let o=await le();return au(o,n,s=>Sg(s,e,r))}async function jI({repo:e=null,number:t=null,branch:n=null}){let r=await $d({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!Ve(r))return r;if(!n)return null;let o=e?await Se(e).catch(()=>null):null,s=await le();return au(s,n,a=>!Ve(a)&&Sg(a,e,o))}async function cn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await $d({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await Se(s).catch(()=>null):null);await $({id:c.id,cwd:c.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),change:e,number:t,url:n,title:r,branch:o??c.workspace?.branch??null,...l?{repo:l}:{},...i}}).catch(()=>{})}async function aW(e){let t=(await le()).filter(n=>!Ve(n));for(let n of e??[]){if(!n.prs?.length)continue;let r=await Se(n.path);if(r)for(let o of n.prs){if(await tt(r,o.number))continue;let s=await au(t,o.headRefName,a=>Sg(a,n.path,r));s&&await Ot({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}v.get("/api/git/prs",async(e,t)=>{try{let n=await rv();await aW(n.repos).catch(()=>{}),await V_(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/git/prs/merge",async(e,t)=>{let{repo:n,number:r,method:o,auto:s,update:a,archive:i,notify:c,headRefName:l,title:u,url:f}=e.body||{};try{if(s){let w=o||"merge";if(!bi.has(w))throw new Error(`invalid merge method: ${w}`);let g=Number(r);if(!Number.isInteger(g)||g<=0)throw new Error("invalid PR number");let k=await Se((await Wn(n)).path);if(!k)throw new Error("repo has no GitHub remote");let S=await $d({repo:n,number:g,branch:l}).catch(()=>null);if(!S)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(a&&await ki(n,g),await Ot({repo:k,number:g,trackId:S.id,url:f,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await mi(k,g,{merge:{method:w}}))throw new Error("couldn't record the auto-merge arm");return await ko(k,g,i===!0),await hi(k,g,c===!0&&i!==!0),gn(),await cn("auto-armed",{number:g,url:f,title:u,branch:l,repo:n,track:S,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:g,auto:!0})}let d=await Ds(n,r,{method:o||"squash"});await cn("merged",{number:d.number,url:f,title:u,branch:l,repo:n});let p=await Se(n).catch(()=>null),h=!1;if(p&&(i===!0&&await ko(p,d.number,!0).catch(()=>{}),c===!0&&i!==!0&&await hi(p,d.number,!0).catch(()=>{}),await Kn(p,d.number).catch(()=>{}),await Bo(p,d.number).catch(()=>{}),h=await qn(p,d.number).catch(()=>!1),await Ir(p,d.number,"merged").catch(()=>{})),i===!0&&!h){let w=await $d({repo:n,number:d.number,branch:l}).catch(()=>null);w&&!w.archivedAt&&await Do(w.id).catch(()=>{})}t.json(d)}catch(d){let p=d?.message||String(d),h=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(p)?400:502;t.status(h).json({error:p})}});v.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 Se((await Wn(n)).path).catch(()=>null),l=c?await wi(c,i).catch(()=>null):null;try{await tm(n,i)}catch(u){if(!l)throw u}gn(),await cn("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})}});v.post("/api/git/prs/merge-all",async(e,t)=>{let{repo:n,method:r}=e.body||{};try{let o=await Se(n).catch(()=>null),s=await cv(n,{method:r||"merge",onMerged:a=>{cn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&Kn(o,a.number).catch(()=>{}).then(()=>Bo(o,a.number)).catch(()=>{}).then(()=>qn(o,a.number)).catch(()=>{}).then(()=>Ir(o,a.number,"merged")).catch(()=>{})}});t.json(s)}catch(o){let s=o?.message||String(o),a=/already running/i.test(s)?409:/invalid|unknown repo|no PRs ready/i.test(s)?400:502;t.status(a).json({error:s})}});v.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:iv()})});v.post("/api/git/prs/merge-track",async(e,t)=>{let{trackId:n,update:r,archive:o,notify:s,method:a}=e.body||{};try{let i=a||"merge";if(!bi.has(i))throw new Error(`invalid merge method: ${i}`);if(!n)return t.status(400).json({error:"trackId required"});let c=await te(n);if(!c)return t.status(404).json({error:`Track ${n} isn't on this node`});let l=(await xo()).filter(d=>d.trackId===c.id&&d.state!=="merged"&&d.state!=="closed").sort(xi);if(!l.length)return t.status(409).json({error:"no open PRs on this Track"});for(let d of l)await ko(d.repo,d.number,o===!0).catch(()=>{}),await hi(d.repo,d.number,s===!0&&o!==!0).catch(()=>{});let u=[],f=[];for(let d of l){let p={repo:d.repo,number:d.number,ok:!0,action:"armed"};u.push(p);try{let h=await So(d.repo);if(!h)throw new Error(`no local checkout for ${d.repo}`);let w=await Ps(h,d.number);f.push({r:p,l:d,repoPath:h,pr:w,plan:ov(w,{update:r!==!1})})}catch(h){p.ok=!1,p.action="failed",p.reason=h?.message||String(h)}}for(let{r:d,l:p,repoPath:h,pr:w,plan:g}of sv(f))try{if(g.action==="skip")d.action="skipped",d.reason=g.reason;else if(g.action==="merge")await Ds(h,p.number,{method:i}),await cn("merged",{number:p.number,url:w.url,title:w.title,branch:w.headRefName,repo:h,track:c}),await Kn(p.repo,p.number).catch(()=>{}),await Bo(p.repo,p.number).catch(()=>{}),await qn(p.repo,p.number).catch(()=>{}),await Ir(p.repo,p.number,"merged").catch(()=>{}),d.action="merged";else{if(g.action==="update-arm"&&(await ki(h,p.number).catch(()=>{}),d.action="updated-armed"),!await mi(p.repo,p.number,{merge:{method:i}}))throw new Error("couldn't record the auto-merge arm");await cn("auto-armed",{number:p.number,url:w.url,title:w.title,branch:w.headRefName,repo:h,track:c,...d.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(k){d.ok=!1,d.action="failed",d.reason=k?.message||String(k)}if(gn(),!u.some(d=>d.ok)){if(o===!0)for(let d of l)await ko(d.repo,d.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let d of l)await hi(d.repo,d.number,!1).catch(()=>{});return t.status(502).json({error:u.map(d=>`${d.repo}#${d.number}: ${d.reason}`).join("; "),results:u})}t.json({ok:!0,trackId:c.id,results:u})}catch(i){let c=i?.message||String(i),l=/invalid|required/i.test(c)?400:502;t.status(l).json({error:c})}});v.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 te(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await xo()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await wi(a.repo,a.number).catch(()=>null),c=await So(a.repo).catch(()=>null);c&&await tm(c,a.number).catch(()=>{}),i&&(await cn("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}))}gn(),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})}});v.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 te(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=Dt(i.workspace),f,d=Array.isArray(a)?a.filter(Boolean):[];if(d.length)f=d.map(w=>{let g=u.find(k=>k.name===w||k.repo===w||k.base===w||k.dir===w);if(!g)throw new Error(`invalid repo "${w}" \u2014 not tagged on this Track`);return g});else if(f=await _o(i),!f.length)return t.status(409).json({error:"no tagged repo has work to ship"});let p=[];for(let w of f)try{let g=await rm(w.dir,{title:r,body:o,base:s}),k=w.repo||await Se(w.dir).catch(()=>null);k&&g.number&&await Ot({repo:k,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await cn("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:k??w.name}}),p.push({repo:w.name,slug:k??null,ok:!0,url:g.url,number:g.number})}catch(g){p.push({repo:w.name,slug:w.repo??null,ok:!1,error:g?.message||String(g)})}let h=p.filter(w=>w.ok);return h.length?t.json({ok:!0,multi:!0,results:p,url:h[0].url,number:h[0].number}):t.status(502).json({error:p.map(w=>`${w.repo}: ${w.error}`).join("; "),results:p})}let c=await rm(i.cwd,{title:r,body:o,base:s}),l=await Se(i.cwd).catch(()=>null);l&&c.number&&await Ot({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await cn("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})}});v.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await te(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await _o(n),o=new Map(r.map(a=>[a.base,a])),s=Dt(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)})}});v.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 Uh(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})}});v.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await Hh(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})}});v.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Ps(n,r),s=await Se(n).catch(()=>null),a=await jI({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=Dt(a.workspace).find(k=>k.base===n||s&&k.repo===s)??null,c=a.workspace?.kind==="multi",l=await lv(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?xe.join("ci",i.name):"ci",f=xe.join(a.cwd,".bostrat",u),d=xe.join(".bostrat",u,`pr-${o.number}-fail.log`);await mt.promises.mkdir(f,{recursive:!0}),await mt.promises.writeFile(xe.join(a.cwd,d),l.map(k=>`\u2550\u2550\u2550\u2550 ${k.name}${k.link?` \xB7 ${k.link}`:""} \u2550\u2550\u2550\u2550
699
- ${k.log??"(no fetchable log \u2014 see link)"}
698
+ `)}catch{t.status(204).end()}});v.post("/api/git/committed",async(e,t)=>{try{let n=await ec(e.get(Rn));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?ve.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?ve.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+ve.sep))?s:o;DA(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)})}});v.post("/api/tracks/:id/rework-cause",async(e,t)=>{try{let n=await re(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 BA(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})}});v.get("/api/usage/rework",async(e,t)=>{try{t.json(await zA(await ue(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/telemetry",async(e,t)=>{try{if(!lI(ga.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await cI(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});v.get("/api/repos",async(e,t)=>{try{let n=await On(),r=new Set((await Promise.all(n.map(a=>Se(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await Ia()).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)})}});v.get("/api/github/token",async(e,t)=>{try{t.json(await Uc(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});v.get("/api/github/status",(e,t)=>{t.json({configured:Fc(),calls:Yx(),latency:Qx()})});v.post("/api/github/refresh",(e,t)=>{Vg(),t.json({ok:!0})});v.get("/api/gmail/search",async(e,t)=>{try{let n=await o_(String(e.query.q||""),{max:Number(e.query.max)||10});t.json({messages:n})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});v.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await s_(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});function Tg(e,t,n){let r=e.workspace;return r?.kind==="multi"?(r.repos??[]).some(o=>t&&o?.base===t||n&&o?.repo===n):!r?.base||!t||r.base===t||n&&r.repo===n}async function Od({repo:e=null,number:t=null,branch:n=null}){let r=e?await Se(e):null;if(r&&t!=null){let s=await tt(r,t),a=s&&await re(s.trackId);if(a)return a}if(!n)return null;let o=await ue();return cu(o,n,s=>Tg(s,e,r))}async function FI({repo:e=null,number:t=null,branch:n=null}){let r=await Od({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!Ve(r))return r;if(!n)return null;let o=e?await Se(e).catch(()=>null):null,s=await ue();return cu(s,n,a=>!Ve(a)&&Tg(a,e,o))}async function cn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await Od({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await Se(s).catch(()=>null):null);await $({id:c.id,cwd:c.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),change:e,number:t,url:n,title:r,branch:o??c.workspace?.branch??null,...l?{repo:l}:{},...i}}).catch(()=>{})}async function uW(e){let t=(await ue()).filter(n=>!Ve(n));for(let n of e??[]){if(!n.prs?.length)continue;let r=await Se(n.path);if(r)for(let o of n.prs){if(await tt(r,o.number))continue;let s=await cu(t,o.headRefName,a=>Tg(a,n.path,r));s&&await Ot({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}v.get("/api/git/prs",async(e,t)=>{try{let n=await av();await uW(n.repos).catch(()=>{}),await Y_(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/git/prs/merge",async(e,t)=>{let{repo:n,number:r,method:o,auto:s,update:a,archive:i,notify:c,headRefName:l,title:u,url:f}=e.body||{};try{if(s){let w=o||"merge";if(!ki.has(w))throw new Error(`invalid merge method: ${w}`);let g=Number(r);if(!Number.isInteger(g)||g<=0)throw new Error("invalid PR number");let b=await Se((await Wn(n)).path);if(!b)throw new Error("repo has no GitHub remote");let E=await Od({repo:n,number:g,branch:l}).catch(()=>null);if(!E)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(a&&await xi(n,g),await Ot({repo:b,number:g,trackId:E.id,url:f,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await hi(b,g,{merge:{method:w}}))throw new Error("couldn't record the auto-merge arm");return await ko(b,g,i===!0),await wi(b,g,c===!0&&i!==!0),gn(),await cn("auto-armed",{number:g,url:f,title:u,branch:l,repo:n,track:E,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:g,auto:!0})}let d=await Bs(n,r,{method:o||"squash"});await cn("merged",{number:d.number,url:f,title:u,branch:l,repo:n});let p=await Se(n).catch(()=>null),h=!1;if(p&&(i===!0&&await ko(p,d.number,!0).catch(()=>{}),c===!0&&i!==!0&&await wi(p,d.number,!0).catch(()=>{}),await Kn(p,d.number).catch(()=>{}),await Bo(p,d.number).catch(()=>{}),h=await qn(p,d.number).catch(()=>!1),await $r(p,d.number,"merged").catch(()=>{})),i===!0&&!h){let w=await Od({repo:n,number:d.number,branch:l}).catch(()=>null);w&&!w.archivedAt&&await Do(w.id).catch(()=>{})}t.json(d)}catch(d){let p=d?.message||String(d),h=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(p)?400:502;t.status(h).json({error:p})}});v.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 Se((await Wn(n)).path).catch(()=>null),l=c?await gi(c,i).catch(()=>null):null;try{await nm(n,i)}catch(u){if(!l)throw u}gn(),await cn("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})}});v.post("/api/git/prs/merge-all",async(e,t)=>{let{repo:n,method:r}=e.body||{};try{let o=await Se(n).catch(()=>null),s=await dv(n,{method:r||"merge",onMerged:a=>{cn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&Kn(o,a.number).catch(()=>{}).then(()=>Bo(o,a.number)).catch(()=>{}).then(()=>qn(o,a.number)).catch(()=>{}).then(()=>$r(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})}});v.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:uv()})});v.post("/api/git/prs/merge-track",async(e,t)=>{let{trackId:n,update:r,archive:o,notify:s,method:a}=e.body||{};try{let i=a||"merge";if(!ki.has(i))throw new Error(`invalid merge method: ${i}`);if(!n)return t.status(400).json({error:"trackId required"});let c=await re(n);if(!c)return t.status(404).json({error:`Track ${n} isn't on this node`});let l=(await xo()).filter(d=>d.trackId===c.id&&d.state!=="merged"&&d.state!=="closed").sort(vi);if(!l.length)return t.status(409).json({error:"no open PRs on this Track"});for(let d of l)await ko(d.repo,d.number,o===!0).catch(()=>{}),await wi(d.repo,d.number,s===!0&&o!==!0).catch(()=>{});let u=[],f=[];for(let d of l){let p={repo:d.repo,number:d.number,ok:!0,action:"armed"};u.push(p);try{let h=await So(d.repo);if(!h)throw new Error(`no local checkout for ${d.repo}`);let w=await Ds(h,d.number);f.push({r:p,l:d,repoPath:h,pr:w,plan:iv(w,{update:r!==!1})})}catch(h){p.ok=!1,p.action="failed",p.reason=h?.message||String(h)}}for(let{r:d,l:p,repoPath:h,pr:w,plan:g}of cv(f))try{if(g.action==="skip")d.action="skipped",d.reason=g.reason;else if(g.action==="merge")await Bs(h,p.number,{method:i}),await cn("merged",{number:p.number,url:w.url,title:w.title,branch:w.headRefName,repo:h,track:c}),await Kn(p.repo,p.number).catch(()=>{}),await Bo(p.repo,p.number).catch(()=>{}),await qn(p.repo,p.number).catch(()=>{}),await $r(p.repo,p.number,"merged").catch(()=>{}),d.action="merged";else{if(g.action==="update-arm"&&(await xi(h,p.number).catch(()=>{}),d.action="updated-armed"),!await hi(p.repo,p.number,{merge:{method:i}}))throw new Error("couldn't record the auto-merge arm");await cn("auto-armed",{number:p.number,url:w.url,title:w.title,branch:w.headRefName,repo:h,track:c,...d.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(b){d.ok=!1,d.action="failed",d.reason=b?.message||String(b)}if(gn(),!u.some(d=>d.ok)){if(o===!0)for(let d of l)await ko(d.repo,d.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let d of l)await wi(d.repo,d.number,!1).catch(()=>{});return t.status(502).json({error:u.map(d=>`${d.repo}#${d.number}: ${d.reason}`).join("; "),results:u})}t.json({ok:!0,trackId:c.id,results:u})}catch(i){let c=i?.message||String(i),l=/invalid|required/i.test(c)?400:502;t.status(l).json({error:c})}});v.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 re(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await xo()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await gi(a.repo,a.number).catch(()=>null),c=await So(a.repo).catch(()=>null);c&&await nm(c,a.number).catch(()=>{}),i&&(await cn("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}))}gn(),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})}});v.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 re(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=Dt(i.workspace),f,d=Array.isArray(a)?a.filter(Boolean):[];if(d.length)f=d.map(w=>{let g=u.find(b=>b.name===w||b.repo===w||b.base===w||b.dir===w);if(!g)throw new Error(`invalid repo "${w}" \u2014 not tagged on this Track`);return g});else if(f=await _o(i),!f.length)return t.status(409).json({error:"no tagged repo has work to ship"});let p=[];for(let w of f)try{let g=await om(w.dir,{title:r,body:o,base:s}),b=w.repo||await Se(w.dir).catch(()=>null);b&&g.number&&await Ot({repo:b,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await cn("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:b??w.name}}),p.push({repo:w.name,slug:b??null,ok:!0,url:g.url,number:g.number})}catch(g){p.push({repo:w.name,slug:w.repo??null,ok:!1,error:g?.message||String(g)})}let h=p.filter(w=>w.ok);return h.length?t.json({ok:!0,multi:!0,results:p,url:h[0].url,number:h[0].number}):t.status(502).json({error:p.map(w=>`${w.repo}: ${w.error}`).join("; "),results:p})}let c=await om(i.cwd,{title:r,body:o,base:s}),l=await Se(i.cwd).catch(()=>null);l&&c.number&&await Ot({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await cn("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})}});v.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await re(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await _o(n),o=new Map(r.map(a=>[a.base,a])),s=Dt(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)})}});v.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 Hh(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})}});v.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await Wh(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})}});v.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Ds(n,r),s=await Se(n).catch(()=>null),a=await FI({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=Dt(a.workspace).find(b=>b.base===n||s&&b.repo===s)??null,c=a.workspace?.kind==="multi",l=await fv(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?ve.join("ci",i.name):"ci",f=ve.join(a.cwd,".bostrat",u),d=ve.join(".bostrat",u,`pr-${o.number}-fail.log`);await mt.promises.mkdir(f,{recursive:!0}),await mt.promises.writeFile(ve.join(a.cwd,d),l.map(b=>`\u2550\u2550\u2550\u2550 ${b.name}${b.link?` \xB7 ${b.link}`:""} \u2550\u2550\u2550\u2550
699
+ ${b.log??"(no fetchable log \u2014 see link)"}
700
700
  `).join(`
701
- `));let p=l.map(k=>k.name).join(", "),h=c&&i?` in the ${i.name}/ checkout`:"",w=await Pt(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${h}. Failing check${l.length===1?"":"s"}: ${p}. The failure log is at ${d} in this ${c?"workspace":"worktree"} \u2014 read it, fix the root cause${c&&i?` in ${i.name}/`:""}, run the relevant tests locally, then commit and push to update the PR.`,{kind:"ci-fix"}),g=s;g&&(await Ot({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await Ix(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await cn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(k=>k.name)}}),t.json({ok:!0,leadBox:w.leadBox,queued:!!w.queued,checks:l.map(k=>k.name),log:d})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});v.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Ps(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await Se(n).catch(()=>null),a=await jI({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=Dt(a.workspace).find(f=>f.base===n||s&&f.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await Pt(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 Ot({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await $x(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await cn("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})}});v.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=Ar.filter(f=>e.body.actions.includes(f)),!o.length)return t.status(400).json({error:"actions must include commit, rebase, push and/or pr"})}else if(r==="pr")o=["commit","push","pr"];else if(r==="push")o=["commit","push"];else if(r!=="dismiss")return t.status(400).json({error:'offerId and actions ["commit"|"rebase"|"push"|"pr"] (or action "dismiss") required'});if(!n)return t.status(400).json({error:"offerId required"});let s=o!=null&&e.body?.notify===!0,a=await te(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await F(a),c=i.find(f=>f.type==="pr.offered"&&f.payload?.offerId===n);if(!c)return t.status(404).json({error:"unknown offer"});if(i.some(f=>f.type==="pr.offer.answered"&&f.payload?.offerId===n))return t.status(409).json({error:"offer already answered"});if(o?.includes("pr")){let f=await lg(a,c,{actions:o,notify:s});if(f)return t.json({ok:!0,offerId:n,action:"pr-exists",actions:o,notify:s,existingPr:f.pr})}let l=null;o&&(l=await Pt(a.id,Os(o,{branch:c.payload.branch,base:c.payload.base,toPr:c.payload.toPr||null,repos:c.payload.repos||null,offeredRebase:Array.isArray(c.payload.offered)&&c.payload.offered.includes("rebase")}),{kind:o.includes("pr")?"pr-go":"push-go"}));let u=o?o.includes("pr")?"pr":o.includes("push")?"push":o.includes("commit")?"commit":"rebase":"dismiss";await $({id:a.id,cwd:a.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:c.boxId,payload:{ts:Date.now(),offerId:n,action:u,actions:o,...s?{notify:!0}:{}}}),s&&Dh(a.id,{actions:o}),t.json({ok:!0,offerId:n,action:u,actions:o,notify:s,queued:!!l?.queued})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});v.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await te(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await ug(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 Rc=e=>t=>({...t,url:h_(t,e.headers)});v.get("/api/views",async(e,t)=>{try{let n=await ku({trackId:e.query.track||void 0});t.json({views:n.map(Rc(e)),maxLive:Br})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/views/:id",async(e,t)=>{let n=await $S(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:Rc(e)(n),session:Hs(n.slug)})});v.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await te(n):null;if(!i&&s&&(i=(await le()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+xe.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await Hm({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:Rc(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})}});v.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:Rc(e)(await RS(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});v.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:Rc(e)(await OS(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})}});v.delete("/api/views/:id",async(e,t)=>{try{t.json(await CS(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var iW=[["linear",Fo,Sw],["jira",nd,xw]],yg=new Map;v.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await kw(),r={};for(let[o,s,a]of iW){let i=await s();if(!i){yg.delete(o),r[o]={configured:!1};continue}let c=yg.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},yg.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)})}});v.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await kw()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await VE(o),i=n?await te(n):null;!i&&r&&(i=(await le()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+xe.sep)))||null),i&&await $({id:i.id,cwd:i.cwd},{type:"ticket.flow.changed",actor:s==="user"?"user":"agent",source:"orchestrator",payload:{ts:Date.now(),set:{...o},flow:a}}).catch(()=>{}),t.json({ok:!0,flow:a})}catch(a){let i=a?.message||String(a);t.status(/unknown|nothing to set/i.test(i)?400:500).json({error:i})}});var Vo=async(e,t)=>{let n=e?await te(e):null;return!n&&t&&(n=(await le()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+xe.sep)))||null),n};v.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await hw()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});v.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await Vo(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 oa(o);await Zu(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})}});v.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await Vo(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await Zu(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var LI=async(e,t,n)=>{if(e)return{ref:e,track:await Vo(t,n)};let r=await Vo(t,n),o=r?await gw(r.id):null;if(!o)throw new Error(r?"this Track isn't in a circuit \u2014 pass --circuit <name-or-id> (or link one first: bostrat-circuit link \u2026)":"run from inside a Track workspace, or pass --circuit <name-or-id>");return{ref:o,track:r}};v.post("/api/blueprints/publish",async(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 LI(o,n,r),l=await LE({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})}});v.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await LI(e.query.circuit,e.query.track,e.query.cwd);t.json(await ww(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})}});v.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 Vo(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let f=await HE(u,{title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l});t.json({ok:!0,trackId:u.id,...f})}catch(u){let f=u?.message||String(u);t.status(/required/i.test(f)?400:502).json({error:f})}});v.get("/api/decisions",async(e,t)=>{try{let n=await Vo(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await WE(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})}});v.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 Vo(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await gw(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 FE(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})}});v.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await te(n):null;if(!s&&r&&(s=(await le()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+xe.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})}});v.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await te(r):null;if(!o&&n&&(o=(await le()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+xe.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 lA(),ticket:await In(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});v.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await In(e.params.id)})});v.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await te(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})}});v.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await Pw(e.params.id)})});var Rd=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;v.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await pA(e.params.id))}catch(n){let r=n?.message||String(n);t.status(Rd(r)).json({error:r})}});v.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await Dw(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(Rd(r)).json({error:r})}});v.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await mA(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(Rd(r)).json({error:r})}});v.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await te(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await hA(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(Rd(s)).json({error:s})}});v.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{t.json(await Zh(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})}});v.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await te(n):null;if(!s&&r&&(s=(await le()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+xe.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 gA(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})}});v.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await wA()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});v.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await te(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await yA(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})}});v.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await Bi({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/mocks/:id",async(e,t)=>{let n=await Yn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var Oc={dotfiles:"allow"};v.get("/api/mocks/:id/png",async(e,t)=>{let n=await Yn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=tn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Pi(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,Oc,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});v.get("/api/mocks/:id/media",async(e,t)=>{let n=await Yn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=tn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Pi(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,Oc,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});v.get("/api/mocks/:id/html",async(e,t)=>{let n=await Yn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=tn(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(Wt(n,r.v).html,Oc,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});v.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Tu(n)?n:null,o=n&&!r?n:null,s=n?e.query:e.body||{},{trackId:a,name:i,cwd:c,width:l,group:u}=s;try{let f=a?await te(a):null;if(!f&&c&&(f=(await le()).find(w=>w.cwd&&(c===w.cwd||c.startsWith(w.cwd+xe.sep)))||null),!f)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=(f.boxes||[]).find(h=>h.name===f.leadBox),p=await YS({trackId:f.id,name:i,html:n?null:s.html,image:r,video:o,cwd:f.cwd,width:l,group:u,box:f.leadBox,agent:d?.agent||null});t.json({ok:!0,mock:p})}catch(f){let d=f?.message||String(f);t.status(/required|invalid|must be/i.test(d)?400:500).json({error:d})}});v.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Tu(n)?n:null;try{let o=await JS(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})}});v.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await QS(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await Pt(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})}});v.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await gT(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await eT(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})}});v.get("/api/flows",async(e,t)=>{try{t.json({flows:await fT({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/flows/:id",async(e,t)=>{let n=await pT(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});v.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await te(n):null;if(!a&&s&&(a=(await le()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+xe.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 mT({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})}});v.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await hT(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})}});v.delete("/api/flows/:id",async(e,t)=>{try{t.json(await wT(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});v.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await le(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+xe.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await ET({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)})}});v.get("/api/runbooks/:id",async(e,t)=>{let n=await nh(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});v.get("/api/runbooks/:id/md",async(e,t)=>{let n=await nh(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=ST(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 AT(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(Qn(n,r.v),Oc,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});v.get("/api/loops",async(e,t)=>{t.json(await Ti())});v.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 le()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+xe.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await Ti();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 fm({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})});v.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await te(n):null;if(!s&&r&&(s=(await le()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+xe.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 v_(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var Tg=async(e,t)=>{let n=e?await te(e):null;return!n&&t&&(n=(await le()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+xe.sep)))||null),n};v.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Tg(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 Uv(s,o,{ship:{changedRepos:_o}})})}catch(s){t.status(400).json({error:s?.message||String(s)})}});v.post("/api/followups/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Tg(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 Wv(s,o)})}catch(s){let a=s?.message||String(s);t.status(/unreachable/i.test(a)?503:400).json({error:a})}});v.get("/api/followups",async(e,t)=>{let n=typeof e.query?.cwd=="string"?e.query.cwd:null,r=await Tg(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:gm,...await zv(r)})});v.post("/api/tracks/:id/followup-offer",async(e,t)=>{let{offerId:n,followupId:r,armId:o,promoted:s}=e.body||{};try{let a=await te(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await Kv(a,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null},{sayToLead:Pt,unarchiveTrack:Fu})})}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})}});v.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await te(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await Hv(n,e.body?.armId)})}catch(n){let r=n?.message||String(n);t.status(/unknown/i.test(r)?404:400).json({error:r})}});v.post("/api/tracks/:id/followup-create-offer",async(e,t)=>{let{proposalId:n,accept:r,followupId:o}=e.body||{};try{let s=await te(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await qv(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})}});ct.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"||te(e.trackId).then(async s=>{if(s&&(n&&await Ai(s,n,o),t==="opened"||t==="pushed")){let a=Vv(await F(s).catch(()=>[]));a&&await Ai(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var FI=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await te(n):null;if(!s&&r&&(s=(await le()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+xe.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await Ti();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=E_(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}};v.post("/api/loops/propose-update",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await FI(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await A_(s.track,s.loop,e.body?.patch)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});v.post("/api/loops/propose-delete",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await FI(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await __(s.track,s.loop,e.body?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});var UI=e=>/unknown proposal/i.test(e)?404:/already answered/i.test(e)?409:400;v.post("/api/tracks/:id/loop-update-offer",async(e,t)=>{let{proposalId:n,action:r,nextFireAt:o}=e.body||{};try{let s=await te(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await $_(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(UI(a)).json({error:a})}});v.post("/api/tracks/:id/loop-delete-offer",async(e,t)=>{let{proposalId:n,action:r}=e.body||{};try{let o=await te(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await R_(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(UI(s)).json({error:s})}});v.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 te(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await S_(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})}});v.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await te(n):null;if(!a&&s&&(a=(await le()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+xe.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 _T({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})}});v.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await IT(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})}});v.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await $T(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})}});v.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await RT(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});v.get("/api/changelog/draft",async(e,t)=>{try{let n=P_(e.query.since||null);t.json({since:n,repos:rg(),...await D_(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var HI=async({trackId:e,cwd:t})=>{let n=e?await te(e):null;return!n&&t&&(n=(await le()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+xe.sep)))||null),n};v.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await HI({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 B_(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})}});v.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await HI({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 j_(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var cW=120,bg=400,ga=null,_I=null;v.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>bg)return t.status(400).json({error:`message is ${i.length} chars \u2014 over the ${bg} cap; a notification is a nudge, put the detail in chat`});let c=ji(`${n||""}
702
- ${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 te(a):null;if(!l&&s&&(l=(await le()).find(h=>h.cwd&&(s===h.cwd||s.startsWith(h.cwd+xe.sep)))||null),!l)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=(l.boxes||[]).find(p=>p.name===l.leadBox),f=(p,h)=>String(p).replace(/\s+/g," ").trim().slice(0,h),d={title:n?f(n,cW):l.name,body:f(i,bg),urgency:o==="high"?"high":"normal",trackName:l.name,ts:Date.now()};await $(l,{type:"notify.raised",actor:"agent",boxId:l.leadBox??null,provider:u?.agent||null,payload:d}),t.json({ok:!0,notification:d,delivered:ga?ga.status().connected:null})}catch(i){t.status(500).json({error:i?.message||String(i)})}});v.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 xI(e.body,e.headers["content-type"]))}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});v.get("/api/dictation/glossary",async(e,t)=>{t.json({configured:!!await uc(),terms:await wg(),problem:await kI()})});v.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 bI(n,r)})});v.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await te(e.params.id))return t.status(404).json({error:"track not found"});t.json(await vI())});v.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await te(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 SI())}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});v.post("/api/tracks/:id/voice-chat/usage",async(e,t)=>{try{let n=await te(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 TI(n,{model:r,usage:o,seconds:s})})}catch(n){t.status(n?.status||500).json({error:n?.message||String(n)})}});v.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 ju({name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i!==!1}),f=null;if(c)try{await ia(u,c,{source:"create"})}catch(p){f=p?.message||String(p)}let d=null;if(l)try{await Zu(u,await oa(l),{source:"picker"})}catch(p){d=p?.message||String(p)}t.json({ok:!0,track:u,...f?{ticketWarning:f}:{},...d?{circuitWarning:d}:{}})}catch(u){let f=u?.message||String(u);t.status(/required|unknown agent|invalid|must be/i.test(f)?400:500).json({error:f})}});v.get("/api/tracks/:id",async(e,t)=>{let n=await te(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:WI(ra(e.params.id)),subtasks:jo(e.params.id).map(Cc),pendingOffers:await Oh(n)})});v.delete("/api/tracks/:id",async(e,t)=>{try{let n=await Gh(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await Pw(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})}});v.post("/api/tracks/:id/archive",async(e,t)=>{try{t.json({ok:!0,track:await Do(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})}});v.post("/api/tracks/:id/rename",async(e,t)=>{try{t.json({ok:!0,track:await Yh(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})}});v.post("/api/tracks/:id/unarchive",async(e,t)=>{try{t.json({ok:!0,track:await Fu(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})}});v.get("/api/tracks/:id/messages",async(e,t)=>{let n=await Nu(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json(n)});v.get("/api/tracks/:id/events",async(e,t)=>{let n=await te(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}
701
+ `));let p=l.map(b=>b.name).join(", "),h=c&&i?` in the ${i.name}/ checkout`:"",w=await Pt(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${h}. Failing check${l.length===1?"":"s"}: ${p}. The failure log is at ${d} in this ${c?"workspace":"worktree"} \u2014 read it, fix the root cause${c&&i?` in ${i.name}/`:""}, run the relevant tests locally, then commit and push to update the PR.`,{kind:"ci-fix"}),g=s;g&&(await Ot({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await Ox(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await cn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(b=>b.name)}}),t.json({ok:!0,leadBox:w.leadBox,queued:!!w.queued,checks:l.map(b=>b.name),log:d})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});v.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Ds(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await Se(n).catch(()=>null),a=await FI({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=Dt(a.workspace).find(f=>f.base===n||s&&f.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await Pt(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 Ot({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await Cx(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await cn("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})}});v.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=_r.filter(f=>e.body.actions.includes(f)),!o.length)return t.status(400).json({error:"actions must include commit, rebase, push and/or pr"})}else if(r==="pr")o=["commit","push","pr"];else if(r==="push")o=["commit","push"];else if(r!=="dismiss")return t.status(400).json({error:'offerId and actions ["commit"|"rebase"|"push"|"pr"] (or action "dismiss") required'});if(!n)return t.status(400).json({error:"offerId required"});let s=o!=null&&e.body?.notify===!0,a=await re(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await U(a),c=i.find(f=>f.type==="pr.offered"&&f.payload?.offerId===n);if(!c)return t.status(404).json({error:"unknown offer"});if(i.some(f=>f.type==="pr.offer.answered"&&f.payload?.offerId===n))return t.status(409).json({error:"offer already answered"});if(o?.includes("pr")){let f=await ug(a,c,{actions:o,notify:s});if(f)return t.json({ok:!0,offerId:n,action:"pr-exists",actions:o,notify:s,existingPr:f.pr})}let l=null;o&&(l=await Pt(a.id,Cs(o,{branch:c.payload.branch,base:c.payload.base,toPr:c.payload.toPr||null,repos:c.payload.repos||null,offeredRebase:Array.isArray(c.payload.offered)&&c.payload.offered.includes("rebase")}),{kind:o.includes("pr")?"pr-go":"push-go"}));let u=o?o.includes("pr")?"pr":o.includes("push")?"push":o.includes("commit")?"commit":"rebase":"dismiss";await $({id:a.id,cwd:a.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:c.boxId,payload:{ts:Date.now(),offerId:n,action:u,actions:o,...s?{notify:!0}:{}}}),s&&Bh(a.id,{actions:o}),t.json({ok:!0,offerId:n,action:u,actions:o,notify:s,queued:!!l?.queued})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});v.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await re(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await dg(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 Cc=e=>t=>({...t,url:g_(t,e.headers)});v.get("/api/views",async(e,t)=>{try{let n=await vu({trackId:e.query.track||void 0});t.json({views:n.map(Cc(e)),maxLive:jr})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/views/:id",async(e,t)=>{let n=await CS(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:Cc(e)(n),session:Ws(n.slug)})});v.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await re(n):null;if(!i&&s&&(i=(await ue()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ve.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await Wm({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:Cc(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})}});v.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:Cc(e)(await MS(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});v.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:Cc(e)(await NS(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})}});v.delete("/api/views/:id",async(e,t)=>{try{t.json(await PS(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var dW=[["linear",Fo,Tw],["jira",od,vw]],bg=new Map;v.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await xw(),r={};for(let[o,s,a]of dW){let i=await s();if(!i){bg.delete(o),r[o]={configured:!1};continue}let c=bg.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},bg.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)})}});v.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await xw()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await JE(o),i=n?await re(n):null;!i&&r&&(i=(await ue()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+ve.sep)))||null),i&&await $({id:i.id,cwd:i.cwd},{type:"ticket.flow.changed",actor:s==="user"?"user":"agent",source:"orchestrator",payload:{ts:Date.now(),set:{...o},flow:a}}).catch(()=>{}),t.json({ok:!0,flow:a})}catch(a){let i=a?.message||String(a);t.status(/unknown|nothing to set/i.test(i)?400:500).json({error:i})}});var Vo=async(e,t)=>{let n=e?await re(e):null;return!n&&t&&(n=(await ue()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+ve.sep)))||null),n};v.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await ww()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});v.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await Vo(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 sa(o);await ed(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})}});v.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await Vo(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await ed(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var UI=async(e,t,n)=>{if(e)return{ref:e,track:await Vo(t,n)};let r=await Vo(t,n),o=r?await yw(r.id):null;if(!o)throw new Error(r?"this Track isn't in a circuit \u2014 pass --circuit <name-or-id> (or link one first: bostrat-circuit link \u2026)":"run from inside a Track workspace, or pass --circuit <name-or-id>");return{ref:o,track:r}};v.post("/api/blueprints/publish",async(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 UI(o,n,r),l=await HE({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})}});v.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await UI(e.query.circuit,e.query.track,e.query.cwd);t.json(await gw(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})}});v.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 Vo(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let f=await KE(u,{title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l});t.json({ok:!0,trackId:u.id,...f})}catch(u){let f=u?.message||String(u);t.status(/required/i.test(f)?400:502).json({error:f})}});v.get("/api/decisions",async(e,t)=>{try{let n=await Vo(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await GE(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})}});v.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 Vo(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await yw(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 WE(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})}});v.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await re(n):null;if(!s&&r&&(s=(await ue()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+ve.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 ca(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})}});v.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await re(r):null;if(!o&&n&&(o=(await ue()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+ve.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 fA(),ticket:await In(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});v.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await In(e.params.id)})});v.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await re(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await ca(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})}});v.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await Dw(e.params.id)})});var Cd=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;v.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await wA(e.params.id))}catch(n){let r=n?.message||String(n);t.status(Cd(r)).json({error:r})}});v.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await Bw(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(Cd(r)).json({error:r})}});v.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await gA(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(Cd(r)).json({error:r})}});v.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await re(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await yA(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(Cd(s)).json({error:s})}});v.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{t.json(await Qh(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})}});v.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await re(n):null;if(!s&&r&&(s=(await ue()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+ve.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 kA(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})}});v.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await bA()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});v.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await re(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await xA(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})}});v.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await ji({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/mocks/:id",async(e,t)=>{let n=await Yn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var Mc={dotfiles:"allow"};v.get("/api/mocks/:id/png",async(e,t)=>{let n=await Yn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=tn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Di(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,Mc,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});v.get("/api/mocks/:id/media",async(e,t)=>{let n=await Yn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=tn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Di(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,Mc,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});v.get("/api/mocks/:id/html",async(e,t)=>{let n=await Yn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=tn(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(Wt(n,r.v).html,Mc,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});v.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Au(n)?n:null,o=n&&!r?n:null,s=n?e.query:e.body||{},{trackId:a,name:i,cwd:c,width:l,group:u}=s;try{let f=a?await re(a):null;if(!f&&c&&(f=(await ue()).find(w=>w.cwd&&(c===w.cwd||c.startsWith(w.cwd+ve.sep)))||null),!f)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=(f.boxes||[]).find(h=>h.name===f.leadBox),p=await ZS({trackId:f.id,name:i,html:n?null:s.html,image:r,video:o,cwd:f.cwd,width:l,group:u,box:f.leadBox,agent:d?.agent||null});t.json({ok:!0,mock:p})}catch(f){let d=f?.message||String(f);t.status(/required|invalid|must be/i.test(d)?400:500).json({error:d})}});v.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Au(n)?n:null;try{let o=await QS(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})}});v.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await nT(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await Pt(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})}});v.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await kT(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await rT(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})}});v.get("/api/flows",async(e,t)=>{try{t.json({flows:await hT({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/flows/:id",async(e,t)=>{let n=await wT(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});v.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await re(n):null;if(!a&&s&&(a=(await ue()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ve.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 gT({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})}});v.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await yT(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})}});v.delete("/api/flows/:id",async(e,t)=>{try{t.json(await bT(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});v.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await ue(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+ve.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await IT({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)})}});v.get("/api/runbooks/:id",async(e,t)=>{let n=await rh(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});v.get("/api/runbooks/:id/md",async(e,t)=>{let n=await rh(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=AT(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 $T(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(Qn(n,r.v),Mc,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});v.get("/api/loops",async(e,t)=>{t.json(await Ei())});v.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 ue()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+ve.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await Ei();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 pm({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})});v.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await re(n):null;if(!s&&r&&(s=(await ue()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+ve.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 T_(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var Eg=async(e,t)=>{let n=e?await re(e):null;return!n&&t&&(n=(await ue()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+ve.sep)))||null),n};v.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Eg(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 qv(s,o,{ship:{changedRepos:_o}})})}catch(s){t.status(400).json({error:s?.message||String(s)})}});v.post("/api/followups/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Eg(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 Gv(s,o)})}catch(s){let a=s?.message||String(s);t.status(/unreachable/i.test(a)?503:400).json({error:a})}});v.get("/api/followups",async(e,t)=>{let n=typeof e.query?.cwd=="string"?e.query.cwd:null,r=await Eg(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:ym,...await Xv(r)})});v.post("/api/tracks/:id/followup-offer",async(e,t)=>{let{offerId:n,followupId:r,armId:o,promoted:s}=e.body||{};try{let a=await re(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await zv(a,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null},{sayToLead:Pt,unarchiveTrack:Hu})})}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})}});v.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await re(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await Kv(n,e.body?.armId)})}catch(n){let r=n?.message||String(n);t.status(/unknown/i.test(r)?404:400).json({error:r})}});v.post("/api/tracks/:id/followup-create-offer",async(e,t)=>{let{proposalId:n,accept:r,followupId:o}=e.body||{};try{let s=await re(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await Vv(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})}});ct.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"||re(e.trackId).then(async s=>{if(s&&(n&&await _i(s,n,o),t==="opened"||t==="pushed")){let a=Jv(await U(s).catch(()=>[]));a&&await _i(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var HI=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await re(n):null;if(!s&&r&&(s=(await ue()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+ve.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await Ei();if(a.source!=="plane")return t.status(503).json({error:a.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${a.error||"no detail"})`}),null;let i;try{i=__(a.loops,o)}catch(c){return t.status(/matches \d+ loops/.test(c.message)?409:404).json({error:c.message}),null}return{track:s,loop:i}};v.post("/api/loops/propose-update",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await HI(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await I_(s.track,s.loop,e.body?.patch)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});v.post("/api/loops/propose-delete",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await HI(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await $_(s.track,s.loop,e.body?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});var WI=e=>/unknown proposal/i.test(e)?404:/already answered/i.test(e)?409:400;v.post("/api/tracks/:id/loop-update-offer",async(e,t)=>{let{proposalId:n,action:r,nextFireAt:o}=e.body||{};try{let s=await re(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await O_(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(WI(a)).json({error:a})}});v.post("/api/tracks/:id/loop-delete-offer",async(e,t)=>{let{proposalId:n,action:r}=e.body||{};try{let o=await re(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await C_(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(WI(s)).json({error:s})}});v.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 re(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await E_(a,n,r===!0,{loopId:o||null,nextFireAt:s??null})})}catch(a){let i=a?.message||String(a);t.status(/unknown proposal/i.test(i)?404:/already answered/i.test(i)?409:400).json({error:i})}});v.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await re(n):null;if(!a&&s&&(a=(await ue()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+ve.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 RT({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})}});v.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await OT(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})}});v.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await CT(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})}});v.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await MT(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});v.get("/api/changelog/draft",async(e,t)=>{try{let n=B_(e.query.since||null);t.json({since:n,repos:og(),...await j_(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var qI=async({trackId:e,cwd:t})=>{let n=e?await re(e):null;return!n&&t&&(n=(await ue()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+ve.sep)))||null),n};v.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await qI({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 L_(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})}});v.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await qI({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 F_(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var fW=120,kg=400,ya=null,$I=null;v.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>kg)return t.status(400).json({error:`message is ${i.length} chars \u2014 over the ${kg} cap; a notification is a nudge, put the detail in chat`});let c=Li(`${n||""}
702
+ ${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 re(a):null;if(!l&&s&&(l=(await ue()).find(h=>h.cwd&&(s===h.cwd||s.startsWith(h.cwd+ve.sep)))||null),!l)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=(l.boxes||[]).find(p=>p.name===l.leadBox),f=(p,h)=>String(p).replace(/\s+/g," ").trim().slice(0,h),d={title:n?f(n,fW):l.name,body:f(i,kg),urgency:o==="high"?"high":"normal",trackName:l.name,ts:Date.now()};await $(l,{type:"notify.raised",actor:"agent",boxId:l.leadBox??null,provider:u?.agent||null,payload:d}),t.json({ok:!0,notification:d,delivered:ya?ya.status().connected:null})}catch(i){t.status(500).json({error:i?.message||String(i)})}});v.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 SI(e.body,e.headers["content-type"]))}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});v.get("/api/dictation/glossary",async(e,t)=>{t.json({configured:!!await dc(),terms:await gg(),problem:await vI()})});v.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 xI(n,r)})});v.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await re(e.params.id))return t.status(404).json({error:"track not found"});t.json(await TI())});v.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await re(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 EI())}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});v.post("/api/tracks/:id/voice-chat/usage",async(e,t)=>{try{let n=await re(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 AI(n,{model:r,usage:o,seconds:s})})}catch(n){t.status(n?.status||500).json({error:n?.message||String(n)})}});v.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 Fu({name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i!==!1}),f=null;if(c)try{await ca(u,c,{source:"create"})}catch(p){f=p?.message||String(p)}let d=null;if(l)try{await ed(u,await sa(l),{source:"picker"})}catch(p){d=p?.message||String(p)}t.json({ok:!0,track:u,...f?{ticketWarning:f}:{},...d?{circuitWarning:d}:{}})}catch(u){let f=u?.message||String(u);t.status(/required|unknown agent|invalid|must be/i.test(f)?400:500).json({error:f})}});v.get("/api/tracks/:id",async(e,t)=>{let n=await re(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:KI(oa(e.params.id)),subtasks:jo(e.params.id).map(Nc),pendingOffers:await Ch(n)})});v.delete("/api/tracks/:id",async(e,t)=>{try{let n=await Vh(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await Dw(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})}});v.post("/api/tracks/:id/archive",async(e,t)=>{try{t.json({ok:!0,track:await Do(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})}});v.post("/api/tracks/:id/rename",async(e,t)=>{try{t.json({ok:!0,track:await Jh(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})}});v.post("/api/tracks/:id/unarchive",async(e,t)=>{try{t.json({ok:!0,track:await Hu(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})}});v.get("/api/tracks/:id/messages",async(e,t)=>{let n=await Du(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json(n)});v.get("/api/tracks/:id/events",async(e,t)=>{let n=await re(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}
703
703
  data: ${JSON.stringify(i)}
704
704
 
705
- `),o=Number(e.query.since??e.headers["last-event-id"])||0;for(let i of await F(n))i.seq>o&&r(i);let s=ny(n.id,r),a=setInterval(()=>t.write(`: hb
705
+ `),o=Number(e.query.since??e.headers["last-event-id"])||0;for(let i of await U(n))i.seq>o&&r(i);let s=ry(n.id,r),a=setInterval(()=>t.write(`: hb
706
706
 
707
- `),25e3);e.on("close",()=>{clearInterval(a),s()})});v.get("/api/tracks/:id/search",async(e,t)=>{let n=await te(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=oi(await F(n)),a=xl(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}))})});v.get("/api/memory",async(e,t)=>{t.json({stores:await by(),harvest:hy()})});v.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 ky(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 lW=["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(`
708
- `);v.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await Pt(e.params.id,lW)})}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})}});v.post("/api/tracks/:id/lead/restart",async(e,t)=>{try{t.json({ok:!0,track:await Uu(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}:{}})}});v.post("/api/tracks/:id/say",async(e,t)=>{let{text:n,attachments:r}=e.body||{};try{t.json(await Pt(e.params.id,n,{attachments:r}))}catch(o){let s=o?.message||String(o);if(o?.usageCap)return t.status(429).json({error:"usage_cap",message:s,cap:o.usageCap});if(o?.transferredTo)return t.status(409).json({error:s,transferredTo:o.transferredTo});t.status(/not found/i.test(s)?404:/archived/i.test(s)?409:/required|not running/i.test(s)?400:500).json({error:s})}});v.post("/api/tracks/:id/upload",async(e,t)=>{try{let n=await te(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 DT(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})}});v.get("/api/tracks/:id/uploads/:file",async(e,t)=>{try{let n=await te(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=xe.basename(String(e.params.file||""));if(!r||!sh(xe.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=oh(n.cwd),s,a;try{s=await mt.promises.realpath(o),a=await mt.promises.realpath(xe.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+xe.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 uW=/^[0-9a-fA-F-]{8,64}$/;v.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await te(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(!uW.test(o)||!Number.isInteger(s)||s<0)return t.status(400).json({error:"bad image ref"});let a=(n.boxes||[]).find(d=>d.name===r);if(!a||a.agent!=="claude"||!a.cwd||!a.sessionId)return t.status(404).json({error:"image source not available"});let i=Jt(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=XH.createInterface({input:mt.createReadStream(i,{encoding:"utf8"}),crlfDelay:1/0});for await(let d of u){if(!d.includes(c))continue;let p;try{p=JSON.parse(d)}catch{continue}if(p.uuid===o){l=p,u.close();break}}let f=l?_f(l)[s]:null;if(!f||!/^image\//.test(f.mediaType))return t.status(404).json({error:"image not found"});t.set("content-type",f.mediaType),t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox"),t.send(Buffer.from(f.data,"base64"))}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/tracks/:id/interrupt",async(e,t)=>{try{t.json(await Bu(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})}});v.delete("/api/tracks/:id/queue",async(e,t)=>{try{let{removed:n,restored:r,draftRev:o}=await Nh(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)})}});v.post("/api/tracks/:id/answer-prompt",async(e,t)=>{let{promptId:n,answers:r,text:o}=e.body||{};try{t.json(await Pu(e.params.id,{promptId:n,answers:r,text:o}))}catch(s){let a=s?.message||String(s),i=/not found/i.test(a)?404:/no pending prompt|changed since|not running|not supported|needs a code|look like a sign-in code|no answer selected/i.test(a)?409:500;t.status(i).json({error:a})}});v.post("/api/setup/:provider/start",async(e,t)=>{try{let n=await qh({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})}});v.post("/api/tracks/:id/navigate-prompt",async(e,t)=>{let{promptId:n,questionIndex:r}=e.body||{};try{t.json(await Mh(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})}});v.put("/api/tracks/:id/draft",async(e,t)=>{let{text:n,rev:r}=e.body||{};try{t.json(await Lh(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})}});v.get("/api/tracks/:id/usage",async(e,t)=>{let n=await te(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 hd(r,{fresh:o}))});v.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await Fh(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})}});v.post("/api/tracks/:id/subtask",async(e,t)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=e.body||{};try{let a=await cw(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:Cc(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})}});v.get("/api/tracks/:id/subtasks",(e,t)=>{t.json({subtasks:jo(e.params.id).map(Cc)})});v.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await Ch(e.params.id,e.params.sid);if(!n)return t.status(404).json({error:"subtask not found"});t.json(n)});v.post("/api/tracks/:id/subtask/:sid/cancel",(e,t)=>{try{t.json({ok:!0,subtask:Cc(Ku(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});v.post("/api/tracks/:id/subtask/:sid/merge-now",(e,t)=>{try{t.json({ok:!0,subtask:Cc(lw(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function Cc(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}v.post("/api/tracks/:id/handoff-lead",async(e,t)=>{let{toAgent:n,skipPermissions:r,reason:o}=e.body||{};try{let s=await Hu(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})}});v.post("/api/tracks/:id/spin-up-view",async(e,t)=>{try{t.json(await Bh(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})}});v.get("/api/tracks/:id/handoff-lead",(e,t)=>{t.json(WI(ra(e.params.id))??{running:!1})});v.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await nw(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})}});v.get("/api/tracks/:id/transfer-out",(e,t)=>{let n=tw(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??{}})});v.post("/api/tracks/:id/transfer-out/commit",async(e,t)=>{try{t.json(await Wu(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})}});v.post("/api/tracks/adopt",async(e,t)=>{let{trackId:n}=e.body||{};try{t.json(await sw({...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 WI(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}v.get("/api/debug/handoff",async(e,t)=>{let n=Math.min(Number(e.query.limit)||80,500);t.json({verbose:el(),paths:Py,trace:await Ny({limit:n})})});var kg=xe.resolve(OI,"..","..","client","dist");mt.existsSync(kg)&&(v.use(Gt.static(kg)),v.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(xe.join(kg,"index.html"),Oc)));var qI=QH.createServer(v),dW=new tW({noServer:!0}),KI=(e,t,n)=>{if(!(vc(e)||wa.allowed(wa.clientIp(e))||vg.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
707
+ `),25e3);e.on("close",()=>{clearInterval(a),s()})});v.get("/api/tracks/:id/search",async(e,t)=>{let n=await re(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=si(await U(n)),a=Sl(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}))})});v.get("/api/memory",async(e,t)=>{t.json({stores:await ky(),harvest:wy()})});v.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 xy(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 pW=["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(`
708
+ `);v.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await Pt(e.params.id,pW)})}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})}});v.post("/api/tracks/:id/lead/restart",async(e,t)=>{try{t.json({ok:!0,track:await Wu(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}:{}})}});v.post("/api/tracks/:id/say",async(e,t)=>{let{text:n,attachments:r}=e.body||{};try{t.json(await Pt(e.params.id,n,{attachments:r}))}catch(o){let s=o?.message||String(o);if(o?.usageCap)return t.status(429).json({error:"usage_cap",message:s,cap:o.usageCap});if(o?.transferredTo)return t.status(409).json({error:s,transferredTo:o.transferredTo});t.status(/not found/i.test(s)?404:/archived/i.test(s)?409:/required|not running/i.test(s)?400:500).json({error:s})}});v.post("/api/tracks/:id/upload",async(e,t)=>{try{let n=await re(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 LT(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})}});v.get("/api/tracks/:id/uploads/:file",async(e,t)=>{try{let n=await re(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=ve.basename(String(e.params.file||""));if(!r||!ah(ve.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=sh(n.cwd),s,a;try{s=await mt.promises.realpath(o),a=await mt.promises.realpath(ve.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+ve.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 mW=/^[0-9a-fA-F-]{8,64}$/;v.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await re(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(!mW.test(o)||!Number.isInteger(s)||s<0)return t.status(400).json({error:"bad image ref"});let a=(n.boxes||[]).find(d=>d.name===r);if(!a||a.agent!=="claude"||!a.cwd||!a.sessionId)return t.status(404).json({error:"image source not available"});let i=Jt(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=tW.createInterface({input:mt.createReadStream(i,{encoding:"utf8"}),crlfDelay:1/0});for await(let d of u){if(!d.includes(c))continue;let p;try{p=JSON.parse(d)}catch{continue}if(p.uuid===o){l=p,u.close();break}}let f=l?$f(l)[s]:null;if(!f||!/^image\//.test(f.mediaType))return t.status(404).json({error:"image not found"});t.set("content-type",f.mediaType),t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox"),t.send(Buffer.from(f.data,"base64"))}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/tracks/:id/interrupt",async(e,t)=>{try{t.json(await Lu(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})}});v.delete("/api/tracks/:id/queue",async(e,t)=>{try{let{removed:n,restored:r,draftRev:o}=await Ph(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)})}});v.post("/api/tracks/:id/answer-prompt",async(e,t)=>{let{promptId:n,answers:r,text:o}=e.body||{};try{t.json(await Bu(e.params.id,{promptId:n,answers:r,text:o}))}catch(s){let a=s?.message||String(s),i=/not found/i.test(a)?404:/no pending prompt|changed since|not running|not supported|needs a code|look like a sign-in code|no answer selected/i.test(a)?409:500;t.status(i).json({error:a})}});v.post("/api/setup/:provider/start",async(e,t)=>{try{let n=await Kh({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})}});v.post("/api/tracks/:id/navigate-prompt",async(e,t)=>{let{promptId:n,questionIndex:r}=e.body||{};try{t.json(await Nh(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})}});v.put("/api/tracks/:id/draft",async(e,t)=>{let{text:n,rev:r}=e.body||{};try{t.json(await Fh(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})}});v.get("/api/tracks/:id/usage",async(e,t)=>{let n=await re(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 gd(r,{fresh:o}))});v.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await Uh(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})}});v.post("/api/tracks/:id/subtask",async(e,t)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=e.body||{};try{let a=await lw(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:Nc(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})}});v.get("/api/tracks/:id/subtasks",(e,t)=>{t.json({subtasks:jo(e.params.id).map(Nc)})});v.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await Mh(e.params.id,e.params.sid);if(!n)return t.status(404).json({error:"subtask not found"});t.json(n)});v.post("/api/tracks/:id/subtask/:sid/cancel",(e,t)=>{try{t.json({ok:!0,subtask:Nc(Vu(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});v.post("/api/tracks/:id/subtask/:sid/merge-now",(e,t)=>{try{t.json({ok:!0,subtask:Nc(uw(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function Nc(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}v.post("/api/tracks/:id/handoff-lead",async(e,t)=>{let{toAgent:n,skipPermissions:r,reason:o}=e.body||{};try{let s=await qu(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})}});v.post("/api/tracks/:id/spin-up-view",async(e,t)=>{try{t.json(await jh(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})}});v.get("/api/tracks/:id/handoff-lead",(e,t)=>{t.json(KI(oa(e.params.id))??{running:!1})});v.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await rw(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})}});v.get("/api/tracks/:id/transfer-out",(e,t)=>{let n=nw(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??{}})});v.post("/api/tracks/:id/transfer-out/commit",async(e,t)=>{try{t.json(await Ku(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})}});v.post("/api/tracks/adopt",async(e,t)=>{let{trackId:n}=e.body||{};try{t.json(await aw({...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 KI(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}v.get("/api/debug/handoff",async(e,t)=>{let n=Math.min(Number(e.query.limit)||80,500);t.json({verbose:nl(),paths:Dy,trace:await Py({limit:n})})});var xg=ve.resolve(MI,"..","..","client","dist");mt.existsSync(xg)&&(v.use(Gt.static(xg)),v.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(ve.join(xg,"index.html"),Mc)));var GI=rW.createServer(v),hW=new sW({noServer:!0}),VI=(e,t,n)=>{if(!(Tc(e)||ga.allowed(ga.clientIp(e))||Sg.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
709
709
  \r
710
- `),t.destroy();return}if(m_(e,t,n))return;if(!f_(e,MI,{enforce:NI})){t.write(`HTTP/1.1 401 Unauthorized\r
710
+ `),t.destroy();return}if(w_(e,t,n))return;if(!m_(e,PI,{enforce:DI})){t.write(`HTTP/1.1 401 Unauthorized\r
711
711
  \r
712
- `),t.destroy();return}let r=eb(e.url);if(!r.ok){t.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
712
+ `),t.destroy();return}let r=tb(e.url);if(!r.ok){t.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
713
713
  \r
714
714
  `),t.destroy();return}let o=r.sessionName;if(!Pe(o)){t.write(`HTTP/1.1 400 Bad Request\r
715
715
  \r
716
- `),t.destroy();return}let{cols:s,rows:a}=r;dW.handleUpgrade(e,t,n,i=>Xy(i,o,{cols:s,rows:a}))};qI.on("upgrade",KI);var GI=process.env.BOSTRAT_CERT_DIR||xe.join(process.env.HOME||_d.tmpdir(),".bostrat","certs"),II=Number(process.env.BOSTRAT_TLS_PORT)||3443,$I=xe.join(GI,"bostrat.globopi.key"),RI=xe.join(GI,"bostrat.globopi.crt");if(mt.existsSync($I)&&mt.existsSync(RI)){let e=eW.createServer({key:mt.readFileSync($I),cert:mt.readFileSync(RI)},v);e.on("upgrade",KI),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(II,Id,()=>{console.log(`[bostrat-agent] https listening on ${Id||"0.0.0.0"}:${II}`)})}qI.listen(EI,Id,()=>{console.log(`[bostrat-agent] listening on ${Id||"0.0.0.0"}:${EI}`);let e=SE(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: ${$t}`),console.log(`[bostrat-agent] auto-trigger default: ${CI}%`),console.log(`[bostrat-agent] ip allowlist: ${wa.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(vg.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),ew().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),aw().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),Jh().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(()=>Xh()).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)),Wh().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)),bW(),mW(),hW(),yW(),Y0({listTracks:le,getTrack:te}).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)),UT()&&HT({listTracks:le}),By().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)),K_(),J_(),bA({resolveTrack:te}),$A({listTracks:le,createTrack:ju,archiveTrack:Do,listRepos:On,resolveTrack:te,sayToLead:Pt,answerPrompt:Pu,startLeadHandoff:Hu,interruptLead:Bu,listSubtaskJobs:jo,cancelSubtask:Ku,readEvents:F,appendEvent:$,divertShip:lg,answerPrExists:ug,knownAgents:Xi}),fW(),Ha().then(t=>{t||console.warn(`[boot] no host tmux server on ${$t} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),uI(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(ga=ME({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,nodeId:process.env.BOSTRAT_NODE_ID||_d.hostname(),name:process.env.BOSTRAT_NODE_NAME||_d.hostname(),listTracks:le,detectAgents:Mu,sampleMetrics:zA,onTracksTransferred:ow,onDegraded:({since:t,unacked:n,oldestAgeMs:r,mode:o})=>{let s=Math.round(r/6e4),a=`${process.env.BOSTRAT_NODE_NAME||_d.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(()=>{}),_I=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(()=>{}),_I=null},onUpdateAvailable:async t=>{try{xg={latest:t.latest,current:t.current},await An({...t,policy:kt()}),kt()==="auto"&&await PI({to:t.latest,from:t.current})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>sW(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await An({current:t,latest:a,min:n,installKind:o,required:!0,policy:kt(),status:"available",reason:"refused"}),kt()!=="off"&&a){let i=await Xu({to:a,kind:Kt,reason:"hard-floor"});i.ok?($c.cancel(),await An({current:t,latest:a,min:n,installKind:o,required:!0,policy:kt(),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:kt}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),os().catch(()=>{}),MT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),kA().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),rT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),kT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),Bx().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 fW(){pW(),bu().catch(()=>{}),setInterval(()=>bu().catch(()=>{}),1e4)}function pW(){for(let e of["bostrat-view","bostrat-mock","bostrat-flow","bostrat-ticket","bostrat-circuit","bostrat-blueprint","bostrat-decision","bostrat-runbook","bostrat-loop","bostrat-followup","bostrat-ship","bostrat-notify","bostrat-gmail","bostrat-changelog","gh"])try{let t=xe.resolve(OI,"..","bin",e),n=xe.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!mt.existsSync(t))continue;mt.mkdirSync(n,{recursive:!0});let r=xe.join(n,e);(mt.existsSync(r)?mt.readlinkSync(r):null)!==t&&(mt.rmSync(r,{force:!0}),mt.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 mW(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await le(),r=await XA({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 hW(){let e=null,t=async()=>{try{let n=bs(),r=0,o=[],s=null;try{let l=await le(),u=await Vw(l);r=u.fleet.unpricedTurns||0,o=u.fleet.unpricedModels||[],s=await YA(l,{days:7})}catch{}let a=[...n.problems];s&&!s.ok&&a.push(`${s.divergent} recent row(s) diverge from the table (implied-rate audit) \u2014 run \`npm run cost -- --audit\``);let i=o.filter(l=>l!=="unknown");i.length&&a.push(`${r} unpriced turn(s) \u2014 add rates for: ${i.join(", ")}`);let c=a.join(`
716
+ `),t.destroy();return}let{cols:s,rows:a}=r;hW.handleUpgrade(e,t,n,i=>Zy(i,o,{cols:s,rows:a}))};GI.on("upgrade",VI);var zI=process.env.BOSTRAT_CERT_DIR||ve.join(process.env.HOME||$d.tmpdir(),".bostrat","certs"),RI=Number(process.env.BOSTRAT_TLS_PORT)||3443,OI=ve.join(zI,"bostrat.globopi.key"),CI=ve.join(zI,"bostrat.globopi.crt");if(mt.existsSync(OI)&&mt.existsSync(CI)){let e=oW.createServer({key:mt.readFileSync(OI),cert:mt.readFileSync(CI)},v);e.on("upgrade",VI),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(RI,Rd,()=>{console.log(`[bostrat-agent] https listening on ${Rd||"0.0.0.0"}:${RI}`)})}GI.listen(_I,Rd,()=>{console.log(`[bostrat-agent] listening on ${Rd||"0.0.0.0"}:${_I}`);let e=AE(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: ${$t}`),console.log(`[bostrat-agent] auto-trigger default: ${NI}%`),console.log(`[bostrat-agent] ip allowlist: ${ga.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(Sg.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),tw().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),iw().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),Xh().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(()=>Zh()).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)),qh().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)),SW(),yW(),bW(),vW(),Z0({listTracks:ue,getTrack:re}).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)),qT()&&KT({listTracks:ue}),jy().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)),V_(),Z_(),vA({resolveTrack:re}),CA({listTracks:ue,createTrack:Fu,archiveTrack:Do,listRepos:On,resolveTrack:re,sayToLead:Pt,answerPrompt:Bu,startLeadHandoff:qu,interruptLead:Lu,listSubtaskJobs:jo,cancelSubtask:Vu,readEvents:U,appendEvent:$,divertShip:ug,answerPrExists:dg,knownAgents:Zi}),wW(),Wa().then(t=>{t||console.warn(`[boot] no host tmux server on ${$t} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),fI(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(ya=DE({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,nodeId:process.env.BOSTRAT_NODE_ID||$d.hostname(),name:process.env.BOSTRAT_NODE_NAME||$d.hostname(),listTracks:ue,detectAgents:Pu,sampleMetrics:JA,onTracksTransferred:sw,onDegraded:({since:t,unacked:n,oldestAgeMs:r,mode:o})=>{let s=Math.round(r/6e4),a=`${process.env.BOSTRAT_NODE_NAME||$d.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(()=>{}),$I=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(()=>{}),$I=null},onUpdateAvailable:async t=>{try{vg={latest:t.latest,current:t.current},await An({...t,policy:kt()}),kt()==="auto"&&await BI({to:t.latest,from:t.current})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>lW(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await An({current:t,latest:a,min:n,installKind:o,required:!0,policy:kt(),status:"available",reason:"refused"}),kt()!=="off"&&a){let i=await Qu({to:a,kind:Kt,reason:"hard-floor"});i.ok?(Oc.cancel(),await An({current:t,latest:a,min:n,installKind:o,required:!0,policy:kt(),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:kt}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),os().catch(()=>{}),DT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),SA().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),aT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),ST().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),Fx().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{ya?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function wW(){gW(),xu().catch(()=>{}),setInterval(()=>xu().catch(()=>{}),1e4)}function gW(){for(let e of["bostrat-view","bostrat-mock","bostrat-flow","bostrat-ticket","bostrat-circuit","bostrat-blueprint","bostrat-decision","bostrat-runbook","bostrat-loop","bostrat-followup","bostrat-ship","bostrat-notify","bostrat-gmail","bostrat-changelog","gh"])try{let t=ve.resolve(MI,"..","bin",e),n=ve.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!mt.existsSync(t))continue;mt.mkdirSync(n,{recursive:!0});let r=ve.join(n,e);(mt.existsSync(r)?mt.readlinkSync(r):null)!==t&&(mt.rmSync(r,{force:!0}),mt.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 yW(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await ue(),r=await QA({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 bW(){let e=null,t=async()=>{try{let n=ks(),r=0,o=[],s=null;try{let l=await ue(),u=await zw(l);r=u.fleet.unpricedTurns||0,o=u.fleet.unpricedModels||[],s=await XA(l,{days:7})}catch{}let a=[...n.problems];s&&!s.ok&&a.push(`${s.divergent} recent row(s) diverge from the table (implied-rate audit) \u2014 run \`npm run cost -- --audit\``);let i=o.filter(l=>l!=="unknown");i.length&&a.push(`${r} unpriced turn(s) \u2014 add rates for: ${i.join(", ")}`);let c=a.join(`
717
717
  `);if(!a.length){e!==""&&console.log(`[pricing] table ok \u2014 rates verified ${n.tableVerifiedAt??"never"}`),e="";return}for(let l of a)console.warn(`[pricing] \u26A0 ${l}`);c!==e&&process.env.BOSTRAT_NTFY_URL&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: cost instrument needs attention",Tags:"warning"},body:a.join(`
718
- `).slice(0,900)}).catch(()=>{}),e=c}catch(n){console.warn(`[pricing] watch failed: ${n?.message||n}`)}};setInterval(t,1440*60*1e3),setTimeout(t,3e4)}var wW=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,gW=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function yW(){let e=async()=>{try{let n=await yy();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await le()).filter(a=>!Ve(a)&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await gy([...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,wW).unref()},gW).unref()}function bW(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await le();for(let n of t)Ve(n)||!n.boxes?.some(r=>r.state==="live")||(await Nu(n.id).catch(()=>{}),await PS(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}
718
+ `).slice(0,900)}).catch(()=>{}),e=c}catch(n){console.warn(`[pricing] watch failed: ${n?.message||n}`)}};setInterval(t,1440*60*1e3),setTimeout(t,3e4)}var kW=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,xW=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function vW(){let e=async()=>{try{let n=await by();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await ue()).filter(a=>!Ve(a)&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await yy([...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,kW).unref()},xW).unref()}function SW(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await ue();for(let n of t)Ve(n)||!n.boxes?.some(r=>r.state==="live")||(await Du(n.id).catch(()=>{}),await jS(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}