bostrat-node 1.8.3 → 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 (3) hide show
  1. package/dist/cli.js +11 -11
  2. package/dist/index.js +187 -187
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,52 +1,52 @@
1
- var i$=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 Pd=(e,t)=>{for(var n in t)i$(e,n,{get:t[n],enumerable:!0})};import{createHash as c$,randomBytes as l$,timingSafeEqual as u$}from"node:crypto";function Pg(){return l$(32).toString("hex")}function xa(e){let t=typeof e=="string"?e.trim():"";return t?c$("sha256").update(t).digest("hex"):null}function Dg(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:u$(Buffer.from(e),Buffer.from(t))}function va(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)<d$)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 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 In,$n,Dd,Bd,d$,Yo=L(()=>{In="BOSTRAT_HOOK_TOKEN",$n="x-bostrat-hook";Dd=new Map,Bd=new Map,d$=6e4});import Et from"node:fs/promises";import jg from"node:os";import xt from"node:path";import{execFile as f$}from"node:child_process";import{promisify as p$}from"node:util";function Mc(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function m$(){return process.env.CLAUDE_CONFIG_DIR?xt.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):xt.join(jg.homedir(),".claude.json")}function h$(){return process.env.CLAUDE_CONFIG_DIR?xt.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):xt.join(jg.homedir(),".claude","settings.json")}async function or(e){if(!e||typeof e!="string")return;let t=xt.resolve(e),n=m$(),r=h$(),o={};try{o=JSON.parse(await Et.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 Et.mkdir(xt.dirname(n),{recursive:!0}),await Et.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await Et.readFile(r,"utf8"))}catch{}if(i.skipDangerousModePermissionPrompt=!0,i.tui===void 0&&(i.tui="default"),process.env.BOSTRAT_HOOKS!=="off"){let l=`curl -sS -m 3 -X POST ${process.env.BOSTRAT_HOOK_URL||`http://127.0.0.1:${process.env.PORT||3362}/api/hook`} -H 'content-type: application/json' -H "${$n}: $${In}" --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 Et.mkdir(xt.dirname(r),{recursive:!0}),await Et.writeFile(r,JSON.stringify(i,null,2)),await w$(t)}async function w$(e){try{let t=xt.resolve(e),n=xt.join(t,".bostrat","memory","claude"),r=xt.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await Et.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(xt.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await Et.mkdir(n,{recursive:!0}),await Et.mkdir(xt.dirname(r),{recursive:!0}),await Et.writeFile(r,JSON.stringify(o,null,2)),await g$(t,["/.claude/settings.local.json"])}catch{}}async function g$(e,t){try{let{stdout:n}=await p$(f$)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=xt.resolve(e,n.trim()),o=await Et.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
2
- `).includes(a));if(!s.length)return;await Et.mkdir(xt.dirname(r),{recursive:!0}),await Et.appendFile(r,(o&&!o.endsWith(`
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
+ `).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 Sa=L(()=>{Yo()});import jd from"node:fs/promises";import y$ from"node:os";import Nc from"node:path";function b$(){let e=process.env.CODEX_HOME||Nc.join(y$.homedir(),".codex");return Nc.join(e,"config.toml")}function Lg(e){return`[projects."${e}"]`}function k$(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=Nc.resolve(e),n=b$(),r="";try{r=await jd.readFile(n,"utf8")}catch{}if(k$(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*$/,"")}
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(Nc.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 Pc=L(()=>{});import Fg from"node:fs/promises";import x$ from"node:os";import Ta from"node:path";function v$(e){let n=Ta.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||Ta.join(x$.homedir(),".cursor");return Ta.join(r,"projects",n)}async function Xo(e){if(!e||typeof e!="string")return;let t=Ta.resolve(e),n=v$(t),r=Ta.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 Dc=L(()=>{});import Fd from"node:fs/promises";import sr from"node:path";import{execFile as S$}from"node:child_process";import{promisify as T$}from"node:util";async function R$(e){try{return(await Fd.stat(sr.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function O$(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 Rn(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await R$(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:sr.basename(o),branch:await O$(o)});return}if(s>=I$)return;let i;try{i=await Fd.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||$$.has(c.name)||await t(sr.join(o,c.name),s+1)}for(let o of _$)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 C$(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 E$("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=C$(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 Rn())if((await Se(n.path))?.toLowerCase()===t)return n.path;return null}var E$,Ug,A$,_$,I$,$$,Ld,ar=L(()=>{E$=T$(S$),Ug=process.env.HOME||"/home/globo",A$=sr.join(process.env.BOSTRAT_STATE_DIR||sr.join(Ug,".bostrat"),"repos"),_$=[...(process.env.BOSTRAT_REPOS_ROOT||sr.join(Ug,"Documents")).split(","),A$].map(e=>e.trim()).filter(Boolean),I$=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,$$=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);Ld=new Map});import M$ from"node:fs";import Hg from"node:fs/promises";import Ea from"node:path";import N$ from"node:os";import{fileURLToPath as P$}from"node:url";import{execFile as D$}from"node:child_process";import{promisify as B$}from"node:util";function _e(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 Bc(e=process.env){return!!(_e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function jc(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!qg.test(n))throw Qo("repo must be owner/name",400);let r=Ud.get(n);if(r&&r.expiresAt-Date.now()>F$)return r;if(!Bc(t))throw Qo("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await Kg(`${_e(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 Ud.set(n,a),a}async function Aa({env:e=process.env,force:t=!1}={}){if(!Bc(e))return{configured:!1,repos:[],username:null};if(!t&&eo&&Date.now()-eo.at<U$)return eo.data;try{let n=await Kg(`${_e(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(){Ud.clear(),eo=null}async function sn({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 jc(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function Hd({env:e=process.env}={}){return(await Aa({env:e})).username??null}function K$(e){let[t,n]=String(e).split("/");return Ea.join(L$,t,n)}async function Wd(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",`!"${W$()}" ${q$(t)}`),await n("config","credential.useHttpPath","true")}async function Lc(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!qg.test(String(e||"")))throw Qo(`bad repo slug "${e}"`,400);let r=K$(e);if(M$.existsSync(Ea.join(r,".git")))return r;let{token:o}=await jc(e,{env:t});await Hg.mkdir(Ea.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:H$,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 Wd(r,{env:t}),r}var Wg,j$,L$,qg,F$,U$,H$,Kg,Ud,eo,Gg,Qo,W$,q$,it=L(()=>{ar();Wg=B$(D$),j$=process.env.BOSTRAT_STATE_DIR||Ea.join(process.env.HOME||N$.tmpdir(),".bostrat"),L$=Ea.join(j$,"repos"),qg=/^[^/\s]+\/[^/\s]+$/,F$=5*6e4,U$=6e4,H$=10*6e4,Kg=fetch,Ud=new Map,eo=null;Gg=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),Qo=(e,t)=>Object.assign(new Error(e),{status:t});W$=()=>P$(new URL("../bin/bostrat-git-credential",import.meta.url)),q$=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function Yg(e=process.env){return!!(_e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Xg(e,t,n,r=zg){let o=_e(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await V$(`${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=qd.get(e);if(!n&&o&&Date.now()-o.at<G$)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 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 Fc(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 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 G$,zg,qd,V$,Jg,Qg=L(()=>{it();G$=6e4,zg=5e3,qd=new Map,V$=(...e)=>fetch(...e);Jg=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import Kd from"node:fs/promises";import es from"node:path";import z$ from"node:os";import{EventEmitter as Y$}from"node:events";import{randomUUID as J$}from"node:crypto";function ts(e){return e?.cwd?es.join(e.cwd,".bostrat","events"):es.join(Gd,"events")}async function eR(e,t){if(!Uc.has(t)){let o=(await F(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);Uc.set(t,o)}let n=Uc.get(t)+1;return Uc.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||!X$.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!Z$.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!Q$.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 eR(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||J$(),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 Kd.mkdir(r,{recursive:!0}),await Kd.appendFile(ey(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(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 X$,Z$,Q$,ct,Gd,ey,Uc,tR,ty,ny,de=L(()=>{X$=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"]),Z$=new Set(["user","agent","orchestrator","system","peer"]),Q$=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor","cli"]),ct=new Y$;ct.setMaxListeners(0);Gd=process.env.BOSTRAT_STATE_DIR||es.join(process.env.HOME||z$.tmpdir(),".bostrat");ey=(e,t)=>es.join(e,`${t}.ndjson`),Uc=new Map;tR=/(?<!\\)((?:\\\\)*)\\u0000/g,ty=e=>e.includes("\\u0000"),ny=e=>e.replace(tR,"$1\\ufffd")});import z from"node:fs/promises";import nR from"node:os";import we from"node:path";import{execFile as rR}from"node:child_process";import{promisify as oR}from"node:util";function Wc(){return we.join(qc,"memory","repos")}function to(e){return e===On?we.join(qc,"memory",On):we.join(Wc(),e)}async function Ia(e){try{return JSON.parse(await z.readFile(we.join(e,uy),"utf8"))}catch{return{}}}async function Yd(e,t){let n=await Ia(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await z.mkdir(e,{recursive:!0}),await z.writeFile(we.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 sR("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function Jd(e){if(!e)return[];let t=sy(await ay(e));if(t)return[t];let n=[],r=[];try{r=await z.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=sy(await ay(we.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function Kc(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 an(e,t=null){let n=t??await z.readFile(e,"utf8").catch(()=>""),{fm:r}=Kc(n),o=ir(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await z.stat(e)).mtimeMs}catch{return 0}}function dy(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()===On){let o=ir(e,"trust");if(!o||/^operator/i.test(o))return On}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 fy(e,t){let n=ir(t,"name")||e.replace(/\.md$/,""),r=ir(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function $a(e){let t=[];try{t=await z.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=we.join(e,".bostrat","memory"),r=await $a(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=we.join(n,f);if(o)try{if((await z.stat(d)).mtimeMs<o-iR)continue}catch{continue}let p;try{p=await z.readFile(d,"utf8")}catch{continue}let{fm:h}=Kc(p),w=dy(h,t);if(!w)continue;let g=to(w),k=we.join(g,f),S=await an(d,p);if(l.has(g)||l.set(g,await Ia(g)),(l.get(g)[f]||0)>=S)continue;let A=await an(k).catch(()=>0);if(await z.access(k).then(()=>!0).catch(()=>!1)&&A>=S)continue;await z.mkdir(g,{recursive:!0}),await z.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,fy(f,h)),i.has(w)||i.set(w,new Set),i.get(w).add(f)}let u=await z.readFile(we.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[f,d]of a){let p=we.join(f,"MEMORY.md"),h=await z.readFile(p,"utf8").catch(()=>"");await z.writeFile(p,Xd(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 z.access(we.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await Jd(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 cR(){let e=we.join(qc,"workspaces"),t=[];try{t=await z.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return my(t.filter(n=>n.isDirectory()).map(n=>we.join(e,n.name)))}async function dR(e,t){let n=to(e),r=await Ia(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!lR.test(l)||l==="MEMORY.md")continue;let u=we.join(n,l),f=await z.access(u).then(()=>!0).catch(()=>!1),d=f?await an(u):0,p=Number(c.modified)||0;if(c.deleted){p>d&&(f&&await z.rm(u,{force:!0}),await Yd(n,[[l,p]]),f&&(a.push(l),i++));continue}f&&d>=p||(r[l]||0)>=p||(await z.mkdir(n,{recursive:!0}),await z.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 z.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 z.mkdir(n,{recursive:!0}),await z.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function Gc(e,t=null){let n=to(e),r=t?.length?t:await $a(n);if(!r.length)return{pushed:0,source:"empty"};let o=uR(await z.readFile(we.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=we.join(n,a),c;try{c=await z.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await an(i,c),indexLine:o.get(a)??null})}return Fc(e,s)}async function fR(e,{timeoutMs:t}={}){let{facts:n,source:r}=await Zg(e,t?{timeoutMs:t}:{});n.length?await dR(e,n):r==="plane"&&await Gc(e)}function pR(e){let t=e.split(`
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
25
  `);t.length>oy&&(t=t.slice(0,oy));let n=t.join(`
26
- `);for(;Buffer.byteLength(n,"utf8")>aR&&t.length;)t.pop(),n=t.join(`
27
- `);return n}async function hR(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 Ia(f);for(let[g,k]of Object.entries(d)){let S=we.join(n,g);await z.access(S).then(()=>!0).catch(()=>!1)&&await an(S)<=k&&(await z.rm(S,{force:!0}),o++)}let p=await $a(f);if(!p.length)continue;await z.mkdir(n,{recursive:!0});for(let g of p){let k=we.join(f,g),S=we.join(n,g),A=await an(k),R=await an(S).catch(()=>0);await z.access(S).then(()=>!0).catch(()=>!1)&&R>=A||(await z.copyFile(k,S),r++)}let h=await z.readFile(we.join(f,"MEMORY.md"),"utf8").catch(()=>""),w=u===On?"## operator memory":`## repo: ${u}`;h.trim()&&s.push(t.length>1?`${w}
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=pR(i);await z.mkdir(n,{recursive:!0}),await z.writeFile(we.join(n,"MEMORY.md"),c);let l=we.join(n,"claude");return await z.mkdir(l,{recursive:!0}),await z.writeFile(we.join(l,"MEMORY.md"),mR,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function hy(e){try{let t=await Jd(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,On];return await Promise.all(n.map(r=>fR(r,{timeoutMs:wR}))),await hR(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function wy(){return{...Xe,pending:ns.size,queued:zd.size}}function gy(e){if(Hc.has(e))return Hc.get(e);zd.add(e);let t=cy.then(async()=>{zd.delete(e),Hc.delete(e);let n=await Qd(e);return Xe.runs++,Xe.lastRunAt=Date.now(),n.error?(Xe.errors++,Xe.lastError=n.error):Xe.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return Hc.set(e,t),cy=t.then(()=>{}),t}function Vc(e,{delayMs:t=gR}={}){if(!e||typeof e!="string")return;Xe.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 Zd(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await z.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([gy(e),s])}finally{clearTimeout(o)}}async function yy(e){return _a||(_a=(async()=>{try{ly||(ly=!0,await bR());let{harvested:t,changedByKey:n}=await my(e);for(let[r,o]of n)await Gc(r,[...o]);return Xe.reconciles++,Xe.lastReconcileAt=Date.now(),Xe.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return Xe.errors++,Xe.lastError=t?.message||String(t),{harvested:0,error:Xe.lastError}}finally{_a=null}})(),_a)}function yR(){return we.join(qc,"memory",".full-sweep-done")}async function by(){let e=yR();try{let t=JSON.parse(await z.readFile(e,"utf8"));return Xe.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...Xe.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await cR();for(let[o,s]of n)await Gc(o,[...s]);let r={at:Date.now(),harvested:t};return await z.mkdir(we.dirname(e),{recursive:!0}),await z.writeFile(e,JSON.stringify(r)),Xe.backfill=r,{ran:!0,...r}}catch(t){return Xe.errors++,Xe.lastError=t?.message||String(t),{ran:!1,error:Xe.lastError}}}async function bR(){let e=0,t=[];try{t=await z.readdir(Wc(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=we.join(Wc(),n.name),o=to(On),s=new Set,a=new Map;for(let p of await $a(r)){let h=we.join(r,p),w;try{w=await z.readFile(h,"utf8")}catch{continue}let{fm:g}=Kc(w);if(dy(g,n.name)!==On)continue;let k=we.join(o,p),S=await an(k).catch(()=>0),A=await an(h,w);await z.mkdir(o,{recursive:!0}),A>S&&await z.writeFile(k,w),await z.rm(h,{force:!0}),s.add(p),a.set(p,fy(p,g)),e++}if(!s.size)continue;let i=Date.now();await Yd(r,[...s].map(p=>[p,i])),await Fc(n.name,[...s].map(p=>({file:p,deleted:!0,modified:i})));let c=we.join(r,"MEMORY.md"),l=await z.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 z.writeFile(c,u).catch(()=>{});let f=we.join(o,"MEMORY.md"),d=await z.readFile(f,"utf8").catch(()=>"");await z.writeFile(f,Xd(d,l,s,a))}return{moved:e}}async function ky(){let e=[],t=[On];try{for(let n of await z.readdir(Wc(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=to(n),o=await $a(r),s=await Ia(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await z.readFile(we.join(r,i),"utf8").catch(()=>""),{fm:l}=Kc(c);a.push({file:i,name:ir(l,"name")||i.replace(/\.md$/,""),description:ir(l,"description")||"",scope:ir(l,"scope")||null,modified:await an(we.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=we.join(n,t);if(!await z.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await z.rm(r,{force:!0}),await Yd(n,[[t,s]]);let a=we.join(n,"MEMORY.md"),i=await z.readFile(a,"utf8").catch(()=>"");await z.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 Fc(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 py(e,t[0]||null);for(let[o,s]of r)await Gc(o,[...s]);return n>0&&await xR(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function xR(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,kR)}}await $({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var sR,qc,oy,aR,On,uy,rs,iy,iR,lR,uR,mR,wR,gR,ns,zd,cy,Xe,Hc,ly,_a,kR,Ra=L(()=>{Qg();de();sR=oR(rR),qc=process.env.BOSTRAT_STATE_DIR||we.join(process.env.HOME||nR.tmpdir(),".bostrat"),oy=200,aR=25*1024;On="operator";uy=".tombstones.json";rs=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;iy=new Map,iR=2e3;lR=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,uR=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};mR=`# 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
- `;wR=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;gR=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,ns=new Map,zd=new Set,cy=Promise.resolve(),Xe={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};Hc=new Map;ly=!1,_a=null;kR=20});import ef from"node:fs/promises";import vR from"node:path";async function vt(e,t,{mode:n}={}){await ef.mkdir(vR.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++SR}.tmp`;await ef.writeFile(r,JSON.stringify(t,null,2)+`
43
- `,n!=null?{mode:n}:void 0),await ef.rename(r,e)}var SR,cr=L(()=>{SR=0});import Ay from"node:fs/promises";import _y from"node:os";import Iy from"node:path";function Me(e=process.env){return!!(_e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Ma(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),TR);try{return await RR(`${_e(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function Ry(){return Yc||(tf||=Ay.readFile($y(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>Yc={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>tf=null),tf)}async function Jc(){await vt($y(),Yc).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 rf(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 Jc()}function Ey(){zc||(zc=setTimeout(()=>{zc=null,os().catch(()=>{})},OR),zc.unref?.())}function nf(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function MR(e,t=process.env){if(e.op==="record"){let n=await Ma(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...Ca(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:$R()}]})},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 Ay.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await Ma(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...Ca(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 Ma(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:Ca(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 Me(e)?Oa||(Oa=(async()=>{let r=await Ry();NR(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await MR(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<AR)return Ey(),await Jc(),{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 Jc();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await Jc()}return{flushed:o,parked:s,pending:0}})().finally(()=>{Oa=null}),Oa):{flushed:0,source:"unconfigured"}}function NR(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=CR);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 ht(e,t,{trackId:n=null,env:r=process.env}={}){return Me(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 Me(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 qt(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return Me(r)?(await rf({op:"delete",family:e,id:t,deletedAt:n}),os({env:r})):{queued:!1,source:"unconfigured"}}async function nt(e,{env:t=process.env}={}){if(!Me(t))return{records:[],source:"unconfigured"};try{let n=await Ma(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:Ca(t)},t);if(!n.ok)throw new Error(`plane ${n.status}`);let r=await n.json();return{records:Array.isArray(r?.records)?r.records:[],source:"plane"}}catch(n){return{records:[],source:"unreachable",error:n?.message}}}async function Na(e,t,n,r,{env:o=process.env}={}){if(!Me(o))return null;try{let s=await Ma(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:Ca(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 TR,ER,vy,AR,Sy,_R,IR,$y,$R,RR,OR,CR,Ca,Yc,tf,zc,Oa,ur=L(()=>{it();cr();TR=1e4,ER=3e4,vy=2e3,AR=5,Sy=100,_R=60*6e4,IR=()=>process.env.BOSTRAT_STATE_DIR||Iy.join(process.env.HOME||_y.tmpdir(),".bostrat"),$y=()=>Iy.join(IR(),"content-outbox.json"),$R=()=>process.env.BOSTRAT_NODE_ID||_y.hostname(),RR=(...e)=>fetch(...e),OR=ER,CR=_R;Ca=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});Yc=null,tf=null,zc=null,Oa=null});import of from"node:fs/promises";import Oy from"node:path";async function Cy(e,t,{box:n=null,agent:r=null}={}){if(!e||!Me())return{pushed:!1};try{let o=Date.now();return await ht("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await lr("checkpoints",e,o,"md",t),Pa=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function LR(){if(Pa&&Date.now()-Pa.at<jR)return{records:Pa.records,source:"plane"};let e=await nt("checkpoints");return e.source==="plane"&&(Pa={at:Date.now(),records:e.records}),e}async function Xc(e){try{let t=BR(e);if(!t||!Me())return{restored:!1};let n=Oy.join(e,PR,DR);if(await of.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await LR();if(o!=="plane")return{restored:!1};let s=r.find(i=>!i.deletedAt&&i.data?.id===t);if(!s?.data?.v)return{restored:!1};let a=await Na("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await of.mkdir(Oy.dirname(n),{recursive:!0}),await of.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var PR,DR,BR,jR,Pa,Zc=L(()=>{ur();PR=".bostrat/handoff",DR="latest.md",BR=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;jR=6e4,Pa=null});import Da from"node:fs/promises";import FR from"node:os";import Ny from"node:path";function no(e){let t=String(e??"");for(let n of UR)t=t.replace(n,"\u2039redacted\u203A");return t}function Qc(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function HR(e){try{await Da.mkdir(sf,{recursive:!0}),await Da.appendFile(ss,`${JSON.stringify(e)}
44
- `,"utf8");let n=(await Da.readFile(ss,"utf8")).split(`
45
- `).filter(Boolean);n.length>My&&await Da.writeFile(ss,`${n.slice(-My).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&&Qc())try{t.paneTail=no((await Oe(t.sessionName,{lines:35})).slice(-4e3))}catch{t.paneTail=null}(Qc()||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 HR(t)}async function Py({limit:e=80}={}){try{return(await Da.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 UR,sf,ss,My,Dy,cn=L(()=>{lt();UR=[/[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||Ny.join(FR.homedir(),".bostrat","debug"),ss=Ny.join(sf,"handoff.jsonl"),My=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;Dy={DEBUG_DIR:sf,LOG_FILE:ss}});import el from"node:fs/promises";import af from"node:path";import WR from"node:os";async function jy(e=By){await el.mkdir(e,{recursive:!0});for(let t of KR){let n=t==="prepare-commit-msg"?GR:t==="post-commit"?VR:`${cf}exit 0
49
- `,r=af.join(e,t),o=null;try{o=await el.readFile(r,"utf8")}catch{}o!==n&&await el.writeFile(r,n,{mode:493}),await el.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",`${Ba}=${e}`]}function Fy(e=process.env){return e.BOSTRAT_NODE_URL||`http://127.0.0.1:${e.PORT||3362}`}var Ba,qR,By,KR,cf,GR,VR,lf=L(()=>{Yo();Ba="BOSTRAT_NODE_URL",qR=process.env.BOSTRAT_STATE_DIR||af.join(process.env.HOME||WR.tmpdir(),".bostrat"),By=af.join(qR,"git-hooks"),KR=["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
- `,GR=`${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
- [ -z "$${In}" ] && exit 0
68
- [ -z "$${Ba}" ] && exit 0
67
+ [ -z "$${$n}" ] && exit 0
68
+ [ -z "$${La}" ] && exit 0
69
69
  [ "$2" = "merge" ] && exit 0
70
- trailers=$(curl -sS -m 3 -H "${$n}: $${In}" "$${Ba}/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
- `,VR=`${cf}
76
+ `,zR=`${uf}
77
77
  # \u2500\u2500 bostrat: report the commit (code.committed + rework analysis, node-side).
78
- [ -z "$${In}" ] && exit 0
79
- [ -z "$${Ba}" ] && exit 0
78
+ [ -z "$${$n}" ] && 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 "$${Ba}/api/git/committed" \\
83
- -H 'content-type: application/json' -H "${$n}: $${In}" --data-binary @- >/dev/null 2>&1 || true
82
+ printf '{"sha":"%s","cwd":"%s"}' "$sha" "$cwd" | curl -sS -m 5 -X POST "$${La}/api/git/committed" \\
83
+ -H 'content-type: application/json' -H "${Rn}: $${$n}" --data-binary @- >/dev/null 2>&1 || true
84
84
  exit 0
85
- `});import{execFile as Hy}from"node:child_process";import{promisify as zR}from"node:util";import nl from"node:fs";import{randomUUID as Wy}from"node:crypto";function cs(e){return new Promise(t=>setTimeout(t,e))}function tl(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 YR({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 La(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${ja}=1`]}function Fa(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&&Ne(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 ZR(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===rl?!0:r===as?!1:n}async function Gy(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 Ie(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),rl}catch(s){return s?.killed||s?.signal?is:s?.code===1||s?.code===127?as:is}}async function ol(e,{retries:t=QR,sleep:n=eO,probe:r=Gy}={}){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 G(...e){return["-S",At,...e]}async function fr(){if(!nl.existsSync(At))return!1;try{return await Ie(K,G("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function Ua(){if(await fr())return!0;try{nl.mkdirSync(At.replace(/\/[^/]+$/,""),{recursive:!0}),await Ie(K,G("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await fr()}function Ne(e){return typeof e=="string"&&tO.test(e)}async function Kt(){if(!nl.existsSync(At))return[];try{let e="#{session_name}|#{session_windows}|#{session_attached}|#{session_activity}|#{pane_current_path}|#{@bostrat-session}|#{@bostrat-title}|#{@bostrat-sid}|#{@bostrat-agent}|#{alternate_on}|#{session_created}",{stdout:t}=await Ie(K,G("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=>!XR.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function ge(e){return(await Kt()).find(n=>n.name===e)||null}function oO(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=rO&&nO.test(t)}function sl(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 Ie(K,G("list-sessions","-F","#{session_name}"));return t.split(`
87
- `).map(n=>n.trim()).includes(e)}catch{return!1}}function iO(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 cO(e,t){let n=Date.now()+Ha(),r=iO(t),o=!1,s=0;for(;;){if(await cs(sO),s+=1,!await Vy(e))return;let a=await Oe(e,{lines:15}),i=!o&&aO.test(a)&&!!r?.test(a);if(!i&&s>1&&!await Cn(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 Ie(K,G("send-keys","-t",e,"C-u")),await Ie(K,G("send-keys","-t",e,"-l",t)),await Ie(K,G("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=JR,n={}){if(!oO(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=sl(r);if(!Ne(o))throw new Error("resulting tmux session name is invalid");if(!await Ua())throw new Error(`host tmux server not running on ${At} and auto-start failed \u2014 start one: ${K} -S ${At} new-session -d -s keeper "sleep 2147483647"`);if(await Vy(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||Wy(),l=i?s:Fa(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 hy(t),n.freshWorkspace!==!0&&await Xc(t));let p=f&&!d?Mc():null,h=Pg(),w=["-e",`${In}=${h}`];w.push(...Ly({nodeUrl:Fy()})),p&&w.push("-e",`ANTHROPIC_API_KEY=${p}`),f&&w.push(...La());try{await Ie(K,G("new-session","-d","-s",o,"-c",t,...w))}catch(g){throw tl(p?tl(g,p):g,h)}return await oo(o),await Ie(K,G("set-option","-t",o,"@bostrat-session","1")),await Ie(K,G("set-option","-t",o,"@bostrat-title",r)),await Ie(K,G("set-option","-t",o,"@bostrat-sid",c)),await Ie(K,G("set-option","-t",o,"@bostrat-agent",a)),await Ie(K,G("send-keys","-t",o,l,"Enter")),ZR(l)&&cO(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:h}}async function Gt(e){if(!Ne(e))throw new Error("invalid session name");await Ie(K,G("kill-session","-t",e))}async function zy(e,t){if(Ne(e))try{let n=t?G("set-option","-t",e,"@bostrat-sid",t):G("set-option","-u","-t",e,"@bostrat-sid");await Ie(K,n)}catch{}}async function Oe(e,{lines:t=40}={}){if(!Ne(e))return"";try{let n=G("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await Ie(K,n);return String(r||"")}catch{return""}}async function Yy(e){if(!Ne(e))return 0;try{let{stdout:t}=await Ie(K,G("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
88
- `).filter(Boolean).length}catch{return 0}}async function oo(e,{cols:t=dO,rows:n=fO}={}){if(!Ne(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 Ie(K,G("resize-window","-t",e,"-x",String(t),"-y",String(n))),await Ie(K,G("set-window-option","-t",e,"window-size","latest")),await cs(80)}catch{}return!0}async function pO(e){if(!Ne(e))return 0;try{let{stdout:t}=await Ie(K,G("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function Cn(e){let t=await pO(e);if(!t)return!1;try{return await Ie("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function Jy(e){if(!Ne(e))return{cols:0,rows:0};try{let{stdout:t}=await Ie(K,G("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 al(e,{cols:t=lO,rows:n=uO}={}){if(Ne(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 Ie(K,G("resize-window","-t",e,"-x",String(o),"-y",String(s))),await Ie(K,G("set-window-option","-t",e,"window-size","latest")),await cs(80))}catch{}}async function Mn(e){return await al(e),Oe(e,{lines:Ze})}async function Be(e,t,{settleMs:n=40,kind:r}={}){if(!Ne(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>mO.has(s));for(let s=0;s<o.length;s++)await Ie(K,G("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(!Ne(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await Ie(K,G("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 cl(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!Ne(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await Ie(K,G("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 hO(e,t){return new Promise((n,r)=>{let o=Hy(K,G(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function wO(e,t){let n=`bostrat-${Wy().slice(0,8)}`;await hO(["load-buffer","-b",n,"-"],t),await Ie(K,G("paste-buffer","-p","-d","-b",n,"-t",e))}async function Qe(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!Ne(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await wO(e,t):await Ie(K,G("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await cs(a),await Ie(K,G("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 Ie,K,Uy,At,JR,df,ja,ff,XR,rl,as,is,uf,QR,eO,pf,tO,nO,rO,Ha,sO,aO,lO,uO,Ze,dO,fO,mO,il,lt=L(()=>{Sa();Pc();Dc();Ra();Zc();cn();Yo();lf();Ie=zR(Hy);K=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";Uy=typeof process.getuid=="function"?process.getuid():0,At=YR({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return nl.existsSync(qy(Uy))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:Uy}),JR=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",df=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",ja="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";ff="bostrat-usage-probe",XR=new Set([ff]);rl="present",as="absent",is="unknown",uf=5e3,QR=[250,1e3,3e3],eO=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"};tO=/^[A-Za-z0-9_.-]{1,64}$/;nO=/^[A-Za-z0-9 ._↻-]+$/,rO=64;Ha=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,sO=1e3,aO=/not found|Unknown command/i;lO=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,uO=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,Ze=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,dO=Number(process.env.BOSTRAT_BOX_COLS)||120,fO=Number(process.env.BOSTRAT_BOX_ROWS)||40;mO=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);il=1600});import Wa from"node:fs";import vO from"node:fs/promises";import us from"node:path";import SO 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=Wa.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}=Wa.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function Vt(e,t){if(!t)return null;let n=us.join(hf,wf(e),`${t}.jsonl`);return Wa.existsSync(n)?n:null}function rb(e){if(!e)return[];let t=us.join(hf,wf(e)),n;try{n=Wa.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=Wa.statSync(us.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function St(e,t=131072){let n=await vO.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 EO(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 qa(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=Vt(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=EO(await St(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(nb,s.model),i=nb[s.model]||TO;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,TO,hf,zt=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},TO=2e5,hf=process.env.BOSTRAT_CLAUDE_PROJECTS||us.join(SO.homedir(),".claude","projects")});function AO(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 Ka(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 Ga(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 Re(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 $O(e){let t=ib(e),n=ut(Re(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${je(n)}`:`Read lines ${t.from}\u2013${t.to} of ${je(n)}`:e.includes("-i")&&n?`Edit ${je(n)}`:null}function yf(e){if(e.includes("--files")){let s=ut(Re(e,ob)[0]);return s&&s!=="."?`List files in ${ds(s)}`:"List files"}let t=Re(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 bf(e){let t=Re(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=Re(e)[0];return n?`Run ${je(n)}`:null}function RO(e){let t=Re(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 MO(e){let t=Ga(Ka(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(je(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return xf(t[2]);let n=je(t[0]);if(CO.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=OO[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=AO(t);for(let i=0;i<r.length-1;i++){let c=Ga(Ka(r[i])),l=Ga(Ka(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(je(c[0]))&&je(l[0])==="sed"){let u=ib(l),f=Re(c)[0];if(u&&f)return fs(u.from===u.to?`Read line ${u.from} of ${je(f)}`:`Read lines ${u.from}\u2013${u.to} of ${je(f)}`,88)}}let o=[];for(let i of r){let c=MO(i);c&&o.push({d:c,head:je(Ga(Ka(i))[0]||""),sub:Re(Ga(Ka(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,je,ds,ab,ob,_O,IO,OO,CO,cb=L(()=>{fs=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,ut=e=>e&&!/[$`]/.test(e)?e:null,je=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"]);_O={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 ${je(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"},IO={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"};OO={git:e=>{let t=Re(e,new Set(["-C","-c"])),n=_O[t[0]];return n?n(t,e):null},gh:e=>{let t=Re(e),n=IO[t[0]];return n?n(t):null},sed:$O,rg:yf,grep:yf,egrep:yf,nl:e=>{let t=ut(Re(e)[0]);return t?`Read ${je(t)}`:null},cat:e=>{let t=ut(Re(e)[0]);return t?`Read ${je(t)}`:null},head:e=>{let t=ut(Re(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${je(t)}`:null},tail:e=>{let t=ut(Re(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${je(t)}`:null},wc:e=>{let t=ut(Re(e)[0]);return t?`Count lines in ${je(t)}`:"Count input lines"},ls:e=>{let t=ut(Re(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(Re(e)[0]);return t?`Create directory ${ds(t)}`:null},touch:e=>{let t=ut(Re(e)[0]);return t?`Create ${je(t)}`:null},rm:e=>{let t=ut(Re(e)[0]);return t?`Delete ${ds(t)}`:null},mv:e=>{let t=ut(Re(e)[0]);return t?`Move ${je(t)}`:null},cp:e=>{let t=ut(Re(e)[0]);return t?`Copy ${je(t)}`:null},chmod:e=>{let t=ut(Re(e)[1]);return t?`Change permissions on ${je(t)}`:null},diff:e=>{let t=Re(e);return t.length>=2?`Compare ${je(t[0])} and ${je(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:bf,pnpm:bf,yarn:bf,npx:e=>{let t=Re(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=Re(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:RO,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=Re(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=Re(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=Re(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},CO=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 lb(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await St(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 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 Sf,ms=L(()=>{zt();cb();Sf=new Set(["Bash"])});import db from"node:fs";import Ef from"node:fs/promises";import Tf from"node:path";import NO from"node:os";async function fb(e){try{return await Ef.realpath(e)}catch{return e}}function DO(e=PO){let t=[],n=r=>{let o;try{o=db.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:db.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function BO(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 jO(e){let t=await BO(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=DO();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 jO(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 St(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=FO(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 UO(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 HO(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 WO(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=HO(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 St(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"&&Va.has(u.name)){let p;try{p=JSON.parse(u.arguments||"{}")}catch{continue}let h=UO(p);h&&(f=[h])}else u.type==="custom_tool_call"&&u.name==="exec"&&(f=WO(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 hb(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 PO,LO,FO,Va,Af,ao,io=L(()=>{zt();ms();PO=process.env.BOSTRAT_CODEX_SESSIONS||Tf.join(process.env.CODEX_HOME||Tf.join(NO.homedir(),".codex"),"sessions");LO=new Set(["output_text","text"]),FO=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&LO.has(t.type)).map(t=>t.text).join(`
98
- `).trim():"";Va=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 za({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||za({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":za({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:za({text:n}),code:null,status:qO(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function qO(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var x5,wb,ul=L(()=>{io();x5=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 KO(e,t){return!e||!t?null:Vt(e,t)}function GO(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 VO(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 zO(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 If(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await St(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"&&YO.test(g)&&s.set(w.id,g.split("/").pop())}if(zO(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=GO(l.content),d=u==="assistant"?VO(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:za({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=KO(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}:** ${JO(s.text||c,700)} ${i}`.trim()}).join(`
101
-
102
- `):""}var YO,JO,dl=L(()=>{ul();zt();YO=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;JO=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});import XO from"node:fs/promises";import{execFile as ZO}from"node:child_process";import{promisify as QO}from"node:util";function Tb(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 Eb({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();!r||xb.has(r)||(xb.add(r),vb=vb.then(()=>tC({sessionName:e,from:t,to:r})).catch(()=>{}))}async function tC({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 XO.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:eC});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 Sb({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 Sb({sessionName:e,from:t,to:n,status:"failed",error:o})}}async function Sb(e){if(Rf)try{await Rf(e)}catch{}}var $f,eC,xb,vb,Rf,fl=L(()=>{cn();$f=QO(ZO),eC=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,xb=new Set,vb=Promise.resolve(),Rf=null});function rC(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(nC);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(`
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
104
  `);for(let r=n.length-1;r>=0;r--)if($b.test(n[r]))return n.slice(r).join(`
105
- `);return t}function oC(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 sC(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 aC(e,t=""){let n=co(e);if(Ya.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])&&oC(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=sC(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function lC(e,t=""){let n=co(e);if(Ya.test(n)||!iC.test(n))return null;let r=n.trimEnd().split(`
107
- `).pop()||"";return cC.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 dC(e,t=""){let n=co(e);if(Ya.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(uC);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 fC(e,t=""){let n=co(e);return Ya.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 pC(e,t=""){let n=co(e);return Ya.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 mC(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 wC(e,t=""){let n=String(e);if(!hC.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 gC(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 Rb(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=lC(t,n)||dC(t,n)||fC(t,n)||pC(t,n)||aC(t,n);if(r)return r}if(e==="cursor"){let r=wC(t,n)||gC(t,n)||mC(t,n);if(r)return r}return rC(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 nC,Ab,Ya,$b,_b,iC,cC,Ib,uC,Cf,hC,pl=L(()=>{nC=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,Ab=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;Ya=/(^|\n)\s*›/,$b=/^\s*Welcome to Codex\b/;_b=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;iC=/Successfully logged in\./,cC=/^\s*Press Enter to continue\.\s*$/;Ib=/Enter this one-time code/,uC=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;Cf=/Run Everything|Add a follow-up|Plan, search, build anything/;hC=/click this link to log in|Signing in with the browser/});function xC(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(bC.test(r)||kC.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 AC(e){let t=String(e||"");if(!We.codex.block.test(t))return null;let n=co(t);if(!We.codex.block.test(n))return null;let r=n.match(EC);return{from:r?.[1]||null,to:r?.[2]||null}}function ln(e){return new Promise(t=>setTimeout(t,e))}function Mf(e,t){let n=Date.now(),r=_C();for(let[s,a]of hl)n-a>=r&&hl.delete(s);let o=`${e}::${t}`;return hl.has(o)?!1:(hl.set(o,n),!0)}function Pb(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
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
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 $C(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 Nf(e,t){let n=We[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(Pb(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=$C(t);return e==="claude"&&r>0&&r<IC?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function Pf(e,t){return Nf(e,t).state}function Db(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
115
- `).slice(-OC).join(`
116
- `);return RC.test(n)}function ws(e,t){return Pf(e,t)==="busy"}function wl(e,t){return Pf(e,t)!=="idle"}function gs(e,t){let n=We[e];return n?.up?n.up.test(t):!0}function CC(e,t){let n=We[e];return n?Df(e,t)?!1:n.up.test(t)&&Pf(e,t)==="idle":!0}function Df(e,t){let n=We[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(`
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 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=Bf(await Oe(e),o);if(CC(t,l)){await s?.(),await ln(hs);return}if(We[t]?.up&&!We[t].up.test(l))if(await Cn(e)){if(c??=Date.now(),Date.now()-c>=Ha()){let u=Cb(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"&&TC.test(l)&&!We.claude.up.test(l)){re({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{});return}if(t==="codex"&&SC.test(l)&&!We.codex.up.test(l)&&i<3){if(!Mf(e,"codex-trust")){await ln(ml);continue}i+=1,await re({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await Qe(e,"",{enter:!0,kind:"codex-trust-accept"}),await ln(hs);continue}if(t==="cursor"&&vC.test(l)&&!We.cursor.up.test(l)&&i<3){if(!Mf(e,"cursor-trust")){await ln(ml);continue}i+=1,await re({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await Qe(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await ln(hs);continue}if(t==="codex"&&i<3){let u=AC(l);if(u){if(!Mf(e,`codex-update:${u.from}->${u.to}`)){await ln(ml);continue}i+=1,await re({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${u.from} -> ${u.to}`}).catch(()=>{}),await Qe(e,"3",{enter:!1,kind:"codex-update-skip"}),Eb({sessionName:e,from:u.from,to:u.to}),await ln(hs);continue}}if(Date.now()>a){if(Df(t,l)){let u=`${t} is blocked on an interactive prompt`;throw t==="codex"?u=We.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"&&We.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"&&We.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"&&We.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 Cn(e)){let u=Cb(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:!!We[t]?.block?.test(l),paneUp:!!We[t]?.up?.test(l),paneBusy:!!We[t]?.busy?.test(Pb(We[t],l))}).catch(()=>{}),await ln(hs);return}await ln(ml)}}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 jb({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 Ja({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=yC(),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 Mb(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c});return}let p=We[r]?r:We[l]?l:null;if(process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&p){await Mb(n,p,s,{launchEcho:i});return}await ln(hs)}var yC,ml,hs,bC,kC,We,vC,SC,TC,EC,_C,hl,IC,Nb,RC,OC,Xa=L(()=>{lt();Sa();Pc();Dc();fl();pl();cn();yC=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,ml=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,hs=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,bC=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,kC=/^\s*tab to queue message\b/;We={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:xC},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/}},vC=/Trust this workspace|\[a\]\s*Trust/,SC=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,TC=/Resume from summary/i,EC=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;_C=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,hl=new Map;IC=68,Nb=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;RC=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,OC=15});function DC(e){return typeof e!="string"||!e?!1:e.includes(`
119
- `)?!0:Buffer.byteLength(e,"utf8")>=PC}function un(e,t){return e==="codex"?{enter:!0,submitDelayMs:MC,...DC(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:NC}:{enter:!0}}var MC,NC,PC,Za=L(()=>{MC=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),NC=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),PC=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function Qa(e,t){if(e==="codex")return UC(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(BC);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 UC(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]){(jC.test(t[o])||LC.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(FC.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=Ue(n.replace(HC,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!Ue(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function Ue(e){return String(e||"").replace(/\s+/g," ").trim()}function Fb(e,t,{slackMs:n=2e4}={}){let r=Ue(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&&Ue(a.text).includes(r));return s>=0&&s<o.length-1}function Ub(e,t,n,{busy:r=!1}={}){let o=Qa(e,n);return o&&gl(t,o)||o&&e==="codex"&&Ff(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function gl(e,t){let n=Ue(e),r=Ue(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var Lb,BC,Lf,jC,LC,FC,HC,yl=L(()=>{Lb=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,BC=/^❯[  ]?(.*)$/,Lf=/^\s*›[  ]?(.*)$/,jC=/\S+ · \S/,LC=/^\s*(?:\? for shortcuts|tab to queue message)\b/,FC=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;HC=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function ti({sessionName:e,agent:t,agentCmd:n=null,text:r,trackId:o=null,flow:s="say"},a={}){if(!WC.has(t))return!0;let i=a.waitForUp??jb({agent:t,agentCmd:n}),c=a.capture||(R=>Oe(R,{lines:Ze})),l=a.pressEnter||(R=>Be(R,["Enter"],{kind:"submit-retry"})),u=a.sleep||VC,f=a.now||Date.now,d=a.log||(R=>re(R).catch(()=>{})),p=a.maxMs??GC(),h=f()+p,w={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},g=0,k=0,S=0,A=!1;for(await u(ei[0]);;){let R=await c(e).catch(()=>""),B=gs(t,R),T=ws(t,R),_=Ub(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:A?"cli-down":"cli-never-up",retries:g,waitedMs:p}),!0);await u(qC);continue}if(A=!0,_==="stuck"){if(g>=KC)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(ei[0]);continue}if(k+=1,k>=ei.length||f()>=h)return!0;S+=1,await u(ei[Math.min(S,ei.length-1)])}}var WC,ei,qC,KC,GC,VC,Uf=L(()=>{lt();Xa();yl();cn();WC=new Set(["claude","codex"]),ei=[250,450,700],qC=500,KC=2,GC=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},VC=e=>new Promise(t=>setTimeout(t,e))});function Nn(e){let t=String(e||"").toLowerCase();if(!t.trim())return null;let n=null;for(let r of zC){let o=0;for(let s of YC[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function Hb(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))JC.has(r)&&(t+=o||0),XC.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function ni(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 zC,YC,JC,XC,bl=L(()=>{zC=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],YC={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/]};JC=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),XC=new Set(["Edit","Write","MultiEdit","NotebookEdit"])});function Gb(e){let t=ni(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||ZC.has(r)||n.push(r);return n}function QC(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(Kb(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(Kb(n,"assistant",o))}}return t}function Kb(e,t,n){let r=Nn(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 ri(e){let t=QC(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=Gb(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 kl(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(Gb(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+Wb*(1-qb+qb*(g/(e.avgdl||1))),S=p*(w*(Wb+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 Wb,qb,ZC,Hf=L(()=>{bl();Wb=1.5,qb=.75,ZC=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 xl from"node:fs/promises";import Vb from"node:path";async function eM(e){let t=Vb.join(e,".bostrat","events"),n;try{n=await xl.readdir(t)}catch{return ri([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await xl.readFile(Vb.join(t,o),"utf8");for(let a of s.split(`
122
- `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return ri(r)}function tM(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 nM(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=kl(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?["",`## ${zb}, 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 Yb(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await xl.readFile(t,"utf8");if(a.includes(zb))return{appended:!1,reason:"already-enriched"};let i=await eM(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=nM(i,tM(a),{k:r,maxChars:o,exclude:s});return c?(await xl.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 zb,Jb=L(()=>{Hf();zb="Relevant prior discussion (verbatim, retrieved"});function cM(e){return rM.test(String(e||"").trimStart())}function Qb(e){let t=String(e||"");if(!cM(t.trimStart()))return null;let n=t.replace(oM,"").trim(),r=lM(n),o=[];for(let u of aM){let f=u.from.map(d=>ys(r.get(d))).find(d=>d&&!Xb(d));f&&o.push({h:u.h,text:oi(f,sM)})}let s=ys(r.get("Current Work"))||ys(r.get("Primary Request and Intent"))||dM(n),a=Sl(s),i=oi(vl(Kf(a[0]||"")),iM)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(oi(vl(Kf(l)),qf));for(let u of["Pending Tasks","Optional Next Step"]){let f=Sl(ys(r.get(u)))[0]||"";if(!(!f||Xb(f))){c.push(oi(`Left to do: ${vl(Kf(f))}`,qf));break}}if(!c.length){let u=Sl(ys(r.get("Problem Solving"))||"")[0];u&&c.push(oi(vl(u),qf))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function lM(e){let t=new Map,n=[];Wf.lastIndex=0;for(let r=Wf.exec(e);r;r=Wf.exec(e))n.push({name:uM(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 uM(e){return Zb.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 dM(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return ys(t.split(/\n{2,}/).slice(0,2).join(" "))}function Sl(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 vl(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function Xb(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function oi(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=Sl(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 rM,Zb,Wf,oM,sM,aM,iM,qf,ek=L(()=>{rM=/^This session is being continued from a previous conversation that ran out of context\./,Zb=["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}(${Zb.join("|")})[:*\t ]*$`,"gim"),oM=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,sM=420,aM=[{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"]}],iM=116,qf=168});function nk(e){return Gf.has(String(e||"").replace(/^\//,"").toLowerCase())}function Tl(e){let t=String(e||"").trim();if(!t)return null;let n=Qb(t);if(n)return n;let r=t.match(fM);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(pM);if(o)return{kind:"skill",name:o[1]};let s=t.match(mM);if(s){let i=s[1].toLowerCase();return Gf.has(i)?{kind:"suppress"}:{kind:"command",command:`/${i}`}}let a=t.match(TM);if(a&&Gf.has(a[1].toLowerCase()))return{kind:"suppress"};if(hM.test(t))return{kind:"suppress"};if(gM.test(t))return{kind:"suppress"};if(wM.test(t))return{kind:"suppress"};if(yM.test(t)){let i=l=>EM(t.match(l)?.[1].trim()||"")||null,c=i(SM);return{kind:"task",summary:i(bM)||"",taskId:i(kM),toolUseId:i(xM),status:i(vM)?.toLowerCase()||null,resultHead:c?c.length>tk?`${c.slice(0,tk).trimEnd()}\u2026`:c:null}}return null}function EM(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function rk(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 ok(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var fM,pM,mM,hM,wM,gM,yM,bM,kM,xM,vM,SM,tk,Gf,TM,Vf=L(()=>{ek();fM=/^Base directory for this skill:\s*(\S+)/,pM=/^Run the "([^"]+)" workflow\./,mM=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,hM=/^<local-command-(?:stdout|caveat)>/i,wM=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,gM=/^Continue from where you left off\.$/,yM=/^<task-notification>/i,bM=/<summary>([\s\S]*?)<\/summary>/i,kM=/<task-id>([\s\S]*?)<\/task-id>/i,xM=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,vM=/<status>([\s\S]*?)<\/status>/i,SM=/<result>([\s\S]*?)(?:<\/result>|$)/i,tk=600,Gf=new Set(["model","clear","compact","login","exit","quit"]);TM=/^\/([a-z0-9:_-]+)$/i});import AM from"node:crypto";function RM(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,ak)){let o=si(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,_M)){let c=si(i?.label);if(!c)return null;let l=si(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<IM)return null;n.push({question:o,header:si(r?.header).slice(0,$M),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Yf(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;sk.lastIndex=0;let t=null;for(let o;o=sk.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=RM(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function Jf(e,t,n){let r=AM.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=ak}={}){if(!Array.isArray(e)||!t||!zf.has(n))return null;let s=null;for(let l=e.length-1;l>=0;l--){let u=e[l];if(u?.kind==="prompt")return null;if(u?.kind==="message"){if(u.role!=="assistant")return null;s=u;break}}if(!s||s.box!==t||s.agent!==n)return null;let a=s.ask?.questions||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 ik(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=si(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 zf,ak,_M,IM,$M,sk,si,ck,Zf=L(()=>{zf=new Set(["cursor","codex"]),ak=4,_M=4,IM=2,$M=24,sk=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,si=e=>typeof e=="string"?e.trim():"";ck=`
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 OM(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 MM(e,t,n){let r=lk(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=Ue(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=Ue(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,A=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,J=new Map,C=new Map,Q=new Map,ve=new Map,W=new Map,be=new Map,se=new Map,ue=new Map,me=new Map,j=new Map,ie=new Map,le=new Map,Ae=new Map,$e=()=>{for(let y of Ae.values())y.questions.length&&t.push(y);Ae.clear()},He=null,ze=6e4,E=new Map,ne=(y,m)=>{let b=o.get(y);if(!b?.length)return!1;let M=Ue(m),X=s.get(y);return b.some(he=>{if(!M.startsWith(he))return!1;let De=Ue(M.slice(he.length));return!!De&&!!X?.has(De)})};for(let y of e||[]){let m=y.payload||{};switch(y.type){case"turn.user":{if(y.source==="hook"||!String(m.text||"").trim()&&!m.images?.length&&!m.attachments?.length)break;{let b=m.note||Tl(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"&&nk(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:ok(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"&&ne(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"&&(He=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(),He&&He.box===y.boxId&&(t.push(OM(He)),He=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=yb(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}$e();let M=(m.images||[]).filter(Ye=>!k(Ye,fe(y)));if(!String(m.text||"").trim()&&!M.length)break;if(y.provider==="cursor"){let Ye=`${y.boxId}|${m.text}`;if(n.has(Ye))break;n.add(Ye)}(!He||He.box===y.boxId)&&(He=null);let X=y.provider==="codex"?(m.tools||[]).filter(Ye=>!Af.has(Ye)&&!Va.has(Ye)):m.tools||[],he=m.text,De=null;if(zf.has(y.provider)){let Ye=Yf(String(m.text||""));Ye&&(he=Ye.text,De={questions:Ye.questions})}t.push({id:y.id,kind:"message",role:"assistant",text:he,ts:fe(y),box:y.boxId,agent:y.provider,boxRole:m.boxRole,...De?{ask:De}:{},...X.length?{tools:X}:{},...m.model?{model:m.model}:{},...m.sourceId?{sourceId:m.sourceId}:{},...M.length?{images:M}:{}}),De&&(He={id:y.id,groupId:Jf(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 tt=l.get(m.name);tt&&tt.ts>=b&&(M=tt)}let X={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},he=E.get(y.boxId),De=he?.jobs[he.jobs.length-1]?.startedTs;if(he&&De!=null&&b-De<=ze)he.jobs.push(X);else{let tt={id:y.id,kind:"job-dock",dockId:m.id,ts:b,box:y.boxId,agent:y.provider,jobs:[X]};E.set(y.boxId,tt),t.push(tt)}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,CM.has(m.change)&&m.number!=null){let M=MM(S,A,m);if(S.size>=2){for(let he of A.values())for(let De of he)De.grouped=!0;b.groupPrs=[...S.values()];let X=[b];for(let he of S.keys())A.set(he,X)}else{let X=A.get(M)??[];X.push(b),A.set(M,X)}}else if(m.change==="merged"||m.change==="closed"||m.change==="lost"){let M=lk(m),X=R&&!R.complete||S.size>=2;if(S.has(M))S.delete(M),A.delete(M);else if(m.number!=null)for(let he of[...S.keys()])he.endsWith(`#${m.number}`)&&(S.delete(he),A.delete(he));if(X&&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);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 X=t.findIndex(he=>he.kind==="event"&&he.type==="node-update"&&he.latest===M.latest);if(X>=0){let he=t[X];t[X]={...M,ts:he.ts,at:he.at,firstAt:he.firstAt??he.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 J.values())M.status="stale";J.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};J.set(m.proposalId,b),C.set(m.proposalId,b),t.push(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,J.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);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 X of W.values())X.trigger===m.trigger&&(X.status="stale",W.delete(X.offerId));let b=Array.isArray(m.rows)?m.rows:[];for(let X of b){let he=X.armId?se.get(X.armId):null;he&&he.status==="armed"&&(he.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(X=>({followupId:X.followupId??null,armId:X.armId??null,label:X.label??"",prompt:X.prompt??null,promptPreview:X.promptPreview??null,promptHash:X.promptHash??null,origin:X.origin??"operator",why:X.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);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 ue.values())M.status="stale";ue.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};ue.set(m.proposalId,b),me.set(m.proposalId,b),t.push(b);break}case"followup.create.answered":{let b=me.get(m.proposalId);b&&(b.status=m.action==="created"?"created":"dismiss",ue.delete(m.proposalId));break}case"followup.created":{let b=m.proposalId?me.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 X of j.values())X.loopId===m.loopId&&(X.status="stale",X.staleReason="superseded",j.delete(X.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};j.set(m.proposalId,M),ie.set(m.proposalId,M),t.push(M);break}case"loop.update.answered":{let b=ie.get(m.proposalId);b&&(m.action==="moved"?(b.status="stale",b.staleReason="moved"):b.status=m.action==="applied"?"applied":"dismiss",j.delete(m.proposalId));break}case"loop.delete.answered":{let b=ie.get(m.proposalId);b&&(m.action==="moved"?(b.status="stale",b.staleReason="moved"):b.status=m.action==="delete"?"deleted":m.action==="pause"?"paused":"keep",j.delete(m.proposalId));break}case"loop.updated":{let b=m.proposalId?ie.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||le.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};le.set(m.sha,b),t.push(b);break}case"rework.cause.answered":{let b=m.sha?le.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(He=null,m.control||!m.question)break;let b=m.groupId||m.promptId;if(!b)break;let M=Ae.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)},Ae.set(b,M));let X=m.questionIndex??0,he={index:X,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:Array.isArray(m.chosen)?m.chosen:[]},De=M.questions.findIndex(tt=>tt.index===X&&Ue(tt.question)===Ue(he.question));De>=0?M.questions[De]=he:M.questions.push(he),M.questions.sort((tt,rr)=>tt.index-rr.index),M.questionTotal=Math.max(M.questionTotal,m.questionTotal??1),M.questions.length>=M.questionTotal&&(t.push(M),Ae.delete(b));break}default:break}}let Ke=u.size?t.filter(y=>!y.retired):t;return PM(Ke.sort((y,m)=>(y.ts??0)-(m.ts??0)))}function PM(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<=NM){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:DM(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 ub(n,r)}function DM(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 uk(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)+BM,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&jM.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function dk(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!FM.has(r.type)||!r.box)continue;let o=(r.ts??0)+LM,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 fk(e){return(e||[]).filter(t=>UM.has(t?.kind)&&t.status==="open")}var fe,CM,lk,NM,BM,jM,LM,FM,UM,ep=L(()=>{ms();io();ul();yl();Vf();Zf();fe=e=>e.payload?.ts??e.ts;CM=new Set(["opened","ci-fixed","reconciled","pushed"]),lk=e=>`${e.repo??""}#${e.number}`;NM=2*6e4;BM=12e4,jM=new Set(["archived","unarchived","opened"]);LM=2500,FM=new Set(["pr-opened","pr-merged","pr-auto-armed"]);UM=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 GM(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 zM(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 YM(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<qM&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<KM&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function wk(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=GM(e),s=zM(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(-HM);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(hk[r]??hk.failover),l.push(""),o.lastPush?.sha){let d=mk(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=mk(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=YM(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"}:** ${VM(d.text,WM)}`),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<=pk?f:`${f.slice(0,pk)}
152
-
153
- [\u2026 brief truncated]`}var HM,WM,pk,qM,KM,VM,mk,hk,gk=L(()=>{ep();HM=12,WM=2e3,pk=48e3,qM=30,KM=10;VM=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},mk=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;hk={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 JM from"node:fs";import gr from"node:fs/promises";import yr from"node:path";function Ek(e){let t=no(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=yk?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,yk).toString("utf8").replace(/�+$/,"")}
154
-
155
- [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function sN(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(kk.test(s)){if(r.length>=Ok)continue;let a=oN(s.replace(kk,"").replace(/[.;,:]+$/,""),Ck,nN);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>bk&&(o=`${o.slice(0,bk-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function Mk(e,t,{timeoutMs:n=9e4}={}){let r=yr.join(t,eN),o=yr.join(r,tN);await gr.mkdir(r,{recursive:!0});let s=await El(o),a=await ge(e);if(!a)throw new Error(`session "${e}" not found`);return await Al(e,a,rN(o)),await Fk(o,s,n),sN(await gr.readFile(o,"utf8"))}function Nk(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===_k||n===Rk;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(Ak)||n===XM||r.startsWith(Ik)||r.startsWith($k)}function Pk(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-aN;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 Dk(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 Bk(e,{windows:t=[]}={}){if(Nk(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 _l(e){return tp.get(e)||null}async function jk(e){let t=tp.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,Sk,Tk)};return tp.set(e,r),lN(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function lN(e,t){e.step="summarize",await Lk(e.name,t),e.step="clear";let n=await ge(e.name);await Al(e.name,n,"/clear"),await op(iN),e.step="resume",await Al(e.name,n,QM),e.step="done",e.finishedAt=Date.now()}async function Lk(e,t,{timeoutMs:n=cN}={}){let r=yr.join(t,Sk),o=yr.join(r,Tk);await gr.mkdir(r,{recursive:!0});let s=await El(o),a=await ge(e);await re({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await Al(e,a,ZM(o)),await Fk(o,s,n),await re({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await El(o)});let i=await Yb(t,o,{exclude:u=>Nk(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:{...Ek(u),ts:Date.now()}})}catch{}}await Qd(t);let l=await uN(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 ge(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);return Lk(e,n.cwd,t?{timeoutMs:t}:void 0)}async function rp(e,t,{trackName:n="this Track"}={}){let r=await F({id:e,cwd:t}),o=wk(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=yr.join(t,xk);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:{...Ek(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),xk}async function El(e){try{return(await gr.stat(e)).mtimeMs}catch{return 0}}async function Fk(e,t,n){let r=Date.now()+n;for(;;){if(await El(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 uN(e,t){try{if(!JM.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 op(e){return new Promise(t=>setTimeout(t,e))}function vk(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 Al(e,t,n){if(t){let o=vk(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 Be(e,["Escape"],{kind:"drive-wipe"}),await op(150),await ls(e,il,{kind:"drive-wipe"}),await Qe(e,n,{kind:"orchestration-drive",...un(r.agent,n)}),await ti({sessionName:e,agent:r.agent,agentCmd:vk(r.agent),text:n,flow:"orchestration-drive"})}var Sk,Tk,yk,Ak,_k,Ik,XM,ZM,QM,$k,Rk,eN,tN,bk,Ok,Ck,nN,rN,kk,oN,aN,iN,cN,tp,xk,sp=L(()=>{lt();Xa();cn();Za();Uf();Jb();Ra();de();Zc();gk();Sk=".bostrat/handoff",Tk="latest.md",yk=32*1024;Ak="Checkpoint: write a work-in-progress handoff",_k="HANDOFF WRITTEN",Ik="Resume from .bostrat/handoff/latest.md",XM="/clear",ZM=e=>`${Ak} 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.`,QM=`${Ik}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,$k="Beat: write a",Rk="BEAT WRITTEN",eN=".bostrat/arc",tN="beat.txt",bk=200,Ok=4,Ck=5,nN=36,rN=e=>`${$k} 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 ${Ok} further lines, each starting with "- " and naming ONE piece in at most ${Ck} 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 ${Rk} and take no further action.`,kk=/^(?:[-–—*•·]|\d+[.)])\s+/,oN=(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};aN=6e5;iN=3500,cN=3e5,tp=new Map;xk=".bostrat/handoff/status-latest.md"});function kr(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!Il.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 Wk(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 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 fN(e){if(!e)return null;let t=String(e).trim();return br[t]?t:Uk[t]?Uk[t]:Object.keys(br).find(r=>t.startsWith(r))||null}function pN(e){if(!e||e===br)return dN;let t=Hk.get(e);return t||(t=Wk(e),Hk.set(e,t)),t}function qk(e,t,n={}){let{table:r,speed:o}=n,s=pN(r),a=r&&r!==br?s[e]?e:null:fN(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 dn(e,t={},n,r){let o=qk(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 mN(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`),Il.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 wN({now:e=Date.now(),table:t=br,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...hN,...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:kr(f.from,"from",c),toMs:kr(f.to,"to",c),verifiedMs:Il.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 bs({now:e=Date.now(),table:t=br,...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=kr(l.from,"from",i),f=kr(l.to,"to",i);r>=u&&r<=f&&Il.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=[...mN(t),...wN({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var br,Uk,Il,dN,Hk,Kk,hN,ap,Pn=L(()=>{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)."}]},Uk={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"},Il=/^\d{4}-\d{2}-\d{2}$/;dN=Wk(br);Hk=new WeakMap;Kk=(e,t,n)=>qk(e,t,n)!==null;hN=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),ap=864e5});function gN(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function Vk(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Bt(e){let t=e.payload?.model||"unknown",n=gN(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=dn(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&&!Kk(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=Gk();for(let d of n){let{usd:p,model:h,tokens:w,repriced:g,unpriced:k,asRecorded:S}=Bt(d);i+=S;let A=d.provider||"unknown",R=d.boxId||"unattributed";if(g&&c++,k&&(l++,u.add(h)),a+=p,Vk(f,w),r[h]||={usd:0,tokens:Gk(),events:0},r[h].usd+=p,r[h].events+=1,Vk(r[h].tokens,w),o[A]||={usd:0,events:0},o[A].usd+=p,o[A].events+=1,s[R]||={usd:0,events:0,provider:A,models:new Set,label: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:A,models:new Set};B.usd+=p,B.events+=1,B.provider=A,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:$l(r,d=>({...d,usd:ks(d.usd)})),byProvider:$l(o,d=>({...d,usd:ks(d.usd)})),byBox:$l(s,d=>({usd:ks(d.usd),events:d.events,provider:d.provider,label:d.label,models:[...d.models],...d.epochs?{epochs:$l(d.epochs,p=>({usd:ks(p.usd),events:p.events,provider:p.provider,models:[...p.models]}))}:{}}))}}var Gk,ks,$l,vr=L(()=>{Pn();Gk=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});ks=e=>Math.round(e*1e4)/1e4,$l=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function yN(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 zk(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=xr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?yN(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var cp,Yk=L(()=>{vr();cp=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as bN}from"node:child_process";import{promisify as kN}from"node:util";import{randomUUID as xN}from"node:crypto";async function lp(e,t){let n=Date.now()+t;for(;;){if(await Cn(e))return!0;if(Date.now()>n)return!1;await ai(SN)}}async function EN(e,t){let n=Xk[t]||Xk.default;n.escape&&(await Be(e,["Escape"],{kind:"swap-exit"}),await ai(150)),n.wipe&&await ls(e,il,{kind:"swap-exit"}),await cl(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=un(t).submitDelayMs||0;await ai(Math.max(r,250)),await Be(e,["Enter"],{kind:"swap-exit"})}async function Zk(e,t){try{let{stdout:n}=await lo(K,G("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function Qk(e){await lo(K,G("respawn-pane","-k","-t",e))}async function up(e,t={}){if(!Ne(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)||vN;await re({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let i=!1;if(!await Cn(e)&&(await EN(e,o),!await lp(e,a)&&(i=!0,await re({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await Qk(e),!await lp(e,Jk))))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);let c=s==="claude"&&ro(n),l=c?Mc():null,u=await Zk(e,"ANTHROPIC_API_KEY"),f=!1;try{l?(await lo(K,G("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),f=!0):u&&(await lo(K,G("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),f=!0)}catch(g){throw l?tl(g,l):g}if(f&&!i&&(await Qk(e),!await lp(e,Jk)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let d=!!t.resumeSessionId,p=t.resumeSessionId||xN(),h=d?n:Fa(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,G("set-option","-t",e,"@bostrat-sid",p)),await lo(K,G("set-option","-t",e,"@bostrat-agent",s)),await ai(TN),c&&La().length&&(await Zk(e,ja)||await lo(K,G("set-environment","-t",e,ja,"1")).catch(()=>{}),await Qe(e,`export ${ja}=1`,{kind:"swap-env"}),await ai(150)),await Qe(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,ai,vN,Jk,SN,TN,Xk,e0=L(()=>{lt();Sa();Pc();Dc();Za();cn();lo=kN(bN),ai=e=>new Promise(t=>setTimeout(t,e)),vN=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,Jk=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,SN=250,TN=400,Xk={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 t0(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await St(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&&AN.test(_N(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 AN,_N,n0=L(()=>{zt();ms();AN=/^Async (?:agent|task) launched/i,_N=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 IN(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 r0(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:Yt(`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 ${dp(t.glob)}`:"",a=Yt(String(r),40);return{command:Yt(`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?Sr(t.target_directory,n):null;return{command:Yt(`glob ${dp(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${Yt(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:Yt(`edit ${Sr(t.path,n)}`,140),description:`Edit ${xs(t.path)}`}:null;case"Write":return t?.path?{command:Yt(`write ${Sr(t.path,n)}`,140),description:`Write ${xs(t.path)}`}:null;case"Delete":return t?.path?{command:Yt(`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:Yt(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=IN(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:Yt(`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:Yt(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var Rl,Yt,xs,dp,o0=L(()=>{Rl=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),Yt=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,xs=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);dp=e=>`"${String(e).replace(/"/g,'\\"')}"`});import ii from"node:fs";import $N from"node:fs/promises";import uo from"node:path";import RN from"node:os";import ON from"node:crypto";import CN from"node:zlib";function i0(e){let t=ON.createHash("md5").update(String(e)).digest("hex");return uo.join(MN,t)}function c0(e){try{let t=JSON.parse(ii.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 NN(e){let t=i0(e),n;try{n=ii.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(!ii.existsSync(a))continue;let i=c0(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 Ol(e,t){if(!e)return null;if(t){let n=uo.join(i0(e),t),r=uo.join(n,"store.db");if(ii.existsSync(r))return{id:t,dir:n,store:r,...c0(n)||{createdAtMs:null,updatedAtMs:null}}}return NN(e)}function s0(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function PN(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=CN.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function DN(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 BN(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!Rl.has(r.toolName))continue;let o=r0(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(!a0)return vs;let{DatabaseSync:n}=a0,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?s0(r,s.latestRootBlobId):null;if(!i)return{...vs,model:a};let c=[],l=[],u=[],f=null,d=[];for(let p of DN(i)){let h=PN(s0(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 A=S?.providerOptions?.cursor?.modelName;A&&(f=A)}l.push(...BN(h.content,t).map((S,A)=>({...S,id:S.id||`${p}:${A}`}))),u.push(...LN(h.content));let g=jN(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 l0(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(ii.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 u0(e,t,{limit:n=80}={}){let r=Ol(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}=l0(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 d0(e,t){let n=Ol(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 f0(e,t,{limit:n=80}={}){let r=Ol(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}=l0(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 p0(e,t){let n=Ol(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await $N.stat(n.store)).mtimeMs)}catch{return null}}var MN,jN,LN,a0,vs,pp=L(()=>{ms();o0();MN=process.env.BOSTRAT_CURSOR_CHATS||uo.join(RN.homedir(),".cursor","chats");jN=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():"",LN=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],a0=process.getBuiltinModule?.("node:sqlite"),vs={turns:[],trailingCommands:[],model:null,requestIds:[]}});import FN from"node:fs/promises";function gp(e){return m0.set(e.agent,e),e}function ci(e){return m0.get(e)||UN}async function bp(e,t={}){return(await ci(e.agent).readMessages(e,t)).map(yp(e))}async function h0(e,t={}){return(await ci(e.agent).readCommands(e,t)).map(yp(e))}async function w0(e,t={}){return(await ci(e.agent).readJobs(e,t)).map(yp(e))}var Ss,mp,hp,wp,UN,m0,yp,g0=L(()=>{zt();dl();ms();n0();pp();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}},mp=class extends Ss{transcript(t){return!t?.cwd||!t?.sessionId?null:Vt(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?lb(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?t0(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await FN.stat(n)).mtimeMs)}catch{return null}}},hp=class extends Ss{async readMessages(t,n){return u0(t.cwd,t.sessionId,n)}async readCommands(t,n){return f0(t.cwd,t.sessionId,n)}async updatedAt(t){return p0(t.cwd,t.sessionId)}},wp=class extends Ss{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))}},UN=new Ss("unknown"),m0=new Map;gp(new mp("claude",Sf));gp(new hp("cursor",Rl));gp(new wp("codex",Va));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 HN(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function WN(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 qN(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=KN(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function KN(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 b0(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function GN(e,t=""){let n=String(e);if(!x0.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 zN(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||!v0.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&&!(VN.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 YN(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 XN(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(JN.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 ZN(e,t=""){let n=String(e);if(!S0.test(n)||!T0.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 QN(e,t=""){let n=String(e);if(!E0.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 tP(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!eP.test(o)||Ep.test(e[r]))break;n+=o}return n}function nP(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=tP(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 oP(e,t=""){let n=String(e);if(!xp.test(n)||!rP.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 sP(e,t=""){let n=String(e);if(!A0.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 aP(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 iP(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 cP(e,t=""){let n=String(e);if(!k0.test(n)||!vp.test(n))return null;let r=n.replace(/\r/g,"").split(`
168
- `),o=iP(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||WN(r[I])||y0.test(U))){O.desc=HN(U);break}}let f=l.filter(O=>!y0.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?b0(r[s]):"")||"The agent is asking a question",k=s>=0?qN(r[s],g):null,S=k?.currentTabLabel||(s>=0?b0(r[s]):""),A=f.map(O=>({label:mo(O.label),description:O.desc})),R=A.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:A}]}}function wo(e,t){let n=String(t||"");return n?e==="claude"?k0.test(n)&&vp.test(n)||x0.test(n)||kp.test(n)||v0.test(n.trimEnd().split(`
169
- `).pop()||"")?!0:ho.test(n)?!1:S0.test(n)&&T0.test(n)||E0.test(n)||Ep.test(n)||xp.test(n)||A0.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 Tr(e,t){return!e||!t?null:e.agent==="claude"?YN(t,e.name)||cP(t,e.name)||GN(t,e.name)||XN(t,e.name)||oP(t,e.name)||nP(t,e.name)||QN(t,e.name)||ZN(t,e.name)||sP(t,e.name)||aP(t,e.name)||zN(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 Mn(e.name).catch(()=>"");return Tr(e,t)}function I0(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 $0(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 k0,vp,fo,y0,po,Sp,x0,v0,VN,kp,JN,ho,S0,T0,E0,Ep,eP,xp,rP,A0,_0,_p=L(()=>{lt();pl();k0=/to navigate\b.*\bEsc to cancel|Enter to select\b/,vp=/Chat about this/i,fo=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,y0=/^(type something|chat about this|submit)\b/i,po=/^[─—-]{6,}\s*$/,Sp=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;x0=/^\s*Switch model\?\s*$/m;v0=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,VN=/^\s*[─—▔-]{6,}\s*$/;kp=/Resume from summary/i,JN=/^\s*This session is\b/;ho=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;S0=/Choose the text style that looks best with your terminal/,T0=/Let's get started\./;E0=/Select login method:/;Ep=/Paste code here if prompted/,eP=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;xp=/OAuth error:/,rP=/Press Enter to retry\./;A0=/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 Cl(e,t,n){if(!e||!t)return null;for(let r of lP)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function dP(e){let t=Ip.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},Ip.set(e,t)),t}function C0(e,t,n=Date.now()){let r=dP(e);if(r.sentAt=r.sentAt.filter(s=>n-s<O0),r.sentAt.length>=R0)return{action:"give-up"};if(n-r.last<uP)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 M0(e,t=Date.now()){let n=Ip.get(e);return n?n.sentAt.filter(r=>t-r<O0).length>=R0:!1}var lP,uP,R0,O0,Ip,$p=L(()=>{lP=[{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"]}];uP=5e3,R0=5,O0=3600*1e3,Ip=new Map});function Ts(e){return typeof e=="string"?e.trim():""}var N0=L(()=>{});import{execFile as fP}from"node:child_process";import{promisify as pP}from"node:util";async function Le(e,t,{input:n}={}){let r=Op("git",["-C",e,...t],{maxBuffer:P0});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 Le(e,["rev-parse","--is-inside-work-tree"]);return t.trim()==="true"}catch{return!1}}async function D0(e){let{stdout:t}=await Le(e,["rev-parse","--show-toplevel"]);return t.trim()}async function mP(e){try{return await Le(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function As(e,t="bostrat: subtask snapshot"){let{stdout:n}=await Le(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:P0,env:o,...i});try{let a=await mP(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 Le(e,["status","--porcelain"]);return r.trim()?(await Le(e,["add","-A"]),await Le(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",t,...n.flatMap(o=>["--trailer",o])]),!0):!1}async function li(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await Le(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 ui(e,t){if(!t)return 0;try{let{stdout:n}=await Le(e,["rev-list","--count",`${t}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function _s(e,t,n,r){return await Le(e,["worktree","add","--no-track","-b",n,t,r]),t}async function B0(e,t){try{return await Le(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function Ml(e,t,n){return await Le(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 Le(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 Le(e,["rev-parse","--verify","--quiet",t]),n}catch{}return"HEAD"}async function Mp(e){await Le(e,["init","-q"]),await Le(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function _t(e,t){try{await Le(e,["worktree","remove","--force",t])}catch{try{await Le(e,["worktree","prune"])}catch{}}}function hP(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 Le(e,Np(["diff","--shortstat",t,n],r));return hP(o)}async function Dp(e,t,n,r){let{stdout:o}=await Le(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 Le(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 wP(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 Le(e,["apply",...n,"-"],{input:t}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function wP(e){try{let{stdout:t}=await Le(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
174
- `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var Op,P0,Nl=L(()=>{Op=pP(fP),P0=64*1024*1024});function Pl(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!gP.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 Ge,gP,Dn=L(()=>{Ge=e=>!!(e&&(e.archivedAt||e.transferredTo)),gP=new Set(["merged","conflict","canceled","failed","handed-off"])});import jp from"node:fs/promises";import L0 from"node:path";import yP from"node:os";function W0(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function q0(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function K0(e){let t=new Date(W0(e));return t.setDate(t.getDate()+7),t.getTime()}function G0(e){let t=new Date(q0(e));return t.setMonth(t.getMonth()+1),t.getTime()}function Bl(e=Date.now()){for(let[t,n]of Object.entries($s)){let r=n.startOf(e);if(r!==Bn[t]){Bn[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 V0(e,t){let n=Jt?.caps?.[e]?.[$s[t].capKey];return Number.isFinite(n)&&n>0?n:null}function yo(e,t=Date.now()){if(!e||!Fp||!Jt?.caps)return null;Bl(t);let n=go.get(e);for(let r of Object.keys($s)){let o=V0(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:Dl(s),resetsAt:$s[r].nextStart(t)}}return null}function z0(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${Bn[t.window]}`;return Rs.has(n)?!1:(Rs.add(n),!0)}function j0(e,t,n,r=Date.now()){if(!e||!t)return;Bl(r);let o=bP(e);for(let[s,a]of Object.entries($s))n>=Bn[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function kP(e,t,n=Date.now()){if(!Jt?.caps||!Lp)return;let r=go.get(e);if(r)for(let[o,s]of Object.entries($s)){let a=V0(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*H0||i>=a)continue;let c=`warn:${e}:${o}:${Bn[o]}`;if(!Rs.has(c)){Rs.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:Dl(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function Y0(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 jl(e,{source:t="local",updatedAt:n=Date.now()}={}){Jt={caps:Y0(e),updatedAt:n,source:t};try{await jp.mkdir(F0,{recursive:!0}),await jp.writeFile(U0(),JSON.stringify(Jt,null,2))}catch{}return di()}function di(e=Date.now()){Bl(e);let t=new Set([...go.keys(),...Object.keys(Jt?.caps||{})]),n={};for(let r of t){let o=go.get(r);n[r]={weeklyUsd:Dl(o?.weekly||0),monthlyUsd:Dl(o?.monthly||0)}}return{caps:Jt?.caps||{},configured:!!Jt,seeded:Fp,updatedAt:Jt?.updatedAt??null,spent:n,windows:{weekly:{start:Bn.weekly,resetsAt:K0(e)},monthly:{start:Bn.monthly,resetsAt:G0(e)}},warnPct:H0}}async function J0({listTracks:e,getTrack:t}={}){Lp=t||null,Bl();try{let o=JSON.parse(await jp.readFile(U0(),"utf8"));Jt={caps:Y0(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{Jt=null}let n=Date.now();ct.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Bt(o);j0(o.provider||"unknown",s,o.ts??Date.now()),kP(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(Bn.weekly,Bn.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||j0(a.provider||"unknown",Bt(a).usd,i,n)}}return Fp=!0,di()}var F0,U0,H0,$s,Jt,Fp,Bn,go,Rs,Lp,bP,Dl,Ll=L(()=>{de();vr();F0=process.env.BOSTRAT_STATE_DIR||L0.join(process.env.HOME||yP.tmpdir(),".bostrat"),U0=()=>L0.join(F0,"usage-caps.json"),H0=.8;$s={weekly:{startOf:W0,nextStart:K0,capKey:"weeklyUsd"},monthly:{startOf:q0,nextStart:G0,capKey:"monthlyUsd"}},Jt=null,Fp=!1,Bn={weekly:0,monthly:0},go=new Map,Rs=new Set,Lp=null,bP=e=>{let t=go.get(e);return t||(t={weekly:0,monthly:0},go.set(e,t)),t};Dl=e=>Math.round(e*1e4)/1e4});import xP from"node:fs/promises";import vP from"node:os";import X0 from"node:path";function ox(e){return e==="codex"?AP:e==="cursor"?rx:tx}function Z0(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 Q0(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 _P(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 ex(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 sx(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&&!nx.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=rx.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!EP.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function fi(e,t,{timeoutMs:n=SP}={}){let r=Date.now()+n;for(;;){let o=await Oe(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await Fl(TP)}}async function IP(e,t){return await Qe(e,`/model ${t.model}`,un("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function $P(e,t){await al(e),await Qe(e,"/model",{enter:!1}),await Fl(250),await Be(e,["Enter"],{kind:"model-switch"});let n=await fi(e,Z0);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await Be(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=_P(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await Qe(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await fi(e,i=>Q0(i)||!Z0(i)&&o(i)&&{done:o(i)});if(!s)throw await Be(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?nx.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 Be(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await Qe(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await fi(e,i=>!Q0(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 RP(){let e=X0.join(process.env.CURSOR_CONFIG_DIR||X0.join(vP.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await xP.readFile(e,"utf8"))?.model||null}catch{return null}}async function OP(e,t){await al(e),await cl(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await fi(e,ex),r=c=>String(c||"").toLowerCase(),o=c=>r(c.label).startsWith(r(t.filter)),s=n?.rows.find(c=>c.active)||null;if(n&&!(s&&o(s)))for(let c=0;c<12;c++){let l=await fi(e,ex,{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 Be(e,["Down"],{kind:"model-switch"}),await Fl(250)}if(!n||!s||!o(s)){await Be(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await Be(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 Be(e,["Enter"],{kind:"model-switch"}),await Fl(800);let a=await RP();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 ax(e,t,n){return e==="codex"?$P(t,n):e==="cursor"?OP(t,n):IP(t,n)}var Fl,SP,TP,tx,EP,AP,nx,rx,ix=L(()=>{lt();Za();Fl=e=>new Promise(t=>setTimeout(t,e)),SP=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,TP=300,tx=[{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"}],EP=new Set([...tx.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"]),AP=[{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"}],nx=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),rx=[{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 Hl(e){let t=e||{},n=CP(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function CP(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:wt(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:wt(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:wt(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:wt(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:wt(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:wt(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:wt(e.agent),payload:{...Er(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:wt(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:wt(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:wt(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:wt(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:wt(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:wt(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};default:return null}}function ux(e,t){let n=Hl(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;Hp(()=>$(r,n))}async function dx(e){if(!(!e?.id||cx.has(e.id))){cx.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=Hl(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 fx(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:wt(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:wt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var wt,Ul,Hp,lx,cx,Up,qp=L(()=>{de();wt=e=>e||null;Ul=Promise.resolve(),Hp=e=>(Ul=Ul.then(e).catch(()=>{}),Ul),lx=()=>Ul;cx=new Set;Up=new Map});function BP(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function yx(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of BP(n).reverse()){if(!MP.test(r))continue;let o=r.endsWith("?")&&r.length<=DP&&PP.test(r);if(NP.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function kx(e){let t=String(e||""),n=[];jP.test(t)&&n.push("commit"),bx.test(t)&&n.push("rebase"),LP.test(t)&&n.push("push");let r=UP.test(t);!r&&FP.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 xx(e){return bx.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 vx(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 Sx(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<=HP&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function Tx(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+WP||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function Ex(e){let t=(Array.isArray(e)?e:[]).filter(r=>px[r]).map(r=>px[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 mx,hx,wx,gx,MP,NP,PP,DP,Ar,jP,bx,LP,FP,UP,HP,WP,px,bo=L(()=>{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|amend(?:ed)?|squash|merge|follow[\s-]?up|clean[\s-]?up)\s)commit(?!s\b)(?!\s+(?:history|log|message|hash|sha)s?\b)/.source,hx=/(?<!\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,wx=/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,gx=/(?<!\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,MP=new RegExp(`\\b(?:${mx}|${hx}|${wx}|${gx})\\b`,"i"),NP=/\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,PP=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,DP=90;Ar=["commit","rebase","push","pr"],jP=new RegExp(`\\b(?:${mx})\\b`,"i"),bx=new RegExp(`\\b(?:${gx})\\b`,"i"),LP=new RegExp(`\\b(?:${hx})\\b`,"i"),FP=new RegExp(`\\b(?:${wx})\\b`,"i"),UP=/\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;HP=3e4;WP=2500;px={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import qP from"node:crypto";import Wl from"node:fs/promises";import Ax from"node:path";import KP from"node:os";async function Fe(){return _r||(Kp??=Wl.readFile(Vp,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(_r=e,!t&&Me()){let{records:n,source:r}=await nt("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 zp().catch(()=>{})}}return _r}).finally(()=>Kp=null),Kp)}async function zp(){let e=JSON.stringify({links:_r},null,2),t=`${Vp}.${process.pid}.tmp`;await Wl.mkdir(_x,{recursive:!0}),await Wl.writeFile(t,e),await Wl.rename(t,Vp)}async function et(e){Gp=Gp.then(zp,zp),await Gp.catch(()=>{});let t=_r?.[e];t&&ht("prlinks",{id:Ix(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function It({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 Fe(),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:GP.has(a),firstSeen:Date.now()},await et(oe(e,t)),{link:i[c],created:!0})}async function jn(e,t){if(!e||t==null)return null;let n=(await Fe())[oe(e,t)];return!n||n.announced?null:(n.announced=!0,await et(oe(e,t)),n)}async function rt(e,t){return!e||t==null?null:(await Fe())[oe(e,t)]??null}async function Ir(e,t,n){if(!e||t==null)return null;let r=(await Fe())[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 et(oe(e,t)),r):null}async function $x(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Fe())[oe(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await et(oe(e,t)),o):null}async function Rx(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Fe())[oe(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await et(oe(e,t)),o):null}async function ql(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Fe())[oe(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await et(oe(e,t)),r)}async function Kl(e,t){if(!e||t==null)return null;let n=(await Fe())[oe(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await et(oe(e,t)),n)}async function Gl(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Fe())[oe(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await et(oe(e,t)),r)}async function Vl(e,t){if(!e||t==null)return null;let n=(await Fe())[oe(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await et(oe(e,t)),n)}async function Ox(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await Fe())[oe(e,t)];return r?(r.baseFoldAt=n,await et(oe(e,t)),r):null}async function Cx(e,t){if(!e||t==null)return null;let n=(await Fe())[oe(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await et(oe(e,t)),n)}async function Mx(e,t,n){if(!e||t==null||!n)return null;let r=(await Fe())[oe(e,t)];return r?(r.lastHeadSha=n,await et(oe(e,t)),r):null}async function Nx(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await Fe())[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 et(oe(e,t))),{prev:o,link:r}}async function pi(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await Fe())[oe(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await et(oe(e,t)),r):null}async function ko(e,t,n=!0){if(!e||t==null)return null;let r=(await Fe())[oe(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await et(oe(e,t)),r):null}async function mi(e,t,n=!0){if(!e||t==null)return null;let r=(await Fe())[oe(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await et(oe(e,t)),r):null}async function Px(e,t,n){if(!e||t==null)return null;let r=(await Fe())[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 et(oe(e,t)),r}async function Dx(e,t,n){if(!e||t==null)return null;let r=(await Fe())[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 et(oe(e,t)),r}async function hi(e,t){if(!e||t==null)return null;let n=(await Fe())[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 et(oe(e,t)),n)}async function Bx(){return Object.values(await Fe()).filter(e=>!VP.has(e.state))}async function xo(){return Object.values(await Fe()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function jx(){if(!Me())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await nt("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Fe(),r=0;for(let[o,s]of Object.entries(n))await ht("prlinks",{id:Ix(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var _x,Vp,oe,Ix,_r,Kp,Gp,GP,VP,Ln=L(()=>{ur();_x=process.env.BOSTRAT_STATE_DIR||Ax.join(process.env.HOME||KP.tmpdir(),".bostrat"),Vp=Ax.join(_x,"pr-links.json"),oe=(e,t)=>`${e}#${Number(t)}`,Ix=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=qP.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},_r=null,Kp=null,Gp=Promise.resolve();GP=new Set(["api","observed","reconciled"]);VP=new Set(["merged","closed","lost"])});import zP from"node:fs";import Yp from"node:fs/promises";import Hx from"node:path";import YP from"node:os";function Kx(e,t=!1){if(!t&&e-Fx<JP)return;Fx=e;let n=JSON.stringify({windowStart:Cs,byCaller:Object.fromEntries(Fn),lastHour:$r});Ux=Ux.then(()=>Yp.mkdir(Wx,{recursive:!0})).then(()=>Yp.writeFile(`${zl}.tmp`,n)).then(()=>Yp.rename(`${zl}.tmp`,zl)).catch(()=>{})}function Gx(e){e-Cs<qx||($r={start:Cs,total:Yl(Fn),byCaller:Object.fromEntries(Fn)},$r.total&&console.log(`[github] ${$r.total} calls last hour`,$r.byCaller),Cs=e,Fn=new Map,Kx(e,!0))}function Un(e="other",t=Date.now()){Gx(t),Fn.set(e,(Fn.get(e)||0)+1),Kx(t)}function Vx(e=Date.now()){return Gx(e),{windowStart:Cs,total:Yl(Fn),byCaller:Object.fromEntries(Fn),lastHour:$r,backoffUntil:vo>e?vo:null}}function Rr(e){return XP.test(String(e?.message||e||""))}function Or(e,t=Date.now()){return vo<=t&&console.warn(`[github] rate limited \u2014 backing off ${Lx/6e4} min:`,String(e?.message||e||"").slice(0,200)),vo=Math.max(vo,t+Lx),vo}function Jl(e=Date.now()){return Math.max(0,vo-e)}var Wx,zl,qx,Lx,JP,Cs,Fn,$r,vo,Fx,Yl,Ux,XP,wi=L(()=>{Wx=process.env.BOSTRAT_STATE_DIR||Hx.join(process.env.HOME||YP.tmpdir(),".bostrat"),zl=Hx.join(Wx,"github-metrics.json"),qx=60*6e4,Lx=5*6e4,JP=6e4,Cs=Date.now(),Fn=new Map,$r=null,vo=0,Fx=0,Yl=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(zP.readFileSync(zl,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<qx?(Cs=e.windowStart,Fn=new Map(Object.entries(e.byCaller||{})),$r=e.lastHour||null):Yl(new Map(Object.entries(e.byCaller||{})))&&($r={start:e.windowStart,total:Yl(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}Ux=Promise.resolve();XP=/rate limit|too quickly|abuse detection|HTTP 429/i});import zx from"node:fs/promises";import Yx from"node:path";import ZP from"node:os";function Zl({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};Xl.push(l),Xl.length>eD&&Xl.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),tD(l),l}async function tD(e){try{await zx.mkdir(Jx,{recursive:!0}),await zx.appendFile(QP,JSON.stringify(e)+`
179
- `)}catch{}}function Xx(){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:Xl.slice(-20)}}var Jx,QP,eD,Xl,Jp,Ql=L(()=>{Jx=process.env.BOSTRAT_STATE_DIR||Yx.join(process.env.HOME||ZP.tmpdir(),".bostrat"),QP=Yx.join(Jx,"github-latency.ndjson"),eD=100,Xl=[],Jp=new Map});import{execFile as nD}from"node:child_process";import{promisify as rD}from"node:util";async function oD(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 jt(e,t,n={}){let{caller:r="prs",...o}=n,s=await sn({cwd:e});Un(r);try{let{stdout:a}=await Ns("gh",t,{cwd:e,...sD,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw Rr(a)&&Or(a),a}}async function Qp(){if(eu&&Date.now()-eu.at<6e4)return eu.data;let e;try{Un("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 Aa();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return eu={at:Date.now(),data:e},e}async function aD(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 Qx(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(Qx),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 tv(e,t){if(!t)return null;let n=await Se(e);if(!n)return null;try{let r=await jt(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 nv(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 rv(e,t){let n=await tv(e,t);return n===null?{...Xp([]),unavailable:!0}:Xp(nv(n))}function tu(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 cD(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)<iD}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 Hn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await jt(n.path,["pr","view",String(r),"--json",em]);return tu(JSON.parse(o))}catch(o){if(!tm(o))throw o;let s=await jt(n.path,["pr","view",String(r),"--json",ev]),a=JSON.parse(s);return tu(a,await rv(n.path,a.headRefOid))}}async function fn(e,{caller:t="prs"}={}){try{let n=await jt(e,["pr","list","--json",em,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>tu(r)).sort(Zx)}catch(n){if(!tm(n))throw n;let r=await jt(e,["pr","list","--json",ev,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>tu(o,await rv(e,o.headRefOid))))).sort(Zx)}}function mn(){gi.clear()}async function dD(e,t){if(!e)return t;for(let n of t){let r=await rt(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 ql(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await Gl(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function ov(){let e=await Qp();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await Rn())await aD(a.path)&&t.push(a);let n=Date.now(),r=Jl(n)>0,o=await Promise.all(t.map(async a=>{let i=gi.get(a.path),c=i?.pending?uD:lD;if(i&&(r||n-i.at<c))return i.entry;try{let l=await Se(a.path).catch(()=>null),u=cD(a.path,await fn(a.path,{caller:"tab"}),n);if(await dD(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&&Zl({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 gi.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:pn(l)}}})),s=new Set(t.map(a=>a.path));for(let a of gi.keys())s.has(a)||gi.delete(a);return{auth:e,repos:o}}async function Hn(e){let t=(await Rn()).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 Hn(e);if(!yi.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 sn({cwd:r.path})).GH_TOKEN){let a=await Hd().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await jt(r.path,s)}catch(a){throw new Error(pn(a))}finally{mn()}return{ok:!0,number:o}}async function bi(e,t){let n=await Hn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await jt(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(pn(s))}finally{mn()}let o=await Se(n.path).catch(()=>null);return o&&await Ox(o,r).catch(()=>{}),{ok:!0,number:r}}async function nm(e,t){let n=await Hn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await jt(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(pn(o))}finally{mn()}return{ok:!0,number:r}}function rm(e){return e.green&&!e.isDraft}function hD(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 sv(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 av(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function ki(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 iv(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(ki))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function cv(){let e={};for(let[t,n]of Zp)e[t]={...n};return e}async function lv(e,{method:t="merge",onMerged:n=null}={}){let r=await Hn(e);if(!yi.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 fn(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),gD(s,o,{listPrs:()=>fn(r.path),merge:a=>Ds(r.path,a,{method:t}),sleep:mD,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function wD(e,t){let n=Date.now()+(t.settleMaxMs??pD),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(fD)}}async function gD(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 wD(t.slice(o).map(i=>i.number),n)}catch(i){for(let c of t.slice(o))e.failed.push({number:c.number,title:c.title,reason:`couldn't re-check PR state: ${pn(i)}`});break}let a=r.find(i=>i.number===s.number);if(!a){e.skipped.push({number:s.number,title:s.title,reason:"no longer open"});continue}if(!rm(a)){e.skipped.push({number:a.number,title:a.title,reason:hD(a)});continue}try{await n.merge(a.number),e.merged.push({number:a.number,title:a.title});try{await n.onMerged?.(a)}catch{}}catch(i){e.failed.push({number:a.number,title:a.title,reason:pn(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),mn()}}async function om(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: ${pn(l)}`)}await oD(e);let o=n||"";if((await sn({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 jt(e,s)}catch(l){throw new Error(pn(l))}finally{mn()}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 uv(e,t){let n=await Hn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await jt(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(pn(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!tm(i))throw i;let c=await jt(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await tv(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(pn(i));o=nv(l).map(Qx).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=yD(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await jt(n.path,["run","view",c,"--log-failed"]).then(u=>bD(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function yD(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function bD(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
- `+r.slice(-n)),r}function pn(e){return String(e?.stderr||e?.message||e||"").trim().split(`
186
- `).find(n=>n.trim())||"gh failed"}var Ns,sD,eu,em,ev,iD,Ms,Zx,lD,uD,gi,yi,fD,pD,mD,Zp,Bs=L(()=>{ar();it();Ln();wi();Ql();de();Ns=rD(nD),sD={timeout:3e4,maxBuffer:8*1024*1024};eu=null;em="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt",ev=em.replace("statusCheckRollup,","");iD=9e4,Ms=new Map;Zx=(e,t)=>e.number-t.number;lD=3e4,uD=1500,gi=new Map;yi=new Set(["squash","merge","rebase"]);fD=2500,pD=9e4,mD=e=>new Promise(t=>setTimeout(t,e));Zp=new Map});import{execFile as kD}from"node:child_process";import{promisify as xD}from"node:util";async function SD(e,t){try{let{stdout:n}=await vD("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function TD(e,t,n,{rebase:r=!1,listPrs:o=fn}={}){let s=await li(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await ui(e.dir,n).catch(()=>0),i=t?await SD(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:nu.filter(h=>d.includes(h)),defaults:nu.filter(h=>p.includes(h))}}async function ru(e,{branch:t,rebase:n=!1,listPrs:r=fn}={}){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 TD(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=nu.filter(d=>c.some(p=>p.available.includes(d))),u=nu.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 vD,nu,sm=L(()=>{Nl();Bs();vD=xD(kD),nu=["commit","rebase","push","pr"]});function ou(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 xi)a-c.at>=dv()&&xi.delete(i);xi.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=xi.get(e);return s?Date.now()-s.at>=dv()?(xi.delete(e),!1):s.busy:!1}async function am(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await Oe(e,{lines:Ze}).catch(()=>"");if(!ou(e,t,r))return Db(t,r)?{working:!0,prompted:!1}:n;if(wo(t,r)){let o=await Mn(e).catch(()=>r),s=Tr({name:e,agent:t},o);if(s)return!Cl({name:e,agent:t},s,o)||M0(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 dv,xi,vi=L(()=>{lt();Xa();_p();$p();dv=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,xi=new Map});import{execFile as ED}from"node:child_process";import{promisify as AD}from"node:util";async function Cr(e){if(!e)return null;let t=fv.get(e);if(t&&Date.now()-t.at<ID)return t.branch;let n=null;try{let{stdout:r}=await _D("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return fv.set(e,{at:Date.now(),branch:n}),n}function pv(e){return String(e||"").match($D)?.[1]??null}function RD(e,t){let n=pv(e);return!!n&&!!t&&n===t}function mv(e,t){let n=pv(e);return!!n&&n!==t}function OD(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 OD(e))n(await Cr(r));return t}async function su(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=>RD(t,a.id));if(s)return s;for(let a of r)if(!Ge(a)&&(await js(a)).includes(t))return a;return null}var _D,ID,fv,$D,Eo=L(()=>{Dn();_D=AD(ED),ID=5e3,fv=new Map;$D=/^track\/.+-([0-9a-f]{8})$/});import{execFile as CD}from"node:child_process";import{promisify as MD}from"node:util";async function im(e,t,{midTurn:n=To,pollMs:r=ND,capMs:o=PD}={}){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 kv(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){hv.lastIndex=n;let o=hv.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*":"")+HD(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 vv(e){let t=kv(e),n=t.match(LD);if(!n)return null;let r=cm(t,n.index);return UD.test(r)?null:{repo:r.match(xv)?.[1]??null,head:r.match(WD)?.[1]??null}}function Sv(e){let t=kv(e),n=t.match(FD);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("-")){KD.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(xv)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function VD(e,t,{exclude:n=()=>!1}={}){let r=async i=>{Un("observer");let{stdout:c}=await wv("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",GD],{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-DD&&!n(c)),s=await sn({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 zD(e,t){if(t)return[t];let n=[];for(let r of Tv(e)){let o=await Se(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await Rn().catch(()=>[])){let o=await Se(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function Tv(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 YD(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)||qD(c.headRefName,e.id),i=[];for(let c of await zD(e,t?.repo??null)){let l;try{l=await VD(c,n,{exclude:a})}catch{continue}for(let u of l){let f=await rt(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 Ev(e,t,{delays:n=gv,turnEnd:r}={}){let o=vv(t.command);if(!o)return null;let s=!!Sv(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 YD(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:f,pr:d}=u,{link:p,created:h}=await It({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 jn(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{Mr.delete(a)}})();return c.catch(()=>Mr.delete(a)),c}function Av(e,t,{delays:n=gv,turnEnd:r,openedWait:o}={}){let s=Sv(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=Tv(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 rt(c,h.number);return g&&g.trackId!==e.id?null:(g||await It({repo:c,number:h.number,trackId:e.id,url:h.url,headRef:h.headRefName,title:h.title,source:"merge-observed"}),await pi(c,h.number),w&&((await F(e).catch(()=>[])).some(A=>A.type==="pr.state.changed"&&(A.payload?.change==="auto-armed"||A.payload?.change==="merged")&&A.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{Un("observer");let{stdout:_}=await wv("gh",["pr","view",String(l),"--repo",T,"--json",JD],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await sn({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 rt(c,k.number);if(S&&S.trackId!==e.id)return null;S||await It({repo:c,number:k.number,trackId:e.id,url:k.url,headRef:k.headRefName,title:k.title,source:"merge-observed"}),await im(t.box,t.agent,r);let A=await F(e).catch(()=>[]);if(A.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(A)){if(vv(t.command)&&await jn(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 rt(c,k.number))?.announced){let T=o?.capMs??BD,_=o?.pollMs??jD,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 qn(c,k.number).catch(()=>{}),await Wn(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 wv,gv,ND,PD,DD,BD,jD,yv,bv,LD,FD,UD,hv,HD,xv,WD,qD,KD,GD,Mr,JD,_v=L(()=>{de();ar();it();wi();Ln();Nr();vi();Eo();wv=MD(CD),gv=[4e3,15e3,45e3],ND=2500,PD=5*6e4;DD=15e3,BD=9e4,jD=2e3,yv=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,bv=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,LD=new RegExp(`${yv}${bv}create\\b`),FD=new RegExp(`${yv}${bv}merge\\b`),UD=/\s--web\b/,hv=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,HD=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");xv=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,WD=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,qD=mv;KD=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);GD="number,url,title,headRefName,createdAt";Mr=new Set;JD="number,url,title,headRefName,state"});import XD from"node:fs/promises";import um from"node:path";import ZD from"node:os";function lm(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function au(e){let t=QD.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=lm(n,"from"),s=o?o.replace(/^uds:/,""):null,a=Iv(s);return{socket:s,pid:a,name:lm(n,"from-name"),mode:lm(n,"from-mode"),text:r.trim()}}function Iv(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function eB(){return process.env.CLAUDE_CONFIG_DIR?um.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):um.join(ZD.homedir(),".claude","sessions")}async function tB(e){let t=Iv(e);if(!t)return null;try{let n=await XD.readFile(um.join(eB(),`${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 $v(e,t){let n=await tB(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 QD,dm=L(()=>{QD=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function fm(e=process.env){return!!(_e(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(),Rv);try{let a=await Ov(`${_e(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 Cv(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=iu.get(e.id)||0;if(a()-i<nB)return{ok:!1,source:"debounced"};iu.set(e.id,a());let c=await Si({env:s}),l=c.loops.find(d=>d.trackId===e.id);if(!l)return iu.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||iu.delete(e.id),{...f,loop:{id:l.id,name:l.name}}}async function Si({env:e=process.env}={}){if(!fm(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),Rv);try{let r=await Ov(`${_e(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 Rv,Ov,nB,iu,mm=L(()=>{it();Rv=1e4,Ov=(...e)=>fetch(...e);nB=10*6e4,iu=new Map});function Mv(e=process.env){return!!(_e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Nv(e,t,n=hm){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await oB(`${_e(t)}${e}`,{headers:sB(t),signal:r.signal})}finally{clearTimeout(o)}}async function Ti({env:e=process.env,force:t=!1,timeoutMs:n=hm}={}){if(!Mv(e))return{followups:[],source:"unconfigured"};if(!t&&Ao&&Date.now()-Ao.at<rB)return{followups:Ao.followups,source:"cache"};try{let r=await Nv("/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 Pv(e,{env:t=process.env,timeoutMs:n=hm}={}){if(!e)return{followup:null,source:"unconfigured"};if(!Mv(t))return{followup:null,source:"unconfigured"};try{let r=await Nv(`/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 rB,hm,Ao,oB,sB,Dv=L(()=>{it();rB=6e4,hm=5e3,Ao=null,oB=(...e)=>fetch(...e);sB=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import{randomUUID as Fs,createHash as aB}from"node:crypto";function Fv(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function dB(e){for(let[t,n]of uB)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 Uv(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>Bv)throw new Error(`label must be \u2264${Bv} characters`);let o=Ls(n.trigger)||(n.ship?"now":""),s=t?cB:Lv.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"?pB(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")>jv)throw new Error(`prompt must be \u2264${jv} bytes`);if(t){let u=dB(i);if(u)throw new Error(u)}let c=Ls(n.why).slice(0,iB)||null,l=t?fB(n.repo):null;return{label:r,prompt:i,trigger:o,why:c,...l?{repo:l}:{},...a?{ship:a}:{}}}function fB(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 pB(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=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 cu(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 Hv(e,t,{pull:n=Ti,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=Uv(t);if(o.ship)return{kind:"ship",...await wB(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:gm(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=Fv(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=cu(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 Wv(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await F(n);if(!cu(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 qv(e,t,{pull:n=Ti}={}){if(bm(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=Uv(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=Fv(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=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 Kv(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 Ei(e,t,n={},{pull:r=Ti}={}){if(!e||bm(e))return null;let o={id:e.id,cwd:e.cwd},s=await F(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null,i=cu(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:mB(p.prompt),promptHash:gm(p.prompt),origin:p.origin,repo:p.repo??null}))}let l=[...i,...c].slice(0,lB);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 hB(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 Gv(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null}={},s={}){let{sayToLead:a,unarchiveTrack:i,getFollowup:c=Pv}=s;if(!t)throw new Error("offerId required");let l={id:e.id,cwd:e.cwd},u=await F(l),f=u.find(A=>A.type==="followup.offered"&&A.payload?.offerId===t);if(!f)throw new Error("unknown offer");if(u.some(A=>A.type==="followup.answered"&&A.payload?.offerId===t))throw new Error("offer already answered");let d=f.payload.rows||[],p=A=>$(l,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...A}});if(!n&&!r)return await p({action:"dismiss",followupIds:d.map(A=>A.followupId).filter(Boolean),armIds:d.map(A=>A.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:A,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(!A||A.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=A.prompt,w=A.label}else{let A=d.find(B=>B.armId===r);if(!A)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??A.prompt,w=A.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=`${hB(f.payload)}
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 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 wB(e,t,{changedRepos:n=null,probe:r=ru,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 Vv(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 zv(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 Yv(e,{pull:t=Ti}={}){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?cu(s):[]}}var Bv,jv,iB,Lv,cB,ym,lB,wm,gm,Ls,uB,bm,mB,lu=L(()=>{de();bo();sm();Eo();Dv();Bv=60,jv=8*1024,iB=200,Lv=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],cB=Lv.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"},lB=3,wm=["commit","push","pr"];gm=e=>aB("sha256").update(String(e)).digest("hex").slice(0,16),Ls=e=>typeof e=="string"?e.trim():"",uB=[[/(^|[^\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");mB=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 gB}from"node:crypto";function Ai(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function Jv(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function Xv(e){return`job|${e.box}|id:${e.id}`}async function xm(e){return km.has(e.id)?km.get(e.id):(uu.has(e.id)||uu.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(Ai({role:o,sourceId:r.payload.sourceId})),n.keys.add(Ai({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(Ai({role:"user",sourceId:r.payload.sourceId})),n.keys.add(Ai({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(Jv({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(Xv({id:r.payload.id,box:r.boxId}));return km.set(e.id,n),n}).finally(()=>uu.delete(e.id))),uu.get(e.id))}async function Zv(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=Ai(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?au(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 $v(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}}),Cv(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=yx(o.text);if(c&&Vv(await F(e).catch(()=>[])))continue;if(c){let l=xx(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 ru(e,{branch:f,rebase:l}).catch(()=>null),p=d?null:kx(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:gB(),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 Qv(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=Jv(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}}),Ev(e,o),Av(e,o))}}catch{}}async function eS(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=Xv(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,uu,tS=L(()=>{de();bo();sm();_v();Eo();dm();Nr();ul();mm();lu();km=new Map,uu=new Map});function yB(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 bB(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?.codexTs!=null&&o.add(s.payload.codexTs);vm.set(n,o)}return vm.get(n)}async function nS(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 bB(e,t),o=yB(await St(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:dn(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,rS=L(()=>{de();io();zt();Pn();vm=new Map});import du from"node:fs";import Tm from"node:path";import kB from"node:os";async function SB({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(vB,{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:oS})});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<oS)break}return r}function TB(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 aS(){try{return JSON.parse(du.readFileSync(fu(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function AB(e){try{du.mkdirSync(Tm.dirname(fu()),{recursive:!0});let t=fu()+".tmp";du.writeFileSync(t,JSON.stringify(e)),du.renameSync(t,fu())}catch{}}async function IB({fetchImpl:e,now:t=Date.now()}={}){if(Pr.rows&&t-Pr.at<EB)return Pr.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=aS(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await SB({sinceMs:o,cookie:n,fetchImpl:e});Pr={at:t,rows:s.map(TB).filter(Boolean),error:null}}catch(s){Pr={at:t,rows:null,error:String(s?.message||s)}}return Pr.rows}async function $B(e,t){let n=`${e.id}:${t.name}`;if(!Sm.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);Sm.set(n,o)}return Sm.get(n)}async function iS(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!sS())return;let r=await IB({fetchImpl:n});if(!r||!r.length)return;let o=await d0(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await $B(e,t),a=aS(),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=dn(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}})}AB({sinceMs:c,seen:[...i].slice(-_B)})}catch{}}var xB,sS,vB,oS,EB,Pr,fu,_B,Em,Sm,Am=L(()=>{de();pp();Pn();xB=process.env.BOSTRAT_STATE_DIR||Tm.join(process.env.HOME||kB.tmpdir(),".bostrat"),sS=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,vB="https://cursor.com/api/dashboard/get-filtered-usage-events",oS=100;EB=5*6e4,Pr={at:0,rows:null,error:null},fu=()=>Tm.join(xB,"cursor-usage.json");_B=5e3;Em=()=>({enabled:sS(),lastPollAt:Pr.at||null,error:Pr.error}),Sm=new Map});import{execFile as RB}from"node:child_process";import{promisify as OB}from"node:util";function Us({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function pu(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function mu({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?DB[r]:null;return a&&s.push(a),s.push(`${dS}: ${Us({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${fS}: ${String(o).trim()}`),s}function cS(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===dS.toLowerCase()&&!t.epoch)t.epoch=pu(a);else if(s===fS.toLowerCase()&&!t.model)t.model=a;else if(s===pS.toLowerCase()&&!t.cause){let i=a.toLowerCase();Ii.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 BB(e,t=Dr){return e<=t?"rework":"drift"}function jB(e,{window:t=Dr,end:n=Rm}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function HB({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return LB.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${pS} trailer`}:UB.test(s)&&!lS.test(s)?{cause:"style",level:"C",basis:"subject"}:lS.test(s)?{cause:"defect",level:"C",basis:"subject"}:FB.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 qB(e){return WB.some(t=>t.test(e))}function KB(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 GB(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 uS(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(`
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 hS(e,t,{fixKey:n=null,window:r=Dr,resolveOrigin:o=null,context:s={}}={}){let a=await uS(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=cS(a.message),l=n?pu(n):c.epoch,u=l?Us(l):null,{stdout:f}=await $m(e,["diff","-U0","--no-color","-M","-C",i,t]),d=KB(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(qB(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=GB((await $m(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,A=new Map;for(let[B,{lines:T,time:_}]of g){let O=A.get(B);if(!O){try{O=await uS(e,B)}catch{O=null}A.set(B,O)}let I=O?cS(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 J=Number.isFinite(_)?_:O?.ts??a.ts,C=Math.max(0,(a.ts-J)/NB),Q=Us(U),ve=Q===u?"self":BB(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(jB(C,{window:r})*1e3)/1e3:0})}k.sort((B,T)=>T.lines-B.lines);let R=HB({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 wS(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:Xt(t),reworkChargedUsd:Xt(e.reworkChargedUsd),reworkPendingUsd:Xt(e.reworkPendingUsd),trueUsd:Xt(t+e.reworkChargedUsd),multiplier:t>0?Xt((t+e.reworkChargedUsd)/t):null}}function gS(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=pu(T)||{};l[T]={key:T,...I,provider:null,model:null,..._m()}}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}=Bt(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,J=0;for(let C of o)C.trackId!==T||C.boxId!==_||(C.epoch??0)===(O??0)&&(C.ts<=H||C.ts>I||(ae+=Bt(C).usd,J++));return{usd:ae,turns:J,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={},A={},R=new Set;for(let T of a){let _=T.payload||{};if(!_.sha||R.has(_.sha))continue;R.add(_.sha);let O=pu(_.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 J=PB.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:Xt(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:Xt(0),origins:[]};if(_.ghost||C===0)h.ghost+=I;else{let be=0;for(let ue of Q){let me=ue.lines/C,j=I*me;if(be+=j,ue.class==="self"){h.self+=j;continue}let ie=ue.class==="rework"?1:Number(ue.decay)||0,le=j*ie;if(h.decayed+=j-le,le<=0)continue;let Ae=f(ue.key,{provider:ue.provider,model:ue.model});Ae.fixes+=1,Ae.linesReworked+=ue.class==="rework"?ue.lines:0;let $e=H?.cause&&Ii.includes(H.cause)?H.cause:"unclassified";Ae.causes[$e]+=1,J?(Ae.reworkChargedUsd+=le,h.charged+=le,W.charged=Xt(W.charged+le)):(Ae.reworkPendingUsd+=le,h.pending+=le),W.origins.push({key:ue.key,provider:Ae.provider,model:Ae.model,lines:ue.lines,ageDays:ue.ageDays,class:ue.class,usd:Xt(le)})}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[_]||=_m()),I(A[O]||=_m())}g.sort((T,_)=>_.ts-T.ts);let B=Object.values(l).map(T=>{let _=n[`${T.trackId}/${T.boxId}`]||{};return Im({...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,Im(_)])),byModel:Object.fromEntries(Object.entries(A).map(([T,_])=>[T,Im(_)])),buckets:Object.fromEntries(Object.entries(h).map(([T,_])=>[T,Xt(_)])),fixUsdTotal:Xt(Object.values(h).reduce((T,_)=>T+_,0)),fixes:g,verdicts:w,pendingTaps:k,commits:s.length}}var CB,MB,$m,dS,fS,pS,NB,Dr,Rm,mS,Ii,PB,DB,LB,lS,FB,UB,WB,Xt,_m,hu=L(()=>{vr();CB=OB(RB),MB=64*1024*1024,$m=(e,t)=>CB("git",["-C",e,...t],{maxBuffer:MB,timeout:6e4}),dS="Bostrat-Epoch",fS="Bostrat-Model",pS="Bostrat-Fix-Cause",NB=24*36e5,Dr=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,Rm=90,mS=3,Ii=Object.freeze(["defect","design","requirements","style"]),PB=new Set(["A","B","E"]);DB={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};LB=/^revert\b|^revert "/i,lS=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,FB=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,UB=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;WB=[/(^|\/)\.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)\//];Xt=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 Oi from"node:fs/promises";import Tt from"node:path";import VB from"node:os";import zB from"node:net";import{randomUUID as YB}from"node:crypto";import{execFile as JB}from"node:child_process";import{promisify as XB}from"node:util";function o1(e){for(let t of Bm(e))if(!SS.test(t))return t;return null}function TS(e){let t=Bm(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function s1(e,t){let n=TS(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return Tt.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return Tt.resolve(e,n[r+1])}return e}function i1(e){let t=!1,n=!1;for(let r of Bm(e)){if(!t){if(SS.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(a1(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function l1(e,t){if(Tt.resolve(e)===Tt.resolve(t))return!0;let[n,r]=await Promise.all([wu(e),wu(t)]);return n===r}async function u1(e){let n=(await Oi.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 ES(Tt.join(e,o.name,Nm))?`./${o.name}`:null))).filter(Boolean)}async function d1(e,t){let[n,r]=await Promise.all([wu(e),wu(t)]),o=Tt.relative(n,r);if(o&&(o.startsWith("..")||Tt.isAbsolute(o)))throw $i(`serve directory escapes the Track workspace: ${t}`)}async function f1(e,t){let n=i1(t);if(n)throw $i(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await c1(e))throw $i(`serve directory does not exist: ${e}`);let r=o1(t);if(!r)return;if(!r.includes("/")&&!await Ky(r,{loginShell:!0,failOpen:!0}))throw $i(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(t1.test(t)||n1.has(r)||!e1.has(r)||!TS(t).includes("run")||r1.test(t))return;let o=s1(e,t);if(await ES(Tt.join(o,Nm)))return;let s=await u1(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw $i(`no ${Nm} in ${o}${a}`)}async function Vn(){return hn||(Cm||=(async()=>{try{hn=JSON.parse(await Oi.readFile(vS,"utf8"))}catch{hn={views:[],adoptWatermarks:{}}}finally{Cm=null}return hn.views||=[],hn.adoptWatermarks||={},hn})(),Cm)}async function gn(){await vt(vS,hn)}function Gn(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 Ri.get(e)||null}function _S(e,{name:t,box:n}={}){let r=Ri.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 Ri.set(e,o),o}function Pm(e,t){let n=Ri.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function gu(e,{error:t=null}={}){let n=Ri.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function IS(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 p1(e,t){let n=Dm(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!kS.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!kS.has(s))return s}}function Ci(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=zB.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 wn("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await wn("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 $S(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function m1(e,t){let n=new Set(e.views.map(o=>o.port)),r=$S();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=yS;o<=bS;o++)if(!(n.has(o)||r.has(o))&&!await Ci(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${yS}-${bS}`)}async function h1(e){try{let{stdout:t}=await wn(K,G("list-sessions","-F","#{session_name}"));return t.split(`
198
- `).some(n=>n.trim()===Hs(e))}catch{return!1}}async function Mi(e){try{await wn(K,G("kill-session","-t",Hs(e)))}catch{}}async function Um(e){if(!await Ua())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=Tt.dirname(process.execPath);await wn(K,G("new-session","-d","-s",t,"-c",n)),await wn(K,G("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await wn(K,G("send-keys","-t",t,"Enter")),await wn(K,G("send-keys","-t",t,"-l",e.cmd)),await wn(K,G("send-keys","-t",t,"Enter"))}async function xS(e,t=12){try{let{stdout:n}=await wn(K,G("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 g1(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await h1(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await xS(e.slug)||"server exited before listening"),Kn.delete(e.id),await Gn(e,e.state,e.error?{error:e.error}:{}),!0}if(await Ci(e.port))return Kn.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await Gn(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>w1?(e.state="error",e.error=await xS(e.slug)||"never started listening",await Gn(e,"error",{error:e.error}),!0):!1;let o=(Kn.get(e.id)||0)+1;return Kn.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function yu(){if(!Mm){Mm=!0;try{let e=await Vn(),t=!1;for(let n of e.views)await g1(n)&&(t=!0);t&&await gn()}finally{Mm=!1}}}async function bu({trackId:e}={}){await yu();let t=await Vn();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function RS(e){let n=(await Vn()).views.find(r=>r.id===e);return n?{...n}:null}function Hm(e){return hn&&hn.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=Tt.resolve(r,o??"."),f=i==="detected"?null:async()=>{await d1(r,u),await f1(u,n)},d=await Vn();if(i!=="detected"){let w=Dm(t),g=String(n).trim(),k=d.views.find(S=>S.trackId===e&&(S.slug===w||Dm(S.name)===w||S.cmd===g&&Tt.resolve(S.serveCwd??S.cwd)===u));if(k)return y1(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:YB().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:p1(d,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await m1(d,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await Um(h),d.views.push(h),await gn(),await Gn(h,"created",{origin:i}),Pm(e,h.id),i==="detected"&&await Ci(h.port)&&(h.state="live",h.lastHealthyAt=Date.now(),await gn(),await Gn(h,"live")),{...h}}async function y1(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 l1(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await Ci(t.port))return await gn(),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>=Br)throw new Error(`view cap reached (${Br} live) \u2014 stop one first`);return t.origin==="detected"?(await Fm(t.port),t.origin="agent"):await Mi(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),Kn.delete(t.id),await Um(t),await gn(),await Gn(t,"created",{restarted:!0,reused:!0}),Pm(t.trackId,t.id),{...t,reused:!0}}async function OS(e){let n=(await Vn()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await Fm(n.port):await Mi(n.slug),n.state!=="stopped"&&(n.state="stopped",Kn.delete(n.id),await gn(),await Gn(n,"stopped")),{...n}}async function CS(e){let t=await Vn(),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 Mi(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),Kn.delete(n.id),await Um(n),await gn(),await Gn(n,"created",{restarted:!0}),{...n}}async function MS(e){let t=await Vn(),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 Mi(r.slug),t.views.splice(n,1),Kn.delete(r.id),await gn(),await Gn(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function NS(e){let t=await Vn(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await Mi(r.slug),Kn.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await gn()),n.length}async function PS(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await Vn(),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 gn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(b1)){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(!$S().has(c)&&!n.views.some(l=>l.port===c)&&await Ci(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 wn,ZB,vS,yS,bS,Br,QB,Hs,kS,$i,e1,Nm,t1,n1,r1,Bm,SS,Om,a1,c1,ES,wu,hn,Cm,Ri,jm,AS,Kn,w1,Mm,b1,ku=L(()=>{lt();de();cr();wn=XB(JB),ZB=process.env.BOSTRAT_STATE_DIR||Tt.join(process.env.HOME||VB.tmpdir(),".bostrat"),vS=Tt.join(ZB,"views.json"),[yS,bS]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),Br=Number(process.env.BOSTRAT_VIEW_MAX)||3,QB="bostrat-view-",Hs=e=>`${QB}${e}`,kS=new Set(["bostrat","www","api","views","app"]),$i=e=>Object.assign(new Error(e),{status:400}),e1=new Set(["npm","pnpm","yarn","bun"]),Nm="package.json",t1=/[|;&`]|\$\(/,n1=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),r1=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,Bm=e=>String(e).trim().split(/\s+/).filter(Boolean),SS=/^[A-Za-z_][A-Za-z0-9_]*=/;Om=e=>e==="/",a1=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");c1=e=>Oi.stat(e).then(t=>t.isDirectory(),()=>!1),ES=e=>Oi.stat(e).then(t=>t.isFile(),()=>!1),wu=e=>Oi.realpath(e).catch(()=>Tt.resolve(e));hn=null,Cm=null;Ri=new Map,jm=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,AS=12e3;Kn=new Map,w1=12e4;Mm=!1;b1=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function xu(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>x1?null:n}function v1(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function DS(e){let t=e?.workspace?.branch;if(!t)return;let n;try{n=await F(e)}catch{return}let r=xu(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)<k1)return;qm.set(e.id,s);let a;try{a=await fn(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 It({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 jn(l,c.number))){if(!v1(u,r))return;let d=await F(e).catch(()=>null);if(d&&xu(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 k1,qm,x1,Km=L(()=>{de();Bs();ar();Ln();vi();Eo();k1=6e3,qm=new Map,x1=30*6e4});import Gm from"node:os";import{execFile as S1}from"node:child_process";import{promisify as T1}from"node:util";async function vu(){if(process.platform!=="darwin")return Gm.freemem();try{let{stdout:e}=await E1("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 E1,Vm=L(()=>{E1=T1(S1)});import qe from"node:fs/promises";import Ve from"node:path";import FS from"node:os";import{randomUUID as A1}from"node:crypto";import{execFile as _1}from"node:child_process";import{promisify as I1}from"node:util";import{chromium as $1}from"playwright-core";async function kn(){return Io||(zm||=(async()=>{try{Io=JSON.parse(await qe.readFile(HS,"utf8"))}catch{Io={mocks:[]}}finally{zm=null}return Io.mocks||=[],Io})(),zm)}async function Lt(){await vt(HS,Io)}function GS(e,t){bn(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&bn(e,t.v,"png")}function gt(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 Ft(e,t){let n=Pi(e.cwd);return{html:Ve.join(n,`${e.id}.v${t}.html`),png:Ve.join(n,`${e.id}.v${t}.png`)}}function Ni(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?Ve.join(e.cwd,r):null}function Zt(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 Su(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(D1)}function B1(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 j1(e){let t=Buffer.alloc(24),n=await qe.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function L1({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 F1(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 U1(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 H1({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await $1.launch({executablePath:WS,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new $t("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 F1(a,i),u=l&&L1({...l,pad:C1*Ws,align:Ws});u&&(i=await U1(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<qS)throw new $t(`capture produced a ${i.length}-byte image`);let c=Xm(i);if(!c)throw new $t("output is not a PNG");return await qe.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 $t?s:new $t(/timeout/i.test(s?.message||"")?`render timed out after ${qs}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function LS({htmlPath:e,outPath:t,width:n}){let r=await qe.mkdtemp(Ve.join(FS.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await Jm(BS,["--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 $t(`firefox not found (${BS})`,""):new $t(c?.killed?`render timed out after ${qs}ms`:"firefox exited non-zero",s)}let a=await qe.stat(t).catch(()=>null);if(!a||a.size<qS)throw new $t(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=Xm(await j1(t));if(!i)throw new $t("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await qe.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function W1(e){if(R1==="firefox")return LS(e);try{return await H1(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await LS(e)}catch(n){throw/not found/.test(n?.message||"")?new $t(`no browser installed \u2014 chromium missing at ${WS} 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 VS(e){return Ym=Ym.then(e,e),Ym}async function zS(e,t){let n=await kn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Lt(),await gt(r,"rendering",{version:t});try{let o=await vu();if(o<M1)throw new $t(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=Ft(r,t),a=await q1({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await qe.rm(s.png,{force:!0}).catch(()=>{});return}Zm(r,{v:t,source:"html",htmlRel:Ve.relative(r.cwd,s.html),pngRel:Ve.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Lt(),await gt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),yn(r),bn(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Lt(),await gt(r,"error",{version:t,error:r.error}),yn(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 K1({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?O1:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function Di({trackId:e,group:t}={}){let n=await kn(),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 zn(e){let n=(await kn()).mocks.find(r=>r.id===e);return n?{...n}:null}function YS({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&&!Su(t))throw new Error("image must be a PNG");if(n){let o=B1(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>jS)throw new Error(`video must be ${jS/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function JS({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let f=K1({trackId:e,name:t,cwd:s,width:a}),d=typeof n=="string"&&n.trim(),p=YS({html:n,image:r,video:o}),h=await kn(),w={id:A1().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 qe.mkdir(Pi(s),{recursive:!0}),h.mocks.push(w),d?(await qe.writeFile(Ft(w,1).html,n),await Lt(),await gt(w,"created"),yn(w),bn(w,1,"html"),VS(()=>zS(w.id,1))):o?(await ZS(w,1,o,p),await Lt(),await gt(w,"created"),await gt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr,durationS:w.versions[0]?.durationS??null}),yn(w),GS(w,w.versions[0])):(await QS(w,1,r),await Lt(),await gt(w,"created"),await gt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr}),yn(w),bn(w,1,"png")),{...w}}async function XS(e,{html:t,image:n,video:r,width:o}={}){let a=(await kn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=YS({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 qe.mkdir(Pi(a.cwd),{recursive:!0}),i?(a.state="queued",await qe.writeFile(Ft(a,l).html,t),await Lt(),await gt(a,"updated",{version:l}),yn(a),bn(a,l,"html"),VS(()=>zS(a.id,l))):r?(await ZS(a,l,r,c),await Lt(),await gt(a,"updated",{version:l}),await gt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:Zt(a)?.durationS??null}),yn(a),GS(a,a.versions.find(u=>u.v===l))):(await QS(a,l,n),await Lt(),await gt(a,"updated",{version:l}),await gt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),yn(a),bn(a,l,"png")),{...a}}async function G1(e){try{let{stdout:t}=await Jm(N1,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:KS,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 V1(e,t){try{await Jm(P1,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:KS,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await qe.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function ZS(e,t,n,r){let o=Pi(e.cwd),s=Ve.join(o,`${e.id}.v${t}.${r.ext}`),a=Ve.join(o,`${e.id}.v${t}.poster.png`);await qe.writeFile(s,n);let i=await G1(s),c=await V1(s,a);Zm(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:Ve.relative(e.cwd,s),posterRel:c?Ve.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 QS(e,t,n){let r=Xm(n);if(!r)throw new Error("image must be a PNG");let o=Ft(e,t);await qe.writeFile(o.png,n),Zm(e,{v:t,source:"image",htmlRel:null,pngRel:Ve.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function eT(e){let t=await kn(),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 gt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function tT(e){let t=await kn(),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=Ft(r,o);await qe.rm(s.html,{force:!0}).catch(()=>{}),await qe.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await qe.rm(Ve.join(r.cwd,s),{force:!0}).catch(()=>{});return await Lt(),await gt(r,"deleted"),qt("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function nT(e){let n=(await kn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=Ve.join(US,"mock-archive",e.id),o=Pi(e.cwd),s=Ve.join(r,".bostrat","mocks");await qe.mkdir(s,{recursive:!0});let a=await qe.readdir(o).catch(()=>[]);for(let i of a)await qe.copyFile(Ve.join(o,i),Ve.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 qe.stat(Ve.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(),yn(i)}return await Lt(),n.length}async function rT(e){let t=await kn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Lt();for(let r of n)qt("mocks",r.id).catch(()=>{})}return n.length}async function oT(){if(!Me())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await nt("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await kn();for(let r of n.mocks){await yn(r);for(let o of r.versions||[])o.htmlRel&&await bn(r,o.v,"html"),(o.pngRel||o.posterRel)&&await bn(r,o.v,"png"),o.videoRel&&await bn(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var Jm,US,HS,R1,WS,BS,O1,Ws,C1,qS,qs,M1,jS,N1,P1,KS,$t,Io,zm,yn,bn,Pi,D1,q1,Ym,Ks=L(()=>{de();cr();Vm();ur();Jm=I1(_1),US=process.env.BOSTRAT_STATE_DIR||Ve.join(process.env.HOME||FS.tmpdir(),".bostrat"),HS=Ve.join(US,"mocks.json"),R1=process.env.BOSTRAT_MOCK_ENGINE||"chromium",WS=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",BS=process.env.BOSTRAT_FIREFOX_BIN||"firefox",O1=1300,Ws=2,C1=32,qS=1500,qs=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,M1=700*1024*1024,jS=100*1024*1024,N1=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",P1=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",KS=2e4,$t=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,zm=null;yn=e=>ht("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),bn=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?Ni(e,r,"video"):r&&Ni(e,r,n)||(n==="html"?Ft(e,t).html:null);return o?lr("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};Pi=e=>Ve.join(e,".bostrat","mocks");D1=Buffer.from([137,80,78,71,13,10,26,10]);q1=W1,Ym=Promise.resolve()});import z1 from"node:fs/promises";import lT from"node:path";import Y1 from"node:os";import{randomUUID as uT}from"node:crypto";async function Jn(){return Yn||(Qm||=(async()=>{let e=!0;try{Yn=JSON.parse(await z1.readFile(dT,"utf8"))}catch{Yn={flows:[]},e=!1}finally{Qm=null}if(Yn.flows||=[],!e&&Me()){let{records:t,source:n}=await nt("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&Yn.flows.push(r.data);Yn.flows.length&&await Gs().catch(()=>{})}}return Yn})(),Qm)}async function Gs(){await vt(dT,Yn)}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 fT({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>sT)throw new Error(`steps must be an array of 1-${sT}`);let r=await Di({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>iT)throw new Error(`${l}: caption over ${iT} chars`);let f=c.title==null?null:String(c.title).trim()||null;if(f&&f.length>cT)throw new Error(`${l}: title over ${cT} 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:uT().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 X1(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>aT)throw new Error(`name over ${aT} chars`);return e.trim()}async function pT({trackId:e}={}){let t=await Jn();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function Z1(e){let n=(await Jn()).flows.find(r=>r.id===e);return n?{...n}:null}async function mT(e){let t=await Z1(e);if(!t)return null;let n=new Map((await Di({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=Zt(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 hT({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=X1(t),i=await Jn(),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 fT({trackId:e,steps:n}),f=Date.now(),d={id:uT().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 eh(d,"created"),Tu(d),{...d}}async function wT(e,{steps:t,note:n}={}){let o=(await Jn()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await fT({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 eh(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),Tu(o),{...o}}async function gT(e){let t=await Jn(),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 eh(r,"deleted"),qt("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function yT(e){return(await Jn()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function bT(e){let n=(await Jn()).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(),Tu(r);return n.length&&await Gs(),n.length}async function kT(e){let t=await Jn(),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)qt("flows",r.id).catch(()=>{})}return n.length}async function xT(){if(!Me())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await nt("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Jn();for(let r of n.flows)await Tu(r);return{pushed:n.flows.length,source:"plane"}}var J1,dT,sT,aT,iT,cT,Yn,Qm,Tu,th=L(()=>{de();cr();Ks();ur();J1=process.env.BOSTRAT_STATE_DIR||lT.join(process.env.HOME||Y1.tmpdir(),".bostrat"),dT=lT.join(J1,"flows.json"),sT=20,aT=80,iT=500,cT=80,Yn=null,Qm=null;Tu=e=>ht("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import Qn from"node:fs/promises";import er from"node:path";import Q1 from"node:os";import{randomUUID as ej}from"node:crypto";function Bi(e){return tj.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function xn(){return Xn||(nh||=(async()=>{let e=!0;try{Xn=JSON.parse(await Qn.readFile(ST,"utf8"))}catch{Xn={runbooks:[]},e=!1}finally{nh=null}return Xn.runbooks||=[],!e&&Me()&&await nj().catch(()=>{}),Xn})(),nh)}async function Ro(){await vt(ST,Xn)}function Au(e){return ji(ht("runbooks",{...e},{trackId:e.trackId}))}async function nj(){let{records:e,source:t}=await nt("runbooks");if(!(t!=="plane"||!e.length)){await Qn.mkdir(Eu,{recursive:!0});for(let n of e){if(n.deletedAt||!n.data?.id)continue;let r=n.data;for(let o of r.versions||[]){let s=await Na("runbooks",r.id,o.v,"md");typeof s=="string"&&await Qn.writeFile(Zn(r,o.v),s).catch(()=>{})}Xn.runbooks.push(r)}Xn.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 Zn(e,t){return er.join(Eu,`${e.id}.v${t}.md`)}function TT(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 ET(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>vT)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${vT/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=Bi(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 rj(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function oj({trackId:e,status:t}={}){let n=await xn(),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 AT({trackId:e,status:t}={}){let n=await xn(),r=await oj({trackId:e,status:t});if(!Me())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await nt("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 sj(e);if(t)return t;if(!Me())return null;let{records:n,source:r}=await nt("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 Na("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function sj(e){let n=(await xn()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function IT({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=ET(r),c=await xn(),l={id:ej().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 Qn.mkdir(Eu,{recursive:!0}),await Qn.writeFile(Zn(l,1),r),l.versions.push({v:1,mdRel:er.relative($o,Zn(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await Ro(),await Vs(l,"created",{version:1}),Au(l),ji(lr("runbooks",l.id,1,"md",Zn(l,1))),{...l}}async function $T(e,{md:t,note:n}={}){let o=(await xn()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");rj(o,"update");let s=ET(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await Qn.mkdir(Eu,{recursive:!0}),await Qn.writeFile(Zn(o,a),t),o.versions.push({v:a,mdRel:er.relative($o,Zn(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)}:{}}),Au(o),ji(lr("runbooks",o.id,a,"md",Zn(o,a))),{...o}}async function RT(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await xn()).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"),Au(r),{...r})}async function OT(e){let t=await xn(),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 Qn.rm(er.join($o,o.mdRel),{force:!0}).catch(()=>{});return await Ro(),r.trackDeletedAt||await Vs(r,"deleted"),ji(qt("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function CT(e){let n=(await xn()).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,Au(r);return n.length&&await Ro(),n.length}async function MT(e){let t=await xn(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await Vs(r,"deleted");for(let o of r.versions||[])await Qn.rm(er.join($o,o.mdRel),{force:!0}).catch(()=>{});ji(qt("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await Ro()),n.length}async function NT(){if(!Me())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await nt("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await xn();for(let r of n.runbooks){await ht("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await lr("runbooks",r.id,o.v,"md",er.join($o,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var $o,ST,Eu,vT,tj,Xn,nh,ji,_u=L(()=>{cr();de();ur();$o=process.env.BOSTRAT_STATE_DIR||er.join(process.env.HOME||Q1.tmpdir(),".bostrat"),ST=er.join($o,"runbooks.json"),Eu=er.join($o,"runbooks"),vT=256*1024,tj=[{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/}];Xn=null,nh=null;ji=e=>Promise.resolve(e).catch(()=>{})});import oh from"node:fs/promises";import Li from"node:path";import{randomUUID as aj}from"node:crypto";function ah(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return ij.has(t)?"image":cj.has(t)?"doc":null}function lj(e){let r=Li.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 BT(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>PT)throw new Error(`file too large \u2014 max ${Math.floor(PT/(1024*1024))} MB`);let r=lj(t),o=Li.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=aj().slice(0,8),i=sh(e);await oh.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await oh.writeFile(Li.join(i,c),n,{mode:384}),await oh.chmod(Li.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${DT}/${c}`,kind:s,size:n.length}}function jT(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"&&uj.test((e.text||"").trim())}var DT,sh,PT,ij,cj,uj,ch=L(()=>{DT=".bostrat/uploads",sh=e=>Li.join(e,DT),PT=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,ij=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),cj=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"]);uj=/\[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 LT=L(()=>{});import{execFile as dj}from"node:child_process";import{promisify as fj}from"node:util";function lh(e){return`refs/bostrat/wip/${e}`}function hj(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function HT(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function wj(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:mj}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 jr(o,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await jr(o,["remote","get-url","origin"])}catch{return FT.has(o)||(FT.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&&Iu.get(o)===i)return{pushed:!1,reason:"unchanged"};let c=lh(r);return await jr(o,["push","--force","origin",`${s}:${c}`],UT),Iu.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 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(Iu.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=hj(n);return await jr(r,["push","origin",`${o}:${i}`],UT),Iu.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 WT({listTracks:e,sweepMs:t=wj(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)Ge(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 pj,mj,UT,jr,Iu,FT,fh=L(()=>{Nl();de();Dn();pj=fj(dj),mj=12e4,UT=6e4;jr=(e,t,n=15e3)=>pj("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),Iu=new Map,FT=new Set});import gj from"node:fs";import ph from"node:fs/promises";import yj from"node:path";function vj(e=process.env){return!!(_e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function qT(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(!vj(t))return{restored:!1,reason:"plane not configured"};let s=ts(e),a=yj.join(s,`${o}.ndjson`);try{if(gj.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=_e(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let d=new AbortController,p=setTimeout(()=>d.abort(),xj),h;try{h=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${bj}`,{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>kj)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(`
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 ph.rename(f,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var bj,kj,xj,KT=L(()=>{it();de();bj=1e3,kj=5e5,xj=3e4});var SE={};Pd(SE,{HANDOFF_LATEST_REL:()=>Co,KNOWN_AGENTS:()=>Ji,TRACK_NAME_MAX:()=>Ah,addTrackRepo:()=>Hh,adoptTrack:()=>aw,agentAvailability:()=>Cu,announceNodeUpdate:()=>Sn,answerFullscreenOffer:()=>Qh,answerPrompt:()=>Nu,archiveTrack:()=>Do,archiveTrackForMergedPr:()=>Wn,augmentFirstPromptAfterHandoff:()=>tE,buildAgentCmd:()=>$h,canResumeSubtask:()=>kE,cancelQueued:()=>Qi,cancelQueuedToDraft:()=>Ph,cancelStopJob:()=>ec,cancelSubtask:()=>qu,changedRepos:()=>_o,commitTransferOut:()=>Hu,createSetupTrack:()=>Kh,createTrack:()=>Bu,deleteTrack:()=>Vh,demoteTransferredTracks:()=>sw,ensureLeadEpochs:()=>Qs,forceMergeSubtask:()=>uw,getHandoffJob:()=>ra,getSubtaskJob:()=>TL,getTrack:()=>te,getTransferOutJob:()=>nw,healDeadLead:()=>zi,interruptLead:()=>Du,isArchiving:()=>mL,isHandoffNoteEcho:()=>vh,isInterruptEcho:()=>Sh,isModelSwitchEcho:()=>Th,leadCliDead:()=>Yh,listSubtaskJobs:()=>jo,listTracks:()=>ce,matchTranscriptsToBoxes:()=>oE,mergeNotifyMessage:()=>wE,navigatePrompt:()=>Nh,notifyTrackForMergedPr:()=>qn,notifyTrackForResolvedPr:()=>ju,offerFollowupsForMergedPr:()=>Bo,pendingOffers:()=>Ch,queueShipCompleteNotify:()=>Bh,queuedMessages:()=>Mo,reapArchivedOrphans:()=>Zh,reconcileDemotedTracks:()=>Xh,reconcileHandoffOutcome:()=>gE,reconcileInterruptedHandoffs:()=>tw,reconcileInterruptedSubtasks:()=>iw,reconcileNodeUpdateNotices:()=>Oh,reconcileSubtaskOutcome:()=>bE,refreshStandingInstructions:()=>qh,refuseIfTransferred:()=>ow,rehydrateLead:()=>nc,removeTrackRepo:()=>Wh,renameTrack:()=>Jh,reposOf:()=>Mt,resolveTrackBox:()=>_i,resolveTrackBoxByHookToken:()=>Zi,restartLead:()=>Fu,resumeAgentCmd:()=>Rh,sayToLead:()=>Ct,sendOptionsForAgent:()=>un,setTrackDraft:()=>Fh,setTrackModel:()=>Uh,startLeadHandoff:()=>Uu,startSpinUpView:()=>jh,startSubtask:()=>lw,startTransferOut:()=>rw,stopJobActive:()=>iE,subtaskMessages:()=>Mh,trackMessages:()=>Mu,unarchiveTrack:()=>Lu});import V from"node:fs/promises";import Y from"node:path";import{randomUUID as Po}from"node:crypto";import{execFile as Sj}from"node:child_process";import{promisify as Tj}from"node:util";function $h(e,{skipPermissions:t=!0}={}){let n=Ou[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=Ou[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&&!Vt(r,t)){let c=o&&Ne(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=Ou[e];if(t)return process.env[t.envVar]||t.base}async function Cu({maxAgeMs:e=6e4}={}){if(Lr.value&&Date.now()-Lr.at<e)return Lr.value;let t=Lr.value,n=await Promise.all(Ji.map(async r=>{let o=await ol(na(r),{retries:[]});return o===is?[r,t?.[r]??!0]:[r,o===rl]}));return Lr.value=Object.fromEntries(n),Lr.at=Date.now(),Lr.value}async function Xi(e,t=!0){let n=$h(e,{skipPermissions:t});if(await ol(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 tE(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 vh(e){return e.role==="user"&&_j.test((e.text||"").trim())}async function Z(){return Ut||(mh||=(async()=>{try{Ut=JSON.parse(await V.readFile(QT,"utf8"))}catch{Ut={tracks:[]}}finally{mh=null}return Ut})(),mh)}async function ee(){await vt(QT,Ut)}function Rj(e,t){let n=JSON.stringify({trackId:e,...t})+`
210
- `;return hh=hh.then(()=>V.mkdir(vn,{recursive:!0})).then(()=>V.appendFile(Ej,n)).catch(()=>{}),hh}async function Sn({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 V.readFile(wh,"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)Ge(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 V.mkdir(Y.dirname(wh),{recursive:!0}),await V.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 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)||Oj(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 Oj(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 nE(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=>Cj.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 rE(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 Qe(t,n,{...un(o.agent,n),kind:r||"orchestration"});let a=await ti({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=pe(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 Mj(e){let t=Y.join(ts(e),`${e.id}.ndjson`),n;try{n=await V.stat(t)}catch{return null}let r=GT.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 GT.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function Nj(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 Rt(e,t=null){let n=t??new Map((await Kt()).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([Mj(e),Nj(e,o)]);return{...e,boxes:o,lastResponseAt:s,working:a,prompted:i,archiving:Vi.has(e.id)}}function oE(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-Pj,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 sE(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=oE(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 ce(){let e=await Z();await sE(e)&&await ee();let t=new Map((await Kt()).map(n=>[n.name,n]));return Promise.all(e.tracks.map(n=>Rt(n,t)))}async function _i(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 Zi(e){let t=xa(e);if(!t)return null;let n=await Z();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 te(e){let t=await Z(),n=pe(t,e);return n?(await sE(t)&&await ee(),Rt(n)):null}async function Ch(e){let t=await F(e).catch(()=>[]),n;try{n=wr(t)}catch{return[]}return fk(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(Dj[e.agent]||[]).some(n=>n.test(t))}function Th(e){let t=(e.text||"").trim();return t?Bj.some(n=>n.test(t)):!1}async function Mu(e,t={}){let n=await te(e);if(!n)return null;let r=new Set([...n.events.filter(E=>E.type==="orchestration-prompt"&&E.prompt).map(E=>String(E.prompt).trim()),...n.events.filter(E=>E.type==="said"&&E.text).map(E=>String(E.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=Lm(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...IS(n),...l],d={windows:[...Pk(n),...Dk(n,_l),...a,...u]},h=(await Promise.all(n.boxes.map(E=>bp(E,t)))).flat(),w=h.map(E=>{let ne={kind:"message",...E};if(ne.role==="assistant"&&(ne.text||"").trim()&&ne.tools?.length){let Ke=ci(ne.agent).cliTools,y=ne.tools.filter(m=>!Ke.has(m));return{...ne,tools:y.length?y:void 0}}return ne}).map(E=>{if(E.role!=="user")return E;let ne=Tl(E.text);return ne?ne.kind==="suppress"?null:{...E,note:ne,text:rk(ne)}:E}).filter(Boolean).filter(E=>!(E.role==="user"&&r.has((E.text||"").trim()))).filter(E=>!Sh(E)).filter(E=>!Th(E)).filter(E=>!vh(E)).filter(E=>!ih(E)).filter(E=>E.role!=="assistant"||!!(E.text||"").trim()||!!E.images?.length).filter(E=>!Bk(E,d)),g=w.filter(E=>E.failed&&E.text===ao);if(g.length){let E=new Map;for(let ne of g){if(!E.has(ne.box)){let m=[...(await Oe(ne.box,{lines:Ze}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(b=>b[1]);E.set(ne.box,m.length?m[m.length-1]:null)}let Ke=E.get(ne.box);Ke&&(ne.text=`\u25A0 ${Ke}`)}}let k=await Promise.all(n.boxes.map(E=>w0(E,t)));await eS(n,k.flat());let{agentTurnBoxes:S}=await Zv(n,w);for(let E of n.boxes)S.has(E.name)&&E.cwd&&Vc(E.cwd);await dx(n),await PS(n,w).catch(()=>{});for(let E of n.boxes)E.agent==="codex"&&E.state==="live"&&await nS(n,E),E.agent==="cursor"&&E.state==="live"&&await iS(n,E);let A=await Promise.all(n.boxes.map(E=>h0(E,t)));await Qv(n,A.flat().filter(E=>!gh(E.box,E.ts,u)));let R=await F(n),B=c&&i.viewId?i.viewId:null,T=Sx(R),_=wr(R).filter(E=>!(E.kind==="message"&&(Sh(E)||Th(E)||vh(E)||ih(E)))&&!(E.kind==="view-card"&&B&&E.viewId===B)),O=Tx(_,T),I=_.filter(E=>!(E.kind==="message"&&E.role==="assistant"&&!O.has(E)&&gh(E.box,E.ts,T))),U=Qf(R,I).map(E=>({kind:"command-batch",id:E.id,ts:E.pending?E.ts:(E.anchorTs??E.ts)-1,anchorTs:E.anchorTs,anchorBox:E.anchorBox,agent:E.agent,boxRole:E.boxRole,commands:E.commands,pending:E.pending})).filter(E=>!gh(E.anchorBox,E.anchorTs??E.ts,u)),H=uk(dk([...I,...U].filter(E=>E.ts!=null).sort((E,ne)=>E.ts-ne.ts))),ae=Lj(n),J=ae.size?H.filter(E=>E.kind==="event"||!ae.has(E.box??E.anchorBox)):H,C=n.boxes.find(E=>E.name===n.leadBox)||null,Q=C?await qa(C.cwd,C.sessionId,{fallbackNewest:!1}):null;if(!Q&&C){let E=[...R].reverse().find(ne=>ne.type==="context.usage"&&ne.boxId===C.name);E?.payload?.window&&(Q={pct:E.payload.pct??(E.payload.occupancy!=null?E.payload.occupancy/E.payload.window:null),occupancy:E.payload.occupancy??null,window:E.payload.window,windowKnown:!0,model:E.payload.model||null})}let ve=[...h].reverse().find(E=>E.role==="assistant"&&E.model),W=ve?.model||null,be=[...n.events||[]].reverse().find(E=>E.type==="model-change"),se=Q?.model||W;be&&(!ve?.ts||be.at>=ve.ts)&&(se=be.to);let ue=C?await Oe(C.name,{lines:Ze}).catch(()=>""):"",me=C&&wo(C.agent,ue)?await Mn(C.name).catch(()=>ue):ue,j=C?Tr(C,me):null;if(j&&C){let E=Cl(C,j,me);if(E){let ne=C0(C.name,j.promptId);ne.action!=="give-up"&&(ne.action==="send"&&(Be(C.name,E.keys,{kind:"auto-reject"}).catch(()=>{}),ne.first&&$(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:C.name,provider:C.agent,payload:{ts:Date.now(),promptId:j.promptId,rule:E.id}}).catch(()=>{})),j=null)}}!j&&C&&!ws(C.agent,ue)&&!Mo(n.id).length&&(j=Xf(J,{leadBoxId:C.name,provider:C.agent,isAnswered:E=>R.some(ne=>ne.type==="prompt.answered"&&ne.payload?.promptId===E)})),j&&fx(n,C,j);let ie=J.filter(E=>!(E.kind==="message"&&E.role==="assistant"&&E.ask&&!String(E.text||"").trim()&&!E.images?.length)),Ae=!!C&&ou(C.name,C.agent,ue)&&!j;C&&!C.readyAt&&(Ae||j||ue&&gs(C.agent,ue))&&(C.readyAt=Date.now(),await ee());let $e=!!C&&!C.readyAt&&Date.now()-(n.createdAt||0)<jj;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&C&&gs(C.agent,ue)&&!j){let E=await Z(),ne=pe(E,n.id);ne?.setup&&!ne.setup.connectedAt&&(ne.setup.connectedAt=Date.now(),n.setup.connectedAt=ne.setup.connectedAt,await $(ne,{type:"provider.connected",actor:"system",source:"pane",boxId:C.name,provider:C.agent,payload:{provider:C.agent,ts:ne.setup.connectedAt}}).catch(()=>{}),await ee())}let He=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,ze=null;if(c){let E=Date.now()-i.startedAt;if(i.viewId&&!Ae){let ne=gu(n.id);ne&&(Te(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:ne.finishedAt}),await ee())}else if(j||E>AS&&!Ae&&!i.viewId||E>jm){let ne=j?"needs-input":E>jm?"timeout":"no-view";gu(n.id,{error:ne})&&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:ne}}).catch(()=>{})}else ze={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:ie,context:Q?{pct:Q.pct,occupancy:Q.occupancy,window:Q.window,windowKnown:Q.windowKnown,model:Q.model}:null,models:{current:se,options:ox(C?.agent)},pendingPrompt:j,working:Ae,stopping:iE(n.id),leadStarting:$e,handoff:He,view:ze,queued:Mo(n.id).filter(E=>E.kind!=="ship-notify"&&E.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function Lj(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 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=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 Oe(o,{lines:Ze}).catch(()=>"");u=ou(o,l.agent||r.agent,f)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}async function Nu(e,{promptId:t,answers:n,text:r}={}){let o=pe(await Z(),e);if(!o)throw new Error(`track "${e}" not found`);ec(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 Ap(s);if(i||(i=await Fj(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 Qe(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 Be(o.leadBox,["Escape"],{kind:"answer-prompt"}),c={mode:"keys",value:"Escape",count:1};else if(i.answerMode==="say"){let h=ik(i,n||[],typeof r=="string"?r:"");if(!h)throw new Error("no answer selected \u2014 pick an option or reply in chat");await Ct(o.id,h,{kind:"prompt-answer"}),c={mode:"say",value:h,count:1}}else if(i.provider==="claude"||i.answerMode==="keys"){let h=I0(i,n||[]);await Be(o.leadBox,h,{kind:"answer-prompt"}),c={mode:"keys",value:h.join(" "),count:h.length}}else{let h=Ob(i,n||[]);await Qe(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||""})),A=(g.options||[]).map((R,B)=>k.has(B)?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:S,rejected:A})}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(()=>{}),Wp(o,s,i,c),{ok:!0,promptId:i.promptId,sent:c.count}}async function Fj(e,t){if(!t)return null;let n=await F(e).catch(()=>[]);return Xf(wr(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=pe(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 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=$0(a,n);return c.length?(await Be(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 Pu(e){let t=Wi.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},Wi.set(e,t)),t}function Mo(e){return(Wi.get(e)?.items??[]).map(t=>({...t}))}function Qi(e){let t=Wi.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=Qi(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=pe(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 Dh(e){let t=Pu(e);t.timer||(t.timer=setInterval(()=>Hj(e).catch(()=>{}),Uj))}async function Hj(e){let t=Wi.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=pe(await Z(),e);if(!n||n.archivedAt){Qi(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 Yh(o)&&(o=await zi(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 Oe(n.leadBox,{lines:Ze}).catch(()=>"");if(wl(s?.agent,a)){Oo(t,!1);return}if(wo(s?.agent,a)){let c=await Mn(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 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 zi(n,s,"queue-gate")}await ee()}finally{t.flushing=!1}}}async function aE(e,t,n,r){let o=yo(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(Zs(e,[n]),await ee()),z0(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 Wj(e,t){let n=await Oe(e.leadBox,{lines:Ze}).catch(()=>"");if(!wo(t?.agent,n))return!1;let r=await Mn(e.leadBox).catch(()=>n);return!!Tr(t,r)}async function Eh(e,t,n,r,o=null,s=null){await aE(e,t,r,o);let a=qi.get(e.id)||0,i=r,c=!1,l=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(i=tE(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=jT(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}),(qi.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 Wj(e,t)){let d=Pu(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 Qe(e.leadBox,i,{...un(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 rL(e,t,i)||(await cE(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 Bh(e,{actions:t}={}){Pu(e).items.push({id:Po(),text:Ex(t),ts:Date.now(),kind:"ship-notify"}),Dh(e)}async function Ct(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=pe(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`);ow(s);let a=s.boxes.find(p=>p.name===s.leadBox),i=Ts(t);await aE(s,a,i,n),ec(e,"say");let c=await ge(s.leadBox);if(c&&await Yh(c)?await zi(s,a,"say")?(await ee(),c=await ge(s.leadBox)):c=null:!c&&await nc(s)&&(await ee(),c=await ge(s.leadBox)),!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l=Pu(e),u=await Oe(s.leadBox,{lines:Ze}).catch(()=>""),f=l.items.length>0||wl(a?.agent,u);if(!f&&wo(a?.agent,u)){let p=await Mn(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),Dh(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 Eh(s,a,c,i,n,o)}catch(p){if(p?.code!=="cli-not-running"||!await zi(s,a,"say-gate")||(await ee(),c=await ge(s.leadBox),!c))throw p;d=await Eh(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 jh(e,{hint:t}={}){let n=pe(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=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()?`${VT}
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()}`:VT;try{await Ct(e,a,{kind:"spin-up-view"})}catch(i){throw gu(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Du(e){let t=pe(await Z(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);qi.set(e,(qi.get(e)||0)+1);let n=Qi(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=Yj(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,No(qj)]);let a=pe(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 iE(e){let t=Js.get(e);return!!t&&!t.canceled}function ec(e,t){let n=Js.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function Lh(e){ec(e,"track-ended"),qi.delete(e),Qi(e)}function Yj(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=pe(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<Kj&&!r.canceled;g++){await Be(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let k of Gj){await No(k);let S=await Oe(s.leadBox,{lines:Ze}).catch(()=>"");if(!ws(a?.agent,S)){c=!0;break e}}}if(!c){l=!0;for(let g=0;g<zj&&!r.canceled&&(await No(Vj),!r.canceled);g++){let k=await Oe(s.leadBox,{lines:Ze}).catch(()=>"");if(!ws(a?.agent,k)){c=!0;break}await Be(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=pe(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 Qj(u,f).catch(()=>null),d||(p=await nL(u,f).catch(()=>null)));let h=u&&i&&!r.canceled?await Xj(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 Jj(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 Jj(e,t,n){await $(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function Xj(e){let t=xu(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 Qj(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 Zj){await No(r);let o=await Oe(e.leadBox,{lines:Ze}).catch(()=>""),s=Qa(t.agent,o);if(s&&gl(n.text,s))return await cE(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 nL(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>eL||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!Ue(r.text))return null;for(let s of tL){await No(s);let a;try{a=await bp(t,{})}catch{return null}if(Fb(a,r))return null;let i=await Oe(e.leadBox,{lines:Ze}).catch(()=>"");if(Qa(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 rL(e,t,n){return ti({sessionName:e.leadBox,agent:t?.agent,agentCmd:na(t?.agent),text:n,trackId:e.id,flow:"say"})}async function cE(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 Oe(e,{lines:Ze}).catch(()=>""),a=Qa(t,s);if(!a||r&&!gl(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=>Ue(s).includes(Ue(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 sL(e,t){let n=Ue(t);if(!n)return!1;if(Mo(e.id).some(o=>Ue(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>oL)break;if(!(s.type!=="said"||!s.text||Ue(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=pe(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&&sL(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;Ue(o).includes(Ue(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 Uh(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=pe(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=sx(a,n),l=[...r.events||[]].reverse().find(f=>f.type==="model-change")?.to??null;l||(l=(await qa(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 ax(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 lE(e){for(let t of e){if(!t||!await Es(t))continue;let n=await D0(t).catch(()=>null);if(!n)continue;if((await V.stat(Y.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function Mt(e){let t=e;return t?t.kind==="multi"?Array.isArray(t.repos)?t.repos.filter(Boolean):[]:t.base?[{name:Y.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 Mt(e?.workspace)){if(!n?.dir)continue;let r=await li(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await ui(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function uE(e){let t=e;typeof t=="string"&&!Y.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await Zo(t)??await Lc(t));let n=await lE([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 aL(e,t,n,r){let o=`track/${cw(t)}-${e}`,s=[];try{await V.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await uE(i);if(s.some(p=>p.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await Se(c).catch(()=>null),u=Y.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let p=2;a.has(u);p++)u=`${Y.basename(c)}-${p}`;a.add(u);let f=Y.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 tc(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await _t(i.base,i.dir).catch(()=>{});throw await V.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function Hh(e,t){let n=await Z(),r=pe(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 uE(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=Y.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let d=2;i.has(c);d++)c=`${Y.basename(s)}-${d}`;let l=Y.join(o.dir,c),u=await Is(s);await B0(s,o.branch)?await Ml(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 tc(o.dir,o.repos,o.branch),Te(r,"retagged",{action:"add",repo:a??s,name:c,workspace:dE(o)}),await ee(),f}async function Wh(e,t){let n=await Z(),r=pe(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 Ot.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 li(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await ui(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 _t(s.base,s.dir).catch(()=>{}),await V.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await tc(o.dir,o.repos,o.branch),Te(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:dE(o)}),await ee(),{removed:s.name}}async function iL(e,t,{repo:n,repos:r,cwd:o}={}){await V.mkdir(Ui,{recursive:!0});let s=Y.join(Ui,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return aL(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!Y.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await Zo(n)??await Lc(n));let i=await lE([n,o,Aj]);if(i){let c=`track/${cw(t)}-${e}`;try{let l=await Is(i);await _s(i,s,c,l),await Gi(s);let u=await Se(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await V.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await V.mkdir(s,{recursive:!0}),await Mp(s),await Gi(s),{dir:s,base:null,branch:null,kind:"repo"}}async function Gi(e){try{await V.writeFile(Y.join(e,"AGENTS.md"),Fi,{flag:"wx"})}catch{return}await dL(e,["/AGENTS.md"])}function uL(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`${lL}
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 tc(e,t,n){let r=uL(t,n);for(let o of["CLAUDE.md","AGENTS.md"])await V.writeFile(Y.join(e,o),r).catch(()=>{})}async function pE(e){let{stdout:t}=await ZT("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return Y.resolve(e,t.trim())}async function dL(e,t){try{let n=await pE(e);await V.mkdir(Y.dirname(n),{recursive:!0});let r=await V.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
232
- `).includes(s));o.length&&await V.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 fL(e,t){try{let n=await pE(e),r=await V.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 V.writeFile(n,o.join(`
239
- `))}catch{}}async function qh(){let e={refreshed:0,removed:0,codexGlobal:null};try{await V.mkdir(vn,{recursive:!0}),await V.writeFile(Y.join(vn,"CLAUDE.md"),cL).catch(()=>{}),await V.writeFile(Y.join(vn,"AGENTS.md"),Fi).catch(()=>{});let t=process.env.CODEX_HOME||Y.join(process.env.HOME||"/tmp",".codex");if((await V.stat(t).catch(()=>null))?.isDirectory()){let r=Y.join(t,"AGENTS.md"),o=await V.readFile(r,"utf8").catch(()=>null);o===null?(await V.writeFile(r,bh,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):yh(o)&&o!==bh&&(await V.writeFile(r,bh).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[Ui,ta]){let o=await V.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=Y.join(r,s.name),i=Y.join(a,"AGENTS.md"),c=await V.readFile(i,"utf8").catch(()=>null);c!==null&&yh(c)&&c!==Fi&&(await V.writeFile(i,Fi).catch(()=>{}),e.refreshed++);let l=Y.join(a,"CLAUDE.md"),u=await V.readFile(l,"utf8").catch(()=>null);u!==null&&yh(u)&&(await V.rm(l,{force:!0}).catch(()=>{}),await fL(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function mE(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of Mt(t))n.base&&n.dir&&await _t(n.base,n.dir).catch(()=>{});await V.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await _t(t.base,t.dir):await V.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function Bu({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 Xi(o,s),i=await Z(),c=Po().slice(0,8),l=await iL(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(sl(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:[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:k})=>({name:h,base:w,baseRef:g,repo:k}))}:{}}}),i.tracks.push(p),await ee(),Ja({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())}}),Rt(p)}async function Kh({provider:e="claude",fresh:t=!1}={}){if(!pL.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 Rt(r);if(u.boxes.find(d=>d.name===u.leadBox)?.state==="live")return u}await Do(r.id).catch(()=>{})}let o=(await Xi(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=Po().slice(0,8),a=Y.join(vn,"setup",s);await V.mkdir(a,{recursive:!0});let i=await pr(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&Ja({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 Z()).tracks.push(c),await ee(),Rt(c)}async function Gh(e,t,n){await Zd(t.cwd).catch(()=>{}),await NS(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 dw(a).catch(()=>{}),Ot.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 Gt(a.name).catch(()=>{})}async function Vh(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 nT(s),Lh(e),await Gh(e,s,"track deleted"),n?await MT(e).catch(()=>{}):await CT(e).catch(()=>{}),await lx(),await mE(s),t&&await rT(e).catch(()=>{}),t?await kT(e).catch(()=>{}):await bT(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=pe(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 ee(),n.kind==="setup"?(await hE(e),Rt(n)):(Vi.add(e),wL(e).catch(()=>{}).finally(()=>Vi.delete(e)),{...await Rt(n),archiving:!0})}async function wL(e){try{await gL(e)}catch{}await hE(e).catch(()=>{})}async function hE(e){let t=await Z(),n=pe(t,e);if(!(!n||!n.archivedAt)){await Gh(e,n,"track archived");for(let r of n.boxes)Fr.has(r.state)||(r.state="stopped");await ee()}}async function gL(e){let t=await Z(),n=pe(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 Mk(n.leadBox,i.cwd,{timeoutMs:hL})),s="lead-cli"}catch{}if(r||(r=zk(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 Wn(e,t){let n=await rt(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 qn(e,t){return ju(e,t,"merged")}async function Bo(e,t){let n=await rt(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 Dx(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=pe(await Z(),n.trackId);if(!a)return null;let i=s[0];return Ei(Rt(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 ju(e,t,n="merged"){let r=await rt(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 Px(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];try{return await Ct(r.trackId,wE(a),{kind:"merge-notify"}),!0}catch{return!1}}function wE(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 ${zT[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 ${zT[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 Yh(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<Ha()?!1:Cn(e.name)}async function zi(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 Gt(t.name).catch(()=>{}),t.state="stopped",nc(e))}async function nc(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=yL(e,r,{freshSession:t,reason:n}).finally(()=>kh.delete(r.name));return kh.set(r.name,s),s}async function yL(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?Fa($h(t.agent),s,t.name):Rh(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await ol(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=xa(u.hookToken),Ja({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 Lu(e,{freshSession:t=!1}={}){let n=await Z(),r=pe(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,Vi.delete(e),Te(r,"unarchived",{}),await nc(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await ee(),Rt(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 Z(),o=pe(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 Rt(o);let s=o.name;return o.name=n,Te(o,"renamed",{from:s,to:n}),await ee(),Rt(o)}async function Xh(){let e=await Z(),t=0;for(let n of e.tracks||[])n.transferredTo&&Pl(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await ee(),t}async function Zh(){let e=await Z(),t=new Set((await Kt()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!Ge(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(Ge(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await Gt(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 Fu(e,{freshSession:t=!1}={}){let n=await Z(),r=pe(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(Fr.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await ge(r.leadBox)){let i=await Oe(r.leadBox,{lines:Ze}).catch(()=>"");if(wl(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await Gt(r.leadBox),o.state="stopped"}let a=await nc(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 Rt(r)}async function Qh(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 Fu(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 YT(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return mu({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 Ru(e,t){let n=await Z(),r=pe(n,e);r&&(r.handoff={...r.handoff||{},...t},await ee())}function gE(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 Z(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=gE(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 Gt(i).catch(()=>{}),a&&await Gt(a).catch(()=>{})}return t&&await ee(),t}async function Uu(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=pe(await Z(),e);if(!s)throw new Error(`track "${e}" not found`);ec(e,"handoff");let a=await Xi(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:nE(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return ea.set(e,l),await Ru(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),bL(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 Ru(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 bL(e,t,n,r,o){let s=async(B,T={})=>{e.step=B,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${B}`),await Ru(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=pe(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 np(e.fromBox,{timeoutMs:eE})}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 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 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 Oe(e.fromBox,{lines:Ze}).catch(()=>""),p);if(!gs(o,h)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let B=Rh(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await up(e.fromBox,{agentCmd:B,agent:c,resumeSessionId:l,pinned:u});let T=await Z(),_=pe(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=pe(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(),A=Qs(k),R=A[A.length-1];R.endedAt=S,e.reason&&(R.endReason=e.reason),A.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:A.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 Ru(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 Z(),r=pe(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 Ot.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),kL(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 kL(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 np(t.leadBox,{timeoutMs:eE})}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 Mt(t.workspace)){if(!u?.dir)continue;let f={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await Qt(u.dir,["push","origin",o],_h);let{stdout:d}=await Qt(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 Z(),c=pe(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 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 Hu(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await Z(),o=pe(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();Pl(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 ee(),{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 Hu(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 JT(e,t,n){try{await Ml(e,t,n)}catch{await Qt(e,["worktree","prune"]).catch(()=>{}),await Ml(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 xL({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{xh.delete(t)}}async function xL({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 Xi(n,r),k=await Z(),S=pe(k,e);if(S&&!S.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);S&&(await dh({id:S.id,cwd:S.cwd}).catch(()=>{}),await mE(S),k.tracks.splice(k.tracks.indexOf(S),1),await ee()),await V.mkdir(Ui,{recursive:!0});let A=Y.join(Ui,e);await V.rm(A,{recursive:!0,force:!0}).catch(()=>{});let R=null,B=!1,T=[];try{let _=[];if(i)for(let j of Array.isArray(c)?c:[]){let ie=typeof j=="string"?j:j?.repo;if(!ie||!/^[^/\s]+\/[^/\s]+$/.test(ie))continue;let le=await Zo(ie)??await Lc(ie);await Qt(le,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],_h),_.push({slug:ie,base:le,name:typeof j=="object"?j?.name??null:null})}if(i&&_.length===1){let{base:j,slug:ie}=_[0];await JT(j,A,i),T.push({base:j,dir:A}),await Gi(A);let le=await Is(j);R={dir:A,base:j,branch:i,kind:"worktree",baseRef:le,repo:ie}}else if(i&&_.length>=2){await V.mkdir(A,{recursive:!0});let j=new Set([".bostrat"]),ie=[];for(let le of _){let Ae=le.name||Y.basename(le.base);j.has(Ae)&&(Ae=le.slug.replace("/","-"));for(let ze=2;j.has(Ae);ze++)Ae=`${Y.basename(le.base)}-${ze}`;j.add(Ae);let $e=Y.join(A,Ae);await JT(le.base,$e,i),T.push({base:le.base,dir:$e});let He=await Is(le.base);ie.push({name:Ae,dir:$e,base:le.base,baseRef:He,repo:le.slug})}await tc(A,ie,i),R={dir:A,kind:"multi",branch:i,repos:ie}}else B=!0,await V.mkdir(A,{recursive:!0}),await Mp(A),await Gi(A),R={dir:A,base:null,branch:null,kind:"repo"};let O=!1,I=null,U=null;if(l?.sha&&R.kind==="worktree")try{await Qt(A,["fetch","origin",l.ref||lh(e)],_h);let{stdout:j}=await Qt(A,["rev-parse","FETCH_HEAD^"]),{stdout:ie}=await Qt(A,["rev-parse","HEAD"]),le=j.trim()===ie.trim();le||await Qt(A,["merge-base","--is-ancestor",ie.trim(),j.trim()]).then(()=>!0,()=>!1)&&(await Qt(A,["reset","--hard",j.trim()]),U={from:ie.trim(),to:j.trim()},le=!0),le?(await Qt(A,["read-tree","--reset","-u","FETCH_HEAD"]),await Qt(A,["reset","-q"]),O=!0):I="snapshot does not parent the fetched branch head"}catch(j){I=String(j?.message||j).split(`
244
- `)[0]}else l?.sha&&(I="wip snapshots cover single-repo worktrees only");await qT({id:e,cwd:A}).catch(()=>({restored:!1}));let H=Y.join(A,Co),ae=null;(await Xc(A)).restored?ae="checkpoint":typeof u=="string"&&u.trim()&&(await V.mkdir(Y.dirname(H),{recursive:!0}),await V.writeFile(H,u),ae="brief");let C=new Set(k.tracks.flatMap(j=>(j.boxes||[]).map(ie=>ie.name))),Q=null;p&&!C.has(p)&&!await ge(p).catch(()=>null)?Q=p:(Q=`${t.trim()} lead`,C.has(sl(Q))&&(Q=`${t.trim().slice(0,50).trim()} ${e} lead`));let ve=await pr(Q,A,{agentCmd:g,agent:n});Ja({cwd:ve.cwd,sessionName:ve.name,agent:n,agentCmd:g});let W=Date.now(),be=ew(ve,"lead","live"),se=(Array.isArray(f)?f:[]).filter(j=>j&&typeof j=="object").map(j=>({...j})),ue=se[se.length-1];ue&&ue.endedAt==null&&(ue.endedAt=W,ue.endReason==null&&(ue.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 me={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(me,"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:me.name,cwd:me.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:j,base:ie,baseRef:le,repo:Ae})=>({name:j,base:ie,baseRef:le,repo:Ae}))}:{}}}),k.tracks.push(me),await ee(),{...await Rt(me),adopt:{wipApplied:O,wipSkipped:I,...U?{wipAdvanced:U}:{},codeless:B,artifactSource:ae}}}catch(_){for(let O of T)await _t(O.base,O.dir).catch(()=>{});throw await V.rm(A,{recursive:!0,force:!0}).catch(()=>{}),_}}async function yE(e,t,n){let r=await Z(),o=pe(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 rc(e)}function bE(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 kE(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function EL(e,t,n){if(!kE(n)||Ot.has(t)||!await ge(n.box).catch(()=>null))return!1;try{await V.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 Ot.set(t,s),vE(s,o).catch(a=>xE(s,a)),!0}async function iw(){let e=await Z(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Ot.has(r))continue;if(await EL(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=bE(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 XT(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||Fr.has(r.state)||Ot.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?Y.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 XT(n,r.name,o)}}return t=await AL(e)||t,t&&await ee(),t}async function XT(e,t,n){if(t&&await Gt(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of Mt(e.workspace)){let s=Y.join(n,o.name);await _t(o.base,s).then(()=>!0,()=>!1)||await _t(o.dir,s).catch(()=>{})}await V.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await ge(e.leadBox).catch(()=>null);r?.cwd&&await _t(r.cwd,n).catch(()=>{})}async function AL(e){let t;try{t=await V.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 Ot.values())o.dir&&n.add(Y.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=Y.join(ta,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of Mt(a.workspace))await _t(i.base,Y.join(s,i.name)).catch(()=>{});await V.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await ge(a.leadBox).catch(()=>null):null;i?.cwd?await _t(i.cwd,s).catch(()=>{}):await V.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await re({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"||!Ts(n))throw new Error("task (string) required");let s=await Xi(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=pe(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=Mt(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:nE(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${cw(i.name)}-${f}`,base:null,repos:u,dir:Y.join(ta,`${e}-${f}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Ot.set(f,d),await rc(d),_L(d,c,s).catch(p=>xE(d,p)),d}async function xE(e,t){e.failedStep=e.step,e.error=t instanceof Yi?"canceled":t?.message||String(t),e.step=t instanceof Yi?"canceled":"error",e.finishedAt=Date.now(),await dw(e).catch(()=>{}),await rc(e).catch(()=>{}),await OL(e).catch(()=>{})}function qu(e){let t=Ot.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=Ot.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 _L(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 rc(e)}else e.base=await As(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await Ys(e,"spawn"),await V.mkdir(ta,{recursive:!0}),e.repos){await V.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await _s(a.leadDir,Y.join(e.dir,a.name),e.branch,a.base);let s=Mt((pe(await Z(),e.trackId)||{}).workspace);await tc(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 Gi(e.dir);await IL(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 $L(e,o),await rE(e.trackId,o.name,Ij(e.task,!!e.repos),{kind:"subtask"}),await vE(e,t)}async function vE(e,t){await Ys(e,"working");let n=Y.join(e.dir,$u);if(await ML(n,e),e.canceled)throw new Yi;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=Y.join(e.dir,l.name);await Cp(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:YT({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await Pp(l.leadDir,l.base,e.branch,zs),l.files=await Dp(l.leadDir,l.base,e.branch,zs);let f=await Bp(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=>Y.join(l.name,d))),i.push(...l.conflicts.map(d=>d.startsWith("patch did not apply cleanly")?`${l.name}: ${d}`:Y.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:YT({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await Pp(t.cwd,e.base,e.branch,zs),e.files=await Dp(t.cwd,e.base,e.branch,zs);let s=await Bp(t.cwd,e.base,e.branch,zs);e.applied=s.applied,e.conflicts=s.conflicts}await rc(e);let r=await CL(e,t,n);await Ys(e,"resume"),await rE(e.trackId,e.leadBox,$j(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await Ys(e,"reap"),await dw(e),e.step="done";let o=Date.now();await yE(e.trackId,e.id,{...Wu(e),finishedAt:o}),await RL(e,o),e.finishedAt=o}async function IL(e,t){let n=Y.join(e.dir,Y.dirname(Hi));await V.mkdir(n,{recursive:!0});let r="";try{r=await kb(t.cwd,t.sessionId)}catch{}if(!r)try{r=await V.readFile(Y.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 Yh(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 V.writeFile(Y.join(e.dir,Hi),o)}async function $L(e,t){let n=await Z(),r=pe(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:xa(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]||{},...Wu(e)},await ee())}async function RL(e,t=e.finishedAt){let n=await Z(),r=pe(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 OL(e){let t=await Z(),n=pe(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]||{},...Wu(e)},await ee()}async function CL(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=Y.join(t.cwd,r);await V.mkdir(Y.dirname(o),{recursive:!0}),await V.copyFile(n,o)}catch{}return r}async function dw(e){if(e.dir&&await Zd(e.dir).catch(()=>{}),e.box&&await Gt(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await _t(t.leadDir,Y.join(e.dir,t.name)).catch(()=>{});await V.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await ge(e.leadBox).catch(()=>null))?.cwd;n&&await _t(n,e.dir).catch(()=>{})}}async function ML(e,t){let n=(t.startedAt||Date.now())+vL;for(;;){if(t.canceled||t.forceMerge)return;try{await V.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await No(SL)}}function No(e){return new Promise(t=>setTimeout(t,e))}var ZT,vn,QT,Ej,Ui,Aj,Ou,Ji,Lr,Co,eE,_j,$u,Hi,Ij,$j,Ut,mh,pe,hh,Te,wh,gh,Cj,Fr,GT,Pj,Dj,Bj,jj,Uj,Wi,VT,qj,Kj,Gj,Vj,zj,Js,qi,Zj,eL,tL,oL,dE,Ki,fE,cL,Fi,yh,lL,bh,pL,Vi,mL,hL,zT,kh,Ah,ew,ea,ra,_h,Qt,Ih,nw,xh,vL,SL,ta,zs,Ot,TL,jo,Wu,rc,cw,Yi,Nr=L(()=>{Ra();lt();sp();Yk();Xa();cr();fl();e0();it();cn();Yo();dl();g0();io();_p();$p();N0();yl();Uf();pl();Zf();zt();Nl();ar();Dn();Za();Ll();ix();qp();tS();ep();Vf();rS();Am();de();hu();ku();vi();bo();Km();Ks();th();_u();ch();Ln();lu();LT();fh();KT();Zc();ZT=Tj(Sj),vn=process.env.BOSTRAT_STATE_DIR||Y.join(process.env.HOME||"/tmp",".bostrat"),QT=Y.join(vn,"tracks.json"),Ej=Y.join(vn,"events.jsonl"),Ui=Y.join(vn,"workspaces"),Aj=process.env.BOSTRAT_DEFAULT_REPO||null,Ou={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"}},Ji=Object.keys(Ou);Lr={at:0,value:null};Co=".bostrat/handoff/latest.md",eE=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;_j=/\(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\.\)$/;$u=".bostrat/handoff/subtask-result.md",Hi=".bostrat/handoff/lead-context.md",Ij=(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 ${Hi} \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 ${$u} (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 ${Hi} \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 ${$u} 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.`,$j=(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."),Ut=null,mh=null;pe=(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),Rj(e.id,r),ux(e,r),r};Tb(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(()=>{}))});wh=Y.join(vn,"plane-link","update-notice.json");gh=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),Cj=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);Fr=new Set(["merged","conflict","canceled","failed","handed-off"]),GT=new Map;Pj=5e3;Dj={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};Bj=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];jj=10*6e4;Uj=1500,Wi=new Map;VT="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.";qj=4e3,Kj=3,Gj=[300,350,400],Vj=1e3,zj=12,Js=new Map,qi=new Map;Zj=[250,400,500,600];eL=3e4,tL=[350,650,900];oL=12e4;dE=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}))});Ki="# bostrat workspace",fE=`${Ki}
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
- `,cL=fE,Fi=fE+ck;yh=e=>typeof e=="string"&&(e===Ki||e.startsWith(`${Ki}
585
- `)),lL="# bostrat multi-repo workspace";bh=Fi.replace(`${Ki}
586
- `,`${Ki}
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
- `);pL=new Set(["claude","codex","cursor"]);Vi=new Set,mL=e=>Vi.has(e);hL=9e4;zT={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:xa(e.hookToken),createdAt:Date.now()});ea=new Map,ra=e=>ea.get(e)||(Ut?pe(Ut,e)?.handoff:null)||null;_h=6e4,Qt=(e,t,n=15e3)=>ZT("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),Ih=new Map,nw=e=>Ih.get(e)||null;xh=new Map;vL=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,SL=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,ta=Y.join(vn,"worktrees"),zs=[Hi,$u],Ot=new Map,TL=e=>Ot.get(e)||(Ut?Ut.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,jo=e=>{let t=new Map([...Ot.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=Ut?pe(Ut,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)},Wu=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});rc=e=>yE(e.trackId,e.id,Wu(e));cw=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",Yi=class extends Error{}});lt();import xe from"node:path";import mt from"node:fs";import ZH from"node:readline";import{fileURLToPath as QH}from"node:url";import Wt from"express";import eW from"node:http";import tW from"node:https";import Ad from"node:os";import{WebSocketServer as nW}from"ws";lt();import gO from"node-pty";async function Zy(e,t,n={}){if(!Ne(t)){ll(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await fr()){ll(e,`host tmux server not running on ${At}`),e.close(1011,"tmux server unavailable");return}if(!await ge(t)){ll(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=gO.spawn(K,["-S",At,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){ll(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"&&xO(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{}kO(t)})}var yO=6,bO=250;async function kO(e,t=yO,n=bO){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 xO(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 mf(e,t){try{e.send(JSON.stringify(t))}catch{}}function ll(e,t){mf(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}}zt();dl();sp();Nr();import{createRequire as rW}from"node:module";var NL=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(NL)&&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 PE from"node:fs";import Hr from"node:fs/promises";import XL from"node:os";import at from"node:path";import{spawn as ZL}from"node:child_process";import{createRequire as QL}from"node:module";de();Ll();import CE from"node:fs";import sc from"node:fs/promises";import BL from"node:http";import tn from"node:path";import Gu from"node:os";import{createRequire as jL}from"node:module";import mw from"ws";import PL from"node:path";import DL from"node:os";var oc=process.env.BOSTRAT_STATE_DIR||PL.join(process.env.HOME||DL.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 TE(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 EE(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 en=(()=>{try{return jL(import.meta.url)("../package.json").version||null}catch{return null}})(),AE=process.env.BOSTRAT_STATE_DIR||tn.join(process.env.HOME||Gu.tmpdir(),".bostrat");function Lo({env:e=process.env,pkgDir:t=tn.resolve(tn.dirname(new URL(import.meta.url).pathname),".."),exists:n=CE.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(tn.join(t,"..",".git"))?"git-checkout":"dev"}function ac(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 Ku(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 LL({home:e=process.env.HOME||Gu.homedir(),env:t=process.env}={}){let n=r=>{try{return CE.statSync(r),!0}catch{return!1}};return{claude:n(tn.join(e,".claude",".credentials.json")),codex:n(tn.join(t.CODEX_HOME||tn.join(e,".codex"),"auth.json"))}}var st=1,_E=1e3,IE=3e4,FL=6e4,UL=1500,HL=500,Ur=100,WL=2e3,qL=25e3,KL=6e4,ME=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},GL=ME(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),VL=3e4,$E=10*6e4,zL=400,RE=250,YL=ME(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),hw=4,JL=6e4,OE=6e4;function NE({url:e,token:t,nodeId:n=Gu.hostname(),name:r=Gu.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,metricsMs:c=JL,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=GL,unackedRetryMs:A=KL,pingMs:R=qL,maxInflightEvents:B=zL,httpTimeoutMs:T=YL,stallBackoffMinMs:_=VL,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=EE(e);let U=h.replace(/^http/,"ws"),H=new Set,ae=new Map,J=new Map,C=tn.join(AE,"plane-link","cursor.json"),Q=tn.join(AE,"plane-link","dead-letter.ndjson"),ve=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),W={},be={},se=new Map,ue=null,me=null,j=0,ie=0,le=0,Ae=Promise.resolve(),$e="ws",He=0,ze=!1,E=0,ne=!1,Ke=Ur,y=new Set,m=[],b=null,M=null,X=!1,he=!1,De=_E,Ye=null,tt=null,rr=null,An=null,_n=null,Rd=!1,Cc=0;async function zI(){try{W=JSON.parse(await sc.readFile(C,"utf8"))}catch{W={}}}function YI(){Rd=!0,!rr&&(rr=setTimeout(async()=>{if(rr=null,!!Rd){Rd=!1;try{await sc.mkdir(tn.dirname(C),{recursive:!0}),await sc.writeFile(C,JSON.stringify(W))}catch(P){I.error("[plane-link] cursor flush failed:",P?.message||P)}}},WL),rr.unref?.())}function ot(P){return!M||M.readyState!==mw.OPEN?!1:(M.send(JSON.stringify(P)),!0)}function ya(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+A,tries:(q?.tries??0)+1,nacks:q?.nacks??0})}return $e==="http"?(QI(P),!0):ot({v:st,ch:"events",type:"append",events:P})}function JI(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=JI(P),N=x==null?D:Math.min(D,x-1);N>(W[P]??0)&&(W[P]=N,YI())}function ba(){if(ue=Date.now(),me!=null){let P=Date.now()-me;I.log(`[plane-link] spine sync recovered after ${Math.round(P/1e3)}s degraded (${j} stall redial(s))`);let D=me;me=null,j=0,ie=0,ze=!1,E=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);ba()}function Ag(P,D){le++;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 sc.mkdir(tn.dirname(Q),{recursive:!0}),await sc.appendFile(Q,JSON.stringify(x)+`
593
- `)}).catch(N=>I.error(`[plane-link] dead-letter write failed: ${N?.message||N}`))}function _g(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 Pe=se.get(Ee);Pe&&(x?(se.delete(Ee),Ag(Pe,D),(be[Pe.trackId]??0)<Pe.seq&&(be[Pe.trackId]=Pe.seq),q.add(Pe.trackId)):(Pe.nacks++,Pe.retryAt=ye+Math.max(1e3,Number(N)||A)))}for(let Ee of q)Od(Ee);ba()}function Ig(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 $g(){if(!X||!se.size)return;let P=Date.now(),D=Ig(P);if(D<S||ue!=null&&P-ue<S||$e==="http"&&ze||ie>P)return;j++;let x=Math.min(_*2**(j-1),$E);if(me==null){me=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:me,unacked:se.size,oldestAgeMs:D,mode:$e})}catch(N){I.error(`[plane-link] onDegraded failed: ${N?.message||N}`)}}if($e==="http"){ze=!0,E=P+x,I.error(`[plane-link] ingest circuit OPEN (stall #${j}); probing /v1/ingest/health in ${Math.round(x/1e3)}s`);return}ie=P+x,I.error(`[plane-link] closing the link and redialing in ${Math.round(x/1e3)}s (stall redial #${j})`);try{M?.terminate()}catch{}}function Md(){if(!X)return;let P=Date.now();if($e==="http"&&ze)return;let D=[...se.values()].filter(N=>N.event&&N.retryAt<=P&&!($e==="http"&&y.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"?Ke: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(He>=hw)return;ya(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(!ya(q))return}}async function XI(P=null){for(;;){if(!X)return!1;let D=se.size<B,x=$e!=="http"||He<hw&&!ze&&(!P||!y.has(P));if(D&&x)return!0;await new Promise(N=>setTimeout(N,100))}}function Nd(){if(b=null,!X||!m.length)return;let P=m;if(m=[],$e!=="http"){for(let x=0;x<P.length;x+=Ur)ya(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(y.has(x)||He>=hw||ze){m.push(...N);continue}for(let q=0;q<N.length;q+=Ke)ya(N.slice(q,q+Ke))}m.length&&!b&&(b=setTimeout(Nd,RE),b.unref?.())}let ZI=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||A))}N&&ba()};async function QI(P){let D=new Set(P.map(x=>x.trackId));for(let x of D)y.add(x);He++;try{let x=await O(`${ve}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:ZI(P)}),signal:AbortSignal.timeout(T)}),N=(Number(x.headers.get("retry-after"))||0)*1e3;if(x.status===200){let q=await x.json();Ke=Ur;for(let ye of q.results??[]){Cd(ye.acked??[]);let Ee=(Pe,kt)=>{let Dt=new Map;for(let Je of Pe??[])(Dt.get(Je.reason)??Dt.set(Je.reason,[]).get(Je.reason)).push(Je.id);for(let[Je,Ng]of Dt)_g(Ng,Je,kt,q.retryAfterMs??null)};Ee(ye.rejected,!0),Ee(ye.deferred,!1)}Cd(q.discarded??[]),ba();return}if(x.status===429){zo(P,"overloaded",N||5e3,{progress:!0});return}if(x.status===413&&P.length>1){Ke=Math.max(1,Math.floor(P.length/2)),I.error(`[plane-link] ingest request too large (${P.length} events) \u2014 halving batches to ${Ke}`),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),Ag(q,"too_large"),(be[q.trackId]??0)<q.seq&&(be[q.trackId]=q.seq),Od(q.trackId)),ba();return}if(x.status===401||x.status===403){if(Date.now()-Cc>=OE){Cc=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&&(Ke=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 ${Ke}`)),zo(P,N?"timeout":"network",5e3,{progress:!1})}finally{He--;for(let x of D)y.delete(x)}}async function e$(){if($e!=="http"||!ze||!X||ne)return;let P=Date.now();if(!(E>P)){ne=!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"),ze=!1,E=0,ie=Date.now()+T+A+1e3;for(let x of se.values())x.retryAt=Math.min(x.retryAt,Date.now());Md()}catch(D){j++;let x=Math.min(_*2**(j-1),$E);E=Date.now()+x,I.error(`[plane-link] ingest door still not answering (${D?.message||D}); next probe in ${Math.round(x/1e3)}s`)}finally{ne=!1}}}function Rg(){let P=Date.now();return{mode:$e,unacked:se.size,oldestUnackedAgeMs:Ig(P),lastProgressAt:ue,degradedSince:me,stallRedials:j,deadLettered:le,http:$e==="http"?{inFlight:He,circuitOpen:ze,nextProbeInMs:ze?Math.max(0,E-P):0,batchCap:Ke}:null}}async function Og(){if(!i)return;let P;try{P=await i()}catch(D){I.error("[plane-link] metrics sample failed:",D?.message||D);return}P&&ot({v:st,ch:"ctl",type:"metrics",metrics:{...P,planeLink:Rg()}})}function t$(){i&&(_n&&clearInterval(_n),Og(),_n=setInterval(Og,c),_n.unref?.())}async function n$(){let P;try{P=await o()}catch(D){I.error("[plane-link] backfill listTracks failed:",D?.message||D);return}ot({v:st,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(!X)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"?Ke:Ur;for(let Ee=0;Ee<q.length;Ee+=ye){if(!await XI(D.id))return;let Pe=q.slice(Ee,Ee+Math.min(ye,$e==="http"?Ke:Ur)).map(kt=>({trackId:D.id,event:kt}));if(!ya(Pe))return}}}function Cg(P){!X||!P?.trackId||typeof P.id!="string"||(m.push({trackId:P.trackId,event:P}),b||(b=setTimeout(Nd,RE),b.unref?.()))}let ka=new Map;async function r$(P){let{reqId:D,method:x,path:N,headers:q={},body:ye}=P,Ee=Object.fromEntries(Object.entries(q).filter(([,kt])=>kt!=null)),Pe=new AbortController;ka.set(D,Pe);try{if(P.host){await o$(P,Ee,Pe);return}let kt=await fetch(h+N,{method:x,headers:Ee,body:ye?Buffer.from(ye,"base64"):void 0,signal:Pe.signal}),Dt=Object.fromEntries(kt.headers);for(let Je of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete Dt[Je];if(Dt["content-type"]||(Dt["content-type"]="application/octet-stream"),ot({v:st,ch:"control",type:"http_head",reqId:D,status:kt.status,headers:Dt}),kt.body){for await(let Je of kt.body)if(!ot({v:st,ch:"control",type:"http_data",reqId:D,data:Buffer.from(Je).toString("base64")}))break}ot({v:st,ch:"control",type:"http_end",reqId:D,error:null})}finally{ka.delete(D)}}function o$(P,D,x){let{reqId:N,method:q,path:ye,body:Ee}=P,Pe=new URL(h);return new Promise(kt=>{let Dt=BL.request({host:Pe.hostname,port:Pe.port,method:q,path:ye,headers:{...D,host:P.host},signal:x.signal},Je=>{let{connection:Ng,"keep-alive":xW,"transfer-encoding":vW,upgrade:SW,...s$}=Je.headers;ot({v:st,ch:"control",type:"http_head",reqId:N,status:Je.statusCode||502,headers:s$}),Je.on("data",a$=>{ot({v:st,ch:"control",type:"http_data",reqId:N,data:Buffer.from(a$).toString("base64")})||Je.destroy()}),Je.on("end",()=>{ot({v:st,ch:"control",type:"http_end",reqId:N,error:null}),kt()}),Je.on("error",()=>{ot({v:st,ch:"control",type:"http_end",reqId:N,error:"view upstream error"}),kt()})});Dt.on("error",Je=>{ot({v:st,ch:"control",type:"http_end",reqId:N,error:Je?.message||"view request failed"}),kt()}),Ee&&Dt.write(Buffer.from(Ee,"base64")),Dt.end()})}function Mg(){if(he)return;M=new mw(e,{headers:{authorization:`Bearer ${t}`}}),M.on("open",async()=>{let D=null;try{D=await s?.()||null}catch{D=null}ot({v:st,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:en,installKind:p,...typeof d=="function"?{updatePolicy:d()}:d?{updatePolicy:d}:{},providers:LL(),...D?{agents:D}:{}})}),M.on("message",D=>{let x;try{x=JSON.parse(D)}catch{return}if(x.ch==="ctl"&&x.type==="hello_ok"){X=!0,De=_E,Ye=null,I.log(`[plane-link] connected to plane as ${n}`),x.minNodeVersion&&en&&ac(en,x.minNodeVersion)&&I.error(`[plane-link] this node is bostrat-node ${en}; the plane asks for \u2265${x.minNodeVersion} \u2014 update with: ${Ku(p)}`);try{u?.(typeof x.updatePolicy=="string"?x.updatePolicy:null)}catch{}let N=typeof x.latestNodeVersion=="string"?x.latestNodeVersion:null;if(N&&en&&ac(en,N)&&!H.has(N)){H.add(N),I.log(`[plane-link] bostrat-node ${N} is available (this node runs ${en}) \u2014 ${Ku(p)}`);try{l?.({current:en,latest:N,min:x.minNodeVersion??null,installKind:p,required:!!(x.minNodeVersion&&ac(en,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"),ze=!1,E=0,Ke=Ur,An&&clearInterval(An),An=setInterval(()=>{ot({v:st,ch:"ctl",type:"ping"}),$g(),e$().catch(()=>{}),Md(),m.length&&!b&&Nd()},R),An.unref?.(),t$(),n$().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 ${en??"?"} is below its minimum ${N??"?"} \u2014 ${x.fix||Ku(p)}`),De=IE,Ye=0;try{f?.({current:en,min:N,latest:q,fix:x.fix||Ku(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"){jl(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)){_g(x.ids,x.reason,x.permanent===!0,x.retryAfterMs??null);return}if(x.ch==="control"&&x.type==="http_open"){r$(x).catch(N=>ot({v:st,ch:"control",type:"http_end",reqId:x.reqId,error:N?.message||"tunnel error"}));return}if(x.ch==="control"&&x.type==="http_cancel"){ka.get(x.reqId)?.abort();return}if(x.ch==="attach"&&x.type==="open"){let N=new mw(U+x.path,Array.isArray(x.protocols)?x.protocols:[],x.host?{headers:{host:x.host}}:void 0);ae.set(x.streamId,N),J.set(x.streamId,[]),N.on("open",()=>{let ye=J.get(x.streamId)||[];J.delete(x.streamId);for(let{buf:Ee,bin:Pe}of ye)N.send(Ee,{binary:Pe})}),N.on("message",(ye,Ee)=>{let Pe=Ee?ye:Buffer.from(String(ye));ot({v:st,ch:"attach",type:"data",streamId:x.streamId,data:Pe.toString("base64"),...Ee?{bin:!0}:{}})});let q=()=>{J.delete(x.streamId),ae.delete(x.streamId)&&ot({v:st,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=J.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),J.delete(x.streamId),N?.close();return}});let P=()=>{X&&I.log("[plane-link] disconnected from plane"),X=!1,An&&(clearInterval(An),An=null),_n&&(clearInterval(_n),_n=null),se.clear(),be={},m=[],b&&(clearTimeout(b),b=null),y.clear();for(let N of ae.values())N.close();ae.clear(),J.clear();for(let N of ka.values())N.abort();if(ka.clear(),he||tt)return;Ye==null&&(Ye=Date.now());let D=Date.now()-Ye<FL,x=Math.max(D?UL+Math.random()*HL:De,ie-Date.now());tt=setTimeout(()=>{tt=null,Mg()},x),tt.unref?.(),D||(De=Math.min(De*2,IE))};M.on("close",P),M.on("error",D=>{let x=/Unexpected server response: (\d+)/.exec(D?.message||"")?.[1];(x==="401"||x==="403")&&Date.now()-Cc>=OE&&(Cc=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",Cg),zI().then(Mg),{stop:()=>{he=!0,ct.off("event",Cg),tt&&clearTimeout(tt),rr&&clearTimeout(rr),An&&clearInterval(An),_n&&clearInterval(_n),b&&clearTimeout(b),ot({v:st,ch:"ctl",type:"bye",reason:"shutdown"}),M?.close()},status:()=>({connected:X,nodeId:n,cursor:{...W},inflight:se.size,...Rg()}),_tick:()=>{$g(),Md()}}}fl();var Vu=(()=>{try{return QL(import.meta.url)("../package.json").version||null}catch{return null}})(),eF=process.env.BOSTRAT_STATE_DIR||at.join(process.env.HOME||XL.tmpdir(),".bostrat"),DE=at.join(eF,"self-update"),zu=at.join(DE,"status.json"),tF=1440*6e4,nF=6e4,ic=new Set(["npm-global","git-checkout"]);function BE({kind:e=Lo(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:ic.has(e)?e==="git-checkout"||rF(t)?"auto":"prompt":"off"}function rF(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var Nt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function oF({kind:e,to:t,from:n=Vu,statusFile:r=zu,logFile:o=at.join(DE,"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||at.resolve(at.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!ic.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 ${Nt(g)} ${k}`,d=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${Nt(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
@@ -601,22 +601,22 @@ health() {
601
601
  # bostrat-node self-update one-shot \u2014 written by agent/src/self-update.js.
602
602
  # ${n??"?"} \u2192 ${t} (${e}). Status: ${r}
603
603
  set -u
604
- FROM=${Nt(n??"")}
605
- TO=${Nt(t)}
606
- STATUS_FILE=${Nt(r)}
604
+ FROM=${Bt(n??"")}
605
+ TO=${Bt(t)}
606
+ STATUS_FILE=${Bt(r)}
607
607
  STARTED_AT=${Number(u)}
608
608
  write_status() { # <status> [error]
609
609
  local err="\${2:-}"
610
610
  err="\${err//\\\\/\\\\\\\\}"; err="\${err//\\"/\\\\\\"}"
611
611
  printf '{"status":"%s","from":"%s","to":"%s","kind":"%s","startedAt":%s,"updatedAt":%s%s}\\n' \\
612
- "$1" "$FROM" "$TO" ${Nt(e)} "$STARTED_AT" "$(date +%s000)" \\
612
+ "$1" "$FROM" "$TO" ${Bt(e)} "$STARTED_AT" "$(date +%s000)" \\
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?at.join(a,"bin","npm"):"npm",k=a?`export PATH=${Nt(at.join(a,"bin"))}:"$PATH"
617
- `:"",S=a?` --prefix ${Nt(a)}`:"",A=R=>`${Nt(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 ! ${A("$TO")}; then
619
+ if ! ${S("$TO")}; then
620
620
  ${f("failed",'"npm install failed"')}
621
621
  exit 1
622
622
  fi
@@ -631,14 +631,14 @@ 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" ] && ${A("$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
638
638
  ${f("failed",'"agent did not answer after the update AND the rollback"')}
639
639
  exit 1
640
- `}let w=g=>`( cd ${Nt(l)} && git fetch -q origin main --tags && git show origin/main:scripts/deploy-pi.sh > "$TMP_SCRIPT" && bash "$TMP_SCRIPT" "v${g}" )`;return h+`
641
- LIVE=${Nt(l)}
640
+ `}let w=g=>`( cd ${Bt(l)} && git fetch -q origin main --tags && git show origin/main:scripts/deploy-pi.sh > "$TMP_SCRIPT" && bash "$TMP_SCRIPT" "v${g}" )`;return h+`
641
+ LIVE=${Bt(l)}
642
642
  TMP_SCRIPT="$(mktemp)"
643
643
  trap 'rm -f "$TMP_SCRIPT"' EXIT
644
644
  # "restarting" is written BEFORE deploy-pi.sh runs (it does fetch \u2192 build \u2192
@@ -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 cc(e=zu){try{return JSON.parse(await Hr.readFile(e,"utf8"))}catch{return null}}var sF=new Set(["updating","restarting","rolling-back"]),Yu=e=>!!(e&&sF.has(e.status));async function Ju({to:e,from:t=Vu,kind:n=Lo(),reason:r="manual",statusFile:o=zu,spawnImpl:s=ZL,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!ic.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!ac(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await cc(o);if(Yu(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(at.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?Of(await aF())||at.resolve(at.dirname(process.execPath),".."):null,f=oF({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),d=at.join(at.dirname(o),`update-${e}.sh`),p=at.join(at.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=PE.existsSync("/run/systemd/system")&&await iF("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",d]]:["setsid",["-f","bash","-c",`exec bash ${Nt(d)} >> ${Nt(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 aF(){try{return await Hr.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function iF(e){for(let t of String(process.env.PATH||"").split(at.delimiter))try{return await Hr.access(at.join(t,e),PE.constants.X_OK),!0}catch{}return!1}var cF=45*6e4;async function jE({statusFile:e=zu,current:t=Vu,now:n=Date.now,staleMs:r=cF}={}){let o=await cc(e);if(!o)return null;let s=a=>Hr.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Yu(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 LE({isBusy:e,start:t=Ju,onStuck:n=null,onStarted:r=null,tickMs:o=nF,stuckMs:s=tF,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=Vu,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}}}de();it();var lF=(...e)=>fetch(...e);function uF(e=process.env){return!!(_e(e)&&e.BOSTRAT_PLANE_TOKEN)}async function ww(e=process.env){if(!uF(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 lF(`${_e(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 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 Xu(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}})}de();it();var dF=(...e)=>fetch(...e);async function Zu(e,t,n,r=process.env){if(!(_e(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 dF(`${_e(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 fF(e,t=process.env){return Zu("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function FE({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await fF(t,o):await oa(e,o),a=await Zu("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 oa(e,t),r=await Zu("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function yw(e,t=process.env){return(await Zu("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function UE(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}}de();it();var pF=(...e)=>fetch(...e);async function mF(e,t,n,r=process.env){if(!(_e(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 pF(`${_e(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 HE=72,bw=160;async function WE(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>HE)throw new Error(`the title is the choice as a LABEL \u2014 ${HE} 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 qE(e,t=process.env){return mF("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}ch();de();import mc from"node:fs/promises";import id from"node:path";import oU from"node:os";cr();import hF from"node:fs/promises";import KE from"node:path";import wF from"node:os";var GE=()=>KE.join(process.env.BOSTRAT_STATE_DIR||KE.join(process.env.HOME||wF.tmpdir(),".bostrat"),"integrations.json");async function tr(){try{return JSON.parse(await hF.readFile(GE(),"utf8"))||{}}catch{return{}}}var Qu=["linked","prOpened","prMerged","create"],kw=["prompt","auto","off"],gF={create:["prompt","off"]},VE=e=>gF[e]??kw;function ed(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of Qu){let s=VE(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 tr(),t=process.env.BOSTRAT_LINEAR_API_KEY||e.linear?.apiKey,n=process.env.BOSTRAT_LINEAR_DEFAULT_TEAM||e.linear?.defaultTeam||null;return t?{apiKey:t,ticketFlow:ed(e),defaultTeam:n}:null}async function td(){let e=await tr(),t=e.jira||{},n=process.env.BOSTRAT_JIRA_BASE_URL||t.baseUrl,r=process.env.BOSTRAT_JIRA_EMAIL||t.email,o=process.env.BOSTRAT_JIRA_API_TOKEN||t.apiToken;return!n||!r||!o?null:{baseUrl:String(n).replace(/\/$/,""),email:r,apiToken:o,tokenExpiresAt:t.tokenExpiresAt??null,ticketFlow:ed(e)}}async function xw(){return ed(await tr())}async function zE(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${Qu.join(", ")}`);for(let[r,o]of t){if(!Qu.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${Qu.join(", ")}`);let s=VE(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 tr();return n.ticketFlow={...ed(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await vt(GE(),n,{mode:384}),n.ticketFlow}async function lc(){let e=(await tr()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function yF(){let e=(await tr()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var bF={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function nd(){let t=(await tr()).voiceChat||{},n=t.provider||"openai",r=bF[n];if(!r)return null;let o=n==="openai"?await yF():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function YE(){let e=(await tr()).cedar||{},t=process.env.BOSTRAT_CEDAR_INGEST_KEY||e.ingestKey,n=process.env.BOSTRAT_CEDAR_URL||e.url||"https://cedar-api.fly.dev";return t?{url:n,ingestKey:t}:null}async function Uo(){let e=(await tr()).slack||{},t=process.env.BOSTRAT_SLACK_BOT_TOKEN||e.botToken,n=process.env.BOSTRAT_SLACK_APP_TOKEN||e.appToken;return!t||!n?null:{botToken:t,appToken:n,channel:process.env.BOSTRAT_SLACK_CHANNEL||e.channel||null,maxConcurrent:Number.isInteger(e.maxConcurrent)&&e.maxConcurrent>0?e.maxConcurrent:2}}de();ur();vr();Ks();import dc from"node:fs/promises";import oA from"node:path";import qF from"node:os";import{randomUUID as sA}from"node:crypto";var Sw={};Pd(Sw,{createComment:()=>IF,findIssueUrl:()=>SF,issueStates:()=>OF,mdToAdf:()=>ZE,moveIssue:()=>CF,parseIssueRef:()=>vF,resolveIssue:()=>TF,uploadImage:()=>$F,upsertCard:()=>EF,whoami:()=>vw});var sa=e=>String(e.baseUrl||"").replace(/\/$/,""),XE=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:XE(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 kF=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,xF=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function vF(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(kF);return r?r[1].toUpperCase():null}let n=t.match(xF);return n?n[1]:null}function SF(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 TF(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 EF(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 AF=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function _F(e){let t=[],n=0;for(let r of e.matchAll(AF)){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 ZE(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(..._F(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 IF(e,t,n){let r=await Ho(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:ZE(n)});return r?.id?`${sa(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(sa(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function $F(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:XE(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 RF={new:"unstarted",indeterminate:"started",done:"completed"},JE=e=>RF[e?.key]??"started";async function OF(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:JE(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:JE(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function CF(e,t,n){await Ho(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var _w={};Pd(_w,{createComment:()=>FF,createIssue:()=>Aw,createProject:()=>Ew,findIssueUrl:()=>BF,issueStates:()=>HF,moveIssue:()=>WF,parseIssueRef:()=>DF,resolveIssue:()=>jF,teams:()=>aa,uploadImage:()=>UF,upsertCard:()=>LF,whoami:()=>Tw});var MF=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function Tn(e,t,n={}){let r=await fetch(MF(),{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 NF=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,PF=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function DF(e){let t=String(e||"").trim(),n=t.match(NF);if(n)return n[1].toUpperCase();let r=t.match(PF);return r?r[1]:null}function BF(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 jF(e,t){let r=(await Tn(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 LF(e,t,{url:n,title:r,subtitle:o}){let s=await Tn(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 FF(e,t,n){let r=await Tn(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 Tn(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 UF(e,{filename:t,contentType:n,buffer:r}){let o=await Tn(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 HF(e,t){let n=await Tn(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 WF(e,t,n){if(!(await Tn(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 Tn(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var QE=255;async function Ew(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>QE,a=s?`${o.slice(0,QE-1).trimEnd()}\u2026`:o,i=await Tn(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 Tn(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 aA={linear:{api:_w,config:Fo},jira:{api:Sw,config:td}};async function Nw(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(aA)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function Wo(e){let t=aA[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 iA=()=>process.env.BOSTRAT_STATE_DIR||oA.join(process.env.HOME||qF.tmpdir(),".bostrat"),Ow=()=>oA.join(iA(),"tickets.json"),cA=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),rd=e=>`${cA()}/track/${e}`,Wr=null,Iw=null,$w=Promise.resolve();async function pc(){return Wr||(Iw??=dc.readFile(Ow(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{if(Wr=e,!t&&Me()){let{records:n,source:r}=await nt("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 Cw().catch(()=>{})}}return Wr}).finally(()=>Iw=null),Iw)}async function Cw(){let e=JSON.stringify({tickets:Wr},null,2),t=`${Ow()}.${process.pid}.tmp`;await dc.mkdir(iA(),{recursive:!0}),await dc.writeFile(t,e),await dc.rename(t,Ow())}async function qr(e=null){if($w=$w.then(Cw,Cw),await $w.catch(()=>{}),!e)return;let t=Wr?.[e];t?ht("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):qt("tickets",e).catch(()=>{})}async function En(e){return(await pc())[e]??null}async function lA(){return{...await pc()}}async function uA(){return(await Nw()).length>0}async function ia(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 pc())[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 fc(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 uc(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await pA(e.id,c,"linked"),c}async function Dw(e){let t=await pc();return t[e]?(delete t[e],await qr(e),!0):!1}var Mw=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function dA(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 KF(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 GF(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 fc(e,t){let n=await Wo(t);if(!n)return;let r=await dA(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:rd(e),title:`Bostrat Track: ${t.track.name}`,subtitle:GF(t,r)})}function od(e){let t=new URL(cA());return`${t.protocol}//${e}.${t.host}/`}var VF={linked:"linked",opened:"prOpened",merged:"prMerged"};function zF(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 fA(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 pA(e,t,n){let r=await Wo(t);if(!r)return;let o=r.cfg.ticketFlow?.[VF[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Pw(s,a),c=zF(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 fA(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:sA(),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 mA(e){let t=await En(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 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 Bw(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await En(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 qr(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await fA(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function hA(e,t){let n=await En(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 wA(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 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 eA=50;async function gA(){let e=await Fo();if(!e)throw new Error("no ticketing integration configured");return aa(e)}function YF(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>eA)throw new Error(`too many issues (${n.length}); cap is ${eA} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function JF(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 En(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 yA(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=YF(t),o=await aa(n),s=await JF(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=sA();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 bA(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 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 En(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 uc(e,t){let n=await Wo(e);n&&await n.api.createComment(n.cfg,e,t)}async function XF(e,t,n){let r=await Wo(e);if(!r)return null;let o=await zn(t);if(!o)return null;let s=Zt(o,n);if(!s)return null;let a=await dc.readFile(Ft(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 tA=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),Rw=new Map;function ZF(e,t){if(tA()<=0)return fc(e,t);if(Rw.has(e))return;let n=setTimeout(()=>{Rw.delete(e),En(e).then(r=>r?fc(e,r):null).catch(()=>{})},tA());n.unref?.(),Rw.set(e,n)}var nA=new Map;async function rA(e,t,n){let r=nA.get(e)??0;Date.now()-r<600*1e3||(nA.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 QF(e,{resolveTrack:t=null}={}){let n=await En(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 ia(s,o,{source:"chat"})}catch(a){await rA(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 fc(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 fc(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await dA(n,e.trackId).catch(()=>null):null;await uc(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: ${KF(o)}.`:"")),await pA(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await XF(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await uc(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 uc(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 uc(n,`**Bostrat** \u2014 live preview **${r.name}**: ${od(r.slug)}
669
- _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await ZF(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await rA(e.trackId,s?.cwd??null,o)}}function kA({resolveTrack:e}){ct.on("event",t=>{QF(t,{resolveTrack:e}).catch(()=>{})})}async function xA(){if(!Me())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await nt("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await pc(),r=0;for(let[o,s]of Object.entries(n))await ht("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}bo();Ks();import eU from"ws";var vA=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function sd(e,t,n={}){let r=await fetch(`${vA()}/${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)=>sd("chat.postMessage",e,t),qo=(e,t)=>sd("chat.update",e,t);async function yt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function tU(e,t,n={}){let r=await fetch(`${vA()}/${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 SA(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await tU("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 sd("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var nU=2200;function TA({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 sd("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new eU(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()},nU);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||id.join(process.env.HOME||oU.tmpdir(),".bostrat"),Ww=()=>id.join(_A(),"slack.json"),ad=null,Lw=null,Fw=Promise.resolve();async function Kw(){return ad||(Lw??=mc.readFile(Ww(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>ad=e).finally(()=>Lw=null),Lw)}async function EA(){let e=JSON.stringify({threads:ad},null,2),t=`${Ww()}.${process.pid}.tmp`;await mc.mkdir(_A(),{recursive:!0}),await mc.writeFile(t,e),await mc.rename(t,Ww())}async function nn(){Fw=Fw.then(EA,EA),await Fw.catch(()=>{})}async function Gw(e){return(await Kw())[e]??null}async function sU(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 ke=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function hc(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function aU(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return hc(n.replace(/\n+/g," "),t)}function IA(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(hc(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:`<${rd(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:IA(t)})}async function Gr(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 AA=new Set;function Kr(e){AA.add(e),e.catch(()=>{}).finally(()=>AA.delete(e))}var Ce=e=>({response_type:"ephemeral",text:e}),iU="*/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._",cU=["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)=>Ce(`No live Track matches \u201C${ke(t)}\u201D. Live: ${e.map(n=>`\`${ke(n.name)}\``).join(" \xB7 ")||"none"}`);async function $A(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 yt(o,{...Ce(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await yt(o,{...Ce("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?id.basename(c.base):"fresh workspace"),lead:"claude"},u=await jw(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:IA(l),unfurl_links:!1});l.ts=u.ts,(await Kw())[i.id]=l,await nn(),await yt(o,{...Ce(`\u2713 *${ke(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await yt(o,{...Ce(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function lU(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 nn(),await qw(t,s).catch(()=>{})),await yt(r,{...Ce(`\u2713 *${ke(n.name)}* archived.`),replace_original:!0})}catch(s){await yt(r,{...Ce(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function uU(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await yt(o,{...Ce(`\u2713 Handing *${ke(n.name)}* to ${ke(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await yt(o,{...Ce(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function dU(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 yt(r,{...Ce(`\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 yt(r,{...Ce(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function fU(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:hc(`${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 pU(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?id.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 mU(e,t){let n=await Uo();if(!n)return Ce("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 Ce("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($A(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),Ce(`Starting *${ke(u)}* on ${ke(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:fU(u,i)}}case"archive":{if(!a.length)return Ce("Usage: `/bostrat archive <track>`");let{match:i,live:c}=Uw(await r.listTracks(),a.join(" "));return i?(Kr(lU(e,n,{track:i,responseUrl:t.response_url})),Ce(`Archiving *${ke(i.name)}*\u2026`)):Hw(c,a.join(" "))}case"handoff":{let i=r.knownAgents??cU,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return Ce(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:f}=Uw(await r.listTracks(),l);return u?(Kr(uU(e,n,{track:u,agent:c,responseUrl:t.response_url})),Ce(`Handing *${ke(u.name)}* to ${ke(c)}\u2026`)):Hw(f,l)}case"stop":{if(!a.length)return Ce("Usage: `/bostrat stop <track>`");let{match:i,live:c}=Uw(await r.listTracks(),a.join(" "));return i?(Kr(dU(e,n,{track:i,responseUrl:t.response_url})),Ce(`Stopping *${ke(i.name)}*\u2026`)):Hw(c,a.join(" "))}case"list":return Ce(await pU(r));default:return Ce(iU)}}async function hU(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 nn(),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 yt(n.response_url,Ce(`Couldn't answer: ${c?.message||c}`))}}async function wU(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 yt(n.response_url,Ce(`Couldn't act on the offer: ${c?.message||c}`))}}async function gU(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 yt(n.response_url,Ce(`Couldn't act on the offer: ${i?.message||i}`))}}async function yU(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 yt(t.response_url,{...Ce(`Starting *${ke(s)}*\u2026`),replace_original:!0}),Kr($A(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(hU(e,r,t,o)):n.action_id==="bostrat-ship"?Kr(wU(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&Kr(gU(e,r,t,o))}async function bU(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 sU(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 kU(e){return async t=>{if(t.type==="slash_commands")return mU(e,t.payload);if(t.type==="interactive"){await yU(e,t.payload);return}if(t.type==="events_api"){await bU(e,t.payload?.event);return}}}var xU=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 vU(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:hc(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 SU(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",vU(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await nn()}async function TU(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 nn(),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 EU(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(hc(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await nn()}async function AU(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await nn();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 _U(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 nn()}async function IU(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await nn();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 $U(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??RU)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await SA(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 RU(e,t){let n=await zn(e);if(!n)return null;let r=Zt(n,t);if(!r)return null;let o=await mc.readFile(Ft(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function OU(e,t){if(!xU.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 nn(),await qw(r,n);return;case"turn.agent":{if(!o.text)return;let s=aU(o.text);if(!s)return;await Gr(r,n,s,[{type:"section",text:{type:"mrkdwn",text:ke(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${rd(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return SU(r,n,t);case"prompt.answered":return TU(r,n,t);case"pr.offered":return EU(r,n,t);case"pr.offer.answered":return AU(r,n,t);case"pr.exists.offered":return _U(r,n,t);case"pr.exists.answered":return IU(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 nn(),await qw(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await Gr(r,n,`Live preview ${o.name}: ${od(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${ke(o.name)}*: ${od(o.slug)}
675
- _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return $U(r,n,t,e.deps)}}function RA(e){let t={deps:e};ct.on("event",s=>{OU(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await Uo()||(r&&clearInterval(r),r=null,n=TA({getToken:async()=>(await Uo())?.appToken,onEnvelope:kU(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}zt();de();cn();dm();Pn();import CU from"node:fs/promises";function MU(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 NU(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 PU=new Set(["Write","Edit","NotebookEdit"]),DU=220,BU=160;function jU(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(PU.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,DU)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=no(o.command.trim().replace(/\s+/g," ")).slice(0,BU));return r}function LU(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?Vt(t.cwd,t.sessionId):t?.cwd?gf(t.cwd):null}async function OA(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=au(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:jU(e,o)});break;case"Stop":await FU(r,o,e,i);break;default:break}return a}async function FU(e,t,n,r){let o=[],s=LU(n,t);if(s)try{o=MU(await CU.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=NU(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:dn(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();de();bl();hu();import{execFile as UU}from"node:child_process";import{promisify as HU}from"node:util";var WU=HU(UU),Vw=(e,t)=>WU("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4});function CA(e,t=Date.now()){return Vd(e,t)??0}function qU(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 MA(e,t,{now:n=Date.now()}={}){let r=CA(t,n),o=await F(e);return mu({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:qU(o,t.name,r)})}function KU(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=Nn(l.payload?.promptHead||l.payload?.text||"")?.category??null;break}}return{wallReason:a,fixerCategory:i}}async function GU(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 VU(e){try{let{stdout:t}=await Vw(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function NA(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 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=CA(t,i),l=await GU(r,n),u=await $(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:await VU(r),...l,ts:i}}),f=null,d=!1;try{let p=await hS(r,n,{fixKey:Us({trackId:e.id,boxId:t.name,epoch:c}),window:Dr,context:{...KU(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=wS(p);if(h>=mS){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 PA(e,t,n){if(!Ii.includes(n))throw new Error(`bad cause "${n}" (${Ii.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()}})}de();de();vr();de();vr();Pn();function wc(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 DA=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),BA=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},cd=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=DA(),f=0,d=[];for(let p of e||[]){let h=await F(p),w=xr(h,{boxLabels:wc(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);BA(u,w.totalTokens);for(let[g,k]of Object.entries(w.byModel))n[g]||={usd:0,events:0,tokens:DA()},n[g].usd=cd(n[g].usd+k.usd),n[g].events+=k.events,BA(n[g].tokens,k.tokens);for(let[g,k]of Object.entries(w.byProvider))r[g]||={usd:0,events:0},r[g].usd=cd(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:cd(o),asRecordedUsd:cd(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 jA(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
- `)}de();qp();import ZU from"node:fs/promises";import QU from"node:path";bl();vr();var ld=e=>e.payload?.ts??e.ts,zU=12e4,zr=e=>Math.round(e*1e4)/1e4,YU=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},byTrack:new Map});function JU(e,{since:t}){let{track:n,events:r,brief:o}=e,s=S=>ld(S)>=t,a=Nn([ni(n?.name),ni(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 A=Nn(S.payload.task);A&&i.set(S.boxId,A)}let c=new Map,l=S=>{let A=S||"unattributed";return c.has(A)||c.set(A,{segments:[u(null)],lastTs:null,provider:null}),c.get(A)},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,A)=>ld(S)-ld(A)),d=0,p=0,h=0,w={turns:0};for(let S of f){let A=l(S.boxId),R=A.segments[A.segments.length-1],B=ld(S);switch(A.lastTs!=null&&B>A.lastTs&&s(S)&&(R.activeMs+=Math.min(B-A.lastTs,zU)),A.lastTs=B,S.provider&&(A.provider=S.provider),S.type){case"turn.user":{let T=S.payload?.text;if(S.source==="hook"||!String(T||"").trim())break;let _=u(Nn(T));A.segments.push(_),s(S)&&(_.turns+=1);break}case"peer.message":{let T=S.payload?.text;if(!String(T||"").trim())break;let _=u(Nn(T));A.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}=Bt(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,A]of c)for(let R of A.segments){if(!(R.usd>0||R.activeMs>0||R.turns>0||R.toolCalls>0))continue;let T=R.textCat?.category??i.get(S)?.category??Hb(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||A.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 FA(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:A,merged:R,failed:B,sawCursorActivity:T,unpricedTurns:_}=JU(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:A,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[J,C]of Object.entries(U.models))O.models[J]=zr((O.models[J]||0)+C);for(let[J,C]of Object.entries(U.providers))O.providers[J]=zr((O.providers[J]||0)+C);o.has(I)||o.set(I,YU());let H=o.get(I);H.usd+=U.usd,H.activeMs+=U.activeMs,H.turns+=U.turns,H.toolCalls+=U.toolCalls;for(let[J,C]of Object.entries(U.models))H.models[J]=(H.models[J]||0)+C;for(let[J,C]of Object.entries(U.providers))H.providers[J]=(H.providers[J]||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=XU(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:LA(g.models),providers:LA(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 XU=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},LA=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 e4(e){let t=String(e||"7d");return t in la?{key:t,ms:la[t]}:{key:"7d",ms:la["7d"]}}function t4(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=Hl(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 n4(e){if(!e?.cwd)return null;try{let n=(await ZU.readFile(QU.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 UA(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}:e4(t),f=[];for(let d of e||[]){let p=await F(d),h=t4(d,p);i&&c<o&&(h=h.filter(w=>(w.ts??0)<=c)),f.push({track:d,events:h,brief:await n4(d)})}return{window:l,...FA(f,{windowMs:u,now:c})}}Pn();var Yr=36e5,KA=24*Yr,r4=400,o4=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 la?String(e||"7d"):"7d",i=la[a];return{key:a,since:i==null?null:r-i,until:r}}var s4=(e,t)=>e!=null&&t-e<=48*Yr?Yr:KA;function HA(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 a4(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 WA=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),qA=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},i4=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Ko(n)]));async function GA(e,t={}){let n=t.now??Date.now(),r=Yw({...t,now:n}),o=r.since==null?KA:s4(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=WA(),f=0,d=0,p=0,h=0,w=0,g=0,k=new Set,S=new Map,A=[],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+=Bt(C).usd)}if(!ae.length)continue;let J=xr(ae,{boxLabels:wc(I)});f+=J.totalUsd,d+=J.turns,p+=J.repricedTurns||0,h+=J.asRecordedUsd||0,w+=J.unpricedTurns||0;for(let C of J.unpricedModels||[])k.add(C);qA(u,J.totalTokens);for(let[C,Q]of Object.entries(J.byModel))c[C]||={usd:0,events:0,tokens:WA()},c[C].usd=Ko(c[C].usd+Q.usd),c[C].events+=Q.events,qA(c[C].tokens,Q.tokens);for(let[C,Q]of Object.entries(J.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}=Bt(C);if(!Q)continue;let ve=HA(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)}A.push({id:I.id,name:I.name||I.id,archived:!!I.archivedAt,usd:J.totalUsd,turns:J.turns,providers:Object.keys(J.byProvider)});for(let[C,Q]of Object.entries(J.byBox))R.push({trackId:I.id,trackName:I.name||I.id,boxId:C,...Q})}let _=r.since!=null?HA(r.since,o):T,O=[];for(let I=_,U=0;I!=null&&I<r.until&&U<r4;I=a4(I,o),U++){let H=S.get(I);O.push(H?{t:I,total:Ko(H.total),byProvider:i4(H.byProvider)}:{t:I,total:0,byProvider:{}})}return A.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:A.length,tracksSilentLive:B},prior:a!=null?{totalUsd:Ko(g),since:r.since-a,until:r.since}:null,tracks:A.slice(0,50),boxes:R.slice(0,o4)}}hu();var c4=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),l4=20,u4=40;async function VA(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 F(l),f=0,d=wc(l);for(let p of u){if(!c4.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=gS(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:Dr,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,l4),fixes:c.fixes.slice(0,u4)}}import d4 from"node:fs";import zA from"node:fs/promises";import gc from"node:os";import f4 from"node:path";Vm();lt();var p4=1024*1024,ud=e=>Math.round(e/p4);async function m4(e){try{let t=await zA.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:ud(r),diskTotalMb:ud(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function h4(){try{return(await Kt()).filter(t=>t.isBostrat).length}catch{return null}}async function w4(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await zA.readdir(f4.join(oc,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function YA({stateDir:e=oc,now:t=Date.now}={}){let n=gc.totalmem(),[r,o,s,a]=await Promise.all([vu().catch(()=>null),m4(d4.existsSync(e)?e:gc.tmpdir()),h4(),w4()]),i=gc.cpus()?.length||null,c=gc.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?ud(n-r):null,memTotalMb:ud(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(gc.uptime())}}de();Hf();Ra();Pn();de();Pn();var g4=864e5;function y4(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=dn(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 JA(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*g4,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=y4(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();Ll();it();Dn();import ua from"node:fs/promises";import b4 from"node:fs";import ft from"node:path";import k4 from"node:os";import{execFile as x4}from"node:child_process";import{promisify as v4}from"node:util";var S4=v4(x4),XA=process.env.BOSTRAT_STATE_DIR||ft.join(process.env.HOME||k4.tmpdir(),".bostrat"),dd=!1,Jw=null;async function Xw(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 T4=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 fd(e,t,{skip:n=null}={}){let r=0,o=await ua.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(T4.has(s.name)||n?.has(s.name))continue;let a=ft.join(e,s.name);s.isDirectory()?r+=await fd(a,ft.join(t,s.name)):s.isFile()&&(r+=await Xw(a,ft.join(t,s.name))?1:0)}return r}async function ZA({stateDir:e=XA,dest:t=process.env.BOSTRAT_SYNC_DIR||`${XA}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await ua.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 fd(ft.join(e,"events"),ft.join(t,"events")),o+=await fd(ft.join(e,"memory"),ft.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await fd(ft.join(u.cwd,".bostrat"),ft.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>S4("git",["-C",t,...u]);b4.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||dd))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,dd&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),dd=!1,Jw=null}catch(u){dd=!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();zt();io();lt();Sa();import{execFile as E4}from"node:child_process";import{promisify as A4}from"node:util";import{randomUUID as _4}from"node:crypto";import I4 from"node:fs";import $4 from"node:os";import R4 from"node:path";var Xr=A4(E4),pd=e=>new Promise(t=>setTimeout(t,e)),Zr=ff,Zw=process.env.BOSTRAT_USAGE_PROBE_CWD||R4.join($4.homedir(),".bostrat","usage-probe"),O4=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,C4=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,M4=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,QA=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,Jr=null,yc=null,bc=null;async function N4(){try{return await Xr(K,G("has-session","-t",Zr)),!0}catch{return!1}}function P4(){Jr&&clearTimeout(Jr),Jr=setTimeout(()=>D4().catch(()=>{}),O4),Jr.unref&&Jr.unref()}async function D4(){Jr&&(clearTimeout(Jr),Jr=null);try{await Xr(K,G("kill-session","-t",Zr))}catch{}}async function B4(){let e=Date.now()+M4;for(;;){let t=await Qw().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await pd(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await pd(500)}}async function j4(){if(await N4())return;if(!await fr())throw new Error("host tmux server not running \u2014 start globo-tmux.service");I4.mkdirSync(Zw,{recursive:!0}),await or(Zw);let e=_4();await Xr(K,G("new-session","-d","-s",Zr,"-c",Zw,"-x","200","-y","60",...La()));let t=`${df} --session-id ${e}`;await Xr(K,G("send-keys","-t",Zr,t,"Enter")),await B4()}async function Qw(){let{stdout:e}=await Xr(K,G("capture-pane","-t",Zr,"-p"));return e}async function L4(){await j4(),await Xr(K,G("send-keys","-t",Zr,"-l","/usage")),await Xr(K,G("send-keys","-t",Zr,"Enter"));let e=Date.now()+C4,t="";for(;await pd(400),t=await Qw(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await pd(900),t=await Qw(),await Xr(K,G("send-keys","-t",Zr,"Escape")).catch(()=>{}),P4(),t}function F4(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 U4(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 e_({fresh:e=!1}={}){return!e&&yc&&Date.now()-yc.at<QA?yc.data:bc||(bc=(async()=>{try{let t=await L4(),n=F4(t),r={...n,contributors:U4(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return yc={at:Date.now(),data:r},r}catch(t){let n={session:null,week:null,contributors:null,subscription:!1,error:t?.message||String(t),capturedAt:Date.now()};return yc={at:Date.now()-(QA-3e3),data:n},n}finally{bc=null}})(),bc)}var H4=262144;function W4(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 q4=new Set([300]),K4=new Set([10080]);function G4(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:q4.has(t)?"session":K4.has(t)?"week":"other"}function V4(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 z4(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?W4((o-n)/1e3):null,resetsAt:o}}var kc=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function Y4(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 kc(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=kc(r);[c.primary,c.secondary].forEach((p,h)=>{let w=z4(p,l,t);if(!w)return;let g=G4(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:V4(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{...kc(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return kc(r)}return kc(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 St(n.file,H4),o=Y4(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 t_(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 md({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 md({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function md(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 e_({fresh:t})}}ar();it();it();function J4(e=process.env){return!!(_e(e)&&e.BOSTRAT_PLANE_TOKEN)}var X4=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),hd=(e,t)=>Object.assign(new Error(e),{status:t});async function n_(e,t){if(!J4(t))throw hd("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${_e(t)}${e}`,{headers:X4(t)})}catch(o){throw hd(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw hd(r?.error||`plane replied ${n.status}`,n.status);return r}async function r_(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await n_(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function o_(e,{env:t=process.env}={}){if(!e)throw hd("message id required",400);return(await n_(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}wi();Ql();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 Z4(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 s_(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(Z4).filter(Boolean)}function Q4(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function a_(e){let t=s_(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:Q4,allowed(r){if(n)return!0;let o=tg((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function i_(e,t){let n=s_(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 c_ from"node:crypto";import wd from"node:fs";import e2 from"node:path";function l_(e=process.env,{stateDir:t=oc,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=e2.join(t,"api-token");try{let a=wd.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=c_.randomBytes(32).toString("base64url");try{wd.mkdirSync(t,{recursive:!0}),wd.writeFileSync(o,s+`
682
- `,{mode:384}),wd.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function xc(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 u_(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:c_.timingSafeEqual(n,r)}function d_(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 t2=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/],n2=e=>t2.some(t=>t.test(e));function f_({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=d_(o);return u_(c,e)?a():n2(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||xc(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 p_(e,t,{enforce:n=!0}={}){return!n||u_(d_(e),t)?!0:xc(e)}cn();ku();ku();import r2 from"node:http";import o2 from"node:net";function gd(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 yd(e){let t=gd(e.headers.host);return t?{slug:t,view:Hm(t)}:null}var s2=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),a2=e=>{let t=s2(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 m_(e,t,n){let r=yd(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(a2(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=r2.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 h_(e,t,n){let r=yd(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=o2.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 w_(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}.${i2(n.host)}/`}function i2(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 gd(t)&&Hm(n[0])?n.slice(1).join("."):t}Ks();th();_u();mm();de();import g_ from"node:os";import{randomUUID as rg}from"node:crypto";var c2=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||g_.hostname(),nodeName:e.BOSTRAT_NODE_NAME||g_.hostname()});var y_=32768,b_=120,k_=1e3,x_=new Set(["claude","codex","cursor"]),l2=new Set(["off","transition","nag"]),u2=[[0,59],[0,23],[1,31],[1,12],[0,6]];function d2(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=u2[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 rn=e=>String(e??"").trim(),Go={name(e){let t=rn(e);if(!t)throw new Error("a loop needs a name");if(t.length>b_)throw new Error(`name is too long (${t.length}); cap is ${b_}`);return t},schedule(e){let t=rn(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!d2(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=rn(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>y_)throw new Error(`prompt is too long (${t.length} chars); cap is ${y_}`);return t},expectation(e){let t=rn(e)||null;if(t&&t.length>k_)throw new Error(`expectation is too long (${t.length}); cap is ${k_}`);return t},notify(e){let t=rn(e)||"off";if(!l2.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=rn(typeof t=="string"?t:t?.provider)||"claude";if(!x_.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...x_].join(", ")}`);let r=typeof t=="object"&&t&&rn(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 f2(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=rn(t?.workspace?.repo)||rn(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}=c2();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:f||null}}async function S_(e,t){let n=f2(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 T_(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 ng=["name","schedule","prompt","expectation","notify","assignment","enabled"],p2=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function E_(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 A_(e,t){let n=rn(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 m2(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"?p2(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 __(e,t,n){let r=E_(t),{patch:o,changed:s}=m2(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 v_=600;async function I_(e,t,n){let r=rn(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>v_)throw new Error(`reason is too long (${r.length}); cap is ${v_}`);let o=E_(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 $_=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 R_(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 $_(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 O_(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 $_(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}}lu();de();ur();de();Ln();_u();var C_=10,M_=200,h2=120,w2=24,P_=/^\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 g2=(e=Date.now())=>new Date(e).toISOString().slice(0,10),pt=(e,t="i")=>new RegExp(e,t),y2=[{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"}],b2=[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 k2({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of y2)if(o.test(n)||o.test(r))return s;return null}function N_(e){let t=String(e||"");for(let n of b2){let r=n.exec(t);if(r)return r[0].trim()}return null}function D_(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 x2=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function v2(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Bi(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,h2)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${w2}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=x2.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=N_(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>M_)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${M_}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=N_(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>C_)throw new Error(`${r.length} bullets \u2014 over the ${C_}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function S2(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:k2({title:r.title,headRef:r.headRef})}))}async function B_(e,t){let n=await S2(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function j_(e,{md:t,day:n=null}){let r=v2(t),o=n==null||n===""?g2():String(n);if(!P_.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 L_(e,{day:t}){let n=String(t||"");if(!P_.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();Ln();Eo();de();Bs();it();Nr();Ln();wi();Ql();vi();Dn();import{execFile as T2}from"node:child_process";import{promisify as E2}from"node:util";var ag=E2(T2),F_=3e4,A2=30*6e4,_2=F_,I2=10*6e4,$2=10080*6e4,R2=60*6e4,O2=8,C2=1440*6e4,M2=3,U_="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",sg=60*6e4,N2=15*6e4,P2=9e4,D2=1440*6e4,bd=new Map,kd=new Map,B2=/could not resolve|not found|no pull requests?/i,j2=e=>B2.test(String(e?.message||e||""));function L2(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<sg)}var H_={fast:_2,slow:I2,decay:R2};function W_(e,t){return e.armedAt&&t-e.armedAt<A2||L2(e,t)||q_(e,t,{grace:0})?"fast":t-(e.firstSeen||0)>$2?"decay":"slow"}function F2(e,t){return H_[W_(e,t)]}function Sc(e,t,n,r){let o=e.lanes?.get(oe(t.repo,t.number))||{};return Zl({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function U2(e,t){Un("watch");try{let{stdout:n}=await ag("gh",["pr","view",String(t),"--repo",e,"--json",U_],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await sn({slug:e})}});return JSON.parse(n||"null")}catch(n){throw Rr(n)&&Or(n),n}}async function H2(e){Un("watch");try{let{stdout:t}=await ag("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",U_],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await sn({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 W2(){let e=new Map;for(let t of await ce().catch(()=>[]))e.set(t.id,t);return e}async function q2(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 K2(e,t){let n=await So(e);return n?Ps(n,t):null}async function G2(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 V2(e,t){let n=await So(e);if(!n)throw new Error(`no local checkout for ${e}`);return bi(n,t)}async function z2(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 Y2=10*6e4;async function J2(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>C2){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<Y2)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 K_(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 X2(e,t){try{return await ag("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function vc(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 q_(e,t,{grace:n=P2}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=D2}async function Z2(e,t,n,r){let o=r.now??Date.now();if(!q_(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||Ge(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??jn)(e.repo,e.number).catch(()=>null),!1):await(r.claim??jn)(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 Q2(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 ql(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await Gl(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<N2;await Mx(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await Cx(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await vc(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)>sg)await Kl(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 Kl(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=Sc(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await vc(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 Kl(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>sg)await Vl(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await Vl(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Sc(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await vc(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 Vl(e.repo,e.number).catch(()=>{})}}}}async function eH(e,t,n,r){let o=Sc(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await vc(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 tH(e,t,n){Sc(n,e,"lost",null);let r=t.get(e.trackId);r&&!await vc(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 K_(e,t,n,r,o={}){let s=Sc(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 nH(e={}){let{now:t=Date.now(),auth:n=Qp,view:r=U2,list:o=H2,links:s=Bx,trackMap:a=W2,emitMerged:i=q2,mark:c=Ir,archiveIfArmed:l=Wn,notifyIfArmed:u=qn,notifyIfResolved:f=ju,followupsIfMerged:d=Bo,batchThreshold:p=M2,detail:h=K2,merge:w=G2,updateBranch:g=V2,lookup:k=rt,disarm:S=hi,emitDisarmed:A=z2,localHasCommit:R=X2,claim:B=jn,midTurn:T=To}=e;if(!(await n().catch(()=>null))?.authenticated||Jl()>0)return 0;let O=await s().catch(()=>[]),I=iv(O),U=O.filter(W=>t-(bd.get(oe(W.repo,W.number))||0)>=F2(W,t));if(!U.length)return 0;let H=Date.now(),ae=new Map,J=new Map;for(let W of[...U].sort(ki)){let be=W_(W,t);ae.set(oe(W.repo,W.number),{lane:be,intervalMs:H_[be]}),bd.set(oe(W.repo,W.number),t),J.has(W.repo)||J.set(W.repo,[]),J.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:A,localHasCommit:R,claim:B,midTurn:T};for(let[W,be]of J){let se,ue=new Set;if(be.length>p)se=await o(W).catch(()=>null);else{se=new Map;for(let me of be)try{let j=await r(W,me.number);j?.number!=null&&se.set(Number(j.number),j)}catch(j){j2(j)&&ue.add(oe(me.repo,me.number))}}if(se)for(let me of be){let j=oe(me.repo,me.number),ie=se.get(Number(me.number));if(!ie){if(ue.has(j)){let le=(kd.get(j)||0)+1;kd.set(j,le),le>=O2&&(await tH(me,C,Q),kd.delete(j),bd.delete(j))}continue}if(kd.delete(j),ie.state==="MERGED"||ie.state==="CLOSED")ie.state==="MERGED"?await K_(me,ie,C,Q):await eH(me,ie,C,Q),bd.delete(j);else{await Z2(me,ie,C,Q).catch(()=>{}),await Q2(me,ie,C,Q).catch(()=>{});let le=!me.trackId||I.get(me.trackId)===j;me.autoMerge&&le&&await J2(me,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 G_(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{await nH()}catch{}finally{e=!1}}},F_)}de();Ln();ar();Nr();Dn();function V_(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function rH(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var oH=new Set(["merged","closed","lost"]);function sH(e,t){if(!e?.blocked)return null;let n=V_(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 aH(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function iH(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 cH(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 z_(e,t={}){let{now:n=Date.now(),slugOf:r=Se,lookup:o=rt,note:s=Nx,tracks:a=async()=>(await ce()).filter(f=>!Ge(f)),asked:i=iH,emitChange:c=cH}=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(!rH(p))continue;let h=await o(d,p.number).catch(()=>null);if(!h?.trackId||oH.has(h.state))continue;let{prev:w}=await s(d,p.number,{blocked:V_(p),sha:p.headSha??null,at:n});if(!w)continue;let g=sH(w,p);if(!g||aH(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 A={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"?A.passed=p.checks.passed:A.base=p.baseRefName||null,await c(k,g.change,A),l.push({change:g.change,number:p.number,reason:g.reason})}catch{}}return l}lt();de();Nr();Dn();import{randomUUID as lH}from"node:crypto";var uH=2e4,Y_=3,ma=new Map,ig=new Set;async function J_(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 dH(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 Kt(),i=n??await ce()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(Ge(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===Y_&&(ig.add(f.name),await J_(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:lH(),box:f.name,agent:f.agent}}).catch(()=>{}))}else{let p=(ma.get(f.name)||0)>=Y_;if(ma.delete(f.name),p||!ig.has(f.name)){ig.add(f.name);let h=await J_(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 Tc=null,cg=!1;function X_(){return Tc?()=>{}:(Tc=setInterval(()=>{cg||(cg=!0,dH().catch(()=>{}).finally(()=>{cg=!1}))},uH),Tc.unref?.(),()=>{clearInterval(Tc),Tc=null})}bo();Km();de();Bs();Eo();bo();import{randomUUID as fH}from"node:crypto";async function pH(){let e=await Promise.resolve().then(()=>(Nr(),SE));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var lg={listRepoPrs:fn,readEvents:F,appendEvent:$,sayDeps:pH,currentBranch:Cr};async function mH(e,t=lg,{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 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 mH(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=fH();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=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,vx(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 nr from"node:fs/promises";import ha from"node:path";import oI from"node:os";import Z_ from"node:fs/promises";import xd from"node:path";import{execFile as hH}from"node:child_process";import{promisify as wH}from"node:util";import{fileURLToPath as gH}from"node:url";var yH=wH(hH),eI=xd.dirname(gH(import.meta.url)),bH=xd.resolve(eI,"..","..","client","dist"),kH="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",xH=new Map([...kH].map((e,t)=>[e,t]));function vH(e){let t=[],n=0,r=0;for(let o of e){let s=xH.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 SH(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=vH(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 TH(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 Q_=new Map;async function EH(e){let t;try{t=await Z_.stat(e)}catch{return null}let n=Q_.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await Z_.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:SH(r.mappings||"")};return Q_.set(e,o),o}catch{return null}}var fg=null;function AH(){return fg||(fg=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):yH("git",["rev-parse","--short","HEAD"],{cwd:xd.resolve(eI,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),fg}var _H=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function IH(e,{distDir:t=bH}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(_H)){let[a,i,c,l]=s,u=await EH(xd.join(t,"assets",`${i}.map`)),f=u?TH(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 tI(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await AH();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await IH(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var $H=()=>process.env.BOSTRAT_STATE_DIR||ha.join(process.env.HOME||oI.tmpdir(),".bostrat"),Qr=()=>ha.join($H(),"telemetry"),sI=()=>ha.join(Qr(),".relay-offsets.json"),RH=50,OH=14,CH=3e4,nI=500,Pt=(e,t)=>typeof e=="string"?e.slice(0,t):"";function MH(e,t){if(!e||typeof e!="object")return null;let n=Pt(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:Pt(e.anonId,64),sessionId:Pt(e.sessionId,64),userId:Pt(e.userId,64),release:Pt(e.release,64),appVersion:Pt(e.appVersion,32),route:Pt(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:Pt(e.error.kind,256),message:Pt(e.error.message,8192),stack:Pt(e.error.stack,32768),fingerprint:Pt(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:Pt(s?.n,64),r:Pt(s?.r,128)}))),o}var aI=e=>new Date(e).toISOString().slice(0,10),rI=0;async function iI(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,RH):[]).map(s=>MH(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await tI(s);await nr.mkdir(Qr(),{recursive:!0});let o=ha.join(Qr(),`${aI(t)}.ndjson`);return await nr.appendFile(o,r.map(s=>JSON.stringify(s)+`
695
- `).join(""),"utf8"),t-rI>6*3600*1e3&&(rI=t,NH(t).catch(()=>{})),r.length}async function NH(e=Date.now()){let t=aI(e-OH*24*3600*1e3),n=[];try{n=await nr.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 nr.rm(ha.join(Qr(),s),{force:!0});let o=await lI();for(let s of r)delete o[s];await uI(o)}var vd=new Map;function cI(e,t=Date.now()){let n=e||"unknown",r=vd.get(n);return r||(vd.size>512&&vd.clear(),r={tokens:40,at:t},vd.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 lI(){try{return JSON.parse(await nr.readFile(sI(),"utf8"))||{}}catch{return{}}}async function uI(e){await nr.mkdir(Qr(),{recursive:!0}),await nr.writeFile(sI(),JSON.stringify(e),"utf8")}function PH(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||oI.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 DH({fetchImpl:e=fetch}={}){let t=await YE();if(!t)return{sent:0,disabled:!0};let n;try{n=(await nr.readdir(Qr())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await lI(),o=0;for(let s of n){let a=ha.join(Qr(),s),i=r[s]||0,c;try{let d=await nr.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+=nI){let p=f.slice(d,d+nI).map(w=>PH(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 uI(r)}return{sent:o,disabled:!1}}var pg=null,mg=!1;function dI(){pg||(pg=setInterval(async()=>{if(!mg){mg=!0;try{await DH()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{mg=!1}}},CH),pg.unref?.())}import Td from"node:fs/promises";import wI from"node:path";import BH from"node:os";var gI=()=>process.env.BOSTRAT_STATE_DIR||wI.join(process.env.HOME||BH.tmpdir(),".bostrat"),yI=()=>wI.join(gI(),"dictation-glossary.json"),jH=100,LH=500,FH=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Ed=null,hg=null,wg=Promise.resolve();function fI(){let e={},t=Date.now();for(let n of FH)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function bI(){return Ed||(hg??=Td.readFile(yI(),"utf8").then(e=>JSON.parse(e)?.terms??fI()).catch(()=>fI()).then(e=>Ed=e).finally(()=>hg=null),hg)}async function pI(){let e=JSON.stringify({terms:Ed},null,2),t=yI(),n=`${t}.${process.pid}.tmp`;await Td.mkdir(gI(),{recursive:!0}),await Td.writeFile(n,e),await Td.rename(n,t)}function UH(){return wg=wg.then(pI,pI),wg.catch(()=>{})}async function gg(){return Object.values(await bI()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var HH=e=>Math.max(1,Math.ceil(e.length/4));async function WH(){let e=[],t=0;for(let{term:n}of await gg()){let r=HH(n);if(!(t+r>LH)&&(e.push(n),t+=r,e.length>=jH))break}return e}async function qH(e,t){let n=await bI(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var mI=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),Sd=e=>e.toLowerCase();function hI(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function kI(e,t){let n=mI(e),r=mI(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]=Sd(n[u])===Sd(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;)Sd(n[c])===Sd(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(hI(r[l])&&i.add(r[l]),l++);for(;l<s;l++)hI(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await qH(u,"learned");return await UH(),[...i]}var Ec=null;function KH(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 xI(){if(!Ec)return null;let e=await lc();if(!e||e.apiKey.slice(-6)!==Ec.keyTail)return null;let{keyTail:t,...n}=Ec;return n}async function vI(e,t){let n=await lc();if(!n){let i=new Error("Deepgram is not configured \u2014 add deepgram.apiKey to ~/.bostrat/integrations.json");throw i.status=503,i.code="not_configured",i}let r=new URL("https://api.deepgram.com/v1/listen");r.searchParams.set("model","nova-3"),r.searchParams.set("smart_format","true");for(let i of await WH())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=KH(o.status,i);c.persistent&&(Ec={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 Ec=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}de();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 GH(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 VH(e,t={}){let n=yg[GH(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 zH(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 Ac=null;async function YH(){if(!Ac)return null;let e=await nd();if(!e||e.apiKey.slice(-6)!==Ac.keyTail)return null;let{keyTail:t,...n}=Ac;return n}async function JH(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=zH(t.status,o);s.persistent&&(Ac={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}Ac=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 XH={openai:JH};async function SI(){let e=await nd();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await YH()}:{configured:!1}}async function TI(){let e=await nd();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 XH[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function EI(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=VH(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}}Dn();var CI=xe.dirname(QH(import.meta.url)),AI=Number(process.env.PORT)||3362,_d=pw(process.env),MI=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,wa=a_(process.env.BOSTRAT_ALLOW_IPS),Sg=i_(process.env.BOSTRAT_VIEW_FRONT_CIDRS,yd),NI=l_(),PI=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",v=Wt();v.disable("x-powered-by");v.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),gd(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(xc(e)||wa.allowed(wa.clientIp(e))||Sg.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});v.use(m_);v.use(f_({token:NI,enforce:PI}));v.use("/api/mocks",Wt.json({limit:"1mb"}));v.use("/api/mocks",Wt.raw({type:"image/png",limit:"24mb"}));v.use("/api/mocks",Wt.raw({type:["video/mp4","video/webm"],limit:"105mb"}));v.use("/api/runbooks",Wt.json({limit:"1mb"}));v.use("/api/tracks/adopt",Wt.json({limit:"1mb"}));v.use("/api/telemetry",Wt.json({limit:"256kb"}));v.use("/api/hook",Wt.json({limit:"2mb"}));v.use("/api/dictation",Wt.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));v.use("/api/tracks/:id/upload",Wt.raw({type:()=>!0,limit:"25mb"}));v.use(Wt.json({limit:"64kb"}));v.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:At,hostTmuxAlive:await fr(),autoTriggerPct:MI,plane:ga?ga.status():null})});v.get("/api/sessions",async(e,t)=>{t.json({sessions:await Kt()})});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(!Ne(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 Gt(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(!Ne(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 qa(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(!Ne(n))return t.status(400).json({error:"invalid session name"});try{let r=await jk(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=_l(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 _I=10;v.get("/api/idle-guard",async(e,t)=>{try{t.json(fw({tracks:await ce(),views:await bu(),queuedOf:n=>Mo(n)}))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var Ht=Lo(),oW=BE({kind:Ht}),_c=null,bt=()=>_c&&["auto","prompt","off"].includes(_c)?_c:oW,vg=null,sW=ic.has(Ht),DI=async({to:e,from:t})=>!sW||Yu(await cc())?!1:(Ic.arm({to:e,from:t,kind:Ht}),!0);async function aW(e){let t=bt();_c=e??null;let n=bt();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){Ic.cancel();return}vg&&await DI(vg)}}var BI=(()=>{try{return rW(import.meta.url)("../package.json").version||null}catch{return null}})(),Ic=LE({isBusy:async()=>fw({tracks:await ce(),views:await bu(),queuedOf:e=>Mo(e)}).busy,onStuck:({to:e,from:t})=>Sn({current:t,latest:e,installKind:Ht,policy:bt(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?Sn({current:t,latest:e,installKind:Ht,policy:bt(),status:"updating",reason:"auto"}):Sn({current:t,latest:e,installKind:Ht,policy:bt(),status:"failed",error:n?.reason})).catch(()=>{})});v.get("/api/node/self-update",async(e,t)=>{t.json({installKind:Ht,policy:bt(),policySource:_c?"plane":"node",current:BI,status:await cc(),armed:Ic.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 Ju({to:n,kind:Ht,reason:"manual"});if(r.ok)return Ic.cancel(),Sn({current:r.from,latest:n,installKind:Ht,policy:bt(),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 jI(){try{let e=await jE();e&&await Sn({current:e.from,latest:e.to,installKind:e.kind||Ht,policy:bt(),status:e.status,error:e.error,reason:e.reason}),await Oh({current:BI,installKind:Ht,policy:bt()})}catch{}}jI();setInterval(jI,3e4).unref();v.get("/api/tracks",async(e,t)=>{let n=(await ce()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>_I){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,_I).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:Ji,agentAvailability:await Cu(),tickets:await lA()})});v.get("/api/cost",async(e,t)=>{try{let n=await ce();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(jA(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 UA(await ce(),{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 GA(await ce(),{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=di(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/usage/caps",(e,t)=>{t.json(di())});v.post("/api/usage/caps",async(e,t)=>{try{t.json(await jl(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 t_(await ce(),{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($n),{byToken:Zi,legacy:()=>_i(e.body?.session_id,e.body?.cwd)});if(n==="refused")return va("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return va("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&&va("mismatch",{track:r.track.id,box:r.box.name}),va(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 OA(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&Vc(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 Zi(e.get($n));if(!n?.track||!n?.box)return t.status(204).end();t.send((await MA(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 Zi(e.get($n));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;NA(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 PA(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 VA(await ce(),{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(!cI(wa.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await iI(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 Rn(),r=new Set((await Promise.all(n.map(a=>Se(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await Aa()).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 jc(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:Bc(),calls:Vx(),latency:Xx()})});v.post("/api/github/refresh",(e,t)=>{Vg(),t.json({ok:!0})});v.get("/api/gmail/search",async(e,t)=>{try{let n=await r_(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 o_(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 Id({repo:e=null,number:t=null,branch:n=null}){let r=e?await Se(e):null;if(r&&t!=null){let s=await rt(r,t),a=s&&await te(s.trackId);if(a)return a}if(!n)return null;let o=await ce();return su(o,n,s=>Tg(s,e,r))}async function LI({repo:e=null,number:t=null,branch:n=null}){let r=await Id({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!Ge(r))return r;if(!n)return null;let o=e?await Se(e).catch(()=>null):null,s=await ce();return su(s,n,a=>!Ge(a)&&Tg(a,e,o))}async function on(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await Id({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 iW(e){let t=(await ce()).filter(n=>!Ge(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 rt(r,o.number))continue;let s=await su(t,o.headRefName,a=>Tg(a,n.path,r));s&&await It({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 ov();await iW(n.repos).catch(()=>{}),await z_(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(!yi.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 Hn(n)).path);if(!k)throw new Error("repo has no GitHub remote");let S=await Id({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 bi(n,g),await It({repo:k,number:g,trackId:S.id,url:f,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await pi(k,g,{merge:{method:w}}))throw new Error("couldn't record the auto-merge arm");return await ko(k,g,i===!0),await mi(k,g,c===!0&&i!==!0),mn(),await on("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 on("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 mi(p,d.number,!0).catch(()=>{}),await qn(p,d.number).catch(()=>{}),await Bo(p,d.number).catch(()=>{}),h=await Wn(p,d.number).catch(()=>!1),await Ir(p,d.number,"merged").catch(()=>{})),i===!0&&!h){let w=await Id({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 Hn(n)).path).catch(()=>null),l=c?await hi(c,i).catch(()=>null):null;try{await nm(n,i)}catch(u){if(!l)throw u}mn(),await on("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 lv(n,{method:r||"merge",onMerged:a=>{on("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&qn(o,a.number).catch(()=>{}).then(()=>Bo(o,a.number)).catch(()=>{}).then(()=>Wn(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:cv()})});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(!yi.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(ki);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 mi(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:sv(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 av(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 on("merged",{number:p.number,url:w.url,title:w.title,branch:w.headRefName,repo:h,track:c}),await qn(p.repo,p.number).catch(()=>{}),await Bo(p.repo,p.number).catch(()=>{}),await Wn(p.repo,p.number).catch(()=>{}),await Ir(p.repo,p.number,"merged").catch(()=>{}),d.action="merged";else{if(g.action==="update-arm"&&(await bi(h,p.number).catch(()=>{}),d.action="updated-armed"),!await pi(p.repo,p.number,{merge:{method:i}}))throw new Error("couldn't record the auto-merge arm");await on("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(mn(),!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 mi(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 hi(a.repo,a.number).catch(()=>null),c=await So(a.repo).catch(()=>null);c&&await nm(c,a.number).catch(()=>{}),i&&(await on("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}))}mn(),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=Mt(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 om(w.dir,{title:r,body:o,base:s}),k=w.repo||await Se(w.dir).catch(()=>null);k&&g.number&&await It({repo:k,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await on("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 om(i.cwd,{title:r,body:o,base:s}),l=await Se(i.cwd).catch(()=>null);l&&c.number&&await It({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await on("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=Mt(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 Ps(n,r),s=await Se(n).catch(()=>null),a=await LI({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=Mt(a.workspace).find(k=>k.base===n||s&&k.repo===s)??null,c=a.workspace?.kind==="multi",l=await uv(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 Ct(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 It({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await $x(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await on("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 LI({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=Mt(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 Ct(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 It({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await Rx(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await on("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 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 Ct(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&&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 te(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 $c=e=>t=>({...t,url:w_(t,e.headers)});v.get("/api/views",async(e,t)=>{try{let n=await bu({trackId:e.query.track||void 0});t.json({views:n.map($c(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 RS(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:$c(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 ce()).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 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:$c(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:$c(e)(await OS(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:$c(e)(await CS(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 MS(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var cW=[["linear",Fo,Tw],["jira",td,vw]],bg=new Map;v.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await xw(),r={};for(let[o,s,a]of cW){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 zE(o),i=n?await te(n):null;!i&&r&&(i=(await ce()).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 ce()).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 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 oa(o);await Xu(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 Xu(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var FI=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 FI(o,n,r),l=await FE({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 FI(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 WE(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 qE(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 UE(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 ce()).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 ce()).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 uA(),ticket:await En(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 En(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 Dw(e.params.id)})});var $d=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 mA(e.params.id))}catch(n){let r=n?.message||String(n);t.status($d(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($d(r)).json({error:r})}});v.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await hA(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status($d(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 wA(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status($d(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 te(n):null;if(!s&&r&&(s=(await ce()).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 yA(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 gA()})}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 bA(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 Di({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 zn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var Rc={dotfiles:"allow"};v.get("/api/mocks/:id/png",async(e,t)=>{let n=await zn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Zt(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Ni(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,Rc,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});v.get("/api/mocks/:id/media",async(e,t)=>{let n=await zn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Zt(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Ni(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,Rc,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});v.get("/api/mocks/:id/html",async(e,t)=>{let n=await zn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Zt(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(Ft(n,r.v).html,Rc,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&&Su(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 ce()).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 JS({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&&Su(n)?n:null;try{let o=await XS(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 eT(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await Ct(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 yT(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await tT(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 pT({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 mT(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 ce()).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 hT({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 wT(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 gT(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 ce(),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 AT({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=TT(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(Zn(n,r.v),Rc,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});v.get("/api/loops",async(e,t)=>{t.json(await Si())});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 ce()).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 Si();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 te(n):null;if(!s&&r&&(s=(await ce()).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 S_(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var Eg=async(e,t)=>{let n=e?await te(e):null;return!n&&t&&(n=(await ce()).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 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 Hv(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 qv(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 Yv(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 Gv(a,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null},{sayToLead:Ct,unarchiveTrack:Lu})})}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 Wv(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 Kv(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 Ei(s,n,o),t==="opened"||t==="pushed")){let a=zv(await F(s).catch(()=>[]));a&&await Ei(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var UI=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await te(n):null;if(!s&&r&&(s=(await ce()).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 Si();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_(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 UI(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?.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 UI(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?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});var HI=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 R_(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(HI(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 O_(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(HI(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 T_(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 ce()).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 IT({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 $T(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 RT(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 OT(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=D_(e.query.since||null);t.json({since:n,repos:og(),...await B_(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var WI=async({trackId:e,cwd:t})=>{let n=e?await te(e):null;return!n&&t&&(n=(await ce()).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 WI({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 j_(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 WI({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 L_(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var lW=120,kg=400,ga=null,II=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=Bi(`${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 ce()).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,lW):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: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 vI(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 lc(),terms:await gg(),problem:await xI()})});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 kI(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 SI())});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 TI())}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 EI(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 Bu({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 Xu(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:qI(ra(e.params.id)),subtasks:jo(e.params.id).map(Oc),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 Lu(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 Mu(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=ry(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=ri(await F(n)),a=kl(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 uW=["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 Ct(e.params.id,uW)})}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 Fu(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 Ct(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 BT(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||!ah(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=sh(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 dW=/^[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(!dW.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=Vt(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=ZH.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 Du(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 Nu(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 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 md(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:Oc(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(Oc)})});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:Oc(qu(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:Oc(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 Oc(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 Uu(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(qI(ra(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 Hu(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 qI(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:Qc(),paths:Dy,trace:await Py({limit:n})})});var xg=xe.resolve(CI,"..","..","client","dist");mt.existsSync(xg)&&(v.use(Wt.static(xg)),v.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(xe.join(xg,"index.html"),Rc)));var KI=eW.createServer(v),fW=new nW({noServer:!0}),GI=(e,t,n)=>{if(!(xc(e)||wa.allowed(wa.clientIp(e))||Sg.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(h_(e,t,n))return;if(!p_(e,NI,{enforce:PI})){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
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
- `),t.destroy();return}let o=r.sessionName;if(!Ne(o)){t.write(`HTTP/1.1 400 Bad Request\r
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;fW.handleUpgrade(e,t,n,i=>Zy(i,o,{cols:s,rows:a}))};KI.on("upgrade",GI);var VI=process.env.BOSTRAT_CERT_DIR||xe.join(process.env.HOME||Ad.tmpdir(),".bostrat","certs"),$I=Number(process.env.BOSTRAT_TLS_PORT)||3443,RI=xe.join(VI,"bostrat.globopi.key"),OI=xe.join(VI,"bostrat.globopi.crt");if(mt.existsSync(RI)&&mt.existsSync(OI)){let e=tW.createServer({key:mt.readFileSync(RI),cert:mt.readFileSync(OI)},v);e.on("upgrade",GI),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen($I,_d,()=>{console.log(`[bostrat-agent] https listening on ${_d||"0.0.0.0"}:${$I}`)})}KI.listen(AI,_d,()=>{console.log(`[bostrat-agent] listening on ${_d||"0.0.0.0"}:${AI}`);let e=TE(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: ${At}`),console.log(`[bostrat-agent] auto-trigger default: ${MI}%`),console.log(`[bostrat-agent] ip allowlist: ${wa.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)),kW(),hW(),wW(),bW(),J0({listTracks:ce,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)),HT()&&WT({listTracks:ce}),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)),G_(),X_(),kA({resolveTrack:te}),RA({listTracks:ce,createTrack:Bu,archiveTrack:Do,listRepos:Rn,resolveTrack:te,sayToLead:Ct,answerPrompt:Nu,startLeadHandoff:Uu,interruptLead:Du,listSubtaskJobs:jo,cancelSubtask:qu,readEvents:F,appendEvent:$,divertShip:ug,answerPrExists:dg,knownAgents:Ji}),pW(),Ua().then(t=>{t||console.warn(`[boot] no host tmux server on ${At} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),dI(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(ga=NE({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,nodeId:process.env.BOSTRAT_NODE_ID||Ad.hostname(),name:process.env.BOSTRAT_NODE_NAME||Ad.hostname(),listTracks:ce,detectAgents:Cu,sampleMetrics:YA,onTracksTransferred:sw,onDegraded:({since:t,unacked:n,oldestAgeMs:r,mode:o})=>{let s=Math.round(r/6e4),a=`${process.env.BOSTRAT_NODE_NAME||Ad.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(()=>{}),II=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(()=>{}),II=null},onUpdateAvailable:async t=>{try{vg={latest:t.latest,current:t.current},await Sn({...t,policy:bt()}),bt()==="auto"&&await DI({to:t.latest,from:t.current})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>aW(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await Sn({current:t,latest:a,min:n,installKind:o,required:!0,policy:bt(),status:"available",reason:"refused"}),bt()!=="off"&&a){let i=await Ju({to:a,kind:Ht,reason:"hard-floor"});i.ok?(Ic.cancel(),await Sn({current:t,latest:a,min:n,installKind:o,required:!0,policy:bt(),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:bt}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),os().catch(()=>{}),NT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),xA().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),oT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),xT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),jx().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 pW(){mW(),yu().catch(()=>{}),setInterval(()=>yu().catch(()=>{}),1e4)}function mW(){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(CI,"..","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 hW(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await ce(),r=await ZA({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 wW(){let e=null,t=async()=>{try{let n=bs(),r=0,o=[],s=null;try{let l=await ce(),u=await zw(l);r=u.fleet.unpricedTurns||0,o=u.fleet.unpricedModels||[],s=await JA(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 gW=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,yW=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function bW(){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 ce()).filter(a=>!Ge(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,gW).unref()},yW).unref()}function kW(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await ce();for(let n of t)Ge(n)||!n.boxes?.some(r=>r.state==="live")||(await Mu(n.id).catch(()=>{}),await DS(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)}