bostrat-node 1.9.7 → 1.9.9

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 +54 -54
  2. package/dist/index.js +202 -198
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,52 +1,52 @@
1
- var VO=Object.defineProperty;var K=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var Dp=(e,t)=>{for(var n in t)VO(e,n,{get:t[n],enumerable:!0})};import{createHash as JO,randomBytes as YO,timingSafeEqual as XO}from"node:crypto";function db(){return YO(32).toString("hex")}function Ha(e){let t=typeof e=="string"?e.trim():"";return t?JO("sha256").update(t).digest("hex"):null}function pb(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:XO(Buffer.from(e),Buffer.from(t))}function Wa(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(Bp.set(e,(Bp.get(e)||0)+1),jp.has(e)&&n-jp.get(e)<ZO)return!1;jp.set(e,n);let o=Object.entries(t).filter(([,s])=>s!=null&&s!=="").map(([s,a])=>`${s}=${a}`).join(" ");return r(`[hook-audit] ${e} n=${Bp.get(e)}${o?` ${o}`:""}`),!0}async function fb(e,{byToken:t,legacy:n,env:r=process.env}={}){let o=typeof e=="string"?e.trim():"";if(!o)return r.BOSTRAT_HOOK_LEGACY_DENY==="1"?{mode:"legacy-denied",target:null}:{mode:"legacy",target:await n()};let s=await t(o);return s?.track?{mode:"token",target:s}:{mode:"refused",target:null}}var zn,Vn,Bp,jp,ZO,fs=K(()=>{zn="BOSTRAT_HOOK_TOKEN",Vn="x-bostrat-hook";Bp=new Map,jp=new Map,ZO=6e4});import Rt from"node:fs/promises";import mb from"node:os";import At from"node:path";import{execFile as QO}from"node:child_process";import{promisify as eM}from"node:util";function fl(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function tM(){return process.env.CLAUDE_CONFIG_DIR?At.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):At.join(mb.homedir(),".claude.json")}function nM(){return process.env.CLAUDE_CONFIG_DIR?At.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):At.join(mb.homedir(),".claude","settings.json")}async function vr(e){if(!e||typeof e!="string")return;let t=At.resolve(e),n=tM(),r=nM(),o={};try{o=JSON.parse(await Rt.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 Rt.mkdir(At.dirname(n),{recursive:!0}),await Rt.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await Rt.readFile(r,"utf8"))}catch{}if(i.skipDangerousModePermissionPrompt=!0,i.remoteControlAtStartup=!1,i.tui===void 0&&(i.tui="default"),process.env.BOSTRAT_HOOKS!=="off"){let l=`curl -sS -m 3 -X POST ${process.env.BOSTRAT_HOOK_URL||`http://127.0.0.1:${process.env.PORT||3362}/api/hook`} -H 'content-type: application/json' -H "${Vn}: $${zn}" --data-binary @- >/dev/null 2>&1 || true`,u=[{hooks:[{type:"command",command:l}]}];i.hooks=i.hooks||{};for(let d of["SessionStart","UserPromptSubmit","Stop"])i.hooks[d]=u;i.hooks.PostToolUse=[{matcher:"*",hooks:[{type:"command",command:l}]}]}await Rt.mkdir(At.dirname(r),{recursive:!0}),await Rt.writeFile(r,JSON.stringify(i,null,2)),await rM(t)}async function rM(e){try{let t=At.resolve(e),n=At.join(t,".bostrat","memory","claude"),r=At.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await Rt.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(At.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await Rt.mkdir(n,{recursive:!0}),await Rt.mkdir(At.dirname(r),{recursive:!0}),await Rt.writeFile(r,JSON.stringify(o,null,2)),await oM(t,["/.claude/settings.local.json"])}catch{}}async function oM(e,t){try{let{stdout:n}=await eM(QO)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=At.resolve(e,n.trim()),o=await Rt.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
2
- `).includes(a));if(!s.length)return;await Rt.mkdir(At.dirname(r),{recursive:!0}),await Rt.appendFile(r,(o&&!o.endsWith(`
1
+ var RM=Object.defineProperty;var q=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var wf=(e,t)=>{for(var n in t)RM(e,n,{get:t[n],enumerable:!0})};import{createHash as OM,randomBytes as MM,timingSafeEqual as CM}from"node:crypto";function zb(){return MM(32).toString("hex")}function $o(e){let t=typeof e=="string"?e.trim():"";return t?OM("sha256").update(t).digest("hex"):null}function Vb(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:CM(Buffer.from(e),Buffer.from(t))}function si(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(gf.set(e,(gf.get(e)||0)+1),yf.has(e)&&n-yf.get(e)<NM)return!1;yf.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=${gf.get(e)}${o?` ${o}`:""}`),!0}async function Jb(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 Jn,Yn,gf,yf,NM,Rs=q(()=>{Jn="BOSTRAT_HOOK_TOKEN",Yn="x-bostrat-hook";gf=new Map,yf=new Map,NM=6e4});import Bt from"node:fs/promises";import Yb from"node:os";import $t from"node:path";import{execFile as PM}from"node:child_process";import{promisify as DM}from"node:util";function Rl(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function BM(){return process.env.CLAUDE_CONFIG_DIR?$t.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):$t.join(Yb.homedir(),".claude.json")}function jM(){return process.env.CLAUDE_CONFIG_DIR?$t.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):$t.join(Yb.homedir(),".claude","settings.json")}async function $r(e){if(!e||typeof e!="string")return;let t=$t.resolve(e),n=BM(),r=jM(),o={};try{o=JSON.parse(await Bt.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 Bt.mkdir($t.dirname(n),{recursive:!0}),await Bt.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await Bt.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 "${Yn}: $${Jn}" --data-binary @- >/dev/null 2>&1 || true`,u=[{hooks:[{type:"command",command:l}]}];i.hooks=i.hooks||{};for(let d of["SessionStart","UserPromptSubmit","Stop"])i.hooks[d]=u;i.hooks.PostToolUse=[{matcher:"*",hooks:[{type:"command",command:l}]}]}await Bt.mkdir($t.dirname(r),{recursive:!0}),await Bt.writeFile(r,JSON.stringify(i,null,2)),await LM(t)}async function LM(e){try{let t=$t.resolve(e),n=$t.join(t,".bostrat","memory","claude"),r=$t.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await Bt.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes($t.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await Bt.mkdir(n,{recursive:!0}),await Bt.mkdir($t.dirname(r),{recursive:!0}),await Bt.writeFile(r,JSON.stringify(o,null,2)),await FM(t,["/.claude/settings.local.json"])}catch{}}async function FM(e,t){try{let{stdout:n}=await DM(PM)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=$t.resolve(e,n.trim()),o=await Bt.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
2
+ `).includes(a));if(!s.length)return;await Bt.mkdir($t.dirname(r),{recursive:!0}),await Bt.appendFile(r,(o&&!o.endsWith(`
3
3
  `)?`
4
4
  `:"")+s.join(`
5
5
  `)+`
6
- `)}catch{}}var qa=K(()=>{fs()});import Lp from"node:fs/promises";import sM from"node:os";import ml from"node:path";function aM(){let e=process.env.CODEX_HOME||ml.join(sM.homedir(),".codex");return ml.join(e,"config.toml")}function hb(e){return`[projects."${e}"]`}function iM(e,t){let n=hb(t),r=e.indexOf(n);if(r===-1)return!1;let o=e.slice(r+n.length),s=o.search(/^\s*\[/m),a=s===-1?o:o.slice(0,s);return/trust_level\s*=\s*"trusted"/.test(a)}async function ms(e){if(!e||typeof e!="string")return;let t=ml.resolve(e),n=aM(),r="";try{r=await Lp.readFile(n,"utf8")}catch{}if(iM(r,t))return;let o=hb(t);if(r.includes(o)){let a=r.indexOf(o)+o.length,c=r.slice(a).search(/^\s*\[/m),l=c===-1?r.length:a+c,u=r.slice(a,l),d=/trust_level\s*=/.test(u)?u.replace(/trust_level\s*=\s*"[^"]*"/,'trust_level = "trusted"'):`${u.replace(/\s*$/,"")}
6
+ `)}catch{}}var ai=q(()=>{Rs()});import bf from"node:fs/promises";import UM from"node:os";import Ol from"node:path";function HM(){let e=process.env.CODEX_HOME||Ol.join(UM.homedir(),".codex");return Ol.join(e,"config.toml")}function Xb(e){return`[projects."${e}"]`}function WM(e,t){let n=Xb(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 Os(e){if(!e||typeof e!="string")return;let t=Ol.resolve(e),n=HM(),r="";try{r=await bf.readFile(n,"utf8")}catch{}if(WM(r,t))return;let o=Xb(t);if(r.includes(o)){let a=r.indexOf(o)+o.length,c=r.slice(a).search(/^\s*\[/m),l=c===-1?r.length:a+c,u=r.slice(a,l),d=/trust_level\s*=/.test(u)?u.replace(/trust_level\s*=\s*"[^"]*"/,'trust_level = "trusted"'):`${u.replace(/\s*$/,"")}
7
7
  trust_level = "trusted"
8
8
  `;r=r.slice(0,a)+d+r.slice(l)}else{let s=`
9
9
  ${o}
10
10
  trust_level = "trusted"
11
11
  `;r=r.trimEnd()+s+(r.length&&!r.endsWith(`
12
12
  `)?`
13
- `:"")}try{await Lp.mkdir(ml.dirname(n),{recursive:!0}),await Lp.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var hl=K(()=>{});import wb from"node:fs/promises";import cM from"node:os";import Ka from"node:path";function lM(e){let n=Ka.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||Ka.join(cM.homedir(),".cursor");return Ka.join(r,"projects",n)}async function hs(e){if(!e||typeof e!="string")return;let t=Ka.resolve(e),n=lM(t),r=Ka.join(n,".workspace-trusted");await wb.mkdir(n,{recursive:!0}),await wb.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
14
- `,"utf8")}var wl=K(()=>{});import Up from"node:fs/promises";import Sr from"node:path";import{execFile as uM}from"node:child_process";import{promisify as dM}from"node:util";async function gM(e){try{return(await Up.stat(Sr.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function yM(e){let t=i=>Up.readFile(Sr.join(e,".git",i),"utf8").then(c=>c.trim()).catch(()=>null),r=(await t("refs/remotes/origin/HEAD"))?.match(/^ref:\s*refs\/remotes\/origin\/(.+)/);if(r)return r[1].trim();let o;for(let i of["main","master"])if(await t(`refs/heads/${i}`)||(o??=await t("packed-refs")||"",new RegExp(`^[0-9a-f]{40} refs/heads/${i}$`,"m").test(o)))return i;let a=(await t("HEAD"))?.match(/^ref:\s*refs\/heads\/(.+)/);return a?a[1].trim():null}async function Jn(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await gM(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:Sr.basename(o),branch:await yM(o)});return}if(s>=hM)return;let i;try{i=await Up.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||wM.has(c.name)||await t(Sr.join(o,c.name),s+1)}for(let o of mM)await t(Sr.resolve(o),0);let n=new Set,r=[];for(let o of e.values()){let s=await _e(o.path),a=s?.toLowerCase();if(a){if(n.has(a))continue;n.add(a),o.slug=s}r.push(o)}return r.sort((o,s)=>o.name.localeCompare(s.name))}function bM(e){let t=String(e||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return t?`${t[1]}/${t[2]}`:null}async function _e(e){if(!e)return null;if(Fp.has(e))return Fp.get(e);let t=null;try{let{stdout:n}=await pM("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=bM(n)}catch{t=null}return Fp.set(e,t),t}async function ws(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await Jn())if((await _e(n.path))?.toLowerCase()===t)return n.path;return null}var pM,gb,fM,mM,hM,wM,Fp,Tr=K(()=>{pM=dM(uM),gb=process.env.HOME||"/home/globo",fM=Sr.join(process.env.BOSTRAT_STATE_DIR||Sr.join(gb,".bostrat"),"repos"),mM=[...(process.env.BOSTRAT_REPOS_ROOT||Sr.join(gb,"Documents")).split(","),fM].map(e=>e.trim()).filter(Boolean),hM=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,wM=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);Fp=new Map});import kM from"node:fs";import yb from"node:fs/promises";import Ga from"node:path";import xM from"node:os";import{fileURLToPath as vM}from"node:url";import{execFile as SM}from"node:child_process";import{promisify as TM}from"node:util";function Oe(e=process.env){let t=e.BOSTRAT_PLANE_URL||"";if(!t)return null;try{let n=new URL(t);return n.protocol=n.protocol==="ws:"?"http:":"https:",n.origin}catch{return null}}function gl(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function yl(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!kb.test(n))throw gs("repo must be owner/name",400);let r=Hp.get(n);if(r&&r.expiresAt-Date.now()>_M)return r;if(!gl(t))throw gs("node is not plane-linked \u2014 GitHub auth unavailable",503);let o;try{o=await xb(`${Oe(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:vb(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw gs(`plane unreachable \u2014 GitHub auth unavailable (${i?.message||i})`,503)}let s=await o.json().catch(()=>({}));if(!o.ok){if(o.status>=500&&r&&r.expiresAt>Date.now())return r;throw gs(s?.error||`plane replied ${o.status}`,o.status)}let a={token:s.token,expiresAt:Number(s.expiresAt)||Date.now()+55*6e4,username:s.username??null,installationId:s.installationId??null};return Hp.set(n,a),a}async function za({env:e=process.env,force:t=!1}={}){if(!gl(e))return{configured:!1,repos:[],username:null};if(!t&&ko&&Date.now()-ko.at<IM)return ko.data;try{let n=await xb(`${Oe(e)}/v1/github/repos`,{headers:vb(e)});if(!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return ko={at:Date.now(),data:r},r}catch(n){return ko?ko.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function Sb(){Hp.clear(),ko=null}async function vn({cwd:e=null,slug:t=null,env:n=process.env}={}){try{let r=t||(e?await _e(e):null);if(!r)return{};let{token:o}=await yl(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function Wp({env:e=process.env}={}){return(await za({env:e})).username??null}function MM(e){let[t,n]=String(e).split("/");return Ga.join(EM,t,n)}async function qp(e,{env:t=process.env}={}){let n=(...r)=>bb("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${RM()}" ${OM(t)}`),await n("config","credential.useHttpPath","true")}async function bl(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!kb.test(String(e||"")))throw gs(`bad repo slug "${e}"`,400);let r=MM(e);if(kM.existsSync(Ga.join(r,".git")))return r;let{token:o}=await yl(e,{env:t});await yb.mkdir(Ga.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await bb("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:$M,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await yb.rm(r,{recursive:!0,force:!0}).catch(()=>{}),gs(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await qp(r,{env:t}),r}var bb,AM,EM,kb,_M,IM,$M,xb,Hp,ko,vb,gs,RM,OM,pt=K(()=>{Tr();bb=TM(SM),AM=process.env.BOSTRAT_STATE_DIR||Ga.join(process.env.HOME||xM.tmpdir(),".bostrat"),EM=Ga.join(AM,"repos"),kb=/^[^/\s]+\/[^/\s]+$/,_M=5*6e4,IM=6e4,$M=10*6e4,xb=fetch,Hp=new Map,ko=null;vb=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),gs=(e,t)=>Object.assign(new Error(e),{status:t});RM=()=>vM(new URL("../bin/bostrat-git-credential",import.meta.url)),OM=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function Ab(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function _b(e,t,n,r=Tb){let o=Oe(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await NM(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function Ib(e,{env:t=process.env,force:n=!1,timeoutMs:r=Tb}={}){if(!Ab(t))return{facts:[],source:"unconfigured"};let o=Kp.get(e);if(!n&&o&&Date.now()-o.at<CM)return{facts:o.facts,source:"cache"};try{let s=await _b(`/v1/memory/${encodeURIComponent(e)}`,{headers:Eb(t)},t,r);if(!s.ok)throw new Error(`plane ${s.status}`);let a=await s.json(),i=Array.isArray(a?.facts)?a.facts:[];return Kp.set(e,{at:Date.now(),facts:i}),{facts:i,source:"plane"}}catch(s){return o?{facts:o.facts,source:"stale",error:s?.message}:{facts:[],source:"unreachable",error:s?.message}}}async function kl(e,t,{env:n=process.env}={}){if(!Ab(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await _b(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...Eb(n),"content-type":"application/json"},body:JSON.stringify({facts:t})},n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.results)?o.results:[];return Kp.delete(e),{pushed:s.filter(a=>a.outcome==="accepted").length,rejected:s.filter(a=>a.outcome==="rejected"),source:"plane"}}catch(r){return{pushed:0,source:"unreachable",error:r?.message}}}var CM,Tb,Kp,NM,Eb,$b=K(()=>{pt();CM=6e4,Tb=5e3,Kp=new Map,NM=(...e)=>fetch(...e);Eb=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import Gp from"node:fs/promises";import ys from"node:path";import PM from"node:os";import{EventEmitter as DM}from"node:events";import{randomUUID as BM}from"node:crypto";function bs(e){return e?.cwd?ys.join(e.cwd,".bostrat","events"):ys.join(zp,"events")}async function UM(e,t){if(!xl.has(t)){let o=(await q(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);xl.set(t,o)}let n=xl.get(t)+1;return xl.set(t,n),n}function Vp(e,t){let n=Array.isArray(e?.epochs)?e.epochs:null;if(!(!n||n.length===0)){if(!Number.isFinite(t))return n.length-1;for(let r=n.length-1;r>=0;r--){let o=n[r].startedAt;if(o==null||o<=t)return r}return 0}}async function M(e,t){let n=typeof e=="string"?e:e?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!t||!jM.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!LM.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!FM.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?ys.join(zp,"events"):bs(e),o=t.epoch;if(o==null&&typeof e=="object"&&t.boxId&&Array.isArray(e?.boxes)){let u=e.boxes.find(d=>d.name===t.boxId);o=Vp(u,Number(t.payload?.ts??t.ts)||Date.now())}let s=await UM(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||BM(),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 Ob(c)&&(c=Mb(c),l=JSON.parse(c)),await Gp.mkdir(r,{recursive:!0}),await Gp.appendFile(Rb(r,n),c+`
15
- `),Je.emit("event",l),Je.emit(`track:${n}`,l),l}async function q(e,t){let n,r;typeof e=="string"&&t?(n=e,r=t):(r=typeof e=="string"?e:e?.id,n=typeof e=="string"?ys.join(zp,"events"):bs(e));let o;try{o=await Gp.readFile(Rb(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
16
- `))if(a.trim())try{s.push(JSON.parse(Ob(a)?Mb(a):a))}catch{}return s}function Cb(e,t){let n=`track:${e}`;return Je.on(n,t),()=>Je.off(n,t)}var jM,LM,FM,Je,zp,Rb,xl,HM,Ob,Mb,pe=K(()=>{jM=new Set(["session.ready","turn.user","turn.agent","turn.retracted","peer.message","provider.error","delivery.queued","delivery.settled","turn.interrupted","tool.called","tool.result","prompt.raised","prompt.answered","prompt.dismissed","prompt.autoRejected","box.fullscreen.detected","box.fullscreen.answered","context.usage","cost.recorded","memory.seed","memory.harvested","handoff.artifact","code.pushed","code.committed","code.rework","rework.cause.offered","rework.cause.answered","rework.cause.retracted","handoff.started","handoff.step","handoff.done","handoff.failed","subtask.delegated","subtask.merged","job.started","job.stalled","pr.state.changed","pr.offered","pr.offer.answered","pr.exists.offered","pr.exists.answered","box.state.changed","view.state.changed","view.spinup.failed","mock.state.changed","flow.state.changed","runbook.state.changed","ticket.linked","ticket.sync.failed","ticket.move.offered","ticket.move.answered","ticket.state.changed","ticket.commented","ticket.flow.changed","ticket.create.offered","ticket.create.answered","ticket.created","loop.create.offered","loop.create.answered","loop.created","loop.update.offered","loop.update.answered","loop.updated","loop.delete.offered","loop.delete.answered","loop.deleted","loop.paused","followup.armed","followup.armed.cancelled","followup.offered","followup.answered","followup.create.offered","followup.create.answered","followup.created","planning.change.offered","planning.change.answered","planning.changed","notify.raised","usage.cap.hit","usage.cap.warning","provider.connected","track.summary.recorded","track.transferred","track.recovered","track.phase.changed","track.operation.changed","track.obligations.changed","track.circuit.tagged","blueprint.item.bound","decision.recorded","changelog.published","stall.detected","error"]),LM=new Set(["user","agent","orchestrator","system","peer"]),FM=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor","cli"]),Je=new DM;Je.setMaxListeners(0);zp=process.env.BOSTRAT_STATE_DIR||ys.join(process.env.HOME||PM.tmpdir(),".bostrat");Rb=(e,t)=>ys.join(e,`${t}.ndjson`),xl=new Map;HM=/(?<!\\)((?:\\\\)*)\\u0000/g,Ob=e=>e.includes("\\u0000"),Mb=e=>e.replace(HM,"$1\\ufffd")});import re from"node:fs/promises";import WM from"node:os";import be from"node:path";import{execFile as qM}from"node:child_process";import{promisify as KM}from"node:util";function Sl(){return be.join(Tl,"memory","repos")}function xo(e){return e===Yn?be.join(Tl,"memory",Yn):be.join(Sl(),e)}async function Ja(e){try{return JSON.parse(await re.readFile(be.join(e,Fb),"utf8"))}catch{return{}}}async function Yp(e,t){let n=await Ja(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await re.mkdir(e,{recursive:!0}),await re.writeFile(be.join(e,Fb),JSON.stringify(n))}function Pb(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 Db(e){try{let{stdout:t}=await GM("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function Xp(e){if(!e)return[];let t=Pb(await Db(e));if(t)return[t];let n=[],r=[];try{r=await re.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=Pb(await Db(be.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function Al(e){let t=/^---\n([\s\S]*?)\n---\n?/.exec(e);return t?{fm:t[1],body:e.slice(t[0].length)}:{fm:null,body:e}}function Ar(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function Sn(e,t=null){let n=t??await re.readFile(e,"utf8").catch(()=>""),{fm:r}=Al(n),o=Ar(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await re.stat(e)).mtimeMs}catch{return 0}}function Ub(e,t){let n=Ar(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===Yn){let o=Ar(e,"trust");if(!o||/^operator/i.test(o))return Yn}return t}function Zp(e,t,n,r=new Map){let o=(e||"").split(`
13
+ `:"")}try{await bf.mkdir(Ol.dirname(n),{recursive:!0}),await bf.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var Ml=q(()=>{});import Zb from"node:fs/promises";import qM from"node:os";import ii from"node:path";function KM(e){let n=ii.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||ii.join(qM.homedir(),".cursor");return ii.join(r,"projects",n)}async function Ms(e){if(!e||typeof e!="string")return;let t=ii.resolve(e),n=KM(t),r=ii.join(n,".workspace-trusted");await Zb.mkdir(n,{recursive:!0}),await Zb.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
14
+ `,"utf8")}var Cl=q(()=>{});import xf from"node:fs/promises";import Rr from"node:path";import{execFile as GM}from"node:child_process";import{promisify as zM}from"node:util";async function QM(e){try{return(await xf.stat(Rr.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function eC(e){let t=i=>xf.readFile(Rr.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 Xn(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await QM(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:Rr.basename(o),branch:await eC(o)});return}if(s>=XM)return;let i;try{i=await xf.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||ZM.has(c.name)||await t(Rr.join(o,c.name),s+1)}for(let o of YM)await t(Rr.resolve(o),0);let n=new Set,r=[];for(let o of e.values()){let s=await _e(o.path),a=s?.toLowerCase();if(a){if(n.has(a))continue;n.add(a),o.slug=s}r.push(o)}return r.sort((o,s)=>o.name.localeCompare(s.name))}function tC(e){let t=String(e||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return t?`${t[1]}/${t[2]}`:null}async function _e(e){if(!e)return null;if(kf.has(e))return kf.get(e);let t=null;try{let{stdout:n}=await VM("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=tC(n)}catch{t=null}return kf.set(e,t),t}async function Cs(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await Xn())if((await _e(n.path))?.toLowerCase()===t)return n.path;return null}var VM,Qb,JM,YM,XM,ZM,kf,Or=q(()=>{VM=zM(GM),Qb=process.env.HOME||"/home/globo",JM=Rr.join(process.env.BOSTRAT_STATE_DIR||Rr.join(Qb,".bostrat"),"repos"),YM=[...(process.env.BOSTRAT_REPOS_ROOT||Rr.join(Qb,"Documents")).split(","),JM].map(e=>e.trim()).filter(Boolean),XM=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,ZM=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);kf=new Map});function Ns(e=Date.now()){if(Oo)return{tripped:!1,holdMs:1/0};if(Ro>e)return{tripped:!1,holdMs:Ro-e};if((!li||e-li>=Nl.windowMs)&&(li=e,ci=0),ci++,ci<Nl.trip)return{tripped:!1,holdMs:0};Pl++;let t=Math.min(Nl.minMs*2**(Pl-1),Nl.maxMs);return Ro=e+t,ci=0,li=0,{tripped:!0,holdMs:t}}function ek(){ci=0,li=0,Pl=0,Ro=0}function ui(e=Date.now()){return Oo?1/0:Ro>e?Ro-e:0}function Ps(e=Date.now()){return ui(e)>0}function vf(e={}){Oo={at:Date.now(),...e},Ro=1/0}function Dl(){return Oo}function tk(e=Date.now()){return{held:Ps(e),holdMs:Oo?null:ui(e),holds:Pl,removed:Oo?{...Oo}:null}}var nC,Nl,ci,li,Pl,Ro,Oo,Sf=q(()=>{nC={trip:3,windowMs:3e5,minMs:3e5,maxMs:216e5},Nl={...nC},ci=0,li=0,Pl=0,Ro=0,Oo=null});import rC from"node:fs";import nk from"node:fs/promises";import di from"node:path";import oC from"node:os";import{fileURLToPath as sC}from"node:url";import{execFile as aC}from"node:child_process";import{promisify as iC}from"node:util";function Re(e=process.env){let t=e.BOSTRAT_PLANE_URL||"";if(!t)return null;try{let n=new URL(t);return n.protocol=n.protocol==="ws:"?"http:":"https:",n.origin}catch{return null}}function Bl(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function jl(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!ok.test(n))throw Mo("repo must be owner/name",400);let r=Af.get(n);if(r&&r.expiresAt-Date.now()>uC)return r;if(!Bl(t))throw Mo("node is not plane-linked \u2014 GitHub auth unavailable",503);if(Ps()){if(r&&r.expiresAt>Date.now())return r;throw Mo(Dl()?"this node was removed from the plane \u2014 GitHub auth unavailable":"plane refused this node's token \u2014 GitHub auth unavailable until it is re-minted",503)}let o;try{o=await sk(`${Re(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:ak(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw Mo(`plane unreachable \u2014 GitHub auth unavailable (${i?.message||i})`,503)}let s=await o.json().catch(()=>({}));if(!o.ok){if((o.status===401||o.status===403||o.status===410)&&Ns(),o.status>=500&&r&&r.expiresAt>Date.now())return r;throw Mo(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 Af.set(n,a),a}async function pi({env:e=process.env,force:t=!1}={}){if(!Bl(e))return{configured:!1,repos:[],username:null};if(!t&&Mr&&Date.now()-Mr.at<dC)return Mr.data;if(Ps())return Mr?.data??{configured:!0,repos:[],username:null,error:"plane refused this node's token"};try{let n=await sk(`${Re(e)}/v1/github/repos`,{headers:ak(e)});if((n.status===401||n.status===403||n.status===410)&&Ns(),!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return Mr={at:Date.now(),data:r},r}catch(n){return Mr?Mr.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function ik(){Af.clear(),Mr=null}async function Sn({cwd:e=null,slug:t=null,env:n=process.env}={}){try{let r=t||(e?await _e(e):null);if(!r)return{};let{token:o}=await jl(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function Tf({env:e=process.env}={}){return(await pi({env:e})).username??null}function mC(e){let[t,n]=String(e).split("/");return di.join(lC,t,n)}async function Ef(e,{env:t=process.env}={}){let n=(...r)=>rk("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${fC()}" ${hC(t)}`),await n("config","credential.useHttpPath","true")}async function Ll(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!ok.test(String(e||"")))throw Mo(`bad repo slug "${e}"`,400);let r=mC(e);if(rC.existsSync(di.join(r,".git")))return r;let{token:o}=await jl(e,{env:t});await nk.mkdir(di.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await rk("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:pC,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await nk.rm(r,{recursive:!0,force:!0}).catch(()=>{}),Mo(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Ef(r,{env:t}),r}var rk,cC,lC,ok,uC,dC,pC,sk,Af,Mr,ak,Mo,fC,hC,mt=q(()=>{Or();Sf();rk=iC(aC),cC=process.env.BOSTRAT_STATE_DIR||di.join(process.env.HOME||oC.tmpdir(),".bostrat"),lC=di.join(cC,"repos"),ok=/^[^/\s]+\/[^/\s]+$/,uC=5*6e4,dC=6e4,pC=10*6e4,sk=fetch,Af=new Map,Mr=null;ak=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),Mo=(e,t)=>Object.assign(new Error(e),{status:t});fC=()=>sC(new URL("../bin/bostrat-git-credential",import.meta.url)),hC=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function lk(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function dk(e,t,n,r=ck){let o=Re(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await gC(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function pk(e,{env:t=process.env,force:n=!1,timeoutMs:r=ck}={}){if(!lk(t))return{facts:[],source:"unconfigured"};let o=_f.get(e);if(!n&&o&&Date.now()-o.at<wC)return{facts:o.facts,source:"cache"};try{let s=await dk(`/v1/memory/${encodeURIComponent(e)}`,{headers:uk(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 _f.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 Fl(e,t,{env:n=process.env}={}){if(!lk(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await dk(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...uk(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 _f.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 wC,ck,_f,gC,uk,fk=q(()=>{mt();wC=6e4,ck=5e3,_f=new Map,gC=(...e)=>fetch(...e);uk=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import If from"node:fs/promises";import Ds from"node:path";import yC from"node:os";import{EventEmitter as bC}from"node:events";import{randomUUID as kC}from"node:crypto";function Bs(e){return e?.cwd?Ds.join(e.cwd,".bostrat","events"):Ds.join($f,"events")}async function AC(e,t){if(!Ul.has(t)){let o=(await K(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);Ul.set(t,o)}let n=Ul.get(t)+1;return Ul.set(t,n),n}function Rf(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 C(e,t){let n=typeof e=="string"?e:e?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!t||!xC.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!vC.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!SC.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?Ds.join($f,"events"):Bs(e),o=t.epoch;if(o==null&&typeof e=="object"&&t.boxId&&Array.isArray(e?.boxes)){let u=e.boxes.find(d=>d.name===t.boxId);o=Rf(u,Number(t.payload?.ts??t.ts)||Date.now())}let s=await AC(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||kC(),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 mk(c)&&(c=wk(c),l=JSON.parse(c)),await If.mkdir(r,{recursive:!0}),await If.appendFile(hk(r,n),c+`
15
+ `),Je.emit("event",l),Je.emit(`track:${n}`,l),l}async function K(e,t){let n,r;typeof e=="string"&&t?(n=e,r=t):(r=typeof e=="string"?e:e?.id,n=typeof e=="string"?Ds.join($f,"events"):Bs(e));let o;try{o=await If.readFile(hk(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
16
+ `))if(a.trim())try{s.push(JSON.parse(mk(a)?wk(a):a))}catch{}return s}function gk(e,t){let n=`track:${e}`;return Je.on(n,t),()=>Je.off(n,t)}var xC,vC,SC,Je,$f,hk,Ul,TC,mk,wk,he=q(()=>{xC=new Set(["session.ready","turn.user","turn.agent","turn.retracted","peer.message","provider.error","delivery.queued","delivery.settled","turn.interrupted","tool.called","tool.result","prompt.raised","prompt.answered","prompt.dismissed","prompt.autoRejected","box.fullscreen.detected","box.fullscreen.answered","context.usage","cost.recorded","memory.seed","memory.harvested","handoff.artifact","code.pushed","code.committed","code.rework","rework.cause.offered","rework.cause.answered","rework.cause.retracted","handoff.started","handoff.step","handoff.done","handoff.failed","subtask.delegated","subtask.merged","job.started","job.stalled","pr.state.changed","pr.offered","pr.offer.answered","pr.exists.offered","pr.exists.answered","box.state.changed","view.state.changed","view.spinup.failed","mock.state.changed","flow.state.changed","runbook.state.changed","ticket.linked","ticket.sync.failed","ticket.move.offered","ticket.move.answered","ticket.state.changed","ticket.commented","ticket.flow.changed","ticket.create.offered","ticket.create.answered","ticket.created","loop.create.offered","loop.create.answered","loop.created","loop.update.offered","loop.update.answered","loop.updated","loop.delete.offered","loop.delete.answered","loop.deleted","loop.paused","followup.armed","followup.armed.cancelled","followup.offered","followup.answered","followup.create.offered","followup.create.answered","followup.created","planning.change.offered","planning.change.answered","planning.changed","notify.raised","usage.cap.hit","usage.cap.warning","provider.connected","track.summary.recorded","track.transferred","track.recovered","track.phase.changed","track.operation.changed","track.obligations.changed","track.circuit.tagged","blueprint.item.bound","decision.recorded","changelog.published","stall.detected","error"]),vC=new Set(["user","agent","orchestrator","system","peer"]),SC=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor","cli"]),Je=new bC;Je.setMaxListeners(0);$f=process.env.BOSTRAT_STATE_DIR||Ds.join(process.env.HOME||yC.tmpdir(),".bostrat");hk=(e,t)=>Ds.join(e,`${t}.ndjson`),Ul=new Map;TC=/(?<!\\)((?:\\\\)*)\\u0000/g,mk=e=>e.includes("\\u0000"),wk=e=>e.replace(TC,"$1\\ufffd")});import oe from"node:fs/promises";import EC from"node:os";import ve from"node:path";import{execFile as _C}from"node:child_process";import{promisify as IC}from"node:util";function Wl(){return ve.join(ql,"memory","repos")}function Co(e){return e===Zn?ve.join(ql,"memory",Zn):ve.join(Wl(),e)}async function hi(e){try{return JSON.parse(await oe.readFile(ve.join(e,Ak),"utf8"))}catch{return{}}}async function Mf(e,t){let n=await hi(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await oe.mkdir(e,{recursive:!0}),await oe.writeFile(ve.join(e,Ak),JSON.stringify(n))}function bk(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 kk(e){try{let{stdout:t}=await $C("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function Cf(e){if(!e)return[];let t=bk(await kk(e));if(t)return[t];let n=[],r=[];try{r=await oe.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=bk(await kk(ve.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function Kl(e){let t=/^---\n([\s\S]*?)\n---\n?/.exec(e);return t?{fm:t[1],body:e.slice(t[0].length)}:{fm:null,body:e}}function Cr(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function An(e,t=null){let n=t??await oe.readFile(e,"utf8").catch(()=>""),{fm:r}=Kl(n),o=Cr(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await oe.stat(e)).mtimeMs}catch{return 0}}function Tk(e,t){let n=Cr(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===Zn){let o=Cr(e,"trust");if(!o||/^operator/i.test(o))return Zn}return t}function Nf(e,t,n,r=new Map){let o=(e||"").split(`
17
17
  `),s=new Map;for(let c of(t||"").split(`
18
- `)){let l=xs(c);l&&c.trim().startsWith("-")&&s.set(l,c)}let a=new Set,i=o.map(c=>{let l=xs(c);return l?(a.add(l),n.has(l)&&s.has(l)?s.get(l):c):c});for(let[c,l]of s)a.has(c)||!n.has(c)||(a.add(c),i.push(l));for(let c of n){if(a.has(c))continue;let l=r.get(c);l&&i.push(l)}return i.join(`
18
+ `)){let l=Ls(c);l&&c.trim().startsWith("-")&&s.set(l,c)}let a=new Set,i=o.map(c=>{let l=Ls(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 Hb(e,t){let n=Ar(t,"name")||e.replace(/\.md$/,""),r=Ar(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function Ya(e){let t=[];try{t=await re.readdir(e,{withFileTypes:!0})}catch{return[]}return t.filter(n=>n.isFile()&&n.name.endsWith(".md")&&n.name!=="MEMORY.md").map(n=>n.name)}async function Wb(e,t){let n=be.join(e,".bostrat","memory"),r=await Ya(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=Bb.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let d of r){let p=be.join(n,d);if(o)try{if((await re.stat(p)).mtimeMs<o-VM)continue}catch{continue}let f;try{f=await re.readFile(p,"utf8")}catch{continue}let{fm:w}=Al(f),m=Ub(w,t);if(!m)continue;let g=xo(m),y=be.join(g,d),x=await Sn(p,f);if(l.has(g)||l.set(g,await Ja(g)),(l.get(g)[d]||0)>=x)continue;let b=await Sn(y).catch(()=>0);if(await re.access(y).then(()=>!0).catch(()=>!1)&&b>=x)continue;await re.mkdir(g,{recursive:!0}),await re.writeFile(y,f),c++;let I=a.get(g);I||a.set(g,I={won:new Set,generated:new Map}),I.won.add(d),I.generated.set(d,Hb(d,w)),i.has(m)||i.set(m,new Set),i.get(m).add(d)}let u=await re.readFile(be.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[d,p]of a){let f=be.join(d,"MEMORY.md"),w=await re.readFile(f,"utf8").catch(()=>"");await re.writeFile(f,Zp(w,u,p.won,p.generated))}return Bb.set(e,s),{harvested:c,changedByKey:i}}async function qb(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await re.access(be.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await Xp(r),a=await Wb(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 JM(){let e=be.join(Tl,"workspaces"),t=[];try{t=await re.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return qb(t.filter(n=>n.isDirectory()).map(n=>be.join(e,n.name)))}async function ZM(e,t){let n=xo(e),r=await Ja(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!YM.test(l)||l==="MEMORY.md")continue;let u=be.join(n,l),d=await re.access(u).then(()=>!0).catch(()=>!1),p=d?await Sn(u):0,f=Number(c.modified)||0;if(c.deleted){f>p&&(d&&await re.rm(u,{force:!0}),await Yp(n,[[l,f]]),d&&(a.push(l),i++));continue}d&&p>=f||(r[l]||0)>=f||(await re.mkdir(n,{recursive:!0}),await re.writeFile(u,String(c.content??"")),o.add(l),typeof c.indexLine=="string"&&c.indexLine.trim()&&s.set(l,c.indexLine),i++)}if(o.size||a.length){let c=be.join(n,"MEMORY.md"),l=await re.readFile(c,"utf8").catch(()=>""),u=Zp(l,[...s.values()].join(`
21
+ `)}function Ek(e,t){let n=Cr(t,"name")||e.replace(/\.md$/,""),r=Cr(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function mi(e){let t=[];try{t=await oe.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 _k(e,t){let n=ve.join(e,".bostrat","memory"),r=await mi(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=xk.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let d of r){let p=ve.join(n,d);if(o)try{if((await oe.stat(p)).mtimeMs<o-OC)continue}catch{continue}let f;try{f=await oe.readFile(p,"utf8")}catch{continue}let{fm:w}=Kl(f),h=Tk(w,t);if(!h)continue;let g=Co(h),y=ve.join(g,d),x=await An(p,f);if(l.has(g)||l.set(g,await hi(g)),(l.get(g)[d]||0)>=x)continue;let b=await An(y).catch(()=>0);if(await oe.access(y).then(()=>!0).catch(()=>!1)&&b>=x)continue;await oe.mkdir(g,{recursive:!0}),await oe.writeFile(y,f),c++;let _=a.get(g);_||a.set(g,_={won:new Set,generated:new Map}),_.won.add(d),_.generated.set(d,Ek(d,w)),i.has(h)||i.set(h,new Set),i.get(h).add(d)}let u=await oe.readFile(ve.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[d,p]of a){let f=ve.join(d,"MEMORY.md"),w=await oe.readFile(f,"utf8").catch(()=>"");await oe.writeFile(f,Nf(w,u,p.won,p.generated))}return xk.set(e,s),{harvested:c,changedByKey:i}}async function Ik(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await oe.access(ve.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await Cf(r),a=await _k(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 MC(){let e=ve.join(ql,"workspaces"),t=[];try{t=await oe.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return Ik(t.filter(n=>n.isDirectory()).map(n=>ve.join(e,n.name)))}async function PC(e,t){let n=Co(e),r=await hi(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!CC.test(l)||l==="MEMORY.md")continue;let u=ve.join(n,l),d=await oe.access(u).then(()=>!0).catch(()=>!1),p=d?await An(u):0,f=Number(c.modified)||0;if(c.deleted){f>p&&(d&&await oe.rm(u,{force:!0}),await Mf(n,[[l,f]]),d&&(a.push(l),i++));continue}d&&p>=f||(r[l]||0)>=f||(await oe.mkdir(n,{recursive:!0}),await oe.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=ve.join(n,"MEMORY.md"),l=await oe.readFile(c,"utf8").catch(()=>""),u=Nf(l,[...s.values()].join(`
22
22
  `),o);if(a.length){let d=new Set(a);u=u.split(`
23
- `).filter(p=>!d.has(xs(p))).join(`
24
- `)}await re.mkdir(n,{recursive:!0}),await re.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function El(e,t=null){let n=xo(e),r=t?.length?t:await Ya(n);if(!r.length)return{pushed:0,source:"empty"};let o=XM(await re.readFile(be.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=be.join(n,a),c;try{c=await re.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await Sn(i,c),indexLine:o.get(a)??null})}return kl(e,s)}async function QM(e,{timeoutMs:t}={}){let{facts:n,source:r}=await Ib(e,t?{timeoutMs:t}:{});n.length?await ZM(e,n):r==="plane"&&await El(e)}function eC(e){let t=e.split(`
25
- `);t.length>Nb&&(t=t.slice(0,Nb));let n=t.join(`
26
- `);for(;Buffer.byteLength(n,"utf8")>zM&&t.length;)t.pop(),n=t.join(`
27
- `);return n}async function nC(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=be.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let d=xo(u),p=await Ja(d);for(let[g,y]of Object.entries(p)){let x=be.join(n,g);await re.access(x).then(()=>!0).catch(()=>!1)&&await Sn(x)<=y&&(await re.rm(x,{force:!0}),o++)}let f=await Ya(d);if(!f.length)continue;await re.mkdir(n,{recursive:!0});for(let g of f){let y=be.join(d,g),x=be.join(n,g),b=await Sn(y),O=await Sn(x).catch(()=>0);await re.access(x).then(()=>!0).catch(()=>!1)&&O>=b||(await re.copyFile(y,x),r++)}let w=await re.readFile(be.join(d,"MEMORY.md"),"utf8").catch(()=>""),m=u===Yn?"## operator memory":`## repo: ${u}`;w.trim()&&s.push(t.length>1?`${m}
23
+ `).filter(p=>!d.has(Ls(p))).join(`
24
+ `)}await oe.mkdir(n,{recursive:!0}),await oe.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function Gl(e,t=null){let n=Co(e),r=t?.length?t:await mi(n);if(!r.length)return{pushed:0,source:"empty"};let o=NC(await oe.readFile(ve.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=ve.join(n,a),c;try{c=await oe.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await An(i,c),indexLine:o.get(a)??null})}return Fl(e,s)}async function DC(e,{timeoutMs:t}={}){let{facts:n,source:r}=await pk(e,t?{timeoutMs:t}:{});n.length?await PC(e,n):r==="plane"&&await Gl(e)}function BC(e){let t=e.split(`
25
+ `);t.length>yk&&(t=t.slice(0,yk));let n=t.join(`
26
+ `);for(;Buffer.byteLength(n,"utf8")>RC&&t.length;)t.pop(),n=t.join(`
27
+ `);return n}async function LC(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=ve.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let d=Co(u),p=await hi(d);for(let[g,y]of Object.entries(p)){let x=ve.join(n,g);await oe.access(x).then(()=>!0).catch(()=>!1)&&await An(x)<=y&&(await oe.rm(x,{force:!0}),o++)}let f=await mi(d);if(!f.length)continue;await oe.mkdir(n,{recursive:!0});for(let g of f){let y=ve.join(d,g),x=ve.join(n,g),b=await An(y),I=await An(x).catch(()=>0);await oe.access(x).then(()=>!0).catch(()=>!1)&&I>=b||(await oe.copyFile(y,x),r++)}let w=await oe.readFile(ve.join(d,"MEMORY.md"),"utf8").catch(()=>""),h=u===Zn?"## operator memory":`## repo: ${u}`;w.trim()&&s.push(t.length>1?`${h}
28
28
 
29
29
  ${w.trim()}`:w.trim())}if(!s.length)return o?{materialized:!1,reason:"empty-store",cleaned:o}:{materialized:!1,reason:"empty-store"};let i="_Shared Track memory (point-in-time facts). Verify file/line citations against the current code before acting on them; correct a wrong fact in place (bump `modified`, use `supersedes`) rather than working around it._\n\n"+s.join(`
30
30
 
31
31
  `)+`
32
- `,c=eC(i);await re.mkdir(n,{recursive:!0}),await re.writeFile(be.join(n,"MEMORY.md"),c);let l=be.join(n,"claude");return await re.mkdir(l,{recursive:!0}),await re.writeFile(be.join(l,"MEMORY.md"),tC,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function Kb(e){try{let t=await Xp(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,Yn];return await Promise.all(n.map(r=>QM(r,{timeoutMs:rC}))),await nC(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function Gb(){return{...rt,pending:ks.size,queued:Jp.size}}function zb(e){if(vl.has(e))return vl.get(e);Jp.add(e);let t=jb.then(async()=>{Jp.delete(e),vl.delete(e);let n=await ef(e);return rt.runs++,rt.lastRunAt=Date.now(),n.error?(rt.errors++,rt.lastError=n.error):rt.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return vl.set(e,t),jb=t.then(()=>{}),t}function _l(e,{delayMs:t=oC}={}){if(!e||typeof e!="string")return;rt.scheduled++;let n=ks.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{ks.delete(e),zb(e)},t);r.unref?.(),ks.set(e,r)}async function Qp(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await re.access(be.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=ks.get(e);r&&(clearTimeout(r),ks.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([zb(e),s])}finally{clearTimeout(o)}}async function Vb(e){return Va||(Va=(async()=>{try{Lb||(Lb=!0,await aC());let{harvested:t,changedByKey:n}=await qb(e);for(let[r,o]of n)await El(r,[...o]);return rt.reconciles++,rt.lastReconcileAt=Date.now(),rt.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return rt.errors++,rt.lastError=t?.message||String(t),{harvested:0,error:rt.lastError}}finally{Va=null}})(),Va)}function sC(){return be.join(Tl,"memory",".full-sweep-done")}async function Jb(){let e=sC();try{let t=JSON.parse(await re.readFile(e,"utf8"));return rt.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...rt.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await JM();for(let[o,s]of n)await El(o,[...s]);let r={at:Date.now(),harvested:t};return await re.mkdir(be.dirname(e),{recursive:!0}),await re.writeFile(e,JSON.stringify(r)),rt.backfill=r,{ran:!0,...r}}catch(t){return rt.errors++,rt.lastError=t?.message||String(t),{ran:!1,error:rt.lastError}}}async function aC(){let e=0,t=[];try{t=await re.readdir(Sl(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=be.join(Sl(),n.name),o=xo(Yn),s=new Set,a=new Map;for(let f of await Ya(r)){let w=be.join(r,f),m;try{m=await re.readFile(w,"utf8")}catch{continue}let{fm:g}=Al(m);if(Ub(g,n.name)!==Yn)continue;let y=be.join(o,f),x=await Sn(y).catch(()=>0),b=await Sn(w,m);await re.mkdir(o,{recursive:!0}),b>x&&await re.writeFile(y,m),await re.rm(w,{force:!0}),s.add(f),a.set(f,Hb(f,g)),e++}if(!s.size)continue;let i=Date.now();await Yp(r,[...s].map(f=>[f,i])),await kl(n.name,[...s].map(f=>({file:f,deleted:!0,modified:i})));let c=be.join(r,"MEMORY.md"),l=await re.readFile(c,"utf8").catch(()=>""),u=l.split(`
33
- `).filter(f=>!s.has(xs(f))).join(`
34
- `);await re.writeFile(c,u).catch(()=>{});let d=be.join(o,"MEMORY.md"),p=await re.readFile(d,"utf8").catch(()=>"");await re.writeFile(d,Zp(p,l,s,a))}return{moved:e}}async function Yb(){let e=[],t=[Yn];try{for(let n of await re.readdir(Sl(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=xo(n),o=await Ya(r),s=await Ja(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await re.readFile(be.join(r,i),"utf8").catch(()=>""),{fm:l}=Al(c);a.push({file:i,name:Ar(l,"name")||i.replace(/\.md$/,""),description:Ar(l,"description")||"",scope:Ar(l,"scope")||null,modified:await Sn(be.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function Xb(e,t){if(!/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/.test(t)||t==="MEMORY.md")throw new Error("bad fact filename");let n=xo(e),r=be.join(n,t);if(!await re.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await re.rm(r,{force:!0}),await Yp(n,[[t,s]]);let a=be.join(n,"MEMORY.md"),i=await re.readFile(a,"utf8").catch(()=>"");await re.writeFile(a,i.split(`
35
- `).filter(l=>xs(l)!==t).join(`
36
- `)).catch(()=>{});let c=await kl(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function ef(e){try{let t=await Xp(e),{harvested:n,changedByKey:r}=await Wb(e,t[0]||null);for(let[o,s]of r)await El(o,[...s]);return n>0&&await cC(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function cC(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,iC)}}await M({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var GM,Tl,Nb,zM,Yn,Fb,xs,Bb,VM,YM,XM,tC,rC,oC,ks,Jp,jb,rt,vl,Lb,Va,iC,Xa=K(()=>{$b();pe();GM=KM(qM),Tl=process.env.BOSTRAT_STATE_DIR||be.join(process.env.HOME||WM.tmpdir(),".bostrat"),Nb=200,zM=25*1024;Yn="operator";Fb=".tombstones.json";xs=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;Bb=new Map,VM=2e3;YM=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,XM=e=>{let t=new Map;for(let n of(e||"").split(`
37
- `)){let r=xs(n);r&&n.trim().startsWith("-")&&t.set(r,n)}return t};tC=`# Track memory
32
+ `,c=BC(i);await oe.mkdir(n,{recursive:!0}),await oe.writeFile(ve.join(n,"MEMORY.md"),c);let l=ve.join(n,"claude");return await oe.mkdir(l,{recursive:!0}),await oe.writeFile(ve.join(l,"MEMORY.md"),jC,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function $k(e){try{let t=await Cf(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,Zn];return await Promise.all(n.map(r=>DC(r,{timeoutMs:FC}))),await LC(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function Rk(){return{...rt,pending:js.size,queued:Of.size}}function Ok(e){if(Hl.has(e))return Hl.get(e);Of.add(e);let t=vk.then(async()=>{Of.delete(e),Hl.delete(e);let n=await Pf(e);return rt.runs++,rt.lastRunAt=Date.now(),n.error?(rt.errors++,rt.lastError=n.error):rt.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return Hl.set(e,t),vk=t.then(()=>{}),t}function zl(e,{delayMs:t=UC}={}){if(!e||typeof e!="string")return;rt.scheduled++;let n=js.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{js.delete(e),Ok(e)},t);r.unref?.(),js.set(e,r)}async function Vl(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await oe.access(ve.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=js.get(e);r&&(clearTimeout(r),js.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([Ok(e),s])}finally{clearTimeout(o)}}async function Mk(e){return fi||(fi=(async()=>{try{Sk||(Sk=!0,await WC());let{harvested:t,changedByKey:n}=await Ik(e);for(let[r,o]of n)await Gl(r,[...o]);return rt.reconciles++,rt.lastReconcileAt=Date.now(),rt.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return rt.errors++,rt.lastError=t?.message||String(t),{harvested:0,error:rt.lastError}}finally{fi=null}})(),fi)}function HC(){return ve.join(ql,"memory",".full-sweep-done")}async function Ck(){let e=HC();try{let t=JSON.parse(await oe.readFile(e,"utf8"));return rt.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...rt.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await MC();for(let[o,s]of n)await Gl(o,[...s]);let r={at:Date.now(),harvested:t};return await oe.mkdir(ve.dirname(e),{recursive:!0}),await oe.writeFile(e,JSON.stringify(r)),rt.backfill=r,{ran:!0,...r}}catch(t){return rt.errors++,rt.lastError=t?.message||String(t),{ran:!1,error:rt.lastError}}}async function WC(){let e=0,t=[];try{t=await oe.readdir(Wl(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=ve.join(Wl(),n.name),o=Co(Zn),s=new Set,a=new Map;for(let f of await mi(r)){let w=ve.join(r,f),h;try{h=await oe.readFile(w,"utf8")}catch{continue}let{fm:g}=Kl(h);if(Tk(g,n.name)!==Zn)continue;let y=ve.join(o,f),x=await An(y).catch(()=>0),b=await An(w,h);await oe.mkdir(o,{recursive:!0}),b>x&&await oe.writeFile(y,h),await oe.rm(w,{force:!0}),s.add(f),a.set(f,Ek(f,g)),e++}if(!s.size)continue;let i=Date.now();await Mf(r,[...s].map(f=>[f,i])),await Fl(n.name,[...s].map(f=>({file:f,deleted:!0,modified:i})));let c=ve.join(r,"MEMORY.md"),l=await oe.readFile(c,"utf8").catch(()=>""),u=l.split(`
33
+ `).filter(f=>!s.has(Ls(f))).join(`
34
+ `);await oe.writeFile(c,u).catch(()=>{});let d=ve.join(o,"MEMORY.md"),p=await oe.readFile(d,"utf8").catch(()=>"");await oe.writeFile(d,Nf(p,l,s,a))}return{moved:e}}async function Nk(){let e=[],t=[Zn];try{for(let n of await oe.readdir(Wl(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=Co(n),o=await mi(r),s=await hi(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await oe.readFile(ve.join(r,i),"utf8").catch(()=>""),{fm:l}=Kl(c);a.push({file:i,name:Cr(l,"name")||i.replace(/\.md$/,""),description:Cr(l,"description")||"",scope:Cr(l,"scope")||null,modified:await An(ve.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function Pk(e,t){if(!/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/.test(t)||t==="MEMORY.md")throw new Error("bad fact filename");let n=Co(e),r=ve.join(n,t);if(!await oe.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await oe.rm(r,{force:!0}),await Mf(n,[[t,s]]);let a=ve.join(n,"MEMORY.md"),i=await oe.readFile(a,"utf8").catch(()=>"");await oe.writeFile(a,i.split(`
35
+ `).filter(l=>Ls(l)!==t).join(`
36
+ `)).catch(()=>{});let c=await Fl(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function Pf(e){try{let t=await Cf(e),{harvested:n,changedByKey:r}=await _k(e,t[0]||null);for(let[o,s]of r)await Gl(o,[...s]);return n>0&&await KC(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function KC(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,qC)}}await C({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var $C,ql,yk,RC,Zn,Ak,Ls,xk,OC,CC,NC,jC,FC,UC,js,Of,vk,rt,Hl,Sk,fi,qC,wi=q(()=>{fk();he();$C=IC(_C),ql=process.env.BOSTRAT_STATE_DIR||ve.join(process.env.HOME||EC.tmpdir(),".bostrat"),yk=200,RC=25*1024;Zn="operator";Ak=".tombstones.json";Ls=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;xk=new Map,OC=2e3;CC=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,NC=e=>{let t=new Map;for(let n of(e||"").split(`
37
+ `)){let r=Ls(n);r&&n.trim().startsWith("-")&&t.set(r,n)}return t};jC=`# 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
- `;rC=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;oC=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,ks=new Map,Jp=new Set,jb=Promise.resolve(),rt={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};vl=new Map;Lb=!1,Va=null;iC=20});import Il from"node:fs/promises";import lC from"node:path";async function Et(e,t,{mode:n}={}){await Il.mkdir(lC.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++uC}.tmp`;try{await Il.writeFile(r,JSON.stringify(t,null,2)+`
43
- `,n!=null?{mode:n}:void 0),await Il.rename(r,e)}catch(o){throw await Il.unlink(r).catch(()=>{}),o}}var uC,Er=K(()=>{uC=0});import nk from"node:fs/promises";import rk from"node:os";import ok from"node:path";function He(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function ei(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),dC);try{return await gC(`${Oe(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function ak(){return Rl||(tf||=nk.readFile(sk(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>Rl={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>tf=null),tf)}async function Ol(){await Et(sk(),Rl).catch(()=>{})}function ek(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 ak(),n=ek(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=>ek(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>Zb&&(t.ops=t.ops.slice(-Zb)),await Ol()}function tk(){$l||($l=setTimeout(()=>{$l=null,vs().catch(()=>{})},yC),$l.unref?.())}function nf(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function kC(e,t=process.env){if(e.op==="record"){let n=await ei(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...Qa(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:wC()}]})},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 nk.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await ei(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...Qa(t),"content-type":"application/octet-stream"},body:n},t);if(!r.ok&&r.status!==400)throw nf(r.status);return r.status===400?{delivered:!1,rejected:(await r.json().catch(()=>null))?.error||"rejected"}:{delivered:!0}}if(e.op==="delete"){let n=await ei(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:Qa(t)},t);if(!n.ok)throw nf(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function vs({env:e=process.env,log:t=console,now:n=Date.now()}={}){return He(e)?Za||(Za=(async()=>{let r=await ak();xC(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await kC(a,e)}catch(c){if(!c?.refused)return tk(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<fC)return tk(),await Ol(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};t.error?.(`[content-plane] ALARM parking ${a.op} ${a.family}/${a.id} after ${a.refusals} refusals (${c.message}) \u2014 draining the ${r.ops.length-1} ops behind it`),r.ops.shift(),r.parked.push({...a,parkedAt:n,error:c.message}),r.parked.length>Qb&&(r.parked=r.parked.slice(-Qb)),s++,await Ol();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await Ol()}return{flushed:o,parked:s,pending:0}})().finally(()=>{Za=null}),Za):{flushed:0,source:"unconfigured"}}function xC(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=bC);if(n.length){e.parked=e.parked.filter(r=>!n.includes(r));for(let r of n)e.ops.push({...r,refusals:0,parkedAt:void 0,error:void 0})}}async function bt(e,t,{trackId:n=null,env:r=process.env}={}){return He(r)?(await rf({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),vs({env:r})):{queued:!1,source:"unconfigured"}}async function _r(e,t,n,r,o,{env:s=process.env}={}){return He(s)?(await rf({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),vs({env:s})):{queued:!1,source:"unconfigured"}}async function tn(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return He(r)?(await rf({op:"delete",family:e,id:t,deletedAt:n}),vs({env:r})):{queued:!1,source:"unconfigured"}}async function st(e,{env:t=process.env}={}){if(!He(t))return{records:[],source:"unconfigured"};try{let n=await ei(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:Qa(t)},t);if(!n.ok)throw new Error(`plane ${n.status}`);let r=await n.json();return{records:Array.isArray(r?.records)?r.records:[],source:"plane"}}catch(n){return{records:[],source:"unreachable",error:n?.message}}}async function ti(e,t,n,r,{env:o=process.env}={}){if(!He(o))return null;try{let s=await ei(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:Qa(o)},o);if(!s.ok)return null;let a=Buffer.from(await s.arrayBuffer());return r==="md"||r==="html"?a.toString("utf8"):a}catch{return null}}var dC,pC,Zb,fC,Qb,mC,hC,sk,wC,gC,yC,bC,Qa,Rl,tf,$l,Za,Ir=K(()=>{pt();Er();dC=1e4,pC=3e4,Zb=2e3,fC=5,Qb=100,mC=60*6e4,hC=()=>process.env.BOSTRAT_STATE_DIR||ok.join(process.env.HOME||rk.tmpdir(),".bostrat"),sk=()=>ok.join(hC(),"content-outbox.json"),wC=()=>process.env.BOSTRAT_NODE_ID||rk.hostname(),gC=(...e)=>fetch(...e),yC=pC,bC=mC;Qa=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});Rl=null,tf=null,$l=null,Za=null});import of from"node:fs/promises";import ik from"node:path";async function ck(e,t,{box:n=null,agent:r=null}={}){if(!e||!He())return{pushed:!1};try{let o=Date.now();return await bt("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await _r("checkpoints",e,o,"md",t),ni=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function EC(){if(ni&&Date.now()-ni.at<AC)return{records:ni.records,source:"plane"};let e=await st("checkpoints");return e.source==="plane"&&(ni={at:Date.now(),records:e.records}),e}async function Ml(e){try{let t=TC(e);if(!t||!He())return{restored:!1};let n=ik.join(e,vC,SC);if(await of.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await EC();if(o!=="plane")return{restored:!1};let s=r.find(i=>!i.deletedAt&&i.data?.id===t);if(!s?.data?.v)return{restored:!1};let a=await ti("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await of.mkdir(ik.dirname(n),{recursive:!0}),await of.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var vC,SC,TC,AC,ni,Cl=K(()=>{Ir();vC=".bostrat/handoff",SC="latest.md",TC=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;AC=6e4,ni=null});import ri from"node:fs/promises";import _C from"node:os";import uk from"node:path";function vo(e){let t=String(e??"");for(let n of IC)t=t.replace(n,"\u2039redacted\u203A");return t}function Nl(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function $C(e){try{await ri.mkdir(sf,{recursive:!0}),await ri.appendFile(Ss,`${JSON.stringify(e)}
44
- `,"utf8");let n=(await ri.readFile(Ss,"utf8")).split(`
45
- `).filter(Boolean);n.length>lk&&await ri.writeFile(Ss,`${n.slice(-lk).join(`
42
+ `;FC=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;UC=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,js=new Map,Of=new Set,vk=Promise.resolve(),rt={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};Hl=new Map;Sk=!1,fi=null;qC=20});import Jl from"node:fs/promises";import GC from"node:path";async function Rt(e,t,{mode:n}={}){await Jl.mkdir(GC.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++zC}.tmp`;try{await Jl.writeFile(r,JSON.stringify(t,null,2)+`
43
+ `,n!=null?{mode:n}:void 0),await Jl.rename(r,e)}catch(o){throw await Jl.unlink(r).catch(()=>{}),o}}var zC,Nr=q(()=>{zC=0});import Fk from"node:fs/promises";import Uk from"node:os";import Hk from"node:path";function Ue(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function bi(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),VC);try{return await eN(`${Re(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function qk(){return Xl||(Df||=Fk.readFile(Wk(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>Xl={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>Df=null),Df)}async function Zl(){await Rt(Wk(),Xl).catch(()=>{})}function jk(e){return e.op==="blob"?`blob ${e.family} ${e.id} ${e.v} ${e.kind}`:`${e.op} ${e.family} ${e.id}`}async function jf(e){let t=await qk(),n=jk(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=>jk(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>Dk&&(t.ops=t.ops.slice(-Dk)),await Zl()}function Lk(){Yl||(Yl=setTimeout(()=>{Yl=null,Fs().catch(()=>{})},tN),Yl.unref?.())}function Bf(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function rN(e,t=process.env){if(e.op==="record"){let n=await bi(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...yi(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:QC()}]})},t);if(!n.ok)throw Bf(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 Fk.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await bi(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...yi(t),"content-type":"application/octet-stream"},body:n},t);if(!r.ok&&r.status!==400)throw Bf(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 bi(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:yi(t)},t);if(!n.ok)throw Bf(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function Fs({env:e=process.env,log:t=console,now:n=Date.now()}={}){return Ue(e)?gi||(gi=(async()=>{let r=await qk();oN(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await rN(a,e)}catch(c){if(!c?.refused)return Lk(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<YC)return Lk(),await Zl(),{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>Bk&&(r.parked=r.parked.slice(-Bk)),s++,await Zl();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await Zl()}return{flushed:o,parked:s,pending:0}})().finally(()=>{gi=null}),gi):{flushed:0,source:"unconfigured"}}function oN(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=nN);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 vt(e,t,{trackId:n=null,env:r=process.env}={}){return Ue(r)?(await jf({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),Fs({env:r})):{queued:!1,source:"unconfigured"}}async function Pr(e,t,n,r,o,{env:s=process.env}={}){return Ue(s)?(await jf({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),Fs({env:s})):{queued:!1,source:"unconfigured"}}async function on(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return Ue(r)?(await jf({op:"delete",family:e,id:t,deletedAt:n}),Fs({env:r})):{queued:!1,source:"unconfigured"}}async function it(e,{env:t=process.env}={}){if(!Ue(t))return{records:[],source:"unconfigured"};try{let n=await bi(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:yi(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 ki(e,t,n,r,{env:o=process.env}={}){if(!Ue(o))return null;try{let s=await bi(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:yi(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 VC,JC,Dk,YC,Bk,XC,ZC,Wk,QC,eN,tN,nN,yi,Xl,Df,Yl,gi,Dr=q(()=>{mt();Nr();VC=1e4,JC=3e4,Dk=2e3,YC=5,Bk=100,XC=60*6e4,ZC=()=>process.env.BOSTRAT_STATE_DIR||Hk.join(process.env.HOME||Uk.tmpdir(),".bostrat"),Wk=()=>Hk.join(ZC(),"content-outbox.json"),QC=()=>process.env.BOSTRAT_NODE_ID||Uk.hostname(),eN=(...e)=>fetch(...e),tN=JC,nN=XC;yi=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});Xl=null,Df=null,Yl=null,gi=null});import Lf from"node:fs/promises";import Kk from"node:path";async function Gk(e,t,{box:n=null,agent:r=null}={}){if(!e||!Ue())return{pushed:!1};try{let o=Date.now();return await vt("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await Pr("checkpoints",e,o,"md",t),xi=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function lN(){if(xi&&Date.now()-xi.at<cN)return{records:xi.records,source:"plane"};let e=await it("checkpoints");return e.source==="plane"&&(xi={at:Date.now(),records:e.records}),e}async function Ql(e){try{let t=iN(e);if(!t||!Ue())return{restored:!1};let n=Kk.join(e,sN,aN);if(await Lf.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await lN();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 ki("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await Lf.mkdir(Kk.dirname(n),{recursive:!0}),await Lf.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var sN,aN,iN,cN,xi,eu=q(()=>{Dr();sN=".bostrat/handoff",aN="latest.md",iN=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;cN=6e4,xi=null});import vi from"node:fs/promises";import uN from"node:os";import Vk from"node:path";function No(e){let t=String(e??"");for(let n of dN)t=t.replace(n,"\u2039redacted\u203A");return t}function tu(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function pN(e){try{await vi.mkdir(Ff,{recursive:!0}),await vi.appendFile(Us,`${JSON.stringify(e)}
44
+ `,"utf8");let n=(await vi.readFile(Us,"utf8")).split(`
45
+ `).filter(Boolean);n.length>zk&&await vi.writeFile(Us,`${n.slice(-zk).join(`
46
46
  `)}
47
- `,"utf8")}catch(t){console.warn(`[handoff-debug] failed to write ${Ss}: ${t?.message||t}`)}}async function le(e={}){let t={at:new Date().toISOString(),ts:Date.now(),...e},n=[t.flow||"handoff",t.phase||t.step||"?",t.trackId?`track=${t.trackId}`:"",t.sessionName?`box=${t.sessionName}`:"",t.error?`ERR=${t.error}`:""].filter(Boolean).join(" \xB7 ");if(console.log(`[handoff-debug] ${n}`),t.sessionName&&Nl())try{t.paneTail=vo((await Be(t.sessionName,{lines:35})).slice(-4e3))}catch{t.paneTail=null}(Nl()||t.error||/^(checkpoint|spawn|hydrate|commit|done|summarize|clear|resume|ready|send|failed|launch|submit-|gate-accept|blocked|timeout|dialog)/.test(String(t.phase||t.step||"")))&&await $C(t)}async function dk({limit:e=80}={}){try{return(await ri.readFile(Ss,"utf8")).split(`
48
- `).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=vo(o.paneTail)),o}catch{return{raw:vo(r)}}})}catch{return[]}}var IC,sf,Ss,lk,pk,Tn=K(()=>{ct();IC=[/[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||uk.join(_C.homedir(),".bostrat","debug"),Ss=uk.join(sf,"handoff.jsonl"),lk=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;pk={DEBUG_DIR:sf,LOG_FILE:Ss}});import Pl from"node:fs/promises";import af from"node:path";import RC from"node:os";async function mk(e=fk){await Pl.mkdir(e,{recursive:!0});for(let t of MC){let n=t==="prepare-commit-msg"?CC:t==="post-commit"?NC:`${cf}exit 0
49
- `,r=af.join(e,t),o=null;try{o=await Pl.readFile(r,"utf8")}catch{}o!==n&&await Pl.writeFile(r,n,{mode:493}),await Pl.chmod(r,493).catch(()=>{})}return e}function hk({nodeUrl:e,dir:t=fk,env:n=process.env}={}){return String(n.BOSTRAT_GIT_HOOKS||"").toLowerCase()==="off"?[]:["-e","GIT_CONFIG_COUNT=1","-e","GIT_CONFIG_KEY_0=core.hooksPath","-e",`GIT_CONFIG_VALUE_0=${t}`,"-e",`${oi}=${e}`]}function wk(e=process.env){return e.BOSTRAT_NODE_URL||`http://127.0.0.1:${e.PORT||3362}`}var oi,OC,fk,MC,cf,CC,NC,lf=K(()=>{fs();oi="BOSTRAT_NODE_URL",OC=process.env.BOSTRAT_STATE_DIR||af.join(process.env.HOME||RC.tmpdir(),".bostrat"),fk=af.join(OC,"git-hooks"),MC=["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 ${Us}: ${t?.message||t}`)}}async function ue(e={}){let t={at:new Date().toISOString(),ts:Date.now(),...e},n=[t.flow||"handoff",t.phase||t.step||"?",t.trackId?`track=${t.trackId}`:"",t.sessionName?`box=${t.sessionName}`:"",t.error?`ERR=${t.error}`:""].filter(Boolean).join(" \xB7 ");if(console.log(`[handoff-debug] ${n}`),t.sessionName&&tu())try{t.paneTail=No((await Pe(t.sessionName,{lines:35})).slice(-4e3))}catch{t.paneTail=null}(tu()||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 pN(t)}async function Jk({limit:e=80}={}){try{return(await vi.readFile(Us,"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 dN,Ff,Us,zk,Yk,Tn=q(()=>{ut();dN=[/[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];Ff=process.env.BOSTRAT_DEBUG_DIR||Vk.join(uN.homedir(),".bostrat","debug"),Us=Vk.join(Ff,"handoff.jsonl"),zk=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;Yk={DEBUG_DIR:Ff,LOG_FILE:Us}});import nu from"node:fs/promises";import Uf from"node:path";import fN from"node:os";async function Zk(e=Xk){await nu.mkdir(e,{recursive:!0});for(let t of mN){let n=t==="prepare-commit-msg"?wN:t==="post-commit"?gN:`${Hf}exit 0
49
+ `,r=Uf.join(e,t),o=null;try{o=await nu.readFile(r,"utf8")}catch{}o!==n&&await nu.writeFile(r,n,{mode:493}),await nu.chmod(r,493).catch(()=>{})}return e}function Qk({nodeUrl:e,dir:t=Xk,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",`${Si}=${e}`]}function e0(e=process.env){return e.BOSTRAT_NODE_URL||`http://127.0.0.1:${e.PORT||3362}`}var Si,hN,Xk,mN,Hf,wN,gN,Wf=q(()=>{Rs();Si="BOSTRAT_NODE_URL",hN=process.env.BOSTRAT_STATE_DIR||Uf.join(process.env.HOME||fN.tmpdir(),".bostrat"),Xk=Uf.join(hN,"git-hooks"),mN=["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"],Hf=`#!/bin/sh
50
50
  # bostrat git hook shim (agent/src/git-hooks.js) \u2014 chains to the repo's own hook,
51
51
  # then stamps/reports for rework attribution when running inside a bostrat box.
52
52
  hook=$(basename "$0")
@@ -61,75 +61,75 @@ esac
61
61
  if [ -x "$orig/$hook" ] && [ "$orig/$hook" != "$0" ]; then
62
62
  "$orig/$hook" "$@" || exit $?
63
63
  fi
64
- `,CC=`${cf}
64
+ `,wN=`${Hf}
65
65
  # \u2500\u2500 bostrat: append provenance trailers (Layer 0). Skipped for merge commits
66
66
  # (nobody "wrote" a merge) and outside a box (no token / no node url).
67
- [ -z "$${zn}" ] && exit 0
68
- [ -z "$${oi}" ] && exit 0
67
+ [ -z "$${Jn}" ] && exit 0
68
+ [ -z "$${Si}" ] && exit 0
69
69
  [ "$2" = "merge" ] && exit 0
70
- trailers=$(curl -sS -m 3 -H "${Vn}: $${zn}" "$${oi}/api/git/trailers" 2>/dev/null) || exit 0
70
+ trailers=$(curl -sS -m 3 -H "${Yn}: $${Jn}" "$${Si}/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
- `,NC=`${cf}
76
+ `,gN=`${Hf}
77
77
  # \u2500\u2500 bostrat: report the commit (code.committed + rework analysis, node-side).
78
- [ -z "$${zn}" ] && exit 0
79
- [ -z "$${oi}" ] && exit 0
78
+ [ -z "$${Jn}" ] && exit 0
79
+ [ -z "$${Si}" ] && exit 0
80
80
  sha=$(git rev-parse HEAD 2>/dev/null) || exit 0
81
81
  cwd=$(git rev-parse --show-toplevel 2>/dev/null)
82
- printf '{"sha":"%s","cwd":"%s"}' "$sha" "$cwd" | curl -sS -m 5 -X POST "$${oi}/api/git/committed" \\
83
- -H 'content-type: application/json' -H "${Vn}: $${zn}" --data-binary @- >/dev/null 2>&1 || true
82
+ printf '{"sha":"%s","cwd":"%s"}' "$sha" "$cwd" | curl -sS -m 5 -X POST "$${Si}/api/git/committed" \\
83
+ -H 'content-type: application/json' -H "${Yn}: $${Jn}" --data-binary @- >/dev/null 2>&1 || true
84
84
  exit 0
85
- `});import{execFile as yk}from"node:child_process";import{promisify as PC}from"node:util";import Bl from"node:fs";import{randomUUID as bk}from"node:crypto";function So(e){return new Promise(t=>setTimeout(t,e))}function Dl(e,t){if(!t)return e;let n=o=>typeof o=="string"?o.split(t).join("<redacted>"):o,r=new Error(n(e?.message)||"command failed");return e?.code!==void 0&&(r.code=e.code),e?.stderr!==void 0&&(r.stderr=n(e.stderr)),r}function kk(e){return`/tmp/tmux-${e}/default`}function DC({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=kk(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function ai(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${si}=1`]}function ii(e,t,n){let r=To(e),o=/(^|\s)(--session-id|--resume|--continue|-r|-c)(\s|=|$)/.test(e);if(!r||o)return e;let s=`${e} --session-id ${t}`,a=/(^|\s)(--name|-n)(\s|=)/.test(e);return n&&!a&&je(n)&&(s+=` --name ${n}`),s}function To(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function $r(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function LC(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:To(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function xk(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await vk(e,{loginShell:t});return r===jl?!0:r===Ts?!1:n}async function vk(e,{loginShell:t=!1,timeoutMs:n=uf}={}){if(!e)return Ts;let r=t?process.env.SHELL||"/bin/sh":"sh",o=t?"-lic":"-c";try{return await Ie(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),jl}catch(s){return s?.killed||s?.signal?As:s?.code===1||s?.code===127?Ts:As}}async function Ll(e,{retries:t=FC,sleep:n=UC,probe:r=vk}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:uf});for(let a=0;s===As&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:uf*2});return s}function Q(...e){return["-S",Ot,...e]}async function Rr(){if(!Bl.existsSync(Ot))return!1;try{return await Ie(X,Q("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function ci(){if(await Rr())return!0;try{Bl.mkdirSync(Ot.replace(/\/[^/]+$/,""),{recursive:!0}),await Ie(X,Q("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await Rr()}function je(e){return typeof e=="string"&&HC.test(e)}async function nn(){if(!Bl.existsSync(Ot))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(X,Q("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
86
- `).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,d,p,f,w]=r.split("|"),m=Number(i),g=Number(w);return{name:o,title:u||null,windows:Number(s),attached:Number(a),lastActivityMs:Number.isFinite(m)?n-m*1e3:null,cwd:c||null,isBostrat:l==="1",sessionId:d||null,agent:p||(l==="1"?"claude":null),alternateOn:f==="1",createdMs:Number.isFinite(g)&&g>0?g*1e3:null}}).filter(r=>!jC.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function ke(e){return(await nn()).find(n=>n.name===e)||null}function KC(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=qC&&WC.test(t)}function Fl(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function Sk(e){try{let{stdout:t}=await Ie(X,Q("list-sessions","-F","#{session_name}"));return t.split(`
87
- `).map(n=>n.trim()).includes(e)}catch{return!1}}function VC(e){let t=String(e||"").trim().split(/\s+/)[0]||"";if(t.includes("/"))return null;let n=[],r=s=>/[A-Za-z0-9_]/.test(s);for(let s=1;s<=t.length-3;s++)r(t[s-1])===r(t[s])&&n.push(t.slice(s));if(!n.length)return null;let o=n.map(s=>s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp(`\\b(?:${o.join("|")})`)}async function JC(e,t){let n=Date.now()+li(),r=VC(t),o=!1,s=0,a=0;for(;;){if(await So(GC),s+=1,!await Sk(e))return;let i=await Be(e,{lines:15}),c=!o&&zC.test(i)&&!!r?.test(i),l=!o&&!!r?.test(i);if(!c&&!l&&s>1&&!await Xn(e)){if(a+=1,a>1)return}else c||(a=0);if(c){o=!0,await le({flow:"spawn",phase:"launch-retry",sessionName:e,agent:$r(t),promptHead:t.slice(0,120)}).catch(()=>{}),await Ie(X,Q("send-keys","-t",e,"C-u")),await Ie(X,Q("send-keys","-t",e,"-l",t)),await Ie(X,Q("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await le({flow:"spawn",phase:"launch-failed",sessionName:e,agent:$r(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function Or(e,t=BC,n={}){if(!KC(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=Fl(r);if(!je(o))throw new Error("resulting tmux session name is invalid");if(!await ci())throw new Error(`host tmux server not running on ${Ot} and auto-start failed \u2014 start one: ${X} -S ${Ot} new-session -d -s keeper "sleep 2147483647"`);if(await Sk(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||df,a=n.agent||$r(s),i=!!n.resumeSessionId,c=n.resumeSessionId||bk(),l=i?s:ii(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&To(s),p=n.firstRun===!0;p||(d&&await vr(t),a==="codex"&&await ms(t),a==="cursor"&&await hs(t),await Kb(t),n.freshWorkspace!==!0&&await Ml(t));let f=d&&!p?fl():null,w=db(),m=["-e",`${zn}=${w}`];m.push(...hk({nodeUrl:wk()})),f&&m.push("-e",`ANTHROPIC_API_KEY=${f}`),d&&m.push(...ai());try{await Ie(X,Q("new-session","-d","-s",o,"-c",t,...m))}catch(g){throw Dl(f?Dl(g,f):g,w)}return await Ao(o),await Ie(X,Q("set-option","-t",o,"@bostrat-session","1")),await Ie(X,Q("set-option","-t",o,"@bostrat-title",r)),await Ie(X,Q("set-option","-t",o,"@bostrat-sid",c)),await Ie(X,Q("set-option","-t",o,"@bostrat-agent",a)),await Ie(X,Q("send-keys","-t",o,l,"Enter")),LC(l)&&JC(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:w}}async function rn(e){if(!je(e))throw new Error("invalid session name");await Ie(X,Q("kill-session","-t",e))}async function Tk(e,t){if(je(e))try{let n=t?Q("set-option","-t",e,"@bostrat-sid",t):Q("set-option","-u","-t",e,"@bostrat-sid");await Ie(X,n)}catch{}}async function Be(e,{lines:t=40}={}){if(!je(e))return"";try{let n=Q("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await Ie(X,n);return String(r||"")}catch{return""}}async function Ak(e){if(!je(e))return[];try{let{stdout:t}=await Ie(X,Q("list-panes","-s","-t",e,"-F","#{pane_pid}"));return String(t||"").trim().split(`
88
- `).map(n=>Number(n.trim())).filter(n=>Number.isFinite(n)&&n>0)}catch{return[]}}async function Ek(e){if(!je(e))return 0;try{let{stdout:t}=await Ie(X,Q("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
89
- `).filter(Boolean).length}catch{return 0}}async function Ao(e,{cols:t=ZC,rows:n=QC}={}){if(!je(e))return!0;if(await Ek(e))return!1;try{let r=await _k(e);if(r.cols===t&&r.rows===n)return!0;await Ie(X,Q("resize-window","-t",e,"-x",String(t),"-y",String(n))),await Ie(X,Q("set-window-option","-t",e,"window-size","latest")),await So(80)}catch{}return!0}async function eN(e){if(!je(e))return 0;try{let{stdout:t}=await Ie(X,Q("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function Xn(e){let t=await eN(e);if(!t)return!1;try{return await Ie("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function _k(e){if(!je(e))return{cols:0,rows:0};try{let{stdout:t}=await Ie(X,Q("display-message","-t",e,"-p","#{window_width} #{window_height}")),[n,r]=String(t||"").trim().split(/\s+/).map(o=>Number(o)||0);return{cols:n,rows:r}}catch{return{cols:0,rows:0}}}async function Ul(e,{cols:t=YC,rows:n=XC}={}){if(je(e)&&!await Ek(e))try{let r=await _k(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await Ie(X,Q("resize-window","-t",e,"-x",String(o),"-y",String(s))),await Ie(X,Q("set-window-option","-t",e,"window-size","latest")),await So(80))}catch{}}async function on(e){return await Ul(e),Be(e,{lines:Ze})}async function qe(e,t,{settleMs:n=40,kind:r}={}){if(!je(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>Ik.has(s));for(let s=0;s<o.length;s++)await Ie(X,Q("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await So(n);return le({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function mf(e,t,{settleMs:n=40,kind:r}={}){if(!je(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[]).filter(s=>s&&(typeof s.key=="string"&&Ik.has(s.key)||typeof s.text=="string"&&s.text.length>0));for(let s=0;s<o.length;s++){let a=o[s];a.text!=null?await Ie(X,Q("send-keys","-t",e,"-l",a.text)):await Ie(X,Q("send-keys","-t",e,a.key)),n>0&&s<o.length-1&&await So(n)}return le({flow:"tmux",phase:"send-sequence",sessionName:e,kind:r||"sequence",steps:o.map(s=>s.text!=null?`\u2039text:${s.text.length}\u203A`:s.key).join(" ")}).catch(()=>{}),o.length}async function Es(e,t,{kind:n}={}){if(!je(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await Ie(X,Q("send-keys","-t",e,"-N",String(r),"BSpace")),le({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function Wl(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!je(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await Ie(X,Q("send-keys","-t",e,"-l",s)),n>0&&await So(n);le({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function tN(e,t){return new Promise((n,r)=>{let o=yk(X,Q(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function nN(e,t){let n=`bostrat-${bk().slice(0,8)}`;await tN(["load-buffer","-b",n,"-"],t),await Ie(X,Q("paste-buffer","-p","-d","-b",n,"-t",e))}async function ot(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!je(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await nN(e,t):await Ie(X,Q("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await So(a),await Ie(X,Q("send-keys","-t",e,"Enter"))}le({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,X,gk,Ot,BC,df,si,pf,jC,jl,Ts,As,uf,FC,UC,ff,HC,WC,qC,li,GC,zC,YC,XC,Ze,ZC,QC,Ik,Hl,ct=K(()=>{qa();hl();wl();Xa();Cl();Tn();fs();lf();Ie=PC(yk);X=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";gk=typeof process.getuid=="function"?process.getuid():0,Ot=DC({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return Bl.existsSync(kk(gk))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:gk}),BC=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",df=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",si="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";pf="bostrat-usage-probe",jC=new Set([pf]);jl="present",Ts="absent",As="unknown",uf=5e3,FC=[250,1e3,3e3],UC=e=>new Promise(t=>setTimeout(t,e));ff={claude:"npm install -g @anthropic-ai/claude-code",codex:"npm install -g @openai/codex","cursor-agent":"curl https://cursor.com/install -fsS | bash",gh:"apt install gh (Debian: enable cli.github.com/packages) / brew install gh \u2014 see https://github.com/cli/cli#installation"};HC=/^[A-Za-z0-9_.-]{1,64}$/;WC=/^[A-Za-z0-9 ._↻-]+$/,qC=64;li=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,GC=1e3,zC=/not found|Unknown command/i;YC=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,XC=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,Ze=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,ZC=Number(process.env.BOSTRAT_BOX_COLS)||120,QC=Number(process.env.BOSTRAT_BOX_ROWS)||40;Ik=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);Hl=1600});import ui from"node:fs";import cN from"node:fs/promises";import _s from"node:path";import lN from"node:os";function gf(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function yf(e){let t=_s.join(wf,gf(e)),n;try{n=ui.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=_s.join(t,o);try{let{mtimeMs:a}=ui.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function sn(e,t){if(!t)return null;let n=_s.join(wf,gf(e),`${t}.jsonl`);return ui.existsSync(n)?n:null}function Pk(e){if(!e)return[];let t=_s.join(wf,gf(e)),n;try{n=ui.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=ui.statSync(_s.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function _t(e,t=131072){let n=await cN.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 dN(e){let t=e.split(`
90
- `);for(let n=t.length-1;n>=0;n--){let r=t[n].trim();if(!r||r[0]!=="{")continue;let o;try{o=JSON.parse(r)}catch{continue}let s=o?.message?.usage;if(!s)continue;let a=(s.input_tokens||0)+(s.cache_creation_input_tokens||0)+(s.cache_read_input_tokens||0);if(a>0)return{occupancy:a,model:o.message.model||o.model||null}}return null}async function di(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=sn(e,t),o=!0,!r)return null}else if(n){if(r=yf(e),o=!1,!r)return null}else return null;let s;try{s=dN(await _t(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(Nk,s.model),i=Nk[s.model]||uN;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 Nk,uN,wf,an=K(()=>{Nk={"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},uN=2e5,wf=process.env.BOSTRAT_CLAUDE_PROJECTS||_s.join(lN.homedir(),".claude","projects")});function pN(e){let t=[],n="",r=null;for(let o=0;o<e.length;o++){let s=e[o];if(r){n+=s,s===r&&e[o-1]!=="\\"&&(r=null);continue}if(s==="'"||s==='"'||s==="`"){r=s,n+=s;continue}if(s==="&"&&e[o+1]==="&"){t.push(n),n="",o++;continue}if(s==="|"&&e[o+1]==="|"){t.push(n),n="",o++;continue}if(s==="|"||s===";"||s===`
91
- `){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function pi(e){let t=[],n="",r=null,o=!1,s=()=>{if(o){if(/^\d*[<>]/.test(n)||n.startsWith(">")){n="",o=!1;return}t.push(n),n="",o=!1}};for(let a=0;a<e.length;a++){let i=e[a];if(r){i===r&&e[a-1]!=="\\"?r=null:n+=i,o=!0;continue}if(i==="'"||i==='"'){r=i,o=!0;continue}if(i==="<"&&e[a+1]==="<")return s(),t.push("<<"),t;if(/\s/.test(i)){s();continue}n+=i,o=!0}return s(),t}function fi(e){let t=e;for(;t.length&&/^[A-Za-z_][A-Za-z0-9_]*=/.test(t[0]);)t=t.slice(1);for(;t.length&&(t[0]==="sudo"||t[0]==="time"||t[0]==="env");)t=t.slice(1);return t}function Pe(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(jk(o)){t.has(o)&&r++;continue}n.push(o)}return n}function Lk(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 hN(e){let t=Lk(e),n=ft(Pe(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${ze(n)}`:`Read lines ${t.from}\u2013${t.to} of ${ze(n)}`:e.includes("-i")&&n?`Edit ${ze(n)}`:null}function bf(e){if(e.includes("--files")){let s=ft(Pe(e,Dk)[0]);return s&&s!=="."?`List files in ${Is(s)}`:"List files"}let t=Pe(e,Dk),n=t[0];if(!n)return null;let r=ft(t.slice(1).find(s=>s!==".")),o=$s(n,40);return r?`Search for \u201C${o}\u201D in ${Is(r)}`:`Search for \u201C${o}\u201D`}function kf(e){let t=Pe(e,new Set(["--prefix"])),n=t[0];return n?n==="test"||n==="t"?"Run tests":n==="run"||n==="run-script"?t[1]?`Run ${t[1]}`:null:n==="ci"||n==="install"||n==="i"||n==="add"?"Install dependencies":null:null}function xf(e,t){if(e.includes("-e")||e.includes("--eval")||e.includes("-c")||e[1]==="-"||e.includes("<<"))return`Run an inline ${t} script`;if(e.includes("--test"))return"Run tests";let n=Pe(e)[0];return n?`Run ${ze(n)}`:null}function wN(e){let t=Pe(e),n=t[0],r=t.find(a=>/\.(service|timer|socket|target)$/.test(a))||t[1],o=r?r.replace(/\.service$/,""):"a service";return{status:`Check ${o} status`,show:`Inspect ${o}`,restart:`Restart ${o}`,start:`Start ${o}`,stop:`Stop ${o}`,"daemon-reload":"Reload systemd"}[n]||null}function Bk(e){return e.find(t=>/^https?:\/\//.test(t))||null}function bN(e){let t=fi(pi(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(ze(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return vf(t[2]);let n=ze(t[0]);if(yN.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=gN[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function vf(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
92
- `,n);i!==-1&&(t=t.slice(0,i))}let r=pN(t);for(let i=0;i<r.length-1;i++){let c=fi(pi(r[i])),l=fi(pi(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(ze(c[0]))&&ze(l[0])==="sed"){let u=Lk(l),d=Pe(c)[0];if(u&&d)return $s(u.from===u.to?`Read line ${u.from} of ${ze(d)}`:`Read lines ${u.from}\u2013${u.to} of ${ze(d)}`,88)}}let o=[];for(let i of r){let c=bN(i);c&&o.push({d:c,head:ze(fi(pi(i))[0]||""),sub:Pe(fi(pi(i)))[0]})}if(!o.length)return null;let s=o.find(i=>i.head==="git"&&i.sub==="commit"),a=o.find(i=>i.head==="git"&&i.sub==="push");return s&&a?"Commit and push changes":$s(s?s.d:o[0].d,88)}var $s,ft,ze,Is,jk,Dk,fN,mN,gN,yN,Fk=K(()=>{$s=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,ft=e=>e&&!/[$`]/.test(e)?e:null,ze=e=>e.replace(/\/+$/,"").split("/").pop()||e,Is=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},jk=e=>e.startsWith("-"),Dk=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);fN={status:()=>"Check git status",diff:()=>"Review changes",log:()=>"Review commit history",show:()=>"Inspect a commit",add:()=>"Stage files",commit:()=>"Commit changes",push:()=>"Push to remote",pull:()=>"Pull from remote",fetch:()=>"Fetch from remote",merge:()=>"Merge branches",rebase:()=>"Rebase branch",stash:()=>"Stash changes",clone:e=>e[1]?`Clone ${ze(e[1])}`:"Clone repository",checkout:()=>"Switch branches",switch:()=>"Switch branches",restore:()=>"Restore files",reset:()=>"Reset git state",branch:(e,t)=>t.includes("--show-current")?"Check current branch":"List branches",remote:()=>"Check git remotes","rev-parse":()=>"Resolve a git ref",worktree:()=>"Manage git worktrees","merge-base":()=>"Find the merge base","ls-files":()=>"List tracked files"},mN={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"};gN={git:e=>{let t=Pe(e,new Set(["-C","-c"])),n=fN[t[0]];return n?n(t,e):null},gh:e=>{let t=Pe(e),n=mN[t[0]];return n?n(t):null},sed:hN,rg:bf,grep:bf,egrep:bf,nl:e=>{let t=ft(Pe(e)[0]);return t?`Read ${ze(t)}`:null},cat:e=>{let t=ft(Pe(e)[0]);return t?`Read ${ze(t)}`:null},head:e=>{let t=ft(Pe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${ze(t)}`:null},tail:e=>{let t=ft(Pe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${ze(t)}`:null},wc:e=>{let t=ft(Pe(e)[0]);return t?`Count lines in ${ze(t)}`:"Count input lines"},ls:e=>{let t=ft(Pe(e)[0]);return t&&t!=="."?`List files in ${Is(t)}`:"List files"},find:e=>ft(e[1])&&!jk(e[1])&&e[1]!=="."?`Find files in ${Is(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=ft(Pe(e)[0]);return t?`Create directory ${Is(t)}`:null},touch:e=>{let t=ft(Pe(e)[0]);return t?`Create ${ze(t)}`:null},rm:e=>{let t=ft(Pe(e)[0]);return t?`Delete ${Is(t)}`:null},mv:e=>{let t=ft(Pe(e)[0]);return t?`Move ${ze(t)}`:null},cp:e=>{let t=ft(Pe(e)[0]);return t?`Copy ${ze(t)}`:null},chmod:e=>{let t=ft(Pe(e)[1]);return t?`Change permissions on ${ze(t)}`:null},diff:e=>{let t=Pe(e);return t.length>=2?`Compare ${ze(t[0])} and ${ze(t[1])}`:null},curl:e=>{let t=Bk(e);return t?`Fetch ${$s(t,56)}`:"Fetch a URL"},wget:e=>{let t=Bk(e);return t?`Fetch ${$s(t,56)}`:"Fetch a URL"},npm:kf,pnpm:kf,yarn:kf,npx:e=>{let t=Pe(e)[0];return t?`Run ${t}`:null},node:e=>xf(e,"Node"),python:e=>xf(e,"Python"),python3:e=>xf(e,"Python"),make:e=>{let t=Pe(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:wN,journalctl:e=>{let t=e.findIndex(r=>r==="-u"||r==="--unit"||r==="--user-unit"),n=t!==-1?e[t+1]:null;return n?`Read ${n.replace(/\.service$/,"")} logs`:"Read system logs"},tmux:e=>{let t=Pe(e,new Set(["-S","-L","-t","-f"]))[0];return{ls:"List tmux sessions","list-sessions":"List tmux sessions","kill-session":"Kill a tmux session","send-keys":"Send keys to a tmux session","capture-pane":"Capture a tmux pane","new-session":"Start a tmux session"}[t]||null},ps:()=>"List processes",which:e=>{let t=Pe(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=Pe(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},yN=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function Rs(e){let t=e.split(`
93
- `).map(n=>n.trim()).find(Boolean)||e;return t.length>88?`${t.slice(0,88).trimEnd()}\u2026`:t}function Mr(e,t=""){let n=t.trim();return n||vf(e)||Rs(e)}function Sf(e,t){if(e){if(Array.isArray(e)){for(let n of e)Sf(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&Tf.has(e.name)){let n=String(e.input?.command||"").trim();n&&t.push({id:e.id||null,tool:e.name,command:n,description:String(e.input?.description||"").trim()})}for(let n of Object.values(e))Sf(n,t)}}}async function Uk(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await _t(e,t)}catch{return[]}let o=[];for(let s of r.split(`
94
- `)){let a=s.trim();if(!a||a[0]!=="{")continue;let i;try{i=JSON.parse(a)}catch{continue}let c=i.message;if(!c)continue;let l=[];if(Sf(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:Mr(d.command,d.description),ts:u})}return o.slice(-n)}function Hk(e,t){let n=a=>a?.box??null,r=new Map;for(let a of t||[]){if(a.role!=="assistant"||!(a.text||"").trim())continue;let i=n(a);r.has(i)||r.set(i,[]),r.get(i).push(a)}let o=new Map;for(let a of e||[]){let i=n(a);o.has(i)||o.set(i,[]),o.get(i).push(a)}let s=[];for(let[a,i]of o)s.push(...kN(i,r.get(a)||[]));return s.sort((a,i)=>(a.ts||0)-(i.ts||0))}function kN(e,t){let n=[...t].sort((l,u)=>(l.ts||0)-(u.ts||0)),r=[...e].sort((l,u)=>(l.ts||0)-(u.ts||0)),o=[],s=0,a=0,i=l=>{let u=l.n??a+1;return u>a&&(a=u),u};for(let l of n){let u=r.findIndex((w,m)=>m>=s&&(w.ts||0)>(l.ts||0)),d=u===-1?r.length:u,p=r.slice(s,d);if(s=d,!p.length)continue;let f=p.map(w=>({...w,n:i(w)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:f,ts:Math.max(...f.map(w=>w.ts||0)),pending:!1})}let c=r.slice(s);if(c.length){let l=c.map(u=>({...u,n:i(u)}));o.push({id:`batch-pending-${l[0]?.box||"lead"}`,anchorTs:null,anchorBox:l[l.length-1]?.box??null,agent:l[l.length-1]?.agent??"claude",boxRole:l[l.length-1]?.boxRole??"lead",commands:l,ts:Math.max(...l.map(u=>u.ts||0)),pending:!0})}return o}var Tf,Os=K(()=>{an();Fk();Tf=new Set(["Bash"])});import Wk from"node:fs";import Ef from"node:fs/promises";import Af from"node:path";import xN from"node:os";async function qk(e){try{return await Ef.realpath(e)}catch{return e}}function SN(e=vN){let t=[],n=r=>{let o;try{o=Wk.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=Af.join(r,s.name);if(s.isDirectory())n(a);else if(s.isFile()&&s.name.startsWith("rollout-")&&s.name.endsWith(".jsonl")){let i=/-([0-9a-f-]{36})\.jsonl$/i.exec(s.name);try{t.push({id:i?i[1]:null,file:a,mtimeMs:Wk.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function TN(e,t=1048576){let n;try{n=await Ef.open(e,"r")}catch{return""}try{let r=Buffer.alloc(Math.min(t,65536)),o="",s=0;for(;;){let{bytesRead:a}=await n.read(r,0,r.length,s);if(!a)break;o+=r.toString("utf8",0,a);let i=o.indexOf(`
95
- `);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=t)break}return o}finally{await n.close()}}async function AN(e){let t=await TN(e);if(!t)return null;let n;try{n=JSON.parse(t)}catch{return null}return n?.type==="session_meta"&&n?.payload?.cwd||null}async function Eo(e,t){if(!e&&!t)return null;let n=SN();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await qk(e);for(let o of n){let s=await AN(o.file);if(s&&(s===e||await qk(s)===r))return o}return null}async function Kk(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await Eo(e,t);if(!o)return[];let s;try{s=await _t(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,d=null;for(let p of s.split(`
96
- `)){let f=p.trim();if(!f||f[0]!=="{")continue;let w;try{w=JSON.parse(f)}catch{continue}if((w.type==="turn_context"&&w.payload?.model||w.type==="session_meta"&&w.payload?.model)&&(i=w.payload.model),w.type==="event_msg"){let x=w.payload?.type;x==="task_started"?(l=!0,u=!1,d=w.payload?.turn_id||null):x==="task_complete"&&l&&(l=!1,!u&&w.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:_o,sourceId:w.payload?.turn_id||d||void 0,ts:w.timestamp?Date.parse(w.timestamp):null,model:i}));continue}if(w.type!=="response_item")continue;let m=w.payload;if(!m)continue;if((m.type==="function_call"||m.type==="custom_tool_call")&&m.name){u=!0,_f.has(m.name)||c.push(m.name);continue}if(m.type!=="message"||m.role!=="assistant")continue;u=!0;let g=_N(m.content),y=c.length?c.slice():null;c=[],!(!g&&!y)&&a.push({role:"assistant",text:g,tools:y||void 0,ts:w.timestamp?Date.parse(w.timestamp):null,model:i})}if(i)for(let p of a)p.model||(p.model=i);return a.slice(-n)}function IN(e){if(typeof e?.cmd=="string"&&e.cmd.trim())return e.cmd.trim();let t=e?.command;return typeof t=="string"&&t.trim()?t.trim():Array.isArray(t)&&t.length?t.length===3&&/^(ba)?sh$/.test(t[0])&&t[1]==="-lc"?String(t[2]).trim():t.map(String).join(" ").trim():null}function $N(e){let t=e[0];if(t!=='"'&&t!=="'"&&t!=="`")return null;let n="";for(let r=1;r<e.length;r++){let o=e[r];if(o==="\\"){let s=e[++r];if(s===void 0)return null;if(s==="n")n+=`
97
- `;else if(s==="t")n+=" ";else if(s==="r")n+="\r";else if(s==="u")if(e[r+1]==="{"){let a=e.indexOf("}",r+2);if(a===-1)return null;n+=String.fromCodePoint(parseInt(e.slice(r+2,a),16)),r=a}else n+=String.fromCharCode(parseInt(e.slice(r+1,r+5),16)),r+=4;else n+=s}else{if(o===t)return n;if(t==="`"&&o==="$"&&e[r+1]==="{")return null;n+=o}}return null}function RN(e){let t=String(e||""),n=[],r=/exec_command\s*\(/g;for(let s;s=r.exec(t);)n.push(s.index+s[0].length);let o=[];return n.forEach((s,a)=>{let i=t.slice(s,a+1<n.length?n[a+1]:t.length),c=/(?:^|[{,\s])["'`]?cmd["'`]?\s*:\s*/.exec(i);if(!c)return;let l=$N(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function Gk(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await Eo(e,t);if(!o)return[];let s;try{s=await _t(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
98
- `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type!=="response_item")continue;let u=l.payload;if(!u)continue;let d=[];if(u.type==="function_call"&&mi.has(u.name)){let f;try{f=JSON.parse(u.arguments||"{}")}catch{continue}let w=IN(f);w&&(d=[w])}else u.type==="custom_tool_call"&&u.name==="exec"&&(d=RN(u.input));if(!d.length)continue;let p=u.call_id||u.id||null;d.forEach((f,w)=>{a.push({id:p?w?`${p}:${w}`:p:null,tool:u.name,command:f,description:"",summary:Mr(f),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function zk(e,t){let n=await Eo(e,t);if(!n)return null;try{return Math.round((await Ef.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var vN,EN,_N,mi,_f,_o,Io=K(()=>{an();Os();vN=process.env.BOSTRAT_CODEX_SESSIONS||Af.join(process.env.CODEX_HOME||Af.join(xN.homedir(),".codex"),"sessions");EN=new Set(["output_text","text"]),_N=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&EN.has(t.type)).map(t=>t.text).join(`
99
- `).trim():"";mi=new Set(["exec_command","shell","exec"]),_f=new Set(["wait","write_stdin"]),_o="Codex ended the turn without a response \u2014 it hit an error the CLI shows only in the terminal (e.g. quota or billing). Check the Terminal tab."});function hi({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&Vk.has(r))return Vk.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 Jk(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||hi({error:t.code,status:t.status,text:e.text}),code:t.code||null,status:t.status||null,requestId:t.requestId||null}}if(e.failed){let t=String(e.text||"");return{cls:t===_o?"other":hi({text:t}),code:null,status:null,requestId:null}}return null}function Yk(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:hi({text:n}),code:null,status:ON(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function ON(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var Cz,Vk,Kl=K(()=>{Io();Cz=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),Vk=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 MN(e,t){return!e||!t?null:sn(e,t)}function CN(e){return typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
100
- `).trim():""}function NN(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 PN(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function If(e){let t=[],n=e?.message?.content;if(!Array.isArray(n))return t;for(let r of n)if(r){if(r.type==="image"&&r.source?.type==="base64"&&r.source.data)t.push({mediaType:r.source.media_type||"image/png",data:r.source.data,toolUseId:null});else if(r.type==="tool_result"&&Array.isArray(r.content))for(let o of r.content)o?.type==="image"&&o.source?.type==="base64"&&o.source.data&&t.push({mediaType:o.source.media_type||"image/png",data:o.source.data,toolUseId:r.tool_use_id||null})}return t}function Xk(e,t){if(!e.uuid)return null;let n=If(e).map((r,o)=>({uuid:e.uuid,index:o,mediaType:r.mediaType,name:r.toolUseId&&t.get(r.toolUseId)||null}));return n.length?n:null}async function $f(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await _t(e,t)}catch{return[]}let o=[],s=new Map,a=new Map;for(let i of r.split(`
101
- `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type==="attachment"){let y=l.attachment;y?.type==="queued_command"&&y.commandMode==="task-notification"&&typeof y.prompt=="string"&&y.prompt.trim()&&o.push({role:"user",text:y.prompt.trim(),ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let u=l.message;if(!u)continue;let d=u.role||l.type;if(d!=="user"&&d!=="assistant"||d==="assistant"&&u.model==="<synthetic>"&&!l.isApiErrorMessage)continue;if(d==="assistant"&&Array.isArray(u.content))for(let y of u.content){let x=y?.type==="tool_use"?y.input?.file_path||y.input?.path:null;typeof x=="string"&&DN.test(x)&&s.set(y.id,x.split("/").pop()),y?.type==="tool_use"&&y.name==="Skill"&&y.id&&a.set(y.id,String(y.input?.skill||"").trim().replace(/^\//,"")||null)}if(PN(u.content)){let y=Xk(l,s);y&&o.push({role:"assistant",text:"",images:y,ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let p=CN(u.content),f=d==="assistant"?NN(u.content):null,w=d==="user"?Xk(l,s):null;if(!p&&!f&&!w)continue;let m=d==="user"&&l.isMeta&&typeof l.sourceToolUseID=="string"&&l.sourceToolUseID?{toolUseId:l.sourceToolUseID,skill:a.get(l.sourceToolUseID)??null}:null,g=d==="assistant"&&l.isApiErrorMessage?{code:typeof l.error=="string"?l.error:null,status:Number(l.apiErrorStatus)||null,requestId:l.requestId||null,cls:hi({error:l.error,status:l.apiErrorStatus,text:p})}:null;o.push({role:d,text:p,tools:f||void 0,images:w||void 0,injected:m||void 0,ts:l.timestamp?Date.parse(l.timestamp):null,model:u.model||null,apiError:g||void 0})}return o.slice(-n)}async function Zk(e,t,{turns:n=16}={}){let r=MN(e,t);if(!r)return"";let o=await $f(r,{limit:n});return o.length?o.map(s=>{let a=s.role==="user"?"User":"Lead agent",i=s.tools?`_(also ran: ${s.tools.join(", ")})_`:"",c=s.images?.length?"(viewed an image)":"(took an action)";return`**${a}:** ${BN(s.text||c,700)} ${i}`.trim()}).join(`
102
-
103
- `):""}var DN,BN,Gl=K(()=>{Kl();an();DN=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;BN=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});import jN from"node:fs/promises";import{execFile as LN}from"node:child_process";import{promisify as FN}from"node:util";function n0(e){Of=typeof e=="function"?e:null}function Mf(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}function r0({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();!r||Qk.has(r)||(Qk.add(r),e0=e0.then(()=>HN({sessionName:e,from:t,to:r})).catch(()=>{}))}async function HN({sessionName:e,from:t,to:n}){await le({flow:"codex-update",phase:"start",sessionName:e,from:t,to:n}).catch(()=>{});try{let r=(await Rf("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await jN.realpath(r),s=Mf(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await Rf("npm",["install","-g","@openai/codex"],{env:a,timeout:UN});let i=(await Rf(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await le({flow:"codex-update",phase:"done",sessionName:e,from:t,to:n,version:i}).catch(()=>{}),await t0({sessionName:e,from:t,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await le({flow:"codex-update",phase:"failed",sessionName:e,from:t,to:n,error:o}).catch(()=>{}),await t0({sessionName:e,from:t,to:n,status:"failed",error:o})}}async function t0(e){if(Of)try{await Of(e)}catch{}}var Rf,UN,Qk,e0,Of,zl=K(()=>{Tn();Rf=FN(LN),UN=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,Qk=new Set,e0=Promise.resolve(),Of=null});function qN(e,{provider:t,box:n}){let r=String(e).replace(/\r/g,"").split(`
104
- `);if(!o0.test(e))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(WN);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"&&o0.test(a)?a:"The agent is asking for approval";return{provider:t,box:n,promptId:`${t}:${c}:${i.map(l=>l.label).join("|")}`.slice(0,200),questions:[{question:c,header:"Approval",multiSelect:!1,options:i.map(l=>({label:l.label,description:""}))}]}}function $o(e){let t=String(e??"").replace(/\r/g,""),n=t.split(`
105
- `);for(let r=n.length-1;r>=0;r--)if(i0.test(n[r]))return n.slice(r).join(`
106
- `);return t}function KN(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 GN(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 zN(e,t=""){let n=$o(e);if(wi.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
107
- `),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(s0);if(!u)continue;s<0&&(s=l);let d="";for(let p=l+1;p<Math.min(l+3,r.length);p++){let f=r[p].trim();if(f){if(s0.test(r[p])||/^Press enter/.test(f))break;d=f;break}}o.push({n:Number(u[2]),cursor:!!u[1],label:u[3].trim(),desc:d})}let a=o.sort((l,u)=>l.n-u.n);if(a.length<2||a.some((l,u)=>l.n!==u+1)||!a.some(l=>/Sign in with ChatGPT/.test(l.label)))return null;let i=[];for(let l=0;l<s;l++){let u=r[l].trim();u&&!i0.test(r[l])&&KN(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=GN(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function YN(e,t=""){let n=$o(e);if(wi.test(n)||!VN.test(n))return null;let r=n.trimEnd().split(`
108
- `).pop()||"";return JN.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 ZN(e,t=""){let n=$o(e);if(wi.test(n)||!a0.test(n))return null;let r=n.split(`
109
- `),o=r.findIndex(i=>a0.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(XN);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 QN(e,t=""){let n=$o(e);return wi.test(n)||!/open the following link to authenticate/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:"codex:signin-browser",questions:[{question:"Codex started its browser sign-in, which opens on the box itself and can't complete from another device. Go back and choose \u201CSign in with Device Code\u201D instead.",header:"Sign in",multiSelect:!1,options:[{label:"Go back to sign-in options",description:""}]}]}}function eP(e,t=""){let n=$o(e);return wi.test(n)||!/Paste or type your API key/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:"codex:signin-apikey",questions:[{question:"Codex is asking for an OpenAI API key. For safety a key can only be typed in the Terminal tab, never through chat. To use your ChatGPT subscription instead, go back and pick a sign-in option.",header:"Sign in",multiSelect:!1,options:[{label:"Go back to sign-in options",description:""}]}]}}function tP(e,t=""){let n=String(e);if(!/Press any key to log in/.test(n)||Cf.test(n))return null;let r=n.replace(/\r/g,"").split(`
110
- `).map(a=>a.trim()),o=r.findIndex(a=>/Press any key to log in/.test(a)),s=r.slice(0,o<0?r.length:o).filter(a=>a&&!/^Cursor Agent$/i.test(a)&&!/^v?\d{4}\.\d{2}\.\d{2}/.test(a)).join(" ");return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",promptId:"cursor:signin-start",questions:[{question:(s?`${s} `:"")+"Cursor isn't signed in on this box \u2014 start the sign-in to get a login link you can open from any device.",header:"Sign in",multiSelect:!1,options:[{label:"Start sign-in",description:"Shows a login link (and a QR option) \u2014 your login goes to cursor.com, never through bostrat"}]}]}}function rP(e,t=""){let n=String(e);if(!nP.test(n)||Cf.test(n))return null;let r=n.replace(/\r/g,"").split(`
111
- `),o="",s=r.findIndex(a=>/https:\/\//.test(a));if(s>=0){o=r[s].slice(r[s].indexOf("https://")).trim();for(let a=s+1;a<r.length;a++){let i=r[a].trim();if(!i||!/^[A-Za-z0-9~%&=?/_.-]+$/.test(i))break;o+=i}}return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:`cursor:signin-link:${(o.match(/[?&]challenge=([\w-]+)/)||[])[1]?.slice(0,16)||o.slice(-24)||"pending"}`,questions:[{question:o?`Cursor is waiting for you to finish signing in: open ${o} on any device and log in. Your login goes straight to cursor.com \u2014 bostrat never sees it. This card clears once sign-in completes.`:"Cursor is waiting for you to finish signing in \u2014 open the login link shown in the Terminal tab. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function oP(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 c0(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=YN(t,n)||ZN(t,n)||QN(t,n)||eP(t,n)||zN(t,n);if(r)return r}if(e==="cursor"){let r=rP(t,n)||oP(t,n)||tP(t,n);if(r)return r}return qN(t,{provider:e,box:n})}function l0(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 WN,o0,wi,i0,s0,VN,JN,a0,XN,Cf,nP,Vl=K(()=>{WN=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,o0=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;wi=/(^|\n)\s*›/,i0=/^\s*Welcome to Codex\b/;s0=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;VN=/Successfully logged in\./,JN=/^\s*Press Enter to continue\.\s*$/;a0=/Enter this one-time code/,XN=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;Cf=/Run Everything|Add a follow-up|Plan, search, build anything/;nP=/click this link to log in|Signing in with the browser/});function cP(e){let t=String(e||"").replace(/\r/g,"").split(`
112
- `),n=-1;for(let c=t.length-1;c>=0;c--)if(t[c].trim()){n=c;break}if(n<0)return!1;let r=t[n];if(aP.test(r)||iP.test(r)){for(let c=n-1;c>=0&&n-c<=64;c--)if(/^\s*›/.test(t[c]))return!0}let s=String(e||""),a=s.split(`
113
- `).filter(c=>/^\s*›/.test(c)),i=a.some(c=>/^\s*›\s+(?:Ask Codex to do anything|Implement \{feature\})\s*$/.test(c));return a.length>0&&!i&&/esc to interrupt|\bWorking \(/.test(s)}function fP(e){let t=String(e||"");if(!Ye.codex.block.test(t))return null;let n=$o(t);if(!Ye.codex.block.test(n))return null;let r=n.match(pP);return{from:r?.[1]||null,to:r?.[2]||null}}function An(e){return new Promise(t=>setTimeout(t,e))}function Nf(e,t){let n=Date.now(),r=mP();for(let[s,a]of Yl)n-a>=r&&Yl.delete(s);let o=`${e}::${t}`;return Yl.has(o)?!1:(Yl.set(o,n),!0)}function f0(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
114
- `),r=-1;for(let o=n.length-1;o>=0;o--)if(p0.test(n[o])){r=o;break}return r<0?t:n.slice(r+1).join(`
115
- `)}function wP(e){let t=0;for(let n of String(e).split(`
116
- `))p0.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function Pf(e,t){let n=Ye[e];if(!n?.busy)return{state:"idle",reason:null};if(Bf(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(f0(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=wP(t);return e==="claude"&&r>0&&r<hP?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function Df(e,t){return Pf(e,t).state}function m0(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
117
- `).slice(-yP).join(`
118
- `);return gP.test(n)}function Cs(e,t){return Df(e,t)==="busy"}function gi(e,t){return Df(e,t)!=="idle"}function Ns(e,t){let n=Ye[e];return n?.up?n.up.test(t):!0}function bP(e,t){let n=Ye[e];return n?Bf(e,t)?!1:n.up.test(t)&&Df(e,t)==="idle":!0}function Bf(e,t){let n=Ye[e];return n?n.auth?.test(t)&&!n.up.test(t)?!0:n.block?.test(t)?e==="codex"?!0:!n.up.test(t):!1:!1}function jf(e,t){let n=String(t||"").trim();if(!n)return e;let r=String(e||"").split(`
85
+ `});import{execFile as n0}from"node:child_process";import{promisify as yN}from"node:util";import ou from"node:fs";import{randomUUID as r0}from"node:crypto";function Po(e){return new Promise(t=>setTimeout(t,e))}function ru(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 o0(e){return`/tmp/tmux-${e}/default`}function bN({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=o0(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function Ti(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${Ai}=1`]}function vN(){return xN.flatMap(e=>["-e",`${e}=`])}function Ei(e,t,n){let r=Do(e),o=/(^|\s)(--session-id|--resume|--continue|-r|-c)(\s|=|$)/.test(e);if(!r||o)return e;let s=`${e} --session-id ${t}`,a=/(^|\s)(--name|-n)(\s|=)/.test(e);return n&&!a&&De(n)&&(s+=` --name ${n}`),s}function Do(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function Br(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function AN(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:Do(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function s0(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await a0(e,{loginShell:t});return r===su?!0:r===Hs?!1:n}async function a0(e,{loginShell:t=!1,timeoutMs:n=qf}={}){if(!e)return Hs;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}),su}catch(s){return s?.killed||s?.signal?Ws:s?.code===1||s?.code===127?Hs:Ws}}async function au(e,{retries:t=TN,sleep:n=EN,probe:r=a0}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:qf});for(let a=0;s===Ws&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:qf*2});return s}function ne(...e){return["-S",jt,...e]}async function jr(){if(!ou.existsSync(jt))return!1;try{return await $e(ee,ne("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function _i(){if(await jr())return!0;try{ou.mkdirSync(jt.replace(/\/[^/]+$/,""),{recursive:!0}),await $e(ee,ne("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await jr()}function De(e){return typeof e=="string"&&_N.test(e)}async function sn(){if(!ou.existsSync(jt))return[];try{let e="#{session_name}|#{session_windows}|#{session_attached}|#{session_activity}|#{pane_current_path}|#{@bostrat-session}|#{@bostrat-title}|#{@bostrat-sid}|#{@bostrat-agent}|#{alternate_on}|#{session_created}",{stdout:t}=await $e(ee,ne("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
86
+ `).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,d,p,f,w]=r.split("|"),h=Number(i),g=Number(w);return{name:o,title:u||null,windows:Number(s),attached:Number(a),lastActivityMs:Number.isFinite(h)?n-h*1e3:null,cwd:c||null,isBostrat:l==="1",sessionId:d||null,agent:p||(l==="1"?"claude":null),alternateOn:f==="1",createdMs:Number.isFinite(g)&&g>0?g*1e3:null}}).filter(r=>!SN.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function ye(e){return(await sn()).find(n=>n.name===e)||null}function RN(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=$N&&IN.test(t)}function iu(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function i0(e){try{let{stdout:t}=await $e(ee,ne("list-sessions","-F","#{session_name}"));return t.split(`
87
+ `).map(n=>n.trim()).includes(e)}catch{return!1}}function CN(e){let t=String(e||"").trim().split(/\s+/)[0]||"";if(t.includes("/"))return null;let n=[],r=s=>/[A-Za-z0-9_]/.test(s);for(let s=1;s<=t.length-3;s++)r(t[s-1])===r(t[s])&&n.push(t.slice(s));if(!n.length)return null;let o=n.map(s=>s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp(`\\b(?:${o.join("|")})`)}async function NN(e,t){let n=Date.now()+Ii(),r=CN(t),o=!1,s=0,a=0;for(;;){if(await Po(ON),s+=1,!await i0(e))return;let i=await Pe(e,{lines:15}),c=!o&&MN.test(i)&&!!r?.test(i),l=!o&&!!r?.test(i);if(!c&&!l&&s>1&&!await Qn(e)){if(a+=1,a>1)return}else c||(a=0);if(c){o=!0,await ue({flow:"spawn",phase:"launch-retry",sessionName:e,agent:Br(t),promptHead:t.slice(0,120)}).catch(()=>{}),await $e(ee,ne("send-keys","-t",e,"C-u")),await $e(ee,ne("send-keys","-t",e,"-l",t)),await $e(ee,ne("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await ue({flow:"spawn",phase:"launch-failed",sessionName:e,agent:Br(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function En(e,t=kN,n={}){if(!RN(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=iu(r);if(!De(o))throw new Error("resulting tmux session name is invalid");if(!await _i())throw new Error(`host tmux server not running on ${jt} and auto-start failed \u2014 start one: ${ee} -S ${jt} new-session -d -s keeper "sleep 2147483647"`);if(await i0(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||Kf,a=n.agent||Br(s),i=!!n.resumeSessionId,c=n.resumeSessionId||r0(),l=i?s:Ei(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&Do(s),p=n.firstRun===!0;p||(d&&await $r(t),a==="codex"&&await Os(t),a==="cursor"&&await Ms(t),await $k(t),n.freshWorkspace!==!0&&await Ql(t));let f=d&&!p?Rl():null,w=zb(),h=["-e",`${Jn}=${w}`];h.push(...Qk({nodeUrl:e0()})),h.push(...vN()),f&&h.push("-e",`ANTHROPIC_API_KEY=${f}`),d&&h.push(...Ti());try{await $e(ee,ne("new-session","-d","-s",o,"-c",t,...h))}catch(g){throw ru(f?ru(g,f):g,w)}return await Bo(o),await $e(ee,ne("set-option","-t",o,"@bostrat-session","1")),await $e(ee,ne("set-option","-t",o,"@bostrat-title",r)),await $e(ee,ne("set-option","-t",o,"@bostrat-sid",c)),await $e(ee,ne("set-option","-t",o,"@bostrat-agent",a)),await $e(ee,ne("send-keys","-t",o,l,"Enter")),AN(l)&&NN(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:w}}async function Ot(e){if(!De(e))throw new Error("invalid session name");await $e(ee,ne("kill-session","-t",e))}async function c0(e,t){if(De(e))try{let n=t?ne("set-option","-t",e,"@bostrat-sid",t):ne("set-option","-u","-t",e,"@bostrat-sid");await $e(ee,n)}catch{}}async function Pe(e,{lines:t=40}={}){if(!De(e))return"";try{let n=ne("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await $e(ee,n);return String(r||"")}catch{return""}}async function l0(e){if(!De(e))return[];try{let{stdout:t}=await $e(ee,ne("list-panes","-s","-t",e,"-F","#{pane_pid}"));return String(t||"").trim().split(`
88
+ `).map(n=>Number(n.trim())).filter(n=>Number.isFinite(n)&&n>0)}catch{return[]}}async function u0(e){if(!De(e))return 0;try{let{stdout:t}=await $e(ee,ne("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
89
+ `).filter(Boolean).length}catch{return 0}}async function Bo(e,{cols:t=BN,rows:n=jN}={}){if(!De(e))return!0;if(await u0(e))return!1;try{let r=await d0(e);if(r.cols===t&&r.rows===n)return!0;await $e(ee,ne("resize-window","-t",e,"-x",String(t),"-y",String(n))),await $e(ee,ne("set-window-option","-t",e,"window-size","latest")),await Po(80)}catch{}return!0}async function LN(e){if(!De(e))return 0;try{let{stdout:t}=await $e(ee,ne("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function Qn(e){let t=await LN(e);if(!t)return!1;try{return await $e("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function d0(e){if(!De(e))return{cols:0,rows:0};try{let{stdout:t}=await $e(ee,ne("display-message","-t",e,"-p","#{window_width} #{window_height}")),[n,r]=String(t||"").trim().split(/\s+/).map(o=>Number(o)||0);return{cols:n,rows:r}}catch{return{cols:0,rows:0}}}async function cu(e,{cols:t=PN,rows:n=DN}={}){if(De(e)&&!await u0(e))try{let r=await d0(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await $e(ee,ne("resize-window","-t",e,"-x",String(o),"-y",String(s))),await $e(ee,ne("set-window-option","-t",e,"window-size","latest")),await Po(80))}catch{}}async function an(e){return await cu(e),Pe(e,{lines:Ye})}async function We(e,t,{settleMs:n=40,kind:r}={}){if(!De(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>p0.has(s));for(let s=0;s<o.length;s++)await $e(ee,ne("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await Po(n);return ue({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function Vf(e,t,{settleMs:n=40,kind:r}={}){if(!De(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[]).filter(s=>s&&(typeof s.key=="string"&&p0.has(s.key)||typeof s.text=="string"&&s.text.length>0));for(let s=0;s<o.length;s++){let a=o[s];a.text!=null?await $e(ee,ne("send-keys","-t",e,"-l",a.text)):await $e(ee,ne("send-keys","-t",e,a.key)),n>0&&s<o.length-1&&await Po(n)}return ue({flow:"tmux",phase:"send-sequence",sessionName:e,kind:r||"sequence",steps:o.map(s=>s.text!=null?`\u2039text:${s.text.length}\u203A`:s.key).join(" ")}).catch(()=>{}),o.length}async function qs(e,t,{kind:n}={}){if(!De(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await $e(ee,ne("send-keys","-t",e,"-N",String(r),"BSpace")),ue({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function uu(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!De(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await $e(ee,ne("send-keys","-t",e,"-l",s)),n>0&&await Po(n);ue({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function FN(e,t){return new Promise((n,r)=>{let o=n0(ee,ne(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function UN(e,t){let n=`bostrat-${r0().slice(0,8)}`;await FN(["load-buffer","-b",n,"-"],t),await $e(ee,ne("paste-buffer","-p","-d","-b",n,"-t",e))}async function ot(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!De(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await UN(e,t):await $e(ee,ne("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await Po(a),await $e(ee,ne("send-keys","-t",e,"Enter"))}ue({flow:"tmux",phase:"send",sessionName:e,kind:o||"text",textLen:typeof t=="string"?t.length:0,textHead:typeof t=="string"?t.slice(0,120):"",enter:n,submitDelayMs:r,...s?{paste:!0}:{}}).catch(()=>{})}var $e,ee,t0,jt,kN,Kf,Ai,xN,Gf,SN,su,Hs,Ws,qf,TN,EN,zf,_N,IN,$N,Ii,ON,MN,PN,DN,Ye,BN,jN,p0,lu,ut=q(()=>{ai();Ml();Cl();wi();eu();Tn();Rs();Wf();$e=yN(n0);ee=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";t0=typeof process.getuid=="function"?process.getuid():0,jt=bN({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return ou.existsSync(o0(t0))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:t0}),kN=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",Kf=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",Ai="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";xN=Object.freeze(["BOSTRAT_PLANE_URL","BOSTRAT_PLANE_TOKEN"]);Gf="bostrat-usage-probe",SN=new Set([Gf]);su="present",Hs="absent",Ws="unknown",qf=5e3,TN=[250,1e3,3e3],EN=e=>new Promise(t=>setTimeout(t,e));zf={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"};_N=/^[A-Za-z0-9_.-]{1,64}$/;IN=/^[A-Za-z0-9 ._↻-]+$/,$N=64;Ii=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,ON=1e3,MN=/not found|Unknown command/i;PN=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,DN=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,Ye=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,BN=Number(process.env.BOSTRAT_BOX_COLS)||120,jN=Number(process.env.BOSTRAT_BOX_ROWS)||40;p0=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);lu=1600});import $i from"node:fs";import zN from"node:fs/promises";import Ks from"node:path";import VN from"node:os";function Xf(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function Zf(e){let t=Ks.join(Yf,Xf(e)),n;try{n=$i.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=Ks.join(t,o);try{let{mtimeMs:a}=$i.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function cn(e,t){if(!t)return null;let n=Ks.join(Yf,Xf(e),`${t}.jsonl`);return $i.existsSync(n)?n:null}function b0(e){if(!e)return[];let t=Ks.join(Yf,Xf(e)),n;try{n=$i.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=$i.statSync(Ks.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function Mt(e,t=131072){let n=await zN.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 YN(e){let t=e.split(`
90
+ `);for(let n=t.length-1;n>=0;n--){let r=t[n].trim();if(!r||r[0]!=="{")continue;let o;try{o=JSON.parse(r)}catch{continue}let s=o?.message?.usage;if(!s)continue;let a=(s.input_tokens||0)+(s.cache_creation_input_tokens||0)+(s.cache_read_input_tokens||0);if(a>0)return{occupancy:a,model:o.message.model||o.model||null}}return null}async function Ri(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=cn(e,t),o=!0,!r)return null}else if(n){if(r=Zf(e),o=!1,!r)return null}else return null;let s;try{s=YN(await Mt(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(y0,s.model),i=y0[s.model]||JN;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 y0,JN,Yf,ln=q(()=>{y0={"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},JN=2e5,Yf=process.env.BOSTRAT_CLAUDE_PROJECTS||Ks.join(VN.homedir(),".claude","projects")});function XN(e){let t=[],n="",r=null;for(let o=0;o<e.length;o++){let s=e[o];if(r){n+=s,s===r&&e[o-1]!=="\\"&&(r=null);continue}if(s==="'"||s==='"'||s==="`"){r=s,n+=s;continue}if(s==="&"&&e[o+1]==="&"){t.push(n),n="",o++;continue}if(s==="|"&&e[o+1]==="|"){t.push(n),n="",o++;continue}if(s==="|"||s===";"||s===`
91
+ `){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function Oi(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 Mi(e){let t=e;for(;t.length&&/^[A-Za-z_][A-Za-z0-9_]*=/.test(t[0]);)t=t.slice(1);for(;t.length&&(t[0]==="sudo"||t[0]==="time"||t[0]==="env");)t=t.slice(1);return t}function Be(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(v0(o)){t.has(o)&&r++;continue}n.push(o)}return n}function S0(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 eP(e){let t=S0(e),n=wt(Be(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${Ge(n)}`:`Read lines ${t.from}\u2013${t.to} of ${Ge(n)}`:e.includes("-i")&&n?`Edit ${Ge(n)}`:null}function Qf(e){if(e.includes("--files")){let s=wt(Be(e,k0)[0]);return s&&s!=="."?`List files in ${Gs(s)}`:"List files"}let t=Be(e,k0),n=t[0];if(!n)return null;let r=wt(t.slice(1).find(s=>s!==".")),o=zs(n,40);return r?`Search for \u201C${o}\u201D in ${Gs(r)}`:`Search for \u201C${o}\u201D`}function eh(e){let t=Be(e,new Set(["--prefix"])),n=t[0];return n?n==="test"||n==="t"?"Run tests":n==="run"||n==="run-script"?t[1]?`Run ${t[1]}`:null:n==="ci"||n==="install"||n==="i"||n==="add"?"Install dependencies":null:null}function th(e,t){if(e.includes("-e")||e.includes("--eval")||e.includes("-c")||e[1]==="-"||e.includes("<<"))return`Run an inline ${t} script`;if(e.includes("--test"))return"Run tests";let n=Be(e)[0];return n?`Run ${Ge(n)}`:null}function tP(e){let t=Be(e),n=t[0],r=t.find(a=>/\.(service|timer|socket|target)$/.test(a))||t[1],o=r?r.replace(/\.service$/,""):"a service";return{status:`Check ${o} status`,show:`Inspect ${o}`,restart:`Restart ${o}`,start:`Start ${o}`,stop:`Stop ${o}`,"daemon-reload":"Reload systemd"}[n]||null}function x0(e){return e.find(t=>/^https?:\/\//.test(t))||null}function oP(e){let t=Mi(Oi(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(Ge(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return nh(t[2]);let n=Ge(t[0]);if(rP.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=nP[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function nh(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
92
+ `,n);i!==-1&&(t=t.slice(0,i))}let r=XN(t);for(let i=0;i<r.length-1;i++){let c=Mi(Oi(r[i])),l=Mi(Oi(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Ge(c[0]))&&Ge(l[0])==="sed"){let u=S0(l),d=Be(c)[0];if(u&&d)return zs(u.from===u.to?`Read line ${u.from} of ${Ge(d)}`:`Read lines ${u.from}\u2013${u.to} of ${Ge(d)}`,88)}}let o=[];for(let i of r){let c=oP(i);c&&o.push({d:c,head:Ge(Mi(Oi(i))[0]||""),sub:Be(Mi(Oi(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":zs(s?s.d:o[0].d,88)}var zs,wt,Ge,Gs,v0,k0,ZN,QN,nP,rP,A0=q(()=>{zs=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,wt=e=>e&&!/[$`]/.test(e)?e:null,Ge=e=>e.replace(/\/+$/,"").split("/").pop()||e,Gs=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},v0=e=>e.startsWith("-"),k0=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);ZN={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 ${Ge(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"},QN={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"};nP={git:e=>{let t=Be(e,new Set(["-C","-c"])),n=ZN[t[0]];return n?n(t,e):null},gh:e=>{let t=Be(e),n=QN[t[0]];return n?n(t):null},sed:eP,rg:Qf,grep:Qf,egrep:Qf,nl:e=>{let t=wt(Be(e)[0]);return t?`Read ${Ge(t)}`:null},cat:e=>{let t=wt(Be(e)[0]);return t?`Read ${Ge(t)}`:null},head:e=>{let t=wt(Be(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${Ge(t)}`:null},tail:e=>{let t=wt(Be(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${Ge(t)}`:null},wc:e=>{let t=wt(Be(e)[0]);return t?`Count lines in ${Ge(t)}`:"Count input lines"},ls:e=>{let t=wt(Be(e)[0]);return t&&t!=="."?`List files in ${Gs(t)}`:"List files"},find:e=>wt(e[1])&&!v0(e[1])&&e[1]!=="."?`Find files in ${Gs(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=wt(Be(e)[0]);return t?`Create directory ${Gs(t)}`:null},touch:e=>{let t=wt(Be(e)[0]);return t?`Create ${Ge(t)}`:null},rm:e=>{let t=wt(Be(e)[0]);return t?`Delete ${Gs(t)}`:null},mv:e=>{let t=wt(Be(e)[0]);return t?`Move ${Ge(t)}`:null},cp:e=>{let t=wt(Be(e)[0]);return t?`Copy ${Ge(t)}`:null},chmod:e=>{let t=wt(Be(e)[1]);return t?`Change permissions on ${Ge(t)}`:null},diff:e=>{let t=Be(e);return t.length>=2?`Compare ${Ge(t[0])} and ${Ge(t[1])}`:null},curl:e=>{let t=x0(e);return t?`Fetch ${zs(t,56)}`:"Fetch a URL"},wget:e=>{let t=x0(e);return t?`Fetch ${zs(t,56)}`:"Fetch a URL"},npm:eh,pnpm:eh,yarn:eh,npx:e=>{let t=Be(e)[0];return t?`Run ${t}`:null},node:e=>th(e,"Node"),python:e=>th(e,"Python"),python3:e=>th(e,"Python"),make:e=>{let t=Be(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:tP,journalctl:e=>{let t=e.findIndex(r=>r==="-u"||r==="--unit"||r==="--user-unit"),n=t!==-1?e[t+1]:null;return n?`Read ${n.replace(/\.service$/,"")} logs`:"Read system logs"},tmux:e=>{let t=Be(e,new Set(["-S","-L","-t","-f"]))[0];return{ls:"List tmux sessions","list-sessions":"List tmux sessions","kill-session":"Kill a tmux session","send-keys":"Send keys to a tmux session","capture-pane":"Capture a tmux pane","new-session":"Start a tmux session"}[t]||null},ps:()=>"List processes",which:e=>{let t=Be(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=Be(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},rP=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function Vs(e){let t=e.split(`
93
+ `).map(n=>n.trim()).find(Boolean)||e;return t.length>88?`${t.slice(0,88).trimEnd()}\u2026`:t}function Lr(e,t=""){let n=t.trim();return n||nh(e)||Vs(e)}function rh(e,t){if(e){if(Array.isArray(e)){for(let n of e)rh(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&oh.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))rh(n,t)}}}async function T0(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await Mt(e,t)}catch{return[]}let o=[];for(let s of r.split(`
94
+ `)){let a=s.trim();if(!a||a[0]!=="{")continue;let i;try{i=JSON.parse(a)}catch{continue}let c=i.message;if(!c)continue;let l=[];if(rh(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:Lr(d.command,d.description),ts:u})}return o.slice(-n)}function E0(e,t){let n=a=>a?.box??null,r=new Map;for(let a of t||[]){if(a.role!=="assistant"||!(a.text||"").trim())continue;let i=n(a);r.has(i)||r.set(i,[]),r.get(i).push(a)}let o=new Map;for(let a of e||[]){let i=n(a);o.has(i)||o.set(i,[]),o.get(i).push(a)}let s=[];for(let[a,i]of o)s.push(...sP(i,r.get(a)||[]));return s.sort((a,i)=>(a.ts||0)-(i.ts||0))}function sP(e,t){let n=[...t].sort((l,u)=>(l.ts||0)-(u.ts||0)),r=[...e].sort((l,u)=>(l.ts||0)-(u.ts||0)),o=[],s=0,a=0,i=l=>{let u=l.n??a+1;return u>a&&(a=u),u};for(let l of n){let u=r.findIndex((w,h)=>h>=s&&(w.ts||0)>(l.ts||0)),d=u===-1?r.length:u,p=r.slice(s,d);if(s=d,!p.length)continue;let f=p.map(w=>({...w,n:i(w)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:f,ts:Math.max(...f.map(w=>w.ts||0)),pending:!1})}let c=r.slice(s);if(c.length){let l=c.map(u=>({...u,n:i(u)}));o.push({id:`batch-pending-${l[0]?.box||"lead"}`,anchorTs:null,anchorBox:l[l.length-1]?.box??null,agent:l[l.length-1]?.agent??"claude",boxRole:l[l.length-1]?.boxRole??"lead",commands:l,ts:Math.max(...l.map(u=>u.ts||0)),pending:!0})}return o}var oh,Js=q(()=>{ln();A0();oh=new Set(["Bash"])});import _0 from"node:fs";import ah from"node:fs/promises";import sh from"node:path";import aP from"node:os";async function I0(e){try{return await ah.realpath(e)}catch{return e}}function cP(e=iP){let t=[],n=r=>{let o;try{o=_0.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=sh.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:_0.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function lP(e,t=1048576){let n;try{n=await ah.open(e,"r")}catch{return""}try{let r=Buffer.alloc(Math.min(t,65536)),o="",s=0;for(;;){let{bytesRead:a}=await n.read(r,0,r.length,s);if(!a)break;o+=r.toString("utf8",0,a);let i=o.indexOf(`
95
+ `);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=t)break}return o}finally{await n.close()}}async function uP(e){let t=await lP(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 jo(e,t){if(!e&&!t)return null;let n=cP();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await I0(e);for(let o of n){let s=await uP(o.file);if(s&&(s===e||await I0(s)===r))return o}return null}async function $0(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await jo(e,t);if(!o)return[];let s;try{s=await Mt(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,d=null;for(let p of s.split(`
96
+ `)){let f=p.trim();if(!f||f[0]!=="{")continue;let w;try{w=JSON.parse(f)}catch{continue}if((w.type==="turn_context"&&w.payload?.model||w.type==="session_meta"&&w.payload?.model)&&(i=w.payload.model),w.type==="event_msg"){let x=w.payload?.type;x==="task_started"?(l=!0,u=!1,d=w.payload?.turn_id||null):x==="task_complete"&&l&&(l=!1,!u&&w.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:Lo,sourceId:w.payload?.turn_id||d||void 0,ts:w.timestamp?Date.parse(w.timestamp):null,model:i}));continue}if(w.type!=="response_item")continue;let h=w.payload;if(!h)continue;if((h.type==="function_call"||h.type==="custom_tool_call")&&h.name){u=!0,ih.has(h.name)||c.push(h.name);continue}if(h.type!=="message"||h.role!=="assistant")continue;u=!0;let g=pP(h.content),y=c.length?c.slice():null;c=[],!(!g&&!y)&&a.push({role:"assistant",text:g,tools:y||void 0,ts:w.timestamp?Date.parse(w.timestamp):null,model:i})}if(i)for(let p of a)p.model||(p.model=i);return a.slice(-n)}function fP(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 hP(e){let t=e[0];if(t!=='"'&&t!=="'"&&t!=="`")return null;let n="";for(let r=1;r<e.length;r++){let o=e[r];if(o==="\\"){let s=e[++r];if(s===void 0)return null;if(s==="n")n+=`
97
+ `;else if(s==="t")n+=" ";else if(s==="r")n+="\r";else if(s==="u")if(e[r+1]==="{"){let a=e.indexOf("}",r+2);if(a===-1)return null;n+=String.fromCodePoint(parseInt(e.slice(r+2,a),16)),r=a}else n+=String.fromCharCode(parseInt(e.slice(r+1,r+5),16)),r+=4;else n+=s}else{if(o===t)return n;if(t==="`"&&o==="$"&&e[r+1]==="{")return null;n+=o}}return null}function mP(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=hP(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function R0(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await jo(e,t);if(!o)return[];let s;try{s=await Mt(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
98
+ `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type!=="response_item")continue;let u=l.payload;if(!u)continue;let d=[];if(u.type==="function_call"&&Ci.has(u.name)){let f;try{f=JSON.parse(u.arguments||"{}")}catch{continue}let w=fP(f);w&&(d=[w])}else u.type==="custom_tool_call"&&u.name==="exec"&&(d=mP(u.input));if(!d.length)continue;let p=u.call_id||u.id||null;d.forEach((f,w)=>{a.push({id:p?w?`${p}:${w}`:p:null,tool:u.name,command:f,description:"",summary:Lr(f),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function O0(e,t){let n=await jo(e,t);if(!n)return null;try{return Math.round((await ah.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var iP,dP,pP,Ci,ih,Lo,Fo=q(()=>{ln();Js();iP=process.env.BOSTRAT_CODEX_SESSIONS||sh.join(process.env.CODEX_HOME||sh.join(aP.homedir(),".codex"),"sessions");dP=new Set(["output_text","text"]),pP=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&dP.has(t.type)).map(t=>t.text).join(`
99
+ `).trim():"";Ci=new Set(["exec_command","shell","exec"]),ih=new Set(["wait","write_stdin"]),Lo="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 Ni({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&M0.has(r))return M0.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 C0(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||Ni({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===Lo?"other":Ni({text:t}),code:null,status:null,requestId:null}}return null}function N0(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:Ni({text:n}),code:null,status:wP(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function wP(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var xV,M0,pu=q(()=>{Fo();xV=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),M0=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 gP(e,t){return!e||!t?null:cn(e,t)}function yP(e){return typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
100
+ `).trim():""}function bP(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 kP(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function ch(e){let t=[],n=e?.message?.content;if(!Array.isArray(n))return t;for(let r of n)if(r){if(r.type==="image"&&r.source?.type==="base64"&&r.source.data)t.push({mediaType:r.source.media_type||"image/png",data:r.source.data,toolUseId:null});else if(r.type==="tool_result"&&Array.isArray(r.content))for(let o of r.content)o?.type==="image"&&o.source?.type==="base64"&&o.source.data&&t.push({mediaType:o.source.media_type||"image/png",data:o.source.data,toolUseId:r.tool_use_id||null})}return t}function P0(e,t){if(!e.uuid)return null;let n=ch(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 lh(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await Mt(e,t)}catch{return[]}let o=[],s=new Map,a=new Map;for(let i of r.split(`
101
+ `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type==="attachment"){let y=l.attachment;y?.type==="queued_command"&&y.commandMode==="task-notification"&&typeof y.prompt=="string"&&y.prompt.trim()&&o.push({role:"user",text:y.prompt.trim(),ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let u=l.message;if(!u)continue;let d=u.role||l.type;if(d!=="user"&&d!=="assistant"||d==="assistant"&&u.model==="<synthetic>"&&!l.isApiErrorMessage)continue;if(d==="assistant"&&Array.isArray(u.content))for(let y of u.content){let x=y?.type==="tool_use"?y.input?.file_path||y.input?.path:null;typeof x=="string"&&xP.test(x)&&s.set(y.id,x.split("/").pop()),y?.type==="tool_use"&&y.name==="Skill"&&y.id&&a.set(y.id,String(y.input?.skill||"").trim().replace(/^\//,"")||null)}if(kP(u.content)){let y=P0(l,s);y&&o.push({role:"assistant",text:"",images:y,ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let p=yP(u.content),f=d==="assistant"?bP(u.content):null,w=d==="user"?P0(l,s):null;if(!p&&!f&&!w)continue;let h=d==="user"&&l.isMeta&&typeof l.sourceToolUseID=="string"&&l.sourceToolUseID?{toolUseId:l.sourceToolUseID,skill:a.get(l.sourceToolUseID)??null}:null,g=d==="assistant"&&l.isApiErrorMessage?{code:typeof l.error=="string"?l.error:null,status:Number(l.apiErrorStatus)||null,requestId:l.requestId||null,cls:Ni({error:l.error,status:l.apiErrorStatus,text:p})}:null;o.push({role:d,text:p,tools:f||void 0,images:w||void 0,injected:h||void 0,ts:l.timestamp?Date.parse(l.timestamp):null,model:u.model||null,apiError:g||void 0})}return o.slice(-n)}async function D0(e,t,{turns:n=16}={}){let r=gP(e,t);if(!r)return"";let o=await lh(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}:** ${vP(s.text||c,700)} ${i}`.trim()}).join(`
102
+
103
+ `):""}var xP,vP,fu=q(()=>{pu();ln();xP=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;vP=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});import SP from"node:fs/promises";import{execFile as AP}from"node:child_process";import{promisify as TP}from"node:util";function F0(e){dh=typeof e=="function"?e:null}function ph(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}function U0({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();!r||B0.has(r)||(B0.add(r),j0=j0.then(()=>_P({sessionName:e,from:t,to:r})).catch(()=>{}))}async function _P({sessionName:e,from:t,to:n}){await ue({flow:"codex-update",phase:"start",sessionName:e,from:t,to:n}).catch(()=>{});try{let r=(await uh("/bin/sh",["-c","command -v codex"])).stdout.trim();if(!r)throw new Error("codex not on PATH");let o=await SP.realpath(r),s=ph(o),a=s?{...process.env,PATH:`${s}/bin:${process.env.PATH||""}`}:process.env;await uh("npm",["install","-g","@openai/codex"],{env:a,timeout:EP});let i=(await uh(r,["--version"])).stdout.trim().replace(/^codex-cli\s*/,"")||n;await ue({flow:"codex-update",phase:"done",sessionName:e,from:t,to:n,version:i}).catch(()=>{}),await L0({sessionName:e,from:t,to:n,version:i,status:"updated"})}catch(r){let o=String(r?.message||r).slice(0,300);await ue({flow:"codex-update",phase:"failed",sessionName:e,from:t,to:n,error:o}).catch(()=>{}),await L0({sessionName:e,from:t,to:n,status:"failed",error:o})}}async function L0(e){if(dh)try{await dh(e)}catch{}}var uh,EP,B0,j0,dh,hu=q(()=>{Tn();uh=TP(AP),EP=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,B0=new Set,j0=Promise.resolve(),dh=null});function $P(e,{provider:t,box:n}){let r=String(e).replace(/\r/g,"").split(`
104
+ `);if(!H0.test(e))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(IP);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"&&H0.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 Fr(e){let t=String(e??"").replace(/\r/g,""),n=t.split(`
105
+ `);for(let r=n.length-1;r>=0;r--)if(K0.test(n[r]))return n.slice(r).join(`
106
+ `);return t}function RP(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 OP(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 MP(e,t=""){let n=Fr(e);if(Pi.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
107
+ `),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(W0);if(!u)continue;s<0&&(s=l);let d="";for(let p=l+1;p<Math.min(l+3,r.length);p++){let f=r[p].trim();if(f){if(W0.test(r[p])||/^Press enter/.test(f))break;d=f;break}}o.push({n:Number(u[2]),cursor:!!u[1],label:u[3].trim(),desc:d})}let a=o.sort((l,u)=>l.n-u.n);if(a.length<2||a.some((l,u)=>l.n!==u+1)||!a.some(l=>/Sign in with ChatGPT/.test(l.label)))return null;let i=[];for(let l=0;l<s;l++){let u=r[l].trim();u&&!K0.test(r[l])&&RP(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=OP(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function PP(e,t=""){let n=Fr(e);if(Pi.test(n)||!CP.test(n))return null;let r=n.trimEnd().split(`
108
+ `).pop()||"";return NP.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 BP(e,t=""){let n=Fr(e);if(Pi.test(n)||!q0.test(n))return null;let r=n.split(`
109
+ `),o=r.findIndex(i=>q0.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(DP);if(c){s=c[1];break}}if(!s)return null;let a=(n.match(/https:\/\/\S+/)||[])[0]||"https://auth.openai.com/codex/device";return{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",promptId:`codex:device-code:${s}`,questions:[{question:`Codex is waiting for you to finish signing in: open ${a} and enter code ${s} (expires in 15 minutes). The code goes straight to OpenAI \u2014 bostrat never sees your login. This card clears once OpenAI confirms.`,header:"Sign in",multiSelect:!1,options:[{label:"Cancel sign-in",description:"Go back to the sign-in options"}]}]}}function jP(e,t=""){let n=Fr(e);return Pi.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 LP(e,t=""){let n=Fr(e);return Pi.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 FP(e,t=""){let n=String(e);if(!/Press any key to log in/.test(n)||fh.test(n))return null;let r=n.replace(/\r/g,"").split(`
110
+ `).map(a=>a.trim()),o=r.findIndex(a=>/Press any key to log in/.test(a)),s=r.slice(0,o<0?r.length:o).filter(a=>a&&!/^Cursor Agent$/i.test(a)&&!/^v?\d{4}\.\d{2}\.\d{2}/.test(a)).join(" ");return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",promptId:"cursor:signin-start",questions:[{question:(s?`${s} `:"")+"Cursor isn't signed in on this box \u2014 start the sign-in to get a login link you can open from any device.",header:"Sign in",multiSelect:!1,options:[{label:"Start sign-in",description:"Shows a login link (and a QR option) \u2014 your login goes to cursor.com, never through bostrat"}]}]}}function HP(e,t=""){let n=String(e);if(!UP.test(n)||fh.test(n))return null;let r=n.replace(/\r/g,"").split(`
111
+ `),o="",s=r.findIndex(a=>/https:\/\//.test(a));if(s>=0){o=r[s].slice(r[s].indexOf("https://")).trim();for(let a=s+1;a<r.length;a++){let i=r[a].trim();if(!i||!/^[A-Za-z0-9~%&=?/_.-]+$/.test(i))break;o+=i}}return{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,promptId:`cursor:signin-link:${(o.match(/[?&]challenge=([\w-]+)/)||[])[1]?.slice(0,16)||o.slice(-24)||"pending"}`,questions:[{question:o?`Cursor is waiting for you to finish signing in: open ${o} on any device and log in. Your login goes straight to cursor.com \u2014 bostrat never sees it. This card clears once sign-in completes.`:"Cursor is waiting for you to finish signing in \u2014 open the login link shown in the Terminal tab. This card clears once sign-in completes.",header:"Sign in",multiSelect:!1,options:[]}]}}function WP(e,t=""){let n=String(e);return!/Scan this QR code to log in/.test(n)||fh.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 G0(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=PP(t,n)||BP(t,n)||jP(t,n)||LP(t,n)||MP(t,n);if(r)return r}if(e==="cursor"){let r=HP(t,n)||WP(t,n)||FP(t,n);if(r)return r}return $P(t,{provider:e,box:n})}function z0(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 IP,H0,Pi,K0,W0,CP,NP,q0,DP,fh,UP,mu=q(()=>{IP=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,H0=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;Pi=/(^|\n)\s*›/,K0=/^\s*Welcome to Codex\b|^\s*(?:│\s*)?>_ OpenAI Codex\b/;W0=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;CP=/Successfully logged in\./,NP=/^\s*Press Enter to continue\.\s*$/;q0=/Enter this one-time code/,DP=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;fh=/Run Everything|Add a follow-up|Plan, search, build anything/;UP=/click this link to log in|Signing in with the browser/});function zP(e){let t=String(e||"").replace(/\r/g,"").split(`
112
+ `),n=-1;for(let c=t.length-1;c>=0;c--)if(t[c].trim()){n=c;break}if(n<0)return!1;let r=t[n];if(KP.test(r)||GP.test(r)){for(let c=n-1;c>=0&&n-c<=64;c--)if(/^\s*›/.test(t[c]))return!0}let s=String(e||""),a=s.split(`
113
+ `).filter(c=>/^\s*›/.test(c)),i=a.some(c=>/^\s*›\s+(?:Ask Codex to do anything|Implement \{feature\})\s*$/.test(c));return a.length>0&&!i&&/esc to interrupt|\bWorking \(/.test(s)}function ZP(e){let t=String(e||"");if(!Xe.codex.block.test(t))return null;let n=Fr(t);if(!Xe.codex.block.test(n))return null;let r=n.match(XP);return{from:r?.[1]||null,to:r?.[2]||null}}function _n(e){return new Promise(t=>setTimeout(t,e))}function hh(e,t){let n=Date.now(),r=QP();for(let[s,a]of gu)n-a>=r&&gu.delete(s);let o=`${e}::${t}`;return gu.has(o)?!1:(gu.set(o,n),!0)}function X0(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
114
+ `),r=-1;for(let o=n.length-1;o>=0;o--)if(Y0.test(n[o])){r=o;break}return r<0?t:n.slice(r+1).join(`
115
+ `)}function tD(e){let t=0;for(let n of String(e).split(`
116
+ `))Y0.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function mh(e,t){let n=Xe[e];if(!n?.busy)return{state:"idle",reason:null};if(gh(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(X0(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=tD(t);return e==="claude"&&r>0&&r<eD?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function wh(e,t){return mh(e,t).state}function Z0(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
117
+ `).slice(-rD).join(`
118
+ `);return nD.test(n)}function Xs(e,t){return wh(e,t)==="busy"}function Di(e,t){return wh(e,t)!=="idle"}function Uo(e,t){let n=Xe[e];return n?.up?n.up.test(t):!0}function oD(e,t){let n=Xe[e];return n?gh(e,t)?!1:n.up.test(t)&&wh(e,t)==="idle":!0}function gh(e,t){let n=Xe[e];if(!n)return!1;let r=e==="codex"?Fr(t):t;return n.auth?.test(r)&&!n.up.test(r)?!0:n.block?.test(r)?e==="codex"?!0:!n.up.test(r):!1}function yh(e,t){let n=String(t||"").trim();if(!n)return e;let r=String(e||"").split(`
119
119
  `);for(let o=r.length-1;o>=0;o--)if(r[o].includes(n))return r.slice(o+1).join(`
120
- `);return e}function h0(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function u0(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 d0(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null,onReady:s}={}){let a=Date.now()+n,i=0,c=null;for(await Ao(e).catch(()=>{});;){let l=jf(await Be(e),o);if(bP(t,l))return await s?.(),await An(Ms),"up";if(Ye[t]?.up&&!Ye[t].up.test(l))if(await Xn(e)){if(c??=Date.now(),Date.now()-c>=li()){let u=u0(t);throw le({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"&&dP.test(l)&&!Ye.claude.up.test(l))return le({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{}),"dialog-bail";if(t==="codex"&&uP.test(l)&&!Ye.codex.up.test(l)&&i<3){if(!Nf(e,"codex-trust")){await An(Jl);continue}i+=1,await le({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await ot(e,"",{enter:!0,kind:"codex-trust-accept"}),await An(Ms);continue}if(t==="cursor"&&lP.test(l)&&!Ye.cursor.up.test(l)&&i<3){if(!Nf(e,"cursor-trust")){await An(Jl);continue}i+=1,await le({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await ot(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await An(Ms);continue}if(t==="codex"&&i<3){let u=fP(l);if(u){if(!Nf(e,`codex-update:${u.from}->${u.to}`)){await An(Jl);continue}i+=1,await le({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${u.from} -> ${u.to}`}).catch(()=>{}),await ot(e,"3",{enter:!1,kind:"codex-update-skip"}),r0({sessionName:e,from:u.from,to:u.to}),await An(Ms);continue}}if(Date.now()>a){if(Bf(t,l)){let u=`${t} is blocked on an interactive prompt`;throw t==="codex"?u=Ye.codex.auth.test(l)?"codex isn't signed in on this box \u2014 answer the Sign in card in chat (Device Code works from any device) or finish signing in from the Terminal tab, then send again":"codex is stuck on its update prompt (auto-skip didn't clear it) \u2014 open the terminal and choose Skip, then send again":t==="cursor"&&Ye.cursor.auth.test(l)?u="cursor isn't signed in on this box \u2014 answer the Sign in card in chat (the login link works from any device) or finish signing in from the Terminal tab, then send again":t==="claude"&&Ye.claude.auth.test(l)?u="claude isn't signed in on this box \u2014 answer the setup cards in chat (or finish signing in from the Terminal tab), then send again":t==="claude"&&Ye.claude.block.test(l)&&(u='claude is waiting on its "Press Enter to continue" screen \u2014 answer the Continue card in chat (or press Enter in the Terminal tab), then send again'),le({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u}).catch(()=>{}),new Error(u)}if(await Xn(e)){let u=u0(t);throw le({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u.message}).catch(()=>{}),u}return console.warn(`[agent-ready] ${t} readiness unconfirmed in ${e} after ${n}ms \u2014 driving the box anyway.`),le({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,paneBlocked:!!Ye[t]?.block?.test(l),paneUp:!!Ye[t]?.up?.test(l),paneBusy:!!Ye[t]?.busy?.test(f0(Ye[t],l))}).catch(()=>{}),await An(Ms),"timeout"}await An(Jl)}}function Lf({agent:e,agentCmd:t}={}){let n=t?$r(t):$r(e||"");return{label:n,realClaude:t?To(t):n==="claude",realCodex:t?/codex/.test(t)&&!/fake-codex|fake-lead/.test(t):n==="codex",realCursor:t?/cursor/.test(t)&&!/fake-cursor|fake-box/.test(t):n==="cursor"}}function w0({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=Lf({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function yi({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}={}){let{realCodex:s,realCursor:a}=Lf({agent:n,agentCmd:r});return!t||!s&&!a?null:Cr({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).then(()=>{},()=>{})}async function Cr({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=sP(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:d,realCursor:p}=Lf({agent:r,agentCmd:o});if(u&&e&&await vr(e),d&&e&&await ms(e),p&&e&&await hs(e),(u||d||p)&&n)return await d0(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c});let f=Ye[r]?r:Ye[l]?l:null;return process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&f?await d0(n,f,s,{launchEcho:i}):(await An(Ms),"settle")}var sP,Jl,Ms,aP,iP,Ye,lP,uP,dP,pP,mP,Yl,hP,p0,gP,yP,bi=K(()=>{ct();qa();hl();wl();zl();Vl();Tn();sP=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,Jl=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,Ms=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,aP=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,iP=/^\s*tab to queue message\b/;Ye={claude:{up:/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/,busy:/esc to interrupt/,busyScope:"footer",busyAlt:/^[·✢✳✶✻✽✺✹✸✷]\s+[A-Z][\w '’-]{1,40}…/m,auth:/Select login method:|Paste code here if prompted|OAuth error:|Choose the text style that looks best|Quick safety check: Is this a project you created/,block:/Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/m},codex:{up:{test:cP},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/}},lP=/Trust this workspace|\[a\]\s*Trust/,uP=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,dP=/Resume from summary/i,pP=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;mP=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,Yl=new Map;hP=68,p0=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;gP=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,yP=15});function SP(e){return typeof e!="string"||!e?!1:e.includes(`
121
- `)?!0:Buffer.byteLength(e,"utf8")>=vP}function En(e,t){return e==="codex"?{enter:!0,submitDelayMs:kP,...SP(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:xP}:{enter:!0}}var kP,xP,vP,ki=K(()=>{kP=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),xP=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),vP=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function xi(e,t){if(e==="codex")return IP(t);if(e!=="claude")return null;let n=String(t).replace(/\r/g,"").split(`
122
- `).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(g0.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(g0.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(TP);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 IP(e){let t=String(e).replace(/\r/g,"").split(`
123
- `).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){(AP.test(t[o])||EP.test(t[o]))&&!Ff.test(t[o])?n=o:Ff.test(t[o])&&/\[Pasted Content \d+ chars\]/.test(t[o])&&(n=o+1);break}if(n<=0)return null;let r=[];for(let o=n-1;o>=0&&n-o<=60;o--){let s=t[o],a=s.match(Ff);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(_P.test(s))return null;r.unshift(s)}return null}function Uf(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=Fe(n.replace($P,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!Fe(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function Fe(e){return String(e||"").replace(/\s+/g," ").trim()}function y0(e,t,{slackMs:n=2e4}={}){let r=Fe(t?.text);if(!r||typeof t?.at!="number")return!1;let o=Array.isArray(e)?e:[],s=o.findIndex(a=>a?.role==="user"&&typeof a.ts=="number"&&a.ts>=t.at-n&&Fe(a.text).includes(r));return s>=0&&s<o.length-1}function b0(e,t,n,{busy:r=!1}={}){let o=xi(e,n);return o&&Xl(t,o)||o&&e==="codex"&&Uf(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function Xl(e,t){let n=Fe(e),r=Fe(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var g0,TP,Ff,AP,EP,_P,$P,vi=K(()=>{g0=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,TP=/^❯[  ]?(.*)$/,Ff=/^\s*›[  ]?(.*)$/,AP=/\S+ · \S/,EP=/^\s*(?:\? for shortcuts|tab to queue message)\b/,_P=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;$P=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function Ti({sessionName:e,agent:t,agentCmd:n=null,text:r,trackId:o=null,flow:s="say",stats:a=null},i={}){let c=(i.now||Date.now)(),l=(U,H,_={})=>(a&&typeof a=="object"&&Object.assign(a,{verdict:U,retries:_.retries??0,ms:(i.now||Date.now)()-c,sawUp:!!_.sawUp,reason:_.reason??null}),H);if(!RP.has(t))return l("skipped",!0);let u=i.waitForUp??w0({agent:t,agentCmd:n}),d=i.capture||(U=>Be(U,{lines:Ze})),p=i.pressEnter||(U=>qe(U,["Enter"],{kind:"submit-retry"})),f=i.sleep||NP,w=i.now||Date.now,m=i.log||(U=>le(U).catch(()=>{})),g=i.maxMs??CP(),y=w()+g,x={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},b=0,O=0,I=0,C=!1;for(await f(Si[0]);;){let U=await d(e).catch(()=>""),H=Ns(t,U),_=Cs(t,U),$=b0(t,r,U,{busy:_});if($==="submitted")return l("submitted",!0,{retries:b,sawUp:!0});if(u&&(!H||$==="stuck"&&_)){if(w()>=y)return $==="stuck"?(m({...x,phase:"submit-failed",reason:"stuck-at-deadline",retries:b}),l("failed",!1,{retries:b,sawUp:C,reason:"stuck-at-deadline"})):(m({...x,phase:"submit-unverified",reason:C?"cli-down":"cli-never-up",retries:b,waitedMs:g}),l("unverified",!0,{retries:b,sawUp:C,reason:C?"cli-down":"cli-never-up"}));await f(OP);continue}if(C=!0,$==="stuck"){if(b>=MP)return m({...x,phase:"submit-failed",retries:b}),l("failed",!1,{retries:b,sawUp:!0,reason:"stuck"});b+=1,O=0,I=0,await p(e),m({...x,phase:"submit-retry",attempt:b}),await f(Si[0]);continue}if(O+=1,O>=Si.length||w()>=y)return l("assumed",!0,{retries:b,sawUp:!0});I+=1,await f(Si[Math.min(I,Si.length-1)])}}var RP,Si,OP,MP,CP,NP,Hf=K(()=>{ct();bi();vi();Tn();RP=new Set(["claude","codex"]),Si=[250,450,700],OP=500,MP=2,CP=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},NP=e=>new Promise(t=>setTimeout(t,e))});function k0(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function Zn(e){let t=k0(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of PP){let o=0;for(let s of DP[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function x0(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))BP.has(r)&&(t+=o||0),jP.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function Ai(e){return String(e||"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[-_/]+/g," ")}function v0(e){let t=k0(e).trim();return t?FP.test(t)?!0:t.split(/\s+/).length<=LP:!1}var PP,DP,BP,jP,LP,FP,Zl=K(()=>{PP=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],DP={research:[/\bresearch\b/,/\binvestigat/,/\bverif/,/\bcompar(e|ing|ison)/,/\bcompetit/,/\bdeep[ -]?dive\b/,/\banaly[sz]/,/\bassess/,/\bdiligence\b/,/\bmarket\b/,/\bstrateg/,/\broadmap\b/,/\bnorth star/,/\bwhat('| i)?s the (state|status)\b/,/\bstatus of\b/,/\bexplore\b/,/\bfeasib/,/\bevaluat/,/\bscope (it |this |that |them )?out\b/,/\btalk (me |us )?through\b/,/\b(give|show|tell) me\b/,/\bwhat about\b/,/\bwhy\b/,/\btake a look\b/,/\bwalk (me |us )?through\b/,/\bexplain\b/,/\bdo we (still |even )?need\b/,/\bis there (a|an|any)\b/,/\bhow often\b/,/\bdo we (currently|already)\b/,/\bwould it be (valuable|useful|worth)\b/,/\bis it possible\b/],"bug-fix":[/\bfix(e[sd]|ing)?\b/,/\bbugs?\b/,/\bbroken\b/,/\bregression\b/,/\bcrash/,/\bincident\b/,/\bdebug/,/\bdoesn'?t (work|render|load|start)/,/\bnot working\b/,/\btroubleshoot/,/\bflaky?\b/,/\brepro(duce|duction)?\b/,/\brace condition\b/,/\bleak\b/,/\bkeeps? getting\b/,/\bdoesn'?t (seem|look) right\b/,/\bseems? (wrong|off|broken)\b/,/\b(too slow|slower than|much slower)\b/,/\bfail(ed|ing|s)\b/],"feature-build":[/\bimplement/,/\bbuild(ing)?\b/,/\badd(ing)?\b/,/\bcreate\b/,/\bwire (it |them )?(up|in)\b/,/\bship(ping)?\b/,/\bintegrat/,/\bsupport for\b/,/\bfeature\b/,/\bendpoint\b/,/\badapter\b/,/\bprototype\b/,/\bupdate (the |this |that |my |our )?[\w-]+( [\w-]+){0,3} to\b/,/\bset up\b/],design:[/\bdesign/,/\bui\b/,/\bux\b/,/\bstyl(e|es|ing)\b/,/\bcss\b/,/\blayout\b/,/\bmock-?up/,/\brender(ing|s)?\b/,/\bpolish/,/\btheme\b/,/\bfonts?\b/,/\bresponsive\b/,/\banimation/,/\bvisual/,/\bpopover\b/],orchestration:[/\bhand[ -]?(off|over)/,/\bhand (it|the lead|this) (over|off)\b/,/\bdelegat/,/\bsubtask/,/\bmerge[ -]?back\b/,/\borchestrat/,/\b(switch|change) (the )?model\b/,/\bmodel switch/],"docs-writing":[/\bdocs?\b/,/\bdocument/,/\bmemo\b/,/\breadme\b/,/\bwrite-?up\b/,/\bchangelog\b/,/\bclaude\.md\b/,/\bblog/,/\bproofread/,/\bcopy(edit|writ)/,/\b(linked[ -]?in|social( media)?) post\b/],"ops-infra":[/\bdeploy/,/\bsystemd\b/,/\bdaemon\b/,/\btmux\b/,/\bdns\b/,/\bwireguard\b/,/\brestart/,/\bnginx\b/,/\bprovision/,/\binstall/,/\bupgrade/,/\bcron\b/,/\bbackups?\b/,/\bcertificat/,/\bssh\b/,/\bsecrets?\b/,/\b(unzip|decompress|untar)\b/]};BP=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),jP=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);LP=12,FP=/^\s*(ok(ay)?|yes|yep|yeah|sure|go ahead|go|proceed|continue|next|begin|start|do it|do that|try again|try once more|again|ship it|perfect|great|good|nice|thanks|lock(ed)? (it |that |those )?in|option [a-z]\b|where are we|what'?s the status)\b/i});function E0(e){let t=Ai(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||UP.has(r)||n.push(r);return n}function HP(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(A0(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(A0(n,"assistant",o))}}return t}function A0(e,t,n){let r=Zn(n);return{id:e.id,seq:e.seq,ts:e.payload?.ts??e.ts,role:t,boxId:e.boxId??null,provider:e.provider??null,text:n,tags:r?[r.category]:[]}}function Ei(e){let t=HP(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=E0(a.text);r[i]=c.length,o+=c.length;let l=new Map;for(let u of c)l.set(u,(l.get(u)||0)+1);for(let[u,d]of l){let p=n.get(u);p||n.set(u,p=new Map),p.set(i,d)}});let s=t.length;return{chunks:t,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function Ql(e,t,n={}){let{k:r=8,role:o=null,tag:s=null,boxId:a=null}=n;if(!e||!e.N)return[];let i=[...new Set(E0(t))];if(!i.length)return[];let c=new Map;for(let u of i){let d=e.postings.get(u);if(!d)continue;let p=d.size,f=Math.log(1+(e.N-p+.5)/(p+.5));for(let[w,m]of d){let g=e.lengths[w],y=m+S0*(1-T0+T0*(g/(e.avgdl||1))),x=f*(m*(S0+1)/y);c.set(w,(c.get(w)||0)+x)}}let l=[];for(let[u,d]of c){let p=e.chunks[u];o&&p.role!==o||s&&!p.tags.includes(s)||a&&p.boxId!==a||l.push({chunk:p,score:d})}return l.sort((u,d)=>d.score-u.score||d.chunk.seq-u.chunk.seq),l.slice(0,r)}var S0,T0,UP,Wf=K(()=>{Zl();S0=1.5,T0=.75,UP=new Set("a an and are as at be been but by for from had has have he her his i if in into is it its of on or our so than that the their them then there these they this those to was were will with would you your we".split(" "))});import eu from"node:fs/promises";import _0 from"node:path";async function WP(e){let t=_0.join(e,".bostrat","events"),n;try{n=await eu.readdir(t)}catch{return Ei([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await eu.readFile(_0.join(t,o),"utf8");for(let a of s.split(`
124
- `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return Ei(r)}function qP(e){let t=String(e||""),n=a=>{let i=t.match(a);return i?i[1].trim():""},r=n(/#+\s*Objective\s*\n([\s\S]*?)(?:\n#+\s|$)/i),o=n(/#+\s*Next steps?[^\n]*\n([\s\S]*?)(?:\n#+\s|$)/i);return`${r}
125
- ${o}`.trim()||t.slice(0,2e3)}function KP(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=Ql(e,t,{k:n*2+4}),a=[],i=0;for(let{chunk:c}of s){if(o&&o(c))continue;let l=c.role==="user"?"Operator":`Agent${c.provider?` (${c.provider})`:""}`,u=c.text.trim(),d=u.length>800?u.slice(0,800)+"\u2026":u,p=`- **${l}:** ${d}`;if(i+p.length>r||(a.push(p),i+=p.length,a.length>=n))break}return a.length?["",`## ${I0}, not a summary)`,"_Auto-selected from the Track's event log by lexical relevance to the Objective / Next steps. Verbatim excerpts, not re-summarization (docs/memory-segmentation-indexing-scope.md \xA71.3)._","",...a,""].join(`
126
- `):""}async function $0(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await eu.readFile(t,"utf8");if(a.includes(I0))return{appended:!1,reason:"already-enriched"};let i=await WP(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=KP(i,qP(a),{k:r,maxChars:o,exclude:s});return c?(await eu.appendFile(t,`
120
+ `);return e}function Q0(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function V0(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 J0(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null,onReady:s}={}){let a=Date.now()+n,i=0,c=null;for(await Bo(e).catch(()=>{});;){let l=yh(await Pe(e),o);if(oD(t,l))return await s?.(),await _n(Ys),"up";if(Xe[t]?.up&&!Xe[t].up.test(l))if(await Qn(e)){if(c??=Date.now(),Date.now()-c>=Ii()){let u=V0(t);throw ue({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,idleMs:Date.now()-c,error:u.message}).catch(()=>{}),u}}else c=null;else c=null;if(r&&t==="claude"&&YP.test(l)&&!Xe.claude.up.test(l))return ue({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{}),"dialog-bail";if(t==="codex"&&JP.test(l)&&!Xe.codex.up.test(l)&&i<3){if(!hh(e,"codex-trust")){await _n(wu);continue}i+=1,await ue({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await ot(e,"",{enter:!0,kind:"codex-trust-accept"}),await _n(Ys);continue}if(t==="cursor"&&VP.test(l)&&!Xe.cursor.up.test(l)&&i<3){if(!hh(e,"cursor-trust")){await _n(wu);continue}i+=1,await ue({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await ot(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await _n(Ys);continue}if(t==="codex"&&i<3){let u=ZP(l);if(u){if(!hh(e,`codex-update:${u.from}->${u.to}`)){await _n(wu);continue}i+=1,await ue({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${u.from} -> ${u.to}`}).catch(()=>{}),await ot(e,"3",{enter:!1,kind:"codex-update-skip"}),U0({sessionName:e,from:u.from,to:u.to}),await _n(Ys);continue}}if(Date.now()>a){if(gh(t,l)){let u=`${t} is blocked on an interactive prompt`;throw t==="codex"?u=Xe.codex.auth.test(l)?"codex isn't signed in on this box \u2014 answer the Sign in card in chat (Device Code works from any device) or finish signing in from the Terminal tab, then send again":"codex is stuck on its update prompt (auto-skip didn't clear it) \u2014 open the terminal and choose Skip, then send again":t==="cursor"&&Xe.cursor.auth.test(l)?u="cursor isn't signed in on this box \u2014 answer the Sign in card in chat (the login link works from any device) or finish signing in from the Terminal tab, then send again":t==="claude"&&Xe.claude.auth.test(l)?u="claude isn't signed in on this box \u2014 answer the setup cards in chat (or finish signing in from the Terminal tab), then send again":t==="claude"&&Xe.claude.block.test(l)&&(u='claude is waiting on its "Press Enter to continue" screen \u2014 answer the Continue card in chat (or press Enter in the Terminal tab), then send again'),ue({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u}).catch(()=>{}),new Error(u)}if(await Qn(e)){let u=V0(t);throw ue({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:u.message}).catch(()=>{}),u}return console.warn(`[agent-ready] ${t} readiness unconfirmed in ${e} after ${n}ms \u2014 driving the box anyway.`),ue({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,paneBlocked:!!Xe[t]?.block?.test(l),paneUp:!!Xe[t]?.up?.test(l),paneBusy:!!Xe[t]?.busy?.test(X0(Xe[t],l))}).catch(()=>{}),await _n(Ys),"timeout"}await _n(wu)}}function bh({agent:e,agentCmd:t}={}){let n=t?Br(t):Br(e||"");return{label:n,realClaude:t?Do(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 ex({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=bh({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function Ho({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}={}){let{realCodex:s,realCursor:a}=bh({agent:n,agentCmd:r});return!t||!s&&!a?null:er({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).then(()=>{},()=>{})}async function er({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=qP(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:d,realCursor:p}=bh({agent:r,agentCmd:o});if(u&&e&&await $r(e),d&&e&&await Os(e),p&&e&&await Ms(e),(u||d||p)&&n)return await J0(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c});let f=Xe[r]?r:Xe[l]?l:null;return process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&f?await J0(n,f,s,{launchEcho:i}):(await _n(Ys),"settle")}var qP,wu,Ys,KP,GP,Xe,VP,JP,YP,XP,QP,gu,eD,Y0,nD,rD,Bi=q(()=>{ut();ai();Ml();Cl();hu();mu();Tn();qP=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,wu=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,Ys=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,KP=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,GP=/^\s*tab to queue message\b/;Xe={claude:{up:/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/,busy:/esc to interrupt/,busyScope:"footer",busyAlt:/^[·✢✳✶✻✽✺✹✸✷]\s+[A-Z][\w '’-]{1,40}…/m,auth:/Select login method:|Paste code here if prompted|OAuth error:|Choose the text style that looks best|Quick safety check: Is this a project you created/,block:/Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/m},codex:{up:{test:zP},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/}},VP=/Trust this workspace|\[a\]\s*Trust/,JP=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,YP=/Resume from summary/i,XP=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;QP=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,gu=new Map;eD=68,Y0=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;nD=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,rD=15});function cD(e){return typeof e!="string"||!e?!1:e.includes(`
121
+ `)?!0:Buffer.byteLength(e,"utf8")>=iD}function In(e,t){return e==="codex"?{enter:!0,submitDelayMs:sD,...cD(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:aD}:{enter:!0}}var sD,aD,iD,ji=q(()=>{sD=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),aD=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),iD=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function Li(e,t){if(e==="codex")return fD(t);if(e!=="claude")return null;let n=String(t).replace(/\r/g,"").split(`
122
+ `).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(tx.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(tx.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(lD);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 fD(e){let t=String(e).replace(/\r/g,"").split(`
123
+ `).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){(uD.test(t[o])||dD.test(t[o]))&&!kh.test(t[o])?n=o:kh.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(kh);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(pD.test(s))return null;r.unshift(s)}return null}function xh(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=Le(n.replace(hD,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!Le(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function Le(e){return String(e||"").replace(/\s+/g," ").trim()}function nx(e,t,{slackMs:n=2e4}={}){let r=Le(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&&Le(a.text).includes(r));return s>=0&&s<o.length-1}function rx(e,t,n,{busy:r=!1}={}){let o=Li(e,n);return o&&yu(t,o)||o&&e==="codex"&&xh(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function yu(e,t){let n=Le(e),r=Le(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var tx,lD,kh,uD,dD,pD,hD,Fi=q(()=>{tx=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,lD=/^❯[  ]?(.*)$/,kh=/^\s*›[  ]?(.*)$/,uD=/\S+ · \S/,dD=/^\s*(?:\? for shortcuts|tab to queue message)\b/,pD=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;hD=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function Hi({sessionName:e,agent:t,agentCmd:n=null,text:r,trackId:o=null,flow:s="say",stats:a=null},i={}){let c=(i.now||Date.now)(),l=(U,j,T={})=>(a&&typeof a=="object"&&Object.assign(a,{verdict:U,retries:T.retries??0,ms:(i.now||Date.now)()-c,sawUp:!!T.sawUp,reason:T.reason??null}),j);if(!mD.has(t))return l("skipped",!0);let u=i.waitForUp??ex({agent:t,agentCmd:n}),d=i.capture||(U=>Pe(U,{lines:Ye})),p=i.pressEnter||(U=>We(U,["Enter"],{kind:"submit-retry"})),f=i.sleep||bD,w=i.now||Date.now,h=i.log||(U=>ue(U).catch(()=>{})),g=i.maxMs??yD(),y=w()+g,x={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},b=0,I=0,_=0,N=!1;for(await f(Ui[0]);;){let U=await d(e).catch(()=>""),j=Uo(t,U),T=Xs(t,U),R=rx(t,r,U,{busy:T});if(R==="submitted")return l("submitted",!0,{retries:b,sawUp:!0});if(u&&(!j||R==="stuck"&&T)){if(w()>=y)return R==="stuck"?(h({...x,phase:"submit-failed",reason:"stuck-at-deadline",retries:b}),l("failed",!1,{retries:b,sawUp:N,reason:"stuck-at-deadline"})):(h({...x,phase:"submit-unverified",reason:N?"cli-down":"cli-never-up",retries:b,waitedMs:g}),l("unverified",!0,{retries:b,sawUp:N,reason:N?"cli-down":"cli-never-up"}));await f(wD);continue}if(N=!0,R==="stuck"){if(b>=gD)return h({...x,phase:"submit-failed",retries:b}),l("failed",!1,{retries:b,sawUp:!0,reason:"stuck"});b+=1,I=0,_=0,await p(e),h({...x,phase:"submit-retry",attempt:b}),await f(Ui[0]);continue}if(I+=1,I>=Ui.length||w()>=y)return l("assumed",!0,{retries:b,sawUp:!0});_+=1,await f(Ui[Math.min(_,Ui.length-1)])}}var mD,Ui,wD,gD,yD,bD,vh=q(()=>{ut();Bi();Fi();Tn();mD=new Set(["claude","codex"]),Ui=[250,450,700],wD=500,gD=2,yD=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},bD=e=>new Promise(t=>setTimeout(t,e))});function ox(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function tr(e){let t=ox(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of kD){let o=0;for(let s of xD[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function sx(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))vD.has(r)&&(t+=o||0),SD.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function Wi(e){return String(e||"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").replace(/[-_/]+/g," ")}function ax(e){let t=ox(e).trim();return t?TD.test(t)?!0:t.split(/\s+/).length<=AD:!1}var kD,xD,vD,SD,AD,TD,bu=q(()=>{kD=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],xD={research:[/\bresearch\b/,/\binvestigat/,/\bverif/,/\bcompar(e|ing|ison)/,/\bcompetit/,/\bdeep[ -]?dive\b/,/\banaly[sz]/,/\bassess/,/\bdiligence\b/,/\bmarket\b/,/\bstrateg/,/\broadmap\b/,/\bnorth star/,/\bwhat('| i)?s the (state|status)\b/,/\bstatus of\b/,/\bexplore\b/,/\bfeasib/,/\bevaluat/,/\bscope (it |this |that |them )?out\b/,/\btalk (me |us )?through\b/,/\b(give|show|tell) me\b/,/\bwhat about\b/,/\bwhy\b/,/\btake a look\b/,/\bwalk (me |us )?through\b/,/\bexplain\b/,/\bdo we (still |even )?need\b/,/\bis there (a|an|any)\b/,/\bhow often\b/,/\bdo we (currently|already)\b/,/\bwould it be (valuable|useful|worth)\b/,/\bis it possible\b/],"bug-fix":[/\bfix(e[sd]|ing)?\b/,/\bbugs?\b/,/\bbroken\b/,/\bregression\b/,/\bcrash/,/\bincident\b/,/\bdebug/,/\bdoesn'?t (work|render|load|start)/,/\bnot working\b/,/\btroubleshoot/,/\bflaky?\b/,/\brepro(duce|duction)?\b/,/\brace condition\b/,/\bleak\b/,/\bkeeps? getting\b/,/\bdoesn'?t (seem|look) right\b/,/\bseems? (wrong|off|broken)\b/,/\b(too slow|slower than|much slower)\b/,/\bfail(ed|ing|s)\b/],"feature-build":[/\bimplement/,/\bbuild(ing)?\b/,/\badd(ing)?\b/,/\bcreate\b/,/\bwire (it |them )?(up|in)\b/,/\bship(ping)?\b/,/\bintegrat/,/\bsupport for\b/,/\bfeature\b/,/\bendpoint\b/,/\badapter\b/,/\bprototype\b/,/\bupdate (the |this |that |my |our )?[\w-]+( [\w-]+){0,3} to\b/,/\bset up\b/],design:[/\bdesign/,/\bui\b/,/\bux\b/,/\bstyl(e|es|ing)\b/,/\bcss\b/,/\blayout\b/,/\bmock-?up/,/\brender(ing|s)?\b/,/\bpolish/,/\btheme\b/,/\bfonts?\b/,/\bresponsive\b/,/\banimation/,/\bvisual/,/\bpopover\b/],orchestration:[/\bhand[ -]?(off|over)/,/\bhand (it|the lead|this) (over|off)\b/,/\bdelegat/,/\bsubtask/,/\bmerge[ -]?back\b/,/\borchestrat/,/\b(switch|change) (the )?model\b/,/\bmodel switch/],"docs-writing":[/\bdocs?\b/,/\bdocument/,/\bmemo\b/,/\breadme\b/,/\bwrite-?up\b/,/\bchangelog\b/,/\bclaude\.md\b/,/\bblog/,/\bproofread/,/\bcopy(edit|writ)/,/\b(linked[ -]?in|social( media)?) post\b/],"ops-infra":[/\bdeploy/,/\bsystemd\b/,/\bdaemon\b/,/\btmux\b/,/\bdns\b/,/\bwireguard\b/,/\brestart/,/\bnginx\b/,/\bprovision/,/\binstall/,/\bupgrade/,/\bcron\b/,/\bbackups?\b/,/\bcertificat/,/\bssh\b/,/\bsecrets?\b/,/\b(unzip|decompress|untar)\b/]};vD=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),SD=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);AD=12,TD=/^\s*(ok(ay)?|yes|yep|yeah|sure|go ahead|go|proceed|continue|next|begin|start|do it|do that|try again|try once more|again|ship it|perfect|great|good|nice|thanks|lock(ed)? (it |that |those )?in|option [a-z]\b|where are we|what'?s the status)\b/i});function ux(e){let t=Wi(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||ED.has(r)||n.push(r);return n}function _D(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(lx(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(lx(n,"assistant",o))}}return t}function lx(e,t,n){let r=tr(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 qi(e){let t=_D(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=ux(a.text);r[i]=c.length,o+=c.length;let l=new Map;for(let u of c)l.set(u,(l.get(u)||0)+1);for(let[u,d]of l){let p=n.get(u);p||n.set(u,p=new Map),p.set(i,d)}});let s=t.length;return{chunks:t,postings:n,lengths:r,N:s,avgdl:s?o/s:0}}function ku(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(ux(t))];if(!i.length)return[];let c=new Map;for(let u of i){let d=e.postings.get(u);if(!d)continue;let p=d.size,f=Math.log(1+(e.N-p+.5)/(p+.5));for(let[w,h]of d){let g=e.lengths[w],y=h+ix*(1-cx+cx*(g/(e.avgdl||1))),x=f*(h*(ix+1)/y);c.set(w,(c.get(w)||0)+x)}}let l=[];for(let[u,d]of c){let p=e.chunks[u];o&&p.role!==o||s&&!p.tags.includes(s)||a&&p.boxId!==a||l.push({chunk:p,score:d})}return l.sort((u,d)=>d.score-u.score||d.chunk.seq-u.chunk.seq),l.slice(0,r)}var ix,cx,ED,Sh=q(()=>{bu();ix=1.5,cx=.75,ED=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 xu from"node:fs/promises";import dx from"node:path";async function ID(e){let t=dx.join(e,".bostrat","events"),n;try{n=await xu.readdir(t)}catch{return qi([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await xu.readFile(dx.join(t,o),"utf8");for(let a of s.split(`
124
+ `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return qi(r)}function $D(e){let t=String(e||""),n=a=>{let i=t.match(a);return i?i[1].trim():""},r=n(/#+\s*Objective\s*\n([\s\S]*?)(?:\n#+\s|$)/i),o=n(/#+\s*Next steps?[^\n]*\n([\s\S]*?)(?:\n#+\s|$)/i);return`${r}
125
+ ${o}`.trim()||t.slice(0,2e3)}function RD(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=ku(e,t,{k:n*2+4}),a=[],i=0;for(let{chunk:c}of s){if(o&&o(c))continue;let l=c.role==="user"?"Operator":`Agent${c.provider?` (${c.provider})`:""}`,u=c.text.trim(),d=u.length>800?u.slice(0,800)+"\u2026":u,p=`- **${l}:** ${d}`;if(i+p.length>r||(a.push(p),i+=p.length,a.length>=n))break}return a.length?["",`## ${px}, not a summary)`,"_Auto-selected from the Track's event log by lexical relevance to the Objective / Next steps. Verbatim excerpts, not re-summarization (docs/memory-segmentation-indexing-scope.md \xA71.3)._","",...a,""].join(`
126
+ `):""}async function fx(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await xu.readFile(t,"utf8");if(a.includes(px))return{appended:!1,reason:"already-enriched"};let i=await ID(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=RD(i,$D(a),{k:r,maxChars:o,exclude:s});return c?(await xu.appendFile(t,`
127
127
  `+c),{appended:!0,chars:c.length,chunks:c.split(`
128
- - `).length-1,indexed:i.N}):{appended:!1,reason:"no-hits",indexed:i.N}}catch(a){return{appended:!1,reason:"error",error:a?.message||String(a)}}}var I0,R0=K(()=>{Wf();I0="Relevant prior discussion (verbatim, retrieved"});function XP(e){return GP.test(String(e||"").trimStart())}function C0(e){let t=String(e||"");if(!XP(t.trimStart()))return null;let n=t.replace(zP,"").trim(),r=ZP(n),o=[];for(let u of JP){let d=u.from.map(p=>Ps(r.get(p))).find(p=>p&&!O0(p));d&&o.push({h:u.h,text:_i(d,VP)})}let s=Ps(r.get("Current Work"))||Ps(r.get("Primary Request and Intent"))||eD(n),a=nu(s),i=_i(tu(Gf(a[0]||"")),YP)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(_i(tu(Gf(l)),Kf));for(let u of["Pending Tasks","Optional Next Step"]){let d=nu(Ps(r.get(u)))[0]||"";if(!(!d||O0(d))){c.push(_i(`Left to do: ${tu(Gf(d))}`,Kf));break}}if(!c.length){let u=nu(Ps(r.get("Problem Solving"))||"")[0];u&&c.push(_i(tu(u),Kf))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function ZP(e){let t=new Map,n=[];qf.lastIndex=0;for(let r=qf.exec(e);r;r=qf.exec(e))n.push({name:QP(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 QP(e){return M0.find(n=>n.toLowerCase()===e.toLowerCase())||e}function Ps(e){return e?String(e).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
129
- `).map(t=>t.replace(/^[ \t]*(?:[-*•]|\d+[.)]|[a-z][.)])[ \t]+/i,"").trim()).filter(t=>t&&!/^#{1,6}[ \t]/.test(t)).join(" ").replace(/\*\*(.+?)\*\*/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\s+/g," ").trim():""}function eD(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return Ps(t.split(/\n{2,}/).slice(0,2).join(" "))}function nu(e){let t=String(e||"").trim();if(!t)return[];let r=t.replace(/\b([A-Za-z0-9_-]+)\.(js|ts|tsx|mjs|json|md|css|jsonl|sh|yml|yaml|py|html)\b/g,"$1<DOT>$2").replace(/\b(e\.g|i\.e|etc|vs|approx|no|fig|Dr|Mr|Ms|St)\./gi,"$1<DOT>").split(/(?<=[.!?])["')\]]?\s+(?=[A-Z"“'(\[]|\d)/).map(s=>s.replace(/<DOT>/g,".").trim()).filter(Boolean),o=[];for(let s of r){let a=o[o.length-1];a&&(a.match(/["“”]/g)?.length??0)%2===1?o[o.length-1]=`${a} ${s}`:o.push(s)}return o}function Gf(e){return String(e||"").replace(/^(?:Immediately before (?:this|the) summary(?: request)?[,:]?\s*|At the (?:time|point) of (?:this )?compaction[,:]?\s*|Currently[,:]?\s*|The (?:most recent|immediately preceding|current) work (?:was|is)\s*)/i,"").replace(/^(?:I(?:'m|'d| am| was| had| have)?\s+(?:currently\s+|just\s+)?(?:been\s+)?(?:working on|in the middle of|completing|finishing)\s+|The user(?:'s)?\s+(?:most recent\s+)?(?:request|ask) (?:was|is)\s+(?:to\s+)?)/i,"").replace(/^I(?:'m|'d| am| was| had| have)?\s+(?:just\s+|then\s+)?(?=(?:[a-z]+(?:ed|ing)|ran|wrote|built|made|began|found|left|sent|took|went|did|got|kept|held|brought|caught|chose|came|saw|said|gave|told|set|put|read)\b)/,"").replace(/^["“]|["”]$/g,"").replace(/^(\w)/,t=>t.toUpperCase()).trim()}function tu(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function O0(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function _i(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=nu(n),o="";for(let i of r){let c=o?`${o} ${i}`:i;if(c.length>t)break;o=c}if(o.length>=Math.min(60,t*.4))return o;let s=n.slice(0,t),a=s.lastIndexOf(" ");return`${(a>t*.6?s.slice(0,a):s).replace(/[,;:.\s]+$/,"")}\u2026`}var GP,M0,qf,zP,VP,JP,YP,Kf,N0=K(()=>{GP=/^This session is being continued from a previous conversation that ran out of context\./,M0=["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"],qf=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${M0.join("|")})[:*\t ]*$`,"gim"),zP=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,VP=420,JP=[{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"]}],YP=116,Kf=168});function B0(e){return zf.has(String(e||"").replace(/^\//,"").toLowerCase())}function Ii(e){let t=String(e||"").trim();if(!t)return null;let n=C0(t);if(n)return n;let r=t.match(tD);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(nD);if(o)return{kind:"skill",name:o[1]};let s=t.match(rD);if(s)return{kind:"skill",name:s[1].toLowerCase()};let a=t.match(oD);if(a){let c=a[1].toLowerCase();return zf.has(c)?{kind:"suppress"}:{kind:"command",command:`/${c}`}}let i=t.match(mD);if(i&&zf.has(i[1].toLowerCase()))return{kind:"suppress"};if(sD.test(t))return{kind:"suppress"};if(iD.test(t))return{kind:"suppress"};if(aD.test(t))return{kind:"suppress"};if(cD.test(t)){let c=u=>yD(t.match(u)?.[1].trim()||"")||null,l=c(fD);return{kind:"task",summary:c(lD)||"",taskId:c(uD),toolUseId:c(dD),status:c(pD)?.toLowerCase()||null,resultHead:l?l.length>P0?`${l.slice(0,P0).trimEnd()}\u2026`:l:null}}return null}function j0(e){let t=Ii(e?.text);return t||(e?.injected?{kind:"skill",name:e.injected.skill||"skill"}:null)}function L0(e){let t=String(e||""),n=t.match(hD);if(n)return{kind:"shell-input",command:n[1].trim()};let r=t.match(wD);return r?{kind:"shell-output",stdout:D0(r[1]),stderr:D0(r[2])}:null}function yD(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function F0(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 U0(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var tD,nD,rD,oD,sD,aD,iD,cD,lD,uD,dD,pD,fD,P0,zf,mD,hD,wD,gD,D0,ru=K(()=>{N0();tD=/^Base directory for this skill:\s*(\S+)/,nD=/^Run the "([^"]+)" workflow\./,rD=/^#\s*\/([a-z0-9:_-]+)\s*[—–:-]/i,oD=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,sD=/^<local-command-(?:stdout|caveat)>/i,aD=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,iD=/^Continue from where you left off\.$/,cD=/^<task-notification>/i,lD=/<summary>([\s\S]*?)<\/summary>/i,uD=/<task-id>([\s\S]*?)<\/task-id>/i,dD=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,pD=/<status>([\s\S]*?)<\/status>/i,fD=/<result>([\s\S]*?)(?:<\/result>|$)/i,P0=600,zf=new Set(["model","clear","compact","login","exit","quit"]);mD=/^\/([a-z0-9:_-]+)$/i;hD=/^\s*<bash-input>([\s\S]*?)<\/bash-input>\s*$/i,wD=/^\s*<bash-stdout>([\s\S]*?)<\/bash-stdout>\s*(?:<bash-stderr>([\s\S]*?)<\/bash-stderr>)?\s*$/i,gD=/\x1b\[[0-9;?]*[ -/]*[@-~]/g,D0=e=>String(e||"").replace(gD,"").replace(/^\n+/,"").replace(/\s+$/,"")});import bD from"node:crypto";function SD(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,W0)){let o=Ds(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,kD)){let c=Ds(i?.label);if(!c)return null;let l=Ds(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<xD)return null;n.push({question:o,header:Ds(r?.header).slice(0,vD),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Vf(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;H0.lastIndex=0;let t=null;for(let o;o=H0.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=SD(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function Jf(e,t,n){let r=bD.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function Yf(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=W0}={}){if(!Array.isArray(e)||!t||!n)return null;let s=null;for(let l=e.length-1;l>=0;l--){let u=e[l];if(u?.kind==="prompt")return null;if(u?.kind==="message"){if(u.role!=="assistant")return null;s=u;break}}if(!s||s.box!==t||s.agent!==n)return null;let a=s.ask?.questions||Vf(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=Jf(n,s.sourceId||s.id,a);return typeof r=="function"&&r(c)?null:{provider:n,box:t,promptId:c,groupId:c,answerMode:"say",source:"transcript",custom:!0,dismissable:!0,multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function q0(e,t,n,r){let o=[];(e?.questions||[]).forEach((i,c)=>{let l=(t?.[c]||[]).map(d=>i.options?.[d]?.label).filter(Boolean),u=Ds(Array.isArray(r)?r[c]:"");u&&l.push(u),l.length&&o.push({name:i.header||i.question,picks:l.join(", ")})});let s=Ds(n),a;return o.length?o.length===1?a=`${o[0].name}: ${o[0].picks}`:a=`Answers:
128
+ - `).length-1,indexed:i.N}):{appended:!1,reason:"no-hits",indexed:i.N}}catch(a){return{appended:!1,reason:"error",error:a?.message||String(a)}}}var px,hx=q(()=>{Sh();px="Relevant prior discussion (verbatim, retrieved"});function DD(e){return OD.test(String(e||"").trimStart())}function gx(e){let t=String(e||"");if(!DD(t.trimStart()))return null;let n=t.replace(MD,"").trim(),r=BD(n),o=[];for(let u of ND){let d=u.from.map(p=>Zs(r.get(p))).find(p=>p&&!mx(p));d&&o.push({h:u.h,text:Ki(d,CD)})}let s=Zs(r.get("Current Work"))||Zs(r.get("Primary Request and Intent"))||LD(n),a=Su(s),i=Ki(vu(Eh(a[0]||"")),PD)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(Ki(vu(Eh(l)),Th));for(let u of["Pending Tasks","Optional Next Step"]){let d=Su(Zs(r.get(u)))[0]||"";if(!(!d||mx(d))){c.push(Ki(`Left to do: ${vu(Eh(d))}`,Th));break}}if(!c.length){let u=Su(Zs(r.get("Problem Solving"))||"")[0];u&&c.push(Ki(vu(u),Th))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function BD(e){let t=new Map,n=[];Ah.lastIndex=0;for(let r=Ah.exec(e);r;r=Ah.exec(e))n.push({name:jD(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 jD(e){return wx.find(n=>n.toLowerCase()===e.toLowerCase())||e}function Zs(e){return e?String(e).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
129
+ `).map(t=>t.replace(/^[ \t]*(?:[-*•]|\d+[.)]|[a-z][.)])[ \t]+/i,"").trim()).filter(t=>t&&!/^#{1,6}[ \t]/.test(t)).join(" ").replace(/\*\*(.+?)\*\*/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\s+/g," ").trim():""}function LD(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return Zs(t.split(/\n{2,}/).slice(0,2).join(" "))}function Su(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 Eh(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 vu(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function mx(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function Ki(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=Su(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 OD,wx,Ah,MD,CD,ND,PD,Th,yx=q(()=>{OD=/^This session is being continued from a previous conversation that ran out of context\./,wx=["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"],Ah=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${wx.join("|")})[:*\t ]*$`,"gim"),MD=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,CD=420,ND=[{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"]}],PD=116,Th=168});function xx(e){return _h.has(String(e||"").replace(/^\//,"").toLowerCase())}function Gi(e){let t=String(e||"").trim();if(!t)return null;let n=gx(t);if(n)return n;let r=t.match(FD);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(UD);if(o)return{kind:"skill",name:o[1]};let s=t.match(HD);if(s)return{kind:"skill",name:s[1].toLowerCase()};let a=t.match(WD);if(a){let c=a[1].toLowerCase();return _h.has(c)?{kind:"suppress"}:{kind:"command",command:`/${c}`}}let i=t.match(QD);if(i&&_h.has(i[1].toLowerCase()))return{kind:"suppress"};if(qD.test(t))return{kind:"suppress"};if(GD.test(t))return{kind:"suppress"};if(KD.test(t))return{kind:"suppress"};if(zD.test(t)){let c=u=>r1(t.match(u)?.[1].trim()||"")||null,l=c(ZD);return{kind:"task",summary:c(VD)||"",taskId:c(JD),toolUseId:c(YD),status:c(XD)?.toLowerCase()||null,resultHead:l?l.length>bx?`${l.slice(0,bx).trimEnd()}\u2026`:l:null}}return null}function vx(e){let t=Gi(e?.text);return t||(e?.injected?{kind:"skill",name:e.injected.skill||"skill"}:null)}function Sx(e){let t=String(e||""),n=t.match(e1);if(n)return{kind:"shell-input",command:n[1].trim()};let r=t.match(t1);return r?{kind:"shell-output",stdout:kx(r[1]),stderr:kx(r[2])}:null}function r1(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function Ax(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 Tx(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var FD,UD,HD,WD,qD,KD,GD,zD,VD,JD,YD,XD,ZD,bx,_h,QD,e1,t1,n1,kx,Au=q(()=>{yx();FD=/^Base directory for this skill:\s*(\S+)/,UD=/^Run the "([^"]+)" workflow\./,HD=/^#\s*\/([a-z0-9:_-]+)\s*[—–:-]/i,WD=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,qD=/^<local-command-(?:stdout|caveat)>/i,KD=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,GD=/^Continue from where you left off\.$/,zD=/^<task-notification>/i,VD=/<summary>([\s\S]*?)<\/summary>/i,JD=/<task-id>([\s\S]*?)<\/task-id>/i,YD=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,XD=/<status>([\s\S]*?)<\/status>/i,ZD=/<result>([\s\S]*?)(?:<\/result>|$)/i,bx=600,_h=new Set(["model","clear","compact","login","exit","quit"]);QD=/^\/([a-z0-9:_-]+)$/i;e1=/^\s*<bash-input>([\s\S]*?)<\/bash-input>\s*$/i,t1=/^\s*<bash-stdout>([\s\S]*?)<\/bash-stdout>\s*(?:<bash-stderr>([\s\S]*?)<\/bash-stderr>)?\s*$/i,n1=/\x1b\[[0-9;?]*[ -/]*[@-~]/g,kx=e=>String(e||"").replace(n1,"").replace(/^\n+/,"").replace(/\s+$/,"")});import o1 from"node:crypto";function c1(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,_x)){let o=Qs(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,s1)){let c=Qs(i?.label);if(!c)return null;let l=Qs(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<a1)return null;n.push({question:o,header:Qs(r?.header).slice(0,i1),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function Ih(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;Ex.lastIndex=0;let t=null;for(let o;o=Ex.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=c1(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function $h(e,t,n){let r=o1.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function Rh(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=_x}={}){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||Ih(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=$h(n,s.sourceId||s.id,a);return typeof r=="function"&&r(c)?null:{provider:n,box:t,promptId:c,groupId:c,answerMode:"say",source:"transcript",custom:!0,dismissable:!0,multiSelect:i[0].multiSelect,questionIndex:0,questionTotal:i.length,questions:i}}function Ix(e,t,n,r){let o=[];(e?.questions||[]).forEach((i,c)=>{let l=(t?.[c]||[]).map(d=>i.options?.[d]?.label).filter(Boolean),u=Qs(Array.isArray(r)?r[c]:"");u&&l.push(u),l.length&&o.push({name:i.header||i.question,picks:l.join(", ")})});let s=Qs(n),a;return o.length?o.length===1?a=`${o[0].name}: ${o[0].picks}`:a=`Answers:
130
130
  ${o.map(i=>`- ${i.name}: ${i.picks}`).join(`
131
131
  `)}`:a=s,o.length&&s&&(a+=`
132
- ${s}`),a||""}var W0,kD,xD,vD,H0,Ds,K0,Xf=K(()=>{W0=4,kD=4,xD=2,vD=24,H0=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,Ds=e=>typeof e=="string"?e.trim():"";K0=`
132
+ ${s}`),a||""}var _x,s1,a1,i1,Ex,Qs,$x,Oh=q(()=>{_x=4,s1=4,a1=2,i1=24,Ex=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,Qs=e=>typeof e=="string"?e.trim():"";$x=`
133
133
  When you are BLOCKED on a decision only the operator can make \u2014 an ambiguous
134
134
  requirement, an irreversible choice, several valid approaches \u2014 do not bury the
135
135
  question in prose. End your message with exactly ONE fenced code block tagged
@@ -150,101 +150,105 @@ your turn. The operator sees the questions as an interactive card in their chat
150
150
  They may instead reply in free text \u2014 treat that as the answer. Never use the block for rhetorical questions, progress updates, or
151
151
  anything you can decide yourself; keep asking in prose for questions without
152
152
  enumerable options.
153
- `});function TD(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 z0(e,t,n){let r=Zf(n),o=e.has(r)?r:null;if(!o&&n.number!=null)for(let[i,c]of e){if(Number(c.number)!==Number(n.number))continue;let l=!!(n.url&&c.url&&n.url===c.url),u=!c.repo&&!!n.repo||!!c.repo&&!n.repo;if(l||u&&(!c.url||!n.url||c.url===n.url)){o=i;break}}let s=n.repo||!o?r:o,a=o?e.get(o):e.get(s);if(o&&o!==s){e.delete(o);let i=t.get(o);if(t.delete(o),i?.length){let c=t.get(s)??[];t.set(s,c.concat(i))}}return e.set(s,{number:n.number,url:n.url??a?.url??null,title:n.title??a?.title??null,repo:n.repo??a?.repo??null,branch:n.branch??a?.branch??null}),s}function _n(e){let t=[],n=new Set,r=new Set,o=new Map,s=new Map,a=new Set,i=new Map,c=new Map,l=new Set,u=new Map,d=new Map,p=(k,h)=>{d.set(k,h),t.push(h)},f=k=>{let h=d.get(k);h&&(h.retired=!0)},w=/^Agent "([\s\S]+)" finished$/,m=new Map;for(let k of e||[]){if(k.type!=="tool.called"||k.source!=="transcript")continue;let h=String(k.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(h))for(let v of h.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let N=v[0].split("/").pop().toLowerCase();m.has(N)||m.set(N,[]),m.get(N).push(k.payload?.ts??k.ts)}}let g=3*6e4,y=20*6e4,x=(k,h)=>!!(k?.name&&m.get(String(k.name).toLowerCase()))?.some(N=>N>=h-g&&N<=h+y);for(let k of e||[])if(k.type==="turn.retracted"){r.add(`${k.boxId}|${k.payload?.saidTs}`);let h=Fe(k.payload?.text);h&&(o.has(k.boxId)||o.set(k.boxId,[]),o.get(k.boxId).push(h))}else if(k.type==="turn.user"&&k.source==="orchestrator"){let h=Fe(k.payload?.text);h&&(s.has(k.boxId)||s.set(k.boxId,new Set),s.get(k.boxId).add(h))}else if(k.type==="job.stalled"&&k.payload?.id)i.set(k.payload.id,{ts:fe(k),quietMs:Number(k.payload.quietMs)||null});else if(k.type==="job.started"&&k.payload?.id)a.add(k.payload.id),(k.payload.kind||"agent")==="agent"&&k.payload.name&&l.add(k.payload.name);else if(k.type==="turn.user"&&k.payload?.note?.kind==="task"){let h=k.payload.note,v={status:h.status||null,summary:h.summary||null,resultHead:h.resultHead??null,ts:fe(k)};h.toolUseId&&c.set(h.toolUseId,v);let N=String(h.summary||"").match(w);N&&u.set(N[1],v)}let b=new Map,O=new Map,I=null,C=new Map,U=new Map,H=new Map,_=new Map,$=new Map,L=new Map,V=new Map,S=new Map,E=new Map,P=new Map,W=new Map,G=new Map,ae=new Map,we=new Map,Re=new Map,Ae=[],Y=k=>Ae.push(k),ye=k=>{if(!Ae.length)return;let h=fe(k);for(let v of Ae){if(v.status!=="open"||v.box&&v.box!==k.boxId||(v.ts??0)>h)continue;let N=t.indexOf(v);N>=0&&t.splice(N,1),v.ts=h,t.push(v)}},J=new Map,z=new Map,se=new Map,ve=new Map,Ne=new Map,R=new Map,D=new Map,de=new Map,Le=()=>{for(let k of de.values())k.questions.length&&t.push(k);de.clear()},Ce=null,Ht=new Map,St=6e4,Gn=new Map,xn=(k,h)=>{let v=o.get(k);if(!v?.length)return!1;let N=Fe(h),ne=s.get(k);return v.some(ge=>{if(!N.startsWith(ge))return!1;let Me=Fe(N.slice(ge.length));return!!Me&&!!ne?.has(Me)})};for(let k of e||[]){let h=k.payload||{};switch(k.type){case"turn.user":{if(k.source==="hook"||(Ae.length=0,!String(h.text||"").trim()&&!h.images?.length&&!h.attachments?.length))break;{let v=L0(h.text);if(v){if(v.kind==="shell-input"){let N={id:k.id,kind:"shell",command:v.command,stdout:null,stderr:null,done:!1,ts:fe(k),box:k.boxId,agent:k.provider};t.push(N),Ht.set(k.boxId,N)}else{let N=Ht.get(k.boxId);N?(N.stdout=v.stdout||null,N.stderr=v.stderr||null,N.done=!0,Ht.delete(k.boxId)):t.push({id:k.id,kind:"shell",command:null,stdout:v.stdout||null,stderr:v.stderr||null,done:!0,ts:fe(k),box:k.boxId,agent:k.provider})}break}}{let v=h.note||Ii(h.text);if(v){if(v.kind==="task"){if(v.toolUseId&&a.has(v.toolUseId))break;let N=String(v.summary||"").match(w);if(!v.toolUseId&&N&&l.has(N[1]))break}if(v.kind==="command"&&B0(v.command))break;if(v.kind==="resume-summary"){t.push({id:k.id,kind:"resume-summary",title:v.title||"Context resumed from summary",bullets:v.bullets||[],sections:v.sections||[],rawChars:v.rawChars??null,ts:fe(k),box:k.boxId,agent:k.provider});break}v.kind!=="suppress"&&t.push({id:k.id,kind:"event",type:U0(v),name:v.name??null,command:v.command??null,summary:v.summary??null,status:v.status??null,ts:fe(k),box:k.boxId,agent:k.provider});break}}if(r.has(`${k.boxId}|${fe(k)}`)||k.source==="transcript"&&xn(k.boxId,h.text))break;if(h.kind==="merge-notify"||h.kind==="ship-notify"){t.push({id:k.id,kind:"event",type:h.kind==="ship-notify"?"ship-notified":"merge-notified",text:h.text,ts:fe(k),box:k.boxId,agent:k.provider});break}if(h.kind==="mock-picked"||h.kind==="ci-fix"||h.kind==="reconcile"||h.kind==="pr-go"||h.kind==="push-go"||h.kind==="spin-up-view"||h.kind==="prompt-answer"||h.kind==="followup-go"){h.kind==="prompt-answer"&&(Ce=null);break}for(let v of C.values())v.status="stale";C.clear();for(let v of H.values())v.status="stale";H.clear();for(let v of ae.values())v.status="stale";ae.clear(),Ce&&Ce.box===k.boxId&&(t.push(TD(Ce)),Ce=null),t.push({id:k.id,kind:"message",role:"user",text:h.text,ts:fe(k),box:k.boxId,agent:k.provider,boxRole:h.boxRole,...k.actor==="orchestrator"?{orchestration:h.kind||!0}:{},...h.sourceId?{sourceId:h.sourceId}:{},...h.attachments?.length?{attachments:h.attachments}:{},...h.images?.length?{images:h.images}:{}});break}case"peer.message":{let v=h.from||{};t.push({id:k.id,kind:"event",type:"peer-message",text:h.text,from:v.trackName||v.boxId||v.name||null,fromTrackId:v.trackId||null,ts:fe(k),box:k.boxId,agent:k.provider});break}case"turn.agent":{if(h.model==="<synthetic>"&&/^No response requested\.$/.test(String(h.text||"").trim()))break;let v=Yk(h,{codexFailedText:_o});if(v){t.push({id:k.id,kind:"event",type:"provider-error",cls:v.cls,status:v.status??void 0,text:v.text,provider:k.provider,legacy:!0,at:fe(k),ts:fe(k),box:k.boxId,agent:k.provider});break}Le();let N=(h.images||[]).filter(Ge=>!x(Ge,fe(k)));if(!String(h.text||"").trim()&&!N.length)break;if(k.provider==="cursor"){let Ge=`${k.boxId}|${h.text}`;if(n.has(Ge))break;n.add(Ge)}(!Ce||Ce.box===k.boxId)&&(Ce=null);let ne=k.provider==="codex"?(h.tools||[]).filter(Ge=>!_f.has(Ge)&&!mi.has(Ge)):h.tools||[],ge=h.text,Me=null,tt=Vf(String(h.text||""));tt&&(ge=tt.text,Me={questions:tt.questions}),t.push({id:k.id,kind:"message",role:"assistant",text:ge,ts:fe(k),box:k.boxId,agent:k.provider,boxRole:h.boxRole,...Me?{ask:Me}:{},...ne.length?{tools:ne}:{},...h.model?{model:h.model}:{},...h.sourceId?{sourceId:h.sourceId}:{},...N.length?{images:N}:{}}),ye(k),Me&&(Ce={id:k.id,groupId:Jf(k.provider,h.sourceId||k.id,Me.questions),provider:k.provider,box:k.boxId,questions:Me.questions,ts:fe(k)});break}case"job.started":{if(!h.id)break;let v=fe(k),N=c.get(h.id);if(!N&&(h.kind||"agent")==="agent"&&h.name){let Wt=u.get(h.name);Wt&&Wt.ts>=v&&(N=Wt)}let ne=N?null:i.get(h.id)||null,ge={jobId:h.id,jobKind:h.kind||"agent",name:h.name||null,detail:h.detail||null,status:N?N.status==="killed"?"stopped":N.status&&N.status!=="completed"?"failed":"done":ne?"stalled":"running",startedTs:v,finishedTs:N?.ts??ne?.ts??null,quietMs:ne?.quietMs??null,summary:N?.summary??null,resultHead:N?.resultHead??null},Me=Gn.get(k.boxId),tt=Me?.jobs[Me.jobs.length-1]?.startedTs;if(Me&&tt!=null&&v-tt<=St)Me.jobs.push(ge);else{let Wt={id:k.id,kind:"job-dock",dockId:h.id,ts:v,box:k.boxId,agent:k.provider,jobs:[ge]};Gn.set(k.boxId,Wt),t.push(Wt)}break}case"handoff.done":t.push(lt(k,"lead-handoff"));break;case"subtask.delegated":t.push({...lt(k,"subtask-delegated"),to:k.boxId,toAgent:k.provider});break;case"subtask.merged":t.push(lt(k,"subtask-merged"));break;case"pr.state.changed":{if(!h.change)break;if(h.change==="opened"){for(let N of C.values())N.status="stale";C.clear();for(let N of H.values())N.status="stale";H.clear()}let v=lt(k,`pr-${h.change}`);if(v.box=k.boxId??null,G0.has(h.change)&&h.number!=null){let N=z0(b,O,h);if(b.size>=2){for(let ge of O.values())for(let Me of ge)Me.grouped=!0;v.groupPrs=[...b.values()];let ne=[v];for(let ge of b.keys())O.set(ge,ne)}else{let ne=O.get(N)??[];ne.push(v),O.set(N,ne)}}else if(h.change==="merged"||h.change==="closed"||h.change==="lost"){let N=Zf(h),ne=I&&!I.complete||b.size>=2;if(b.has(N))b.delete(N),O.delete(N);else if(h.number!=null)for(let ge of[...b.keys()])ge.endsWith(`#${h.number}`)&&(b.delete(ge),O.delete(ge));if(ne&&h.number!=null){(!I||I.complete)&&(I={id:k.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:fe(k),ts:fe(k),box:k.boxId,agent:k.provider},t.push(I)),I.prs.push({number:h.number,url:h.url??null,title:h.title??null,repo:h.repo??null,branch:h.branch??null,change:h.change,ts:fe(k)}),I.remaining=[...b.values()],I.complete=b.size===0;break}}t.push(v);break}case"pr.offered":{if(!h.offerId)break;for(let N of C.values())N.status="stale";C.clear();for(let N of H.values())N.status="stale";H.clear();let v={id:k.id,kind:"pr-offer",offerId:h.offerId,excerpt:h.excerpt||null,branch:h.branch||null,base:h.base||null,offered:Array.isArray(h.offered)&&h.offered.length?h.offered:null,toPr:h.toPr&&typeof h.toPr=="object"?{number:h.toPr.number??null}:null,available:Array.isArray(h.available)?h.available:null,defaults:Array.isArray(h.defaults)?h.defaults:null,prState:h.prState||null,openPr:h.openPr&&typeof h.openPr=="object"?h.openPr:null,repos:Array.isArray(h.repos)&&h.repos.length?h.repos:null,status:"open",source:k.source==="cli"||h.via==="cli"?"cli":"transcript",ts:fe(k),box:k.boxId,agent:k.provider};C.set(h.offerId,v),U.set(h.offerId,v),t.push(v),v.source==="cli"&&Y(v);break}case"pr.offer.answered":{let v=U.get(h.offerId);v&&(v.status=h.action||"dismiss",v.actions=Array.isArray(h.actions)?h.actions:null,v.notify=h.notify===!0,h.existingPr&&typeof h.existingPr=="object"&&(v.existingPr={number:h.existingPr.number??null}),C.delete(h.offerId));break}case"pr.exists.offered":{if(!h.offerId)break;for(let N of H.values())N.status="stale";H.clear();let v={id:k.id,kind:"pr-exists-offer",offerId:h.offerId,srcOfferId:h.srcOfferId??null,branch:h.branch||null,base:h.base||null,pr:h.pr&&typeof h.pr=="object"?{number:h.pr.number??null,url:h.pr.url??null,title:h.pr.title??null}:null,actions:Array.isArray(h.actions)&&h.actions.length?h.actions:null,notify:h.notify===!0,status:"open",ts:fe(k),box:k.boxId,agent:k.provider};H.set(h.offerId,v),_.set(h.offerId,v),t.push(v);break}case"pr.exists.answered":{let v=_.get(h.offerId);v&&(v.status=h.choice||"dismiss",H.delete(h.offerId));break}case"box.state.changed":{let v=h.change==="model"?"model-change":h.change;if(!v)break;let N=lt(k,v);if(v==="model-change"&&(N.to=h.model),v==="node-update"&&N.latest){let ne=t.findIndex(ge=>ge.kind==="event"&&ge.type==="node-update"&&ge.latest===N.latest);if(ne>=0){let ge=t[ne];t[ne]={...N,ts:ge.ts,at:ge.at,firstAt:ge.firstAt??ge.ts,updatedAt:N.ts};break}}t.push(N);break}case"track.transferred":case"track.recovered":t.push(lt(k,"track-moved"));break;case"view.state.changed":{if(h.change==="deleted"){f(`view:${h.viewId}`);break}if(h.change!=="created"||h.restarted)break;p(`view:${h.viewId}`,{id:k.id,kind:"view-card",viewId:h.viewId,name:h.name,slug:h.slug,port:h.port,origin:h.origin,ts:fe(k),box:k.boxId,agent:k.provider});break}case"view.spinup.failed":{t.push({id:k.id,kind:"view-spinup-failed",name:h.name||null,reason:h.reason||"no-view",ts:fe(k),box:k.boxId,agent:k.provider});break}case"mock.state.changed":{if(h.change==="picked"){t.push({id:k.id,kind:"mock-picked",mockId:h.mockId,name:h.name,group:h.group??null,version:h.version??null,siblings:h.siblings??[],ts:fe(k),box:k.boxId,agent:k.provider});break}if(h.change==="deleted"){f(`mock:${h.mockId}`);break}if(h.change!=="created")break;p(`mock:${h.mockId}`,{id:k.id,kind:"mock-card",mockId:h.mockId,name:h.name,group:h.group??null,ts:fe(k),box:k.boxId,agent:k.provider});break}case"flow.state.changed":{if(h.change==="deleted"){f(`flow:${h.flowId}`);break}if(h.change!=="created")break;p(`flow:${h.flowId}`,{id:k.id,kind:"flow-card",flowId:h.flowId,name:h.name,stepCount:h.stepCount??null,mockIds:h.mockIds??[],ts:fe(k),box:k.boxId,agent:k.provider});break}case"runbook.state.changed":{if(h.change==="deleted"){f(`runbook:${h.runbookId}`);break}if(h.change!=="created")break;p(`runbook:${h.runbookId}`,{id:k.id,kind:"runbook-card",runbookId:h.runbookId,name:h.name,ts:fe(k),box:k.boxId,agent:k.provider});break}case"ticket.linked":{t.push({id:k.id,kind:"ticket-card",provider:h.provider||"linear",key:h.key,url:h.url,title:h.title??null,linkSource:h.linkSource??null,ts:fe(k),box:k.boxId,agent:k.provider});break}case"box.fullscreen.detected":{if(!h.offerId)break;for(let N of V.values())N.box===(h.box||k.boxId)&&(N.status="stale",V.delete(N.offerId));let v={id:k.id,kind:"fullscreen-offer",offerId:h.offerId,status:"open",ts:fe(k),box:h.box||k.boxId,agent:h.agent||k.provider};V.set(h.offerId,v),S.set(h.offerId,v),t.push(v);break}case"box.fullscreen.answered":{let v=S.get(h.offerId);v&&(v.status=h.action==="restarted"?"restarted":h.action==="cleared"?"cleared":"dismiss",V.delete(h.offerId));break}case"ticket.move.offered":{if(!h.offerId)break;for(let N of $.values())N.key===h.key&&(N.status="stale",$.delete(N.offerId));let v={id:k.id,kind:"ticket-offer",offerId:h.offerId,provider:h.provider||"linear",key:h.key,url:h.url??null,phase:h.phase??null,from:h.from??null,to:h.to?.name??null,prNumber:h.prNumber??null,status:"open",ts:fe(k),box:k.boxId,agent:k.provider};$.set(h.offerId,v),L.set(h.offerId,v),t.push(v);break}case"ticket.move.answered":{let v=L.get(h.offerId);v&&(v.status=h.action==="moved"?"moved":"dismiss",$.delete(h.offerId));break}case"ticket.state.changed":{for(let v of $.values())v.key===h.key&&v.to===h.to&&(v.status="stale",$.delete(v.offerId));if(h.mode==="offer")break;t.push(lt(k,"ticket-state"));break}case"ticket.commented":{t.push({id:k.id,kind:"ticket-comment",key:h.key,url:h.url??null,excerpt:h.excerpt??null,ts:fe(k),box:k.boxId,agent:k.provider});break}case"ticket.flow.changed":t.push(lt(k,"ticket-flow"));break;case"ticket.create.offered":{if(!h.proposalId)break;for(let N of E.values())N.status="stale";E.clear();let v={id:k.id,kind:"ticket-create-offer",proposalId:h.proposalId,provider:h.provider||"linear",epic:h.epic??null,issues:Array.isArray(h.issues)?h.issues:[],team:h.team??null,needsTeam:!!h.needsTeam,linkCurrentTrack:!!h.linkCurrentTrack,status:"open",ts:fe(k),box:k.boxId,agent:k.provider};E.set(h.proposalId,v),P.set(h.proposalId,v),t.push(v),Y(v);break}case"ticket.create.answered":{let v=P.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",v.createdCount=h.createdCount??null,v.failedCount=h.failedCount??null,E.delete(h.proposalId));break}case"loop.create.offered":{if(!h.proposalId)break;for(let N of W.values())N.status="stale";W.clear();let v={id:k.id,kind:"loop-create-offer",proposalId:h.proposalId,name:h.name??"",schedule:h.schedule??"",prompt:h.prompt??"",expectation:h.expectation??null,notify:h.notify??"off",assignment:h.assignment??{provider:"claude"},repo:h.repo??null,nodeId:h.nodeId??null,nodeName:h.nodeName??null,status:"open",ts:fe(k),box:k.boxId,agent:k.provider};W.set(h.proposalId,v),G.set(h.proposalId,v),t.push(v),Y(v);break}case"loop.create.answered":{let v=G.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",W.delete(h.proposalId));break}case"followup.armed":{if(!h.armId)break;let v=h.replaces?Re.get(h.replaces):null;v&&v.status==="armed"&&(v.status="replaced");let N={id:k.id,kind:"followup-armed",armId:h.armId,trigger:h.trigger??"now",label:h.label??"",prompt:h.prompt??"",why:h.why??null,status:"armed",ts:fe(k),box:k.boxId,agent:k.provider};Re.set(h.armId,N),N.trigger!=="now"&&t.push(N);break}case"followup.armed.cancelled":{let v=Re.get(h.armId);v&&v.status==="armed"&&(v.status="cancelled");break}case"followup.offered":{if(!h.offerId)break;for(let ne of ae.values())ne.trigger===h.trigger&&(ne.status="stale",ae.delete(ne.offerId));let v=Array.isArray(h.rows)?h.rows:[];for(let ne of v){let ge=ne.armId?Re.get(ne.armId):null;ge&&ge.status==="armed"&&(ge.status="offered")}let N={id:k.id,kind:"followup-offer",offerId:h.offerId,trigger:h.trigger??"now",repo:h.repo??null,context:h.context&&typeof h.context=="object"?h.context:{},rows:v.map(ne=>({followupId:ne.followupId??null,armId:ne.armId??null,label:ne.label??"",prompt:ne.prompt??null,promptPreview:ne.promptPreview??null,promptHash:ne.promptHash??null,origin:ne.origin??"operator",why:ne.why??null})),status:"open",answer:null,ts:fe(k),box:k.boxId,agent:k.provider};ae.set(h.offerId,N),we.set(h.offerId,N),t.push(N),N.trigger==="now"&&Y(N);break}case"followup.answered":{let v=we.get(h.offerId);v&&(v.status=h.action==="sent"?"sent":h.action==="removed"?"removed":"dismiss",v.answer={followupId:h.followupId??null,armId:h.armId??null,label:h.label??null,promoted:h.promoted??null,revived:h.revived===!0},ae.delete(h.offerId));break}case"followup.create.offered":{if(!h.proposalId)break;for(let N of J.values())N.status="stale";J.clear();let v={id:k.id,kind:"followup-create-offer",proposalId:h.proposalId,label:h.label??"",prompt:h.prompt??"",trigger:h.trigger??"pr.merged",repo:h.repo??null,why:h.why??null,status:"open",created:null,ts:fe(k),box:k.boxId,agent:k.provider};J.set(h.proposalId,v),z.set(h.proposalId,v),t.push(v),Y(v);break}case"followup.create.answered":{let v=z.get(h.proposalId);v&&(v.status=h.action==="created"?"created":"dismiss",J.delete(h.proposalId));break}case"followup.created":{let v=h.proposalId?z.get(h.proposalId):null;v&&(v.created={followupId:h.followupId??null});break}case"loop.created":{let v=h.proposalId?G.get(h.proposalId):null;v&&(v.created={loopId:h.loopId??null,nextFireAt:Number.isFinite(Number(h.nextFireAt))?Number(h.nextFireAt):null}),t.push(lt(k,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!h.proposalId||!h.loopId)break;for(let ne of se.values())ne.loopId===h.loopId&&(ne.status="stale",ne.staleReason="superseded",se.delete(ne.proposalId));let v=k.type==="loop.update.offered",N={id:k.id,kind:v?"loop-update-offer":"loop-delete-offer",proposalId:h.proposalId,loopId:String(h.loopId),name:h.name??h.base?.name??"",base:h.base??null,...v?{patch:h.patch??{},changed:Array.isArray(h.changed)?h.changed:Object.keys(h.patch||{})}:{reason:h.reason??""},selfEdit:!!h.selfEdit,status:"open",staleReason:null,ts:fe(k),box:k.boxId,agent:k.provider};se.set(h.proposalId,N),ve.set(h.proposalId,N),t.push(N),Y(N);break}case"loop.update.answered":{let v=ve.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="applied"?"applied":"dismiss",se.delete(h.proposalId));break}case"loop.delete.answered":{let v=ve.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="delete"?"deleted":h.action==="pause"?"paused":"keep",se.delete(h.proposalId));break}case"loop.updated":{let v=h.proposalId?ve.get(h.proposalId):null;v&&(v.applied={changed:Array.isArray(h.changed)?h.changed:[],nextFireAt:Number.isFinite(Number(h.nextFireAt))?Number(h.nextFireAt):null}),t.push(lt(k,"loop-updated"));break}case"loop.deleted":t.push(lt(k,"loop-deleted"));break;case"loop.paused":t.push(lt(k,"loop-paused"));break;case"planning.change.offered":{if(!h.proposalId||!Array.isArray(h.ops)||!h.ops.length)break;for(let N of Ne.values())N.status="stale",N.staleReason="superseded",Ne.delete(N.proposalId);let v={id:k.id,kind:"planning-offer",proposalId:h.proposalId,why:h.why??"",ops:h.ops,base:h.base??{},resolved:h.resolved??{},snapped:!!h.snapped,createsMeRow:!!h.createsMeRow,status:"open",staleReason:null,applied:null,ts:fe(k),box:k.boxId,agent:k.provider};Ne.set(h.proposalId,v),R.set(h.proposalId,v),t.push(v),Y(v);break}case"planning.change.answered":{let v=R.get(h.proposalId);v&&(h.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=h.action==="applied"?"applied":"dismiss",Ne.delete(h.proposalId));break}case"planning.changed":{let v=h.proposalId?R.get(h.proposalId):null;v&&(v.applied={results:Array.isArray(h.results)?h.results:[]}),t.push(lt(k,"planning-changed"));break}case"rework.cause.offered":{if(!h.sha||D.has(h.sha))break;let v={id:k.id,kind:"rework-cause-offer",sha:h.sha,subject:h.subject??"",linesReworked:Number(h.linesReworked)||0,origins:Array.isArray(h.origins)?h.origins:[],heuristic:h.heuristic??null,intent:h.intent??null,shas:Array.isArray(h.shas)?h.shas:null,pr:h.pr??null,retracts:0,status:"open",cause:null,ts:fe(k),box:k.boxId,agent:k.provider};D.set(h.sha,v),t.push(v);break}case"rework.cause.answered":{let v=h.sha?D.get(h.sha):null;v&&(v.status="answered",v.cause=h.cause??null);break}case"rework.cause.retracted":{let v=h.sha?D.get(h.sha):null;v&&(v.status="open",v.cause=null,v.retracts=(v.retracts??0)+1);break}case"ticket.created":{let v={items:Array.isArray(h.items)?h.items:[],failed:Array.isArray(h.failed)?h.failed:[],team:h.team??null},N=h.proposalId?P.get(h.proposalId):null;if(N){N.created=v;break}t.push({id:k.id,kind:"ticket-created",...v,ts:fe(k),box:k.boxId,agent:k.provider});break}case"error":{if(!h.kind)break;t.push(lt(k,h.kind));break}case"provider.error":t.push({...lt(k,"provider-error"),provider:k.provider,box:k.boxId,agent:k.provider});break;case"usage.cap.hit":t.push(lt(k,"usage-cap-hit"));break;case"usage.cap.warning":t.push(lt(k,"usage-cap-warning"));break;case"provider.connected":{t.push({id:k.id,kind:"event",type:"provider-connected",provider:h.provider||k.provider,ts:fe(k),at:fe(k),box:k.boxId,agent:k.provider});break}case"prompt.answered":{if(Ce=null,h.control||!h.question)break;let v=h.groupId||h.promptId;if(!v)break;let N=de.get(v);N||(N={id:k.id,kind:"prompt",groupId:v,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:h.questionTotal??1,questions:[],ts:fe(k)},de.set(v,N));let ne=h.questionIndex??0,ge={index:ne,header:h.header||"",question:h.question,multiSelect:!!h.multiSelect,chosen:Array.isArray(h.chosen)?h.chosen:[]},Me=N.questions.findIndex(Ge=>Ge.index===ne&&Fe(Ge.question)===Fe(ge.question));Me>=0?N.questions[Me]=ge:N.questions.push(ge),N.questions.sort((Ge,Wt)=>Ge.index-Wt.index),N.questionTotal=Math.max(N.questionTotal,h.questionTotal??1),N.questions.length>=N.questionTotal&&(t.push(N),de.delete(v));break}case"prompt.dismissed":{Ce=null;let v=h.groupId||h.promptId;if(!v||!h.question)break;let ne=de.get(v)||{id:k.id,kind:"prompt",groupId:v,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:h.questionTotal??1,questions:[],ts:fe(k)},ge=h.questionIndex??0;ne.questions.some(Me=>Me.index===ge&&Fe(Me.question)===Fe(h.question))||(ne.questions.push({index:ge,header:h.header||"",question:h.question,multiSelect:!!h.multiSelect,chosen:[]}),ne.questions.sort((Me,tt)=>Me.index-tt.index)),ne.answeredVia="chat",t.push(ne),de.delete(v);break}default:break}}let yt=d.size?t.filter(k=>!k.retired):t;return ED(yt.sort((k,h)=>(k.ts??0)-(h.ts??0)))}function ED(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<=AD){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:_D(s),ts:s.ts??o.ts,n:s.n,box:o.boxId,agent:o.provider,boxRole:s.boxRole})}if(!n.length)return[];let r=(t??_n(e)).filter(o=>o.kind==="message");return Hk(n,r)}function _D(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==Rs(e.command)?t:Mr(e.command,e.description||"")}function lt(e,t){let{ts:n,change:r,...o}=e.payload||{};return{id:e.id,kind:"event",type:t,...o,at:fe(e),ts:fe(e)}}function V0(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)+ID,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&$D.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function J0(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!OD.has(r.type)||!r.box)continue;let o=(r.ts??0)+RD,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||!(a?.kind==="message"&&a.role==="assistant"&&a.box===r.box||a?.kind==="command-batch"&&a.anchorBox===r.box))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function ou(e){return(e||[]).filter(t=>MD.has(t?.kind)&&t.status==="open")}function Y0(e){let t=new Map,n=new Map;for(let r of e||[]){if(r.type!=="pr.state.changed")continue;let o=r.payload||{};if(G0.has(o.change)&&o.number!=null)z0(t,n,o);else if(o.change==="merged"||o.change==="closed"||o.change==="lost"){let s=Zf(o);if(t.has(s))t.delete(s);else if(o.number!=null)for(let a of[...t.keys()])a.endsWith(`#${o.number}`)&&t.delete(a)}}return[...t.values()]}var fe,G0,Zf,AD,ID,$D,RD,OD,MD,su=K(()=>{Os();Io();Kl();vi();ru();Xf();fe=e=>e.payload?.ts??e.ts;G0=new Set(["opened","ci-fixed","reconciled","pushed"]),Zf=e=>`${e.repo??""}#${e.number}`;AD=2*6e4;ID=12e4,$D=new Set(["archived","unarchived","opened"]);RD=2500,OD=new Set(["pr-opened","pr-merged","pr-auto-armed"]);MD=new Set(["pr-offer","pr-exists-offer","ticket-offer","ticket-create-offer","loop-create-offer","loop-update-offer","loop-delete-offer","planning-offer","fullscreen-offer","followup-create-offer"])});function BD(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 LD(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 FD(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<PD&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<DD&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function ex(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=BD(e),s=LD(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=_n(e??[]).filter(p=>p?.kind==="message"&&typeof p.text=="string"&&p.text.trim()).slice(-CD);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(Q0[r]??Q0.failover),l.push(""),o.lastPush?.sha){let p=Z0(n,o.lastPush.ts),f=p?` (~${p} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${f}`+(o.lastPush.wip?" \u2014 a bostrat WIP snapshot (full working tree incl. uncommitted edits at push time).":"."))}else r==="in-place"?l.push("**Code state:** no push recorded \u2014 the working tree in this workspace is the only copy; commit early."):l.push("**Code state:** no push was ever recorded for this Track \u2014 work since the branch's last known state stayed on the offline node.");if(l.push(""),a){let p=Z0(n,i);l.push(`## Last real checkpoint (written by the previous agent${p?`, ~${p} min before this reconstruction`:""})`),l.push(""),l.push(a.trim()),l.push("")}let u=FD(e??[],i);if((u.files.length||u.heads.length)&&(l.push(`## Work since ${a?"that checkpoint":"the start of the log"} (from the event log)`),l.push(""),u.files.length&&l.push(`Files touched (most recent first): ${u.files.map(p=>`\`${p}\``).join(", ")}`),u.heads.length&&(u.files.length&&l.push(""),l.push(`Commands run (most recent first): ${u.heads.map(p=>`\`${p}\``).join(" \xB7 ")}`)),l.push("")),c.length){l.push(`## Recent conversation (last ${c.length} message${c.length===1?"":"s"})`),l.push("");for(let p of c)l.push(`**${p.role==="user"?"operator":"agent"}:** ${jD(p.text,ND)}`),l.push("")}l.push("---"),l.push("Resume: continue the objective above from the verified repository state; ask the operator before redoing anything the log says was already done.");let d=l.join(`
154
- `);return d.length<=X0?d:`${d.slice(0,X0)}
155
-
156
- [\u2026 brief truncated]`}var CD,ND,X0,PD,DD,jD,Z0,Q0,tx=K(()=>{su();CD=12,ND=2e3,X0=48e3,PD=30,DD=10;jD=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},Z0=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;Q0={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 UD from"node:fs";import Nr from"node:fs/promises";import Pr from"node:path";function lx(e){let t=vo(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=nx?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,nx).toString("utf8").replace(/�+$/,"")}
157
-
158
- [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function YD(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(ox.test(s)){if(r.length>=hx)continue;let a=JD(s.replace(ox,"").replace(/[.;,:]+$/,""),wx,zD);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>rx&&(o=`${o.slice(0,rx-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function gx(e,t,{timeoutMs:n=9e4}={}){let r=Pr.join(t,KD),o=Pr.join(r,GD);await Nr.mkdir(r,{recursive:!0});let s=await au(o),a=await ke(e);if(!a)throw new Error(`session "${e}" not found`);return await iu(e,a,VD(o)),await Tx(o,s,n),YD(await Nr.readFile(o,"utf8"))}function yx(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===dx||n===mx;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(ux)||n===HD||r.startsWith(px)||r.startsWith(fx)}function bx(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-XD;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 kx(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 xx(e,{windows:t=[]}={}){if(yx(e.role,e.text))return!0;if(e.role!=="assistant"||!e.ts)return!1;for(let n of t)if(e.box===n.box&&e.ts>=n.from&&e.ts<=n.to)return!0;return!1}function cu(e){return em.get(e)||null}async function vx(e){let t=em.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await ke(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);let r={name:e,step:"summarize",startedAt:Date.now(),finishedAt:null,error:null,file:Pr.join(n.cwd,ix,cx)};return em.set(e,r),e1(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function e1(e,t){e.step="summarize",await Sx(e.name,t),e.step="clear";let n=await ke(e.name);await iu(e.name,n,"/clear"),await rm(ZD),e.step="resume",await iu(e.name,n,qD),e.step="done",e.finishedAt=Date.now()}async function Sx(e,t,{timeoutMs:n=QD}={}){let r=Pr.join(t,ix),o=Pr.join(r,cx);await Nr.mkdir(r,{recursive:!0});let s=await au(o),a=await ke(e);await le({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await iu(e,a,WD(o)),await Tx(o,s,n),await le({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await au(o)});let i=await $0(t,o,{exclude:u=>yx(u.role,u.text)});await le({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(c){await M({id:c,cwd:t},{type:"memory.seed",actor:"orchestrator",payload:{...i,tokensEst:i.chars?Math.round(i.chars/4):0,ts:Date.now()}}).catch(()=>{});try{let u=await Nr.readFile(o,"utf8");await M({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...lx(u),ts:Date.now()}})}catch{}}await ef(t);let l=await t1(r,o);return c&&await ck(c,l||o,{box:e,agent:a?.agent??null}),o}async function tm(e,{timeoutMs:t}={}){let n=await ke(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);return Sx(e,n.cwd,t?{timeoutMs:t}:void 0)}async function nm(e,t,{trackName:n="this Track"}={}){let r=await q({id:e,cwd:t}),o=ex(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=Pr.join(t,sx);return await Nr.mkdir(Pr.dirname(s),{recursive:!0}),await Nr.writeFile(s,o,"utf8"),await M({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...lx(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),sx}async function au(e){try{return(await Nr.stat(e)).mtimeMs}catch{return 0}}async function Tx(e,t,n){let r=Date.now()+n;for(;;){if(await au(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await rm(2e3)}}async function t1(e,t){try{if(!UD.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=Pr.join(e,`${n}.md`);return await Nr.copyFile(t,r),r}catch{return null}}function rm(e){return new Promise(t=>setTimeout(t,e))}function ax(e){return e==="claude"?process.env.BOSTRAT_AGENT_CMD||"claude":e==="cursor"?process.env.BOSTRAT_CURSOR_CMD||"cursor-agent":e==="codex"?process.env.BOSTRAT_CODEX_CMD||"codex":""}async function iu(e,t,n){if(t){let o=ax(t.agent);await Cr({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await ke(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await qe(e,["Escape"],{kind:"drive-wipe"}),await rm(150),await Es(e,Hl,{kind:"drive-wipe"}),await ot(e,n,{kind:"orchestration-drive",...En(r.agent,n)}),await Ti({sessionName:e,agent:r.agent,agentCmd:ax(r.agent),text:n,flow:"orchestration-drive"})}var ix,cx,nx,ux,dx,px,HD,WD,qD,fx,mx,KD,GD,rx,hx,wx,zD,VD,ox,JD,XD,ZD,QD,em,sx,om=K(()=>{ct();bi();Tn();ki();Hf();R0();Xa();pe();Cl();tx();ix=".bostrat/handoff",cx="latest.md",nx=32*1024;ux="Checkpoint: write a work-in-progress handoff",dx="HANDOFF WRITTEN",px="Resume from .bostrat/handoff/latest.md",HD="/clear",WD=e=>`${ux} 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 ${dx} and take no further action.`,qD=`${px}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,fx="Beat: write a",mx="BEAT WRITTEN",KD=".bostrat/arc",GD="beat.txt",rx=200,hx=4,wx=5,zD=36,VD=e=>`${fx} 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 ${hx} further lines, each starting with "- " and naming ONE piece in at most ${wx} 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 ${mx} and take no further action.`,ox=/^(?:[-–—*•·]|\d+[.)])\s+/,JD=(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};XD=6e5;ZD=3500,QD=3e5,em=new Map;sx=".bostrat/handoff/status-latest.md"});function Br(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!lu.test(String(e)))throw new Error(`pricing.js: ${n} window ${t} must be YYYY-MM-DD, got ${JSON.stringify(e)}`);let r=Date.parse(`${e}T${t==="from"?"00:00:00.000":"23:59:59.999"}Z`);if(!Number.isFinite(r))throw new Error(`pricing.js: ${n} window ${t} is not a real date: ${e}`);return r}function _x(e){let t={};for(let[n,r]of Object.entries(e)){if(!Array.isArray(r)||r.length===0)throw new Error(`pricing.js: ${n} must be a non-empty array of rate windows`);t[n]=r.map(o=>({...o,fromMs:Br(o.from,"from",n),toMs:Br(o.to,"to",n)}))}return t}function am(e){if(e==null)return Date.now();if(typeof e=="number")return Number.isFinite(e)?e:null;if(e instanceof Date){let n=e.getTime();return Number.isFinite(n)?n:null}let t=Date.parse(String(e));return Number.isFinite(t)?t:null}function r1(e){if(!e)return null;let t=String(e).trim();return Dr[t]?t:Ax[t]?Ax[t]:Object.keys(Dr).find(r=>t.startsWith(r))||null}function o1(e){if(!e||e===Dr)return n1;let t=Ex.get(e);return t||(t=_x(e),Ex.set(e,t)),t}function Ix(e,t,n={}){let{table:r,speed:o}=n,s=o1(r),a=r&&r!==Dr?s[e]?e:null:r1(e);if(!a)return null;let i=am(t);if(i===null)return null;let c=s[a].find(l=>i>=l.fromMs&&i<=l.toMs)||null;return c?o==null||o==="standard"?c:o==="fast"&&c.fast?{...c.fast,fromMs:c.fromMs,toMs:c.toMs,verifiedAt:c.verifiedAt,note:c.note,speed:"fast"}:null:null}function In(e,t={},n,r){let o=Ix(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 s1(e=Dr){let t=[];for(let[n,r]of Object.entries(e)){if(!Array.isArray(r)||r.length===0){t.push(`${n}: must be a non-empty array of windows`);continue}let o;try{o=r.map(a=>({fromMs:Br(a.from,"from",n),toMs:Br(a.to,"to",n)}))}catch(a){t.push(String(a.message));continue}let s=r.filter(a=>a.to==null);s.length!==1?t.push(`${n}: expected exactly 1 open-ended window (to: null), found ${s.length}`):r[r.length-1].to!=null&&t.push(`${n}: the open-ended window must be last`),r[0].from!=null&&t.push(`${n}: the first window must be open at the start (from: null)`);for(let a=0;a<o.length;a++){if(o[a].fromMs>o[a].toMs&&t.push(`${n}: window ${a} ends before it begins (${r[a].from} \u2192 ${r[a].to})`),a===0)continue;let i=o[a-1],c=o[a];c.fromMs<=i.toMs?t.push(`${n}: windows ${a-1} and ${a} overlap (${r[a-1].to} / ${r[a].from})`):c.fromMs-i.toMs>2&&t.push(`${n}: gap between windows ${a-1} and ${a} (${r[a-1].to} \u2192 ${r[a].from})`),r[a].from||t.push(`${n}: window ${a} must declare a from bound`)}for(let a of r){a.note||t.push(`${n}: every window needs a note recording what was verified and when`),lu.test(String(a.verifiedAt??""))||t.push(`${n}: every window needs a verifiedAt (YYYY-MM-DD) \u2014 the date its rates were checked against the vendor's published page`);for(let i of["input","output","cacheWrite","cacheRead"])(typeof a[i]!="number"||!Number.isFinite(a[i])||a[i]<0)&&t.push(`${n}: window ${i} must be a non-negative number, got ${JSON.stringify(a[i])}`),a.fast&&(typeof a.fast[i]!="number"||!Number.isFinite(a.fast[i])||a.fast[i]<0)&&t.push(`${n}: fast variant ${i} must be a non-negative number, got ${JSON.stringify(a.fast?.[i])}`)}}return t}function i1({now:e=Date.now(),table:t=Dr,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...a1,...n},a=[],i=am(e);if(i===null)return[`pricingFreshness: unparseable now ${JSON.stringify(e)}`];for(let[c,l]of Object.entries(t)){if(!Array.isArray(l))continue;let u;try{u=l.map(d=>({...d,fromMs:Br(d.from,"from",c),toMs:Br(d.to,"to",c),verifiedMs:lu.test(String(d.verifiedAt??""))?Date.parse(`${d.verifiedAt}T00:00:00.000Z`):NaN}))}catch(d){a.push(String(d.message));continue}for(let d of u){if(!Number.isFinite(d.verifiedMs)){a.push(`${c}: window ${d.from??"\u2026"} \u2192 ${d.to??"now"} has no verifiedAt`);continue}let p=i>=d.fromMs&&i<=d.toMs,f=d.fromMs>i&&d.fromMs-i<=o*sm;p&&i-d.verifiedMs>r*sm&&a.push(`${c}: current rate last verified ${d.verifiedAt} (>${r}d) \u2014 re-check the vendor page and bump verifiedAt`),f&&d.fromMs-d.verifiedMs>s*sm&&a.push(`${c}: scheduled rate change on ${d.from} was last verified ${d.verifiedAt} \u2014 confirm it is still happening (vendors cancel; sonnet-5 did) and bump verifiedAt`)}}return a}function Bs({now:e=Date.now(),table:t=Dr,...n}={}){let r=am(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=Br(l.from,"from",i),d=Br(l.to,"to",i);r>=u&&r<=d&&lu.test(String(l.verifiedAt??""))&&(!o||l.verifiedAt<o)&&(o=l.verifiedAt),u>r&&s.push({model:i,from:l.from,verifiedAt:l.verifiedAt??null})}s.sort((i,c)=>i.from<c.from?-1:1);let a=[...s1(t),...i1({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var Dr,Ax,lu,n1,Ex,$x,a1,sm,Qn=K(()=>{Dr={"claude-opus-5":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"GA rates; verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-opus-4-8":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-sonnet-5":[{from:null,to:null,input:2,output:10,cacheWrite:4,cacheRead:.2,verifiedAt:"2026-08-17",note:"$2/$10 is the standard price (intro pricing made permanent; the 2026-09-01 $3/$15 increase was cancelled) \u2014 verified 2026-08-17 against platform.claude.com/docs/en/about-claude/pricing."}],"claude-sonnet-4-6":[{from:null,to:null,input:3,output:15,cacheWrite:6,cacheRead:.3,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-haiku-4-5":[{from:null,to:null,input:1,output:5,cacheWrite:2,cacheRead:.1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-fable-5":[{from:null,to:null,input:10,output:50,cacheWrite:20,cacheRead:1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); 83% of fleet spend."}],"gpt-5.5":[{from:null,to:null,input:5,output:30,cacheWrite:5,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-03, re-verified 2026-08-17 (developers.openai.com pricing); no cache-write premium on 5.5-and-earlier."}],"gpt-5.6-sol":[{from:null,to:"2026-08-23",input:5,output:30,cacheWrite:6.25,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-18, re-verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL). Superseded 2026-08-24 by the vendor's promotional cut (window below)."},{from:"2026-08-24",to:null,input:4,output:20,cacheWrite:5,cacheRead:.4,verifiedAt:"2026-08-24",note:"promotional pricing verified 2026-08-24 (developers.openai.com pricing), 'at least through November 21, 2026'; cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-terra":[{from:null,to:"2026-08-16",input:2.5,output:15,cacheWrite:3.125,cacheRead:.25,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:2,output:12,cacheWrite:2.5,cacheRead:.2,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-luna":[{from:null,to:"2026-08-16",input:1,output:6,cacheWrite:1.25,cacheRead:.1,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:.2,output:1.2,cacheWrite:.25,cacheRead:.02,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}]},Ax={opus:"claude-opus-5",opusplan:"claude-opus-5",default:"claude-opus-5",sonnet:"claude-sonnet-5",haiku:"claude-haiku-4-5",fable:"claude-fable-5","gpt-5.6":"gpt-5.6-sol"},lu=/^\d{4}-\d{2}-\d{2}$/;n1=_x(Dr);Ex=new WeakMap;$x=(e,t,n)=>Ix(e,t,n)!==null;a1=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),sm=864e5});function c1(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function Ox(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Kt(e){let t=e.payload?.model||"unknown",n=c1(e.payload?.tokens),r=Number(e.payload?.usd)||0,o=e.payload?.speed||void 0,s=e.source==="vendor",a=r,i=!1;if(n&&!s){let u=In(t,n,e.ts,o?{speed:o}:void 0);u>0&&(a=u,i=Math.abs(u-r)>1e-9)}let c=n?n.input+n.output+n.cacheRead+n.cacheWrite:0,l=!a&&c>0&&!$x(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function jr(e,{boxLabels:t={}}={}){let n=(e||[]).filter(p=>p.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,d=Rx();for(let p of n){let{usd:f,model:w,tokens:m,repriced:g,unpriced:y,asRecorded:x}=Kt(p);i+=x;let b=p.provider||"unknown",O=p.boxId||"unattributed";if(g&&c++,y&&(l++,u.add(w)),a+=f,Ox(d,m),r[w]||={usd:0,tokens:Rx(),events:0},r[w].usd+=f,r[w].events+=1,Ox(r[w].tokens,m),o[b]||={usd:0,events:0},o[b].usd+=f,o[b].events+=1,s[O]||={usd:0,events:0,provider:b,models:new Set,label:t[O]||O},s[O].usd+=f,s[O].events+=1,w!=="unknown"&&s[O].models.add(w),p.epoch!=null){let I=(s[O].epochs||={})[p.epoch]||={usd:0,events:0,provider:b,models:new Set};I.usd+=f,I.events+=1,I.provider=b,w!=="unknown"&&I.models.add(w)}}return{totalUsd:js(a),asRecordedUsd:js(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:uu(r,p=>({...p,usd:js(p.usd)})),byProvider:uu(o,p=>({...p,usd:js(p.usd)})),byBox:uu(s,p=>({usd:js(p.usd),events:p.events,provider:p.provider,label:p.label,models:[...p.models],...p.epochs?{epochs:uu(p.epochs,f=>({usd:js(f.usd),events:f.events,provider:f.provider,models:[...f.models]}))}:{}}))}}var Rx,js,uu,Lr=K(()=>{Qn();Rx=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});js=e=>Math.round(e*1e4)/1e4,uu=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function l1(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 Mx(e,t=[]){let n=[],r=e?.events||[],o=new Map,s=0;for(let u of t){if(u.type!=="pr.state.changed")continue;let d=u.payload||{};!d.repo||d.number==null||(d.change==="merged"?o.set(`${d.repo}#${d.number}`,d):d.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(d=>{let[p,f]=d.split("#");return`${p.split("/").pop()}#${f}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(im(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(im(a,"subtask"));let i=r.filter(u=>u.type==="lead-handoff"&&u.fromAgent&&u.toAgent);if(i.length){let u=i.slice(0,3).map(d=>`${d.fromAgent}\u2192${d.toAgent}`).join(", ");n.push(`${im(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=jr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?l1(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var im,Cx=K(()=>{Lr();im=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as u1}from"node:child_process";import{promisify as d1}from"node:util";import{randomUUID as p1}from"node:crypto";async function cm(e,t){let n=Date.now()+t;for(;;){if(await Xn(e))return!0;if(Date.now()>n)return!1;await $i(m1)}}async function w1(e,t){let n=Px[t]||Px.default;n.escape&&(await qe(e,["Escape"],{kind:"swap-exit"}),await $i(150)),n.wipe&&await Es(e,Hl,{kind:"swap-exit"}),await Wl(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=En(t).submitDelayMs||0;await $i(Math.max(r,250)),await qe(e,["Enter"],{kind:"swap-exit"})}async function Dx(e,t){try{let{stdout:n}=await Ro(X,Q("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function Bx(e){await Ro(X,Q("respawn-pane","-k","-t",e))}async function lm(e,t={}){if(!je(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await ke(e);if(!r)throw new Error(`session "${e}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${e}"`);let o=r.agent||"agent",s=t.agent||$r(n),a=Number(t.exitTimeoutMs)||f1;await le({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let i=!1;if(!await Xn(e)&&(await w1(e,o),!await cm(e,a)&&(i=!0,await le({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await Bx(e),!await cm(e,Nx))))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);let c=s==="claude"&&To(n),l=c?fl():null,u=await Dx(e,"ANTHROPIC_API_KEY"),d=!1;try{l?(await Ro(X,Q("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),d=!0):u&&(await Ro(X,Q("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),d=!0)}catch(g){throw l?Dl(g,l):g}if(d&&!i&&(await Bx(e),!await cm(e,Nx)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let p=!!t.resumeSessionId,f=t.resumeSessionId||p1(),w=p?n:ii(n,f,e),m=p?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(w);return c&&await vr(r.cwd),s==="codex"&&await ms(r.cwd),s==="cursor"&&await hs(r.cwd),await Ao(e),await Ro(X,Q("set-option","-t",e,"@bostrat-sid",f)),await Ro(X,Q("set-option","-t",e,"@bostrat-agent",s)),await $i(h1),c&&ai().length&&(await Dx(e,si)||await Ro(X,Q("set-environment","-t",e,si,"1")).catch(()=>{}),await ot(e,`export ${si}=1`,{kind:"swap-env"}),await $i(150)),await ot(e,w,{kind:"swap-launch"}),await le({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:f,forced:i,envRespawned:d}),{name:e,cwd:r.cwd,sessionId:f,agent:s,pinned:m,forced:i,envRespawned:d,launchCmd:w}}var Ro,$i,f1,Nx,m1,h1,Px,jx=K(()=>{ct();qa();hl();wl();ki();Tn();Ro=d1(u1),$i=e=>new Promise(t=>setTimeout(t,e)),f1=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,Nx=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,m1=250,h1=400,Px={claude:{escape:!0,wipe:!0,text:"/exit"},codex:{escape:!0,wipe:!0,text:"/quit"},cursor:{escape:!0,wipe:!0,text:"/quit"},default:{escape:!1,wipe:!1,text:"exit"}}});function x1(e){if(e.type==="queue-operation"&&e.operation==="enqueue")return Lx.test(String(e.content||""))?String(e.content):null;if(e.type==="attachment"){let n=e.attachment;return n?.type==="queued_command"&&n.commandMode==="task-notification"&&typeof n.prompt=="string"?n.prompt:null}let t=e.message?.content;return typeof t=="string"&&Lx.test(t)?t:null}async function Fx(e,t={}){return(await Hx(e,t)).launches}async function Ux(e,t={}){let{launches:n,done:r}=await Hx(e,t);return n.filter(o=>!r.has(o.id))}async function Hx(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await _t(e,t)}catch{return{launches:[],done:new Set}}let o=new Map,s=new Set,a=new Set,i=new Map;for(let l of r.split(`
159
- `)){let u=l.trim();if(!u||u[0]!=="{")continue;let d;try{d=JSON.parse(u)}catch{continue}if(d.isSidechain)continue;let p=x1(d);if(p){let m=p.match(k1)?.[1]?.trim();m&&a.add(m);continue}let f=d.message?.content;if(!Array.isArray(f))continue;let w=d.timestamp?Date.parse(d.timestamp):null;for(let m of f)if(!(!m||typeof m!="object")){if(m.type==="tool_use"&&m.id){if(m.name==="Agent"){let g=m.input||{};o.set(m.id,{id:m.id,kind:"agent",name:String(g.description||"").trim()||null,detail:String(g.subagent_type||"").trim()||null,ts:w,proven:!1})}else if(m.name==="Bash"){let g=String(m.input?.command||"").trim(),y={id:m.id,kind:"command",name:String(m.input?.description||"").trim()||(g?Rs(g):null),detail:g?Rs(g):null,ts:w,proven:m.input?.run_in_background===!0};y.proven?o.set(m.id,y):i.set(m.id,y)}}else if(m.type==="tool_result"&&m.tool_use_id){let g=v1(m.content);if(g1.test(g)&&s.add(m.tool_use_id),g.match(y1)){let x=i.get(m.tool_use_id);x&&(i.delete(m.tool_use_id),x.proven=!0,x.outputFile=g.match(b1)?.[1]?.replace(/\.$/,"")||null,o.set(x.id,x))}}}}let c=[];for(let l of o.values()){if(!l.proven&&!s.has(l.id))continue;let{proven:u,...d}=l;c.push(d)}return{launches:c.slice(-n),done:a}}var g1,y1,b1,Lx,k1,v1,Wx=K(()=>{an();Os();g1=/^Async (?:agent|task) launched/i,y1=/^Command did not complete within its [^\n]*?moved to the background \(ID: ([^)]+)\)/i,b1=/Output is being written to:\s*(\S+)/i,Lx=/^\s*<task-notification>/i,k1=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i;v1=e=>{if(typeof e=="string")return e.trim();if(!Array.isArray(e))return"";let t=e.find(n=>n&&n.type==="text"&&typeof n.text=="string");return t?t.text.trim():""}});function Fr(e,t){if(!e)return null;let n=String(e);if(t){let o=t.endsWith("/")?t:`${t}/`;if(n===t)return".";if(n.startsWith(o))return n.slice(o.length)||"."}let r=n.split("/").filter(Boolean);return n.startsWith("/")&&r.length>2?r.slice(-2).join("/"):n}function S1(e){let t=typeof e=="string"?e:String(e?.patch??e?.input??""),n=[];for(let r of t.matchAll(/^\*{3} (?:Update|Add|Delete) File: (.+)$/gm))n.push(r[1].trim());return n}function qx(e,t,n){switch(e){case"Shell":{let r=String(t?.command||"").trim();return r?{command:r,description:String(t?.description||"").trim()}:null}case"Read":{let r=t?.path;if(!r)return null;let o=Number(t?.offset)||null,s=o&&Number(t?.limit)?o+Number(t.limit)-1:null;return{command:cn(`read ${Fr(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${Ls(r)}`:`Read ${Ls(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?Fr(t.path,n):null,s=t?.glob?` --glob ${um(t.glob)}`:"",a=cn(String(r),40);return{command:cn(`grep ${um(r)}${o&&o!=="."?` ${o}`:""}${s}`,140),description:o&&o!=="."?`Search for \u201C${a}\u201D in ${o}`:`Search for \u201C${a}\u201D`}}case"Glob":{let r=t?.glob_pattern;if(!r)return null;let o=t?.target_directory?Fr(t.target_directory,n):null;return{command:cn(`glob ${um(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${cn(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:cn(`edit ${Fr(t.path,n)}`,140),description:`Edit ${Ls(t.path)}`}:null;case"Write":return t?.path?{command:cn(`write ${Fr(t.path,n)}`,140),description:`Write ${Ls(t.path)}`}:null;case"Delete":return t?.path?{command:cn(`delete ${Fr(t.path,n)}`,140),description:`Delete ${Ls(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>Fr(s,n)).filter(Boolean);return{command:cn(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=S1(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:cn(`apply_patch ${Fr(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${Ls(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:cn(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var du,cn,Ls,um,Kx=K(()=>{du=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),cn=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,Ls=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);um=e=>`"${String(e).replace(/"/g,'\\"')}"`});import Ri from"node:fs";import T1 from"node:fs/promises";import Oo from"node:path";import A1 from"node:os";import E1 from"node:crypto";import _1 from"node:zlib";function Vx(e){let t=E1.createHash("md5").update(String(e)).digest("hex");return Oo.join(I1,t)}function Jx(e){try{let t=JSON.parse(Ri.readFileSync(Oo.join(e,"meta.json"),"utf8"));return{createdAtMs:Number(t.createdAtMs)||null,updatedAtMs:Number(t.updatedAtMs)||Number(t.createdAtMs)||null,hasConversation:t.hasConversation===!0}}catch{return null}}function $1(e){let t=Vx(e),n;try{n=Ri.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=Oo.join(t,o.name),a=Oo.join(s,"store.db");if(!Ri.existsSync(a))continue;let i=Jx(s);if(!i)continue;let c={id:o.name,dir:s,store:a,...i};(!r||c.hasConversation&&!r.hasConversation||c.hasConversation===r.hasConversation&&(c.updatedAtMs||0)>(r.updatedAtMs||0))&&(r=c)}return r}function pu(e,t){if(!e)return null;if(t){let n=Oo.join(Vx(e),t),r=Oo.join(n,"store.db");if(Ri.existsSync(r))return{id:t,dir:n,store:r,...Jx(n)||{createdAtMs:null,updatedAtMs:null}}}return $1(e)}function Gx(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function R1(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=_1.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function O1(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 M1(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!du.has(r.toolName))continue;let o=qx(r.toolName,r.args,t);!o||!o.command||n.push({id:r.toolCallId||null,tool:r.toolName,command:o.command,description:o.description||""})}return n}async function dm(e,t){if(!zx)return Fs;let{DatabaseSync:n}=zx,r;try{r=new n(e,{readOnly:!0})}catch{return Fs}try{let o=r.prepare("SELECT value FROM meta WHERE key = '0'").get()||r.prepare("SELECT value FROM meta LIMIT 1").get();if(!o)return Fs;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return Fs}let a=s.lastUsedModel||null,i=s.latestRootBlobId?Gx(r,s.latestRootBlobId):null;if(!i)return{...Fs,model:a};let c=[],l=[],u=[],d=null,p=[];for(let f of O1(i)){let w=R1(Gx(r,f));if(!w)continue;let m=w.providerOptions?.cursor;if(m?.requestId&&p.push(m.requestId),m?.modelProviderMessageId&&p.push(m.modelProviderMessageId),w.role!=="assistant")continue;if(Array.isArray(w.content))for(let x of w.content){let b=x?.providerOptions?.cursor?.modelName;b&&(d=b)}l.push(...M1(w.content,t).map((x,b)=>({...x,id:x.id||`${f}:${b}`}))),u.push(...N1(w.content));let g=C1(w.content);if(!g)continue;let y=[...new Set(u)];u=[],c.push({id:f,text:g,tools:y.length?y:void 0,commands:l,model:d}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:p}}catch{return Fs}finally{try{r.close()}catch{}}}function Yx(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(Ri.statSync(e.store).mtimeMs)}catch{n=Date.now()}let r=e.createdAtMs;(!r||r>n)&&(r=n-t*1e3);let o=Math.max(0,n-r);return{end:n,tsAt:s=>Math.round(r+o*(s+1)/t)}}async function Xx(e,t,{limit:n=80}={}){let r=pu(e,t);if(!r)return[];let{turns:o,model:s}=await dm(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=Yx(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 Zx(e,t){let n=pu(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await dm(n.store,e);return{chatId:n.id,requestIds:o,models:[...new Set(r.map(a=>a.model).filter(Boolean))],configuredModel:s,updatedAtMs:n.updatedAtMs||null}}async function Qx(e,t,{limit:n=80}={}){let r=pu(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await dm(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=Yx(r,a.length||1),l=[];a.forEach((u,d)=>{for(let p of u.commands)l.push({...p,summary:Mr(p.command,p.description),ts:c(d)})});for(let u of s)l.push({...u,summary:Mr(u.command,u.description),ts:i+1});return l}async function ev(e,t){let n=pu(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await T1.stat(n.store)).mtimeMs)}catch{return null}}var I1,C1,N1,zx,Fs,pm=K(()=>{Os();Kx();I1=process.env.BOSTRAT_CURSOR_CHATS||Oo.join(A1.homedir(),".cursor","chats");C1=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
160
- `).trim():"",N1=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],zx=process.getBuiltinModule?.("node:sqlite"),Fs={turns:[],trailingCommands:[],model:null,requestIds:[]}});import P1 from"node:fs/promises";function wm(e){return tv.set(e.agent,e),e}function Ur(e){return tv.get(e)||D1}async function gm(e,t={}){return(await Ur(e.agent).readMessages(e,t)).map(fu(e))}async function nv(e,t={}){return(await Ur(e.agent).readCommands(e,t)).map(fu(e))}async function rv(e,t={}){return(await Ur(e.agent).readJobs(e,t)).map(fu(e))}async function ov(e,t={}){return(await Ur(e.agent).readOpenJobs(e,t)).map(fu(e))}var Us,fm,mm,hm,D1,tv,fu,ym=K(()=>{an();Gl();Os();Wx();pm();Io();Us=class{constructor(t,n=new Set){this.agent=t,this.cliTools=n}async readMessages(){return[]}async readCommands(){return[]}async readJobs(){return[]}async readOpenJobs(){return[]}async updatedAt(){return null}},fm=class extends Us{transcript(t){return!t?.cwd||!t?.sessionId?null:sn(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?$f(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?Uk(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?Fx(r,n):[]}async readOpenJobs(t,n){let r=this.transcript(t);return r?Ux(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await P1.stat(n)).mtimeMs)}catch{return null}}},mm=class extends Us{async readMessages(t,n){return Xx(t.cwd,t.sessionId,n)}async readCommands(t,n){return Qx(t.cwd,t.sessionId,n)}async updatedAt(t){return ev(t.cwd,t.sessionId)}},hm=class extends Us{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return Kk(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return Gk(t.cwd,this.sessionId(t),n)}async updatedAt(t){return zk(t.cwd,this.sessionId(t))}},D1=new Us("unknown"),tv=new Map;wm(new fm("claude",Tf));wm(new mm("cursor",du));wm(new hm("codex",mi));fu=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function Wr(e){let t=e.search(vm);return(t>=0?e.slice(0,t):e).trim()}function B1(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function j1(e){let t=String(e).trim();return!!(!t||Hr.test(e)||vm.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function L1(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=F1(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function F1(e,t){let n=String(t).toLowerCase(),r=e.findIndex(c=>!c.answered),o=r>=0?r:e.length-1;if(!n)return o;let s=e.map(c=>{let l=c.label.toLowerCase(),u=l.split(/\s+/).filter(p=>p.length>3&&n.includes(p)).length;if(u)return u;let d=l.slice(0,8).trim();return d.length>=4&&n.includes(d)?1:0}),a=Math.max(...s);if(a===0||s[o]===a)return o;let i=s.flatMap((c,l)=>c===a?[l]:[]);return i.length===1?i[0]:o}function sv(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function U1(e,t=""){let n=String(e);if(!iv.test(n))return null;let r=n.replace(/\r/g,"").split(`
161
- `),o=-1;for(let u=r.length-1;u>=0;u--)if(/^\s*Switch model\?\s*$/.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[];for(let u=o+1;u<r.length;u++){let d=r[u].match(Mo);if(d)s.push({cursor:!!d[1],label:d[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let p=r[u].trim();p&&!Hr.test(r[u])&&a.push(p)}}if(s.length<2)return null;let i=s.map(u=>({label:Wr(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 W1(e,t=""){let n=String(e).replace(/\r/g,"").split(`
162
- `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!cv.test(n[r]))return null;let o=r-1;for(;o>=0&&n[o].trim()==="";)o--;let s=[];for(;o>=0;o--){let c=n[o].match(Mo);if(!c)break;s.unshift({cursor:!!c[1],n:Number(c[2]),label:c[4].trim()})}if(s.length<2||s.some((c,l)=>c.n!==l+1))return null;let a=[];for(let c=o;c>=0&&a.length<6&&!(H1.test(n[c])||Hr.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:Wr(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 q1(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
163
- `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(Mo);l&&o.push({cursor:!!l[1],label:l[4].trim()})}let s=o.filter(c=>/^(submit answers|cancel)$/i.test(c.label));if(s.length<2)return null;let a=s.map(c=>({label:c.label,description:""})),i=Math.max(0,s.findIndex(c=>c.cursor));return{provider:"claude",box:t,multiSelect:!1,cursorIndex:i,review:!0,promptId:"claude:review:submit-answers",questions:[{question:"Ready to submit your answers?",header:"Review",multiSelect:!1,options:a}]}}function G1(e,t=""){let n=String(e);if(!bm.test(n))return null;let r=n.replace(/\r/g,"").split(`
164
- `),o=-1;for(let u=r.length-1;u>=0;u--)if(K1.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[r[o].trim()];for(let u=o+1;u<r.length;u++){let d=r[u].match(Mo);if(d)s.push({cursor:!!d[1],label:d[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let p=r[u].trim();p&&!Hr.test(r[u])&&a.push(p)}}if(s.length<2||!s.some(u=>bm.test(u.label)))return null;let i=s.map(u=>({label:Wr(u.label),description:""})),c=Math.max(0,s.findIndex(u=>u.cursor)),l=a.join(" ");return{provider:"claude",box:t,multiSelect:!1,cursorIndex:c,promptId:`claude:resume-confirm:${i.map(u=>u.label).join("|")}`.slice(0,240),questions:[{question:l,header:"Resume",multiSelect:!1,options:i}]}}function Sm(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(Mo);o&&t.push({line:r,cursor:!!o[1],n:Number(o[2]),label:o[4].trim()})}let n=t.sort((r,o)=>r.n-o.n);return n.length<2||n.some((r,o)=>r.n!==o+1)?null:n}function z1(e,t=""){let n=String(e);if(!lv.test(n)||!uv.test(n)||Co.test(n))return null;let r=n.replace(/\r/g,"").split(`
165
- `),o=Sm(r);return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(s=>s.cursor)),setup:"theme",promptId:`claude:setup:theme:${o.map(s=>s.label).join("|")}`.slice(0,200),questions:[{question:"Claude Code asks: choose the text style that looks best with your terminal. You can change it later with /theme.",header:"Theme",multiSelect:!1,options:o.map(s=>({label:Wr(s.label),description:""}))}]}:null}function V1(e,t=""){let n=String(e);if(!dv.test(n)||Co.test(n))return null;let r=n.replace(/\r/g,"").split(`
166
- `),o=Sm(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:Wr(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 Y1(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!J1.test(o)||Tm.test(e[r]))break;n+=o}return n}function X1(e,t=""){let n=String(e);if(!Tm.test(n)||Co.test(n))return null;let r=n.replace(/\r/g,"").split(`
167
- `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=Y1(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 Q1(e,t=""){let n=String(e);if(!km.test(n)||!Z1.test(n)||Co.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
168
- `)].reverse().find(a=>km.test(a))||"OAuth error").trim();return{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,setup:"oauth-error",promptId:`claude:setup:oauth-error:${s}`.slice(0,200),questions:[{question:`${s} \u2014 retry to get a fresh sign-in link.`,header:"Log in",multiSelect:!1,options:[{label:"Retry sign-in",description:"Mints a new sign-in link and code"}]}]}}function eB(e,t=""){let n=String(e);if(!pv.test(n)||Co.test(n))return null;let r=n.replace(/\r/g,"").split(`
169
- `),o=Sm(r);return o?{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,o.findIndex(s=>s.cursor)),setup:"trust",promptId:`claude:setup:trust:${o.map(s=>s.label).join("|")}`.slice(0,200),questions:[{question:"Claude Code asks whether it can read, edit, and run files in this workspace. This box's workspace is bostrat-managed scratch space, so trusting it is safe.",header:"Folder trust",multiSelect:!1,options:o.map(s=>({label:Wr(s.label),description:""}))}]}:null}function tB(e,t=""){let n=String(e);if(Co.test(n))return null;let r=n.replace(/\r/g,"").split(`
170
- `),o=-1;for(let l=r.length-1;l>=0;l--)if(r[l].trim()!==""){o=l;break}if(o<0)return null;let s=r[o].match(fv);if(!s)return null;let a=[];for(let l=o-1;l>=0&&a.length<3;l--){let u=r[l].trim();if(!u){if(a.length)break;continue}if(Hr.test(r[l])||vm.test(u))break;a.unshift(u)}let i=s[1].trim();i&&a.push(i);let c=a.join(" ")||"Claude Code is waiting for you to continue.";return{provider:"claude",box:t,multiSelect:!1,cursorIndex:0,setup:"continue",promptId:`claude:setup:continue:${c}`.slice(0,200),questions:[{question:c,header:"Continue",multiSelect:!1,options:[{label:"Continue",description:""}]}]}}function nB(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(xm.test(e[r])){t=r;break}if(t<0)return null;let n=-1;for(let r=t-1;r>=0;r--)if(/[☐☒]/.test(e[r])){n=r;break}return n<0?null:{headerLine:n,chatLine:t,optStart:n+1,optEnd:t}}function rB(e,t){let n=e.find(s=>/^type something\b/i.test(s.label));if(n)return n;if(e.length<2)return null;let r=e[e.length-1];if(mu.test(r.label))return null;let o=null;for(let s=r.line+1;s<Math.min(t.length,r.line+3);s++){let a=t[s].replace(/^\s*❯/,"").trim();if(a){o=a;break}}return o&&(Hr.test(o)||/^submit\b/i.test(o))?r:null}function oB(e,t=""){let n=String(e);if(!av.test(n)||!xm.test(n))return null;let r=n.replace(/\r/g,"").split(`
171
- `),o=nB(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let $=i;$<c;$++){let L=r[$].match(Mo);L&&(u<0&&(u=$),l.push({line:$,cursor:!!L[1],checked:L[3]!=null&&L[3]!==" ",hasCheckbox:L[3]!=null,label:L[4].trim(),desc:""}))}if(!l.length)return null;for(let $ of l)for(let L=$.line+1;L<Math.min(r.length,$.line+4)&&!(Mo.test(r[L])||Hr.test(r[L]));L++){let V=r[L].trim();if(!(!V||j1(r[L])||mu.test(V))){$.desc=B1(V);break}}let d=rB(l,r),p=l.filter($=>$!==d&&!mu.test($.label));if(!p.length)return null;let f=p.some($=>$.hasCheckbox),w=d?.cursor?p.length:Math.max(0,p.findIndex($=>$.cursor)),m=d&&!mu.test(d.label)?Wr(d.label):"",g=s>=0?s+1:0,y=[];for(let $=g;$<u;$++){let L=r[$].trim();L&&!Hr.test(r[$])&&!/[☐☒]/.test(r[$])&&y.push(L)}let x=y.join(" ")||(s>=0?sv(r[s]):"")||"The agent is asking a question",b=s>=0?L1(r[s],x):null,O=b?.currentTabLabel||(s>=0?sv(r[s]):""),I=p.map($=>({label:Wr($.label),description:$.desc})),C=I.map($=>$.label).join("|"),H=`claude:${b?`q${b.questionIndex+1}/${b.questionTotal}`:"q1/1"}:${O}:${x}:${C}`.slice(0,240),_=b?`claude:ask:${b.tabs.map($=>$.label).join("|")}`.slice(0,240):H;return{provider:"claude",box:t,multiSelect:f,cursorIndex:w,promptId:H,groupId:_,...d?{custom:!0,customIndex:p.length,customText:m}:{},dismissable:!0,...b?{questionIndex:b.questionIndex,questionTotal:b.questionTotal,currentTabLabel:b.currentTabLabel,tabs:b.tabs}:{},questions:[{question:x,header:O,multiSelect:f,options:I}]}}function qr(e,t){let n=String(t||"");return n?e==="claude"?av.test(n)&&xm.test(n)||iv.test(n)||bm.test(n)||cv.test(n.trimEnd().split(`
172
- `).pop()||"")?!0:Co.test(n)?!1:lv.test(n)&&uv.test(n)||dv.test(n)||Tm.test(n)||km.test(n)||pv.test(n)||fv.test(n.trimEnd().split(`
173
- `).pop()||""):e==="codex"&&/Sign in with ChatGPT|one-time code|Paste or type your API key|link to authenticate|Successfully logged in\.[\s\S]*Press Enter to continue\./i.test(n)?!0:e==="cursor"||e==="codex"?/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i.test(n):!1:!1}function $n(e,t){return!e||!t?null:e.agent==="claude"?q1(t,e.name)||oB(t,e.name)||U1(t,e.name)||G1(t,e.name)||Q1(t,e.name)||X1(t,e.name)||V1(t,e.name)||z1(t,e.name)||eB(t,e.name)||tB(t,e.name)||W1(t,e.name):e.agent==="cursor"||e.agent==="codex"?c0(e.agent,t,e.name):null}async function Am(e){if(!e)return null;let t=await on(e.name).catch(()=>"");return $n(e,t)}function Em(e,t){let n=Array.isArray(t?.[0])?t[0].filter(a=>Number.isInteger(a)&&a>=0):[],r=Number.isInteger(e?.cursorIndex)?e.cursorIndex:0,o=(a,i)=>{let c=i-a;return Array.from({length:Math.abs(c)},()=>c>0?"Down":"Up")},s=[];if(e?.multiSelect){let a=r;for(let i of[...n].sort((c,l)=>c-l))s.push(...o(a,i),"Enter"),a=i;s.push("Tab","Enter")}else{let a=n.length?n[0]:0;s.push(...o(r,a),"Enter")}return s}function mv(e,t,n=""){let r=typeof n=="string"?n.trim():"";if(!r||!e?.custom)return{pre:Em(e,t).map(d=>({key:d})),text:"",post:[]};let o=Array.isArray(t?.[0])?t[0].filter(d=>Number.isInteger(d)&&d>=0):[],s=Number.isInteger(e.customIndex)?e.customIndex:e.questions?.[0]?.options?.length??0,a=Number.isInteger(e.cursorIndex)?e.cursorIndex:0,i=(d,p)=>{let f=p-d;return Array.from({length:Math.abs(f)},()=>({key:f>0?"Down":"Up"}))},c=[],l=a,u=typeof e.customText=="string"?e.customText.length:0;if(u>0&&a===s&&c.push(...Array.from({length:u+2},()=>({key:"BSpace"}))),e.multiSelect){for(let d of[...o].sort((p,f)=>p-f))c.push(...i(l,d),{key:"Enter"}),l=d;return c.push(...i(l,s)),{pre:c,text:r,post:[{key:"Down"},{key:"Enter"}]}}return c.push(...i(l,s)),{pre:c,text:r,post:[{key:"Enter"}]}}function hv(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 av,xm,Mo,mu,Hr,vm,iv,cv,H1,bm,K1,Co,lv,uv,dv,Tm,J1,km,Z1,pv,fv,_m=K(()=>{ct();Vl();av=/to navigate\b.*\bEsc to cancel|Enter to select\b/,xm=/Chat about this/i,Mo=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,mu=/^(type something|chat about this|submit)\b/i,Hr=/^[─—-]{6,}\s*$/,vm=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;iv=/^\s*Switch model\?\s*$/m;cv=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,H1=/^\s*[─—▔-]{6,}\s*$/;bm=/Resume from summary/i,K1=/^\s*This session is\b/;Co=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;lv=/Choose the text style that looks best with your terminal/,uv=/Let's get started\./;dv=/Select login method:/;Tm=/Paste code here if prompted/,J1=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;km=/OAuth error:/,Z1=/Press Enter to retry\./;pv=/Quick safety check: Is this a project you created or one you trust/;fv=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function hu(e,t,n){if(!e||!t)return null;for(let r of sB)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function iB(e){let t=Im.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},Im.set(e,t)),t}function yv(e,t,n=Date.now()){let r=iB(e);if(r.sentAt=r.sentAt.filter(s=>n-s<gv),r.sentAt.length>=wv)return{action:"give-up"};if(n-r.last<aB)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 bv(e,t=Date.now()){let n=Im.get(e);return n?n.sentAt.filter(r=>t-r<gv).length>=wv:!1}var sB,aB,wv,gv,Im,$m=K(()=>{sB=[{provider:"claude",id:"fullscreen-upsell",match(e,t){let n=e?.questions?.[0],r=(n?.options||[]).map(s=>String(s.label||"").trim());if(r.length!==2||!/^Yes, try it$/.test(r[0])||!/^Not now$/.test(r[1]))return!1;let o=`${n?.question||""}
174
- ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];aB=5e3,wv=5,gv=3600*1e3,Im=new Map});function Hs(e){return typeof e=="string"?e.trim():""}var kv=K(()=>{});import{execFile as cB}from"node:child_process";import{promisify as lB}from"node:util";async function Ve(e,t,{input:n}={}){let r=Om("git",["-C",e,...t],{maxBuffer:xv});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function Ws(e){if(!e)return!1;try{let{stdout:t}=await Ve(e,["rev-parse","--is-inside-work-tree"]);return t.trim()==="true"}catch{return!1}}async function vv(e){let{stdout:t}=await Ve(e,["rev-parse","--show-toplevel"]);return t.trim()}async function uB(e){try{return await Ve(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function qs(e,t="bostrat: subtask snapshot"){let{stdout:n}=await Ve(e,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>Om("git",["-C",e,...a],{maxBuffer:xv,env:o,...i});try{let a=await uB(e);a&&await s(["read-tree","HEAD"]),await s(["add","-A"]);let{stdout:i}=await s(["write-tree"]),c=i.trim(),l=a?["commit-tree",c,"-p","HEAD","-m",t]:["commit-tree",c,"-m",t],{stdout:u}=await s(l);return u.trim()}finally{try{await Om("rm",["-f",r])}catch{}}}async function Mm(e,t,{trailers:n=[]}={}){let{stdout:r}=await Ve(e,["status","--porcelain"]);return r.trim()?(await Ve(e,["add","-A"]),await Ve(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",t,...n.flatMap(o=>["--trailer",o])]),!0):!1}async function Oi(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await Ve(e,["status","--porcelain"]),r=n.split(`
175
- `).filter(Boolean);return t&&(r=r.filter(o=>{let s=o.slice(3);return!(s===".bostrat"||s===".bostrat/"||s.startsWith(".bostrat/")||o.startsWith("??")&&(s==="AGENTS.md"||s==="CLAUDE.md"))})),r.length>0}async function Mi(e,t){if(!t)return 0;try{let{stdout:n}=await Ve(e,["rev-list","--count",`${t}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function Ks(e,t,n,r){return await Ve(e,["worktree","add","--no-track","-b",n,t,r]),t}async function Sv(e,t){try{return await Ve(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function wu(e,t,n){return await Ve(e,["worktree","add","--end-of-options",t,n]),t}async function Gs(e){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:t}=await Ve(e,["symbolic-ref","--short","refs/remotes/origin/HEAD"]);if(t.trim())return t.trim()}catch{}for(let[t,n]of[["refs/remotes/origin/main","origin/main"],["refs/remotes/origin/master","origin/master"],["refs/heads/main","main"],["refs/heads/master","master"]])try{return await Ve(e,["rev-parse","--verify","--quiet",t]),n}catch{}return"HEAD"}async function Cm(e){await Ve(e,["init","-q"]),await Ve(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function Mt(e,t){try{await Ve(e,["worktree","remove","--force",t])}catch{try{await Ve(e,["worktree","prune"])}catch{}}}function dB(e){let t=/(\d+) files? changed/.exec(e),n=/(\d+) insertions?\(\+\)/.exec(e),r=/(\d+) deletions?\(-\)/.exec(e);return{files:t?Number(t[1]):0,insertions:n?Number(n[1]):0,deletions:r?Number(r[1]):0}}function Nm(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function Pm(e,t,n,r){let{stdout:o}=await Ve(e,Nm(["diff","--shortstat",t,n],r));return dB(o)}async function Dm(e,t,n,r){let{stdout:o}=await Ve(e,Nm(["diff","--name-only",t,n],r));return o.split(`
176
- `).map(s=>s.trim()).filter(Boolean)}async function Bm(e,t,n,r){let{stdout:o}=await Ve(e,Nm(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await Rm(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await Rm(e,o,["--3way","--whitespace=nowarn"]),a=await pB(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await Rm(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function Rm(e,t,n){try{return await Ve(e,["apply",...n,"-"],{input:t}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function pB(e){try{let{stdout:t}=await Ve(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
177
- `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var Om,xv,gu=K(()=>{Om=lB(cB),xv=64*1024*1024});function yu(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!fB.has(o.state)&&o.state!=="stopped"&&(o.state="stopped",r=!0);let s=Array.isArray(o.epochs)?o.epochs:[],a=s[s.length-1];a&&typeof a=="object"&&a.endedAt==null&&(a.endedAt=t,a.endReason==null&&(a.endReason=n),r=!0)}return r}var De,fB,Gt=K(()=>{De=e=>!!(e&&(e.archivedAt||e.transferredTo)),fB=new Set(["merged","conflict","canceled","failed","handed-off"])});import jm from"node:fs/promises";import Av from"node:path";import mB from"node:os";function $v(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function Rv(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function Ov(e){let t=new Date($v(e));return t.setDate(t.getDate()+7),t.getTime()}function Mv(e){let t=new Date(Rv(e));return t.setMonth(t.getMonth()+1),t.getTime()}function ku(e=Date.now()){for(let[t,n]of Object.entries(zs)){let r=n.startOf(e);if(r!==er[t]){er[t]=r;for(let o of No.values())o[t]=0;for(let o of Vs)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&Vs.delete(o)}}}function Cv(e,t){let n=ln?.caps?.[e]?.[zs[t].capKey];return Number.isFinite(n)&&n>0?n:null}function Po(e,t=Date.now()){if(!e||!Fm||!ln?.caps)return null;ku(t);let n=No.get(e);for(let r of Object.keys(zs)){let o=Cv(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:bu(s),resetsAt:zs[r].nextStart(t)}}return null}function Nv(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${er[t.window]}`;return Vs.has(n)?!1:(Vs.add(n),!0)}function Tv(e,t,n,r=Date.now()){if(!e||!t)return;ku(r);let o=hB(e);for(let[s,a]of Object.entries(zs))n>=er[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function wB(e,t,n=Date.now()){if(!ln?.caps||!Lm)return;let r=No.get(e);if(r)for(let[o,s]of Object.entries(zs)){let a=Cv(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*Iv||i>=a)continue;let c=`warn:${e}:${o}:${er[o]}`;if(!Vs.has(c)){Vs.add(c);try{let l=await Lm(t);if(!l)continue;await M(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:bu(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function Pv(e){let t={};for(let[n,r]of Object.entries(e||{})){if(typeof n!="string"||!/^[a-z][a-z0-9-]{0,31}$/.test(n))throw new Error(`bad provider key "${n}"`);let o={};for(let s of["weeklyUsd","monthlyUsd"]){let a=r?.[s];if(a==null||a==="")continue;let i=Number(a);if(!Number.isFinite(i)||i<=0)throw new Error(`${n}.${s} must be a positive number or null`);o[s]=i}Object.keys(o).length&&(t[n]=o)}return t}async function xu(e,{source:t="local",updatedAt:n=Date.now()}={}){ln={caps:Pv(e),updatedAt:n,source:t};try{await jm.mkdir(Ev,{recursive:!0}),await jm.writeFile(_v(),JSON.stringify(ln,null,2))}catch{}return Ci()}function Ci(e=Date.now()){ku(e);let t=new Set([...No.keys(),...Object.keys(ln?.caps||{})]),n={};for(let r of t){let o=No.get(r);n[r]={weeklyUsd:bu(o?.weekly||0),monthlyUsd:bu(o?.monthly||0)}}return{caps:ln?.caps||{},configured:!!ln,seeded:Fm,updatedAt:ln?.updatedAt??null,spent:n,windows:{weekly:{start:er.weekly,resetsAt:Ov(e)},monthly:{start:er.monthly,resetsAt:Mv(e)}},warnPct:Iv}}async function Dv({listTracks:e,getTrack:t}={}){Lm=t||null,ku();try{let o=JSON.parse(await jm.readFile(_v(),"utf8"));ln={caps:Pv(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{ln=null}let n=Date.now();Je.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Kt(o);Tv(o.provider||"unknown",s,o.ts??Date.now()),wB(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(er.weekly,er.monthly);for(let o of await e?.()||[]){let s;try{s=await q(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||Tv(a.provider||"unknown",Kt(a).usd,i,n)}}return Fm=!0,Ci()}var Ev,_v,Iv,zs,ln,Fm,er,No,Vs,Lm,hB,bu,vu=K(()=>{pe();Lr();Ev=process.env.BOSTRAT_STATE_DIR||Av.join(process.env.HOME||mB.tmpdir(),".bostrat"),_v=()=>Av.join(Ev,"usage-caps.json"),Iv=.8;zs={weekly:{startOf:$v,nextStart:Ov,capKey:"weeklyUsd"},monthly:{startOf:Rv,nextStart:Mv,capKey:"monthlyUsd"}},ln=null,Fm=!1,er={weekly:0,monthly:0},No=new Map,Vs=new Set,Lm=null,hB=e=>{let t=No.get(e);return t||(t={weekly:0,monthly:0},No.set(e,t)),t};bu=e=>Math.round(e*1e4)/1e4});import gB from"node:fs/promises";import yB from"node:os";import Bv from"node:path";function Um(e){return e==="codex"?vB:e==="cursor"?Wv:Uv}function jv(e){let t=String(e||"").split(`
178
- `),n=t.findIndex(o=>/Select Model and Effort/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+(\S+?)(?:\s+\((current|default)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),id:s[3],current:s[4]==="current",active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function Lv(e){let t=String(e||"").split(`
179
- `),n=t.findIndex(o=>/Select Reasoning Level/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+([A-Za-z ]+?)(?:\s+\((default|current)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),label:s[3].trim(),isDefault:!!s[4],active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function SB(e){let t=String(e||"").split(`
180
- `);for(let n=t.length-1;n>=0;n--){let r=t[n].match(/Model changed to\s+(\S+)(?:\s+(\S+))?\s*$/i);if(r)return{model:r[1],effort:r[2]||null}}return null}function Fv(e){let t=String(e||"").split(`
181
- `),n=t.findIndex(s=>/Available models|Models matching/i.test(s));if(n<0)return null;let r=/Models matching/i.test(t[n]),o=[];for(let s=n+1;s<t.length;s++){let a=t[s];if(/^\s*Filter:/i.test(a)||!a.trim())continue;if(/to filter|Enter to select|^\s*\d+-\d+ of \d+/i.test(a))break;let i=a.match(/^\s*(→\s+)?(.+?)\s*$/);if(!i)continue;let c=i[2].replace(/\s*\(Tab to modify\)\s*$/i,""),l=null,u=c.split(/\s{2,}/);u.length>1&&(c=u[0],l=u.slice(1).join(" ").trim()||null),c&&o.push({label:c.trim(),params:l,active:!!i[1]})}return o.length?{filtered:r,rows:o}:null}function qv(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&&!Hv.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=Wv.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!xB.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Ni(e,t,{timeoutMs:n=bB}={}){let r=Date.now()+n;for(;;){let o=await Be(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await Su(kB)}}async function TB(e,t){return await ot(e,`/model ${t.model}`,En("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function AB(e,t){await Ul(e),await ot(e,"/model",{enter:!1}),await Su(250),await qe(e,["Enter"],{kind:"model-switch"});let n=await Ni(e,jv);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await qe(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`unknown model "${t.model}" \u2014 codex offers: ${n.map(i=>i.id).join(", ")}`);let o=i=>{let c=SB(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await ot(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await Ni(e,i=>Lv(i)||!jv(i)&&o(i)&&{done:o(i)});if(!s)throw await qe(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?Hv.get(t.effort):null,c=i?s.find(l=>l.label.toLowerCase()===i.toLowerCase()):s.find(l=>l.isDefault)||s[0];if(!c)throw await qe(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await ot(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Ni(e,i=>!Lv(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 EB(){let e=Bv.join(process.env.CURSOR_CONFIG_DIR||Bv.join(yB.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await gB.readFile(e,"utf8"))?.model||null}catch{return null}}async function _B(e,t){await Ul(e),await Wl(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await Ni(e,Fv),r=c=>String(c||"").toLowerCase(),o=c=>r(c.label).startsWith(r(t.filter)),s=n?.rows.find(c=>c.active)||null;if(n&&!(s&&o(s)))for(let c=0;c<12;c++){let l=await Ni(e,Fv,{timeoutMs:1500});if(s=l?.rows.find(u=>u.active)||null,s&&o(s))break;if(!l||!l.rows.some(o)){s=null;break}await qe(e,["Down"],{kind:"model-switch"}),await Su(250)}if(!n||!s||!o(s)){await qe(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await qe(e,c,{settleMs:15,kind:"model-switch"}).catch(()=>{}),new Error(n?`cursor picker has no model matching "${t.filter}"`:"cursor model picker didn't open")}await qe(e,["Enter"],{kind:"model-switch"}),await Su(800);let a=await EB();return{verified:!!a&&(a.modelId===t.model||a.displayModelId===t.model||r(a.displayName).startsWith(r(t.filter))),model:a?.modelId||null,note:"cursor applies this as the global default for new sessions too"}}async function Kv(e,t,n){return e==="codex"?AB(t,n):e==="cursor"?_B(t,n):TB(t,n)}var Su,bB,kB,Uv,xB,vB,Hv,Wv,Gv=K(()=>{ct();ki();Su=e=>new Promise(t=>setTimeout(t,e)),bB=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,kB=300,Uv=[{alias:"default",label:"Default"},{alias:"opus",label:"Opus 5"},{alias:"sonnet",label:"Sonnet 5"},{alias:"haiku",label:"Haiku 4.5"},{alias:"fable",label:"Fable 5.1"},{alias:"opusplan",label:"Opus Plan"}],xB=new Set([...Uv.map(e=>e.alias),"best","opus[1m]","sonnet[1m]","claude-opus-5","claude-opus-4-8","claude-sonnet-5","claude-sonnet-4-6","claude-haiku-4-5","claude-fable-5","claude-fable-5-1"]),vB=[{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"}],Hv=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),Wv=[{alias:"auto",label:"Auto"},{alias:"composer-2.5",label:"Composer 2.5"},{alias:"claude-opus-5-high",label:"Opus 5"},{alias:"claude-fable-5-1-high",label:"Fable 5.1"},{alias:"claude-sonnet-5-high",label:"Sonnet 5"},{alias:"cursor-grok-4.6-high",label:"Cursor Grok 4.6"},{alias:"gpt-5.6-sol-high",label:"GPT-5.6 Sol High"},{alias:"gpt-5.3-codex",label:"Codex 5.3"}]});function Eu(e){let t=e||{},n=IB(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function IB(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{text:e.text,boxRole:e.boxRole,...e.kind?{kind:e.kind}:{},...e.attachments?.length?{attachments:e.attachments}:{},...e.deliveryId?{deliveryId:e.deliveryId}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{saidTs:e.saidTs,text:e.text,boxRole:e.boxRole}};case"orchestration-prompt":return{type:"turn.user",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{text:e.prompt,kind:e.kind,boxRole:e.boxRole,...e.deliveryId?{deliveryId:e.deliveryId}:{}}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:mt(e.toAgent),payload:{from:e.from,fromAgent:e.fromAgent,to:e.to,toAgent:e.toAgent,reason:e.reason,handoffStartedAt:e.handoffStartedAt,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,singleBox:e.singleBox,forced:e.forced,recovered:e.recovered,checkpoint:e.checkpoint}};case"lead-handoff-failed":return{type:"handoff.failed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:mt(e.toAgent),payload:{box:e.box,fromAgent:e.fromAgent,toAgent:e.toAgent,reason:e.reason,error:e.error,rolledBack:e.rolledBack,handoffStartedAt:e.handoffStartedAt}};case"subtask-delegated":return{type:"subtask.delegated",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:mt(e.toAgent),payload:{task:e.task,subtaskId:e.subtaskId,reason:e.reason}};case"subtask-merged":return{type:"subtask.merged",actor:"orchestrator",source:"orchestrator",boxId:e.box||e.from,provider:mt(e.agent),payload:{...Kr(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:mt(e.agent||e.toAgent),payload:{kind:"subtask-failed",...Kr(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{change:"subtask-resumed",...Kr(e)}};case"model-change":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"model",model:e.to,from:e.from??null,verified:e.verified??null}};case"codex-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:"codex",payload:{change:"cli-update",from:e.from??null,to:e.to??null,status:e.status,...e.error?{error:e.error}:{}}};case"node-update":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",payload:{change:"node-update",...Kr(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...Kr(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...Kr(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{change:"rehydrated",...e.fresh?{fresh:!0}:{}}};case"lead-refreshed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{change:"lead-refreshed",box:e.box,agent:e.agent,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,reason:e.reason}};case"transferred-in":return{type:e.mode==="recover"?"track.recovered":"track.transferred",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{...Kr(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...Kr(e)}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:mt(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};default:return null}}function Jv(e,t){let n=Eu(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;_u(()=>M(r,n))}async function Yv(e){if(!(!e?.id||zv.has(e.id))){zv.add(e.id);try{let t=await q(e),n=new Set(t.filter(r=>r.source==="orchestrator").map(r=>`${r.type}|${r.payload?.ts??"?"}`));for(let r of e.events||[]){let o=Eu(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await M(e,o)}}catch{}}}function Kr(e){let{type:t,at:n,...r}=e;return r}function Xv(e,t,n){!n?.promptId||Au.get(e.id)===n.promptId||(Au.set(e.id,n.promptId),_u(()=>M(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:mt(n.provider||t?.agent),payload:{promptId:n.promptId,question:n.question||n.title||null,options:(n.options||[]).map(r=>r?.label??r).slice(0,12)}})))}function Zv(e,t,n,r={}){Au.delete(e.id),_u(()=>M(e,{type:"prompt.dismissed",actor:"user",source:"orchestrator",boxId:t?.name,provider:mt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}function Hm(e,t,n,r={}){Au.delete(e.id),_u(()=>M(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:mt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var mt,Tu,_u,Vv,zv,Au,Wm=K(()=>{pe();mt=e=>e||null;Tu=Promise.resolve(),_u=e=>(Tu=Tu.then(e).catch(()=>{}),Tu),Vv=()=>Tu;zv=new Set;Au=new Map});function CB(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function oS(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of CB(n).reverse()){if(!$B.test(r))continue;let o=r.endsWith("?")&&r.length<=MB&&OB.test(r);if(RB.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function aS(e){let t=String(e||""),n=[];NB.test(t)&&n.push("commit"),sS.test(t)&&n.push("rebase"),PB.test(t)&&n.push("push");let r=BB.test(t);!r&&DB.test(t)&&n.push("pr");let o=null;if(r){let s=t.match(/(?:pr|pull\s+request)\s*\(?\s*#(\d+)\)?/i)||t.match(/#(\d+)/);o={number:s?Number(s[1]):null}}return{offered:n.length?n:null,toPr:o}}function iS(e){return sS.test(String(e||""))}function Js(e,{branch:t=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1}={}){Array.isArray(e)||(e=e==="push"?["commit","push"]:["commit","push","pr"]);let a=new Set(e),i=Array.isArray(o)&&o.length>0,c=i?o.map(f=>`${f.name}/`).join(", "):null,l=t?` on this branch (${t})`:"",u=[];if(a.has("commit")&&u.push(i?`commit the work in each changed checkout (${c})${l} with a clear commit message per repo`:`commit the work${l} with a clear commit message`),a.has("rebase")){let f=a.has("commit")?"the branch":`this branch${t?` (${t})`:""}`;u.push(i?`rebase ${f} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${f} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`)}if(a.has("push")||a.has("pr")){let f=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",w=a.has("rebase")?" with `--force-with-lease` (the rebase rewrote history)":"";i?u.push(a.has("commit")||a.has("rebase")?`push each one to its remote${w}${f}`:`push this branch${t?` (${t})`:""} from each changed checkout (${c}) to its remote${f}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${w}${f}`:`push this branch${l} to the remote${f}`)}a.has("pr")&&u.push(i?"open a pull request in each changed repo with a concise title and a description of what changed and why (run `gh pr create` inside each checkout)":`open a pull request${n?` against ${n}`:""} with a concise title and a description of what changed and why (use \`gh pr create\`)`);let d=[];a.has("commit")||d.push("don't create any new commits \u2014 ship what's already committed"),s&&!a.has("rebase")&&d.push("don't rebase \u2014 leave the branch's history as it is"),!a.has("push")&&!a.has("pr")&&d.push("don't push"),a.has("pr")||d.push("don't open a pull request");let p=`Yes \u2014 go ahead: ${u.join(", then ")}.`;return d.length&&(p+=` ${d.join(", and ").replace(/^./,f=>f.toUpperCase())}.`),a.has("pr")&&(p+=i?" If a repo's PR for this branch is already open, just push that repo's update instead.":" If a PR for this branch is already open, just push the update instead."),p}function cS(e,{branch:t=null,base:n=null,prNumber:r=null,offeredRebase:o=!1}={}){let s=new Set(Array.isArray(e)?e:["commit","push","pr"]),a=t?` on this branch (${t})`:"",i=[];s.has("commit")&&i.push(`commit the work${a} with a clear commit message`),s.has("rebase")&&i.push(`rebase ${s.has("commit")?"the branch":`this branch${t?` (${t})`:""}`} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`),i.push("move the work to a fresh branch (branch off the current HEAD with a clear new name)"),i.push("push the new branch to the remote"),i.push(`open a pull request${n?` against ${n}`:""} from the new branch with a concise title and a description of what changed and why (use \`gh pr create\`)`);let c=[];s.has("commit")||c.push("don't create any new commits \u2014 ship what's already committed"),o&&!s.has("rebase")&&c.push("don't rebase \u2014 leave the branch's history as it is");let l=`Yes \u2014 go ahead, as a NEW pull request: ${i.join(", then ")}.`;return c.length&&(l+=` ${c.join(", and ").replace(/^./,u=>u.toUpperCase())}.`),l+=` Leave the existing open PR${r?` #${r}`:""}${t?` and its remote branch (${t})`:" and its remote branch"} exactly as they are \u2014 don't push ${t||"the old branch"} itself.`,l}function lS(e,t=Date.now()){let n=[],r=null;for(let o of e||[]){let s=o.payload||{},a=s.ts??o.ts;if(o.type==="pr.offer.answered"&&s.action==="pr"){r={box:o.boxId,from:a,lastActivity:a};continue}if(o.type==="pr.exists.answered"&&s.choice==="new"){r={box:o.boxId,from:a,lastActivity:a};continue}!r||a==null||a<r.from||(o.type==="pr.offer.answered"||o.type==="pr.exists.answered"?r=null:o.type==="pr.state.changed"&&s.change==="opened"?(n.push({box:r.box,from:r.from,to:a,settled:!0}),r=null):o.type==="turn.user"&&o.source!=="hook"&&!s.kind&&String(s.text||"").trim()?r=null:o.boxId===r.box&&/^(?:turn|tool)\./.test(o.type)&&(r.lastActivity=Math.max(r.lastActivity,a)))}return r&&t-r.lastActivity<=jB&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function uS(e,t){let n=new Set;for(let r of t||[]){if(!r.settled)continue;let o=null;for(let s of e||[])s.kind!=="message"||s.role!=="assistant"||s.box!==r.box||s.ts==null||s.ts<r.from||s.ts>r.to+LB||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function dS(e){let t=(Array.isArray(e)?e:[]).filter(r=>Qv[r]).map(r=>Qv[r]);return`The ship you were given the go-ahead for${t.length?` (${t.join(", then ")})`:""} should now be complete. This is an automated ship notification the operator armed on the offer: carry straight on with this Track's follow-up work (dependent tasks, cleanup, next steps) \u2014 don't wait for review or merge. If a ship step failed or is unfinished, finish the ship first. If nothing needs doing, say so briefly.`}var eS,tS,nS,rS,$B,RB,OB,MB,Gr,NB,sS,PB,DB,BB,jB,LB,Qv,Do=K(()=>{eS=/(?<!\b(?:a|an|the|this|that|another|one|each|any|no|separate|single|new|initial|final|first|second|third|last|later|next|subsequent|extra|additional|amend(?:ed)?|squash|merge|follow[\s-]?up|clean[\s-]?up)\s)commit(?!s\b)(?!\s+(?:history|log|message|hash|sha)s?\b)/.source,tS=/(?<!\b(?:a|an|the|this|that|another|one|each|any|no|separate|single|new|initial|final|first|second|third|last|later|next|subsequent|extra|additional)\s)push(?!\s+notifications?\b)(?:\s+(?:it|this|that|them|everything|the\s+\w+))?\s*(?:up)?/.source,nS=/open(?:\s+up)?\s+(?:a|the|that)\s+(?:draft\s+)?(?:pr|pull\s+request)|creat(?:e|ing)\s+(?:a|the)\s+(?:draft\s+)?(?:pr|pull\s+request)|rais(?:e|ing)\s+(?:a|the)\s+(?:pr|pull\s+request)|put\s+up\s+(?:a|the)\s+(?:pr|pull\s+request)|send\s+(?:up\s+)?(?:a|the)\s+(?:pr|pull\s+request)/.source,rS=/(?<!\b(?:a|an|the|this|that|another|one|each|any|no|clean|interactive)\s)rebase(?!s\b)(?:\s+(?:it|this|that|them|(?:this|that|the)\s+branch))?(?:\s+(?:on(?:to)?|against|atop|over)\s+\S+)?/.source,$B=new RegExp(`\\b(?:${eS}|${tS}|${nS}|${rS})\\b`,"i"),RB=/\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,OB=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,MB=90;Gr=["commit","rebase","push","pr"],NB=new RegExp(`\\b(?:${eS})\\b`,"i"),sS=new RegExp(`\\b(?:${rS})\\b`,"i"),PB=new RegExp(`\\b(?:${tS})\\b`,"i"),DB=new RegExp(`\\b(?:${nS})\\b`,"i"),BB=/\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;jB=3e4;LB=2500;Qv={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import FB from"node:crypto";import Iu from"node:fs/promises";import pS from"node:path";import UB from"node:os";async function Ke(){return zr||(qm??=Iu.readFile(Gm,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(zr=e,!t&&He()){let{records:n,source:r}=await st("prlinks").catch(()=>({records:[],source:"error"}));if(r==="plane"){for(let o of n){if(o.deletedAt||!o.data?.repo||o.data?.number==null)continue;let{id:s,updatedAt:a,...i}=o.data;zr[ce(i.repo,i.number)]=i}Object.keys(zr).length&&await zm().catch(()=>{})}}return zr}).finally(()=>qm=null),qm)}async function zm(){let e=JSON.stringify({links:zr},null,2),t=`${Gm}.${process.pid}.tmp`;await Iu.mkdir(fS,{recursive:!0}),await Iu.writeFile(t,e),await Iu.rename(t,Gm)}async function Qe(e){Km=Km.then(zm,zm),await Km.catch(()=>{});let t=zr?.[e];t&&bt("prlinks",{id:mS(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function Ct({repo:e,number:t,trackId:n,url:r=null,headRef:o=null,title:s=null,source:a="matched"}){if(!e||!Number.isInteger(Number(t))||!n)return{link:null,created:!1};let i=await Ke(),c=ce(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:HB.has(a),firstSeen:Date.now()},await Qe(ce(e,t)),{link:i[c],created:!0})}async function tr(e,t){if(!e||t==null)return null;let n=(await Ke())[ce(e,t)];return!n||n.announced?null:(n.announced=!0,await Qe(ce(e,t)),n)}async function hS(e,t){if(!e||t==null)return!1;let n=(await Ke())[ce(e,t)];return n?.notifyOnMerge?(delete n.notifyOnMerge,await Qe(ce(e,t)),!0):!1}async function at(e,t){return!e||t==null?null:(await Ke())[ce(e,t)]??null}async function Vr(e,t,n){if(!e||t==null)return null;let r=(await Ke())[ce(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(ce(e,t)),r):null}async function wS(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ke())[ce(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await Qe(ce(e,t)),o):null}async function gS(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ke())[ce(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await Qe(ce(e,t)),o):null}async function $u(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ke())[ce(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await Qe(ce(e,t)),r)}async function Ru(e,t){if(!e||t==null)return null;let n=(await Ke())[ce(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await Qe(ce(e,t)),n)}async function Ou(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ke())[ce(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await Qe(ce(e,t)),r)}async function Mu(e,t){if(!e||t==null)return null;let n=(await Ke())[ce(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await Qe(ce(e,t)),n)}async function yS(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await Ke())[ce(e,t)];return r?(r.baseFoldAt=n,await Qe(ce(e,t)),r):null}async function bS(e,t){if(!e||t==null)return null;let n=(await Ke())[ce(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await Qe(ce(e,t)),n)}async function kS(e,t,n){if(!e||t==null||!n)return null;let r=(await Ke())[ce(e,t)];return r?(r.lastHeadSha=n,await Qe(ce(e,t)),r):null}async function xS(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await Ke())[ce(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(ce(e,t))),{prev:o,link:r}}async function Pi(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await Ke())[ce(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await Qe(ce(e,t)),r):null}async function Bo(e,t,n=!0){if(!e||t==null)return null;let r=(await Ke())[ce(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await Qe(ce(e,t)),r):null}async function jo(e,t,n=!0){if(!e||t==null)return null;let r=(await Ke())[ce(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await Qe(ce(e,t)),r):null}async function vS(e,t,n){if(!e||t==null)return null;let r=(await Ke())[ce(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(ce(e,t)),r}async function SS(e,t,n){if(!e||t==null)return null;let r=(await Ke())[ce(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(ce(e,t)),r}async function Di(e,t){if(!e||t==null)return null;let n=(await Ke())[ce(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(ce(e,t)),n)}async function TS(){return Object.values(await Ke()).filter(e=>!WB.has(e.state))}async function un(){return Object.values(await Ke()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function AS(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Ke(),r=0;for(let[o,s]of Object.entries(n))await bt("prlinks",{id:mS(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var fS,Gm,ce,mS,zr,qm,Km,HB,WB,Rn=K(()=>{Ir();fS=process.env.BOSTRAT_STATE_DIR||pS.join(process.env.HOME||UB.tmpdir(),".bostrat"),Gm=pS.join(fS,"pr-links.json"),ce=(e,t)=>`${e}#${Number(t)}`,mS=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=FB.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},zr=null,qm=null,Km=Promise.resolve();HB=new Set(["api","observed","reconciled"]);WB=new Set(["merged","closed","lost"])});import qB from"node:fs";import Vm from"node:fs/promises";import $S from"node:path";import KB from"node:os";function MS(e,t=!1){if(!t&&e-_S<GB)return;_S=e;let n=JSON.stringify({windowStart:Ys,byCaller:Object.fromEntries(nr),lastHour:Jr});IS=IS.then(()=>Vm.mkdir(RS,{recursive:!0})).then(()=>Vm.writeFile(`${Cu}.tmp`,n)).then(()=>Vm.rename(`${Cu}.tmp`,Cu)).catch(()=>{})}function CS(e){e-Ys<OS||(Jr={start:Ys,total:Nu(nr),byCaller:Object.fromEntries(nr)},Jr.total&&console.log(`[github] ${Jr.total} calls last hour`,Jr.byCaller),Ys=e,nr=new Map,MS(e,!0))}function rr(e="other",t=Date.now()){CS(t),nr.set(e,(nr.get(e)||0)+1),MS(t)}function NS(e=Date.now()){return CS(e),{windowStart:Ys,total:Nu(nr),byCaller:Object.fromEntries(nr),lastHour:Jr,backoffUntil:Lo>e?Lo:null}}function Yr(e){return zB.test(String(e?.message||e||""))}function Xr(e,t=Date.now()){return Lo<=t&&console.warn(`[github] rate limited \u2014 backing off ${ES/6e4} min:`,String(e?.message||e||"").slice(0,200)),Lo=Math.max(Lo,t+ES),Lo}function Pu(e=Date.now()){return Math.max(0,Lo-e)}var RS,Cu,OS,ES,GB,Ys,nr,Jr,Lo,_S,Nu,IS,zB,Bi=K(()=>{RS=process.env.BOSTRAT_STATE_DIR||$S.join(process.env.HOME||KB.tmpdir(),".bostrat"),Cu=$S.join(RS,"github-metrics.json"),OS=60*6e4,ES=5*6e4,GB=6e4,Ys=Date.now(),nr=new Map,Jr=null,Lo=0,_S=0,Nu=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(qB.readFileSync(Cu,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<OS?(Ys=e.windowStart,nr=new Map(Object.entries(e.byCaller||{})),Jr=e.lastHour||null):Nu(new Map(Object.entries(e.byCaller||{})))&&(Jr={start:e.windowStart,total:Nu(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}IS=Promise.resolve();zB=/rate limit|too quickly|abuse detection|HTTP 429/i});import PS from"node:fs/promises";import DS from"node:path";import VB from"node:os";function Bu({change:e,repo:t=null,number:n=null,githubAt:r=null,observedAt:o=Date.now(),lane:s=null,intervalMs:a=null,source:i=null}){let c=r?o-r:null,l={change:e,repo:t,number:n,githubAt:r,observedAt:o,latencyMs:c,lane:s,intervalMs:a,source:i};Du.push(l),Du.length>YB&&Du.shift();let u=Jm.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)),Jm.set(e,u),XB(l),l}async function XB(e){try{await PS.mkdir(BS,{recursive:!0}),await PS.appendFile(JB,JSON.stringify(e)+`
182
- `)}catch{}}function jS(){let e={};for(let[t,n]of Jm)e[t]={count:n.count,measured:n.measured,avgMs:n.measured?Math.round(n.totalMs/n.measured):null,maxMs:n.measured?n.maxMs:null};return{byChange:e,recent:Du.slice(-20)}}var BS,JB,YB,Du,Jm,ju=K(()=>{BS=process.env.BOSTRAT_STATE_DIR||DS.join(process.env.HOME||VB.tmpdir(),".bostrat"),JB=DS.join(BS,"github-latency.ndjson"),YB=100,Du=[],Jm=new Map});import{execFile as ZB}from"node:child_process";import{promisify as QB}from"node:util";async function ej(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([Zs("git",["-C",e,"rev-parse","HEAD"]),Zs("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await M({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function zt(e,t,n={}){let{caller:r="prs",...o}=n,s=await vn({cwd:e});rr(r);try{let{stdout:a}=await Zs("gh",t,{cwd:e,...tj,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw Yr(a)&&Xr(a),a}}async function Zm(){if(Lu&&Date.now()-Lu.at<6e4)return Lu.data;let e;try{rr("auth");let t=await Zs("gh",["auth","status"],{timeout:1e4});e={installed:!0,authenticated:!0,login:`${t.stdout||""}${t.stderr||""}`.match(/account\s+(\S+)/)?.[1]??null}}catch(t){e=t?.code==="ENOENT"||t?.code===127?{installed:!1,authenticated:!1,login:null}:{installed:!0,authenticated:!1,login:null}}if(e.installed&&!e.authenticated)try{let t=await za();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return Lu={at:Date.now(),data:e},e}async function nj(e){try{let{stdout:t}=await Zs("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function FS(e){let t=e.name||e.context||"check",n=e.detailsUrl||e.targetUrl||null,r=e.completedAt||e.createdAt||null,o;return e.__typename==="StatusContext"?o=e.state==="SUCCESS"?"pass":e.state==="PENDING"||e.state==="EXPECTED"?"pending":"fail":e.status&&e.status!=="COMPLETED"?o="pending":["SUCCESS","NEUTRAL","SKIPPED"].includes(e.conclusion)?o="pass":o="fail",{name:t,state:o,url:n,completedAt:r}}function Ym(e){let t=(e||[]).map(FS),n=t.filter(s=>s.state==="pending").length,r=t.map(s=>Date.parse(s.completedAt||"")).filter(s=>s>0),o=t.length&&!n&&r.length?Math.max(...r):null;return{total:t.length,passed:t.filter(s=>s.state==="pass").length,failed:t.filter(s=>s.state==="fail").length,pending:n,failing:t.filter(s=>s.state==="fail").map(({name:s,url:a})=>({name:s,url:a})),settledAt:o}}function eh(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function HS(e,t){if(!t)return null;let n=await _e(e);if(!n)return null;try{let r=await zt(e,["api",`repos/${n}/actions/runs?head_sha=${encodeURIComponent(t)}&per_page=100`,"--jq",".workflow_runs"]),o=new Map;for(let s of JSON.parse(r||"[]"))o.has(s.name)||o.set(s.name,s);return[...o.values()]}catch{return null}}function WS(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 qS(e,t){let n=await HS(e,t);return n===null?{...Ym([]),unavailable:!0}:Ym(WS(n))}function Fu(e,t=Ym(e.statusCheckRollup)){return{number:e.number,title:e.title,url:e.url,author:e.author?.login??null,headRefName:e.headRefName,headSha:e.headRefOid??null,baseRefName:e.baseRefName,isDraft:!!e.isDraft,reviewDecision:e.reviewDecision||null,mergeable:e.mergeable||"UNKNOWN",mergeStateStatus:e.mergeStateStatus||"UNKNOWN",state:e.state??null,mergedAt:e.mergedAt??null,closedAt:e.closedAt??null,additions:e.additions??0,deletions:e.deletions??0,createdAt:e.createdAt,updatedAt:e.updatedAt,checks:t,green:t.failed===0&&t.pending===0&&e.mergeStateStatus==="CLEAN",autoMergeArmed:!!e.autoMergeRequest,mergeabilityPending:!1}}function oj(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){Xs.delete(s);continue}r.add(s),Xs.has(s)||Xs.set(s,n),o.mergeabilityPending=n-Xs.get(s)<rj}for(let o of Xs.keys())o.startsWith(`${e}#`)&&!r.has(o)&&Xs.delete(o);return t}async function Qs(e,t){let n=await or(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await zt(n.path,["pr","view",String(r),"--json",Qm]);return Fu(JSON.parse(o))}catch(o){if(!eh(o))throw o;let s=await zt(n.path,["pr","view",String(r),"--json",US]),a=JSON.parse(s);return Fu(a,await qS(n.path,a.headRefOid))}}async function On(e,{caller:t="prs"}={}){try{let n=await zt(e,["pr","list","--json",Qm,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>Fu(r)).sort(LS)}catch(n){if(!eh(n))throw n;let r=await zt(e,["pr","list","--json",US,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>Fu(o,await qS(e,o.headRefOid))))).sort(LS)}}function Vt(){ji.clear()}async function ij(e,t){if(!e)return t;for(let n of t){let r=await at(e,n.number).catch(()=>null);if(!r)continue;r.trackId&&(n.trackId=r.trackId),r.autoMerge&&(n.autoMergeArmed=!0),r.archiveOnMerge&&(n.archiveOnMerge=!0),r.notifyOnMerge&&(n.notifyOnMerge=!0);let o=s=>n.headSha&&s.headSha&&n.headSha!==s.headSha;r.ciFix&&(o(r.ciFix)?await $u(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await Ou(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function KS(){let e=await Zm();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await Jn())await nj(a.path)&&t.push(a);let n=Date.now(),r=Pu(n)>0,o=await Promise.all(t.map(async a=>{let i=ji.get(a.path),c=i?.pending?aj:sj;if(i&&(r||n-i.at<c))return i.entry;try{let l=await _e(a.path).catch(()=>null),u=oj(a.path,await On(a.path,{caller:"tab"}),n);if(await ij(l,u),i?.entry?.prs)for(let f of u)i.entry.prs.find(m=>m.number===f.number)?.checks?.pending>0&&f.checks.total>0&&f.checks.pending===0&&Bu({change:f.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:f.number,githubAt:f.checks.settledAt,source:"tab"});let d={name:a.name,path:a.path,prs:u},p=u.some(f=>f.mergeabilityPending||f.checks.pending>0||f.autoMergeArmed);return ji.set(a.path,{at:Date.now(),entry:d,pending:p}),d}catch(l){return i?i.entry:{name:a.name,path:a.path,prs:[],error:Mn(l)}}})),s=new Set(t.map(a=>a.path));for(let a of ji.keys())s.has(a)||ji.delete(a);return{auth:e,repos:o}}async function or(e){let t=(await Jn()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function Fo(e){return ws(e)}async function ea(e,t,{method:n="squash"}={}){let r=await or(e);if(!Li.has(n))throw new Error(`invalid merge method: ${n}`);let o=Number(t);if(!Number.isInteger(o)||o<=0)throw new Error("invalid PR number");let s=["pr","merge",String(o),`--${n}`];if(n!=="rebase"&&(await vn({cwd:r.path})).GH_TOKEN){let a=await Wp().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await zt(r.path,s)}catch(a){throw new Error(Mn(a))}finally{Vt()}return{ok:!0,number:o}}async function Fi(e,t){let n=await or(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await zt(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(Mn(s))}finally{Vt()}let o=await _e(n.path).catch(()=>null);return o&&await yS(o,r).catch(()=>{}),{ok:!0,number:r}}async function th(e,t){let n=await or(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await zt(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(Mn(o))}finally{Vt()}return{ok:!0,number:r}}function nh(e){return e.green&&!e.isDraft}function dj(e){return e.isDraft?"draft":e.mergeable==="CONFLICTING"?`conflicts with ${e.baseRefName}`:e.checks.failed>0?"checks failing":e.checks.pending>0?"checks running":e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN"?"mergeability unresolved":e.mergeStateStatus==="BEHIND"?`behind ${e.baseRefName}`:e.mergeStateStatus==="BLOCKED"?"blocked by branch protection":`not clean (${e.mergeStateStatus})`}function GS(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:nh(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function zS(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function Ui(e,t){let n=a=>a?.firstSeen!=null&&Number.isFinite(Number(a.firstSeen))?Number(a.firstSeen):Number.MAX_SAFE_INTEGER,r=n(e),o=n(t);if(r!==o)return r-o;let s=String(e?.repo||"").localeCompare(String(t?.repo||""));return s||Number(e?.number||0)-Number(t?.number||0)}function VS(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(Ui))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function JS(){let e={};for(let[t,n]of Xm)e[t]={...n};return e}async function YS(e,{method:t="merge",onMerged:n=null}={}){let r=await or(e);if(!Li.has(t))throw new Error(`invalid merge method: ${t}`);if(Xm.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await On(r.path)).filter(nh).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 Xm.set(r.path,s),fj(s,o,{listPrs:()=>On(r.path),merge:a=>ea(r.path,a,{method:t}),sleep:uj,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function pj(e,t){let n=Date.now()+(t.settleMaxMs??lj),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(cj)}}async function fj(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 pj(t.slice(o).map(i=>i.number),n)}catch(i){for(let c of t.slice(o))e.failed.push({number:c.number,title:c.title,reason:`couldn't re-check PR state: ${Mn(i)}`});break}let a=r.find(i=>i.number===s.number);if(!a){e.skipped.push({number:s.number,title:s.title,reason:"no longer open"});continue}if(!nh(a)){e.skipped.push({number:a.number,title:a.title,reason:dj(a)});continue}try{await n.merge(a.number),e.merged.push({number:a.number,title:a.title});try{await n.onMerged?.(a)}catch{}}catch(i){e.failed.push({number:a.number,title:a.title,reason:Mn(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),Vt()}}async function rh(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await Zs("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${Mn(l)}`)}await ej(e);let o=n||"";if((await vn({cwd:e})).GH_TOKEN){let l=await Wp().catch(()=>null);l&&(o=`${o?`${o}
183
-
184
- `:""}Opened by bostrat on behalf of @${l}`)}let s=["pr","create","--title",t.trim(),"--body",o];r&&s.push("--base",r);let a;try{a=await zt(e,s)}catch(l){throw new Error(Mn(l))}finally{Vt()}let i=a.match(/https:\/\/\S+\/pull\/\d+/)?.[0]??null,c=i?Number(i.match(/\/pull\/(\d+)/)?.[1]):null;return{ok:!0,url:i,number:c}}async function XS(e,t){let n=await or(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await zt(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(Mn(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!eh(i))throw i;let c=await zt(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await HS(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(Mn(i));o=WS(l).map(FS).filter(u=>u.state==="fail").map(u=>({name:u.name,link:u.url}))}let s=new Set,a=[];for(let i of o){let c=mj(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await zt(n.path,["run","view",c,"--log-failed"]).then(u=>hj(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function mj(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function hj(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
153
+ `});function l1(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 Ox(e,t,n){let r=Mh(n),o=e.has(r)?r:null;if(!o&&n.number!=null)for(let[i,c]of e){if(Number(c.number)!==Number(n.number))continue;let l=!!(n.url&&c.url&&n.url===c.url),u=!c.repo&&!!n.repo||!!c.repo&&!n.repo;if(l||u&&(!c.url||!n.url||c.url===n.url)){o=i;break}}let s=n.repo||!o?r:o,a=o?e.get(o):e.get(s);if(o&&o!==s){e.delete(o);let i=t.get(o);if(t.delete(o),i?.length){let c=t.get(s)??[];t.set(s,c.concat(i))}}return e.set(s,{number:n.number,url:n.url??a?.url??null,title:n.title??a?.title??null,repo:n.repo??a?.repo??null,branch:n.branch??a?.branch??null}),s}function $n(e){let t=[],n=new Set,r=new Set,o=new Map,s=new Map,a=new Set,i=new Map,c=new Map,l=new Set,u=new Map,d=new Map,p=(k,m)=>{d.set(k,m),t.push(m)},f=k=>{let m=d.get(k);m&&(m.retired=!0)},w=/^Agent "([\s\S]+)" finished$/,h=new Map;for(let k of e||[]){if(k.type!=="tool.called"||k.source!=="transcript")continue;let m=String(k.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(m))for(let v of m.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let P=v[0].split("/").pop().toLowerCase();h.has(P)||h.set(P,[]),h.get(P).push(k.payload?.ts??k.ts)}}let g=3*6e4,y=20*6e4,x=(k,m)=>!!(k?.name&&h.get(String(k.name).toLowerCase()))?.some(P=>P>=m-g&&P<=m+y);for(let k of e||[])if(k.type==="turn.retracted"){r.add(`${k.boxId}|${k.payload?.saidTs}`);let m=Le(k.payload?.text);m&&(o.has(k.boxId)||o.set(k.boxId,[]),o.get(k.boxId).push(m))}else if(k.type==="turn.user"&&k.source==="orchestrator"){let m=Le(k.payload?.text);m&&(s.has(k.boxId)||s.set(k.boxId,new Set),s.get(k.boxId).add(m))}else if(k.type==="job.stalled"&&k.payload?.id)i.set(k.payload.id,{ts:me(k),quietMs:Number(k.payload.quietMs)||null});else if(k.type==="job.started"&&k.payload?.id)a.add(k.payload.id),(k.payload.kind||"agent")==="agent"&&k.payload.name&&l.add(k.payload.name);else if(k.type==="turn.user"&&k.payload?.note?.kind==="task"){let m=k.payload.note,v={status:m.status||null,summary:m.summary||null,resultHead:m.resultHead??null,ts:me(k)};m.toolUseId&&c.set(m.toolUseId,v);let P=String(m.summary||"").match(w);P&&u.set(P[1],v)}let b=new Map,I=new Map,_=null,N=new Map,U=new Map,j=new Map,T=new Map,R=new Map,L=new Map,V=new Map,O=new Map,S=new Map,M=new Map,H=new Map,W=new Map,te=new Map,pe=new Map,Ie=new Map,Oe=[],re=k=>Oe.push(k),Ne=k=>{if(!Oe.length)return;let m=me(k);for(let v of Oe){if(v.status!=="open"||v.box&&v.box!==k.boxId||(v.ts??0)>m)continue;let P=t.indexOf(v);P>=0&&t.splice(P,1),v.ts=m,t.push(v)}},X=new Map,G=new Map,fe=new Map,be=new Map,xe=new Map,Ke=new Map,le=new Map,$=new Map,Y=()=>{for(let k of $.values())k.questions.length&&t.push(k);$.clear()},Ce=null,Ve=new Map,xt=6e4,Er=new Map,_t=(k,m)=>{let v=o.get(k);if(!v?.length)return!1;let P=Le(m),ae=s.get(k);return v.some(ge=>{if(!P.startsWith(ge))return!1;let Me=Le(P.slice(ge.length));return!!Me&&!!ae?.has(Me)})};for(let k of e||[]){let m=k.payload||{};switch(k.type){case"turn.user":{if(k.source==="hook"||(Oe.length=0,!String(m.text||"").trim()&&!m.images?.length&&!m.attachments?.length))break;{let v=Sx(m.text);if(v){if(v.kind==="shell-input"){let P={id:k.id,kind:"shell",command:v.command,stdout:null,stderr:null,done:!1,ts:me(k),box:k.boxId,agent:k.provider};t.push(P),Ve.set(k.boxId,P)}else{let P=Ve.get(k.boxId);P?(P.stdout=v.stdout||null,P.stderr=v.stderr||null,P.done=!0,Ve.delete(k.boxId)):t.push({id:k.id,kind:"shell",command:null,stdout:v.stdout||null,stderr:v.stderr||null,done:!0,ts:me(k),box:k.boxId,agent:k.provider})}break}}{let v=m.note||Gi(m.text);if(v){if(v.kind==="task"){if(v.toolUseId&&a.has(v.toolUseId))break;let P=String(v.summary||"").match(w);if(!v.toolUseId&&P&&l.has(P[1]))break}if(v.kind==="command"&&xx(v.command))break;if(v.kind==="resume-summary"){t.push({id:k.id,kind:"resume-summary",title:v.title||"Context resumed from summary",bullets:v.bullets||[],sections:v.sections||[],rawChars:v.rawChars??null,ts:me(k),box:k.boxId,agent:k.provider});break}v.kind!=="suppress"&&t.push({id:k.id,kind:"event",type:Tx(v),name:v.name??null,command:v.command??null,summary:v.summary??null,status:v.status??null,ts:me(k),box:k.boxId,agent:k.provider});break}}if(r.has(`${k.boxId}|${me(k)}`)||k.source==="transcript"&&_t(k.boxId,m.text))break;if(m.kind==="merge-notify"||m.kind==="ship-notify"){t.push({id:k.id,kind:"event",type:m.kind==="ship-notify"?"ship-notified":"merge-notified",text:m.text,ts:me(k),box:k.boxId,agent:k.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"&&(Ce=null);break}for(let v of N.values())v.status="stale";N.clear();for(let v of j.values())v.status="stale";j.clear();for(let v of te.values())v.status="stale";te.clear(),Ce&&Ce.box===k.boxId&&(t.push(l1(Ce)),Ce=null),t.push({id:k.id,kind:"message",role:"user",text:m.text,ts:me(k),box:k.boxId,agent:k.provider,boxRole:m.boxRole,...k.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 v=m.from||{};t.push({id:k.id,kind:"event",type:"peer-message",text:m.text,from:v.trackName||v.boxId||v.name||null,fromTrackId:v.trackId||null,ts:me(k),box:k.boxId,agent:k.provider});break}case"turn.agent":{if(m.model==="<synthetic>"&&/^No response requested\.$/.test(String(m.text||"").trim()))break;let v=N0(m,{codexFailedText:Lo});if(v){t.push({id:k.id,kind:"event",type:"provider-error",cls:v.cls,status:v.status??void 0,text:v.text,provider:k.provider,legacy:!0,at:me(k),ts:me(k),box:k.boxId,agent:k.provider});break}Y();let P=(m.images||[]).filter(Qe=>!x(Qe,me(k)));if(!String(m.text||"").trim()&&!P.length)break;if(k.provider==="cursor"){let Qe=`${k.boxId}|${m.text}`;if(n.has(Qe))break;n.add(Qe)}(!Ce||Ce.box===k.boxId)&&(Ce=null);let ae=k.provider==="codex"?(m.tools||[]).filter(Qe=>!ih.has(Qe)&&!Ci.has(Qe)):m.tools||[],ge=m.text,Me=null,ht=Ih(String(m.text||""));ht&&(ge=ht.text,Me={questions:ht.questions}),t.push({id:k.id,kind:"message",role:"assistant",text:ge,ts:me(k),box:k.boxId,agent:k.provider,boxRole:m.boxRole,...Me?{ask:Me}:{},...ae.length?{tools:ae}:{},...m.model?{model:m.model}:{},...m.sourceId?{sourceId:m.sourceId}:{},...P.length?{images:P}:{}}),Ne(k),Me&&(Ce={id:k.id,groupId:$h(k.provider,m.sourceId||k.id,Me.questions),provider:k.provider,box:k.boxId,questions:Me.questions,ts:me(k)});break}case"job.started":{if(!m.id)break;let v=me(k),P=c.get(m.id);if(!P&&(m.kind||"agent")==="agent"&&m.name){let st=u.get(m.name);st&&st.ts>=v&&(P=st)}let ae=P?null:i.get(m.id)||null,ge={jobId:m.id,jobKind:m.kind||"agent",name:m.name||null,detail:m.detail||null,status:P?P.status==="killed"?"stopped":P.status&&P.status!=="completed"?"failed":"done":ae?"stalled":"running",startedTs:v,finishedTs:P?.ts??ae?.ts??null,quietMs:ae?.quietMs??null,summary:P?.summary??null,resultHead:P?.resultHead??null},Me=Er.get(k.boxId),ht=Me?.jobs[Me.jobs.length-1]?.startedTs;if(Me&&ht!=null&&v-ht<=xt)Me.jobs.push(ge);else{let st={id:k.id,kind:"job-dock",dockId:m.id,ts:v,box:k.boxId,agent:k.provider,jobs:[ge]};Er.set(k.boxId,st),t.push(st)}break}case"handoff.done":t.push(dt(k,"lead-handoff"));break;case"subtask.delegated":t.push({...dt(k,"subtask-delegated"),to:k.boxId,toAgent:k.provider});break;case"subtask.merged":t.push(dt(k,"subtask-merged"));break;case"pr.state.changed":{if(!m.change)break;if(m.change==="opened"){for(let P of N.values())P.status="stale";N.clear();for(let P of j.values())P.status="stale";j.clear()}let v=dt(k,`pr-${m.change}`);if(v.box=k.boxId??null,Rx.has(m.change)&&m.number!=null){let P=Ox(b,I,m);if(b.size>=2){for(let ge of I.values())for(let Me of ge)Me.grouped=!0;v.groupPrs=[...b.values()];let ae=[v];for(let ge of b.keys())I.set(ge,ae)}else{let ae=I.get(P)??[];ae.push(v),I.set(P,ae)}}else if(m.change==="merged"||m.change==="closed"||m.change==="lost"){let P=Mh(m),ae=_&&!_.complete||b.size>=2;if(b.has(P))b.delete(P),I.delete(P);else if(m.number!=null)for(let ge of[...b.keys()])ge.endsWith(`#${m.number}`)&&(b.delete(ge),I.delete(ge));if(ae&&m.number!=null){(!_||_.complete)&&(_={id:k.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:me(k),ts:me(k),box:k.boxId,agent:k.provider},t.push(_)),_.prs.push({number:m.number,url:m.url??null,title:m.title??null,repo:m.repo??null,branch:m.branch??null,change:m.change,ts:me(k)}),_.remaining=[...b.values()],_.complete=b.size===0;break}}t.push(v);break}case"pr.offered":{if(!m.offerId)break;for(let P of N.values())P.status="stale";N.clear();for(let P of j.values())P.status="stale";j.clear();let v={id:k.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:k.source==="cli"||m.via==="cli"?"cli":"transcript",ts:me(k),box:k.boxId,agent:k.provider};N.set(m.offerId,v),U.set(m.offerId,v),t.push(v),v.source==="cli"&&re(v);break}case"pr.offer.answered":{let v=U.get(m.offerId);v&&(v.status=m.action||"dismiss",v.actions=Array.isArray(m.actions)?m.actions:null,v.notify=m.notify===!0,m.existingPr&&typeof m.existingPr=="object"&&(v.existingPr={number:m.existingPr.number??null}),N.delete(m.offerId));break}case"pr.exists.offered":{if(!m.offerId)break;for(let P of j.values())P.status="stale";j.clear();let v={id:k.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:me(k),box:k.boxId,agent:k.provider};j.set(m.offerId,v),T.set(m.offerId,v),t.push(v);break}case"pr.exists.answered":{let v=T.get(m.offerId);v&&(v.status=m.choice||"dismiss",j.delete(m.offerId));break}case"box.state.changed":{let v=m.change==="model"?"model-change":m.change;if(!v)break;let P=dt(k,v);if(v==="model-change"&&(P.to=m.model),v==="node-update"&&P.latest){let ae=t.findIndex(ge=>ge.kind==="event"&&ge.type==="node-update"&&ge.latest===P.latest);if(ae>=0){let ge=t[ae];t[ae]={...P,ts:ge.ts,at:ge.at,firstAt:ge.firstAt??ge.ts,updatedAt:P.ts};break}}t.push(P);break}case"track.transferred":case"track.recovered":t.push(dt(k,"track-moved"));break;case"view.state.changed":{if(m.change==="deleted"){f(`view:${m.viewId}`);break}if(m.change!=="created"||m.restarted)break;p(`view:${m.viewId}`,{id:k.id,kind:"view-card",viewId:m.viewId,name:m.name,slug:m.slug,port:m.port,origin:m.origin,ts:me(k),box:k.boxId,agent:k.provider});break}case"view.spinup.failed":{t.push({id:k.id,kind:"view-spinup-failed",name:m.name||null,reason:m.reason||"no-view",ts:me(k),box:k.boxId,agent:k.provider});break}case"mock.state.changed":{if(m.change==="picked"){t.push({id:k.id,kind:"mock-picked",mockId:m.mockId,name:m.name,group:m.group??null,version:m.version??null,siblings:m.siblings??[],ts:me(k),box:k.boxId,agent:k.provider});break}if(m.change==="deleted"){f(`mock:${m.mockId}`);break}if(m.change!=="created")break;p(`mock:${m.mockId}`,{id:k.id,kind:"mock-card",mockId:m.mockId,name:m.name,group:m.group??null,ts:me(k),box:k.boxId,agent:k.provider});break}case"flow.state.changed":{if(m.change==="deleted"){f(`flow:${m.flowId}`);break}if(m.change!=="created")break;p(`flow:${m.flowId}`,{id:k.id,kind:"flow-card",flowId:m.flowId,name:m.name,stepCount:m.stepCount??null,mockIds:m.mockIds??[],ts:me(k),box:k.boxId,agent:k.provider});break}case"runbook.state.changed":{if(m.change==="deleted"){f(`runbook:${m.runbookId}`);break}if(m.change!=="created")break;p(`runbook:${m.runbookId}`,{id:k.id,kind:"runbook-card",runbookId:m.runbookId,name:m.name,ts:me(k),box:k.boxId,agent:k.provider});break}case"ticket.linked":{t.push({id:k.id,kind:"ticket-card",provider:m.provider||"linear",key:m.key,url:m.url,title:m.title??null,linkSource:m.linkSource??null,ts:me(k),box:k.boxId,agent:k.provider});break}case"box.fullscreen.detected":{if(!m.offerId)break;for(let P of V.values())P.box===(m.box||k.boxId)&&(P.status="stale",V.delete(P.offerId));let v={id:k.id,kind:"fullscreen-offer",offerId:m.offerId,status:"open",ts:me(k),box:m.box||k.boxId,agent:m.agent||k.provider};V.set(m.offerId,v),O.set(m.offerId,v),t.push(v);break}case"box.fullscreen.answered":{let v=O.get(m.offerId);v&&(v.status=m.action==="restarted"?"restarted":m.action==="cleared"?"cleared":"dismiss",V.delete(m.offerId));break}case"ticket.move.offered":{if(!m.offerId)break;for(let P of R.values())P.key===m.key&&(P.status="stale",R.delete(P.offerId));let v={id:k.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:me(k),box:k.boxId,agent:k.provider};R.set(m.offerId,v),L.set(m.offerId,v),t.push(v);break}case"ticket.move.answered":{let v=L.get(m.offerId);v&&(v.status=m.action==="moved"?"moved":"dismiss",R.delete(m.offerId));break}case"ticket.state.changed":{for(let v of R.values())v.key===m.key&&v.to===m.to&&(v.status="stale",R.delete(v.offerId));if(m.mode==="offer")break;t.push(dt(k,"ticket-state"));break}case"ticket.commented":{t.push({id:k.id,kind:"ticket-comment",key:m.key,url:m.url??null,excerpt:m.excerpt??null,ts:me(k),box:k.boxId,agent:k.provider});break}case"ticket.flow.changed":t.push(dt(k,"ticket-flow"));break;case"ticket.create.offered":{if(!m.proposalId)break;for(let P of S.values())P.status="stale";S.clear();let v={id:k.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:me(k),box:k.boxId,agent:k.provider};S.set(m.proposalId,v),M.set(m.proposalId,v),t.push(v),re(v);break}case"ticket.create.answered":{let v=M.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",v.createdCount=m.createdCount??null,v.failedCount=m.failedCount??null,S.delete(m.proposalId));break}case"loop.create.offered":{if(!m.proposalId)break;for(let P of H.values())P.status="stale";H.clear();let v={id:k.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:me(k),box:k.boxId,agent:k.provider};H.set(m.proposalId,v),W.set(m.proposalId,v),t.push(v),re(v);break}case"loop.create.answered":{let v=W.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",H.delete(m.proposalId));break}case"followup.armed":{if(!m.armId)break;let v=m.replaces?Ie.get(m.replaces):null;v&&v.status==="armed"&&(v.status="replaced");let P={id:k.id,kind:"followup-armed",armId:m.armId,trigger:m.trigger??"now",label:m.label??"",prompt:m.prompt??"",why:m.why??null,status:"armed",ts:me(k),box:k.boxId,agent:k.provider};Ie.set(m.armId,P),P.trigger!=="now"&&t.push(P);break}case"followup.armed.cancelled":{let v=Ie.get(m.armId);v&&v.status==="armed"&&(v.status="cancelled");break}case"followup.offered":{if(!m.offerId)break;for(let ae of te.values())ae.trigger===m.trigger&&(ae.status="stale",te.delete(ae.offerId));let v=Array.isArray(m.rows)?m.rows:[];for(let ae of v){let ge=ae.armId?Ie.get(ae.armId):null;ge&&ge.status==="armed"&&(ge.status="offered")}let P={id:k.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:v.map(ae=>({followupId:ae.followupId??null,armId:ae.armId??null,label:ae.label??"",prompt:ae.prompt??null,promptPreview:ae.promptPreview??null,promptHash:ae.promptHash??null,origin:ae.origin??"operator",why:ae.why??null})),status:"open",answer:null,ts:me(k),box:k.boxId,agent:k.provider};te.set(m.offerId,P),pe.set(m.offerId,P),t.push(P),P.trigger==="now"&&re(P);break}case"followup.answered":{let v=pe.get(m.offerId);v&&(v.status=m.action==="sent"?"sent":m.action==="removed"?"removed":"dismiss",v.answer={followupId:m.followupId??null,armId:m.armId??null,label:m.label??null,promoted:m.promoted??null,revived:m.revived===!0},te.delete(m.offerId));break}case"followup.create.offered":{if(!m.proposalId)break;for(let P of X.values())P.status="stale";X.clear();let v={id:k.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:me(k),box:k.boxId,agent:k.provider};X.set(m.proposalId,v),G.set(m.proposalId,v),t.push(v),re(v);break}case"followup.create.answered":{let v=G.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",X.delete(m.proposalId));break}case"followup.created":{let v=m.proposalId?G.get(m.proposalId):null;v&&(v.created={followupId:m.followupId??null});break}case"loop.created":{let v=m.proposalId?W.get(m.proposalId):null;v&&(v.created={loopId:m.loopId??null,nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),t.push(dt(k,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!m.proposalId||!m.loopId)break;for(let ae of fe.values())ae.loopId===m.loopId&&(ae.status="stale",ae.staleReason="superseded",fe.delete(ae.proposalId));let v=k.type==="loop.update.offered",P={id:k.id,kind:v?"loop-update-offer":"loop-delete-offer",proposalId:m.proposalId,loopId:String(m.loopId),name:m.name??m.base?.name??"",base:m.base??null,...v?{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:me(k),box:k.boxId,agent:k.provider};fe.set(m.proposalId,P),be.set(m.proposalId,P),t.push(P),re(P);break}case"loop.update.answered":{let v=be.get(m.proposalId);v&&(m.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=m.action==="applied"?"applied":"dismiss",fe.delete(m.proposalId));break}case"loop.delete.answered":{let v=be.get(m.proposalId);v&&(m.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=m.action==="delete"?"deleted":m.action==="pause"?"paused":"keep",fe.delete(m.proposalId));break}case"loop.updated":{let v=m.proposalId?be.get(m.proposalId):null;v&&(v.applied={changed:Array.isArray(m.changed)?m.changed:[],nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),t.push(dt(k,"loop-updated"));break}case"loop.deleted":t.push(dt(k,"loop-deleted"));break;case"loop.paused":t.push(dt(k,"loop-paused"));break;case"planning.change.offered":{if(!m.proposalId||!Array.isArray(m.ops)||!m.ops.length)break;for(let P of xe.values())P.status="stale",P.staleReason="superseded",xe.delete(P.proposalId);let v={id:k.id,kind:"planning-offer",proposalId:m.proposalId,why:m.why??"",ops:m.ops,base:m.base??{},resolved:m.resolved??{},snapped:!!m.snapped,createsMeRow:!!m.createsMeRow,status:"open",staleReason:null,applied:null,ts:me(k),box:k.boxId,agent:k.provider};xe.set(m.proposalId,v),Ke.set(m.proposalId,v),t.push(v),re(v);break}case"planning.change.answered":{let v=Ke.get(m.proposalId);v&&(m.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=m.action==="applied"?"applied":"dismiss",xe.delete(m.proposalId));break}case"planning.changed":{let v=m.proposalId?Ke.get(m.proposalId):null;v&&(v.applied={results:Array.isArray(m.results)?m.results:[]}),t.push(dt(k,"planning-changed"));break}case"rework.cause.offered":{if(!m.sha||le.has(m.sha))break;let v={id:k.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,intent:m.intent??null,shas:Array.isArray(m.shas)?m.shas:null,pr:m.pr??null,retracts:0,status:"open",cause:null,ts:me(k),box:k.boxId,agent:k.provider};le.set(m.sha,v),t.push(v);break}case"rework.cause.answered":{let v=m.sha?le.get(m.sha):null;v&&(v.status="answered",v.cause=m.cause??null);break}case"rework.cause.retracted":{let v=m.sha?le.get(m.sha):null;v&&(v.status="open",v.cause=null,v.retracts=(v.retracts??0)+1);break}case"ticket.created":{let v={items:Array.isArray(m.items)?m.items:[],failed:Array.isArray(m.failed)?m.failed:[],team:m.team??null},P=m.proposalId?M.get(m.proposalId):null;if(P){P.created=v;break}t.push({id:k.id,kind:"ticket-created",...v,ts:me(k),box:k.boxId,agent:k.provider});break}case"error":{if(!m.kind)break;t.push(dt(k,m.kind));break}case"provider.error":t.push({...dt(k,"provider-error"),provider:k.provider,box:k.boxId,agent:k.provider});break;case"usage.cap.hit":t.push(dt(k,"usage-cap-hit"));break;case"usage.cap.warning":t.push(dt(k,"usage-cap-warning"));break;case"provider.connected":{t.push({id:k.id,kind:"event",type:"provider-connected",provider:m.provider||k.provider,ts:me(k),at:me(k),box:k.boxId,agent:k.provider});break}case"prompt.answered":{if(Ce=null,m.control||!m.question)break;let v=m.groupId||m.promptId;if(!v)break;let P=$.get(v);P||(P={id:k.id,kind:"prompt",groupId:v,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:m.questionTotal??1,questions:[],ts:me(k)},$.set(v,P));let ae=m.questionIndex??0,ge={index:ae,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:Array.isArray(m.chosen)?m.chosen:[]},Me=P.questions.findIndex(Qe=>Qe.index===ae&&Le(Qe.question)===Le(ge.question));Me>=0?P.questions[Me]=ge:P.questions.push(ge),P.questions.sort((Qe,st)=>Qe.index-st.index),P.questionTotal=Math.max(P.questionTotal,m.questionTotal??1),P.questions.length>=P.questionTotal&&(t.push(P),$.delete(v));break}case"prompt.dismissed":{Ce=null;let v=m.groupId||m.promptId;if(!v||!m.question)break;let ae=$.get(v)||{id:k.id,kind:"prompt",groupId:v,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:m.questionTotal??1,questions:[],ts:me(k)},ge=m.questionIndex??0;ae.questions.some(Me=>Me.index===ge&&Le(Me.question)===Le(m.question))||(ae.questions.push({index:ge,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:[]}),ae.questions.sort((Me,ht)=>Me.index-ht.index)),ae.answeredVia="chat",t.push(ae),$.delete(v);break}default:break}}let _r=d.size?t.filter(k=>!k.retired):t;return d1(_r.sort((k,m)=>(k.ts??0)-(m.ts??0)))}function d1(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<=u1){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 Ch(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:p1(s),ts:s.ts??o.ts,n:s.n,box:o.boxId,agent:o.provider,boxRole:s.boxRole})}if(!n.length)return[];let r=(t??$n(e)).filter(o=>o.kind==="message");return E0(n,r)}function p1(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==Vs(e.command)?t:Lr(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:me(e),ts:me(e)}}function Mx(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)+f1,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&h1.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function Cx(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!w1.has(r.type)||!r.box)continue;let o=(r.ts??0)+m1,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 Tu(e){return(e||[]).filter(t=>g1.has(t?.kind)&&t.status==="open")}function Nx(e){let t=new Map,n=new Map;for(let r of e||[]){if(r.type!=="pr.state.changed")continue;let o=r.payload||{};if(Rx.has(o.change)&&o.number!=null)Ox(t,n,o);else if(o.change==="merged"||o.change==="closed"||o.change==="lost"){let s=Mh(o);if(t.has(s))t.delete(s);else if(o.number!=null)for(let a of[...t.keys()])a.endsWith(`#${o.number}`)&&t.delete(a)}}return[...t.values()]}var me,Rx,Mh,u1,f1,h1,m1,w1,g1,Eu=q(()=>{Js();Fo();pu();Fi();Au();Oh();me=e=>e.payload?.ts??e.ts;Rx=new Set(["opened","ci-fixed","reconciled","pushed"]),Mh=e=>`${e.repo??""}#${e.number}`;u1=2*6e4;f1=12e4,h1=new Set(["archived","unarchived","opened"]);m1=2500,w1=new Set(["pr-opened","pr-merged","pr-auto-armed"]);g1=new Set(["pr-offer","pr-exists-offer","ticket-offer","ticket-create-offer","loop-create-offer","loop-update-offer","loop-delete-offer","planning-offer","fullscreen-offer","followup-create-offer"])});function v1(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 A1(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 T1(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<k1&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<x1&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function jx(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=v1(e),s=A1(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=$n(e??[]).filter(p=>p?.kind==="message"&&typeof p.text=="string"&&p.text.trim()).slice(-y1);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(Bx[r]??Bx.failover),l.push(""),o.lastPush?.sha){let p=Dx(n,o.lastPush.ts),f=p?` (~${p} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${f}`+(o.lastPush.wip?" \u2014 a bostrat WIP snapshot (full working tree incl. uncommitted edits at push time).":"."))}else r==="in-place"?l.push("**Code state:** no push recorded \u2014 the working tree in this workspace is the only copy; commit early."):l.push("**Code state:** no push was ever recorded for this Track \u2014 work since the branch's last known state stayed on the offline node.");if(l.push(""),a){let p=Dx(n,i);l.push(`## Last real checkpoint (written by the previous agent${p?`, ~${p} min before this reconstruction`:""})`),l.push(""),l.push(a.trim()),l.push("")}let u=T1(e??[],i);if((u.files.length||u.heads.length)&&(l.push(`## Work since ${a?"that checkpoint":"the start of the log"} (from the event log)`),l.push(""),u.files.length&&l.push(`Files touched (most recent first): ${u.files.map(p=>`\`${p}\``).join(", ")}`),u.heads.length&&(u.files.length&&l.push(""),l.push(`Commands run (most recent first): ${u.heads.map(p=>`\`${p}\``).join(" \xB7 ")}`)),l.push("")),c.length){l.push(`## Recent conversation (last ${c.length} message${c.length===1?"":"s"})`),l.push("");for(let p of c)l.push(`**${p.role==="user"?"operator":"agent"}:** ${S1(p.text,b1)}`),l.push("")}l.push("---"),l.push("Resume: continue the objective above from the verified repository state; ask the operator before redoing anything the log says was already done.");let d=l.join(`
154
+ `);return d.length<=Px?d:`${d.slice(0,Px)}
155
+
156
+ [\u2026 brief truncated]`}var y1,b1,Px,k1,x1,S1,Dx,Bx,Lx=q(()=>{Eu();y1=12,b1=2e3,Px=48e3,k1=30,x1=10;S1=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},Dx=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;Bx={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 E1 from"node:fs";import Ur from"node:fs/promises";import Hr from"node:path";function zx(e){let t=No(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=Fx?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,Fx).toString("utf8").replace(/�+$/,"")}
157
+
158
+ [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function P1(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(Hx.test(s)){if(r.length>=Qx)continue;let a=N1(s.replace(Hx,"").replace(/[.;,:]+$/,""),ev,M1);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>Ux&&(o=`${o.slice(0,Ux-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function tv(e,t,{timeoutMs:n=9e4}={}){let r=Hr.join(t,R1),o=Hr.join(r,O1);await Ur.mkdir(r,{recursive:!0});let s=await _u(o),a=await ye(e);if(!a)throw new Error(`session "${e}" not found`);return await Iu(e,a,C1(o)),await cv(o,s,n),P1(await Ur.readFile(o,"utf8"))}function nv(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===Jx||n===Zx;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(Vx)||n===_1||r.startsWith(Yx)||r.startsWith(Xx)}function rv(e){let t=[];for(let r of e?.events||[]){if(r.type!=="lead-handoff"||!r.from)continue;let o=r.at??Date.now(),s=r.handoffStartedAt??o-D1;t.push({box:r.from,from:s,to:o}),r.to&&r.to!==r.from&&t.push({box:r.to,from:s,to:o})}let n=e?.handoff;return n?.fromBox&&n.startedAt&&n.finishedAt&&t.push({box:n.fromBox,from:n.startedAt,to:n.finishedAt}),n?.toBox&&n.startedAt&&n.finishedAt&&t.push({box:n.toBox,from:n.startedAt,to:n.finishedAt}),t}function ov(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 sv(e,{windows:t=[]}={}){if(nv(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 $u(e){return Nh.get(e)||null}async function av(e){let t=Nh.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await ye(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);let r={name:e,step:"summarize",startedAt:Date.now(),finishedAt:null,error:null,file:Hr.join(n.cwd,Kx,Gx)};return Nh.set(e,r),L1(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function L1(e,t){e.step="summarize",await iv(e.name,t),e.step="clear";let n=await ye(e.name);await Iu(e.name,n,"/clear"),await Ph(B1),e.step="resume",await Iu(e.name,n,$1),e.step="done",e.finishedAt=Date.now()}async function iv(e,t,{timeoutMs:n=j1}={}){let r=Hr.join(t,Kx),o=Hr.join(r,Gx);await Ur.mkdir(r,{recursive:!0});let s=await _u(o),a=await ye(e);await ue({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:o,beforeMtime:s}),await Iu(e,a,I1(o)),await cv(o,s,n),await ue({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:o,afterMtime:await _u(o)});let i=await fx(t,o,{exclude:u=>nv(u.role,u.text)});await ue({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:o,...i});let c=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(c){await C({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 Ur.readFile(o,"utf8");await C({id:c,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...zx(u),ts:Date.now()}})}catch{}}await Pf(t);let l=await F1(r,o);return c&&await Gk(c,l||o,{box:e,agent:a?.agent??null}),o}async function Ru(e,{timeoutMs:t}={}){let n=await ye(e);if(!n)throw new Error(`session "${e}" not found`);if(!n.cwd)throw new Error(`can't resolve cwd for "${e}"`);return iv(e,n.cwd,t?{timeoutMs:t}:void 0)}async function Ou(e,t,{trackName:n="this Track"}={}){let r=await K({id:e,cwd:t}),o=jx(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=Hr.join(t,Wx);return await Ur.mkdir(Hr.dirname(s),{recursive:!0}),await Ur.writeFile(s,o,"utf8"),await C({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...zx(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),Wx}async function _u(e){try{return(await Ur.stat(e)).mtimeMs}catch{return 0}}async function cv(e,t,n){let r=Date.now()+n;for(;;){if(await _u(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await Ph(2e3)}}async function F1(e,t){try{if(!E1.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=Hr.join(e,`${n}.md`);return await Ur.copyFile(t,r),r}catch{return null}}function Ph(e){return new Promise(t=>setTimeout(t,e))}function qx(e){return e==="claude"?process.env.BOSTRAT_AGENT_CMD||"claude":e==="cursor"?process.env.BOSTRAT_CURSOR_CMD||"cursor-agent":e==="codex"?process.env.BOSTRAT_CODEX_CMD||"codex":""}async function Iu(e,t,n){if(t){let o=qx(t.agent);await er({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await ye(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await We(e,["Escape"],{kind:"drive-wipe"}),await Ph(150),await qs(e,lu,{kind:"drive-wipe"}),await ot(e,n,{kind:"orchestration-drive",...In(r.agent,n)}),await Hi({sessionName:e,agent:r.agent,agentCmd:qx(r.agent),text:n,flow:"orchestration-drive"})}var Kx,Gx,Fx,Vx,Jx,Yx,_1,I1,$1,Xx,Zx,R1,O1,Ux,Qx,ev,M1,C1,Hx,N1,D1,B1,j1,Nh,Wx,Dh=q(()=>{ut();Bi();Tn();ji();vh();hx();wi();he();eu();Lx();Kx=".bostrat/handoff",Gx="latest.md",Fx=32*1024;Vx="Checkpoint: write a work-in-progress handoff",Jx="HANDOFF WRITTEN",Yx="Resume from .bostrat/handoff/latest.md",_1="/clear",I1=e=>`${Vx} 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 ${Jx} and take no further action.`,$1=`${Yx}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,Xx="Beat: write a",Zx="BEAT WRITTEN",R1=".bostrat/arc",O1="beat.txt",Ux=200,Qx=4,ev=5,M1=36,C1=e=>`${Xx} 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 ${Qx} further lines, each starting with "- " and naming ONE piece in at most ${ev} 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 ${Zx} and take no further action.`,Hx=/^(?:[-–—*•·]|\d+[.)])\s+/,N1=(e,t,n)=>{let r=e.split(/\s+/).filter(Boolean).slice(0,t).join(" ");return r.length>n?`${r.slice(0,n-1).trimEnd()}\u2026`:r};D1=6e5;B1=3500,j1=3e5,Nh=new Map;Wx=".bostrat/handoff/status-latest.md"});function qr(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!Mu.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 dv(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:qr(o.from,"from",n),toMs:qr(o.to,"to",n)}))}return t}function jh(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 H1(e){if(!e)return null;let t=String(e).trim();return Wr[t]?t:lv[t]?lv[t]:Object.keys(Wr).find(r=>t.startsWith(r))||null}function W1(e){if(!e||e===Wr)return U1;let t=uv.get(e);return t||(t=dv(e),uv.set(e,t)),t}function pv(e,t,n={}){let{table:r,speed:o}=n,s=W1(r),a=r&&r!==Wr?s[e]?e:null:H1(e);if(!a)return null;let i=jh(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 Rn(e,t={},n,r){let o=pv(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 q1(e=Wr){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:qr(a.from,"from",n),toMs:qr(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`),Mu.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 G1({now:e=Date.now(),table:t=Wr,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...K1,...n},a=[],i=jh(e);if(i===null)return[`pricingFreshness: unparseable now ${JSON.stringify(e)}`];for(let[c,l]of Object.entries(t)){if(!Array.isArray(l))continue;let u;try{u=l.map(d=>({...d,fromMs:qr(d.from,"from",c),toMs:qr(d.to,"to",c),verifiedMs:Mu.test(String(d.verifiedAt??""))?Date.parse(`${d.verifiedAt}T00:00:00.000Z`):NaN}))}catch(d){a.push(String(d.message));continue}for(let d of u){if(!Number.isFinite(d.verifiedMs)){a.push(`${c}: window ${d.from??"\u2026"} \u2192 ${d.to??"now"} has no verifiedAt`);continue}let p=i>=d.fromMs&&i<=d.toMs,f=d.fromMs>i&&d.fromMs-i<=o*Bh;p&&i-d.verifiedMs>r*Bh&&a.push(`${c}: current rate last verified ${d.verifiedAt} (>${r}d) \u2014 re-check the vendor page and bump verifiedAt`),f&&d.fromMs-d.verifiedMs>s*Bh&&a.push(`${c}: scheduled rate change on ${d.from} was last verified ${d.verifiedAt} \u2014 confirm it is still happening (vendors cancel; sonnet-5 did) and bump verifiedAt`)}}return a}function ea({now:e=Date.now(),table:t=Wr,...n}={}){let r=jh(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=qr(l.from,"from",i),d=qr(l.to,"to",i);r>=u&&r<=d&&Mu.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=[...q1(t),...G1({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var Wr,lv,Mu,U1,uv,fv,K1,Bh,nr=q(()=>{Wr={"claude-opus-5":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"GA rates; verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-opus-4-8":[{from:null,to:null,input:5,output:25,cacheWrite:10,cacheRead:.5,fast:{input:10,output:50,cacheWrite:20,cacheRead:1},verifiedAt:"2026-08-20",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); fast-mode variant added 2026-08-20."}],"claude-sonnet-5":[{from:null,to:null,input:2,output:10,cacheWrite:4,cacheRead:.2,verifiedAt:"2026-08-17",note:"$2/$10 is the standard price (intro pricing made permanent; the 2026-09-01 $3/$15 increase was cancelled) \u2014 verified 2026-08-17 against platform.claude.com/docs/en/about-claude/pricing."}],"claude-sonnet-4-6":[{from:null,to:null,input:3,output:15,cacheWrite:6,cacheRead:.3,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-haiku-4-5":[{from:null,to:null,input:1,output:5,cacheWrite:2,cacheRead:.1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page)."}],"claude-fable-5":[{from:null,to:null,input:10,output:50,cacheWrite:20,cacheRead:1,verifiedAt:"2026-08-17",note:"verified 2026-08-06 (claude-api skill), re-verified 2026-08-17 (live pricing page); 83% of fleet spend."}],"gpt-5.5":[{from:null,to:null,input:5,output:30,cacheWrite:5,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-03, re-verified 2026-08-17 (developers.openai.com pricing); no cache-write premium on 5.5-and-earlier."}],"gpt-5.6-sol":[{from:null,to:"2026-08-23",input:5,output:30,cacheWrite:6.25,cacheRead:.5,verifiedAt:"2026-08-17",note:"verified 2026-07-18, re-verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL). Superseded 2026-08-24 by the vendor's promotional cut (window below)."},{from:"2026-08-24",to:null,input:4,output:20,cacheWrite:5,cacheRead:.4,verifiedAt:"2026-08-24",note:"promotional pricing verified 2026-08-24 (developers.openai.com pricing), 'at least through November 21, 2026'; cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-terra":[{from:null,to:"2026-08-16",input:2.5,output:15,cacheWrite:3.125,cacheRead:.25,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:2,output:12,cacheWrite:2.5,cacheRead:.2,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}],"gpt-5.6-luna":[{from:null,to:"2026-08-16",input:1,output:6,cacheWrite:1.25,cacheRead:.1,verifiedAt:"2026-07-18",note:"as verified 2026-07-18; superseded by the 2026-08-17 sweep (0 corpus rows in this window)."},{from:"2026-08-17",to:null,input:.2,output:1.2,cacheWrite:.25,cacheRead:.02,verifiedAt:"2026-08-17",note:"verified 2026-08-17 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input (30-min TTL)."}]},lv={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"},Mu=/^\d{4}-\d{2}-\d{2}$/;U1=dv(Wr);uv=new WeakMap;fv=(e,t,n)=>pv(e,t,n)!==null;K1=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),Bh=864e5});function z1(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function mv(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function Jt(e){let t=e.payload?.model||"unknown",n=z1(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=Rn(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&&!fv(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function Kr(e,{boxLabels:t={}}={}){let n=(e||[]).filter(p=>p.type==="cost.recorded"),r={},o={},s={},a=0,i=0,c=0,l=0,u=new Set,d=hv();for(let p of n){let{usd:f,model:w,tokens:h,repriced:g,unpriced:y,asRecorded:x}=Jt(p);i+=x;let b=p.provider||"unknown",I=p.boxId||"unattributed";if(g&&c++,y&&(l++,u.add(w)),a+=f,mv(d,h),r[w]||={usd:0,tokens:hv(),events:0},r[w].usd+=f,r[w].events+=1,mv(r[w].tokens,h),o[b]||={usd:0,events:0},o[b].usd+=f,o[b].events+=1,s[I]||={usd:0,events:0,provider:b,models:new Set,label:t[I]||I},s[I].usd+=f,s[I].events+=1,w!=="unknown"&&s[I].models.add(w),p.epoch!=null){let _=(s[I].epochs||={})[p.epoch]||={usd:0,events:0,provider:b,models:new Set};_.usd+=f,_.events+=1,_.provider=b,w!=="unknown"&&_.models.add(w)}}return{totalUsd:ta(a),asRecordedUsd:ta(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:Cu(r,p=>({...p,usd:ta(p.usd)})),byProvider:Cu(o,p=>({...p,usd:ta(p.usd)})),byBox:Cu(s,p=>({usd:ta(p.usd),events:p.events,provider:p.provider,label:p.label,models:[...p.models],...p.epochs?{epochs:Cu(p.epochs,f=>({usd:ta(f.usd),events:f.events,provider:f.provider,models:[...f.models]}))}:{}}))}}var hv,ta,Cu,Gr=q(()=>{nr();hv=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});ta=e=>Math.round(e*1e4)/1e4,Cu=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function V1(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 wv(e,t=[]){let n=[],r=e?.events||[],o=new Map,s=0;for(let u of t){if(u.type!=="pr.state.changed")continue;let d=u.payload||{};!d.repo||d.number==null||(d.change==="merged"?o.set(`${d.repo}#${d.number}`,d):d.change==="opened"&&s++)}if(o.size){let u=[...o.keys()].map(d=>{let[p,f]=d.split("#");return`${p.split("/").pop()}#${f}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(Lh(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(Lh(a,"subtask"));let i=r.filter(u=>u.type==="lead-handoff"&&u.fromAgent&&u.toAgent);if(i.length){let u=i.slice(0,3).map(d=>`${d.fromAgent}\u2192${d.toAgent}`).join(", ");n.push(`${Lh(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=Kr(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?V1(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var Lh,gv=q(()=>{Gr();Lh=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as J1}from"node:child_process";import{promisify as Y1}from"node:util";import{randomUUID as X1}from"node:crypto";async function Fh(e,t){let n=Date.now()+t;for(;;){if(await Qn(e))return!0;if(Date.now()>n)return!1;await zi(Z1)}}async function eB(e,t){let n=yv[t]||yv.default;n.escape&&(await We(e,["Escape"],{kind:"swap-exit"}),await zi(150)),n.wipe&&await qs(e,lu,{kind:"swap-exit"}),await uu(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=In(t).submitDelayMs||0;await zi(Math.max(r,250)),await We(e,["Enter"],{kind:"swap-exit"})}async function bv(e,t){try{let{stdout:n}=await Wo(ee,ne("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function vv(e){await Wo(ee,ne("respawn-pane","-k","-t",e))}async function Uh(e,{exitTimeoutMs:t=kv,fromAgent:n=null}={}){if(!De(e))throw new Error("invalid session name");let r=!1;if(await Qn(e))return{forced:r};let o=n||(await ye(e))?.agent||"agent";if(await eB(e,o),!await Fh(e,t)&&(r=!0,await ue({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await vv(e),!await Fh(e,xv)))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);return{forced:r}}async function Hh(e,t={}){if(!De(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await ye(e);if(!r)throw new Error(`session "${e}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${e}"`);let o=r.agent||"agent",s=t.agent||Br(n),a=Number(t.exitTimeoutMs)||kv;await ue({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd});let{forced:i}=await Uh(e,{exitTimeoutMs:a,fromAgent:o}),c=s==="claude"&&Do(n),l=c?Rl():null,u=await bv(e,"ANTHROPIC_API_KEY"),d=!1;try{l?(await Wo(ee,ne("set-environment","-t",e,"ANTHROPIC_API_KEY",l)),d=!0):u&&(await Wo(ee,ne("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),d=!0)}catch(g){throw l?ru(g,l):g}if(d&&!i&&(await vv(e),!await Fh(e,xv)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let p=!!t.resumeSessionId,f=t.resumeSessionId||X1(),w=p?n:Ei(n,f,e),h=p?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(w);return c&&await $r(r.cwd),s==="codex"&&await Os(r.cwd),s==="cursor"&&await Ms(r.cwd),await Bo(e),await Wo(ee,ne("set-option","-t",e,"@bostrat-sid",f)),await Wo(ee,ne("set-option","-t",e,"@bostrat-agent",s)),await zi(Q1),c&&Ti().length&&(await bv(e,Ai)||await Wo(ee,ne("set-environment","-t",e,Ai,"1")).catch(()=>{}),await ot(e,`export ${Ai}=1`,{kind:"swap-env"}),await zi(150)),await ot(e,w,{kind:"swap-launch"}),await ue({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:f,forced:i,envRespawned:d}),{name:e,cwd:r.cwd,sessionId:f,agent:s,pinned:h,forced:i,envRespawned:d,launchCmd:w}}var Wo,zi,kv,xv,Z1,Q1,yv,Sv=q(()=>{ut();ai();Ml();Cl();ji();Tn();Wo=Y1(J1),zi=e=>new Promise(t=>setTimeout(t,e)),kv=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,xv=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,Z1=250,Q1=400,yv={claude:{escape:!0,wipe:!0,text:"/exit"},codex:{escape:!0,wipe:!0,text:"/quit"},cursor:{escape:!0,wipe:!0,text:"/quit"},default:{escape:!1,wipe:!1,text:"exit"}}});function sB(e){if(e.type==="queue-operation"&&e.operation==="enqueue")return Av.test(String(e.content||""))?String(e.content):null;if(e.type==="attachment"){let n=e.attachment;return n?.type==="queued_command"&&n.commandMode==="task-notification"&&typeof n.prompt=="string"?n.prompt:null}let t=e.message?.content;return typeof t=="string"&&Av.test(t)?t:null}async function Tv(e,t={}){return(await _v(e,t)).launches}async function Ev(e,t={}){let{launches:n,done:r}=await _v(e,t);return n.filter(o=>!r.has(o.id))}async function _v(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await Mt(e,t)}catch{return{launches:[],done:new Set}}let o=new Map,s=new Set,a=new Set,i=new Map;for(let l of r.split(`
159
+ `)){let u=l.trim();if(!u||u[0]!=="{")continue;let d;try{d=JSON.parse(u)}catch{continue}if(d.isSidechain)continue;let p=sB(d);if(p){let h=p.match(oB)?.[1]?.trim();h&&a.add(h);continue}let f=d.message?.content;if(!Array.isArray(f))continue;let w=d.timestamp?Date.parse(d.timestamp):null;for(let h of f)if(!(!h||typeof h!="object")){if(h.type==="tool_use"&&h.id){if(h.name==="Agent"){let g=h.input||{};o.set(h.id,{id:h.id,kind:"agent",name:String(g.description||"").trim()||null,detail:String(g.subagent_type||"").trim()||null,ts:w,proven:!1})}else if(h.name==="Bash"){let g=String(h.input?.command||"").trim(),y={id:h.id,kind:"command",name:String(h.input?.description||"").trim()||(g?Vs(g):null),detail:g?Vs(g):null,ts:w,proven:h.input?.run_in_background===!0};y.proven?o.set(h.id,y):i.set(h.id,y)}}else if(h.type==="tool_result"&&h.tool_use_id){let g=aB(h.content);if(tB.test(g)&&s.add(h.tool_use_id),g.match(nB)){let x=i.get(h.tool_use_id);x&&(i.delete(h.tool_use_id),x.proven=!0,x.outputFile=g.match(rB)?.[1]?.replace(/\.$/,"")||null,o.set(x.id,x))}}}}let c=[];for(let l of o.values()){if(!l.proven&&!s.has(l.id))continue;let{proven:u,...d}=l;c.push(d)}return{launches:c.slice(-n),done:a}}var tB,nB,rB,Av,oB,aB,Iv=q(()=>{ln();Js();tB=/^Async (?:agent|task) launched/i,nB=/^Command did not complete within its [^\n]*?moved to the background \(ID: ([^)]+)\)/i,rB=/Output is being written to:\s*(\S+)/i,Av=/^\s*<task-notification>/i,oB=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i;aB=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 zr(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 iB(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 $v(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:un(`read ${zr(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${na(r)}`:`Read ${na(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?zr(t.path,n):null,s=t?.glob?` --glob ${Wh(t.glob)}`:"",a=un(String(r),40);return{command:un(`grep ${Wh(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?zr(t.target_directory,n):null;return{command:un(`glob ${Wh(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${un(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:un(`edit ${zr(t.path,n)}`,140),description:`Edit ${na(t.path)}`}:null;case"Write":return t?.path?{command:un(`write ${zr(t.path,n)}`,140),description:`Write ${na(t.path)}`}:null;case"Delete":return t?.path?{command:un(`delete ${zr(t.path,n)}`,140),description:`Delete ${na(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>zr(s,n)).filter(Boolean);return{command:un(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=iB(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:un(`apply_patch ${zr(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${na(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:un(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var Nu,un,na,Wh,Rv=q(()=>{Nu=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),un=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,na=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);Wh=e=>`"${String(e).replace(/"/g,'\\"')}"`});import Vi from"node:fs";import cB from"node:fs/promises";import qo from"node:path";import lB from"node:os";import uB from"node:crypto";import dB from"node:zlib";function Cv(e){let t=uB.createHash("md5").update(String(e)).digest("hex");return qo.join(pB,t)}function Nv(e){try{let t=JSON.parse(Vi.readFileSync(qo.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 fB(e){let t=Cv(e),n;try{n=Vi.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=qo.join(t,o.name),a=qo.join(s,"store.db");if(!Vi.existsSync(a))continue;let i=Nv(s);if(!i)continue;let c={id:o.name,dir:s,store:a,...i};(!r||c.hasConversation&&!r.hasConversation||c.hasConversation===r.hasConversation&&(c.updatedAtMs||0)>(r.updatedAtMs||0))&&(r=c)}return r}function Pu(e,t){if(!e)return null;if(t){let n=qo.join(Cv(e),t),r=qo.join(n,"store.db");if(Vi.existsSync(r))return{id:t,dir:n,store:r,...Nv(n)||{createdAtMs:null,updatedAtMs:null}}}return fB(e)}function Ov(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function hB(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=dB.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function mB(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 wB(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!Nu.has(r.toolName))continue;let o=$v(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 qh(e,t){if(!Mv)return ra;let{DatabaseSync:n}=Mv,r;try{r=new n(e,{readOnly:!0})}catch{return ra}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 ra;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return ra}let a=s.lastUsedModel||null,i=s.latestRootBlobId?Ov(r,s.latestRootBlobId):null;if(!i)return{...ra,model:a};let c=[],l=[],u=[],d=null,p=[];for(let f of mB(i)){let w=hB(Ov(r,f));if(!w)continue;let h=w.providerOptions?.cursor;if(h?.requestId&&p.push(h.requestId),h?.modelProviderMessageId&&p.push(h.modelProviderMessageId),w.role!=="assistant")continue;if(Array.isArray(w.content))for(let x of w.content){let b=x?.providerOptions?.cursor?.modelName;b&&(d=b)}l.push(...wB(w.content,t).map((x,b)=>({...x,id:x.id||`${f}:${b}`}))),u.push(...yB(w.content));let g=gB(w.content);if(!g)continue;let y=[...new Set(u)];u=[],c.push({id:f,text:g,tools:y.length?y:void 0,commands:l,model:d}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:p}}catch{return ra}finally{try{r.close()}catch{}}}function Pv(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(Vi.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 Dv(e,t,{limit:n=80}={}){let r=Pu(e,t);if(!r)return[];let{turns:o,model:s}=await qh(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=Pv(r,a.length);return a.map((c,l)=>({role:"assistant",text:c.text,tools:c.tools,ts:i(l),model:c.model||s,sourceId:c.id}))}async function Bv(e,t){let n=Pu(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await qh(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 jv(e,t,{limit:n=80}={}){let r=Pu(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await qh(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=Pv(r,a.length||1),l=[];a.forEach((u,d)=>{for(let p of u.commands)l.push({...p,summary:Lr(p.command,p.description),ts:c(d)})});for(let u of s)l.push({...u,summary:Lr(u.command,u.description),ts:i+1});return l}async function Lv(e,t){let n=Pu(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await cB.stat(n.store)).mtimeMs)}catch{return null}}var pB,gB,yB,Mv,ra,Kh=q(()=>{Js();Rv();pB=process.env.BOSTRAT_CURSOR_CHATS||qo.join(lB.homedir(),".cursor","chats");gB=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
160
+ `).trim():"",yB=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],Mv=process.getBuiltinModule?.("node:sqlite"),ra={turns:[],trailingCommands:[],model:null,requestIds:[]}});import bB from"node:fs/promises";function Jh(e){return Fv.set(e.agent,e),e}function Vr(e){return Fv.get(e)||kB}async function Yh(e,t={}){return(await Vr(e.agent).readMessages(e,t)).map(Du(e))}async function Uv(e,t={}){return(await Vr(e.agent).readCommands(e,t)).map(Du(e))}async function Hv(e,t={}){return(await Vr(e.agent).readJobs(e,t)).map(Du(e))}async function Wv(e,t={}){return(await Vr(e.agent).readOpenJobs(e,t)).map(Du(e))}var oa,Gh,zh,Vh,kB,Fv,Du,Xh=q(()=>{ln();fu();Js();Iv();Kh();Fo();oa=class{constructor(t,n=new Set){this.agent=t,this.cliTools=n}async readMessages(){return[]}async readCommands(){return[]}async readJobs(){return[]}async readOpenJobs(){return[]}async updatedAt(){return null}},Gh=class extends oa{transcript(t){return!t?.cwd||!t?.sessionId?null:cn(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?lh(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?T0(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?Tv(r,n):[]}async readOpenJobs(t,n){let r=this.transcript(t);return r?Ev(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await bB.stat(n)).mtimeMs)}catch{return null}}},zh=class extends oa{async readMessages(t,n){return Dv(t.cwd,t.sessionId,n)}async readCommands(t,n){return jv(t.cwd,t.sessionId,n)}async updatedAt(t){return Lv(t.cwd,t.sessionId)}},Vh=class extends oa{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return $0(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return R0(t.cwd,this.sessionId(t),n)}async updatedAt(t){return O0(t.cwd,this.sessionId(t))}},kB=new oa("unknown"),Fv=new Map;Jh(new Gh("claude",oh));Jh(new zh("cursor",Nu));Jh(new Vh("codex",Ci));Du=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function Yr(e){let t=e.search(tm);return(t>=0?e.slice(0,t):e).trim()}function xB(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function vB(e){let t=String(e).trim();return!!(!t||Jr.test(e)||tm.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function SB(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=AB(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function AB(e,t){let n=String(t).toLowerCase(),r=e.findIndex(c=>!c.answered),o=r>=0?r:e.length-1;if(!n)return o;let s=e.map(c=>{let l=c.label.toLowerCase(),u=l.split(/\s+/).filter(p=>p.length>3&&n.includes(p)).length;if(u)return u;let d=l.slice(0,8).trim();return d.length>=4&&n.includes(d)?1:0}),a=Math.max(...s);if(a===0||s[o]===a)return o;let i=s.flatMap((c,l)=>c===a?[l]:[]);return i.length===1?i[0]:o}function qv(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function TB(e,t=""){let n=String(e);if(!Gv.test(n))return null;let r=n.replace(/\r/g,"").split(`
161
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(/^\s*Switch model\?\s*$/.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[];for(let u=o+1;u<r.length;u++){let d=r[u].match(Ko);if(d)s.push({cursor:!!d[1],label:d[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let p=r[u].trim();p&&!Jr.test(r[u])&&a.push(p)}}if(s.length<2)return null;let i=s.map(u=>({label:Yr(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 _B(e,t=""){let n=String(e).replace(/\r/g,"").split(`
162
+ `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!zv.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(Ko);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&&!(EB.test(n[c])||Jr.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:Yr(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 IB(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
163
+ `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(Ko);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 RB(e,t=""){let n=String(e);if(!Zh.test(n))return null;let r=n.replace(/\r/g,"").split(`
164
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if($B.test(r[u])){o=u;break}if(o<0)return null;let s=[],a=[r[o].trim()];for(let u=o+1;u<r.length;u++){let d=r[u].match(Ko);if(d)s.push({cursor:!!d[1],label:d[4].trim()});else if(s.length){if(r[u].trim()==="")break}else{let p=r[u].trim();p&&!Jr.test(r[u])&&a.push(p)}}if(s.length<2||!s.some(u=>Zh.test(u.label)))return null;let i=s.map(u=>({label:Yr(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 nm(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(Ko);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 OB(e,t=""){let n=String(e);if(!Vv.test(n)||!Jv.test(n)||Go.test(n))return null;let r=n.replace(/\r/g,"").split(`
165
+ `),o=nm(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:Yr(s.label),description:""}))}]}:null}function MB(e,t=""){let n=String(e);if(!Yv.test(n)||Go.test(n))return null;let r=n.replace(/\r/g,"").split(`
166
+ `),o=nm(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:Yr(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 NB(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!CB.test(o)||rm.test(e[r]))break;n+=o}return n}function PB(e,t=""){let n=String(e);if(!rm.test(n)||Go.test(n))return null;let r=n.replace(/\r/g,"").split(`
167
+ `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=NB(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 BB(e,t=""){let n=String(e);if(!Qh.test(n)||!DB.test(n)||Go.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
168
+ `)].reverse().find(a=>Qh.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 jB(e,t=""){let n=String(e);if(!Xv.test(n)||Go.test(n))return null;let r=n.replace(/\r/g,"").split(`
169
+ `),o=nm(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:Yr(s.label),description:""}))}]}:null}function LB(e,t=""){let n=String(e);if(Go.test(n))return null;let r=n.replace(/\r/g,"").split(`
170
+ `),o=-1;for(let l=r.length-1;l>=0;l--)if(r[l].trim()!==""){o=l;break}if(o<0)return null;let s=r[o].match(Zv);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(Jr.test(r[l])||tm.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 FB(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(em.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 UB(e,t){let n=e.find(s=>/^type something\b/i.test(s.label));if(n)return n;if(e.length<2)return null;let r=e[e.length-1];if(Bu.test(r.label))return null;let o=null;for(let s=r.line+1;s<Math.min(t.length,r.line+3);s++){let a=t[s].replace(/^\s*❯/,"").trim();if(a){o=a;break}}return o&&(Jr.test(o)||/^submit\b/i.test(o))?r:null}function HB(e,t=""){let n=String(e);if(!Kv.test(n)||!em.test(n))return null;let r=n.replace(/\r/g,"").split(`
171
+ `),o=FB(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let R=i;R<c;R++){let L=r[R].match(Ko);L&&(u<0&&(u=R),l.push({line:R,cursor:!!L[1],checked:L[3]!=null&&L[3]!==" ",hasCheckbox:L[3]!=null,label:L[4].trim(),desc:""}))}if(!l.length)return null;for(let R of l)for(let L=R.line+1;L<Math.min(r.length,R.line+4)&&!(Ko.test(r[L])||Jr.test(r[L]));L++){let V=r[L].trim();if(!(!V||vB(r[L])||Bu.test(V))){R.desc=xB(V);break}}let d=UB(l,r),p=l.filter(R=>R!==d&&!Bu.test(R.label));if(!p.length)return null;let f=p.some(R=>R.hasCheckbox),w=d?.cursor?p.length:Math.max(0,p.findIndex(R=>R.cursor)),h=d&&!Bu.test(d.label)?Yr(d.label):"",g=s>=0?s+1:0,y=[];for(let R=g;R<u;R++){let L=r[R].trim();L&&!Jr.test(r[R])&&!/[☐☒]/.test(r[R])&&y.push(L)}let x=y.join(" ")||(s>=0?qv(r[s]):"")||"The agent is asking a question",b=s>=0?SB(r[s],x):null,I=b?.currentTabLabel||(s>=0?qv(r[s]):""),_=p.map(R=>({label:Yr(R.label),description:R.desc})),N=_.map(R=>R.label).join("|"),j=`claude:${b?`q${b.questionIndex+1}/${b.questionTotal}`:"q1/1"}:${I}:${x}:${N}`.slice(0,240),T=b?`claude:ask:${b.tabs.map(R=>R.label).join("|")}`.slice(0,240):j;return{provider:"claude",box:t,multiSelect:f,cursorIndex:w,promptId:j,groupId:T,...d?{custom:!0,customIndex:p.length,customText:h}:{},dismissable:!0,...b?{questionIndex:b.questionIndex,questionTotal:b.questionTotal,currentTabLabel:b.currentTabLabel,tabs:b.tabs}:{},questions:[{question:x,header:I,multiSelect:f,options:_}]}}function Xr(e,t){let n=String(t||"");return n?e==="claude"?Kv.test(n)&&em.test(n)||Gv.test(n)||Zh.test(n)||zv.test(n.trimEnd().split(`
172
+ `).pop()||"")?!0:Go.test(n)?!1:Vv.test(n)&&Jv.test(n)||Yv.test(n)||rm.test(n)||Qh.test(n)||Xv.test(n)||Zv.test(n.trimEnd().split(`
173
+ `).pop()||""):e==="codex"&&/Sign in with ChatGPT|one-time code|Paste or type your API key|link to authenticate|Successfully logged in\.[\s\S]*Press Enter to continue\./i.test(n)?!0:e==="cursor"||e==="codex"?/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i.test(n):!1:!1}function On(e,t){return!e||!t?null:e.agent==="claude"?IB(t,e.name)||HB(t,e.name)||TB(t,e.name)||RB(t,e.name)||BB(t,e.name)||PB(t,e.name)||MB(t,e.name)||OB(t,e.name)||jB(t,e.name)||LB(t,e.name)||_B(t,e.name):e.agent==="cursor"||e.agent==="codex"?G0(e.agent,t,e.name):null}async function om(e){if(!e)return null;let t=await an(e.name).catch(()=>"");return On(e,t)}function sm(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 Qv(e,t,n=""){let r=typeof n=="string"?n.trim():"";if(!r||!e?.custom)return{pre:sm(e,t).map(d=>({key:d})),text:"",post:[]};let o=Array.isArray(t?.[0])?t[0].filter(d=>Number.isInteger(d)&&d>=0):[],s=Number.isInteger(e.customIndex)?e.customIndex:e.questions?.[0]?.options?.length??0,a=Number.isInteger(e.cursorIndex)?e.cursorIndex:0,i=(d,p)=>{let f=p-d;return Array.from({length:Math.abs(f)},()=>({key:f>0?"Down":"Up"}))},c=[],l=a,u=typeof e.customText=="string"?e.customText.length:0;if(u>0&&a===s&&c.push(...Array.from({length:u+2},()=>({key:"BSpace"}))),e.multiSelect){for(let d of[...o].sort((p,f)=>p-f))c.push(...i(l,d),{key:"Enter"}),l=d;return c.push(...i(l,s)),{pre:c,text:r,post:[{key:"Down"},{key:"Enter"}]}}return c.push(...i(l,s)),{pre:c,text:r,post:[{key:"Enter"}]}}function eS(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 Kv,em,Ko,Bu,Jr,tm,Gv,zv,EB,Zh,$B,Go,Vv,Jv,Yv,rm,CB,Qh,DB,Xv,Zv,am=q(()=>{ut();mu();Kv=/to navigate\b.*\bEsc to cancel|Enter to select\b/,em=/Chat about this/i,Ko=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,Bu=/^(type something|chat about this|submit)\b/i,Jr=/^[─—-]{6,}\s*$/,tm=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;Gv=/^\s*Switch model\?\s*$/m;zv=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,EB=/^\s*[─—▔-]{6,}\s*$/;Zh=/Resume from summary/i,$B=/^\s*This session is\b/;Go=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;Vv=/Choose the text style that looks best with your terminal/,Jv=/Let's get started\./;Yv=/Select login method:/;rm=/Paste code here if prompted/,CB=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;Qh=/OAuth error:/,DB=/Press Enter to retry\./;Xv=/Quick safety check: Is this a project you created or one you trust/;Zv=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function ju(e,t,n){if(!e||!t)return null;for(let r of WB)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function KB(e){let t=im.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},im.set(e,t)),t}function rS(e,t,n=Date.now()){let r=KB(e);if(r.sentAt=r.sentAt.filter(s=>n-s<nS),r.sentAt.length>=tS)return{action:"give-up"};if(n-r.last<qB)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 oS(e,t=Date.now()){let n=im.get(e);return n?n.sentAt.filter(r=>t-r<nS).length>=tS:!1}var WB,qB,tS,nS,im,cm=q(()=>{WB=[{provider:"claude",id:"fullscreen-upsell",match(e,t){let n=e?.questions?.[0],r=(n?.options||[]).map(s=>String(s.label||"").trim());if(r.length!==2||!/^Yes, try it$/.test(r[0])||!/^Not now$/.test(r[1]))return!1;let o=`${n?.question||""}
174
+ ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];qB=5e3,tS=5,nS=3600*1e3,im=new Map});function sa(e){return typeof e=="string"?e.trim():""}var sS=q(()=>{});import{execFile as GB}from"node:child_process";import{promisify as zB}from"node:util";async function ze(e,t,{input:n}={}){let r=um("git",["-C",e,...t],{maxBuffer:aS});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function aa(e){if(!e)return!1;try{let{stdout:t}=await ze(e,["rev-parse","--is-inside-work-tree"]);return t.trim()==="true"}catch{return!1}}async function iS(e){let{stdout:t}=await ze(e,["rev-parse","--show-toplevel"]);return t.trim()}async function VB(e){try{return await ze(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function ia(e,t="bostrat: subtask snapshot"){let{stdout:n}=await ze(e,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>um("git",["-C",e,...a],{maxBuffer:aS,env:o,...i});try{let a=await VB(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 um("rm",["-f",r])}catch{}}}async function dm(e,t,{trailers:n=[]}={}){let{stdout:r}=await ze(e,["status","--porcelain"]);return r.trim()?(await ze(e,["add","-A"]),await ze(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",t,...n.flatMap(o=>["--trailer",o])]),!0):!1}async function zo(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await ze(e,["status","--porcelain"]),r=n.split(`
175
+ `).filter(Boolean);return t&&(r=r.filter(o=>{let s=o.slice(3);return!(s===".bostrat"||s===".bostrat/"||s.startsWith(".bostrat/")||o.startsWith("??")&&(s==="AGENTS.md"||s==="CLAUDE.md"))})),r.length>0}async function Vo(e,t){if(!t)return 0;try{let{stdout:n}=await ze(e,["rev-list","--count",`${t}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function Jo(e,t,n,r){return await ze(e,["worktree","add","--no-track","-b",n,t,r]),t}async function pm(e,t){try{return await ze(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function Ji(e,t,n){return await ze(e,["worktree","add","--end-of-options",t,n]),t}async function Yo(e){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:t}=await ze(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 ze(e,["rev-parse","--verify","--quiet",t]),n}catch{}return"HEAD"}async function fm(e){await ze(e,["init","-q"]),await ze(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function St(e,t){try{await ze(e,["worktree","remove","--force",t])}catch{try{await ze(e,["worktree","prune"])}catch{}}}function JB(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 hm(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function mm(e,t,n,r){let{stdout:o}=await ze(e,hm(["diff","--shortstat",t,n],r));return JB(o)}async function wm(e,t,n,r){let{stdout:o}=await ze(e,hm(["diff","--name-only",t,n],r));return o.split(`
176
+ `).map(s=>s.trim()).filter(Boolean)}async function gm(e,t,n,r){let{stdout:o}=await ze(e,hm(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await lm(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await lm(e,o,["--3way","--whitespace=nowarn"]),a=await YB(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await lm(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function lm(e,t,n){try{return await ze(e,["apply",...n,"-"],{input:t}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function YB(e){try{let{stdout:t}=await ze(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
177
+ `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var um,aS,Lu=q(()=>{um=zB(GB),aS=64*1024*1024});function Fu(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!XB.has(o.state)&&o.state!=="stopped"&&(o.state="stopped",r=!0);let s=Array.isArray(o.epochs)?o.epochs:[],a=s[s.length-1];a&&typeof a=="object"&&a.endedAt==null&&(a.endedAt=t,a.endReason==null&&(a.endReason=n),r=!0)}return r}var je,XB,Yt=q(()=>{je=e=>!!(e&&(e.archivedAt||e.transferredTo)),XB=new Set(["merged","conflict","canceled","failed","handed-off"])});import ym from"node:fs/promises";import lS from"node:path";import ZB from"node:os";function fS(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function hS(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function mS(e){let t=new Date(fS(e));return t.setDate(t.getDate()+7),t.getTime()}function wS(e){let t=new Date(hS(e));return t.setMonth(t.getMonth()+1),t.getTime()}function Hu(e=Date.now()){for(let[t,n]of Object.entries(ca)){let r=n.startOf(e);if(r!==rr[t]){rr[t]=r;for(let o of Xo.values())o[t]=0;for(let o of la)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&la.delete(o)}}}function gS(e,t){let n=dn?.caps?.[e]?.[ca[t].capKey];return Number.isFinite(n)&&n>0?n:null}function Zr(e,t=Date.now()){if(!e||!km||!dn?.caps)return null;Hu(t);let n=Xo.get(e);for(let r of Object.keys(ca)){let o=gS(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:Uu(s),resetsAt:ca[r].nextStart(t)}}return null}function yS(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${rr[t.window]}`;return la.has(n)?!1:(la.add(n),!0)}function cS(e,t,n,r=Date.now()){if(!e||!t)return;Hu(r);let o=QB(e);for(let[s,a]of Object.entries(ca))n>=rr[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function ej(e,t,n=Date.now()){if(!dn?.caps||!bm)return;let r=Xo.get(e);if(r)for(let[o,s]of Object.entries(ca)){let a=gS(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*pS||i>=a)continue;let c=`warn:${e}:${o}:${rr[o]}`;if(!la.has(c)){la.add(c);try{let l=await bm(t);if(!l)continue;await C(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:Uu(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function bS(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 Wu(e,{source:t="local",updatedAt:n=Date.now()}={}){dn={caps:bS(e),updatedAt:n,source:t};try{await ym.mkdir(uS,{recursive:!0}),await ym.writeFile(dS(),JSON.stringify(dn,null,2))}catch{}return Yi()}function Yi(e=Date.now()){Hu(e);let t=new Set([...Xo.keys(),...Object.keys(dn?.caps||{})]),n={};for(let r of t){let o=Xo.get(r);n[r]={weeklyUsd:Uu(o?.weekly||0),monthlyUsd:Uu(o?.monthly||0)}}return{caps:dn?.caps||{},configured:!!dn,seeded:km,updatedAt:dn?.updatedAt??null,spent:n,windows:{weekly:{start:rr.weekly,resetsAt:mS(e)},monthly:{start:rr.monthly,resetsAt:wS(e)}},warnPct:pS}}async function kS({listTracks:e,getTrack:t}={}){bm=t||null,Hu();try{let o=JSON.parse(await ym.readFile(dS(),"utf8"));dn={caps:bS(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{dn=null}let n=Date.now();Je.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=Jt(o);cS(o.provider||"unknown",s,o.ts??Date.now()),ej(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(rr.weekly,rr.monthly);for(let o of await e?.()||[]){let s;try{s=await K(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||cS(a.provider||"unknown",Jt(a).usd,i,n)}}return km=!0,Yi()}var uS,dS,pS,ca,dn,km,rr,Xo,la,bm,QB,Uu,qu=q(()=>{he();Gr();uS=process.env.BOSTRAT_STATE_DIR||lS.join(process.env.HOME||ZB.tmpdir(),".bostrat"),dS=()=>lS.join(uS,"usage-caps.json"),pS=.8;ca={weekly:{startOf:fS,nextStart:mS,capKey:"weeklyUsd"},monthly:{startOf:hS,nextStart:wS,capKey:"monthlyUsd"}},dn=null,km=!1,rr={weekly:0,monthly:0},Xo=new Map,la=new Set,bm=null,QB=e=>{let t=Xo.get(e);return t||(t={weekly:0,monthly:0},Xo.set(e,t)),t};Uu=e=>Math.round(e*1e4)/1e4});import tj from"node:fs/promises";import nj from"node:os";import xS from"node:path";function xm(e){return e==="codex"?aj:e==="cursor"?_S:TS}function vS(e){let t=String(e||"").split(`
178
+ `),n=t.findIndex(o=>/Select Model and Effort/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+(\S+?)(?:\s+\((current|default)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),id:s[3],current:s[4]==="current",active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function SS(e){let t=String(e||"").split(`
179
+ `),n=t.findIndex(o=>/Select Reasoning Level/i.test(o));if(n<0)return null;let r=[];for(let o=n+1;o<t.length;o++){let s=t[o].match(/^\s*(›\s*)?(\d+)\.\s+([A-Za-z ]+?)(?:\s+\((default|current)\))?(?:\s{2,}|\s*$)/);if(s)r.push({n:Number(s[2]),label:s[3].trim(),isDefault:!!s[4],active:!!s[1]});else if(r.length&&/Press enter|esc to go back/i.test(t[o]))break}return r.length?r:null}function ij(e){let t=String(e||"").split(`
180
+ `);for(let n=t.length-1;n>=0;n--){let r=t[n].match(/Model changed to\s+(\S+)(?:\s+(\S+))?\s*$/i);if(r)return{model:r[1],effort:r[2]||null}}return null}function AS(e){let t=String(e||"").split(`
181
+ `),n=t.findIndex(s=>/Available models|Models matching/i.test(s));if(n<0)return null;let r=/Models matching/i.test(t[n]),o=[];for(let s=n+1;s<t.length;s++){let a=t[s];if(/^\s*Filter:/i.test(a)||!a.trim())continue;if(/to filter|Enter to select|^\s*\d+-\d+ of \d+/i.test(a))break;let i=a.match(/^\s*(→\s+)?(.+?)\s*$/);if(!i)continue;let c=i[2].replace(/\s*\(Tab to modify\)\s*$/i,""),l=null,u=c.split(/\s{2,}/);u.length>1&&(c=u[0],l=u.slice(1).join(" ").trim()||null),c&&o.push({label:c.trim(),params:l,active:!!i[1]})}return o.length?{filtered:r,rows:o}:null}function IS(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&&!ES.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=_S.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!sj.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Xi(e,t,{timeoutMs:n=rj}={}){let r=Date.now()+n;for(;;){let o=await Pe(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await Ku(oj)}}async function cj(e,t){return await ot(e,`/model ${t.model}`,In("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function lj(e,t){await cu(e),await ot(e,"/model",{enter:!1}),await Ku(250),await We(e,["Enter"],{kind:"model-switch"});let n=await Xi(e,vS);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await We(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`unknown model "${t.model}" \u2014 codex offers: ${n.map(i=>i.id).join(", ")}`);let o=i=>{let c=ij(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await ot(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await Xi(e,i=>SS(i)||!vS(i)&&o(i)&&{done:o(i)});if(!s)throw await We(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?ES.get(t.effort):null,c=i?s.find(l=>l.label.toLowerCase()===i.toLowerCase()):s.find(l=>l.isDefault)||s[0];if(!c)throw await We(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await ot(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Xi(e,i=>!SS(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 uj(){let e=xS.join(process.env.CURSOR_CONFIG_DIR||xS.join(nj.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await tj.readFile(e,"utf8"))?.model||null}catch{return null}}async function dj(e,t){await cu(e),await uu(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await Xi(e,AS),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 Xi(e,AS,{timeoutMs:1500});if(s=l?.rows.find(u=>u.active)||null,s&&o(s))break;if(!l||!l.rows.some(o)){s=null;break}await We(e,["Down"],{kind:"model-switch"}),await Ku(250)}if(!n||!s||!o(s)){await We(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await We(e,c,{settleMs:15,kind:"model-switch"}).catch(()=>{}),new Error(n?`cursor picker has no model matching "${t.filter}"`:"cursor model picker didn't open")}await We(e,["Enter"],{kind:"model-switch"}),await Ku(800);let a=await uj();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 $S(e,t,n){return e==="codex"?lj(t,n):e==="cursor"?dj(t,n):cj(t,n)}var Ku,rj,oj,TS,sj,aj,ES,_S,RS=q(()=>{ut();ji();Ku=e=>new Promise(t=>setTimeout(t,e)),rj=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,oj=300,TS=[{alias:"default",label:"Default"},{alias:"opus",label:"Opus 5"},{alias:"sonnet",label:"Sonnet 5"},{alias:"haiku",label:"Haiku 4.5"},{alias:"fable",label:"Fable 5.1"},{alias:"opusplan",label:"Opus Plan"}],sj=new Set([...TS.map(e=>e.alias),"best","opus[1m]","sonnet[1m]","claude-opus-5","claude-opus-4-8","claude-sonnet-5","claude-sonnet-4-6","claude-haiku-4-5","claude-fable-5","claude-fable-5-1"]),aj=[{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"}],ES=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),_S=[{alias:"auto",label:"Auto"},{alias:"composer-2.5",label:"Composer 2.5"},{alias:"claude-opus-5-high",label:"Opus 5"},{alias:"claude-fable-5-1-high",label:"Fable 5.1"},{alias:"claude-sonnet-5-high",label:"Sonnet 5"},{alias:"cursor-grok-4.6-high",label:"Cursor Grok 4.6"},{alias:"gpt-5.6-sol-high",label:"GPT-5.6 Sol High"},{alias:"gpt-5.3-codex",label:"Codex 5.3"}]});function Vu(e){let t=e||{},n=pj(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function pj(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:pt(e.agent),payload:{text:e.text,boxRole:e.boxRole,...e.kind?{kind:e.kind}:{},...e.attachments?.length?{attachments:e.attachments}:{},...e.deliveryId?{deliveryId:e.deliveryId}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:e.box,provider:pt(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:pt(e.agent),payload:{text:e.prompt,kind:e.kind,boxRole:e.boxRole,...e.deliveryId?{deliveryId:e.deliveryId}:{}}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:pt(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:pt(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:pt(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:pt(e.agent),payload:{...Qr(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:pt(e.agent||e.toAgent),payload:{kind:"subtask-failed",...Qr(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:pt(e.agent),payload:{change:"subtask-resumed",...Qr(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",...Qr(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...Qr(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...Qr(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:pt(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:pt(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:pt(e.agent),payload:{...Qr(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...Qr(e)}};case"retag-failed":return{type:"error",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:pt(e.agent),payload:{kind:"retag-failed",action:e.action??"reshape",reason:e.reason,rolledBack:e.rolledBack!==!1,...e.recovered?{recovered:!0}:{}}};case"rehydrate-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:pt(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};default:return null}}function CS(e,t){let n=Vu(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;Ju(()=>C(r,n))}async function NS(e){if(!(!e?.id||OS.has(e.id))){OS.add(e.id);try{let t=await K(e),n=new Set(t.filter(r=>r.source==="orchestrator").map(r=>`${r.type}|${r.payload?.ts??"?"}`));for(let r of e.events||[]){let o=Vu(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await C(e,o)}}catch{}}}function Qr(e){let{type:t,at:n,...r}=e;return r}function PS(e,t,n){!n?.promptId||zu.get(e.id)===n.promptId||(zu.set(e.id,n.promptId),Ju(()=>C(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:pt(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 DS(e,t,n,r={}){zu.delete(e.id),Ju(()=>C(e,{type:"prompt.dismissed",actor:"user",source:"orchestrator",boxId:t?.name,provider:pt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}function vm(e,t,n,r={}){zu.delete(e.id),Ju(()=>C(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:pt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var pt,Gu,Ju,MS,OS,zu,Sm=q(()=>{he();pt=e=>e||null;Gu=Promise.resolve(),Ju=e=>(Gu=Gu.then(e).catch(()=>{}),Gu),MS=()=>Gu;OS=new Set;zu=new Map});function gj(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function HS(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of gj(n).reverse()){if(!fj.test(r))continue;let o=r.endsWith("?")&&r.length<=wj&&mj.test(r);if(hj.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function qS(e){let t=String(e||""),n=[];yj.test(t)&&n.push("commit"),WS.test(t)&&n.push("rebase"),bj.test(t)&&n.push("push");let r=xj.test(t);!r&&kj.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 KS(e){return WS.test(String(e||""))}function ua(e,{branch:t=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1}={}){Array.isArray(e)||(e=e==="push"?["commit","push"]:["commit","push","pr"]);let a=new Set(e),i=Array.isArray(o)&&o.length>0,c=i?o.map(f=>`${f.name}/`).join(", "):null,l=t?` on this branch (${t})`:"",u=[];if(a.has("commit")&&u.push(i?`commit the work in each changed checkout (${c})${l} with a clear commit message per repo`:`commit the work${l} with a clear commit message`),a.has("rebase")){let f=a.has("commit")?"the branch":`this branch${t?` (${t})`:""}`;u.push(i?`rebase ${f} in each changed checkout (${c}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${f} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`)}if(a.has("push")||a.has("pr")){let f=r&&!a.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",w=a.has("rebase")?" with `--force-with-lease` (the rebase rewrote history)":"";i?u.push(a.has("commit")||a.has("rebase")?`push each one to its remote${w}${f}`:`push this branch${t?` (${t})`:""} from each changed checkout (${c}) to its remote${f}`):u.push(a.has("commit")||a.has("rebase")?`push it to the remote${w}${f}`:`push this branch${l} to the remote${f}`)}a.has("pr")&&u.push(i?"open a pull request in each changed repo with a concise title and a description of what changed and why (run `gh pr create` inside each checkout)":`open a pull request${n?` against ${n}`:""} with a concise title and a description of what changed and why (use \`gh pr create\`)`);let d=[];a.has("commit")||d.push("don't create any new commits \u2014 ship what's already committed"),s&&!a.has("rebase")&&d.push("don't rebase \u2014 leave the branch's history as it is"),!a.has("push")&&!a.has("pr")&&d.push("don't push"),a.has("pr")||d.push("don't open a pull request");let p=`Yes \u2014 go ahead: ${u.join(", then ")}.`;return d.length&&(p+=` ${d.join(", and ").replace(/^./,f=>f.toUpperCase())}.`),a.has("pr")&&(p+=i?" If a repo's PR for this branch is already open, just push that repo's update instead.":" If a PR for this branch is already open, just push the update instead."),p}function GS(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 zS(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<=vj&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function VS(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+Sj||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function JS(e){let t=(Array.isArray(e)?e:[]).filter(r=>BS[r]).map(r=>BS[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 jS,LS,FS,US,fj,hj,mj,wj,eo,yj,WS,bj,kj,xj,vj,Sj,BS,Zo=q(()=>{jS=/(?<!\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,LS=/(?<!\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,FS=/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,US=/(?<!\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,fj=new RegExp(`\\b(?:${jS}|${LS}|${FS}|${US})\\b`,"i"),hj=/\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,mj=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,wj=90;eo=["commit","rebase","push","pr"],yj=new RegExp(`\\b(?:${jS})\\b`,"i"),WS=new RegExp(`\\b(?:${US})\\b`,"i"),bj=new RegExp(`\\b(?:${LS})\\b`,"i"),kj=new RegExp(`\\b(?:${FS})\\b`,"i"),xj=/\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;vj=3e4;Sj=2500;BS={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import Aj from"node:crypto";import Yu from"node:fs/promises";import YS from"node:path";import Tj from"node:os";async function qe(){return to||(Am??=Yu.readFile(Em,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(to=e,!t&&Ue()){let{records:n,source:r}=await it("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;to[ce(i.repo,i.number)]=i}Object.keys(to).length&&await _m().catch(()=>{})}}return to}).finally(()=>Am=null),Am)}async function _m(){let e=JSON.stringify({links:to},null,2),t=`${Em}.${process.pid}.tmp`;await Yu.mkdir(XS,{recursive:!0}),await Yu.writeFile(t,e),await Yu.rename(t,Em)}async function et(e){Tm=Tm.then(_m,_m),await Tm.catch(()=>{});let t=to?.[e];t&&vt("prlinks",{id:ZS(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function Lt({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 qe(),c=ce(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:Ej.has(a),firstSeen:Date.now()},await et(ce(e,t)),{link:i[c],created:!0})}async function or(e,t){if(!e||t==null)return null;let n=(await qe())[ce(e,t)];return!n||n.announced?null:(n.announced=!0,await et(ce(e,t)),n)}async function QS(e,t){if(!e||t==null)return!1;let n=(await qe())[ce(e,t)];return n?.notifyOnMerge?(delete n.notifyOnMerge,await et(ce(e,t)),!0):!1}async function ct(e,t){return!e||t==null?null:(await qe())[ce(e,t)]??null}async function no(e,t,n){if(!e||t==null)return null;let r=(await qe())[ce(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(ce(e,t)),r):null}async function eA(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await qe())[ce(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await et(ce(e,t)),o):null}async function tA(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await qe())[ce(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await et(ce(e,t)),o):null}async function Xu(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await qe())[ce(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await et(ce(e,t)),r)}async function Zu(e,t){if(!e||t==null)return null;let n=(await qe())[ce(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await et(ce(e,t)),n)}async function Qu(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await qe())[ce(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await et(ce(e,t)),r)}async function ed(e,t){if(!e||t==null)return null;let n=(await qe())[ce(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await et(ce(e,t)),n)}async function nA(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await qe())[ce(e,t)];return r?(r.baseFoldAt=n,await et(ce(e,t)),r):null}async function rA(e,t){if(!e||t==null)return null;let n=(await qe())[ce(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await et(ce(e,t)),n)}async function oA(e,t,n){if(!e||t==null||!n)return null;let r=(await qe())[ce(e,t)];return r?(r.lastHeadSha=n,await et(ce(e,t)),r):null}async function sA(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await qe())[ce(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(ce(e,t))),{prev:o,link:r}}async function Zi(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await qe())[ce(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await et(ce(e,t)),r):null}async function Qo(e,t,n=!0){if(!e||t==null)return null;let r=(await qe())[ce(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await et(ce(e,t)),r):null}async function es(e,t,n=!0){if(!e||t==null)return null;let r=(await qe())[ce(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await et(ce(e,t)),r):null}async function aA(e,t,n){if(!e||t==null)return null;let r=(await qe())[ce(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(ce(e,t)),r}async function iA(e,t,n){if(!e||t==null)return null;let r=(await qe())[ce(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(ce(e,t)),r}async function Qi(e,t){if(!e||t==null)return null;let n=(await qe())[ce(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(ce(e,t)),n)}async function cA(){return Object.values(await qe()).filter(e=>!_j.has(e.state))}async function pn(){return Object.values(await qe()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function lA(){if(!Ue())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await it("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await qe(),r=0;for(let[o,s]of Object.entries(n))await vt("prlinks",{id:ZS(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var XS,Em,ce,ZS,to,Am,Tm,Ej,_j,Mn=q(()=>{Dr();XS=process.env.BOSTRAT_STATE_DIR||YS.join(process.env.HOME||Tj.tmpdir(),".bostrat"),Em=YS.join(XS,"pr-links.json"),ce=(e,t)=>`${e}#${Number(t)}`,ZS=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=Aj.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},to=null,Am=null,Tm=Promise.resolve();Ej=new Set(["api","observed","reconciled"]);_j=new Set(["merged","closed","lost"])});import Ij from"node:fs";import Im from"node:fs/promises";import fA from"node:path";import $j from"node:os";function wA(e,t=!1){if(!t&&e-dA<Rj)return;dA=e;let n=JSON.stringify({windowStart:da,byCaller:Object.fromEntries(sr),lastHour:ro});pA=pA.then(()=>Im.mkdir(hA,{recursive:!0})).then(()=>Im.writeFile(`${td}.tmp`,n)).then(()=>Im.rename(`${td}.tmp`,td)).catch(()=>{})}function gA(e){e-da<mA||(ro={start:da,total:nd(sr),byCaller:Object.fromEntries(sr)},ro.total&&console.log(`[github] ${ro.total} calls last hour`,ro.byCaller),da=e,sr=new Map,wA(e,!0))}function ar(e="other",t=Date.now()){gA(t),sr.set(e,(sr.get(e)||0)+1),wA(t)}function yA(e=Date.now()){return gA(e),{windowStart:da,total:nd(sr),byCaller:Object.fromEntries(sr),lastHour:ro,backoffUntil:ts>e?ts:null}}function oo(e){return Oj.test(String(e?.message||e||""))}function so(e,t=Date.now()){return ts<=t&&console.warn(`[github] rate limited \u2014 backing off ${uA/6e4} min:`,String(e?.message||e||"").slice(0,200)),ts=Math.max(ts,t+uA),ts}function rd(e=Date.now()){return Math.max(0,ts-e)}var hA,td,mA,uA,Rj,da,sr,ro,ts,dA,nd,pA,Oj,ec=q(()=>{hA=process.env.BOSTRAT_STATE_DIR||fA.join(process.env.HOME||$j.tmpdir(),".bostrat"),td=fA.join(hA,"github-metrics.json"),mA=60*6e4,uA=5*6e4,Rj=6e4,da=Date.now(),sr=new Map,ro=null,ts=0,dA=0,nd=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(Ij.readFileSync(td,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<mA?(da=e.windowStart,sr=new Map(Object.entries(e.byCaller||{})),ro=e.lastHour||null):nd(new Map(Object.entries(e.byCaller||{})))&&(ro={start:e.windowStart,total:nd(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}pA=Promise.resolve();Oj=/rate limit|too quickly|abuse detection|HTTP 429/i});import bA from"node:fs/promises";import kA from"node:path";import Mj from"node:os";function sd({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};od.push(l),od.length>Nj&&od.shift();let u=$m.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)),$m.set(e,u),Pj(l),l}async function Pj(e){try{await bA.mkdir(xA,{recursive:!0}),await bA.appendFile(Cj,JSON.stringify(e)+`
182
+ `)}catch{}}function vA(){let e={};for(let[t,n]of $m)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:od.slice(-20)}}var xA,Cj,Nj,od,$m,ad=q(()=>{xA=process.env.BOSTRAT_STATE_DIR||kA.join(process.env.HOME||Mj.tmpdir(),".bostrat"),Cj=kA.join(xA,"github-latency.ndjson"),Nj=100,od=[],$m=new Map});import{execFile as Dj}from"node:child_process";import{promisify as Bj}from"node:util";async function jj(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([fa("git",["-C",e,"rev-parse","HEAD"]),fa("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await C({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function Xt(e,t,n={}){let{caller:r="prs",...o}=n,s=await Sn({cwd:e});ar(r);try{let{stdout:a}=await fa("gh",t,{cwd:e,...Lj,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw oo(a)&&so(a),a}}async function Mm(){if(id&&Date.now()-id.at<6e4)return id.data;let e;try{ar("auth");let t=await fa("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 pi();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return id={at:Date.now(),data:e},e}async function Fj(e){try{let{stdout:t}=await fa("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function AA(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 Rm(e){let t=(e||[]).map(AA),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 Nm(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function EA(e,t){if(!t)return null;let n=await _e(e);if(!n)return null;try{let r=await Xt(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 _A(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 IA(e,t){let n=await EA(e,t);return n===null?{...Rm([]),unavailable:!0}:Rm(_A(n))}function cd(e,t=Rm(e.statusCheckRollup)){return{number:e.number,title:e.title,url:e.url,author:e.author?.login??null,headRefName:e.headRefName,headSha:e.headRefOid??null,baseRefName:e.baseRefName,isDraft:!!e.isDraft,reviewDecision:e.reviewDecision||null,mergeable:e.mergeable||"UNKNOWN",mergeStateStatus:e.mergeStateStatus||"UNKNOWN",state:e.state??null,mergedAt:e.mergedAt??null,closedAt:e.closedAt??null,additions:e.additions??0,deletions:e.deletions??0,createdAt:e.createdAt,updatedAt:e.updatedAt,checks:t,green:t.failed===0&&t.pending===0&&e.mergeStateStatus==="CLEAN",autoMergeArmed:!!e.autoMergeRequest,mergeabilityPending:!1}}function Hj(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){pa.delete(s);continue}r.add(s),pa.has(s)||pa.set(s,n),o.mergeabilityPending=n-pa.get(s)<Uj}for(let o of pa.keys())o.startsWith(`${e}#`)&&!r.has(o)&&pa.delete(o);return t}async function ha(e,t){let n=await ir(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await Xt(n.path,["pr","view",String(r),"--json",Cm]);return cd(JSON.parse(o))}catch(o){if(!Nm(o))throw o;let s=await Xt(n.path,["pr","view",String(r),"--json",TA]),a=JSON.parse(s);return cd(a,await IA(n.path,a.headRefOid))}}async function Cn(e,{caller:t="prs"}={}){try{let n=await Xt(e,["pr","list","--json",Cm,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>cd(r)).sort(SA)}catch(n){if(!Nm(n))throw n;let r=await Xt(e,["pr","list","--json",TA,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>cd(o,await IA(e,o.headRefOid))))).sort(SA)}}function Zt(){tc.clear()}async function Kj(e,t){if(!e)return t;for(let n of t){let r=await ct(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 Xu(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await Qu(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function $A(){let e=await Mm();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await Xn())await Fj(a.path)&&t.push(a);let n=Date.now(),r=rd(n)>0,o=await Promise.all(t.map(async a=>{let i=tc.get(a.path),c=i?.pending?qj:Wj;if(i&&(r||n-i.at<c))return i.entry;try{let l=await _e(a.path).catch(()=>null),u=Hj(a.path,await Cn(a.path,{caller:"tab"}),n);if(await Kj(l,u),i?.entry?.prs)for(let f of u)i.entry.prs.find(h=>h.number===f.number)?.checks?.pending>0&&f.checks.total>0&&f.checks.pending===0&&sd({change:f.checks.failed>0?"checks-failed":"checks-green",repo:l||a.name,number:f.number,githubAt:f.checks.settledAt,source:"tab"});let d={name:a.name,path:a.path,prs:u},p=u.some(f=>f.mergeabilityPending||f.checks.pending>0||f.autoMergeArmed);return tc.set(a.path,{at:Date.now(),entry:d,pending:p}),d}catch(l){return i?i.entry:{name:a.name,path:a.path,prs:[],error:Nn(l)}}})),s=new Set(t.map(a=>a.path));for(let a of tc.keys())s.has(a)||tc.delete(a);return{auth:e,repos:o}}async function ir(e){let t=(await Xn()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function ns(e){return Cs(e)}async function ma(e,t,{method:n="squash"}={}){let r=await ir(e);if(!nc.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 Tf().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await Xt(r.path,s)}catch(a){throw new Error(Nn(a))}finally{Zt()}return{ok:!0,number:o}}async function rc(e,t){let n=await ir(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Xt(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(Nn(s))}finally{Zt()}let o=await _e(n.path).catch(()=>null);return o&&await nA(o,r).catch(()=>{}),{ok:!0,number:r}}async function Pm(e,t){let n=await ir(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await Xt(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(Nn(o))}finally{Zt()}return{ok:!0,number:r}}function Dm(e){return e.green&&!e.isDraft}function Jj(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 RA(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:Dm(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function OA(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function oc(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 MA(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(oc))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function CA(){let e={};for(let[t,n]of Om)e[t]={...n};return e}async function NA(e,{method:t="merge",onMerged:n=null}={}){let r=await ir(e);if(!nc.has(t))throw new Error(`invalid merge method: ${t}`);if(Om.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await Cn(r.path)).filter(Dm).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 Om.set(r.path,s),Xj(s,o,{listPrs:()=>Cn(r.path),merge:a=>ma(r.path,a,{method:t}),sleep:Vj,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function Yj(e,t){let n=Date.now()+(t.settleMaxMs??zj),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(Gj)}}async function Xj(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 Yj(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: ${Nn(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(!Dm(a)){e.skipped.push({number:a.number,title:a.title,reason:Jj(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:Nn(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),Zt()}}async function Bm(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await fa("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${Nn(l)}`)}await jj(e);let o=n||"";if((await Sn({cwd:e})).GH_TOKEN){let l=await Tf().catch(()=>null);l&&(o=`${o?`${o}
183
+
184
+ `:""}Opened by bostrat on behalf of @${l}`)}let s=["pr","create","--title",t.trim(),"--body",o];r&&s.push("--base",r);let a;try{a=await Xt(e,s)}catch(l){throw new Error(Nn(l))}finally{Zt()}let i=a.match(/https:\/\/\S+\/pull\/\d+/)?.[0]??null,c=i?Number(i.match(/\/pull\/(\d+)/)?.[1]):null;return{ok:!0,url:i,number:c}}async function PA(e,t){let n=await ir(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await Xt(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(Nn(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!Nm(i))throw i;let c=await Xt(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await EA(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(Nn(i));o=_A(l).map(AA).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=Zj(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await Xt(n.path,["run","view",c,"--log-failed"]).then(u=>Qj(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function Zj(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function Qj(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
185
185
  `);return o.length>t&&(r=`\u2026 (${o.length-t} earlier lines truncated)
186
186
  `+o.slice(-t).join(`
187
187
  `)),Buffer.byteLength(r)>n&&(r=`\u2026 (truncated)
188
- `+r.slice(-n)),r}function Mn(e){return String(e?.stderr||e?.message||e||"").trim().split(`
189
- `).find(n=>n.trim())||"gh failed"}var Zs,tj,Lu,Qm,US,rj,Xs,LS,sj,aj,ji,Li,cj,lj,uj,Xm,Uo=K(()=>{Tr();pt();Rn();Bi();ju();pe();Zs=QB(ZB),tj={timeout:3e4,maxBuffer:8*1024*1024};Lu=null;Qm="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt,state,mergedAt,closedAt",US=Qm.replace("statusCheckRollup,","");rj=9e4,Xs=new Map;LS=(e,t)=>e.number-t.number;sj=3e4,aj=1500,ji=new Map;Li=new Set(["squash","merge","rebase"]);cj=2500,lj=9e4,uj=e=>new Promise(t=>setTimeout(t,e));Xm=new Map});import{execFile as wj}from"node:child_process";import{promisify as gj}from"node:util";async function bj(e,t){try{let{stdout:n}=await yj("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function kj(e,t,n,{rebase:r=!1,listPrs:o=On}={}){let s=await Oi(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await Mi(e.dir,n).catch(()=>0),i=t?await bj(e.dir,`refs/remotes/origin/${t}..HEAD`):null,c=i==null?a>0:i>0,l=null,u="unknown";try{l=(await o(e.dir,{caller:"ship-state"})||[]).find(m=>m.headRefName===t)||null,u=l?"open":"none"}catch{}let d=s||a>0,p=[];s&&p.push("commit"),r&&p.push("rebase"),(s||c)&&p.push("push"),d&&(u!=="open"||s||c)&&p.push("pr");let f=p.filter(w=>!(w==="pr"&&u==="open"));return{name:e.name??null,slug:e.repo??null,dirty:s,unpushed:c,aheadBase:a,prState:u,openPr:l?{number:l.number,url:l.url??null,title:l.title??null}:null,available:Uu.filter(w=>p.includes(w)),defaults:Uu.filter(w=>f.includes(w))}}async function Hu(e,{branch:t,rebase:n=!1,listPrs:r=On}={}){let o=e?.workspace,s=o?.kind==="multi"?(o.repos||[]).filter(p=>p?.dir):o?.base&&(o.dir||e?.cwd)?[{name:o.base?.split("/").pop()??null,dir:o.dir||e.cwd,repo:o.repo??null,baseRef:o.baseRef}]:[];if(!s.length||!await Ws(s[0].dir).catch(()=>!1))return null;let a=[];for(let p of s)a.push(await kj(p,t,p.baseRef||o.baseRef,{rebase:n,listPrs:r}));let i=a.filter(p=>p.dirty||p.aheadBase>0||p.openPr),c=i.length?i:a,l=Uu.filter(p=>c.some(f=>f.available.includes(p))),u=Uu.filter(p=>c.some(f=>f.defaults.includes(p))),d=c.filter(p=>p.openPr);return{available:l,defaults:u,prState:d.length?"open":c.every(p=>p.prState==="none")?"none":"unknown",openPr:c.length===1?c[0].openPr:null,repos:c.map(p=>({name:p.name,slug:p.slug,dirty:p.dirty,unpushed:p.unpushed,prState:p.prState,openPr:p.openPr}))}}var yj,Uu,oh=K(()=>{gu();Uo();yj=gj(wj),Uu=["commit","rebase","push","pr"]});function Wu(e,t,n){let{state:r,reason:o}=Pf(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of Hi)a-c.at>=ZS()&&Hi.delete(i);Hi.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=Hi.get(e);return s?Date.now()-s.at>=ZS()?(Hi.delete(e),!1):s.busy:!1}async function sh(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await Be(e,{lines:Ze}).catch(()=>"");if(!Wu(e,t,r))return m0(t,r)?{working:!0,prompted:!1}:n;if(qr(t,r)){let o=await on(e).catch(()=>r),s=$n({name:e,agent:t},o);if(s)return!hu({name:e,agent:t},s,o)||bv(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function Ho(e,t){return(await sh(e,t)).working}var ZS,Hi,Wi=K(()=>{ct();bi();_m();$m();ZS=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,Hi=new Map});import{execFile as xj}from"node:child_process";import{promisify as vj}from"node:util";async function Zr(e){if(!e)return null;let t=QS.get(e);if(t&&Date.now()-t.at<Tj)return t.branch;let n=null;try{let{stdout:r}=await Sj("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return QS.set(e,{at:Date.now(),branch:n}),n}function eT(e){return String(e||"").match(Aj)?.[1]??null}function tT(e,t){let n=eT(e);return!!n&&!!t&&n===t}function nT(e,t){let n=eT(e);return!!n&&n!==t}function Ej(e){let t=e?.workspace;return t?.kind==="multi"?(t.repos??[]).map(n=>n?.dir).filter(Boolean):[t?.dir||e?.cwd].filter(Boolean)}async function ta(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of Ej(e))n(await Zr(r));return t}async function qu(e,t,n=()=>!0){if(!t)return null;let r=(e??[]).filter(a=>a&&n(a)),o=r.find(a=>a.workspace?.branch===t);if(o)return o;let s=r.find(a=>tT(t,a.id));if(s)return s;for(let a of r)if(!De(a)&&(await ta(a)).includes(t))return a;return null}function _j(e,t,n){let r=e?.workspace;return r?.kind==="multi"?(r.repos??[]).some(o=>t&&o?.base===t||n&&o?.repo===n):!r?.base||!t||r.base===t||n&&r.repo===n}function Ku(e,{branch:t=null,repo:n=null,slug:r=null}={}){return tT(t,e?.id)?!0:_j(e,n,r)}var Sj,Tj,QS,Aj,Wo=K(()=>{Gt();Sj=vj(xj),Tj=5e3,QS=new Map;Aj=/^track\/.+-([0-9a-f]{8})$/});import{execFile as Ij}from"node:child_process";import{promisify as $j}from"node:util";function na({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function zu(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function Ju({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?Pj[r]:null;return a&&s.push(a),s.push(`${iT}: ${na({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${cT}: ${String(o).trim()}`),s}function rT(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
190
- `)){let r=n.trim(),o=/^([A-Za-z-]+):\s*(.+)$/.exec(r);if(!o)continue;let s=o[1].toLowerCase(),a=o[2].trim();if(s===iT.toLowerCase()&&!t.epoch)t.epoch=zu(a);else if(s===cT.toLowerCase()&&!t.model)t.model=a;else if(s===lT.toLowerCase()&&!t.cause){let i=a.toLowerCase();qi.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 Dj(e,t=Qr){return e<=t?"rework":"drift"}function Bj(e,{window:t=Qr,end:n=uh}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function Yu({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return jj.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${lT} trailer`}:Fj.test(s)&&!oT.test(s)?{cause:"style",level:"C",basis:"subject"}:oT.test(s)?{cause:"defect",level:"C",basis:"subject"}:Lj.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 ph({heuristic:e=null,subject:t="",ref:n=null,promptKind:r=null,fixerCategory:o=null,ticketKind:s=null}={}){let a=String(t||""),i=Uj.exec(a),c=i?i[1].toLowerCase():null;return e&&(e.level==="A"||e.level==="E")?{intent:"fix",basis:e.basis}:s&&/^bug/i.test(s)?{intent:"fix",basis:`linked ticket: ${s}`}:c&&Hj.has(c)?{intent:"fix",basis:`subject prefix: ${c}:`}:c&&Wj.has(c)?{intent:"planned",basis:`subject prefix: ${c}:`}:s&&/^(story|feature|task)/i.test(s)?{intent:"planned",basis:`linked ticket: ${s}`}:e?{intent:"likely-fix",basis:e.basis}:r==="followup-go"?{intent:"planned",basis:"operator-tapped follow-up"}:sT.test(String(n||""))||sT.test(a)?{intent:"planned",basis:"blueprint item"}:o&&qj.has(o)?{intent:"planned",basis:`prompt: ${o}`}:{intent:"unknown",basis:null}}function Vj(e){let t=String(e||"");return Kj.some(n=>n.test(t))?"excluded":Gj.some(n=>n.test(t))?"docs":zj.some(n=>n.test(t))?"config":"code"}function Jj(e){let t=[],n=null,r=null;for(let o of String(e||"").split(`
191
- `)){if(o.startsWith("diff --git ")){n={oldPath:null,newPath:null,deleted:[],added:0,binary:!1,hunks:[]},r=null,t.push(n);continue}if(n)if(o.startsWith("--- ")&&!r){let s=o.slice(4).trim();n.oldPath=s==="/dev/null"?null:s.replace(/^a\//,"")}else if(o.startsWith("+++ ")&&!r){let s=o.slice(4).trim();n.newPath=s==="/dev/null"?null:s.replace(/^b\//,"")}else if(o.startsWith("Binary files"))n.binary=!0;else if(o.startsWith("@@")){let s=/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(o);if(!s)continue;let a=Number(s[1]),i=s[2]==null?1:Number(s[2]),c=Number(s[3]),l=s[4]==null?1:Number(s[4]);i>0&&n.deleted.push([a,i]),n.added+=l,r={oldStart:a,oldCount:i,newStart:c,newCount:l,del:[],add:[]},n.hunks.push(r)}else r&&o.startsWith("-")?r.del.push(o.slice(1)):r&&o.startsWith("+")&&r.add.push(o.slice(1))}return t}function Yj(e,t){let n=lh(e),r=lh(t);if(n===r)return 1;if(!n.length||!r.length)return 0;n.length>Gu&&(n=n.slice(0,Gu)),r.length>Gu&&(r=r.slice(0,Gu));let o=new Array(r.length+1),s=new Array(r.length+1);for(let a=0;a<=r.length;a++)o[a]=a;for(let a=1;a<=n.length;a++){s[0]=a;let i=n.charCodeAt(a-1);for(let c=1;c<=r.length;c++){let l=i===r.charCodeAt(c-1)?0:1;s[c]=Math.min(o[c]+1,s[c-1]+1,o[c-1]+l)}[o,s]=[s,o]}return 1-o[r.length]/Math.max(n.length,r.length)}function Xj(e,t=uT){let n=new Set,r=e?.del||[],o=e?.add||[];for(let s=0;s<r.length;s++){let a=e.oldStart+s;if(!lh(r[s]).length){n.add(a);continue}s<o.length&&Yj(r[s],o[s])>=t&&n.add(a)}return n}function Zj(e){let t=[...e].sort((r,o)=>r-o),n=[];for(let r of t){let o=n[n.length-1];o&&o[0]+o[1]===r?o[1]+=1:n.push([r,1])}return n}function Qj(e){let t=new Map,n=null;for(let r of String(e||"").split(`
192
- `)){let o=/^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/.exec(r);if(o){n={sha:o[1],line:Number(o[3]),time:null},t.set(n.line,n);continue}n&&r.startsWith("committer-time ")&&(n.time=Number(r.slice(15))*1e3)}return t}async function aT(e,t){let{stdout:n}=await ch(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
188
+ `+r.slice(-n)),r}function Nn(e){return String(e?.stderr||e?.message||e||"").trim().split(`
189
+ `).find(n=>n.trim())||"gh failed"}var fa,Lj,id,Cm,TA,Uj,pa,SA,Wj,qj,tc,nc,Gj,zj,Vj,Om,rs=q(()=>{Or();mt();Mn();ec();ad();he();fa=Bj(Dj),Lj={timeout:3e4,maxBuffer:8*1024*1024};id=null;Cm="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt,state,mergedAt,closedAt",TA=Cm.replace("statusCheckRollup,","");Uj=9e4,pa=new Map;SA=(e,t)=>e.number-t.number;Wj=3e4,qj=1500,tc=new Map;nc=new Set(["squash","merge","rebase"]);Gj=2500,zj=9e4,Vj=e=>new Promise(t=>setTimeout(t,e));Om=new Map});import{execFile as eL}from"node:child_process";import{promisify as tL}from"node:util";async function rL(e,t){try{let{stdout:n}=await nL("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function oL(e,t,n,{rebase:r=!1,listPrs:o=Cn}={}){let s=await zo(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await Vo(e.dir,n).catch(()=>0),i=t?await rL(e.dir,`refs/remotes/origin/${t}..HEAD`):null,c=i==null?a>0:i>0,l=null,u="unknown";try{l=(await o(e.dir,{caller:"ship-state"})||[]).find(h=>h.headRefName===t)||null,u=l?"open":"none"}catch{}let d=s||a>0,p=[];s&&p.push("commit"),r&&p.push("rebase"),(s||c)&&p.push("push"),d&&(u!=="open"||s||c)&&p.push("pr");let f=p.filter(w=>!(w==="pr"&&u==="open"));return{name:e.name??null,slug:e.repo??null,dirty:s,unpushed:c,aheadBase:a,prState:u,openPr:l?{number:l.number,url:l.url??null,title:l.title??null}:null,available:ld.filter(w=>p.includes(w)),defaults:ld.filter(w=>f.includes(w))}}async function ud(e,{branch:t,rebase:n=!1,listPrs:r=Cn}={}){let o=e?.workspace,s=o?.kind==="multi"?(o.repos||[]).filter(p=>p?.dir):o?.base&&(o.dir||e?.cwd)?[{name:o.base?.split("/").pop()??null,dir:o.dir||e.cwd,repo:o.repo??null,baseRef:o.baseRef}]:[];if(!s.length||!await aa(s[0].dir).catch(()=>!1))return null;let a=[];for(let p of s)a.push(await oL(p,t,p.baseRef||o.baseRef,{rebase:n,listPrs:r}));let i=a.filter(p=>p.dirty||p.aheadBase>0||p.openPr),c=i.length?i:a,l=ld.filter(p=>c.some(f=>f.available.includes(p))),u=ld.filter(p=>c.some(f=>f.defaults.includes(p))),d=c.filter(p=>p.openPr);return{available:l,defaults:u,prState:d.length?"open":c.every(p=>p.prState==="none")?"none":"unknown",openPr:c.length===1?c[0].openPr:null,repos:c.map(p=>({name:p.name,slug:p.slug,dirty:p.dirty,unpushed:p.unpushed,prState:p.prState,openPr:p.openPr}))}}var nL,ld,jm=q(()=>{Lu();rs();nL=tL(eL),ld=["commit","rebase","push","pr"]});function dd(e,t,n){let{state:r,reason:o}=mh(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of sc)a-c.at>=DA()&&sc.delete(i);sc.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=sc.get(e);return s?Date.now()-s.at>=DA()?(sc.delete(e),!1):s.busy:!1}async function Lm(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await Pe(e,{lines:Ye}).catch(()=>"");if(!dd(e,t,r))return Z0(t,r)?{working:!0,prompted:!1}:n;if(Xr(t,r)){let o=await an(e).catch(()=>r),s=On({name:e,agent:t},o);if(s)return!ju({name:e,agent:t},s,o)||oS(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function os(e,t){return(await Lm(e,t)).working}var DA,sc,ac=q(()=>{ut();Bi();am();cm();DA=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,sc=new Map});import{execFile as sL}from"node:child_process";import{promisify as aL}from"node:util";async function ao(e){if(!e)return null;let t=BA.get(e);if(t&&Date.now()-t.at<cL)return t.branch;let n=null;try{let{stdout:r}=await iL("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return BA.set(e,{at:Date.now(),branch:n}),n}function jA(e){return String(e||"").match(lL)?.[1]??null}function LA(e,t){let n=jA(e);return!!n&&!!t&&n===t}function FA(e,t){let n=jA(e);return!!n&&n!==t}function uL(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 wa(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of uL(e))n(await ao(r));return t}async function pd(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=>LA(t,a.id));if(s)return s;for(let a of r)if(!je(a)&&(await wa(a)).includes(t))return a;return null}function dL(e,t,n){let r=e?.workspace;return r?.kind==="multi"?(r.repos??[]).some(o=>t&&o?.base===t||n&&o?.repo===n):!r?.base||!t||r.base===t||n&&r.repo===n}function fd(e,{branch:t=null,repo:n=null,slug:r=null}={}){return LA(t,e?.id)?!0:dL(e,n,r)}var iL,cL,BA,lL,ss=q(()=>{Yt();iL=aL(sL),cL=5e3,BA=new Map;lL=/^track\/.+-([0-9a-f]{8})$/});import{execFile as pL}from"node:child_process";import{promisify as fL}from"node:util";function ga({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function md(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function gd({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?bL[r]:null;return a&&s.push(a),s.push(`${KA}: ${ga({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${GA}: ${String(o).trim()}`),s}function UA(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
190
+ `)){let r=n.trim(),o=/^([A-Za-z-]+):\s*(.+)$/.exec(r);if(!o)continue;let s=o[1].toLowerCase(),a=o[2].trim();if(s===KA.toLowerCase()&&!t.epoch)t.epoch=md(a);else if(s===GA.toLowerCase()&&!t.model)t.model=a;else if(s===zA.toLowerCase()&&!t.cause){let i=a.toLowerCase();ic.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 kL(e,t=io){return e<=t?"rework":"drift"}function xL(e,{window:t=io,end:n=qm}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function yd({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return vL.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${zA} trailer`}:AL.test(s)&&!HA.test(s)?{cause:"style",level:"C",basis:"subject"}:HA.test(s)?{cause:"defect",level:"C",basis:"subject"}:SL.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 Gm({heuristic:e=null,subject:t="",ref:n=null,promptKind:r=null,fixerCategory:o=null,ticketKind:s=null}={}){let a=String(t||""),i=TL.exec(a),c=i?i[1].toLowerCase():null;return e&&(e.level==="A"||e.level==="E")?{intent:"fix",basis:e.basis}:s&&/^bug/i.test(s)?{intent:"fix",basis:`linked ticket: ${s}`}:c&&EL.has(c)?{intent:"fix",basis:`subject prefix: ${c}:`}:c&&_L.has(c)?{intent:"planned",basis:`subject prefix: ${c}:`}:s&&/^(story|feature|task)/i.test(s)?{intent:"planned",basis:`linked ticket: ${s}`}:e?{intent:"likely-fix",basis:e.basis}:r==="followup-go"?{intent:"planned",basis:"operator-tapped follow-up"}:WA.test(String(n||""))||WA.test(a)?{intent:"planned",basis:"blueprint item"}:o&&IL.has(o)?{intent:"planned",basis:`prompt: ${o}`}:{intent:"unknown",basis:null}}function ML(e){let t=String(e||"");return $L.some(n=>n.test(t))?"excluded":RL.some(n=>n.test(t))?"docs":OL.some(n=>n.test(t))?"config":"code"}function CL(e){let t=[],n=null,r=null;for(let o of String(e||"").split(`
191
+ `)){if(o.startsWith("diff --git ")){n={oldPath:null,newPath:null,deleted:[],added:0,binary:!1,hunks:[]},r=null,t.push(n);continue}if(n)if(o.startsWith("--- ")&&!r){let s=o.slice(4).trim();n.oldPath=s==="/dev/null"?null:s.replace(/^a\//,"")}else if(o.startsWith("+++ ")&&!r){let s=o.slice(4).trim();n.newPath=s==="/dev/null"?null:s.replace(/^b\//,"")}else if(o.startsWith("Binary files"))n.binary=!0;else if(o.startsWith("@@")){let s=/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(o);if(!s)continue;let a=Number(s[1]),i=s[2]==null?1:Number(s[2]),c=Number(s[3]),l=s[4]==null?1:Number(s[4]);i>0&&n.deleted.push([a,i]),n.added+=l,r={oldStart:a,oldCount:i,newStart:c,newCount:l,del:[],add:[]},n.hunks.push(r)}else r&&o.startsWith("-")?r.del.push(o.slice(1)):r&&o.startsWith("+")&&r.add.push(o.slice(1))}return t}function NL(e,t){let n=Wm(e),r=Wm(t);if(n===r)return 1;if(!n.length||!r.length)return 0;n.length>hd&&(n=n.slice(0,hd)),r.length>hd&&(r=r.slice(0,hd));let o=new Array(r.length+1),s=new Array(r.length+1);for(let a=0;a<=r.length;a++)o[a]=a;for(let a=1;a<=n.length;a++){s[0]=a;let i=n.charCodeAt(a-1);for(let c=1;c<=r.length;c++){let l=i===r.charCodeAt(c-1)?0:1;s[c]=Math.min(o[c]+1,s[c-1]+1,o[c-1]+l)}[o,s]=[s,o]}return 1-o[r.length]/Math.max(n.length,r.length)}function PL(e,t=VA){let n=new Set,r=e?.del||[],o=e?.add||[];for(let s=0;s<r.length;s++){let a=e.oldStart+s;if(!Wm(r[s]).length){n.add(a);continue}s<o.length&&NL(r[s],o[s])>=t&&n.add(a)}return n}function DL(e){let t=[...e].sort((r,o)=>r-o),n=[];for(let r of t){let o=n[n.length-1];o&&o[0]+o[1]===r?o[1]+=1:n.push([r,1])}return n}function BL(e){let t=new Map,n=null;for(let r of String(e||"").split(`
192
+ `)){let o=/^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/.exec(r);if(o){n={sha:o[1],line:Number(o[3]),time:null},t.set(n.line,n);continue}n&&r.startsWith("committer-time ")&&(n.time=Number(r.slice(15))*1e3)}return t}async function qA(e,t){let{stdout:n}=await Hm(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
193
193
  `);return{sha:r.trim(),parents:o.trim()?o.trim().split(" "):[],ts:Number(s)*1e3,subject:a??"",message:i.join(`
194
- `)}}async function dT(e,t,{fixKey:n=null,window:r=Qr,resolveOrigin:o=null,context:s={}}={}){let a=await aT(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=rT(a.message),l=n?zu(n):c.epoch,u=l?na(l):null,{stdout:d}=await ch(e,["diff","-U0","--no-color","-M","-C",i,t]),p=Jj(d),f=0,w=0,m=0,g=0,y=0,x=0,b=0,O=new Map;for(let $ of p){if($.binary)continue;let L=$.oldPath||$.newPath||"",V=$.deleted.reduce((G,[,ae])=>G+ae,0),S=Vj(L);if(S==="excluded"){m+=V;continue}if(S==="docs"){g+=V,y+=$.added;continue}if(S==="config"){x+=V;continue}f+=$.added;let E=new Set;for(let G of $.hunks||[])for(let ae of Xj(G))E.add(ae);b+=E.size;let P=[];for(let[G,ae]of $.deleted)for(let we=G;we<G+ae;we++)E.has(we)||P.push(we);if(w+=P.length,!$.oldPath||!P.length)continue;let W;try{let G=["blame","-w","-M","-C","--line-porcelain"];for(let[ae,we]of Zj(P))G.push("-L",`${ae},${ae+we-1}`);G.push(i,"--",$.oldPath),W=Qj((await ch(e,G)).stdout)}catch{continue}for(let{sha:G,time:ae}of W.values()){let we=O.get(G)??{lines:0,time:ae};we.lines+=1,O.set(G,we)}}let I=[],C=0,U=new Map;for(let[$,{lines:L,time:V}]of O){let S=U.get($);if(!S){try{S=await aT(e,$)}catch{S=null}U.set($,S)}let E=S?rT(S.message):{epoch:null},P=E.epoch,W=E.provider,G=E.model;if(!P&&o){let Y=await o($,S);Y?.trackId&&Y?.boxId!=null&&(P={trackId:Y.trackId,boxId:Y.boxId,epoch:Y.epoch??0},W=W??Y.provider??null,G=G??Y.model??null)}if(!P){C+=L;continue}let ae=Number.isFinite(V)?V:S?.ts??a.ts,we=Math.max(0,(a.ts-ae)/Mj),Re=na(P),Ae=Re===u?"self":Dj(we,r);I.push({sha:$,key:Re,trackId:P.trackId,boxId:P.boxId,epoch:P.epoch,provider:W??null,model:G??null,lines:L,ageDays:Math.round(we*100)/100,class:Ae,decay:Ae==="rework"?1:Ae==="drift"?Math.round(Bj(we,{window:r})*1e3)/1e3:0})}I.sort(($,L)=>L.lines-$.lines);let H=Yu({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),_=ph({heuristic:H,subject:a.subject,ref:s.ref??null,promptKind:s.promptKind??null,fixerCategory:s.fixerCategory??null,ticketKind:s.ticketKind??null});return{sha:a.sha,parent:i,subject:a.subject.slice(0,200),ts:a.ts,fixKey:u,fixProvider:c.provider??s.provider??null,fixModel:c.model??s.model??null,window:r,added:f,deleted:w,excludedDeleted:m,cosmeticDeleted:b,docsDeleted:g,docsAdded:y,configDeleted:x,codeDelta:f+w+b>0,origins:I,unattributedLines:C,ghost:w===0&&f>0,heuristic:H,intent:_}}function pT(e,{minLines:t=dh}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return ra.has(n)?Ki(e)>=t:!1}function Ki(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function ih(e){let t=e.genUsd;return{...e,genUsd:dn(t),reworkChargedUsd:dn(e.reworkChargedUsd),reworkPendingUsd:dn(e.reworkPendingUsd),trueUsd:dn(t+e.reworkChargedUsd),multiplier:t>0?dn((t+e.reworkChargedUsd)/t):null}}function fT(e,{window:t=Qr,boxMeta:n={}}={}){let r=e||[],o=r.filter(_=>_.type==="cost.recorded"),s=r.filter(_=>_.type==="code.committed"),a=r.filter(_=>_.type==="code.rework"),i=_=>Array.isArray(_?.shas)&&_.shas.length?_.shas:_?.sha?[_.sha]:[],c=new Map,l=new Set;for(let _ of r)if(_.type==="rework.cause.offered")for(let $ of i(_.payload))l.add($);else if(_.type==="rework.cause.answered"&&_.payload?.cause)for(let $ of i(_.payload))c.set($,_.payload.cause);else if(_.type==="rework.cause.retracted")for(let $ of i(_.payload))c.delete($);let u={},d=(_,$,L)=>na({trackId:_,boxId:$,epoch:L??0}),p=(_,$={})=>{if(!u[_]){let V=zu(_)||{};u[_]={key:_,...V,provider:null,model:null,...ah()}}let L=u[_];return $.provider&&!L.provider&&(L.provider=$.provider),$.model&&!L.model&&(L.model=$.model),L};for(let _ of o){if(!_.boxId)continue;let $=d(_.trackId,_.boxId,_.epoch),{usd:L,model:V}=Kt(_),S=p($,{provider:_.provider,model:V!=="unknown"?V:null});S.genUsd+=L}let f=new Map;for(let _ of s){let $=`${_.trackId}/${_.boxId}`;(f.get($)??f.set($,[]).get($)).push({..._,ts:_.payload?.ts??_.ts})}for(let _ of f.values())_.sort(($,L)=>$.ts-L.ts);let w=(_,$,L,V)=>{let S=f.get(`${_}/${$}`)||[],E=-1/0;for(let G of S)G.ts<V&&(E=G.ts);let P=0,W=0;for(let G of o)G.trackId!==_||G.boxId!==$||(G.epoch??0)===(L??0)&&(G.ts<=E||G.ts>V||(P+=Kt(G).usd,W++));return{usd:P,turns:W,from:Number.isFinite(E)?E:null}},m={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0,planned:0},g={A:0,B:0,C:0,E:0,none:0},y={fix:0,"likely-fix":0,planned:0,unknown:0},x=0,b=[],O=[],I={},C={},U=new Set;for(let _ of a){let $=_.payload||{};if(!$.sha||U.has($.sha))continue;if(U.add($.sha),$.codeDelta===!1){x++;continue}let L=zu($.fixKey)||{trackId:_.trackId,boxId:_.boxId,epoch:_.epoch??0},{usd:V,turns:S}=w(L.trackId,L.boxId,L.epoch,$.ts??_.ts),E=Nj.includes($.intent?.intent)?$.intent.intent:"unknown";y[E]+=1;let P=null;c.has($.sha)?P={cause:c.get($.sha),level:"B",basis:"operator"}:($.heuristic?.level&&$.heuristic.level!=="C"||$.heuristic)&&(P=$.heuristic);let W=P?.level??"none";g[W]=(g[W]||0)+1;let G=Cj.has(W),ae=Number($.deleted)||0,we=Array.isArray($.origins)?$.origins:[],Re=we.filter(Y=>Y.class==="rework").reduce((Y,ye)=>Y+ye.lines,0),Ae={sha:$.sha,subject:$.subject??"",ts:$.ts??_.ts,trackId:_.trackId,fixKey:$.fixKey??null,fixProvider:$.fixProvider??_.provider??null,fixUsd:dn(V),fixTurns:S,linesReworked:Re,unattributedLines:Number($.unattributedLines)||0,ghost:$.ghost===!0,intent:{intent:E,basis:$.intent?.basis??null},verdict:P?{cause:P.cause,level:W,basis:P.basis??null}:null,charged:dn(0),origins:[]};if(E==="planned"||P?.cause===Vu){m.planned+=V;for(let Y of we)Y.class==="rework"&&Ae.origins.push({key:Y.key,provider:Y.provider??null,model:Y.model??null,lines:Y.lines,ageDays:Y.ageDays,class:Y.class,usd:0})}else if($.ghost||ae===0)m.ghost+=V;else{let Y=0;for(let J of we){let z=J.lines/ae,se=V*z;if(Y+=se,J.class==="self"){m.self+=se;continue}let ve=J.class==="rework"?1:Number(J.decay)||0,Ne=se*ve;if(m.decayed+=se-Ne,Ne<=0)continue;let R=p(J.key,{provider:J.provider,model:J.model});R.fixes+=1,R.linesReworked+=J.class==="rework"?J.lines:0;let D=P?.cause&&qi.includes(P.cause)?P.cause:"unclassified";R.causes[D]+=1,G?(R.reworkChargedUsd+=Ne,m.charged+=Ne,Ae.charged=dn(Ae.charged+Ne)):(R.reworkPendingUsd+=Ne,m.pending+=Ne),Ae.origins.push({key:J.key,provider:R.provider,model:R.model,lines:J.lines,ageDays:J.ageDays,class:J.class,usd:dn(Ne)})}let ye=Math.max(0,V-Y);m.unattributed+=ye}b.push(Ae),!c.has($.sha)&&l.has($.sha)&&O.push($.sha)}for(let _ of Object.values(u)){let $=_.provider||"unknown",L=_.model||"unknown",V=S=>{S.genUsd+=_.genUsd,S.reworkChargedUsd+=_.reworkChargedUsd,S.reworkPendingUsd+=_.reworkPendingUsd,S.linesReworked+=_.linesReworked,S.fixes+=_.fixes;for(let E of Object.keys(S.causes))S.causes[E]+=_.causes[E]};V(I[$]||=ah()),V(C[L]||=ah())}b.sort((_,$)=>$.ts-_.ts);let H=Object.values(u).map(_=>{let $=n[`${_.trackId}/${_.boxId}`]||{};return ih({..._,trackName:$.trackName??null,label:$.label??null})}).sort((_,$)=>$.reworkChargedUsd+$.reworkPendingUsd-(_.reworkChargedUsd+_.reworkPendingUsd)||$.genUsd-_.genUsd);return{window:t,basis:`rework = code lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old (docs/config churn and in-place updates \u2265${uT} similar are counted, not blamed); fix cost = the fixing box's turns since its previous commit; charged only on an authoritative / operator / self-reported cause; planned work (follow-up, blueprint item, feat:/docs: prefix, non-fix prompt) is generation cost`,intents:y,noCodeDelta:x,byEpoch:Object.fromEntries(H.map(_=>[_.key,_])),epochs:H,byProvider:Object.fromEntries(Object.entries(I).map(([_,$])=>[_,ih($)])),byModel:Object.fromEntries(Object.entries(C).map(([_,$])=>[_,ih($)])),buckets:Object.fromEntries(Object.entries(m).map(([_,$])=>[_,dn($)])),fixUsdTotal:dn(Object.values(m).reduce((_,$)=>_+$,0)),fixes:b,verdicts:g,pendingTaps:O,commits:s.length}}var Rj,Oj,ch,iT,cT,lT,Mj,Qr,uh,dh,qi,Vu,Cj,Nj,ra,uT,Pj,jj,oT,Lj,Fj,Uj,Hj,Wj,sT,qj,Kj,Gj,zj,lh,Gu,dn,ah,Xu=K(()=>{Lr();Rj=$j(Ij),Oj=64*1024*1024,ch=(e,t)=>Rj("git",["-C",e,...t],{maxBuffer:Oj,timeout:6e4}),iT="Bostrat-Epoch",cT="Bostrat-Model",lT="Bostrat-Fix-Cause",Mj=24*36e5,Qr=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,uh=90,dh=3,qi=Object.freeze(["defect","design","requirements","style"]),Vu="not-a-fix",Cj=new Set(["A","B","E"]),Nj=Object.freeze(["fix","likely-fix","planned","unknown"]),ra=new Set(["fix","likely-fix"]),uT=.8;Pj={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};jj=/^revert\b|^revert "/i,oT=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,Lj=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,Fj=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;Uj=/^([a-z]+)(\([^)]*\))?!?:\s/i,Hj=new Set(["fix","hotfix","bugfix","revert"]),Wj=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),sT=/\bBP-[A-Z]*\d+\b/i,qj=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);Kj=[/(^|\/)\.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)\//],Gj=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],zj=[/\.(json|jsonc|json5|ya?ml|toml|ini|cfg|conf|properties|env|example)$/i,/(^|\/)\.[^/]+$/,/(^|\/)\.github\//,/(^|\/)(Dockerfile|Makefile|Procfile|fly\.toml)$/];lh=e=>String(e??"").replace(/\s+/g," ").trim(),Gu=400;dn=e=>Math.round(e*1e4)/1e4,ah=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as eL}from"node:child_process";import{promisify as tL}from"node:util";function mT(e,t=Date.now()){return Vp(e,t)??0}function rL(e,t,n){for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="cost.recorded"||o.boxId!==t||n!=null&&o.epoch!=null&&o.epoch!==n)continue;let s=o.payload?.model;if(s&&s!=="unknown")return s}return null}async function hT(e,t,{now:n=Date.now()}={}){let r=mT(t,n),o=await q(e);return Ju({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:rL(o,t.name,r)})}function oL(e,t){let n=null;for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="turn.user"||o.boxId!==t||o.actor!=="user")continue;let s=o.payload||{};if(s.note?.kind!=="task"){if(o.source==="orchestrator"&&typeof s.text=="string"&&s.text.trim())return{text:s.text,kind:s.kind??null};!n&&typeof s.promptHead=="string"&&s.promptHead.trim()&&(n={text:s.promptHead,kind:s.kind??null})}}return n}function sL(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=oL(n,t.name),c=i?Zn(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function aL(e,t){try{let{stdout:n}=await fh(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 iL(e){try{let{stdout:t}=await fh(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function wT(e,t,n,{cwd:r=t?.cwd,log:o=console,now:s=Date.now()}={}){if(!e?.id||!t?.name||!n||!r)return{recorded:!1,reason:"incomplete"};let a=await q(e);if(a.some(w=>w.type==="code.committed"&&w.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s;try{let{stdout:w}=await fh(r,["show","-s","--format=%ct",n]),m=Number(w.trim())*1e3;Number.isFinite(m)&&m>0&&(i=m)}catch{return{recorded:!1,reason:"unknown-sha"}}let c=mT(t,i),l=await aL(r,n),u=await iL(r),d=await M(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:u,...l,ts:i}}),p=null,f=!1;try{let w=await dT(r,n,{fixKey:na({trackId:e.id,boxId:t.name,epoch:c}),window:Qr,context:{...sL(e,t,a,c),ref:u,provider:t.agent??null}});if(w&&(p=await M(e,{type:"code.rework",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:d.id,payload:w}),!(e?.workspace?.kind==="worktree"&&!!e?.workspace?.branch)&&pT(w))){let g=Ki(w),y=w.origins.filter(x=>x.class==="rework").slice(0,3);await M(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:p.id,payload:{sha:n,subject:w.subject,linesReworked:g,origins:y.map(x=>({key:x.key,provider:x.provider,model:x.model,lines:x.lines,ageDays:x.ageDays})),heuristic:w.heuristic,intent:w.intent,ts:i}}),f=!0}}catch(w){o.warn?.(`[rework] ${e.id}: analysis of ${String(n).slice(0,7)} failed: ${w?.message||w}`)}return{recorded:!0,event:d,rework:p,offered:f}}function gT(e,t){let n=0;for(let r of e)r.payload?.sha===t&&(r.type==="rework.cause.answered"?n++:r.type==="rework.cause.retracted"&&n--);return n>0}async function yT(e,t,n){if(!qi.includes(n)&&n!==Vu)throw new Error(`bad cause "${n}" (${qi.join("|")}|${Vu})`);let r=await q(e),o=r.find(s=>s.type==="rework.cause.offered"&&s.payload?.sha===t);if(!o)throw new Error("unknown rework offer");if(gT(r,t))throw new Error("already answered");return M(e,{type:"rework.cause.answered",actor:"user",source:"orchestrator",boxId:o.boxId??null,causationId:o.id,payload:{sha:t,...Array.isArray(o.payload?.shas)?{shas:o.payload.shas}:{},cause:n,level:"B",ts:Date.now()}})}async function bT(e,t){let n=await q(e);if(!gT(n,t))throw new Error("no standing answer to retract");let r=[...n].reverse().find(o=>o.type==="rework.cause.answered"&&o.payload?.sha===t);return M(e,{type:"rework.cause.retracted",actor:"user",source:"orchestrator",boxId:r?.boxId??null,causationId:r?.id,payload:{sha:t,...Array.isArray(r?.payload?.shas)?{shas:r.payload.shas}:{},ts:Date.now()}})}async function Zu(e,{repo:t=null,number:n,title:r="",branch:o=null,url:s=null}={},{log:a=console,now:i=Date.now()}={}){try{if(!e?.id||n==null)return{offered:!1,reason:"incomplete"};let c=await q(e);if(c.some(x=>x.type==="rework.cause.offered"&&x.payload?.pr?.number===n&&(t==null||x.payload.pr.repo===t)))return{offered:!1,reason:"duplicate"};let l=new Set;for(let x of c)if(x.type==="rework.cause.offered")for(let b of Array.isArray(x.payload?.shas)?x.payload.shas:[x.payload?.sha])b&&l.add(b);let u=new Map;for(let x of c)x.type==="code.committed"&&x.payload?.sha&&u.set(x.payload.sha,x.payload.ref??null);let d=ph({heuristic:Yu({subject:r}),subject:r,ref:o}),p=[];for(let x of c){if(x.type!=="code.rework")continue;let b=x.payload||{};if(!b.sha||l.has(b.sha)||b.codeDelta===!1||o&&u.has(b.sha)&&u.get(b.sha)!==o)continue;let O=b.intent?.intent??"unknown";(ra.has(O)||O==="unknown"&&ra.has(d.intent))&&Ki(b)!==0&&p.push(b)}let f=p.reduce((x,b)=>x+Ki(b),0);if(f<dh)return{offered:!1,reason:"below-threshold"};let w=new Map;for(let x of p)for(let b of x.origins??[]){if(b.class!=="rework")continue;let O=w.get(b.key)??{key:b.key,provider:b.provider??null,model:b.model??null,lines:0,ageDays:b.ageDays};O.lines+=b.lines,O.ageDays=Math.min(O.ageDays,b.ageDays),w.set(b.key,O)}let m=p.map(x=>x.sha),g=p.map(x=>x.heuristic).find(x=>x&&x.level!=="C")??Yu({subject:r})??p.map(x=>x.heuristic).find(Boolean)??null,y=ra.has(d.intent)?d:p.find(x=>ra.has(x.intent?.intent))?.intent??d;return await M(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:null,payload:{sha:m[m.length-1],shas:m,pr:{repo:t,number:n,title:String(r||"").slice(0,200),url:s,branch:o},subject:String(r||"").slice(0,200)||p[p.length-1].subject,linesReworked:f,origins:[...w.values()].sort((x,b)=>b.lines-x.lines).slice(0,3),heuristic:g,intent:y,ts:i}}),{offered:!0,shas:m}}catch(c){return a.warn?.(`[rework] ${e?.id}: PR-level offer for #${n} failed: ${c?.message||c}`),{offered:!1,reason:"error"}}}var nL,fh,Qu=K(()=>{pe();Zl();Xu();nL=tL(eL),fh=(e,t)=>nL("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4})});import{execFile as cL}from"node:child_process";import{promisify as lL}from"node:util";async function mh(e,t,{midTurn:n=Ho,pollMs:r=uL,capMs:o=dL}={}){let s=Date.now()+o;for(;await n(e,t).catch(()=>!1);){if(Date.now()>=s)return!1;await new Promise(a=>setTimeout(a,r))}return!0}function AT(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){kT.lastIndex=n;let o=kT.exec(t);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=t.indexOf(`
195
- `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+yL(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 hh(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function _T(e){let t=AT(e),n=t.match(hL);if(!n)return null;let r=hh(t,n.index);return gL.test(r)?null:{repo:r.match(ET)?.[1]??null,head:r.match(bL)?.[1]??null}}function IT(e){let t=AT(e),n=t.match(wL);if(!n)return null;let r=hh(t,n.index),o=hh(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("-")){xL.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(ET)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function SL(e,t,{exclude:n=()=>!1}={}){let r=async i=>{rr("observer");let{stdout:c}=await xT("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",vL],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw Yr(l)&&Xr(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-pL&&!n(c)),s=await vn({slug:e}),a=o(await r(s));return!a.length&&s.GH_TOKEN&&(a=o(await r({}).catch(()=>[]))),a.sort((i,c)=>Date.parse(c.createdAt)-Date.parse(i.createdAt))}async function TL(e,t){if(t)return[t];let n=[];for(let r of $T(e)){let o=await _e(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await Jn().catch(()=>[])){let o=await _e(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function $T(e){let t=e.workspace;return t?.kind==="multi"?(t.repos??[]).map(n=>n?.base).filter(Boolean):[t?.base||e.cwd].filter(Boolean)}async function AL(e,t,n){let r=await ta(e).catch(()=>[e.workspace?.branch].filter(Boolean)),o=t?.head??null,s=c=>r.includes(c)||o&&c===o,a=c=>o!=null&&!s(c.headRefName)||kL(c.headRefName,e.id),i=[];for(let c of await TL(e,t?.repo??null)){let l;try{l=await SL(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await at(c,u.number);if(s(u.headRefName)){if(d&&d.trackId===e.id&&d.announced)return{settled:!0};if(d&&d.trackId!==e.id)continue;return{slug:c,pr:u}}d&&(d.trackId!==e.id||d.announced)||i.push({slug:c,pr:u})}}return i.length?(i.sort((c,l)=>Date.parse(l.pr.createdAt)-Date.parse(c.pr.createdAt)),i[0]):null}function RT(e){if(!e)return 0;let t=0;for(let n of sr)n.startsWith(`${e}|`)&&t++;return t}function OT(){for(let e of[...wh])e()}function MT(e,t,{delays:n=vT,turnEnd:r}={}){let o=_T(t.command);if(!o)return null;let s=!!IT(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(sr.has(a))return null;sr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(m=>{let g=()=>{clearTimeout(y),wh.delete(g),m()},y=setTimeout(g,l);wh.add(g)});let u=await AL(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:p}=u,{link:f,created:w}=await Ct({repo:d,number:p.number,trackId:e.id,url:p.url,headRef:p.headRefName,title:p.title,source:"observed"});return!w&&!(f?.trackId===e.id&&await tr(d,p.number))?null:(await mh(t.box,t.agent,r),await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"opened",number:p.number,url:p.url,title:p.title,branch:p.headRefName,repo:d,...s?{selfMerge:!0}:{}}}),p)}return null}finally{sr.delete(a)}})();return c.catch(()=>sr.delete(a)),c}function CT(e,t,{delays:n=vT,turnEnd:r,openedWait:o}={}){let s=IT(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(sr.has(a))return null;sr.add(a);let i=(async()=>{try{let c=s.repo,l=s.selector,u=l?.match(/github\.com\/([\w.-]+\/[\w.-]+)\/pull\/(\d+)/);u&&([,c,l]=u);let d=[];if(c)d=[c];else{let w=$T(e);if(w.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let m of w){let g=await _e(m).catch(()=>null);g&&!d.includes(g)&&d.push(g)}}if(l||=(await ta(e).catch(()=>[])).filter(w=>w!==e.workspace?.branch)[0]||e.workspace?.branch,!d.length||!l)return null;c=d[0];let p=async(w,m)=>{let g=await at(c,w.number);return g&&g.trackId!==e.id?null:(g||await Ct({repo:c,number:w.number,trackId:e.id,url:w.url,headRef:w.headRefName,title:w.title,source:"merge-observed"}),await Pi(c,w.number),m&&((await q(e).catch(()=>[])).some(b=>b.type==="pr.state.changed"&&(b.payload?.change==="auto-armed"||b.payload?.change==="merged")&&b.payload?.number===w.number)||(await mh(t.box,t.agent,r),await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:w.number,url:w.url,title:w.title,branch:w.headRefName,repo:c}}))),w)},f=null;for(let w of n){await new Promise(C=>setTimeout(C,w));let m=[];for(let C of d)try{rr("observer");let{stdout:U}=await xT("gh",["pr","view",String(l),"--repo",C,"--json",EL],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await vn({slug:C})}}),H=JSON.parse(U||"null");H?.number&&m.push({slug:C,pr:H})}catch(U){Yr(U)&&Xr(U)}let g=m.find(C=>C.pr.state==="MERGED")??(m.length===1?m[0]:null);if(!g)continue;c=g.slug;let y=g.pr;if(!y?.number)continue;if(y.state==="CLOSED")return null;if(y.state!=="MERGED"){if(f=y,s.auto)return p(y,!0);continue}let x=await at(c,y.number);if(x&&x.trackId!==e.id)return null;x||await Ct({repo:c,number:y.number,trackId:e.id,url:y.url,headRef:y.headRefName,title:y.title,source:"merge-observed"}),await mh(t.box,t.agent,r);let b=await q(e).catch(()=>[]);if(b.some(C=>C.type==="pr.state.changed"&&C.payload?.change==="merged"&&C.payload?.number===y.number))return null;let O=C=>C.some(U=>U.type==="pr.state.changed"&&U.payload?.change==="opened"&&U.payload?.number===y.number),I=0;if(!O(b)){if(_T(t.command)&&await tr(c,y.number)){let C=Date.now();I=C+1,await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:C,change:"opened",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c,selfMerge:!0}})}else if((await at(c,y.number))?.announced){let C=o?.capMs??fL,U=o?.pollMs??mL,H=Date.now()+C;for(;Date.now()<H&&(await new Promise(_=>setTimeout(_,U)),!O(await q(e).catch(()=>[]))););}}return await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Math.max(Date.now(),I),change:"merged",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c}}),await Zu(e,{repo:c,number:y.number,title:y.title,branch:y.headRefName,url:y.url}).catch(()=>{}),await ir(c,y.number).catch(()=>{}),await ar(c,y.number).catch(()=>{}),await Vr(c,y.number,"merged"),y}return f?p(f,!1):null}finally{sr.delete(a)}})();return i.catch(()=>sr.delete(a)),i}var xT,vT,uL,dL,pL,fL,mL,ST,TT,hL,wL,gL,kT,yL,ET,bL,kL,xL,vL,sr,wh,EL,ed=K(()=>{pe();Tr();pt();Bi();Rn();cr();Wi();Wo();Qu();xT=lL(cL),vT=[4e3,15e3,45e3],uL=2500,dL=5*6e4;pL=15e3,fL=9e4,mL=2e3,ST=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,TT=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,hL=new RegExp(`${ST}${TT}create\\b`),wL=new RegExp(`${ST}${TT}merge\\b`),gL=/\s--web\b/,kT=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,yL=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");ET=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,bL=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,kL=nT;xL=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);vL="number,url,title,headRefName,createdAt";sr=new Set;wh=new Set;EL="number,url,title,headRefName,state"});import _L from"node:fs/promises";import yh from"node:path";import IL from"node:os";function gh(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function td(e){let t=$L.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=gh(n,"from"),s=o?o.replace(/^uds:/,""):null,a=NT(s);return{socket:s,pid:a,name:gh(n,"from-name"),mode:gh(n,"from-mode"),text:r.trim()}}function NT(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function RL(){return process.env.CLAUDE_CONFIG_DIR?yh.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):yh.join(IL.homedir(),".claude","sessions")}async function OL(e){let t=NT(e);if(!t)return null;try{let n=await _L.readFile(yh.join(RL(),`${t}.json`),"utf8"),r=JSON.parse(n);return{pid:t,sessionId:r.sessionId??null,cwd:r.cwd??null,name:r.name??null,tmux:r.tmux??null}}catch{return null}}async function PT(e,t){let n=await OL(e?.socket),r=n?.cwd??null,o=null;if((n?.sessionId||r)&&typeof t=="function")try{o=await t(n?.sessionId??null,r)??null}catch{o=null}return{socket:e?.socket??null,pid:n?.pid??e?.pid??null,sessionId:n?.sessionId??null,cwd:r,tmux:n?.tmux??null,name:n?.name??e?.name??null,mode:e?.mode??null,trackId:o?.track?.id??null,trackName:o?.track?.name??null,boxId:o?.box?.name??null}}var $L,bh=K(()=>{$L=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function kh(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function xh({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!kh(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),DT);try{let a=await BT(`${Oe(r)}/v1/loops/${encodeURIComponent(e)}/report`,{method:"POST",headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN||""}`,"content-type":"application/json"},body:JSON.stringify({outcome:t,...n?{note:n}:{}}),signal:o.signal}),i=await a.json().catch(()=>({}));return a.ok?{ok:!0,source:"plane",status:a.status,run:i?.run||null}:{ok:!1,source:"plane",status:a.status,error:i?.error||`plane ${a.status}`}}catch(a){return{ok:!1,source:"unreachable",error:a?.message||String(a)}}finally{clearTimeout(s)}}async function jT(e,{provider:t=null,cls:n="other",status:r=null,text:o=""}={},{env:s=process.env,now:a=Date.now}={}){if(!e?.id||!String(e.name||"").startsWith("\u21BB"))return{ok:!1,source:"not-a-loop-track"};if(!kh(s))return{ok:!1,source:"unconfigured"};let i=nd.get(e.id)||0;if(a()-i<ML)return{ok:!1,source:"debounced"};nd.set(e.id,a());let c=await Gi({env:s}),l=c.loops.find(p=>p.trackId===e.id);if(!l)return nd.delete(e.id),{ok:!1,source:c.source==="plane"?"no-loop":c.source};let u=`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`.slice(0,500),d=await xh({loopId:l.id,outcome:"errored",note:u,env:s});return d.ok||nd.delete(e.id),{...d,loop:{id:l.id,name:l.name}}}async function Gi({env:e=process.env}={}){if(!kh(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),DT);try{let r=await BT(`${Oe(e)}/v1/loops`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`},signal:t.signal});if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json();return{loops:Array.isArray(o?.loops)?o.loops:[],source:"plane"}}catch(r){return{loops:[],source:"unreachable",error:r?.message||String(r)}}finally{clearTimeout(n)}}var DT,BT,ML,nd,vh=K(()=>{pt();DT=1e4,BT=(...e)=>fetch(...e);ML=10*6e4,nd=new Map});function LT(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function FT(e,t,n=Sh){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await NL(`${Oe(t)}${e}`,{headers:PL(t),signal:r.signal})}finally{clearTimeout(o)}}async function zi({env:e=process.env,force:t=!1,timeoutMs:n=Sh}={}){if(!LT(e))return{followups:[],source:"unconfigured"};if(!t&&qo&&Date.now()-qo.at<CL)return{followups:qo.followups,source:"cache"};try{let r=await FT("/v1/followups?deleted=1",e,n);if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json(),s=Array.isArray(o?.followups)?o.followups:[];return qo={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return qo?{followups:qo.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function UT(e,{env:t=process.env,timeoutMs:n=Sh}={}){if(!e)return{followup:null,source:"unconfigured"};if(!LT(t))return{followup:null,source:"unconfigured"};try{let r=await FT(`/v1/followups/${encodeURIComponent(e)}`,t,n);if(r.status===404)return{followup:null,source:"gone"};if(!r.ok)throw new Error(`plane ${r.status}`);return{followup:(await r.json())?.followup??null,source:"plane"}}catch(r){let o=qo?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var CL,Sh,qo,NL,PL,HT=K(()=>{pt();CL=6e4,Sh=5e3,qo=null,NL=(...e)=>fetch(...e);PL=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});async function eo(e,t){if(Th.has(e)){let n=new Error("offer already answered (answer in flight)");throw n.code="answer-in-flight",n}Th.add(e);try{return await t()}finally{Th.delete(e)}}var Th,Vi=K(()=>{Th=new Set});import{randomUUID as sa,createHash as DL}from"node:crypto";function GT(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function UL(e){for(let[t,n]of FL)if(t.test(String(e||"")))return`a standing prompt must not embed this Track's specifics (${n}) \u2014 the card supplies them at fire time; arm a one-shot with \`offer\` instead`;return null}function zT(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=oa(n.label).replace(/\s+/g," ");if(!r)throw new Error('label required (\u226460 chars, e.g. "Deploy to Pi")');if(r.length>WT)throw new Error(`label must be \u2264${WT} characters`);let o=oa(n.trigger)||(n.ship?"now":""),s=t?jL:KT.filter(u=>u!=="track.opened");if(!s.includes(o))throw new Error(`trigger must be one of ${s.join(" | ")}${t?" (a standing follow-up can't be `now` \u2014 it would fire every turn)":""}, got "${n.trigger??""}"`);let a=n.ship&&o==="now"?WL(n.ship):null,i=oa(n.prompt);if(!a&&!i)throw new Error("prompt required \u2014 the full instruction a fresh session could execute");if(Buffer.byteLength(i,"utf8")>qT)throw new Error(`prompt must be \u2264${qT} bytes`);if(t){let u=UL(i);if(u)throw new Error(u)}let c=oa(n.why).slice(0,BL)||null,l=t?HL(n.repo):null;return{label:r,prompt:i,trigger:o,why:c,...l?{repo:l}:{},...a?{ship:a}:{}}}function HL(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 WL(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):Ah.slice();for(let i of n)if(!Ah.includes(i))throw new Error(`ship.actions may only contain ${Ah.join(" | ")}, got "${i}"`);if(!n.length)throw new Error("ship.actions must name at least one of commit | push | pr");let r=t.rebase==null?"none":String(t.rebase).trim();if(!["offered","none"].includes(r))throw new Error(`ship.rebase must be "offered" or "none", got "${t.rebase}"`);let o=null;if(t.toPr!=null&&t.toPr!==""){let i=Number(t.toPr);if(!Number.isInteger(i)||i<=0)throw new Error(`ship.toPr must be a PR number, got "${t.toPr}"`);o=i}let s=oa(t.base)||null,a=null;if(t.repos!=null){if(!Array.isArray(t.repos))throw new Error("ship.repos must be an array of checkout names");a=t.repos.map(i=>oa(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function rd(e,{trigger:t=null}={}){let n=new Map;for(let r of e){let o=r.payload||{};if(r.type==="followup.armed"&&o.armId)o.replaces&&n.delete(o.replaces),n.set(o.armId,{...o,ts:o.ts??r.ts,boxId:r.boxId??null,provider:r.provider??null});else if(r.type==="followup.armed.cancelled"&&o.armId)n.delete(o.armId);else if(r.type==="followup.offered")for(let s of o.rows||[])s.armId&&n.delete(s.armId)}return[...n.values()].filter(r=>!t||r.trigger===t)}async function VT(e,t,{pull:n=zi,ship:r={}}={}){if(Ih(e))throw new Error("follow-ups don't fire on a loop's run Track \u2014 report the outcome with `bostrat-loop report` instead");let o=zT(t);if(o.ship)return{kind:"ship",...await zL(e,o,r)};let s={id:e.id,cwd:e.cwd},a=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,i={boxId:e.leadBox??null,provider:a?.agent??null};if(o.trigger==="now"){let g=sa(),y=sa();return await M(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:g,trigger:"now",label:o.label,prompt:o.prompt,why:o.why}}),await M(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:y,trigger:"now",repo:e.workspace?.repo||null,context:{},rows:[{armId:g,label:o.label,prompt:o.prompt,promptHash:Eh(o.prompt),origin:"agent",why:o.why}]}}),{kind:"now",armId:g,offerId:y,...o}}let c=e.workspace?.repo||null,{followups:l}=await n().catch(()=>({followups:[]})),u=GT(o.label),d=l.find(g=>g.status==="active"&&g.mode!=="off"&&g.trigger===o.trigger&&(g.repo==null||g.repo===c)&&g.dedupeKey===u);if(d)return{kind:"covered",covered:{id:d.id,label:d.label},...o};let p=await q(s),f=rd(p,{trigger:o.trigger}),w=f.length?f[f.length-1].armId:null,m=sa();return await M(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:m,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,...w?{replaces:w}:{}}}),{kind:"armed",armId:m,replaces:w,...o}}async function JT(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await q(n);if(!rd(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await M(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function YT(e,t,{pull:n=zi}={}){if(Ih(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=zT(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await q(s)).reduce((g,y)=>y.type==="followup.create.offered"?y.payload?.proposalId??g:y.type==="followup.create.answered"&&y.payload?.proposalId===g?null:g,null))throw new Error("a follow-up proposal is already waiting on the operator in this Track \u2014 one at a time");let{followups:c,source:l}=await n().catch(()=>({followups:[],source:"unreachable"}));if(l==="unreachable")throw new Error("plane unreachable \u2014 standing follow-ups live in the plane; try again shortly");let u=GT(r.label),d=c.filter(g=>g.dedupeKey===u&&g.trigger===r.trigger),p=d.find(g=>g.status==="deleted"),f=d.find(g=>g.status!=="deleted");if(f)throw new Error(`"${f.label}" (${_h[f.trigger]||f.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(p){let g=p.deletedAt?new Date(p.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${p.label}" on ${g} \u2014 do not re-propose it`)}let w=sa(),m=(e.boxes||[]).find(g=>g.name===e.leadBox)||null;return await M(s,{type:"followup.create.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:m?.agent??null,payload:{ts:Date.now(),proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why,origin:"agent"}}),{proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why}}async function XT(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await q(o),a=s.find(c=>c.type==="followup.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="followup.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await M(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("followupId required \u2014 the follow-up is created on the plane before the card is answered");let i=a.payload;return await M(o,{type:"followup.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,followupId:String(r),label:i.label,trigger:i.trigger,repo:i.repo??null}}),await M(o,{type:"followup.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",followupId:String(r)}}),{proposalId:t,action:"created",followupId:String(r)}}async function Ji(e,t,n={},{pull:r=zi}={}){if(!e||Ih(e))return null;let o={id:e.id,cwd:e.cwd},s=await q(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null;if(t==="pr.merged"){let p=m=>{let g=(m?.prs||[]).filter(y=>Number.isFinite(Number(y?.number))).map(y=>`${y?.repo??m?.repo??""}#${Number(y.number)}`);return Number.isFinite(Number(m?.prNumber))&&g.push(`${m?.repo??""}#${Number(m.prNumber)}`),g},f=new Set(p(n));if(s.some(m=>m.type==="followup.offered"&&m.payload?.trigger==="pr.merged"&&p(m.payload?.context).some(g=>f.has(g))))return null}let i=rd(s,{trigger:t}).map(p=>({armId:p.armId,label:p.label,prompt:p.prompt,promptHash:Eh(p.prompt),origin:"agent",why:p.why??null})),c=[];if(t!=="now"){let{followups:p}=await r().catch(()=>({followups:[]}));c=p.filter(f=>f.status==="active"&&f.mode!=="off"&&f.trigger===t&&(f.repo==null||f.repo===a)).sort((f,w)=>{let m=g=>g.stats?.offered?(g.stats.accepted||0)/g.stats.offered:0;return m(w)-m(f)||(f.origin==="operator"?-1:0)-(w.origin==="operator"?-1:0)||(w.createdAt||0)-(f.createdAt||0)}).map(f=>({followupId:f.id,label:f.label,promptPreview:qL(f.prompt),promptHash:Eh(f.prompt),origin:f.origin,repo:f.repo??null}))}let l=[...i,...c].slice(0,LL);if(!l.length)return null;let u=sa(),d={ts:Date.now(),offerId:u,trigger:t,repo:a,context:{...n,repo:a},rows:l};return await M(o,{type:"followup.offered",actor:"system",source:"orchestrator",payload:d}),d}function KL(e){let t=e?.context||{},n=Array.isArray(t.prs)&&t.prs.length?t.prs:t.prNumber?[{number:t.prNumber,title:t.prTitle,url:t.prUrl,repo:t.repo}]:[],r=o=>`PR #${o.number}${o.title?` "${o.title}"`:""}${o.url?` (${o.url})`:""}${o.repo?` on ${o.repo}`:""}`;switch(e?.trigger){case"pr.merged":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} merged:`:"Follow-up the operator tapped after this Track's PR merged:";case"pr.opened":return n.length?`Follow-up the operator tapped after ${n.map(r).join(" and ")} opened:`:"Follow-up the operator tapped after this Track's PR opened:";case"checks.green":return n.length?`Follow-up the operator tapped after CI went green on ${n.map(r).join(" and ")}:`:"Follow-up the operator tapped after CI went green:";case"ship.done":return"Follow-up the operator tapped after the ship you just ran completed:";default:return"Follow-up the operator tapped:"}}async function ZT(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null}={},s={}){if(!t)throw new Error("offerId required");return eo(`fu:${e.id}:${t}`,()=>GL(e,{offerId:t,followupId:n,armId:r,promoted:o},s))}async function GL(e,{offerId:t,followupId:n,armId:r,promoted:o},s){let{sayToLead:a,unarchiveTrack:i,getFollowup:c=UT}=s,l={id:e.id,cwd:e.cwd},u=await q(l),d=u.find(b=>b.type==="followup.offered"&&b.payload?.offerId===t);if(!d)throw new Error("unknown offer");if(u.some(b=>b.type==="followup.answered"&&b.payload?.offerId===t))throw new Error("offer already answered");let p=d.payload.rows||[],f=b=>M(l,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...b}});if(!n&&!r)return await f({action:"dismiss",followupIds:p.map(b=>b.followupId).filter(Boolean),armIds:p.map(b=>b.armId).filter(Boolean)}),{offerId:t,action:"dismiss"};let w=null,m=null;if(n){if(!p.some(I=>I.followupId===n))throw new Error("that follow-up is not on this card");let{followup:b,source:O}=await c(n);if(O==="unreachable")throw new Error("plane unreachable \u2014 the follow-up's current prompt can't be read; try again shortly");if(!b||b.status!=="active"){await f({action:"removed",followupId:n});let I=new Error("removed in Settings since it was offered");throw I.code="removed",I}w=b.prompt,m=b.label}else{let b=p.find(I=>I.armId===r);if(!b)throw new Error("that arm is not on this card");if(w=u.find(I=>I.type==="followup.armed"&&I.payload?.armId===r)?.payload?.prompt??b.prompt,m=b.label,!w)throw new Error("the arm's prompt is missing from the log")}let g=!1;if(e.archivedAt){if(!i)throw new Error("this Track is archived");await i(e.id,{freshSession:!0}),g=!0}if(!a)throw new Error("sayToLead unavailable");let y=`${KL(d.payload)}
194
+ `)}}async function JA(e,t,{fixKey:n=null,window:r=io,resolveOrigin:o=null,context:s={}}={}){let a=await qA(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=UA(a.message),l=n?md(n):c.epoch,u=l?ga(l):null,{stdout:d}=await Hm(e,["diff","-U0","--no-color","-M","-C",i,t]),p=CL(d),f=0,w=0,h=0,g=0,y=0,x=0,b=0,I=new Map;for(let R of p){if(R.binary)continue;let L=R.oldPath||R.newPath||"",V=R.deleted.reduce((W,[,te])=>W+te,0),O=ML(L);if(O==="excluded"){h+=V;continue}if(O==="docs"){g+=V,y+=R.added;continue}if(O==="config"){x+=V;continue}f+=R.added;let S=new Set;for(let W of R.hunks||[])for(let te of PL(W))S.add(te);b+=S.size;let M=[];for(let[W,te]of R.deleted)for(let pe=W;pe<W+te;pe++)S.has(pe)||M.push(pe);if(w+=M.length,!R.oldPath||!M.length)continue;let H;try{let W=["blame","-w","-M","-C","--line-porcelain"];for(let[te,pe]of DL(M))W.push("-L",`${te},${te+pe-1}`);W.push(i,"--",R.oldPath),H=BL((await Hm(e,W)).stdout)}catch{continue}for(let{sha:W,time:te}of H.values()){let pe=I.get(W)??{lines:0,time:te};pe.lines+=1,I.set(W,pe)}}let _=[],N=0,U=new Map;for(let[R,{lines:L,time:V}]of I){let O=U.get(R);if(!O){try{O=await qA(e,R)}catch{O=null}U.set(R,O)}let S=O?UA(O.message):{epoch:null},M=S.epoch,H=S.provider,W=S.model;if(!M&&o){let re=await o(R,O);re?.trackId&&re?.boxId!=null&&(M={trackId:re.trackId,boxId:re.boxId,epoch:re.epoch??0},H=H??re.provider??null,W=W??re.model??null)}if(!M){N+=L;continue}let te=Number.isFinite(V)?V:O?.ts??a.ts,pe=Math.max(0,(a.ts-te)/wL),Ie=ga(M),Oe=Ie===u?"self":kL(pe,r);_.push({sha:R,key:Ie,trackId:M.trackId,boxId:M.boxId,epoch:M.epoch,provider:H??null,model:W??null,lines:L,ageDays:Math.round(pe*100)/100,class:Oe,decay:Oe==="rework"?1:Oe==="drift"?Math.round(xL(pe,{window:r})*1e3)/1e3:0})}_.sort((R,L)=>L.lines-R.lines);let j=yd({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),T=Gm({heuristic:j,subject:a.subject,ref:s.ref??null,promptKind:s.promptKind??null,fixerCategory:s.fixerCategory??null,ticketKind:s.ticketKind??null});return{sha:a.sha,parent:i,subject:a.subject.slice(0,200),ts:a.ts,fixKey:u,fixProvider:c.provider??s.provider??null,fixModel:c.model??s.model??null,window:r,added:f,deleted:w,excludedDeleted:h,cosmeticDeleted:b,docsDeleted:g,docsAdded:y,configDeleted:x,codeDelta:f+w+b>0,origins:_,unattributedLines:N,ghost:w===0&&f>0,heuristic:j,intent:T}}function YA(e,{minLines:t=Km}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return ya.has(n)?cc(e)>=t:!1}function cc(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function Um(e){let t=e.genUsd;return{...e,genUsd:fn(t),reworkChargedUsd:fn(e.reworkChargedUsd),reworkPendingUsd:fn(e.reworkPendingUsd),trueUsd:fn(t+e.reworkChargedUsd),multiplier:t>0?fn((t+e.reworkChargedUsd)/t):null}}function XA(e,{window:t=io,boxMeta:n={}}={}){let r=e||[],o=r.filter(T=>T.type==="cost.recorded"),s=r.filter(T=>T.type==="code.committed"),a=r.filter(T=>T.type==="code.rework"),i=T=>Array.isArray(T?.shas)&&T.shas.length?T.shas:T?.sha?[T.sha]:[],c=new Map,l=new Set;for(let T of r)if(T.type==="rework.cause.offered")for(let R of i(T.payload))l.add(R);else if(T.type==="rework.cause.answered"&&T.payload?.cause)for(let R of i(T.payload))c.set(R,T.payload.cause);else if(T.type==="rework.cause.retracted")for(let R of i(T.payload))c.delete(R);let u={},d=(T,R,L)=>ga({trackId:T,boxId:R,epoch:L??0}),p=(T,R={})=>{if(!u[T]){let V=md(T)||{};u[T]={key:T,...V,provider:null,model:null,...Fm()}}let L=u[T];return R.provider&&!L.provider&&(L.provider=R.provider),R.model&&!L.model&&(L.model=R.model),L};for(let T of o){if(!T.boxId)continue;let R=d(T.trackId,T.boxId,T.epoch),{usd:L,model:V}=Jt(T),O=p(R,{provider:T.provider,model:V!=="unknown"?V:null});O.genUsd+=L}let f=new Map;for(let T of s){let R=`${T.trackId}/${T.boxId}`;(f.get(R)??f.set(R,[]).get(R)).push({...T,ts:T.payload?.ts??T.ts})}for(let T of f.values())T.sort((R,L)=>R.ts-L.ts);let w=(T,R,L,V)=>{let O=f.get(`${T}/${R}`)||[],S=-1/0;for(let W of O)W.ts<V&&(S=W.ts);let M=0,H=0;for(let W of o)W.trackId!==T||W.boxId!==R||(W.epoch??0)===(L??0)&&(W.ts<=S||W.ts>V||(M+=Jt(W).usd,H++));return{usd:M,turns:H,from:Number.isFinite(S)?S:null}},h={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0,planned:0},g={A:0,B:0,C:0,E:0,none:0},y={fix:0,"likely-fix":0,planned:0,unknown:0},x=0,b=[],I=[],_={},N={},U=new Set;for(let T of a){let R=T.payload||{};if(!R.sha||U.has(R.sha))continue;if(U.add(R.sha),R.codeDelta===!1){x++;continue}let L=md(R.fixKey)||{trackId:T.trackId,boxId:T.boxId,epoch:T.epoch??0},{usd:V,turns:O}=w(L.trackId,L.boxId,L.epoch,R.ts??T.ts),S=yL.includes(R.intent?.intent)?R.intent.intent:"unknown";y[S]+=1;let M=null;c.has(R.sha)?M={cause:c.get(R.sha),level:"B",basis:"operator"}:(R.heuristic?.level&&R.heuristic.level!=="C"||R.heuristic)&&(M=R.heuristic);let H=M?.level??"none";g[H]=(g[H]||0)+1;let W=gL.has(H),te=Number(R.deleted)||0,pe=Array.isArray(R.origins)?R.origins:[],Ie=pe.filter(re=>re.class==="rework").reduce((re,Ne)=>re+Ne.lines,0),Oe={sha:R.sha,subject:R.subject??"",ts:R.ts??T.ts,trackId:T.trackId,fixKey:R.fixKey??null,fixProvider:R.fixProvider??T.provider??null,fixUsd:fn(V),fixTurns:O,linesReworked:Ie,unattributedLines:Number(R.unattributedLines)||0,ghost:R.ghost===!0,intent:{intent:S,basis:R.intent?.basis??null},verdict:M?{cause:M.cause,level:H,basis:M.basis??null}:null,charged:fn(0),origins:[]};if(S==="planned"||M?.cause===wd){h.planned+=V;for(let re of pe)re.class==="rework"&&Oe.origins.push({key:re.key,provider:re.provider??null,model:re.model??null,lines:re.lines,ageDays:re.ageDays,class:re.class,usd:0})}else if(R.ghost||te===0)h.ghost+=V;else{let re=0;for(let X of pe){let G=X.lines/te,fe=V*G;if(re+=fe,X.class==="self"){h.self+=fe;continue}let be=X.class==="rework"?1:Number(X.decay)||0,xe=fe*be;if(h.decayed+=fe-xe,xe<=0)continue;let Ke=p(X.key,{provider:X.provider,model:X.model});Ke.fixes+=1,Ke.linesReworked+=X.class==="rework"?X.lines:0;let le=M?.cause&&ic.includes(M.cause)?M.cause:"unclassified";Ke.causes[le]+=1,W?(Ke.reworkChargedUsd+=xe,h.charged+=xe,Oe.charged=fn(Oe.charged+xe)):(Ke.reworkPendingUsd+=xe,h.pending+=xe),Oe.origins.push({key:X.key,provider:Ke.provider,model:Ke.model,lines:X.lines,ageDays:X.ageDays,class:X.class,usd:fn(xe)})}let Ne=Math.max(0,V-re);h.unattributed+=Ne}b.push(Oe),!c.has(R.sha)&&l.has(R.sha)&&I.push(R.sha)}for(let T of Object.values(u)){let R=T.provider||"unknown",L=T.model||"unknown",V=O=>{O.genUsd+=T.genUsd,O.reworkChargedUsd+=T.reworkChargedUsd,O.reworkPendingUsd+=T.reworkPendingUsd,O.linesReworked+=T.linesReworked,O.fixes+=T.fixes;for(let S of Object.keys(O.causes))O.causes[S]+=T.causes[S]};V(_[R]||=Fm()),V(N[L]||=Fm())}b.sort((T,R)=>R.ts-T.ts);let j=Object.values(u).map(T=>{let R=n[`${T.trackId}/${T.boxId}`]||{};return Um({...T,trackName:R.trackName??null,label:R.label??null})}).sort((T,R)=>R.reworkChargedUsd+R.reworkPendingUsd-(T.reworkChargedUsd+T.reworkPendingUsd)||R.genUsd-T.genUsd);return{window:t,basis:`rework = code lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old (docs/config churn and in-place updates \u2265${VA} similar are counted, not blamed); fix cost = the fixing box's turns since its previous commit; charged only on an authoritative / operator / self-reported cause; planned work (follow-up, blueprint item, feat:/docs: prefix, non-fix prompt) is generation cost`,intents:y,noCodeDelta:x,byEpoch:Object.fromEntries(j.map(T=>[T.key,T])),epochs:j,byProvider:Object.fromEntries(Object.entries(_).map(([T,R])=>[T,Um(R)])),byModel:Object.fromEntries(Object.entries(N).map(([T,R])=>[T,Um(R)])),buckets:Object.fromEntries(Object.entries(h).map(([T,R])=>[T,fn(R)])),fixUsdTotal:fn(Object.values(h).reduce((T,R)=>T+R,0)),fixes:b,verdicts:g,pendingTaps:I,commits:s.length}}var hL,mL,Hm,KA,GA,zA,wL,io,qm,Km,ic,wd,gL,yL,ya,VA,bL,vL,HA,SL,AL,TL,EL,_L,WA,IL,$L,RL,OL,Wm,hd,fn,Fm,bd=q(()=>{Gr();hL=fL(pL),mL=64*1024*1024,Hm=(e,t)=>hL("git",["-C",e,...t],{maxBuffer:mL,timeout:6e4}),KA="Bostrat-Epoch",GA="Bostrat-Model",zA="Bostrat-Fix-Cause",wL=24*36e5,io=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,qm=90,Km=3,ic=Object.freeze(["defect","design","requirements","style"]),wd="not-a-fix",gL=new Set(["A","B","E"]),yL=Object.freeze(["fix","likely-fix","planned","unknown"]),ya=new Set(["fix","likely-fix"]),VA=.8;bL={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};vL=/^revert\b|^revert "/i,HA=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,SL=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,AL=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;TL=/^([a-z]+)(\([^)]*\))?!?:\s/i,EL=new Set(["fix","hotfix","bugfix","revert"]),_L=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),WA=/\bBP-[A-Z]*\d+\b/i,IL=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);$L=[/(^|\/)\.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)\//],RL=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],OL=[/\.(json|jsonc|json5|ya?ml|toml|ini|cfg|conf|properties|env|example)$/i,/(^|\/)\.[^/]+$/,/(^|\/)\.github\//,/(^|\/)(Dockerfile|Makefile|Procfile|fly\.toml)$/];Wm=e=>String(e??"").replace(/\s+/g," ").trim(),hd=400;fn=e=>Math.round(e*1e4)/1e4,Fm=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as jL}from"node:child_process";import{promisify as LL}from"node:util";function ZA(e,t=Date.now()){return Rf(e,t)??0}function UL(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 QA(e,t,{now:n=Date.now()}={}){let r=ZA(t,n),o=await K(e);return gd({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:UL(o,t.name,r)})}function HL(e,t){let n=null;for(let r=e.length-1;r>=0;r--){let o=e[r];if(o.type!=="turn.user"||o.boxId!==t||o.actor!=="user")continue;let s=o.payload||{};if(s.note?.kind!=="task"){if(o.source==="orchestrator"&&typeof s.text=="string"&&s.text.trim())return{text:s.text,kind:s.kind??null};!n&&typeof s.promptHead=="string"&&s.promptHead.trim()&&(n={text:s.promptHead,kind:s.kind??null})}}return n}function WL(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=HL(n,t.name),c=i?tr(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function qL(e,t){try{let{stdout:n}=await zm(e,["show","--shortstat","--format=",t]),r=/(\d+) files? changed/.exec(n),o=/(\d+) insertions?\(\+\)/.exec(n),s=/(\d+) deletions?\(-\)/.exec(n);return{files:r?Number(r[1]):0,insertions:o?Number(o[1]):0,deletions:s?Number(s[1]):0}}catch{return{files:0,insertions:0,deletions:0}}}async function KL(e){try{let{stdout:t}=await zm(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function eT(e,t,n,{cwd:r=t?.cwd,log:o=console,now:s=Date.now()}={}){if(!e?.id||!t?.name||!n||!r)return{recorded:!1,reason:"incomplete"};let a=await K(e);if(a.some(w=>w.type==="code.committed"&&w.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s;try{let{stdout:w}=await zm(r,["show","-s","--format=%ct",n]),h=Number(w.trim())*1e3;Number.isFinite(h)&&h>0&&(i=h)}catch{return{recorded:!1,reason:"unknown-sha"}}let c=ZA(t,i),l=await qL(r,n),u=await KL(r),d=await C(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:u,...l,ts:i}}),p=null,f=!1;try{let w=await JA(r,n,{fixKey:ga({trackId:e.id,boxId:t.name,epoch:c}),window:io,context:{...WL(e,t,a,c),ref:u,provider:t.agent??null}});if(w&&(p=await C(e,{type:"code.rework",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:d.id,payload:w}),!(e?.workspace?.kind==="worktree"&&!!e?.workspace?.branch)&&YA(w))){let g=cc(w),y=w.origins.filter(x=>x.class==="rework").slice(0,3);await C(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:p.id,payload:{sha:n,subject:w.subject,linesReworked:g,origins:y.map(x=>({key:x.key,provider:x.provider,model:x.model,lines:x.lines,ageDays:x.ageDays})),heuristic:w.heuristic,intent:w.intent,ts:i}}),f=!0}}catch(w){o.warn?.(`[rework] ${e.id}: analysis of ${String(n).slice(0,7)} failed: ${w?.message||w}`)}return{recorded:!0,event:d,rework:p,offered:f}}function tT(e,t){let n=0;for(let r of e)r.payload?.sha===t&&(r.type==="rework.cause.answered"?n++:r.type==="rework.cause.retracted"&&n--);return n>0}async function nT(e,t,n){if(!ic.includes(n)&&n!==wd)throw new Error(`bad cause "${n}" (${ic.join("|")}|${wd})`);let r=await K(e),o=r.find(s=>s.type==="rework.cause.offered"&&s.payload?.sha===t);if(!o)throw new Error("unknown rework offer");if(tT(r,t))throw new Error("already answered");return C(e,{type:"rework.cause.answered",actor:"user",source:"orchestrator",boxId:o.boxId??null,causationId:o.id,payload:{sha:t,...Array.isArray(o.payload?.shas)?{shas:o.payload.shas}:{},cause:n,level:"B",ts:Date.now()}})}async function rT(e,t){let n=await K(e);if(!tT(n,t))throw new Error("no standing answer to retract");let r=[...n].reverse().find(o=>o.type==="rework.cause.answered"&&o.payload?.sha===t);return C(e,{type:"rework.cause.retracted",actor:"user",source:"orchestrator",boxId:r?.boxId??null,causationId:r?.id,payload:{sha:t,...Array.isArray(r?.payload?.shas)?{shas:r.payload.shas}:{},ts:Date.now()}})}async function kd(e,{repo:t=null,number:n,title:r="",branch:o=null,url:s=null}={},{log:a=console,now:i=Date.now()}={}){try{if(!e?.id||n==null)return{offered:!1,reason:"incomplete"};let c=await K(e);if(c.some(x=>x.type==="rework.cause.offered"&&x.payload?.pr?.number===n&&(t==null||x.payload.pr.repo===t)))return{offered:!1,reason:"duplicate"};let l=new Set;for(let x of c)if(x.type==="rework.cause.offered")for(let b of Array.isArray(x.payload?.shas)?x.payload.shas:[x.payload?.sha])b&&l.add(b);let u=new Map;for(let x of c)x.type==="code.committed"&&x.payload?.sha&&u.set(x.payload.sha,x.payload.ref??null);let d=Gm({heuristic:yd({subject:r}),subject:r,ref:o}),p=[];for(let x of c){if(x.type!=="code.rework")continue;let b=x.payload||{};if(!b.sha||l.has(b.sha)||b.codeDelta===!1||o&&u.has(b.sha)&&u.get(b.sha)!==o)continue;let I=b.intent?.intent??"unknown";(ya.has(I)||I==="unknown"&&ya.has(d.intent))&&cc(b)!==0&&p.push(b)}let f=p.reduce((x,b)=>x+cc(b),0);if(f<Km)return{offered:!1,reason:"below-threshold"};let w=new Map;for(let x of p)for(let b of x.origins??[]){if(b.class!=="rework")continue;let I=w.get(b.key)??{key:b.key,provider:b.provider??null,model:b.model??null,lines:0,ageDays:b.ageDays};I.lines+=b.lines,I.ageDays=Math.min(I.ageDays,b.ageDays),w.set(b.key,I)}let h=p.map(x=>x.sha),g=p.map(x=>x.heuristic).find(x=>x&&x.level!=="C")??yd({subject:r})??p.map(x=>x.heuristic).find(Boolean)??null,y=ya.has(d.intent)?d:p.find(x=>ya.has(x.intent?.intent))?.intent??d;return await C(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:null,payload:{sha:h[h.length-1],shas:h,pr:{repo:t,number:n,title:String(r||"").slice(0,200),url:s,branch:o},subject:String(r||"").slice(0,200)||p[p.length-1].subject,linesReworked:f,origins:[...w.values()].sort((x,b)=>b.lines-x.lines).slice(0,3),heuristic:g,intent:y,ts:i}}),{offered:!0,shas:h}}catch(c){return a.warn?.(`[rework] ${e?.id}: PR-level offer for #${n} failed: ${c?.message||c}`),{offered:!1,reason:"error"}}}var FL,zm,xd=q(()=>{he();bu();bd();FL=LL(jL),zm=(e,t)=>FL("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4})});import{execFile as GL}from"node:child_process";import{promisify as zL}from"node:util";async function Vm(e,t,{midTurn:n=os,pollMs:r=VL,capMs:o=JL}={}){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 lT(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){oT.lastIndex=n;let o=oT.exec(t);if(!o)break;n=o.index+o[0].length;let s=o[1]==="-",a=o[2]??o[3]??o[4],i=t.indexOf(`
195
+ `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+nF(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 Jm(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function dT(e){let t=lT(e),n=t.match(QL);if(!n)return null;let r=Jm(t,n.index);return tF.test(r)?null:{repo:r.match(uT)?.[1]??null,head:r.match(rF)?.[1]??null}}function pT(e){let t=lT(e),n=t.match(eF);if(!n)return null;let r=Jm(t,n.index),o=Jm(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("-")){sF.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(uT)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function iF(e,t,{exclude:n=()=>!1}={}){let r=async i=>{ar("observer");let{stdout:c}=await sT("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",aF],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw oo(l)&&so(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-YL&&!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 cF(e,t){if(t)return[t];let n=[];for(let r of fT(e)){let o=await _e(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await Xn().catch(()=>[])){let o=await _e(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function fT(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 lF(e,t,n){let r=await wa(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)||oF(c.headRefName,e.id),i=[];for(let c of await cF(e,t?.repo??null)){let l;try{l=await iF(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await ct(c,u.number);if(s(u.headRefName)){if(d&&d.trackId===e.id&&d.announced)return{settled:!0};if(d&&d.trackId!==e.id)continue;return{slug:c,pr:u}}d&&(d.trackId!==e.id||d.announced)||i.push({slug:c,pr:u})}}return i.length?(i.sort((c,l)=>Date.parse(l.pr.createdAt)-Date.parse(c.pr.createdAt)),i[0]):null}function hT(e){if(!e)return 0;let t=0;for(let n of cr)n.startsWith(`${e}|`)&&t++;return t}function mT(){for(let e of[...Ym])e()}function wT(e,t,{delays:n=aT,turnEnd:r}={}){let o=dT(t.command);if(!o)return null;let s=!!pT(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(cr.has(a))return null;cr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(h=>{let g=()=>{clearTimeout(y),Ym.delete(g),h()},y=setTimeout(g,l);Ym.add(g)});let u=await lF(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:p}=u,{link:f,created:w}=await Lt({repo:d,number:p.number,trackId:e.id,url:p.url,headRef:p.headRefName,title:p.title,source:"observed"});return!w&&!(f?.trackId===e.id&&await or(d,p.number))?null:(await Vm(t.box,t.agent,r),await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"opened",number:p.number,url:p.url,title:p.title,branch:p.headRefName,repo:d,...s?{selfMerge:!0}:{}}}),p)}return null}finally{cr.delete(a)}})();return c.catch(()=>cr.delete(a)),c}function gT(e,t,{delays:n=aT,turnEnd:r,openedWait:o}={}){let s=pT(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(cr.has(a))return null;cr.add(a);let i=(async()=>{try{let c=s.repo,l=s.selector,u=l?.match(/github\.com\/([\w.-]+\/[\w.-]+)\/pull\/(\d+)/);u&&([,c,l]=u);let d=[];if(c)d=[c];else{let w=fT(e);if(w.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let h of w){let g=await _e(h).catch(()=>null);g&&!d.includes(g)&&d.push(g)}}if(l||=(await wa(e).catch(()=>[])).filter(w=>w!==e.workspace?.branch)[0]||e.workspace?.branch,!d.length||!l)return null;c=d[0];let p=async(w,h)=>{let g=await ct(c,w.number);return g&&g.trackId!==e.id?null:(g||await Lt({repo:c,number:w.number,trackId:e.id,url:w.url,headRef:w.headRefName,title:w.title,source:"merge-observed"}),await Zi(c,w.number),h&&((await K(e).catch(()=>[])).some(b=>b.type==="pr.state.changed"&&(b.payload?.change==="auto-armed"||b.payload?.change==="merged")&&b.payload?.number===w.number)||(await Vm(t.box,t.agent,r),await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Date.now(),change:"auto-armed",number:w.number,url:w.url,title:w.title,branch:w.headRefName,repo:c}}))),w)},f=null;for(let w of n){await new Promise(N=>setTimeout(N,w));let h=[];for(let N of d)try{ar("observer");let{stdout:U}=await sT("gh",["pr","view",String(l),"--repo",N,"--json",uF],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await Sn({slug:N})}}),j=JSON.parse(U||"null");j?.number&&h.push({slug:N,pr:j})}catch(U){oo(U)&&so(U)}let g=h.find(N=>N.pr.state==="MERGED")??(h.length===1?h[0]:null);if(!g)continue;c=g.slug;let y=g.pr;if(!y?.number)continue;if(y.state==="CLOSED")return null;if(y.state!=="MERGED"){if(f=y,s.auto)return p(y,!0);continue}let x=await ct(c,y.number);if(x&&x.trackId!==e.id)return null;x||await Lt({repo:c,number:y.number,trackId:e.id,url:y.url,headRef:y.headRefName,title:y.title,source:"merge-observed"}),await Vm(t.box,t.agent,r);let b=await K(e).catch(()=>[]);if(b.some(N=>N.type==="pr.state.changed"&&N.payload?.change==="merged"&&N.payload?.number===y.number))return null;let I=N=>N.some(U=>U.type==="pr.state.changed"&&U.payload?.change==="opened"&&U.payload?.number===y.number),_=0;if(!I(b)){if(dT(t.command)&&await or(c,y.number)){let N=Date.now();_=N+1,await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:N,change:"opened",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c,selfMerge:!0}})}else if((await ct(c,y.number))?.announced){let N=o?.capMs??XL,U=o?.pollMs??ZL,j=Date.now()+N;for(;Date.now()<j&&(await new Promise(T=>setTimeout(T,U)),!I(await K(e).catch(()=>[]))););}}return await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:Math.max(Date.now(),_),change:"merged",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c}}),await kd(e,{repo:c,number:y.number,title:y.title,branch:y.headRefName,url:y.url}).catch(()=>{}),await ur(c,y.number).catch(()=>{}),await lr(c,y.number).catch(()=>{}),await no(c,y.number,"merged"),y}return f?p(f,!1):null}finally{cr.delete(a)}})();return i.catch(()=>cr.delete(a)),i}var sT,aT,VL,JL,YL,XL,ZL,iT,cT,QL,eF,tF,oT,nF,uT,rF,oF,sF,aF,cr,Ym,uF,vd=q(()=>{he();Or();mt();ec();Mn();dr();ac();ss();xd();sT=zL(GL),aT=[4e3,15e3,45e3],VL=2500,JL=5*6e4;YL=15e3,XL=9e4,ZL=2e3,iT=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,cT=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,QL=new RegExp(`${iT}${cT}create\\b`),eF=new RegExp(`${iT}${cT}merge\\b`),tF=/\s--web\b/,oT=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,nF=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");uT=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,rF=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,oF=FA;sF=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);aF="number,url,title,headRefName,createdAt";cr=new Set;Ym=new Set;uF="number,url,title,headRefName,state"});import dF from"node:fs/promises";import Zm from"node:path";import pF from"node:os";function Xm(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function Sd(e){let t=fF.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=Xm(n,"from"),s=o?o.replace(/^uds:/,""):null,a=yT(s);return{socket:s,pid:a,name:Xm(n,"from-name"),mode:Xm(n,"from-mode"),text:r.trim()}}function yT(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function hF(){return process.env.CLAUDE_CONFIG_DIR?Zm.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):Zm.join(pF.homedir(),".claude","sessions")}async function mF(e){let t=yT(e);if(!t)return null;try{let n=await dF.readFile(Zm.join(hF(),`${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 bT(e,t){let n=await mF(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 fF,Qm=q(()=>{fF=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function ew(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function tw({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!ew(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),kT);try{let a=await xT(`${Re(r)}/v1/loops/${encodeURIComponent(e)}/report`,{method:"POST",headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN||""}`,"content-type":"application/json"},body:JSON.stringify({outcome:t,...n?{note:n}:{}}),signal:o.signal}),i=await a.json().catch(()=>({}));return a.ok?{ok:!0,source:"plane",status:a.status,run:i?.run||null}:{ok:!1,source:"plane",status:a.status,error:i?.error||`plane ${a.status}`}}catch(a){return{ok:!1,source:"unreachable",error:a?.message||String(a)}}finally{clearTimeout(s)}}async function vT(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(!ew(s))return{ok:!1,source:"unconfigured"};let i=Ad.get(e.id)||0;if(a()-i<wF)return{ok:!1,source:"debounced"};Ad.set(e.id,a());let c=await lc({env:s}),l=c.loops.find(p=>p.trackId===e.id);if(!l)return Ad.delete(e.id),{ok:!1,source:c.source==="plane"?"no-loop":c.source};let u=`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`.slice(0,500),d=await tw({loopId:l.id,outcome:"errored",note:u,env:s});return d.ok||Ad.delete(e.id),{...d,loop:{id:l.id,name:l.name}}}async function lc({env:e=process.env}={}){if(!ew(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),kT);try{let r=await xT(`${Re(e)}/v1/loops`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`},signal:t.signal});if(!r.ok)throw new Error(`plane ${r.status}`);let o=await r.json();return{loops:Array.isArray(o?.loops)?o.loops:[],source:"plane"}}catch(r){return{loops:[],source:"unreachable",error:r?.message||String(r)}}finally{clearTimeout(n)}}var kT,xT,wF,Ad,nw=q(()=>{mt();kT=1e4,xT=(...e)=>fetch(...e);wF=10*6e4,Ad=new Map});function ST(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function AT(e,t,n=rw){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await yF(`${Re(t)}${e}`,{headers:bF(t),signal:r.signal})}finally{clearTimeout(o)}}async function uc({env:e=process.env,force:t=!1,timeoutMs:n=rw}={}){if(!ST(e))return{followups:[],source:"unconfigured"};if(!t&&as&&Date.now()-as.at<gF)return{followups:as.followups,source:"cache"};try{let r=await AT("/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 as={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return as?{followups:as.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function TT(e,{env:t=process.env,timeoutMs:n=rw}={}){if(!e)return{followup:null,source:"unconfigured"};if(!ST(t))return{followup:null,source:"unconfigured"};try{let r=await AT(`/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=as?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var gF,rw,as,yF,bF,ET=q(()=>{mt();gF=6e4,rw=5e3,as=null,yF=(...e)=>fetch(...e);bF=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});async function co(e,t){if(ow.has(e)){let n=new Error("offer already answered (answer in flight)");throw n.code="answer-in-flight",n}ow.add(e);try{return await t()}finally{ow.delete(e)}}var ow,dc=q(()=>{ow=new Set});import{randomUUID as ka,createHash as kF}from"node:crypto";function RT(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function TF(e){for(let[t,n]of AF)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 OT(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=ba(n.label).replace(/\s+/g," ");if(!r)throw new Error('label required (\u226460 chars, e.g. "Deploy to Pi")');if(r.length>_T)throw new Error(`label must be \u2264${_T} characters`);let o=ba(n.trigger)||(n.ship?"now":""),s=t?vF:$T.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"?_F(n.ship):null,i=ba(n.prompt);if(!a&&!i)throw new Error("prompt required \u2014 the full instruction a fresh session could execute");if(Buffer.byteLength(i,"utf8")>IT)throw new Error(`prompt must be \u2264${IT} bytes`);if(t){let u=TF(i);if(u)throw new Error(u)}let c=ba(n.why).slice(0,xF)||null,l=t?EF(n.repo):null;return{label:r,prompt:i,trigger:o,why:c,...l?{repo:l}:{},...a?{ship:a}:{}}}function EF(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 _F(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):sw.slice();for(let i of n)if(!sw.includes(i))throw new Error(`ship.actions may only contain ${sw.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=ba(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=>ba(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function Td(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 MT(e,t,{pull:n=uc,ship:r={}}={}){if(cw(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=OT(t);if(o.ship)return{kind:"ship",...await OF(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=ka(),y=ka();return await C(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 C(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:y,trigger:"now",repo:e.workspace?.repo||null,context:{},rows:[{armId:g,label:o.label,prompt:o.prompt,promptHash:aw(o.prompt),origin:"agent",why:o.why}]}}),{kind:"now",armId:g,offerId:y,...o}}let c=e.workspace?.repo||null,{followups:l}=await n().catch(()=>({followups:[]})),u=RT(o.label),d=l.find(g=>g.status==="active"&&g.mode!=="off"&&g.trigger===o.trigger&&(g.repo==null||g.repo===c)&&g.dedupeKey===u);if(d)return{kind:"covered",covered:{id:d.id,label:d.label},...o};let p=await K(s),f=Td(p,{trigger:o.trigger}),w=f.length?f[f.length-1].armId:null,h=ka();return await C(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:{ts:Date.now(),armId:h,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,...w?{replaces:w}:{}}}),{kind:"armed",armId:h,replaces:w,...o}}async function CT(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await K(n);if(!Td(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await C(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function NT(e,t,{pull:n=uc}={}){if(cw(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=OT(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await K(s)).reduce((g,y)=>y.type==="followup.create.offered"?y.payload?.proposalId??g:y.type==="followup.create.answered"&&y.payload?.proposalId===g?null:g,null))throw new Error("a follow-up proposal is already waiting on the operator in this Track \u2014 one at a time");let{followups:c,source:l}=await n().catch(()=>({followups:[],source:"unreachable"}));if(l==="unreachable")throw new Error("plane unreachable \u2014 standing follow-ups live in the plane; try again shortly");let u=RT(r.label),d=c.filter(g=>g.dedupeKey===u&&g.trigger===r.trigger),p=d.find(g=>g.status==="deleted"),f=d.find(g=>g.status!=="deleted");if(f)throw new Error(`"${f.label}" (${iw[f.trigger]||f.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(p){let g=p.deletedAt?new Date(p.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${p.label}" on ${g} \u2014 do not re-propose it`)}let w=ka(),h=(e.boxes||[]).find(g=>g.name===e.leadBox)||null;return await C(s,{type:"followup.create.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:h?.agent??null,payload:{ts:Date.now(),proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why,origin:"agent"}}),{proposalId:w,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why}}async function PT(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await K(o),a=s.find(c=>c.type==="followup.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="followup.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await C(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 C(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 C(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 pc(e,t,n={},{pull:r=uc}={}){if(!e||cw(e))return null;let o={id:e.id,cwd:e.cwd},s=await K(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null;if(t==="pr.merged"){let p=h=>{let g=(h?.prs||[]).filter(y=>Number.isFinite(Number(y?.number))).map(y=>`${y?.repo??h?.repo??""}#${Number(y.number)}`);return Number.isFinite(Number(h?.prNumber))&&g.push(`${h?.repo??""}#${Number(h.prNumber)}`),g},f=new Set(p(n));if(s.some(h=>h.type==="followup.offered"&&h.payload?.trigger==="pr.merged"&&p(h.payload?.context).some(g=>f.has(g))))return null}let i=Td(s,{trigger:t}).map(p=>({armId:p.armId,label:p.label,prompt:p.prompt,promptHash:aw(p.prompt),origin:"agent",why:p.why??null})),c=[];if(t!=="now"){let{followups:p}=await r().catch(()=>({followups:[]}));c=p.filter(f=>f.status==="active"&&f.mode!=="off"&&f.trigger===t&&(f.repo==null||f.repo===a)).sort((f,w)=>{let h=g=>g.stats?.offered?(g.stats.accepted||0)/g.stats.offered:0;return h(w)-h(f)||(f.origin==="operator"?-1:0)-(w.origin==="operator"?-1:0)||(w.createdAt||0)-(f.createdAt||0)}).map(f=>({followupId:f.id,label:f.label,promptPreview:IF(f.prompt),promptHash:aw(f.prompt),origin:f.origin,repo:f.repo??null}))}let l=[...i,...c].slice(0,SF);if(!l.length)return null;let u=ka(),d={ts:Date.now(),offerId:u,trigger:t,repo:a,context:{...n,repo:a},rows:l};return await C(o,{type:"followup.offered",actor:"system",source:"orchestrator",payload:d}),d}function $F(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 DT(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null}={},s={}){if(!t)throw new Error("offerId required");return co(`fu:${e.id}:${t}`,()=>RF(e,{offerId:t,followupId:n,armId:r,promoted:o},s))}async function RF(e,{offerId:t,followupId:n,armId:r,promoted:o},s){let{sayToLead:a,unarchiveTrack:i,getFollowup:c=TT}=s,l={id:e.id,cwd:e.cwd},u=await K(l),d=u.find(b=>b.type==="followup.offered"&&b.payload?.offerId===t);if(!d)throw new Error("unknown offer");if(u.some(b=>b.type==="followup.answered"&&b.payload?.offerId===t))throw new Error("offer already answered");let p=d.payload.rows||[],f=b=>C(l,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...b}});if(!n&&!r)return await f({action:"dismiss",followupIds:p.map(b=>b.followupId).filter(Boolean),armIds:p.map(b=>b.armId).filter(Boolean)}),{offerId:t,action:"dismiss"};let w=null,h=null;if(n){if(!p.some(_=>_.followupId===n))throw new Error("that follow-up is not on this card");let{followup:b,source:I}=await c(n);if(I==="unreachable")throw new Error("plane unreachable \u2014 the follow-up's current prompt can't be read; try again shortly");if(!b||b.status!=="active"){await f({action:"removed",followupId:n});let _=new Error("removed in Settings since it was offered");throw _.code="removed",_}w=b.prompt,h=b.label}else{let b=p.find(_=>_.armId===r);if(!b)throw new Error("that arm is not on this card");if(w=u.find(_=>_.type==="followup.armed"&&_.payload?.armId===r)?.payload?.prompt??b.prompt,h=b.label,!w)throw new Error("the arm's prompt is missing from the log")}let g=!1;if(e.archivedAt){if(!i)throw new Error("this Track is archived");await i(e.id,{freshSession:!0}),g=!0}if(!a)throw new Error("sayToLead unavailable");let y=`${$F(d.payload)}
196
196
 
197
- ${w}`,x=await a(e.id,y,{kind:"followup-go"});return await f({action:"sent",...n?{followupId:n}:{armId:r},label:m,...o?{promoted:String(o)}:{},...g?{revived:!0}:{},source:n?`followup:${n}`:`arm:${r}`}),{offerId:t,action:"sent",followupId:n,armId:r,promoted:o,revived:g,queued:!!x?.queued}}async function zL(e,t,{changedRepos:n=null,probe:r=Hu,branchOf:o=Zr}={}){let s=t.ship;if(!e.workspace?.branch)throw new Error("this Track has no branch to ship \u2014 a ship offer needs a worktree Track");let a={id:e.id,cwd:e.cwd},i=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,c=e.workspace?.kind==="multi",l;if(c&&n){let g=await n(e).catch(()=>[]),y=s.repos?g.filter(x=>s.repos.includes(x.name)):g;l=y.length?y.map(x=>({name:x.name,slug:x.repo??null})):void 0}let u=(c?null:await o(e.cwd).catch(()=>null))||e.workspace.branch,d=s.rebase==="offered",p=await r(e,{branch:u,rebase:d}).catch(()=>null),f=[...d?["rebase"]:[],...s.actions].filter(g=>Gr.includes(g));if(p&&p.available.length===0)return{skipped:!0,reason:"nothing to ship \u2014 the tree is clean, pushed, and its PR is open",shipState:p};let w=sa(),m=t.why?`${t.label} \u2014 ${t.why}`:t.label;return await M(a,{type:"pr.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:i?.agent??null,payload:{offerId:w,ts:Date.now(),excerpt:m,via:"cli",branch:u,base:s.base||e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:"lead",available:p?.available,defaults:p?p.defaults.filter(g=>f.includes(g)||g==="rebase"):void 0,prState:p?.prState,openPr:p?.openPr||void 0,repos:p?.repos||l,offered:p?f.filter(g=>p.available.includes(g)):f,toPr:s.toPr?{number:s.toPr}:void 0}}),{offerId:w,branch:u,offered:f,available:p?.available??null,prState:p?.prState??null}}function QT(e){let t=!1;for(let n of e)n.type==="pr.offered"&&(n.source==="cli"||n.payload?.via==="cli")?t=!0:(n.type==="turn.user"&&!n.payload?.kind||n.type==="pr.offer.answered")&&(t=!1);return t}function eA(e){let t=null;for(let n of e){let r=n.payload||{};n.type==="pr.offer.answered"?t=r.action&&r.action!=="dismiss"&&r.action!=="pr-exists"?r.offerId:null:n.type==="pr.exists.answered"?t=r.choice&&r.choice!=="dismiss"?r.offerId??t:null:(n.type==="turn.user"&&!r.kind||n.type==="followup.offered"&&r.trigger==="ship.done"&&r.context?.shipOfferId&&r.context.shipOfferId===t)&&(t=null)}return t}async function tA(e,{pull:t=zi}={}){let{followups:n,source:r,error:o}=await t().catch(a=>({followups:[],source:"unreachable",error:a?.message})),s=e?await q({id:e.id,cwd:e.cwd}).catch(()=>[]):[];return{followups:n,source:r,error:o,arms:e?rd(s):[]}}var WT,qT,BL,KT,jL,_h,LL,Ah,Eh,oa,FL,Ih,qL,od=K(()=>{pe();Do();oh();Wo();HT();Vi();WT=60,qT=8*1024,BL=200,KT=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],jL=KT.filter(e=>e!=="now"&&e!=="track.opened"),_h={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"},LL=3,Ah=["commit","push","pr"];Eh=e=>DL("sha256").update(String(e)).digest("hex").slice(0,16),oa=e=>typeof e=="string"?e.trim():"",FL=[[/(^|[^\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"]];Ih=e=>String(e?.name||"").startsWith("\u21BB");qL=e=>String(e||"").split(`
197
+ ${w}`,x=await a(e.id,y,{kind:"followup-go"});return await f({action:"sent",...n?{followupId:n}:{armId:r},label:h,...o?{promoted:String(o)}:{},...g?{revived:!0}:{},source:n?`followup:${n}`:`arm:${r}`}),{offerId:t,action:"sent",followupId:n,armId:r,promoted:o,revived:g,queued:!!x?.queued}}async function OF(e,t,{changedRepos:n=null,probe:r=ud,branchOf:o=ao}={}){let s=t.ship;if(!e.workspace?.branch)throw new Error("this Track has no branch to ship \u2014 a ship offer needs a worktree Track");let a={id:e.id,cwd:e.cwd},i=(e.boxes||[]).find(g=>g.name===e.leadBox)||null,c=e.workspace?.kind==="multi",l;if(c&&n){let g=await n(e).catch(()=>[]),y=s.repos?g.filter(x=>s.repos.includes(x.name)):g;l=y.length?y.map(x=>({name:x.name,slug:x.repo??null})):void 0}let u=(c?null:await o(e.cwd).catch(()=>null))||e.workspace.branch,d=s.rebase==="offered",p=await r(e,{branch:u,rebase:d}).catch(()=>null),f=[...d?["rebase"]:[],...s.actions].filter(g=>eo.includes(g));if(p&&p.available.length===0)return{skipped:!0,reason:"nothing to ship \u2014 the tree is clean, pushed, and its PR is open",shipState:p};let w=ka(),h=t.why?`${t.label} \u2014 ${t.why}`:t.label;return await C(a,{type:"pr.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:i?.agent??null,payload:{offerId:w,ts:Date.now(),excerpt:h,via:"cli",branch:u,base:s.base||e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:"lead",available:p?.available,defaults:p?p.defaults.filter(g=>f.includes(g)||g==="rebase"):void 0,prState:p?.prState,openPr:p?.openPr||void 0,repos:p?.repos||l,offered:p?f.filter(g=>p.available.includes(g)):f,toPr:s.toPr?{number:s.toPr}:void 0}}),{offerId:w,branch:u,offered:f,available:p?.available??null,prState:p?.prState??null}}function BT(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 jT(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 LT(e,{pull:t=uc}={}){let{followups:n,source:r,error:o}=await t().catch(a=>({followups:[],source:"unreachable",error:a?.message})),s=e?await K({id:e.id,cwd:e.cwd}).catch(()=>[]):[];return{followups:n,source:r,error:o,arms:e?Td(s):[]}}var _T,IT,xF,$T,vF,iw,SF,sw,aw,ba,AF,cw,IF,Ed=q(()=>{he();Zo();jm();ss();ET();dc();_T=60,IT=8*1024,xF=200,$T=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],vF=$T.filter(e=>e!=="now"&&e!=="track.opened"),iw={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"},SF=3,sw=["commit","push","pr"];aw=e=>kF("sha256").update(String(e)).digest("hex").slice(0,16),ba=e=>typeof e=="string"?e.trim():"",AF=[[/(^|[^\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"]];cw=e=>String(e?.name||"").startsWith("\u21BB");IF=e=>String(e||"").split(`
198
198
  `).slice(0,3).join(`
199
- `).slice(0,400)});import{randomUUID as VL}from"node:crypto";function Yi(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function nA(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function rA(e){return`job|${e.box}|id:${e.id}`}async function Rh(e){return $h.has(e.id)?$h.get(e.id):(sd.has(e.id)||sd.set(e.id,q(e).then(t=>{let n={keys:new Set,cmdN:new Map};for(let r of t)if((r.type==="turn.user"||r.type==="turn.agent"||r.type==="provider.error")&&r.payload?.text!=null){let o=r.type==="turn.user"?"user":"assistant";r.payload.sourceId&&n.keys.add(Yi({role:o,sourceId:r.payload.sourceId})),n.keys.add(Yi({role:o,ts:r.payload.ts,text:r.payload.text}))}else if(r.type==="peer.message"&&r.source==="transcript")r.payload?.sourceId&&n.keys.add(Yi({role:"user",sourceId:r.payload.sourceId})),n.keys.add(Yi({role:"user",ts:r.payload?.ts,text:r.payload?.keyText??""}));else if(r.type==="tool.called"&&r.source==="transcript"&&r.payload?.command){let o=r.payload;n.keys.add(nA({id:o.id,box:r.boxId,ts:o.ts,command:o.command})),Number(o.n)>(n.cmdN.get(r.boxId)??0)&&n.cmdN.set(r.boxId,Number(o.n))}else r.type==="job.started"&&r.payload?.id&&n.keys.add(rA({id:r.payload.id,box:r.boxId}));return $h.set(e.id,n),n}).finally(()=>sd.delete(e.id))),sd.get(e.id))}async function oA(e,t){let n=new Set;try{let r=(await Rh(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=Yi(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?td(o.text):null;if(a){await M(e,{type:"peer.message",actor:"peer",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:a.text,ts:o.ts,keyText:String(o.text||"").slice(0,40),from:await PT(a,Xi),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=Jk(o);if(i){await M(e,{type:"provider.error",actor:"system",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{cls:i.cls,code:i.code||void 0,status:i.status||void 0,requestId:i.requestId||void 0,text:o.text,ts:o.ts,model:o.model||null,boxRole:o.boxRole,sourceId:o.sourceId||void 0}}),jT(e,{provider:o.agent||null,cls:i.cls,status:i.status,text:o.text}).catch(()=>{});continue}if(o.role!=="user"&&o.box&&n.add(o.box),await M(e,{type:o.role==="user"?"turn.user":"turn.agent",actor:o.role==="user"?"user":"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{text:o.text,ts:o.ts,model:o.model||null,tools:o.tools||void 0,boxRole:o.boxRole,sourceId:o.sourceId||void 0,note:o.note||void 0,images:o.images?.length?o.images:void 0}}),o.role==="assistant"&&o.box===e.leadBox&&e.workspace?.branch){let c=oS(o.text);if(c&&QT(await q(e).catch(()=>[])))continue;if(c){let l=iS(c),u;if(e.workspace?.kind==="multi"){let w=await Ko(e).catch(()=>[]);u=w.length?w.map(m=>({name:m.name,slug:m.repo??null})):void 0}let d=(e.workspace?.kind==="multi"?null:await Zr(e.cwd).catch(()=>null))||e.workspace.branch,p=await Hu(e,{branch:d,rebase:l}).catch(()=>null),f=p?null:aS(c);if(p&&p.available.length===0)continue;await M(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:VL(),ts:o.ts,excerpt:c,branch:d,base:e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:o.boxRole,available:p?.available,defaults:p?.defaults,prState:p?.prState,openPr:p?.openPr||void 0,repos:p?.repos||u,offered:p?.defaults||f?.offered||void 0,toPr:f?.toPr||void 0}})}}}}catch{}return{agentTurnBoxes:n}}async function sA(e,t){try{let n=await Rh(e),r=[...t||[]].filter(o=>o&&String(o.command||"").trim()).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=nA(o);if(n.keys.has(s))continue;n.keys.add(s);let a=(n.cmdN.get(o.box)??0)+1;n.cmdN.set(o.box,a),await M(e,{type:"tool.called",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id??null,tool:o.tool||null,command:o.command,description:o.description||"",summary:o.summary||o.command,ts:o.ts??null,boxRole:o.boxRole,n:a}}),MT(e,o),CT(e,o)}}catch{}}async function aA(e,t){try{let n=await Rh(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=rA(o);n.keys.has(s)||(n.keys.add(s),await M(e,{type:"job.started",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id,kind:o.kind||"agent",name:o.name||null,detail:o.detail||null,ts:o.ts??null,boxRole:o.boxRole}}))}}catch{}}var $h,sd,iA=K(()=>{pe();Do();oh();ed();Wo();bh();cr();Kl();vh();od();$h=new Map,sd=new Map});function JL(e){let t=[],n=null;for(let r of String(e||"").split(`
200
- `)){let o=r.trim();if(!o||o[0]!=="{")continue;let s;try{s=JSON.parse(o)}catch{continue}let a=s.payload||{};if(s.type==="turn_context"&&a.model&&(n=a.model),s.type==="event_msg"&&a.type==="token_count"&&a.info?.last_token_usage){let i=a.info.last_token_usage;t.push({ts:s.timestamp?Date.parse(s.timestamp):null,model:n,last:{input:i.input_tokens||0,cachedInput:i.cached_input_tokens||0,output:i.output_tokens||0,reasoningOutput:i.reasoning_output_tokens||0},occupancy:i.total_tokens??null,contextWindow:a.info.model_context_window??null})}}return t}async function YL(e,t){let n=`${e.id}:${t.name}`;if(!Oh.has(n)){let r=await q(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);Oh.set(n,o)}return Oh.get(n)}async function cA(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await Eo(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await YL(e,t),o=JL(await _t(n.file,262144)),s=o[o.length-1];for(let a of o){if(a.ts==null||r.has(a.ts))continue;r.add(a.ts);let i={input:Math.max(0,a.last.input-a.last.cachedInput),output:a.last.output,cacheRead:a.last.cachedInput,cacheWrite:0},c=a.model||t.model||"gpt-5.5";await M(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:In(c,i,a.ts),model:c,tokens:i,reasoningOutput:a.last.reasoningOutput||void 0,codexTs:a.ts,ts:a.ts}}),a===s&&a.contextWindow&&await M(e,{type:"context.usage",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{occupancy:a.occupancy,window:a.contextWindow,pct:a.occupancy!=null?a.occupancy/a.contextWindow:null,model:a.model||null,ts:a.ts}})}}catch{}}var Oh,lA=K(()=>{pe();Io();an();Qn();Oh=new Map});import ad from"node:fs";import Ch from"node:path";import XL from"node:os";async function eF({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(QL,{method:"POST",headers:{"content-type":"application/json",origin:"https://cursor.com",cookie:`WorkosCursorSessionToken=${t}`},body:JSON.stringify({teamId:0,startDate:String(e),endDate:String(Date.now()),page:o,pageSize:uA})});if(!s.ok)throw new Error(`cursor usage feed: HTTP ${s.status}`);let a=await s.json(),i=a?.usageEventsDisplay||a?.usageEvents||[];if(r.push(...i),i.length<uA)break}return r}function tF(e){if(!e)return null;let t=Number(e.timestamp)||null,n=e.tokenUsage||null,r=n?{input:n.inputTokens||0,output:n.outputTokens||0,cacheRead:n.cacheReadTokens||0,cacheWrite:n.cacheWriteTokens||0}:null,o=e.conversationId||null;return{id:[o||"?",t??"?",r?`${r.input}.${r.output}.${r.cacheRead}.${r.cacheWrite}`:"?"].join(":"),conversationId:o,ts:t,model:e.model||e.modelIntent||null,kind:e.kindLabel||e.kind||null,isHeadless:e.isHeadless===!0,tokens:r,vendorCents:n?.totalCents??null,chargedCents:e.chargedCents??null}}function pA(){try{return JSON.parse(ad.readFileSync(id(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function rF(e){try{ad.mkdirSync(Ch.dirname(id()),{recursive:!0});let t=id()+".tmp";ad.writeFileSync(t,JSON.stringify(e)),ad.renameSync(t,id())}catch{}}async function sF({fetchImpl:e,now:t=Date.now()}={}){if(to.rows&&t-to.at<nF)return to.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=pA(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await eF({sinceMs:o,cookie:n,fetchImpl:e});to={at:t,rows:s.map(tF).filter(Boolean),error:null}}catch(s){to={at:t,rows:null,error:String(s?.message||s)}}return to.rows}async function aF(e,t){let n=`${e.id}:${t.name}`;if(!Mh.has(n)){let r=await q(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);Mh.set(n,o)}return Mh.get(n)}async function fA(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!dA())return;let r=await sF({fetchImpl:n});if(!r||!r.length)return;let o=await Zx(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await aF(e,t),a=pA(),i=new Set(a.seen||[]),c=a.sinceMs||0;for(let l of r){if(!l.conversationId||l.conversationId!==o.chatId||s.has(l.id)||i.has(`${e.id}:${t.name}:${l.id}`))continue;s.add(l.id),i.add(`${e.id}:${t.name}:${l.id}`),l.ts&&l.ts>c&&(c=l.ts);let u=l.model||o.models[o.models.length-1]||"cursor-unknown",d=l.tokens||null,p=l.vendorCents!=null?l.vendorCents/100:0;!p&&d&&(p=In(u,d,l.ts??void 0)),!p&&l.chargedCents!=null&&(p=l.chargedCents/100),await M(e,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:t.name,provider:"cursor",payload:{usd:p,model:u,...d?{tokens:d}:{},...l.vendorCents!=null?{vendorCents:l.vendorCents}:{},...l.chargedCents!=null?{chargedCents:l.chargedCents}:{},...l.kind?{kind:l.kind}:{},conversationId:l.conversationId,cursorEventId:l.id,ts:l.ts??void 0}})}rF({sinceMs:c,seen:[...i].slice(-oF)})}catch{}}var ZL,dA,QL,uA,nF,to,id,oF,Nh,Mh,Ph=K(()=>{pe();pm();Qn();ZL=process.env.BOSTRAT_STATE_DIR||Ch.join(process.env.HOME||XL.tmpdir(),".bostrat"),dA=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,QL="https://cursor.com/api/dashboard/get-filtered-usage-events",uA=100;nF=5*6e4,to={at:0,rows:null,error:null},id=()=>Ch.join(ZL,"cursor-usage.json");oF=5e3;Nh=()=>({enabled:dA(),lastPollAt:to.at||null,error:to.error}),Mh=new Map});import{randomUUID as iF,createHmac as cF}from"node:crypto";function hA(e){Bh=typeof e=="string"&&e?e:null}function lF(e){if(!Bh)return null;let t=Fe(e);return t?cF("sha256",Buffer.from(Bh,"base64url")).update(t,"utf8").digest("hex").slice(0,16):null}function yA(){let e={};for(let t of gA)e[String(t)]=0;return e.inf=0,{buckets:e,sumMs:0,count:0}}function mA(e,t){let n=Math.max(0,Number(t)||0);for(let r of gA)n<=r&&(e.buckets[String(r)]+=1);e.buckets.inf+=1,e.sumMs+=n,e.count+=1}function bA(){let e={};for(let t of wA)e[t]=0;return e}function dF(){Cn={total:new Map,holds:bA(),queueWaitMs:yA(),readyWaitMs:new Map,verify:new Map,retries:new Map}}function kA({queueDepth:e=0,queueOldestAgeMs:t=0}={}){let n=Cn;return{total:[...n.total].map(([r,o])=>{let[s,a,i]=r.split("|");return{provider:s,producer:a,outcome:i,n:o}}),holds:{...n.holds},queueWaitMs:{buckets:{...n.queueWaitMs.buckets},sumMs:n.queueWaitMs.sumMs,count:n.queueWaitMs.count},readyWaitMs:[...n.readyWaitMs].map(([r,o])=>{let[s,a]=r.split("|");return{provider:s,outcome:a,buckets:{...o.buckets},sumMs:o.sumMs,count:o.count}}),verify:[...n.verify].map(([r,o])=>{let[s,a]=r.split("|");return{provider:s,verdict:a,n:o}}),retries:[...n.retries].map(([r,o])=>({provider:r,n:o})),queueDepth:Number(e)||0,queueOldestAgeMs:Number(t)||0}}function Zi({kind:e=null,producer:t=null,orchestration:n=!1}={}){return n?`orchestration:${e||"orchestration"}`:e?`scripted:${e}`:uF.has(t)?t:"composer"}function Qi({text:e="",producer:t="composer",kind:n=null,provider:r=null,attachments:o=0,now:s=Date.now}={}){let a=s();return{id:iF(),producer:t,kind:n||null,provider:r||null,textBytes:Buffer.byteLength(String(e||""),"utf8"),textHmac16:lF(e),attachments:Number(o)||0,paste:null,t0:a,queuedAt:null,dequeuedAt:null,holds:bA(),requeued:0,readyWaitMs:null,readyOutcome:null,verify:null,settled:!1,outcome:null}}async function ec(e,t,{position:n=null,reason:r="busy"}={}){!t||!e||(t.queuedAt=Date.now(),await M(e,{type:"delivery.queued",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:{ts:t.queuedAt,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},reason:r,position:n,textBytes:t.textBytes,textHmac16:t.textHmac16,requeued:t.requeued}}).catch(()=>{}))}function xA(e,t){wA.includes(t)&&(e?.holds&&(e.holds[t]+=1),Cn.holds[t]+=1)}function tc(e,{ms:t,outcome:n}){e&&(e.readyWaitMs=Math.max(0,Number(t)||0),e.readyOutcome=n||null)}async function Nn(e,t,n,{now:r=Date.now}={}){if(!t||t.settled)return null;t.settled=!0,t.outcome=n;let o=r(),s=t.provider||"unknown",a=t.queuedAt!=null,i=a?Math.max(0,(t.dequeuedAt??o)-t.queuedAt):null;if(Dh(Cn.total,`${s}|${t.producer}|${n}`),a&&mA(Cn.queueWaitMs,i),t.readyWaitMs!=null){let l=`${s}|${t.readyOutcome||"unknown"}`;Cn.readyWaitMs.has(l)||Cn.readyWaitMs.set(l,yA()),mA(Cn.readyWaitMs.get(l),t.readyWaitMs)}t.verify?.verdict&&(Dh(Cn.verify,`${s}|${t.verify.verdict}`),t.verify.retries&&Dh(Cn.retries,s,t.verify.retries));let c={ts:o,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},cliVersion:null,textBytes:t.textBytes,textHmac16:t.textHmac16,paste:t.paste,attachments:t.attachments,outcome:n,queued:a,queueWaitMs:i,queueHolds:{...t.holds},requeued:t.requeued,readyWaitMs:t.readyWaitMs,readyOutcome:t.readyOutcome,verify:t.verify?{...t.verify}:null,receiptMs:null,totalMs:Math.max(0,o-t.t0)};return e&&await M(e,{type:"delivery.settled",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:c}).catch(()=>{}),c}function aa(e){if(e?.usageCap)return"refused:cap";if(e?.interrupted)return"interrupted";if(e?.code)return`failed:${e.code}`;let t=String(e?.message||"");return/not running/i.test(t)?"failed:not-running":/archived/i.test(t)?"failed:archived":/blocked on an interactive prompt|isn't signed in|is waiting on its|stuck on its update/i.test(t)?"failed:blocked":"failed:error"}var Bh,wA,gA,uF,Cn,Dh,jh=K(()=>{pe();vi();Bh=null;wA=["busy","prompt","handoff","noSession","cap","grace"],gA=[500,2e3,1e4,6e4,6e5],uF=new Set(["composer","voice","loop"]);Cn=null;dF();Dh=(e,t,n=1)=>e.set(t,(e.get(t)||0)+n)});import oc from"node:fs/promises";import It from"node:path";import pF from"node:os";import fF from"node:net";import{randomUUID as mF}from"node:crypto";import{execFile as hF}from"node:child_process";import{promisify as wF}from"node:util";function SF(e){for(let t of Kh(e))if(!_A.test(t))return t;return null}function IA(e){let t=Kh(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function TF(e,t){let n=IA(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return It.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return It.resolve(e,n[r+1])}return e}function EF(e){let t=!1,n=!1;for(let r of Kh(e)){if(!t){if(_A.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&Lh(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,Lh(r))return`serves the filesystem root ("${r}")`;continue}if(Lh(r))return`serves the filesystem root ("${r}")`;if(AF(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function IF(e,t){if(It.resolve(e)===It.resolve(t))return!0;let[n,r]=await Promise.all([cd(e),cd(t)]);return n===r}async function $F(e){let n=(await oc.readdir(e,{withFileTypes:!0}).catch(()=>[])).filter(o=>o.isDirectory()&&!o.name.startsWith(".")&&o.name!=="node_modules");return(await Promise.all(n.map(async o=>await $A(It.join(e,o.name,Hh))?`./${o.name}`:null))).filter(Boolean)}async function RF(e,t){let[n,r]=await Promise.all([cd(e),cd(t)]),o=It.relative(n,r);if(o&&(o.startsWith("..")||It.isAbsolute(o)))throw nc(`serve directory escapes the Track workspace: ${t}`)}async function OF(e,t){let n=EF(t);if(n)throw nc(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await _F(e))throw nc(`serve directory does not exist: ${e}`);let r=SF(t);if(!r)return;if(!r.includes("/")&&!await xk(r,{loginShell:!0,failOpen:!0}))throw nc(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(kF.test(t)||xF.has(r)||!bF.has(r)||!IA(t).includes("run")||vF.test(t))return;let o=TF(e,t);if(await $A(It.join(o,Hh)))return;let s=await $F(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw nc(`no ${Hh} in ${o}${a}`)}async function dr(){return Pn||(Fh||=(async()=>{try{Pn=JSON.parse(await oc.readFile(EA,"utf8"))}catch{Pn={views:[],adoptWatermarks:{}}}finally{Fh=null}return Pn.views||=[],Pn.adoptWatermarks||={},Pn})(),Fh)}async function Bn(){await Et(EA,Pn)}function ur(e,t,n={}){return M({id:e.trackId,cwd:e.cwd},{type:"view.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,payload:{ts:Date.now(),change:t,viewId:e.id,name:e.name,slug:e.slug,port:e.port,cmd:e.cmd||null,...n}}).catch(()=>{})}function zh(e){return rc.get(e)||null}function OA(e,{name:t,box:n}={}){let r=rc.get(e);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o={trackId:e,name:t||"preview",box:n||null,step:"spinning-up",startedAt:Date.now(),finishedAt:null,viewId:null,error:null};return rc.set(e,o),o}function Wh(e,t){let n=rc.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function ld(e,{error:t=null}={}){let n=rc.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function MA(e){let t=[];for(let n of e?.events||[])n.type!=="view-spinup"||!n.box||!n.startedAt||!n.endedAt||t.push({box:n.box,from:n.startedAt,to:n.endedAt});return t}function qh(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function MF(e,t){let n=qh(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!TA.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!TA.has(s))return s}}function sc(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=fF.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 Vh(e){if(process.platform!=="darwin"){await Dn("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await Dn("lsof",["-t","-sTCP:LISTEN","-i",`tcp:${e}`]))}catch{return}for(let n of t.split(/\s+/).filter(Boolean)){let r=Number(n);if(!(!r||r===process.pid))try{process.kill(r,"SIGKILL")}catch{}}}function CA(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function CF(e,t){let n=new Set(e.views.map(o=>o.port)),r=CA();if(t){let o=Number(t);if(!Number.isInteger(o)||o<1024||o>65535)throw new Error("invalid port");if(r.has(o))throw new Error(`port ${o} is the node's own API port`);if(n.has(o))throw new Error(`port ${o} is already owned by a view`);return o}for(let o=vA;o<=SA;o++)if(!(n.has(o)||r.has(o))&&!await sc(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${vA}-${SA}`)}async function NF(e){try{let{stdout:t}=await Dn(X,Q("list-sessions","-F","#{session_name}"));return t.split(`
201
- `).some(n=>n.trim()===ia(e))}catch{return!1}}async function ac(e){try{await Dn(X,Q("kill-session","-t",ia(e)))}catch{}}async function Jh(e){if(!await ci())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=ia(e.slug),n=e.serveCwd??e.cwd,r=It.dirname(process.execPath);await Dn(X,Q("new-session","-d","-s",t,"-c",n)),await Dn(X,Q("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await Dn(X,Q("send-keys","-t",t,"Enter")),await Dn(X,Q("send-keys","-t",t,"-l",e.cmd)),await Dn(X,Q("send-keys","-t",t,"Enter"))}async function AA(e,t=12){try{let{stdout:n}=await Dn(X,Q("capture-pane","-t",ia(e),"-p"));return String(n||"").trimEnd().split(`
199
+ `).slice(0,400)});import{randomUUID as MF}from"node:crypto";function fc(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function FT(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function UT(e){return`job|${e.box}|id:${e.id}`}async function uw(e){return lw.has(e.id)?lw.get(e.id):(_d.has(e.id)||_d.set(e.id,K(e).then(t=>{let n={keys:new Set,cmdN:new Map};for(let r of t)if((r.type==="turn.user"||r.type==="turn.agent"||r.type==="provider.error")&&r.payload?.text!=null){let o=r.type==="turn.user"?"user":"assistant";r.payload.sourceId&&n.keys.add(fc({role:o,sourceId:r.payload.sourceId})),n.keys.add(fc({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(fc({role:"user",sourceId:r.payload.sourceId})),n.keys.add(fc({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(FT({id:o.id,box:r.boxId,ts:o.ts,command:o.command})),Number(o.n)>(n.cmdN.get(r.boxId)??0)&&n.cmdN.set(r.boxId,Number(o.n))}else r.type==="job.started"&&r.payload?.id&&n.keys.add(UT({id:r.payload.id,box:r.boxId}));return lw.set(e.id,n),n}).finally(()=>_d.delete(e.id))),_d.get(e.id))}async function HT(e,t){let n=new Set;try{let r=(await uw(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=fc(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?Sd(o.text):null;if(a){await C(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 bT(a,hc),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=C0(o);if(i){await C(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}}),vT(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 C(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=HS(o.text);if(c&&BT(await K(e).catch(()=>[])))continue;if(c){let l=KS(c),u;if(e.workspace?.kind==="multi"){let w=await is(e).catch(()=>[]);u=w.length?w.map(h=>({name:h.name,slug:h.repo??null})):void 0}let d=(e.workspace?.kind==="multi"?null:await ao(e.cwd).catch(()=>null))||e.workspace.branch,p=await ud(e,{branch:d,rebase:l}).catch(()=>null),f=p?null:qS(c);if(p&&p.available.length===0)continue;await C(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:MF(),ts:o.ts,excerpt:c,branch:d,base:e.workspace.baseRef?.replace(/^origin\//,"")||null,boxRole:o.boxRole,available:p?.available,defaults:p?.defaults,prState:p?.prState,openPr:p?.openPr||void 0,repos:p?.repos||u,offered:p?.defaults||f?.offered||void 0,toPr:f?.toPr||void 0}})}}}}catch{}return{agentTurnBoxes:n}}async function WT(e,t){try{let n=await uw(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=FT(o);if(n.keys.has(s))continue;n.keys.add(s);let a=(n.cmdN.get(o.box)??0)+1;n.cmdN.set(o.box,a),await C(e,{type:"tool.called",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id??null,tool:o.tool||null,command:o.command,description:o.description||"",summary:o.summary||o.command,ts:o.ts??null,boxRole:o.boxRole,n:a}}),wT(e,o),gT(e,o)}}catch{}}async function qT(e,t){try{let n=await uw(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=UT(o);n.keys.has(s)||(n.keys.add(s),await C(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 lw,_d,KT=q(()=>{he();Zo();jm();vd();ss();Qm();dr();pu();nw();Ed();lw=new Map,_d=new Map});function CF(e){let t=[],n=null;for(let r of String(e||"").split(`
200
+ `)){let o=r.trim();if(!o||o[0]!=="{")continue;let s;try{s=JSON.parse(o)}catch{continue}let a=s.payload||{};if(s.type==="turn_context"&&a.model&&(n=a.model),s.type==="event_msg"&&a.type==="token_count"&&a.info?.last_token_usage){let i=a.info.last_token_usage;t.push({ts:s.timestamp?Date.parse(s.timestamp):null,model:n,last:{input:i.input_tokens||0,cachedInput:i.cached_input_tokens||0,output:i.output_tokens||0,reasoningOutput:i.reasoning_output_tokens||0},occupancy:i.total_tokens??null,contextWindow:a.info.model_context_window??null})}}return t}async function NF(e,t){let n=`${e.id}:${t.name}`;if(!dw.has(n)){let r=await K(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.codexTs!=null&&o.add(s.payload.codexTs);dw.set(n,o)}return dw.get(n)}async function GT(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await jo(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await NF(e,t),o=CF(await Mt(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 C(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:Rn(c,i,a.ts),model:c,tokens:i,reasoningOutput:a.last.reasoningOutput||void 0,codexTs:a.ts,ts:a.ts}}),a===s&&a.contextWindow&&await C(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 dw,zT=q(()=>{he();Fo();ln();nr();dw=new Map});import Id from"node:fs";import fw from"node:path";import PF from"node:os";async function jF({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(BF,{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:VT})});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<VT)break}return r}function LF(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 YT(){try{return JSON.parse(Id.readFileSync($d(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function UF(e){try{Id.mkdirSync(fw.dirname($d()),{recursive:!0});let t=$d()+".tmp";Id.writeFileSync(t,JSON.stringify(e)),Id.renameSync(t,$d())}catch{}}async function WF({fetchImpl:e,now:t=Date.now()}={}){if(lo.rows&&t-lo.at<FF)return lo.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=YT(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await jF({sinceMs:o,cookie:n,fetchImpl:e});lo={at:t,rows:s.map(LF).filter(Boolean),error:null}}catch(s){lo={at:t,rows:null,error:String(s?.message||s)}}return lo.rows}async function qF(e,t){let n=`${e.id}:${t.name}`;if(!pw.has(n)){let r=await K(e),o=new Set;for(let s of r)s.type==="cost.recorded"&&s.boxId===t.name&&s.payload?.cursorEventId&&o.add(s.payload.cursorEventId);pw.set(n,o)}return pw.get(n)}async function XT(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!JT())return;let r=await WF({fetchImpl:n});if(!r||!r.length)return;let o=await Bv(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await qF(e,t),a=YT(),i=new Set(a.seen||[]),c=a.sinceMs||0;for(let l of r){if(!l.conversationId||l.conversationId!==o.chatId||s.has(l.id)||i.has(`${e.id}:${t.name}:${l.id}`))continue;s.add(l.id),i.add(`${e.id}:${t.name}:${l.id}`),l.ts&&l.ts>c&&(c=l.ts);let u=l.model||o.models[o.models.length-1]||"cursor-unknown",d=l.tokens||null,p=l.vendorCents!=null?l.vendorCents/100:0;!p&&d&&(p=Rn(u,d,l.ts??void 0)),!p&&l.chargedCents!=null&&(p=l.chargedCents/100),await C(e,{type:"cost.recorded",actor:"agent",source:"vendor",boxId:t.name,provider:"cursor",payload:{usd:p,model:u,...d?{tokens:d}:{},...l.vendorCents!=null?{vendorCents:l.vendorCents}:{},...l.chargedCents!=null?{chargedCents:l.chargedCents}:{},...l.kind?{kind:l.kind}:{},conversationId:l.conversationId,cursorEventId:l.id,ts:l.ts??void 0}})}UF({sinceMs:c,seen:[...i].slice(-HF)})}catch{}}var DF,JT,BF,VT,FF,lo,$d,HF,hw,pw,mw=q(()=>{he();Kh();nr();DF=process.env.BOSTRAT_STATE_DIR||fw.join(process.env.HOME||PF.tmpdir(),".bostrat"),JT=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,BF="https://cursor.com/api/dashboard/get-filtered-usage-events",VT=100;FF=5*6e4,lo={at:0,rows:null,error:null},$d=()=>fw.join(DF,"cursor-usage.json");HF=5e3;hw=()=>({enabled:JT(),lastPollAt:lo.at||null,error:lo.error}),pw=new Map});import{randomUUID as KF,createHmac as GF}from"node:crypto";function QT(e){gw=typeof e=="string"&&e?e:null}function zF(e){if(!gw)return null;let t=Le(e);return t?GF("sha256",Buffer.from(gw,"base64url")).update(t,"utf8").digest("hex").slice(0,16):null}function nE(){let e={};for(let t of tE)e[String(t)]=0;return e.inf=0,{buckets:e,sumMs:0,count:0}}function ZT(e,t){let n=Math.max(0,Number(t)||0);for(let r of tE)n<=r&&(e.buckets[String(r)]+=1);e.buckets.inf+=1,e.sumMs+=n,e.count+=1}function rE(){let e={};for(let t of eE)e[t]=0;return e}function JF(){Pn={total:new Map,holds:rE(),queueWaitMs:nE(),readyWaitMs:new Map,verify:new Map,retries:new Map}}function oE({queueDepth:e=0,queueOldestAgeMs:t=0}={}){let n=Pn;return{total:[...n.total].map(([r,o])=>{let[s,a,i]=r.split("|");return{provider:s,producer:a,outcome:i,n:o}}),holds:{...n.holds},queueWaitMs:{buckets:{...n.queueWaitMs.buckets},sumMs:n.queueWaitMs.sumMs,count:n.queueWaitMs.count},readyWaitMs:[...n.readyWaitMs].map(([r,o])=>{let[s,a]=r.split("|");return{provider:s,outcome:a,buckets:{...o.buckets},sumMs:o.sumMs,count:o.count}}),verify:[...n.verify].map(([r,o])=>{let[s,a]=r.split("|");return{provider:s,verdict:a,n:o}}),retries:[...n.retries].map(([r,o])=>({provider:r,n:o})),queueDepth:Number(e)||0,queueOldestAgeMs:Number(t)||0}}function mc({kind:e=null,producer:t=null,orchestration:n=!1}={}){return n?`orchestration:${e||"orchestration"}`:e?`scripted:${e}`:VF.has(t)?t:"composer"}function wc({text:e="",producer:t="composer",kind:n=null,provider:r=null,attachments:o=0,now:s=Date.now}={}){let a=s();return{id:KF(),producer:t,kind:n||null,provider:r||null,textBytes:Buffer.byteLength(String(e||""),"utf8"),textHmac16:zF(e),attachments:Number(o)||0,paste:null,t0:a,queuedAt:null,dequeuedAt:null,holds:rE(),requeued:0,readyWaitMs:null,readyOutcome:null,verify:null,settled:!1,outcome:null}}async function gc(e,t,{position:n=null,reason:r="busy"}={}){!t||!e||(t.queuedAt=Date.now(),await C(e,{type:"delivery.queued",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:{ts:t.queuedAt,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},reason:r,position:n,textBytes:t.textBytes,textHmac16:t.textHmac16,requeued:t.requeued}}).catch(()=>{}))}function sE(e,t){eE.includes(t)&&(e?.holds&&(e.holds[t]+=1),Pn.holds[t]+=1)}function yc(e,{ms:t,outcome:n}){e&&(e.readyWaitMs=Math.max(0,Number(t)||0),e.readyOutcome=n||null)}async function Dn(e,t,n,{now:r=Date.now}={}){if(!t||t.settled)return null;t.settled=!0,t.outcome=n;let o=r(),s=t.provider||"unknown",a=t.queuedAt!=null,i=a?Math.max(0,(t.dequeuedAt??o)-t.queuedAt):null;if(ww(Pn.total,`${s}|${t.producer}|${n}`),a&&ZT(Pn.queueWaitMs,i),t.readyWaitMs!=null){let l=`${s}|${t.readyOutcome||"unknown"}`;Pn.readyWaitMs.has(l)||Pn.readyWaitMs.set(l,nE()),ZT(Pn.readyWaitMs.get(l),t.readyWaitMs)}t.verify?.verdict&&(ww(Pn.verify,`${s}|${t.verify.verdict}`),t.verify.retries&&ww(Pn.retries,s,t.verify.retries));let c={ts:o,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},cliVersion:null,textBytes:t.textBytes,textHmac16:t.textHmac16,paste:t.paste,attachments:t.attachments,outcome:n,queued:a,queueWaitMs:i,queueHolds:{...t.holds},requeued:t.requeued,readyWaitMs:t.readyWaitMs,readyOutcome:t.readyOutcome,verify:t.verify?{...t.verify}:null,receiptMs:null,totalMs:Math.max(0,o-t.t0)};return e&&await C(e,{type:"delivery.settled",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:c}).catch(()=>{}),c}function xa(e){if(e?.usageCap)return"refused:cap";if(e?.interrupted)return"interrupted";if(e?.code)return`failed:${e.code}`;let t=String(e?.message||"");return/not running/i.test(t)?"failed:not-running":/archived/i.test(t)?"failed:archived":/blocked on an interactive prompt|isn't signed in|is waiting on its|stuck on its update/i.test(t)?"failed:blocked":"failed:error"}var gw,eE,tE,VF,Pn,ww,yw=q(()=>{he();Fi();gw=null;eE=["busy","prompt","handoff","noSession","cap","grace"],tE=[500,2e3,1e4,6e4,6e5],VF=new Set(["composer","voice","loop"]);Pn=null;JF();ww=(e,t,n=1)=>e.set(t,(e.get(t)||0)+n)});import xc from"node:fs/promises";import Ct from"node:path";import YF from"node:os";import XF from"node:net";import{randomUUID as ZF}from"node:crypto";import{execFile as QF}from"node:child_process";import{promisify as eU}from"node:util";function iU(e){for(let t of Tw(e))if(!dE.test(t))return t;return null}function pE(e){let t=Tw(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function cU(e,t){let n=pE(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return Ct.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return Ct.resolve(e,n[r+1])}return e}function uU(e){let t=!1,n=!1;for(let r of Tw(e)){if(!t){if(dE.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&bw(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,bw(r))return`serves the filesystem root ("${r}")`;continue}if(bw(r))return`serves the filesystem root ("${r}")`;if(lU(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function pU(e,t){if(Ct.resolve(e)===Ct.resolve(t))return!0;let[n,r]=await Promise.all([Rd(e),Rd(t)]);return n===r}async function fU(e){let n=(await xc.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 fE(Ct.join(e,o.name,vw))?`./${o.name}`:null))).filter(Boolean)}async function hU(e,t){let[n,r]=await Promise.all([Rd(e),Rd(t)]),o=Ct.relative(n,r);if(o&&(o.startsWith("..")||Ct.isAbsolute(o)))throw bc(`serve directory escapes the Track workspace: ${t}`)}async function mU(e,t){let n=uU(t);if(n)throw bc(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await dU(e))throw bc(`serve directory does not exist: ${e}`);let r=iU(t);if(!r)return;if(!r.includes("/")&&!await s0(r,{loginShell:!0,failOpen:!0}))throw bc(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(oU.test(t)||sU.has(r)||!rU.has(r)||!pE(t).includes("run")||aU.test(t))return;let o=cU(e,t);if(await fE(Ct.join(o,vw)))return;let s=await fU(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw bc(`no ${vw} in ${o}${a}`)}async function hr(){return Bn||(kw||=(async()=>{try{Bn=JSON.parse(await xc.readFile(uE,"utf8"))}catch{Bn={views:[],adoptWatermarks:{}}}finally{kw=null}return Bn.views||=[],Bn.adoptWatermarks||={},Bn})(),kw)}async function Ln(){await Rt(uE,Bn)}function fr(e,t,n={}){return C({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 _w(e){return kc.get(e)||null}function mE(e,{name:t,box:n}={}){let r=kc.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 kc.set(e,o),o}function Sw(e,t){let n=kc.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function Od(e,{error:t=null}={}){let n=kc.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function wE(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 Aw(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function wU(e,t){let n=Aw(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!cE.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!cE.has(s))return s}}function vc(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=XF.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 Iw(e){if(process.platform!=="darwin"){await jn("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await jn("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 gE(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function gU(e,t){let n=new Set(e.views.map(o=>o.port)),r=gE();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=aE;o<=iE;o++)if(!(n.has(o)||r.has(o))&&!await vc(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${aE}-${iE}`)}async function yU(e){try{let{stdout:t}=await jn(ee,ne("list-sessions","-F","#{session_name}"));return t.split(`
201
+ `).some(n=>n.trim()===va(e))}catch{return!1}}async function Sc(e){try{await jn(ee,ne("kill-session","-t",va(e)))}catch{}}async function $w(e){if(!await _i())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=va(e.slug),n=e.serveCwd??e.cwd,r=Ct.dirname(process.execPath);await jn(ee,ne("new-session","-d","-s",t,"-c",n)),await jn(ee,ne("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await jn(ee,ne("send-keys","-t",t,"Enter")),await jn(ee,ne("send-keys","-t",t,"-l",e.cmd)),await jn(ee,ne("send-keys","-t",t,"Enter"))}async function lE(e,t=12){try{let{stdout:n}=await jn(ee,ne("capture-pane","-t",va(e),"-p"));return String(n||"").trimEnd().split(`
202
202
  `).filter(Boolean).slice(-t).join(`
203
- `)}catch{return""}}async function DF(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await NF(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await AA(e.slug)||"server exited before listening"),lr.delete(e.id),await ur(e,e.state,e.error?{error:e.error}:{}),!0}if(await sc(e.port))return lr.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await ur(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>PF?(e.state="error",e.error=await AA(e.slug)||"never started listening",await ur(e,"error",{error:e.error}),!0):!1;let o=(lr.get(e.id)||0)+1;return lr.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function ud(){if(!Uh){Uh=!0;try{let e=await dr(),t=!1;for(let n of e.views)await DF(n)&&(t=!0);t&&await Bn()}finally{Uh=!1}}}async function Yh({trackId:e}={}){await ud();let t=await dr();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function NA(e){let n=(await dr()).views.find(r=>r.id===e);return n?{...n}:null}function Xh(e){return Pn&&Pn.views.find(t=>t.slug===e)||null}async function Zh({trackId:e,name:t,cmd:n,cwd:r,serveCwd:o,port:s,box:a,origin:i="agent",branch:c=null}){if(!e)throw new Error("trackId required");if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(i!=="detected"&&(typeof n!="string"||!n.trim()))throw new Error("cmd (string) required");if(!r)throw new Error("cwd required");let l=o!=null,u=It.resolve(r,o??"."),d=i==="detected"?null:async()=>{await RF(r,u),await OF(u,n)},p=await dr();if(i!=="detected"){let m=qh(t),g=String(n).trim(),y=p.views.find(x=>x.trackId===e&&(x.slug===m||qh(x.name)===m||x.cmd===g&&It.resolve(x.serveCwd??x.cwd)===u));if(y)return BF(p,y,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:d})}if(d&&await d(),p.views.filter(m=>m.state==="live"||m.state==="starting").length>=no)throw new Error(`view cap reached (${no} live) \u2014 stop one first`);let w={id:mF().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:MF(p,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await CF(p,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await Jh(w),p.views.push(w),await Bn(),await ur(w,"created",{origin:i}),Wh(e,w.id),i==="detected"&&await sc(w.port)&&(w.state="live",w.lastHealthyAt=Date.now(),await Bn(),await ur(w,"live")),{...w}}async function BF(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 IF(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await sc(t.port))return await Bn(),Wh(t.trackId,t.id),{...t,reused:!0};if(a&&await a(),e.views.filter(d=>d.id!==t.id&&(d.state==="live"||d.state==="starting")).length>=no)throw new Error(`view cap reached (${no} live) \u2014 stop one first`);return t.origin==="detected"?(await Vh(t.port),t.origin="agent"):await ac(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),lr.delete(t.id),await Jh(t),await Bn(),await ur(t,"created",{restarted:!0,reused:!0}),Wh(t.trackId,t.id),{...t,reused:!0}}async function PA(e){let n=(await dr()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await Vh(n.port):await ac(n.slug),n.state!=="stopped"&&(n.state="stopped",lr.delete(n.id),await Bn(),await ur(n,"stopped")),{...n}}async function DA(e){let t=await dr(),n=t.views.find(o=>o.id===e);if(!n)throw new Error("view not found");if(!n.cmd)throw new Error("a detected view has no known command \u2014 recreate it as a managed view");if(t.views.filter(o=>o.id!==e&&(o.state==="live"||o.state==="starting")).length>=no)throw new Error(`view cap reached (${no} live) \u2014 stop one first`);return await ac(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),lr.delete(n.id),await Jh(n),await Bn(),await ur(n,"created",{restarted:!0}),{...n}}async function BA(e){let t=await dr(),n=t.views.findIndex(o=>o.id===e);if(n===-1)throw new Error("view not found");let r=t.views[n];return r.origin==="detected"?await Vh(r.port):await ac(r.slug),t.views.splice(n,1),lr.delete(r.id),await Bn(),await ur(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function jA(e){let t=await dr(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await ac(r.slug),lr.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await Bn()),n.length}async function LA(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await dr(),r=n.adoptWatermarks[e.id]??null,o=t.filter(c=>c.role==="assistant"&&c.ts!=null&&(r==null?!1:c.ts>r)),s=t.reduce((c,l)=>l.ts>c?l.ts:c,r??0);if(n.adoptWatermarks[e.id]!==s&&(n.adoptWatermarks[e.id]=s,await Bn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(jF)){let u=Number(l[1]||80);u>=1024&&u<=65535&&a.add(u)}if(!a.size)return[];let i=[];for(let c of a)if(!CA().has(c)&&!n.views.some(l=>l.port===c)&&await sc(c))try{i.push(await Zh({trackId:e.id,name:`${e.name} preview`,cmd:null,cwd:e.cwd,port:c,origin:"detected",branch:e.workspace?.branch??null}))}catch{}return i}var Dn,gF,EA,vA,SA,no,yF,ia,TA,nc,bF,Hh,kF,xF,vF,Kh,_A,Lh,AF,_F,$A,cd,Pn,Fh,rc,Gh,RA,lr,PF,Uh,jF,dd=K(()=>{ct();pe();Er();Dn=wF(hF),gF=process.env.BOSTRAT_STATE_DIR||It.join(process.env.HOME||pF.tmpdir(),".bostrat"),EA=It.join(gF,"views.json"),[vA,SA]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),no=Number(process.env.BOSTRAT_VIEW_MAX)||3,yF="bostrat-view-",ia=e=>`${yF}${e}`,TA=new Set(["bostrat","www","api","views","app"]),nc=e=>Object.assign(new Error(e),{status:400}),bF=new Set(["npm","pnpm","yarn","bun"]),Hh="package.json",kF=/[|;&`]|\$\(/,xF=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),vF=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,Kh=e=>String(e).trim().split(/\s+/).filter(Boolean),_A=/^[A-Za-z_][A-Za-z0-9_]*=/;Lh=e=>e==="/",AF=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");_F=e=>oc.stat(e).then(t=>t.isDirectory(),()=>!1),$A=e=>oc.stat(e).then(t=>t.isFile(),()=>!1),cd=e=>oc.realpath(e).catch(()=>It.resolve(e));Pn=null,Fh=null;rc=new Map,Gh=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,RA=12e3;lr=new Map,PF=12e4;Uh=!1;jF=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function ca(e,t=Date.now()){let n=null;for(let r of e||[]){let o=r.payload?.ts??r.ts;r.type==="pr.offer.answered"?n=r.payload?.action==="pr"?{ts:o,offerId:r.payload?.offerId??null,box:r.boxId??null,offerType:"offer"}:null:r.type==="pr.exists.answered"?n=r.payload?.choice==="push"?{ts:o,offerId:r.payload?.offerId??null,box:r.boxId??null,offerType:"exists"}:null:r.type==="pr.state.changed"&&(r.payload?.change==="opened"||r.payload?.change==="pushed")&&n!=null&&o>=n.ts&&(n=null)}return n!=null&&t-n.ts>ew?null:n}function FF(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function pd(e,{bypassThrottle:t=!1}={}){let n=e?.workspace?.branch;if(!n)return;let r;try{r=await q(e)}catch{return}let o=ca(r);if(o==null)return;let s=(e.boxes||[]).find(d=>d.name===e.leadBox);if(await Ho(e.leadBox,s?.agent).catch(()=>!1))return;let a=Date.now();if(!t&&a-(Qh.get(e.id)||0)<LF)return;Qh.set(e.id,a);let i;try{i=await On(e.cwd,{caller:"reconcile"})}catch{return}let c=await ta(e).catch(()=>[n]),l=(i||[]).find(d=>c.includes(d.headRefName));if(!l)return;let u=await _e(e.cwd).catch(()=>null);if(u){let{link:d,created:p}=await Ct({repo:u,number:l.number,trackId:e.id,url:l.url,headRef:l.headRefName||n,title:l.title,source:"reconciled"});if(!p&&!(d?.trackId===e.id&&await tr(u,l.number))){if(!FF(d,o))return;let f=await q(e).catch(()=>null);if(f&&ca(f)==null)return;await M(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"pushed",number:l.number,url:l.url,title:l.title,branch:n,repo:u}});return}}await M(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"opened",number:l.number,url:l.url,title:l.title,branch:n,...u?{repo:u}:{}}}).catch(()=>{}),Qh.delete(e.id)}var LF,Qh,ew,ic=K(()=>{pe();Uo();Tr();Rn();Wi();Wo();LF=6e3,Qh=new Map,ew=30*6e4});import tw from"node:os";import{execFile as UF}from"node:child_process";import{promisify as HF}from"node:util";async function fd(){if(process.platform!=="darwin")return tw.freemem();try{let{stdout:e}=await WF("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:tw.freemem()}catch{return tw.freemem()}}var WF,nw=K(()=>{WF=HF(UF)});import Xe from"node:fs/promises";import et from"node:path";import WA from"node:os";import{randomUUID as qF}from"node:crypto";import{execFile as KF}from"node:child_process";import{promisify as GF}from"node:util";import{chromium as zF}from"playwright-core";async function Fn(){return Go||(rw||=(async()=>{try{Go=JSON.parse(await Xe.readFile(KA,"utf8"))}catch{Go={mocks:[]}}finally{rw=null}return Go.mocks||=[],Go})(),rw)}async function Jt(){await Et(KA,Go)}function JA(e,t){Ln(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&Ln(e,t.v,"png")}function kt(e,t,n={}){return M({id:e.trackId,cwd:e.cwd},{type:"mock.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,mockId:e.id,name:e.name,...e.group?{group:e.group}:{},...e.kind==="video"?{kind:"video"}:{},...n}}).catch(()=>{})}function Yt(e,t){let n=lc(e.cwd);return{html:et.join(n,`${e.id}.v${t}.html`),png:et.join(n,`${e.id}.v${t}.png`)}}function cc(e,t,n){if(!t)return null;let r=n==="html"?t.htmlRel:n==="png"?t.pngRel??t.posterRel??null:n==="video"?t.videoRel??null:null;return r?et.join(e.cwd,r):null}function pn(e,t=null){let n=e.versions||[];return t!=null?n.find(r=>r.v===Number(t))||null:n.length?n[n.length-1]:null}function aw(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function md(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(eU)}function tU(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 nU(e){let t=Buffer.alloc(24),n=await Xe.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function rU({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 oU(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((w,m)=>{r.onload=w,r.onerror=()=>m(new Error("decode failed")),r.src=`data:image/png;base64,${n}`});let o=r.naturalWidth,s=r.naturalHeight;if(!o||!s||o*s>24e6)return null;let a=document.createElement("canvas");a.width=o,a.height=s;let i=a.getContext("2d",{willReadFrequently:!0});i.drawImage(r,0,0);let c=i.getImageData(0,0,o,s).data,l=[c[0],c[1],c[2]],u=o,d=s,p=-1,f=-1;for(let w=0;w<s;w++)for(let m=w*o*4,g=0;g<o;g++,m+=4)Math.abs(c[m]-l[0])+Math.abs(c[m+1]-l[1])+Math.abs(c[m+2]-l[2])>24&&(g<u&&(u=g),g>p&&(p=g),w<d&&(d=w),f=w);return p<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:d,right:p,bottom:f}}},t.toString("base64"))}async function sU(e,t,{bg:n,crop:r}){let o=await e.evaluate(async({b64:s,bg:a,crop:i})=>{let c=new Image;await new Promise((d,p)=>{c.onload=d,c.onerror=()=>p(new Error("decode failed")),c.src=`data:image/png;base64,${s}`});let l=document.createElement("canvas");l.width=i.outW,l.height=i.outH;let u=l.getContext("2d");return u.fillStyle=`rgb(${a[0]},${a[1]},${a[2]})`,u.fillRect(0,0,i.outW,i.outH),u.drawImage(c,i.sx,i.sy,i.sw,i.sh,i.dx,i.dy,i.sw,i.sh),l.toDataURL("image/png").split(",")[1]},{b64:t.toString("base64"),bg:n,crop:r});return Buffer.from(o,"base64")}async function aU({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await zF.launch({executablePath:GA,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new Nt("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:la})).newPage();a.setDefaultTimeout(ua),await a.goto(`file://${e}`,{waitUntil:"load",timeout:ua}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:ua});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await oU(a,i),u=l&&rU({...l,pad:YF*la,align:la});u&&(i=await sU(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<zA)throw new Nt(`capture produced a ${i.length}-byte image`);let c=aw(i);if(!c)throw new Nt("output is not a PNG");return await Xe.writeFile(t,i),{width:Math.round(c.width/la),height:Math.round(c.height/la),dpr:la,renderMs:Date.now()-r}}catch(s){throw s instanceof Nt?s:new Nt(/timeout/i.test(s?.message||"")?`render timed out after ${ua}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function HA({htmlPath:e,outPath:t,width:n}){let r=await Xe.mkdtemp(et.join(WA.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await sw(FA,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:ua,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new Nt(`firefox not found (${FA})`,""):new Nt(c?.killed?`render timed out after ${ua}ms`:"firefox exited non-zero",s)}let a=await Xe.stat(t).catch(()=>null);if(!a||a.size<zA)throw new Nt(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=aw(await nU(t));if(!i)throw new Nt("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await Xe.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function iU(e){if(VF==="firefox")return HA(e);try{return await aU(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await HA(e)}catch(n){throw/not found/.test(n?.message||"")?new Nt(`no browser installed \u2014 chromium missing at ${GA} and no firefox on PATH; install chromium (Debian: apt install chromium fonts-dejavu-core fonts-liberation) or point BOSTRAT_CHROMIUM_BIN at a Chrome/Chromium binary`,t?.message||""):n}}}function YA(e){return ow=ow.then(e,e),ow}async function XA(e,t){let n=await Fn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Jt(),await kt(r,"rendering",{version:t});try{let o=await fd();if(o<XF)throw new Nt(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=Yt(r,t),a=await cU({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await Xe.rm(s.png,{force:!0}).catch(()=>{});return}iw(r,{v:t,source:"html",htmlRel:et.relative(r.cwd,s.html),pngRel:et.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Jt(),await kt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),jn(r),Ln(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Jt(),await kt(r,"error",{version:t,error:r.error}),jn(r)}}}function iw(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 lU({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?JF:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function uc({trackId:e,group:t}={}){let n=await Fn(),r=e?n.mocks.filter(o=>o.trackId===e):n.mocks;return t&&(r=r.filter(o=>o.group===t)),r.map(o=>({...o}))}async function pr(e){let n=(await Fn()).mocks.find(r=>r.id===e);return n?{...n}:null}function ZA({html:e,image:t,video:n}){if([typeof e=="string"&&e.trim(),!!t,!!n].filter(Boolean).length!==1)throw new Error("exactly one of html (string), image (png) or video (mp4/webm) required");if(t&&!md(t))throw new Error("image must be a PNG");if(n){let o=tU(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>UA)throw new Error(`video must be ${UA/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function QA({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=lU({trackId:e,name:t,cwd:s,width:a}),p=typeof n=="string"&&n.trim(),f=ZA({html:n,image:r,video:o}),w=await Fn(),m={id:qF().slice(0,8),trackId:e,box:c||null,agent:l||null,name:t.trim(),prompt:u?String(u).slice(0,500):null,group:i?String(i).trim():null,cwd:s,width:d,height:null,dpr:null,state:"queued",source:p?"html":o?"video":"image",kind:o?"video":"image",version:1,readyVersion:null,versions:[],error:null,renderMs:null,createdAt:Date.now(),updatedAt:Date.now()};return await Xe.mkdir(lc(s),{recursive:!0}),w.mocks.push(m),p?(await Xe.writeFile(Yt(m,1).html,n),await Jt(),await kt(m,"created"),jn(m),Ln(m,1,"html"),YA(()=>XA(m.id,1))):o?(await tE(m,1,o,f),await Jt(),await kt(m,"created"),await kt(m,"ready",{version:1,width:m.width,height:m.height,dpr:m.dpr,durationS:m.versions[0]?.durationS??null}),jn(m),JA(m,m.versions[0])):(await nE(m,1,r),await Jt(),await kt(m,"created"),await kt(m,"ready",{version:1,width:m.width,height:m.height,dpr:m.dpr}),jn(m),Ln(m,1,"png")),{...m}}async function eE(e,{html:t,image:n,video:r,width:o}={}){let a=(await Fn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=ZA({html:t,image:n,video:r});if(o!=null){let u=Number(o);if(!Number.isInteger(u)||u<320||u>4e3)throw new Error("invalid width (320-4000)");a.width=u}let l=a.version+1;return a.version=l,a.updatedAt=Date.now(),a.source=i?"html":r?"video":"image",a.kind=r?"video":"image",await Xe.mkdir(lc(a.cwd),{recursive:!0}),i?(a.state="queued",await Xe.writeFile(Yt(a,l).html,t),await Jt(),await kt(a,"updated",{version:l}),jn(a),Ln(a,l,"html"),YA(()=>XA(a.id,l))):r?(await tE(a,l,r,c),await Jt(),await kt(a,"updated",{version:l}),await kt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:pn(a)?.durationS??null}),jn(a),JA(a,a.versions.find(u=>u.v===l))):(await nE(a,l,n),await Jt(),await kt(a,"updated",{version:l}),await kt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),jn(a),Ln(a,l,"png")),{...a}}async function uU(e){try{let{stdout:t}=await sw(ZF,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:VA,killSignal:"SIGKILL",maxBuffer:4194304}),n=JSON.parse(t),r=(n.streams||[]).find(s=>s.codec_type==="video"),o=Number(n.format?.duration)||Number(r?.duration)||0;return{durationS:o>0?Math.round(o*10)/10:null,width:Number(r?.width)||null,height:Number(r?.height)||null}}catch{return null}}async function dU(e,t){try{await sw(QF,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:VA,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Xe.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function tE(e,t,n,r){let o=lc(e.cwd),s=et.join(o,`${e.id}.v${t}.${r.ext}`),a=et.join(o,`${e.id}.v${t}.poster.png`);await Xe.writeFile(s,n);let i=await uU(s),c=await dU(s,a);iw(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:et.relative(e.cwd,s),posterRel:c?et.relative(e.cwd,a):null,mimeType:r.mime,bytes:n.length,durationS:i?.durationS??null,width:i?.width??null,height:i?.height??null,dpr:1,renderMs:null,createdAt:Date.now()}),i?.width&&(e.width=i.width)}async function nE(e,t,n){let r=aw(n);if(!r)throw new Error("image must be a PNG");let o=Yt(e,t);await Xe.writeFile(o.png,n),iw(e,{v:t,source:"image",htmlRel:null,pngRel:et.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function rE(e){let t=await Fn(),n=t.mocks.find(o=>o.id===e);if(!n)throw new Error("mock not found");if(n.readyVersion==null)throw new Error(`mock is ${n.state} \u2014 nothing to pick yet`);let r=n.group?t.mocks.filter(o=>o.trackId===n.trackId&&o.group===n.group&&o.id!==e&&o.readyVersion!=null).map(o=>({mockId:o.id,name:o.name})):[];return await kt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function oE(e){let t=await Fn(),n=t.mocks.findIndex(o=>o.id===e);if(n===-1)throw new Error("mock not found");let r=t.mocks[n];t.mocks.splice(n,1);for(let o=1;o<=r.version;o++){let s=Yt(r,o);await Xe.rm(s.html,{force:!0}).catch(()=>{}),await Xe.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Xe.rm(et.join(r.cwd,s),{force:!0}).catch(()=>{});return await Jt(),await kt(r,"deleted"),tn("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function sE(e){let n=(await Fn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=et.join(qA,"mock-archive",e.id),o=lc(e.cwd),s=et.join(r,".bostrat","mocks");await Xe.mkdir(s,{recursive:!0});let a=await Xe.readdir(o).catch(()=>[]);for(let i of a)await Xe.copyFile(et.join(o,i),et.join(s,i));for(let i of n){for(let c of i.versions||[])for(let l of[c.htmlRel,c.pngRel,c.videoRel,c.posterRel]){if(!l)continue;if(!(await Xe.stat(et.join(r,l)).catch(()=>null))?.isFile())throw new Error(`mock evacuation incomplete: ${l} missing from the archive`)}i.cwd=r,i.trackDeletedAt=Date.now(),i.trackName=e.name||e.id,i.updatedAt=Date.now(),jn(i)}return await Jt(),n.length}async function aE(e){let t=await Fn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Jt();for(let r of n)tn("mocks",r.id).catch(()=>{})}return n.length}async function iE(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Fn();for(let r of n.mocks){await jn(r);for(let o of r.versions||[])o.htmlRel&&await Ln(r,o.v,"html"),(o.pngRel||o.posterRel)&&await Ln(r,o.v,"png"),o.videoRel&&await Ln(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var sw,qA,KA,VF,GA,FA,JF,la,YF,zA,ua,XF,UA,ZF,QF,VA,Nt,Go,rw,jn,Ln,lc,eU,cU,ow,da=K(()=>{pe();Er();nw();Ir();sw=GF(KF),qA=process.env.BOSTRAT_STATE_DIR||et.join(process.env.HOME||WA.tmpdir(),".bostrat"),KA=et.join(qA,"mocks.json"),VF=process.env.BOSTRAT_MOCK_ENGINE||"chromium",GA=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",FA=process.env.BOSTRAT_FIREFOX_BIN||"firefox",JF=1300,la=2,YF=32,zA=1500,ua=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,XF=700*1024*1024,UA=100*1024*1024,ZF=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",QF=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",VA=2e4,Nt=class extends Error{constructor(t,n=""){super(n?`${t}
203
+ `)}catch{return""}}async function kU(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await yU(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await lE(e.slug)||"server exited before listening"),pr.delete(e.id),await fr(e,e.state,e.error?{error:e.error}:{}),!0}if(await vc(e.port))return pr.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await fr(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>bU?(e.state="error",e.error=await lE(e.slug)||"never started listening",await fr(e,"error",{error:e.error}),!0):!1;let o=(pr.get(e.id)||0)+1;return pr.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function Md(){if(!xw){xw=!0;try{let e=await hr(),t=!1;for(let n of e.views)await kU(n)&&(t=!0);t&&await Ln()}finally{xw=!1}}}async function Rw({trackId:e}={}){await Md();let t=await hr();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function yE(e){let n=(await hr()).views.find(r=>r.id===e);return n?{...n}:null}function Ow(e){return Bn&&Bn.views.find(t=>t.slug===e)||null}async function Mw({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=Ct.resolve(r,o??"."),d=i==="detected"?null:async()=>{await hU(r,u),await mU(u,n)},p=await hr();if(i!=="detected"){let h=Aw(t),g=String(n).trim(),y=p.views.find(x=>x.trackId===e&&(x.slug===h||Aw(x.name)===h||x.cmd===g&&Ct.resolve(x.serveCwd??x.cwd)===u));if(y)return xU(p,y,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:d})}if(d&&await d(),p.views.filter(h=>h.state==="live"||h.state==="starting").length>=uo)throw new Error(`view cap reached (${uo} live) \u2014 stop one first`);let w={id:ZF().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:wU(p,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await gU(p,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await $w(w),p.views.push(w),await Ln(),await fr(w,"created",{origin:i}),Sw(e,w.id),i==="detected"&&await vc(w.port)&&(w.state="live",w.lastHealthyAt=Date.now(),await Ln(),await fr(w,"live")),{...w}}async function xU(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 pU(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await vc(t.port))return await Ln(),Sw(t.trackId,t.id),{...t,reused:!0};if(a&&await a(),e.views.filter(d=>d.id!==t.id&&(d.state==="live"||d.state==="starting")).length>=uo)throw new Error(`view cap reached (${uo} live) \u2014 stop one first`);return t.origin==="detected"?(await Iw(t.port),t.origin="agent"):await Sc(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),pr.delete(t.id),await $w(t),await Ln(),await fr(t,"created",{restarted:!0,reused:!0}),Sw(t.trackId,t.id),{...t,reused:!0}}async function bE(e){let n=(await hr()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await Iw(n.port):await Sc(n.slug),n.state!=="stopped"&&(n.state="stopped",pr.delete(n.id),await Ln(),await fr(n,"stopped")),{...n}}async function kE(e){let t=await hr(),n=t.views.find(o=>o.id===e);if(!n)throw new Error("view not found");if(!n.cmd)throw new Error("a detected view has no known command \u2014 recreate it as a managed view");if(t.views.filter(o=>o.id!==e&&(o.state==="live"||o.state==="starting")).length>=uo)throw new Error(`view cap reached (${uo} live) \u2014 stop one first`);return await Sc(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),pr.delete(n.id),await $w(n),await Ln(),await fr(n,"created",{restarted:!0}),{...n}}async function xE(e){let t=await hr(),n=t.views.findIndex(o=>o.id===e);if(n===-1)throw new Error("view not found");let r=t.views[n];return r.origin==="detected"?await Iw(r.port):await Sc(r.slug),t.views.splice(n,1),pr.delete(r.id),await Ln(),await fr(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function Cw(e){let t=await hr(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await Sc(r.slug),pr.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await Ln()),n.length}async function vE(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await hr(),r=n.adoptWatermarks[e.id]??null,o=t.filter(c=>c.role==="assistant"&&c.ts!=null&&(r==null?!1:c.ts>r)),s=t.reduce((c,l)=>l.ts>c?l.ts:c,r??0);if(n.adoptWatermarks[e.id]!==s&&(n.adoptWatermarks[e.id]=s,await Ln()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(vU)){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(!gE().has(c)&&!n.views.some(l=>l.port===c)&&await vc(c))try{i.push(await Mw({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 jn,tU,uE,aE,iE,uo,nU,va,cE,bc,rU,vw,oU,sU,aU,Tw,dE,bw,lU,dU,fE,Rd,Bn,kw,kc,Ew,hE,pr,bU,xw,vU,Cd=q(()=>{ut();he();Nr();jn=eU(QF),tU=process.env.BOSTRAT_STATE_DIR||Ct.join(process.env.HOME||YF.tmpdir(),".bostrat"),uE=Ct.join(tU,"views.json"),[aE,iE]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),uo=Number(process.env.BOSTRAT_VIEW_MAX)||3,nU="bostrat-view-",va=e=>`${nU}${e}`,cE=new Set(["bostrat","www","api","views","app"]),bc=e=>Object.assign(new Error(e),{status:400}),rU=new Set(["npm","pnpm","yarn","bun"]),vw="package.json",oU=/[|;&`]|\$\(/,sU=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),aU=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,Tw=e=>String(e).trim().split(/\s+/).filter(Boolean),dE=/^[A-Za-z_][A-Za-z0-9_]*=/;bw=e=>e==="/",lU=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");dU=e=>xc.stat(e).then(t=>t.isDirectory(),()=>!1),fE=e=>xc.stat(e).then(t=>t.isFile(),()=>!1),Rd=e=>xc.realpath(e).catch(()=>Ct.resolve(e));Bn=null,kw=null;kc=new Map,Ew=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,hE=12e3;pr=new Map,bU=12e4;xw=!1;vU=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});function Sa(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>Pw?null:n}function AU(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function Nd(e,{bypassThrottle:t=!1}={}){let n=e?.workspace?.branch;if(!n)return;let r;try{r=await K(e)}catch{return}let o=Sa(r);if(o==null)return;let s=(e.boxes||[]).find(d=>d.name===e.leadBox);if(await os(e.leadBox,s?.agent).catch(()=>!1))return;let a=Date.now();if(!t&&a-(Nw.get(e.id)||0)<SU)return;Nw.set(e.id,a);let i;try{i=await Cn(e.cwd,{caller:"reconcile"})}catch{return}let c=await wa(e).catch(()=>[n]),l=(i||[]).find(d=>c.includes(d.headRefName));if(!l)return;let u=await _e(e.cwd).catch(()=>null);if(u){let{link:d,created:p}=await Lt({repo:u,number:l.number,trackId:e.id,url:l.url,headRef:l.headRefName||n,title:l.title,source:"reconciled"});if(!p&&!(d?.trackId===e.id&&await or(u,l.number))){if(!AU(d,o))return;let f=await K(e).catch(()=>null);if(f&&Sa(f)==null)return;await C(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"pushed",number:l.number,url:l.url,title:l.title,branch:n,repo:u}});return}}await C(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:{ts:Date.now(),change:"opened",number:l.number,url:l.url,title:l.title,branch:n,...u?{repo:u}:{}}}).catch(()=>{}),Nw.delete(e.id)}var SU,Nw,Pw,Ac=q(()=>{he();rs();Or();Mn();ac();ss();SU=6e3,Nw=new Map,Pw=30*6e4});import Dw from"node:os";import{execFile as TU}from"node:child_process";import{promisify as EU}from"node:util";async function Pd(){if(process.platform!=="darwin")return Dw.freemem();try{let{stdout:e}=await _U("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:Dw.freemem()}catch{return Dw.freemem()}}var _U,Bw=q(()=>{_U=EU(TU)});import Ze from"node:fs/promises";import tt from"node:path";import EE from"node:os";import{randomUUID as IU}from"node:crypto";import{execFile as $U}from"node:child_process";import{promisify as RU}from"node:util";import{chromium as OU}from"playwright-core";async function Hn(){return cs||(jw||=(async()=>{try{cs=JSON.parse(await Ze.readFile(IE,"utf8"))}catch{cs={mocks:[]}}finally{jw=null}return cs.mocks||=[],cs})(),jw)}async function Qt(){await Rt(IE,cs)}function ME(e,t){Un(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&Un(e,t.v,"png")}function At(e,t,n={}){return C({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 en(e,t){let n=Ec(e.cwd);return{html:tt.join(n,`${e.id}.v${t}.html`),png:tt.join(n,`${e.id}.v${t}.png`)}}function Tc(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?tt.join(e.cwd,r):null}function hn(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 Uw(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function Dd(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(jU)}function LU(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 FU(e){let t=Buffer.alloc(24),n=await Ze.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function UU({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 HU(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((w,h)=>{r.onload=w,r.onerror=()=>h(new Error("decode failed")),r.src=`data:image/png;base64,${n}`});let o=r.naturalWidth,s=r.naturalHeight;if(!o||!s||o*s>24e6)return null;let a=document.createElement("canvas");a.width=o,a.height=s;let i=a.getContext("2d",{willReadFrequently:!0});i.drawImage(r,0,0);let c=i.getImageData(0,0,o,s).data,l=[c[0],c[1],c[2]],u=o,d=s,p=-1,f=-1;for(let w=0;w<s;w++)for(let h=w*o*4,g=0;g<o;g++,h+=4)Math.abs(c[h]-l[0])+Math.abs(c[h+1]-l[1])+Math.abs(c[h+2]-l[2])>24&&(g<u&&(u=g),g>p&&(p=g),w<d&&(d=w),f=w);return p<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:d,right:p,bottom:f}}},t.toString("base64"))}async function WU(e,t,{bg:n,crop:r}){let o=await e.evaluate(async({b64:s,bg:a,crop:i})=>{let c=new Image;await new Promise((d,p)=>{c.onload=d,c.onerror=()=>p(new Error("decode failed")),c.src=`data:image/png;base64,${s}`});let l=document.createElement("canvas");l.width=i.outW,l.height=i.outH;let u=l.getContext("2d");return u.fillStyle=`rgb(${a[0]},${a[1]},${a[2]})`,u.fillRect(0,0,i.outW,i.outH),u.drawImage(c,i.sx,i.sy,i.sw,i.sh,i.dx,i.dy,i.sw,i.sh),l.toDataURL("image/png").split(",")[1]},{b64:t.toString("base64"),bg:n,crop:r});return Buffer.from(o,"base64")}async function qU({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await OU.launch({executablePath:$E,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new Ft("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:Aa})).newPage();a.setDefaultTimeout(Ta),await a.goto(`file://${e}`,{waitUntil:"load",timeout:Ta}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:Ta});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await HU(a,i),u=l&&UU({...l,pad:NU*Aa,align:Aa});u&&(i=await WU(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<RE)throw new Ft(`capture produced a ${i.length}-byte image`);let c=Uw(i);if(!c)throw new Ft("output is not a PNG");return await Ze.writeFile(t,i),{width:Math.round(c.width/Aa),height:Math.round(c.height/Aa),dpr:Aa,renderMs:Date.now()-r}}catch(s){throw s instanceof Ft?s:new Ft(/timeout/i.test(s?.message||"")?`render timed out after ${Ta}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function TE({htmlPath:e,outPath:t,width:n}){let r=await Ze.mkdtemp(tt.join(EE.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await Fw(SE,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:Ta,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new Ft(`firefox not found (${SE})`,""):new Ft(c?.killed?`render timed out after ${Ta}ms`:"firefox exited non-zero",s)}let a=await Ze.stat(t).catch(()=>null);if(!a||a.size<RE)throw new Ft(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=Uw(await FU(t));if(!i)throw new Ft("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await Ze.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function KU(e){if(MU==="firefox")return TE(e);try{return await qU(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await TE(e)}catch(n){throw/not found/.test(n?.message||"")?new Ft(`no browser installed \u2014 chromium missing at ${$E} 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 CE(e){return Lw=Lw.then(e,e),Lw}async function NE(e,t){let n=await Hn(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Qt(),await At(r,"rendering",{version:t});try{let o=await Pd();if(o<PU)throw new Ft(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=en(r,t),a=await GU({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await Ze.rm(s.png,{force:!0}).catch(()=>{});return}Hw(r,{v:t,source:"html",htmlRel:tt.relative(r.cwd,s.html),pngRel:tt.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Qt(),await At(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),Fn(r),Un(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Qt(),await At(r,"error",{version:t,error:r.error}),Fn(r)}}}function Hw(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 zU({trackId:e,name:t,cwd:n,width:r}){if(!e)throw new Error("trackId required");if(typeof t!="string"||!t.trim())throw new Error("name (string) required");if(!n)throw new Error("cwd required");let o=r==null?CU:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function _c({trackId:e,group:t}={}){let n=await Hn(),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 mr(e){let n=(await Hn()).mocks.find(r=>r.id===e);return n?{...n}:null}function PE({html:e,image:t,video:n}){if([typeof e=="string"&&e.trim(),!!t,!!n].filter(Boolean).length!==1)throw new Error("exactly one of html (string), image (png) or video (mp4/webm) required");if(t&&!Dd(t))throw new Error("image must be a PNG");if(n){let o=LU(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>AE)throw new Error(`video must be ${AE/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function DE({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=zU({trackId:e,name:t,cwd:s,width:a}),p=typeof n=="string"&&n.trim(),f=PE({html:n,image:r,video:o}),w=await Hn(),h={id:IU().slice(0,8),trackId:e,box:c||null,agent:l||null,name:t.trim(),prompt:u?String(u).slice(0,500):null,group:i?String(i).trim():null,cwd:s,width:d,height:null,dpr:null,state:"queued",source:p?"html":o?"video":"image",kind:o?"video":"image",version:1,readyVersion:null,versions:[],error:null,renderMs:null,createdAt:Date.now(),updatedAt:Date.now()};return await Ze.mkdir(Ec(s),{recursive:!0}),w.mocks.push(h),p?(await Ze.writeFile(en(h,1).html,n),await Qt(),await At(h,"created"),Fn(h),Un(h,1,"html"),CE(()=>NE(h.id,1))):o?(await jE(h,1,o,f),await Qt(),await At(h,"created"),await At(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr,durationS:h.versions[0]?.durationS??null}),Fn(h),ME(h,h.versions[0])):(await LE(h,1,r),await Qt(),await At(h,"created"),await At(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr}),Fn(h),Un(h,1,"png")),{...h}}async function BE(e,{html:t,image:n,video:r,width:o}={}){let a=(await Hn()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=PE({html:t,image:n,video:r});if(o!=null){let u=Number(o);if(!Number.isInteger(u)||u<320||u>4e3)throw new Error("invalid width (320-4000)");a.width=u}let l=a.version+1;return a.version=l,a.updatedAt=Date.now(),a.source=i?"html":r?"video":"image",a.kind=r?"video":"image",await Ze.mkdir(Ec(a.cwd),{recursive:!0}),i?(a.state="queued",await Ze.writeFile(en(a,l).html,t),await Qt(),await At(a,"updated",{version:l}),Fn(a),Un(a,l,"html"),CE(()=>NE(a.id,l))):r?(await jE(a,l,r,c),await Qt(),await At(a,"updated",{version:l}),await At(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:hn(a)?.durationS??null}),Fn(a),ME(a,a.versions.find(u=>u.v===l))):(await LE(a,l,n),await Qt(),await At(a,"updated",{version:l}),await At(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),Fn(a),Un(a,l,"png")),{...a}}async function VU(e){try{let{stdout:t}=await Fw(DU,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:OE,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 JU(e,t){try{await Fw(BU,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:OE,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await Ze.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function jE(e,t,n,r){let o=Ec(e.cwd),s=tt.join(o,`${e.id}.v${t}.${r.ext}`),a=tt.join(o,`${e.id}.v${t}.poster.png`);await Ze.writeFile(s,n);let i=await VU(s),c=await JU(s,a);Hw(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:tt.relative(e.cwd,s),posterRel:c?tt.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 LE(e,t,n){let r=Uw(n);if(!r)throw new Error("image must be a PNG");let o=en(e,t);await Ze.writeFile(o.png,n),Hw(e,{v:t,source:"image",htmlRel:null,pngRel:tt.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function FE(e){let t=await Hn(),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 At(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function UE(e){let t=await Hn(),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=en(r,o);await Ze.rm(s.html,{force:!0}).catch(()=>{}),await Ze.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await Ze.rm(tt.join(r.cwd,s),{force:!0}).catch(()=>{});return await Qt(),await At(r,"deleted"),on("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function HE(e){let n=(await Hn()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=tt.join(_E,"mock-archive",e.id),o=Ec(e.cwd),s=tt.join(r,".bostrat","mocks");await Ze.mkdir(s,{recursive:!0});let a=await Ze.readdir(o).catch(()=>[]);for(let i of a)await Ze.copyFile(tt.join(o,i),tt.join(s,i));for(let i of n){for(let c of i.versions||[])for(let l of[c.htmlRel,c.pngRel,c.videoRel,c.posterRel]){if(!l)continue;if(!(await Ze.stat(tt.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(),Fn(i)}return await Qt(),n.length}async function WE(e){let t=await Hn(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Qt();for(let r of n)on("mocks",r.id).catch(()=>{})}return n.length}async function qE(){if(!Ue())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await it("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Hn();for(let r of n.mocks){await Fn(r);for(let o of r.versions||[])o.htmlRel&&await Un(r,o.v,"html"),(o.pngRel||o.posterRel)&&await Un(r,o.v,"png"),o.videoRel&&await Un(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var Fw,_E,IE,MU,$E,SE,CU,Aa,NU,RE,Ta,PU,AE,DU,BU,OE,Ft,cs,jw,Fn,Un,Ec,jU,GU,Lw,Ea=q(()=>{he();Nr();Bw();Dr();Fw=RU($U),_E=process.env.BOSTRAT_STATE_DIR||tt.join(process.env.HOME||EE.tmpdir(),".bostrat"),IE=tt.join(_E,"mocks.json"),MU=process.env.BOSTRAT_MOCK_ENGINE||"chromium",$E=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",SE=process.env.BOSTRAT_FIREFOX_BIN||"firefox",CU=1300,Aa=2,NU=32,RE=1500,Ta=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,PU=700*1024*1024,AE=100*1024*1024,DU=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",BU=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",OE=2e4,Ft=class extends Error{constructor(t,n=""){super(n?`${t}
204
204
  ${n.trim().split(`
205
205
  `).slice(-6).join(`
206
- `)}`:t),this.name="MockRenderError"}},Go=null,rw=null;jn=e=>bt("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),Ln=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?cc(e,r,"video"):r&&cc(e,r,n)||(n==="html"?Yt(e,t).html:null);return o?_r("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};lc=e=>et.join(e,".bostrat","mocks");eU=Buffer.from([137,80,78,71,13,10,26,10]);cU=iU,ow=Promise.resolve()});import pU from"node:fs/promises";import pE from"node:path";import fU from"node:os";import{randomUUID as fE}from"node:crypto";async function mr(){return fr||(cw||=(async()=>{let e=!0;try{fr=JSON.parse(await pU.readFile(mE,"utf8"))}catch{fr={flows:[]},e=!1}finally{cw=null}if(fr.flows||=[],!e&&He()){let{records:t,source:n}=await st("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&fr.flows.push(r.data);fr.flows.length&&await pa().catch(()=>{})}}return fr})(),cw)}async function pa(){await Et(mE,fr)}function lw(e,t,n={}){return M({id:e.trackId,cwd:e.cwd},{type:"flow.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,flowId:e.id,name:e.name,stepCount:e.steps.length,mockIds:[...new Set(e.steps.map(r=>r.mockId))],...n}}).catch(()=>{})}async function hE({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>cE)throw new Error(`steps must be an array of 1-${cE}`);let r=await uc({trackId:e}),o=[...n],s=[];for(let i=0;i<t.length;i++){let c=t[i]||{},l=`step ${i+1}`,u=typeof c.caption=="string"?c.caption.trim():"";if(!u)throw new Error(`${l}: caption (string) required`);if(u.length>uE)throw new Error(`${l}: caption over ${uE} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>dE)throw new Error(`${l}: title over ${dE} chars`);let p=String(c.mock??"").trim().replace(/^mock:/,"");if(!p)throw new Error(`${l}: mock (name or id) required`);let f=r.filter(x=>x.id===p);if(f.length||(f=r.filter(x=>x.name.toLowerCase()===p.toLowerCase())),!f.length)throw new Error(`${l}: no mock matching "${p}" in this Track \u2014 see \`bostrat-mock ls\``);if(f.length>1)throw new Error(`${l}: "${p}" is ambiguous (${f.map(x=>`mock:${x.id}`).join(", ")}) \u2014 use the id`);let w=f[0],m=null;if(c.v!=null&&(m=Number(c.v),!Number.isInteger(m)||!(w.versions||[]).some(x=>x.v===m)))throw new Error(`${l}: "${w.name}" has no captured v${c.v} to pin`);let g=o.findIndex(x=>x.mockId===w.id),y=g>=0?o.splice(g,1)[0].id:fE().slice(0,8);s.push({id:y,mockId:w.id,caption:u,title:d,v:m})}let a={};for(let i of s)i.mockId in a||(a[i.mockId]=r.find(c=>c.id===i.mockId)?.readyVersion??null);return{steps:s,resolved:a}}function hU(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>lE)throw new Error(`name over ${lE} chars`);return e.trim()}async function wE({trackId:e}={}){let t=await mr();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function wU(e){let n=(await mr()).flows.find(r=>r.id===e);return n?{...n}:null}async function gE(e){let t=await wU(e);if(!t)return null;let n=new Map((await uc({trackId:t.trackId})).map(r=>[r.id,r]));return t.steps=t.steps.map(r=>{let o=n.get(r.mockId);if(!o)return{...r,missing:!0,mockName:null,mockState:null,servedV:null,width:null,height:null};let s=pn(o,r.v);return{...r,missing:!1,mockName:o.name,mockState:o.state,servedV:s?.v??null,width:s?.width??null,height:s?.height??null}}),t}async function yE({trackId:e,name:t,steps:n,cwd:r,box:o,agent:s}){if(!e)throw new Error("trackId required");if(!r)throw new Error("cwd required");let a=hU(t),i=await mr(),c=i.flows.find(f=>f.trackId===e&&f.name.toLowerCase()===a.toLowerCase());if(c)throw new Error(`flow "${c.name}" already exists in this Track (flow:${c.id}) \u2014 revise it with \`bostrat-flow update\``);let{steps:l,resolved:u}=await hE({trackId:e,steps:n}),d=Date.now(),p={id:fE().slice(0,8),trackId:e,box:o||null,agent:s||null,name:a,cwd:r,version:1,versions:[{v:1,steps:l,resolved:u,note:null,createdAt:d}],steps:l,createdAt:d,updatedAt:d};return i.flows.push(p),await pa(),await lw(p,"created"),hd(p),{...p}}async function bE(e,{steps:t,note:n}={}){let o=(await mr()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await hE({trackId:o.trackId,steps:t,prevSteps:o.steps});return o.version+=1,o.versions.push({v:o.version,steps:s,resolved:a,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),o.steps=s,o.updatedAt=Date.now(),await pa(),await lw(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),hd(o),{...o}}async function kE(e){let t=await mr(),n=t.flows.findIndex(o=>o.id===e);if(n===-1)throw new Error("flow not found");let r=t.flows[n];return t.flows.splice(n,1),await pa(),await lw(r,"deleted"),tn("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function xE(e){return(await mr()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function vE(e){let n=(await mr()).flows.filter(r=>r.trackId===e.id);for(let r of n)r.trackDeletedAt=Date.now(),r.trackName=e.name||e.id,r.updatedAt=Date.now(),hd(r);return n.length&&await pa(),n.length}async function SE(e){let t=await mr(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await pa();for(let r of n)tn("flows",r.id).catch(()=>{})}return n.length}async function TE(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await mr();for(let r of n.flows)await hd(r);return{pushed:n.flows.length,source:"plane"}}var mU,mE,cE,lE,uE,dE,fr,cw,hd,uw=K(()=>{pe();Er();da();Ir();mU=process.env.BOSTRAT_STATE_DIR||pE.join(process.env.HOME||fU.tmpdir(),".bostrat"),mE=pE.join(mU,"flows.json"),cE=20,lE=80,uE=500,dE=80,fr=null,cw=null;hd=e=>bt("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import gr from"node:fs/promises";import yr from"node:path";import gU from"node:os";import{randomUUID as yU}from"node:crypto";function dc(e){return bU.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function Un(){return hr||(dw||=(async()=>{let e=!0;try{hr=JSON.parse(await gr.readFile(EE,"utf8"))}catch{hr={runbooks:[]},e=!1}finally{dw=null}return hr.runbooks||=[],!e&&He()&&await kU().catch(()=>{}),hr})(),dw)}async function Vo(){await Et(EE,hr)}function gd(e){return pc(bt("runbooks",{...e},{trackId:e.trackId}))}async function kU(){let{records:e,source:t}=await st("runbooks");if(!(t!=="plane"||!e.length)){await gr.mkdir(wd,{recursive:!0});for(let n of e){if(n.deletedAt||!n.data?.id)continue;let r=n.data;for(let o of r.versions||[]){let s=await ti("runbooks",r.id,o.v,"md");typeof s=="string"&&await gr.writeFile(wr(r,o.v),s).catch(()=>{})}hr.runbooks.push(r)}hr.runbooks.length&&await Vo()}}function fa(e,t,n={}){return M({id:e.trackId,cwd:e.cwd},{type:"runbook.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box||null,provider:e.agent||null,payload:{ts:Date.now(),change:t,runbookId:e.id,name:e.name,status:e.status,...n}}).catch(()=>{})}function wr(e,t){return yr.join(wd,`${e.id}.v${t}.md`)}function _E(e,t=null){let n=e.versions||[];return t!=null?n.find(r=>r.v===Number(t))||null:n.length?n[n.length-1]:null}function IE(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>AE)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${AE/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=dc(e);if(n.length)throw new Error(`runbook appears to contain a secret VALUE (${n.join(", ")}) \u2014 runbooks ship off-box; name the secret and where it goes, never its value. Replace it with a placeholder like <your key> and retry.`);return t}function xU(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function vU({trackId:e,status:t}={}){let n=await Un(),r=e?n.runbooks.filter(o=>o.trackId===e):n.runbooks;return t&&(r=r.filter(o=>o.status===t)),r.map(o=>({...o}))}async function $E({trackId:e,status:t}={}){let n=await Un(),r=await vU({trackId:e,status:t});if(!He())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await st("runbooks");if(s!=="plane")return{runbooks:r,fleetDegraded:!0};let a=new Set(n.runbooks.map(c=>c.id)),i=o.filter(c=>!c.deletedAt&&c.data?.id&&!a.has(c.data.id)).map(c=>({...c.data,originNode:c.originNode||null,remote:!0})).filter(c=>(!e||c.trackId===e)&&(!t||c.status===t));return{runbooks:[...r,...i],fleetDegraded:!1}}async function pw(e){let t=await SU(e);if(t)return t;if(!He())return null;let{records:n,source:r}=await st("runbooks");if(r!=="plane")return null;let o=n.find(s=>!s.deletedAt&&s.data?.id===e);return o?{...o.data,originNode:o.originNode||null,remote:!0}:null}async function RE(e,t){let n=await ti("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function SU(e){let n=(await Un()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function OE({trackId:e,trackName:t,name:n,md:r,cwd:o,box:s,agent:a}){if(!e)throw new Error("trackId required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");let i=IE(r),c=await Un(),l={id:yU().slice(0,8),trackId:e,trackName:t||e,box:s||null,agent:a||null,name:n.trim(),status:"open",version:1,versions:[],trackDeletedAt:null,cwd:o||null,createdAt:Date.now(),updatedAt:Date.now()};return await gr.mkdir(wd,{recursive:!0}),await gr.writeFile(wr(l,1),r),l.versions.push({v:1,mdRel:yr.relative(zo,wr(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await Vo(),await fa(l,"created",{version:1}),gd(l),pc(_r("runbooks",l.id,1,"md",wr(l,1))),{...l}}async function ME(e,{md:t,note:n}={}){let o=(await Un()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");xU(o,"update");let s=IE(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await gr.mkdir(wd,{recursive:!0}),await gr.writeFile(wr(o,a),t),o.versions.push({v:a,mdRel:yr.relative(zo,wr(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await Vo(),await fa(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),gd(o),pc(_r("runbooks",o.id,a,"md",wr(o,a))),{...o}}async function CE(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await Un()).runbooks.find(o=>o.id===e);if(!r)throw new Error("runbook not found");return r.status===t?{...r}:(r.status=t,r.updatedAt=Date.now(),await Vo(),await fa(r,t==="done"?"done":"reopened"),gd(r),{...r})}async function NE(e){let t=await Un(),n=t.runbooks.findIndex(o=>o.id===e);if(n===-1)throw new Error("runbook not found");let r=t.runbooks[n];t.runbooks.splice(n,1);for(let o of r.versions||[])await gr.rm(yr.join(zo,o.mdRel),{force:!0}).catch(()=>{});return await Vo(),r.trackDeletedAt||await fa(r,"deleted"),pc(tn("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function PE(e){let n=(await Un()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await fa(r,"orphaned"),r.cwd=null,gd(r);return n.length&&await Vo(),n.length}async function DE(e){let t=await Un(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await fa(r,"deleted");for(let o of r.versions||[])await gr.rm(yr.join(zo,o.mdRel),{force:!0}).catch(()=>{});pc(tn("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await Vo()),n.length}async function BE(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Un();for(let r of n.runbooks){await bt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await _r("runbooks",r.id,o.v,"md",yr.join(zo,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var zo,EE,wd,AE,bU,hr,dw,pc,yd=K(()=>{Er();pe();Ir();zo=process.env.BOSTRAT_STATE_DIR||yr.join(process.env.HOME||gU.tmpdir(),".bostrat"),EE=yr.join(zo,"runbooks.json"),wd=yr.join(zo,"runbooks"),AE=256*1024,bU=[{label:"Anthropic API key",re:/\bsk-ant-[A-Za-z0-9_-]{20,}/},{label:"OpenAI-style API key",re:/\bsk-(?:proj-|svcacct-)?[A-Za-z0-9_-]{32,}\b/},{label:"Stripe secret key",re:/\bsk_(?:live|test)_[A-Za-z0-9]{16,}/},{label:"GitHub token",re:/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}|\bgithub_pat_[A-Za-z0-9_]{22,}/},{label:"AWS access key id",re:/\bAKIA[0-9A-Z]{16}\b/},{label:"Slack token",re:/\bxox[baprs]-[A-Za-z0-9-]{10,}/},{label:"private key block",re:/-----BEGIN [A-Z ]*PRIVATE KEY-----/},{label:"JWT",re:/\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/}];hr=null,dw=null;pc=e=>Promise.resolve(e).catch(()=>{})});import fw from"node:fs/promises";import fc from"node:path";import{randomUUID as TU}from"node:crypto";function hw(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return AU.has(t)?"image":EU.has(t)?"doc":null}function _U(e){let r=fc.basename(String(e||"")).replace(/[\x00-\x1f]/g,"").replace(/[^A-Za-z0-9._-]+/g,"_").replace(/^_+|_+$/g,"").slice(-80)||"file";return r.startsWith(".")?`f${r}`:r}async function FE(e,{filename:t,buffer:n}){if(!e)throw new Error("cwd required");if(!Buffer.isBuffer(n)||n.length===0)throw new Error("empty upload");if(n.length>jE)throw new Error(`file too large \u2014 max ${Math.floor(jE/(1024*1024))} MB`);let r=_U(t),o=fc.extname(r).slice(1),s=hw(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=TU().slice(0,8),i=mw(e);await fw.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await fw.writeFile(fc.join(i,c),n,{mode:384}),await fw.chmod(fc.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${LE}/${c}`,kind:s,size:n.length}}function UE(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function ww(e){return e.role==="user"&&IU.test((e.text||"").trim())}var LE,mw,jE,AU,EU,IU,gw=K(()=>{LE=".bostrat/uploads",mw=e=>fc.join(e,LE),jE=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,AU=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),EU=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"]);IU=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function Jo(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}var HE=K(()=>{});import{execFile as $U}from"node:child_process";import{promisify as RU}from"node:util";function yw(e){return`refs/bostrat/wip/${e}`}function CU(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function KE(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function NU(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:MU}function GE(e){let t=e?.workspace;return t?.kind==="multi"?(Array.isArray(t.repos)?t.repos:[]).filter(n=>n?.dir).map(n=>({dir:n.dir,name:n.name??null,repo:n.repo??null})):e?.cwd?[{dir:e.cwd,name:null,repo:t?.repo??null}]:[]}async function PU(e,{log:t=console,force:n=!1,checkout:r=null}={}){let o=e?.id,s=r?.dir??e?.cwd;if(!o||!s)return{pushed:!1,reason:"no-workspace"};let a=r?.name?`${o}/${r.name}`:o;try{await ro(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await ro(s,["remote","get-url","origin"])}catch{return WE.has(s)||(WE.add(s),t.log?.(`[wip-sync] ${a}: no origin remote \u2014 durable code fidelity is chat/memory-only for this checkout`)),{pushed:!1,reason:"no-origin"}}try{let i=await qs(s,"bostrat: wip snapshot"),{stdout:c}=await ro(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(!n&&bd.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=yw(o);return await ro(s,["push","--force","origin",`${i}:${u}`],qE),bd.set(s,l),await M(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,wip:!0,...zE(r),ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${a}: pushed ${i.slice(0,7)} \u2192 ${u}`),{pushed:!0,sha:i,ref:u}}catch(i){return t.log?.(`[wip-sync] ${a}: push failed (will retry): ${String(i?.message||i).split(`
207
- `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function bw(e,{log:t=console,force:n=!1}={}){let r=[],o=[];for(let s of GE(e)){let a=await PU(e,{log:t,force:n,checkout:s});a.pushed?r.push({name:s.name,repo:s.repo,ref:a.ref,sha:a.sha}):o.push({name:s.name,repo:s.repo,reason:a.reason})}return{pushed:r,skipped:o}}async function DU(e,{log:t=console,checkout:n=null,ts:r=Date.now()}={}){let o=e?.id,s=n?.dir??e?.cwd;if(!o||!s)return{pushed:!1,reason:"no-workspace"};let a=n?.name?`${o}/${n.name}`:o;try{await ro(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await ro(s,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let i=await qs(s,"bostrat: transfer rescue snapshot"),{stdout:c}=await ro(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(bd.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=CU(o,r);return await ro(s,["push","origin",`${i}:${u}`],qE),bd.set(s,l),await M(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,rescue:!0,...zE(n),ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${a}: rescued stranded work ${i.slice(0,7)} \u2192 ${u}`),{pushed:!0,sha:i,ref:u}}catch(i){return t.log?.(`[wip-sync] ${a}: rescue push failed: ${String(i?.message||i).split(`
208
- `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function kw(e,{log:t=console,ts:n=Date.now()}={}){let r=[],o=[];for(let s of GE(e)){let a=await DU(e,{log:t,checkout:s,ts:n});a.pushed?r.push({name:s.name,repo:s.repo,ref:a.ref,sha:a.sha}):o.push({name:s.name,repo:s.repo,reason:a.reason})}return{pushed:r,skipped:o}}function VE({listTracks:e,sweepMs:t=NU(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)De(i)||i?.kind==="setup"||await bw(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 OU,MU,qE,ro,bd,WE,zE,xw=K(()=>{gu();pe();Gt();OU=RU($U),MU=12e4,qE=6e4;ro=(e,t,n=15e3)=>OU("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),bd=new Map,WE=new Set,zE=e=>e?.name||e?.repo?{name:e.name??null,repo:e.repo??null}:{}});import BU from"node:fs";import vw from"node:fs/promises";import jU from"node:path";function HU(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function JE(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(!HU(t))return{restored:!1,reason:"plane not configured"};let s=bs(e),a=jU.join(s,`${o}.ndjson`);try{if(BU.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=Oe(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let p=new AbortController,f=setTimeout(()=>p.abort(),UU),w;try{w=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${LU}`,{headers:c,signal:p.signal})}finally{clearTimeout(f)}if(w.status===404)return{restored:!1,reason:"unknown to plane"};if(!w.ok)return{restored:!1,reason:`plane ${w.status}`};let m=await w.json();for(let g of m.events||[])l.push(JSON.stringify(g));if(l.length>FU)return{restored:!1,reason:"event count over safety cap"};if(m.next==null)break;u=m.next}if(!l.length)return{restored:!1,reason:"unknown to plane"};await vw.mkdir(s,{recursive:!0});let d=`${a}.pull-${process.pid}-${Date.now()}`;return await vw.writeFile(d,l.join(`
206
+ `)}`:t),this.name="MockRenderError"}},cs=null,jw=null;Fn=e=>vt("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),Un=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?Tc(e,r,"video"):r&&Tc(e,r,n)||(n==="html"?en(e,t).html:null);return o?Pr("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};Ec=e=>tt.join(e,".bostrat","mocks");jU=Buffer.from([137,80,78,71,13,10,26,10]);GU=KU,Lw=Promise.resolve()});import YU from"node:fs/promises";import JE from"node:path";import XU from"node:os";import{randomUUID as YE}from"node:crypto";async function gr(){return wr||(Ww||=(async()=>{let e=!0;try{wr=JSON.parse(await YU.readFile(XE,"utf8"))}catch{wr={flows:[]},e=!1}finally{Ww=null}if(wr.flows||=[],!e&&Ue()){let{records:t,source:n}=await it("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&wr.flows.push(r.data);wr.flows.length&&await _a().catch(()=>{})}}return wr})(),Ww)}async function _a(){await Rt(XE,wr)}function qw(e,t,n={}){return C({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 ZE({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>KE)throw new Error(`steps must be an array of 1-${KE}`);let r=await _c({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>zE)throw new Error(`${l}: caption over ${zE} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>VE)throw new Error(`${l}: title over ${VE} chars`);let p=String(c.mock??"").trim().replace(/^mock:/,"");if(!p)throw new Error(`${l}: mock (name or id) required`);let f=r.filter(x=>x.id===p);if(f.length||(f=r.filter(x=>x.name.toLowerCase()===p.toLowerCase())),!f.length)throw new Error(`${l}: no mock matching "${p}" in this Track \u2014 see \`bostrat-mock ls\``);if(f.length>1)throw new Error(`${l}: "${p}" is ambiguous (${f.map(x=>`mock:${x.id}`).join(", ")}) \u2014 use the id`);let w=f[0],h=null;if(c.v!=null&&(h=Number(c.v),!Number.isInteger(h)||!(w.versions||[]).some(x=>x.v===h)))throw new Error(`${l}: "${w.name}" has no captured v${c.v} to pin`);let g=o.findIndex(x=>x.mockId===w.id),y=g>=0?o.splice(g,1)[0].id:YE().slice(0,8);s.push({id:y,mockId:w.id,caption:u,title:d,v:h})}let a={};for(let i of s)i.mockId in a||(a[i.mockId]=r.find(c=>c.id===i.mockId)?.readyVersion??null);return{steps:s,resolved:a}}function QU(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>GE)throw new Error(`name over ${GE} chars`);return e.trim()}async function QE({trackId:e}={}){let t=await gr();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function e4(e){let n=(await gr()).flows.find(r=>r.id===e);return n?{...n}:null}async function e_(e){let t=await e4(e);if(!t)return null;let n=new Map((await _c({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=hn(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 t_({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=QU(t),i=await gr(),c=i.flows.find(f=>f.trackId===e&&f.name.toLowerCase()===a.toLowerCase());if(c)throw new Error(`flow "${c.name}" already exists in this Track (flow:${c.id}) \u2014 revise it with \`bostrat-flow update\``);let{steps:l,resolved:u}=await ZE({trackId:e,steps:n}),d=Date.now(),p={id:YE().slice(0,8),trackId:e,box:o||null,agent:s||null,name:a,cwd:r,version:1,versions:[{v:1,steps:l,resolved:u,note:null,createdAt:d}],steps:l,createdAt:d,updatedAt:d};return i.flows.push(p),await _a(),await qw(p,"created"),Bd(p),{...p}}async function n_(e,{steps:t,note:n}={}){let o=(await gr()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await ZE({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 _a(),await qw(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),Bd(o),{...o}}async function r_(e){let t=await gr(),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 _a(),await qw(r,"deleted"),on("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function o_(e){return(await gr()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function s_(e){let n=(await gr()).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(),Bd(r);return n.length&&await _a(),n.length}async function a_(e){let t=await gr(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await _a();for(let r of n)on("flows",r.id).catch(()=>{})}return n.length}async function i_(){if(!Ue())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await it("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await gr();for(let r of n.flows)await Bd(r);return{pushed:n.flows.length,source:"plane"}}var ZU,XE,KE,GE,zE,VE,wr,Ww,Bd,Kw=q(()=>{he();Nr();Ea();Dr();ZU=process.env.BOSTRAT_STATE_DIR||JE.join(process.env.HOME||XU.tmpdir(),".bostrat"),XE=JE.join(ZU,"flows.json"),KE=20,GE=80,zE=500,VE=80,wr=null,Ww=null;Bd=e=>vt("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import kr from"node:fs/promises";import xr from"node:path";import t4 from"node:os";import{randomUUID as n4}from"node:crypto";function Ic(e){return r4.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function Wn(){return yr||(Gw||=(async()=>{let e=!0;try{yr=JSON.parse(await kr.readFile(l_,"utf8"))}catch{yr={runbooks:[]},e=!1}finally{Gw=null}return yr.runbooks||=[],!e&&Ue()&&await o4().catch(()=>{}),yr})(),Gw)}async function us(){await Rt(l_,yr)}function Ld(e){return $c(vt("runbooks",{...e},{trackId:e.trackId}))}async function o4(){let{records:e,source:t}=await it("runbooks");if(!(t!=="plane"||!e.length)){await kr.mkdir(jd,{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 ki("runbooks",r.id,o.v,"md");typeof s=="string"&&await kr.writeFile(br(r,o.v),s).catch(()=>{})}yr.runbooks.push(r)}yr.runbooks.length&&await us()}}function Ia(e,t,n={}){return C({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 br(e,t){return xr.join(jd,`${e.id}.v${t}.md`)}function u_(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 d_(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>c_)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${c_/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=Ic(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 s4(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function a4({trackId:e,status:t}={}){let n=await Wn(),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 p_({trackId:e,status:t}={}){let n=await Wn(),r=await a4({trackId:e,status:t});if(!Ue())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await it("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 zw(e){let t=await i4(e);if(t)return t;if(!Ue())return null;let{records:n,source:r}=await it("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 f_(e,t){let n=await ki("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function i4(e){let n=(await Wn()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function h_({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=d_(r),c=await Wn(),l={id:n4().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 kr.mkdir(jd,{recursive:!0}),await kr.writeFile(br(l,1),r),l.versions.push({v:1,mdRel:xr.relative(ls,br(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await us(),await Ia(l,"created",{version:1}),Ld(l),$c(Pr("runbooks",l.id,1,"md",br(l,1))),{...l}}async function m_(e,{md:t,note:n}={}){let o=(await Wn()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");s4(o,"update");let s=d_(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await kr.mkdir(jd,{recursive:!0}),await kr.writeFile(br(o,a),t),o.versions.push({v:a,mdRel:xr.relative(ls,br(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await us(),await Ia(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),Ld(o),$c(Pr("runbooks",o.id,a,"md",br(o,a))),{...o}}async function w_(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await Wn()).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 us(),await Ia(r,t==="done"?"done":"reopened"),Ld(r),{...r})}async function g_(e){let t=await Wn(),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 kr.rm(xr.join(ls,o.mdRel),{force:!0}).catch(()=>{});return await us(),r.trackDeletedAt||await Ia(r,"deleted"),$c(on("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function y_(e){let n=(await Wn()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await Ia(r,"orphaned"),r.cwd=null,Ld(r);return n.length&&await us(),n.length}async function b_(e){let t=await Wn(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await Ia(r,"deleted");for(let o of r.versions||[])await kr.rm(xr.join(ls,o.mdRel),{force:!0}).catch(()=>{});$c(on("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await us()),n.length}async function k_(){if(!Ue())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await it("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Wn();for(let r of n.runbooks){await vt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await Pr("runbooks",r.id,o.v,"md",xr.join(ls,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var ls,l_,jd,c_,r4,yr,Gw,$c,Fd=q(()=>{Nr();he();Dr();ls=process.env.BOSTRAT_STATE_DIR||xr.join(process.env.HOME||t4.tmpdir(),".bostrat"),l_=xr.join(ls,"runbooks.json"),jd=xr.join(ls,"runbooks"),c_=256*1024,r4=[{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/}];yr=null,Gw=null;$c=e=>Promise.resolve(e).catch(()=>{})});import Vw from"node:fs/promises";import Rc from"node:path";import{randomUUID as c4}from"node:crypto";function Yw(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return l4.has(t)?"image":u4.has(t)?"doc":null}function d4(e){let r=Rc.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 S_(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>x_)throw new Error(`file too large \u2014 max ${Math.floor(x_/(1024*1024))} MB`);let r=d4(t),o=Rc.extname(r).slice(1),s=Yw(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=c4().slice(0,8),i=Jw(e);await Vw.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await Vw.writeFile(Rc.join(i,c),n,{mode:384}),await Vw.chmod(Rc.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${v_}/${c}`,kind:s,size:n.length}}function A_(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function Xw(e){return e.role==="user"&&p4.test((e.text||"").trim())}var v_,Jw,x_,l4,u4,p4,Zw=q(()=>{v_=".bostrat/uploads",Jw=e=>Rc.join(e,v_),x_=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,l4=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),u4=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"]);p4=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function ds(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}var T_=q(()=>{});import{execFile as f4}from"node:child_process";import{promisify as h4}from"node:util";function Qw(e){return`refs/bostrat/wip/${e}`}function g4(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function I_(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function y4(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:w4}function $_(e){let t=e?.workspace;return t?.kind==="multi"?(Array.isArray(t.repos)?t.repos:[]).filter(n=>n?.dir).map(n=>({dir:n.dir,name:n.name??null,repo:n.repo??null})):e?.cwd?[{dir:e.cwd,name:null,repo:t?.repo??null}]:[]}async function b4(e,{log:t=console,force:n=!1,checkout:r=null}={}){let o=e?.id,s=r?.dir??e?.cwd;if(!o||!s)return{pushed:!1,reason:"no-workspace"};let a=r?.name?`${o}/${r.name}`:o;try{await po(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await po(s,["remote","get-url","origin"])}catch{return E_.has(s)||(E_.add(s),t.log?.(`[wip-sync] ${a}: no origin remote \u2014 durable code fidelity is chat/memory-only for this checkout`)),{pushed:!1,reason:"no-origin"}}try{let i=await ia(s,"bostrat: wip snapshot"),{stdout:c}=await po(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(!n&&Ud.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=Qw(o);return await po(s,["push","--force","origin",`${i}:${u}`],__),Ud.set(s,l),await C(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,wip:!0,...R_(r),ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${a}: pushed ${i.slice(0,7)} \u2192 ${u}`),{pushed:!0,sha:i,ref:u}}catch(i){return t.log?.(`[wip-sync] ${a}: push failed (will retry): ${String(i?.message||i).split(`
207
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function eg(e,{log:t=console,force:n=!1}={}){let r=[],o=[];for(let s of $_(e)){let a=await b4(e,{log:t,force:n,checkout:s});a.pushed?r.push({name:s.name,repo:s.repo,ref:a.ref,sha:a.sha}):o.push({name:s.name,repo:s.repo,reason:a.reason})}return{pushed:r,skipped:o}}async function k4(e,{log:t=console,checkout:n=null,ts:r=Date.now()}={}){let o=e?.id,s=n?.dir??e?.cwd;if(!o||!s)return{pushed:!1,reason:"no-workspace"};let a=n?.name?`${o}/${n.name}`:o;try{await po(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await po(s,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let i=await ia(s,"bostrat: transfer rescue snapshot"),{stdout:c}=await po(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(Ud.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=g4(o,r);return await po(s,["push","origin",`${i}:${u}`],__),Ud.set(s,l),await C(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,rescue:!0,...R_(n),ts:Date.now()}}).catch(()=>{}),t.log?.(`[wip-sync] ${a}: rescued stranded work ${i.slice(0,7)} \u2192 ${u}`),{pushed:!0,sha:i,ref:u}}catch(i){return t.log?.(`[wip-sync] ${a}: rescue push failed: ${String(i?.message||i).split(`
208
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function tg(e,{log:t=console,ts:n=Date.now()}={}){let r=[],o=[];for(let s of $_(e)){let a=await k4(e,{log:t,checkout:s,ts:n});a.pushed?r.push({name:s.name,repo:s.repo,ref:a.ref,sha:a.sha}):o.push({name:s.name,repo:s.repo,reason:a.reason})}return{pushed:r,skipped:o}}function O_({listTracks:e,sweepMs:t=y4(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)je(i)||i?.kind==="setup"||await eg(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 m4,w4,__,po,Ud,E_,R_,ng=q(()=>{Lu();he();Yt();m4=h4(f4),w4=12e4,__=6e4;po=(e,t,n=15e3)=>m4("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),Ud=new Map,E_=new Set,R_=e=>e?.name||e?.repo?{name:e.name??null,repo:e.repo??null}:{}});import x4 from"node:fs";import rg from"node:fs/promises";import v4 from"node:path";function E4(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function M_(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(!E4(t))return{restored:!1,reason:"plane not configured"};let s=Bs(e),a=v4.join(s,`${o}.ndjson`);try{if(x4.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=Re(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let p=new AbortController,f=setTimeout(()=>p.abort(),T4),w;try{w=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${S4}`,{headers:c,signal:p.signal})}finally{clearTimeout(f)}if(w.status===404)return{restored:!1,reason:"unknown to plane"};if(!w.ok)return{restored:!1,reason:`plane ${w.status}`};let h=await w.json();for(let g of h.events||[])l.push(JSON.stringify(g));if(l.length>A4)return{restored:!1,reason:"event count over safety cap"};if(h.next==null)break;u=h.next}if(!l.length)return{restored:!1,reason:"unknown to plane"};await rg.mkdir(s,{recursive:!0});let d=`${a}.pull-${process.pid}-${Date.now()}`;return await rg.writeFile(d,l.join(`
209
209
  `)+`
210
- `),await vw.rename(d,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var LU,FU,UU,YE=K(()=>{pt();pe();LU=1e3,FU=5e5,UU=3e4});function XE(e,t=Date.now()){let n=e.find(s=>s.reconcile||s.ciFix);if(n?.reconcile)return{status:"working",since:n.reconcile.delegatedAt,summary:"reconciling the branch"};if(n?.ciFix)return{status:"working",since:n.ciFix.delegatedAt,summary:"repairing failed checks"};let r=e.find(s=>s.reconcileAwait||s.ciFixAwait);if(r?.reconcileAwait)return{status:"waiting",since:r.reconcileAwait.since,summary:"fix pushed \u2014 waiting for mergeability"};if(r?.ciFixAwait)return{status:"waiting",since:r.ciFixAwait.since,summary:"fix pushed \u2014 waiting for CI"};let o=e.filter(s=>s.autoMerge||s.armedAt);return o.length?{status:"waiting",since:Math.min(...o.map(s=>s.autoMerge?.armedAt||s.armedAt||t)),count:o.length,summary:o.length===1?"auto-merge armed \u2014 lands when checks pass":`auto-merge armed on ${o.length} PRs`}:null}function ZE(e){let t=(e||[]).filter(n=>!WU.has(n.state)&&!n.ciFix&&!n.reconcile&&!n.ciFixAwait&&!n.reconcileAwait&&!n.autoMerge&&!n.armedAt);return t.length?{count:t.length,since:Math.min(...t.map(n=>n.announcedAt||n.firstSeen||Date.now())),summary:t.length===1?`PR #${t[0].number} is open \u2014 review, merge or arm it`:`${t.length} open PRs waiting on you`}:null}function QE({archivedAt:e=null,archiving:t=!1,prompted:n=!1,openActions:r=0,openActionSince:o=null,loopAttention:s=!1,prDecisions:a=null,operation:i=null,phase:c=null,working:l=!1,workingSince:u=null,pending:d=null,completedTurnAt:p=null,live:f=!1,now:w=Date.now()}={}){return e&&!t?fn("archived","lifecycle",e):n||r>0||s?fn("needs-you",n?"pane":s?"loop":"obligations",o||w,{count:r||(n||s?1:null)}):t?fn("archiving","lifecycle",e||w):a?.count?fn("needs-you","pr",a.since,{count:a.count,summary:a.summary??null}):i?.status==="working"?fn("working","operation",i.since,{summary:i.summary??null,count:i.count??null}):(l||n)&&c?.phase?fn("working","agent-phase",c.at,{summary:c.summary??null}):l?fn("working","pane",u||w):i?.status==="waiting"?fn("waiting","operation",i.since,{summary:i.summary??null,count:i.count??null}):d?.count?fn("waiting",d.source||"pending",d.since,{summary:d.summary??null,count:d.count}):p&&f?fn("settled","obligations",p,{summary:"no open actions"}):fn("idle","fallback",p||w)}var fn,WU,e_=K(()=>{fn=(e,t,n,r={})=>({kind:e,source:t,since:n||0,...r});WU=new Set(["merged","closed","lost"])});function qU(e,t){let n=0;for(let o of e||[]){if(o?.type!=="track.obligations.changed")continue;let s=Number(o.payload?.open);n=Number.isFinite(s)&&s>0?Math.floor(s):0}let r=Number(t?.openActions)||0;return r===n?null:{open:r,since:r?t.openActionSince??null:null}}async function KU(e,t,n){let r=qU(t,n);return r?M(e,{type:"track.obligations.changed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),open:r.open,since:r.since}}).catch(()=>null):null}async function Sw(e){if(kd.has(e.id))return kd.get(e.id);let t=await q(e).catch(()=>[]),n=[];try{n=_n(t)}catch{}let r=ou(n),o=n.filter(f=>f?.kind==="followup-offer"&&f.status==="open"),s=new Set(t.filter(f=>f.type==="prompt.answered").map(f=>f.payload?.promptId)),a=t.filter(f=>f.type==="prompt.raised"&&f.payload?.promptId&&!s.has(f.payload.promptId)),i=[...r,...o,...a.map(f=>({ts:f.payload?.ts??f.ts}))],c=null;for(let f of t){if(f.type!=="track.phase.changed")continue;let w=f.payload||{};c=w.phase?{phase:w.phase,summary:w.summary??null,scope:w.scope??null,phaseId:w.phaseId??null,at:w.ts??f.ts}:null}let l=n.flatMap(f=>f?.kind==="job-dock"?f.jobs||[]:[]).filter(f=>f?.status==="running"),u=t.reduce((f,w)=>w.type==="turn.agent"?Math.max(f,w.payload?.ts??w.ts??0):f,0)||null,d=t.reduce((f,w)=>w.type==="turn.user"?Math.max(f,w.payload?.ts??w.ts??0):f,0)||null,p={openActions:i.length,openActionSince:i.length?Math.min(...i.map(f=>f.ts||Date.now())):null,phase:c,completedTurnAt:u,currentTurnAt:d,runningJobs:l.length,runningJobsSince:l.length?Math.min(...l.map(f=>f.startedTs||Date.now())):null};return kd.set(e.id,p),!De(e)&&e.kind!=="setup"&&KU(e,t,p),p}function t_({trackOf:e,debounceMs:t=GU,log:n=console}={}){if(typeof e!="function")throw new Error("watchObligations: trackOf(id) is required");let r=o=>{let s=o?.trackId;if(!s)return;clearTimeout(mc.get(s));let a=setTimeout(()=>{mc.delete(s),Promise.resolve(e(s)).then(i=>i&&!De(i)&&i.kind!=="setup"?Sw(i):null).catch(i=>n.warn?.(`[obligations] fold ${s} failed: ${i?.message||i}`))},t);a.unref?.(),mc.set(s,a)};return Je.on("event",r),()=>{Je.off("event",r);for(let o of mc.values())clearTimeout(o);mc.clear()}}var kd,GU,mc,Tw=K(()=>{pe();su();Gt();kd=new Map;Je.on("event",e=>{e?.trackId&&kd.delete(e.trackId)});GU=750,mc=new Map});import{randomUUID as zU}from"node:crypto";async function vd(e,t,n={}){let r={operationId:zU(),kind:t,startedAt:Date.now(),...n};return xd.set(e.id,r),await M(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:r.startedAt,state:"started",...r}}).catch(()=>{}),r}async function Aw(e,t,n="completed",r=null){xd.get(e.id)?.operationId===t?.operationId&&xd.delete(e.id),await M(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:Date.now(),state:"finished",operationId:t?.operationId,kind:t?.kind,outcome:n,...r?{error:String(r)}:{}}}).catch(()=>{})}var xd,n_,Ew=K(()=>{pe();xd=new Map;n_=e=>xd.get(e)||null});var P_={};Dp(P_,{HANDOFF_LATEST_REL:()=>Yo,KNOWN_AGENTS:()=>Ac,TRACK_NAME_MAX:()=>Lw,addTrackRepo:()=>ng,adoptTrack:()=>xg,agentAvailability:()=>_d,announceNodeUpdate:()=>Wn,answerFullscreenOffer:()=>fg,answerPrompt:()=>$d,archiveTrack:()=>Zo,archiveTrackForMergedPr:()=>ar,augmentFirstPromptAfterHandoff:()=>f_,buildAgentCmd:()=>Uw,canResumeSubtask:()=>M_,cancelQueued:()=>Ic,cancelQueuedToDraft:()=>Jw,cancelStopJob:()=>$c,cancelSubtask:()=>Ld,changedRepos:()=>Ko,commitTransferOut:()=>Bd,createSetupTrack:()=>sg,createTrack:()=>Md,deleteTrack:()=>ig,demoteTransferredTracks:()=>kg,ensureLeadEpochs:()=>ka,forceMergeSubtask:()=>Ag,getHandoffJob:()=>Ta,getSubtaskJob:()=>s2,getTrack:()=>ie,getTransferOutJob:()=>gg,healDeadLead:()=>Sc,interruptLead:()=>Od,isArchiving:()=>K4,isHandoffNoteEcho:()=>Pw,isInterruptEcho:()=>Dw,isModelSwitchEcho:()=>Bw,leadCliDead:()=>lg,listSubtaskJobs:()=>es,listTracks:()=>he,matchTranscriptsToBoxes:()=>w_,mergeNotifyMessage:()=>I_,navigatePrompt:()=>zw,notifyTrackForMergedPr:()=>ir,notifyTrackForResolvedPr:()=>Cd,offerFollowupsForMergedPr:()=>Qo,pendingOffers:()=>Kw,queueGauges:()=>Vw,queueShipCompleteNotify:()=>Xw,queuedMessages:()=>Xo,rawTrack:()=>qw,reapArchivedOrphans:()=>pg,reconcileDemotedTracks:()=>dg,reconcileHandoffOutcome:()=>$_,reconcileInterruptedHandoffs:()=>hg,reconcileInterruptedSubtasks:()=>vg,reconcileNodeUpdateNotices:()=>Ww,reconcileSubtaskOutcome:()=>O_,refreshStandingInstructions:()=>og,refuseIfTransferred:()=>bg,rehydrateLead:()=>Oc,removeTrackRepo:()=>rg,renameTrack:()=>ug,reposOf:()=>$t,resolveTrackBox:()=>Xi,resolveTrackBoxByHookToken:()=>_c,restartLead:()=>Pd,resumeAgentCmd:()=>Hw,sayToLead:()=>Bt,sendOptionsForAgent:()=>En,setTrackDraft:()=>eg,setTrackModel:()=>tg,startLeadHandoff:()=>Dd,startSpinUpView:()=>Zw,startSubtask:()=>Tg,startTransferOut:()=>yg,stopJobActive:()=>b_,subtaskMessages:()=>Gw,trackMessages:()=>Id,unarchiveTrack:()=>Nd});import te from"node:fs/promises";import oe from"node:path";import{randomUUID as Ad}from"node:crypto";import{execFile as VU}from"node:child_process";import{promisify as JU}from"node:util";function Uw(e,{skipPermissions:t=!0,model:n=null}={}){let r=Ed[e];if(!r)throw new Error(`unknown agent "${e}"`);let o=process.env[r.envVar];if(o)return o;let s=t&&r.skipFlag?`${r.base} ${r.skipFlag}`:r.base;if(n&&n!=="default"){let a=Um(e).find(i=>i.alias===n);if(!a)throw new Error(`unknown ${e} launch model "${n}"`);s+=` --model ${a.alias}`}return s}function Hw(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=Ed[e];if(!s)throw new Error(`unknown agent "${e}"`);let a=process.env[s.envVar];if(a)return a;let i=n&&s.skipFlag?` ${s.skipFlag}`:"";switch(e){case"claude":{if(!t)return`${s.base}${i}`;if(r&&!sn(r,t)){let c=o&&je(o)?` --name ${o}`:"";return`${s.base} --session-id ${t}${c}${i}`}return`${s.base} --resume ${t}${i}`}case"cursor":return`${s.base} --continue${i}`;case"codex":return`${s.base} resume --last${i}`;default:return`${s.base}${i}`}}function Sa(e){let t=Ed[e];if(t)return process.env[t.envVar]||t.base}async function _d({maxAgeMs:e=6e4}={}){if(oo.value&&Date.now()-oo.at<e)return oo.value;let t=oo.value,n=await Promise.all(Ac.map(async r=>{let o=await Ll(Sa(r),{retries:[]});return o===As?[r,t?.[r]??!0]:[r,o===jl]}));return oo.value=Object.fromEntries(n),oo.at=Date.now(),oo.value}async function Ec(e,t=!0,n=null){let r=Uw(e,{skipPermissions:t,model:n});if(await Ll(r)===Ts){oo.at=0;let o=r.split(/\s+/)[0],s=process.env.FLY_APP_NAME?"This Fly node's image predates CLI parity \u2014 update the node image (Links page \u2192 Fly card \u2192 Update) or re-provision.":ff[o]?`Install it on this node: ${ff[o]}`:"Its CLI must be installed and on PATH first.";throw new Error(`agent "${e}" isn't available on this box (command not found: ${o}). ${s}`)}return r}function f_(e,t=Yo){return`${e.trim()}
210
+ `),await rg.rename(d,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var S4,A4,T4,C_=q(()=>{mt();he();S4=1e3,A4=5e5,T4=3e4});function N_(e,t=Date.now()){let n=e.find(s=>s.reconcile||s.ciFix);if(n?.reconcile)return{status:"working",since:n.reconcile.delegatedAt,summary:"reconciling the branch"};if(n?.ciFix)return{status:"working",since:n.ciFix.delegatedAt,summary:"repairing failed checks"};let r=e.find(s=>s.reconcileAwait||s.ciFixAwait);if(r?.reconcileAwait)return{status:"waiting",since:r.reconcileAwait.since,summary:"fix pushed \u2014 waiting for mergeability"};if(r?.ciFixAwait)return{status:"waiting",since:r.ciFixAwait.since,summary:"fix pushed \u2014 waiting for CI"};let o=e.filter(s=>s.autoMerge||s.armedAt);return o.length?{status:"waiting",since:Math.min(...o.map(s=>s.autoMerge?.armedAt||s.armedAt||t)),count:o.length,summary:o.length===1?"auto-merge armed \u2014 lands when checks pass":`auto-merge armed on ${o.length} PRs`}:null}function P_(e){let t=(e||[]).filter(n=>!_4.has(n.state)&&!n.ciFix&&!n.reconcile&&!n.ciFixAwait&&!n.reconcileAwait&&!n.autoMerge&&!n.armedAt);return t.length?{count:t.length,since:Math.min(...t.map(n=>n.announcedAt||n.firstSeen||Date.now())),summary:t.length===1?`PR #${t[0].number} is open \u2014 review, merge or arm it`:`${t.length} open PRs waiting on you`}:null}function D_({archivedAt:e=null,archiving:t=!1,prompted:n=!1,openActions:r=0,openActionSince:o=null,loopAttention:s=!1,prDecisions:a=null,operation:i=null,phase:c=null,working:l=!1,workingSince:u=null,pending:d=null,completedTurnAt:p=null,live:f=!1,now:w=Date.now()}={}){return e&&!t?mn("archived","lifecycle",e):n||r>0||s?mn("needs-you",n?"pane":s?"loop":"obligations",o||w,{count:r||(n||s?1:null)}):t?mn("archiving","lifecycle",e||w):a?.count?mn("needs-you","pr",a.since,{count:a.count,summary:a.summary??null}):i?.status==="working"?mn("working","operation",i.since,{summary:i.summary??null,count:i.count??null}):(l||n)&&c?.phase?mn("working","agent-phase",c.at,{summary:c.summary??null}):l?mn("working","pane",u||w):i?.status==="waiting"?mn("waiting","operation",i.since,{summary:i.summary??null,count:i.count??null}):d?.count?mn("waiting",d.source||"pending",d.since,{summary:d.summary??null,count:d.count}):p&&f?mn("settled","obligations",p,{summary:"no open actions"}):mn("idle","fallback",p||w)}var mn,_4,B_=q(()=>{mn=(e,t,n,r={})=>({kind:e,source:t,since:n||0,...r});_4=new Set(["merged","closed","lost"])});function I4(e,t){let n=0;for(let o of e||[]){if(o?.type!=="track.obligations.changed")continue;let s=Number(o.payload?.open);n=Number.isFinite(s)&&s>0?Math.floor(s):0}let r=Number(t?.openActions)||0;return r===n?null:{open:r,since:r?t.openActionSince??null:null}}async function $4(e,t,n){let r=I4(t,n);return r?C(e,{type:"track.obligations.changed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),open:r.open,since:r.since}}).catch(()=>null):null}async function og(e){if(Hd.has(e.id))return Hd.get(e.id);let t=await K(e).catch(()=>[]),n=[];try{n=$n(t)}catch{}let r=Tu(n),o=n.filter(f=>f?.kind==="followup-offer"&&f.status==="open"),s=new Set(t.filter(f=>f.type==="prompt.answered").map(f=>f.payload?.promptId)),a=t.filter(f=>f.type==="prompt.raised"&&f.payload?.promptId&&!s.has(f.payload.promptId)),i=[...r,...o,...a.map(f=>({ts:f.payload?.ts??f.ts}))],c=null;for(let f of t){if(f.type!=="track.phase.changed")continue;let w=f.payload||{};c=w.phase?{phase:w.phase,summary:w.summary??null,scope:w.scope??null,phaseId:w.phaseId??null,at:w.ts??f.ts}:null}let l=n.flatMap(f=>f?.kind==="job-dock"?f.jobs||[]:[]).filter(f=>f?.status==="running"),u=t.reduce((f,w)=>w.type==="turn.agent"?Math.max(f,w.payload?.ts??w.ts??0):f,0)||null,d=t.reduce((f,w)=>w.type==="turn.user"?Math.max(f,w.payload?.ts??w.ts??0):f,0)||null,p={openActions:i.length,openActionSince:i.length?Math.min(...i.map(f=>f.ts||Date.now())):null,phase:c,completedTurnAt:u,currentTurnAt:d,runningJobs:l.length,runningJobsSince:l.length?Math.min(...l.map(f=>f.startedTs||Date.now())):null};return Hd.set(e.id,p),!je(e)&&e.kind!=="setup"&&$4(e,t,p),p}function j_({trackOf:e,debounceMs:t=R4,log:n=console}={}){if(typeof e!="function")throw new Error("watchObligations: trackOf(id) is required");let r=o=>{let s=o?.trackId;if(!s)return;clearTimeout(Oc.get(s));let a=setTimeout(()=>{Oc.delete(s),Promise.resolve(e(s)).then(i=>i&&!je(i)&&i.kind!=="setup"?og(i):null).catch(i=>n.warn?.(`[obligations] fold ${s} failed: ${i?.message||i}`))},t);a.unref?.(),Oc.set(s,a)};return Je.on("event",r),()=>{Je.off("event",r);for(let o of Oc.values())clearTimeout(o);Oc.clear()}}var Hd,R4,Oc,sg=q(()=>{he();Eu();Yt();Hd=new Map;Je.on("event",e=>{e?.trackId&&Hd.delete(e.trackId)});R4=750,Oc=new Map});import{randomUUID as O4}from"node:crypto";async function qd(e,t,n={}){let r={operationId:O4(),kind:t,startedAt:Date.now(),...n};return Wd.set(e.id,r),await C(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:r.startedAt,state:"started",...r}}).catch(()=>{}),r}async function ag(e,t,n="completed",r=null){Wd.get(e.id)?.operationId===t?.operationId&&Wd.delete(e.id),await C(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:Date.now(),state:"finished",operationId:t?.operationId,kind:t?.kind,outcome:n,...r?{error:String(r)}:{}}}).catch(()=>{})}var Wd,L_,ig=q(()=>{he();Wd=new Map;L_=e=>Wd.get(e)||null});var gI={};wf(gI,{HANDOFF_LATEST_REL:()=>ho,KNOWN_AGENTS:()=>Wc,TRACK_NAME_MAX:()=>bg,addTrackRepo:()=>ap,adoptTrack:()=>ty,agentAvailability:()=>tp,announceNodeUpdate:()=>Kn,answerFullscreenOffer:()=>Vg,answerPrompt:()=>rp,archiveTrack:()=>ws,archiveTrackForMergedPr:()=>lr,augmentFirstPromptAfterHandoff:()=>J_,buildAgentCmd:()=>kg,canResumeSubtask:()=>hI,cancelQueued:()=>Kc,cancelQueuedToDraft:()=>Ig,cancelStopJob:()=>Ba,cancelSubtask:()=>gp,changedRepos:()=>is,commitTransferOut:()=>hp,createSetupTrack:()=>Fg,createTrack:()=>cp,deleteTrack:()=>Hg,demoteTransferredTracks:()=>ey,ensureLeadEpochs:()=>fs,forceMergeSubtask:()=>oy,getHandoffJob:()=>La,getReshapeJob:()=>Gc,getSubtaskJob:()=>q2,getTrack:()=>ie,getTransferOutJob:()=>Zg,healDeadLead:()=>Uc,interruptLead:()=>sp,isArchiving:()=>R2,isHandoffNoteEcho:()=>hg,isInterruptEcho:()=>mg,isModelSwitchEcho:()=>wg,leadCliDead:()=>qg,listSubtaskJobs:()=>ys,listTracks:()=>we,matchTranscriptsToBoxes:()=>Z_,mergeNotifyMessage:()=>uI,navigatePrompt:()=>Eg,notifyTrackForMergedPr:()=>ur,notifyTrackForResolvedPr:()=>lp,offerFollowupsForMergedPr:()=>gs,pendingOffers:()=>Ag,queueGauges:()=>_g,queueShipCompleteNotify:()=>Rg,queuedMessages:()=>ps,rawTrack:()=>Sg,reapArchivedOrphans:()=>zg,reconcileDemotedTracks:()=>Gg,reconcileHandoffOutcome:()=>dI,reconcileInterruptedHandoffs:()=>Yg,reconcileInterruptedReshapes:()=>jg,reconcileInterruptedSubtasks:()=>ny,reconcileNodeUpdateNotices:()=>vg,reconcileSubtaskOutcome:()=>fI,refreshStandingInstructions:()=>Lg,refuseIfTransferred:()=>fp,rehydrateLead:()=>zc,removeTrackRepo:()=>ip,renameTrack:()=>Kg,reposOf:()=>Dt,reshapeTrack:()=>Bg,resolveTrackBox:()=>hc,resolveTrackBoxByHookToken:()=>qc,restartLead:()=>dp,resumeAgentCmd:()=>ep,sayToLead:()=>Ht,sendOptionsForAgent:()=>In,setTrackDraft:()=>Cg,setTrackModel:()=>Ng,startLeadHandoff:()=>pp,startSpinUpView:()=>Og,startSubtask:()=>ry,startTransferOut:()=>Qg,stopJobActive:()=>tI,subtaskMessages:()=>Tg,trackMessages:()=>np,unarchiveTrack:()=>up});import J from"node:fs/promises";import z from"node:path";import{randomUUID as Xd}from"node:crypto";import{execFile as M4}from"node:child_process";import{promisify as C4}from"node:util";function kg(e,{skipPermissions:t=!0,model:n=null}={}){let r=Qd[e];if(!r)throw new Error(`unknown agent "${e}"`);let o=process.env[r.envVar];if(o)return o;let s=t&&r.skipFlag?`${r.base} ${r.skipFlag}`:r.base;if(n&&n!=="default"){let a=xm(e).find(i=>i.alias===n);if(!a)throw new Error(`unknown ${e} launch model "${n}"`);s+=` --model ${a.alias}`}return s}function ep(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=Qd[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&&!cn(r,t)){let c=o&&De(o)?` --name ${o}`:"";return`${s.base} --session-id ${t}${c}${i}`}return`${s.base} --resume ${t}${i}`}case"cursor":return`${s.base} --continue${i}`;case"codex":return`${s.base} resume --last${i}`;default:return`${s.base}${i}`}}function ms(e){let t=Qd[e];if(t)return process.env[t.envVar]||t.base}async function tp({maxAgeMs:e=6e4}={}){if(fo.value&&Date.now()-fo.at<e)return fo.value;let t=fo.value,n=await Promise.all(Wc.map(async r=>{let o=await au(ms(r),{retries:[]});return o===Ws?[r,t?.[r]??!0]:[r,o===su]}));return fo.value=Object.fromEntries(n),fo.at=Date.now(),fo.value}async function Da(e,t=!0,n=null){let r=kg(e,{skipPermissions:t,model:n});if(await au(r)===Hs){fo.at=0;let o=r.split(/\s+/)[0],s=process.env.FLY_APP_NAME?"This Fly node's image predates CLI parity \u2014 update the node image (Links page \u2192 Fly card \u2192 Update) or re-provision.":zf[o]?`Install it on this node: ${zf[o]}`:"Its CLI must be installed and on PATH first.";throw new Error(`agent "${e}" isn't available on this box (command not found: ${o}). ${s}`)}return r}function J_(e,t=ho){return`${e.trim()}
211
211
 
212
- (Read ${t} for handoff context from the prior lead \u2014 you are now the lead; none of the prior chat is in your context. Then respond to the user above.)`}function Pw(e){return e.role==="user"&&ZU.test((e.text||"").trim())}async function ee(){return Xt||(_w||=(async()=>{try{Xt=JSON.parse(await te.readFile(d_,"utf8"))}catch{Xt={tracks:[]}}finally{_w=null}return Xt})(),_w)}async function ue(){await Et(d_,Xt)}function t4(e,t){let n=JSON.stringify({trackId:e,...t})+`
213
- `;return Iw=Iw.then(()=>te.mkdir(Hn,{recursive:!0})).then(()=>te.appendFile(YU,n)).catch(()=>{}),Iw}async function Wn({current:e,latest:t,min:n=null,installKind:r=null,required:o=!1,status:s="available",policy:a=null,error:i=null,reason:c=null}={}){if(!t)return{announced:0};if(s==="available"){let d=null;try{d=JSON.parse(await te.readFile($w,"utf8"))}catch{}if(d?.latest===t&&d?.current===e)return{announced:0,deduped:!0}}let l=await ee(),u=0;for(let d of l.tracks)De(d)||!d.leadBox||($e(d,"node-update",{status:s,current:e??null,latest:t,...n?{min:n}:{},...r?{installKind:r}:{},...a?{policy:a}:{},...i?{error:String(i).slice(0,400)}:{},...c?{reason:c}:{},required:o===!0}),u++);if(await ue().catch(()=>{}),s==="available")try{await te.mkdir(oe.dirname($w),{recursive:!0}),await te.writeFile($w,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function Ww({current:e,installKind:t=null,policy:n=null}={}){if(!e)return{reconciled:!1,announced:0,targets:[]};let r=await ee(),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)||n4(e,c)||($e(a,"node-update",{status:"done",current:l.current??null,latest:c,...t?{installKind:t}:{},...n?{policy:n}:{},reason:"version-reconciled",installed:e,required:!1}),o++,s.add(c))}return o&&await ue().catch(()=>{}),{reconciled:o>0,announced:o,targets:[...s]}}function n4(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 m_(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=>r4.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 h_(e,t,n,{kind:r}={}){let o=await ke(t);if(!o)throw new Error(`box "${t}" is not running`);let s=Sa(o.agent),a=Qi({text:n,producer:Zi({kind:r,orchestration:!0}),kind:r||"orchestration",provider:o.agent}),i=me(await ee(),e)||null,c=Date.now(),l=null;try{l=await Cr({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s})}catch(g){throw tc(a,{ms:Date.now()-c,outcome:g?.code==="cli-not-running"?"cli-not-running":"blocked"}),await Nn(i,a,aa(g)),g}tc(a,{ms:Date.now()-c,outcome:l||"up"});let u=En(o.agent,n);a.paste=!!u.paste;try{await ot(t,n,{...u,kind:r||"orchestration"})}catch(g){throw await Nn(i,a,aa(g)),g}let d={},p=await Ti({sessionName:t,agent:o.agent,agentCmd:s,text:n,trackId:e,flow:"orchestration",stats:d});a.verify=d,await Nn(i,a,p?d.verdict==="unverified"?"unverified":"delivered":"unsubmitted"),await le({flow:"orchestration",phase:"sent",submitted:p,trackId:e,sessionName:t,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let f=await ee(),w=me(f,e);if(!w)return;let m=w.boxes.find(g=>g.name===t);$e(w,"orchestration-prompt",{box:t,agent:m?.agent||o.agent,boxRole:m?.role,prompt:n,kind:r||"orchestration",deliveryId:a.id}),await ue()}async function o4(e){let t=oe.join(bs(e),`${e.id}.ndjson`),n;try{n=await te.stat(t)}catch{return null}let r=r_.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await q(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return r_.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function s4(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:sh(n.name,n.agent)}async function Pt(e,t=null,n=null){let r=t??new Map((await nn()).map(b=>[b.name,b])),o=!!e.transferredTo,s=e.boxes.map(b=>{let O=o?null:r.get(b.name),I=so.has(b.state)?b.state:O?b.role==="lead"?"live":b.state:"stopped";return{...b,state:I,cwd:O?.cwd||b.cwd,agent:O?.agent||b.agent,sessionId:O?.sessionId||b.sessionId}}),[a,{working:i,prompted:c},l,u]=await Promise.all([o4(e),s4(e,s),Sw(e),n??un().catch(()=>[])]),d=vc.has(e.id),p=(u||[]).filter(b=>b.trackId===e.id&&!["merged","closed","lost"].includes(b.state)),f=n_(e.id),w=f&&{status:"waiting",since:f.startedAt,summary:f.summary??null,count:f.count??null}||XE(p),m=s.find(b=>b.name===e.leadBox)?.state==="live",g=m?Xo(e.id).filter(b=>b.kind!=="ship-notify"&&b.kind!=="prompt-answer"):[],y=m&&l.runningJobs?{source:"jobs",count:l.runningJobs,since:l.runningJobsSince,summary:l.runningJobs===1?"a background job is still running":`${l.runningJobs} background jobs are still running`}:g.length?{source:"queue",count:g.length,since:Math.min(...g.map(b=>b.ts||Date.now())),summary:"a queued message is about to send"}:null,x=QE({archivedAt:e.archivedAt,archiving:d,prompted:c,openActions:l.openActions,openActionSince:l.openActionSince,prDecisions:ZE(p),operation:w,phase:l.phase,working:i,workingSince:l.currentTurnAt,pending:y,completedTurnAt:l.completedTurnAt||a,live:m});return{...e,boxes:s,lastResponseAt:a,working:i,prompted:c,archiving:d,status:x}}function w_(e,t,n){let r=[...e].sort((l,u)=>l.createdAt-u.createdAt),o=[...t].sort((l,u)=>l.birthMs-u.birthMs),s=new Set,a=[];for(let l of r)l.sessionId&&n(l.sessionId)&&!s.has(l.sessionId)?s.add(l.sessionId):a.push(l);let i=new Map(r.map((l,u)=>[l,u])),c=[];for(let l of a){if(l.sessionId&&n(l.sessionId)){c.push({box:l.name,sessionId:null});continue}if(!l.sessionId||l.pinned)continue;let u=i.get(l),d=l.createdAt-a4,p=r[u+1]?.createdAt??1/0,f=o.find(w=>!s.has(w.id)&&w.birthMs>=d&&w.birthMs<p);f&&(s.add(f.id),c.push({box:l.name,sessionId:f.id}))}return c}async function g_(e){let t=new Map;for(let r of e.tracks)for(let o of r.boxes)o.agent==="claude"&&o.cwd&&(t.has(o.cwd)||t.set(o.cwd,[]),t.get(o.cwd).push({track:r,box:o}));let n=!1;for(let[r,o]of t){let s=o.map(p=>p.box.sessionId),a=Pk(r),i=new Set(a.map(p=>p.id)),c=s.every(p=>p&&i.has(p)),l=new Set(s).size===s.length;if(c&&l)continue;let u=o.map(p=>p.box),d=w_(u,a,p=>i.has(p));for(let p of d){let f=u.find(w=>w.name===p.box);f&&(f.sessionId=p.sessionId),await Tk(p.box,p.sessionId),n=!0}}return n}async function he(){let e=await ee();await g_(e)&&await ue();let t=new Map((await nn()).map(r=>[r.name,r])),n=await un().catch(()=>[]);return Promise.all(e.tracks.map(r=>Pt(r,t,n)))}async function Xi(e,t){let n=await ee();if(e)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.sessionId&&s.sessionId===e);if(o)return{track:r,box:o}}if(t)for(let r of n.tracks||[]){let o=r.boxes.find(s=>s.cwd===t);if(o)return{track:r,box:o}}return null}async function _c(e){let t=Ha(e);if(!t)return null;let n=await ee();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&pb(o.hookTokenHash,t))return{track:r,box:o};return null}async function qw(e){return me(await ee(),e)??null}async function ie(e){let t=await ee(),n=me(t,e);return n?(await g_(t)&&await ue(),Pt(n)):null}async function Kw(e){let t=await q(e).catch(()=>[]),n;try{n=_n(t)}catch{return[]}let r=ou(n).map(s=>({kind:s.kind,id:s.offerId??s.proposalId??s.id,ts:s.ts??null})),o=[];try{o=Y0(t)}catch{o=[]}return r.concat(o.map(s=>({kind:"pr-open",id:`${s.repo??""}#${s.number}`,ts:null})))}function Dw(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(i4[e.agent]||[]).some(n=>n.test(t))}function Bw(e){let t=(e.text||"").trim();return t?c4.some(n=>n.test(t)):!1}async function Id(e,t={}){let n=await ie(e);if(!n)return null;let r=new Set([...n.events.filter(R=>R.type==="orchestration-prompt"&&R.prompt).map(R=>String(R.prompt).trim()),...n.events.filter(R=>R.type==="said"&&R.text).map(R=>String(R.text).trim())]),o=Ta(n.id),s=!!(o&&!o.finishedAt&&o.step!=="done"&&!o.error),a=s&&o?.startedAt?[...o.fromBox?[{box:o.fromBox,from:o.startedAt,to:Date.now()+1e12}]:[],...o.toBox?[{box:o.toBox,from:o.startedAt,to:Date.now()+1e12}]:[]]:[],i=zh(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...MA(n),...l],p={windows:[...bx(n),...kx(n,cu),...a,...u]},w=(await Promise.all(n.boxes.map(R=>gm(R,t)))).flat(),m=w.map(R=>{let D={kind:"message",...R};if(D.role==="assistant"&&(D.text||"").trim()&&D.tools?.length){let de=Ur(D.agent).cliTools,Le=D.tools.filter(Ce=>!de.has(Ce));return{...D,tools:Le.length?Le:void 0}}return D}).map(R=>{if(R.role!=="user")return R;let D=j0(R);return D?D.kind==="suppress"?null:{...R,note:D,text:F0(D)}:R}).filter(Boolean).filter(R=>!(R.role==="user"&&r.has((R.text||"").trim()))).filter(R=>!Dw(R)).filter(R=>!Bw(R)).filter(R=>!Pw(R)).filter(R=>!ww(R)).filter(R=>R.role!=="assistant"||!!(R.text||"").trim()||!!R.images?.length).filter(R=>!xx(R,p)),g=m.filter(R=>R.failed&&R.text===_o);if(g.length){let R=new Map;for(let D of g){if(!R.has(D.box)){let Ce=[...(await Be(D.box,{lines:Ze}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(Ht=>Ht[1]);R.set(D.box,Ce.length?Ce[Ce.length-1]:null)}let de=R.get(D.box);de&&(D.text=`\u25A0 ${de}`)}}let y=await Promise.all(n.boxes.map(R=>rv(R,t)));await aA(n,y.flat());let{agentTurnBoxes:x}=await oA(n,m);for(let R of n.boxes)x.has(R.name)&&R.cwd&&_l(R.cwd);await Yv(n),await LA(n,m).catch(()=>{});for(let R of n.boxes)R.agent==="codex"&&R.state==="live"&&await cA(n,R),R.agent==="cursor"&&R.state==="live"&&await fA(n,R);let b=await Promise.all(n.boxes.map(R=>nv(R,t)));await sA(n,b.flat().filter(R=>!Rw(R.box,R.ts,u)));let O=await q(n),I=c&&i.viewId?i.viewId:null,C=lS(O),U=_n(O).filter(R=>!(R.kind==="message"&&(Dw(R)||Bw(R)||Pw(R)||ww(R)))&&!(R.kind==="view-card"&&I&&R.viewId===I)),H=uS(U,C),_=U.filter(R=>!(R.kind==="message"&&R.role==="assistant"&&!H.has(R)&&Rw(R.box,R.ts,C))),$=Qf(O,_).map(R=>({kind:"command-batch",id:R.id,ts:R.pending?R.ts:(R.anchorTs??R.ts)-1,anchorTs:R.anchorTs,anchorBox:R.anchorBox,agent:R.agent,boxRole:R.boxRole,commands:R.commands,pending:R.pending})).filter(R=>!Rw(R.anchorBox,R.anchorTs??R.ts,u)),L=V0(J0([..._,...$].filter(R=>R.ts!=null).sort((R,D)=>R.ts-D.ts))),V=u4(n),S=V.size?L.filter(R=>R.kind==="event"||!V.has(R.box??R.anchorBox)):L,E=n.boxes.find(R=>R.name===n.leadBox)||null,P=E?await di(E.cwd,E.sessionId,{fallbackNewest:!1}):null;if(!P&&E){let R=[...O].reverse().find(D=>D.type==="context.usage"&&D.boxId===E.name);R?.payload?.window&&(P={pct:R.payload.pct??(R.payload.occupancy!=null?R.payload.occupancy/R.payload.window:null),occupancy:R.payload.occupancy??null,window:R.payload.window,windowKnown:!0,model:R.payload.model||null})}let W=[...w].reverse().find(R=>R.role==="assistant"&&R.model),G=W?.model||null,ae=[...n.events||[]].reverse().find(R=>R.type==="model-change"),we=P?.model||G;ae&&(!W?.ts||ae.at>=W.ts)&&(we=ae.to);let Re=E?await Be(E.name,{lines:Ze}).catch(()=>""):"",Ae=E&&qr(E.agent,Re)?await on(E.name).catch(()=>Re):Re,Y=E?$n(E,Ae):null;if(Y&&E){let R=hu(E,Y,Ae);if(R){let D=yv(E.name,Y.promptId);D.action!=="give-up"&&(D.action==="send"&&(qe(E.name,R.keys,{kind:"auto-reject"}).catch(()=>{}),D.first&&M(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:E.name,provider:E.agent,payload:{ts:Date.now(),promptId:Y.promptId,rule:R.id}}).catch(()=>{})),Y=null)}}!Y&&E&&!Cs(E.agent,Re)&&!Xo(n.id).length&&(Y=Yf(S,{leadBoxId:E.name,provider:E.agent,isAnswered:R=>O.some(D=>D.type==="prompt.answered"&&D.payload?.promptId===R)})),Y&&Xv(n,E,Y);let ye=S.filter(R=>!(R.kind==="message"&&R.role==="assistant"&&R.ask&&!String(R.text||"").trim()&&!R.images?.length)),z=!!E&&Wu(E.name,E.agent,Re)&&!Y;E&&!E.readyAt&&(z||Y||Re&&Ns(E.agent,Re))&&(E.readyAt=Date.now(),await ue());let se=!!E&&!E.readyAt&&Date.now()-(n.createdAt||0)<l4;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&E&&Ns(E.agent,Re)&&!Y){let R=await ee(),D=me(R,n.id);D?.setup&&!D.setup.connectedAt&&(D.setup.connectedAt=Date.now(),n.setup.connectedAt=D.setup.connectedAt,await M(D,{type:"provider.connected",actor:"system",source:"pane",boxId:E.name,provider:E.agent,payload:{provider:E.agent,ts:D.setup.connectedAt}}).catch(()=>{}),await ue())}let ve=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,Ne=null;if(c){let R=Date.now()-i.startedAt;if(i.viewId&&!z){let D=ld(n.id);D&&($e(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:D.finishedAt}),await ue())}else if(Y||R>RA&&!z&&!i.viewId||R>Gh){let D=Y?"needs-input":R>Gh?"timeout":"no-view";ld(n.id,{error:D})&&await M(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:E?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:D}}).catch(()=>{})}else Ne={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:ye,context:P?{pct:P.pct,occupancy:P.occupancy,window:P.window,windowKnown:P.windowKnown,model:P.model}:null,models:{current:we,options:Um(E?.agent)},pendingPrompt:Y,working:z,stopping:b_(n.id),leadStarting:se,handoff:ve,view:Ne,queued:Xo(n.id).filter(R=>R.kind!=="ship-notify"&&R.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function u4(e){let t=new Set;for(let n of e.boxes||[])n.role==="subtask"&&n.name&&t.add(n.name);for(let n of Object.values(e.subtasks||{}))n?.box&&t.add(n.box);return t}async function Gw(e,t){let n=await ie(e);if(!n)return null;let r=es(e).find(d=>d.id===t)||null;if(!r)return null;let o=r.box||null;if(!o)return{items:[],working:!1,box:null,agent:r.agent,task:r.task};let s=await q(n),a=_n(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=Qf(s.filter(d=>d.boxId===o),a.filter(d=>d.kind==="message")).map(d=>({kind:"command-batch",id:d.id,ts:d.pending?d.ts:(d.anchorTs??d.ts)-1,anchorTs:d.anchorTs,anchorBox:d.anchorBox,agent:d.agent,boxRole:d.boxRole,commands:d.commands,pending:d.pending})),c=[...a,...i].filter(d=>d.ts!=null).sort((d,p)=>d.ts-p.ts),l=n.boxes.find(d=>d.name===o)||null,u=!1;if(l&&l.state==="live"){let d=await Be(o,{lines:Ze}).catch(()=>"");u=Wu(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}function d4(e,t){if(e==null)return[];if(!Array.isArray(e))throw new Error("custom answer must be a list of strings");return e.slice(0,Math.max(1,t)).map(n=>{if(n==null||n==="")return"";if(typeof n!="string")throw new Error("custom answer must be text");let r=n.replace(/\s+/g," ").trim();if(/[\x00-\x1f\x7f]/.test(r))throw new Error("custom answer can't contain control characters");if(r.length>o_)throw new Error(`custom answer is too long (max ${o_} characters)`);return r})}function p4(e,t){let n=String(e||"").replace(/\s+/g," ").trim(),r=String(t||"").replace(/\s+/g," ").trim();return!n||!r?!1:n===r||r.startsWith(n)||n.startsWith(r.slice(0,24))}async function $d(e,t={}){let n=hc.get(e);n&&await n.catch(()=>{});let r=f4(e,t);hc.set(e,r);try{return await r}finally{hc.get(e)===r&&hc.delete(e)}}async function f4(e,{promptId:t,answers:n,text:r,custom:o}={}){let s=me(await ee(),e);if(!s)throw new Error(`track "${e}" not found`);$c(e,"prompt-answer");let a=s.boxes.find(y=>y.name===s.leadBox);if(!a)throw new Error(`track "${e}" has no lead box`);if(!await ke(s.leadBox))throw new Error(`lead box "${s.leadBox}" is not running`);let c=await Am(a);if(c||(c=await m4(s,a)),!c)throw new Error("no pending prompt to answer");if(t&&t!==c.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");let l=d4(o,c.questions?.length??1);if(l.some(Boolean)&&!c.custom)throw new Error("custom answer isn't available for this prompt \u2014 pick one of its options");let u=(n||[]).some(y=>Array.isArray(y)&&y.length>0);if(c.custom&&!u&&!l.some(Boolean)&&c.answerMode!=="text")throw new Error("no answer selected \u2014 pick an option or type your own");l.some(Boolean)&&(n=(c.questions||[]).map((y,x)=>l[x]&&!y.multiSelect?[]:Array.isArray(n?.[x])?n[x]:[]));let d;if(c.answerMode==="text"){let y=typeof r=="string"?r.trim():"";if(!y)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(y)||y.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await ot(s.leadBox,y,{enter:!0,kind:"answer-prompt"}),d={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(c.answerMode==="esc")await qe(s.leadBox,["Escape"],{kind:"answer-prompt"}),d={mode:"keys",value:"Escape",count:1};else if(c.answerMode==="say"){let y=q0(c,n||[],typeof r=="string"?r:"",l);if(!y)throw new Error("no answer selected \u2014 pick an option or reply in chat");await Bt(s.id,y,{kind:"prompt-answer"}),d={mode:"say",value:y,count:1}}else if(l[0]&&c.provider==="claude"){let y=mv(c,n||[],l[0]);await mf(s.leadBox,[...y.pre,{text:y.text}],{kind:"answer-prompt"});let x=!1;for(let O of[150,300,600]){await br(O);let I=await on(s.leadBox).catch(()=>""),C=$n(a,I);if(C?.customText&&p4(C.customText,y.text)){x=!0;break}}if(!x)throw new Error("custom answer didn't take \u2014 the widget moved; reload and answer again");await mf(s.leadBox,y.post,{kind:"answer-prompt"});let b=O=>O.map(I=>I.key).join(" ");d={mode:"keys+text",value:`${b(y.pre)} \u2039text\u203A ${b(y.post)}`.trim(),count:y.pre.length+1+y.post.length}}else if(c.provider==="claude"||c.answerMode==="keys"){let y=Em(c,n||[]);await qe(s.leadBox,y,{kind:"answer-prompt"}),d={mode:"keys",value:y.join(" "),count:y.length}}else{let y=l0(c,n||[]);await ot(s.leadBox,y,{enter:!0,kind:"answer-prompt"}),d={mode:"text",value:y,count:1}}if(c.answerMode==="say"){let y=c.questions||[];for(let x=0;x<y.length;x++){let b=y[x],O=new Set(Array.isArray(n?.[x])?n[x]:[]),I=[...O].map(U=>b.options?.[U]).filter(Boolean).map(U=>({label:U.label,description:U.description||""}));l[x]&&I.push({label:l[x],description:"",custom:!0});let C=(b.options||[]).map((U,H)=>O.has(H)?null:U?.label).filter(Boolean);Hm(s,a,c,{...d,groupId:c.groupId||c.promptId,questionIndex:x,questionTotal:c.questionTotal??y.length,header:b.header||"",question:b.question||"",multiSelect:!!b.multiSelect,chosen:I,rejected:C})}return await le({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:c.provider,promptId:c.promptId,...d}).catch(()=>{}),{ok:!0,promptId:c.promptId,sent:d.count}}let p=c.questions?.[0]||{},f=new Set(Array.isArray(n?.[0])?n[0]:[]),w=[...f].map(y=>p.options?.[y]).filter(Boolean).map(y=>({label:y.label,description:y.description||""}));l[0]&&w.push({label:l[0],description:"",custom:!0});let m=(p.options||[]).map((y,x)=>f.has(x)?null:y?.label).filter(Boolean),g=c.review?"review":/^claude:model-confirm:/.test(c.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(c.promptId||"")?"resume-confirm":void 0;return d={...d,groupId:c.groupId||c.promptId,questionIndex:c.questionIndex??0,questionTotal:c.questionTotal??1,header:p.header||"",question:p.question||"",multiSelect:!!p.multiSelect,chosen:w,rejected:m,...g?{control:g}:{}},await le({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:c.provider,promptId:c.promptId,...d}).catch(()=>{}),Hm(s,a,c,d),{ok:!0,promptId:c.promptId,sent:d.count}}async function m4(e,t){if(!t)return null;let n=await q(e).catch(()=>[]);return Yf(_n(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function zw(e,{promptId:t,questionIndex:n}={}){let r=me(await ee(),e);if(!r)throw new Error(`track "${e}" not found`);let o=r.boxes.find(l=>l.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(!await ke(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await Am(o);if(!a)throw new Error("no pending prompt to navigate");if(a.provider!=="claude")throw new Error("prompt navigation not supported for this provider");if(a.review)throw new Error("cannot navigate on the review screen \u2014 answer or cancel");let i=a.questionTotal??1;if(i<2)throw new Error("not a multi-question prompt");if(!Number.isInteger(n)||n<0||n>=i)throw new Error("questionIndex out of range");if(t&&t!==a.promptId)throw new Error("prompt changed since it was shown \u2014 reload and try again");let c=hv(a,n);return c.length?(await qe(r.leadBox,c,{kind:"navigate-prompt"}),await le({flow:"prompt",phase:"navigated",sessionName:r.leadBox,agent:o.agent,provider:a.provider,promptId:a.promptId,fromIndex:a.questionIndex??0,toIndex:n,mode:"keys",value:c.join(" "),count:c.length}).catch(()=>{}),{ok:!0,promptId:a.promptId,sent:c.length}):{ok:!0,promptId:a.promptId,sent:0}}function Rd(e){let t=ya.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},ya.set(e,t)),t}function Xo(e){return(ya.get(e)?.items??[]).map(({delivery:t,...n})=>({...n}))}function Vw(e=Date.now()){let t=0,n=0;for(let r of ya.values())for(let o of r.items){t+=1;let s=e-(o.delivery?.queuedAt??o.ts??e);s>n&&(n=s)}return{queueDepth:t,queueOldestAgeMs:n}}function w4(e,t,n){let r=t.filter(o=>o.delivery&&!o.delivery.settled);r.length&&(async()=>{let o=me(await ee(),e)||null;for(let s of r)await Nn(o,s.delivery,`dropped:${n}`)})().catch(()=>{})}function Ic(e,t="cancel"){let n=ya.get(e);if(!n)return[];let r=n.items.splice(0);return n.idleSince=null,n.timer&&(clearInterval(n.timer),n.timer=null),w4(e,r,t),r}async function Jw(e){let t=Ic(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=me(await ee(),e);if(o)return r=ba(o,n),await ue(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function Yw(e){let t=Rd(e);t.timer||(t.timer=setInterval(()=>g4(e).catch(()=>{}),h4))}async function g4(e){let t=ya.get(e);if(!(!t||t.flushing)){if(!t.items.length){t.timer&&(clearInterval(t.timer),t.timer=null);return}t.flushing=!0;try{let n=me(await ee(),e);if(!n||n.archivedAt){Ic(e,"archived");return}let r=l=>{for(let u of t.items)xA(u.delivery,l)},o=Ta(e);if(o&&!o.finishedAt&&o.step!=="done"&&!o.error){Jo(t,!1),r("handoff");return}let s=await ke(n.leadBox),a=n.boxes.find(l=>l.name===n.leadBox);if(s&&await lg(s)&&(s=await Sc(n,a,"queue")?await ke(n.leadBox):null,await ue()),!s){Jo(t,!1),r("noSession");return}if(Po(a?.agent)){Jo(t,!1),r("cap");return}let i=await Be(n.leadBox,{lines:Ze}).catch(()=>"");if(gi(a?.agent,i)){Jo(t,!1),r("busy");return}if(qr(a?.agent,i)){let l=await on(n.leadBox).catch(()=>i);if($n(a,l)){Jo(t,!1),r("prompt");return}}if(!Jo(t,!0)){r("grace");return}let c=t.items.shift();t.idleSince=null,c.delivery&&(c.delivery.dequeuedAt=Date.now());try{await jw(n,a,s,c.text,c.kind??null,c.attachments??null,c.delivery??null)}catch(l){if(l?.code!=="cli-not-running")throw c.delivery&&await Nn(n,c.delivery,aa(l)),l;t.items.unshift(c),c.delivery&&(c.delivery.requeued+=1,c.delivery.dequeuedAt=null,await ec(n,c.delivery,{position:1,reason:"requeue"})),await Sc(n,a,"queue-gate")}await ue()}finally{t.flushing=!1}}}async function y_(e,t,n,r){let o=Po(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(ba(e,[n]),await ue()),Nv(e.id,o))try{await M(e,{type:"usage.cap.hit",actor:"system",provider:t?.agent??null,boxId:e.leadBox,payload:{...o,blockedKind:r??null}})}catch{}let s=new Error(`${t?.agent??"the lead provider"} is paused \u2014 its ${o.window} spend limit is reached ($${o.spentUsd.toFixed(2)} of $${o.limitUsd.toFixed(2)})`);throw s.usageCap=o,s}async function y4(e,t){let n=await Be(e.leadBox,{lines:Ze}).catch(()=>"");if(!qr(t?.agent,n))return!1;let r=await on(e.leadBox).catch(()=>n);return!!$n(t,r)}async function jw(e,t,n,r,o=null,s=null,a=null){a||(a=Qi({text:r,producer:Zi({kind:o}),kind:o,provider:t?.agent??null,attachments:Array.isArray(s)?s.length:0})),a.provider??=t?.agent??null,await y_(e,t,r,o);let i=bc.get(e.id)||0,c=r,l=!1,u=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(c=f_(r,e.pendingHandoffHydrate.artifact||Yo),delete e.pendingHandoffHydrate,l=!0);let d=Array.isArray(s)?s.filter(m=>m&&m.rel):[];if(d.length){let m=UE(d.map(g=>g.rel));c=c.trim()?`${c.trim()}
212
+ (Read ${t} for handoff context from the prior lead \u2014 you are now the lead; none of the prior chat is in your context. Then respond to the user above.)`}function hg(e){return e.role==="user"&&D4.test((e.text||"").trim())}async function Z(){return Nt||(cg||=(async()=>{try{Nt=JSON.parse(await J.readFile(V_,"utf8"))}catch{Nt={tracks:[]}}finally{cg=null}return Nt})(),cg)}async function se(){await Rt(V_,Nt)}function L4(e,t){let n=JSON.stringify({trackId:e,...t})+`
213
+ `;return lg=lg.then(()=>J.mkdir(qn,{recursive:!0})).then(()=>J.appendFile(N4,n)).catch(()=>{}),lg}async function Kn({current:e,latest:t,min:n=null,installKind:r=null,required:o=!1,status:s="available",policy:a=null,error:i=null,reason:c=null}={}){if(!t)return{announced:0};if(s==="available"){let d=null;try{d=JSON.parse(await J.readFile(ug,"utf8"))}catch{}if(d?.latest===t&&d?.current===e)return{announced:0,deduped:!0}}let l=await Z(),u=0;for(let d of l.tracks)je(d)||!d.leadBox||(Ae(d,"node-update",{status:s,current:e??null,latest:t,...n?{min:n}:{},...r?{installKind:r}:{},...a?{policy:a}:{},...i?{error:String(i).slice(0,400)}:{},...c?{reason:c}:{},required:o===!0}),u++);if(await se().catch(()=>{}),s==="available")try{await J.mkdir(z.dirname(ug),{recursive:!0}),await J.writeFile(ug,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function vg({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)||F4(e,c)||(Ae(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 se().catch(()=>{}),{reconciled:o>0,announced:o,targets:[...s]}}function F4(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 Y_(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=>U4.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 X_(e,t,n,{kind:r}={}){let o=await ye(t);if(!o)throw new Error(`box "${t}" is not running`);let s=ms(o.agent),a=wc({text:n,producer:mc({kind:r,orchestration:!0}),kind:r||"orchestration",provider:o.agent}),i=de(await Z(),e)||null,c=Date.now(),l=null;try{l=await er({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s})}catch(g){throw yc(a,{ms:Date.now()-c,outcome:g?.code==="cli-not-running"?"cli-not-running":"blocked"}),await Dn(i,a,xa(g)),g}yc(a,{ms:Date.now()-c,outcome:l||"up"});let u=In(o.agent,n);a.paste=!!u.paste;try{await ot(t,n,{...u,kind:r||"orchestration"})}catch(g){throw await Dn(i,a,xa(g)),g}let d={},p=await Hi({sessionName:t,agent:o.agent,agentCmd:s,text:n,trackId:e,flow:"orchestration",stats:d});a.verify=d,await Dn(i,a,p?d.verdict==="unverified"?"unverified":"delivered":"unsubmitted"),await ue({flow:"orchestration",phase:"sent",submitted:p,trackId:e,sessionName:t,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let f=await Z(),w=de(f,e);if(!w)return;let h=w.boxes.find(g=>g.name===t);Ae(w,"orchestration-prompt",{box:t,agent:h?.agent||o.agent,boxRole:h?.role,prompt:n,kind:r||"orchestration",deliveryId:a.id}),await se()}async function H4(e){let t=z.join(Bs(e),`${e.id}.ndjson`),n;try{n=await J.stat(t)}catch{return null}let r=F_.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await K(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return F_.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function W4(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:Lm(n.name,n.agent)}async function Ut(e,t=null,n=null){let r=t??new Map((await sn()).map(b=>[b.name,b])),o=!!e.transferredTo,s=e.boxes.map(b=>{let I=o?null:r.get(b.name),_=vr.has(b.state)?b.state:I?b.role==="lead"?"live":b.state:"stopped";return{...b,state:_,cwd:I?.cwd||b.cwd,agent:I?.agent||b.agent,sessionId:I?.sessionId||b.sessionId}}),[a,{working:i,prompted:c},l,u]=await Promise.all([H4(e),W4(e,s),og(e),n??pn().catch(()=>[])]),d=Fc.has(e.id),p=(u||[]).filter(b=>b.trackId===e.id&&!["merged","closed","lost"].includes(b.state)),f=L_(e.id),w=f&&{status:"waiting",since:f.startedAt,summary:f.summary??null,count:f.count??null}||N_(p),h=s.find(b=>b.name===e.leadBox)?.state==="live",g=h?ps(e.id).filter(b=>b.kind!=="ship-notify"&&b.kind!=="prompt-answer"):[],y=h&&l.runningJobs?{source:"jobs",count:l.runningJobs,since:l.runningJobsSince,summary:l.runningJobs===1?"a background job is still running":`${l.runningJobs} background jobs are still running`}:g.length?{source:"queue",count:g.length,since:Math.min(...g.map(b=>b.ts||Date.now())),summary:"a queued message is about to send"}:null,x=D_({archivedAt:e.archivedAt,archiving:d,prompted:c,openActions:l.openActions,openActionSince:l.openActionSince,prDecisions:P_(p),operation:w,phase:l.phase,working:i,workingSince:l.currentTurnAt,pending:y,completedTurnAt:l.completedTurnAt||a,live:h});return{...e,boxes:s,lastResponseAt:a,working:i,prompted:c,archiving:d,status:x}}function Z_(e,t,n){let r=[...e].sort((l,u)=>l.createdAt-u.createdAt),o=[...t].sort((l,u)=>l.birthMs-u.birthMs),s=new Set,a=[];for(let l of r)l.sessionId&&n(l.sessionId)&&!s.has(l.sessionId)?s.add(l.sessionId):a.push(l);let i=new Map(r.map((l,u)=>[l,u])),c=[];for(let l of a){if(l.sessionId&&n(l.sessionId)){c.push({box:l.name,sessionId:null});continue}if(!l.sessionId||l.pinned)continue;let u=i.get(l),d=l.createdAt-q4,p=r[u+1]?.createdAt??1/0,f=o.find(w=>!s.has(w.id)&&w.birthMs>=d&&w.birthMs<p);f&&(s.add(f.id),c.push({box:l.name,sessionId:f.id}))}return c}async function Q_(e){let t=new Map;for(let r of e.tracks)for(let o of r.boxes)o.agent==="claude"&&o.cwd&&(t.has(o.cwd)||t.set(o.cwd,[]),t.get(o.cwd).push({track:r,box:o}));let n=!1;for(let[r,o]of t){let s=o.map(p=>p.box.sessionId),a=b0(r),i=new Set(a.map(p=>p.id)),c=s.every(p=>p&&i.has(p)),l=new Set(s).size===s.length;if(c&&l)continue;let u=o.map(p=>p.box),d=Z_(u,a,p=>i.has(p));for(let p of d){let f=u.find(w=>w.name===p.box);f&&(f.sessionId=p.sessionId),await c0(p.box,p.sessionId),n=!0}}return n}async function we(){let e=await Z();await Q_(e)&&await se();let t=new Map((await sn()).map(r=>[r.name,r])),n=await pn().catch(()=>[]);return Promise.all(e.tracks.map(r=>Ut(r,t,n)))}async function hc(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 qc(e){let t=$o(e);if(!t)return null;let n=await Z();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&Vb(o.hookTokenHash,t))return{track:r,box:o};return null}async function Sg(e){return de(await Z(),e)??null}async function ie(e){let t=await Z(),n=de(t,e);return n?(await Q_(t)&&await se(),Ut(n)):null}async function Ag(e){let t=await K(e).catch(()=>[]),n;try{n=$n(t)}catch{return[]}let r=Tu(n).map(s=>({kind:s.kind,id:s.offerId??s.proposalId??s.id,ts:s.ts??null})),o=[];try{o=Nx(t)}catch{o=[]}return r.concat(o.map(s=>({kind:"pr-open",id:`${s.repo??""}#${s.number}`,ts:null})))}function mg(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(K4[e.agent]||[]).some(n=>n.test(t))}function wg(e){let t=(e.text||"").trim();return t?G4.some(n=>n.test(t)):!1}async function np(e,t={}){let n=await ie(e);if(!n)return null;let r=new Set([...n.events.filter($=>$.type==="orchestration-prompt"&&$.prompt).map($=>String($.prompt).trim()),...n.events.filter($=>$.type==="said"&&$.text).map($=>String($.text).trim())]),o=La(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=_w(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...wE(n),...l],p={windows:[...rv(n),...ov(n,$u),...a,...u]},w=(await Promise.all(n.boxes.map($=>Yh($,t)))).flat(),h=w.map($=>{let Y={kind:"message",...$};if(Y.role==="assistant"&&(Y.text||"").trim()&&Y.tools?.length){let Ce=Vr(Y.agent).cliTools,Ve=Y.tools.filter(xt=>!Ce.has(xt));return{...Y,tools:Ve.length?Ve:void 0}}return Y}).map($=>{if($.role!=="user")return $;let Y=vx($);return Y?Y.kind==="suppress"?null:{...$,note:Y,text:Ax(Y)}:$}).filter(Boolean).filter($=>!($.role==="user"&&r.has(($.text||"").trim()))).filter($=>!mg($)).filter($=>!wg($)).filter($=>!hg($)).filter($=>!Xw($)).filter($=>$.role!=="assistant"||!!($.text||"").trim()||!!$.images?.length).filter($=>!sv($,p)),g=h.filter($=>$.failed&&$.text===Lo);if(g.length){let $=new Map;for(let Y of g){if(!$.has(Y.box)){let xt=[...(await Pe(Y.box,{lines:Ye}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(Er=>Er[1]);$.set(Y.box,xt.length?xt[xt.length-1]:null)}let Ce=$.get(Y.box);Ce&&(Y.text=`\u25A0 ${Ce}`)}}let y=await Promise.all(n.boxes.map($=>Hv($,t)));await qT(n,y.flat());let{agentTurnBoxes:x}=await HT(n,h);for(let $ of n.boxes)x.has($.name)&&$.cwd&&zl($.cwd);await NS(n),await vE(n,h).catch(()=>{});for(let $ of n.boxes)$.agent==="codex"&&$.state==="live"&&await GT(n,$),$.agent==="cursor"&&$.state==="live"&&await XT(n,$);let b=await Promise.all(n.boxes.map($=>Uv($,t)));await WT(n,b.flat().filter($=>!dg($.box,$.ts,u)));let I=await K(n),_=c&&i.viewId?i.viewId:null,N=zS(I),U=$n(I).filter($=>!($.kind==="message"&&(mg($)||wg($)||hg($)||Xw($)))&&!($.kind==="view-card"&&_&&$.viewId===_)),j=VS(U,N),T=U.filter($=>!($.kind==="message"&&$.role==="assistant"&&!j.has($)&&dg($.box,$.ts,N))),R=Ch(I,T).map($=>({kind:"command-batch",id:$.id,ts:$.pending?$.ts:($.anchorTs??$.ts)-1,anchorTs:$.anchorTs,anchorBox:$.anchorBox,agent:$.agent,boxRole:$.boxRole,commands:$.commands,pending:$.pending})).filter($=>!dg($.anchorBox,$.anchorTs??$.ts,u)),L=Mx(Cx([...T,...R].filter($=>$.ts!=null).sort(($,Y)=>$.ts-Y.ts))),V=V4(n),O=V.size?L.filter($=>$.kind==="event"||!V.has($.box??$.anchorBox)):L,S=n.boxes.find($=>$.name===n.leadBox)||null,M=S?await Ri(S.cwd,S.sessionId,{fallbackNewest:!1}):null;if(!M&&S){let $=[...I].reverse().find(Y=>Y.type==="context.usage"&&Y.boxId===S.name);$?.payload?.window&&(M={pct:$.payload.pct??($.payload.occupancy!=null?$.payload.occupancy/$.payload.window:null),occupancy:$.payload.occupancy??null,window:$.payload.window,windowKnown:!0,model:$.payload.model||null})}let H=[...w].reverse().find($=>$.role==="assistant"&&$.model),W=H?.model||null,te=[...n.events||[]].reverse().find($=>$.type==="model-change"),pe=M?.model||W;te&&(!H?.ts||te.at>=H.ts)&&(pe=te.to);let Ie=S?await Pe(S.name,{lines:Ye}).catch(()=>""):"",Oe=S&&Xr(S.agent,Ie)?await an(S.name).catch(()=>Ie):Ie,re=S?On(S,Oe):null;if(re&&S){let $=ju(S,re,Oe);if($){let Y=rS(S.name,re.promptId);Y.action!=="give-up"&&(Y.action==="send"&&(We(S.name,$.keys,{kind:"auto-reject"}).catch(()=>{}),Y.first&&C(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:S.name,provider:S.agent,payload:{ts:Date.now(),promptId:re.promptId,rule:$.id}}).catch(()=>{})),re=null)}}!re&&S&&!Xs(S.agent,Ie)&&!ps(n.id).length&&(re=Rh(O,{leadBoxId:S.name,provider:S.agent,isAnswered:$=>I.some(Y=>Y.type==="prompt.answered"&&Y.payload?.promptId===$)})),re&&PS(n,S,re);let Ne=O.filter($=>!($.kind==="message"&&$.role==="assistant"&&$.ask&&!String($.text||"").trim()&&!$.images?.length)),G=!!S&&dd(S.name,S.agent,Ie)&&!re;S&&!S.readyAt&&(G||re||Ie&&Uo(S.agent,Ie))&&(S.readyAt=Date.now(),await se());let fe=!!S&&!S.readyAt&&Date.now()-(n.createdAt||0)<z4;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&S&&Uo(S.agent,Ie)&&!re){let $=await Z(),Y=de($,n.id);Y?.setup&&!Y.setup.connectedAt&&(Y.setup.connectedAt=Date.now(),n.setup.connectedAt=Y.setup.connectedAt,await C(Y,{type:"provider.connected",actor:"system",source:"pane",boxId:S.name,provider:S.agent,payload:{provider:S.agent,ts:Y.setup.connectedAt}}).catch(()=>{}),await se())}let be=s?{running:!0,step:o.step,toAgent:o.toAgent||null}:null,xe=Gc(n.id),Ke=xe&&!xe.finishedAt?{running:!0,step:xe.step||null,added:xe.added||[],removed:xe.removed||[]}:null,le=null;if(c){let $=Date.now()-i.startedAt;if(i.viewId&&!G){let Y=Od(n.id);Y&&(Ae(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:Y.finishedAt}),await se())}else if(re||$>hE&&!G&&!i.viewId||$>Ew){let Y=re?"needs-input":$>Ew?"timeout":"no-view";Od(n.id,{error:Y})&&await C(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:S?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:Y}}).catch(()=>{})}else le={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:Ne,context:M?{pct:M.pct,occupancy:M.occupancy,window:M.window,windowKnown:M.windowKnown,model:M.model}:null,models:{current:pe,options:xm(S?.agent)},pendingPrompt:re,working:G,stopping:tI(n.id),leadStarting:fe,handoff:be,reshape:Ke,view:le,queued:ps(n.id).filter($=>$.kind!=="ship-notify"&&$.kind!=="prompt-answer"),draft:n.draft||null,draftRev:n.draftRev||0}}function V4(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 Tg(e,t){let n=await ie(e);if(!n)return null;let r=ys(e).find(d=>d.id===t)||null;if(!r)return null;let o=r.box||null;if(!o)return{items:[],working:!1,box:null,agent:r.agent,task:r.task};let s=await K(n),a=$n(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=Ch(s.filter(d=>d.boxId===o),a.filter(d=>d.kind==="message")).map(d=>({kind:"command-batch",id:d.id,ts:d.pending?d.ts:(d.anchorTs??d.ts)-1,anchorTs:d.anchorTs,anchorBox:d.anchorBox,agent:d.agent,boxRole:d.boxRole,commands:d.commands,pending:d.pending})),c=[...a,...i].filter(d=>d.ts!=null).sort((d,p)=>d.ts-p.ts),l=n.boxes.find(d=>d.name===o)||null,u=!1;if(l&&l.state==="live"){let d=await Pe(o,{lines:Ye}).catch(()=>"");u=dd(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}function J4(e,t){if(e==null)return[];if(!Array.isArray(e))throw new Error("custom answer must be a list of strings");return e.slice(0,Math.max(1,t)).map(n=>{if(n==null||n==="")return"";if(typeof n!="string")throw new Error("custom answer must be text");let r=n.replace(/\s+/g," ").trim();if(/[\x00-\x1f\x7f]/.test(r))throw new Error("custom answer can't contain control characters");if(r.length>U_)throw new Error(`custom answer is too long (max ${U_} characters)`);return r})}function Y4(e,t){let n=String(e||"").replace(/\s+/g," ").trim(),r=String(t||"").replace(/\s+/g," ").trim();return!n||!r?!1:n===r||r.startsWith(n)||n.startsWith(r.slice(0,24))}async function rp(e,t={}){let n=Mc.get(e);n&&await n.catch(()=>{});let r=X4(e,t);Mc.set(e,r);try{return await r}finally{Mc.get(e)===r&&Mc.delete(e)}}async function X4(e,{promptId:t,answers:n,text:r,custom:o}={}){let s=de(await Z(),e);if(!s)throw new Error(`track "${e}" not found`);Ba(e,"prompt-answer");let a=s.boxes.find(y=>y.name===s.leadBox);if(!a)throw new Error(`track "${e}" has no lead box`);if(!await ye(s.leadBox))throw new Error(`lead box "${s.leadBox}" is not running`);let c=await om(a);if(c||(c=await Z4(s,a)),!c)throw new Error("no pending prompt to answer");if(t&&t!==c.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");let l=J4(o,c.questions?.length??1);if(l.some(Boolean)&&!c.custom)throw new Error("custom answer isn't available for this prompt \u2014 pick one of its options");let u=(n||[]).some(y=>Array.isArray(y)&&y.length>0);if(c.custom&&!u&&!l.some(Boolean)&&c.answerMode!=="text")throw new Error("no answer selected \u2014 pick an option or type your own");l.some(Boolean)&&(n=(c.questions||[]).map((y,x)=>l[x]&&!y.multiSelect?[]:Array.isArray(n?.[x])?n[x]:[]));let d;if(c.answerMode==="text"){let y=typeof r=="string"?r.trim():"";if(!y)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(y)||y.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await ot(s.leadBox,y,{enter:!0,kind:"answer-prompt"}),d={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(c.answerMode==="esc")await We(s.leadBox,["Escape"],{kind:"answer-prompt"}),d={mode:"keys",value:"Escape",count:1};else if(c.answerMode==="say"){let y=Ix(c,n||[],typeof r=="string"?r:"",l);if(!y)throw new Error("no answer selected \u2014 pick an option or reply in chat");await Ht(s.id,y,{kind:"prompt-answer"}),d={mode:"say",value:y,count:1}}else if(l[0]&&c.provider==="claude"){let y=Qv(c,n||[],l[0]);await Vf(s.leadBox,[...y.pre,{text:y.text}],{kind:"answer-prompt"});let x=!1;for(let I of[150,300,600]){await Sr(I);let _=await an(s.leadBox).catch(()=>""),N=On(a,_);if(N?.customText&&Y4(N.customText,y.text)){x=!0;break}}if(!x)throw new Error("custom answer didn't take \u2014 the widget moved; reload and answer again");await Vf(s.leadBox,y.post,{kind:"answer-prompt"});let b=I=>I.map(_=>_.key).join(" ");d={mode:"keys+text",value:`${b(y.pre)} \u2039text\u203A ${b(y.post)}`.trim(),count:y.pre.length+1+y.post.length}}else if(c.provider==="claude"||c.answerMode==="keys"){let y=sm(c,n||[]);await We(s.leadBox,y,{kind:"answer-prompt"}),d={mode:"keys",value:y.join(" "),count:y.length}}else{let y=z0(c,n||[]);await ot(s.leadBox,y,{enter:!0,kind:"answer-prompt"}),d={mode:"text",value:y,count:1}}if(c.answerMode==="say"){let y=c.questions||[];for(let x=0;x<y.length;x++){let b=y[x],I=new Set(Array.isArray(n?.[x])?n[x]:[]),_=[...I].map(U=>b.options?.[U]).filter(Boolean).map(U=>({label:U.label,description:U.description||""}));l[x]&&_.push({label:l[x],description:"",custom:!0});let N=(b.options||[]).map((U,j)=>I.has(j)?null:U?.label).filter(Boolean);vm(s,a,c,{...d,groupId:c.groupId||c.promptId,questionIndex:x,questionTotal:c.questionTotal??y.length,header:b.header||"",question:b.question||"",multiSelect:!!b.multiSelect,chosen:_,rejected:N})}return await ue({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:c.provider,promptId:c.promptId,...d}).catch(()=>{}),{ok:!0,promptId:c.promptId,sent:d.count}}let p=c.questions?.[0]||{},f=new Set(Array.isArray(n?.[0])?n[0]:[]),w=[...f].map(y=>p.options?.[y]).filter(Boolean).map(y=>({label:y.label,description:y.description||""}));l[0]&&w.push({label:l[0],description:"",custom:!0});let h=(p.options||[]).map((y,x)=>f.has(x)?null:y?.label).filter(Boolean),g=c.review?"review":/^claude:model-confirm:/.test(c.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(c.promptId||"")?"resume-confirm":void 0;return d={...d,groupId:c.groupId||c.promptId,questionIndex:c.questionIndex??0,questionTotal:c.questionTotal??1,header:p.header||"",question:p.question||"",multiSelect:!!p.multiSelect,chosen:w,rejected:h,...g?{control:g}:{}},await ue({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:c.provider,promptId:c.promptId,...d}).catch(()=>{}),vm(s,a,c,d),{ok:!0,promptId:c.promptId,sent:d.count}}async function Z4(e,t){if(!t)return null;let n=await K(e).catch(()=>[]);return Rh($n(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function Eg(e,{promptId:t,questionIndex:n}={}){let r=de(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 ye(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await om(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=eS(a,n);return c.length?(await We(r.leadBox,c,{kind:"navigate-prompt"}),await ue({flow:"prompt",phase:"navigated",sessionName:r.leadBox,agent:o.agent,provider:a.provider,promptId:a.promptId,fromIndex:a.questionIndex??0,toIndex:n,mode:"keys",value:c.join(" "),count:c.length}).catch(()=>{}),{ok:!0,promptId:a.promptId,sent:c.length}):{ok:!0,promptId:a.promptId,sent:0}}function op(e){let t=Ca.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},Ca.set(e,t)),t}function ps(e){return(Ca.get(e)?.items??[]).map(({delivery:t,...n})=>({...n}))}function _g(e=Date.now()){let t=0,n=0;for(let r of Ca.values())for(let o of r.items){t+=1;let s=e-(o.delivery?.queuedAt??o.ts??e);s>n&&(n=s)}return{queueDepth:t,queueOldestAgeMs:n}}function e2(e,t,n){let r=t.filter(o=>o.delivery&&!o.delivery.settled);r.length&&(async()=>{let o=de(await Z(),e)||null;for(let s of r)await Dn(o,s.delivery,`dropped:${n}`)})().catch(()=>{})}function Kc(e,t="cancel"){let n=Ca.get(e);if(!n)return[];let r=n.items.splice(0);return n.idleSince=null,n.timer&&(clearInterval(n.timer),n.timer=null),e2(e,r,t),r}async function Ig(e){let t=Kc(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=de(await Z(),e);if(o)return r=Na(o,n),await se(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function $g(e){let t=op(e);t.timer||(t.timer=setInterval(()=>t2(e).catch(()=>{}),Q4))}async function t2(e){let t=Ca.get(e);if(!(!t||t.flushing)){if(!t.items.length){t.timer&&(clearInterval(t.timer),t.timer=null);return}t.flushing=!0;try{let n=de(await Z(),e);if(!n||n.archivedAt){Kc(e,"archived");return}let r=l=>{for(let u of t.items)sE(u.delivery,l)},o=La(e);if(o&&!o.finishedAt&&o.step!=="done"&&!o.error){ds(t,!1),r("handoff");return}let s=await ye(n.leadBox),a=n.boxes.find(l=>l.name===n.leadBox);if(s&&await qg(s)&&(s=await Uc(n,a,"queue")?await ye(n.leadBox):null,await se()),!s){ds(t,!1),r("noSession");return}if(Zr(a?.agent)){ds(t,!1),r("cap");return}let i=await Pe(n.leadBox,{lines:Ye}).catch(()=>"");if(Di(a?.agent,i)){ds(t,!1),r("busy");return}if(Xr(a?.agent,i)){let l=await an(n.leadBox).catch(()=>i);if(On(a,l)){ds(t,!1),r("prompt");return}}if(!ds(t,!0)){r("grace");return}let c=t.items.shift();t.idleSince=null,c.delivery&&(c.delivery.dequeuedAt=Date.now());try{await gg(n,a,s,c.text,c.kind??null,c.attachments??null,c.delivery??null)}catch(l){if(l?.code!=="cli-not-running")throw c.delivery&&await Dn(n,c.delivery,xa(l)),l;t.items.unshift(c),c.delivery&&(c.delivery.requeued+=1,c.delivery.dequeuedAt=null,await gc(n,c.delivery,{position:1,reason:"requeue"})),await Uc(n,a,"queue-gate")}await se()}finally{t.flushing=!1}}}async function eI(e,t,n,r){let o=Zr(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(Na(e,[n]),await se()),yS(e.id,o))try{await C(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 n2(e,t){let n=await Pe(e.leadBox,{lines:Ye}).catch(()=>"");if(!Xr(t?.agent,n))return!1;let r=await an(e.leadBox).catch(()=>n);return!!On(t,r)}async function gg(e,t,n,r,o=null,s=null,a=null){a||(a=wc({text:r,producer:mc({kind:o}),kind:o,provider:t?.agent??null,attachments:Array.isArray(s)?s.length:0})),a.provider??=t?.agent??null,await eI(e,t,r,o);let i=Bc.get(e.id)||0,c=r,l=!1,u=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(c=J_(r,e.pendingHandoffHydrate.artifact||ho),delete e.pendingHandoffHydrate,l=!0);let d=Array.isArray(s)?s.filter(h=>h&&h.rel):[];if(d.length){let h=A_(d.map(g=>g.rel));c=c.trim()?`${c.trim()}
214
214
 
215
- ${m}`:m}let p=$e(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,deliveryId:a.id,...o?{kind:o}:{},...d.length?{attachments:d}:{}});o||ga(e,null);try{let m=Date.now(),g=null;try{g=await Cr({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:Sa(n.agent),bailOnDialog:!0})}catch(x){throw tc(a,{ms:Date.now()-m,outcome:x?.code==="cli-not-running"?"cli-not-running":"blocked"}),x}if(tc(a,{ms:Date.now()-m,outcome:g||"up"}),(bc.get(e.id)||0)!==i){!o&&r.trim()&&(ba(e,[r]),await ue());let x=new Error("delivery stopped \u2014 the message was handed back as the draft");throw x.interrupted=!0,x}if(await y4(e,t)){let x=Rd(e.id);a.requeued+=1,a.dequeuedAt=null;let b={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...d.length?{attachments:d}:{},delivery:a};x.items.unshift(b),Yw(e.id),await ec(e,a,{position:1,reason:"prompt"});let O=new Error("lead is blocked on a prompt \u2014 message queued");throw O.requeued={id:b.id,position:x.items.length},O}let y=En(t?.agent,c);a.paste=!!y.paste,await ot(e.leadBox,c,{...y,kind:l?"lead-handoff-first-prompt":"say"})}catch(m){if(u&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=u),$e(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,...m?.interrupted?{reason:"interrupted"}:{},...m?.requeued?{reason:"requeued"}:{}}),m?.requeued)return{queued:!0,...m.requeued};throw m?.code!=="cli-not-running"&&await Nn(e,a,aa(m)),m}let f={},w=await N4(e,t,c,f);a.verify=f,w?await Nn(e,a,f.verdict==="unverified"?"unverified":"delivered"):(await k_(e.leadBox,t?.agent,c.length+8,c).catch(()=>{}),$e(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,reason:"unsubmitted"}),o||ba(e,[r]),await Nn(e,a,"unsubmitted")),l&&await le({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function Xw(e,{actions:t}={}){let n=Rd(e),r=dS(t),o=Qi({text:r,producer:Zi({kind:"ship-notify"}),kind:"ship-notify"});n.items.push({id:o.id,text:r,ts:Date.now(),kind:"ship-notify",delivery:o}),Yw(e),(async()=>{let s=me(await ee(),e);s&&(o.provider=s.boxes.find(a=>a.name===s.leadBox)?.agent??null,await ec(s,o,{position:n.items.length,reason:"queue"}))})().catch(()=>{})}async function b4(e,t,n,r){await qe(e.leadBox,["Escape"],{kind:"dismiss-prompt"});let o="",s=!1;for(let c of[250,400,600,900]){if(await br(c),o=await Be(e.leadBox,{lines:Ze}).catch(()=>""),!qr(t?.agent,o)){s=!0;break}let l=await on(e.leadBox).catch(()=>o);if(!$n(t,l)){s=!0;break}}let a=n.questions?.[0]||{},i={groupId:n.groupId||n.promptId,questionIndex:n.questionIndex??0,questionTotal:n.questionTotal??1,header:a.header||"",question:a.question||"",multiSelect:!!a.multiSelect,options:(a.options||[]).map(c=>c?.label).filter(Boolean),via:"send",deliveryId:r?.id??null,gone:s};return le({flow:"prompt",phase:"dismissed",sessionName:e.leadBox,agent:t?.agent,provider:n.provider,promptId:n.promptId,...i}).catch(()=>{}),s&&Zv(e,t,n,i),{gone:s,pane:o}}async function Bt(e,t,{kind:n=null,attachments:r=null,producer:o=null,dismissPrompt:s=!1}={}){let a=Array.isArray(r)?r.filter(d=>d&&typeof d.rel=="string"):[];if((typeof t!="string"||!Hs(t))&&!a.length)throw new Error("text (string) or an attachment required");let i=me(await ee(),e);if(!i)throw new Error(`track "${e}" not found`);if(i.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before driving it`);bg(i);let c=i.boxes.find(d=>d.name===i.leadBox),l=Hs(t),u=Qi({text:l,producer:Zi({kind:n,producer:o}),kind:n,provider:c?.agent??null,attachments:a.length});try{return await k4(e,i,c,l,{kind:n,atts:a,d:u,dismissPrompt:s})}catch(d){throw await Nn(i,u,aa(d)),d}}async function k4(e,t,n,r,{kind:o,atts:s,d:a,dismissPrompt:i=!1}){await y_(t,n,r,o),$c(e,"say");let c=await ke(t.leadBox);if(c&&await lg(c)?await Sc(t,n,"say")?(await ue(),c=await ke(t.leadBox)):c=null:!c&&await Oc(t)&&(await ue(),c=await ke(t.leadBox)),!c)throw new Error(`lead box "${t.leadBox}" is not running`);let l=hc.get(e);l&&await l.catch(()=>{});let u=Rd(e),d=await Be(t.leadBox,{lines:Ze}).catch(()=>""),p=u.items.length>0?"queue":gi(n?.agent,d)?"busy":null,f=p!=null,w=i&&!o;if((!f||p==="queue"&&w)&&qr(n?.agent,d)){let g=await on(t.leadBox).catch(()=>d),y=$n(n,g);if(f||(f=!!y,f&&(p="prompt")),y&&w&&y.dismissable){let x=await b4(t,n,y,a);x.gone&&p==="prompt"&&(d=x.pane,f=gi(n?.agent,d),p=f?"busy":null)}}if(f){let g={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...s.length?{attachments:s}:{},delivery:a};return u.items.push(g),Yw(e),o||ga(t,null),await ue(),await ec(t,a,{position:u.items.length,reason:p}),{ok:!0,leadBox:t.leadBox,queued:!0,id:g.id,position:u.items.length,deliveryId:a.id}}let m;try{m=await jw(t,n,c,r,o,s,a)}catch(g){if(g?.code!=="cli-not-running"||!await Sc(t,n,"say-gate")||(await ue(),c=await ke(t.leadBox),!c))throw g;m=await jw(t,n,c,r,o,s,a)}return await ue(),m?.queued?{ok:!0,leadBox:t.leadBox,queued:!0,id:m.id,position:m.position,deliveryId:a.id}:{ok:!0,leadBox:t.leadBox,deliveryId:a.id}}async function Zw(e,{hint:t}={}){let n=me(await ee(),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=zh(n.id);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o=n.boxes.find(i=>i.name===n.leadBox),s=String(t||"").trim()?String(t).trim().slice(0,40):"preview";OA(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${s_}
215
+ ${h}`:h}let p=Ae(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,deliveryId:a.id,...o?{kind:o}:{},...d.length?{attachments:d}:{}});o||Ma(e,null);try{let h=Date.now(),g=null;try{g=await er({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:ms(n.agent),bailOnDialog:!0})}catch(x){throw yc(a,{ms:Date.now()-h,outcome:x?.code==="cli-not-running"?"cli-not-running":"blocked"}),x}if(yc(a,{ms:Date.now()-h,outcome:g||"up"}),(Bc.get(e.id)||0)!==i){!o&&r.trim()&&(Na(e,[r]),await se());let x=new Error("delivery stopped \u2014 the message was handed back as the draft");throw x.interrupted=!0,x}if(await n2(e,t)){let x=op(e.id);a.requeued+=1,a.dequeuedAt=null;let b={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...d.length?{attachments:d}:{},delivery:a};x.items.unshift(b),$g(e.id),await gc(e,a,{position:1,reason:"prompt"});let I=new Error("lead is blocked on a prompt \u2014 message queued");throw I.requeued={id:b.id,position:x.items.length},I}let y=In(t?.agent,c);a.paste=!!y.paste,await ot(e.leadBox,c,{...y,kind:l?"lead-handoff-first-prompt":"say"})}catch(h){if(u&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=u),Ae(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,...h?.interrupted?{reason:"interrupted"}:{},...h?.requeued?{reason:"requeued"}:{}}),h?.requeued)return{queued:!0,...h.requeued};throw h?.code!=="cli-not-running"&&await Dn(e,a,xa(h)),h}let f={},w=await y2(e,t,c,f);a.verify=f,w?await Dn(e,a,f.verdict==="unverified"?"unverified":"delivered"):(await nI(e.leadBox,t?.agent,c.length+8,c).catch(()=>{}),Ae(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,reason:"unsubmitted"}),o||Na(e,[r]),await Dn(e,a,"unsubmitted")),l&&await ue({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function Rg(e,{actions:t}={}){let n=op(e),r=JS(t),o=wc({text:r,producer:mc({kind:"ship-notify"}),kind:"ship-notify"});n.items.push({id:o.id,text:r,ts:Date.now(),kind:"ship-notify",delivery:o}),$g(e),(async()=>{let s=de(await Z(),e);s&&(o.provider=s.boxes.find(a=>a.name===s.leadBox)?.agent??null,await gc(s,o,{position:n.items.length,reason:"queue"}))})().catch(()=>{})}async function r2(e,t,n,r){await We(e.leadBox,["Escape"],{kind:"dismiss-prompt"});let o="",s=!1;for(let c of[250,400,600,900]){if(await Sr(c),o=await Pe(e.leadBox,{lines:Ye}).catch(()=>""),!Xr(t?.agent,o)){s=!0;break}let l=await an(e.leadBox).catch(()=>o);if(!On(t,l)){s=!0;break}}let a=n.questions?.[0]||{},i={groupId:n.groupId||n.promptId,questionIndex:n.questionIndex??0,questionTotal:n.questionTotal??1,header:a.header||"",question:a.question||"",multiSelect:!!a.multiSelect,options:(a.options||[]).map(c=>c?.label).filter(Boolean),via:"send",deliveryId:r?.id??null,gone:s};return ue({flow:"prompt",phase:"dismissed",sessionName:e.leadBox,agent:t?.agent,provider:n.provider,promptId:n.promptId,...i}).catch(()=>{}),s&&DS(e,t,n,i),{gone:s,pane:o}}async function Ht(e,t,{kind:n=null,attachments:r=null,producer:o=null,dismissPrompt:s=!1}={}){let a=Array.isArray(r)?r.filter(d=>d&&typeof d.rel=="string"):[];if((typeof t!="string"||!sa(t))&&!a.length)throw new Error("text (string) or an attachment required");let i=de(await Z(),e);if(!i)throw new Error(`track "${e}" not found`);if(i.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before driving it`);fp(i);let c=i.boxes.find(d=>d.name===i.leadBox),l=sa(t),u=wc({text:l,producer:mc({kind:n,producer:o}),kind:n,provider:c?.agent??null,attachments:a.length});try{return await o2(e,i,c,l,{kind:n,atts:a,d:u,dismissPrompt:s})}catch(d){throw await Dn(i,u,xa(d)),d}}async function o2(e,t,n,r,{kind:o,atts:s,d:a,dismissPrompt:i=!1}){await eI(t,n,r,o),Ba(e,"say");let c=await ye(t.leadBox);if(c&&await qg(c)?await Uc(t,n,"say")?(await se(),c=await ye(t.leadBox)):c=null:!c&&await zc(t)&&(await se(),c=await ye(t.leadBox)),!c)throw new Error(`lead box "${t.leadBox}" is not running`);let l=Mc.get(e);l&&await l.catch(()=>{});let u=op(e),d=await Pe(t.leadBox,{lines:Ye}).catch(()=>""),p=u.items.length>0?"queue":Di(n?.agent,d)?"busy":null,f=p!=null,w=i&&!o;if((!f||p==="queue"&&w)&&Xr(n?.agent,d)){let g=await an(t.leadBox).catch(()=>d),y=On(n,g);if(f||(f=!!y,f&&(p="prompt")),y&&w&&y.dismissable){let x=await r2(t,n,y,a);x.gone&&p==="prompt"&&(d=x.pane,f=Di(n?.agent,d),p=f?"busy":null)}}if(f){let g={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...s.length?{attachments:s}:{},delivery:a};return u.items.push(g),$g(e),o||Ma(t,null),await se(),await gc(t,a,{position:u.items.length,reason:p}),{ok:!0,leadBox:t.leadBox,queued:!0,id:g.id,position:u.items.length,deliveryId:a.id}}let h;try{h=await gg(t,n,c,r,o,s,a)}catch(g){if(g?.code!=="cli-not-running"||!await Uc(t,n,"say-gate")||(await se(),c=await ye(t.leadBox),!c))throw g;h=await gg(t,n,c,r,o,s,a)}return await se(),h?.queued?{ok:!0,leadBox:t.leadBox,queued:!0,id:h.id,position:h.position,deliveryId:a.id}:{ok:!0,leadBox:t.leadBox,deliveryId:a.id}}async function Og(e,{hint:t}={}){let n=de(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=_w(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";mE(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${H_}
216
216
 
217
- What to preview: ${String(t).trim()}`:s_;try{await Bt(e,a,{kind:"spin-up-view"})}catch(i){throw ld(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Od(e){let t=me(await ee(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);bc.set(e,(bc.get(e)||0)+1);let n=Ic(e,"interrupt"),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=wa.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=ba(t,r),await ue()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=E4(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,br(x4)]);let a=me(await ee(),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 b_(e){let t=wa.get(e);return!!t&&!t.canceled}function $c(e,t){let n=wa.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function Qw(e){$c(e,"track-ended"),bc.delete(e),Ic(e,"track-ended")}function E4(e,{droppedCount:t,droppedTexts:n}){let r={startedAt:Date.now(),clicks:1,escSends:0,bgSends:0,queuedTexts:[...n],canceled:!1,cancelReason:null,result:null,restored:null},o;return r.settled=new Promise(s=>{o=s}),wa.set(e,r),(async()=>{let s=me(await ee(),e),a=s?.boxes.find(g=>g.name===s.leadBox),i=s?await ke(s.leadBox):null,c=!1,l=!1;if(i){e:for(let g=0;g<v4&&!r.canceled;g++){await qe(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let y of S4){await br(y);let x=await Be(s.leadBox,{lines:Ze}).catch(()=>"");if(!Cs(a?.agent,x)){c=!0;break e}}}if(!c){l=!0;for(let g=0;g<A4&&!r.canceled&&(await br(T4),!r.canceled);g++){let y=await Be(s.leadBox,{lines:Ze}).catch(()=>"");if(!Cs(a?.agent,y)){c=!0;break}await qe(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=me(await ee(),e)||s,d=u?.boxes.find(g=>g.name===u.leadBox)||a,p=null,f=null;u&&d&&i&&c&&!r.canceled&&(p=await R4(u,d).catch(()=>null),p||(f=await C4(u,d).catch(()=>null)));let w=u&&i&&!r.canceled?await I4(u).catch(()=>null):null,m=[p||f,...r.queuedTexts].filter(Boolean);u&&m.length&&(r.restored=ba(u,m),await ue()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await _4(u||s,d,{ts:r.startedAt,result:r.result,dropped:t,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!p,lostRestored:!!f,queuedRestored:r.queuedTexts.length,shipDismissed:!!w,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await le({flow:"interrupt",phase:r.result==="gave-up"?"failed":"done",trackId:e,sessionName:u?.leadBox,agent:d?.agent,result:r.result,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!p,lostRestored:!!f,queuedRestored:r.queuedTexts.length,shipDismissed:!!w}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),wa.get(e)===r&&wa.delete(e),o()}),r}async function _4(e,t,n){await M(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function I4(e){let t=ca(await q(e));if(!t?.offerId)return null;let n=t.offerType==="exists";return await M(e,{type:n?"pr.exists.answered":"pr.offer.answered",actor:"user",source:"orchestrator",boxId:t.box,payload:{ts:Date.now(),offerId:t.offerId,...n?{choice:"dismiss"}:{action:"dismiss",actions:null},reason:"interrupt"}}),t.offerId}async function R4(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 $4){await br(r);let o=await Be(e.leadBox,{lines:Ze}).catch(()=>""),s=xi(t.agent,o);if(s&&Xl(n.text,s))return await k_(e.leadBox,t.agent,n.text.length+8),$e(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function C4(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>O4||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!Fe(r.text))return null;for(let s of M4){await br(s);let a;try{a=await gm(t,{})}catch{return null}if(y0(a,r))return null;let i=await Be(e.leadBox,{lines:Ze}).catch(()=>"");if(xi(t.agent,i))return null}return $e(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function N4(e,t,n,r=null){return Ti({sessionName:e.leadBox,agent:t?.agent,agentCmd:Sa(t?.agent),text:n,trackId:e.id,flow:"say",stats:r})}async function k_(e,t,n,r=null){for(let o=0;o<3;o++){await Es(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await br(200);let s=await Be(e,{lines:Ze}).catch(()=>""),a=xi(t,s);if(!a||r&&!Xl(r,a)&&!(t==="codex"&&Uf(r,a)))return!0;n=a.length+8}return!1}function ga(e,t,{source:n}={}){e.draftRev=(e.draftRev||0)+1;let r=typeof t=="string"?t:"";return r.trim()?e.draft={text:r,updatedAt:Date.now(),...n?{source:n}:{}}:delete e.draft,e.draft||null}function ba(e,t){let n=[],r=o=>n.some(s=>Fe(s).includes(Fe(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?ga(e,n.join(`
217
+ What to preview: ${String(t).trim()}`:H_;try{await Ht(e,a,{kind:"spin-up-view"})}catch(i){throw Od(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function sp(e){let t=de(await Z(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);Bc.set(e,(Bc.get(e)||0)+1);let n=Kc(e,"interrupt"),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=Oa.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=Na(t,r),await se()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=u2(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,Sr(s2)]);let a=de(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 tI(e){let t=Oa.get(e);return!!t&&!t.canceled}function Ba(e,t){let n=Oa.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function Mg(e){Ba(e,"track-ended"),Bc.delete(e),Kc(e,"track-ended")}function u2(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}),Oa.set(e,r),(async()=>{let s=de(await Z(),e),a=s?.boxes.find(g=>g.name===s.leadBox),i=s?await ye(s.leadBox):null,c=!1,l=!1;if(i){e:for(let g=0;g<a2&&!r.canceled;g++){await We(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let y of i2){await Sr(y);let x=await Pe(s.leadBox,{lines:Ye}).catch(()=>"");if(!Xs(a?.agent,x)){c=!0;break e}}}if(!c){l=!0;for(let g=0;g<l2&&!r.canceled&&(await Sr(c2),!r.canceled);g++){let y=await Pe(s.leadBox,{lines:Ye}).catch(()=>"");if(!Xs(a?.agent,y)){c=!0;break}await We(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=de(await Z(),e)||s,d=u?.boxes.find(g=>g.name===u.leadBox)||a,p=null,f=null;u&&d&&i&&c&&!r.canceled&&(p=await h2(u,d).catch(()=>null),p||(f=await g2(u,d).catch(()=>null)));let w=u&&i&&!r.canceled?await p2(u).catch(()=>null):null,h=[p||f,...r.queuedTexts].filter(Boolean);u&&h.length&&(r.restored=Na(u,h),await se()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await d2(u||s,d,{ts:r.startedAt,result:r.result,dropped:t,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!p,lostRestored:!!f,queuedRestored:r.queuedTexts.length,shipDismissed:!!w,durationMs:Date.now()-r.startedAt,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),await ue({flow:"interrupt",phase:r.result==="gave-up"?"failed":"done",trackId:e,sessionName:u?.leadBox,agent:d?.agent,result:r.result,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!p,lostRestored:!!f,queuedRestored:r.queuedTexts.length,shipDismissed:!!w}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),Oa.get(e)===r&&Oa.delete(e),o()}),r}async function d2(e,t,n){await C(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function p2(e){let t=Sa(await K(e));if(!t?.offerId)return null;let n=t.offerType==="exists";return await C(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 h2(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 f2){await Sr(r);let o=await Pe(e.leadBox,{lines:Ye}).catch(()=>""),s=Li(t.agent,o);if(s&&yu(n.text,s))return await nI(e.leadBox,t.agent,n.text.length+8),Ae(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function g2(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>m2||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!Le(r.text))return null;for(let s of w2){await Sr(s);let a;try{a=await Yh(t,{})}catch{return null}if(nx(a,r))return null;let i=await Pe(e.leadBox,{lines:Ye}).catch(()=>"");if(Li(t.agent,i))return null}return Ae(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function y2(e,t,n,r=null){return Hi({sessionName:e.leadBox,agent:t?.agent,agentCmd:ms(t?.agent),text:n,trackId:e.id,flow:"say",stats:r})}async function nI(e,t,n,r=null){for(let o=0;o<3;o++){await qs(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await Sr(200);let s=await Pe(e,{lines:Ye}).catch(()=>""),a=Li(t,s);if(!a||r&&!yu(r,a)&&!(t==="codex"&&xh(r,a)))return!0;n=a.length+8}return!1}function Ma(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 Na(e,t){let n=[],r=o=>n.some(s=>Le(s).includes(Le(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?Ma(e,n.join(`
218
218
 
219
- `),{source:"restore"})?.text??null:null}function D4(e,t){let n=Fe(t);if(!n)return!1;if(Xo(e.id).some(o=>Fe(o.text)===n))return!0;let r=e.events||[];for(let o=r.length-1;o>=0;o--){let s=r[o];if(typeof s.at=="number"&&Date.now()-s.at>P4)break;if(!(s.type!=="said"||!s.text||Fe(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function eg(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=me(await ee(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=Hs(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&D4(r,s))return{ok:!0,draft:r.draft||null,rev:null,ignored:"already-sent"};if(typeof n=="number"&&n<(r.draftRev||0)&&!o.trim()&&r.draft?.text)return{ok:!0,draft:r.draft,rev:r.draftRev||0,ignored:"stale-clear"};if(typeof n=="number"&&n<(r.draftRev||0)&&r.draft?.source==="restore"){let i=r.draft.text;Fe(o).includes(Fe(i))?ga(r,o):ga(r,`${i}
219
+ `),{source:"restore"})?.text??null:null}function k2(e,t){let n=Le(t);if(!n)return!1;if(ps(e.id).some(o=>Le(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>b2)break;if(!(s.type!=="said"||!s.text||Le(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function Cg(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=de(await Z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=sa(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&k2(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;Le(o).includes(Le(i))?Ma(r,o):Ma(r,`${i}
220
220
 
221
- ${o}`,{source:"restore"})}else ga(r,o);return await ue(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function tg(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=me(await ee(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await ke(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(d=>d.name===r.leadBox)?.agent||o.agent||"claude",i=qv(a,n),l=[...r.events||[]].reverse().find(d=>d.type==="model-change")?.to??null;l||(l=(await di(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await Cr({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:Sa(o.agent)});let u=await Kv(a,r.leadBox,i);return $e(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await ue(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function x_(e){for(let t of e){if(!t||!await Ws(t))continue;let n=await vv(t).catch(()=>null);if(!n)continue;if((await te.stat(oe.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function $t(e){let t=e;return t?t.kind==="multi"?Array.isArray(t.repos)?t.repos.filter(Boolean):[]:t.base?[{name:oe.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function Ko(e){let t=[];for(let n of $t(e?.workspace)){if(!n?.dir)continue;let r=await Oi(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await Mi(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function v_(e){let t=e;typeof t=="string"&&!oe.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await ws(t)??await bl(t));let n=await x_([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 B4(e,t,n,r){let o=`track/${Sg(t)}-${e}`,s=[];try{await te.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await v_(i);if(s.some(f=>f.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await _e(c).catch(()=>null),u=oe.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let f=2;a.has(u);f++)u=`${oe.basename(c)}-${f}`;a.add(u);let d=oe.join(n,u),p=await Gs(c);await Ks(c,d,o,p),s.push({name:u,dir:d,base:c,baseRef:p,repo:l})}return await Rc(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await Mt(i.base,i.dir).catch(()=>{});throw await te.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function ng(e,t){let n=await ee(),r=me(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 v_(typeof t=="string"?t.trim():t);if((o.repos??[]).some(p=>p?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await _e(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(p=>p?.name).filter(Boolean)]),c=oe.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let p=2;i.has(c);p++)c=`${oe.basename(s)}-${p}`;let l=oe.join(o.dir,c),u=await Gs(s);await Sv(s,o.branch)?await wu(s,l,o.branch):await Ks(s,l,o.branch,u);let d={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),d],await Rc(o.dir,o.repos,o.branch),$e(r,"retagged",{action:"add",repo:a??s,name:c,workspace:S_(o)}),await ue(),d}async function rg(e,t){let n=await ee(),r=me(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 Dt.values())if(c.trackId===e&&!c.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before untagging");let a=await Oi(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await Mi(s.dir,s.baseRef).catch(()=>0);if(a||i>0)throw new Error(`"${s.name}" has work (${a?"uncommitted changes":`${i} commit${i===1?"":"s"} ahead of ${s.baseRef??"base"}`}) \u2014 ship or discard it first`);return await Mt(s.base,s.dir).catch(()=>{}),await te.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await Rc(o.dir,o.repos,o.branch),$e(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:S_(o)}),await ue(),{removed:s.name}}async function j4(e,t,{repo:n,repos:r,cwd:o}={}){await te.mkdir(gc,{recursive:!0});let s=oe.join(gc,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return B4(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!oe.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await ws(n)??await bl(n));let i=await x_([n,o,XU]);if(i){let c=`track/${Sg(t)}-${e}`;try{let l=await Gs(i);await Ks(i,s,c,l),await xc(s);let u=await _e(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await te.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await te.mkdir(s,{recursive:!0}),await Cm(s),await xc(s),{dir:s,base:null,branch:null,kind:"repo"}}async function xc(e){try{await te.writeFile(oe.join(e,"AGENTS.md"),wc,{flag:"wx"})}catch{return}await H4(e,["/AGENTS.md"])}function U4(e,t){let n=e.map(r=>`- \`${r.name}/\`${r.repo?` \u2014 github.com/${r.repo}`:""}${r.baseRef?` (forked from ${r.baseRef})`:""}`).join(`
222
- `);return`${F4}
221
+ ${o}`,{source:"restore"})}else Ma(r,o);return await se(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function Ng(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=de(await Z(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await ye(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(d=>d.name===r.leadBox)?.agent||o.agent||"claude",i=IS(a,n),l=[...r.events||[]].reverse().find(d=>d.type==="model-change")?.to??null;l||(l=(await Ri(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await er({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:ms(o.agent)});let u=await $S(a,r.leadBox,i);return Ae(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await se(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function rI(e){for(let t of e){if(!t||!await aa(t))continue;let n=await iS(t).catch(()=>null);if(!n)continue;if((await J.stat(z.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function Dt(e){let t=e;return t?t.kind==="multi"?Array.isArray(t.repos)?t.repos.filter(Boolean):[]:t.base?[{name:z.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function is(e){let t=[];for(let n of Dt(e?.workspace)){if(!n?.dir)continue;let r=await zo(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await Vo(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function Pg(e){let t=e;typeof t=="string"&&!z.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await Cs(t)??await Ll(t));let n=await rI([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 x2(e,t,n,r){let o=`track/${wp(t)}-${e}`,s=[];try{await J.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await Pg(i);if(s.some(f=>f.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await _e(c).catch(()=>null),u=z.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let f=2;a.has(u);f++)u=`${z.basename(c)}-${f}`;a.add(u);let d=z.join(n,u),p=await Yo(c);await Jo(c,d,o,p),s.push({name:u,dir:d,base:c,baseRef:p,repo:l})}return await ja(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await St(i.base,i.dir).catch(()=>{});throw await J.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function ap(e,t){let n=await Z(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 unarchive it first");let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track \u2014 a single-repo Track's workspace IS its repo checkout; create the Track with multiple repos tagged instead");let s=await Pg(typeof t=="string"?t.trim():t);if((o.repos??[]).some(p=>p?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await _e(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(p=>p?.name).filter(Boolean)]),c=z.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let p=2;i.has(c);p++)c=`${z.basename(s)}-${p}`;let l=z.join(o.dir,c),u=await Yo(s);await pm(s,o.branch)?await Ji(s,l,o.branch):await Jo(s,l,o.branch,u);let d={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),d],await ja(o.dir,o.repos,o.branch),Ae(r,"retagged",{action:"add",repo:a??s,name:c,workspace:Dg(o)}),await se(),d}async function ip(e,t){let n=await Z(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track");let s=(o.repos??[]).find(c=>c&&(c.name===t||c.repo===t||c.base===t));if(!s)throw new Error(`repo "${t}" is not tagged on this Track`);if((o.repos??[]).filter(Boolean).length<=1)throw new Error("can't untag the last repo \u2014 archive or delete the Track instead");for(let c of Pt.values())if(c.trackId===e&&!c.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before untagging");let a=await zo(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await Vo(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 St(s.base,s.dir).catch(()=>{}),await J.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await ja(o.dir,o.repos,o.branch),Ae(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:Dg(o)}),await se(),{removed:s.name}}async function zd(e,t){let n=await Z(),r=de(n,e);r&&(r.reshape={...r.reshape||{},...t},await se())}async function v2(e){let t=await J.readdir(e).catch(()=>[]);for(let n of t)if(!(n===".git"||n===".bostrat")){if(n==="AGENTS.md"){let r=await J.readFile(z.join(e,n),"utf8").catch(()=>"");if(Nc(r))continue}return!0}try{let{stdout:n}=await Zd("git",["-C",e,"rev-list","--count","HEAD"]);if(Number(n.trim())>1)return!0}catch{}return!1}function W_(e,t,n){let r=z.basename(e);n.has(r)&&t&&(r=t.replace("/","-"));for(let o=2;n.has(r);o++)r=`${z.basename(e)}-${o}`;return n.add(r),r}async function oI(e,{added:t=[]}={}){let{shape:n,dir:r,staging:o,sub:s,base:a,scratch:i}=e;for(let l of t)await St(l.base,l.dir).catch(()=>{});let c=async(l,u)=>{await wn(l)&&!await wn(u)&&await J.rename(l,u)};if(n==="worktree"&&s){let l=z.join(r,s);await wn(l)&&(await c(z.join(r,".bostrat"),z.join(l,".bostrat")),await Vd(a,l,o))}if(n==="repo"&&i){let l=z.join(r,i);await wn(l)&&(await wn(o)&&await J.rm(o,{recursive:!0,force:!0}),await J.rename(l,o))}return await wn(o)?(await wn(r)&&(await c(z.join(r,".bostrat"),z.join(o,".bostrat")),await J.rm(r,{recursive:!0,force:!0})),n==="worktree"?await Vd(a,o,r):await J.rename(o,r),!0):!1}async function Bg(e,t,{skipPermissions:n=!0}={}){let r=await Z(),o=de(r,e);if(!o)throw gt(`track "${e}" not found`,404);if(o.archivedAt)throw gt("track is archived \u2014 unarchive it first");try{fp(o)}catch(g){throw Object.assign(g,{status:409})}if(o.kind==="setup")throw gt("setup boxes have no repos to reshape");if(String(o.name||"").startsWith("\u21BB"))throw gt("this Track's repos are the loop's \u2014 propose-update the loop instead");let s=yg.get(e);if(s&&!s.finishedAt)throw gt("a reshape is already running for this Track");let a=hs.get(e);if(a&&!a.finishedAt)throw gt("a lead handoff is running \u2014 retry when it settles");let i=Yd.get(e);if(i&&!i.finishedAt)throw gt("a node transfer is running \u2014 retry when it settles");if(Kd.has(e))throw gt("an adopt is running for this Track \u2014 retry when it settles");for(let g of Pt.values())if(g.trackId===e&&!g.finishedAt)throw gt("a subtask is still running on this Track \u2014 wait for it to merge back before reshaping");let c=(Array.isArray(t)?t:[]).map(g=>typeof g=="string"?g.trim():"").filter(Boolean);if(!c.length)throw gt("repos (non-empty list of paths or owner/name slugs) required",400);let l=[];for(let g of c){let y;try{y=await Pg(g)}catch(x){throw gt(x?.message||String(x),400)}if(l.some(x=>x.base===y))throw gt(`repo tagged twice: ${g}`,400);l.push({sel:g,base:y,slug:await _e(y).catch(()=>null)})}let u=o.workspace;if(u?.kind==="multi"){let g=(u.repos??[]).filter(Boolean),y=g.filter(I=>!l.some(_=>_.base===I.base)),x=l.filter(I=>!g.some(_=>_.base===I.base));if(!y.length&&!x.length)return{trackId:e,step:"done",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:Date.now(),error:null};for(let I of y){let _=await zo(I.dir,{ignorePlumbing:!0}).catch(()=>!1),N=await Vo(I.dir,I.baseRef).catch(()=>0);if(_||N>0)throw gt(`"${I.name}" has work \u2014 ship or discard it before dropping it`)}let b={trackId:e,step:"retag",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:null,error:null};for(let I of x){let _=await ap(e,I.base);b.added.push(_.repo??_.base)}for(let I of y)await ip(e,I.name),b.removed.push(I.repo??I.base);return b.step="done",b.finishedAt=Date.now(),b}if(u?.kind!=="worktree"&&u?.kind!=="repo")throw gt(`can't reshape a "${u?.kind??"unknown"}" workspace`);let d=u.kind==="worktree"&&l.some(g=>g.base===u.base);if(u.kind==="worktree"&&!d){let g=await zo(u.dir??o.cwd,{ignorePlumbing:!0}).catch(()=>!1),y=await Vo(u.dir??o.cwd,u.baseRef).catch(()=>0);if(g||y>0)throw gt(`"${z.basename(u.base)}" has work (${g?"uncommitted changes":`${y} commit${y===1?"":"s"} ahead of ${u.baseRef??"base"}`}) \u2014 ship or discard it before swapping it out`)}Ba(e,"reshape");let p=o.boxes.find(g=>g.name===o.leadBox)||null;if(!p)throw gt("this Track has no lead box");let f=p.agent||"claude",w=await Da(f,n),h={trackId:e,step:"checkpoint",inPlace:!1,startedAt:Date.now(),finishedAt:null,error:null,added:l.filter(g=>!(u.kind==="worktree"&&g.base===u.base)).map(g=>g.slug??g.base),removed:u.kind==="worktree"&&!d?[u.repo??u.base]:[],scratch:!1,views:0,checkpoint:null};return yg.set(e,h),await zd(e,{step:h.step,startedAt:h.startedAt,finishedAt:null,error:null,added:h.added,removed:h.removed,layout:null}),S2(h,o,{desired:l,keep:d,lead:p,agent:f,agentCmd:w,skipPermissions:n}).catch(async g=>{h.error=g?.message||String(g),h.finishedAt=Date.now(),console.error(`[reshape ${e}] FAILED at step "${h.step}": ${h.error}`),await zd(e,{step:h.step,error:h.error,finishedAt:h.finishedAt}).catch(()=>{})}),h}async function S2(e,t,{desired:n,keep:r,lead:o,agent:s,agentCmd:a,skipPermissions:i}){let c=e.trackId,l=t.workspace,u=t.cwd,d=async(O,S={})=>{e.step=O,console.log(`[reshape ${c}] step \u2192 ${O}`),await zd(c,{step:O,...S})},p=await ye(o.name).catch(()=>null),f=o.sessionId??p?.sessionId??null,w=o.pinned===!0;if(await d("checkpoint"),e.checkpoint="llm",!p)e.checkpoint="skipped-dead";else if(Zr(s))e.checkpoint="skipped-capped";else try{await Ru(o.name,{timeoutMs:xg})}catch{e.checkpoint="reconstructed"}let h=null;e.checkpoint!=="llm"&&(h=await Ou(c,u,{trackName:t.name||c}).catch(()=>null)),await d("quiesce"),e.views=await Cw(c).catch(()=>0),await Vl(u).catch(()=>{}),p&&(await Uh(o.name,{fromAgent:s}).catch(()=>{}),await Ot(o.name).catch(()=>{}));let g=`${u}.reshape-${Date.now()}`,y=new Set([".bostrat"]),x={shape:l.kind,dir:u,staging:g,base:l.kind==="worktree"?l.base:null,sub:l.kind==="worktree"&&r?W_(l.base,l.repo??null,y):null,scratch:null},b=l.branch||`track/${wp(t.name||c)}-${c}`,I=[],_=[],N=null;try{if(await d("move",{layout:x}),l.kind==="worktree")if(await Vd(l.base,u,g),await J.mkdir(u,{recursive:!0}),r){let S=z.join(u,x.sub);await Vd(l.base,g,S),await wn(z.join(S,".bostrat"))&&await J.rename(z.join(S,".bostrat"),z.join(u,".bostrat"));let M=z.join(S,"AGENTS.md");Nc(await J.readFile(M,"utf8").catch(()=>null))&&(await J.rm(M,{force:!0}).catch(()=>{}),await iI(S,"/AGENTS.md").catch(()=>{})),I.push({name:x.sub,dir:S,base:l.base,baseRef:l.baseRef??null,repo:l.repo??null})}else await wn(z.join(g,".bostrat"))&&await J.rename(z.join(g,".bostrat"),z.join(u,".bostrat"));else await J.rename(u,g),await J.mkdir(u,{recursive:!0}),await wn(z.join(g,".bostrat"))&&await J.rename(z.join(g,".bostrat"),z.join(u,".bostrat"));await d("materialize");for(let S of n){if(l.kind==="worktree"&&S.base===l.base)continue;let M=W_(S.base,S.slug,y),H=z.join(u,M),W=await Yo(S.base);await pm(S.base,b)?await Ji(S.base,H,b):await Jo(S.base,H,b,W);let te={name:M,dir:H,base:S.base,baseRef:W,repo:S.slug};I.push(te),_.push(te)}if(l.kind==="repo"&&await v2(g)){let S="scratch";for(let M=2;y.has(S);M++)S=`scratch-${M}`;y.add(S),x.scratch=S,await zd(c,{layout:x}),await J.rename(g,z.join(u,S)),e.scratch=!0}await ja(u,I,b,{scratch:x.scratch}),await d("relaunch"),N=await En(o.name,u,{agentCmd:a,agent:s}),await er({cwd:u,sessionName:o.name,agent:s,agentCmd:ms(s)}).catch(S=>{if(S?.code!=="cli-not-running")throw S});let O=await Pe(o.name,{lines:Ye}).catch(()=>"");if(!Uo(s,O))throw new Error(`relaunched ${s} CLI never drew its composer in the hub`)}catch(O){await d("rollback",{error:O?.message||String(O)}),await Ot(o.name).catch(()=>{}),await oI(x,{added:_}).catch(W=>{console.error(`[reshape ${c}] rollback move failed: ${W?.message||W}`)});let S=await Z(),M=de(S,c),H=M?.boxes.find(W=>W.name===o.name)||null;try{let W=ep(s,f,{skipPermissions:i,cwd:u,peerName:o.name}),te=await En(o.name,u,{agentCmd:W,agent:s,resumeSessionId:f,pinned:w});H&&(H.hookTokenHash=$o(te.hookToken),H.state="live"),Ho({cwd:u,sessionName:o.name,agent:s,agentCmd:W})}catch(W){console.error(`[reshape ${c}] rollback relaunch failed: ${W?.message||W}`)}throw M&&(Ae(M,"retag-failed",{action:"reshape",box:o.name,agent:s,reason:O?.message||String(O),rolledBack:!0}),M.reshape={...M.reshape||{},step:"error",error:O?.message||String(O),finishedAt:Date.now(),recovered:"rolled-back"},await se()),e.step="error",e.recovered="rolled-back",e.error=O?.message||String(O),e.finishedAt=Date.now(),O}await d("commit");let U=await Z(),j=de(U,c);if(!j)throw new Error(`track "${c}" vanished mid-reshape`);let T=j.boxes.find(O=>O.name===o.name);if(!T)throw new Error(`lead box row "${o.name}" missing during reshape commit`);let R=Date.now(),L=fs(T),V=L[L.length-1];V.endedAt==null&&(V.endedAt=R),V.endReason==null&&(V.endReason="reshape"),L.push({agent:s,sessionId:N.sessionId,pinned:N.pinned===!0,startedAt:R,endedAt:null}),T.cwd=u,T.agent=s,T.sessionId=N.sessionId,T.pinned=N.pinned===!0,T.hookTokenHash=$o(N.hookToken),T.state="live",T.role="lead",delete T.readyAt,j.cwd=u,j.workspace={dir:u,kind:"multi",branch:b,repos:I},j.pendingHandoffHydrate={artifact:h||ho,at:R},Ae(j,"retagged",{action:"reshape",added:e.added,removed:e.removed,scratch:e.scratch,checkpoint:e.checkpoint,views:e.views,box:o.name,agent:s,fromSessionId:f,toSessionId:N.sessionId,epoch:L.length-1,workspace:Dg(j.workspace)}),j.reshape={...j.reshape||{},step:"done",finishedAt:R,error:null,checkpoint:e.checkpoint,scratch:e.scratch,views:e.views,layout:null},await se(),Ho({cwd:u,sessionName:o.name,agent:s,agentCmd:a,onReady:async()=>{T.readyAt||(T.readyAt=Date.now(),await se())}}),await wn(g)&&(l.kind==="worktree"&&await St(l.base,g).catch(()=>{}),await J.rm(g,{recursive:!0,force:!0}).catch(()=>{})),e.step="done",e.finishedAt=R}async function jg(){let e=await Z(),t=0;for(let n of e.tracks||[]){let r=n.reshape;if(!r||r.finishedAt)continue;t++;let o=n.boxes.find(c=>c.name===n.leadBox)||null;o&&await Ot(o.name).catch(()=>{});let s=!1,a=null;if(r.layout)try{let{dir:c,sub:l,scratch:u}=r.layout,d=new Set([".bostrat",l,u].filter(Boolean)),p=[];for(let f of await J.readdir(c).catch(()=>[])){if(d.has(f))continue;let w=z.join(c,f),h=await J.readFile(z.join(w,".git"),"utf8").catch(()=>null),g=h&&/^gitdir:\s*(.+?)\/\.git\/worktrees\//m.exec(h);g&&p.push({base:g[1],dir:w})}s=await oI(r.layout,{added:p})}catch(c){a=c?.message||String(c),console.error(`[reshape ${n.id}] boot rollback failed: ${a}`)}o&&!vr.has(o.state)&&(o.state="stopped");let i=`interrupted by a node restart during "${r.step}"${s?" \u2014 moved back":""}${a?` (${a})`:""}`;Ae(n,"retag-failed",{action:"reshape",box:n.leadBox,agent:o?.agent??null,reason:i,rolledBack:!a,recovered:!0}),n.reshape={...r,step:"error",error:i,finishedAt:Date.now(),recovered:a?"rollback-failed":"rolled-back",layout:null}}return t&&await se(),t}async function A2(e,t,{repo:n,repos:r,cwd:o}={}){await J.mkdir(Pc,{recursive:!0});let s=z.join(Pc,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return x2(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!z.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await Cs(n)??await Ll(n));let i=await rI([n,o,P4]);if(i){let c=`track/${wp(t)}-${e}`;try{let l=await Yo(i);await Jo(i,s,c,l),await Lc(s);let u=await _e(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await J.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await J.mkdir(s,{recursive:!0}),await fm(s),await Lc(s),{dir:s,base:null,branch:null,kind:"repo"}}async function Lc(e){try{await J.writeFile(z.join(e,"AGENTS.md"),Cc,{flag:"wx"})}catch{return}await I2(e,["/AGENTS.md"])}function _2(e,t,{scratch:n=null}={}){let r=e.map(s=>`- \`${s.name}/\`${s.repo?` \u2014 github.com/${s.repo}`:""}${s.baseRef?` (forked from ${s.baseRef})`:""}`).join(`
222
+ `),o=n?`
223
+ \`${n}/\` is this Track's pre-repo workspace, carried over when the
224
+ Track was reshaped onto these repos. It is not part of any tagged repo and
225
+ cannot be shipped \u2014 move anything worth keeping into the repo it belongs to.
226
+ `:"";return`${E2}
223
227
 
224
228
  This directory is NOT a git repo. It is a bostrat Track workspace holding one
225
229
  git worktree per tagged repo, ALL on the same branch \`${t}\`:
226
230
 
227
- ${n}
231
+ ${r}
228
232
 
229
233
  cd into the repo a change belongs to before running git commands; commit (and
230
234
  push / open PRs) in each repo separately, always on that shared branch. Work
231
235
  only needs to land in the repos it actually touches \u2014 an untouched repo's
232
236
  branch simply stays at its fork point and never gets pushed. When asked to run
233
237
  or preview an app, run it from that app's own repo directory.
234
- `}async function Rc(e,t,n){let r=U4(t,n);for(let o of["CLAUDE.md","AGENTS.md"])await te.writeFile(oe.join(e,o),r).catch(()=>{})}async function A_(e){let{stdout:t}=await u_("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return oe.resolve(e,t.trim())}async function H4(e,t){try{let n=await A_(e);await te.mkdir(oe.dirname(n),{recursive:!0});let r=await te.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
235
- `).includes(s));o.length&&await te.appendFile(n,(r.endsWith(`
238
+ ${o}`}async function ja(e,t,n,r={}){let o=_2(t,n,r);for(let s of["CLAUDE.md","AGENTS.md"])await J.writeFile(z.join(e,s),o).catch(()=>{})}async function aI(e){let{stdout:t}=await Zd("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return z.resolve(e,t.trim())}async function I2(e,t){try{let n=await aI(e);await J.mkdir(z.dirname(n),{recursive:!0});let r=await J.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
239
+ `).includes(s));o.length&&await J.appendFile(n,(r.endsWith(`
236
240
  `)||!r?"":`
237
241
  `)+o.join(`
238
242
  `)+`
239
- `)}catch{}}async function W4(e,t){try{let n=await A_(e),r=await te.readFile(n,"utf8"),o=r.split(`
243
+ `)}catch{}}async function iI(e,t){try{let n=await aI(e),r=await J.readFile(n,"utf8"),o=r.split(`
240
244
  `).filter(s=>s!==t);o.length!==r.split(`
241
- `).length&&await te.writeFile(n,o.join(`
242
- `))}catch{}}async function og(){let e={refreshed:0,removed:0,codexGlobal:null};try{await te.mkdir(Hn,{recursive:!0}),await te.writeFile(oe.join(Hn,"CLAUDE.md"),L4).catch(()=>{}),await te.writeFile(oe.join(Hn,"AGENTS.md"),wc).catch(()=>{});let t=process.env.CODEX_HOME||oe.join(process.env.HOME||"/tmp",".codex");if((await te.stat(t).catch(()=>null))?.isDirectory()){let r=oe.join(t,"AGENTS.md"),o=await te.readFile(r,"utf8").catch(()=>null);o===null?(await te.writeFile(r,Mw,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):Ow(o)&&o!==Mw&&(await te.writeFile(r,Mw).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[gc,va]){let o=await te.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=oe.join(r,s.name),i=oe.join(a,"AGENTS.md"),c=await te.readFile(i,"utf8").catch(()=>null);c!==null&&Ow(c)&&c!==wc&&(await te.writeFile(i,wc).catch(()=>{}),e.refreshed++);let l=oe.join(a,"CLAUDE.md"),u=await te.readFile(l,"utf8").catch(()=>null);u!==null&&Ow(u)&&(await te.rm(l,{force:!0}).catch(()=>{}),await W4(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function E_(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of $t(t))n.base&&n.dir&&await Mt(n.base,n.dir).catch(()=>{});await te.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await Mt(t.base,t.dir):await te.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function Md({name:e,cwd:t,repo:n,repos:r,agent:o="claude",model:s=null,skipPermissions:a=!0}){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");let i=await Ec(o,a,s),c=await ee(),l=Ad().slice(0,8),u=await j4(l,e,{repo:n,repos:r,cwd:t}),d=new Set(c.tracks.flatMap(m=>(m.boxes||[]).map(g=>g.name))),p=`${e.trim()} lead`;d.has(Fl(p))&&(p=`${e.trim().slice(0,50).trim()} ${l} lead`);let f=await Or(p,u.dir,{agentCmd:i,agent:o,freshWorkspace:!0}),w={id:l,name:e.trim(),cwd:f.cwd,workspace:u,leadBox:f.name,boxes:[mg(f,"lead","live")],events:[],createdAt:Date.now()};return $e(w,"opened",{agent:o,...s?{model:s}:{},box:f.name,skipPermissions:a,name:w.name,cwd:w.cwd,workspace:{base:u.base??null,branch:u.branch,kind:u.kind,...u.baseRef?{baseRef:u.baseRef}:{},...u.repo?{repo:u.repo}:{},...u.repos?{repos:u.repos.map(({name:m,base:g,baseRef:y,repo:x})=>({name:m,base:g,baseRef:y,repo:x}))}:{}}}),c.tracks.push(w),await ue(),yi({cwd:f.cwd,sessionName:f.name,agent:o,agentCmd:i,onReady:async()=>{let m=w.boxes.find(g=>g.name===w.leadBox);!m||m.readyAt||(m.readyAt=Date.now(),await ue())}}),Pt(w)}async function sg({provider:e="claude",fresh:t=!1}={}){if(!q4.has(e))throw new Error(`unknown setup provider "${e}" (claude | codex | cursor)`);let r=(await ee()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===e&&!u.archivedAt);if(r){if(!t){let u=await Pt(r);if(u.boxes.find(p=>p.name===u.leadBox)?.state==="live")return u}await Zo(r.id).catch(()=>{})}let o=(await Ec(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=Ad().slice(0,8),a=oe.join(Hn,"setup",s);await te.mkdir(a,{recursive:!0});let i=await Or(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&yi({cwd:i.cwd,sessionName:i.name,agent:e,agentCmd:o});let c={id:s,name:`Connect ${e}`,kind:"setup",setup:{provider:e,startedAt:Date.now(),connectedAt:null},cwd:i.cwd,workspace:{dir:a,base:null,branch:null,kind:"scratch"},leadBox:i.name,boxes:[mg(i,"lead","live")],events:[],createdAt:Date.now()};return $e(c,"opened",{agent:e,box:i.name,skipPermissions:!1,trackKind:"setup",name:c.name,cwd:c.cwd,workspace:{base:null,branch:null,kind:"scratch"}}),(await ee()).tracks.push(c),await ue(),Pt(c)}async function ag(e,t,n){await Qp(t.cwd).catch(()=>{}),await jA(e).catch(()=>{});let r=xa.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),xa.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of es(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await Eg(a).catch(()=>{}),Dt.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 ee(),s=new Set((o.tracks||[]).filter(a=>a.id!==e&&!a.archivedAt).flatMap(a=>(a.boxes||[]).map(i=>i.name)));for(let a of t.boxes)s.has(a.name)||await rn(a.name).catch(()=>{})}async function ig(e,{cascadeMocks:t=!0,cascadeRunbooks:n=!1}={}){let r=await ee(),o=r.tracks.findIndex(a=>a.id===e);if(o===-1)throw new Error(`track "${e}" not found`);let s=r.tracks[o];return t||await sE(s),Qw(e),await ag(e,s,"track deleted"),n?await DE(e).catch(()=>{}):await PE(e).catch(()=>{}),await Vv(),await E_(s),t&&await aE(e).catch(()=>{}),t?await SE(e).catch(()=>{}):await vE(s).catch(()=>{}),$e(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await ue(),{ok:!0,id:e,name:s.name,boxes:s.boxes.length}}async function Zo(e){let t=await ee(),n=me(t,e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is already archived`);return n.archivedAt=Date.now(),Qw(e),$e(n,"archived",{boxes:n.boxes.length}),await ue(),n.kind==="setup"?(await __(e),Pt(n)):(vc.add(e),z4(e).catch(()=>{}).finally(()=>vc.delete(e)),{...await Pt(n),archiving:!0})}async function z4(e){try{await V4(e)}catch{}await __(e).catch(()=>{})}async function __(e){let t=await ee(),n=me(t,e);if(!(!n||!n.archivedAt)){await ag(e,n,"track archived");for(let r of n.boxes)so.has(r.state)||(r.state="stopped");await ue()}}async function V4(e){let t=await ee(),n=me(t,e);if(!n||!n.archivedAt)return;let r=null,o=[],s="derived",a=(n.events||[]).some(l=>l.type==="said"),i=n.leadBox?await ke(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await gx(n.leadBox,i.cwd,{timeoutMs:G4})),s="lead-cli"}catch{}if(r||(r=Mx(n,await q(n).catch(()=>[]))),!r)return;let c={text:r,source:s,at:Date.now()};o.length&&(c.items=o),n.beat=c,await M(n,{type:"track.summary.recorded",actor:"orchestrator",source:"orchestrator",boxId:n.leadBox||null,provider:i?.agent||null,payload:o.length?{text:r,items:o,source:s}:{text:r,source:s}}).catch(()=>{}),await ue()}async function ar(e,t){let n=await at(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await cg(n);if(r.length){for(let o of r)await Bo(o.repo,o.number,!0).catch(()=>{});return!1}try{return await Zo(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function cg(e){return(await un().catch(()=>[])).filter(n=>n.trackId===e.trackId&&n.state!=="merged"&&n.state!=="closed"&&n.state!=="lost"&&!(n.repo===e.repo&&n.number===e.number))}async function ir(e,t){return Cd(e,t,"merged")}async function Qo(e,t){let n=await at(e,t).catch(()=>null);if(!n?.trackId)return null;let r={repo:n.repo??null,number:n.number,title:n.title??null,url:n.url??null},o=await cg(n);if(o.length){let c=[...n.followupPending||[],r];for(let l of o)await SS(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=me(await ee(),n.trackId);if(!a)return null;let i=s[0];return Ji(await Pt(a),"pr.merged",{repo:n.repo??a.workspace?.repo??null,prs:s,prNumber:i?.number??null,prTitle:i?.title??null,prUrl:i?.url??null}).catch(()=>null)}async function Cd(e,t,n="merged"){let r=await at(e,t).catch(()=>null);if(!r?.notifyOnMerge||r.archiveOnMerge||!r.trackId)return!1;let o={repo:r.repo??null,number:r.number,title:r.title??null,url:r.url??null,headRef:r.headRef??null,outcome:n},s=await cg(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await vS(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];if(!await hS(r.repo,r.number).catch(()=>!0))return!1;try{return await Bt(r.trackId,I_(a),{kind:"merge-notify"}),!0}catch{return await jo(r.repo,r.number,!0).catch(()=>{}),!1}}function I_(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 ${a_[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 ${a_[i.outcome]??i.outcome}`).join(`
245
+ `).length&&await J.writeFile(n,o.join(`
246
+ `))}catch{}}async function Lg(){let e={refreshed:0,removed:0,codexGlobal:null};try{await J.mkdir(qn,{recursive:!0}),await J.writeFile(z.join(qn,"CLAUDE.md"),T2).catch(()=>{}),await J.writeFile(z.join(qn,"AGENTS.md"),Cc).catch(()=>{});let t=process.env.CODEX_HOME||z.join(process.env.HOME||"/tmp",".codex");if((await J.stat(t).catch(()=>null))?.isDirectory()){let r=z.join(t,"AGENTS.md"),o=await J.readFile(r,"utf8").catch(()=>null);o===null?(await J.writeFile(r,pg,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):Nc(o)&&o!==pg&&(await J.writeFile(r,pg).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[Pc,Pa]){let o=await J.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=z.join(r,s.name),i=z.join(a,"AGENTS.md"),c=await J.readFile(i,"utf8").catch(()=>null);c!==null&&Nc(c)&&c!==Cc&&(await J.writeFile(i,Cc).catch(()=>{}),e.refreshed++);let l=z.join(a,"CLAUDE.md"),u=await J.readFile(l,"utf8").catch(()=>null);u!==null&&Nc(u)&&(await J.rm(l,{force:!0}).catch(()=>{}),await iI(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function cI(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 St(n.base,n.dir).catch(()=>{});await J.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await St(t.base,t.dir):await J.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function cp({name:e,cwd:t,repo:n,repos:r,agent:o="claude",model:s=null,skipPermissions:a=!0}){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");let i=await Da(o,a,s),c=await Z(),l=Xd().slice(0,8),u=await A2(l,e,{repo:n,repos:r,cwd:t}),d=new Set(c.tracks.flatMap(h=>(h.boxes||[]).map(g=>g.name))),p=`${e.trim()} lead`;d.has(iu(p))&&(p=`${e.trim().slice(0,50).trim()} ${l} lead`);let f=await En(p,u.dir,{agentCmd:i,agent:o,freshWorkspace:!0}),w={id:l,name:e.trim(),cwd:f.cwd,workspace:u,leadBox:f.name,boxes:[Jg(f,"lead","live")],events:[],createdAt:Date.now()};return Ae(w,"opened",{agent:o,...s?{model:s}:{},box:f.name,skipPermissions:a,name:w.name,cwd:w.cwd,workspace:{base:u.base??null,branch:u.branch,kind:u.kind,...u.baseRef?{baseRef:u.baseRef}:{},...u.repo?{repo:u.repo}:{},...u.repos?{repos:u.repos.map(({name:h,base:g,baseRef:y,repo:x})=>({name:h,base:g,baseRef:y,repo:x}))}:{}}}),c.tracks.push(w),await se(),Ho({cwd:f.cwd,sessionName:f.name,agent:o,agentCmd:i,onReady:async()=>{let h=w.boxes.find(g=>g.name===w.leadBox);!h||h.readyAt||(h.readyAt=Date.now(),await se())}}),Ut(w)}async function Fg({provider:e="claude",fresh:t=!1}={}){if(!$2.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 Ut(r);if(u.boxes.find(p=>p.name===u.leadBox)?.state==="live")return u}await ws(r.id).catch(()=>{})}let o=(await Da(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=Xd().slice(0,8),a=z.join(qn,"setup",s);await J.mkdir(a,{recursive:!0});let i=await En(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&Ho({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:[Jg(i,"lead","live")],events:[],createdAt:Date.now()};return Ae(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 se(),Ut(c)}async function Ug(e,t,n){await Vl(t.cwd).catch(()=>{}),await Cw(e).catch(()=>{});let r=hs.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),hs.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of ys(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await sy(a).catch(()=>{}),Pt.delete(a.id);for(let a of Object.values(t.subtasks||{}))a.finishedAt||(a.step="error",a.error=n,a.canceled=!0,a.finishedAt=Date.now());let o=await 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 Ot(a.name).catch(()=>{})}async function Hg(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 HE(s),Mg(e),await Ug(e,s,"track deleted"),n?await b_(e).catch(()=>{}):await y_(e).catch(()=>{}),await MS(),await cI(s),t&&await WE(e).catch(()=>{}),t?await a_(e).catch(()=>{}):await s_(s).catch(()=>{}),Ae(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await se(),{ok:!0,id:e,name:s.name,boxes:s.boxes.length}}async function ws(e){let t=await Z(),n=de(t,e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is already archived`);return n.archivedAt=Date.now(),Mg(e),Ae(n,"archived",{boxes:n.boxes.length}),await se(),n.kind==="setup"?(await lI(e),Ut(n)):(Fc.add(e),M2(e).catch(()=>{}).finally(()=>Fc.delete(e)),{...await Ut(n),archiving:!0})}async function M2(e){try{await C2(e)}catch{}await lI(e).catch(()=>{})}async function lI(e){let t=await Z(),n=de(t,e);if(!(!n||!n.archivedAt)){await Ug(e,n,"track archived");for(let r of n.boxes)vr.has(r.state)||(r.state="stopped");await se()}}async function C2(e){let t=await Z(),n=de(t,e);if(!n||!n.archivedAt)return;let r=null,o=[],s="derived",a=(n.events||[]).some(l=>l.type==="said"),i=n.leadBox?await ye(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await tv(n.leadBox,i.cwd,{timeoutMs:O2})),s="lead-cli"}catch{}if(r||(r=wv(n,await K(n).catch(()=>[]))),!r)return;let c={text:r,source:s,at:Date.now()};o.length&&(c.items=o),n.beat=c,await C(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 se()}async function lr(e,t){let n=await ct(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await Wg(n);if(r.length){for(let o of r)await Qo(o.repo,o.number,!0).catch(()=>{});return!1}try{return await ws(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function Wg(e){return(await pn().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 ur(e,t){return lp(e,t,"merged")}async function gs(e,t){let n=await ct(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 Wg(n);if(o.length){let c=[...n.followupPending||[],r];for(let l of o)await iA(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=de(await Z(),n.trackId);if(!a)return null;let i=s[0];return pc(await Ut(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 lp(e,t,n="merged"){let r=await ct(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 Wg(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await aA(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];if(!await QS(r.repo,r.number).catch(()=>!0))return!1;try{return await Ht(r.trackId,uI(a),{kind:"merge-notify"}),!0}catch{return await es(r.repo,r.number,!0).catch(()=>{}),!1}}function uI(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 ${q_[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 ${q_[i.outcome]??i.outcome}`).join(`
243
247
  `),a=n.length?r.length?`This is an automated merge notification: pick up whatever follow-up work the merged PR${n.length===1?"":"s"} unblock${n.length===1?"s":""} \u2014 and note the unmerged one${r.length===1?"":"s"}: that work did NOT land, so check whether it still needs to ship. If nothing needs doing, say so briefly.`:"This is an automated merge notification: pick up whatever follow-up work these merges unblock (dependent tasks, cleanup, next steps that were waiting on them). If nothing needs doing, say so briefly.":"This is an automated notification: NONE of the PRs landed \u2014 the work did not ship. Check whether it still needs to go out another way. If not, say so briefly.";return`${o}
244
248
  ${s}
245
- ${a}`}async function lg(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<li()?!1:Xn(e.name)}async function Sc(e,t,n){return!t||e.archivedAt||so.has(t.state)?!1:(await le({flow:"rehydrate",phase:"resume-dead-cli",trackId:e.id,sessionName:t.name,agent:t.agent,via:n}).catch(()=>{}),console.warn(`[track] ${t.name}: CLI is not running (bare shell) \u2014 relaunching (${n})`),await rn(t.name).catch(()=>{}),t.state="stopped",Oc(e))}async function Oc(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=Cw.get(r.name);if(o)return o;let s=J4(e,r,{freshSession:t,reason:n}).finally(()=>Cw.delete(r.name));return Cw.set(r.name,s),s}async function J4(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||so.has(t.state)||await ke(t.name))return!1;let o=n===!0,s=o?Ad():null,a=o?ii(Uw(t.agent),s,t.name):Hw(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await Ll(a);if(i===Ts)return $e(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===As&&console.warn(`[track] ${t.name}: could not confirm "${t.agent}" on PATH \u2014 relaunching anyway (launch verifier will catch a real miss)`);let c=o?{sessionId:t.sessionId??null,pinned:t.pinned===!0,epochs:JSON.parse(JSON.stringify(ka(t)))}:null,l=Date.now();if(o){let u=ka(t),d=u[u.length-1];d.endedAt==null&&(d.endedAt=l),d.endReason==null&&(d.endReason=r||"fresh-session"),u.push({agent:t.agent,sessionId:s,pinned:t.agent==="claude",startedAt:l,endedAt:null}),t.sessionId=s,t.pinned=t.agent==="claude"}try{let u=await Or(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=Ha(u.hookToken),yi({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a}),t.state="live",o&&$e(e,"lead-refreshed",{box:t.name,agent:t.agent,fromSessionId:c.sessionId,toSessionId:s,epoch:t.epochs.length-1,reason:r||"fresh-session"}),$e(e,"rehydrated",{box:t.name,agent:t.agent,...o?{fresh:!0}:{}}),!0}catch(u){return o&&(t.sessionId=c.sessionId,t.pinned=c.pinned,t.epochs=c.epochs),$e(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function Nd(e,{freshSession:t=!1}={}){let n=await ee(),r=me(n,e);if(!r)throw new Error(`track "${e}" not found`);if(!r.archivedAt)throw new Error(`track "${e}" is not archived`);return delete r.archivedAt,vc.delete(e),$e(r,"unarchived",{}),await Oc(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await ue(),Pt(r)}async function ug(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>Lw)throw new Error(`name too long (max ${Lw} chars)`);let r=await ee(),o=me(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 Pt(o);let s=o.name;return o.name=n,$e(o,"renamed",{from:s,to:n}),await ue(),Pt(o)}async function dg(){let e=await ee(),t=0;for(let n of e.tracks||[])n.transferredTo&&yu(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await ue(),t}async function pg(){let e=await ee(),t=new Set((await nn()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!De(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(De(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await rn(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):$e(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!so.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await ue(),r}async function Pd(e,{freshSession:t=!1}={}){let n=await ee(),r=me(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`);bg(r);let o=r.boxes.find(i=>i.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(so.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await ke(r.leadBox)){let i=await Be(r.leadBox,{lines:Ze}).catch(()=>"");if(gi(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await rn(r.leadBox),o.state="stopped"}let a=await Oc(r,t?{freshSession:!0,reason:"loop-fire"}:{});if(await ue(),!a)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Pt(r)}async function fg(e,t,n){let r=await ie(e);if(!r)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let o=await q(r).catch(()=>[]);if(!o.some(i=>i.type==="box.fullscreen.detected"&&i.payload?.offerId===t))throw new Error("unknown offer");if(o.some(i=>i.type==="box.fullscreen.answered"&&i.payload?.offerId===t))throw new Error("offer already answered");return n&&await Pd(e),await M(r,{type:"box.fullscreen.answered",actor:"user",source:"orchestrator",boxId:r.leadBox,payload:{ts:Date.now(),offerId:t,action:n?"restarted":"dismiss"}}).catch(()=>{}),{ok:!0,action:n?"restarted":"dismiss"}}function i_(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return Ju({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function ka(e){return(!Array.isArray(e.epochs)||e.epochs.length===0)&&(e.epochs=[{agent:e.agent??null,sessionId:e.sessionId??null,pinned:e.pinned===!0,startedAt:e.createdAt??null,endedAt:null}]),e.epochs}async function Td(e,t){let n=await ee(),r=me(n,e);r&&(r.handoff={...r.handoff||{},...t},await ue())}function $_(e,t=Date.now()){let n=e?.handoff;if(!n||n.finishedAt)return null;let r=n.step,o=!!n.toBox&&n.toBox===n.fromBox,s=e.boxes?.find?.(i=>i.name===e.leadBox)||null;return(o?e.leadBox===n.fromBox&&!!n.startedAt&&Array.isArray(s?.epochs)&&s.epochs.some(i=>i.startedAt!=null&&i.startedAt>=n.startedAt):!!n.toBox&&e.leadBox===n.toBox)?{...n,step:"done",finishedAt:t,recovered:`committed before restart (was "${r}")`}:{...n,step:"error",finishedAt:t,error:`interrupted by an agent restart during "${r}"; lead "${e.leadBox}" retained \u2014 retry the handoff`,recovered:"rolled-back"}}async function hg(){let e=await ee(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=$_(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await ke(r.fromBox).catch(()=>null),l=n.boxes.find(u=>u.name===r.fromBox);if(c&&l&&c.agent===r.toAgent&&r.toAgent!==l.agent){let u=Date.now(),d=ka(l),p=d[d.length-1],f=p.agent,w=p.sessionId??null;p.endedAt=u,r.reason&&(p.endReason=r.reason);let m=c.agent==="claude"&&!!c.sessionId;d.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:m,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.sessionId=c.sessionId||null,l.pinned=m,l.state="live",n.pendingHandoffHydrate={artifact:Yo,at:u},$e(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:f,toAgent:r.toAgent,fromSessionId:w,toSessionId:c.sessionId||null,epoch:d.length-1,singleBox:!0,skipPermissions:r.skipPermissions,reason:r.reason??null,handoffStartedAt:r.startedAt,recovered:!0}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await le({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 le({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await rn(i).catch(()=>{}),a&&await rn(a).catch(()=>{})}return t&&await ue(),t}async function Dd(e,t,n=!0,r=null){let o=xa.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=me(await ee(),e);if(!s)throw new Error(`track "${e}" not found`);$c(e,"handoff");let a=await Ec(t,n),i=Po(t);if(i){let u=new Error(`can't hand off to ${t} \u2014 its ${i.window} spend limit is reached ($${i.spentUsd.toFixed(2)} of $${i.limitUsd.toFixed(2)})`);throw u.usageCap=i,u}let c=await ke(s.leadBox);if(!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l={trackId:e,step:"checkpoint",fromBox:s.leadBox,toAgent:t,skipPermissions:n,reason:m_(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return xa.set(e,l),await Td(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),Y4(l,s,c,a,t).catch(async u=>{l.error=u?.message||String(u),l.finishedAt=Date.now(),console.error(`[lead-handoff ${e}] FAILED at step "${l.step}": ${l.error}`),await Td(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),le({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),le({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function Y4(e,t,n,r,o){let s=async(I,C={})=>{e.step=I,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${I}`),await Td(e.trackId,{step:I,toBox:e.toBox}),await le({flow:"lead-handoff",phase:I,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:C.sessionName,...C})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await ee(),i=me(a,e.trackId)?.boxes.find(I=>I.name===e.fromBox)||null,c=i?.agent||n.agent,l=i?.sessionId??n.sessionId??null,u=i?.pinned===!0;if(await s("checkpoint",{sessionName:e.fromBox}),e.checkpoint="llm",Po(c))e.checkpoint="skipped-capped";else try{await tm(e.fromBox,{timeoutMs:p_})}catch(I){e.checkpoint="reconstructed",await le({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:I?.message||String(I)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await nm(e.trackId,n.cwd,{trackName:t.name||t.id}).catch(()=>null),await s("checkpoint-degraded",{sessionName:e.fromBox,checkpoint:e.checkpoint,statusArtifact:e.statusArtifact})),await s("swap",{cwd:n.cwd,agentCmd:r});let p=await lm(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let f=h0(p.launchCmd);await Cr({cwd:n.cwd,sessionId:p.sessionId,sessionName:e.fromBox,agent:o,agentCmd:Sa(o),launchEcho:f}).catch(I=>{if(I?.code!=="cli-not-running")throw I});let w=jf(await Be(e.fromBox,{lines:Ze}).catch(()=>""),f);if(!Ns(o,w)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let I=Hw(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await lm(e.fromBox,{agentCmd:I,agent:c,resumeSessionId:l,pinned:u});let C=await ee(),U=me(C,e.trackId);if(U){let H=U.boxes.find(_=>_.name===e.fromBox);H&&(H.state="live"),$e(U,"lead-handoff-failed",{box:e.fromBox,fromAgent:c,toAgent:o,reason:e.reason,error:`incoming ${o} CLI never drew its composer`,rolledBack:!0,handoffStartedAt:e.startedAt}),await ue()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let m=await ee(),g=me(m,e.trackId);if(!g)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let y=g.boxes.find(I=>I.name===e.fromBox);if(!y)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let x=Date.now(),b=ka(y),O=b[b.length-1];O.endedAt=x,e.reason&&(O.endReason=e.reason),b.push({agent:o,sessionId:p.sessionId,pinned:p.pinned,startedAt:x,endedAt:null}),y.agent=o,y.sessionId=p.sessionId,y.pinned=p.pinned,y.state="live",y.role="lead",g.pendingHandoffHydrate={artifact:e.statusArtifact||Yo,at:x},$e(g,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:p.sessionId,epoch:b.length-1,singleBox:!0,forced:p.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint}),await ue(),await s("done",{sessionName:e.fromBox}),await Td(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function yg(e){let t=Fw.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await ee(),r=me(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 restore it before moving it");if(r.kind==="setup")throw new Error("setup boxes don't move");if(r.transferredTo)throw new Error(`track already transferred to ${r.transferredTo}`);let o=xa.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Dt.values())if(a.trackId===e&&!a.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before moving");let s={trackId:e,step:"checkpoint",startedAt:Date.now(),finishedAt:null,error:null};return Fw.set(e,s),X4(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 X4(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await ke(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&Po(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await tm(t.leadBox,{timeoutMs:p_})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await nm(t.id,t.cwd,{trackName:t.name||t.id}).catch(()=>null),e.step="push";let o=t.workspace?.branch??null,s=[];if(o)for(let u of $t(t.workspace)){if(!u?.dir)continue;let d={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await mn(u.dir,["push","origin",o],wg);let{stdout:p}=await mn(u.dir,["rev-parse","HEAD"]);d.baseSha=p.trim(),d.pushed=!0}catch(p){d.error=String(p?.message||p).split(`
246
- `)[0]}s.push(d)}e.step="wip";let a=await bw(t,{force:!0}),i=await ee(),c=me(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&ka(l),await ue(),e.result={name:c?.name??t.name,agent:l?.agent??null,leadBox:c?.leadBox??t.leadBox,createdAt:c?.createdAt??null,branch:o,repos:s.filter(u=>u.pushed).map(({name:u,repo:d,baseSha:p})=>({name:u,repo:d,baseSha:p})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:d,error:p})=>({name:u,repo:d,error:p})),wip:a.pushed[0]?{ref:a.pushed[0].ref,sha:a.pushed[0].sha}:null,wips:a.pushed,wipSkipped:a.skipped,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function bg(e){if(!e?.transferredTo)return;let t=new Error(`track "${e.id}" moved to node ${e.transferredTo} \u2014 drive it there`);throw t.transferredTo=e.transferredTo,t}async function Bd(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await ee(),o=me(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};Qw(e),await ag(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();yu(o,{at:s,reason:n==="recover"?"node-offline":"node-transfer"});let a=await kw(o,{ts:s}),i=a.pushed[0]??null;return o.transferredTo=t,o.transferredAt=s,$e(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...i?{rescueRef:i.ref,rescueSha:i.sha}:{},...a.pushed.length?{rescues:a.pushed}:{}}),await ue(),{ok:!0,toNode:t,rescue:i?{ref:i.ref,sha:i.sha}:null,rescues:a.pushed}}async function kg(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await Bd(n.id,{toNode:n.toNode,mode:n.mode==="recover"?"recover":"transfer"});t.push({id:n.id,...r})}catch(r){/not found/i.test(String(r?.message))||console.error(`[transfer] demote of ${n.id} failed: ${r?.message||r}`)}return t}async function c_(e,t,n){try{await wu(e,t,n)}catch{await mn(e,["worktree","prune"]).catch(()=>{}),await wu(e,t,n)}return t}function Z4(e,{wip:t=null,wips:n=null}={}){let r=$t(e).filter(a=>a?.dir),o=Array.isArray(n)?n.filter(a=>a?.sha):[];if(!o.length)return t?.sha&&r.length===1?r:[];let s=r.filter(a=>o.some(i=>i.repo?i.repo===a.repo:i.name!=null&&i.name===a.name));return!s.length&&r.length===1&&o.length===1?r:s}async function Q4(e,t){try{await mn(e,["fetch","origin",yw(t)],wg);let{stdout:n}=await mn(e,["rev-parse","FETCH_HEAD^"]),{stdout:r}=await mn(e,["rev-parse","HEAD"]),o=null,s=n.trim()===r.trim();return s||await mn(e,["merge-base","--is-ancestor",r.trim(),n.trim()]).then(()=>!0,()=>!1)&&(await mn(e,["reset","--hard",n.trim()]),o={from:r.trim(),to:n.trim()},s=!0),s?(await mn(e,["read-tree","--reset","-u","FETCH_HEAD"]),await mn(e,["reset","-q"]),{applied:!0,skipped:null,advanced:o}):{applied:!1,skipped:"snapshot does not parent the fetched branch head",advanced:null}}catch(n){return{applied:!1,skipped:String(n?.message||n).split(`
247
- `)[0],advanced:null}}}function t2(e){if(typeof e!="string"||!e2.test(e)||e.includes("..")||e.includes("@{")||e.endsWith(".lock"))throw new Error("branch fails the safe-ref check")}async function xg(e={}){let{trackId:t,name:n,agent:r="claude",skipPermissions:o=!0,mode:s="transfer"}=e;if(!t||typeof t!="string"||!/^[0-9a-f]{8}$/.test(t))throw new Error("trackId (8-hex string) required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");if(s!=="transfer"&&s!=="recover")throw new Error(`unknown adopt mode "${s}"`);if(e.branch!=null&&t2(e.branch),Nw.has(t))throw new Error("an adopt is already running for this Track");Nw.set(t,{startedAt:Date.now()});try{return await n2({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{Nw.delete(t)}}async function n2({trackId:e,name:t,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,wips:u=null,brief:d=null,epochs:p=[],createdAt:f=null,leadBox:w=null,reason:m=null,downSince:g=null}){let y=await Ec(n,r),x=await ee(),b=me(x,e);if(b&&!b.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);b&&(await kw(b).catch(()=>{}),await E_(b),x.tracks.splice(x.tracks.indexOf(b),1),await ue()),await te.mkdir(gc,{recursive:!0});let O=oe.join(gc,e);await te.rm(O,{recursive:!0,force:!0}).catch(()=>{});let I=null,C=!1,U=[];try{let H=[];if(i)for(let J of Array.isArray(c)?c:[]){let z=typeof J=="string"?J:J?.repo;if(!z||!/^[^/\s]+\/[^/\s]+$/.test(z))continue;let se=await ws(z)??await bl(z);await mn(se,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],wg),H.push({slug:z,base:se,name:typeof J=="object"?J?.name??null:null})}if(i&&H.length===1){let{base:J,slug:z}=H[0];await c_(J,O,i),U.push({base:J,dir:O}),await xc(O);let se=await Gs(J);I={dir:O,base:J,branch:i,kind:"worktree",baseRef:se,repo:z}}else if(i&&H.length>=2){await te.mkdir(O,{recursive:!0});let J=new Set([".bostrat"]),z=[];for(let se of H){let ve=se.name||oe.basename(se.base);J.has(ve)&&(ve=se.slug.replace("/","-"));for(let D=2;J.has(ve);D++)ve=`${oe.basename(se.base)}-${D}`;J.add(ve);let Ne=oe.join(O,ve);await c_(se.base,Ne,i),U.push({base:se.base,dir:Ne});let R=await Gs(se.base);z.push({name:ve,dir:Ne,base:se.base,baseRef:R,repo:se.slug})}await Rc(O,z,i),I={dir:O,kind:"multi",branch:i,repos:z}}else C=!0,await te.mkdir(O,{recursive:!0}),await Cm(O),await xc(O),I={dir:O,base:null,branch:null,kind:"repo"};let _=[];for(let J of Z4(I,{wip:l,wips:u})){let z=await Q4(J.dir,e);_.push({name:J.name,repo:J.repo,applied:z.applied,skipped:z.skipped,...z.advanced?{advanced:z.advanced}:{}})}let $=_.some(J=>J.applied),L=_.length===1?_[0].skipped:_.filter(J=>J.skipped).map(J=>`${J.name??J.repo}: ${J.skipped}`).join("; ")||null,V=_.length===1?_[0].advanced??null:null;await JE({id:e,cwd:O}).catch(()=>({restored:!1}));let S=oe.join(O,Yo),E=null;(await Ml(O)).restored?E="checkpoint":typeof d=="string"&&d.trim()&&(await te.mkdir(oe.dirname(S),{recursive:!0}),await te.writeFile(S,d),E="brief");let W=new Set(x.tracks.flatMap(J=>(J.boxes||[]).map(z=>z.name))),G=null;w&&!W.has(w)&&!await ke(w).catch(()=>null)?G=w:(G=`${t.trim()} lead`,W.has(Fl(G))&&(G=`${t.trim().slice(0,50).trim()} ${e} lead`));let ae=await Or(G,O,{agentCmd:y,agent:n});yi({cwd:ae.cwd,sessionName:ae.name,agent:n,agentCmd:y});let we=Date.now(),Re=mg(ae,"lead","live"),Ae=(Array.isArray(p)?p:[]).filter(J=>J&&typeof J=="object").map(J=>({...J})),Y=Ae[Ae.length-1];Y&&Y.endedAt==null&&(Y.endedAt=we,Y.endReason==null&&(Y.endReason=o==="recover"?"node-offline":"node-transfer")),Ae.push({agent:n,sessionId:ae.sessionId??null,pinned:ae.pinned===!0,startedAt:we,endedAt:null}),Re.epochs=Ae;let ye={id:e,name:t.trim(),cwd:ae.cwd,workspace:I,leadBox:ae.name,boxes:[Re],events:[],createdAt:Number.isFinite(f)?f:we,...E?{pendingHandoffHydrate:{artifact:Yo,at:we}}:{}};return $e(ye,"transferred-in",{box:ae.name,agent:n,fromNode:s,toNode:a,mode:o,reason:m,...o==="recover"?{downSince:Number.isFinite(g)?g:null}:{},branch:I.branch??null,wip:$,...V?{wipAdvanced:V}:{},...I.kind==="multi"&&_.length?{wipRepos:_}:{},epoch:Ae.length-1,name:ye.name,cwd:ye.cwd,workspace:{base:I.base??null,branch:I.branch??null,kind:I.kind,...I.baseRef?{baseRef:I.baseRef}:{},...I.repo?{repo:I.repo}:{},...I.repos?{repos:I.repos.map(({name:J,base:z,baseRef:se,repo:ve})=>({name:J,base:z,baseRef:se,repo:ve}))}:{}}}),x.tracks.push(ye),await ue(),{...await Pt(ye),adopt:{wipApplied:$,wipSkipped:L,...V?{wipAdvanced:V}:{},...I.kind==="multi"?{wipRepos:_}:{},codeless:C,artifactSource:E}}}catch(H){for(let _ of U)await Mt(_.base,_.dir).catch(()=>{});throw await te.rm(O,{recursive:!0,force:!0}).catch(()=>{}),H}}async function R_(e,t,n){let r=await ee(),o=me(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await ue())}async function ha(e,t){e.step=t,await Mc(e)}function O_(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 M_(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function a2(e,t,n){if(!M_(n)||Dt.has(t)||!await ke(n.box).catch(()=>null))return!1;try{await te.access(n.dir)}catch{return!1}let o=await ke(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return Dt.set(t,s),N_(s,o).catch(a=>C_(s,a)),!0}async function vg(){let e=await ee(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Dt.has(r))continue;if(await a2(n,r,o)){t=!0,$e(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await le({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=O_(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!so.has(i.state)&&(i.state="canceled"),$e(n,"subtask-failed",{from:o.box,fromAgent:o.agent,task:o.task,subtaskId:r,failedStep:s,error:a.error,recovered:a.recovered,durationMs:o.startedAt?a.finishedAt-o.startedAt:null}),await le({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await l_(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||so.has(r.state)||Dt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?oe.join(va,`${n.id}-${r.subtaskId}`):null;await le({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await l_(n,r.name,o)}}return t=await i2(e)||t,t&&await ue(),t}async function l_(e,t,n){if(t&&await rn(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of $t(e.workspace)){let s=oe.join(n,o.name);await Mt(o.base,s).then(()=>!0,()=>!1)||await Mt(o.dir,s).catch(()=>{})}await te.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await ke(e.leadBox).catch(()=>null);r?.cwd&&await Mt(r.cwd,n).catch(()=>{})}async function i2(e){let t;try{t=await te.readdir(va)}catch{return!1}let n=new Set;for(let o of e.tracks||[]){for(let s of Object.keys(o.subtasks||{}))n.add(`${o.id}-${s}`);for(let s of o.boxes||[])s.subtaskId&&n.add(`${o.id}-${s.subtaskId}`)}for(let o of Dt.values())o.dir&&n.add(oe.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=oe.join(va,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of $t(a.workspace))await Mt(i.base,oe.join(s,i.name)).catch(()=>{});await te.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await ke(a.leadBox).catch(()=>null):null;i?.cwd?await Mt(i.cwd,s).catch(()=>{}):await te.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await le({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function Tg(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!Hs(n))throw new Error("task (string) required");let s=await Ec(t,r),a=Po(t);if(a){let f=new Error(`can't delegate to ${t} \u2014 its ${a.window} spend limit is reached ($${a.spentUsd.toFixed(2)} of $${a.limitUsd.toFixed(2)})`);throw f.usageCap=a,f}let i=me(await ee(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await ke(i.leadBox);if(!c)throw new Error(`lead box "${i.leadBox}" is not running`);if(!c.cwd)throw new Error("can't resolve the lead's working directory");let l=i.workspace?.kind==="multi",u=null;if(l){let f=$t(i.workspace);if(!f.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let w of f)if(!w?.dir||!await Ws(w.dir))throw new Error(`tagged checkout "${w?.name??"?"}" is missing from the lead workspace (${w?.dir??"no dir"})`);u=f.map(w=>({name:w.name,leadDir:w.dir,base:null}))}else if(!await Ws(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=Ad().slice(0,8),p={id:d,trackId:e,trackName:i.name,agent:t,task:Hs(n),skipPermissions:r,reason:m_(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${Sg(i.name)}-${d}`,base:null,repos:u,dir:oe.join(va,`${e}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Dt.set(d,p),await Mc(p),c2(p,c,s).catch(f=>C_(p,f)),p}async function C_(e,t){e.failedStep=e.step,e.error=t instanceof Tc?"canceled":t?.message||String(t),e.step=t instanceof Tc?"canceled":"error",e.finishedAt=Date.now(),await Eg(e).catch(()=>{}),await Mc(e).catch(()=>{}),await p2(e).catch(()=>{})}function Ld(e){let t=Dt.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 Ag(e){let t=Dt.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 c2(e,t,n){if(await ha(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await qs(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await Mc(e)}else e.base=await qs(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await ha(e,"spawn"),await te.mkdir(va,{recursive:!0}),e.repos){await te.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await Ks(a.leadDir,oe.join(e.dir,a.name),e.branch,a.base);let s=$t((me(await ee(),e.trackId)||{}).workspace);await Rc(e.dir,e.repos.map(a=>{let i=s.find(c=>c?.name===a.name);return{name:a.name,repo:i?.repo??null,baseRef:null}}),e.branch)}else await Ks(t.cwd,e.dir,e.branch,e.base),await xc(e.dir);await l2(e,t);let r=e.trackName.slice(0,38).trim(),o=await Or(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await u2(e,o),await h_(e.trackId,o.name,QU(e.task,!!e.repos),{kind:"subtask"}),await N_(e,t)}async function N_(e,t){await ha(e,"working");let n=oe.join(e.dir,Sd);if(await m2(n,e),e.canceled)throw new Tc;if(await ha(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=oe.join(e.dir,l.name);await Mm(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:i_({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await Pm(l.leadDir,l.base,e.branch,ma),l.files=await Dm(l.leadDir,l.base,e.branch,ma);let d=await Bm(l.leadDir,l.base,e.branch,ma);l.applied=d.applied,l.conflicts=d.conflicts??[],s.files+=l.stat.files,s.insertions+=l.stat.insertions,s.deletions+=l.stat.deletions,a.push(...l.files.map(p=>oe.join(l.name,p))),i.push(...l.conflicts.map(p=>p.startsWith("patch did not apply cleanly")?`${l.name}: ${p}`:oe.join(l.name,p))),d.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await Mm(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:i_({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await Pm(t.cwd,e.base,e.branch,ma),e.files=await Dm(t.cwd,e.base,e.branch,ma);let s=await Bm(t.cwd,e.base,e.branch,ma);e.applied=s.applied,e.conflicts=s.conflicts}await Mc(e);let r=await f2(e,t,n);await ha(e,"resume"),await h_(e.trackId,e.leadBox,e4(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await ha(e,"reap"),await Eg(e),e.step="done";let o=Date.now();await R_(e.trackId,e.id,{...jd(e),finishedAt:o}),await d2(e,o),e.finishedAt=o}async function l2(e,t){let n=oe.join(e.dir,oe.dirname(yc));await te.mkdir(n,{recursive:!0});let r="";try{r=await Zk(t.cwd,t.sessionId)}catch{}if(!r)try{r=await te.readFile(oe.join(t.cwd,".bostrat/handoff/latest.md"),"utf8")}catch{r="_(no prior conversation digest available \u2014 rely on the working tree.)_"}let o=`# Lead context for subtask ${e.id}
249
+ ${a}`}async function qg(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<Ii()?!1:Qn(e.name)}async function Uc(e,t,n){return!t||e.archivedAt||vr.has(t.state)?!1:(await ue({flow:"rehydrate",phase:"resume-dead-cli",trackId:e.id,sessionName:t.name,agent:t.agent,via:n}).catch(()=>{}),console.warn(`[track] ${t.name}: CLI is not running (bare shell) \u2014 relaunching (${n})`),await Ot(t.name).catch(()=>{}),t.state="stopped",zc(e))}async function zc(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=fg.get(r.name);if(o)return o;let s=N2(e,r,{freshSession:t,reason:n}).finally(()=>fg.delete(r.name));return fg.set(r.name,s),s}async function N2(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||vr.has(t.state)||await ye(t.name))return!1;let o=n===!0,s=o?Xd():null,a=o?Ei(kg(t.agent),s,t.name):ep(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await au(a);if(i===Hs)return Ae(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===Ws&&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(fs(t)))}:null,l=Date.now();if(o){let u=fs(t),d=u[u.length-1];d.endedAt==null&&(d.endedAt=l),d.endReason==null&&(d.endReason=r||"fresh-session"),u.push({agent:t.agent,sessionId:s,pinned:t.agent==="claude",startedAt:l,endedAt:null}),t.sessionId=s,t.pinned=t.agent==="claude"}try{let u=await En(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=$o(u.hookToken),Ho({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a}),t.state="live",o&&Ae(e,"lead-refreshed",{box:t.name,agent:t.agent,fromSessionId:c.sessionId,toSessionId:s,epoch:t.epochs.length-1,reason:r||"fresh-session"}),Ae(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),Ae(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function up(e,{freshSession:t=!1}={}){let n=await Z(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);if(!r.archivedAt)throw new Error(`track "${e}" is not archived`);return delete r.archivedAt,Fc.delete(e),Ae(r,"unarchived",{}),await zc(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await se(),Ut(r)}async function Kg(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>bg)throw new Error(`name too long (max ${bg} chars)`);let r=await Z(),o=de(r,e);if(!o)throw new Error(`track "${e}" not found`);if(String(o.name||"").startsWith("\u21BB"))throw new Error("loop run Tracks are named by their loop \u2014 rename the loop on the Loops tab");if(n===o.name)return Ut(o);let s=o.name;return o.name=n,Ae(o,"renamed",{from:s,to:n}),await se(),Ut(o)}async function Gg(){let e=await Z(),t=0;for(let n of e.tracks||[])n.transferredTo&&Fu(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await se(),t}async function zg(){let e=await Z(),t=new Set((await sn()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!je(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(je(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await Ot(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):Ae(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!vr.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await se(),r}async function dp(e,{freshSession:t=!1}={}){let n=await Z(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before restarting the lead`);fp(r);let o=r.boxes.find(i=>i.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(vr.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await ye(r.leadBox)){let i=await Pe(r.leadBox,{lines:Ye}).catch(()=>"");if(Di(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await Ot(r.leadBox),o.state="stopped"}let a=await zc(r,t?{freshSession:!0,reason:"loop-fire"}:{});if(await se(),!a)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Ut(r)}async function Vg(e,t,n){let r=await ie(e);if(!r)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let o=await K(r).catch(()=>[]);if(!o.some(i=>i.type==="box.fullscreen.detected"&&i.payload?.offerId===t))throw new Error("unknown offer");if(o.some(i=>i.type==="box.fullscreen.answered"&&i.payload?.offerId===t))throw new Error("offer already answered");return n&&await dp(e),await C(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 K_(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return gd({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function fs(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 Jd(e,t){let n=await Z(),r=de(n,e);r&&(r.handoff={...r.handoff||{},...t},await se())}function dI(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 Yg(){let e=await Z(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=dI(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await ye(r.fromBox).catch(()=>null),l=n.boxes.find(u=>u.name===r.fromBox);if(c&&l&&c.agent===r.toAgent&&r.toAgent!==l.agent){let u=Date.now(),d=fs(l),p=d[d.length-1],f=p.agent,w=p.sessionId??null;p.endedAt=u,r.reason&&(p.endReason=r.reason);let h=c.agent==="claude"&&!!c.sessionId;d.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:h,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.sessionId=c.sessionId||null,l.pinned=h,l.state="live",n.pendingHandoffHydrate={artifact:ho,at:u},Ae(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:f,toAgent:r.toAgent,fromSessionId:w,toSessionId:c.sessionId||null,epoch:d.length-1,singleBox:!0,skipPermissions:r.skipPermissions,reason:r.reason??null,handoffStartedAt:r.startedAt,recovered:!0}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await ue({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:"done",recovered:n.handoff.recovered,fromBox:r.fromBox,toBox:r.toBox}).catch(()=>{});continue}}let a=!s&&o.recovered==="rolled-back"&&r.toBox&&r.toBox!==n.leadBox?r.toBox:null,i=!s&&o.step==="done"?r.fromBox:null;n.handoff=o,await ue({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await Ot(i).catch(()=>{}),a&&await Ot(a).catch(()=>{})}return t&&await se(),t}async function pp(e,t,n=!0,r=null){let o=hs.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=de(await Z(),e);if(!s)throw new Error(`track "${e}" not found`);Ba(e,"handoff");let a=await Da(t,n),i=Zr(t);if(i){let u=new Error(`can't hand off to ${t} \u2014 its ${i.window} spend limit is reached ($${i.spentUsd.toFixed(2)} of $${i.limitUsd.toFixed(2)})`);throw u.usageCap=i,u}let c=await ye(s.leadBox);if(!c)throw new Error(`lead box "${s.leadBox}" is not running`);let l={trackId:e,step:"checkpoint",fromBox:s.leadBox,toAgent:t,skipPermissions:n,reason:Y_(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return hs.set(e,l),await Jd(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),P2(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 Jd(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),ue({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),ue({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function P2(e,t,n,r,o){let s=async(_,N={})=>{e.step=_,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${_}`),await Jd(e.trackId,{step:_,toBox:e.toBox}),await ue({flow:"lead-handoff",phase:_,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:N.sessionName,...N})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await Z(),i=de(a,e.trackId)?.boxes.find(_=>_.name===e.fromBox)||null,c=i?.agent||n.agent,l=i?.sessionId??n.sessionId??null,u=i?.pinned===!0;if(await s("checkpoint",{sessionName:e.fromBox}),e.checkpoint="llm",Zr(c))e.checkpoint="skipped-capped";else try{await Ru(e.fromBox,{timeoutMs:xg})}catch(_){e.checkpoint="reconstructed",await ue({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:_?.message||String(_)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await Ou(e.trackId,n.cwd,{trackName:t.name||t.id}).catch(()=>null),await s("checkpoint-degraded",{sessionName:e.fromBox,checkpoint:e.checkpoint,statusArtifact:e.statusArtifact})),await s("swap",{cwd:n.cwd,agentCmd:r});let p=await Hh(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let f=Q0(p.launchCmd);await er({cwd:n.cwd,sessionId:p.sessionId,sessionName:e.fromBox,agent:o,agentCmd:ms(o),launchEcho:f}).catch(_=>{if(_?.code!=="cli-not-running")throw _});let w=yh(await Pe(e.fromBox,{lines:Ye}).catch(()=>""),f);if(!Uo(o,w)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let _=ep(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await Hh(e.fromBox,{agentCmd:_,agent:c,resumeSessionId:l,pinned:u});let N=await Z(),U=de(N,e.trackId);if(U){let j=U.boxes.find(T=>T.name===e.fromBox);j&&(j.state="live"),Ae(U,"lead-handoff-failed",{box:e.fromBox,fromAgent:c,toAgent:o,reason:e.reason,error:`incoming ${o} CLI never drew its composer`,rolledBack:!0,handoffStartedAt:e.startedAt}),await se()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let h=await Z(),g=de(h,e.trackId);if(!g)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let y=g.boxes.find(_=>_.name===e.fromBox);if(!y)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let x=Date.now(),b=fs(y),I=b[b.length-1];I.endedAt=x,e.reason&&(I.endReason=e.reason),b.push({agent:o,sessionId:p.sessionId,pinned:p.pinned,startedAt:x,endedAt:null}),y.agent=o,y.sessionId=p.sessionId,y.pinned=p.pinned,y.state="live",y.role="lead",g.pendingHandoffHydrate={artifact:e.statusArtifact||ho,at:x},Ae(g,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:p.sessionId,epoch:b.length-1,singleBox:!0,forced:p.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint}),await se(),await s("done",{sessionName:e.fromBox}),await Jd(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function Qg(e){let t=Yd.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await Z(),r=de(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 restore it before moving it");if(r.kind==="setup")throw new Error("setup boxes don't move");if(r.transferredTo)throw new Error(`track already transferred to ${r.transferredTo}`);let o=hs.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Pt.values())if(a.trackId===e&&!a.finishedAt)throw new Error("a subtask is still running on this Track \u2014 wait for it to merge back before moving");let s={trackId:e,step:"checkpoint",startedAt:Date.now(),finishedAt:null,error:null};return Yd.set(e,s),D2(s,r).catch(a=>{s.error=a?.message||String(a),s.finishedAt=Date.now(),console.error(`[transfer-out ${e}] FAILED at step "${s.step}": ${s.error}`)}),s}async function D2(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await ye(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&Zr(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await Ru(t.leadBox,{timeoutMs:xg})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await Ou(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 d={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await gn(u.dir,["push","origin",o],Xg);let{stdout:p}=await gn(u.dir,["rev-parse","HEAD"]);d.baseSha=p.trim(),d.pushed=!0}catch(p){d.error=String(p?.message||p).split(`
250
+ `)[0]}s.push(d)}e.step="wip";let a=await eg(t,{force:!0}),i=await Z(),c=de(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&fs(l),await se(),e.result={name:c?.name??t.name,agent:l?.agent??null,leadBox:c?.leadBox??t.leadBox,createdAt:c?.createdAt??null,branch:o,repos:s.filter(u=>u.pushed).map(({name:u,repo:d,baseSha:p})=>({name:u,repo:d,baseSha:p})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:d,error:p})=>({name:u,repo:d,error:p})),wip:a.pushed[0]?{ref:a.pushed[0].ref,sha:a.pushed[0].sha}:null,wips:a.pushed,wipSkipped:a.skipped,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function fp(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 hp(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await Z(),o=de(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};Mg(e),await Ug(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();Fu(o,{at:s,reason:n==="recover"?"node-offline":"node-transfer"});let a=await tg(o,{ts:s}),i=a.pushed[0]??null;return o.transferredTo=t,o.transferredAt=s,Ae(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...i?{rescueRef:i.ref,rescueSha:i.sha}:{},...a.pushed.length?{rescues:a.pushed}:{}}),await se(),{ok:!0,toNode:t,rescue:i?{ref:i.ref,sha:i.sha}:null,rescues:a.pushed}}async function ey(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await hp(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 G_(e,t,n){try{await Ji(e,t,n)}catch{await gn(e,["worktree","prune"]).catch(()=>{}),await Ji(e,t,n)}return t}function B2(e,{wip:t=null,wips:n=null}={}){let r=Dt(e).filter(a=>a?.dir),o=Array.isArray(n)?n.filter(a=>a?.sha):[];if(!o.length)return t?.sha&&r.length===1?r:[];let s=r.filter(a=>o.some(i=>i.repo?i.repo===a.repo:i.name!=null&&i.name===a.name));return!s.length&&r.length===1&&o.length===1?r:s}async function j2(e,t){try{await gn(e,["fetch","origin",Qw(t)],Xg);let{stdout:n}=await gn(e,["rev-parse","FETCH_HEAD^"]),{stdout:r}=await gn(e,["rev-parse","HEAD"]),o=null,s=n.trim()===r.trim();return s||await gn(e,["merge-base","--is-ancestor",r.trim(),n.trim()]).then(()=>!0,()=>!1)&&(await gn(e,["reset","--hard",n.trim()]),o={from:r.trim(),to:n.trim()},s=!0),s?(await gn(e,["read-tree","--reset","-u","FETCH_HEAD"]),await gn(e,["reset","-q"]),{applied:!0,skipped:null,advanced:o}):{applied:!1,skipped:"snapshot does not parent the fetched branch head",advanced:null}}catch(n){return{applied:!1,skipped:String(n?.message||n).split(`
251
+ `)[0],advanced:null}}}function F2(e){if(typeof e!="string"||!L2.test(e)||e.includes("..")||e.includes("@{")||e.endsWith(".lock"))throw new Error("branch fails the safe-ref check")}async function ty(e={}){let{trackId:t,name:n,agent:r="claude",skipPermissions:o=!0,mode:s="transfer"}=e;if(!t||typeof t!="string"||!/^[0-9a-f]{8}$/.test(t))throw new Error("trackId (8-hex string) required");if(typeof n!="string"||!n.trim())throw new Error("name (string) required");if(s!=="transfer"&&s!=="recover")throw new Error(`unknown adopt mode "${s}"`);if(e.branch!=null&&F2(e.branch),Kd.has(t))throw new Error("an adopt is already running for this Track");Kd.set(t,{startedAt:Date.now()});try{return await U2({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{Kd.delete(t)}}async function U2({trackId:e,name:t,agent:n,skipPermissions:r,mode:o,fromNode:s=null,toNode:a=null,branch:i=null,repos:c=[],wip:l=null,wips:u=null,brief:d=null,epochs:p=[],createdAt:f=null,leadBox:w=null,reason:h=null,downSince:g=null}){let y=await Da(n,r),x=await Z(),b=de(x,e);if(b&&!b.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);b&&(await tg(b).catch(()=>{}),await cI(b),x.tracks.splice(x.tracks.indexOf(b),1),await se()),await J.mkdir(Pc,{recursive:!0});let I=z.join(Pc,e);await J.rm(I,{recursive:!0,force:!0}).catch(()=>{});let _=null,N=!1,U=[];try{let j=[];if(i)for(let X of Array.isArray(c)?c:[]){let G=typeof X=="string"?X:X?.repo;if(!G||!/^[^/\s]+\/[^/\s]+$/.test(G))continue;let fe=await Cs(G)??await Ll(G);await gn(fe,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],Xg),j.push({slug:G,base:fe,name:typeof X=="object"?X?.name??null:null})}if(i&&j.length===1){let{base:X,slug:G}=j[0];await G_(X,I,i),U.push({base:X,dir:I}),await Lc(I);let fe=await Yo(X);_={dir:I,base:X,branch:i,kind:"worktree",baseRef:fe,repo:G}}else if(i&&j.length>=2){await J.mkdir(I,{recursive:!0});let X=new Set([".bostrat"]),G=[];for(let fe of j){let be=fe.name||z.basename(fe.base);X.has(be)&&(be=fe.slug.replace("/","-"));for(let le=2;X.has(be);le++)be=`${z.basename(fe.base)}-${le}`;X.add(be);let xe=z.join(I,be);await G_(fe.base,xe,i),U.push({base:fe.base,dir:xe});let Ke=await Yo(fe.base);G.push({name:be,dir:xe,base:fe.base,baseRef:Ke,repo:fe.slug})}await ja(I,G,i),_={dir:I,kind:"multi",branch:i,repos:G}}else N=!0,await J.mkdir(I,{recursive:!0}),await fm(I),await Lc(I),_={dir:I,base:null,branch:null,kind:"repo"};let T=[];for(let X of B2(_,{wip:l,wips:u})){let G=await j2(X.dir,e);T.push({name:X.name,repo:X.repo,applied:G.applied,skipped:G.skipped,...G.advanced?{advanced:G.advanced}:{}})}let R=T.some(X=>X.applied),L=T.length===1?T[0].skipped:T.filter(X=>X.skipped).map(X=>`${X.name??X.repo}: ${X.skipped}`).join("; ")||null,V=T.length===1?T[0].advanced??null:null;await M_({id:e,cwd:I}).catch(()=>({restored:!1}));let O=z.join(I,ho),S=null;(await Ql(I)).restored?S="checkpoint":typeof d=="string"&&d.trim()&&(await J.mkdir(z.dirname(O),{recursive:!0}),await J.writeFile(O,d),S="brief");let H=new Set(x.tracks.flatMap(X=>(X.boxes||[]).map(G=>G.name))),W=null;w&&!H.has(w)&&!await ye(w).catch(()=>null)?W=w:(W=`${t.trim()} lead`,H.has(iu(W))&&(W=`${t.trim().slice(0,50).trim()} ${e} lead`));let te=await En(W,I,{agentCmd:y,agent:n});Ho({cwd:te.cwd,sessionName:te.name,agent:n,agentCmd:y});let pe=Date.now(),Ie=Jg(te,"lead","live"),Oe=(Array.isArray(p)?p:[]).filter(X=>X&&typeof X=="object").map(X=>({...X})),re=Oe[Oe.length-1];re&&re.endedAt==null&&(re.endedAt=pe,re.endReason==null&&(re.endReason=o==="recover"?"node-offline":"node-transfer")),Oe.push({agent:n,sessionId:te.sessionId??null,pinned:te.pinned===!0,startedAt:pe,endedAt:null}),Ie.epochs=Oe;let Ne={id:e,name:t.trim(),cwd:te.cwd,workspace:_,leadBox:te.name,boxes:[Ie],events:[],createdAt:Number.isFinite(f)?f:pe,...S?{pendingHandoffHydrate:{artifact:ho,at:pe}}:{}};return Ae(Ne,"transferred-in",{box:te.name,agent:n,fromNode:s,toNode:a,mode:o,reason:h,...o==="recover"?{downSince:Number.isFinite(g)?g:null}:{},branch:_.branch??null,wip:R,...V?{wipAdvanced:V}:{},..._.kind==="multi"&&T.length?{wipRepos:T}:{},epoch:Oe.length-1,name:Ne.name,cwd:Ne.cwd,workspace:{base:_.base??null,branch:_.branch??null,kind:_.kind,..._.baseRef?{baseRef:_.baseRef}:{},..._.repo?{repo:_.repo}:{},..._.repos?{repos:_.repos.map(({name:X,base:G,baseRef:fe,repo:be})=>({name:X,base:G,baseRef:fe,repo:be}))}:{}}}),x.tracks.push(Ne),await se(),{...await Ut(Ne),adopt:{wipApplied:R,wipSkipped:L,...V?{wipAdvanced:V}:{},..._.kind==="multi"?{wipRepos:T}:{},codeless:N,artifactSource:S}}}catch(j){for(let T of U)await St(T.base,T.dir).catch(()=>{});throw await J.rm(I,{recursive:!0,force:!0}).catch(()=>{}),j}}async function pI(e,t,n){let r=await Z(),o=de(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await se())}async function Ra(e,t){e.step=t,await Vc(e)}function fI(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 hI(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function K2(e,t,n){if(!hI(n)||Pt.has(t)||!await ye(n.box).catch(()=>null))return!1;try{await J.access(n.dir)}catch{return!1}let o=await ye(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return Pt.set(t,s),wI(s,o).catch(a=>mI(s,a)),!0}async function ny(){let e=await Z(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Pt.has(r))continue;if(await K2(n,r,o)){t=!0,Ae(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await ue({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=fI(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!vr.has(i.state)&&(i.state="canceled"),Ae(n,"subtask-failed",{from:o.box,fromAgent:o.agent,task:o.task,subtaskId:r,failedStep:s,error:a.error,recovered:a.recovered,durationMs:o.startedAt?a.finishedAt-o.startedAt:null}),await ue({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await z_(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||vr.has(r.state)||Pt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?z.join(Pa,`${n.id}-${r.subtaskId}`):null;await ue({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await z_(n,r.name,o)}}return t=await G2(e)||t,t&&await se(),t}async function z_(e,t,n){if(t&&await Ot(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of Dt(e.workspace)){let s=z.join(n,o.name);await St(o.base,s).then(()=>!0,()=>!1)||await St(o.dir,s).catch(()=>{})}await J.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await ye(e.leadBox).catch(()=>null);r?.cwd&&await St(r.cwd,n).catch(()=>{})}async function G2(e){let t;try{t=await J.readdir(Pa)}catch{return!1}let n=new Set;for(let o of e.tracks||[]){for(let s of Object.keys(o.subtasks||{}))n.add(`${o.id}-${s}`);for(let s of o.boxes||[])s.subtaskId&&n.add(`${o.id}-${s.subtaskId}`)}for(let o of Pt.values())o.dir&&n.add(z.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=z.join(Pa,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of Dt(a.workspace))await St(i.base,z.join(s,i.name)).catch(()=>{});await J.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await ye(a.leadBox).catch(()=>null):null;i?.cwd?await St(i.cwd,s).catch(()=>{}):await J.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await ue({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function ry(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!sa(n))throw new Error("task (string) required");let s=await Da(t,r),a=Zr(t);if(a){let f=new Error(`can't delegate to ${t} \u2014 its ${a.window} spend limit is reached ($${a.spentUsd.toFixed(2)} of $${a.limitUsd.toFixed(2)})`);throw f.usageCap=a,f}let i=de(await Z(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await ye(i.leadBox);if(!c)throw new Error(`lead box "${i.leadBox}" is not running`);if(!c.cwd)throw new Error("can't resolve the lead's working directory");let l=i.workspace?.kind==="multi",u=null;if(l){let f=Dt(i.workspace);if(!f.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let w of f)if(!w?.dir||!await aa(w.dir))throw new Error(`tagged checkout "${w?.name??"?"}" is missing from the lead workspace (${w?.dir??"no dir"})`);u=f.map(w=>({name:w.name,leadDir:w.dir,base:null}))}else if(!await aa(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=Xd().slice(0,8),p={id:d,trackId:e,trackName:i.name,agent:t,task:sa(n),skipPermissions:r,reason:Y_(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${wp(i.name)}-${d}`,base:null,repos:u,dir:z.join(Pa,`${e}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Pt.set(d,p),await Vc(p),z2(p,c,s).catch(f=>mI(p,f)),p}async function mI(e,t){e.failedStep=e.step,e.error=t instanceof Hc?"canceled":t?.message||String(t),e.step=t instanceof Hc?"canceled":"error",e.finishedAt=Date.now(),await sy(e).catch(()=>{}),await Vc(e).catch(()=>{}),await X2(e).catch(()=>{})}function gp(e){let t=Pt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");return t.canceled=!0,t}function oy(e){let t=Pt.get(e);if(!t)throw new Error(`subtask "${e}" not found`);if(t.finishedAt)throw new Error("subtask already finished");if(t.step!=="working")throw new Error(`subtask is not waiting to merge (step: ${t.step})`);return t.forceMerge=!0,t}async function z2(e,t,n){if(await Ra(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await ia(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await Vc(e)}else e.base=await ia(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await Ra(e,"spawn"),await J.mkdir(Pa,{recursive:!0}),e.repos){await J.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await Jo(a.leadDir,z.join(e.dir,a.name),e.branch,a.base);let s=Dt((de(await Z(),e.trackId)||{}).workspace);await ja(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 Jo(t.cwd,e.dir,e.branch,e.base),await Lc(e.dir);await V2(e,t);let r=e.trackName.slice(0,38).trim(),o=await En(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await J2(e,o),await X_(e.trackId,o.name,B4(e.task,!!e.repos),{kind:"subtask"}),await wI(e,t)}async function wI(e,t){await Ra(e,"working");let n=z.join(e.dir,Gd);if(await Q2(n,e),e.canceled)throw new Hc;if(await Ra(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=z.join(e.dir,l.name);await dm(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:K_({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await mm(l.leadDir,l.base,e.branch,$a),l.files=await wm(l.leadDir,l.base,e.branch,$a);let d=await gm(l.leadDir,l.base,e.branch,$a);l.applied=d.applied,l.conflicts=d.conflicts??[],s.files+=l.stat.files,s.insertions+=l.stat.insertions,s.deletions+=l.stat.deletions,a.push(...l.files.map(p=>z.join(l.name,p))),i.push(...l.conflicts.map(p=>p.startsWith("patch did not apply cleanly")?`${l.name}: ${p}`:z.join(l.name,p))),d.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await dm(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:K_({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await mm(t.cwd,e.base,e.branch,$a),e.files=await wm(t.cwd,e.base,e.branch,$a);let s=await gm(t.cwd,e.base,e.branch,$a);e.applied=s.applied,e.conflicts=s.conflicts}await Vc(e);let r=await Z2(e,t,n);await Ra(e,"resume"),await X_(e.trackId,e.leadBox,j4(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await Ra(e,"reap"),await sy(e),e.step="done";let o=Date.now();await pI(e.trackId,e.id,{...mp(e),finishedAt:o}),await Y2(e,o),e.finishedAt=o}async function V2(e,t){let n=z.join(e.dir,z.dirname(Dc));await J.mkdir(n,{recursive:!0});let r="";try{r=await D0(t.cwd,t.sessionId)}catch{}if(!r)try{r=await J.readFile(z.join(t.cwd,".bostrat/handoff/latest.md"),"utf8")}catch{r="_(no prior conversation digest available \u2014 rely on the working tree.)_"}let o=`# Lead context for subtask ${e.id}
248
252
 
249
253
  **Delegated task:** ${e.task}
250
254
 
@@ -255,15 +259,15 @@ ${a}`}async function lg(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<
255
259
  ## Conversation so far (lead \u2192 you)
256
260
 
257
261
  ${r}
258
- `;await te.writeFile(oe.join(e.dir,yc),o)}async function u2(e,t){let n=await ee(),r=me(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:Ha(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),$e(r,"subtask-delegated",{to:t.name,toAgent:e.agent,task:e.task,subtaskId:e.id,skipPermissions:e.skipPermissions,reason:e.reason}),r.subtasks=r.subtasks||{},r.subtasks[e.id]={...r.subtasks[e.id]||{},...jd(e)},await ue())}async function d2(e,t=e.finishedAt){let n=await ee(),r=me(n,e.trackId);if(!r)return;let o=r.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=e.conflicts.length?"conflict":"merged",o.stat=e.stat),$e(r,"subtask-merged",{from:e.box,fromAgent:e.agent,task:e.task,subtaskId:e.id,stat:e.stat,conflicts:e.conflicts.length,files:e.files,durationMs:t?t-e.startedAt:null}),await ue()}async function p2(e){let t=await ee(),n=me(t,e.trackId);if(!n)return;let r=e.canceled||e.error==="canceled",o=n.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=r?"canceled":"failed"),$e(n,r?"subtask-canceled":"subtask-failed",{from:e.box,fromAgent:e.agent,task:e.task,subtaskId:e.id,failedStep:e.failedStep||e.step,error:e.error,durationMs:e.finishedAt?e.finishedAt-e.startedAt:null}),n.subtasks=n.subtasks||{},n.subtasks[e.id]={...n.subtasks[e.id]||{},...jd(e)},await ue()}async function f2(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=oe.join(t.cwd,r);await te.mkdir(oe.dirname(o),{recursive:!0}),await te.copyFile(n,o)}catch{}return r}async function Eg(e){if(e.dir&&await Qp(e.dir).catch(()=>{}),e.box&&await rn(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await Mt(t.leadDir,oe.join(e.dir,t.name)).catch(()=>{});await te.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await ke(e.leadBox).catch(()=>null))?.cwd;n&&await Mt(n,e.dir).catch(()=>{})}}async function m2(e,t){let n=(t.startedAt||Date.now())+r2;for(;;){if(t.canceled||t.forceMerge)return;try{await te.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await br(o2)}}function br(e){return new Promise(t=>setTimeout(t,e))}var u_,Hn,d_,YU,gc,XU,Ed,Ac,oo,Yo,p_,ZU,Sd,yc,QU,e4,Xt,_w,me,Iw,$e,$w,Rw,r4,so,r_,a4,i4,c4,l4,o_,hc,h4,ya,s_,x4,v4,S4,T4,A4,wa,bc,$4,O4,M4,P4,S_,kc,T_,L4,wc,Ow,F4,Mw,q4,vc,K4,G4,a_,Cw,Lw,mg,xa,Ta,wg,mn,Fw,gg,e2,Nw,r2,o2,va,ma,Dt,s2,es,jd,Mc,Sg,Tc,cr=K(()=>{Xa();ct();om();Cx();bi();Er();zl();jx();pt();Tn();fs();Gl();ym();Io();_m();$m();kv();vi();Hf();Vl();Xf();an();gu();Tr();Gt();ki();vu();Gv();Wm();iA();su();ru();lA();Ph();pe();jh();Xu();dd();Wi();Do();ic();da();uw();yd();gw();Rn();od();HE();xw();YE();Cl();e_();Tw();Ew();u_=JU(VU),Hn=process.env.BOSTRAT_STATE_DIR||oe.join(process.env.HOME||"/tmp",".bostrat"),d_=oe.join(Hn,"tracks.json"),YU=oe.join(Hn,"events.jsonl"),gc=oe.join(Hn,"workspaces"),XU=process.env.BOSTRAT_DEFAULT_REPO||null,Ed={claude:{envVar:"BOSTRAT_AGENT_CMD",base:"claude",skipFlag:"--dangerously-skip-permissions"},cursor:{envVar:"BOSTRAT_CURSOR_CMD",base:"cursor-agent",skipFlag:"--force"},codex:{envVar:"BOSTRAT_CODEX_CMD",base:"codex",skipFlag:"--dangerously-bypass-approvals-and-sandbox"}},Ac=Object.keys(Ed);oo={at:0,value:null};Yo=".bostrat/handoff/latest.md",p_=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;ZU=/\(Read \S{1,300} for handoff context from the prior lead — you are now the lead; none of the prior chat is in your context\. Then respond to the user above\.\)$/;Sd=".bostrat/handoff/subtask-result.md",yc=".bostrat/handoff/lead-context.md",QU=(e,t=!1)=>t?`You are a SUBTASK agent working in an isolated multi-repo workspace, delegated by a lead agent on a shared workstream. This directory is NOT itself a git repo: each subdirectory is an isolated git worktree of one of the workstream's repos, already seeded with the lead's full working tree for that repo. The conversation so far is summarized in ${yc} \u2014 read that first for context. Your scoped task:
262
+ `;await J.writeFile(z.join(e.dir,Dc),o)}async function J2(e,t){let n=await Z(),r=de(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:$o(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),Ae(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]||{},...mp(e)},await se())}async function Y2(e,t=e.finishedAt){let n=await Z(),r=de(n,e.trackId);if(!r)return;let o=r.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=e.conflicts.length?"conflict":"merged",o.stat=e.stat),Ae(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 se()}async function X2(e){let t=await Z(),n=de(t,e.trackId);if(!n)return;let r=e.canceled||e.error==="canceled",o=n.boxes.find(s=>s.subtaskId===e.id);o&&(o.state=r?"canceled":"failed"),Ae(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]||{},...mp(e)},await se()}async function Z2(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=z.join(t.cwd,r);await J.mkdir(z.dirname(o),{recursive:!0}),await J.copyFile(n,o)}catch{}return r}async function sy(e){if(e.dir&&await Vl(e.dir).catch(()=>{}),e.box&&await Ot(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await St(t.leadDir,z.join(e.dir,t.name)).catch(()=>{});await J.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await ye(e.leadBox).catch(()=>null))?.cwd;n&&await St(n,e.dir).catch(()=>{})}}async function Q2(e,t){let n=(t.startedAt||Date.now())+H2;for(;;){if(t.canceled||t.forceMerge)return;try{await J.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await Sr(W2)}}function Sr(e){return new Promise(t=>setTimeout(t,e))}var Zd,qn,V_,N4,Pc,P4,Qd,Wc,fo,ho,xg,D4,Gd,Dc,B4,j4,Nt,cg,de,lg,Ae,ug,dg,U4,vr,F_,q4,K4,G4,z4,U_,Mc,Q4,Ca,H_,s2,a2,i2,c2,l2,Oa,Bc,f2,m2,w2,b2,Dg,yg,Gc,gt,wn,Vd,jc,sI,T2,Cc,Nc,E2,pg,$2,Fc,R2,O2,q_,fg,bg,Jg,hs,La,Xg,gn,Yd,Zg,L2,Kd,H2,W2,Pa,$a,Pt,q2,ys,mp,Vc,wp,Hc,dr=q(()=>{wi();ut();Dh();gv();Bi();Nr();hu();Sv();mt();Tn();Rs();fu();Xh();Fo();am();cm();sS();Fi();vh();mu();Oh();ln();Lu();Or();Yt();ji();qu();RS();Sm();KT();Eu();Au();zT();mw();he();yw();bd();Cd();ac();Zo();Ac();Ea();Kw();Fd();Zw();Mn();Ed();T_();ng();C_();eu();B_();sg();ig();Zd=C4(M4),qn=process.env.BOSTRAT_STATE_DIR||z.join(process.env.HOME||"/tmp",".bostrat"),V_=z.join(qn,"tracks.json"),N4=z.join(qn,"events.jsonl"),Pc=z.join(qn,"workspaces"),P4=process.env.BOSTRAT_DEFAULT_REPO||null,Qd={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"}},Wc=Object.keys(Qd);fo={at:0,value:null};ho=".bostrat/handoff/latest.md",xg=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;D4=/\(Read \S{1,300} for handoff context from the prior lead — you are now the lead; none of the prior chat is in your context\. Then respond to the user above\.\)$/;Gd=".bostrat/handoff/subtask-result.md",Dc=".bostrat/handoff/lead-context.md",B4=(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 ${Dc} \u2014 read that first for context. Your scoped task:
259
263
 
260
264
  ${e}
261
265
 
262
- Work ONLY inside this directory. cd into the repo a change belongs to before running git commands, and commit per repo with a clear message (repos you don't touch need nothing). When you are finished: (1) make your code changes, (2) commit them in each changed repo, (3) LAST, write a short markdown digest to ${Sd} (at this directory's root) with sections \u2014 Result (what you did), Files (paths you changed, prefixed with the repo directory), Notes (anything the lead must know). Writing that file is your DONE signal: do it last, then stop and take no further action.`:`You are a SUBTASK agent working in an isolated git worktree, delegated by a lead agent on a shared workstream. The lead's full working tree is already checked out here, and the conversation so far is summarized in ${yc} \u2014 read that first for context. Your scoped task:
266
+ Work ONLY inside this directory. cd into the repo a change belongs to before running git commands, and commit per repo with a clear message (repos you don't touch need nothing). When you are finished: (1) make your code changes, (2) commit them in each changed repo, (3) LAST, write a short markdown digest to ${Gd} (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 ${Dc} \u2014 read that first for context. Your scoped task:
263
267
 
264
268
  ${e}
265
269
 
266
- Work ONLY inside this directory. When you are finished: (1) make your code changes, (2) commit them with git and a clear message, (3) LAST, write a short markdown digest to ${Sd} with sections \u2014 Result (what you did), Files (paths you changed), Notes (anything the lead must know). Writing that file is your DONE signal: do it last, then stop and take no further action.`,e4=(e,t,n,r)=>`A subtask box you delegated has finished: "${e}". Its changes are now merged into your working tree (${t.files} file${t.files===1?"":"s"}, +${t.insertions} \u2212${t.deletions}). Read ${r} for exactly what it did. `+(n.length?`IMPORTANT: ${n.length} merge conflict${n.length===1?"":"s"} need resolving \u2014 fix the conflict markers in: ${n.join(", ")}, then continue.`:"Review the merged changes and continue the work."),Xt=null,_w=null;me=(e,t)=>e.tracks.find(n=>n.id===t)||null,Iw=Promise.resolve();$e=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),t4(e.id,r),Jv(e,r),r};n0(async({sessionName:e,from:t,to:n,version:r,status:o,error:s})=>{let i=(await ee()).tracks.find(c=>c.leadBox===e||(c.boxes||[]).some(l=>l.name===e));i&&($e(i,"codex-update",{box:e,from:t,to:r||n,status:o,...s?{error:s}:{}}),await ue().catch(()=>{}))});$w=oe.join(Hn,"plane-link","update-notice.json");Rw=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),r4=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);so=new Set(["merged","conflict","canceled","failed","handed-off"]),r_=new Map;a4=5e3;i4={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};c4=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];l4=10*6e4;o_=400;hc=new Map;h4=1500,ya=new Map;s_="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.";x4=4e3,v4=3,S4=[300,350,400],T4=1e3,A4=12,wa=new Map,bc=new Map;$4=[250,400,500,600];O4=3e4,M4=[350,650,900];P4=12e4;S_=e=>({branch:e.branch,kind:e.kind,repos:(e.repos??[]).filter(Boolean).map(({name:t,base:n,baseRef:r,repo:o})=>({name:t,base:n,baseRef:r,repo:o}))});kc="# bostrat workspace",T_=`${kc}
270
+ Work ONLY inside this directory. When you are finished: (1) make your code changes, (2) commit them with git and a clear message, (3) LAST, write a short markdown digest to ${Gd} 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.`,j4=(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."),Nt=null,cg=null;de=(e,t)=>e.tracks.find(n=>n.id===t)||null,lg=Promise.resolve();Ae=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),L4(e.id,r),CS(e,r),r};F0(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&&(Ae(i,"codex-update",{box:e,from:t,to:r||n,status:o,...s?{error:s}:{}}),await se().catch(()=>{}))});ug=z.join(qn,"plane-link","update-notice.json");dg=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),U4=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);vr=new Set(["merged","conflict","canceled","failed","handed-off"]),F_=new Map;q4=5e3;K4={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};G4=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];z4=10*6e4;U_=400;Mc=new Map;Q4=1500,Ca=new Map;H_="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.";s2=4e3,a2=3,i2=[300,350,400],c2=1e3,l2=12,Oa=new Map,Bc=new Map;f2=[250,400,500,600];m2=3e4,w2=[350,650,900];b2=12e4;Dg=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}))});yg=new Map,Gc=e=>yg.get(e)||(Nt?de(Nt,e)?.reshape:null)||null,gt=(e,t=409)=>Object.assign(new Error(e),{status:t});wn=e=>J.access(e).then(()=>!0,()=>!1),Vd=(e,t,n)=>Zd("git",["-C",e,"worktree","move","--end-of-options",t,n],{timeout:6e4});jc="# bostrat workspace",sI=`${jc}
267
271
 
268
272
  TRACK MEMORY: if \`.bostrat/memory/MEMORY.md\` exists in your workspace, read it
269
273
  before substantive work \u2014 it is the shared cross-provider memory for this repo
@@ -641,16 +645,16 @@ for the same follow-up at the same moment twice; run bostrat-followup ls first
641
645
  specifics (no PR numbers, URLs, SHAs, tags \u2014 the card supplies them), and HOLD
642
646
  HERE after proposing until the operator answers the card. Bostrat never runs a
643
647
  follow-up on its own; the operator's tap is the gate.
644
- `,L4=T_,wc=T_+K0;Ow=e=>typeof e=="string"&&(e===kc||e.startsWith(`${kc}
645
- `)),F4="# bostrat multi-repo workspace";Mw=wc.replace(`${kc}
646
- `,`${kc}
648
+ `,T2=sI,Cc=sI+$x;Nc=e=>typeof e=="string"&&(e===jc||e.startsWith(`${jc}
649
+ `)),E2="# bostrat multi-repo workspace";pg=Cc.replace(`${jc}
650
+ `,`${jc}
647
651
 
648
652
  (Global copy managed by bostrat \u2014 rewritten on service start; edits will be lost.)
649
653
  SCOPE: these instructions apply ONLY when your working directory is under
650
654
  ~/.bostrat/workspaces/ or ~/.bostrat/worktrees/ \u2014 a bostrat-orchestrated box.
651
655
  When working anywhere else, ignore everything below.
652
- `);q4=new Set(["claude","codex","cursor"]);vc=new Set,K4=e=>vc.has(e);G4=9e4;a_={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};Cw=new Map;Lw=120;mg=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:Ha(e.hookToken),createdAt:Date.now()});xa=new Map,Ta=e=>xa.get(e)||(Xt?me(Xt,e)?.handoff:null)||null;wg=6e4,mn=(e,t,n=15e3)=>u_("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),Fw=new Map,gg=e=>Fw.get(e)||null;e2=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,200}$/;Nw=new Map;r2=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,o2=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,va=oe.join(Hn,"worktrees"),ma=[yc,Sd],Dt=new Map,s2=e=>Dt.get(e)||(Xt?Xt.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,es=e=>{let t=new Map([...Dt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=Xt?me(Xt,e):null;if(n?.subtasks)for(let[r,o]of Object.entries(n.subtasks))t.has(r)||t.set(r,o);return[...t.values()].sort((r,o)=>r.startedAt-o.startedAt)},jd=e=>({id:e.id,trackId:e.trackId,trackName:e.trackName,agent:e.agent,task:e.task,skipPermissions:e.skipPermissions,reason:e.reason||null,step:e.step,failedStep:e.failedStep||null,box:e.box,branch:e.branch,base:e.base,repos:e.repos||null,dir:e.dir,stat:e.stat,files:e.files||null,conflicts:e.conflicts||[],applied:e.applied,error:e.error,canceled:e.canceled,startedAt:e.startedAt,finishedAt:e.finishedAt});Mc=e=>R_(e.trackId,e.id,jd(e));Sg=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",Tc=class extends Error{}});ct();import Te from"node:path";import gt from"node:fs";import l6 from"node:readline";import{fileURLToPath as u6}from"node:url";import Ut from"express";import d6 from"node:http";import p6 from"node:https";import $p from"node:os";import{randomUUID as f6}from"node:crypto";import{WebSocketServer as m6}from"ws";ct();import rN from"node-pty";async function Rk(e,t,n={}){if(!je(t)){ql(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await Rr()){ql(e,`host tmux server not running on ${Ot}`),e.close(1011,"tmux server unavailable");return}if(!await ke(t)){ql(e,`session "${t}" not found`),e.close(1008,"session not found");return}let r=$k(n.cols,120,Ok),o=$k(n.rows,32,Mk),s;try{s=rN.spawn(X,["-S",Ot,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){ql(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&hf(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(hf(e,{type:"exit",code:a??null,signal:i??null}),e.close(1e3,"tmux exited"))}),e.on("message",a=>{let i;try{i=JSON.parse(a.toString())}catch{return}if(!(!i||typeof i!="object")){if(i.type==="data"&&typeof i.data=="string")s.write(i.data);else if(i.type==="resize"&&iN(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{}aN(t)})}var oN=6,sN=250;async function aN(e,t=oN,n=sN){for(let r=0;r<t;r++){if(await Ao(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var Ok=20,Mk=6;function iN(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=Ok&&Number(t)>=Mk}function $k(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function hf(e,t){try{e.send(JSON.stringify(t))}catch{}}function ql(e,t){hf(e,{type:"error",message:t})}function Ck(e){let t=typeof e=="string"&&e?e:"/",n=t.indexOf("?"),r=n===-1?t:t.slice(0,n),o=n===-1?"":t.slice(n+1),s=r.match(/^\/api\/attach\/([^/]+)$/);if(!s)return{ok:!1,status:404};let a;try{a=decodeURIComponent(s[1])}catch{return{ok:!1,status:400}}let i=new URLSearchParams(o);return{ok:!0,sessionName:a,cols:Number(i.get("cols"))||void 0,rows:Number(i.get("rows"))||void 0}}an();Gl();om();cr();import{createRequire as h6}from"node:module";var h2=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function _g({tracks:e=[],views:t=[],queuedOf:n=()=>[],jobsOf:r=()=>[],prPendingOf:o=()=>[]}={}){let s=[];for(let a of e)!a||a.archivedAt&&!a.archiving||a.transferredTo||(a.working&&s.push(`working:${a.id}`),a.prompted&&s.push(`prompted:${a.id}`),(n(a.id)??[]).length&&s.push(`queued:${a.id}`),(a.boxes||[]).some(i=>i?.role==="subtask"&&i?.state==="live")&&s.push(`subtask:${a.id}`),(r(a.id)??[]).length&&s.push(`job:${a.id}`),Object.values(a.subtasks||{}).some(h2)&&s.push(`merge-back:${a.id}`),(o(a.id)??[]).length&&s.push(`pr:${a.id}`));return t.some(a=>a?.state==="live"||a?.state==="starting")&&s.push("views"),{busy:s.length>0,reasons:s}}pe();ym();ct();import b2 from"node:fs/promises";import Ig from"node:fs/promises";var w2=100;async function g2(e){let t;try{t=await Ig.readFile(`/proc/${e}/stat`,"utf8")}catch{return null}let n=t.lastIndexOf(")");if(n<0)return null;let r=t.slice(n+2).split(" "),o=Number(r[1]),s=Number(r[11])+Number(r[12]);return!Number.isFinite(o)||!Number.isFinite(s)?null:{ppid:o,cpuMs:s/w2*1e3,ioBytes:await y2(e)}}async function y2(e){let t;try{t=await Ig.readFile(`/proc/${e}/io`,"utf8")}catch{return 0}let n=r=>Number(t.match(new RegExp(`^${r}: (\\d+)$`,"m"))?.[1]||0);return n("rchar")+n("wchar")}async function D_(e){let t=[...new Set((e||[]).map(Number).filter(l=>Number.isFinite(l)&&l>0))];if(!t.length)return{procs:0,cpuMs:0,ioBytes:0};let n;try{n=await Ig.readdir("/proc")}catch{return null}let r=new Map;await Promise.all(n.map(async l=>{if(!/^\d+$/.test(l))return;let u=await g2(l);u&&r.set(Number(l),u)}));let o=new Map;for(let[l,u]of r)o.has(u.ppid)||o.set(u.ppid,[]),o.get(u.ppid).push(l);let s=new Set,a=t.filter(l=>r.has(l));for(let l of a)s.add(l);let i=0,c=0;for(let l=0;l<a.length;l++){let u=a[l];i+=r.get(u).cpuMs,c+=r.get(u).ioBytes;for(let d of o.get(u)||[])s.has(d)||(s.add(d),a.push(d))}return{procs:s.size,cpuMs:Math.round(i),ioBytes:c}}var k2=Number(process.env.BOSTRAT_JOB_CHECK_MS)||15*6e4,x2=Number(process.env.BOSTRAT_JOB_STALL_CHECKS)||3,v2=Number(process.env.BOSTRAT_JOB_CPU_RATE_MIN)||25,S2=Number(process.env.BOSTRAT_JOB_IO_RATE_MIN)||64*1024,T2=5*6e4,j_={readOpenJobs:ov,statFile:async e=>{try{let t=await b2.stat(e);return{size:t.size,mtimeMs:Math.round(t.mtimeMs)}}catch{return null}},updatedAt:e=>Ur(e.agent).updatedAt(e),panePids:Ak,treeStats:D_,appendEvent:M},hn=new Map,B_=new Map,$g=new Map,Rg=(e,t,n)=>`${e}|${t}|${n}`;function L_(e){let t=[];for(let n of e||[])if(!(!n||n.archivedAt&&!n.archiving||n.transferredTo))for(let r of n.boxes||[])r?.state==="live"&&r.name&&t.push({track:n,box:r});return t}async function F_(e,t,n){let r=null;try{r=await n.updatedAt(e)}catch{r=null}let o=B_.get(e.name);if(o&&o.mtime===r&&t-o.at<T2)return o.jobs;let s=[];try{s=await n.readOpenJobs(e)}catch{s=[]}return B_.set(e.name,{at:t,mtime:r,jobs:s}),s}async function A2(e,t,n){let r=await n.panePids(e.name),o=r.length?await n.treeStats(r):null,s=null;try{s=await n.updatedAt(e)}catch{s=null}return{at:t,cpuMs:o?.cpuMs??null,ioBytes:o?.ioBytes??null,procs:o?.procs??null,mtime:s}}async function E2(e,t){return e?.outputFile?await t.statFile(e.outputFile):null}function _2(e,t){if(!e)return!0;let n=Math.max(1,(t.at-e.at)/1e3);return t.mtime!=null&&e.mtime!=null&&t.mtime>e.mtime||t.procs!=null&&e.procs!=null&&t.procs>e.procs||t.cpuMs!=null&&e.cpuMs!=null&&(t.cpuMs-e.cpuMs)/n>=v2||t.ioBytes!=null&&e.ioBytes!=null&&(t.ioBytes-e.ioBytes)/n>=S2}function U_(e,t,n,r){let o=[];for(let s of n){let a=Rg(e.id,t.name,s.id),i=hn.get(a);i?i.job=s:hn.set(a,{trackId:e.id,boxName:t.name,agent:t.agent||null,job:s,firstSeenAt:r,quiet:0,stalled:!1}),o.push(a)}return o}async function H_(e,{now:t=Date.now(),deps:n=j_}={}){let r=new Map,o=new Set;for(let{track:s,box:a}of L_(e)){let i=await F_(a,t,n);for(let l of i)o.add(Rg(s.id,a.name,l.id));let c=U_(s,a,i,t).filter(l=>!hn.get(l).stalled).map(l=>hn.get(l).job);c.length&&r.set(s.id,[...r.get(s.id)??[],...c])}for(let s of[...hn.keys()])o.has(s)||hn.delete(s);return r}async function I2(e,{now:t=Date.now(),deps:n=j_}={}){let r={checked:0,progressing:0,quiet:0,stalled:[]},o=L_(e),s=new Set(o.map(({box:a})=>a.name));for(let[a,i]of[...hn])s.has(i.boxName)||hn.delete(a);for(let{track:a,box:i}of o){let c=await F_(i,t,n),l=new Set(c.map(w=>Rg(a.id,i.name,w.id)));for(let[w,m]of[...hn])m.boxName===i.name&&!l.has(w)&&hn.delete(w);if(!c.length){$g.delete(i.name);continue}let u=U_(a,i,c,t),d=await A2(i,t,n),p=$g.get(i.name);$g.set(i.name,d);let f=_2(p,d);for(let w of u){let m=hn.get(w);r.checked++;let g=await E2(m.job,n),y=!!g&&!!m.file&&(g.size>m.file.size||g.mtimeMs>m.file.mtimeMs),x=!!g&&!m.file;if(m.file=g??m.file,f||y||x){m.quiet=0,m.lastProgressAt=t,m.stalled=!1,r.progressing++;continue}if(m.stalled||(m.quiet++,r.quiet++,m.quiet<x2))continue;m.stalled=!0,m.stalledAt=t,r.stalled.push(w);let O=t-(m.lastProgressAt??m.firstSeenAt);try{await n.appendEvent(a,{type:"job.stalled",actor:"orchestrator",source:"orchestrator",boxId:i.name,provider:i.agent||null,payload:{id:m.job.id,kind:m.job.kind||"agent",name:m.job.name||null,detail:m.job.detail||null,startedTs:m.job.ts??m.firstSeenAt,quietMs:O,checks:m.quiet}})}catch{}console.log(`[job-watch] ${a.id}/${i.name} job ${m.job.id} (${m.job.name||m.job.kind}) quiet for ${Math.round(O/6e4)}m over ${m.quiet} check(s) \u2014 released; the node may sleep`)}}return r}function W_({listTracks:e,intervalMs:t=k2}={}){let n=!1,o=setInterval(async()=>{if(!n){n=!0;try{await I2(await e())}catch(s){console.error(`[job-watch] sweep: ${s?.message||s}`)}finally{n=!1}}},t);return o.unref?.(),o}pe();ic();Rn();ed();Gt();var Fd=60*6e4,$2=1440*6e4,R2=new Set(["merged","closed","lost"]),Cc=(e,t,n)=>Number.isFinite(Number(e))&&n-Number(e)<=t;function O2({trackId:e,shipPending:t=null,links:n=[],observers:r=0,now:o=Date.now()}={}){let s=[];t&&Number.isFinite(Number(t.ts))&&o-Number(t.ts)<=ew&&s.push("ship"),r>0&&s.push("create-net");for(let a of n||[]){if(!a||R2.has(a.state))continue;let i=[a.ciFix,a.reconcile,a.ciFixAwait,a.reconcileAwait];if(!(a.trackId===e||i.some(d=>d?.trackId===e)))continue;let l=a.number??"?";a.ciFix&&Cc(a.ciFix.delegatedAt,Fd,o)&&s.push(`ci-fix#${l}`),a.reconcile&&Cc(a.reconcile.delegatedAt,Fd,o)&&s.push(`reconcile#${l}`),a.ciFixAwait&&Cc(a.ciFixAwait.since,Fd,o)&&s.push(`ci-fix-await#${l}`),a.reconcileAwait&&Cc(a.reconcileAwait.since,Fd,o)&&s.push(`reconcile-await#${l}`);let u=a.autoMerge?.armedAt??a.armedAt??null;a.trackId===e&&(a.autoMerge||a.armedAt)&&Cc(u,$2,o)&&s.push(`auto-merge#${l}`)}return s}var Ud=new Map;Je.on("event",e=>{e?.trackId&&Ud.delete(e.trackId)});async function M2(e){if(Ud.has(e.id))return Ud.get(e.id);let t=await q(e).catch(()=>[]),n=ca(t,-1/0);return Ud.set(e.id,n),n}async function q_(e,{now:t=Date.now()}={}){let n=new Map,r=await un().catch(()=>[]);for(let o of e||[]){if(!o||De(o))continue;let s=O2({trackId:o.id,shipPending:await M2(o),links:r,observers:RT(o.id),now:t});s.length&&n.set(o.id,s)}return n}Tw();import nI from"node:fs";import io from"node:fs/promises";import J2 from"node:os";import dt from"node:path";import{spawn as Y2}from"node:child_process";import{createRequire as X2}from"node:module";pe();vu();import Q_ from"node:fs";import Pc from"node:fs/promises";import P2 from"node:http";import gn from"node:path";import Wd from"node:os";import{createRequire as D2}from"node:module";import Mg from"ws";import C2 from"node:path";import N2 from"node:os";var Nc=process.env.BOSTRAT_STATE_DIR||C2.join(process.env.HOME||N2.tmpdir(),".bostrat");function Og(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 K_(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=Og(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function G_(e){let t=String(e||"").trim();if(!t)return"";let n=/^[a-z][a-z0-9+.-]*:\/\//i.test(t)?t:`wss://${t}`,r;try{r=new URL(n)}catch{return t}let o={"https:":"wss:","http:":"ws:","wss:":"wss:","ws:":"ws:"}[r.protocol];return o?(r.protocol=o,(r.pathname===""||r.pathname==="/")&&(r.pathname="/v1/node"),r.toString()):t}var wn=(()=>{try{return D2(import.meta.url)("../package.json").version||null}catch{return null}})(),z_=process.env.BOSTRAT_STATE_DIR||gn.join(process.env.HOME||Wd.tmpdir(),".bostrat");function ts({env:e=process.env,pkgDir:t=gn.resolve(gn.dirname(new URL(import.meta.url).pathname),".."),exists:n=Q_.existsSync}={}){let r=String(e.BOSTRAT_INSTALL_KIND||"").trim();return["container","npm-global","git-checkout","dev"].includes(r)?r:/\/lib\/node_modules\/bostrat-node(?:\/|$)/.test(t.replace(/\\/g,"/"))?"npm-global":n(gn.join(t,"..",".git"))?"git-checkout":"dev"}function Dc(e,t){let n=String(e).split(".").map(Number),r=String(t).split(".").map(Number);if(n.some(Number.isNaN)||r.some(Number.isNaN))return!1;for(let o=0;o<Math.max(n.length,r.length);o++){let s=(n[o]||0)-(r[o]||0);if(s)return s<0}return!1}function Hd(e){switch(e){case"npm-global":return"npm install -g bostrat-node && restart the bostrat-node service";case"git-checkout":return"scripts/deploy-pi.sh (or The Bakery \u2192 Deploy to Pi \u2192 bostrat)";case"container":return"Links \u2192 Fly \u2192 Update (or the plane's auto-update while the node sleeps)";default:return"update this node's bostrat-node checkout/install"}}function B2({home:e=process.env.HOME||Wd.homedir(),env:t=process.env}={}){let n=r=>{try{return Q_.statSync(r),!0}catch{return!1}};return{claude:n(gn.join(e,".claude",".credentials.json")),codex:n(gn.join(t.CODEX_HOME||gn.join(e,".codex"),"auth.json"))}}var ut=1,V_=1e3,J_=3e4,j2=6e4,L2=1500,F2=500,ao=100,U2=2e3,H2=25e3,W2=6e4,eI=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},q2=eI(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),K2=3e4,Y_=10*6e4,G2=400,X_=250,z2=eI(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),Cg=4,V2=6e4,Z_=6e4;function tI({url:e,token:t,nodeId:n=Wd.hostname(),name:r=Wd.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,deliverySample:c=null,onHashKey:l=null,metricsMs:u=V2,onUpdateAvailable:d=null,onUpdatePolicy:p=null,onHelloRefused:f=null,updatePolicy:w=null,installKind:m=ts(),selfUrl:g=`http://127.0.0.1:${process.env.PORT||3362}`,apiToken:y=null,onDegraded:x=null,onRecovered:b=null,onConnected:O=null,ingestMode:I=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:C=q2,unackedRetryMs:U=W2,pingMs:H=H2,maxInflightEvents:_=G2,httpTimeoutMs:$=z2,stallBackoffMinMs:L=K2,fetchImpl:V=globalThis.fetch,log:S=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=G_(e);let E=g.replace(/^http/,"ws"),P=new Set,W=new Map,G=new Map,ae=gn.join(z_,"plane-link","cursor.json"),we=gn.join(z_,"plane-link","dead-letter.ndjson"),Re=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),Ae={},Y={},ye=new Map,J=null,z=null,se=0,ve=0,Ne=0,R=Promise.resolve(),D="ws",de=0,Le=!1,Ce=0,Ht=!1,St=ao,Gn=new Set,xn=[],yt=null,k=null,h=!1,v=!1,N=V_,ne=null,ge=null,Me=null,tt=null,Ge=null,Wt=!1,pl=0;async function PO(){try{Ae=JSON.parse(await Pc.readFile(ae,"utf8"))}catch{Ae={}}}function DO(){Wt=!0,!Me&&(Me=setTimeout(async()=>{if(Me=null,!!Wt){Wt=!1;try{await Pc.mkdir(gn.dirname(ae),{recursive:!0}),await Pc.writeFile(ae,JSON.stringify(Ae))}catch(j){S.error("[plane-link] cursor flush failed:",j?.message||j)}}},U2),Me.unref?.())}function it(j){return!k||k.readyState!==Mg.OPEN?!1:(k.send(JSON.stringify(j)),!0)}function La(j){let F=Date.now();for(let{trackId:A,event:B}of j){let Z=ye.get(B.id);ye.set(B.id,{trackId:A,seq:B.seq,event:B,sentAt:F,firstSentAt:Z?.firstSentAt??F,retryAt:F+U,tries:(Z?.tries??0)+1,nacks:Z?.nacks??0})}return D==="http"?(FO(j),!0):it({v:ut,ch:"events",type:"append",events:j})}function BO(j){let F=null;for(let A of ye.values())A.trackId===j&&(F==null||A.seq<F)&&(F=A.seq);return F}function Mp(j){let F=Y[j];if(F==null)return;let A=BO(j),B=A==null?F:Math.min(F,A-1);B>(Ae[j]??0)&&(Ae[j]=B,DO())}function Fa(){if(J=Date.now(),z!=null){let j=Date.now()-z;S.log(`[plane-link] spine sync recovered after ${Math.round(j/1e3)}s degraded (${se} stall redial(s))`);let F=z;z=null,se=0,ve=0,Le=!1,Ce=0;try{b?.({since:F,downMs:j})}catch(A){S.error(`[plane-link] onRecovered failed: ${A?.message||A}`)}}}function Cp(j){if(!Array.isArray(j)||!j.length)return;let F=new Set;for(let A of j){let B=ye.get(A);B&&(ye.delete(A),(Y[B.trackId]??0)<B.seq&&(Y[B.trackId]=B.seq),F.add(B.trackId))}for(let A of F)Mp(A);Fa()}function nb(j,F){Ne++;let A={at:Date.now(),trackId:j.trackId,seq:j.seq,id:j.event?.id??null,type:j.event?.type??null,reason:F,event:j.event??null};S.error(`[plane-link] DEAD-LETTER ${j.trackId} seq ${j.seq} (${A.type??"?"}): plane rejected it permanently (${F}) \u2014 kept in ${we}`),R=R.then(async()=>{await Pc.mkdir(gn.dirname(we),{recursive:!0}),await Pc.appendFile(we,JSON.stringify(A)+`
653
- `)}).catch(B=>S.error(`[plane-link] dead-letter write failed: ${B?.message||B}`))}function rb(j,F,A,B=null){if(!Array.isArray(j)||!j.length)return;let Z=new Set,xe=Date.now();for(let Ee of j){let We=ye.get(Ee);We&&(A?(ye.delete(Ee),nb(We,F),(Y[We.trackId]??0)<We.seq&&(Y[We.trackId]=We.seq),Z.add(We.trackId)):(We.nacks++,We.retryAt=xe+Math.max(1e3,Number(B)||U)))}for(let Ee of Z)Mp(Ee);Fa()}function ob(j=Date.now()){let F=1/0;for(let A of ye.values())A.firstSentAt<F&&(F=A.firstSentAt);return F===1/0?0:j-F}function sb(){if(!h||!ye.size)return;let j=Date.now(),F=ob(j);if(F<C||J!=null&&j-J<C||D==="http"&&Le||ve>j)return;se++;let A=Math.min(L*2**(se-1),Y_);if(z==null){z=j-F,S.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(F/1e3)}s with ${ye.size} event(s) in flight (${D} door) \u2014 the plane is not answering appends`);try{x?.({since:z,unacked:ye.size,oldestAgeMs:F,mode:D})}catch(B){S.error(`[plane-link] onDegraded failed: ${B?.message||B}`)}}if(D==="http"){Le=!0,Ce=j+A,S.error(`[plane-link] ingest circuit OPEN (stall #${se}); probing /v1/ingest/health in ${Math.round(A/1e3)}s`);return}ve=j+A,S.error(`[plane-link] closing the link and redialing in ${Math.round(A/1e3)}s (stall redial #${se})`);try{k?.terminate()}catch{}}function Np(){if(!h)return;let j=Date.now();if(D==="http"&&Le)return;let F=[...ye.values()].filter(B=>B.event&&B.retryAt<=j&&!(D==="http"&&Gn.has(B.trackId)));if(!F.length)return;F.sort((B,Z)=>B.trackId===Z.trackId?B.seq-Z.seq:B.trackId<Z.trackId?-1:1),S.log(`[plane-link] re-sending ${F.length} unacked event(s) the plane never confirmed`);let A=D==="http"?St:ao;if(D==="http"){let B=new Map;for(let Z of F)(B.get(Z.trackId)??B.set(Z.trackId,[]).get(Z.trackId)).push(Z);for(let[,Z]of B){if(de>=Cg)return;La(Z.slice(0,A).map(xe=>({trackId:xe.trackId,event:xe.event})))}return}for(let B=0;B<F.length;B+=A){let Z=F.slice(B,B+A).map(xe=>({trackId:xe.trackId,event:xe.event}));if(!La(Z))return}}async function jO(j=null){for(;;){if(!h)return!1;let F=ye.size<_,A=D!=="http"||de<Cg&&!Le&&(!j||!Gn.has(j));if(F&&A)return!0;await new Promise(B=>setTimeout(B,100))}}function Pp(){if(yt=null,!h||!xn.length)return;let j=xn;if(xn=[],D!=="http"){for(let A=0;A<j.length;A+=ao)La(j.slice(A,A+ao));return}let F=new Map;for(let A of j)(F.get(A.trackId)??F.set(A.trackId,[]).get(A.trackId)).push(A);for(let[A,B]of F){if(Gn.has(A)||de>=Cg||Le){xn.push(...B);continue}for(let Z=0;Z<B.length;Z+=St)La(B.slice(Z,Z+St))}xn.length&&!yt&&(yt=setTimeout(Pp,X_),yt.unref?.())}let LO=j=>{let F=new Map;for(let{trackId:A,event:B}of j)(F.get(A)??F.set(A,[]).get(A)).push(B);return[...F].map(([A,B])=>({trackId:A,events:B}))},ps=(j,F,A,{progress:B})=>{let Z=Date.now();for(let{event:xe}of j){let Ee=ye.get(xe.id);Ee&&(Ee.nacks++,Ee.retryAt=Z+Math.max(1e3,A||U))}B&&Fa()};async function FO(j){let F=new Set(j.map(A=>A.trackId));for(let A of F)Gn.add(A);de++;try{let A=await V(`${Re}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:LO(j)}),signal:AbortSignal.timeout($)}),B=(Number(A.headers.get("retry-after"))||0)*1e3;if(A.status===200){let Z=await A.json();St=ao;for(let xe of Z.results??[]){Cp(xe.acked??[]);let Ee=(We,Tt)=>{let qt=new Map;for(let nt of We??[])(qt.get(nt.reason)??qt.set(nt.reason,[]).get(nt.reason)).push(nt.id);for(let[nt,ub]of qt)rb(ub,nt,Tt,Z.retryAfterMs??null)};Ee(xe.rejected,!0),Ee(xe.deferred,!1)}Cp(Z.discarded??[]),Fa();return}if(A.status===429){ps(j,"overloaded",B||5e3,{progress:!0});return}if(A.status===413&&j.length>1){St=Math.max(1,Math.floor(j.length/2)),S.error(`[plane-link] ingest request too large (${j.length} events) \u2014 halving batches to ${St}`),ps(j,"too_large",1e3,{progress:!0});return}if(A.status===413){let Z=ye.get(j[0].event.id);Z&&(ye.delete(Z.event.id),nb(Z,"too_large"),(Y[Z.trackId]??0)<Z.seq&&(Y[Z.trackId]=Z.seq),Mp(Z.trackId)),Fa();return}if(A.status===401||A.status===403){if(Date.now()-pl>=Z_){pl=Date.now();let Z="";try{Z=(await A.json())?.error??""}catch{}S.error(`[plane-link] plane refused ingest (HTTP ${A.status}${Z?`: ${Z}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}ps(j,`http_${A.status}`,6e4,{progress:!1});return}if(A.status===400){S.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${j.length} event(s) for retry; this is a bug, not data`),ps(j,"http_400",6e4,{progress:!1});return}ps(j,`http_${A.status}`,B||5e3,{progress:!1})}catch(A){let B=A?.name==="TimeoutError"||A?.name==="AbortError";B&&j.length>1&&(St=Math.max(1,Math.floor(j.length/2)),S.error(`[plane-link] ingest request of ${j.length} event(s) outlived its ${$} ms deadline \u2014 halving batches to ${St}`)),ps(j,B?"timeout":"network",5e3,{progress:!1})}finally{de--;for(let A of F)Gn.delete(A)}}async function UO(){if(D!=="http"||!Le||!h||Ht)return;let j=Date.now();if(!(Ce>j)){Ht=!0;try{let F=await V(`${Re}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout($)});if(!F.ok)throw new Error(`HTTP ${F.status}`);S.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),Le=!1,Ce=0,ve=Date.now()+$+U+1e3;for(let A of ye.values())A.retryAt=Math.min(A.retryAt,Date.now());Np()}catch(F){se++;let A=Math.min(L*2**(se-1),Y_);Ce=Date.now()+A,S.error(`[plane-link] ingest door still not answering (${F?.message||F}); next probe in ${Math.round(A/1e3)}s`)}finally{Ht=!1}}}function ab(){let j=Date.now();return{mode:D,unacked:ye.size,oldestUnackedAgeMs:ob(j),lastProgressAt:J,degradedSince:z,stallRedials:se,deadLettered:Ne,http:D==="http"?{inFlight:de,circuitOpen:Le,nextProbeInMs:Le?Math.max(0,Ce-j):0,batchCap:St}:null}}async function ib(){if(!i)return;let j;try{j=await i()}catch(A){S.error("[plane-link] metrics sample failed:",A?.message||A);return}let F=null;try{F=c?.()??null}catch{}j&&it({v:ut,ch:"ctl",type:"metrics",metrics:{...j,planeLink:ab(),...F?{delivery:F}:{}}})}function HO(){i&&(Ge&&clearInterval(Ge),ib(),Ge=setInterval(ib,u),Ge.unref?.())}async function WO(){let j;try{j=await o()}catch(F){S.error("[plane-link] backfill listTracks failed:",F?.message||F);return}it({v:ut,ch:"ctl",type:"tracks",ids:j.filter(F=>!F.transferredTo).map(F=>F.id).filter(F=>typeof F=="string")});for(let F of j){if(!h)return;let A;try{A=await q(F)}catch{continue}let B=Ae[F.id]??0,Z=A.filter(Ee=>Ee.seq>B&&typeof Ee.id=="string"),xe=D==="http"?St:ao;for(let Ee=0;Ee<Z.length;Ee+=xe){if(!await jO(F.id))return;let We=Z.slice(Ee,Ee+Math.min(xe,D==="http"?St:ao)).map(Tt=>({trackId:F.id,event:Tt}));if(!La(We))return}}}function cb(j){!h||!j?.trackId||typeof j.id!="string"||(xn.push({trackId:j.trackId,event:j}),yt||(yt=setTimeout(Pp,X_),yt.unref?.()))}let Ua=new Map;async function qO(j){let{reqId:F,method:A,path:B,headers:Z={},body:xe}=j,Ee=Object.fromEntries(Object.entries(Z).filter(([,Tt])=>Tt!=null)),We=new AbortController;Ua.set(F,We);try{if(j.host){await KO(j,Ee,We);return}y&&(Ee["x-bostrat-token"]=y);let Tt=await fetch(g+B,{method:A,headers:Ee,body:xe?Buffer.from(xe,"base64"):void 0,signal:We.signal}),qt=Object.fromEntries(Tt.headers);for(let nt of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete qt[nt];if(qt["content-type"]||(qt["content-type"]="application/octet-stream"),it({v:ut,ch:"control",type:"http_head",reqId:F,status:Tt.status,headers:qt}),Tt.body){for await(let nt of Tt.body)if(!it({v:ut,ch:"control",type:"http_data",reqId:F,data:Buffer.from(nt).toString("base64")}))break}it({v:ut,ch:"control",type:"http_end",reqId:F,error:null})}finally{Ua.delete(F)}}function KO(j,F,A){let{reqId:B,method:Z,path:xe,body:Ee}=j,We=new URL(g);return new Promise(Tt=>{let qt=P2.request({host:We.hostname,port:We.port,method:Z,path:xe,headers:{...F,host:j.host},signal:A.signal},nt=>{let{connection:ub,"keep-alive":C6,"transfer-encoding":N6,upgrade:P6,...GO}=nt.headers;it({v:ut,ch:"control",type:"http_head",reqId:B,status:nt.statusCode||502,headers:GO}),nt.on("data",zO=>{it({v:ut,ch:"control",type:"http_data",reqId:B,data:Buffer.from(zO).toString("base64")})||nt.destroy()}),nt.on("end",()=>{it({v:ut,ch:"control",type:"http_end",reqId:B,error:null}),Tt()}),nt.on("error",()=>{it({v:ut,ch:"control",type:"http_end",reqId:B,error:"view upstream error"}),Tt()})});qt.on("error",nt=>{it({v:ut,ch:"control",type:"http_end",reqId:B,error:nt?.message||"view request failed"}),Tt()}),Ee&&qt.write(Buffer.from(Ee,"base64")),qt.end()})}function lb(){if(v)return;k=new Mg(e,{headers:{authorization:`Bearer ${t}`}}),k.on("open",async()=>{let F=null;try{F=await s?.()||null}catch{F=null}it({v:ut,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:wn,installKind:m,...typeof w=="function"?{updatePolicy:w()}:w?{updatePolicy:w}:{},providers:B2(),...F?{agents:F}:{}})}),k.on("message",F=>{let A;try{A=JSON.parse(F)}catch{return}if(A.ch==="ctl"&&A.type==="hello_ok"){h=!0,N=V_,ne=null,S.log(`[plane-link] connected to plane as ${n}`);try{O?.()}catch{}if(typeof A.hashKey=="string"&&A.hashKey)try{l?.(A.hashKey)}catch{}A.minNodeVersion&&wn&&Dc(wn,A.minNodeVersion)&&S.error(`[plane-link] this node is bostrat-node ${wn}; the plane asks for \u2265${A.minNodeVersion} \u2014 update with: ${Hd(m)}`);try{p?.(typeof A.updatePolicy=="string"?A.updatePolicy:null)}catch{}let B=typeof A.latestNodeVersion=="string"?A.latestNodeVersion:null;if(B&&wn&&Dc(wn,B)&&!P.has(B)){P.add(B),S.log(`[plane-link] bostrat-node ${B} is available (this node runs ${wn}) \u2014 ${Hd(m)}`);try{d?.({current:wn,latest:B,min:A.minNodeVersion??null,installKind:m,required:!!(A.minNodeVersion&&Dc(wn,A.minNodeVersion))})}catch(xe){S.error(`[plane-link] update notice failed: ${xe?.message||xe}`)}}let Z=A.ingest==="http";D=I==="ws"?"ws":I==="http"||Z?"http":"ws",I==="http"&&!Z&&S.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),D==="http"&&S.log("[plane-link] spine rides the HTTPS ingest door"),Le=!1,Ce=0,St=ao,tt&&clearInterval(tt),tt=setInterval(()=>{it({v:ut,ch:"ctl",type:"ping"}),sb(),UO().catch(()=>{}),Np(),xn.length&&!yt&&Pp()},H),tt.unref?.(),HO(),WO().catch(xe=>S.error("[plane-link] backfill failed:",xe?.message||xe));return}if(A.ch==="ctl"&&A.type==="hello_refused"){let B=typeof A.minNodeVersion=="string"?A.minNodeVersion:null,Z=typeof A.latestNodeVersion=="string"?A.latestNodeVersion:null;S.error(`[plane-link] plane REFUSED this node: bostrat-node ${wn??"?"} is below its minimum ${B??"?"} \u2014 ${A.fix||Hd(m)}`),N=J_,ne=0;try{f?.({current:wn,min:B,latest:Z,fix:A.fix||Hd(m),installKind:m})}catch(xe){S.error(`[plane-link] refusal handler failed: ${xe?.message||xe}`)}return}if(A.ch==="ctl"&&A.type==="update_policy"){try{p?.(typeof A.mode=="string"?A.mode:null)}catch{}return}if(A.ch==="ctl"&&A.type==="usage_caps"){xu(A.caps??{},{source:"plane",updatedAt:A.updatedAt??Date.now()}).then(B=>S.log(`[plane-link] spend caps ${Object.keys(B.caps).length?`updated (${Object.keys(B.caps).join(", ")})`:"cleared"} from plane`)).catch(B=>S.error("[plane-link] spend-caps push rejected:",B?.message||B));return}if(A.ch==="ctl"&&A.type==="transferred"&&Array.isArray(A.tracks)){Promise.resolve().then(()=>a?.(A.tracks)).catch(B=>S.error("[plane-link] transfer notice failed:",B?.message||B));return}if(A.ch==="events"&&A.type==="ack"&&Array.isArray(A.ids)){Cp(A.ids);return}if(A.ch==="events"&&A.type==="nack"&&Array.isArray(A.ids)){rb(A.ids,A.reason,A.permanent===!0,A.retryAfterMs??null);return}if(A.ch==="control"&&A.type==="http_open"){qO(A).catch(B=>it({v:ut,ch:"control",type:"http_end",reqId:A.reqId,error:B?.message||"tunnel error"}));return}if(A.ch==="control"&&A.type==="http_cancel"){Ua.get(A.reqId)?.abort();return}if(A.ch==="attach"&&A.type==="open"){let B=new Mg(E+A.path,Array.isArray(A.protocols)?A.protocols:[],A.host?{headers:{host:A.host}}:void 0);W.set(A.streamId,B),G.set(A.streamId,[]),B.on("open",()=>{let xe=G.get(A.streamId)||[];G.delete(A.streamId);for(let{buf:Ee,bin:We}of xe)B.send(Ee,{binary:We})}),B.on("message",(xe,Ee)=>{let We=Ee?xe:Buffer.from(String(xe));it({v:ut,ch:"attach",type:"data",streamId:A.streamId,data:We.toString("base64"),...Ee?{bin:!0}:{}})});let Z=()=>{G.delete(A.streamId),W.delete(A.streamId)&&it({v:ut,ch:"attach",type:"close",streamId:A.streamId})};B.on("close",Z),B.on("error",Z);return}if(A.ch==="attach"&&A.type==="data"){let B=W.get(A.streamId);if(!B)return;let Z=Buffer.from(A.data,"base64"),xe=A.bin===!0,Ee=G.get(A.streamId);Ee?Ee.push({buf:Z,bin:xe}):B.send(Z,{binary:xe});return}if(A.ch==="attach"&&A.type==="close"){let B=W.get(A.streamId);W.delete(A.streamId),G.delete(A.streamId),B?.close();return}});let j=()=>{h&&S.log("[plane-link] disconnected from plane"),h=!1,tt&&(clearInterval(tt),tt=null),Ge&&(clearInterval(Ge),Ge=null),ye.clear(),Y={},xn=[],yt&&(clearTimeout(yt),yt=null),Gn.clear();for(let B of W.values())B.close();W.clear(),G.clear();for(let B of Ua.values())B.abort();if(Ua.clear(),v||ge)return;ne==null&&(ne=Date.now());let F=Date.now()-ne<j2,A=Math.max(F?L2+Math.random()*F2:N,ve-Date.now());ge=setTimeout(()=>{ge=null,lb()},A),ge.unref?.(),F||(N=Math.min(N*2,J_))};k.on("close",j),k.on("error",F=>{let A=/Unexpected server response: (\d+)/.exec(F?.message||"")?.[1];(A==="401"||A==="403")&&Date.now()-pl>=Z_&&(pl=Date.now(),S.error(`[plane-link] plane refused this node's credentials (HTTP ${A}) \u2014 the token was revoked or is unknown to the plane; mint a new node token and update this node's BOSTRAT_PLANE_TOKEN (still retrying)`)),j()})}return Je.on("event",cb),PO().then(lb),{stop:()=>{v=!0,Je.off("event",cb),ge&&clearTimeout(ge),Me&&clearTimeout(Me),tt&&clearInterval(tt),Ge&&clearInterval(Ge),yt&&clearTimeout(yt),it({v:ut,ch:"ctl",type:"bye",reason:"shutdown"}),k?.close()},status:()=>({connected:h,nodeId:n,cursor:{...Ae},inflight:ye.size,...ab()}),_tick:()=>{sb(),Np()}}}zl();var qd=(()=>{try{return X2(import.meta.url)("../package.json").version||null}catch{return null}})(),Z2=process.env.BOSTRAT_STATE_DIR||dt.join(process.env.HOME||J2.tmpdir(),".bostrat"),rI=dt.join(Z2,"self-update"),Kd=dt.join(rI,"status.json"),Q2=1440*6e4,eH=6e4,Bc=new Set(["npm-global","git-checkout"]);function oI({kind:e=ts(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:Bc.has(e)?e==="git-checkout"||tH(t)?"auto":"prompt":"off"}function tH(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var jt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function nH({kind:e,to:t,from:n=qd,statusFile:r=Kd,logFile:o=dt.join(rI,"last.log"),port:s=Number(process.env.PORT)||3362,npmPrefix:a=null,serviceName:i=process.platform==="darwin"?"com.bostrat.node":"bostrat-node.service",uid:c=typeof process.getuid=="function"?process.getuid():0,liveDir:l=process.env.BOSTRAT_LIVE_CHECKOUT||dt.resolve(dt.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!Bc.has(e))throw new Error(`self-update: install kind "${e}" is not actionable here`);if(!/^\d+\.\d+\.\d+$/.test(String(t)))throw new Error(`self-update: bad target version "${t}"`);if(n&&!/^\d+\.\d+\.\d+$/.test(String(n)))throw new Error(`self-update: bad current version "${n}"`);let d=(g,y="")=>`write_status ${jt(g)} ${y}`,p=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${jt(i)}`,f=`
656
+ `);$2=new Set(["claude","codex","cursor"]);Fc=new Set,R2=e=>Fc.has(e);O2=9e4;q_={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};fg=new Map;bg=120;Jg=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:$o(e.hookToken),createdAt:Date.now()});hs=new Map,La=e=>hs.get(e)||(Nt?de(Nt,e)?.handoff:null)||null;Xg=6e4,gn=(e,t,n=15e3)=>Zd("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),Yd=new Map,Zg=e=>Yd.get(e)||null;L2=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,200}$/;Kd=new Map;H2=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,W2=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,Pa=z.join(qn,"worktrees"),$a=[Dc,Gd],Pt=new Map,q2=e=>Pt.get(e)||(Nt?Nt.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,ys=e=>{let t=new Map([...Pt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=Nt?de(Nt,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)},mp=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});Vc=e=>pI(e.trackId,e.id,mp(e));wp=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",Hc=class extends Error{}});ut();import Ee from"node:path";import kt from"node:fs";import JK from"node:readline";import{fileURLToPath as YK}from"node:url";import zt from"express";import XK from"node:http";import ZK from"node:https";import vl from"node:os";import{randomUUID as QK}from"node:crypto";import{WebSocketServer as eG}from"ws";ut();import HN from"node-pty";async function h0(e,t,n={}){if(!De(t)){du(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await jr()){du(e,`host tmux server not running on ${jt}`),e.close(1011,"tmux server unavailable");return}if(!await ye(t)){du(e,`session "${t}" not found`),e.close(1008,"session not found");return}let r=f0(n.cols,120,m0),o=f0(n.rows,32,w0),s;try{s=HN.spawn(ee,["-S",jt,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){du(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&Jf(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(Jf(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"&&GN(i.cols,i.rows))try{s.resize(Math.min(500,i.cols|0),Math.min(500,i.rows|0))}catch{}}}),e.on("close",()=>{try{s.kill()}catch{}KN(t)})}var WN=6,qN=250;async function KN(e,t=WN,n=qN){for(let r=0;r<t;r++){if(await Bo(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var m0=20,w0=6;function GN(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=m0&&Number(t)>=w0}function f0(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function Jf(e,t){try{e.send(JSON.stringify(t))}catch{}}function du(e,t){Jf(e,{type:"error",message:t})}function g0(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}}ln();fu();Dh();dr();import{createRequire as tG}from"node:module";var eH=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function ay({tracks:e=[],views:t=[],queuedOf:n=()=>[],jobsOf:r=()=>[],prPendingOf:o=()=>[]}={}){let s=[];for(let a of e)!a||a.archivedAt&&!a.archiving||a.transferredTo||(a.working&&s.push(`working:${a.id}`),a.prompted&&s.push(`prompted:${a.id}`),(n(a.id)??[]).length&&s.push(`queued:${a.id}`),(a.boxes||[]).some(i=>i?.role==="subtask"&&i?.state==="live")&&s.push(`subtask:${a.id}`),(r(a.id)??[]).length&&s.push(`job:${a.id}`),Object.values(a.subtasks||{}).some(eH)&&s.push(`merge-back:${a.id}`),(o(a.id)??[]).length&&s.push(`pr:${a.id}`));return t.some(a=>a?.state==="live"||a?.state==="starting")&&s.push("views"),{busy:s.length>0,reasons:s}}he();Xh();ut();import oH from"node:fs/promises";import iy from"node:fs/promises";var tH=100;async function nH(e){let t;try{t=await iy.readFile(`/proc/${e}/stat`,"utf8")}catch{return null}let n=t.lastIndexOf(")");if(n<0)return null;let r=t.slice(n+2).split(" "),o=Number(r[1]),s=Number(r[11])+Number(r[12]);return!Number.isFinite(o)||!Number.isFinite(s)?null:{ppid:o,cpuMs:s/tH*1e3,ioBytes:await rH(e)}}async function rH(e){let t;try{t=await iy.readFile(`/proc/${e}/io`,"utf8")}catch{return 0}let n=r=>Number(t.match(new RegExp(`^${r}: (\\d+)$`,"m"))?.[1]||0);return n("rchar")+n("wchar")}async function yI(e){let t=[...new Set((e||[]).map(Number).filter(l=>Number.isFinite(l)&&l>0))];if(!t.length)return{procs:0,cpuMs:0,ioBytes:0};let n;try{n=await iy.readdir("/proc")}catch{return null}let r=new Map;await Promise.all(n.map(async l=>{if(!/^\d+$/.test(l))return;let u=await nH(l);u&&r.set(Number(l),u)}));let o=new Map;for(let[l,u]of r)o.has(u.ppid)||o.set(u.ppid,[]),o.get(u.ppid).push(l);let s=new Set,a=t.filter(l=>r.has(l));for(let l of a)s.add(l);let i=0,c=0;for(let l=0;l<a.length;l++){let u=a[l];i+=r.get(u).cpuMs,c+=r.get(u).ioBytes;for(let d of o.get(u)||[])s.has(d)||(s.add(d),a.push(d))}return{procs:s.size,cpuMs:Math.round(i),ioBytes:c}}var sH=Number(process.env.BOSTRAT_JOB_CHECK_MS)||15*6e4,aH=Number(process.env.BOSTRAT_JOB_STALL_CHECKS)||3,iH=Number(process.env.BOSTRAT_JOB_CPU_RATE_MIN)||25,cH=Number(process.env.BOSTRAT_JOB_IO_RATE_MIN)||64*1024,lH=5*6e4,kI={readOpenJobs:Wv,statFile:async e=>{try{let t=await oH.stat(e);return{size:t.size,mtimeMs:Math.round(t.mtimeMs)}}catch{return null}},updatedAt:e=>Vr(e.agent).updatedAt(e),panePids:l0,treeStats:yI,appendEvent:C},yn=new Map,bI=new Map,cy=new Map,ly=(e,t,n)=>`${e}|${t}|${n}`;function xI(e){let t=[];for(let n of e||[])if(!(!n||n.archivedAt&&!n.archiving||n.transferredTo))for(let r of n.boxes||[])r?.state==="live"&&r.name&&t.push({track:n,box:r});return t}async function vI(e,t,n){let r=null;try{r=await n.updatedAt(e)}catch{r=null}let o=bI.get(e.name);if(o&&o.mtime===r&&t-o.at<lH)return o.jobs;let s=[];try{s=await n.readOpenJobs(e)}catch{s=[]}return bI.set(e.name,{at:t,mtime:r,jobs:s}),s}async function uH(e,t,n){let r=await n.panePids(e.name),o=r.length?await n.treeStats(r):null,s=null;try{s=await n.updatedAt(e)}catch{s=null}return{at:t,cpuMs:o?.cpuMs??null,ioBytes:o?.ioBytes??null,procs:o?.procs??null,mtime:s}}async function dH(e,t){return e?.outputFile?await t.statFile(e.outputFile):null}function pH(e,t){if(!e)return!0;let n=Math.max(1,(t.at-e.at)/1e3);return t.mtime!=null&&e.mtime!=null&&t.mtime>e.mtime||t.procs!=null&&e.procs!=null&&t.procs>e.procs||t.cpuMs!=null&&e.cpuMs!=null&&(t.cpuMs-e.cpuMs)/n>=iH||t.ioBytes!=null&&e.ioBytes!=null&&(t.ioBytes-e.ioBytes)/n>=cH}function SI(e,t,n,r){let o=[];for(let s of n){let a=ly(e.id,t.name,s.id),i=yn.get(a);i?i.job=s:yn.set(a,{trackId:e.id,boxName:t.name,agent:t.agent||null,job:s,firstSeenAt:r,quiet:0,stalled:!1}),o.push(a)}return o}async function AI(e,{now:t=Date.now(),deps:n=kI}={}){let r=new Map,o=new Set;for(let{track:s,box:a}of xI(e)){let i=await vI(a,t,n);for(let l of i)o.add(ly(s.id,a.name,l.id));let c=SI(s,a,i,t).filter(l=>!yn.get(l).stalled).map(l=>yn.get(l).job);c.length&&r.set(s.id,[...r.get(s.id)??[],...c])}for(let s of[...yn.keys()])o.has(s)||yn.delete(s);return r}async function fH(e,{now:t=Date.now(),deps:n=kI}={}){let r={checked:0,progressing:0,quiet:0,stalled:[]},o=xI(e),s=new Set(o.map(({box:a})=>a.name));for(let[a,i]of[...yn])s.has(i.boxName)||yn.delete(a);for(let{track:a,box:i}of o){let c=await vI(i,t,n),l=new Set(c.map(w=>ly(a.id,i.name,w.id)));for(let[w,h]of[...yn])h.boxName===i.name&&!l.has(w)&&yn.delete(w);if(!c.length){cy.delete(i.name);continue}let u=SI(a,i,c,t),d=await uH(i,t,n),p=cy.get(i.name);cy.set(i.name,d);let f=pH(p,d);for(let w of u){let h=yn.get(w);r.checked++;let g=await dH(h.job,n),y=!!g&&!!h.file&&(g.size>h.file.size||g.mtimeMs>h.file.mtimeMs),x=!!g&&!h.file;if(h.file=g??h.file,f||y||x){h.quiet=0,h.lastProgressAt=t,h.stalled=!1,r.progressing++;continue}if(h.stalled||(h.quiet++,r.quiet++,h.quiet<aH))continue;h.stalled=!0,h.stalledAt=t,r.stalled.push(w);let I=t-(h.lastProgressAt??h.firstSeenAt);try{await n.appendEvent(a,{type:"job.stalled",actor:"orchestrator",source:"orchestrator",boxId:i.name,provider:i.agent||null,payload:{id:h.job.id,kind:h.job.kind||"agent",name:h.job.name||null,detail:h.job.detail||null,startedTs:h.job.ts??h.firstSeenAt,quietMs:I,checks:h.quiet}})}catch{}console.log(`[job-watch] ${a.id}/${i.name} job ${h.job.id} (${h.job.name||h.job.kind}) quiet for ${Math.round(I/6e4)}m over ${h.quiet} check(s) \u2014 released; the node may sleep`)}}return r}function TI({listTracks:e,intervalMs:t=sH}={}){let n=!1,o=setInterval(async()=>{if(!n){n=!0;try{await fH(await e())}catch(s){console.error(`[job-watch] sweep: ${s?.message||s}`)}finally{n=!1}}},t);return o.unref?.(),o}he();Ac();Mn();vd();Yt();var yp=60*6e4,hH=1440*6e4,mH=new Set(["merged","closed","lost"]),Jc=(e,t,n)=>Number.isFinite(Number(e))&&n-Number(e)<=t;function wH({trackId:e,shipPending:t=null,links:n=[],observers:r=0,now:o=Date.now()}={}){let s=[];t&&Number.isFinite(Number(t.ts))&&o-Number(t.ts)<=Pw&&s.push("ship"),r>0&&s.push("create-net");for(let a of n||[]){if(!a||mH.has(a.state))continue;let i=[a.ciFix,a.reconcile,a.ciFixAwait,a.reconcileAwait];if(!(a.trackId===e||i.some(d=>d?.trackId===e)))continue;let l=a.number??"?";a.ciFix&&Jc(a.ciFix.delegatedAt,yp,o)&&s.push(`ci-fix#${l}`),a.reconcile&&Jc(a.reconcile.delegatedAt,yp,o)&&s.push(`reconcile#${l}`),a.ciFixAwait&&Jc(a.ciFixAwait.since,yp,o)&&s.push(`ci-fix-await#${l}`),a.reconcileAwait&&Jc(a.reconcileAwait.since,yp,o)&&s.push(`reconcile-await#${l}`);let u=a.autoMerge?.armedAt??a.armedAt??null;a.trackId===e&&(a.autoMerge||a.armedAt)&&Jc(u,hH,o)&&s.push(`auto-merge#${l}`)}return s}var bp=new Map;Je.on("event",e=>{e?.trackId&&bp.delete(e.trackId)});async function gH(e){if(bp.has(e.id))return bp.get(e.id);let t=await K(e).catch(()=>[]),n=Sa(t,-1/0);return bp.set(e.id,n),n}async function EI(e,{now:t=Date.now()}={}){let n=new Map,r=await pn().catch(()=>[]);for(let o of e||[]){if(!o||je(o))continue;let s=wH({trackId:o.id,shipPending:await gH(o),links:r,observers:hT(o.id),now:t});s.length&&n.set(o.id,s)}return n}sg();import jI from"node:fs";import wo from"node:fs/promises";import PH from"node:os";import ft from"node:path";import{spawn as DH}from"node:child_process";import{createRequire as BH}from"node:module";he();qu();import Fa from"node:fs";import Xc from"node:fs/promises";import kH from"node:http";import Wt from"node:path";import xp from"node:os";import{createRequire as xH}from"node:module";import dy from"ws";import yH from"node:path";import bH from"node:os";var Yc=process.env.BOSTRAT_STATE_DIR||yH.join(process.env.HOME||bH.tmpdir(),".bostrat");function uy(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 _I(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=uy(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function II(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}Sf();var bn=(()=>{try{return xH(import.meta.url)("../package.json").version||null}catch{return null}})(),fy=process.env.BOSTRAT_STATE_DIR||Wt.join(process.env.HOME||xp.tmpdir(),".bostrat"),PI=Wt.join(fy,"plane-link","removed.json");function $I(e){return typeof e!="string"||e.length<8?"\u2022\u2022\u2022\u2022":`${e.slice(0,6)}\u2026${e.slice(-4)}`}function vH(e=PI){try{let t=JSON.parse(Fa.readFileSync(e,"utf8"));return t&&typeof t=="object"?t:null}catch{return null}}function bs({env:e=process.env,pkgDir:t=Wt.resolve(Wt.dirname(new URL(import.meta.url).pathname),".."),exists:n=Fa.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(Wt.join(t,"..",".git"))?"git-checkout":"dev"}function Zc(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 kp(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 SH({home:e=process.env.HOME||xp.homedir(),env:t=process.env}={}){let n=r=>{try{return Fa.statSync(r),!0}catch{return!1}};return{claude:n(Wt.join(e,".claude",".credentials.json")),codex:n(Wt.join(t.CODEX_HOME||Wt.join(e,".codex"),"auth.json"))}}var lt=1,RI=1e3,OI=3e4,AH=6e4,TH=1500,EH=500,mo=100,_H=2e3,IH=25e3,$H=6e4,DI=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},RH=DI(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),OH=3e4,MI=10*6e4,MH=400,CI=250,CH=DI(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),py=4,NH=6e4,NI=6e4;function BI({url:e,token:t,nodeId:n=xp.hostname(),name:r=xp.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,deliverySample:c=null,onHashKey:l=null,metricsMs:u=NH,onUpdateAvailable:d=null,onUpdatePolicy:p=null,onHelloRefused:f=null,updatePolicy:w=null,installKind:h=bs(),selfUrl:g=`http://127.0.0.1:${process.env.PORT||3362}`,apiToken:y=null,removedMarkerFile:x=PI,onRemoved:b=null,onDegraded:I=null,onRecovered:_=null,onConnected:N=null,ingestMode:U=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:j=RH,unackedRetryMs:T=$H,pingMs:R=IH,maxInflightEvents:L=MH,httpTimeoutMs:V=CH,stallBackoffMinMs:O=OH,fetchImpl:S=globalThis.fetch,log:M=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=II(e);let H=g.replace(/^http/,"ws"),W=new Set,te=new Map,pe=new Map,Ie=Wt.join(fy,"plane-link","cursor.json"),Oe=Wt.join(fy,"plane-link","dead-letter.ndjson"),re=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),Ne={},X={},G=new Map,fe=null,be=null,xe=0,Ke=0,le=0,$=Promise.resolve(),Y="ws",Ce=0,Ve=!1,xt=0,Er=!1,_t=mo,_r=new Set,k=[],m=null,v=null,P=!1,ae=!1,ge=RI,Me=null,ht=null,Qe=null,st=null,Vn=null,uf=!1,$l=0,ti=!1,Ir=vH(x);if(Ir)if(Ir.tokenPreview===$I(t))ti=!0,vf({reason:Ir.reason??"removed",at:Ir.at??null,nodeId:Ir.nodeId??n}),M.error(`[plane-link] this node was REMOVED from the plane (${Ir.reason??"removed"}${Ir.at?` at ${new Date(Ir.at).toISOString()}`:""}) \u2014 not dialing. Re-provision it with a new node token, or delete ${x} to force a dial.`);else try{Fa.unlinkSync(x),M.log("[plane-link] stale removed-marker discarded \u2014 the node token changed")}catch{}function df({reason:D="removed",at:F=Date.now(),via:A="ctl"}={}){if(!ti){ti=!0,vf({reason:D,at:F,nodeId:n,via:A});try{Fa.mkdirSync(Wt.dirname(x),{recursive:!0}),Fa.writeFileSync(x,JSON.stringify({at:F,reason:D,via:A,nodeId:n,tokenPreview:$I(t)},null,2))}catch(B){M.error(`[plane-link] could not write ${x}: ${B?.message||B}`)}M.error(`[plane-link] the plane REMOVED this node (${D}, via ${A}) \u2014 going dormant: no more dials, ingest or broker calls. Re-provision with a new node token to reconnect; the box and its data are untouched.`);try{b?.({reason:D,at:F,via:A})}catch{}Kb({bye:!1})}}async function gM(){try{Ne=JSON.parse(await Xc.readFile(Ie,"utf8"))}catch{Ne={}}}function yM(){uf=!0,!Qe&&(Qe=setTimeout(async()=>{if(Qe=null,!!uf){uf=!1;try{await Xc.mkdir(Wt.dirname(Ie),{recursive:!0}),await Xc.writeFile(Ie,JSON.stringify(Ne))}catch(D){M.error("[plane-link] cursor flush failed:",D?.message||D)}}},_H),Qe.unref?.())}function at(D){return!v||v.readyState!==dy.OPEN?!1:(v.send(JSON.stringify(D)),!0)}function ni(D){let F=Date.now();for(let{trackId:A,event:B}of D){let Q=G.get(B.id);G.set(B.id,{trackId:A,seq:B.seq,event:B,sentAt:F,firstSentAt:Q?.firstSentAt??F,retryAt:F+T,tries:(Q?.tries??0)+1,nacks:Q?.nacks??0})}return Y==="http"?(vM(D),!0):at({v:lt,ch:"events",type:"append",events:D})}function bM(D){let F=null;for(let A of G.values())A.trackId===D&&(F==null||A.seq<F)&&(F=A.seq);return F}function pf(D){let F=X[D];if(F==null)return;let A=bM(D),B=A==null?F:Math.min(F,A-1);B>(Ne[D]??0)&&(Ne[D]=B,yM())}function ri(){if(fe=Date.now(),be!=null){let D=Date.now()-be;M.log(`[plane-link] spine sync recovered after ${Math.round(D/1e3)}s degraded (${xe} stall redial(s))`);let F=be;be=null,xe=0,Ke=0,Ve=!1,xt=0;try{_?.({since:F,downMs:D})}catch(A){M.error(`[plane-link] onRecovered failed: ${A?.message||A}`)}}}function ff(D){if(!Array.isArray(D)||!D.length)return;let F=new Set;for(let A of D){let B=G.get(A);B&&(G.delete(A),(X[B.trackId]??0)<B.seq&&(X[B.trackId]=B.seq),F.add(B.trackId))}for(let A of F)pf(A);ri()}function Bb(D,F){le++;let A={at:Date.now(),trackId:D.trackId,seq:D.seq,id:D.event?.id??null,type:D.event?.type??null,reason:F,event:D.event??null};M.error(`[plane-link] DEAD-LETTER ${D.trackId} seq ${D.seq} (${A.type??"?"}): plane rejected it permanently (${F}) \u2014 kept in ${Oe}`),$=$.then(async()=>{await Xc.mkdir(Wt.dirname(Oe),{recursive:!0}),await Xc.appendFile(Oe,JSON.stringify(A)+`
657
+ `)}).catch(B=>M.error(`[plane-link] dead-letter write failed: ${B?.message||B}`))}function jb(D,F,A,B=null){if(!Array.isArray(D)||!D.length)return;let Q=new Set,ke=Date.now();for(let Se of D){let He=G.get(Se);He&&(A?(G.delete(Se),Bb(He,F),(X[He.trackId]??0)<He.seq&&(X[He.trackId]=He.seq),Q.add(He.trackId)):(He.nacks++,He.retryAt=ke+Math.max(1e3,Number(B)||T)))}for(let Se of Q)pf(Se);ri()}function Lb(D=Date.now()){let F=1/0;for(let A of G.values())A.firstSentAt<F&&(F=A.firstSentAt);return F===1/0?0:D-F}function Fb(){if(!P||!G.size)return;let D=Date.now(),F=Lb(D);if(F<j||fe!=null&&D-fe<j||Y==="http"&&Ve||Ke>D)return;xe++;let A=Math.min(O*2**(xe-1),MI);if(be==null){be=D-F,M.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(F/1e3)}s with ${G.size} event(s) in flight (${Y} door) \u2014 the plane is not answering appends`);try{I?.({since:be,unacked:G.size,oldestAgeMs:F,mode:Y})}catch(B){M.error(`[plane-link] onDegraded failed: ${B?.message||B}`)}}if(Y==="http"){Ve=!0,xt=D+A,M.error(`[plane-link] ingest circuit OPEN (stall #${xe}); probing /v1/ingest/health in ${Math.round(A/1e3)}s`);return}Ke=D+A,M.error(`[plane-link] closing the link and redialing in ${Math.round(A/1e3)}s (stall redial #${xe})`);try{v?.terminate()}catch{}}function hf(){if(!P)return;let D=Date.now();if(Y==="http"&&Ve)return;let F=[...G.values()].filter(B=>B.event&&B.retryAt<=D&&!(Y==="http"&&_r.has(B.trackId)));if(!F.length)return;F.sort((B,Q)=>B.trackId===Q.trackId?B.seq-Q.seq:B.trackId<Q.trackId?-1:1),M.log(`[plane-link] re-sending ${F.length} unacked event(s) the plane never confirmed`);let A=Y==="http"?_t:mo;if(Y==="http"){let B=new Map;for(let Q of F)(B.get(Q.trackId)??B.set(Q.trackId,[]).get(Q.trackId)).push(Q);for(let[,Q]of B){if(Ce>=py)return;ni(Q.slice(0,A).map(ke=>({trackId:ke.trackId,event:ke.event})))}return}for(let B=0;B<F.length;B+=A){let Q=F.slice(B,B+A).map(ke=>({trackId:ke.trackId,event:ke.event}));if(!ni(Q))return}}async function kM(D=null){for(;;){if(!P)return!1;let F=G.size<L,A=Y!=="http"||Ce<py&&!Ve&&(!D||!_r.has(D));if(F&&A)return!0;await new Promise(B=>setTimeout(B,100))}}function mf(){if(m=null,!P||!k.length)return;let D=k;if(k=[],Y!=="http"){for(let A=0;A<D.length;A+=mo)ni(D.slice(A,A+mo));return}let F=new Map;for(let A of D)(F.get(A.trackId)??F.set(A.trackId,[]).get(A.trackId)).push(A);for(let[A,B]of F){if(_r.has(A)||Ce>=py||Ve){k.push(...B);continue}for(let Q=0;Q<B.length;Q+=_t)ni(B.slice(Q,Q+_t))}k.length&&!m&&(m=setTimeout(mf,CI),m.unref?.())}let xM=D=>{let F=new Map;for(let{trackId:A,event:B}of D)(F.get(A)??F.set(A,[]).get(A)).push(B);return[...F].map(([A,B])=>({trackId:A,events:B}))},Io=(D,F,A,{progress:B})=>{let Q=Date.now();for(let{event:ke}of D){let Se=G.get(ke.id);Se&&(Se.nacks++,Se.retryAt=Q+Math.max(1e3,A||T))}B&&ri()};async function vM(D){let F=new Set(D.map(A=>A.trackId));for(let A of F)_r.add(A);Ce++;try{let A=await S(`${re}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:xM(D)}),signal:AbortSignal.timeout(V)}),B=(Number(A.headers.get("retry-after"))||0)*1e3;if(A.status===200){let Q=await A.json();_t=mo;for(let ke of Q.results??[]){ff(ke.acked??[]);let Se=(He,It)=>{let Vt=new Map;for(let nt of He??[])(Vt.get(nt.reason)??Vt.set(nt.reason,[]).get(nt.reason)).push(nt.id);for(let[nt,Gb]of Vt)jb(Gb,nt,It,Q.retryAfterMs??null)};Se(ke.rejected,!0),Se(ke.deferred,!1)}ff(Q.discarded??[]),ri();return}if(A.status===429){Io(D,"overloaded",B||5e3,{progress:!0});return}if(A.status===413&&D.length>1){_t=Math.max(1,Math.floor(D.length/2)),M.error(`[plane-link] ingest request too large (${D.length} events) \u2014 halving batches to ${_t}`),Io(D,"too_large",1e3,{progress:!0});return}if(A.status===413){let Q=G.get(D[0].event.id);Q&&(G.delete(Q.event.id),Bb(Q,"too_large"),(X[Q.trackId]??0)<Q.seq&&(X[Q.trackId]=Q.seq),pf(Q.trackId)),ri();return}if(A.status===410){df({reason:"removed",via:"410"}),Io(D,"http_410",6e4,{progress:!1});return}if(A.status===401||A.status===403){let{tripped:Q,holdMs:ke}=Ns();if(Q&&M.error(`[plane-link] holding every plane call for ${Math.round(ke/6e4)} min \u2014 the ingest door refused this node's token three times in a row`),Date.now()-$l>=NI){$l=Date.now();let Se="";try{Se=(await A.json())?.error??""}catch{}M.error(`[plane-link] plane refused ingest (HTTP ${A.status}${Se?`: ${Se}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}Io(D,`http_${A.status}`,Math.max(6e4,ui()),{progress:!1});return}if(A.status===400){M.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${D.length} event(s) for retry; this is a bug, not data`),Io(D,"http_400",6e4,{progress:!1});return}Io(D,`http_${A.status}`,B||5e3,{progress:!1})}catch(A){let B=A?.name==="TimeoutError"||A?.name==="AbortError";B&&D.length>1&&(_t=Math.max(1,Math.floor(D.length/2)),M.error(`[plane-link] ingest request of ${D.length} event(s) outlived its ${V} ms deadline \u2014 halving batches to ${_t}`)),Io(D,B?"timeout":"network",5e3,{progress:!1})}finally{Ce--;for(let A of F)_r.delete(A)}}async function SM(){if(Y!=="http"||!Ve||!P||Er)return;let D=Date.now();if(!(xt>D||Ps(D))){Er=!0;try{let F=await S(`${re}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(V)});if(!F.ok)throw new Error(`HTTP ${F.status}`);M.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),Ve=!1,xt=0,Ke=Date.now()+V+T+1e3;for(let A of G.values())A.retryAt=Math.min(A.retryAt,Date.now());hf()}catch(F){xe++;let A=Math.min(O*2**(xe-1),MI);xt=Date.now()+A,M.error(`[plane-link] ingest door still not answering (${F?.message||F}); next probe in ${Math.round(A/1e3)}s`)}finally{Er=!1}}}function Ub(){let D=Date.now();return{mode:Y,unacked:G.size,oldestUnackedAgeMs:Lb(D),lastProgressAt:fe,degradedSince:be,stallRedials:xe,deadLettered:le,http:Y==="http"?{inFlight:Ce,circuitOpen:Ve,nextProbeInMs:Ve?Math.max(0,xt-D):0,batchCap:_t}:null}}async function Hb(){if(!i)return;let D;try{D=await i()}catch(A){M.error("[plane-link] metrics sample failed:",A?.message||A);return}let F=null;try{F=c?.()??null}catch{}D&&at({v:lt,ch:"ctl",type:"metrics",metrics:{...D,planeLink:Ub(),...F?{delivery:F}:{}}})}function AM(){i&&(Vn&&clearInterval(Vn),Hb(),Vn=setInterval(Hb,u),Vn.unref?.())}async function TM(){let D;try{D=await o()}catch(F){M.error("[plane-link] backfill listTracks failed:",F?.message||F);return}at({v:lt,ch:"ctl",type:"tracks",ids:D.filter(F=>!F.transferredTo).map(F=>F.id).filter(F=>typeof F=="string")});for(let F of D){if(!P)return;let A;try{A=await K(F)}catch{continue}let B=Ne[F.id]??0,Q=A.filter(Se=>Se.seq>B&&typeof Se.id=="string"),ke=Y==="http"?_t:mo;for(let Se=0;Se<Q.length;Se+=ke){if(!await kM(F.id))return;let He=Q.slice(Se,Se+Math.min(ke,Y==="http"?_t:mo)).map(It=>({trackId:F.id,event:It}));if(!ni(He))return}}}function Wb(D){!P||!D?.trackId||typeof D.id!="string"||(k.push({trackId:D.trackId,event:D}),m||(m=setTimeout(mf,CI),m.unref?.()))}let oi=new Map;async function EM(D){let{reqId:F,method:A,path:B,headers:Q={},body:ke}=D,Se=Object.fromEntries(Object.entries(Q).filter(([,It])=>It!=null)),He=new AbortController;oi.set(F,He);try{if(D.host){await _M(D,Se,He);return}y&&(Se["x-bostrat-token"]=y);let It=await fetch(g+B,{method:A,headers:Se,body:ke?Buffer.from(ke,"base64"):void 0,signal:He.signal}),Vt=Object.fromEntries(It.headers);for(let nt of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete Vt[nt];if(Vt["content-type"]||(Vt["content-type"]="application/octet-stream"),at({v:lt,ch:"control",type:"http_head",reqId:F,status:It.status,headers:Vt}),It.body){for await(let nt of It.body)if(!at({v:lt,ch:"control",type:"http_data",reqId:F,data:Buffer.from(nt).toString("base64")}))break}at({v:lt,ch:"control",type:"http_end",reqId:F,error:null})}finally{oi.delete(F)}}function _M(D,F,A){let{reqId:B,method:Q,path:ke,body:Se}=D,He=new URL(g);return new Promise(It=>{let Vt=kH.request({host:He.hostname,port:He.port,method:Q,path:ke,headers:{...F,host:D.host},signal:A.signal},nt=>{let{connection:Gb,"keep-alive":bG,"transfer-encoding":kG,upgrade:xG,...IM}=nt.headers;at({v:lt,ch:"control",type:"http_head",reqId:B,status:nt.statusCode||502,headers:IM}),nt.on("data",$M=>{at({v:lt,ch:"control",type:"http_data",reqId:B,data:Buffer.from($M).toString("base64")})||nt.destroy()}),nt.on("end",()=>{at({v:lt,ch:"control",type:"http_end",reqId:B,error:null}),It()}),nt.on("error",()=>{at({v:lt,ch:"control",type:"http_end",reqId:B,error:"view upstream error"}),It()})});Vt.on("error",nt=>{at({v:lt,ch:"control",type:"http_end",reqId:B,error:nt?.message||"view request failed"}),It()}),Se&&Vt.write(Buffer.from(Se,"base64")),Vt.end()})}function qb(){if(ae||ti)return;v=new dy(e,{headers:{authorization:`Bearer ${t}`}}),v.on("open",async()=>{let F=null;try{F=await s?.()||null}catch{F=null}at({v:lt,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:bn,installKind:h,...typeof w=="function"?{updatePolicy:w()}:w?{updatePolicy:w}:{},providers:SH(),...F?{agents:F}:{}})}),v.on("message",F=>{let A;try{A=JSON.parse(F)}catch{return}if(A.ch==="ctl"&&A.type==="hello_ok"){P=!0,ge=RI,Me=null,ek(),M.log(`[plane-link] connected to plane as ${n}`);try{N?.()}catch{}if(typeof A.hashKey=="string"&&A.hashKey)try{l?.(A.hashKey)}catch{}A.minNodeVersion&&bn&&Zc(bn,A.minNodeVersion)&&M.error(`[plane-link] this node is bostrat-node ${bn}; the plane asks for \u2265${A.minNodeVersion} \u2014 update with: ${kp(h)}`);try{p?.(typeof A.updatePolicy=="string"?A.updatePolicy:null)}catch{}let B=typeof A.latestNodeVersion=="string"?A.latestNodeVersion:null;if(B&&bn&&Zc(bn,B)&&!W.has(B)){W.add(B),M.log(`[plane-link] bostrat-node ${B} is available (this node runs ${bn}) \u2014 ${kp(h)}`);try{d?.({current:bn,latest:B,min:A.minNodeVersion??null,installKind:h,required:!!(A.minNodeVersion&&Zc(bn,A.minNodeVersion))})}catch(ke){M.error(`[plane-link] update notice failed: ${ke?.message||ke}`)}}let Q=A.ingest==="http";Y=U==="ws"?"ws":U==="http"||Q?"http":"ws",U==="http"&&!Q&&M.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),Y==="http"&&M.log("[plane-link] spine rides the HTTPS ingest door"),Ve=!1,xt=0,_t=mo,st&&clearInterval(st),st=setInterval(()=>{at({v:lt,ch:"ctl",type:"ping"}),Fb(),SM().catch(()=>{}),hf(),k.length&&!m&&mf()},R),st.unref?.(),AM(),TM().catch(ke=>M.error("[plane-link] backfill failed:",ke?.message||ke));return}if(A.ch==="ctl"&&A.type==="hello_refused"){let B=typeof A.minNodeVersion=="string"?A.minNodeVersion:null,Q=typeof A.latestNodeVersion=="string"?A.latestNodeVersion:null;M.error(`[plane-link] plane REFUSED this node: bostrat-node ${bn??"?"} is below its minimum ${B??"?"} \u2014 ${A.fix||kp(h)}`),ge=OI,Me=0;try{f?.({current:bn,min:B,latest:Q,fix:A.fix||kp(h),installKind:h})}catch(ke){M.error(`[plane-link] refusal handler failed: ${ke?.message||ke}`)}return}if(A.ch==="ctl"&&A.type==="removed"){at({v:lt,ch:"ctl",type:"removed_ack",nodeId:n}),df({reason:typeof A.reason=="string"?A.reason:"removed",at:Number(A.at)||Date.now(),via:"ctl"});return}if(A.ch==="ctl"&&A.type==="update_policy"){try{p?.(typeof A.mode=="string"?A.mode:null)}catch{}return}if(A.ch==="ctl"&&A.type==="usage_caps"){Wu(A.caps??{},{source:"plane",updatedAt:A.updatedAt??Date.now()}).then(B=>M.log(`[plane-link] spend caps ${Object.keys(B.caps).length?`updated (${Object.keys(B.caps).join(", ")})`:"cleared"} from plane`)).catch(B=>M.error("[plane-link] spend-caps push rejected:",B?.message||B));return}if(A.ch==="ctl"&&A.type==="transferred"&&Array.isArray(A.tracks)){Promise.resolve().then(()=>a?.(A.tracks)).catch(B=>M.error("[plane-link] transfer notice failed:",B?.message||B));return}if(A.ch==="events"&&A.type==="ack"&&Array.isArray(A.ids)){ff(A.ids);return}if(A.ch==="events"&&A.type==="nack"&&Array.isArray(A.ids)){jb(A.ids,A.reason,A.permanent===!0,A.retryAfterMs??null);return}if(A.ch==="control"&&A.type==="http_open"){EM(A).catch(B=>at({v:lt,ch:"control",type:"http_end",reqId:A.reqId,error:B?.message||"tunnel error"}));return}if(A.ch==="control"&&A.type==="http_cancel"){oi.get(A.reqId)?.abort();return}if(A.ch==="attach"&&A.type==="open"){let B=new dy(H+A.path,Array.isArray(A.protocols)?A.protocols:[],A.host?{headers:{host:A.host}}:void 0);te.set(A.streamId,B),pe.set(A.streamId,[]),B.on("open",()=>{let ke=pe.get(A.streamId)||[];pe.delete(A.streamId);for(let{buf:Se,bin:He}of ke)B.send(Se,{binary:He})}),B.on("message",(ke,Se)=>{let He=Se?ke:Buffer.from(String(ke));at({v:lt,ch:"attach",type:"data",streamId:A.streamId,data:He.toString("base64"),...Se?{bin:!0}:{}})});let Q=()=>{pe.delete(A.streamId),te.delete(A.streamId)&&at({v:lt,ch:"attach",type:"close",streamId:A.streamId})};B.on("close",Q),B.on("error",Q);return}if(A.ch==="attach"&&A.type==="data"){let B=te.get(A.streamId);if(!B)return;let Q=Buffer.from(A.data,"base64"),ke=A.bin===!0,Se=pe.get(A.streamId);Se?Se.push({buf:Q,bin:ke}):B.send(Q,{binary:ke});return}if(A.ch==="attach"&&A.type==="close"){let B=te.get(A.streamId);te.delete(A.streamId),pe.delete(A.streamId),B?.close();return}});let D=()=>{P&&M.log("[plane-link] disconnected from plane"),P=!1,st&&(clearInterval(st),st=null),Vn&&(clearInterval(Vn),Vn=null),G.clear(),X={},k=[],m&&(clearTimeout(m),m=null),_r.clear();for(let B of te.values())B.close();te.clear(),pe.clear();for(let B of oi.values())B.abort();if(oi.clear(),ae||ht)return;Me==null&&(Me=Date.now());let F=Date.now()-Me<AH,A=Math.max(F?TH+Math.random()*EH:ge,Ke-Date.now(),ui());ht=setTimeout(()=>{ht=null,qb()},A),ht.unref?.(),F||(ge=Math.min(ge*2,OI))};v.on("close",D),v.on("error",F=>{let A=/Unexpected server response: (\d+)/.exec(F?.message||"")?.[1];if(A==="410"){df({reason:"removed",via:"410"});return}if(A==="401"||A==="403"){let{tripped:B,holdMs:Q}=Ns();B?M.error(`[plane-link] holding every plane call for ${Math.round(Q/6e4)} min \u2014 three credential refusals in a row (HTTP ${A}) mean the token is revoked or unknown, not that the plane is down; mint a new node token and update this node's BOSTRAT_PLANE_TOKEN. Next dial in ${Math.round(Q/6e4)} min.`):Date.now()-$l>=NI&&($l=Date.now(),M.error(`[plane-link] plane refused this node's credentials (HTTP ${A}) \u2014 the token was revoked or is unknown to the plane; mint a new node token and update this node's BOSTRAT_PLANE_TOKEN (still retrying)`))}D()})}Je.on("event",Wb),gM().then(qb);function Kb({bye:D=!0}={}){ae=!0,Je.off("event",Wb),ht&&clearTimeout(ht),Qe&&clearTimeout(Qe),st&&clearInterval(st),Vn&&clearInterval(Vn),m&&clearTimeout(m),D&&at({v:lt,ch:"ctl",type:"bye",reason:"shutdown"}),v?.close()}return{stop:()=>Kb(),status:()=>({connected:P,nodeId:n,cursor:{...Ne},inflight:G.size,...Ub(),auth:tk(),dormant:ti,removed:Dl()}),_tick:()=>{Fb(),hf()}}}hu();var vp=(()=>{try{return BH(import.meta.url)("../package.json").version||null}catch{return null}})(),jH=process.env.BOSTRAT_STATE_DIR||ft.join(process.env.HOME||PH.tmpdir(),".bostrat"),LI=ft.join(jH,"self-update"),Sp=ft.join(LI,"status.json"),LH=1440*6e4,FH=6e4,Qc=new Set(["npm-global","git-checkout"]);function FI({kind:e=bs(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:Qc.has(e)?e==="git-checkout"||UH(t)?"auto":"prompt":"off"}function UH(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var qt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function HH({kind:e,to:t,from:n=vp,statusFile:r=Sp,logFile:o=ft.join(LI,"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||ft.resolve(ft.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!Qc.has(e))throw new Error(`self-update: install kind "${e}" is not actionable here`);if(!/^\d+\.\d+\.\d+$/.test(String(t)))throw new Error(`self-update: bad target version "${t}"`);if(n&&!/^\d+\.\d+\.\d+$/.test(String(n)))throw new Error(`self-update: bad current version "${n}"`);let d=(g,y="")=>`write_status ${qt(g)} ${y}`,p=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${qt(i)}`,f=`
654
658
  health() {
655
659
  for i in $(seq 1 45); do
656
660
  sleep 1
@@ -661,20 +665,20 @@ health() {
661
665
  # bostrat-node self-update one-shot \u2014 written by agent/src/self-update.js.
662
666
  # ${n??"?"} \u2192 ${t} (${e}). Status: ${r}
663
667
  set -u
664
- FROM=${jt(n??"")}
665
- TO=${jt(t)}
666
- STATUS_FILE=${jt(r)}
668
+ FROM=${qt(n??"")}
669
+ TO=${qt(t)}
670
+ STATUS_FILE=${qt(r)}
667
671
  STARTED_AT=${Number(u)}
668
672
  write_status() { # <status> [error]
669
673
  local err="\${2:-}"
670
674
  err="\${err//\\\\/\\\\\\\\}"; err="\${err//\\"/\\\\\\"}"
671
675
  printf '{"status":"%s","from":"%s","to":"%s","kind":"%s","startedAt":%s,"updatedAt":%s%s}\\n' \\
672
- "$1" "$FROM" "$TO" ${jt(e)} "$STARTED_AT" "$(date +%s000)" \\
676
+ "$1" "$FROM" "$TO" ${qt(e)} "$STARTED_AT" "$(date +%s000)" \\
673
677
  "\${err:+,\\"error\\":\\"$err\\"}" > "$STATUS_FILE.tmp" && mv "$STATUS_FILE.tmp" "$STATUS_FILE"
674
678
  }
675
679
  ${f}
676
- `;if(e==="npm-global"){let g=a?dt.join(a,"bin","npm"):"npm",y=a?`export PATH=${jt(dt.join(a,"bin"))}:"$PATH"
677
- `:"",x=a?` --prefix ${jt(a)}`:"",b=O=>`${jt(g)} install -g "bostrat-node@${O}" --no-audit --no-fund${x}`;return w+y+`
680
+ `;if(e==="npm-global"){let g=a?ft.join(a,"bin","npm"):"npm",y=a?`export PATH=${qt(ft.join(a,"bin"))}:"$PATH"
681
+ `:"",x=a?` --prefix ${qt(a)}`:"",b=I=>`${qt(g)} install -g "bostrat-node@${I}" --no-audit --no-fund${x}`;return w+y+`
678
682
  ${d("updating",'"" ')}
679
683
  if ! ${b("$TO")}; then
680
684
  ${d("failed",'"npm install failed"')}
@@ -697,83 +701,83 @@ if [ -n "$FROM" ] && ${b("$FROM")} && ${p} && health; then
697
701
  fi
698
702
  ${d("failed",'"agent did not answer after the update AND the rollback"')}
699
703
  exit 1
700
- `}let m=g=>`( cd ${jt(l)} && git fetch -q origin main --tags && git show origin/main:scripts/deploy-pi.sh > "$TMP_SCRIPT" && bash "$TMP_SCRIPT" "v${g}" )`;return w+`
701
- LIVE=${jt(l)}
704
+ `}let h=g=>`( cd ${qt(l)} && git fetch -q origin main --tags && git show origin/main:scripts/deploy-pi.sh > "$TMP_SCRIPT" && bash "$TMP_SCRIPT" "v${g}" )`;return w+`
705
+ LIVE=${qt(l)}
702
706
  TMP_SCRIPT="$(mktemp)"
703
707
  trap 'rm -f "$TMP_SCRIPT"' EXIT
704
708
  # "restarting" is written BEFORE deploy-pi.sh runs (it does fetch \u2192 build \u2192
705
709
  # restart \u2192 health in one call): the agent it restarts settles "done" on boot,
706
710
  # and nothing here may write after that boot or the settle would repeat.
707
711
  ${d("restarting")}
708
- if ${m("$TO")}; then
712
+ if ${h("$TO")}; then
709
713
  exit 0
710
714
  fi
711
715
  ${d("rolling-back",'"deploy-pi.sh v$TO failed"')}
712
- if [ -n "$FROM" ] && ${m("$FROM")}; then
716
+ if [ -n "$FROM" ] && ${h("$FROM")}; then
713
717
  ${d("rolled-back",'"deploy-pi.sh v$TO failed; rolled back to v$FROM"')}
714
718
  exit 1
715
719
  fi
716
720
  ${d("failed",'"deploy-pi.sh v$TO failed AND the rollback failed"')}
717
721
  exit 1
718
- `}async function jc(e=Kd){try{return JSON.parse(await io.readFile(e,"utf8"))}catch{return null}}var rH=new Set(["updating","restarting","rolling-back"]),Gd=e=>!!(e&&rH.has(e.status));async function zd({to:e,from:t=qd,kind:n=ts(),reason:r="manual",statusFile:o=Kd,spawnImpl:s=Y2,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!Bc.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!Dc(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await jc(o);if(Gd(l))return{ok:!1,reason:`an update to ${l.to} is already in flight`,status:l};if(l&&l.to===e&&(l.status==="failed"||l.status==="rolled-back"))return{ok:!1,reason:`update to ${e} already ${l.status} (${l.error||"no detail"}) \u2014 retried when a newer release exists`,status:l};await io.mkdir(dt.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?Mf(await oH())||dt.resolve(dt.dirname(process.execPath),".."):null,d=nH({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),p=dt.join(dt.dirname(o),`update-${e}.sh`),f=dt.join(dt.dirname(o),"last.log");await io.writeFile(p,d,{mode:448}),await io.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let w=nI.existsSync("/run/systemd/system")&&await sH("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",p]]:["setsid",["-f","bash","-c",`exec bash ${jt(p)} >> ${jt(f)} 2>&1`]];try{s(w[0],w[1],{detached:!0,stdio:"ignore"}).unref?.()}catch(m){return await io.writeFile(o,JSON.stringify({status:"failed",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a(),error:`could not spawn updater: ${m?.message||m}`})),{ok:!1,reason:`could not spawn updater: ${m?.message||m}`}}return c.log?.(`[self-update] ${t??"?"} \u2192 ${e} (${n}, ${r}) started \u2014 status ${o}`),{ok:!0,to:e,from:t,kind:n,scriptFile:p,statusFile:o}}async function oH(){try{return await io.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function sH(e){for(let t of String(process.env.PATH||"").split(dt.delimiter))try{return await io.access(dt.join(t,e),nI.constants.X_OK),!0}catch{}return!1}var aH=45*6e4;async function sI({statusFile:e=Kd,current:t=qd,now:n=Date.now,staleMs:r=aH}={}){let o=await jc(e);if(!o)return null;let s=a=>io.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Gd(o)){if(t&&o.to===t){let a={...o,status:"done",updatedAt:n(),finishedAt:n(),announced:!0};return await s(a),a}if(n()-Number(o.updatedAt||o.startedAt||0)>r){let a={...o,status:"failed",error:`updater went silent while ${o.status} (no status change for ${Math.round(r/6e4)} min)`,updatedAt:n(),finishedAt:n(),announced:!0};return await s(a),a}return null}if(["failed","rolled-back","done"].includes(o.status)&&!o.announced){let a={...o,announced:!0};return await s(a),a}return null}function aI({isBusy:e,start:t=zd,onStuck:n=null,onStarted:r=null,tickMs:o=eH,stuckMs:s=Q2,now:a=Date.now,setIntervalImpl:i=setInterval,clearIntervalImpl:c=clearInterval,log:l=console}={}){let u=null,d=()=>{u?.timer&&c(u.timer),u=null},p=async()=>{if(!u)return;let f=!0;try{f=await e()!==!1}catch{f=!0}if(f){if(!u.stuckFired&&a()-u.since>=s){u.stuckFired=!0;try{await n?.({to:u.to,from:u.from,since:u.since})}catch{}}return}let w=u;d();let m=await t({to:w.to,from:w.from,kind:w.kind,reason:"auto"});l.log?.(`[self-update] stasis reached \u2192 ${m.ok?"started":`not started: ${m.reason}`}`);try{await r?.({...w,result:m})}catch{}};return{arm({to:f,from:w=qd,kind:m=ts()}){return u?.to===f?!1:(d(),u={to:f,from:w,kind:m,since:a(),stuckFired:!1,timer:i(p,o)},u.timer.unref?.(),!0)},tick:p,cancel:d,get armed(){return u?{to:u.to,from:u.from,kind:u.kind,since:u.since}:null}}}pe();pt();var iI=(...e)=>fetch(...e);function cI(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Ng(e=process.env){if(!cI(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 iI(`${Oe(e)}/v1/circuits`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN}`},signal:t.signal}),o=await r.json().catch(()=>({}));if(!r.ok)throw new Error(o?.error||`plane answered ${r.status}`);return Array.isArray(o.circuits)?o.circuits:[]}finally{clearTimeout(n)}}async function Pg(e=process.env){if(!cI(e))throw new Error("no plane configured \u2014 the roadmap lives on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let t=new AbortController,n=setTimeout(()=>t.abort(),1e4);try{let r=await iI(`${Oe(e)}/v1/roadmap`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN}`},signal:t.signal}),o=await r.json().catch(()=>({}));if(!r.ok)throw new Error(o?.error||`plane answered ${r.status}`);return{people:Array.isArray(o.people)?o.people:[],slots:Array.isArray(o.slots)?o.slots:[],reservations:Array.isArray(o.reservations)?o.reservations:[],tray:Array.isArray(o.tray)?o.tray:[],circuits:Array.isArray(o.circuits)?o.circuits:[]}}finally{clearTimeout(n)}}async function Aa(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await Ng(t),o=r.find(c=>c.id===n);if(o)return o;let s=n.toLowerCase(),a=r.filter(c=>c.name.toLowerCase()===s);if(a.length===1)return a[0];if(a.length>1)throw new Error(`"${n}" names ${a.length} circuits \u2014 use an id (bostrat-circuit ls)`);let i=r.filter(c=>c.name.toLowerCase().includes(s)).slice(0,5);throw new Error(i.length?`no circuit named "${n}" \u2014 near matches: ${i.map(c=>`${c.name} (${c.id})`).join(", ")}`:`no circuit named "${n}" \u2014 create it on the Circuits page first (bostrat-circuit ls lists yours)`)}async function Vd(e,t,{source:n="chat"}={}){return M(e,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:t?{circuitId:t.id,circuitName:t.name??null,source:n}:{circuitId:null,source:n}})}pe();pt();var iH=(...e)=>fetch(...e);async function Jd(e,t,n,r=process.env){if(!(Oe(r)&&r.BOSTRAT_PLANE_TOKEN))throw new Error("no plane configured \u2014 blueprints live on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let o=new AbortController,s=setTimeout(()=>o.abort(),15e3);try{let a=await iH(`${Oe(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}function cH(e,t=process.env){return Jd("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function lI({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await cH(t,o):await Aa(e,o),a=await Jd("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function Dg(e,t=process.env){let n=await Aa(e,t),r=await Jd("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function Bg(e,t=process.env){return(await Jd("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function uI(e,t,n,r=process.env){let{blueprint:o,items:s}=await Dg(t,r),a=new Map(s.map(c=>[c.itemId,c])),i=n.filter(c=>!a.get(c)?.bindable);if(i.length){let c=s.filter(l=>l.bindable).map(l=>l.itemId);throw new Error(`unknown/unbindable item(s): ${i.join(", ")} \u2014 bindable ids: ${c.join(", ")||"(none)"}`)}return await M(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}pe();pt();var lH=(...e)=>fetch(...e);async function uH(e,t,n,r=process.env){if(!(Oe(r)&&r.BOSTRAT_PLANE_TOKEN))throw new Error("no plane configured \u2014 the decision ledger lives on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let o=new AbortController,s=setTimeout(()=>o.abort(),15e3);try{let a=await lH(`${Oe(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}var dI=72,jg=160;async function pI(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>dI)throw new Error(`the title is the choice as a LABEL \u2014 ${dI} 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 ${jg} chars) a reader can act on without opening the record`);if(c.length>jg)throw new Error(`the summary is one sentence \u2014 ${jg} chars max (yours is ${c.length}); the full story goes in the decision text`);if(!String(r??"").trim())throw new Error("the decision itself is required (what was decided)");return await M(e,{type:"decision.recorded",actor:"orchestrator",source:"orchestrator",payload:{title:i,context:String(n??"").trim(),decision:String(r).trim(),summary:c,alternatives:(Array.isArray(s)?s:[]).map(l=>typeof l=="string"?{label:l}:l).filter(l=>l?.label),...a?{supersedesId:a}:{}}}),{title:i}}function fI(e,t=process.env){return uH("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}gw();pe();import qc from"node:fs/promises";import op from"node:path";import tW from"node:os";Er();import dH from"node:fs/promises";import mI from"node:path";import pH from"node:os";var hI=()=>mI.join(process.env.BOSTRAT_STATE_DIR||mI.join(process.env.HOME||pH.tmpdir(),".bostrat"),"integrations.json");async function kr(){try{return JSON.parse(await dH.readFile(hI(),"utf8"))||{}}catch{return{}}}var Yd=["linked","prOpened","prMerged","create"],Lg=["prompt","auto","off"],fH={create:["prompt","off"]},wI=e=>fH[e]??Lg;function Xd(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of Yd){let s=wI(o),a=s.includes(n)?n:"prompt",i=e.ticketFlow?.[o]??t.ticketFlow?.[o];r[o]=s.includes(i)?i:a}return r}async function ns(){let e=await kr(),t=process.env.BOSTRAT_LINEAR_API_KEY||e.linear?.apiKey,n=process.env.BOSTRAT_LINEAR_DEFAULT_TEAM||e.linear?.defaultTeam||null;return t?{apiKey:t,ticketFlow:Xd(e),defaultTeam:n}:null}async function Zd(){let e=await kr(),t=e.jira||{},n=process.env.BOSTRAT_JIRA_BASE_URL||t.baseUrl,r=process.env.BOSTRAT_JIRA_EMAIL||t.email,o=process.env.BOSTRAT_JIRA_API_TOKEN||t.apiToken;return!n||!r||!o?null:{baseUrl:String(n).replace(/\/$/,""),email:r,apiToken:o,tokenExpiresAt:t.tokenExpiresAt??null,ticketFlow:Xd(e)}}async function Fg(){return Xd(await kr())}async function gI(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${Yd.join(", ")}`);for(let[r,o]of t){if(!Yd.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${Yd.join(", ")}`);let s=wI(r);if(!s.includes(o))throw new Error(s.length<Lg.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${Lg.join(", ")}`)}let n=await kr();return n.ticketFlow={...Xd(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Et(hI(),n,{mode:384}),n.ticketFlow}async function Lc(){let e=(await kr()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function mH(){let e=(await kr()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var hH={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function Qd(){let t=(await kr()).voiceChat||{},n=t.provider||"openai",r=hH[n];if(!r)return null;let o=n==="openai"?await mH():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function yI(){let e=(await kr()).cedar||{},t=process.env.BOSTRAT_CEDAR_INGEST_KEY||e.ingestKey,n=process.env.BOSTRAT_CEDAR_URL||e.url||"https://cedar-api.fly.dev";return t?{url:n,ingestKey:t}:null}async function rs(){let e=(await kr()).slack||{},t=process.env.BOSTRAT_SLACK_BOT_TOKEN||e.botToken,n=process.env.BOSTRAT_SLACK_APP_TOKEN||e.appToken;return!t||!n?null:{botToken:t,appToken:n,channel:process.env.BOSTRAT_SLACK_CHANNEL||e.channel||null,maxConcurrent:Number.isInteger(e.maxConcurrent)&&e.maxConcurrent>0?e.maxConcurrent:2}}pe();Ir();Lr();da();import Uc from"node:fs/promises";import _I from"node:path";import FH from"node:os";import{randomUUID as II}from"node:crypto";var Hg={};Dp(Hg,{createComment:()=>TH,findIssueUrl:()=>bH,issueStates:()=>_H,mdToAdf:()=>xI,moveIssue:()=>IH,parseIssueRef:()=>yH,resolveIssue:()=>kH,uploadImage:()=>AH,upsertCard:()=>xH,whoami:()=>Ug});var Ea=e=>String(e.baseUrl||"").replace(/\/$/,""),kI=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function os(e,t,n,r){let o=await fetch(`${Ea(e)}${n}`,{method:t,headers:{authorization:kI(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 wH=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,gH=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function yH(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(wH);return r?r[1].toUpperCase():null}let n=t.match(gH);return n?n[1]:null}function bH(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 kH(e,t){let n;try{n=await os(e,"GET",`/rest/api/3/issue/${encodeURIComponent(t)}?fields=summary,status`)}catch(r){throw r.status===404?new Error(`jira: issue "${t}" not found`):r}return{issueId:n.id,key:n.key,title:n.fields?.summary??null,url:`${Ea(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function xH(e,t,{url:n,title:r,subtitle:o}){await os(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/remotelink`,{globalId:n,application:{type:"com.bostrat.tracks",name:"Bostrat"},object:{url:n,title:r,summary:o,icon:{title:"Bostrat"}}})}var vH=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function SH(e){let t=[],n=0;for(let r of e.matchAll(vH)){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 xI(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
719
- `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...SH(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 TH(e,t,n){let r=await os(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:xI(n)});return r?.id?`${Ea(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function Ug(e){let t=await os(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(Ea(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function AH(e,{issue:t,filename:n,contentType:r,buffer:o}){let s=new FormData;s.append("file",new Blob([o],{type:r}),n);let a=await fetch(`${Ea(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:kI(e),"x-atlassian-token":"no-check",accept:"application/json"},body:s}),i=await a.json().catch(()=>null),c=Array.isArray(i)?i[0]:null;if(!a.ok||!c)throw new Error(`jira: attachment upload failed (HTTP ${a.status})`);return c.content??`${Ea(e)}/rest/api/3/attachment/content/${c.id}`}var EH={new:"unstarted",indeterminate:"started",done:"completed"},bI=e=>EH[e?.key]??"started";async function _H(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([os(e,"GET",`/rest/api/3/issue/${n}?fields=status`),os(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:bI(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:bI(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function IH(e,t,n){await os(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var Gg={};Dp(Gg,{createComment:()=>DH,createIssue:()=>Kg,createProject:()=>qg,findIssueUrl:()=>CH,issueStates:()=>jH,moveIssue:()=>LH,parseIssueRef:()=>MH,resolveIssue:()=>NH,teams:()=>_a,uploadImage:()=>BH,upsertCard:()=>PH,whoami:()=>Wg});var $H=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function qn(e,t,n={}){let r=await fetch($H(),{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 RH=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,OH=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function MH(e){let t=String(e||"").trim(),n=t.match(RH);if(n)return n[1].toUpperCase();let r=t.match(OH);return r?r[1]:null}function CH(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 NH(e,t){let r=(await qn(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 PH(e,t,{url:n,title:r,subtitle:o}){let s=await qn(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 DH(e,t,n){let r=await qn(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 Wg(e){let t=await qn(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 BH(e,{filename:t,contentType:n,buffer:r}){let o=await qn(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
722
+ `}async function el(e=Sp){try{return JSON.parse(await wo.readFile(e,"utf8"))}catch{return null}}var WH=new Set(["updating","restarting","rolling-back"]),Ap=e=>!!(e&&WH.has(e.status));async function Tp({to:e,from:t=vp,kind:n=bs(),reason:r="manual",statusFile:o=Sp,spawnImpl:s=DH,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!Qc.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!Zc(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await el(o);if(Ap(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 wo.mkdir(ft.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?ph(await qH())||ft.resolve(ft.dirname(process.execPath),".."):null,d=HH({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),p=ft.join(ft.dirname(o),`update-${e}.sh`),f=ft.join(ft.dirname(o),"last.log");await wo.writeFile(p,d,{mode:448}),await wo.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let w=jI.existsSync("/run/systemd/system")&&await KH("systemd-run")?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",p]]:["setsid",["-f","bash","-c",`exec bash ${qt(p)} >> ${qt(f)} 2>&1`]];try{s(w[0],w[1],{detached:!0,stdio:"ignore"}).unref?.()}catch(h){return await wo.writeFile(o,JSON.stringify({status:"failed",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a(),error:`could not spawn updater: ${h?.message||h}`})),{ok:!1,reason:`could not spawn updater: ${h?.message||h}`}}return c.log?.(`[self-update] ${t??"?"} \u2192 ${e} (${n}, ${r}) started \u2014 status ${o}`),{ok:!0,to:e,from:t,kind:n,scriptFile:p,statusFile:o}}async function qH(){try{return await wo.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function KH(e){for(let t of String(process.env.PATH||"").split(ft.delimiter))try{return await wo.access(ft.join(t,e),jI.constants.X_OK),!0}catch{}return!1}var GH=45*6e4;async function UI({statusFile:e=Sp,current:t=vp,now:n=Date.now,staleMs:r=GH}={}){let o=await el(e);if(!o)return null;let s=a=>wo.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Ap(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 HI({isBusy:e,start:t=Tp,onStuck:n=null,onStarted:r=null,tickMs:o=FH,stuckMs:s=LH,now:a=Date.now,setIntervalImpl:i=setInterval,clearIntervalImpl:c=clearInterval,log:l=console}={}){let u=null,d=()=>{u?.timer&&c(u.timer),u=null},p=async()=>{if(!u)return;let f=!0;try{f=await e()!==!1}catch{f=!0}if(f){if(!u.stuckFired&&a()-u.since>=s){u.stuckFired=!0;try{await n?.({to:u.to,from:u.from,since:u.since})}catch{}}return}let w=u;d();let h=await t({to:w.to,from:w.from,kind:w.kind,reason:"auto"});l.log?.(`[self-update] stasis reached \u2192 ${h.ok?"started":`not started: ${h.reason}`}`);try{await r?.({...w,result:h})}catch{}};return{arm({to:f,from:w=vp,kind:h=bs()}){return u?.to===f?!1:(d(),u={to:f,from:w,kind:h,since:a(),stuckFired:!1,timer:i(p,o)},u.timer.unref?.(),!0)},tick:p,cancel:d,get armed(){return u?{to:u.to,from:u.from,kind:u.kind,since:u.since}:null}}}he();mt();var WI=(...e)=>fetch(...e);function qI(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}async function hy(e=process.env){if(!qI(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 WI(`${Re(e)}/v1/circuits`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN}`},signal:t.signal}),o=await r.json().catch(()=>({}));if(!r.ok)throw new Error(o?.error||`plane answered ${r.status}`);return Array.isArray(o.circuits)?o.circuits:[]}finally{clearTimeout(n)}}async function my(e=process.env){if(!qI(e))throw new Error("no plane configured \u2014 the roadmap lives on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let t=new AbortController,n=setTimeout(()=>t.abort(),1e4);try{let r=await WI(`${Re(e)}/v1/roadmap`,{headers:{authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN}`},signal:t.signal}),o=await r.json().catch(()=>({}));if(!r.ok)throw new Error(o?.error||`plane answered ${r.status}`);return{people:Array.isArray(o.people)?o.people:[],slots:Array.isArray(o.slots)?o.slots:[],reservations:Array.isArray(o.reservations)?o.reservations:[],tray:Array.isArray(o.tray)?o.tray:[],circuits:Array.isArray(o.circuits)?o.circuits:[]}}finally{clearTimeout(n)}}async function Ua(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await hy(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 Ep(e,t,{source:n="chat"}={}){return C(e,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:t?{circuitId:t.id,circuitName:t.name??null,source:n}:{circuitId:null,source:n}})}he();mt();var zH=(...e)=>fetch(...e);async function _p(e,t,n,r=process.env){if(!(Re(r)&&r.BOSTRAT_PLANE_TOKEN))throw new Error("no plane configured \u2014 blueprints live on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let o=new AbortController,s=setTimeout(()=>o.abort(),15e3);try{let a=await zH(`${Re(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}function VH(e,t=process.env){return _p("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function KI({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await VH(t,o):await Ua(e,o),a=await _p("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function wy(e,t=process.env){let n=await Ua(e,t),r=await _p("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function gy(e,t=process.env){return(await _p("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function GI(e,t,n,r=process.env){let{blueprint:o,items:s}=await wy(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 C(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}he();mt();var JH=(...e)=>fetch(...e);async function YH(e,t,n,r=process.env){if(!(Re(r)&&r.BOSTRAT_PLANE_TOKEN))throw new Error("no plane configured \u2014 the decision ledger lives on the plane (set BOSTRAT_PLANE_URL/BOSTRAT_PLANE_TOKEN via bostrat-node init)");let o=new AbortController,s=setTimeout(()=>o.abort(),15e3);try{let a=await JH(`${Re(r)}${t}`,{method:e,headers:{authorization:`Bearer ${r.BOSTRAT_PLANE_TOKEN}`,...n?{"content-type":"application/json"}:{}},body:n?JSON.stringify(n):void 0,signal:o.signal}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i?.error||`plane answered ${a.status}`);return i}finally{clearTimeout(s)}}var zI=72,yy=160;async function VI(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>zI)throw new Error(`the title is the choice as a LABEL \u2014 ${zI} 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 ${yy} chars) a reader can act on without opening the record`);if(c.length>yy)throw new Error(`the summary is one sentence \u2014 ${yy} 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 C(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 JI(e,t=process.env){return YH("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}Zw();he();import al from"node:fs/promises";import Dp from"node:path";import UW from"node:os";Nr();import XH from"node:fs/promises";import YI from"node:path";import ZH from"node:os";var XI=()=>YI.join(process.env.BOSTRAT_STATE_DIR||YI.join(process.env.HOME||ZH.tmpdir(),".bostrat"),"integrations.json");async function Ar(){try{return JSON.parse(await XH.readFile(XI(),"utf8"))||{}}catch{return{}}}var Ip=["linked","prOpened","prMerged","create"],by=["prompt","auto","off"],QH={create:["prompt","off"]},ZI=e=>QH[e]??by;function $p(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of Ip){let s=ZI(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 ks(){let e=await Ar(),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:$p(e),defaultTeam:n}:null}async function Rp(){let e=await Ar(),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:$p(e)}}async function ky(){return $p(await Ar())}async function QI(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${Ip.join(", ")}`);for(let[r,o]of t){if(!Ip.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${Ip.join(", ")}`);let s=ZI(r);if(!s.includes(o))throw new Error(s.length<by.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${by.join(", ")}`)}let n=await Ar();return n.ticketFlow={...$p(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Rt(XI(),n,{mode:384}),n.ticketFlow}async function tl(){let e=(await Ar()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function eW(){let e=(await Ar()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var tW={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function Op(){let t=(await Ar()).voiceChat||{},n=t.provider||"openai",r=tW[n];if(!r)return null;let o=n==="openai"?await eW():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function e$(){let e=(await Ar()).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 xs(){let e=(await Ar()).slack||{},t=process.env.BOSTRAT_SLACK_BOT_TOKEN||e.botToken,n=process.env.BOSTRAT_SLACK_APP_TOKEN||e.appToken;return!t||!n?null:{botToken:t,appToken:n,channel:process.env.BOSTRAT_SLACK_CHANNEL||e.channel||null,maxConcurrent:Number.isInteger(e.maxConcurrent)&&e.maxConcurrent>0?e.maxConcurrent:2}}he();Dr();Gr();Ea();import rl from"node:fs/promises";import l$ from"node:path";import EW from"node:os";import{randomUUID as u$}from"node:crypto";var vy={};wf(vy,{createComment:()=>uW,findIssueUrl:()=>sW,issueStates:()=>fW,mdToAdf:()=>r$,moveIssue:()=>hW,parseIssueRef:()=>oW,resolveIssue:()=>aW,uploadImage:()=>dW,upsertCard:()=>iW,whoami:()=>xy});var Ha=e=>String(e.baseUrl||"").replace(/\/$/,""),n$=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function vs(e,t,n,r){let o=await fetch(`${Ha(e)}${n}`,{method:t,headers:{authorization:n$(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 nW=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,rW=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function oW(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(nW);return r?r[1].toUpperCase():null}let n=t.match(rW);return n?n[1]:null}function sW(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 aW(e,t){let n;try{n=await vs(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:`${Ha(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function iW(e,t,{url:n,title:r,subtitle:o}){await vs(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 cW=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function lW(e){let t=[],n=0;for(let r of e.matchAll(cW)){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 r$(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
723
+ `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...lW(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 uW(e,t,n){let r=await vs(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:r$(n)});return r?.id?`${Ha(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function xy(e){let t=await vs(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(Ha(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function dW(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(`${Ha(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:n$(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??`${Ha(e)}/rest/api/3/attachment/content/${c.id}`}var pW={new:"unstarted",indeterminate:"started",done:"completed"},t$=e=>pW[e?.key]??"started";async function fW(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([vs(e,"GET",`/rest/api/3/issue/${n}?fields=status`),vs(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:t$(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:t$(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function hW(e,t,n){await vs(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var Ey={};wf(Ey,{createComment:()=>vW,createIssue:()=>Ty,createProject:()=>Ay,findIssueUrl:()=>bW,issueStates:()=>AW,moveIssue:()=>TW,parseIssueRef:()=>yW,resolveIssue:()=>kW,teams:()=>Wa,uploadImage:()=>SW,upsertCard:()=>xW,whoami:()=>Sy});var mW=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function Gn(e,t,n={}){let r=await fetch(mW(),{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 wW=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,gW=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function yW(e){let t=String(e||"").trim(),n=t.match(wW);if(n)return n[1].toUpperCase();let r=t.match(gW);return r?r[1]:null}function bW(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 kW(e,t){let r=(await Gn(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 xW(e,t,{url:n,title:r,subtitle:o}){let s=await Gn(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 vW(e,t,n){let r=await Gn(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 Sy(e){let t=await Gn(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 SW(e,{filename:t,contentType:n,buffer:r}){let o=await Gn(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
720
724
  fileUpload(contentType: $contentType, filename: $filename, size: $size) {
721
725
  success
722
726
  uploadFile { uploadUrl assetUrl headers { key value } }
723
727
  }
724
- }`,{contentType:n,filename:t,size:r.length}),s=o.fileUpload?.uploadFile;if(!o.fileUpload?.success||!s?.uploadUrl)throw new Error("linear: fileUpload did not succeed");let a={"content-type":n};for(let c of s.headers||[])a[c.key]=c.value;let i=await fetch(s.uploadUrl,{method:"PUT",headers:a,body:r});if(!i.ok)throw new Error(`linear: asset PUT failed (HTTP ${i.status})`);return s.assetUrl}async function jH(e,t){let n=await qn(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 LH(e,t,n){if(!(await qn(e,"mutation($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }",{id:t.issueId,input:{stateId:n}})).issueUpdate?.success)throw new Error("linear: issueUpdate did not succeed")}async function _a(e){return((await qn(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var vI=255;async function qg(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>vI,a=s?`${o.slice(0,vI-1).trimEnd()}\u2026`:o,i=await qn(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 Kg(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await qn(e,"mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier url title } } }",{input:{teamId:t,title:n,...r?{description:r}:{},...o?{projectId:o}:{},...Number.isInteger(s)?{priority:s}:{}}}),i=a.issueCreate?.issue;if(!a.issueCreate?.success||!i)throw new Error("linear: issueCreate did not succeed");return{id:i.id,key:i.identifier,url:i.url,title:i.title}}Vi();var $I={linear:{api:Gg,config:ns},jira:{api:Hg,config:Zd}};async function Qg(){let e=[];for(let[t,{api:n,config:r}]of Object.entries($I)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function ss(e){let t=$I[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function ey(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 RI=()=>process.env.BOSTRAT_STATE_DIR||_I.join(process.env.HOME||FH.tmpdir(),".bostrat"),Yg=()=>_I.join(RI(),"tickets.json"),OI=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),ep=e=>`${OI()}/track/${e}`,co=null,zg=null,Vg=Promise.resolve();async function Wc(){return co||(zg??=Uc.readFile(Yg(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{if(co=e,!t&&He()){let{records:n,source:r}=await st("tickets").catch(()=>({records:[],source:"error"}));if(r==="plane"){for(let o of n){if(o.deletedAt||!o.data?.id)continue;let{id:s,updatedAt:a,...i}=o.data;co[s]=i}Object.keys(co).length&&await Xg().catch(()=>{})}}return co}).finally(()=>zg=null),zg)}async function Xg(){let e=JSON.stringify({tickets:co},null,2),t=`${Yg()}.${process.pid}.tmp`;await Uc.mkdir(RI(),{recursive:!0}),await Uc.writeFile(t,e),await Uc.rename(t,Yg())}async function lo(e=null){if(Vg=Vg.then(Xg,Xg),await Vg.catch(()=>{}),!e)return;let t=co?.[e];t?bt("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):tn("tickets",e).catch(()=>{})}async function Kn(e){return(await Wc())[e]??null}async function MI(){return{...await Wc()}}async function CI(){return(await Qg()).length>0}async function Ia(e,t,{source:n="api"}={}){let r=await Qg();if(!r.length)throw new Error("no ticketing integration configured \u2014 add a linear or jira entry to ~/.bostrat/integrations.json");let o=null,s=null,a=null;for(let u of r){let d=u.api.parseIssueRef(t);if(d)try{s=await u.api.resolveIssue(u.cfg,d),o=u;break}catch(p){a=p}}if(!o)throw a||new Error(`"${t}" is not a Linear or Jira issue URL or key (ABC-123)`);let i=(e.boxes||[]).find(u=>u.name===e.leadBox),c={provider:o.name,key:s.key,issueId:s.issueId,url:s.url,title:s.title,state:s.state,source:n,linkedAt:Date.now(),track:{name:e.name,branch:e.workspace?.branch??null,leadAgent:i?.agent??null,cwd:e.cwd??null,...e.workspace?.kind==="multi"?{repos:(e.workspace.repos??[]).map(u=>u?.name).filter(Boolean)}:{}},pr:null};(await Wc())[e.id]=c,await lo(e.id),await M({id:e.id,cwd:e.cwd},{type:"ticket.linked",actor:"user",source:"orchestrator",payload:{ts:Date.now(),provider:c.provider,key:c.key,url:c.url,title:c.title,linkSource:n}}).catch(()=>{}),await Hc(e.id,c);let l=[];return c.track.branch&&l.push(`\`${c.track.branch}\``),c.track.repos?.length&&l.push(`repos ${c.track.repos.join(" + ")}`),c.track.leadAgent&&l.push(`lead ${c.track.leadAgent}`),await Fc(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await DI(e.id,c,"linked"),c}async function ty(e){let t=await Wc();return t[e]?(delete t[e],await lo(e),!0):!1}var Zg=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function NI(e,t){if(!e.track?.cwd)return null;let n=jr(await q({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function UH(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${Zg(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${Zg(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function HH(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(Zg(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function Hc(e,t){let n=await ss(t);if(!n)return;let r=await NI(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:ep(e),title:`Bostrat Track: ${t.track.name}`,subtitle:HH(t,r)})}function tp(e){let t=new URL(OI());return`${t.protocol}//${e}.${t.host}/`}var WH={linked:"linked",opened:"prOpened",merged:"prMerged"};function qH(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 PI(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await lo(e),await M({id:e,cwd:t.track?.cwd},{type:"ticket.state.changed",actor:a,source:"orchestrator",payload:{ts:Date.now(),key:t.key,url:t.url,from:n??null,to:r,mode:o,...s?{phase:s}:{}}}).catch(()=>{})}async function DI(e,t,n){let r=await ss(t);if(!r)return;let o=r.cfg.ticketFlow?.[WH[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=ey(s,a),c=qH(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 PI(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await M({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:II(),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 BI(e){let t=await Kn(e);if(!t)throw new Error("no ticket linked to this Track");let n=await ss(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=ey(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await lo(e)),{key:t.key,url:t.url,current:s?{id:s.id,name:s.name??null,type:s.type??null}:null,states:[...o].sort((a,i)=>a.position-i.position).map(({id:a,name:i,type:c,position:l})=>({id:a,name:i,type:c,position:l}))}}async function ny(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await Kn(e);if(!r)throw new Error("no ticket linked to this Track");let o=await ss(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=ey(s,a),c=a.find(u=>u.id===t);if(!c)throw new Error("unknown state for this ticket's team");let l=i?.name??r.state??null;return i?.id===c.id?(r.state!==c.name&&(r.state=c.name,await lo(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await PI(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function jI(e,t){let n=await Kn(e);if(!n)throw new Error("no ticket linked to this Track");let r=await ss(n);if(!r)throw new Error("no ticketing integration configured");let o=String(t||"").trim();if(!o)throw new Error("comment body required");let s=await r.api.createComment(r.cfg,n,o);return await M({id:e,cwd:n.track?.cwd},{type:"ticket.commented",actor:"user",source:"orchestrator",payload:{ts:Date.now(),key:n.key,url:s??n.url,excerpt:o.length>280?`${o.slice(0,279)}\u2026`:o}}).catch(()=>{}),{key:n.key,url:s??n.url}}async function LI(e,t,n){if(!t)throw new Error("offerId required");return eo(`tkt:${e.id}:${t}`,()=>KH(e,t,n))}async function KH(e,t,n){let r=await q({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 ny(e.id,o.payload.to?.id,{mode:"offer"})),await M({id:e.id,cwd:e.cwd},{type:"ticket.move.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,action:n?"moved":"dismiss",...s?{from:s.from,to:s.to}:{}}}),{offerId:t,action:n?"moved":"dismiss",...s??{}}}var SI=50;async function FI(){let e=await ns();if(!e)throw new Error("no ticketing integration configured");return _a(e)}function GH(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>SI)throw new Error(`too many issues (${n.length}); cap is ${SI} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function zH(e,t,n,r){let o=r??await _a(e),s=i=>o.find(c=>c.id===i||c.key.toLowerCase()===String(i).toLowerCase()||c.name.toLowerCase()===String(i).toLowerCase())??null;if(t.team){let i=s(t.team);if(i)return i}let a=await Kn(n.id);if(a?.key){let i=a.key.split("-")[0],c=o.find(l=>l.key===i);if(c)return c}if(e.defaultTeam){let i=s(e.defaultTeam);if(i)return i}return o.length===1?o[0]:null}async function UI(e,t){let n=await ns();if(!n)throw new Error("no ticketing integration configured \u2014 add a linear apiKey to ~/.bostrat/integrations.json");if(n.ticketFlow?.create==="off")throw new Error("ticket creation offers are off (bostrat-ticket flow set create=prompt to re-enable)");let r=GH(t),o=await _a(n),s=await zH(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=II();return await M({id:e.id,cwd:e.cwd},{type:"ticket.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:i,provider:"linear",epic:r.epic,issues:r.issues,team:a,needsTeam:!s,linkCurrentTrack:r.linkCurrentTrack}}),{proposalId:i,epic:r.epic,issues:r.issues,team:a,needsTeam:!s}}async function HI(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await q({id:e.id,cwd:e.cwd}),s=o.find(w=>w.type==="ticket.create.offered"&&w.payload?.proposalId===t);if(!s)throw new Error("unknown proposal");if(o.some(w=>w.type==="ticket.create.answered"&&w.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await M({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};let a=await ns();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let w=(await _a(a)).find(m=>m.id===r);if(!w)throw new Error("unknown team");c={id:w.id,key:w.key,name:w.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],d=null;if(i.epic){let w=await qg(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});d=w.id,l.push({kind:"epic",title:w.name,url:w.url})}for(let w of i.issues||[])try{let m=await Kg(a,{teamId:c.id,title:w.title,description:w.description,projectId:d,priority:w.priority});l.push({kind:"issue",key:m.key,title:m.title,url:m.url})}catch(m){u.push({title:w.title,message:m?.message||String(m)})}await M({id:e.id,cwd:e.cwd},{type:"ticket.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,team:{key:c.key,name:c.name},items:l,failed:u}}),await M({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",createdCount:l.length,failedCount:u.length}});let p=l.filter(w=>w.kind==="issue"),f=null;return i.linkCurrentTrack&&p.length===1&&!await Kn(e.id)&&(f=await Ia(e,p[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:f?f.key:null}}async function Fc(e,t){let n=await ss(e);n&&await n.api.createComment(n.cfg,e,t)}async function VH(e,t,n){let r=await ss(e);if(!r)return null;let o=await pr(t);if(!o)return null;let s=pn(o,n);if(!s)return null;let a=await Uc.readFile(Yt(o,s.v).png).catch(()=>null);return a?r.api.uploadImage(r.cfg,{issue:e.key,filename:`${o.name.replace(/[^\w.-]+/g,"-")}.v${s.v}.png`,contentType:"image/png",buffer:a}):null}var TI=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),Jg=new Map;function JH(e,t){if(TI()<=0)return Hc(e,t);if(Jg.has(e))return;let n=setTimeout(()=>{Jg.delete(e),Kn(e).then(r=>r?Hc(e,r):null).catch(()=>{})},TI());n.unref?.(),Jg.set(e,n)}var AI=new Map;async function EI(e,t,n){let r=AI.get(e)??0;Date.now()-r<600*1e3||(AI.set(e,Date.now()),await M({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function YH(e,{resolveTrack:t=null}={}){let n=await Kn(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Qg())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 EI(e.trackId,s.cwd,a)}return}if(!n.track.cwd&&t){let o=await t(e.trackId).catch(()=>null);o?.cwd&&(n.track.cwd=o.cwd,await lo(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await lo(e.trackId),await Hc(e.trackId,n);break;case"pr.state.changed":{if(!r.change)break;if(r.number&&(n.pr={number:r.number,url:r.url??n.pr?.url??null,change:r.change}),await lo(e.trackId),await Hc(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await NI(n,e.trackId).catch(()=>null):null;await Fc(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
728
+ }`,{contentType:n,filename:t,size:r.length}),s=o.fileUpload?.uploadFile;if(!o.fileUpload?.success||!s?.uploadUrl)throw new Error("linear: fileUpload did not succeed");let a={"content-type":n};for(let c of s.headers||[])a[c.key]=c.value;let i=await fetch(s.uploadUrl,{method:"PUT",headers:a,body:r});if(!i.ok)throw new Error(`linear: asset PUT failed (HTTP ${i.status})`);return s.assetUrl}async function AW(e,t){let n=await Gn(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 TW(e,t,n){if(!(await Gn(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 Wa(e){return((await Gn(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var o$=255;async function Ay(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>o$,a=s?`${o.slice(0,o$-1).trimEnd()}\u2026`:o,i=await Gn(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 Ty(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await Gn(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}}dc();var d$={linear:{api:Ey,config:ks},jira:{api:vy,config:Rp}};async function Cy(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(d$)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function Ss(e){let t=d$[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function Ny(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 p$=()=>process.env.BOSTRAT_STATE_DIR||l$.join(process.env.HOME||EW.tmpdir(),".bostrat"),Ry=()=>l$.join(p$(),"tickets.json"),f$=()=>(process.env.BOSTRAT_PUBLIC_URL||"http://bostrat.globopi").replace(/\/$/,""),Mp=e=>`${f$()}/track/${e}`,go=null,_y=null,Iy=Promise.resolve();async function sl(){return go||(_y??=rl.readFile(Ry(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{if(go=e,!t&&Ue()){let{records:n,source:r}=await it("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;go[s]=i}Object.keys(go).length&&await Oy().catch(()=>{})}}return go}).finally(()=>_y=null),_y)}async function Oy(){let e=JSON.stringify({tickets:go},null,2),t=`${Ry()}.${process.pid}.tmp`;await rl.mkdir(p$(),{recursive:!0}),await rl.writeFile(t,e),await rl.rename(t,Ry())}async function yo(e=null){if(Iy=Iy.then(Oy,Oy),await Iy.catch(()=>{}),!e)return;let t=go?.[e];t?vt("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):on("tickets",e).catch(()=>{})}async function zn(e){return(await sl())[e]??null}async function h$(){return{...await sl()}}async function m$(){return(await Cy()).length>0}async function qa(e,t,{source:n="api"}={}){let r=await Cy();if(!r.length)throw new Error("no ticketing integration configured \u2014 add a linear or jira entry to ~/.bostrat/integrations.json");let o=null,s=null,a=null;for(let u of r){let d=u.api.parseIssueRef(t);if(d)try{s=await u.api.resolveIssue(u.cfg,d),o=u;break}catch(p){a=p}}if(!o)throw a||new Error(`"${t}" is not a Linear or Jira issue URL or key (ABC-123)`);let i=(e.boxes||[]).find(u=>u.name===e.leadBox),c={provider:o.name,key:s.key,issueId:s.issueId,url:s.url,title:s.title,state:s.state,source:n,linkedAt:Date.now(),track:{name:e.name,branch:e.workspace?.branch??null,leadAgent:i?.agent??null,cwd:e.cwd??null,...e.workspace?.kind==="multi"?{repos:(e.workspace.repos??[]).map(u=>u?.name).filter(Boolean)}:{}},pr:null};(await sl())[e.id]=c,await yo(e.id),await C({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 ol(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 nl(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await y$(e.id,c,"linked"),c}async function Py(e){let t=await sl();return t[e]?(delete t[e],await yo(e),!0):!1}var My=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function w$(e,t){if(!e.track?.cwd)return null;let n=Kr(await K({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function _W(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${My(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${My(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function IW(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(My(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function ol(e,t){let n=await Ss(t);if(!n)return;let r=await w$(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:Mp(e),title:`Bostrat Track: ${t.track.name}`,subtitle:IW(t,r)})}function Cp(e){let t=new URL(f$());return`${t.protocol}//${e}.${t.host}/`}var $W={linked:"linked",opened:"prOpened",merged:"prMerged"};function RW(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 g$(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await yo(e),await C({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 y$(e,t,n){let r=await Ss(t);if(!r)return;let o=r.cfg.ticketFlow?.[$W[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Ny(s,a),c=RW(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 g$(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await C({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:u$(),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 b$(e){let t=await zn(e);if(!t)throw new Error("no ticket linked to this Track");let n=await Ss(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=Ny(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await yo(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 Dy(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await zn(e);if(!r)throw new Error("no ticket linked to this Track");let o=await Ss(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Ny(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 yo(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await g$(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function k$(e,t){let n=await zn(e);if(!n)throw new Error("no ticket linked to this Track");let r=await Ss(n);if(!r)throw new Error("no ticketing integration configured");let o=String(t||"").trim();if(!o)throw new Error("comment body required");let s=await r.api.createComment(r.cfg,n,o);return await C({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 x$(e,t,n){if(!t)throw new Error("offerId required");return co(`tkt:${e.id}:${t}`,()=>OW(e,t,n))}async function OW(e,t,n){let r=await K({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type==="ticket.move.offered"&&a.payload?.offerId===t);if(!o)throw new Error("unknown offer");if(r.some(a=>a.type==="ticket.move.answered"&&a.payload?.offerId===t))throw new Error("offer already answered");let s=null;return n&&(s=await Dy(e.id,o.payload.to?.id,{mode:"offer"})),await C({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 s$=50;async function v$(){let e=await ks();if(!e)throw new Error("no ticketing integration configured");return Wa(e)}function MW(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>s$)throw new Error(`too many issues (${n.length}); cap is ${s$} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function CW(e,t,n,r){let o=r??await Wa(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 zn(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 S$(e,t){let n=await ks();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=MW(t),o=await Wa(n),s=await CW(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=u$();return await C({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 A$(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await K({id:e.id,cwd:e.cwd}),s=o.find(w=>w.type==="ticket.create.offered"&&w.payload?.proposalId===t);if(!s)throw new Error("unknown proposal");if(o.some(w=>w.type==="ticket.create.answered"&&w.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await C({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 ks();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let w=(await Wa(a)).find(h=>h.id===r);if(!w)throw new Error("unknown team");c={id:w.id,key:w.key,name:w.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],d=null;if(i.epic){let w=await Ay(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});d=w.id,l.push({kind:"epic",title:w.name,url:w.url})}for(let w of i.issues||[])try{let h=await Ty(a,{teamId:c.id,title:w.title,description:w.description,projectId:d,priority:w.priority});l.push({kind:"issue",key:h.key,title:h.title,url:h.url})}catch(h){u.push({title:w.title,message:h?.message||String(h)})}await C({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 C({id:e.id,cwd:e.cwd},{type:"ticket.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",createdCount:l.length,failedCount:u.length}});let p=l.filter(w=>w.kind==="issue"),f=null;return i.linkCurrentTrack&&p.length===1&&!await zn(e.id)&&(f=await qa(e,p[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:f?f.key:null}}async function nl(e,t){let n=await Ss(e);n&&await n.api.createComment(n.cfg,e,t)}async function NW(e,t,n){let r=await Ss(e);if(!r)return null;let o=await mr(t);if(!o)return null;let s=hn(o,n);if(!s)return null;let a=await rl.readFile(en(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 a$=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),$y=new Map;function PW(e,t){if(a$()<=0)return ol(e,t);if($y.has(e))return;let n=setTimeout(()=>{$y.delete(e),zn(e).then(r=>r?ol(e,r):null).catch(()=>{})},a$());n.unref?.(),$y.set(e,n)}var i$=new Map;async function c$(e,t,n){let r=i$.get(e)??0;Date.now()-r<600*1e3||(i$.set(e,Date.now()),await C({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function DW(e,{resolveTrack:t=null}={}){let n=await zn(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Cy())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 qa(s,o,{source:"chat"})}catch(a){await c$(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 yo(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await yo(e.trackId),await ol(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 yo(e.trackId),await ol(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await w$(n,e.trackId).catch(()=>null):null;await nl(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
725
729
 
726
- Agent cost for this Track: ${UH(o)}.`:"")),await DI(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await VH(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await Fc(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
730
+ Agent cost for this Track: ${_W(o)}.`:"")),await y$(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await NW(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await nl(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
727
731
 
728
- ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await Fc(n,`**Bostrat** \u2014 design decision: **${r.name}** picked${o?` over ${o}`:""}.`)}break}case"view.state.changed":{if(r.change!=="created"||r.restarted||!r.slug)break;await Fc(n,`**Bostrat** \u2014 live preview **${r.name}**: ${tp(r.slug)}
729
- _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await JH(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await EI(e.trackId,s?.cwd??null,o)}}function WI({resolveTrack:e}){Je.on("event",t=>{YH(t,{resolveTrack:e}).catch(()=>{})})}async function qI(){if(!He())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await st("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Wc(),r=0;for(let[o,s]of Object.entries(n))await bt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}Do();da();import XH from"ws";var KI=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function np(e,t,n={}){let r=await fetch(`${KI()}/${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 ry=(e,t)=>np("chat.postMessage",e,t),as=(e,t)=>np("chat.update",e,t);async function xt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function ZH(e,t,n={}){let r=await fetch(`${KI()}/${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 GI(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await ZH("files.getUploadURLExternal",e,{filename:t,length:String(n.length)}),l=await fetch(i,{method:"POST",body:n});if(!l.ok)throw new Error(`slack upload: http ${l.status}`);return np("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var QH=2200;function zI({getToken:e,onEnvelope:t,log:n=()=>{}}){let r=!1,o=null,s=null,a=1e3;async function i(){if(r)return;let l;try{let u=await e();if(!u)throw new Error("app token missing");({url:l}=await np("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new XH(l),o.on("message",u=>{let d;try{d=JSON.parse(u)}catch{return}if(d.type==="hello"){a=1e3,n("socket connected");return}if(d.type==="disconnect"){try{o.close()}catch{}return}if(!d.envelope_id)return;let p=m=>{try{o.send(JSON.stringify(m?{envelope_id:d.envelope_id,payload:m}:{envelope_id:d.envelope_id}))}catch{}},f=!1,w=setTimeout(()=>{f=!0,p()},QH);Promise.resolve().then(()=>t(d)).then(m=>{clearTimeout(w),!f&&(f=!0,p(d.accepts_response_payload?m:void 0))},m=>{clearTimeout(w),f||(f=!0,p()),n(`envelope handler failed: ${m?.message||m}`)})}),o.on("close",c),o.on("error",u=>{n(`socket error: ${u?.message||u}`);try{o.close()}catch{}})}function c(){if(r||s)return;let l=a;a=Math.min(a*2,6e4),s=setTimeout(()=>{s=null,i()},l)}return i(),()=>{r=!0,s&&clearTimeout(s);try{o?.close()}catch{}}}var YI=()=>process.env.BOSTRAT_STATE_DIR||op.join(process.env.HOME||tW.tmpdir(),".bostrat"),cy=()=>op.join(YI(),"slack.json"),rp=null,oy=null,sy=Promise.resolve();async function uy(){return rp||(oy??=qc.readFile(cy(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>rp=e).finally(()=>oy=null),oy)}async function VI(){let e=JSON.stringify({threads:rp},null,2),t=`${cy()}.${process.pid}.tmp`;await qc.mkdir(YI(),{recursive:!0}),await qc.writeFile(t,e),await qc.rename(t,cy())}async function yn(){sy=sy.then(VI,VI),await sy.catch(()=>{})}async function dy(e){return(await uy())[e]??null}async function nW(e,t){let n=await uy();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var Se=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function Kc(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function rW(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return Kc(n.replace(/\n+/g," "),t)}function XI(e){let t=`*${Se(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${Se(e.repoLabel)} \xB7 \`${Se(e.branch||"?")}\` \xB7 lead *${Se(e.lead)}*`,r=e.kickoff?`> ${Se(Kc(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
730
- ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${ep(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function ly(e,t){await as(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:XI(t)})}async function po(e,t,n,r=void 0){return ry(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var JI=new Set;function uo(e){JI.add(e),e.catch(()=>{}).finally(()=>JI.delete(e))}var Ue=e=>({response_type:"ephemeral",text:e}),oW="*/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._",sW=["claude","cursor","codex"];function ay(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 iy=(e,t)=>Ue(`No live Track matches \u201C${Se(t)}\u201D. Live: ${e.map(n=>`\`${Se(n.name)}\``).join(" \xB7 ")||"none"}`);async function ZI(e,t,{name:n,repo:r,responseUrl:o}){let s=e.deps;try{let a=(await s.listTracks()).filter(d=>!d.archivedAt);if(a.length>=t.maxConcurrent){await xt(o,{...Ue(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await xt(o,{...Ue("No designated channel configured \u2014 set `slack.channel` in integrations.json."),replace_original:!0});return}let i=await s.createTrack({name:n,...r?{repo:r}:{}}),c=i.workspace||{},l={trackId:i.id,channel:t.channel,name:i.name,branch:c.branch||null,repoLabel:c.repo||(c.base?op.basename(c.base):"fresh workspace"),lead:"claude"},u=await ry(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:XI(l),unfurl_links:!1});l.ts=u.ts,(await uy())[i.id]=l,await yn(),await xt(o,{...Ue(`\u2713 *${Se(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await xt(o,{...Ue(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function aW(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await dy(n.id);s&&(s.archivedAt=Date.now(),await yn(),await ly(t,s).catch(()=>{})),await xt(r,{...Ue(`\u2713 *${Se(n.name)}* archived.`),replace_original:!0})}catch(s){await xt(r,{...Ue(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function iW(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await xt(o,{...Ue(`\u2713 Handing *${Se(n.name)}* to ${Se(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await xt(o,{...Ue(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function cW(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.interruptLead(n.id);let s=(o.listSubtaskJobs?.(n.id)??[]).filter(a=>!a.finishedAt);for(let a of s)try{o.cancelSubtask(a.id)}catch{}await xt(r,{...Ue(`\u2713 Stopped *${Se(n.name)}*${s.length?` (+ ${s.length} subtask${s.length>1?"s":""} canceled)`:""} \u2014 Track parked, resume from the Track page.`),replace_original:!0})}catch(s){await xt(r,{...Ue(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function lW(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:Kc(`${r.name} (${r.branch})`,75)},value:r.path})),{text:{type:"plain_text",text:"fresh workspace"},value:"__fresh__"}];return[{type:"section",block_id:JSON.stringify({name:e}),text:{type:"mrkdwn",text:`Repo for *${Se(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function uW(e){let t=await e.listTracks(),n=t.filter(s=>!s.archivedAt);if(n.sort((s,a)=>(a.lastResponseAt??a.createdAt??0)-(s.lastResponseAt??s.createdAt??0)),!n.length)return"No live Tracks.";let r=n.map(s=>{let a=s.workspace||{},i=a.repo||(a.base?op.basename(a.base):"fresh"),c=[...s.boxes||[]].reverse().find(u=>u.role==="lead")?.agent||"?",l=s.prompted?"\u26A0 needs an answer":s.working?"working":"idle";return`\u2022 *${Se(s.name)}* \u2014 ${Se(i)}${a.branch?` \`${Se(a.branch)}\``:""} \xB7 lead ${Se(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
732
+ ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await nl(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 nl(n,`**Bostrat** \u2014 live preview **${r.name}**: ${Cp(r.slug)}
733
+ _(runs on the Track's branch; reachable on the operator's private network only)_`);break}case"cost.recorded":await PW(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await c$(e.trackId,s?.cwd??null,o)}}function T$({resolveTrack:e}){Je.on("event",t=>{DW(t,{resolveTrack:e}).catch(()=>{})})}async function E$(){if(!Ue())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await it("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await sl(),r=0;for(let[o,s]of Object.entries(n))await vt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}Zo();Ea();import BW from"ws";var _$=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function Np(e,t,n={}){let r=await fetch(`${_$()}/${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 By=(e,t)=>Np("chat.postMessage",e,t),As=(e,t)=>Np("chat.update",e,t);async function Tt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function jW(e,t,n={}){let r=await fetch(`${_$()}/${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 I$(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await jW("files.getUploadURLExternal",e,{filename:t,length:String(n.length)}),l=await fetch(i,{method:"POST",body:n});if(!l.ok)throw new Error(`slack upload: http ${l.status}`);return Np("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var LW=2200;function $$({getToken:e,onEnvelope:t,log:n=()=>{}}){let r=!1,o=null,s=null,a=1e3;async function i(){if(r)return;let l;try{let u=await e();if(!u)throw new Error("app token missing");({url:l}=await Np("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new BW(l),o.on("message",u=>{let d;try{d=JSON.parse(u)}catch{return}if(d.type==="hello"){a=1e3,n("socket connected");return}if(d.type==="disconnect"){try{o.close()}catch{}return}if(!d.envelope_id)return;let p=h=>{try{o.send(JSON.stringify(h?{envelope_id:d.envelope_id,payload:h}:{envelope_id:d.envelope_id}))}catch{}},f=!1,w=setTimeout(()=>{f=!0,p()},LW);Promise.resolve().then(()=>t(d)).then(h=>{clearTimeout(w),!f&&(f=!0,p(d.accepts_response_payload?h:void 0))},h=>{clearTimeout(w),f||(f=!0,p()),n(`envelope handler failed: ${h?.message||h}`)})}),o.on("close",c),o.on("error",u=>{n(`socket error: ${u?.message||u}`);try{o.close()}catch{}})}function c(){if(r||s)return;let l=a;a=Math.min(a*2,6e4),s=setTimeout(()=>{s=null,i()},l)}return i(),()=>{r=!0,s&&clearTimeout(s);try{o?.close()}catch{}}}var M$=()=>process.env.BOSTRAT_STATE_DIR||Dp.join(process.env.HOME||UW.tmpdir(),".bostrat"),Hy=()=>Dp.join(M$(),"slack.json"),Pp=null,jy=null,Ly=Promise.resolve();async function qy(){return Pp||(jy??=al.readFile(Hy(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>Pp=e).finally(()=>jy=null),jy)}async function R$(){let e=JSON.stringify({threads:Pp},null,2),t=`${Hy()}.${process.pid}.tmp`;await al.mkdir(M$(),{recursive:!0}),await al.writeFile(t,e),await al.rename(t,Hy())}async function kn(){Ly=Ly.then(R$,R$),await Ly.catch(()=>{})}async function Ky(e){return(await qy())[e]??null}async function HW(e,t){let n=await qy();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var Te=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function il(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function WW(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return il(n.replace(/\n+/g," "),t)}function C$(e){let t=`*${Te(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${Te(e.repoLabel)} \xB7 \`${Te(e.branch||"?")}\` \xB7 lead *${Te(e.lead)}*`,r=e.kickoff?`> ${Te(il(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
734
+ ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${Mp(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function Wy(e,t){await As(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:C$(t)})}async function ko(e,t,n,r=void 0){return By(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var O$=new Set;function bo(e){O$.add(e),e.catch(()=>{}).finally(()=>O$.delete(e))}var Fe=e=>({response_type:"ephemeral",text:e}),qW="*/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._",KW=["claude","cursor","codex"];function Fy(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 Uy=(e,t)=>Fe(`No live Track matches \u201C${Te(t)}\u201D. Live: ${e.map(n=>`\`${Te(n.name)}\``).join(" \xB7 ")||"none"}`);async function N$(e,t,{name:n,repo:r,responseUrl:o}){let s=e.deps;try{let a=(await s.listTracks()).filter(d=>!d.archivedAt);if(a.length>=t.maxConcurrent){await Tt(o,{...Fe(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await Tt(o,{...Fe("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?Dp.basename(c.base):"fresh workspace"),lead:"claude"},u=await By(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:C$(l),unfurl_links:!1});l.ts=u.ts,(await qy())[i.id]=l,await kn(),await Tt(o,{...Fe(`\u2713 *${Te(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await Tt(o,{...Fe(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function GW(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await Ky(n.id);s&&(s.archivedAt=Date.now(),await kn(),await Wy(t,s).catch(()=>{})),await Tt(r,{...Fe(`\u2713 *${Te(n.name)}* archived.`),replace_original:!0})}catch(s){await Tt(r,{...Fe(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function zW(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await Tt(o,{...Fe(`\u2713 Handing *${Te(n.name)}* to ${Te(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await Tt(o,{...Fe(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function VW(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.interruptLead(n.id);let s=(o.listSubtaskJobs?.(n.id)??[]).filter(a=>!a.finishedAt);for(let a of s)try{o.cancelSubtask(a.id)}catch{}await Tt(r,{...Fe(`\u2713 Stopped *${Te(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 Tt(r,{...Fe(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function JW(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:il(`${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 *${Te(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function YW(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?Dp.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 *${Te(s.name)}* \u2014 ${Te(i)}${a.branch?` \`${Te(a.branch)}\``:""} \xB7 lead ${Te(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
731
735
  `)+(o?`
732
- _${o} archived_`:"")}async function dW(e,t){let n=await rs();if(!n)return Ue("Slack integration not configured.");let r=e.deps,o=(t.text||"").trim().split(/\s+/).filter(Boolean),s=(o[0]||"help").toLowerCase(),a=o.slice(1);switch(s){case"start":{if(!a.length)return Ue("Usage: `/bostrat start <name> [repo]`");let i=await r.listRepos(),c=a[a.length-1]?.toLowerCase(),l=a.length>1?i.find(d=>d.name.toLowerCase()===c):null,u=(l?a.slice(0,-1):a).join(" ");return l?(uo(ZI(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),Ue(`Starting *${Se(u)}* on ${Se(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:lW(u,i)}}case"archive":{if(!a.length)return Ue("Usage: `/bostrat archive <track>`");let{match:i,live:c}=ay(await r.listTracks(),a.join(" "));return i?(uo(aW(e,n,{track:i,responseUrl:t.response_url})),Ue(`Archiving *${Se(i.name)}*\u2026`)):iy(c,a.join(" "))}case"handoff":{let i=r.knownAgents??sW,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return Ue(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:d}=ay(await r.listTracks(),l);return u?(uo(iW(e,n,{track:u,agent:c,responseUrl:t.response_url})),Ue(`Handing *${Se(u.name)}* to ${Se(c)}\u2026`)):iy(d,l)}case"stop":{if(!a.length)return Ue("Usage: `/bostrat stop <track>`");let{match:i,live:c}=ay(await r.listTracks(),a.join(" "));return i?(uo(cW(e,n,{track:i,responseUrl:t.response_url})),Ue(`Stopping *${Se(i.name)}*\u2026`)):iy(c,a.join(" "))}case"list":return Ue(await uW(r));default:return Ue(oW)}}async function pW(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await dy(o);try{if(await e.deps.answerPrompt(o,{promptId:s,answers:[a]}),i?.prompt?.promptId===s){let{ts:c,question:l}=i.prompt;delete i.prompt,await yn(),await as(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Se(l||"question")}~
733
- \u2713 *${Se(a)}*`}}]}).catch(()=>{})}}catch(c){await xt(n.response_url,Ue(`Couldn't answer: ${c?.message||c}`))}}async function fW(e,t,n,r){let{trackId:o,offerId:s,action:a}=r,i=e.deps;try{let c=await i.resolveTrack(o);if(!c)throw new Error("track not found");let l=await i.readEvents(c),u=l.find(p=>p.type==="pr.offered"&&p.payload?.offerId===s);if(!u)throw new Error("unknown offer");if(l.some(p=>p.type==="pr.offer.answered"&&p.payload?.offerId===s))throw new Error("offer already answered");let d=Array.isArray(r.actions)?Gr.filter(p=>r.actions.includes(p)):a==="pr"?["commit","push","pr"]:a==="push"?["commit","push"]:null;if(d?.includes("pr")&&i.divertShip&&await i.divertShip(c,u,{actions:d}))return;d&&await i.sayToLead(c.id,Js(d,{branch:u.payload.branch,base:u.payload.base}),{kind:d.includes("pr")?"pr-go":"push-go"}),await i.appendEvent({id:c.id,cwd:c.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:u.boxId,payload:{ts:Date.now(),offerId:s,action:d?a:"dismiss",actions:d}})}catch(c){await xt(n.response_url,Ue(`Couldn't act on the offer: ${c?.message||c}`))}}async function mW(e,t,n,r){let{trackId:o,offerId:s,choice:a}=r;try{let i=await e.deps.resolveTrack(o);if(!i)throw new Error("track not found");await e.deps.answerPrExists(i,{offerId:s,choice:a})}catch(i){await xt(n.response_url,Ue(`Couldn't act on the offer: ${i?.message||i}`))}}async function hW(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await rs();if(!r)return;if(n.action_id==="bostrat-start-repo"){let s;try{({name:s}=JSON.parse(n.block_id))}catch{return}let a=n.selected_option?.value;await xt(t.response_url,{...Ue(`Starting *${Se(s)}*\u2026`),replace_original:!0}),uo(ZI(e,r,{name:s,repo:a==="__fresh__"?null:a,responseUrl:t.response_url}));return}let o;try{o=JSON.parse(n.value)}catch{return}n.action_id==="bostrat-prompt"?uo(pW(e,r,t,o)):n.action_id==="bostrat-ship"?uo(fW(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&uo(mW(e,r,t,o))}async function wW(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 nW(t.channel,t.thread_ts);if(!n)return;let r=await rs();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await po(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function gW(e){return async t=>{if(t.type==="slash_commands")return dW(e,t.payload);if(t.type==="interactive"){await hW(e,t.payload);return}if(t.type==="events_api"){await wW(e,t.payload?.event);return}}}var yW=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 bW(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${Se(t.question||"The lead needs an answer")}`}}],r=(t.options||[]).slice(0,12);return r.length?n.push({type:"actions",elements:r.map(o=>({type:"button",action_id:"bostrat-prompt",text:{type:"plain_text",text:Kc(String(o),75)},value:JSON.stringify({trackId:e,promptId:t.promptId,label:String(o)})}))}):n.push({type:"context",elements:[{type:"mrkdwn",text:"_reply in this thread to answer_"}]}),n}async function kW(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await as(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Se(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await po(e,t,r.question||"The lead needs an answer",bW(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await yn()}async function xW(e,t,n){let r=n.payload||{};if(!t.prompt||r.promptId&&t.prompt.promptId!==r.promptId)return;let{ts:o,question:s}=t.prompt;delete t.prompt,await yn(),await as(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Se(s||"question")}~
734
- \u2713 _answered_`}}]})}async function vW(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=(i,c,l,u)=>({type:"button",action_id:"bostrat-ship",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,action:i,...u?{actions:u}:{}}),...l?{style:l}:{}}),s;if(!Array.isArray(r.available))s=r.toPr?[o("push",`Commit & push${r.toPr.number?` to #${r.toPr.number}`:""}`,"primary"),o("dismiss","Not now")]:[o("pr","Open PR","primary"),o("push","Just push"),o("dismiss","Not now")];else{let i=r.available,c=Array.isArray(r.defaults)&&r.defaults.length?r.defaults:i,l={commit:"Commit",rebase:"rebase",push:"push",pr:r.prState==="open"?"open new PR":"open PR"},u=c.map(d=>l[d]).filter(Boolean).join(" & ");s=[o(c.includes("pr")?"pr":"push",u||"Ship","primary",c)],i.includes("pr")&&!c.includes("pr")&&s.push(o("pr","Open new PR",void 0,["pr"])),s.push(o("dismiss","Not now"))}let a=await po(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${Se(Kc(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await yn()}async function SW(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await yn();let s=r.action==="dismiss"?"dismissed":r.action==="pr-exists"?`PR${r.existingPr?.number?` #${r.existingPr.number}`:""} already open \u2014 pick how to ship`:r.action==="pr"?"\u2713 opening a PR":"\u2713 pushing";await as(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function TW(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=r.pr?.number?`#${r.pr.number}`:"a PR",s=(i,c,l)=>({type:"button",action_id:"bostrat-pr-exists",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,choice:i}),...l?{style:l}:{}}),a=await po(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${Se(r.branch)})`:""} is already open. Push the update to it, or open a new PR?`}},{type:"actions",elements:[s("push",`Push to ${o}`,"primary"),s("new","Open a new PR"),s("dismiss","Not now")]}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await yn()}async function AW(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await yn();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await as(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function EW(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??_W)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await GI(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${Se(o.name)}*${a}${o.group?` (group \`${Se(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${Se(a.name)}*`).join(", ");await po(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${Se(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function _W(e,t){let n=await pr(e);if(!n)return null;let r=pn(n,t);if(!r)return null;let o=await qc.readFile(Yt(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function IW(e,t){if(!yW.has(t.type))return;let n=await dy(t.trackId);if(!n)return;let r=await rs();if(!r)return;let o=t.payload||{};switch(t.type){case"turn.user":if(n.kickoff||t.actor!=="user"||!o.text)return;n.kickoff=o.text,await yn(),await ly(r,n);return;case"turn.agent":{if(!o.text)return;let s=rW(o.text);if(!s)return;await po(r,n,s,[{type:"section",text:{type:"mrkdwn",text:Se(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${ep(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return kW(r,n,t);case"prompt.answered":return xW(r,n,t);case"pr.offered":return vW(r,n,t);case"pr.offer.answered":return SW(r,n,t);case"pr.exists.offered":return TW(r,n,t);case"pr.exists.answered":return AW(r,n,t);case"pr.state.changed":{if(o.change!=="opened"&&o.change!=="merged")return;let s=o.change==="opened"?"PR opened":"PR merged";await po(r,n,`${s}${o.url?`: ${o.url}`:o.number?` (#${o.number})`:""}`);return}case"handoff.done":if(!o.toAgent||o.toAgent===n.lead)return;n.lead=o.toAgent,await yn(),await ly(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await po(r,n,`Live preview ${o.name}: ${tp(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${Se(o.name)}*: ${tp(o.slug)}
735
- _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return EW(r,n,t,e.deps)}}function QI(e){let t={deps:e};Je.on("event",s=>{IW(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await rs()||(r&&clearInterval(r),r=null,n=zI({getToken:async()=>(await rs())?.appToken,onEnvelope:gW(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}an();pe();Tn();bh();Qn();import $W from"node:fs/promises";function RW(e){let t=new Map;for(let n of String(e||"").split(`
736
- `)){let r=n.trim();if(!r||r[0]!=="{")continue;let o;try{o=JSON.parse(r)}catch{continue}let s=o?.message?.usage;if(!s)continue;let a={input:s.input_tokens||0,output:s.output_tokens||0,cacheWrite:s.cache_creation_input_tokens||0,cacheRead:s.cache_read_input_tokens||0};if(a.input+a.output+a.cacheWrite+a.cacheRead===0)continue;let i=o.message?.id||o.uuid||null;if(!i)continue;let c=s.cache_creation,l=c&&typeof c=="object"?{m5:c.ephemeral_5m_input_tokens||0,h1:c.ephemeral_1h_input_tokens||0}:null,u=typeof s.speed=="string"&&s.speed!=="standard"?s.speed:null;t.set(i,{messageId:i,tokens:a,cacheWriteTtl:l,speed:u,model:o.message?.model||o.model||null})}return[...t.values()]}function OW(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 MW=new Set(["Write","Edit","NotebookEdit"]),CW=220,NW=160;function PW(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(MW.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,CW)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=vo(o.command.trim().replace(/\s+/g," ")).slice(0,NW));return r}function DW(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?sn(t.cwd,t.sessionId):t?.cwd?yf(t.cwd):null}async function e$(e,t){let n=await t(e?.session_id,e?.cwd);if(!n?.track)return[];let{track:r,box:o}=n,s={boxId:o?.name||null,provider:"claude",source:"hook"},a=[],i=async c=>{a.push(await M(r,{...s,...c}))};switch(e?.hook_event_name){case"SessionStart":await i({type:"session.ready",actor:"system",payload:{sessionId:e.session_id}});break;case"UserPromptSubmit":{let c=String(e.prompt??e.user_prompt??""),l=td(c);await i({type:"turn.user",actor:l?"peer":"user",payload:{promptHead:(l?l.text:c).slice(0,160)||null,...l?{peer:{socket:l.socket,name:l.name,mode:l.mode}}:{}}});break}case"PostToolUse":await i({type:"tool.called",actor:"agent",payload:PW(e,o)});break;case"Stop":await BW(r,o,e,i);break;default:break}return a}async function BW(e,t,n,r){let o=[],s=DW(n,t);if(s)try{o=RW(await $W.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=OW(await q(e)),c=o.filter(u=>!i.has(u.messageId));if(c.length){let u=new Map;for(let d of c){let p=`${d.model||"unknown"}\0${d.speed||""}`,f=u.get(p)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},cacheWriteTtl:null,messageIds:[]};for(let w of Object.keys(f.tokens))f.tokens[w]+=d.tokens[w];d.cacheWriteTtl&&(f.cacheWriteTtl??={m5:0,h1:0},f.cacheWriteTtl.m5+=d.cacheWriteTtl.m5,f.cacheWriteTtl.h1+=d.cacheWriteTtl.h1),f.messageIds.push(d.messageId),f.speed=d.speed||null,u.set(p,f)}for(let[d,p]of u){let f=d.split("\0")[0];await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:f,usd:In(f,p.tokens,void 0,p.speed?{speed:p.speed}:void 0),tokens:p.tokens,...p.speed?{speed:p.speed}:{},cacheWriteTtl:p.cacheWriteTtl,messageId:p.messageIds[p.messageIds.length-1],messageIds:p.messageIds,apiCalls:p.messageIds.length}})}}let l=a.tokens.input+a.tokens.cacheWrite+a.tokens.cacheRead;await r({type:"context.usage",actor:"system",source:"transcript",payload:{model:a.model,occupancy:l,tokens:a.tokens}})}fs();lf();Qu();pe();pe();Lr();pe();Lr();Qn();function Gc(e){let t={};for(let n of e.boxes||[]){let r=n.role&&n.role!=="lead"?` \xB7 ${n.role}`:"";t[n.name]=`${n.name} (${n.agent||"?"}${r})`}return t}var t$=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),n$=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},sp=e=>Math.round(e*1e4)/1e4;async function py(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=t$(),d=0,p=[];for(let f of e||[]){let w=await q(f),m=jr(w,{boxLabels:Gc(f)});if(m.turns===0){f.archivedAt?d++:p.push(f.name||f.id);continue}o+=m.totalUsd,s+=m.turns,a+=m.repricedTurns||0,i+=m.asRecordedUsd||0,c+=m.unpricedTurns||0;for(let g of m.unpricedModels||[])l.add(g);n$(u,m.totalTokens);for(let[g,y]of Object.entries(m.byModel))n[g]||={usd:0,events:0,tokens:t$()},n[g].usd=sp(n[g].usd+y.usd),n[g].events+=y.events,n$(n[g].tokens,y.tokens);for(let[g,y]of Object.entries(m.byProvider))r[g]||={usd:0,events:0},r[g].usd=sp(r[g].usd+y.usd),r[g].events+=y.events;t.push({id:f.id,name:f.name,usd:m.totalUsd,rollup:m})}return t.sort((f,w)=>w.usd-f.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:Bs(),fleet:{totalUsd:sp(o),asRecordedUsd:sp(i),turns:s,repricedTurns:a,unpricedTurns:c,unpricedModels:[...l],totalTokens:u,byModel:n,byProvider:r,tracksWithCost:t.length,tracksSilent:d+p.length,tracksSilentArchived:d,tracksSilentLive:p},tracks:t}}var fo=e=>`$${e.toFixed(4)}`,$a=(e,t)=>String(e).padEnd(t);function r$(e){let{fleet:t,tracks:n}=e,r=[];r.push(`BOSTRAT COST READ-OUT \xB7 ${e.generatedAt}`),e.pricingBasis&&r.push(`basis: ${e.pricingBasis}`);let o=t.tracksSilentLive||[];if(r.push(`fleet total ${fo(t.totalUsd)} over ${t.turns} turn(s) \xB7 ${t.tracksWithCost} track(s) with cost, ${t.tracksSilentArchived??t.tracksSilent} silent (archived)`+(o.length?`, ${o.length} LIVE with no cost data: ${o.join(", ")}`:"")),t.repricedTurns&&r.push(`${t.repricedTurns} turn(s) priced at current table rates (differs from as-recorded)`),t.asRecordedUsd!=null&&Math.abs(t.asRecordedUsd-t.totalUsd)>=.005&&r.push(`as-recorded total ${fo(t.asRecordedUsd)} \xB7 current-rates total ${fo(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${fo(t.totalUsd-t.asRecordedUsd)})`),t.unpricedTurns&&r.push(`\u26A0 ${t.unpricedTurns} turn(s) UNPRICED \u2014 total under-reports. Add PER_MTOK rate(s) for: ${(t.unpricedModels||[]).join(", ")}`),e.pricing){let a=e.pricing;r.push(`rates verified against vendor pages: ${a.tableVerifiedAt??"never"}`+(a.upcomingChanges?.length?` \xB7 scheduled: ${a.upcomingChanges.map(i=>`${i.model} ${i.from}`).join(", ")}`:""));for(let i of a.problems||[])r.push(`\u26A0 RATE TABLE: ${i}`)}r.push(""),r.push("BY MODEL");let s=Object.entries(t.byModel).sort((a,i)=>i[1].usd-a[1].usd);s.length||r.push(" (no cost events yet \u2014 hooks emit on each turn of a newly started box)");for(let[a,i]of s){let c=i.tokens;r.push(` ${$a(a,26)} ${$a(fo(i.usd),10)} ${i.events} turn(s) \xB7 in ${c.input} out ${c.output} cacheR ${c.cacheRead} cacheW ${c.cacheCreation}`)}r.push(""),r.push("BY TRACK / TASK");for(let a of n){r.push(` ${$a(a.name||a.id,30)} ${fo(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${$a(c.label,40)} ${$a(fo(c.usd),10)} ${c.models.join(",")||"?"}`),c.epochs)for(let[l,u]of Object.entries(c.epochs).sort((d,p)=>Number(d[0])-Number(p[0])))r.push(` \u21B3 tenure ${l} (${u.provider||"?"})${" ".repeat(Math.max(1,24-String(u.provider||"?").length))}${$a(fo(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
737
- `)}pe();Wm();import qW from"node:fs/promises";import KW from"node:path";Zl();ru();Lr();var ap=e=>e.payload?.ts??e.ts,jW=12e4,Zt=e=>Math.round(e*1e4)/1e4,LW=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{},byTrack:new Map});function FW(e,{since:t}){let{track:n,events:r,brief:o}=e,s=b=>ap(b)>=t,a=Zn([Ai(n?.name),Ai(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let b of r)if(b.type==="subtask.delegated"&&b.boxId&&b.payload?.task){let O=Zn(b.payload.task);O&&i.set(b.boxId,O)}let c=new Map,l=b=>{let O=b||"unattributed";return c.has(O)||c.set(O,{segments:[u(null)],lastTs:null,provider:null}),c.get(O)},u=(b,{shape:O="initial",continuation:I=!1,text:C=null,ts:U=null}={})=>({textCat:b,shape:O,continuation:I,text:C,ts:U,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),d=[...r].sort((b,O)=>ap(b)-ap(O)),p=0,f=0,w=0,m={turns:0};for(let b of d){let O=l(b.boxId),I=O.segments[O.segments.length-1],C=ap(b);switch(O.lastTs!=null&&C>O.lastTs&&s(b)&&(I.activeMs+=Math.min(C-O.lastTs,jW)),O.lastTs=C,b.provider&&(O.provider=b.provider),b.type){case"turn.user":{let U=b.payload?.text;if(b.source==="hook"||!String(U||"").trim()||b.payload?.note||Ii(U))break;let H=Zn(U),_=!!b.payload?.kind,$=_||v0(U),L=u(H,{shape:_?"injected":$?"follow-up":"novel-ask",continuation:!H&&$,text:s$(U),ts:C});O.segments.push(L),s(b)&&(L.turns+=1);break}case"peer.message":{let U=b.payload?.text;if(!String(U||"").trim())break;let H=Zn(U),_=u(H,{shape:"peer",continuation:!H,text:s$(U),ts:C});O.segments.push(_),s(b)&&(_.turns+=1);break}case"tool.called":{if(b.source==="transcript")break;let U=b.payload?.tool;U&&(I.tools[U]=(I.tools[U]||0)+1),s(b)&&(I.toolCalls+=1);break}case"cost.recorded":{if(!s(b))break;let{usd:U,tokens:H,model:_,unpriced:$}=Kt(b);$&&(m.turns+=1),I.usd+=U,H&&(I.tokens.input+=H.input,I.tokens.output+=H.output,I.tokens.cacheRead+=H.cacheRead,I.tokens.cacheWrite+=H.cacheWrite),I.models[_]=(I.models[_]||0)+U,b.provider&&(I.provider=b.provider);break}case"handoff.done":s(b)&&(p+=1);break;case"subtask.merged":s(b)&&(f+=1);break;case"error":s(b)&&b.payload?.kind==="subtask-failed"&&(w+=1);break;default:break}}let g=new Map,y={usd:0,turns:0,byShape:{},samples:[]},x=!1;for(let[b,O]of c){let I=null;for(let C of O.segments){let U=null,H=null;if(C.textCat)U=C.textCat.category,H="text";else if(i.get(b))U=i.get(b).category,H="boxTask";else if(C.continuation&&I)U=I,H="inherited";else{let S=x0(C.tools);S?(U=S.category,H="toolMix"):a&&(U=a.category,H="hint")}if(U&&(I=U),!(C.usd>0||C.activeMs>0||C.turns>0||C.toolCalls>0))continue;let $=U??"uncategorized";g.has($)||g.set($,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{}});let L=g.get($);L.usd+=C.usd,L.activeMs+=C.activeMs,L.turns+=C.turns,L.toolCalls+=C.toolCalls,H&&(L.provenance[H]=(L.provenance[H]||0)+C.usd);for(let[S,E]of Object.entries(C.models))L.models[S]=(L.models[S]||0)+E;let V=C.provider||O.provider;V&&(L.providers[V]=(L.providers[V]||0)+C.usd),V==="cursor"&&C.usd===0&&(x=!0),U||(y.usd+=C.usd,y.turns+=C.turns,y.byShape[C.shape]=(y.byShape[C.shape]||0)+C.usd,C.usd>0&&C.text&&y.samples.push({trackId:n?.id,track:n?.name||n?.id,shape:C.shape,usd:Zt(C.usd),ts:C.ts,text:C.text}))}}return{perCategory:g,uncategorized:y,handoffs:p,merged:f,failed:w,sawCursorActivity:x,unpricedTurns:m.turns}}function fy(e,{windowMs:t=null,now:n=Date.now()}={}){let r=t==null?0:n-t,o=new Map,s=[],a=0,i=!1,c=0,l={usd:0,turns:0,byShape:{},samples:[]};for(let y of e||[]){let{track:x,events:b}=y;if(!b?.length){a+=1;continue}let{perCategory:O,uncategorized:I,handoffs:C,merged:U,failed:H,sawCursorActivity:_,unpricedTurns:$}=FW(y,{since:r});_&&(i=!0),c+=$,l.usd+=I.usd,l.turns+=I.turns;for(let[V,S]of Object.entries(I.byShape))l.byShape[V]=(l.byShape[V]||0)+S;l.samples.push(...I.samples);let L={trackId:x?.id,name:x?.name||x?.id,archived:!!x?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:C,subtasksMerged:U,subtasksFailed:H};for(let[V,S]of O){L.usd+=S.usd,L.activeMs+=S.activeMs,L.turns+=S.turns,L.categories[V]={usd:Zt(S.usd),activeMs:S.activeMs};for(let[W,G]of Object.entries(S.models))L.models[W]=Zt((L.models[W]||0)+G);for(let[W,G]of Object.entries(S.providers))L.providers[W]=Zt((L.providers[W]||0)+G);o.has(V)||o.set(V,LW());let E=o.get(V);E.usd+=S.usd,E.activeMs+=S.activeMs,E.turns+=S.turns,E.toolCalls+=S.toolCalls;for(let[W,G]of Object.entries(S.models))E.models[W]=(E.models[W]||0)+G;for(let[W,G]of Object.entries(S.providers))E.providers[W]=(E.providers[W]||0)+G;for(let[W,G]of Object.entries(S.provenance))E.provenance[W]=(E.provenance[W]||0)+G;let P=E.byTrack.get(x?.id)||{usd:0,activeMs:0};P.usd+=S.usd,P.activeMs+=S.activeMs,E.byTrack.set(x?.id,P)}(L.usd>0||L.activeMs>0||L.turns>0)&&(L.usd=Zt(L.usd),L.dominantCategory=WW(L.categories),s.push(L))}let u=[...o.values()].reduce((y,x)=>y+x.usd,0),d=[...o.values()].reduce((y,x)=>y+x.activeMs,0),p=u>0?"usd":"time",f=p==="usd"?u:d,w=new Map((e||[]).map(y=>[y.track?.id,y.track?.name||y.track?.id])),m=[...o.entries()].map(([y,x])=>({category:y,sharePct:f>0?Math.round((p==="usd"?x.usd:x.activeMs)/f*100):0,shareBasis:p,usd:Zt(x.usd),activeMs:x.activeMs,turns:x.turns,toolCalls:x.toolCalls,models:zc(x.models),providers:zc(x.providers),provenance:zc(x.provenance),topWorkstreams:[...x.byTrack.entries()].sort((b,O)=>O[1].usd-b[1].usd||O[1].activeMs-b[1].activeMs).slice(0,2).map(([b,O])=>({trackId:b,name:w.get(b),usd:Zt(O.usd),activeMs:O.activeMs}))})).sort((y,x)=>x.usd-y.usd||x.activeMs-y.activeMs);s.sort((y,x)=>x.usd-y.usd||x.activeMs-y.activeMs);let g={};for(let y of o.values())for(let[x,b]of Object.entries(y.provenance))g[x]=(g[x]||0)+b;return{since:r,capturedAt:n,totalUsd:Zt(u),activeMs:d,turns:[...o.values()].reduce((y,x)=>y+x.turns,0),bullets:m,workstreams:s,provenance:zc(g),gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c,uncategorized:{usd:Zt(l.usd),turns:l.turns,sharePct:u>0?Math.round(l.usd/u*100):0,byShape:zc(l.byShape),top:l.samples.sort((y,x)=>x.usd-y.usd).slice(0,UW)}}}}var UW=25,o$=160,s$=e=>{let t=String(e||"").replace(/\s+/g," ").trim();return t.length>o$?`${t.slice(0,o$).trimEnd()}\u2026`:t},HW=10;function a$(e,{thresholdPct:t=HW}={}){let n=e?.gaps?.uncategorized||{usd:0,turns:0},r=e?.totalUsd||0,o=n.usd||0,s=r>0?o/r*100:0,a=s<=t,i=a?[]:[`${s.toFixed(1)}% of the last 7d ($${o.toFixed(2)} of $${r.toFixed(2)}) is uncategorized (threshold ${t}%) \u2014 run \`npm run cost -- --uncategorized\` and add classifier table lines for the top asks`];return{ok:a,sharePct:Math.round(s*10)/10,thresholdPct:t,usd:Zt(o),totalUsd:Zt(r),turns:n.turns||0,inheritedPct:r>0?Math.round((e?.provenance?.inherited||0)/r*100):0,problems:i}}var WW=e=>{let t=null;for(let[n,r]of Object.entries(e))(!t||r.usd>t.v.usd||r.usd===t.v.usd&&r.activeMs>t.v.activeMs)&&(t={cat:n,v:r});return t?.cat??null},zc=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Zt(n)]));var cs={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function GW(e){let t=String(e||"7d");return t in cs?{key:t,ms:cs[t]}:{key:"7d",ms:cs["7d"]}}function zW(e,t){let n=new Set((t||[]).filter(o=>o.source==="orchestrator").map(o=>`${o.type}|${o.payload?.ts??"?"}`)),r=[...t||[]];for(let o of e?.events||[]){let s=Eu(o);!s||n.has(`${s.type}|${s.payload?.ts??"?"}`)||r.push({trackId:e.id,boxId:s.boxId??null,ts:o.at,type:s.type,actor:s.actor,provider:s.provider??null,source:s.source,payload:s.payload})}return r}async function VW(e){if(!e?.cwd)return null;try{let n=(await qW.readFile(KW.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 my(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}:GW(t),d=[];for(let w of e||[]){let m=await q(w),g=zW(w,m);i&&c<o&&(g=g.filter(y=>(y.ts??0)<=c)),d.push({track:w,events:g,brief:await VW(w)})}let p=fy(d,{windowMs:u,now:c}),f=l==="7d"&&c===o?p:fy(d,{windowMs:cs["7d"],now:o});return{window:l,...p,categorization:a$(f)}}var Vc=e=>`$${Number(e||0).toFixed(2)}`,i$=e=>{let t=Math.round((e||0)/6e4);return t>=60?`${Math.floor(t/60)}h${String(t%60).padStart(2,"0")}`:`${t}m`},is=(e,t)=>String(e).padEnd(t);function c$(e){let t=[];t.push(`USAGE ROUNDUP \xB7 ${e.window} \xB7 ${Vc(e.totalUsd)} \xB7 ${i$(e.activeMs)} active \xB7 ${e.turns} turn(s) \xB7 as of ${new Date(e.capturedAt).toISOString()}`);let n=e.provenance||{};e.totalUsd>0&&Object.keys(n).length&&t.push("labeled by: "+Object.entries(n).sort((a,i)=>i[1]-a[1]).map(([a,i])=>`${a} ${Math.round(i/e.totalUsd*100)}%`).join(" \xB7 ")),t.push(""),t.push("WHERE IT WENT");for(let a of e.bullets||[])t.push(` ${is(`${a.shareBasis==="time"?"~":""}${a.sharePct}%`,5)} ${is(a.category,15)} ${is(Vc(a.usd),10)} ${is(i$(a.activeMs),6)} ${a.turns} turn(s)`+(a.topWorkstreams?.length?` \xB7 ${a.topWorkstreams.map(i=>i.name).join(", ")}`:""));let r=e.gaps||{};r.tracksWithoutEvents&&t.push(`${r.tracksWithoutEvents} track(s) have no attributed events yet`),r.cursorCostUnknown&&t.push("cursor time counted, cost unavailable"),r.unpricedTurns&&t.push(`WARNING: ${r.unpricedTurns} turn(s) unpriced \u2014 total under-reports`);let o=e.categorization;if(o){t.push(""),t.push((o.ok?"categorization ok: ":"CATEGORIZATION ALARM: ")+`${o.sharePct}% of the last 7d uncategorized (threshold ${o.thresholdPct}%) \xB7 ${o.inheritedPct}% inferred from the previous ask`);for(let a of o.problems||[])t.push(`WARNING: ${a}`)}let s=r.uncategorized;if(s){t.push(""),t.push(`UNCATEGORIZED RESIDUE \xB7 ${Vc(s.usd)} (${s.sharePct}%) \xB7 ${s.turns} turn(s) \xB7 by shape: `+(Object.entries(s.byShape||{}).filter(([,a])=>a>0).sort((a,i)=>i[1]-a[1]).map(([a,i])=>`${a} ${Vc(i)}`).join(" \xB7 ")||"none")),s.top?.length||t.push(" (nothing unmatched carried cost in this window)");for(let a of s.top||[])t.push(` ${is(Vc(a.usd),8)} ${is(a.shape,10)} ${is(String(a.track||"").slice(0,26),26)} | ${a.text}`);s.top?.length&&(t.push(""),t.push("novel-ask rows are vocabulary the classifier lacks: add a rule in agent/src/task-classifier.js (and a line in test/uncategorized-corpus.test.mjs). follow-up rows had no prior ask on their box."))}return t.join(`
738
- `)}Qn();var mo=36e5,p$=24*mo,JW=400,YW=12,ls=e=>Math.round(e*1e4)/1e4;function hy({window:e,from:t,to:n,now:r=Date.now()}={}){let o=Number(t),s=Number(n);if(Number.isFinite(o)&&o>0){let c=Number.isFinite(s)&&s>o?Math.min(s,r):r;return{key:"custom",since:o,until:c}}let a=String(e||"7d")in cs?String(e||"7d"):"7d",i=cs[a];return{key:a,since:i==null?null:r-i,until:r}}var XW=(e,t)=>e!=null&&t-e<=48*mo?mo:p$;function l$(e,t){if(t===mo)return Math.floor(e/mo)*mo;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function ZW(e,t){if(t===mo)return e+mo;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var u$=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),d$=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},QW=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,ls(n)]));async function f$(e,t={}){let n=t.now??Date.now(),r=hy({...t,now:n}),o=r.since==null?p$:XW(r.since,r.until),s=_=>(r.since==null||_>=r.since)&&_<r.until,a=r.since!=null?r.until-r.since:null,i=_=>a!=null&&_>=r.since-a&&_<r.since,c={},l={},u=u$(),d=0,p=0,f=0,w=0,m=0,g=0,y=new Set,x=new Map,b=[],O=[],I=[],C=null;for(let _ of e||[]){let L=(await q(_)).filter(E=>E.type==="cost.recorded");if(!L.length){_.archivedAt||I.push(_.name||_.id);continue}let V=[];for(let E of L){let P=E.ts??0;s(P)?V.push(E):i(P)&&(g+=Kt(E).usd)}if(!V.length)continue;let S=jr(V,{boxLabels:Gc(_)});d+=S.totalUsd,p+=S.turns,f+=S.repricedTurns||0,w+=S.asRecordedUsd||0,m+=S.unpricedTurns||0;for(let E of S.unpricedModels||[])y.add(E);d$(u,S.totalTokens);for(let[E,P]of Object.entries(S.byModel))c[E]||={usd:0,events:0,tokens:u$()},c[E].usd=ls(c[E].usd+P.usd),c[E].events+=P.events,d$(c[E].tokens,P.tokens);for(let[E,P]of Object.entries(S.byProvider))l[E]||={usd:0,events:0},l[E].usd=ls(l[E].usd+P.usd),l[E].events+=P.events;for(let E of V){let{usd:P}=Kt(E);if(!P)continue;let W=l$(E.ts??0,o),G=x.get(W)??{t:W,total:0,byProvider:{}};G.total+=P;let ae=E.provider||"unknown";G.byProvider[ae]=(G.byProvider[ae]||0)+P,x.set(W,G),(C==null||W<C)&&(C=W)}b.push({id:_.id,name:_.name||_.id,archived:!!_.archivedAt,usd:S.totalUsd,turns:S.turns,providers:Object.keys(S.byProvider)});for(let[E,P]of Object.entries(S.byBox))O.push({trackId:_.id,trackName:_.name||_.id,boxId:E,...P})}let U=r.since!=null?l$(r.since,o):C,H=[];for(let _=U,$=0;_!=null&&_<r.until&&$<JW;_=ZW(_,o),$++){let L=x.get(_);H.push(L?{t:_,total:ls(L.total),byProvider:QW(L.byProvider)}:{t:_,total:0,byProvider:{}})}return b.sort((_,$)=>$.usd-_.usd),O.sort((_,$)=>$.usd-_.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:H,fleet:{totalUsd:ls(d),asRecordedUsd:ls(w),turns:p,repricedTurns:f,unpricedTurns:m,unpricedModels:[...y],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:b.length,tracksSilentLive:I},prior:a!=null?{totalUsd:ls(g),since:r.since-a,until:r.since}:null,tracks:b.slice(0,50),boxes:O.slice(0,YW)}}Xu();var eq=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),tq=20,nq=40;async function m$(e,t={}){let n=t.now??Date.now(),r=hy({...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 q(l),d=0,p=Gc(l);for(let f of u){if(!eq.has(f.type))continue;let w=f.type==="code.rework"?f.payload?.ts??f.ts:f.ts;f.type!=="rework.cause.answered"&&!o(w??0)||(f.type==="code.committed"&&d++,s.push(f.trackId?f:{...f,trackId:l.id}))}d&&i++;for(let f of l.boxes||[])a[`${l.id}/${f.name}`]={trackName:l.name||l.id,label:p[f.name]||f.name}}let c=fT(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:Qr,decayEndDays:uh,basis:c.basis,commits:c.commits,tracksWithCommits:i,fixesAnalyzed:c.fixes.length,fixUsdTotal:c.fixUsdTotal,buckets:c.buckets,verdicts:c.verdicts,intents:c.intents,noCodeDelta:c.noCodeDelta,pendingTaps:c.pendingTaps.length,byProvider:c.byProvider,byModel:c.byModel,epochs:c.epochs.slice(0,tq),fixes:c.fixes.slice(0,nq)}}import rq from"node:fs";import h$ from"node:fs/promises";import Jc from"node:os";import oq from"node:path";nw();ct();var sq=1024*1024,ip=e=>Math.round(e/sq);async function aq(e){try{let t=await h$.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:ip(r),diskTotalMb:ip(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function iq(){try{return(await nn()).filter(t=>t.isBostrat).length}catch{return null}}async function cq(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await h$.readdir(oq.join(Nc,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function w$({stateDir:e=Nc,now:t=Date.now}={}){let n=Jc.totalmem(),[r,o,s,a]=await Promise.all([fd().catch(()=>null),aq(rq.existsSync(e)?e:Jc.tmpdir()),iq(),cq()]),i=Jc.cpus()?.length||null,c=Jc.loadavg()?.[0]??null;return{ts:t(),loadavg1:c!=null?Math.round(c*100)/100:null,cpus:i,cpuPct:c!=null&&i?Math.min(100,Math.round(c/i*100)):null,memUsedMb:r!=null?ip(n-r):null,memTotalMb:ip(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(Jc.uptime())}}jh();pe();Wf();Xa();Qn();pe();Qn();var lq=864e5;function uq(e,{tolerance:t=.005}={}){if(e.type!=="cost.recorded"||e.source==="vendor")return null;let n=e.payload?.tokens,r=Number(e.payload?.usd)||0;if(!(n?(n.input||0)+(n.output||0)+(n.cacheRead||0)+(n.cacheWrite??n.cacheCreation??0):0)||!r)return null;let s=e.payload?.model||"unknown",a=e.payload?.speed||void 0,i={input:n.input||0,output:n.output||0,cacheRead:n.cacheRead||0,cacheWrite:n.cacheWrite??n.cacheCreation??0},c=In(s,i,e.ts,a?{speed:a}:void 0);if(!c)return null;let l=r-c,u=Math.abs(l)>Math.max(c*t,.001);return{model:s,speed:a??null,ts:e.ts,asRecorded:r,expected:c,delta:l,divergent:u}}async function g$(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*lq,s={},a=0,i=0,c=[];for(let u of e||[]){let d=await q(u);for(let p of d){if(!p.ts||p.ts<o)continue;let f=uq(p,{tolerance:n});if(!f)continue;a++;let w=f.speed?`${f.model} (${f.speed})`:f.model,m=s[w]||={rows:0,divergent:0,asRecordedUsd:0,expectedUsd:0};m.rows++,m.asRecordedUsd+=f.asRecorded,m.expectedUsd+=f.expected,f.divergent&&(i++,m.divergent++,c.length<10&&c.push({track:u.name||u.id,...f}))}}let l=u=>Math.round(u*1e4)/1e4;for(let u of Object.values(s))u.asRecordedUsd=l(u.asRecordedUsd),u.expectedUsd=l(u.expectedUsd);return{sinceMs:o,days:t,tolerance:n,rows:a,divergent:i,byModel:s,examples:c,ok:i===0}}Ph();Ew();vu();pt();Gt();import Ra from"node:fs/promises";import dq from"node:fs";import ht from"node:path";import pq from"node:os";import{execFile as fq}from"node:child_process";import{promisify as mq}from"node:util";var hq=mq(fq),y$=process.env.BOSTRAT_STATE_DIR||ht.join(process.env.HOME||pq.tmpdir(),".bostrat"),cp=!1,wy=null;async function gy(e,t){let n=await Ra.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await Ra.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await Ra.mkdir(ht.dirname(t),{recursive:!0}),await Ra.copyFile(e,t),!0)}var wq=new Set([".claude",".codex",".cursor",".credentials.json","auth.json",".claude.json","api-token","node.env","certs","integrations.json","gcloud","application_default_credentials.json",".gemini"]);async function lp(e,t,{skip:n=null}={}){let r=0,o=await Ra.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(wq.has(s.name)||n?.has(s.name))continue;let a=ht.join(e,s.name);s.isDirectory()?r+=await lp(a,ht.join(t,s.name)):s.isFile()&&(r+=await gy(a,ht.join(t,s.name))?1:0)}return r}async function b$({stateDir:e=y$,dest:t=process.env.BOSTRAT_SYNC_DIR||`${y$}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await Ra.mkdir(t,{recursive:!0});let o=0;o+=await gy(ht.join(e,"tracks.json"),ht.join(t,"tracks.json"))?1:0,o+=await gy(ht.join(e,"events.jsonl"),ht.join(t,"events.jsonl"))?1:0,o+=await lp(ht.join(e,"events"),ht.join(t,"events")),o+=await lp(ht.join(e,"memory"),ht.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await lp(ht.join(u.cwd,".bostrat"),ht.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>hq("git",["-C",t,...u]);dq.existsSync(ht.join(t,".git"))||(await a("init","-q"),await a("config","user.email","agent@bostrat.local"),await a("config","user.name","bostrat state sync")),n&&/^https:\/\/github\.com\//i.test(n)&&(await a("config","--get","credential.useHttpPath").then(()=>!0).catch(()=>!1)||await qp(t).catch(()=>{}));let i=!1,{stdout:c}=await a("status","--porcelain");c.trim()&&(await a("add","-A"),await a("commit","-q","-m",`state sync ${new Date().toISOString()}`),i=!0);let l=!1;if(n&&(i||cp))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,cp&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),cp=!1,wy=null}catch(u){cp=!0;let d=(u?.stderr||u?.message||String(u)).trim().split(`
739
- `).slice(-3).join(" | ").slice(0,300);d!==wy&&(wy=d,console.warn(`[state-sync] PUSH FAILING (retrying each cycle; off-box copy is STALE): ${d}`))}return{staged:o,committed:i,pushed:l}}catch(o){return{staged:0,committed:!1,pushed:!1,error:o?.message||String(o)}}}xw();an();Io();ct();qa();import{execFile as gq}from"node:child_process";import{promisify as yq}from"node:util";import{randomUUID as bq}from"node:crypto";import kq from"node:fs";import xq from"node:os";import vq from"node:path";var wo=yq(gq),up=e=>new Promise(t=>setTimeout(t,e)),go=pf,yy=process.env.BOSTRAT_USAGE_PROBE_CWD||vq.join(xq.homedir(),".bostrat","usage-probe"),Sq=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,Tq=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,Aq=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,k$=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,ho=null,Yc=null,Xc=null;async function Eq(){try{return await wo(X,Q("has-session","-t",go)),!0}catch{return!1}}function _q(){ho&&clearTimeout(ho),ho=setTimeout(()=>Iq().catch(()=>{}),Sq),ho.unref&&ho.unref()}async function Iq(){ho&&(clearTimeout(ho),ho=null);try{await wo(X,Q("kill-session","-t",go))}catch{}}async function $q(){let e=Date.now()+Aq;for(;;){let t=await by().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await up(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await up(500)}}async function Rq(){if(await Eq())return;if(!await Rr())throw new Error("host tmux server not running \u2014 start globo-tmux.service");kq.mkdirSync(yy,{recursive:!0}),await vr(yy);let e=bq();await wo(X,Q("new-session","-d","-s",go,"-c",yy,"-x","200","-y","60",...ai()));let t=`${df} --session-id ${e}`;await wo(X,Q("send-keys","-t",go,t,"Enter")),await $q()}async function by(){let{stdout:e}=await wo(X,Q("capture-pane","-t",go,"-p"));return e}async function Oq(){await Rq(),await wo(X,Q("send-keys","-t",go,"-l","/usage")),await wo(X,Q("send-keys","-t",go,"Enter"));let e=Date.now()+Tq,t="";for(;await up(400),t=await by(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await up(900),t=await by(),await wo(X,Q("send-keys","-t",go,"Escape")).catch(()=>{}),_q(),t}function Mq(e){let t=String(e||"").split(`
740
- `).map(s=>s.replace(/\s+$/,"").trim()),n=s=>{let a=null,i=null;for(let c=s+1;c<Math.min(s+5,t.length)&&!/^Current\s/i.test(t[c]);c++){let l=t[c].match(/(\d+)%\s*used/i);l&&a===null&&(a=Number(l[1]));let u=t[c].match(/^Resets\s+(.+)$/i);u&&i===null&&(i=u[1].trim())}return a===null?null:{pct:a,resets:i||null}},r=s=>{let a=t.findIndex(i=>s.test(i));return a<0?null:n(a)},o=[];return t.forEach((s,a)=>{let i=s.match(/^Current week \(([^)]+)\)$/i);if(!i||/all models/i.test(i[1]))return;let c=n(a);c&&o.push({model:i[1].trim(),...c})}),{session:r(/^Current session\b/i),week:r(/^Current week \(all models\)/i)||r(/^Current week$/i),weekModels:o.length?o:null}}function Cq(e){let t=String(e||"").split(`
741
- `).map(s=>s.replace(/\s+$/,"")),n=t.findIndex(s=>/What's contributing/i.test(s));if(n<0)return null;let r=/(Usage credits|Esc to cancel|d to day · w to week|^\s*d to day)/i,o=[];for(let s=n+1;s<t.length&&!r.test(t[s]);s++)t[s].trim()&&o.push(t[s].trim());return o.length?o:null}async function x$({fresh:e=!1}={}){return!e&&Yc&&Date.now()-Yc.at<k$?Yc.data:Xc||(Xc=(async()=>{try{let t=await Oq(),n=Mq(t),r={...n,contributors:Cq(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()-(k$-3e3),data:n},n}finally{Xc=null}})(),Xc)}var Nq=262144;function Pq(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 Dq=new Set([300]),Bq=new Set([10080]);function jq(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:Dq.has(t)?"session":Bq.has(t)?"week":"other"}function Lq(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 Fq(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?Pq((o-n)/1e3):null,resetsAt:o}}var Zc=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function Uq(e,t=Date.now()){let n=String(e||"").split(`
742
- `),r=!1;for(let o=n.length-1;o>=0;o--){let s=n[o].trim();if(!s||s[0]!=="{"||!s.includes("token_count"))continue;let a;try{a=JSON.parse(s)}catch{continue}let i=a?.payload;if(i?.type!=="token_count")continue;r=!0;let c=i.rate_limits;if(!c)return Zc(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=Zc(r);[c.primary,c.secondary].forEach((f,w)=>{let m=Fq(f,l,t);if(!m)return;let g=jq(f.window_minutes);g===null&&(g=w===0?"session":"week"),g==="session"&&!u.session?u.session=m:g==="week"&&!u.week?u.week=m:(u.other??=[]).push({label:Lq(f.window_minutes),...m})}),u.planType=typeof c.plan_type=="string"?c.plan_type:null;let p=c.credits;return p&&(p.has_credits||p.unlimited)&&(u.credits={balance:String(p.balance??""),unlimited:!!p.unlimited}),u.limitReached=typeof c.rate_limit_reached_type=="string"&&c.rate_limit_reached_type||(c.spend_control_reached?"spend_control":null),u}if(c.primary_used_percent!=null||c.secondary_used_percent!=null){let l=u=>Number.isFinite(Number(u))?{pct:Math.round(Number(u)),resets:null,resetsAt:null}:null;return{...Zc(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return Zc(r)}return Zc(r)}async function ky(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await Eo(e?.cwd,e?.sessionId);if(!n)return{...t,session:null,week:null,subscription:!1,error:"no codex rollout found for this box yet",capturedAt:Date.now()};let r=await _t(n.file,Nq),o=Uq(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 v$(e,{fresh:t=!1}={}){let n=new Set;for(let o of e||[])for(let s of o.boxes||[])s.agent&&n.add(s.agent);let r=[];if((n.has("claude")||n.size===0)&&r.push(await dp({agent:"claude"},{fresh:t})),n.has("codex")){let o=[],s=[...e||[]].sort((i,c)=>(i.archivedAt?1:0)-(c.archivedAt?1:0)||(c.createdAt||0)-(i.createdAt||0));for(let i of s)for(let c of i.boxes||[])c.agent==="codex"&&o.push({...c,cwd:c.cwd||i.cwd});let a=null;for(let i of o.slice(0,8)){let c=await ky(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await ky(null))}return n.has("cursor")&&r.push(await dp({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function dp(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?ky(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await x$({fresh:t})}}Tr();pt();pt();function Hq(e=process.env){return!!(Oe(e)&&e.BOSTRAT_PLANE_TOKEN)}var Wq=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),pp=(e,t)=>Object.assign(new Error(e),{status:t});async function S$(e,t){if(!Hq(t))throw pp("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${Oe(t)}${e}`,{headers:Wq(t)})}catch(o){throw pp(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw pp(r?.error||`plane replied ${n.status}`,n.status);return r}async function T$(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await S$(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function A$(e,{env:t=process.env}={}){if(!e)throw pp("message id required",400);return(await S$(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}Bi();ju();function xy(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 qq(e){let[t,n]=e.split("/"),r=xy(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 E$(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(qq).filter(Boolean)}function Kq(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function _$(e){let t=E$(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:Kq,allowed(r){if(n)return!0;let o=xy((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function I$(e,t){let n=E$(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=xy(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import $$ from"node:crypto";import fp from"node:fs";import Gq from"node:path";function R$(e=process.env,{stateDir:t=Nc,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=Gq.join(t,"api-token");try{let a=fp.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=$$.randomBytes(32).toString("base64url");try{fp.mkdirSync(t,{recursive:!0}),fp.writeFileSync(o,s+`
743
- `,{mode:384}),fp.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function Qc(e){let t=e?.socket?.remoteAddress||"";if(!t)return!1;let n=t.replace(/^::ffff:/,"");return n==="::1"||n==="127.0.0.1"||/^127\./.test(n)}function O$(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:$$.timingSafeEqual(n,r)}function M$(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 zq=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/,/^\/api\/tracks\/adopt\b/,/^\/api\/tracks\/[^/]+\/transfer-out\b/,/^\/api\/node\/self-update\b/,/^\/api\/changelog\/(publish|retract)\b/,/^\/api\/tracks\/[^/]+\/loop-(update|delete)-offer\b/],Vq=e=>zq.some(t=>t.test(e));function C$({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=M$(o);return O$(c,e)?a():Vq(i)?(n.log?.(`[perimeter] refused ${o.method} ${i} \u2014 sensitive route requires the node API token`),s.status(401).json({error:"this route requires the node API token"})):!t||Qc(o)?a():(n.log?.(`[perimeter] refused ${o.method} ${i} from ${o.socket?.remoteAddress||"?"} \u2014 no node API token`),s.status(401).json({error:"unauthorized"}))}}function N$(e,t,{enforce:n=!0}={}){return!n||O$(M$(e),t)?!0:Qc(e)}Tn();dd();dd();import Jq from"node:http";import Yq from"node:net";function mp(e){if(!e)return null;let t=String(e).replace(/:\d+$/,"").toLowerCase();if(/^[\d.]+$/.test(t)||t.includes(":"))return null;let n=t.split(".");if(n.length<3)return null;let r=n[0];return/^[a-z0-9-]+$/.test(r)?r:null}function hp(e){let t=mp(e.headers.host);return t?{slug:t,view:Xh(t)}:null}var Xq=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),Zq=e=>{let t=Xq(e.name);return`<!doctype html><meta charset="utf-8">
736
+ _${o} archived_`:"")}async function XW(e,t){let n=await xs();if(!n)return Fe("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 Fe("Usage: `/bostrat start <name> [repo]`");let i=await r.listRepos(),c=a[a.length-1]?.toLowerCase(),l=a.length>1?i.find(d=>d.name.toLowerCase()===c):null,u=(l?a.slice(0,-1):a).join(" ");return l?(bo(N$(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),Fe(`Starting *${Te(u)}* on ${Te(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:JW(u,i)}}case"archive":{if(!a.length)return Fe("Usage: `/bostrat archive <track>`");let{match:i,live:c}=Fy(await r.listTracks(),a.join(" "));return i?(bo(GW(e,n,{track:i,responseUrl:t.response_url})),Fe(`Archiving *${Te(i.name)}*\u2026`)):Uy(c,a.join(" "))}case"handoff":{let i=r.knownAgents??KW,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return Fe(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:d}=Fy(await r.listTracks(),l);return u?(bo(zW(e,n,{track:u,agent:c,responseUrl:t.response_url})),Fe(`Handing *${Te(u.name)}* to ${Te(c)}\u2026`)):Uy(d,l)}case"stop":{if(!a.length)return Fe("Usage: `/bostrat stop <track>`");let{match:i,live:c}=Fy(await r.listTracks(),a.join(" "));return i?(bo(VW(e,n,{track:i,responseUrl:t.response_url})),Fe(`Stopping *${Te(i.name)}*\u2026`)):Uy(c,a.join(" "))}case"list":return Fe(await YW(r));default:return Fe(qW)}}async function ZW(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await Ky(o);try{if(await e.deps.answerPrompt(o,{promptId:s,answers:[a]}),i?.prompt?.promptId===s){let{ts:c,question:l}=i.prompt;delete i.prompt,await kn(),await As(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Te(l||"question")}~
737
+ \u2713 *${Te(a)}*`}}]}).catch(()=>{})}}catch(c){await Tt(n.response_url,Fe(`Couldn't answer: ${c?.message||c}`))}}async function QW(e,t,n,r){let{trackId:o,offerId:s,action:a}=r,i=e.deps;try{let c=await i.resolveTrack(o);if(!c)throw new Error("track not found");let l=await i.readEvents(c),u=l.find(p=>p.type==="pr.offered"&&p.payload?.offerId===s);if(!u)throw new Error("unknown offer");if(l.some(p=>p.type==="pr.offer.answered"&&p.payload?.offerId===s))throw new Error("offer already answered");let d=Array.isArray(r.actions)?eo.filter(p=>r.actions.includes(p)):a==="pr"?["commit","push","pr"]:a==="push"?["commit","push"]:null;if(d?.includes("pr")&&i.divertShip&&await i.divertShip(c,u,{actions:d}))return;d&&await i.sayToLead(c.id,ua(d,{branch:u.payload.branch,base:u.payload.base}),{kind:d.includes("pr")?"pr-go":"push-go"}),await i.appendEvent({id:c.id,cwd:c.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:u.boxId,payload:{ts:Date.now(),offerId:s,action:d?a:"dismiss",actions:d}})}catch(c){await Tt(n.response_url,Fe(`Couldn't act on the offer: ${c?.message||c}`))}}async function eq(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 Tt(n.response_url,Fe(`Couldn't act on the offer: ${i?.message||i}`))}}async function tq(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await xs();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 Tt(t.response_url,{...Fe(`Starting *${Te(s)}*\u2026`),replace_original:!0}),bo(N$(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"?bo(ZW(e,r,t,o)):n.action_id==="bostrat-ship"?bo(QW(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&bo(eq(e,r,t,o))}async function nq(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 HW(t.channel,t.thread_ts);if(!n)return;let r=await xs();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await ko(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function rq(e){return async t=>{if(t.type==="slash_commands")return XW(e,t.payload);if(t.type==="interactive"){await tq(e,t.payload);return}if(t.type==="events_api"){await nq(e,t.payload?.event);return}}}var oq=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 sq(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${Te(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:il(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 aq(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await As(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Te(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await ko(e,t,r.question||"The lead needs an answer",sq(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await kn()}async function iq(e,t,n){let r=n.payload||{};if(!t.prompt||r.promptId&&t.prompt.promptId!==r.promptId)return;let{ts:o,question:s}=t.prompt;delete t.prompt,await kn(),await As(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Te(s||"question")}~
738
+ \u2713 _answered_`}}]})}async function cq(e,t,n){let r=n.payload||{};if(!r.offerId||t.offers?.[r.offerId])return;let o=(i,c,l,u)=>({type:"button",action_id:"bostrat-ship",text:{type:"plain_text",text:c},value:JSON.stringify({trackId:n.trackId,offerId:r.offerId,action:i,...u?{actions:u}:{}}),...l?{style:l}:{}}),s;if(!Array.isArray(r.available))s=r.toPr?[o("push",`Commit & push${r.toPr.number?` to #${r.toPr.number}`:""}`,"primary"),o("dismiss","Not now")]:[o("pr","Open PR","primary"),o("push","Just push"),o("dismiss","Not now")];else{let i=r.available,c=Array.isArray(r.defaults)&&r.defaults.length?r.defaults:i,l={commit:"Commit",rebase:"rebase",push:"push",pr:r.prState==="open"?"open new PR":"open PR"},u=c.map(d=>l[d]).filter(Boolean).join(" & ");s=[o(c.includes("pr")?"pr":"push",u||"Ship","primary",c)],i.includes("pr")&&!c.includes("pr")&&s.push(o("pr","Open new PR",void 0,["pr"])),s.push(o("dismiss","Not now"))}let a=await ko(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${Te(il(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await kn()}async function lq(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await kn();let s=r.action==="dismiss"?"dismissed":r.action==="pr-exists"?`PR${r.existingPr?.number?` #${r.existingPr.number}`:""} already open \u2014 pick how to ship`:r.action==="pr"?"\u2713 opening a PR":"\u2713 pushing";await As(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function uq(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 ko(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${Te(r.branch)})`:""} is already open. Push the update to it, or open a new PR?`}},{type:"actions",elements:[s("push",`Push to ${o}`,"primary"),s("new","Open a new PR"),s("dismiss","Not now")]}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await kn()}async function dq(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await kn();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await As(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function pq(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??fq)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await I$(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${Te(o.name)}*${a}${o.group?` (group \`${Te(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${Te(a.name)}*`).join(", ");await ko(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${Te(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function fq(e,t){let n=await mr(e);if(!n)return null;let r=hn(n,t);if(!r)return null;let o=await al.readFile(en(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function hq(e,t){if(!oq.has(t.type))return;let n=await Ky(t.trackId);if(!n)return;let r=await xs();if(!r)return;let o=t.payload||{};switch(t.type){case"turn.user":if(n.kickoff||t.actor!=="user"||!o.text)return;n.kickoff=o.text,await kn(),await Wy(r,n);return;case"turn.agent":{if(!o.text)return;let s=WW(o.text);if(!s)return;await ko(r,n,s,[{type:"section",text:{type:"mrkdwn",text:Te(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${Mp(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return aq(r,n,t);case"prompt.answered":return iq(r,n,t);case"pr.offered":return cq(r,n,t);case"pr.offer.answered":return lq(r,n,t);case"pr.exists.offered":return uq(r,n,t);case"pr.exists.answered":return dq(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 ko(r,n,`${s}${o.url?`: ${o.url}`:o.number?` (#${o.number})`:""}`);return}case"handoff.done":if(!o.toAgent||o.toAgent===n.lead)return;n.lead=o.toAgent,await kn(),await Wy(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await ko(r,n,`Live preview ${o.name}: ${Cp(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${Te(o.name)}*: ${Cp(o.slug)}
739
+ _runs on the Track's branch; reachable on the operator's private network only_`}}]);return}case"mock.state.changed":return pq(r,n,t,e.deps)}}function P$(e){let t={deps:e};Je.on("event",s=>{hq(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await xs()||(r&&clearInterval(r),r=null,n=$$({getToken:async()=>(await xs())?.appToken,onEnvelope:rq(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}ln();he();Tn();Qm();nr();import mq from"node:fs/promises";function wq(e){let t=new Map;for(let n of String(e||"").split(`
740
+ `)){let r=n.trim();if(!r||r[0]!=="{")continue;let o;try{o=JSON.parse(r)}catch{continue}let s=o?.message?.usage;if(!s)continue;let a={input:s.input_tokens||0,output:s.output_tokens||0,cacheWrite:s.cache_creation_input_tokens||0,cacheRead:s.cache_read_input_tokens||0};if(a.input+a.output+a.cacheWrite+a.cacheRead===0)continue;let i=o.message?.id||o.uuid||null;if(!i)continue;let c=s.cache_creation,l=c&&typeof c=="object"?{m5:c.ephemeral_5m_input_tokens||0,h1:c.ephemeral_1h_input_tokens||0}:null,u=typeof s.speed=="string"&&s.speed!=="standard"?s.speed:null;t.set(i,{messageId:i,tokens:a,cacheWriteTtl:l,speed:u,model:o.message?.model||o.model||null})}return[...t.values()]}function gq(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 yq=new Set(["Write","Edit","NotebookEdit"]),bq=220,kq=160;function xq(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(yq.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,bq)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=No(o.command.trim().replace(/\s+/g," ")).slice(0,kq));return r}function vq(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?cn(t.cwd,t.sessionId):t?.cwd?Zf(t.cwd):null}async function D$(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 C(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=Sd(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:xq(e,o)});break;case"Stop":await Sq(r,o,e,i);break;default:break}return a}async function Sq(e,t,n,r){let o=[],s=vq(n,t);if(s)try{o=wq(await mq.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=gq(await K(e)),c=o.filter(u=>!i.has(u.messageId));if(c.length){let u=new Map;for(let d of c){let p=`${d.model||"unknown"}\0${d.speed||""}`,f=u.get(p)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},cacheWriteTtl:null,messageIds:[]};for(let w of Object.keys(f.tokens))f.tokens[w]+=d.tokens[w];d.cacheWriteTtl&&(f.cacheWriteTtl??={m5:0,h1:0},f.cacheWriteTtl.m5+=d.cacheWriteTtl.m5,f.cacheWriteTtl.h1+=d.cacheWriteTtl.h1),f.messageIds.push(d.messageId),f.speed=d.speed||null,u.set(p,f)}for(let[d,p]of u){let f=d.split("\0")[0];await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:f,usd:Rn(f,p.tokens,void 0,p.speed?{speed:p.speed}:void 0),tokens:p.tokens,...p.speed?{speed:p.speed}:{},cacheWriteTtl:p.cacheWriteTtl,messageId:p.messageIds[p.messageIds.length-1],messageIds:p.messageIds,apiCalls:p.messageIds.length}})}}let l=a.tokens.input+a.tokens.cacheWrite+a.tokens.cacheRead;await r({type:"context.usage",actor:"system",source:"transcript",payload:{model:a.model,occupancy:l,tokens:a.tokens}})}Rs();Wf();xd();he();he();Gr();he();Gr();nr();function cl(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 B$=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),j$=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},Bp=e=>Math.round(e*1e4)/1e4;async function Gy(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=B$(),d=0,p=[];for(let f of e||[]){let w=await K(f),h=Kr(w,{boxLabels:cl(f)});if(h.turns===0){f.archivedAt?d++:p.push(f.name||f.id);continue}o+=h.totalUsd,s+=h.turns,a+=h.repricedTurns||0,i+=h.asRecordedUsd||0,c+=h.unpricedTurns||0;for(let g of h.unpricedModels||[])l.add(g);j$(u,h.totalTokens);for(let[g,y]of Object.entries(h.byModel))n[g]||={usd:0,events:0,tokens:B$()},n[g].usd=Bp(n[g].usd+y.usd),n[g].events+=y.events,j$(n[g].tokens,y.tokens);for(let[g,y]of Object.entries(h.byProvider))r[g]||={usd:0,events:0},r[g].usd=Bp(r[g].usd+y.usd),r[g].events+=y.events;t.push({id:f.id,name:f.name,usd:h.totalUsd,rollup:h})}return t.sort((f,w)=>w.usd-f.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:ea(),fleet:{totalUsd:Bp(o),asRecordedUsd:Bp(i),turns:s,repricedTurns:a,unpricedTurns:c,unpricedModels:[...l],totalTokens:u,byModel:n,byProvider:r,tracksWithCost:t.length,tracksSilent:d+p.length,tracksSilentArchived:d,tracksSilentLive:p},tracks:t}}var xo=e=>`$${e.toFixed(4)}`,Ka=(e,t)=>String(e).padEnd(t);function L$(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 ${xo(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 ${xo(t.asRecordedUsd)} \xB7 current-rates total ${xo(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${xo(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(` ${Ka(a,26)} ${Ka(xo(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(` ${Ka(a.name||a.id,30)} ${xo(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${Ka(c.label,40)} ${Ka(xo(c.usd),10)} ${c.models.join(",")||"?"}`),c.epochs)for(let[l,u]of Object.entries(c.epochs).sort((d,p)=>Number(d[0])-Number(p[0])))r.push(` \u21B3 tenure ${l} (${u.provider||"?"})${" ".repeat(Math.max(1,24-String(u.provider||"?").length))}${Ka(xo(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
741
+ `)}he();Sm();import Rq from"node:fs/promises";import Oq from"node:path";bu();Au();Gr();var jp=e=>e.payload?.ts??e.ts,Aq=12e4,tn=e=>Math.round(e*1e4)/1e4,Tq=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{},byTrack:new Map});function Eq(e,{since:t}){let{track:n,events:r,brief:o}=e,s=b=>jp(b)>=t,a=tr([Wi(n?.name),Wi(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let b of r)if(b.type==="subtask.delegated"&&b.boxId&&b.payload?.task){let I=tr(b.payload.task);I&&i.set(b.boxId,I)}let c=new Map,l=b=>{let I=b||"unattributed";return c.has(I)||c.set(I,{segments:[u(null)],lastTs:null,provider:null}),c.get(I)},u=(b,{shape:I="initial",continuation:_=!1,text:N=null,ts:U=null}={})=>({textCat:b,shape:I,continuation:_,text:N,ts:U,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),d=[...r].sort((b,I)=>jp(b)-jp(I)),p=0,f=0,w=0,h={turns:0};for(let b of d){let I=l(b.boxId),_=I.segments[I.segments.length-1],N=jp(b);switch(I.lastTs!=null&&N>I.lastTs&&s(b)&&(_.activeMs+=Math.min(N-I.lastTs,Aq)),I.lastTs=N,b.provider&&(I.provider=b.provider),b.type){case"turn.user":{let U=b.payload?.text;if(b.source==="hook"||!String(U||"").trim()||b.payload?.note||Gi(U))break;let j=tr(U),T=!!b.payload?.kind,R=T||ax(U),L=u(j,{shape:T?"injected":R?"follow-up":"novel-ask",continuation:!j&&R,text:U$(U),ts:N});I.segments.push(L),s(b)&&(L.turns+=1);break}case"peer.message":{let U=b.payload?.text;if(!String(U||"").trim())break;let j=tr(U),T=u(j,{shape:"peer",continuation:!j,text:U$(U),ts:N});I.segments.push(T),s(b)&&(T.turns+=1);break}case"tool.called":{if(b.source==="transcript")break;let U=b.payload?.tool;U&&(_.tools[U]=(_.tools[U]||0)+1),s(b)&&(_.toolCalls+=1);break}case"cost.recorded":{if(!s(b))break;let{usd:U,tokens:j,model:T,unpriced:R}=Jt(b);R&&(h.turns+=1),_.usd+=U,j&&(_.tokens.input+=j.input,_.tokens.output+=j.output,_.tokens.cacheRead+=j.cacheRead,_.tokens.cacheWrite+=j.cacheWrite),_.models[T]=(_.models[T]||0)+U,b.provider&&(_.provider=b.provider);break}case"handoff.done":s(b)&&(p+=1);break;case"subtask.merged":s(b)&&(f+=1);break;case"error":s(b)&&b.payload?.kind==="subtask-failed"&&(w+=1);break;default:break}}let g=new Map,y={usd:0,turns:0,byShape:{},samples:[]},x=!1;for(let[b,I]of c){let _=null;for(let N of I.segments){let U=null,j=null;if(N.textCat)U=N.textCat.category,j="text";else if(i.get(b))U=i.get(b).category,j="boxTask";else if(N.continuation&&_)U=_,j="inherited";else{let O=sx(N.tools);O?(U=O.category,j="toolMix"):a&&(U=a.category,j="hint")}if(U&&(_=U),!(N.usd>0||N.activeMs>0||N.turns>0||N.toolCalls>0))continue;let R=U??"uncategorized";g.has(R)||g.set(R,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{}});let L=g.get(R);L.usd+=N.usd,L.activeMs+=N.activeMs,L.turns+=N.turns,L.toolCalls+=N.toolCalls,j&&(L.provenance[j]=(L.provenance[j]||0)+N.usd);for(let[O,S]of Object.entries(N.models))L.models[O]=(L.models[O]||0)+S;let V=N.provider||I.provider;V&&(L.providers[V]=(L.providers[V]||0)+N.usd),V==="cursor"&&N.usd===0&&(x=!0),U||(y.usd+=N.usd,y.turns+=N.turns,y.byShape[N.shape]=(y.byShape[N.shape]||0)+N.usd,N.usd>0&&N.text&&y.samples.push({trackId:n?.id,track:n?.name||n?.id,shape:N.shape,usd:tn(N.usd),ts:N.ts,text:N.text}))}}return{perCategory:g,uncategorized:y,handoffs:p,merged:f,failed:w,sawCursorActivity:x,unpricedTurns:h.turns}}function zy(e,{windowMs:t=null,now:n=Date.now()}={}){let r=t==null?0:n-t,o=new Map,s=[],a=0,i=!1,c=0,l={usd:0,turns:0,byShape:{},samples:[]};for(let y of e||[]){let{track:x,events:b}=y;if(!b?.length){a+=1;continue}let{perCategory:I,uncategorized:_,handoffs:N,merged:U,failed:j,sawCursorActivity:T,unpricedTurns:R}=Eq(y,{since:r});T&&(i=!0),c+=R,l.usd+=_.usd,l.turns+=_.turns;for(let[V,O]of Object.entries(_.byShape))l.byShape[V]=(l.byShape[V]||0)+O;l.samples.push(..._.samples);let L={trackId:x?.id,name:x?.name||x?.id,archived:!!x?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:N,subtasksMerged:U,subtasksFailed:j};for(let[V,O]of I){L.usd+=O.usd,L.activeMs+=O.activeMs,L.turns+=O.turns,L.categories[V]={usd:tn(O.usd),activeMs:O.activeMs};for(let[H,W]of Object.entries(O.models))L.models[H]=tn((L.models[H]||0)+W);for(let[H,W]of Object.entries(O.providers))L.providers[H]=tn((L.providers[H]||0)+W);o.has(V)||o.set(V,Tq());let S=o.get(V);S.usd+=O.usd,S.activeMs+=O.activeMs,S.turns+=O.turns,S.toolCalls+=O.toolCalls;for(let[H,W]of Object.entries(O.models))S.models[H]=(S.models[H]||0)+W;for(let[H,W]of Object.entries(O.providers))S.providers[H]=(S.providers[H]||0)+W;for(let[H,W]of Object.entries(O.provenance))S.provenance[H]=(S.provenance[H]||0)+W;let M=S.byTrack.get(x?.id)||{usd:0,activeMs:0};M.usd+=O.usd,M.activeMs+=O.activeMs,S.byTrack.set(x?.id,M)}(L.usd>0||L.activeMs>0||L.turns>0)&&(L.usd=tn(L.usd),L.dominantCategory=$q(L.categories),s.push(L))}let u=[...o.values()].reduce((y,x)=>y+x.usd,0),d=[...o.values()].reduce((y,x)=>y+x.activeMs,0),p=u>0?"usd":"time",f=p==="usd"?u:d,w=new Map((e||[]).map(y=>[y.track?.id,y.track?.name||y.track?.id])),h=[...o.entries()].map(([y,x])=>({category:y,sharePct:f>0?Math.round((p==="usd"?x.usd:x.activeMs)/f*100):0,shareBasis:p,usd:tn(x.usd),activeMs:x.activeMs,turns:x.turns,toolCalls:x.toolCalls,models:ll(x.models),providers:ll(x.providers),provenance:ll(x.provenance),topWorkstreams:[...x.byTrack.entries()].sort((b,I)=>I[1].usd-b[1].usd||I[1].activeMs-b[1].activeMs).slice(0,2).map(([b,I])=>({trackId:b,name:w.get(b),usd:tn(I.usd),activeMs:I.activeMs}))})).sort((y,x)=>x.usd-y.usd||x.activeMs-y.activeMs);s.sort((y,x)=>x.usd-y.usd||x.activeMs-y.activeMs);let g={};for(let y of o.values())for(let[x,b]of Object.entries(y.provenance))g[x]=(g[x]||0)+b;return{since:r,capturedAt:n,totalUsd:tn(u),activeMs:d,turns:[...o.values()].reduce((y,x)=>y+x.turns,0),bullets:h,workstreams:s,provenance:ll(g),gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c,uncategorized:{usd:tn(l.usd),turns:l.turns,sharePct:u>0?Math.round(l.usd/u*100):0,byShape:ll(l.byShape),top:l.samples.sort((y,x)=>x.usd-y.usd).slice(0,_q)}}}}var _q=25,F$=160,U$=e=>{let t=String(e||"").replace(/\s+/g," ").trim();return t.length>F$?`${t.slice(0,F$).trimEnd()}\u2026`:t},Iq=10;function H$(e,{thresholdPct:t=Iq}={}){let n=e?.gaps?.uncategorized||{usd:0,turns:0},r=e?.totalUsd||0,o=n.usd||0,s=r>0?o/r*100:0,a=s<=t,i=a?[]:[`${s.toFixed(1)}% of the last 7d ($${o.toFixed(2)} of $${r.toFixed(2)}) is uncategorized (threshold ${t}%) \u2014 run \`npm run cost -- --uncategorized\` and add classifier table lines for the top asks`];return{ok:a,sharePct:Math.round(s*10)/10,thresholdPct:t,usd:tn(o),totalUsd:tn(r),turns:n.turns||0,inheritedPct:r>0?Math.round((e?.provenance?.inherited||0)/r*100):0,problems:i}}var $q=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},ll=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,tn(n)]));var Es={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function Mq(e){let t=String(e||"7d");return t in Es?{key:t,ms:Es[t]}:{key:"7d",ms:Es["7d"]}}function Cq(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=Vu(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 Nq(e){if(!e?.cwd)return null;try{let n=(await Rq.readFile(Oq.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 Vy(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}:Mq(t),d=[];for(let w of e||[]){let h=await K(w),g=Cq(w,h);i&&c<o&&(g=g.filter(y=>(y.ts??0)<=c)),d.push({track:w,events:g,brief:await Nq(w)})}let p=zy(d,{windowMs:u,now:c}),f=l==="7d"&&c===o?p:zy(d,{windowMs:Es["7d"],now:o});return{window:l,...p,categorization:H$(f)}}var ul=e=>`$${Number(e||0).toFixed(2)}`,W$=e=>{let t=Math.round((e||0)/6e4);return t>=60?`${Math.floor(t/60)}h${String(t%60).padStart(2,"0")}`:`${t}m`},Ts=(e,t)=>String(e).padEnd(t);function q$(e){let t=[];t.push(`USAGE ROUNDUP \xB7 ${e.window} \xB7 ${ul(e.totalUsd)} \xB7 ${W$(e.activeMs)} active \xB7 ${e.turns} turn(s) \xB7 as of ${new Date(e.capturedAt).toISOString()}`);let n=e.provenance||{};e.totalUsd>0&&Object.keys(n).length&&t.push("labeled by: "+Object.entries(n).sort((a,i)=>i[1]-a[1]).map(([a,i])=>`${a} ${Math.round(i/e.totalUsd*100)}%`).join(" \xB7 ")),t.push(""),t.push("WHERE IT WENT");for(let a of e.bullets||[])t.push(` ${Ts(`${a.shareBasis==="time"?"~":""}${a.sharePct}%`,5)} ${Ts(a.category,15)} ${Ts(ul(a.usd),10)} ${Ts(W$(a.activeMs),6)} ${a.turns} turn(s)`+(a.topWorkstreams?.length?` \xB7 ${a.topWorkstreams.map(i=>i.name).join(", ")}`:""));let r=e.gaps||{};r.tracksWithoutEvents&&t.push(`${r.tracksWithoutEvents} track(s) have no attributed events yet`),r.cursorCostUnknown&&t.push("cursor time counted, cost unavailable"),r.unpricedTurns&&t.push(`WARNING: ${r.unpricedTurns} turn(s) unpriced \u2014 total under-reports`);let o=e.categorization;if(o){t.push(""),t.push((o.ok?"categorization ok: ":"CATEGORIZATION ALARM: ")+`${o.sharePct}% of the last 7d uncategorized (threshold ${o.thresholdPct}%) \xB7 ${o.inheritedPct}% inferred from the previous ask`);for(let a of o.problems||[])t.push(`WARNING: ${a}`)}let s=r.uncategorized;if(s){t.push(""),t.push(`UNCATEGORIZED RESIDUE \xB7 ${ul(s.usd)} (${s.sharePct}%) \xB7 ${s.turns} turn(s) \xB7 by shape: `+(Object.entries(s.byShape||{}).filter(([,a])=>a>0).sort((a,i)=>i[1]-a[1]).map(([a,i])=>`${a} ${ul(i)}`).join(" \xB7 ")||"none")),s.top?.length||t.push(" (nothing unmatched carried cost in this window)");for(let a of s.top||[])t.push(` ${Ts(ul(a.usd),8)} ${Ts(a.shape,10)} ${Ts(String(a.track||"").slice(0,26),26)} | ${a.text}`);s.top?.length&&(t.push(""),t.push("novel-ask rows are vocabulary the classifier lacks: add a rule in agent/src/task-classifier.js (and a line in test/uncategorized-corpus.test.mjs). follow-up rows had no prior ask on their box."))}return t.join(`
742
+ `)}nr();var vo=36e5,V$=24*vo,Pq=400,Dq=12,_s=e=>Math.round(e*1e4)/1e4;function Jy({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 Es?String(e||"7d"):"7d",i=Es[a];return{key:a,since:i==null?null:r-i,until:r}}var Bq=(e,t)=>e!=null&&t-e<=48*vo?vo:V$;function K$(e,t){if(t===vo)return Math.floor(e/vo)*vo;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function jq(e,t){if(t===vo)return e+vo;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var G$=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),z$=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},Lq=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,_s(n)]));async function J$(e,t={}){let n=t.now??Date.now(),r=Jy({...t,now:n}),o=r.since==null?V$:Bq(r.since,r.until),s=T=>(r.since==null||T>=r.since)&&T<r.until,a=r.since!=null?r.until-r.since:null,i=T=>a!=null&&T>=r.since-a&&T<r.since,c={},l={},u=G$(),d=0,p=0,f=0,w=0,h=0,g=0,y=new Set,x=new Map,b=[],I=[],_=[],N=null;for(let T of e||[]){let L=(await K(T)).filter(S=>S.type==="cost.recorded");if(!L.length){T.archivedAt||_.push(T.name||T.id);continue}let V=[];for(let S of L){let M=S.ts??0;s(M)?V.push(S):i(M)&&(g+=Jt(S).usd)}if(!V.length)continue;let O=Kr(V,{boxLabels:cl(T)});d+=O.totalUsd,p+=O.turns,f+=O.repricedTurns||0,w+=O.asRecordedUsd||0,h+=O.unpricedTurns||0;for(let S of O.unpricedModels||[])y.add(S);z$(u,O.totalTokens);for(let[S,M]of Object.entries(O.byModel))c[S]||={usd:0,events:0,tokens:G$()},c[S].usd=_s(c[S].usd+M.usd),c[S].events+=M.events,z$(c[S].tokens,M.tokens);for(let[S,M]of Object.entries(O.byProvider))l[S]||={usd:0,events:0},l[S].usd=_s(l[S].usd+M.usd),l[S].events+=M.events;for(let S of V){let{usd:M}=Jt(S);if(!M)continue;let H=K$(S.ts??0,o),W=x.get(H)??{t:H,total:0,byProvider:{}};W.total+=M;let te=S.provider||"unknown";W.byProvider[te]=(W.byProvider[te]||0)+M,x.set(H,W),(N==null||H<N)&&(N=H)}b.push({id:T.id,name:T.name||T.id,archived:!!T.archivedAt,usd:O.totalUsd,turns:O.turns,providers:Object.keys(O.byProvider)});for(let[S,M]of Object.entries(O.byBox))I.push({trackId:T.id,trackName:T.name||T.id,boxId:S,...M})}let U=r.since!=null?K$(r.since,o):N,j=[];for(let T=U,R=0;T!=null&&T<r.until&&R<Pq;T=jq(T,o),R++){let L=x.get(T);j.push(L?{t:T,total:_s(L.total),byProvider:Lq(L.byProvider)}:{t:T,total:0,byProvider:{}})}return b.sort((T,R)=>R.usd-T.usd),I.sort((T,R)=>R.usd-T.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:ea(),window:r.key,since:r.since,until:r.until,bucketMs:o,series:j,fleet:{totalUsd:_s(d),asRecordedUsd:_s(w),turns:p,repricedTurns:f,unpricedTurns:h,unpricedModels:[...y],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:b.length,tracksSilentLive:_},prior:a!=null?{totalUsd:_s(g),since:r.since-a,until:r.since}:null,tracks:b.slice(0,50),boxes:I.slice(0,Dq)}}bd();var Fq=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),Uq=20,Hq=40;async function Y$(e,t={}){let n=t.now??Date.now(),r=Jy({...t,now:n}),o=l=>(r.since==null||l>=r.since)&&l<r.until,s=[],a={},i=0;for(let l of e||[]){let u=await K(l),d=0,p=cl(l);for(let f of u){if(!Fq.has(f.type))continue;let w=f.type==="code.rework"?f.payload?.ts??f.ts:f.ts;f.type!=="rework.cause.answered"&&!o(w??0)||(f.type==="code.committed"&&d++,s.push(f.trackId?f:{...f,trackId:l.id}))}d&&i++;for(let f of l.boxes||[])a[`${l.id}/${f.name}`]={trackName:l.name||l.id,label:p[f.name]||f.name}}let c=XA(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:io,decayEndDays:qm,basis:c.basis,commits:c.commits,tracksWithCommits:i,fixesAnalyzed:c.fixes.length,fixUsdTotal:c.fixUsdTotal,buckets:c.buckets,verdicts:c.verdicts,intents:c.intents,noCodeDelta:c.noCodeDelta,pendingTaps:c.pendingTaps.length,byProvider:c.byProvider,byModel:c.byModel,epochs:c.epochs.slice(0,Uq),fixes:c.fixes.slice(0,Hq)}}import Wq from"node:fs";import X$ from"node:fs/promises";import dl from"node:os";import qq from"node:path";Bw();ut();var Kq=1024*1024,Lp=e=>Math.round(e/Kq);async function Gq(e){try{let t=await X$.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:Lp(r),diskTotalMb:Lp(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function zq(){try{return(await sn()).filter(t=>t.isBostrat).length}catch{return null}}async function Vq(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await X$.readdir(qq.join(Yc,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function Z$({stateDir:e=Yc,now:t=Date.now}={}){let n=dl.totalmem(),[r,o,s,a]=await Promise.all([Pd().catch(()=>null),Gq(Wq.existsSync(e)?e:dl.tmpdir()),zq(),Vq()]),i=dl.cpus()?.length||null,c=dl.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?Lp(n-r):null,memTotalMb:Lp(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(dl.uptime())}}yw();he();Sh();wi();nr();he();nr();var Jq=864e5;function Yq(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=Rn(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 Q$(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*Jq,s={},a=0,i=0,c=[];for(let u of e||[]){let d=await K(u);for(let p of d){if(!p.ts||p.ts<o)continue;let f=Yq(p,{tolerance:n});if(!f)continue;a++;let w=f.speed?`${f.model} (${f.speed})`:f.model,h=s[w]||={rows:0,divergent:0,asRecordedUsd:0,expectedUsd:0};h.rows++,h.asRecordedUsd+=f.asRecorded,h.expectedUsd+=f.expected,f.divergent&&(i++,h.divergent++,c.length<10&&c.push({track:u.name||u.id,...f}))}}let l=u=>Math.round(u*1e4)/1e4;for(let u of Object.values(s))u.asRecordedUsd=l(u.asRecordedUsd),u.expectedUsd=l(u.expectedUsd);return{sinceMs:o,days:t,tolerance:n,rows:a,divergent:i,byModel:s,examples:c,ok:i===0}}mw();ig();qu();mt();Yt();import Ga from"node:fs/promises";import Xq from"node:fs";import yt from"node:path";import Zq from"node:os";import{execFile as Qq}from"node:child_process";import{promisify as e5}from"node:util";var t5=e5(Qq),eR=process.env.BOSTRAT_STATE_DIR||yt.join(process.env.HOME||Zq.tmpdir(),".bostrat"),Fp=!1,Yy=null;async function Xy(e,t){let n=await Ga.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await Ga.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await Ga.mkdir(yt.dirname(t),{recursive:!0}),await Ga.copyFile(e,t),!0)}var n5=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 Up(e,t,{skip:n=null}={}){let r=0,o=await Ga.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(n5.has(s.name)||n?.has(s.name))continue;let a=yt.join(e,s.name);s.isDirectory()?r+=await Up(a,yt.join(t,s.name)):s.isFile()&&(r+=await Xy(a,yt.join(t,s.name))?1:0)}return r}async function tR({stateDir:e=eR,dest:t=process.env.BOSTRAT_SYNC_DIR||`${eR}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await Ga.mkdir(t,{recursive:!0});let o=0;o+=await Xy(yt.join(e,"tracks.json"),yt.join(t,"tracks.json"))?1:0,o+=await Xy(yt.join(e,"events.jsonl"),yt.join(t,"events.jsonl"))?1:0,o+=await Up(yt.join(e,"events"),yt.join(t,"events")),o+=await Up(yt.join(e,"memory"),yt.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await Up(yt.join(u.cwd,".bostrat"),yt.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>t5("git",["-C",t,...u]);Xq.existsSync(yt.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 Ef(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||Fp))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,Fp&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),Fp=!1,Yy=null}catch(u){Fp=!0;let d=(u?.stderr||u?.message||String(u)).trim().split(`
743
+ `).slice(-3).join(" | ").slice(0,300);d!==Yy&&(Yy=d,console.warn(`[state-sync] PUSH FAILING (retrying each cycle; off-box copy is STALE): ${d}`))}return{staged:o,committed:i,pushed:l}}catch(o){return{staged:0,committed:!1,pushed:!1,error:o?.message||String(o)}}}ng();ln();Fo();ut();ai();import{execFile as r5}from"node:child_process";import{promisify as o5}from"node:util";import{randomUUID as s5}from"node:crypto";import a5 from"node:fs";import i5 from"node:os";import c5 from"node:path";var Ao=o5(r5),Hp=e=>new Promise(t=>setTimeout(t,e)),To=Gf,Zy=process.env.BOSTRAT_USAGE_PROBE_CWD||c5.join(i5.homedir(),".bostrat","usage-probe"),l5=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,u5=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,d5=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,nR=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,So=null,pl=null,fl=null;async function p5(){try{return await Ao(ee,ne("has-session","-t",To)),!0}catch{return!1}}function f5(){So&&clearTimeout(So),So=setTimeout(()=>h5().catch(()=>{}),l5),So.unref&&So.unref()}async function h5(){So&&(clearTimeout(So),So=null);try{await Ao(ee,ne("kill-session","-t",To))}catch{}}async function m5(){let e=Date.now()+d5;for(;;){let t=await Qy().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await Hp(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await Hp(500)}}async function w5(){if(await p5())return;if(!await jr())throw new Error("host tmux server not running \u2014 start globo-tmux.service");a5.mkdirSync(Zy,{recursive:!0}),await $r(Zy);let e=s5();await Ao(ee,ne("new-session","-d","-s",To,"-c",Zy,"-x","200","-y","60",...Ti()));let t=`${Kf} --session-id ${e}`;await Ao(ee,ne("send-keys","-t",To,t,"Enter")),await m5()}async function Qy(){let{stdout:e}=await Ao(ee,ne("capture-pane","-t",To,"-p"));return e}async function g5(){await w5(),await Ao(ee,ne("send-keys","-t",To,"-l","/usage")),await Ao(ee,ne("send-keys","-t",To,"Enter"));let e=Date.now()+u5,t="";for(;await Hp(400),t=await Qy(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await Hp(900),t=await Qy(),await Ao(ee,ne("send-keys","-t",To,"Escape")).catch(()=>{}),f5(),t}function y5(e){let t=String(e||"").split(`
744
+ `).map(s=>s.replace(/\s+$/,"").trim()),n=s=>{let a=null,i=null;for(let c=s+1;c<Math.min(s+5,t.length)&&!/^Current\s/i.test(t[c]);c++){let l=t[c].match(/(\d+)%\s*used/i);l&&a===null&&(a=Number(l[1]));let u=t[c].match(/^Resets\s+(.+)$/i);u&&i===null&&(i=u[1].trim())}return a===null?null:{pct:a,resets:i||null}},r=s=>{let a=t.findIndex(i=>s.test(i));return a<0?null:n(a)},o=[];return t.forEach((s,a)=>{let i=s.match(/^Current week \(([^)]+)\)$/i);if(!i||/all models/i.test(i[1]))return;let c=n(a);c&&o.push({model:i[1].trim(),...c})}),{session:r(/^Current session\b/i),week:r(/^Current week \(all models\)/i)||r(/^Current week$/i),weekModels:o.length?o:null}}function b5(e){let t=String(e||"").split(`
745
+ `).map(s=>s.replace(/\s+$/,"")),n=t.findIndex(s=>/What's contributing/i.test(s));if(n<0)return null;let r=/(Usage credits|Esc to cancel|d to day · w to week|^\s*d to day)/i,o=[];for(let s=n+1;s<t.length&&!r.test(t[s]);s++)t[s].trim()&&o.push(t[s].trim());return o.length?o:null}async function rR({fresh:e=!1}={}){return!e&&pl&&Date.now()-pl.at<nR?pl.data:fl||(fl=(async()=>{try{let t=await g5(),n=y5(t),r={...n,contributors:b5(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return pl={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 pl={at:Date.now()-(nR-3e3),data:n},n}finally{fl=null}})(),fl)}var k5=262144;function x5(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 v5=new Set([300]),S5=new Set([10080]);function A5(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:v5.has(t)?"session":S5.has(t)?"week":"other"}function T5(e){let t=Number(e);return!Number.isFinite(t)||t<=0?"Window":t%1440===0?`Window \xB7 ${t/1440}d`:t%60===0?`Window \xB7 ${t/60}h`:`Window \xB7 ${t}m`}function E5(e,t,n){if(!e||typeof e!="object")return null;let r=Number(e.used_percent);if(!Number.isFinite(r))return null;let o=null,s=Number(e.resets_at),a=Number(e.resets_in_seconds);return Number.isFinite(s)&&s>0?o=s*1e3:Number.isFinite(a)&&a>=0&&(o=(Number.isFinite(t)?t:n)+a*1e3),{pct:Math.round(r),resets:o!=null?x5((o-n)/1e3):null,resetsAt:o}}var hl=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function _5(e,t=Date.now()){let n=String(e||"").split(`
746
+ `),r=!1;for(let o=n.length-1;o>=0;o--){let s=n[o].trim();if(!s||s[0]!=="{"||!s.includes("token_count"))continue;let a;try{a=JSON.parse(s)}catch{continue}let i=a?.payload;if(i?.type!=="token_count")continue;r=!0;let c=i.rate_limits;if(!c)return hl(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=hl(r);[c.primary,c.secondary].forEach((f,w)=>{let h=E5(f,l,t);if(!h)return;let g=A5(f.window_minutes);g===null&&(g=w===0?"session":"week"),g==="session"&&!u.session?u.session=h:g==="week"&&!u.week?u.week=h:(u.other??=[]).push({label:T5(f.window_minutes),...h})}),u.planType=typeof c.plan_type=="string"?c.plan_type:null;let p=c.credits;return p&&(p.has_credits||p.unlimited)&&(u.credits={balance:String(p.balance??""),unlimited:!!p.unlimited}),u.limitReached=typeof c.rate_limit_reached_type=="string"&&c.rate_limit_reached_type||(c.spend_control_reached?"spend_control":null),u}if(c.primary_used_percent!=null||c.secondary_used_percent!=null){let l=u=>Number.isFinite(Number(u))?{pct:Math.round(Number(u)),resets:null,resetsAt:null}:null;return{...hl(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return hl(r)}return hl(r)}async function eb(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await jo(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 Mt(n.file,k5),o=_5(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 oR(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 Wp({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 eb(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await eb(null))}return n.has("cursor")&&r.push(await Wp({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function Wp(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?eb(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await rR({fresh:t})}}Or();mt();mt();function I5(e=process.env){return!!(Re(e)&&e.BOSTRAT_PLANE_TOKEN)}var $5=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),qp=(e,t)=>Object.assign(new Error(e),{status:t});async function sR(e,t){if(!I5(t))throw qp("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${Re(t)}${e}`,{headers:$5(t)})}catch(o){throw qp(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw qp(r?.error||`plane replied ${n.status}`,n.status);return r}async function aR(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await sR(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function iR(e,{env:t=process.env}={}){if(!e)throw qp("message id required",400);return(await sR(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}ec();ad();function tb(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 R5(e){let[t,n]=e.split("/"),r=tb(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 cR(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(R5).filter(Boolean)}function O5(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function lR(e){let t=cR(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:O5,allowed(r){if(n)return!0;let o=tb((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function uR(e,t){let n=cR(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=tb(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import dR from"node:crypto";import Kp from"node:fs";import M5 from"node:path";function pR(e=process.env,{stateDir:t=Yc,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=M5.join(t,"api-token");try{let a=Kp.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=dR.randomBytes(32).toString("base64url");try{Kp.mkdirSync(t,{recursive:!0}),Kp.writeFileSync(o,s+`
747
+ `,{mode:384}),Kp.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function ml(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 fR(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:dR.timingSafeEqual(n,r)}function hR(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 C5=[/^\/api\/github\/token\b/,/^\/api\/gmail\b/,/^\/api\/tracks\/adopt\b/,/^\/api\/tracks\/[^/]+\/transfer-out\b/,/^\/api\/node\/self-update\b/,/^\/api\/changelog\/(publish|retract)\b/,/^\/api\/tracks\/[^/]+\/loop-(update|delete)-offer\b/],N5=e=>C5.some(t=>t.test(e));function mR({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=hR(o);return fR(c,e)?a():N5(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||ml(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 wR(e,t,{enforce:n=!0}={}){return!n||fR(hR(e),t)?!0:ml(e)}Tn();Cd();Cd();import P5 from"node:http";import D5 from"node:net";function Gp(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 zp(e){let t=Gp(e.headers.host);return t?{slug:t,view:Ow(t)}:null}var B5=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),j5=e=>{let t=B5(e.name);return`<!doctype html><meta charset="utf-8">
744
748
  <meta http-equiv="refresh" content="3">
745
749
  <title>${t} \u2014 starting</title>
746
750
  <body style="font-family:system-ui;background:#0b0e14;color:#dce3f0;display:grid;place-items:center;height:100vh;margin:0">
747
751
  <div style="text-align:center"><p style="font-size:2rem;margin:0">\u23F3</p>
748
- <p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function P$(e){if(!/[?&]token=/.test(e))return e;try{let t=new URL(e,"http://view");return t.searchParams.delete("token"),t.pathname+t.search}catch{return e}}function D$(e,t,n){let r=hp(e);if(!r)return n();let{view:o,slug:s}=r;if(!o)return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: no view named "${s}"`);if(o.state==="starting")return t.statusCode=503,t.setHeader("content-type","text/html"),t.end(Zq(o));if(o.state!=="live"&&o.state!=="unhealthy")return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" is ${o.state} \u2014 restart it from the Views tab`);let a={...e.headers,host:`127.0.0.1:${o.port}`,"x-forwarded-host":e.headers.host,"x-forwarded-proto":e.headers["x-forwarded-proto"]||"http"};delete a.authorization,delete a.cookie,delete a["x-bostrat-token"];let i=Jq.request({host:"127.0.0.1",port:o.port,method:e.method,path:P$(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 B$(e,t,n){let r=hp(e);if(!r)return!1;let{view:o,slug:s}=r;if(!o||o.state!=="live"&&o.state!=="unhealthy")return t.write(`HTTP/1.1 404 Not Found\r
752
+ <p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function gR(e){if(!/[?&]token=/.test(e))return e;try{let t=new URL(e,"http://view");return t.searchParams.delete("token"),t.pathname+t.search}catch{return e}}function yR(e,t,n){let r=zp(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(j5(o));if(o.state!=="live"&&o.state!=="unhealthy")return t.statusCode=404,t.setHeader("content-type","text/plain"),t.end(`bostrat: view "${s}" is ${o.state} \u2014 restart it from the Views tab`);let a={...e.headers,host:`127.0.0.1:${o.port}`,"x-forwarded-host":e.headers.host,"x-forwarded-proto":e.headers["x-forwarded-proto"]||"http"};delete a.authorization,delete a.cookie,delete a["x-bostrat-token"];let i=P5.request({host:"127.0.0.1",port:o.port,method:e.method,path:gR(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 bR(e,t,n){let r=zp(e);if(!r)return!1;let{view:o,slug:s}=r;if(!o||o.state!=="live"&&o.state!=="unhealthy")return t.write(`HTTP/1.1 404 Not Found\r
749
753
  \r
750
754
  bostrat: no live view "${s}"\r
751
- `),t.destroy(),!0;let a=Yq.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${P$(e.url)} HTTP/1.1`];for(let[l,u]of Object.entries(e.headers))l!=="host"&&(l==="authorization"||l==="cookie"||l==="x-bostrat-token"||c.push(`${l}: ${Array.isArray(u)?u.join(", "):u}`));c.push(`host: 127.0.0.1:${o.port}`),a.write(c.join(`\r
755
+ `),t.destroy(),!0;let a=D5.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${gR(e.url)} HTTP/1.1`];for(let[l,u]of Object.entries(e.headers))l!=="host"&&(l==="authorization"||l==="cookie"||l==="x-bostrat-token"||c.push(`${l}: ${Array.isArray(u)?u.join(", "):u}`));c.push(`host: 127.0.0.1:${o.port}`),a.write(c.join(`\r
752
756
  `)+`\r
753
757
  \r
754
- `),n?.length&&a.write(n),t.pipe(a),a.pipe(t)}),i=()=>{a.destroy(),t.destroy()};return a.on("error",i),t.on("error",i),!0}function j$(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}.${Qq(n.host)}/`}function Qq(e){if(process.env.BOSTRAT_PUBLIC_HOST)return String(process.env.BOSTRAT_PUBLIC_HOST).replace(/:\d+$/,"");let t=String(e||"").replace(/:\d+$/,"").toLowerCase();if(!t||!t.includes(".")||/^[\d.]+$/.test(t))return"bostrat.globopi";let n=t.split(".");return mp(t)&&Xh(n[0])?n.slice(1).join("."):t}da();uw();yd();vh();pe();import L$ from"node:os";import{randomUUID as Sy}from"node:crypto";var e5=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||L$.hostname(),nodeName:e.BOSTRAT_NODE_NAME||L$.hostname()});var F$=32768,U$=120,H$=1e3,W$=new Set(["claude","codex","cursor"]),t5=new Set(["off","transition","nag"]),n5=[[0,59],[0,23],[1,31],[1,12],[0,6]];function r5(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=n5[r];return String(n).split(",").every(a=>{if(!a)return!1;let[i,c]=a.split("/");if(c!==void 0&&!(Number.isInteger(Number(c))&&Number(c)>=1))return!1;if(i==="*")return!0;let[l,u]=i.includes("-")?i.split("-").map(Number):[Number(i),Number(i)];return Number.isInteger(l)&&Number.isInteger(u)&&l>=o&&u<=s&&l<=u})})}var bn=e=>String(e??"").trim(),us={name(e){let t=bn(e);if(!t)throw new Error("a loop needs a name");if(t.length>U$)throw new Error(`name is too long (${t.length}); cap is ${U$}`);return t},schedule(e){let t=bn(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!r5(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=bn(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>F$)throw new Error(`prompt is too long (${t.length} chars); cap is ${F$}`);return t},expectation(e){let t=bn(e)||null;if(t&&t.length>H$)throw new Error(`expectation is too long (${t.length}); cap is ${H$}`);return t},notify(e){let t=bn(e)||"off";if(!t5.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=bn(typeof t=="string"?t:t?.provider)||"claude";if(!W$.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...W$].join(", ")}`);let r=typeof t=="object"&&t&&bn(t.model)||null;return r?{provider:n,model:r}:{provider:n}},enabled(e){if(typeof e=="boolean")return e;if(e==="true"||e==="false")return e==="true";throw new Error(`enabled must be true or false, got "${e}"`)}};function o5(e,t){let n=e&&typeof e=="object"?e:{},r=us.name(n.name),o=us.schedule(n.schedule),s=us.prompt(n.prompt),a=us.expectation(n.expectation),i=us.notify(n.notify),c=us.assignment(n.assignment),l=bn(t?.workspace?.repo)||bn(t?.workspace?.base)||null;if(!l)throw new Error("this Track isn't based on a repo, so there's nothing for a loop to run in \u2014 propose from a repo-backed Track");let{nodeId:u,nodeName:d}=e5();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:d||null}}async function K$(e,t){let n=o5(t,e),r=Sy();return await M({id:e.id,cwd:e.cwd},{type:"loop.create.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),proposalId:r,...n}}),{proposalId:r,...n}}async function G$(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await q({id:e.id,cwd:e.cwd}),a=s.find(c=>c.type==="loop.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="loop.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await M({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"dismiss"}}),{proposalId:t,action:"dismiss"};if(!r)throw new Error("loopId required \u2014 the loop is created on the plane before the card is answered");let i=a.payload;return await M({id:e.id,cwd:e.cwd},{type:"loop.created",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:String(r),name:i.name,schedule:i.schedule,provider:i.assignment?.provider??"claude",repo:i.repo??null,nodeId:i.nodeId??null,nextFireAt:Number.isFinite(Number(o))?Number(o):null}}),await M({id:e.id,cwd:e.cwd},{type:"loop.create.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:"created",loopId:String(r)}}),{proposalId:t,action:"created",loopId:String(r)}}var vy=["name","schedule","prompt","expectation","notify","assignment","enabled"],s5=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function z$(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 V$(e,t){let n=bn(t);if(!n)throw new Error("which loop? give an id or a name \u2014 see `bostrat-loop ls`");let r=e.find(a=>a.id===n)||e.find(a=>a.name===n);if(r)return r;let o=n.toLowerCase(),s=e.filter(a=>String(a.id).toLowerCase().startsWith(o)||String(a.name).toLowerCase().startsWith(o));if(s.length===1)return s[0];throw s.length>1?new Error(`"${n}" matches ${s.length} loops: ${s.map(a=>`${a.name} (${a.id})`).join(", ")} \u2014 use the id`):new Error(`no loop matching "${n}" \u2014 use \`bostrat-loop ls\``)}function a5(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=>!vy.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: ${vy.join(", ")}`)}let o={};for(let a of vy){if(!(a in n))continue;let i=us[a](n[a]);(a==="assignment"?s5(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 J$(e,t,n){let r=z$(t),{patch:o,changed:s}=a5(n,r),a=Sy(),i={ts:Date.now(),proposalId:a,loopId:String(t.id),name:r.name,base:r,patch:o,changed:s,selfEdit:!!(r.trackId&&r.trackId===e.id)};return await M({id:e.id,cwd:e.cwd},{type:"loop.update.offered",actor:"system",source:"orchestrator",payload:i}),i}var q$=600;async function Y$(e,t,n){let r=bn(n);if(!r)throw new Error('a delete proposal needs a reason \u2014 bostrat-loop propose-delete <loop> --reason "<why this loop should go>"');if(r.length>q$)throw new Error(`reason is too long (${r.length}); cap is ${q$}`);let o=z$(t),s=Sy(),a={ts:Date.now(),proposalId:s,loopId:String(t.id),name:o.name,base:o,reason:r,selfEdit:!!(o.trackId&&o.trackId===e.id)};return await M({id:e.id,cwd:e.cwd},{type:"loop.delete.offered",actor:"system",source:"orchestrator",payload:a}),a}var X$=async(e,t,n)=>{if(!n)throw new Error("proposalId required");let r=await q({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 Z$(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 X$(e,"loop.update.offered",t)).payload,a={id:e.id,cwd:e.cwd};return n==="applied"&&await M(a,{type:"loop.updated",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:s.loopId,name:s.patch?.name??s.name,changed:s.changed??Object.keys(s.patch||{}),nextFireAt:Number.isFinite(Number(r))?Number(r):null}}),await M(a,{type:"loop.update.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,loopId:s.loopId}}),{proposalId:t,action:n,loopId:s.loopId}}async function Q$(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 X$(e,"loop.delete.offered",t)).payload,s={id:e.id,cwd:e.cwd};return(n==="delete"||n==="pause")&&await M(s,{type:n==="delete"?"loop.deleted":"loop.paused",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,loopId:o.loopId,name:o.name,trackId:o.base?.trackId??null}}),await M(s,{type:"loop.delete.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,loopId:o.loopId}}),{proposalId:t,action:n,loopId:o.loopId}}pe();import{randomUUID as i5}from"node:crypto";var Ey=20,c5=300,Ty=120,eR=120,tR=2e3,wp=new Set(["build","ops","debt","spike"]),nR=new Set(["active","done","abandoned"]),_y=new Set(["circuit.create","circuit.update","circuit.delete"]),l5=new Set(["person.create","slot.create","slot.update","slot.delete","reservation.create","reservation.update","reservation.delete"]),el=new Set([..._y,...l5]),u5=["name","description","status","type"],d5=["person","startDate","endDate","estUsd"],p5=["person","label","startDate","endDate"],f5=/^\d{4}-\d{2}-\d{2}$/,Lt=e=>String(e??"").trim(),Iy=e=>typeof e=="string"&&e.startsWith("@"),sR=864e5;function aR(e){let t=Date.parse(`${e}T00:00:00Z`),n=new Date(t).getUTCDay();return new Date(t-(n+6)%7*sR).toISOString().slice(0,10)}function m5(e){return new Date(Date.parse(`${aR(e)}T00:00:00Z`)+6*sR).toISOString().slice(0,10)}var rR=(e,t)=>{let n=Lt(e);if(!f5.test(n))throw new Error(`${t} must be YYYY-MM-DD, got "${e??""}"`);if(!Number.isFinite(Date.parse(`${n}T00:00:00Z`)))throw new Error(`${t} "${n}" is not a real date`);return n};function h5(e,t){let n=rR(e,"startDate"),r=rR(t,"endDate");if(r<n)throw new Error(`endDate ${r} is before startDate ${n}`);let o=aR(n),s=m5(r);return{startDate:o,endDate:s,snapped:o!==n||s!==r}}var oR=e=>{if(e==null||e==="")return null;let t=Number(e);if(!Number.isFinite(t)||t<0)throw new Error(`estUsd must be a non-negative number, got "${e}"`);return t},yo=(e,t,n)=>{let r=Lt(e);if(r.length>t)throw new Error(`${n} is too long (${r.length}); cap is ${t}`);return r};function Ay(e,t){let n=Lt(t);if(!n)throw new Error("a circuit name or id is required");if(Iy(n))return{ref:n,id:null,name:n.slice(1)};let r=e.find(i=>i.id===n);if(r)return r;let o=n.toLowerCase(),s=e.filter(i=>String(i.name).toLowerCase()===o);if(s.length===1)return s[0];if(s.length>1)throw new Error(`"${n}" names ${s.length} circuits \u2014 use an id (bostrat-circuit ls)`);let a=e.filter(i=>String(i.name).toLowerCase().includes(o)).slice(0,5);throw new Error(a.length?`no circuit named "${n}" \u2014 near matches: ${a.map(i=>`${i.name} (${i.id})`).join(", ")}`:`no circuit named "${n}" \u2014 propose a circuit.create op if it should exist (bostrat-circuit ls lists yours)`)}function w5(e,t){let n=Lt(t);if(!n)throw new Error('a person is required \u2014 "me", a person id, or a row label');if(n==="me"||Iy(n))return{ref:n,id:null,label:n==="me"?"you":n.slice(1)};let r=e.find(a=>a.personId===n);if(r)return{...r,id:r.personId};let o=n.toLowerCase(),s=e.filter(a=>String(a.label).toLowerCase()===o);if(s.length===1)return{...s[0],id:s[0].personId};throw s.length>1?new Error(`"${n}" names ${s.length} roadmap rows \u2014 use a person id`):new Error(e.length?`no roadmap row for "${n}" \u2014 rows: ${e.map(a=>`${a.label} (${a.personId})`).join(", ")}, or propose a person.create op`:`no roadmap rows yet \u2014 use "me", or propose a person.create op for "${n}"`)}function g5(e,t,{allow:n=el}={}){let r=e&&typeof e=="object"&&!Array.isArray(e)?e:null;if(!r)throw new Error("a plan must be a JSON object with an `ops` array");let o=Array.isArray(r.ops)?r.ops:null;if(!o?.length)throw new Error("a plan needs at least one op in `ops`");if(o.length>Ey)throw new Error(`too many ops (${o.length}); cap is ${Ey} \u2014 propose one intent at a time`);let s=Array.isArray(t?.circuits)?t.circuits:[],a=Array.isArray(t?.people)?t.people:[],i=Array.isArray(t?.slots)?t.slots:[],c=Array.isArray(t?.reservations)?t.reservations:[],l={circuits:{},slots:{},reservations:{}},u={},d=new Set,p=!1,f=!1,w=b=>{b.id&&(l.circuits[b.id]={name:b.name,status:b.status,type:b.type??"build",updatedAt:b.updatedAt??null},u[b.id]=b.name)},m=b=>{b.id&&(u[b.id]=b.label)},g=(b,O)=>{let I=Lt(b);if(!I)return null;if(d.has(I))throw new Error(`ref "${I}" is used by two ops \u2014 each ref names one thing`);return d.add(I),u[`@${I}`]=O,I},y=o.map((b,O)=>{let I=b&&typeof b=="object"?b:{},C=Lt(I.op),U=`op ${O+1}`;if(!el.has(C))throw new Error(`${U}: unknown op "${C}" \u2014 one of ${[...el].join(", ")}`);if(!n.has(C))throw new Error(`${U}: "${C}" isn't a circuit op \u2014 roadmap changes go through \`bostrat-roadmap propose\` (one card, either CLI)`);let H=S=>{throw new Error(`${U} (${C}): ${S}`)},_=S=>{let E=I.set&&typeof I.set=="object"&&!Array.isArray(I.set)?I.set:null;E||H("needs a `set` object naming the fields to change");let P=Object.keys(E).filter(W=>!S.includes(W));return P.length&&H(`unknown field(s) ${P.join(", ")} \u2014 settable: ${S.join(", ")}`),Object.keys(E).length||H("`set` names no fields"),E},$=S=>{let{startDate:E,endDate:P,snapped:W}=h5(S.startDate,S.endDate);return W&&(p=!0),{startDate:E,endDate:P,snapped:W}},L=S=>{let E=w5(a,S);return Lt(S)==="me"&&(f=!0),m(E),{key:E.id??Lt(S),label:E.label}},V=(S,E,P,W,G)=>{let ae=Lt(S);ae||H(`needs a ${W} id`);let we=E.find(Re=>Re[P]===ae);return we||H(`no ${W} "${ae}" \u2014 see \`bostrat-roadmap ls\``),G[ae]={...we},we};switch(C){case"circuit.create":{let S=yo(I.name,eR,"name");S||H("a circuit needs a name");let E=Lt(I.type)||"build";wp.has(E)||H(`bad type "${E}" (${[...wp].join(" | ")})`);let P=s.find(G=>String(G.name).toLowerCase()===S.toLowerCase());P&&H(`a circuit named "${P.name}" already exists (${P.id}) \u2014 update it instead of making a twin`);let W=g(I.ref,S);return{op:C,...W?{ref:W}:{},name:S,description:yo(I.description,tR,"description"),type:E}}case"circuit.update":{let S=Ay(s,I.circuit);S.id||H("can't update a circuit created in the same plan \u2014 set its fields on the create op"),w(S);let E=_(u5),P={};if(E.name!==void 0){let W=yo(E.name,eR,"name");W||H("name can't be blank"),W!==S.name&&(P.name=W)}return E.description!==void 0&&(P.description=yo(E.description,tR,"description")),E.status!==void 0&&(nR.has(E.status)||H(`bad status "${E.status}" (${[...nR].join(" | ")})`),E.status!==S.status&&(P.status=E.status)),E.type!==void 0&&(wp.has(E.type)||H(`bad type "${E.type}" (${[...wp].join(" | ")})`),E.type!==(S.type??"build")&&(P.type=E.type)),Object.keys(P).length||H("nothing would change \u2014 the set equals the circuit's current values"),{op:C,circuit:S.id,name:S.name,set:P}}case"circuit.delete":{let S=Ay(s,I.circuit);S.id||H("can't delete a circuit created in the same plan"),w(S);let E=o.some((P,W)=>W<O&&Lt(P?.op)==="circuit.update"&&P?.set?.status&&P.set.status!=="active"&&Lt(P?.circuit)===Lt(I.circuit));return S.status==="active"&&!E&&H(`\u201C${S.name}\u201D is active \u2014 an active circuit can't be deleted; propose a circuit.update to done/abandoned first (both can ride one card)`),{op:C,circuit:S.id,name:S.name,status:S.status}}case"person.create":{let S=yo(I.label,Ty,"label");S||H("a person row needs a label");let E=a.find(W=>String(W.label).toLowerCase()===S.toLowerCase());E&&H(`a roadmap row labelled "${E.label}" already exists (${E.personId})`);let P=g(I.ref,S);return{op:C,...P?{ref:P}:{},label:S}}case"slot.create":{let S=Ay(s,I.circuit);w(S);let E=L(I.person),P=$(I);return{op:C,circuit:S.id??S.ref,circuitName:S.name,person:E.key,personLabel:E.label,...P,estUsd:oR(I.estUsd)}}case"slot.update":{let S=V(I.slot,i,"slotId","slot",l.slots),E=_(d5),P={};if(E.person!==void 0){let G=L(E.person);P.person=G.key,P.personLabel=G.label}if(E.startDate!==void 0||E.endDate!==void 0){let G=$({startDate:E.startDate??S.startDate,endDate:E.endDate??S.endDate});G.startDate!==S.startDate&&(P.startDate=G.startDate),G.endDate!==S.endDate&&(P.endDate=G.endDate)}E.estUsd!==void 0&&(P.estUsd=oR(E.estUsd)),Object.keys(P).length||H("nothing would change");let W=s.find(G=>G.id===S.circuitId);return{op:C,slot:S.slotId,circuitName:W?.name??null,set:P}}case"slot.delete":{let S=V(I.slot,i,"slotId","slot",l.slots),E=s.find(P=>P.id===S.circuitId);return{op:C,slot:S.slotId,circuitName:E?.name??null,startDate:S.startDate,endDate:S.endDate}}case"reservation.create":{let S=L(I.person),E=yo(I.label,Ty,"label");return E||H("a reservation needs a label (Leave, Support rotation, \u2026)"),{op:C,person:S.key,personLabel:S.label,label:E,...$(I)}}case"reservation.update":{let S=V(I.reservation,c,"reservationId","reservation",l.reservations),E=_(p5),P={};if(E.person!==void 0){let W=L(E.person);P.person=W.key,P.personLabel=W.label}if(E.label!==void 0){let W=yo(E.label,Ty,"label");W||H("label can't be blank"),W!==S.label&&(P.label=W)}if(E.startDate!==void 0||E.endDate!==void 0){let W=$({startDate:E.startDate??S.startDate,endDate:E.endDate??S.endDate});W.startDate!==S.startDate&&(P.startDate=W.startDate),W.endDate!==S.endDate&&(P.endDate=W.endDate)}return Object.keys(P).length||H("nothing would change"),{op:C,reservation:S.reservationId,label:S.label,set:P}}case"reservation.delete":{let S=V(I.reservation,c,"reservationId","reservation",l.reservations);return{op:C,reservation:S.reservationId,label:S.label,startDate:S.startDate,endDate:S.endDate}}default:return H("unhandled op")}});y.forEach((b,O)=>{for(let I of[b.circuit,b.person,b.set?.person])if(Iy(I)&&!d.has(String(I).slice(1)))throw new Error(`op ${O+1} (${b.op}): unknown ref "${I}" \u2014 no earlier op in this plan creates it`)});let x=a.some(b=>b.kind==="user"&&b.userId);return{why:yo(r.why,c5,"why"),ops:y,base:l,resolved:u,snapped:p,createsMeRow:f&&!x}}async function iR(e,t,n,r={}){let o=g5(t,n,r),s=i5(),a={ts:Date.now(),proposalId:s,...o};return await M({id:e.id,cwd:e.cwd},{type:"planning.change.offered",actor:"system",source:"orchestrator",payload:a}),a}var y5=async(e,t)=>{if(!t)throw new Error("proposalId required");let n=await q({id:e.id,cwd:e.cwd}),r=n.find(o=>o.type==="planning.change.offered"&&o.payload?.proposalId===t);if(!r)throw new Error("unknown proposal");if(n.some(o=>o.type==="planning.change.answered"&&o.payload?.proposalId===t))throw new Error("proposal already answered");return r};async function cR(e,t,n,{results:r=[]}={}){if(!["applied","dismiss","moved"].includes(n))throw new Error("action must be one of applied | dismiss | moved");let o=await y5(e,t),s={id:e.id,cwd:e.cwd},a=o.payload;return n==="applied"&&await M(s,{type:"planning.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,why:a.why??"",results:Array.isArray(r)?r.slice(0,Ey+1):[]}}),await M(s,{type:"planning.change.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,ops:a.ops?.length??0}}),{proposalId:t,action:n}}od();pe();Ir();pe();Rn();yd();var lR=10,uR=200,b5=120,k5=24,pR=/^\d{4}-\d{2}-\d{2}$/;function $y(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var x5=(e=Date.now())=>new Date(e).toISOString().slice(0,10),wt=(e,t="i")=>new RegExp(e,t),v5=[{re:wt("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:wt("\\bSPC\\b",""),reason:"business (SPC)"},{re:wt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:wt("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:wt("\\bReplicas\\b",""),reason:"competitor research"},{re:wt("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:wt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:wt("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],S5=[wt("\\bSPC\\b",""),wt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),wt("competitor|cloudcli|\\bkiro\\b"),wt("\\bReplicas\\b",""),wt("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),wt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),wt("(^|[^\\w&])#\\d+\\b"),wt("\\btrack/[\\w.-]+")];function T5({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of v5)if(o.test(n)||o.test(r))return s;return null}function dR(e){let t=String(e||"");for(let n of S5){let r=n.exec(t);if(r)return r[0].trim()}return null}function fR(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 A5=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function E5(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=dc(e);if(t.length)throw new Error(`changelog entry appears to contain a secret VALUE (${t.join(", ")}) \u2014 entries ship off-box; never put a credential in one. Replace it and retry.`);let n=null,r=[];for(let o of e.split(`
755
- `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,b5)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${k5}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=A5.exec(i);if(!u||!u[1].trim()||!u[2].trim())throw new Error(`bullet ${r.length+1} must be \`**Short summary** \u2014 the item, one sentence.\` (bold summary title, em dash, then the change) \u2014 got "${i.slice(0,80)}". Rewrite it and re-publish.`);i=`**${u[1].trim().replace(/[:.]\s*$/,"")}** \u2014 ${u[2].trim()}`;let d=dR(i);if(d)throw new Error(`bullet ${r.length+1} mentions "${d}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items, PR numbers, branch names or codenames; drop the bullet or rewrite it as the user-visible change and re-publish.`);if(i.length>uR)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${uR}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=dR(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>lR)throw new Error(`${r.length} bullets \u2014 over the ${lR}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function _5(e,{repos:t=$y()}={}){let n=new Set(t);return(await un()).filter(r=>r.state==="merged"&&(r.resolvedAt??0)>=e&&n.has(r.repo)).sort((r,o)=>(r.resolvedAt??0)-(o.resolvedAt??0)).map(r=>({repo:r.repo,number:r.number,title:r.title||null,url:r.url||null,headRef:r.headRef||null,mergedAt:r.resolvedAt??null,excluded:T5({title:r.title,headRef:r.headRef})}))}async function mR(e,t){let n=await _5(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function hR(e,{md:t,day:n=null}){let r=E5(t),o=n==null||n===""?x5():String(n);if(!pR.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await M({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:o,title:r.title,bullets:r.bullets}});return{day:o,title:r.title,bullets:r.bullets,eventId:s.id}}async function wR(e,{day:t}){let n=String(t||"");if(!pR.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await M({id:e.id,cwd:e.cwd},{type:"changelog.published",actor:"agent",source:"orchestrator",boxId:e.leadBox||null,payload:{ts:Date.now(),day:n,title:null,bullets:[],retract:!0}});return{day:n,retracted:!0,eventId:r.id}}Uo();Rn();Wo();pe();Uo();pt();cr();Rn();Bi();Qu();ju();Wi();Gt();import{execFile as L5}from"node:child_process";import{promisify as F5}from"node:util";var I5=new Set(["pull_request","check_suite","workflow_run","push"]),$5=/^[^/\s]+\/[^/\s]+$/,R5=500,Ry=new Set,Oy=[],gp=new Map,Qt={hourStart:0,byEvent:{},duplicates:0,rejected:0};function My(e,t,n){let r=Math.floor(e/36e5)*36e5;r!==Qt.hourStart&&(Qt.hourStart=r,Qt.byEvent={},Qt.duplicates=0,Qt.rejected=0),t==="accepted"?Qt.byEvent[n]=(Qt.byEvent[n]||0)+1:Qt[t]+=1}function O5(e){if(!e||typeof e!="object"||e.forge!=="github"||typeof e.event!="string"||!I5.has(e.event)||typeof e.repo!="string"||!$5.test(e.repo))return null;let t=(Array.isArray(e.numbers)?e.numbers:[]).map(Number).filter(r=>Number.isInteger(r)&&r>0),n=Number.isInteger(e.number)&&e.number>0?e.number:t[0]??null;return{forge:"github",deliveryId:typeof e.deliveryId=="string"&&e.deliveryId?e.deliveryId.slice(0,128):null,event:e.event,action:typeof e.action=="string"?e.action.slice(0,64):null,repo:e.repo,number:n,numbers:n&&!t.includes(n)?[n,...t]:t,headSha:typeof e.headSha=="string"?e.headSha.slice(0,64):null,headRef:typeof e.headRef=="string"?e.headRef.slice(0,256):null,baseRef:typeof e.baseRef=="string"?e.baseRef.slice(0,256):null,merged:typeof e.merged=="boolean"?e.merged:null,draft:typeof e.draft=="boolean"?e.draft:null,conclusion:typeof e.conclusion=="string"?e.conclusion.slice(0,64):null,deleted:e.deleted===!0,senderLogin:typeof e.senderLogin=="string"?e.senderLogin.slice(0,128):null,ts:Number.isFinite(e.ts)?e.ts:null}}function gR(e,{now:t=Date.now(),onAccept:n=null,log:r=console}={}){let o=O5(e);if(!o)return My(t,"rejected"),{ok:!1,error:"malformed github event envelope"};if(o.deliveryId){if(Ry.has(o.deliveryId))return My(t,"duplicates"),{ok:!0,duplicate:!0,envelope:o};for(Ry.add(o.deliveryId),Oy.push(o.deliveryId);Oy.length>R5;)Ry.delete(Oy.shift())}let s=o.repo.toLowerCase(),a=gp.get(s)||{lastDeliveryAt:0,count:0};a.lastDeliveryAt=t,a.count+=1,gp.set(s,a),My(t,"accepted",o.event),r.log?.(`[github-event] ${o.event}${o.action?` ${o.action}`:""} ${o.repo}${o.number?` #${o.number}`:o.headRef?` ${o.headRef}`:""}${o.conclusion?` (${o.conclusion})`:""}${o.deliveryId?` delivery ${o.deliveryId.slice(0,8)}`:""}`);try{n?.(o)}catch(i){r.error?.("[github-event] onAccept failed:",i?.message||i)}return{ok:!0,duplicate:!1,envelope:o}}function M5(e,t=Date.now()){let n=gp.get(String(e||"").toLowerCase());return n?{covered:!0,lastDeliveryAt:n.lastDeliveryAt,ageMs:t-n.lastDeliveryAt,count:n.count}:{covered:!1,lastDeliveryAt:null,ageMs:null,count:0}}var yR=1440*6e4;function Cy(e,t=Date.now()){let n=M5(e,t);return n.covered&&n.ageMs<yR}function bR(e=Date.now()){let t={};for(let[n,r]of gp)t[n]={lastDeliveryAt:r.lastDeliveryAt,count:r.count,covered:e-r.lastDeliveryAt<yR};return{hourStart:Qt.hourStart,byEvent:{...Qt.byEvent},duplicates:Qt.duplicates,rejected:Qt.rejected,repos:t}}pe();Rn();Tr();cr();Gt();function kR(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function C5(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var N5=new Set(["merged","closed","lost"]);function P5(e,t){if(!e?.blocked)return null;let n=kR(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 D5(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function B5(e,t,n,r,o){return(await q(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 j5(e,t,n){await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function yp(e,t={}){let{now:n=Date.now(),slugOf:r=_e,lookup:o=at,note:s=xS,tracks:a=async()=>(await he()).filter(d=>!De(d)),asked:i=B5,emitChange:c=j5}=t,l=[],u=null;for(let d of e??[]){if(!d?.prs?.length)continue;let p=await r(d.path).catch(()=>null);if(p)for(let f of d.prs)try{if(!C5(f))continue;let w=await o(p,f.number).catch(()=>null);if(!w?.trackId||N5.has(w.state))continue;let{prev:m}=await s(p,f.number,{blocked:kR(f),sha:f.headSha??null,at:n});if(!m)continue;let g=P5(m,f);if(!g||D5(w,g.change))continue;u??=new Map((await a()).map(O=>[O.id,O]));let y=u.get(w.trackId);if(!y)continue;let x=f.headSha??null;if(await i(y,g.change,f.number,x,m.at||0))continue;let b={number:Number(f.number),url:f.url||w.url,title:f.title||w.title,branch:f.headRefName||w.headRef,repo:p,sha:x,delegated:!1,reason:g.reason};g.change==="ci-fixed"?b.passed=f.checks.passed:b.base=f.baseRefName||null,await c(y,g.change,b),l.push({change:g.change,number:f.number,reason:g.reason})}catch{}}return l}var Dy=F5(L5),_R=3e4,U5=30*6e4,H5=_R,W5=10*6e4,q5=10080*6e4,K5=60*6e4,G5=8,IR=1440*6e4,z5=3,$R="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",Py=60*6e4,V5=15*6e4,J5=9e4,Y5=1440*6e4,bp=new Map,kp=new Map,X5=/could not resolve|not found|no pull requests?/i,Z5=e=>X5.test(String(e?.message||e||""));function Q5(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<Py)}var xR={fast:H5,slow:W5,decay:K5};function vR(e,t,n=Cy){return RR(e,t,{grace:0})||!n(e.repo,t)&&(e.armedAt&&t-e.armedAt<U5||Q5(e,t))?"fast":t-(e.firstSeen||0)>q5?"decay":"slow"}function nl(e,t,n,r){let o=e.lanes?.get(ce(t.repo,t.number))||{};return Bu({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function eK(e,t){rr("watch");try{let{stdout:n}=await Dy("gh",["pr","view",String(t),"--repo",e,"--json",$R],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await vn({slug:e})}});return JSON.parse(n||"null")}catch(n){throw Yr(n)&&Xr(n),n}}async function tK(e){rr("watch");try{let{stdout:t}=await Dy("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",$R],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await vn({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw Yr(t)&&Xr(t),t}}async function nK(){let e=new Map;for(let t of await he().catch(()=>[]))e.set(t.id,t);return e}async function rK(e,t){await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}}),await Zu(e,t).catch(()=>{})}async function oK(e,t){let n=await Fo(e);return n?Qs(n,t):null}async function sK(e,t,n){let r=await Fo(e);if(!r)throw new Error(`no local checkout for ${e}`);return ea(r,t,{method:n})}async function aK(e,t){let n=await Fo(e);if(!n)throw new Error(`no local checkout for ${e}`);return Fi(n,t)}async function iK(e,t){await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"auto-canceled",...t}})}async function Oa(e,t,n,r,o){if(!await r.disarm(e.repo,e.number).catch(()=>null))return;let a=n.get(e.trackId);a&&await r.emitDisarmed(a,{number:Number(e.number),url:t?.url||e.url,title:t?.title||e.title,branch:t?.headRefName||e.headRef,repo:e.repo,reason:o}).catch(()=>{})}var cK=10*6e4;async function lK(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>IR){await Oa(e,null,t,n,"auto-merge expired \u2014 checks never settled within 24h");return}let o=await n.detail(e.repo,e.number).catch(()=>null);if(!o)return;if(o.checks.failed>0){let a=o.checks.failing.map(i=>i.name).join(", ");await Oa(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await Oa(e,o,t,n,`conflicts with ${o.baseRefName}`);return}if(!o.checks.total){let a=Math.max(e.autoMerge?.armedAt||0,Date.parse(o.updatedAt||"")||0);if((n.now??Date.now())-a<cK)return;await Oa(e,o,t,n,o.checks.unavailable?"this token can't read the checks":"no CI checks appeared");return}if(o.checks.pending>0||o.mergeable==="UNKNOWN"||o.mergeStateStatus==="UNKNOWN"||o.isDraft)return;let s=await n.lookup(e.repo,e.number).catch(()=>null);if(s?.autoMerge){if(o.mergeStateStatus==="BEHIND"){try{await n.updateBranch(e.repo,e.number)}catch(a){let i=String(a?.message||a).trim();/no new commits|already up.to.date/i.test(i)||await Oa(e,o,t,n,i||`couldn't update with ${o.baseRefName}`)}return}try{await n.merge(e.repo,e.number,s.autoMerge.method||"merge")}catch(a){if(/already merged|not open|is closed/i.test(String(a?.message||a)))return;await Oa(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await OR(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function Ma(e,t,n){await M({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function uK(e,t){try{return await Dy("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function tl(e,t,n,r=()=>!0){return(await q(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var Ca=(e,t)=>({number:Number(e.number),url:t?.url||e.url,title:t?.title||e.title,branch:t?.headRefName||e.headRef,repo:e.repo});function RR(e,t,{grace:n=J5}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=Y5}async function dK(e,t,n,r){let o=r.now??Date.now();if(!RR(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||De(s))return!1;let a=(s.boxes||[]).find(d=>d.name===s.leadBox);return await(r.midTurn??Ho)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await q(s).catch(()=>[])).some(d=>d.type==="pr.state.changed"&&d.payload?.number===Number(e.number))?(await(r.claim??tr)(e.repo,e.number).catch(()=>null),!1):await(r.claim??tr)(e.repo,e.number).catch(()=>null)?(await Ma(s,"opened",{...Ca(e,t),announcedBy:"watch"}).catch(()=>{}),console.log(`[pr-watch] announced passive link ${e.repo}#${e.number} \u2192 track ${s.id} (no active door claimed it)`),!0):!1}async function pK(e,t,n,r){let o=r.now??Date.now(),s=t.headRefOid||null,a=n.get(e.trackId)||null;if(s&&(e.ciFix?.headSha&&s!==e.ciFix.headSha&&await $u(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await Ou(e.repo,e.number,{headSha:s}).catch(()=>{})),s&&s!==e.lastHeadSha){let i=!e.lastHeadSha,c=!!(e.ciFix||e.reconcile||e.ciFixAwait||e.reconcileAwait),l=!!e.baseFoldAt&&o-e.baseFoldAt<V5;await kS(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await bS(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await tl(a,"pushed",e.number,d=>d.payload?.sha===s)&&await Ma(a,"pushed",{...Ca(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>Py)await Ru(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i?.checks){if(i.checks.failed>0)await Ru(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=nl(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await tl(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await Ma(a,"ci-fixed",{...Ca(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await Ru(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>Py)await Mu(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await Mu(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){nl(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await tl(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await Ma(a,"reconciled",{...Ca(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await Mu(e.repo,e.number).catch(()=>{})}}}}async function fK(e,t,n,r){let o=nl(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await tl(s,"closed",e.number)&&await Ma(s,"closed",{...Ca(e,t),githubAt:o.githubAt,latencyMs:o.latencyMs,lane:o.lane}).catch(()=>{}),await r.notifyIfResolved(e.repo,e.number,"closed").catch(()=>{}),await r.mark(e.repo,e.number,"closed").catch(()=>{})}async function mK(e,t,n){nl(n,e,"lost",null);let r=t.get(e.trackId);r&&!await tl(r,"lost",e.number)&&await Ma(r,"lost",Ca(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function OR(e,t,n,r,o={}){let s=nl(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await q(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 SR(e={}){let{now:t=Date.now(),auth:n=Zm,view:r=eK,list:o=tK,links:s=TS,trackMap:a=nK,emitMerged:i=rK,mark:c=Vr,archiveIfArmed:l=ar,notifyIfArmed:u=ir,notifyIfResolved:d=Cd,followupsIfMerged:p=Qo,batchThreshold:f=z5,detail:w=oK,merge:m=sK,updateBranch:g=aK,lookup:y=at,disarm:x=Di,emitDisarmed:b=iK,localHasCommit:O=uK,claim:I=tr,midTurn:C=Ho,only:U=null,wantDetail:H=null,covered:_=Cy,verdicts:$=null}=e;if(!(await n().catch(()=>null))?.authenticated||Pu()>0)return 0;let V=await s().catch(()=>[]),S=VS(V),E=z=>{try{return!!H?.(z)}catch{return!1}},P=U?V.filter(z=>{try{return U(z)}catch{return!1}}):V.filter(z=>t-(bp.get(ce(z.repo,z.number))||0)>=xR[vR(z,t,_)]);if(!P.length)return 0;let W=Date.now(),G=new Map,ae=new Map;for(let z of[...P].sort(Ui)){let se=U?"event":vR(z,t,_);G.set(ce(z.repo,z.number),{lane:se,intervalMs:xR[se]??null}),bp.set(ce(z.repo,z.number),t),ae.has(z.repo)||ae.set(z.repo,[]),ae.get(z.repo).push(z)}let we=await a().catch(()=>new Map),Re=new Map,Ae=(z,se)=>{let ve=ce(z,se);if(!Re.has(ve)){let Ne=Promise.resolve().then(()=>w(z,se));Ne.catch(()=>{}),Re.set(ve,Ne)}return Re.get(ve)},Y=$??((z,se)=>yp([{path:z,prs:[se]}],{now:t,slugOf:async()=>z,tracks:async()=>[...we.values()].filter(ve=>!De(ve))}).catch(()=>{})),ye={now:t,lanes:G,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,followupsIfMerged:p,detail:Ae,merge:m,updateBranch:g,lookup:y,disarm:x,emitDisarmed:b,localHasCommit:O,claim:I,midTurn:C};for(let[z,se]of ae){let ve,Ne=new Set,R=D=>D.ciFixAwait||D.reconcileAwait||E(D)?!0:!D.autoMerge||D.trackId&&S.get(D.trackId)!==ce(D.repo,D.number)?!1:t-(D.autoMerge.armedAt||0)<=IR;if(se.length>f)ve=await o(z).catch(()=>null);else{ve=new Map;for(let D of se){if(R(D)){let de=await Ae(z,D.number).catch(()=>null);if(de?.state){ve.set(Number(D.number),{number:Number(D.number),url:de.url,title:de.title,headRefName:de.headRefName,headRefOid:de.headSha??null,state:de.state,mergedAt:de.mergedAt??null,closedAt:de.closedAt??null});continue}}try{let de=await r(z,D.number);de?.number!=null&&ve.set(Number(de.number),de)}catch(de){Z5(de)&&Ne.add(ce(D.repo,D.number))}}}if(ve)for(let D of se){let de=ce(D.repo,D.number),Le=ve.get(Number(D.number));if(!Le){if(Ne.has(de)){let Ce=(kp.get(de)||0)+1;kp.set(de,Ce),Ce>=G5&&(await mK(D,we,ye),kp.delete(de),bp.delete(de))}continue}if(kp.delete(de),Le.state==="MERGED"||Le.state==="CLOSED")Le.state==="MERGED"?await OR(D,Le,we,ye):await fK(D,Le,we,ye),bp.delete(de);else{await dK(D,Le,we,ye).catch(()=>{}),await pK(D,Le,we,ye).catch(()=>{});let Ce=!D.trackId||S.get(D.trackId)===de;D.autoMerge&&Ce&&await lK(D,we,ye).catch(()=>{});try{if(E(D)&&!Re.has(de)&&Ae(D.repo,D.number),Re.has(de)){let Ht=await Re.get(de).catch(()=>null);Ht?.checks&&await Y(D.repo,Ht)}}catch{}}}}let J={};for(let{lane:z}of G.values())J[z]=(J[z]||0)+1;return console.log(`[pr-watch] probed ${P.length} link(s) (${Object.entries(J).map(([z,se])=>`${z} ${se}`).join(", ")}) in ${Date.now()-W}ms`),P.length}function TR(e,t){return!e||!t?!1:e.all?!0:String(t.repo||"").toLowerCase()!==e.repo?!1:e.numbers?.length?e.numbers.includes(Number(t.number)):e.event==="push"?!!e.branch&&t.headRef===e.branch||!!t.autoMerge:e.branch?t.headRef===e.branch:!0}var Ny=!1,xp=!1,vp=[],AR=Promise.resolve();async function hK(){for(;xp||vp.length;){if(xp){xp=!1;try{await SR()}catch{}continue}let e=vp;vp=[];let t=e.map(r=>r.spec),n=Object.assign({},...e.map(r=>r.deps||{}));try{await SR({...n,only:r=>t.some(o=>TR(o,r)),wantDetail:r=>t.some(o=>o.detail&&TR(o,r))})}catch{}}}function Sp(e,t){return e===null?xp=!0:vp.push({spec:e,deps:t}),Ny||(Ny=!0,AR=hK().finally(()=>{Ny=!1})),AR}function MR(e,t=void 0){let n=String(e?.repo||"").toLowerCase();if(!/^[^/\s]+\/[^/\s]+$/.test(n))return Promise.resolve();let r=(Array.isArray(e.numbers)?e.numbers:[]).map(Number).filter(o=>Number.isInteger(o)&&o>0);return Sp({repo:n,numbers:r,branch:e.branch||null,event:e.event||null,detail:e.detail===!0},t)}var wK=6e4,ER=0;function CR(e=void 0){let t=e?.now??Date.now();return t-ER<wK?Promise.resolve():(ER=t,Sp({all:!0},e))}function NR(){Sp(null),setInterval(()=>Sp(null),_R)}Uo();ed();ic();cr();Gt();var gK=new Set(["opened","reopened","closed","synchronize","ready_for_review","converted_to_draft","edited"]);async function yK({tracks:e=he,reconcile:t=pd}={}){for(let n of(await e().catch(()=>[])).filter(r=>!De(r)))await t(n,{bypassThrottle:!0}).catch(()=>{})}function PR(e,t={}){let{invalidate:n=Vt,probe:r=MR,poke:o=OT,reconcileOpened:s=yK}=t;try{n()}catch{}let a={probe:null,poked:!1,reconciled:!1};if(!e?.repo)return a;if(e.event==="pull_request"&&gK.has(e.action)){if(e.action==="opened"||e.action==="reopened"){a.poked=!0,a.reconciled=!0;try{o()}catch{}s()}a.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event}}else(e.event==="check_suite"||e.event==="workflow_run")&&e.action==="completed"?a.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event,detail:!0}:e.event==="push"&&!e.deleted&&(a.probe={repo:e.repo,branch:e.headRef||null,event:"push"});return a.probe&&r(a.probe),a}ct();pe();cr();Gt();import{randomUUID as bK}from"node:crypto";var kK=2e4,DR=3,Na=new Map,By=new Set;async function BR(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 xK(e={}){let{sessions:t=null,tracks:n=null,append:r=M,read:o=q,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await nn(),i=n??await he()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(De(u)||!u.leadBox)continue;let d=(u.boxes||[]).find(f=>f.name===u.leadBox);if(!d||d.agent!=="claude"||d.state!=="live")continue;let p=c.get(d.name);if(p)if(l.add(d.name),p.alternateOn){let f=(Na.get(d.name)||0)+1;Na.set(d.name,f),f===DR&&(By.add(d.name),await BR(u,d.name,o)||await r(u,{type:"box.fullscreen.detected",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:bK(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let f=(Na.get(d.name)||0)>=DR;if(Na.delete(d.name),f||!By.has(d.name)){By.add(d.name);let w=await BR(u,d.name,o);w&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:w,action:"cleared"}}).catch(()=>{})}}}for(let u of[...Na.keys()])l.has(u)||Na.delete(u)}var rl=null,jy=!1;function jR(){return rl?()=>{}:(rl=setInterval(()=>{jy||(jy=!0,xK().catch(()=>{}).finally(()=>{jy=!1}))},kK),rl.unref?.(),()=>{clearInterval(rl),rl=null})}Do();ic();pe();Uo();Wo();Do();Vi();import{randomUUID as vK}from"node:crypto";async function SK(){let e=await Promise.resolve().then(()=>(cr(),P_));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var Ly={listRepoPrs:On,readEvents:q,appendEvent:M,sayDeps:SK,currentBranch:Zr};async function TK(e,t=Ly,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??Zr)(e.workspace?.kind==="multi"?null:e.cwd).catch(()=>null)||e?.workspace?.branch;if(!r)return null;let o;try{o=await t.listRepoPrs(e.cwd,{caller:"pr-exists"})}catch{return null}let s=(o||[]).find(a=>a.headRefName===r);return s?{number:s.number,url:s.url??null,title:s.title??null}:null}async function Fy(e,t,{actions:n,notify:r=!1}={},o=Ly){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 TK(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=vK();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 Uy(e,{offerId:t,choice:n}={},r=Ly){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');return eo(`prx:${e.id}:${t}`,()=>AK(e,{offerId:t,choice:n},r))}async function AK(e,{offerId:t,choice:n},r){let o=await r.readEvents(e),s=o.find(u=>u.type==="pr.exists.offered"&&u.payload?.offerId===t);if(!s)throw new Error("unknown offer");if(o.some(u=>u.type==="pr.exists.answered"&&u.payload?.offerId===t))throw new Error("offer already answered");let a=s.payload||{},i=Array.isArray(a.actions)&&a.actions.length?a.actions:["commit","push","pr"],c=null,l=null;if(n==="push"){let{sayToLead:u}=await r.sayDeps();l=Gr.filter(d=>d!=="pr"&&(i.includes(d)||d==="push")),c=await u(e.id,Js(l,{branch:a.branch??null,base:a.base??null,toPr:{number:a.pr?.number??null},offeredRebase:a.offeredRebase===!0}),{kind:"push-go"})}else if(n==="new"){let{sayToLead:u}=await r.sayDeps();l=i,c=await u(e.id,cS(i,{branch:a.branch??null,base:a.base??null,prNumber:a.pr?.number??null,offeredRebase:a.offeredRebase===!0}),{kind:"pr-go"})}if(await r.appendEvent({id:e.id,cwd:e.cwd},{type:"pr.exists.answered",actor:"user",source:"orchestrator",boxId:s.boxId,payload:{ts:Date.now(),offerId:t,choice:n}}),n!=="dismiss"&&a.notify===!0){let{queueShipCompleteNotify:u}=await r.sayDeps();u(e.id,{actions:l})}return{say:c,choice:n}}Vi();import xr from"node:fs/promises";import Pa from"node:path";import KR from"node:os";import LR from"node:fs/promises";import Tp from"node:path";import{execFile as EK}from"node:child_process";import{promisify as _K}from"node:util";import{fileURLToPath as IK}from"node:url";var $K=_K(EK),UR=Tp.dirname(IK(import.meta.url)),RK=Tp.resolve(UR,"..","..","client","dist"),OK="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",MK=new Map([...OK].map((e,t)=>[e,t]));function CK(e){let t=[],n=0,r=0;for(let o of e){let s=MK.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 NK(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=CK(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 PK(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 FR=new Map;async function DK(e){let t;try{t=await LR.stat(e)}catch{return null}let n=FR.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await LR.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:NK(r.mappings||"")};return FR.set(e,o),o}catch{return null}}var Hy=null;function BK(){return Hy||(Hy=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):$K("git",["rev-parse","--short","HEAD"],{cwd:Tp.resolve(UR,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),Hy}var jK=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function LK(e,{distDir:t=RK}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(jK)){let[a,i,c,l]=s,u=await DK(Tp.join(t,"assets",`${i}.map`)),d=u?PK(u.lines[Number(c)-1],Number(l)-1):null;if(n.push(e.slice(r,s.index)),d&&u.sources[d[1]]){let p=u.sources[d[1]].replace(/^(\.\.\/)+/,"");n.push(`${p}:${d[2]+1}:${d[3]+1}`),o=!0}else n.push(a);r=s.index+a.length}return n.push(e.slice(r)),{stack:n.join(""),symbolicated:o}}async function HR(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await BK();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await LK(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var FK=()=>process.env.BOSTRAT_STATE_DIR||Pa.join(process.env.HOME||KR.tmpdir(),".bostrat"),bo=()=>Pa.join(FK(),"telemetry"),GR=()=>Pa.join(bo(),".relay-offsets.json"),UK=50,HK=14,WK=3e4,WR=500,Ft=(e,t)=>typeof e=="string"?e.slice(0,t):"";function qK(e,t){if(!e||typeof e!="object")return null;let n=Ft(e.name,64);if(!n)return null;let r=Number.isFinite(e.ts)?e.ts:t,o={name:n,ts:Math.abs(r-t)<168*3600*1e3?r:t,receivedAt:t,anonId:Ft(e.anonId,64),sessionId:Ft(e.sessionId,64),userId:Ft(e.userId,64),release:Ft(e.release,64),appVersion:Ft(e.appVersion,32),route:Ft(e.route,128),deviceClass:e.deviceClass==="phone"||e.deviceClass==="desktop"?e.deviceClass:""};return e.props&&typeof e.props=="object"&&!Array.isArray(e.props)&&(JSON.stringify(e.props).length<=8192?o.props=e.props:o.props={clamped:!0}),e.error&&typeof e.error=="object"&&(o.error={kind:Ft(e.error.kind,256),message:Ft(e.error.message,8192),stack:Ft(e.error.stack,32768),fingerprint:Ft(e.error.fingerprint,64)}),Array.isArray(e.breadcrumbs)&&(o.breadcrumbs=e.breadcrumbs.slice(-50).map(s=>({t:Number.isFinite(s?.t)?s.t:0,n:Ft(s?.n,64),r:Ft(s?.r,128)}))),o}var zR=e=>new Date(e).toISOString().slice(0,10),qR=0;async function VR(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,UK):[]).map(s=>qK(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await HR(s);await xr.mkdir(bo(),{recursive:!0});let o=Pa.join(bo(),`${zR(t)}.ndjson`);return await xr.appendFile(o,r.map(s=>JSON.stringify(s)+`
756
- `).join(""),"utf8"),t-qR>6*3600*1e3&&(qR=t,KK(t).catch(()=>{})),r.length}async function KK(e=Date.now()){let t=zR(e-HK*24*3600*1e3),n=[];try{n=await xr.readdir(bo())}catch{return}let r=n.filter(s=>s.endsWith(".ndjson")&&s.slice(0,10)<t);if(!r.length)return;for(let s of r)await xr.rm(Pa.join(bo(),s),{force:!0});let o=await YR();for(let s of r)delete o[s];await XR(o)}var Ap=new Map;function JR(e,t=Date.now()){let n=e||"unknown",r=Ap.get(n);return r||(Ap.size>512&&Ap.clear(),r={tokens:40,at:t},Ap.set(n,r)),r.tokens=Math.min(40,r.tokens+(t-r.at)/6e4*20),r.at=t,r.tokens<1?!1:(r.tokens-=1,!0)}async function YR(){try{return JSON.parse(await xr.readFile(GR(),"utf8"))||{}}catch{return{}}}async function XR(e){await xr.mkdir(bo(),{recursive:!0}),await xr.writeFile(GR(),JSON.stringify(e),"utf8")}function GK(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||KR.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 zK({fetchImpl:e=fetch}={}){let t=await yI();if(!t)return{sent:0,disabled:!0};let n;try{n=(await xr.readdir(bo())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await YR(),o=0;for(let s of n){let a=Pa.join(bo(),s),i=r[s]||0,c;try{let p=await xr.open(a,"r");try{let f=(await p.stat()).size;if(f<=i)continue;c=Buffer.alloc(f-i),await p.read(c,0,c.length,i)}finally{await p.close()}}catch{continue}let l=c.lastIndexOf(10);if(l<0)continue;let u=c.toString("utf8",0,l+1).split(`
757
- `).filter(Boolean),d=[];for(let p of u)try{d.push(JSON.parse(p))}catch{}for(let p=0;p<d.length;p+=WR){let f=d.slice(p,p+WR).map(m=>GK(m)),w=await e(`${t.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${t.ingestKey}`},body:JSON.stringify({events:f})}).catch(()=>null);if(!w||!w.ok)return{sent:o,disabled:!1};o+=f.length}r[s]=i+l+1,await XR(r)}return{sent:o,disabled:!1}}var Wy=null,qy=!1;function ZR(){Wy||(Wy=setInterval(async()=>{if(!qy){qy=!0;try{await zK()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{qy=!1}}},WK),Wy.unref?.())}import _p from"node:fs/promises";import rO from"node:path";import VK from"node:os";var oO=()=>process.env.BOSTRAT_STATE_DIR||rO.join(process.env.HOME||VK.tmpdir(),".bostrat"),sO=()=>rO.join(oO(),"dictation-glossary.json"),JK=100,YK=500,XK=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Ip=null,Ky=null,Gy=Promise.resolve();function QR(){let e={},t=Date.now();for(let n of XK)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function aO(){return Ip||(Ky??=_p.readFile(sO(),"utf8").then(e=>JSON.parse(e)?.terms??QR()).catch(()=>QR()).then(e=>Ip=e).finally(()=>Ky=null),Ky)}async function eO(){let e=JSON.stringify({terms:Ip},null,2),t=sO(),n=`${t}.${process.pid}.tmp`;await _p.mkdir(oO(),{recursive:!0}),await _p.writeFile(n,e),await _p.rename(n,t)}function ZK(){return Gy=Gy.then(eO,eO),Gy.catch(()=>{})}async function zy(){return Object.values(await aO()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var QK=e=>Math.max(1,Math.ceil(e.length/4));async function e6(){let e=[],t=0;for(let{term:n}of await zy()){let r=QK(n);if(!(t+r>YK)&&(e.push(n),t+=r,e.length>=JK))break}return e}async function t6(e,t){let n=await aO(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var tO=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),Ep=e=>e.toLowerCase();function nO(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function iO(e,t){let n=tO(e),r=tO(t);if(!n.length||!r.length)return[];let o=n.length,s=r.length,a=Array.from({length:o+1},()=>new Array(s+1).fill(0));for(let u=o-1;u>=0;u--)for(let d=s-1;d>=0;d--)a[u][d]=Ep(n[u])===Ep(r[d])?a[u+1][d+1]+1:Math.max(a[u+1][d],a[u][d+1]);let i=new Set,c=0,l=0;for(;c<o&&l<s;)Ep(n[c])===Ep(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(nO(r[l])&&i.add(r[l]),l++);for(;l<s;l++)nO(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await t6(u,"learned");return await ZK(),[...i]}var ol=null;function n6(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 cO(){if(!ol)return null;let e=await Lc();if(!e||e.apiKey.slice(-6)!==ol.keyTail)return null;let{keyTail:t,...n}=ol;return n}async function lO(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 e6())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=n6(o.status,i);c.persistent&&(ol={code:c.code,message:c.message,at:Date.now(),keyTail:n.apiKey.slice(-6)});let l=new Error(c.message);throw l.status=c.status,l.code=c.code,l}return ol=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}pe();var Vy={"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 r6(e){if(!e)return null;let t=String(e).trim();if(Vy[t])return t;let n=null;for(let r of Object.keys(Vy))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function o6(e,t={}){let n=Vy[r6(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 s6(e,t){let n=null;try{n=JSON.parse(t)}catch{}let r=n?.error?.code||n?.error?.type||"";return e===429&&/insufficient_quota/i.test(r)?{status:402,code:"credits_exhausted",persistent:!0,message:"The OpenAI account is out of credit \u2014 voice chat is down until you top up at platform.openai.com or drop a new key into ~/.bostrat/integrations.json."}:e===401||e===403?{status:502,code:"key_invalid",persistent:!0,message:"OpenAI rejected the API key (revoked, or missing Realtime access) \u2014 replace it in ~/.bostrat/integrations.json."}:{status:502,code:"mint_failed",persistent:!1,message:`OpenAI realtime session mint failed (${e}): ${t.slice(0,300)}`}}var sl=null;async function a6(){if(!sl)return null;let e=await Qd();if(!e||e.apiKey.slice(-6)!==sl.keyTail)return null;let{keyTail:t,...n}=sl;return n}async function i6(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=s6(t.status,o);s.persistent&&(sl={code:s.code,message:s.message,at:Date.now(),keyTail:e.apiKey.slice(-6)});let a=new Error(s.message);throw a.status=s.status,a.code=s.code,a}sl=null;let n=await t.json(),r=n?.value??n?.client_secret?.value;if(!r){let o=new Error("OpenAI returned no client secret");throw o.status=502,o.code="mint_failed",o}return{clientSecret:{value:r,expiresAt:n?.expires_at??n?.client_secret?.expires_at??null}}}var c6={openai:i6};async function uO(){let e=await Qd();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await a6()}:{configured:!1}}async function dO(){let e=await Qd();if(!e){let n=new Error("Voice chat is not configured \u2014 add openai.apiKey to ~/.bostrat/integrations.json");throw n.status=503,n.code="not_configured",n}let t=await c6[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function pO(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=o6(t,s),i=await M(e,{type:"cost.recorded",actor:"user",provider:"openai-realtime",payload:{model:t||"unknown",usd:a,tokens:{input:s.textIn+s.audioIn,output:s.textOut+s.audioOut,cacheRead:s.textInCached+s.audioInCached,cacheWrite:0},voice:s,seconds:Math.max(0,Math.round(Number(r)||0)),source:"voice-chat"}});return{usd:a,seq:i.seq}}Gt();var kO=Te.dirname(u6(import.meta.url)),fO=Number(process.env.PORT)||3362,Rp=Og(process.env),xO=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,Da=_$(process.env.BOSTRAT_ALLOW_IPS),Qy=I$(process.env.BOSTRAT_VIEW_FRONT_CIDRS,hp),eb=R$(),vO=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",T=Ut();T.disable("x-powered-by");T.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),mp(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});T.use((e,t,n)=>{if(Qc(e)||Da.allowed(Da.clientIp(e))||Qy.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});T.use(D$);T.use(C$({token:eb,enforce:vO}));T.use("/api/mocks",Ut.json({limit:"1mb"}));T.use("/api/mocks",Ut.raw({type:"image/png",limit:"24mb"}));T.use("/api/mocks",Ut.raw({type:["video/mp4","video/webm"],limit:"105mb"}));T.use("/api/runbooks",Ut.json({limit:"1mb"}));T.use("/api/tracks/adopt",Ut.json({limit:"1mb"}));T.use("/api/telemetry",Ut.json({limit:"256kb"}));T.use("/api/hook",Ut.json({limit:"2mb"}));T.use("/api/dictation",Ut.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));T.use("/api/tracks/:id/upload",Ut.raw({type:()=>!0,limit:"25mb"}));T.use(Ut.json({limit:"64kb"}));T.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:Ot,hostTmuxAlive:await Rr(),autoTriggerPct:xO,plane:Ba?Ba.status():null})});T.get("/api/sessions",async(e,t)=>{t.json({sessions:await nn()})});T.post("/api/sessions",async(e,t)=>{let{displayName:n,cwd:r}=e.body||{};if(typeof n!="string")return t.status(400).json({error:"displayName (string) required"});try{let o=await Or(n,r||void 0);t.json({ok:!0,...o})}catch(o){let s=o?.message||String(o),a=/already exists/i.test(s)?409:/must be|invalid/i.test(s)?400:500;t.status(a).json({error:s})}});T.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!je(n))return t.status(400).json({error:"invalid session name"});if(!await ke(n))return t.status(404).json({error:"session not found"});try{await rn(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});T.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!je(n))return t.status(400).json({error:"invalid session name"});let r=await ke(n);if(!r)return t.status(404).json({error:"session not found"});let o=await di(r.cwd,r.sessionId);if(!o)return t.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});t.json({available:!0,...o})});T.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!je(n))return t.status(400).json({error:"invalid session name"});try{let r=await vx(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)})}});T.get("/api/handoff/:name",(e,t)=>{let n=decodeURIComponent(e.params.name),r=cu(n);if(!r)return t.json({running:!1});t.json({running:!r.finishedAt,step:r.step,error:r.error,file:r.file,startedAt:r.startedAt,finishedAt:r.finishedAt})});var mO=10;async function SO(){let e=await he(),[t,n]=await Promise.all([H_(e),q_(e)]);return{tracks:e,views:await Yh(),queuedOf:r=>Xo(r),jobsOf:r=>t.get(r)??[],prPendingOf:r=>n.get(r)??[]}}T.get("/api/idle-guard",async(e,t)=>{try{t.json(_g(await SO()))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var en=ts(),w6=oI({kind:en}),al=null,vt=()=>al&&["auto","prompt","off"].includes(al)?al:w6,Zy=null,g6=Bc.has(en),TO=async({to:e,from:t})=>!g6||Gd(await jc())?!1:(cl.arm({to:e,from:t,kind:en}),!0);async function y6(e){let t=vt();al=e??null;let n=vt();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){cl.cancel();return}Zy&&await TO(Zy)}}var AO=(()=>{try{return h6(import.meta.url)("../package.json").version||null}catch{return null}})(),cl=aI({isBusy:async()=>_g(await SO()).busy,onStuck:({to:e,from:t})=>Wn({current:t,latest:e,installKind:en,policy:vt(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?Wn({current:t,latest:e,installKind:en,policy:vt(),status:"updating",reason:"auto"}):Wn({current:t,latest:e,installKind:en,policy:vt(),status:"failed",error:n?.reason})).catch(()=>{})});T.get("/api/node/self-update",async(e,t)=>{t.json({installKind:en,policy:vt(),policySource:al?"plane":"node",current:AO,status:await jc(),armed:cl.armed})});T.post("/api/node/self-update",async(e,t)=>{let n=typeof e.body?.to=="string"?e.body.to.trim():"";if(!/^\d+\.\d+\.\d+$/.test(n))return t.status(400).json({error:"body.to must be a release version (X.Y.Z)"});let r=await zd({to:n,kind:en,reason:"manual"});if(r.ok)return cl.cancel(),Wn({current:r.from,latest:n,installKind:en,policy:vt(),status:"updating",reason:"manual"}).catch(()=>{}),t.json({ok:!0,...r});t.status(409).json({ok:!1,error:r.reason,status:r.status??null})});async function EO(){try{let e=await sI();e&&await Wn({current:e.from,latest:e.to,installKind:e.kind||en,policy:vt(),status:e.status,error:e.error,reason:e.reason}),await Ww({current:AO,installKind:en,policy:vt()})}catch{}}EO();setInterval(EO,3e4).unref();T.get("/api/tracks",async(e,t)=>{let n=(await he()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>mO){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,mO).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:Ac,agentAvailability:await _d(),tickets:await MI()})});T.get("/api/cost",async(e,t)=>{try{let n=await he();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await py(n);if(r.cursorUsage=Nh(),e.query.format==="text")return t.type("text/plain").send(r$(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.get("/api/usage/roundup",async(e,t)=>{try{let n=await my(await he(),{window:e.query.window,from:e.query.from,to:e.query.to});if(e.query.format==="text")return t.type("text/plain").send(c$(n));t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.get("/api/usage/spend",async(e,t)=>{try{let n=await f$(await he(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=Nh(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=Ci(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.get("/api/usage/caps",(e,t)=>{t.json(Ci())});T.post("/api/usage/caps",async(e,t)=>{try{t.json(await xu(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});T.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await v$(await he(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await fb(e.get(Vn),{byToken:_c,legacy:()=>Xi(e.body?.session_id,e.body?.cwd)});if(n==="refused")return Wa("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Wa("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&&Wa("mismatch",{track:r.track.id,box:r.box.name}),Wa(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 e$(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&_l(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});T.get("/api/git/trailers",async(e,t)=>{t.type("text/plain");try{let n=await _c(e.get(Vn));if(!n?.track||!n?.box)return t.status(204).end();t.send((await hT(n.track,n.box)).join(`
758
+ `),n?.length&&a.write(n),t.pipe(a),a.pipe(t)}),i=()=>{a.destroy(),t.destroy()};return a.on("error",i),t.on("error",i),!0}function kR(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}.${L5(n.host)}/`}function L5(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 Gp(t)&&Ow(n[0])?n.slice(1).join("."):t}Ea();Kw();Fd();nw();he();import xR from"node:os";import{randomUUID as rb}from"node:crypto";var F5=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||xR.hostname(),nodeName:e.BOSTRAT_NODE_NAME||xR.hostname()});var vR=32768,SR=120,AR=1e3,TR=new Set(["claude","codex","cursor"]),U5=new Set(["off","transition","nag"]),H5=[[0,59],[0,23],[1,31],[1,12],[0,6]];function W5(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=H5[r];return String(n).split(",").every(a=>{if(!a)return!1;let[i,c]=a.split("/");if(c!==void 0&&!(Number.isInteger(Number(c))&&Number(c)>=1))return!1;if(i==="*")return!0;let[l,u]=i.includes("-")?i.split("-").map(Number):[Number(i),Number(i)];return Number.isInteger(l)&&Number.isInteger(u)&&l>=o&&u<=s&&l<=u})})}var xn=e=>String(e??"").trim(),Is={name(e){let t=xn(e);if(!t)throw new Error("a loop needs a name");if(t.length>SR)throw new Error(`name is too long (${t.length}); cap is ${SR}`);return t},schedule(e){let t=xn(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!W5(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=xn(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>vR)throw new Error(`prompt is too long (${t.length} chars); cap is ${vR}`);return t},expectation(e){let t=xn(e)||null;if(t&&t.length>AR)throw new Error(`expectation is too long (${t.length}); cap is ${AR}`);return t},notify(e){let t=xn(e)||"off";if(!U5.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=xn(typeof t=="string"?t:t?.provider)||"claude";if(!TR.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...TR].join(", ")}`);let r=typeof t=="object"&&t&&xn(t.model)||null;return r?{provider:n,model:r}:{provider:n}},enabled(e){if(typeof e=="boolean")return e;if(e==="true"||e==="false")return e==="true";throw new Error(`enabled must be true or false, got "${e}"`)}};function q5(e,t){let n=e&&typeof e=="object"?e:{},r=Is.name(n.name),o=Is.schedule(n.schedule),s=Is.prompt(n.prompt),a=Is.expectation(n.expectation),i=Is.notify(n.notify),c=Is.assignment(n.assignment),l=xn(t?.workspace?.repo)||xn(t?.workspace?.base)||null;if(!l)throw new Error("this Track isn't based on a repo, so there's nothing for a loop to run in \u2014 propose from a repo-backed Track");let{nodeId:u,nodeName:d}=F5();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:d||null}}async function _R(e,t){let n=q5(t,e),r=rb();return await C({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 IR(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await K({id:e.id,cwd:e.cwd}),a=s.find(c=>c.type==="loop.create.offered"&&c.payload?.proposalId===t);if(!a)throw new Error("unknown proposal");if(s.some(c=>c.type==="loop.create.answered"&&c.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await C({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 C({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 C({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 nb=["name","schedule","prompt","expectation","notify","assignment","enabled"],K5=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function $R(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 RR(e,t){let n=xn(t);if(!n)throw new Error("which loop? give an id or a name \u2014 see `bostrat-loop ls`");let r=e.find(a=>a.id===n)||e.find(a=>a.name===n);if(r)return r;let o=n.toLowerCase(),s=e.filter(a=>String(a.id).toLowerCase().startsWith(o)||String(a.name).toLowerCase().startsWith(o));if(s.length===1)return s[0];throw s.length>1?new Error(`"${n}" matches ${s.length} loops: ${s.map(a=>`${a.name} (${a.id})`).join(", ")} \u2014 use the id`):new Error(`no loop matching "${n}" \u2014 use \`bostrat-loop ls\``)}function G5(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=>!nb.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: ${nb.join(", ")}`)}let o={};for(let a of nb){if(!(a in n))continue;let i=Is[a](n[a]);(a==="assignment"?K5(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 OR(e,t,n){let r=$R(t),{patch:o,changed:s}=G5(n,r),a=rb(),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 C({id:e.id,cwd:e.cwd},{type:"loop.update.offered",actor:"system",source:"orchestrator",payload:i}),i}var ER=600;async function MR(e,t,n){let r=xn(n);if(!r)throw new Error('a delete proposal needs a reason \u2014 bostrat-loop propose-delete <loop> --reason "<why this loop should go>"');if(r.length>ER)throw new Error(`reason is too long (${r.length}); cap is ${ER}`);let o=$R(t),s=rb(),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 C({id:e.id,cwd:e.cwd},{type:"loop.delete.offered",actor:"system",source:"orchestrator",payload:a}),a}var CR=async(e,t,n)=>{if(!n)throw new Error("proposalId required");let r=await K({id:e.id,cwd:e.cwd}),o=r.find(a=>a.type===t&&a.payload?.proposalId===n);if(!o)throw new Error("unknown proposal");let s=t.replace(".offered",".answered");if(r.some(a=>a.type===s&&a.payload?.proposalId===n))throw new Error("proposal already answered");return o};async function NR(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 CR(e,"loop.update.offered",t)).payload,a={id:e.id,cwd:e.cwd};return n==="applied"&&await C(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 C(a,{type:"loop.update.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,loopId:s.loopId}}),{proposalId:t,action:n,loopId:s.loopId}}async function PR(e,t,n){if(!["delete","pause","keep","moved"].includes(n))throw new Error("action must be one of delete | pause | keep | moved");let o=(await CR(e,"loop.delete.offered",t)).payload,s={id:e.id,cwd:e.cwd};return(n==="delete"||n==="pause")&&await C(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 C(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}}he();import{randomUUID as z5}from"node:crypto";var ab=20,V5=300,ob=120,DR=120,BR=2e3,Vp=new Set(["build","ops","debt","spike"]),jR=new Set(["active","done","abandoned"]),ib=new Set(["circuit.create","circuit.update","circuit.delete"]),J5=new Set(["person.create","slot.create","slot.update","slot.delete","reservation.create","reservation.update","reservation.delete"]),wl=new Set([...ib,...J5]),Y5=["name","description","status","type"],X5=["person","startDate","endDate","estUsd"],Z5=["person","label","startDate","endDate"],Q5=/^\d{4}-\d{2}-\d{2}$/,Kt=e=>String(e??"").trim(),cb=e=>typeof e=="string"&&e.startsWith("@"),UR=864e5;function HR(e){let t=Date.parse(`${e}T00:00:00Z`),n=new Date(t).getUTCDay();return new Date(t-(n+6)%7*UR).toISOString().slice(0,10)}function e6(e){return new Date(Date.parse(`${HR(e)}T00:00:00Z`)+6*UR).toISOString().slice(0,10)}var LR=(e,t)=>{let n=Kt(e);if(!Q5.test(n))throw new Error(`${t} must be YYYY-MM-DD, got "${e??""}"`);if(!Number.isFinite(Date.parse(`${n}T00:00:00Z`)))throw new Error(`${t} "${n}" is not a real date`);return n};function t6(e,t){let n=LR(e,"startDate"),r=LR(t,"endDate");if(r<n)throw new Error(`endDate ${r} is before startDate ${n}`);let o=HR(n),s=e6(r);return{startDate:o,endDate:s,snapped:o!==n||s!==r}}var FR=e=>{if(e==null||e==="")return null;let t=Number(e);if(!Number.isFinite(t)||t<0)throw new Error(`estUsd must be a non-negative number, got "${e}"`);return t},Eo=(e,t,n)=>{let r=Kt(e);if(r.length>t)throw new Error(`${n} is too long (${r.length}); cap is ${t}`);return r};function sb(e,t){let n=Kt(t);if(!n)throw new Error("a circuit name or id is required");if(cb(n))return{ref:n,id:null,name:n.slice(1)};let r=e.find(i=>i.id===n);if(r)return r;let o=n.toLowerCase(),s=e.filter(i=>String(i.name).toLowerCase()===o);if(s.length===1)return s[0];if(s.length>1)throw new Error(`"${n}" names ${s.length} circuits \u2014 use an id (bostrat-circuit ls)`);let a=e.filter(i=>String(i.name).toLowerCase().includes(o)).slice(0,5);throw new Error(a.length?`no circuit named "${n}" \u2014 near matches: ${a.map(i=>`${i.name} (${i.id})`).join(", ")}`:`no circuit named "${n}" \u2014 propose a circuit.create op if it should exist (bostrat-circuit ls lists yours)`)}function n6(e,t){let n=Kt(t);if(!n)throw new Error('a person is required \u2014 "me", a person id, or a row label');if(n==="me"||cb(n))return{ref:n,id:null,label:n==="me"?"you":n.slice(1)};let r=e.find(a=>a.personId===n);if(r)return{...r,id:r.personId};let o=n.toLowerCase(),s=e.filter(a=>String(a.label).toLowerCase()===o);if(s.length===1)return{...s[0],id:s[0].personId};throw s.length>1?new Error(`"${n}" names ${s.length} roadmap rows \u2014 use a person id`):new Error(e.length?`no roadmap row for "${n}" \u2014 rows: ${e.map(a=>`${a.label} (${a.personId})`).join(", ")}, or propose a person.create op`:`no roadmap rows yet \u2014 use "me", or propose a person.create op for "${n}"`)}function r6(e,t,{allow:n=wl}={}){let r=e&&typeof e=="object"&&!Array.isArray(e)?e:null;if(!r)throw new Error("a plan must be a JSON object with an `ops` array");let o=Array.isArray(r.ops)?r.ops:null;if(!o?.length)throw new Error("a plan needs at least one op in `ops`");if(o.length>ab)throw new Error(`too many ops (${o.length}); cap is ${ab} \u2014 propose one intent at a time`);let s=Array.isArray(t?.circuits)?t.circuits:[],a=Array.isArray(t?.people)?t.people:[],i=Array.isArray(t?.slots)?t.slots:[],c=Array.isArray(t?.reservations)?t.reservations:[],l={circuits:{},slots:{},reservations:{}},u={},d=new Set,p=!1,f=!1,w=b=>{b.id&&(l.circuits[b.id]={name:b.name,status:b.status,type:b.type??"build",updatedAt:b.updatedAt??null},u[b.id]=b.name)},h=b=>{b.id&&(u[b.id]=b.label)},g=(b,I)=>{let _=Kt(b);if(!_)return null;if(d.has(_))throw new Error(`ref "${_}" is used by two ops \u2014 each ref names one thing`);return d.add(_),u[`@${_}`]=I,_},y=o.map((b,I)=>{let _=b&&typeof b=="object"?b:{},N=Kt(_.op),U=`op ${I+1}`;if(!wl.has(N))throw new Error(`${U}: unknown op "${N}" \u2014 one of ${[...wl].join(", ")}`);if(!n.has(N))throw new Error(`${U}: "${N}" isn't a circuit op \u2014 roadmap changes go through \`bostrat-roadmap propose\` (one card, either CLI)`);let j=O=>{throw new Error(`${U} (${N}): ${O}`)},T=O=>{let S=_.set&&typeof _.set=="object"&&!Array.isArray(_.set)?_.set:null;S||j("needs a `set` object naming the fields to change");let M=Object.keys(S).filter(H=>!O.includes(H));return M.length&&j(`unknown field(s) ${M.join(", ")} \u2014 settable: ${O.join(", ")}`),Object.keys(S).length||j("`set` names no fields"),S},R=O=>{let{startDate:S,endDate:M,snapped:H}=t6(O.startDate,O.endDate);return H&&(p=!0),{startDate:S,endDate:M,snapped:H}},L=O=>{let S=n6(a,O);return Kt(O)==="me"&&(f=!0),h(S),{key:S.id??Kt(O),label:S.label}},V=(O,S,M,H,W)=>{let te=Kt(O);te||j(`needs a ${H} id`);let pe=S.find(Ie=>Ie[M]===te);return pe||j(`no ${H} "${te}" \u2014 see \`bostrat-roadmap ls\``),W[te]={...pe},pe};switch(N){case"circuit.create":{let O=Eo(_.name,DR,"name");O||j("a circuit needs a name");let S=Kt(_.type)||"build";Vp.has(S)||j(`bad type "${S}" (${[...Vp].join(" | ")})`);let M=s.find(W=>String(W.name).toLowerCase()===O.toLowerCase());M&&j(`a circuit named "${M.name}" already exists (${M.id}) \u2014 update it instead of making a twin`);let H=g(_.ref,O);return{op:N,...H?{ref:H}:{},name:O,description:Eo(_.description,BR,"description"),type:S}}case"circuit.update":{let O=sb(s,_.circuit);O.id||j("can't update a circuit created in the same plan \u2014 set its fields on the create op"),w(O);let S=T(Y5),M={};if(S.name!==void 0){let H=Eo(S.name,DR,"name");H||j("name can't be blank"),H!==O.name&&(M.name=H)}return S.description!==void 0&&(M.description=Eo(S.description,BR,"description")),S.status!==void 0&&(jR.has(S.status)||j(`bad status "${S.status}" (${[...jR].join(" | ")})`),S.status!==O.status&&(M.status=S.status)),S.type!==void 0&&(Vp.has(S.type)||j(`bad type "${S.type}" (${[...Vp].join(" | ")})`),S.type!==(O.type??"build")&&(M.type=S.type)),Object.keys(M).length||j("nothing would change \u2014 the set equals the circuit's current values"),{op:N,circuit:O.id,name:O.name,set:M}}case"circuit.delete":{let O=sb(s,_.circuit);O.id||j("can't delete a circuit created in the same plan"),w(O);let S=o.some((M,H)=>H<I&&Kt(M?.op)==="circuit.update"&&M?.set?.status&&M.set.status!=="active"&&Kt(M?.circuit)===Kt(_.circuit));return O.status==="active"&&!S&&j(`\u201C${O.name}\u201D is active \u2014 an active circuit can't be deleted; propose a circuit.update to done/abandoned first (both can ride one card)`),{op:N,circuit:O.id,name:O.name,status:O.status}}case"person.create":{let O=Eo(_.label,ob,"label");O||j("a person row needs a label");let S=a.find(H=>String(H.label).toLowerCase()===O.toLowerCase());S&&j(`a roadmap row labelled "${S.label}" already exists (${S.personId})`);let M=g(_.ref,O);return{op:N,...M?{ref:M}:{},label:O}}case"slot.create":{let O=sb(s,_.circuit);w(O);let S=L(_.person),M=R(_);return{op:N,circuit:O.id??O.ref,circuitName:O.name,person:S.key,personLabel:S.label,...M,estUsd:FR(_.estUsd)}}case"slot.update":{let O=V(_.slot,i,"slotId","slot",l.slots),S=T(X5),M={};if(S.person!==void 0){let W=L(S.person);M.person=W.key,M.personLabel=W.label}if(S.startDate!==void 0||S.endDate!==void 0){let W=R({startDate:S.startDate??O.startDate,endDate:S.endDate??O.endDate});W.startDate!==O.startDate&&(M.startDate=W.startDate),W.endDate!==O.endDate&&(M.endDate=W.endDate)}S.estUsd!==void 0&&(M.estUsd=FR(S.estUsd)),Object.keys(M).length||j("nothing would change");let H=s.find(W=>W.id===O.circuitId);return{op:N,slot:O.slotId,circuitName:H?.name??null,set:M}}case"slot.delete":{let O=V(_.slot,i,"slotId","slot",l.slots),S=s.find(M=>M.id===O.circuitId);return{op:N,slot:O.slotId,circuitName:S?.name??null,startDate:O.startDate,endDate:O.endDate}}case"reservation.create":{let O=L(_.person),S=Eo(_.label,ob,"label");return S||j("a reservation needs a label (Leave, Support rotation, \u2026)"),{op:N,person:O.key,personLabel:O.label,label:S,...R(_)}}case"reservation.update":{let O=V(_.reservation,c,"reservationId","reservation",l.reservations),S=T(Z5),M={};if(S.person!==void 0){let H=L(S.person);M.person=H.key,M.personLabel=H.label}if(S.label!==void 0){let H=Eo(S.label,ob,"label");H||j("label can't be blank"),H!==O.label&&(M.label=H)}if(S.startDate!==void 0||S.endDate!==void 0){let H=R({startDate:S.startDate??O.startDate,endDate:S.endDate??O.endDate});H.startDate!==O.startDate&&(M.startDate=H.startDate),H.endDate!==O.endDate&&(M.endDate=H.endDate)}return Object.keys(M).length||j("nothing would change"),{op:N,reservation:O.reservationId,label:O.label,set:M}}case"reservation.delete":{let O=V(_.reservation,c,"reservationId","reservation",l.reservations);return{op:N,reservation:O.reservationId,label:O.label,startDate:O.startDate,endDate:O.endDate}}default:return j("unhandled op")}});y.forEach((b,I)=>{for(let _ of[b.circuit,b.person,b.set?.person])if(cb(_)&&!d.has(String(_).slice(1)))throw new Error(`op ${I+1} (${b.op}): unknown ref "${_}" \u2014 no earlier op in this plan creates it`)});let x=a.some(b=>b.kind==="user"&&b.userId);return{why:Eo(r.why,V5,"why"),ops:y,base:l,resolved:u,snapped:p,createsMeRow:f&&!x}}async function WR(e,t,n,r={}){let o=r6(t,n,r),s=z5(),a={ts:Date.now(),proposalId:s,...o};return await C({id:e.id,cwd:e.cwd},{type:"planning.change.offered",actor:"system",source:"orchestrator",payload:a}),a}var o6=async(e,t)=>{if(!t)throw new Error("proposalId required");let n=await K({id:e.id,cwd:e.cwd}),r=n.find(o=>o.type==="planning.change.offered"&&o.payload?.proposalId===t);if(!r)throw new Error("unknown proposal");if(n.some(o=>o.type==="planning.change.answered"&&o.payload?.proposalId===t))throw new Error("proposal already answered");return r};async function qR(e,t,n,{results:r=[]}={}){if(!["applied","dismiss","moved"].includes(n))throw new Error("action must be one of applied | dismiss | moved");let o=await o6(e,t),s={id:e.id,cwd:e.cwd},a=o.payload;return n==="applied"&&await C(s,{type:"planning.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,why:a.why??"",results:Array.isArray(r)?r.slice(0,ab+1):[]}}),await C(s,{type:"planning.change.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,action:n,ops:a.ops?.length??0}}),{proposalId:t,action:n}}Ed();he();Dr();he();Mn();Fd();var KR=10,GR=200,s6=120,a6=24,VR=/^\d{4}-\d{2}-\d{2}$/;function lb(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var i6=(e=Date.now())=>new Date(e).toISOString().slice(0,10),bt=(e,t="i")=>new RegExp(e,t),c6=[{re:bt("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:bt("\\bSPC\\b",""),reason:"business (SPC)"},{re:bt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:bt("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:bt("\\bReplicas\\b",""),reason:"competitor research"},{re:bt("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:bt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:bt("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],l6=[bt("\\bSPC\\b",""),bt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),bt("competitor|cloudcli|\\bkiro\\b"),bt("\\bReplicas\\b",""),bt("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),bt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),bt("(^|[^\\w&])#\\d+\\b"),bt("\\btrack/[\\w.-]+")];function u6({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of c6)if(o.test(n)||o.test(r))return s;return null}function zR(e){let t=String(e||"");for(let n of l6){let r=n.exec(t);if(r)return r[0].trim()}return null}function JR(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 d6=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function p6(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Ic(e);if(t.length)throw new Error(`changelog entry appears to contain a secret VALUE (${t.join(", ")}) \u2014 entries ship off-box; never put a credential in one. Replace it and retry.`);let n=null,r=[];for(let o of e.split(`
759
+ `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,s6)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${a6}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=d6.exec(i);if(!u||!u[1].trim()||!u[2].trim())throw new Error(`bullet ${r.length+1} must be \`**Short summary** \u2014 the item, one sentence.\` (bold summary title, em dash, then the change) \u2014 got "${i.slice(0,80)}". Rewrite it and re-publish.`);i=`**${u[1].trim().replace(/[:.]\s*$/,"")}** \u2014 ${u[2].trim()}`;let d=zR(i);if(d)throw new Error(`bullet ${r.length+1} mentions "${d}" \u2014 the product changelog never carries business, security/tenancy or internal-ops items, PR numbers, branch names or codenames; drop the bullet or rewrite it as the user-visible change and re-publish.`);if(i.length>GR)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${GR}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=zR(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>KR)throw new Error(`${r.length} bullets \u2014 over the ${KR}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function f6(e,{repos:t=lb()}={}){let n=new Set(t);return(await pn()).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:u6({title:r.title,headRef:r.headRef})}))}async function YR(e,t){let n=await f6(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function XR(e,{md:t,day:n=null}){let r=p6(t),o=n==null||n===""?i6():String(n);if(!VR.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await C({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 ZR(e,{day:t}){let n=String(t||"");if(!VR.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await C({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}}rs();Mn();ss();he();rs();mt();dr();Mn();ec();xd();ad();ac();Yt();import{execFile as T6}from"node:child_process";import{promisify as E6}from"node:util";var h6=new Set(["pull_request","check_suite","workflow_run","push"]),m6=/^[^/\s]+\/[^/\s]+$/,w6=500,ub=new Set,db=[],Jp=new Map,nn={hourStart:0,byEvent:{},duplicates:0,rejected:0};function pb(e,t,n){let r=Math.floor(e/36e5)*36e5;r!==nn.hourStart&&(nn.hourStart=r,nn.byEvent={},nn.duplicates=0,nn.rejected=0),t==="accepted"?nn.byEvent[n]=(nn.byEvent[n]||0)+1:nn[t]+=1}function g6(e){if(!e||typeof e!="object"||e.forge!=="github"||typeof e.event!="string"||!h6.has(e.event)||typeof e.repo!="string"||!m6.test(e.repo))return null;let t=(Array.isArray(e.numbers)?e.numbers:[]).map(Number).filter(r=>Number.isInteger(r)&&r>0),n=Number.isInteger(e.number)&&e.number>0?e.number:t[0]??null;return{forge:"github",deliveryId:typeof e.deliveryId=="string"&&e.deliveryId?e.deliveryId.slice(0,128):null,event:e.event,action:typeof e.action=="string"?e.action.slice(0,64):null,repo:e.repo,number:n,numbers:n&&!t.includes(n)?[n,...t]:t,headSha:typeof e.headSha=="string"?e.headSha.slice(0,64):null,headRef:typeof e.headRef=="string"?e.headRef.slice(0,256):null,baseRef:typeof e.baseRef=="string"?e.baseRef.slice(0,256):null,merged:typeof e.merged=="boolean"?e.merged:null,draft:typeof e.draft=="boolean"?e.draft:null,conclusion:typeof e.conclusion=="string"?e.conclusion.slice(0,64):null,deleted:e.deleted===!0,senderLogin:typeof e.senderLogin=="string"?e.senderLogin.slice(0,128):null,ts:Number.isFinite(e.ts)?e.ts:null}}function QR(e,{now:t=Date.now(),onAccept:n=null,log:r=console}={}){let o=g6(e);if(!o)return pb(t,"rejected"),{ok:!1,error:"malformed github event envelope"};if(o.deliveryId){if(ub.has(o.deliveryId))return pb(t,"duplicates"),{ok:!0,duplicate:!0,envelope:o};for(ub.add(o.deliveryId),db.push(o.deliveryId);db.length>w6;)ub.delete(db.shift())}let s=o.repo.toLowerCase(),a=Jp.get(s)||{lastDeliveryAt:0,count:0};a.lastDeliveryAt=t,a.count+=1,Jp.set(s,a),pb(t,"accepted",o.event),r.log?.(`[github-event] ${o.event}${o.action?` ${o.action}`:""} ${o.repo}${o.number?` #${o.number}`:o.headRef?` ${o.headRef}`:""}${o.conclusion?` (${o.conclusion})`:""}${o.deliveryId?` delivery ${o.deliveryId.slice(0,8)}`:""}`);try{n?.(o)}catch(i){r.error?.("[github-event] onAccept failed:",i?.message||i)}return{ok:!0,duplicate:!1,envelope:o}}function y6(e,t=Date.now()){let n=Jp.get(String(e||"").toLowerCase());return n?{covered:!0,lastDeliveryAt:n.lastDeliveryAt,ageMs:t-n.lastDeliveryAt,count:n.count}:{covered:!1,lastDeliveryAt:null,ageMs:null,count:0}}var eO=1440*6e4;function fb(e,t=Date.now()){let n=y6(e,t);return n.covered&&n.ageMs<eO}function tO(e=Date.now()){let t={};for(let[n,r]of Jp)t[n]={lastDeliveryAt:r.lastDeliveryAt,count:r.count,covered:e-r.lastDeliveryAt<eO};return{hourStart:nn.hourStart,byEvent:{...nn.byEvent},duplicates:nn.duplicates,rejected:nn.rejected,repos:t}}he();Mn();Or();dr();Yt();function nO(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function b6(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var k6=new Set(["merged","closed","lost"]);function x6(e,t){if(!e?.blocked)return null;let n=nO(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 v6(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function S6(e,t,n,r,o){return(await K(e).catch(()=>[])).some(a=>{if(a.type!=="pr.state.changed"||a.payload?.number!==Number(n))return!1;let i=a.payload?.change;return i===t?a.payload?.sha&&r?a.payload.sha===r:(a.payload?.ts||0)>=o:i==="pushed"&&!!r&&a.payload?.sha===r})}async function A6(e,t,n){await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function Yp(e,t={}){let{now:n=Date.now(),slugOf:r=_e,lookup:o=ct,note:s=sA,tracks:a=async()=>(await we()).filter(d=>!je(d)),asked:i=S6,emitChange:c=A6}=t,l=[],u=null;for(let d of e??[]){if(!d?.prs?.length)continue;let p=await r(d.path).catch(()=>null);if(p)for(let f of d.prs)try{if(!b6(f))continue;let w=await o(p,f.number).catch(()=>null);if(!w?.trackId||k6.has(w.state))continue;let{prev:h}=await s(p,f.number,{blocked:nO(f),sha:f.headSha??null,at:n});if(!h)continue;let g=x6(h,f);if(!g||v6(w,g.change))continue;u??=new Map((await a()).map(I=>[I.id,I]));let y=u.get(w.trackId);if(!y)continue;let x=f.headSha??null;if(await i(y,g.change,f.number,x,h.at||0))continue;let b={number:Number(f.number),url:f.url||w.url,title:f.title||w.title,branch:f.headRefName||w.headRef,repo:p,sha:x,delegated:!1,reason:g.reason};g.change==="ci-fixed"?b.passed=f.checks.passed:b.base=f.baseRefName||null,await c(y,g.change,b),l.push({change:g.change,number:f.number,reason:g.reason})}catch{}}return l}var wb=E6(T6),lO=3e4,_6=30*6e4,I6=lO,$6=10*6e4,R6=10080*6e4,O6=60*6e4,M6=8,uO=1440*6e4,C6=3,dO="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",mb=60*6e4,N6=15*6e4,P6=9e4,D6=1440*6e4,Xp=new Map,Zp=new Map,B6=/could not resolve|not found|no pull requests?/i,j6=e=>B6.test(String(e?.message||e||""));function L6(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<mb)}var rO={fast:I6,slow:$6,decay:O6};function oO(e,t,n=fb){return pO(e,t,{grace:0})||!n(e.repo,t)&&(e.armedAt&&t-e.armedAt<_6||L6(e,t))?"fast":t-(e.firstSeen||0)>R6?"decay":"slow"}function yl(e,t,n,r){let o=e.lanes?.get(ce(t.repo,t.number))||{};return sd({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function F6(e,t){ar("watch");try{let{stdout:n}=await wb("gh",["pr","view",String(t),"--repo",e,"--json",dO],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await Sn({slug:e})}});return JSON.parse(n||"null")}catch(n){throw oo(n)&&so(n),n}}async function U6(e){ar("watch");try{let{stdout:t}=await wb("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",dO],{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 oo(t)&&so(t),t}}async function H6(){let e=new Map;for(let t of await we().catch(()=>[]))e.set(t.id,t);return e}async function W6(e,t){await C({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}}),await kd(e,t).catch(()=>{})}async function q6(e,t){let n=await ns(e);return n?ha(n,t):null}async function K6(e,t,n){let r=await ns(e);if(!r)throw new Error(`no local checkout for ${e}`);return ma(r,t,{method:n})}async function G6(e,t){let n=await ns(e);if(!n)throw new Error(`no local checkout for ${e}`);return rc(n,t)}async function z6(e,t){await C({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 za(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 V6=10*6e4;async function J6(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>uO){await za(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 za(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await za(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<V6)return;await za(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 za(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 za(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await fO(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function Va(e,t,n){await C({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 Y6(e,t){try{return await wb("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function gl(e,t,n,r=()=>!0){return(await K(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var Ja=(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 pO(e,t,{grace:n=P6}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=D6}async function X6(e,t,n,r){let o=r.now??Date.now();if(!pO(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||je(s))return!1;let a=(s.boxes||[]).find(d=>d.name===s.leadBox);return await(r.midTurn??os)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await K(s).catch(()=>[])).some(d=>d.type==="pr.state.changed"&&d.payload?.number===Number(e.number))?(await(r.claim??or)(e.repo,e.number).catch(()=>null),!1):await(r.claim??or)(e.repo,e.number).catch(()=>null)?(await Va(s,"opened",{...Ja(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 Z6(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 Xu(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await Qu(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<N6;await oA(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await rA(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await gl(a,"pushed",e.number,d=>d.payload?.sha===s)&&await Va(a,"pushed",{...Ja(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>mb)await Zu(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 Zu(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=yl(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await gl(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await Va(a,"ci-fixed",{...Ja(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await Zu(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>mb)await ed(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await ed(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){yl(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await gl(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await Va(a,"reconciled",{...Ja(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await ed(e.repo,e.number).catch(()=>{})}}}}async function Q6(e,t,n,r){let o=yl(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await gl(s,"closed",e.number)&&await Va(s,"closed",{...Ja(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 eK(e,t,n){yl(n,e,"lost",null);let r=t.get(e.trackId);r&&!await gl(r,"lost",e.number)&&await Va(r,"lost",Ja(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function fO(e,t,n,r,o={}){let s=yl(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await K(a).catch(()=>[])).some(l=>l.type==="pr.state.changed"&&l.payload?.change==="merged"&&l.payload?.number===Number(e.number))||await r.emitMerged(a,{number:Number(e.number),url:t.url||e.url,title:t.title||e.title,branch:t.headRefName||e.headRef,repo:e.repo,githubAt:s.githubAt,latencyMs:s.latencyMs,lane:s.lane}).catch(()=>{})),await r.notifyIfArmed(e.repo,e.number).catch(()=>{}),await r.followupsIfMerged(e.repo,e.number).catch(()=>{}),await r.archiveIfArmed(e.repo,e.number).catch(()=>{}),await r.mark(e.repo,e.number,"merged").catch(()=>{})}async function sO(e={}){let{now:t=Date.now(),auth:n=Mm,view:r=F6,list:o=U6,links:s=cA,trackMap:a=H6,emitMerged:i=W6,mark:c=no,archiveIfArmed:l=lr,notifyIfArmed:u=ur,notifyIfResolved:d=lp,followupsIfMerged:p=gs,batchThreshold:f=C6,detail:w=q6,merge:h=K6,updateBranch:g=G6,lookup:y=ct,disarm:x=Qi,emitDisarmed:b=z6,localHasCommit:I=Y6,claim:_=or,midTurn:N=os,only:U=null,wantDetail:j=null,covered:T=fb,verdicts:R=null}=e;if(!(await n().catch(()=>null))?.authenticated||rd()>0)return 0;let V=await s().catch(()=>[]),O=MA(V),S=G=>{try{return!!j?.(G)}catch{return!1}},M=U?V.filter(G=>{try{return U(G)}catch{return!1}}):V.filter(G=>t-(Xp.get(ce(G.repo,G.number))||0)>=rO[oO(G,t,T)]);if(!M.length)return 0;let H=Date.now(),W=new Map,te=new Map;for(let G of[...M].sort(oc)){let fe=U?"event":oO(G,t,T);W.set(ce(G.repo,G.number),{lane:fe,intervalMs:rO[fe]??null}),Xp.set(ce(G.repo,G.number),t),te.has(G.repo)||te.set(G.repo,[]),te.get(G.repo).push(G)}let pe=await a().catch(()=>new Map),Ie=new Map,Oe=(G,fe)=>{let be=ce(G,fe);if(!Ie.has(be)){let xe=Promise.resolve().then(()=>w(G,fe));xe.catch(()=>{}),Ie.set(be,xe)}return Ie.get(be)},re=R??((G,fe)=>Yp([{path:G,prs:[fe]}],{now:t,slugOf:async()=>G,tracks:async()=>[...pe.values()].filter(be=>!je(be))}).catch(()=>{})),Ne={now:t,lanes:W,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,followupsIfMerged:p,detail:Oe,merge:h,updateBranch:g,lookup:y,disarm:x,emitDisarmed:b,localHasCommit:I,claim:_,midTurn:N};for(let[G,fe]of te){let be,xe=new Set,Ke=le=>le.ciFixAwait||le.reconcileAwait||S(le)?!0:!le.autoMerge||le.trackId&&O.get(le.trackId)!==ce(le.repo,le.number)?!1:t-(le.autoMerge.armedAt||0)<=uO;if(fe.length>f)be=await o(G).catch(()=>null);else{be=new Map;for(let le of fe){if(Ke(le)){let $=await Oe(G,le.number).catch(()=>null);if($?.state){be.set(Number(le.number),{number:Number(le.number),url:$.url,title:$.title,headRefName:$.headRefName,headRefOid:$.headSha??null,state:$.state,mergedAt:$.mergedAt??null,closedAt:$.closedAt??null});continue}}try{let $=await r(G,le.number);$?.number!=null&&be.set(Number($.number),$)}catch($){j6($)&&xe.add(ce(le.repo,le.number))}}}if(be)for(let le of fe){let $=ce(le.repo,le.number),Y=be.get(Number(le.number));if(!Y){if(xe.has($)){let Ce=(Zp.get($)||0)+1;Zp.set($,Ce),Ce>=M6&&(await eK(le,pe,Ne),Zp.delete($),Xp.delete($))}continue}if(Zp.delete($),Y.state==="MERGED"||Y.state==="CLOSED")Y.state==="MERGED"?await fO(le,Y,pe,Ne):await Q6(le,Y,pe,Ne),Xp.delete($);else{await X6(le,Y,pe,Ne).catch(()=>{}),await Z6(le,Y,pe,Ne).catch(()=>{});let Ce=!le.trackId||O.get(le.trackId)===$;le.autoMerge&&Ce&&await J6(le,pe,Ne).catch(()=>{});try{if(S(le)&&!Ie.has($)&&Oe(le.repo,le.number),Ie.has($)){let Ve=await Ie.get($).catch(()=>null);Ve?.checks&&await re(le.repo,Ve)}}catch{}}}}let X={};for(let{lane:G}of W.values())X[G]=(X[G]||0)+1;return console.log(`[pr-watch] probed ${M.length} link(s) (${Object.entries(X).map(([G,fe])=>`${G} ${fe}`).join(", ")}) in ${Date.now()-H}ms`),M.length}function aO(e,t){return!e||!t?!1:e.all?!0:String(t.repo||"").toLowerCase()!==e.repo?!1:e.numbers?.length?e.numbers.includes(Number(t.number)):e.event==="push"?!!e.branch&&t.headRef===e.branch||!!t.autoMerge:e.branch?t.headRef===e.branch:!0}var hb=!1,Qp=!1,ef=[],iO=Promise.resolve();async function tK(){for(;Qp||ef.length;){if(Qp){Qp=!1;try{await sO()}catch{}continue}let e=ef;ef=[];let t=e.map(r=>r.spec),n=Object.assign({},...e.map(r=>r.deps||{}));try{await sO({...n,only:r=>t.some(o=>aO(o,r)),wantDetail:r=>t.some(o=>o.detail&&aO(o,r))})}catch{}}}function tf(e,t){return e===null?Qp=!0:ef.push({spec:e,deps:t}),hb||(hb=!0,iO=tK().finally(()=>{hb=!1})),iO}function hO(e,t=void 0){let n=String(e?.repo||"").toLowerCase();if(!/^[^/\s]+\/[^/\s]+$/.test(n))return Promise.resolve();let r=(Array.isArray(e.numbers)?e.numbers:[]).map(Number).filter(o=>Number.isInteger(o)&&o>0);return tf({repo:n,numbers:r,branch:e.branch||null,event:e.event||null,detail:e.detail===!0},t)}var nK=6e4,cO=0;function mO(e=void 0){let t=e?.now??Date.now();return t-cO<nK?Promise.resolve():(cO=t,tf({all:!0},e))}function wO(){tf(null),setInterval(()=>tf(null),lO)}rs();vd();Ac();dr();Yt();var rK=new Set(["opened","reopened","closed","synchronize","ready_for_review","converted_to_draft","edited"]);async function oK({tracks:e=we,reconcile:t=Nd}={}){for(let n of(await e().catch(()=>[])).filter(r=>!je(r)))await t(n,{bypassThrottle:!0}).catch(()=>{})}function gO(e,t={}){let{invalidate:n=Zt,probe:r=hO,poke:o=mT,reconcileOpened:s=oK}=t;try{n()}catch{}let a={probe:null,poked:!1,reconciled:!1};if(!e?.repo)return a;if(e.event==="pull_request"&&rK.has(e.action)){if(e.action==="opened"||e.action==="reopened"){a.poked=!0,a.reconciled=!0;try{o()}catch{}s()}a.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event}}else(e.event==="check_suite"||e.event==="workflow_run")&&e.action==="completed"?a.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event,detail:!0}:e.event==="push"&&!e.deleted&&(a.probe={repo:e.repo,branch:e.headRef||null,event:"push"});return a.probe&&r(a.probe),a}ut();he();dr();Yt();import{randomUUID as sK}from"node:crypto";var aK=2e4,yO=3,Ya=new Map,gb=new Set;async function bO(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 iK(e={}){let{sessions:t=null,tracks:n=null,append:r=C,read:o=K,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await sn(),i=n??await we()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(je(u)||!u.leadBox)continue;let d=(u.boxes||[]).find(f=>f.name===u.leadBox);if(!d||d.agent!=="claude"||d.state!=="live")continue;let p=c.get(d.name);if(p)if(l.add(d.name),p.alternateOn){let f=(Ya.get(d.name)||0)+1;Ya.set(d.name,f),f===yO&&(gb.add(d.name),await bO(u,d.name,o)||await r(u,{type:"box.fullscreen.detected",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:sK(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let f=(Ya.get(d.name)||0)>=yO;if(Ya.delete(d.name),f||!gb.has(d.name)){gb.add(d.name);let w=await bO(u,d.name,o);w&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:w,action:"cleared"}}).catch(()=>{})}}}for(let u of[...Ya.keys()])l.has(u)||Ya.delete(u)}var bl=null,yb=!1;function kO(){return bl?()=>{}:(bl=setInterval(()=>{yb||(yb=!0,iK().catch(()=>{}).finally(()=>{yb=!1}))},aK),bl.unref?.(),()=>{clearInterval(bl),bl=null})}Zo();Ac();he();rs();ss();Zo();dc();import{randomUUID as cK}from"node:crypto";async function lK(){let e=await Promise.resolve().then(()=>(dr(),gI));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var bb={listRepoPrs:Cn,readEvents:K,appendEvent:C,sayDeps:lK,currentBranch:ao};async function uK(e,t=bb,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??ao)(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 kb(e,t,{actions:n,notify:r=!1}={},o=bb){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 uK(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=cK();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 xb(e,{offerId:t,choice:n}={},r=bb){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');return co(`prx:${e.id}:${t}`,()=>dK(e,{offerId:t,choice:n},r))}async function dK(e,{offerId:t,choice:n},r){let o=await r.readEvents(e),s=o.find(u=>u.type==="pr.exists.offered"&&u.payload?.offerId===t);if(!s)throw new Error("unknown offer");if(o.some(u=>u.type==="pr.exists.answered"&&u.payload?.offerId===t))throw new Error("offer already answered");let a=s.payload||{},i=Array.isArray(a.actions)&&a.actions.length?a.actions:["commit","push","pr"],c=null,l=null;if(n==="push"){let{sayToLead:u}=await r.sayDeps();l=eo.filter(d=>d!=="pr"&&(i.includes(d)||d==="push")),c=await u(e.id,ua(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,GS(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}}dc();import Tr from"node:fs/promises";import Xa from"node:path";import _O from"node:os";import xO from"node:fs/promises";import nf from"node:path";import{execFile as pK}from"node:child_process";import{promisify as fK}from"node:util";import{fileURLToPath as hK}from"node:url";var mK=fK(pK),SO=nf.dirname(hK(import.meta.url)),wK=nf.resolve(SO,"..","..","client","dist"),gK="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",yK=new Map([...gK].map((e,t)=>[e,t]));function bK(e){let t=[],n=0,r=0;for(let o of e){let s=yK.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 kK(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=bK(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 xK(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 vO=new Map;async function vK(e){let t;try{t=await xO.stat(e)}catch{return null}let n=vO.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await xO.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:kK(r.mappings||"")};return vO.set(e,o),o}catch{return null}}var vb=null;function SK(){return vb||(vb=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):mK("git",["rev-parse","--short","HEAD"],{cwd:nf.resolve(SO,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),vb}var AK=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function TK(e,{distDir:t=wK}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(AK)){let[a,i,c,l]=s,u=await vK(nf.join(t,"assets",`${i}.map`)),d=u?xK(u.lines[Number(c)-1],Number(l)-1):null;if(n.push(e.slice(r,s.index)),d&&u.sources[d[1]]){let p=u.sources[d[1]].replace(/^(\.\.\/)+/,"");n.push(`${p}:${d[2]+1}:${d[3]+1}`),o=!0}else n.push(a);r=s.index+a.length}return n.push(e.slice(r)),{stack:n.join(""),symbolicated:o}}async function AO(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await SK();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await TK(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var EK=()=>process.env.BOSTRAT_STATE_DIR||Xa.join(process.env.HOME||_O.tmpdir(),".bostrat"),_o=()=>Xa.join(EK(),"telemetry"),IO=()=>Xa.join(_o(),".relay-offsets.json"),_K=50,IK=14,$K=3e4,TO=500,Gt=(e,t)=>typeof e=="string"?e.slice(0,t):"";function RK(e,t){if(!e||typeof e!="object")return null;let n=Gt(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:Gt(e.anonId,64),sessionId:Gt(e.sessionId,64),userId:Gt(e.userId,64),release:Gt(e.release,64),appVersion:Gt(e.appVersion,32),route:Gt(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:Gt(e.error.kind,256),message:Gt(e.error.message,8192),stack:Gt(e.error.stack,32768),fingerprint:Gt(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:Gt(s?.n,64),r:Gt(s?.r,128)}))),o}var $O=e=>new Date(e).toISOString().slice(0,10),EO=0;async function RO(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,_K):[]).map(s=>RK(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await AO(s);await Tr.mkdir(_o(),{recursive:!0});let o=Xa.join(_o(),`${$O(t)}.ndjson`);return await Tr.appendFile(o,r.map(s=>JSON.stringify(s)+`
760
+ `).join(""),"utf8"),t-EO>6*3600*1e3&&(EO=t,OK(t).catch(()=>{})),r.length}async function OK(e=Date.now()){let t=$O(e-IK*24*3600*1e3),n=[];try{n=await Tr.readdir(_o())}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 Tr.rm(Xa.join(_o(),s),{force:!0});let o=await MO();for(let s of r)delete o[s];await CO(o)}var rf=new Map;function OO(e,t=Date.now()){let n=e||"unknown",r=rf.get(n);return r||(rf.size>512&&rf.clear(),r={tokens:40,at:t},rf.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 MO(){try{return JSON.parse(await Tr.readFile(IO(),"utf8"))||{}}catch{return{}}}async function CO(e){await Tr.mkdir(_o(),{recursive:!0}),await Tr.writeFile(IO(),JSON.stringify(e),"utf8")}function MK(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||_O.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 CK({fetchImpl:e=fetch}={}){let t=await e$();if(!t)return{sent:0,disabled:!0};let n;try{n=(await Tr.readdir(_o())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await MO(),o=0;for(let s of n){let a=Xa.join(_o(),s),i=r[s]||0,c;try{let p=await Tr.open(a,"r");try{let f=(await p.stat()).size;if(f<=i)continue;c=Buffer.alloc(f-i),await p.read(c,0,c.length,i)}finally{await p.close()}}catch{continue}let l=c.lastIndexOf(10);if(l<0)continue;let u=c.toString("utf8",0,l+1).split(`
761
+ `).filter(Boolean),d=[];for(let p of u)try{d.push(JSON.parse(p))}catch{}for(let p=0;p<d.length;p+=TO){let f=d.slice(p,p+TO).map(h=>MK(h)),w=await e(`${t.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${t.ingestKey}`},body:JSON.stringify({events:f})}).catch(()=>null);if(!w||!w.ok)return{sent:o,disabled:!1};o+=f.length}r[s]=i+l+1,await CO(r)}return{sent:o,disabled:!1}}var Sb=null,Ab=!1;function NO(){Sb||(Sb=setInterval(async()=>{if(!Ab){Ab=!0;try{await CK()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{Ab=!1}}},$K),Sb.unref?.())}import sf from"node:fs/promises";import LO from"node:path";import NK from"node:os";var FO=()=>process.env.BOSTRAT_STATE_DIR||LO.join(process.env.HOME||NK.tmpdir(),".bostrat"),UO=()=>LO.join(FO(),"dictation-glossary.json"),PK=100,DK=500,BK=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],af=null,Tb=null,Eb=Promise.resolve();function PO(){let e={},t=Date.now();for(let n of BK)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function HO(){return af||(Tb??=sf.readFile(UO(),"utf8").then(e=>JSON.parse(e)?.terms??PO()).catch(()=>PO()).then(e=>af=e).finally(()=>Tb=null),Tb)}async function DO(){let e=JSON.stringify({terms:af},null,2),t=UO(),n=`${t}.${process.pid}.tmp`;await sf.mkdir(FO(),{recursive:!0}),await sf.writeFile(n,e),await sf.rename(n,t)}function jK(){return Eb=Eb.then(DO,DO),Eb.catch(()=>{})}async function _b(){return Object.values(await HO()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var LK=e=>Math.max(1,Math.ceil(e.length/4));async function FK(){let e=[],t=0;for(let{term:n}of await _b()){let r=LK(n);if(!(t+r>DK)&&(e.push(n),t+=r,e.length>=PK))break}return e}async function UK(e,t){let n=await HO(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var BO=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),of=e=>e.toLowerCase();function jO(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function WO(e,t){let n=BO(e),r=BO(t);if(!n.length||!r.length)return[];let o=n.length,s=r.length,a=Array.from({length:o+1},()=>new Array(s+1).fill(0));for(let u=o-1;u>=0;u--)for(let d=s-1;d>=0;d--)a[u][d]=of(n[u])===of(r[d])?a[u+1][d+1]+1:Math.max(a[u+1][d],a[u][d+1]);let i=new Set,c=0,l=0;for(;c<o&&l<s;)of(n[c])===of(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(jO(r[l])&&i.add(r[l]),l++);for(;l<s;l++)jO(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await UK(u,"learned");return await jK(),[...i]}var kl=null;function HK(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 qO(){if(!kl)return null;let e=await tl();if(!e||e.apiKey.slice(-6)!==kl.keyTail)return null;let{keyTail:t,...n}=kl;return n}async function KO(e,t){let n=await tl();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 FK())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=HK(o.status,i);c.persistent&&(kl={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 kl=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}he();var Ib={"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 WK(e){if(!e)return null;let t=String(e).trim();if(Ib[t])return t;let n=null;for(let r of Object.keys(Ib))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function qK(e,t={}){let n=Ib[WK(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 KK(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 xl=null;async function GK(){if(!xl)return null;let e=await Op();if(!e||e.apiKey.slice(-6)!==xl.keyTail)return null;let{keyTail:t,...n}=xl;return n}async function zK(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=KK(t.status,o);s.persistent&&(xl={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}xl=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 VK={openai:zK};async function GO(){let e=await Op();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await GK()}:{configured:!1}}async function zO(){let e=await Op();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 VK[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function VO(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=qK(t,s),i=await C(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}}Yt();var nM=Ee.dirname(YK(import.meta.url)),JO=Number(process.env.PORT)||3362,cf=uy(process.env),rM=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,Za=lR(process.env.BOSTRAT_ALLOW_IPS),Cb=uR(process.env.BOSTRAT_VIEW_FRONT_CIDRS,zp),Nb=pR(),oM=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",E=zt();E.disable("x-powered-by");E.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),Gp(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});E.use((e,t,n)=>{if(ml(e)||Za.allowed(Za.clientIp(e))||Cb.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});E.use(yR);E.use(mR({token:Nb,enforce:oM}));E.use("/api/mocks",zt.json({limit:"1mb"}));E.use("/api/mocks",zt.raw({type:"image/png",limit:"24mb"}));E.use("/api/mocks",zt.raw({type:["video/mp4","video/webm"],limit:"105mb"}));E.use("/api/runbooks",zt.json({limit:"1mb"}));E.use("/api/tracks/adopt",zt.json({limit:"1mb"}));E.use("/api/telemetry",zt.json({limit:"256kb"}));E.use("/api/hook",zt.json({limit:"2mb"}));E.use("/api/dictation",zt.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));E.use("/api/tracks/:id/upload",zt.raw({type:()=>!0,limit:"25mb"}));E.use(zt.json({limit:"64kb"}));E.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:jt,hostTmuxAlive:await jr(),autoTriggerPct:rM,plane:Qa?Qa.status():null})});E.get("/api/sessions",async(e,t)=>{t.json({sessions:await sn()})});E.post("/api/sessions",async(e,t)=>{let{displayName:n,cwd:r}=e.body||{};if(typeof n!="string")return t.status(400).json({error:"displayName (string) required"});try{let o=await En(n,r||void 0);t.json({ok:!0,...o})}catch(o){let s=o?.message||String(o),a=/already exists/i.test(s)?409:/must be|invalid/i.test(s)?400:500;t.status(a).json({error:s})}});E.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!De(n))return t.status(400).json({error:"invalid session name"});if(!await ye(n))return t.status(404).json({error:"session not found"});try{await Ot(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});E.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!De(n))return t.status(400).json({error:"invalid session name"});let r=await ye(n);if(!r)return t.status(404).json({error:"session not found"});let o=await Ri(r.cwd,r.sessionId);if(!o)return t.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});t.json({available:!0,...o})});E.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!De(n))return t.status(400).json({error:"invalid session name"});try{let r=await av(n);t.json({ok:!0,step:r.step,file:r.file,startedAt:r.startedAt})}catch(r){t.status(409).json({error:r?.message||String(r)})}});E.get("/api/handoff/:name",(e,t)=>{let n=decodeURIComponent(e.params.name),r=$u(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 YO=10;async function sM(){let e=await we(),[t,n]=await Promise.all([AI(e),EI(e)]);return{tracks:e,views:await Rw(),queuedOf:r=>ps(r),jobsOf:r=>t.get(r)??[],prPendingOf:r=>n.get(r)??[]}}E.get("/api/idle-guard",async(e,t)=>{try{t.json(ay(await sM()))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var rn=bs(),nG=FI({kind:rn}),Sl=null,Et=()=>Sl&&["auto","prompt","off"].includes(Sl)?Sl:nG,Mb=null,rG=Qc.has(rn),aM=async({to:e,from:t})=>!rG||Ap(await el())?!1:(Tl.arm({to:e,from:t,kind:rn}),!0);async function oG(e){let t=Et();Sl=e??null;let n=Et();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){Tl.cancel();return}Mb&&await aM(Mb)}}var iM=(()=>{try{return tG(import.meta.url)("../package.json").version||null}catch{return null}})(),Tl=HI({isBusy:async()=>ay(await sM()).busy,onStuck:({to:e,from:t})=>Kn({current:t,latest:e,installKind:rn,policy:Et(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?Kn({current:t,latest:e,installKind:rn,policy:Et(),status:"updating",reason:"auto"}):Kn({current:t,latest:e,installKind:rn,policy:Et(),status:"failed",error:n?.reason})).catch(()=>{})});E.get("/api/node/self-update",async(e,t)=>{t.json({installKind:rn,policy:Et(),policySource:Sl?"plane":"node",current:iM,status:await el(),armed:Tl.armed})});E.post("/api/node/self-update",async(e,t)=>{let n=typeof e.body?.to=="string"?e.body.to.trim():"";if(!/^\d+\.\d+\.\d+$/.test(n))return t.status(400).json({error:"body.to must be a release version (X.Y.Z)"});let r=await Tp({to:n,kind:rn,reason:"manual"});if(r.ok)return Tl.cancel(),Kn({current:r.from,latest:n,installKind:rn,policy:Et(),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 cM(){try{let e=await UI();e&&await Kn({current:e.from,latest:e.to,installKind:e.kind||rn,policy:Et(),status:e.status,error:e.error,reason:e.reason}),await vg({current:iM,installKind:rn,policy:Et()})}catch{}}cM();setInterval(cM,3e4).unref();E.get("/api/tracks",async(e,t)=>{let n=(await we()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>YO){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,YO).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:Wc,agentAvailability:await tp(),tickets:await h$()})});E.get("/api/cost",async(e,t)=>{try{let n=await we();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await Gy(n);if(r.cursorUsage=hw(),e.query.format==="text")return t.type("text/plain").send(L$(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/roundup",async(e,t)=>{try{let n=await Vy(await we(),{window:e.query.window,from:e.query.from,to:e.query.to});if(e.query.format==="text")return t.type("text/plain").send(q$(n));t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/spend",async(e,t)=>{try{let n=await J$(await we(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=hw(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=Yi(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/caps",(e,t)=>{t.json(Yi())});E.post("/api/usage/caps",async(e,t)=>{try{t.json(await Wu(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});E.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await oR(await we(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await Jb(e.get(Yn),{byToken:qc,legacy:()=>hc(e.body?.session_id,e.body?.cwd)});if(n==="refused")return si("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return si("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&&si("mismatch",{track:r.track.id,box:r.box.name}),si(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 D$(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&zl(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});E.get("/api/git/trailers",async(e,t)=>{t.type("text/plain");try{let n=await qc(e.get(Yn));if(!n?.track||!n?.box)return t.status(204).end();t.send((await QA(n.track,n.box)).join(`
758
762
  `)+`
759
- `)}catch{t.status(204).end()}});T.post("/api/git/committed",async(e,t)=>{try{let n=await _c(e.get(Vn));if(!n?.track||!n?.box)return t.json({ok:!1,error:"unknown hook token"});let r=String(e.body?.sha||"").trim();if(!/^[0-9a-f]{7,40}$/i.test(r))return t.json({ok:!1,error:"sha required"});t.json({ok:!0});let o=n.box.cwd?Te.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?Te.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+Te.sep))?s:o;wT(n.track,n.box,r,{cwd:a}).catch(i=>console.warn(`[rework] ${n.track.id}: recordCommit failed: ${i?.message||i}`))}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});T.post("/api/tracks/:id/rework-cause",async(e,t)=>{try{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let{sha:r,cause:o}=e.body||{};t.json({ok:!0,event:await yT(n,String(r||""),String(o||""))})}catch(n){let r=n?.message||String(n);t.status(/unknown rework/i.test(r)?404:/already answered/i.test(r)?409:400).json({error:r})}});T.post("/api/tracks/:id/rework-cause/retract",async(e,t)=>{try{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,event:await bT(n,String(e.body?.sha||""))})}catch(n){let r=n?.message||String(n);t.status(/no standing answer/i.test(r)?409:400).json({error:r})}});T.get("/api/usage/rework",async(e,t)=>{try{t.json(await m$(await he(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.post("/api/telemetry",async(e,t)=>{try{if(!JR(Da.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await VR(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});T.get("/api/repos",async(e,t)=>{try{let n=await Jn(),r=new Set((await Promise.all(n.map(a=>_e(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await za()).repos||[]).filter(a=>!r.has(String(a.slug).toLowerCase())).map(a=>({slug:a.slug,name:a.slug.split("/")[1],branch:a.defaultBranch||null,private:!!a.private,remote:!0}));t.json({repos:[...n,...s]})}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.get("/api/github/token",async(e,t)=>{try{t.json(await yl(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});T.get("/api/github/status",(e,t)=>{t.json({configured:gl(),calls:NS(),latency:jS(),webhook:bR()})});T.post("/api/github/event",Ut.json({limit:"64kb"}),(e,t)=>{let n=gR(e.body,{onAccept:r=>PR(r)});if(!n.ok)return t.status(400).json({error:n.error});t.json({ok:!0,duplicate:n.duplicate})});T.post("/api/github/refresh",(e,t)=>{Sb(),t.json({ok:!0})});T.get("/api/gmail/search",async(e,t)=>{try{let n=await T$(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)})}});T.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await A$(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});async function il({repo:e=null,number:t=null,branch:n=null}){let r=e?await _e(e):null;if(r&&t!=null){let s=await at(r,t),a=s&&await ie(s.trackId);if(a)return a}if(!n)return null;let o=await he();return qu(o,n,s=>Ku(s,{branch:n,repo:e,slug:r}))}async function _O({repo:e=null,number:t=null,branch:n=null}){let r=await il({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!De(r))return r;if(!n)return null;let o=e?await _e(e).catch(()=>null):null,s=await he();return qu(s,n,a=>!De(a)&&Ku(a,{branch:n,repo:e,slug:o}))}async function kn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await il({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await _e(s).catch(()=>null):null);await M({id:c.id,cwd:c.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),change:e,number:t,url:n,title:r,branch:o??c.workspace?.branch??null,...l?{repo:l}:{},...i}}).catch(()=>{})}async function b6(e){let t=(await he()).filter(n=>!De(n));for(let n of e??[]){if(!n.prs?.length)continue;let r=await _e(n.path);if(r)for(let o of n.prs){if(await at(r,o.number))continue;let s=await qu(t,o.headRefName,a=>Ku(a,{branch:o.headRefName,repo:n.path,slug:r}));s&&await Ct({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}T.get("/api/git/prs",async(e,t)=>{try{let n=await KS();await b6(n.repos).catch(()=>{}),await yp(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.post("/api/git/prs/merge",async(e,t)=>{let{repo:n,number:r,method:o,auto:s,update:a,archive:i,notify:c,headRefName:l,title:u,url:d}=e.body||{},p=null,f=null,w=null;try{if(s){let x=o||"merge";if(!Li.has(x))throw new Error(`invalid merge method: ${x}`);let b=Number(r);if(!Number.isInteger(b)||b<=0)throw new Error("invalid PR number");let O=await _e((await or(n)).path);if(!O)throw new Error("repo has no GitHub remote");let I=await il({repo:n,number:b,branch:l}).catch(()=>null);if(!I)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(p=I,f=await vd(I,"merge",{count:1,summary:`arming auto-merge on PR #${b}`}),a&&await Fi(n,b),await Ct({repo:O,number:b,trackId:I.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await Pi(O,b,{merge:{method:x}}))throw new Error("couldn't record the auto-merge arm");return await Bo(O,b,i===!0),await jo(O,b,c===!0&&i!==!0),Vt(),await kn("auto-armed",{number:b,url:d,title:u,branch:l,repo:n,track:I,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:b,auto:!0})}p=await il({repo:n,number:r,branch:l}).catch(()=>null),p&&(f=await vd(p,"merge",{count:1,summary:`merging PR #${r}`}));let m=await ea(n,r,{method:o||"squash"});await kn("merged",{number:m.number,url:d,title:u,branch:l,repo:n});let g=await _e(n).catch(()=>null),y=!1;if(g&&(i===!0&&await Bo(g,m.number,!0).catch(()=>{}),c===!0&&i!==!0&&await jo(g,m.number,!0).catch(()=>{}),await ir(g,m.number).catch(()=>{}),await Qo(g,m.number).catch(()=>{}),y=await ar(g,m.number).catch(()=>!1),await Vr(g,m.number,"merged").catch(()=>{})),i===!0&&!y){let x=await il({repo:n,number:m.number,branch:l}).catch(()=>null);x&&!x.archivedAt&&await Zo(x.id).catch(()=>{})}t.json(m)}catch(m){w=m;let g=m?.message||String(m),y=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(g)?400:502;t.status(y).json({error:g})}finally{p&&f&&await Aw(p,f,w?"failed":"completed",w).catch(()=>{})}});T.post("/api/git/prs/disarm-auto",async(e,t)=>{let{repo:n,number:r,headRefName:o,title:s,url:a}=e.body||{};try{let i=Number(r);if(!Number.isInteger(i)||i<=0)throw new Error("invalid PR number");let c=await _e((await or(n)).path).catch(()=>null),l=c?await Di(c,i).catch(()=>null):null;try{await th(n,i)}catch(u){if(!l)throw u}Vt(),await kn("auto-canceled",{number:i,url:a,title:s,branch:o,repo:n}),t.json({ok:!0,number:i})}catch(i){let c=i?.message||String(i),l=/invalid|unknown repo|required/i.test(c)?400:502;t.status(l).json({error:c})}});T.post("/api/git/prs/merge-all",async(e,t)=>{let{repo:n,method:r}=e.body||{};try{let o=await _e(n).catch(()=>null),s=await YS(n,{method:r||"merge",onMerged:a=>{kn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&ir(o,a.number).catch(()=>{}).then(()=>Qo(o,a.number)).catch(()=>{}).then(()=>ar(o,a.number)).catch(()=>{}).then(()=>Vr(o,a.number,"merged")).catch(()=>{})}});t.json(s)}catch(o){let s=o?.message||String(o),a=/already running/i.test(s)?409:/invalid|unknown repo|no PRs ready/i.test(s)?400:502;t.status(a).json({error:s})}});T.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:JS()})});T.post("/api/git/prs/merge-track",async(e,t)=>{let{trackId:n,update:r,archive:o,notify:s,method:a}=e.body||{},i=null,c=null,l=null;try{let u=a||"merge";if(!Li.has(u))throw new Error(`invalid merge method: ${u}`);if(!n)return t.status(400).json({error:"trackId required"});let d=await ie(n);if(!d)return t.status(404).json({error:`Track ${n} isn't on this node`});i=d;let p=(await un()).filter(m=>m.trackId===d.id&&m.state!=="merged"&&m.state!=="closed").sort(Ui);if(!p.length)return t.status(409).json({error:"no open PRs on this Track"});c=await vd(d,"merge",{count:p.length,summary:p.length===1?"merging 1 PR":`merging ${p.length} PRs`});for(let m of p)await Bo(m.repo,m.number,o===!0).catch(()=>{}),await jo(m.repo,m.number,s===!0&&o!==!0).catch(()=>{});let f=[],w=[];for(let m of p){let g={repo:m.repo,number:m.number,ok:!0,action:"armed"};f.push(g);try{let y=await Fo(m.repo);if(!y)throw new Error(`no local checkout for ${m.repo}`);let x=await Qs(y,m.number);w.push({r:g,l:m,repoPath:y,pr:x,plan:GS(x,{update:r!==!1})})}catch(y){g.ok=!1,g.action="failed",g.reason=y?.message||String(y)}}for(let{r:m,l:g,repoPath:y,pr:x,plan:b}of zS(w))try{if(b.action==="skip")m.action="skipped",m.reason=b.reason;else if(b.action==="merge")await ea(y,g.number,{method:u}),await kn("merged",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:y,track:d}),await ir(g.repo,g.number).catch(()=>{}),await Qo(g.repo,g.number).catch(()=>{}),await ar(g.repo,g.number).catch(()=>{}),await Vr(g.repo,g.number,"merged").catch(()=>{}),m.action="merged";else{if(b.action==="update-arm"&&(await Fi(y,g.number).catch(()=>{}),m.action="updated-armed"),!await Pi(g.repo,g.number,{merge:{method:u}}))throw new Error("couldn't record the auto-merge arm");await kn("auto-armed",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:y,track:d,...m.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(O){m.ok=!1,m.action="failed",m.reason=O?.message||String(O)}if(Vt(),!f.some(m=>m.ok)){if(o===!0)for(let m of p)await Bo(m.repo,m.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let m of p)await jo(m.repo,m.number,!1).catch(()=>{});return t.status(502).json({error:f.map(m=>`${m.repo}#${m.number}: ${m.reason}`).join("; "),results:f})}t.json({ok:!0,trackId:d.id,results:f})}catch(u){l=u;let d=u?.message||String(u),p=/invalid|required/i.test(d)?400:502;t.status(p).json({error:d})}finally{i&&c&&await Aw(i,c,l?"failed":"completed",l).catch(()=>{})}});T.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 ie(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await un()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await Di(a.repo,a.number).catch(()=>null),c=await Fo(a.repo).catch(()=>null);c&&await th(c,a.number).catch(()=>{}),i&&(await kn("auto-canceled",{number:a.number,url:a.url,title:a.title,branch:a.headRef,repo:c,track:r}),s.push({repo:a.repo,number:a.number}))}Vt(),t.json({ok:!0,trackId:r.id,canceled:s})}catch(r){let o=r?.message||String(r),s=/invalid|required/i.test(o)?400:502;t.status(s).json({error:o})}});T.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 ie(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=$t(i.workspace),d,p=Array.isArray(a)?a.filter(Boolean):[];if(p.length)d=p.map(m=>{let g=u.find(y=>y.name===m||y.repo===m||y.base===m||y.dir===m);if(!g)throw new Error(`invalid repo "${m}" \u2014 not tagged on this Track`);return g});else if(d=await Ko(i),!d.length)return t.status(409).json({error:"no tagged repo has work to ship"});let f=[];for(let m of d)try{let g=await rh(m.dir,{title:r,body:o,base:s}),y=m.repo||await _e(m.dir).catch(()=>null);y&&g.number&&await Ct({repo:y,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await kn("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:y??m.name}}),f.push({repo:m.name,slug:y??null,ok:!0,url:g.url,number:g.number})}catch(g){f.push({repo:m.name,slug:m.repo??null,ok:!1,error:g?.message||String(g)})}let w=f.filter(m=>m.ok);return w.length?t.json({ok:!0,multi:!0,results:f,url:w[0].url,number:w[0].number}):t.status(502).json({error:f.map(m=>`${m.repo}: ${m.error}`).join("; "),results:f})}let c=await rh(i.cwd,{title:r,body:o,base:s}),l=await _e(i.cwd).catch(()=>null);l&&c.number&&await Ct({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await kn("opened",{number:c.number,url:c.url,title:r,track:i,branch:i.workspace?.branch,extra:{...l?{repo:l}:{}}}),t.json(c)}catch(i){let c=i?.message||String(i),l=/required|invalid/i.test(c)?400:502;t.status(l).json({error:c})}});T.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await Ko(n),o=new Map(r.map(a=>[a.base,a])),s=$t(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)})}});T.post("/api/tracks/:id/repos",async(e,t)=>{let{repo:n}=e.body||{};try{if(!n||typeof n!="string")return t.status(400).json({error:"repo (path or owner/name) required"});let r=await ng(e.params.id,n);t.json({ok:!0,added:{name:r.name,base:r.base,baseRef:r.baseRef??null,repo:r.repo??null}})}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/already tagged|needs a multi|not a usable|archived|required/i.test(o)?400:502;t.status(s).json({error:o})}});T.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await rg(e.params.id,e.params.name);t.json({ok:!0,...n})}catch(n){let r=n?.message||String(n),o=/track .* not found/i.test(r)?404:/has work|still running|last repo/i.test(r)?409:/needs a multi|not tagged/i.test(r)?400:502;t.status(o).json({error:r})}});T.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Qs(n,r),s=await _e(n).catch(()=>null),a=await _O({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=$t(a.workspace).find(y=>y.base===n||s&&y.repo===s)??null,c=a.workspace?.kind==="multi",l=await XS(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?Te.join("ci",i.name):"ci",d=Te.join(a.cwd,".bostrat",u),p=Te.join(".bostrat",u,`pr-${o.number}-fail.log`);await gt.promises.mkdir(d,{recursive:!0}),await gt.promises.writeFile(Te.join(a.cwd,p),l.map(y=>`\u2550\u2550\u2550\u2550 ${y.name}${y.link?` \xB7 ${y.link}`:""} \u2550\u2550\u2550\u2550
763
+ `)}catch{t.status(204).end()}});E.post("/api/git/committed",async(e,t)=>{try{let n=await qc(e.get(Yn));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?Ee.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?Ee.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+Ee.sep))?s:o;eT(n.track,n.box,r,{cwd:a}).catch(i=>console.warn(`[rework] ${n.track.id}: recordCommit failed: ${i?.message||i}`))}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});E.post("/api/tracks/:id/rework-cause",async(e,t)=>{try{let n=await ie(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 nT(n,String(r||""),String(o||""))})}catch(n){let r=n?.message||String(n);t.status(/unknown rework/i.test(r)?404:/already answered/i.test(r)?409:400).json({error:r})}});E.post("/api/tracks/:id/rework-cause/retract",async(e,t)=>{try{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,event:await rT(n,String(e.body?.sha||""))})}catch(n){let r=n?.message||String(n);t.status(/no standing answer/i.test(r)?409:400).json({error:r})}});E.get("/api/usage/rework",async(e,t)=>{try{t.json(await Y$(await we(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/telemetry",async(e,t)=>{try{if(!OO(Za.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await RO(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});E.get("/api/repos",async(e,t)=>{try{let n=await Xn(),r=new Set((await Promise.all(n.map(a=>_e(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await pi()).repos||[]).filter(a=>!r.has(String(a.slug).toLowerCase())).map(a=>({slug:a.slug,name:a.slug.split("/")[1],branch:a.defaultBranch||null,private:!!a.private,remote:!0}));t.json({repos:[...n,...s]})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/github/token",async(e,t)=>{try{t.json(await jl(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});E.get("/api/github/status",(e,t)=>{t.json({configured:Bl(),calls:yA(),latency:vA(),webhook:tO()})});E.post("/api/github/event",zt.json({limit:"64kb"}),(e,t)=>{let n=QR(e.body,{onAccept:r=>gO(r)});if(!n.ok)return t.status(400).json({error:n.error});t.json({ok:!0,duplicate:n.duplicate})});E.post("/api/github/refresh",(e,t)=>{ik(),t.json({ok:!0})});E.get("/api/gmail/search",async(e,t)=>{try{let n=await aR(String(e.query.q||""),{max:Number(e.query.max)||10});t.json({messages:n})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});E.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await iR(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});async function Al({repo:e=null,number:t=null,branch:n=null}){let r=e?await _e(e):null;if(r&&t!=null){let s=await ct(r,t),a=s&&await ie(s.trackId);if(a)return a}if(!n)return null;let o=await we();return pd(o,n,s=>fd(s,{branch:n,repo:e,slug:r}))}async function lM({repo:e=null,number:t=null,branch:n=null}){let r=await Al({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!je(r))return r;if(!n)return null;let o=e?await _e(e).catch(()=>null):null,s=await we();return pd(s,n,a=>!je(a)&&fd(a,{branch:n,repo:e,slug:o}))}async function vn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await Al({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await _e(s).catch(()=>null):null);await C({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 sG(e){let t=(await we()).filter(n=>!je(n));for(let n of e??[]){if(!n.prs?.length)continue;let r=await _e(n.path);if(r)for(let o of n.prs){if(await ct(r,o.number))continue;let s=await pd(t,o.headRefName,a=>fd(a,{branch:o.headRefName,repo:n.path,slug:r}));s&&await Lt({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}E.get("/api/git/prs",async(e,t)=>{try{let n=await $A();await sG(n.repos).catch(()=>{}),await Yp(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/git/prs/merge",async(e,t)=>{let{repo:n,number:r,method:o,auto:s,update:a,archive:i,notify:c,headRefName:l,title:u,url:d}=e.body||{},p=null,f=null,w=null;try{if(s){let x=o||"merge";if(!nc.has(x))throw new Error(`invalid merge method: ${x}`);let b=Number(r);if(!Number.isInteger(b)||b<=0)throw new Error("invalid PR number");let I=await _e((await ir(n)).path);if(!I)throw new Error("repo has no GitHub remote");let _=await Al({repo:n,number:b,branch:l}).catch(()=>null);if(!_)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(p=_,f=await qd(_,"merge",{count:1,summary:`arming auto-merge on PR #${b}`}),a&&await rc(n,b),await Lt({repo:I,number:b,trackId:_.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await Zi(I,b,{merge:{method:x}}))throw new Error("couldn't record the auto-merge arm");return await Qo(I,b,i===!0),await es(I,b,c===!0&&i!==!0),Zt(),await vn("auto-armed",{number:b,url:d,title:u,branch:l,repo:n,track:_,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:b,auto:!0})}p=await Al({repo:n,number:r,branch:l}).catch(()=>null),p&&(f=await qd(p,"merge",{count:1,summary:`merging PR #${r}`}));let h=await ma(n,r,{method:o||"squash"});await vn("merged",{number:h.number,url:d,title:u,branch:l,repo:n});let g=await _e(n).catch(()=>null),y=!1;if(g&&(i===!0&&await Qo(g,h.number,!0).catch(()=>{}),c===!0&&i!==!0&&await es(g,h.number,!0).catch(()=>{}),await ur(g,h.number).catch(()=>{}),await gs(g,h.number).catch(()=>{}),y=await lr(g,h.number).catch(()=>!1),await no(g,h.number,"merged").catch(()=>{})),i===!0&&!y){let x=await Al({repo:n,number:h.number,branch:l}).catch(()=>null);x&&!x.archivedAt&&await ws(x.id).catch(()=>{})}t.json(h)}catch(h){w=h;let g=h?.message||String(h),y=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(g)?400:502;t.status(y).json({error:g})}finally{p&&f&&await ag(p,f,w?"failed":"completed",w).catch(()=>{})}});E.post("/api/git/prs/disarm-auto",async(e,t)=>{let{repo:n,number:r,headRefName:o,title:s,url:a}=e.body||{};try{let i=Number(r);if(!Number.isInteger(i)||i<=0)throw new Error("invalid PR number");let c=await _e((await ir(n)).path).catch(()=>null),l=c?await Qi(c,i).catch(()=>null):null;try{await Pm(n,i)}catch(u){if(!l)throw u}Zt(),await vn("auto-canceled",{number:i,url:a,title:s,branch:o,repo:n}),t.json({ok:!0,number:i})}catch(i){let c=i?.message||String(i),l=/invalid|unknown repo|required/i.test(c)?400:502;t.status(l).json({error:c})}});E.post("/api/git/prs/merge-all",async(e,t)=>{let{repo:n,method:r}=e.body||{};try{let o=await _e(n).catch(()=>null),s=await NA(n,{method:r||"merge",onMerged:a=>{vn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&ur(o,a.number).catch(()=>{}).then(()=>gs(o,a.number)).catch(()=>{}).then(()=>lr(o,a.number)).catch(()=>{}).then(()=>no(o,a.number,"merged")).catch(()=>{})}});t.json(s)}catch(o){let s=o?.message||String(o),a=/already running/i.test(s)?409:/invalid|unknown repo|no PRs ready/i.test(s)?400:502;t.status(a).json({error:s})}});E.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:CA()})});E.post("/api/git/prs/merge-track",async(e,t)=>{let{trackId:n,update:r,archive:o,notify:s,method:a}=e.body||{},i=null,c=null,l=null;try{let u=a||"merge";if(!nc.has(u))throw new Error(`invalid merge method: ${u}`);if(!n)return t.status(400).json({error:"trackId required"});let d=await ie(n);if(!d)return t.status(404).json({error:`Track ${n} isn't on this node`});i=d;let p=(await pn()).filter(h=>h.trackId===d.id&&h.state!=="merged"&&h.state!=="closed").sort(oc);if(!p.length)return t.status(409).json({error:"no open PRs on this Track"});c=await qd(d,"merge",{count:p.length,summary:p.length===1?"merging 1 PR":`merging ${p.length} PRs`});for(let h of p)await Qo(h.repo,h.number,o===!0).catch(()=>{}),await es(h.repo,h.number,s===!0&&o!==!0).catch(()=>{});let f=[],w=[];for(let h of p){let g={repo:h.repo,number:h.number,ok:!0,action:"armed"};f.push(g);try{let y=await ns(h.repo);if(!y)throw new Error(`no local checkout for ${h.repo}`);let x=await ha(y,h.number);w.push({r:g,l:h,repoPath:y,pr:x,plan:RA(x,{update:r!==!1})})}catch(y){g.ok=!1,g.action="failed",g.reason=y?.message||String(y)}}for(let{r:h,l:g,repoPath:y,pr:x,plan:b}of OA(w))try{if(b.action==="skip")h.action="skipped",h.reason=b.reason;else if(b.action==="merge")await ma(y,g.number,{method:u}),await vn("merged",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:y,track:d}),await ur(g.repo,g.number).catch(()=>{}),await gs(g.repo,g.number).catch(()=>{}),await lr(g.repo,g.number).catch(()=>{}),await no(g.repo,g.number,"merged").catch(()=>{}),h.action="merged";else{if(b.action==="update-arm"&&(await rc(y,g.number).catch(()=>{}),h.action="updated-armed"),!await Zi(g.repo,g.number,{merge:{method:u}}))throw new Error("couldn't record the auto-merge arm");await vn("auto-armed",{number:g.number,url:x.url,title:x.title,branch:x.headRefName,repo:y,track:d,...h.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(I){h.ok=!1,h.action="failed",h.reason=I?.message||String(I)}if(Zt(),!f.some(h=>h.ok)){if(o===!0)for(let h of p)await Qo(h.repo,h.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let h of p)await es(h.repo,h.number,!1).catch(()=>{});return t.status(502).json({error:f.map(h=>`${h.repo}#${h.number}: ${h.reason}`).join("; "),results:f})}t.json({ok:!0,trackId:d.id,results:f})}catch(u){l=u;let d=u?.message||String(u),p=/invalid|required/i.test(d)?400:502;t.status(p).json({error:d})}finally{i&&c&&await ag(i,c,l?"failed":"completed",l).catch(()=>{})}});E.post("/api/git/prs/disarm-track",async(e,t)=>{let{trackId:n}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let r=await ie(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await pn()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await Qi(a.repo,a.number).catch(()=>null),c=await ns(a.repo).catch(()=>null);c&&await Pm(c,a.number).catch(()=>{}),i&&(await vn("auto-canceled",{number:a.number,url:a.url,title:a.title,branch:a.headRef,repo:c,track:r}),s.push({repo:a.repo,number:a.number}))}Zt(),t.json({ok:!0,trackId:r.id,canceled:s})}catch(r){let o=r?.message||String(r),s=/invalid|required/i.test(o)?400:502;t.status(s).json({error:o})}});E.post("/api/git/prs/open",async(e,t)=>{let{trackId:n,title:r,body:o,base:s,repos:a}=e.body||{};try{if(!n)return t.status(400).json({error:"trackId required"});let i=await ie(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),d,p=Array.isArray(a)?a.filter(Boolean):[];if(p.length)d=p.map(h=>{let g=u.find(y=>y.name===h||y.repo===h||y.base===h||y.dir===h);if(!g)throw new Error(`invalid repo "${h}" \u2014 not tagged on this Track`);return g});else if(d=await is(i),!d.length)return t.status(409).json({error:"no tagged repo has work to ship"});let f=[];for(let h of d)try{let g=await Bm(h.dir,{title:r,body:o,base:s}),y=h.repo||await _e(h.dir).catch(()=>null);y&&g.number&&await Lt({repo:y,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await vn("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:y??h.name}}),f.push({repo:h.name,slug:y??null,ok:!0,url:g.url,number:g.number})}catch(g){f.push({repo:h.name,slug:h.repo??null,ok:!1,error:g?.message||String(g)})}let w=f.filter(h=>h.ok);return w.length?t.json({ok:!0,multi:!0,results:f,url:w[0].url,number:w[0].number}):t.status(502).json({error:f.map(h=>`${h.repo}: ${h.error}`).join("; "),results:f})}let c=await Bm(i.cwd,{title:r,body:o,base:s}),l=await _e(i.cwd).catch(()=>null);l&&c.number&&await Lt({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await vn("opened",{number:c.number,url:c.url,title:r,track:i,branch:i.workspace?.branch,extra:{...l?{repo:l}:{}}}),t.json(c)}catch(i){let c=i?.message||String(i),l=/required|invalid/i.test(c)?400:502;t.status(l).json({error:c})}});E.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await is(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)})}});E.post("/api/tracks/:id/repos",async(e,t)=>{let{repo:n}=e.body||{};try{if(!n||typeof n!="string")return t.status(400).json({error:"repo (path or owner/name) required"});let r=await ap(e.params.id,n);t.json({ok:!0,added:{name:r.name,base:r.base,baseRef:r.baseRef??null,repo:r.repo??null}})}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/already tagged|needs a multi|not a usable|archived|required/i.test(o)?400:502;t.status(s).json({error:o})}});E.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await ip(e.params.id,e.params.name);t.json({ok:!0,...n})}catch(n){let r=n?.message||String(n),o=/track .* not found/i.test(r)?404:/has work|still running|last repo/i.test(r)?409:/needs a multi|not tagged/i.test(r)?400:502;t.status(o).json({error:r})}});E.post("/api/tracks/:id/reshape",async(e,t)=>{let{repos:n,skipPermissions:r}=e.body||{};try{let o=await Bg(e.params.id,n,{skipPermissions:r!==!1});t.status(o.finishedAt?200:202).json({ok:!0,...Pb(o)})}catch(o){let s=o?.message||String(o),a=o?.status||(/not found/i.test(s)?404:/has work|still running|already|running|archived|last repo/i.test(s)?409:/required|not a usable|tagged twice/i.test(s)?400:502);t.status(a).json({error:s})}});E.get("/api/tracks/:id/reshape",(e,t)=>{t.json(Pb(Gc(e.params.id))??{running:!1})});function Pb(e){return e?{running:!e.finishedAt,step:e.step,error:e.error??null,inPlace:e.inPlace===!0,added:e.added??[],removed:e.removed??[],scratch:e.scratch===!0,views:e.views??0,checkpoint:e.checkpoint??null,startedAt:e.startedAt??null,finishedAt:e.finishedAt??null}:null}E.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await ha(n,r),s=await _e(n).catch(()=>null),a=await lM({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(y=>y.base===n||s&&y.repo===s)??null,c=a.workspace?.kind==="multi",l=await PA(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?Ee.join("ci",i.name):"ci",d=Ee.join(a.cwd,".bostrat",u),p=Ee.join(".bostrat",u,`pr-${o.number}-fail.log`);await kt.promises.mkdir(d,{recursive:!0}),await kt.promises.writeFile(Ee.join(a.cwd,p),l.map(y=>`\u2550\u2550\u2550\u2550 ${y.name}${y.link?` \xB7 ${y.link}`:""} \u2550\u2550\u2550\u2550
760
764
  ${y.log??"(no fetchable log \u2014 see link)"}
761
765
  `).join(`
762
- `));let f=l.map(y=>y.name).join(", "),w=c&&i?` in the ${i.name}/ checkout`:"",m=await Bt(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${w}. Failing check${l.length===1?"":"s"}: ${f}. The failure log is at ${p} in this ${c?"workspace":"worktree"} \u2014 read it, fix the root cause${c&&i?` in ${i.name}/`:""}, run the relevant tests locally, then commit and push to update the PR.`,{kind:"ci-fix"}),g=s;g&&(await Ct({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await wS(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await kn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(y=>y.name)}}),t.json({ok:!0,leadBox:m.leadBox,queued:!!m.queued,checks:l.map(y=>y.name),log:p})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});T.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Qs(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await _e(n).catch(()=>null),a=await _O({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=$t(a.workspace).find(d=>d.base===n||s&&d.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await Bt(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 Ct({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await gS(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await kn("reconcile-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{base:o.baseRefName}}),t.json({ok:!0,leadBox:l.leadBox,queued:!!l.queued,base:o.baseRefName})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});T.post("/api/tracks/:id/pr-offer",async(e,t)=>{let{offerId:n,action:r}=e.body||{};try{let o=null;if(Array.isArray(e.body?.actions)){if(o=Gr.filter(a=>e.body.actions.includes(a)),!o.length)return t.status(400).json({error:"actions must include commit, rebase, push and/or pr"})}else if(r==="pr")o=["commit","push","pr"];else if(r==="push")o=["commit","push"];else if(r!=="dismiss")return t.status(400).json({error:'offerId and actions ["commit"|"rebase"|"push"|"pr"] (or action "dismiss") required'});if(!n)return t.status(400).json({error:"offerId required"});let s=o!=null&&e.body?.notify===!0;await eo(`pr:${e.params.id}:${n}`,async()=>{let a=await ie(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await q(a),c=i.find(d=>d.type==="pr.offered"&&d.payload?.offerId===n);if(!c)return t.status(404).json({error:"unknown offer"});if(i.some(d=>d.type==="pr.offer.answered"&&d.payload?.offerId===n))return t.status(409).json({error:"offer already answered"});if(o?.includes("pr")){let d=await Fy(a,c,{actions:o,notify:s});if(d)return t.json({ok:!0,offerId:n,action:"pr-exists",actions:o,notify:s,existingPr:d.pr})}let l=null;o&&(l=await Bt(a.id,Js(o,{branch:c.payload.branch,base:c.payload.base,toPr:c.payload.toPr||null,repos:c.payload.repos||null,offeredRebase:Array.isArray(c.payload.offered)&&c.payload.offered.includes("rebase")}),{kind:o.includes("pr")?"pr-go":"push-go"}));let u=o?o.includes("pr")?"pr":o.includes("push")?"push":o.includes("commit")?"commit":"rebase":"dismiss";await M({id:a.id,cwd:a.cwd},{type:"pr.offer.answered",actor:"user",source:"orchestrator",boxId:c.boxId,payload:{ts:Date.now(),offerId:n,action:u,actions:o,...s?{notify:!0}:{}}}),s&&Xw(a.id,{actions:o}),t.json({ok:!0,offerId:n,action:u,actions:o,notify:s,queued:!!l?.queued})})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/already answered|not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});T.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await ie(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await Uy(o,{offerId:n,choice:r});t.json({ok:!0,offerId:n,choice:r,queued:!!s?.queued})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/unknown offer/i.test(s)?404:/already answered|not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});var ll=e=>t=>({...t,url:j$(t,e.headers)});T.get("/api/views",async(e,t)=>{try{let n=await Yh({trackId:e.query.track||void 0});t.json({views:n.map(ll(e)),maxLive:no})}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.get("/api/views/:id",async(e,t)=>{let n=await NA(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:ll(e)(n),session:ia(n.slug)})});T.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await ie(n):null;if(!i&&s&&(i=(await he()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await Zh({trackId:i.id,name:r,cmd:o,cwd:i.cwd,serveCwd:s,port:a,box:i.leadBox,branch:i.workspace?.branch??null});t.json({ok:!0,view:ll(e)(c)})}catch(i){let c=i?.message||String(i),l=i?.status??(/cap reached/i.test(c)?409:/required|invalid|already owned|no free/i.test(c)?400:500);t.status(l).json({error:c})}});T.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:ll(e)(await PA(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});T.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:ll(e)(await DA(e.params.id))})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/cap reached|no known command/i.test(r)?409:500;t.status(o).json({error:r})}});T.delete("/api/views/:id",async(e,t)=>{try{t.json(await BA(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var k6=[["linear",ns,Wg],["jira",Zd,Ug]],Jy=new Map;T.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await Fg(),r={};for(let[o,s,a]of k6){let i=await s();if(!i){Jy.delete(o),r[o]={configured:!1};continue}let c=Jy.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},Jy.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)})}});T.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await Fg()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await gI(o),i=n?await ie(n):null;!i&&r&&(i=(await he()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Te.sep)))||null),i&&await M({id:i.id,cwd:i.cwd},{type:"ticket.flow.changed",actor:s==="user"?"user":"agent",source:"orchestrator",payload:{ts:Date.now(),set:{...o},flow:a}}).catch(()=>{}),t.json({ok:!0,flow:a})}catch(a){let i=a?.message||String(a);t.status(/unknown|nothing to set/i.test(i)?400:500).json({error:i})}});var ds=async(e,t)=>{let n=e?await ie(e):null;return!n&&t&&(n=(await he()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Te.sep)))||null),n};T.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await Ng()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});T.get("/api/roadmap",async(e,t)=>{try{t.json(await Pg())}catch(n){t.status(502).json({error:n?.message||String(n)})}});T.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await ds(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (circuit name or id) required"});let a=await Aa(o);await Vd(s,a,{source:"chat"}),t.json({ok:!0,trackId:s.id,circuit:a})}catch(s){let a=s?.message||String(s);t.status(/required|no circuit|names \d|no plane/i.test(a)?400:502).json({error:a})}});T.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await ds(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await Vd(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var IO=async(e,t,n)=>{if(e)return{ref:e,track:await ds(t,n)};let r=await ds(t,n),o=r?await Bg(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}};T.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 IO(o,n,r),l=await lI({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})}});T.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await IO(e.query.circuit,e.query.track,e.query.cwd);t.json(await Dg(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})}});T.post("/api/decisions/record",async(e,t)=>{let{trackId:n,cwd:r,title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l}=e.body||{};try{let u=await ds(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=await pI(u,{title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l});t.json({ok:!0,trackId:u.id,...d})}catch(u){let d=u?.message||String(u);t.status(/required/i.test(d)?400:502).json({error:d})}});T.get("/api/decisions",async(e,t)=>{try{let n=await ds(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await fI(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})}});T.post("/api/blueprints/tag",async(e,t)=>{let{trackId:n,cwd:r,itemIds:o}=e.body||{};try{let s=Array.isArray(o)?o.map(String):[];if(!s.length)return t.status(400).json({error:"itemIds required (BP-\u2026 ids)"});let a=await ds(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await Bg(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 uI(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})}});T.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await ie(n):null;if(!s&&r&&(s=(await he()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!o)return t.status(400).json({error:"ref (issue URL or key) required"});let a=await 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})}});T.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await ie(r):null;if(!o&&n&&(o=(await he()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+Te.sep)))||null),!o)return t.status(400).json({error:"track (or a cwd inside a Track workspace) required"});t.json({trackId:o.id,configured:await CI(),ticket:await Kn(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});T.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await Kn(e.params.id)})});T.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await ie(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})}});T.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await ty(e.params.id)})});var Op=e=>/no ticket linked|unknown offer|unknown state/i.test(e)?404:/already answered/i.test(e)?409:/required|no ticketing/i.test(e)?400:502;T.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await BI(e.params.id))}catch(n){let r=n?.message||String(n);t.status(Op(r)).json({error:r})}});T.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await ny(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(Op(r)).json({error:r})}});T.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await jI(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(Op(r)).json({error:r})}});T.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await ie(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await LI(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(Op(s)).json({error:s})}});T.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{t.json(await fg(e.params.id,n,r===!0))}catch(o){let s=o?.message||String(o),a=/not found|unknown offer/.test(s)?404:/already answered/.test(s)||/mid-turn/.test(s)?409:500;t.status(a).json({error:s})}});T.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ie(n):null;if(!s&&r&&(s=(await he()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await UI(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})}});T.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await FI()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});T.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await ie(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await HI(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})}});T.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await uc({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.get("/api/mocks/:id",async(e,t)=>{let n=await pr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var ul={dotfiles:"allow"};T.get("/api/mocks/:id/png",async(e,t)=>{let n=await pr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=pn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=cc(n,r,"png");if(!o)return t.status(404).json({error:"no image for this version (poster extraction failed)"});t.set("cache-control","private, max-age=31536000, immutable"),t.sendFile(o,ul,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});T.get("/api/mocks/:id/media",async(e,t)=>{let n=await pr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=pn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=cc(n,r,"video");if(!o)return t.status(404).json({error:"this version has no video (image or html sourced)"});t.set("cache-control","private, max-age=31536000, immutable"),t.sendFile(o,ul,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});T.get("/api/mocks/:id/html",async(e,t)=>{let n=await pr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=pn(n,e.query.v??null);if(!r?.htmlRel)return t.status(404).json({error:"this version has no HTML source (image-sourced)"});t.set("content-security-policy","sandbox"),t.sendFile(Yt(n,r.v).html,ul,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});T.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&md(n)?n:null,o=n&&!r?n:null,s=n?e.query:e.body||{},{trackId:a,name:i,cwd:c,width:l,group:u}=s;try{let d=a?await ie(a):null;if(!d&&c&&(d=(await he()).find(m=>m.cwd&&(c===m.cwd||c.startsWith(m.cwd+Te.sep)))||null),!d)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let p=(d.boxes||[]).find(w=>w.name===d.leadBox),f=await QA({trackId:d.id,name:i,html:n?null:s.html,image:r,video:o,cwd:d.cwd,width:l,group:u,box:d.leadBox,agent:p?.agent||null});t.json({ok:!0,mock:f})}catch(d){let p=d?.message||String(d);t.status(/required|invalid|must be/i.test(p)?400:500).json({error:p})}});T.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&md(n)?n:null;try{let o=await eE(e.params.id,{html:n?null:(e.body||{}).html,image:r,video:n&&!r?n:null,width:n?e.query.width:(e.body||{}).width});t.json({ok:!0,mock:o})}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required|invalid|must be/i.test(s)?400:500;t.status(a).json({error:s})}});T.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await rE(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await Bt(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})}});T.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await xE(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await oE(e.params.id),...n.length?{danglingFlows:n}:{}})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});T.get("/api/flows",async(e,t)=>{try{t.json({flows:await wE({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.get("/api/flows/:id",async(e,t)=>{let n=await gE(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});T.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await ie(n):null;if(!a&&s&&(a=(await he()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await yE({trackId:a.id,name:r,steps:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,flow:c})}catch(a){let i=a?.message||String(a),c=/already exists/i.test(i)?409:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(i)?400:500;t.status(c).json({error:i})}});T.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await bE(e.params.id,{steps:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(r)?400:500;t.status(o).json({error:r})}});T.delete("/api/flows/:id",async(e,t)=>{try{t.json(await kE(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});T.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await he(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+Te.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await $E({trackId:n,status:e.query.status||void 0});t.json({runbooks:r,...o?{fleetDegraded:!0}:{}})}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.get("/api/runbooks/:id",async(e,t)=>{let n=await pw(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});T.get("/api/runbooks/:id/md",async(e,t)=>{let n=await pw(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=_E(n,e.query.v??null);if(!r)return t.status(404).json({error:"no such version"});if(t.set("content-security-policy","sandbox"),t.set("cache-control","private, max-age=31536000, immutable"),t.type("text/markdown; charset=utf-8"),n.remote){let o=await RE(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(wr(n,r.v),ul,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});T.get("/api/loops",async(e,t)=>{t.json(await Gi())});T.post("/api/loops/report",async(e,t)=>{let{outcome:n,note:r,cwd:o}=e.body||{};if(!["ok","acted","attention"].includes(n))return t.status(400).json({error:"outcome must be one of ok | acted | attention"});if(!o)return t.status(400).json({error:"cwd required"});let a=(await he()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+Te.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await Gi();if(i.source!=="plane")return t.status(503).json({error:i.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${i.error||"no detail"})`});let c=i.loops.find(u=>u.trackId===a.id);if(!c)return t.status(404).json({error:`Track "${a.name}" is not a loop's run Track \u2014 nothing to report on`});let l=await xh({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})});T.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ie(n):null;if(!s&&r&&(s=(await he()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await K$(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var ja=async(e,t)=>{let n=e?await ie(e):null;return!n&&t&&(n=(await he()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Te.sep)))||null),n};T.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await ja(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,result:await VT(s,o,{ship:{changedRepos:Ko}})})}catch(s){t.status(400).json({error:s?.message||String(s)})}});T.post("/api/followups/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await ja(n,r);if(!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:s.id,proposal:await YT(s,o)})}catch(s){let a=s?.message||String(s);t.status(/unreachable/i.test(a)?503:400).json({error:a})}});T.get("/api/followups",async(e,t)=>{let n=typeof e.query?.cwd=="string"?e.query.cwd:null,r=await ja(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:_h,...await tA(r)})});var hO=new Set(["reconcile","fixing-ci","rebase","merge"]);T.get("/api/status",async(e,t)=>{let n=await ja(null,typeof e.query?.cwd=="string"?e.query.cwd:null).catch(()=>null);if(!n)return t.status(400).json({error:"a cwd inside a Track workspace is required"});t.json({ok:!0,trackId:n.id,status:n.status})});T.post("/api/status",async(e,t)=>{try{let{trackId:n,cwd:r,phase:o,summary:s,scope:a,reason:i}=e.body||{},c=await ja(n,r);if(!c)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let l=o==="fix-ci"?"fixing-ci":o;if(l!=null&&!hO.has(l))throw new Error(`phase must be one of ${[...hO].join(" | ")}`);let u=s==null?null:String(s).trim();if(u&&u.length>120)throw new Error("summary is too long (cap is 120 characters)");let d=f6();await M(c,{type:"track.phase.changed",actor:"agent",source:"cli",boxId:c.leadBox,provider:c.boxes?.find(p=>p.name===c.leadBox)?.agent??null,payload:{ts:Date.now(),phase:l||null,phaseId:d,summary:u,scope:a&&typeof a=="object"?a:null,...l?{}:{reason:i||"completed"}}}),t.json({ok:!0,trackId:c.id,phase:l||null,phaseId:d})}catch(n){t.status(400).json({error:n?.message||String(n)})}});T.post("/api/tracks/:id/followup-offer",async(e,t)=>{let{offerId:n,followupId:r,armId:o,promoted:s}=e.body||{};try{let a=await ie(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await ZT(a,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null},{sayToLead:Bt,unarchiveTrack:Nd})})}catch(a){let i=a?.message||String(a),c=a?.code==="removed"?410:/unknown offer/i.test(i)?404:/already answered/i.test(i)?409:/required|not on this card/i.test(i)?400:/unreachable/i.test(i)?503:502;t.status(c).json({error:i})}});T.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await JT(n,e.body?.armId)})}catch(n){let r=n?.message||String(n);t.status(/unknown/i.test(r)?404:400).json({error:r})}});T.post("/api/tracks/:id/followup-create-offer",async(e,t)=>{let{proposalId:n,accept:r,followupId:o}=e.body||{};try{let s=await ie(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await XT(s,n,r===!0,{followupId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal/i.test(a)?404:/already answered/i.test(a)?409:400).json({error:a})}});Je.on("event",e=>{let t=e?.type==="pr.state.changed"?e.payload?.change:null;if(!t||!e.trackId)return;let n=t==="opened"?"pr.opened":t==="ci-fixed"?"checks.green":null,r=e.payload||{},o={repo:r.repo??null,prNumber:r.number??null,prTitle:r.title??null,prUrl:r.url??null};!n&&t!=="pushed"||ie(e.trackId).then(async s=>{if(s&&(n&&await Ji(s,n,o),t==="opened"||t==="pushed")){let a=eA(await q(s).catch(()=>[]));a&&await Ji(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var $O=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await ie(n):null;if(!s&&r&&(s=(await he()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Te.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await Gi();if(a.source!=="plane")return t.status(503).json({error:a.source==="unconfigured"?"this node isn't linked to a plane \u2014 loops live in the plane":`plane unreachable (${a.error||"no detail"})`}),null;let i;try{i=V$(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}};T.post("/api/loops/propose-update",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await $O(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await J$(s.track,s.loop,e.body?.patch)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});T.post("/api/loops/propose-delete",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await $O(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await Y$(s.track,s.loop,e.body?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});T.post("/api/planning/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o,scope:s}=e.body||{},a=await ja(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i;try{i=await Pg()}catch(c){return t.status(503).json({error:c?.message||String(c)})}try{let c=s==="circuit"?_y:el;t.json({ok:!0,trackId:a.id,proposal:await iR(a,o,i,{allow:c})})}catch(c){t.status(400).json({error:c?.message||String(c)})}});var tb=e=>/unknown proposal/i.test(e)?404:/already answered/i.test(e)?409:400;T.post("/api/tracks/:id/planning-offer",async(e,t)=>{let{proposalId:n,action:r,results:o}=e.body||{};try{let s=await ie(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await cR(s,n,r,{results:o||[]})})}catch(s){let a=s?.message||String(s);t.status(tb(a)).json({error:a})}});T.post("/api/tracks/:id/loop-update-offer",async(e,t)=>{let{proposalId:n,action:r,nextFireAt:o}=e.body||{};try{let s=await ie(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await Z$(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(tb(a)).json({error:a})}});T.post("/api/tracks/:id/loop-delete-offer",async(e,t)=>{let{proposalId:n,action:r}=e.body||{};try{let o=await ie(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await Q$(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(tb(s)).json({error:s})}});T.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 ie(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await G$(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})}});T.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await ie(n):null;if(!a&&s&&(a=(await he()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Te.sep)))||null),!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=(a.boxes||[]).find(l=>l.name===a.leadBox),c=await OE({trackId:a.id,trackName:a.name,name:r,md:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,runbook:c})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|over the|secret VALUE/i.test(i)?400:500).json({error:i})}});T.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await ME(e.params.id,{md:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/required|invalid|over the|secret VALUE/i.test(r)?400:500;t.status(o).json({error:r})}});T.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await CE(e.params.id,(e.body||{}).status)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/must be/i.test(r)?400:500;t.status(o).json({error:r})}});T.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await NE(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});T.get("/api/changelog/draft",async(e,t)=>{try{let n=fR(e.query.since||null);t.json({since:n,repos:$y(),...await mR(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var RO=async({trackId:e,cwd:t})=>{let n=e?await ie(e):null;return!n&&t&&(n=(await he()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+Te.sep)))||null),n};T.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await RO({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 hR(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})}});T.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await RO({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 wR(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var x6=120,Yy=400,Ba=null,wO=null;T.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>Yy)return t.status(400).json({error:`message is ${i.length} chars \u2014 over the ${Yy} cap; a notification is a nudge, put the detail in chat`});let c=dc(`${n||""}
763
- ${i}`);if(c.length)return t.status(400).json({error:`notification appears to contain a secret VALUE (${c.join(", ")}) \u2014 notifications ship off-box; never put a credential in one`});let l=a?await ie(a):null;if(!l&&s&&(l=(await he()).find(w=>w.cwd&&(s===w.cwd||s.startsWith(w.cwd+Te.sep)))||null),!l)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=(l.boxes||[]).find(f=>f.name===l.leadBox),d=(f,w)=>String(f).replace(/\s+/g," ").trim().slice(0,w),p={title:n?d(n,x6):l.name,body:d(i,Yy),urgency:o==="high"?"high":"normal",trackName:l.name,ts:Date.now()};await M(l,{type:"notify.raised",actor:"agent",boxId:l.leadBox??null,provider:u?.agent||null,payload:p}),t.json({ok:!0,notification:p,delivered:Ba?Ba.status().connected:null})}catch(i){t.status(500).json({error:i?.message||String(i)})}});T.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 lO(e.body,e.headers["content-type"]))}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});T.get("/api/dictation/glossary",async(e,t)=>{t.json({configured:!!await Lc(),terms:await zy(),problem:await cO()})});T.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 iO(n,r)})});T.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await ie(e.params.id))return t.status(404).json({error:"track not found"});t.json(await uO())});T.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await ie(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 dO())}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});T.post("/api/tracks/:id/voice-chat/usage",async(e,t)=>{try{let n=await ie(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 pO(n,{model:r,usage:o,seconds:s})})}catch(n){t.status(n?.status||500).json({error:n?.message||String(n)})}});T.post("/api/tracks",async(e,t)=>{let{name:n,cwd:r,repo:o,repos:s,agent:a,model:i,skipPermissions:c,ticket:l,circuit:u}=e.body||{};try{let d=await Md({name:n,cwd:r,repo:o,repos:s,agent:a,model:i,skipPermissions:c!==!1}),p=null;if(l)try{await Ia(d,l,{source:"create"})}catch(w){p=w?.message||String(w)}let f=null;if(u)try{await Vd(d,await Aa(u),{source:"picker"})}catch(w){f=w?.message||String(w)}t.json({ok:!0,track:d,...p?{ticketWarning:p}:{},...f?{circuitWarning:f}:{}})}catch(d){let p=d?.message||String(d);t.status(/required|unknown agent|invalid|must be/i.test(p)?400:500).json({error:p})}});T.get("/api/tracks/:id",async(e,t)=>{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:OO(Ta(e.params.id)),subtasks:es(e.params.id).map(dl),pendingOffers:await Kw(n)})});T.delete("/api/tracks/:id",async(e,t)=>{try{let n=await ig(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await ty(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})}});T.post("/api/tracks/:id/archive",async(e,t)=>{try{t.json({ok:!0,track:await Zo(e.params.id)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/already archived/i.test(r)?409:500).json({error:r})}});T.post("/api/tracks/:id/rename",async(e,t)=>{try{t.json({ok:!0,track:await ug(e.params.id,e.body?.name)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/loop run Tracks/i.test(r)?409:/required|too long/i.test(r)?400:500;t.status(o).json({error:r})}});T.post("/api/tracks/:id/unarchive",async(e,t)=>{try{t.json({ok:!0,track:await Nd(e.params.id,{freshSession:e.body?.freshSession===!0})})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/not archived/i.test(r)?409:500).json({error:r})}});T.get("/api/tracks/:id/messages",async(e,t)=>{let n=await Id(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json(n)});T.get("/api/tracks/:id/events",async(e,t)=>{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.set({"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"}),t.flushHeaders();let r=i=>t.write(`id: ${i.seq}
766
+ `));let f=l.map(y=>y.name).join(", "),w=c&&i?` in the ${i.name}/ checkout`:"",h=await Ht(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${w}. Failing check${l.length===1?"":"s"}: ${f}. The failure log is at ${p} in this ${c?"workspace":"worktree"} \u2014 read it, fix the root cause${c&&i?` in ${i.name}/`:""}, run the relevant tests locally, then commit and push to update the PR.`,{kind:"ci-fix"}),g=s;g&&(await Lt({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await eA(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await vn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(y=>y.name)}}),t.json({ok:!0,leadBox:h.leadBox,queued:!!h.queued,checks:l.map(y=>y.name),log:p})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});E.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await ha(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await _e(n).catch(()=>null),a=await lM({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(d=>d.base===n||s&&d.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await Ht(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 Lt({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await tA(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await vn("reconcile-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{base:o.baseRefName}}),t.json({ok:!0,leadBox:l.leadBox,queued:!!l.queued,base:o.baseRefName})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});E.post("/api/tracks/:id/pr-offer",async(e,t)=>{let{offerId:n,action:r}=e.body||{};try{let o=null;if(Array.isArray(e.body?.actions)){if(o=eo.filter(a=>e.body.actions.includes(a)),!o.length)return t.status(400).json({error:"actions must include commit, rebase, push and/or pr"})}else if(r==="pr")o=["commit","push","pr"];else if(r==="push")o=["commit","push"];else if(r!=="dismiss")return t.status(400).json({error:'offerId and actions ["commit"|"rebase"|"push"|"pr"] (or action "dismiss") required'});if(!n)return t.status(400).json({error:"offerId required"});let s=o!=null&&e.body?.notify===!0;await co(`pr:${e.params.id}:${n}`,async()=>{let a=await ie(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await K(a),c=i.find(d=>d.type==="pr.offered"&&d.payload?.offerId===n);if(!c)return t.status(404).json({error:"unknown offer"});if(i.some(d=>d.type==="pr.offer.answered"&&d.payload?.offerId===n))return t.status(409).json({error:"offer already answered"});if(o?.includes("pr")){let d=await kb(a,c,{actions:o,notify:s});if(d)return t.json({ok:!0,offerId:n,action:"pr-exists",actions:o,notify:s,existingPr:d.pr})}let l=null;o&&(l=await Ht(a.id,ua(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 C({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&&Rg(a.id,{actions:o}),t.json({ok:!0,offerId:n,action:u,actions:o,notify:s,queued:!!l?.queued})})}catch(o){let s=o?.message||String(o),a=/required|invalid/i.test(s)?400:/already answered|not found|not running|archived/i.test(s)?409:502;t.status(a).json({error:s})}});E.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await ie(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await xb(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 El=e=>t=>({...t,url:kR(t,e.headers)});E.get("/api/views",async(e,t)=>{try{let n=await Rw({trackId:e.query.track||void 0});t.json({views:n.map(El(e)),maxLive:uo})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/views/:id",async(e,t)=>{let n=await yE(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:El(e)(n),session:va(n.slug)})});E.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await ie(n):null;if(!i&&s&&(i=(await we()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Ee.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let c=await Mw({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:El(e)(c)})}catch(i){let c=i?.message||String(i),l=i?.status??(/cap reached/i.test(c)?409:/required|invalid|already owned|no free/i.test(c)?400:500);t.status(l).json({error:c})}});E.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:El(e)(await bE(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:El(e)(await kE(e.params.id))})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/cap reached|no known command/i.test(r)?409:500;t.status(o).json({error:r})}});E.delete("/api/views/:id",async(e,t)=>{try{t.json(await xE(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var aG=[["linear",ks,Sy],["jira",Rp,xy]],$b=new Map;E.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await ky(),r={};for(let[o,s,a]of aG){let i=await s();if(!i){$b.delete(o),r[o]={configured:!1};continue}let c=$b.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},$b.set(o,c)}r[o]={...c.body,flow:n},o==="jira"&&i.tokenExpiresAt&&(r[o].tokenExpiresAt=i.tokenExpiresAt)}t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await ky()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await QI(o),i=n?await ie(n):null;!i&&r&&(i=(await we()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Ee.sep)))||null),i&&await C({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 $s=async(e,t)=>{let n=e?await ie(e):null;return!n&&t&&(n=(await we()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Ee.sep)))||null),n};E.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await hy()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});E.get("/api/roadmap",async(e,t)=>{try{t.json(await my())}catch(n){t.status(502).json({error:n?.message||String(n)})}});E.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await $s(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 Ua(o);await Ep(s,a,{source:"chat"}),t.json({ok:!0,trackId:s.id,circuit:a})}catch(s){let a=s?.message||String(s);t.status(/required|no circuit|names \d|no plane/i.test(a)?400:502).json({error:a})}});E.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await $s(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await Ep(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var uM=async(e,t,n)=>{if(e)return{ref:e,track:await $s(t,n)};let r=await $s(t,n),o=r?await gy(r.id):null;if(!o)throw new Error(r?"this Track isn't in a circuit \u2014 pass --circuit <name-or-id> (or link one first: bostrat-circuit link \u2026)":"run from inside a Track workspace, or pass --circuit <name-or-id>");return{ref:o,track:r}};E.post("/api/blueprints/publish",async(e,t)=>{let{trackId:n,cwd:r,circuit:o,newCircuit:s,name:a,markdown:i}=e.body||{};try{if(!i||!String(i).trim())return t.status(400).json({error:"markdown required"});let{ref:c}=s?{ref:null}:await uM(o,n,r),l=await KI({circuitRef:c,newCircuitName:s,name:a,markdown:i});t.json({ok:!0,...l})}catch(c){let l=c?.message||String(c);t.status(/required|no circuit|names \d|no plane|isn't in a circuit|run from inside/i.test(l)?400:502).json({error:l})}});E.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await uM(e.query.circuit,e.query.track,e.query.cwd);t.json(await wy(n))}catch(n){let r=n?.message||String(n);t.status(/no blueprint|no circuit|isn't in a circuit|run from inside|names \d/i.test(r)?404:502).json({error:r})}});E.post("/api/decisions/record",async(e,t)=>{let{trackId:n,cwd:r,title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l}=e.body||{};try{let u=await $s(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=await VI(u,{title:o,context:s,decision:a,summary:i,alternatives:c,supersedesId:l});t.json({ok:!0,trackId:u.id,...d})}catch(u){let d=u?.message||String(u);t.status(/required/i.test(d)?400:502).json({error:d})}});E.get("/api/decisions",async(e,t)=>{try{let n=await $s(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await JI(n.id))}catch(n){let r=n?.message||String(n);t.status(/no plane|required|run from inside/i.test(r)?400:502).json({error:r})}});E.post("/api/blueprints/tag",async(e,t)=>{let{trackId:n,cwd:r,itemIds:o}=e.body||{};try{let s=Array.isArray(o)?o.map(String):[];if(!s.length)return t.status(400).json({error:"itemIds required (BP-\u2026 ids)"});let a=await $s(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await gy(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 GI(a,i,s);t.json({ok:!0,trackId:a.id,...c})}catch(s){let a=s?.message||String(s);t.status(/unknown\/unbindable|required|no blueprint|isn't in a circuit/i.test(a)?400:502).json({error:a})}});E.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await ie(n):null;if(!s&&r&&(s=(await we()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+Ee.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 qa(s,o,{source:n?"api":"cli"});t.json({ok:!0,trackId:s.id,ticket:a})}catch(s){let a=s?.message||String(s);t.status(/not a Linear|not found|no ticketing|required/i.test(a)?400:502).json({error:a})}});E.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await ie(r):null;if(!o&&n&&(o=(await we()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+Ee.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 m$(),ticket:await zn(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});E.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await zn(e.params.id)})});E.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await qa(n,(e.body||{}).ref,{source:"api"});t.json({ok:!0,ticket:r})}catch(n){let r=n?.message||String(n);t.status(/not a Linear|not found|no ticketing|required/i.test(r)?400:502).json({error:r})}});E.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await Py(e.params.id)})});var lf=e=>/no ticket linked|unknown offer|unknown state/i.test(e)?404:/already answered/i.test(e)?409:/required|no ticketing/i.test(e)?400:502;E.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await b$(e.params.id))}catch(n){let r=n?.message||String(n);t.status(lf(r)).json({error:r})}});E.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await Dy(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(lf(r)).json({error:r})}});E.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await k$(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(lf(r)).json({error:r})}});E.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await ie(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await x$(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(lf(s)).json({error:s})}});E.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{t.json(await Vg(e.params.id,n,r===!0))}catch(o){let s=o?.message||String(o),a=/not found|unknown offer/.test(s)?404:/already answered/.test(s)||/mid-turn/.test(s)?409:500;t.status(a).json({error:s})}});E.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ie(n):null;if(!s&&r&&(s=(await we()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Ee.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){let a=s?.message||String(s);t.status(/no ticketing|are off|needs an epic|too many|required/i.test(a)?400:502).json({error:a})}});E.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await v$()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});E.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await ie(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await A$(s,n,r===!0,{teamId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal|unknown team/i.test(a)?404:/already answered/i.test(a)?409:/required|no ticketing|pick one/i.test(a)?400:502).json({error:a})}});E.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await _c({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/mocks/:id",async(e,t)=>{let n=await mr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var _l={dotfiles:"allow"};E.get("/api/mocks/:id/png",async(e,t)=>{let n=await mr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=hn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Tc(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,_l,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});E.get("/api/mocks/:id/media",async(e,t)=>{let n=await mr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=hn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Tc(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,_l,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});E.get("/api/mocks/:id/html",async(e,t)=>{let n=await mr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=hn(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(en(n,r.v).html,_l,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});E.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Dd(n)?n:null,o=n&&!r?n:null,s=n?e.query:e.body||{},{trackId:a,name:i,cwd:c,width:l,group:u}=s;try{let d=a?await ie(a):null;if(!d&&c&&(d=(await we()).find(h=>h.cwd&&(c===h.cwd||c.startsWith(h.cwd+Ee.sep)))||null),!d)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let p=(d.boxes||[]).find(w=>w.name===d.leadBox),f=await DE({trackId:d.id,name:i,html:n?null:s.html,image:r,video:o,cwd:d.cwd,width:l,group:u,box:d.leadBox,agent:p?.agent||null});t.json({ok:!0,mock:f})}catch(d){let p=d?.message||String(d);t.status(/required|invalid|must be/i.test(p)?400:500).json({error:p})}});E.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Dd(n)?n:null;try{let o=await BE(e.params.id,{html:n?null:(e.body||{}).html,image:r,video:n&&!r?n:null,width:n?e.query.width:(e.body||{}).width});t.json({ok:!0,mock:o})}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required|invalid|must be/i.test(s)?400:500;t.status(a).json({error:s})}});E.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await FE(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await Ht(n.trackId,`Design decision: go with "${n.name}" (mock:${n.id})${o} \u2014 proceed with this design.`,{kind:"mock-picked"}).catch(()=>{}),t.json({ok:!0,mock:n,siblings:r})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/nothing to pick/i.test(r)?409:500;t.status(o).json({error:r})}});E.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await o_(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await UE(e.params.id),...n.length?{danglingFlows:n}:{}})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.get("/api/flows",async(e,t)=>{try{t.json({flows:await QE({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/flows/:id",async(e,t)=>{let n=await e_(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});E.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await ie(n):null;if(!a&&s&&(a=(await we()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Ee.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,name:r,steps:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,flow:c})}catch(a){let i=a?.message||String(a),c=/already exists/i.test(i)?409:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(i)?400:500;t.status(c).json({error:i})}});E.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await n_(e.params.id,{steps:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/required|invalid|no mock|ambiguous|over \d+ chars|must be|no captured/i.test(r)?400:500;t.status(o).json({error:r})}});E.delete("/api/flows/:id",async(e,t)=>{try{t.json(await r_(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await we(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+Ee.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await p_({trackId:n,status:e.query.status||void 0});t.json({runbooks:r,...o?{fleetDegraded:!0}:{}})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/runbooks/:id",async(e,t)=>{let n=await zw(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});E.get("/api/runbooks/:id/md",async(e,t)=>{let n=await zw(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=u_(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 f_(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(br(n,r.v),_l,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});E.get("/api/loops",async(e,t)=>{t.json(await lc())});E.post("/api/loops/report",async(e,t)=>{let{outcome:n,note:r,cwd:o}=e.body||{};if(!["ok","acted","attention"].includes(n))return t.status(400).json({error:"outcome must be one of ok | acted | attention"});if(!o)return t.status(400).json({error:"cwd required"});let a=(await we()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+Ee.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await lc();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 tw({loopId:c.id,outcome:n,note:r});if(!l.ok)return t.status(l.status||503).json({error:l.error||"report failed"});t.json({ok:!0,loop:{id:c.id,name:c.name},run:l.run})});E.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ie(n):null;if(!s&&r&&(s=(await we()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Ee.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 _R(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var ei=async(e,t)=>{let n=e?await ie(e):null;return!n&&t&&(n=(await we()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Ee.sep)))||null),n};E.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await ei(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 MT(s,o,{ship:{changedRepos:is}})})}catch(s){t.status(400).json({error:s?.message||String(s)})}});E.post("/api/followups/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await ei(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 NT(s,o)})}catch(s){let a=s?.message||String(s);t.status(/unreachable/i.test(a)?503:400).json({error:a})}});E.get("/api/followups",async(e,t)=>{let n=typeof e.query?.cwd=="string"?e.query.cwd:null,r=await ei(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:iw,...await LT(r)})});var XO=new Set(["reconcile","fixing-ci","rebase","merge"]);E.get("/api/status",async(e,t)=>{let n=await ei(null,typeof e.query?.cwd=="string"?e.query.cwd:null).catch(()=>null);if(!n)return t.status(400).json({error:"a cwd inside a Track workspace is required"});t.json({ok:!0,trackId:n.id,status:n.status})});E.post("/api/status",async(e,t)=>{try{let{trackId:n,cwd:r,phase:o,summary:s,scope:a,reason:i}=e.body||{},c=await ei(n,r);if(!c)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let l=o==="fix-ci"?"fixing-ci":o;if(l!=null&&!XO.has(l))throw new Error(`phase must be one of ${[...XO].join(" | ")}`);let u=s==null?null:String(s).trim();if(u&&u.length>120)throw new Error("summary is too long (cap is 120 characters)");let d=QK();await C(c,{type:"track.phase.changed",actor:"agent",source:"cli",boxId:c.leadBox,provider:c.boxes?.find(p=>p.name===c.leadBox)?.agent??null,payload:{ts:Date.now(),phase:l||null,phaseId:d,summary:u,scope:a&&typeof a=="object"?a:null,...l?{}:{reason:i||"completed"}}}),t.json({ok:!0,trackId:c.id,phase:l||null,phaseId:d})}catch(n){t.status(400).json({error:n?.message||String(n)})}});E.post("/api/tracks/:id/followup-offer",async(e,t)=>{let{offerId:n,followupId:r,armId:o,promoted:s}=e.body||{};try{let a=await ie(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await DT(a,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null},{sayToLead:Ht,unarchiveTrack:up})})}catch(a){let i=a?.message||String(a),c=a?.code==="removed"?410:/unknown offer/i.test(i)?404:/already answered/i.test(i)?409:/required|not on this card/i.test(i)?400:/unreachable/i.test(i)?503:502;t.status(c).json({error:i})}});E.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await CT(n,e.body?.armId)})}catch(n){let r=n?.message||String(n);t.status(/unknown/i.test(r)?404:400).json({error:r})}});E.post("/api/tracks/:id/followup-create-offer",async(e,t)=>{let{proposalId:n,accept:r,followupId:o}=e.body||{};try{let s=await ie(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await PT(s,n,r===!0,{followupId:o||null})})}catch(s){let a=s?.message||String(s);t.status(/unknown proposal/i.test(a)?404:/already answered/i.test(a)?409:400).json({error:a})}});Je.on("event",e=>{let t=e?.type==="pr.state.changed"?e.payload?.change:null;if(!t||!e.trackId)return;let n=t==="opened"?"pr.opened":t==="ci-fixed"?"checks.green":null,r=e.payload||{},o={repo:r.repo??null,prNumber:r.number??null,prTitle:r.title??null,prUrl:r.url??null};!n&&t!=="pushed"||ie(e.trackId).then(async s=>{if(s&&(n&&await pc(s,n,o),t==="opened"||t==="pushed")){let a=jT(await K(s).catch(()=>[]));a&&await pc(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var dM=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await ie(n):null;if(!s&&r&&(s=(await we()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Ee.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await lc();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=RR(a.loops,o)}catch(c){return t.status(/matches \d+ loops/.test(c.message)?409:404).json({error:c.message}),null}return{track:s,loop:i}};E.post("/api/loops/propose-update",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await dM(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await OR(s.track,s.loop,e.body?.patch)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});E.post("/api/loops/propose-delete",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await dM(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await MR(s.track,s.loop,e.body?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});E.post("/api/planning/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o,scope:s}=e.body||{},a=await ei(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i;try{i=await my()}catch(c){return t.status(503).json({error:c?.message||String(c)})}try{let c=s==="circuit"?ib:wl;t.json({ok:!0,trackId:a.id,proposal:await WR(a,o,i,{allow:c})})}catch(c){t.status(400).json({error:c?.message||String(c)})}});var Db=e=>/unknown proposal/i.test(e)?404:/already answered/i.test(e)?409:400;E.post("/api/tracks/:id/planning-offer",async(e,t)=>{let{proposalId:n,action:r,results:o}=e.body||{};try{let s=await ie(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await qR(s,n,r,{results:o||[]})})}catch(s){let a=s?.message||String(s);t.status(Db(a)).json({error:a})}});E.post("/api/tracks/:id/loop-update-offer",async(e,t)=>{let{proposalId:n,action:r,nextFireAt:o}=e.body||{};try{let s=await ie(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await NR(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(Db(a)).json({error:a})}});E.post("/api/tracks/:id/loop-delete-offer",async(e,t)=>{let{proposalId:n,action:r}=e.body||{};try{let o=await ie(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await PR(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(Db(s)).json({error:s})}});E.post("/api/tracks/:id/loop-create-offer",async(e,t)=>{let{proposalId:n,accept:r,loopId:o,nextFireAt:s}=e.body||{};try{let a=await ie(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await IR(a,n,r===!0,{loopId:o||null,nextFireAt:s??null})})}catch(a){let i=a?.message||String(a);t.status(/unknown proposal/i.test(i)?404:/already answered/i.test(i)?409:400).json({error:i})}});E.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await ie(n):null;if(!a&&s&&(a=(await we()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Ee.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 h_({trackId:a.id,trackName:a.name,name:r,md:o,cwd:a.cwd,box:a.leadBox,agent:i?.agent||null});t.json({ok:!0,runbook:c})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|over the|secret VALUE/i.test(i)?400:500).json({error:i})}});E.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await m_(e.params.id,{md:n,note:r})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/required|invalid|over the|secret VALUE/i.test(r)?400:500;t.status(o).json({error:r})}});E.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await w_(e.params.id,(e.body||{}).status)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/must be/i.test(r)?400:500;t.status(o).json({error:r})}});E.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await g_(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.get("/api/changelog/draft",async(e,t)=>{try{let n=JR(e.query.since||null);t.json({since:n,repos:lb(),...await YR(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var pM=async({trackId:e,cwd:t})=>{let n=e?await ie(e):null;return!n&&t&&(n=(await we()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+Ee.sep)))||null),n};E.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await pM({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 XR(a,{md:n,day:r})})}catch(a){let i=a?.message||String(a);t.status(/required|invalid|no `- `|over the|secret VALUE|mentions "/i.test(i)?400:500).json({error:i})}});E.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await pM({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 ZR(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var iG=120,Rb=400,Qa=null,ZO=null;E.post("/api/notify",async(e,t)=>{let{title:n,body:r,urgency:o,cwd:s,trackId:a}=e.body||{};try{let i=typeof r=="string"?r.trim():"";if(!i)return t.status(400).json({error:"body (the message) required"});if(i.length>Rb)return t.status(400).json({error:`message is ${i.length} chars \u2014 over the ${Rb} cap; a notification is a nudge, put the detail in chat`});let c=Ic(`${n||""}
767
+ ${i}`);if(c.length)return t.status(400).json({error:`notification appears to contain a secret VALUE (${c.join(", ")}) \u2014 notifications ship off-box; never put a credential in one`});let l=a?await ie(a):null;if(!l&&s&&(l=(await we()).find(w=>w.cwd&&(s===w.cwd||s.startsWith(w.cwd+Ee.sep)))||null),!l)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let u=(l.boxes||[]).find(f=>f.name===l.leadBox),d=(f,w)=>String(f).replace(/\s+/g," ").trim().slice(0,w),p={title:n?d(n,iG):l.name,body:d(i,Rb),urgency:o==="high"?"high":"normal",trackName:l.name,ts:Date.now()};await C(l,{type:"notify.raised",actor:"agent",boxId:l.leadBox??null,provider:u?.agent||null,payload:p}),t.json({ok:!0,notification:p,delivered:Qa?Qa.status().connected:null})}catch(i){t.status(500).json({error:i?.message||String(i)})}});E.post("/api/dictation",async(e,t)=>{if(!Buffer.isBuffer(e.body)||e.body.length===0)return t.status(400).json({error:"expected a raw audio body"});try{t.json(await KO(e.body,e.headers["content-type"]))}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});E.get("/api/dictation/glossary",async(e,t)=>{t.json({configured:!!await tl(),terms:await _b(),problem:await qO()})});E.post("/api/dictation/learn",async(e,t)=>{let{transcript:n,finalText:r}=e.body||{};if(typeof n!="string"||typeof r!="string")return t.status(400).json({error:"transcript and finalText are required"});t.json({learned:await WO(n,r)})});E.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await ie(e.params.id))return t.status(404).json({error:"track not found"});t.json(await GO())});E.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await ie(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 zO())}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});E.post("/api/tracks/:id/voice-chat/usage",async(e,t)=>{try{let n=await ie(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 VO(n,{model:r,usage:o,seconds:s})})}catch(n){t.status(n?.status||500).json({error:n?.message||String(n)})}});E.post("/api/tracks",async(e,t)=>{let{name:n,cwd:r,repo:o,repos:s,agent:a,model:i,skipPermissions:c,ticket:l,circuit:u}=e.body||{};try{let d=await cp({name:n,cwd:r,repo:o,repos:s,agent:a,model:i,skipPermissions:c!==!1}),p=null;if(l)try{await qa(d,l,{source:"create"})}catch(w){p=w?.message||String(w)}let f=null;if(u)try{await Ep(d,await Ua(u),{source:"picker"})}catch(w){f=w?.message||String(w)}t.json({ok:!0,track:d,...p?{ticketWarning:p}:{},...f?{circuitWarning:f}:{}})}catch(d){let p=d?.message||String(d);t.status(/required|unknown agent|invalid|must be/i.test(p)?400:500).json({error:p})}});E.get("/api/tracks/:id",async(e,t)=>{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:fM(La(e.params.id)),reshape:Pb(Gc(e.params.id)),subtasks:ys(e.params.id).map(Il),pendingOffers:await Ag(n)})});E.delete("/api/tracks/:id",async(e,t)=>{try{let n=await Hg(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await Py(e.params.id).catch(()=>{}),t.json(n)}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});E.post("/api/tracks/:id/archive",async(e,t)=>{try{t.json({ok:!0,track:await ws(e.params.id)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/already archived/i.test(r)?409:500).json({error:r})}});E.post("/api/tracks/:id/rename",async(e,t)=>{try{t.json({ok:!0,track:await Kg(e.params.id,e.body?.name)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/loop run Tracks/i.test(r)?409:/required|too long/i.test(r)?400:500;t.status(o).json({error:r})}});E.post("/api/tracks/:id/unarchive",async(e,t)=>{try{t.json({ok:!0,track:await up(e.params.id,{freshSession:e.body?.freshSession===!0})})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/not archived/i.test(r)?409:500).json({error:r})}});E.get("/api/tracks/:id/messages",async(e,t)=>{let n=await np(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json(n)});E.get("/api/tracks/:id/events",async(e,t)=>{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.set({"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive","x-accel-buffering":"no"}),t.flushHeaders();let r=i=>t.write(`id: ${i.seq}
764
768
  data: ${JSON.stringify(i)}
765
769
 
766
- `),o=Number(e.query.since??e.headers["last-event-id"])||0;for(let i of await q(n))i.seq>o&&r(i);let s=Cb(n.id,r),a=setInterval(()=>t.write(`: hb
770
+ `),o=Number(e.query.since??e.headers["last-event-id"])||0;for(let i of await K(n))i.seq>o&&r(i);let s=gk(n.id,r),a=setInterval(()=>t.write(`: hb
767
771
 
768
- `),25e3);e.on("close",()=>{clearInterval(a),s()})});T.get("/api/tracks/:id/search",async(e,t)=>{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=String(e.query.q||"").trim();if(!r)return t.status(400).json({error:"q (query) is required"});let o=Math.min(Math.max(Number(e.query.k)||8,1),50),s=Ei(await q(n)),a=Ql(s,r,{k:o,role:e.query.role||null,tag:e.query.tag||null});t.json({q:r,indexed:s.N,hits:a.map(i=>({score:Number(i.score.toFixed(3)),seq:i.chunk.seq,ts:i.chunk.ts,role:i.chunk.role,box:i.chunk.boxId,provider:i.chunk.provider,tags:i.chunk.tags,text:i.chunk.text}))})});T.get("/api/memory",async(e,t)=>{t.json({stores:await Yb(),harvest:Gb()})});T.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 Xb(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 v6=["Run a memory consolidation pass on this workspace's `.bostrat/memory/` directory:","1. Read `MEMORY.md` and every fact file.","2. Merge duplicates and facts that describe the same thing (keep the best-written one; fold unique details in; give the survivor a `supersedes:` entry naming what it absorbed, delete the absorbed file, and remove its index line).","3. Resolve contradictions in favor of the newest evidence \u2014 check the code where feasible before deciding.","4. Mark clearly-stale facts: correct them in place or delete them (file + index line).","5. Bump `metadata.modified` (ISO-8601, now) on every fact you touch.","6. Keep `MEMORY.md` one line per fact, under 200 lines.","When done, summarize what you merged, corrected, and deleted \u2014 that summary is the review record."].join(`
769
- `);T.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await Bt(e.params.id,v6)})}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})}});T.post("/api/tracks/:id/lead/restart",async(e,t)=>{try{t.json({ok:!0,track:await Pd(e.params.id,{freshSession:e.body?.freshSession===!0})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:n?.transferredTo||/mid-turn|terminal|archived/i.test(r)?409:500;t.status(o).json({error:r,...n?.transferredTo?{transferredTo:n.transferredTo}:{}})}});T.post("/api/tracks/:id/say",async(e,t)=>{let{text:n,attachments:r,producer:o}=e.body||{};try{t.json(await Bt(e.params.id,n,{attachments:r,producer:typeof o=="string"?o:null,dismissPrompt:!0}))}catch(s){let a=s?.message||String(s);if(s?.usageCap)return t.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});if(s?.transferredTo)return t.status(409).json({error:a,transferredTo:s.transferredTo});t.status(/not found/i.test(a)?404:/archived/i.test(a)?409:/required|not running/i.test(a)?400:500).json({error:a})}});T.post("/api/tracks/:id/upload",async(e,t)=>{try{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});if(n.archivedAt)return t.status(409).json({error:"track is archived"});if(!n.cwd)return t.status(409).json({error:"track has no workspace yet"});let r=Buffer.isBuffer(e.body)?e.body:null,o=await FE(n.cwd,{filename:e.query.filename,buffer:r});t.json({ok:!0,attachment:o})}catch(n){let r=n?.message||String(n);t.status(/too large|unsupported|empty|required/i.test(r)?400:500).json({error:r})}});T.get("/api/tracks/:id/uploads/:file",async(e,t)=>{try{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:`track "${e.params.id}" not found`});if(!n.cwd)return t.status(404).json({error:"track has no workspace"});let r=Te.basename(String(e.params.file||""));if(!r||!hw(Te.extname(r).slice(1)))return t.status(400).json({error:"not an upload path"});t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox");let o=mw(n.cwd),s,a;try{s=await gt.promises.realpath(o),a=await gt.promises.realpath(Te.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+Te.sep))return t.status(404).json({error:"upload not found"});t.sendFile(r,{root:o},i=>{i&&!t.headersSent&&t.status(404).json({error:"upload not found"})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});var S6=/^[0-9a-fA-F-]{8,64}$/;T.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await ie(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(!S6.test(o)||!Number.isInteger(s)||s<0)return t.status(400).json({error:"bad image ref"});let a=(n.boxes||[]).find(p=>p.name===r);if(!a||a.agent!=="claude"||!a.cwd||!a.sessionId)return t.status(404).json({error:"image source not available"});let i=sn(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=l6.createInterface({input:gt.createReadStream(i,{encoding:"utf8"}),crlfDelay:1/0});for await(let p of u){if(!p.includes(c))continue;let f;try{f=JSON.parse(p)}catch{continue}if(f.uuid===o){l=f,u.close();break}}let d=l?If(l)[s]:null;if(!d||!/^image\//.test(d.mediaType))return t.status(404).json({error:"image not found"});t.set("content-type",d.mediaType),t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox"),t.send(Buffer.from(d.data,"base64"))}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.post("/api/tracks/:id/interrupt",async(e,t)=>{try{t.json(await Od(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/archived/i.test(r)?409:500).json({error:r})}});T.delete("/api/tracks/:id/queue",async(e,t)=>{try{let{removed:n,restored:r,draftRev:o}=await Jw(e.params.id);t.json({ok:!0,removed:n.filter(s=>s.kind!=="ship-notify"),restored:r,draftRev:o})}catch(n){t.status(500).json({error:n?.message||String(n)})}});T.post("/api/tracks/:id/answer-prompt",async(e,t)=>{let{promptId:n,answers:r,text:o,custom:s}=e.body||{};try{t.json(await $d(e.params.id,{promptId:n,answers:r,text:o,custom:s}))}catch(a){let i=a?.message||String(a),c=/not found/i.test(i)?404:/no pending prompt|changed since|not running|not supported|needs a code|look like a sign-in code|no answer selected|custom answer|didn't take/i.test(i)?409:500;t.status(c).json({error:i})}});T.post("/api/setup/:provider/start",async(e,t)=>{try{let n=await sg({provider:e.params.provider,fresh:e.body?.fresh===!0});t.json({ok:!0,track:n})}catch(n){let r=n?.message||String(n);t.status(/unknown setup provider|isn't available/i.test(r)?400:500).json({error:r})}});T.post("/api/tracks/:id/navigate-prompt",async(e,t)=>{let{promptId:n,questionIndex:r}=e.body||{};try{t.json(await zw(e.params.id,{promptId:n,questionIndex:r}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/no pending prompt|changed since|not running|not supported|out of range|review screen/i.test(s)?409:500;t.status(a).json({error:s})}});T.put("/api/tracks/:id/draft",async(e,t)=>{let{text:n,rev:r}=e.body||{};try{t.json(await eg(e.params.id,typeof n=="string"?n:"",{rev:typeof r=="number"?r:null}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required/i.test(s)?400:500;t.status(a).json({error:s})}});T.get("/api/tracks/:id/usage",async(e,t)=>{let n=await ie(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=n.boxes?.find(s=>s.name===n.leadBox)||null,o=e.query.fresh==="1"||e.query.fresh==="true";t.json(await dp(r,{fresh:o}))});T.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await tg(e.params.id,n))}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/required|unknown model|not running/i.test(o)?400:500;t.status(s).json({error:o})}});T.post("/api/tracks/:id/subtask",async(e,t)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=e.body||{};try{let a=await Tg(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:dl(a)})}catch(a){let i=a?.message||String(a);if(a?.usageCap)return t.status(429).json({error:"usage_cap",message:i,cap:a.usageCap});let c=/not found/i.test(i)?404:/required|unknown agent|git repo|not running|can't resolve/i.test(i)?400:500;t.status(c).json({error:i})}});T.get("/api/tracks/:id/subtasks",(e,t)=>{t.json({subtasks:es(e.params.id).map(dl)})});T.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await Gw(e.params.id,e.params.sid);if(!n)return t.status(404).json({error:"subtask not found"});t.json(n)});T.post("/api/tracks/:id/subtask/:sid/cancel",(e,t)=>{try{t.json({ok:!0,subtask:dl(Ld(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});T.post("/api/tracks/:id/subtask/:sid/merge-now",(e,t)=>{try{t.json({ok:!0,subtask:dl(Ag(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function dl(e){return e?{id:e.id,agent:e.agent,task:e.task,skipPermissions:e.skipPermissions,step:e.step,running:!e.finishedAt,box:e.box,branch:e.branch,stat:e.stat,files:e.files||null,conflicts:e.conflicts||[],applied:e.applied,error:e.error,canceled:e.canceled,startedAt:e.startedAt,finishedAt:e.finishedAt}:null}T.post("/api/tracks/:id/handoff-lead",async(e,t)=>{let{toAgent:n,skipPermissions:r,reason:o}=e.body||{};try{let s=await Dd(e.params.id,n,r!==!1,o);t.json({ok:!0,step:s.step,toAgent:s.toAgent,fromBox:s.fromBox,skipPermissions:s.skipPermissions})}catch(s){let a=s?.message||String(s);if(s?.usageCap)return t.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});t.status(/already running/i.test(a)?409:/not found/i.test(a)?404:400).json({error:a})}});T.post("/api/tracks/:id/spin-up-view",async(e,t)=>{try{t.json(await Zw(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/already being spun up/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});T.get("/api/tracks/:id/handoff-lead",(e,t)=>{t.json(OO(Ta(e.params.id))??{running:!1})});T.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await yg(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})}});T.get("/api/tracks/:id/transfer-out",(e,t)=>{let n=gg(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??{}})});T.post("/api/tracks/:id/transfer-out/commit",async(e,t)=>{try{t.json(await Bd(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:400).json({error:r})}});T.post("/api/tracks/adopt",async(e,t)=>{let{trackId:n}=e.body||{};try{t.json(await xg({...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 OO(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}T.get("/api/debug/handoff",async(e,t)=>{let n=Math.min(Number(e.query.limit)||80,500);t.json({verbose:Nl(),paths:pk,trace:await dk({limit:n})})});var Xy=Te.resolve(kO,"..","..","client","dist");gt.existsSync(Xy)&&(T.use(Ut.static(Xy)),T.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(Te.join(Xy,"index.html"),ul)));var MO=d6.createServer(T),T6=new m6({noServer:!0}),CO=(e,t,n)=>{if(!(Qc(e)||Da.allowed(Da.clientIp(e))||Qy.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
772
+ `),25e3);e.on("close",()=>{clearInterval(a),s()})});E.get("/api/tracks/:id/search",async(e,t)=>{let n=await ie(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=qi(await K(n)),a=ku(s,r,{k:o,role:e.query.role||null,tag:e.query.tag||null});t.json({q:r,indexed:s.N,hits:a.map(i=>({score:Number(i.score.toFixed(3)),seq:i.chunk.seq,ts:i.chunk.ts,role:i.chunk.role,box:i.chunk.boxId,provider:i.chunk.provider,tags:i.chunk.tags,text:i.chunk.text}))})});E.get("/api/memory",async(e,t)=>{t.json({stores:await Nk(),harvest:Rk()})});E.delete("/api/memory/:key/:file",async(e,t)=>{let n=String(e.params.key||"");if(!/^[a-z0-9][a-z0-9._-]*$/.test(n))return t.status(400).json({error:"bad store key"});try{t.json({ok:!0,...await Pk(n,String(e.params.file||""))})}catch(r){let o=r?.message||String(r);t.status(/not found/i.test(o)?404:/bad fact/i.test(o)?400:500).json({error:o})}});var cG=["Run a memory consolidation pass on this workspace's `.bostrat/memory/` directory:","1. Read `MEMORY.md` and every fact file.","2. Merge duplicates and facts that describe the same thing (keep the best-written one; fold unique details in; give the survivor a `supersedes:` entry naming what it absorbed, delete the absorbed file, and remove its index line).","3. Resolve contradictions in favor of the newest evidence \u2014 check the code where feasible before deciding.","4. Mark clearly-stale facts: correct them in place or delete them (file + index line).","5. Bump `metadata.modified` (ISO-8601, now) on every fact you touch.","6. Keep `MEMORY.md` one line per fact, under 200 lines.","When done, summarize what you merged, corrected, and deleted \u2014 that summary is the review record."].join(`
773
+ `);E.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await Ht(e.params.id,cG)})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/archived/i.test(r)?409:/not running/i.test(r)?400:500).json({error:r})}});E.post("/api/tracks/:id/lead/restart",async(e,t)=>{try{t.json({ok:!0,track:await dp(e.params.id,{freshSession:e.body?.freshSession===!0})})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:n?.transferredTo||/mid-turn|terminal|archived/i.test(r)?409:500;t.status(o).json({error:r,...n?.transferredTo?{transferredTo:n.transferredTo}:{}})}});E.post("/api/tracks/:id/say",async(e,t)=>{let{text:n,attachments:r,producer:o}=e.body||{};try{t.json(await Ht(e.params.id,n,{attachments:r,producer:typeof o=="string"?o:null,dismissPrompt:!0}))}catch(s){let a=s?.message||String(s);if(s?.usageCap)return t.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});if(s?.transferredTo)return t.status(409).json({error:a,transferredTo:s.transferredTo});t.status(/not found/i.test(a)?404:/archived/i.test(a)?409:/required|not running/i.test(a)?400:500).json({error:a})}});E.post("/api/tracks/:id/upload",async(e,t)=>{try{let n=await ie(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 S_(n.cwd,{filename:e.query.filename,buffer:r});t.json({ok:!0,attachment:o})}catch(n){let r=n?.message||String(n);t.status(/too large|unsupported|empty|required/i.test(r)?400:500).json({error:r})}});E.get("/api/tracks/:id/uploads/:file",async(e,t)=>{try{let n=await ie(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=Ee.basename(String(e.params.file||""));if(!r||!Yw(Ee.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=Jw(n.cwd),s,a;try{s=await kt.promises.realpath(o),a=await kt.promises.realpath(Ee.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+Ee.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 lG=/^[0-9a-fA-F-]{8,64}$/;E.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await ie(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(!lG.test(o)||!Number.isInteger(s)||s<0)return t.status(400).json({error:"bad image ref"});let a=(n.boxes||[]).find(p=>p.name===r);if(!a||a.agent!=="claude"||!a.cwd||!a.sessionId)return t.status(404).json({error:"image source not available"});let i=cn(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=JK.createInterface({input:kt.createReadStream(i,{encoding:"utf8"}),crlfDelay:1/0});for await(let p of u){if(!p.includes(c))continue;let f;try{f=JSON.parse(p)}catch{continue}if(f.uuid===o){l=f,u.close();break}}let d=l?ch(l)[s]:null;if(!d||!/^image\//.test(d.mediaType))return t.status(404).json({error:"image not found"});t.set("content-type",d.mediaType),t.set("cache-control","private, max-age=31536000, immutable"),t.set("content-security-policy","sandbox"),t.send(Buffer.from(d.data,"base64"))}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/tracks/:id/interrupt",async(e,t)=>{try{t.json(await sp(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:/archived/i.test(r)?409:500).json({error:r})}});E.delete("/api/tracks/:id/queue",async(e,t)=>{try{let{removed:n,restored:r,draftRev:o}=await Ig(e.params.id);t.json({ok:!0,removed:n.filter(s=>s.kind!=="ship-notify"),restored:r,draftRev:o})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.post("/api/tracks/:id/answer-prompt",async(e,t)=>{let{promptId:n,answers:r,text:o,custom:s}=e.body||{};try{t.json(await rp(e.params.id,{promptId:n,answers:r,text:o,custom:s}))}catch(a){let i=a?.message||String(a),c=/not found/i.test(i)?404:/no pending prompt|changed since|not running|not supported|needs a code|look like a sign-in code|no answer selected|custom answer|didn't take/i.test(i)?409:500;t.status(c).json({error:i})}});E.post("/api/setup/:provider/start",async(e,t)=>{try{let n=await Fg({provider:e.params.provider,fresh:e.body?.fresh===!0});t.json({ok:!0,track:n})}catch(n){let r=n?.message||String(n);t.status(/unknown setup provider|isn't available/i.test(r)?400:500).json({error:r})}});E.post("/api/tracks/:id/navigate-prompt",async(e,t)=>{let{promptId:n,questionIndex:r}=e.body||{};try{t.json(await Eg(e.params.id,{promptId:n,questionIndex:r}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/no pending prompt|changed since|not running|not supported|out of range|review screen/i.test(s)?409:500;t.status(a).json({error:s})}});E.put("/api/tracks/:id/draft",async(e,t)=>{let{text:n,rev:r}=e.body||{};try{t.json(await Cg(e.params.id,typeof n=="string"?n:"",{rev:typeof r=="number"?r:null}))}catch(o){let s=o?.message||String(o),a=/not found/i.test(s)?404:/required/i.test(s)?400:500;t.status(a).json({error:s})}});E.get("/api/tracks/:id/usage",async(e,t)=>{let n=await ie(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 Wp(r,{fresh:o}))});E.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await Ng(e.params.id,n))}catch(r){let o=r?.message||String(r),s=/not found/i.test(o)?404:/required|unknown model|not running/i.test(o)?400:500;t.status(s).json({error:o})}});E.post("/api/tracks/:id/subtask",async(e,t)=>{let{agent:n,task:r,skipPermissions:o,reason:s}=e.body||{};try{let a=await ry(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:Il(a)})}catch(a){let i=a?.message||String(a);if(a?.usageCap)return t.status(429).json({error:"usage_cap",message:i,cap:a.usageCap});let c=/not found/i.test(i)?404:/required|unknown agent|git repo|not running|can't resolve/i.test(i)?400:500;t.status(c).json({error:i})}});E.get("/api/tracks/:id/subtasks",(e,t)=>{t.json({subtasks:ys(e.params.id).map(Il)})});E.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await Tg(e.params.id,e.params.sid);if(!n)return t.status(404).json({error:"subtask not found"});t.json(n)});E.post("/api/tracks/:id/subtask/:sid/cancel",(e,t)=>{try{t.json({ok:!0,subtask:Il(gp(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});E.post("/api/tracks/:id/subtask/:sid/merge-now",(e,t)=>{try{t.json({ok:!0,subtask:Il(oy(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function Il(e){return e?{id:e.id,agent:e.agent,task:e.task,skipPermissions:e.skipPermissions,step:e.step,running:!e.finishedAt,box:e.box,branch:e.branch,stat:e.stat,files:e.files||null,conflicts:e.conflicts||[],applied:e.applied,error:e.error,canceled:e.canceled,startedAt:e.startedAt,finishedAt:e.finishedAt}:null}E.post("/api/tracks/:id/handoff-lead",async(e,t)=>{let{toAgent:n,skipPermissions:r,reason:o}=e.body||{};try{let s=await pp(e.params.id,n,r!==!1,o);t.json({ok:!0,step:s.step,toAgent:s.toAgent,fromBox:s.fromBox,skipPermissions:s.skipPermissions})}catch(s){let a=s?.message||String(s);if(s?.usageCap)return t.status(429).json({error:"usage_cap",message:a,cap:s.usageCap});t.status(/already running/i.test(a)?409:/not found/i.test(a)?404:400).json({error:a})}});E.post("/api/tracks/:id/spin-up-view",async(e,t)=>{try{t.json(await Og(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/already being spun up/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});E.get("/api/tracks/:id/handoff-lead",(e,t)=>{t.json(fM(La(e.params.id))??{running:!1})});E.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await Qg(e.params.id);t.json({ok:!0,step:n.step,startedAt:n.startedAt})}catch(n){let r=n?.message||String(n);t.status(/already running/i.test(r)?409:/not found/i.test(r)?404:400).json({error:r})}});E.get("/api/tracks/:id/transfer-out",(e,t)=>{let n=Zg(e.params.id);if(!n)return t.json({running:!1});t.json({running:!n.finishedAt,step:n.step,error:n.error,startedAt:n.startedAt,finishedAt:n.finishedAt,...n.result??{}})});E.post("/api/tracks/:id/transfer-out/commit",async(e,t)=>{try{t.json(await hp(e.params.id,e.body||{}))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:400).json({error:r})}});E.post("/api/tracks/adopt",async(e,t)=>{let{trackId:n}=e.body||{};try{t.json(await ty({...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 fM(e){return e?{running:!e.finishedAt,step:e.step,error:e.error,fromBox:e.fromBox,toBox:e.toBox,toAgent:e.toAgent,skipPermissions:e.skipPermissions,startedAt:e.startedAt,finishedAt:e.finishedAt}:null}E.get("/api/debug/handoff",async(e,t)=>{let n=Math.min(Number(e.query.limit)||80,500);t.json({verbose:tu(),paths:Yk,trace:await Jk({limit:n})})});var Ob=Ee.resolve(nM,"..","..","client","dist");kt.existsSync(Ob)&&(E.use(zt.static(Ob)),E.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(Ee.join(Ob,"index.html"),_l)));var hM=XK.createServer(E),uG=new eG({noServer:!0}),mM=(e,t,n)=>{if(!(ml(e)||Za.allowed(Za.clientIp(e))||Cb.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
770
774
  \r
771
- `),t.destroy();return}if(B$(e,t,n))return;if(!N$(e,eb,{enforce:vO})){t.write(`HTTP/1.1 401 Unauthorized\r
775
+ `),t.destroy();return}if(bR(e,t,n))return;if(!wR(e,Nb,{enforce:oM})){t.write(`HTTP/1.1 401 Unauthorized\r
772
776
  \r
773
- `),t.destroy();return}let r=Ck(e.url);if(!r.ok){t.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
777
+ `),t.destroy();return}let r=g0(e.url);if(!r.ok){t.write(`HTTP/1.1 ${r.status} ${r.status===400?"Bad Request":"Not Found"}\r
774
778
  \r
775
- `),t.destroy();return}let o=r.sessionName;if(!je(o)){t.write(`HTTP/1.1 400 Bad Request\r
779
+ `),t.destroy();return}let o=r.sessionName;if(!De(o)){t.write(`HTTP/1.1 400 Bad Request\r
776
780
  \r
777
- `),t.destroy();return}let{cols:s,rows:a}=r;T6.handleUpgrade(e,t,n,i=>Rk(i,o,{cols:s,rows:a}))};MO.on("upgrade",CO);var NO=process.env.BOSTRAT_CERT_DIR||Te.join(process.env.HOME||$p.tmpdir(),".bostrat","certs"),gO=Number(process.env.BOSTRAT_TLS_PORT)||3443,yO=Te.join(NO,"bostrat.globopi.key"),bO=Te.join(NO,"bostrat.globopi.crt");if(gt.existsSync(yO)&&gt.existsSync(bO)){let e=p6.createServer({key:gt.readFileSync(yO),cert:gt.readFileSync(bO)},T);e.on("upgrade",CO),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(gO,Rp,()=>{console.log(`[bostrat-agent] https listening on ${Rp||"0.0.0.0"}:${gO}`)})}MO.listen(fO,Rp,()=>{console.log(`[bostrat-agent] listening on ${Rp||"0.0.0.0"}:${fO}`);let e=K_(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: ${Ot}`),console.log(`[bostrat-agent] auto-trigger default: ${xO}%`),console.log(`[bostrat-agent] ip allowlist: ${Da.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(Qy.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),hg().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),vg().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),dg().then(t=>t&&console.log(`[bostrat-agent] healed ${t} half-demoted transferred track(s)`)).catch(t=>console.error("[bostrat-agent] demoted-track reconcile failed:",t?.message||t)).then(()=>pg()).then(t=>t&&console.log(`[bostrat-agent] reaped ${t} orphaned box(es) on archived track(s)`)).catch(t=>console.error("[bostrat-agent] archived-orphan sweep failed:",t?.message||t)),og().then(t=>console.log(`[bostrat-agent] standing instructions refreshed (${t.refreshed} updated, ${t.removed} legacy CLAUDE.md removed${t.codexGlobal?`, codex global ${t.codexGlobal}`:""})`)).catch(t=>console.error("[bostrat-agent] standing-instructions refresh failed:",t?.message||t)),M6(),W_({listTracks:he}),t_({trackOf:qw}),_6(),I6(),O6(),Dv({listTracks:he,getTrack:ie}).then(t=>console.log(`[bostrat-agent] spend caps ${t.configured?"armed":"unconfigured (fail-open)"} \u2014 seeded ${Object.keys(t.spent).length} provider counter(s)`)).catch(t=>console.error("[bostrat-agent] spend-caps seed failed (staying fail-open):",t?.message||t)),KE()&&VE({listTracks:he}),mk().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)),NR(),jR(),WI({resolveTrack:ie}),QI({listTracks:he,createTrack:Md,archiveTrack:Zo,listRepos:Jn,resolveTrack:ie,sayToLead:Bt,answerPrompt:$d,startLeadHandoff:Dd,interruptLead:Od,listSubtaskJobs:es,cancelSubtask:Ld,readEvents:q,appendEvent:M,divertShip:Fy,answerPrExists:Uy,knownAgents:Ac}),A6(),ci().then(t=>{t||console.warn(`[boot] no host tmux server on ${Ot} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),ZR(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(Ba=tI({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,apiToken:eb,nodeId:process.env.BOSTRAT_NODE_ID||$p.hostname(),name:process.env.BOSTRAT_NODE_NAME||$p.hostname(),listTracks:he,detectAgents:_d,sampleMetrics:w$,deliverySample:()=>kA(Vw()),onHashKey:hA,onTracksTransferred:kg,onDegraded:({since:t,unacked:n,oldestAgeMs:r,mode:o})=>{let s=Math.round(r/6e4),a=`${process.env.BOSTRAT_NODE_NAME||$p.hostname()} \u2192 plane spine sync has stalled: ${n} event(s) unanswered for ${s} min (${o} door). New Tracks won't open from the plane until it recovers; the node is redialing with backoff.`;console.error(`[plane-link] ${a}`),process.env.BOSTRAT_NTFY_URL&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: plane sync stalled",Tags:"rotating_light"},body:a}).catch(()=>{}),wO=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(()=>{}),wO=null},onConnected:()=>{CR()},onUpdateAvailable:async t=>{try{Zy={latest:t.latest,current:t.current},await Wn({...t,policy:vt()}),vt()==="auto"&&await TO({to:t.latest,from:t.current})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>y6(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await Wn({current:t,latest:a,min:n,installKind:o,required:!0,policy:vt(),status:"available",reason:"refused"}),vt()!=="off"&&a){let i=await zd({to:a,kind:en,reason:"hard-floor"});i.ok?(cl.cancel(),await Wn({current:t,latest:a,min:n,installKind:o,required:!0,policy:vt(),status:"updating",reason:"hard-floor"})):console.error(`[self-update] hard-floor update not started: ${i.reason} \u2014 ${s}`)}}catch(a){console.error(`[plane-link] hard-floor handling failed: ${a?.message||a}`)}},updatePolicy:vt}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),vs().catch(()=>{}),BE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),qI().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),iE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),TE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),AS().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{Ba?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function A6(){E6(),ud().catch(()=>{}),setInterval(()=>ud().catch(()=>{}),1e4)}function E6(){for(let e of["bostrat-view","bostrat-mock","bostrat-flow","bostrat-ticket","bostrat-circuit","bostrat-roadmap","bostrat-blueprint","bostrat-decision","bostrat-runbook","bostrat-loop","bostrat-followup","bostrat-ship","bostrat-status","bostrat-notify","bostrat-gmail","bostrat-changelog","gh"])try{let t=Te.resolve(kO,"..","bin",e),n=Te.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!gt.existsSync(t))continue;gt.mkdirSync(n,{recursive:!0});let r=Te.join(n,e);(gt.existsSync(r)?gt.readlinkSync(r):null)!==t&&(gt.rmSync(r,{force:!0}),gt.symlinkSync(t,r)),console.log(`[bostrat-agent] ${e} CLI linked at ${r}`)}catch(t){console.error(`[bostrat-agent] ${e} CLI link failed:`,t?.message||t)}}function _6(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await he(),r=await b$({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 I6(){let e=null,t=async()=>{try{let n=Bs(),r=0,o=[],s=null,a=null;try{let u=await he(),d=await py(u);r=d.fleet.unpricedTurns||0,o=d.fleet.unpricedModels||[],s=await g$(u,{days:7}),a=(await my(u,{window:"7d"})).categorization}catch{}let i=[...n.problems,...a?.problems||[]];s&&!s.ok&&i.push(`${s.divergent} recent row(s) diverge from the table (implied-rate audit) \u2014 run \`npm run cost -- --audit\``);let c=o.filter(u=>u!=="unknown");c.length&&i.push(`${r} unpriced turn(s) \u2014 add rates for: ${c.join(", ")}`);let l=i.join(`
781
+ `),t.destroy();return}let{cols:s,rows:a}=r;uG.handleUpgrade(e,t,n,i=>h0(i,o,{cols:s,rows:a}))};hM.on("upgrade",mM);var wM=process.env.BOSTRAT_CERT_DIR||Ee.join(process.env.HOME||vl.tmpdir(),".bostrat","certs"),QO=Number(process.env.BOSTRAT_TLS_PORT)||3443,eM=Ee.join(wM,"bostrat.globopi.key"),tM=Ee.join(wM,"bostrat.globopi.crt");if(kt.existsSync(eM)&&kt.existsSync(tM)){let e=ZK.createServer({key:kt.readFileSync(eM),cert:kt.readFileSync(tM)},E);e.on("upgrade",mM),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(QO,cf,()=>{console.log(`[bostrat-agent] https listening on ${cf||"0.0.0.0"}:${QO}`)})}hM.listen(JO,cf,()=>{console.log(`[bostrat-agent] listening on ${cf||"0.0.0.0"}:${JO}`);let e=_I(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: ${jt}`),console.log(`[bostrat-agent] auto-trigger default: ${rM}%`),console.log(`[bostrat-agent] ip allowlist: ${Za.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(Cb.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),Yg().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),jg().then(t=>t&&console.log(`[bostrat-agent] rolled back ${t} interrupted reshape(s)`)).catch(t=>console.error("[bostrat-agent] reshape reconcile failed:",t?.message||t)),ny().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),Gg().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(()=>zg()).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)),Lg().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)),yG(),TI({listTracks:we}),j_({trackOf:Sg}),fG(),hG(),gG(),kS({listTracks:we,getTrack:ie}).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)),I_()&&O_({listTracks:we}),Zk().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)),wO(),kO(),T$({resolveTrack:ie}),P$({listTracks:we,createTrack:cp,archiveTrack:ws,listRepos:Xn,resolveTrack:ie,sayToLead:Ht,answerPrompt:rp,startLeadHandoff:pp,interruptLead:sp,listSubtaskJobs:ys,cancelSubtask:gp,readEvents:K,appendEvent:C,divertShip:kb,answerPrExists:xb,knownAgents:Wc}),dG(),_i().then(t=>{t||console.warn(`[boot] no host tmux server on ${jt} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),NO(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(Qa=BI({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,apiToken:Nb,nodeId:process.env.BOSTRAT_NODE_ID||vl.hostname(),name:process.env.BOSTRAT_NODE_NAME||vl.hostname(),listTracks:we,detectAgents:tp,sampleMetrics:Z$,deliverySample:()=>oE(_g()),onHashKey:QT,onTracksTransferred:ey,onDegraded:({since:t,unacked:n,oldestAgeMs:r,mode:o})=>{let s=Math.round(r/6e4),a=`${process.env.BOSTRAT_NODE_NAME||vl.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(()=>{}),ZO=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(()=>{}),ZO=null},onConnected:()=>{mO()},onRemoved:({reason:t,via:n})=>{let r=`${process.env.BOSTRAT_NODE_NAME||vl.hostname()} was removed from Bostrat (${t}, via ${n}) and is now dormant: it will not redial. The box and its data are untouched; destroy the machine or re-provision it with a new node token.`;console.error(`[plane-link] ${r}`),process.env.BOSTRAT_NTFY_URL&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: node removed, now dormant",Tags:"zzz"},body:r}).catch(()=>{})},onUpdateAvailable:async t=>{try{Mb={latest:t.latest,current:t.current},await Kn({...t,policy:Et()}),Et()==="auto"&&await aM({to:t.latest,from:t.current})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>oG(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await Kn({current:t,latest:a,min:n,installKind:o,required:!0,policy:Et(),status:"available",reason:"refused"}),Et()!=="off"&&a){let i=await Tp({to:a,kind:rn,reason:"hard-floor"});i.ok?(Tl.cancel(),await Kn({current:t,latest:a,min:n,installKind:o,required:!0,policy:Et(),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:Et}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),Fs().catch(()=>{}),k_().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),E$().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),qE().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),i_().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),lA().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{Qa?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function dG(){pG(),Md().catch(()=>{}),setInterval(()=>Md().catch(()=>{}),1e4)}function pG(){for(let e of["bostrat-view","bostrat-mock","bostrat-flow","bostrat-ticket","bostrat-circuit","bostrat-roadmap","bostrat-blueprint","bostrat-decision","bostrat-runbook","bostrat-loop","bostrat-followup","bostrat-ship","bostrat-status","bostrat-notify","bostrat-gmail","bostrat-changelog","gh"])try{let t=Ee.resolve(nM,"..","bin",e),n=Ee.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!kt.existsSync(t))continue;kt.mkdirSync(n,{recursive:!0});let r=Ee.join(n,e);(kt.existsSync(r)?kt.readlinkSync(r):null)!==t&&(kt.rmSync(r,{force:!0}),kt.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 fG(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await we(),r=await tR({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 hG(){let e=null,t=async()=>{try{let n=ea(),r=0,o=[],s=null,a=null;try{let u=await we(),d=await Gy(u);r=d.fleet.unpricedTurns||0,o=d.fleet.unpricedModels||[],s=await Q$(u,{days:7}),a=(await Vy(u,{window:"7d"})).categorization}catch{}let i=[...n.problems,...a?.problems||[]];s&&!s.ok&&i.push(`${s.divergent} recent row(s) diverge from the table (implied-rate audit) \u2014 run \`npm run cost -- --audit\``);let c=o.filter(u=>u!=="unknown");c.length&&i.push(`${r} unpriced turn(s) \u2014 add rates for: ${c.join(", ")}`);let l=i.join(`
778
782
  `);if(!i.length){e!==""&&console.log(`[pricing] table ok \u2014 rates verified ${n.tableVerifiedAt??"never"}`),e="";return}for(let u of i)console.warn(`[pricing] \u26A0 ${u}`);l!==e&&process.env.BOSTRAT_NTFY_URL&&fetch(process.env.BOSTRAT_NTFY_URL,{method:"POST",headers:{Title:"bostrat: cost instrument needs attention",Tags:"warning"},body:i.join(`
779
- `).slice(0,900)}).catch(()=>{}),e=l}catch(n){console.warn(`[pricing] watch failed: ${n?.message||n}`)}};setInterval(t,1440*60*1e3),setTimeout(t,3e4)}var $6=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,R6=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function O6(){let e=async()=>{try{let n=await Jb();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await he()).filter(a=>!De(a)&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await Vb([...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,$6).unref()},R6).unref()}function M6(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await he();for(let n of t)De(n)||!n.boxes?.some(r=>r.state==="live")||(await Id(n.id).catch(()=>{}),await pd(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}
783
+ `).slice(0,900)}).catch(()=>{}),e=l}catch(n){console.warn(`[pricing] watch failed: ${n?.message||n}`)}};setInterval(t,1440*60*1e3),setTimeout(t,3e4)}var mG=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,wG=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function gG(){let e=async()=>{try{let n=await Ck();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await we()).filter(a=>!je(a)&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await Mk([...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,mG).unref()},wG).unref()}function yG(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await we();for(let n of t)je(n)||!n.boxes?.some(r=>r.state==="live")||(await np(n.id).catch(()=>{}),await Nd(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}