bostrat-node 1.8.3 → 1.8.4

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 +190 -190
  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 a$=Object.defineProperty;var j=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var Pd=(e,t)=>{for(var n in t)a$(e,n,{get:t[n],enumerable:!0})};import{createHash as i$,randomBytes as c$,timingSafeEqual as l$}from"node:crypto";function Ng(){return c$(32).toString("hex")}function va(e){let t=typeof e=="string"?e.trim():"";return t?i$("sha256").update(t).digest("hex"):null}function Pg(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:l$(Buffer.from(e),Buffer.from(t))}function Sa(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(Dd.set(e,(Dd.get(e)||0)+1),Bd.has(e)&&n-Bd.get(e)<u$)return!1;Bd.set(e,n);let o=Object.entries(t).filter(([,s])=>s!=null&&s!=="").map(([s,a])=>`${s}=${a}`).join(" ");return r(`[hook-audit] ${e} n=${Dd.get(e)}${o?` ${o}`:""}`),!0}async function Dg(e,{byToken:t,legacy:n,env:r=process.env}={}){let o=typeof e=="string"?e.trim():"";if(!o)return r.BOSTRAT_HOOK_LEGACY_DENY==="1"?{mode:"legacy-denied",target:null}:{mode:"legacy",target:await n()};let s=await t(o);return s?.track?{mode:"token",target:s}:{mode:"refused",target:null}}var $n,Rn,Dd,Bd,u$,Yo=j(()=>{$n="BOSTRAT_HOOK_TOKEN",Rn="x-bostrat-hook";Dd=new Map,Bd=new Map,u$=6e4});import It from"node:fs/promises";import Bg from"node:os";import St from"node:path";import{execFile as d$}from"node:child_process";import{promisify as f$}from"node:util";function Nc(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function p$(){return process.env.CLAUDE_CONFIG_DIR?St.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):St.join(Bg.homedir(),".claude.json")}function m$(){return process.env.CLAUDE_CONFIG_DIR?St.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):St.join(Bg.homedir(),".claude","settings.json")}async function or(e){if(!e||typeof e!="string")return;let t=St.resolve(e),n=p$(),r=m$(),o={};try{o=JSON.parse(await It.readFile(n,"utf8"))}catch{}o.hasCompletedOnboarding=!0,o.theme||(o.theme="dark"),o.projects=o.projects||{},o.projects[t]=o.projects[t]||{};let s=o.projects[t];Array.isArray(s.allowedTools)||(s.allowedTools=[]),s.hasTrustDialogAccepted=!0,s.hasCompletedProjectOnboarding=!0;let a=process.env.ANTHROPIC_API_KEY;if(a){let c=a.slice(-20);o.customApiKeyResponses=o.customApiKeyResponses||{},o.customApiKeyResponses.approved=o.customApiKeyResponses.approved||[],o.customApiKeyResponses.rejected=o.customApiKeyResponses.rejected||[],o.customApiKeyResponses.approved.includes(c)||o.customApiKeyResponses.approved.push(c)}await It.mkdir(St.dirname(n),{recursive:!0}),await It.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await It.readFile(r,"utf8"))}catch{}if(i.skipDangerousModePermissionPrompt=!0,i.remoteControlAtStartup=!1,i.tui===void 0&&(i.tui="default"),process.env.BOSTRAT_HOOKS!=="off"){let l=`curl -sS -m 3 -X POST ${process.env.BOSTRAT_HOOK_URL||`http://127.0.0.1:${process.env.PORT||3362}/api/hook`} -H 'content-type: application/json' -H "${Rn}: $${$n}" --data-binary @- >/dev/null 2>&1 || true`,u=[{hooks:[{type:"command",command:l}]}];i.hooks=i.hooks||{};for(let f of["SessionStart","UserPromptSubmit","Stop"])i.hooks[f]=u;i.hooks.PostToolUse=[{matcher:"*",hooks:[{type:"command",command:l}]}]}await It.mkdir(St.dirname(r),{recursive:!0}),await It.writeFile(r,JSON.stringify(i,null,2)),await h$(t)}async function h$(e){try{let t=St.resolve(e),n=St.join(t,".bostrat","memory","claude"),r=St.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await It.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(St.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await It.mkdir(n,{recursive:!0}),await It.mkdir(St.dirname(r),{recursive:!0}),await It.writeFile(r,JSON.stringify(o,null,2)),await w$(t,["/.claude/settings.local.json"])}catch{}}async function w$(e,t){try{let{stdout:n}=await f$(d$)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=St.resolve(e,n.trim()),o=await It.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
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 Ta=j(()=>{Yo()});import jd from"node:fs/promises";import g$ from"node:os";import Pc from"node:path";function y$(){let e=process.env.CODEX_HOME||Pc.join(g$.homedir(),".codex");return Pc.join(e,"config.toml")}function jg(e){return`[projects."${e}"]`}function b$(e,t){let n=jg(t),r=e.indexOf(n);if(r===-1)return!1;let o=e.slice(r+n.length),s=o.search(/^\s*\[/m),a=s===-1?o:o.slice(0,s);return/trust_level\s*=\s*"trusted"/.test(a)}async function Jo(e){if(!e||typeof e!="string")return;let t=Pc.resolve(e),n=y$(),r="";try{r=await jd.readFile(n,"utf8")}catch{}if(b$(r,t))return;let o=jg(t);if(r.includes(o)){let a=r.indexOf(o)+o.length,c=r.slice(a).search(/^\s*\[/m),l=c===-1?r.length:a+c,u=r.slice(a,l),f=/trust_level\s*=/.test(u)?u.replace(/trust_level\s*=\s*"[^"]*"/,'trust_level = "trusted"'):`${u.replace(/\s*$/,"")}
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 jd.mkdir(Pc.dirname(n),{recursive:!0}),await jd.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var Dc=j(()=>{});import Lg from"node:fs/promises";import k$ from"node:os";import Ea from"node:path";function x$(e){let n=Ea.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||Ea.join(k$.homedir(),".cursor");return Ea.join(r,"projects",n)}async function Xo(e){if(!e||typeof e!="string")return;let t=Ea.resolve(e),n=x$(t),r=Ea.join(n,".workspace-trusted");await Lg.mkdir(n,{recursive:!0}),await Lg.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
14
+ `,"utf8")}var Bc=j(()=>{});import Fd from"node:fs/promises";import sr from"node:path";import{execFile as v$}from"node:child_process";import{promisify as S$}from"node:util";async function $$(e){try{return(await Fd.stat(sr.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function R$(e){let t=i=>Fd.readFile(sr.join(e,".git",i),"utf8").then(c=>c.trim()).catch(()=>null),r=(await t("refs/remotes/origin/HEAD"))?.match(/^ref:\s*refs\/remotes\/origin\/(.+)/);if(r)return r[1].trim();let o;for(let i of["main","master"])if(await t(`refs/heads/${i}`)||(o??=await t("packed-refs")||"",new RegExp(`^[0-9a-f]{40} refs/heads/${i}$`,"m").test(o)))return i;let a=(await t("HEAD"))?.match(/^ref:\s*refs\/heads\/(.+)/);return a?a[1].trim():null}async function On(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await $$(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:sr.basename(o),branch:await R$(o)});return}if(s>=_$)return;let i;try{i=await Fd.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||I$.has(c.name)||await t(sr.join(o,c.name),s+1)}for(let o of A$)await t(sr.resolve(o),0);let n=new Set,r=[];for(let o of e.values()){let s=(await Se(o.path))?.toLowerCase();if(s){if(n.has(s))continue;n.add(s)}r.push(o)}return r.sort((o,s)=>o.name.localeCompare(s.name))}function O$(e){let t=String(e||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return t?`${t[1]}/${t[2]}`:null}async function Se(e){if(!e)return null;if(Ld.has(e))return Ld.get(e);let t=null;try{let{stdout:n}=await T$("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=O$(n)}catch{t=null}return Ld.set(e,t),t}async function Zo(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await On())if((await Se(n.path))?.toLowerCase()===t)return n.path;return null}var T$,Fg,E$,A$,_$,I$,Ld,ar=j(()=>{T$=S$(v$),Fg=process.env.HOME||"/home/globo",E$=sr.join(process.env.BOSTRAT_STATE_DIR||sr.join(Fg,".bostrat"),"repos"),A$=[...(process.env.BOSTRAT_REPOS_ROOT||sr.join(Fg,"Documents")).split(","),E$].map(e=>e.trim()).filter(Boolean),_$=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,I$=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);Ld=new Map});import C$ from"node:fs";import Ug from"node:fs/promises";import Aa from"node:path";import M$ from"node:os";import{fileURLToPath as N$}from"node:url";import{execFile as P$}from"node:child_process";import{promisify as D$}from"node:util";function Ie(e=process.env){let t=e.BOSTRAT_PLANE_URL||"";if(!t)return null;try{let n=new URL(t);return n.protocol=n.protocol==="ws:"?"http:":"https:",n.origin}catch{return null}}function jc(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Lc(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!Wg.test(n))throw Qo("repo must be owner/name",400);let r=Ud.get(n);if(r&&r.expiresAt-Date.now()>L$)return r;if(!jc(t))throw Qo("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await qg(`${Ie(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:Kg(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw Qo(`plane unreachable \u2014 GitHub auth unavailable (${i?.message||i})`,503)}let s=await o.json().catch(()=>({}));if(!o.ok){if(o.status>=500&&r&&r.expiresAt>Date.now())return r;throw Qo(s?.error||`plane replied ${o.status}`,o.status)}let a={token:s.token,expiresAt:Number(s.expiresAt)||Date.now()+55*6e4,username:s.username??null,installationId:s.installationId??null};return Ud.set(n,a),a}async function _a({env:e=process.env,force:t=!1}={}){if(!jc(e))return{configured:!1,repos:[],username:null};if(!t&&eo&&Date.now()-eo.at<F$)return eo.data;try{let n=await qg(`${Ie(e)}/v1/github/repos`,{headers:Kg(e)});if(!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return eo={at:Date.now(),data:r},r}catch(n){return eo?eo.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function Gg(){Ud.clear(),eo=null}async function ln({cwd:e=null,slug:t=null,env:n=process.env}={}){try{let r=t||(e?await Se(e):null);if(!r)return{};let{token:o}=await Lc(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function Hd({env:e=process.env}={}){return(await _a({env:e})).username??null}function q$(e){let[t,n]=String(e).split("/");return Aa.join(j$,t,n)}async function Wd(e,{env:t=process.env}={}){let n=(...r)=>Hg("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${H$()}" ${W$(t)}`),await n("config","credential.useHttpPath","true")}async function Fc(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!Wg.test(String(e||"")))throw Qo(`bad repo slug "${e}"`,400);let r=q$(e);if(C$.existsSync(Aa.join(r,".git")))return r;let{token:o}=await Lc(e,{env:t});await Ug.mkdir(Aa.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await Hg("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:U$,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await Ug.rm(r,{recursive:!0,force:!0}).catch(()=>{}),Qo(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Wd(r,{env:t}),r}var Hg,B$,j$,Wg,L$,F$,U$,qg,Ud,eo,Kg,Qo,H$,W$,it=j(()=>{ar();Hg=D$(P$),B$=process.env.BOSTRAT_STATE_DIR||Aa.join(process.env.HOME||M$.tmpdir(),".bostrat"),j$=Aa.join(B$,"repos"),Wg=/^[^/\s]+\/[^/\s]+$/,L$=5*6e4,F$=6e4,U$=10*6e4,qg=fetch,Ud=new Map,eo=null;Kg=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),Qo=(e,t)=>Object.assign(new Error(e),{status:t});H$=()=>N$(new URL("../bin/bostrat-git-credential",import.meta.url)),W$=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function zg(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Jg(e,t,n,r=Vg){let o=Ie(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await G$(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function Xg(e,{env:t=process.env,force:n=!1,timeoutMs:r=Vg}={}){if(!zg(t))return{facts:[],source:"unconfigured"};let o=qd.get(e);if(!n&&o&&Date.now()-o.at<K$)return{facts:o.facts,source:"cache"};try{let s=await Jg(`/v1/memory/${encodeURIComponent(e)}`,{headers:Yg(t)},t,r);if(!s.ok)throw new Error(`plane ${s.status}`);let a=await s.json(),i=Array.isArray(a?.facts)?a.facts:[];return qd.set(e,{at:Date.now(),facts:i}),{facts:i,source:"plane"}}catch(s){return o?{facts:o.facts,source:"stale",error:s?.message}:{facts:[],source:"unreachable",error:s?.message}}}async function Uc(e,t,{env:n=process.env}={}){if(!zg(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await Jg(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...Yg(n),"content-type":"application/json"},body:JSON.stringify({facts:t})},n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.results)?o.results:[];return qd.delete(e),{pushed:s.filter(a=>a.outcome==="accepted").length,rejected:s.filter(a=>a.outcome==="rejected"),source:"plane"}}catch(r){return{pushed:0,source:"unreachable",error:r?.message}}}var K$,Vg,qd,G$,Yg,Zg=j(()=>{it();K$=6e4,Vg=5e3,qd=new Map,G$=(...e)=>fetch(...e);Yg=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import Kd from"node:fs/promises";import es from"node:path";import V$ from"node:os";import{EventEmitter as z$}from"node:events";import{randomUUID as Y$}from"node:crypto";function ts(e){return e?.cwd?es.join(e.cwd,".bostrat","events"):es.join(Gd,"events")}async function Q$(e,t){if(!Hc.has(t)){let o=(await F(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);Hc.set(t,o)}let n=Hc.get(t)+1;return Hc.set(t,n),n}function Vd(e,t){let n=Array.isArray(e?.epochs)?e.epochs:null;if(!(!n||n.length===0)){if(!Number.isFinite(t))return n.length-1;for(let r=n.length-1;r>=0;r--){let o=n[r].startedAt;if(o==null||o<=t)return r}return 0}}async function $(e,t){let n=typeof e=="string"?e:e?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!t||!J$.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!X$.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!Z$.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?es.join(Gd,"events"):ts(e),o=t.epoch;if(o==null&&typeof e=="object"&&t.boxId&&Array.isArray(e?.boxes)){let u=e.boxes.find(f=>f.name===t.boxId);o=Vd(u,Number(t.payload?.ts??t.ts)||Date.now())}let s=await Q$(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||Y$(),trackId:n,boxId:t.boxId??null,...o!=null?{epoch:o}:{},...a?{userId:a}:{},seq:s,ts:t.ts??Date.now(),type:t.type,actor:t.actor??"system",provider:t.provider??null,source:t.source??"orchestrator",payload:t.payload??{},...t.causationId?{causationId:t.causationId}:{},...t.correlationId?{correlationId:t.correlationId}:{}},c=JSON.stringify(i),l=i;return ey(c)&&(c=ty(c),l=JSON.parse(c)),await Kd.mkdir(r,{recursive:!0}),await Kd.appendFile(Qg(r,n),c+`
15
+ `),ct.emit("event",l),ct.emit(`track:${n}`,l),l}async function F(e,t){let n,r;typeof e=="string"&&t?(n=e,r=t):(r=typeof e=="string"?e:e?.id,n=typeof e=="string"?es.join(Gd,"events"):ts(e));let o;try{o=await Kd.readFile(Qg(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
16
+ `))if(a.trim())try{s.push(JSON.parse(ey(a)?ty(a):a))}catch{}return s}function ny(e,t){let n=`track:${e}`;return ct.on(n,t),()=>ct.off(n,t)}var J$,X$,Z$,ct,Gd,Qg,Hc,eR,ey,ty,me=j(()=>{J$=new Set(["session.ready","turn.user","turn.agent","turn.retracted","peer.message","provider.error","turn.interrupted","tool.called","tool.result","prompt.raised","prompt.answered","prompt.autoRejected","box.fullscreen.detected","box.fullscreen.answered","context.usage","cost.recorded","memory.seed","memory.harvested","handoff.artifact","code.pushed","code.committed","code.rework","rework.cause.offered","rework.cause.answered","handoff.started","handoff.step","handoff.done","handoff.failed","subtask.delegated","subtask.merged","job.started","pr.state.changed","pr.offered","pr.offer.answered","pr.exists.offered","pr.exists.answered","box.state.changed","view.state.changed","view.spinup.failed","mock.state.changed","flow.state.changed","runbook.state.changed","ticket.linked","ticket.sync.failed","ticket.move.offered","ticket.move.answered","ticket.state.changed","ticket.commented","ticket.flow.changed","ticket.create.offered","ticket.create.answered","ticket.created","loop.create.offered","loop.create.answered","loop.created","loop.update.offered","loop.update.answered","loop.updated","loop.delete.offered","loop.delete.answered","loop.deleted","loop.paused","followup.armed","followup.armed.cancelled","followup.offered","followup.answered","followup.create.offered","followup.create.answered","followup.created","notify.raised","usage.cap.hit","usage.cap.warning","provider.connected","track.summary.recorded","track.transferred","track.recovered","track.circuit.tagged","blueprint.item.bound","decision.recorded","changelog.published","stall.detected","error"]),X$=new Set(["user","agent","orchestrator","system","peer"]),Z$=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor","cli"]),ct=new z$;ct.setMaxListeners(0);Gd=process.env.BOSTRAT_STATE_DIR||es.join(process.env.HOME||V$.tmpdir(),".bostrat");Qg=(e,t)=>es.join(e,`${t}.ndjson`),Hc=new Map;eR=/(?<!\\)((?:\\\\)*)\\u0000/g,ey=e=>e.includes("\\u0000"),ty=e=>e.replace(eR,"$1\\ufffd")});import Y from"node:fs/promises";import tR from"node:os";import we from"node:path";import{execFile as nR}from"node:child_process";import{promisify as rR}from"node:util";function qc(){return we.join(Kc,"memory","repos")}function to(e){return e===Cn?we.join(Kc,"memory",Cn):we.join(qc(),e)}async function $a(e){try{return JSON.parse(await Y.readFile(we.join(e,ly),"utf8"))}catch{return{}}}async function Yd(e,t){let n=await $a(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await Y.mkdir(e,{recursive:!0}),await Y.writeFile(we.join(e,ly),JSON.stringify(n))}function oy(e){let t=String(e||"").trim();if(!t)return null;let r=(t.replace(/\/+$/,"").split(/[/:]/).pop()||"").replace(/\.git$/i,"").toLowerCase();return/^[a-z0-9][a-z0-9._-]*$/.test(r)?r:null}async function sy(e){try{let{stdout:t}=await oR("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function Jd(e){if(!e)return[];let t=oy(await sy(e));if(t)return[t];let n=[],r=[];try{r=await Y.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=oy(await sy(we.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function Gc(e){let t=/^---\n([\s\S]*?)\n---\n?/.exec(e);return t?{fm:t[1],body:e.slice(t[0].length)}:{fm:null,body:e}}function ir(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function un(e,t=null){let n=t??await Y.readFile(e,"utf8").catch(()=>""),{fm:r}=Gc(n),o=ir(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await Y.stat(e)).mtimeMs}catch{return 0}}function uy(e,t){let n=ir(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===Cn){let o=ir(e,"trust");if(!o||/^operator/i.test(o))return Cn}return t}function Xd(e,t,n,r=new Map){let o=(e||"").split(`
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 dy(e,t){let n=ir(t,"name")||e.replace(/\.md$/,""),r=ir(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function Ra(e){let t=[];try{t=await Y.readdir(e,{withFileTypes:!0})}catch{return[]}return t.filter(n=>n.isFile()&&n.name.endsWith(".md")&&n.name!=="MEMORY.md").map(n=>n.name)}async function fy(e,t){let n=we.join(e,".bostrat","memory"),r=await Ra(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=ay.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let f of r){let d=we.join(n,f);if(o)try{if((await Y.stat(d)).mtimeMs<o-aR)continue}catch{continue}let p;try{p=await Y.readFile(d,"utf8")}catch{continue}let{fm:h}=Gc(p),w=uy(h,t);if(!w)continue;let g=to(w),k=we.join(g,f),S=await un(d,p);if(l.has(g)||l.set(g,await $a(g)),(l.get(g)[f]||0)>=S)continue;let E=await un(k).catch(()=>0);if(await Y.access(k).then(()=>!0).catch(()=>!1)&&E>=S)continue;await Y.mkdir(g,{recursive:!0}),await Y.writeFile(k,p),c++;let B=a.get(g);B||a.set(g,B={won:new Set,generated:new Map}),B.won.add(f),B.generated.set(f,dy(f,h)),i.has(w)||i.set(w,new Set),i.get(w).add(f)}let u=await Y.readFile(we.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[f,d]of a){let p=we.join(f,"MEMORY.md"),h=await Y.readFile(p,"utf8").catch(()=>"");await Y.writeFile(p,Xd(h,u,d.won,d.generated))}return ay.set(e,s),{harvested:c,changedByKey:i}}async function py(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await Y.access(we.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await Jd(r),a=await fy(r,s||null);t+=a.harvested;for(let[i,c]of a.changedByKey){n.has(i)||n.set(i,new Set);for(let l of c)n.get(i).add(l)}}return{harvested:t,changedByKey:n}}async function iR(){let e=we.join(Kc,"workspaces"),t=[];try{t=await Y.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return py(t.filter(n=>n.isDirectory()).map(n=>we.join(e,n.name)))}async function uR(e,t){let n=to(e),r=await $a(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!cR.test(l)||l==="MEMORY.md")continue;let u=we.join(n,l),f=await Y.access(u).then(()=>!0).catch(()=>!1),d=f?await un(u):0,p=Number(c.modified)||0;if(c.deleted){p>d&&(f&&await Y.rm(u,{force:!0}),await Yd(n,[[l,p]]),f&&(a.push(l),i++));continue}f&&d>=p||(r[l]||0)>=p||(await Y.mkdir(n,{recursive:!0}),await Y.writeFile(u,String(c.content??"")),o.add(l),typeof c.indexLine=="string"&&c.indexLine.trim()&&s.set(l,c.indexLine),i++)}if(o.size||a.length){let c=we.join(n,"MEMORY.md"),l=await Y.readFile(c,"utf8").catch(()=>""),u=Xd(l,[...s.values()].join(`
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(`
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}
24
+ `)}await Y.mkdir(n,{recursive:!0}),await Y.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function Vc(e,t=null){let n=to(e),r=t?.length?t:await Ra(n);if(!r.length)return{pushed:0,source:"empty"};let o=lR(await Y.readFile(we.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=we.join(n,a),c;try{c=await Y.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await un(i,c),indexLine:o.get(a)??null})}return Uc(e,s)}async function dR(e,{timeoutMs:t}={}){let{facts:n,source:r}=await Xg(e,t?{timeoutMs:t}:{});n.length?await uR(e,n):r==="plane"&&await Vc(e)}function fR(e){let t=e.split(`
25
+ `);t.length>ry&&(t=t.slice(0,ry));let n=t.join(`
26
+ `);for(;Buffer.byteLength(n,"utf8")>sR&&t.length;)t.pop(),n=t.join(`
27
+ `);return n}async function mR(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=we.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let f=to(u),d=await $a(f);for(let[g,k]of Object.entries(d)){let S=we.join(n,g);await Y.access(S).then(()=>!0).catch(()=>!1)&&await un(S)<=k&&(await Y.rm(S,{force:!0}),o++)}let p=await Ra(f);if(!p.length)continue;await Y.mkdir(n,{recursive:!0});for(let g of p){let k=we.join(f,g),S=we.join(n,g),E=await un(k),R=await un(S).catch(()=>0);await Y.access(S).then(()=>!0).catch(()=>!1)&&R>=E||(await Y.copyFile(k,S),r++)}let h=await Y.readFile(we.join(f,"MEMORY.md"),"utf8").catch(()=>""),w=u===Cn?"## operator memory":`## repo: ${u}`;h.trim()&&s.push(t.length>1?`${w}
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=fR(i);await Y.mkdir(n,{recursive:!0}),await Y.writeFile(we.join(n,"MEMORY.md"),c);let l=we.join(n,"claude");return await Y.mkdir(l,{recursive:!0}),await Y.writeFile(we.join(l,"MEMORY.md"),pR,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function my(e){try{let t=await Jd(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,Cn];return await Promise.all(n.map(r=>dR(r,{timeoutMs:hR}))),await mR(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function hy(){return{...Je,pending:ns.size,queued:zd.size}}function wy(e){if(Wc.has(e))return Wc.get(e);zd.add(e);let t=iy.then(async()=>{zd.delete(e),Wc.delete(e);let n=await Qd(e);return Je.runs++,Je.lastRunAt=Date.now(),n.error?(Je.errors++,Je.lastError=n.error):Je.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return Wc.set(e,t),iy=t.then(()=>{}),t}function zc(e,{delayMs:t=wR}={}){if(!e||typeof e!="string")return;Je.scheduled++;let n=ns.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{ns.delete(e),wy(e)},t);r.unref?.(),ns.set(e,r)}async function Zd(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await Y.access(we.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=ns.get(e);r&&(clearTimeout(r),ns.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([wy(e),s])}finally{clearTimeout(o)}}async function gy(e){return Ia||(Ia=(async()=>{try{cy||(cy=!0,await yR());let{harvested:t,changedByKey:n}=await py(e);for(let[r,o]of n)await Vc(r,[...o]);return Je.reconciles++,Je.lastReconcileAt=Date.now(),Je.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return Je.errors++,Je.lastError=t?.message||String(t),{harvested:0,error:Je.lastError}}finally{Ia=null}})(),Ia)}function gR(){return we.join(Kc,"memory",".full-sweep-done")}async function yy(){let e=gR();try{let t=JSON.parse(await Y.readFile(e,"utf8"));return Je.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...Je.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await iR();for(let[o,s]of n)await Vc(o,[...s]);let r={at:Date.now(),harvested:t};return await Y.mkdir(we.dirname(e),{recursive:!0}),await Y.writeFile(e,JSON.stringify(r)),Je.backfill=r,{ran:!0,...r}}catch(t){return Je.errors++,Je.lastError=t?.message||String(t),{ran:!1,error:Je.lastError}}}async function yR(){let e=0,t=[];try{t=await Y.readdir(qc(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=we.join(qc(),n.name),o=to(Cn),s=new Set,a=new Map;for(let p of await Ra(r)){let h=we.join(r,p),w;try{w=await Y.readFile(h,"utf8")}catch{continue}let{fm:g}=Gc(w);if(uy(g,n.name)!==Cn)continue;let k=we.join(o,p),S=await un(k).catch(()=>0),E=await un(h,w);await Y.mkdir(o,{recursive:!0}),E>S&&await Y.writeFile(k,w),await Y.rm(h,{force:!0}),s.add(p),a.set(p,dy(p,g)),e++}if(!s.size)continue;let i=Date.now();await Yd(r,[...s].map(p=>[p,i])),await Uc(n.name,[...s].map(p=>({file:p,deleted:!0,modified:i})));let c=we.join(r,"MEMORY.md"),l=await Y.readFile(c,"utf8").catch(()=>""),u=l.split(`
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 Y.writeFile(c,u).catch(()=>{});let f=we.join(o,"MEMORY.md"),d=await Y.readFile(f,"utf8").catch(()=>"");await Y.writeFile(f,Xd(d,l,s,a))}return{moved:e}}async function by(){let e=[],t=[Cn];try{for(let n of await Y.readdir(qc(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=to(n),o=await Ra(r),s=await $a(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await Y.readFile(we.join(r,i),"utf8").catch(()=>""),{fm:l}=Gc(c);a.push({file:i,name:ir(l,"name")||i.replace(/\.md$/,""),description:ir(l,"description")||"",scope:ir(l,"scope")||null,modified:await un(we.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function ky(e,t){if(!/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/.test(t)||t==="MEMORY.md")throw new Error("bad fact filename");let n=to(e),r=we.join(n,t);if(!await Y.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await Y.rm(r,{force:!0}),await Yd(n,[[t,s]]);let a=we.join(n,"MEMORY.md"),i=await Y.readFile(a,"utf8").catch(()=>"");await Y.writeFile(a,i.split(`
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 Uc(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function Qd(e){try{let t=await Jd(e),{harvested:n,changedByKey:r}=await fy(e,t[0]||null);for(let[o,s]of r)await Vc(o,[...s]);return n>0&&await kR(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function kR(e,t){let n=/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1];if(!n)return;let r={},o=0;for(let[s,a]of t){let i=[...a].sort();o+=i.length,r[s]={count:i.length,files:i.slice(0,bR)}}await $({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var oR,Kc,ry,sR,Cn,ly,rs,ay,aR,cR,lR,pR,hR,wR,ns,zd,iy,Je,Wc,cy,Ia,bR,Oa=j(()=>{Zg();me();oR=rR(nR),Kc=process.env.BOSTRAT_STATE_DIR||we.join(process.env.HOME||tR.tmpdir(),".bostrat"),ry=200,sR=25*1024;Cn="operator";ly=".tombstones.json";rs=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;ay=new Map,aR=2e3;cR=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,lR=e=>{let t=new Map;for(let n of(e||"").split(`
37
+ `)){let r=rs(n);r&&n.trim().startsWith("-")&&t.set(r,n)}return t};pR=`# Track memory
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
+ `;hR=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;wR=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,ns=new Map,zd=new Set,iy=Promise.resolve(),Je={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};Wc=new Map;cy=!1,Ia=null;bR=20});import ef from"node:fs/promises";import xR from"node:path";async function Tt(e,t,{mode:n}={}){await ef.mkdir(xR.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++vR}.tmp`;await ef.writeFile(r,JSON.stringify(t,null,2)+`
43
+ `,n!=null?{mode:n}:void 0),await ef.rename(r,e)}var vR,cr=j(()=>{vR=0});import Ey from"node:fs/promises";import Ay from"node:os";import _y from"node:path";function Ne(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Na(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),SR);try{return await $R(`${Ie(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function $y(){return Jc||(tf||=Ey.readFile(Iy(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>Jc={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>tf=null),tf)}async function Xc(){await Tt(Iy(),Jc).catch(()=>{})}function Sy(e){return e.op==="blob"?`blob ${e.family} ${e.id} ${e.v} ${e.kind}`:`${e.op} ${e.family} ${e.id}`}async function rf(e){let t=await $y(),n=Sy(e);if(e.op==="delete")t.ops=t.ops.filter(r=>!(r.family===e.family&&r.id===e.id)),t.ops.push(e);else{t.ops=t.ops.filter(o=>!(o.op==="delete"&&o.family===e.family&&o.id===e.id));let r=t.ops.findIndex(o=>Sy(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>xy&&(t.ops=t.ops.slice(-xy)),await Xc()}function Ty(){Yc||(Yc=setTimeout(()=>{Yc=null,os().catch(()=>{})},RR),Yc.unref?.())}function nf(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function CR(e,t=process.env){if(e.op==="record"){let n=await Na(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...Ma(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:IR()}]})},t);if(!n.ok)throw nf(n.status);let o=(await n.json().catch(()=>null))?.results?.[0];return o?.outcome==="rejected"?{delivered:!1,rejected:o.reason}:{delivered:!0}}if(e.op==="blob"){let n=await Ey.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await Na(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...Ma(t),"content-type":"application/octet-stream"},body:n},t);if(!r.ok&&r.status!==400)throw nf(r.status);return r.status===400?{delivered:!1,rejected:(await r.json().catch(()=>null))?.error||"rejected"}:{delivered:!0}}if(e.op==="delete"){let n=await Na(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:Ma(t)},t);if(!n.ok)throw nf(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function os({env:e=process.env,log:t=console,now:n=Date.now()}={}){return Ne(e)?Ca||(Ca=(async()=>{let r=await $y();MR(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await CR(a,e)}catch(c){if(!c?.refused)return Ty(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<ER)return Ty(),await Xc(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};t.error?.(`[content-plane] ALARM parking ${a.op} ${a.family}/${a.id} after ${a.refusals} refusals (${c.message}) \u2014 draining the ${r.ops.length-1} ops behind it`),r.ops.shift(),r.parked.push({...a,parkedAt:n,error:c.message}),r.parked.length>vy&&(r.parked=r.parked.slice(-vy)),s++,await Xc();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await Xc()}return{flushed:o,parked:s,pending:0}})().finally(()=>{Ca=null}),Ca):{flushed:0,source:"unconfigured"}}function MR(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=OR);if(n.length){e.parked=e.parked.filter(r=>!n.includes(r));for(let r of n)e.ops.push({...r,refusals:0,parkedAt:void 0,error:void 0})}}async function wt(e,t,{trackId:n=null,env:r=process.env}={}){return Ne(r)?(await rf({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),os({env:r})):{queued:!1,source:"unconfigured"}}async function lr(e,t,n,r,o,{env:s=process.env}={}){return Ne(s)?(await rf({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),os({env:s})):{queued:!1,source:"unconfigured"}}async function Vt(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return Ne(r)?(await rf({op:"delete",family:e,id:t,deletedAt:n}),os({env:r})):{queued:!1,source:"unconfigured"}}async function et(e,{env:t=process.env}={}){if(!Ne(t))return{records:[],source:"unconfigured"};try{let n=await Na(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:Ma(t)},t);if(!n.ok)throw new Error(`plane ${n.status}`);let r=await n.json();return{records:Array.isArray(r?.records)?r.records:[],source:"plane"}}catch(n){return{records:[],source:"unreachable",error:n?.message}}}async function Pa(e,t,n,r,{env:o=process.env}={}){if(!Ne(o))return null;try{let s=await Na(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:Ma(o)},o);if(!s.ok)return null;let a=Buffer.from(await s.arrayBuffer());return r==="md"||r==="html"?a.toString("utf8"):a}catch{return null}}var SR,TR,xy,ER,vy,AR,_R,Iy,IR,$R,RR,OR,Ma,Jc,tf,Yc,Ca,ur=j(()=>{it();cr();SR=1e4,TR=3e4,xy=2e3,ER=5,vy=100,AR=60*6e4,_R=()=>process.env.BOSTRAT_STATE_DIR||_y.join(process.env.HOME||Ay.tmpdir(),".bostrat"),Iy=()=>_y.join(_R(),"content-outbox.json"),IR=()=>process.env.BOSTRAT_NODE_ID||Ay.hostname(),$R=(...e)=>fetch(...e),RR=TR,OR=AR;Ma=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});Jc=null,tf=null,Yc=null,Ca=null});import of from"node:fs/promises";import Ry from"node:path";async function Oy(e,t,{box:n=null,agent:r=null}={}){if(!e||!Ne())return{pushed:!1};try{let o=Date.now();return await wt("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await lr("checkpoints",e,o,"md",t),Da=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function jR(){if(Da&&Date.now()-Da.at<BR)return{records:Da.records,source:"plane"};let e=await et("checkpoints");return e.source==="plane"&&(Da={at:Date.now(),records:e.records}),e}async function Zc(e){try{let t=DR(e);if(!t||!Ne())return{restored:!1};let n=Ry.join(e,NR,PR);if(await of.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await jR();if(o!=="plane")return{restored:!1};let s=r.find(i=>!i.deletedAt&&i.data?.id===t);if(!s?.data?.v)return{restored:!1};let a=await Pa("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await of.mkdir(Ry.dirname(n),{recursive:!0}),await of.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var NR,PR,DR,BR,Da,Qc=j(()=>{ur();NR=".bostrat/handoff",PR="latest.md",DR=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;BR=6e4,Da=null});import Ba from"node:fs/promises";import LR from"node:os";import My from"node:path";function no(e){let t=String(e??"");for(let n of FR)t=t.replace(n,"\u2039redacted\u203A");return t}function el(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function UR(e){try{await Ba.mkdir(sf,{recursive:!0}),await Ba.appendFile(ss,`${JSON.stringify(e)}
44
+ `,"utf8");let n=(await Ba.readFile(ss,"utf8")).split(`
45
+ `).filter(Boolean);n.length>Cy&&await Ba.writeFile(ss,`${n.slice(-Cy).join(`
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 re(e={}){let t={at:new Date().toISOString(),ts:Date.now(),...e},n=[t.flow||"handoff",t.phase||t.step||"?",t.trackId?`track=${t.trackId}`:"",t.sessionName?`box=${t.sessionName}`:"",t.error?`ERR=${t.error}`:""].filter(Boolean).join(" \xB7 ");if(console.log(`[handoff-debug] ${n}`),t.sessionName&&el())try{t.paneTail=no((await Ce(t.sessionName,{lines:35})).slice(-4e3))}catch{t.paneTail=null}(el()||t.error||/^(checkpoint|spawn|hydrate|commit|done|summarize|clear|resume|ready|send|failed|launch|submit-|gate-accept|blocked|timeout|dialog)/.test(String(t.phase||t.step||"")))&&await UR(t)}async function Ny({limit:e=80}={}){try{return(await Ba.readFile(ss,"utf8")).split(`
48
+ `).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=no(o.paneTail)),o}catch{return{raw:no(r)}}})}catch{return[]}}var FR,sf,ss,Cy,Py,dn=j(()=>{lt();FR=[/[A-Za-z0-9_-]{20,}#[A-Za-z0-9_-]{20,}/g,/\bsk-[A-Za-z0-9_-]{16,}/g,/\bghs_[A-Za-z0-9]{16,}|\bghp_[A-Za-z0-9]{16,}|\bgithub_pat_[A-Za-z0-9_]{20,}/g,/\bFlyV1 [A-Za-z0-9+/=_-]{16,}/g,/\bey[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g];sf=process.env.BOSTRAT_DEBUG_DIR||My.join(LR.homedir(),".bostrat","debug"),ss=My.join(sf,"handoff.jsonl"),Cy=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;Py={DEBUG_DIR:sf,LOG_FILE:ss}});import tl from"node:fs/promises";import af from"node:path";import HR from"node:os";async function By(e=Dy){await tl.mkdir(e,{recursive:!0});for(let t of qR){let n=t==="prepare-commit-msg"?KR:t==="post-commit"?GR:`${cf}exit 0
49
+ `,r=af.join(e,t),o=null;try{o=await tl.readFile(r,"utf8")}catch{}o!==n&&await tl.writeFile(r,n,{mode:493}),await tl.chmod(r,493).catch(()=>{})}return e}function jy({nodeUrl:e,dir:t=Dy,env:n=process.env}={}){return String(n.BOSTRAT_GIT_HOOKS||"").toLowerCase()==="off"?[]:["-e","GIT_CONFIG_COUNT=1","-e","GIT_CONFIG_KEY_0=core.hooksPath","-e",`GIT_CONFIG_VALUE_0=${t}`,"-e",`${ja}=${e}`]}function Ly(e=process.env){return e.BOSTRAT_NODE_URL||`http://127.0.0.1:${e.PORT||3362}`}var ja,WR,Dy,qR,cf,KR,GR,lf=j(()=>{Yo();ja="BOSTRAT_NODE_URL",WR=process.env.BOSTRAT_STATE_DIR||af.join(process.env.HOME||HR.tmpdir(),".bostrat"),Dy=af.join(WR,"git-hooks"),qR=["applypatch-msg","pre-applypatch","post-applypatch","pre-commit","pre-merge-commit","prepare-commit-msg","commit-msg","post-commit","pre-rebase","post-checkout","post-merge","pre-push","post-rewrite","pre-auto-gc"],cf=`#!/bin/sh
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
+ `,KR=`${cf}
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 "$${ja}" ] && 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}" "$${ja}/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
+ `,GR=`${cf}
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 "$${ja}" ] && 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 "$${ja}/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(`
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(`
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(`
85
+ `});import{execFile as Uy}from"node:child_process";import{promisify as VR}from"node:util";import rl from"node:fs";import{randomUUID as Hy}from"node:crypto";function cs(e){return new Promise(t=>setTimeout(t,e))}function nl(e,t){if(!t)return e;let n=o=>typeof o=="string"?o.split(t).join("<redacted>"):o,r=new Error(n(e?.message)||"command failed");return e?.code!==void 0&&(r.code=e.code),e?.stderr!==void 0&&(r.stderr=n(e.stderr)),r}function Wy(e){return`/tmp/tmux-${e}/default`}function zR({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=Wy(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function Fa(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${La}=1`]}function Ua(e,t,n){let r=ro(e),o=/(^|\s)(--session-id|--resume|--continue|-r|-c)(\s|=|$)/.test(e);if(!r||o)return e;let s=`${e} --session-id ${t}`,a=/(^|\s)(--name|-n)(\s|=)/.test(e);return n&&!a&&Pe(n)&&(s+=` --name ${n}`),s}function ro(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function dr(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function XR(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:ro(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function qy(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await Ky(e,{loginShell:t});return r===ol?!0:r===as?!1:n}async function Ky(e,{loginShell:t=!1,timeoutMs:n=uf}={}){if(!e)return as;let r=t?process.env.SHELL||"/bin/sh":"sh",o=t?"-lic":"-c";try{return await $e(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),ol}catch(s){return s?.killed||s?.signal?is:s?.code===1||s?.code===127?as:is}}async function sl(e,{retries:t=ZR,sleep:n=QR,probe:r=Ky}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:uf});for(let a=0;s===is&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:uf*2});return s}function V(...e){return["-S",$t,...e]}async function fr(){if(!rl.existsSync($t))return!1;try{return await $e(K,V("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function Ha(){if(await fr())return!0;try{rl.mkdirSync($t.replace(/\/[^/]+$/,""),{recursive:!0}),await $e(K,V("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await fr()}function Pe(e){return typeof e=="string"&&eO.test(e)}async function zt(){if(!rl.existsSync($t))return[];try{let e="#{session_name}|#{session_windows}|#{session_attached}|#{session_activity}|#{pane_current_path}|#{@bostrat-session}|#{@bostrat-title}|#{@bostrat-sid}|#{@bostrat-agent}|#{alternate_on}|#{session_created}",{stdout:t}=await $e(K,V("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
86
+ `).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,f,d,p,h]=r.split("|"),w=Number(i),g=Number(h);return{name:o,title:u||null,windows:Number(s),attached:Number(a),lastActivityMs:Number.isFinite(w)?n-w*1e3:null,cwd:c||null,isBostrat:l==="1",sessionId:f||null,agent:d||(l==="1"?"claude":null),alternateOn:p==="1",createdMs:Number.isFinite(g)&&g>0?g*1e3:null}}).filter(r=>!JR.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function ge(e){return(await zt()).find(n=>n.name===e)||null}function rO(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=nO&&tO.test(t)}function al(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function Gy(e){try{let{stdout:t}=await $e(K,V("list-sessions","-F","#{session_name}"));return t.split(`
87
+ `).map(n=>n.trim()).includes(e)}catch{return!1}}function aO(e){let t=String(e||"").trim().split(/\s+/)[0]||"";if(t.includes("/"))return null;let n=[];for(let o=1;o<=t.length-3;o++)n.push(t.slice(o));if(!n.length)return null;let r=n.map(o=>o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp(`\\b(?:${r.join("|")})`)}async function iO(e,t){let n=Date.now()+Wa(),r=aO(t),o=!1,s=0;for(;;){if(await cs(oO),s+=1,!await Gy(e))return;let a=await Ce(e,{lines:15}),i=!o&&sO.test(a)&&!!r?.test(a);if(!i&&s>1&&!await Mn(e))return;if(i){o=!0,await re({flow:"spawn",phase:"launch-retry",sessionName:e,agent:dr(t),promptHead:t.slice(0,120)}).catch(()=>{}),await $e(K,V("send-keys","-t",e,"C-u")),await $e(K,V("send-keys","-t",e,"-l",t)),await $e(K,V("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await re({flow:"spawn",phase:"launch-failed",sessionName:e,agent:dr(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function pr(e,t=YR,n={}){if(!rO(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=al(r);if(!Pe(o))throw new Error("resulting tmux session name is invalid");if(!await Ha())throw new Error(`host tmux server not running on ${$t} and auto-start failed \u2014 start one: ${K} -S ${$t} new-session -d -s keeper "sleep 2147483647"`);if(await Gy(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||df,a=n.agent||dr(s),i=!!n.resumeSessionId,c=n.resumeSessionId||Hy(),l=i?s:Ua(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),f=a==="claude"&&ro(s),d=n.firstRun===!0;d||(f&&await or(t),a==="codex"&&await Jo(t),a==="cursor"&&await Xo(t),await my(t),n.freshWorkspace!==!0&&await Zc(t));let p=f&&!d?Nc():null,h=Ng(),w=["-e",`${$n}=${h}`];w.push(...jy({nodeUrl:Ly()})),p&&w.push("-e",`ANTHROPIC_API_KEY=${p}`),f&&w.push(...Fa());try{await $e(K,V("new-session","-d","-s",o,"-c",t,...w))}catch(g){throw nl(p?nl(g,p):g,h)}return await oo(o),await $e(K,V("set-option","-t",o,"@bostrat-session","1")),await $e(K,V("set-option","-t",o,"@bostrat-title",r)),await $e(K,V("set-option","-t",o,"@bostrat-sid",c)),await $e(K,V("set-option","-t",o,"@bostrat-agent",a)),await $e(K,V("send-keys","-t",o,l,"Enter")),XR(l)&&iO(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:h}}async function Yt(e){if(!Pe(e))throw new Error("invalid session name");await $e(K,V("kill-session","-t",e))}async function Vy(e,t){if(Pe(e))try{let n=t?V("set-option","-t",e,"@bostrat-sid",t):V("set-option","-u","-t",e,"@bostrat-sid");await $e(K,n)}catch{}}async function Ce(e,{lines:t=40}={}){if(!Pe(e))return"";try{let n=V("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await $e(K,n);return String(r||"")}catch{return""}}async function zy(e){if(!Pe(e))return 0;try{let{stdout:t}=await $e(K,V("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
88
+ `).filter(Boolean).length}catch{return 0}}async function oo(e,{cols:t=uO,rows:n=dO}={}){if(!Pe(e))return!0;if(await zy(e))return!1;try{let r=await Yy(e);if(r.cols===t&&r.rows===n)return!0;await $e(K,V("resize-window","-t",e,"-x",String(t),"-y",String(n))),await $e(K,V("set-window-option","-t",e,"window-size","latest")),await cs(80)}catch{}return!0}async function fO(e){if(!Pe(e))return 0;try{let{stdout:t}=await $e(K,V("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function Mn(e){let t=await fO(e);if(!t)return!1;try{return await $e("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function Yy(e){if(!Pe(e))return{cols:0,rows:0};try{let{stdout:t}=await $e(K,V("display-message","-t",e,"-p","#{window_width} #{window_height}")),[n,r]=String(t||"").trim().split(/\s+/).map(o=>Number(o)||0);return{cols:n,rows:r}}catch{return{cols:0,rows:0}}}async function il(e,{cols:t=cO,rows:n=lO}={}){if(Pe(e)&&!await zy(e))try{let r=await Yy(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await $e(K,V("resize-window","-t",e,"-x",String(o),"-y",String(s))),await $e(K,V("set-window-option","-t",e,"window-size","latest")),await cs(80))}catch{}}async function Nn(e){return await il(e),Ce(e,{lines:Xe})}async function Le(e,t,{settleMs:n=40,kind:r}={}){if(!Pe(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>pO.has(s));for(let s=0;s<o.length;s++)await $e(K,V("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await cs(n);return re({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function ls(e,t,{kind:n}={}){if(!Pe(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await $e(K,V("send-keys","-t",e,"-N",String(r),"BSpace")),re({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function ll(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!Pe(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await $e(K,V("send-keys","-t",e,"-l",s)),n>0&&await cs(n);re({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function mO(e,t){return new Promise((n,r)=>{let o=Uy(K,V(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function hO(e,t){let n=`bostrat-${Hy().slice(0,8)}`;await mO(["load-buffer","-b",n,"-"],t),await $e(K,V("paste-buffer","-p","-d","-b",n,"-t",e))}async function Ze(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!Pe(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await hO(e,t):await $e(K,V("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await cs(a),await $e(K,V("send-keys","-t",e,"Enter"))}re({flow:"tmux",phase:"send",sessionName:e,kind:o||"text",textLen:typeof t=="string"?t.length:0,textHead:typeof t=="string"?t.slice(0,120):"",enter:n,submitDelayMs:r,...s?{paste:!0}:{}}).catch(()=>{})}var $e,K,Fy,$t,YR,df,La,ff,JR,ol,as,is,uf,ZR,QR,pf,eO,tO,nO,Wa,oO,sO,cO,lO,Xe,uO,dO,pO,cl,lt=j(()=>{Ta();Dc();Bc();Oa();Qc();dn();Yo();lf();$e=VR(Uy);K=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";Fy=typeof process.getuid=="function"?process.getuid():0,$t=zR({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return rl.existsSync(Wy(Fy))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:Fy}),YR=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",df=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",La="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";ff="bostrat-usage-probe",JR=new Set([ff]);ol="present",as="absent",is="unknown",uf=5e3,ZR=[250,1e3,3e3],QR=e=>new Promise(t=>setTimeout(t,e));pf={claude:"npm install -g @anthropic-ai/claude-code",codex:"npm install -g @openai/codex","cursor-agent":"curl https://cursor.com/install -fsS | bash",gh:"apt install gh (Debian: enable cli.github.com/packages) / brew install gh \u2014 see https://github.com/cli/cli#installation"};eO=/^[A-Za-z0-9_.-]{1,64}$/;tO=/^[A-Za-z0-9 ._↻-]+$/,nO=64;Wa=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,oO=1e3,sO=/not found|Unknown command/i;cO=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,lO=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,Xe=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,uO=Number(process.env.BOSTRAT_BOX_COLS)||120,dO=Number(process.env.BOSTRAT_BOX_ROWS)||40;pO=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);cl=1600});import qa from"node:fs";import xO from"node:fs/promises";import us from"node:path";import vO from"node:os";function wf(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function gf(e){let t=us.join(hf,wf(e)),n;try{n=qa.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=us.join(t,o);try{let{mtimeMs:a}=qa.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function Jt(e,t){if(!t)return null;let n=us.join(hf,wf(e),`${t}.jsonl`);return qa.existsSync(n)?n:null}function nb(e){if(!e)return[];let t=us.join(hf,wf(e)),n;try{n=qa.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=qa.statSync(us.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function Et(e,t=131072){let n=await xO.open(e,"r");try{let{size:r}=await n.stat(),o=Math.max(0,r-t),s=r-o;if(s===0)return"";let a=Buffer.alloc(s);return await n.read(a,0,s,o),a.toString("utf8")}finally{await n.close()}}function TO(e){let t=e.split(`
89
+ `);for(let n=t.length-1;n>=0;n--){let r=t[n].trim();if(!r||r[0]!=="{")continue;let o;try{o=JSON.parse(r)}catch{continue}let s=o?.message?.usage;if(!s)continue;let a=(s.input_tokens||0)+(s.cache_creation_input_tokens||0)+(s.cache_read_input_tokens||0);if(a>0)return{occupancy:a,model:o.message.model||o.model||null}}return null}async function Ka(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=Jt(e,t),o=!0,!r)return null}else if(n){if(r=gf(e),o=!1,!r)return null}else return null;let s;try{s=TO(await Et(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(tb,s.model),i=tb[s.model]||SO;return{source:"transcript",exact:o,model:s.model,windowKnown:a,window:i,occupancy:s.occupancy,pct:Math.min(1,s.occupancy/i),transcript:r}}var tb,SO,hf,Xt=j(()=>{tb={"claude-opus-5":1e6,"claude-opus-4-8":1e6,"claude-opus-4-7":1e6,"claude-opus-4-6":1e6,"claude-sonnet-5":1e6,"claude-sonnet-4-6":1e6,"claude-haiku-4-5":2e5,"claude-fable-5":1e6},SO=2e5,hf=process.env.BOSTRAT_CLAUDE_PROJECTS||us.join(vO.homedir(),".claude","projects")});function EO(e){let t=[],n="",r=null;for(let o=0;o<e.length;o++){let s=e[o];if(r){n+=s,s===r&&e[o-1]!=="\\"&&(r=null);continue}if(s==="'"||s==='"'||s==="`"){r=s,n+=s;continue}if(s==="&"&&e[o+1]==="&"){t.push(n),n="",o++;continue}if(s==="|"&&e[o+1]==="|"){t.push(n),n="",o++;continue}if(s==="|"||s===";"||s===`
90
+ `){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function Ga(e){let t=[],n="",r=null,o=!1,s=()=>{if(o){if(/^\d*[<>]/.test(n)||n.startsWith(">")){n="",o=!1;return}t.push(n),n="",o=!1}};for(let a=0;a<e.length;a++){let i=e[a];if(r){i===r&&e[a-1]!=="\\"?r=null:n+=i,o=!0;continue}if(i==="'"||i==='"'){r=i,o=!0;continue}if(i==="<"&&e[a+1]==="<")return s(),t.push("<<"),t;if(/\s/.test(i)){s();continue}n+=i,o=!0}return s(),t}function Va(e){let t=e;for(;t.length&&/^[A-Za-z_][A-Za-z0-9_]*=/.test(t[0]);)t=t.slice(1);for(;t.length&&(t[0]==="sudo"||t[0]==="time"||t[0]==="env");)t=t.slice(1);return t}function Oe(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(sb(o)){t.has(o)&&r++;continue}n.push(o)}return n}function ab(e){let t=e.indexOf("-n"),n=t!==-1?e[t+1]:null;if(!n)return null;let r=/^(\d+),(\d+)p$/.exec(n)||/^(\d+)p$/.exec(n);return r?r[2]?{from:r[1],to:r[2]}:{from:r[1],to:r[1]}:null}function IO(e){let t=ab(e),n=ut(Oe(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${Fe(n)}`:`Read lines ${t.from}\u2013${t.to} of ${Fe(n)}`:e.includes("-i")&&n?`Edit ${Fe(n)}`:null}function yf(e){if(e.includes("--files")){let s=ut(Oe(e,rb)[0]);return s&&s!=="."?`List files in ${ds(s)}`:"List files"}let t=Oe(e,rb),n=t[0];if(!n)return null;let r=ut(t.slice(1).find(s=>s!==".")),o=fs(n,40);return r?`Search for \u201C${o}\u201D in ${ds(r)}`:`Search for \u201C${o}\u201D`}function bf(e){let t=Oe(e,new Set(["--prefix"])),n=t[0];return n?n==="test"||n==="t"?"Run tests":n==="run"||n==="run-script"?t[1]?`Run ${t[1]}`:null:n==="ci"||n==="install"||n==="i"||n==="add"?"Install dependencies":null:null}function kf(e,t){if(e.includes("-e")||e.includes("--eval")||e.includes("-c")||e[1]==="-"||e.includes("<<"))return`Run an inline ${t} script`;if(e.includes("--test"))return"Run tests";let n=Oe(e)[0];return n?`Run ${Fe(n)}`:null}function $O(e){let t=Oe(e),n=t[0],r=t.find(a=>/\.(service|timer|socket|target)$/.test(a))||t[1],o=r?r.replace(/\.service$/,""):"a service";return{status:`Check ${o} status`,show:`Inspect ${o}`,restart:`Restart ${o}`,start:`Start ${o}`,stop:`Stop ${o}`,"daemon-reload":"Reload systemd"}[n]||null}function ob(e){return e.find(t=>/^https?:\/\//.test(t))||null}function CO(e){let t=Va(Ga(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(Fe(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return xf(t[2]);let n=Fe(t[0]);if(OO.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=RO[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function xf(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
91
+ `,n);i!==-1&&(t=t.slice(0,i))}let r=EO(t);for(let i=0;i<r.length-1;i++){let c=Va(Ga(r[i])),l=Va(Ga(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Fe(c[0]))&&Fe(l[0])==="sed"){let u=ab(l),f=Oe(c)[0];if(u&&f)return fs(u.from===u.to?`Read line ${u.from} of ${Fe(f)}`:`Read lines ${u.from}\u2013${u.to} of ${Fe(f)}`,88)}}let o=[];for(let i of r){let c=CO(i);c&&o.push({d:c,head:Fe(Va(Ga(i))[0]||""),sub:Oe(Va(Ga(i)))[0]})}if(!o.length)return null;let s=o.find(i=>i.head==="git"&&i.sub==="commit"),a=o.find(i=>i.head==="git"&&i.sub==="push");return s&&a?"Commit and push changes":fs(s?s.d:o[0].d,88)}var fs,ut,Fe,ds,sb,rb,AO,_O,RO,OO,ib=j(()=>{fs=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,ut=e=>e&&!/[$`]/.test(e)?e:null,Fe=e=>e.replace(/\/+$/,"").split("/").pop()||e,ds=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},sb=e=>e.startsWith("-"),rb=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);AO={status:()=>"Check git status",diff:()=>"Review changes",log:()=>"Review commit history",show:()=>"Inspect a commit",add:()=>"Stage files",commit:()=>"Commit changes",push:()=>"Push to remote",pull:()=>"Pull from remote",fetch:()=>"Fetch from remote",merge:()=>"Merge branches",rebase:()=>"Rebase branch",stash:()=>"Stash changes",clone:e=>e[1]?`Clone ${Fe(e[1])}`:"Clone repository",checkout:()=>"Switch branches",switch:()=>"Switch branches",restore:()=>"Restore files",reset:()=>"Reset git state",branch:(e,t)=>t.includes("--show-current")?"Check current branch":"List branches",remote:()=>"Check git remotes","rev-parse":()=>"Resolve a git ref",worktree:()=>"Manage git worktrees","merge-base":()=>"Find the merge base","ls-files":()=>"List tracked files"},_O={pr:e=>({create:"Create a pull request",list:"List pull requests",view:"View a pull request",merge:"Merge a pull request",checks:"Check PR status"})[e[1]]||"Run a gh pr command",auth:()=>"Authenticate GitHub CLI",api:()=>"Call the GitHub API",repo:()=>"Inspect the GitHub repo",issue:()=>"Work with GitHub issues"};RO={git:e=>{let t=Oe(e,new Set(["-C","-c"])),n=AO[t[0]];return n?n(t,e):null},gh:e=>{let t=Oe(e),n=_O[t[0]];return n?n(t):null},sed:IO,rg:yf,grep:yf,egrep:yf,nl:e=>{let t=ut(Oe(e)[0]);return t?`Read ${Fe(t)}`:null},cat:e=>{let t=ut(Oe(e)[0]);return t?`Read ${Fe(t)}`:null},head:e=>{let t=ut(Oe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${Fe(t)}`:null},tail:e=>{let t=ut(Oe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${Fe(t)}`:null},wc:e=>{let t=ut(Oe(e)[0]);return t?`Count lines in ${Fe(t)}`:"Count input lines"},ls:e=>{let t=ut(Oe(e)[0]);return t&&t!=="."?`List files in ${ds(t)}`:"List files"},find:e=>ut(e[1])&&!sb(e[1])&&e[1]!=="."?`Find files in ${ds(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=ut(Oe(e)[0]);return t?`Create directory ${ds(t)}`:null},touch:e=>{let t=ut(Oe(e)[0]);return t?`Create ${Fe(t)}`:null},rm:e=>{let t=ut(Oe(e)[0]);return t?`Delete ${ds(t)}`:null},mv:e=>{let t=ut(Oe(e)[0]);return t?`Move ${Fe(t)}`:null},cp:e=>{let t=ut(Oe(e)[0]);return t?`Copy ${Fe(t)}`:null},chmod:e=>{let t=ut(Oe(e)[1]);return t?`Change permissions on ${Fe(t)}`:null},diff:e=>{let t=Oe(e);return t.length>=2?`Compare ${Fe(t[0])} and ${Fe(t[1])}`:null},curl:e=>{let t=ob(e);return t?`Fetch ${fs(t,56)}`:"Fetch a URL"},wget:e=>{let t=ob(e);return t?`Fetch ${fs(t,56)}`:"Fetch a URL"},npm:bf,pnpm:bf,yarn:bf,npx:e=>{let t=Oe(e)[0];return t?`Run ${t}`:null},node:e=>kf(e,"Node"),python:e=>kf(e,"Python"),python3:e=>kf(e,"Python"),make:e=>{let t=Oe(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:$O,journalctl:e=>{let t=e.findIndex(r=>r==="-u"||r==="--unit"||r==="--user-unit"),n=t!==-1?e[t+1]:null;return n?`Read ${n.replace(/\.service$/,"")} logs`:"Read system logs"},tmux:e=>{let t=Oe(e,new Set(["-S","-L","-t","-f"]))[0];return{ls:"List tmux sessions","list-sessions":"List tmux sessions","kill-session":"Kill a tmux session","send-keys":"Send keys to a tmux session","capture-pane":"Capture a tmux pane","new-session":"Start a tmux session"}[t]||null},ps:()=>"List processes",which:e=>{let t=Oe(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=Oe(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},OO=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function ps(e){let t=e.split(`
92
+ `).map(n=>n.trim()).find(Boolean)||e;return t.length>88?`${t.slice(0,88).trimEnd()}\u2026`:t}function mr(e,t=""){let n=t.trim();return n||xf(e)||ps(e)}function vf(e,t){if(e){if(Array.isArray(e)){for(let n of e)vf(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&Sf.has(e.name)){let n=String(e.input?.command||"").trim();n&&t.push({id:e.id||null,tool:e.name,command:n,description:String(e.input?.description||"").trim()})}for(let n of Object.values(e))vf(n,t)}}}async function cb(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await Et(e,t)}catch{return[]}let o=[];for(let s of r.split(`
93
+ `)){let a=s.trim();if(!a||a[0]!=="{")continue;let i;try{i=JSON.parse(a)}catch{continue}let c=i.message;if(!c)continue;let l=[];if(vf(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let f of l)o.push({...f,summary:mr(f.command,f.description),ts:u})}return o.slice(-n)}function lb(e,t){let n=t.filter(l=>l.role==="assistant"&&(l.text||"").trim()).sort((l,u)=>(l.ts||0)-(u.ts||0)),r=[...e].sort((l,u)=>(l.ts||0)-(u.ts||0)),o=[],s=0,a=0,i=l=>{let u=l.n??a+1;return u>a&&(a=u),u};for(let l of n){let u=r.findIndex((h,w)=>w>=s&&(h.ts||0)>(l.ts||0)),f=u===-1?r.length:u,d=r.slice(s,f);if(s=f,!d.length)continue;let p=d.map(h=>({...h,n:i(h)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:p,ts:Math.max(...p.map(h=>h.ts||0)),pending:!1})}let c=r.slice(s);if(c.length){let l=c.map(u=>({...u,n:i(u)}));o.push({id:`batch-pending-${l[0]?.box||"lead"}`,anchorTs:null,anchorBox:l[l.length-1]?.box??null,agent:l[l.length-1]?.agent??"claude",boxRole:l[l.length-1]?.boxRole??"lead",commands:l,ts:Math.max(...l.map(u=>u.ts||0)),pending:!0})}return o}var Sf,ms=j(()=>{Xt();ib();Sf=new Set(["Bash"])});import ub from"node:fs";import Ef from"node:fs/promises";import Tf from"node:path";import MO from"node:os";async function db(e){try{return await Ef.realpath(e)}catch{return e}}function PO(e=NO){let t=[],n=r=>{let o;try{o=ub.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=Tf.join(r,s.name);if(s.isDirectory())n(a);else if(s.isFile()&&s.name.startsWith("rollout-")&&s.name.endsWith(".jsonl")){let i=/-([0-9a-f-]{36})\.jsonl$/i.exec(s.name);try{t.push({id:i?i[1]:null,file:a,mtimeMs:ub.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function DO(e,t=1048576){let n;try{n=await Ef.open(e,"r")}catch{return""}try{let r=Buffer.alloc(Math.min(t,65536)),o="",s=0;for(;;){let{bytesRead:a}=await n.read(r,0,r.length,s);if(!a)break;o+=r.toString("utf8",0,a);let i=o.indexOf(`
94
+ `);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=t)break}return o}finally{await n.close()}}async function BO(e){let t=await DO(e);if(!t)return null;let n;try{n=JSON.parse(t)}catch{return null}return n?.type==="session_meta"&&n?.payload?.cwd||null}async function so(e,t){if(!e&&!t)return null;let n=PO();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await db(e);for(let o of n){let s=await BO(o.file);if(s&&(s===e||await db(s)===r))return o}return null}async function fb(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await so(e,t);if(!o)return[];let s;try{s=await Et(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,f=null;for(let d of s.split(`
95
+ `)){let p=d.trim();if(!p||p[0]!=="{")continue;let h;try{h=JSON.parse(p)}catch{continue}if((h.type==="turn_context"&&h.payload?.model||h.type==="session_meta"&&h.payload?.model)&&(i=h.payload.model),h.type==="event_msg"){let S=h.payload?.type;S==="task_started"?(l=!0,u=!1,f=h.payload?.turn_id||null):S==="task_complete"&&l&&(l=!1,!u&&h.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:ao,sourceId:h.payload?.turn_id||f||void 0,ts:h.timestamp?Date.parse(h.timestamp):null,model:i}));continue}if(h.type!=="response_item")continue;let w=h.payload;if(!w)continue;if((w.type==="function_call"||w.type==="custom_tool_call")&&w.name){u=!0,Af.has(w.name)||c.push(w.name);continue}if(w.type!=="message"||w.role!=="assistant")continue;u=!0;let g=LO(w.content),k=c.length?c.slice():null;c=[],!(!g&&!k)&&a.push({role:"assistant",text:g,tools:k||void 0,ts:h.timestamp?Date.parse(h.timestamp):null,model:i})}if(i)for(let d of a)d.model||(d.model=i);return a.slice(-n)}function FO(e){if(typeof e?.cmd=="string"&&e.cmd.trim())return e.cmd.trim();let t=e?.command;return typeof t=="string"&&t.trim()?t.trim():Array.isArray(t)&&t.length?t.length===3&&/^(ba)?sh$/.test(t[0])&&t[1]==="-lc"?String(t[2]).trim():t.map(String).join(" ").trim():null}function UO(e){let t=e[0];if(t!=='"'&&t!=="'"&&t!=="`")return null;let n="";for(let r=1;r<e.length;r++){let o=e[r];if(o==="\\"){let s=e[++r];if(s===void 0)return null;if(s==="n")n+=`
96
+ `;else if(s==="t")n+=" ";else if(s==="r")n+="\r";else if(s==="u")if(e[r+1]==="{"){let a=e.indexOf("}",r+2);if(a===-1)return null;n+=String.fromCodePoint(parseInt(e.slice(r+2,a),16)),r=a}else n+=String.fromCharCode(parseInt(e.slice(r+1,r+5),16)),r+=4;else n+=s}else{if(o===t)return n;if(t==="`"&&o==="$"&&e[r+1]==="{")return null;n+=o}}return null}function HO(e){let t=String(e||""),n=[],r=/exec_command\s*\(/g;for(let s;s=r.exec(t);)n.push(s.index+s[0].length);let o=[];return n.forEach((s,a)=>{let i=t.slice(s,a+1<n.length?n[a+1]:t.length),c=/(?:^|[{,\s])["'`]?cmd["'`]?\s*:\s*/.exec(i);if(!c)return;let l=UO(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function pb(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await so(e,t);if(!o)return[];let s;try{s=await Et(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
97
+ `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type!=="response_item")continue;let u=l.payload;if(!u)continue;let f=[];if(u.type==="function_call"&&za.has(u.name)){let p;try{p=JSON.parse(u.arguments||"{}")}catch{continue}let h=FO(p);h&&(f=[h])}else u.type==="custom_tool_call"&&u.name==="exec"&&(f=HO(u.input));if(!f.length)continue;let d=u.call_id||u.id||null;f.forEach((p,h)=>{a.push({id:d?h?`${d}:${h}`:d:null,tool:u.name,command:p,description:"",summary:mr(p),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function mb(e,t){let n=await so(e,t);if(!n)return null;try{return Math.round((await Ef.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var NO,jO,LO,za,Af,ao,io=j(()=>{Xt();ms();NO=process.env.BOSTRAT_CODEX_SESSIONS||Tf.join(process.env.CODEX_HOME||Tf.join(MO.homedir(),".codex"),"sessions");jO=new Set(["output_text","text"]),LO=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&jO.has(t.type)).map(t=>t.text).join(`
98
+ `).trim():"";za=new Set(["exec_command","shell","exec"]),Af=new Set(["wait","write_stdin"]),ao="Codex ended the turn without a response \u2014 it hit an error the CLI shows only in the terminal (e.g. quota or billing). Check the Terminal tab."});function Ya({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&hb.has(r))return hb.get(r);let o=Number(t)||0;if(o===401)return"auth";if(o===403)return"entitlement";if(o===429)return"rate_limit";if(o===529)return"overloaded";if(o>=500)return"server";let s=String(n||"").toLowerCase();return/overloaded/.test(s)?"overloaded":/rate limit|too many requests|quota|usage limit/.test(s)?"rate_limit":/billing|subscription|not allowed|disabled .* access|upgrade your plan|no credits/.test(s)?"entitlement":/log ?in|authenticat|expired|invalid.*key|unauthorized/.test(s)?"auth":/server|internal error|5\d\d/.test(s)?"server":"other"}function wb(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||Ya({error:t.code,status:t.status,text:e.text}),code:t.code||null,status:t.status||null,requestId:t.requestId||null}}if(e.failed){let t=String(e.text||"");return{cls:t===ao?"other":Ya({text:t}),code:null,status:null,requestId:null}}return null}function gb(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:Ya({text:n}),code:null,status:WO(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function WO(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var k5,hb,dl=j(()=>{io();k5=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),hb=new Map([["oauth_org_not_allowed","entitlement"],["permission_error","entitlement"],["billing_error","entitlement"],["authentication_error","auth"],["oauth_token_expired","auth"],["invalid_api_key","auth"],["rate_limit_error","rate_limit"],["overloaded_error","overloaded"],["server_error","server"],["api_error","server"],["internal_server_error","server"]])});function qO(e,t){return!e||!t?null:Jt(e,t)}function KO(e){return typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
99
+ `).trim():""}function GO(e){if(!Array.isArray(e))return null;let t=e.filter(n=>n&&n.type==="tool_use").map(n=>n.name).filter(Boolean);return t.length?t:null}function VO(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function _f(e){let t=[],n=e?.message?.content;if(!Array.isArray(n))return t;for(let r of n)if(r){if(r.type==="image"&&r.source?.type==="base64"&&r.source.data)t.push({mediaType:r.source.media_type||"image/png",data:r.source.data,toolUseId:null});else if(r.type==="tool_result"&&Array.isArray(r.content))for(let o of r.content)o?.type==="image"&&o.source?.type==="base64"&&o.source.data&&t.push({mediaType:o.source.media_type||"image/png",data:o.source.data,toolUseId:r.tool_use_id||null})}return t}function yb(e,t){if(!e.uuid)return null;let n=_f(e).map((r,o)=>({uuid:e.uuid,index:o,mediaType:r.mediaType,name:r.toolUseId&&t.get(r.toolUseId)||null}));return n.length?n:null}async function If(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await Et(e,t)}catch{return[]}let o=[],s=new Map;for(let a of r.split(`
100
+ `)){let i=a.trim();if(!i||i[0]!=="{")continue;let c;try{c=JSON.parse(i)}catch{continue}if(c.type==="attachment"){let w=c.attachment;w?.type==="queued_command"&&w.commandMode==="task-notification"&&typeof w.prompt=="string"&&w.prompt.trim()&&o.push({role:"user",text:w.prompt.trim(),ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let l=c.message;if(!l)continue;let u=l.role||c.type;if(u!=="user"&&u!=="assistant"||u==="assistant"&&l.model==="<synthetic>"&&!c.isApiErrorMessage)continue;if(u==="assistant"&&Array.isArray(l.content))for(let w of l.content){let g=w?.type==="tool_use"?w.input?.file_path||w.input?.path:null;typeof g=="string"&&zO.test(g)&&s.set(w.id,g.split("/").pop())}if(VO(l.content)){let w=yb(c,s);w&&o.push({role:"assistant",text:"",images:w,ts:c.timestamp?Date.parse(c.timestamp):null,model:null});continue}let f=KO(l.content),d=u==="assistant"?GO(l.content):null,p=u==="user"?yb(c,s):null;if(!f&&!d&&!p)continue;let h=u==="assistant"&&c.isApiErrorMessage?{code:typeof c.error=="string"?c.error:null,status:Number(c.apiErrorStatus)||null,requestId:c.requestId||null,cls:Ya({error:c.error,status:c.apiErrorStatus,text:f})}:null;o.push({role:u,text:f,tools:d||void 0,images:p||void 0,ts:c.timestamp?Date.parse(c.timestamp):null,model:l.model||null,apiError:h||void 0})}return o.slice(-n)}async function bb(e,t,{turns:n=16}={}){let r=qO(e,t);if(!r)return"";let o=await If(r,{limit:n});return o.length?o.map(s=>{let a=s.role==="user"?"User":"Lead agent",i=s.tools?`_(also ran: ${s.tools.join(", ")})_`:"",c=s.images?.length?"(viewed an image)":"(took an action)";return`**${a}:** ${YO(s.text||c,700)} ${i}`.trim()}).join(`
101
+
102
+ `):""}var zO,YO,fl=j(()=>{dl();Xt();zO=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;YO=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});import JO from"node:fs/promises";import{execFile as XO}from"node:child_process";import{promisify as ZO}from"node:util";function Sb(e){Rf=typeof e=="function"?e:null}function Of(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}function Tb({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();!r||kb.has(r)||(kb.add(r),xb=xb.then(()=>eC({sessionName:e,from:t,to:r})).catch(()=>{}))}async function eC({sessionName:e,from:t,to:n}){await re({flow:"codex-update",phase:"start",sessionName:e,from:t,to:n}).catch(()=>{});try{let r=(await $f("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await JO.realpath(r),s=Of(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await $f("npm",["install","-g","@openai/codex"],{env:a,timeout:QO});let i=(await $f(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await re({flow:"codex-update",phase:"done",sessionName:e,from:t,to:n,version:i}).catch(()=>{}),await vb({sessionName:e,from:t,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await re({flow:"codex-update",phase:"failed",sessionName:e,from:t,to:n,error:o}).catch(()=>{}),await vb({sessionName:e,from:t,to:n,status:"failed",error:o})}}async function vb(e){if(Rf)try{await Rf(e)}catch{}}var $f,QO,kb,xb,Rf,pl=j(()=>{dn();$f=ZO(XO),QO=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,kb=new Set,xb=Promise.resolve(),Rf=null});function nC(e,{provider:t,box:n}){let r=String(e).replace(/\r/g,"").split(`
103
+ `);if(!Eb.test(e))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(tC);if(u)o.unshift({n:Number(u[1]),label:u[2]}),s=!0;else{if(s&&r[l].trim()==="")continue;if(s){var a=r[l].trim();break}}}if(o.length<2)return null;let i=o.sort((l,u)=>l.n-u.n);if(i.some((l,u)=>l.n!==u+1))return null;let c=typeof a=="string"&&Eb.test(a)?a:"The agent is asking for approval";return{provider:t,box:n,promptId:`${t}:${c}:${i.map(l=>l.label).join("|")}`.slice(0,200),questions:[{question:c,header:"Approval",multiSelect:!1,options:i.map(l=>({label:l.label,description:""}))}]}}function co(e){let t=String(e??"").replace(/\r/g,""),n=t.split(`
104
+ `);for(let r=n.length-1;r>=0;r--)if(Ib.test(n[r]))return n.slice(r).join(`
105
+ `);return t}function rC(e){let t=String(e).trim();if(!t)return!1;let n=(t.match(/[A-Za-z]/g)||[]).length;return n>=3&&n/t.length>=.5}function oC(e){return/device code/i.test(e)?"works from the device you're reading this on":/sign in with chatgpt/i.test(e)?"opens a browser link on the node itself \u2014 can't finish from another device":""}function sC(e,t=""){let n=co(e);if(Ja.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
106
+ `),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(Ab);if(!u)continue;s<0&&(s=l);let f="";for(let d=l+1;d<Math.min(l+3,r.length);d++){let p=r[d].trim();if(p){if(Ab.test(r[d])||/^Press enter/.test(p))break;f=p;break}}o.push({n:Number(u[2]),cursor:!!u[1],label:u[3].trim(),desc:f})}let a=o.sort((l,u)=>l.n-u.n);if(a.length<2||a.some((l,u)=>l.n!==u+1)||!a.some(l=>/Sign in with ChatGPT/.test(l.label)))return null;let i=[];for(let l=0;l<s;l++){let u=r[l].trim();u&&!Ib.test(r[l])&&rC(u)&&i.push(u)}let c=i.join(" ").slice(0,400)||"Codex isn't signed in on this box \u2014 choose a sign-in method";return{provider:"codex",box:t,multiSelect:!1,cursorIndex:Math.max(0,a.findIndex(l=>l.cursor)),answerMode:"keys",promptId:`codex:signin:${a.map(l=>l.label).join("|")}`.slice(0,200),questions:[{question:c,header:"Sign in",multiSelect:!1,options:a.map(l=>{let u=oC(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function cC(e,t=""){let n=co(e);if(Ja.test(n)||!aC.test(n))return null;let r=n.trimEnd().split(`
107
+ `).pop()||"";return iC.test(r)?{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",promptId:"codex:signin-complete",questions:[{question:"Codex successfully signed in and is waiting to open the session.",header:"Signed in",multiSelect:!1,options:[{label:"Continue",description:""}]}]}:null}function uC(e,t=""){let n=co(e);if(Ja.test(n)||!_b.test(n))return null;let r=n.split(`
108
+ `),o=r.findIndex(i=>_b.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(lC);if(c){s=c[1];break}}if(!s)return null;let a=(n.match(/https:\/\/\S+/)||[])[0]||"https://auth.openai.com/codex/device";return{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:`codex:device-code:${s}`,questions:[{question:`Codex is waiting for you to finish signing in: open ${a} and enter code ${s} (expires in 15 minutes). The code goes straight to OpenAI \u2014 bostrat never sees your login. This card clears once OpenAI confirms.`,header:"Sign in",multiSelect:!1,options:[{label:"Cancel sign-in",description:"Go back to the sign-in options"}]}]}}function dC(e,t=""){let n=co(e);return Ja.test(n)||!/open the following link to authenticate/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:"codex:signin-browser",questions:[{question:"Codex started its browser sign-in, which opens on the box itself and can't complete from another device. Go back and choose \u201CSign in with Device Code\u201D instead.",header:"Sign in",multiSelect:!1,options:[{label:"Go back to sign-in options",description:""}]}]}}function fC(e,t=""){let n=co(e);return Ja.test(n)||!/Paste or type your API key/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:"codex:signin-apikey",questions:[{question:"Codex is asking for an OpenAI API key. For safety a key can only be typed in the Terminal tab, never through chat. To use your ChatGPT subscription instead, go back and pick a sign-in option.",header:"Sign in",multiSelect:!1,options:[{label:"Go back to sign-in options",description:""}]}]}}function pC(e,t=""){let n=String(e);if(!/Press any key to log in/.test(n)||Cf.test(n))return null;let r=n.replace(/\r/g,"").split(`
109
+ `).map(a=>a.trim()),o=r.findIndex(a=>/Press any key to log in/.test(a)),s=r.slice(0,o<0?r.length:o).filter(a=>a&&!/^Cursor Agent$/i.test(a)&&!/^v?\d{4}\.\d{2}\.\d{2}/.test(a)).join(" ");return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",promptId:"cursor:signin-start",questions:[{question:(s?`${s} `:"")+"Cursor isn't signed in on this box \u2014 start the sign-in to get a login link you can open from any device.",header:"Sign in",multiSelect:!1,options:[{label:"Start sign-in",description:"Shows a login link (and a QR option) \u2014 your login goes to cursor.com, never through bostrat"}]}]}}function hC(e,t=""){let n=String(e);if(!mC.test(n)||Cf.test(n))return null;let r=n.replace(/\r/g,"").split(`
110
+ `),o="",s=r.findIndex(a=>/https:\/\//.test(a));if(s>=0){o=r[s].slice(r[s].indexOf("https://")).trim();for(let a=s+1;a<r.length;a++){let i=r[a].trim();if(!i||!/^[A-Za-z0-9~%&=?/_.-]+$/.test(i))break;o+=i}}return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:`cursor:signin-link:${(o.match(/[?&]challenge=([\w-]+)/)||[])[1]?.slice(0,16)||o.slice(-24)||"pending"}`,questions:[{question:o?`Cursor is waiting for you to finish signing in: open ${o} on any device and log in. Your login goes straight to cursor.com \u2014 bostrat never sees it. This card clears once sign-in completes.`:"Cursor is waiting for you to finish signing in \u2014 open the login link shown in the Terminal tab. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function wC(e,t=""){let n=String(e);return!/Scan this QR code to log in/.test(n)||Cf.test(n)?null:{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:"cursor:signin-qr",questions:[{question:"Cursor is showing a QR sign-in code in the Terminal tab \u2014 scan it from another device to log in. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function $b(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=cC(t,n)||uC(t,n)||dC(t,n)||fC(t,n)||sC(t,n);if(r)return r}if(e==="cursor"){let r=hC(t,n)||wC(t,n)||pC(t,n);if(r)return r}return nC(t,{provider:e,box:n})}function Rb(e,t){let n=Array.isArray(t?.[0])?t[0]:[],o=(Number.isInteger(n[0])&&n[0]>=0?n[0]:0)+1;return String(o)}var tC,Eb,Ja,Ib,Ab,aC,iC,_b,lC,Cf,mC,ml=j(()=>{tC=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,Eb=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;Ja=/(^|\n)\s*›/,Ib=/^\s*Welcome to Codex\b/;Ab=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;aC=/Successfully logged in\./,iC=/^\s*Press Enter to continue\.\s*$/;_b=/Enter this one-time code/,lC=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;Cf=/Run Everything|Add a follow-up|Plan, search, build anything/;mC=/click this link to log in|Signing in with the browser/});function kC(e){let t=String(e||"").replace(/\r/g,"").split(`
111
+ `),n=-1;for(let s=t.length-1;s>=0;s--)if(t[s].trim()){n=s;break}if(n<0)return!1;let r=t[n];if(yC.test(r)||bC.test(r)){for(let s=n-1;s>=0&&n-s<=64;s--)if(/^\s*›/.test(t[s]))return!0}return/esc to interrupt|\bWorking \(/.test(String(e||""))}function EC(e){let t=String(e||"");if(!qe.codex.block.test(t))return null;let n=co(t);if(!qe.codex.block.test(n))return null;let r=n.match(TC);return{from:r?.[1]||null,to:r?.[2]||null}}function fn(e){return new Promise(t=>setTimeout(t,e))}function Mf(e,t){let n=Date.now(),r=AC();for(let[s,a]of wl)n-a>=r&&wl.delete(s);let o=`${e}::${t}`;return wl.has(o)?!1:(wl.set(o,n),!0)}function Nb(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
112
+ `),r=-1;for(let o=n.length-1;o>=0;o--)if(Mb.test(n[o])){r=o;break}return r<0?t:n.slice(r+1).join(`
113
+ `)}function IC(e){let t=0;for(let n of String(e).split(`
114
+ `))Mb.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function Nf(e,t){let n=qe[e];if(!n?.busy)return{state:"idle",reason:null};if(Df(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(Nb(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=IC(t);return e==="claude"&&r>0&&r<_C?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function Pf(e,t){return Nf(e,t).state}function Pb(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
115
+ `).slice(-RC).join(`
116
+ `);return $C.test(n)}function ws(e,t){return Pf(e,t)==="busy"}function gl(e,t){return Pf(e,t)!=="idle"}function gs(e,t){let n=qe[e];return n?.up?n.up.test(t):!0}function OC(e,t){let n=qe[e];return n?Df(e,t)?!1:n.up.test(t)&&Pf(e,t)==="idle":!0}function Df(e,t){let n=qe[e];return n?n.auth?.test(t)&&!n.up.test(t)?!0:n.block?.test(t)?e==="codex"?!0:!n.up.test(t):!1:!1}function Bf(e,t){let n=String(t||"").trim();if(!n)return e;let r=String(e||"").split(`
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 Db(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function Ob(e){let t=new Error(`${e} isn't running in this box \u2014 its pane is sitting at a bare shell (the launch command was likely swallowed at shell startup, or the CLI exited). Relaunch it from the Terminal tab, or stop and reopen the box, then send again.`);return t.code="cli-not-running",t}async function Cb(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null,onReady:s}={}){let a=Date.now()+n,i=0,c=null;for(await oo(e).catch(()=>{});;){let l=Bf(await Ce(e),o);if(OC(t,l)){await s?.(),await fn(hs);return}if(qe[t]?.up&&!qe[t].up.test(l))if(await Mn(e)){if(c??=Date.now(),Date.now()-c>=Wa()){let u=Ob(t);throw re({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,idleMs:Date.now()-c,error:u.message}).catch(()=>{}),u}}else c=null;else c=null;if(r&&t==="claude"&&SC.test(l)&&!qe.claude.up.test(l)){re({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{});return}if(t==="codex"&&vC.test(l)&&!qe.codex.up.test(l)&&i<3){if(!Mf(e,"codex-trust")){await fn(hl);continue}i+=1,await re({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await Ze(e,"",{enter:!0,kind:"codex-trust-accept"}),await fn(hs);continue}if(t==="cursor"&&xC.test(l)&&!qe.cursor.up.test(l)&&i<3){if(!Mf(e,"cursor-trust")){await fn(hl);continue}i+=1,await re({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await Ze(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await fn(hs);continue}if(t==="codex"&&i<3){let u=EC(l);if(u){if(!Mf(e,`codex-update:${u.from}->${u.to}`)){await fn(hl);continue}i+=1,await re({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${u.from} -> ${u.to}`}).catch(()=>{}),await Ze(e,"3",{enter:!1,kind:"codex-update-skip"}),Tb({sessionName:e,from:u.from,to:u.to}),await fn(hs);continue}}if(Date.now()>a){if(Df(t,l)){let u=`${t} is blocked on an interactive prompt`;throw t==="codex"?u=qe.codex.auth.test(l)?"codex isn't signed in on this box \u2014 answer the Sign in card in chat (Device Code works from any device) or finish signing in from the Terminal tab, then send again":"codex is stuck on its update prompt (auto-skip didn't clear it) \u2014 open the terminal and choose Skip, then send again":t==="cursor"&&qe.cursor.auth.test(l)?u="cursor isn't signed in on this box \u2014 answer the Sign in card in chat (the login link works from any device) or finish signing in from the Terminal tab, then send again":t==="claude"&&qe.claude.auth.test(l)?u="claude isn't signed in on this box \u2014 answer the setup cards in chat (or finish signing in from the Terminal tab), then send again":t==="claude"&&qe.claude.block.test(l)&&(u='claude is waiting on its "Press Enter to continue" screen \u2014 answer the Continue card in chat (or press Enter in the Terminal tab), then send again'),re({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u}).catch(()=>{}),new Error(u)}if(await Mn(e)){let u=Ob(t);throw re({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u.message}).catch(()=>{}),u}console.warn(`[agent-ready] ${t} readiness unconfirmed in ${e} after ${n}ms \u2014 driving the box anyway.`),re({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,paneBlocked:!!qe[t]?.block?.test(l),paneUp:!!qe[t]?.up?.test(l),paneBusy:!!qe[t]?.busy?.test(Nb(qe[t],l))}).catch(()=>{}),await fn(hs);return}await fn(hl)}}function jf({agent:e,agentCmd:t}={}){let n=t?dr(t):dr(e||"");return{label:n,realClaude:t?ro(t):n==="claude",realCodex:t?/codex/.test(t)&&!/fake-codex|fake-lead/.test(t):n==="codex",realCursor:t?/cursor/.test(t)&&!/fake-cursor|fake-box/.test(t):n==="cursor"}}function Bb({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=jf({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function Xa({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}={}){let{realCodex:s,realCursor:a}=jf({agent:n,agentCmd:r});return!t||!s&&!a?null:hr({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).catch(()=>{})}async function hr({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=gC(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:f,realCursor:d}=jf({agent:r,agentCmd:o});if(u&&e&&await or(e),f&&e&&await Jo(e),d&&e&&await Xo(e),(u||f||d)&&n){await Cb(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c});return}let p=qe[r]?r:qe[l]?l:null;if(process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&p){await Cb(n,p,s,{launchEcho:i});return}await fn(hs)}var gC,hl,hs,yC,bC,qe,xC,vC,SC,TC,AC,wl,_C,Mb,$C,RC,Za=j(()=>{lt();Ta();Dc();Bc();pl();ml();dn();gC=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,hl=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,hs=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,yC=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,bC=/^\s*tab to queue message\b/;qe={claude:{up:/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/,busy:/esc to interrupt/,busyScope:"footer",busyAlt:/^[·✢✳✶✻✽✺✹✸✷]\s+[A-Z][\w '’-]{1,40}…/m,auth:/Select login method:|Paste code here if prompted|OAuth error:|Choose the text style that looks best|Quick safety check: Is this a project you created/,block:/Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/m},codex:{up:{test:kC},busy:/esc to interrupt|\bWorking \(/,block:/Update available![\s\S]*\b(?:Update now|Skip until next version)\b[\s\S]*Press enter to continue/,auth:/Sign in with ChatGPT[\s\S]*Press enter to continue|Finish signing in via your browser|Paste or type your API key|Successfully logged in\.[\s\S]*Press Enter to continue\./},cursor:{up:/Run Everything|Add a follow-up|Plan, search, build anything/,busy:/ctrl\+c to stop|^\s*[⠁-⣿]+\s+\S/m,block:/Workspace Trust Required|Trust this workspace|\[a\]\s*Trust|Trusting workspace/,auth:/Press any key to log in|click this link to log in|Scan this QR code to log in|Signing in with the browser/}},xC=/Trust this workspace|\[a\]\s*Trust/,vC=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,SC=/Resume from summary/i,TC=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;AC=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,wl=new Map;_C=68,Mb=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;$C=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,RC=15});function PC(e){return typeof e!="string"||!e?!1:e.includes(`
119
+ `)?!0:Buffer.byteLength(e,"utf8")>=NC}function pn(e,t){return e==="codex"?{enter:!0,submitDelayMs:CC,...PC(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:MC}:{enter:!0}}var CC,MC,NC,Qa=j(()=>{CC=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),MC=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),NC=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function ei(e,t){if(e==="codex")return FC(t);if(e!=="claude")return null;let n=String(t).replace(/\r/g,"").split(`
120
+ `).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(jb.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(jb.test(n[c])){o=c;break}if(o<0)return null;let s=n.slice(o+1,r);if(!s.length)return null;let a=s[0].match(DC);if(!a)return null;let i=[a[1].trim(),...s.slice(1).map(c=>c.trim())].filter(Boolean);return i.length?i.join(" "):null}function FC(e){let t=String(e).replace(/\r/g,"").split(`
121
+ `).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){(BC.test(t[o])||jC.test(t[o]))&&!Lf.test(t[o])?n=o:Lf.test(t[o])&&/\[Pasted Content \d+ chars\]/.test(t[o])&&(n=o+1);break}if(n<=0)return null;let r=[];for(let o=n-1;o>=0&&n-o<=60;o--){let s=t[o],a=s.match(Lf);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(LC.test(s))return null;r.unshift(s)}return null}function Ff(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=We(n.replace(UC,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!We(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function We(e){return String(e||"").replace(/\s+/g," ").trim()}function Lb(e,t,{slackMs:n=2e4}={}){let r=We(t?.text);if(!r||typeof t?.at!="number")return!1;let o=Array.isArray(e)?e:[],s=o.findIndex(a=>a?.role==="user"&&typeof a.ts=="number"&&a.ts>=t.at-n&&We(a.text).includes(r));return s>=0&&s<o.length-1}function Fb(e,t,n,{busy:r=!1}={}){let o=ei(e,n);return o&&yl(t,o)||o&&e==="codex"&&Ff(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function yl(e,t){let n=We(e),r=We(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var jb,DC,Lf,BC,jC,LC,UC,bl=j(()=>{jb=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,DC=/^❯[  ]?(.*)$/,Lf=/^\s*›[  ]?(.*)$/,BC=/\S+ · \S/,jC=/^\s*(?:\? for shortcuts|tab to queue message)\b/,LC=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;UC=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function ni({sessionName:e,agent:t,agentCmd:n=null,text:r,trackId:o=null,flow:s="say"},a={}){if(!HC.has(t))return!0;let i=a.waitForUp??Bb({agent:t,agentCmd:n}),c=a.capture||(R=>Ce(R,{lines:Xe})),l=a.pressEnter||(R=>Le(R,["Enter"],{kind:"submit-retry"})),u=a.sleep||GC,f=a.now||Date.now,d=a.log||(R=>re(R).catch(()=>{})),p=a.maxMs??KC(),h=f()+p,w={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},g=0,k=0,S=0,E=!1;for(await u(ti[0]);;){let R=await c(e).catch(()=>""),B=gs(t,R),T=ws(t,R),_=Fb(t,r,R,{busy:T});if(_==="submitted")return!0;if(i&&(!B||_==="stuck"&&T)){if(f()>=h)return _==="stuck"?(d({...w,phase:"submit-failed",reason:"stuck-at-deadline",retries:g}),!1):(d({...w,phase:"submit-unverified",reason:E?"cli-down":"cli-never-up",retries:g,waitedMs:p}),!0);await u(WC);continue}if(E=!0,_==="stuck"){if(g>=qC)return d({...w,phase:"submit-failed",retries:g}),!1;g+=1,k=0,S=0,await l(e),d({...w,phase:"submit-retry",attempt:g}),await u(ti[0]);continue}if(k+=1,k>=ti.length||f()>=h)return!0;S+=1,await u(ti[Math.min(S,ti.length-1)])}}var HC,ti,WC,qC,KC,GC,Uf=j(()=>{lt();Za();bl();dn();HC=new Set(["claude","codex"]),ti=[250,450,700],WC=500,qC=2,KC=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},GC=e=>new Promise(t=>setTimeout(t,e))});function Pn(e){let t=String(e||"").toLowerCase();if(!t.trim())return null;let n=null;for(let r of VC){let o=0;for(let s of zC[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function Ub(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))YC.has(r)&&(t+=o||0),JC.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function ri(e){return String(e||"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[-_/]+/g," ")}var VC,zC,YC,JC,kl=j(()=>{VC=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],zC={research:[/\bresearch\b/,/\binvestigat/,/\bverif/,/\bcompar(e|ing|ison)/,/\bcompetit/,/\bdeep[ -]?dive\b/,/\banaly[sz]/,/\bassess/,/\bdiligence\b/,/\bmarket\b/,/\bstrateg/,/\broadmap\b/,/\bnorth star/,/\bwhat('| i)?s the (state|status)\b/,/\bstatus of\b/,/\bexplore\b/,/\bfeasib/,/\bevaluat/,/\bscope out\b/,/\btalk through\b/],"bug-fix":[/\bfix(e[sd]|ing)?\b/,/\bbugs?\b/,/\bbroken\b/,/\bregression\b/,/\bcrash/,/\bincident\b/,/\bdebug/,/\bdoesn'?t (work|render|load|start)/,/\bnot working\b/,/\btroubleshoot/,/\bflaky?\b/,/\brepro(duce|duction)?\b/,/\brace condition\b/,/\bleak\b/],"feature-build":[/\bimplement/,/\bbuild(ing)?\b/,/\badd(ing)?\b/,/\bcreate\b/,/\bwire (it |them )?(up|in)\b/,/\bship(ping)?\b/,/\bintegrat/,/\bsupport for\b/,/\bfeature\b/,/\bendpoint\b/,/\badapter\b/,/\bprototype\b/],design:[/\bdesign/,/\bui\b/,/\bux\b/,/\bstyl(e|es|ing)\b/,/\bcss\b/,/\blayout\b/,/\bmock-?up/,/\brender(ing|s)?\b/,/\bpolish/,/\btheme\b/,/\bfonts?\b/,/\bresponsive\b/,/\banimation/,/\bvisual/,/\bpopover\b/],orchestration:[/\bhand[ -]?(off|over)/,/\bhand (it|the lead|this) (over|off)\b/,/\bdelegat/,/\bsubtask/,/\bmerge[ -]?back\b/,/\borchestrat/,/\b(switch|change) (the )?model\b/,/\bmodel switch/],"docs-writing":[/\bdocs?\b/,/\bdocument/,/\bmemo\b/,/\breadme\b/,/\bwrite-?up\b/,/\bchangelog\b/,/\bclaude\.md\b/,/\bblog/,/\bproofread/,/\bcopy(edit|writ)/],"ops-infra":[/\bdeploy/,/\bsystemd\b/,/\bdaemon\b/,/\btmux\b/,/\bdns\b/,/\bwireguard\b/,/\brestart/,/\bnginx\b/,/\bprovision/,/\binstall/,/\bupgrade/,/\bcron\b/,/\bbackups?\b/,/\bcertificat/,/\bssh\b/,/\bsecrets?\b/]};YC=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),JC=new Set(["Edit","Write","MultiEdit","NotebookEdit"])});function Kb(e){let t=ri(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||XC.has(r)||n.push(r);return n}function ZC(e){let t=[];for(let n of e||[]){let r=n.payload||{},o=String(r.text||"").trim();if(n.type==="turn.user"){if(n.source==="hook"||!o)continue;t.push(qb(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(qb(n,"assistant",o))}}return t}function qb(e,t,n){let r=Pn(n);return{id:e.id,seq:e.seq,ts:e.payload?.ts??e.ts,role:t,boxId:e.boxId??null,provider:e.provider??null,text:n,tags:r?[r.category]:[]}}function oi(e){let t=ZC(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=Kb(a.text);r[i]=c.length,o+=c.length;let l=new Map;for(let u of c)l.set(u,(l.get(u)||0)+1);for(let[u,f]of l){let d=n.get(u);d||n.set(u,d=new Map),d.set(i,f)}});let s=t.length;return{chunks:t,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function xl(e,t,n={}){let{k:r=8,role:o=null,tag:s=null,boxId:a=null}=n;if(!e||!e.N)return[];let i=[...new Set(Kb(t))];if(!i.length)return[];let c=new Map;for(let u of i){let f=e.postings.get(u);if(!f)continue;let d=f.size,p=Math.log(1+(e.N-d+.5)/(d+.5));for(let[h,w]of f){let g=e.lengths[h],k=w+Hb*(1-Wb+Wb*(g/(e.avgdl||1))),S=p*(w*(Hb+1)/k);c.set(h,(c.get(h)||0)+S)}}let l=[];for(let[u,f]of c){let d=e.chunks[u];o&&d.role!==o||s&&!d.tags.includes(s)||a&&d.boxId!==a||l.push({chunk:d,score:f})}return l.sort((u,f)=>f.score-u.score||f.chunk.seq-u.chunk.seq),l.slice(0,r)}var Hb,Wb,XC,Hf=j(()=>{kl();Hb=1.5,Wb=.75,XC=new Set("a an and are as at be been but by for from had has have he her his i if in into is it its of on or our so than that the their them then there these they this those to was were will with would you your we".split(" "))});import vl from"node:fs/promises";import Gb from"node:path";async function QC(e){let t=Gb.join(e,".bostrat","events"),n;try{n=await vl.readdir(t)}catch{return oi([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await vl.readFile(Gb.join(t,o),"utf8");for(let a of s.split(`
122
+ `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return oi(r)}function eM(e){let t=String(e||""),n=a=>{let i=t.match(a);return i?i[1].trim():""},r=n(/#+\s*Objective\s*\n([\s\S]*?)(?:\n#+\s|$)/i),o=n(/#+\s*Next steps?[^\n]*\n([\s\S]*?)(?:\n#+\s|$)/i);return`${r}
123
+ ${o}`.trim()||t.slice(0,2e3)}function tM(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=xl(e,t,{k:n*2+4}),a=[],i=0;for(let{chunk:c}of s){if(o&&o(c))continue;let l=c.role==="user"?"Operator":`Agent${c.provider?` (${c.provider})`:""}`,u=c.text.trim(),f=u.length>800?u.slice(0,800)+"\u2026":u,d=`- **${l}:** ${f}`;if(i+d.length>r||(a.push(d),i+=d.length,a.length>=n))break}return a.length?["",`## ${Vb}, not a summary)`,"_Auto-selected from the Track's event log by lexical relevance to the Objective / Next steps. Verbatim excerpts, not re-summarization (docs/memory-segmentation-indexing-scope.md \xA71.3)._","",...a,""].join(`
124
+ `):""}async function zb(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await vl.readFile(t,"utf8");if(a.includes(Vb))return{appended:!1,reason:"already-enriched"};let i=await QC(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=tM(i,eM(a),{k:r,maxChars:o,exclude:s});return c?(await vl.appendFile(t,`
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 Vb,Yb=j(()=>{Hf();Vb="Relevant prior discussion (verbatim, retrieved"});function iM(e){return nM.test(String(e||"").trimStart())}function Zb(e){let t=String(e||"");if(!iM(t.trimStart()))return null;let n=t.replace(rM,"").trim(),r=cM(n),o=[];for(let u of sM){let f=u.from.map(d=>ys(r.get(d))).find(d=>d&&!Jb(d));f&&o.push({h:u.h,text:si(f,oM)})}let s=ys(r.get("Current Work"))||ys(r.get("Primary Request and Intent"))||uM(n),a=Tl(s),i=si(Sl(Kf(a[0]||"")),aM)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(si(Sl(Kf(l)),qf));for(let u of["Pending Tasks","Optional Next Step"]){let f=Tl(ys(r.get(u)))[0]||"";if(!(!f||Jb(f))){c.push(si(`Left to do: ${Sl(Kf(f))}`,qf));break}}if(!c.length){let u=Tl(ys(r.get("Problem Solving"))||"")[0];u&&c.push(si(Sl(u),qf))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function cM(e){let t=new Map,n=[];Wf.lastIndex=0;for(let r=Wf.exec(e);r;r=Wf.exec(e))n.push({name:lM(r[1]),start:r.index,end:r.index+r[0].length});for(let r=0;r<n.length;r++){let o=n[r+1]?.start??e.length;t.has(n[r].name)||t.set(n[r].name,e.slice(n[r].end,o).trim())}return t}function lM(e){return Xb.find(n=>n.toLowerCase()===e.toLowerCase())||e}function ys(e){return e?String(e).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
127
+ `).map(t=>t.replace(/^[ \t]*(?:[-*•]|\d+[.)]|[a-z][.)])[ \t]+/i,"").trim()).filter(t=>t&&!/^#{1,6}[ \t]/.test(t)).join(" ").replace(/\*\*(.+?)\*\*/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\s+/g," ").trim():""}function uM(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return ys(t.split(/\n{2,}/).slice(0,2).join(" "))}function Tl(e){let t=String(e||"").trim();if(!t)return[];let r=t.replace(/\b([A-Za-z0-9_-]+)\.(js|ts|tsx|mjs|json|md|css|jsonl|sh|yml|yaml|py|html)\b/g,"$1<DOT>$2").replace(/\b(e\.g|i\.e|etc|vs|approx|no|fig|Dr|Mr|Ms|St)\./gi,"$1<DOT>").split(/(?<=[.!?])["')\]]?\s+(?=[A-Z"“'(\[]|\d)/).map(s=>s.replace(/<DOT>/g,".").trim()).filter(Boolean),o=[];for(let s of r){let a=o[o.length-1];a&&(a.match(/["“”]/g)?.length??0)%2===1?o[o.length-1]=`${a} ${s}`:o.push(s)}return o}function Kf(e){return String(e||"").replace(/^(?:Immediately before (?:this|the) summary(?: request)?[,:]?\s*|At the (?:time|point) of (?:this )?compaction[,:]?\s*|Currently[,:]?\s*|The (?:most recent|immediately preceding|current) work (?:was|is)\s*)/i,"").replace(/^(?:I(?:'m|'d| am| was| had| have)?\s+(?:currently\s+|just\s+)?(?:been\s+)?(?:working on|in the middle of|completing|finishing)\s+|The user(?:'s)?\s+(?:most recent\s+)?(?:request|ask) (?:was|is)\s+(?:to\s+)?)/i,"").replace(/^I(?:'m|'d| am| was| had| have)?\s+(?:just\s+|then\s+)?(?=(?:[a-z]+(?:ed|ing)|ran|wrote|built|made|began|found|left|sent|took|went|did|got|kept|held|brought|caught|chose|came|saw|said|gave|told|set|put|read)\b)/,"").replace(/^["“]|["”]$/g,"").replace(/^(\w)/,t=>t.toUpperCase()).trim()}function Sl(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function Jb(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function si(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=Tl(n),o="";for(let i of r){let c=o?`${o} ${i}`:i;if(c.length>t)break;o=c}if(o.length>=Math.min(60,t*.4))return o;let s=n.slice(0,t),a=s.lastIndexOf(" ");return`${(a>t*.6?s.slice(0,a):s).replace(/[,;:.\s]+$/,"")}\u2026`}var nM,Xb,Wf,rM,oM,sM,aM,qf,Qb=j(()=>{nM=/^This session is being continued from a previous conversation that ran out of context\./,Xb=["Primary Request and Intent","Key Technical Concepts","Files and Code Sections","Errors and Fixes","Problem Solving","All user messages","Pending Tasks","Current Work","Optional Next Step"],Wf=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${Xb.join("|")})[:*\t ]*$`,"gim"),rM=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,oM=420,sM=[{h:"What we were doing",from:["Primary Request and Intent"]},{h:"Key decisions",from:["Key Technical Concepts"]},{h:"Where it got to",from:["Current Work","Problem Solving"]},{h:"Left to do",from:["Pending Tasks","Optional Next Step"]}],aM=116,qf=168});function tk(e){return Gf.has(String(e||"").replace(/^\//,"").toLowerCase())}function El(e){let t=String(e||"").trim();if(!t)return null;let n=Zb(t);if(n)return n;let r=t.match(dM);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(fM);if(o)return{kind:"skill",name:o[1]};let s=t.match(pM);if(s){let i=s[1].toLowerCase();return Gf.has(i)?{kind:"suppress"}:{kind:"command",command:`/${i}`}}let a=t.match(SM);if(a&&Gf.has(a[1].toLowerCase()))return{kind:"suppress"};if(mM.test(t))return{kind:"suppress"};if(wM.test(t))return{kind:"suppress"};if(hM.test(t))return{kind:"suppress"};if(gM.test(t)){let i=l=>TM(t.match(l)?.[1].trim()||"")||null,c=i(vM);return{kind:"task",summary:i(yM)||"",taskId:i(bM),toolUseId:i(kM),status:i(xM)?.toLowerCase()||null,resultHead:c?c.length>ek?`${c.slice(0,ek).trimEnd()}\u2026`:c:null}}return null}function TM(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function nk(e){return e?.kind==="skill"?`Ran the ${e.name} skill`:e?.kind==="command"?`Ran ${e.command}`:e?.kind==="task"?e.summary||"A background task finished":e?.kind==="resume-summary"?e.title?`Context resumed from summary: ${e.title}`:"Context resumed from summary":""}function rk(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var dM,fM,pM,mM,hM,wM,gM,yM,bM,kM,xM,vM,ek,Gf,SM,Vf=j(()=>{Qb();dM=/^Base directory for this skill:\s*(\S+)/,fM=/^Run the "([^"]+)" workflow\./,pM=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,mM=/^<local-command-(?:stdout|caveat)>/i,hM=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,wM=/^Continue from where you left off\.$/,gM=/^<task-notification>/i,yM=/<summary>([\s\S]*?)<\/summary>/i,bM=/<task-id>([\s\S]*?)<\/task-id>/i,kM=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,xM=/<status>([\s\S]*?)<\/status>/i,vM=/<result>([\s\S]*?)(?:<\/result>|$)/i,ek=600,Gf=new Set(["model","clear","compact","login","exit","quit"]);SM=/^\/([a-z0-9:_-]+)$/i});import EM from"node:crypto";function $M(e){let t=Array.isArray(e)?e:Array.isArray(e?.questions)?e.questions:null;if(!t||!t.length)return null;let n=[];for(let r of t.slice(0,sk)){let o=ai(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,AM)){let c=ai(i?.label);if(!c)return null;let l=ai(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<_M)return null;n.push({question:o,header:ai(r?.header).slice(0,IM),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function zf(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;ok.lastIndex=0;let t=null;for(let o;o=ok.exec(e);)t=o;if(!t||t.index+t[0].length<e.trimEnd().length)return null;let n;try{n=JSON.parse(t[2])}catch{return null}let r=$M(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function Yf(e,t,n){let r=EM.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function Jf(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=sk}={}){if(!Array.isArray(e)||!t||!n)return null;let s=null;for(let l=e.length-1;l>=0;l--){let u=e[l];if(u?.kind==="prompt")return null;if(u?.kind==="message"){if(u.role!=="assistant")return null;s=u;break}}if(!s||s.box!==t||s.agent!==n)return null;let a=s.ask?.questions||zf(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=Yf(n,s.sourceId||s.id,a);return typeof r=="function"&&r(c)?null:{provider:n,box:t,promptId:c,groupId:c,answerMode:"say",source:"transcript",multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function ak(e,t,n){let r=[];(e?.questions||[]).forEach((a,i)=>{let c=(t?.[i]||[]).map(l=>a.options?.[l]?.label).filter(Boolean);c.length&&r.push({name:a.header||a.question,picks:c.join(", ")})});let o=ai(n),s;return r.length?r.length===1?s=`${r[0].name}: ${r[0].picks}`:s=`Answers:
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 sk,AM,_M,IM,ok,ai,ik,Xf=j(()=>{sk=4,AM=4,_M=2,IM=24,ok=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,ai=e=>typeof e=="string"?e.trim():"";ik=`
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 RM(e){return{id:e.id,kind:"prompt",groupId:e.groupId,provider:e.provider,box:e.box,agent:e.provider,questionTotal:e.questions.length,answeredVia:"chat",questions:e.questions.map((t,n)=>({index:n,header:t.header||"",question:t.question,multiSelect:!!t.multiSelect,chosen:[]})),ts:e.ts}}function CM(e,t,n){let r=ck(n),o=e.has(r)?r:null;if(!o&&n.number!=null)for(let[i,c]of e){if(Number(c.number)!==Number(n.number))continue;let l=!!(n.url&&c.url&&n.url===c.url),u=!c.repo&&!!n.repo||!!c.repo&&!n.repo;if(l||u&&(!c.url||!n.url||c.url===n.url)){o=i;break}}let s=n.repo||!o?r:o,a=o?e.get(o):e.get(s);if(o&&o!==s){e.delete(o);let i=t.get(o);if(t.delete(o),i?.length){let c=t.get(s)??[];t.set(s,c.concat(i))}}return e.set(s,{number:n.number,url:n.url??a?.url??null,title:n.title??a?.title??null,repo:n.repo??a?.repo??null,branch:n.branch??a?.branch??null}),s}function wr(e){let t=[],n=new Set,r=new Set,o=new Map,s=new Map,a=new Set,i=new Map,c=new Set,l=new Map,u=new Map,f=(y,m)=>{u.set(y,m),t.push(m)},d=y=>{let m=u.get(y);m&&(m.retired=!0)},p=/^Agent "([\s\S]+)" finished$/,h=new Map;for(let y of e||[]){if(y.type!=="tool.called"||y.source!=="transcript")continue;let m=String(y.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(m))for(let b of m.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let M=b[0].split("/").pop().toLowerCase();h.has(M)||h.set(M,[]),h.get(M).push(y.payload?.ts??y.ts)}}let w=3*6e4,g=20*6e4,k=(y,m)=>!!(y?.name&&h.get(String(y.name).toLowerCase()))?.some(M=>M>=m-w&&M<=m+g);for(let y of e||[])if(y.type==="turn.retracted"){r.add(`${y.boxId}|${y.payload?.saidTs}`);let m=We(y.payload?.text);m&&(o.has(y.boxId)||o.set(y.boxId,[]),o.get(y.boxId).push(m))}else if(y.type==="turn.user"&&y.source==="orchestrator"){let m=We(y.payload?.text);m&&(s.has(y.boxId)||s.set(y.boxId,new Set),s.get(y.boxId).add(m))}else if(y.type==="job.started"&&y.payload?.id)a.add(y.payload.id),(y.payload.kind||"agent")==="agent"&&y.payload.name&&c.add(y.payload.name);else if(y.type==="turn.user"&&y.payload?.note?.kind==="task"){let m=y.payload.note,b={status:m.status||null,summary:m.summary||null,resultHead:m.resultHead??null,ts:fe(y)};m.toolUseId&&i.set(m.toolUseId,b);let M=String(m.summary||"").match(p);M&&l.set(M[1],b)}let S=new Map,E=new Map,R=null,B=new Map,T=new Map,_=new Map,O=new Map,I=new Map,U=new Map,H=new Map,ae=new Map,X=new Map,C=new Map,Q=new Map,ve=new Map,W=new Map,be=new Map,se=new Map,pe=[],ie=y=>pe.push(y),L=y=>{if(!pe.length)return;let m=fe(y);for(let b of pe){if(b.status!=="open"||b.box&&b.box!==y.boxId||(b.ts??0)>m)continue;let M=t.indexOf(b);M>=0&&t.splice(M,1),b.ts=m,t.push(b)}},ce=new Map,ue=new Map,Ae=new Map,_e=new Map,xt=new Map,je=new Map,A=()=>{for(let y of je.values())y.questions.length&&t.push(y);je.clear()},G=null,Ge=6e4,_t=new Map,at=(y,m)=>{let b=o.get(y);if(!b?.length)return!1;let M=We(m),ne=s.get(y);return b.some(de=>{if(!M.startsWith(de))return!1;let De=We(M.slice(de.length));return!!De&&!!ne?.has(De)})};for(let y of e||[]){let m=y.payload||{};switch(y.type){case"turn.user":{if(y.source==="hook"||(pe.length=0,!String(m.text||"").trim()&&!m.images?.length&&!m.attachments?.length))break;{let b=m.note||El(m.text);if(b){if(b.kind==="task"){if(b.toolUseId&&a.has(b.toolUseId))break;let M=String(b.summary||"").match(p);if(!b.toolUseId&&M&&c.has(M[1]))break}if(b.kind==="command"&&tk(b.command))break;if(b.kind==="resume-summary"){t.push({id:y.id,kind:"resume-summary",title:b.title||"Context resumed from summary",bullets:b.bullets||[],sections:b.sections||[],rawChars:b.rawChars??null,ts:fe(y),box:y.boxId,agent:y.provider});break}b.kind!=="suppress"&&t.push({id:y.id,kind:"event",type:rk(b),name:b.name??null,command:b.command??null,summary:b.summary??null,status:b.status??null,ts:fe(y),box:y.boxId,agent:y.provider});break}}if(r.has(`${y.boxId}|${fe(y)}`)||y.source==="transcript"&&at(y.boxId,m.text))break;if(m.kind==="merge-notify"||m.kind==="ship-notify"){t.push({id:y.id,kind:"event",type:m.kind==="ship-notify"?"ship-notified":"merge-notified",text:m.text,ts:fe(y),box:y.boxId,agent:y.provider});break}if(m.kind==="mock-picked"||m.kind==="ci-fix"||m.kind==="reconcile"||m.kind==="pr-go"||m.kind==="push-go"||m.kind==="spin-up-view"||m.kind==="prompt-answer"||m.kind==="followup-go"){m.kind==="prompt-answer"&&(G=null);break}for(let b of B.values())b.status="stale";B.clear();for(let b of _.values())b.status="stale";_.clear();for(let b of W.values())b.status="stale";W.clear(),G&&G.box===y.boxId&&(t.push(RM(G)),G=null),t.push({id:y.id,kind:"message",role:"user",text:m.text,ts:fe(y),box:y.boxId,agent:y.provider,boxRole:m.boxRole,...y.actor==="orchestrator"?{orchestration:m.kind||!0}:{},...m.sourceId?{sourceId:m.sourceId}:{},...m.attachments?.length?{attachments:m.attachments}:{},...m.images?.length?{images:m.images}:{}});break}case"peer.message":{let b=m.from||{};t.push({id:y.id,kind:"event",type:"peer-message",text:m.text,from:b.trackName||b.boxId||b.name||null,fromTrackId:b.trackId||null,ts:fe(y),box:y.boxId,agent:y.provider});break}case"turn.agent":{if(m.model==="<synthetic>"&&/^No response requested\.$/.test(String(m.text||"").trim()))break;let b=gb(m,{codexFailedText:ao});if(b){t.push({id:y.id,kind:"event",type:"provider-error",cls:b.cls,status:b.status??void 0,text:b.text,provider:y.provider,legacy:!0,at:fe(y),ts:fe(y),box:y.boxId,agent:y.provider});break}A();let M=(m.images||[]).filter(Re=>!k(Re,fe(y)));if(!String(m.text||"").trim()&&!M.length)break;if(y.provider==="cursor"){let Re=`${y.boxId}|${m.text}`;if(n.has(Re))break;n.add(Re)}(!G||G.box===y.boxId)&&(G=null);let ne=y.provider==="codex"?(m.tools||[]).filter(Re=>!Af.has(Re)&&!za.has(Re)):m.tools||[],de=m.text,De=null,ht=zf(String(m.text||""));ht&&(de=ht.text,De={questions:ht.questions}),t.push({id:y.id,kind:"message",role:"assistant",text:de,ts:fe(y),box:y.boxId,agent:y.provider,boxRole:m.boxRole,...De?{ask:De}:{},...ne.length?{tools:ne}:{},...m.model?{model:m.model}:{},...m.sourceId?{sourceId:m.sourceId}:{},...M.length?{images:M}:{}}),L(y),De&&(G={id:y.id,groupId:Yf(y.provider,m.sourceId||y.id,De.questions),provider:y.provider,box:y.boxId,questions:De.questions,ts:fe(y)});break}case"job.started":{if(!m.id)break;let b=fe(y),M=i.get(m.id);if(!M&&(m.kind||"agent")==="agent"&&m.name){let Re=l.get(m.name);Re&&Re.ts>=b&&(M=Re)}let ne={jobId:m.id,jobKind:m.kind||"agent",name:m.name||null,detail:m.detail||null,status:M?M.status==="killed"?"stopped":M.status&&M.status!=="completed"?"failed":"done":"running",startedTs:b,finishedTs:M?.ts??null,summary:M?.summary??null,resultHead:M?.resultHead??null},de=_t.get(y.boxId),De=de?.jobs[de.jobs.length-1]?.startedTs;if(de&&De!=null&&b-De<=Ge)de.jobs.push(ne);else{let Re={id:y.id,kind:"job-dock",dockId:m.id,ts:b,box:y.boxId,agent:y.provider,jobs:[ne]};_t.set(y.boxId,Re),t.push(Re)}break}case"handoff.done":t.push(dt(y,"lead-handoff"));break;case"subtask.delegated":t.push({...dt(y,"subtask-delegated"),to:y.boxId,toAgent:y.provider});break;case"subtask.merged":t.push(dt(y,"subtask-merged"));break;case"pr.state.changed":{if(!m.change)break;if(m.change==="opened"){for(let M of B.values())M.status="stale";B.clear();for(let M of _.values())M.status="stale";_.clear()}let b=dt(y,`pr-${m.change}`);if(b.box=y.boxId??null,OM.has(m.change)&&m.number!=null){let M=CM(S,E,m);if(S.size>=2){for(let de of E.values())for(let De of de)De.grouped=!0;b.groupPrs=[...S.values()];let ne=[b];for(let de of S.keys())E.set(de,ne)}else{let ne=E.get(M)??[];ne.push(b),E.set(M,ne)}}else if(m.change==="merged"||m.change==="closed"||m.change==="lost"){let M=ck(m),ne=R&&!R.complete||S.size>=2;if(S.has(M))S.delete(M),E.delete(M);else if(m.number!=null)for(let de of[...S.keys()])de.endsWith(`#${m.number}`)&&(S.delete(de),E.delete(de));if(ne&&m.number!=null){(!R||R.complete)&&(R={id:y.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:fe(y),ts:fe(y),box:y.boxId,agent:y.provider},t.push(R)),R.prs.push({number:m.number,url:m.url??null,title:m.title??null,repo:m.repo??null,branch:m.branch??null,change:m.change,ts:fe(y)}),R.remaining=[...S.values()],R.complete=S.size===0;break}}t.push(b);break}case"pr.offered":{if(!m.offerId)break;for(let M of B.values())M.status="stale";B.clear();for(let M of _.values())M.status="stale";_.clear();let b={id:y.id,kind:"pr-offer",offerId:m.offerId,excerpt:m.excerpt||null,branch:m.branch||null,base:m.base||null,offered:Array.isArray(m.offered)&&m.offered.length?m.offered:null,toPr:m.toPr&&typeof m.toPr=="object"?{number:m.toPr.number??null}:null,available:Array.isArray(m.available)?m.available:null,defaults:Array.isArray(m.defaults)?m.defaults:null,prState:m.prState||null,openPr:m.openPr&&typeof m.openPr=="object"?m.openPr:null,repos:Array.isArray(m.repos)&&m.repos.length?m.repos:null,status:"open",source:y.source==="cli"||m.via==="cli"?"cli":"transcript",ts:fe(y),box:y.boxId,agent:y.provider};B.set(m.offerId,b),T.set(m.offerId,b),t.push(b),b.source==="cli"&&ie(b);break}case"pr.offer.answered":{let b=T.get(m.offerId);b&&(b.status=m.action||"dismiss",b.actions=Array.isArray(m.actions)?m.actions:null,b.notify=m.notify===!0,m.existingPr&&typeof m.existingPr=="object"&&(b.existingPr={number:m.existingPr.number??null}),B.delete(m.offerId));break}case"pr.exists.offered":{if(!m.offerId)break;for(let M of _.values())M.status="stale";_.clear();let b={id:y.id,kind:"pr-exists-offer",offerId:m.offerId,srcOfferId:m.srcOfferId??null,branch:m.branch||null,base:m.base||null,pr:m.pr&&typeof m.pr=="object"?{number:m.pr.number??null,url:m.pr.url??null,title:m.pr.title??null}:null,actions:Array.isArray(m.actions)&&m.actions.length?m.actions:null,notify:m.notify===!0,status:"open",ts:fe(y),box:y.boxId,agent:y.provider};_.set(m.offerId,b),O.set(m.offerId,b),t.push(b);break}case"pr.exists.answered":{let b=O.get(m.offerId);b&&(b.status=m.choice||"dismiss",_.delete(m.offerId));break}case"box.state.changed":{let b=m.change==="model"?"model-change":m.change;if(!b)break;let M=dt(y,b);if(b==="model-change"&&(M.to=m.model),b==="node-update"&&M.latest){let ne=t.findIndex(de=>de.kind==="event"&&de.type==="node-update"&&de.latest===M.latest);if(ne>=0){let de=t[ne];t[ne]={...M,ts:de.ts,at:de.at,firstAt:de.firstAt??de.ts,updatedAt:M.ts};break}}t.push(M);break}case"track.transferred":case"track.recovered":t.push(dt(y,"track-moved"));break;case"view.state.changed":{if(m.change==="deleted"){d(`view:${m.viewId}`);break}if(m.change!=="created"||m.restarted)break;f(`view:${m.viewId}`,{id:y.id,kind:"view-card",viewId:m.viewId,name:m.name,slug:m.slug,port:m.port,origin:m.origin,ts:fe(y),box:y.boxId,agent:y.provider});break}case"view.spinup.failed":{t.push({id:y.id,kind:"view-spinup-failed",name:m.name||null,reason:m.reason||"no-view",ts:fe(y),box:y.boxId,agent:y.provider});break}case"mock.state.changed":{if(m.change==="picked"){t.push({id:y.id,kind:"mock-picked",mockId:m.mockId,name:m.name,group:m.group??null,version:m.version??null,siblings:m.siblings??[],ts:fe(y),box:y.boxId,agent:y.provider});break}if(m.change==="deleted"){d(`mock:${m.mockId}`);break}if(m.change!=="created")break;f(`mock:${m.mockId}`,{id:y.id,kind:"mock-card",mockId:m.mockId,name:m.name,group:m.group??null,ts:fe(y),box:y.boxId,agent:y.provider});break}case"flow.state.changed":{if(m.change==="deleted"){d(`flow:${m.flowId}`);break}if(m.change!=="created")break;f(`flow:${m.flowId}`,{id:y.id,kind:"flow-card",flowId:m.flowId,name:m.name,stepCount:m.stepCount??null,mockIds:m.mockIds??[],ts:fe(y),box:y.boxId,agent:y.provider});break}case"runbook.state.changed":{if(m.change==="deleted"){d(`runbook:${m.runbookId}`);break}if(m.change!=="created")break;f(`runbook:${m.runbookId}`,{id:y.id,kind:"runbook-card",runbookId:m.runbookId,name:m.name,ts:fe(y),box:y.boxId,agent:y.provider});break}case"ticket.linked":{t.push({id:y.id,kind:"ticket-card",provider:m.provider||"linear",key:m.key,url:m.url,title:m.title??null,linkSource:m.linkSource??null,ts:fe(y),box:y.boxId,agent:y.provider});break}case"box.fullscreen.detected":{if(!m.offerId)break;for(let M of H.values())M.box===(m.box||y.boxId)&&(M.status="stale",H.delete(M.offerId));let b={id:y.id,kind:"fullscreen-offer",offerId:m.offerId,status:"open",ts:fe(y),box:m.box||y.boxId,agent:m.agent||y.provider};H.set(m.offerId,b),ae.set(m.offerId,b),t.push(b);break}case"box.fullscreen.answered":{let b=ae.get(m.offerId);b&&(b.status=m.action==="restarted"?"restarted":m.action==="cleared"?"cleared":"dismiss",H.delete(m.offerId));break}case"ticket.move.offered":{if(!m.offerId)break;for(let M of I.values())M.key===m.key&&(M.status="stale",I.delete(M.offerId));let b={id:y.id,kind:"ticket-offer",offerId:m.offerId,provider:m.provider||"linear",key:m.key,url:m.url??null,phase:m.phase??null,from:m.from??null,to:m.to?.name??null,prNumber:m.prNumber??null,status:"open",ts:fe(y),box:y.boxId,agent:y.provider};I.set(m.offerId,b),U.set(m.offerId,b),t.push(b);break}case"ticket.move.answered":{let b=U.get(m.offerId);b&&(b.status=m.action==="moved"?"moved":"dismiss",I.delete(m.offerId));break}case"ticket.state.changed":{for(let b of I.values())b.key===m.key&&b.to===m.to&&(b.status="stale",I.delete(b.offerId));if(m.mode==="offer")break;t.push(dt(y,"ticket-state"));break}case"ticket.commented":{t.push({id:y.id,kind:"ticket-comment",key:m.key,url:m.url??null,excerpt:m.excerpt??null,ts:fe(y),box:y.boxId,agent:y.provider});break}case"ticket.flow.changed":t.push(dt(y,"ticket-flow"));break;case"ticket.create.offered":{if(!m.proposalId)break;for(let M of X.values())M.status="stale";X.clear();let b={id:y.id,kind:"ticket-create-offer",proposalId:m.proposalId,provider:m.provider||"linear",epic:m.epic??null,issues:Array.isArray(m.issues)?m.issues:[],team:m.team??null,needsTeam:!!m.needsTeam,linkCurrentTrack:!!m.linkCurrentTrack,status:"open",ts:fe(y),box:y.boxId,agent:y.provider};X.set(m.proposalId,b),C.set(m.proposalId,b),t.push(b),ie(b);break}case"ticket.create.answered":{let b=C.get(m.proposalId);b&&(b.status=m.action==="created"?"created":"dismiss",b.createdCount=m.createdCount??null,b.failedCount=m.failedCount??null,X.delete(m.proposalId));break}case"loop.create.offered":{if(!m.proposalId)break;for(let M of Q.values())M.status="stale";Q.clear();let b={id:y.id,kind:"loop-create-offer",proposalId:m.proposalId,name:m.name??"",schedule:m.schedule??"",prompt:m.prompt??"",expectation:m.expectation??null,notify:m.notify??"off",assignment:m.assignment??{provider:"claude"},repo:m.repo??null,nodeId:m.nodeId??null,nodeName:m.nodeName??null,status:"open",ts:fe(y),box:y.boxId,agent:y.provider};Q.set(m.proposalId,b),ve.set(m.proposalId,b),t.push(b),ie(b);break}case"loop.create.answered":{let b=ve.get(m.proposalId);b&&(b.status=m.action==="created"?"created":"dismiss",Q.delete(m.proposalId));break}case"followup.armed":{if(!m.armId)break;let b=m.replaces?se.get(m.replaces):null;b&&b.status==="armed"&&(b.status="replaced");let M={id:y.id,kind:"followup-armed",armId:m.armId,trigger:m.trigger??"now",label:m.label??"",prompt:m.prompt??"",why:m.why??null,status:"armed",ts:fe(y),box:y.boxId,agent:y.provider};se.set(m.armId,M),M.trigger!=="now"&&t.push(M);break}case"followup.armed.cancelled":{let b=se.get(m.armId);b&&b.status==="armed"&&(b.status="cancelled");break}case"followup.offered":{if(!m.offerId)break;for(let ne of W.values())ne.trigger===m.trigger&&(ne.status="stale",W.delete(ne.offerId));let b=Array.isArray(m.rows)?m.rows:[];for(let ne of b){let de=ne.armId?se.get(ne.armId):null;de&&de.status==="armed"&&(de.status="offered")}let M={id:y.id,kind:"followup-offer",offerId:m.offerId,trigger:m.trigger??"now",repo:m.repo??null,context:m.context&&typeof m.context=="object"?m.context:{},rows:b.map(ne=>({followupId:ne.followupId??null,armId:ne.armId??null,label:ne.label??"",prompt:ne.prompt??null,promptPreview:ne.promptPreview??null,promptHash:ne.promptHash??null,origin:ne.origin??"operator",why:ne.why??null})),status:"open",answer:null,ts:fe(y),box:y.boxId,agent:y.provider};W.set(m.offerId,M),be.set(m.offerId,M),t.push(M),M.trigger==="now"&&ie(M);break}case"followup.answered":{let b=be.get(m.offerId);b&&(b.status=m.action==="sent"?"sent":m.action==="removed"?"removed":"dismiss",b.answer={followupId:m.followupId??null,armId:m.armId??null,label:m.label??null,promoted:m.promoted??null,revived:m.revived===!0},W.delete(m.offerId));break}case"followup.create.offered":{if(!m.proposalId)break;for(let M of ce.values())M.status="stale";ce.clear();let b={id:y.id,kind:"followup-create-offer",proposalId:m.proposalId,label:m.label??"",prompt:m.prompt??"",trigger:m.trigger??"pr.merged",repo:m.repo??null,why:m.why??null,status:"open",created:null,ts:fe(y),box:y.boxId,agent:y.provider};ce.set(m.proposalId,b),ue.set(m.proposalId,b),t.push(b),ie(b);break}case"followup.create.answered":{let b=ue.get(m.proposalId);b&&(b.status=m.action==="created"?"created":"dismiss",ce.delete(m.proposalId));break}case"followup.created":{let b=m.proposalId?ue.get(m.proposalId):null;b&&(b.created={followupId:m.followupId??null});break}case"loop.created":{let b=m.proposalId?ve.get(m.proposalId):null;b&&(b.created={loopId:m.loopId??null,nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),t.push(dt(y,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!m.proposalId||!m.loopId)break;for(let ne of Ae.values())ne.loopId===m.loopId&&(ne.status="stale",ne.staleReason="superseded",Ae.delete(ne.proposalId));let b=y.type==="loop.update.offered",M={id:y.id,kind:b?"loop-update-offer":"loop-delete-offer",proposalId:m.proposalId,loopId:String(m.loopId),name:m.name??m.base?.name??"",base:m.base??null,...b?{patch:m.patch??{},changed:Array.isArray(m.changed)?m.changed:Object.keys(m.patch||{})}:{reason:m.reason??""},selfEdit:!!m.selfEdit,status:"open",staleReason:null,ts:fe(y),box:y.boxId,agent:y.provider};Ae.set(m.proposalId,M),_e.set(m.proposalId,M),t.push(M),ie(M);break}case"loop.update.answered":{let b=_e.get(m.proposalId);b&&(m.action==="moved"?(b.status="stale",b.staleReason="moved"):b.status=m.action==="applied"?"applied":"dismiss",Ae.delete(m.proposalId));break}case"loop.delete.answered":{let b=_e.get(m.proposalId);b&&(m.action==="moved"?(b.status="stale",b.staleReason="moved"):b.status=m.action==="delete"?"deleted":m.action==="pause"?"paused":"keep",Ae.delete(m.proposalId));break}case"loop.updated":{let b=m.proposalId?_e.get(m.proposalId):null;b&&(b.applied={changed:Array.isArray(m.changed)?m.changed:[],nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),t.push(dt(y,"loop-updated"));break}case"loop.deleted":t.push(dt(y,"loop-deleted"));break;case"loop.paused":t.push(dt(y,"loop-paused"));break;case"rework.cause.offered":{if(!m.sha||xt.has(m.sha))break;let b={id:y.id,kind:"rework-cause-offer",sha:m.sha,subject:m.subject??"",linesReworked:Number(m.linesReworked)||0,origins:Array.isArray(m.origins)?m.origins:[],heuristic:m.heuristic??null,status:"open",cause:null,ts:fe(y),box:y.boxId,agent:y.provider};xt.set(m.sha,b),t.push(b);break}case"rework.cause.answered":{let b=m.sha?xt.get(m.sha):null;b&&(b.status="answered",b.cause=m.cause??null);break}case"ticket.created":{let b={items:Array.isArray(m.items)?m.items:[],failed:Array.isArray(m.failed)?m.failed:[],team:m.team??null},M=m.proposalId?C.get(m.proposalId):null;if(M){M.created=b;break}t.push({id:y.id,kind:"ticket-created",...b,ts:fe(y),box:y.boxId,agent:y.provider});break}case"error":{if(!m.kind)break;t.push(dt(y,m.kind));break}case"provider.error":t.push({...dt(y,"provider-error"),provider:y.provider,box:y.boxId,agent:y.provider});break;case"usage.cap.hit":t.push(dt(y,"usage-cap-hit"));break;case"usage.cap.warning":t.push(dt(y,"usage-cap-warning"));break;case"provider.connected":{t.push({id:y.id,kind:"event",type:"provider-connected",provider:m.provider||y.provider,ts:fe(y),at:fe(y),box:y.boxId,agent:y.provider});break}case"prompt.answered":{if(G=null,m.control||!m.question)break;let b=m.groupId||m.promptId;if(!b)break;let M=je.get(b);M||(M={id:y.id,kind:"prompt",groupId:b,provider:y.provider,box:y.boxId,agent:y.provider,questionTotal:m.questionTotal??1,questions:[],ts:fe(y)},je.set(b,M));let ne=m.questionIndex??0,de={index:ne,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:Array.isArray(m.chosen)?m.chosen:[]},De=M.questions.findIndex(Re=>Re.index===ne&&We(Re.question)===We(de.question));De>=0?M.questions[De]=de:M.questions.push(de),M.questions.sort((Re,ya)=>Re.index-ya.index),M.questionTotal=Math.max(M.questionTotal,m.questionTotal??1),M.questions.length>=M.questionTotal&&(t.push(M),je.delete(b));break}default:break}}let nt=u.size?t.filter(y=>!y.retired):t;return NM(nt.sort((y,m)=>(y.ts??0)-(m.ts??0)))}function NM(e){let t=new Map,n=[];for(let r of e){if(r.kind!=="message"||!r.box){n.push(r);continue}let o=r.role==="assistant"&&!String(r.text||"").trim()&&r.images?.length,s=t.get(r.box);if(o&&s&&(r.ts??0)-s.lastTs<=MM){s.item.images.push(...r.images),s.lastTs=r.ts??s.lastTs;continue}if(o){let a={...r,images:[...r.images]};t.set(r.box,{item:a,lastTs:r.ts??0}),n.push(a)}else t.delete(r.box),n.push(r)}return n}function Zf(e,t=null){let n=[];for(let o of e||[]){if(o.type!=="tool.called"||o.source!=="transcript")continue;let s=o.payload||{};String(s.command||"").trim()&&n.push({id:s.id??null,tool:s.tool||null,command:s.command,description:s.description||"",summary:PM(s),ts:s.ts??o.ts,n:s.n,box:o.boxId,agent:o.provider,boxRole:s.boxRole})}if(!n.length)return[];let r=(t??wr(e)).filter(o=>o.kind==="message");return lb(n,r)}function PM(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==ps(e.command)?t:mr(e.command,e.description||"")}function dt(e,t){let{ts:n,change:r,...o}=e.payload||{};return{id:e.id,kind:"event",type:t,...o,at:fe(e),ts:fe(e)}}function lk(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||r.type!=="archived")continue;let o=(r.ts??0)+DM,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&BM.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function uk(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!LM.has(r.type)||!r.box)continue;let o=(r.ts??0)+jM,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||!(a?.kind==="message"&&a.role==="assistant"&&a.box===r.box||a?.kind==="command-batch"&&a.anchorBox===r.box))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function dk(e){return(e||[]).filter(t=>FM.has(t?.kind)&&t.status==="open")}var fe,OM,ck,MM,DM,BM,jM,LM,FM,Qf=j(()=>{ms();io();dl();bl();Vf();Xf();fe=e=>e.payload?.ts??e.ts;OM=new Set(["opened","ci-fixed","reconciled","pushed"]),ck=e=>`${e.repo??""}#${e.number}`;MM=2*6e4;DM=12e4,BM=new Set(["archived","unarchived","opened"]);jM=2500,LM=new Set(["pr-opened","pr-merged","pr-auto-armed"]);FM=new Set(["pr-offer","pr-exists-offer","ticket-offer","ticket-create-offer","loop-create-offer","loop-update-offer","loop-delete-offer","fullscreen-offer","followup-create-offer"])});function KM(e){let t=null,n=null,r=null;for(let o of e??[]){let s=o?.ts??null;s&&(r=Math.max(r??0,s)),o?.type==="handoff.artifact"&&(t={ts:o.payload?.ts??s,truncated:!!o.payload?.truncated,...o.payload?.reconstructed?{reconstructed:!0}:{}}),o?.type==="code.pushed"&&(n={ts:o.payload?.ts??s,sha:o.payload?.sha??null,ref:o.payload?.ref??null,wip:!!o.payload?.wip})}return{lastArtifact:t,lastPush:n,lastEventAt:r}}function VM(e){for(let t=(e?.length??0)-1;t>=0;t--){let n=e[t];if(n?.type==="handoff.artifact"&&!n.payload?.reconstructed)return n}return null}function zM(e,t){let n=[],r=[],o=new Set,s=new Set;for(let a=(e?.length??0)-1;a>=0;a--){let i=e[a];if(i?.type!=="tool.called")continue;if(t!=null&&(i.ts??0)<=t)break;let c=i.payload||{};c.path&&!o.has(c.path)&&n.length<WM&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<qM&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function hk(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=KM(e),s=VM(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=wr(e??[]).filter(d=>d?.kind==="message"&&typeof d.text=="string"&&d.text.trim()).slice(-UM);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(mk[r]??mk.failover),l.push(""),o.lastPush?.sha){let d=pk(n,o.lastPush.ts),p=d?` (~${d} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${p}`+(o.lastPush.wip?" \u2014 a bostrat WIP snapshot (full working tree incl. uncommitted edits at push time).":"."))}else r==="in-place"?l.push("**Code state:** no push recorded \u2014 the working tree in this workspace is the only copy; commit early."):l.push("**Code state:** no push was ever recorded for this Track \u2014 work since the branch's last known state stayed on the offline node.");if(l.push(""),a){let d=pk(n,i);l.push(`## Last real checkpoint (written by the previous agent${d?`, ~${d} min before this reconstruction`:""})`),l.push(""),l.push(a.trim()),l.push("")}let u=zM(e??[],i);if((u.files.length||u.heads.length)&&(l.push(`## Work since ${a?"that checkpoint":"the start of the log"} (from the event log)`),l.push(""),u.files.length&&l.push(`Files touched (most recent first): ${u.files.map(d=>`\`${d}\``).join(", ")}`),u.heads.length&&(u.files.length&&l.push(""),l.push(`Commands run (most recent first): ${u.heads.map(d=>`\`${d}\``).join(" \xB7 ")}`)),l.push("")),c.length){l.push(`## Recent conversation (last ${c.length} message${c.length===1?"":"s"})`),l.push("");for(let d of c)l.push(`**${d.role==="user"?"operator":"agent"}:** ${GM(d.text,HM)}`),l.push("")}l.push("---"),l.push("Resume: continue the objective above from the verified repository state; ask the operator before redoing anything the log says was already done.");let f=l.join(`
151
+ `);return f.length<=fk?f:`${f.slice(0,fk)}
152
+
153
+ [\u2026 brief truncated]`}var UM,HM,fk,WM,qM,GM,pk,mk,wk=j(()=>{Qf();UM=12,HM=2e3,fk=48e3,WM=30,qM=10;GM=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},pk=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;mk={failover:"**This is a reconstruction, not a checkpoint.** The node this Track lived on went offline without a clean handoff; bostrat assembled this brief from the durable event log. Treat every claim below as a lead, not a fact \u2014 **verify the repository state first** (git status, git log, the diff against the last pushed ref) before continuing work.","in-place":"**This is a reconstruction, not a checkpoint.** The previous lead ended without writing one (out of credits, capped, or unresponsive); bostrat assembled this status from the Track's event log. You are in the SAME live workspace \u2014 uncommitted work is present locally. **Run git status and git log first** and treat every claim below as a lead, not a fact.",get recover(){return this.failover},transfer:"**This Track was MOVED to a new machine while it was alive.** The previous node checkpointed and pushed its work as part of the move; this workspace was re-created from that push (uncommitted work re-applied when possible). **Run git status and git log to confirm what carried over**, then continue the objective below."}});import YM from"node:fs";import gr from"node:fs/promises";import yr from"node:path";function Tk(e){let t=no(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=gk?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,gk).toString("utf8").replace(/�+$/,"")}
154
+
155
+ [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function oN(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(bk.test(s)){if(r.length>=Rk)continue;let a=rN(s.replace(bk,"").replace(/[.;,:]+$/,""),Ok,tN);a&&r.push(a)}else r.length||n.push(s);let o=n.join(" ").replace(/\s+/g," ").replace(/[:\-–—]+$/,"").trim();if(!o)throw new Error("beat file has no summary line");return o.length>yk&&(o=`${o.slice(0,yk-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function Ck(e,t,{timeoutMs:n=9e4}={}){let r=yr.join(t,QM),o=yr.join(r,eN);await gr.mkdir(r,{recursive:!0});let s=await Al(o),a=await ge(e);if(!a)throw new Error(`session "${e}" not found`);return await _l(e,a,nN(o)),await Lk(o,s,n),oN(await gr.readFile(o,"utf8"))}function Mk(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===Ak||n===$k;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(Ek)||n===JM||r.startsWith(_k)||r.startsWith(Ik)}function Nk(e){let t=[];for(let r of e?.events||[]){if(r.type!=="lead-handoff"||!r.from)continue;let o=r.at??Date.now(),s=r.handoffStartedAt??o-sN;t.push({box:r.from,from:s,to:o}),r.to&&r.to!==r.from&&t.push({box:r.to,from:s,to:o})}let n=e?.handoff;return n?.fromBox&&n.startedAt&&n.finishedAt&&t.push({box:n.fromBox,from:n.startedAt,to:n.finishedAt}),n?.toBox&&n.startedAt&&n.finishedAt&&t.push({box:n.toBox,from:n.startedAt,to:n.finishedAt}),t}function Pk(e,t){let n=[];for(let r of e?.boxes||[]){let o=t?.(r.name);o?.startedAt&&n.push({box:r.name,from:o.startedAt,to:o.finishedAt||Date.now()+1e12})}return n}function Dk(e,{windows:t=[]}={}){if(Mk(e.role,e.text))return!0;if(e.role!=="assistant"||!e.ts)return!1;for(let n of t)if(e.box===n.box&&e.ts>=n.from&&e.ts<=n.to)return!0;return!1}function Il(e){return ep.get(e)||null}async function Bk(e){let t=ep.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await ge(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);let r={name:e,step:"summarize",startedAt:Date.now(),finishedAt:null,error:null,file:yr.join(n.cwd,vk,Sk)};return ep.set(e,r),cN(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function cN(e,t){e.step="summarize",await jk(e.name,t),e.step="clear";let n=await ge(e.name);await _l(e.name,n,"/clear"),await rp(aN),e.step="resume",await _l(e.name,n,ZM),e.step="done",e.finishedAt=Date.now()}async function jk(e,t,{timeoutMs:n=iN}={}){let r=yr.join(t,vk),o=yr.join(r,Sk);await gr.mkdir(r,{recursive:!0});let s=await Al(o),a=await ge(e);await re({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await _l(e,a,XM(o)),await Lk(o,s,n),await re({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await Al(o)});let i=await zb(t,o,{exclude:u=>Mk(u.role,u.text)});await re({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(c){await $({id:c,cwd:t},{type:"memory.seed",actor:"orchestrator",payload:{...i,tokensEst:i.chars?Math.round(i.chars/4):0,ts:Date.now()}}).catch(()=>{});try{let u=await gr.readFile(o,"utf8");await $({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...Tk(u),ts:Date.now()}})}catch{}}await Qd(t);let l=await lN(r,o);return c&&await Oy(c,l||o,{box:e,agent:a?.agent??null}),o}async function tp(e,{timeoutMs:t}={}){let n=await ge(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);return jk(e,n.cwd,t?{timeoutMs:t}:void 0)}async function np(e,t,{trackName:n="this Track"}={}){let r=await F({id:e,cwd:t}),o=hk(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=yr.join(t,kk);return await gr.mkdir(yr.dirname(s),{recursive:!0}),await gr.writeFile(s,o,"utf8"),await $({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...Tk(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),kk}async function Al(e){try{return(await gr.stat(e)).mtimeMs}catch{return 0}}async function Lk(e,t,n){let r=Date.now()+n;for(;;){if(await Al(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await rp(2e3)}}async function lN(e,t){try{if(!YM.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=yr.join(e,`${n}.md`);return await gr.copyFile(t,r),r}catch{return null}}function rp(e){return new Promise(t=>setTimeout(t,e))}function xk(e){return e==="claude"?process.env.BOSTRAT_AGENT_CMD||"claude":e==="cursor"?process.env.BOSTRAT_CURSOR_CMD||"cursor-agent":e==="codex"?process.env.BOSTRAT_CODEX_CMD||"codex":""}async function _l(e,t,n){if(t){let o=xk(t.agent);await hr({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await ge(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await Le(e,["Escape"],{kind:"drive-wipe"}),await rp(150),await ls(e,cl,{kind:"drive-wipe"}),await Ze(e,n,{kind:"orchestration-drive",...pn(r.agent,n)}),await ni({sessionName:e,agent:r.agent,agentCmd:xk(r.agent),text:n,flow:"orchestration-drive"})}var vk,Sk,gk,Ek,Ak,_k,JM,XM,ZM,Ik,$k,QM,eN,yk,Rk,Ok,tN,nN,bk,rN,sN,aN,iN,ep,kk,op=j(()=>{lt();Za();dn();Qa();Uf();Yb();Oa();me();Qc();wk();vk=".bostrat/handoff",Sk="latest.md",gk=32*1024;Ek="Checkpoint: write a work-in-progress handoff",Ak="HANDOFF WRITTEN",_k="Resume from .bostrat/handoff/latest.md",JM="/clear",XM=e=>`${Ek} to the EXACT absolute path ${e} (write it there specifically \u2014 NOT into any sub-project or other directory; create the directory if needed, overwrite the file) so a FRESH Claude context with none of this conversation can resume seamlessly. Use these sections: Objective; Done (with file paths); In progress (exact state); Next steps (ordered); Key files & commands; Open decisions/blockers; Resume instruction (one line). Be concrete and self-contained \u2014 assume the reader has none of this chat. When the file is written, reply only with ${Ak} and take no further action.`,ZM=`${_k}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,Ik="Beat: write a",$k="BEAT WRITTEN",QM=".bostrat/arc",eN="beat.txt",yk=200,Rk=4,Ok=5,tN=36,nN=e=>`${Ik} short summary of what this workstream accomplished, to the EXACT absolute path ${e} (write it there specifically \u2014 NOT into any sub-project or other directory; create the directory if needed, overwrite the file). Format the file as: FIRST LINE = one sentence of at most 18 words, plain past tense, saying the outcome \u2014 no heading, no bullet, no trailing list. THEN, only if this workstream covered several separable pieces of work, up to ${Rk} further lines, each starting with "- " and naming ONE piece in at most ${Ok} words \u2014 a label, not a sentence (e.g. "- stale working flag on poll"). Write nothing else in the file. When the file is written, reply only with ${$k} and take no further action.`,bk=/^(?:[-–—*•·]|\d+[.)])\s+/,rN=(e,t,n)=>{let r=e.split(/\s+/).filter(Boolean).slice(0,t).join(" ");return r.length>n?`${r.slice(0,n-1).trimEnd()}\u2026`:r};sN=6e5;aN=3500,iN=3e5,ep=new Map;kk=".bostrat/handoff/status-latest.md"});function kr(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!$l.test(String(e)))throw new Error(`pricing.js: ${n} window ${t} must be YYYY-MM-DD, got ${JSON.stringify(e)}`);let r=Date.parse(`${e}T${t==="from"?"00:00:00.000":"23:59:59.999"}Z`);if(!Number.isFinite(r))throw new Error(`pricing.js: ${n} window ${t} is not a real date: ${e}`);return r}function Hk(e){let t={};for(let[n,r]of Object.entries(e)){if(!Array.isArray(r)||r.length===0)throw new Error(`pricing.js: ${n} must be a non-empty array of rate windows`);t[n]=r.map(o=>({...o,fromMs:kr(o.from,"from",n),toMs:kr(o.to,"to",n)}))}return t}function ap(e){if(e==null)return Date.now();if(typeof e=="number")return Number.isFinite(e)?e:null;if(e instanceof Date){let n=e.getTime();return Number.isFinite(n)?n:null}let t=Date.parse(String(e));return Number.isFinite(t)?t:null}function dN(e){if(!e)return null;let t=String(e).trim();return br[t]?t:Fk[t]?Fk[t]:Object.keys(br).find(r=>t.startsWith(r))||null}function fN(e){if(!e||e===br)return uN;let t=Uk.get(e);return t||(t=Hk(e),Uk.set(e,t)),t}function Wk(e,t,n={}){let{table:r,speed:o}=n,s=fN(r),a=r&&r!==br?s[e]?e:null:dN(e);if(!a)return null;let i=ap(t);if(i===null)return null;let c=s[a].find(l=>i>=l.fromMs&&i<=l.toMs)||null;return c?o==null||o==="standard"?c:o==="fast"&&c.fast?{...c.fast,fromMs:c.fromMs,toMs:c.toMs,verifiedAt:c.verifiedAt,note:c.note,speed:"fast"}:null:null}function mn(e,t={},n,r){let o=Wk(e,n,r);return o?((t.input||0)*o.input+(t.output||0)*o.output+(t.cacheWrite||0)*o.cacheWrite+(t.cacheRead||0)*o.cacheRead)/1e6:0}function pN(e=br){let t=[];for(let[n,r]of Object.entries(e)){if(!Array.isArray(r)||r.length===0){t.push(`${n}: must be a non-empty array of windows`);continue}let o;try{o=r.map(a=>({fromMs:kr(a.from,"from",n),toMs:kr(a.to,"to",n)}))}catch(a){t.push(String(a.message));continue}let s=r.filter(a=>a.to==null);s.length!==1?t.push(`${n}: expected exactly 1 open-ended window (to: null), found ${s.length}`):r[r.length-1].to!=null&&t.push(`${n}: the open-ended window must be last`),r[0].from!=null&&t.push(`${n}: the first window must be open at the start (from: null)`);for(let a=0;a<o.length;a++){if(o[a].fromMs>o[a].toMs&&t.push(`${n}: window ${a} ends before it begins (${r[a].from} \u2192 ${r[a].to})`),a===0)continue;let i=o[a-1],c=o[a];c.fromMs<=i.toMs?t.push(`${n}: windows ${a-1} and ${a} overlap (${r[a-1].to} / ${r[a].from})`):c.fromMs-i.toMs>2&&t.push(`${n}: gap between windows ${a-1} and ${a} (${r[a-1].to} \u2192 ${r[a].from})`),r[a].from||t.push(`${n}: window ${a} must declare a from bound`)}for(let a of r){a.note||t.push(`${n}: every window needs a note recording what was verified and when`),$l.test(String(a.verifiedAt??""))||t.push(`${n}: every window needs a verifiedAt (YYYY-MM-DD) \u2014 the date its rates were checked against the vendor's published page`);for(let i of["input","output","cacheWrite","cacheRead"])(typeof a[i]!="number"||!Number.isFinite(a[i])||a[i]<0)&&t.push(`${n}: window ${i} must be a non-negative number, got ${JSON.stringify(a[i])}`),a.fast&&(typeof a.fast[i]!="number"||!Number.isFinite(a.fast[i])||a.fast[i]<0)&&t.push(`${n}: fast variant ${i} must be a non-negative number, got ${JSON.stringify(a.fast?.[i])}`)}}return t}function hN({now:e=Date.now(),table:t=br,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...mN,...n},a=[],i=ap(e);if(i===null)return[`pricingFreshness: unparseable now ${JSON.stringify(e)}`];for(let[c,l]of Object.entries(t)){if(!Array.isArray(l))continue;let u;try{u=l.map(f=>({...f,fromMs:kr(f.from,"from",c),toMs:kr(f.to,"to",c),verifiedMs:$l.test(String(f.verifiedAt??""))?Date.parse(`${f.verifiedAt}T00:00:00.000Z`):NaN}))}catch(f){a.push(String(f.message));continue}for(let f of u){if(!Number.isFinite(f.verifiedMs)){a.push(`${c}: window ${f.from??"\u2026"} \u2192 ${f.to??"now"} has no verifiedAt`);continue}let d=i>=f.fromMs&&i<=f.toMs,p=f.fromMs>i&&f.fromMs-i<=o*sp;d&&i-f.verifiedMs>r*sp&&a.push(`${c}: current rate last verified ${f.verifiedAt} (>${r}d) \u2014 re-check the vendor page and bump verifiedAt`),p&&f.fromMs-f.verifiedMs>s*sp&&a.push(`${c}: scheduled rate change on ${f.from} was last verified ${f.verifiedAt} \u2014 confirm it is still happening (vendors cancel; sonnet-5 did) and bump verifiedAt`)}}return a}function bs({now:e=Date.now(),table:t=br,...n}={}){let r=ap(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=kr(l.from,"from",i),f=kr(l.to,"to",i);r>=u&&r<=f&&$l.test(String(l.verifiedAt??""))&&(!o||l.verifiedAt<o)&&(o=l.verifiedAt),u>r&&s.push({model:i,from:l.from,verifiedAt:l.verifiedAt??null})}s.sort((i,c)=>i.from<c.from?-1:1);let a=[...pN(t),...hN({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var br,Fk,$l,uN,Uk,qk,mN,sp,Dn=j(()=>{br={"claude-opus-5":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"GA rates; verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-opus-4-8":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-sonnet-5":[{from:null,to:null,input:2,output:10,cacheWrite:4,cacheRead:.2,verifiedAt:"2026-08-17",note:"$2/$10 is the standard price (intro pricing made permanent; the 2026-09-01 $3/$15 increase was cancelled) \u2014 verified 2026-08-17 against platform.claude.com/docs/en/about-claude/pricing."}],"claude-sonnet-4-6":[{from:null,to:null,input:3,output:15,cacheWrite:6,cacheRead:.3,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-haiku-4-5":[{from:null,to:null,input:1,output:5,cacheWrite:2,cacheRead:.1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-fable-5":[{from:null,to:null,input:10,output:50,cacheWrite:20,cacheRead:1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); 83% of fleet spend."}],"gpt-5.5":[{from:null,to:null,input:5,output:30,cacheWrite:5,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-03, re-verified 2026-08-17 (developers.openai.com pricing); no cache-write premium on 5.5-and-earlier."}],"gpt-5.6-sol":[{from:null,to:null,input:5,output:30,cacheWrite:6.25,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-18, re-verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-terra":[{from:null,to:"2026-08-16",input:2.5,output:15,cacheWrite:3.125,cacheRead:.25,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:2,output:12,cacheWrite:2.5,cacheRead:.2,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-luna":[{from:null,to:"2026-08-16",input:1,output:6,cacheWrite:1.25,cacheRead:.1,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:.2,output:1.2,cacheWrite:.25,cacheRead:.02,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}]},Fk={opus:"claude-opus-5",opusplan:"claude-opus-5",default:"claude-opus-5",sonnet:"claude-sonnet-5",haiku:"claude-haiku-4-5",fable:"claude-fable-5","gpt-5.6":"gpt-5.6-sol"},$l=/^\d{4}-\d{2}-\d{2}$/;uN=Hk(br);Uk=new WeakMap;qk=(e,t,n)=>Wk(e,t,n)!==null;mN=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),sp=864e5});function wN(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function Gk(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Ft(e){let t=e.payload?.model||"unknown",n=wN(e.payload?.tokens),r=Number(e.payload?.usd)||0,o=e.payload?.speed||void 0,s=e.source==="vendor",a=r,i=!1;if(n&&!s){let u=mn(t,n,e.ts,o?{speed:o}:void 0);u>0&&(a=u,i=Math.abs(u-r)>1e-9)}let c=n?n.input+n.output+n.cacheRead+n.cacheWrite:0,l=!a&&c>0&&!qk(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function xr(e,{boxLabels:t={}}={}){let n=(e||[]).filter(d=>d.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,f=Kk();for(let d of n){let{usd:p,model:h,tokens:w,repriced:g,unpriced:k,asRecorded:S}=Ft(d);i+=S;let E=d.provider||"unknown",R=d.boxId||"unattributed";if(g&&c++,k&&(l++,u.add(h)),a+=p,Gk(f,w),r[h]||={usd:0,tokens:Kk(),events:0},r[h].usd+=p,r[h].events+=1,Gk(r[h].tokens,w),o[E]||={usd:0,events:0},o[E].usd+=p,o[E].events+=1,s[R]||={usd:0,events:0,provider:E,models:new Set,label:t[R]||R},s[R].usd+=p,s[R].events+=1,h!=="unknown"&&s[R].models.add(h),d.epoch!=null){let B=(s[R].epochs||={})[d.epoch]||={usd:0,events:0,provider:E,models:new Set};B.usd+=p,B.events+=1,B.provider=E,h!=="unknown"&&B.models.add(h)}}return{totalUsd:ks(a),asRecordedUsd:ks(i),totalTokens:f,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:Rl(r,d=>({...d,usd:ks(d.usd)})),byProvider:Rl(o,d=>({...d,usd:ks(d.usd)})),byBox:Rl(s,d=>({usd:ks(d.usd),events:d.events,provider:d.provider,label:d.label,models:[...d.models],...d.epochs?{epochs:Rl(d.epochs,p=>({usd:ks(p.usd),events:p.events,provider:p.provider,models:[...p.models]}))}:{}}))}}var Kk,ks,Rl,vr=j(()=>{Dn();Kk=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});ks=e=>Math.round(e*1e4)/1e4,Rl=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function gN(e){if(!Number.isFinite(e)||e<=0)return null;let t=e/864e5;if(t>=1)return`${Math.round(t)}d`;let n=e/36e5;return n>=1?`${Math.round(n)}h`:`${Math.max(1,Math.round(e/6e4))}m`}function Vk(e,t=[]){let n=[],r=e?.events||[],o=new Map,s=0;for(let u of t){if(u.type!=="pr.state.changed")continue;let f=u.payload||{};!f.repo||f.number==null||(f.change==="merged"?o.set(`${f.repo}#${f.number}`,f):f.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(f=>{let[d,p]=f.split("#");return`${d.split("/").pop()}#${p}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(ip(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(ip(a,"subtask"));let i=r.filter(u=>u.type==="lead-handoff"&&u.fromAgent&&u.toAgent);if(i.length){let u=i.slice(0,3).map(f=>`${f.fromAgent}\u2192${f.toAgent}`).join(", ");n.push(`${ip(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=xr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?gN(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var ip,zk=j(()=>{vr();ip=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as yN}from"node:child_process";import{promisify as bN}from"node:util";import{randomUUID as kN}from"node:crypto";async function cp(e,t){let n=Date.now()+t;for(;;){if(await Mn(e))return!0;if(Date.now()>n)return!1;await ii(vN)}}async function TN(e,t){let n=Jk[t]||Jk.default;n.escape&&(await Le(e,["Escape"],{kind:"swap-exit"}),await ii(150)),n.wipe&&await ls(e,cl,{kind:"swap-exit"}),await ll(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=pn(t).submitDelayMs||0;await ii(Math.max(r,250)),await Le(e,["Enter"],{kind:"swap-exit"})}async function Xk(e,t){try{let{stdout:n}=await lo(K,V("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function Zk(e){await lo(K,V("respawn-pane","-k","-t",e))}async function lp(e,t={}){if(!Pe(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await ge(e);if(!r)throw new Error(`session "${e}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${e}"`);let o=r.agent||"agent",s=t.agent||dr(n),a=Number(t.exitTimeoutMs)||xN;await re({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let i=!1;if(!await Mn(e)&&(await TN(e,o),!await cp(e,a)&&(i=!0,await re({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await Zk(e),!await cp(e,Yk))))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);let c=s==="claude"&&ro(n),l=c?Nc():null,u=await Xk(e,"ANTHROPIC_API_KEY"),f=!1;try{l?(await lo(K,V("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),f=!0):u&&(await lo(K,V("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),f=!0)}catch(g){throw l?nl(g,l):g}if(f&&!i&&(await Zk(e),!await cp(e,Yk)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let d=!!t.resumeSessionId,p=t.resumeSessionId||kN(),h=d?n:Ua(n,p,e),w=d?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(h);return c&&await or(r.cwd),s==="codex"&&await Jo(r.cwd),s==="cursor"&&await Xo(r.cwd),await oo(e),await lo(K,V("set-option","-t",e,"@bostrat-sid",p)),await lo(K,V("set-option","-t",e,"@bostrat-agent",s)),await ii(SN),c&&Fa().length&&(await Xk(e,La)||await lo(K,V("set-environment","-t",e,La,"1")).catch(()=>{}),await Ze(e,`export ${La}=1`,{kind:"swap-env"}),await ii(150)),await Ze(e,h,{kind:"swap-launch"}),await re({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:p,forced:i,envRespawned:f}),{name:e,cwd:r.cwd,sessionId:p,agent:s,pinned:w,forced:i,envRespawned:f,launchCmd:h}}var lo,ii,xN,Yk,vN,SN,Jk,Qk=j(()=>{lt();Ta();Dc();Bc();Qa();dn();lo=bN(yN),ii=e=>new Promise(t=>setTimeout(t,e)),xN=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,Yk=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,vN=250,SN=400,Jk={claude:{escape:!0,wipe:!0,text:"/exit"},codex:{escape:!0,wipe:!0,text:"/quit"},cursor:{escape:!0,wipe:!0,text:"/quit"},default:{escape:!1,wipe:!1,text:"exit"}}});async function e0(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await Et(e,t)}catch{return[]}let o=new Map,s=new Set;for(let i of r.split(`
156
+ `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.isSidechain)continue;let u=l.message?.content;if(!Array.isArray(u))continue;let f=l.timestamp?Date.parse(l.timestamp):null;for(let d of u)if(!(!d||typeof d!="object"))if(d.type==="tool_use"&&d.id){if(d.name==="Agent"){let p=d.input||{};o.set(d.id,{id:d.id,kind:"agent",name:String(p.description||"").trim()||null,detail:String(p.subagent_type||"").trim()||null,ts:f,proven:!1})}else if(d.name==="Bash"&&d.input?.run_in_background===!0){let p=String(d.input.command||"").trim();o.set(d.id,{id:d.id,kind:"command",name:String(d.input.description||"").trim()||(p?ps(p):null),detail:p?ps(p):null,ts:f,proven:!0})}}else d.type==="tool_result"&&d.tool_use_id&&EN.test(AN(d.content))&&s.add(d.tool_use_id)}let a=[];for(let i of o.values()){if(!i.proven&&!s.has(i.id))continue;let{proven:c,...l}=i;a.push(l)}return a.slice(-n)}var EN,AN,t0=j(()=>{Xt();ms();EN=/^Async (?:agent|task) launched/i,AN=e=>{if(typeof e=="string")return e.trim();if(!Array.isArray(e))return"";let t=e.find(n=>n&&n.type==="text"&&typeof n.text=="string");return t?t.text.trim():""}});function Sr(e,t){if(!e)return null;let n=String(e);if(t){let o=t.endsWith("/")?t:`${t}/`;if(n===t)return".";if(n.startsWith(o))return n.slice(o.length)||"."}let r=n.split("/").filter(Boolean);return n.startsWith("/")&&r.length>2?r.slice(-2).join("/"):n}function _N(e){let t=typeof e=="string"?e:String(e?.patch??e?.input??""),n=[];for(let r of t.matchAll(/^\*{3} (?:Update|Add|Delete) File: (.+)$/gm))n.push(r[1].trim());return n}function n0(e,t,n){switch(e){case"Shell":{let r=String(t?.command||"").trim();return r?{command:r,description:String(t?.description||"").trim()}:null}case"Read":{let r=t?.path;if(!r)return null;let o=Number(t?.offset)||null,s=o&&Number(t?.limit)?o+Number(t.limit)-1:null;return{command:Zt(`read ${Sr(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${xs(r)}`:`Read ${xs(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?Sr(t.path,n):null,s=t?.glob?` --glob ${up(t.glob)}`:"",a=Zt(String(r),40);return{command:Zt(`grep ${up(r)}${o&&o!=="."?` ${o}`:""}${s}`,140),description:o&&o!=="."?`Search for \u201C${a}\u201D in ${o}`:`Search for \u201C${a}\u201D`}}case"Glob":{let r=t?.glob_pattern;if(!r)return null;let o=t?.target_directory?Sr(t.target_directory,n):null;return{command:Zt(`glob ${up(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${Zt(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:Zt(`edit ${Sr(t.path,n)}`,140),description:`Edit ${xs(t.path)}`}:null;case"Write":return t?.path?{command:Zt(`write ${Sr(t.path,n)}`,140),description:`Write ${xs(t.path)}`}:null;case"Delete":return t?.path?{command:Zt(`delete ${Sr(t.path,n)}`,140),description:`Delete ${xs(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>Sr(s,n)).filter(Boolean);return{command:Zt(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=_N(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:Zt(`apply_patch ${Sr(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${xs(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:Zt(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var Ol,Zt,xs,up,r0=j(()=>{Ol=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),Zt=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,xs=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);up=e=>`"${String(e).replace(/"/g,'\\"')}"`});import ci from"node:fs";import IN from"node:fs/promises";import uo from"node:path";import $N from"node:os";import RN from"node:crypto";import ON from"node:zlib";function a0(e){let t=RN.createHash("md5").update(String(e)).digest("hex");return uo.join(CN,t)}function i0(e){try{let t=JSON.parse(ci.readFileSync(uo.join(e,"meta.json"),"utf8"));return{createdAtMs:Number(t.createdAtMs)||null,updatedAtMs:Number(t.updatedAtMs)||Number(t.createdAtMs)||null,hasConversation:t.hasConversation===!0}}catch{return null}}function MN(e){let t=a0(e),n;try{n=ci.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=uo.join(t,o.name),a=uo.join(s,"store.db");if(!ci.existsSync(a))continue;let i=i0(s);if(!i)continue;let c={id:o.name,dir:s,store:a,...i};(!r||c.hasConversation&&!r.hasConversation||c.hasConversation===r.hasConversation&&(c.updatedAtMs||0)>(r.updatedAtMs||0))&&(r=c)}return r}function Cl(e,t){if(!e)return null;if(t){let n=uo.join(a0(e),t),r=uo.join(n,"store.db");if(ci.existsSync(r))return{id:t,dir:n,store:r,...i0(n)||{createdAtMs:null,updatedAtMs:null}}}return MN(e)}function o0(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function NN(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=ON.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function PN(e){let t=[],n=0,r=e.length,o=()=>{let s=0,a=0;for(;n<r;){let i=e[n++];if(s+=(i&127)*2**a,!(i&128))break;a+=7}return s};for(;n<r;){let s=o(),a=s>>>3,i=s&7;if(i===2){let c=o(),l=e.subarray(n,n+c);n+=c,a===1&&c===32&&t.push(l.toString("hex"))}else if(i===0)o();else if(i===5)n+=4;else if(i===1)n+=8;else break}return t}function DN(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!Ol.has(r.toolName))continue;let o=n0(r.toolName,r.args,t);!o||!o.command||n.push({id:r.toolCallId||null,tool:r.toolName,command:o.command,description:o.description||""})}return n}async function dp(e,t){if(!s0)return vs;let{DatabaseSync:n}=s0,r;try{r=new n(e,{readOnly:!0})}catch{return vs}try{let o=r.prepare("SELECT value FROM meta WHERE key = '0'").get()||r.prepare("SELECT value FROM meta LIMIT 1").get();if(!o)return vs;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return vs}let a=s.lastUsedModel||null,i=s.latestRootBlobId?o0(r,s.latestRootBlobId):null;if(!i)return{...vs,model:a};let c=[],l=[],u=[],f=null,d=[];for(let p of PN(i)){let h=NN(o0(r,p));if(!h)continue;let w=h.providerOptions?.cursor;if(w?.requestId&&d.push(w.requestId),w?.modelProviderMessageId&&d.push(w.modelProviderMessageId),h.role!=="assistant")continue;if(Array.isArray(h.content))for(let S of h.content){let E=S?.providerOptions?.cursor?.modelName;E&&(f=E)}l.push(...DN(h.content,t).map((S,E)=>({...S,id:S.id||`${p}:${E}`}))),u.push(...jN(h.content));let g=BN(h.content);if(!g)continue;let k=[...new Set(u)];u=[],c.push({id:p,text:g,tools:k.length?k:void 0,commands:l,model:f}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:d}}catch{return vs}finally{try{r.close()}catch{}}}function c0(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(ci.statSync(e.store).mtimeMs)}catch{n=Date.now()}let r=e.createdAtMs;(!r||r>n)&&(r=n-t*1e3);let o=Math.max(0,n-r);return{end:n,tsAt:s=>Math.round(r+o*(s+1)/t)}}async function l0(e,t,{limit:n=80}={}){let r=Cl(e,t);if(!r)return[];let{turns:o,model:s}=await dp(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=c0(r,a.length);return a.map((c,l)=>({role:"assistant",text:c.text,tools:c.tools,ts:i(l),model:c.model||s,sourceId:c.id}))}async function u0(e,t){let n=Cl(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await dp(n.store,e);return{chatId:n.id,requestIds:o,models:[...new Set(r.map(a=>a.model).filter(Boolean))],configuredModel:s,updatedAtMs:n.updatedAtMs||null}}async function d0(e,t,{limit:n=80}={}){let r=Cl(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await dp(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=c0(r,a.length||1),l=[];a.forEach((u,f)=>{for(let d of u.commands)l.push({...d,summary:mr(d.command,d.description),ts:c(f)})});for(let u of s)l.push({...u,summary:mr(u.command,u.description),ts:i+1});return l}async function f0(e,t){let n=Cl(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await IN.stat(n.store)).mtimeMs)}catch{return null}}var CN,BN,jN,s0,vs,fp=j(()=>{ms();r0();CN=process.env.BOSTRAT_CURSOR_CHATS||uo.join($N.homedir(),".cursor","chats");BN=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
157
+ `).trim():"",jN=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],s0=process.getBuiltinModule?.("node:sqlite"),vs={turns:[],trailingCommands:[],model:null,requestIds:[]}});import LN from"node:fs/promises";function wp(e){return p0.set(e.agent,e),e}function li(e){return p0.get(e)||FN}async function yp(e,t={}){return(await li(e.agent).readMessages(e,t)).map(gp(e))}async function m0(e,t={}){return(await li(e.agent).readCommands(e,t)).map(gp(e))}async function h0(e,t={}){return(await li(e.agent).readJobs(e,t)).map(gp(e))}var Ss,pp,mp,hp,FN,p0,gp,w0=j(()=>{Xt();fl();ms();t0();fp();io();Ss=class{constructor(t,n=new Set){this.agent=t,this.cliTools=n}async readMessages(){return[]}async readCommands(){return[]}async readJobs(){return[]}async updatedAt(){return null}},pp=class extends Ss{transcript(t){return!t?.cwd||!t?.sessionId?null:Jt(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?If(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?cb(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?e0(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await LN.stat(n)).mtimeMs)}catch{return null}}},mp=class extends Ss{async readMessages(t,n){return l0(t.cwd,t.sessionId,n)}async readCommands(t,n){return d0(t.cwd,t.sessionId,n)}async updatedAt(t){return f0(t.cwd,t.sessionId)}},hp=class extends Ss{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return fb(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return pb(t.cwd,this.sessionId(t),n)}async updatedAt(t){return mb(t.cwd,this.sessionId(t))}},FN=new Ss("unknown"),p0=new Map;wp(new pp("claude",Sf));wp(new mp("cursor",Ol));wp(new hp("codex",za));gp=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function mo(e){let t=e.search(vp);return(t>=0?e.slice(0,t):e).trim()}function UN(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function HN(e){let t=String(e).trim();return!!(!t||po.test(e)||vp.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function WN(e,t=""){let n=[],r=/([☐☒])\s+([^☐☒←→✔]+)/g,o;for(;(o=r.exec(e))!==null;)n.push({label:o[2].trim(),answered:o[1]==="\u2612",current:!1});if(!n.length)return null;let s=qN(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function qN(e,t){let n=String(t).toLowerCase(),r=e.findIndex(c=>!c.answered),o=r>=0?r:e.length-1;if(!n)return o;let s=e.map(c=>{let l=c.label.toLowerCase(),u=l.split(/\s+/).filter(d=>d.length>3&&n.includes(d)).length;if(u)return u;let f=l.slice(0,8).trim();return f.length>=4&&n.includes(f)?1:0}),a=Math.max(...s);if(a===0||s[o]===a)return o;let i=s.flatMap((c,l)=>c===a?[l]:[]);return i.length===1?i[0]:o}function y0(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function KN(e,t=""){let n=String(e);if(!k0.test(n))return null;let r=n.replace(/\r/g,"").split(`
158
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(/^\s*Switch model\?\s*$/.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[];for(let u=o+1;u<r.length;u++){let f=r[u].match(fo);if(f)s.push({cursor:!!f[1],label:f[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let d=r[u].trim();d&&!po.test(r[u])&&a.push(d)}}if(s.length<2)return null;let i=s.map(u=>({label:mo(u.label),description:""})),c=Math.max(0,s.findIndex(u=>u.cursor)),l=["Switch model?",...a].join(" ");return{provider:"claude",box:t,multiSelect:!1,cursorIndex:c,promptId:`claude:model-confirm:${i.map(u=>u.label).join("|")}`.slice(0,240),questions:[{question:l,header:"Model",multiSelect:!1,options:i}]}}function VN(e,t=""){let n=String(e).replace(/\r/g,"").split(`
159
+ `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!x0.test(n[r]))return null;let o=r-1;for(;o>=0&&n[o].trim()==="";)o--;let s=[];for(;o>=0;o--){let c=n[o].match(fo);if(!c)break;s.unshift({cursor:!!c[1],n:Number(c[2]),label:c[4].trim()})}if(s.length<2||s.some((c,l)=>c.n!==l+1))return null;let a=[];for(let c=o;c>=0&&a.length<6&&!(GN.test(n[c])||po.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:mo(c.label),description:""}));return{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,s.findIndex(c=>c.cursor)),promptId:`claude:confirm-gate:${i.map(c=>c.label).join("|")}`.slice(0,240),questions:[{question:a.join(" ")||"Claude Code is asking you to confirm",header:"Confirm",multiSelect:!1,options:i}]}}function zN(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
160
+ `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(fo);l&&o.push({cursor:!!l[1],label:l[4].trim()})}let s=o.filter(c=>/^(submit answers|cancel)$/i.test(c.label));if(s.length<2)return null;let a=s.map(c=>({label:c.label,description:""})),i=Math.max(0,s.findIndex(c=>c.cursor));return{provider:"claude",box:t,multiSelect:!1,cursorIndex:i,review:!0,promptId:"claude:review:submit-answers",questions:[{question:"Ready to submit your answers?",header:"Review",multiSelect:!1,options:a}]}}function JN(e,t=""){let n=String(e);if(!bp.test(n))return null;let r=n.replace(/\r/g,"").split(`
161
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(YN.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[r[o].trim()];for(let u=o+1;u<r.length;u++){let f=r[u].match(fo);if(f)s.push({cursor:!!f[1],label:f[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let d=r[u].trim();d&&!po.test(r[u])&&a.push(d)}}if(s.length<2||!s.some(u=>bp.test(u.label)))return null;let i=s.map(u=>({label:mo(u.label),description:""})),c=Math.max(0,s.findIndex(u=>u.cursor)),l=a.join(" ");return{provider:"claude",box:t,multiSelect:!1,cursorIndex:c,promptId:`claude:resume-confirm:${i.map(u=>u.label).join("|")}`.slice(0,240),questions:[{question:l,header:"Resume",multiSelect:!1,options:i}]}}function Sp(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(fo);o&&t.push({line:r,cursor:!!o[1],n:Number(o[2]),label:o[4].trim()})}let n=t.sort((r,o)=>r.n-o.n);return n.length<2||n.some((r,o)=>r.n!==o+1)?null:n}function XN(e,t=""){let n=String(e);if(!v0.test(n)||!S0.test(n)||ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
162
+ `),o=Sp(r);return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(s=>s.cursor)),setup:"theme",promptId:`claude:setup:theme:${o.map(s=>s.label).join("|")}`.slice(0,200),questions:[{question:"Claude Code asks: choose the text style that looks best with your terminal. You can change it later with /theme.",header:"Theme",multiSelect:!1,options:o.map(s=>({label:mo(s.label),description:""}))}]}:null}function ZN(e,t=""){let n=String(e);if(!T0.test(n)||ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
163
+ `),o=Sp(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:mo(i),description:c.join("\xB7").trim()}});return{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(a=>a.cursor)),setup:"login-method",promptId:`claude:setup:login-method:${s.map(a=>a.label).join("|")}`.slice(0,200),questions:[{question:"How do you want to sign in to Claude? A Claude subscription (Pro/Max/Team) uses your existing plan; a Console account bills API usage. Your login stays on this box \u2014 bostrat never sees it.",header:"Log in",multiSelect:!1,options:s}]}}function eP(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!QN.test(o)||Tp.test(e[r]))break;n+=o}return n}function tP(e,t=""){let n=String(e);if(!Tp.test(n)||ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
164
+ `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=eP(r,s);break}return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,answerMode:"text",setup:"oauth",url:o,inputLabel:"Paste your sign-in code",promptId:"claude:setup:oauth",questions:[{question:"Open the sign-in link, approve access, then paste the code you're shown back here. The code goes straight to the Claude CLI on your box \u2014 bostrat relays the keystrokes and never stores it.",header:"Log in",multiSelect:!1,options:[]}]}:null}function rP(e,t=""){let n=String(e);if(!kp.test(n)||!nP.test(n)||ho.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
165
+ `)].reverse().find(a=>kp.test(a))||"OAuth error").trim();return{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,setup:"oauth-error",promptId:`claude:setup:oauth-error:${s}`.slice(0,200),questions:[{question:`${s} \u2014 retry to get a fresh sign-in link.`,header:"Log in",multiSelect:!1,options:[{label:"Retry sign-in",description:"Mints a new sign-in link and code"}]}]}}function oP(e,t=""){let n=String(e);if(!E0.test(n)||ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
166
+ `),o=Sp(r);return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(s=>s.cursor)),setup:"trust",promptId:`claude:setup:trust:${o.map(s=>s.label).join("|")}`.slice(0,200),questions:[{question:"Claude Code asks whether it can read, edit, and run files in this workspace. This box's workspace is bostrat-managed scratch space, so trusting it is safe.",header:"Folder trust",multiSelect:!1,options:o.map(s=>({label:mo(s.label),description:""}))}]}:null}function sP(e,t=""){let n=String(e);if(ho.test(n))return null;let r=n.replace(/\r/g,"").split(`
167
+ `),o=-1;for(let l=r.length-1;l>=0;l--)if(r[l].trim()!==""){o=l;break}if(o<0)return null;let s=r[o].match(A0);if(!s)return null;let a=[];for(let l=o-1;l>=0&&a.length<3;l--){let u=r[l].trim();if(!u){if(a.length)break;continue}if(po.test(r[l])||vp.test(u))break;a.unshift(u)}let i=s[1].trim();i&&a.push(i);let c=a.join(" ")||"Claude Code is waiting for you to continue.";return{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,setup:"continue",promptId:`claude:setup:continue:${c}`.slice(0,200),questions:[{question:c,header:"Continue",multiSelect:!1,options:[{label:"Continue",description:""}]}]}}function aP(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(xp.test(e[r])){t=r;break}if(t<0)return null;let n=-1;for(let r=t-1;r>=0;r--)if(/[☐☒]/.test(e[r])){n=r;break}return n<0?null:{headerLine:n,chatLine:t,optStart:n+1,optEnd:t}}function iP(e,t=""){let n=String(e);if(!b0.test(n)||!xp.test(n))return null;let r=n.replace(/\r/g,"").split(`
168
+ `),o=aP(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let O=i;O<c;O++){let I=r[O].match(fo);I&&(u<0&&(u=O),l.push({line:O,cursor:!!I[1],checked:I[3]!=null&&I[3]!==" ",hasCheckbox:I[3]!=null,label:I[4].trim(),desc:""}))}if(!l.length)return null;for(let O of l)for(let I=O.line+1;I<Math.min(r.length,O.line+4)&&!(fo.test(r[I])||po.test(r[I]));I++){let U=r[I].trim();if(!(!U||HN(r[I])||g0.test(U))){O.desc=UN(U);break}}let f=l.filter(O=>!g0.test(O.label));if(!f.length)return null;let d=f.some(O=>O.hasCheckbox),p=Math.max(0,f.findIndex(O=>O.cursor)),h=s>=0?s+1:0,w=[];for(let O=h;O<u;O++){let I=r[O].trim();I&&!po.test(r[O])&&!/[☐☒]/.test(r[O])&&w.push(I)}let g=w.join(" ")||(s>=0?y0(r[s]):"")||"The agent is asking a question",k=s>=0?WN(r[s],g):null,S=k?.currentTabLabel||(s>=0?y0(r[s]):""),E=f.map(O=>({label:mo(O.label),description:O.desc})),R=E.map(O=>O.label).join("|"),T=`claude:${k?`q${k.questionIndex+1}/${k.questionTotal}`:"q1/1"}:${S}:${g}:${R}`.slice(0,240),_=k?`claude:ask:${k.tabs.map(O=>O.label).join("|")}`.slice(0,240):T;return{provider:"claude",box:t,multiSelect:d,cursorIndex:p,promptId:T,groupId:_,...k?{questionIndex:k.questionIndex,questionTotal:k.questionTotal,currentTabLabel:k.currentTabLabel,tabs:k.tabs}:{},questions:[{question:g,header:S,multiSelect:d,options:E}]}}function wo(e,t){let n=String(t||"");return n?e==="claude"?b0.test(n)&&xp.test(n)||k0.test(n)||bp.test(n)||x0.test(n.trimEnd().split(`
169
+ `).pop()||"")?!0:ho.test(n)?!1:v0.test(n)&&S0.test(n)||T0.test(n)||Tp.test(n)||kp.test(n)||E0.test(n)||A0.test(n.trimEnd().split(`
170
+ `).pop()||""):e==="codex"&&/Sign in with ChatGPT|one-time code|Paste or type your API key|link to authenticate|Successfully logged in\.[\s\S]*Press Enter to continue\./i.test(n)?!0:e==="cursor"||e==="codex"?/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i.test(n):!1:!1}function Tr(e,t){return!e||!t?null:e.agent==="claude"?zN(t,e.name)||iP(t,e.name)||KN(t,e.name)||JN(t,e.name)||rP(t,e.name)||tP(t,e.name)||ZN(t,e.name)||XN(t,e.name)||oP(t,e.name)||sP(t,e.name)||VN(t,e.name):e.agent==="cursor"||e.agent==="codex"?$b(e.agent,t,e.name):null}async function Ep(e){if(!e)return null;let t=await Nn(e.name).catch(()=>"");return Tr(e,t)}function _0(e,t){let n=Array.isArray(t?.[0])?t[0].filter(a=>Number.isInteger(a)&&a>=0):[],r=Number.isInteger(e?.cursorIndex)?e.cursorIndex:0,o=(a,i)=>{let c=i-a;return Array.from({length:Math.abs(c)},()=>c>0?"Down":"Up")},s=[];if(e?.multiSelect){let a=r;for(let i of[...n].sort((c,l)=>c-l))s.push(...o(a,i),"Enter"),a=i;s.push("Tab","Enter")}else{let a=n.length?n[0]:0;s.push(...o(r,a),"Enter")}return s}function I0(e,t){let n=Number.isInteger(e?.questionIndex)?e.questionIndex:0,o=(Number.isInteger(t)?t:n)-n;if(!o)return[];let s=o>0?"Tab":"BTab";return Array.from({length:Math.abs(o)},()=>s)}var b0,xp,fo,g0,po,vp,k0,x0,GN,bp,YN,ho,v0,S0,T0,Tp,QN,kp,nP,E0,A0,Ap=j(()=>{lt();ml();b0=/to navigate\b.*\bEsc to cancel|Enter to select\b/,xp=/Chat about this/i,fo=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,g0=/^(type something|chat about this|submit)\b/i,po=/^[─—-]{6,}\s*$/,vp=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;k0=/^\s*Switch model\?\s*$/m;x0=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,GN=/^\s*[─—▔-]{6,}\s*$/;bp=/Resume from summary/i,YN=/^\s*This session is\b/;ho=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;v0=/Choose the text style that looks best with your terminal/,S0=/Let's get started\./;T0=/Select login method:/;Tp=/Paste code here if prompted/,QN=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;kp=/OAuth error:/,nP=/Press Enter to retry\./;E0=/Quick safety check: Is this a project you created or one you trust/;A0=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function Ml(e,t,n){if(!e||!t)return null;for(let r of cP)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function uP(e){let t=_p.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},_p.set(e,t)),t}function O0(e,t,n=Date.now()){let r=uP(e);if(r.sentAt=r.sentAt.filter(s=>n-s<R0),r.sentAt.length>=$0)return{action:"give-up"};if(n-r.last<lP)return{action:"wait"};r.last=n,r.sentAt.push(n);let o=!r.emitted.has(t);return o&&r.emitted.add(t),{action:"send",first:o}}function C0(e,t=Date.now()){let n=_p.get(e);return n?n.sentAt.filter(r=>t-r<R0).length>=$0:!1}var cP,lP,$0,R0,_p,Ip=j(()=>{cP=[{provider:"claude",id:"fullscreen-upsell",match(e,t){let n=e?.questions?.[0],r=(n?.options||[]).map(s=>String(s.label||"").trim());if(r.length!==2||!/^Yes, try it$/.test(r[0])||!/^Not now$/.test(r[1]))return!1;let o=`${n?.question||""}
171
+ ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];lP=5e3,$0=5,R0=3600*1e3,_p=new Map});function Ts(e){return typeof e=="string"?e.trim():""}var M0=j(()=>{});import{execFile as dP}from"node:child_process";import{promisify as fP}from"node:util";async function Ue(e,t,{input:n}={}){let r=Rp("git",["-C",e,...t],{maxBuffer:N0});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function Es(e){if(!e)return!1;try{let{stdout:t}=await Ue(e,["rev-parse","--is-inside-work-tree"]);return t.trim()==="true"}catch{return!1}}async function P0(e){let{stdout:t}=await Ue(e,["rev-parse","--show-toplevel"]);return t.trim()}async function pP(e){try{return await Ue(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function As(e,t="bostrat: subtask snapshot"){let{stdout:n}=await Ue(e,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>Rp("git",["-C",e,...a],{maxBuffer:N0,env:o,...i});try{let a=await pP(e);a&&await s(["read-tree","HEAD"]),await s(["add","-A"]);let{stdout:i}=await s(["write-tree"]),c=i.trim(),l=a?["commit-tree",c,"-p","HEAD","-m",t]:["commit-tree",c,"-m",t],{stdout:u}=await s(l);return u.trim()}finally{try{await Rp("rm",["-f",r])}catch{}}}async function Op(e,t,{trailers:n=[]}={}){let{stdout:r}=await Ue(e,["status","--porcelain"]);return r.trim()?(await Ue(e,["add","-A"]),await Ue(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",t,...n.flatMap(o=>["--trailer",o])]),!0):!1}async function ui(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await Ue(e,["status","--porcelain"]),r=n.split(`
172
+ `).filter(Boolean);return t&&(r=r.filter(o=>{let s=o.slice(3);return!(s===".bostrat"||s===".bostrat/"||s.startsWith(".bostrat/")||o.startsWith("??")&&(s==="AGENTS.md"||s==="CLAUDE.md"))})),r.length>0}async function di(e,t){if(!t)return 0;try{let{stdout:n}=await Ue(e,["rev-list","--count",`${t}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function _s(e,t,n,r){return await Ue(e,["worktree","add","--no-track","-b",n,t,r]),t}async function D0(e,t){try{return await Ue(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function Nl(e,t,n){return await Ue(e,["worktree","add",t,n]),t}async function Is(e){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:t}=await Ue(e,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(t.trim())return t.trim()}catch{}for(let[t,n]of[["refs/remotes/origin/main","origin/main"],["refs/remotes/origin/master","origin/master"],["refs/heads/main","main"],["refs/heads/master","master"]])try{return await Ue(e,["rev-parse","--verify","--quiet",t]),n}catch{}return"HEAD"}async function Cp(e){await Ue(e,["init","-q"]),await Ue(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function Rt(e,t){try{await Ue(e,["worktree","remove","--force",t])}catch{try{await Ue(e,["worktree","prune"])}catch{}}}function mP(e){let t=/(\d+) files? changed/.exec(e),n=/(\d+) insertions?\(\+\)/.exec(e),r=/(\d+) deletions?\(-\)/.exec(e);return{files:t?Number(t[1]):0,insertions:n?Number(n[1]):0,deletions:r?Number(r[1]):0}}function Mp(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function Np(e,t,n,r){let{stdout:o}=await Ue(e,Mp(["diff","--shortstat",t,n],r));return mP(o)}async function Pp(e,t,n,r){let{stdout:o}=await Ue(e,Mp(["diff","--name-only",t,n],r));return o.split(`
173
+ `).map(s=>s.trim()).filter(Boolean)}async function Dp(e,t,n,r){let{stdout:o}=await Ue(e,Mp(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await $p(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await $p(e,o,["--3way","--whitespace=nowarn"]),a=await hP(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await $p(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function $p(e,t,n){try{return await Ue(e,["apply",...n,"-"],{input:t}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function hP(e){try{let{stdout:t}=await Ue(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
174
+ `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var Rp,N0,Pl=j(()=>{Rp=fP(dP),N0=64*1024*1024});function Dl(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!wP.has(o.state)&&o.state!=="stopped"&&(o.state="stopped",r=!0);let s=Array.isArray(o.epochs)?o.epochs:[],a=s[s.length-1];a&&typeof a=="object"&&a.endedAt==null&&(a.endedAt=t,a.endReason==null&&(a.endReason=n),r=!0)}return r}var Ve,wP,Bn=j(()=>{Ve=e=>!!(e&&(e.archivedAt||e.transferredTo)),wP=new Set(["merged","conflict","canceled","failed","handed-off"])});import Bp from"node:fs/promises";import j0 from"node:path";import gP from"node:os";function H0(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function W0(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function q0(e){let t=new Date(H0(e));return t.setDate(t.getDate()+7),t.getTime()}function K0(e){let t=new Date(W0(e));return t.setMonth(t.getMonth()+1),t.getTime()}function jl(e=Date.now()){for(let[t,n]of Object.entries($s)){let r=n.startOf(e);if(r!==jn[t]){jn[t]=r;for(let o of go.values())o[t]=0;for(let o of Rs)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&Rs.delete(o)}}}function G0(e,t){let n=Qt?.caps?.[e]?.[$s[t].capKey];return Number.isFinite(n)&&n>0?n:null}function yo(e,t=Date.now()){if(!e||!Lp||!Qt?.caps)return null;jl(t);let n=go.get(e);for(let r of Object.keys($s)){let o=G0(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:Bl(s),resetsAt:$s[r].nextStart(t)}}return null}function V0(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${jn[t.window]}`;return Rs.has(n)?!1:(Rs.add(n),!0)}function B0(e,t,n,r=Date.now()){if(!e||!t)return;jl(r);let o=yP(e);for(let[s,a]of Object.entries($s))n>=jn[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function bP(e,t,n=Date.now()){if(!Qt?.caps||!jp)return;let r=go.get(e);if(r)for(let[o,s]of Object.entries($s)){let a=G0(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*U0||i>=a)continue;let c=`warn:${e}:${o}:${jn[o]}`;if(!Rs.has(c)){Rs.add(c);try{let l=await jp(t);if(!l)continue;await $(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:Bl(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function z0(e){let t={};for(let[n,r]of Object.entries(e||{})){if(typeof n!="string"||!/^[a-z][a-z0-9-]{0,31}$/.test(n))throw new Error(`bad provider key "${n}"`);let o={};for(let s of["weeklyUsd","monthlyUsd"]){let a=r?.[s];if(a==null||a==="")continue;let i=Number(a);if(!Number.isFinite(i)||i<=0)throw new Error(`${n}.${s} must be a positive number or null`);o[s]=i}Object.keys(o).length&&(t[n]=o)}return t}async function Ll(e,{source:t="local",updatedAt:n=Date.now()}={}){Qt={caps:z0(e),updatedAt:n,source:t};try{await Bp.mkdir(L0,{recursive:!0}),await Bp.writeFile(F0(),JSON.stringify(Qt,null,2))}catch{}return fi()}function fi(e=Date.now()){jl(e);let t=new Set([...go.keys(),...Object.keys(Qt?.caps||{})]),n={};for(let r of t){let o=go.get(r);n[r]={weeklyUsd:Bl(o?.weekly||0),monthlyUsd:Bl(o?.monthly||0)}}return{caps:Qt?.caps||{},configured:!!Qt,seeded:Lp,updatedAt:Qt?.updatedAt??null,spent:n,windows:{weekly:{start:jn.weekly,resetsAt:q0(e)},monthly:{start:jn.monthly,resetsAt:K0(e)}},warnPct:U0}}async function Y0({listTracks:e,getTrack:t}={}){jp=t||null,jl();try{let o=JSON.parse(await Bp.readFile(F0(),"utf8"));Qt={caps:z0(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{Qt=null}let n=Date.now();ct.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Ft(o);B0(o.provider||"unknown",s,o.ts??Date.now()),bP(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(jn.weekly,jn.monthly);for(let o of await e?.()||[]){let s;try{s=await F(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||B0(a.provider||"unknown",Ft(a).usd,i,n)}}return Lp=!0,fi()}var L0,F0,U0,$s,Qt,Lp,jn,go,Rs,jp,yP,Bl,Fl=j(()=>{me();vr();L0=process.env.BOSTRAT_STATE_DIR||j0.join(process.env.HOME||gP.tmpdir(),".bostrat"),F0=()=>j0.join(L0,"usage-caps.json"),U0=.8;$s={weekly:{startOf:H0,nextStart:q0,capKey:"weeklyUsd"},monthly:{startOf:W0,nextStart:K0,capKey:"monthlyUsd"}},Qt=null,Lp=!1,jn={weekly:0,monthly:0},go=new Map,Rs=new Set,jp=null,yP=e=>{let t=go.get(e);return t||(t={weekly:0,monthly:0},go.set(e,t)),t};Bl=e=>Math.round(e*1e4)/1e4});import kP from"node:fs/promises";import xP from"node:os";import J0 from"node:path";function rx(e){return e==="codex"?EP:e==="cursor"?nx:ex}function X0(e){let t=String(e||"").split(`
175
+ `),n=t.findIndex(o=>/Select Model and Effort/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+(\S+?)(?:\s+\((current|default)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),id:s[3],current:s[4]==="current",active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function Z0(e){let t=String(e||"").split(`
176
+ `),n=t.findIndex(o=>/Select Reasoning Level/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+([A-Za-z ]+?)(?:\s+\((default|current)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),label:s[3].trim(),isDefault:!!s[4],active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function AP(e){let t=String(e||"").split(`
177
+ `);for(let n=t.length-1;n>=0;n--){let r=t[n].match(/Model changed to\s+(\S+)(?:\s+(\S+))?\s*$/i);if(r)return{model:r[1],effort:r[2]||null}}return null}function Q0(e){let t=String(e||"").split(`
178
+ `),n=t.findIndex(s=>/Available models|Models matching/i.test(s));if(n<0)return null;let r=/Models matching/i.test(t[n]),o=[];for(let s=n+1;s<t.length;s++){let a=t[s];if(/^\s*Filter:/i.test(a)||!a.trim())continue;if(/to filter|Enter to select|^\s*\d+-\d+ of \d+/i.test(a))break;let i=a.match(/^\s*(→\s+)?(.+?)\s*$/);if(!i)continue;let c=i[2].replace(/\s*\(Tab to modify\)\s*$/i,""),l=null,u=c.split(/\s{2,}/);u.length>1&&(c=u[0],l=u.slice(1).join(" ").trim()||null),c&&o.push({label:c.trim(),params:l,active:!!i[1]})}return o.length?{filtered:r,rows:o}:null}function ox(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim();if(e==="codex"){let[r,o]=n.split(/[\s:]+/);if(o&&!tx.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=nx.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!TP.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function pi(e,t,{timeoutMs:n=vP}={}){let r=Date.now()+n;for(;;){let o=await Ce(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await Ul(SP)}}async function _P(e,t){return await Ze(e,`/model ${t.model}`,pn("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function IP(e,t){await il(e),await Ze(e,"/model",{enter:!1}),await Ul(250),await Le(e,["Enter"],{kind:"model-switch"});let n=await pi(e,X0);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await Le(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`unknown model "${t.model}" \u2014 codex offers: ${n.map(i=>i.id).join(", ")}`);let o=i=>{let c=AP(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await Ze(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await pi(e,i=>Z0(i)||!X0(i)&&o(i)&&{done:o(i)});if(!s)throw await Le(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?tx.get(t.effort):null,c=i?s.find(l=>l.label.toLowerCase()===i.toLowerCase()):s.find(l=>l.isDefault)||s[0];if(!c)throw await Le(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await Ze(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await pi(e,i=>!Z0(i)&&o(i));if(!a)throw new Error("codex never confirmed the model change");return{verified:!0,model:a.model,effort:a.effort}}async function $P(){let e=J0.join(process.env.CURSOR_CONFIG_DIR||J0.join(xP.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await kP.readFile(e,"utf8"))?.model||null}catch{return null}}async function RP(e,t){await il(e),await ll(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await pi(e,Q0),r=c=>String(c||"").toLowerCase(),o=c=>r(c.label).startsWith(r(t.filter)),s=n?.rows.find(c=>c.active)||null;if(n&&!(s&&o(s)))for(let c=0;c<12;c++){let l=await pi(e,Q0,{timeoutMs:1500});if(s=l?.rows.find(u=>u.active)||null,s&&o(s))break;if(!l||!l.rows.some(o)){s=null;break}await Le(e,["Down"],{kind:"model-switch"}),await Ul(250)}if(!n||!s||!o(s)){await Le(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await Le(e,c,{settleMs:15,kind:"model-switch"}).catch(()=>{}),new Error(n?`cursor picker has no model matching "${t.filter}"`:"cursor model picker didn't open")}await Le(e,["Enter"],{kind:"model-switch"}),await Ul(800);let a=await $P();return{verified:!!a&&(a.modelId===t.model||a.displayModelId===t.model||r(a.displayName).startsWith(r(t.filter))),model:a?.modelId||null,note:"cursor applies this as the global default for new sessions too"}}async function sx(e,t,n){return e==="codex"?IP(t,n):e==="cursor"?RP(t,n):_P(t,n)}var Ul,vP,SP,ex,TP,EP,tx,nx,ax=j(()=>{lt();Qa();Ul=e=>new Promise(t=>setTimeout(t,e)),vP=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,SP=300,ex=[{alias:"default",label:"Default"},{alias:"opus",label:"Opus 5"},{alias:"sonnet",label:"Sonnet 5"},{alias:"haiku",label:"Haiku 4.5"},{alias:"fable",label:"Fable 5"},{alias:"opusplan",label:"Opus Plan"}],TP=new Set([...ex.map(e=>e.alias),"best","opus[1m]","sonnet[1m]","claude-opus-5","claude-opus-4-8","claude-sonnet-5","claude-sonnet-4-6","claude-haiku-4-5","claude-fable-5"]),EP=[{alias:"gpt-5.6-sol",label:"GPT-5.6 Sol"},{alias:"gpt-5.6-terra",label:"GPT-5.6 Terra"},{alias:"gpt-5.6-luna",label:"GPT-5.6 Luna"},{alias:"gpt-5.5",label:"GPT-5.5"},{alias:"gpt-5.3-codex",label:"Codex 5.3"}],tx=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),nx=[{alias:"auto",label:"Auto"},{alias:"composer-2.5",label:"Composer 2.5"},{alias:"claude-opus-5",label:"Opus 5"},{alias:"claude-fable-5",label:"Fable 5"},{alias:"claude-sonnet-5",label:"Sonnet 5"},{alias:"claude-sonnet-4-6",label:"Sonnet 4.6"},{alias:"gpt-5.6-sol",label:"GPT-5.6 Sol"},{alias:"gpt-5.3-codex",label:"Codex 5.3"}]});function Wl(e){let t=e||{},n=OP(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function OP(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{text:e.text,boxRole:e.boxRole,...e.kind?{kind:e.kind}:{},...e.attachments?.length?{attachments:e.attachments}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{saidTs:e.saidTs,text:e.text,boxRole:e.boxRole}};case"orchestration-prompt":return{type:"turn.user",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{text:e.prompt,kind:e.kind,boxRole:e.boxRole}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:gt(e.toAgent),payload:{from:e.from,fromAgent:e.fromAgent,to:e.to,toAgent:e.toAgent,reason:e.reason,handoffStartedAt:e.handoffStartedAt,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,singleBox:e.singleBox,forced:e.forced,recovered:e.recovered,checkpoint:e.checkpoint}};case"lead-handoff-failed":return{type:"handoff.failed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.toAgent),payload:{box:e.box,fromAgent:e.fromAgent,toAgent:e.toAgent,reason:e.reason,error:e.error,rolledBack:e.rolledBack,handoffStartedAt:e.handoffStartedAt}};case"subtask-delegated":return{type:"subtask.delegated",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:gt(e.toAgent),payload:{task:e.task,subtaskId:e.subtaskId,reason:e.reason}};case"subtask-merged":return{type:"subtask.merged",actor:"orchestrator",source:"orchestrator",boxId:e.box||e.from,provider:gt(e.agent),payload:{...Er(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:gt(e.agent||e.toAgent),payload:{kind:"subtask-failed",...Er(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{change:"subtask-resumed",...Er(e)}};case"model-change":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"model",model:e.to,from:e.from??null,verified:e.verified??null}};case"codex-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:"codex",payload:{change:"cli-update",from:e.from??null,to:e.to??null,status:e.status,...e.error?{error:e.error}:{}}};case"node-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",payload:{change:"node-update",...Er(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...Er(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...Er(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{change:"rehydrated",...e.fresh?{fresh:!0}:{}}};case"lead-refreshed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{change:"lead-refreshed",box:e.box,agent:e.agent,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,reason:e.reason}};case"transferred-in":return{type:e.mode==="recover"?"track.recovered":"track.transferred",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{...Er(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...Er(e)}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};default:return null}}function lx(e,t){let n=Wl(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;Up(()=>$(r,n))}async function ux(e){if(!(!e?.id||ix.has(e.id))){ix.add(e.id);try{let t=await F(e),n=new Set(t.filter(r=>r.source==="orchestrator").map(r=>`${r.type}|${r.payload?.ts??"?"}`));for(let r of e.events||[]){let o=Wl(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await $(e,o)}}catch{}}}function Er(e){let{type:t,at:n,...r}=e;return r}function dx(e,t,n){!n?.promptId||Fp.get(e.id)===n.promptId||(Fp.set(e.id,n.promptId),Up(()=>$(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:gt(n.provider||t?.agent),payload:{promptId:n.promptId,question:n.question||n.title||null,options:(n.options||[]).map(r=>r?.label??r).slice(0,12)}})))}function Hp(e,t,n,r={}){Fp.delete(e.id),Up(()=>$(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:gt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var gt,Hl,Up,cx,ix,Fp,Wp=j(()=>{me();gt=e=>e||null;Hl=Promise.resolve(),Up=e=>(Hl=Hl.then(e).catch(()=>{}),Hl),cx=()=>Hl;ix=new Set;Fp=new Map});function DP(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function gx(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of DP(n).reverse()){if(!CP.test(r))continue;let o=r.endsWith("?")&&r.length<=PP&&NP.test(r);if(MP.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function bx(e){let t=String(e||""),n=[];BP.test(t)&&n.push("commit"),yx.test(t)&&n.push("rebase"),jP.test(t)&&n.push("push");let r=FP.test(t);!r&&LP.test(t)&&n.push("pr");let o=null;if(r){let s=t.match(/(?:pr|pull\s+request)\s*\(?\s*#(\d+)\)?/i)||t.match(/#(\d+)/);o={number:s?Number(s[1]):null}}return{offered:n.length?n:null,toPr:o}}function kx(e){return yx.test(String(e||""))}function Os(e,{branch:t=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1}={}){Array.isArray(e)||(e=e==="push"?["commit","push"]:["commit","push","pr"]);let a=new Set(e),i=Array.isArray(o)&&o.length>0,c=i?o.map(p=>`${p.name}/`).join(", "):null,l=t?` on this branch (${t})`:"",u=[];if(a.has("commit")&&u.push(i?`commit the work in each changed checkout (${c})${l} with a clear commit message per repo`:`commit the work${l} with a clear commit message`),a.has("rebase")){let p=a.has("commit")?"the branch":`this branch${t?` (${t})`:""}`;u.push(i?`rebase ${p} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${p} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`)}if(a.has("push")||a.has("pr")){let p=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",h=a.has("rebase")?" with `--force-with-lease` (the rebase rewrote history)":"";i?u.push(a.has("commit")||a.has("rebase")?`push each one to its remote${h}${p}`:`push this branch${t?` (${t})`:""} from each changed checkout (${c}) to its remote${p}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${h}${p}`:`push this branch${l} to the remote${p}`)}a.has("pr")&&u.push(i?"open a pull request in each changed repo with a concise title and a description of what changed and why (run `gh pr create` inside each checkout)":`open a pull request${n?` against ${n}`:""} with a concise title and a description of what changed and why (use \`gh pr create\`)`);let f=[];a.has("commit")||f.push("don't create any new commits \u2014 ship what's already committed"),s&&!a.has("rebase")&&f.push("don't rebase \u2014 leave the branch's history as it is"),!a.has("push")&&!a.has("pr")&&f.push("don't push"),a.has("pr")||f.push("don't open a pull request");let d=`Yes \u2014 go ahead: ${u.join(", then ")}.`;return f.length&&(d+=` ${f.join(", and ").replace(/^./,p=>p.toUpperCase())}.`),a.has("pr")&&(d+=i?" If a repo's PR for this branch is already open, just push that repo's update instead.":" If a PR for this branch is already open, just push the update instead."),d}function xx(e,{branch:t=null,base:n=null,prNumber:r=null,offeredRebase:o=!1}={}){let s=new Set(Array.isArray(e)?e:["commit","push","pr"]),a=t?` on this branch (${t})`:"",i=[];s.has("commit")&&i.push(`commit the work${a} with a clear commit message`),s.has("rebase")&&i.push(`rebase ${s.has("commit")?"the branch":`this branch${t?` (${t})`:""}`} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`),i.push("move the work to a fresh branch (branch off the current HEAD with a clear new name)"),i.push("push the new branch to the remote"),i.push(`open a pull request${n?` against ${n}`:""} from the new branch with a concise title and a description of what changed and why (use \`gh pr create\`)`);let c=[];s.has("commit")||c.push("don't create any new commits \u2014 ship what's already committed"),o&&!s.has("rebase")&&c.push("don't rebase \u2014 leave the branch's history as it is");let l=`Yes \u2014 go ahead, as a NEW pull request: ${i.join(", then ")}.`;return c.length&&(l+=` ${c.join(", and ").replace(/^./,u=>u.toUpperCase())}.`),l+=` Leave the existing open PR${r?` #${r}`:""}${t?` and its remote branch (${t})`:" and its remote branch"} exactly as they are \u2014 don't push ${t||"the old branch"} itself.`,l}function vx(e,t=Date.now()){let n=[],r=null;for(let o of e||[]){let s=o.payload||{},a=s.ts??o.ts;if(o.type==="pr.offer.answered"&&s.action==="pr"){r={box:o.boxId,from:a,lastActivity:a};continue}if(o.type==="pr.exists.answered"&&s.choice==="new"){r={box:o.boxId,from:a,lastActivity:a};continue}!r||a==null||a<r.from||(o.type==="pr.offer.answered"||o.type==="pr.exists.answered"?r=null:o.type==="pr.state.changed"&&s.change==="opened"?(n.push({box:r.box,from:r.from,to:a,settled:!0}),r=null):o.type==="turn.user"&&o.source!=="hook"&&!s.kind&&String(s.text||"").trim()?r=null:o.boxId===r.box&&/^(?:turn|tool)\./.test(o.type)&&(r.lastActivity=Math.max(r.lastActivity,a)))}return r&&t-r.lastActivity<=UP&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function Sx(e,t){let n=new Set;for(let r of t||[]){if(!r.settled)continue;let o=null;for(let s of e||[])s.kind!=="message"||s.role!=="assistant"||s.box!==r.box||s.ts==null||s.ts<r.from||s.ts>r.to+HP||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function Tx(e){let t=(Array.isArray(e)?e:[]).filter(r=>fx[r]).map(r=>fx[r]);return`The ship you were given the go-ahead for${t.length?` (${t.join(", then ")})`:""} should now be complete. This is an automated ship notification the operator armed on the offer: carry straight on with this Track's follow-up work (dependent tasks, cleanup, next steps) \u2014 don't wait for review or merge. If a ship step failed or is unfinished, finish the ship first. If nothing needs doing, say so briefly.`}var px,mx,hx,wx,CP,MP,NP,PP,Ar,BP,yx,jP,LP,FP,UP,HP,fx,bo=j(()=>{px=/(?<!\b(?:a|an|the|this|that|another|one|each|any|no|separate|single|new|initial|final|first|second|third|last|later|next|subsequent|extra|additional|amend(?:ed)?|squash|merge|follow[\s-]?up|clean[\s-]?up)\s)commit(?!s\b)(?!\s+(?:history|log|message|hash|sha)s?\b)/.source,mx=/(?<!\b(?:a|an|the|this|that|another|one|each|any|no|separate|single|new|initial|final|first|second|third|last|later|next|subsequent|extra|additional)\s)push(?!\s+notifications?\b)(?:\s+(?:it|this|that|them|everything|the\s+\w+))?\s*(?:up)?/.source,hx=/open(?:\s+up)?\s+(?:a|the|that)\s+(?:draft\s+)?(?:pr|pull\s+request)|creat(?:e|ing)\s+(?:a|the)\s+(?:draft\s+)?(?:pr|pull\s+request)|rais(?:e|ing)\s+(?:a|the)\s+(?:pr|pull\s+request)|put\s+up\s+(?:a|the)\s+(?:pr|pull\s+request)|send\s+(?:up\s+)?(?:a|the)\s+(?:pr|pull\s+request)/.source,wx=/(?<!\b(?:a|an|the|this|that|another|one|each|any|no|clean|interactive)\s)rebase(?!s\b)(?:\s+(?:it|this|that|them|(?:this|that|the)\s+branch))?(?:\s+(?:on(?:to)?|against|atop|over)\s+\S+)?/.source,CP=new RegExp(`\\b(?:${px}|${mx}|${hx}|${wx})\\b`,"i"),MP=/\b(?:want\s+me\s+to|would\s+you\s+like(?:\s+me)?(?:\s+to)?|should\s+i|shall\s+i|do\s+you\s+want(?:\s+me)?(?:\s+to)?|happy\s+to|ready\s+for\s+me\s+to|let\s+me\s+know\s+(?:if|when|whether|and)|say\s+the\s+word|give\s+me\s+the\s+(?:word|go[\s-]?ahead)|if\s+you(?:'d|\s+would)?\s+(?:like|want|prefer)|just\s+say\s+(?:so|yes|go))\b/i,NP=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,PP=90;Ar=["commit","rebase","push","pr"],BP=new RegExp(`\\b(?:${px})\\b`,"i"),yx=new RegExp(`\\b(?:${wx})\\b`,"i"),jP=new RegExp(`\\b(?:${mx})\\b`,"i"),LP=new RegExp(`\\b(?:${hx})\\b`,"i"),FP=/\b(?:to|into|onto|on|updat(?:e|es|ing))\s+(?:the|that|this)\s+(?:open\s+|existing\s+|current\s+|same\s+)?(?:draft\s+)?(?:pr|pull\s+request)\b/i;UP=3e4;HP=2500;fx={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import WP from"node:crypto";import ql from"node:fs/promises";import Ex from"node:path";import qP from"node:os";async function He(){return _r||(qp??=ql.readFile(Gp,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(_r=e,!t&&Ne()){let{records:n,source:r}=await et("prlinks").catch(()=>({records:[],source:"error"}));if(r==="plane"){for(let o of n){if(o.deletedAt||!o.data?.repo||o.data?.number==null)continue;let{id:s,updatedAt:a,...i}=o.data;_r[oe(i.repo,i.number)]=i}Object.keys(_r).length&&await Vp().catch(()=>{})}}return _r}).finally(()=>qp=null),qp)}async function Vp(){let e=JSON.stringify({links:_r},null,2),t=`${Gp}.${process.pid}.tmp`;await ql.mkdir(Ax,{recursive:!0}),await ql.writeFile(t,e),await ql.rename(t,Gp)}async function Qe(e){Kp=Kp.then(Vp,Vp),await Kp.catch(()=>{});let t=_r?.[e];t&&wt("prlinks",{id:_x(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function Ot({repo:e,number:t,trackId:n,url:r=null,headRef:o=null,title:s=null,source:a="matched"}){if(!e||!Number.isInteger(Number(t))||!n)return{link:null,created:!1};let i=await He(),c=oe(e,t);return i[c]?{link:i[c],created:!1}:(i[c]={repo:e,number:Number(t),trackId:n,url:r,headRef:o,title:s,source:a,announced:KP.has(a),firstSeen:Date.now()},await Qe(oe(e,t)),{link:i[c],created:!0})}async function Ln(e,t){if(!e||t==null)return null;let n=(await He())[oe(e,t)];return!n||n.announced?null:(n.announced=!0,await Qe(oe(e,t)),n)}async function tt(e,t){return!e||t==null?null:(await He())[oe(e,t)]??null}async function Ir(e,t,n){if(!e||t==null)return null;let r=(await He())[oe(e,t)];return r?(r.state=n,r.resolvedAt=Date.now(),delete r.armedAt,delete r.autoMerge,delete r.archiveOnMerge,delete r.notifyOnMerge,delete r.notifyPending,delete r.followupPending,await Qe(oe(e,t)),r):null}async function Ix(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await He())[oe(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Qe(oe(e,t)),o):null}async function $x(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await He())[oe(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Qe(oe(e,t)),o):null}async function Kl(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await He())[oe(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Qe(oe(e,t)),r)}async function Gl(e,t){if(!e||t==null)return null;let n=(await He())[oe(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Qe(oe(e,t)),n)}async function Vl(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await He())[oe(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Qe(oe(e,t)),r)}async function zl(e,t){if(!e||t==null)return null;let n=(await He())[oe(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Qe(oe(e,t)),n)}async function Rx(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await He())[oe(e,t)];return r?(r.baseFoldAt=n,await Qe(oe(e,t)),r):null}async function Ox(e,t){if(!e||t==null)return null;let n=(await He())[oe(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Qe(oe(e,t)),n)}async function Cx(e,t,n){if(!e||t==null||!n)return null;let r=(await He())[oe(e,t)];return r?(r.lastHeadSha=n,await Qe(oe(e,t)),r):null}async function Mx(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await He())[oe(e,t)];if(!r)return{prev:null,link:null};let o=r.verdict??null;return o&&o.blocked===(n.blocked??null)&&(o.sha??null)===(n.sha??null)||(r.verdict={blocked:n.blocked??null,sha:n.sha??null,at:n.at??Date.now()},await Qe(oe(e,t))),{prev:o,link:r}}async function mi(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await He())[oe(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Qe(oe(e,t)),r):null}async function ko(e,t,n=!0){if(!e||t==null)return null;let r=(await He())[oe(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Qe(oe(e,t)),r):null}async function hi(e,t,n=!0){if(!e||t==null)return null;let r=(await He())[oe(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Qe(oe(e,t)),r):null}async function Nx(e,t,n){if(!e||t==null)return null;let r=(await He())[oe(e,t)];if(!r)return null;r.notifyOnMerge=!0;let o=new Map((r.notifyPending||[]).map(s=>[`${s.repo}#${s.number}`,s]));for(let s of n||[])s&&s.number!=null&&o.set(`${s.repo}#${s.number}`,s);return r.notifyPending=[...o.values()],await Qe(oe(e,t)),r}async function Px(e,t,n){if(!e||t==null)return null;let r=(await He())[oe(e,t)];if(!r)return null;let o=new Map((r.followupPending||[]).map(s=>[`${s.repo}#${s.number}`,s]));for(let s of n||[])s&&s.number!=null&&o.set(`${s.repo}#${s.number}`,s);return r.followupPending=[...o.values()],await Qe(oe(e,t)),r}async function wi(e,t){if(!e||t==null)return null;let n=(await He())[oe(e,t)];return!n||!n.armedAt&&!n.autoMerge?null:(delete n.armedAt,delete n.autoMerge,delete n.archiveOnMerge,delete n.notifyOnMerge,delete n.notifyPending,await Qe(oe(e,t)),n)}async function Dx(){return Object.values(await He()).filter(e=>!GP.has(e.state))}async function xo(){return Object.values(await He()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function Bx(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await He(),r=0;for(let[o,s]of Object.entries(n))await wt("prlinks",{id:_x(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var Ax,Gp,oe,_x,_r,qp,Kp,KP,GP,Fn=j(()=>{ur();Ax=process.env.BOSTRAT_STATE_DIR||Ex.join(process.env.HOME||qP.tmpdir(),".bostrat"),Gp=Ex.join(Ax,"pr-links.json"),oe=(e,t)=>`${e}#${Number(t)}`,_x=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=WP.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},_r=null,qp=null,Kp=Promise.resolve();KP=new Set(["api","observed","reconciled"]);GP=new Set(["merged","closed","lost"])});import VP from"node:fs";import zp from"node:fs/promises";import Ux from"node:path";import zP from"node:os";function qx(e,t=!1){if(!t&&e-Lx<YP)return;Lx=e;let n=JSON.stringify({windowStart:Cs,byCaller:Object.fromEntries(Un),lastHour:$r});Fx=Fx.then(()=>zp.mkdir(Hx,{recursive:!0})).then(()=>zp.writeFile(`${Yl}.tmp`,n)).then(()=>zp.rename(`${Yl}.tmp`,Yl)).catch(()=>{})}function Kx(e){e-Cs<Wx||($r={start:Cs,total:Jl(Un),byCaller:Object.fromEntries(Un)},$r.total&&console.log(`[github] ${$r.total} calls last hour`,$r.byCaller),Cs=e,Un=new Map,qx(e,!0))}function Hn(e="other",t=Date.now()){Kx(t),Un.set(e,(Un.get(e)||0)+1),qx(t)}function Gx(e=Date.now()){return Kx(e),{windowStart:Cs,total:Jl(Un),byCaller:Object.fromEntries(Un),lastHour:$r,backoffUntil:vo>e?vo:null}}function Rr(e){return JP.test(String(e?.message||e||""))}function Or(e,t=Date.now()){return vo<=t&&console.warn(`[github] rate limited \u2014 backing off ${jx/6e4} min:`,String(e?.message||e||"").slice(0,200)),vo=Math.max(vo,t+jx),vo}function Xl(e=Date.now()){return Math.max(0,vo-e)}var Hx,Yl,Wx,jx,YP,Cs,Un,$r,vo,Lx,Jl,Fx,JP,gi=j(()=>{Hx=process.env.BOSTRAT_STATE_DIR||Ux.join(process.env.HOME||zP.tmpdir(),".bostrat"),Yl=Ux.join(Hx,"github-metrics.json"),Wx=60*6e4,jx=5*6e4,YP=6e4,Cs=Date.now(),Un=new Map,$r=null,vo=0,Lx=0,Jl=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(VP.readFileSync(Yl,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<Wx?(Cs=e.windowStart,Un=new Map(Object.entries(e.byCaller||{})),$r=e.lastHour||null):Jl(new Map(Object.entries(e.byCaller||{})))&&($r={start:e.windowStart,total:Jl(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}Fx=Promise.resolve();JP=/rate limit|too quickly|abuse detection|HTTP 429/i});import Vx from"node:fs/promises";import zx from"node:path";import XP from"node:os";function Ql({change:e,repo:t=null,number:n=null,githubAt:r=null,observedAt:o=Date.now(),lane:s=null,intervalMs:a=null,source:i=null}){let c=r?o-r:null,l={change:e,repo:t,number:n,githubAt:r,observedAt:o,latencyMs:c,lane:s,intervalMs:a,source:i};Zl.push(l),Zl.length>QP&&Zl.shift();let u=Yp.get(e)||{count:0,measured:0,totalMs:0,maxMs:0};return u.count+=1,c!=null&&(u.measured+=1,u.totalMs+=c,u.maxMs=Math.max(u.maxMs,c)),Yp.set(e,u),eD(l),l}async function eD(e){try{await Vx.mkdir(Yx,{recursive:!0}),await Vx.appendFile(ZP,JSON.stringify(e)+`
179
+ `)}catch{}}function Jx(){let e={};for(let[t,n]of Yp)e[t]={count:n.count,measured:n.measured,avgMs:n.measured?Math.round(n.totalMs/n.measured):null,maxMs:n.measured?n.maxMs:null};return{byChange:e,recent:Zl.slice(-20)}}var Yx,ZP,QP,Zl,Yp,eu=j(()=>{Yx=process.env.BOSTRAT_STATE_DIR||zx.join(process.env.HOME||XP.tmpdir(),".bostrat"),ZP=zx.join(Yx,"github-latency.ndjson"),QP=100,Zl=[],Yp=new Map});import{execFile as tD}from"node:child_process";import{promisify as nD}from"node:util";async function rD(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([Ns("git",["-C",e,"rev-parse","HEAD"]),Ns("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await $({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function Ut(e,t,n={}){let{caller:r="prs",...o}=n,s=await ln({cwd:e});Hn(r);try{let{stdout:a}=await Ns("gh",t,{cwd:e,...oD,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw Rr(a)&&Or(a),a}}async function Zp(){if(tu&&Date.now()-tu.at<6e4)return tu.data;let e;try{Hn("auth");let t=await Ns("gh",["auth","status"],{timeout:1e4});e={installed:!0,authenticated:!0,login:`${t.stdout||""}${t.stderr||""}`.match(/account\s+(\S+)/)?.[1]??null}}catch(t){e=t?.code==="ENOENT"||t?.code===127?{installed:!1,authenticated:!1,login:null}:{installed:!0,authenticated:!1,login:null}}if(e.installed&&!e.authenticated)try{let t=await _a();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return tu={at:Date.now(),data:e},e}async function sD(e){try{let{stdout:t}=await Ns("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function Zx(e){let t=e.name||e.context||"check",n=e.detailsUrl||e.targetUrl||null,r=e.completedAt||e.createdAt||null,o;return e.__typename==="StatusContext"?o=e.state==="SUCCESS"?"pass":e.state==="PENDING"||e.state==="EXPECTED"?"pending":"fail":e.status&&e.status!=="COMPLETED"?o="pending":["SUCCESS","NEUTRAL","SKIPPED"].includes(e.conclusion)?o="pass":o="fail",{name:t,state:o,url:n,completedAt:r}}function Jp(e){let t=(e||[]).map(Zx),n=t.filter(s=>s.state==="pending").length,r=t.map(s=>Date.parse(s.completedAt||"")).filter(s=>s>0),o=t.length&&!n&&r.length?Math.max(...r):null;return{total:t.length,passed:t.filter(s=>s.state==="pass").length,failed:t.filter(s=>s.state==="fail").length,pending:n,failing:t.filter(s=>s.state==="fail").map(({name:s,url:a})=>({name:s,url:a})),settledAt:o}}function em(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function ev(e,t){if(!t)return null;let n=await Se(e);if(!n)return null;try{let r=await Ut(e,["api",`repos/${n}/actions/runs?head_sha=${encodeURIComponent(t)}&per_page=100`,"--jq",".workflow_runs"]),o=new Map;for(let s of JSON.parse(r||"[]"))o.has(s.name)||o.set(s.name,s);return[...o.values()]}catch{return null}}function tv(e){return(e||[]).map(t=>({name:t.name,detailsUrl:t.html_url||null,status:String(t.status||"").toUpperCase(),conclusion:t.conclusion?String(t.conclusion).toUpperCase():null,completedAt:t.status==="completed"&&t.updated_at||null}))}async function nv(e,t){let n=await ev(e,t);return n===null?{...Jp([]),unavailable:!0}:Jp(tv(n))}function nu(e,t=Jp(e.statusCheckRollup)){return{number:e.number,title:e.title,url:e.url,author:e.author?.login??null,headRefName:e.headRefName,headSha:e.headRefOid??null,baseRefName:e.baseRefName,isDraft:!!e.isDraft,reviewDecision:e.reviewDecision||null,mergeable:e.mergeable||"UNKNOWN",mergeStateStatus:e.mergeStateStatus||"UNKNOWN",additions:e.additions??0,deletions:e.deletions??0,createdAt:e.createdAt,updatedAt:e.updatedAt,checks:t,green:t.failed===0&&t.pending===0&&e.mergeStateStatus==="CLEAN",autoMergeArmed:!!e.autoMergeRequest,mergeabilityPending:!1}}function iD(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){Ms.delete(s);continue}r.add(s),Ms.has(s)||Ms.set(s,n),o.mergeabilityPending=n-Ms.get(s)<aD}for(let o of Ms.keys())o.startsWith(`${e}#`)&&!r.has(o)&&Ms.delete(o);return t}async function Ps(e,t){let n=await Wn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await Ut(n.path,["pr","view",String(r),"--json",Qp]);return nu(JSON.parse(o))}catch(o){if(!em(o))throw o;let s=await Ut(n.path,["pr","view",String(r),"--json",Qx]),a=JSON.parse(s);return nu(a,await nv(n.path,a.headRefOid))}}async function hn(e,{caller:t="prs"}={}){try{let n=await Ut(e,["pr","list","--json",Qp,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>nu(r)).sort(Xx)}catch(n){if(!em(n))throw n;let r=await Ut(e,["pr","list","--json",Qx,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>nu(o,await nv(e,o.headRefOid))))).sort(Xx)}}function gn(){yi.clear()}async function uD(e,t){if(!e)return t;for(let n of t){let r=await tt(e,n.number).catch(()=>null);if(!r)continue;r.trackId&&(n.trackId=r.trackId),r.autoMerge&&(n.autoMergeArmed=!0),r.archiveOnMerge&&(n.archiveOnMerge=!0),r.notifyOnMerge&&(n.notifyOnMerge=!0);let o=s=>n.headSha&&s.headSha&&n.headSha!==s.headSha;r.ciFix&&(o(r.ciFix)?await Kl(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await Vl(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function rv(){let e=await Zp();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await On())await sD(a.path)&&t.push(a);let n=Date.now(),r=Xl(n)>0,o=await Promise.all(t.map(async a=>{let i=yi.get(a.path),c=i?.pending?lD:cD;if(i&&(r||n-i.at<c))return i.entry;try{let l=await Se(a.path).catch(()=>null),u=iD(a.path,await hn(a.path,{caller:"tab"}),n);if(await uD(l,u),i?.entry?.prs)for(let p of u)i.entry.prs.find(w=>w.number===p.number)?.checks?.pending>0&&p.checks.total>0&&p.checks.pending===0&&Ql({change:p.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:p.number,githubAt:p.checks.settledAt,source:"tab"});let f={name:a.name,path:a.path,prs:u},d=u.some(p=>p.mergeabilityPending||p.checks.pending>0||p.autoMergeArmed);return yi.set(a.path,{at:Date.now(),entry:f,pending:d}),f}catch(l){return i?i.entry:{name:a.name,path:a.path,prs:[],error:wn(l)}}})),s=new Set(t.map(a=>a.path));for(let a of yi.keys())s.has(a)||yi.delete(a);return{auth:e,repos:o}}async function Wn(e){let t=(await On()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function So(e){return Zo(e)}async function Ds(e,t,{method:n="squash"}={}){let r=await Wn(e);if(!bi.has(n))throw new Error(`invalid merge method: ${n}`);let o=Number(t);if(!Number.isInteger(o)||o<=0)throw new Error("invalid PR number");let s=["pr","merge",String(o),`--${n}`];if(n!=="rebase"&&(await ln({cwd:r.path})).GH_TOKEN){let a=await Hd().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await Ut(r.path,s)}catch(a){throw new Error(wn(a))}finally{gn()}return{ok:!0,number:o}}async function ki(e,t){let n=await Wn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Ut(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(wn(s))}finally{gn()}let o=await Se(n.path).catch(()=>null);return o&&await Rx(o,r).catch(()=>{}),{ok:!0,number:r}}async function tm(e,t){let n=await Wn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Ut(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(wn(o))}finally{gn()}return{ok:!0,number:r}}function nm(e){return e.green&&!e.isDraft}function mD(e){return e.isDraft?"draft":e.mergeable==="CONFLICTING"?`conflicts with ${e.baseRefName}`:e.checks.failed>0?"checks failing":e.checks.pending>0?"checks running":e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN"?"mergeability unresolved":e.mergeStateStatus==="BEHIND"?`behind ${e.baseRefName}`:e.mergeStateStatus==="BLOCKED"?"blocked by branch protection":`not clean (${e.mergeStateStatus})`}function ov(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:nm(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function sv(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function xi(e,t){let n=a=>a?.firstSeen!=null&&Number.isFinite(Number(a.firstSeen))?Number(a.firstSeen):Number.MAX_SAFE_INTEGER,r=n(e),o=n(t);if(r!==o)return r-o;let s=String(e?.repo||"").localeCompare(String(t?.repo||""));return s||Number(e?.number||0)-Number(t?.number||0)}function av(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(xi))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function iv(){let e={};for(let[t,n]of Xp)e[t]={...n};return e}async function cv(e,{method:t="merge",onMerged:n=null}={}){let r=await Wn(e);if(!bi.has(t))throw new Error(`invalid merge method: ${t}`);if(Xp.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await hn(r.path)).filter(nm).sort((a,i)=>Date.parse(a.createdAt)-Date.parse(i.createdAt));if(!o.length)throw new Error("no PRs ready to merge");let s={running:!0,startedAt:Date.now(),finishedAt:null,method:t,total:o.length,current:o[0].number,queue:o.map(a=>({number:a.number,title:a.title})),merged:[],skipped:[],failed:[]};return Xp.set(r.path,s),wD(s,o,{listPrs:()=>hn(r.path),merge:a=>Ds(r.path,a,{method:t}),sleep:pD,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function hD(e,t){let n=Date.now()+(t.settleMaxMs??fD),r=null;for(;;){let o=null;try{if(o=await t.listPrs(),r=null,!o.some(a=>e.includes(a.number)&&(a.mergeable==="UNKNOWN"||a.mergeStateStatus==="UNKNOWN")))return o}catch(s){r=s}if(Date.now()>=n){if(o)return o;if(r)throw r;return[]}await t.sleep(dD)}}async function wD(e,t,n){try{let r=t;for(let o=0;o<t.length;o++){let s=t[o];if(e.current=s.number,o>0)try{r=await hD(t.slice(o).map(i=>i.number),n)}catch(i){for(let c of t.slice(o))e.failed.push({number:c.number,title:c.title,reason:`couldn't re-check PR state: ${wn(i)}`});break}let a=r.find(i=>i.number===s.number);if(!a){e.skipped.push({number:s.number,title:s.title,reason:"no longer open"});continue}if(!nm(a)){e.skipped.push({number:a.number,title:a.title,reason:mD(a)});continue}try{await n.merge(a.number),e.merged.push({number:a.number,title:a.title});try{await n.onMerged?.(a)}catch{}}catch(i){e.failed.push({number:a.number,title:a.title,reason:wn(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),gn()}}async function rm(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await Ns("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${wn(l)}`)}await rD(e);let o=n||"";if((await ln({cwd:e})).GH_TOKEN){let l=await Hd().catch(()=>null);l&&(o=`${o?`${o}
180
+
181
+ `:""}Opened by bostrat on behalf of @${l}`)}let s=["pr","create","--title",t.trim(),"--body",o];r&&s.push("--base",r);let a;try{a=await Ut(e,s)}catch(l){throw new Error(wn(l))}finally{gn()}let i=a.match(/https:\/\/\S+\/pull\/\d+/)?.[0]??null,c=i?Number(i.match(/\/pull\/(\d+)/)?.[1]):null;return{ok:!0,url:i,number:c}}async function lv(e,t){let n=await Wn(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await Ut(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(wn(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!em(i))throw i;let c=await Ut(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await ev(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(wn(i));o=tv(l).map(Zx).filter(u=>u.state==="fail").map(u=>({name:u.name,link:u.url}))}let s=new Set,a=[];for(let i of o){let c=gD(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await Ut(n.path,["run","view",c,"--log-failed"]).then(u=>yD(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function gD(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function yD(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
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 Ns,oD,tu,Qp,Qx,aD,Ms,Xx,cD,lD,yi,bi,dD,fD,pD,Xp,Bs=j(()=>{ar();it();Fn();gi();eu();me();Ns=nD(tD),oD={timeout:3e4,maxBuffer:8*1024*1024};tu=null;Qp="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt",Qx=Qp.replace("statusCheckRollup,","");aD=9e4,Ms=new Map;Xx=(e,t)=>e.number-t.number;cD=3e4,lD=1500,yi=new Map;bi=new Set(["squash","merge","rebase"]);dD=2500,fD=9e4,pD=e=>new Promise(t=>setTimeout(t,e));Xp=new Map});import{execFile as bD}from"node:child_process";import{promisify as kD}from"node:util";async function vD(e,t){try{let{stdout:n}=await xD("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function SD(e,t,n,{rebase:r=!1,listPrs:o=hn}={}){let s=await ui(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await di(e.dir,n).catch(()=>0),i=t?await vD(e.dir,`refs/remotes/origin/${t}..HEAD`):null,c=i==null?a>0:i>0,l=null,u="unknown";try{l=(await o(e.dir,{caller:"ship-state"})||[]).find(w=>w.headRefName===t)||null,u=l?"open":"none"}catch{}let f=s||a>0,d=[];s&&d.push("commit"),r&&d.push("rebase"),(s||c)&&d.push("push"),f&&(u!=="open"||s||c)&&d.push("pr");let p=d.filter(h=>!(h==="pr"&&u==="open"));return{name:e.name??null,slug:e.repo??null,dirty:s,unpushed:c,aheadBase:a,prState:u,openPr:l?{number:l.number,url:l.url??null,title:l.title??null}:null,available:ru.filter(h=>d.includes(h)),defaults:ru.filter(h=>p.includes(h))}}async function ou(e,{branch:t,rebase:n=!1,listPrs:r=hn}={}){let o=e?.workspace,s=o?.kind==="multi"?(o.repos||[]).filter(d=>d?.dir):o?.base&&(o.dir||e?.cwd)?[{name:o.base?.split("/").pop()??null,dir:o.dir||e.cwd,repo:o.repo??null,baseRef:o.baseRef}]:[];if(!s.length||!await Es(s[0].dir).catch(()=>!1))return null;let a=[];for(let d of s)a.push(await SD(d,t,d.baseRef||o.baseRef,{rebase:n,listPrs:r}));let i=a.filter(d=>d.dirty||d.aheadBase>0||d.openPr),c=i.length?i:a,l=ru.filter(d=>c.some(p=>p.available.includes(d))),u=ru.filter(d=>c.some(p=>p.defaults.includes(d))),f=c.filter(d=>d.openPr);return{available:l,defaults:u,prState:f.length?"open":c.every(d=>d.prState==="none")?"none":"unknown",openPr:c.length===1?c[0].openPr:null,repos:c.map(d=>({name:d.name,slug:d.slug,dirty:d.dirty,unpushed:d.unpushed,prState:d.prState,openPr:d.openPr}))}}var xD,ru,om=j(()=>{Pl();Bs();xD=kD(bD),ru=["commit","rebase","push","pr"]});function su(e,t,n){let{state:r,reason:o}=Nf(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of vi)a-c.at>=uv()&&vi.delete(i);vi.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=vi.get(e);return s?Date.now()-s.at>=uv()?(vi.delete(e),!1):s.busy:!1}async function sm(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await Ce(e,{lines:Xe}).catch(()=>"");if(!su(e,t,r))return Pb(t,r)?{working:!0,prompted:!1}:n;if(wo(t,r)){let o=await Nn(e).catch(()=>r),s=Tr({name:e,agent:t},o);if(s)return!Ml({name:e,agent:t},s,o)||C0(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function To(e,t){return(await sm(e,t)).working}var uv,vi,Si=j(()=>{lt();Za();Ap();Ip();uv=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,vi=new Map});import{execFile as TD}from"node:child_process";import{promisify as ED}from"node:util";async function Cr(e){if(!e)return null;let t=dv.get(e);if(t&&Date.now()-t.at<_D)return t.branch;let n=null;try{let{stdout:r}=await AD("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return dv.set(e,{at:Date.now(),branch:n}),n}function fv(e){return String(e||"").match(ID)?.[1]??null}function $D(e,t){let n=fv(e);return!!n&&!!t&&n===t}function pv(e,t){let n=fv(e);return!!n&&n!==t}function RD(e){let t=e?.workspace;return t?.kind==="multi"?(t.repos??[]).map(n=>n?.dir).filter(Boolean):[t?.dir||e?.cwd].filter(Boolean)}async function js(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of RD(e))n(await Cr(r));return t}async function au(e,t,n=()=>!0){if(!t)return null;let r=(e??[]).filter(a=>a&&n(a)),o=r.find(a=>a.workspace?.branch===t);if(o)return o;let s=r.find(a=>$D(t,a.id));if(s)return s;for(let a of r)if(!Ve(a)&&(await js(a)).includes(t))return a;return null}var AD,_D,dv,ID,Eo=j(()=>{Bn();AD=ED(TD),_D=5e3,dv=new Map;ID=/^track\/.+-([0-9a-f]{8})$/});import{execFile as OD}from"node:child_process";import{promisify as CD}from"node:util";async function am(e,t,{midTurn:n=To,pollMs:r=MD,capMs:o=ND}={}){let s=Date.now()+o;for(;await n(e,t).catch(()=>!1);){if(Date.now()>=s)return!1;await new Promise(a=>setTimeout(a,r))}return!0}function bv(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){mv.lastIndex=n;let o=mv.exec(t);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=t.indexOf(`
187
+ `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+UD(a)+"[ \\t]*$","m").exec(t.slice(i+1));if(!l)continue;let u=i+1+l.index+l[0].length;t=t.slice(0,i)+t.slice(u)}return t}function im(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function xv(e){let t=bv(e),n=t.match(jD);if(!n)return null;let r=im(t,n.index);return FD.test(r)?null:{repo:r.match(kv)?.[1]??null,head:r.match(HD)?.[1]??null}}function vv(e){let t=bv(e),n=t.match(LD);if(!n)return null;let r=im(t,n.index),o=im(t,n.index+n[0].length),s=null,a=o.trim().split(/\s+/).filter(Boolean);for(let i=0;i<a.length;i++){let c=a[i];if(c.startsWith("-")){qD.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(kv)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function GD(e,t,{exclude:n=()=>!1}={}){let r=async i=>{Hn("observer");let{stdout:c}=await hv("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",KD],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw Rr(l)&&Or(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-PD&&!n(c)),s=await ln({slug:e}),a=o(await r(s));return!a.length&&s.GH_TOKEN&&(a=o(await r({}).catch(()=>[]))),a.sort((i,c)=>Date.parse(c.createdAt)-Date.parse(i.createdAt))}async function VD(e,t){if(t)return[t];let n=[];for(let r of Sv(e)){let o=await Se(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await On().catch(()=>[])){let o=await Se(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function Sv(e){let t=e.workspace;return t?.kind==="multi"?(t.repos??[]).map(n=>n?.base).filter(Boolean):[t?.base||e.cwd].filter(Boolean)}async function zD(e,t,n){let r=await js(e).catch(()=>[e.workspace?.branch].filter(Boolean)),o=t?.head??null,s=c=>r.includes(c)||o&&c===o,a=c=>o!=null&&!s(c.headRefName)||WD(c.headRefName,e.id),i=[];for(let c of await VD(e,t?.repo??null)){let l;try{l=await GD(c,n,{exclude:a})}catch{continue}for(let u of l){let f=await tt(c,u.number);if(s(u.headRefName)){if(f&&f.trackId===e.id&&f.announced)return{settled:!0};if(f&&f.trackId!==e.id)continue;return{slug:c,pr:u}}f&&(f.trackId!==e.id||f.announced)||i.push({slug:c,pr:u})}}return i.length?(i.sort((c,l)=>Date.parse(l.pr.createdAt)-Date.parse(c.pr.createdAt)),i[0]):null}function Tv(e,t,{delays:n=wv,turnEnd:r}={}){let o=xv(t.command);if(!o)return null;let s=!!vv(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(Mr.has(a))return null;Mr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(w=>setTimeout(w,l));let u=await zD(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:f,pr:d}=u,{link:p,created:h}=await Ot({repo:f,number:d.number,trackId:e.id,url:d.url,headRef:d.headRefName,title:d.title,source:"observed"});return!h&&!(p?.trackId===e.id&&await Ln(f,d.number))?null:(await am(t.box,t.agent,r),await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"opened",number:d.number,url:d.url,title:d.title,branch:d.headRefName,repo:f,...s?{selfMerge:!0}:{}}}),d)}return null}finally{Mr.delete(a)}})();return c.catch(()=>Mr.delete(a)),c}function Ev(e,t,{delays:n=wv,turnEnd:r,openedWait:o}={}){let s=vv(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(Mr.has(a))return null;Mr.add(a);let i=(async()=>{try{let c=s.repo,l=s.selector,u=l?.match(/github\.com\/([\w.-]+\/[\w.-]+)\/pull\/(\d+)/);u&&([,c,l]=u);let f=[];if(c)f=[c];else{let h=Sv(e);if(h.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let w of h){let g=await Se(w).catch(()=>null);g&&!f.includes(g)&&f.push(g)}}if(l||=(await js(e).catch(()=>[])).filter(h=>h!==e.workspace?.branch)[0]||e.workspace?.branch,!f.length||!l)return null;c=f[0];let d=async(h,w)=>{let g=await tt(c,h.number);return g&&g.trackId!==e.id?null:(g||await Ot({repo:c,number:h.number,trackId:e.id,url:h.url,headRef:h.headRefName,title:h.title,source:"merge-observed"}),await mi(c,h.number),w&&((await F(e).catch(()=>[])).some(E=>E.type==="pr.state.changed"&&(E.payload?.change==="auto-armed"||E.payload?.change==="merged")&&E.payload?.number===h.number)||(await am(t.box,t.agent,r),await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:h.number,url:h.url,title:h.title,branch:h.headRefName,repo:c}}))),h)},p=null;for(let h of n){await new Promise(T=>setTimeout(T,h));let w=[];for(let T of f)try{Hn("observer");let{stdout:_}=await hv("gh",["pr","view",String(l),"--repo",T,"--json",YD],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await ln({slug:T})}}),O=JSON.parse(_||"null");O?.number&&w.push({slug:T,pr:O})}catch(_){Rr(_)&&Or(_)}let g=w.find(T=>T.pr.state==="MERGED")??(w.length===1?w[0]:null);if(!g)continue;c=g.slug;let k=g.pr;if(!k?.number)continue;if(k.state==="CLOSED")return null;if(k.state!=="MERGED"){if(p=k,s.auto)return d(k,!0);continue}let S=await tt(c,k.number);if(S&&S.trackId!==e.id)return null;S||await Ot({repo:c,number:k.number,trackId:e.id,url:k.url,headRef:k.headRefName,title:k.title,source:"merge-observed"}),await am(t.box,t.agent,r);let E=await F(e).catch(()=>[]);if(E.some(T=>T.type==="pr.state.changed"&&T.payload?.change==="merged"&&T.payload?.number===k.number))return null;let R=T=>T.some(_=>_.type==="pr.state.changed"&&_.payload?.change==="opened"&&_.payload?.number===k.number),B=0;if(!R(E)){if(xv(t.command)&&await Ln(c,k.number)){let T=Date.now();B=T+1,await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:T,change:"opened",number:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c,selfMerge:!0}})}else if((await tt(c,k.number))?.announced){let T=o?.capMs??DD,_=o?.pollMs??BD,O=Date.now()+T;for(;Date.now()<O&&(await new Promise(I=>setTimeout(I,_)),!R(await F(e).catch(()=>[]))););}}return await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Math.max(Date.now(),B),change:"merged",number:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c}}),await Kn(c,k.number).catch(()=>{}),await qn(c,k.number).catch(()=>{}),await Ir(c,k.number,"merged"),k}return p?d(p,!1):null}finally{Mr.delete(a)}})();return i.catch(()=>Mr.delete(a)),i}var hv,wv,MD,ND,PD,DD,BD,gv,yv,jD,LD,FD,mv,UD,kv,HD,WD,qD,KD,Mr,YD,Av=j(()=>{me();ar();it();gi();Fn();Nr();Si();Eo();hv=CD(OD),wv=[4e3,15e3,45e3],MD=2500,ND=5*6e4;PD=15e3,DD=9e4,BD=2e3,gv=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,yv=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,jD=new RegExp(`${gv}${yv}create\\b`),LD=new RegExp(`${gv}${yv}merge\\b`),FD=/\s--web\b/,mv=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,UD=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");kv=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,HD=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,WD=pv;qD=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);KD="number,url,title,headRefName,createdAt";Mr=new Set;YD="number,url,title,headRefName,state"});import JD from"node:fs/promises";import lm from"node:path";import XD from"node:os";function cm(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function iu(e){let t=ZD.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=cm(n,"from"),s=o?o.replace(/^uds:/,""):null,a=_v(s);return{socket:s,pid:a,name:cm(n,"from-name"),mode:cm(n,"from-mode"),text:r.trim()}}function _v(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function QD(){return process.env.CLAUDE_CONFIG_DIR?lm.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):lm.join(XD.homedir(),".claude","sessions")}async function eB(e){let t=_v(e);if(!t)return null;try{let n=await JD.readFile(lm.join(QD(),`${t}.json`),"utf8"),r=JSON.parse(n);return{pid:t,sessionId:r.sessionId??null,cwd:r.cwd??null,name:r.name??null,tmux:r.tmux??null}}catch{return null}}async function Iv(e,t){let n=await eB(e?.socket),r=n?.cwd??null,o=null;if((n?.sessionId||r)&&typeof t=="function")try{o=await t(n?.sessionId??null,r)??null}catch{o=null}return{socket:e?.socket??null,pid:n?.pid??e?.pid??null,sessionId:n?.sessionId??null,cwd:r,tmux:n?.tmux??null,name:n?.name??e?.name??null,mode:e?.mode??null,trackId:o?.track?.id??null,trackName:o?.track?.name??null,boxId:o?.box?.name??null}}var ZD,um=j(()=>{ZD=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function dm(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function fm({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!dm(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),$v);try{let a=await Rv(`${Ie(r)}/v1/loops/${encodeURIComponent(e)}/report`,{method:"POST",headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN||""}`,"content-type":"application/json"},body:JSON.stringify({outcome:t,...n?{note:n}:{}}),signal:o.signal}),i=await a.json().catch(()=>({}));return a.ok?{ok:!0,source:"plane",status:a.status,run:i?.run||null}:{ok:!1,source:"plane",status:a.status,error:i?.error||`plane ${a.status}`}}catch(a){return{ok:!1,source:"unreachable",error:a?.message||String(a)}}finally{clearTimeout(s)}}async function Ov(e,{provider:t=null,cls:n="other",status:r=null,text:o=""}={},{env:s=process.env,now:a=Date.now}={}){if(!e?.id||!String(e.name||"").startsWith("\u21BB"))return{ok:!1,source:"not-a-loop-track"};if(!dm(s))return{ok:!1,source:"unconfigured"};let i=cu.get(e.id)||0;if(a()-i<tB)return{ok:!1,source:"debounced"};cu.set(e.id,a());let c=await Ti({env:s}),l=c.loops.find(d=>d.trackId===e.id);if(!l)return cu.delete(e.id),{ok:!1,source:c.source==="plane"?"no-loop":c.source};let u=`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`.slice(0,500),f=await fm({loopId:l.id,outcome:"errored",note:u,env:s});return f.ok||cu.delete(e.id),{...f,loop:{id:l.id,name:l.name}}}async function Ti({env:e=process.env}={}){if(!dm(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),$v);try{let r=await Rv(`${Ie(e)}/v1/loops`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`},signal:t.signal});if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json();return{loops:Array.isArray(o?.loops)?o.loops:[],source:"plane"}}catch(r){return{loops:[],source:"unreachable",error:r?.message||String(r)}}finally{clearTimeout(n)}}var $v,Rv,tB,cu,pm=j(()=>{it();$v=1e4,Rv=(...e)=>fetch(...e);tB=10*6e4,cu=new Map});function Cv(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Mv(e,t,n=mm){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await rB(`${Ie(t)}${e}`,{headers:oB(t),signal:r.signal})}finally{clearTimeout(o)}}async function Ei({env:e=process.env,force:t=!1,timeoutMs:n=mm}={}){if(!Cv(e))return{followups:[],source:"unconfigured"};if(!t&&Ao&&Date.now()-Ao.at<nB)return{followups:Ao.followups,source:"cache"};try{let r=await Mv("/v1/followups?deleted=1",e,n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.followups)?o.followups:[];return Ao={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return Ao?{followups:Ao.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function Nv(e,{env:t=process.env,timeoutMs:n=mm}={}){if(!e)return{followup:null,source:"unconfigured"};if(!Cv(t))return{followup:null,source:"unconfigured"};try{let r=await Mv(`/v1/followups/${encodeURIComponent(e)}`,t,n);if(r.status===404)return{followup:null,source:"gone"};if(!r.ok)throw new Error(`plane ${r.status}`);return{followup:(await r.json())?.followup??null,source:"plane"}}catch(r){let o=Ao?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var nB,mm,Ao,rB,oB,Pv=j(()=>{it();nB=6e4,mm=5e3,Ao=null,rB=(...e)=>fetch(...e);oB=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import{randomUUID as Fs,createHash as sB}from"node:crypto";function Lv(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function uB(e){for(let[t,n]of lB)if(t.test(String(e||"")))return`a standing prompt must not embed this Track's specifics (${n}) \u2014 the card supplies them at fire time; arm a one-shot with \`offer\` instead`;return null}function Fv(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=Ls(n.label).replace(/\s+/g," ");if(!r)throw new Error('label required (\u226460 chars, e.g. "Deploy to Pi")');if(r.length>Dv)throw new Error(`label must be \u2264${Dv} characters`);let o=Ls(n.trigger)||(n.ship?"now":""),s=t?iB:jv.filter(u=>u!=="track.opened");if(!s.includes(o))throw new Error(`trigger must be one of ${s.join(" | ")}${t?" (a standing follow-up can't be `now` \u2014 it would fire every turn)":""}, got "${n.trigger??""}"`);let a=n.ship&&o==="now"?fB(n.ship):null,i=Ls(n.prompt);if(!a&&!i)throw new Error("prompt required \u2014 the full instruction a fresh session could execute");if(Buffer.byteLength(i,"utf8")>Bv)throw new Error(`prompt must be \u2264${Bv} bytes`);if(t){let u=uB(i);if(u)throw new Error(u)}let c=Ls(n.why).slice(0,aB)||null,l=t?dB(n.repo):null;return{label:r,prompt:i,trigger:o,why:c,...l?{repo:l}:{},...a?{ship:a}:{}}}function dB(e){if(e==null||e===""||e==="*")return null;let t=String(e).trim();if(!/^[\w.-]+\/[\w.-]+$/.test(t))throw new Error(`repo must be a forge slug like owner/name, got "${e}"`);return t}function fB(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):hm.slice();for(let i of n)if(!hm.includes(i))throw new Error(`ship.actions may only contain ${hm.join(" | ")}, got "${i}"`);if(!n.length)throw new Error("ship.actions must name at least one of commit | push | pr");let r=t.rebase==null?"none":String(t.rebase).trim();if(!["offered","none"].includes(r))throw new Error(`ship.rebase must be "offered" or "none", got "${t.rebase}"`);let o=null;if(t.toPr!=null&&t.toPr!==""){let i=Number(t.toPr);if(!Number.isInteger(i)||i<=0)throw new Error(`ship.toPr must be a PR number, got "${t.toPr}"`);o=i}let s=Ls(t.base)||null,a=null;if(t.repos!=null){if(!Array.isArray(t.repos))throw new Error("ship.repos must be an array of checkout names");a=t.repos.map(i=>Ls(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function lu(e,{trigger:t=null}={}){let n=new Map;for(let r of e){let o=r.payload||{};if(r.type==="followup.armed"&&o.armId)o.replaces&&n.delete(o.replaces),n.set(o.armId,{...o,ts:o.ts??r.ts,boxId:r.boxId??null,provider:r.provider??null});else if(r.type==="followup.armed.cancelled"&&o.armId)n.delete(o.armId);else if(r.type==="followup.offered")for(let s of o.rows||[])s.armId&&n.delete(s.armId)}return[...n.values()].filter(r=>!t||r.trigger===t)}async function Uv(e,t,{pull:n=Ei,ship:r={}}={}){if(ym(e))throw new Error("follow-ups don't fire on a loop's run Track \u2014 report the outcome with `bostrat-loop report` instead");let o=Fv(t);if(o.ship)return{kind:"ship",...await hB(e,o,r)};let s={id:e.id,cwd:e.cwd},a=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,i={boxId:e.leadBox??null,provider:a?.agent??null};if(o.trigger==="now"){let g=Fs(),k=Fs();return await $(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:g,trigger:"now",label:o.label,prompt:o.prompt,why:o.why}}),await $(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:k,trigger:"now",repo:e.workspace?.repo||null,context:{},rows:[{armId:g,label:o.label,prompt:o.prompt,promptHash:wm(o.prompt),origin:"agent",why:o.why}]}}),{kind:"now",armId:g,offerId:k,...o}}let c=e.workspace?.repo||null,{followups:l}=await n().catch(()=>({followups:[]})),u=Lv(o.label),f=l.find(g=>g.status==="active"&&g.mode!=="off"&&g.trigger===o.trigger&&(g.repo==null||g.repo===c)&&g.dedupeKey===u);if(f)return{kind:"covered",covered:{id:f.id,label:f.label},...o};let d=await F(s),p=lu(d,{trigger:o.trigger}),h=p.length?p[p.length-1].armId:null,w=Fs();return await $(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:w,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,...h?{replaces:h}:{}}}),{kind:"armed",armId:w,replaces:h,...o}}async function Hv(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await F(n);if(!lu(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await $(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function Wv(e,t,{pull:n=Ei}={}){if(ym(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=Fv(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await F(s)).reduce((g,k)=>k.type==="followup.create.offered"?k.payload?.proposalId??g:k.type==="followup.create.answered"&&k.payload?.proposalId===g?null:g,null))throw new Error("a follow-up proposal is already waiting on the operator in this Track \u2014 one at a time");let{followups:c,source:l}=await n().catch(()=>({followups:[],source:"unreachable"}));if(l==="unreachable")throw new Error("plane unreachable \u2014 standing follow-ups live in the plane; try again shortly");let u=Lv(r.label),f=c.filter(g=>g.dedupeKey===u&&g.trigger===r.trigger),d=f.find(g=>g.status==="deleted"),p=f.find(g=>g.status!=="deleted");if(p)throw new Error(`"${p.label}" (${gm[p.trigger]||p.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(d){let g=d.deletedAt?new Date(d.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${d.label}" on ${g} \u2014 do not re-propose it`)}let h=Fs(),w=(e.boxes||[]).find(g=>g.name===e.leadBox)||null;return await $(s,{type:"followup.create.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:w?.agent??null,payload:{ts:Date.now(),proposalId:h,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why,origin:"agent"}}),{proposalId:h,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why}}async function qv(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await F(o),a=s.find(c=>c.type==="followup.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="followup.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await $(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("followupId required \u2014 the follow-up is created on the plane before the card is answered");let i=a.payload;return await $(o,{type:"followup.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,followupId:String(r),label:i.label,trigger:i.trigger,repo:i.repo??null}}),await $(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",followupId:String(r)}}),{proposalId:t,action:"created",followupId:String(r)}}async function Ai(e,t,n={},{pull:r=Ei}={}){if(!e||ym(e))return null;let o={id:e.id,cwd:e.cwd},s=await F(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null,i=lu(s,{trigger:t}).map(d=>({armId:d.armId,label:d.label,prompt:d.prompt,promptHash:wm(d.prompt),origin:"agent",why:d.why??null})),c=[];if(t!=="now"){let{followups:d}=await r().catch(()=>({followups:[]}));c=d.filter(p=>p.status==="active"&&p.mode!=="off"&&p.trigger===t&&(p.repo==null||p.repo===a)).sort((p,h)=>{let w=g=>g.stats?.offered?(g.stats.accepted||0)/g.stats.offered:0;return w(h)-w(p)||(p.origin==="operator"?-1:0)-(h.origin==="operator"?-1:0)||(h.createdAt||0)-(p.createdAt||0)}).map(p=>({followupId:p.id,label:p.label,promptPreview:pB(p.prompt),promptHash:wm(p.prompt),origin:p.origin,repo:p.repo??null}))}let l=[...i,...c].slice(0,cB);if(!l.length)return null;let u=Fs(),f={ts:Date.now(),offerId:u,trigger:t,repo:a,context:{...n,repo:a},rows:l};return await $(o,{type:"followup.offered",actor:"system",source:"orchestrator",payload:f}),f}function mB(e){let t=e?.context||{},n=Array.isArray(t.prs)&&t.prs.length?t.prs:t.prNumber?[{number:t.prNumber,title:t.prTitle,url:t.prUrl,repo:t.repo}]:[],r=o=>`PR #${o.number}${o.title?` "${o.title}"`:""}${o.url?` (${o.url})`:""}${o.repo?` on ${o.repo}`:""}`;switch(e?.trigger){case"pr.merged":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} merged:`:"Follow-up the operator tapped after this Track's PR merged:";case"pr.opened":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} opened:`:"Follow-up the operator tapped after this Track's PR opened:";case"checks.green":return n.length?`Follow-up the operator tapped after CI went green on ${n.map(r).join(" and ")}:`:"Follow-up the operator tapped after CI went green:";case"ship.done":return"Follow-up the operator tapped after the ship you just ran completed:";default:return"Follow-up the operator tapped:"}}async function Kv(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null}={},s={}){let{sayToLead:a,unarchiveTrack:i,getFollowup:c=Nv}=s;if(!t)throw new Error("offerId required");let l={id:e.id,cwd:e.cwd},u=await F(l),f=u.find(E=>E.type==="followup.offered"&&E.payload?.offerId===t);if(!f)throw new Error("unknown offer");if(u.some(E=>E.type==="followup.answered"&&E.payload?.offerId===t))throw new Error("offer already answered");let d=f.payload.rows||[],p=E=>$(l,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...E}});if(!n&&!r)return await p({action:"dismiss",followupIds:d.map(E=>E.followupId).filter(Boolean),armIds:d.map(E=>E.armId).filter(Boolean)}),{offerId:t,action:"dismiss"};let h=null,w=null;if(n){if(!d.some(B=>B.followupId===n))throw new Error("that follow-up is not on this card");let{followup:E,source:R}=await c(n);if(R==="unreachable")throw new Error("plane unreachable \u2014 the follow-up's current prompt can't be read; try again shortly");if(!E||E.status!=="active"){await p({action:"removed",followupId:n});let B=new Error("removed in Settings since it was offered");throw B.code="removed",B}h=E.prompt,w=E.label}else{let E=d.find(B=>B.armId===r);if(!E)throw new Error("that arm is not on this card");if(h=u.find(B=>B.type==="followup.armed"&&B.payload?.armId===r)?.payload?.prompt??E.prompt,w=E.label,!h)throw new Error("the arm's prompt is missing from the log")}let g=!1;if(e.archivedAt){if(!i)throw new Error("this Track is archived");await i(e.id,{freshSession:!0}),g=!0}if(!a)throw new Error("sayToLead unavailable");let k=`${mB(f.payload)}
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}`,S=await a(e.id,k,{kind:"followup-go"});return await p({action:"sent",...n?{followupId:n}:{armId:r},label:w,...o?{promoted:String(o)}:{},...g?{revived:!0}:{},source:n?`followup:${n}`:`arm:${r}`}),{offerId:t,action:"sent",followupId:n,armId:r,promoted:o,revived:g,queued:!!S?.queued}}async function hB(e,t,{changedRepos:n=null,probe:r=ou,branchOf:o=Cr}={}){let s=t.ship;if(!e.workspace?.branch)throw new Error("this Track has no branch to ship \u2014 a ship offer needs a worktree Track");let a={id:e.id,cwd:e.cwd},i=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,c=e.workspace?.kind==="multi",l;if(c&&n){let g=await n(e).catch(()=>[]),k=s.repos?g.filter(S=>s.repos.includes(S.name)):g;l=k.length?k.map(S=>({name:S.name,slug:S.repo??null})):void 0}let u=(c?null:await o(e.cwd).catch(()=>null))||e.workspace.branch,f=s.rebase==="offered",d=await r(e,{branch:u,rebase:f}).catch(()=>null),p=[...f?["rebase"]:[],...s.actions].filter(g=>Ar.includes(g));if(d&&d.available.length===0)return{skipped:!0,reason:"nothing to ship \u2014 the tree is clean, pushed, and its PR is open",shipState:d};let h=Fs(),w=t.why?`${t.label} \u2014 ${t.why}`:t.label;return await $(a,{type:"pr.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:i?.agent??null,payload:{offerId:h,ts:Date.now(),excerpt:w,via:"cli",branch:u,base:s.base||e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:"lead",available:d?.available,defaults:d?d.defaults.filter(g=>p.includes(g)||g==="rebase"):void 0,prState:d?.prState,openPr:d?.openPr||void 0,repos:d?.repos||l,offered:d?p.filter(g=>d.available.includes(g)):p,toPr:s.toPr?{number:s.toPr}:void 0}}),{offerId:h,branch:u,offered:p,available:d?.available??null,prState:d?.prState??null}}function Gv(e){let t=!1;for(let n of e)n.type==="pr.offered"&&(n.source==="cli"||n.payload?.via==="cli")?t=!0:(n.type==="turn.user"&&!n.payload?.kind||n.type==="pr.offer.answered")&&(t=!1);return t}function Vv(e){let t=null;for(let n of e){let r=n.payload||{};n.type==="pr.offer.answered"?t=r.action&&r.action!=="dismiss"&&r.action!=="pr-exists"?r.offerId:null:n.type==="pr.exists.answered"?t=r.choice&&r.choice!=="dismiss"?r.offerId??t:null:(n.type==="turn.user"&&!r.kind||n.type==="followup.offered"&&r.trigger==="ship.done"&&r.context?.shipOfferId&&r.context.shipOfferId===t)&&(t=null)}return t}async function zv(e,{pull:t=Ei}={}){let{followups:n,source:r,error:o}=await t().catch(a=>({followups:[],source:"unreachable",error:a?.message})),s=e?await F({id:e.id,cwd:e.cwd}).catch(()=>[]):[];return{followups:n,source:r,error:o,arms:e?lu(s):[]}}var Dv,Bv,aB,jv,iB,gm,cB,hm,wm,Ls,lB,ym,pB,uu=j(()=>{me();bo();om();Eo();Pv();Dv=60,Bv=8*1024,aB=200,jv=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],iB=jv.filter(e=>e!=="now"&&e!=="track.opened"),gm={now:"now","pr.merged":"after merge","ship.done":"after ship","pr.opened":"after PR opens","checks.green":"after CI goes green","track.opened":"when a Track opens"},cB=3,hm=["commit","push","pr"];wm=e=>sB("sha256").update(String(e)).digest("hex").slice(0,16),Ls=e=>typeof e=="string"?e.trim():"",lB=[[/(^|[^\w&])#\d+\b/,"a PR/issue number"],[/https?:\/\/\S+/i,"a URL"],[/\b[0-9a-f]{7,40}\b/i,"a commit SHA"],[/\bv\d+\.\d+\.\d+\b/,"a release tag"]];ym=e=>String(e?.name||"").startsWith("\u21BB");pB=e=>String(e||"").split(`
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 wB}from"node:crypto";function _i(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function Yv(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function Jv(e){return`job|${e.box}|id:${e.id}`}async function km(e){return bm.has(e.id)?bm.get(e.id):(du.has(e.id)||du.set(e.id,F(e).then(t=>{let n={keys:new Set,cmdN:0};for(let r of t)if((r.type==="turn.user"||r.type==="turn.agent"||r.type==="provider.error")&&r.payload?.text!=null){let o=r.type==="turn.user"?"user":"assistant";r.payload.sourceId&&n.keys.add(_i({role:o,sourceId:r.payload.sourceId})),n.keys.add(_i({role:o,ts:r.payload.ts,text:r.payload.text}))}else if(r.type==="peer.message"&&r.source==="transcript")r.payload?.sourceId&&n.keys.add(_i({role:"user",sourceId:r.payload.sourceId})),n.keys.add(_i({role:"user",ts:r.payload?.ts,text:r.payload?.keyText??""}));else if(r.type==="tool.called"&&r.source==="transcript"&&r.payload?.command){let o=r.payload;n.keys.add(Yv({id:o.id,box:r.boxId,ts:o.ts,command:o.command})),Number(o.n)>n.cmdN&&(n.cmdN=Number(o.n))}else r.type==="job.started"&&r.payload?.id&&n.keys.add(Jv({id:r.payload.id,box:r.boxId}));return bm.set(e.id,n),n}).finally(()=>du.delete(e.id))),du.get(e.id))}async function Xv(e,t){let n=new Set;try{let r=(await km(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=_i(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?iu(o.text):null;if(a){await $(e,{type:"peer.message",actor:"peer",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:a.text,ts:o.ts,keyText:String(o.text||"").slice(0,40),from:await Iv(a,Ii),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=wb(o);if(i){await $(e,{type:"provider.error",actor:"system",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{cls:i.cls,code:i.code||void 0,status:i.status||void 0,requestId:i.requestId||void 0,text:o.text,ts:o.ts,model:o.model||null,boxRole:o.boxRole,sourceId:o.sourceId||void 0}}),Ov(e,{provider:o.agent||null,cls:i.cls,status:i.status,text:o.text}).catch(()=>{});continue}if(o.role!=="user"&&o.box&&n.add(o.box),await $(e,{type:o.role==="user"?"turn.user":"turn.agent",actor:o.role==="user"?"user":"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:o.text,ts:o.ts,model:o.model||null,tools:o.tools||void 0,boxRole:o.boxRole,sourceId:o.sourceId||void 0,note:o.note||void 0,images:o.images?.length?o.images:void 0}}),o.role==="assistant"&&o.box===e.leadBox&&e.workspace?.branch){let c=gx(o.text);if(c&&Gv(await F(e).catch(()=>[])))continue;if(c){let l=kx(c),u;if(e.workspace?.kind==="multi"){let h=await _o(e).catch(()=>[]);u=h.length?h.map(w=>({name:w.name,slug:w.repo??null})):void 0}let f=(e.workspace?.kind==="multi"?null:await Cr(e.cwd).catch(()=>null))||e.workspace.branch,d=await ou(e,{branch:f,rebase:l}).catch(()=>null),p=d?null:bx(c);if(d&&d.available.length===0)continue;await $(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:wB(),ts:o.ts,excerpt:c,branch:f,base:e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:o.boxRole,available:d?.available,defaults:d?.defaults,prState:d?.prState,openPr:d?.openPr||void 0,repos:d?.repos||u,offered:d?.defaults||p?.offered||void 0,toPr:p?.toPr||void 0}})}}}}catch{}return{agentTurnBoxes:n}}async function Zv(e,t){try{let n=await km(e),r=[...t||[]].filter(o=>o&&String(o.command||"").trim()).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=Yv(o);n.keys.has(s)||(n.keys.add(s),n.cmdN+=1,await $(e,{type:"tool.called",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id??null,tool:o.tool||null,command:o.command,description:o.description||"",summary:o.summary||o.command,ts:o.ts??null,boxRole:o.boxRole,n:n.cmdN}}),Tv(e,o),Ev(e,o))}}catch{}}async function Qv(e,t){try{let n=await km(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=Jv(o);n.keys.has(s)||(n.keys.add(s),await $(e,{type:"job.started",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id,kind:o.kind||"agent",name:o.name||null,detail:o.detail||null,ts:o.ts??null,boxRole:o.boxRole}}))}}catch{}}var bm,du,eS=j(()=>{me();bo();om();Av();Eo();um();Nr();dl();pm();uu();bm=new Map,du=new Map});function gB(e){let t=[],n=null;for(let r of String(e||"").split(`
192
+ `)){let o=r.trim();if(!o||o[0]!=="{")continue;let s;try{s=JSON.parse(o)}catch{continue}let a=s.payload||{};if(s.type==="turn_context"&&a.model&&(n=a.model),s.type==="event_msg"&&a.type==="token_count"&&a.info?.last_token_usage){let i=a.info.last_token_usage;t.push({ts:s.timestamp?Date.parse(s.timestamp):null,model:n,last:{input:i.input_tokens||0,cachedInput:i.cached_input_tokens||0,output:i.output_tokens||0,reasoningOutput:i.reasoning_output_tokens||0},occupancy:i.total_tokens??null,contextWindow:a.info.model_context_window??null})}}return t}async function yB(e,t){let n=`${e.id}:${t.name}`;if(!xm.has(n)){let r=await F(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.codexTs!=null&&o.add(s.payload.codexTs);xm.set(n,o)}return xm.get(n)}async function tS(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await so(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await yB(e,t),o=gB(await Et(n.file,262144)),s=o[o.length-1];for(let a of o){if(a.ts==null||r.has(a.ts))continue;r.add(a.ts);let i={input:Math.max(0,a.last.input-a.last.cachedInput),output:a.last.output,cacheRead:a.last.cachedInput,cacheWrite:0},c=a.model||t.model||"gpt-5.5";await $(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:mn(c,i),model:c,tokens:i,reasoningOutput:a.last.reasoningOutput||void 0,codexTs:a.ts,ts:a.ts}}),a===s&&a.contextWindow&&await $(e,{type:"context.usage",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{occupancy:a.occupancy,window:a.contextWindow,pct:a.occupancy!=null?a.occupancy/a.contextWindow:null,model:a.model||null,ts:a.ts}})}}catch{}}var xm,nS=j(()=>{me();io();Xt();Dn();xm=new Map});import fu from"node:fs";import Sm from"node:path";import bB from"node:os";async function vB({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(xB,{method:"POST",headers:{"content-type":"application/json",origin:"https://cursor.com",cookie:`WorkosCursorSessionToken=${t}`},body:JSON.stringify({teamId:0,startDate:String(e),endDate:String(Date.now()),page:o,pageSize:rS})});if(!s.ok)throw new Error(`cursor usage feed: HTTP ${s.status}`);let a=await s.json(),i=a?.usageEventsDisplay||a?.usageEvents||[];if(r.push(...i),i.length<rS)break}return r}function SB(e){if(!e)return null;let t=Number(e.timestamp)||null,n=e.tokenUsage||null,r=n?{input:n.inputTokens||0,output:n.outputTokens||0,cacheRead:n.cacheReadTokens||0,cacheWrite:n.cacheWriteTokens||0}:null,o=e.conversationId||null;return{id:[o||"?",t??"?",r?`${r.input}.${r.output}.${r.cacheRead}.${r.cacheWrite}`:"?"].join(":"),conversationId:o,ts:t,model:e.model||e.modelIntent||null,kind:e.kindLabel||e.kind||null,isHeadless:e.isHeadless===!0,tokens:r,vendorCents:n?.totalCents??null,chargedCents:e.chargedCents??null}}function sS(){try{return JSON.parse(fu.readFileSync(pu(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function EB(e){try{fu.mkdirSync(Sm.dirname(pu()),{recursive:!0});let t=pu()+".tmp";fu.writeFileSync(t,JSON.stringify(e)),fu.renameSync(t,pu())}catch{}}async function _B({fetchImpl:e,now:t=Date.now()}={}){if(Pr.rows&&t-Pr.at<TB)return Pr.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=sS(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await vB({sinceMs:o,cookie:n,fetchImpl:e});Pr={at:t,rows:s.map(SB).filter(Boolean),error:null}}catch(s){Pr={at:t,rows:null,error:String(s?.message||s)}}return Pr.rows}async function IB(e,t){let n=`${e.id}:${t.name}`;if(!vm.has(n)){let r=await F(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.cursorEventId&&o.add(s.payload.cursorEventId);vm.set(n,o)}return vm.get(n)}async function aS(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!oS())return;let r=await _B({fetchImpl:n});if(!r||!r.length)return;let o=await u0(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await IB(e,t),a=sS(),i=new Set(a.seen||[]),c=a.sinceMs||0;for(let l of r){if(!l.conversationId||l.conversationId!==o.chatId||s.has(l.id)||i.has(`${e.id}:${t.name}:${l.id}`))continue;s.add(l.id),i.add(`${e.id}:${t.name}:${l.id}`),l.ts&&l.ts>c&&(c=l.ts);let u=l.model||o.models[o.models.length-1]||"cursor-unknown",f=l.tokens||null,d=l.vendorCents!=null?l.vendorCents/100:0;!d&&f&&(d=mn(u,f)),!d&&l.chargedCents!=null&&(d=l.chargedCents/100),await $(e,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:t.name,provider:"cursor",payload:{usd:d,model:u,...f?{tokens:f}:{},...l.vendorCents!=null?{vendorCents:l.vendorCents}:{},...l.chargedCents!=null?{chargedCents:l.chargedCents}:{},...l.kind?{kind:l.kind}:{},conversationId:l.conversationId,cursorEventId:l.id,ts:l.ts??void 0}})}EB({sinceMs:c,seen:[...i].slice(-AB)})}catch{}}var kB,oS,xB,rS,TB,Pr,pu,AB,Tm,vm,Em=j(()=>{me();fp();Dn();kB=process.env.BOSTRAT_STATE_DIR||Sm.join(process.env.HOME||bB.tmpdir(),".bostrat"),oS=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,xB="https://cursor.com/api/dashboard/get-filtered-usage-events",rS=100;TB=5*6e4,Pr={at:0,rows:null,error:null},pu=()=>Sm.join(kB,"cursor-usage.json");AB=5e3;Tm=()=>({enabled:oS(),lastPollAt:Pr.at||null,error:Pr.error}),vm=new Map});import{execFile as $B}from"node:child_process";import{promisify as RB}from"node:util";function Us({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function mu(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function hu({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?PB[r]:null;return a&&s.push(a),s.push(`${uS}: ${Us({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${dS}: ${String(o).trim()}`),s}function iS(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
193
+ `)){let r=n.trim(),o=/^([A-Za-z-]+):\s*(.+)$/.exec(r);if(!o)continue;let s=o[1].toLowerCase(),a=o[2].trim();if(s===uS.toLowerCase()&&!t.epoch)t.epoch=mu(a);else if(s===dS.toLowerCase()&&!t.model)t.model=a;else if(s===fS.toLowerCase()&&!t.cause){let i=a.toLowerCase();$i.includes(i)&&(t.cause=i)}else if(s==="co-authored-by"||s==="made-with"){let i=a.toLowerCase();t.provider||(i.startsWith("claude")?t.provider="claude":i.startsWith("codex")?t.provider="codex":i.startsWith("cursor")&&(t.provider="cursor"))}}return t}function DB(e,t=Dr){return e<=t?"rework":"drift"}function BB(e,{window:t=Dr,end:n=$m}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function UB({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return jB.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${fS} trailer`}:FB.test(s)&&!cS.test(s)?{cause:"style",level:"C",basis:"subject"}:cS.test(s)?{cause:"defect",level:"C",basis:"subject"}:LB.test(s)?{cause:"design",level:"C",basis:"subject: refactor"}:n==="wrong-approach"?{cause:"design",level:"C",basis:"wall label: wrong-approach"}:r==="bug-fix"?{cause:"defect",level:"C",basis:"fixer prompt: bug-fix"}:null}function WB(e){return HB.some(t=>t.test(e))}function qB(e){let t=[],n=null;for(let r of String(e||"").split(`
194
+ `)){if(r.startsWith("diff --git ")){n={oldPath:null,newPath:null,deleted:[],added:0,binary:!1},t.push(n);continue}if(n){if(r.startsWith("--- ")){let o=r.slice(4).trim();n.oldPath=o==="/dev/null"?null:o.replace(/^a\//,"")}else if(r.startsWith("+++ ")){let o=r.slice(4).trim();n.newPath=o==="/dev/null"?null:o.replace(/^b\//,"")}else if(r.startsWith("Binary files"))n.binary=!0;else if(r.startsWith("@@")){let o=/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(r);if(!o)continue;let s=Number(o[1]),a=o[2]==null?1:Number(o[2]),i=o[4]==null?1:Number(o[4]);a>0&&n.deleted.push([s,a]),n.added+=i}}}return t}function KB(e){let t=new Map,n=null;for(let r of String(e||"").split(`
195
+ `)){let o=/^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/.exec(r);if(o){n={sha:o[1],line:Number(o[3]),time:null},t.set(n.line,n);continue}n&&r.startsWith("committer-time ")&&(n.time=Number(r.slice(15))*1e3)}return t}async function lS(e,t){let{stdout:n}=await Im(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
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 mS(e,t,{fixKey:n=null,window:r=Dr,resolveOrigin:o=null,context:s={}}={}){let a=await lS(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=iS(a.message),l=n?mu(n):c.epoch,u=l?Us(l):null,{stdout:f}=await Im(e,["diff","-U0","--no-color","-M","-C",i,t]),d=qB(f),p=0,h=0,w=0,g=new Map;for(let B of d){if(B.binary)continue;let T=B.oldPath||B.newPath||"",_=B.deleted.reduce((I,[,U])=>I+U,0);if(WB(T)){w+=_;continue}if(p+=B.added,h+=_,!B.oldPath||!_)continue;let O;try{let I=["blame","-w","-M","-C","--line-porcelain"];for(let[U,H]of B.deleted)I.push("-L",`${U},${U+H-1}`);I.push(i,"--",B.oldPath),O=KB((await Im(e,I)).stdout)}catch{continue}for(let{sha:I,time:U}of O.values()){let H=g.get(I)??{lines:0,time:U};H.lines+=1,g.set(I,H)}}let k=[],S=0,E=new Map;for(let[B,{lines:T,time:_}]of g){let O=E.get(B);if(!O){try{O=await lS(e,B)}catch{O=null}E.set(B,O)}let I=O?iS(O.message):{epoch:null},U=I.epoch,H=I.provider,ae=I.model;if(!U&&o){let W=await o(B,O);W?.trackId&&W?.boxId!=null&&(U={trackId:W.trackId,boxId:W.boxId,epoch:W.epoch??0},H=H??W.provider??null,ae=ae??W.model??null)}if(!U){S+=T;continue}let X=Number.isFinite(_)?_:O?.ts??a.ts,C=Math.max(0,(a.ts-X)/MB),Q=Us(U),ve=Q===u?"self":DB(C,r);k.push({sha:B,key:Q,trackId:U.trackId,boxId:U.boxId,epoch:U.epoch,provider:H??null,model:ae??null,lines:T,ageDays:Math.round(C*100)/100,class:ve,decay:ve==="rework"?1:ve==="drift"?Math.round(BB(C,{window:r})*1e3)/1e3:0})}k.sort((B,T)=>T.lines-B.lines);let R=UB({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0});return{sha:a.sha,parent:i,subject:a.subject.slice(0,200),ts:a.ts,fixKey:u,fixProvider:c.provider??s.provider??null,fixModel:c.model??s.model??null,window:r,added:p,deleted:h,excludedDeleted:w,origins:k,unattributedLines:S,ghost:h===0&&p>0,heuristic:R}}function hS(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function _m(e){let t=e.genUsd;return{...e,genUsd:en(t),reworkChargedUsd:en(e.reworkChargedUsd),reworkPendingUsd:en(e.reworkPendingUsd),trueUsd:en(t+e.reworkChargedUsd),multiplier:t>0?en((t+e.reworkChargedUsd)/t):null}}function wS(e,{window:t=Dr,boxMeta:n={}}={}){let r=e||[],o=r.filter(T=>T.type==="cost.recorded"),s=r.filter(T=>T.type==="code.committed"),a=r.filter(T=>T.type==="code.rework"),i=new Map;for(let T of r)T.type==="rework.cause.answered"&&T.payload?.sha&&T.payload?.cause&&i.set(T.payload.sha,T.payload.cause);let c=new Set;for(let T of r)T.type==="rework.cause.offered"&&T.payload?.sha&&c.add(T.payload.sha);let l={},u=(T,_,O)=>Us({trackId:T,boxId:_,epoch:O??0}),f=(T,_={})=>{if(!l[T]){let I=mu(T)||{};l[T]={key:T,...I,provider:null,model:null,...Am()}}let O=l[T];return _.provider&&!O.provider&&(O.provider=_.provider),_.model&&!O.model&&(O.model=_.model),O};for(let T of o){if(!T.boxId)continue;let _=u(T.trackId,T.boxId,T.epoch),{usd:O,model:I}=Ft(T),U=f(_,{provider:T.provider,model:I!=="unknown"?I:null});U.genUsd+=O}let d=new Map;for(let T of s){let _=`${T.trackId}/${T.boxId}`;(d.get(_)??d.set(_,[]).get(_)).push(T)}for(let T of d.values())T.sort((_,O)=>_.ts-O.ts);let p=(T,_,O,I)=>{let U=d.get(`${T}/${_}`)||[],H=-1/0;for(let C of U)C.ts<I&&(H=C.ts);let ae=0,X=0;for(let C of o)C.trackId!==T||C.boxId!==_||(C.epoch??0)===(O??0)&&(C.ts<=H||C.ts>I||(ae+=Ft(C).usd,X++));return{usd:ae,turns:X,from:Number.isFinite(H)?H:null}},h={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0},w={A:0,B:0,C:0,E:0,none:0},g=[],k=[],S={},E={},R=new Set;for(let T of a){let _=T.payload||{};if(!_.sha||R.has(_.sha))continue;R.add(_.sha);let O=mu(_.fixKey)||{trackId:T.trackId,boxId:T.boxId,epoch:T.epoch??0},{usd:I,turns:U}=p(O.trackId,O.boxId,O.epoch,_.ts??T.ts),H=null;i.has(_.sha)?H={cause:i.get(_.sha),level:"B",basis:"operator"}:(_.heuristic?.level&&_.heuristic.level!=="C"||_.heuristic)&&(H=_.heuristic);let ae=H?.level??"none";w[ae]=(w[ae]||0)+1;let X=NB.has(ae),C=Number(_.deleted)||0,Q=Array.isArray(_.origins)?_.origins:[],ve=Q.filter(be=>be.class==="rework").reduce((be,se)=>be+se.lines,0),W={sha:_.sha,subject:_.subject??"",ts:_.ts??T.ts,trackId:T.trackId,fixKey:_.fixKey??null,fixProvider:_.fixProvider??T.provider??null,fixUsd:en(I),fixTurns:U,linesReworked:ve,unattributedLines:Number(_.unattributedLines)||0,ghost:_.ghost===!0,verdict:H?{cause:H.cause,level:ae,basis:H.basis??null}:null,charged:en(0),origins:[]};if(_.ghost||C===0)h.ghost+=I;else{let be=0;for(let pe of Q){let ie=pe.lines/C,L=I*ie;if(be+=L,pe.class==="self"){h.self+=L;continue}let ce=pe.class==="rework"?1:Number(pe.decay)||0,ue=L*ce;if(h.decayed+=L-ue,ue<=0)continue;let Ae=f(pe.key,{provider:pe.provider,model:pe.model});Ae.fixes+=1,Ae.linesReworked+=pe.class==="rework"?pe.lines:0;let _e=H?.cause&&$i.includes(H.cause)?H.cause:"unclassified";Ae.causes[_e]+=1,X?(Ae.reworkChargedUsd+=ue,h.charged+=ue,W.charged=en(W.charged+ue)):(Ae.reworkPendingUsd+=ue,h.pending+=ue),W.origins.push({key:pe.key,provider:Ae.provider,model:Ae.model,lines:pe.lines,ageDays:pe.ageDays,class:pe.class,usd:en(ue)})}let se=Math.max(0,I-be);h.unattributed+=se}g.push(W),!i.has(_.sha)&&c.has(_.sha)&&k.push(_.sha)}for(let T of Object.values(l)){let _=T.provider||"unknown",O=T.model||"unknown",I=U=>{U.genUsd+=T.genUsd,U.reworkChargedUsd+=T.reworkChargedUsd,U.reworkPendingUsd+=T.reworkPendingUsd,U.linesReworked+=T.linesReworked,U.fixes+=T.fixes;for(let H of Object.keys(U.causes))U.causes[H]+=T.causes[H]};I(S[_]||=Am()),I(E[O]||=Am())}g.sort((T,_)=>_.ts-T.ts);let B=Object.values(l).map(T=>{let _=n[`${T.trackId}/${T.boxId}`]||{};return _m({...T,trackName:_.trackName??null,label:_.label??null})}).sort((T,_)=>_.reworkChargedUsd+_.reworkPendingUsd-(T.reworkChargedUsd+T.reworkPendingUsd)||_.genUsd-T.genUsd);return{window:t,basis:`rework = lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old; fix cost = the fixing box's turns since its previous commit; charged only on an authoritative / operator / self-reported cause`,byEpoch:Object.fromEntries(B.map(T=>[T.key,T])),epochs:B,byProvider:Object.fromEntries(Object.entries(S).map(([T,_])=>[T,_m(_)])),byModel:Object.fromEntries(Object.entries(E).map(([T,_])=>[T,_m(_)])),buckets:Object.fromEntries(Object.entries(h).map(([T,_])=>[T,en(_)])),fixUsdTotal:en(Object.values(h).reduce((T,_)=>T+_,0)),fixes:g,verdicts:w,pendingTaps:k,commits:s.length}}var OB,CB,Im,uS,dS,fS,MB,Dr,$m,pS,$i,NB,PB,jB,cS,LB,FB,HB,en,Am,wu=j(()=>{vr();OB=RB($B),CB=64*1024*1024,Im=(e,t)=>OB("git",["-C",e,...t],{maxBuffer:CB,timeout:6e4}),uS="Bostrat-Epoch",dS="Bostrat-Model",fS="Bostrat-Fix-Cause",MB=24*36e5,Dr=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,$m=90,pS=3,$i=Object.freeze(["defect","design","requirements","style"]),NB=new Set(["A","B","E"]);PB={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};jB=/^revert\b|^revert "/i,cS=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,LB=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,FB=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;HB=[/(^|\/)\.bostrat\//,/(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|Cargo\.lock|poetry\.lock|Gemfile\.lock|go\.sum|composer\.lock)$/,/\.min\.(js|css)$/,/\.map$/,/\.snap$/,/(^|\/)(node_modules|dist|build|vendor|\.next|target)\//];en=e=>Math.round(e*1e4)/1e4,Am=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import Ci from"node:fs/promises";import At from"node:path";import GB from"node:os";import VB from"node:net";import{randomUUID as zB}from"node:crypto";import{execFile as YB}from"node:child_process";import{promisify as JB}from"node:util";function r1(e){for(let t of Dm(e))if(!vS.test(t))return t;return null}function SS(e){let t=Dm(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function o1(e,t){let n=SS(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return At.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return At.resolve(e,n[r+1])}return e}function a1(e){let t=!1,n=!1;for(let r of Dm(e)){if(!t){if(vS.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&Rm(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,Rm(r))return`serves the filesystem root ("${r}")`;continue}if(Rm(r))return`serves the filesystem root ("${r}")`;if(s1(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function c1(e,t){if(At.resolve(e)===At.resolve(t))return!0;let[n,r]=await Promise.all([gu(e),gu(t)]);return n===r}async function l1(e){let n=(await Ci.readdir(e,{withFileTypes:!0}).catch(()=>[])).filter(o=>o.isDirectory()&&!o.name.startsWith(".")&&o.name!=="node_modules");return(await Promise.all(n.map(async o=>await TS(At.join(e,o.name,Mm))?`./${o.name}`:null))).filter(Boolean)}async function u1(e,t){let[n,r]=await Promise.all([gu(e),gu(t)]),o=At.relative(n,r);if(o&&(o.startsWith("..")||At.isAbsolute(o)))throw Ri(`serve directory escapes the Track workspace: ${t}`)}async function d1(e,t){let n=a1(t);if(n)throw Ri(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await i1(e))throw Ri(`serve directory does not exist: ${e}`);let r=r1(t);if(!r)return;if(!r.includes("/")&&!await qy(r,{loginShell:!0,failOpen:!0}))throw Ri(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(e1.test(t)||t1.has(r)||!QB.has(r)||!SS(t).includes("run")||n1.test(t))return;let o=o1(e,t);if(await TS(At.join(o,Mm)))return;let s=await l1(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Ri(`no ${Mm} in ${o}${a}`)}async function zn(){return yn||(Om||=(async()=>{try{yn=JSON.parse(await Ci.readFile(xS,"utf8"))}catch{yn={views:[],adoptWatermarks:{}}}finally{Om=null}return yn.views||=[],yn.adoptWatermarks||={},yn})(),Om)}async function kn(){await Tt(xS,yn)}function Vn(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"view.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,payload:{ts:Date.now(),change:t,viewId:e.id,name:e.name,slug:e.slug,port:e.port,cmd:e.cmd||null,...n}}).catch(()=>{})}function jm(e){return Oi.get(e)||null}function AS(e,{name:t,box:n}={}){let r=Oi.get(e);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o={trackId:e,name:t||"preview",box:n||null,step:"spinning-up",startedAt:Date.now(),finishedAt:null,viewId:null,error:null};return Oi.set(e,o),o}function Nm(e,t){let n=Oi.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function yu(e,{error:t=null}={}){let n=Oi.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function _S(e){let t=[];for(let n of e?.events||[])n.type!=="view-spinup"||!n.box||!n.startedAt||!n.endedAt||t.push({box:n.box,from:n.startedAt,to:n.endedAt});return t}function Pm(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function f1(e,t){let n=Pm(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!bS.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!bS.has(s))return s}}function Mi(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=VB.connect({port:e,host:"127.0.0.1"}),o=s=>{r.destroy(),n(s)};r.setTimeout(t,()=>o(!1)),r.once("connect",()=>o(!0)),r.once("error",()=>o(!1))})}async function Lm(e){if(process.platform!=="darwin"){await bn("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await bn("lsof",["-t","-sTCP:LISTEN","-i",`tcp:${e}`]))}catch{return}for(let n of t.split(/\s+/).filter(Boolean)){let r=Number(n);if(!(!r||r===process.pid))try{process.kill(r,"SIGKILL")}catch{}}}function IS(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function p1(e,t){let n=new Set(e.views.map(o=>o.port)),r=IS();if(t){let o=Number(t);if(!Number.isInteger(o)||o<1024||o>65535)throw new Error("invalid port");if(r.has(o))throw new Error(`port ${o} is the node's own API port`);if(n.has(o))throw new Error(`port ${o} is already owned by a view`);return o}for(let o=gS;o<=yS;o++)if(!(n.has(o)||r.has(o))&&!await Mi(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${gS}-${yS}`)}async function m1(e){try{let{stdout:t}=await bn(K,V("list-sessions","-F","#{session_name}"));return t.split(`
198
+ `).some(n=>n.trim()===Hs(e))}catch{return!1}}async function Ni(e){try{await bn(K,V("kill-session","-t",Hs(e)))}catch{}}async function Fm(e){if(!await Ha())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=Hs(e.slug),n=e.serveCwd??e.cwd,r=At.dirname(process.execPath);await bn(K,V("new-session","-d","-s",t,"-c",n)),await bn(K,V("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await bn(K,V("send-keys","-t",t,"Enter")),await bn(K,V("send-keys","-t",t,"-l",e.cmd)),await bn(K,V("send-keys","-t",t,"Enter"))}async function kS(e,t=12){try{let{stdout:n}=await bn(K,V("capture-pane","-t",Hs(e),"-p"));return String(n||"").trimEnd().split(`
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 w1(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await m1(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await kS(e.slug)||"server exited before listening"),Gn.delete(e.id),await Vn(e,e.state,e.error?{error:e.error}:{}),!0}if(await Mi(e.port))return Gn.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await Vn(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>h1?(e.state="error",e.error=await kS(e.slug)||"never started listening",await Vn(e,"error",{error:e.error}),!0):!1;let o=(Gn.get(e.id)||0)+1;return Gn.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function bu(){if(!Cm){Cm=!0;try{let e=await zn(),t=!1;for(let n of e.views)await w1(n)&&(t=!0);t&&await kn()}finally{Cm=!1}}}async function ku({trackId:e}={}){await bu();let t=await zn();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function $S(e){let n=(await zn()).views.find(r=>r.id===e);return n?{...n}:null}function Um(e){return yn&&yn.views.find(t=>t.slug===e)||null}async function Hm({trackId:e,name:t,cmd:n,cwd:r,serveCwd:o,port:s,box:a,origin:i="agent",branch:c=null}){if(!e)throw new Error("trackId required");if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(i!=="detected"&&(typeof n!="string"||!n.trim()))throw new Error("cmd (string) required");if(!r)throw new Error("cwd required");let l=o!=null,u=At.resolve(r,o??"."),f=i==="detected"?null:async()=>{await u1(r,u),await d1(u,n)},d=await zn();if(i!=="detected"){let w=Pm(t),g=String(n).trim(),k=d.views.find(S=>S.trackId===e&&(S.slug===w||Pm(S.name)===w||S.cmd===g&&At.resolve(S.serveCwd??S.cwd)===u));if(k)return g1(d,k,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:f})}if(f&&await f(),d.views.filter(w=>w.state==="live"||w.state==="starting").length>=Br)throw new Error(`view cap reached (${Br} live) \u2014 stop one first`);let h={id:zB().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:f1(d,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await p1(d,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await Fm(h),d.views.push(h),await kn(),await Vn(h,"created",{origin:i}),Nm(e,h.id),i==="detected"&&await Mi(h.port)&&(h.state="live",h.lastHealthyAt=Date.now(),await kn(),await Vn(h,"live")),{...h}}async function g1(e,t,{cmd:n,box:r,branch:o,serveCwd:s,validate:a}){r&&(t.box=r),o&&(t.branch=o);let i=t.cmd!==n,c=s!==void 0&&!await c1(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await Mi(t.port))return await kn(),Nm(t.trackId,t.id),{...t,reused:!0};if(a&&await a(),e.views.filter(f=>f.id!==t.id&&(f.state==="live"||f.state==="starting")).length>=Br)throw new Error(`view cap reached (${Br} live) \u2014 stop one first`);return t.origin==="detected"?(await Lm(t.port),t.origin="agent"):await Ni(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),Gn.delete(t.id),await Fm(t),await kn(),await Vn(t,"created",{restarted:!0,reused:!0}),Nm(t.trackId,t.id),{...t,reused:!0}}async function RS(e){let n=(await zn()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await Lm(n.port):await Ni(n.slug),n.state!=="stopped"&&(n.state="stopped",Gn.delete(n.id),await kn(),await Vn(n,"stopped")),{...n}}async function OS(e){let t=await zn(),n=t.views.find(o=>o.id===e);if(!n)throw new Error("view not found");if(!n.cmd)throw new Error("a detected view has no known command \u2014 recreate it as a managed view");if(t.views.filter(o=>o.id!==e&&(o.state==="live"||o.state==="starting")).length>=Br)throw new Error(`view cap reached (${Br} live) \u2014 stop one first`);return await Ni(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),Gn.delete(n.id),await Fm(n),await kn(),await Vn(n,"created",{restarted:!0}),{...n}}async function CS(e){let t=await zn(),n=t.views.findIndex(o=>o.id===e);if(n===-1)throw new Error("view not found");let r=t.views[n];return r.origin==="detected"?await Lm(r.port):await Ni(r.slug),t.views.splice(n,1),Gn.delete(r.id),await kn(),await Vn(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function MS(e){let t=await zn(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await Ni(r.slug),Gn.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await kn()),n.length}async function NS(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await zn(),r=n.adoptWatermarks[e.id]??null,o=t.filter(c=>c.role==="assistant"&&c.ts!=null&&(r==null?!1:c.ts>r)),s=t.reduce((c,l)=>l.ts>c?l.ts:c,r??0);if(n.adoptWatermarks[e.id]!==s&&(n.adoptWatermarks[e.id]=s,await kn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(y1)){let u=Number(l[1]||80);u>=1024&&u<=65535&&a.add(u)}if(!a.size)return[];let i=[];for(let c of a)if(!IS().has(c)&&!n.views.some(l=>l.port===c)&&await Mi(c))try{i.push(await Hm({trackId:e.id,name:`${e.name} preview`,cmd:null,cwd:e.cwd,port:c,origin:"detected",branch:e.workspace?.branch??null}))}catch{}return i}var bn,XB,xS,gS,yS,Br,ZB,Hs,bS,Ri,QB,Mm,e1,t1,n1,Dm,vS,Rm,s1,i1,TS,gu,yn,Om,Oi,Bm,ES,Gn,h1,Cm,y1,xu=j(()=>{lt();me();cr();bn=JB(YB),XB=process.env.BOSTRAT_STATE_DIR||At.join(process.env.HOME||GB.tmpdir(),".bostrat"),xS=At.join(XB,"views.json"),[gS,yS]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),Br=Number(process.env.BOSTRAT_VIEW_MAX)||3,ZB="bostrat-view-",Hs=e=>`${ZB}${e}`,bS=new Set(["bostrat","www","api","views","app"]),Ri=e=>Object.assign(new Error(e),{status:400}),QB=new Set(["npm","pnpm","yarn","bun"]),Mm="package.json",e1=/[|;&`]|\$\(/,t1=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),n1=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,Dm=e=>String(e).trim().split(/\s+/).filter(Boolean),vS=/^[A-Za-z_][A-Za-z0-9_]*=/;Rm=e=>e==="/",s1=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");i1=e=>Ci.stat(e).then(t=>t.isDirectory(),()=>!1),TS=e=>Ci.stat(e).then(t=>t.isFile(),()=>!1),gu=e=>Ci.realpath(e).catch(()=>At.resolve(e));yn=null,Om=null;Oi=new Map,Bm=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,ES=12e3;Gn=new Map,h1=12e4;Cm=!1;y1=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function vu(e,t=Date.now()){let n=null;for(let r of e||[]){let o=r.payload?.ts??r.ts;r.type==="pr.offer.answered"?n=r.payload?.action==="pr"?{ts:o,offerId:r.payload?.offerId??null,box:r.boxId??null,offerType:"offer"}:null:r.type==="pr.exists.answered"?n=r.payload?.choice==="push"?{ts:o,offerId:r.payload?.offerId??null,box:r.boxId??null,offerType:"exists"}:null:r.type==="pr.state.changed"&&(r.payload?.change==="opened"||r.payload?.change==="pushed")&&n!=null&&o>=n.ts&&(n=null)}return n!=null&&t-n.ts>k1?null:n}function x1(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function PS(e){let t=e?.workspace?.branch;if(!t)return;let n;try{n=await F(e)}catch{return}let r=vu(n);if(r==null)return;let o=(e.boxes||[]).find(u=>u.name===e.leadBox);if(await To(e.leadBox,o?.agent).catch(()=>!1))return;let s=Date.now();if(s-(Wm.get(e.id)||0)<b1)return;Wm.set(e.id,s);let a;try{a=await hn(e.cwd,{caller:"reconcile"})}catch{return}let i=await js(e).catch(()=>[t]),c=(a||[]).find(u=>i.includes(u.headRefName));if(!c)return;let l=await Se(e.cwd).catch(()=>null);if(l){let{link:u,created:f}=await Ot({repo:l,number:c.number,trackId:e.id,url:c.url,headRef:c.headRefName||t,title:c.title,source:"reconciled"});if(!f&&!(u?.trackId===e.id&&await Ln(l,c.number))){if(!x1(u,r))return;let d=await F(e).catch(()=>null);if(d&&vu(d)==null)return;await $(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"pushed",number:c.number,url:c.url,title:c.title,branch:t,repo:l}});return}}await $(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"opened",number:c.number,url:c.url,title:c.title,branch:t,...l?{repo:l}:{}}}).catch(()=>{}),Wm.delete(e.id)}var b1,Wm,k1,qm=j(()=>{me();Bs();ar();Fn();Si();Eo();b1=6e3,Wm=new Map,k1=30*6e4});import Km from"node:os";import{execFile as v1}from"node:child_process";import{promisify as S1}from"node:util";async function Su(){if(process.platform!=="darwin")return Km.freemem();try{let{stdout:e}=await T1("vm_stat",[],{timeout:3e3}),t=Number(/page size of (\d+) bytes/.exec(e)?.[1])||4096,n=o=>Number(new RegExp(`Pages ${o}:\\s+(\\d+)\\.`).exec(e)?.[1])||0,r=(n("free")+n("inactive")+n("speculative"))*t;return r>0?r:Km.freemem()}catch{return Km.freemem()}}var T1,Gm=j(()=>{T1=S1(v1)});import Ke from"node:fs/promises";import ze from"node:path";import LS from"node:os";import{randomUUID as E1}from"node:crypto";import{execFile as A1}from"node:child_process";import{promisify as _1}from"node:util";import{chromium as I1}from"playwright-core";async function Sn(){return Io||(Vm||=(async()=>{try{Io=JSON.parse(await Ke.readFile(US,"utf8"))}catch{Io={mocks:[]}}finally{Vm=null}return Io.mocks||=[],Io})(),Vm)}async function Ht(){await Tt(US,Io)}function KS(e,t){vn(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&vn(e,t.v,"png")}function yt(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"mock.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,mockId:e.id,name:e.name,...e.group?{group:e.group}:{},...e.kind==="video"?{kind:"video"}:{},...n}}).catch(()=>{})}function Wt(e,t){let n=Di(e.cwd);return{html:ze.join(n,`${e.id}.v${t}.html`),png:ze.join(n,`${e.id}.v${t}.png`)}}function Pi(e,t,n){if(!t)return null;let r=n==="html"?t.htmlRel:n==="png"?t.pngRel??t.posterRel??null:n==="video"?t.videoRel??null:null;return r?ze.join(e.cwd,r):null}function tn(e,t=null){let n=e.versions||[];return t!=null?n.find(r=>r.v===Number(t))||null:n.length?n[n.length-1]:null}function Jm(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function Tu(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(P1)}function D1(e){return!Buffer.isBuffer(e)||e.length<32?null:e.subarray(4,8).toString("latin1")==="ftyp"?{ext:"mp4",mime:"video/mp4"}:e.readUInt32BE(0)===440786851?{ext:"webm",mime:"video/webm"}:null}async function B1(e){let t=Buffer.alloc(24),n=await Ke.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function j1({imgW:e,imgH:t,bbox:n,pad:r,align:o=1}){if(!n||!(e>0)||!(t>0))return null;let s=n.right-n.left+1,a=n.bottom-n.top+1;if(s<=0||a<=0||s>=e*.9&&a>=t*.9)return null;let i=s+2*r,c=a+2*r;return i+=(o-i%o)%o,c+=(o-c%o)%o,{sx:n.left,sy:n.top,sw:s,sh:a,outW:i,outH:c,dx:Math.floor((i-s)/2),dy:Math.floor((c-a)/2)}}async function L1(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((h,w)=>{r.onload=h,r.onerror=()=>w(new Error("decode failed")),r.src=`data:image/png;base64,${n}`});let o=r.naturalWidth,s=r.naturalHeight;if(!o||!s||o*s>24e6)return null;let a=document.createElement("canvas");a.width=o,a.height=s;let i=a.getContext("2d",{willReadFrequently:!0});i.drawImage(r,0,0);let c=i.getImageData(0,0,o,s).data,l=[c[0],c[1],c[2]],u=o,f=s,d=-1,p=-1;for(let h=0;h<s;h++)for(let w=h*o*4,g=0;g<o;g++,w+=4)Math.abs(c[w]-l[0])+Math.abs(c[w+1]-l[1])+Math.abs(c[w+2]-l[2])>24&&(g<u&&(u=g),g>d&&(d=g),h<f&&(f=h),p=h);return d<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:f,right:d,bottom:p}}},t.toString("base64"))}async function F1(e,t,{bg:n,crop:r}){let o=await e.evaluate(async({b64:s,bg:a,crop:i})=>{let c=new Image;await new Promise((f,d)=>{c.onload=f,c.onerror=()=>d(new Error("decode failed")),c.src=`data:image/png;base64,${s}`});let l=document.createElement("canvas");l.width=i.outW,l.height=i.outH;let u=l.getContext("2d");return u.fillStyle=`rgb(${a[0]},${a[1]},${a[2]})`,u.fillRect(0,0,i.outW,i.outH),u.drawImage(c,i.sx,i.sy,i.sw,i.sh,i.dx,i.dy,i.sw,i.sh),l.toDataURL("image/png").split(",")[1]},{b64:t.toString("base64"),bg:n,crop:r});return Buffer.from(o,"base64")}async function U1({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await I1.launch({executablePath:HS,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new Ct("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:Ws})).newPage();a.setDefaultTimeout(qs),await a.goto(`file://${e}`,{waitUntil:"load",timeout:qs}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:qs});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await L1(a,i),u=l&&j1({...l,pad:O1*Ws,align:Ws});u&&(i=await F1(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<WS)throw new Ct(`capture produced a ${i.length}-byte image`);let c=Jm(i);if(!c)throw new Ct("output is not a PNG");return await Ke.writeFile(t,i),{width:Math.round(c.width/Ws),height:Math.round(c.height/Ws),dpr:Ws,renderMs:Date.now()-r}}catch(s){throw s instanceof Ct?s:new Ct(/timeout/i.test(s?.message||"")?`render timed out after ${qs}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function jS({htmlPath:e,outPath:t,width:n}){let r=await Ke.mkdtemp(ze.join(LS.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await Ym(DS,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:qs,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new Ct(`firefox not found (${DS})`,""):new Ct(c?.killed?`render timed out after ${qs}ms`:"firefox exited non-zero",s)}let a=await Ke.stat(t).catch(()=>null);if(!a||a.size<WS)throw new Ct(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=Jm(await B1(t));if(!i)throw new Ct("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await Ke.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function H1(e){if($1==="firefox")return jS(e);try{return await U1(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await jS(e)}catch(n){throw/not found/.test(n?.message||"")?new Ct(`no browser installed \u2014 chromium missing at ${HS} and no firefox on PATH; install chromium (Debian: apt install chromium fonts-dejavu-core fonts-liberation) or point BOSTRAT_CHROMIUM_BIN at a Chrome/Chromium binary`,t?.message||""):n}}}function GS(e){return zm=zm.then(e,e),zm}async function VS(e,t){let n=await Sn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Ht(),await yt(r,"rendering",{version:t});try{let o=await Su();if(o<C1)throw new Ct(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=Wt(r,t),a=await W1({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await Ke.rm(s.png,{force:!0}).catch(()=>{});return}Xm(r,{v:t,source:"html",htmlRel:ze.relative(r.cwd,s.html),pngRel:ze.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Ht(),await yt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),xn(r),vn(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Ht(),await yt(r,"error",{version:t,error:r.error}),xn(r)}}}function Xm(e,t){e.versions=(e.versions||[]).filter(r=>r.v!==t.v).concat(t),e.versions.sort((r,o)=>r.v-o.v);let n=e.versions[e.versions.length-1];e.readyVersion=n.v,e.height=n.height,e.dpr=n.dpr,e.renderMs=n.renderMs??null,n.v===e.version&&(e.state="ready",e.error=null)}function q1({trackId:e,name:t,cwd:n,width:r}){if(!e)throw new Error("trackId required");if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(!n)throw new Error("cwd required");let o=r==null?R1:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function Bi({trackId:e,group:t}={}){let n=await Sn(),r=e?n.mocks.filter(o=>o.trackId===e):n.mocks;return t&&(r=r.filter(o=>o.group===t)),r.map(o=>({...o}))}async function Yn(e){let n=(await Sn()).mocks.find(r=>r.id===e);return n?{...n}:null}function zS({html:e,image:t,video:n}){if([typeof e=="string"&&e.trim(),!!t,!!n].filter(Boolean).length!==1)throw new Error("exactly one of html (string), image (png) or video (mp4/webm) required");if(t&&!Tu(t))throw new Error("image must be a PNG");if(n){let o=D1(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>BS)throw new Error(`video must be ${BS/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function YS({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let f=q1({trackId:e,name:t,cwd:s,width:a}),d=typeof n=="string"&&n.trim(),p=zS({html:n,image:r,video:o}),h=await Sn(),w={id:E1().slice(0,8),trackId:e,box:c||null,agent:l||null,name:t.trim(),prompt:u?String(u).slice(0,500):null,group:i?String(i).trim():null,cwd:s,width:f,height:null,dpr:null,state:"queued",source:d?"html":o?"video":"image",kind:o?"video":"image",version:1,readyVersion:null,versions:[],error:null,renderMs:null,createdAt:Date.now(),updatedAt:Date.now()};return await Ke.mkdir(Di(s),{recursive:!0}),h.mocks.push(w),d?(await Ke.writeFile(Wt(w,1).html,n),await Ht(),await yt(w,"created"),xn(w),vn(w,1,"html"),GS(()=>VS(w.id,1))):o?(await XS(w,1,o,p),await Ht(),await yt(w,"created"),await yt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr,durationS:w.versions[0]?.durationS??null}),xn(w),KS(w,w.versions[0])):(await ZS(w,1,r),await Ht(),await yt(w,"created"),await yt(w,"ready",{version:1,width:w.width,height:w.height,dpr:w.dpr}),xn(w),vn(w,1,"png")),{...w}}async function JS(e,{html:t,image:n,video:r,width:o}={}){let a=(await Sn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=zS({html:t,image:n,video:r});if(o!=null){let u=Number(o);if(!Number.isInteger(u)||u<320||u>4e3)throw new Error("invalid width (320-4000)");a.width=u}let l=a.version+1;return a.version=l,a.updatedAt=Date.now(),a.source=i?"html":r?"video":"image",a.kind=r?"video":"image",await Ke.mkdir(Di(a.cwd),{recursive:!0}),i?(a.state="queued",await Ke.writeFile(Wt(a,l).html,t),await Ht(),await yt(a,"updated",{version:l}),xn(a),vn(a,l,"html"),GS(()=>VS(a.id,l))):r?(await XS(a,l,r,c),await Ht(),await yt(a,"updated",{version:l}),await yt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:tn(a)?.durationS??null}),xn(a),KS(a,a.versions.find(u=>u.v===l))):(await ZS(a,l,n),await Ht(),await yt(a,"updated",{version:l}),await yt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),xn(a),vn(a,l,"png")),{...a}}async function K1(e){try{let{stdout:t}=await Ym(M1,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:qS,killSignal:"SIGKILL",maxBuffer:4194304}),n=JSON.parse(t),r=(n.streams||[]).find(s=>s.codec_type==="video"),o=Number(n.format?.duration)||Number(r?.duration)||0;return{durationS:o>0?Math.round(o*10)/10:null,width:Number(r?.width)||null,height:Number(r?.height)||null}}catch{return null}}async function G1(e,t){try{await Ym(N1,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:qS,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Ke.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function XS(e,t,n,r){let o=Di(e.cwd),s=ze.join(o,`${e.id}.v${t}.${r.ext}`),a=ze.join(o,`${e.id}.v${t}.poster.png`);await Ke.writeFile(s,n);let i=await K1(s),c=await G1(s,a);Xm(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:ze.relative(e.cwd,s),posterRel:c?ze.relative(e.cwd,a):null,mimeType:r.mime,bytes:n.length,durationS:i?.durationS??null,width:i?.width??null,height:i?.height??null,dpr:1,renderMs:null,createdAt:Date.now()}),i?.width&&(e.width=i.width)}async function ZS(e,t,n){let r=Jm(n);if(!r)throw new Error("image must be a PNG");let o=Wt(e,t);await Ke.writeFile(o.png,n),Xm(e,{v:t,source:"image",htmlRel:null,pngRel:ze.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function QS(e){let t=await Sn(),n=t.mocks.find(o=>o.id===e);if(!n)throw new Error("mock not found");if(n.readyVersion==null)throw new Error(`mock is ${n.state} \u2014 nothing to pick yet`);let r=n.group?t.mocks.filter(o=>o.trackId===n.trackId&&o.group===n.group&&o.id!==e&&o.readyVersion!=null).map(o=>({mockId:o.id,name:o.name})):[];return await yt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function eT(e){let t=await Sn(),n=t.mocks.findIndex(o=>o.id===e);if(n===-1)throw new Error("mock not found");let r=t.mocks[n];t.mocks.splice(n,1);for(let o=1;o<=r.version;o++){let s=Wt(r,o);await Ke.rm(s.html,{force:!0}).catch(()=>{}),await Ke.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Ke.rm(ze.join(r.cwd,s),{force:!0}).catch(()=>{});return await Ht(),await yt(r,"deleted"),Vt("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function tT(e){let n=(await Sn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=ze.join(FS,"mock-archive",e.id),o=Di(e.cwd),s=ze.join(r,".bostrat","mocks");await Ke.mkdir(s,{recursive:!0});let a=await Ke.readdir(o).catch(()=>[]);for(let i of a)await Ke.copyFile(ze.join(o,i),ze.join(s,i));for(let i of n){for(let c of i.versions||[])for(let l of[c.htmlRel,c.pngRel,c.videoRel,c.posterRel]){if(!l)continue;if(!(await Ke.stat(ze.join(r,l)).catch(()=>null))?.isFile())throw new Error(`mock evacuation incomplete: ${l} missing from the archive`)}i.cwd=r,i.trackDeletedAt=Date.now(),i.trackName=e.name||e.id,i.updatedAt=Date.now(),xn(i)}return await Ht(),n.length}async function nT(e){let t=await Sn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Ht();for(let r of n)Vt("mocks",r.id).catch(()=>{})}return n.length}async function rT(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Sn();for(let r of n.mocks){await xn(r);for(let o of r.versions||[])o.htmlRel&&await vn(r,o.v,"html"),(o.pngRel||o.posterRel)&&await vn(r,o.v,"png"),o.videoRel&&await vn(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var Ym,FS,US,$1,HS,DS,R1,Ws,O1,WS,qs,C1,BS,M1,N1,qS,Ct,Io,Vm,xn,vn,Di,P1,W1,zm,Ks=j(()=>{me();cr();Gm();ur();Ym=_1(A1),FS=process.env.BOSTRAT_STATE_DIR||ze.join(process.env.HOME||LS.tmpdir(),".bostrat"),US=ze.join(FS,"mocks.json"),$1=process.env.BOSTRAT_MOCK_ENGINE||"chromium",HS=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",DS=process.env.BOSTRAT_FIREFOX_BIN||"firefox",R1=1300,Ws=2,O1=32,WS=1500,qs=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,C1=700*1024*1024,BS=100*1024*1024,M1=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",N1=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",qS=2e4,Ct=class extends Error{constructor(t,n=""){super(n?`${t}
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,Vm=null;xn=e=>wt("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),vn=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?Pi(e,r,"video"):r&&Pi(e,r,n)||(n==="html"?Wt(e,t).html:null);return o?lr("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};Di=e=>ze.join(e,".bostrat","mocks");P1=Buffer.from([137,80,78,71,13,10,26,10]);W1=H1,zm=Promise.resolve()});import V1 from"node:fs/promises";import cT from"node:path";import z1 from"node:os";import{randomUUID as lT}from"node:crypto";async function Xn(){return Jn||(Zm||=(async()=>{let e=!0;try{Jn=JSON.parse(await V1.readFile(uT,"utf8"))}catch{Jn={flows:[]},e=!1}finally{Zm=null}if(Jn.flows||=[],!e&&Ne()){let{records:t,source:n}=await et("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&Jn.flows.push(r.data);Jn.flows.length&&await Gs().catch(()=>{})}}return Jn})(),Zm)}async function Gs(){await Tt(uT,Jn)}function Qm(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"flow.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,flowId:e.id,name:e.name,stepCount:e.steps.length,mockIds:[...new Set(e.steps.map(r=>r.mockId))],...n}}).catch(()=>{})}async function dT({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>oT)throw new Error(`steps must be an array of 1-${oT}`);let r=await Bi({trackId:e}),o=[...n],s=[];for(let i=0;i<t.length;i++){let c=t[i]||{},l=`step ${i+1}`,u=typeof c.caption=="string"?c.caption.trim():"";if(!u)throw new Error(`${l}: caption (string) required`);if(u.length>aT)throw new Error(`${l}: caption over ${aT} chars`);let f=c.title==null?null:String(c.title).trim()||null;if(f&&f.length>iT)throw new Error(`${l}: title over ${iT} chars`);let d=String(c.mock??"").trim().replace(/^mock:/,"");if(!d)throw new Error(`${l}: mock (name or id) required`);let p=r.filter(S=>S.id===d);if(p.length||(p=r.filter(S=>S.name.toLowerCase()===d.toLowerCase())),!p.length)throw new Error(`${l}: no mock matching "${d}" in this Track \u2014 see \`bostrat-mock ls\``);if(p.length>1)throw new Error(`${l}: "${d}" is ambiguous (${p.map(S=>`mock:${S.id}`).join(", ")}) \u2014 use the id`);let h=p[0],w=null;if(c.v!=null&&(w=Number(c.v),!Number.isInteger(w)||!(h.versions||[]).some(S=>S.v===w)))throw new Error(`${l}: "${h.name}" has no captured v${c.v} to pin`);let g=o.findIndex(S=>S.mockId===h.id),k=g>=0?o.splice(g,1)[0].id:lT().slice(0,8);s.push({id:k,mockId:h.id,caption:u,title:f,v:w})}let a={};for(let i of s)i.mockId in a||(a[i.mockId]=r.find(c=>c.id===i.mockId)?.readyVersion??null);return{steps:s,resolved:a}}function J1(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>sT)throw new Error(`name over ${sT} chars`);return e.trim()}async function fT({trackId:e}={}){let t=await Xn();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function X1(e){let n=(await Xn()).flows.find(r=>r.id===e);return n?{...n}:null}async function pT(e){let t=await X1(e);if(!t)return null;let n=new Map((await Bi({trackId:t.trackId})).map(r=>[r.id,r]));return t.steps=t.steps.map(r=>{let o=n.get(r.mockId);if(!o)return{...r,missing:!0,mockName:null,mockState:null,servedV:null,width:null,height:null};let s=tn(o,r.v);return{...r,missing:!1,mockName:o.name,mockState:o.state,servedV:s?.v??null,width:s?.width??null,height:s?.height??null}}),t}async function mT({trackId:e,name:t,steps:n,cwd:r,box:o,agent:s}){if(!e)throw new Error("trackId required");if(!r)throw new Error("cwd required");let a=J1(t),i=await Xn(),c=i.flows.find(p=>p.trackId===e&&p.name.toLowerCase()===a.toLowerCase());if(c)throw new Error(`flow "${c.name}" already exists in this Track (flow:${c.id}) \u2014 revise it with \`bostrat-flow update\``);let{steps:l,resolved:u}=await dT({trackId:e,steps:n}),f=Date.now(),d={id:lT().slice(0,8),trackId:e,box:o||null,agent:s||null,name:a,cwd:r,version:1,versions:[{v:1,steps:l,resolved:u,note:null,createdAt:f}],steps:l,createdAt:f,updatedAt:f};return i.flows.push(d),await Gs(),await Qm(d,"created"),Eu(d),{...d}}async function hT(e,{steps:t,note:n}={}){let o=(await Xn()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await dT({trackId:o.trackId,steps:t,prevSteps:o.steps});return o.version+=1,o.versions.push({v:o.version,steps:s,resolved:a,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),o.steps=s,o.updatedAt=Date.now(),await Gs(),await Qm(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),Eu(o),{...o}}async function wT(e){let t=await Xn(),n=t.flows.findIndex(o=>o.id===e);if(n===-1)throw new Error("flow not found");let r=t.flows[n];return t.flows.splice(n,1),await Gs(),await Qm(r,"deleted"),Vt("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function gT(e){return(await Xn()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function yT(e){let n=(await Xn()).flows.filter(r=>r.trackId===e.id);for(let r of n)r.trackDeletedAt=Date.now(),r.trackName=e.name||e.id,r.updatedAt=Date.now(),Eu(r);return n.length&&await Gs(),n.length}async function bT(e){let t=await Xn(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await Gs();for(let r of n)Vt("flows",r.id).catch(()=>{})}return n.length}async function kT(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Xn();for(let r of n.flows)await Eu(r);return{pushed:n.flows.length,source:"plane"}}var Y1,uT,oT,sT,aT,iT,Jn,Zm,Eu,eh=j(()=>{me();cr();Ks();ur();Y1=process.env.BOSTRAT_STATE_DIR||cT.join(process.env.HOME||z1.tmpdir(),".bostrat"),uT=cT.join(Y1,"flows.json"),oT=20,sT=80,aT=500,iT=80,Jn=null,Zm=null;Eu=e=>wt("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import er from"node:fs/promises";import tr from"node:path";import Z1 from"node:os";import{randomUUID as Q1}from"node:crypto";function ji(e){return ej.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function Tn(){return Zn||(th||=(async()=>{let e=!0;try{Zn=JSON.parse(await er.readFile(vT,"utf8"))}catch{Zn={runbooks:[]},e=!1}finally{th=null}return Zn.runbooks||=[],!e&&Ne()&&await tj().catch(()=>{}),Zn})(),th)}async function Ro(){await Tt(vT,Zn)}function _u(e){return Li(wt("runbooks",{...e},{trackId:e.trackId}))}async function tj(){let{records:e,source:t}=await et("runbooks");if(!(t!=="plane"||!e.length)){await er.mkdir(Au,{recursive:!0});for(let n of e){if(n.deletedAt||!n.data?.id)continue;let r=n.data;for(let o of r.versions||[]){let s=await Pa("runbooks",r.id,o.v,"md");typeof s=="string"&&await er.writeFile(Qn(r,o.v),s).catch(()=>{})}Zn.runbooks.push(r)}Zn.runbooks.length&&await Ro()}}function Vs(e,t,n={}){return $({id:e.trackId,cwd:e.cwd},{type:"runbook.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,runbookId:e.id,name:e.name,status:e.status,...n}}).catch(()=>{})}function Qn(e,t){return tr.join(Au,`${e.id}.v${t}.md`)}function ST(e,t=null){let n=e.versions||[];return t!=null?n.find(r=>r.v===Number(t))||null:n.length?n[n.length-1]:null}function TT(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>xT)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${xT/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=ji(e);if(n.length)throw new Error(`runbook appears to contain a secret VALUE (${n.join(", ")}) \u2014 runbooks ship off-box; name the secret and where it goes, never its value. Replace it with a placeholder like <your key> and retry.`);return t}function nj(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function rj({trackId:e,status:t}={}){let n=await Tn(),r=e?n.runbooks.filter(o=>o.trackId===e):n.runbooks;return t&&(r=r.filter(o=>o.status===t)),r.map(o=>({...o}))}async function ET({trackId:e,status:t}={}){let n=await Tn(),r=await rj({trackId:e,status:t});if(!Ne())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await et("runbooks");if(s!=="plane")return{runbooks:r,fleetDegraded:!0};let a=new Set(n.runbooks.map(c=>c.id)),i=o.filter(c=>!c.deletedAt&&c.data?.id&&!a.has(c.data.id)).map(c=>({...c.data,originNode:c.originNode||null,remote:!0})).filter(c=>(!e||c.trackId===e)&&(!t||c.status===t));return{runbooks:[...r,...i],fleetDegraded:!1}}async function nh(e){let t=await oj(e);if(t)return t;if(!Ne())return null;let{records:n,source:r}=await et("runbooks");if(r!=="plane")return null;let o=n.find(s=>!s.deletedAt&&s.data?.id===e);return o?{...o.data,originNode:o.originNode||null,remote:!0}:null}async function AT(e,t){let n=await Pa("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function oj(e){let n=(await Tn()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function _T({trackId:e,trackName:t,name:n,md:r,cwd:o,box:s,agent:a}){if(!e)throw new Error("trackId required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");let i=TT(r),c=await Tn(),l={id:Q1().slice(0,8),trackId:e,trackName:t||e,box:s||null,agent:a||null,name:n.trim(),status:"open",version:1,versions:[],trackDeletedAt:null,cwd:o||null,createdAt:Date.now(),updatedAt:Date.now()};return await er.mkdir(Au,{recursive:!0}),await er.writeFile(Qn(l,1),r),l.versions.push({v:1,mdRel:tr.relative($o,Qn(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await Ro(),await Vs(l,"created",{version:1}),_u(l),Li(lr("runbooks",l.id,1,"md",Qn(l,1))),{...l}}async function IT(e,{md:t,note:n}={}){let o=(await Tn()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");nj(o,"update");let s=TT(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await er.mkdir(Au,{recursive:!0}),await er.writeFile(Qn(o,a),t),o.versions.push({v:a,mdRel:tr.relative($o,Qn(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await Ro(),await Vs(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),_u(o),Li(lr("runbooks",o.id,a,"md",Qn(o,a))),{...o}}async function $T(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await Tn()).runbooks.find(o=>o.id===e);if(!r)throw new Error("runbook not found");return r.status===t?{...r}:(r.status=t,r.updatedAt=Date.now(),await Ro(),await Vs(r,t==="done"?"done":"reopened"),_u(r),{...r})}async function RT(e){let t=await Tn(),n=t.runbooks.findIndex(o=>o.id===e);if(n===-1)throw new Error("runbook not found");let r=t.runbooks[n];t.runbooks.splice(n,1);for(let o of r.versions||[])await er.rm(tr.join($o,o.mdRel),{force:!0}).catch(()=>{});return await Ro(),r.trackDeletedAt||await Vs(r,"deleted"),Li(Vt("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function OT(e){let n=(await Tn()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await Vs(r,"orphaned"),r.cwd=null,_u(r);return n.length&&await Ro(),n.length}async function CT(e){let t=await Tn(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await Vs(r,"deleted");for(let o of r.versions||[])await er.rm(tr.join($o,o.mdRel),{force:!0}).catch(()=>{});Li(Vt("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await Ro()),n.length}async function MT(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Tn();for(let r of n.runbooks){await wt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await lr("runbooks",r.id,o.v,"md",tr.join($o,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var $o,vT,Au,xT,ej,Zn,th,Li,Iu=j(()=>{cr();me();ur();$o=process.env.BOSTRAT_STATE_DIR||tr.join(process.env.HOME||Z1.tmpdir(),".bostrat"),vT=tr.join($o,"runbooks.json"),Au=tr.join($o,"runbooks"),xT=256*1024,ej=[{label:"Anthropic API key",re:/\bsk-ant-[A-Za-z0-9_-]{20,}/},{label:"OpenAI-style API key",re:/\bsk-(?:proj-|svcacct-)?[A-Za-z0-9_-]{32,}\b/},{label:"Stripe secret key",re:/\bsk_(?:live|test)_[A-Za-z0-9]{16,}/},{label:"GitHub token",re:/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}|\bgithub_pat_[A-Za-z0-9_]{22,}/},{label:"AWS access key id",re:/\bAKIA[0-9A-Z]{16}\b/},{label:"Slack token",re:/\bxox[baprs]-[A-Za-z0-9-]{10,}/},{label:"private key block",re:/-----BEGIN [A-Z ]*PRIVATE KEY-----/},{label:"JWT",re:/\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/}];Zn=null,th=null;Li=e=>Promise.resolve(e).catch(()=>{})});import rh from"node:fs/promises";import Fi from"node:path";import{randomUUID as sj}from"node:crypto";function sh(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return aj.has(t)?"image":ij.has(t)?"doc":null}function cj(e){let r=Fi.basename(String(e||"")).replace(/[\x00-\x1f]/g,"").replace(/[^A-Za-z0-9._-]+/g,"_").replace(/^_+|_+$/g,"").slice(-80)||"file";return r.startsWith(".")?`f${r}`:r}async function DT(e,{filename:t,buffer:n}){if(!e)throw new Error("cwd required");if(!Buffer.isBuffer(n)||n.length===0)throw new Error("empty upload");if(n.length>NT)throw new Error(`file too large \u2014 max ${Math.floor(NT/(1024*1024))} MB`);let r=cj(t),o=Fi.extname(r).slice(1),s=sh(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=sj().slice(0,8),i=oh(e);await rh.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await rh.writeFile(Fi.join(i,c),n,{mode:384}),await rh.chmod(Fi.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${PT}/${c}`,kind:s,size:n.length}}function BT(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function ah(e){return e.role==="user"&&lj.test((e.text||"").trim())}var PT,oh,NT,aj,ij,lj,ih=j(()=>{PT=".bostrat/uploads",oh=e=>Fi.join(e,PT),NT=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,aj=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),ij=new Set(["pdf","doc","docx","xls","xlsx","ppt","pptx","odt","ods","odp","rtf","txt","md","markdown","rst","csv","tsv","json","jsonl","yaml","yml","xml","html","htm","log","ini","toml","conf","env","js","jsx","ts","tsx","py","rb","go","rs","java","kt","c","h","cpp","cc","cs","php","swift","sh","bash","zsh","sql","css","scss"]);lj=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function Oo(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}var jT=j(()=>{});import{execFile as uj}from"node:child_process";import{promisify as dj}from"node:util";function ch(e){return`refs/bostrat/wip/${e}`}function mj(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function UT(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function hj(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:pj}async function lh(e,{log:t=console,force:n=!1}={}){let{id:r,cwd:o}=e??{};if(!r||!o)return{pushed:!1,reason:"no-workspace"};try{await jr(o,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await jr(o,["remote","get-url","origin"])}catch{return LT.has(o)||(LT.add(o),t.log?.(`[wip-sync] ${r}: no origin remote \u2014 durable code fidelity is chat/memory-only for this Track`)),{pushed:!1,reason:"no-origin"}}try{let s=await As(o,"bostrat: wip snapshot"),{stdout:a}=await jr(o,["rev-parse",`${s}^{tree}`]),i=a.trim();if(!n&&$u.get(o)===i)return{pushed:!1,reason:"unchanged"};let c=ch(r);return await jr(o,["push","--force","origin",`${s}:${c}`],FT),$u.set(o,i),await $(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:c,sha:s,wip:!0,ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${r}: pushed ${s.slice(0,7)} \u2192 ${c}`),{pushed:!0,sha:s,ref:c}}catch(s){return t.log?.(`[wip-sync] ${r}: push failed (will retry): ${String(s?.message||s).split(`
204
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function uh(e,{log:t=console}={}){let{id:n,cwd:r}=e??{};if(!n||!r)return{pushed:!1,reason:"no-workspace"};try{await jr(r,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await jr(r,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let o=await As(r,"bostrat: transfer rescue snapshot"),{stdout:s}=await jr(r,["rev-parse",`${o}^{tree}`]),a=s.trim();if($u.get(r)===a)return{pushed:!1,reason:"unchanged"};let i=mj(n);return await jr(r,["push","origin",`${o}:${i}`],FT),$u.set(r,a),await $(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:i,sha:o,rescue:!0,ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${n}: rescued stranded work ${o.slice(0,7)} \u2192 ${i}`),{pushed:!0,sha:o,ref:i}}catch(o){return t.log?.(`[wip-sync] ${n}: rescue push failed: ${String(o?.message||o).split(`
205
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}function HT({listTracks:e,sweepMs:t=hj(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)Ve(i)||i?.kind==="setup"||await lh(i,{log:n})}catch(a){n.log?.(`[wip-sync] sweep failed: ${a?.message||a}`)}finally{r=!1}}},s=setInterval(o,t);return s.unref?.(),o(),{stop:()=>clearInterval(s),cycle:o}}var fj,pj,FT,jr,$u,LT,dh=j(()=>{Pl();me();Bn();fj=dj(uj),pj=12e4,FT=6e4;jr=(e,t,n=15e3)=>fj("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),$u=new Map,LT=new Set});import wj from"node:fs";import fh from"node:fs/promises";import gj from"node:path";function xj(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function WT(e,{env:t=process.env,fetchImpl:n=(...o)=>fetch(...o),log:r=console}={}){let o=e?.id;if(!o)return{restored:!1,reason:"no track id"};if(!xj(t))return{restored:!1,reason:"plane not configured"};let s=ts(e),a=gj.join(s,`${o}.ndjson`);try{if(wj.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=Ie(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let d=new AbortController,p=setTimeout(()=>d.abort(),kj),h;try{h=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${yj}`,{headers:c,signal:d.signal})}finally{clearTimeout(p)}if(h.status===404)return{restored:!1,reason:"unknown to plane"};if(!h.ok)return{restored:!1,reason:`plane ${h.status}`};let w=await h.json();for(let g of w.events||[])l.push(JSON.stringify(g));if(l.length>bj)return{restored:!1,reason:"event count over safety cap"};if(w.next==null)break;u=w.next}if(!l.length)return{restored:!1,reason:"unknown to plane"};await fh.mkdir(s,{recursive:!0});let f=`${a}.pull-${process.pid}-${Date.now()}`;return await fh.writeFile(f,l.join(`
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 fh.rename(f,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var yj,bj,kj,qT=j(()=>{it();me();yj=1e3,bj=5e5,kj=3e4});var vE={};Pd(vE,{HANDOFF_LATEST_REL:()=>Co,KNOWN_AGENTS:()=>Xi,TRACK_NAME_MAX:()=>Eh,addTrackRepo:()=>Uh,adoptTrack:()=>sw,agentAvailability:()=>Mu,announceNodeUpdate:()=>An,answerFullscreenOffer:()=>Zh,answerPrompt:()=>Pu,archiveTrack:()=>Do,archiveTrackForMergedPr:()=>qn,augmentFirstPromptAfterHandoff:()=>eE,buildAgentCmd:()=>Ih,canResumeSubtask:()=>bE,cancelQueued:()=>ec,cancelQueuedToDraft:()=>Nh,cancelStopJob:()=>tc,cancelSubtask:()=>Ku,changedRepos:()=>_o,commitTransferOut:()=>Wu,createSetupTrack:()=>qh,createTrack:()=>ju,deleteTrack:()=>Gh,demoteTransferredTracks:()=>ow,ensureLeadEpochs:()=>Qs,forceMergeSubtask:()=>lw,getHandoffJob:()=>ra,getSubtaskJob:()=>SL,getTrack:()=>te,getTransferOutJob:()=>tw,healDeadLead:()=>Yi,interruptLead:()=>Bu,isArchiving:()=>pL,isHandoffNoteEcho:()=>xh,isInterruptEcho:()=>vh,isModelSwitchEcho:()=>Sh,leadCliDead:()=>zh,listSubtaskJobs:()=>jo,listTracks:()=>le,matchTranscriptsToBoxes:()=>rE,mergeNotifyMessage:()=>hE,navigatePrompt:()=>Mh,notifyTrackForMergedPr:()=>Kn,notifyTrackForResolvedPr:()=>Lu,offerFollowupsForMergedPr:()=>Bo,pendingOffers:()=>Oh,queueShipCompleteNotify:()=>Dh,queuedMessages:()=>Mo,reapArchivedOrphans:()=>Xh,reconcileDemotedTracks:()=>Jh,reconcileHandoffOutcome:()=>wE,reconcileInterruptedHandoffs:()=>ew,reconcileInterruptedSubtasks:()=>aw,reconcileNodeUpdateNotices:()=>Rh,reconcileSubtaskOutcome:()=>yE,refreshStandingInstructions:()=>Wh,refuseIfTransferred:()=>rw,rehydrateLead:()=>rc,removeTrackRepo:()=>Hh,renameTrack:()=>Yh,reposOf:()=>Dt,resolveTrackBox:()=>Ii,resolveTrackBoxByHookToken:()=>Qi,restartLead:()=>Uu,resumeAgentCmd:()=>$h,sayToLead:()=>Pt,sendOptionsForAgent:()=>pn,setTrackDraft:()=>Lh,setTrackModel:()=>Fh,startLeadHandoff:()=>Hu,startSpinUpView:()=>Bh,startSubtask:()=>cw,startTransferOut:()=>nw,stopJobActive:()=>aE,subtaskMessages:()=>Ch,trackMessages:()=>Nu,unarchiveTrack:()=>Fu});import z from"node:fs/promises";import J from"node:path";import{randomUUID as Po}from"node:crypto";import{execFile as vj}from"node:child_process";import{promisify as Sj}from"node:util";function Ih(e,{skipPermissions:t=!0}={}){let n=Cu[e];if(!n)throw new Error(`unknown agent "${e}"`);let r=process.env[n.envVar];return r||(t&&n.skipFlag?`${n.base} ${n.skipFlag}`:n.base)}function $h(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=Cu[e];if(!s)throw new Error(`unknown agent "${e}"`);let a=process.env[s.envVar];if(a)return a;let i=n&&s.skipFlag?` ${s.skipFlag}`:"";switch(e){case"claude":{if(!t)return`${s.base}${i}`;if(r&&!Jt(r,t)){let c=o&&Pe(o)?` --name ${o}`:"";return`${s.base} --session-id ${t}${c}${i}`}return`${s.base} --resume ${t}${i}`}case"cursor":return`${s.base} --continue${i}`;case"codex":return`${s.base} resume --last${i}`;default:return`${s.base}${i}`}}function na(e){let t=Cu[e];if(t)return process.env[t.envVar]||t.base}async function Mu({maxAgeMs:e=6e4}={}){if(Lr.value&&Date.now()-Lr.at<e)return Lr.value;let t=Lr.value,n=await Promise.all(Xi.map(async r=>{let o=await sl(na(r),{retries:[]});return o===is?[r,t?.[r]??!0]:[r,o===ol]}));return Lr.value=Object.fromEntries(n),Lr.at=Date.now(),Lr.value}async function Zi(e,t=!0){let n=Ih(e,{skipPermissions:t});if(await sl(n)===as){Lr.at=0;let r=n.split(/\s+/)[0],o=process.env.FLY_APP_NAME?"This Fly node's image predates CLI parity \u2014 update the node image (Links page \u2192 Fly card \u2192 Update) or re-provision.":pf[r]?`Install it on this node: ${pf[r]}`:"Its CLI must be installed and on PATH first.";throw new Error(`agent "${e}" isn't available on this box (command not found: ${r}). ${o}`)}return n}function eE(e,t=Co){return`${e.trim()}
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 xh(e){return e.role==="user"&&Aj.test((e.text||"").trim())}async function Z(){return qt||(ph||=(async()=>{try{qt=JSON.parse(await z.readFile(ZT,"utf8"))}catch{qt={tracks:[]}}finally{ph=null}return qt})(),ph)}async function ee(){await Tt(ZT,qt)}function $j(e,t){let n=JSON.stringify({trackId:e,...t})+`
210
+ `;return mh=mh.then(()=>z.mkdir(En,{recursive:!0})).then(()=>z.appendFile(Tj,n)).catch(()=>{}),mh}async function An({current:e,latest:t,min:n=null,installKind:r=null,required:o=!1,status:s="available",policy:a=null,error:i=null,reason:c=null}={}){if(!t)return{announced:0};if(s==="available"){let f=null;try{f=JSON.parse(await z.readFile(hh,"utf8"))}catch{}if(f?.latest===t&&f?.current===e)return{announced:0,deduped:!0}}let l=await Z(),u=0;for(let f of l.tracks)Ve(f)||!f.leadBox||(Te(f,"node-update",{status:s,current:e??null,latest:t,...n?{min:n}:{},...r?{installKind:r}:{},...a?{policy:a}:{},...i?{error:String(i).slice(0,400)}:{},...c?{reason:c}:{},required:o===!0}),u++);if(await ee().catch(()=>{}),s==="available")try{await z.mkdir(J.dirname(hh),{recursive:!0}),await z.writeFile(hh,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function Rh({current:e,installKind:t=null,policy:n=null}={}){if(!e)return{reconciled:!1,announced:0,targets:[]};let r=await Z(),o=0,s=new Set;for(let a of r.tracks){if(a.archivedAt||a.transferredTo||!a.leadBox)continue;let i=new Map;for(let c of a.events||[])c.type==="node-update"&&c.latest&&i.set(c.latest,c);for(let[c,l]of i)["done","failed","rolled-back"].includes(l.status)||Rj(e,c)||(Te(a,"node-update",{status:"done",current:l.current??null,latest:c,...t?{installKind:t}:{},...n?{policy:n}:{},reason:"version-reconciled",installed:e,required:!1}),o++,s.add(c))}return o&&await ee().catch(()=>{}),{reconciled:o>0,announced:o,targets:[...s]}}function Rj(e,t){let n=String(e).split(".").map(Number),r=String(t).split(".").map(Number);if(n.some(Number.isNaN)||r.some(Number.isNaN))return!0;for(let o=0;o<Math.max(n.length,r.length);o++){let s=(n[o]||0)-(r[o]||0);if(s)return s<0}return!1}function tE(e){if(!e)return null;let t=typeof e=="string"?[e]:Array.isArray(e?.codes)&&e.codes.length?e.codes:e?.code?[e.code]:[],n=[...new Set(t.filter(s=>Oj.has(s)))];if(!n.length)return null;let r=typeof e=="object"?e?.note:null,o=r&&String(r).slice(0,500).trim()||null;return{code:n[0],...n.length>1?{codes:n}:{},note:o}}async function nE(e,t,n,{kind:r}={}){let o=await ge(t);if(!o)throw new Error(`box "${t}" is not running`);let s=na(o.agent);await hr({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s}),await Ze(t,n,{...pn(o.agent,n),kind:r||"orchestration"});let a=await ni({sessionName:t,agent:o.agent,agentCmd:s,text:n,trackId:e,flow:"orchestration"});await re({flow:"orchestration",phase:"sent",submitted:a,trackId:e,sessionName:t,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let i=await Z(),c=he(i,e);if(!c)return;let l=c.boxes.find(u=>u.name===t);Te(c,"orchestration-prompt",{box:t,agent:l?.agent||o.agent,boxRole:l?.role,prompt:n,kind:r||"orchestration"}),await ee()}async function Cj(e){let t=J.join(ts(e),`${e.id}.ndjson`),n;try{n=await z.stat(t)}catch{return null}let r=KT.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await F(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return KT.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function Mj(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:sm(n.name,n.agent)}async function Mt(e,t=null){let n=t??new Map((await zt()).map(c=>[c.name,c])),r=!!e.transferredTo,o=e.boxes.map(c=>{let l=r?null:n.get(c.name),u=Fr.has(c.state)?c.state:l?c.role==="lead"?"live":c.state:"stopped";return{...c,state:u,cwd:l?.cwd||c.cwd,agent:l?.agent||c.agent,sessionId:l?.sessionId||c.sessionId}}),[s,{working:a,prompted:i}]=await Promise.all([Cj(e),Mj(e,o)]);return{...e,boxes:o,lastResponseAt:s,working:a,prompted:i,archiving:zi.has(e.id)}}function rE(e,t,n){let r=[...e].sort((l,u)=>l.createdAt-u.createdAt),o=[...t].sort((l,u)=>l.birthMs-u.birthMs),s=new Set,a=[];for(let l of r)l.sessionId&&n(l.sessionId)&&!s.has(l.sessionId)?s.add(l.sessionId):a.push(l);let i=new Map(r.map((l,u)=>[l,u])),c=[];for(let l of a){if(l.sessionId&&n(l.sessionId)){c.push({box:l.name,sessionId:null});continue}if(!l.sessionId||l.pinned)continue;let u=i.get(l),f=l.createdAt-Nj,d=r[u+1]?.createdAt??1/0,p=o.find(h=>!s.has(h.id)&&h.birthMs>=f&&h.birthMs<d);p&&(s.add(p.id),c.push({box:l.name,sessionId:p.id}))}return c}async function oE(e){let t=new Map;for(let r of e.tracks)for(let o of r.boxes)o.agent==="claude"&&o.cwd&&(t.has(o.cwd)||t.set(o.cwd,[]),t.get(o.cwd).push({track:r,box:o}));let n=!1;for(let[r,o]of t){let s=o.map(d=>d.box.sessionId),a=nb(r),i=new Set(a.map(d=>d.id)),c=s.every(d=>d&&i.has(d)),l=new Set(s).size===s.length;if(c&&l)continue;let u=o.map(d=>d.box),f=rE(u,a,d=>i.has(d));for(let d of f){let p=u.find(h=>h.name===d.box);p&&(p.sessionId=d.sessionId),await Vy(d.box,d.sessionId),n=!0}}return n}async function le(){let e=await Z();await oE(e)&&await ee();let t=new Map((await zt()).map(n=>[n.name,n]));return Promise.all(e.tracks.map(n=>Mt(n,t)))}async function Ii(e,t){let n=await Z();if(e)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.sessionId&&s.sessionId===e);if(o)return{track:r,box:o}}if(t)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.cwd===t);if(o)return{track:r,box:o}}return null}async function Qi(e){let t=va(e);if(!t)return null;let n=await Z();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&Pg(o.hookTokenHash,t))return{track:r,box:o};return null}async function te(e){let t=await Z(),n=he(t,e);return n?(await oE(t)&&await ee(),Mt(n)):null}async function Oh(e){let t=await F(e).catch(()=>[]),n;try{n=wr(t)}catch{return[]}return dk(n).map(r=>({kind:r.kind,id:r.offerId??r.proposalId??r.id,ts:r.ts??null}))}function vh(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(Pj[e.agent]||[]).some(n=>n.test(t))}function Sh(e){let t=(e.text||"").trim();return t?Dj.some(n=>n.test(t)):!1}async function Nu(e,t={}){let n=await te(e);if(!n)return null;let r=new Set([...n.events.filter(A=>A.type==="orchestration-prompt"&&A.prompt).map(A=>String(A.prompt).trim()),...n.events.filter(A=>A.type==="said"&&A.text).map(A=>String(A.text).trim())]),o=ra(n.id),s=!!(o&&!o.finishedAt&&o.step!=="done"&&!o.error),a=s&&o?.startedAt?[...o.fromBox?[{box:o.fromBox,from:o.startedAt,to:Date.now()+1e12}]:[],...o.toBox?[{box:o.toBox,from:o.startedAt,to:Date.now()+1e12}]:[]]:[],i=jm(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[..._S(n),...l],d={windows:[...Nk(n),...Pk(n,Il),...a,...u]},h=(await Promise.all(n.boxes.map(A=>yp(A,t)))).flat(),w=h.map(A=>{let G={kind:"message",...A};if(G.role==="assistant"&&(G.text||"").trim()&&G.tools?.length){let Ge=li(G.agent).cliTools,_t=G.tools.filter(at=>!Ge.has(at));return{...G,tools:_t.length?_t:void 0}}return G}).map(A=>{if(A.role!=="user")return A;let G=El(A.text);return G?G.kind==="suppress"?null:{...A,note:G,text:nk(G)}:A}).filter(Boolean).filter(A=>!(A.role==="user"&&r.has((A.text||"").trim()))).filter(A=>!vh(A)).filter(A=>!Sh(A)).filter(A=>!xh(A)).filter(A=>!ah(A)).filter(A=>A.role!=="assistant"||!!(A.text||"").trim()||!!A.images?.length).filter(A=>!Dk(A,d)),g=w.filter(A=>A.failed&&A.text===ao);if(g.length){let A=new Map;for(let G of g){if(!A.has(G.box)){let at=[...(await Ce(G.box,{lines:Xe}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(nt=>nt[1]);A.set(G.box,at.length?at[at.length-1]:null)}let Ge=A.get(G.box);Ge&&(G.text=`\u25A0 ${Ge}`)}}let k=await Promise.all(n.boxes.map(A=>h0(A,t)));await Qv(n,k.flat());let{agentTurnBoxes:S}=await Xv(n,w);for(let A of n.boxes)S.has(A.name)&&A.cwd&&zc(A.cwd);await ux(n),await NS(n,w).catch(()=>{});for(let A of n.boxes)A.agent==="codex"&&A.state==="live"&&await tS(n,A),A.agent==="cursor"&&A.state==="live"&&await aS(n,A);let E=await Promise.all(n.boxes.map(A=>m0(A,t)));await Zv(n,E.flat().filter(A=>!wh(A.box,A.ts,u)));let R=await F(n),B=c&&i.viewId?i.viewId:null,T=vx(R),_=wr(R).filter(A=>!(A.kind==="message"&&(vh(A)||Sh(A)||xh(A)||ah(A)))&&!(A.kind==="view-card"&&B&&A.viewId===B)),O=Sx(_,T),I=_.filter(A=>!(A.kind==="message"&&A.role==="assistant"&&!O.has(A)&&wh(A.box,A.ts,T))),U=Zf(R,I).map(A=>({kind:"command-batch",id:A.id,ts:A.pending?A.ts:(A.anchorTs??A.ts)-1,anchorTs:A.anchorTs,anchorBox:A.anchorBox,agent:A.agent,boxRole:A.boxRole,commands:A.commands,pending:A.pending})).filter(A=>!wh(A.anchorBox,A.anchorTs??A.ts,u)),H=lk(uk([...I,...U].filter(A=>A.ts!=null).sort((A,G)=>A.ts-G.ts))),ae=jj(n),X=ae.size?H.filter(A=>A.kind==="event"||!ae.has(A.box??A.anchorBox)):H,C=n.boxes.find(A=>A.name===n.leadBox)||null,Q=C?await Ka(C.cwd,C.sessionId,{fallbackNewest:!1}):null;if(!Q&&C){let A=[...R].reverse().find(G=>G.type==="context.usage"&&G.boxId===C.name);A?.payload?.window&&(Q={pct:A.payload.pct??(A.payload.occupancy!=null?A.payload.occupancy/A.payload.window:null),occupancy:A.payload.occupancy??null,window:A.payload.window,windowKnown:!0,model:A.payload.model||null})}let ve=[...h].reverse().find(A=>A.role==="assistant"&&A.model),W=ve?.model||null,be=[...n.events||[]].reverse().find(A=>A.type==="model-change"),se=Q?.model||W;be&&(!ve?.ts||be.at>=ve.ts)&&(se=be.to);let pe=C?await Ce(C.name,{lines:Xe}).catch(()=>""):"",ie=C&&wo(C.agent,pe)?await Nn(C.name).catch(()=>pe):pe,L=C?Tr(C,ie):null;if(L&&C){let A=Ml(C,L,ie);if(A){let G=O0(C.name,L.promptId);G.action!=="give-up"&&(G.action==="send"&&(Le(C.name,A.keys,{kind:"auto-reject"}).catch(()=>{}),G.first&&$(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:C.name,provider:C.agent,payload:{ts:Date.now(),promptId:L.promptId,rule:A.id}}).catch(()=>{})),L=null)}}!L&&C&&!ws(C.agent,pe)&&!Mo(n.id).length&&(L=Jf(X,{leadBoxId:C.name,provider:C.agent,isAnswered:A=>R.some(G=>G.type==="prompt.answered"&&G.payload?.promptId===A)})),L&&dx(n,C,L);let ce=X.filter(A=>!(A.kind==="message"&&A.role==="assistant"&&A.ask&&!String(A.text||"").trim()&&!A.images?.length)),Ae=!!C&&su(C.name,C.agent,pe)&&!L;C&&!C.readyAt&&(Ae||L||pe&&gs(C.agent,pe))&&(C.readyAt=Date.now(),await ee());let _e=!!C&&!C.readyAt&&Date.now()-(n.createdAt||0)<Bj;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&C&&gs(C.agent,pe)&&!L){let A=await Z(),G=he(A,n.id);G?.setup&&!G.setup.connectedAt&&(G.setup.connectedAt=Date.now(),n.setup.connectedAt=G.setup.connectedAt,await $(G,{type:"provider.connected",actor:"system",source:"pane",boxId:C.name,provider:C.agent,payload:{provider:C.agent,ts:G.setup.connectedAt}}).catch(()=>{}),await ee())}let xt=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,je=null;if(c){let A=Date.now()-i.startedAt;if(i.viewId&&!Ae){let G=yu(n.id);G&&(Te(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:G.finishedAt}),await ee())}else if(L||A>ES&&!Ae&&!i.viewId||A>Bm){let G=L?"needs-input":A>Bm?"timeout":"no-view";yu(n.id,{error:G})&&await $(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:C?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:G}}).catch(()=>{})}else je={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:ce,context:Q?{pct:Q.pct,occupancy:Q.occupancy,window:Q.window,windowKnown:Q.windowKnown,model:Q.model}:null,models:{current:se,options:rx(C?.agent)},pendingPrompt:L,working:Ae,stopping:aE(n.id),leadStarting:_e,handoff:xt,view:je,queued:Mo(n.id).filter(A=>A.kind!=="ship-notify"&&A.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function jj(e){let t=new Set;for(let n of e.boxes||[])n.role==="subtask"&&n.name&&t.add(n.name);for(let n of Object.values(e.subtasks||{}))n?.box&&t.add(n.box);return t}async function Ch(e,t){let n=await te(e);if(!n)return null;let r=jo(e).find(f=>f.id===t)||null;if(!r)return null;let o=r.box||null;if(!o)return{items:[],working:!1,box:null,agent:r.agent,task:r.task};let s=await F(n),a=wr(s).filter(f=>f.box===o&&!(f.kind==="message"&&f.role==="assistant"&&f.ask&&!String(f.text||"").trim()&&!f.images?.length)),i=Zf(s.filter(f=>f.boxId===o),a.filter(f=>f.kind==="message")).map(f=>({kind:"command-batch",id:f.id,ts:f.pending?f.ts:(f.anchorTs??f.ts)-1,anchorTs:f.anchorTs,anchorBox:f.anchorBox,agent:f.agent,boxRole:f.boxRole,commands:f.commands,pending:f.pending})),c=[...a,...i].filter(f=>f.ts!=null).sort((f,d)=>f.ts-d.ts),l=n.boxes.find(f=>f.name===o)||null,u=!1;if(l&&l.state==="live"){let f=await Ce(o,{lines:Xe}).catch(()=>"");u=su(o,l.agent||r.agent,f)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}async function Pu(e,{promptId:t,answers:n,text:r}={}){let o=he(await Z(),e);if(!o)throw new Error(`track "${e}" not found`);tc(e,"prompt-answer");let s=o.boxes.find(h=>h.name===o.leadBox);if(!s)throw new Error(`track "${e}" has no lead box`);if(!await ge(o.leadBox))throw new Error(`lead box "${o.leadBox}" is not running`);let i=await Ep(s);if(i||(i=await Lj(o,s)),!i)throw new Error("no pending prompt to answer");if(t&&t!==i.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");let c;if(i.answerMode==="text"){let h=typeof r=="string"?r.trim():"";if(!h)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(h)||h.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await Ze(o.leadBox,h,{enter:!0,kind:"answer-prompt"}),c={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(i.answerMode==="esc")await Le(o.leadBox,["Escape"],{kind:"answer-prompt"}),c={mode:"keys",value:"Escape",count:1};else if(i.answerMode==="say"){let h=ak(i,n||[],typeof r=="string"?r:"");if(!h)throw new Error("no answer selected \u2014 pick an option or reply in chat");await Pt(o.id,h,{kind:"prompt-answer"}),c={mode:"say",value:h,count:1}}else if(i.provider==="claude"||i.answerMode==="keys"){let h=_0(i,n||[]);await Le(o.leadBox,h,{kind:"answer-prompt"}),c={mode:"keys",value:h.join(" "),count:h.length}}else{let h=Rb(i,n||[]);await Ze(o.leadBox,h,{enter:!0,kind:"answer-prompt"}),c={mode:"text",value:h,count:1}}if(i.answerMode==="say"){let h=i.questions||[];for(let w=0;w<h.length;w++){let g=h[w],k=new Set(Array.isArray(n?.[w])?n[w]:[]),S=[...k].map(R=>g.options?.[R]).filter(Boolean).map(R=>({label:R.label,description:R.description||""})),E=(g.options||[]).map((R,B)=>k.has(B)?null:R?.label).filter(Boolean);Hp(o,s,i,{...c,groupId:i.groupId||i.promptId,questionIndex:w,questionTotal:i.questionTotal??h.length,header:g.header||"",question:g.question||"",multiSelect:!!g.multiSelect,chosen:S,rejected:E})}return await re({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),{ok:!0,promptId:i.promptId,sent:c.count}}let l=i.questions?.[0]||{},u=new Set(Array.isArray(n?.[0])?n[0]:[]),f=[...u].map(h=>l.options?.[h]).filter(Boolean).map(h=>({label:h.label,description:h.description||""})),d=(l.options||[]).map((h,w)=>u.has(w)?null:h?.label).filter(Boolean),p=i.review?"review":/^claude:model-confirm:/.test(i.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(i.promptId||"")?"resume-confirm":void 0;return c={...c,groupId:i.groupId||i.promptId,questionIndex:i.questionIndex??0,questionTotal:i.questionTotal??1,header:l.header||"",question:l.question||"",multiSelect:!!l.multiSelect,chosen:f,rejected:d,...p?{control:p}:{}},await re({flow:"prompt",phase:"answered",sessionName:o.leadBox,agent:s.agent,provider:i.provider,promptId:i.promptId,...c}).catch(()=>{}),Hp(o,s,i,c),{ok:!0,promptId:i.promptId,sent:c.count}}async function Lj(e,t){if(!t)return null;let n=await F(e).catch(()=>[]);return Jf(wr(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function Mh(e,{promptId:t,questionIndex:n}={}){let r=he(await Z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=r.boxes.find(l=>l.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(!await ge(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await Ep(o);if(!a)throw new Error("no pending prompt to navigate");if(a.provider!=="claude")throw new Error("prompt navigation not supported for this provider");if(a.review)throw new Error("cannot navigate on the review screen \u2014 answer or cancel");let i=a.questionTotal??1;if(i<2)throw new Error("not a multi-question prompt");if(!Number.isInteger(n)||n<0||n>=i)throw new Error("questionIndex out of range");if(t&&t!==a.promptId)throw new Error("prompt changed since it was shown \u2014 reload and try again");let c=I0(a,n);return c.length?(await Le(r.leadBox,c,{kind:"navigate-prompt"}),await re({flow:"prompt",phase:"navigated",sessionName:r.leadBox,agent:o.agent,provider:a.provider,promptId:a.promptId,fromIndex:a.questionIndex??0,toIndex:n,mode:"keys",value:c.join(" "),count:c.length}).catch(()=>{}),{ok:!0,promptId:a.promptId,sent:c.length}):{ok:!0,promptId:a.promptId,sent:0}}function Du(e){let t=qi.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},qi.set(e,t)),t}function Mo(e){return(qi.get(e)?.items??[]).map(t=>({...t}))}function ec(e){let t=qi.get(e);if(!t)return[];let n=t.items.splice(0);return t.idleSince=null,t.timer&&(clearInterval(t.timer),t.timer=null),n}async function Nh(e){let t=ec(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=he(await Z(),e);if(o)return r=Zs(o,n),await ee(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function Ph(e){let t=Du(e);t.timer||(t.timer=setInterval(()=>Uj(e).catch(()=>{}),Fj))}async function Uj(e){let t=qi.get(e);if(!(!t||t.flushing)){if(!t.items.length){t.timer&&(clearInterval(t.timer),t.timer=null);return}t.flushing=!0;try{let n=he(await Z(),e);if(!n||n.archivedAt){ec(e);return}let r=ra(e);if(r&&!r.finishedAt&&r.step!=="done"&&!r.error){Oo(t,!1);return}let o=await ge(n.leadBox),s=n.boxes.find(c=>c.name===n.leadBox);if(o&&await zh(o)&&(o=await Yi(n,s,"queue")?await ge(n.leadBox):null,await ee()),!o){Oo(t,!1);return}if(yo(s?.agent)){Oo(t,!1);return}let a=await Ce(n.leadBox,{lines:Xe}).catch(()=>"");if(gl(s?.agent,a)){Oo(t,!1);return}if(wo(s?.agent,a)){let c=await Nn(n.leadBox).catch(()=>a);if(Tr(s,c)){Oo(t,!1);return}}if(!Oo(t,!0))return;let i=t.items.shift();t.idleSince=null;try{await Th(n,s,o,i.text,i.kind??null,i.attachments??null)}catch(c){if(c?.code!=="cli-not-running")throw c;t.items.unshift(i),await Yi(n,s,"queue-gate")}await ee()}finally{t.flushing=!1}}}async function sE(e,t,n,r){let o=yo(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(Zs(e,[n]),await ee()),V0(e.id,o))try{await $(e,{type:"usage.cap.hit",actor:"system",provider:t?.agent??null,boxId:e.leadBox,payload:{...o,blockedKind:r??null}})}catch{}let s=new Error(`${t?.agent??"the lead provider"} is paused \u2014 its ${o.window} spend limit is reached ($${o.spentUsd.toFixed(2)} of $${o.limitUsd.toFixed(2)})`);throw s.usageCap=o,s}async function Hj(e,t){let n=await Ce(e.leadBox,{lines:Xe}).catch(()=>"");if(!wo(t?.agent,n))return!1;let r=await Nn(e.leadBox).catch(()=>n);return!!Tr(t,r)}async function Th(e,t,n,r,o=null,s=null){await sE(e,t,r,o);let a=Ki.get(e.id)||0,i=r,c=!1,l=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(i=eE(r,e.pendingHandoffHydrate.artifact||Co),delete e.pendingHandoffHydrate,c=!0);let u=Array.isArray(s)?s.filter(d=>d&&d.rel):[];if(u.length){let d=BT(u.map(p=>p.rel));i=i.trim()?`${i.trim()}
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||Xs(e,null);try{if(await hr({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:na(n.agent),bailOnDialog:!0}),(Ki.get(e.id)||0)!==a){!o&&r.trim()&&(Zs(e,[r]),await ee());let d=new Error("delivery stopped \u2014 the message was handed back as the draft");throw d.interrupted=!0,d}if(await Hj(e,t)){let d=Du(e.id),p={id:Po(),text:r,ts:Date.now(),...o?{kind:o}:{},...u.length?{attachments:u}:{}};d.items.unshift(p),Ph(e.id);let h=new Error("lead is blocked on a prompt \u2014 message queued");throw h.requeued={id:p.id,position:d.items.length},h}await Ze(e.leadBox,i,{...pn(t?.agent,i),kind:c?"lead-handoff-first-prompt":"say"})}catch(d){if(l&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=l),Te(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:f.at,text:r,...d?.interrupted?{reason:"interrupted"}:{},...d?.requeued?{reason:"requeued"}:{}}),d?.requeued)return{queued:!0,...d.requeued};throw d}await nL(e,t,i)||(await iE(e.leadBox,t?.agent,i.length+8,i).catch(()=>{}),Te(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:f.at,text:r,reason:"unsubmitted"}),o||Zs(e,[r])),c&&await re({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function Dh(e,{actions:t}={}){Du(e).items.push({id:Po(),text:Tx(t),ts:Date.now(),kind:"ship-notify"}),Ph(e)}async function Pt(e,t,{kind:n=null,attachments:r=null}={}){let o=Array.isArray(r)?r.filter(p=>p&&typeof p.rel=="string"):[];if((typeof t!="string"||!Ts(t))&&!o.length)throw new Error("text (string) or an attachment required");let s=he(await Z(),e);if(!s)throw new Error(`track "${e}" not found`);if(s.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before driving it`);rw(s);let a=s.boxes.find(p=>p.name===s.leadBox),i=Ts(t);await sE(s,a,i,n),tc(e,"say");let c=await ge(s.leadBox);if(c&&await zh(c)?await Yi(s,a,"say")?(await ee(),c=await ge(s.leadBox)):c=null:!c&&await rc(s)&&(await ee(),c=await ge(s.leadBox)),!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l=Du(e),u=await Ce(s.leadBox,{lines:Xe}).catch(()=>""),f=l.items.length>0||gl(a?.agent,u);if(!f&&wo(a?.agent,u)){let p=await Nn(s.leadBox).catch(()=>u);f=!!Tr(a,p)}if(f){let p={id:Po(),text:i,ts:Date.now(),...n?{kind:n}:{},...o.length?{attachments:o}:{}};return l.items.push(p),Ph(e),n||Xs(s,null),await ee(),{ok:!0,leadBox:s.leadBox,queued:!0,id:p.id,position:l.items.length}}let d;try{d=await Th(s,a,c,i,n,o)}catch(p){if(p?.code!=="cli-not-running"||!await Yi(s,a,"say-gate")||(await ee(),c=await ge(s.leadBox),!c))throw p;d=await Th(s,a,c,i,n,o)}return await ee(),d?.queued?{ok:!0,leadBox:s.leadBox,queued:!0,id:d.id,position:d.position}:{ok:!0,leadBox:s.leadBox}}async function Bh(e,{hint:t}={}){let n=he(await Z(),e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it first`);let r=jm(n.id);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o=n.boxes.find(i=>i.name===n.leadBox),s=String(t||"").trim()?String(t).trim().slice(0,40):"preview";AS(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${GT}
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()}`:GT;try{await Pt(e,a,{kind:"spin-up-view"})}catch(i){throw yu(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Bu(e){let t=he(await Z(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);Ki.set(e,(Ki.get(e)||0)+1);let n=ec(e),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=Js.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=Zs(t,r),await ee()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=zj(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,No(Wj)]);let a=he(await Z(),e)||t;return{ok:!0,interrupted:s.result!=="no-session",stopped:s.result==="stopped"||s.result==="stopped-late",stopping:!s.result,dropped:n.length,restored:s.restored,draftRev:a.draftRev||0}}function aE(e){let t=Js.get(e);return!!t&&!t.canceled}function tc(e,t){let n=Js.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function jh(e){tc(e,"track-ended"),Ki.delete(e),ec(e)}function zj(e,{droppedCount:t,droppedTexts:n}){let r={startedAt:Date.now(),clicks:1,escSends:0,bgSends:0,queuedTexts:[...n],canceled:!1,cancelReason:null,result:null,restored:null},o;return r.settled=new Promise(s=>{o=s}),Js.set(e,r),(async()=>{let s=he(await Z(),e),a=s?.boxes.find(g=>g.name===s.leadBox),i=s?await ge(s.leadBox):null,c=!1,l=!1;if(i){e:for(let g=0;g<qj&&!r.canceled;g++){await Le(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let k of Kj){await No(k);let S=await Ce(s.leadBox,{lines:Xe}).catch(()=>"");if(!ws(a?.agent,S)){c=!0;break e}}}if(!c){l=!0;for(let g=0;g<Vj&&!r.canceled&&(await No(Gj),!r.canceled);g++){let k=await Ce(s.leadBox,{lines:Xe}).catch(()=>"");if(!ws(a?.agent,k)){c=!0;break}await Le(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=he(await Z(),e)||s,f=u?.boxes.find(g=>g.name===u.leadBox)||a,d=null,p=null;u&&f&&i&&c&&!r.canceled&&(d=await Zj(u,f).catch(()=>null),d||(p=await tL(u,f).catch(()=>null)));let h=u&&i&&!r.canceled?await Jj(u).catch(()=>null):null,w=[d||p,...r.queuedTexts].filter(Boolean);u&&w.length&&(r.restored=Zs(u,w),await ee()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await Yj(u||s,f,{ts:r.startedAt,result:r.result,dropped:t,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!d,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!h,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await re({flow:"interrupt",phase:r.result==="gave-up"?"failed":"done",trackId:e,sessionName:u?.leadBox,agent:f?.agent,result:r.result,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!d,lostRestored:!!p,queuedRestored:r.queuedTexts.length,shipDismissed:!!h}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),Js.get(e)===r&&Js.delete(e),o()}),r}async function Yj(e,t,n){await $(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function Jj(e){let t=vu(await F(e));if(!t?.offerId)return null;let n=t.offerType==="exists";return await $(e,{type:n?"pr.exists.answered":"pr.offer.answered",actor:"user",source:"orchestrator",boxId:t.box,payload:{ts:Date.now(),offerId:t.offerId,...n?{choice:"dismiss"}:{action:"dismiss",actions:null},reason:"interrupt"}}),t.offerId}async function Zj(e,t){if(t?.agent!=="claude")return null;let n=[...e.events||[]].reverse().find(r=>r.type==="said"&&r.text);if(!n)return null;for(let r of Xj){await No(r);let o=await Ce(e.leadBox,{lines:Xe}).catch(()=>""),s=ei(t.agent,o);if(s&&yl(n.text,s))return await iE(e.leadBox,t.agent,n.text.length+8),Te(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function tL(e,t){if(t?.agent!=="claude")return null;let n=e.events||[],r=[...n].reverse().find(s=>s.type==="said"&&s.text);if(!r||r.kind||Date.now()-r.at>Qj||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!We(r.text))return null;for(let s of eL){await No(s);let a;try{a=await yp(t,{})}catch{return null}if(Lb(a,r))return null;let i=await Ce(e.leadBox,{lines:Xe}).catch(()=>"");if(ei(t.agent,i))return null}return Te(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function nL(e,t,n){return ni({sessionName:e.leadBox,agent:t?.agent,agentCmd:na(t?.agent),text:n,trackId:e.id,flow:"say"})}async function iE(e,t,n,r=null){for(let o=0;o<3;o++){await ls(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await No(200);let s=await Ce(e,{lines:Xe}).catch(()=>""),a=ei(t,s);if(!a||r&&!yl(r,a)&&!(t==="codex"&&Ff(r,a)))return!0;n=a.length+8}return!1}function Xs(e,t,{source:n}={}){e.draftRev=(e.draftRev||0)+1;let r=typeof t=="string"?t:"";return r.trim()?e.draft={text:r,updatedAt:Date.now(),...n?{source:n}:{}}:delete e.draft,e.draft||null}function Zs(e,t){let n=[],r=o=>n.some(s=>We(s).includes(We(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?Xs(e,n.join(`
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 oL(e,t){let n=We(t);if(!n)return!1;if(Mo(e.id).some(o=>We(o.text)===n))return!0;let r=e.events||[];for(let o=r.length-1;o>=0;o--){let s=r[o];if(typeof s.at=="number"&&Date.now()-s.at>rL)break;if(!(s.type!=="said"||!s.text||We(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function Lh(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=he(await Z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=Ts(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&oL(r,s))return{ok:!0,draft:r.draft||null,rev:null,ignored:"already-sent"};if(typeof n=="number"&&n<(r.draftRev||0)&&!o.trim()&&r.draft?.text)return{ok:!0,draft:r.draft,rev:r.draftRev||0,ignored:"stale-clear"};if(typeof n=="number"&&n<(r.draftRev||0)&&r.draft?.source==="restore"){let i=r.draft.text;We(o).includes(We(i))?Xs(r,o):Xs(r,`${i}
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 Xs(r,o);return await ee(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function Fh(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=he(await Z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await ge(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(f=>f.name===r.leadBox)?.agent||o.agent||"claude",i=ox(a,n),l=[...r.events||[]].reverse().find(f=>f.type==="model-change")?.to??null;l||(l=(await Ka(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await hr({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:na(o.agent)});let u=await sx(a,r.leadBox,i);return Te(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await ee(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function cE(e){for(let t of e){if(!t||!await Es(t))continue;let n=await P0(t).catch(()=>null);if(!n)continue;if((await z.stat(J.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function Dt(e){let t=e;return t?t.kind==="multi"?Array.isArray(t.repos)?t.repos.filter(Boolean):[]:t.base?[{name:J.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function _o(e){let t=[];for(let n of Dt(e?.workspace)){if(!n?.dir)continue;let r=await ui(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await di(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function lE(e){let t=e;typeof t=="string"&&!J.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await Zo(t)??await Fc(t));let n=await cE([t]);if(!n)throw new Error(`tagged repo "${e}" is not a usable base (need a primary checkout or a synced owner/name)`);return n}async function sL(e,t,n,r){let o=`track/${iw(t)}-${e}`,s=[];try{await z.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await lE(i);if(s.some(p=>p.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await Se(c).catch(()=>null),u=J.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let p=2;a.has(u);p++)u=`${J.basename(c)}-${p}`;a.add(u);let f=J.join(n,u),d=await Is(c);await _s(c,f,o,d),s.push({name:u,dir:f,base:c,baseRef:d,repo:l})}return await nc(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await Rt(i.base,i.dir).catch(()=>{});throw await z.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function Uh(e,t){let n=await Z(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 unarchive it first");let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track \u2014 a single-repo Track's workspace IS its repo checkout; create the Track with multiple repos tagged instead");let s=await lE(typeof t=="string"?t.trim():t);if((o.repos??[]).some(d=>d?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await Se(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(d=>d?.name).filter(Boolean)]),c=J.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let d=2;i.has(c);d++)c=`${J.basename(s)}-${d}`;let l=J.join(o.dir,c),u=await Is(s);await D0(s,o.branch)?await Nl(s,l,o.branch):await _s(s,l,o.branch,u);let f={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),f],await nc(o.dir,o.repos,o.branch),Te(r,"retagged",{action:"add",repo:a??s,name:c,workspace:uE(o)}),await ee(),f}async function Hh(e,t){let n=await Z(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track");let s=(o.repos??[]).find(c=>c&&(c.name===t||c.repo===t||c.base===t));if(!s)throw new Error(`repo "${t}" is not tagged on this Track`);if((o.repos??[]).filter(Boolean).length<=1)throw new Error("can't untag the last repo \u2014 archive or delete the Track instead");for(let c of Nt.values())if(c.trackId===e&&!c.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before untagging");let a=await ui(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await di(s.dir,s.baseRef).catch(()=>0);if(a||i>0)throw new Error(`"${s.name}" has work (${a?"uncommitted changes":`${i} commit${i===1?"":"s"} ahead of ${s.baseRef??"base"}`}) \u2014 ship or discard it first`);return await Rt(s.base,s.dir).catch(()=>{}),await z.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await nc(o.dir,o.repos,o.branch),Te(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:uE(o)}),await ee(),{removed:s.name}}async function aL(e,t,{repo:n,repos:r,cwd:o}={}){await z.mkdir(Hi,{recursive:!0});let s=J.join(Hi,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return sL(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!J.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await Zo(n)??await Fc(n));let i=await cE([n,o,Ej]);if(i){let c=`track/${iw(t)}-${e}`;try{let l=await Is(i);await _s(i,s,c,l),await Vi(s);let u=await Se(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await z.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await z.mkdir(s,{recursive:!0}),await Cp(s),await Vi(s),{dir:s,base:null,branch:null,kind:"repo"}}async function Vi(e){try{await z.writeFile(J.join(e,"AGENTS.md"),Ui,{flag:"wx"})}catch{return}await uL(e,["/AGENTS.md"])}function lL(e,t){let n=e.map(r=>`- \`${r.name}/\`${r.repo?` \u2014 github.com/${r.repo}`:""}${r.baseRef?` (forked from ${r.baseRef})`:""}`).join(`
219
+ `);return`${cL}
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 nc(e,t,n){let r=lL(t,n);for(let o of["CLAUDE.md","AGENTS.md"])await z.writeFile(J.join(e,o),r).catch(()=>{})}async function fE(e){let{stdout:t}=await XT("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return J.resolve(e,t.trim())}async function uL(e,t){try{let n=await fE(e);await z.mkdir(J.dirname(n),{recursive:!0});let r=await z.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
232
+ `).includes(s));o.length&&await z.appendFile(n,(r.endsWith(`
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 dL(e,t){try{let n=await fE(e),r=await z.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 z.writeFile(n,o.join(`
239
+ `))}catch{}}async function Wh(){let e={refreshed:0,removed:0,codexGlobal:null};try{await z.mkdir(En,{recursive:!0}),await z.writeFile(J.join(En,"CLAUDE.md"),iL).catch(()=>{}),await z.writeFile(J.join(En,"AGENTS.md"),Ui).catch(()=>{});let t=process.env.CODEX_HOME||J.join(process.env.HOME||"/tmp",".codex");if((await z.stat(t).catch(()=>null))?.isDirectory()){let r=J.join(t,"AGENTS.md"),o=await z.readFile(r,"utf8").catch(()=>null);o===null?(await z.writeFile(r,yh,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):gh(o)&&o!==yh&&(await z.writeFile(r,yh).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[Hi,ta]){let o=await z.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=J.join(r,s.name),i=J.join(a,"AGENTS.md"),c=await z.readFile(i,"utf8").catch(()=>null);c!==null&&gh(c)&&c!==Ui&&(await z.writeFile(i,Ui).catch(()=>{}),e.refreshed++);let l=J.join(a,"CLAUDE.md"),u=await z.readFile(l,"utf8").catch(()=>null);u!==null&&gh(u)&&(await z.rm(l,{force:!0}).catch(()=>{}),await dL(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function pE(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of Dt(t))n.base&&n.dir&&await Rt(n.base,n.dir).catch(()=>{});await z.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await Rt(t.base,t.dir):await z.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function ju({name:e,cwd:t,repo:n,repos:r,agent:o="claude",skipPermissions:s=!0}){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");let a=await Zi(o,s),i=await Z(),c=Po().slice(0,8),l=await aL(c,e,{repo:n,repos:r,cwd:t}),u=new Set(i.tracks.flatMap(h=>(h.boxes||[]).map(w=>w.name))),f=`${e.trim()} lead`;u.has(al(f))&&(f=`${e.trim().slice(0,50).trim()} ${c} lead`);let d=await pr(f,l.dir,{agentCmd:a,agent:o,freshWorkspace:!0}),p={id:c,name:e.trim(),cwd:d.cwd,workspace:l,leadBox:d.name,boxes:[Qh(d,"lead","live")],events:[],createdAt:Date.now()};return Te(p,"opened",{agent:o,box:d.name,skipPermissions:s,name:p.name,cwd:p.cwd,workspace:{base:l.base??null,branch:l.branch,kind:l.kind,...l.baseRef?{baseRef:l.baseRef}:{},...l.repo?{repo:l.repo}:{},...l.repos?{repos:l.repos.map(({name:h,base:w,baseRef:g,repo:k})=>({name:h,base:w,baseRef:g,repo:k}))}:{}}}),i.tracks.push(p),await ee(),Xa({cwd:d.cwd,sessionName:d.name,agent:o,agentCmd:a,onReady:async()=>{let h=p.boxes.find(w=>w.name===p.leadBox);!h||h.readyAt||(h.readyAt=Date.now(),await ee())}}),Mt(p)}async function qh({provider:e="claude",fresh:t=!1}={}){if(!fL.has(e))throw new Error(`unknown setup provider "${e}" (claude | codex | cursor)`);let r=(await Z()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===e&&!u.archivedAt);if(r){if(!t){let u=await Mt(r);if(u.boxes.find(d=>d.name===u.leadBox)?.state==="live")return u}await Do(r.id).catch(()=>{})}let o=(await Zi(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=Po().slice(0,8),a=J.join(En,"setup",s);await z.mkdir(a,{recursive:!0});let i=await pr(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&Xa({cwd:i.cwd,sessionName:i.name,agent:e,agentCmd:o});let c={id:s,name:`Connect ${e}`,kind:"setup",setup:{provider:e,startedAt:Date.now(),connectedAt:null},cwd:i.cwd,workspace:{dir:a,base:null,branch:null,kind:"scratch"},leadBox:i.name,boxes:[Qh(i,"lead","live")],events:[],createdAt:Date.now()};return Te(c,"opened",{agent:e,box:i.name,skipPermissions:!1,trackKind:"setup",name:c.name,cwd:c.cwd,workspace:{base:null,branch:null,kind:"scratch"}}),(await Z()).tracks.push(c),await ee(),Mt(c)}async function Kh(e,t,n){await Zd(t.cwd).catch(()=>{}),await MS(e).catch(()=>{});let r=ea.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),ea.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of jo(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await uw(a).catch(()=>{}),Nt.delete(a.id);for(let a of Object.values(t.subtasks||{}))a.finishedAt||(a.step="error",a.error=n,a.canceled=!0,a.finishedAt=Date.now());let o=await Z(),s=new Set((o.tracks||[]).filter(a=>a.id!==e&&!a.archivedAt).flatMap(a=>(a.boxes||[]).map(i=>i.name)));for(let a of t.boxes)s.has(a.name)||await Yt(a.name).catch(()=>{})}async function Gh(e,{cascadeMocks:t=!0,cascadeRunbooks:n=!1}={}){let r=await Z(),o=r.tracks.findIndex(a=>a.id===e);if(o===-1)throw new Error(`track "${e}" not found`);let s=r.tracks[o];return t||await tT(s),jh(e),await Kh(e,s,"track deleted"),n?await CT(e).catch(()=>{}):await OT(e).catch(()=>{}),await cx(),await pE(s),t&&await nT(e).catch(()=>{}),t?await bT(e).catch(()=>{}):await yT(s).catch(()=>{}),Te(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await ee(),{ok:!0,id:e,name:s.name,boxes:s.boxes.length}}async function Do(e){let t=await Z(),n=he(t,e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is already archived`);return n.archivedAt=Date.now(),jh(e),Te(n,"archived",{boxes:n.boxes.length}),await ee(),n.kind==="setup"?(await mE(e),Mt(n)):(zi.add(e),hL(e).catch(()=>{}).finally(()=>zi.delete(e)),{...await Mt(n),archiving:!0})}async function hL(e){try{await wL(e)}catch{}await mE(e).catch(()=>{})}async function mE(e){let t=await Z(),n=he(t,e);if(!(!n||!n.archivedAt)){await Kh(e,n,"track archived");for(let r of n.boxes)Fr.has(r.state)||(r.state="stopped");await ee()}}async function wL(e){let t=await Z(),n=he(t,e);if(!n||!n.archivedAt)return;let r=null,o=[],s="derived",a=(n.events||[]).some(l=>l.type==="said"),i=n.leadBox?await ge(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await Ck(n.leadBox,i.cwd,{timeoutMs:mL})),s="lead-cli"}catch{}if(r||(r=Vk(n,await F(n).catch(()=>[]))),!r)return;let c={text:r,source:s,at:Date.now()};o.length&&(c.items=o),n.beat=c,await $(n,{type:"track.summary.recorded",actor:"orchestrator",source:"orchestrator",boxId:n.leadBox||null,provider:i?.agent||null,payload:o.length?{text:r,items:o,source:s}:{text:r,source:s}}).catch(()=>{}),await ee()}async function qn(e,t){let n=await tt(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await Vh(n);if(r.length){for(let o of r)await ko(o.repo,o.number,!0).catch(()=>{});return!1}try{return await Do(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function Vh(e){return(await xo().catch(()=>[])).filter(n=>n.trackId===e.trackId&&n.state!=="merged"&&n.state!=="closed"&&n.state!=="lost"&&!(n.repo===e.repo&&n.number===e.number))}async function Kn(e,t){return Lu(e,t,"merged")}async function Bo(e,t){let n=await tt(e,t).catch(()=>null);if(!n?.trackId)return null;let r={repo:n.repo??null,number:n.number,title:n.title??null,url:n.url??null},o=await Vh(n);if(o.length){let c=[...n.followupPending||[],r];for(let l of o)await Px(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=he(await Z(),n.trackId);if(!a)return null;let i=s[0];return Ai(Mt(a),"pr.merged",{repo:n.repo??a.workspace?.repo??null,prs:s,prNumber:i?.number??null,prTitle:i?.title??null,prUrl:i?.url??null}).catch(()=>null)}async function Lu(e,t,n="merged"){let r=await tt(e,t).catch(()=>null);if(!r?.notifyOnMerge||r.archiveOnMerge||!r.trackId)return!1;let o={repo:r.repo??null,number:r.number,title:r.title??null,url:r.url??null,headRef:r.headRef??null,outcome:n},s=await Vh(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await Nx(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];try{return await Pt(r.trackId,hE(a),{kind:"merge-notify"}),!0}catch{return!1}}function hE(e){let t=i=>`${i.repo?`${i.repo}`:""}#${i.number}${i.title?` "${i.title}"`:""}${i.url?` (${i.url})`:""}`;if(e.length===1){let i=e[0],c=`#${i.number}${i.title?` "${i.title}"`:""}`;return i.outcome!=="merged"?`PR ${c}${i.url?` (${i.url})`:""}${i.headRef?` \u2014 branch ${i.headRef} \u2014`:""} was ${VT[i.outcome]??i.outcome}. This is an automated notification: the work did NOT land \u2014 check whether it still needs to ship another way. If not, say so briefly.`:`PR ${c}${i.url?` (${i.url})`:""}${i.headRef?` \u2014 branch ${i.headRef} \u2014`:""} has merged. This is an automated merge notification: pick up whatever follow-up work this merge unblocks (dependent tasks, cleanup, next steps that were waiting on it). If nothing needs doing, say so briefly.`}let n=e.filter(i=>i.outcome==="merged"),r=e.filter(i=>i.outcome!=="merged"),o=r.length?`${n.length} of the ${e.length} PRs on this Track merged; ${r.length} did not land:`:`All ${e.length} PRs on this Track have merged:`,s=e.map(i=>`- ${t(i)} \u2014 ${VT[i.outcome]??i.outcome}`).join(`
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 zh(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<Wa()?!1:Mn(e.name)}async function Yi(e,t,n){return!t||e.archivedAt||Fr.has(t.state)?!1:(await re({flow:"rehydrate",phase:"resume-dead-cli",trackId:e.id,sessionName:t.name,agent:t.agent,via:n}).catch(()=>{}),console.warn(`[track] ${t.name}: CLI is not running (bare shell) \u2014 relaunching (${n})`),await Yt(t.name).catch(()=>{}),t.state="stopped",rc(e))}async function rc(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=bh.get(r.name);if(o)return o;let s=gL(e,r,{freshSession:t,reason:n}).finally(()=>bh.delete(r.name));return bh.set(r.name,s),s}async function gL(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||Fr.has(t.state)||await ge(t.name))return!1;let o=n===!0,s=o?Po():null,a=o?Ua(Ih(t.agent),s,t.name):$h(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await sl(a);if(i===as)return Te(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===is&&console.warn(`[track] ${t.name}: could not confirm "${t.agent}" on PATH \u2014 relaunching anyway (launch verifier will catch a real miss)`);let c=o?{sessionId:t.sessionId??null,pinned:t.pinned===!0,epochs:JSON.parse(JSON.stringify(Qs(t)))}:null,l=Date.now();if(o){let u=Qs(t),f=u[u.length-1];f.endedAt==null&&(f.endedAt=l),f.endReason==null&&(f.endReason=r||"fresh-session"),u.push({agent:t.agent,sessionId:s,pinned:t.agent==="claude",startedAt:l,endedAt:null}),t.sessionId=s,t.pinned=t.agent==="claude"}try{let u=await pr(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=va(u.hookToken),Xa({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a}),t.state="live",o&&Te(e,"lead-refreshed",{box:t.name,agent:t.agent,fromSessionId:c.sessionId,toSessionId:s,epoch:t.epochs.length-1,reason:r||"fresh-session"}),Te(e,"rehydrated",{box:t.name,agent:t.agent,...o?{fresh:!0}:{}}),!0}catch(u){return o&&(t.sessionId=c.sessionId,t.pinned=c.pinned,t.epochs=c.epochs),Te(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function Fu(e,{freshSession:t=!1}={}){let n=await Z(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);if(!r.archivedAt)throw new Error(`track "${e}" is not archived`);return delete r.archivedAt,zi.delete(e),Te(r,"unarchived",{}),await rc(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await ee(),Mt(r)}async function Yh(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>Eh)throw new Error(`name too long (max ${Eh} chars)`);let r=await Z(),o=he(r,e);if(!o)throw new Error(`track "${e}" not found`);if(String(o.name||"").startsWith("\u21BB"))throw new Error("loop run Tracks are named by their loop \u2014 rename the loop on the Loops tab");if(n===o.name)return Mt(o);let s=o.name;return o.name=n,Te(o,"renamed",{from:s,to:n}),await ee(),Mt(o)}async function Jh(){let e=await Z(),t=0;for(let n of e.tracks||[])n.transferredTo&&Dl(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await ee(),t}async function Xh(){let e=await Z(),t=new Set((await zt()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!Ve(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(Ve(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await Yt(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):Te(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!Fr.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await ee(),r}async function Uu(e,{freshSession:t=!1}={}){let n=await Z(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before restarting the lead`);rw(r);let o=r.boxes.find(i=>i.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(Fr.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await ge(r.leadBox)){let i=await Ce(r.leadBox,{lines:Xe}).catch(()=>"");if(gl(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await Yt(r.leadBox),o.state="stopped"}let a=await rc(r,t?{freshSession:!0,reason:"loop-fire"}:{});if(await ee(),!a)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Mt(r)}async function Zh(e,t,n){let r=await te(e);if(!r)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let o=await F(r).catch(()=>[]);if(!o.some(i=>i.type==="box.fullscreen.detected"&&i.payload?.offerId===t))throw new Error("unknown offer");if(o.some(i=>i.type==="box.fullscreen.answered"&&i.payload?.offerId===t))throw new Error("offer already answered");return n&&await Uu(e),await $(r,{type:"box.fullscreen.answered",actor:"user",source:"orchestrator",boxId:r.leadBox,payload:{ts:Date.now(),offerId:t,action:n?"restarted":"dismiss"}}).catch(()=>{}),{ok:!0,action:n?"restarted":"dismiss"}}function zT(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return hu({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function Qs(e){return(!Array.isArray(e.epochs)||e.epochs.length===0)&&(e.epochs=[{agent:e.agent??null,sessionId:e.sessionId??null,pinned:e.pinned===!0,startedAt:e.createdAt??null,endedAt:null}]),e.epochs}async function Ou(e,t){let n=await Z(),r=he(n,e);r&&(r.handoff={...r.handoff||{},...t},await ee())}function wE(e,t=Date.now()){let n=e?.handoff;if(!n||n.finishedAt)return null;let r=n.step,o=!!n.toBox&&n.toBox===n.fromBox,s=e.boxes?.find?.(i=>i.name===e.leadBox)||null;return(o?e.leadBox===n.fromBox&&!!n.startedAt&&Array.isArray(s?.epochs)&&s.epochs.some(i=>i.startedAt!=null&&i.startedAt>=n.startedAt):!!n.toBox&&e.leadBox===n.toBox)?{...n,step:"done",finishedAt:t,recovered:`committed before restart (was "${r}")`}:{...n,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${r}"; lead "${e.leadBox}" retained \u2014 retry the handoff`,recovered:"rolled-back"}}async function ew(){let e=await Z(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=wE(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await ge(r.fromBox).catch(()=>null),l=n.boxes.find(u=>u.name===r.fromBox);if(c&&l&&c.agent===r.toAgent&&r.toAgent!==l.agent){let u=Date.now(),f=Qs(l),d=f[f.length-1],p=d.agent,h=d.sessionId??null;d.endedAt=u,r.reason&&(d.endReason=r.reason);let w=c.agent==="claude"&&!!c.sessionId;f.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:w,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.sessionId=c.sessionId||null,l.pinned=w,l.state="live",n.pendingHandoffHydrate={artifact:Co,at:u},Te(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:p,toAgent:r.toAgent,fromSessionId:h,toSessionId:c.sessionId||null,epoch:f.length-1,singleBox:!0,skipPermissions:r.skipPermissions,reason:r.reason??null,handoffStartedAt:r.startedAt,recovered:!0}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await re({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:"done",recovered:n.handoff.recovered,fromBox:r.fromBox,toBox:r.toBox}).catch(()=>{});continue}}let a=!s&&o.recovered==="rolled-back"&&r.toBox&&r.toBox!==n.leadBox?r.toBox:null,i=!s&&o.step==="done"?r.fromBox:null;n.handoff=o,await re({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await Yt(i).catch(()=>{}),a&&await Yt(a).catch(()=>{})}return t&&await ee(),t}async function Hu(e,t,n=!0,r=null){let o=ea.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=he(await Z(),e);if(!s)throw new Error(`track "${e}" not found`);tc(e,"handoff");let a=await Zi(t,n),i=yo(t);if(i){let u=new Error(`can't hand off to ${t} \u2014 its ${i.window} spend limit is reached ($${i.spentUsd.toFixed(2)} of $${i.limitUsd.toFixed(2)})`);throw u.usageCap=i,u}let c=await ge(s.leadBox);if(!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l={trackId:e,step:"checkpoint",fromBox:s.leadBox,toAgent:t,skipPermissions:n,reason:tE(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return ea.set(e,l),await Ou(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),yL(l,s,c,a,t).catch(async u=>{l.error=u?.message||String(u),l.finishedAt=Date.now(),console.error(`[lead-handoff ${e}] FAILED at step "${l.step}": ${l.error}`),await Ou(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),re({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),re({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function yL(e,t,n,r,o){let s=async(B,T={})=>{e.step=B,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${B}`),await Ou(e.trackId,{step:B,toBox:e.toBox}),await re({flow:"lead-handoff",phase:B,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:T.sessionName,...T})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await Z(),i=he(a,e.trackId)?.boxes.find(B=>B.name===e.fromBox)||null,c=i?.agent||n.agent,l=i?.sessionId??n.sessionId??null,u=i?.pinned===!0;if(await s("checkpoint",{sessionName:e.fromBox}),e.checkpoint="llm",yo(c))e.checkpoint="skipped-capped";else try{await tp(e.fromBox,{timeoutMs:QT})}catch(B){e.checkpoint="reconstructed",await re({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:B?.message||String(B)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await np(e.trackId,n.cwd,{trackName:t.name||t.id}).catch(()=>null),await s("checkpoint-degraded",{sessionName:e.fromBox,checkpoint:e.checkpoint,statusArtifact:e.statusArtifact})),await s("swap",{cwd:n.cwd,agentCmd:r});let d=await lp(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let p=Db(d.launchCmd);await hr({cwd:n.cwd,sessionId:d.sessionId,sessionName:e.fromBox,agent:o,agentCmd:na(o),launchEcho:p}).catch(B=>{if(B?.code!=="cli-not-running")throw B});let h=Bf(await Ce(e.fromBox,{lines:Xe}).catch(()=>""),p);if(!gs(o,h)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let B=$h(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await lp(e.fromBox,{agentCmd:B,agent:c,resumeSessionId:l,pinned:u});let T=await Z(),_=he(T,e.trackId);if(_){let O=_.boxes.find(I=>I.name===e.fromBox);O&&(O.state="live"),Te(_,"lead-handoff-failed",{box:e.fromBox,fromAgent:c,toAgent:o,reason:e.reason,error:`incoming ${o} CLI never drew its composer`,rolledBack:!0,handoffStartedAt:e.startedAt}),await ee()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let w=await Z(),g=he(w,e.trackId);if(!g)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let k=g.boxes.find(B=>B.name===e.fromBox);if(!k)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let S=Date.now(),E=Qs(k),R=E[E.length-1];R.endedAt=S,e.reason&&(R.endReason=e.reason),E.push({agent:o,sessionId:d.sessionId,pinned:d.pinned,startedAt:S,endedAt:null}),k.agent=o,k.sessionId=d.sessionId,k.pinned=d.pinned,k.state="live",k.role="lead",g.pendingHandoffHydrate={artifact:e.statusArtifact||Co,at:S},Te(g,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:d.sessionId,epoch:E.length-1,singleBox:!0,forced:d.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint}),await ee(),await s("done",{sessionName:e.fromBox}),await Ou(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function nw(e){let t=_h.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await Z(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 restore it before moving it");if(r.kind==="setup")throw new Error("setup boxes don't move");if(r.transferredTo)throw new Error(`track already transferred to ${r.transferredTo}`);let o=ea.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Nt.values())if(a.trackId===e&&!a.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before moving");let s={trackId:e,step:"checkpoint",startedAt:Date.now(),finishedAt:null,error:null};return _h.set(e,s),bL(s,r).catch(a=>{s.error=a?.message||String(a),s.finishedAt=Date.now(),console.error(`[transfer-out ${e}] FAILED at step "${s.step}": ${s.error}`)}),s}async function bL(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await ge(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&yo(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await tp(t.leadBox,{timeoutMs:QT})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await np(t.id,t.cwd,{trackName:t.name||t.id}).catch(()=>null),e.step="push";let o=t.workspace?.branch??null,s=[];if(o)for(let u of Dt(t.workspace)){if(!u?.dir)continue;let f={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await nn(u.dir,["push","origin",o],Ah);let{stdout:d}=await nn(u.dir,["rev-parse","HEAD"]);f.baseSha=d.trim(),f.pushed=!0}catch(d){f.error=String(d?.message||d).split(`
243
+ `)[0]}s.push(f)}e.step="wip";let a=await lh({id:t.id,cwd:t.cwd},{force:!0}),i=await Z(),c=he(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&Qs(l),await ee(),e.result={name:c?.name??t.name,agent:l?.agent??null,leadBox:c?.leadBox??t.leadBox,createdAt:c?.createdAt??null,branch:o,repos:s.filter(u=>u.pushed).map(({name:u,repo:f,baseSha:d})=>({name:u,repo:f,baseSha:d})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:f,error:d})=>({name:u,repo:f,error:d})),wip:a.pushed?{ref:a.ref,sha:a.sha}:null,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function rw(e){if(!e?.transferredTo)return;let t=new Error(`track "${e.id}" moved to node ${e.transferredTo} \u2014 drive it there`);throw t.transferredTo=e.transferredTo,t}async function Wu(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await Z(),o=he(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};jh(e),await Kh(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();Dl(o,{at:s,reason:n==="recover"?"node-offline":"node-transfer"});let a=await uh({id:o.id,cwd:o.cwd});return o.transferredTo=t,o.transferredAt=s,Te(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...a.pushed?{rescueRef:a.ref,rescueSha:a.sha}:{}}),await ee(),{ok:!0,toNode:t,rescue:a.pushed?{ref:a.ref,sha:a.sha}:null}}async function ow(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await Wu(n.id,{toNode:n.toNode,mode:n.mode==="recover"?"recover":"transfer"});t.push({id:n.id,...r})}catch(r){/not found/i.test(String(r?.message))||console.error(`[transfer] demote of ${n.id} failed: ${r?.message||r}`)}return t}async function YT(e,t,n){try{await Nl(e,t,n)}catch{await nn(e,["worktree","prune"]).catch(()=>{}),await Nl(e,t,n)}return t}async function sw(e={}){let{trackId:t,name:n,agent:r="claude",skipPermissions:o=!0,mode:s="transfer"}=e;if(!t||typeof t!="string"||!/^[0-9a-f]{8}$/.test(t))throw new Error("trackId (8-hex string) required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");if(s!=="transfer"&&s!=="recover")throw new Error(`unknown adopt mode "${s}"`);if(kh.has(t))throw new Error("an adopt is already running for this Track");kh.set(t,{startedAt:Date.now()});try{return await kL({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{kh.delete(t)}}async function kL({trackId:e,name:t,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,brief:u=null,epochs:f=[],createdAt:d=null,leadBox:p=null,reason:h=null,downSince:w=null}){let g=await Zi(n,r),k=await Z(),S=he(k,e);if(S&&!S.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);S&&(await uh({id:S.id,cwd:S.cwd}).catch(()=>{}),await pE(S),k.tracks.splice(k.tracks.indexOf(S),1),await ee()),await z.mkdir(Hi,{recursive:!0});let E=J.join(Hi,e);await z.rm(E,{recursive:!0,force:!0}).catch(()=>{});let R=null,B=!1,T=[];try{let _=[];if(i)for(let L of Array.isArray(c)?c:[]){let ce=typeof L=="string"?L:L?.repo;if(!ce||!/^[^/\s]+\/[^/\s]+$/.test(ce))continue;let ue=await Zo(ce)??await Fc(ce);await nn(ue,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],Ah),_.push({slug:ce,base:ue,name:typeof L=="object"?L?.name??null:null})}if(i&&_.length===1){let{base:L,slug:ce}=_[0];await YT(L,E,i),T.push({base:L,dir:E}),await Vi(E);let ue=await Is(L);R={dir:E,base:L,branch:i,kind:"worktree",baseRef:ue,repo:ce}}else if(i&&_.length>=2){await z.mkdir(E,{recursive:!0});let L=new Set([".bostrat"]),ce=[];for(let ue of _){let Ae=ue.name||J.basename(ue.base);L.has(Ae)&&(Ae=ue.slug.replace("/","-"));for(let je=2;L.has(Ae);je++)Ae=`${J.basename(ue.base)}-${je}`;L.add(Ae);let _e=J.join(E,Ae);await YT(ue.base,_e,i),T.push({base:ue.base,dir:_e});let xt=await Is(ue.base);ce.push({name:Ae,dir:_e,base:ue.base,baseRef:xt,repo:ue.slug})}await nc(E,ce,i),R={dir:E,kind:"multi",branch:i,repos:ce}}else B=!0,await z.mkdir(E,{recursive:!0}),await Cp(E),await Vi(E),R={dir:E,base:null,branch:null,kind:"repo"};let O=!1,I=null,U=null;if(l?.sha&&R.kind==="worktree")try{await nn(E,["fetch","origin",l.ref||ch(e)],Ah);let{stdout:L}=await nn(E,["rev-parse","FETCH_HEAD^"]),{stdout:ce}=await nn(E,["rev-parse","HEAD"]),ue=L.trim()===ce.trim();ue||await nn(E,["merge-base","--is-ancestor",ce.trim(),L.trim()]).then(()=>!0,()=>!1)&&(await nn(E,["reset","--hard",L.trim()]),U={from:ce.trim(),to:L.trim()},ue=!0),ue?(await nn(E,["read-tree","--reset","-u","FETCH_HEAD"]),await nn(E,["reset","-q"]),O=!0):I="snapshot does not parent the fetched branch head"}catch(L){I=String(L?.message||L).split(`
244
+ `)[0]}else l?.sha&&(I="wip snapshots cover single-repo worktrees only");await WT({id:e,cwd:E}).catch(()=>({restored:!1}));let H=J.join(E,Co),ae=null;(await Zc(E)).restored?ae="checkpoint":typeof u=="string"&&u.trim()&&(await z.mkdir(J.dirname(H),{recursive:!0}),await z.writeFile(H,u),ae="brief");let C=new Set(k.tracks.flatMap(L=>(L.boxes||[]).map(ce=>ce.name))),Q=null;p&&!C.has(p)&&!await ge(p).catch(()=>null)?Q=p:(Q=`${t.trim()} lead`,C.has(al(Q))&&(Q=`${t.trim().slice(0,50).trim()} ${e} lead`));let ve=await pr(Q,E,{agentCmd:g,agent:n});Xa({cwd:ve.cwd,sessionName:ve.name,agent:n,agentCmd:g});let W=Date.now(),be=Qh(ve,"lead","live"),se=(Array.isArray(f)?f:[]).filter(L=>L&&typeof L=="object").map(L=>({...L})),pe=se[se.length-1];pe&&pe.endedAt==null&&(pe.endedAt=W,pe.endReason==null&&(pe.endReason=o==="recover"?"node-offline":"node-transfer")),se.push({agent:n,sessionId:ve.sessionId??null,pinned:ve.pinned===!0,startedAt:W,endedAt:null}),be.epochs=se;let ie={id:e,name:t.trim(),cwd:ve.cwd,workspace:R,leadBox:ve.name,boxes:[be],events:[],createdAt:Number.isFinite(d)?d:W,...ae?{pendingHandoffHydrate:{artifact:Co,at:W}}:{}};return Te(ie,"transferred-in",{box:ve.name,agent:n,fromNode:s,toNode:a,mode:o,reason:h,...o==="recover"?{downSince:Number.isFinite(w)?w:null}:{},branch:R.branch??null,wip:O,...U?{wipAdvanced:U}:{},epoch:se.length-1,name:ie.name,cwd:ie.cwd,workspace:{base:R.base??null,branch:R.branch??null,kind:R.kind,...R.baseRef?{baseRef:R.baseRef}:{},...R.repo?{repo:R.repo}:{},...R.repos?{repos:R.repos.map(({name:L,base:ce,baseRef:ue,repo:Ae})=>({name:L,base:ce,baseRef:ue,repo:Ae}))}:{}}}),k.tracks.push(ie),await ee(),{...await Mt(ie),adopt:{wipApplied:O,wipSkipped:I,...U?{wipAdvanced:U}:{},codeless:B,artifactSource:ae}}}catch(_){for(let O of T)await Rt(O.base,O.dir).catch(()=>{});throw await z.rm(E,{recursive:!0,force:!0}).catch(()=>{}),_}}async function gE(e,t,n){let r=await Z(),o=he(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await ee())}async function Ys(e,t){e.step=t,await oc(e)}function yE(e,t=Date.now()){if(!e||e.finishedAt)return null;let n=e.step;return["snapshot","spawn","working"].includes(n)?{...e,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${n}"; no changes were applied to the lead \u2014 retry the delegation`,recovered:"rolled-back"}:{...e,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${n}"; the lead's working tree may hold a PARTIAL merge \u2014 review git status. The subtask's work is preserved on branch ${e.branch}`,recovered:"partial-merge"}}function bE(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function TL(e,t,n){if(!bE(n)||Nt.has(t)||!await ge(n.box).catch(()=>null))return!1;try{await z.access(n.dir)}catch{return!1}let o=await ge(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return Nt.set(t,s),xE(s,o).catch(a=>kE(s,a)),!0}async function aw(){let e=await Z(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Nt.has(r))continue;if(await TL(n,r,o)){t=!0,Te(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await re({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=yE(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!Fr.has(i.state)&&(i.state="canceled"),Te(n,"subtask-failed",{from:o.box,fromAgent:o.agent,task:o.task,subtaskId:r,failedStep:s,error:a.error,recovered:a.recovered,durationMs:o.startedAt?a.finishedAt-o.startedAt:null}),await re({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await JT(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||Fr.has(r.state)||Nt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?J.join(ta,`${n.id}-${r.subtaskId}`):null;await re({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await JT(n,r.name,o)}}return t=await EL(e)||t,t&&await ee(),t}async function JT(e,t,n){if(t&&await Yt(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of Dt(e.workspace)){let s=J.join(n,o.name);await Rt(o.base,s).then(()=>!0,()=>!1)||await Rt(o.dir,s).catch(()=>{})}await z.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await ge(e.leadBox).catch(()=>null);r?.cwd&&await Rt(r.cwd,n).catch(()=>{})}async function EL(e){let t;try{t=await z.readdir(ta)}catch{return!1}let n=new Set;for(let o of e.tracks||[]){for(let s of Object.keys(o.subtasks||{}))n.add(`${o.id}-${s}`);for(let s of o.boxes||[])s.subtaskId&&n.add(`${o.id}-${s.subtaskId}`)}for(let o of Nt.values())o.dir&&n.add(J.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=J.join(ta,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of Dt(a.workspace))await Rt(i.base,J.join(s,i.name)).catch(()=>{});await z.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await ge(a.leadBox).catch(()=>null):null;i?.cwd?await Rt(i.cwd,s).catch(()=>{}):await z.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await re({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function cw(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!Ts(n))throw new Error("task (string) required");let s=await Zi(t,r),a=yo(t);if(a){let p=new Error(`can't delegate to ${t} \u2014 its ${a.window} spend limit is reached ($${a.spentUsd.toFixed(2)} of $${a.limitUsd.toFixed(2)})`);throw p.usageCap=a,p}let i=he(await Z(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await ge(i.leadBox);if(!c)throw new Error(`lead box "${i.leadBox}" is not running`);if(!c.cwd)throw new Error("can't resolve the lead's working directory");let l=i.workspace?.kind==="multi",u=null;if(l){let p=Dt(i.workspace);if(!p.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let h of p)if(!h?.dir||!await Es(h.dir))throw new Error(`tagged checkout "${h?.name??"?"}" is missing from the lead workspace (${h?.dir??"no dir"})`);u=p.map(h=>({name:h.name,leadDir:h.dir,base:null}))}else if(!await Es(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let f=Po().slice(0,8),d={id:f,trackId:e,trackName:i.name,agent:t,task:Ts(n),skipPermissions:r,reason:tE(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${iw(i.name)}-${f}`,base:null,repos:u,dir:J.join(ta,`${e}-${f}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Nt.set(f,d),await oc(d),AL(d,c,s).catch(p=>kE(d,p)),d}async function kE(e,t){e.failedStep=e.step,e.error=t instanceof Ji?"canceled":t?.message||String(t),e.step=t instanceof Ji?"canceled":"error",e.finishedAt=Date.now(),await uw(e).catch(()=>{}),await oc(e).catch(()=>{}),await RL(e).catch(()=>{})}function Ku(e){let t=Nt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");return t.canceled=!0,t}function lw(e){let t=Nt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");if(t.step!=="working")throw new Error(`subtask is not waiting to merge (step: ${t.step})`);return t.forceMerge=!0,t}async function AL(e,t,n){if(await Ys(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await As(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await oc(e)}else e.base=await As(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await Ys(e,"spawn"),await z.mkdir(ta,{recursive:!0}),e.repos){await z.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await _s(a.leadDir,J.join(e.dir,a.name),e.branch,a.base);let s=Dt((he(await Z(),e.trackId)||{}).workspace);await nc(e.dir,e.repos.map(a=>{let i=s.find(c=>c?.name===a.name);return{name:a.name,repo:i?.repo??null,baseRef:null}}),e.branch)}else await _s(t.cwd,e.dir,e.branch,e.base),await Vi(e.dir);await _L(e,t);let r=e.trackName.slice(0,38).trim(),o=await pr(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await IL(e,o),await nE(e.trackId,o.name,_j(e.task,!!e.repos),{kind:"subtask"}),await xE(e,t)}async function xE(e,t){await Ys(e,"working");let n=J.join(e.dir,Ru);if(await CL(n,e),e.canceled)throw new Ji;if(await Ys(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=J.join(e.dir,l.name);await Op(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:zT({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await Np(l.leadDir,l.base,e.branch,zs),l.files=await Pp(l.leadDir,l.base,e.branch,zs);let f=await Dp(l.leadDir,l.base,e.branch,zs);l.applied=f.applied,l.conflicts=f.conflicts??[],s.files+=l.stat.files,s.insertions+=l.stat.insertions,s.deletions+=l.stat.deletions,a.push(...l.files.map(d=>J.join(l.name,d))),i.push(...l.conflicts.map(d=>d.startsWith("patch did not apply cleanly")?`${l.name}: ${d}`:J.join(l.name,d))),f.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await Op(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:zT({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await Np(t.cwd,e.base,e.branch,zs),e.files=await Pp(t.cwd,e.base,e.branch,zs);let s=await Dp(t.cwd,e.base,e.branch,zs);e.applied=s.applied,e.conflicts=s.conflicts}await oc(e);let r=await OL(e,t,n);await Ys(e,"resume"),await nE(e.trackId,e.leadBox,Ij(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await Ys(e,"reap"),await uw(e),e.step="done";let o=Date.now();await gE(e.trackId,e.id,{...qu(e),finishedAt:o}),await $L(e,o),e.finishedAt=o}async function _L(e,t){let n=J.join(e.dir,J.dirname(Wi));await z.mkdir(n,{recursive:!0});let r="";try{r=await bb(t.cwd,t.sessionId)}catch{}if(!r)try{r=await z.readFile(J.join(t.cwd,".bostrat/handoff/latest.md"),"utf8")}catch{r="_(no prior conversation digest available \u2014 rely on the working tree.)_"}let o=`# Lead context for subtask ${e.id}
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 z.writeFile(J.join(e.dir,Wi),o)}async function IL(e,t){let n=await Z(),r=he(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:va(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),Te(r,"subtask-delegated",{to:t.name,toAgent:e.agent,task:e.task,subtaskId:e.id,skipPermissions:e.skipPermissions,reason:e.reason}),r.subtasks=r.subtasks||{},r.subtasks[e.id]={...r.subtasks[e.id]||{},...qu(e)},await ee())}async function $L(e,t=e.finishedAt){let n=await Z(),r=he(n,e.trackId);if(!r)return;let o=r.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=e.conflicts.length?"conflict":"merged",o.stat=e.stat),Te(r,"subtask-merged",{from:e.box,fromAgent:e.agent,task:e.task,subtaskId:e.id,stat:e.stat,conflicts:e.conflicts.length,files:e.files,durationMs:t?t-e.startedAt:null}),await ee()}async function RL(e){let t=await Z(),n=he(t,e.trackId);if(!n)return;let r=e.canceled||e.error==="canceled",o=n.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=r?"canceled":"failed"),Te(n,r?"subtask-canceled":"subtask-failed",{from:e.box,fromAgent:e.agent,task:e.task,subtaskId:e.id,failedStep:e.failedStep||e.step,error:e.error,durationMs:e.finishedAt?e.finishedAt-e.startedAt:null}),n.subtasks=n.subtasks||{},n.subtasks[e.id]={...n.subtasks[e.id]||{},...qu(e)},await ee()}async function OL(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=J.join(t.cwd,r);await z.mkdir(J.dirname(o),{recursive:!0}),await z.copyFile(n,o)}catch{}return r}async function uw(e){if(e.dir&&await Zd(e.dir).catch(()=>{}),e.box&&await Yt(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await Rt(t.leadDir,J.join(e.dir,t.name)).catch(()=>{});await z.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await ge(e.leadBox).catch(()=>null))?.cwd;n&&await Rt(n,e.dir).catch(()=>{})}}async function CL(e,t){let n=(t.startedAt||Date.now())+xL;for(;;){if(t.canceled||t.forceMerge)return;try{await z.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await No(vL)}}function No(e){return new Promise(t=>setTimeout(t,e))}var XT,En,ZT,Tj,Hi,Ej,Cu,Xi,Lr,Co,QT,Aj,Ru,Wi,_j,Ij,qt,ph,he,mh,Te,hh,wh,Oj,Fr,KT,Nj,Pj,Dj,Bj,Fj,qi,GT,Wj,qj,Kj,Gj,Vj,Js,Ki,Xj,Qj,eL,rL,uE,Gi,dE,iL,Ui,gh,cL,yh,fL,zi,pL,mL,VT,bh,Eh,Qh,ea,ra,Ah,nn,_h,tw,kh,xL,vL,ta,zs,Nt,SL,jo,qu,oc,iw,Ji,Nr=j(()=>{Oa();lt();op();zk();Za();cr();pl();Qk();it();dn();Yo();fl();w0();io();Ap();Ip();M0();bl();Uf();ml();Xf();Xt();Pl();ar();Bn();Qa();Fl();ax();Wp();eS();Qf();Vf();nS();Em();me();wu();xu();Si();bo();qm();Ks();eh();Iu();ih();Fn();uu();jT();dh();qT();Qc();XT=Sj(vj),En=process.env.BOSTRAT_STATE_DIR||J.join(process.env.HOME||"/tmp",".bostrat"),ZT=J.join(En,"tracks.json"),Tj=J.join(En,"events.jsonl"),Hi=J.join(En,"workspaces"),Ej=process.env.BOSTRAT_DEFAULT_REPO||null,Cu={claude:{envVar:"BOSTRAT_AGENT_CMD",base:"claude",skipFlag:"--dangerously-skip-permissions"},cursor:{envVar:"BOSTRAT_CURSOR_CMD",base:"cursor-agent",skipFlag:"--force"},codex:{envVar:"BOSTRAT_CODEX_CMD",base:"codex",skipFlag:"--dangerously-bypass-approvals-and-sandbox"}},Xi=Object.keys(Cu);Lr={at:0,value:null};Co=".bostrat/handoff/latest.md",QT=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;Aj=/\(Read \S{1,300} for handoff context from the prior lead — you are now the lead; none of the prior chat is in your context\. Then respond to the user above\.\)$/;Ru=".bostrat/handoff/subtask-result.md",Wi=".bostrat/handoff/lead-context.md",_j=(e,t=!1)=>t?`You are a SUBTASK agent working in an isolated multi-repo workspace, delegated by a lead agent on a shared workstream. This directory is NOT itself a git repo: each subdirectory is an isolated git worktree of one of the workstream's repos, already seeded with the lead's full working tree for that repo. The conversation so far is summarized in ${Wi} \u2014 read that first for context. Your scoped task:
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 ${Ru} (at this directory's root) with sections \u2014 Result (what you did), Files (paths you changed, prefixed with the repo directory), Notes (anything the lead must know). Writing that file is your DONE signal: do it last, then stop and take no further action.`:`You are a SUBTASK agent working in an isolated git worktree, delegated by a lead agent on a shared workstream. The lead's full working tree is already checked out here, and the conversation so far is summarized in ${Wi} \u2014 read that first for context. Your scoped task:
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 ${Ru} with sections \u2014 Result (what you did), Files (paths you changed), Notes (anything the lead must know). Writing that file is your DONE signal: do it last, then stop and take no further action.`,Ij=(e,t,n,r)=>`A subtask box you delegated has finished: "${e}". Its changes are now merged into your working tree (${t.files} file${t.files===1?"":"s"}, +${t.insertions} \u2212${t.deletions}). Read ${r} for exactly what it did. `+(n.length?`IMPORTANT: ${n.length} merge conflict${n.length===1?"":"s"} need resolving \u2014 fix the conflict markers in: ${n.join(", ")}, then continue.`:"Review the merged changes and continue the work."),qt=null,ph=null;he=(e,t)=>e.tracks.find(n=>n.id===t)||null,mh=Promise.resolve();Te=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),$j(e.id,r),lx(e,r),r};Sb(async({sessionName:e,from:t,to:n,version:r,status:o,error:s})=>{let i=(await Z()).tracks.find(c=>c.leadBox===e||(c.boxes||[]).some(l=>l.name===e));i&&(Te(i,"codex-update",{box:e,from:t,to:r||n,status:o,...s?{error:s}:{}}),await ee().catch(()=>{}))});hh=J.join(En,"plane-link","update-notice.json");wh=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),Oj=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);Fr=new Set(["merged","conflict","canceled","failed","handed-off"]),KT=new Map;Nj=5e3;Pj={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};Dj=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];Bj=10*6e4;Fj=1500,qi=new Map;GT="Spin up a live preview View of this app so I can see it on another device. From the repo root, run `bostrat-view up --name \"<short name>\" -- <serve command>` \u2014 pick the right dev/serve command for this repo yourself (e.g. `npm run dev`), pass $PORT through if the command needs an explicit port, and share the public URL it prints. If a suitable View is already live, just re-share its URL instead of starting another. Don't paste a localhost link \u2014 it's dead on my device.\n\nIMPORTANT: if you cannot confidently identify WHICH project/app to serve, or which serve command to use (e.g. several apps in this tree, or no obvious dev script), do NOT guess and do NOT run `bostrat-view up`. Instead, reply with a short question asking me which one you should preview, and stop.";Wj=4e3,qj=3,Kj=[300,350,400],Gj=1e3,Vj=12,Js=new Map,Ki=new Map;Xj=[250,400,500,600];Qj=3e4,eL=[350,650,900];rL=12e4;uE=e=>({branch:e.branch,kind:e.kind,repos:(e.repos??[]).filter(Boolean).map(({name:t,base:n,baseRef:r,repo:o})=>({name:t,base:n,baseRef:r,repo:o}))});Gi="# bostrat workspace",dE=`${Gi}
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
+ `,iL=dE,Ui=dE+ik;gh=e=>typeof e=="string"&&(e===Gi||e.startsWith(`${Gi}
585
+ `)),cL="# bostrat multi-repo workspace";yh=Ui.replace(`${Gi}
586
+ `,`${Gi}
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
+ `);fL=new Set(["claude","codex","cursor"]);zi=new Set,pL=e=>zi.has(e);mL=9e4;VT={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};bh=new Map;Eh=120;Qh=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:va(e.hookToken),createdAt:Date.now()});ea=new Map,ra=e=>ea.get(e)||(qt?he(qt,e)?.handoff:null)||null;Ah=6e4,nn=(e,t,n=15e3)=>XT("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),_h=new Map,tw=e=>_h.get(e)||null;kh=new Map;xL=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,vL=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,ta=J.join(En,"worktrees"),zs=[Wi,Ru],Nt=new Map,SL=e=>Nt.get(e)||(qt?qt.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,jo=e=>{let t=new Map([...Nt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=qt?he(qt,e):null;if(n?.subtasks)for(let[r,o]of Object.entries(n.subtasks))t.has(r)||t.set(r,o);return[...t.values()].sort((r,o)=>r.startedAt-o.startedAt)},qu=e=>({id:e.id,trackId:e.trackId,trackName:e.trackName,agent:e.agent,task:e.task,skipPermissions:e.skipPermissions,reason:e.reason||null,step:e.step,failedStep:e.failedStep||null,box:e.box,branch:e.branch,base:e.base,repos:e.repos||null,dir:e.dir,stat:e.stat,files:e.files||null,conflicts:e.conflicts||[],applied:e.applied,error:e.error,canceled:e.canceled,startedAt:e.startedAt,finishedAt:e.finishedAt});oc=e=>gE(e.trackId,e.id,qu(e));iw=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",Ji=class extends Error{}});lt();import xe from"node:path";import mt from"node:fs";import XH from"node:readline";import{fileURLToPath as ZH}from"node:url";import Gt from"express";import QH from"node:http";import eW from"node:https";import _d from"node:os";import{WebSocketServer as tW}from"ws";lt();import wO from"node-pty";async function Xy(e,t,n={}){if(!Pe(t)){ul(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await fr()){ul(e,`host tmux server not running on ${$t}`),e.close(1011,"tmux server unavailable");return}if(!await ge(t)){ul(e,`session "${t}" not found`),e.close(1008,"session not found");return}let r=Jy(n.cols,120,Zy),o=Jy(n.rows,32,Qy),s;try{s=wO.spawn(K,["-S",$t,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){ul(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&mf(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(mf(e,{type:"exit",code:a??null,signal:i??null}),e.close(1e3,"tmux exited"))}),e.on("message",a=>{let i;try{i=JSON.parse(a.toString())}catch{return}if(!(!i||typeof i!="object")){if(i.type==="data"&&typeof i.data=="string")s.write(i.data);else if(i.type==="resize"&&kO(i.cols,i.rows))try{s.resize(Math.min(500,i.cols|0),Math.min(500,i.rows|0))}catch{}}}),e.on("close",()=>{try{s.kill()}catch{}bO(t)})}var gO=6,yO=250;async function bO(e,t=gO,n=yO){for(let r=0;r<t;r++){if(await oo(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var Zy=20,Qy=6;function kO(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=Zy&&Number(t)>=Qy}function Jy(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function mf(e,t){try{e.send(JSON.stringify(t))}catch{}}function ul(e,t){mf(e,{type:"error",message:t})}function eb(e){let t=typeof e=="string"&&e?e:"/",n=t.indexOf("?"),r=n===-1?t:t.slice(0,n),o=n===-1?"":t.slice(n+1),s=r.match(/^\/api\/attach\/([^/]+)$/);if(!s)return{ok:!1,status:404};let a;try{a=decodeURIComponent(s[1])}catch{return{ok:!1,status:400}}let i=new URLSearchParams(o);return{ok:!0,sessionName:a,cols:Number(i.get("cols"))||void 0,rows:Number(i.get("rows"))||void 0}}Xt();fl();op();Nr();import{createRequire as nW}from"node:module";var ML=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function dw({tracks:e=[],views:t=[],queuedOf:n=()=>[]}={}){let r=[];for(let o of e)!o||o.archivedAt&&!o.archiving||o.transferredTo||(o.working&&r.push(`working:${o.id}`),o.prompted&&r.push(`prompted:${o.id}`),(n(o.id)??[]).length&&r.push(`queued:${o.id}`),(o.boxes||[]).some(s=>s?.role==="subtask"&&s?.state==="live")&&r.push(`subtask:${o.id}`),Object.values(o.subtasks||{}).some(ML)&&r.push(`merge-back:${o.id}`));return t.some(o=>o?.state==="live"||o?.state==="starting")&&r.push("views"),{busy:r.length>0,reasons:r}}import NE from"node:fs";import Hr from"node:fs/promises";import JL from"node:os";import st from"node:path";import{spawn as XL}from"node:child_process";import{createRequire as ZL}from"node:module";me();Fl();import OE from"node:fs";import ac from"node:fs/promises";import DL from"node:http";import on from"node:path";import Vu from"node:os";import{createRequire as BL}from"node:module";import pw from"ws";import NL from"node:path";import PL from"node:os";var sc=process.env.BOSTRAT_STATE_DIR||NL.join(process.env.HOME||PL.tmpdir(),".bostrat");function fw(e=process.env){let t=(e.BOSTRAT_HOST||"").trim();if(t!=="all")return t||(e.BOSTRAT_PLANE_URL?"127.0.0.1":void 0)}function SE(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=fw(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function TE(e){let t=String(e||"").trim();if(!t)return"";let n=/^[a-z][a-z0-9+.-]*:\/\//i.test(t)?t:`wss://${t}`,r;try{r=new URL(n)}catch{return t}let o={"https:":"wss:","http:":"ws:","wss:":"wss:","ws:":"ws:"}[r.protocol];return o?(r.protocol=o,(r.pathname===""||r.pathname==="/")&&(r.pathname="/v1/node"),r.toString()):t}var rn=(()=>{try{return BL(import.meta.url)("../package.json").version||null}catch{return null}})(),EE=process.env.BOSTRAT_STATE_DIR||on.join(process.env.HOME||Vu.tmpdir(),".bostrat");function Lo({env:e=process.env,pkgDir:t=on.resolve(on.dirname(new URL(import.meta.url).pathname),".."),exists:n=OE.existsSync}={}){let r=String(e.BOSTRAT_INSTALL_KIND||"").trim();return["container","npm-global","git-checkout","dev"].includes(r)?r:/\/lib\/node_modules\/bostrat-node(?:\/|$)/.test(t.replace(/\\/g,"/"))?"npm-global":n(on.join(t,"..",".git"))?"git-checkout":"dev"}function ic(e,t){let n=String(e).split(".").map(Number),r=String(t).split(".").map(Number);if(n.some(Number.isNaN)||r.some(Number.isNaN))return!1;for(let o=0;o<Math.max(n.length,r.length);o++){let s=(n[o]||0)-(r[o]||0);if(s)return s<0}return!1}function Gu(e){switch(e){case"npm-global":return"npm install -g bostrat-node && restart the bostrat-node service";case"git-checkout":return"scripts/deploy-pi.sh (or The Bakery \u2192 Deploy to Pi \u2192 bostrat)";case"container":return"Links \u2192 Fly \u2192 Update (or the plane's auto-update while the node sleeps)";default:return"update this node's bostrat-node checkout/install"}}function jL({home:e=process.env.HOME||Vu.homedir(),env:t=process.env}={}){let n=r=>{try{return OE.statSync(r),!0}catch{return!1}};return{claude:n(on.join(e,".claude",".credentials.json")),codex:n(on.join(t.CODEX_HOME||on.join(e,".codex"),"auth.json"))}}var ot=1,AE=1e3,_E=3e4,LL=6e4,FL=1500,UL=500,Ur=100,HL=2e3,WL=25e3,qL=6e4,CE=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},KL=CE(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),GL=3e4,IE=10*6e4,VL=400,$E=250,zL=CE(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),mw=4,YL=6e4,RE=6e4;function ME({url:e,token:t,nodeId:n=Vu.hostname(),name:r=Vu.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,metricsMs:c=YL,onUpdateAvailable:l=null,onUpdatePolicy:u=null,onHelloRefused:f=null,updatePolicy:d=null,installKind:p=Lo(),selfUrl:h=`http://127.0.0.1:${process.env.PORT||3362}`,onDegraded:w=null,onRecovered:g=null,ingestMode:k=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:S=KL,unackedRetryMs:E=qL,pingMs:R=WL,maxInflightEvents:B=VL,httpTimeoutMs:T=zL,stallBackoffMinMs:_=GL,fetchImpl:O=globalThis.fetch,log:I=console}){if(!e||!t)throw new Error("plane-link: url and token are required");if(typeof o!="function")throw new Error("plane-link: listTracks is required");e=TE(e);let U=h.replace(/^http/,"ws"),H=new Set,ae=new Map,X=new Map,C=on.join(EE,"plane-link","cursor.json"),Q=on.join(EE,"plane-link","dead-letter.ndjson"),ve=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),W={},be={},se=new Map,pe=null,ie=null,L=0,ce=0,ue=0,Ae=Promise.resolve(),_e="ws",xt=0,je=!1,A=0,G=!1,Ge=Ur,_t=new Set,at=[],nt=null,y=null,m=!1,b=!1,M=AE,ne=null,de=null,De=null,ht=null,Re=null,ya=!1,Mc=0;async function VI(){try{W=JSON.parse(await ac.readFile(C,"utf8"))}catch{W={}}}function zI(){ya=!0,!De&&(De=setTimeout(async()=>{if(De=null,!!ya){ya=!1;try{await ac.mkdir(on.dirname(C),{recursive:!0}),await ac.writeFile(C,JSON.stringify(W))}catch(P){I.error("[plane-link] cursor flush failed:",P?.message||P)}}},HL),De.unref?.())}function rt(P){return!y||y.readyState!==pw.OPEN?!1:(y.send(JSON.stringify(P)),!0)}function ba(P){let D=Date.now();for(let{trackId:x,event:N}of P){let q=se.get(N.id);se.set(N.id,{trackId:x,seq:N.seq,event:N,sentAt:D,firstSentAt:q?.firstSentAt??D,retryAt:D+E,tries:(q?.tries??0)+1,nacks:q?.nacks??0})}return _e==="http"?(ZI(P),!0):rt({v:ot,ch:"events",type:"append",events:P})}function YI(P){let D=null;for(let x of se.values())x.trackId===P&&(D==null||x.seq<D)&&(D=x.seq);return D}function Od(P){let D=be[P];if(D==null)return;let x=YI(P),N=x==null?D:Math.min(D,x-1);N>(W[P]??0)&&(W[P]=N,zI())}function ka(){if(pe=Date.now(),ie!=null){let P=Date.now()-ie;I.log(`[plane-link] spine sync recovered after ${Math.round(P/1e3)}s degraded (${L} stall redial(s))`);let D=ie;ie=null,L=0,ce=0,je=!1,A=0;try{g?.({since:D,downMs:P})}catch(x){I.error(`[plane-link] onRecovered failed: ${x?.message||x}`)}}}function Cd(P){if(!Array.isArray(P)||!P.length)return;let D=new Set;for(let x of P){let N=se.get(x);N&&(se.delete(x),(be[N.trackId]??0)<N.seq&&(be[N.trackId]=N.seq),D.add(N.trackId))}for(let x of D)Od(x);ka()}function Eg(P,D){ue++;let x={at:Date.now(),trackId:P.trackId,seq:P.seq,id:P.event?.id??null,type:P.event?.type??null,reason:D,event:P.event??null};I.error(`[plane-link] DEAD-LETTER ${P.trackId} seq ${P.seq} (${x.type??"?"}): plane rejected it permanently (${D}) \u2014 kept in ${Q}`),Ae=Ae.then(async()=>{await ac.mkdir(on.dirname(Q),{recursive:!0}),await ac.appendFile(Q,JSON.stringify(x)+`
593
+ `)}).catch(N=>I.error(`[plane-link] dead-letter write failed: ${N?.message||N}`))}function Ag(P,D,x,N=null){if(!Array.isArray(P)||!P.length)return;let q=new Set,ye=Date.now();for(let Ee of P){let Be=se.get(Ee);Be&&(x?(se.delete(Ee),Eg(Be,D),(be[Be.trackId]??0)<Be.seq&&(be[Be.trackId]=Be.seq),q.add(Be.trackId)):(Be.nacks++,Be.retryAt=ye+Math.max(1e3,Number(N)||E)))}for(let Ee of q)Od(Ee);ka()}function _g(P=Date.now()){let D=1/0;for(let x of se.values())x.firstSentAt<D&&(D=x.firstSentAt);return D===1/0?0:P-D}function Ig(){if(!m||!se.size)return;let P=Date.now(),D=_g(P);if(D<S||pe!=null&&P-pe<S||_e==="http"&&je||ce>P)return;L++;let x=Math.min(_*2**(L-1),IE);if(ie==null){ie=P-D,I.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(D/1e3)}s with ${se.size} event(s) in flight (${_e} door) \u2014 the plane is not answering appends`);try{w?.({since:ie,unacked:se.size,oldestAgeMs:D,mode:_e})}catch(N){I.error(`[plane-link] onDegraded failed: ${N?.message||N}`)}}if(_e==="http"){je=!0,A=P+x,I.error(`[plane-link] ingest circuit OPEN (stall #${L}); probing /v1/ingest/health in ${Math.round(x/1e3)}s`);return}ce=P+x,I.error(`[plane-link] closing the link and redialing in ${Math.round(x/1e3)}s (stall redial #${L})`);try{y?.terminate()}catch{}}function Md(){if(!m)return;let P=Date.now();if(_e==="http"&&je)return;let D=[...se.values()].filter(N=>N.event&&N.retryAt<=P&&!(_e==="http"&&_t.has(N.trackId)));if(!D.length)return;D.sort((N,q)=>N.trackId===q.trackId?N.seq-q.seq:N.trackId<q.trackId?-1:1),I.log(`[plane-link] re-sending ${D.length} unacked event(s) the plane never confirmed`);let x=_e==="http"?Ge:Ur;if(_e==="http"){let N=new Map;for(let q of D)(N.get(q.trackId)??N.set(q.trackId,[]).get(q.trackId)).push(q);for(let[,q]of N){if(xt>=mw)return;ba(q.slice(0,x).map(ye=>({trackId:ye.trackId,event:ye.event})))}return}for(let N=0;N<D.length;N+=x){let q=D.slice(N,N+x).map(ye=>({trackId:ye.trackId,event:ye.event}));if(!ba(q))return}}async function JI(P=null){for(;;){if(!m)return!1;let D=se.size<B,x=_e!=="http"||xt<mw&&!je&&(!P||!_t.has(P));if(D&&x)return!0;await new Promise(N=>setTimeout(N,100))}}function Nd(){if(nt=null,!m||!at.length)return;let P=at;if(at=[],_e!=="http"){for(let x=0;x<P.length;x+=Ur)ba(P.slice(x,x+Ur));return}let D=new Map;for(let x of P)(D.get(x.trackId)??D.set(x.trackId,[]).get(x.trackId)).push(x);for(let[x,N]of D){if(_t.has(x)||xt>=mw||je){at.push(...N);continue}for(let q=0;q<N.length;q+=Ge)ba(N.slice(q,q+Ge))}at.length&&!nt&&(nt=setTimeout(Nd,$E),nt.unref?.())}let XI=P=>{let D=new Map;for(let{trackId:x,event:N}of P)(D.get(x)??D.set(x,[]).get(x)).push(N);return[...D].map(([x,N])=>({trackId:x,events:N}))},zo=(P,D,x,{progress:N})=>{let q=Date.now();for(let{event:ye}of P){let Ee=se.get(ye.id);Ee&&(Ee.nacks++,Ee.retryAt=q+Math.max(1e3,x||E))}N&&ka()};async function ZI(P){let D=new Set(P.map(x=>x.trackId));for(let x of D)_t.add(x);xt++;try{let x=await O(`${ve}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:XI(P)}),signal:AbortSignal.timeout(T)}),N=(Number(x.headers.get("retry-after"))||0)*1e3;if(x.status===200){let q=await x.json();Ge=Ur;for(let ye of q.results??[]){Cd(ye.acked??[]);let Ee=(Be,vt)=>{let Lt=new Map;for(let Ye of Be??[])(Lt.get(Ye.reason)??Lt.set(Ye.reason,[]).get(Ye.reason)).push(Ye.id);for(let[Ye,Mg]of Lt)Ag(Mg,Ye,vt,q.retryAfterMs??null)};Ee(ye.rejected,!0),Ee(ye.deferred,!1)}Cd(q.discarded??[]),ka();return}if(x.status===429){zo(P,"overloaded",N||5e3,{progress:!0});return}if(x.status===413&&P.length>1){Ge=Math.max(1,Math.floor(P.length/2)),I.error(`[plane-link] ingest request too large (${P.length} events) \u2014 halving batches to ${Ge}`),zo(P,"too_large",1e3,{progress:!0});return}if(x.status===413){let q=se.get(P[0].event.id);q&&(se.delete(q.event.id),Eg(q,"too_large"),(be[q.trackId]??0)<q.seq&&(be[q.trackId]=q.seq),Od(q.trackId)),ka();return}if(x.status===401||x.status===403){if(Date.now()-Mc>=RE){Mc=Date.now();let q="";try{q=(await x.json())?.error??""}catch{}I.error(`[plane-link] plane refused ingest (HTTP ${x.status}${q?`: ${q}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}zo(P,`http_${x.status}`,6e4,{progress:!1});return}if(x.status===400){I.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${P.length} event(s) for retry; this is a bug, not data`),zo(P,"http_400",6e4,{progress:!1});return}zo(P,`http_${x.status}`,N||5e3,{progress:!1})}catch(x){let N=x?.name==="TimeoutError"||x?.name==="AbortError";N&&P.length>1&&(Ge=Math.max(1,Math.floor(P.length/2)),I.error(`[plane-link] ingest request of ${P.length} event(s) outlived its ${T} ms deadline \u2014 halving batches to ${Ge}`)),zo(P,N?"timeout":"network",5e3,{progress:!1})}finally{xt--;for(let x of D)_t.delete(x)}}async function QI(){if(_e!=="http"||!je||!m||G)return;let P=Date.now();if(!(A>P)){G=!0;try{let D=await O(`${ve}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(T)});if(!D.ok)throw new Error(`HTTP ${D.status}`);I.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),je=!1,A=0,ce=Date.now()+T+E+1e3;for(let x of se.values())x.retryAt=Math.min(x.retryAt,Date.now());Md()}catch(D){L++;let x=Math.min(_*2**(L-1),IE);A=Date.now()+x,I.error(`[plane-link] ingest door still not answering (${D?.message||D}); next probe in ${Math.round(x/1e3)}s`)}finally{G=!1}}}function $g(){let P=Date.now();return{mode:_e,unacked:se.size,oldestUnackedAgeMs:_g(P),lastProgressAt:pe,degradedSince:ie,stallRedials:L,deadLettered:ue,http:_e==="http"?{inFlight:xt,circuitOpen:je,nextProbeInMs:je?Math.max(0,A-P):0,batchCap:Ge}:null}}async function Rg(){if(!i)return;let P;try{P=await i()}catch(D){I.error("[plane-link] metrics sample failed:",D?.message||D);return}P&&rt({v:ot,ch:"ctl",type:"metrics",metrics:{...P,planeLink:$g()}})}function e$(){i&&(Re&&clearInterval(Re),Rg(),Re=setInterval(Rg,c),Re.unref?.())}async function t$(){let P;try{P=await o()}catch(D){I.error("[plane-link] backfill listTracks failed:",D?.message||D);return}rt({v:ot,ch:"ctl",type:"tracks",ids:P.filter(D=>!D.transferredTo).map(D=>D.id).filter(D=>typeof D=="string")});for(let D of P){if(!m)return;let x;try{x=await F(D)}catch{continue}let N=W[D.id]??0,q=x.filter(Ee=>Ee.seq>N&&typeof Ee.id=="string"),ye=_e==="http"?Ge:Ur;for(let Ee=0;Ee<q.length;Ee+=ye){if(!await JI(D.id))return;let Be=q.slice(Ee,Ee+Math.min(ye,_e==="http"?Ge:Ur)).map(vt=>({trackId:D.id,event:vt}));if(!ba(Be))return}}}function Og(P){!m||!P?.trackId||typeof P.id!="string"||(at.push({trackId:P.trackId,event:P}),nt||(nt=setTimeout(Nd,$E),nt.unref?.()))}let xa=new Map;async function n$(P){let{reqId:D,method:x,path:N,headers:q={},body:ye}=P,Ee=Object.fromEntries(Object.entries(q).filter(([,vt])=>vt!=null)),Be=new AbortController;xa.set(D,Be);try{if(P.host){await r$(P,Ee,Be);return}let vt=await fetch(h+N,{method:x,headers:Ee,body:ye?Buffer.from(ye,"base64"):void 0,signal:Be.signal}),Lt=Object.fromEntries(vt.headers);for(let Ye of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete Lt[Ye];if(Lt["content-type"]||(Lt["content-type"]="application/octet-stream"),rt({v:ot,ch:"control",type:"http_head",reqId:D,status:vt.status,headers:Lt}),vt.body){for await(let Ye of vt.body)if(!rt({v:ot,ch:"control",type:"http_data",reqId:D,data:Buffer.from(Ye).toString("base64")}))break}rt({v:ot,ch:"control",type:"http_end",reqId:D,error:null})}finally{xa.delete(D)}}function r$(P,D,x){let{reqId:N,method:q,path:ye,body:Ee}=P,Be=new URL(h);return new Promise(vt=>{let Lt=DL.request({host:Be.hostname,port:Be.port,method:q,path:ye,headers:{...D,host:P.host},signal:x.signal},Ye=>{let{connection:Mg,"keep-alive":kW,"transfer-encoding":xW,upgrade:vW,...o$}=Ye.headers;rt({v:ot,ch:"control",type:"http_head",reqId:N,status:Ye.statusCode||502,headers:o$}),Ye.on("data",s$=>{rt({v:ot,ch:"control",type:"http_data",reqId:N,data:Buffer.from(s$).toString("base64")})||Ye.destroy()}),Ye.on("end",()=>{rt({v:ot,ch:"control",type:"http_end",reqId:N,error:null}),vt()}),Ye.on("error",()=>{rt({v:ot,ch:"control",type:"http_end",reqId:N,error:"view upstream error"}),vt()})});Lt.on("error",Ye=>{rt({v:ot,ch:"control",type:"http_end",reqId:N,error:Ye?.message||"view request failed"}),vt()}),Ee&&Lt.write(Buffer.from(Ee,"base64")),Lt.end()})}function Cg(){if(b)return;y=new pw(e,{headers:{authorization:`Bearer ${t}`}}),y.on("open",async()=>{let D=null;try{D=await s?.()||null}catch{D=null}rt({v:ot,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:rn,installKind:p,...typeof d=="function"?{updatePolicy:d()}:d?{updatePolicy:d}:{},providers:jL(),...D?{agents:D}:{}})}),y.on("message",D=>{let x;try{x=JSON.parse(D)}catch{return}if(x.ch==="ctl"&&x.type==="hello_ok"){m=!0,M=AE,ne=null,I.log(`[plane-link] connected to plane as ${n}`),x.minNodeVersion&&rn&&ic(rn,x.minNodeVersion)&&I.error(`[plane-link] this node is bostrat-node ${rn}; the plane asks for \u2265${x.minNodeVersion} \u2014 update with: ${Gu(p)}`);try{u?.(typeof x.updatePolicy=="string"?x.updatePolicy:null)}catch{}let N=typeof x.latestNodeVersion=="string"?x.latestNodeVersion:null;if(N&&rn&&ic(rn,N)&&!H.has(N)){H.add(N),I.log(`[plane-link] bostrat-node ${N} is available (this node runs ${rn}) \u2014 ${Gu(p)}`);try{l?.({current:rn,latest:N,min:x.minNodeVersion??null,installKind:p,required:!!(x.minNodeVersion&&ic(rn,x.minNodeVersion))})}catch(ye){I.error(`[plane-link] update notice failed: ${ye?.message||ye}`)}}let q=x.ingest==="http";_e=k==="ws"?"ws":k==="http"||q?"http":"ws",k==="http"&&!q&&I.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),_e==="http"&&I.log("[plane-link] spine rides the HTTPS ingest door"),je=!1,A=0,Ge=Ur,ht&&clearInterval(ht),ht=setInterval(()=>{rt({v:ot,ch:"ctl",type:"ping"}),Ig(),QI().catch(()=>{}),Md(),at.length&&!nt&&Nd()},R),ht.unref?.(),e$(),t$().catch(ye=>I.error("[plane-link] backfill failed:",ye?.message||ye));return}if(x.ch==="ctl"&&x.type==="hello_refused"){let N=typeof x.minNodeVersion=="string"?x.minNodeVersion:null,q=typeof x.latestNodeVersion=="string"?x.latestNodeVersion:null;I.error(`[plane-link] plane REFUSED this node: bostrat-node ${rn??"?"} is below its minimum ${N??"?"} \u2014 ${x.fix||Gu(p)}`),M=_E,ne=0;try{f?.({current:rn,min:N,latest:q,fix:x.fix||Gu(p),installKind:p})}catch(ye){I.error(`[plane-link] refusal handler failed: ${ye?.message||ye}`)}return}if(x.ch==="ctl"&&x.type==="update_policy"){try{u?.(typeof x.mode=="string"?x.mode:null)}catch{}return}if(x.ch==="ctl"&&x.type==="usage_caps"){Ll(x.caps??{},{source:"plane",updatedAt:x.updatedAt??Date.now()}).then(N=>I.log(`[plane-link] spend caps ${Object.keys(N.caps).length?`updated (${Object.keys(N.caps).join(", ")})`:"cleared"} from plane`)).catch(N=>I.error("[plane-link] spend-caps push rejected:",N?.message||N));return}if(x.ch==="ctl"&&x.type==="transferred"&&Array.isArray(x.tracks)){Promise.resolve().then(()=>a?.(x.tracks)).catch(N=>I.error("[plane-link] transfer notice failed:",N?.message||N));return}if(x.ch==="events"&&x.type==="ack"&&Array.isArray(x.ids)){Cd(x.ids);return}if(x.ch==="events"&&x.type==="nack"&&Array.isArray(x.ids)){Ag(x.ids,x.reason,x.permanent===!0,x.retryAfterMs??null);return}if(x.ch==="control"&&x.type==="http_open"){n$(x).catch(N=>rt({v:ot,ch:"control",type:"http_end",reqId:x.reqId,error:N?.message||"tunnel error"}));return}if(x.ch==="control"&&x.type==="http_cancel"){xa.get(x.reqId)?.abort();return}if(x.ch==="attach"&&x.type==="open"){let N=new pw(U+x.path,Array.isArray(x.protocols)?x.protocols:[],x.host?{headers:{host:x.host}}:void 0);ae.set(x.streamId,N),X.set(x.streamId,[]),N.on("open",()=>{let ye=X.get(x.streamId)||[];X.delete(x.streamId);for(let{buf:Ee,bin:Be}of ye)N.send(Ee,{binary:Be})}),N.on("message",(ye,Ee)=>{let Be=Ee?ye:Buffer.from(String(ye));rt({v:ot,ch:"attach",type:"data",streamId:x.streamId,data:Be.toString("base64"),...Ee?{bin:!0}:{}})});let q=()=>{X.delete(x.streamId),ae.delete(x.streamId)&&rt({v:ot,ch:"attach",type:"close",streamId:x.streamId})};N.on("close",q),N.on("error",q);return}if(x.ch==="attach"&&x.type==="data"){let N=ae.get(x.streamId);if(!N)return;let q=Buffer.from(x.data,"base64"),ye=x.bin===!0,Ee=X.get(x.streamId);Ee?Ee.push({buf:q,bin:ye}):N.send(q,{binary:ye});return}if(x.ch==="attach"&&x.type==="close"){let N=ae.get(x.streamId);ae.delete(x.streamId),X.delete(x.streamId),N?.close();return}});let P=()=>{m&&I.log("[plane-link] disconnected from plane"),m=!1,ht&&(clearInterval(ht),ht=null),Re&&(clearInterval(Re),Re=null),se.clear(),be={},at=[],nt&&(clearTimeout(nt),nt=null),_t.clear();for(let N of ae.values())N.close();ae.clear(),X.clear();for(let N of xa.values())N.abort();if(xa.clear(),b||de)return;ne==null&&(ne=Date.now());let D=Date.now()-ne<LL,x=Math.max(D?FL+Math.random()*UL:M,ce-Date.now());de=setTimeout(()=>{de=null,Cg()},x),de.unref?.(),D||(M=Math.min(M*2,_E))};y.on("close",P),y.on("error",D=>{let x=/Unexpected server response: (\d+)/.exec(D?.message||"")?.[1];(x==="401"||x==="403")&&Date.now()-Mc>=RE&&(Mc=Date.now(),I.error(`[plane-link] plane refused this node's credentials (HTTP ${x}) \u2014 the token was revoked or is unknown to the plane; mint a new node token and update this node's BOSTRAT_PLANE_TOKEN (still retrying)`)),P()})}return ct.on("event",Og),VI().then(Cg),{stop:()=>{b=!0,ct.off("event",Og),de&&clearTimeout(de),De&&clearTimeout(De),ht&&clearInterval(ht),Re&&clearInterval(Re),nt&&clearTimeout(nt),rt({v:ot,ch:"ctl",type:"bye",reason:"shutdown"}),y?.close()},status:()=>({connected:m,nodeId:n,cursor:{...W},inflight:se.size,...$g()}),_tick:()=>{Ig(),Md()}}}pl();var zu=(()=>{try{return ZL(import.meta.url)("../package.json").version||null}catch{return null}})(),QL=process.env.BOSTRAT_STATE_DIR||st.join(process.env.HOME||JL.tmpdir(),".bostrat"),PE=st.join(QL,"self-update"),Yu=st.join(PE,"status.json"),eF=1440*6e4,tF=6e4,cc=new Set(["npm-global","git-checkout"]);function DE({kind:e=Lo(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:cc.has(e)?e==="git-checkout"||nF(t)?"auto":"prompt":"off"}function nF(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var Bt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function rF({kind:e,to:t,from:n=zu,statusFile:r=Yu,logFile:o=st.join(PE,"last.log"),port:s=Number(process.env.PORT)||3362,npmPrefix:a=null,serviceName:i=process.platform==="darwin"?"com.bostrat.node":"bostrat-node.service",uid:c=typeof process.getuid=="function"?process.getuid():0,liveDir:l=process.env.BOSTRAT_LIVE_CHECKOUT||st.resolve(st.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!cc.has(e))throw new Error(`self-update: install kind "${e}" is not actionable here`);if(!/^\d+\.\d+\.\d+$/.test(String(t)))throw new Error(`self-update: bad target version "${t}"`);if(n&&!/^\d+\.\d+\.\d+$/.test(String(n)))throw new Error(`self-update: bad current version "${n}"`);let f=(g,k="")=>`write_status ${Bt(g)} ${k}`,d=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${Bt(i)}`,p=`
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",k=a?`export PATH=${Bt(st.join(a,"bin"))}:"$PATH"
617
+ `:"",S=a?` --prefix ${Bt(a)}`:"",E=R=>`${Bt(g)} install -g "bostrat-node@${R}" --no-audit --no-fund${S}`;return h+k+`
618
618
  ${f("updating",'"" ')}
619
- if ! ${A("$TO")}; then
619
+ if ! ${E("$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" ] && ${E("$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 lc(e=Yu){try{return JSON.parse(await Hr.readFile(e,"utf8"))}catch{return null}}var oF=new Set(["updating","restarting","rolling-back"]),Ju=e=>!!(e&&oF.has(e.status));async function Xu({to:e,from:t=zu,kind:n=Lo(),reason:r="manual",statusFile:o=Yu,spawnImpl:s=XL,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!cc.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!ic(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await lc(o);if(Ju(l))return{ok:!1,reason:`an update to ${l.to} is already in flight`,status:l};if(l&&l.to===e&&(l.status==="failed"||l.status==="rolled-back"))return{ok:!1,reason:`update to ${e} already ${l.status} (${l.error||"no detail"}) \u2014 retried when a newer release exists`,status:l};await Hr.mkdir(st.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?Of(await sF())||st.resolve(st.dirname(process.execPath),".."):null,f=rF({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),d=st.join(st.dirname(o),`update-${e}.sh`),p=st.join(st.dirname(o),"last.log");await Hr.writeFile(d,f,{mode:448}),await Hr.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let h=NE.existsSync("/run/systemd/system")&&await aF("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",d]]:["setsid",["-f","bash","-c",`exec bash ${Bt(d)} >> ${Bt(p)} 2>&1`]];try{s(h[0],h[1],{detached:!0,stdio:"ignore"}).unref?.()}catch(w){return await Hr.writeFile(o,JSON.stringify({status:"failed",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a(),error:`could not spawn updater: ${w?.message||w}`})),{ok:!1,reason:`could not spawn updater: ${w?.message||w}`}}return c.log?.(`[self-update] ${t??"?"} \u2192 ${e} (${n}, ${r}) started \u2014 status ${o}`),{ok:!0,to:e,from:t,kind:n,scriptFile:d,statusFile:o}}async function sF(){try{return await Hr.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function aF(e){for(let t of String(process.env.PATH||"").split(st.delimiter))try{return await Hr.access(st.join(t,e),NE.constants.X_OK),!0}catch{}return!1}var iF=45*6e4;async function BE({statusFile:e=Yu,current:t=zu,now:n=Date.now,staleMs:r=iF}={}){let o=await lc(e);if(!o)return null;let s=a=>Hr.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Ju(o)){if(t&&o.to===t){let a={...o,status:"done",updatedAt:n(),finishedAt:n(),announced:!0};return await s(a),a}if(n()-Number(o.updatedAt||o.startedAt||0)>r){let a={...o,status:"failed",error:`updater went silent while ${o.status} (no status change for ${Math.round(r/6e4)} min)`,updatedAt:n(),finishedAt:n(),announced:!0};return await s(a),a}return null}if(["failed","rolled-back","done"].includes(o.status)&&!o.announced){let a={...o,announced:!0};return await s(a),a}return null}function jE({isBusy:e,start:t=Xu,onStuck:n=null,onStarted:r=null,tickMs:o=tF,stuckMs:s=eF,now:a=Date.now,setIntervalImpl:i=setInterval,clearIntervalImpl:c=clearInterval,log:l=console}={}){let u=null,f=()=>{u?.timer&&c(u.timer),u=null},d=async()=>{if(!u)return;let p=!0;try{p=await e()!==!1}catch{p=!0}if(p){if(!u.stuckFired&&a()-u.since>=s){u.stuckFired=!0;try{await n?.({to:u.to,from:u.from,since:u.since})}catch{}}return}let h=u;f();let w=await t({to:h.to,from:h.from,kind:h.kind,reason:"auto"});l.log?.(`[self-update] stasis reached \u2192 ${w.ok?"started":`not started: ${w.reason}`}`);try{await r?.({...h,result:w})}catch{}};return{arm({to:p,from:h=zu,kind:w=Lo()}){return u?.to===p?!1:(f(),u={to:p,from:h,kind:w,since:a(),stuckFired:!1,timer:i(d,o)},u.timer.unref?.(),!0)},tick:d,cancel:f,get armed(){return u?{to:u.to,from:u.from,kind:u.kind,since:u.since}:null}}}me();it();var cF=(...e)=>fetch(...e);function lF(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}async function hw(e=process.env){if(!lF(e))throw new Error("no plane configured \u2014 circuits live on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let t=new AbortController,n=setTimeout(()=>t.abort(),1e4);try{let r=await cF(`${Ie(e)}/v1/circuits`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN}`},signal:t.signal}),o=await r.json().catch(()=>({}));if(!r.ok)throw new Error(o?.error||`plane answered ${r.status}`);return Array.isArray(o.circuits)?o.circuits:[]}finally{clearTimeout(n)}}async function oa(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await hw(t),o=r.find(c=>c.id===n);if(o)return o;let s=n.toLowerCase(),a=r.filter(c=>c.name.toLowerCase()===s);if(a.length===1)return a[0];if(a.length>1)throw new Error(`"${n}" names ${a.length} circuits \u2014 use an id (bostrat-circuit ls)`);let i=r.filter(c=>c.name.toLowerCase().includes(s)).slice(0,5);throw new Error(i.length?`no circuit named "${n}" \u2014 near matches: ${i.map(c=>`${c.name} (${c.id})`).join(", ")}`:`no circuit named "${n}" \u2014 create it on the Circuits page first (bostrat-circuit ls lists yours)`)}async function Zu(e,t,{source:n="chat"}={}){return $(e,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:t?{circuitId:t.id,circuitName:t.name??null,source:n}:{circuitId:null,source:n}})}me();it();var uF=(...e)=>fetch(...e);async function Qu(e,t,n,r=process.env){if(!(Ie(r)&&r.BOSTRAT_PLANE_TOKEN))throw new Error("no plane configured \u2014 blueprints live on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let o=new AbortController,s=setTimeout(()=>o.abort(),15e3);try{let a=await uF(`${Ie(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}function dF(e,t=process.env){return Qu("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function LE({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await dF(t,o):await oa(e,o),a=await Qu("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function ww(e,t=process.env){let n=await oa(e,t),r=await Qu("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function gw(e,t=process.env){return(await Qu("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function FE(e,t,n,r=process.env){let{blueprint:o,items:s}=await ww(t,r),a=new Map(s.map(c=>[c.itemId,c])),i=n.filter(c=>!a.get(c)?.bindable);if(i.length){let c=s.filter(l=>l.bindable).map(l=>l.itemId);throw new Error(`unknown/unbindable item(s): ${i.join(", ")} \u2014 bindable ids: ${c.join(", ")||"(none)"}`)}return await $(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}me();it();var fF=(...e)=>fetch(...e);async function pF(e,t,n,r=process.env){if(!(Ie(r)&&r.BOSTRAT_PLANE_TOKEN))throw new Error("no plane configured \u2014 the decision ledger lives on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let o=new AbortController,s=setTimeout(()=>o.abort(),15e3);try{let a=await fF(`${Ie(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}var UE=72,yw=160;async function HE(e,{title:t,context:n="",decision:r,summary:o,alternatives:s=[],supersedesId:a=null}){let i=String(t??"").trim(),c=String(o??"").trim();if(!i)throw new Error("a title is required");if(i.length>UE)throw new Error(`the title is the choice as a LABEL \u2014 ${UE} chars max (yours is ${i.length}); the full story goes in the decision text`);if(!c)throw new Error(`a summary is required \u2014 one sentence (max ${yw} chars) a reader can act on without opening the record`);if(c.length>yw)throw new Error(`the summary is one sentence \u2014 ${yw} chars max (yours is ${c.length}); the full story goes in the decision text`);if(!String(r??"").trim())throw new Error("the decision itself is required (what was decided)");return await $(e,{type:"decision.recorded",actor:"orchestrator",source:"orchestrator",payload:{title:i,context:String(n??"").trim(),decision:String(r).trim(),summary:c,alternatives:(Array.isArray(s)?s:[]).map(l=>typeof l=="string"?{label:l}:l).filter(l=>l?.label),...a?{supersedesId:a}:{}}}),{title:i}}function WE(e,t=process.env){return pF("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}ih();me();import hc from"node:fs/promises";import cd from"node:path";import rU from"node:os";cr();import mF from"node:fs/promises";import qE from"node:path";import hF from"node:os";var KE=()=>qE.join(process.env.BOSTRAT_STATE_DIR||qE.join(process.env.HOME||hF.tmpdir(),".bostrat"),"integrations.json");async function nr(){try{return JSON.parse(await mF.readFile(KE(),"utf8"))||{}}catch{return{}}}var ed=["linked","prOpened","prMerged","create"],bw=["prompt","auto","off"],wF={create:["prompt","off"]},GE=e=>wF[e]??bw;function td(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of ed){let s=GE(o),a=s.includes(n)?n:"prompt",i=e.ticketFlow?.[o]??t.ticketFlow?.[o];r[o]=s.includes(i)?i:a}return r}async function Fo(){let e=await nr(),t=process.env.BOSTRAT_LINEAR_API_KEY||e.linear?.apiKey,n=process.env.BOSTRAT_LINEAR_DEFAULT_TEAM||e.linear?.defaultTeam||null;return t?{apiKey:t,ticketFlow:td(e),defaultTeam:n}:null}async function nd(){let e=await nr(),t=e.jira||{},n=process.env.BOSTRAT_JIRA_BASE_URL||t.baseUrl,r=process.env.BOSTRAT_JIRA_EMAIL||t.email,o=process.env.BOSTRAT_JIRA_API_TOKEN||t.apiToken;return!n||!r||!o?null:{baseUrl:String(n).replace(/\/$/,""),email:r,apiToken:o,tokenExpiresAt:t.tokenExpiresAt??null,ticketFlow:td(e)}}async function kw(){return td(await nr())}async function VE(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${ed.join(", ")}`);for(let[r,o]of t){if(!ed.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${ed.join(", ")}`);let s=GE(r);if(!s.includes(o))throw new Error(s.length<bw.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${bw.join(", ")}`)}let n=await nr();return n.ticketFlow={...td(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Tt(KE(),n,{mode:384}),n.ticketFlow}async function uc(){let e=(await nr()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function gF(){let e=(await nr()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var yF={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function rd(){let t=(await nr()).voiceChat||{},n=t.provider||"openai",r=yF[n];if(!r)return null;let o=n==="openai"?await gF():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function zE(){let e=(await nr()).cedar||{},t=process.env.BOSTRAT_CEDAR_INGEST_KEY||e.ingestKey,n=process.env.BOSTRAT_CEDAR_URL||e.url||"https://cedar-api.fly.dev";return t?{url:n,ingestKey:t}:null}async function Uo(){let e=(await nr()).slack||{},t=process.env.BOSTRAT_SLACK_BOT_TOKEN||e.botToken,n=process.env.BOSTRAT_SLACK_APP_TOKEN||e.appToken;return!t||!n?null:{botToken:t,appToken:n,channel:process.env.BOSTRAT_SLACK_CHANNEL||e.channel||null,maxConcurrent:Number.isInteger(e.maxConcurrent)&&e.maxConcurrent>0?e.maxConcurrent:2}}me();ur();vr();Ks();import fc from"node:fs/promises";import rA from"node:path";import WF from"node:os";import{randomUUID as oA}from"node:crypto";var vw={};Pd(vw,{createComment:()=>_F,findIssueUrl:()=>vF,issueStates:()=>RF,mdToAdf:()=>XE,moveIssue:()=>OF,parseIssueRef:()=>xF,resolveIssue:()=>SF,uploadImage:()=>IF,upsertCard:()=>TF,whoami:()=>xw});var sa=e=>String(e.baseUrl||"").replace(/\/$/,""),JE=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function Ho(e,t,n,r){let o=await fetch(`${sa(e)}${n}`,{method:t,headers:{authorization:JE(e),accept:"application/json",...r!==void 0?{"content-type":"application/json"}:{}},body:r!==void 0?JSON.stringify(r):void 0}),s=await o.text(),a=null;try{a=s?JSON.parse(s):null}catch{a=null}if(!o.ok){let i=a?.errorMessages?.[0]??Object.values(a?.errors??{})[0]??`HTTP ${o.status}`,c=new Error(`jira: ${i}`);throw c.status=o.status,c}return a}var bF=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,kF=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function xF(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(bF);return r?r[1].toUpperCase():null}let n=t.match(kF);return n?n[1]:null}function vF(e,t=null){let n=null;try{n=t?.baseUrl?new URL(t.baseUrl).host:null}catch{n=null}let r=/https?:\/\/[^\s)]+\/browse\/[A-Za-z][A-Za-z0-9]{0,9}-\d+[^\s)]*/g;for(let o of String(e||"").matchAll(r))try{let s=new URL(o[0]).host;if(s===n||/\.atlassian\.net$/i.test(s))return o[0]}catch{}return null}async function SF(e,t){let n;try{n=await Ho(e,"GET",`/rest/api/3/issue/${encodeURIComponent(t)}?fields=summary,status`)}catch(r){throw r.status===404?new Error(`jira: issue "${t}" not found`):r}return{issueId:n.id,key:n.key,title:n.fields?.summary??null,url:`${sa(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function TF(e,t,{url:n,title:r,subtitle:o}){await Ho(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/remotelink`,{globalId:n,application:{type:"com.bostrat.tracks",name:"Bostrat"},object:{url:n,title:r,summary:o,icon:{title:"Bostrat"}}})}var EF=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function AF(e){let t=[],n=0;for(let r of e.matchAll(EF)){r.index>n&&t.push({type:"text",text:e.slice(n,r.index)});let o=r[0];if(o.startsWith("![")){let[,s,a]=o.match(/^!\[([^\]]*)\]\(([^)\s]+)\)$/);t.push({type:"text",text:s||a,marks:[{type:"link",attrs:{href:a}}]})}else o.startsWith("**")?t.push({type:"text",text:o.slice(2,-2),marks:[{type:"strong"}]}):o.startsWith("`")?t.push({type:"text",text:o.slice(1,-1),marks:[{type:"code"}]}):o.startsWith("_")?t.push({type:"text",text:o.slice(1,-1),marks:[{type:"em"}]}):t.push({type:"text",text:o,marks:[{type:"link",attrs:{href:o}}]});n=r.index+o.length}return n<e.length&&t.push({type:"text",text:e.slice(n)}),t}function XE(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
659
+ `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...AF(o))}),{type:"paragraph",content:r.length?r:[{type:"text",text:" "}]}});return{type:"doc",version:1,content:t.length?t:[{type:"paragraph",content:[{type:"text",text:" "}]}]}}async function _F(e,t,n){let r=await Ho(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:XE(n)});return r?.id?`${sa(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function xw(e){let t=await Ho(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(sa(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function IF(e,{issue:t,filename:n,contentType:r,buffer:o}){let s=new FormData;s.append("file",new Blob([o],{type:r}),n);let a=await fetch(`${sa(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:JE(e),"x-atlassian-token":"no-check",accept:"application/json"},body:s}),i=await a.json().catch(()=>null),c=Array.isArray(i)?i[0]:null;if(!a.ok||!c)throw new Error(`jira: attachment upload failed (HTTP ${a.status})`);return c.content??`${sa(e)}/rest/api/3/attachment/content/${c.id}`}var $F={new:"unstarted",indeterminate:"started",done:"completed"},YE=e=>$F[e?.key]??"started";async function RF(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([Ho(e,"GET",`/rest/api/3/issue/${n}?fields=status`),Ho(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:YE(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:YE(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function OF(e,t,n){await Ho(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var Aw={};Pd(Aw,{createComment:()=>LF,createIssue:()=>Ew,createProject:()=>Tw,findIssueUrl:()=>DF,issueStates:()=>UF,moveIssue:()=>HF,parseIssueRef:()=>PF,resolveIssue:()=>BF,teams:()=>aa,uploadImage:()=>FF,upsertCard:()=>jF,whoami:()=>Sw});var CF=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function _n(e,t,n={}){let r=await fetch(CF(),{method:"POST",headers:{"content-type":"application/json",authorization:e.apiKey},body:JSON.stringify({query:t,variables:n})}),o=await r.json().catch(()=>null);if(!r.ok)throw new Error(`linear: HTTP ${r.status}${o?.errors?.[0]?.message?` \u2014 ${o.errors[0].message}`:""}`);if(o?.errors?.length){let s=o.errors[0],a=(s.extensions?.validationErrors??[]).flatMap(i=>Object.values(i?.constraints??{})).join("; ");throw new Error(`linear: ${s.message}${a?` \u2014 ${a}`:""}`)}return o?.data??{}}var MF=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,NF=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function PF(e){let t=String(e||"").trim(),n=t.match(MF);if(n)return n[1].toUpperCase();let r=t.match(NF);return r?r[1]:null}function DF(e){let t=String(e||"").match(/https?:\/\/linear\.app\/[^/\s]+\/issue\/[A-Za-z][A-Za-z0-9]{0,9}-\d+[^\s)]*/);return t?t[0]:null}async function BF(e,t){let r=(await _n(e,"query($id: String!) { issue(id: $id) { id identifier title url state { name } team { key } } }",{id:t})).issue;if(!r)throw new Error(`linear: issue "${t}" not found`);return{issueId:r.id,key:r.identifier,title:r.title,url:r.url,state:r.state?.name??null,team:r.team?.key??null}}async function jF(e,t,{url:n,title:r,subtitle:o}){let s=await _n(e,"mutation($input: AttachmentCreateInput!) { attachmentCreate(input: $input) { success attachment { id } } }",{input:{issueId:t.issueId,url:n,title:r,subtitle:o}});if(!s.attachmentCreate?.success)throw new Error("linear: attachmentCreate did not succeed");return s.attachmentCreate.attachment?.id??null}async function LF(e,t,n){let r=await _n(e,"mutation($input: CommentCreateInput!) { commentCreate(input: $input) { success comment { url } } }",{input:{issueId:t.issueId,body:n}});if(!r.commentCreate?.success)throw new Error("linear: commentCreate did not succeed");return r.commentCreate.comment?.url??null}async function Sw(e){let t=await _n(e,"query { viewer { name email } organization { name urlKey } }");return{user:t.viewer?.name??t.viewer?.email??null,org:t.organization?.name??t.organization?.urlKey??null}}async function FF(e,{filename:t,contentType:n,buffer:r}){let o=await _n(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
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 UF(e,t){let n=await _n(e,"query($id: String!) { issue(id: $id) { state { id name type } team { states { nodes { id name type position } } } } }",{id:t.key});if(!n.issue)throw new Error(`linear: issue "${t.key}" not found`);return{current:n.issue.state??null,states:n.issue.team?.states?.nodes??[]}}async function HF(e,t,n){if(!(await _n(e,"mutation($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }",{id:t.issueId,input:{stateId:n}})).issueUpdate?.success)throw new Error("linear: issueUpdate did not succeed")}async function aa(e){return((await _n(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var ZE=255;async function Tw(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>ZE,a=s?`${o.slice(0,ZE-1).trimEnd()}\u2026`:o,i=await _n(e,"mutation($input: ProjectCreateInput!) { projectCreate(input: $input) { success project { id url name } } }",{input:{teamIds:[t],name:n,...a?{description:a}:{},...s?{content:o}:{}}}),c=i.projectCreate?.project;if(!i.projectCreate?.success||!c)throw new Error("linear: projectCreate did not succeed");return{id:c.id,url:c.url,name:c.name}}async function Ew(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await _n(e,"mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier url title } } }",{input:{teamId:t,title:n,...r?{description:r}:{},...o?{projectId:o}:{},...Number.isInteger(s)?{priority:s}:{}}}),i=a.issueCreate?.issue;if(!a.issueCreate?.success||!i)throw new Error("linear: issueCreate did not succeed");return{id:i.id,key:i.identifier,url:i.url,title:i.title}}var sA={linear:{api:Aw,config:Fo},jira:{api:vw,config:nd}};async function Mw(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(sA)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function Wo(e){let t=sA[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function Nw(e,t){if(!e||e.name)return e;let n=t.find(r=>r.id===e.id);return n?{...e,name:n.name}:e}var aA=()=>process.env.BOSTRAT_STATE_DIR||rA.join(process.env.HOME||WF.tmpdir(),".bostrat"),Rw=()=>rA.join(aA(),"tickets.json"),iA=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),od=e=>`${iA()}/track/${e}`,Wr=null,_w=null,Iw=Promise.resolve();async function mc(){return Wr||(_w??=fc.readFile(Rw(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{if(Wr=e,!t&&Ne()){let{records:n,source:r}=await et("tickets").catch(()=>({records:[],source:"error"}));if(r==="plane"){for(let o of n){if(o.deletedAt||!o.data?.id)continue;let{id:s,updatedAt:a,...i}=o.data;Wr[s]=i}Object.keys(Wr).length&&await Ow().catch(()=>{})}}return Wr}).finally(()=>_w=null),_w)}async function Ow(){let e=JSON.stringify({tickets:Wr},null,2),t=`${Rw()}.${process.pid}.tmp`;await fc.mkdir(aA(),{recursive:!0}),await fc.writeFile(t,e),await fc.rename(t,Rw())}async function qr(e=null){if(Iw=Iw.then(Ow,Ow),await Iw.catch(()=>{}),!e)return;let t=Wr?.[e];t?wt("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):Vt("tickets",e).catch(()=>{})}async function In(e){return(await mc())[e]??null}async function cA(){return{...await mc()}}async function lA(){return(await Mw()).length>0}async function ia(e,t,{source:n="api"}={}){let r=await Mw();if(!r.length)throw new Error("no ticketing integration configured \u2014 add a linear or jira entry to ~/.bostrat/integrations.json");let o=null,s=null,a=null;for(let u of r){let f=u.api.parseIssueRef(t);if(f)try{s=await u.api.resolveIssue(u.cfg,f),o=u;break}catch(d){a=d}}if(!o)throw a||new Error(`"${t}" is not a Linear or Jira issue URL or key (ABC-123)`);let i=(e.boxes||[]).find(u=>u.name===e.leadBox),c={provider:o.name,key:s.key,issueId:s.issueId,url:s.url,title:s.title,state:s.state,source:n,linkedAt:Date.now(),track:{name:e.name,branch:e.workspace?.branch??null,leadAgent:i?.agent??null,cwd:e.cwd??null,...e.workspace?.kind==="multi"?{repos:(e.workspace.repos??[]).map(u=>u?.name).filter(Boolean)}:{}},pr:null};(await mc())[e.id]=c,await qr(e.id),await $({id:e.id,cwd:e.cwd},{type:"ticket.linked",actor:"user",source:"orchestrator",payload:{ts:Date.now(),provider:c.provider,key:c.key,url:c.url,title:c.title,linkSource:n}}).catch(()=>{}),await pc(e.id,c);let l=[];return c.track.branch&&l.push(`\`${c.track.branch}\``),c.track.repos?.length&&l.push(`repos ${c.track.repos.join(" + ")}`),c.track.leadAgent&&l.push(`lead ${c.track.leadAgent}`),await dc(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await fA(e.id,c,"linked"),c}async function Pw(e){let t=await mc();return t[e]?(delete t[e],await qr(e),!0):!1}var Cw=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function uA(e,t){if(!e.track?.cwd)return null;let n=xr(await F({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function qF(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${Cw(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${Cw(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function KF(e,t){let n=[];return e.track.leadAgent&&n.push(`lead ${e.track.leadAgent}`),e.track.branch&&n.push(e.track.branch),e.track.repos?.length&&n.push(e.track.repos.join(" + ")),e.pr?.number&&n.push(`PR #${e.pr.number} ${e.pr.change==="merged"?"merged":"open"}`),t&&n.push(Cw(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function pc(e,t){let n=await Wo(t);if(!n)return;let r=await uA(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:od(e),title:`Bostrat Track: ${t.track.name}`,subtitle:KF(t,r)})}function sd(e){let t=new URL(iA());return`${t.protocol}//${e}.${t.host}/`}var GF={linked:"linked",opened:"prOpened",merged:"prMerged"};function VF(e,t,n){let r=o=>t.filter(s=>s.type===o).sort((s,a)=>s.position-a.position);if(n==="linked"){if(["triage","backlog","unstarted"].includes(e?.type))return r("started")[0]??null}else if(n==="opened"){if(e?.type!=="completed")return r("started").find(o=>/review/i.test(o.name))??null}else if(n==="merged"&&e?.type!=="completed")return r("completed")[0]??null;return null}async function dA(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await qr(e),await $({id:e,cwd:t.track?.cwd},{type:"ticket.state.changed",actor:a,source:"orchestrator",payload:{ts:Date.now(),key:t.key,url:t.url,from:n??null,to:r,mode:o,...s?{phase:s}:{}}}).catch(()=>{})}async function fA(e,t,n){let r=await Wo(t);if(!r)return;let o=r.cfg.ticketFlow?.[GF[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Nw(s,a),c=VF(i,a,n);if(!c||c.id===i?.id)return;let l=i?.name??t.state??null;if(o==="auto"){await r.api.moveIssue(r.cfg,t,c.id),await dA(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await $({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:oA(),provider:t.provider,key:t.key,url:t.url,phase:n,from:l,to:{id:c.id,name:c.name,type:c.type},...t.pr?.number?{prNumber:t.pr.number}:{}}}).catch(()=>{})}async function pA(e){let t=await In(e);if(!t)throw new Error("no ticket linked to this Track");let n=await Wo(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=Nw(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await qr(e)),{key:t.key,url:t.url,current:s?{id:s.id,name:s.name??null,type:s.type??null}:null,states:[...o].sort((a,i)=>a.position-i.position).map(({id:a,name:i,type:c,position:l})=>({id:a,name:i,type:c,position:l}))}}async function Dw(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await In(e);if(!r)throw new Error("no ticket linked to this Track");let o=await Wo(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Nw(s,a),c=a.find(u=>u.id===t);if(!c)throw new Error("unknown state for this ticket's team");let l=i?.name??r.state??null;return i?.id===c.id?(r.state!==c.name&&(r.state=c.name,await qr(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await dA(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function mA(e,t){let n=await In(e);if(!n)throw new Error("no ticket linked to this Track");let r=await Wo(n);if(!r)throw new Error("no ticketing integration configured");let o=String(t||"").trim();if(!o)throw new Error("comment body required");let s=await r.api.createComment(r.cfg,n,o);return await $({id:e,cwd:n.track?.cwd},{type:"ticket.commented",actor:"user",source:"orchestrator",payload:{ts:Date.now(),key:n.key,url:s??n.url,excerpt:o.length>280?`${o.slice(0,279)}\u2026`:o}}).catch(()=>{}),{key:n.key,url:s??n.url}}async function hA(e,t,n){if(!t)throw new Error("offerId required");let r=await F({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type==="ticket.move.offered"&&a.payload?.offerId===t);if(!o)throw new Error("unknown offer");if(r.some(a=>a.type==="ticket.move.answered"&&a.payload?.offerId===t))throw new Error("offer already answered");let s=null;return n&&(s=await Dw(e.id,o.payload.to?.id,{mode:"offer"})),await $({id:e.id,cwd:e.cwd},{type:"ticket.move.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,action:n?"moved":"dismiss",...s?{from:s.from,to:s.to}:{}}}),{offerId:t,action:n?"moved":"dismiss",...s??{}}}var QE=50;async function wA(){let e=await Fo();if(!e)throw new Error("no ticketing integration configured");return aa(e)}function zF(e){let t=e&&typeof e=="object"?e:{},n=(Array.isArray(t.issues)?t.issues:[]).map(o=>o&&typeof o=="object"?o:{title:String(o||"")}).map(o=>({title:String(o.title||"").trim(),description:o.description?String(o.description):null,priority:Number.isInteger(o.priority)&&o.priority>=0&&o.priority<=4?o.priority:null})).filter(o=>o.title),r=t.epic&&String(t.epic.name||"").trim()?{name:String(t.epic.name).trim(),description:t.epic.description?String(t.epic.description):null}:null;if(!n.length&&!r)throw new Error("a plan needs an epic or at least one issue");if(n.length>QE)throw new Error(`too many issues (${n.length}); cap is ${QE} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function YF(e,t,n,r){let o=r??await aa(e),s=i=>o.find(c=>c.id===i||c.key.toLowerCase()===String(i).toLowerCase()||c.name.toLowerCase()===String(i).toLowerCase())??null;if(t.team){let i=s(t.team);if(i)return i}let a=await In(n.id);if(a?.key){let i=a.key.split("-")[0],c=o.find(l=>l.key===i);if(c)return c}if(e.defaultTeam){let i=s(e.defaultTeam);if(i)return i}return o.length===1?o[0]:null}async function gA(e,t){let n=await Fo();if(!n)throw new Error("no ticketing integration configured \u2014 add a linear apiKey to ~/.bostrat/integrations.json");if(n.ticketFlow?.create==="off")throw new Error("ticket creation offers are off (bostrat-ticket flow set create=prompt to re-enable)");let r=zF(t),o=await aa(n),s=await YF(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=oA();return await $({id:e.id,cwd:e.cwd},{type:"ticket.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:i,provider:"linear",epic:r.epic,issues:r.issues,team:a,needsTeam:!s,linkCurrentTrack:r.linkCurrentTrack}}),{proposalId:i,epic:r.epic,issues:r.issues,team:a,needsTeam:!s}}async function yA(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await F({id:e.id,cwd:e.cwd}),s=o.find(h=>h.type==="ticket.create.offered"&&h.payload?.proposalId===t);if(!s)throw new Error("unknown proposal");if(o.some(h=>h.type==="ticket.create.answered"&&h.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await $({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};let a=await Fo();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let h=(await aa(a)).find(w=>w.id===r);if(!h)throw new Error("unknown team");c={id:h.id,key:h.key,name:h.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],f=null;if(i.epic){let h=await Tw(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});f=h.id,l.push({kind:"epic",title:h.name,url:h.url})}for(let h of i.issues||[])try{let w=await Ew(a,{teamId:c.id,title:h.title,description:h.description,projectId:f,priority:h.priority});l.push({kind:"issue",key:w.key,title:w.title,url:w.url})}catch(w){u.push({title:h.title,message:w?.message||String(w)})}await $({id:e.id,cwd:e.cwd},{type:"ticket.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,team:{key:c.key,name:c.name},items:l,failed:u}}),await $({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",createdCount:l.length,failedCount:u.length}});let d=l.filter(h=>h.kind==="issue"),p=null;return i.linkCurrentTrack&&d.length===1&&!await In(e.id)&&(p=await ia(e,d[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:p?p.key:null}}async function dc(e,t){let n=await Wo(e);n&&await n.api.createComment(n.cfg,e,t)}async function JF(e,t,n){let r=await Wo(e);if(!r)return null;let o=await Yn(t);if(!o)return null;let s=tn(o,n);if(!s)return null;let a=await fc.readFile(Wt(o,s.v).png).catch(()=>null);return a?r.api.uploadImage(r.cfg,{issue:e.key,filename:`${o.name.replace(/[^\w.-]+/g,"-")}.v${s.v}.png`,contentType:"image/png",buffer:a}):null}var eA=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),$w=new Map;function XF(e,t){if(eA()<=0)return pc(e,t);if($w.has(e))return;let n=setTimeout(()=>{$w.delete(e),In(e).then(r=>r?pc(e,r):null).catch(()=>{})},eA());n.unref?.(),$w.set(e,n)}var tA=new Map;async function nA(e,t,n){let r=tA.get(e)??0;Date.now()-r<600*1e3||(tA.set(e,Date.now()),await $({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function ZF(e,{resolveTrack:t=null}={}){let n=await In(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Mw())if(o=a.api.findIssueUrl(r.text,a.cfg),o)break;if(!o)return;let s=t?await t(e.trackId):null;if(!s)return;try{await ia(s,o,{source:"chat"})}catch(a){await nA(e.trackId,s.cwd,a)}return}if(!n.track.cwd&&t){let o=await t(e.trackId).catch(()=>null);o?.cwd&&(n.track.cwd=o.cwd,await qr(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await qr(e.trackId),await pc(e.trackId,n);break;case"pr.state.changed":{if(!r.change)break;if(r.number&&(n.pr={number:r.number,url:r.url??n.pr?.url??null,change:r.change}),await qr(e.trackId),await pc(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await uA(n,e.trackId).catch(()=>null):null;await dc(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
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: ${qF(o)}.`:"")),await fA(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await JF(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await dc(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
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 dc(n,`**Bostrat** \u2014 design decision: **${r.name}** picked${o?` over ${o}`:""}.`)}break}case"view.state.changed":{if(r.change!=="created"||r.restarted||!r.slug)break;await dc(n,`**Bostrat** \u2014 live preview **${r.name}**: ${sd(r.slug)}
669
+ _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await XF(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await nA(e.trackId,s?.cwd??null,o)}}function bA({resolveTrack:e}){ct.on("event",t=>{ZF(t,{resolveTrack:e}).catch(()=>{})})}async function kA(){if(!Ne())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await et("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await mc(),r=0;for(let[o,s]of Object.entries(n))await wt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}bo();Ks();import QF from"ws";var xA=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function ad(e,t,n={}){let r=await fetch(`${xA()}/${e}`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json; charset=utf-8"},body:JSON.stringify(n)}),o=await r.json().catch(()=>null);if(!o?.ok)throw new Error(`slack ${e}: ${o?.error||`http ${r.status}`}`);return o}var Bw=(e,t)=>ad("chat.postMessage",e,t),qo=(e,t)=>ad("chat.update",e,t);async function bt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function eU(e,t,n={}){let r=await fetch(`${xA()}/${e}`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/x-www-form-urlencoded; charset=utf-8"},body:new URLSearchParams(n).toString()}),o=await r.json().catch(()=>null);if(!o?.ok)throw new Error(`slack ${e}: ${o?.error||`http ${r.status}`}`);return o}async function vA(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await eU("files.getUploadURLExternal",e,{filename:t,length:String(n.length)}),l=await fetch(i,{method:"POST",body:n});if(!l.ok)throw new Error(`slack upload: http ${l.status}`);return ad("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var tU=2200;function SA({getToken:e,onEnvelope:t,log:n=()=>{}}){let r=!1,o=null,s=null,a=1e3;async function i(){if(r)return;let l;try{let u=await e();if(!u)throw new Error("app token missing");({url:l}=await ad("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new QF(l),o.on("message",u=>{let f;try{f=JSON.parse(u)}catch{return}if(f.type==="hello"){a=1e3,n("socket connected");return}if(f.type==="disconnect"){try{o.close()}catch{}return}if(!f.envelope_id)return;let d=w=>{try{o.send(JSON.stringify(w?{envelope_id:f.envelope_id,payload:w}:{envelope_id:f.envelope_id}))}catch{}},p=!1,h=setTimeout(()=>{p=!0,d()},tU);Promise.resolve().then(()=>t(f)).then(w=>{clearTimeout(h),!p&&(p=!0,d(f.accepts_response_payload?w:void 0))},w=>{clearTimeout(h),p||(p=!0,d()),n(`envelope handler failed: ${w?.message||w}`)})}),o.on("close",c),o.on("error",u=>{n(`socket error: ${u?.message||u}`);try{o.close()}catch{}})}function c(){if(r||s)return;let l=a;a=Math.min(a*2,6e4),s=setTimeout(()=>{s=null,i()},l)}return i(),()=>{r=!0,s&&clearTimeout(s);try{o?.close()}catch{}}}var AA=()=>process.env.BOSTRAT_STATE_DIR||cd.join(process.env.HOME||rU.tmpdir(),".bostrat"),Hw=()=>cd.join(AA(),"slack.json"),id=null,jw=null,Lw=Promise.resolve();async function qw(){return id||(jw??=hc.readFile(Hw(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>id=e).finally(()=>jw=null),jw)}async function TA(){let e=JSON.stringify({threads:id},null,2),t=`${Hw()}.${process.pid}.tmp`;await hc.mkdir(AA(),{recursive:!0}),await hc.writeFile(t,e),await hc.rename(t,Hw())}async function sn(){Lw=Lw.then(TA,TA),await Lw.catch(()=>{})}async function Kw(e){return(await qw())[e]??null}async function oU(e,t){let n=await qw();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var ke=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function wc(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function sU(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return wc(n.replace(/\n+/g," "),t)}function _A(e){let t=`*${ke(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${ke(e.repoLabel)} \xB7 \`${ke(e.branch||"?")}\` \xB7 lead *${ke(e.lead)}*`,r=e.kickoff?`> ${ke(wc(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
670
+ ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${od(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function Ww(e,t){await qo(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:_A(t)})}async function Gr(e,t,n,r=void 0){return Bw(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var EA=new Set;function Kr(e){EA.add(e),e.catch(()=>{}).finally(()=>EA.delete(e))}var Me=e=>({response_type:"ephemeral",text:e}),aU="*/bostrat* \u2014 `start <name> [repo]` \xB7 `archive <track>` \xB7 `handoff <track> <agent>` \xB7 `stop <track>` \xB7 `list`\n_Reply in a Track's thread to steer its lead; question prompts and ship offers appear there as buttons._",iU=["claude","cursor","codex"];function Fw(e,t){let n=(t||"").toLowerCase(),r=e.filter(s=>!s.archivedAt),o=r.filter(s=>s.name.toLowerCase().startsWith(n));return o.sort((s,a)=>(a.lastResponseAt??a.createdAt??0)-(s.lastResponseAt??s.createdAt??0)),{match:o[0]??null,live:r}}var Uw=(e,t)=>Me(`No live Track matches \u201C${ke(t)}\u201D. Live: ${e.map(n=>`\`${ke(n.name)}\``).join(" \xB7 ")||"none"}`);async function IA(e,t,{name:n,repo:r,responseUrl:o}){let s=e.deps;try{let a=(await s.listTracks()).filter(f=>!f.archivedAt);if(a.length>=t.maxConcurrent){await bt(o,{...Me(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await bt(o,{...Me("No designated channel configured \u2014 set `slack.channel` in integrations.json."),replace_original:!0});return}let i=await s.createTrack({name:n,...r?{repo:r}:{}}),c=i.workspace||{},l={trackId:i.id,channel:t.channel,name:i.name,branch:c.branch||null,repoLabel:c.repo||(c.base?cd.basename(c.base):"fresh workspace"),lead:"claude"},u=await Bw(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:_A(l),unfurl_links:!1});l.ts=u.ts,(await qw())[i.id]=l,await sn(),await bt(o,{...Me(`\u2713 *${ke(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await bt(o,{...Me(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function cU(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await Kw(n.id);s&&(s.archivedAt=Date.now(),await sn(),await Ww(t,s).catch(()=>{})),await bt(r,{...Me(`\u2713 *${ke(n.name)}* archived.`),replace_original:!0})}catch(s){await bt(r,{...Me(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function lU(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await bt(o,{...Me(`\u2713 Handing *${ke(n.name)}* to ${ke(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await bt(o,{...Me(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function uU(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.interruptLead(n.id);let s=(o.listSubtaskJobs?.(n.id)??[]).filter(a=>!a.finishedAt);for(let a of s)try{o.cancelSubtask(a.id)}catch{}await bt(r,{...Me(`\u2713 Stopped *${ke(n.name)}*${s.length?` (+ ${s.length} subtask${s.length>1?"s":""} canceled)`:""} \u2014 Track parked, resume from the Track page.`),replace_original:!0})}catch(s){await bt(r,{...Me(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function dU(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:wc(`${r.name} (${r.branch})`,75)},value:r.path})),{text:{type:"plain_text",text:"fresh workspace"},value:"__fresh__"}];return[{type:"section",block_id:JSON.stringify({name:e}),text:{type:"mrkdwn",text:`Repo for *${ke(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function fU(e){let t=await e.listTracks(),n=t.filter(s=>!s.archivedAt);if(n.sort((s,a)=>(a.lastResponseAt??a.createdAt??0)-(s.lastResponseAt??s.createdAt??0)),!n.length)return"No live Tracks.";let r=n.map(s=>{let a=s.workspace||{},i=a.repo||(a.base?cd.basename(a.base):"fresh"),c=[...s.boxes||[]].reverse().find(u=>u.role==="lead")?.agent||"?",l=s.prompted?"\u26A0 needs an answer":s.working?"working":"idle";return`\u2022 *${ke(s.name)}* \u2014 ${ke(i)}${a.branch?` \`${ke(a.branch)}\``:""} \xB7 lead ${ke(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
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 pU(e,t){let n=await Uo();if(!n)return Me("Slack integration not configured.");let r=e.deps,o=(t.text||"").trim().split(/\s+/).filter(Boolean),s=(o[0]||"help").toLowerCase(),a=o.slice(1);switch(s){case"start":{if(!a.length)return Me("Usage: `/bostrat start <name> [repo]`");let i=await r.listRepos(),c=a[a.length-1]?.toLowerCase(),l=a.length>1?i.find(f=>f.name.toLowerCase()===c):null,u=(l?a.slice(0,-1):a).join(" ");return l?(Kr(IA(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),Me(`Starting *${ke(u)}* on ${ke(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:dU(u,i)}}case"archive":{if(!a.length)return Me("Usage: `/bostrat archive <track>`");let{match:i,live:c}=Fw(await r.listTracks(),a.join(" "));return i?(Kr(cU(e,n,{track:i,responseUrl:t.response_url})),Me(`Archiving *${ke(i.name)}*\u2026`)):Uw(c,a.join(" "))}case"handoff":{let i=r.knownAgents??iU,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return Me(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:f}=Fw(await r.listTracks(),l);return u?(Kr(lU(e,n,{track:u,agent:c,responseUrl:t.response_url})),Me(`Handing *${ke(u.name)}* to ${ke(c)}\u2026`)):Uw(f,l)}case"stop":{if(!a.length)return Me("Usage: `/bostrat stop <track>`");let{match:i,live:c}=Fw(await r.listTracks(),a.join(" "));return i?(Kr(uU(e,n,{track:i,responseUrl:t.response_url})),Me(`Stopping *${ke(i.name)}*\u2026`)):Uw(c,a.join(" "))}case"list":return Me(await fU(r));default:return Me(aU)}}async function mU(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await Kw(o);try{if(await e.deps.answerPrompt(o,{promptId:s,answers:[a]}),i?.prompt?.promptId===s){let{ts:c,question:l}=i.prompt;delete i.prompt,await sn(),await qo(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ke(l||"question")}~
673
+ \u2713 *${ke(a)}*`}}]}).catch(()=>{})}}catch(c){await bt(n.response_url,Me(`Couldn't answer: ${c?.message||c}`))}}async function hU(e,t,n,r){let{trackId:o,offerId:s,action:a}=r,i=e.deps;try{let c=await i.resolveTrack(o);if(!c)throw new Error("track not found");let l=await i.readEvents(c),u=l.find(d=>d.type==="pr.offered"&&d.payload?.offerId===s);if(!u)throw new Error("unknown offer");if(l.some(d=>d.type==="pr.offer.answered"&&d.payload?.offerId===s))throw new Error("offer already answered");let f=Array.isArray(r.actions)?Ar.filter(d=>r.actions.includes(d)):a==="pr"?["commit","push","pr"]:a==="push"?["commit","push"]:null;if(f?.includes("pr")&&i.divertShip&&await i.divertShip(c,u,{actions:f}))return;f&&await i.sayToLead(c.id,Os(f,{branch:u.payload.branch,base:u.payload.base}),{kind:f.includes("pr")?"pr-go":"push-go"}),await i.appendEvent({id:c.id,cwd:c.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:u.boxId,payload:{ts:Date.now(),offerId:s,action:f?a:"dismiss",actions:f}})}catch(c){await bt(n.response_url,Me(`Couldn't act on the offer: ${c?.message||c}`))}}async function wU(e,t,n,r){let{trackId:o,offerId:s,choice:a}=r;try{let i=await e.deps.resolveTrack(o);if(!i)throw new Error("track not found");await e.deps.answerPrExists(i,{offerId:s,choice:a})}catch(i){await bt(n.response_url,Me(`Couldn't act on the offer: ${i?.message||i}`))}}async function gU(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await Uo();if(!r)return;if(n.action_id==="bostrat-start-repo"){let s;try{({name:s}=JSON.parse(n.block_id))}catch{return}let a=n.selected_option?.value;await bt(t.response_url,{...Me(`Starting *${ke(s)}*\u2026`),replace_original:!0}),Kr(IA(e,r,{name:s,repo:a==="__fresh__"?null:a,responseUrl:t.response_url}));return}let o;try{o=JSON.parse(n.value)}catch{return}n.action_id==="bostrat-prompt"?Kr(mU(e,r,t,o)):n.action_id==="bostrat-ship"?Kr(hU(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&Kr(wU(e,r,t,o))}async function yU(e,t){if(!t||t.type!=="message"||t.bot_id||t.subtype||!t.thread_ts||t.thread_ts===t.ts||!t.text?.trim())return;let n=await oU(t.channel,t.thread_ts);if(!n)return;let r=await Uo();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await Gr(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function bU(e){return async t=>{if(t.type==="slash_commands")return pU(e,t.payload);if(t.type==="interactive"){await gU(e,t.payload);return}if(t.type==="events_api"){await yU(e,t.payload?.event);return}}}var kU=new Set(["turn.user","turn.agent","prompt.raised","prompt.answered","pr.offered","pr.offer.answered","pr.exists.offered","pr.exists.answered","pr.state.changed","handoff.done","view.state.changed","mock.state.changed"]);function xU(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${ke(t.question||"The lead needs an answer")}`}}],r=(t.options||[]).slice(0,12);return r.length?n.push({type:"actions",elements:r.map(o=>({type:"button",action_id:"bostrat-prompt",text:{type:"plain_text",text:wc(String(o),75)},value:JSON.stringify({trackId:e,promptId:t.promptId,label:String(o)})}))}):n.push({type:"context",elements:[{type:"mrkdwn",text:"_reply in this thread to answer_"}]}),n}async function vU(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await qo(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ke(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await Gr(e,t,r.question||"The lead needs an answer",xU(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await sn()}async function SU(e,t,n){let r=n.payload||{};if(!t.prompt||r.promptId&&t.prompt.promptId!==r.promptId)return;let{ts:o,question:s}=t.prompt;delete t.prompt,await sn(),await qo(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${ke(s||"question")}~
674
+ \u2713 _answered_`}}]})}async function TU(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=(i,c,l,u)=>({type:"button",action_id:"bostrat-ship",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,action:i,...u?{actions:u}:{}}),...l?{style:l}:{}}),s;if(!Array.isArray(r.available))s=r.toPr?[o("push",`Commit & push${r.toPr.number?` to #${r.toPr.number}`:""}`,"primary"),o("dismiss","Not now")]:[o("pr","Open PR","primary"),o("push","Just push"),o("dismiss","Not now")];else{let i=r.available,c=Array.isArray(r.defaults)&&r.defaults.length?r.defaults:i,l={commit:"Commit",rebase:"rebase",push:"push",pr:r.prState==="open"?"open new PR":"open PR"},u=c.map(f=>l[f]).filter(Boolean).join(" & ");s=[o(c.includes("pr")?"pr":"push",u||"Ship","primary",c)],i.includes("pr")&&!c.includes("pr")&&s.push(o("pr","Open new PR",void 0,["pr"])),s.push(o("dismiss","Not now"))}let a=await Gr(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${ke(wc(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await sn()}async function EU(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await sn();let s=r.action==="dismiss"?"dismissed":r.action==="pr-exists"?`PR${r.existingPr?.number?` #${r.existingPr.number}`:""} already open \u2014 pick how to ship`:r.action==="pr"?"\u2713 opening a PR":"\u2713 pushing";await qo(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function AU(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=r.pr?.number?`#${r.pr.number}`:"a PR",s=(i,c,l)=>({type:"button",action_id:"bostrat-pr-exists",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,choice:i}),...l?{style:l}:{}}),a=await Gr(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${ke(r.branch)})`:""} is already open. Push the update to it, or open a new PR?`}},{type:"actions",elements:[s("push",`Push to ${o}`,"primary"),s("new","Open a new PR"),s("dismiss","Not now")]}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await sn()}async function _U(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await sn();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await qo(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function IU(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??$U)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await vA(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${ke(o.name)}*${a}${o.group?` (group \`${ke(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${ke(a.name)}*`).join(", ");await Gr(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${ke(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function $U(e,t){let n=await Yn(e);if(!n)return null;let r=tn(n,t);if(!r)return null;let o=await hc.readFile(Wt(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function RU(e,t){if(!kU.has(t.type))return;let n=await Kw(t.trackId);if(!n)return;let r=await Uo();if(!r)return;let o=t.payload||{};switch(t.type){case"turn.user":if(n.kickoff||t.actor!=="user"||!o.text)return;n.kickoff=o.text,await sn(),await Ww(r,n);return;case"turn.agent":{if(!o.text)return;let s=sU(o.text);if(!s)return;await Gr(r,n,s,[{type:"section",text:{type:"mrkdwn",text:ke(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${od(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return vU(r,n,t);case"prompt.answered":return SU(r,n,t);case"pr.offered":return TU(r,n,t);case"pr.offer.answered":return EU(r,n,t);case"pr.exists.offered":return AU(r,n,t);case"pr.exists.answered":return _U(r,n,t);case"pr.state.changed":{if(o.change!=="opened"&&o.change!=="merged")return;let s=o.change==="opened"?"PR opened":"PR merged";await Gr(r,n,`${s}${o.url?`: ${o.url}`:o.number?` (#${o.number})`:""}`);return}case"handoff.done":if(!o.toAgent||o.toAgent===n.lead)return;n.lead=o.toAgent,await sn(),await Ww(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await Gr(r,n,`Live preview ${o.name}: ${sd(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${ke(o.name)}*: ${sd(o.slug)}
675
+ _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return IU(r,n,t,e.deps)}}function $A(e){let t={deps:e};ct.on("event",s=>{RU(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await Uo()||(r&&clearInterval(r),r=null,n=SA({getToken:async()=>(await Uo())?.appToken,onEnvelope:bU(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}Xt();me();dn();um();Dn();import OU from"node:fs/promises";function CU(e){let t=new Map;for(let n of String(e||"").split(`
676
+ `)){let r=n.trim();if(!r||r[0]!=="{")continue;let o;try{o=JSON.parse(r)}catch{continue}let s=o?.message?.usage;if(!s)continue;let a={input:s.input_tokens||0,output:s.output_tokens||0,cacheWrite:s.cache_creation_input_tokens||0,cacheRead:s.cache_read_input_tokens||0};if(a.input+a.output+a.cacheWrite+a.cacheRead===0)continue;let i=o.message?.id||o.uuid||null;if(!i)continue;let c=s.cache_creation,l=c&&typeof c=="object"?{m5:c.ephemeral_5m_input_tokens||0,h1:c.ephemeral_1h_input_tokens||0}:null,u=typeof s.speed=="string"&&s.speed!=="standard"?s.speed:null;t.set(i,{messageId:i,tokens:a,cacheWriteTtl:l,speed:u,model:o.message?.model||o.model||null})}return[...t.values()]}function MU(e){let t=new Set;for(let n of e)if(n.type==="cost.recorded"){n.payload?.messageId&&t.add(n.payload.messageId);for(let r of n.payload?.messageIds||[])t.add(r)}return t}var NU=new Set(["Write","Edit","NotebookEdit"]),PU=220,DU=160;function BU(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(NU.has(n)&&typeof o.file_path=="string"&&o.file_path){let s=o.file_path,a=t?.cwd;a&&s.startsWith(`${a}/`)&&(s=s.slice(a.length+1)),r.path=s.slice(0,PU)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=no(o.command.trim().replace(/\s+/g," ")).slice(0,DU));return r}function jU(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?Jt(t.cwd,t.sessionId):t?.cwd?gf(t.cwd):null}async function RA(e,t){let n=await t(e?.session_id,e?.cwd);if(!n?.track)return[];let{track:r,box:o}=n,s={boxId:o?.name||null,provider:"claude",source:"hook"},a=[],i=async c=>{a.push(await $(r,{...s,...c}))};switch(e?.hook_event_name){case"SessionStart":await i({type:"session.ready",actor:"system",payload:{sessionId:e.session_id}});break;case"UserPromptSubmit":{let c=String(e.prompt??e.user_prompt??""),l=iu(c);await i({type:"turn.user",actor:l?"peer":"user",payload:{promptHead:(l?l.text:c).slice(0,160)||null,...l?{peer:{socket:l.socket,name:l.name,mode:l.mode}}:{}}});break}case"PostToolUse":await i({type:"tool.called",actor:"agent",payload:BU(e,o)});break;case"Stop":await LU(r,o,e,i);break;default:break}return a}async function LU(e,t,n,r){let o=[],s=jU(n,t);if(s)try{o=CU(await OU.readFile(s,"utf8"))}catch{}let a=o.length?o[o.length-1]:null;if(await r({type:"turn.agent",actor:"agent",payload:{model:a?.model??t?.model??null,messageId:a?.messageId??null}}),!o.length)return;let i=MU(await F(e)),c=o.filter(u=>!i.has(u.messageId));if(c.length){let u=new Map;for(let f of c){let d=`${f.model||"unknown"}\0${f.speed||""}`,p=u.get(d)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},cacheWriteTtl:null,messageIds:[]};for(let h of Object.keys(p.tokens))p.tokens[h]+=f.tokens[h];f.cacheWriteTtl&&(p.cacheWriteTtl??={m5:0,h1:0},p.cacheWriteTtl.m5+=f.cacheWriteTtl.m5,p.cacheWriteTtl.h1+=f.cacheWriteTtl.h1),p.messageIds.push(f.messageId),p.speed=f.speed||null,u.set(d,p)}for(let[f,d]of u){let p=f.split("\0")[0];await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:p,usd:mn(p,d.tokens,void 0,d.speed?{speed:d.speed}:void 0),tokens:d.tokens,...d.speed?{speed:d.speed}:{},cacheWriteTtl:d.cacheWriteTtl,messageId:d.messageIds[d.messageIds.length-1],messageIds:d.messageIds,apiCalls:d.messageIds.length}})}}let l=a.tokens.input+a.tokens.cacheWrite+a.tokens.cacheRead;await r({type:"context.usage",actor:"system",source:"transcript",payload:{model:a.model,occupancy:l,tokens:a.tokens}})}Yo();lf();me();kl();wu();import{execFile as FU}from"node:child_process";import{promisify as UU}from"node:util";var HU=UU(FU),Gw=(e,t)=>HU("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4});function OA(e,t=Date.now()){return Vd(e,t)??0}function WU(e,t,n){for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="cost.recorded"||o.boxId!==t||n!=null&&o.epoch!=null&&o.epoch!==n)continue;let s=o.payload?.model;if(s&&s!=="unknown")return s}return null}async function CA(e,t,{now:n=Date.now()}={}){let r=OA(t,n),o=await F(e);return hu({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:WU(o,t.name,r)})}function qU(e,t,n,r){let o=Array.isArray(t?.epochs)?t.epochs:[],s=r>0?o[r-1]:null,a=s?.endReason?.code??(typeof s?.endReason=="string"?s.endReason:null),i=null;for(let c=n.length-1;c>=0;c--){let l=n[c];if(l.type==="turn.user"&&l.boxId===t.name&&l.actor==="user"){i=Pn(l.payload?.promptHead||l.payload?.text||"")?.category??null;break}}return{wallReason:a,fixerCategory:i}}async function KU(e,t){try{let{stdout:n}=await Gw(e,["show","--shortstat","--format=",t]),r=/(\d+) files? changed/.exec(n),o=/(\d+) insertions?\(\+\)/.exec(n),s=/(\d+) deletions?\(-\)/.exec(n);return{files:r?Number(r[1]):0,insertions:o?Number(o[1]):0,deletions:s?Number(s[1]):0}}catch{return{files:0,insertions:0,deletions:0}}}async function GU(e){try{let{stdout:t}=await Gw(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function MA(e,t,n,{cwd:r=t?.cwd,log:o=console,now:s=Date.now()}={}){if(!e?.id||!t?.name||!n||!r)return{recorded:!1,reason:"incomplete"};let a=await F(e);if(a.some(p=>p.type==="code.committed"&&p.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s;try{let{stdout:p}=await Gw(r,["show","-s","--format=%ct",n]),h=Number(p.trim())*1e3;Number.isFinite(h)&&h>0&&(i=h)}catch{return{recorded:!1,reason:"unknown-sha"}}let c=OA(t,i),l=await KU(r,n),u=await $(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:await GU(r),...l,ts:i}}),f=null,d=!1;try{let p=await mS(r,n,{fixKey:Us({trackId:e.id,boxId:t.name,epoch:c}),window:Dr,context:{...qU(e,t,a,c),provider:t.agent??null}});if(p){f=await $(e,{type:"code.rework",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:u.id,payload:p});let h=hS(p);if(h>=pS){let w=p.origins.filter(g=>g.class==="rework").slice(0,3);await $(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:f.id,payload:{sha:n,subject:p.subject,linesReworked:h,origins:w.map(g=>({key:g.key,provider:g.provider,model:g.model,lines:g.lines,ageDays:g.ageDays})),heuristic:p.heuristic,ts:i}}),d=!0}}}catch(p){o.warn?.(`[rework] ${e.id}: analysis of ${String(n).slice(0,7)} failed: ${p?.message||p}`)}return{recorded:!0,event:u,rework:f,offered:d}}async function NA(e,t,n){if(!$i.includes(n))throw new Error(`bad cause "${n}" (${$i.join("|")})`);let r=await F(e),o=r.find(s=>s.type==="rework.cause.offered"&&s.payload?.sha===t);if(!o)throw new Error("unknown rework offer");if(r.some(s=>s.type==="rework.cause.answered"&&s.payload?.sha===t))throw new Error("already answered");return $(e,{type:"rework.cause.answered",actor:"user",source:"orchestrator",boxId:o.boxId??null,causationId:o.id,payload:{sha:t,cause:n,level:"B",ts:Date.now()}})}me();me();vr();me();vr();Dn();function gc(e){let t={};for(let n of e.boxes||[]){let r=n.role&&n.role!=="lead"?` \xB7 ${n.role}`:"";t[n.name]=`${n.name} (${n.agent||"?"}${r})`}return t}var PA=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),DA=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},ld=e=>Math.round(e*1e4)/1e4;async function Vw(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=PA(),f=0,d=[];for(let p of e||[]){let h=await F(p),w=xr(h,{boxLabels:gc(p)});if(w.turns===0){p.archivedAt?f++:d.push(p.name||p.id);continue}o+=w.totalUsd,s+=w.turns,a+=w.repricedTurns||0,i+=w.asRecordedUsd||0,c+=w.unpricedTurns||0;for(let g of w.unpricedModels||[])l.add(g);DA(u,w.totalTokens);for(let[g,k]of Object.entries(w.byModel))n[g]||={usd:0,events:0,tokens:PA()},n[g].usd=ld(n[g].usd+k.usd),n[g].events+=k.events,DA(n[g].tokens,k.tokens);for(let[g,k]of Object.entries(w.byProvider))r[g]||={usd:0,events:0},r[g].usd=ld(r[g].usd+k.usd),r[g].events+=k.events;t.push({id:p.id,name:p.name,usd:w.totalUsd,rollup:w})}return t.sort((p,h)=>h.usd-p.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:bs(),fleet:{totalUsd:ld(o),asRecordedUsd:ld(i),turns:s,repricedTurns:a,unpricedTurns:c,unpricedModels:[...l],totalTokens:u,byModel:n,byProvider:r,tracksWithCost:t.length,tracksSilent:f+d.length,tracksSilentArchived:f,tracksSilentLive:d},tracks:t}}var Vr=e=>`$${e.toFixed(4)}`,ca=(e,t)=>String(e).padEnd(t);function BA(e){let{fleet:t,tracks:n}=e,r=[];r.push(`BOSTRAT COST READ-OUT \xB7 ${e.generatedAt}`),e.pricingBasis&&r.push(`basis: ${e.pricingBasis}`);let o=t.tracksSilentLive||[];if(r.push(`fleet total ${Vr(t.totalUsd)} over ${t.turns} turn(s) \xB7 ${t.tracksWithCost} track(s) with cost, ${t.tracksSilentArchived??t.tracksSilent} silent (archived)`+(o.length?`, ${o.length} LIVE with no cost data: ${o.join(", ")}`:"")),t.repricedTurns&&r.push(`${t.repricedTurns} turn(s) priced at current table rates (differs from as-recorded)`),t.asRecordedUsd!=null&&Math.abs(t.asRecordedUsd-t.totalUsd)>=.005&&r.push(`as-recorded total ${Vr(t.asRecordedUsd)} \xB7 current-rates total ${Vr(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${Vr(t.totalUsd-t.asRecordedUsd)})`),t.unpricedTurns&&r.push(`\u26A0 ${t.unpricedTurns} turn(s) UNPRICED \u2014 total under-reports. Add PER_MTOK rate(s) for: ${(t.unpricedModels||[]).join(", ")}`),e.pricing){let a=e.pricing;r.push(`rates verified against vendor pages: ${a.tableVerifiedAt??"never"}`+(a.upcomingChanges?.length?` \xB7 scheduled: ${a.upcomingChanges.map(i=>`${i.model} ${i.from}`).join(", ")}`:""));for(let i of a.problems||[])r.push(`\u26A0 RATE TABLE: ${i}`)}r.push(""),r.push("BY MODEL");let s=Object.entries(t.byModel).sort((a,i)=>i[1].usd-a[1].usd);s.length||r.push(" (no cost events yet \u2014 hooks emit on each turn of a newly started box)");for(let[a,i]of s){let c=i.tokens;r.push(` ${ca(a,26)} ${ca(Vr(i.usd),10)} ${i.events} turn(s) \xB7 in ${c.input} out ${c.output} cacheR ${c.cacheRead} cacheW ${c.cacheCreation}`)}r.push(""),r.push("BY TRACK / TASK");for(let a of n){r.push(` ${ca(a.name||a.id,30)} ${Vr(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${ca(c.label,40)} ${ca(Vr(c.usd),10)} ${c.models.join(",")||"?"}`),c.epochs)for(let[l,u]of Object.entries(c.epochs).sort((f,d)=>Number(f[0])-Number(d[0])))r.push(` \u21B3 tenure ${l} (${u.provider||"?"})${" ".repeat(Math.max(1,24-String(u.provider||"?").length))}${ca(Vr(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
677
+ `)}me();Wp();import XU from"node:fs/promises";import ZU from"node:path";kl();vr();var ud=e=>e.payload?.ts??e.ts,VU=12e4,zr=e=>Math.round(e*1e4)/1e4,zU=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},byTrack:new Map});function YU(e,{since:t}){let{track:n,events:r,brief:o}=e,s=S=>ud(S)>=t,a=Pn([ri(n?.name),ri(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let S of r)if(S.type==="subtask.delegated"&&S.boxId&&S.payload?.task){let E=Pn(S.payload.task);E&&i.set(S.boxId,E)}let c=new Map,l=S=>{let E=S||"unattributed";return c.has(E)||c.set(E,{segments:[u(null)],lastTs:null,provider:null}),c.get(E)},u=S=>({textCat:S,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),f=[...r].sort((S,E)=>ud(S)-ud(E)),d=0,p=0,h=0,w={turns:0};for(let S of f){let E=l(S.boxId),R=E.segments[E.segments.length-1],B=ud(S);switch(E.lastTs!=null&&B>E.lastTs&&s(S)&&(R.activeMs+=Math.min(B-E.lastTs,VU)),E.lastTs=B,S.provider&&(E.provider=S.provider),S.type){case"turn.user":{let T=S.payload?.text;if(S.source==="hook"||!String(T||"").trim())break;let _=u(Pn(T));E.segments.push(_),s(S)&&(_.turns+=1);break}case"peer.message":{let T=S.payload?.text;if(!String(T||"").trim())break;let _=u(Pn(T));E.segments.push(_),s(S)&&(_.turns+=1);break}case"tool.called":{if(S.source==="transcript")break;let T=S.payload?.tool;T&&(R.tools[T]=(R.tools[T]||0)+1),s(S)&&(R.toolCalls+=1);break}case"cost.recorded":{if(!s(S))break;let{usd:T,tokens:_,model:O,unpriced:I}=Ft(S);I&&(w.turns+=1),R.usd+=T,_&&(R.tokens.input+=_.input,R.tokens.output+=_.output,R.tokens.cacheRead+=_.cacheRead,R.tokens.cacheWrite+=_.cacheWrite),R.models[O]=(R.models[O]||0)+T,S.provider&&(R.provider=S.provider);break}case"handoff.done":s(S)&&(d+=1);break;case"subtask.merged":s(S)&&(p+=1);break;case"error":s(S)&&S.payload?.kind==="subtask-failed"&&(h+=1);break;default:break}}let g=new Map,k=!1;for(let[S,E]of c)for(let R of E.segments){if(!(R.usd>0||R.activeMs>0||R.turns>0||R.toolCalls>0))continue;let T=R.textCat?.category??i.get(S)?.category??Ub(R.tools)?.category??a?.category??"uncategorized";g.has(T)||g.set(T,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{}});let _=g.get(T);_.usd+=R.usd,_.activeMs+=R.activeMs,_.turns+=R.turns,_.toolCalls+=R.toolCalls;for(let[I,U]of Object.entries(R.models))_.models[I]=(_.models[I]||0)+U;let O=R.provider||E.provider;O&&(_.providers[O]=(_.providers[O]||0)+R.usd),O==="cursor"&&R.usd===0&&(k=!0)}return{perCategory:g,handoffs:d,merged:p,failed:h,sawCursorActivity:k,unpricedTurns:w.turns}}function LA(e,{windowMs:t=null,now:n=Date.now()}={}){let r=t==null?0:n-t,o=new Map,s=[],a=0,i=!1,c=0;for(let w of e||[]){let{track:g,events:k}=w;if(!k?.length){a+=1;continue}let{perCategory:S,handoffs:E,merged:R,failed:B,sawCursorActivity:T,unpricedTurns:_}=YU(w,{since:r});T&&(i=!0),c+=_;let O={trackId:g?.id,name:g?.name||g?.id,archived:!!g?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:E,subtasksMerged:R,subtasksFailed:B};for(let[I,U]of S){O.usd+=U.usd,O.activeMs+=U.activeMs,O.turns+=U.turns,O.categories[I]={usd:zr(U.usd),activeMs:U.activeMs};for(let[X,C]of Object.entries(U.models))O.models[X]=zr((O.models[X]||0)+C);for(let[X,C]of Object.entries(U.providers))O.providers[X]=zr((O.providers[X]||0)+C);o.has(I)||o.set(I,zU());let H=o.get(I);H.usd+=U.usd,H.activeMs+=U.activeMs,H.turns+=U.turns,H.toolCalls+=U.toolCalls;for(let[X,C]of Object.entries(U.models))H.models[X]=(H.models[X]||0)+C;for(let[X,C]of Object.entries(U.providers))H.providers[X]=(H.providers[X]||0)+C;let ae=H.byTrack.get(g?.id)||{usd:0,activeMs:0};ae.usd+=U.usd,ae.activeMs+=U.activeMs,H.byTrack.set(g?.id,ae)}(O.usd>0||O.activeMs>0||O.turns>0)&&(O.usd=zr(O.usd),O.dominantCategory=JU(O.categories),s.push(O))}let l=[...o.values()].reduce((w,g)=>w+g.usd,0),u=[...o.values()].reduce((w,g)=>w+g.activeMs,0),f=l>0?"usd":"time",d=f==="usd"?l:u,p=new Map((e||[]).map(w=>[w.track?.id,w.track?.name||w.track?.id])),h=[...o.entries()].map(([w,g])=>({category:w,sharePct:d>0?Math.round((f==="usd"?g.usd:g.activeMs)/d*100):0,shareBasis:f,usd:zr(g.usd),activeMs:g.activeMs,turns:g.turns,toolCalls:g.toolCalls,models:jA(g.models),providers:jA(g.providers),topWorkstreams:[...g.byTrack.entries()].sort((k,S)=>S[1].usd-k[1].usd||S[1].activeMs-k[1].activeMs).slice(0,2).map(([k,S])=>({trackId:k,name:p.get(k),usd:zr(S.usd),activeMs:S.activeMs}))})).sort((w,g)=>g.usd-w.usd||g.activeMs-w.activeMs);return s.sort((w,g)=>g.usd-w.usd||g.activeMs-w.activeMs),{since:r,capturedAt:n,totalUsd:zr(l),activeMs:u,turns:[...o.values()].reduce((w,g)=>w+g.turns,0),bullets:h,workstreams:s,gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c}}}var JU=e=>{let t=null;for(let[n,r]of Object.entries(e))(!t||r.usd>t.v.usd||r.usd===t.v.usd&&r.activeMs>t.v.activeMs)&&(t={cat:n,v:r});return t?.cat??null},jA=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,zr(n)]));var la={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function QU(e){let t=String(e||"7d");return t in la?{key:t,ms:la[t]}:{key:"7d",ms:la["7d"]}}function e4(e,t){let n=new Set((t||[]).filter(o=>o.source==="orchestrator").map(o=>`${o.type}|${o.payload?.ts??"?"}`)),r=[...t||[]];for(let o of e?.events||[]){let s=Wl(o);!s||n.has(`${s.type}|${s.payload?.ts??"?"}`)||r.push({trackId:e.id,boxId:s.boxId??null,ts:o.at,type:s.type,actor:s.actor,provider:s.provider??null,source:s.source,payload:s.payload})}return r}async function t4(e){if(!e?.cwd)return null;try{let n=(await XU.readFile(ZU.join(e.cwd,".bostrat","handoff","latest.md"),"utf8")).match(/^##\s*Objective\s*\n([\s\S]*?)(?:\n##\s|\n*$)/m);return n?n[1].trim().slice(0,1e3):null}catch{return null}}async function FA(e,{window:t="7d",from:n,to:r,now:o=Date.now()}={}){let s=Number(n),a=Number(r),i=Number.isFinite(s)&&s>0,c=i&&Number.isFinite(a)&&a>s?Math.min(a,o):o,{key:l,ms:u}=i?{key:"custom",ms:c-s}:QU(t),f=[];for(let d of e||[]){let p=await F(d),h=e4(d,p);i&&c<o&&(h=h.filter(w=>(w.ts??0)<=c)),f.push({track:d,events:h,brief:await t4(d)})}return{window:l,...LA(f,{windowMs:u,now:c})}}Dn();var Yr=36e5,qA=24*Yr,n4=400,r4=12,Ko=e=>Math.round(e*1e4)/1e4;function zw({window:e,from:t,to:n,now:r=Date.now()}={}){let o=Number(t),s=Number(n);if(Number.isFinite(o)&&o>0){let c=Number.isFinite(s)&&s>o?Math.min(s,r):r;return{key:"custom",since:o,until:c}}let a=String(e||"7d")in la?String(e||"7d"):"7d",i=la[a];return{key:a,since:i==null?null:r-i,until:r}}var o4=(e,t)=>e!=null&&t-e<=48*Yr?Yr:qA;function UA(e,t){if(t===Yr)return Math.floor(e/Yr)*Yr;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function s4(e,t){if(t===Yr)return e+Yr;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var HA=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),WA=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},a4=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Ko(n)]));async function KA(e,t={}){let n=t.now??Date.now(),r=zw({...t,now:n}),o=r.since==null?qA:o4(r.since,r.until),s=I=>(r.since==null||I>=r.since)&&I<r.until,a=r.since!=null?r.until-r.since:null,i=I=>a!=null&&I>=r.since-a&&I<r.since,c={},l={},u=HA(),f=0,d=0,p=0,h=0,w=0,g=0,k=new Set,S=new Map,E=[],R=[],B=[],T=null;for(let I of e||[]){let H=(await F(I)).filter(C=>C.type==="cost.recorded");if(!H.length){I.archivedAt||B.push(I.name||I.id);continue}let ae=[];for(let C of H){let Q=C.ts??0;s(Q)?ae.push(C):i(Q)&&(g+=Ft(C).usd)}if(!ae.length)continue;let X=xr(ae,{boxLabels:gc(I)});f+=X.totalUsd,d+=X.turns,p+=X.repricedTurns||0,h+=X.asRecordedUsd||0,w+=X.unpricedTurns||0;for(let C of X.unpricedModels||[])k.add(C);WA(u,X.totalTokens);for(let[C,Q]of Object.entries(X.byModel))c[C]||={usd:0,events:0,tokens:HA()},c[C].usd=Ko(c[C].usd+Q.usd),c[C].events+=Q.events,WA(c[C].tokens,Q.tokens);for(let[C,Q]of Object.entries(X.byProvider))l[C]||={usd:0,events:0},l[C].usd=Ko(l[C].usd+Q.usd),l[C].events+=Q.events;for(let C of ae){let{usd:Q}=Ft(C);if(!Q)continue;let ve=UA(C.ts??0,o),W=S.get(ve)??{t:ve,total:0,byProvider:{}};W.total+=Q;let be=C.provider||"unknown";W.byProvider[be]=(W.byProvider[be]||0)+Q,S.set(ve,W),(T==null||ve<T)&&(T=ve)}E.push({id:I.id,name:I.name||I.id,archived:!!I.archivedAt,usd:X.totalUsd,turns:X.turns,providers:Object.keys(X.byProvider)});for(let[C,Q]of Object.entries(X.byBox))R.push({trackId:I.id,trackName:I.name||I.id,boxId:C,...Q})}let _=r.since!=null?UA(r.since,o):T,O=[];for(let I=_,U=0;I!=null&&I<r.until&&U<n4;I=s4(I,o),U++){let H=S.get(I);O.push(H?{t:I,total:Ko(H.total),byProvider:a4(H.byProvider)}:{t:I,total:0,byProvider:{}})}return E.sort((I,U)=>U.usd-I.usd),R.sort((I,U)=>U.usd-I.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:bs(),window:r.key,since:r.since,until:r.until,bucketMs:o,series:O,fleet:{totalUsd:Ko(f),asRecordedUsd:Ko(h),turns:d,repricedTurns:p,unpricedTurns:w,unpricedModels:[...k],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:E.length,tracksSilentLive:B},prior:a!=null?{totalUsd:Ko(g),since:r.since-a,until:r.since}:null,tracks:E.slice(0,50),boxes:R.slice(0,r4)}}wu();var i4=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),c4=20,l4=40;async function GA(e,t={}){let n=t.now??Date.now(),r=zw({...t,now:n}),o=l=>(r.since==null||l>=r.since)&&l<r.until,s=[],a={},i=0;for(let l of e||[]){let u=await F(l),f=0,d=gc(l);for(let p of u){if(!i4.has(p.type))continue;let h=p.type==="code.rework"?p.payload?.ts??p.ts:p.ts;p.type!=="rework.cause.answered"&&!o(h??0)||(p.type==="code.committed"&&f++,s.push(p.trackId?p:{...p,trackId:l.id}))}f&&i++;for(let p of l.boxes||[])a[`${l.id}/${p.name}`]={trackName:l.name||l.id,label:d[p.name]||p.name}}let c=wS(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:Dr,decayEndDays:$m,basis:c.basis,commits:c.commits,tracksWithCommits:i,fixesAnalyzed:c.fixes.length,fixUsdTotal:c.fixUsdTotal,buckets:c.buckets,verdicts:c.verdicts,pendingTaps:c.pendingTaps.length,byProvider:c.byProvider,byModel:c.byModel,epochs:c.epochs.slice(0,c4),fixes:c.fixes.slice(0,l4)}}import u4 from"node:fs";import VA from"node:fs/promises";import yc from"node:os";import d4 from"node:path";Gm();lt();var f4=1024*1024,dd=e=>Math.round(e/f4);async function p4(e){try{let t=await VA.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:dd(r),diskTotalMb:dd(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function m4(){try{return(await zt()).filter(t=>t.isBostrat).length}catch{return null}}async function h4(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await VA.readdir(d4.join(sc,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function zA({stateDir:e=sc,now:t=Date.now}={}){let n=yc.totalmem(),[r,o,s,a]=await Promise.all([Su().catch(()=>null),p4(u4.existsSync(e)?e:yc.tmpdir()),m4(),h4()]),i=yc.cpus()?.length||null,c=yc.loadavg()?.[0]??null;return{ts:t(),loadavg1:c!=null?Math.round(c*100)/100:null,cpus:i,cpuPct:c!=null&&i?Math.min(100,Math.round(c/i*100)):null,memUsedMb:r!=null?dd(n-r):null,memTotalMb:dd(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(yc.uptime())}}me();Hf();Oa();Dn();me();Dn();var w4=864e5;function g4(e,{tolerance:t=.005}={}){if(e.type!=="cost.recorded"||e.source==="vendor")return null;let n=e.payload?.tokens,r=Number(e.payload?.usd)||0;if(!(n?(n.input||0)+(n.output||0)+(n.cacheRead||0)+(n.cacheWrite??n.cacheCreation??0):0)||!r)return null;let s=e.payload?.model||"unknown",a=e.payload?.speed||void 0,i={input:n.input||0,output:n.output||0,cacheRead:n.cacheRead||0,cacheWrite:n.cacheWrite??n.cacheCreation??0},c=mn(s,i,e.ts,a?{speed:a}:void 0);if(!c)return null;let l=r-c,u=Math.abs(l)>Math.max(c*t,.001);return{model:s,speed:a??null,ts:e.ts,asRecorded:r,expected:c,delta:l,divergent:u}}async function YA(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*w4,s={},a=0,i=0,c=[];for(let u of e||[]){let f=await F(u);for(let d of f){if(!d.ts||d.ts<o)continue;let p=g4(d,{tolerance:n});if(!p)continue;a++;let h=p.speed?`${p.model} (${p.speed})`:p.model,w=s[h]||={rows:0,divergent:0,asRecordedUsd:0,expectedUsd:0};w.rows++,w.asRecordedUsd+=p.asRecorded,w.expectedUsd+=p.expected,p.divergent&&(i++,w.divergent++,c.length<10&&c.push({track:u.name||u.id,...p}))}}let l=u=>Math.round(u*1e4)/1e4;for(let u of Object.values(s))u.asRecordedUsd=l(u.asRecordedUsd),u.expectedUsd=l(u.expectedUsd);return{sinceMs:o,days:t,tolerance:n,rows:a,divergent:i,byModel:s,examples:c,ok:i===0}}Em();Fl();it();Bn();import ua from"node:fs/promises";import y4 from"node:fs";import ft from"node:path";import b4 from"node:os";import{execFile as k4}from"node:child_process";import{promisify as x4}from"node:util";var v4=x4(k4),JA=process.env.BOSTRAT_STATE_DIR||ft.join(process.env.HOME||b4.tmpdir(),".bostrat"),fd=!1,Yw=null;async function Jw(e,t){let n=await ua.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await ua.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await ua.mkdir(ft.dirname(t),{recursive:!0}),await ua.copyFile(e,t),!0)}var S4=new Set([".claude",".codex",".cursor",".credentials.json","auth.json",".claude.json","api-token","node.env","certs","integrations.json","gcloud","application_default_credentials.json",".gemini"]);async function pd(e,t,{skip:n=null}={}){let r=0,o=await ua.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(S4.has(s.name)||n?.has(s.name))continue;let a=ft.join(e,s.name);s.isDirectory()?r+=await pd(a,ft.join(t,s.name)):s.isFile()&&(r+=await Jw(a,ft.join(t,s.name))?1:0)}return r}async function XA({stateDir:e=JA,dest:t=process.env.BOSTRAT_SYNC_DIR||`${JA}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await ua.mkdir(t,{recursive:!0});let o=0;o+=await Jw(ft.join(e,"tracks.json"),ft.join(t,"tracks.json"))?1:0,o+=await Jw(ft.join(e,"events.jsonl"),ft.join(t,"events.jsonl"))?1:0,o+=await pd(ft.join(e,"events"),ft.join(t,"events")),o+=await pd(ft.join(e,"memory"),ft.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await pd(ft.join(u.cwd,".bostrat"),ft.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>v4("git",["-C",t,...u]);y4.existsSync(ft.join(t,".git"))||(await a("init","-q"),await a("config","user.email","agent@bostrat.local"),await a("config","user.name","bostrat state sync")),n&&/^https:\/\/github\.com\//i.test(n)&&(await a("config","--get","credential.useHttpPath").then(()=>!0).catch(()=>!1)||await Wd(t).catch(()=>{}));let i=!1,{stdout:c}=await a("status","--porcelain");c.trim()&&(await a("add","-A"),await a("commit","-q","-m",`state sync ${new Date().toISOString()}`),i=!0);let l=!1;if(n&&(i||fd))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,fd&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),fd=!1,Yw=null}catch(u){fd=!0;let f=(u?.stderr||u?.message||String(u)).trim().split(`
678
+ `).slice(-3).join(" | ").slice(0,300);f!==Yw&&(Yw=f,console.warn(`[state-sync] PUSH FAILING (retrying each cycle; off-box copy is STALE): ${f}`))}return{staged:o,committed:i,pushed:l}}catch(o){return{staged:0,committed:!1,pushed:!1,error:o?.message||String(o)}}}dh();Xt();io();lt();Ta();import{execFile as T4}from"node:child_process";import{promisify as E4}from"node:util";import{randomUUID as A4}from"node:crypto";import _4 from"node:fs";import I4 from"node:os";import $4 from"node:path";var Xr=E4(T4),md=e=>new Promise(t=>setTimeout(t,e)),Zr=ff,Xw=process.env.BOSTRAT_USAGE_PROBE_CWD||$4.join(I4.homedir(),".bostrat","usage-probe"),R4=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,O4=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,C4=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,ZA=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,Jr=null,bc=null,kc=null;async function M4(){try{return await Xr(K,V("has-session","-t",Zr)),!0}catch{return!1}}function N4(){Jr&&clearTimeout(Jr),Jr=setTimeout(()=>P4().catch(()=>{}),R4),Jr.unref&&Jr.unref()}async function P4(){Jr&&(clearTimeout(Jr),Jr=null);try{await Xr(K,V("kill-session","-t",Zr))}catch{}}async function D4(){let e=Date.now()+C4;for(;;){let t=await Zw().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await md(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await md(500)}}async function B4(){if(await M4())return;if(!await fr())throw new Error("host tmux server not running \u2014 start globo-tmux.service");_4.mkdirSync(Xw,{recursive:!0}),await or(Xw);let e=A4();await Xr(K,V("new-session","-d","-s",Zr,"-c",Xw,"-x","200","-y","60",...Fa()));let t=`${df} --session-id ${e}`;await Xr(K,V("send-keys","-t",Zr,t,"Enter")),await D4()}async function Zw(){let{stdout:e}=await Xr(K,V("capture-pane","-t",Zr,"-p"));return e}async function j4(){await B4(),await Xr(K,V("send-keys","-t",Zr,"-l","/usage")),await Xr(K,V("send-keys","-t",Zr,"Enter"));let e=Date.now()+O4,t="";for(;await md(400),t=await Zw(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await md(900),t=await Zw(),await Xr(K,V("send-keys","-t",Zr,"Escape")).catch(()=>{}),N4(),t}function L4(e){let t=String(e||"").split(`
679
+ `).map(s=>s.replace(/\s+$/,"").trim()),n=s=>{let a=null,i=null;for(let c=s+1;c<Math.min(s+5,t.length)&&!/^Current\s/i.test(t[c]);c++){let l=t[c].match(/(\d+)%\s*used/i);l&&a===null&&(a=Number(l[1]));let u=t[c].match(/^Resets\s+(.+)$/i);u&&i===null&&(i=u[1].trim())}return a===null?null:{pct:a,resets:i||null}},r=s=>{let a=t.findIndex(i=>s.test(i));return a<0?null:n(a)},o=[];return t.forEach((s,a)=>{let i=s.match(/^Current week \(([^)]+)\)$/i);if(!i||/all models/i.test(i[1]))return;let c=n(a);c&&o.push({model:i[1].trim(),...c})}),{session:r(/^Current session\b/i),week:r(/^Current week \(all models\)/i)||r(/^Current week$/i),weekModels:o.length?o:null}}function F4(e){let t=String(e||"").split(`
680
+ `).map(s=>s.replace(/\s+$/,"")),n=t.findIndex(s=>/What's contributing/i.test(s));if(n<0)return null;let r=/(Usage credits|Esc to cancel|d to day · w to week|^\s*d to day)/i,o=[];for(let s=n+1;s<t.length&&!r.test(t[s]);s++)t[s].trim()&&o.push(t[s].trim());return o.length?o:null}async function QA({fresh:e=!1}={}){return!e&&bc&&Date.now()-bc.at<ZA?bc.data:kc||(kc=(async()=>{try{let t=await j4(),n=L4(t),r={...n,contributors:F4(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return bc={at:Date.now(),data:r},r}catch(t){let n={session:null,week:null,contributors:null,subscription:!1,error:t?.message||String(t),capturedAt:Date.now()};return bc={at:Date.now()-(ZA-3e3),data:n},n}finally{kc=null}})(),kc)}var U4=262144;function H4(e){let t=Number(e);if(!Number.isFinite(t)||t<0)return null;let n=Math.floor(t/3600),r=Math.round(t%3600/60);return n>=48?`in ${Math.round(n/24)}d`:n>0?`in ${n}h ${r}m`:`in ${Math.max(1,r)}m`}var W4=new Set([300]),q4=new Set([10080]);function K4(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:W4.has(t)?"session":q4.has(t)?"week":"other"}function G4(e){let t=Number(e);return!Number.isFinite(t)||t<=0?"Window":t%1440===0?`Window \xB7 ${t/1440}d`:t%60===0?`Window \xB7 ${t/60}h`:`Window \xB7 ${t}m`}function V4(e,t,n){if(!e||typeof e!="object")return null;let r=Number(e.used_percent);if(!Number.isFinite(r))return null;let o=null,s=Number(e.resets_at),a=Number(e.resets_in_seconds);return Number.isFinite(s)&&s>0?o=s*1e3:Number.isFinite(a)&&a>=0&&(o=(Number.isFinite(t)?t:n)+a*1e3),{pct:Math.round(r),resets:o!=null?H4((o-n)/1e3):null,resetsAt:o}}var xc=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function z4(e,t=Date.now()){let n=String(e||"").split(`
681
+ `),r=!1;for(let o=n.length-1;o>=0;o--){let s=n[o].trim();if(!s||s[0]!=="{"||!s.includes("token_count"))continue;let a;try{a=JSON.parse(s)}catch{continue}let i=a?.payload;if(i?.type!=="token_count")continue;r=!0;let c=i.rate_limits;if(!c)return xc(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=xc(r);[c.primary,c.secondary].forEach((p,h)=>{let w=V4(p,l,t);if(!w)return;let g=K4(p.window_minutes);g===null&&(g=h===0?"session":"week"),g==="session"&&!u.session?u.session=w:g==="week"&&!u.week?u.week=w:(u.other??=[]).push({label:G4(p.window_minutes),...w})}),u.planType=typeof c.plan_type=="string"?c.plan_type:null;let d=c.credits;return d&&(d.has_credits||d.unlimited)&&(u.credits={balance:String(d.balance??""),unlimited:!!d.unlimited}),u.limitReached=typeof c.rate_limit_reached_type=="string"&&c.rate_limit_reached_type||(c.spend_control_reached?"spend_control":null),u}if(c.primary_used_percent!=null||c.secondary_used_percent!=null){let l=u=>Number.isFinite(Number(u))?{pct:Math.round(Number(u)),resets:null,resetsAt:null}:null;return{...xc(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return xc(r)}return xc(r)}async function Qw(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await so(e?.cwd,e?.sessionId);if(!n)return{...t,session:null,week:null,subscription:!1,error:"no codex rollout found for this box yet",capturedAt:Date.now()};let r=await Et(n.file,U4),o=z4(r);return{...t,session:o.session,week:o.week,other:o.other,planType:o.planType,credits:o.credits,limitReached:o.limitReached,subscription:!!(o.session||o.week||o.other?.length),capturedAt:n.mtimeMs||Date.now()}}catch(n){return{...t,session:null,week:null,subscription:!1,error:n?.message||String(n),capturedAt:Date.now()}}}async function e_(e,{fresh:t=!1}={}){let n=new Set;for(let o of e||[])for(let s of o.boxes||[])s.agent&&n.add(s.agent);let r=[];if((n.has("claude")||n.size===0)&&r.push(await hd({agent:"claude"},{fresh:t})),n.has("codex")){let o=[],s=[...e||[]].sort((i,c)=>(i.archivedAt?1:0)-(c.archivedAt?1:0)||(c.createdAt||0)-(i.createdAt||0));for(let i of s)for(let c of i.boxes||[])c.agent==="codex"&&o.push({...c,cwd:c.cwd||i.cwd});let a=null;for(let i of o.slice(0,8)){let c=await Qw(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await Qw(null))}return n.has("cursor")&&r.push(await hd({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function hd(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?Qw(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await QA({fresh:t})}}ar();it();it();function Y4(e=process.env){return!!(Ie(e)&&e.BOSTRAT_PLANE_TOKEN)}var J4=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),wd=(e,t)=>Object.assign(new Error(e),{status:t});async function t_(e,t){if(!Y4(t))throw wd("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${Ie(t)}${e}`,{headers:J4(t)})}catch(o){throw wd(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw wd(r?.error||`plane replied ${n.status}`,n.status);return r}async function n_(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await t_(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function r_(e,{env:t=process.env}={}){if(!e)throw wd("message id required",400);return(await t_(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}gi();eu();function eg(e){let t=e.split(".");if(t.length!==4)return null;let n=0;for(let r of t){let o=Number(r);if(!Number.isInteger(o)||o<0||o>255)return null;n=n*256+o}return n>>>0}function X4(e){let[t,n]=e.split("/"),r=eg(t);if(r==null)return null;let o=n==null?32:Number(n);if(!Number.isInteger(o)||o<0||o>32)return null;let s=o===0?0:4294967295<<32-o>>>0;return a=>(a&s)===(r&s)}function o_(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(X4).filter(Boolean)}function Z4(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function s_(e){let t=o_(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:Z4,allowed(r){if(n)return!0;let o=eg((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function a_(e,t){let n=o_(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=eg(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import i_ from"node:crypto";import gd from"node:fs";import Q4 from"node:path";function c_(e=process.env,{stateDir:t=sc,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=Q4.join(t,"api-token");try{let a=gd.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=i_.randomBytes(32).toString("base64url");try{gd.mkdirSync(t,{recursive:!0}),gd.writeFileSync(o,s+`
682
+ `,{mode:384}),gd.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function vc(e){let t=e?.socket?.remoteAddress||"";if(!t)return!1;let n=t.replace(/^::ffff:/,"");return n==="::1"||n==="127.0.0.1"||/^127\./.test(n)}function l_(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:i_.timingSafeEqual(n,r)}function u_(e,t=null){let n=e?.headers?.["x-bostrat-token"];if(typeof n=="string"&&n.trim())return n.trim();let r=e?.headers?.authorization||"",o=/^Bearer\s+(.+)$/i.exec(r)?.[1];if(o)return o.trim();try{return(t??new URL(e.url,"http://node")).searchParams.get("token")||""}catch{return""}}var e2=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/],t2=e=>e2.some(t=>t.test(e));function d_({token:e,enforce:t=!0,log:n=console}={}){return function(o,s,a){let i=o.path||o.url||"";if(!i.startsWith("/api"))return a();let c=u_(o);return l_(c,e)?a():t2(i)?(n.log?.(`[perimeter] refused ${o.method} ${i} \u2014 sensitive route requires the node API token`),s.status(401).json({error:"this route requires the node API token"})):!t||vc(o)?a():(n.log?.(`[perimeter] refused ${o.method} ${i} from ${o.socket?.remoteAddress||"?"} \u2014 no node API token`),s.status(401).json({error:"unauthorized"}))}}function f_(e,t,{enforce:n=!0}={}){return!n||l_(u_(e),t)?!0:vc(e)}dn();xu();xu();import n2 from"node:http";import r2 from"node:net";function yd(e){if(!e)return null;let t=String(e).replace(/:\d+$/,"").toLowerCase();if(/^[\d.]+$/.test(t)||t.includes(":"))return null;let n=t.split(".");if(n.length<3)return null;let r=n[0];return/^[a-z0-9-]+$/.test(r)?r:null}function bd(e){let t=yd(e.headers.host);return t?{slug:t,view:Um(t)}:null}var o2=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),s2=e=>{let t=o2(e.name);return`<!doctype html><meta charset="utf-8">
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 p_(e,t,n){let r=bd(e);if(!r)return n();let{view:o,slug:s}=r;if(!o)return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: no view named "${s}"`);if(o.state==="starting")return t.statusCode=503,t.setHeader("content-type","text/html"),t.end(s2(o));if(o.state!=="live"&&o.state!=="unhealthy")return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" is ${o.state} \u2014 restart it from the Views tab`);let a={...e.headers,host:`127.0.0.1:${o.port}`,"x-forwarded-host":e.headers.host,"x-forwarded-proto":e.headers["x-forwarded-proto"]||"http"};delete a.authorization,delete a.cookie;let i=n2.request({host:"127.0.0.1",port:o.port,method:e.method,path:e.url,headers:a},c=>{t.writeHead(c.statusCode||502,c.headers),c.pipe(t)});i.on("error",()=>{t.headersSent?t.destroy():(t.statusCode=502,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" did not answer on :${o.port}`))}),e.pipe(i),e.on("aborted",()=>i.destroy())}function m_(e,t,n){let r=bd(e);if(!r)return!1;let{view:o,slug:s}=r;if(!o||o.state!=="live"&&o.state!=="unhealthy")return t.write(`HTTP/1.1 404 Not Found\r
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=r2.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${e.url} HTTP/1.1`];for(let[l,u]of Object.entries(e.headers))l!=="host"&&(l==="authorization"||l==="cookie"||c.push(`${l}: ${Array.isArray(u)?u.join(", "):u}`));c.push(`host: 127.0.0.1:${o.port}`),a.write(c.join(`\r
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 h_(e,t){let n=typeof t=="string"?{host:t}:t||{},r=n["x-bostrat-view-base"];return typeof r=="string"&&r?`${n["x-forwarded-proto"]==="https"?"https":"http"}://${e.slug}.${r.replace(/:\d+$/,"")}/`:`http://${e.slug}.${a2(n.host)}/`}function a2(e){if(process.env.BOSTRAT_PUBLIC_HOST)return String(process.env.BOSTRAT_PUBLIC_HOST).replace(/:\d+$/,"");let t=String(e||"").replace(/:\d+$/,"").toLowerCase();if(!t||!t.includes(".")||/^[\d.]+$/.test(t))return"bostrat.globopi";let n=t.split(".");return yd(t)&&Um(n[0])?n.slice(1).join("."):t}Ks();eh();Iu();pm();me();import w_ from"node:os";import{randomUUID as ng}from"node:crypto";var i2=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||w_.hostname(),nodeName:e.BOSTRAT_NODE_NAME||w_.hostname()});var g_=32768,y_=120,b_=1e3,k_=new Set(["claude","codex","cursor"]),c2=new Set(["off","transition","nag"]),l2=[[0,59],[0,23],[1,31],[1,12],[0,6]];function u2(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=l2[r];return String(n).split(",").every(a=>{if(!a)return!1;let[i,c]=a.split("/");if(c!==void 0&&!(Number.isInteger(Number(c))&&Number(c)>=1))return!1;if(i==="*")return!0;let[l,u]=i.includes("-")?i.split("-").map(Number):[Number(i),Number(i)];return Number.isInteger(l)&&Number.isInteger(u)&&l>=o&&u<=s&&l<=u})})}var an=e=>String(e??"").trim(),Go={name(e){let t=an(e);if(!t)throw new Error("a loop needs a name");if(t.length>y_)throw new Error(`name is too long (${t.length}); cap is ${y_}`);return t},schedule(e){let t=an(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!u2(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=an(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>g_)throw new Error(`prompt is too long (${t.length} chars); cap is ${g_}`);return t},expectation(e){let t=an(e)||null;if(t&&t.length>b_)throw new Error(`expectation is too long (${t.length}); cap is ${b_}`);return t},notify(e){let t=an(e)||"off";if(!c2.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=an(typeof t=="string"?t:t?.provider)||"claude";if(!k_.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...k_].join(", ")}`);let r=typeof t=="object"&&t&&an(t.model)||null;return r?{provider:n,model:r}:{provider:n}},enabled(e){if(typeof e=="boolean")return e;if(e==="true"||e==="false")return e==="true";throw new Error(`enabled must be true or false, got "${e}"`)}};function d2(e,t){let n=e&&typeof e=="object"?e:{},r=Go.name(n.name),o=Go.schedule(n.schedule),s=Go.prompt(n.prompt),a=Go.expectation(n.expectation),i=Go.notify(n.notify),c=Go.assignment(n.assignment),l=an(t?.workspace?.repo)||an(t?.workspace?.base)||null;if(!l)throw new Error("this Track isn't based on a repo, so there's nothing for a loop to run in \u2014 propose from a repo-backed Track");let{nodeId:u,nodeName:f}=i2();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:f||null}}async function v_(e,t){let n=d2(t,e),r=ng();return await $({id:e.id,cwd:e.cwd},{type:"loop.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:r,...n}}),{proposalId:r,...n}}async function S_(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await F({id:e.id,cwd:e.cwd}),a=s.find(c=>c.type==="loop.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="loop.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await $({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("loopId required \u2014 the loop is created on the plane before the card is answered");let i=a.payload;return await $({id:e.id,cwd:e.cwd},{type:"loop.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:String(r),name:i.name,schedule:i.schedule,provider:i.assignment?.provider??"claude",repo:i.repo??null,nodeId:i.nodeId??null,nextFireAt:Number.isFinite(Number(o))?Number(o):null}}),await $({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",loopId:String(r)}}),{proposalId:t,action:"created",loopId:String(r)}}var tg=["name","schedule","prompt","expectation","notify","assignment","enabled"],f2=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function T_(e){let t=Array.isArray(e.runs)?e.runs:[],n=t[t.length-1]??null;return{definitionUpdatedAt:Number(e.definitionUpdatedAt??e.updatedAt)||null,name:e.name??"",schedule:e.schedule??"",prompt:e.prompt??"",expectation:e.expectation??null,notify:e.notify??"off",assignment:e.assignment&&typeof e.assignment=="object"?e.assignment:{provider:String(e.assignment||"claude")},enabled:e.enabled!==!1,repo:e.repo??null,nodeId:e.nodeId??null,nodeName:e.nodeName??null,trackId:e.trackId??null,nextFireAt:Number.isFinite(Number(e.nextFireAt))?Number(e.nextFireAt):null,createdAt:Number(e.createdAt)||null,runCount:t.length,lastRun:n?{firedAt:Number(n.firedAt)||null,outcome:n.outcome??(n.error?"errored":null)}:null}}function E_(e,t){let n=an(t);if(!n)throw new Error("which loop? give an id or a name \u2014 see `bostrat-loop ls`");let r=e.find(a=>a.id===n)||e.find(a=>a.name===n);if(r)return r;let o=n.toLowerCase(),s=e.filter(a=>String(a.id).toLowerCase().startsWith(o)||String(a.name).toLowerCase().startsWith(o));if(s.length===1)return s[0];throw s.length>1?new Error(`"${n}" matches ${s.length} loops: ${s.map(a=>`${a.name} (${a.id})`).join(", ")} \u2014 use the id`):new Error(`no loop matching "${n}" \u2014 use \`bostrat-loop ls\``)}function p2(e,t){let n=e&&typeof e=="object"&&!Array.isArray(e)?e:null;if(!n)throw new Error("a patch must be a JSON object of the fields to change");let r=Object.keys(n).filter(a=>!tg.includes(a));if(r.length){let a=r.filter(i=>["repo","nodeId","cwd","userId","owner","id","trackId"].includes(i));throw a.length?new Error(`a proposal can't change ${a.join(", ")} \u2014 retargeting a loop is a Loops-tab edit (scope D5)`):new Error(`unknown field(s) ${r.join(", ")} \u2014 patchable: ${tg.join(", ")}`)}let o={};for(let a of tg){if(!(a in n))continue;let i=Go[a](n[a]);(a==="assignment"?f2(i,t.assignment):i===(t[a]??(a==="notify"?"off":a==="enabled"?!0:null)))||(o[a]=i)}let s=Object.keys(o);if(!s.length)throw new Error("nothing would change \u2014 the patch equals the loop's current definition");return{patch:o,changed:s}}async function A_(e,t,n){let r=T_(t),{patch:o,changed:s}=p2(n,r),a=ng(),i={ts:Date.now(),proposalId:a,loopId:String(t.id),name:r.name,base:r,patch:o,changed:s,selfEdit:!!(r.trackId&&r.trackId===e.id)};return await $({id:e.id,cwd:e.cwd},{type:"loop.update.offered",actor:"system",source:"orchestrator",payload:i}),i}var x_=600;async function __(e,t,n){let r=an(n);if(!r)throw new Error('a delete proposal needs a reason \u2014 bostrat-loop propose-delete <loop> --reason "<why this loop should go>"');if(r.length>x_)throw new Error(`reason is too long (${r.length}); cap is ${x_}`);let o=T_(t),s=ng(),a={ts:Date.now(),proposalId:s,loopId:String(t.id),name:o.name,base:o,reason:r,selfEdit:!!(o.trackId&&o.trackId===e.id)};return await $({id:e.id,cwd:e.cwd},{type:"loop.delete.offered",actor:"system",source:"orchestrator",payload:a}),a}var I_=async(e,t,n)=>{if(!n)throw new Error("proposalId required");let r=await F({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type===t&&a.payload?.proposalId===n);if(!o)throw new Error("unknown proposal");let s=t.replace(".offered",".answered");if(r.some(a=>a.type===s&&a.payload?.proposalId===n))throw new Error("proposal already answered");return o};async function $_(e,t,n,{nextFireAt:r=null}={}){if(!["applied","dismiss","moved"].includes(n))throw new Error("action must be one of applied | dismiss | moved");let s=(await I_(e,"loop.update.offered",t)).payload,a={id:e.id,cwd:e.cwd};return n==="applied"&&await $(a,{type:"loop.updated",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:s.loopId,name:s.patch?.name??s.name,changed:s.changed??Object.keys(s.patch||{}),nextFireAt:Number.isFinite(Number(r))?Number(r):null}}),await $(a,{type:"loop.update.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,loopId:s.loopId}}),{proposalId:t,action:n,loopId:s.loopId}}async function R_(e,t,n){if(!["delete","pause","keep","moved"].includes(n))throw new Error("action must be one of delete | pause | keep | moved");let o=(await I_(e,"loop.delete.offered",t)).payload,s={id:e.id,cwd:e.cwd};return(n==="delete"||n==="pause")&&await $(s,{type:n==="delete"?"loop.deleted":"loop.paused",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:o.loopId,name:o.name,trackId:o.base?.trackId??null}}),await $(s,{type:"loop.delete.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,loopId:o.loopId}}),{proposalId:t,action:n,loopId:o.loopId}}uu();me();ur();me();Fn();Iu();var O_=10,C_=200,m2=120,h2=24,N_=/^\d{4}-\d{2}-\d{2}$/;function rg(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var w2=(e=Date.now())=>new Date(e).toISOString().slice(0,10),pt=(e,t="i")=>new RegExp(e,t),g2=[{re:pt("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:pt("\\bSPC\\b",""),reason:"business (SPC)"},{re:pt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:pt("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:pt("\\bReplicas\\b",""),reason:"competitor research"},{re:pt("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:pt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:pt("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],y2=[pt("\\bSPC\\b",""),pt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),pt("competitor|cloudcli|\\bkiro\\b"),pt("\\bReplicas\\b",""),pt("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),pt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),pt("(^|[^\\w&])#\\d+\\b"),pt("\\btrack/[\\w.-]+")];function b2({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of g2)if(o.test(n)||o.test(r))return s;return null}function M_(e){let t=String(e||"");for(let n of y2){let r=n.exec(t);if(r)return r[0].trim()}return null}function P_(e,t=Date.now()){if(!e)return t-24*36e5;let n=/^(\d+)\s*([hd])$/.exec(String(e).trim());if(n)return t-Number(n[1])*(n[2]==="h"?36e5:24*36e5);let r=Date.parse(e);if(!Number.isNaN(r))return r;throw new Error(`unparseable since "${e}" \u2014 use 24h, 7d, or an ISO date`)}var k2=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function x2(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=ji(e);if(t.length)throw new Error(`changelog entry appears to contain a secret VALUE (${t.join(", ")}) \u2014 entries ship off-box; never put a credential in one. Replace it and retry.`);let n=null,r=[];for(let o of e.split(`
694
+ `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,m2)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${h2}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=k2.exec(i);if(!u||!u[1].trim()||!u[2].trim())throw new Error(`bullet ${r.length+1} must be \`**Short summary** \u2014 the item, one sentence.\` (bold summary title, em dash, then the change) \u2014 got "${i.slice(0,80)}". Rewrite it and re-publish.`);i=`**${u[1].trim().replace(/[:.]\s*$/,"")}** \u2014 ${u[2].trim()}`;let f=M_(i);if(f)throw new Error(`bullet ${r.length+1} mentions "${f}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items, PR numbers, branch names or codenames; drop the bullet or rewrite it as the user-visible change and re-publish.`);if(i.length>C_)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${C_}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=M_(n);if(o)throw new Error(`headline mentions "${o}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items; rewrite it and re-publish.`)}if(!r.length)throw new Error("no `- ` bullets found \u2014 an entry is a bullet list, optionally under a `# headline`");if(r.length>O_)throw new Error(`${r.length} bullets \u2014 over the ${O_}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function v2(e,{repos:t=rg()}={}){let n=new Set(t);return(await xo()).filter(r=>r.state==="merged"&&(r.resolvedAt??0)>=e&&n.has(r.repo)).sort((r,o)=>(r.resolvedAt??0)-(o.resolvedAt??0)).map(r=>({repo:r.repo,number:r.number,title:r.title||null,url:r.url||null,headRef:r.headRef||null,mergedAt:r.resolvedAt??null,excluded:b2({title:r.title,headRef:r.headRef})}))}async function D_(e,t){let n=await v2(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function B_(e,{md:t,day:n=null}){let r=x2(t),o=n==null||n===""?w2():String(n);if(!N_.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await $({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:o,title:r.title,bullets:r.bullets}});return{day:o,title:r.title,bullets:r.bullets,eventId:s.id}}async function j_(e,{day:t}){let n=String(t||"");if(!N_.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await $({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:n,title:null,bullets:[],retract:!0}});return{day:n,retracted:!0,eventId:r.id}}Bs();Fn();Eo();me();Bs();it();Nr();Fn();gi();eu();Si();Bn();import{execFile as S2}from"node:child_process";import{promisify as T2}from"node:util";var sg=T2(S2),L_=3e4,E2=30*6e4,A2=L_,_2=10*6e4,I2=10080*6e4,$2=60*6e4,R2=8,O2=1440*6e4,C2=3,F_="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",og=60*6e4,M2=15*6e4,N2=9e4,P2=1440*6e4,kd=new Map,xd=new Map,D2=/could not resolve|not found|no pull requests?/i,B2=e=>D2.test(String(e?.message||e||""));function j2(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<og)}var U_={fast:A2,slow:_2,decay:$2};function H_(e,t){return e.armedAt&&t-e.armedAt<E2||j2(e,t)||W_(e,t,{grace:0})?"fast":t-(e.firstSeen||0)>I2?"decay":"slow"}function L2(e,t){return U_[H_(e,t)]}function Tc(e,t,n,r){let o=e.lanes?.get(oe(t.repo,t.number))||{};return Ql({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function F2(e,t){Hn("watch");try{let{stdout:n}=await sg("gh",["pr","view",String(t),"--repo",e,"--json",F_],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await ln({slug:e})}});return JSON.parse(n||"null")}catch(n){throw Rr(n)&&Or(n),n}}async function U2(e){Hn("watch");try{let{stdout:t}=await sg("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",F_],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await ln({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw Rr(t)&&Or(t),t}}async function H2(){let e=new Map;for(let t of await le().catch(()=>[]))e.set(t.id,t);return e}async function W2(e,t){await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}})}async function q2(e,t){let n=await So(e);return n?Ps(n,t):null}async function K2(e,t,n){let r=await So(e);if(!r)throw new Error(`no local checkout for ${e}`);return Ds(r,t,{method:n})}async function G2(e,t){let n=await So(e);if(!n)throw new Error(`no local checkout for ${e}`);return ki(n,t)}async function V2(e,t){await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"auto-canceled",...t}})}async function da(e,t,n,r,o){if(!await r.disarm(e.repo,e.number).catch(()=>null))return;let a=n.get(e.trackId);a&&await r.emitDisarmed(a,{number:Number(e.number),url:t?.url||e.url,title:t?.title||e.title,branch:t?.headRefName||e.headRef,repo:e.repo,reason:o}).catch(()=>{})}var z2=10*6e4;async function Y2(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>O2){await da(e,null,t,n,"auto-merge expired \u2014 checks never settled within 24h");return}let o=await n.detail(e.repo,e.number).catch(()=>null);if(!o)return;if(o.checks.failed>0){let a=o.checks.failing.map(i=>i.name).join(", ");await da(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await da(e,o,t,n,`conflicts with ${o.baseRefName}`);return}if(!o.checks.total){let a=Math.max(e.autoMerge?.armedAt||0,Date.parse(o.updatedAt||"")||0);if((n.now??Date.now())-a<z2)return;await da(e,o,t,n,o.checks.unavailable?"this token can't read the checks":"no CI checks appeared");return}if(o.checks.pending>0||o.mergeable==="UNKNOWN"||o.mergeStateStatus==="UNKNOWN"||o.isDraft)return;let s=await n.lookup(e.repo,e.number).catch(()=>null);if(s?.autoMerge){if(o.mergeStateStatus==="BEHIND"){try{await n.updateBranch(e.repo,e.number)}catch(a){let i=String(a?.message||a).trim();/no new commits|already up.to.date/i.test(i)||await da(e,o,t,n,i||`couldn't update with ${o.baseRefName}`)}return}try{await n.merge(e.repo,e.number,s.autoMerge.method||"merge")}catch(a){if(/already merged|not open|is closed/i.test(String(a?.message||a)))return;await da(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await q_(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function fa(e,t,n){await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function J2(e,t){try{return await sg("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function Sc(e,t,n,r=()=>!0){return(await F(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var pa=(e,t)=>({number:Number(e.number),url:t?.url||e.url,title:t?.title||e.title,branch:t?.headRefName||e.headRef,repo:e.repo});function W_(e,t,{grace:n=N2}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=P2}async function X2(e,t,n,r){let o=r.now??Date.now();if(!W_(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||Ve(s))return!1;let a=(s.boxes||[]).find(f=>f.name===s.leadBox);return await(r.midTurn??To)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await F(s).catch(()=>[])).some(f=>f.type==="pr.state.changed"&&f.payload?.number===Number(e.number))?(await(r.claim??Ln)(e.repo,e.number).catch(()=>null),!1):await(r.claim??Ln)(e.repo,e.number).catch(()=>null)?(await fa(s,"opened",{...pa(e,t),announcedBy:"watch"}).catch(()=>{}),console.log(`[pr-watch] announced passive link ${e.repo}#${e.number} \u2192 track ${s.id} (no active door claimed it)`),!0):!1}async function Z2(e,t,n,r){let o=r.now??Date.now(),s=t.headRefOid||null,a=n.get(e.trackId)||null;if(s&&(e.ciFix?.headSha&&s!==e.ciFix.headSha&&await Kl(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await Vl(e.repo,e.number,{headSha:s}).catch(()=>{})),s&&s!==e.lastHeadSha){let i=!e.lastHeadSha,c=!!(e.ciFix||e.reconcile||e.ciFixAwait||e.reconcileAwait),l=!!e.baseFoldAt&&o-e.baseFoldAt<M2;await Cx(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await Ox(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await Sc(a,"pushed",e.number,f=>f.payload?.sha===s)&&await fa(a,"pushed",{...pa(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>og)await Gl(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i?.checks){if(i.checks.failed>0)await Gl(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=Tc(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await Sc(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await fa(a,"ci-fixed",{...pa(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await Gl(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>og)await zl(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await zl(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Tc(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await Sc(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await fa(a,"reconciled",{...pa(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await zl(e.repo,e.number).catch(()=>{})}}}}async function Q2(e,t,n,r){let o=Tc(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await Sc(s,"closed",e.number)&&await fa(s,"closed",{...pa(e,t),githubAt:o.githubAt,latencyMs:o.latencyMs,lane:o.lane}).catch(()=>{}),await r.notifyIfResolved(e.repo,e.number,"closed").catch(()=>{}),await r.mark(e.repo,e.number,"closed").catch(()=>{})}async function eH(e,t,n){Tc(n,e,"lost",null);let r=t.get(e.trackId);r&&!await Sc(r,"lost",e.number)&&await fa(r,"lost",pa(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function q_(e,t,n,r,o={}){let s=Tc(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await F(a).catch(()=>[])).some(l=>l.type==="pr.state.changed"&&l.payload?.change==="merged"&&l.payload?.number===Number(e.number))||await r.emitMerged(a,{number:Number(e.number),url:t.url||e.url,title:t.title||e.title,branch:t.headRefName||e.headRef,repo:e.repo,githubAt:s.githubAt,latencyMs:s.latencyMs,lane:s.lane}).catch(()=>{})),await r.notifyIfArmed(e.repo,e.number).catch(()=>{}),await r.followupsIfMerged(e.repo,e.number).catch(()=>{}),await r.archiveIfArmed(e.repo,e.number).catch(()=>{}),await r.mark(e.repo,e.number,"merged").catch(()=>{})}async function tH(e={}){let{now:t=Date.now(),auth:n=Zp,view:r=F2,list:o=U2,links:s=Dx,trackMap:a=H2,emitMerged:i=W2,mark:c=Ir,archiveIfArmed:l=qn,notifyIfArmed:u=Kn,notifyIfResolved:f=Lu,followupsIfMerged:d=Bo,batchThreshold:p=C2,detail:h=q2,merge:w=K2,updateBranch:g=G2,lookup:k=tt,disarm:S=wi,emitDisarmed:E=V2,localHasCommit:R=J2,claim:B=Ln,midTurn:T=To}=e;if(!(await n().catch(()=>null))?.authenticated||Xl()>0)return 0;let O=await s().catch(()=>[]),I=av(O),U=O.filter(W=>t-(kd.get(oe(W.repo,W.number))||0)>=L2(W,t));if(!U.length)return 0;let H=Date.now(),ae=new Map,X=new Map;for(let W of[...U].sort(xi)){let be=H_(W,t);ae.set(oe(W.repo,W.number),{lane:be,intervalMs:U_[be]}),kd.set(oe(W.repo,W.number),t),X.has(W.repo)||X.set(W.repo,[]),X.get(W.repo).push(W)}let C=await a().catch(()=>new Map),Q={now:t,lanes:ae,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:f,followupsIfMerged:d,detail:h,merge:w,updateBranch:g,lookup:k,disarm:S,emitDisarmed:E,localHasCommit:R,claim:B,midTurn:T};for(let[W,be]of X){let se,pe=new Set;if(be.length>p)se=await o(W).catch(()=>null);else{se=new Map;for(let ie of be)try{let L=await r(W,ie.number);L?.number!=null&&se.set(Number(L.number),L)}catch(L){B2(L)&&pe.add(oe(ie.repo,ie.number))}}if(se)for(let ie of be){let L=oe(ie.repo,ie.number),ce=se.get(Number(ie.number));if(!ce){if(pe.has(L)){let ue=(xd.get(L)||0)+1;xd.set(L,ue),ue>=R2&&(await eH(ie,C,Q),xd.delete(L),kd.delete(L))}continue}if(xd.delete(L),ce.state==="MERGED"||ce.state==="CLOSED")ce.state==="MERGED"?await q_(ie,ce,C,Q):await Q2(ie,ce,C,Q),kd.delete(L);else{await X2(ie,ce,C,Q).catch(()=>{}),await Z2(ie,ce,C,Q).catch(()=>{});let ue=!ie.trackId||I.get(ie.trackId)===L;ie.autoMerge&&ue&&await Y2(ie,C,Q).catch(()=>{})}}}let ve={};for(let{lane:W}of ae.values())ve[W]=(ve[W]||0)+1;return console.log(`[pr-watch] probed ${U.length} link(s) (${Object.entries(ve).map(([W,be])=>`${W} ${be}`).join(", ")}) in ${Date.now()-H}ms`),U.length}function K_(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{await tH()}catch{}finally{e=!1}}},L_)}me();Fn();ar();Nr();Bn();function G_(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function nH(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var rH=new Set(["merged","closed","lost"]);function oH(e,t){if(!e?.blocked)return null;let n=G_(t);if(e.blocked==="red")return t.checks.failed===0&&t.checks.total>0?{change:"ci-fixed",reason:"red"}:null;if(e.blocked==="conflict")return t.mergeable==="MERGEABLE"&&n!=="red"?{change:"reconciled",reason:"conflict"}:null;if(e.blocked==="behind"){let r=t.headSha??null;return n===null&&r&&e.sha&&r!==e.sha?{change:"reconciled",reason:"behind"}:null}return null}function sH(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function aH(e,t,n,r,o){return(await F(e).catch(()=>[])).some(a=>{if(a.type!=="pr.state.changed"||a.payload?.number!==Number(n))return!1;let i=a.payload?.change;return i===t?a.payload?.sha&&r?a.payload.sha===r:(a.payload?.ts||0)>=o:i==="pushed"&&!!r&&a.payload?.sha===r})}async function iH(e,t,n){await $({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function V_(e,t={}){let{now:n=Date.now(),slugOf:r=Se,lookup:o=tt,note:s=Mx,tracks:a=async()=>(await le()).filter(f=>!Ve(f)),asked:i=aH,emitChange:c=iH}=t,l=[],u=null;for(let f of e??[]){if(!f?.prs?.length)continue;let d=await r(f.path).catch(()=>null);if(d)for(let p of f.prs)try{if(!nH(p))continue;let h=await o(d,p.number).catch(()=>null);if(!h?.trackId||rH.has(h.state))continue;let{prev:w}=await s(d,p.number,{blocked:G_(p),sha:p.headSha??null,at:n});if(!w)continue;let g=oH(w,p);if(!g||sH(h,g.change))continue;u??=new Map((await a()).map(R=>[R.id,R]));let k=u.get(h.trackId);if(!k)continue;let S=p.headSha??null;if(await i(k,g.change,p.number,S,w.at||0))continue;let E={number:Number(p.number),url:p.url||h.url,title:p.title||h.title,branch:p.headRefName||h.headRef,repo:d,sha:S,delegated:!1,reason:g.reason};g.change==="ci-fixed"?E.passed=p.checks.passed:E.base=p.baseRefName||null,await c(k,g.change,E),l.push({change:g.change,number:p.number,reason:g.reason})}catch{}}return l}lt();me();Nr();Bn();import{randomUUID as cH}from"node:crypto";var lH=2e4,z_=3,ma=new Map,ag=new Set;async function Y_(e,t,n){let r=await n(e).catch(()=>[]),o=null;for(let s of r)s.type==="box.fullscreen.detected"&&s.boxId===t?o=s.payload?.offerId||null:s.type==="box.fullscreen.answered"&&o&&s.payload?.offerId===o&&(o=null);return o}async function uH(e={}){let{sessions:t=null,tracks:n=null,append:r=$,read:o=F,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await zt(),i=n??await le()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(Ve(u)||!u.leadBox)continue;let f=(u.boxes||[]).find(p=>p.name===u.leadBox);if(!f||f.agent!=="claude"||f.state!=="live")continue;let d=c.get(f.name);if(d)if(l.add(f.name),d.alternateOn){let p=(ma.get(f.name)||0)+1;ma.set(f.name,p),p===z_&&(ag.add(f.name),await Y_(u,f.name,o)||await r(u,{type:"box.fullscreen.detected",actor:"system",source:"orchestrator",boxId:f.name,provider:f.agent,payload:{ts:s,offerId:cH(),box:f.name,agent:f.agent}}).catch(()=>{}))}else{let p=(ma.get(f.name)||0)>=z_;if(ma.delete(f.name),p||!ag.has(f.name)){ag.add(f.name);let h=await Y_(u,f.name,o);h&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:f.name,provider:f.agent,payload:{ts:s,offerId:h,action:"cleared"}}).catch(()=>{})}}}for(let u of[...ma.keys()])l.has(u)||ma.delete(u)}var Ec=null,ig=!1;function J_(){return Ec?()=>{}:(Ec=setInterval(()=>{ig||(ig=!0,uH().catch(()=>{}).finally(()=>{ig=!1}))},lH),Ec.unref?.(),()=>{clearInterval(Ec),Ec=null})}bo();qm();me();Bs();Eo();bo();import{randomUUID as dH}from"node:crypto";async function fH(){let e=await Promise.resolve().then(()=>(Nr(),vE));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var cg={listRepoPrs:hn,readEvents:F,appendEvent:$,sayDeps:fH,currentBranch:Cr};async function pH(e,t=cg,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??Cr)(e.workspace?.kind==="multi"?null:e.cwd).catch(()=>null)||e?.workspace?.branch;if(!r)return null;let o;try{o=await t.listRepoPrs(e.cwd,{caller:"pr-exists"})}catch{return null}let s=(o||[]).find(a=>a.headRefName===r);return s?{number:s.number,url:s.url??null,title:s.title??null}:null}async function lg(e,t,{actions:n,notify:r=!1}={},o=cg){let s=t?.payload||{};if(!Array.isArray(n)||!n.includes("pr")||s.toPr||Array.isArray(s.repos)&&s.repos.length||!s.branch)return null;let a=await pH(e,o,{branch:s.branch});if(!a)return null;let i={id:e.id,cwd:e.cwd};await o.appendEvent(i,{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:t.boxId,payload:{ts:Date.now(),offerId:s.offerId,action:"pr-exists",actions:n,...r?{notify:!0}:{},existingPr:{number:a.number}}});let c=dH();return await o.appendEvent(i,{type:"pr.exists.offered",actor:"system",source:"orchestrator",boxId:t.boxId,payload:{ts:Date.now(),offerId:c,srcOfferId:s.offerId??null,branch:s.branch,base:s.base??null,pr:a,actions:n,...r?{notify:!0}:{},offeredRebase:Array.isArray(s.offered)&&s.offered.includes("rebase")}}),{offerId:c,pr:a}}async function ug(e,{offerId:t,choice:n}={},r=cg){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');let o=await r.readEvents(e),s=o.find(u=>u.type==="pr.exists.offered"&&u.payload?.offerId===t);if(!s)throw new Error("unknown offer");if(o.some(u=>u.type==="pr.exists.answered"&&u.payload?.offerId===t))throw new Error("offer already answered");let a=s.payload||{},i=Array.isArray(a.actions)&&a.actions.length?a.actions:["commit","push","pr"],c=null,l=null;if(n==="push"){let{sayToLead:u}=await r.sayDeps();l=Ar.filter(f=>f!=="pr"&&(i.includes(f)||f==="push")),c=await u(e.id,Os(l,{branch:a.branch??null,base:a.base??null,toPr:{number:a.pr?.number??null},offeredRebase:a.offeredRebase===!0}),{kind:"push-go"})}else if(n==="new"){let{sayToLead:u}=await r.sayDeps();l=i,c=await u(e.id,xx(i,{branch:a.branch??null,base:a.base??null,prNumber:a.pr?.number??null,offeredRebase:a.offeredRebase===!0}),{kind:"pr-go"})}if(await r.appendEvent({id:e.id,cwd:e.cwd},{type:"pr.exists.answered",actor:"user",source:"orchestrator",boxId:s.boxId,payload:{ts:Date.now(),offerId:t,choice:n}}),n!=="dismiss"&&a.notify===!0){let{queueShipCompleteNotify:u}=await r.sayDeps();u(e.id,{actions:l})}return{say:c,choice:n}}import rr from"node:fs/promises";import ha from"node:path";import rI from"node:os";import X_ from"node:fs/promises";import vd from"node:path";import{execFile as mH}from"node:child_process";import{promisify as hH}from"node:util";import{fileURLToPath as wH}from"node:url";var gH=hH(mH),Q_=vd.dirname(wH(import.meta.url)),yH=vd.resolve(Q_,"..","..","client","dist"),bH="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",kH=new Map([...bH].map((e,t)=>[e,t]));function xH(e){let t=[],n=0,r=0;for(let o of e){let s=kH.get(o);if(s===void 0)return t;n+=(s&31)<<r,s&32?r+=5:(t.push(n&1?-(n>>>1):n>>>1),n=0,r=0)}return t}function vH(e){let t=[],n=0,r=0,o=0;for(let s of e.split(";")){let a=[],i=0;if(s)for(let c of s.split(",")){let l=xH(c);l.length!==0&&(i+=l[0],l.length>=4&&(n+=l[1],r+=l[2],o+=l[3],a.push([i,n,r,o])))}t.push(a)}return t}function SH(e,t){if(!e||e.length===0||e[0][0]>t)return null;let n=0,r=e.length-1;for(;n<r;){let o=n+r+1>>1;e[o][0]<=t?n=o:r=o-1}return e[n]}var Z_=new Map;async function TH(e){let t;try{t=await X_.stat(e)}catch{return null}let n=Z_.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await X_.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:vH(r.mappings||"")};return Z_.set(e,o),o}catch{return null}}var dg=null;function EH(){return dg||(dg=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):gH("git",["rev-parse","--short","HEAD"],{cwd:vd.resolve(Q_,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),dg}var AH=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function _H(e,{distDir:t=yH}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(AH)){let[a,i,c,l]=s,u=await TH(vd.join(t,"assets",`${i}.map`)),f=u?SH(u.lines[Number(c)-1],Number(l)-1):null;if(n.push(e.slice(r,s.index)),f&&u.sources[f[1]]){let d=u.sources[f[1]].replace(/^(\.\.\/)+/,"");n.push(`${d}:${f[2]+1}:${f[3]+1}`),o=!0}else n.push(a);r=s.index+a.length}return n.push(e.slice(r)),{stack:n.join(""),symbolicated:o}}async function eI(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await EH();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await _H(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var IH=()=>process.env.BOSTRAT_STATE_DIR||ha.join(process.env.HOME||rI.tmpdir(),".bostrat"),Qr=()=>ha.join(IH(),"telemetry"),oI=()=>ha.join(Qr(),".relay-offsets.json"),$H=50,RH=14,OH=3e4,tI=500,jt=(e,t)=>typeof e=="string"?e.slice(0,t):"";function CH(e,t){if(!e||typeof e!="object")return null;let n=jt(e.name,64);if(!n)return null;let r=Number.isFinite(e.ts)?e.ts:t,o={name:n,ts:Math.abs(r-t)<168*3600*1e3?r:t,receivedAt:t,anonId:jt(e.anonId,64),sessionId:jt(e.sessionId,64),userId:jt(e.userId,64),release:jt(e.release,64),appVersion:jt(e.appVersion,32),route:jt(e.route,128),deviceClass:e.deviceClass==="phone"||e.deviceClass==="desktop"?e.deviceClass:""};return e.props&&typeof e.props=="object"&&!Array.isArray(e.props)&&(JSON.stringify(e.props).length<=8192?o.props=e.props:o.props={clamped:!0}),e.error&&typeof e.error=="object"&&(o.error={kind:jt(e.error.kind,256),message:jt(e.error.message,8192),stack:jt(e.error.stack,32768),fingerprint:jt(e.error.fingerprint,64)}),Array.isArray(e.breadcrumbs)&&(o.breadcrumbs=e.breadcrumbs.slice(-50).map(s=>({t:Number.isFinite(s?.t)?s.t:0,n:jt(s?.n,64),r:jt(s?.r,128)}))),o}var sI=e=>new Date(e).toISOString().slice(0,10),nI=0;async function aI(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,$H):[]).map(s=>CH(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await eI(s);await rr.mkdir(Qr(),{recursive:!0});let o=ha.join(Qr(),`${sI(t)}.ndjson`);return await rr.appendFile(o,r.map(s=>JSON.stringify(s)+`
695
+ `).join(""),"utf8"),t-nI>6*3600*1e3&&(nI=t,MH(t).catch(()=>{})),r.length}async function MH(e=Date.now()){let t=sI(e-RH*24*3600*1e3),n=[];try{n=await rr.readdir(Qr())}catch{return}let r=n.filter(s=>s.endsWith(".ndjson")&&s.slice(0,10)<t);if(!r.length)return;for(let s of r)await rr.rm(ha.join(Qr(),s),{force:!0});let o=await cI();for(let s of r)delete o[s];await lI(o)}var Sd=new Map;function iI(e,t=Date.now()){let n=e||"unknown",r=Sd.get(n);return r||(Sd.size>512&&Sd.clear(),r={tokens:40,at:t},Sd.set(n,r)),r.tokens=Math.min(40,r.tokens+(t-r.at)/6e4*20),r.at=t,r.tokens<1?!1:(r.tokens-=1,!0)}async function cI(){try{return JSON.parse(await rr.readFile(oI(),"utf8"))||{}}catch{return{}}}async function lI(e){await rr.mkdir(Qr(),{recursive:!0}),await rr.writeFile(oI(),JSON.stringify(e),"utf8")}function NH(e,{env:t,host:n}={}){let r=e.name==="app.error"&&e.error,o={};for(let[a,i]of[["event",e.name],["route",e.route],["session",e.sessionId],["anon",e.anonId],["user",e.userId],["release",e.release],["appVersion",e.appVersion],["device",e.deviceClass]])i&&(o[a]=i);let s={timestamp:new Date(e.ts).toISOString(),service:"bostrat-client",source:"treetop-js",env:t||process.env.BOSTRAT_ENV||"pi",host:n||rI.hostname(),level:r?"error":"info",message:r?`${e.error.kind||"Error"}: ${e.error.message||"(no message)"}`.slice(0,8192):e.name,tags:o,attributes:{...e.props?{props:e.props}:{},receivedAt:e.receivedAt}};return r&&(s.error={kind:e.error.kind,message:e.error.message,stack:e.error.stack},e.error.fingerprint&&(s.fingerprint=e.error.fingerprint),e.error.symbolicated&&(s.attributes.symbolicated=!0),e.breadcrumbs&&(s.attributes.breadcrumbs=e.breadcrumbs)),s}async function PH({fetchImpl:e=fetch}={}){let t=await zE();if(!t)return{sent:0,disabled:!0};let n;try{n=(await rr.readdir(Qr())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await cI(),o=0;for(let s of n){let a=ha.join(Qr(),s),i=r[s]||0,c;try{let d=await rr.open(a,"r");try{let p=(await d.stat()).size;if(p<=i)continue;c=Buffer.alloc(p-i),await d.read(c,0,c.length,i)}finally{await d.close()}}catch{continue}let l=c.lastIndexOf(10);if(l<0)continue;let u=c.toString("utf8",0,l+1).split(`
696
+ `).filter(Boolean),f=[];for(let d of u)try{f.push(JSON.parse(d))}catch{}for(let d=0;d<f.length;d+=tI){let p=f.slice(d,d+tI).map(w=>NH(w)),h=await e(`${t.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${t.ingestKey}`},body:JSON.stringify({events:p})}).catch(()=>null);if(!h||!h.ok)return{sent:o,disabled:!1};o+=p.length}r[s]=i+l+1,await lI(r)}return{sent:o,disabled:!1}}var fg=null,pg=!1;function uI(){fg||(fg=setInterval(async()=>{if(!pg){pg=!0;try{await PH()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{pg=!1}}},OH),fg.unref?.())}import Ed from"node:fs/promises";import hI from"node:path";import DH from"node:os";var wI=()=>process.env.BOSTRAT_STATE_DIR||hI.join(process.env.HOME||DH.tmpdir(),".bostrat"),gI=()=>hI.join(wI(),"dictation-glossary.json"),BH=100,jH=500,LH=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Ad=null,mg=null,hg=Promise.resolve();function dI(){let e={},t=Date.now();for(let n of LH)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function yI(){return Ad||(mg??=Ed.readFile(gI(),"utf8").then(e=>JSON.parse(e)?.terms??dI()).catch(()=>dI()).then(e=>Ad=e).finally(()=>mg=null),mg)}async function fI(){let e=JSON.stringify({terms:Ad},null,2),t=gI(),n=`${t}.${process.pid}.tmp`;await Ed.mkdir(wI(),{recursive:!0}),await Ed.writeFile(n,e),await Ed.rename(n,t)}function FH(){return hg=hg.then(fI,fI),hg.catch(()=>{})}async function wg(){return Object.values(await yI()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var UH=e=>Math.max(1,Math.ceil(e.length/4));async function HH(){let e=[],t=0;for(let{term:n}of await wg()){let r=UH(n);if(!(t+r>jH)&&(e.push(n),t+=r,e.length>=BH))break}return e}async function WH(e,t){let n=await yI(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var pI=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),Td=e=>e.toLowerCase();function mI(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function bI(e,t){let n=pI(e),r=pI(t);if(!n.length||!r.length)return[];let o=n.length,s=r.length,a=Array.from({length:o+1},()=>new Array(s+1).fill(0));for(let u=o-1;u>=0;u--)for(let f=s-1;f>=0;f--)a[u][f]=Td(n[u])===Td(r[f])?a[u+1][f+1]+1:Math.max(a[u+1][f],a[u][f+1]);let i=new Set,c=0,l=0;for(;c<o&&l<s;)Td(n[c])===Td(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(mI(r[l])&&i.add(r[l]),l++);for(;l<s;l++)mI(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await WH(u,"learned");return await FH(),[...i]}var Ac=null;function qH(e,t){let n=null;try{n=JSON.parse(t)}catch{}let r=n?.err_code||n?.error_code||n?.category||"";return e===402||/PAYMENT_REQUIRED/i.test(r)?{status:402,code:"credits_exhausted",persistent:!0,message:"Deepgram credits are exhausted \u2014 dictation is down until you top up at console.deepgram.com or drop a new key into ~/.bostrat/integrations.json."}:e===401||e===403?{status:502,code:"key_invalid",persistent:!0,message:"Deepgram rejected the API key (revoked, or missing ASR scope) \u2014 replace it in ~/.bostrat/integrations.json."}:{status:502,code:"transcription_failed",persistent:!1,message:`Deepgram error ${e}: ${t.slice(0,300)}`}}async function kI(){if(!Ac)return null;let e=await uc();if(!e||e.apiKey.slice(-6)!==Ac.keyTail)return null;let{keyTail:t,...n}=Ac;return n}async function xI(e,t){let n=await uc();if(!n){let i=new Error("Deepgram is not configured \u2014 add deepgram.apiKey to ~/.bostrat/integrations.json");throw i.status=503,i.code="not_configured",i}let r=new URL("https://api.deepgram.com/v1/listen");r.searchParams.set("model","nova-3"),r.searchParams.set("smart_format","true");for(let i of await HH())r.searchParams.append("keyterm",i);let o=await fetch(r,{method:"POST",headers:{Authorization:`Token ${n.apiKey}`,"Content-Type":t||"application/octet-stream"},body:e});if(!o.ok){let i=await o.text().catch(()=>""),c=qH(o.status,i);c.persistent&&(Ac={code:c.code,message:c.message,at:Date.now(),keyTail:n.apiKey.slice(-6)});let l=new Error(c.message);throw l.status=c.status,l.code=c.code,l}return Ac=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}me();var gg={"gpt-realtime-2.1":{textIn:4,textInCached:.4,textOut:24,audioIn:32,audioInCached:.4,audioOut:64},"gpt-realtime-2":{textIn:4,textInCached:.4,textOut:24,audioIn:32,audioInCached:.4,audioOut:64},"gpt-realtime":{textIn:4,textInCached:.4,textOut:16,audioIn:32,audioInCached:.4,audioOut:64},"gpt-realtime-2.1-mini":{textIn:.6,textInCached:.06,textOut:2.4,audioIn:10,audioInCached:.3,audioOut:20},"gpt-realtime-mini":{textIn:.6,textInCached:.06,textOut:2.4,audioIn:10,audioInCached:.3,audioOut:20}};function KH(e){if(!e)return null;let t=String(e).trim();if(gg[t])return t;let n=null;for(let r of Object.keys(gg))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function GH(e,t={}){let n=gg[KH(e)];if(!n)return 0;let r=0;for(let o of Object.keys(n))r+=(Number(t[o])||0)*n[o];return r/1e6}function VH(e,t){let n=null;try{n=JSON.parse(t)}catch{}let r=n?.error?.code||n?.error?.type||"";return e===429&&/insufficient_quota/i.test(r)?{status:402,code:"credits_exhausted",persistent:!0,message:"The OpenAI account is out of credit \u2014 voice chat is down until you top up at platform.openai.com or drop a new key into ~/.bostrat/integrations.json."}:e===401||e===403?{status:502,code:"key_invalid",persistent:!0,message:"OpenAI rejected the API key (revoked, or missing Realtime access) \u2014 replace it in ~/.bostrat/integrations.json."}:{status:502,code:"mint_failed",persistent:!1,message:`OpenAI realtime session mint failed (${e}): ${t.slice(0,300)}`}}var _c=null;async function zH(){if(!_c)return null;let e=await rd();if(!e||e.apiKey.slice(-6)!==_c.keyTail)return null;let{keyTail:t,...n}=_c;return n}async function YH(e){let t=await fetch("https://api.openai.com/v1/realtime/client_secrets",{method:"POST",headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({session:{type:"realtime",model:e.model,audio:{output:{voice:e.voice}}}})});if(!t.ok){let o=await t.text().catch(()=>""),s=VH(t.status,o);s.persistent&&(_c={code:s.code,message:s.message,at:Date.now(),keyTail:e.apiKey.slice(-6)});let a=new Error(s.message);throw a.status=s.status,a.code=s.code,a}_c=null;let n=await t.json(),r=n?.value??n?.client_secret?.value;if(!r){let o=new Error("OpenAI returned no client secret");throw o.status=502,o.code="mint_failed",o}return{clientSecret:{value:r,expiresAt:n?.expires_at??n?.client_secret?.expires_at??null}}}var JH={openai:YH};async function vI(){let e=await rd();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await zH()}:{configured:!1}}async function SI(){let e=await rd();if(!e){let n=new Error("Voice chat is not configured \u2014 add openai.apiKey to ~/.bostrat/integrations.json");throw n.status=503,n.code="not_configured",n}let t=await JH[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function TI(e,{model:t,usage:n={},seconds:r}={}){let o=c=>Math.max(0,Math.round(Number(c)||0)),s={textIn:o(n.textIn),textInCached:o(n.textInCached),textOut:o(n.textOut),audioIn:o(n.audioIn),audioInCached:o(n.audioInCached),audioOut:o(n.audioOut)},a=GH(t,s),i=await $(e,{type:"cost.recorded",actor:"user",provider:"openai-realtime",payload:{model:t||"unknown",usd:a,tokens:{input:s.textIn+s.audioIn,output:s.textOut+s.audioOut,cacheRead:s.textInCached+s.audioInCached,cacheWrite:0},voice:s,seconds:Math.max(0,Math.round(Number(r)||0)),source:"voice-chat"}});return{usd:a,seq:i.seq}}Bn();var OI=xe.dirname(ZH(import.meta.url)),EI=Number(process.env.PORT)||3362,Id=fw(process.env),CI=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,wa=s_(process.env.BOSTRAT_ALLOW_IPS),vg=a_(process.env.BOSTRAT_VIEW_FRONT_CIDRS,bd),MI=c_(),NI=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",v=Gt();v.disable("x-powered-by");v.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),yd(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});v.use((e,t,n)=>{if(vc(e)||wa.allowed(wa.clientIp(e))||vg.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});v.use(p_);v.use(d_({token:MI,enforce:NI}));v.use("/api/mocks",Gt.json({limit:"1mb"}));v.use("/api/mocks",Gt.raw({type:"image/png",limit:"24mb"}));v.use("/api/mocks",Gt.raw({type:["video/mp4","video/webm"],limit:"105mb"}));v.use("/api/runbooks",Gt.json({limit:"1mb"}));v.use("/api/tracks/adopt",Gt.json({limit:"1mb"}));v.use("/api/telemetry",Gt.json({limit:"256kb"}));v.use("/api/hook",Gt.json({limit:"2mb"}));v.use("/api/dictation",Gt.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));v.use("/api/tracks/:id/upload",Gt.raw({type:()=>!0,limit:"25mb"}));v.use(Gt.json({limit:"64kb"}));v.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:$t,hostTmuxAlive:await fr(),autoTriggerPct:CI,plane:ga?ga.status():null})});v.get("/api/sessions",async(e,t)=>{t.json({sessions:await zt()})});v.post("/api/sessions",async(e,t)=>{let{displayName:n,cwd:r}=e.body||{};if(typeof n!="string")return t.status(400).json({error:"displayName (string) required"});try{let o=await pr(n,r||void 0);t.json({ok:!0,...o})}catch(o){let s=o?.message||String(o),a=/already exists/i.test(s)?409:/must be|invalid/i.test(s)?400:500;t.status(a).json({error:s})}});v.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!Pe(n))return t.status(400).json({error:"invalid session name"});if(!await ge(n))return t.status(404).json({error:"session not found"});try{await Yt(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});v.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!Pe(n))return t.status(400).json({error:"invalid session name"});let r=await ge(n);if(!r)return t.status(404).json({error:"session not found"});let o=await Ka(r.cwd,r.sessionId);if(!o)return t.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});t.json({available:!0,...o})});v.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!Pe(n))return t.status(400).json({error:"invalid session name"});try{let r=await Bk(n);t.json({ok:!0,step:r.step,file:r.file,startedAt:r.startedAt})}catch(r){t.status(409).json({error:r?.message||String(r)})}});v.get("/api/handoff/:name",(e,t)=>{let n=decodeURIComponent(e.params.name),r=Il(n);if(!r)return t.json({running:!1});t.json({running:!r.finishedAt,step:r.step,error:r.error,file:r.file,startedAt:r.startedAt,finishedAt:r.finishedAt})});var AI=10;v.get("/api/idle-guard",async(e,t)=>{try{t.json(dw({tracks:await le(),views:await ku(),queuedOf:n=>Mo(n)}))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var Kt=Lo(),rW=DE({kind:Kt}),Ic=null,kt=()=>Ic&&["auto","prompt","off"].includes(Ic)?Ic:rW,xg=null,oW=cc.has(Kt),PI=async({to:e,from:t})=>!oW||Ju(await lc())?!1:($c.arm({to:e,from:t,kind:Kt}),!0);async function sW(e){let t=kt();Ic=e??null;let n=kt();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){$c.cancel();return}xg&&await PI(xg)}}var DI=(()=>{try{return nW(import.meta.url)("../package.json").version||null}catch{return null}})(),$c=jE({isBusy:async()=>dw({tracks:await le(),views:await ku(),queuedOf:e=>Mo(e)}).busy,onStuck:({to:e,from:t})=>An({current:t,latest:e,installKind:Kt,policy:kt(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?An({current:t,latest:e,installKind:Kt,policy:kt(),status:"updating",reason:"auto"}):An({current:t,latest:e,installKind:Kt,policy:kt(),status:"failed",error:n?.reason})).catch(()=>{})});v.get("/api/node/self-update",async(e,t)=>{t.json({installKind:Kt,policy:kt(),policySource:Ic?"plane":"node",current:DI,status:await lc(),armed:$c.armed})});v.post("/api/node/self-update",async(e,t)=>{let n=typeof e.body?.to=="string"?e.body.to.trim():"";if(!/^\d+\.\d+\.\d+$/.test(n))return t.status(400).json({error:"body.to must be a release version (X.Y.Z)"});let r=await Xu({to:n,kind:Kt,reason:"manual"});if(r.ok)return $c.cancel(),An({current:r.from,latest:n,installKind:Kt,policy:kt(),status:"updating",reason:"manual"}).catch(()=>{}),t.json({ok:!0,...r});t.status(409).json({ok:!1,error:r.reason,status:r.status??null})});async function BI(){try{let e=await BE();e&&await An({current:e.from,latest:e.to,installKind:e.kind||Kt,policy:kt(),status:e.status,error:e.error,reason:e.reason}),await Rh({current:DI,installKind:Kt,policy:kt()})}catch{}}BI();setInterval(BI,3e4).unref();v.get("/api/tracks",async(e,t)=>{let n=(await le()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>AI){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,AI).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:Xi,agentAvailability:await Mu(),tickets:await cA()})});v.get("/api/cost",async(e,t)=>{try{let n=await le();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await Vw(n);if(r.cursorUsage=Tm(),e.query.format==="text")return t.type("text/plain").send(BA(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/usage/roundup",async(e,t)=>{try{t.json(await FA(await le(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/usage/spend",async(e,t)=>{try{let n=await KA(await le(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=Tm(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=fi(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/usage/caps",(e,t)=>{t.json(fi())});v.post("/api/usage/caps",async(e,t)=>{try{t.json(await Ll(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});v.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await e_(await le(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await Dg(e.get(Rn),{byToken:Qi,legacy:()=>Ii(e.body?.session_id,e.body?.cwd)});if(n==="refused")return Sa("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Sa("legacy-denied",{reason:"tokenless-denied",hook:e.body?.hook_event_name}),t.status(401).json({ok:!1,error:"tokenless hook ingest is disabled (BOSTRAT_HOOK_LEGACY_DENY)"});n==="token"&&e.body?.session_id&&r.box?.sessionId&&e.body.session_id!==r.box.sessionId&&Sa("mismatch",{track:r.track.id,box:r.box.name}),Sa(n,{track:r?.track?.id,hook:e.body?.hook_event_name,...n==="legacy"?{reason:"tokenless-body-resolved",deny_with:"BOSTRAT_HOOK_LEGACY_DENY=1"}:{}});let o=await RA(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&zc(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});v.get("/api/git/trailers",async(e,t)=>{t.type("text/plain");try{let n=await Qi(e.get(Rn));if(!n?.track||!n?.box)return t.status(204).end();t.send((await CA(n.track,n.box)).join(`
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
698
+ `)}catch{t.status(204).end()}});v.post("/api/git/committed",async(e,t)=>{try{let n=await Qi(e.get(Rn));if(!n?.track||!n?.box)return t.json({ok:!1,error:"unknown hook token"});let r=String(e.body?.sha||"").trim();if(!/^[0-9a-f]{7,40}$/i.test(r))return t.json({ok:!1,error:"sha required"});t.json({ok:!0});let o=n.box.cwd?xe.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?xe.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+xe.sep))?s:o;MA(n.track,n.box,r,{cwd:a}).catch(i=>console.warn(`[rework] ${n.track.id}: recordCommit failed: ${i?.message||i}`))}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});v.post("/api/tracks/:id/rework-cause",async(e,t)=>{try{let n=await te(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let{sha:r,cause:o}=e.body||{};t.json({ok:!0,event:await NA(n,String(r||""),String(o||""))})}catch(n){let r=n?.message||String(n);t.status(/unknown rework/i.test(r)?404:/already answered/i.test(r)?409:400).json({error:r})}});v.get("/api/usage/rework",async(e,t)=>{try{t.json(await GA(await le(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/telemetry",async(e,t)=>{try{if(!iI(wa.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await aI(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});v.get("/api/repos",async(e,t)=>{try{let n=await On(),r=new Set((await Promise.all(n.map(a=>Se(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await _a()).repos||[]).filter(a=>!r.has(String(a.slug).toLowerCase())).map(a=>({slug:a.slug,name:a.slug.split("/")[1],branch:a.defaultBranch||null,private:!!a.private,remote:!0}));t.json({repos:[...n,...s]})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/github/token",async(e,t)=>{try{t.json(await Lc(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});v.get("/api/github/status",(e,t)=>{t.json({configured:jc(),calls:Gx(),latency:Jx()})});v.post("/api/github/refresh",(e,t)=>{Gg(),t.json({ok:!0})});v.get("/api/gmail/search",async(e,t)=>{try{let n=await n_(String(e.query.q||""),{max:Number(e.query.max)||10});t.json({messages:n})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});v.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await r_(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});function Sg(e,t,n){let r=e.workspace;return r?.kind==="multi"?(r.repos??[]).some(o=>t&&o?.base===t||n&&o?.repo===n):!r?.base||!t||r.base===t||n&&r.repo===n}async function $d({repo:e=null,number:t=null,branch:n=null}){let r=e?await Se(e):null;if(r&&t!=null){let s=await tt(r,t),a=s&&await te(s.trackId);if(a)return a}if(!n)return null;let o=await le();return au(o,n,s=>Sg(s,e,r))}async function jI({repo:e=null,number:t=null,branch:n=null}){let r=await $d({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!Ve(r))return r;if(!n)return null;let o=e?await Se(e).catch(()=>null):null,s=await le();return au(s,n,a=>!Ve(a)&&Sg(a,e,o))}async function cn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await $d({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await Se(s).catch(()=>null):null);await $({id:c.id,cwd:c.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),change:e,number:t,url:n,title:r,branch:o??c.workspace?.branch??null,...l?{repo:l}:{},...i}}).catch(()=>{})}async function aW(e){let t=(await le()).filter(n=>!Ve(n));for(let n of e??[]){if(!n.prs?.length)continue;let r=await Se(n.path);if(r)for(let o of n.prs){if(await tt(r,o.number))continue;let s=await au(t,o.headRefName,a=>Sg(a,n.path,r));s&&await Ot({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}v.get("/api/git/prs",async(e,t)=>{try{let n=await rv();await aW(n.repos).catch(()=>{}),await V_(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/git/prs/merge",async(e,t)=>{let{repo:n,number:r,method:o,auto:s,update:a,archive:i,notify:c,headRefName:l,title:u,url:f}=e.body||{};try{if(s){let w=o||"merge";if(!bi.has(w))throw new Error(`invalid merge method: ${w}`);let g=Number(r);if(!Number.isInteger(g)||g<=0)throw new Error("invalid PR number");let k=await Se((await Wn(n)).path);if(!k)throw new Error("repo has no GitHub remote");let S=await $d({repo:n,number:g,branch:l}).catch(()=>null);if(!S)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(a&&await ki(n,g),await Ot({repo:k,number:g,trackId:S.id,url:f,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await mi(k,g,{merge:{method:w}}))throw new Error("couldn't record the auto-merge arm");return await ko(k,g,i===!0),await hi(k,g,c===!0&&i!==!0),gn(),await cn("auto-armed",{number:g,url:f,title:u,branch:l,repo:n,track:S,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:g,auto:!0})}let d=await Ds(n,r,{method:o||"squash"});await cn("merged",{number:d.number,url:f,title:u,branch:l,repo:n});let p=await Se(n).catch(()=>null),h=!1;if(p&&(i===!0&&await ko(p,d.number,!0).catch(()=>{}),c===!0&&i!==!0&&await hi(p,d.number,!0).catch(()=>{}),await Kn(p,d.number).catch(()=>{}),await Bo(p,d.number).catch(()=>{}),h=await qn(p,d.number).catch(()=>!1),await Ir(p,d.number,"merged").catch(()=>{})),i===!0&&!h){let w=await $d({repo:n,number:d.number,branch:l}).catch(()=>null);w&&!w.archivedAt&&await Do(w.id).catch(()=>{})}t.json(d)}catch(d){let p=d?.message||String(d),h=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(p)?400:502;t.status(h).json({error:p})}});v.post("/api/git/prs/disarm-auto",async(e,t)=>{let{repo:n,number:r,headRefName:o,title:s,url:a}=e.body||{};try{let i=Number(r);if(!Number.isInteger(i)||i<=0)throw new Error("invalid PR number");let c=await Se((await Wn(n)).path).catch(()=>null),l=c?await wi(c,i).catch(()=>null):null;try{await tm(n,i)}catch(u){if(!l)throw u}gn(),await cn("auto-canceled",{number:i,url:a,title:s,branch:o,repo:n}),t.json({ok:!0,number:i})}catch(i){let c=i?.message||String(i),l=/invalid|unknown repo|required/i.test(c)?400:502;t.status(l).json({error:c})}});v.post("/api/git/prs/merge-all",async(e,t)=>{let{repo:n,method:r}=e.body||{};try{let o=await Se(n).catch(()=>null),s=await cv(n,{method:r||"merge",onMerged:a=>{cn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&Kn(o,a.number).catch(()=>{}).then(()=>Bo(o,a.number)).catch(()=>{}).then(()=>qn(o,a.number)).catch(()=>{}).then(()=>Ir(o,a.number,"merged")).catch(()=>{})}});t.json(s)}catch(o){let s=o?.message||String(o),a=/already running/i.test(s)?409:/invalid|unknown repo|no PRs ready/i.test(s)?400:502;t.status(a).json({error:s})}});v.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:iv()})});v.post("/api/git/prs/merge-track",async(e,t)=>{let{trackId:n,update:r,archive:o,notify:s,method:a}=e.body||{};try{let i=a||"merge";if(!bi.has(i))throw new Error(`invalid merge method: ${i}`);if(!n)return t.status(400).json({error:"trackId required"});let c=await te(n);if(!c)return t.status(404).json({error:`Track ${n} isn't on this node`});let l=(await xo()).filter(d=>d.trackId===c.id&&d.state!=="merged"&&d.state!=="closed").sort(xi);if(!l.length)return t.status(409).json({error:"no open PRs on this Track"});for(let d of l)await ko(d.repo,d.number,o===!0).catch(()=>{}),await hi(d.repo,d.number,s===!0&&o!==!0).catch(()=>{});let u=[],f=[];for(let d of l){let p={repo:d.repo,number:d.number,ok:!0,action:"armed"};u.push(p);try{let h=await So(d.repo);if(!h)throw new Error(`no local checkout for ${d.repo}`);let w=await Ps(h,d.number);f.push({r:p,l:d,repoPath:h,pr:w,plan:ov(w,{update:r!==!1})})}catch(h){p.ok=!1,p.action="failed",p.reason=h?.message||String(h)}}for(let{r:d,l:p,repoPath:h,pr:w,plan:g}of sv(f))try{if(g.action==="skip")d.action="skipped",d.reason=g.reason;else if(g.action==="merge")await Ds(h,p.number,{method:i}),await cn("merged",{number:p.number,url:w.url,title:w.title,branch:w.headRefName,repo:h,track:c}),await Kn(p.repo,p.number).catch(()=>{}),await Bo(p.repo,p.number).catch(()=>{}),await qn(p.repo,p.number).catch(()=>{}),await Ir(p.repo,p.number,"merged").catch(()=>{}),d.action="merged";else{if(g.action==="update-arm"&&(await ki(h,p.number).catch(()=>{}),d.action="updated-armed"),!await mi(p.repo,p.number,{merge:{method:i}}))throw new Error("couldn't record the auto-merge arm");await cn("auto-armed",{number:p.number,url:w.url,title:w.title,branch:w.headRefName,repo:h,track:c,...d.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(k){d.ok=!1,d.action="failed",d.reason=k?.message||String(k)}if(gn(),!u.some(d=>d.ok)){if(o===!0)for(let d of l)await ko(d.repo,d.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let d of l)await hi(d.repo,d.number,!1).catch(()=>{});return t.status(502).json({error:u.map(d=>`${d.repo}#${d.number}: ${d.reason}`).join("; "),results:u})}t.json({ok:!0,trackId:c.id,results:u})}catch(i){let c=i?.message||String(i),l=/invalid|required/i.test(c)?400:502;t.status(l).json({error:c})}});v.post("/api/git/prs/disarm-track",async(e,t)=>{let{trackId:n}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let r=await te(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await xo()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await wi(a.repo,a.number).catch(()=>null),c=await So(a.repo).catch(()=>null);c&&await tm(c,a.number).catch(()=>{}),i&&(await cn("auto-canceled",{number:a.number,url:a.url,title:a.title,branch:a.headRef,repo:c,track:r}),s.push({repo:a.repo,number:a.number}))}gn(),t.json({ok:!0,trackId:r.id,canceled:s})}catch(r){let o=r?.message||String(r),s=/invalid|required/i.test(o)?400:502;t.status(s).json({error:o})}});v.post("/api/git/prs/open",async(e,t)=>{let{trackId:n,title:r,body:o,base:s,repos:a}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let i=await te(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=Dt(i.workspace),f,d=Array.isArray(a)?a.filter(Boolean):[];if(d.length)f=d.map(w=>{let g=u.find(k=>k.name===w||k.repo===w||k.base===w||k.dir===w);if(!g)throw new Error(`invalid repo "${w}" \u2014 not tagged on this Track`);return g});else if(f=await _o(i),!f.length)return t.status(409).json({error:"no tagged repo has work to ship"});let p=[];for(let w of f)try{let g=await rm(w.dir,{title:r,body:o,base:s}),k=w.repo||await Se(w.dir).catch(()=>null);k&&g.number&&await Ot({repo:k,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await cn("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:k??w.name}}),p.push({repo:w.name,slug:k??null,ok:!0,url:g.url,number:g.number})}catch(g){p.push({repo:w.name,slug:w.repo??null,ok:!1,error:g?.message||String(g)})}let h=p.filter(w=>w.ok);return h.length?t.json({ok:!0,multi:!0,results:p,url:h[0].url,number:h[0].number}):t.status(502).json({error:p.map(w=>`${w.repo}: ${w.error}`).join("; "),results:p})}let c=await rm(i.cwd,{title:r,body:o,base:s}),l=await Se(i.cwd).catch(()=>null);l&&c.number&&await Ot({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await cn("opened",{number:c.number,url:c.url,title:r,track:i,branch:i.workspace?.branch,extra:{...l?{repo:l}:{}}}),t.json(c)}catch(i){let c=i?.message||String(i),l=/required|invalid/i.test(c)?400:502;t.status(l).json({error:c})}});v.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await te(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await _o(n),o=new Map(r.map(a=>[a.base,a])),s=Dt(n.workspace).map(a=>{let i=o.get(a.base);return{name:a.name,base:a.base,baseRef:a.baseRef??null,repo:a.repo??null,dirty:i?.dirty??!1,ahead:i?.ahead??0,changed:!!i}});t.json({repos:s,branch:n.workspace?.branch??null,kind:n.workspace?.kind??null})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/tracks/:id/repos",async(e,t)=>{let{repo:n}=e.body||{};try{if(!n||typeof n!="string")return t.status(400).json({error:"repo (path or owner/name) required"});let r=await Uh(e.params.id,n);t.json({ok:!0,added:{name:r.name,base:r.base,baseRef:r.baseRef??null,repo:r.repo??null}})}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/already tagged|needs a multi|not a usable|archived|required/i.test(o)?400:502;t.status(s).json({error:o})}});v.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await Hh(e.params.id,e.params.name);t.json({ok:!0,...n})}catch(n){let r=n?.message||String(n),o=/track .* not found/i.test(r)?404:/has work|still running|last repo/i.test(r)?409:/needs a multi|not tagged/i.test(r)?400:502;t.status(o).json({error:r})}});v.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Ps(n,r),s=await Se(n).catch(()=>null),a=await jI({repo:n,number:r,branch:o.headRefName});if(!a)return t.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=Dt(a.workspace).find(k=>k.base===n||s&&k.repo===s)??null,c=a.workspace?.kind==="multi",l=await lv(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?xe.join("ci",i.name):"ci",f=xe.join(a.cwd,".bostrat",u),d=xe.join(".bostrat",u,`pr-${o.number}-fail.log`);await mt.promises.mkdir(f,{recursive:!0}),await mt.promises.writeFile(xe.join(a.cwd,d),l.map(k=>`\u2550\u2550\u2550\u2550 ${k.name}${k.link?` \xB7 ${k.link}`:""} \u2550\u2550\u2550\u2550
699
699
  ${k.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(k=>k.name).join(", "),h=c&&i?` in the ${i.name}/ checkout`:"",w=await Pt(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${h}. Failing check${l.length===1?"":"s"}: ${p}. The failure log is at ${d} in this ${c?"workspace":"worktree"} \u2014 read it, fix the root cause${c&&i?` in ${i.name}/`:""}, run the relevant tests locally, then commit and push to update the PR.`,{kind:"ci-fix"}),g=s;g&&(await Ot({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await Ix(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await cn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(k=>k.name)}}),t.json({ok:!0,leadBox:w.leadBox,queued:!!w.queued,checks:l.map(k=>k.name),log:d})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});v.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Ps(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await Se(n).catch(()=>null),a=await jI({repo:n,number:r,branch:o.headRefName});if(!a)return t.status(404).json({error:`no active Track owns PR #${o.number} (branch "${o.headRefName}")`});let i=Dt(a.workspace).find(f=>f.base===n||s&&f.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await Pt(a.id,`PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName} \u2014 has merge conflicts with ${o.baseRefName}.${c} Bring ${o.baseRefName} into this branch (fetch origin, then merge origin/${o.baseRefName} \u2014 don't rebase this pushed PR branch), and resolve every conflict so that BOTH sides' intent is preserved. Run the relevant tests, then commit and push to update the PR. If any conflict is a genuine ambiguity \u2014 where you can't confidently tell which side's behavior should win, or reconciling would drop work from either side \u2014 STOP and ask me here rather than guessing, laying out the specific choice and your recommendation.`,{kind:"reconcile"}),u=s;u&&(await Ot({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await $x(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await cn("reconcile-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{base:o.baseRefName}}),t.json({ok:!0,leadBox:l.leadBox,queued:!!l.queued,base:o.baseRefName})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});v.post("/api/tracks/:id/pr-offer",async(e,t)=>{let{offerId:n,action:r}=e.body||{};try{let o=null;if(Array.isArray(e.body?.actions)){if(o=Ar.filter(f=>e.body.actions.includes(f)),!o.length)return t.status(400).json({error:"actions must include commit, rebase, push and/or pr"})}else if(r==="pr")o=["commit","push","pr"];else if(r==="push")o=["commit","push"];else if(r!=="dismiss")return t.status(400).json({error:'offerId and actions ["commit"|"rebase"|"push"|"pr"] (or action "dismiss") required'});if(!n)return t.status(400).json({error:"offerId required"});let s=o!=null&&e.body?.notify===!0,a=await te(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await F(a),c=i.find(f=>f.type==="pr.offered"&&f.payload?.offerId===n);if(!c)return t.status(404).json({error:"unknown offer"});if(i.some(f=>f.type==="pr.offer.answered"&&f.payload?.offerId===n))return t.status(409).json({error:"offer already answered"});if(o?.includes("pr")){let f=await lg(a,c,{actions:o,notify:s});if(f)return t.json({ok:!0,offerId:n,action:"pr-exists",actions:o,notify:s,existingPr:f.pr})}let l=null;o&&(l=await Pt(a.id,Os(o,{branch:c.payload.branch,base:c.payload.base,toPr:c.payload.toPr||null,repos:c.payload.repos||null,offeredRebase:Array.isArray(c.payload.offered)&&c.payload.offered.includes("rebase")}),{kind:o.includes("pr")?"pr-go":"push-go"}));let u=o?o.includes("pr")?"pr":o.includes("push")?"push":o.includes("commit")?"commit":"rebase":"dismiss";await $({id:a.id,cwd:a.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:c.boxId,payload:{ts:Date.now(),offerId:n,action:u,actions:o,...s?{notify:!0}:{}}}),s&&Dh(a.id,{actions:o}),t.json({ok:!0,offerId:n,action:u,actions:o,notify:s,queued:!!l?.queued})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});v.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await te(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await ug(o,{offerId:n,choice:r});t.json({ok:!0,offerId:n,choice:r,queued:!!s?.queued})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/unknown offer/i.test(s)?404:/already answered|not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});var Rc=e=>t=>({...t,url:h_(t,e.headers)});v.get("/api/views",async(e,t)=>{try{let n=await ku({trackId:e.query.track||void 0});t.json({views:n.map(Rc(e)),maxLive:Br})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/views/:id",async(e,t)=>{let n=await $S(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:Rc(e)(n),session:Hs(n.slug)})});v.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await te(n):null;if(!i&&s&&(i=(await le()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+xe.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await Hm({trackId:i.id,name:r,cmd:o,cwd:i.cwd,serveCwd:s,port:a,box:i.leadBox,branch:i.workspace?.branch??null});t.json({ok:!0,view:Rc(e)(c)})}catch(i){let c=i?.message||String(i),l=i?.status??(/cap reached/i.test(c)?409:/required|invalid|already owned|no free/i.test(c)?400:500);t.status(l).json({error:c})}});v.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:Rc(e)(await RS(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});v.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:Rc(e)(await OS(e.params.id))})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/cap reached|no known command/i.test(r)?409:500;t.status(o).json({error:r})}});v.delete("/api/views/:id",async(e,t)=>{try{t.json(await CS(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var iW=[["linear",Fo,Sw],["jira",nd,xw]],yg=new Map;v.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await kw(),r={};for(let[o,s,a]of iW){let i=await s();if(!i){yg.delete(o),r[o]={configured:!1};continue}let c=yg.get(o);if(!c||Date.now()-c.at>300*1e3){let l;try{l={configured:!0,ok:!0,...await a(i)}}catch(u){l={configured:!0,ok:!1,error:u?.message||String(u)}}c={at:Date.now(),body:l},yg.set(o,c)}r[o]={...c.body,flow:n},o==="jira"&&i.tokenExpiresAt&&(r[o].tokenExpiresAt=i.tokenExpiresAt)}t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await kw()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await VE(o),i=n?await te(n):null;!i&&r&&(i=(await le()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+xe.sep)))||null),i&&await $({id:i.id,cwd:i.cwd},{type:"ticket.flow.changed",actor:s==="user"?"user":"agent",source:"orchestrator",payload:{ts:Date.now(),set:{...o},flow:a}}).catch(()=>{}),t.json({ok:!0,flow:a})}catch(a){let i=a?.message||String(a);t.status(/unknown|nothing to set/i.test(i)?400:500).json({error:i})}});var Vo=async(e,t)=>{let n=e?await te(e):null;return!n&&t&&(n=(await le()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+xe.sep)))||null),n};v.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await hw()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});v.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await Vo(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (circuit name or id) required"});let a=await oa(o);await Zu(s,a,{source:"chat"}),t.json({ok:!0,trackId:s.id,circuit:a})}catch(s){let a=s?.message||String(s);t.status(/required|no circuit|names \d|no plane/i.test(a)?400:502).json({error:a})}});v.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await Vo(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await Zu(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var LI=async(e,t,n)=>{if(e)return{ref:e,track:await Vo(t,n)};let r=await Vo(t,n),o=r?await gw(r.id):null;if(!o)throw new Error(r?"this Track isn't in a circuit \u2014 pass --circuit <name-or-id> (or link one first: bostrat-circuit link \u2026)":"run from inside a Track workspace, or pass --circuit <name-or-id>");return{ref:o,track:r}};v.post("/api/blueprints/publish",async(e,t)=>{let{trackId:n,cwd:r,circuit:o,newCircuit:s,name:a,markdown:i}=e.body||{};try{if(!i||!String(i).trim())return t.status(400).json({error:"markdown required"});let{ref:c}=s?{ref:null}:await LI(o,n,r),l=await LE({circuitRef:c,newCircuitName:s,name:a,markdown:i});t.json({ok:!0,...l})}catch(c){let l=c?.message||String(c);t.status(/required|no circuit|names \d|no plane|isn't in a circuit|run from inside/i.test(l)?400:502).json({error:l})}});v.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await LI(e.query.circuit,e.query.track,e.query.cwd);t.json(await ww(n))}catch(n){let r=n?.message||String(n);t.status(/no blueprint|no circuit|isn't in a circuit|run from inside|names \d/i.test(r)?404:502).json({error:r})}});v.post("/api/decisions/record",async(e,t)=>{let{trackId:n,cwd:r,title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l}=e.body||{};try{let u=await Vo(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let f=await HE(u,{title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l});t.json({ok:!0,trackId:u.id,...f})}catch(u){let f=u?.message||String(u);t.status(/required/i.test(f)?400:502).json({error:f})}});v.get("/api/decisions",async(e,t)=>{try{let n=await Vo(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await WE(n.id))}catch(n){let r=n?.message||String(n);t.status(/no plane|required|run from inside/i.test(r)?400:502).json({error:r})}});v.post("/api/blueprints/tag",async(e,t)=>{let{trackId:n,cwd:r,itemIds:o}=e.body||{};try{let s=Array.isArray(o)?o.map(String):[];if(!s.length)return t.status(400).json({error:"itemIds required (BP-\u2026 ids)"});let a=await Vo(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await gw(a.id);if(!i)return t.status(400).json({error:"this Track isn't in a circuit \u2014 link one first (bostrat-circuit link \u2026)"});let c=await FE(a,i,s);t.json({ok:!0,trackId:a.id,...c})}catch(s){let a=s?.message||String(s);t.status(/unknown\/unbindable|required|no blueprint|isn't in a circuit/i.test(a)?400:502).json({error:a})}});v.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await te(n):null;if(!s&&r&&(s=(await le()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+xe.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (issue URL or key) required"});let a=await ia(s,o,{source:n?"api":"cli"});t.json({ok:!0,trackId:s.id,ticket:a})}catch(s){let a=s?.message||String(s);t.status(/not a Linear|not found|no ticketing|required/i.test(a)?400:502).json({error:a})}});v.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await te(r):null;if(!o&&n&&(o=(await le()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+xe.sep)))||null),!o)return t.status(400).json({error:"track (or a cwd inside a Track workspace) required"});t.json({trackId:o.id,configured:await lA(),ticket:await In(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});v.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await In(e.params.id)})});v.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await te(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await ia(n,(e.body||{}).ref,{source:"api"});t.json({ok:!0,ticket:r})}catch(n){let r=n?.message||String(n);t.status(/not a Linear|not found|no ticketing|required/i.test(r)?400:502).json({error:r})}});v.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await Pw(e.params.id)})});var Rd=e=>/no ticket linked|unknown offer|unknown state/i.test(e)?404:/already answered/i.test(e)?409:/required|no ticketing/i.test(e)?400:502;v.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await pA(e.params.id))}catch(n){let r=n?.message||String(n);t.status(Rd(r)).json({error:r})}});v.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await Dw(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(Rd(r)).json({error:r})}});v.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await mA(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(Rd(r)).json({error:r})}});v.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await te(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await hA(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(Rd(s)).json({error:s})}});v.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{t.json(await Zh(e.params.id,n,r===!0))}catch(o){let s=o?.message||String(o),a=/not found|unknown offer/.test(s)?404:/already answered/.test(s)||/mid-turn/.test(s)?409:500;t.status(a).json({error:s})}});v.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await te(n):null;if(!s&&r&&(s=(await le()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+xe.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await gA(s,o)})}catch(s){let a=s?.message||String(s);t.status(/no ticketing|are off|needs an epic|too many|required/i.test(a)?400:502).json({error:a})}});v.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await wA()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});v.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await te(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await yA(s,n,r===!0,{teamId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal|unknown team/i.test(a)?404:/already answered/i.test(a)?409:/required|no ticketing|pick one/i.test(a)?400:502).json({error:a})}});v.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await Bi({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/mocks/:id",async(e,t)=>{let n=await Yn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var Oc={dotfiles:"allow"};v.get("/api/mocks/:id/png",async(e,t)=>{let n=await Yn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=tn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Pi(n,r,"png");if(!o)return t.status(404).json({error:"no image for this version (poster extraction failed)"});t.set("cache-control","private, max-age=31536000, immutable"),t.sendFile(o,Oc,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});v.get("/api/mocks/:id/media",async(e,t)=>{let n=await Yn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=tn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Pi(n,r,"video");if(!o)return t.status(404).json({error:"this version has no video (image or html sourced)"});t.set("cache-control","private, max-age=31536000, immutable"),t.sendFile(o,Oc,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});v.get("/api/mocks/:id/html",async(e,t)=>{let n=await Yn(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=tn(n,e.query.v??null);if(!r?.htmlRel)return t.status(404).json({error:"this version has no HTML source (image-sourced)"});t.set("content-security-policy","sandbox"),t.sendFile(Wt(n,r.v).html,Oc,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});v.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Tu(n)?n:null,o=n&&!r?n:null,s=n?e.query:e.body||{},{trackId:a,name:i,cwd:c,width:l,group:u}=s;try{let f=a?await te(a):null;if(!f&&c&&(f=(await le()).find(w=>w.cwd&&(c===w.cwd||c.startsWith(w.cwd+xe.sep)))||null),!f)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=(f.boxes||[]).find(h=>h.name===f.leadBox),p=await YS({trackId:f.id,name:i,html:n?null:s.html,image:r,video:o,cwd:f.cwd,width:l,group:u,box:f.leadBox,agent:d?.agent||null});t.json({ok:!0,mock:p})}catch(f){let d=f?.message||String(f);t.status(/required|invalid|must be/i.test(d)?400:500).json({error:d})}});v.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Tu(n)?n:null;try{let o=await JS(e.params.id,{html:n?null:(e.body||{}).html,image:r,video:n&&!r?n:null,width:n?e.query.width:(e.body||{}).width});t.json({ok:!0,mock:o})}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required|invalid|must be/i.test(s)?400:500;t.status(a).json({error:s})}});v.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await QS(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await Pt(n.trackId,`Design decision: go with "${n.name}" (mock:${n.id})${o} \u2014 proceed with this design.`,{kind:"mock-picked"}).catch(()=>{}),t.json({ok:!0,mock:n,siblings:r})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/nothing to pick/i.test(r)?409:500;t.status(o).json({error:r})}});v.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await gT(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await eT(e.params.id),...n.length?{danglingFlows:n}:{}})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});v.get("/api/flows",async(e,t)=>{try{t.json({flows:await fT({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/flows/:id",async(e,t)=>{let n=await pT(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});v.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await te(n):null;if(!a&&s&&(a=(await le()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+xe.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await mT({trackId:a.id,name:r,steps:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,flow:c})}catch(a){let i=a?.message||String(a),c=/already exists/i.test(i)?409:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(i)?400:500;t.status(c).json({error:i})}});v.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await hT(e.params.id,{steps:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(r)?400:500;t.status(o).json({error:r})}});v.delete("/api/flows/:id",async(e,t)=>{try{t.json(await wT(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});v.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await le(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+xe.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await ET({trackId:n,status:e.query.status||void 0});t.json({runbooks:r,...o?{fleetDegraded:!0}:{}})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.get("/api/runbooks/:id",async(e,t)=>{let n=await nh(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});v.get("/api/runbooks/:id/md",async(e,t)=>{let n=await nh(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=ST(n,e.query.v??null);if(!r)return t.status(404).json({error:"no such version"});if(t.set("content-security-policy","sandbox"),t.set("cache-control","private, max-age=31536000, immutable"),t.type("text/markdown; charset=utf-8"),n.remote){let o=await AT(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(Qn(n,r.v),Oc,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});v.get("/api/loops",async(e,t)=>{t.json(await Ti())});v.post("/api/loops/report",async(e,t)=>{let{outcome:n,note:r,cwd:o}=e.body||{};if(!["ok","acted","attention"].includes(n))return t.status(400).json({error:"outcome must be one of ok | acted | attention"});if(!o)return t.status(400).json({error:"cwd required"});let a=(await le()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+xe.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await Ti();if(i.source!=="plane")return t.status(503).json({error:i.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${i.error||"no detail"})`});let c=i.loops.find(u=>u.trackId===a.id);if(!c)return t.status(404).json({error:`Track "${a.name}" is not a loop's run Track \u2014 nothing to report on`});let l=await fm({loopId:c.id,outcome:n,note:r});if(!l.ok)return t.status(l.status||503).json({error:l.error||"report failed"});t.json({ok:!0,loop:{id:c.id,name:c.name},run:l.run})});v.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await te(n):null;if(!s&&r&&(s=(await le()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+xe.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await v_(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var Tg=async(e,t)=>{let n=e?await te(e):null;return!n&&t&&(n=(await le()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+xe.sep)))||null),n};v.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Tg(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,result:await Uv(s,o,{ship:{changedRepos:_o}})})}catch(s){t.status(400).json({error:s?.message||String(s)})}});v.post("/api/followups/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Tg(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await Wv(s,o)})}catch(s){let a=s?.message||String(s);t.status(/unreachable/i.test(a)?503:400).json({error:a})}});v.get("/api/followups",async(e,t)=>{let n=typeof e.query?.cwd=="string"?e.query.cwd:null,r=await Tg(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:gm,...await zv(r)})});v.post("/api/tracks/:id/followup-offer",async(e,t)=>{let{offerId:n,followupId:r,armId:o,promoted:s}=e.body||{};try{let a=await te(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await Kv(a,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null},{sayToLead:Pt,unarchiveTrack:Fu})})}catch(a){let i=a?.message||String(a),c=a?.code==="removed"?410:/unknown offer/i.test(i)?404:/already answered/i.test(i)?409:/required|not on this card/i.test(i)?400:/unreachable/i.test(i)?503:502;t.status(c).json({error:i})}});v.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await te(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await Hv(n,e.body?.armId)})}catch(n){let r=n?.message||String(n);t.status(/unknown/i.test(r)?404:400).json({error:r})}});v.post("/api/tracks/:id/followup-create-offer",async(e,t)=>{let{proposalId:n,accept:r,followupId:o}=e.body||{};try{let s=await te(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await qv(s,n,r===!0,{followupId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal/i.test(a)?404:/already answered/i.test(a)?409:400).json({error:a})}});ct.on("event",e=>{let t=e?.type==="pr.state.changed"?e.payload?.change:null;if(!t||!e.trackId)return;let n=t==="opened"?"pr.opened":t==="ci-fixed"?"checks.green":null,r=e.payload||{},o={repo:r.repo??null,prNumber:r.number??null,prTitle:r.title??null,prUrl:r.url??null};!n&&t!=="pushed"||te(e.trackId).then(async s=>{if(s&&(n&&await Ai(s,n,o),t==="opened"||t==="pushed")){let a=Vv(await F(s).catch(()=>[]));a&&await Ai(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var FI=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await te(n):null;if(!s&&r&&(s=(await le()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+xe.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await Ti();if(a.source!=="plane")return t.status(503).json({error:a.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${a.error||"no detail"})`}),null;let i;try{i=E_(a.loops,o)}catch(c){return t.status(/matches \d+ loops/.test(c.message)?409:404).json({error:c.message}),null}return{track:s,loop:i}};v.post("/api/loops/propose-update",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await FI(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await A_(s.track,s.loop,e.body?.patch)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});v.post("/api/loops/propose-delete",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await FI(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await __(s.track,s.loop,e.body?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});var UI=e=>/unknown proposal/i.test(e)?404:/already answered/i.test(e)?409:400;v.post("/api/tracks/:id/loop-update-offer",async(e,t)=>{let{proposalId:n,action:r,nextFireAt:o}=e.body||{};try{let s=await te(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await $_(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(UI(a)).json({error:a})}});v.post("/api/tracks/:id/loop-delete-offer",async(e,t)=>{let{proposalId:n,action:r}=e.body||{};try{let o=await te(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await R_(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(UI(s)).json({error:s})}});v.post("/api/tracks/:id/loop-create-offer",async(e,t)=>{let{proposalId:n,accept:r,loopId:o,nextFireAt:s}=e.body||{};try{let a=await te(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await S_(a,n,r===!0,{loopId:o||null,nextFireAt:s??null})})}catch(a){let i=a?.message||String(a);t.status(/unknown proposal/i.test(i)?404:/already answered/i.test(i)?409:400).json({error:i})}});v.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await te(n):null;if(!a&&s&&(a=(await le()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+xe.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await _T({trackId:a.id,trackName:a.name,name:r,md:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,runbook:c})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|over the|secret VALUE/i.test(i)?400:500).json({error:i})}});v.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await IT(e.params.id,{md:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/required|invalid|over the|secret VALUE/i.test(r)?400:500;t.status(o).json({error:r})}});v.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await $T(e.params.id,(e.body||{}).status)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/must be/i.test(r)?400:500;t.status(o).json({error:r})}});v.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await RT(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});v.get("/api/changelog/draft",async(e,t)=>{try{let n=P_(e.query.since||null);t.json({since:n,repos:rg(),...await D_(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var HI=async({trackId:e,cwd:t})=>{let n=e?await te(e):null;return!n&&t&&(n=(await le()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+xe.sep)))||null),n};v.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await HI({trackId:o,cwd:s});if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,entry:await B_(a,{md:n,day:r})})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|no `- `|over the|secret VALUE|mentions "/i.test(i)?400:500).json({error:i})}});v.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await HI({trackId:r,cwd:o});if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,entry:await j_(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var cW=120,bg=400,ga=null,_I=null;v.post("/api/notify",async(e,t)=>{let{title:n,body:r,urgency:o,cwd:s,trackId:a}=e.body||{};try{let i=typeof r=="string"?r.trim():"";if(!i)return t.status(400).json({error:"body (the message) required"});if(i.length>bg)return t.status(400).json({error:`message is ${i.length} chars \u2014 over the ${bg} cap; a notification is a nudge, put the detail in chat`});let c=ji(`${n||""}
702
+ ${i}`);if(c.length)return t.status(400).json({error:`notification appears to contain a secret VALUE (${c.join(", ")}) \u2014 notifications ship off-box; never put a credential in one`});let l=a?await te(a):null;if(!l&&s&&(l=(await le()).find(h=>h.cwd&&(s===h.cwd||s.startsWith(h.cwd+xe.sep)))||null),!l)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=(l.boxes||[]).find(p=>p.name===l.leadBox),f=(p,h)=>String(p).replace(/\s+/g," ").trim().slice(0,h),d={title:n?f(n,cW):l.name,body:f(i,bg),urgency:o==="high"?"high":"normal",trackName:l.name,ts:Date.now()};await $(l,{type:"notify.raised",actor:"agent",boxId:l.leadBox??null,provider:u?.agent||null,payload:d}),t.json({ok:!0,notification:d,delivered:ga?ga.status().connected:null})}catch(i){t.status(500).json({error:i?.message||String(i)})}});v.post("/api/dictation",async(e,t)=>{if(!Buffer.isBuffer(e.body)||e.body.length===0)return t.status(400).json({error:"expected a raw audio body"});try{t.json(await xI(e.body,e.headers["content-type"]))}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});v.get("/api/dictation/glossary",async(e,t)=>{t.json({configured:!!await uc(),terms:await wg(),problem:await kI()})});v.post("/api/dictation/learn",async(e,t)=>{let{transcript:n,finalText:r}=e.body||{};if(typeof n!="string"||typeof r!="string")return t.status(400).json({error:"transcript and finalText are required"});t.json({learned:await bI(n,r)})});v.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await te(e.params.id))return t.status(404).json({error:"track not found"});t.json(await vI())});v.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await te(e.params.id);if(!n)return t.status(404).json({error:"track not found"});if(n.archivedAt)return t.status(409).json({error:"track is archived"});t.json(await SI())}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});v.post("/api/tracks/:id/voice-chat/usage",async(e,t)=>{try{let n=await te(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let{model:r,usage:o,seconds:s}=e.body||{};t.json({ok:!0,...await TI(n,{model:r,usage:o,seconds:s})})}catch(n){t.status(n?.status||500).json({error:n?.message||String(n)})}});v.post("/api/tracks",async(e,t)=>{let{name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i,ticket:c,circuit:l}=e.body||{};try{let u=await ju({name:n,cwd:r,repo:o,repos:s,agent:a,skipPermissions:i!==!1}),f=null;if(c)try{await ia(u,c,{source:"create"})}catch(p){f=p?.message||String(p)}let d=null;if(l)try{await Zu(u,await oa(l),{source:"picker"})}catch(p){d=p?.message||String(p)}t.json({ok:!0,track:u,...f?{ticketWarning:f}:{},...d?{circuitWarning:d}:{}})}catch(u){let f=u?.message||String(u);t.status(/required|unknown agent|invalid|must be/i.test(f)?400:500).json({error:f})}});v.get("/api/tracks/:id",async(e,t)=>{let n=await te(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:WI(ra(e.params.id)),subtasks:jo(e.params.id).map(Cc),pendingOffers:await Oh(n)})});v.delete("/api/tracks/:id",async(e,t)=>{try{let n=await Gh(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await Pw(e.params.id).catch(()=>{}),t.json(n)}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});v.post("/api/tracks/:id/archive",async(e,t)=>{try{t.json({ok:!0,track:await Do(e.params.id)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/already archived/i.test(r)?409:500).json({error:r})}});v.post("/api/tracks/:id/rename",async(e,t)=>{try{t.json({ok:!0,track:await Yh(e.params.id,e.body?.name)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/loop run Tracks/i.test(r)?409:/required|too long/i.test(r)?400:500;t.status(o).json({error:r})}});v.post("/api/tracks/:id/unarchive",async(e,t)=>{try{t.json({ok:!0,track:await Fu(e.params.id,{freshSession:e.body?.freshSession===!0})})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/not archived/i.test(r)?409:500).json({error:r})}});v.get("/api/tracks/:id/messages",async(e,t)=>{let n=await Nu(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json(n)});v.get("/api/tracks/:id/events",async(e,t)=>{let n=await te(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.set({"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"}),t.flushHeaders();let r=i=>t.write(`id: ${i.seq}
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 F(n))i.seq>o&&r(i);let s=ny(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 te(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=String(e.query.q||"").trim();if(!r)return t.status(400).json({error:"q (query) is required"});let o=Math.min(Math.max(Number(e.query.k)||8,1),50),s=oi(await F(n)),a=xl(s,r,{k:o,role:e.query.role||null,tag:e.query.tag||null});t.json({q:r,indexed:s.N,hits:a.map(i=>({score:Number(i.score.toFixed(3)),seq:i.chunk.seq,ts:i.chunk.ts,role:i.chunk.role,box:i.chunk.boxId,provider:i.chunk.provider,tags:i.chunk.tags,text:i.chunk.text}))})});v.get("/api/memory",async(e,t)=>{t.json({stores:await by(),harvest:hy()})});v.delete("/api/memory/:key/:file",async(e,t)=>{let n=String(e.params.key||"");if(!/^[a-z0-9][a-z0-9._-]*$/.test(n))return t.status(400).json({error:"bad store key"});try{t.json({ok:!0,...await ky(n,String(e.params.file||""))})}catch(r){let o=r?.message||String(r);t.status(/not found/i.test(o)?404:/bad fact/i.test(o)?400:500).json({error:o})}});var lW=["Run a memory consolidation pass on this workspace's `.bostrat/memory/` directory:","1. Read `MEMORY.md` and every fact file.","2. Merge duplicates and facts that describe the same thing (keep the best-written one; fold unique details in; give the survivor a `supersedes:` entry naming what it absorbed, delete the absorbed file, and remove its index line).","3. Resolve contradictions in favor of the newest evidence \u2014 check the code where feasible before deciding.","4. Mark clearly-stale facts: correct them in place or delete them (file + index line).","5. Bump `metadata.modified` (ISO-8601, now) on every fact you touch.","6. Keep `MEMORY.md` one line per fact, under 200 lines.","When done, summarize what you merged, corrected, and deleted \u2014 that summary is the review record."].join(`
708
+ `);v.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await Pt(e.params.id,lW)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/archived/i.test(r)?409:/not running/i.test(r)?400:500).json({error:r})}});v.post("/api/tracks/:id/lead/restart",async(e,t)=>{try{t.json({ok:!0,track:await Uu(e.params.id,{freshSession:e.body?.freshSession===!0})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:n?.transferredTo||/mid-turn|terminal|archived/i.test(r)?409:500;t.status(o).json({error:r,...n?.transferredTo?{transferredTo:n.transferredTo}:{}})}});v.post("/api/tracks/:id/say",async(e,t)=>{let{text:n,attachments:r}=e.body||{};try{t.json(await Pt(e.params.id,n,{attachments:r}))}catch(o){let s=o?.message||String(o);if(o?.usageCap)return t.status(429).json({error:"usage_cap",message:s,cap:o.usageCap});if(o?.transferredTo)return t.status(409).json({error:s,transferredTo:o.transferredTo});t.status(/not found/i.test(s)?404:/archived/i.test(s)?409:/required|not running/i.test(s)?400:500).json({error:s})}});v.post("/api/tracks/:id/upload",async(e,t)=>{try{let n=await te(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});if(n.archivedAt)return t.status(409).json({error:"track is archived"});if(!n.cwd)return t.status(409).json({error:"track has no workspace yet"});let r=Buffer.isBuffer(e.body)?e.body:null,o=await DT(n.cwd,{filename:e.query.filename,buffer:r});t.json({ok:!0,attachment:o})}catch(n){let r=n?.message||String(n);t.status(/too large|unsupported|empty|required/i.test(r)?400:500).json({error:r})}});v.get("/api/tracks/:id/uploads/:file",async(e,t)=>{try{let n=await te(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});if(!n.cwd)return t.status(404).json({error:"track has no workspace"});let r=xe.basename(String(e.params.file||""));if(!r||!sh(xe.extname(r).slice(1)))return t.status(400).json({error:"not an upload path"});t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox");let o=oh(n.cwd),s,a;try{s=await mt.promises.realpath(o),a=await mt.promises.realpath(xe.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+xe.sep))return t.status(404).json({error:"upload not found"});t.sendFile(r,{root:o},i=>{i&&!t.headersSent&&t.status(404).json({error:"upload not found"})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});var uW=/^[0-9a-fA-F-]{8,64}$/;v.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await te(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});let{box:r,uuid:o}=e.params,s=Number(e.params.idx);if(!uW.test(o)||!Number.isInteger(s)||s<0)return t.status(400).json({error:"bad image ref"});let a=(n.boxes||[]).find(d=>d.name===r);if(!a||a.agent!=="claude"||!a.cwd||!a.sessionId)return t.status(404).json({error:"image source not available"});let i=Jt(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=XH.createInterface({input:mt.createReadStream(i,{encoding:"utf8"}),crlfDelay:1/0});for await(let d of u){if(!d.includes(c))continue;let p;try{p=JSON.parse(d)}catch{continue}if(p.uuid===o){l=p,u.close();break}}let f=l?_f(l)[s]:null;if(!f||!/^image\//.test(f.mediaType))return t.status(404).json({error:"image not found"});t.set("content-type",f.mediaType),t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox"),t.send(Buffer.from(f.data,"base64"))}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/tracks/:id/interrupt",async(e,t)=>{try{t.json(await Bu(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/archived/i.test(r)?409:500).json({error:r})}});v.delete("/api/tracks/:id/queue",async(e,t)=>{try{let{removed:n,restored:r,draftRev:o}=await Nh(e.params.id);t.json({ok:!0,removed:n.filter(s=>s.kind!=="ship-notify"),restored:r,draftRev:o})}catch(n){t.status(500).json({error:n?.message||String(n)})}});v.post("/api/tracks/:id/answer-prompt",async(e,t)=>{let{promptId:n,answers:r,text:o}=e.body||{};try{t.json(await Pu(e.params.id,{promptId:n,answers:r,text:o}))}catch(s){let a=s?.message||String(s),i=/not found/i.test(a)?404:/no pending prompt|changed since|not running|not supported|needs a code|look like a sign-in code|no answer selected/i.test(a)?409:500;t.status(i).json({error:a})}});v.post("/api/setup/:provider/start",async(e,t)=>{try{let n=await qh({provider:e.params.provider,fresh:e.body?.fresh===!0});t.json({ok:!0,track:n})}catch(n){let r=n?.message||String(n);t.status(/unknown setup provider|isn't available/i.test(r)?400:500).json({error:r})}});v.post("/api/tracks/:id/navigate-prompt",async(e,t)=>{let{promptId:n,questionIndex:r}=e.body||{};try{t.json(await Mh(e.params.id,{promptId:n,questionIndex:r}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/no pending prompt|changed since|not running|not supported|out of range|review screen/i.test(s)?409:500;t.status(a).json({error:s})}});v.put("/api/tracks/:id/draft",async(e,t)=>{let{text:n,rev:r}=e.body||{};try{t.json(await Lh(e.params.id,typeof n=="string"?n:"",{rev:typeof r=="number"?r:null}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required/i.test(s)?400:500;t.status(a).json({error:s})}});v.get("/api/tracks/:id/usage",async(e,t)=>{let n=await te(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=n.boxes?.find(s=>s.name===n.leadBox)||null,o=e.query.fresh==="1"||e.query.fresh==="true";t.json(await hd(r,{fresh:o}))});v.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await Fh(e.params.id,n))}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/required|unknown model|not running/i.test(o)?400:500;t.status(s).json({error:o})}});v.post("/api/tracks/:id/subtask",async(e,t)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=e.body||{};try{let a=await cw(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:Cc(a)})}catch(a){let i=a?.message||String(a);if(a?.usageCap)return t.status(429).json({error:"usage_cap",message:i,cap:a.usageCap});let c=/not found/i.test(i)?404:/required|unknown agent|git repo|not running|can't resolve/i.test(i)?400:500;t.status(c).json({error:i})}});v.get("/api/tracks/:id/subtasks",(e,t)=>{t.json({subtasks:jo(e.params.id).map(Cc)})});v.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await Ch(e.params.id,e.params.sid);if(!n)return t.status(404).json({error:"subtask not found"});t.json(n)});v.post("/api/tracks/:id/subtask/:sid/cancel",(e,t)=>{try{t.json({ok:!0,subtask:Cc(Ku(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});v.post("/api/tracks/:id/subtask/:sid/merge-now",(e,t)=>{try{t.json({ok:!0,subtask:Cc(lw(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function Cc(e){return e?{id:e.id,agent:e.agent,task:e.task,skipPermissions:e.skipPermissions,step:e.step,running:!e.finishedAt,box:e.box,branch:e.branch,stat:e.stat,files:e.files||null,conflicts:e.conflicts||[],applied:e.applied,error:e.error,canceled:e.canceled,startedAt:e.startedAt,finishedAt:e.finishedAt}:null}v.post("/api/tracks/:id/handoff-lead",async(e,t)=>{let{toAgent:n,skipPermissions:r,reason:o}=e.body||{};try{let s=await Hu(e.params.id,n,r!==!1,o);t.json({ok:!0,step:s.step,toAgent:s.toAgent,fromBox:s.fromBox,skipPermissions:s.skipPermissions})}catch(s){let a=s?.message||String(s);if(s?.usageCap)return t.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});t.status(/already running/i.test(a)?409:/not found/i.test(a)?404:400).json({error:a})}});v.post("/api/tracks/:id/spin-up-view",async(e,t)=>{try{t.json(await Bh(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/already being spun up/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});v.get("/api/tracks/:id/handoff-lead",(e,t)=>{t.json(WI(ra(e.params.id))??{running:!1})});v.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await nw(e.params.id);t.json({ok:!0,step:n.step,startedAt:n.startedAt})}catch(n){let r=n?.message||String(n);t.status(/already running/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});v.get("/api/tracks/:id/transfer-out",(e,t)=>{let n=tw(e.params.id);if(!n)return t.json({running:!1});t.json({running:!n.finishedAt,step:n.step,error:n.error,startedAt:n.startedAt,finishedAt:n.finishedAt,...n.result??{}})});v.post("/api/tracks/:id/transfer-out/commit",async(e,t)=>{try{t.json(await Wu(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:400).json({error:r})}});v.post("/api/tracks/adopt",async(e,t)=>{let{trackId:n}=e.body||{};try{t.json(await sw({...e.body||{},trackId:n}))}catch(r){let o=r?.message||String(r);t.status(/already running|already hosted/i.test(o)?409:/not found/i.test(o)?404:400).json({error:o})}});function WI(e){return e?{running:!e.finishedAt,step:e.step,error:e.error,fromBox:e.fromBox,toBox:e.toBox,toAgent:e.toAgent,skipPermissions:e.skipPermissions,startedAt:e.startedAt,finishedAt:e.finishedAt}:null}v.get("/api/debug/handoff",async(e,t)=>{let n=Math.min(Number(e.query.limit)||80,500);t.json({verbose:el(),paths:Py,trace:await Ny({limit:n})})});var kg=xe.resolve(OI,"..","..","client","dist");mt.existsSync(kg)&&(v.use(Gt.static(kg)),v.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(xe.join(kg,"index.html"),Oc)));var qI=QH.createServer(v),dW=new tW({noServer:!0}),KI=(e,t,n)=>{if(!(vc(e)||wa.allowed(wa.clientIp(e))||vg.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
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(m_(e,t,n))return;if(!f_(e,MI,{enforce:NI})){t.write(`HTTP/1.1 401 Unauthorized\r
711
711
  \r
712
- `),t.destroy();return}let r=tb(e.url);if(!r.ok){t.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
712
+ `),t.destroy();return}let r=eb(e.url);if(!r.ok){t.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
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;dW.handleUpgrade(e,t,n,i=>Xy(i,o,{cols:s,rows:a}))};qI.on("upgrade",KI);var GI=process.env.BOSTRAT_CERT_DIR||xe.join(process.env.HOME||_d.tmpdir(),".bostrat","certs"),II=Number(process.env.BOSTRAT_TLS_PORT)||3443,$I=xe.join(GI,"bostrat.globopi.key"),RI=xe.join(GI,"bostrat.globopi.crt");if(mt.existsSync($I)&&mt.existsSync(RI)){let e=eW.createServer({key:mt.readFileSync($I),cert:mt.readFileSync(RI)},v);e.on("upgrade",KI),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(II,Id,()=>{console.log(`[bostrat-agent] https listening on ${Id||"0.0.0.0"}:${II}`)})}qI.listen(EI,Id,()=>{console.log(`[bostrat-agent] listening on ${Id||"0.0.0.0"}:${EI}`);let e=SE(process.env);e&&console.warn(`[bostrat-agent] \u26A0 SECURITY: plane-linked node bound to ${e.host?e.host:"ALL interfaces (BOSTRAT_HOST=all)"} \u2014 the API + Views are reachable off-loopback (LAN/VPN), where the IP allowlist is spoofable and Views need no token. The plane tunnel does not require this; set BOSTRAT_HOST=127.0.0.1 once any local reverse-proxy/WireGuard path is retired (F-2).`),console.log(`[bostrat-agent] tmux socket: ${$t}`),console.log(`[bostrat-agent] auto-trigger default: ${CI}%`),console.log(`[bostrat-agent] ip allowlist: ${wa.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(vg.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),ew().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),aw().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),Jh().then(t=>t&&console.log(`[bostrat-agent] healed ${t} half-demoted transferred track(s)`)).catch(t=>console.error("[bostrat-agent] demoted-track reconcile failed:",t?.message||t)).then(()=>Xh()).then(t=>t&&console.log(`[bostrat-agent] reaped ${t} orphaned box(es) on archived track(s)`)).catch(t=>console.error("[bostrat-agent] archived-orphan sweep failed:",t?.message||t)),Wh().then(t=>console.log(`[bostrat-agent] standing instructions refreshed (${t.refreshed} updated, ${t.removed} legacy CLAUDE.md removed${t.codexGlobal?`, codex global ${t.codexGlobal}`:""})`)).catch(t=>console.error("[bostrat-agent] standing-instructions refresh failed:",t?.message||t)),bW(),mW(),hW(),yW(),Y0({listTracks:le,getTrack:te}).then(t=>console.log(`[bostrat-agent] spend caps ${t.configured?"armed":"unconfigured (fail-open)"} \u2014 seeded ${Object.keys(t.spent).length} provider counter(s)`)).catch(t=>console.error("[bostrat-agent] spend-caps seed failed (staying fail-open):",t?.message||t)),UT()&&HT({listTracks:le}),By().then(t=>console.log(`[bostrat-agent] git hook shims at ${t}`)).catch(t=>console.error("[bostrat-agent] git hook shims failed (commits go unstamped):",t?.message||t)),K_(),J_(),bA({resolveTrack:te}),$A({listTracks:le,createTrack:ju,archiveTrack:Do,listRepos:On,resolveTrack:te,sayToLead:Pt,answerPrompt:Pu,startLeadHandoff:Hu,interruptLead:Bu,listSubtaskJobs:jo,cancelSubtask:Ku,readEvents:F,appendEvent:$,divertShip:lg,answerPrExists:ug,knownAgents:Xi}),fW(),Ha().then(t=>{t||console.warn(`[boot] no host tmux server on ${$t} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),uI(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(ga=ME({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,nodeId:process.env.BOSTRAT_NODE_ID||_d.hostname(),name:process.env.BOSTRAT_NODE_NAME||_d.hostname(),listTracks:le,detectAgents:Mu,sampleMetrics:zA,onTracksTransferred:ow,onDegraded:({since:t,unacked:n,oldestAgeMs:r,mode:o})=>{let s=Math.round(r/6e4),a=`${process.env.BOSTRAT_NODE_NAME||_d.hostname()} \u2192 plane spine sync has stalled: ${n} event(s) unanswered for ${s} min (${o} door). New Tracks won't open from the plane until it recovers; the node is redialing with backoff.`;console.error(`[plane-link] ${a}`),process.env.BOSTRAT_NTFY_URL&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: plane sync stalled",Tags:"rotating_light"},body:a}).catch(()=>{}),_I=t},onRecovered:async({downMs:t})=>{let n=Math.round(t/6e4);process.env.BOSTRAT_NTFY_URL&&n>=5&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: plane sync recovered",Tags:"white_check_mark"},body:`Spine sync to the plane recovered after ${n} min; the backlog is delivered.`}).catch(()=>{}),_I=null},onUpdateAvailable:async t=>{try{xg={latest:t.latest,current:t.current},await An({...t,policy:kt()}),kt()==="auto"&&await PI({to:t.latest,from:t.current})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>sW(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await An({current:t,latest:a,min:n,installKind:o,required:!0,policy:kt(),status:"available",reason:"refused"}),kt()!=="off"&&a){let i=await Xu({to:a,kind:Kt,reason:"hard-floor"});i.ok?($c.cancel(),await An({current:t,latest:a,min:n,installKind:o,required:!0,policy:kt(),status:"updating",reason:"hard-floor"})):console.error(`[self-update] hard-floor update not started: ${i.reason} \u2014 ${s}`)}}catch(a){console.error(`[plane-link] hard-floor handling failed: ${a?.message||a}`)}},updatePolicy:kt}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),os().catch(()=>{}),MT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),kA().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),rT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),kT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),Bx().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{ga?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function fW(){pW(),bu().catch(()=>{}),setInterval(()=>bu().catch(()=>{}),1e4)}function pW(){for(let e of["bostrat-view","bostrat-mock","bostrat-flow","bostrat-ticket","bostrat-circuit","bostrat-blueprint","bostrat-decision","bostrat-runbook","bostrat-loop","bostrat-followup","bostrat-ship","bostrat-notify","bostrat-gmail","bostrat-changelog","gh"])try{let t=xe.resolve(OI,"..","bin",e),n=xe.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!mt.existsSync(t))continue;mt.mkdirSync(n,{recursive:!0});let r=xe.join(n,e);(mt.existsSync(r)?mt.readlinkSync(r):null)!==t&&(mt.rmSync(r,{force:!0}),mt.symlinkSync(t,r)),console.log(`[bostrat-agent] ${e} CLI linked at ${r}`)}catch(t){console.error(`[bostrat-agent] ${e} CLI link failed:`,t?.message||t)}}function mW(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await le(),r=await XA({tracks:n});r.committed&&console.log(`[state-sync] committed (${r.staged} file(s) staged${r.pushed?", pushed":""})`)}catch{}finally{e=!1}}};setInterval(t,6e4),t()}function hW(){let e=null,t=async()=>{try{let n=bs(),r=0,o=[],s=null;try{let l=await le(),u=await Vw(l);r=u.fleet.unpricedTurns||0,o=u.fleet.unpricedModels||[],s=await YA(l,{days:7})}catch{}let a=[...n.problems];s&&!s.ok&&a.push(`${s.divergent} recent row(s) diverge from the table (implied-rate audit) \u2014 run \`npm run cost -- --audit\``);let i=o.filter(l=>l!=="unknown");i.length&&a.push(`${r} unpriced turn(s) \u2014 add rates for: ${i.join(", ")}`);let c=a.join(`
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 wW=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,gW=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function yW(){let e=async()=>{try{let n=await yy();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await le()).filter(a=>!Ve(a)&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await gy([...new Set(o)]);s.harvested&&console.log(`[memory] reconciler harvested ${s.harvested} fact(s) from ${o.length} live workspace(s)`)}catch{}};setTimeout(()=>{e(),setInterval(e,wW).unref()},gW).unref()}function bW(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await le();for(let n of t)Ve(n)||!n.boxes?.some(r=>r.state==="live")||(await Nu(n.id).catch(()=>{}),await PS(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}