bostrat-node 1.11.2 → 1.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +155 -155
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,55 +1,55 @@
1
- var RN=Object.defineProperty;var G=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var om=(e,t)=>{for(var n in t)RN(e,n,{get:t[n],enumerable:!0})};import{createHash as ON,randomBytes as MN,timingSafeEqual as CN}from"node:crypto";function Yk(){return MN(32).toString("hex")}function Ho(e){let t=typeof e=="string"?e.trim():"";return t?ON("sha256").update(t).digest("hex"):null}function Xk(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:CN(Buffer.from(e),Buffer.from(t))}function Ii(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(sm.set(e,(sm.get(e)||0)+1),am.has(e)&&n-am.get(e)<NN)return!1;am.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=${sm.get(e)}${o?` ${o}`:""}`),!0}async function Zk(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 dr,pr,sm,am,NN,Ys=G(()=>{dr="BOSTRAT_HOOK_TOKEN",pr="x-bostrat-hook";sm=new Map,am=new Map,NN=6e4});import Vt from"node:fs/promises";import Qk from"node:os";import Dt from"node:path";import{execFile as PN}from"node:child_process";import{promisify as DN}from"node:util";function iu(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function im(){return process.env.CLAUDE_CONFIG_DIR?Dt.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):Dt.join(Qk.homedir(),".claude.json")}function BN(){return process.env.CLAUDE_CONFIG_DIR?Dt.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):Dt.join(Qk.homedir(),".claude","settings.json")}async function Wr(e){if(!e||typeof e!="string")return;let t=Dt.resolve(e),n=im(),r=BN(),o={};try{o=JSON.parse(await Vt.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 Vt.mkdir(Dt.dirname(n),{recursive:!0}),await Vt.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await Vt.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 "${pr}: $${dr}" --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 Vt.mkdir(Dt.dirname(r),{recursive:!0}),await Vt.writeFile(r,JSON.stringify(i,null,2)),await LN(t)}async function LN(e){try{let t=Dt.resolve(e),n=Dt.join(t,".bostrat","memory","claude"),r=Dt.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await Vt.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(Dt.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await Vt.mkdir(n,{recursive:!0}),await Vt.mkdir(Dt.dirname(r),{recursive:!0}),await Vt.writeFile(r,JSON.stringify(o,null,2)),await jN(t,["/.claude/settings.local.json"])}catch{}}async function jN(e,t){try{let{stdout:n}=await DN(PN)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=Dt.resolve(e,n.trim()),o=await Vt.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
1
+ var RN=Object.defineProperty;var G=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(r){throw n=[r],r}};var sm=(e,t)=>{for(var n in t)RN(e,n,{get:t[n],enumerable:!0})};import{createHash as ON,randomBytes as MN,timingSafeEqual as CN}from"node:crypto";function Yk(){return MN(32).toString("hex")}function Ho(e){let t=typeof e=="string"?e.trim():"";return t?ON("sha256").update(t).digest("hex"):null}function Xk(e,t){return typeof e!="string"||typeof t!="string"||e.length!==t.length||!e?!1:CN(Buffer.from(e),Buffer.from(t))}function Ii(e,t={},{now:n=Date.now(),log:r=console.warn}={}){if(am.set(e,(am.get(e)||0)+1),im.has(e)&&n-im.get(e)<NN)return!1;im.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=${am.get(e)}${o?` ${o}`:""}`),!0}async function Zk(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 dr,pr,am,im,NN,Ys=G(()=>{dr="BOSTRAT_HOOK_TOKEN",pr="x-bostrat-hook";am=new Map,im=new Map,NN=6e4});import Vt from"node:fs/promises";import Qk from"node:os";import Dt from"node:path";import{execFile as PN}from"node:child_process";import{promisify as DN}from"node:util";function iu(){return/^(1|true|yes|on)$/i.test(process.env.BOSTRAT_CLAUDE_USE_API_KEY||"")&&process.env.ANTHROPIC_API_KEY?.trim()||null}function cm(){return process.env.CLAUDE_CONFIG_DIR?Dt.join(process.env.CLAUDE_CONFIG_DIR,".claude.json"):Dt.join(Qk.homedir(),".claude.json")}function BN(){return process.env.CLAUDE_CONFIG_DIR?Dt.join(process.env.CLAUDE_CONFIG_DIR,"settings.json"):Dt.join(Qk.homedir(),".claude","settings.json")}async function Wr(e){if(!e||typeof e!="string")return;let t=Dt.resolve(e),n=cm(),r=BN(),o={};try{o=JSON.parse(await Vt.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 Vt.mkdir(Dt.dirname(n),{recursive:!0}),await Vt.writeFile(n,JSON.stringify(o,null,2));let i={};try{i=JSON.parse(await Vt.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 "${pr}: $${dr}" --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 Vt.mkdir(Dt.dirname(r),{recursive:!0}),await Vt.writeFile(r,JSON.stringify(i,null,2)),await LN(t)}async function LN(e){try{let t=Dt.resolve(e),n=Dt.join(t,".bostrat","memory","claude"),r=Dt.join(t,".claude","settings.local.json"),o={};try{o=JSON.parse(await Vt.readFile(r,"utf8"))}catch{}let s=o.autoMemoryDirectory,a=typeof s=="string"&&s.includes(Dt.join(".bostrat","memory"));if(s&&!a||s===n)return;o.autoMemoryDirectory=n,await Vt.mkdir(n,{recursive:!0}),await Vt.mkdir(Dt.dirname(r),{recursive:!0}),await Vt.writeFile(r,JSON.stringify(o,null,2)),await jN(t,["/.claude/settings.local.json"])}catch{}}async function jN(e,t){try{let{stdout:n}=await DN(PN)("git",["-C",e,"rev-parse","--git-path","info/exclude"]),r=Dt.resolve(e,n.trim()),o=await Vt.readFile(r,"utf8").catch(()=>""),s=t.filter(a=>!o.split(`
2
2
  `).includes(a));if(!s.length)return;await Vt.mkdir(Dt.dirname(r),{recursive:!0}),await Vt.appendFile(r,(o&&!o.endsWith(`
3
3
  `)?`
4
4
  `:"")+s.join(`
5
5
  `)+`
6
- `)}catch{}}var $i=G(()=>{Ys()});import cm from"node:fs/promises";import FN from"node:os";import cu from"node:path";function UN(){let e=process.env.CODEX_HOME||cu.join(FN.homedir(),".codex");return cu.join(e,"config.toml")}function HN(e=process.env){return String(e.BOSTRAT_CODEX_UPDATE_CHECK||"").trim().toLowerCase()!=="codex"}function WN(e){let t=String(e||""),n=t.search(/^\s*\[/m),r=n===-1?t:t.slice(0,n);return new RegExp(`^\\s*${t0}\\s*=`,"m").test(r)}function qN(e,{env:t=process.env}={}){let n=String(e||"");return!HN(t)||WN(n)?n:n.trim()?`${e0}
6
+ `)}catch{}}var $i=G(()=>{Ys()});import lm from"node:fs/promises";import FN from"node:os";import cu from"node:path";function UN(){let e=process.env.CODEX_HOME||cu.join(FN.homedir(),".codex");return cu.join(e,"config.toml")}function HN(e=process.env){return String(e.BOSTRAT_CODEX_UPDATE_CHECK||"").trim().toLowerCase()!=="codex"}function WN(e){let t=String(e||""),n=t.search(/^\s*\[/m),r=n===-1?t:t.slice(0,n);return new RegExp(`^\\s*${t0}\\s*=`,"m").test(r)}function qN(e,{env:t=process.env}={}){let n=String(e||"");return!HN(t)||WN(n)?n:n.trim()?`${e0}
7
7
 
8
8
  ${n.replace(/^\n+/,"")}`:`${e0}
9
- `}function n0(e){return`[projects."${e}"]`}function GN(e,t){let n=n0(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 Xs(e){if(!e||typeof e!="string")return;let t=cu.resolve(e),n=UN(),r="";try{r=await cm.readFile(n,"utf8")}catch{}let o=r;if(r=qN(r),!GN(r,t)){let s=n0(t);if(r.includes(s)){let i=r.indexOf(s)+s.length,l=r.slice(i).search(/^\s*\[/m),u=l===-1?r.length:i+l,d=r.slice(i,u),p=/trust_level\s*=/.test(d)?d.replace(/trust_level\s*=\s*"[^"]*"/,'trust_level = "trusted"'):`${d.replace(/\s*$/,"")}
9
+ `}function n0(e){return`[projects."${e}"]`}function GN(e,t){let n=n0(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 Xs(e){if(!e||typeof e!="string")return;let t=cu.resolve(e),n=UN(),r="";try{r=await lm.readFile(n,"utf8")}catch{}let o=r;if(r=qN(r),!GN(r,t)){let s=n0(t);if(r.includes(s)){let i=r.indexOf(s)+s.length,l=r.slice(i).search(/^\s*\[/m),u=l===-1?r.length:i+l,d=r.slice(i,u),p=/trust_level\s*=/.test(d)?d.replace(/trust_level\s*=\s*"[^"]*"/,'trust_level = "trusted"'):`${d.replace(/\s*$/,"")}
10
10
  trust_level = "trusted"
11
11
  `;r=r.slice(0,i)+p+r.slice(u)}else{let a=`
12
12
  ${s}
13
13
  trust_level = "trusted"
14
14
  `;r=r.trimEnd()+a+(r.length&&!r.endsWith(`
15
15
  `)?`
16
- `:"")}}if(r!==o)try{await cm.mkdir(cu.dirname(n),{recursive:!0}),await cm.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var t0,e0,lu=G(()=>{t0="check_for_update_on_startup",e0=`${t0} = false`});import Ri from"node:fs/promises";import KN from"node:os";import o0 from"node:path";function Wo(e){let t=String(e??"");for(let n of VN)t=t.replace(n,"\u2039redacted\u203A");return t}function uu(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function zN(e){try{await Ri.mkdir(lm,{recursive:!0}),await Ri.appendFile(Zs,`${JSON.stringify(e)}
16
+ `:"")}}if(r!==o)try{await lm.mkdir(cu.dirname(n),{recursive:!0}),await lm.writeFile(n,r)}catch(s){console.warn(`[codex-config] could not seed folder trust for ${t}: ${s?.message||s}`)}}var t0,e0,lu=G(()=>{t0="check_for_update_on_startup",e0=`${t0} = false`});import Ri from"node:fs/promises";import KN from"node:os";import o0 from"node:path";function Wo(e){let t=String(e??"");for(let n of VN)t=t.replace(n,"\u2039redacted\u203A");return t}function uu(){let e=process.env.BOSTRAT_HANDOFF_DEBUG;return e==="1"||e==="true"}async function zN(e){try{await Ri.mkdir(um,{recursive:!0}),await Ri.appendFile(Zs,`${JSON.stringify(e)}
17
17
  `,"utf8");let n=(await Ri.readFile(Zs,"utf8")).split(`
18
18
  `).filter(Boolean);n.length>r0&&await Ri.writeFile(Zs,`${n.slice(-r0).join(`
19
19
  `)}
20
20
  `,"utf8")}catch(t){console.warn(`[handoff-debug] failed to write ${Zs}: ${t?.message||t}`)}}async function ee(e={}){let t=e.paneTail===!0,n={at:new Date().toISOString(),ts:Date.now(),...e};t&&delete n.paneTail;let r=[n.flow||"handoff",n.phase||n.step||"?",n.trackId?`track=${n.trackId}`:"",n.sessionName?`box=${n.sessionName}`:"",n.error?`ERR=${n.error}`:""].filter(Boolean).join(" \xB7 ");if(console.log(`[handoff-debug] ${r}`),n.sessionName&&(t||uu()))try{n.paneTail=Wo((await Ne(n.sessionName,{lines:t?JN:35})).slice(-YN))}catch{n.paneTail=null}(t||uu()||n.error||/^(checkpoint|spawn|hydrate|commit|done|summarize|clear|resume|ready|send|seed|failed|launch|submit-|gate-accept|blocked|timeout|dialog|exit|config-|waiting|quiet|quiescence-|await-)/.test(String(n.phase||n.step||"")))&&await zN(n)}async function s0({limit:e=80}={}){try{return(await Ri.readFile(Zs,"utf8")).split(`
21
- `).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=Wo(o.paneTail)),o}catch{return{raw:Wo(r)}}})}catch{return[]}}var VN,lm,Zs,r0,JN,YN,a0,yn=G(()=>{dt();VN=[/[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];lm=process.env.BOSTRAT_DEBUG_DIR||o0.join(KN.homedir(),".bostrat","debug"),Zs=o0.join(lm,"handoff.jsonl"),r0=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;JN=40,YN=4e3;a0={DEBUG_DIR:lm,LOG_FILE:Zs}});import XN from"node:fs/promises";import{execFile as ZN}from"node:child_process";import{promisify as QN}from"node:util";function fm(e){um=typeof e=="function"?e:null}function d0({holdWhile:e=null}={}){dm=typeof e=="function"?e:null}function aP(e){return new Promise(t=>setTimeout(t,e))}function pu(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}function iP(e,t){let n=s=>String(s||"").split(/[-+]/)[0].split(".").map(Number),r=n(e),o=n(t);if(!r.length||!o.length||r.some(Number.isNaN)||o.some(Number.isNaN))return!1;for(let s=0;s<Math.max(r.length,o.length);s++){let a=(r[s]||0)-(o[s]||0);if(a)return a<0}return!1}async function p0(e){let t=(await du("/bin/sh",["-c",`command -v ${e.bin}`])).stdout.trim();if(!t)throw new Error(`${e.bin} not on PATH`);let n=await XN.realpath(t).catch(()=>t),r=pu(n),o=r?{...process.env,PATH:`${r}/bin:${process.env.PATH||""}`}:process.env;return{bin:t,env:o}}async function f0(e,t){return(await du(t,["--version"],{timeout:u0})).stdout.trim().replace(e.versionRe,"")||null}async function fu({timeoutMs:e=tP()}={}){if(!Oi)return{waited:!1,timedOut:!1};let t=Date.now(),n=null,r=await Promise.race([Oi.then(()=>!1,()=>!1),new Promise(o=>{n=setTimeout(()=>o(!0),e)})]);return clearTimeout(n),{waited:!0,waitedMs:Date.now()-t,timedOut:r}}function mu(e,{ttlMs:t=nP()}={}){let n=String(e||"");return n?(Mi.set(n,Date.now()+t),()=>mm(n)):()=>{}}function mm(e){Mi.delete(String(e||""))}function cP(){let e=Date.now();for(let[t,n]of Mi)n<=e&&Mi.delete(t);return Mi.size}async function lP({timeoutMs:e=rP()}={}){let t=Date.now()+e;for(;cP()>0||dm&&await dm().catch(()=>!1);){if(Date.now()>t)return!1;await aP(oP)}return!0}function m0({cli:e=pm.codex,sessionName:t=null,from:n=null,to:r,reason:o="sweep"}={}){let s=String(r||"").trim();if(!s||i0.has(s))return!1;i0.add(s);let a=c0.then(()=>uP({cli:e,sessionName:t,from:n,to:s,reason:o})).catch(()=>{});c0=a;let i=a.then(()=>{Oi===i&&(Oi=null)});return Oi=i,!0}function hm({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();r&&(ee({flow:"cli-currency",phase:"fallback",cli:"codex",sessionName:e,from:t,to:r}).catch(()=>{}),m0({cli:pm.codex,sessionName:e,from:t,to:r,reason:"chooser"}))}async function uP({cli:e,sessionName:t,from:n,to:r,reason:o}){await ee({flow:"codex-update",phase:"start",cli:e.name,sessionName:t,from:n,to:r,reason:o}).catch(()=>{});try{await lP()||await ee({flow:"codex-update",phase:"lease-wait-cap",cli:e.name,to:r}).catch(()=>{});let{bin:a,env:i}=await p0(e);await du("npm",["install","-g",e.pkg],{env:i,timeout:eP});let c=await f0(e,a).catch(()=>null)||r;await ee({flow:"codex-update",phase:"done",cli:e.name,sessionName:t,from:n,to:r,version:c,reason:o}).catch(()=>{}),await l0({cli:e.name,sessionName:t,from:n,to:r,version:c,status:"updated",reason:o})}catch(s){let a=String(s?.message||s).slice(0,300);await ee({flow:"codex-update",phase:"failed",cli:e.name,sessionName:t,from:n,to:r,error:a,reason:o}).catch(()=>{}),await l0({cli:e.name,sessionName:t,from:n,to:r,status:"failed",error:a,reason:o})}}async function l0(e){if(um)try{await um(e)}catch{}}async function dP(e="codex",{reason:t="sweep"}={}){let n=pm[e],r={cli:e,installed:null,latest:null,drift:!1,scheduled:!1};if(!n)return r;try{let{bin:o,env:s}=await p0(n);r.installed=await f0(n,o);let a=await du("npm",["view",n.pkg,"dist-tags.latest"],{env:s,timeout:u0});if(r.latest=String(a.stdout||"").trim().split(/\s+/).pop()||null,!/^\d+\.\d+\.\d+/.test(r.latest||""))throw new Error(`registry answered "${r.latest}"`);r.drift=!!(r.installed&&iP(r.installed,r.latest)),await ee({flow:"cli-currency",phase:"discover",cli:e,installed:r.installed,latest:r.latest,drift:r.drift,reason:t}).catch(()=>{}),r.drift&&(r.scheduled=m0({cli:n,from:r.installed,to:r.latest,reason:t}))}catch(o){await ee({flow:"cli-currency",phase:"discover-failed",cli:e,error:String(o?.message||o).slice(0,300),reason:t}).catch(()=>{})}return r}async function pP({reason:e="sweep"}={}){let t=[];for(let n of sP)t.push(await dP(n,{reason:e}));return t}function h0({env:e=process.env,initialDelayMs:t=9e4}={}){let n=e.BOSTRAT_CLI_CURRENCY_MS===void 0?216e5:Number(e.BOSTRAT_CLI_CURRENCY_MS);if(!(n>0))return null;let r=()=>pP({reason:"sweep"}).catch(()=>{}),o=setTimeout(r,t);o.unref?.();let s=setInterval(r,n);return s.unref?.(),{stop:()=>{clearTimeout(o),clearInterval(s)}}}var du,eP,u0,tP,nP,rP,oP,pm,sP,i0,c0,Oi,Mi,um,dm,qo=G(()=>{yn();du=QN(ZN),eP=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,u0=Number(process.env.BOSTRAT_CLI_REGISTRY_TIMEOUT_MS)||15e3,tP=()=>Number(process.env.BOSTRAT_CLI_UPDATE_WAIT_MS)||45e3,nP=()=>Number(process.env.BOSTRAT_CLI_SPAWN_LEASE_MS)||9e4,rP=()=>Number(process.env.BOSTRAT_CLI_LEASE_WAIT_MS)||12e4,oP=250,pm={codex:{name:"codex",pkg:"@openai/codex",bin:"codex",versionRe:/^codex-cli\s*/}},sP=["codex"],i0=new Set,c0=Promise.resolve(),Oi=null,Mi=new Map,um=null;dm=null});import w0 from"node:fs/promises";import fP from"node:os";import Ci from"node:path";function mP(e){let n=Ci.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||Ci.join(fP.homedir(),".cursor");return Ci.join(r,"projects",n)}async function Qs(e){if(!e||typeof e!="string")return;let t=Ci.resolve(e),n=mP(t),r=Ci.join(n,".workspace-trusted");await w0.mkdir(n,{recursive:!0}),await w0.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
22
- `,"utf8")}var hu=G(()=>{});import gm from"node:fs/promises";import qr from"node:path";import{execFile as hP}from"node:child_process";import{promisify as wP}from"node:util";async function vP(e){try{return(await gm.stat(qr.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function SP(e){let t=i=>gm.readFile(qr.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 fr(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await vP(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:qr.basename(o),branch:await SP(o)});return}if(s>=kP)return;let i;try{i=await gm.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||xP.has(c.name)||await t(qr.join(o,c.name),s+1)}for(let o of bP)await t(qr.resolve(o),0);let n=new Set,r=[];for(let o of e.values()){let s=await Me(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 AP(e){let t=String(e||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return t?`${t[1]}/${t[2]}`:null}async function Me(e){if(!e)return null;if(wm.has(e))return wm.get(e);let t=null;try{let{stdout:n}=await gP("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=AP(n)}catch{t=null}return wm.set(e,t),t}async function ea(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await fr())if((await Me(n.path))?.toLowerCase()===t)return n.path;return null}var gP,g0,yP,bP,kP,xP,wm,Gr=G(()=>{gP=wP(hP),g0=process.env.HOME||"/home/globo",yP=qr.join(process.env.BOSTRAT_STATE_DIR||qr.join(g0,".bostrat"),"repos"),bP=[...(process.env.BOSTRAT_REPOS_ROOT||qr.join(g0,"Documents")).split(","),yP].map(e=>e.trim()).filter(Boolean),kP=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,xP=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);wm=new Map});function ta(e=Date.now()){if(Ko)return{tripped:!1,holdMs:1/0};if(Go>e)return{tripped:!1,holdMs:Go-e};if((!Pi||e-Pi>=wu.windowMs)&&(Pi=e,Ni=0),Ni++,Ni<wu.trip)return{tripped:!1,holdMs:0};gu++;let t=Math.min(wu.minMs*2**(gu-1),wu.maxMs);return Go=e+t,Ni=0,Pi=0,{tripped:!0,holdMs:t}}function y0(){Ni=0,Pi=0,gu=0,Go=0}function Di(e=Date.now()){return Ko?1/0:Go>e?Go-e:0}function na(e=Date.now()){return Di(e)>0}function ym(e={}){Ko={at:Date.now(),...e},Go=1/0}function yu(){return Ko}function b0(e=Date.now()){return{held:na(e),holdMs:Ko?null:Di(e),holds:gu,removed:Ko?{...Ko}:null}}var TP,wu,Ni,Pi,gu,Go,Ko,bm=G(()=>{TP={trip:3,windowMs:3e5,minMs:3e5,maxMs:216e5},wu={...TP},Ni=0,Pi=0,gu=0,Go=0,Ko=null});import EP from"node:fs";import k0 from"node:fs/promises";import Bi from"node:path";import _P from"node:os";import{fileURLToPath as IP}from"node:url";import{execFile as $P}from"node:child_process";import{promisify as RP}from"node:util";function De(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 bu(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}function T0(e){return e?.status===404&&/not granted/i.test(String(e?.message||""))}async function ra(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!v0.test(n))throw Vo("repo must be owner/name",400);let r=km.get(n);if(r&&r.expiresAt-Date.now()>CP)return r;if(!bu(t))throw Vo("node is not plane-linked \u2014 GitHub auth unavailable",503);if(na()){if(r&&r.expiresAt>Date.now())return r;throw Vo(yu()?"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 S0(`${De(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:A0(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw Vo(`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)&&ta(),o.status>=500&&r&&r.expiresAt>Date.now())return r;throw Vo(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 km.set(n,a),a}async function Li({env:e=process.env,force:t=!1}={}){if(!bu(e))return{configured:!1,repos:[],username:null};if(!t&&Kr&&Date.now()-Kr.at<NP)return Kr.data;if(na())return Kr?.data??{configured:!0,repos:[],username:null,error:"plane refused this node's token"};try{let n=await S0(`${De(e)}/v1/github/repos`,{headers:A0(e)});if((n.status===401||n.status===403||n.status===410)&&ta(),!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return Kr={at:Date.now(),data:r},r}catch(n){return Kr?Kr.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function E0(){km.clear(),Kr=null}async function Bn({cwd:e=null,slug:t=null,env:n=process.env}={}){try{let r=t||(e?await Me(e):null);if(!r)return{};let{token:o}=await ra(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function xm({env:e=process.env}={}){return(await Li({env:e})).username??null}function LP(e){let[t,n]=String(e).split("/");return Bi.join(MP,t,n)}async function vm(e,{env:t=process.env}={}){let n=(...r)=>x0("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${DP()}" ${BP(t)}`),await n("config","credential.useHttpPath","true")}async function ku(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!v0.test(String(e||"")))throw Vo(`bad repo slug "${e}"`,400);let r=LP(e);if(EP.existsSync(Bi.join(r,".git")))return r;let{token:o}=await ra(e,{env:t});await k0.mkdir(Bi.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await x0("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:PP,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await k0.rm(r,{recursive:!0,force:!0}).catch(()=>{}),Vo(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await vm(r,{env:t}),r}var x0,OP,MP,v0,CP,NP,PP,S0,km,Kr,A0,Vo,DP,BP,xt=G(()=>{Gr();bm();x0=RP($P),OP=process.env.BOSTRAT_STATE_DIR||Bi.join(process.env.HOME||_P.tmpdir(),".bostrat"),MP=Bi.join(OP,"repos"),v0=/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?\/[A-Za-z0-9._-]{1,100}$/,CP=5*6e4,NP=6e4,PP=10*6e4,S0=fetch,km=new Map,Kr=null;A0=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),Vo=(e,t)=>Object.assign(new Error(e),{status:t});DP=()=>IP(new URL("../bin/bostrat-git-credential",import.meta.url)),BP=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function I0(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}async function R0(e,t,n,r=_0){let o=De(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await FP(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function O0(e,{env:t=process.env,force:n=!1,timeoutMs:r=_0}={}){if(!I0(t))return{facts:[],source:"unconfigured"};let o=Sm.get(e);if(!n&&o&&Date.now()-o.at<jP)return{facts:o.facts,source:"cache"};try{let s=await R0(`/v1/memory/${encodeURIComponent(e)}`,{headers:$0(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 Sm.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 xu(e,t,{env:n=process.env}={}){if(!I0(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await R0(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...$0(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 Sm.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 jP,_0,Sm,FP,$0,M0=G(()=>{xt();jP=6e4,_0=5e3,Sm=new Map,FP=(...e)=>fetch(...e);$0=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import Am from"node:fs/promises";import oa from"node:path";import UP from"node:os";import{EventEmitter as HP}from"node:events";import{randomUUID as WP}from"node:crypto";function sa(e){return e?.cwd?oa.join(e.cwd,".bostrat","events"):oa.join(Tm,"events")}async function VP(e,t){if(!vu.has(t)){let o=(await K(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);vu.set(t,o)}let n=vu.get(t)+1;return vu.set(t,n),n}function ji(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 N(e,t){let n=typeof e=="string"?e:e?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!t||!qP.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!GP.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!KP.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?oa.join(Tm,"events"):sa(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=ji(u,Number(t.payload?.ts??t.ts)||Date.now())}let s=await VP(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||WP(),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 N0(c)&&(c=P0(c),l=JSON.parse(c)),await Am.mkdir(r,{recursive:!0}),await Am.appendFile(C0(r,n),c+`
23
- `),Ze.emit("event",l),Ze.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"?oa.join(Tm,"events"):sa(e));let o;try{o=await Am.readFile(C0(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
24
- `))if(a.trim())try{s.push(JSON.parse(N0(a)?P0(a):a))}catch{}return s}function D0(e,t){let n=`track:${e}`;return Ze.on(n,t),()=>Ze.off(n,t)}var qP,GP,KP,Ze,Tm,C0,vu,zP,N0,P0,be=G(()=>{qP=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","job.stopped","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.login.started","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"]),GP=new Set(["user","agent","orchestrator","system","peer"]),KP=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor","cli"]),Ze=new HP;Ze.setMaxListeners(0);Tm=process.env.BOSTRAT_STATE_DIR||oa.join(process.env.HOME||UP.tmpdir(),".bostrat");C0=(e,t)=>oa.join(e,`${t}.ndjson`),vu=new Map;zP=/(?<!\\)((?:\\\\)*)\\u0000/g,N0=e=>e.includes("\\u0000"),P0=e=>e.replace(zP,"$1\\ufffd")});import ue from"node:fs/promises";import JP from"node:os";import Te from"node:path";import{execFile as YP}from"node:child_process";import{promisify as XP}from"node:util";function Au(){return Te.join(Tu,"memory","repos")}function zo(e){return e===mr?Te.join(Tu,"memory",mr):Te.join(Au(),e)}async function Ui(e){try{return JSON.parse(await ue.readFile(Te.join(e,W0),"utf8"))}catch{return{}}}async function _m(e,t){let n=await Ui(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await ue.mkdir(e,{recursive:!0}),await ue.writeFile(Te.join(e,W0),JSON.stringify(n))}function L0(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 j0(e){try{let{stdout:t}=await ZP("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function Im(e){if(!e)return[];let t=L0(await j0(e));if(t)return[t];let n=[],r=[];try{r=await ue.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=L0(await j0(Te.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function Eu(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 Vr(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function Ln(e,t=null){let n=t??await ue.readFile(e,"utf8").catch(()=>""),{fm:r}=Eu(n),o=Vr(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await ue.stat(e)).mtimeMs}catch{return 0}}function q0(e,t){let n=Vr(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===mr){let o=Vr(e,"trust");if(!o||/^operator/i.test(o))return mr}return t}function $m(e,t,n,r=new Map){let o=(e||"").split(`
21
+ `).filter(Boolean).slice(-e).map(r=>{try{let o=JSON.parse(r);return typeof o?.paneTail=="string"&&(o.paneTail=Wo(o.paneTail)),o}catch{return{raw:Wo(r)}}})}catch{return[]}}var VN,um,Zs,r0,JN,YN,a0,yn=G(()=>{dt();VN=[/[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];um=process.env.BOSTRAT_DEBUG_DIR||o0.join(KN.homedir(),".bostrat","debug"),Zs=o0.join(um,"handoff.jsonl"),r0=Number(process.env.BOSTRAT_HANDOFF_DEBUG_MAX)||500;JN=40,YN=4e3;a0={DEBUG_DIR:um,LOG_FILE:Zs}});import XN from"node:fs/promises";import{execFile as ZN}from"node:child_process";import{promisify as QN}from"node:util";function mm(e){dm=typeof e=="function"?e:null}function d0({holdWhile:e=null}={}){pm=typeof e=="function"?e:null}function aP(e){return new Promise(t=>setTimeout(t,e))}function pu(e){let t=String(e||""),n=t.indexOf("/lib/node_modules/");return n>0?t.slice(0,n):null}function iP(e,t){let n=s=>String(s||"").split(/[-+]/)[0].split(".").map(Number),r=n(e),o=n(t);if(!r.length||!o.length||r.some(Number.isNaN)||o.some(Number.isNaN))return!1;for(let s=0;s<Math.max(r.length,o.length);s++){let a=(r[s]||0)-(o[s]||0);if(a)return a<0}return!1}async function p0(e){let t=(await du("/bin/sh",["-c",`command -v ${e.bin}`])).stdout.trim();if(!t)throw new Error(`${e.bin} not on PATH`);let n=await XN.realpath(t).catch(()=>t),r=pu(n),o=r?{...process.env,PATH:`${r}/bin:${process.env.PATH||""}`}:process.env;return{bin:t,env:o}}async function f0(e,t){return(await du(t,["--version"],{timeout:u0})).stdout.trim().replace(e.versionRe,"")||null}async function fu({timeoutMs:e=tP()}={}){if(!Oi)return{waited:!1,timedOut:!1};let t=Date.now(),n=null,r=await Promise.race([Oi.then(()=>!1,()=>!1),new Promise(o=>{n=setTimeout(()=>o(!0),e)})]);return clearTimeout(n),{waited:!0,waitedMs:Date.now()-t,timedOut:r}}function mu(e,{ttlMs:t=nP()}={}){let n=String(e||"");return n?(Mi.set(n,Date.now()+t),()=>hm(n)):()=>{}}function hm(e){Mi.delete(String(e||""))}function cP(){let e=Date.now();for(let[t,n]of Mi)n<=e&&Mi.delete(t);return Mi.size}async function lP({timeoutMs:e=rP()}={}){let t=Date.now()+e;for(;cP()>0||pm&&await pm().catch(()=>!1);){if(Date.now()>t)return!1;await aP(oP)}return!0}function m0({cli:e=fm.codex,sessionName:t=null,from:n=null,to:r,reason:o="sweep"}={}){let s=String(r||"").trim();if(!s||i0.has(s))return!1;i0.add(s);let a=c0.then(()=>uP({cli:e,sessionName:t,from:n,to:s,reason:o})).catch(()=>{});c0=a;let i=a.then(()=>{Oi===i&&(Oi=null)});return Oi=i,!0}function wm({sessionName:e,from:t,to:n}={}){let r=String(n||"").trim();r&&(ee({flow:"cli-currency",phase:"fallback",cli:"codex",sessionName:e,from:t,to:r}).catch(()=>{}),m0({cli:fm.codex,sessionName:e,from:t,to:r,reason:"chooser"}))}async function uP({cli:e,sessionName:t,from:n,to:r,reason:o}){await ee({flow:"codex-update",phase:"start",cli:e.name,sessionName:t,from:n,to:r,reason:o}).catch(()=>{});try{await lP()||await ee({flow:"codex-update",phase:"lease-wait-cap",cli:e.name,to:r}).catch(()=>{});let{bin:a,env:i}=await p0(e);await du("npm",["install","-g",e.pkg],{env:i,timeout:eP});let c=await f0(e,a).catch(()=>null)||r;await ee({flow:"codex-update",phase:"done",cli:e.name,sessionName:t,from:n,to:r,version:c,reason:o}).catch(()=>{}),await l0({cli:e.name,sessionName:t,from:n,to:r,version:c,status:"updated",reason:o})}catch(s){let a=String(s?.message||s).slice(0,300);await ee({flow:"codex-update",phase:"failed",cli:e.name,sessionName:t,from:n,to:r,error:a,reason:o}).catch(()=>{}),await l0({cli:e.name,sessionName:t,from:n,to:r,status:"failed",error:a,reason:o})}}async function l0(e){if(dm)try{await dm(e)}catch{}}async function dP(e="codex",{reason:t="sweep"}={}){let n=fm[e],r={cli:e,installed:null,latest:null,drift:!1,scheduled:!1};if(!n)return r;try{let{bin:o,env:s}=await p0(n);r.installed=await f0(n,o);let a=await du("npm",["view",n.pkg,"dist-tags.latest"],{env:s,timeout:u0});if(r.latest=String(a.stdout||"").trim().split(/\s+/).pop()||null,!/^\d+\.\d+\.\d+/.test(r.latest||""))throw new Error(`registry answered "${r.latest}"`);r.drift=!!(r.installed&&iP(r.installed,r.latest)),await ee({flow:"cli-currency",phase:"discover",cli:e,installed:r.installed,latest:r.latest,drift:r.drift,reason:t}).catch(()=>{}),r.drift&&(r.scheduled=m0({cli:n,from:r.installed,to:r.latest,reason:t}))}catch(o){await ee({flow:"cli-currency",phase:"discover-failed",cli:e,error:String(o?.message||o).slice(0,300),reason:t}).catch(()=>{})}return r}async function pP({reason:e="sweep"}={}){let t=[];for(let n of sP)t.push(await dP(n,{reason:e}));return t}function h0({env:e=process.env,initialDelayMs:t=9e4}={}){let n=e.BOSTRAT_CLI_CURRENCY_MS===void 0?216e5:Number(e.BOSTRAT_CLI_CURRENCY_MS);if(!(n>0))return null;let r=()=>pP({reason:"sweep"}).catch(()=>{}),o=setTimeout(r,t);o.unref?.();let s=setInterval(r,n);return s.unref?.(),{stop:()=>{clearTimeout(o),clearInterval(s)}}}var du,eP,u0,tP,nP,rP,oP,fm,sP,i0,c0,Oi,Mi,dm,pm,qo=G(()=>{yn();du=QN(ZN),eP=Number(process.env.BOSTRAT_CODEX_UPDATE_TIMEOUT_MS)||5*6e4,u0=Number(process.env.BOSTRAT_CLI_REGISTRY_TIMEOUT_MS)||15e3,tP=()=>Number(process.env.BOSTRAT_CLI_UPDATE_WAIT_MS)||45e3,nP=()=>Number(process.env.BOSTRAT_CLI_SPAWN_LEASE_MS)||9e4,rP=()=>Number(process.env.BOSTRAT_CLI_LEASE_WAIT_MS)||12e4,oP=250,fm={codex:{name:"codex",pkg:"@openai/codex",bin:"codex",versionRe:/^codex-cli\s*/}},sP=["codex"],i0=new Set,c0=Promise.resolve(),Oi=null,Mi=new Map,dm=null;pm=null});import w0 from"node:fs/promises";import fP from"node:os";import Ci from"node:path";function mP(e){let n=Ci.resolve(e).slice(1).replace(/\//g,"-").replace(/\./g,""),r=process.env.CURSOR_CONFIG_DIR||Ci.join(fP.homedir(),".cursor");return Ci.join(r,"projects",n)}async function Qs(e){if(!e||typeof e!="string")return;let t=Ci.resolve(e),n=mP(t),r=Ci.join(n,".workspace-trusted");await w0.mkdir(n,{recursive:!0}),await w0.writeFile(r,`${JSON.stringify({trustedAt:new Date().toISOString(),workspacePath:t},null,2)}
22
+ `,"utf8")}var hu=G(()=>{});import ym from"node:fs/promises";import qr from"node:path";import{execFile as hP}from"node:child_process";import{promisify as wP}from"node:util";async function vP(e){try{return(await ym.stat(qr.join(e,".git"))).isDirectory()?"repo":"worktree"}catch{return null}}async function SP(e){let t=i=>ym.readFile(qr.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 fr(){let e=new Map;async function t(o,s){if(e.has(o))return;let a=await vP(o);if(a==="worktree")return;if(a==="repo"){e.set(o,{path:o,name:qr.basename(o),branch:await SP(o)});return}if(s>=kP)return;let i;try{i=await ym.readdir(o,{withFileTypes:!0})}catch{return}for(let c of i)!c.isDirectory()||c.name.startsWith(".")||xP.has(c.name)||await t(qr.join(o,c.name),s+1)}for(let o of bP)await t(qr.resolve(o),0);let n=new Set,r=[];for(let o of e.values()){let s=await Me(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 TP(e){let t=String(e||"").trim().match(/github\.com[:/]+([^/\s]+)\/([^/\s]+?)(?:\.git)?\/?$/i);return t?`${t[1]}/${t[2]}`:null}async function Me(e){if(!e)return null;if(gm.has(e))return gm.get(e);let t=null;try{let{stdout:n}=await gP("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});t=TP(n)}catch{t=null}return gm.set(e,t),t}async function ea(e){let t=String(e||"").toLowerCase();if(!t)return null;for(let n of await fr())if((await Me(n.path))?.toLowerCase()===t)return n.path;return null}var gP,g0,yP,bP,kP,xP,gm,Gr=G(()=>{gP=wP(hP),g0=process.env.HOME||"/home/globo",yP=qr.join(process.env.BOSTRAT_STATE_DIR||qr.join(g0,".bostrat"),"repos"),bP=[...(process.env.BOSTRAT_REPOS_ROOT||qr.join(g0,"Documents")).split(","),yP].map(e=>e.trim()).filter(Boolean),kP=Number(process.env.BOSTRAT_REPOS_DEPTH)||3,xP=new Set(["node_modules",".git",".cache","dist","build",".next","vendor","__pycache__","venv",".venv","target"]);gm=new Map});function ta(e=Date.now()){if(Ko)return{tripped:!1,holdMs:1/0};if(Go>e)return{tripped:!1,holdMs:Go-e};if((!Pi||e-Pi>=wu.windowMs)&&(Pi=e,Ni=0),Ni++,Ni<wu.trip)return{tripped:!1,holdMs:0};gu++;let t=Math.min(wu.minMs*2**(gu-1),wu.maxMs);return Go=e+t,Ni=0,Pi=0,{tripped:!0,holdMs:t}}function y0(){Ni=0,Pi=0,gu=0,Go=0}function Di(e=Date.now()){return Ko?1/0:Go>e?Go-e:0}function na(e=Date.now()){return Di(e)>0}function bm(e={}){Ko={at:Date.now(),...e},Go=1/0}function yu(){return Ko}function b0(e=Date.now()){return{held:na(e),holdMs:Ko?null:Di(e),holds:gu,removed:Ko?{...Ko}:null}}var AP,wu,Ni,Pi,gu,Go,Ko,km=G(()=>{AP={trip:3,windowMs:3e5,minMs:3e5,maxMs:216e5},wu={...AP},Ni=0,Pi=0,gu=0,Go=0,Ko=null});import EP from"node:fs";import k0 from"node:fs/promises";import Bi from"node:path";import _P from"node:os";import{fileURLToPath as IP}from"node:url";import{execFile as $P}from"node:child_process";import{promisify as RP}from"node:util";function De(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 bu(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}function A0(e){return e?.status===404&&/not granted/i.test(String(e?.message||""))}async function ra(e,{env:t=process.env}={}){let n=String(e||"").toLowerCase();if(!v0.test(n))throw Vo("repo must be owner/name",400);let r=xm.get(n);if(r&&r.expiresAt-Date.now()>CP)return r;if(!bu(t))throw Vo("node is not plane-linked \u2014 GitHub auth unavailable",503);if(na()){if(r&&r.expiresAt>Date.now())return r;throw Vo(yu()?"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 S0(`${De(t)}/v1/github/token?repo=${encodeURIComponent(e)}`,{headers:T0(t)})}catch(i){if(r&&r.expiresAt>Date.now())return r;throw Vo(`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)&&ta(),o.status>=500&&r&&r.expiresAt>Date.now())return r;throw Vo(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 xm.set(n,a),a}async function Li({env:e=process.env,force:t=!1}={}){if(!bu(e))return{configured:!1,repos:[],username:null};if(!t&&Kr&&Date.now()-Kr.at<NP)return Kr.data;if(na())return Kr?.data??{configured:!0,repos:[],username:null,error:"plane refused this node's token"};try{let n=await S0(`${De(e)}/v1/github/repos`,{headers:T0(e)});if((n.status===401||n.status===403||n.status===410)&&ta(),!n.ok)throw new Error(`plane replied ${n.status}`);let r=await n.json();return Kr={at:Date.now(),data:r},r}catch(n){return Kr?Kr.data:{configured:!0,repos:[],username:null,error:n?.message||String(n)}}}function E0(){xm.clear(),Kr=null}async function Bn({cwd:e=null,slug:t=null,env:n=process.env}={}){try{let r=t||(e?await Me(e):null);if(!r)return{};let{token:o}=await ra(r,{env:n});return o?{GH_TOKEN:o}:{}}catch{return{}}}async function vm({env:e=process.env}={}){return(await Li({env:e})).username??null}function LP(e){let[t,n]=String(e).split("/");return Bi.join(MP,t,n)}async function Sm(e,{env:t=process.env}={}){let n=(...r)=>x0("git",["-C",e,...r],{timeout:1e4});await n("config","--replace-all","credential.helper",""),await n("config","--add","credential.helper",`!"${DP()}" ${BP(t)}`),await n("config","credential.useHttpPath","true")}async function ku(e,{env:t=process.env,baseUrl:n="https://github.com"}={}){if(!v0.test(String(e||"")))throw Vo(`bad repo slug "${e}"`,400);let r=LP(e);if(EP.existsSync(Bi.join(r,".git")))return r;let{token:o}=await ra(e,{env:t});await k0.mkdir(Bi.dirname(r),{recursive:!0});let s="!f() { echo username=x-access-token; echo password=$BOSTRAT_GIT_TOKEN; }; f";try{await x0("git",["-c","credential.helper=","-c",`credential.helper=${s}`,"clone","--no-tags","-q",`${n}/${e}.git`,r],{timeout:PP,env:{...t,BOSTRAT_GIT_TOKEN:o,GIT_TERMINAL_PROMPT:"0"}})}catch(a){throw await k0.rm(r,{recursive:!0,force:!0}).catch(()=>{}),Vo(`clone of ${e} failed: ${a?.stderr?.trim?.()||a?.message||a}`,502)}return await Sm(r,{env:t}),r}var x0,OP,MP,v0,CP,NP,PP,S0,xm,Kr,T0,Vo,DP,BP,xt=G(()=>{Gr();km();x0=RP($P),OP=process.env.BOSTRAT_STATE_DIR||Bi.join(process.env.HOME||_P.tmpdir(),".bostrat"),MP=Bi.join(OP,"repos"),v0=/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?\/[A-Za-z0-9._-]{1,100}$/,CP=5*6e4,NP=6e4,PP=10*6e4,S0=fetch,xm=new Map,Kr=null;T0=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),Vo=(e,t)=>Object.assign(new Error(e),{status:t});DP=()=>IP(new URL("../bin/bostrat-git-credential",import.meta.url)),BP=(e=process.env)=>`http://127.0.0.1:${Number(e.PORT)||3362}`});function I0(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}async function R0(e,t,n,r=_0){let o=De(n),s=new AbortController,a=setTimeout(()=>s.abort(),r);try{return await FP(`${o}${e}`,{...t,signal:s.signal})}finally{clearTimeout(a)}}async function O0(e,{env:t=process.env,force:n=!1,timeoutMs:r=_0}={}){if(!I0(t))return{facts:[],source:"unconfigured"};let o=Tm.get(e);if(!n&&o&&Date.now()-o.at<jP)return{facts:o.facts,source:"cache"};try{let s=await R0(`/v1/memory/${encodeURIComponent(e)}`,{headers:$0(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 Tm.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 xu(e,t,{env:n=process.env}={}){if(!I0(n))return{pushed:0,source:"unconfigured"};if(!t?.length)return{pushed:0,source:"empty"};try{let r=await R0(`/v1/memory/${encodeURIComponent(e)}`,{method:"POST",headers:{...$0(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 Tm.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 jP,_0,Tm,FP,$0,M0=G(()=>{xt();jP=6e4,_0=5e3,Tm=new Map,FP=(...e)=>fetch(...e);$0=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});import Am from"node:fs/promises";import oa from"node:path";import UP from"node:os";import{EventEmitter as HP}from"node:events";import{randomUUID as WP}from"node:crypto";function sa(e){return e?.cwd?oa.join(e.cwd,".bostrat","events"):oa.join(Em,"events")}async function VP(e,t){if(!vu.has(t)){let o=(await K(e,t)).reduce((s,a)=>a.seq>s?a.seq:s,0);vu.set(t,o)}let n=vu.get(t)+1;return vu.set(t,n),n}function ji(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 N(e,t){let n=typeof e=="string"?e:e?.id;if(!n)throw new Error("appendEvent: a track (or trackId) is required");if(!t||!qP.has(t.type))throw new Error(`appendEvent: unknown event type "${t?.type}"`);if(t.actor&&!GP.has(t.actor))throw new Error(`appendEvent: bad actor "${t.actor}"`);if(t.source&&!KP.has(t.source))throw new Error(`appendEvent: bad source "${t.source}"`);let r=typeof e=="string"?oa.join(Em,"events"):sa(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=ji(u,Number(t.payload?.ts??t.ts)||Date.now())}let s=await VP(r,n),a=t.userId??process.env.BOSTRAT_OWNER??null,i={id:t.id||WP(),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 N0(c)&&(c=P0(c),l=JSON.parse(c)),await Am.mkdir(r,{recursive:!0}),await Am.appendFile(C0(r,n),c+`
23
+ `),Ze.emit("event",l),Ze.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"?oa.join(Em,"events"):sa(e));let o;try{o=await Am.readFile(C0(n,r),"utf8")}catch{return[]}let s=[];for(let a of o.split(`
24
+ `))if(a.trim())try{s.push(JSON.parse(N0(a)?P0(a):a))}catch{}return s}function D0(e,t){let n=`track:${e}`;return Ze.on(n,t),()=>Ze.off(n,t)}var qP,GP,KP,Ze,Em,C0,vu,zP,N0,P0,be=G(()=>{qP=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","job.stopped","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.login.started","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"]),GP=new Set(["user","agent","orchestrator","system","peer"]),KP=new Set(["hook","otel","statusline","transcript","pane","orchestrator","vendor","cli"]),Ze=new HP;Ze.setMaxListeners(0);Em=process.env.BOSTRAT_STATE_DIR||oa.join(process.env.HOME||UP.tmpdir(),".bostrat");C0=(e,t)=>oa.join(e,`${t}.ndjson`),vu=new Map;zP=/(?<!\\)((?:\\\\)*)\\u0000/g,N0=e=>e.includes("\\u0000"),P0=e=>e.replace(zP,"$1\\ufffd")});import ue from"node:fs/promises";import JP from"node:os";import Ae from"node:path";import{execFile as YP}from"node:child_process";import{promisify as XP}from"node:util";function Tu(){return Ae.join(Au,"memory","repos")}function zo(e){return e===mr?Ae.join(Au,"memory",mr):Ae.join(Tu(),e)}async function Ui(e){try{return JSON.parse(await ue.readFile(Ae.join(e,W0),"utf8"))}catch{return{}}}async function Im(e,t){let n=await Ui(e);for(let[r,o]of t)n[r]=Math.max(Number(n[r])||0,o);await ue.mkdir(e,{recursive:!0}),await ue.writeFile(Ae.join(e,W0),JSON.stringify(n))}function L0(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 j0(e){try{let{stdout:t}=await ZP("git",["-C",e,"config","--get","remote.origin.url"]);return t.trim()||null}catch{return null}}async function $m(e){if(!e)return[];let t=L0(await j0(e));if(t)return[t];let n=[],r=[];try{r=await ue.readdir(e,{withFileTypes:!0})}catch{return[]}for(let o of r){if(!o.isDirectory()||o.name.startsWith("."))continue;let s=L0(await j0(Ae.join(e,o.name)));s&&!n.includes(s)&&n.push(s)}return n}function Eu(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 Vr(e,t){let n=new RegExp(`^\\s*${t}:\\s*(.+?)\\s*$`,"m").exec(e||"");return n?n[1].replace(/^"|"$/g,""):null}async function Ln(e,t=null){let n=t??await ue.readFile(e,"utf8").catch(()=>""),{fm:r}=Eu(n),o=Vr(r,"modified"),s=o?Date.parse(o):NaN;if(Number.isFinite(s))return s;try{return(await ue.stat(e)).mtimeMs}catch{return 0}}function q0(e,t){let n=Vr(e,"scope"),r=/^repo:([a-z0-9][a-z0-9._-]*)$/i.exec(n||"");if(r)return r[1].toLowerCase();if((n||"").toLowerCase()===mr){let o=Vr(e,"trust");if(!o||/^operator/i.test(o))return mr}return t}function Rm(e,t,n,r=new Map){let o=(e||"").split(`
25
25
  `),s=new Map;for(let c of(t||"").split(`
26
26
  `)){let l=ia(c);l&&c.trim().startsWith("-")&&s.set(l,c)}let a=new Set,i=o.map(c=>{let l=ia(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(`
27
27
  `).replace(/\n{3,}/g,`
28
28
 
29
- `)}function G0(e,t){let n=Vr(t,"name")||e.replace(/\.md$/,""),r=Vr(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function Hi(e){let t=[];try{t=await ue.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 K0(e,t){let n=Te.join(e,".bostrat","memory"),r=await Hi(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=F0.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let d of r){let p=Te.join(n,d);if(o)try{if((await ue.stat(p)).mtimeMs<o-eD)continue}catch{continue}let f;try{f=await ue.readFile(p,"utf8")}catch{continue}let{fm:w}=Eu(f),h=q0(w,t);if(!h)continue;let y=zo(h),k=Te.join(y,d),g=await Ln(p,f);if(l.has(y)||l.set(y,await Ui(y)),(l.get(y)[d]||0)>=g)continue;let x=await Ln(k).catch(()=>0);if(await ue.access(k).then(()=>!0).catch(()=>!1)&&x>=g)continue;await ue.mkdir(y,{recursive:!0}),await ue.writeFile(k,f),c++;let _=a.get(y);_||a.set(y,_={won:new Set,generated:new Map}),_.won.add(d),_.generated.set(d,G0(d,w)),i.has(h)||i.set(h,new Set),i.get(h).add(d)}let u=await ue.readFile(Te.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[d,p]of a){let f=Te.join(d,"MEMORY.md"),w=await ue.readFile(f,"utf8").catch(()=>"");await ue.writeFile(f,$m(w,u,p.won,p.generated))}return F0.set(e,s),{harvested:c,changedByKey:i}}async function V0(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await ue.access(Te.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await Im(r),a=await K0(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 tD(){let e=Te.join(Tu,"workspaces"),t=[];try{t=await ue.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return V0(t.filter(n=>n.isDirectory()).map(n=>Te.join(e,n.name)))}async function oD(e,t){let n=zo(e),r=await Ui(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!nD.test(l)||l==="MEMORY.md")continue;let u=Te.join(n,l),d=await ue.access(u).then(()=>!0).catch(()=>!1),p=d?await Ln(u):0,f=Number(c.modified)||0;if(c.deleted){f>p&&(d&&await ue.rm(u,{force:!0}),await _m(n,[[l,f]]),d&&(a.push(l),i++));continue}d&&p>=f||(r[l]||0)>=f||(await ue.mkdir(n,{recursive:!0}),await ue.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=Te.join(n,"MEMORY.md"),l=await ue.readFile(c,"utf8").catch(()=>""),u=$m(l,[...s.values()].join(`
29
+ `)}function G0(e,t){let n=Vr(t,"name")||e.replace(/\.md$/,""),r=Vr(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function Hi(e){let t=[];try{t=await ue.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 K0(e,t){let n=Ae.join(e,".bostrat","memory"),r=await Hi(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=F0.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let d of r){let p=Ae.join(n,d);if(o)try{if((await ue.stat(p)).mtimeMs<o-eD)continue}catch{continue}let f;try{f=await ue.readFile(p,"utf8")}catch{continue}let{fm:w}=Eu(f),h=q0(w,t);if(!h)continue;let y=zo(h),k=Ae.join(y,d),g=await Ln(p,f);if(l.has(y)||l.set(y,await Ui(y)),(l.get(y)[d]||0)>=g)continue;let x=await Ln(k).catch(()=>0);if(await ue.access(k).then(()=>!0).catch(()=>!1)&&x>=g)continue;await ue.mkdir(y,{recursive:!0}),await ue.writeFile(k,f),c++;let _=a.get(y);_||a.set(y,_={won:new Set,generated:new Map}),_.won.add(d),_.generated.set(d,G0(d,w)),i.has(h)||i.set(h,new Set),i.get(h).add(d)}let u=await ue.readFile(Ae.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[d,p]of a){let f=Ae.join(d,"MEMORY.md"),w=await ue.readFile(f,"utf8").catch(()=>"");await ue.writeFile(f,Rm(w,u,p.won,p.generated))}return F0.set(e,s),{harvested:c,changedByKey:i}}async function V0(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await ue.access(Ae.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await $m(r),a=await K0(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 tD(){let e=Ae.join(Au,"workspaces"),t=[];try{t=await ue.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return V0(t.filter(n=>n.isDirectory()).map(n=>Ae.join(e,n.name)))}async function oD(e,t){let n=zo(e),r=await Ui(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!nD.test(l)||l==="MEMORY.md")continue;let u=Ae.join(n,l),d=await ue.access(u).then(()=>!0).catch(()=>!1),p=d?await Ln(u):0,f=Number(c.modified)||0;if(c.deleted){f>p&&(d&&await ue.rm(u,{force:!0}),await Im(n,[[l,f]]),d&&(a.push(l),i++));continue}d&&p>=f||(r[l]||0)>=f||(await ue.mkdir(n,{recursive:!0}),await ue.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=Ae.join(n,"MEMORY.md"),l=await ue.readFile(c,"utf8").catch(()=>""),u=Rm(l,[...s.values()].join(`
30
30
  `),o);if(a.length){let d=new Set(a);u=u.split(`
31
31
  `).filter(p=>!d.has(ia(p))).join(`
32
- `)}await ue.mkdir(n,{recursive:!0}),await ue.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function _u(e,t=null){let n=zo(e),r=t?.length?t:await Hi(n);if(!r.length)return{pushed:0,source:"empty"};let o=rD(await ue.readFile(Te.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=Te.join(n,a),c;try{c=await ue.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await Ln(i,c),indexLine:o.get(a)??null})}return xu(e,s)}async function sD(e,{timeoutMs:t}={}){let{facts:n,source:r}=await O0(e,t?{timeoutMs:t}:{});n.length?await oD(e,n):r==="plane"&&await _u(e)}function aD(e){let t=e.split(`
32
+ `)}await ue.mkdir(n,{recursive:!0}),await ue.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function _u(e,t=null){let n=zo(e),r=t?.length?t:await Hi(n);if(!r.length)return{pushed:0,source:"empty"};let o=rD(await ue.readFile(Ae.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=Ae.join(n,a),c;try{c=await ue.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await Ln(i,c),indexLine:o.get(a)??null})}return xu(e,s)}async function sD(e,{timeoutMs:t}={}){let{facts:n,source:r}=await O0(e,t?{timeoutMs:t}:{});n.length?await oD(e,n):r==="plane"&&await _u(e)}function aD(e){let t=e.split(`
33
33
  `);t.length>B0&&(t=t.slice(0,B0));let n=t.join(`
34
34
  `);for(;Buffer.byteLength(n,"utf8")>QP&&t.length;)t.pop(),n=t.join(`
35
- `);return n}async function cD(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=Te.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let d=zo(u),p=await Ui(d);for(let[y,k]of Object.entries(p)){let g=Te.join(n,y);await ue.access(g).then(()=>!0).catch(()=>!1)&&await Ln(g)<=k&&(await ue.rm(g,{force:!0}),o++)}let f=await Hi(d);if(!f.length)continue;await ue.mkdir(n,{recursive:!0});for(let y of f){let k=Te.join(d,y),g=Te.join(n,y),x=await Ln(k),S=await Ln(g).catch(()=>0);await ue.access(g).then(()=>!0).catch(()=>!1)&&S>=x||(await ue.copyFile(k,g),r++)}let w=await ue.readFile(Te.join(d,"MEMORY.md"),"utf8").catch(()=>""),h=u===mr?"## operator memory":`## repo: ${u}`;w.trim()&&s.push(t.length>1?`${h}
35
+ `);return n}async function cD(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=Ae.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let d=zo(u),p=await Ui(d);for(let[y,k]of Object.entries(p)){let g=Ae.join(n,y);await ue.access(g).then(()=>!0).catch(()=>!1)&&await Ln(g)<=k&&(await ue.rm(g,{force:!0}),o++)}let f=await Hi(d);if(!f.length)continue;await ue.mkdir(n,{recursive:!0});for(let y of f){let k=Ae.join(d,y),g=Ae.join(n,y),x=await Ln(k),S=await Ln(g).catch(()=>0);await ue.access(g).then(()=>!0).catch(()=>!1)&&S>=x||(await ue.copyFile(k,g),r++)}let w=await ue.readFile(Ae.join(d,"MEMORY.md"),"utf8").catch(()=>""),h=u===mr?"## operator memory":`## repo: ${u}`;w.trim()&&s.push(t.length>1?`${h}
36
36
 
37
37
  ${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(`
38
38
 
39
39
  `)+`
40
- `,c=aD(i);await ue.mkdir(n,{recursive:!0}),await ue.writeFile(Te.join(n,"MEMORY.md"),c);let l=Te.join(n,"claude");return await ue.mkdir(l,{recursive:!0}),await ue.writeFile(Te.join(l,"MEMORY.md"),iD,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function z0(e){try{let t=await Im(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,mr];return await Promise.all(n.map(r=>sD(r,{timeoutMs:lD}))),await cD(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function J0(){return{...ct,pending:aa.size,queued:Em.size}}function Y0(e){if(Su.has(e))return Su.get(e);Em.add(e);let t=U0.then(async()=>{Em.delete(e),Su.delete(e);let n=await Rm(e);return ct.runs++,ct.lastRunAt=Date.now(),n.error?(ct.errors++,ct.lastError=n.error):ct.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return Su.set(e,t),U0=t.then(()=>{}),t}function Iu(e,{delayMs:t=uD}={}){if(!e||typeof e!="string")return;ct.scheduled++;let n=aa.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{aa.delete(e),Y0(e)},t);r.unref?.(),aa.set(e,r)}async function $u(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await ue.access(Te.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=aa.get(e);r&&(clearTimeout(r),aa.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([Y0(e),s])}finally{clearTimeout(o)}}async function X0(e){return Fi||(Fi=(async()=>{try{H0||(H0=!0,await pD());let{harvested:t,changedByKey:n}=await V0(e);for(let[r,o]of n)await _u(r,[...o]);return ct.reconciles++,ct.lastReconcileAt=Date.now(),ct.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return ct.errors++,ct.lastError=t?.message||String(t),{harvested:0,error:ct.lastError}}finally{Fi=null}})(),Fi)}function dD(){return Te.join(Tu,"memory",".full-sweep-done")}async function Z0(){let e=dD();try{let t=JSON.parse(await ue.readFile(e,"utf8"));return ct.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...ct.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await tD();for(let[o,s]of n)await _u(o,[...s]);let r={at:Date.now(),harvested:t};return await ue.mkdir(Te.dirname(e),{recursive:!0}),await ue.writeFile(e,JSON.stringify(r)),ct.backfill=r,{ran:!0,...r}}catch(t){return ct.errors++,ct.lastError=t?.message||String(t),{ran:!1,error:ct.lastError}}}async function pD(){let e=0,t=[];try{t=await ue.readdir(Au(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=Te.join(Au(),n.name),o=zo(mr),s=new Set,a=new Map;for(let f of await Hi(r)){let w=Te.join(r,f),h;try{h=await ue.readFile(w,"utf8")}catch{continue}let{fm:y}=Eu(h);if(q0(y,n.name)!==mr)continue;let k=Te.join(o,f),g=await Ln(k).catch(()=>0),x=await Ln(w,h);await ue.mkdir(o,{recursive:!0}),x>g&&await ue.writeFile(k,h),await ue.rm(w,{force:!0}),s.add(f),a.set(f,G0(f,y)),e++}if(!s.size)continue;let i=Date.now();await _m(r,[...s].map(f=>[f,i])),await xu(n.name,[...s].map(f=>({file:f,deleted:!0,modified:i})));let c=Te.join(r,"MEMORY.md"),l=await ue.readFile(c,"utf8").catch(()=>""),u=l.split(`
40
+ `,c=aD(i);await ue.mkdir(n,{recursive:!0}),await ue.writeFile(Ae.join(n,"MEMORY.md"),c);let l=Ae.join(n,"claude");return await ue.mkdir(l,{recursive:!0}),await ue.writeFile(Ae.join(l,"MEMORY.md"),iD,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function z0(e){try{let t=await $m(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,mr];return await Promise.all(n.map(r=>sD(r,{timeoutMs:lD}))),await cD(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function J0(){return{...ct,pending:aa.size,queued:_m.size}}function Y0(e){if(Su.has(e))return Su.get(e);_m.add(e);let t=U0.then(async()=>{_m.delete(e),Su.delete(e);let n=await Om(e);return ct.runs++,ct.lastRunAt=Date.now(),n.error?(ct.errors++,ct.lastError=n.error):ct.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return Su.set(e,t),U0=t.then(()=>{}),t}function Iu(e,{delayMs:t=uD}={}){if(!e||typeof e!="string")return;ct.scheduled++;let n=aa.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{aa.delete(e),Y0(e)},t);r.unref?.(),aa.set(e,r)}async function $u(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await ue.access(Ae.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=aa.get(e);r&&(clearTimeout(r),aa.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([Y0(e),s])}finally{clearTimeout(o)}}async function X0(e){return Fi||(Fi=(async()=>{try{H0||(H0=!0,await pD());let{harvested:t,changedByKey:n}=await V0(e);for(let[r,o]of n)await _u(r,[...o]);return ct.reconciles++,ct.lastReconcileAt=Date.now(),ct.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return ct.errors++,ct.lastError=t?.message||String(t),{harvested:0,error:ct.lastError}}finally{Fi=null}})(),Fi)}function dD(){return Ae.join(Au,"memory",".full-sweep-done")}async function Z0(){let e=dD();try{let t=JSON.parse(await ue.readFile(e,"utf8"));return ct.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...ct.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await tD();for(let[o,s]of n)await _u(o,[...s]);let r={at:Date.now(),harvested:t};return await ue.mkdir(Ae.dirname(e),{recursive:!0}),await ue.writeFile(e,JSON.stringify(r)),ct.backfill=r,{ran:!0,...r}}catch(t){return ct.errors++,ct.lastError=t?.message||String(t),{ran:!1,error:ct.lastError}}}async function pD(){let e=0,t=[];try{t=await ue.readdir(Tu(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=Ae.join(Tu(),n.name),o=zo(mr),s=new Set,a=new Map;for(let f of await Hi(r)){let w=Ae.join(r,f),h;try{h=await ue.readFile(w,"utf8")}catch{continue}let{fm:y}=Eu(h);if(q0(y,n.name)!==mr)continue;let k=Ae.join(o,f),g=await Ln(k).catch(()=>0),x=await Ln(w,h);await ue.mkdir(o,{recursive:!0}),x>g&&await ue.writeFile(k,h),await ue.rm(w,{force:!0}),s.add(f),a.set(f,G0(f,y)),e++}if(!s.size)continue;let i=Date.now();await Im(r,[...s].map(f=>[f,i])),await xu(n.name,[...s].map(f=>({file:f,deleted:!0,modified:i})));let c=Ae.join(r,"MEMORY.md"),l=await ue.readFile(c,"utf8").catch(()=>""),u=l.split(`
41
41
  `).filter(f=>!s.has(ia(f))).join(`
42
- `);await ue.writeFile(c,u).catch(()=>{});let d=Te.join(o,"MEMORY.md"),p=await ue.readFile(d,"utf8").catch(()=>"");await ue.writeFile(d,$m(p,l,s,a))}return{moved:e}}async function Q0(){let e=[],t=[mr];try{for(let n of await ue.readdir(Au(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=zo(n),o=await Hi(r),s=await Ui(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await ue.readFile(Te.join(r,i),"utf8").catch(()=>""),{fm:l}=Eu(c);a.push({file:i,name:Vr(l,"name")||i.replace(/\.md$/,""),description:Vr(l,"description")||"",scope:Vr(l,"scope")||null,modified:await Ln(Te.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function ex(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=zo(e),r=Te.join(n,t);if(!await ue.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await ue.rm(r,{force:!0}),await _m(n,[[t,s]]);let a=Te.join(n,"MEMORY.md"),i=await ue.readFile(a,"utf8").catch(()=>"");await ue.writeFile(a,i.split(`
42
+ `);await ue.writeFile(c,u).catch(()=>{});let d=Ae.join(o,"MEMORY.md"),p=await ue.readFile(d,"utf8").catch(()=>"");await ue.writeFile(d,Rm(p,l,s,a))}return{moved:e}}async function Q0(){let e=[],t=[mr];try{for(let n of await ue.readdir(Tu(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=zo(n),o=await Hi(r),s=await Ui(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await ue.readFile(Ae.join(r,i),"utf8").catch(()=>""),{fm:l}=Eu(c);a.push({file:i,name:Vr(l,"name")||i.replace(/\.md$/,""),description:Vr(l,"description")||"",scope:Vr(l,"scope")||null,modified:await Ln(Ae.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function ex(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=zo(e),r=Ae.join(n,t);if(!await ue.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await ue.rm(r,{force:!0}),await Im(n,[[t,s]]);let a=Ae.join(n,"MEMORY.md"),i=await ue.readFile(a,"utf8").catch(()=>"");await ue.writeFile(a,i.split(`
43
43
  `).filter(l=>ia(l)!==t).join(`
44
- `)).catch(()=>{});let c=await xu(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function Rm(e){try{let t=await Im(e),{harvested:n,changedByKey:r}=await K0(e,t[0]||null);for(let[o,s]of r)await _u(o,[...s]);return n>0&&await mD(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function mD(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,fD)}}await N({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var ZP,Tu,B0,QP,mr,W0,ia,F0,eD,nD,rD,iD,lD,uD,aa,Em,U0,ct,Su,H0,Fi,fD,Wi=G(()=>{M0();be();ZP=XP(YP),Tu=process.env.BOSTRAT_STATE_DIR||Te.join(process.env.HOME||JP.tmpdir(),".bostrat"),B0=200,QP=25*1024;mr="operator";W0=".tombstones.json";ia=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;F0=new Map,eD=2e3;nD=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,rD=e=>{let t=new Map;for(let n of(e||"").split(`
44
+ `)).catch(()=>{});let c=await xu(e,[{file:t,deleted:!0,modified:s}]);return{deleted:t,key:e,plane:c.source}}async function Om(e){try{let t=await $m(e),{harvested:n,changedByKey:r}=await K0(e,t[0]||null);for(let[o,s]of r)await _u(o,[...s]);return n>0&&await mD(e,r).catch(()=>{}),{harvested:n}}catch(t){return{harvested:0,error:t?.message||String(t)}}}async function mD(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,fD)}}await N({id:n,cwd:e},{type:"memory.harvested",actor:"orchestrator",payload:{harvested:o,keys:r,ts:Date.now()}})}var ZP,Au,B0,QP,mr,W0,ia,F0,eD,nD,rD,iD,lD,uD,aa,_m,U0,ct,Su,H0,Fi,fD,Wi=G(()=>{M0();be();ZP=XP(YP),Au=process.env.BOSTRAT_STATE_DIR||Ae.join(process.env.HOME||JP.tmpdir(),".bostrat"),B0=200,QP=25*1024;mr="operator";W0=".tombstones.json";ia=e=>/\]\(([^)]+\.md)\)/.exec(e)?.[1]||null;F0=new Map,eD=2e3;nD=/^[A-Za-z0-9][A-Za-z0-9._-]*\.md$/,rD=e=>{let t=new Map;for(let n of(e||"").split(`
45
45
  `)){let r=ia(n);r&&n.trim().startsWith("-")&&t.set(r,n)}return t};iD=`# Track memory
46
46
 
47
47
  Shared Track memory (all providers) lives one level up: read \`../MEMORY.md\` for the
48
48
  index and the fact files beside it. Facts you save here stay Claude-local but ride the
49
49
  same sync; prefer adding durable cross-provider facts to \`../\` following its format.
50
- `;lD=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;uD=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,aa=new Map,Em=new Set,U0=Promise.resolve(),ct={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};Su=new Map;H0=!1,Fi=null;fD=20});import Ru from"node:fs/promises";import hD from"node:path";async function Bt(e,t,{mode:n}={}){await Ru.mkdir(hD.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++wD}.tmp`;try{await Ru.writeFile(r,JSON.stringify(t,null,2)+`
51
- `,n!=null?{mode:n}:void 0),await Ru.rename(r,e)}catch(o){throw await Ru.unlink(r).catch(()=>{}),o}}var wD,zr=G(()=>{wD=0});import sx from"node:fs/promises";import ax from"node:os";import ix from"node:path";function Ge(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Ki(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),gD);try{return await vD(`${De(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function dx(){return Mu||(Om||=sx.readFile(cx(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>Mu={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>Om=null),Om)}async function Cu(){await Bt(cx(),Mu).catch(()=>{})}function rx(e){return e.op==="blob"?`blob ${e.family} ${e.id} ${e.v} ${e.kind}`:`${e.op} ${e.family} ${e.id}`}async function Cm(e){let t=await dx(),n=rx(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=>rx(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>tx&&(t.ops=t.ops.slice(-tx)),await Cu()}function ox(){Ou||(Ou=setTimeout(()=>{Ou=null,ca().catch(()=>{})},SD),Ou.unref?.())}function Mm(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function TD(e,t=process.env){if(e.op==="record"){let n=await Ki(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...Gi(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:lx()}]})},t);if(!n.ok)throw Mm(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 sx.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await Ki(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...Gi(t),"content-type":"application/octet-stream"},body:n},t);if(!r.ok&&r.status!==400)throw Mm(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 Ki(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:Gi(t)},t);if(!n.ok)throw Mm(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function ca({env:e=process.env,log:t=console,now:n=Date.now()}={}){return Ge(e)?qi||(qi=(async()=>{let r=await dx();ED(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await TD(a,e)}catch(c){if(!c?.refused)return ox(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<bD)return ox(),await Cu(),{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>nx&&(r.parked=r.parked.slice(-nx)),s++,await Cu();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await Cu()}return{flushed:o,parked:s,pending:0}})().finally(()=>{qi=null}),qi):{flushed:0,source:"unconfigured"}}function ED(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=AD);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 It(e,t,{trackId:n=null,env:r=process.env}={}){return Ge(r)?(await Cm({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),ca({env:r})):{queued:!1,source:"unconfigured"}}async function Jr(e,t,n,r,o,{env:s=process.env}={}){return Ge(s)?(await Cm({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),ca({env:s})):{queued:!1,source:"unconfigured"}}async function bn(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return Ge(r)?(await Cm({op:"delete",family:e,id:t,deletedAt:n}),ca({env:r})):{queued:!1,source:"unconfigured"}}async function pt(e,{env:t=process.env}={}){if(!Ge(t))return{records:[],source:"unconfigured"};try{let n=await Ki(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:Gi(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 Vi(e,t,n,r,{env:o=process.env}={}){if(!Ge(o))return null;try{let s=await Ki(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:Gi(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 gD,yD,tx,bD,nx,kD,xD,cx,lx,ux,vD,SD,AD,Gi,Mu,Om,Ou,qi,Yr=G(()=>{xt();zr();gD=1e4,yD=3e4,tx=2e3,bD=5,nx=100,kD=60*6e4,xD=()=>process.env.BOSTRAT_STATE_DIR||ix.join(process.env.HOME||ax.tmpdir(),".bostrat"),cx=()=>ix.join(xD(),"content-outbox.json"),lx=()=>process.env.BOSTRAT_NODE_ID||ax.hostname(),ux=()=>lx(),vD=(...e)=>fetch(...e),SD=yD,AD=kD;Gi=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});Mu=null,Om=null,Ou=null,qi=null});import Nm from"node:fs/promises";import px from"node:path";async function fx(e,t,{box:n=null,agent:r=null}={}){if(!e||!Ge())return{pushed:!1};try{let o=Date.now();return await It("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await Jr("checkpoints",e,o,"md",t),zi=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function OD(){if(zi&&Date.now()-zi.at<RD)return{records:zi.records,source:"plane"};let e=await pt("checkpoints");return e.source==="plane"&&(zi={at:Date.now(),records:e.records}),e}async function Nu(e){try{let t=$D(e);if(!t||!Ge())return{restored:!1};let n=px.join(e,_D,ID);if(await Nm.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await OD();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 Vi("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await Nm.mkdir(px.dirname(n),{recursive:!0}),await Nm.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var _D,ID,$D,RD,zi,Pu=G(()=>{Yr();_D=".bostrat/handoff",ID="latest.md",$D=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;RD=6e4,zi=null});import Du from"node:fs/promises";import Pm from"node:path";import MD from"node:os";async function hx(e=mx){await Du.mkdir(e,{recursive:!0});for(let t of ND){let n=t==="prepare-commit-msg"?PD:t==="post-commit"?DD:`${Dm}exit 0
52
- `,r=Pm.join(e,t),o=null;try{o=await Du.readFile(r,"utf8")}catch{}o!==n&&await Du.writeFile(r,n,{mode:493}),await Du.chmod(r,493).catch(()=>{})}return e}function wx({nodeUrl:e,dir:t=mx,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",`${Ji}=${e}`]}function gx(e=process.env){return e.BOSTRAT_NODE_URL||`http://127.0.0.1:${e.PORT||3362}`}var Ji,CD,mx,ND,Dm,PD,DD,Bm=G(()=>{Ys();Ji="BOSTRAT_NODE_URL",CD=process.env.BOSTRAT_STATE_DIR||Pm.join(process.env.HOME||MD.tmpdir(),".bostrat"),mx=Pm.join(CD,"git-hooks"),ND=["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"],Dm=`#!/bin/sh
50
+ `;lD=Number(process.env.BOSTRAT_MEMORY_SPAWN_PULL_MS)||1500;uD=Number(process.env.BOSTRAT_MEMORY_HARVEST_DEBOUNCE_MS)||2e3,aa=new Map,_m=new Set,U0=Promise.resolve(),ct={scheduled:0,runs:0,harvested:0,errors:0,lastRunAt:null,lastError:null,reconciles:0,lastReconcileAt:null,backfill:null};Su=new Map;H0=!1,Fi=null;fD=20});import Ru from"node:fs/promises";import hD from"node:path";async function Bt(e,t,{mode:n}={}){await Ru.mkdir(hD.dirname(e),{recursive:!0});let r=`${e}.${process.pid}.${++wD}.tmp`;try{await Ru.writeFile(r,JSON.stringify(t,null,2)+`
51
+ `,n!=null?{mode:n}:void 0),await Ru.rename(r,e)}catch(o){throw await Ru.unlink(r).catch(()=>{}),o}}var wD,zr=G(()=>{wD=0});import sx from"node:fs/promises";import ax from"node:os";import ix from"node:path";function Ge(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Ki(e,t={},n=process.env){let r=new AbortController,o=setTimeout(()=>r.abort(),gD);try{return await vD(`${De(n)}${e}`,{...t,signal:r.signal})}finally{clearTimeout(o)}}async function dx(){return Mu||(Mm||=sx.readFile(cx(),"utf8").then(e=>JSON.parse(e)).catch(()=>({ops:[]})).then(e=>Mu={ops:Array.isArray(e?.ops)?e.ops:[],parked:Array.isArray(e?.parked)?e.parked:[]}).finally(()=>Mm=null),Mm)}async function Cu(){await Bt(cx(),Mu).catch(()=>{})}function rx(e){return e.op==="blob"?`blob ${e.family} ${e.id} ${e.v} ${e.kind}`:`${e.op} ${e.family} ${e.id}`}async function Nm(e){let t=await dx(),n=rx(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=>rx(o)===n);r>=0?t.ops[r]=e:t.ops.push(e)}t.ops.length>tx&&(t.ops=t.ops.slice(-tx)),await Cu()}function ox(){Ou||(Ou=setTimeout(()=>{Ou=null,ca().catch(()=>{})},SD),Ou.unref?.())}function Cm(e){let t=new Error(`plane ${e}`);return t.refused=!0,t}async function AD(e,t=process.env){if(e.op==="record"){let n=await Ki(`/v1/content/${encodeURIComponent(e.family)}`,{method:"POST",headers:{...Gi(t),"content-type":"application/json"},body:JSON.stringify({records:[{id:e.id,trackId:e.trackId??null,data:e.data,updatedAt:e.updatedAt,originNode:lx()}]})},t);if(!n.ok)throw Cm(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 sx.readFile(e.path).catch(()=>null);if(!n)return{delivered:!0,dropped:"source file gone"};let r=await Ki(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}/blob?v=${e.v}&kind=${encodeURIComponent(e.kind)}`,{method:"POST",headers:{...Gi(t),"content-type":"application/octet-stream"},body:n},t);if(!r.ok&&r.status!==400)throw Cm(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 Ki(`/v1/content/${encodeURIComponent(e.family)}/${encodeURIComponent(e.id)}?deletedAt=${e.deletedAt}`,{method:"DELETE",headers:Gi(t)},t);if(!n.ok)throw Cm(n.status);return{delivered:!0}}return{delivered:!0,dropped:"unknown op"}}async function ca({env:e=process.env,log:t=console,now:n=Date.now()}={}){return Ge(e)?qi||(qi=(async()=>{let r=await dx();ED(r,n);let o=0,s=0;for(;r.ops.length;){let a=r.ops[0],i;try{i=await AD(a,e)}catch(c){if(!c?.refused)return ox(),{flushed:o,parked:s,pending:r.ops.length,error:c?.message||String(c)};if(a.refusals=(a.refusals||0)+1,a.refusals<bD)return ox(),await Cu(),{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>nx&&(r.parked=r.parked.slice(-nx)),s++,await Cu();continue}i.rejected&&t.error?.(`[content-plane] ALARM plane rejected ${a.op} ${a.family}/${a.id}: ${i.rejected}`),r.ops.shift(),o++,await Cu()}return{flushed:o,parked:s,pending:0}})().finally(()=>{qi=null}),qi):{flushed:0,source:"unconfigured"}}function ED(e,t){if(!e.parked.length||e.ops.length)return;let n=e.parked.filter(r=>t-(r.parkedAt||0)>=TD);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 It(e,t,{trackId:n=null,env:r=process.env}={}){return Ge(r)?(await Nm({op:"record",family:e,id:t.id,trackId:n??t.trackId??null,data:t,updatedAt:Number(t.updatedAt)||Date.now()}),ca({env:r})):{queued:!1,source:"unconfigured"}}async function Jr(e,t,n,r,o,{env:s=process.env}={}){return Ge(s)?(await Nm({op:"blob",family:e,id:t,v:Number(n),kind:r,path:o}),ca({env:s})):{queued:!1,source:"unconfigured"}}async function bn(e,t,{deletedAt:n=Date.now(),env:r=process.env}={}){return Ge(r)?(await Nm({op:"delete",family:e,id:t,deletedAt:n}),ca({env:r})):{queued:!1,source:"unconfigured"}}async function pt(e,{env:t=process.env}={}){if(!Ge(t))return{records:[],source:"unconfigured"};try{let n=await Ki(`/v1/content/${encodeURIComponent(e)}?tombstones=1`,{headers:Gi(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 Vi(e,t,n,r,{env:o=process.env}={}){if(!Ge(o))return null;try{let s=await Ki(`/v1/content/${encodeURIComponent(e)}/${encodeURIComponent(t)}/blob?v=${Number(n)}&kind=${encodeURIComponent(r)}`,{headers:Gi(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 gD,yD,tx,bD,nx,kD,xD,cx,lx,ux,vD,SD,TD,Gi,Mu,Mm,Ou,qi,Yr=G(()=>{xt();zr();gD=1e4,yD=3e4,tx=2e3,bD=5,nx=100,kD=60*6e4,xD=()=>process.env.BOSTRAT_STATE_DIR||ix.join(process.env.HOME||ax.tmpdir(),".bostrat"),cx=()=>ix.join(xD(),"content-outbox.json"),lx=()=>process.env.BOSTRAT_NODE_ID||ax.hostname(),ux=()=>lx(),vD=(...e)=>fetch(...e),SD=yD,TD=kD;Gi=(e=process.env)=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`});Mu=null,Mm=null,Ou=null,qi=null});import Pm from"node:fs/promises";import px from"node:path";async function fx(e,t,{box:n=null,agent:r=null}={}){if(!e||!Ge())return{pushed:!1};try{let o=Date.now();return await It("checkpoints",{id:e,trackId:e,v:o,box:n,agent:r,updatedAt:o},{trackId:e}),await Jr("checkpoints",e,o,"md",t),zi=null,{pushed:!0,v:o}}catch{return{pushed:!1}}}async function OD(){if(zi&&Date.now()-zi.at<RD)return{records:zi.records,source:"plane"};let e=await pt("checkpoints");return e.source==="plane"&&(zi={at:Date.now(),records:e.records}),e}async function Nu(e){try{let t=$D(e);if(!t||!Ge())return{restored:!1};let n=px.join(e,_D,ID);if(await Pm.stat(n).then(()=>!0,()=>!1))return{restored:!1};let{records:r,source:o}=await OD();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 Vi("checkpoints",t,s.data.v,"md");return typeof a!="string"||!a?{restored:!1}:(await Pm.mkdir(px.dirname(n),{recursive:!0}),await Pm.writeFile(n,a),{restored:!0,v:s.data.v})}catch{return{restored:!1}}}var _D,ID,$D,RD,zi,Pu=G(()=>{Yr();_D=".bostrat/handoff",ID="latest.md",$D=e=>/workspaces[/\\]([0-9a-f]{8})$/.exec(e||"")?.[1]??null;RD=6e4,zi=null});import Du from"node:fs/promises";import Dm from"node:path";import MD from"node:os";async function hx(e=mx){await Du.mkdir(e,{recursive:!0});for(let t of ND){let n=t==="prepare-commit-msg"?PD:t==="post-commit"?DD:`${Bm}exit 0
52
+ `,r=Dm.join(e,t),o=null;try{o=await Du.readFile(r,"utf8")}catch{}o!==n&&await Du.writeFile(r,n,{mode:493}),await Du.chmod(r,493).catch(()=>{})}return e}function wx({nodeUrl:e,dir:t=mx,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",`${Ji}=${e}`]}function gx(e=process.env){return e.BOSTRAT_NODE_URL||`http://127.0.0.1:${e.PORT||3362}`}var Ji,CD,mx,ND,Bm,PD,DD,Lm=G(()=>{Ys();Ji="BOSTRAT_NODE_URL",CD=process.env.BOSTRAT_STATE_DIR||Dm.join(process.env.HOME||MD.tmpdir(),".bostrat"),mx=Dm.join(CD,"git-hooks"),ND=["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"],Bm=`#!/bin/sh
53
53
  # bostrat git hook shim (agent/src/git-hooks.js) \u2014 chains to the repo's own hook,
54
54
  # then stamps/reports for rework attribution when running inside a bostrat box.
55
55
  hook=$(basename "$0")
@@ -64,7 +64,7 @@ esac
64
64
  if [ -x "$orig/$hook" ] && [ "$orig/$hook" != "$0" ]; then
65
65
  "$orig/$hook" "$@" || exit $?
66
66
  fi
67
- `,PD=`${Dm}
67
+ `,PD=`${Bm}
68
68
  # \u2500\u2500 bostrat: append provenance trailers (Layer 0). Skipped for merge commits
69
69
  # (nobody "wrote" a merge) and outside a box (no token / no node url).
70
70
  [ -z "$${dr}" ] && exit 0
@@ -76,7 +76,7 @@ printf '%s\\n' "$trailers" | while IFS= read -r line; do
76
76
  [ -n "$line" ] && git interpret-trailers --in-place --if-exists addIfDifferent --trailer "$line" "$1" >/dev/null 2>&1 || true
77
77
  done
78
78
  exit 0
79
- `,DD=`${Dm}
79
+ `,DD=`${Bm}
80
80
  # \u2500\u2500 bostrat: report the commit (code.committed + rework analysis, node-side).
81
81
  [ -z "$${dr}" ] && exit 0
82
82
  [ -z "$${Ji}" ] && exit 0
@@ -85,23 +85,23 @@ cwd=$(git rev-parse --show-toplevel 2>/dev/null)
85
85
  printf '{"sha":"%s","cwd":"%s"}' "$sha" "$cwd" | curl -sS -m 5 -X POST "$${Ji}/api/git/committed" \\
86
86
  -H 'content-type: application/json' -H "${pr}: $${dr}" --data-binary @- >/dev/null 2>&1 || true
87
87
  exit 0
88
- `});import{execFile as bx}from"node:child_process";import{promisify as BD}from"node:util";import Lu from"node:fs";import{randomUUID as kx}from"node:crypto";function Jo(e){return new Promise(t=>setTimeout(t,e))}function Bu(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 xx(e){return`/tmp/tmux-${e}/default`}function LD({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=xx(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function Xi(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${Yi}=1`]}function UD(){return FD.flatMap(e=>["-e",`${e}=`])}function Zi(e,t,n){let r=Yo(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 Yo(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function Xr(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function WD(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:Yo(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function vx(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await Sx(e,{loginShell:t});return r===ju?!0:r===la?!1:n}async function Sx(e,{loginShell:t=!1,timeoutMs:n=Lm}={}){if(!e)return la;let r=t?process.env.SHELL||"/bin/sh":"sh",o=t?"-lic":"-c";try{return await Ce(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),ju}catch(s){return s?.killed||s?.signal?ua:s?.code===1||s?.code===127?la:ua}}async function Fu(e,{retries:t=qD,sleep:n=GD,probe:r=Sx}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:Lm});for(let a=0;s===ua&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:Lm*2});return s}function se(...e){return["-S",zt,...e]}async function Zr(){if(!Lu.existsSync(zt))return!1;try{return await Ce(oe,se("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function Qi(){if(await Zr())return!0;try{Lu.mkdirSync(zt.replace(/\/[^/]+$/,""),{recursive:!0}),await Ce(oe,se("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await Zr()}function je(e){return typeof e=="string"&&KD.test(e)}async function kn(){if(!Lu.existsSync(zt))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 Ce(oe,se("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
89
- `).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,d,p,f,w]=r.split("|"),h=Number(i),y=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(y)&&y>0?y*1e3:null}}).filter(r=>!HD.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function Se(e){return(await kn()).find(n=>n.name===e)||null}function JD(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=zD&&VD.test(t)}function Uu(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function Ax(e){try{let{stdout:t}=await Ce(oe,se("list-sessions","-F","#{session_name}"));return t.split(`
90
- `).map(n=>n.trim()).includes(e)}catch{return!1}}function ZD(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 QD(e,t){let n=Date.now()+ec(),r=ZD(t),o=!1,s=0,a=0;for(;;){if(await Jo(YD),s+=1,!await Ax(e))return;let i=await Ne(e,{lines:15}),c=!o&&XD.test(i)&&!!r?.test(i),l=!o&&!!r?.test(i);if(!c&&!l&&s>1&&!await Fn(e)){if(a+=1,a>1)return}else c||(a=0);if(c){o=!0,await ee({flow:"spawn",phase:"launch-retry",sessionName:e,agent:Xr(t),promptHead:t.slice(0,120)}).catch(()=>{}),await Ce(oe,se("send-keys","-t",e,"C-u")),await Ce(oe,se("send-keys","-t",e,"-l",t)),await Ce(oe,se("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await ee({flow:"spawn",phase:"launch-failed",sessionName:e,agent:Xr(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function jn(e,t=jD,n={}){if(!JD(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=Uu(r);if(!je(o))throw new Error("resulting tmux session name is invalid");if(!await Qi())throw new Error(`host tmux server not running on ${zt} and auto-start failed \u2014 start one: ${oe} -S ${zt} new-session -d -s keeper "sleep 2147483647"`);if(await Ax(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||jm,a=n.agent||Xr(s),i=!!n.resumeSessionId,c=n.resumeSessionId||kx(),l=i?s:Zi(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&Yo(s),p=n.firstRun===!0;if(a==="codex"){let y=await fu();y.waited&&await ee({flow:"cli-currency",phase:"spawn-gate",sessionName:o,...y}),mu(o)}p||(d&&await Wr(t),a==="codex"&&await Xs(t),a==="cursor"&&await Qs(t),await z0(t),n.freshWorkspace!==!0&&await Nu(t));let f=d&&!p?iu():null,w=Yk(),h=["-e",`${dr}=${w}`];h.push(...wx({nodeUrl:gx()})),h.push(...UD()),f&&h.push("-e",`ANTHROPIC_API_KEY=${f}`),d&&h.push(...Xi());try{await Ce(oe,se("new-session","-d","-s",o,"-c",t,...h))}catch(y){throw Bu(f?Bu(y,f):y,w)}return await Xo(o),await Ce(oe,se("set-option","-t",o,"@bostrat-session","1")),await Ce(oe,se("set-option","-t",o,"@bostrat-title",r)),await Ce(oe,se("set-option","-t",o,"@bostrat-sid",c)),await Ce(oe,se("set-option","-t",o,"@bostrat-agent",a)),await Ce(oe,se("send-keys","-t",o,l,"Enter")),WD(l)&&QD(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:w}}async function Lt(e){if(!je(e))throw new Error("invalid session name");await Ce(oe,se("kill-session","-t",e))}async function Tx(e,t){if(je(e))try{let n=t?se("set-option","-t",e,"@bostrat-sid",t):se("set-option","-u","-t",e,"@bostrat-sid");await Ce(oe,n)}catch{}}async function Ne(e,{lines:t=40}={}){if(!je(e))return"";try{let n=se("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await Ce(oe,n);return String(r||"")}catch{return""}}async function Ex(e){if(!je(e))return[];try{let{stdout:t}=await Ce(oe,se("list-panes","-s","-t",e,"-F","#{pane_pid}"));return String(t||"").trim().split(`
88
+ `});import{execFile as bx}from"node:child_process";import{promisify as BD}from"node:util";import Lu from"node:fs";import{randomUUID as kx}from"node:crypto";function Jo(e){return new Promise(t=>setTimeout(t,e))}function Bu(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 xx(e){return`/tmp/tmux-${e}/default`}function LD({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=xx(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function Xi(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${Yi}=1`]}function UD(){return FD.flatMap(e=>["-e",`${e}=`])}function Zi(e,t,n){let r=Yo(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 Yo(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function Xr(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function WD(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:Yo(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function vx(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await Sx(e,{loginShell:t});return r===ju?!0:r===la?!1:n}async function Sx(e,{loginShell:t=!1,timeoutMs:n=jm}={}){if(!e)return la;let r=t?process.env.SHELL||"/bin/sh":"sh",o=t?"-lic":"-c";try{return await Ce(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),ju}catch(s){return s?.killed||s?.signal?ua:s?.code===1||s?.code===127?la:ua}}async function Fu(e,{retries:t=qD,sleep:n=GD,probe:r=Sx}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:jm});for(let a=0;s===ua&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:jm*2});return s}function se(...e){return["-S",zt,...e]}async function Zr(){if(!Lu.existsSync(zt))return!1;try{return await Ce(oe,se("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function Qi(){if(await Zr())return!0;try{Lu.mkdirSync(zt.replace(/\/[^/]+$/,""),{recursive:!0}),await Ce(oe,se("new-session","-d","-s","keeper","sleep 2147483647"))}catch{}return await Zr()}function je(e){return typeof e=="string"&&KD.test(e)}async function kn(){if(!Lu.existsSync(zt))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 Ce(oe,se("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
89
+ `).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,d,p,f,w]=r.split("|"),h=Number(i),y=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(y)&&y>0?y*1e3:null}}).filter(r=>!HD.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function Se(e){return(await kn()).find(n=>n.name===e)||null}function JD(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=zD&&VD.test(t)}function Uu(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function Tx(e){try{let{stdout:t}=await Ce(oe,se("list-sessions","-F","#{session_name}"));return t.split(`
90
+ `).map(n=>n.trim()).includes(e)}catch{return!1}}function ZD(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 QD(e,t){let n=Date.now()+ec(),r=ZD(t),o=!1,s=0,a=0;for(;;){if(await Jo(YD),s+=1,!await Tx(e))return;let i=await Ne(e,{lines:15}),c=!o&&XD.test(i)&&!!r?.test(i),l=!o&&!!r?.test(i);if(!c&&!l&&s>1&&!await Fn(e)){if(a+=1,a>1)return}else c||(a=0);if(c){o=!0,await ee({flow:"spawn",phase:"launch-retry",sessionName:e,agent:Xr(t),promptHead:t.slice(0,120)}).catch(()=>{}),await Ce(oe,se("send-keys","-t",e,"C-u")),await Ce(oe,se("send-keys","-t",e,"-l",t)),await Ce(oe,se("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await ee({flow:"spawn",phase:"launch-failed",sessionName:e,agent:Xr(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function jn(e,t=jD,n={}){if(!JD(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=Uu(r);if(!je(o))throw new Error("resulting tmux session name is invalid");if(!await Qi())throw new Error(`host tmux server not running on ${zt} and auto-start failed \u2014 start one: ${oe} -S ${zt} new-session -d -s keeper "sleep 2147483647"`);if(await Tx(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||Fm,a=n.agent||Xr(s),i=!!n.resumeSessionId,c=n.resumeSessionId||kx(),l=i?s:Zi(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&Yo(s),p=n.firstRun===!0;if(a==="codex"){let y=await fu();y.waited&&await ee({flow:"cli-currency",phase:"spawn-gate",sessionName:o,...y}),mu(o)}p||(d&&await Wr(t),a==="codex"&&await Xs(t),a==="cursor"&&await Qs(t),await z0(t),n.freshWorkspace!==!0&&await Nu(t));let f=d&&!p?iu():null,w=Yk(),h=["-e",`${dr}=${w}`];h.push(...wx({nodeUrl:gx()})),h.push(...UD()),f&&h.push("-e",`ANTHROPIC_API_KEY=${f}`),d&&h.push(...Xi());try{await Ce(oe,se("new-session","-d","-s",o,"-c",t,...h))}catch(y){throw Bu(f?Bu(y,f):y,w)}return await Xo(o),await Ce(oe,se("set-option","-t",o,"@bostrat-session","1")),await Ce(oe,se("set-option","-t",o,"@bostrat-title",r)),await Ce(oe,se("set-option","-t",o,"@bostrat-sid",c)),await Ce(oe,se("set-option","-t",o,"@bostrat-agent",a)),await Ce(oe,se("send-keys","-t",o,l,"Enter")),WD(l)&&QD(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:w}}async function Lt(e){if(!je(e))throw new Error("invalid session name");await Ce(oe,se("kill-session","-t",e))}async function Ax(e,t){if(je(e))try{let n=t?se("set-option","-t",e,"@bostrat-sid",t):se("set-option","-u","-t",e,"@bostrat-sid");await Ce(oe,n)}catch{}}async function Ne(e,{lines:t=40}={}){if(!je(e))return"";try{let n=se("capture-pane","-t",e,"-p");Number.isFinite(t)&&t>0&&n.push("-S",`-${Math.floor(t)}`);let{stdout:r}=await Ce(oe,n);return String(r||"")}catch{return""}}async function Ex(e){if(!je(e))return[];try{let{stdout:t}=await Ce(oe,se("list-panes","-s","-t",e,"-F","#{pane_pid}"));return String(t||"").trim().split(`
91
91
  `).map(n=>Number(n.trim())).filter(n=>Number.isFinite(n)&&n>0)}catch{return[]}}async function _x(e){if(!je(e))return 0;try{let{stdout:t}=await Ce(oe,se("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
92
- `).filter(Boolean).length}catch{return 0}}async function Xo(e,{cols:t=n1,rows:n=r1}={}){if(!je(e))return!0;if(await _x(e))return!1;try{let r=await Ix(e);if(r.cols===t&&r.rows===n)return!0;await Ce(oe,se("resize-window","-t",e,"-x",String(t),"-y",String(n))),await Ce(oe,se("set-window-option","-t",e,"window-size","latest")),await Jo(80)}catch{}return!0}async function o1(e){if(!je(e))return 0;try{let{stdout:t}=await Ce(oe,se("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function Fn(e){let t=await o1(e);if(!t)return!1;try{return await Ce("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function Ix(e){if(!je(e))return{cols:0,rows:0};try{let{stdout:t}=await Ce(oe,se("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 Hu(e,{cols:t=e1,rows:n=t1}={}){if(je(e)&&!await _x(e))try{let r=await Ix(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await Ce(oe,se("resize-window","-t",e,"-x",String(o),"-y",String(s))),await Ce(oe,se("set-window-option","-t",e,"window-size","latest")),await Jo(80))}catch{}}async function Jt(e){return await Hu(e),Ne(e,{lines:ze})}async function Ke(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=>$x.has(s));for(let s=0;s<o.length;s++)await Ce(oe,se("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await Jo(n);return ee({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function Hm(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"&&$x.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 Ce(oe,se("send-keys","-t",e,"-l",a.text)):await Ce(oe,se("send-keys","-t",e,a.key)),n>0&&s<o.length-1&&await Jo(n)}return ee({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 da(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 Ce(oe,se("send-keys","-t",e,"-N",String(r),"BSpace")),ee({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function qu(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 Ce(oe,se("send-keys","-t",e,"-l",s)),n>0&&await Jo(n);ee({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function s1(e,t){return new Promise((n,r)=>{let o=bx(oe,se(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function a1(e,t){let n=`bostrat-${kx().slice(0,8)}`;await s1(["load-buffer","-b",n,"-"],t),await Ce(oe,se("paste-buffer","-p","-d","-b",n,"-t",e))}async function Qe(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!je(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await a1(e,t):await Ce(oe,se("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await Jo(a),await Ce(oe,se("send-keys","-t",e,"Enter"))}ee({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 Ce,oe,yx,zt,jD,jm,Yi,FD,Fm,HD,ju,la,ua,Lm,qD,GD,Um,KD,VD,zD,ec,YD,XD,e1,t1,ze,n1,r1,$x,Wu,dt=G(()=>{$i();lu();qo();hu();Wi();Pu();yn();Ys();Bm();Ce=BD(bx);oe=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";yx=typeof process.getuid=="function"?process.getuid():0,zt=LD({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return Lu.existsSync(xx(yx))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:yx}),jD=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",jm=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",Yi="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";FD=Object.freeze(["BOSTRAT_PLANE_URL","BOSTRAT_PLANE_TOKEN"]);Fm="bostrat-usage-probe",HD=new Set([Fm]);ju="present",la="absent",ua="unknown",Lm=5e3,qD=[250,1e3,3e3],GD=e=>new Promise(t=>setTimeout(t,e));Um={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"};KD=/^[A-Za-z0-9_.-]{1,64}$/;VD=/^[A-Za-z0-9 ._↻-]+$/,zD=64;ec=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,YD=1e3,XD=/not found|Unknown command/i;e1=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,t1=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,ze=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,n1=Number(process.env.BOSTRAT_BOX_COLS)||120,r1=Number(process.env.BOSTRAT_BOX_ROWS)||40;$x=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);Wu=1600});import tc from"node:fs";import p1 from"node:fs/promises";import pa from"node:path";import f1 from"node:os";function qm(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function Gm(e){let t=pa.join(Wm,qm(e)),n;try{n=tc.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=pa.join(t,o);try{let{mtimeMs:a}=tc.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function xn(e,t){if(!t)return null;let n=pa.join(Wm,qm(e),`${t}.jsonl`);return tc.existsSync(n)?n:null}function Dx(e){if(!e)return[];let t=pa.join(Wm,qm(e)),n;try{n=tc.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=tc.statSync(pa.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function jt(e,t=131072){let n=await p1.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 h1(e){let t=e.split(`
93
- `);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 nc(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=xn(e,t),o=!0,!r)return null}else if(n){if(r=Gm(e),o=!1,!r)return null}else return null;let s;try{s=h1(await jt(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(Px,s.model),i=Px[s.model]||m1;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 Px,m1,Wm,vn=G(()=>{Px={"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},m1=2e5,Wm=process.env.BOSTRAT_CLAUDE_PROJECTS||pa.join(f1.homedir(),".claude","projects")});function w1(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===`
94
- `){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function rc(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 oc(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 Fe(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(jx(o)){t.has(o)&&r++;continue}n.push(o)}return n}function Fx(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 b1(e){let t=Fx(e),n=vt(Fe(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${Je(n)}`:`Read lines ${t.from}\u2013${t.to} of ${Je(n)}`:e.includes("-i")&&n?`Edit ${Je(n)}`:null}function Km(e){if(e.includes("--files")){let s=vt(Fe(e,Bx)[0]);return s&&s!=="."?`List files in ${fa(s)}`:"List files"}let t=Fe(e,Bx),n=t[0];if(!n)return null;let r=vt(t.slice(1).find(s=>s!==".")),o=ma(n,40);return r?`Search for \u201C${o}\u201D in ${fa(r)}`:`Search for \u201C${o}\u201D`}function Vm(e){let t=Fe(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 zm(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=Fe(e)[0];return n?`Run ${Je(n)}`:null}function k1(e){let t=Fe(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 Lx(e){return e.find(t=>/^https?:\/\//.test(t))||null}function S1(e){let t=oc(rc(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(Je(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return Jm(t[2]);let n=Je(t[0]);if(v1.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=x1[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function Jm(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
95
- `,n);i!==-1&&(t=t.slice(0,i))}let r=w1(t);for(let i=0;i<r.length-1;i++){let c=oc(rc(r[i])),l=oc(rc(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Je(c[0]))&&Je(l[0])==="sed"){let u=Fx(l),d=Fe(c)[0];if(u&&d)return ma(u.from===u.to?`Read line ${u.from} of ${Je(d)}`:`Read lines ${u.from}\u2013${u.to} of ${Je(d)}`,88)}}let o=[];for(let i of r){let c=S1(i);c&&o.push({d:c,head:Je(oc(rc(i))[0]||""),sub:Fe(oc(rc(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":ma(s?s.d:o[0].d,88)}var ma,vt,Je,fa,jx,Bx,g1,y1,x1,v1,Ux=G(()=>{ma=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,vt=e=>e&&!/[$`]/.test(e)?e:null,Je=e=>e.replace(/\/+$/,"").split("/").pop()||e,fa=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},jx=e=>e.startsWith("-"),Bx=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);g1={status:()=>"Check git status",diff:()=>"Review changes",log:()=>"Review commit history",show:()=>"Inspect a commit",add:()=>"Stage files",commit:()=>"Commit changes",push:()=>"Push to remote",pull:()=>"Pull from remote",fetch:()=>"Fetch from remote",merge:()=>"Merge branches",rebase:()=>"Rebase branch",stash:()=>"Stash changes",clone:e=>e[1]?`Clone ${Je(e[1])}`:"Clone repository",checkout:()=>"Switch branches",switch:()=>"Switch branches",restore:()=>"Restore files",reset:()=>"Reset git state",branch:(e,t)=>t.includes("--show-current")?"Check current branch":"List branches",remote:()=>"Check git remotes","rev-parse":()=>"Resolve a git ref",worktree:()=>"Manage git worktrees","merge-base":()=>"Find the merge base","ls-files":()=>"List tracked files"},y1={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"};x1={git:e=>{let t=Fe(e,new Set(["-C","-c"])),n=g1[t[0]];return n?n(t,e):null},gh:e=>{let t=Fe(e),n=y1[t[0]];return n?n(t):null},sed:b1,rg:Km,grep:Km,egrep:Km,nl:e=>{let t=vt(Fe(e)[0]);return t?`Read ${Je(t)}`:null},cat:e=>{let t=vt(Fe(e)[0]);return t?`Read ${Je(t)}`:null},head:e=>{let t=vt(Fe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${Je(t)}`:null},tail:e=>{let t=vt(Fe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${Je(t)}`:null},wc:e=>{let t=vt(Fe(e)[0]);return t?`Count lines in ${Je(t)}`:"Count input lines"},ls:e=>{let t=vt(Fe(e)[0]);return t&&t!=="."?`List files in ${fa(t)}`:"List files"},find:e=>vt(e[1])&&!jx(e[1])&&e[1]!=="."?`Find files in ${fa(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=vt(Fe(e)[0]);return t?`Create directory ${fa(t)}`:null},touch:e=>{let t=vt(Fe(e)[0]);return t?`Create ${Je(t)}`:null},rm:e=>{let t=vt(Fe(e)[0]);return t?`Delete ${fa(t)}`:null},mv:e=>{let t=vt(Fe(e)[0]);return t?`Move ${Je(t)}`:null},cp:e=>{let t=vt(Fe(e)[0]);return t?`Copy ${Je(t)}`:null},chmod:e=>{let t=vt(Fe(e)[1]);return t?`Change permissions on ${Je(t)}`:null},diff:e=>{let t=Fe(e);return t.length>=2?`Compare ${Je(t[0])} and ${Je(t[1])}`:null},curl:e=>{let t=Lx(e);return t?`Fetch ${ma(t,56)}`:"Fetch a URL"},wget:e=>{let t=Lx(e);return t?`Fetch ${ma(t,56)}`:"Fetch a URL"},npm:Vm,pnpm:Vm,yarn:Vm,npx:e=>{let t=Fe(e)[0];return t?`Run ${t}`:null},node:e=>zm(e,"Node"),python:e=>zm(e,"Python"),python3:e=>zm(e,"Python"),make:e=>{let t=Fe(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:k1,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=Fe(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=Fe(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=Fe(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},v1=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function ha(e){let t=e.split(`
96
- `).map(n=>n.trim()).find(Boolean)||e;return t.length>88?`${t.slice(0,88).trimEnd()}\u2026`:t}function Qr(e,t=""){let n=t.trim();return n||Jm(e)||ha(e)}function Ym(e,t){if(e){if(Array.isArray(e)){for(let n of e)Ym(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&Xm.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))Ym(n,t)}}}async function Hx(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await jt(e,t)}catch{return[]}let o=[];for(let s of r.split(`
97
- `)){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(Ym(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:Qr(d.command,d.description),ts:u})}return o.slice(-n)}function Wx(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(...A1(i,r.get(a)||[]));return s.sort((a,i)=>(a.ts||0)-(i.ts||0))}function A1(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 Xm,wa=G(()=>{vn();Ux();Xm=new Set(["Bash"])});import qx from"node:fs";import Qm from"node:fs/promises";import Zm from"node:path";import T1 from"node:os";async function Gx(e){try{return await Qm.realpath(e)}catch{return e}}function _1(e=E1){let t=[],n=r=>{let o;try{o=qx.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=Zm.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:qx.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function I1(e,t=1048576){let n;try{n=await Qm.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(`
92
+ `).filter(Boolean).length}catch{return 0}}async function Xo(e,{cols:t=n1,rows:n=r1}={}){if(!je(e))return!0;if(await _x(e))return!1;try{let r=await Ix(e);if(r.cols===t&&r.rows===n)return!0;await Ce(oe,se("resize-window","-t",e,"-x",String(t),"-y",String(n))),await Ce(oe,se("set-window-option","-t",e,"window-size","latest")),await Jo(80)}catch{}return!0}async function o1(e){if(!je(e))return 0;try{let{stdout:t}=await Ce(oe,se("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function Fn(e){let t=await o1(e);if(!t)return!1;try{return await Ce("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function Ix(e){if(!je(e))return{cols:0,rows:0};try{let{stdout:t}=await Ce(oe,se("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 Hu(e,{cols:t=e1,rows:n=t1}={}){if(je(e)&&!await _x(e))try{let r=await Ix(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await Ce(oe,se("resize-window","-t",e,"-x",String(o),"-y",String(s))),await Ce(oe,se("set-window-option","-t",e,"window-size","latest")),await Jo(80))}catch{}}async function Jt(e){return await Hu(e),Ne(e,{lines:ze})}async function Ke(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=>$x.has(s));for(let s=0;s<o.length;s++)await Ce(oe,se("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await Jo(n);return ee({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function Wm(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"&&$x.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 Ce(oe,se("send-keys","-t",e,"-l",a.text)):await Ce(oe,se("send-keys","-t",e,a.key)),n>0&&s<o.length-1&&await Jo(n)}return ee({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 da(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 Ce(oe,se("send-keys","-t",e,"-N",String(r),"BSpace")),ee({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function qu(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 Ce(oe,se("send-keys","-t",e,"-l",s)),n>0&&await Jo(n);ee({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function s1(e,t){return new Promise((n,r)=>{let o=bx(oe,se(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function a1(e,t){let n=`bostrat-${kx().slice(0,8)}`;await s1(["load-buffer","-b",n,"-"],t),await Ce(oe,se("paste-buffer","-p","-d","-b",n,"-t",e))}async function Qe(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!je(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await a1(e,t):await Ce(oe,se("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await Jo(a),await Ce(oe,se("send-keys","-t",e,"Enter"))}ee({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 Ce,oe,yx,zt,jD,Fm,Yi,FD,Um,HD,ju,la,ua,jm,qD,GD,Hm,KD,VD,zD,ec,YD,XD,e1,t1,ze,n1,r1,$x,Wu,dt=G(()=>{$i();lu();qo();hu();Wi();Pu();yn();Ys();Lm();Ce=BD(bx);oe=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";yx=typeof process.getuid=="function"?process.getuid():0,zt=LD({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return Lu.existsSync(xx(yx))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:yx}),jD=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",Fm=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",Yi="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";FD=Object.freeze(["BOSTRAT_PLANE_URL","BOSTRAT_PLANE_TOKEN"]);Um="bostrat-usage-probe",HD=new Set([Um]);ju="present",la="absent",ua="unknown",jm=5e3,qD=[250,1e3,3e3],GD=e=>new Promise(t=>setTimeout(t,e));Hm={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"};KD=/^[A-Za-z0-9_.-]{1,64}$/;VD=/^[A-Za-z0-9 ._↻-]+$/,zD=64;ec=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,YD=1e3,XD=/not found|Unknown command/i;e1=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,t1=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,ze=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,n1=Number(process.env.BOSTRAT_BOX_COLS)||120,r1=Number(process.env.BOSTRAT_BOX_ROWS)||40;$x=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace"]);Wu=1600});import tc from"node:fs";import p1 from"node:fs/promises";import pa from"node:path";import f1 from"node:os";function Gm(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function Km(e){let t=pa.join(qm,Gm(e)),n;try{n=tc.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=pa.join(t,o);try{let{mtimeMs:a}=tc.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function xn(e,t){if(!t)return null;let n=pa.join(qm,Gm(e),`${t}.jsonl`);return tc.existsSync(n)?n:null}function Dx(e){if(!e)return[];let t=pa.join(qm,Gm(e)),n;try{n=tc.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=tc.statSync(pa.join(t,o));r.push({id:o.slice(0,-6),birthMs:s.birthtimeMs||s.ctimeMs||s.mtimeMs})}catch{}return r}async function jt(e,t=131072){let n=await p1.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 h1(e){let t=e.split(`
93
+ `);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 nc(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=xn(e,t),o=!0,!r)return null}else if(n){if(r=Km(e),o=!1,!r)return null}else return null;let s;try{s=h1(await jt(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(Px,s.model),i=Px[s.model]||m1;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 Px,m1,qm,vn=G(()=>{Px={"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},m1=2e5,qm=process.env.BOSTRAT_CLAUDE_PROJECTS||pa.join(f1.homedir(),".claude","projects")});function w1(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===`
94
+ `){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function rc(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 oc(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 Fe(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(jx(o)){t.has(o)&&r++;continue}n.push(o)}return n}function Fx(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 b1(e){let t=Fx(e),n=vt(Fe(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${Je(n)}`:`Read lines ${t.from}\u2013${t.to} of ${Je(n)}`:e.includes("-i")&&n?`Edit ${Je(n)}`:null}function Vm(e){if(e.includes("--files")){let s=vt(Fe(e,Bx)[0]);return s&&s!=="."?`List files in ${fa(s)}`:"List files"}let t=Fe(e,Bx),n=t[0];if(!n)return null;let r=vt(t.slice(1).find(s=>s!==".")),o=ma(n,40);return r?`Search for \u201C${o}\u201D in ${fa(r)}`:`Search for \u201C${o}\u201D`}function zm(e){let t=Fe(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 Jm(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=Fe(e)[0];return n?`Run ${Je(n)}`:null}function k1(e){let t=Fe(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 Lx(e){return e.find(t=>/^https?:\/\//.test(t))||null}function S1(e){let t=oc(rc(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(Je(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return Ym(t[2]);let n=Je(t[0]);if(v1.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=x1[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function Ym(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
95
+ `,n);i!==-1&&(t=t.slice(0,i))}let r=w1(t);for(let i=0;i<r.length-1;i++){let c=oc(rc(r[i])),l=oc(rc(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(Je(c[0]))&&Je(l[0])==="sed"){let u=Fx(l),d=Fe(c)[0];if(u&&d)return ma(u.from===u.to?`Read line ${u.from} of ${Je(d)}`:`Read lines ${u.from}\u2013${u.to} of ${Je(d)}`,88)}}let o=[];for(let i of r){let c=S1(i);c&&o.push({d:c,head:Je(oc(rc(i))[0]||""),sub:Fe(oc(rc(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":ma(s?s.d:o[0].d,88)}var ma,vt,Je,fa,jx,Bx,g1,y1,x1,v1,Ux=G(()=>{ma=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,vt=e=>e&&!/[$`]/.test(e)?e:null,Je=e=>e.replace(/\/+$/,"").split("/").pop()||e,fa=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},jx=e=>e.startsWith("-"),Bx=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);g1={status:()=>"Check git status",diff:()=>"Review changes",log:()=>"Review commit history",show:()=>"Inspect a commit",add:()=>"Stage files",commit:()=>"Commit changes",push:()=>"Push to remote",pull:()=>"Pull from remote",fetch:()=>"Fetch from remote",merge:()=>"Merge branches",rebase:()=>"Rebase branch",stash:()=>"Stash changes",clone:e=>e[1]?`Clone ${Je(e[1])}`:"Clone repository",checkout:()=>"Switch branches",switch:()=>"Switch branches",restore:()=>"Restore files",reset:()=>"Reset git state",branch:(e,t)=>t.includes("--show-current")?"Check current branch":"List branches",remote:()=>"Check git remotes","rev-parse":()=>"Resolve a git ref",worktree:()=>"Manage git worktrees","merge-base":()=>"Find the merge base","ls-files":()=>"List tracked files"},y1={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"};x1={git:e=>{let t=Fe(e,new Set(["-C","-c"])),n=g1[t[0]];return n?n(t,e):null},gh:e=>{let t=Fe(e),n=y1[t[0]];return n?n(t):null},sed:b1,rg:Vm,grep:Vm,egrep:Vm,nl:e=>{let t=vt(Fe(e)[0]);return t?`Read ${Je(t)}`:null},cat:e=>{let t=vt(Fe(e)[0]);return t?`Read ${Je(t)}`:null},head:e=>{let t=vt(Fe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${Je(t)}`:null},tail:e=>{let t=vt(Fe(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${Je(t)}`:null},wc:e=>{let t=vt(Fe(e)[0]);return t?`Count lines in ${Je(t)}`:"Count input lines"},ls:e=>{let t=vt(Fe(e)[0]);return t&&t!=="."?`List files in ${fa(t)}`:"List files"},find:e=>vt(e[1])&&!jx(e[1])&&e[1]!=="."?`Find files in ${fa(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=vt(Fe(e)[0]);return t?`Create directory ${fa(t)}`:null},touch:e=>{let t=vt(Fe(e)[0]);return t?`Create ${Je(t)}`:null},rm:e=>{let t=vt(Fe(e)[0]);return t?`Delete ${fa(t)}`:null},mv:e=>{let t=vt(Fe(e)[0]);return t?`Move ${Je(t)}`:null},cp:e=>{let t=vt(Fe(e)[0]);return t?`Copy ${Je(t)}`:null},chmod:e=>{let t=vt(Fe(e)[1]);return t?`Change permissions on ${Je(t)}`:null},diff:e=>{let t=Fe(e);return t.length>=2?`Compare ${Je(t[0])} and ${Je(t[1])}`:null},curl:e=>{let t=Lx(e);return t?`Fetch ${ma(t,56)}`:"Fetch a URL"},wget:e=>{let t=Lx(e);return t?`Fetch ${ma(t,56)}`:"Fetch a URL"},npm:zm,pnpm:zm,yarn:zm,npx:e=>{let t=Fe(e)[0];return t?`Run ${t}`:null},node:e=>Jm(e,"Node"),python:e=>Jm(e,"Python"),python3:e=>Jm(e,"Python"),make:e=>{let t=Fe(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:k1,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=Fe(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=Fe(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=Fe(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},v1=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function ha(e){let t=e.split(`
96
+ `).map(n=>n.trim()).find(Boolean)||e;return t.length>88?`${t.slice(0,88).trimEnd()}\u2026`:t}function Qr(e,t=""){let n=t.trim();return n||Ym(e)||ha(e)}function Xm(e,t){if(e){if(Array.isArray(e)){for(let n of e)Xm(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&Zm.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))Xm(n,t)}}}async function Hx(e,{maxBytes:t=1048576,limit:n=400}={}){let r;try{r=await jt(e,t)}catch{return[]}let o=[];for(let s of r.split(`
97
+ `)){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(Xm(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:Qr(d.command,d.description),ts:u})}return o.slice(-n)}function Wx(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(...T1(i,r.get(a)||[]));return s.sort((a,i)=>(a.ts||0)-(i.ts||0))}function T1(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 Zm,wa=G(()=>{vn();Ux();Zm=new Set(["Bash"])});import qx from"node:fs";import eh from"node:fs/promises";import Qm from"node:path";import A1 from"node:os";async function Gx(e){try{return await eh.realpath(e)}catch{return e}}function _1(e=E1){let t=[],n=r=>{let o;try{o=qx.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=Qm.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:qx.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function I1(e,t=1048576){let n;try{n=await eh.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(`
98
98
  `);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=t)break}return o}finally{await n.close()}}async function $1(e){let t=await I1(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 Zo(e,t){if(!e&&!t)return null;let n=_1();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await Gx(e);for(let o of n){let s=await $1(o.file);if(s&&(s===e||await Gx(s)===r))return o}return null}async function Kx(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await Zo(e,t);if(!o)return[];let s;try{s=await jt(o.file,r)}catch{return[]}let a=[],i=null,c=[],l=!1,u=!1,d=null;for(let p of s.split(`
99
- `)){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 g=w.payload?.type;g==="task_started"?(l=!0,u=!1,d=w.payload?.turn_id||null):g==="task_complete"&&l&&(l=!1,!u&&w.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:Qo,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,eh.has(h.name)||c.push(h.name);continue}if(h.type!=="message"||h.role!=="assistant")continue;u=!0;let y=O1(h.content),k=c.length?c.slice():null;c=[],!(!y&&!k)&&a.push({role:"assistant",text:y,tools:k||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 M1(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 C1(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+=`
99
+ `)){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 g=w.payload?.type;g==="task_started"?(l=!0,u=!1,d=w.payload?.turn_id||null):g==="task_complete"&&l&&(l=!1,!u&&w.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:Qo,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,th.has(h.name)||c.push(h.name);continue}if(h.type!=="message"||h.role!=="assistant")continue;u=!0;let y=O1(h.content),k=c.length?c.slice():null;c=[],!(!y&&!k)&&a.push({role:"assistant",text:y,tools:k||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 M1(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 C1(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+=`
100
100
  `;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 N1(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=C1(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function Vx(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await Zo(e,t);if(!o)return[];let s;try{s=await jt(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
101
- `)){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"&&sc.has(u.name)){let f;try{f=JSON.parse(u.arguments||"{}")}catch{continue}let w=M1(f);w&&(d=[w])}else u.type==="custom_tool_call"&&u.name==="exec"&&(d=N1(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:Qr(f),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function zx(e,t){let n=await Zo(e,t);if(!n)return null;try{return Math.round((await Qm.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var E1,R1,O1,sc,eh,Qo,es=G(()=>{vn();wa();E1=process.env.BOSTRAT_CODEX_SESSIONS||Zm.join(process.env.CODEX_HOME||Zm.join(T1.homedir(),".codex"),"sessions");R1=new Set(["output_text","text"]),O1=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&R1.has(t.type)).map(t=>t.text).join(`
102
- `).trim():"";sc=new Set(["exec_command","shell","exec"]),eh=new Set(["wait","write_stdin"]),Qo="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 ac({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&Jx.has(r))return Jx.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 Yx(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||ac({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===Qo?"other":ac({text:t}),code:null,status:null,requestId:null}}return null}function Xx(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:ac({text:n}),code:null,status:P1(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function P1(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var nY,Jx,Vu=G(()=>{es();nY=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),Jx=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 D1(e,t){return!e||!t?null:xn(e,t)}function B1(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(`
103
- `).trim():""}function L1(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 j1(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function th(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 Zx(e,t){if(!e.uuid)return null;let n=th(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 nh(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await jt(e,t)}catch{return[]}let o=[],s=new Map,a=new Map;for(let i of r.split(`
104
- `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type==="attachment"){let k=l.attachment;k?.type==="queued_command"&&k.commandMode==="task-notification"&&typeof k.prompt=="string"&&k.prompt.trim()&&o.push({role:"user",text:k.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 k of u.content){let g=k?.type==="tool_use"?k.input?.file_path||k.input?.path:null;typeof g=="string"&&F1.test(g)&&s.set(k.id,g.split("/").pop()),k?.type==="tool_use"&&k.name==="Skill"&&k.id&&a.set(k.id,String(k.input?.skill||"").trim().replace(/^\//,"")||null)}if(j1(u.content)){let k=Zx(l,s);k&&o.push({role:"assistant",text:"",images:k,ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let p=B1(u.content),f=d==="assistant"?L1(u.content):null,w=d==="user"?Zx(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,y=d==="assistant"&&l.isApiErrorMessage?{code:typeof l.error=="string"?l.error:null,status:Number(l.apiErrorStatus)||null,requestId:l.requestId||null,cls:ac({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:y||void 0})}return o.slice(-n)}async function Qx(e,t,{turns:n=16}={}){let r=D1(e,t);if(!r)return"";let o=await nh(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}:** ${U1(s.text||c,700)} ${i}`.trim()}).join(`
101
+ `)){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"&&sc.has(u.name)){let f;try{f=JSON.parse(u.arguments||"{}")}catch{continue}let w=M1(f);w&&(d=[w])}else u.type==="custom_tool_call"&&u.name==="exec"&&(d=N1(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:Qr(f),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function zx(e,t){let n=await Zo(e,t);if(!n)return null;try{return Math.round((await eh.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var E1,R1,O1,sc,th,Qo,es=G(()=>{vn();wa();E1=process.env.BOSTRAT_CODEX_SESSIONS||Qm.join(process.env.CODEX_HOME||Qm.join(A1.homedir(),".codex"),"sessions");R1=new Set(["output_text","text"]),O1=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&R1.has(t.type)).map(t=>t.text).join(`
102
+ `).trim():"";sc=new Set(["exec_command","shell","exec"]),th=new Set(["wait","write_stdin"]),Qo="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 ac({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&Jx.has(r))return Jx.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 Yx(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||ac({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===Qo?"other":ac({text:t}),code:null,status:null,requestId:null}}return null}function Xx(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:ac({text:n}),code:null,status:P1(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function P1(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var rY,Jx,Vu=G(()=>{es();rY=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),Jx=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 D1(e,t){return!e||!t?null:xn(e,t)}function B1(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(`
103
+ `).trim():""}function L1(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 j1(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function nh(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 Zx(e,t){if(!e.uuid)return null;let n=nh(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 rh(e,{maxBytes:t=524288,limit:n=80}={}){let r;try{r=await jt(e,t)}catch{return[]}let o=[],s=new Map,a=new Map;for(let i of r.split(`
104
+ `)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type==="attachment"){let k=l.attachment;k?.type==="queued_command"&&k.commandMode==="task-notification"&&typeof k.prompt=="string"&&k.prompt.trim()&&o.push({role:"user",text:k.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 k of u.content){let g=k?.type==="tool_use"?k.input?.file_path||k.input?.path:null;typeof g=="string"&&F1.test(g)&&s.set(k.id,g.split("/").pop()),k?.type==="tool_use"&&k.name==="Skill"&&k.id&&a.set(k.id,String(k.input?.skill||"").trim().replace(/^\//,"")||null)}if(j1(u.content)){let k=Zx(l,s);k&&o.push({role:"assistant",text:"",images:k,ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let p=B1(u.content),f=d==="assistant"?L1(u.content):null,w=d==="user"?Zx(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,y=d==="assistant"&&l.isApiErrorMessage?{code:typeof l.error=="string"?l.error:null,status:Number(l.apiErrorStatus)||null,requestId:l.requestId||null,cls:ac({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:y||void 0})}return o.slice(-n)}async function Qx(e,t,{turns:n=16}={}){let r=D1(e,t);if(!r)return"";let o=await rh(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}:** ${U1(s.text||c,700)} ${i}`.trim()}).join(`
105
105
 
106
106
  `):""}var F1,U1,zu=G(()=>{Vu();vn();F1=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;U1=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});function W1(e,{provider:t,box:n}){let r=String(e).replace(/\r/g,"").split(`
107
107
  `);if(!ev.test(e))return null;let o=[],s=!1;for(let l=r.length-1;l>=0;l--){let u=r[l].match(H1);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"&&ev.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 hr(e){let t=String(e??"").replace(/\r/g,""),n=t.split(`
@@ -109,33 +109,33 @@ exit 0
109
109
  `);return t}function q1(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 G1(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 K1(e,t=""){let n=hr(e);if(ic.test(n)||!/Sign in with ChatGPT/.test(n)||!/Press enter to continue/.test(n))return null;let r=n.split(`
110
110
  `),o=[],s=-1;for(let l=0;l<r.length;l++){let u=r[l].match(tv);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(tv.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&&!rv.test(r[l])&&q1(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",setup:"login-method",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=G1(l.label);return{label:l.label,description:[l.desc,u].filter(Boolean).join(" \xB7 ")}})}]}}function J1(e,t=""){let n=hr(e);if(ic.test(n)||!V1.test(n))return null;let r=n.trimEnd().split(`
111
111
  `).pop()||"";return z1.test(r)?{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"keys",setup:"continue",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 X1(e,t=""){let n=hr(e);if(ic.test(n)||!nv.test(n))return null;let r=n.split(`
112
- `),o=r.findIndex(i=>nv.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(Y1);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",setup:"device-code",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 Z1(e,t=""){let n=hr(e);return ic.test(n)||!/open the following link to authenticate/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",setup:"browser",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 Q1(e,t=""){let n=hr(e);return ic.test(n)||!/Paste or type your API key/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",setup:"apikey",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 eB(e,t=""){let n=String(e);if(!/Press any key to log in/.test(n)||rh.test(n))return null;let r=n.replace(/\r/g,"").split(`
113
- `).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",setup:"login-start",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 nB(e,t=""){let n=String(e);if(!tB.test(n)||rh.test(n))return null;let r=n.replace(/\r/g,"").split(`
114
- `),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,setup:"link",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 rB(e,t=""){let n=String(e);return!/Scan this QR code to log in/.test(n)||rh.test(n)?null:{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,setup:"qr",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 ov(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=J1(t,n)||X1(t,n)||Z1(t,n)||Q1(t,n)||K1(t,n);if(r)return r}if(e==="cursor"){let r=nB(t,n)||rB(t,n)||eB(t,n);if(r)return r}return W1(t,{provider:e,box:n})}function sv(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 H1,ev,ic,rv,tv,V1,z1,nv,Y1,rh,tB,Ju=G(()=>{H1=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,ev=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;ic=/(^|\n)\s*›/,rv=/^\s*Welcome to Codex\b|^\s*(?:│\s*)?>_ OpenAI Codex\b/;tv=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;V1=/Successfully logged in\./,z1=/^\s*Press Enter to continue\.\s*$/;nv=/Enter this one-time code/,Y1=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;rh=/Run Everything|Add a follow-up|Plan, search, build anything/;tB=/click this link to log in|Signing in with the browser/});function cc(e,t){if(e!=="claude")return!1;let n=String(t||"");if(!iv.test(n))return!1;let r=n.replace(/\r/g,"").split(`
115
- `).filter(o=>o.trim());return oB.test(r.slice(-6).join(`
112
+ `),o=r.findIndex(i=>nv.test(i)),s="";for(let i=o+1;i<r.length;i++){let c=r[i].match(Y1);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",setup:"device-code",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 Z1(e,t=""){let n=hr(e);return ic.test(n)||!/open the following link to authenticate/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",setup:"browser",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 Q1(e,t=""){let n=hr(e);return ic.test(n)||!/Paste or type your API key/.test(n)?null:{provider:"codex",box:t,multiSelect:!1,cursorIndex:0,answerMode:"esc",setup:"apikey",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 eB(e,t=""){let n=String(e);if(!/Press any key to log in/.test(n)||Ju.test(n))return null;let r=n.replace(/\r/g,"").split(`
113
+ `).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",setup:"login-start",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 nB(e,t=""){let n=String(e);if(!tB.test(n)||Ju.test(n))return null;let r=n.replace(/\r/g,"").split(`
114
+ `),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,setup:"link",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 rB(e,t=""){let n=String(e);return!/Scan this QR code to log in/.test(n)||Ju.test(n)?null:{provider:"cursor",box:t,multiSelect:!1,cursorIndex:0,setup:"qr",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 oB(e,t=""){let n=String(e);return Ju.test(n)||!/Trust this workspace/.test(n)||!/\[a\]\s*Trust/i.test(n)?null:{provider:"cursor",box:t,setup:"trust",answerMode:"keys",cursorIndex:0,promptId:"cursor:setup:trust",multiSelect:!1,questions:[{header:"Workspace trust",question:"Trust this workspace?",multiSelect:!1,options:[{label:"Trust this workspace",description:"Allow Cursor to work in this node's workspace"}]}]}}function ov(e,t,n=""){if(e!=="cursor"&&e!=="codex")return null;if(e==="codex"){let r=J1(t,n)||X1(t,n)||Z1(t,n)||Q1(t,n)||K1(t,n);if(r)return r}if(e==="cursor"){let r=oB(t,n)||nB(t,n)||rB(t,n)||eB(t,n);if(r)return r}return W1(t,{provider:e,box:n})}function sv(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 H1,ev,ic,rv,tv,V1,z1,nv,Y1,Ju,tB,Yu=G(()=>{H1=/^\s*[›>*\-❯]?\s*(\d+)[.)]\s+(.+?)\s*$/,ev=/\b(allow|approve|apply (this )?patch|run (this )?command|do you want to run|grant)\b/i;ic=/(^|\n)\s*›/,rv=/^\s*Welcome to Codex\b|^\s*(?:│\s*)?>_ OpenAI Codex\b/;tv=/^\s*(>)?\s*(\d+)\.\s+(.+?)\s*$/;V1=/Successfully logged in\./,z1=/^\s*Press Enter to continue\.\s*$/;nv=/Enter this one-time code/,Y1=/^\s*([A-Z0-9]{2,10}-[A-Z0-9]{2,10})\s*$/;Ju=/Run Everything|Add a follow-up|Plan, search, build anything/;tB=/click this link to log in|Signing in with the browser/});function cc(e,t){if(e!=="claude")return!1;let n=String(t||"");if(!iv.test(n))return!1;let r=n.replace(/\r/g,"").split(`
115
+ `).filter(o=>o.trim());return sB.test(r.slice(-6).join(`
116
116
  `))}function av(e){let t=String(e||"").replace(/\r/g,"").split(`
117
- `);for(let n=t.length-1;n>=0;n--)if(t[n].trim())return t[n];return""}function cv(e,t){let n=String(t||"");return e==="claude"?iv.test(n)?!1:sB.test(av(n)):e==="codex"?cB.test(n)||!aB.test(n)?!1:iB.test(av(n)):!1}function lv(e){let t=String(e||"").match(lB);if(!t)return null;let n=t[1].replace(/[.,;:]+$/,"");return n.length>1&&n.length<=120?n:null}function uv(e){return ga.get(e)||null}function Yu(e){let t=ga.get(e);return t||(t={issuedAt:0,issueCount:0,startedReason:null,enterClearedAt:0,account:null,connectedAt:0,reported:{started:!1,connected:!1}},ga.set(e,t)),t}function dv(e){let t=ga.get(e);return!!t&&!!t.startedReason&&!t.connectedAt}function Xu(e,{onDrive:t=!1,now:n=Date.now()}={}){let r=ga.get(e);return!r||!r.issuedAt?!0:t?n-r.issuedAt>=uB:!1}function Zu(e,t=Date.now()){let n=Yu(e);return n.issuedAt=t,n.issueCount+=1,n.connectedAt&&(n.connectedAt=0,n.reported={started:!1,connected:!1},n.startedReason=null),n.startedReason||(n.startedReason="not-logged-in"),n}function pv(e,t=""){let n=Yu(e);n.startedReason||(n.startedReason="auth-screen"),n.connectedAt&&(n.connectedAt=0,n.reported={started:!1,connected:!1});let r=lv(t);return r&&(n.account=r),n}function Qu(e,t="",n=Date.now()){let r=Yu(e);r.startedReason||(r.startedReason="auth-screen"),r.enterClearedAt=n;let o=lv(t);return o&&(r.account=o),r}function fv(e,t=Date.now()){let n=Yu(e);return n.connectedAt=t,n}function mv(e){let t=ga.get(e);if(!t)return{started:!1,connected:!1};let n={started:!1,connected:!1};return t.startedReason&&!t.reported.started&&(t.reported.started=!0,n.started=!0),t.connectedAt&&!t.reported.connected&&(t.reported.connected=!0,n.connected=!0),n}var oB,iv,sB,aB,iB,cB,lB,ga,uB,oh=G(()=>{oB=/Not logged in · (?:Run|Please run) \/login/,iv=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;sB=/Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/,aB=/Successfully logged in\./,iB=/^\s*Press Enter to continue\.\s*$/,cB=/^\s*›/m;lB=/Logged in as\s+(\S+@\S+|\S+)/;ga=new Map;uB=3e4});function mB(e){let t=String(e||"").replace(/\r/g,"").split(`
118
- `),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(pB.test(r)||fB.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(`
119
- `).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 bB(e){let t=String(e||"");if(!rt.codex.block.test(t))return null;let n=hr(t);if(!rt.codex.block.test(n))return null;let r=n.match(yB);return{from:r?.[1]||null,to:r?.[2]||null}}function Ft(e){return new Promise(t=>setTimeout(t,e))}function eo(e,t){let n=Date.now(),r=kB();for(let[s,a]of ed)n-a>=r&&ed.delete(s);let o=`${e}::${t}`;return ed.has(o)?!1:(ed.set(o,n),!0)}function yv(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
117
+ `);for(let n=t.length-1;n>=0;n--)if(t[n].trim())return t[n];return""}function cv(e,t){let n=String(t||"");return e==="claude"?iv.test(n)?!1:aB.test(av(n)):e==="codex"?lB.test(n)||!iB.test(n)?!1:cB.test(av(n)):!1}function lv(e){let t=String(e||"").match(uB);if(!t)return null;let n=t[1].replace(/[.,;:]+$/,"");return n.length>1&&n.length<=120?n:null}function uv(e){return ga.get(e)||null}function Xu(e){let t=ga.get(e);return t||(t={issuedAt:0,issueCount:0,startedReason:null,enterClearedAt:0,account:null,connectedAt:0,reported:{started:!1,connected:!1}},ga.set(e,t)),t}function dv(e){let t=ga.get(e);return!!t&&!!t.startedReason&&!t.connectedAt}function Zu(e,{onDrive:t=!1,now:n=Date.now()}={}){let r=ga.get(e);return!r||!r.issuedAt?!0:t?n-r.issuedAt>=dB:!1}function Qu(e,t=Date.now()){let n=Xu(e);return n.issuedAt=t,n.issueCount+=1,n.connectedAt&&(n.connectedAt=0,n.reported={started:!1,connected:!1},n.startedReason=null),n.startedReason||(n.startedReason="not-logged-in"),n}function pv(e,t=""){let n=Xu(e);n.startedReason||(n.startedReason="auth-screen"),n.connectedAt&&(n.connectedAt=0,n.reported={started:!1,connected:!1});let r=lv(t);return r&&(n.account=r),n}function ed(e,t="",n=Date.now()){let r=Xu(e);r.startedReason||(r.startedReason="auth-screen"),r.enterClearedAt=n;let o=lv(t);return o&&(r.account=o),r}function fv(e,t=Date.now()){let n=Xu(e);return n.connectedAt=t,n}function mv(e){let t=ga.get(e);if(!t)return{started:!1,connected:!1};let n={started:!1,connected:!1};return t.startedReason&&!t.reported.started&&(t.reported.started=!0,n.started=!0),t.connectedAt&&!t.reported.connected&&(t.reported.connected=!0,n.connected=!0),n}var sB,iv,aB,iB,cB,lB,uB,ga,dB,oh=G(()=>{sB=/Not logged in · (?:Run|Please run) \/login/,iv=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;aB=/Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/,iB=/Successfully logged in\./,cB=/^\s*Press Enter to continue\.\s*$/,lB=/^\s*›/m;uB=/Logged in as\s+(\S+@\S+|\S+)/;ga=new Map;dB=3e4});function hB(e){let t=String(e||"").replace(/\r/g,"").split(`
118
+ `),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(fB.test(r)||mB.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(`
119
+ `).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 kB(e){let t=String(e||"");if(!rt.codex.block.test(t))return null;let n=hr(t);if(!rt.codex.block.test(n))return null;let r=n.match(bB);return{from:r?.[1]||null,to:r?.[2]||null}}function Ft(e){return new Promise(t=>setTimeout(t,e))}function eo(e,t){let n=Date.now(),r=xB();for(let[s,a]of td)n-a>=r&&td.delete(s);let o=`${e}::${t}`;return td.has(o)?!1:(td.set(o,n),!0)}function yv(e,t){if(e?.busyScope!=="footer")return t;let n=String(t||"").split(`
120
120
  `),r=-1;for(let o=n.length-1;o>=0;o--)if(gv.test(n[o])){r=o;break}return r<0?t:n.slice(r+1).join(`
121
- `)}function vB(e){let t=0;for(let n of String(e).split(`
122
- `))gv.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function lc(e,t){let n=rt[e];if(!n?.busy)return{state:"idle",reason:null};if(ya(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(yv(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=vB(t);return e==="claude"&&r>0&&r<xB?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function sh(e,t){return lc(e,t).state}function nd(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
121
+ `)}function SB(e){let t=0;for(let n of String(e).split(`
122
+ `))gv.test(n)&&(t=Math.max(t,n.trimEnd().length));return t}function lc(e,t){let n=rt[e];if(!n?.busy)return{state:"idle",reason:null};if(ya(e,t))return{state:"unknown",reason:"blocked"};if(n.up&&!n.up.test(t))return{state:"idle",reason:null};if(n.busy.test(yv(n,t)))return{state:"busy",reason:null};if(n.busyAlt&&n.busyAlt.test(t))return{state:"busy",reason:null};let r=SB(t);return e==="claude"&&r>0&&r<vB?{state:"unknown",reason:"narrow"}:{state:"idle",reason:null}}function sh(e,t){return lc(e,t).state}function rd(e,t){if(e!=="claude")return!1;let n=String(t||"").split(`
123
123
  `).slice(-AB).join(`
124
- `);return SB.test(n)}function ba(e,t){return sh(e,t)==="busy"}function uc(e,t){return sh(e,t)!=="idle"}function to(e,t){let n=rt[e];return n?.up?n.up.test(t):!0}function TB(e,t){let n=rt[e];return n?ya(e,t)?!1:n.up.test(t)&&sh(e,t)==="idle":!0}function ya(e,t){let n=rt[e];if(!n)return!1;let r=e==="codex"?hr(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 td(e,t){let n=String(t||"").trim();if(!n)return e;let r=String(e||"").split(`
124
+ `);return TB.test(n)}function ba(e,t){return sh(e,t)==="busy"}function uc(e,t){return sh(e,t)!=="idle"}function to(e,t){let n=rt[e];return n?.up?n.up.test(t):!0}function EB(e,t){let n=rt[e];return n?ya(e,t)?!1:n.up.test(t)&&sh(e,t)==="idle":!0}function ya(e,t){let n=rt[e];if(!n)return!1;let r=e==="codex"?hr(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 nd(e,t){let n=String(t||"").trim();if(!n)return e;let r=String(e||"").split(`
125
125
  `);for(let o=r.length-1;o>=0;o--)if(r[o].includes(n))return r.slice(o+1).join(`
126
- `);return e}function bv(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function hv(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 wv(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null,onReady:s}={}){let a=Date.now()+n,i=0,c=null;await Xo(e).catch(()=>{});let l=0;for(;;){let u=td(await Ne(e),o);if(cc(t,u)){if(l<2&&Xu(e,{onDrive:!0})&&eo(e,"login-issue")){l+=1,Zu(e),await ee({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"login-issue",attempt:l}).catch(()=>{}),await Qe(e,"/login",{enter:!0,submitDelayMs:600,kind:"login-issue"});let d=Date.now()+8e3,p=!1;for(;Date.now()<d;)if(await Ft(ts),ya(t,td(await Ne(e),o))){p=!0;break}if(p&&r)return ee({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"login-issued"}).catch(()=>{}),"login-issued";continue}if(Date.now()>a){let d=`${t} isn't signed in on this box \u2014 answer the Sign-in card in chat (or run /login from the Terminal tab), then send again`;throw ee({flow:"agent-ready",phase:"blocked",reason:"not-logged-in",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:d}).catch(()=>{}),new Error(d)}await Ft(ts);continue}if((t==="claude"||t==="codex")&&i<3){let d=t==="codex"?hr(u):u;if(cv(t,d)){if(!eo(e,"login-enter")){await Ft(ts);continue}i+=1,Qu(e,d),await ee({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"login-enter",attempt:i}).catch(()=>{}),await Qe(e,"",{enter:!0,kind:"login-enter"}),await Ft(ns);continue}}if(TB(t,u))return await s?.(),await Ft(ns),"up";if(rt[t]?.up&&!rt[t].up.test(u))if(await Fn(e)){if(c??=Date.now(),Date.now()-c>=ec()){let d=hv(t);throw ee({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,idleMs:Date.now()-c,error:d.message}).catch(()=>{}),d}}else c=null;else c=null;if(r&&t==="claude"&&gB.test(u)&&!rt.claude.up.test(u))return ee({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{}),"dialog-bail";if(t==="codex"&&wB.test(u)&&!rt.codex.up.test(u)&&i<3){if(!eo(e,"codex-trust")){await Ft(ts);continue}i+=1,await ee({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await Qe(e,"",{enter:!0,kind:"codex-trust-accept"}),await Ft(ns);continue}if(t==="cursor"&&hB.test(u)&&!rt.cursor.up.test(u)&&i<3){if(!eo(e,"cursor-trust")){await Ft(ts);continue}i+=1,await ee({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await Qe(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await Ft(ns);continue}if(t==="codex"&&i<3){let d=bB(u);if(d){if(!eo(e,`codex-update:${d.from}->${d.to}`)){await Ft(ts);continue}i+=1,await ee({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${d.from} -> ${d.to}`}).catch(()=>{}),await Qe(e,"3",{enter:!1,kind:"codex-update-skip"}),hm({sessionName:e,from:d.from,to:d.to}),await Ft(ns);continue}}if(Date.now()>a){if(ya(t,u)){let d=`${t} is blocked on an interactive prompt`;throw t==="codex"?d=rt.codex.auth.test(u)?"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"&&rt.cursor.auth.test(u)?d="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"&&rt.claude.auth.test(u)?d="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"&&rt.claude.block.test(u)&&(d=`claude is waiting on its "Press Enter to continue" screen (bostrat's Enter didn't clear it) \u2014 answer the Continue card in chat (or press Enter in the Terminal tab), then send again`),ee({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:d}).catch(()=>{}),new Error(d)}if(await Fn(e)){let d=hv(t);throw ee({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:d.message}).catch(()=>{}),d}return console.warn(`[agent-ready] ${t} readiness unconfirmed in ${e} after ${n}ms \u2014 driving the box anyway.`),ee({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,paneBlocked:!!rt[t]?.block?.test(u),paneUp:!!rt[t]?.up?.test(u),paneBusy:!!rt[t]?.busy?.test(yv(rt[t],u))}).catch(()=>{}),await Ft(ns),"timeout"}await Ft(ts)}}function dc({agent:e,agentCmd:t}={}){let n=t?Xr(t):Xr(e||"");return{label:n,realClaude:t?Yo(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 kv({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=dc({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function rs({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o,onBlocked:s}={}){let{realCodex:a,realCursor:i}=dc({agent:n,agentCmd:r});return!t||!a&&!i?null:wr({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).then(()=>{},c=>{try{EB(c,{onBlocked:s,agent:n,sessionName:t})}catch{}})}function EB(e,{onBlocked:t=null,agent:n=null,sessionName:r=null}={}){if(typeof t!="function"||!e||e.code==="cli-not-running")return!1;let o=String(typeof e=="string"?e:e.message??"").trim();return o?(t({message:o,agent:n??null,sessionName:r??null}),!0):!1}async function wr({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=dB(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:d,realCursor:p}=dc({agent:r,agentCmd:o});if(u&&e&&await Wr(e),d&&e&&await Xs(e),p&&e&&await Qs(e),(u||d||p)&&n)try{return await wv(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c})}finally{d&&mm(n)}let f=rt[r]?r:rt[l]?l:null;return process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&f?await wv(n,f,s,{launchEcho:i}):(await Ft(ns),"settle")}var dB,ts,ns,pB,fB,rt,hB,wB,gB,yB,kB,ed,xB,gv,SB,AB,os=G(()=>{dt();$i();lu();hu();qo();Ju();yn();oh();dB=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,ts=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,ns=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,pB=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,fB=/^\s*tab to queue message\b/;rt={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:mB},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/}},hB=/Trust this workspace|\[a\]\s*Trust/,wB=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,gB=/Resume from summary/i,yB=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;kB=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,ed=new Map;xB=68,gv=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;SB=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,AB=15});function RB(e){return typeof e!="string"||!e?!1:e.includes(`
127
- `)?!0:Buffer.byteLength(e,"utf8")>=$B}function Un(e,t){return e==="codex"?{enter:!0,submitDelayMs:_B,...RB(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:IB}:{enter:!0}}var _B,IB,$B,pc=G(()=>{_B=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),IB=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),$B=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function fc(e,t){if(e==="codex")return PB(t);if(e!=="claude")return null;let n=String(t).replace(/\r/g,"").split(`
128
- `).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(xv.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(xv.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(OB);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 PB(e){let t=String(e).replace(/\r/g,"").split(`
129
- `).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){(MB.test(t[o])||CB.test(t[o]))&&!ah.test(t[o])?n=o:ah.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(ah);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(NB.test(s))return null;r.unshift(s)}return null}function ih(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=He(n.replace(DB,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!He(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function He(e){return String(e||"").replace(/\s+/g," ").trim()}function vv(e,t,{slackMs:n=2e4}={}){let r=He(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&&He(a.text).includes(r));return s>=0&&s<o.length-1}function Sv(e,t,n,{busy:r=!1}={}){let o=fc(e,n);return o&&rd(t,o)||o&&e==="codex"&&ih(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function rd(e,t){let n=He(e),r=He(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var xv,OB,ah,MB,CB,NB,DB,mc=G(()=>{xv=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,OB=/^❯[  ]?(.*)$/,ah=/^\s*›[  ]?(.*)$/,MB=/\S+ · \S/,CB=/^\s*(?:\? for shortcuts|tab to queue message)\b/,NB=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;DB=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function wc({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=(P,j,T={})=>(a&&typeof a=="object"&&Object.assign(a,{verdict:P,retries:T.retries??0,ms:(i.now||Date.now)()-c,sawUp:!!T.sawUp,reason:T.reason??null}),j);if(!BB.has(t))return l("skipped",!0);let u=i.waitForUp??kv({agent:t,agentCmd:n}),d=i.capture||(P=>Ne(P,{lines:ze})),p=i.pressEnter||(P=>Ke(P,["Enter"],{kind:"submit-retry"})),f=i.sleep||UB,w=i.now||Date.now,h=i.log||(P=>ee(P).catch(()=>{})),y=i.maxMs??FB(),k=w()+y,g={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},x=0,S=0,_=0,M=!1;for(await f(hc[0]);;){let P=await d(e).catch(()=>""),j=to(t,P),T=ba(t,P),$=Sv(t,r,P,{busy:T});if($==="submitted")return l("submitted",!0,{retries:x,sawUp:!0});if(u&&(!j||$==="stuck"&&T)){if(w()>=k)return $==="stuck"?(h({...g,phase:"submit-failed",reason:"stuck-at-deadline",retries:x}),l("failed",!1,{retries:x,sawUp:M,reason:"stuck-at-deadline"})):(h({...g,phase:"submit-unverified",reason:M?"cli-down":"cli-never-up",retries:x,waitedMs:y}),l("unverified",!0,{retries:x,sawUp:M,reason:M?"cli-down":"cli-never-up"}));await f(LB);continue}if(M=!0,$==="stuck"){if(x>=jB)return h({...g,phase:"submit-failed",retries:x}),l("failed",!1,{retries:x,sawUp:!0,reason:"stuck"});x+=1,S=0,_=0,await p(e),h({...g,phase:"submit-retry",attempt:x}),await f(hc[0]);continue}if(S+=1,S>=hc.length||w()>=k)return l("assumed",!0,{retries:x,sawUp:!0});_+=1,await f(hc[Math.min(_,hc.length-1)])}}var BB,hc,LB,jB,FB,UB,ch=G(()=>{dt();os();mc();yn();BB=new Set(["claude","codex"]),hc=[250,450,700],LB=500,jB=2,FB=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},UB=e=>new Promise(t=>setTimeout(t,e))});function Av(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function gr(e){let t=Av(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of HB){let o=0;for(let s of WB[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function Tv(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))qB.has(r)&&(t+=o||0),GB.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function gc(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 Ev(e){let t=Av(e).trim();return t?VB.test(t)?!0:t.split(/\s+/).length<=KB:!1}var HB,WB,qB,GB,KB,VB,od=G(()=>{HB=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],WB={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/,/\bwhat are the odds\b/,/\bdetermine (what|which|whether|how|if)\b/,/\bwhat (does|do|would|could|should|will) .{1,60}\blook like\b/,/\bhow (is|are) (our|the|this|that|your|my) .{1,50}\b(going|doing|performing|trending)\b/,/\bhow (thorough|far along|complete|accurate|reliable|good) are we\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/,/\b(another|one other|one more|next) (thing|issue|bug|problem) i (found|noticed|spotted|saw)\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/,/\b(can|could) we (also |maybe )?(tag|allow for|support|enable)\b/,/\bnow needs to be\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/,/\bpropose (the |a |these |those |new )?loops?\b/],"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/,/\b(framed|phrased|worded) as\b/,/\bwhat'?s a good (response|reply|answer)\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/]};qB=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),GB=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);KB=12,VB=/^\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 Rv(e){let t=gc(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||zB.has(r)||n.push(r);return n}function JB(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($v(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push($v(n,"assistant",o))}}return t}function $v(e,t,n){let r=gr(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 yc(e){let t=JB(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=Rv(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 sd(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(Rv(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 y=e.lengths[w],k=h+_v*(1-Iv+Iv*(y/(e.avgdl||1))),g=f*(h*(_v+1)/k);c.set(w,(c.get(w)||0)+g)}}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 _v,Iv,zB,lh=G(()=>{od();_v=1.5,Iv=.75,zB=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 ad from"node:fs/promises";import Ov from"node:path";async function YB(e){let t=Ov.join(e,".bostrat","events"),n;try{n=await ad.readdir(t)}catch{return yc([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await ad.readFile(Ov.join(t,o),"utf8");for(let a of s.split(`
130
- `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return yc(r)}function XB(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}
131
- ${o}`.trim()||t.slice(0,2e3)}function ZB(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=sd(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?["",`## ${Mv}, 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(`
132
- `):""}async function Cv(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await ad.readFile(t,"utf8");if(a.includes(Mv))return{appended:!1,reason:"already-enriched"};let i=await YB(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=ZB(i,XB(a),{k:r,maxChars:o,exclude:s});return c?(await ad.appendFile(t,`
126
+ `);return e}function bv(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function hv(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 wv(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null,onReady:s}={}){let a=Date.now()+n,i=0,c=null;await Xo(e).catch(()=>{});let l=0;for(;;){let u=nd(await Ne(e),o);if(cc(t,u)){if(l<2&&Zu(e,{onDrive:!0})&&eo(e,"login-issue")){l+=1,Qu(e),await ee({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"login-issue",attempt:l}).catch(()=>{}),await Qe(e,"/login",{enter:!0,submitDelayMs:600,kind:"login-issue"});let d=Date.now()+8e3,p=!1;for(;Date.now()<d;)if(await Ft(ts),ya(t,nd(await Ne(e),o))){p=!0;break}if(p&&r)return ee({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"login-issued"}).catch(()=>{}),"login-issued";continue}if(Date.now()>a){let d=`${t} isn't signed in on this box \u2014 answer the Sign-in card in chat (or run /login from the Terminal tab), then send again`;throw ee({flow:"agent-ready",phase:"blocked",reason:"not-logged-in",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:d}).catch(()=>{}),new Error(d)}await Ft(ts);continue}if((t==="claude"||t==="codex")&&i<3){let d=t==="codex"?hr(u):u;if(cv(t,d)){if(!eo(e,"login-enter")){await Ft(ts);continue}i+=1,ed(e,d),await ee({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"login-enter",attempt:i}).catch(()=>{}),await Qe(e,"",{enter:!0,kind:"login-enter"}),await Ft(ns);continue}}if(EB(t,u))return await s?.(),await Ft(ns),"up";if(rt[t]?.up&&!rt[t].up.test(u))if(await Fn(e)){if(c??=Date.now(),Date.now()-c>=ec()){let d=hv(t);throw ee({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,idleMs:Date.now()-c,error:d.message}).catch(()=>{}),d}}else c=null;else c=null;if(r&&t==="claude"&&yB.test(u)&&!rt.claude.up.test(u))return ee({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{}),"dialog-bail";if(t==="codex"&&gB.test(u)&&!rt.codex.up.test(u)&&i<3){if(!eo(e,"codex-trust")){await Ft(ts);continue}i+=1,await ee({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await Qe(e,"",{enter:!0,kind:"codex-trust-accept"}),await Ft(ns);continue}if(t==="cursor"&&wB.test(u)&&!rt.cursor.up.test(u)&&i<3){if(!eo(e,"cursor-trust")){await Ft(ts);continue}i+=1,await ee({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await Qe(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await Ft(ns);continue}if(t==="codex"&&i<3){let d=kB(u);if(d){if(!eo(e,`codex-update:${d.from}->${d.to}`)){await Ft(ts);continue}i+=1,await ee({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${d.from} -> ${d.to}`}).catch(()=>{}),await Qe(e,"3",{enter:!1,kind:"codex-update-skip"}),wm({sessionName:e,from:d.from,to:d.to}),await Ft(ns);continue}}if(Date.now()>a){if(ya(t,u)){let d=`${t} is blocked on an interactive prompt`;throw t==="codex"?d=rt.codex.auth.test(u)?"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"&&rt.cursor.auth.test(u)?d="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"&&rt.claude.auth.test(u)?d="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"&&rt.claude.block.test(u)&&(d=`claude is waiting on its "Press Enter to continue" screen (bostrat's Enter didn't clear it) \u2014 answer the Continue card in chat (or press Enter in the Terminal tab), then send again`),ee({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:d}).catch(()=>{}),new Error(d)}if(await Fn(e)){let d=hv(t);throw ee({flow:"agent-ready",phase:"blocked",reason:"cli-not-running",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:d.message}).catch(()=>{}),d}return console.warn(`[agent-ready] ${t} readiness unconfirmed in ${e} after ${n}ms \u2014 driving the box anyway.`),ee({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,paneBlocked:!!rt[t]?.block?.test(u),paneUp:!!rt[t]?.up?.test(u),paneBusy:!!rt[t]?.busy?.test(yv(rt[t],u))}).catch(()=>{}),await Ft(ns),"timeout"}await Ft(ts)}}function dc({agent:e,agentCmd:t}={}){let n=t?Xr(t):Xr(e||"");return{label:n,realClaude:t?Yo(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 kv({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=dc({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function rs({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o,onBlocked:s}={}){let{realCodex:a,realCursor:i}=dc({agent:n,agentCmd:r});return!t||!a&&!i?null:wr({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).then(()=>{},c=>{try{_B(c,{onBlocked:s,agent:n,sessionName:t})}catch{}})}function _B(e,{onBlocked:t=null,agent:n=null,sessionName:r=null}={}){if(typeof t!="function"||!e||e.code==="cli-not-running")return!1;let o=String(typeof e=="string"?e:e.message??"").trim();return o?(t({message:o,agent:n??null,sessionName:r??null}),!0):!1}async function wr({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=pB(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:d,realCursor:p}=dc({agent:r,agentCmd:o});if(u&&e&&await Wr(e),d&&e&&await Xs(e),p&&e&&await Qs(e),(u||d||p)&&n)try{return await wv(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c})}finally{d&&hm(n)}let f=rt[r]?r:rt[l]?l:null;return process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&f?await wv(n,f,s,{launchEcho:i}):(await Ft(ns),"settle")}var pB,ts,ns,fB,mB,rt,wB,gB,yB,bB,xB,td,vB,gv,TB,AB,os=G(()=>{dt();$i();lu();hu();qo();Yu();yn();oh();pB=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,ts=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,ns=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,fB=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,mB=/^\s*tab to queue message\b/;rt={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:hB},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/}},wB=/Trust this workspace|\[a\]\s*Trust/,gB=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,yB=/Resume from summary/i,bB=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;xB=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,td=new Map;vB=68,gv=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;TB=/\bWaiting for \d+\b[^\n]*\bto finish\b|\/workflows to (?:stop|monitor)\b/,AB=15});function OB(e){return typeof e!="string"||!e?!1:e.includes(`
127
+ `)?!0:Buffer.byteLength(e,"utf8")>=RB}function Un(e,t){return e==="codex"?{enter:!0,submitDelayMs:IB,...OB(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:$B}:{enter:!0}}var IB,$B,RB,pc=G(()=>{IB=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),$B=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),RB=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});function fc(e,t){if(e==="codex")return DB(t);if(e!=="claude")return null;let n=String(t).replace(/\r/g,"").split(`
128
+ `).map(c=>c.replace(/\s+$/,"")),r=-1;for(let c=n.length-1;c>=0;c--)if(xv.test(n[c])){r=c;break}if(r<=0)return null;let o=-1;for(let c=r-1;c>=0;c--)if(xv.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(MB);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 DB(e){let t=String(e).replace(/\r/g,"").split(`
129
+ `).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){(CB.test(t[o])||NB.test(t[o]))&&!ah.test(t[o])?n=o:ah.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(ah);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(PB.test(s))return null;r.unshift(s)}return null}function ih(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=He(n.replace(BB,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!He(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function He(e){return String(e||"").replace(/\s+/g," ").trim()}function vv(e,t,{slackMs:n=2e4}={}){let r=He(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&&He(a.text).includes(r));return s>=0&&s<o.length-1}function Sv(e,t,n,{busy:r=!1}={}){let o=fc(e,n);return o&&od(t,o)||o&&e==="codex"&&ih(t,o)?"stuck":r&&e!=="codex"||o?"submitted":"unknown"}function od(e,t){let n=He(e),r=He(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var xv,MB,ah,CB,NB,PB,BB,mc=G(()=>{xv=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,MB=/^❯[  ]?(.*)$/,ah=/^\s*›[  ]?(.*)$/,CB=/\S+ · \S/,NB=/^\s*(?:\? for shortcuts|tab to queue message)\b/,PB=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;BB=/\[Pasted Content (\d+) chars\](?: #\d+)?/g});async function wc({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=(P,j,A={})=>(a&&typeof a=="object"&&Object.assign(a,{verdict:P,retries:A.retries??0,ms:(i.now||Date.now)()-c,sawUp:!!A.sawUp,reason:A.reason??null}),j);if(!LB.has(t))return l("skipped",!0);let u=i.waitForUp??kv({agent:t,agentCmd:n}),d=i.capture||(P=>Ne(P,{lines:ze})),p=i.pressEnter||(P=>Ke(P,["Enter"],{kind:"submit-retry"})),f=i.sleep||HB,w=i.now||Date.now,h=i.log||(P=>ee(P).catch(()=>{})),y=i.maxMs??UB(),k=w()+y,g={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},x=0,S=0,_=0,M=!1;for(await f(hc[0]);;){let P=await d(e).catch(()=>""),j=to(t,P),A=ba(t,P),$=Sv(t,r,P,{busy:A});if($==="submitted")return l("submitted",!0,{retries:x,sawUp:!0});if(u&&(!j||$==="stuck"&&A)){if(w()>=k)return $==="stuck"?(h({...g,phase:"submit-failed",reason:"stuck-at-deadline",retries:x}),l("failed",!1,{retries:x,sawUp:M,reason:"stuck-at-deadline"})):(h({...g,phase:"submit-unverified",reason:M?"cli-down":"cli-never-up",retries:x,waitedMs:y}),l("unverified",!0,{retries:x,sawUp:M,reason:M?"cli-down":"cli-never-up"}));await f(jB);continue}if(M=!0,$==="stuck"){if(x>=FB)return h({...g,phase:"submit-failed",retries:x}),l("failed",!1,{retries:x,sawUp:!0,reason:"stuck"});x+=1,S=0,_=0,await p(e),h({...g,phase:"submit-retry",attempt:x}),await f(hc[0]);continue}if(S+=1,S>=hc.length||w()>=k)return l("assumed",!0,{retries:x,sawUp:!0});_+=1,await f(hc[Math.min(_,hc.length-1)])}}var LB,hc,jB,FB,UB,HB,ch=G(()=>{dt();os();mc();yn();LB=new Set(["claude","codex"]),hc=[250,450,700],jB=500,FB=2,UB=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},HB=e=>new Promise(t=>setTimeout(t,e))});function Tv(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function gr(e){let t=Tv(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of WB){let o=0;for(let s of qB[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function Av(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))GB.has(r)&&(t+=o||0),KB.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function gc(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 Ev(e){let t=Tv(e).trim();return t?zB.test(t)?!0:t.split(/\s+/).length<=VB:!1}var WB,qB,GB,KB,VB,zB,sd=G(()=>{WB=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],qB={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/,/\bwhat are the odds\b/,/\bdetermine (what|which|whether|how|if)\b/,/\bwhat (does|do|would|could|should|will) .{1,60}\blook like\b/,/\bhow (is|are) (our|the|this|that|your|my) .{1,50}\b(going|doing|performing|trending)\b/,/\bhow (thorough|far along|complete|accurate|reliable|good) are we\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/,/\b(another|one other|one more|next) (thing|issue|bug|problem) i (found|noticed|spotted|saw)\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/,/\b(can|could) we (also |maybe )?(tag|allow for|support|enable)\b/,/\bnow needs to be\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/,/\bpropose (the |a |these |those |new )?loops?\b/],"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/,/\b(framed|phrased|worded) as\b/,/\bwhat'?s a good (response|reply|answer)\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/]};GB=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),KB=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);VB=12,zB=/^\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 Rv(e){let t=gc(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||JB.has(r)||n.push(r);return n}function YB(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($v(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push($v(n,"assistant",o))}}return t}function $v(e,t,n){let r=gr(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 yc(e){let t=YB(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=Rv(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 ad(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(Rv(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 y=e.lengths[w],k=h+_v*(1-Iv+Iv*(y/(e.avgdl||1))),g=f*(h*(_v+1)/k);c.set(w,(c.get(w)||0)+g)}}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 _v,Iv,JB,lh=G(()=>{sd();_v=1.5,Iv=.75,JB=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 id from"node:fs/promises";import Ov from"node:path";async function XB(e){let t=Ov.join(e,".bostrat","events"),n;try{n=await id.readdir(t)}catch{return yc([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await id.readFile(Ov.join(t,o),"utf8");for(let a of s.split(`
130
+ `))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return yc(r)}function ZB(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}
131
+ ${o}`.trim()||t.slice(0,2e3)}function QB(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=ad(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?["",`## ${Mv}, 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(`
132
+ `):""}async function Cv(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await id.readFile(t,"utf8");if(a.includes(Mv))return{appended:!1,reason:"already-enriched"};let i=await XB(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=QB(i,ZB(a),{k:r,maxChars:o,exclude:s});return c?(await id.appendFile(t,`
133
133
  `+c),{appended:!0,chars:c.length,chunks:c.split(`
134
- - `).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 Mv,Nv=G(()=>{lh();Mv="Relevant prior discussion (verbatim, retrieved"});function oL(e){return QB.test(String(e||"").trimStart())}function Bv(e){let t=String(e||"");if(!oL(t.trimStart()))return null;let n=t.replace(eL,"").trim(),r=sL(n),o=[];for(let u of nL){let d=u.from.map(p=>ka(r.get(p))).find(p=>p&&!Pv(p));d&&o.push({h:u.h,text:bc(d,tL)})}let s=ka(r.get("Current Work"))||ka(r.get("Primary Request and Intent"))||iL(n),a=cd(s),i=bc(id(ph(a[0]||"")),rL)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(bc(id(ph(l)),dh));for(let u of["Pending Tasks","Optional Next Step"]){let d=cd(ka(r.get(u)))[0]||"";if(!(!d||Pv(d))){c.push(bc(`Left to do: ${id(ph(d))}`,dh));break}}if(!c.length){let u=cd(ka(r.get("Problem Solving"))||"")[0];u&&c.push(bc(id(u),dh))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function sL(e){let t=new Map,n=[];uh.lastIndex=0;for(let r=uh.exec(e);r;r=uh.exec(e))n.push({name:aL(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 aL(e){return Dv.find(n=>n.toLowerCase()===e.toLowerCase())||e}function ka(e){return e?String(e).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
135
- `).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 iL(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return ka(t.split(/\n{2,}/).slice(0,2).join(" "))}function cd(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 ph(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 id(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function Pv(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function bc(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=cd(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 QB,Dv,uh,eL,tL,nL,rL,dh,Lv=G(()=>{QB=/^This session is being continued from a previous conversation that ran out of context\./,Dv=["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"],uh=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${Dv.join("|")})[:*\t ]*$`,"gim"),eL=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,tL=420,nL=[{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"]}],rL=116,dh=168});function Uv(e){return fh.has(String(e||"").replace(/^\//,"").toLowerCase())}function kc(e){let t=String(e||"").trim();if(!t)return null;let n=Bv(t);if(n)return n;let r=t.match(cL);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(lL);if(o)return{kind:"skill",name:o[1]};let s=t.match(uL);if(s)return{kind:"skill",name:s[1].toLowerCase()};let a=t.match(dL);if(a){let c=a[1].toLowerCase();return fh.has(c)?{kind:"suppress"}:{kind:"command",command:`/${c}`}}let i=t.match(xL);if(i&&fh.has(i[1].toLowerCase()))return{kind:"suppress"};if(pL.test(t))return{kind:"suppress"};if(mL.test(t))return{kind:"suppress"};if(fL.test(t))return{kind:"suppress"};if(hL.test(t)){let c=u=>TL(t.match(u)?.[1].trim()||"")||null,l=c(kL);return{kind:"task",summary:c(wL)||"",taskId:c(gL),toolUseId:c(yL),status:c(bL)?.toLowerCase()||null,resultHead:l?l.length>jv?`${l.slice(0,jv).trimEnd()}\u2026`:l:null}}return null}function Hv(e){let t=kc(e?.text);return t||(e?.injected?{kind:"skill",name:e.injected.skill||"skill"}:null)}function Wv(e){let t=String(e||""),n=t.match(vL);if(n)return{kind:"shell-input",command:n[1].trim()};let r=t.match(SL);return r?{kind:"shell-output",stdout:Fv(r[1]),stderr:Fv(r[2])}:null}function TL(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function qv(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 Gv(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var cL,lL,uL,dL,pL,fL,mL,hL,wL,gL,yL,bL,kL,jv,fh,xL,vL,SL,AL,Fv,ld=G(()=>{Lv();cL=/^Base directory for this skill:\s*(\S+)/,lL=/^Run the "([^"]+)" workflow\./,uL=/^#\s*\/([a-z0-9:_-]+)\s*[—–:-]/i,dL=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,pL=/^<local-command-(?:stdout|caveat)>/i,fL=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,mL=/^Continue from where you left off\.$/,hL=/^<task-notification>/i,wL=/<summary>([\s\S]*?)<\/summary>/i,gL=/<task-id>([\s\S]*?)<\/task-id>/i,yL=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,bL=/<status>([\s\S]*?)<\/status>/i,kL=/<result>([\s\S]*?)(?:<\/result>|$)/i,jv=600,fh=new Set(["model","clear","compact","login","exit","quit"]);xL=/^\/([a-z0-9:_-]+)$/i;vL=/^\s*<bash-input>([\s\S]*?)<\/bash-input>\s*$/i,SL=/^\s*<bash-stdout>([\s\S]*?)<\/bash-stdout>\s*(?:<bash-stderr>([\s\S]*?)<\/bash-stderr>)?\s*$/i,AL=/\x1b\[[0-9;?]*[ -/]*[@-~]/g,Fv=e=>String(e||"").replace(AL,"").replace(/^\n+/,"").replace(/\s+$/,"")});import EL from"node:crypto";function RL(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,Vv)){let o=xa(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,_L)){let c=xa(i?.label);if(!c)return null;let l=xa(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<IL)return null;n.push({question:o,header:xa(r?.header).slice(0,$L),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function mh(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;Kv.lastIndex=0;let t=null;for(let o;o=Kv.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=RL(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function hh(e,t,n){let r=EL.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function wh(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=Vv}={}){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||mh(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=hh(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 zv(e,t,n,r){let o=[];(e?.questions||[]).forEach((i,c)=>{let l=(t?.[c]||[]).map(d=>i.options?.[d]?.label).filter(Boolean),u=xa(Array.isArray(r)?r[c]:"");u&&l.push(u),l.length&&o.push({name:i.header||i.question,picks:l.join(", ")})});let s=xa(n),a;return o.length?o.length===1?a=`${o[0].name}: ${o[0].picks}`:a=`Answers:
134
+ - `).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 Mv,Nv=G(()=>{lh();Mv="Relevant prior discussion (verbatim, retrieved"});function sL(e){return eL.test(String(e||"").trimStart())}function Bv(e){let t=String(e||"");if(!sL(t.trimStart()))return null;let n=t.replace(tL,"").trim(),r=aL(n),o=[];for(let u of rL){let d=u.from.map(p=>ka(r.get(p))).find(p=>p&&!Pv(p));d&&o.push({h:u.h,text:bc(d,nL)})}let s=ka(r.get("Current Work"))||ka(r.get("Primary Request and Intent"))||cL(n),a=ld(s),i=bc(cd(ph(a[0]||"")),oL)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(bc(cd(ph(l)),dh));for(let u of["Pending Tasks","Optional Next Step"]){let d=ld(ka(r.get(u)))[0]||"";if(!(!d||Pv(d))){c.push(bc(`Left to do: ${cd(ph(d))}`,dh));break}}if(!c.length){let u=ld(ka(r.get("Problem Solving"))||"")[0];u&&c.push(bc(cd(u),dh))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function aL(e){let t=new Map,n=[];uh.lastIndex=0;for(let r=uh.exec(e);r;r=uh.exec(e))n.push({name:iL(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 iL(e){return Dv.find(n=>n.toLowerCase()===e.toLowerCase())||e}function ka(e){return e?String(e).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
135
+ `).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 cL(e){let t=e.replace(/^[\s\S]*?\bSummary:\s*/i,"");return ka(t.split(/\n{2,}/).slice(0,2).join(" "))}function ld(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 ph(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 cd(e){return String(e||"").replace(/(?<![:\w/])(?:\/[\w.@+-]+){4,}/g,t=>`\u2026/${t.split("/").slice(-2).join("/")}`)}function Pv(e){return/^(none|nothing|n\/a|no pending|there are no)\b/i.test(String(e||"").trim())}function bc(e,t){let n=String(e||"").trim();if(n.length<=t)return n;let r=ld(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 eL,Dv,uh,tL,nL,rL,oL,dh,Lv=G(()=>{eL=/^This session is being continued from a previous conversation that ran out of context\./,Dv=["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"],uh=new RegExp(String.raw`^[ \t]*#{0,4}[ \t]*(?:\d+[.)][ \t]*)?\*{0,2}(${Dv.join("|")})[:*\t ]*$`,"gim"),tL=/\n+If you need specific details from before compaction[\s\S]*$|\n+Continue the conversation from where it left off[\s\S]*$/,nL=420,rL=[{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"]}],oL=116,dh=168});function Uv(e){return fh.has(String(e||"").replace(/^\//,"").toLowerCase())}function kc(e){let t=String(e||"").trim();if(!t)return null;let n=Bv(t);if(n)return n;let r=t.match(lL);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(uL);if(o)return{kind:"skill",name:o[1]};let s=t.match(dL);if(s)return{kind:"skill",name:s[1].toLowerCase()};let a=t.match(pL);if(a){let c=a[1].toLowerCase();return fh.has(c)?{kind:"suppress"}:{kind:"command",command:`/${c}`}}let i=t.match(vL);if(i&&fh.has(i[1].toLowerCase()))return{kind:"suppress"};if(fL.test(t))return{kind:"suppress"};if(hL.test(t))return{kind:"suppress"};if(mL.test(t))return{kind:"suppress"};if(wL.test(t)){let c=u=>EL(t.match(u)?.[1].trim()||"")||null,l=c(xL);return{kind:"task",summary:c(gL)||"",taskId:c(yL),toolUseId:c(bL),status:c(kL)?.toLowerCase()||null,resultHead:l?l.length>jv?`${l.slice(0,jv).trimEnd()}\u2026`:l:null}}return null}function Hv(e){let t=kc(e?.text);return t||(e?.injected?{kind:"skill",name:e.injected.skill||"skill"}:null)}function Wv(e){let t=String(e||""),n=t.match(SL);if(n)return{kind:"shell-input",command:n[1].trim()};let r=t.match(TL);return r?{kind:"shell-output",stdout:Fv(r[1]),stderr:Fv(r[2])}:null}function EL(e){return e.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&")}function qv(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 Gv(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":"command-run"}var lL,uL,dL,pL,fL,mL,hL,wL,gL,yL,bL,kL,xL,jv,fh,vL,SL,TL,AL,Fv,ud=G(()=>{Lv();lL=/^Base directory for this skill:\s*(\S+)/,uL=/^Run the "([^"]+)" workflow\./,dL=/^#\s*\/([a-z0-9:_-]+)\s*[—–:-]/i,pL=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,fL=/^<local-command-(?:stdout|caveat)>/i,mL=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,hL=/^Continue from where you left off\.$/,wL=/^<task-notification>/i,gL=/<summary>([\s\S]*?)<\/summary>/i,yL=/<task-id>([\s\S]*?)<\/task-id>/i,bL=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,kL=/<status>([\s\S]*?)<\/status>/i,xL=/<result>([\s\S]*?)(?:<\/result>|$)/i,jv=600,fh=new Set(["model","clear","compact","login","exit","quit"]);vL=/^\/([a-z0-9:_-]+)$/i;SL=/^\s*<bash-input>([\s\S]*?)<\/bash-input>\s*$/i,TL=/^\s*<bash-stdout>([\s\S]*?)<\/bash-stdout>\s*(?:<bash-stderr>([\s\S]*?)<\/bash-stderr>)?\s*$/i,AL=/\x1b\[[0-9;?]*[ -/]*[@-~]/g,Fv=e=>String(e||"").replace(AL,"").replace(/^\n+/,"").replace(/\s+$/,"")});import _L from"node:crypto";function OL(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,Vv)){let o=xa(r?.question);if(!o)return null;let s=Array.isArray(r?.options)?r.options:[],a=[];for(let i of s.slice(0,IL)){let c=xa(i?.label);if(!c)return null;let l=xa(i?.description);a.push(l?{label:c,description:l}:{label:c})}if(a.length<$L)return null;n.push({question:o,header:xa(r?.header).slice(0,RL),multiSelect:r?.multiSelect===!0,options:a})}return n.length?n:null}function mh(e){if(typeof e!="string"||!e.includes("```bostrat-question"))return null;Kv.lastIndex=0;let t=null;for(let o;o=Kv.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=OL(n);return r?{text:e.slice(0,t.index).trimEnd(),questions:r}:null}function hh(e,t,n){let r=_L.createHash("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8);return`${e}:ask:${t||"turn"}:${r}`}function wh(e,{leadBoxId:t,provider:n,isAnswered:r,maxQuestions:o=Vv}={}){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||mh(s.text)?.questions;if(!a?.length)return null;let i=a.slice(0,Math.max(1,o)),c=hh(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 zv(e,t,n,r){let o=[];(e?.questions||[]).forEach((i,c)=>{let l=(t?.[c]||[]).map(d=>i.options?.[d]?.label).filter(Boolean),u=xa(Array.isArray(r)?r[c]:"");u&&l.push(u),l.length&&o.push({name:i.header||i.question,picks:l.join(", ")})});let s=xa(n),a;return o.length?o.length===1?a=`${o[0].name}: ${o[0].picks}`:a=`Answers:
136
136
  ${o.map(i=>`- ${i.name}: ${i.picks}`).join(`
137
137
  `)}`:a=s,o.length&&s&&(a+=`
138
- ${s}`),a||""}var Vv,_L,IL,$L,Kv,xa,Jv,gh=G(()=>{Vv=4,_L=4,IL=2,$L=24,Kv=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,xa=e=>typeof e=="string"?e.trim():"";Jv=`
138
+ ${s}`),a||""}var Vv,IL,$L,RL,Kv,xa,Jv,gh=G(()=>{Vv=4,IL=4,$L=2,RL=24,Kv=/^[ \t]{0,3}(`{3,})bostrat-question[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]{0,3}\1`*[ \t]*$/gm,xa=e=>typeof e=="string"?e.trim():"";Jv=`
139
139
  When you are BLOCKED on a decision only the operator can make \u2014 an ambiguous
140
140
  requirement, an irreversible choice, several valid approaches \u2014 do not bury the
141
141
  question in prose. End your message with exactly ONE fenced code block tagged
@@ -156,91 +156,91 @@ your turn. The operator sees the questions as an interactive card in their chat
156
156
  They may instead reply in free text \u2014 treat that as the answer. Never use the block for rhetorical questions, progress updates, or
157
157
  anything you can decide yourself; keep asking in prose for questions without
158
158
  enumerable options.
159
- `});function OL(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 Xv(e,t,n){let r=yh(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 Hn(e,{now:t=Date.now()}={}){let n=[],r=new Set,o=new Set,s=new Map,a=new Map,i=new Set,c=new Map,l=new Map,u=new Map,d=(b,m)=>{m!=null&&(u.has(b)||u.set(b,[]),u.get(b).push(m))},p=(b,m)=>{let v=null;for(let D of[b,null])for(let J of u.get(D)||[])J>m&&(v==null||J<v)&&(v=J);return v},f=new Set,w=new Map,h=new Map,y=(b,m)=>{h.set(b,m),n.push(m)},k=b=>{let m=h.get(b);m&&(m.retired=!0)},g=/^Agent "([\s\S]+)" finished$/,x=new Map;for(let b of e||[]){if(b.type!=="tool.called"||b.source!=="transcript")continue;let m=String(b.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 D=v[0].split("/").pop().toLowerCase();x.has(D)||x.set(D,[]),x.get(D).push(b.payload?.ts??b.ts)}}let S=3*6e4,_=20*6e4,M=(b,m)=>!!(b?.name&&x.get(String(b.name).toLowerCase()))?.some(D=>D>=m-S&&D<=m+_);for(let b of e||[])if(b.type==="turn.retracted"){o.add(`${b.boxId}|${b.payload?.saidTs}`);let m=He(b.payload?.text);m&&(s.has(b.boxId)||s.set(b.boxId,[]),s.get(b.boxId).push(m))}else if(b.type==="turn.user"&&b.source==="orchestrator"){let m=He(b.payload?.text);m&&(a.has(b.boxId)||a.set(b.boxId,new Set),a.get(b.boxId).add(m))}else if(b.type==="job.stalled"&&b.payload?.id)c.set(b.payload.id,{ts:pe(b),quietMs:Number(b.payload.quietMs)||null});else if(b.type==="job.stopped"&&b.payload?.id)l.has(b.payload.id)||l.set(b.payload.id,{status:"killed",summary:null,resultHead:null,ts:pe(b)});else if(b.type==="session.ready"){let m=b.payload?.source;m!=="compact"&&m!=="clear"&&d(b.boxId??null,pe(b))}else if(b.type==="handoff.done")d(b.boxId??b.payload?.from??null,pe(b));else if(b.type==="box.state.changed"&&b.payload?.change==="archived")d(null,pe(b));else if(b.type==="job.started"&&b.payload?.id)i.add(b.payload.id),(b.payload.kind||"agent")==="agent"&&b.payload.name&&f.add(b.payload.name);else if(b.type==="turn.user"&&b.payload?.note?.kind==="task"){let m=b.payload.note,v={status:m.status||null,summary:m.summary||null,resultHead:m.resultHead??null,ts:pe(b)};m.toolUseId&&l.set(m.toolUseId,v);let D=String(m.summary||"").match(g);D&&w.set(D[1],v)}let P=new Map,j=new Map,T=null,$=new Map,L=new Map,H=new Map,R=new Map,A=new Map,C=new Map,W=new Map,B=new Map,Z=new Map,xe=new Map,Ae=new Map,_e=new Map,Q=new Map,Xe=new Map,Pe=new Map,le=new Map,ge=(b,m)=>{b.arm.status=m;let v=b.line,D=v.arms.map(J=>J.status);v.status=D.includes("armed")?"armed":D.includes("offered")?"offered":D.includes("replaced")?"replaced":"cancelled"},de=[],te=new Set,we=new Map,Oe=(b,m)=>{we.delete(b);let v=n.indexOf(b);v>=0&&n.splice(v,1),m!=null&&(b.ts=m),n.push(b)},Ve=b=>{if(de.push(b),!(b.box?te.has(b.box):te.size>0))return;let v=n.indexOf(b);v>=0&&n.splice(v,1),we.set(b,"held")},Nt=b=>{if(!de.length)return;let m=pe(b);for(let v of de)v.status!=="open"||we.get(v)==="superseded"||v.box&&v.box!==b.boxId||(v.ts??0)>m||Oe(v,m)},O=b=>{if(!de.length)return;let m=pe(b);for(let v of de)we.get(v)!=="held"||v.status!=="open"||v.box&&b.boxId&&v.box!==b.boxId||Oe(v,Math.max(v.ts??0,m))},X=()=>{for(let[b,m]of[...we])m==="held"&&Oe(b,null);de.length=0,re.clear()},re=new Set,he=b=>{for(let m of re){if(m.status!=="open"||m.box&&b&&m.box!==b)continue;m.status="superseded";let v=n.indexOf(m);v>=0&&n.splice(v,1),we.set(m,"superseded"),$.delete(m.offerId)}re.clear()},Be=new Map,Pt=new Map,tt=new Map,wn=new Map,Kt=new Map,ht=new Map,wt=new Map,at=new Map,Ti=()=>{for(let b of at.values())b.questions.length&&n.push(b);at.clear()},gt=null,cr=new Map,Hr=6e4,lr=new Map,gn=(b,m)=>{let v=s.get(b);if(!v?.length)return!1;let D=He(m),J=a.get(b);return v.some(ie=>{if(!D.startsWith(ie))return!1;let ve=He(D.slice(ie.length));return!!ve&&!!J?.has(ve)})};for(let b of e||[]){let m=b.payload||{};switch(b.type){case"turn.user":{if(b.source==="hook"){b.boxId&&te.add(b.boxId);break}if(X(),!String(m.text||"").trim()&&!m.images?.length&&!m.attachments?.length)break;{let v=Wv(m.text);if(v){if(v.kind==="shell-input"){let D={id:b.id,kind:"shell",command:v.command,stdout:null,stderr:null,done:!1,ts:pe(b),box:b.boxId,agent:b.provider};n.push(D),cr.set(b.boxId,D)}else{let D=cr.get(b.boxId);D?(D.stdout=v.stdout||null,D.stderr=v.stderr||null,D.done=!0,cr.delete(b.boxId)):n.push({id:b.id,kind:"shell",command:null,stdout:v.stdout||null,stderr:v.stderr||null,done:!0,ts:pe(b),box:b.boxId,agent:b.provider})}break}}{let v=m.note||kc(m.text);if(v){if(v.kind==="task"){if(v.toolUseId&&i.has(v.toolUseId))break;let D=String(v.summary||"").match(g);if(!v.toolUseId&&D&&f.has(D[1]))break}if(v.kind==="command"&&Uv(v.command))break;if(v.kind==="resume-summary"){n.push({id:b.id,kind:"resume-summary",title:v.title||"Context resumed from summary",bullets:v.bullets||[],sections:v.sections||[],rawChars:v.rawChars??null,ts:pe(b),box:b.boxId,agent:b.provider});break}v.kind!=="suppress"&&n.push({id:b.id,kind:"event",type:Gv(v),name:v.name??null,command:v.command??null,summary:v.summary??null,status:v.status??null,ts:pe(b),box:b.boxId,agent:b.provider});break}}if(o.has(`${b.boxId}|${pe(b)}`)||b.source==="transcript"&&gn(b.boxId,m.text))break;if(m.kind==="merge-notify"||m.kind==="ship-notify"){n.push({id:b.id,kind:"event",type:m.kind==="ship-notify"?"ship-notified":"merge-notified",text:m.text,ts:pe(b),box:b.boxId,agent:b.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==="login-greet"){m.kind==="prompt-answer"&&(gt=null);break}for(let v of $.values())v.status="stale";$.clear();for(let v of H.values())v.status="stale";H.clear();for(let v of Q.values())v.rows.some(D=>D.rowStatus==="sent")||(v.status="stale",Q.delete(v.offerId));gt&&gt.box===b.boxId&&(n.push(OL(gt)),gt=null),n.push({id:b.id,kind:"message",role:"user",text:m.text,ts:pe(b),box:b.boxId,agent:b.provider,boxRole:m.boxRole,...b.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||{};n.push({id:b.id,kind:"event",type:"peer-message",text:m.text,from:v.trackName||v.boxId||v.name||null,fromTrackId:v.trackId||null,ts:pe(b),box:b.boxId,agent:b.provider});break}case"turn.agent":{if(m.model==="<synthetic>"&&/^No response requested\.$/.test(String(m.text||"").trim()))break;let v=Xx(m,{codexFailedText:Qo});if(v){n.push({id:b.id,kind:"event",type:"provider-error",cls:v.cls,status:v.status??void 0,text:v.text,provider:b.provider,legacy:!0,at:pe(b),ts:pe(b),box:b.boxId,agent:b.provider});break}Ti();let D=(m.images||[]).filter(yt=>!M(yt,pe(b)));if(b.source==="hook"&&!String(m.text||"").trim()&&(O(b),b.boxId&&te.delete(b.boxId)),!String(m.text||"").trim()&&!D.length)break;if(b.provider==="cursor"){let yt=`${b.boxId}|${m.text}`;if(r.has(yt))break;r.add(yt)}(!gt||gt.box===b.boxId)&&(gt=null);let J=b.provider==="codex"?(m.tools||[]).filter(yt=>!eh.has(yt)&&!sc.has(yt)):m.tools||[],ie=m.text,ve=null,_t=mh(String(m.text||""));_t&&(ie=_t.text,ve={questions:_t.questions}),n.push({id:b.id,kind:"message",role:"assistant",text:ie,ts:pe(b),box:b.boxId,agent:b.provider,boxRole:m.boxRole,...ve?{ask:ve}:{},...J.length?{tools:J}:{},...m.model?{model:m.model}:{},...m.sourceId?{sourceId:m.sourceId}:{},...D.length?{images:D}:{}}),Nt(b),ve&&(gt={id:b.id,groupId:hh(b.provider,m.sourceId||b.id,ve.questions),provider:b.provider,box:b.boxId,questions:ve.questions,ts:pe(b)});break}case"job.started":{if(!m.id)break;let v=pe(b),D=l.get(m.id);if(!D&&(m.kind||"agent")==="agent"&&m.name){let rn=w.get(m.name);rn&&rn.ts>=v&&(D=rn)}let J=D?null:c.get(m.id)||null,ie=D||J?null:p(b.boxId??null,v),ve={jobId:m.id,jobKind:m.kind||"agent",name:m.name||null,detail:m.detail||null,status:D?D.status==="killed"?"stopped":D.status&&D.status!=="completed"?"failed":"done":J?"stalled":ie!=null?"lost":"running",startedTs:v,finishedTs:D?.ts??J?.ts??ie??null,quietMs:J?.quietMs??null,summary:D?.summary??null,resultHead:D?.resultHead??null},_t=lr.get(b.boxId),yt=_t?.jobs[_t.jobs.length-1]?.startedTs;if(_t&&yt!=null&&v-yt<=Hr)_t.jobs.push(ve);else{let rn={id:b.id,kind:"job-dock",dockId:m.id,ts:v,box:b.boxId,agent:b.provider,jobs:[ve]};lr.set(b.boxId,rn),n.push(rn)}break}case"handoff.done":n.push(bt(b,"lead-handoff"));break;case"subtask.delegated":n.push({...bt(b,"subtask-delegated"),to:b.boxId,toAgent:b.provider});break;case"subtask.merged":n.push(bt(b,"subtask-merged"));break;case"pr.state.changed":{if(!m.change)break;if(m.change==="opened"){for(let D of $.values())D.status="stale";$.clear();for(let D of H.values())D.status="stale";H.clear()}let v=bt(b,`pr-${m.change}`);if(v.box=b.boxId??null,Yv.has(m.change)&&m.number!=null){let D=Xv(P,j,m);if(P.size>=2){for(let ie of j.values())for(let ve of ie)ve.grouped=!0;v.groupPrs=[...P.values()];let J=[v];for(let ie of P.keys())j.set(ie,J)}else{let J=j.get(D)??[];J.push(v),j.set(D,J)}}else if(m.change==="merged"||m.change==="closed"||m.change==="lost"){let D=yh(m),J=T&&!T.complete||P.size>=2;if(P.has(D))P.delete(D),j.delete(D);else if(m.number!=null)for(let ie of[...P.keys()])ie.endsWith(`#${m.number}`)&&(P.delete(ie),j.delete(ie));if(J&&m.number!=null){(!T||T.complete)&&(T={id:b.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:pe(b),ts:pe(b),box:b.boxId,agent:b.provider},n.push(T)),T.prs.push({number:m.number,url:m.url??null,title:m.title??null,repo:m.repo??null,branch:m.branch??null,change:m.change,ts:pe(b)}),T.remaining=[...P.values()],T.complete=P.size===0;break}}n.push(v);break}case"pr.offered":{if(!m.offerId)break;he(b.boxId);for(let D of $.values())D.status="stale";$.clear();for(let D of H.values())D.status="stale";H.clear();let v={id:b.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:b.source==="cli"||m.via==="cli"?"cli":"transcript",ts:pe(b),box:b.boxId,agent:b.provider};$.set(m.offerId,v),L.set(m.offerId,v),n.push(v),re.add(v),v.source==="cli"&&Ve(v);break}case"pr.offer.answered":{let v=L.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}),$.delete(m.offerId));break}case"pr.exists.offered":{if(!m.offerId)break;for(let D of H.values())D.status="stale";H.clear();let v={id:b.id,kind:"pr-exists-offer",offerId:m.offerId,srcOfferId:m.srcOfferId??null,branch:m.branch||null,base:m.base||null,pr:m.pr&&typeof m.pr=="object"?{number:m.pr.number??null,url:m.pr.url??null,title:m.pr.title??null}:null,actions:Array.isArray(m.actions)&&m.actions.length?m.actions:null,notify:m.notify===!0,status:"open",ts:pe(b),box:b.boxId,agent:b.provider};H.set(m.offerId,v),R.set(m.offerId,v),n.push(v);break}case"pr.exists.answered":{let v=R.get(m.offerId);v&&(v.status=m.choice||"dismiss",H.delete(m.offerId));break}case"box.state.changed":{let v=m.change==="model"?"model-change":m.change;if(!v||v==="cli-update"&&m.status!=="failed")break;let D=bt(b,v);if(v==="model-change"&&(D.to=m.model),v==="node-update"&&D.latest){let J=n.findIndex(ie=>ie.kind==="event"&&ie.type==="node-update"&&ie.latest===D.latest);if(J>=0){let ie=n[J];n[J]={...D,ts:ie.ts,at:ie.at,firstAt:ie.firstAt??ie.ts,updatedAt:D.ts};break}}n.push(D);break}case"track.transferred":case"track.recovered":n.push(bt(b,"track-moved"));break;case"view.state.changed":{if(m.change==="deleted"){k(`view:${m.viewId}`);break}if(m.change!=="created"||m.restarted)break;y(`view:${m.viewId}`,{id:b.id,kind:"view-card",viewId:m.viewId,name:m.name,slug:m.slug,port:m.port,origin:m.origin,ts:pe(b),box:b.boxId,agent:b.provider});break}case"view.spinup.failed":{n.push({id:b.id,kind:"view-spinup-failed",name:m.name||null,reason:m.reason||"no-view",ts:pe(b),box:b.boxId,agent:b.provider});break}case"mock.state.changed":{if(m.change==="picked"){n.push({id:b.id,kind:"mock-picked",mockId:m.mockId,name:m.name,group:m.group??null,version:m.version??null,siblings:m.siblings??[],ts:pe(b),box:b.boxId,agent:b.provider});break}if(m.change==="deleted"){k(`mock:${m.mockId}`);break}if(m.change!=="created")break;y(`mock:${m.mockId}`,{id:b.id,kind:"mock-card",mockId:m.mockId,name:m.name,group:m.group??null,ts:pe(b),box:b.boxId,agent:b.provider});break}case"flow.state.changed":{if(m.change==="deleted"){k(`flow:${m.flowId}`);break}if(m.change!=="created")break;y(`flow:${m.flowId}`,{id:b.id,kind:"flow-card",flowId:m.flowId,name:m.name,stepCount:m.stepCount??null,mockIds:m.mockIds??[],ts:pe(b),box:b.boxId,agent:b.provider});break}case"runbook.state.changed":{if(m.change==="deleted"){k(`runbook:${m.runbookId}`);break}if(m.change!=="created")break;y(`runbook:${m.runbookId}`,{id:b.id,kind:"runbook-card",runbookId:m.runbookId,name:m.name,ts:pe(b),box:b.boxId,agent:b.provider});break}case"ticket.linked":{n.push({id:b.id,kind:"ticket-card",provider:m.provider||"linear",key:m.key,url:m.url,title:m.title??null,linkSource:m.linkSource??null,ts:pe(b),box:b.boxId,agent:b.provider});break}case"box.fullscreen.detected":{if(!m.offerId)break;for(let D of W.values())D.box===(m.box||b.boxId)&&(D.status="stale",W.delete(D.offerId));let v={id:b.id,kind:"fullscreen-offer",offerId:m.offerId,status:"open",ts:pe(b),box:m.box||b.boxId,agent:m.agent||b.provider};W.set(m.offerId,v),B.set(m.offerId,v),n.push(v);break}case"box.fullscreen.answered":{let v=B.get(m.offerId);v&&(v.status=m.action==="restarted"?"restarted":m.action==="cleared"?"cleared":"dismiss",W.delete(m.offerId));break}case"ticket.move.offered":{if(!m.offerId)break;for(let D of A.values())D.key===m.key&&(D.status="stale",A.delete(D.offerId));let v={id:b.id,kind:"ticket-offer",offerId:m.offerId,provider:m.provider||"linear",key:m.key,url:m.url??null,phase:m.phase??null,from:m.from??null,to:m.to?.name??null,prNumber:m.prNumber??null,status:"open",ts:pe(b),box:b.boxId,agent:b.provider};A.set(m.offerId,v),C.set(m.offerId,v),n.push(v);break}case"ticket.move.answered":{let v=C.get(m.offerId);v&&(v.status=m.action==="moved"?"moved":"dismiss",A.delete(m.offerId));break}case"ticket.state.changed":{for(let v of A.values())v.key===m.key&&v.to===m.to&&(v.status="stale",A.delete(v.offerId));if(m.mode==="offer")break;n.push(bt(b,"ticket-state"));break}case"ticket.commented":{n.push({id:b.id,kind:"ticket-comment",key:m.key,url:m.url??null,excerpt:m.excerpt??null,ts:pe(b),box:b.boxId,agent:b.provider});break}case"ticket.flow.changed":n.push(bt(b,"ticket-flow"));break;case"ticket.create.offered":{if(!m.proposalId)break;for(let D of Z.values())D.status="stale";Z.clear();let v={id:b.id,kind:"ticket-create-offer",proposalId:m.proposalId,provider:m.provider||"linear",epic:m.epic??null,issues:Array.isArray(m.issues)?m.issues:[],team:m.team??null,needsTeam:!!m.needsTeam,linkCurrentTrack:!!m.linkCurrentTrack,status:"open",ts:pe(b),box:b.boxId,agent:b.provider};Z.set(m.proposalId,v),xe.set(m.proposalId,v),n.push(v),Ve(v);break}case"ticket.create.answered":{let v=xe.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",v.createdCount=m.createdCount??null,v.failedCount=m.failedCount??null,Z.delete(m.proposalId));break}case"loop.create.offered":{if(!m.proposalId)break;for(let D of Ae.values())D.status="stale";Ae.clear();let v={id:b.id,kind:"loop-create-offer",proposalId:m.proposalId,name:m.name??"",schedule:m.schedule??"",prompt:m.prompt??"",expectation:m.expectation??null,notify:m.notify??"off",assignment:m.assignment??{provider:"claude"},repo:m.repo??null,nodeId:m.nodeId??null,nodeName:m.nodeName??null,status:"open",ts:pe(b),box:b.boxId,agent:b.provider};Ae.set(m.proposalId,v),_e.set(m.proposalId,v),n.push(v),Ve(v);break}case"loop.create.answered":{let v=_e.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",Ae.delete(m.proposalId));break}case"followup.armed":{if(!m.armId)break;let v=m.replaces?Pe.get(m.replaces):null;v&&v.arm.status==="armed"&&ge(v,"replaced");let D={armId:m.armId,seq:Number.isInteger(m.seq)?m.seq:0,label:m.label??"",prompt:m.prompt??"",why:m.why??null,standing:m.standing==="never"?"never":"offerable",status:"armed"},J=m.groupId??null,ie=J?le.get(J):null;ie||(ie={id:b.id,kind:"followup-armed",groupId:J,armId:D.armId,trigger:m.trigger??"now",label:D.label,prompt:D.prompt,why:D.why,planWhy:m.planWhy??null,arms:[],status:"armed",ts:pe(b),box:b.boxId,agent:b.provider},J&&le.set(J,ie),ie.trigger!=="now"&&n.push(ie)),ie.arms.push(D),Pe.set(m.armId,{arm:D,line:ie});break}case"followup.armed.cancelled":{let v=Pe.get(m.armId);v&&v.arm.status==="armed"&&ge(v,"cancelled");break}case"followup.offered":{if(!m.offerId)break;for(let J of Q.values())J.trigger===m.trigger&&(J.status="stale",Q.delete(J.offerId));let v=Array.isArray(m.rows)?m.rows:[];for(let J of v){let ie=J.armId?Pe.get(J.armId):null;ie&&ie.arm.status==="armed"&&ge(ie,"offered")}let D={id:b.id,kind:"followup-offer",offerId:m.offerId,trigger:m.trigger??"now",repo:m.repo??null,context:m.context&&typeof m.context=="object"?m.context:{},groupId:m.groupId??null,why:m.why??null,rows:v.map(J=>({followupId:J.followupId??null,armId:J.armId??null,label:J.label??"",prompt:J.prompt??null,promptPreview:J.promptPreview??null,promptHash:J.promptHash??null,origin:J.origin??"operator",why:J.why??null,groupId:J.groupId??null,seq:Number.isInteger(J.seq)?J.seq:0,standing:J.standing==="never"?"never":"offerable",promotable:J.armId?J.promotable!==!1:!1,promotableReason:J.promotableReason??null,rowStatus:"open"})),status:"open",answer:null,answers:[],ts:pe(b),box:b.boxId,agent:b.provider};Q.set(m.offerId,D),Xe.set(m.offerId,D),n.push(D),D.trigger==="now"&&Ve(D);break}case"followup.answered":{let v=Xe.get(m.offerId);if(!v)break;let D=new Set;m.armId&&D.add(`arm:${m.armId}`),m.followupId&&D.add(`fu:${m.followupId}`);for(let ve of Array.isArray(m.armIds)?m.armIds:[])D.add(`arm:${ve}`);for(let ve of Array.isArray(m.followupIds)?m.followupIds:[])D.add(`fu:${ve}`);let J=m.action==="sent"?"sent":m.action==="removed"?"removed":"dismiss";for(let ve of v.rows){if(ve.rowStatus!=="open")continue;let _t=ve.armId?`arm:${ve.armId}`:`fu:${ve.followupId}`;D.size&&!D.has(_t)||(ve.rowStatus=J)}let ie={followupId:m.followupId??null,armId:m.armId??null,label:m.label??null,promoted:m.promoted??null,revived:m.revived===!0,action:J,batchId:m.batchId??null};v.answers.push(ie),v.answer=ie,v.rows.some(ve=>ve.rowStatus==="open")?v.status="open":(v.status=v.rows.some(ve=>ve.rowStatus==="sent")?"sent":v.rows.some(ve=>ve.rowStatus==="removed")?"removed":"dismiss",Q.delete(m.offerId));break}case"followup.create.offered":{if(!m.proposalId)break;for(let D of Be.values())D.status="stale";Be.clear();let v={id:b.id,kind:"followup-create-offer",proposalId:m.proposalId,label:m.label??"",prompt:m.prompt??"",trigger:m.trigger??"pr.merged",repo:m.repo??null,why:m.why??null,status:"open",created:null,ts:pe(b),box:b.boxId,agent:b.provider};Be.set(m.proposalId,v),Pt.set(m.proposalId,v),n.push(v),Ve(v);break}case"followup.create.answered":{let v=Pt.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",Be.delete(m.proposalId));break}case"followup.created":{let v=m.proposalId?Pt.get(m.proposalId):null;v&&(v.created={followupId:m.followupId??null});break}case"loop.created":{let v=m.proposalId?_e.get(m.proposalId):null;v&&(v.created={loopId:m.loopId??null,nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),n.push(bt(b,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!m.proposalId||!m.loopId)break;for(let J of tt.values())J.loopId===m.loopId&&(J.status="stale",J.staleReason="superseded",tt.delete(J.proposalId));let v=b.type==="loop.update.offered",D={id:b.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:pe(b),box:b.boxId,agent:b.provider};tt.set(m.proposalId,D),wn.set(m.proposalId,D),n.push(D),Ve(D);break}case"loop.update.answered":{let v=wn.get(m.proposalId);v&&(m.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=m.action==="applied"?"applied":"dismiss",tt.delete(m.proposalId));break}case"loop.delete.answered":{let v=wn.get(m.proposalId);v&&(m.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=m.action==="delete"?"deleted":m.action==="pause"?"paused":"keep",tt.delete(m.proposalId));break}case"loop.updated":{let v=m.proposalId?wn.get(m.proposalId):null;v&&(v.applied={changed:Array.isArray(m.changed)?m.changed:[],nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),n.push(bt(b,"loop-updated"));break}case"loop.deleted":n.push(bt(b,"loop-deleted"));break;case"loop.paused":n.push(bt(b,"loop-paused"));break;case"planning.change.offered":{if(!m.proposalId||!Array.isArray(m.ops)||!m.ops.length)break;for(let D of Kt.values())D.status="stale",D.staleReason="superseded",Kt.delete(D.proposalId);let v={id:b.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:pe(b),box:b.boxId,agent:b.provider};Kt.set(m.proposalId,v),ht.set(m.proposalId,v),n.push(v),Ve(v);break}case"planning.change.answered":{let v=ht.get(m.proposalId);v&&(m.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=m.action==="applied"?"applied":"dismiss",Kt.delete(m.proposalId));break}case"planning.changed":{let v=m.proposalId?ht.get(m.proposalId):null;v&&(v.applied={results:Array.isArray(m.results)?m.results:[]}),n.push(bt(b,"planning-changed"));break}case"rework.cause.offered":{if(!m.sha||wt.has(m.sha))break;let v={id:b.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:pe(b),box:b.boxId,agent:b.provider};wt.set(m.sha,v),n.push(v);break}case"rework.cause.answered":{let v=m.sha?wt.get(m.sha):null;v&&(v.status="answered",v.cause=m.cause??null);break}case"rework.cause.retracted":{let v=m.sha?wt.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},D=m.proposalId?xe.get(m.proposalId):null;if(D){D.created=v;break}n.push({id:b.id,kind:"ticket-created",...v,ts:pe(b),box:b.boxId,agent:b.provider});break}case"error":{if(!m.kind)break;n.push(bt(b,m.kind));break}case"provider.error":n.push({...bt(b,"provider-error"),provider:b.provider,box:b.boxId,agent:b.provider});break;case"usage.cap.hit":n.push(bt(b,"usage-cap-hit"));break;case"usage.cap.warning":n.push(bt(b,"usage-cap-warning"));break;case"provider.connected":{n.push({id:b.id,kind:"event",type:"provider-connected",provider:m.provider||b.provider,account:m.account||null,reason:m.reason||null,ts:pe(b),at:pe(b),box:b.boxId,agent:b.provider});break}case"provider.login.started":break;case"prompt.answered":{if(gt=null,m.control||!m.question)break;let v=m.groupId||m.promptId;if(!v)break;let D=at.get(v);D||(D={id:b.id,kind:"prompt",groupId:v,provider:b.provider,box:b.boxId,agent:b.provider,questionTotal:m.questionTotal??1,questions:[],ts:pe(b)},at.set(v,D));let J=m.questionIndex??0,ie={index:J,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:Array.isArray(m.chosen)?m.chosen:[]},ve=D.questions.findIndex(yt=>yt.index===J&&He(yt.question)===He(ie.question));ve>=0?D.questions[ve]=ie:D.questions.push(ie),D.questions.sort((yt,nt)=>yt.index-nt.index),D.questionTotal=Math.max(D.questionTotal,m.questionTotal??1),D.questions.length>=D.questionTotal&&(n.push(D),at.delete(v));break}case"prompt.dismissed":{gt=null;let v=m.groupId||m.promptId;if(!v||!m.question)break;let J=at.get(v)||{id:b.id,kind:"prompt",groupId:v,provider:b.provider,box:b.boxId,agent:b.provider,questionTotal:m.questionTotal??1,questions:[],ts:pe(b)},ie=m.questionIndex??0;J.questions.some(ve=>ve.index===ie&&He(ve.question)===He(m.question))||(J.questions.push({index:ie,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:[]}),J.questions.sort((ve,_t)=>ve.index-_t.index)),J.answeredVia="chat",n.push(J),at.delete(v);break}default:break}}for(let[b,m]of[...we]){if(m==="superseded"){b.status!=="superseded"&&Oe(b,null);continue}(b.status!=="open"||t-(b.ts??0)>=ML)&&Oe(b,null)}let ur=h.size?n.filter(b=>!b.retired):n;return NL(ur.sort((b,m)=>(b.ts??0)-(m.ts??0)))}function NL(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<=CL){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 bh(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:PL(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??Hn(e)).filter(o=>o.kind==="message");return Wx(n,r)}function PL(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==ha(e.command)?t:Qr(e.command,e.description||"")}function bt(e,t){let{ts:n,change:r,kind:o,...s}=e.payload||{};return{id:e.id,kind:"event",type:t,...s,at:pe(e),ts:pe(e)}}function Zv(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)+DL,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&BL.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function Qv(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!jL.has(r.type)||!r.box)continue;let o=(r.ts??0)+LL,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 ud(e){return(e||[]).filter(t=>FL.has(t?.kind)&&t.status==="open")}function eS(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(Yv.has(o.change)&&o.number!=null)Xv(t,n,o);else if(o.change==="merged"||o.change==="closed"||o.change==="lost"){let s=yh(o);if(t.has(s))t.delete(s);else if(o.number!=null)for(let a of[...t.keys()])a.endsWith(`#${o.number}`)&&t.delete(a)}}return[...t.values()]}var pe,Yv,yh,ML,CL,DL,BL,LL,jL,FL,dd=G(()=>{wa();es();Vu();mc();ld();gh();pe=e=>e.payload?.ts??e.ts;Yv=new Set(["opened","ci-fixed","reconciled","pushed"]),yh=e=>`${e.repo??""}#${e.number}`;ML=3e4;CL=2*6e4;DL=12e4,BL=new Set(["archived","unarchived","opened"]);LL=2500,jL=new Set(["pr-opened","pr-merged","pr-auto-armed"]);FL=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 GL(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 VL(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 zL(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<WL&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<qL&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function oS(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=GL(e),s=VL(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=Hn(e??[]).filter(p=>p?.kind==="message"&&typeof p.text=="string"&&p.text.trim()).slice(-UL);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(rS[r]??rS.failover),l.push(""),o.lastPush?.sha){let p=nS(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=nS(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=zL(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"}:** ${KL(p.text,HL)}`),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(`
159
+ `});function ML(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 Xv(e,t,n){let r=yh(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 Hn(e,{now:t=Date.now()}={}){let n=[],r=new Set,o=new Set,s=new Map,a=new Map,i=new Set,c=new Map,l=new Map,u=new Map,d=(b,m)=>{m!=null&&(u.has(b)||u.set(b,[]),u.get(b).push(m))},p=(b,m)=>{let v=null;for(let D of[b,null])for(let J of u.get(D)||[])J>m&&(v==null||J<v)&&(v=J);return v},f=new Set,w=new Map,h=new Map,y=(b,m)=>{h.set(b,m),n.push(m)},k=b=>{let m=h.get(b);m&&(m.retired=!0)},g=/^Agent "([\s\S]+)" finished$/,x=new Map;for(let b of e||[]){if(b.type!=="tool.called"||b.source!=="transcript")continue;let m=String(b.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 D=v[0].split("/").pop().toLowerCase();x.has(D)||x.set(D,[]),x.get(D).push(b.payload?.ts??b.ts)}}let S=3*6e4,_=20*6e4,M=(b,m)=>!!(b?.name&&x.get(String(b.name).toLowerCase()))?.some(D=>D>=m-S&&D<=m+_);for(let b of e||[])if(b.type==="turn.retracted"){o.add(`${b.boxId}|${b.payload?.saidTs}`);let m=He(b.payload?.text);m&&(s.has(b.boxId)||s.set(b.boxId,[]),s.get(b.boxId).push(m))}else if(b.type==="turn.user"&&b.source==="orchestrator"){let m=He(b.payload?.text);m&&(a.has(b.boxId)||a.set(b.boxId,new Set),a.get(b.boxId).add(m))}else if(b.type==="job.stalled"&&b.payload?.id)c.set(b.payload.id,{ts:pe(b),quietMs:Number(b.payload.quietMs)||null});else if(b.type==="job.stopped"&&b.payload?.id)l.has(b.payload.id)||l.set(b.payload.id,{status:"killed",summary:null,resultHead:null,ts:pe(b)});else if(b.type==="session.ready"){let m=b.payload?.source;m!=="compact"&&m!=="clear"&&d(b.boxId??null,pe(b))}else if(b.type==="handoff.done")d(b.boxId??b.payload?.from??null,pe(b));else if(b.type==="box.state.changed"&&b.payload?.change==="archived")d(null,pe(b));else if(b.type==="job.started"&&b.payload?.id)i.add(b.payload.id),(b.payload.kind||"agent")==="agent"&&b.payload.name&&f.add(b.payload.name);else if(b.type==="turn.user"&&b.payload?.note?.kind==="task"){let m=b.payload.note,v={status:m.status||null,summary:m.summary||null,resultHead:m.resultHead??null,ts:pe(b)};m.toolUseId&&l.set(m.toolUseId,v);let D=String(m.summary||"").match(g);D&&w.set(D[1],v)}let P=new Map,j=new Map,A=null,$=new Map,L=new Map,H=new Map,R=new Map,T=new Map,C=new Map,W=new Map,B=new Map,Z=new Map,xe=new Map,Te=new Map,_e=new Map,Q=new Map,Xe=new Map,Pe=new Map,le=new Map,ge=(b,m)=>{b.arm.status=m;let v=b.line,D=v.arms.map(J=>J.status);v.status=D.includes("armed")?"armed":D.includes("offered")?"offered":D.includes("replaced")?"replaced":"cancelled"},de=[],te=new Set,we=new Map,Oe=(b,m)=>{we.delete(b);let v=n.indexOf(b);v>=0&&n.splice(v,1),m!=null&&(b.ts=m),n.push(b)},Ve=b=>{if(de.push(b),!(b.box?te.has(b.box):te.size>0))return;let v=n.indexOf(b);v>=0&&n.splice(v,1),we.set(b,"held")},Nt=b=>{if(!de.length)return;let m=pe(b);for(let v of de)v.status!=="open"||we.get(v)==="superseded"||v.box&&v.box!==b.boxId||(v.ts??0)>m||Oe(v,m)},O=b=>{if(!de.length)return;let m=pe(b);for(let v of de)we.get(v)!=="held"||v.status!=="open"||v.box&&b.boxId&&v.box!==b.boxId||Oe(v,Math.max(v.ts??0,m))},X=()=>{for(let[b,m]of[...we])m==="held"&&Oe(b,null);de.length=0,re.clear()},re=new Set,he=b=>{for(let m of re){if(m.status!=="open"||m.box&&b&&m.box!==b)continue;m.status="superseded";let v=n.indexOf(m);v>=0&&n.splice(v,1),we.set(m,"superseded"),$.delete(m.offerId)}re.clear()},Be=new Map,Pt=new Map,tt=new Map,wn=new Map,Kt=new Map,ht=new Map,wt=new Map,at=new Map,Ai=()=>{for(let b of at.values())b.questions.length&&n.push(b);at.clear()},gt=null,cr=new Map,Hr=6e4,lr=new Map,gn=(b,m)=>{let v=s.get(b);if(!v?.length)return!1;let D=He(m),J=a.get(b);return v.some(ie=>{if(!D.startsWith(ie))return!1;let ve=He(D.slice(ie.length));return!!ve&&!!J?.has(ve)})};for(let b of e||[]){let m=b.payload||{};switch(b.type){case"turn.user":{if(b.source==="hook"){b.boxId&&te.add(b.boxId);break}if(X(),!String(m.text||"").trim()&&!m.images?.length&&!m.attachments?.length)break;{let v=Wv(m.text);if(v){if(v.kind==="shell-input"){let D={id:b.id,kind:"shell",command:v.command,stdout:null,stderr:null,done:!1,ts:pe(b),box:b.boxId,agent:b.provider};n.push(D),cr.set(b.boxId,D)}else{let D=cr.get(b.boxId);D?(D.stdout=v.stdout||null,D.stderr=v.stderr||null,D.done=!0,cr.delete(b.boxId)):n.push({id:b.id,kind:"shell",command:null,stdout:v.stdout||null,stderr:v.stderr||null,done:!0,ts:pe(b),box:b.boxId,agent:b.provider})}break}}{let v=m.note||kc(m.text);if(v){if(v.kind==="task"){if(v.toolUseId&&i.has(v.toolUseId))break;let D=String(v.summary||"").match(g);if(!v.toolUseId&&D&&f.has(D[1]))break}if(v.kind==="command"&&Uv(v.command))break;if(v.kind==="resume-summary"){n.push({id:b.id,kind:"resume-summary",title:v.title||"Context resumed from summary",bullets:v.bullets||[],sections:v.sections||[],rawChars:v.rawChars??null,ts:pe(b),box:b.boxId,agent:b.provider});break}v.kind!=="suppress"&&n.push({id:b.id,kind:"event",type:Gv(v),name:v.name??null,command:v.command??null,summary:v.summary??null,status:v.status??null,ts:pe(b),box:b.boxId,agent:b.provider});break}}if(o.has(`${b.boxId}|${pe(b)}`)||b.source==="transcript"&&gn(b.boxId,m.text))break;if(m.kind==="merge-notify"||m.kind==="ship-notify"){n.push({id:b.id,kind:"event",type:m.kind==="ship-notify"?"ship-notified":"merge-notified",text:m.text,ts:pe(b),box:b.boxId,agent:b.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==="login-greet"){m.kind==="prompt-answer"&&(gt=null);break}for(let v of $.values())v.status="stale";$.clear();for(let v of H.values())v.status="stale";H.clear();for(let v of Q.values())v.rows.some(D=>D.rowStatus==="sent")||(v.status="stale",Q.delete(v.offerId));gt&&gt.box===b.boxId&&(n.push(ML(gt)),gt=null),n.push({id:b.id,kind:"message",role:"user",text:m.text,ts:pe(b),box:b.boxId,agent:b.provider,boxRole:m.boxRole,...b.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||{};n.push({id:b.id,kind:"event",type:"peer-message",text:m.text,from:v.trackName||v.boxId||v.name||null,fromTrackId:v.trackId||null,ts:pe(b),box:b.boxId,agent:b.provider});break}case"turn.agent":{if(m.model==="<synthetic>"&&/^No response requested\.$/.test(String(m.text||"").trim()))break;let v=Xx(m,{codexFailedText:Qo});if(v){n.push({id:b.id,kind:"event",type:"provider-error",cls:v.cls,status:v.status??void 0,text:v.text,provider:b.provider,legacy:!0,at:pe(b),ts:pe(b),box:b.boxId,agent:b.provider});break}Ai();let D=(m.images||[]).filter(yt=>!M(yt,pe(b)));if(b.source==="hook"&&!String(m.text||"").trim()&&(O(b),b.boxId&&te.delete(b.boxId)),!String(m.text||"").trim()&&!D.length)break;if(b.provider==="cursor"){let yt=`${b.boxId}|${m.text}`;if(r.has(yt))break;r.add(yt)}(!gt||gt.box===b.boxId)&&(gt=null);let J=b.provider==="codex"?(m.tools||[]).filter(yt=>!th.has(yt)&&!sc.has(yt)):m.tools||[],ie=m.text,ve=null,_t=mh(String(m.text||""));_t&&(ie=_t.text,ve={questions:_t.questions}),n.push({id:b.id,kind:"message",role:"assistant",text:ie,ts:pe(b),box:b.boxId,agent:b.provider,boxRole:m.boxRole,...ve?{ask:ve}:{},...J.length?{tools:J}:{},...m.model?{model:m.model}:{},...m.sourceId?{sourceId:m.sourceId}:{},...D.length?{images:D}:{}}),Nt(b),ve&&(gt={id:b.id,groupId:hh(b.provider,m.sourceId||b.id,ve.questions),provider:b.provider,box:b.boxId,questions:ve.questions,ts:pe(b)});break}case"job.started":{if(!m.id)break;let v=pe(b),D=l.get(m.id);if(!D&&(m.kind||"agent")==="agent"&&m.name){let rn=w.get(m.name);rn&&rn.ts>=v&&(D=rn)}let J=D?null:c.get(m.id)||null,ie=D||J?null:p(b.boxId??null,v),ve={jobId:m.id,jobKind:m.kind||"agent",name:m.name||null,detail:m.detail||null,status:D?D.status==="killed"?"stopped":D.status&&D.status!=="completed"?"failed":"done":J?"stalled":ie!=null?"lost":"running",startedTs:v,finishedTs:D?.ts??J?.ts??ie??null,quietMs:J?.quietMs??null,summary:D?.summary??null,resultHead:D?.resultHead??null},_t=lr.get(b.boxId),yt=_t?.jobs[_t.jobs.length-1]?.startedTs;if(_t&&yt!=null&&v-yt<=Hr)_t.jobs.push(ve);else{let rn={id:b.id,kind:"job-dock",dockId:m.id,ts:v,box:b.boxId,agent:b.provider,jobs:[ve]};lr.set(b.boxId,rn),n.push(rn)}break}case"handoff.done":n.push(bt(b,"lead-handoff"));break;case"subtask.delegated":n.push({...bt(b,"subtask-delegated"),to:b.boxId,toAgent:b.provider});break;case"subtask.merged":n.push(bt(b,"subtask-merged"));break;case"pr.state.changed":{if(!m.change)break;if(m.change==="opened"){for(let D of $.values())D.status="stale";$.clear();for(let D of H.values())D.status="stale";H.clear()}let v=bt(b,`pr-${m.change}`);if(v.box=b.boxId??null,Yv.has(m.change)&&m.number!=null){let D=Xv(P,j,m);if(P.size>=2){for(let ie of j.values())for(let ve of ie)ve.grouped=!0;v.groupPrs=[...P.values()];let J=[v];for(let ie of P.keys())j.set(ie,J)}else{let J=j.get(D)??[];J.push(v),j.set(D,J)}}else if(m.change==="merged"||m.change==="closed"||m.change==="lost"){let D=yh(m),J=A&&!A.complete||P.size>=2;if(P.has(D))P.delete(D),j.delete(D);else if(m.number!=null)for(let ie of[...P.keys()])ie.endsWith(`#${m.number}`)&&(P.delete(ie),j.delete(ie));if(J&&m.number!=null){(!A||A.complete)&&(A={id:b.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:pe(b),ts:pe(b),box:b.boxId,agent:b.provider},n.push(A)),A.prs.push({number:m.number,url:m.url??null,title:m.title??null,repo:m.repo??null,branch:m.branch??null,change:m.change,ts:pe(b)}),A.remaining=[...P.values()],A.complete=P.size===0;break}}n.push(v);break}case"pr.offered":{if(!m.offerId)break;he(b.boxId);for(let D of $.values())D.status="stale";$.clear();for(let D of H.values())D.status="stale";H.clear();let v={id:b.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:b.source==="cli"||m.via==="cli"?"cli":"transcript",ts:pe(b),box:b.boxId,agent:b.provider};$.set(m.offerId,v),L.set(m.offerId,v),n.push(v),re.add(v),v.source==="cli"&&Ve(v);break}case"pr.offer.answered":{let v=L.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}),$.delete(m.offerId));break}case"pr.exists.offered":{if(!m.offerId)break;for(let D of H.values())D.status="stale";H.clear();let v={id:b.id,kind:"pr-exists-offer",offerId:m.offerId,srcOfferId:m.srcOfferId??null,branch:m.branch||null,base:m.base||null,pr:m.pr&&typeof m.pr=="object"?{number:m.pr.number??null,url:m.pr.url??null,title:m.pr.title??null}:null,actions:Array.isArray(m.actions)&&m.actions.length?m.actions:null,notify:m.notify===!0,status:"open",ts:pe(b),box:b.boxId,agent:b.provider};H.set(m.offerId,v),R.set(m.offerId,v),n.push(v);break}case"pr.exists.answered":{let v=R.get(m.offerId);v&&(v.status=m.choice||"dismiss",H.delete(m.offerId));break}case"box.state.changed":{let v=m.change==="model"?"model-change":m.change;if(!v||v==="cli-update"&&m.status!=="failed")break;let D=bt(b,v);if(v==="model-change"&&(D.to=m.model),v==="node-update"&&D.latest){let J=n.findIndex(ie=>ie.kind==="event"&&ie.type==="node-update"&&ie.latest===D.latest);if(J>=0){let ie=n[J];n[J]={...D,ts:ie.ts,at:ie.at,firstAt:ie.firstAt??ie.ts,updatedAt:D.ts};break}}n.push(D);break}case"track.transferred":case"track.recovered":n.push(bt(b,"track-moved"));break;case"view.state.changed":{if(m.change==="deleted"){k(`view:${m.viewId}`);break}if(m.change!=="created"||m.restarted)break;y(`view:${m.viewId}`,{id:b.id,kind:"view-card",viewId:m.viewId,name:m.name,slug:m.slug,port:m.port,origin:m.origin,ts:pe(b),box:b.boxId,agent:b.provider});break}case"view.spinup.failed":{n.push({id:b.id,kind:"view-spinup-failed",name:m.name||null,reason:m.reason||"no-view",ts:pe(b),box:b.boxId,agent:b.provider});break}case"mock.state.changed":{if(m.change==="picked"){n.push({id:b.id,kind:"mock-picked",mockId:m.mockId,name:m.name,group:m.group??null,version:m.version??null,siblings:m.siblings??[],ts:pe(b),box:b.boxId,agent:b.provider});break}if(m.change==="deleted"){k(`mock:${m.mockId}`);break}if(m.change!=="created")break;y(`mock:${m.mockId}`,{id:b.id,kind:"mock-card",mockId:m.mockId,name:m.name,group:m.group??null,ts:pe(b),box:b.boxId,agent:b.provider});break}case"flow.state.changed":{if(m.change==="deleted"){k(`flow:${m.flowId}`);break}if(m.change!=="created")break;y(`flow:${m.flowId}`,{id:b.id,kind:"flow-card",flowId:m.flowId,name:m.name,stepCount:m.stepCount??null,mockIds:m.mockIds??[],ts:pe(b),box:b.boxId,agent:b.provider});break}case"runbook.state.changed":{if(m.change==="deleted"){k(`runbook:${m.runbookId}`);break}if(m.change!=="created")break;y(`runbook:${m.runbookId}`,{id:b.id,kind:"runbook-card",runbookId:m.runbookId,name:m.name,ts:pe(b),box:b.boxId,agent:b.provider});break}case"ticket.linked":{n.push({id:b.id,kind:"ticket-card",provider:m.provider||"linear",key:m.key,url:m.url,title:m.title??null,linkSource:m.linkSource??null,ts:pe(b),box:b.boxId,agent:b.provider});break}case"box.fullscreen.detected":{if(!m.offerId)break;for(let D of W.values())D.box===(m.box||b.boxId)&&(D.status="stale",W.delete(D.offerId));let v={id:b.id,kind:"fullscreen-offer",offerId:m.offerId,status:"open",ts:pe(b),box:m.box||b.boxId,agent:m.agent||b.provider};W.set(m.offerId,v),B.set(m.offerId,v),n.push(v);break}case"box.fullscreen.answered":{let v=B.get(m.offerId);v&&(v.status=m.action==="restarted"?"restarted":m.action==="cleared"?"cleared":"dismiss",W.delete(m.offerId));break}case"ticket.move.offered":{if(!m.offerId)break;for(let D of T.values())D.key===m.key&&(D.status="stale",T.delete(D.offerId));let v={id:b.id,kind:"ticket-offer",offerId:m.offerId,provider:m.provider||"linear",key:m.key,url:m.url??null,phase:m.phase??null,from:m.from??null,to:m.to?.name??null,prNumber:m.prNumber??null,status:"open",ts:pe(b),box:b.boxId,agent:b.provider};T.set(m.offerId,v),C.set(m.offerId,v),n.push(v);break}case"ticket.move.answered":{let v=C.get(m.offerId);v&&(v.status=m.action==="moved"?"moved":"dismiss",T.delete(m.offerId));break}case"ticket.state.changed":{for(let v of T.values())v.key===m.key&&v.to===m.to&&(v.status="stale",T.delete(v.offerId));if(m.mode==="offer")break;n.push(bt(b,"ticket-state"));break}case"ticket.commented":{n.push({id:b.id,kind:"ticket-comment",key:m.key,url:m.url??null,excerpt:m.excerpt??null,ts:pe(b),box:b.boxId,agent:b.provider});break}case"ticket.flow.changed":n.push(bt(b,"ticket-flow"));break;case"ticket.create.offered":{if(!m.proposalId)break;for(let D of Z.values())D.status="stale";Z.clear();let v={id:b.id,kind:"ticket-create-offer",proposalId:m.proposalId,provider:m.provider||"linear",epic:m.epic??null,issues:Array.isArray(m.issues)?m.issues:[],team:m.team??null,needsTeam:!!m.needsTeam,linkCurrentTrack:!!m.linkCurrentTrack,status:"open",ts:pe(b),box:b.boxId,agent:b.provider};Z.set(m.proposalId,v),xe.set(m.proposalId,v),n.push(v),Ve(v);break}case"ticket.create.answered":{let v=xe.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",v.createdCount=m.createdCount??null,v.failedCount=m.failedCount??null,Z.delete(m.proposalId));break}case"loop.create.offered":{if(!m.proposalId)break;for(let D of Te.values())D.status="stale";Te.clear();let v={id:b.id,kind:"loop-create-offer",proposalId:m.proposalId,name:m.name??"",schedule:m.schedule??"",prompt:m.prompt??"",expectation:m.expectation??null,notify:m.notify??"off",assignment:m.assignment??{provider:"claude"},repo:m.repo??null,nodeId:m.nodeId??null,nodeName:m.nodeName??null,status:"open",ts:pe(b),box:b.boxId,agent:b.provider};Te.set(m.proposalId,v),_e.set(m.proposalId,v),n.push(v),Ve(v);break}case"loop.create.answered":{let v=_e.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",Te.delete(m.proposalId));break}case"followup.armed":{if(!m.armId)break;let v=m.replaces?Pe.get(m.replaces):null;v&&v.arm.status==="armed"&&ge(v,"replaced");let D={armId:m.armId,seq:Number.isInteger(m.seq)?m.seq:0,label:m.label??"",prompt:m.prompt??"",why:m.why??null,standing:m.standing==="never"?"never":"offerable",status:"armed"},J=m.groupId??null,ie=J?le.get(J):null;ie||(ie={id:b.id,kind:"followup-armed",groupId:J,armId:D.armId,trigger:m.trigger??"now",label:D.label,prompt:D.prompt,why:D.why,planWhy:m.planWhy??null,arms:[],status:"armed",ts:pe(b),box:b.boxId,agent:b.provider},J&&le.set(J,ie),ie.trigger!=="now"&&n.push(ie)),ie.arms.push(D),Pe.set(m.armId,{arm:D,line:ie});break}case"followup.armed.cancelled":{let v=Pe.get(m.armId);v&&v.arm.status==="armed"&&ge(v,"cancelled");break}case"followup.offered":{if(!m.offerId)break;for(let J of Q.values())J.trigger===m.trigger&&(J.status="stale",Q.delete(J.offerId));let v=Array.isArray(m.rows)?m.rows:[];for(let J of v){let ie=J.armId?Pe.get(J.armId):null;ie&&ie.arm.status==="armed"&&ge(ie,"offered")}let D={id:b.id,kind:"followup-offer",offerId:m.offerId,trigger:m.trigger??"now",repo:m.repo??null,context:m.context&&typeof m.context=="object"?m.context:{},groupId:m.groupId??null,why:m.why??null,rows:v.map(J=>({followupId:J.followupId??null,armId:J.armId??null,label:J.label??"",prompt:J.prompt??null,promptPreview:J.promptPreview??null,promptHash:J.promptHash??null,origin:J.origin??"operator",why:J.why??null,groupId:J.groupId??null,seq:Number.isInteger(J.seq)?J.seq:0,standing:J.standing==="never"?"never":"offerable",promotable:J.armId?J.promotable!==!1:!1,promotableReason:J.promotableReason??null,rowStatus:"open"})),status:"open",answer:null,answers:[],ts:pe(b),box:b.boxId,agent:b.provider};Q.set(m.offerId,D),Xe.set(m.offerId,D),n.push(D),D.trigger==="now"&&Ve(D);break}case"followup.answered":{let v=Xe.get(m.offerId);if(!v)break;let D=new Set;m.armId&&D.add(`arm:${m.armId}`),m.followupId&&D.add(`fu:${m.followupId}`);for(let ve of Array.isArray(m.armIds)?m.armIds:[])D.add(`arm:${ve}`);for(let ve of Array.isArray(m.followupIds)?m.followupIds:[])D.add(`fu:${ve}`);let J=m.action==="sent"?"sent":m.action==="removed"?"removed":"dismiss";for(let ve of v.rows){if(ve.rowStatus!=="open")continue;let _t=ve.armId?`arm:${ve.armId}`:`fu:${ve.followupId}`;D.size&&!D.has(_t)||(ve.rowStatus=J)}let ie={followupId:m.followupId??null,armId:m.armId??null,label:m.label??null,promoted:m.promoted??null,revived:m.revived===!0,action:J,batchId:m.batchId??null};v.answers.push(ie),v.answer=ie,v.rows.some(ve=>ve.rowStatus==="open")?v.status="open":(v.status=v.rows.some(ve=>ve.rowStatus==="sent")?"sent":v.rows.some(ve=>ve.rowStatus==="removed")?"removed":"dismiss",Q.delete(m.offerId));break}case"followup.create.offered":{if(!m.proposalId)break;for(let D of Be.values())D.status="stale";Be.clear();let v={id:b.id,kind:"followup-create-offer",proposalId:m.proposalId,label:m.label??"",prompt:m.prompt??"",trigger:m.trigger??"pr.merged",repo:m.repo??null,why:m.why??null,status:"open",created:null,ts:pe(b),box:b.boxId,agent:b.provider};Be.set(m.proposalId,v),Pt.set(m.proposalId,v),n.push(v),Ve(v);break}case"followup.create.answered":{let v=Pt.get(m.proposalId);v&&(v.status=m.action==="created"?"created":"dismiss",Be.delete(m.proposalId));break}case"followup.created":{let v=m.proposalId?Pt.get(m.proposalId):null;v&&(v.created={followupId:m.followupId??null});break}case"loop.created":{let v=m.proposalId?_e.get(m.proposalId):null;v&&(v.created={loopId:m.loopId??null,nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),n.push(bt(b,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!m.proposalId||!m.loopId)break;for(let J of tt.values())J.loopId===m.loopId&&(J.status="stale",J.staleReason="superseded",tt.delete(J.proposalId));let v=b.type==="loop.update.offered",D={id:b.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:pe(b),box:b.boxId,agent:b.provider};tt.set(m.proposalId,D),wn.set(m.proposalId,D),n.push(D),Ve(D);break}case"loop.update.answered":{let v=wn.get(m.proposalId);v&&(m.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=m.action==="applied"?"applied":"dismiss",tt.delete(m.proposalId));break}case"loop.delete.answered":{let v=wn.get(m.proposalId);v&&(m.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=m.action==="delete"?"deleted":m.action==="pause"?"paused":"keep",tt.delete(m.proposalId));break}case"loop.updated":{let v=m.proposalId?wn.get(m.proposalId):null;v&&(v.applied={changed:Array.isArray(m.changed)?m.changed:[],nextFireAt:Number.isFinite(Number(m.nextFireAt))?Number(m.nextFireAt):null}),n.push(bt(b,"loop-updated"));break}case"loop.deleted":n.push(bt(b,"loop-deleted"));break;case"loop.paused":n.push(bt(b,"loop-paused"));break;case"planning.change.offered":{if(!m.proposalId||!Array.isArray(m.ops)||!m.ops.length)break;for(let D of Kt.values())D.status="stale",D.staleReason="superseded",Kt.delete(D.proposalId);let v={id:b.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:pe(b),box:b.boxId,agent:b.provider};Kt.set(m.proposalId,v),ht.set(m.proposalId,v),n.push(v),Ve(v);break}case"planning.change.answered":{let v=ht.get(m.proposalId);v&&(m.action==="moved"?(v.status="stale",v.staleReason="moved"):v.status=m.action==="applied"?"applied":"dismiss",Kt.delete(m.proposalId));break}case"planning.changed":{let v=m.proposalId?ht.get(m.proposalId):null;v&&(v.applied={results:Array.isArray(m.results)?m.results:[]}),n.push(bt(b,"planning-changed"));break}case"rework.cause.offered":{if(!m.sha||wt.has(m.sha))break;let v={id:b.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:pe(b),box:b.boxId,agent:b.provider};wt.set(m.sha,v),n.push(v);break}case"rework.cause.answered":{let v=m.sha?wt.get(m.sha):null;v&&(v.status="answered",v.cause=m.cause??null);break}case"rework.cause.retracted":{let v=m.sha?wt.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},D=m.proposalId?xe.get(m.proposalId):null;if(D){D.created=v;break}n.push({id:b.id,kind:"ticket-created",...v,ts:pe(b),box:b.boxId,agent:b.provider});break}case"error":{if(!m.kind)break;n.push(bt(b,m.kind));break}case"provider.error":n.push({...bt(b,"provider-error"),provider:b.provider,box:b.boxId,agent:b.provider});break;case"usage.cap.hit":n.push(bt(b,"usage-cap-hit"));break;case"usage.cap.warning":n.push(bt(b,"usage-cap-warning"));break;case"provider.connected":{n.push({id:b.id,kind:"event",type:"provider-connected",provider:m.provider||b.provider,account:m.account||null,reason:m.reason||null,ts:pe(b),at:pe(b),box:b.boxId,agent:b.provider});break}case"provider.login.started":break;case"prompt.answered":{if(gt=null,m.control||!m.question)break;let v=m.groupId||m.promptId;if(!v)break;let D=at.get(v);D||(D={id:b.id,kind:"prompt",groupId:v,provider:b.provider,box:b.boxId,agent:b.provider,questionTotal:m.questionTotal??1,questions:[],ts:pe(b)},at.set(v,D));let J=m.questionIndex??0,ie={index:J,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:Array.isArray(m.chosen)?m.chosen:[]},ve=D.questions.findIndex(yt=>yt.index===J&&He(yt.question)===He(ie.question));ve>=0?D.questions[ve]=ie:D.questions.push(ie),D.questions.sort((yt,nt)=>yt.index-nt.index),D.questionTotal=Math.max(D.questionTotal,m.questionTotal??1),D.questions.length>=D.questionTotal&&(n.push(D),at.delete(v));break}case"prompt.dismissed":{gt=null;let v=m.groupId||m.promptId;if(!v||!m.question)break;let J=at.get(v)||{id:b.id,kind:"prompt",groupId:v,provider:b.provider,box:b.boxId,agent:b.provider,questionTotal:m.questionTotal??1,questions:[],ts:pe(b)},ie=m.questionIndex??0;J.questions.some(ve=>ve.index===ie&&He(ve.question)===He(m.question))||(J.questions.push({index:ie,header:m.header||"",question:m.question,multiSelect:!!m.multiSelect,chosen:[]}),J.questions.sort((ve,_t)=>ve.index-_t.index)),J.answeredVia="chat",n.push(J),at.delete(v);break}default:break}}for(let[b,m]of[...we]){if(m==="superseded"){b.status!=="superseded"&&Oe(b,null);continue}(b.status!=="open"||t-(b.ts??0)>=CL)&&Oe(b,null)}let ur=h.size?n.filter(b=>!b.retired):n;return PL(ur.sort((b,m)=>(b.ts??0)-(m.ts??0)))}function PL(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<=NL){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 bh(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:DL(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??Hn(e)).filter(o=>o.kind==="message");return Wx(n,r)}function DL(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==ha(e.command)?t:Qr(e.command,e.description||"")}function bt(e,t){let{ts:n,change:r,kind:o,...s}=e.payload||{};return{id:e.id,kind:"event",type:t,...s,at:pe(e),ts:pe(e)}}function Zv(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)+BL,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&LL.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function Qv(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!FL.has(r.type)||!r.box)continue;let o=(r.ts??0)+jL,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 dd(e){return(e||[]).filter(t=>UL.has(t?.kind)&&t.status==="open")}function eS(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(Yv.has(o.change)&&o.number!=null)Xv(t,n,o);else if(o.change==="merged"||o.change==="closed"||o.change==="lost"){let s=yh(o);if(t.has(s))t.delete(s);else if(o.number!=null)for(let a of[...t.keys()])a.endsWith(`#${o.number}`)&&t.delete(a)}}return[...t.values()]}var pe,Yv,yh,CL,NL,BL,LL,jL,FL,UL,pd=G(()=>{wa();es();Vu();mc();ud();gh();pe=e=>e.payload?.ts??e.ts;Yv=new Set(["opened","ci-fixed","reconciled","pushed"]),yh=e=>`${e.repo??""}#${e.number}`;CL=3e4;NL=2*6e4;BL=12e4,LL=new Set(["archived","unarchived","opened"]);jL=2500,FL=new Set(["pr-opened","pr-merged","pr-auto-armed"]);UL=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 KL(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 zL(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 JL(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<qL&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<GL&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function oS(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=KL(e),s=zL(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=Hn(e??[]).filter(p=>p?.kind==="message"&&typeof p.text=="string"&&p.text.trim()).slice(-HL);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(rS[r]??rS.failover),l.push(""),o.lastPush?.sha){let p=nS(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=nS(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=JL(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"}:** ${VL(p.text,WL)}`),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(`
160
160
  `);return d.length<=tS?d:`${d.slice(0,tS)}
161
161
 
162
- [\u2026 brief truncated]`}var UL,HL,tS,WL,qL,KL,nS,rS,sS=G(()=>{dd();UL=12,HL=2e3,tS=48e3,WL=30,qL=10;KL=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},nS=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;rS={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."}});function ro(e){let t=e.search(Sh);return(t>=0?e.slice(0,t):e).trim()}function JL(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function YL(e){let t=String(e).trim();return!!(!t||no.test(e)||Sh.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function XL(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=ZL(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function ZL(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 aS(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function QL(e,t=""){let n=String(e);if(!lS.test(n))return null;let r=n.replace(/\r/g,"").split(`
163
- `),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(ss);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&&!no.test(r[u])&&a.push(p)}}if(s.length<2)return null;let i=s.map(u=>({label:ro(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 tj(e,t=""){let n=String(e).replace(/\r/g,"").split(`
164
- `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!uS.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(ss);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&&!(ej.test(n[c])||no.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:ro(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 nj(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
165
- `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(ss);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 oj(e,t=""){let n=String(e);if(!kh.test(n))return null;let r=n.replace(/\r/g,"").split(`
166
- `),o=-1;for(let u=r.length-1;u>=0;u--)if(rj.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(ss);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&&!no.test(r[u])&&a.push(p)}}if(s.length<2||!s.some(u=>kh.test(u.label)))return null;let i=s.map(u=>({label:ro(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 Ah(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(ss);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 sj(e,t=""){let n=String(e);if(!dS.test(n)||!pS.test(n)||as.test(n))return null;let r=n.replace(/\r/g,"").split(`
167
- `),o=Ah(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:ro(s.label),description:""}))}]}:null}function aj(e,t=""){let n=String(e);if(!fS.test(n)||as.test(n))return null;let r=n.replace(/\r/g,"").split(`
168
- `),o=Ah(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:ro(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 cj(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!ij.test(o)||Th.test(e[r]))break;n+=o}return n}function lj(e,t=""){let n=String(e);if(!Th.test(n)||as.test(n))return null;let r=n.replace(/\r/g,"").split(`
169
- `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=cj(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 dj(e,t=""){let n=String(e);if(!xh.test(n)||!uj.test(n)||as.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
170
- `)].reverse().find(a=>xh.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 pj(e,t=""){let n=String(e);if(!mS.test(n)||as.test(n))return null;let r=n.replace(/\r/g,"").split(`
171
- `),o=r.flatMap(a=>{let i=a.match(/^\s*(❯\s*)?(Yes, I trust this folder|No, exit)\s*$/);return i?[{cursor:!!i[1],label:i[2]}]:[]}),s=o.length===2&&new Set(o.map(a=>a.label)).size===2&&o.filter(a=>a.cursor).length===1?o:Ah(r);return s?{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,s.findIndex(a=>a.cursor)),setup:"trust",promptId:`claude:setup:trust:${s.map(a=>a.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:s.map(a=>({label:ro(a.label),description:""}))}]}:null}function fj(e,t=""){let n=String(e);if(as.test(n))return null;let r=n.replace(/\r/g,"").split(`
172
- `),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(hS);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(no.test(r[l])||Sh.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 mj(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(vh.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 hj(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(pd.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&&(no.test(o)||cS.test(o))?r:null}function wj(e,t){if(!e)return null;for(let n=e.line+1;n<Math.min(t.length,e.line+3);n++){let r=t[n],o=r.replace(/^\s*❯/,"").trim();if(o)return cS.test(o)?{cursor:/^\s*❯/.test(r)}:null}return null}function gj(e,t=""){let n=String(e);if(!iS.test(n)||!vh.test(n))return null;let r=n.replace(/\r/g,"").split(`
173
- `),o=mj(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let L=i;L<c;L++){let H=r[L].match(ss);H&&(u<0&&(u=L),l.push({line:L,cursor:!!H[1],checked:H[3]!=null&&H[3]!==" ",hasCheckbox:H[3]!=null,label:H[4].trim(),desc:""}))}if(!l.length)return null;for(let L of l)for(let H=L.line+1;H<Math.min(r.length,L.line+4)&&!(ss.test(r[H])||no.test(r[H]));H++){let R=r[H].trim();if(!(!R||YL(r[H])||pd.test(R))){L.desc=JL(R);break}}let d=hj(l,r),p=l.filter(L=>L!==d&&!pd.test(L.label));if(!p.length)return null;let f=p.some(L=>L.hasCheckbox),w=f?wj(d,r):null,h=w?.cursor?p.length+1:d?.cursor?p.length:Math.max(0,p.findIndex(L=>L.cursor)),y=d&&!pd.test(d.label)?ro(d.label):"",k=s>=0?s+1:0,g=[];for(let L=k;L<u;L++){let H=r[L].trim();H&&!no.test(r[L])&&!/[☐☒]/.test(r[L])&&g.push(H)}let x=g.join(" ")||(s>=0?aS(r[s]):"")||"The agent is asking a question",S=s>=0?XL(r[s],x):null,_=S?.currentTabLabel||(s>=0?aS(r[s]):""),M=p.map(L=>({label:ro(L.label),description:L.desc,...f?{checked:!!L.checked}:{}})),P=M.map(L=>L.label).join("|"),T=`claude:${S?`q${S.questionIndex+1}/${S.questionTotal}`:"q1/1"}:${_}:${x}:${P}`.slice(0,240),$=S?`claude:ask:${S.tabs.map(L=>L.label).join("|")}`.slice(0,240):T;return{provider:"claude",box:t,multiSelect:f,cursorIndex:h,promptId:T,groupId:$,...d?{custom:!0,customIndex:p.length,customText:y}:{},...w?{commitIndex:p.length+1}:{},dismissable:!0,...S?{questionIndex:S.questionIndex,questionTotal:S.questionTotal,currentTabLabel:S.currentTabLabel,tabs:S.tabs}:{},questions:[{question:x,header:_,multiSelect:f,options:M}]}}function oo(e,t){let n=String(t||"");return n?e==="claude"?iS.test(n)&&vh.test(n)||lS.test(n)||kh.test(n)||uS.test(n.trimEnd().split(`
174
- `).pop()||"")?!0:as.test(n)?!1:dS.test(n)&&pS.test(n)||fS.test(n)||Th.test(n)||xh.test(n)||mS.test(n)||hS.test(n.trimEnd().split(`
175
- `).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 Sn(e,t){return!e||!t?null:e.agent==="claude"?nj(t,e.name)||gj(t,e.name)||QL(t,e.name)||oj(t,e.name)||dj(t,e.name)||lj(t,e.name)||aj(t,e.name)||sj(t,e.name)||pj(t,e.name)||fj(t,e.name)||tj(t,e.name):e.agent==="cursor"||e.agent==="codex"?ov(e.agent,t,e.name):null}async function wS(e){if(!e)return null;let t=await Jt(e.name).catch(()=>"");return Sn(e,t)}function Eh(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 gS(e,n))s.push(...o(a,i),"Enter"),a=i;Number.isInteger(e.commitIndex)?s.push(...o(a,e.commitIndex),"Enter"):s.push("Tab","Enter")}else{let a=n.length?n[0]:0;s.push(...o(r,a),"Enter")}return s}function gS(e,t){let n=e?.questions?.[0]?.options||[],r=new Set(t),o=Math.max(n.length,t.length?Math.max(...t)+1:0),s=[];for(let a=0;a<o;a++)!!n[a]?.checked!==r.has(a)&&s.push(a);return s}function yS(e,t,n=""){let r=typeof n=="string"?n.trim():"";if(!r||!e?.custom)return{pre:Eh(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 gS(e,o))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 bS(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 iS,vh,ss,pd,cS,no,Sh,lS,uS,ej,kh,rj,as,dS,pS,fS,Th,ij,xh,uj,mS,hS,_h=G(()=>{dt();Ju();iS=/to navigate\b.*\bEsc to cancel|Enter to select\b/,vh=/Chat about this/i,ss=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,pd=/^(type something|chat about this|submit|next)\b/i,cS=/^(submit|next)\b/i,no=/^[─—-]{6,}\s*$/,Sh=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;lS=/^\s*Switch model\?\s*$/m;uS=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,ej=/^\s*[─—▔-]{6,}\s*$/;kh=/Resume from summary/i,rj=/^\s*This session is\b/;as=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;dS=/Choose the text style that looks best with your terminal/,pS=/Let's get started\./;fS=/Select login method:/;Th=/Paste code here if prompted/,ij=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;xh=/OAuth error:/,uj=/Press Enter to retry\./;mS=/Quick safety check:\s+Is this a project you created or one you trust/;hS=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function fd(e,t,n){if(!e||!t)return null;for(let r of yj)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function kj(e){let t=Ih.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},Ih.set(e,t)),t}function vS(e,t,n=Date.now()){let r=kj(e);if(r.sentAt=r.sentAt.filter(s=>n-s<xS),r.sentAt.length>=kS)return{action:"give-up"};if(n-r.last<bj)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 SS(e,t=Date.now()){let n=Ih.get(e);return n?n.sentAt.filter(r=>t-r<xS).length>=kS:!1}var yj,bj,kS,xS,Ih,$h=G(()=>{yj=[{provider:"claude",id:"login-continue",match(e){return/^claude:setup:continue:/.test(e?.promptId||"")&&e?.setup==="continue"},keys:["Enter"],accept:!0,gate:"login-enter"},{provider:"codex",id:"login-continue",match(e){return e?.promptId==="codex:signin-complete"&&e?.setup==="continue"},keys:["Enter"],accept:!0,gate:"login-enter"},{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||""}
176
- ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];bj=5e3,kS=5,xS=3600*1e3,Ih=new Map});function md(e,t,n){let{state:r,reason:o}=lc(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of xc)a-c.at>=AS()&&xc.delete(i);xc.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=xc.get(e);return s?Date.now()-s.at>=AS()?(xc.delete(e),!1):s.busy:!1}async function vc(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await Ne(e,{lines:ze}).catch(()=>"");if(!md(e,t,r))return nd(t,r)?{working:!0,prompted:!1}:n;if(oo(t,r)){let o=await Jt(e).catch(()=>r),s=Sn({name:e,agent:t},o);if(s)return!fd({name:e,agent:t},s,o)||SS(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function is(e,t){return(await vc(e,t)).working}var AS,xc,va=G(()=>{dt();os();_h();$h();AS=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,xc=new Map});function Ij(e){if(e.startsWith("{"))try{let t=JSON.parse(e);return{message:String(t?.message??""),taskId:t?.task_id?String(t.task_id):null}}catch{}return{message:e,taskId:null}}function Rj(e){if(e.type==="queue-operation"&&e.operation==="enqueue")return TS.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"&&TS.test(t)?t:null}async function ES(e,t={}){return(await IS(e,t)).launches}async function _S(e,t={}){let{launches:n,done:r}=await IS(e,t);return n.filter(o=>!r.has(o.id))}async function IS(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await jt(e,t)}catch{return{launches:[],done:new Set,stopped:new Map}}let o=new Map,s=new Set,a=new Set,i=new Map,c=new Map,l=new Map,u=new Map;for(let p of r.split(`
177
- `)){let f=p.trim();if(!f||f[0]!=="{")continue;let w;try{w=JSON.parse(f)}catch{continue}if(w.isSidechain)continue;let h=Rj(w);if(h){let g=h.match($j)?.[1]?.trim();g&&a.add(g);continue}let y=w.message?.content;if(!Array.isArray(y))continue;let k=w.timestamp?Date.parse(w.timestamp):null;for(let g of y)if(!(!g||typeof g!="object")){if(g.type==="tool_use"&&g.id){if(g.name==="Agent"){let x=g.input||{};o.set(g.id,{id:g.id,kind:"agent",name:String(x.description||"").trim()||null,detail:String(x.subagent_type||"").trim()||null,ts:k,proven:!1})}else if(g.name==="Bash"){let x=String(g.input?.command||"").trim(),S={id:g.id,kind:"command",name:String(g.input?.description||"").trim()||(x?ha(x):null),detail:x?ha(x):null,ts:k,proven:g.input?.run_in_background===!0};S.proven?o.set(g.id,S):c.set(g.id,S)}else if(Ej.has(g.name)){let x=g.input?.task_id??g.input?.shell_id??g.input?.bash_id;x&&u.set(g.id,{taskId:String(x),ts:k})}}else if(g.type==="tool_result"&&g.tool_use_id){let x=Oj(g.content);if(xj.test(x)){s.add(g.tool_use_id);let P=x.match(Tj)?.[1];P&&l.set(P,g.tool_use_id)}let S=x.match(Aj)?.[1];S&&l.set(S,g.tool_use_id);let _=x.match(vj);if(_){l.set(_[1].trim(),g.tool_use_id);let P=c.get(g.tool_use_id);P&&(c.delete(g.tool_use_id),P.proven=!0,P.outputFile=x.match(Sj)?.[1]?.replace(/\.$/,"")||null,o.set(P.id,P))}let M=u.get(g.tool_use_id);if(M){u.delete(g.tool_use_id);let{message:P,taskId:j}=Ij(x);if(!g.is_error&&_j.test(P)){let T=l.get(M.taskId)??(j?l.get(j):void 0);T&&(a.add(T),i.set(T,k??M.ts??null))}}}}}let d=[];for(let p of o.values()){if(!p.proven&&!s.has(p.id))continue;let{proven:f,...w}=p;w.stoppedTs=i.has(p.id)?i.get(p.id):null,d.push(w)}return{launches:d.slice(-n),done:a,stopped:i}}var xj,vj,Sj,Aj,Tj,Ej,_j,TS,$j,Oj,$S=G(()=>{vn();wa();xj=/^Async (?:agent|task) launched/i,vj=/^Command did not complete within its [^\n]*?moved to the background \(ID: ([^)]+)\)/i,Sj=/Output is being written to:\s*(\S+)/i,Aj=/^Command running in background with ID:\s*([^\s.]+)/i,Tj=/\bagentId:\s*([A-Za-z0-9_-]+)/,Ej=new Set(["TaskStop","KillShell"]),_j=/^Successfully (?:stopped|killed)\b/i;TS=/^\s*<task-notification>/i,$j=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i;Oj=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 so(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 Mj(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 RS(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:An(`read ${so(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${Sa(r)}`:`Read ${Sa(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?so(t.path,n):null,s=t?.glob?` --glob ${Rh(t.glob)}`:"",a=An(String(r),40);return{command:An(`grep ${Rh(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?so(t.target_directory,n):null;return{command:An(`glob ${Rh(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${An(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:An(`edit ${so(t.path,n)}`,140),description:`Edit ${Sa(t.path)}`}:null;case"Write":return t?.path?{command:An(`write ${so(t.path,n)}`,140),description:`Write ${Sa(t.path)}`}:null;case"Delete":return t?.path?{command:An(`delete ${so(t.path,n)}`,140),description:`Delete ${Sa(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>so(s,n)).filter(Boolean);return{command:An(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=Mj(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:An(`apply_patch ${so(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${Sa(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:An(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var hd,An,Sa,Rh,OS=G(()=>{hd=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),An=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,Sa=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);Rh=e=>`"${String(e).replace(/"/g,'\\"')}"`});import Sc from"node:fs";import Cj from"node:fs/promises";import cs from"node:path";import Nj from"node:os";import Pj from"node:crypto";import Dj from"node:zlib";function NS(e){let t=Pj.createHash("md5").update(String(e)).digest("hex");return cs.join(Bj,t)}function PS(e){try{let t=JSON.parse(Sc.readFileSync(cs.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 Lj(e){let t=NS(e),n;try{n=Sc.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=cs.join(t,o.name),a=cs.join(s,"store.db");if(!Sc.existsSync(a))continue;let i=PS(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 wd(e,t){if(!e)return null;if(t){let n=cs.join(NS(e),t),r=cs.join(n,"store.db");if(Sc.existsSync(r))return{id:t,dir:n,store:r,...PS(n)||{createdAtMs:null,updatedAtMs:null}}}return Lj(e)}function MS(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function jj(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=Dj.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function Fj(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 Uj(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!hd.has(r.toolName))continue;let o=RS(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 Oh(e,t){if(!CS)return Aa;let{DatabaseSync:n}=CS,r;try{r=new n(e,{readOnly:!0})}catch{return Aa}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 Aa;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return Aa}let a=s.lastUsedModel||null,i=s.latestRootBlobId?MS(r,s.latestRootBlobId):null;if(!i)return{...Aa,model:a};let c=[],l=[],u=[],d=null,p=[];for(let f of Fj(i)){let w=jj(MS(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 g of w.content){let x=g?.providerOptions?.cursor?.modelName;x&&(d=x)}l.push(...Uj(w.content,t).map((g,x)=>({...g,id:g.id||`${f}:${x}`}))),u.push(...Wj(w.content));let y=Hj(w.content);if(!y)continue;let k=[...new Set(u)];u=[],c.push({id:f,text:y,tools:k.length?k:void 0,commands:l,model:d}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:p}}catch{return Aa}finally{try{r.close()}catch{}}}function DS(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(Sc.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 BS(e,t,{limit:n=80}={}){let r=wd(e,t);if(!r)return[];let{turns:o,model:s}=await Oh(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=DS(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 LS(e,t){let n=wd(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await Oh(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 jS(e,t,{limit:n=80}={}){let r=wd(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await Oh(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=DS(r,a.length||1),l=[];a.forEach((u,d)=>{for(let p of u.commands)l.push({...p,summary:Qr(p.command,p.description),ts:c(d)})});for(let u of s)l.push({...u,summary:Qr(u.command,u.description),ts:i+1});return l}async function FS(e,t){let n=wd(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await Cj.stat(n.store)).mtimeMs)}catch{return null}}var Bj,Hj,Wj,CS,Aa,Mh=G(()=>{wa();OS();Bj=process.env.BOSTRAT_CURSOR_CHATS||cs.join(Nj.homedir(),".cursor","chats");Hj=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(`
178
- `).trim():"",Wj=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],CS=process.getBuiltinModule?.("node:sqlite"),Aa={turns:[],trailingCommands:[],model:null,requestIds:[]}});import qj from"node:fs/promises";function Dh(e){return US.set(e.agent,e),e}function ao(e){return US.get(e)||Gj}async function Bh(e,t={}){return(await ao(e.agent).readMessages(e,t)).map(gd(e))}async function HS(e,t={}){return(await ao(e.agent).readCommands(e,t)).map(gd(e))}async function WS(e,t={}){return(await ao(e.agent).readJobs(e,t)).map(gd(e))}async function yd(e,t={}){return(await ao(e.agent).readOpenJobs(e,t)).map(gd(e))}var Ta,Ch,Nh,Ph,Gj,US,gd,bd=G(()=>{vn();zu();wa();$S();Mh();es();Ta=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}},Ch=class extends Ta{transcript(t){return!t?.cwd||!t?.sessionId?null:xn(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?nh(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?Hx(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?ES(r,n):[]}async readOpenJobs(t,n){let r=this.transcript(t);return r?_S(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await qj.stat(n)).mtimeMs)}catch{return null}}},Nh=class extends Ta{async readMessages(t,n){return BS(t.cwd,t.sessionId,n)}async readCommands(t,n){return jS(t.cwd,t.sessionId,n)}async updatedAt(t){return FS(t.cwd,t.sessionId)}},Ph=class extends Ta{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return Kx(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return Vx(t.cwd,this.sessionId(t),n)}async updatedAt(t){return zx(t.cwd,this.sessionId(t))}},Gj=new Ta("unknown"),US=new Map;Dh(new Ch("claude",Xm));Dh(new Nh("cursor",hd));Dh(new Ph("codex",sc));gd=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function Lh(e){if(!e)return"the current turn";let t=[];e.prompted?t.push("an unanswered prompt"):e.busy?t.push("the current turn"):e.unknown&&t.push("a pane too narrow to read"),e.awaitingBackground&&t.push("a background wait");let n=Array.isArray(e.jobs)?e.jobs:[];if(n.length){let r=n.slice(0,2).map(o=>o.name||o.id).filter(Boolean);t.push(`${n.length} background job${n.length===1?"":"s"}${r.length?` (${r.join(", ")}${n.length>r.length?", \u2026":""})`:""}`)}return t.length?t.join(" and "):"the current turn"}async function qS(e,{timeoutMs:t,reason:n=null,onWait:r=null,deps:o=null}={}){let s={...Yj,...o||{}},a=e?.name,i=e?.agent||null;if(!a)throw new Error("awaitQuiescence: box.name is required");let c=Number(t)||Kj(),l=Vj(),u=s.now(),d=0,p=0,f=!1,w=null;for(;;){p++;let h=await s.capture(a),y=s.busyRead(i,h);if(y.reason==="blocked"){let g=new Error(`${i||"the agent"} in "${a}" is sitting at a login or trust gate \u2014 answer it in the terminal, then retry`);throw g.code="quiescence-blocked",g.detail={blocked:!0},g}if(w={busy:y.state==="busy",unknown:y.state==="unknown",awaitingBackground:s.awaitingBackground(i,h),prompted:!1,jobs:[]},w.busy){let g=await s.turnState(a,i).catch(()=>({prompted:!1}));w.prompted=g?.prompted===!0}if(!w.busy&&!w.unknown&&!w.awaitingBackground){let g=await s.openJobs(e).catch(()=>[]);w.jobs=(Array.isArray(g)?g:[]).map(x=>({id:x.id??null,name:x.name??null,kind:x.kind??null}))}let k=!w.busy&&!w.unknown&&!w.awaitingBackground&&!w.prompted&&w.jobs.length===0;if(d=k?d+1:0,d>=zj){let g=s.now()-u;return f&&ee({flow:"quiescence",phase:"quiet",sessionName:a,agent:i,reason:n,waitedMs:g,reads:p}).catch(()=>{}),{waitedMs:g,reads:p,waited:f,detail:w}}if(!k&&!f&&(f=!0,ee({flow:"quiescence",phase:"waiting",sessionName:a,agent:i,reason:n,detail:w}).catch(()=>{}),r&&await r(w)),s.now()-u>=c){let g=new Error(`waited ${Math.round(c/1e3)}s for ${Lh(w)} in "${a}" to finish`);throw g.code="quiescence-timeout",g.detail=w,g.waitedMs=s.now()-u,ee({flow:"quiescence",phase:"timeout",sessionName:a,agent:i,reason:n,waitedMs:g.waitedMs,reads:p,detail:w,error:g.message}).catch(()=>{}),g}await s.sleep(l)}}var Kj,Vj,zj,Jj,Yj,GS=G(()=>{dt();os();va();bd();yn();Kj=()=>Number(process.env.BOSTRAT_QUIESCENCE_TIMEOUT_MS)||6e5,Vj=()=>Number(process.env.BOSTRAT_QUIESCENCE_POLL_MS)||1500,zj=2,Jj=e=>new Promise(t=>setTimeout(t,e)),Yj={capture:e=>Ne(e,{lines:ze}),busyRead:lc,awaitingBackground:nd,turnState:vc,openJobs:yd,now:()=>Date.now(),sleep:Jj}});import Xj from"node:fs";import io from"node:fs/promises";import co from"node:path";function eA(e){let t=Wo(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=KS?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,KS).toString("utf8").replace(/�+$/,"")}
179
-
180
- [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function aF(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(zS.test(s)){if(r.length>=aA)continue;let a=sF(s.replace(zS,"").replace(/[.;,:]+$/,""),iA,rF);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>VS&&(o=`${o.slice(0,VS-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function cA(e,t,{timeoutMs:n=9e4}={}){let r=co.join(t,tF),o=co.join(r,nF);await io.mkdir(r,{recursive:!0});let s=await kd(o),a=await Se(e);if(!a)throw new Error(`session "${e}" not found`);return await xd(e,a,oF(o)),await hA(o,s,n),aF(await io.readFile(o,"utf8"))}function lA(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===nA||n===sA;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(tA)||n===Zj||r.startsWith(rA)||r.startsWith(oA)}function uA(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-iF;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 dA(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 pA(e,{windows:t=[]}={}){if(lA(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 vd(e){return jh.get(e)||null}async function fA(e){let t=jh.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await Se(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:co.join(n.cwd,ZS,QS)};return jh.set(e,r),uF(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function uF(e,t){e.step="summarize",await mA(e.name,t,{quiesce:{reason:"console-checkpoint",onWait:r=>{e.step="await-turn",e.wait=r},onResume:()=>{e.step="summarize"}}}),e.step="clear";let n=await Se(e.name);await xd(e.name,n,"/clear"),await Uh(cF),e.step="resume",await xd(e.name,n,eF),e.step="done",e.finishedAt=Date.now()}async function JS(e,t,n,r){if(!r)return{outcome:"skipped"};let o=r.box||{name:t,agent:n?.agent??null,cwd:n?.cwd??null,sessionId:n?.sessionId??null},s=r.reason?`${r.reason}:${e}`:e,a=!1;try{let i=await qS({...o,name:t},{timeoutMs:r.timeoutMs,reason:s,onWait:async c=>{a=!0,r.onWait&&await r.onWait(c,e)}});return a&&r.onResume&&await r.onResume(e),{outcome:"ok",waitedMs:i.waitedMs,waited:i.waited}}catch(i){if(i?.code!=="quiescence-timeout"||(r.onTimeout||dF)===pF)throw i;return await ee({flow:"checkpoint",phase:"quiescence-timeout",sessionName:t,gate:e,waitedMs:i.waitedMs,detail:i.detail,still:Lh(i.detail),paneTail:!0}),r.onResume&&await r.onResume(e),{outcome:"timeout",waitedMs:i.waitedMs,waited:!0,detail:i.detail}}}async function mA(e,t,{timeoutMs:n=lF,quiesce:r=null}={}){let o=co.join(t,ZS),s=co.join(o,QS);await io.mkdir(o,{recursive:!0});let a=await Se(e),i=await JS("pre-drive",e,a,r),c=await kd(s);await ee({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:s,beforeMtime:c,quiescence:i.outcome,waitedMs:i.waitedMs});try{await xd(e,a,Qj(s)),await hA(s,c,n)}catch(f){throw f&&typeof f=="object"&&(f.quiescence={pre:i,post:{outcome:"skipped"}}),f}let l=await JS("post-write",e,a,r);await ee({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:s,afterMtime:await kd(s),quiescence:l.outcome,waitedMs:l.waitedMs});let u=await Cv(t,s,{exclude:f=>lA(f.role,f.text)});await ee({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:s,...u});let d=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(d){await N({id:d,cwd:t},{type:"memory.seed",actor:"orchestrator",payload:{...u,tokensEst:u.chars?Math.round(u.chars/4):0,ts:Date.now()}}).catch(()=>{});try{let f=await io.readFile(s,"utf8");await N({id:d,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...eA(f),ts:Date.now()}})}catch{}}await Rm(t);let p=await fF(o,s);return d&&await fx(d,p||s,{box:e,agent:a?.agent??null}),{file:s,quiescence:{pre:i,post:l}}}async function Sd(e,{timeoutMs:t,quiesce:n=null}={}){let r=await Se(e);if(!r)throw new Error(`session "${e}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${e}"`);return mA(e,r.cwd,{...t?{timeoutMs:t}:{},quiesce:n})}function Fh(e){let t=e?.quiescence;if(!t)return null;let n=[t.pre?.outcome,t.post?.outcome].filter(r=>r&&r!=="skipped");return n.length?n.includes("timeout")?"timeout":"ok":null}async function Ad(e,t,{trackName:n="this Track"}={}){let r=await K({id:e,cwd:t}),o=oS(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=co.join(t,YS);return await io.mkdir(co.dirname(s),{recursive:!0}),await io.writeFile(s,o,"utf8"),await N({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...eA(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),YS}async function kd(e){try{return(await io.stat(e)).mtimeMs}catch{return 0}}async function hA(e,t,n){let r=Date.now()+n;for(;;){if(await kd(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await Uh(2e3)}}async function fF(e,t){try{if(!Xj.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=co.join(e,`${n}.md`);return await io.copyFile(t,r),r}catch{return null}}function Uh(e){return new Promise(t=>setTimeout(t,e))}function XS(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 xd(e,t,n){if(t){let o=XS(t.agent);await wr({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await Se(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await Ke(e,["Escape"],{kind:"drive-wipe"}),await Uh(150),await da(e,Wu,{kind:"drive-wipe"}),await Qe(e,n,{kind:"orchestration-drive",...Un(r.agent,n)}),await wc({sessionName:e,agent:r.agent,agentCmd:XS(r.agent),text:n,flow:"orchestration-drive"})}var ZS,QS,KS,tA,nA,rA,Zj,Qj,eF,oA,sA,tF,nF,VS,aA,iA,rF,oF,zS,sF,iF,cF,lF,jh,dF,pF,YS,Hh=G(()=>{dt();os();yn();pc();ch();Nv();Wi();be();Pu();sS();GS();ZS=".bostrat/handoff",QS="latest.md",KS=32*1024;tA="Checkpoint: write a work-in-progress handoff",nA="HANDOFF WRITTEN",rA="Resume from .bostrat/handoff/latest.md",Zj="/clear",Qj=e=>`${tA} 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 ${nA} and take no further action.`,eF=`${rA}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,oA="Beat: write a",sA="BEAT WRITTEN",tF=".bostrat/arc",nF="beat.txt",VS=200,aA=4,iA=5,rF=36,oF=e=>`${oA} 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 ${aA} further lines, each starting with "- " and naming ONE piece in at most ${iA} 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 ${sA} and take no further action.`,zS=/^(?:[-–—*•·]|\d+[.)])\s+/,sF=(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};iF=6e5;cF=3500,lF=3e5,jh=new Map;dF="proceed",pF="reject";YS=".bostrat/handoff/status-latest.md"});function uo(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!Td.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 yA(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:uo(o.from,"from",n),toMs:uo(o.to,"to",n)}))}return t}function qh(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 hF(e){if(!e)return null;let t=String(e).trim();if(lo[t])return t;if(wA[t])return wA[t];let n=null;for(let r of Object.keys(lo))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function wF(e){if(!e||e===lo)return mF;let t=gA.get(e);return t||(t=yA(e),gA.set(e,t)),t}function bA(e,t,n={}){let{table:r,speed:o}=n,s=wF(r),a=r&&r!==lo?s[e]?e:null:hF(e);if(!a)return null;let i=qh(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 Wn(e,t={},n,r){let o=bA(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 gF(e=lo){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:uo(a.from,"from",n),toMs:uo(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`),Td.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 bF({now:e=Date.now(),table:t=lo,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...yF,...n},a=[],i=qh(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:uo(d.from,"from",c),toMs:uo(d.to,"to",c),verifiedMs:Td.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*Wh;p&&i-d.verifiedMs>r*Wh&&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*Wh&&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=lo,...n}={}){let r=qh(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=uo(l.from,"from",i),d=uo(l.to,"to",i);r>=u&&r<=d&&Td.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=[...gF(t),...bF({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var lo,wA,Td,mF,gA,kA,yF,Wh,yr=G(()=>{lo={"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-1":[{from:null,to:null,input:10,output:50,cacheWrite:20,cacheRead:.25,cacheReadX:.025,verifiedAt:"2026-09-07",note:"verified 2026-09-07 against platform.claude.com/docs/en/about-claude/pricing: $10/$50, 1h cache write $20 (2\xD7), cache hits $0.25 (0.025\xD7 \u2014 the 5.1-only multiplier; footnote 1 on the 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)."}],"gpt-6-astra":[{from:null,to:null,input:10,output:50,cacheWrite:12.5,cacheRead:1,fast:{input:20,output:100,cacheWrite:25,cacheRead:2},verifiedAt:"2026-09-07",note:"verified 2026-09-07 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input; fast tier $20/$100 recorded as the fast variant (codex reports no speed)."}]},wA={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-1","gpt-5.6":"gpt-5.6-sol"},Td=/^\d{4}-\d{2}-\d{2}$/;mF=yA(lo);gA=new WeakMap;kA=(e,t,n)=>bA(e,t,n)!==null;yF=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),Wh=864e5});function kF(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function vA(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function sn(e){let t=e.payload?.model||"unknown",n=kF(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=Wn(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&&!kA(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function po(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=xA();for(let p of n){let{usd:f,model:w,tokens:h,repriced:y,unpriced:k,asRecorded:g}=sn(p);i+=g;let x=p.provider||"unknown",S=p.boxId||"unattributed";if(y&&c++,k&&(l++,u.add(w)),a+=f,vA(d,h),r[w]||={usd:0,tokens:xA(),events:0},r[w].usd+=f,r[w].events+=1,vA(r[w].tokens,h),o[x]||={usd:0,events:0},o[x].usd+=f,o[x].events+=1,s[S]||={usd:0,events:0,provider:x,models:new Set,label:t[S]||S},s[S].usd+=f,s[S].events+=1,w!=="unknown"&&s[S].models.add(w),p.epoch!=null){let _=(s[S].epochs||={})[p.epoch]||={usd:0,events:0,provider:x,models:new Set};_.usd+=f,_.events+=1,_.provider=x,w!=="unknown"&&_.models.add(w)}}return{totalUsd:_a(a),asRecordedUsd:_a(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:Ed(r,p=>({...p,usd:_a(p.usd)})),byProvider:Ed(o,p=>({...p,usd:_a(p.usd)})),byBox:Ed(s,p=>({usd:_a(p.usd),events:p.events,provider:p.provider,label:p.label,models:[...p.models],...p.epochs?{epochs:Ed(p.epochs,f=>({usd:_a(f.usd),events:f.events,provider:f.provider,models:[...f.models]}))}:{}}))}}var xA,_a,Ed,fo=G(()=>{yr();xA=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});_a=e=>Math.round(e*1e4)/1e4,Ed=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function xF(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 SA(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(Gh(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(Gh(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(`${Gh(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=po(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?xF(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var Gh,AA=G(()=>{fo();Gh=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as vF}from"node:child_process";import{promisify as SF}from"node:util";import{randomUUID as AF}from"node:crypto";import TA from"node:fs/promises";async function Kh(e,t){let n=Date.now()+t;for(;;){if(await Fn(e))return!0;if(Date.now()>n)return!1;await us(RA)}}function RF(e){let t=String(e||"").split(`
181
- `).map(n=>n.trimEnd()).filter(n=>n.trim());return!t.length||!_F.test(t[t.length-1])?!1:EF.test(t.slice(-IF).join(`
182
- `))}async function OF(e,t){if(t!=="claude")return null;let n=Date.now()+$F;for(;;){if(await Fn(e))return null;let r=await Ne(e,{lines:30});if(RF(r))return await ee({flow:"swap",phase:"exit-chooser",sessionName:e,from:t,paneTail:!0}),await Ke(e,["Enter"],{kind:"swap-exit"}),"answered";if(Date.now()>n)return null;await us(RA)}}async function MF(e,t){let n=EA[t]||EA.default;n.escape&&(await Ke(e,["Escape"],{kind:"swap-exit"}),await us(150)),n.wipe&&await da(e,Wu,{kind:"swap-exit"}),await qu(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=Un(t).submitDelayMs||0;return await us(Math.max(r,250)),await Ke(e,["Enter"],{kind:"swap-exit"}),{chooser:await OF(e,t)}}async function DF(e,{settleMs:t=CF,timeoutMs:n=NF,parse:r=!0}={}){let o=Date.now(),s=null,a=null;for(;;){let i=null,c=!0;try{let u=await TA.stat(e);i=`${u.mtimeMs}:${u.size}`}catch{c=!1}if(!c)return{settled:!0,waitedMs:Date.now()-o,parsed:null,missing:!0};let l=Date.now();if(i!==s)s=i,a=l;else if(l-a>=t){let u=null;if(r)try{JSON.parse(await TA.readFile(e,"utf8")),u=!0}catch{u=!1}if(u!==!1)return{settled:!0,waitedMs:l-o,parsed:u};a=l}if(l-o>=n)return{settled:!1,waitedMs:l-o,parsed:null};await us(PF)}}async function _A(e,t){try{let{stdout:n}=await ls(oe,se("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function OA(e){await ls(oe,se("respawn-pane","-k","-t",e))}async function Vh(e,{exitTimeoutMs:t=IA,fromAgent:n=null}={}){if(!je(e))throw new Error("invalid session name");let r=!1;if(await Fn(e))return{forced:r,chooser:null};let o=n||(await Se(e))?.agent||"agent",{chooser:s}=await MF(e,o),a=await Kh(e,t);if(await ee({flow:"swap",phase:"exit",sessionName:e,from:o,graceful:a,chooser:s,paneTail:!0}),!a&&(r=!0,await ee({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await OA(e),!await Kh(e,$A)))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);return{forced:r,chooser:s}}async function zh(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 Se(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||Xr(n),a=Number(t.exitTimeoutMs)||IA;if(await ee({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd}),s==="codex"){let k=await fu();k.waited&&await ee({flow:"cli-currency",phase:"spawn-gate",sessionName:e,...k}),mu(e)}let{forced:i,chooser:c}=await Vh(e,{exitTimeoutMs:a,fromAgent:o});if(o==="claude"){let k=await DF(im());await ee({flow:"swap",phase:"config-settled",sessionName:e,from:o,...k})}let l=s==="claude"&&Yo(n),u=l?iu():null,d=await _A(e,"ANTHROPIC_API_KEY"),p=!1;try{u?(await ls(oe,se("set-environment","-t",e,"ANTHROPIC_API_KEY",u)),p=!0):d&&(await ls(oe,se("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),p=!0)}catch(k){throw u?Bu(k,u):k}if(p&&!i&&(await OA(e),!await Kh(e,$A)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let f=!!t.resumeSessionId,w=t.resumeSessionId||AF(),h=f?n:Zi(n,w,e),y=f?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(h);return l&&await Wr(r.cwd),s==="codex"&&await Xs(r.cwd),s==="cursor"&&await Qs(r.cwd),await Xo(e),await ls(oe,se("set-option","-t",e,"@bostrat-sid",w)),await ls(oe,se("set-option","-t",e,"@bostrat-agent",s)),await us(TF),l&&Xi().length&&(await _A(e,Yi)||await ls(oe,se("set-environment","-t",e,Yi,"1")).catch(()=>{}),await Qe(e,`export ${Yi}=1`,{kind:"swap-env"}),await us(150)),await Qe(e,h,{kind:"swap-launch"}),await ee({flow:"swap",phase:"launched",sessionName:e,from:o,to:s,paneTail:!0}),await ee({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:w,forced:i,chooser:c,envRespawned:p}),{name:e,cwd:r.cwd,sessionId:w,agent:s,pinned:y,forced:i,chooser:c,envRespawned:p,launchCmd:h}}var ls,us,IA,$A,RA,TF,EA,EF,_F,IF,$F,CF,NF,PF,MA=G(()=>{dt();$i();lu();qo();hu();pc();yn();ls=SF(vF),us=e=>new Promise(t=>setTimeout(t,e)),IA=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,$A=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,RA=250,TF=400,EA={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"}};EF=/Background work is running/,_F=/Enter to confirm\s*·\s*Esc to cancel/,IF=12,$F=Number(process.env.BOSTRAT_SWAP_CHOOSER_WAIT_MS)||3e3;CF=Number(process.env.BOSTRAT_CLAUDE_CONFIG_SETTLE_MS)||500,NF=Number(process.env.BOSTRAT_CLAUDE_CONFIG_SETTLE_TIMEOUT_MS)||5e3,PF=100});function Jh(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Yh({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!Jh(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),CA);try{let a=await NA(`${De(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 Ac(e,{provider:t=null,cls:n="other",status:r=null,text:o="",note:s=null}={},{env:a=process.env,now:i=Date.now}={}){if(!e?.id||!String(e.name||"").startsWith("\u21BB"))return{ok:!1,source:"not-a-loop-track"};if(!Jh(a))return{ok:!1,source:"unconfigured"};let c=_d.get(e.id)||0;if(i()-c<BF)return{ok:!1,source:"debounced"};_d.set(e.id,i());let l=await Tc({env:a}),u=l.loops.find(f=>f.trackId===e.id);if(!u)return _d.delete(e.id),{ok:!1,source:l.source==="plane"?"no-loop":l.source};let d=s?String(s).replace(/\s+/g," ").trim():`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`,p=await Yh({loopId:u.id,outcome:"errored",note:d.slice(0,500),env:a});return p.ok||_d.delete(e.id),{...p,loop:{id:u.id,name:u.name}}}async function Tc({env:e=process.env}={}){if(!Jh(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),CA);try{let r=await NA(`${De(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 CA,NA,BF,_d,Id=G(()=>{xt();CA=1e4,NA=(...e)=>fetch(...e);BF=10*6e4,_d=new Map});import{execFile as LF}from"node:child_process";import $d from"node:fs/promises";import Xh from"node:path";import{promisify as jF}from"node:util";function KF(e){let n=String(e||"").trim().match(/\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]+)?/);return n?n[0]:null}async function VF(e,{env:t=process.env}={}){let n=String(e||"").trim();if(!n)return null;let r=n.includes("/")?[Xh.resolve(n)]:String(t.PATH||"").split(Xh.delimiter).filter(Boolean).map(o=>Xh.join(o,n));for(let o of r)try{await $d.access(o,$d.constants.X_OK);let s=await $d.realpath(o),a=await $d.stat(s);if(!a.isFile())continue;return{path:s,mtimeMs:a.mtimeMs}}catch{}return null}async function ds({agent:e=null,agentCmd:t=null,env:n=process.env}={}){let r=String(t||(e?n[WF[e]]||HF[e]:"")||"").trim();if(!r)return null;let{realClaude:o,realCodex:s,realCursor:a}=dc({agent:e,agentCmd:r});if(!(o||s||a))return null;let i=await VF(r.split(/\s+/)[0],{env:n});if(!i)return null;let c=`${i.path}@${i.mtimeMs}`;return Zh.has(c)||Zh.set(c,Promise.resolve().then(()=>GF(i.path,{agent:e})).then(l=>KF(l)).catch(()=>null)),Zh.get(c)}var FF,UF,HF,WF,Zh,qF,GF,PA=G(()=>{os();FF=jF(LF),UF=8e3,HF={claude:"claude",codex:"codex",cursor:"cursor-agent"},WF={claude:"BOSTRAT_AGENT_CMD",codex:"BOSTRAT_CODEX_CMD",cursor:"BOSTRAT_CURSOR_CMD"},Zh=new Map,qF=async e=>(await FF(e,["--version"],{timeout:UF})).stdout,GF=qF});function Ia(e){return typeof e=="string"?e.trim():""}var DA=G(()=>{});import{execFile as zF}from"node:child_process";import{promisify as JF}from"node:util";async function Ye(e,t,{input:n}={}){let r=ew("git",["-C",e,...t],{maxBuffer:BA});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function $a(e){if(!e)return!1;try{let{stdout:t}=await Ye(e,["rev-parse","--is-inside-work-tree"]);return t.trim()==="true"}catch{return!1}}async function LA(e){let{stdout:t}=await Ye(e,["rev-parse","--show-toplevel"]);return t.trim()}async function YF(e){try{return await Ye(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function Ra(e,t="bostrat: subtask snapshot"){let{stdout:n}=await Ye(e,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>ew("git",["-C",e,...a],{maxBuffer:BA,env:o,...i});try{let a=await YF(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 ew("rm",["-f",r])}catch{}}}async function tw(e,t,{trailers:n=[]}={}){let{stdout:r}=await Ye(e,["status","--porcelain"]);return r.trim()?(await Ye(e,["add","-A"]),await Ye(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",t,...n.flatMap(o=>["--trailer",o])]),!0):!1}async function ps(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await Ye(e,["status","--porcelain"]),r=n.split(`
183
- `).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 fs(e,t){if(!t)return 0;try{let{stdout:n}=await Ye(e,["rev-list","--count",`${t}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function ms(e,t,n,r){return await Ye(e,["worktree","add","--no-track","-b",n,t,r]),t}async function nw(e,t){try{return await Ye(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function Ec(e,t,n){return await Ye(e,["worktree","add","--end-of-options",t,n]),t}async function hs(e){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:t}=await Ye(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 Ye(e,["rev-parse","--verify","--quiet",t]),n}catch{}return"HEAD"}async function rw(e){await Ye(e,["init","-q"]),await Ye(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function $t(e,t){try{await Ye(e,["worktree","remove","--force",t])}catch{try{await Ye(e,["worktree","prune"])}catch{}}}function XF(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 ow(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function sw(e,t,n,r){let{stdout:o}=await Ye(e,ow(["diff","--shortstat",t,n],r));return XF(o)}async function aw(e,t,n,r){let{stdout:o}=await Ye(e,ow(["diff","--name-only",t,n],r));return o.split(`
184
- `).map(s=>s.trim()).filter(Boolean)}async function iw(e,t,n,r){let{stdout:o}=await Ye(e,ow(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await Qh(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await Qh(e,o,["--3way","--whitespace=nowarn"]),a=await ZF(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await Qh(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function Qh(e,t,n){try{return await Ye(e,["apply",...n,"-"],{input:t}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function ZF(e){try{let{stdout:t}=await Ye(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
185
- `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var ew,BA,Rd=G(()=>{ew=JF(zF),BA=64*1024*1024});function Od(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!QF.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 Ue,QF,an=G(()=>{Ue=e=>!!(e&&(e.archivedAt||e.transferredTo)),QF=new Set(["merged","conflict","canceled","failed","handed-off"])});import cw from"node:fs/promises";import FA from"node:path";import eU from"node:os";function qA(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function GA(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function KA(e){let t=new Date(qA(e));return t.setDate(t.getDate()+7),t.getTime()}function VA(e){let t=new Date(GA(e));return t.setMonth(t.getMonth()+1),t.getTime()}function Cd(e=Date.now()){for(let[t,n]of Object.entries(Oa)){let r=n.startOf(e);if(r!==br[t]){br[t]=r;for(let o of ws.values())o[t]=0;for(let o of Ma)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&Ma.delete(o)}}}function zA(e,t){let n=Tn?.caps?.[e]?.[Oa[t].capKey];return Number.isFinite(n)&&n>0?n:null}function mo(e,t=Date.now()){if(!e||!uw||!Tn?.caps)return null;Cd(t);let n=ws.get(e);for(let r of Object.keys(Oa)){let o=zA(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:Md(s),resetsAt:Oa[r].nextStart(t)}}return null}function JA(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${br[t.window]}`;return Ma.has(n)?!1:(Ma.add(n),!0)}function jA(e,t,n,r=Date.now()){if(!e||!t)return;Cd(r);let o=tU(e);for(let[s,a]of Object.entries(Oa))n>=br[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function nU(e,t,n=Date.now()){if(!Tn?.caps||!lw)return;let r=ws.get(e);if(r)for(let[o,s]of Object.entries(Oa)){let a=zA(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*WA||i>=a)continue;let c=`warn:${e}:${o}:${br[o]}`;if(!Ma.has(c)){Ma.add(c);try{let l=await lw(t);if(!l)continue;await N(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:Md(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function YA(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 Nd(e,{source:t="local",updatedAt:n=Date.now()}={}){Tn={caps:YA(e),updatedAt:n,source:t};try{await cw.mkdir(UA,{recursive:!0}),await cw.writeFile(HA(),JSON.stringify(Tn,null,2))}catch{}return _c()}function _c(e=Date.now()){Cd(e);let t=new Set([...ws.keys(),...Object.keys(Tn?.caps||{})]),n={};for(let r of t){let o=ws.get(r);n[r]={weeklyUsd:Md(o?.weekly||0),monthlyUsd:Md(o?.monthly||0)}}return{caps:Tn?.caps||{},configured:!!Tn,seeded:uw,updatedAt:Tn?.updatedAt??null,spent:n,windows:{weekly:{start:br.weekly,resetsAt:KA(e)},monthly:{start:br.monthly,resetsAt:VA(e)}},warnPct:WA}}async function XA({listTracks:e,getTrack:t}={}){lw=t||null,Cd();try{let o=JSON.parse(await cw.readFile(HA(),"utf8"));Tn={caps:YA(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{Tn=null}let n=Date.now();Ze.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=sn(o);jA(o.provider||"unknown",s,o.ts??Date.now()),nU(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(br.weekly,br.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||jA(a.provider||"unknown",sn(a).usd,i,n)}}return uw=!0,_c()}var UA,HA,WA,Oa,Tn,uw,br,ws,Ma,lw,tU,Md,Pd=G(()=>{be();fo();UA=process.env.BOSTRAT_STATE_DIR||FA.join(process.env.HOME||eU.tmpdir(),".bostrat"),HA=()=>FA.join(UA,"usage-caps.json"),WA=.8;Oa={weekly:{startOf:qA,nextStart:KA,capKey:"weeklyUsd"},monthly:{startOf:GA,nextStart:VA,capKey:"monthlyUsd"}},Tn=null,uw=!1,br={weekly:0,monthly:0},ws=new Map,Ma=new Set,lw=null,tU=e=>{let t=ws.get(e);return t||(t={weekly:0,monthly:0},ws.set(e,t)),t};Md=e=>Math.round(e*1e4)/1e4});import rU from"node:fs/promises";import oU from"node:os";import ZA from"node:path";function dw(e){return e==="codex"?cU:e==="cursor"?oT:nT}function QA(e){let t=String(e||"").split(`
186
- `),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 eT(e){let t=String(e||"").split(`
187
- `),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 lU(e){let t=String(e||"").split(`
188
- `);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 tT(e){let t=String(e||"").split(`
189
- `),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 sT(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&&!rT.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=oT.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!iU.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Ic(e,t,{timeoutMs:n=sU}={}){let r=Date.now()+n;for(;;){let o=await Ne(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await Dd(aU)}}async function uU(e,t){return await Qe(e,`/model ${t.model}`,Un("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function dU(e,t){await Hu(e),await Qe(e,"/model",{enter:!1}),await Dd(250),await Ke(e,["Enter"],{kind:"model-switch"});let n=await Ic(e,QA);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await Ke(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=lU(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await Qe(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await Ic(e,i=>eT(i)||!QA(i)&&o(i)&&{done:o(i)});if(!s)throw await Ke(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?rT.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 Ke(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await Qe(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Ic(e,i=>!eT(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 pU(){let e=ZA.join(process.env.CURSOR_CONFIG_DIR||ZA.join(oU.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await rU.readFile(e,"utf8"))?.model||null}catch{return null}}async function fU(e,t){await Hu(e),await qu(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await Ic(e,tT),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 Ic(e,tT,{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 Ke(e,["Down"],{kind:"model-switch"}),await Dd(250)}if(!n||!s||!o(s)){await Ke(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await Ke(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 Ke(e,["Enter"],{kind:"model-switch"}),await Dd(800);let a=await pU();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 aT(e,t,n){return e==="codex"?dU(t,n):e==="cursor"?fU(t,n):uU(t,n)}var Dd,sU,aU,nT,iU,cU,rT,oT,iT=G(()=>{dt();pc();Dd=e=>new Promise(t=>setTimeout(t,e)),sU=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,aU=300,nT=[{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"}],iU=new Set([...nT.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"]),cU=[{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"}],rT=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),oT=[{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 jd(e){let t=e||{},n=mU(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function mU(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:lt(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:lt(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:lt(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:lt(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,cliVersion:e.cliVersion??null,...e.standing?{standing:e.standing}:{}}};case"lead-handoff-failed":return{type:"handoff.failed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:lt(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:lt(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:lt(e.agent),payload:{...qn(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:lt(e.agent||e.toAgent),payload:{kind:"subtask-failed",...qn(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:lt(e.agent),payload:{change:"subtask-resumed",...qn(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",...qn(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...qn(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...qn(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:lt(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:lt(e.agent),payload:{change:"lead-refreshed",box:e.box,agent:e.agent,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,reason:e.reason,cliVersion:e.cliVersion??null,...e.standing?{standing:e.standing}:{}}};case"transferred-in":return{type:e.mode==="recover"?"track.recovered":"track.transferred",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:lt(e.agent),payload:{...qn(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...qn(e)}};case"retag-failed":return{type:"error",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:lt(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:lt(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};case"delivery-held":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:lt(e.agent),payload:{kind:"delivery-held",...qn(e)}};case"startup-gate":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:lt(e.agent),payload:{kind:"startup-gate",...qn(e)}};default:return null}}function uT(e,t){let n=jd(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;Fd(()=>N(r,n))}async function dT(e){if(!(!e?.id||cT.has(e.id))){cT.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=jd(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await N(e,o)}}catch{}}}function qn(e){let{type:t,at:n,...r}=e;return r}function pT(e,t,n){!n?.promptId||Ld.get(e.id)===n.promptId||(Ld.set(e.id,n.promptId),Fd(()=>N(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:lt(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 fT(e,t,n,r={}){Ld.delete(e.id),Fd(()=>N(e,{type:"prompt.dismissed",actor:"user",source:"orchestrator",boxId:t?.name,provider:lt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}function pw(e,t,n,r={}){Ld.delete(e.id),Fd(()=>N(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:lt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var lt,Bd,Fd,lT,cT,Ld,fw=G(()=>{be();lt=e=>e||null;Bd=Promise.resolve(),Fd=e=>(Bd=Bd.then(e).catch(()=>{}),Bd),lT=()=>Bd;cT=new Set;Ld=new Map});function bU(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function bT(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of bU(n).reverse()){if(!hU.test(r))continue;let o=r.endsWith("?")&&r.length<=yU&&gU.test(r);if(wU.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function xT(e){let t=String(e||""),n=[];kU.test(t)&&n.push("commit"),kT.test(t)&&n.push("rebase"),xU.test(t)&&n.push("push");let r=SU.test(t);!r&&vU.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 vT(e){return kT.test(String(e||""))}function Ca(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 ST(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 AT(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<=AU&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function TT(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+TU||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function ET(e){let t=(Array.isArray(e)?e:[]).filter(r=>mT[r]).map(r=>mT[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 hT,wT,gT,yT,hU,wU,gU,yU,ho,kU,kT,xU,vU,SU,AU,TU,mT,gs=G(()=>{hT=/(?<!\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,wT=/(?<!\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,gT=/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,yT=/(?<!\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,hU=new RegExp(`\\b(?:${hT}|${wT}|${gT}|${yT})\\b`,"i"),wU=/\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,gU=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,yU=90;ho=["commit","rebase","push","pr"],kU=new RegExp(`\\b(?:${hT})\\b`,"i"),kT=new RegExp(`\\b(?:${yT})\\b`,"i"),xU=new RegExp(`\\b(?:${wT})\\b`,"i"),vU=new RegExp(`\\b(?:${gT})\\b`,"i"),SU=/\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;AU=3e4;TU=2500;mT={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import EU from"node:crypto";import Ud from"node:fs/promises";import _T from"node:path";import _U from"node:os";function OT(e){RT=typeof e=="function"?e:async()=>new Set}function IU(e,t,n){if(e.originNode&&e.originNode===t)return!0;let r=e.data?.trackId;return!!r&&n.has(r)}async function We(){return kr||(mw??=Ud.readFile(ww,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(kr=e,!t&&Ge()){let{records:n,source:r}=await pt("prlinks").catch(()=>({records:[],source:"error"}));if(r==="plane"){let o=ux(),s=await RT().catch(()=>new Set),a=0;for(let i of n){if(i.deletedAt||!i.data?.repo||i.data?.number==null)continue;if(!IU(i,o,s)){a++;continue}let{id:c,updatedAt:l,...u}=i.data;kr[ce(u.repo,u.number)]=u}a&&console.log(`[pr-links] restore: ${Object.keys(kr).length} link(s) re-seeded, ${a} other-node record(s) left on the plane`),Object.keys(kr).length&&await gw().catch(()=>{})}}return kr}).finally(()=>mw=null),mw)}async function gw(){let e=JSON.stringify({links:kr},null,2),t=`${ww}.${process.pid}.tmp`;await Ud.mkdir(IT,{recursive:!0}),await Ud.writeFile(t,e),await Ud.rename(t,ww)}async function et(e){hw=hw.then(gw,gw),await hw.catch(()=>{});let t=kr?.[e];t&&It("prlinks",{id:$T(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function Yt({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 We(),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:$U.has(a),firstSeen:Date.now()},await et(ce(e,t)),{link:i[c],created:!0})}async function xr(e,t){if(!e||t==null)return null;let n=(await We())[ce(e,t)];return!n||n.announced?null:(n.announced=!0,await et(ce(e,t)),n)}async function MT(e,t){if(!e||t==null)return!1;let n=(await We())[ce(e,t)];return n?.notifyOnMerge?(delete n.notifyOnMerge,await et(ce(e,t)),!0):!1}async function ft(e,t){return!e||t==null?null:(await We())[ce(e,t)]??null}async function wo(e,t,n){if(!e||t==null)return null;let r=(await We())[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 CT(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await We())[ce(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await et(ce(e,t)),o):null}async function NT(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await We())[ce(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await et(ce(e,t)),o):null}async function Hd(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await We())[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 Wd(e,t){if(!e||t==null)return null;let n=(await We())[ce(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await et(ce(e,t)),n)}async function qd(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await We())[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 Gd(e,t){if(!e||t==null)return null;let n=(await We())[ce(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await et(ce(e,t)),n)}async function PT(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await We())[ce(e,t)];return r?(r.baseFoldAt=n,await et(ce(e,t)),r):null}async function DT(e,t,{misses:n,until:r}){if(!e||t==null)return null;let o=(await We())[ce(e,t)];return o?(o.brokerRefused={misses:Number(n)||0,until:Number(r)||0},await et(ce(e,t)),o):null}async function BT(e,t){if(!e||t==null)return null;let n=(await We())[ce(e,t)];return n?.brokerRefused?(delete n.brokerRefused,await et(ce(e,t)),n):null}async function LT(e,t){if(!e||t==null)return null;let n=(await We())[ce(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await et(ce(e,t)),n)}async function jT(e,t,n){if(!e||t==null||!n)return null;let r=(await We())[ce(e,t)];return r?(r.lastHeadSha=n,await et(ce(e,t)),r):null}async function FT(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await We())[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 $c(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await We())[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 ys(e,t,n=!0){if(!e||t==null)return null;let r=(await We())[ce(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await et(ce(e,t)),r):null}async function bs(e,t,n=!0){if(!e||t==null)return null;let r=(await We())[ce(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await et(ce(e,t)),r):null}async function UT(e,t,n){if(!e||t==null)return null;let r=(await We())[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 HT(e,t,n){if(!e||t==null)return null;let r=(await We())[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 Rc(e,t){if(!e||t==null)return null;let n=(await We())[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,delete n.verdict,await et(ce(e,t)),n)}async function WT(){return Object.values(await We()).filter(e=>!RU.has(e.state))}async function En(){return Object.values(await We()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function qT(){if(!Ge())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await pt("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await We(),r=0;for(let[o,s]of Object.entries(n))await It("prlinks",{id:$T(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var IT,ww,ce,$T,kr,mw,hw,RT,$U,RU,Gn=G(()=>{Yr();IT=process.env.BOSTRAT_STATE_DIR||_T.join(process.env.HOME||_U.tmpdir(),".bostrat"),ww=_T.join(IT,"pr-links.json"),ce=(e,t)=>`${e}#${Number(t)}`,$T=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=EU.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},kr=null,mw=null,hw=Promise.resolve(),RT=async()=>new Set;$U=new Set(["api","observed","reconciled"]);RU=new Set(["merged","closed","lost"])});import OU from"node:fs";import yw from"node:fs/promises";import zT from"node:path";import MU from"node:os";function XT(e,t=!1){if(!t&&e-KT<CU)return;KT=e;let n=JSON.stringify({windowStart:Na,byCaller:Object.fromEntries(vr),lastHour:go});VT=VT.then(()=>yw.mkdir(JT,{recursive:!0})).then(()=>yw.writeFile(`${Kd}.tmp`,n)).then(()=>yw.rename(`${Kd}.tmp`,Kd)).catch(()=>{})}function ZT(e){e-Na<YT||(go={start:Na,total:Vd(vr),byCaller:Object.fromEntries(vr)},go.total&&console.log(`[github] ${go.total} calls last hour`,go.byCaller),Na=e,vr=new Map,XT(e,!0))}function Sr(e="other",t=Date.now()){ZT(t),vr.set(e,(vr.get(e)||0)+1),XT(t)}function QT(e=Date.now()){return ZT(e),{windowStart:Na,total:Vd(vr),byCaller:Object.fromEntries(vr),lastHour:go,backoffUntil:ks>e?ks:null}}function yo(e){return NU.test(String(e?.message||e||""))}function bo(e,t=Date.now()){return ks<=t&&console.warn(`[github] rate limited \u2014 backing off ${GT/6e4} min:`,String(e?.message||e||"").slice(0,200)),ks=Math.max(ks,t+GT),ks}function zd(e=Date.now()){return Math.max(0,ks-e)}var JT,Kd,YT,GT,CU,Na,vr,go,ks,KT,Vd,VT,NU,Oc=G(()=>{JT=process.env.BOSTRAT_STATE_DIR||zT.join(process.env.HOME||MU.tmpdir(),".bostrat"),Kd=zT.join(JT,"github-metrics.json"),YT=60*6e4,GT=5*6e4,CU=6e4,Na=Date.now(),vr=new Map,go=null,ks=0,KT=0,Vd=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(OU.readFileSync(Kd,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<YT?(Na=e.windowStart,vr=new Map(Object.entries(e.byCaller||{})),go=e.lastHour||null):Vd(new Map(Object.entries(e.byCaller||{})))&&(go={start:e.windowStart,total:Vd(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}VT=Promise.resolve();NU=/rate limit|too quickly|abuse detection|HTTP 429/i});import eE from"node:fs/promises";import tE from"node:path";import PU from"node:os";function Yd({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};Jd.push(l),Jd.length>BU&&Jd.shift();let u=bw.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)),bw.set(e,u),LU(l),l}async function LU(e){try{await eE.mkdir(nE,{recursive:!0}),await eE.appendFile(DU,JSON.stringify(e)+`
190
- `)}catch{}}function rE(){let e={};for(let[t,n]of bw)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:Jd.slice(-20)}}var nE,DU,BU,Jd,bw,Xd=G(()=>{nE=process.env.BOSTRAT_STATE_DIR||tE.join(process.env.HOME||PU.tmpdir(),".bostrat"),DU=tE.join(nE,"github-latency.ndjson"),BU=100,Jd=[],bw=new Map});import{execFile as jU}from"node:child_process";import{promisify as FU}from"node:util";async function UU(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([Da("git",["-C",e,"rev-parse","HEAD"]),Da("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await N({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function cn(e,t,n={}){let{caller:r="prs",...o}=n,s=await Bn({cwd:e});Sr(r);try{let{stdout:a}=await Da("gh",t,{cwd:e,...HU,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw yo(a)&&bo(a),a}}async function vw(){if(Zd&&Date.now()-Zd.at<6e4)return Zd.data;let e;try{Sr("auth");let t=await Da("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 Li();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return Zd={at:Date.now(),data:e},e}async function WU(e){try{let{stdout:t}=await Da("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function sE(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 kw(e){let t=(e||[]).map(sE),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 Aw(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function iE(e,t){if(!t)return null;let n=await Me(e);if(!n)return null;try{let r=await cn(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 cE(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 lE(e,t){let n=await iE(e,t);return n===null?{...kw([]),unavailable:!0}:kw(cE(n))}function Qd(e,t=kw(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 GU(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)<qU}for(let o of Pa.keys())o.startsWith(`${e}#`)&&!r.has(o)&&Pa.delete(o);return t}async function Ba(e,t){let n=await Ar(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await cn(n.path,["pr","view",String(r),"--json",Sw]);return Qd(JSON.parse(o))}catch(o){if(!Aw(o))throw o;let s=await cn(n.path,["pr","view",String(r),"--json",aE]),a=JSON.parse(s);return Qd(a,await lE(n.path,a.headRefOid))}}async function Kn(e,{caller:t="prs"}={}){try{let n=await cn(e,["pr","list","--json",Sw,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>Qd(r)).sort(oE)}catch(n){if(!Aw(n))throw n;let r=await cn(e,["pr","list","--json",aE,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>Qd(o,await lE(e,o.headRefOid))))).sort(oE)}}function ln(){Mc.clear()}async function zU(e,t){if(!e)return t;for(let n of t){let r=await ft(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 Hd(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await qd(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function uE(){let e=await vw();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await fr())await WU(a.path)&&t.push(a);let n=Date.now(),r=zd(n)>0,o=await Promise.all(t.map(async a=>{let i=Mc.get(a.path),c=i?.pending?VU:KU;if(i&&(r||n-i.at<c))return i.entry;try{let l=await Me(a.path).catch(()=>null),u=GU(a.path,await Kn(a.path,{caller:"tab"}),n);if(await zU(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&&Yd({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 Mc.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:Vn(l)}}})),s=new Set(t.map(a=>a.path));for(let a of Mc.keys())s.has(a)||Mc.delete(a);return{auth:e,repos:o}}async function Ar(e){let t=(await fr()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function xs(e){return ea(e)}async function La(e,t,{method:n="squash"}={}){let r=await Ar(e);if(!Cc.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 Bn({cwd:r.path})).GH_TOKEN){let a=await xm().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await cn(r.path,s)}catch(a){throw new Error(Vn(a))}finally{ln()}return{ok:!0,number:o}}async function Nc(e,t){let n=await Ar(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await cn(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(Vn(s))}finally{ln()}let o=await Me(n.path).catch(()=>null);return o&&await PT(o,r).catch(()=>{}),{ok:!0,number:r}}async function Tw(e,t){let n=await Ar(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await cn(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(Vn(o))}finally{ln()}return{ok:!0,number:r}}function Ew(e){return e.green&&!e.isDraft}function ZU(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 dE(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:Ew(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function pE(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function Pc(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 fE(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(Pc))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function mE(){let e={};for(let[t,n]of xw)e[t]={...n};return e}async function hE(e,{method:t="merge",onMerged:n=null}={}){let r=await Ar(e);if(!Cc.has(t))throw new Error(`invalid merge method: ${t}`);if(xw.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await Kn(r.path)).filter(Ew).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 xw.set(r.path,s),e4(s,o,{listPrs:()=>Kn(r.path),merge:a=>La(r.path,a,{method:t}),sleep:XU,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function QU(e,t){let n=Date.now()+(t.settleMaxMs??YU),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(JU)}}async function e4(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 QU(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: ${Vn(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(!Ew(a)){e.skipped.push({number:a.number,title:a.title,reason:ZU(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:Vn(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),ln()}}async function _w(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await Da("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${Vn(l)}`)}await UU(e);let o=n||"";if((await Bn({cwd:e})).GH_TOKEN){let l=await xm().catch(()=>null);l&&(o=`${o?`${o}
191
-
192
- `:""}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 cn(e,s)}catch(l){throw new Error(Vn(l))}finally{ln()}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 wE(e,t){let n=await Ar(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await cn(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(Vn(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!Aw(i))throw i;let c=await cn(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await iE(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(Vn(i));o=cE(l).map(sE).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=t4(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await cn(n.path,["run","view",c,"--log-failed"]).then(u=>n4(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function t4(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function n4(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
162
+ [\u2026 brief truncated]`}var HL,WL,tS,qL,GL,VL,nS,rS,sS=G(()=>{pd();HL=12,WL=2e3,tS=48e3,qL=30,GL=10;VL=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},nS=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;rS={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."}});function ro(e){let t=e.search(Sh);return(t>=0?e.slice(0,t):e).trim()}function YL(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function XL(e){let t=String(e).trim();return!!(!t||no.test(e)||Sh.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function ZL(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=QL(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function QL(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 aS(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function ej(e,t=""){let n=String(e);if(!lS.test(n))return null;let r=n.replace(/\r/g,"").split(`
163
+ `),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(ss);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&&!no.test(r[u])&&a.push(p)}}if(s.length<2)return null;let i=s.map(u=>({label:ro(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 nj(e,t=""){let n=String(e).replace(/\r/g,"").split(`
164
+ `),r=n.length-1;for(;r>=0&&n[r].trim()==="";)r--;if(r<0||!uS.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(ss);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&&!(tj.test(n[c])||no.test(n[c]));c--){let l=n[c].trim();l&&a.unshift(l)}let i=s.map(c=>({label:ro(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 rj(e,t=""){let n=String(e);if(!/ready to submit your answers/i.test(n))return null;let r=n.replace(/\r/g,"").split(`
165
+ `),o=[];for(let c=0;c<r.length;c++){let l=r[c].match(ss);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 sj(e,t=""){let n=String(e);if(!kh.test(n))return null;let r=n.replace(/\r/g,"").split(`
166
+ `),o=-1;for(let u=r.length-1;u>=0;u--)if(oj.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(ss);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&&!no.test(r[u])&&a.push(p)}}if(s.length<2||!s.some(u=>kh.test(u.label)))return null;let i=s.map(u=>({label:ro(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 Th(e){let t=[];for(let r=0;r<e.length;r++){let o=e[r].match(ss);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 aj(e,t=""){let n=String(e);if(!dS.test(n)||!pS.test(n)||as.test(n))return null;let r=n.replace(/\r/g,"").split(`
167
+ `),o=Th(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:ro(s.label),description:""}))}]}:null}function ij(e,t=""){let n=String(e);if(!fS.test(n)||as.test(n))return null;let r=n.replace(/\r/g,"").split(`
168
+ `),o=Th(r);if(!o)return null;let s=o.map(a=>{let[i,...c]=a.label.split("\xB7");return{label:ro(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 lj(e,t){let n=e[t].trim();for(let r=t+1;r<e.length;r++){let o=e[r].trim();if(!o||!cj.test(o)||Ah.test(e[r]))break;n+=o}return n}function uj(e,t=""){let n=String(e);if(!Ah.test(n)||as.test(n))return null;let r=n.replace(/\r/g,"").split(`
169
+ `),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=lj(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 pj(e,t=""){let n=String(e);if(!xh.test(n)||!dj.test(n)||as.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
170
+ `)].reverse().find(a=>xh.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 fj(e,t=""){let n=String(e);if(!mS.test(n)||as.test(n))return null;let r=n.replace(/\r/g,"").split(`
171
+ `),o=r.flatMap(a=>{let i=a.match(/^\s*(❯\s*)?(Yes, I trust this folder|No, exit)\s*$/);return i?[{cursor:!!i[1],label:i[2]}]:[]}),s=o.length===2&&new Set(o.map(a=>a.label)).size===2&&o.filter(a=>a.cursor).length===1?o:Th(r);return s?{provider:"claude",box:t,multiSelect:!1,cursorIndex:Math.max(0,s.findIndex(a=>a.cursor)),setup:"trust",promptId:`claude:setup:trust:${s.map(a=>a.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:s.map(a=>({label:ro(a.label),description:""}))}]}:null}function mj(e,t=""){let n=String(e);if(as.test(n))return null;let r=n.replace(/\r/g,"").split(`
172
+ `),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(hS);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(no.test(r[l])||Sh.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 hj(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(vh.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 wj(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(fd.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&&(no.test(o)||cS.test(o))?r:null}function gj(e,t){if(!e)return null;for(let n=e.line+1;n<Math.min(t.length,e.line+3);n++){let r=t[n],o=r.replace(/^\s*❯/,"").trim();if(o)return cS.test(o)?{cursor:/^\s*❯/.test(r)}:null}return null}function yj(e,t=""){let n=String(e);if(!iS.test(n)||!vh.test(n))return null;let r=n.replace(/\r/g,"").split(`
173
+ `),o=hj(r);if(!o)return null;let{headerLine:s,chatLine:a,optStart:i,optEnd:c}=o,l=[],u=-1;for(let L=i;L<c;L++){let H=r[L].match(ss);H&&(u<0&&(u=L),l.push({line:L,cursor:!!H[1],checked:H[3]!=null&&H[3]!==" ",hasCheckbox:H[3]!=null,label:H[4].trim(),desc:""}))}if(!l.length)return null;for(let L of l)for(let H=L.line+1;H<Math.min(r.length,L.line+4)&&!(ss.test(r[H])||no.test(r[H]));H++){let R=r[H].trim();if(!(!R||XL(r[H])||fd.test(R))){L.desc=YL(R);break}}let d=wj(l,r),p=l.filter(L=>L!==d&&!fd.test(L.label));if(!p.length)return null;let f=p.some(L=>L.hasCheckbox),w=f?gj(d,r):null,h=w?.cursor?p.length+1:d?.cursor?p.length:Math.max(0,p.findIndex(L=>L.cursor)),y=d&&!fd.test(d.label)?ro(d.label):"",k=s>=0?s+1:0,g=[];for(let L=k;L<u;L++){let H=r[L].trim();H&&!no.test(r[L])&&!/[☐☒]/.test(r[L])&&g.push(H)}let x=g.join(" ")||(s>=0?aS(r[s]):"")||"The agent is asking a question",S=s>=0?ZL(r[s],x):null,_=S?.currentTabLabel||(s>=0?aS(r[s]):""),M=p.map(L=>({label:ro(L.label),description:L.desc,...f?{checked:!!L.checked}:{}})),P=M.map(L=>L.label).join("|"),A=`claude:${S?`q${S.questionIndex+1}/${S.questionTotal}`:"q1/1"}:${_}:${x}:${P}`.slice(0,240),$=S?`claude:ask:${S.tabs.map(L=>L.label).join("|")}`.slice(0,240):A;return{provider:"claude",box:t,multiSelect:f,cursorIndex:h,promptId:A,groupId:$,...d?{custom:!0,customIndex:p.length,customText:y}:{},...w?{commitIndex:p.length+1}:{},dismissable:!0,...S?{questionIndex:S.questionIndex,questionTotal:S.questionTotal,currentTabLabel:S.currentTabLabel,tabs:S.tabs}:{},questions:[{question:x,header:_,multiSelect:f,options:M}]}}function oo(e,t){let n=String(t||"");return n?e==="claude"?iS.test(n)&&vh.test(n)||lS.test(n)||kh.test(n)||uS.test(n.trimEnd().split(`
174
+ `).pop()||"")?!0:as.test(n)?!1:dS.test(n)&&pS.test(n)||fS.test(n)||Ah.test(n)||xh.test(n)||mS.test(n)||hS.test(n.trimEnd().split(`
175
+ `).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)||e==="cursor"&&/Trust this workspace[\s\S]*\[a\]\s*Trust/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 Sn(e,t){return!e||!t?null:e.agent==="claude"?rj(t,e.name)||yj(t,e.name)||ej(t,e.name)||sj(t,e.name)||pj(t,e.name)||uj(t,e.name)||ij(t,e.name)||aj(t,e.name)||fj(t,e.name)||mj(t,e.name)||nj(t,e.name):e.agent==="cursor"||e.agent==="codex"?ov(e.agent,t,e.name):null}async function wS(e){if(!e)return null;let t=await Jt(e.name).catch(()=>"");return Sn(e,t)}function Eh(e,t){if(e?.provider==="cursor"&&e.promptId==="cursor:setup:trust")return["a"];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 gS(e,n))s.push(...o(a,i),"Enter"),a=i;Number.isInteger(e.commitIndex)?s.push(...o(a,e.commitIndex),"Enter"):s.push("Tab","Enter")}else{let a=n.length?n[0]:0;s.push(...o(r,a),"Enter")}return s}function gS(e,t){let n=e?.questions?.[0]?.options||[],r=new Set(t),o=Math.max(n.length,t.length?Math.max(...t)+1:0),s=[];for(let a=0;a<o;a++)!!n[a]?.checked!==r.has(a)&&s.push(a);return s}function yS(e,t,n=""){let r=typeof n=="string"?n.trim():"";if(!r||!e?.custom)return{pre:Eh(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 gS(e,o))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 bS(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 iS,vh,ss,fd,cS,no,Sh,lS,uS,tj,kh,oj,as,dS,pS,fS,Ah,cj,xh,dj,mS,hS,_h=G(()=>{dt();Yu();iS=/to navigate\b.*\bEsc to cancel|Enter to select\b/,vh=/Chat about this/i,ss=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,fd=/^(type something|chat about this|submit|next)\b/i,cS=/^(submit|next)\b/i,no=/^[─—-]{6,}\s*$/,Sh=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;lS=/^\s*Switch model\?\s*$/m;uS=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,tj=/^\s*[─—▔-]{6,}\s*$/;kh=/Resume from summary/i,oj=/^\s*This session is\b/;as=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;dS=/Choose the text style that looks best with your terminal/,pS=/Let's get started\./;fS=/Select login method:/;Ah=/Paste code here if prompted/,cj=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;xh=/OAuth error:/,dj=/Press Enter to retry\./;mS=/Quick safety check:\s+Is this a project you created or one you trust/;hS=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/});function md(e,t,n){if(!e||!t)return null;for(let r of bj)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function xj(e){let t=Ih.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},Ih.set(e,t)),t}function vS(e,t,n=Date.now()){let r=xj(e);if(r.sentAt=r.sentAt.filter(s=>n-s<xS),r.sentAt.length>=kS)return{action:"give-up"};if(n-r.last<kj)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 SS(e,t=Date.now()){let n=Ih.get(e);return n?n.sentAt.filter(r=>t-r<xS).length>=kS:!1}var bj,kj,kS,xS,Ih,$h=G(()=>{bj=[{provider:"claude",id:"login-continue",match(e){return/^claude:setup:continue:/.test(e?.promptId||"")&&e?.setup==="continue"},keys:["Enter"],accept:!0,gate:"login-enter"},{provider:"codex",id:"login-continue",match(e){return e?.promptId==="codex:signin-complete"&&e?.setup==="continue"},keys:["Enter"],accept:!0,gate:"login-enter"},{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||""}
176
+ ${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];kj=5e3,kS=5,xS=3600*1e3,Ih=new Map});function hd(e,t,n){let{state:r,reason:o}=lc(t,n);if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of xc)a-c.at>=TS()&&xc.delete(i);xc.set(e,{busy:r==="busy",at:a})}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=xc.get(e);return s?Date.now()-s.at>=TS()?(xc.delete(e),!1):s.busy:!1}async function vc(e,t){let n={working:!1,prompted:!1};if(!e)return n;let r=await Ne(e,{lines:ze}).catch(()=>"");if(!hd(e,t,r))return rd(t,r)?{working:!0,prompted:!1}:n;if(oo(t,r)){let o=await Jt(e).catch(()=>r),s=Sn({name:e,agent:t},o);if(s)return!md({name:e,agent:t},s,o)||SS(e)?{working:!1,prompted:!0}:{working:!1,prompted:!1}}return{working:!0,prompted:!1}}async function is(e,t){return(await vc(e,t)).working}var TS,xc,va=G(()=>{dt();os();_h();$h();TS=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,xc=new Map});function $j(e){if(e.startsWith("{"))try{let t=JSON.parse(e);return{message:String(t?.message??""),taskId:t?.task_id?String(t.task_id):null}}catch{}return{message:e,taskId:null}}function Oj(e){if(e.type==="queue-operation"&&e.operation==="enqueue")return AS.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"&&AS.test(t)?t:null}async function ES(e,t={}){return(await IS(e,t)).launches}async function _S(e,t={}){let{launches:n,done:r}=await IS(e,t);return n.filter(o=>!r.has(o.id))}async function IS(e,{maxBytes:t=2097152,limit:n=100}={}){let r;try{r=await jt(e,t)}catch{return{launches:[],done:new Set,stopped:new Map}}let o=new Map,s=new Set,a=new Set,i=new Map,c=new Map,l=new Map,u=new Map;for(let p of r.split(`
177
+ `)){let f=p.trim();if(!f||f[0]!=="{")continue;let w;try{w=JSON.parse(f)}catch{continue}if(w.isSidechain)continue;let h=Oj(w);if(h){let g=h.match(Rj)?.[1]?.trim();g&&a.add(g);continue}let y=w.message?.content;if(!Array.isArray(y))continue;let k=w.timestamp?Date.parse(w.timestamp):null;for(let g of y)if(!(!g||typeof g!="object")){if(g.type==="tool_use"&&g.id){if(g.name==="Agent"){let x=g.input||{};o.set(g.id,{id:g.id,kind:"agent",name:String(x.description||"").trim()||null,detail:String(x.subagent_type||"").trim()||null,ts:k,proven:!1})}else if(g.name==="Bash"){let x=String(g.input?.command||"").trim(),S={id:g.id,kind:"command",name:String(g.input?.description||"").trim()||(x?ha(x):null),detail:x?ha(x):null,ts:k,proven:g.input?.run_in_background===!0};S.proven?o.set(g.id,S):c.set(g.id,S)}else if(_j.has(g.name)){let x=g.input?.task_id??g.input?.shell_id??g.input?.bash_id;x&&u.set(g.id,{taskId:String(x),ts:k})}}else if(g.type==="tool_result"&&g.tool_use_id){let x=Mj(g.content);if(vj.test(x)){s.add(g.tool_use_id);let P=x.match(Ej)?.[1];P&&l.set(P,g.tool_use_id)}let S=x.match(Aj)?.[1];S&&l.set(S,g.tool_use_id);let _=x.match(Sj);if(_){l.set(_[1].trim(),g.tool_use_id);let P=c.get(g.tool_use_id);P&&(c.delete(g.tool_use_id),P.proven=!0,P.outputFile=x.match(Tj)?.[1]?.replace(/\.$/,"")||null,o.set(P.id,P))}let M=u.get(g.tool_use_id);if(M){u.delete(g.tool_use_id);let{message:P,taskId:j}=$j(x);if(!g.is_error&&Ij.test(P)){let A=l.get(M.taskId)??(j?l.get(j):void 0);A&&(a.add(A),i.set(A,k??M.ts??null))}}}}}let d=[];for(let p of o.values()){if(!p.proven&&!s.has(p.id))continue;let{proven:f,...w}=p;w.stoppedTs=i.has(p.id)?i.get(p.id):null,d.push(w)}return{launches:d.slice(-n),done:a,stopped:i}}var vj,Sj,Tj,Aj,Ej,_j,Ij,AS,Rj,Mj,$S=G(()=>{vn();wa();vj=/^Async (?:agent|task) launched/i,Sj=/^Command did not complete within its [^\n]*?moved to the background \(ID: ([^)]+)\)/i,Tj=/Output is being written to:\s*(\S+)/i,Aj=/^Command running in background with ID:\s*([^\s.]+)/i,Ej=/\bagentId:\s*([A-Za-z0-9_-]+)/,_j=new Set(["TaskStop","KillShell"]),Ij=/^Successfully (?:stopped|killed)\b/i;AS=/^\s*<task-notification>/i,Rj=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i;Mj=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 so(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 Cj(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 RS(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:Tn(`read ${so(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${Sa(r)}`:`Read ${Sa(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?so(t.path,n):null,s=t?.glob?` --glob ${Rh(t.glob)}`:"",a=Tn(String(r),40);return{command:Tn(`grep ${Rh(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?so(t.target_directory,n):null;return{command:Tn(`glob ${Rh(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${Tn(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:Tn(`edit ${so(t.path,n)}`,140),description:`Edit ${Sa(t.path)}`}:null;case"Write":return t?.path?{command:Tn(`write ${so(t.path,n)}`,140),description:`Write ${Sa(t.path)}`}:null;case"Delete":return t?.path?{command:Tn(`delete ${so(t.path,n)}`,140),description:`Delete ${Sa(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>so(s,n)).filter(Boolean);return{command:Tn(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=Cj(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:Tn(`apply_patch ${so(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${Sa(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:Tn(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var wd,Tn,Sa,Rh,OS=G(()=>{wd=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),Tn=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,Sa=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);Rh=e=>`"${String(e).replace(/"/g,'\\"')}"`});import Sc from"node:fs";import Nj from"node:fs/promises";import cs from"node:path";import Pj from"node:os";import Dj from"node:crypto";import Bj from"node:zlib";function NS(e){let t=Dj.createHash("md5").update(String(e)).digest("hex");return cs.join(Lj,t)}function PS(e){try{let t=JSON.parse(Sc.readFileSync(cs.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 jj(e){let t=NS(e),n;try{n=Sc.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=cs.join(t,o.name),a=cs.join(s,"store.db");if(!Sc.existsSync(a))continue;let i=PS(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 gd(e,t){if(!e)return null;if(t){let n=cs.join(NS(e),t),r=cs.join(n,"store.db");if(Sc.existsSync(r))return{id:t,dir:n,store:r,...PS(n)||{createdAtMs:null,updatedAtMs:null}}}return jj(e)}function MS(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function Fj(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=Bj.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function Uj(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 Hj(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!wd.has(r.toolName))continue;let o=RS(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 Oh(e,t){if(!CS)return Ta;let{DatabaseSync:n}=CS,r;try{r=new n(e,{readOnly:!0})}catch{return Ta}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 Ta;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return Ta}let a=s.lastUsedModel||null,i=s.latestRootBlobId?MS(r,s.latestRootBlobId):null;if(!i)return{...Ta,model:a};let c=[],l=[],u=[],d=null,p=[];for(let f of Uj(i)){let w=Fj(MS(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 g of w.content){let x=g?.providerOptions?.cursor?.modelName;x&&(d=x)}l.push(...Hj(w.content,t).map((g,x)=>({...g,id:g.id||`${f}:${x}`}))),u.push(...qj(w.content));let y=Wj(w.content);if(!y)continue;let k=[...new Set(u)];u=[],c.push({id:f,text:y,tools:k.length?k:void 0,commands:l,model:d}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:p}}catch{return Ta}finally{try{r.close()}catch{}}}function DS(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(Sc.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 BS(e,t,{limit:n=80}={}){let r=gd(e,t);if(!r)return[];let{turns:o,model:s}=await Oh(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=DS(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 LS(e,t){let n=gd(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await Oh(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 jS(e,t,{limit:n=80}={}){let r=gd(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await Oh(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=DS(r,a.length||1),l=[];a.forEach((u,d)=>{for(let p of u.commands)l.push({...p,summary:Qr(p.command,p.description),ts:c(d)})});for(let u of s)l.push({...u,summary:Qr(u.command,u.description),ts:i+1});return l}async function FS(e,t){let n=gd(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await Nj.stat(n.store)).mtimeMs)}catch{return null}}var Lj,Wj,qj,CS,Ta,Mh=G(()=>{wa();OS();Lj=process.env.BOSTRAT_CURSOR_CHATS||cs.join(Pj.homedir(),".cursor","chats");Wj=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(`
178
+ `).trim():"",qj=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],CS=process.getBuiltinModule?.("node:sqlite"),Ta={turns:[],trailingCommands:[],model:null,requestIds:[]}});import Gj from"node:fs/promises";function Dh(e){return US.set(e.agent,e),e}function ao(e){return US.get(e)||Kj}async function Bh(e,t={}){return(await ao(e.agent).readMessages(e,t)).map(yd(e))}async function HS(e,t={}){return(await ao(e.agent).readCommands(e,t)).map(yd(e))}async function WS(e,t={}){return(await ao(e.agent).readJobs(e,t)).map(yd(e))}async function bd(e,t={}){return(await ao(e.agent).readOpenJobs(e,t)).map(yd(e))}var Aa,Ch,Nh,Ph,Kj,US,yd,kd=G(()=>{vn();zu();wa();$S();Mh();es();Aa=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}},Ch=class extends Aa{transcript(t){return!t?.cwd||!t?.sessionId?null:xn(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?rh(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?Hx(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?ES(r,n):[]}async readOpenJobs(t,n){let r=this.transcript(t);return r?_S(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await Gj.stat(n)).mtimeMs)}catch{return null}}},Nh=class extends Aa{async readMessages(t,n){return BS(t.cwd,t.sessionId,n)}async readCommands(t,n){return jS(t.cwd,t.sessionId,n)}async updatedAt(t){return FS(t.cwd,t.sessionId)}},Ph=class extends Aa{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return Kx(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return Vx(t.cwd,this.sessionId(t),n)}async updatedAt(t){return zx(t.cwd,this.sessionId(t))}},Kj=new Aa("unknown"),US=new Map;Dh(new Ch("claude",Zm));Dh(new Nh("cursor",wd));Dh(new Ph("codex",sc));yd=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function Lh(e){if(!e)return"the current turn";let t=[];e.prompted?t.push("an unanswered prompt"):e.busy?t.push("the current turn"):e.unknown&&t.push("a pane too narrow to read"),e.awaitingBackground&&t.push("a background wait");let n=Array.isArray(e.jobs)?e.jobs:[];if(n.length){let r=n.slice(0,2).map(o=>o.name||o.id).filter(Boolean);t.push(`${n.length} background job${n.length===1?"":"s"}${r.length?` (${r.join(", ")}${n.length>r.length?", \u2026":""})`:""}`)}return t.length?t.join(" and "):"the current turn"}async function qS(e,{timeoutMs:t,reason:n=null,onWait:r=null,deps:o=null}={}){let s={...Xj,...o||{}},a=e?.name,i=e?.agent||null;if(!a)throw new Error("awaitQuiescence: box.name is required");let c=Number(t)||Vj(),l=zj(),u=s.now(),d=0,p=0,f=!1,w=null;for(;;){p++;let h=await s.capture(a),y=s.busyRead(i,h);if(y.reason==="blocked"){let g=new Error(`${i||"the agent"} in "${a}" is sitting at a login or trust gate \u2014 answer it in the terminal, then retry`);throw g.code="quiescence-blocked",g.detail={blocked:!0},g}if(w={busy:y.state==="busy",unknown:y.state==="unknown",awaitingBackground:s.awaitingBackground(i,h),prompted:!1,jobs:[]},w.busy){let g=await s.turnState(a,i).catch(()=>({prompted:!1}));w.prompted=g?.prompted===!0}if(!w.busy&&!w.unknown&&!w.awaitingBackground){let g=await s.openJobs(e).catch(()=>[]);w.jobs=(Array.isArray(g)?g:[]).map(x=>({id:x.id??null,name:x.name??null,kind:x.kind??null}))}let k=!w.busy&&!w.unknown&&!w.awaitingBackground&&!w.prompted&&w.jobs.length===0;if(d=k?d+1:0,d>=Jj){let g=s.now()-u;return f&&ee({flow:"quiescence",phase:"quiet",sessionName:a,agent:i,reason:n,waitedMs:g,reads:p}).catch(()=>{}),{waitedMs:g,reads:p,waited:f,detail:w}}if(!k&&!f&&(f=!0,ee({flow:"quiescence",phase:"waiting",sessionName:a,agent:i,reason:n,detail:w}).catch(()=>{}),r&&await r(w)),s.now()-u>=c){let g=new Error(`waited ${Math.round(c/1e3)}s for ${Lh(w)} in "${a}" to finish`);throw g.code="quiescence-timeout",g.detail=w,g.waitedMs=s.now()-u,ee({flow:"quiescence",phase:"timeout",sessionName:a,agent:i,reason:n,waitedMs:g.waitedMs,reads:p,detail:w,error:g.message}).catch(()=>{}),g}await s.sleep(l)}}var Vj,zj,Jj,Yj,Xj,GS=G(()=>{dt();os();va();kd();yn();Vj=()=>Number(process.env.BOSTRAT_QUIESCENCE_TIMEOUT_MS)||6e5,zj=()=>Number(process.env.BOSTRAT_QUIESCENCE_POLL_MS)||1500,Jj=2,Yj=e=>new Promise(t=>setTimeout(t,e)),Xj={capture:e=>Ne(e,{lines:ze}),busyRead:lc,awaitingBackground:rd,turnState:vc,openJobs:bd,now:()=>Date.now(),sleep:Yj}});import Zj from"node:fs";import io from"node:fs/promises";import co from"node:path";function eT(e){let t=Wo(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=KS?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,KS).toString("utf8").replace(/�+$/,"")}
179
+
180
+ [\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function iF(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(zS.test(s)){if(r.length>=aT)continue;let a=aF(s.replace(zS,"").replace(/[.;,:]+$/,""),iT,oF);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>VS&&(o=`${o.slice(0,VS-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function cT(e,t,{timeoutMs:n=9e4}={}){let r=co.join(t,nF),o=co.join(r,rF);await io.mkdir(r,{recursive:!0});let s=await xd(o),a=await Se(e);if(!a)throw new Error(`session "${e}" not found`);return await vd(e,a,sF(o)),await hT(o,s,n),iF(await io.readFile(o,"utf8"))}function lT(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===nT||n===sT;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(tT)||n===Qj||r.startsWith(rT)||r.startsWith(oT)}function uT(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-cF;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 dT(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 pT(e,{windows:t=[]}={}){if(lT(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 Sd(e){return jh.get(e)||null}async function fT(e){let t=jh.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await Se(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:co.join(n.cwd,ZS,QS)};return jh.set(e,r),dF(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function dF(e,t){e.step="summarize",await mT(e.name,t,{quiesce:{reason:"console-checkpoint",onWait:r=>{e.step="await-turn",e.wait=r},onResume:()=>{e.step="summarize"}}}),e.step="clear";let n=await Se(e.name);await vd(e.name,n,"/clear"),await Uh(lF),e.step="resume",await vd(e.name,n,tF),e.step="done",e.finishedAt=Date.now()}async function JS(e,t,n,r){if(!r)return{outcome:"skipped"};let o=r.box||{name:t,agent:n?.agent??null,cwd:n?.cwd??null,sessionId:n?.sessionId??null},s=r.reason?`${r.reason}:${e}`:e,a=!1;try{let i=await qS({...o,name:t},{timeoutMs:r.timeoutMs,reason:s,onWait:async c=>{a=!0,r.onWait&&await r.onWait(c,e)}});return a&&r.onResume&&await r.onResume(e),{outcome:"ok",waitedMs:i.waitedMs,waited:i.waited}}catch(i){if(i?.code!=="quiescence-timeout"||(r.onTimeout||pF)===fF)throw i;return await ee({flow:"checkpoint",phase:"quiescence-timeout",sessionName:t,gate:e,waitedMs:i.waitedMs,detail:i.detail,still:Lh(i.detail),paneTail:!0}),r.onResume&&await r.onResume(e),{outcome:"timeout",waitedMs:i.waitedMs,waited:!0,detail:i.detail}}}async function mT(e,t,{timeoutMs:n=uF,quiesce:r=null}={}){let o=co.join(t,ZS),s=co.join(o,QS);await io.mkdir(o,{recursive:!0});let a=await Se(e),i=await JS("pre-drive",e,a,r),c=await xd(s);await ee({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:s,beforeMtime:c,quiescence:i.outcome,waitedMs:i.waitedMs});try{await vd(e,a,eF(s)),await hT(s,c,n)}catch(f){throw f&&typeof f=="object"&&(f.quiescence={pre:i,post:{outcome:"skipped"}}),f}let l=await JS("post-write",e,a,r);await ee({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:s,afterMtime:await xd(s),quiescence:l.outcome,waitedMs:l.waitedMs});let u=await Cv(t,s,{exclude:f=>lT(f.role,f.text)});await ee({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:s,...u});let d=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(d){await N({id:d,cwd:t},{type:"memory.seed",actor:"orchestrator",payload:{...u,tokensEst:u.chars?Math.round(u.chars/4):0,ts:Date.now()}}).catch(()=>{});try{let f=await io.readFile(s,"utf8");await N({id:d,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...eT(f),ts:Date.now()}})}catch{}}await Om(t);let p=await mF(o,s);return d&&await fx(d,p||s,{box:e,agent:a?.agent??null}),{file:s,quiescence:{pre:i,post:l}}}async function Td(e,{timeoutMs:t,quiesce:n=null}={}){let r=await Se(e);if(!r)throw new Error(`session "${e}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${e}"`);return mT(e,r.cwd,{...t?{timeoutMs:t}:{},quiesce:n})}function Fh(e){let t=e?.quiescence;if(!t)return null;let n=[t.pre?.outcome,t.post?.outcome].filter(r=>r&&r!=="skipped");return n.length?n.includes("timeout")?"timeout":"ok":null}async function Ad(e,t,{trackName:n="this Track"}={}){let r=await K({id:e,cwd:t}),o=oS(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=co.join(t,YS);return await io.mkdir(co.dirname(s),{recursive:!0}),await io.writeFile(s,o,"utf8"),await N({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...eT(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),YS}async function xd(e){try{return(await io.stat(e)).mtimeMs}catch{return 0}}async function hT(e,t,n){let r=Date.now()+n;for(;;){if(await xd(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await Uh(2e3)}}async function mF(e,t){try{if(!Zj.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=co.join(e,`${n}.md`);return await io.copyFile(t,r),r}catch{return null}}function Uh(e){return new Promise(t=>setTimeout(t,e))}function XS(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 vd(e,t,n){if(t){let o=XS(t.agent);await wr({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await Se(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await Ke(e,["Escape"],{kind:"drive-wipe"}),await Uh(150),await da(e,Wu,{kind:"drive-wipe"}),await Qe(e,n,{kind:"orchestration-drive",...Un(r.agent,n)}),await wc({sessionName:e,agent:r.agent,agentCmd:XS(r.agent),text:n,flow:"orchestration-drive"})}var ZS,QS,KS,tT,nT,rT,Qj,eF,tF,oT,sT,nF,rF,VS,aT,iT,oF,sF,zS,aF,cF,lF,uF,jh,pF,fF,YS,Hh=G(()=>{dt();os();yn();pc();ch();Nv();Wi();be();Pu();sS();GS();ZS=".bostrat/handoff",QS="latest.md",KS=32*1024;tT="Checkpoint: write a work-in-progress handoff",nT="HANDOFF WRITTEN",rT="Resume from .bostrat/handoff/latest.md",Qj="/clear",eF=e=>`${tT} 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 ${nT} and take no further action.`,tF=`${rT}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,oT="Beat: write a",sT="BEAT WRITTEN",nF=".bostrat/arc",rF="beat.txt",VS=200,aT=4,iT=5,oF=36,sF=e=>`${oT} 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 ${aT} further lines, each starting with "- " and naming ONE piece in at most ${iT} 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 ${sT} and take no further action.`,zS=/^(?:[-–—*•·]|\d+[.)])\s+/,aF=(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};cF=6e5;lF=3500,uF=3e5,jh=new Map;pF="proceed",fF="reject";YS=".bostrat/handoff/status-latest.md"});function uo(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!Ed.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 yT(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:uo(o.from,"from",n),toMs:uo(o.to,"to",n)}))}return t}function qh(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 wF(e){if(!e)return null;let t=String(e).trim();if(lo[t])return t;if(wT[t])return wT[t];let n=null;for(let r of Object.keys(lo))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function gF(e){if(!e||e===lo)return hF;let t=gT.get(e);return t||(t=yT(e),gT.set(e,t)),t}function bT(e,t,n={}){let{table:r,speed:o}=n,s=gF(r),a=r&&r!==lo?s[e]?e:null:wF(e);if(!a)return null;let i=qh(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 Wn(e,t={},n,r){let o=bT(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 yF(e=lo){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:uo(a.from,"from",n),toMs:uo(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`),Ed.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 kF({now:e=Date.now(),table:t=lo,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...bF,...n},a=[],i=qh(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:uo(d.from,"from",c),toMs:uo(d.to,"to",c),verifiedMs:Ed.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*Wh;p&&i-d.verifiedMs>r*Wh&&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*Wh&&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=lo,...n}={}){let r=qh(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=uo(l.from,"from",i),d=uo(l.to,"to",i);r>=u&&r<=d&&Ed.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=[...yF(t),...kF({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var lo,wT,Ed,hF,gT,kT,bF,Wh,yr=G(()=>{lo={"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-1":[{from:null,to:null,input:10,output:50,cacheWrite:20,cacheRead:.25,cacheReadX:.025,verifiedAt:"2026-09-07",note:"verified 2026-09-07 against platform.claude.com/docs/en/about-claude/pricing: $10/$50, 1h cache write $20 (2\xD7), cache hits $0.25 (0.025\xD7 \u2014 the 5.1-only multiplier; footnote 1 on the 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)."}],"gpt-6-astra":[{from:null,to:null,input:10,output:50,cacheWrite:12.5,cacheRead:1,fast:{input:20,output:100,cacheWrite:25,cacheRead:2},verifiedAt:"2026-09-07",note:"verified 2026-09-07 (developers.openai.com pricing); cacheWrite = 1.25\xD7 input; fast tier $20/$100 recorded as the fast variant (codex reports no speed)."}]},wT={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-1","gpt-5.6":"gpt-5.6-sol"},Ed=/^\d{4}-\d{2}-\d{2}$/;hF=yT(lo);gT=new WeakMap;kT=(e,t,n)=>bT(e,t,n)!==null;bF=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),Wh=864e5});function xF(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function vT(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function sn(e){let t=e.payload?.model||"unknown",n=xF(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=Wn(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&&!kT(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function po(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=xT();for(let p of n){let{usd:f,model:w,tokens:h,repriced:y,unpriced:k,asRecorded:g}=sn(p);i+=g;let x=p.provider||"unknown",S=p.boxId||"unattributed";if(y&&c++,k&&(l++,u.add(w)),a+=f,vT(d,h),r[w]||={usd:0,tokens:xT(),events:0},r[w].usd+=f,r[w].events+=1,vT(r[w].tokens,h),o[x]||={usd:0,events:0},o[x].usd+=f,o[x].events+=1,s[S]||={usd:0,events:0,provider:x,models:new Set,label:t[S]||S},s[S].usd+=f,s[S].events+=1,w!=="unknown"&&s[S].models.add(w),p.epoch!=null){let _=(s[S].epochs||={})[p.epoch]||={usd:0,events:0,provider:x,models:new Set};_.usd+=f,_.events+=1,_.provider=x,w!=="unknown"&&_.models.add(w)}}return{totalUsd:_a(a),asRecordedUsd:_a(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:_d(r,p=>({...p,usd:_a(p.usd)})),byProvider:_d(o,p=>({...p,usd:_a(p.usd)})),byBox:_d(s,p=>({usd:_a(p.usd),events:p.events,provider:p.provider,label:p.label,models:[...p.models],...p.epochs?{epochs:_d(p.epochs,f=>({usd:_a(f.usd),events:f.events,provider:f.provider,models:[...f.models]}))}:{}}))}}var xT,_a,_d,fo=G(()=>{yr();xT=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});_a=e=>Math.round(e*1e4)/1e4,_d=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function vF(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 ST(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(Gh(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(Gh(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(`${Gh(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=po(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?vF(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var Gh,TT=G(()=>{fo();Gh=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as SF}from"node:child_process";import{promisify as TF}from"node:util";import{randomUUID as AF}from"node:crypto";import AT from"node:fs/promises";async function Kh(e,t){let n=Date.now()+t;for(;;){if(await Fn(e))return!0;if(Date.now()>n)return!1;await us(RT)}}function OF(e){let t=String(e||"").split(`
181
+ `).map(n=>n.trimEnd()).filter(n=>n.trim());return!t.length||!IF.test(t[t.length-1])?!1:_F.test(t.slice(-$F).join(`
182
+ `))}async function MF(e,t){if(t!=="claude")return null;let n=Date.now()+RF;for(;;){if(await Fn(e))return null;let r=await Ne(e,{lines:30});if(OF(r))return await ee({flow:"swap",phase:"exit-chooser",sessionName:e,from:t,paneTail:!0}),await Ke(e,["Enter"],{kind:"swap-exit"}),"answered";if(Date.now()>n)return null;await us(RT)}}async function CF(e,t){let n=ET[t]||ET.default;n.escape&&(await Ke(e,["Escape"],{kind:"swap-exit"}),await us(150)),n.wipe&&await da(e,Wu,{kind:"swap-exit"}),await qu(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=Un(t).submitDelayMs||0;return await us(Math.max(r,250)),await Ke(e,["Enter"],{kind:"swap-exit"}),{chooser:await MF(e,t)}}async function BF(e,{settleMs:t=NF,timeoutMs:n=PF,parse:r=!0}={}){let o=Date.now(),s=null,a=null;for(;;){let i=null,c=!0;try{let u=await AT.stat(e);i=`${u.mtimeMs}:${u.size}`}catch{c=!1}if(!c)return{settled:!0,waitedMs:Date.now()-o,parsed:null,missing:!0};let l=Date.now();if(i!==s)s=i,a=l;else if(l-a>=t){let u=null;if(r)try{JSON.parse(await AT.readFile(e,"utf8")),u=!0}catch{u=!1}if(u!==!1)return{settled:!0,waitedMs:l-o,parsed:u};a=l}if(l-o>=n)return{settled:!1,waitedMs:l-o,parsed:null};await us(DF)}}async function _T(e,t){try{let{stdout:n}=await ls(oe,se("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function OT(e){await ls(oe,se("respawn-pane","-k","-t",e))}async function Vh(e,{exitTimeoutMs:t=IT,fromAgent:n=null}={}){if(!je(e))throw new Error("invalid session name");let r=!1;if(await Fn(e))return{forced:r,chooser:null};let o=n||(await Se(e))?.agent||"agent",{chooser:s}=await CF(e,o),a=await Kh(e,t);if(await ee({flow:"swap",phase:"exit",sessionName:e,from:o,graceful:a,chooser:s,paneTail:!0}),!a&&(r=!0,await ee({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await OT(e),!await Kh(e,$T)))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);return{forced:r,chooser:s}}async function zh(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 Se(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||Xr(n),a=Number(t.exitTimeoutMs)||IT;if(await ee({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd}),s==="codex"){let k=await fu();k.waited&&await ee({flow:"cli-currency",phase:"spawn-gate",sessionName:e,...k}),mu(e)}let{forced:i,chooser:c}=await Vh(e,{exitTimeoutMs:a,fromAgent:o});if(o==="claude"){let k=await BF(cm());await ee({flow:"swap",phase:"config-settled",sessionName:e,from:o,...k})}let l=s==="claude"&&Yo(n),u=l?iu():null,d=await _T(e,"ANTHROPIC_API_KEY"),p=!1;try{u?(await ls(oe,se("set-environment","-t",e,"ANTHROPIC_API_KEY",u)),p=!0):d&&(await ls(oe,se("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),p=!0)}catch(k){throw u?Bu(k,u):k}if(p&&!i&&(await OT(e),!await Kh(e,$T)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let f=!!t.resumeSessionId,w=t.resumeSessionId||AF(),h=f?n:Zi(n,w,e),y=f?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(h);return l&&await Wr(r.cwd),s==="codex"&&await Xs(r.cwd),s==="cursor"&&await Qs(r.cwd),await Xo(e),await ls(oe,se("set-option","-t",e,"@bostrat-sid",w)),await ls(oe,se("set-option","-t",e,"@bostrat-agent",s)),await us(EF),l&&Xi().length&&(await _T(e,Yi)||await ls(oe,se("set-environment","-t",e,Yi,"1")).catch(()=>{}),await Qe(e,`export ${Yi}=1`,{kind:"swap-env"}),await us(150)),await Qe(e,h,{kind:"swap-launch"}),await ee({flow:"swap",phase:"launched",sessionName:e,from:o,to:s,paneTail:!0}),await ee({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:w,forced:i,chooser:c,envRespawned:p}),{name:e,cwd:r.cwd,sessionId:w,agent:s,pinned:y,forced:i,chooser:c,envRespawned:p,launchCmd:h}}var ls,us,IT,$T,RT,EF,ET,_F,IF,$F,RF,NF,PF,DF,MT=G(()=>{dt();$i();lu();qo();hu();pc();yn();ls=TF(SF),us=e=>new Promise(t=>setTimeout(t,e)),IT=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,$T=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,RT=250,EF=400,ET={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"}};_F=/Background work is running/,IF=/Enter to confirm\s*·\s*Esc to cancel/,$F=12,RF=Number(process.env.BOSTRAT_SWAP_CHOOSER_WAIT_MS)||3e3;NF=Number(process.env.BOSTRAT_CLAUDE_CONFIG_SETTLE_MS)||500,PF=Number(process.env.BOSTRAT_CLAUDE_CONFIG_SETTLE_TIMEOUT_MS)||5e3,DF=100});function Jh(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}async function Yh({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!Jh(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),CT);try{let a=await NT(`${De(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 Tc(e,{provider:t=null,cls:n="other",status:r=null,text:o="",note:s=null}={},{env:a=process.env,now:i=Date.now}={}){if(!e?.id||!String(e.name||"").startsWith("\u21BB"))return{ok:!1,source:"not-a-loop-track"};if(!Jh(a))return{ok:!1,source:"unconfigured"};let c=Id.get(e.id)||0;if(i()-c<LF)return{ok:!1,source:"debounced"};Id.set(e.id,i());let l=await Ac({env:a}),u=l.loops.find(f=>f.trackId===e.id);if(!u)return Id.delete(e.id),{ok:!1,source:l.source==="plane"?"no-loop":l.source};let d=s?String(s).replace(/\s+/g," ").trim():`${t||"provider"} ${r?r+" ":""}${n}: ${String(o||"").replace(/\s+/g," ").trim()}`,p=await Yh({loopId:u.id,outcome:"errored",note:d.slice(0,500),env:a});return p.ok||Id.delete(e.id),{...p,loop:{id:u.id,name:u.name}}}async function Ac({env:e=process.env}={}){if(!Jh(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),CT);try{let r=await NT(`${De(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 CT,NT,LF,Id,$d=G(()=>{xt();CT=1e4,NT=(...e)=>fetch(...e);LF=10*6e4,Id=new Map});import{execFile as jF}from"node:child_process";import Rd from"node:fs/promises";import Xh from"node:path";import{promisify as FF}from"node:util";function VF(e){let n=String(e||"").trim().match(/\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]+)?/);return n?n[0]:null}async function zF(e,{env:t=process.env}={}){let n=String(e||"").trim();if(!n)return null;let r=n.includes("/")?[Xh.resolve(n)]:String(t.PATH||"").split(Xh.delimiter).filter(Boolean).map(o=>Xh.join(o,n));for(let o of r)try{await Rd.access(o,Rd.constants.X_OK);let s=await Rd.realpath(o),a=await Rd.stat(s);if(!a.isFile())continue;return{path:s,mtimeMs:a.mtimeMs}}catch{}return null}async function ds({agent:e=null,agentCmd:t=null,env:n=process.env}={}){let r=String(t||(e?n[qF[e]]||WF[e]:"")||"").trim();if(!r)return null;let{realClaude:o,realCodex:s,realCursor:a}=dc({agent:e,agentCmd:r});if(!(o||s||a))return null;let i=await zF(r.split(/\s+/)[0],{env:n});if(!i)return null;let c=`${i.path}@${i.mtimeMs}`;return Zh.has(c)||Zh.set(c,Promise.resolve().then(()=>KF(i.path,{agent:e})).then(l=>VF(l)).catch(()=>null)),Zh.get(c)}var UF,HF,WF,qF,Zh,GF,KF,PT=G(()=>{os();UF=FF(jF),HF=8e3,WF={claude:"claude",codex:"codex",cursor:"cursor-agent"},qF={claude:"BOSTRAT_AGENT_CMD",codex:"BOSTRAT_CODEX_CMD",cursor:"BOSTRAT_CURSOR_CMD"},Zh=new Map,GF=async e=>(await UF(e,["--version"],{timeout:HF})).stdout,KF=GF});function Ia(e){return typeof e=="string"?e.trim():""}var DT=G(()=>{});import{execFile as JF}from"node:child_process";import{promisify as YF}from"node:util";async function Ye(e,t,{input:n}={}){let r=ew("git",["-C",e,...t],{maxBuffer:BT});return n!==void 0&&r.child.stdin&&(r.child.stdin.on("error",()=>{}),r.child.stdin.end(n)),r}async function $a(e){if(!e)return!1;try{let{stdout:t}=await Ye(e,["rev-parse","--is-inside-work-tree"]);return t.trim()==="true"}catch{return!1}}async function LT(e){let{stdout:t}=await Ye(e,["rev-parse","--show-toplevel"]);return t.trim()}async function XF(e){try{return await Ye(e,["rev-parse","--verify","HEAD"]),!0}catch{return!1}}async function Ra(e,t="bostrat: subtask snapshot"){let{stdout:n}=await Ye(e,["rev-parse","--absolute-git-dir"]),r=`${n.trim()}/bostrat-snapshot-index`,o={...process.env,GIT_INDEX_FILE:r},s=(a,i)=>ew("git",["-C",e,...a],{maxBuffer:BT,env:o,...i});try{let a=await XF(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 ew("rm",["-f",r])}catch{}}}async function tw(e,t,{trailers:n=[]}={}){let{stdout:r}=await Ye(e,["status","--porcelain"]);return r.trim()?(await Ye(e,["add","-A"]),await Ye(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","-m",t,...n.flatMap(o=>["--trailer",o])]),!0):!1}async function ps(e,{ignorePlumbing:t=!1}={}){let{stdout:n}=await Ye(e,["status","--porcelain"]),r=n.split(`
183
+ `).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 fs(e,t){if(!t)return 0;try{let{stdout:n}=await Ye(e,["rev-list","--count",`${t}..HEAD`]);return Number(n.trim())||0}catch{return 0}}async function ms(e,t,n,r){return await Ye(e,["worktree","add","--no-track","-b",n,t,r]),t}async function nw(e,t){try{return await Ye(e,["rev-parse","--verify","--quiet",`refs/heads/${t}`]),!0}catch{return!1}}async function Ec(e,t,n){return await Ye(e,["worktree","add","--end-of-options",t,n]),t}async function hs(e){if(process.env.BOSTRAT_TRACK_BASE_REF)return process.env.BOSTRAT_TRACK_BASE_REF;try{let{stdout:t}=await Ye(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 Ye(e,["rev-parse","--verify","--quiet",t]),n}catch{}return"HEAD"}async function rw(e){await Ye(e,["init","-q"]),await Ye(e,["-c","user.email=agent@bostrat.local","-c","user.name=bostrat","commit","--allow-empty","-qm","bostrat: track workspace"])}async function $t(e,t){try{await Ye(e,["worktree","remove","--force",t])}catch{try{await Ye(e,["worktree","prune"])}catch{}}}function ZF(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 ow(e,t){return!t||!t.length?e:[...e,"--",".",...t.map(n=>`:(exclude)${n}`)]}async function sw(e,t,n,r){let{stdout:o}=await Ye(e,ow(["diff","--shortstat",t,n],r));return ZF(o)}async function aw(e,t,n,r){let{stdout:o}=await Ye(e,ow(["diff","--name-only",t,n],r));return o.split(`
184
+ `).map(s=>s.trim()).filter(Boolean)}async function iw(e,t,n,r){let{stdout:o}=await Ye(e,ow(["diff","--binary",t,n],r));if(!o.trim())return{applied:!0,empty:!0,conflicts:[]};if((await Qh(e,o,["--whitespace=nowarn"])).ok)return{applied:!0,empty:!1,conflicts:[]};let s=await Qh(e,o,["--3way","--whitespace=nowarn"]),a=await QF(e);return a.length>0?{applied:!1,empty:!1,conflicts:a}:s.ok?{applied:!0,empty:!1,conflicts:[]}:(await Qh(e,o,["--reject","--whitespace=nowarn"]),{applied:!1,empty:!1,conflicts:[`patch did not apply cleanly: ${s.err}`]})}async function Qh(e,t,n){try{return await Ye(e,["apply",...n,"-"],{input:t}),{ok:!0}}catch(r){return{ok:!1,err:r?.stderr?.trim()||r?.message||String(r)}}}async function QF(e){try{let{stdout:t}=await Ye(e,["diff","--name-only","--diff-filter=U"]);return t.split(`
185
+ `).map(n=>n.trim()).filter(Boolean)}catch{return[]}}var ew,BT,Od=G(()=>{ew=YF(JF),BT=64*1024*1024});function Md(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!eU.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 Ue,eU,an=G(()=>{Ue=e=>!!(e&&(e.archivedAt||e.transferredTo)),eU=new Set(["merged","conflict","canceled","failed","handed-off"])});import cw from"node:fs/promises";import FT from"node:path";import tU from"node:os";function qT(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function GT(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function KT(e){let t=new Date(qT(e));return t.setDate(t.getDate()+7),t.getTime()}function VT(e){let t=new Date(GT(e));return t.setMonth(t.getMonth()+1),t.getTime()}function Nd(e=Date.now()){for(let[t,n]of Object.entries(Oa)){let r=n.startOf(e);if(r!==br[t]){br[t]=r;for(let o of ws.values())o[t]=0;for(let o of Ma)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&Ma.delete(o)}}}function zT(e,t){let n=An?.caps?.[e]?.[Oa[t].capKey];return Number.isFinite(n)&&n>0?n:null}function mo(e,t=Date.now()){if(!e||!uw||!An?.caps)return null;Nd(t);let n=ws.get(e);for(let r of Object.keys(Oa)){let o=zT(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:Cd(s),resetsAt:Oa[r].nextStart(t)}}return null}function JT(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${br[t.window]}`;return Ma.has(n)?!1:(Ma.add(n),!0)}function jT(e,t,n,r=Date.now()){if(!e||!t)return;Nd(r);let o=nU(e);for(let[s,a]of Object.entries(Oa))n>=br[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function rU(e,t,n=Date.now()){if(!An?.caps||!lw)return;let r=ws.get(e);if(r)for(let[o,s]of Object.entries(Oa)){let a=zT(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*WT||i>=a)continue;let c=`warn:${e}:${o}:${br[o]}`;if(!Ma.has(c)){Ma.add(c);try{let l=await lw(t);if(!l)continue;await N(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:Cd(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function YT(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 Pd(e,{source:t="local",updatedAt:n=Date.now()}={}){An={caps:YT(e),updatedAt:n,source:t};try{await cw.mkdir(UT,{recursive:!0}),await cw.writeFile(HT(),JSON.stringify(An,null,2))}catch{}return _c()}function _c(e=Date.now()){Nd(e);let t=new Set([...ws.keys(),...Object.keys(An?.caps||{})]),n={};for(let r of t){let o=ws.get(r);n[r]={weeklyUsd:Cd(o?.weekly||0),monthlyUsd:Cd(o?.monthly||0)}}return{caps:An?.caps||{},configured:!!An,seeded:uw,updatedAt:An?.updatedAt??null,spent:n,windows:{weekly:{start:br.weekly,resetsAt:KT(e)},monthly:{start:br.monthly,resetsAt:VT(e)}},warnPct:WT}}async function XT({listTracks:e,getTrack:t}={}){lw=t||null,Nd();try{let o=JSON.parse(await cw.readFile(HT(),"utf8"));An={caps:YT(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{An=null}let n=Date.now();Ze.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=sn(o);jT(o.provider||"unknown",s,o.ts??Date.now()),rU(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(br.weekly,br.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||jT(a.provider||"unknown",sn(a).usd,i,n)}}return uw=!0,_c()}var UT,HT,WT,Oa,An,uw,br,ws,Ma,lw,nU,Cd,Dd=G(()=>{be();fo();UT=process.env.BOSTRAT_STATE_DIR||FT.join(process.env.HOME||tU.tmpdir(),".bostrat"),HT=()=>FT.join(UT,"usage-caps.json"),WT=.8;Oa={weekly:{startOf:qT,nextStart:KT,capKey:"weeklyUsd"},monthly:{startOf:GT,nextStart:VT,capKey:"monthlyUsd"}},An=null,uw=!1,br={weekly:0,monthly:0},ws=new Map,Ma=new Set,lw=null,nU=e=>{let t=ws.get(e);return t||(t={weekly:0,monthly:0},ws.set(e,t)),t};Cd=e=>Math.round(e*1e4)/1e4});import oU from"node:fs/promises";import sU from"node:os";import ZT from"node:path";function dw(e){return e==="codex"?lU:e==="cursor"?oA:nA}function QT(e){let t=String(e||"").split(`
186
+ `),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 eA(e){let t=String(e||"").split(`
187
+ `),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 uU(e){let t=String(e||"").split(`
188
+ `);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 tA(e){let t=String(e||"").split(`
189
+ `),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 sA(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&&!rA.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=oA.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!cU.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Ic(e,t,{timeoutMs:n=aU}={}){let r=Date.now()+n;for(;;){let o=await Ne(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await Bd(iU)}}async function dU(e,t){return await Qe(e,`/model ${t.model}`,Un("claude")),{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function pU(e,t){await Hu(e),await Qe(e,"/model",{enter:!1}),await Bd(250),await Ke(e,["Enter"],{kind:"model-switch"});let n=await Ic(e,QT);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await Ke(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=uU(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await Qe(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await Ic(e,i=>eA(i)||!QT(i)&&o(i)&&{done:o(i)});if(!s)throw await Ke(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?rA.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 Ke(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await Qe(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Ic(e,i=>!eA(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 fU(){let e=ZT.join(process.env.CURSOR_CONFIG_DIR||ZT.join(sU.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await oU.readFile(e,"utf8"))?.model||null}catch{return null}}async function mU(e,t){await Hu(e),await qu(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await Ic(e,tA),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 Ic(e,tA,{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 Ke(e,["Down"],{kind:"model-switch"}),await Bd(250)}if(!n||!s||!o(s)){await Ke(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await Ke(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 Ke(e,["Enter"],{kind:"model-switch"}),await Bd(800);let a=await fU();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 aA(e,t,n){return e==="codex"?pU(t,n):e==="cursor"?mU(t,n):dU(t,n)}var Bd,aU,iU,nA,cU,lU,rA,oA,iA=G(()=>{dt();pc();Bd=e=>new Promise(t=>setTimeout(t,e)),aU=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,iU=300,nA=[{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"}],cU=new Set([...nA.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"]),lU=[{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"}],rA=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),oA=[{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 Fd(e){let t=e||{},n=hU(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function hU(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:lt(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:lt(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:lt(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:lt(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,cliVersion:e.cliVersion??null,...e.standing?{standing:e.standing}:{}}};case"lead-handoff-failed":return{type:"handoff.failed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:lt(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:lt(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:lt(e.agent),payload:{...qn(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:lt(e.agent||e.toAgent),payload:{kind:"subtask-failed",...qn(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:lt(e.agent),payload:{change:"subtask-resumed",...qn(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",...qn(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...qn(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...qn(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:lt(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:lt(e.agent),payload:{change:"lead-refreshed",box:e.box,agent:e.agent,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,reason:e.reason,cliVersion:e.cliVersion??null,...e.standing?{standing:e.standing}:{}}};case"transferred-in":return{type:e.mode==="recover"?"track.recovered":"track.transferred",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:lt(e.agent),payload:{...qn(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...qn(e)}};case"retag-failed":return{type:"error",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:lt(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:lt(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};case"delivery-held":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:lt(e.agent),payload:{kind:"delivery-held",...qn(e)}};case"startup-gate":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:lt(e.agent),payload:{kind:"startup-gate",...qn(e)}};default:return null}}function uA(e,t){let n=Fd(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;Ud(()=>N(r,n))}async function dA(e){if(!(!e?.id||cA.has(e.id))){cA.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=Fd(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await N(e,o)}}catch{}}}function qn(e){let{type:t,at:n,...r}=e;return r}function pA(e,t,n){!n?.promptId||jd.get(e.id)===n.promptId||(jd.set(e.id,n.promptId),Ud(()=>N(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:lt(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 fA(e,t,n,r={}){jd.delete(e.id),Ud(()=>N(e,{type:"prompt.dismissed",actor:"user",source:"orchestrator",boxId:t?.name,provider:lt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}function pw(e,t,n,r={}){jd.delete(e.id),Ud(()=>N(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:lt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var lt,Ld,Ud,lA,cA,jd,fw=G(()=>{be();lt=e=>e||null;Ld=Promise.resolve(),Ud=e=>(Ld=Ld.then(e).catch(()=>{}),Ld),lA=()=>Ld;cA=new Set;jd=new Map});function kU(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function bA(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-600);for(let r of kU(n).reverse()){if(!wU.test(r))continue;let o=r.endsWith("?")&&r.length<=bU&&yU.test(r);if(gU.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function xA(e){let t=String(e||""),n=[];xU.test(t)&&n.push("commit"),kA.test(t)&&n.push("rebase"),vU.test(t)&&n.push("push");let r=TU.test(t);!r&&SU.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 vA(e){return kA.test(String(e||""))}function Ca(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 SA(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 TA(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<=AU&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function AA(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+EU||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function EA(e){let t=(Array.isArray(e)?e:[]).filter(r=>mA[r]).map(r=>mA[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 hA,wA,gA,yA,wU,gU,yU,bU,ho,xU,kA,vU,SU,TU,AU,EU,mA,gs=G(()=>{hA=/(?<!\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,wA=/(?<!\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,gA=/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,yA=/(?<!\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,wU=new RegExp(`\\b(?:${hA}|${wA}|${gA}|${yA})\\b`,"i"),gU=/\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,yU=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,bU=90;ho=["commit","rebase","push","pr"],xU=new RegExp(`\\b(?:${hA})\\b`,"i"),kA=new RegExp(`\\b(?:${yA})\\b`,"i"),vU=new RegExp(`\\b(?:${wA})\\b`,"i"),SU=new RegExp(`\\b(?:${gA})\\b`,"i"),TU=/\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;AU=3e4;EU=2500;mA={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import _U from"node:crypto";import Hd from"node:fs/promises";import _A from"node:path";import IU from"node:os";function OA(e){RA=typeof e=="function"?e:async()=>new Set}function $U(e,t,n){if(e.originNode&&e.originNode===t)return!0;let r=e.data?.trackId;return!!r&&n.has(r)}async function We(){return kr||(mw??=Hd.readFile(ww,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(kr=e,!t&&Ge()){let{records:n,source:r}=await pt("prlinks").catch(()=>({records:[],source:"error"}));if(r==="plane"){let o=ux(),s=await RA().catch(()=>new Set),a=0;for(let i of n){if(i.deletedAt||!i.data?.repo||i.data?.number==null)continue;if(!$U(i,o,s)){a++;continue}let{id:c,updatedAt:l,...u}=i.data;kr[ce(u.repo,u.number)]=u}a&&console.log(`[pr-links] restore: ${Object.keys(kr).length} link(s) re-seeded, ${a} other-node record(s) left on the plane`),Object.keys(kr).length&&await gw().catch(()=>{})}}return kr}).finally(()=>mw=null),mw)}async function gw(){let e=JSON.stringify({links:kr},null,2),t=`${ww}.${process.pid}.tmp`;await Hd.mkdir(IA,{recursive:!0}),await Hd.writeFile(t,e),await Hd.rename(t,ww)}async function et(e){hw=hw.then(gw,gw),await hw.catch(()=>{});let t=kr?.[e];t&&It("prlinks",{id:$A(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function Yt({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 We(),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:RU.has(a),firstSeen:Date.now()},await et(ce(e,t)),{link:i[c],created:!0})}async function xr(e,t){if(!e||t==null)return null;let n=(await We())[ce(e,t)];return!n||n.announced?null:(n.announced=!0,await et(ce(e,t)),n)}async function MA(e,t){if(!e||t==null)return!1;let n=(await We())[ce(e,t)];return n?.notifyOnMerge?(delete n.notifyOnMerge,await et(ce(e,t)),!0):!1}async function ft(e,t){return!e||t==null?null:(await We())[ce(e,t)]??null}async function wo(e,t,n){if(!e||t==null)return null;let r=(await We())[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 CA(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await We())[ce(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await et(ce(e,t)),o):null}async function NA(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await We())[ce(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await et(ce(e,t)),o):null}async function Wd(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await We())[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 qd(e,t){if(!e||t==null)return null;let n=(await We())[ce(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await et(ce(e,t)),n)}async function Gd(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await We())[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 Kd(e,t){if(!e||t==null)return null;let n=(await We())[ce(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await et(ce(e,t)),n)}async function PA(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await We())[ce(e,t)];return r?(r.baseFoldAt=n,await et(ce(e,t)),r):null}async function DA(e,t,{misses:n,until:r}){if(!e||t==null)return null;let o=(await We())[ce(e,t)];return o?(o.brokerRefused={misses:Number(n)||0,until:Number(r)||0},await et(ce(e,t)),o):null}async function BA(e,t){if(!e||t==null)return null;let n=(await We())[ce(e,t)];return n?.brokerRefused?(delete n.brokerRefused,await et(ce(e,t)),n):null}async function LA(e,t){if(!e||t==null)return null;let n=(await We())[ce(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await et(ce(e,t)),n)}async function jA(e,t,n){if(!e||t==null||!n)return null;let r=(await We())[ce(e,t)];return r?(r.lastHeadSha=n,await et(ce(e,t)),r):null}async function FA(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await We())[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 $c(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await We())[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 ys(e,t,n=!0){if(!e||t==null)return null;let r=(await We())[ce(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await et(ce(e,t)),r):null}async function bs(e,t,n=!0){if(!e||t==null)return null;let r=(await We())[ce(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await et(ce(e,t)),r):null}async function UA(e,t,n){if(!e||t==null)return null;let r=(await We())[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 HA(e,t,n){if(!e||t==null)return null;let r=(await We())[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 Rc(e,t){if(!e||t==null)return null;let n=(await We())[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,delete n.verdict,await et(ce(e,t)),n)}async function WA(){return Object.values(await We()).filter(e=>!OU.has(e.state))}async function En(){return Object.values(await We()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function qA(){if(!Ge())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await pt("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await We(),r=0;for(let[o,s]of Object.entries(n))await It("prlinks",{id:$A(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var IA,ww,ce,$A,kr,mw,hw,RA,RU,OU,Gn=G(()=>{Yr();IA=process.env.BOSTRAT_STATE_DIR||_A.join(process.env.HOME||IU.tmpdir(),".bostrat"),ww=_A.join(IA,"pr-links.json"),ce=(e,t)=>`${e}#${Number(t)}`,$A=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=_U.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},kr=null,mw=null,hw=Promise.resolve(),RA=async()=>new Set;RU=new Set(["api","observed","reconciled"]);OU=new Set(["merged","closed","lost"])});import MU from"node:fs";import yw from"node:fs/promises";import zA from"node:path";import CU from"node:os";function XA(e,t=!1){if(!t&&e-KA<NU)return;KA=e;let n=JSON.stringify({windowStart:Na,byCaller:Object.fromEntries(vr),lastHour:go});VA=VA.then(()=>yw.mkdir(JA,{recursive:!0})).then(()=>yw.writeFile(`${Vd}.tmp`,n)).then(()=>yw.rename(`${Vd}.tmp`,Vd)).catch(()=>{})}function ZA(e){e-Na<YA||(go={start:Na,total:zd(vr),byCaller:Object.fromEntries(vr)},go.total&&console.log(`[github] ${go.total} calls last hour`,go.byCaller),Na=e,vr=new Map,XA(e,!0))}function Sr(e="other",t=Date.now()){ZA(t),vr.set(e,(vr.get(e)||0)+1),XA(t)}function QA(e=Date.now()){return ZA(e),{windowStart:Na,total:zd(vr),byCaller:Object.fromEntries(vr),lastHour:go,backoffUntil:ks>e?ks:null}}function yo(e){return PU.test(String(e?.message||e||""))}function bo(e,t=Date.now()){return ks<=t&&console.warn(`[github] rate limited \u2014 backing off ${GA/6e4} min:`,String(e?.message||e||"").slice(0,200)),ks=Math.max(ks,t+GA),ks}function Jd(e=Date.now()){return Math.max(0,ks-e)}var JA,Vd,YA,GA,NU,Na,vr,go,ks,KA,zd,VA,PU,Oc=G(()=>{JA=process.env.BOSTRAT_STATE_DIR||zA.join(process.env.HOME||CU.tmpdir(),".bostrat"),Vd=zA.join(JA,"github-metrics.json"),YA=60*6e4,GA=5*6e4,NU=6e4,Na=Date.now(),vr=new Map,go=null,ks=0,KA=0,zd=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(MU.readFileSync(Vd,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<YA?(Na=e.windowStart,vr=new Map(Object.entries(e.byCaller||{})),go=e.lastHour||null):zd(new Map(Object.entries(e.byCaller||{})))&&(go={start:e.windowStart,total:zd(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}VA=Promise.resolve();PU=/rate limit|too quickly|abuse detection|HTTP 429/i});import eE from"node:fs/promises";import tE from"node:path";import DU from"node:os";function Xd({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};Yd.push(l),Yd.length>LU&&Yd.shift();let u=bw.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)),bw.set(e,u),jU(l),l}async function jU(e){try{await eE.mkdir(nE,{recursive:!0}),await eE.appendFile(BU,JSON.stringify(e)+`
190
+ `)}catch{}}function rE(){let e={};for(let[t,n]of bw)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:Yd.slice(-20)}}var nE,BU,LU,Yd,bw,Zd=G(()=>{nE=process.env.BOSTRAT_STATE_DIR||tE.join(process.env.HOME||DU.tmpdir(),".bostrat"),BU=tE.join(nE,"github-latency.ndjson"),LU=100,Yd=[],bw=new Map});import{execFile as FU}from"node:child_process";import{promisify as UU}from"node:util";async function HU(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([Da("git",["-C",e,"rev-parse","HEAD"]),Da("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await N({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function cn(e,t,n={}){let{caller:r="prs",...o}=n,s=await Bn({cwd:e});Sr(r);try{let{stdout:a}=await Da("gh",t,{cwd:e,...WU,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw yo(a)&&bo(a),a}}async function vw(){if(Qd&&Date.now()-Qd.at<6e4)return Qd.data;let e;try{Sr("auth");let t=await Da("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 Li();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return Qd={at:Date.now(),data:e},e}async function qU(e){try{let{stdout:t}=await Da("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function sE(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 kw(e){let t=(e||[]).map(sE),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 Tw(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function iE(e,t){if(!t)return null;let n=await Me(e);if(!n)return null;try{let r=await cn(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 cE(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 lE(e,t){let n=await iE(e,t);return n===null?{...kw([]),unavailable:!0}:kw(cE(n))}function ep(e,t=kw(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 KU(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)<GU}for(let o of Pa.keys())o.startsWith(`${e}#`)&&!r.has(o)&&Pa.delete(o);return t}async function Ba(e,t){let n=await Tr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{let o=await cn(n.path,["pr","view",String(r),"--json",Sw]);return ep(JSON.parse(o))}catch(o){if(!Tw(o))throw o;let s=await cn(n.path,["pr","view",String(r),"--json",aE]),a=JSON.parse(s);return ep(a,await lE(n.path,a.headRefOid))}}async function Kn(e,{caller:t="prs"}={}){try{let n=await cn(e,["pr","list","--json",Sw,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>ep(r)).sort(oE)}catch(n){if(!Tw(n))throw n;let r=await cn(e,["pr","list","--json",aE,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>ep(o,await lE(e,o.headRefOid))))).sort(oE)}}function ln(){Mc.clear()}async function JU(e,t){if(!e)return t;for(let n of t){let r=await ft(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 Wd(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await Gd(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function uE(){let e=await vw();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await fr())await qU(a.path)&&t.push(a);let n=Date.now(),r=Jd(n)>0,o=await Promise.all(t.map(async a=>{let i=Mc.get(a.path),c=i?.pending?zU:VU;if(i&&(r||n-i.at<c))return i.entry;try{let l=await Me(a.path).catch(()=>null),u=KU(a.path,await Kn(a.path,{caller:"tab"}),n);if(await JU(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&&Xd({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 Mc.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:Vn(l)}}})),s=new Set(t.map(a=>a.path));for(let a of Mc.keys())s.has(a)||Mc.delete(a);return{auth:e,repos:o}}async function Tr(e){let t=(await fr()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function xs(e){return ea(e)}async function La(e,t,{method:n="squash"}={}){let r=await Tr(e);if(!Cc.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 Bn({cwd:r.path})).GH_TOKEN){let a=await vm().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await cn(r.path,s)}catch(a){throw new Error(Vn(a))}finally{ln()}return{ok:!0,number:o}}async function Nc(e,t){let n=await Tr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await cn(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(Vn(s))}finally{ln()}let o=await Me(n.path).catch(()=>null);return o&&await PA(o,r).catch(()=>{}),{ok:!0,number:r}}async function Aw(e,t){let n=await Tr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await cn(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(Vn(o))}finally{ln()}return{ok:!0,number:r}}function Ew(e){return e.green&&!e.isDraft}function QU(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 dE(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:Ew(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function pE(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function Pc(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 fE(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(Pc))t.has(n.trackId)||t.set(n.trackId,`${n.repo}#${n.number}`);return t}function mE(){let e={};for(let[t,n]of xw)e[t]={...n};return e}async function hE(e,{method:t="merge",onMerged:n=null}={}){let r=await Tr(e);if(!Cc.has(t))throw new Error(`invalid merge method: ${t}`);if(xw.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await Kn(r.path)).filter(Ew).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 xw.set(r.path,s),t4(s,o,{listPrs:()=>Kn(r.path),merge:a=>La(r.path,a,{method:t}),sleep:ZU,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function e4(e,t){let n=Date.now()+(t.settleMaxMs??XU),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(YU)}}async function t4(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 e4(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: ${Vn(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(!Ew(a)){e.skipped.push({number:a.number,title:a.title,reason:QU(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:Vn(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),ln()}}async function _w(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await Da("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${Vn(l)}`)}await HU(e);let o=n||"";if((await Bn({cwd:e})).GH_TOKEN){let l=await vm().catch(()=>null);l&&(o=`${o?`${o}
191
+
192
+ `:""}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 cn(e,s)}catch(l){throw new Error(Vn(l))}finally{ln()}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 wE(e,t){let n=await Tr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await cn(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(Vn(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!Tw(i))throw i;let c=await cn(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await iE(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(Vn(i));o=cE(l).map(sE).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=n4(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await cn(n.path,["run","view",c,"--log-failed"]).then(u=>r4(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function n4(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function r4(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
193
193
  `);return o.length>t&&(r=`\u2026 (${o.length-t} earlier lines truncated)
194
194
  `+o.slice(-t).join(`
195
195
  `)),Buffer.byteLength(r)>n&&(r=`\u2026 (truncated)
196
196
  `+r.slice(-n)),r}function Vn(e){return String(e?.stderr||e?.message||e||"").trim().split(`
197
- `).find(n=>n.trim())||"gh failed"}var Da,HU,Zd,Sw,aE,qU,Pa,oE,KU,VU,Mc,Cc,JU,YU,XU,xw,vs=G(()=>{Gr();xt();Gn();Oc();Xd();be();Da=FU(jU),HU={timeout:3e4,maxBuffer:8*1024*1024};Zd=null;Sw="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt,state,mergedAt,closedAt",aE=Sw.replace("statusCheckRollup,","");qU=9e4,Pa=new Map;oE=(e,t)=>e.number-t.number;KU=3e4,VU=1500,Mc=new Map;Cc=new Set(["squash","merge","rebase"]);JU=2500,YU=9e4,XU=e=>new Promise(t=>setTimeout(t,e));xw=new Map});import{execFile as r4}from"node:child_process";import{promisify as o4}from"node:util";async function a4(e,t){try{let{stdout:n}=await s4("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function i4(e,t,n,{rebase:r=!1,listPrs:o=Kn}={}){let s=await ps(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await fs(e.dir,n).catch(()=>0),i=t?await a4(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:ep.filter(w=>p.includes(w)),defaults:ep.filter(w=>f.includes(w))}}async function tp(e,{branch:t,rebase:n=!1,listPrs:r=Kn}={}){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 $a(s[0].dir).catch(()=>!1))return null;let a=[];for(let p of s)a.push(await i4(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=ep.filter(p=>c.some(f=>f.available.includes(p))),u=ep.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 s4,ep,Iw=G(()=>{Rd();vs();s4=o4(r4),ep=["commit","rebase","push","pr"]});import{execFile as c4}from"node:child_process";import{promisify as l4}from"node:util";async function ko(e){if(!e)return null;let t=gE.get(e);if(t&&Date.now()-t.at<d4)return t.branch;let n=null;try{let{stdout:r}=await u4("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return gE.set(e,{at:Date.now(),branch:n}),n}function yE(e){return String(e||"").match(p4)?.[1]??null}function bE(e,t){let n=yE(e);return!!n&&!!t&&n===t}function kE(e,t){let n=yE(e);return!!n&&n!==t}function f4(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 ja(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of f4(e))n(await ko(r));return t}async function np(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=>bE(t,a.id));if(s)return s;for(let a of r)if(!Ue(a)&&(await ja(a)).includes(t))return a;return null}function m4(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 rp(e,{branch:t=null,repo:n=null,slug:r=null}={}){return bE(t,e?.id)?!0:m4(e,n,r)}var u4,d4,gE,p4,Ss=G(()=>{an();u4=l4(c4),d4=5e3,gE=new Map;p4=/^track\/.+-([0-9a-f]{8})$/});import{execFile as h4}from"node:child_process";import{promisify as w4}from"node:util";function Fa({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function sp(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function ip({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?v4[r]:null;return a&&s.push(a),s.push(`${TE}: ${Fa({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${EE}: ${String(o).trim()}`),s}function xE(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
198
- `)){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===TE.toLowerCase()&&!t.epoch)t.epoch=sp(a);else if(s===EE.toLowerCase()&&!t.model)t.model=a;else if(s===_E.toLowerCase()&&!t.cause){let i=a.toLowerCase();Dc.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 S4(e,t=xo){return e<=t?"rework":"drift"}function A4(e,{window:t=xo,end:n=Cw}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function cp({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return T4.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${_E} trailer`}:_4.test(s)&&!vE.test(s)?{cause:"style",level:"C",basis:"subject"}:vE.test(s)?{cause:"defect",level:"C",basis:"subject"}:E4.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 Pw({heuristic:e=null,subject:t="",ref:n=null,promptKind:r=null,fixerCategory:o=null,ticketKind:s=null}={}){let a=String(t||""),i=I4.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&&$4.has(c)?{intent:"fix",basis:`subject prefix: ${c}:`}:c&&R4.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"}:SE.test(String(n||""))||SE.test(a)?{intent:"planned",basis:"blueprint item"}:o&&O4.has(o)?{intent:"planned",basis:`prompt: ${o}`}:{intent:"unknown",basis:null}}function P4(e){let t=String(e||"");return M4.some(n=>n.test(t))?"excluded":C4.some(n=>n.test(t))?"docs":N4.some(n=>n.test(t))?"config":"code"}function D4(e){let t=[],n=null,r=null;for(let o of String(e||"").split(`
199
- `)){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 B4(e,t){let n=Mw(e),r=Mw(t);if(n===r)return 1;if(!n.length||!r.length)return 0;n.length>op&&(n=n.slice(0,op)),r.length>op&&(r=r.slice(0,op));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 L4(e,t=IE){let n=new Set,r=e?.del||[],o=e?.add||[];for(let s=0;s<r.length;s++){let a=e.oldStart+s;if(!Mw(r[s]).length){n.add(a);continue}s<o.length&&B4(r[s],o[s])>=t&&n.add(a)}return n}function j4(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 F4(e){let t=new Map,n=null;for(let r of String(e||"").split(`
200
- `)){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 AE(e,t){let{stdout:n}=await Ow(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
197
+ `).find(n=>n.trim())||"gh failed"}var Da,WU,Qd,Sw,aE,GU,Pa,oE,VU,zU,Mc,Cc,YU,XU,ZU,xw,vs=G(()=>{Gr();xt();Gn();Oc();Zd();be();Da=UU(FU),WU={timeout:3e4,maxBuffer:8*1024*1024};Qd=null;Sw="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt,state,mergedAt,closedAt",aE=Sw.replace("statusCheckRollup,","");GU=9e4,Pa=new Map;oE=(e,t)=>e.number-t.number;VU=3e4,zU=1500,Mc=new Map;Cc=new Set(["squash","merge","rebase"]);YU=2500,XU=9e4,ZU=e=>new Promise(t=>setTimeout(t,e));xw=new Map});import{execFile as o4}from"node:child_process";import{promisify as s4}from"node:util";async function i4(e,t){try{let{stdout:n}=await a4("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function c4(e,t,n,{rebase:r=!1,listPrs:o=Kn}={}){let s=await ps(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await fs(e.dir,n).catch(()=>0),i=t?await i4(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:tp.filter(w=>p.includes(w)),defaults:tp.filter(w=>f.includes(w))}}async function np(e,{branch:t,rebase:n=!1,listPrs:r=Kn}={}){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 $a(s[0].dir).catch(()=>!1))return null;let a=[];for(let p of s)a.push(await c4(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=tp.filter(p=>c.some(f=>f.available.includes(p))),u=tp.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 a4,tp,Iw=G(()=>{Od();vs();a4=s4(o4),tp=["commit","rebase","push","pr"]});import{execFile as l4}from"node:child_process";import{promisify as u4}from"node:util";async function ko(e){if(!e)return null;let t=gE.get(e);if(t&&Date.now()-t.at<p4)return t.branch;let n=null;try{let{stdout:r}=await d4("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return gE.set(e,{at:Date.now(),branch:n}),n}function yE(e){return String(e||"").match(f4)?.[1]??null}function bE(e,t){let n=yE(e);return!!n&&!!t&&n===t}function kE(e,t){let n=yE(e);return!!n&&n!==t}function m4(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 ja(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of m4(e))n(await ko(r));return t}async function rp(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=>bE(t,a.id));if(s)return s;for(let a of r)if(!Ue(a)&&(await ja(a)).includes(t))return a;return null}function h4(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 op(e,{branch:t=null,repo:n=null,slug:r=null}={}){return bE(t,e?.id)?!0:h4(e,n,r)}var d4,p4,gE,f4,Ss=G(()=>{an();d4=u4(l4),p4=5e3,gE=new Map;f4=/^track\/.+-([0-9a-f]{8})$/});import{execFile as w4}from"node:child_process";import{promisify as g4}from"node:util";function Fa({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function ap(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function cp({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?S4[r]:null;return a&&s.push(a),s.push(`${AE}: ${Fa({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${EE}: ${String(o).trim()}`),s}function xE(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
198
+ `)){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===AE.toLowerCase()&&!t.epoch)t.epoch=ap(a);else if(s===EE.toLowerCase()&&!t.model)t.model=a;else if(s===_E.toLowerCase()&&!t.cause){let i=a.toLowerCase();Dc.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 T4(e,t=xo){return e<=t?"rework":"drift"}function A4(e,{window:t=xo,end:n=Cw}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function lp({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return E4.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${_E} trailer`}:I4.test(s)&&!vE.test(s)?{cause:"style",level:"C",basis:"subject"}:vE.test(s)?{cause:"defect",level:"C",basis:"subject"}:_4.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 Pw({heuristic:e=null,subject:t="",ref:n=null,promptKind:r=null,fixerCategory:o=null,ticketKind:s=null}={}){let a=String(t||""),i=$4.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&&R4.has(c)?{intent:"fix",basis:`subject prefix: ${c}:`}:c&&O4.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"}:SE.test(String(n||""))||SE.test(a)?{intent:"planned",basis:"blueprint item"}:o&&M4.has(o)?{intent:"planned",basis:`prompt: ${o}`}:{intent:"unknown",basis:null}}function D4(e){let t=String(e||"");return C4.some(n=>n.test(t))?"excluded":N4.some(n=>n.test(t))?"docs":P4.some(n=>n.test(t))?"config":"code"}function B4(e){let t=[],n=null,r=null;for(let o of String(e||"").split(`
199
+ `)){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 L4(e,t){let n=Mw(e),r=Mw(t);if(n===r)return 1;if(!n.length||!r.length)return 0;n.length>sp&&(n=n.slice(0,sp)),r.length>sp&&(r=r.slice(0,sp));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 j4(e,t=IE){let n=new Set,r=e?.del||[],o=e?.add||[];for(let s=0;s<r.length;s++){let a=e.oldStart+s;if(!Mw(r[s]).length){n.add(a);continue}s<o.length&&L4(r[s],o[s])>=t&&n.add(a)}return n}function F4(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 U4(e){let t=new Map,n=null;for(let r of String(e||"").split(`
200
+ `)){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 TE(e,t){let{stdout:n}=await Ow(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
201
201
  `);return{sha:r.trim(),parents:o.trim()?o.trim().split(" "):[],ts:Number(s)*1e3,subject:a??"",message:i.join(`
202
- `)}}async function $E(e,t,{fixKey:n=null,window:r=xo,resolveOrigin:o=null,context:s={}}={}){let a=await AE(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=xE(a.message),l=n?sp(n):c.epoch,u=l?Fa(l):null,{stdout:d}=await Ow(e,["diff","-U0","--no-color","-M","-C",i,t]),p=D4(d),f=0,w=0,h=0,y=0,k=0,g=0,x=0,S=new Map;for(let $ of p){if($.binary)continue;let L=$.oldPath||$.newPath||"",H=$.deleted.reduce((B,[,Z])=>B+Z,0),R=P4(L);if(R==="excluded"){h+=H;continue}if(R==="docs"){y+=H,k+=$.added;continue}if(R==="config"){g+=H;continue}f+=$.added;let A=new Set;for(let B of $.hunks||[])for(let Z of L4(B))A.add(Z);x+=A.size;let C=[];for(let[B,Z]of $.deleted)for(let xe=B;xe<B+Z;xe++)A.has(xe)||C.push(xe);if(w+=C.length,!$.oldPath||!C.length)continue;let W;try{let B=["blame","-w","-M","-C","--line-porcelain"];for(let[Z,xe]of j4(C))B.push("-L",`${Z},${Z+xe-1}`);B.push(i,"--",$.oldPath),W=F4((await Ow(e,B)).stdout)}catch{continue}for(let{sha:B,time:Z}of W.values()){let xe=S.get(B)??{lines:0,time:Z};xe.lines+=1,S.set(B,xe)}}let _=[],M=0,P=new Map;for(let[$,{lines:L,time:H}]of S){let R=P.get($);if(!R){try{R=await AE(e,$)}catch{R=null}P.set($,R)}let A=R?xE(R.message):{epoch:null},C=A.epoch,W=A.provider,B=A.model;if(!C&&o){let Q=await o($,R);Q?.trackId&&Q?.boxId!=null&&(C={trackId:Q.trackId,boxId:Q.boxId,epoch:Q.epoch??0},W=W??Q.provider??null,B=B??Q.model??null)}if(!C){M+=L;continue}let Z=Number.isFinite(H)?H:R?.ts??a.ts,xe=Math.max(0,(a.ts-Z)/b4),Ae=Fa(C),_e=Ae===u?"self":S4(xe,r);_.push({sha:$,key:Ae,trackId:C.trackId,boxId:C.boxId,epoch:C.epoch,provider:W??null,model:B??null,lines:L,ageDays:Math.round(xe*100)/100,class:_e,decay:_e==="rework"?1:_e==="drift"?Math.round(A4(xe,{window:r})*1e3)/1e3:0})}_.sort(($,L)=>L.lines-$.lines);let j=cp({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),T=Pw({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:x,docsDeleted:y,docsAdded:k,configDeleted:g,codeDelta:f+w+x>0,origins:_,unattributedLines:M,ghost:w===0&&f>0,heuristic:j,intent:T}}function RE(e,{minLines:t=Nw}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return Ua.has(n)?Bc(e)>=t:!1}function Bc(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function Rw(e){let t=e.genUsd;return{...e,genUsd:_n(t),reworkChargedUsd:_n(e.reworkChargedUsd),reworkPendingUsd:_n(e.reworkPendingUsd),trueUsd:_n(t+e.reworkChargedUsd),multiplier:t>0?_n((t+e.reworkChargedUsd)/t):null}}function OE(e,{window:t=xo,boxMeta:n={}}={}){let r=e||[],o=r.filter(T=>T.type==="cost.recorded"),s=r.filter(T=>T.type==="code.committed"),a=r.filter(T=>T.type==="code.rework"),i=T=>Array.isArray(T?.shas)&&T.shas.length?T.shas:T?.sha?[T.sha]:[],c=new Map,l=new Set;for(let T of r)if(T.type==="rework.cause.offered")for(let $ of i(T.payload))l.add($);else if(T.type==="rework.cause.answered"&&T.payload?.cause)for(let $ of i(T.payload))c.set($,T.payload.cause);else if(T.type==="rework.cause.retracted")for(let $ of i(T.payload))c.delete($);let u={},d=(T,$,L)=>Fa({trackId:T,boxId:$,epoch:L??0}),p=(T,$={})=>{if(!u[T]){let H=sp(T)||{};u[T]={key:T,...H,provider:null,model:null,...$w()}}let L=u[T];return $.provider&&!L.provider&&(L.provider=$.provider),$.model&&!L.model&&(L.model=$.model),L};for(let T of o){if(!T.boxId)continue;let $=d(T.trackId,T.boxId,T.epoch),{usd:L,model:H}=sn(T),R=p($,{provider:T.provider,model:H!=="unknown"?H:null});R.genUsd+=L}let f=new Map;for(let T of s){let $=`${T.trackId}/${T.boxId}`;(f.get($)??f.set($,[]).get($)).push({...T,ts:T.payload?.ts??T.ts})}for(let T of f.values())T.sort(($,L)=>$.ts-L.ts);let w=(T,$,L,H)=>{let R=f.get(`${T}/${$}`)||[],A=-1/0;for(let B of R)B.ts<H&&(A=B.ts);let C=0,W=0;for(let B of o)B.trackId!==T||B.boxId!==$||(B.epoch??0)===(L??0)&&(B.ts<=A||B.ts>H||(C+=sn(B).usd,W++));return{usd:C,turns:W,from:Number.isFinite(A)?A:null}},h={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0,planned:0},y={A:0,B:0,C:0,E:0,none:0},k={fix:0,"likely-fix":0,planned:0,unknown:0},g=0,x=[],S=[],_={},M={},P=new Set;for(let T of a){let $=T.payload||{};if(!$.sha||P.has($.sha))continue;if(P.add($.sha),$.codeDelta===!1){g++;continue}let L=sp($.fixKey)||{trackId:T.trackId,boxId:T.boxId,epoch:T.epoch??0},{usd:H,turns:R}=w(L.trackId,L.boxId,L.epoch,$.ts??T.ts),A=x4.includes($.intent?.intent)?$.intent.intent:"unknown";k[A]+=1;let C=null;c.has($.sha)?C={cause:c.get($.sha),level:"B",basis:"operator"}:($.heuristic?.level&&$.heuristic.level!=="C"||$.heuristic)&&(C=$.heuristic);let W=C?.level??"none";y[W]=(y[W]||0)+1;let B=k4.has(W),Z=Number($.deleted)||0,xe=Array.isArray($.origins)?$.origins:[],Ae=xe.filter(Q=>Q.class==="rework").reduce((Q,Xe)=>Q+Xe.lines,0),_e={sha:$.sha,subject:$.subject??"",ts:$.ts??T.ts,trackId:T.trackId,fixKey:$.fixKey??null,fixProvider:$.fixProvider??T.provider??null,fixUsd:_n(H),fixTurns:R,linesReworked:Ae,unattributedLines:Number($.unattributedLines)||0,ghost:$.ghost===!0,intent:{intent:A,basis:$.intent?.basis??null},verdict:C?{cause:C.cause,level:W,basis:C.basis??null}:null,charged:_n(0),origins:[]};if(A==="planned"||C?.cause===ap){h.planned+=H;for(let Q of xe)Q.class==="rework"&&_e.origins.push({key:Q.key,provider:Q.provider??null,model:Q.model??null,lines:Q.lines,ageDays:Q.ageDays,class:Q.class,usd:0})}else if($.ghost||Z===0)h.ghost+=H;else{let Q=0;for(let Pe of xe){let le=Pe.lines/Z,ge=H*le;if(Q+=ge,Pe.class==="self"){h.self+=ge;continue}let de=Pe.class==="rework"?1:Number(Pe.decay)||0,te=ge*de;if(h.decayed+=ge-te,te<=0)continue;let we=p(Pe.key,{provider:Pe.provider,model:Pe.model});we.fixes+=1,we.linesReworked+=Pe.class==="rework"?Pe.lines:0;let Oe=C?.cause&&Dc.includes(C.cause)?C.cause:"unclassified";we.causes[Oe]+=1,B?(we.reworkChargedUsd+=te,h.charged+=te,_e.charged=_n(_e.charged+te)):(we.reworkPendingUsd+=te,h.pending+=te),_e.origins.push({key:Pe.key,provider:we.provider,model:we.model,lines:Pe.lines,ageDays:Pe.ageDays,class:Pe.class,usd:_n(te)})}let Xe=Math.max(0,H-Q);h.unattributed+=Xe}x.push(_e),!c.has($.sha)&&l.has($.sha)&&S.push($.sha)}for(let T of Object.values(u)){let $=T.provider||"unknown",L=T.model||"unknown",H=R=>{R.genUsd+=T.genUsd,R.reworkChargedUsd+=T.reworkChargedUsd,R.reworkPendingUsd+=T.reworkPendingUsd,R.linesReworked+=T.linesReworked,R.fixes+=T.fixes;for(let A of Object.keys(R.causes))R.causes[A]+=T.causes[A]};H(_[$]||=$w()),H(M[L]||=$w())}x.sort((T,$)=>$.ts-T.ts);let j=Object.values(u).map(T=>{let $=n[`${T.trackId}/${T.boxId}`]||{};return Rw({...T,trackName:$.trackName??null,label:$.label??null})}).sort((T,$)=>$.reworkChargedUsd+$.reworkPendingUsd-(T.reworkChargedUsd+T.reworkPendingUsd)||$.genUsd-T.genUsd);return{window:t,basis:`rework = code lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old (docs/config churn and in-place updates \u2265${IE} 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:k,noCodeDelta:g,byEpoch:Object.fromEntries(j.map(T=>[T.key,T])),epochs:j,byProvider:Object.fromEntries(Object.entries(_).map(([T,$])=>[T,Rw($)])),byModel:Object.fromEntries(Object.entries(M).map(([T,$])=>[T,Rw($)])),buckets:Object.fromEntries(Object.entries(h).map(([T,$])=>[T,_n($)])),fixUsdTotal:_n(Object.values(h).reduce((T,$)=>T+$,0)),fixes:x,verdicts:y,pendingTaps:S,commits:s.length}}var g4,y4,Ow,TE,EE,_E,b4,xo,Cw,Nw,Dc,ap,k4,x4,Ua,IE,v4,T4,vE,E4,_4,I4,$4,R4,SE,O4,M4,C4,N4,Mw,op,_n,$w,lp=G(()=>{fo();g4=w4(h4),y4=64*1024*1024,Ow=(e,t)=>g4("git",["-C",e,...t],{maxBuffer:y4,timeout:6e4}),TE="Bostrat-Epoch",EE="Bostrat-Model",_E="Bostrat-Fix-Cause",b4=24*36e5,xo=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,Cw=90,Nw=3,Dc=Object.freeze(["defect","design","requirements","style"]),ap="not-a-fix",k4=new Set(["A","B","E"]),x4=Object.freeze(["fix","likely-fix","planned","unknown"]),Ua=new Set(["fix","likely-fix"]),IE=.8;v4={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};T4=/^revert\b|^revert "/i,vE=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,E4=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,_4=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;I4=/^([a-z]+)(\([^)]*\))?!?:\s/i,$4=new Set(["fix","hotfix","bugfix","revert"]),R4=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),SE=/\bBP-[A-Z0-9]+(?:-[A-Z0-9]+)*\b/i,O4=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);M4=[/(^|\/)\.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)\//],C4=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],N4=[/\.(json|jsonc|json5|ya?ml|toml|ini|cfg|conf|properties|env|example)$/i,/(^|\/)\.[^/]+$/,/(^|\/)\.github\//,/(^|\/)(Dockerfile|Makefile|Procfile|fly\.toml)$/];Mw=e=>String(e??"").replace(/\s+/g," ").trim(),op=400;_n=e=>Math.round(e*1e4)/1e4,$w=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as U4}from"node:child_process";import{promisify as H4}from"node:util";function ME(e,t=Date.now()){return ji(e,t)??0}function q4(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 CE(e,t,{now:n=Date.now()}={}){let r=ME(t,n),o=await K(e);return ip({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:q4(o,t.name,r)})}function G4(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 K4(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=G4(n,t.name),c=i?gr(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function V4(e,t){try{let{stdout:n}=await Dw(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 z4(e){try{let{stdout:t}=await Dw(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function NE(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(h=>h.type==="code.committed"&&h.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s,c=null;try{let{stdout:h}=await Dw(r,["show","-s","--format=%ct%n%s",n]),[y,...k]=h.split(`
202
+ `)}}async function $E(e,t,{fixKey:n=null,window:r=xo,resolveOrigin:o=null,context:s={}}={}){let a=await TE(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=xE(a.message),l=n?ap(n):c.epoch,u=l?Fa(l):null,{stdout:d}=await Ow(e,["diff","-U0","--no-color","-M","-C",i,t]),p=B4(d),f=0,w=0,h=0,y=0,k=0,g=0,x=0,S=new Map;for(let $ of p){if($.binary)continue;let L=$.oldPath||$.newPath||"",H=$.deleted.reduce((B,[,Z])=>B+Z,0),R=D4(L);if(R==="excluded"){h+=H;continue}if(R==="docs"){y+=H,k+=$.added;continue}if(R==="config"){g+=H;continue}f+=$.added;let T=new Set;for(let B of $.hunks||[])for(let Z of j4(B))T.add(Z);x+=T.size;let C=[];for(let[B,Z]of $.deleted)for(let xe=B;xe<B+Z;xe++)T.has(xe)||C.push(xe);if(w+=C.length,!$.oldPath||!C.length)continue;let W;try{let B=["blame","-w","-M","-C","--line-porcelain"];for(let[Z,xe]of F4(C))B.push("-L",`${Z},${Z+xe-1}`);B.push(i,"--",$.oldPath),W=U4((await Ow(e,B)).stdout)}catch{continue}for(let{sha:B,time:Z}of W.values()){let xe=S.get(B)??{lines:0,time:Z};xe.lines+=1,S.set(B,xe)}}let _=[],M=0,P=new Map;for(let[$,{lines:L,time:H}]of S){let R=P.get($);if(!R){try{R=await TE(e,$)}catch{R=null}P.set($,R)}let T=R?xE(R.message):{epoch:null},C=T.epoch,W=T.provider,B=T.model;if(!C&&o){let Q=await o($,R);Q?.trackId&&Q?.boxId!=null&&(C={trackId:Q.trackId,boxId:Q.boxId,epoch:Q.epoch??0},W=W??Q.provider??null,B=B??Q.model??null)}if(!C){M+=L;continue}let Z=Number.isFinite(H)?H:R?.ts??a.ts,xe=Math.max(0,(a.ts-Z)/k4),Te=Fa(C),_e=Te===u?"self":T4(xe,r);_.push({sha:$,key:Te,trackId:C.trackId,boxId:C.boxId,epoch:C.epoch,provider:W??null,model:B??null,lines:L,ageDays:Math.round(xe*100)/100,class:_e,decay:_e==="rework"?1:_e==="drift"?Math.round(A4(xe,{window:r})*1e3)/1e3:0})}_.sort(($,L)=>L.lines-$.lines);let j=lp({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),A=Pw({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:x,docsDeleted:y,docsAdded:k,configDeleted:g,codeDelta:f+w+x>0,origins:_,unattributedLines:M,ghost:w===0&&f>0,heuristic:j,intent:A}}function RE(e,{minLines:t=Nw}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return Ua.has(n)?Bc(e)>=t:!1}function Bc(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function Rw(e){let t=e.genUsd;return{...e,genUsd:_n(t),reworkChargedUsd:_n(e.reworkChargedUsd),reworkPendingUsd:_n(e.reworkPendingUsd),trueUsd:_n(t+e.reworkChargedUsd),multiplier:t>0?_n((t+e.reworkChargedUsd)/t):null}}function OE(e,{window:t=xo,boxMeta:n={}}={}){let r=e||[],o=r.filter(A=>A.type==="cost.recorded"),s=r.filter(A=>A.type==="code.committed"),a=r.filter(A=>A.type==="code.rework"),i=A=>Array.isArray(A?.shas)&&A.shas.length?A.shas:A?.sha?[A.sha]:[],c=new Map,l=new Set;for(let A of r)if(A.type==="rework.cause.offered")for(let $ of i(A.payload))l.add($);else if(A.type==="rework.cause.answered"&&A.payload?.cause)for(let $ of i(A.payload))c.set($,A.payload.cause);else if(A.type==="rework.cause.retracted")for(let $ of i(A.payload))c.delete($);let u={},d=(A,$,L)=>Fa({trackId:A,boxId:$,epoch:L??0}),p=(A,$={})=>{if(!u[A]){let H=ap(A)||{};u[A]={key:A,...H,provider:null,model:null,...$w()}}let L=u[A];return $.provider&&!L.provider&&(L.provider=$.provider),$.model&&!L.model&&(L.model=$.model),L};for(let A of o){if(!A.boxId)continue;let $=d(A.trackId,A.boxId,A.epoch),{usd:L,model:H}=sn(A),R=p($,{provider:A.provider,model:H!=="unknown"?H:null});R.genUsd+=L}let f=new Map;for(let A of s){let $=`${A.trackId}/${A.boxId}`;(f.get($)??f.set($,[]).get($)).push({...A,ts:A.payload?.ts??A.ts})}for(let A of f.values())A.sort(($,L)=>$.ts-L.ts);let w=(A,$,L,H)=>{let R=f.get(`${A}/${$}`)||[],T=-1/0;for(let B of R)B.ts<H&&(T=B.ts);let C=0,W=0;for(let B of o)B.trackId!==A||B.boxId!==$||(B.epoch??0)===(L??0)&&(B.ts<=T||B.ts>H||(C+=sn(B).usd,W++));return{usd:C,turns:W,from:Number.isFinite(T)?T:null}},h={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0,planned:0},y={A:0,B:0,C:0,E:0,none:0},k={fix:0,"likely-fix":0,planned:0,unknown:0},g=0,x=[],S=[],_={},M={},P=new Set;for(let A of a){let $=A.payload||{};if(!$.sha||P.has($.sha))continue;if(P.add($.sha),$.codeDelta===!1){g++;continue}let L=ap($.fixKey)||{trackId:A.trackId,boxId:A.boxId,epoch:A.epoch??0},{usd:H,turns:R}=w(L.trackId,L.boxId,L.epoch,$.ts??A.ts),T=v4.includes($.intent?.intent)?$.intent.intent:"unknown";k[T]+=1;let C=null;c.has($.sha)?C={cause:c.get($.sha),level:"B",basis:"operator"}:($.heuristic?.level&&$.heuristic.level!=="C"||$.heuristic)&&(C=$.heuristic);let W=C?.level??"none";y[W]=(y[W]||0)+1;let B=x4.has(W),Z=Number($.deleted)||0,xe=Array.isArray($.origins)?$.origins:[],Te=xe.filter(Q=>Q.class==="rework").reduce((Q,Xe)=>Q+Xe.lines,0),_e={sha:$.sha,subject:$.subject??"",ts:$.ts??A.ts,trackId:A.trackId,fixKey:$.fixKey??null,fixProvider:$.fixProvider??A.provider??null,fixUsd:_n(H),fixTurns:R,linesReworked:Te,unattributedLines:Number($.unattributedLines)||0,ghost:$.ghost===!0,intent:{intent:T,basis:$.intent?.basis??null},verdict:C?{cause:C.cause,level:W,basis:C.basis??null}:null,charged:_n(0),origins:[]};if(T==="planned"||C?.cause===ip){h.planned+=H;for(let Q of xe)Q.class==="rework"&&_e.origins.push({key:Q.key,provider:Q.provider??null,model:Q.model??null,lines:Q.lines,ageDays:Q.ageDays,class:Q.class,usd:0})}else if($.ghost||Z===0)h.ghost+=H;else{let Q=0;for(let Pe of xe){let le=Pe.lines/Z,ge=H*le;if(Q+=ge,Pe.class==="self"){h.self+=ge;continue}let de=Pe.class==="rework"?1:Number(Pe.decay)||0,te=ge*de;if(h.decayed+=ge-te,te<=0)continue;let we=p(Pe.key,{provider:Pe.provider,model:Pe.model});we.fixes+=1,we.linesReworked+=Pe.class==="rework"?Pe.lines:0;let Oe=C?.cause&&Dc.includes(C.cause)?C.cause:"unclassified";we.causes[Oe]+=1,B?(we.reworkChargedUsd+=te,h.charged+=te,_e.charged=_n(_e.charged+te)):(we.reworkPendingUsd+=te,h.pending+=te),_e.origins.push({key:Pe.key,provider:we.provider,model:we.model,lines:Pe.lines,ageDays:Pe.ageDays,class:Pe.class,usd:_n(te)})}let Xe=Math.max(0,H-Q);h.unattributed+=Xe}x.push(_e),!c.has($.sha)&&l.has($.sha)&&S.push($.sha)}for(let A of Object.values(u)){let $=A.provider||"unknown",L=A.model||"unknown",H=R=>{R.genUsd+=A.genUsd,R.reworkChargedUsd+=A.reworkChargedUsd,R.reworkPendingUsd+=A.reworkPendingUsd,R.linesReworked+=A.linesReworked,R.fixes+=A.fixes;for(let T of Object.keys(R.causes))R.causes[T]+=A.causes[T]};H(_[$]||=$w()),H(M[L]||=$w())}x.sort((A,$)=>$.ts-A.ts);let j=Object.values(u).map(A=>{let $=n[`${A.trackId}/${A.boxId}`]||{};return Rw({...A,trackName:$.trackName??null,label:$.label??null})}).sort((A,$)=>$.reworkChargedUsd+$.reworkPendingUsd-(A.reworkChargedUsd+A.reworkPendingUsd)||$.genUsd-A.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${IE} 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:k,noCodeDelta:g,byEpoch:Object.fromEntries(j.map(A=>[A.key,A])),epochs:j,byProvider:Object.fromEntries(Object.entries(_).map(([A,$])=>[A,Rw($)])),byModel:Object.fromEntries(Object.entries(M).map(([A,$])=>[A,Rw($)])),buckets:Object.fromEntries(Object.entries(h).map(([A,$])=>[A,_n($)])),fixUsdTotal:_n(Object.values(h).reduce((A,$)=>A+$,0)),fixes:x,verdicts:y,pendingTaps:S,commits:s.length}}var y4,b4,Ow,AE,EE,_E,k4,xo,Cw,Nw,Dc,ip,x4,v4,Ua,IE,S4,E4,vE,_4,I4,$4,R4,O4,SE,M4,C4,N4,P4,Mw,sp,_n,$w,up=G(()=>{fo();y4=g4(w4),b4=64*1024*1024,Ow=(e,t)=>y4("git",["-C",e,...t],{maxBuffer:b4,timeout:6e4}),AE="Bostrat-Epoch",EE="Bostrat-Model",_E="Bostrat-Fix-Cause",k4=24*36e5,xo=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,Cw=90,Nw=3,Dc=Object.freeze(["defect","design","requirements","style"]),ip="not-a-fix",x4=new Set(["A","B","E"]),v4=Object.freeze(["fix","likely-fix","planned","unknown"]),Ua=new Set(["fix","likely-fix"]),IE=.8;S4={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};E4=/^revert\b|^revert "/i,vE=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,_4=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,I4=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;$4=/^([a-z]+)(\([^)]*\))?!?:\s/i,R4=new Set(["fix","hotfix","bugfix","revert"]),O4=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),SE=/\bBP-[A-Z0-9]+(?:-[A-Z0-9]+)*\b/i,M4=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);C4=[/(^|\/)\.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)\//],N4=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],P4=[/\.(json|jsonc|json5|ya?ml|toml|ini|cfg|conf|properties|env|example)$/i,/(^|\/)\.[^/]+$/,/(^|\/)\.github\//,/(^|\/)(Dockerfile|Makefile|Procfile|fly\.toml)$/];Mw=e=>String(e??"").replace(/\s+/g," ").trim(),sp=400;_n=e=>Math.round(e*1e4)/1e4,$w=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as H4}from"node:child_process";import{promisify as W4}from"node:util";function ME(e,t=Date.now()){return ji(e,t)??0}function G4(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 CE(e,t,{now:n=Date.now()}={}){let r=ME(t,n),o=await K(e);return cp({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:G4(o,t.name,r)})}function K4(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 V4(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=K4(n,t.name),c=i?gr(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function z4(e,t){try{let{stdout:n}=await Dw(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 J4(e){try{let{stdout:t}=await Dw(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function NE(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(h=>h.type==="code.committed"&&h.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s,c=null;try{let{stdout:h}=await Dw(r,["show","-s","--format=%ct%n%s",n]),[y,...k]=h.split(`
203
203
  `),g=Number(y.trim())*1e3;Number.isFinite(g)&&g>0&&(i=g),c=k.join(`
204
- `).trim().slice(0,300)||null}catch{return{recorded:!1,reason:"unknown-sha"}}let l=ME(t,i),u=await V4(r,n),d=await z4(r),p=await N(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:d,subject:c,...u,ts:i}}),f=null,w=!1;try{let h=await $E(r,n,{fixKey:Fa({trackId:e.id,boxId:t.name,epoch:l}),window:xo,context:{...K4(e,t,a,l),ref:d,provider:t.agent??null}});if(h&&(f=await N(e,{type:"code.rework",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:p.id,payload:h}),!(e?.workspace?.kind==="worktree"&&!!e?.workspace?.branch)&&RE(h))){let k=Bc(h),g=h.origins.filter(x=>x.class==="rework").slice(0,3);await N(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:f.id,payload:{sha:n,subject:h.subject,linesReworked:k,origins:g.map(x=>({key:x.key,provider:x.provider,model:x.model,lines:x.lines,ageDays:x.ageDays})),heuristic:h.heuristic,intent:h.intent,ts:i}}),w=!0}}catch(h){o.warn?.(`[rework] ${e.id}: analysis of ${String(n).slice(0,7)} failed: ${h?.message||h}`)}return{recorded:!0,event:p,rework:f,offered:w}}function PE(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 DE(e,t,n){if(!Dc.includes(n)&&n!==ap)throw new Error(`bad cause "${n}" (${Dc.join("|")}|${ap})`);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(PE(r,t))throw new Error("already answered");return N(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 BE(e,t){let n=await K(e);if(!PE(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 N(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 up(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(g=>g.type==="rework.cause.offered"&&g.payload?.pr?.number===n&&(t==null||g.payload.pr.repo===t)))return{offered:!1,reason:"duplicate"};let l=new Set;for(let g of c)if(g.type==="rework.cause.offered")for(let x of Array.isArray(g.payload?.shas)?g.payload.shas:[g.payload?.sha])x&&l.add(x);let u=new Map;for(let g of c)g.type==="code.committed"&&g.payload?.sha&&u.set(g.payload.sha,g.payload.ref??null);let d=Pw({heuristic:cp({subject:r}),subject:r,ref:o}),p=[];for(let g of c){if(g.type!=="code.rework")continue;let x=g.payload||{};if(!x.sha||l.has(x.sha)||x.codeDelta===!1||o&&u.has(x.sha)&&u.get(x.sha)!==o)continue;let S=x.intent?.intent??"unknown";(Ua.has(S)||S==="unknown"&&Ua.has(d.intent))&&Bc(x)!==0&&p.push(x)}let f=p.reduce((g,x)=>g+Bc(x),0);if(f<Nw)return{offered:!1,reason:"below-threshold"};let w=new Map;for(let g of p)for(let x of g.origins??[]){if(x.class!=="rework")continue;let S=w.get(x.key)??{key:x.key,provider:x.provider??null,model:x.model??null,lines:0,ageDays:x.ageDays};S.lines+=x.lines,S.ageDays=Math.min(S.ageDays,x.ageDays),w.set(x.key,S)}let h=p.map(g=>g.sha),y=p.map(g=>g.heuristic).find(g=>g&&g.level!=="C")??cp({subject:r})??p.map(g=>g.heuristic).find(Boolean)??null,k=Ua.has(d.intent)?d:p.find(g=>Ua.has(g.intent?.intent))?.intent??d;return await N(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((g,x)=>x.lines-g.lines).slice(0,3),heuristic:y,intent:k,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 W4,Dw,dp=G(()=>{be();od();lp();W4=H4(U4),Dw=(e,t)=>W4("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4})});import{execFile as J4}from"node:child_process";import{promisify as Y4}from"node:util";async function Bw(e,t,{midTurn:n=is,pollMs:r=X4,capMs:o=Z4}={}){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 WE(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){LE.lastIndex=n;let o=LE.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(`
205
- `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+s2(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 Lw(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function GE(e){let t=WE(e),n=t.match(n2);if(!n)return null;let r=Lw(t,n.index);return o2.test(r)?null:{repo:r.match(qE)?.[1]??null,head:r.match(a2)?.[1]??null}}function KE(e){let t=WE(e),n=t.match(r2);if(!n)return null;let r=Lw(t,n.index),o=Lw(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("-")){c2.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(qE)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function u2(e,t,{exclude:n=()=>!1}={}){let r=async i=>{Sr("observer");let{stdout:c}=await jE("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",l2],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw yo(l)&&bo(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-Q4&&!n(c)),s=await Bn({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 d2(e,t){if(t)return[t];let n=[];for(let r of VE(e)){let o=await Me(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await fr().catch(()=>[])){let o=await Me(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function VE(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 p2(e,t,n){let r=await ja(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)||i2(c.headRefName,e.id),i=[];for(let c of await d2(e,t?.repo??null)){let l;try{l=await u2(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await ft(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 zE(e){if(!e)return 0;let t=0;for(let n of Tr)n.startsWith(`${e}|`)&&t++;return t}function JE(){for(let e of[...jw])e()}function YE(e,t,{delays:n=FE,turnEnd:r}={}){let o=GE(t.command);if(!o)return null;let s=!!KE(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(Tr.has(a))return null;Tr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(h=>{let y=()=>{clearTimeout(k),jw.delete(y),h()},k=setTimeout(y,l);jw.add(y)});let u=await p2(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:p}=u,{link:f,created:w}=await Yt({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 xr(d,p.number))?null:(await Bw(t.box,t.agent,r),await N({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{Tr.delete(a)}})();return c.catch(()=>Tr.delete(a)),c}function XE(e,t,{delays:n=FE,turnEnd:r,openedWait:o}={}){let s=KE(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(Tr.has(a))return null;Tr.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=VE(e);if(w.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let h of w){let y=await Me(h).catch(()=>null);y&&!d.includes(y)&&d.push(y)}}if(l||=(await ja(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 y=await ft(c,w.number);return y&&y.trackId!==e.id?null:(y||await Yt({repo:c,number:w.number,trackId:e.id,url:w.url,headRef:w.headRefName,title:w.title,source:"merge-observed"}),await $c(c,w.number),h&&((await K(e).catch(()=>[])).some(x=>x.type==="pr.state.changed"&&(x.payload?.change==="auto-armed"||x.payload?.change==="merged")&&x.payload?.number===w.number)||(await Bw(t.box,t.agent,r),await N({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(M=>setTimeout(M,w));let h=[];for(let M of d)try{Sr("observer");let{stdout:P}=await jE("gh",["pr","view",String(l),"--repo",M,"--json",f2],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await Bn({slug:M})}}),j=JSON.parse(P||"null");j?.number&&h.push({slug:M,pr:j})}catch(P){yo(P)&&bo(P)}let y=h.find(M=>M.pr.state==="MERGED")??(h.length===1?h[0]:null);if(!y)continue;c=y.slug;let k=y.pr;if(!k?.number)continue;if(k.state==="CLOSED")return null;if(k.state!=="MERGED"){if(f=k,s.auto)return p(k,!0);continue}let g=await ft(c,k.number);if(g&&g.trackId!==e.id)return null;g||await Yt({repo:c,number:k.number,trackId:e.id,url:k.url,headRef:k.headRefName,title:k.title,source:"merge-observed"}),await Bw(t.box,t.agent,r);let x=await K(e).catch(()=>[]);if(x.some(M=>M.type==="pr.state.changed"&&M.payload?.change==="merged"&&M.payload?.number===k.number))return null;let S=M=>M.some(P=>P.type==="pr.state.changed"&&P.payload?.change==="opened"&&P.payload?.number===k.number),_=0;if(!S(x)){if(GE(t.command)&&await xr(c,k.number)){let M=Date.now();_=M+1,await N({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:M,change:"opened",number:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c,selfMerge:!0}})}else if((await ft(c,k.number))?.announced){let M=o?.capMs??e2,P=o?.pollMs??t2,j=Date.now()+M;for(;Date.now()<j&&(await new Promise(T=>setTimeout(T,P)),!S(await K(e).catch(()=>[]))););}}return await N({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:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c}}),await up(e,{repo:c,number:k.number,title:k.title,branch:k.headRefName,url:k.url}).catch(()=>{}),await _r(c,k.number).catch(()=>{}),await Er(c,k.number).catch(()=>{}),await wo(c,k.number,"merged"),k}return f?p(f,!1):null}finally{Tr.delete(a)}})();return i.catch(()=>Tr.delete(a)),i}var jE,FE,X4,Z4,Q4,e2,t2,UE,HE,n2,r2,o2,LE,s2,qE,a2,i2,c2,l2,Tr,jw,f2,pp=G(()=>{be();Gr();xt();Oc();Gn();Ir();va();Ss();dp();jE=Y4(J4),FE=[4e3,15e3,45e3],X4=2500,Z4=5*6e4;Q4=15e3,e2=9e4,t2=2e3,UE=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,HE=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,n2=new RegExp(`${UE}${HE}create\\b`),r2=new RegExp(`${UE}${HE}merge\\b`),o2=/\s--web\b/,LE=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,s2=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");qE=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,a2=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,i2=kE;c2=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);l2="number,url,title,headRefName,createdAt";Tr=new Set;jw=new Set;f2="number,url,title,headRefName,state"});import m2 from"node:fs/promises";import Uw from"node:path";import h2 from"node:os";function Fw(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function fp(e){let t=w2.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=Fw(n,"from"),s=o?o.replace(/^uds:/,""):null,a=ZE(s);return{socket:s,pid:a,name:Fw(n,"from-name"),mode:Fw(n,"from-mode"),text:r.trim()}}function ZE(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function g2(){return process.env.CLAUDE_CONFIG_DIR?Uw.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):Uw.join(h2.homedir(),".claude","sessions")}async function y2(e){let t=ZE(e);if(!t)return null;try{let n=await m2.readFile(Uw.join(g2(),`${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 QE(e,t){let n=await y2(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 w2,Hw=G(()=>{w2=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function e_(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}async function t_(e,t,n=Ww){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await k2(`${De(t)}${e}`,{headers:x2(t),signal:r.signal})}finally{clearTimeout(o)}}async function Lc({env:e=process.env,force:t=!1,timeoutMs:n=Ww}={}){if(!e_(e))return{followups:[],source:"unconfigured"};if(!t&&As&&Date.now()-As.at<b2)return{followups:As.followups,source:"cache"};try{let r=await t_("/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 n_(e,{env:t=process.env,timeoutMs:n=Ww}={}){if(!e)return{followup:null,source:"unconfigured"};if(!e_(t))return{followup:null,source:"unconfigured"};try{let r=await t_(`/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 b2,Ww,As,k2,x2,r_=G(()=>{xt();b2=6e4,Ww=5e3,As=null,k2=(...e)=>fetch(...e);x2=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});async function vo(e,t){if(qw.has(e)){let n=new Error("offer already answered (answer in flight)");throw n.code="answer-in-flight",n}qw.add(e);try{return await t()}finally{qw.delete(e)}}var qw,jc=G(()=>{qw=new Set});import{randomUUID as Ts,createHash as v2}from"node:crypto";function mp(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function p_(e){for(let[t,n]of E2)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 i_(e,{at:t="",promptRequired:n=!0,standing:r=!1}={}){let o=e&&typeof e=="object"?e:{},s=Es(o.label).replace(/\s+/g," ");if(!s)throw new Error(`${t}label required (\u2264${Gw} chars, e.g. "Deploy to Pi")`);if(s.length>Gw)throw new Error(`${t}label must be \u2264${Gw} characters`);let a=Es(o.prompt);if(n&&!a)throw new Error(`${t}prompt required \u2014 the full instruction a fresh session could execute`);if(Buffer.byteLength(a,"utf8")>o_)throw new Error(`${t}prompt must be \u2264${o_} bytes`);if(r){let l=p_(a);if(l)throw new Error(`${t}${l}`)}let i=o.standing==null||o.standing===""?"offerable":String(o.standing).trim().toLowerCase();if(!T2.includes(i))throw new Error(`${t}standing must be "offerable" or "never", got "${o.standing}"`);let c=Es(o.why).slice(0,l_)||null;return{label:s,prompt:a,why:c,standing:i}}function f_(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=Es(n.trigger)||(n.ship?"now":""),o=t?S2:u_.filter(p=>p!=="track.opened");if(!o.includes(r))throw new Error(`trigger must be one of ${o.join(" | ")}${t?" (a standing follow-up can't be `now` \u2014 it would fire every turn)":""}, got "${n.trigger??""}"`);let s=n.ship&&r==="now"?$2(n.ship):null,a=n.items!=null;if(a&&s)throw new Error("a ship offer has its own card \u2014 `items` cannot be combined with a `ship` block");let i,c=null;if(a){if(!Array.isArray(n.items)||!n.items.length)throw new Error("items must be a non-empty array of {label, prompt, why?, standing?}");if(n.items.length>a_)throw new Error(`items must be \u2264${a_} \u2014 one item per step the operator might run, save or skip separately`);if(t&&n.items.length>1)throw new Error("propose one standing follow-up at a time \u2014 a standing follow-up is one prompt");i=n.items.map((f,w)=>i_(f,{at:`items[${w}]: `,standing:t})),c=Es(n.why).slice(0,l_)||null;let p=new Set;for(let f of i){let w=mp(f.label);if(p.has(w))throw new Error(`items must have distinct labels ("${f.label}" appears twice)`);p.add(w)}}else i=[i_(n,{promptRequired:!s,standing:t})];let l=i[0],u=c??l.why,d=t?I2(n.repo):null;return{label:l.label,prompt:l.prompt,trigger:r,why:u,planWhy:c,items:i,...d?{repo:d}:{},...s?{ship:s}:{}}}function _2(e){return e.standing==="never"?{promotable:!1,promotableReason:"one-off"}:p_(e.prompt)?{promotable:!1,promotableReason:"specifics"}:{promotable:!0,promotableReason:null}}function I2(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 $2(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):Kw.slice();for(let i of n)if(!Kw.includes(i))throw new Error(`ship.actions may only contain ${Kw.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=Es(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=>Es(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function hp(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)}function m_(e){return{armId:e.armId,label:e.label,prompt:e.prompt,promptHash:d_(e.prompt),origin:"agent",why:e.why??null,groupId:e.groupId??null,seq:Number.isInteger(e.seq)?e.seq:0,standing:e.standing==="never"?"never":"offerable",..._2(e)}}async function h_(e,t,{pull:n=Lc,ship:r={}}={}){if(zw(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=f_(t);if(o.ship)return{kind:"ship",...await N2(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},c=Ts(),l=(g,x,S={})=>({ts:Date.now(),armId:Ts(),trigger:o.trigger,label:g.label,prompt:g.prompt,why:g.why,standing:g.standing,groupId:c,seq:x,...o.planWhy?{planWhy:o.planWhy}:{},...S}),u={groupId:c,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,planWhy:o.planWhy};if(o.trigger==="now"){let g=Ts(),x=[];for(let[S,_]of o.items.entries()){let M=l(_,S);await N(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:M}),x.push(M)}return await N(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:g,trigger:"now",repo:e.workspace?.repo||null,context:{},groupId:c,why:o.planWhy,rows:x.map(m_)}}),{kind:"now",offerId:g,armId:x[0].armId,items:x.map(S=>({armId:S.armId,label:S.label,standing:S.standing})),...u}}let d=e.workspace?.repo||null,{followups:p}=await n().catch(()=>({followups:[]})),f=await K(s),w=hp(f,{trigger:o.trigger}),h=[],y=0;for(let g of o.items){let x=mp(g.label),S=p.find(j=>j.status==="active"&&j.mode!=="off"&&j.trigger===o.trigger&&(j.repo==null||j.repo===d)&&j.dedupeKey===x);if(S){h.push({label:g.label,standing:g.standing,covered:{id:S.id,label:S.label}});continue}let _=w.filter(j=>mp(j.label)===x),M=_.length?_[_.length-1].armId:null,P=l(g,y++,M?{replaces:M}:{});await N(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:P}),h.push({armId:P.armId,label:g.label,standing:g.standing,replaces:M})}let k=h.filter(g=>g.armId);return k.length?{kind:"armed",armId:k[0].armId,replaces:k[0].replaces,items:h,...u}:{kind:"covered",covered:h[0].covered,items:h,...u}}async function w_(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await K(n);if(!hp(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await N(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function g_(e,t,{pull:n=Lc}={}){if(zw(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=f_(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await K(s)).reduce((y,k)=>k.type==="followup.create.offered"?k.payload?.proposalId??y:k.type==="followup.create.answered"&&k.payload?.proposalId===y?null:y,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=mp(r.label),d=c.filter(y=>y.dedupeKey===u&&y.trigger===r.trigger),p=d.find(y=>y.status==="deleted"),f=d.find(y=>y.status!=="deleted");if(f)throw new Error(`"${f.label}" (${Vw[f.trigger]||f.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(p){let y=p.deletedAt?new Date(p.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${p.label}" on ${y} \u2014 do not re-propose it`)}let w=Ts(),h=(e.boxes||[]).find(y=>y.name===e.leadBox)||null;return await N(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 y_(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 N(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 N(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 N(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 Fc(e,t,n={},{pull:r=Lc}={}){if(!e||zw(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 k=S=>{let _=(S?.prs||[]).filter(M=>Number.isFinite(Number(M?.number))).map(M=>`${M?.repo??S?.repo??""}#${Number(M.number)}`);return Number.isFinite(Number(S?.prNumber))&&_.push(`${S?.repo??""}#${Number(S.prNumber)}`),_},g=new Set(k(n));if(s.some(S=>S.type==="followup.offered"&&S.payload?.trigger==="pr.merged"&&k(S.payload?.context).some(_=>g.has(_))))return null}let i=hp(s,{trigger:t}),c=i.length?i[i.length-1].groupId??null:null,l=new Map(i.map((k,g)=>[k.armId,g])),u=k=>k.groupId&&k.groupId===c?0:1,d=i.slice().sort((k,g)=>u(k)-u(g)||l.get(k.armId)-l.get(g.armId)).slice(0,s_).map(m_),p=c?i.find(k=>k.groupId===c&&k.planWhy)?.planWhy??null:null,f=[];if(t!=="now"){let{followups:k}=await r().catch(()=>({followups:[]}));f=k.filter(g=>g.status==="active"&&g.mode!=="off"&&g.trigger===t&&(g.repo==null||g.repo===a)).sort((g,x)=>{let S=_=>_.stats?.offered?(_.stats.accepted||0)/_.stats.offered:0;return S(x)-S(g)||(g.origin==="operator"?-1:0)-(x.origin==="operator"?-1:0)||(x.createdAt||0)-(g.createdAt||0)}).slice(0,A2).map(g=>({followupId:g.id,label:g.label,promptPreview:R2(g.prompt),promptHash:d_(g.prompt),origin:g.origin,repo:g.repo??null}))}let w=[...d,...f].slice(0,s_);if(!w.length)return null;let h=Ts(),y={ts:Date.now(),offerId:h,trigger:t,repo:a,context:{...n,repo:a},groupId:c,why:p,rows:w};return await N(o,{type:"followup.offered",actor:"system",source:"orchestrator",payload:y}),y}function O2(e,t){let n=t?.rows||[],r=a=>a.armId?`arm:${a.armId}`:`fu:${a.followupId}`,o=new Map(n.map(a=>[r(a),null])),s=(a,i)=>{o.has(a)&&o.get(a)==null&&o.set(a,i)};for(let a of e){if(a.type!=="followup.answered"||a.payload?.offerId!==t.offerId)continue;let i=a.payload,c=[];i.armId&&c.push(`arm:${i.armId}`),i.followupId&&c.push(`fu:${i.followupId}`);for(let l of Array.isArray(i.armIds)?i.armIds:[])c.push(`arm:${l}`);for(let l of Array.isArray(i.followupIds)?i.followupIds:[])c.push(`fu:${l}`);if(c.length)for(let l of c)s(l,i.action);else for(let l of o.keys())s(l,i.action)}return o}function c_(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 b_(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null,all:s=!1}={},a={}){if(!t)throw new Error("offerId required");return vo(`fu:${e.id}:${t}`,()=>C2(e,{offerId:t,followupId:n,armId:r,promoted:o,all:s===!0},a))}async function C2(e,{offerId:t,followupId:n,armId:r,promoted:o,all:s},a){let{sayToLead:i,unarchiveTrack:c,getFollowup:l=n_}=a,u={id:e.id,cwd:e.cwd},d=await K(u),p=d.find(T=>T.type==="followup.offered"&&T.payload?.offerId===t);if(!p)throw new Error("unknown offer");let f=p.payload.rows||[],w=O2(d,p.payload),h=M2(w,f);if(!h.length)throw new Error("offer already answered");let y=T=>N(u,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...T}}),k=async()=>{if(!e.archivedAt)return!1;if(!c)throw new Error("this Track is archived");return await c(e.id,{freshSession:!0}),e={...e,archivedAt:null},!0},g=T=>{let L=d.find(H=>H.type==="followup.armed"&&H.payload?.armId===T.armId)?.payload?.prompt??T.prompt;if(!L)throw new Error("the arm's prompt is missing from the log");return L};if(s){let T=p.payload.groupId??null,$=h.filter(B=>B.armId&&(!T||B.groupId===T)).sort((B,Z)=>(B.seq??0)-(Z.seq??0));if(!$.length)throw new Error("nothing to run together \u2014 no open items from this plan remain on the card");let L=$.map(B=>({row:B,prompt:g(B)})),H=await k();if(!i)throw new Error("sayToLead unavailable");let R=`${c_(p.payload).replace(/:$/,"")} \u2014 ${L.length} steps, in order:`,A=L.map((B,Z)=>`${Z+1}. ${B.row.label}
204
+ `).trim().slice(0,300)||null}catch{return{recorded:!1,reason:"unknown-sha"}}let l=ME(t,i),u=await z4(r,n),d=await J4(r),p=await N(e,{type:"code.committed",actor:"agent",source:"hook",boxId:t.name,provider:t.agent??null,payload:{sha:n,ref:d,subject:c,...u,ts:i}}),f=null,w=!1;try{let h=await $E(r,n,{fixKey:Fa({trackId:e.id,boxId:t.name,epoch:l}),window:xo,context:{...V4(e,t,a,l),ref:d,provider:t.agent??null}});if(h&&(f=await N(e,{type:"code.rework",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:p.id,payload:h}),!(e?.workspace?.kind==="worktree"&&!!e?.workspace?.branch)&&RE(h))){let k=Bc(h),g=h.origins.filter(x=>x.class==="rework").slice(0,3);await N(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:f.id,payload:{sha:n,subject:h.subject,linesReworked:k,origins:g.map(x=>({key:x.key,provider:x.provider,model:x.model,lines:x.lines,ageDays:x.ageDays})),heuristic:h.heuristic,intent:h.intent,ts:i}}),w=!0}}catch(h){o.warn?.(`[rework] ${e.id}: analysis of ${String(n).slice(0,7)} failed: ${h?.message||h}`)}return{recorded:!0,event:p,rework:f,offered:w}}function PE(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 DE(e,t,n){if(!Dc.includes(n)&&n!==ip)throw new Error(`bad cause "${n}" (${Dc.join("|")}|${ip})`);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(PE(r,t))throw new Error("already answered");return N(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 BE(e,t){let n=await K(e);if(!PE(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 N(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 dp(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(g=>g.type==="rework.cause.offered"&&g.payload?.pr?.number===n&&(t==null||g.payload.pr.repo===t)))return{offered:!1,reason:"duplicate"};let l=new Set;for(let g of c)if(g.type==="rework.cause.offered")for(let x of Array.isArray(g.payload?.shas)?g.payload.shas:[g.payload?.sha])x&&l.add(x);let u=new Map;for(let g of c)g.type==="code.committed"&&g.payload?.sha&&u.set(g.payload.sha,g.payload.ref??null);let d=Pw({heuristic:lp({subject:r}),subject:r,ref:o}),p=[];for(let g of c){if(g.type!=="code.rework")continue;let x=g.payload||{};if(!x.sha||l.has(x.sha)||x.codeDelta===!1||o&&u.has(x.sha)&&u.get(x.sha)!==o)continue;let S=x.intent?.intent??"unknown";(Ua.has(S)||S==="unknown"&&Ua.has(d.intent))&&Bc(x)!==0&&p.push(x)}let f=p.reduce((g,x)=>g+Bc(x),0);if(f<Nw)return{offered:!1,reason:"below-threshold"};let w=new Map;for(let g of p)for(let x of g.origins??[]){if(x.class!=="rework")continue;let S=w.get(x.key)??{key:x.key,provider:x.provider??null,model:x.model??null,lines:0,ageDays:x.ageDays};S.lines+=x.lines,S.ageDays=Math.min(S.ageDays,x.ageDays),w.set(x.key,S)}let h=p.map(g=>g.sha),y=p.map(g=>g.heuristic).find(g=>g&&g.level!=="C")??lp({subject:r})??p.map(g=>g.heuristic).find(Boolean)??null,k=Ua.has(d.intent)?d:p.find(g=>Ua.has(g.intent?.intent))?.intent??d;return await N(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((g,x)=>x.lines-g.lines).slice(0,3),heuristic:y,intent:k,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 q4,Dw,pp=G(()=>{be();sd();up();q4=W4(H4),Dw=(e,t)=>q4("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4})});import{execFile as Y4}from"node:child_process";import{promisify as X4}from"node:util";async function Bw(e,t,{midTurn:n=is,pollMs:r=Z4,capMs:o=Q4}={}){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 WE(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){LE.lastIndex=n;let o=LE.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(`
205
+ `,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+a2(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 Lw(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function GE(e){let t=WE(e),n=t.match(r2);if(!n)return null;let r=Lw(t,n.index);return s2.test(r)?null:{repo:r.match(qE)?.[1]??null,head:r.match(i2)?.[1]??null}}function KE(e){let t=WE(e),n=t.match(o2);if(!n)return null;let r=Lw(t,n.index),o=Lw(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("-")){l2.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(qE)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function d2(e,t,{exclude:n=()=>!1}={}){let r=async i=>{Sr("observer");let{stdout:c}=await jE("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",u2],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw yo(l)&&bo(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-e2&&!n(c)),s=await Bn({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 p2(e,t){if(t)return[t];let n=[];for(let r of VE(e)){let o=await Me(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await fr().catch(()=>[])){let o=await Me(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function VE(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 f2(e,t,n){let r=await ja(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)||c2(c.headRefName,e.id),i=[];for(let c of await p2(e,t?.repo??null)){let l;try{l=await d2(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await ft(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 zE(e){if(!e)return 0;let t=0;for(let n of Ar)n.startsWith(`${e}|`)&&t++;return t}function JE(){for(let e of[...jw])e()}function YE(e,t,{delays:n=FE,turnEnd:r}={}){let o=GE(t.command);if(!o)return null;let s=!!KE(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(Ar.has(a))return null;Ar.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(h=>{let y=()=>{clearTimeout(k),jw.delete(y),h()},k=setTimeout(y,l);jw.add(y)});let u=await f2(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:p}=u,{link:f,created:w}=await Yt({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 xr(d,p.number))?null:(await Bw(t.box,t.agent,r),await N({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{Ar.delete(a)}})();return c.catch(()=>Ar.delete(a)),c}function XE(e,t,{delays:n=FE,turnEnd:r,openedWait:o}={}){let s=KE(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(Ar.has(a))return null;Ar.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=VE(e);if(w.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let h of w){let y=await Me(h).catch(()=>null);y&&!d.includes(y)&&d.push(y)}}if(l||=(await ja(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 y=await ft(c,w.number);return y&&y.trackId!==e.id?null:(y||await Yt({repo:c,number:w.number,trackId:e.id,url:w.url,headRef:w.headRefName,title:w.title,source:"merge-observed"}),await $c(c,w.number),h&&((await K(e).catch(()=>[])).some(x=>x.type==="pr.state.changed"&&(x.payload?.change==="auto-armed"||x.payload?.change==="merged")&&x.payload?.number===w.number)||(await Bw(t.box,t.agent,r),await N({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(M=>setTimeout(M,w));let h=[];for(let M of d)try{Sr("observer");let{stdout:P}=await jE("gh",["pr","view",String(l),"--repo",M,"--json",m2],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await Bn({slug:M})}}),j=JSON.parse(P||"null");j?.number&&h.push({slug:M,pr:j})}catch(P){yo(P)&&bo(P)}let y=h.find(M=>M.pr.state==="MERGED")??(h.length===1?h[0]:null);if(!y)continue;c=y.slug;let k=y.pr;if(!k?.number)continue;if(k.state==="CLOSED")return null;if(k.state!=="MERGED"){if(f=k,s.auto)return p(k,!0);continue}let g=await ft(c,k.number);if(g&&g.trackId!==e.id)return null;g||await Yt({repo:c,number:k.number,trackId:e.id,url:k.url,headRef:k.headRefName,title:k.title,source:"merge-observed"}),await Bw(t.box,t.agent,r);let x=await K(e).catch(()=>[]);if(x.some(M=>M.type==="pr.state.changed"&&M.payload?.change==="merged"&&M.payload?.number===k.number))return null;let S=M=>M.some(P=>P.type==="pr.state.changed"&&P.payload?.change==="opened"&&P.payload?.number===k.number),_=0;if(!S(x)){if(GE(t.command)&&await xr(c,k.number)){let M=Date.now();_=M+1,await N({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:M,change:"opened",number:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c,selfMerge:!0}})}else if((await ft(c,k.number))?.announced){let M=o?.capMs??t2,P=o?.pollMs??n2,j=Date.now()+M;for(;Date.now()<j&&(await new Promise(A=>setTimeout(A,P)),!S(await K(e).catch(()=>[]))););}}return await N({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:k.number,url:k.url,title:k.title,branch:k.headRefName,repo:c}}),await dp(e,{repo:c,number:k.number,title:k.title,branch:k.headRefName,url:k.url}).catch(()=>{}),await _r(c,k.number).catch(()=>{}),await Er(c,k.number).catch(()=>{}),await wo(c,k.number,"merged"),k}return f?p(f,!1):null}finally{Ar.delete(a)}})();return i.catch(()=>Ar.delete(a)),i}var jE,FE,Z4,Q4,e2,t2,n2,UE,HE,r2,o2,s2,LE,a2,qE,i2,c2,l2,u2,Ar,jw,m2,fp=G(()=>{be();Gr();xt();Oc();Gn();Ir();va();Ss();pp();jE=X4(Y4),FE=[4e3,15e3,45e3],Z4=2500,Q4=5*6e4;e2=15e3,t2=9e4,n2=2e3,UE=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,HE=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,r2=new RegExp(`${UE}${HE}create\\b`),o2=new RegExp(`${UE}${HE}merge\\b`),s2=/\s--web\b/,LE=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,a2=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");qE=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,i2=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,c2=kE;l2=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);u2="number,url,title,headRefName,createdAt";Ar=new Set;jw=new Set;m2="number,url,title,headRefName,state"});import h2 from"node:fs/promises";import Uw from"node:path";import w2 from"node:os";function Fw(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function mp(e){let t=g2.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=Fw(n,"from"),s=o?o.replace(/^uds:/,""):null,a=ZE(s);return{socket:s,pid:a,name:Fw(n,"from-name"),mode:Fw(n,"from-mode"),text:r.trim()}}function ZE(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function y2(){return process.env.CLAUDE_CONFIG_DIR?Uw.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):Uw.join(w2.homedir(),".claude","sessions")}async function b2(e){let t=ZE(e);if(!t)return null;try{let n=await h2.readFile(Uw.join(y2(),`${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 QE(e,t){let n=await b2(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 g2,Hw=G(()=>{g2=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function e_(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}async function t_(e,t,n=Ww){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await x2(`${De(t)}${e}`,{headers:v2(t),signal:r.signal})}finally{clearTimeout(o)}}async function Lc({env:e=process.env,force:t=!1,timeoutMs:n=Ww}={}){if(!e_(e))return{followups:[],source:"unconfigured"};if(!t&&Ts&&Date.now()-Ts.at<k2)return{followups:Ts.followups,source:"cache"};try{let r=await t_("/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 Ts={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return Ts?{followups:Ts.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function n_(e,{env:t=process.env,timeoutMs:n=Ww}={}){if(!e)return{followup:null,source:"unconfigured"};if(!e_(t))return{followup:null,source:"unconfigured"};try{let r=await t_(`/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=Ts?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var k2,Ww,Ts,x2,v2,r_=G(()=>{xt();k2=6e4,Ww=5e3,Ts=null,x2=(...e)=>fetch(...e);v2=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});async function vo(e,t){if(qw.has(e)){let n=new Error("offer already answered (answer in flight)");throw n.code="answer-in-flight",n}qw.add(e);try{return await t()}finally{qw.delete(e)}}var qw,jc=G(()=>{qw=new Set});import{randomUUID as As,createHash as S2}from"node:crypto";function hp(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function p_(e){for(let[t,n]of _2)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 i_(e,{at:t="",promptRequired:n=!0,standing:r=!1}={}){let o=e&&typeof e=="object"?e:{},s=Es(o.label).replace(/\s+/g," ");if(!s)throw new Error(`${t}label required (\u2264${Gw} chars, e.g. "Deploy to Pi")`);if(s.length>Gw)throw new Error(`${t}label must be \u2264${Gw} characters`);let a=Es(o.prompt);if(n&&!a)throw new Error(`${t}prompt required \u2014 the full instruction a fresh session could execute`);if(Buffer.byteLength(a,"utf8")>o_)throw new Error(`${t}prompt must be \u2264${o_} bytes`);if(r){let l=p_(a);if(l)throw new Error(`${t}${l}`)}let i=o.standing==null||o.standing===""?"offerable":String(o.standing).trim().toLowerCase();if(!E2.includes(i))throw new Error(`${t}standing must be "offerable" or "never", got "${o.standing}"`);let c=Es(o.why).slice(0,l_)||null;return{label:s,prompt:a,why:c,standing:i}}function f_(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=Es(n.trigger)||(n.ship?"now":""),o=t?T2:u_.filter(p=>p!=="track.opened");if(!o.includes(r))throw new Error(`trigger must be one of ${o.join(" | ")}${t?" (a standing follow-up can't be `now` \u2014 it would fire every turn)":""}, got "${n.trigger??""}"`);let s=n.ship&&r==="now"?R2(n.ship):null,a=n.items!=null;if(a&&s)throw new Error("a ship offer has its own card \u2014 `items` cannot be combined with a `ship` block");let i,c=null;if(a){if(!Array.isArray(n.items)||!n.items.length)throw new Error("items must be a non-empty array of {label, prompt, why?, standing?}");if(n.items.length>a_)throw new Error(`items must be \u2264${a_} \u2014 one item per step the operator might run, save or skip separately`);if(t&&n.items.length>1)throw new Error("propose one standing follow-up at a time \u2014 a standing follow-up is one prompt");i=n.items.map((f,w)=>i_(f,{at:`items[${w}]: `,standing:t})),c=Es(n.why).slice(0,l_)||null;let p=new Set;for(let f of i){let w=hp(f.label);if(p.has(w))throw new Error(`items must have distinct labels ("${f.label}" appears twice)`);p.add(w)}}else i=[i_(n,{promptRequired:!s,standing:t})];let l=i[0],u=c??l.why,d=t?$2(n.repo):null;return{label:l.label,prompt:l.prompt,trigger:r,why:u,planWhy:c,items:i,...d?{repo:d}:{},...s?{ship:s}:{}}}function I2(e){return e.standing==="never"?{promotable:!1,promotableReason:"one-off"}:p_(e.prompt)?{promotable:!1,promotableReason:"specifics"}:{promotable:!0,promotableReason:null}}function $2(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 R2(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):Kw.slice();for(let i of n)if(!Kw.includes(i))throw new Error(`ship.actions may only contain ${Kw.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=Es(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=>Es(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function wp(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)}function m_(e){return{armId:e.armId,label:e.label,prompt:e.prompt,promptHash:d_(e.prompt),origin:"agent",why:e.why??null,groupId:e.groupId??null,seq:Number.isInteger(e.seq)?e.seq:0,standing:e.standing==="never"?"never":"offerable",...I2(e)}}async function h_(e,t,{pull:n=Lc,ship:r={}}={}){if(zw(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=f_(t);if(o.ship)return{kind:"ship",...await P2(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},c=As(),l=(g,x,S={})=>({ts:Date.now(),armId:As(),trigger:o.trigger,label:g.label,prompt:g.prompt,why:g.why,standing:g.standing,groupId:c,seq:x,...o.planWhy?{planWhy:o.planWhy}:{},...S}),u={groupId:c,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,planWhy:o.planWhy};if(o.trigger==="now"){let g=As(),x=[];for(let[S,_]of o.items.entries()){let M=l(_,S);await N(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:M}),x.push(M)}return await N(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:g,trigger:"now",repo:e.workspace?.repo||null,context:{},groupId:c,why:o.planWhy,rows:x.map(m_)}}),{kind:"now",offerId:g,armId:x[0].armId,items:x.map(S=>({armId:S.armId,label:S.label,standing:S.standing})),...u}}let d=e.workspace?.repo||null,{followups:p}=await n().catch(()=>({followups:[]})),f=await K(s),w=wp(f,{trigger:o.trigger}),h=[],y=0;for(let g of o.items){let x=hp(g.label),S=p.find(j=>j.status==="active"&&j.mode!=="off"&&j.trigger===o.trigger&&(j.repo==null||j.repo===d)&&j.dedupeKey===x);if(S){h.push({label:g.label,standing:g.standing,covered:{id:S.id,label:S.label}});continue}let _=w.filter(j=>hp(j.label)===x),M=_.length?_[_.length-1].armId:null,P=l(g,y++,M?{replaces:M}:{});await N(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:P}),h.push({armId:P.armId,label:g.label,standing:g.standing,replaces:M})}let k=h.filter(g=>g.armId);return k.length?{kind:"armed",armId:k[0].armId,replaces:k[0].replaces,items:h,...u}:{kind:"covered",covered:h[0].covered,items:h,...u}}async function w_(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await K(n);if(!wp(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await N(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function g_(e,t,{pull:n=Lc}={}){if(zw(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=f_(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await K(s)).reduce((y,k)=>k.type==="followup.create.offered"?k.payload?.proposalId??y:k.type==="followup.create.answered"&&k.payload?.proposalId===y?null:y,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=hp(r.label),d=c.filter(y=>y.dedupeKey===u&&y.trigger===r.trigger),p=d.find(y=>y.status==="deleted"),f=d.find(y=>y.status!=="deleted");if(f)throw new Error(`"${f.label}" (${Vw[f.trigger]||f.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(p){let y=p.deletedAt?new Date(p.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${p.label}" on ${y} \u2014 do not re-propose it`)}let w=As(),h=(e.boxes||[]).find(y=>y.name===e.leadBox)||null;return await N(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 y_(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 N(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 N(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 N(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 Fc(e,t,n={},{pull:r=Lc}={}){if(!e||zw(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 k=S=>{let _=(S?.prs||[]).filter(M=>Number.isFinite(Number(M?.number))).map(M=>`${M?.repo??S?.repo??""}#${Number(M.number)}`);return Number.isFinite(Number(S?.prNumber))&&_.push(`${S?.repo??""}#${Number(S.prNumber)}`),_},g=new Set(k(n));if(s.some(S=>S.type==="followup.offered"&&S.payload?.trigger==="pr.merged"&&k(S.payload?.context).some(_=>g.has(_))))return null}let i=wp(s,{trigger:t}),c=i.length?i[i.length-1].groupId??null:null,l=new Map(i.map((k,g)=>[k.armId,g])),u=k=>k.groupId&&k.groupId===c?0:1,d=i.slice().sort((k,g)=>u(k)-u(g)||l.get(k.armId)-l.get(g.armId)).slice(0,s_).map(m_),p=c?i.find(k=>k.groupId===c&&k.planWhy)?.planWhy??null:null,f=[];if(t!=="now"){let{followups:k}=await r().catch(()=>({followups:[]}));f=k.filter(g=>g.status==="active"&&g.mode!=="off"&&g.trigger===t&&(g.repo==null||g.repo===a)).sort((g,x)=>{let S=_=>_.stats?.offered?(_.stats.accepted||0)/_.stats.offered:0;return S(x)-S(g)||(g.origin==="operator"?-1:0)-(x.origin==="operator"?-1:0)||(x.createdAt||0)-(g.createdAt||0)}).slice(0,A2).map(g=>({followupId:g.id,label:g.label,promptPreview:O2(g.prompt),promptHash:d_(g.prompt),origin:g.origin,repo:g.repo??null}))}let w=[...d,...f].slice(0,s_);if(!w.length)return null;let h=As(),y={ts:Date.now(),offerId:h,trigger:t,repo:a,context:{...n,repo:a},groupId:c,why:p,rows:w};return await N(o,{type:"followup.offered",actor:"system",source:"orchestrator",payload:y}),y}function M2(e,t){let n=t?.rows||[],r=a=>a.armId?`arm:${a.armId}`:`fu:${a.followupId}`,o=new Map(n.map(a=>[r(a),null])),s=(a,i)=>{o.has(a)&&o.get(a)==null&&o.set(a,i)};for(let a of e){if(a.type!=="followup.answered"||a.payload?.offerId!==t.offerId)continue;let i=a.payload,c=[];i.armId&&c.push(`arm:${i.armId}`),i.followupId&&c.push(`fu:${i.followupId}`);for(let l of Array.isArray(i.armIds)?i.armIds:[])c.push(`arm:${l}`);for(let l of Array.isArray(i.followupIds)?i.followupIds:[])c.push(`fu:${l}`);if(c.length)for(let l of c)s(l,i.action);else for(let l of o.keys())s(l,i.action)}return o}function c_(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 b_(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null,all:s=!1}={},a={}){if(!t)throw new Error("offerId required");return vo(`fu:${e.id}:${t}`,()=>N2(e,{offerId:t,followupId:n,armId:r,promoted:o,all:s===!0},a))}async function N2(e,{offerId:t,followupId:n,armId:r,promoted:o,all:s},a){let{sayToLead:i,unarchiveTrack:c,getFollowup:l=n_}=a,u={id:e.id,cwd:e.cwd},d=await K(u),p=d.find(A=>A.type==="followup.offered"&&A.payload?.offerId===t);if(!p)throw new Error("unknown offer");let f=p.payload.rows||[],w=M2(d,p.payload),h=C2(w,f);if(!h.length)throw new Error("offer already answered");let y=A=>N(u,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...A}}),k=async()=>{if(!e.archivedAt)return!1;if(!c)throw new Error("this Track is archived");return await c(e.id,{freshSession:!0}),e={...e,archivedAt:null},!0},g=A=>{let L=d.find(H=>H.type==="followup.armed"&&H.payload?.armId===A.armId)?.payload?.prompt??A.prompt;if(!L)throw new Error("the arm's prompt is missing from the log");return L};if(s){let A=p.payload.groupId??null,$=h.filter(B=>B.armId&&(!A||B.groupId===A)).sort((B,Z)=>(B.seq??0)-(Z.seq??0));if(!$.length)throw new Error("nothing to run together \u2014 no open items from this plan remain on the card");let L=$.map(B=>({row:B,prompt:g(B)})),H=await k();if(!i)throw new Error("sayToLead unavailable");let R=`${c_(p.payload).replace(/:$/,"")} \u2014 ${L.length} steps, in order:`,T=L.map((B,Z)=>`${Z+1}. ${B.row.label}
206
206
  ${B.prompt}`).join(`
207
207
 
208
208
  `),C=await i(e.id,`${R}
209
209
 
210
- ${A}`,{kind:"followup-go"}),W=Ts();for(let[B,Z]of L.entries())await y({action:"sent",armId:Z.row.armId,label:Z.row.label,batchId:W,...B===0&&H?{revived:!0}:{},source:`arm:${Z.row.armId}`});return{offerId:t,action:"sent",all:!0,batchId:W,armIds:L.map(B=>B.row.armId),revived:H,remaining:h.length-L.length,queued:!!C?.queued}}if(!n&&!r)return await y({action:"dismiss",followupIds:h.map(T=>T.followupId).filter(Boolean),armIds:h.map(T=>T.armId).filter(Boolean)}),{offerId:t,action:"dismiss",remaining:0};let x=null,S=null,_=n?`fu:${n}`:`arm:${r}`;if(n){if(!f.find(H=>H.followupId===n))throw new Error("that follow-up is not on this card");if(w.get(_)!=null)throw new Error("that row is already answered");let{followup:$,source:L}=await l(n);if(L==="unreachable")throw new Error("plane unreachable \u2014 the follow-up's current prompt can't be read; try again shortly");if(!$||$.status!=="active"){await y({action:"removed",followupId:n});let H=new Error("removed in Settings since it was offered");throw H.code="removed",H}x=$.prompt,S=$.label}else{let T=f.find($=>$.armId===r);if(!T)throw new Error("that arm is not on this card");if(w.get(_)!=null)throw new Error("that row is already answered");x=g(T),S=T.label}let M=await k();if(!i)throw new Error("sayToLead unavailable");let P=`${c_(p.payload)}
210
+ ${T}`,{kind:"followup-go"}),W=As();for(let[B,Z]of L.entries())await y({action:"sent",armId:Z.row.armId,label:Z.row.label,batchId:W,...B===0&&H?{revived:!0}:{},source:`arm:${Z.row.armId}`});return{offerId:t,action:"sent",all:!0,batchId:W,armIds:L.map(B=>B.row.armId),revived:H,remaining:h.length-L.length,queued:!!C?.queued}}if(!n&&!r)return await y({action:"dismiss",followupIds:h.map(A=>A.followupId).filter(Boolean),armIds:h.map(A=>A.armId).filter(Boolean)}),{offerId:t,action:"dismiss",remaining:0};let x=null,S=null,_=n?`fu:${n}`:`arm:${r}`;if(n){if(!f.find(H=>H.followupId===n))throw new Error("that follow-up is not on this card");if(w.get(_)!=null)throw new Error("that row is already answered");let{followup:$,source:L}=await l(n);if(L==="unreachable")throw new Error("plane unreachable \u2014 the follow-up's current prompt can't be read; try again shortly");if(!$||$.status!=="active"){await y({action:"removed",followupId:n});let H=new Error("removed in Settings since it was offered");throw H.code="removed",H}x=$.prompt,S=$.label}else{let A=f.find($=>$.armId===r);if(!A)throw new Error("that arm is not on this card");if(w.get(_)!=null)throw new Error("that row is already answered");x=g(A),S=A.label}let M=await k();if(!i)throw new Error("sayToLead unavailable");let P=`${c_(p.payload)}
211
211
 
212
- ${x}`,j=await i(e.id,P,{kind:"followup-go"});return await y({action:"sent",...n?{followupId:n}:{armId:r},label:S,...o?{promoted:String(o)}:{},...M?{revived:!0}:{},source:n?`followup:${n}`:`arm:${r}`}),{offerId:t,action:"sent",followupId:n,armId:r,promoted:o,revived:M,remaining:h.length-1,queued:!!j?.queued}}async function N2(e,t,{changedRepos:n=null,probe:r=tp,branchOf:o=ko}={}){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(k=>k.name===e.leadBox)||null,c=e.workspace?.kind==="multi",l;if(c&&n){let k=await n(e).catch(()=>[]),g=s.repos?k.filter(x=>s.repos.includes(x.name)):k;l=g.length?g.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(k=>ho.includes(k));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=Ts(),h=t.why?`${t.label} \u2014 ${t.why}`:t.label,y=Jw(await K(a).catch(()=>[]));return await N(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(k=>f.includes(k)||k==="rebase"):void 0,prState:p?.prState,openPr:p?.openPr||void 0,repos:p?.repos||l,offered:p?f.filter(k=>p.available.includes(k)):f,toPr:s.toPr?{number:s.toPr}:void 0}}),{offerId:w,branch:u,offered:f,available:p?.available??null,prState:p?.prState??null,replaced:y}}function Jw(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 k_(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 x_(e,{pull:t=Lc}={}){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?hp(s):[]}}var Gw,o_,l_,u_,S2,Vw,A2,s_,a_,T2,Kw,d_,Es,E2,zw,R2,M2,wp=G(()=>{be();gs();Iw();Ss();r_();jc();Gw=60,o_=8*1024,l_=200,u_=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],S2=u_.filter(e=>e!=="now"&&e!=="track.opened"),Vw={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"},A2=3,s_=6,a_=5,T2=["offerable","never"],Kw=["commit","push","pr"];d_=e=>v2("sha256").update(String(e)).digest("hex").slice(0,16),Es=e=>typeof e=="string"?e.trim():"",E2=[[/(^|[^\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"]];zw=e=>String(e?.name||"").startsWith("\u21BB");R2=e=>String(e||"").split(`
212
+ ${x}`,j=await i(e.id,P,{kind:"followup-go"});return await y({action:"sent",...n?{followupId:n}:{armId:r},label:S,...o?{promoted:String(o)}:{},...M?{revived:!0}:{},source:n?`followup:${n}`:`arm:${r}`}),{offerId:t,action:"sent",followupId:n,armId:r,promoted:o,revived:M,remaining:h.length-1,queued:!!j?.queued}}async function P2(e,t,{changedRepos:n=null,probe:r=np,branchOf:o=ko}={}){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(k=>k.name===e.leadBox)||null,c=e.workspace?.kind==="multi",l;if(c&&n){let k=await n(e).catch(()=>[]),g=s.repos?k.filter(x=>s.repos.includes(x.name)):k;l=g.length?g.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(k=>ho.includes(k));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=As(),h=t.why?`${t.label} \u2014 ${t.why}`:t.label,y=Jw(await K(a).catch(()=>[]));return await N(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(k=>f.includes(k)||k==="rebase"):void 0,prState:p?.prState,openPr:p?.openPr||void 0,repos:p?.repos||l,offered:p?f.filter(k=>p.available.includes(k)):f,toPr:s.toPr?{number:s.toPr}:void 0}}),{offerId:w,branch:u,offered:f,available:p?.available??null,prState:p?.prState??null,replaced:y}}function Jw(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 k_(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 x_(e,{pull:t=Lc}={}){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?wp(s):[]}}var Gw,o_,l_,u_,T2,Vw,A2,s_,a_,E2,Kw,d_,Es,_2,zw,O2,C2,gp=G(()=>{be();gs();Iw();Ss();r_();jc();Gw=60,o_=8*1024,l_=200,u_=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],T2=u_.filter(e=>e!=="now"&&e!=="track.opened"),Vw={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"},A2=3,s_=6,a_=5,E2=["offerable","never"],Kw=["commit","push","pr"];d_=e=>S2("sha256").update(String(e)).digest("hex").slice(0,16),Es=e=>typeof e=="string"?e.trim():"",_2=[[/(^|[^\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"]];zw=e=>String(e?.name||"").startsWith("\u21BB");O2=e=>String(e||"").split(`
213
213
  `).slice(0,3).join(`
214
- `).slice(0,400);M2=(e,t)=>t.filter(n=>e.get(n.armId?`arm:${n.armId}`:`fu:${n.followupId}`)==null)});import{randomUUID as P2}from"node:crypto";function Uc(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function v_(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function S_(e){return`job|${e.box}|id:${e.id}`}function A_(e){return`jobstop|${e.box}|id:${e.id}`}async function Xw(e){return Yw.has(e.id)?Yw.get(e.id):(gp.has(e.id)||gp.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(Uc({role:o,sourceId:r.payload.sourceId})),n.keys.add(Uc({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(Uc({role:"user",sourceId:r.payload.sourceId})),n.keys.add(Uc({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(v_({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(S_({id:r.payload.id,box:r.boxId})):r.type==="job.stopped"&&r.payload?.id&&n.keys.add(A_({id:r.payload.id,box:r.boxId}));return Yw.set(e.id,n),n}).finally(()=>gp.delete(e.id))),gp.get(e.id))}async function T_(e,t){let n=new Set;try{let r=(await Xw(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=Uc(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?fp(o.text):null;if(a){await N(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 QE(a,Hc),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=Yx(o);if(i){await N(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}}),Ac(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 N(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=bT(o.text);if(c&&Jw(await K(e).catch(()=>[])))continue;if(c){let l=vT(c),u;if(e.workspace?.kind==="multi"){let w=await _s(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 ko(e.cwd).catch(()=>null))||e.workspace.branch,p=await tp(e,{branch:d,rebase:l}).catch(()=>null),f=p?null:xT(c);if(p&&p.available.length===0)continue;await N(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:P2(),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 E_(e,t){try{let n=await Xw(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=v_(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 N(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}}),YE(e,o),XE(e,o)}}catch{}}async function __(e,t){try{let n=await Xw(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=S_(o);if(n.keys.has(s)||(n.keys.add(s),await N(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}})),o.stoppedTs==null)continue;let a=A_(o);n.keys.has(a)||(n.keys.add(a),await N(e,{type:"job.stopped",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id,kind:o.kind||"agent",name:o.name||null,ts:o.stoppedTs,boxRole:o.boxRole}}))}}catch{}}var Yw,gp,I_=G(()=>{be();gs();Iw();pp();Ss();Hw();Ir();Vu();Id();wp();Yw=new Map,gp=new Map});function D2(e){let t=[],n=null;for(let r of String(e||"").split(`
215
- `)){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 B2(e,t){let n=`${e.id}:${t.name}`;if(!Zw.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);Zw.set(n,o)}return Zw.get(n)}async function $_(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await Zo(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await B2(e,t),o=D2(await jt(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 N(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:Wn(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 N(e,{type:"context.usage",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{occupancy:a.occupancy,first:null,window:a.contextWindow,pct:a.occupancy!=null?a.occupancy/a.contextWindow:null,model:a.model||null,ts:a.ts}})}}catch{}}var Zw,R_=G(()=>{be();es();vn();yr();Zw=new Map});import yp from"node:fs";import eg from"node:path";import L2 from"node:os";async function U2({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(F2,{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:O_})});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<O_)break}return r}function H2(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 C_(){try{return JSON.parse(yp.readFileSync(bp(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function q2(e){try{yp.mkdirSync(eg.dirname(bp()),{recursive:!0});let t=bp()+".tmp";yp.writeFileSync(t,JSON.stringify(e)),yp.renameSync(t,bp())}catch{}}async function K2({fetchImpl:e,now:t=Date.now()}={}){if(So.rows&&t-So.at<W2)return So.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=C_(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await U2({sinceMs:o,cookie:n,fetchImpl:e});So={at:t,rows:s.map(H2).filter(Boolean),error:null}}catch(s){So={at:t,rows:null,error:String(s?.message||s)}}return So.rows}async function V2(e,t){let n=`${e.id}:${t.name}`;if(!Qw.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);Qw.set(n,o)}return Qw.get(n)}async function N_(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!M_())return;let r=await K2({fetchImpl:n});if(!r||!r.length)return;let o=await LS(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await V2(e,t),a=C_(),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=Wn(u,d,l.ts??void 0)),!p&&l.chargedCents!=null&&(p=l.chargedCents/100),await N(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}})}q2({sinceMs:c,seen:[...i].slice(-G2)})}catch{}}var j2,M_,F2,O_,W2,So,bp,G2,tg,Qw,ng=G(()=>{be();Mh();yr();j2=process.env.BOSTRAT_STATE_DIR||eg.join(process.env.HOME||L2.tmpdir(),".bostrat"),M_=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,F2="https://cursor.com/api/dashboard/get-filtered-usage-events",O_=100;W2=5*6e4,So={at:0,rows:null,error:null},bp=()=>eg.join(j2,"cursor-usage.json");G2=5e3;tg=()=>({enabled:M_(),lastPollAt:So.at||null,error:So.error}),Qw=new Map});import{randomUUID as z2,createHmac as J2}from"node:crypto";function D_(e){og=typeof e=="string"&&e?e:null}function Y2(e){if(!og)return null;let t=He(e);return t?J2("sha256",Buffer.from(og,"base64url")).update(t,"utf8").digest("hex").slice(0,16):null}function j_(){let e={};for(let t of L_)e[String(t)]=0;return e.inf=0,{buckets:e,sumMs:0,count:0}}function P_(e,t){let n=Math.max(0,Number(t)||0);for(let r of L_)n<=r&&(e.buckets[String(r)]+=1);e.buckets.inf+=1,e.sumMs+=n,e.count+=1}function F_(){let e={};for(let t of B_)e[t]=0;return e}function Z2(){zn={total:new Map,holds:F_(),queueWaitMs:j_(),readyWaitMs:new Map,verify:new Map,retries:new Map}}function U_({queueDepth:e=0,queueOldestAgeMs:t=0}={}){let n=zn;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,i]=r.split("|");return{provider:s,verdict:a,cliVersion:i||null,n:o}}),retries:[...n.retries].map(([r,o])=>({provider:r,n:o})),queueDepth:Number(e)||0,queueOldestAgeMs:Number(t)||0}}function Wc({kind:e=null,producer:t=null,orchestration:n=!1}={}){return n?`orchestration:${e||"orchestration"}`:e?`scripted:${e}`:X2.has(t)?t:"composer"}function qc({text:e="",producer:t="composer",kind:n=null,provider:r=null,attachments:o=0,now:s=Date.now}={}){let a=s();return{id:z2(),producer:t,kind:n||null,provider:r||null,textBytes:Buffer.byteLength(String(e||""),"utf8"),textHmac16:Y2(e),attachments:Number(o)||0,paste:null,t0:a,queuedAt:null,dequeuedAt:null,holds:F_(),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 N(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 H_(e,t){B_.includes(t)&&(e?.holds&&(e.holds[t]+=1),zn.holds[t]+=1)}function Kc(e,{ms:t,outcome:n}){e&&(e.readyWaitMs=Math.max(0,Number(t)||0),e.readyOutcome=n||null)}function Q2(e){let t=e?.boxes?.find?.(n=>n.name===e.leadBox);return typeof t?.cliVersion=="string"&&t.cliVersion?t.cliVersion:null}async function In(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(rg(zn.total,`${s}|${t.producer}|${n}`),a&&P_(zn.queueWaitMs,i),t.readyWaitMs!=null){let u=`${s}|${t.readyOutcome||"unknown"}`;zn.readyWaitMs.has(u)||zn.readyWaitMs.set(u,j_()),P_(zn.readyWaitMs.get(u),t.readyWaitMs)}let c=Q2(e);t.verify?.verdict&&(rg(zn.verify,`${s}|${t.verify.verdict}|${c||""}`),t.verify.retries&&rg(zn.retries,s,t.verify.retries));let l={ts:o,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},cliVersion:c,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 N(e,{type:"delivery.settled",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:l}).catch(()=>{}),l}function Ha(e){if(e?.usageCap)return"refused:cap";if(e?.interrupted)return"interrupted";if(e?.code)return`failed:${e.code}`;let t=String(e?.message||"");return/not running/i.test(t)?"failed:not-running":/archived/i.test(t)?"failed:archived":/blocked on an interactive prompt|isn't signed in|is waiting on its|stuck on its update/i.test(t)?"failed:blocked":"failed:error"}var og,B_,L_,X2,zn,rg,sg=G(()=>{be();mc();og=null;B_=["busy","prompt","handoff","noSession","cap","grace"],L_=[500,2e3,1e4,6e4,6e5],X2=new Set(["composer","voice","loop"]);zn=null;Z2();rg=(e,t,n=1)=>e.set(t,(e.get(t)||0)+n)});import Jc from"node:fs/promises";import Ut from"node:path";import eH from"node:os";import tH from"node:net";import{randomUUID as nH}from"node:crypto";import{execFile as rH}from"node:child_process";import{promisify as oH}from"node:util";function dH(e){for(let t of pg(e))if(!z_.test(t))return t;return null}function J_(e){let t=pg(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function pH(e,t){let n=J_(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return Ut.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return Ut.resolve(e,n[r+1])}return e}function mH(e){let t=!1,n=!1;for(let r of pg(e)){if(!t){if(z_.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&ag(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,ag(r))return`serves the filesystem root ("${r}")`;continue}if(ag(r))return`serves the filesystem root ("${r}")`;if(fH(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function wH(e,t){if(Ut.resolve(e)===Ut.resolve(t))return!0;let[n,r]=await Promise.all([kp(e),kp(t)]);return n===r}async function gH(e){let n=(await Jc.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 Y_(Ut.join(e,o.name,lg))?`./${o.name}`:null))).filter(Boolean)}async function yH(e,t){let[n,r]=await Promise.all([kp(e),kp(t)]),o=Ut.relative(n,r);if(o&&(o.startsWith("..")||Ut.isAbsolute(o)))throw Vc(`serve directory escapes the Track workspace: ${t}`)}async function bH(e,t){let n=mH(t);if(n)throw Vc(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await hH(e))throw Vc(`serve directory does not exist: ${e}`);let r=dH(t);if(!r)return;if(!r.includes("/")&&!await vx(r,{loginShell:!0,failOpen:!0}))throw Vc(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(cH.test(t)||lH.has(r)||!iH.has(r)||!J_(t).includes("run")||uH.test(t))return;let o=pH(e,t);if(await Y_(Ut.join(o,lg)))return;let s=await gH(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Vc(`no ${lg} in ${o}${a}`)}async function Or(){return Jn||(ig||=(async()=>{try{Jn=JSON.parse(await Jc.readFile(V_,"utf8"))}catch{Jn={views:[],adoptWatermarks:{}}}finally{ig=null}return Jn.views||=[],Jn.adoptWatermarks||={},Jn})(),ig)}async function Xn(){await Bt(V_,Jn)}function Rr(e,t,n={}){return N({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 mg(e){return zc.get(e)||null}function Z_(e,{name:t,box:n}={}){let r=zc.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 zc.set(e,o),o}function ug(e,t){let n=zc.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function xp(e,{error:t=null}={}){let n=zc.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function Q_(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 dg(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function kH(e,t){let n=dg(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!G_.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!G_.has(s))return s}}function Yc(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=tH.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 hg(e){if(process.platform!=="darwin"){await Yn("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await Yn("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 eI(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function xH(e,t){let n=new Set(e.views.map(o=>o.port)),r=eI();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=W_;o<=q_;o++)if(!(n.has(o)||r.has(o))&&!await Yc(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${W_}-${q_}`)}async function vH(e){try{let{stdout:t}=await Yn(oe,se("list-sessions","-F","#{session_name}"));return t.split(`
214
+ `).slice(0,400);C2=(e,t)=>t.filter(n=>e.get(n.armId?`arm:${n.armId}`:`fu:${n.followupId}`)==null)});import{randomUUID as D2}from"node:crypto";function Uc(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function v_(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function S_(e){return`job|${e.box}|id:${e.id}`}function T_(e){return`jobstop|${e.box}|id:${e.id}`}async function Xw(e){return Yw.has(e.id)?Yw.get(e.id):(yp.has(e.id)||yp.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(Uc({role:o,sourceId:r.payload.sourceId})),n.keys.add(Uc({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(Uc({role:"user",sourceId:r.payload.sourceId})),n.keys.add(Uc({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(v_({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(S_({id:r.payload.id,box:r.boxId})):r.type==="job.stopped"&&r.payload?.id&&n.keys.add(T_({id:r.payload.id,box:r.boxId}));return Yw.set(e.id,n),n}).finally(()=>yp.delete(e.id))),yp.get(e.id))}async function A_(e,t){let n=new Set;try{let r=(await Xw(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=Uc(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?mp(o.text):null;if(a){await N(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 QE(a,Hc),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=Yx(o);if(i){await N(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}}),Tc(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 N(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=bA(o.text);if(c&&Jw(await K(e).catch(()=>[])))continue;if(c){let l=vA(c),u;if(e.workspace?.kind==="multi"){let w=await _s(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 ko(e.cwd).catch(()=>null))||e.workspace.branch,p=await np(e,{branch:d,rebase:l}).catch(()=>null),f=p?null:xA(c);if(p&&p.available.length===0)continue;await N(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:D2(),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 E_(e,t){try{let n=await Xw(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=v_(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 N(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}}),YE(e,o),XE(e,o)}}catch{}}async function __(e,t){try{let n=await Xw(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=S_(o);if(n.keys.has(s)||(n.keys.add(s),await N(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}})),o.stoppedTs==null)continue;let a=T_(o);n.keys.has(a)||(n.keys.add(a),await N(e,{type:"job.stopped",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{id:o.id,kind:o.kind||"agent",name:o.name||null,ts:o.stoppedTs,boxRole:o.boxRole}}))}}catch{}}var Yw,yp,I_=G(()=>{be();gs();Iw();fp();Ss();Hw();Ir();Vu();$d();gp();Yw=new Map,yp=new Map});function B2(e){let t=[],n=null;for(let r of String(e||"").split(`
215
+ `)){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 L2(e,t){let n=`${e.id}:${t.name}`;if(!Zw.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);Zw.set(n,o)}return Zw.get(n)}async function $_(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await Zo(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await L2(e,t),o=B2(await jt(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 N(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:Wn(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 N(e,{type:"context.usage",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{occupancy:a.occupancy,first:null,window:a.contextWindow,pct:a.occupancy!=null?a.occupancy/a.contextWindow:null,model:a.model||null,ts:a.ts}})}}catch{}}var Zw,R_=G(()=>{be();es();vn();yr();Zw=new Map});import bp from"node:fs";import eg from"node:path";import j2 from"node:os";async function H2({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(U2,{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:O_})});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<O_)break}return r}function W2(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 C_(){try{return JSON.parse(bp.readFileSync(kp(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function G2(e){try{bp.mkdirSync(eg.dirname(kp()),{recursive:!0});let t=kp()+".tmp";bp.writeFileSync(t,JSON.stringify(e)),bp.renameSync(t,kp())}catch{}}async function V2({fetchImpl:e,now:t=Date.now()}={}){if(So.rows&&t-So.at<q2)return So.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=C_(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await H2({sinceMs:o,cookie:n,fetchImpl:e});So={at:t,rows:s.map(W2).filter(Boolean),error:null}}catch(s){So={at:t,rows:null,error:String(s?.message||s)}}return So.rows}async function z2(e,t){let n=`${e.id}:${t.name}`;if(!Qw.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);Qw.set(n,o)}return Qw.get(n)}async function N_(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!M_())return;let r=await V2({fetchImpl:n});if(!r||!r.length)return;let o=await LS(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await z2(e,t),a=C_(),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=Wn(u,d,l.ts??void 0)),!p&&l.chargedCents!=null&&(p=l.chargedCents/100),await N(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}})}G2({sinceMs:c,seen:[...i].slice(-K2)})}catch{}}var F2,M_,U2,O_,q2,So,kp,K2,tg,Qw,ng=G(()=>{be();Mh();yr();F2=process.env.BOSTRAT_STATE_DIR||eg.join(process.env.HOME||j2.tmpdir(),".bostrat"),M_=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,U2="https://cursor.com/api/dashboard/get-filtered-usage-events",O_=100;q2=5*6e4,So={at:0,rows:null,error:null},kp=()=>eg.join(F2,"cursor-usage.json");K2=5e3;tg=()=>({enabled:M_(),lastPollAt:So.at||null,error:So.error}),Qw=new Map});import{randomUUID as J2,createHmac as Y2}from"node:crypto";function D_(e){og=typeof e=="string"&&e?e:null}function X2(e){if(!og)return null;let t=He(e);return t?Y2("sha256",Buffer.from(og,"base64url")).update(t,"utf8").digest("hex").slice(0,16):null}function j_(){let e={};for(let t of L_)e[String(t)]=0;return e.inf=0,{buckets:e,sumMs:0,count:0}}function P_(e,t){let n=Math.max(0,Number(t)||0);for(let r of L_)n<=r&&(e.buckets[String(r)]+=1);e.buckets.inf+=1,e.sumMs+=n,e.count+=1}function F_(){let e={};for(let t of B_)e[t]=0;return e}function Q2(){zn={total:new Map,holds:F_(),queueWaitMs:j_(),readyWaitMs:new Map,verify:new Map,retries:new Map}}function U_({queueDepth:e=0,queueOldestAgeMs:t=0}={}){let n=zn;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,i]=r.split("|");return{provider:s,verdict:a,cliVersion:i||null,n:o}}),retries:[...n.retries].map(([r,o])=>({provider:r,n:o})),queueDepth:Number(e)||0,queueOldestAgeMs:Number(t)||0}}function Wc({kind:e=null,producer:t=null,orchestration:n=!1}={}){return n?`orchestration:${e||"orchestration"}`:e?`scripted:${e}`:Z2.has(t)?t:"composer"}function qc({text:e="",producer:t="composer",kind:n=null,provider:r=null,attachments:o=0,now:s=Date.now}={}){let a=s();return{id:J2(),producer:t,kind:n||null,provider:r||null,textBytes:Buffer.byteLength(String(e||""),"utf8"),textHmac16:X2(e),attachments:Number(o)||0,paste:null,t0:a,queuedAt:null,dequeuedAt:null,holds:F_(),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 N(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 H_(e,t){B_.includes(t)&&(e?.holds&&(e.holds[t]+=1),zn.holds[t]+=1)}function Kc(e,{ms:t,outcome:n}){e&&(e.readyWaitMs=Math.max(0,Number(t)||0),e.readyOutcome=n||null)}function eH(e){let t=e?.boxes?.find?.(n=>n.name===e.leadBox);return typeof t?.cliVersion=="string"&&t.cliVersion?t.cliVersion:null}async function In(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(rg(zn.total,`${s}|${t.producer}|${n}`),a&&P_(zn.queueWaitMs,i),t.readyWaitMs!=null){let u=`${s}|${t.readyOutcome||"unknown"}`;zn.readyWaitMs.has(u)||zn.readyWaitMs.set(u,j_()),P_(zn.readyWaitMs.get(u),t.readyWaitMs)}let c=eH(e);t.verify?.verdict&&(rg(zn.verify,`${s}|${t.verify.verdict}|${c||""}`),t.verify.retries&&rg(zn.retries,s,t.verify.retries));let l={ts:o,deliveryId:t.id,producer:t.producer,...t.kind?{kind:t.kind}:{},cliVersion:c,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 N(e,{type:"delivery.settled",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:l}).catch(()=>{}),l}function Ha(e){if(e?.usageCap)return"refused:cap";if(e?.interrupted)return"interrupted";if(e?.code)return`failed:${e.code}`;let t=String(e?.message||"");return/not running/i.test(t)?"failed:not-running":/archived/i.test(t)?"failed:archived":/blocked on an interactive prompt|isn't signed in|is waiting on its|stuck on its update/i.test(t)?"failed:blocked":"failed:error"}var og,B_,L_,Z2,zn,rg,sg=G(()=>{be();mc();og=null;B_=["busy","prompt","handoff","noSession","cap","grace"],L_=[500,2e3,1e4,6e4,6e5],Z2=new Set(["composer","voice","loop"]);zn=null;Q2();rg=(e,t,n=1)=>e.set(t,(e.get(t)||0)+n)});import Jc from"node:fs/promises";import Ut from"node:path";import tH from"node:os";import nH from"node:net";import{randomUUID as rH}from"node:crypto";import{execFile as oH}from"node:child_process";import{promisify as sH}from"node:util";function pH(e){for(let t of pg(e))if(!z_.test(t))return t;return null}function J_(e){let t=pg(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function fH(e,t){let n=J_(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return Ut.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return Ut.resolve(e,n[r+1])}return e}function hH(e){let t=!1,n=!1;for(let r of pg(e)){if(!t){if(z_.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&ag(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,ag(r))return`serves the filesystem root ("${r}")`;continue}if(ag(r))return`serves the filesystem root ("${r}")`;if(mH(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function gH(e,t){if(Ut.resolve(e)===Ut.resolve(t))return!0;let[n,r]=await Promise.all([xp(e),xp(t)]);return n===r}async function yH(e){let n=(await Jc.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 Y_(Ut.join(e,o.name,lg))?`./${o.name}`:null))).filter(Boolean)}async function bH(e,t){let[n,r]=await Promise.all([xp(e),xp(t)]),o=Ut.relative(n,r);if(o&&(o.startsWith("..")||Ut.isAbsolute(o)))throw Vc(`serve directory escapes the Track workspace: ${t}`)}async function kH(e,t){let n=hH(t);if(n)throw Vc(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await wH(e))throw Vc(`serve directory does not exist: ${e}`);let r=pH(t);if(!r)return;if(!r.includes("/")&&!await vx(r,{loginShell:!0,failOpen:!0}))throw Vc(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(lH.test(t)||uH.has(r)||!cH.has(r)||!J_(t).includes("run")||dH.test(t))return;let o=fH(e,t);if(await Y_(Ut.join(o,lg)))return;let s=await yH(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw Vc(`no ${lg} in ${o}${a}`)}async function Or(){return Jn||(ig||=(async()=>{try{Jn=JSON.parse(await Jc.readFile(V_,"utf8"))}catch{Jn={views:[],adoptWatermarks:{}}}finally{ig=null}return Jn.views||=[],Jn.adoptWatermarks||={},Jn})(),ig)}async function Xn(){await Bt(V_,Jn)}function Rr(e,t,n={}){return N({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 mg(e){return zc.get(e)||null}function Z_(e,{name:t,box:n}={}){let r=zc.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 zc.set(e,o),o}function ug(e,t){let n=zc.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function vp(e,{error:t=null}={}){let n=zc.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function Q_(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 dg(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function xH(e,t){let n=dg(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!G_.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!G_.has(s))return s}}function Yc(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=nH.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 hg(e){if(process.platform!=="darwin"){await Yn("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await Yn("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 eI(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function vH(e,t){let n=new Set(e.views.map(o=>o.port)),r=eI();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=W_;o<=q_;o++)if(!(n.has(o)||r.has(o))&&!await Yc(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${W_}-${q_}`)}async function SH(e){try{let{stdout:t}=await Yn(oe,se("list-sessions","-F","#{session_name}"));return t.split(`
216
216
  `).some(n=>n.trim()===Wa(e))}catch{return!1}}async function Xc(e){try{await Yn(oe,se("kill-session","-t",Wa(e)))}catch{}}async function wg(e){if(!await Qi())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");let t=Wa(e.slug),n=e.serveCwd??e.cwd,r=Ut.dirname(process.execPath);await Yn(oe,se("new-session","-d","-s",t,"-c",n)),await Yn(oe,se("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await Yn(oe,se("send-keys","-t",t,"Enter")),await Yn(oe,se("send-keys","-t",t,"-l",e.cmd)),await Yn(oe,se("send-keys","-t",t,"Enter"))}async function K_(e,t=12){try{let{stdout:n}=await Yn(oe,se("capture-pane","-t",Wa(e),"-p"));return String(n||"").trimEnd().split(`
217
217
  `).filter(Boolean).slice(-t).join(`
218
- `)}catch{return""}}async function AH(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await vH(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await K_(e.slug)||"server exited before listening"),$r.delete(e.id),await Rr(e,e.state,e.error?{error:e.error}:{}),!0}if(await Yc(e.port))return $r.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await Rr(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>SH?(e.state="error",e.error=await K_(e.slug)||"never started listening",await Rr(e,"error",{error:e.error}),!0):!1;let o=($r.get(e.id)||0)+1;return $r.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function vp(){if(!cg){cg=!0;try{let e=await Or(),t=!1;for(let n of e.views)await AH(n)&&(t=!0);t&&await Xn()}finally{cg=!1}}}async function gg({trackId:e}={}){await vp();let t=await Or();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function tI(e){let n=(await Or()).views.find(r=>r.id===e);return n?{...n}:null}function yg(e){return Jn&&Jn.views.find(t=>t.slug===e)||null}async function bg({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=Ut.resolve(r,o??"."),d=i==="detected"?null:async()=>{await yH(r,u),await bH(u,n)},p=await Or();if(i!=="detected"){let h=dg(t),y=String(n).trim(),k=p.views.find(g=>g.trackId===e&&(g.slug===h||dg(g.name)===h||g.cmd===y&&Ut.resolve(g.serveCwd??g.cwd)===u));if(k)return TH(p,k,{cmd:y,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>=Ao)throw new Error(`view cap reached (${Ao} live) \u2014 stop one first`);let w={id:nH().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:kH(p,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await xH(p,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await wg(w),p.views.push(w),await Xn(),await Rr(w,"created",{origin:i}),ug(e,w.id),i==="detected"&&await Yc(w.port)&&(w.state="live",w.lastHealthyAt=Date.now(),await Xn(),await Rr(w,"live")),{...w}}async function TH(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 wH(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await Yc(t.port))return await Xn(),ug(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>=Ao)throw new Error(`view cap reached (${Ao} live) \u2014 stop one first`);return t.origin==="detected"?(await hg(t.port),t.origin="agent"):await Xc(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),$r.delete(t.id),await wg(t),await Xn(),await Rr(t,"created",{restarted:!0,reused:!0}),ug(t.trackId,t.id),{...t,reused:!0}}async function nI(e){let n=(await Or()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await hg(n.port):await Xc(n.slug),n.state!=="stopped"&&(n.state="stopped",$r.delete(n.id),await Xn(),await Rr(n,"stopped")),{...n}}async function rI(e){let t=await Or(),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>=Ao)throw new Error(`view cap reached (${Ao} live) \u2014 stop one first`);return await Xc(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),$r.delete(n.id),await wg(n),await Xn(),await Rr(n,"created",{restarted:!0}),{...n}}async function oI(e){let t=await Or(),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 hg(r.port):await Xc(r.slug),t.views.splice(n,1),$r.delete(r.id),await Xn(),await Rr(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function kg(e){let t=await Or(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await Xc(r.slug),$r.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await Xn()),n.length}async function sI(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await Or(),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 Xn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(EH)){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(!eI().has(c)&&!n.views.some(l=>l.port===c)&&await Yc(c))try{i.push(await bg({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 Yn,sH,V_,W_,q_,Ao,aH,Wa,G_,Vc,iH,lg,cH,lH,uH,pg,z_,ag,fH,hH,Y_,kp,Jn,ig,zc,fg,X_,$r,SH,cg,EH,Sp=G(()=>{dt();be();zr();Yn=oH(rH),sH=process.env.BOSTRAT_STATE_DIR||Ut.join(process.env.HOME||eH.tmpdir(),".bostrat"),V_=Ut.join(sH,"views.json"),[W_,q_]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),Ao=Number(process.env.BOSTRAT_VIEW_MAX)||3,aH="bostrat-view-",Wa=e=>`${aH}${e}`,G_=new Set(["bostrat","www","api","views","app"]),Vc=e=>Object.assign(new Error(e),{status:400}),iH=new Set(["npm","pnpm","yarn","bun"]),lg="package.json",cH=/[|;&`]|\$\(/,lH=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),uH=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,pg=e=>String(e).trim().split(/\s+/).filter(Boolean),z_=/^[A-Za-z_][A-Za-z0-9_]*=/;ag=e=>e==="/",fH=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");hH=e=>Jc.stat(e).then(t=>t.isDirectory(),()=>!1),Y_=e=>Jc.stat(e).then(t=>t.isFile(),()=>!1),kp=e=>Jc.realpath(e).catch(()=>Ut.resolve(e));Jn=null,ig=null;zc=new Map,fg=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,X_=12e3;$r=new Map,SH=12e4;cg=!1;EH=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});import{execFile as _H}from"node:child_process";import{promisify as IH}from"node:util";function OH(e){return iI(e?.toPr?.number??e?.openPr?.number)}function iI(e){if(e==null||e==="")return null;let t=Number(e);return Number.isFinite(t)&&t>0?t:null}function MH(e){return Array.isArray(e?.actions)?e.actions.includes("push")||e.actions.includes("pr"):e?.action==="push"||e?.action==="pr"}function qa(e,t=Date.now()){let n=null,r=new Map;for(let o of e||[]){let s=o.payload?.ts??o.ts;if(o.type==="pr.offered"){o.payload?.offerId&&r.set(o.payload.offerId,o.payload);continue}if(o.type==="pr.offer.answered"){let a=o.payload||{},i=r.get(a.offerId)||null,c=OH(i),l=Array.isArray(a.actions)&&a.actions.includes("rebase"),u=i?.base??null;a.action==="pr"?n={ts:s,offerId:a.offerId??null,box:o.boxId??null,offerType:"offer",toPr:c,base:u,rebase:l}:a.action!=="dismiss"&&a.action!=="pr-exists"&&c!=null&&MH(a)?n={ts:s,offerId:a.offerId??null,box:o.boxId??null,offerType:"offer",toPr:c,base:u,rebase:l}:n=null}else if(o.type==="pr.exists.answered"){let a=o.payload||{};n=a.choice==="push"?{ts:s,offerId:a.offerId??null,box:o.boxId??null,offerType:"exists",toPr:iI(a.number),base:null,rebase:Array.isArray(a.actions)&&a.actions.includes("rebase")}:null}else o.type==="pr.state.changed"&&(o.payload?.change==="opened"||o.payload?.change==="pushed")&&n!=null&&s>=n.ts&&(n=null)}return n!=null&&t-n.ts>xg?null:n}function CH(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function Tp(e,{bypassThrottle:t=!1}={}){let n=e?.workspace?.branch;if(!n)return;let r;try{r=await K(e)}catch{return}let o=qa(r);if(o==null)return;let s=(e.boxes||[]).find(d=>d.name===e.leadBox);if(await is(e.leadBox,s?.agent).catch(()=>!1))return;let a=Date.now();if(!t&&a<(Zc.get(e.id)||0))return;Zc.set(e.id,a+aI);let i;try{i=await Kn(e.cwd,{caller:"reconcile"})}catch{return}let c=await ja(e).catch(()=>[n]),l=o.toPr!=null&&(i||[]).find(d=>Number(d.number)===o.toPr&&c.includes(d.headRefName))||(i||[]).find(d=>c.includes(d.headRefName));if(!l)return;let u=await Me(e.cwd).catch(()=>null);if(u){let{link:d,created:p}=await Yt({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 xr(u,l.number))){if(!CH(d,o))return;let f=await NH(e);if(f&&l.headSha&&f!==l.headSha){let h=Math.min(RH,(Ap.get(e.id)||aI)*2);Ap.set(e.id,h),Zc.set(e.id,a+h);return}let w=await K(e).catch(()=>null);if(w&&qa(w)==null)return;await N(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:PH(o,l,{branch:n,repo:u})}),Zc.delete(e.id),Ap.delete(e.id);return}}await N(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(()=>{}),Zc.delete(e.id),Ap.delete(e.id)}async function NH(e){try{let{stdout:t}=await $H("git",["-C",e.cwd,"rev-parse","HEAD"],{timeout:1e4}),n=String(t||"").trim();return/^[0-9a-f]{40}$/.test(n)?n:null}catch{return null}}function PH(e,t,{branch:n=null,repo:r=null,now:o=Date.now()}={}){return{ts:o,change:"pushed",number:t.number,url:t.url,title:t.title,branch:n,...r?{repo:r}:{},...t.headSha?{sha:t.headSha}:{},via:"ship",...e?.rebase?{rebased:!0}:{},...e?.base?{base:e.base}:{}}}var $H,aI,Zc,RH,Ap,xg,Qc=G(()=>{be();vs();Gr();Gn();va();Ss();$H=IH(_H),aI=6e3,Zc=new Map,RH=5*6e4,Ap=new Map,xg=30*6e4});import vg from"node:os";import{execFile as DH}from"node:child_process";import{promisify as BH}from"node:util";async function Ep(){if(process.platform!=="darwin")return vg.freemem();try{let{stdout:e}=await LH("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:vg.freemem()}catch{return vg.freemem()}}var LH,Sg=G(()=>{LH=BH(DH)});import ot from"node:fs/promises";import st from"node:path";import dI from"node:os";import{randomUUID as jH}from"node:crypto";import{execFile as FH}from"node:child_process";import{promisify as UH}from"node:util";import{chromium as HH}from"playwright-core";async function er(){return Is||(Ag||=(async()=>{try{Is=JSON.parse(await ot.readFile(fI,"utf8"))}catch{Is={mocks:[]}}finally{Ag=null}return Is.mocks||=[],Is})(),Ag)}async function un(){await Bt(fI,Is)}function gI(e,t){Qn(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&Qn(e,t.v,"png")}function Rt(e,t,n={}){return N({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 dn(e,t){let n=tl(e.cwd);return{html:st.join(n,`${e.id}.v${t}.html`),png:st.join(n,`${e.id}.v${t}.png`)}}function el(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?st.join(e.cwd,r):null}function $n(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 _g(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function _p(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(JH)}function YH(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 XH(e){let t=Buffer.alloc(24),n=await ot.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function ZH({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 QH(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,y=0;y<o;y++,h+=4)Math.abs(c[h]-l[0])+Math.abs(c[h+1]-l[1])+Math.abs(c[h+2]-l[2])>24&&(y<u&&(u=y),y>p&&(p=y),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 eW(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 tW({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await HH.launch({executablePath:mI,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new Xt("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:Ga})).newPage();a.setDefaultTimeout(Ka),await a.goto(`file://${e}`,{waitUntil:"load",timeout:Ka}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:Ka});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await QH(a,i),u=l&&ZH({...l,pad:GH*Ga,align:Ga});u&&(i=await eW(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<hI)throw new Xt(`capture produced a ${i.length}-byte image`);let c=_g(i);if(!c)throw new Xt("output is not a PNG");return await ot.writeFile(t,i),{width:Math.round(c.width/Ga),height:Math.round(c.height/Ga),dpr:Ga,renderMs:Date.now()-r}}catch(s){throw s instanceof Xt?s:new Xt(/timeout/i.test(s?.message||"")?`render timed out after ${Ka}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function uI({htmlPath:e,outPath:t,width:n}){let r=await ot.mkdtemp(st.join(dI.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await Eg(cI,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:Ka,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new Xt(`firefox not found (${cI})`,""):new Xt(c?.killed?`render timed out after ${Ka}ms`:"firefox exited non-zero",s)}let a=await ot.stat(t).catch(()=>null);if(!a||a.size<hI)throw new Xt(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=_g(await XH(t));if(!i)throw new Xt("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await ot.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function nW(e){if(WH==="firefox")return uI(e);try{return await tW(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await uI(e)}catch(n){throw/not found/.test(n?.message||"")?new Xt(`no browser installed \u2014 chromium missing at ${mI} 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 yI(e){return Tg=Tg.then(e,e),Tg}async function bI(e,t){let n=await er(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await un(),await Rt(r,"rendering",{version:t});try{let o=await Ep();if(o<KH)throw new Xt(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=dn(r,t),a=await rW({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await ot.rm(s.png,{force:!0}).catch(()=>{});return}Ig(r,{v:t,source:"html",htmlRel:st.relative(r.cwd,s.html),pngRel:st.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await un(),await Rt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),Zn(r),Qn(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await un(),await Rt(r,"error",{version:t,error:r.error}),Zn(r)}}}function Ig(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 oW({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?qH:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function nl({trackId:e,group:t}={}){let n=await er(),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 er()).mocks.find(r=>r.id===e);return n?{...n}:null}function kI({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&&!_p(t))throw new Error("image must be a PNG");if(n){let o=YH(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>lI)throw new Error(`video must be ${lI/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function xI({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=oW({trackId:e,name:t,cwd:s,width:a}),p=typeof n=="string"&&n.trim(),f=kI({html:n,image:r,video:o}),w=await er(),h={id:jH().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 ot.mkdir(tl(s),{recursive:!0}),w.mocks.push(h),p?(await ot.writeFile(dn(h,1).html,n),await un(),await Rt(h,"created"),Zn(h),Qn(h,1,"html"),yI(()=>bI(h.id,1))):o?(await SI(h,1,o,f),await un(),await Rt(h,"created"),await Rt(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr,durationS:h.versions[0]?.durationS??null}),Zn(h),gI(h,h.versions[0])):(await AI(h,1,r),await un(),await Rt(h,"created"),await Rt(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr}),Zn(h),Qn(h,1,"png")),{...h}}async function vI(e,{html:t,image:n,video:r,width:o}={}){let a=(await er()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=kI({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 ot.mkdir(tl(a.cwd),{recursive:!0}),i?(a.state="queued",await ot.writeFile(dn(a,l).html,t),await un(),await Rt(a,"updated",{version:l}),Zn(a),Qn(a,l,"html"),yI(()=>bI(a.id,l))):r?(await SI(a,l,r,c),await un(),await Rt(a,"updated",{version:l}),await Rt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:$n(a)?.durationS??null}),Zn(a),gI(a,a.versions.find(u=>u.v===l))):(await AI(a,l,n),await un(),await Rt(a,"updated",{version:l}),await Rt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),Zn(a),Qn(a,l,"png")),{...a}}async function sW(e){try{let{stdout:t}=await Eg(VH,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:wI,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 aW(e,t){try{await Eg(zH,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:wI,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await ot.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function SI(e,t,n,r){let o=tl(e.cwd),s=st.join(o,`${e.id}.v${t}.${r.ext}`),a=st.join(o,`${e.id}.v${t}.poster.png`);await ot.writeFile(s,n);let i=await sW(s),c=await aW(s,a);Ig(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:st.relative(e.cwd,s),posterRel:c?st.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 AI(e,t,n){let r=_g(n);if(!r)throw new Error("image must be a PNG");let o=dn(e,t);await ot.writeFile(o.png,n),Ig(e,{v:t,source:"image",htmlRel:null,pngRel:st.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function TI(e){let t=await er(),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 Rt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function EI(e){let t=await er(),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=dn(r,o);await ot.rm(s.html,{force:!0}).catch(()=>{}),await ot.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await ot.rm(st.join(r.cwd,s),{force:!0}).catch(()=>{});return await un(),await Rt(r,"deleted"),bn("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function _I(e){let n=(await er()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=st.join(pI,"mock-archive",e.id),o=tl(e.cwd),s=st.join(r,".bostrat","mocks");await ot.mkdir(s,{recursive:!0});let a=await ot.readdir(o).catch(()=>[]);for(let i of a)await ot.copyFile(st.join(o,i),st.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 ot.stat(st.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(),Zn(i)}return await un(),n.length}async function II(e){let t=await er(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await un();for(let r of n)bn("mocks",r.id).catch(()=>{})}return n.length}async function $I(){if(!Ge())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await pt("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await er();for(let r of n.mocks){await Zn(r);for(let o of r.versions||[])o.htmlRel&&await Qn(r,o.v,"html"),(o.pngRel||o.posterRel)&&await Qn(r,o.v,"png"),o.videoRel&&await Qn(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var Eg,pI,fI,WH,mI,cI,qH,Ga,GH,hI,Ka,KH,lI,VH,zH,wI,Xt,Is,Ag,Zn,Qn,tl,JH,rW,Tg,Va=G(()=>{be();zr();Sg();Yr();Eg=UH(FH),pI=process.env.BOSTRAT_STATE_DIR||st.join(process.env.HOME||dI.tmpdir(),".bostrat"),fI=st.join(pI,"mocks.json"),WH=process.env.BOSTRAT_MOCK_ENGINE||"chromium",mI=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",cI=process.env.BOSTRAT_FIREFOX_BIN||"firefox",qH=1300,Ga=2,GH=32,hI=1500,Ka=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,KH=700*1024*1024,lI=100*1024*1024,VH=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",zH=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",wI=2e4,Xt=class extends Error{constructor(t,n=""){super(n?`${t}
218
+ `)}catch{return""}}async function AH(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await SH(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await K_(e.slug)||"server exited before listening"),$r.delete(e.id),await Rr(e,e.state,e.error?{error:e.error}:{}),!0}if(await Yc(e.port))return $r.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await Rr(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>TH?(e.state="error",e.error=await K_(e.slug)||"never started listening",await Rr(e,"error",{error:e.error}),!0):!1;let o=($r.get(e.id)||0)+1;return $r.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function Sp(){if(!cg){cg=!0;try{let e=await Or(),t=!1;for(let n of e.views)await AH(n)&&(t=!0);t&&await Xn()}finally{cg=!1}}}async function gg({trackId:e}={}){await Sp();let t=await Or();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function tI(e){let n=(await Or()).views.find(r=>r.id===e);return n?{...n}:null}function yg(e){return Jn&&Jn.views.find(t=>t.slug===e)||null}async function bg({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=Ut.resolve(r,o??"."),d=i==="detected"?null:async()=>{await bH(r,u),await kH(u,n)},p=await Or();if(i!=="detected"){let h=dg(t),y=String(n).trim(),k=p.views.find(g=>g.trackId===e&&(g.slug===h||dg(g.name)===h||g.cmd===y&&Ut.resolve(g.serveCwd??g.cwd)===u));if(k)return EH(p,k,{cmd:y,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>=To)throw new Error(`view cap reached (${To} live) \u2014 stop one first`);let w={id:rH().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:xH(p,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await vH(p,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await wg(w),p.views.push(w),await Xn(),await Rr(w,"created",{origin:i}),ug(e,w.id),i==="detected"&&await Yc(w.port)&&(w.state="live",w.lastHealthyAt=Date.now(),await Xn(),await Rr(w,"live")),{...w}}async function EH(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 gH(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await Yc(t.port))return await Xn(),ug(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>=To)throw new Error(`view cap reached (${To} live) \u2014 stop one first`);return t.origin==="detected"?(await hg(t.port),t.origin="agent"):await Xc(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.createdAt=Date.now(),$r.delete(t.id),await wg(t),await Xn(),await Rr(t,"created",{restarted:!0,reused:!0}),ug(t.trackId,t.id),{...t,reused:!0}}async function nI(e){let n=(await Or()).views.find(r=>r.id===e);if(!n)throw new Error("view not found");return n.origin==="detected"?await hg(n.port):await Xc(n.slug),n.state!=="stopped"&&(n.state="stopped",$r.delete(n.id),await Xn(),await Rr(n,"stopped")),{...n}}async function rI(e){let t=await Or(),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>=To)throw new Error(`view cap reached (${To} live) \u2014 stop one first`);return await Xc(n.slug),n.state="starting",n.error=null,n.createdAt=Date.now(),$r.delete(n.id),await wg(n),await Xn(),await Rr(n,"created",{restarted:!0}),{...n}}async function oI(e){let t=await Or(),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 hg(r.port):await Xc(r.slug),t.views.splice(n,1),$r.delete(r.id),await Xn(),await Rr(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function kg(e){let t=await Or(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await Xc(r.slug),$r.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await Xn()),n.length}async function sI(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await Or(),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 Xn()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(_H)){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(!eI().has(c)&&!n.views.some(l=>l.port===c)&&await Yc(c))try{i.push(await bg({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 Yn,aH,V_,W_,q_,To,iH,Wa,G_,Vc,cH,lg,lH,uH,dH,pg,z_,ag,mH,wH,Y_,xp,Jn,ig,zc,fg,X_,$r,TH,cg,_H,Tp=G(()=>{dt();be();zr();Yn=sH(oH),aH=process.env.BOSTRAT_STATE_DIR||Ut.join(process.env.HOME||tH.tmpdir(),".bostrat"),V_=Ut.join(aH,"views.json"),[W_,q_]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),To=Number(process.env.BOSTRAT_VIEW_MAX)||3,iH="bostrat-view-",Wa=e=>`${iH}${e}`,G_=new Set(["bostrat","www","api","views","app"]),Vc=e=>Object.assign(new Error(e),{status:400}),cH=new Set(["npm","pnpm","yarn","bun"]),lg="package.json",lH=/[|;&`]|\$\(/,uH=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),dH=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,pg=e=>String(e).trim().split(/\s+/).filter(Boolean),z_=/^[A-Za-z_][A-Za-z0-9_]*=/;ag=e=>e==="/",mH=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");wH=e=>Jc.stat(e).then(t=>t.isDirectory(),()=>!1),Y_=e=>Jc.stat(e).then(t=>t.isFile(),()=>!1),xp=e=>Jc.realpath(e).catch(()=>Ut.resolve(e));Jn=null,ig=null;zc=new Map,fg=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,X_=12e3;$r=new Map,TH=12e4;cg=!1;_H=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});import{execFile as IH}from"node:child_process";import{promisify as $H}from"node:util";function MH(e){return iI(e?.toPr?.number??e?.openPr?.number)}function iI(e){if(e==null||e==="")return null;let t=Number(e);return Number.isFinite(t)&&t>0?t:null}function CH(e){return Array.isArray(e?.actions)?e.actions.includes("push")||e.actions.includes("pr"):e?.action==="push"||e?.action==="pr"}function qa(e,t=Date.now()){let n=null,r=new Map;for(let o of e||[]){let s=o.payload?.ts??o.ts;if(o.type==="pr.offered"){o.payload?.offerId&&r.set(o.payload.offerId,o.payload);continue}if(o.type==="pr.offer.answered"){let a=o.payload||{},i=r.get(a.offerId)||null,c=MH(i),l=Array.isArray(a.actions)&&a.actions.includes("rebase"),u=i?.base??null;a.action==="pr"?n={ts:s,offerId:a.offerId??null,box:o.boxId??null,offerType:"offer",toPr:c,base:u,rebase:l}:a.action!=="dismiss"&&a.action!=="pr-exists"&&c!=null&&CH(a)?n={ts:s,offerId:a.offerId??null,box:o.boxId??null,offerType:"offer",toPr:c,base:u,rebase:l}:n=null}else if(o.type==="pr.exists.answered"){let a=o.payload||{};n=a.choice==="push"?{ts:s,offerId:a.offerId??null,box:o.boxId??null,offerType:"exists",toPr:iI(a.number),base:null,rebase:Array.isArray(a.actions)&&a.actions.includes("rebase")}:null}else o.type==="pr.state.changed"&&(o.payload?.change==="opened"||o.payload?.change==="pushed")&&n!=null&&s>=n.ts&&(n=null)}return n!=null&&t-n.ts>xg?null:n}function NH(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function Ep(e,{bypassThrottle:t=!1}={}){let n=e?.workspace?.branch;if(!n)return;let r;try{r=await K(e)}catch{return}let o=qa(r);if(o==null)return;let s=(e.boxes||[]).find(d=>d.name===e.leadBox);if(await is(e.leadBox,s?.agent).catch(()=>!1))return;let a=Date.now();if(!t&&a<(Zc.get(e.id)||0))return;Zc.set(e.id,a+aI);let i;try{i=await Kn(e.cwd,{caller:"reconcile"})}catch{return}let c=await ja(e).catch(()=>[n]),l=o.toPr!=null&&(i||[]).find(d=>Number(d.number)===o.toPr&&c.includes(d.headRefName))||(i||[]).find(d=>c.includes(d.headRefName));if(!l)return;let u=await Me(e.cwd).catch(()=>null);if(u){let{link:d,created:p}=await Yt({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 xr(u,l.number))){if(!NH(d,o))return;let f=await PH(e);if(f&&l.headSha&&f!==l.headSha){let h=Math.min(OH,(Ap.get(e.id)||aI)*2);Ap.set(e.id,h),Zc.set(e.id,a+h);return}let w=await K(e).catch(()=>null);if(w&&qa(w)==null)return;await N(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:DH(o,l,{branch:n,repo:u})}),Zc.delete(e.id),Ap.delete(e.id);return}}await N(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(()=>{}),Zc.delete(e.id),Ap.delete(e.id)}async function PH(e){try{let{stdout:t}=await RH("git",["-C",e.cwd,"rev-parse","HEAD"],{timeout:1e4}),n=String(t||"").trim();return/^[0-9a-f]{40}$/.test(n)?n:null}catch{return null}}function DH(e,t,{branch:n=null,repo:r=null,now:o=Date.now()}={}){return{ts:o,change:"pushed",number:t.number,url:t.url,title:t.title,branch:n,...r?{repo:r}:{},...t.headSha?{sha:t.headSha}:{},via:"ship",...e?.rebase?{rebased:!0}:{},...e?.base?{base:e.base}:{}}}var RH,aI,Zc,OH,Ap,xg,Qc=G(()=>{be();vs();Gr();Gn();va();Ss();RH=$H(IH),aI=6e3,Zc=new Map,OH=5*6e4,Ap=new Map,xg=30*6e4});import vg from"node:os";import{execFile as BH}from"node:child_process";import{promisify as LH}from"node:util";async function _p(){if(process.platform!=="darwin")return vg.freemem();try{let{stdout:e}=await jH("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:vg.freemem()}catch{return vg.freemem()}}var jH,Sg=G(()=>{jH=LH(BH)});import ot from"node:fs/promises";import st from"node:path";import dI from"node:os";import{randomUUID as FH}from"node:crypto";import{execFile as UH}from"node:child_process";import{promisify as HH}from"node:util";import{chromium as WH}from"playwright-core";async function er(){return Is||(Tg||=(async()=>{try{Is=JSON.parse(await ot.readFile(fI,"utf8"))}catch{Is={mocks:[]}}finally{Tg=null}return Is.mocks||=[],Is})(),Tg)}async function un(){await Bt(fI,Is)}function gI(e,t){Qn(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&Qn(e,t.v,"png")}function Rt(e,t,n={}){return N({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 dn(e,t){let n=tl(e.cwd);return{html:st.join(n,`${e.id}.v${t}.html`),png:st.join(n,`${e.id}.v${t}.png`)}}function el(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?st.join(e.cwd,r):null}function $n(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 _g(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function Ip(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(YH)}function XH(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 ZH(e){let t=Buffer.alloc(24),n=await ot.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function QH({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 eW(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,y=0;y<o;y++,h+=4)Math.abs(c[h]-l[0])+Math.abs(c[h+1]-l[1])+Math.abs(c[h+2]-l[2])>24&&(y<u&&(u=y),y>p&&(p=y),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 tW(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 nW({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await WH.launch({executablePath:mI,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new Xt("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:Ga})).newPage();a.setDefaultTimeout(Ka),await a.goto(`file://${e}`,{waitUntil:"load",timeout:Ka}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:Ka});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await eW(a,i),u=l&&QH({...l,pad:KH*Ga,align:Ga});u&&(i=await tW(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<hI)throw new Xt(`capture produced a ${i.length}-byte image`);let c=_g(i);if(!c)throw new Xt("output is not a PNG");return await ot.writeFile(t,i),{width:Math.round(c.width/Ga),height:Math.round(c.height/Ga),dpr:Ga,renderMs:Date.now()-r}}catch(s){throw s instanceof Xt?s:new Xt(/timeout/i.test(s?.message||"")?`render timed out after ${Ka}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function uI({htmlPath:e,outPath:t,width:n}){let r=await ot.mkdtemp(st.join(dI.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await Eg(cI,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:Ka,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new Xt(`firefox not found (${cI})`,""):new Xt(c?.killed?`render timed out after ${Ka}ms`:"firefox exited non-zero",s)}let a=await ot.stat(t).catch(()=>null);if(!a||a.size<hI)throw new Xt(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=_g(await ZH(t));if(!i)throw new Xt("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await ot.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function rW(e){if(qH==="firefox")return uI(e);try{return await nW(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await uI(e)}catch(n){throw/not found/.test(n?.message||"")?new Xt(`no browser installed \u2014 chromium missing at ${mI} 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 yI(e){return Ag=Ag.then(e,e),Ag}async function bI(e,t){let n=await er(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await un(),await Rt(r,"rendering",{version:t});try{let o=await _p();if(o<VH)throw new Xt(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=dn(r,t),a=await oW({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await ot.rm(s.png,{force:!0}).catch(()=>{});return}Ig(r,{v:t,source:"html",htmlRel:st.relative(r.cwd,s.html),pngRel:st.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await un(),await Rt(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),Zn(r),Qn(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await un(),await Rt(r,"error",{version:t,error:r.error}),Zn(r)}}}function Ig(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 sW({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?GH:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function nl({trackId:e,group:t}={}){let n=await er(),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 er()).mocks.find(r=>r.id===e);return n?{...n}:null}function kI({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&&!Ip(t))throw new Error("image must be a PNG");if(n){let o=XH(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>lI)throw new Error(`video must be ${lI/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function xI({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=sW({trackId:e,name:t,cwd:s,width:a}),p=typeof n=="string"&&n.trim(),f=kI({html:n,image:r,video:o}),w=await er(),h={id:FH().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 ot.mkdir(tl(s),{recursive:!0}),w.mocks.push(h),p?(await ot.writeFile(dn(h,1).html,n),await un(),await Rt(h,"created"),Zn(h),Qn(h,1,"html"),yI(()=>bI(h.id,1))):o?(await SI(h,1,o,f),await un(),await Rt(h,"created"),await Rt(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr,durationS:h.versions[0]?.durationS??null}),Zn(h),gI(h,h.versions[0])):(await TI(h,1,r),await un(),await Rt(h,"created"),await Rt(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr}),Zn(h),Qn(h,1,"png")),{...h}}async function vI(e,{html:t,image:n,video:r,width:o}={}){let a=(await er()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=kI({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 ot.mkdir(tl(a.cwd),{recursive:!0}),i?(a.state="queued",await ot.writeFile(dn(a,l).html,t),await un(),await Rt(a,"updated",{version:l}),Zn(a),Qn(a,l,"html"),yI(()=>bI(a.id,l))):r?(await SI(a,l,r,c),await un(),await Rt(a,"updated",{version:l}),await Rt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:$n(a)?.durationS??null}),Zn(a),gI(a,a.versions.find(u=>u.v===l))):(await TI(a,l,n),await un(),await Rt(a,"updated",{version:l}),await Rt(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),Zn(a),Qn(a,l,"png")),{...a}}async function aW(e){try{let{stdout:t}=await Eg(zH,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:wI,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 iW(e,t){try{await Eg(JH,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:wI,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await ot.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function SI(e,t,n,r){let o=tl(e.cwd),s=st.join(o,`${e.id}.v${t}.${r.ext}`),a=st.join(o,`${e.id}.v${t}.poster.png`);await ot.writeFile(s,n);let i=await aW(s),c=await iW(s,a);Ig(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:st.relative(e.cwd,s),posterRel:c?st.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 TI(e,t,n){let r=_g(n);if(!r)throw new Error("image must be a PNG");let o=dn(e,t);await ot.writeFile(o.png,n),Ig(e,{v:t,source:"image",htmlRel:null,pngRel:st.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function AI(e){let t=await er(),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 Rt(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function EI(e){let t=await er(),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=dn(r,o);await ot.rm(s.html,{force:!0}).catch(()=>{}),await ot.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await ot.rm(st.join(r.cwd,s),{force:!0}).catch(()=>{});return await un(),await Rt(r,"deleted"),bn("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function _I(e){let n=(await er()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=st.join(pI,"mock-archive",e.id),o=tl(e.cwd),s=st.join(r,".bostrat","mocks");await ot.mkdir(s,{recursive:!0});let a=await ot.readdir(o).catch(()=>[]);for(let i of a)await ot.copyFile(st.join(o,i),st.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 ot.stat(st.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(),Zn(i)}return await un(),n.length}async function II(e){let t=await er(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await un();for(let r of n)bn("mocks",r.id).catch(()=>{})}return n.length}async function $I(){if(!Ge())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await pt("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await er();for(let r of n.mocks){await Zn(r);for(let o of r.versions||[])o.htmlRel&&await Qn(r,o.v,"html"),(o.pngRel||o.posterRel)&&await Qn(r,o.v,"png"),o.videoRel&&await Qn(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var Eg,pI,fI,qH,mI,cI,GH,Ga,KH,hI,Ka,VH,lI,zH,JH,wI,Xt,Is,Tg,Zn,Qn,tl,YH,oW,Ag,Va=G(()=>{be();zr();Sg();Yr();Eg=HH(UH),pI=process.env.BOSTRAT_STATE_DIR||st.join(process.env.HOME||dI.tmpdir(),".bostrat"),fI=st.join(pI,"mocks.json"),qH=process.env.BOSTRAT_MOCK_ENGINE||"chromium",mI=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",cI=process.env.BOSTRAT_FIREFOX_BIN||"firefox",GH=1300,Ga=2,KH=32,hI=1500,Ka=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,VH=700*1024*1024,lI=100*1024*1024,zH=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",JH=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",wI=2e4,Xt=class extends Error{constructor(t,n=""){super(n?`${t}
219
219
  ${n.trim().split(`
220
220
  `).slice(-6).join(`
221
- `)}`:t),this.name="MockRenderError"}},Is=null,Ag=null;Zn=e=>It("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),Qn=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?el(e,r,"video"):r&&el(e,r,n)||(n==="html"?dn(e,t).html:null);return o?Jr("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};tl=e=>st.join(e,".bostrat","mocks");JH=Buffer.from([137,80,78,71,13,10,26,10]);rW=nW,Tg=Promise.resolve()});import iW from"node:fs/promises";import NI from"node:path";import cW from"node:os";import{randomUUID as PI}from"node:crypto";async function Nr(){return Cr||($g||=(async()=>{let e=!0;try{Cr=JSON.parse(await iW.readFile(DI,"utf8"))}catch{Cr={flows:[]},e=!1}finally{$g=null}if(Cr.flows||=[],!e&&Ge()){let{records:t,source:n}=await pt("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&Cr.flows.push(r.data);Cr.flows.length&&await za().catch(()=>{})}}return Cr})(),$g)}async function za(){await Bt(DI,Cr)}function Rg(e,t,n={}){return N({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 BI({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>RI)throw new Error(`steps must be an array of 1-${RI}`);let r=await nl({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>MI)throw new Error(`${l}: caption over ${MI} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>CI)throw new Error(`${l}: title over ${CI} chars`);let p=String(c.mock??"").trim().replace(/^mock:/,"");if(!p)throw new Error(`${l}: mock (name or id) required`);let f=r.filter(g=>g.id===p);if(f.length||(f=r.filter(g=>g.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(g=>`mock:${g.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(g=>g.v===h)))throw new Error(`${l}: "${w.name}" has no captured v${c.v} to pin`);let y=o.findIndex(g=>g.mockId===w.id),k=y>=0?o.splice(y,1)[0].id:PI().slice(0,8);s.push({id:k,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 uW(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>OI)throw new Error(`name over ${OI} chars`);return e.trim()}async function LI({trackId:e}={}){let t=await Nr();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function dW(e){let n=(await Nr()).flows.find(r=>r.id===e);return n?{...n}:null}async function jI(e){let t=await dW(e);if(!t)return null;let n=new Map((await nl({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=$n(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 FI({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=uW(t),i=await Nr(),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 BI({trackId:e,steps:n}),d=Date.now(),p={id:PI().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 za(),await Rg(p,"created"),Ip(p),{...p}}async function UI(e,{steps:t,note:n}={}){let o=(await Nr()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await BI({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 za(),await Rg(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),Ip(o),{...o}}async function HI(e){let t=await Nr(),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 za(),await Rg(r,"deleted"),bn("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function WI(e){return(await Nr()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function qI(e){let n=(await Nr()).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(),Ip(r);return n.length&&await za(),n.length}async function GI(e){let t=await Nr(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await za();for(let r of n)bn("flows",r.id).catch(()=>{})}return n.length}async function KI(){if(!Ge())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await pt("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Nr();for(let r of n.flows)await Ip(r);return{pushed:n.flows.length,source:"plane"}}var lW,DI,RI,OI,MI,CI,Cr,$g,Ip,Og=G(()=>{be();zr();Va();Yr();lW=process.env.BOSTRAT_STATE_DIR||NI.join(process.env.HOME||cW.tmpdir(),".bostrat"),DI=NI.join(lW,"flows.json"),RI=20,OI=80,MI=500,CI=80,Cr=null,$g=null;Ip=e=>It("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import Br from"node:fs/promises";import Lr from"node:path";import pW from"node:os";import{randomUUID as fW}from"node:crypto";function rl(e){return mW.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function tr(){return Pr||(Mg||=(async()=>{let e=!0;try{Pr=JSON.parse(await Br.readFile(zI,"utf8"))}catch{Pr={runbooks:[]},e=!1}finally{Mg=null}return Pr.runbooks||=[],!e&&Ge()&&await hW().catch(()=>{}),Pr})(),Mg)}async function Rs(){await Bt(zI,Pr)}function Rp(e){return ol(It("runbooks",{...e},{trackId:e.trackId}))}async function hW(){let{records:e,source:t}=await pt("runbooks");if(!(t!=="plane"||!e.length)){await Br.mkdir($p,{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 Vi("runbooks",r.id,o.v,"md");typeof s=="string"&&await Br.writeFile(Dr(r,o.v),s).catch(()=>{})}Pr.runbooks.push(r)}Pr.runbooks.length&&await Rs()}}function Ja(e,t,n={}){return N({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 Dr(e,t){return Lr.join($p,`${e.id}.v${t}.md`)}function JI(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 YI(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>VI)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${VI/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=rl(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 wW(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function gW({trackId:e,status:t}={}){let n=await tr(),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 XI({trackId:e,status:t}={}){let n=await tr(),r=await gW({trackId:e,status:t});if(!Ge())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await pt("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 Cg(e){let t=await yW(e);if(t)return t;if(!Ge())return null;let{records:n,source:r}=await pt("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 ZI(e,t){let n=await Vi("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function yW(e){let n=(await tr()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function QI({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=YI(r),c=await tr(),l={id:fW().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 Br.mkdir($p,{recursive:!0}),await Br.writeFile(Dr(l,1),r),l.versions.push({v:1,mdRel:Lr.relative($s,Dr(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await Rs(),await Ja(l,"created",{version:1}),Rp(l),ol(Jr("runbooks",l.id,1,"md",Dr(l,1))),{...l}}async function e$(e,{md:t,note:n}={}){let o=(await tr()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");wW(o,"update");let s=YI(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await Br.mkdir($p,{recursive:!0}),await Br.writeFile(Dr(o,a),t),o.versions.push({v:a,mdRel:Lr.relative($s,Dr(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await Rs(),await Ja(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),Rp(o),ol(Jr("runbooks",o.id,a,"md",Dr(o,a))),{...o}}async function t$(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await tr()).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 Rs(),await Ja(r,t==="done"?"done":"reopened"),Rp(r),{...r})}async function n$(e){let t=await tr(),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 Br.rm(Lr.join($s,o.mdRel),{force:!0}).catch(()=>{});return await Rs(),r.trackDeletedAt||await Ja(r,"deleted"),ol(bn("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function r$(e){let n=(await tr()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await Ja(r,"orphaned"),r.cwd=null,Rp(r);return n.length&&await Rs(),n.length}async function o$(e){let t=await tr(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await Ja(r,"deleted");for(let o of r.versions||[])await Br.rm(Lr.join($s,o.mdRel),{force:!0}).catch(()=>{});ol(bn("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await Rs()),n.length}async function s$(){if(!Ge())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await pt("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await tr();for(let r of n.runbooks){await It("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await Jr("runbooks",r.id,o.v,"md",Lr.join($s,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var $s,zI,$p,VI,mW,Pr,Mg,ol,Op=G(()=>{zr();be();Yr();$s=process.env.BOSTRAT_STATE_DIR||Lr.join(process.env.HOME||pW.tmpdir(),".bostrat"),zI=Lr.join($s,"runbooks.json"),$p=Lr.join($s,"runbooks"),VI=256*1024,mW=[{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/}];Pr=null,Mg=null;ol=e=>Promise.resolve(e).catch(()=>{})});import Ng from"node:fs/promises";import sl from"node:path";import{randomUUID as bW}from"node:crypto";function Dg(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return kW.has(t)?"image":xW.has(t)?"doc":null}function vW(e){let r=sl.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 c$(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>a$)throw new Error(`file too large \u2014 max ${Math.floor(a$/(1024*1024))} MB`);let r=vW(t),o=sl.extname(r).slice(1),s=Dg(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=bW().slice(0,8),i=Pg(e);await Ng.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await Ng.writeFile(sl.join(i,c),n,{mode:384}),await Ng.chmod(sl.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${i$}/${c}`,kind:s,size:n.length}}function l$(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function Bg(e){return e.role==="user"&&SW.test((e.text||"").trim())}var i$,Pg,a$,kW,xW,SW,Lg=G(()=>{i$=".bostrat/uploads",Pg=e=>sl.join(e,i$),a$=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,kW=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),xW=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"]);SW=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function Os(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}function jg(){let e=Number(process.env.BOSTRAT_LOOP_QUEUE_HOLD_MS);return Number.isFinite(e)&&e>0?e:AW}function EW(e,t,n=Date.now()){return e?((e.heldReason!==t||e.heldSince==null)&&(e.heldReason=t,e.heldSince=n),Math.max(0,n-e.heldSince)):0}function u$(e,t,{capMs:n=jg(),now:r=Date.now()}={}){if(!e)return!1;let o=EW(e,t,r);return e.delivery?.producer!=="loop"||!TW.has(t)?!1:o>=n}var AW,TW,d$=G(()=>{AW=5*6e4,TW=new Set(["busy","noSession"])});import{execFile as _W}from"node:child_process";import{promisify as IW}from"node:util";function Fg(e){return`refs/bostrat/wip/${e}`}function OW(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function m$(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function MW(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:RW}function h$(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 CW(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 To(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await To(s,["remote","get-url","origin"])}catch{return p$.has(s)||(p$.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 Ra(s,"bostrat: wip snapshot"),{stdout:c}=await To(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(!n&&Mp.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=Fg(o);return await To(s,["push","--force","origin",`${i}:${u}`],f$),Mp.set(s,l),await N(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,wip:!0,...w$(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(`
222
- `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function Ug(e,{log:t=console,force:n=!1}={}){let r=[],o=[];for(let s of h$(e)){let a=await CW(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 NW(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 To(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await To(s,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let i=await Ra(s,"bostrat: transfer rescue snapshot"),{stdout:c}=await To(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(Mp.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=OW(o,r);return await To(s,["push","origin",`${i}:${u}`],f$),Mp.set(s,l),await N(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,rescue:!0,...w$(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(`
223
- `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function Hg(e,{log:t=console,ts:n=Date.now()}={}){let r=[],o=[];for(let s of h$(e)){let a=await NW(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 g$({listTracks:e,sweepMs:t=MW(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)Ue(i)||i?.kind==="setup"||await Ug(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 $W,RW,f$,To,Mp,p$,w$,Wg=G(()=>{Rd();be();an();$W=IW(_W),RW=12e4,f$=6e4;To=(e,t,n=15e3)=>$W("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),Mp=new Map,p$=new Set,w$=e=>e?.name||e?.repo?{name:e.name??null,repo:e.repo??null}:{}});import PW from"node:fs";import qg from"node:fs/promises";import DW from"node:path";function FW(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}async function y$(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(!FW(t))return{restored:!1,reason:"plane not configured"};let s=sa(e),a=DW.join(s,`${o}.ndjson`);try{if(PW.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=De(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let p=new AbortController,f=setTimeout(()=>p.abort(),jW),w;try{w=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${BW}`,{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 y of h.events||[])l.push(JSON.stringify(y));if(l.length>LW)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 qg.mkdir(s,{recursive:!0});let d=`${a}.pull-${process.pid}-${Date.now()}`;return await qg.writeFile(d,l.join(`
221
+ `)}`:t),this.name="MockRenderError"}},Is=null,Tg=null;Zn=e=>It("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),Qn=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?el(e,r,"video"):r&&el(e,r,n)||(n==="html"?dn(e,t).html:null);return o?Jr("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};tl=e=>st.join(e,".bostrat","mocks");YH=Buffer.from([137,80,78,71,13,10,26,10]);oW=rW,Ag=Promise.resolve()});import cW from"node:fs/promises";import NI from"node:path";import lW from"node:os";import{randomUUID as PI}from"node:crypto";async function Nr(){return Cr||($g||=(async()=>{let e=!0;try{Cr=JSON.parse(await cW.readFile(DI,"utf8"))}catch{Cr={flows:[]},e=!1}finally{$g=null}if(Cr.flows||=[],!e&&Ge()){let{records:t,source:n}=await pt("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&Cr.flows.push(r.data);Cr.flows.length&&await za().catch(()=>{})}}return Cr})(),$g)}async function za(){await Bt(DI,Cr)}function Rg(e,t,n={}){return N({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 BI({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>RI)throw new Error(`steps must be an array of 1-${RI}`);let r=await nl({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>MI)throw new Error(`${l}: caption over ${MI} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>CI)throw new Error(`${l}: title over ${CI} chars`);let p=String(c.mock??"").trim().replace(/^mock:/,"");if(!p)throw new Error(`${l}: mock (name or id) required`);let f=r.filter(g=>g.id===p);if(f.length||(f=r.filter(g=>g.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(g=>`mock:${g.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(g=>g.v===h)))throw new Error(`${l}: "${w.name}" has no captured v${c.v} to pin`);let y=o.findIndex(g=>g.mockId===w.id),k=y>=0?o.splice(y,1)[0].id:PI().slice(0,8);s.push({id:k,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 dW(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>OI)throw new Error(`name over ${OI} chars`);return e.trim()}async function LI({trackId:e}={}){let t=await Nr();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function pW(e){let n=(await Nr()).flows.find(r=>r.id===e);return n?{...n}:null}async function jI(e){let t=await pW(e);if(!t)return null;let n=new Map((await nl({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=$n(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 FI({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=dW(t),i=await Nr(),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 BI({trackId:e,steps:n}),d=Date.now(),p={id:PI().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 za(),await Rg(p,"created"),$p(p),{...p}}async function UI(e,{steps:t,note:n}={}){let o=(await Nr()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await BI({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 za(),await Rg(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),$p(o),{...o}}async function HI(e){let t=await Nr(),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 za(),await Rg(r,"deleted"),bn("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function WI(e){return(await Nr()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function qI(e){let n=(await Nr()).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(),$p(r);return n.length&&await za(),n.length}async function GI(e){let t=await Nr(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await za();for(let r of n)bn("flows",r.id).catch(()=>{})}return n.length}async function KI(){if(!Ge())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await pt("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Nr();for(let r of n.flows)await $p(r);return{pushed:n.flows.length,source:"plane"}}var uW,DI,RI,OI,MI,CI,Cr,$g,$p,Og=G(()=>{be();zr();Va();Yr();uW=process.env.BOSTRAT_STATE_DIR||NI.join(process.env.HOME||lW.tmpdir(),".bostrat"),DI=NI.join(uW,"flows.json"),RI=20,OI=80,MI=500,CI=80,Cr=null,$g=null;$p=e=>It("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import Br from"node:fs/promises";import Lr from"node:path";import fW from"node:os";import{randomUUID as mW}from"node:crypto";function rl(e){return hW.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function tr(){return Pr||(Mg||=(async()=>{let e=!0;try{Pr=JSON.parse(await Br.readFile(zI,"utf8"))}catch{Pr={runbooks:[]},e=!1}finally{Mg=null}return Pr.runbooks||=[],!e&&Ge()&&await wW().catch(()=>{}),Pr})(),Mg)}async function Rs(){await Bt(zI,Pr)}function Op(e){return ol(It("runbooks",{...e},{trackId:e.trackId}))}async function wW(){let{records:e,source:t}=await pt("runbooks");if(!(t!=="plane"||!e.length)){await Br.mkdir(Rp,{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 Vi("runbooks",r.id,o.v,"md");typeof s=="string"&&await Br.writeFile(Dr(r,o.v),s).catch(()=>{})}Pr.runbooks.push(r)}Pr.runbooks.length&&await Rs()}}function Ja(e,t,n={}){return N({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 Dr(e,t){return Lr.join(Rp,`${e.id}.v${t}.md`)}function JI(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 YI(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>VI)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${VI/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=rl(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 gW(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function yW({trackId:e,status:t}={}){let n=await tr(),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 XI({trackId:e,status:t}={}){let n=await tr(),r=await yW({trackId:e,status:t});if(!Ge())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await pt("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 Cg(e){let t=await bW(e);if(t)return t;if(!Ge())return null;let{records:n,source:r}=await pt("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 ZI(e,t){let n=await Vi("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function bW(e){let n=(await tr()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function QI({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=YI(r),c=await tr(),l={id:mW().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 Br.mkdir(Rp,{recursive:!0}),await Br.writeFile(Dr(l,1),r),l.versions.push({v:1,mdRel:Lr.relative($s,Dr(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await Rs(),await Ja(l,"created",{version:1}),Op(l),ol(Jr("runbooks",l.id,1,"md",Dr(l,1))),{...l}}async function e$(e,{md:t,note:n}={}){let o=(await tr()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");gW(o,"update");let s=YI(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await Br.mkdir(Rp,{recursive:!0}),await Br.writeFile(Dr(o,a),t),o.versions.push({v:a,mdRel:Lr.relative($s,Dr(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await Rs(),await Ja(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),Op(o),ol(Jr("runbooks",o.id,a,"md",Dr(o,a))),{...o}}async function t$(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await tr()).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 Rs(),await Ja(r,t==="done"?"done":"reopened"),Op(r),{...r})}async function n$(e){let t=await tr(),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 Br.rm(Lr.join($s,o.mdRel),{force:!0}).catch(()=>{});return await Rs(),r.trackDeletedAt||await Ja(r,"deleted"),ol(bn("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function r$(e){let n=(await tr()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await Ja(r,"orphaned"),r.cwd=null,Op(r);return n.length&&await Rs(),n.length}async function o$(e){let t=await tr(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await Ja(r,"deleted");for(let o of r.versions||[])await Br.rm(Lr.join($s,o.mdRel),{force:!0}).catch(()=>{});ol(bn("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await Rs()),n.length}async function s$(){if(!Ge())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await pt("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await tr();for(let r of n.runbooks){await It("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await Jr("runbooks",r.id,o.v,"md",Lr.join($s,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var $s,zI,Rp,VI,hW,Pr,Mg,ol,Mp=G(()=>{zr();be();Yr();$s=process.env.BOSTRAT_STATE_DIR||Lr.join(process.env.HOME||fW.tmpdir(),".bostrat"),zI=Lr.join($s,"runbooks.json"),Rp=Lr.join($s,"runbooks"),VI=256*1024,hW=[{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/}];Pr=null,Mg=null;ol=e=>Promise.resolve(e).catch(()=>{})});import Ng from"node:fs/promises";import sl from"node:path";import{randomUUID as kW}from"node:crypto";function Dg(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return xW.has(t)?"image":vW.has(t)?"doc":null}function SW(e){let r=sl.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 c$(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>a$)throw new Error(`file too large \u2014 max ${Math.floor(a$/(1024*1024))} MB`);let r=SW(t),o=sl.extname(r).slice(1),s=Dg(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=kW().slice(0,8),i=Pg(e);await Ng.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await Ng.writeFile(sl.join(i,c),n,{mode:384}),await Ng.chmod(sl.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${i$}/${c}`,kind:s,size:n.length}}function l$(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function Bg(e){return e.role==="user"&&TW.test((e.text||"").trim())}var i$,Pg,a$,xW,vW,TW,Lg=G(()=>{i$=".bostrat/uploads",Pg=e=>sl.join(e,i$),a$=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,xW=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),vW=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"]);TW=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function Os(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}function jg(){let e=Number(process.env.BOSTRAT_LOOP_QUEUE_HOLD_MS);return Number.isFinite(e)&&e>0?e:AW}function _W(e,t,n=Date.now()){return e?((e.heldReason!==t||e.heldSince==null)&&(e.heldReason=t,e.heldSince=n),Math.max(0,n-e.heldSince)):0}function u$(e,t,{capMs:n=jg(),now:r=Date.now()}={}){if(!e)return!1;let o=_W(e,t,r);return e.delivery?.producer!=="loop"||!EW.has(t)?!1:o>=n}var AW,EW,d$=G(()=>{AW=5*6e4,EW=new Set(["busy","noSession"])});import{execFile as IW}from"node:child_process";import{promisify as $W}from"node:util";function Fg(e){return`refs/bostrat/wip/${e}`}function MW(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function m$(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function CW(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:OW}function h$(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 NW(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 Ao(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await Ao(s,["remote","get-url","origin"])}catch{return p$.has(s)||(p$.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 Ra(s,"bostrat: wip snapshot"),{stdout:c}=await Ao(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(!n&&Cp.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=Fg(o);return await Ao(s,["push","--force","origin",`${i}:${u}`],f$),Cp.set(s,l),await N(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,wip:!0,...w$(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(`
222
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function Ug(e,{log:t=console,force:n=!1}={}){let r=[],o=[];for(let s of h$(e)){let a=await NW(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 PW(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 Ao(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await Ao(s,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let i=await Ra(s,"bostrat: transfer rescue snapshot"),{stdout:c}=await Ao(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(Cp.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=MW(o,r);return await Ao(s,["push","origin",`${i}:${u}`],f$),Cp.set(s,l),await N(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,rescue:!0,...w$(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(`
223
+ `)[0]}`),{pushed:!1,reason:"push-failed"}}}async function Hg(e,{log:t=console,ts:n=Date.now()}={}){let r=[],o=[];for(let s of h$(e)){let a=await PW(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 g$({listTracks:e,sweepMs:t=CW(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)Ue(i)||i?.kind==="setup"||await Ug(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 RW,OW,f$,Ao,Cp,p$,w$,Wg=G(()=>{Od();be();an();RW=$W(IW),OW=12e4,f$=6e4;Ao=(e,t,n=15e3)=>RW("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),Cp=new Map,p$=new Set,w$=e=>e?.name||e?.repo?{name:e.name??null,repo:e.repo??null}:{}});import DW from"node:fs";import qg from"node:fs/promises";import BW from"node:path";function UW(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}async function y$(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(!UW(t))return{restored:!1,reason:"plane not configured"};let s=sa(e),a=BW.join(s,`${o}.ndjson`);try{if(DW.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=De(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let p=new AbortController,f=setTimeout(()=>p.abort(),FW),w;try{w=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${LW}`,{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 y of h.events||[])l.push(JSON.stringify(y));if(l.length>jW)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 qg.mkdir(s,{recursive:!0});let d=`${a}.pull-${process.pid}-${Date.now()}`;return await qg.writeFile(d,l.join(`
224
224
  `)+`
225
- `),await qg.rename(d,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var BW,LW,jW,b$=G(()=>{xt();be();BW=1e3,LW=5e5,jW=3e4});function k$(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 x$(e){let t=(e||[]).filter(n=>!UW.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 v$({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?pn("archived","lifecycle",e):n?pn("needs-you","pane",o||w,{count:r||1}):t?pn("archiving","lifecycle",e||w):i?.status==="working"?pn("working","operation",i.since,{summary:i.summary??null,count:i.count??null}):(l||n)&&c?.phase?pn("working","agent-phase",c.at,{summary:c.summary??null}):l?pn("working","pane",u||w):r>0||s?pn("needs-you",s?"loop":"obligations",o||w,{count:r||1}):a?.count?pn("needs-you","pr",a.since,{count:a.count,summary:a.summary??null}):i?.status==="waiting"?pn("waiting","operation",i.since,{summary:i.summary??null,count:i.count??null}):d?.count?pn("waiting",d.source||"pending",d.since,{summary:d.summary??null,count:d.count}):p&&f?pn("settled","obligations",p,{summary:"no open actions"}):pn("idle","fallback",p||w)}var pn,UW,S$=G(()=>{pn=(e,t,n,r={})=>({kind:e,source:t,since:n||0,...r});UW=new Set(["merged","closed","lost"])});function HW(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 WW(e,t,n){let r=HW(t,n);return r?N(e,{type:"track.obligations.changed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),open:r.open,since:r.since}}).catch(()=>null):null}async function Gg(e){if(Cp.has(e.id))return Cp.get(e.id);let t=await K(e).catch(()=>[]),n=[];try{n=Hn(t)}catch{}let r=ud(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 Cp.set(e.id,p),!Ue(e)&&e.kind!=="setup"&&WW(e,t,p),p}function A$({trackOf:e,debounceMs:t=qW,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(al.get(s));let a=setTimeout(()=>{al.delete(s),Promise.resolve(e(s)).then(i=>i&&!Ue(i)&&i.kind!=="setup"?Gg(i):null).catch(i=>n.warn?.(`[obligations] fold ${s} failed: ${i?.message||i}`))},t);a.unref?.(),al.set(s,a)};return Ze.on("event",r),()=>{Ze.off("event",r);for(let o of al.values())clearTimeout(o);al.clear()}}var Cp,qW,al,Kg=G(()=>{be();dd();an();Cp=new Map;Ze.on("event",e=>{e?.trackId&&Cp.delete(e.trackId)});qW=750,al=new Map});import Vg from"node:fs/promises";async function KW(e){let t;try{t=await Vg.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/GW*1e3,ioBytes:await VW(e)}}async function VW(e){let t;try{t=await Vg.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 T$(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 Vg.readdir("/proc")}catch{return null}let r=new Map;await Promise.all(n.map(async l=>{if(!/^\d+$/.test(l))return;let u=await KW(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 GW,E$=G(()=>{GW=100});import zW from"node:fs/promises";function Xg(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 Zg(e,t,n){let r=null;try{r=await n.updatedAt(e)}catch{r=null}let o=_$.get(e.name);if(o&&o.mtime===r&&t-o.at<QW)return o.jobs;let s=[];try{s=await n.readOpenJobs(e)}catch{s=[]}return _$.set(e.name,{at:t,mtime:r,jobs:s}),s}async function eq(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 tq(e,t){return e?.outputFile?await t.statFile(e.outputFile):null}function nq(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>=XW||t.ioBytes!=null&&e.ioBytes!=null&&(t.ioBytes-e.ioBytes)/n>=ZW}function I$(e,t,n,r){let o=[];for(let s of n){let a=Yg(e.id,t.name,s.id),i=Rn.get(a);i?i.job=s:Rn.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 $$(e,{now:t=Date.now(),deps:n=Jg}={}){let o=(await Promise.all(Xg([e]).map(({box:s})=>Zg(s,t,n)))).flat();return o.length?{source:"jobs",count:o.length,since:Math.min(...o.map(s=>s.ts||t)),summary:o.length===1?"a background job is still running":`${o.length} background jobs are still running`}:null}async function R$(e,{now:t=Date.now(),deps:n=Jg}={}){let r=new Map,o=new Set;for(let{track:s,box:a}of Xg(e)){let i=await Zg(a,t,n);for(let l of i)o.add(Yg(s.id,a.name,l.id));let c=I$(s,a,i,t).filter(l=>!Rn.get(l).stalled).map(l=>Rn.get(l).job);c.length&&r.set(s.id,[...r.get(s.id)??[],...c])}for(let s of[...Rn.keys()])o.has(s)||Rn.delete(s);return r}async function rq(e,{now:t=Date.now(),deps:n=Jg}={}){let r={checked:0,progressing:0,quiet:0,stalled:[]},o=Xg(e),s=new Set(o.map(({box:a})=>a.name));for(let[a,i]of[...Rn])s.has(i.boxName)||Rn.delete(a);for(let{track:a,box:i}of o){let c=await Zg(i,t,n),l=new Set(c.map(w=>Yg(a.id,i.name,w.id)));for(let[w,h]of[...Rn])h.boxName===i.name&&!l.has(w)&&Rn.delete(w);if(!c.length){zg.delete(i.name);continue}let u=I$(a,i,c,t),d=await eq(i,t,n),p=zg.get(i.name);zg.set(i.name,d);let f=nq(p,d);for(let w of u){let h=Rn.get(w);r.checked++;let y=await tq(h.job,n),k=!!y&&!!h.file&&(y.size>h.file.size||y.mtimeMs>h.file.mtimeMs),g=!!y&&!h.file;if(h.file=y??h.file,f||k||g){h.quiet=0,h.lastProgressAt=t,h.stalled=!1,r.progressing++;continue}if(h.stalled||(h.quiet++,r.quiet++,h.quiet<YW))continue;h.stalled=!0,h.stalledAt=t,r.stalled.push(w);let S=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:S,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(S/6e4)}m over ${h.quiet} check(s) \u2014 released; the node may sleep`)}}return r}function O$({listTracks:e,intervalMs:t=JW}={}){let n=!1,o=setInterval(async()=>{if(!n){n=!0;try{await rq(await e())}catch(s){console.error(`[job-watch] sweep: ${s?.message||s}`)}finally{n=!1}}},t);return o.unref?.(),o}var JW,YW,XW,ZW,QW,Jg,Rn,_$,zg,Yg,Qg=G(()=>{be();bd();dt();E$();JW=Number(process.env.BOSTRAT_JOB_CHECK_MS)||15*6e4,YW=Number(process.env.BOSTRAT_JOB_STALL_CHECKS)||3,XW=Number(process.env.BOSTRAT_JOB_CPU_RATE_MIN)||25,ZW=Number(process.env.BOSTRAT_JOB_IO_RATE_MIN)||64*1024,QW=5*6e4,Jg={readOpenJobs:yd,statFile:async e=>{try{let t=await zW.stat(e);return{size:t.size,mtimeMs:Math.round(t.mtimeMs)}}catch{return null}},updatedAt:e=>ao(e.agent).updatedAt(e),panePids:Ex,treeStats:T$,appendEvent:N},Rn=new Map,_$=new Map,zg=new Map,Yg=(e,t,n)=>`${e}|${t}|${n}`});import oq from"node:fs/promises";import sq from"node:os";import Np from"node:path";async function ey(e){try{return(await oq.stat(e)).size}catch{return null}}async function Ya(e){let[t,n,r]=await Promise.all([ey(Np.join(aq,"CLAUDE.md")),e?ey(Np.join(e,"CLAUDE.md")):null,e?ey(Np.join(e,".bostrat","memory","MEMORY.md")):null]);return{bostratClaudeMd:t,repoClaudeMd:n,memoryIndex:r}}var aq,ty=G(()=>{aq=process.env.BOSTRAT_STATE_DIR||Np.join(process.env.HOME||sq.tmpdir(),".bostrat")});import{randomUUID as iq}from"node:crypto";async function Dp(e,t,n={}){let r={operationId:iq(),kind:t,startedAt:Date.now(),...n};return Pp.set(e.id,r),await N(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:r.startedAt,state:"started",...r}}).catch(()=>{}),r}async function ny(e,t,n="completed",r=null){Pp.get(e.id)?.operationId===t?.operationId&&Pp.delete(e.id),await N(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 Pp,M$,ry=G(()=>{be();Pp=new Map;M$=e=>Pp.get(e)||null});var mR={};om(mR,{HANDOFF_LATEST_REL:()=>Io,KNOWN_AGENTS:()=>yl,LOGIN_GREETING:()=>Y$,TRACK_NAME_MAX:()=>gy,addTrackRepo:()=>Zp,adoptTrack:()=>tb,agentAvailability:()=>Vp,announceNodeUpdate:()=>or,answerFullscreenOffer:()=>zy,answerPrompt:()=>Jp,answeringFor:()=>Ay,archiveTrack:()=>Ds,archiveTrackForMergedPr:()=>Er,augmentFirstPromptAfterHandoff:()=>H$,buildAgentCmd:()=>yy,canResumeSubtask:()=>dR,cancelQueued:()=>kl,cancelQueuedToDraft:()=>_y,cancelStopJob:()=>oi,cancelSubtask:()=>uf,changedRepos:()=>_s,commitTransferOut:()=>af,createSetupTrack:()=>jy,createTrack:()=>ef,deleteTrack:()=>Uy,demoteTransferredTracks:()=>eb,ensureLeadEpochs:()=>_o,forceMergeSubtask:()=>ob,getHandoffJob:()=>ii,getReshapeJob:()=>xl,getSubtaskJob:()=>E5,getTrack:()=>me,getTransferOutJob:()=>Zy,healDeadLead:()=>wl,interruptLead:()=>Xp,isArchiving:()=>d5,isHandoffNoteEcho:()=>dy,isInterruptEcho:()=>py,isLeadStarting:()=>z$,isModelSwitchEcho:()=>fy,leadCliDead:()=>Wy,listSubtaskJobs:()=>Ls,listTracks:()=>ke,matchTranscriptsToBoxes:()=>K$,mergeNotifyMessage:()=>iR,navigatePrompt:()=>Ty,notifyTrackForMergedPr:()=>_r,notifyTrackForResolvedPr:()=>tf,offerFollowupsForMergedPr:()=>Bs,pendingOffers:()=>vy,queueGauges:()=>Ey,queueShipCompleteNotify:()=>$y,queuedMessages:()=>Cs,rawTrack:()=>xy,reapArchivedOrphans:()=>Vy,reconcileDemotedTracks:()=>Ky,reconcileHandoffOutcome:()=>cR,reconcileInterruptedHandoffs:()=>Yy,reconcileInterruptedReshapes:()=>By,reconcileInterruptedSubtasks:()=>nb,reconcileNodeUpdateNotices:()=>ky,reconcileSubtaskOutcome:()=>uR,refreshStandingInstructions:()=>Ly,refuseIfTransferred:()=>sf,rehydrateLead:()=>ai,removeTrackRepo:()=>Qp,renameTrack:()=>Gy,reposOf:()=>Gt,reshapeTrack:()=>Dy,resolveTrackBox:()=>Hc,resolveTrackBoxByHookToken:()=>bl,restartLead:()=>rf,resumeAgentCmd:()=>Kp,reviveLeadForSession:()=>qy,sayToLead:()=>qt,sendOptionsForAgent:()=>Un,setTrackDraft:()=>My,setTrackModel:()=>Cy,startLeadHandoff:()=>of,startSpinUpView:()=>Ry,startSubtask:()=>rb,startTransferOut:()=>Qy,stopJobActive:()=>Z$,subtaskMessages:()=>Sy,trackMessages:()=>zp,unarchiveTrack:()=>nf});import Y from"node:fs/promises";import z from"node:path";import{randomUUID as Wp,createHash as cq}from"node:crypto";import{execFile as lq}from"node:child_process";import{promisify as uq}from"node:util";function yy(e,{skipPermissions:t=!0,model:n=null}={}){let r=Gp[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=dw(e).find(i=>i.alias===n);if(!a)throw new Error(`unknown ${e} launch model "${n}"`);s+=` --model ${a.alias}`}return s}function Kp(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=Gp[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&&!xn(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 Ps(e){let t=Gp[e];if(t)return process.env[t.envVar]||t.base}async function Vp({maxAgeMs:e=6e4}={}){if(Eo.value&&Date.now()-Eo.at<e)return Eo.value;let t=Eo.value,n=await Promise.all(yl.map(async r=>{let o=await Fu(Ps(r),{retries:[]});return o===ua?[r,t?.[r]??!0]:[r,o===ju]}));return Eo.value=Object.fromEntries(n),Eo.at=Date.now(),Eo.value}async function ri(e,t=!0,n=null){let r=yy(e,{skipPermissions:t,model:n});if(await Fu(r)===la){Eo.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.":Um[o]?`Install it on this node: ${Um[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 H$(e,t=Io){return`${e.trim()}
225
+ `),await qg.rename(d,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var LW,jW,FW,b$=G(()=>{xt();be();LW=1e3,jW=5e5,FW=3e4});function k$(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 x$(e){let t=(e||[]).filter(n=>!HW.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 v$({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?pn("archived","lifecycle",e):n?pn("needs-you","pane",o||w,{count:r||1}):t?pn("archiving","lifecycle",e||w):i?.status==="working"?pn("working","operation",i.since,{summary:i.summary??null,count:i.count??null}):(l||n)&&c?.phase?pn("working","agent-phase",c.at,{summary:c.summary??null}):l?pn("working","pane",u||w):r>0||s?pn("needs-you",s?"loop":"obligations",o||w,{count:r||1}):a?.count?pn("needs-you","pr",a.since,{count:a.count,summary:a.summary??null}):i?.status==="waiting"?pn("waiting","operation",i.since,{summary:i.summary??null,count:i.count??null}):d?.count?pn("waiting",d.source||"pending",d.since,{summary:d.summary??null,count:d.count}):p&&f?pn("settled","obligations",p,{summary:"no open actions"}):pn("idle","fallback",p||w)}var pn,HW,S$=G(()=>{pn=(e,t,n,r={})=>({kind:e,source:t,since:n||0,...r});HW=new Set(["merged","closed","lost"])});function WW(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 qW(e,t,n){let r=WW(t,n);return r?N(e,{type:"track.obligations.changed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),open:r.open,since:r.since}}).catch(()=>null):null}async function Gg(e){if(Np.has(e.id))return Np.get(e.id);let t=await K(e).catch(()=>[]),n=[];try{n=Hn(t)}catch{}let r=dd(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 Np.set(e.id,p),!Ue(e)&&e.kind!=="setup"&&qW(e,t,p),p}function T$({trackOf:e,debounceMs:t=GW,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(al.get(s));let a=setTimeout(()=>{al.delete(s),Promise.resolve(e(s)).then(i=>i&&!Ue(i)&&i.kind!=="setup"?Gg(i):null).catch(i=>n.warn?.(`[obligations] fold ${s} failed: ${i?.message||i}`))},t);a.unref?.(),al.set(s,a)};return Ze.on("event",r),()=>{Ze.off("event",r);for(let o of al.values())clearTimeout(o);al.clear()}}var Np,GW,al,Kg=G(()=>{be();pd();an();Np=new Map;Ze.on("event",e=>{e?.trackId&&Np.delete(e.trackId)});GW=750,al=new Map});import Vg from"node:fs/promises";async function VW(e){let t;try{t=await Vg.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/KW*1e3,ioBytes:await zW(e)}}async function zW(e){let t;try{t=await Vg.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 A$(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 Vg.readdir("/proc")}catch{return null}let r=new Map;await Promise.all(n.map(async l=>{if(!/^\d+$/.test(l))return;let u=await VW(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 KW,E$=G(()=>{KW=100});import JW from"node:fs/promises";function Xg(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 Zg(e,t,n){let r=null;try{r=await n.updatedAt(e)}catch{r=null}let o=_$.get(e.name);if(o&&o.mtime===r&&t-o.at<eq)return o.jobs;let s=[];try{s=await n.readOpenJobs(e)}catch{s=[]}return _$.set(e.name,{at:t,mtime:r,jobs:s}),s}async function tq(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 nq(e,t){return e?.outputFile?await t.statFile(e.outputFile):null}function rq(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>=ZW||t.ioBytes!=null&&e.ioBytes!=null&&(t.ioBytes-e.ioBytes)/n>=QW}function I$(e,t,n,r){let o=[];for(let s of n){let a=Yg(e.id,t.name,s.id),i=Rn.get(a);i?i.job=s:Rn.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 $$(e,{now:t=Date.now(),deps:n=Jg}={}){let o=(await Promise.all(Xg([e]).map(({box:s})=>Zg(s,t,n)))).flat();return o.length?{source:"jobs",count:o.length,since:Math.min(...o.map(s=>s.ts||t)),summary:o.length===1?"a background job is still running":`${o.length} background jobs are still running`}:null}async function R$(e,{now:t=Date.now(),deps:n=Jg}={}){let r=new Map,o=new Set;for(let{track:s,box:a}of Xg(e)){let i=await Zg(a,t,n);for(let l of i)o.add(Yg(s.id,a.name,l.id));let c=I$(s,a,i,t).filter(l=>!Rn.get(l).stalled).map(l=>Rn.get(l).job);c.length&&r.set(s.id,[...r.get(s.id)??[],...c])}for(let s of[...Rn.keys()])o.has(s)||Rn.delete(s);return r}async function oq(e,{now:t=Date.now(),deps:n=Jg}={}){let r={checked:0,progressing:0,quiet:0,stalled:[]},o=Xg(e),s=new Set(o.map(({box:a})=>a.name));for(let[a,i]of[...Rn])s.has(i.boxName)||Rn.delete(a);for(let{track:a,box:i}of o){let c=await Zg(i,t,n),l=new Set(c.map(w=>Yg(a.id,i.name,w.id)));for(let[w,h]of[...Rn])h.boxName===i.name&&!l.has(w)&&Rn.delete(w);if(!c.length){zg.delete(i.name);continue}let u=I$(a,i,c,t),d=await tq(i,t,n),p=zg.get(i.name);zg.set(i.name,d);let f=rq(p,d);for(let w of u){let h=Rn.get(w);r.checked++;let y=await nq(h.job,n),k=!!y&&!!h.file&&(y.size>h.file.size||y.mtimeMs>h.file.mtimeMs),g=!!y&&!h.file;if(h.file=y??h.file,f||k||g){h.quiet=0,h.lastProgressAt=t,h.stalled=!1,r.progressing++;continue}if(h.stalled||(h.quiet++,r.quiet++,h.quiet<XW))continue;h.stalled=!0,h.stalledAt=t,r.stalled.push(w);let S=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:S,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(S/6e4)}m over ${h.quiet} check(s) \u2014 released; the node may sleep`)}}return r}function O$({listTracks:e,intervalMs:t=YW}={}){let n=!1,o=setInterval(async()=>{if(!n){n=!0;try{await oq(await e())}catch(s){console.error(`[job-watch] sweep: ${s?.message||s}`)}finally{n=!1}}},t);return o.unref?.(),o}var YW,XW,ZW,QW,eq,Jg,Rn,_$,zg,Yg,Qg=G(()=>{be();kd();dt();E$();YW=Number(process.env.BOSTRAT_JOB_CHECK_MS)||15*6e4,XW=Number(process.env.BOSTRAT_JOB_STALL_CHECKS)||3,ZW=Number(process.env.BOSTRAT_JOB_CPU_RATE_MIN)||25,QW=Number(process.env.BOSTRAT_JOB_IO_RATE_MIN)||64*1024,eq=5*6e4,Jg={readOpenJobs:bd,statFile:async e=>{try{let t=await JW.stat(e);return{size:t.size,mtimeMs:Math.round(t.mtimeMs)}}catch{return null}},updatedAt:e=>ao(e.agent).updatedAt(e),panePids:Ex,treeStats:A$,appendEvent:N},Rn=new Map,_$=new Map,zg=new Map,Yg=(e,t,n)=>`${e}|${t}|${n}`});import sq from"node:fs/promises";import aq from"node:os";import Pp from"node:path";async function ey(e){try{return(await sq.stat(e)).size}catch{return null}}async function Ya(e){let[t,n,r]=await Promise.all([ey(Pp.join(iq,"CLAUDE.md")),e?ey(Pp.join(e,"CLAUDE.md")):null,e?ey(Pp.join(e,".bostrat","memory","MEMORY.md")):null]);return{bostratClaudeMd:t,repoClaudeMd:n,memoryIndex:r}}var iq,ty=G(()=>{iq=process.env.BOSTRAT_STATE_DIR||Pp.join(process.env.HOME||aq.tmpdir(),".bostrat")});import{randomUUID as cq}from"node:crypto";async function Bp(e,t,n={}){let r={operationId:cq(),kind:t,startedAt:Date.now(),...n};return Dp.set(e.id,r),await N(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:r.startedAt,state:"started",...r}}).catch(()=>{}),r}async function ny(e,t,n="completed",r=null){Dp.get(e.id)?.operationId===t?.operationId&&Dp.delete(e.id),await N(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 Dp,M$,ry=G(()=>{be();Dp=new Map;M$=e=>Dp.get(e)||null});var mR={};sm(mR,{HANDOFF_LATEST_REL:()=>Io,KNOWN_AGENTS:()=>yl,LOGIN_GREETING:()=>Y$,TRACK_NAME_MAX:()=>gy,addTrackRepo:()=>Qp,adoptTrack:()=>tb,agentAvailability:()=>zp,announceNodeUpdate:()=>or,answerFullscreenOffer:()=>zy,answerPrompt:()=>Yp,answeringFor:()=>Ty,archiveTrack:()=>Ds,archiveTrackForMergedPr:()=>Er,augmentFirstPromptAfterHandoff:()=>H$,buildAgentCmd:()=>yy,canResumeSubtask:()=>dR,cancelQueued:()=>kl,cancelQueuedToDraft:()=>_y,cancelStopJob:()=>oi,cancelSubtask:()=>df,changedRepos:()=>_s,commitTransferOut:()=>cf,createSetupTrack:()=>jy,createTrack:()=>tf,deleteTrack:()=>Uy,demoteTransferredTracks:()=>eb,ensureLeadEpochs:()=>_o,forceMergeSubtask:()=>ob,getHandoffJob:()=>ii,getReshapeJob:()=>xl,getSubtaskJob:()=>_5,getTrack:()=>me,getTransferOutJob:()=>Zy,healDeadLead:()=>wl,interruptLead:()=>Zp,isArchiving:()=>p5,isHandoffNoteEcho:()=>dy,isInterruptEcho:()=>py,isLeadStarting:()=>z$,isModelSwitchEcho:()=>fy,leadCliDead:()=>Wy,listSubtaskJobs:()=>Ls,listTracks:()=>ke,matchTranscriptsToBoxes:()=>K$,mergeNotifyMessage:()=>iR,navigatePrompt:()=>Ay,notifyTrackForMergedPr:()=>_r,notifyTrackForResolvedPr:()=>nf,offerFollowupsForMergedPr:()=>Bs,pendingOffers:()=>vy,queueGauges:()=>Ey,queueShipCompleteNotify:()=>$y,queuedMessages:()=>Cs,rawTrack:()=>xy,reapArchivedOrphans:()=>Vy,reconcileDemotedTracks:()=>Ky,reconcileHandoffOutcome:()=>cR,reconcileInterruptedHandoffs:()=>Yy,reconcileInterruptedReshapes:()=>By,reconcileInterruptedSubtasks:()=>nb,reconcileNodeUpdateNotices:()=>ky,reconcileSubtaskOutcome:()=>uR,refreshStandingInstructions:()=>Ly,refuseIfTransferred:()=>af,rehydrateLead:()=>ai,removeTrackRepo:()=>ef,renameTrack:()=>Gy,reposOf:()=>Gt,reshapeTrack:()=>Dy,resolveTrackBox:()=>Hc,resolveTrackBoxByHookToken:()=>bl,restartLead:()=>of,resumeAgentCmd:()=>Vp,reviveLeadForSession:()=>qy,sayToLead:()=>qt,sendOptionsForAgent:()=>Un,setTrackDraft:()=>My,setTrackModel:()=>Cy,startLeadHandoff:()=>sf,startSpinUpView:()=>Ry,startSubtask:()=>rb,startTransferOut:()=>Qy,stopJobActive:()=>Z$,subtaskMessages:()=>Sy,trackMessages:()=>Jp,unarchiveTrack:()=>rf});import Y from"node:fs/promises";import z from"node:path";import{randomUUID as qp,createHash as lq}from"node:crypto";import{execFile as uq}from"node:child_process";import{promisify as dq}from"node:util";function yy(e,{skipPermissions:t=!0,model:n=null}={}){let r=Kp[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=dw(e).find(i=>i.alias===n);if(!a)throw new Error(`unknown ${e} launch model "${n}"`);s+=` --model ${a.alias}`}return s}function Vp(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=Kp[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&&!xn(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 Ps(e){let t=Kp[e];if(t)return process.env[t.envVar]||t.base}async function zp({maxAgeMs:e=6e4}={}){if(Eo.value&&Date.now()-Eo.at<e)return Eo.value;let t=Eo.value,n=await Promise.all(yl.map(async r=>{let o=await Fu(Ps(r),{retries:[]});return o===ua?[r,t?.[r]??!0]:[r,o===ju]}));return Eo.value=Object.fromEntries(n),Eo.at=Date.now(),Eo.value}async function ri(e,t=!0,n=null){let r=yy(e,{skipPermissions:t,model:n});if(await Fu(r)===la){Eo.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.":Hm[o]?`Install it on this node: ${Hm[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 H$(e,t=Io){return`${e.trim()}
226
226
 
227
- (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 dy(e){return e.role==="user"&&fq.test((e.text||"").trim())}async function ne(){return Ht||(oy||=(async()=>{try{Ht=JSON.parse(await Y.readFile(U$,"utf8"))}catch{Ht={tracks:[]}}finally{oy=null}return Ht})(),oy)}async function ae(){await Bt(U$,Ht)}function wq(e,t){let n=JSON.stringify({trackId:e,...t})+`
228
- `;return sy=sy.then(()=>Y.mkdir(nr,{recursive:!0})).then(()=>Y.appendFile(dq,n)).catch(()=>{}),sy}async function W$(e,{box:t,agent:n,message:r}){let o=fe(await ne(),e);!o||o.archivedAt||(Ee(o,"startup-gate",{box:t,agent:n??null,message:r}),await ae(),Ac(o,{provider:n??null,cls:"startup-gate",note:r}).catch(()=>{}))}async function or({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 Y.readFile(ay,"utf8"))}catch{}if(d?.latest===t&&d?.current===e)return{announced:0,deduped:!0}}let l=await ne(),u=0;for(let d of l.tracks)Ue(d)||!d.leadBox||(Ee(d,"node-update",{status:s,current:e??null,latest:t,...n?{min:n}:{},...r?{installKind:r}:{},...a?{policy:a}:{},...i?{error:String(i).slice(0,400)}:{},...c?{reason:c}:{},required:o===!0}),u++);if(await ae().catch(()=>{}),s==="available")try{await Y.mkdir(z.dirname(ay),{recursive:!0}),await Y.writeFile(ay,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function ky({current:e,installKind:t=null,policy:n=null}={}){if(!e)return{reconciled:!1,announced:0,targets:[]};let r=await ne(),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)||gq(e,c)||(Ee(a,"node-update",{status:"done",current:l.current??null,latest:c,...t?{installKind:t}:{},...n?{policy:n}:{},reason:"version-reconciled",installed:e,required:!1}),o++,s.add(c))}return o&&await ae().catch(()=>{}),{reconciled:o>0,announced:o,targets:[...s]}}function gq(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 q$(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=>yq.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 G$(e,t,n,{kind:r}={}){let o=await Se(t);if(!o)throw new Error(`box "${t}" is not running`);let s=Ps(o.agent),a=qc({text:n,producer:Wc({kind:r,orchestration:!0}),kind:r||"orchestration",provider:o.agent}),i=fe(await ne(),e)||null,c=Date.now(),l=null;try{l=await wr({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s})}catch(y){throw Kc(a,{ms:Date.now()-c,outcome:y?.code==="cli-not-running"?"cli-not-running":"blocked"}),await In(i,a,Ha(y)),y}Kc(a,{ms:Date.now()-c,outcome:l||"up"});let u=Un(o.agent,n);a.paste=!!u.paste;try{await Qe(t,n,{...u,kind:r||"orchestration"})}catch(y){throw await In(i,a,Ha(y)),y}let d={},p=await wc({sessionName:t,agent:o.agent,agentCmd:s,text:n,trackId:e,flow:"orchestration",stats:d});a.verify=d,await In(i,a,p?d.verdict==="unverified"?"unverified":"delivered":"unsubmitted"),await ee({flow:"orchestration",phase:"sent",submitted:p,trackId:e,sessionName:t,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let f=await ne(),w=fe(f,e);if(!w)return;let h=w.boxes.find(y=>y.name===t);Ee(w,"orchestration-prompt",{box:t,agent:h?.agent||o.agent,boxRole:h?.role,prompt:n,kind:r||"orchestration",deliveryId:a.id}),await ae()}async function bq(e){let t=z.join(sa(e),`${e.id}.ndjson`),n;try{n=await Y.stat(t)}catch{return null}let r=C$.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 C$.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function kq(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:vc(n.name,n.agent)}async function Zt(e,t=null,n=null){let r=t??new Map((await kn()).map(S=>[S.name,S])),o=!!e.transferredTo,s=e.boxes.map(S=>{let _=o?null:r.get(S.name),M=jr.has(S.state)?S.state:_?S.role==="lead"?"live":S.state:"stopped";return{...S,state:M,cwd:_?.cwd||S.cwd,agent:_?.agent||S.agent,sessionId:_?.sessionId||S.sessionId}}),[a,{working:i,prompted:c},l,u,d]=await Promise.all([bq(e),kq(e,s),Gg(e),n??En().catch(()=>[]),$$({...e,boxes:s})]),p=hl.has(e.id),f=(u||[]).filter(S=>S.trackId===e.id&&!["merged","closed","lost"].includes(S.state)),w=M$(e.id),h=w&&{status:"waiting",since:w.startedAt,summary:w.summary??null,count:w.count??null}||k$(f),y=s.find(S=>S.name===e.leadBox)?.state==="live",k=y?Cs(e.id).filter(S=>S.kind!=="ship-notify"&&S.kind!=="prompt-answer"&&S.kind!=="login-greet"):[],g=d||(y&&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`}:k.length?{source:"queue",count:k.length,since:Math.min(...k.map(S=>S.ts||Date.now())),summary:"a queued message is about to send"}:null),x=v$({archivedAt:e.archivedAt,archiving:p,prompted:c,openActions:l.openActions,openActionSince:l.openActionSince,prDecisions:x$(f),operation:h,phase:l.phase,working:i,workingSince:l.currentTurnAt,pending:g,completedTurnAt:l.completedTurnAt||a,live:y});return{...e,boxes:s,lastResponseAt:a,working:i,prompted:c,archiving:p,status:x}}function K$(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-xq,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 V$(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=Dx(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=K$(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 Tx(p.box,p.sessionId),n=!0}}return n}async function ke(){let e=await ne();await V$(e)&&await ae();let t=new Map((await kn()).map(r=>[r.name,r])),n=await En().catch(()=>[]);return Promise.all(e.tracks.map(r=>Zt(r,t,n)))}async function Hc(e,t){let n=await ne();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 bl(e){let t=Ho(e);if(!t)return null;let n=await ne();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&Xk(o.hookTokenHash,t))return{track:r,box:o};return null}async function xy(e){return fe(await ne(),e)??null}async function me(e){let t=await ne(),n=fe(t,e);return n?(await V$(t)&&await ae(),Zt(n)):null}async function vy(e){let t=await K(e).catch(()=>[]),n;try{n=Hn(t)}catch{return[]}let r=ud(n).map(s=>({kind:s.kind,id:s.offerId??s.proposalId??s.id,ts:s.ts??null})),o=[];try{o=eS(t)}catch{o=[]}return r.concat(o.map(s=>({kind:"pr-open",id:`${s.repo??""}#${s.number}`,ts:null})))}function py(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(vq[e.agent]||[]).some(n=>n.test(t))}function fy(e){let t=(e.text||"").trim();return t?Sq.some(n=>n.test(t)):!1}function z$(e,t,n=Date.now()){return!e||e.readyAt||e.state!=="live"?!1:n-(t||0)<Aq}async function zp(e,t={}){let n=await me(e);if(!n)return null;let r=new Set([...n.events.filter(O=>O.type==="orchestration-prompt"&&O.prompt).map(O=>String(O.prompt).trim()),...n.events.filter(O=>O.type==="said"&&O.text).map(O=>String(O.text).trim())]),o=ii(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=mg(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...Q_(n),...l],p={windows:[...uA(n),...dA(n,vd),...a,...u]},w=(await Promise.all(n.boxes.map(O=>Bh(O,t)))).flat(),h=w.map(O=>{let X={kind:"message",...O};if(X.role==="assistant"&&(X.text||"").trim()&&X.tools?.length){let re=ao(X.agent).cliTools,he=X.tools.filter(Be=>!re.has(Be));return{...X,tools:he.length?he:void 0}}return X}).map(O=>{if(O.role!=="user")return O;let X=Hv(O);return X?X.kind==="suppress"?null:{...O,note:X,text:qv(X)}:O}).filter(Boolean).filter(O=>!(O.role==="user"&&r.has((O.text||"").trim()))).filter(O=>!py(O)).filter(O=>!fy(O)).filter(O=>!dy(O)).filter(O=>!Bg(O)).filter(O=>O.role!=="assistant"||!!(O.text||"").trim()||!!O.images?.length).filter(O=>!pA(O,p)),y=h.filter(O=>O.failed&&O.text===Qo);if(y.length){let O=new Map;for(let X of y){if(!O.has(X.box)){let Be=[...(await Ne(X.box,{lines:ze}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(Pt=>Pt[1]);O.set(X.box,Be.length?Be[Be.length-1]:null)}let re=O.get(X.box);re&&(X.text=`\u25A0 ${re}`)}}let k=await Promise.all(n.boxes.map(O=>WS(O,t)));await __(n,k.flat());let{agentTurnBoxes:g}=await T_(n,h);for(let O of n.boxes)g.has(O.name)&&O.cwd&&Iu(O.cwd);await dT(n),await sI(n,h).catch(()=>{});for(let O of n.boxes)O.agent==="codex"&&O.state==="live"&&await $_(n,O),O.agent==="cursor"&&O.state==="live"&&await N_(n,O);let x=await Promise.all(n.boxes.map(O=>HS(O,t)));await E_(n,x.flat().filter(O=>!iy(O.box,O.ts,u)));let S=await K(n),_=c&&i.viewId?i.viewId:null,M=AT(S),P=Hn(S).filter(O=>!(O.kind==="message"&&(py(O)||fy(O)||dy(O)||Bg(O)))&&!(O.kind==="view-card"&&_&&O.viewId===_)),j=TT(P,M),T=P.filter(O=>!(O.kind==="message"&&O.role==="assistant"&&!j.has(O)&&iy(O.box,O.ts,M))),$=bh(S,T).map(O=>({kind:"command-batch",id:O.id,ts:O.pending?O.ts:(O.anchorTs??O.ts)-1,anchorTs:O.anchorTs,anchorBox:O.anchorBox,agent:O.agent,boxRole:O.boxRole,commands:O.commands,pending:O.pending})).filter(O=>!iy(O.anchorBox,O.anchorTs??O.ts,u)),L=Zv(Qv([...T,...$].filter(O=>O.ts!=null).sort((O,X)=>O.ts-X.ts))),H=Tq(n),R=H.size?L.filter(O=>O.kind==="event"||!H.has(O.box??O.anchorBox)):L,A=n.boxes.find(O=>O.name===n.leadBox)||null,C=A?await nc(A.cwd,A.sessionId,{fallbackNewest:!1}):null;if(!C&&A){let O=[...S].reverse().find(X=>X.type==="context.usage"&&X.boxId===A.name);O?.payload?.window&&(C={pct:O.payload.pct??(O.payload.occupancy!=null?O.payload.occupancy/O.payload.window:null),occupancy:O.payload.occupancy??null,window:O.payload.window,windowKnown:!0,model:O.payload.model||null})}let W=[...w].reverse().find(O=>O.role==="assistant"&&O.model),B=W?.model||null,Z=[...n.events||[]].reverse().find(O=>O.type==="model-change"),xe=C?.model||B;Z&&(!W?.ts||Z.at>=W.ts)&&(xe=Z.to);let Ae=A?await Ne(A.name,{lines:ze}).catch(()=>""):"",_e=A&&oo(A.agent,Ae)?await Jt(A.name).catch(()=>Ae):Ae,Q=A?Sn(A,_e):null;if(A&&Ay(A.name,Q,_e)&&Q&&(Q={...Q,answering:!0}),Q&&A){let O=fd(A,Q,_e);if(O){let X=vS(A.name,Q.promptId);X.action!=="give-up"&&(X.action==="send"&&(O.accept&&Qu(A.name,_e),(!O.gate||eo(A.name,O.gate))&&Ke(A.name,O.keys,{kind:O.accept?"auto-accept":"auto-reject"}).catch(()=>{}),X.first&&N(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:A.name,provider:A.agent,payload:{ts:Date.now(),promptId:Q.promptId,rule:O.id}}).catch(()=>{})),Q=null)}}A&&(Q?.setup&&pv(A.name,_e),!Q&&cc(A.agent,Ae)&&Xu(A.name)&&eo(A.name,"login-issue")&&(Zu(A.name),Qe(A.name,"/login",{enter:!0,submitDelayMs:600,kind:"login-issue"}).catch(()=>{}))),!Q&&A&&!ba(A.agent,Ae)&&!Cs(n.id).length&&(Q=wh(R,{leadBoxId:A.name,provider:A.agent,isAnswered:O=>S.some(X=>X.type==="prompt.answered"&&X.payload?.promptId===O)})),Q&&pT(n,A,Q);let Xe=R.filter(O=>!(O.kind==="message"&&O.role==="assistant"&&O.ask&&!String(O.text||"").trim()&&!O.images?.length)),le=!!A&&md(A.name,A.agent,Ae)&&!Q;if(A&&!A.readyAt&&(le||Q||Ae&&to(A.agent,Ae))){A.readyAt=Date.now();let O=fe(await ne(),n.id)?.boxes?.find(X=>X.name===A.name);O&&!O.readyAt&&(O.readyAt=A.readyAt,await ae())}let ge=z$(A,n.createdAt),de=!!A&&!!Ae&&to(A.agent,Ae)&&!Q&&!cc(A.agent,Ae)&&!ya(A.agent,Ae),te=!1;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&A){if(de){let O=await ne(),X=fe(O,n.id);X?.setup&&!X.setup.connectedAt&&(X.setup.connectedAt=Date.now(),n.setup.connectedAt=X.setup.connectedAt,te=!0,await ae())}}else A&&de&&dv(A.name)&&(te=!0);if(te&&fv(A.name),A){let O=mv(A.name),X=uv(A.name);O.started&&N(n,{type:"provider.login.started",actor:"system",source:"pane",boxId:A.name,provider:A.agent,payload:{provider:A.agent,reason:X?.startedReason||"auth-screen",ts:Date.now()}}).catch(()=>{}),O.connected&&(await N(n,{type:"provider.connected",actor:"system",source:"pane",boxId:A.name,provider:A.agent,payload:{provider:A.agent,ts:X?.connectedAt||Date.now(),...X?.account?{account:X.account}:{},reason:X?.startedReason||"already-signed-in"}}).catch(()=>{}),n.kind!=="setup"&&X?.startedReason&&!Nq(n.id)&&qt(n.id,Y$,{kind:"login-greet"}).catch(re=>{console.warn(`[track ${n.id}] login greeting not delivered: ${re?.message||re}`)}))}let we=s?{running:!0,step:o.step,toAgent:o.toAgent||null,wait:o.wait||null}:null,Oe=xl(n.id),Ve=Oe&&!Oe.finishedAt?{running:!0,step:Oe.step||null,added:Oe.added||[],removed:Oe.removed||[]}:null,Nt=null;if(c){let O=Date.now()-i.startedAt;if(i.viewId&&!le){let X=xp(n.id);X&&(Ee(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:X.finishedAt}),await ae())}else if(Q||O>X_&&!le&&!i.viewId||O>fg){let X=Q?"needs-input":O>fg?"timeout":"no-view";xp(n.id,{error:X})&&await N(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:A?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:X}}).catch(()=>{})}else Nt={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:Xe,context:C?{pct:C.pct,occupancy:C.occupancy,window:C.window,windowKnown:C.windowKnown,model:C.model}:null,models:{current:xe,options:dw(A?.agent)},pendingPrompt:Q,working:le,stopping:Z$(n.id),leadStarting:ge,handoff:we,reshape:Ve,view:Nt,queued:Cs(n.id).filter(O=>O.kind!=="ship-notify"&&O.kind!=="prompt-answer"&&O.kind!=="login-greet"),draft:n.draft||null,draftRev:n.draftRev||0}}function Tq(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 Sy(e,t){let n=await me(e);if(!n)return null;let r=Ls(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=Hn(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=bh(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 Ne(o,{lines:ze}).catch(()=>"");u=md(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}function Eq(e,t){if(e==null)return[];if(!Array.isArray(e))throw new Error("custom answer must be a list of strings");return e.slice(0,Math.max(1,t)).map(n=>{if(n==null||n==="")return"";if(typeof n!="string")throw new Error("custom answer must be text");let r=n.replace(/\s+/g," ").trim();if(/[\x00-\x1f\x7f]/.test(r))throw new Error("custom answer can't contain control characters");if(r.length>N$)throw new Error(`custom answer is too long (max ${N$} characters)`);return r})}function _q(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))}function Ay(e,t,n,r=Date.now()){let o=my.get(e);if(!o)return!1;let s=!!t&&t.promptId===o.promptId&&r-o.at<Iq&&(t.setup?!0:J$(n)===o.paneHash);return s||my.delete(e),s}async function Rq(e,t,n){let r=n;for(let o of $q){await rr(o);let s=await Jt(e).catch(()=>null);if(s!=null&&(r=s,s!==n))break}my.set(e,{promptId:t.promptId,paneHash:J$(r),setup:t.setup||null,at:Date.now()})}async function Jp(e,t={}){let n=il.get(e);n&&await n.catch(()=>{});let r=Oq(e,t);il.set(e,r);try{return await r}finally{il.get(e)===r&&il.delete(e)}}async function Oq(e,{promptId:t,answers:n,text:r,custom:o}={}){let s=fe(await ne(),e);if(!s)throw new Error(`track "${e}" not found`);oi(e,"prompt-answer");let a=s.boxes.find(g=>g.name===s.leadBox);if(!a)throw new Error(`track "${e}" has no lead box`);if(!await Se(s.leadBox))throw new Error(`lead box "${s.leadBox}" is not running`);let c=await Jt(a.name).catch(()=>""),l=Sn(a,c);if(l||(l=await Mq(s,a)),!l)throw new Error("no pending prompt to answer");if(t&&t!==l.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");if(l.answerMode!=="say"&&Ay(a.name,l,c))throw new Error("prompt already answered \u2014 waiting for the CLI to move on");let u=Eq(o,l.questions?.length??1);if(u.some(Boolean)&&!l.custom)throw new Error("custom answer isn't available for this prompt \u2014 pick one of its options");let d=(n||[]).some(g=>Array.isArray(g)&&g.length>0);if(l.custom&&!d&&!u.some(Boolean)&&l.answerMode!=="text")throw new Error("no answer selected \u2014 pick an option or type your own");u.some(Boolean)&&(n=(l.questions||[]).map((g,x)=>u[x]&&!g.multiSelect?[]:Array.isArray(n?.[x])?n[x]:[]));let p;if(l.answerMode==="text"){let g=typeof r=="string"?r.trim():"";if(!g)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(g)||g.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await Qe(s.leadBox,g,{enter:!0,kind:"answer-prompt"}),p={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(l.answerMode==="esc")await Ke(s.leadBox,["Escape"],{kind:"answer-prompt"}),p={mode:"keys",value:"Escape",count:1};else if(l.answerMode==="say"){let g=zv(l,n||[],typeof r=="string"?r:"",u);if(!g)throw new Error("no answer selected \u2014 pick an option or reply in chat");await qt(s.id,g,{kind:"prompt-answer"}),p={mode:"say",value:g,count:1}}else if(u[0]&&l.provider==="claude"){let g=yS(l,n||[],u[0]);await Hm(s.leadBox,[...g.pre,{text:g.text}],{kind:"answer-prompt"});let x=!1;for(let _ of[150,300,600]){await rr(_);let M=await Jt(s.leadBox).catch(()=>""),P=Sn(a,M);if(P?.customText&&_q(P.customText,g.text)){x=!0;break}}if(!x)throw new Error("custom answer didn't take \u2014 the widget moved; reload and answer again");await Hm(s.leadBox,g.post,{kind:"answer-prompt"});let S=_=>_.map(M=>M.key).join(" ");p={mode:"keys+text",value:`${S(g.pre)} \u2039text\u203A ${S(g.post)}`.trim(),count:g.pre.length+1+g.post.length}}else if(l.provider==="claude"||l.answerMode==="keys"){let g=Eh(l,n||[]);await Ke(s.leadBox,g,{kind:"answer-prompt"}),p={mode:"keys",value:g.join(" "),count:g.length}}else{let g=sv(l,n||[]);await Qe(s.leadBox,g,{enter:!0,kind:"answer-prompt"}),p={mode:"text",value:g,count:1}}if(l.answerMode!=="say"&&await Rq(a.name,l,c),l.answerMode==="say"){let g=l.questions||[];for(let x=0;x<g.length;x++){let S=g[x],_=new Set(Array.isArray(n?.[x])?n[x]:[]),M=[..._].map(j=>S.options?.[j]).filter(Boolean).map(j=>({label:j.label,description:j.description||""}));u[x]&&M.push({label:u[x],description:"",custom:!0});let P=(S.options||[]).map((j,T)=>_.has(T)?null:j?.label).filter(Boolean);pw(s,a,l,{...p,groupId:l.groupId||l.promptId,questionIndex:x,questionTotal:l.questionTotal??g.length,header:S.header||"",question:S.question||"",multiSelect:!!S.multiSelect,chosen:M,rejected:P})}return await ee({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:l.provider,promptId:l.promptId,...p}).catch(()=>{}),{ok:!0,promptId:l.promptId,sent:p.count}}let f=l.questions?.[0]||{},w=new Set(Array.isArray(n?.[0])?n[0]:[]),h=[...w].map(g=>f.options?.[g]).filter(Boolean).map(g=>({label:g.label,description:g.description||""}));u[0]&&h.push({label:u[0],description:"",custom:!0});let y=(f.options||[]).map((g,x)=>w.has(x)?null:g?.label).filter(Boolean),k=l.review?"review":/^claude:model-confirm:/.test(l.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(l.promptId||"")?"resume-confirm":l.setup==="continue"?"login-continue":void 0;return p={...p,groupId:l.groupId||l.promptId,questionIndex:l.questionIndex??0,questionTotal:l.questionTotal??1,header:f.header||"",question:f.question||"",multiSelect:!!f.multiSelect,chosen:h,rejected:y,...k?{control:k}:{}},await ee({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:l.provider,promptId:l.promptId,...p}).catch(()=>{}),pw(s,a,l,p),{ok:!0,promptId:l.promptId,sent:p.count}}async function Mq(e,t){if(!t)return null;let n=await K(e).catch(()=>[]);return wh(Hn(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function Ty(e,{promptId:t,questionIndex:n}={}){let r=fe(await ne(),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 Se(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await wS(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=bS(a,n);return c.length?(await Ke(r.leadBox,c,{kind:"navigate-prompt"}),await ee({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 Yp(e){let t=Ms.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},Ms.set(e,t)),t}function Nq(e){let t=Ms.get(e);return!!t&&(t.items.length>0||!!t.flushing)}function Cs(e){return(Ms.get(e)?.items??[]).map(({delivery:t,...n})=>({...n}))}function Ey(e=Date.now()){let t=0,n=0;for(let r of Ms.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 Pq(e,t,n){let r=t.filter(o=>o.delivery&&!o.delivery.settled);r.length&&(async()=>{let o=fe(await ne(),e)||null;for(let s of r)await In(o,s.delivery,`dropped:${n}`)})().catch(()=>{})}function kl(e,t="cancel"){let n=Ms.get(e);if(!n)return[];let r=n.items.splice(0);return n.idleSince=null,n.timer&&(clearInterval(n.timer),n.timer=null),Pq(e,r,t),r}async function _y(e){let t=kl(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=fe(await ne(),e);if(o)return r=ti(o,n),await ae(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function Iy(e){let t=Yp(e);t.timer||(t.timer=setInterval(()=>Dq(e).catch(()=>{}),Cq))}async function Dq(e){let t=Ms.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=fe(await ne(),e);if(!n||n.archivedAt){kl(e,"archived");return}let r=async(l,u="")=>{let d=[];for(let y of t.items)H_(y.delivery,l),u$(y,l)&&d.push(y);if(!d.length)return;t.items=t.items.filter(y=>!d.includes(y));let p=Date.now()-Math.min(...d.map(y=>y.heldSince||Date.now())),f=Math.max(1,Math.round(jg()/6e4)),w=String(u||"").split(`
227
+ (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 dy(e){return e.role==="user"&&mq.test((e.text||"").trim())}async function ne(){return Ht||(oy||=(async()=>{try{Ht=JSON.parse(await Y.readFile(U$,"utf8"))}catch{Ht={tracks:[]}}finally{oy=null}return Ht})(),oy)}async function ae(){await Bt(U$,Ht)}function gq(e,t){let n=JSON.stringify({trackId:e,...t})+`
228
+ `;return sy=sy.then(()=>Y.mkdir(nr,{recursive:!0})).then(()=>Y.appendFile(pq,n)).catch(()=>{}),sy}async function W$(e,{box:t,agent:n,message:r}){let o=fe(await ne(),e);!o||o.archivedAt||(Ee(o,"startup-gate",{box:t,agent:n??null,message:r}),await ae(),Tc(o,{provider:n??null,cls:"startup-gate",note:r}).catch(()=>{}))}async function or({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 Y.readFile(ay,"utf8"))}catch{}if(d?.latest===t&&d?.current===e)return{announced:0,deduped:!0}}let l=await ne(),u=0;for(let d of l.tracks)Ue(d)||!d.leadBox||(Ee(d,"node-update",{status:s,current:e??null,latest:t,...n?{min:n}:{},...r?{installKind:r}:{},...a?{policy:a}:{},...i?{error:String(i).slice(0,400)}:{},...c?{reason:c}:{},required:o===!0}),u++);if(await ae().catch(()=>{}),s==="available")try{await Y.mkdir(z.dirname(ay),{recursive:!0}),await Y.writeFile(ay,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function ky({current:e,installKind:t=null,policy:n=null}={}){if(!e)return{reconciled:!1,announced:0,targets:[]};let r=await ne(),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)||yq(e,c)||(Ee(a,"node-update",{status:"done",current:l.current??null,latest:c,...t?{installKind:t}:{},...n?{policy:n}:{},reason:"version-reconciled",installed:e,required:!1}),o++,s.add(c))}return o&&await ae().catch(()=>{}),{reconciled:o>0,announced:o,targets:[...s]}}function yq(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 q$(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=>bq.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 G$(e,t,n,{kind:r}={}){let o=await Se(t);if(!o)throw new Error(`box "${t}" is not running`);let s=Ps(o.agent),a=qc({text:n,producer:Wc({kind:r,orchestration:!0}),kind:r||"orchestration",provider:o.agent}),i=fe(await ne(),e)||null,c=Date.now(),l=null;try{l=await wr({cwd:o.cwd,sessionId:o.sessionId,sessionName:t,agent:o.agent,agentCmd:s})}catch(y){throw Kc(a,{ms:Date.now()-c,outcome:y?.code==="cli-not-running"?"cli-not-running":"blocked"}),await In(i,a,Ha(y)),y}Kc(a,{ms:Date.now()-c,outcome:l||"up"});let u=Un(o.agent,n);a.paste=!!u.paste;try{await Qe(t,n,{...u,kind:r||"orchestration"})}catch(y){throw await In(i,a,Ha(y)),y}let d={},p=await wc({sessionName:t,agent:o.agent,agentCmd:s,text:n,trackId:e,flow:"orchestration",stats:d});a.verify=d,await In(i,a,p?d.verdict==="unverified"?"unverified":"delivered":"unsubmitted"),await ee({flow:"orchestration",phase:"sent",submitted:p,trackId:e,sessionName:t,agent:o.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let f=await ne(),w=fe(f,e);if(!w)return;let h=w.boxes.find(y=>y.name===t);Ee(w,"orchestration-prompt",{box:t,agent:h?.agent||o.agent,boxRole:h?.role,prompt:n,kind:r||"orchestration",deliveryId:a.id}),await ae()}async function kq(e){let t=z.join(sa(e),`${e.id}.ndjson`),n;try{n=await Y.stat(t)}catch{return null}let r=C$.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 C$.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function xq(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:vc(n.name,n.agent)}async function Zt(e,t=null,n=null){let r=t??new Map((await kn()).map(S=>[S.name,S])),o=!!e.transferredTo,s=e.boxes.map(S=>{let _=o?null:r.get(S.name),M=jr.has(S.state)?S.state:_?S.role==="lead"?"live":S.state:"stopped";return{...S,state:M,cwd:_?.cwd||S.cwd,agent:_?.agent||S.agent,sessionId:_?.sessionId||S.sessionId}}),[a,{working:i,prompted:c},l,u,d]=await Promise.all([kq(e),xq(e,s),Gg(e),n??En().catch(()=>[]),$$({...e,boxes:s})]),p=hl.has(e.id),f=(u||[]).filter(S=>S.trackId===e.id&&!["merged","closed","lost"].includes(S.state)),w=M$(e.id),h=w&&{status:"waiting",since:w.startedAt,summary:w.summary??null,count:w.count??null}||k$(f),y=s.find(S=>S.name===e.leadBox)?.state==="live",k=y?Cs(e.id).filter(S=>S.kind!=="ship-notify"&&S.kind!=="prompt-answer"&&S.kind!=="login-greet"):[],g=d||(y&&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`}:k.length?{source:"queue",count:k.length,since:Math.min(...k.map(S=>S.ts||Date.now())),summary:"a queued message is about to send"}:null),x=v$({archivedAt:e.archivedAt,archiving:p,prompted:c,openActions:l.openActions,openActionSince:l.openActionSince,prDecisions:x$(f),operation:h,phase:l.phase,working:i,workingSince:l.currentTurnAt,pending:g,completedTurnAt:l.completedTurnAt||a,live:y});return{...e,boxes:s,lastResponseAt:a,working:i,prompted:c,archiving:p,status:x}}function K$(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-vq,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 V$(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=Dx(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=K$(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 Ax(p.box,p.sessionId),n=!0}}return n}async function ke(){let e=await ne();await V$(e)&&await ae();let t=new Map((await kn()).map(r=>[r.name,r])),n=await En().catch(()=>[]);return Promise.all(e.tracks.map(r=>Zt(r,t,n)))}async function Hc(e,t){let n=await ne();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 bl(e){let t=Ho(e);if(!t)return null;let n=await ne();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&Xk(o.hookTokenHash,t))return{track:r,box:o};return null}async function xy(e){return fe(await ne(),e)??null}async function me(e){let t=await ne(),n=fe(t,e);return n?(await V$(t)&&await ae(),Zt(n)):null}async function vy(e){let t=await K(e).catch(()=>[]),n;try{n=Hn(t)}catch{return[]}let r=dd(n).map(s=>({kind:s.kind,id:s.offerId??s.proposalId??s.id,ts:s.ts??null})),o=[];try{o=eS(t)}catch{o=[]}return r.concat(o.map(s=>({kind:"pr-open",id:`${s.repo??""}#${s.number}`,ts:null})))}function py(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(Sq[e.agent]||[]).some(n=>n.test(t))}function fy(e){let t=(e.text||"").trim();return t?Tq.some(n=>n.test(t)):!1}function z$(e,t,n=Date.now()){return!e||e.readyAt||e.state!=="live"?!1:n-(t||0)<Aq}async function Jp(e,t={}){let n=await me(e);if(!n)return null;let r=new Set([...n.events.filter(O=>O.type==="orchestration-prompt"&&O.prompt).map(O=>String(O.prompt).trim()),...n.events.filter(O=>O.type==="said"&&O.text).map(O=>String(O.text).trim())]),o=ii(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=mg(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...Q_(n),...l],p={windows:[...uT(n),...dT(n,Sd),...a,...u]},w=(await Promise.all(n.boxes.map(O=>Bh(O,t)))).flat(),h=w.map(O=>{let X={kind:"message",...O};if(X.role==="assistant"&&(X.text||"").trim()&&X.tools?.length){let re=ao(X.agent).cliTools,he=X.tools.filter(Be=>!re.has(Be));return{...X,tools:he.length?he:void 0}}return X}).map(O=>{if(O.role!=="user")return O;let X=Hv(O);return X?X.kind==="suppress"?null:{...O,note:X,text:qv(X)}:O}).filter(Boolean).filter(O=>!(O.role==="user"&&r.has((O.text||"").trim()))).filter(O=>!py(O)).filter(O=>!fy(O)).filter(O=>!dy(O)).filter(O=>!Bg(O)).filter(O=>O.role!=="assistant"||!!(O.text||"").trim()||!!O.images?.length).filter(O=>!pT(O,p)),y=h.filter(O=>O.failed&&O.text===Qo);if(y.length){let O=new Map;for(let X of y){if(!O.has(X.box)){let Be=[...(await Ne(X.box,{lines:ze}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(Pt=>Pt[1]);O.set(X.box,Be.length?Be[Be.length-1]:null)}let re=O.get(X.box);re&&(X.text=`\u25A0 ${re}`)}}let k=await Promise.all(n.boxes.map(O=>WS(O,t)));await __(n,k.flat());let{agentTurnBoxes:g}=await A_(n,h);for(let O of n.boxes)g.has(O.name)&&O.cwd&&Iu(O.cwd);await dA(n),await sI(n,h).catch(()=>{});for(let O of n.boxes)O.agent==="codex"&&O.state==="live"&&await $_(n,O),O.agent==="cursor"&&O.state==="live"&&await N_(n,O);let x=await Promise.all(n.boxes.map(O=>HS(O,t)));await E_(n,x.flat().filter(O=>!iy(O.box,O.ts,u)));let S=await K(n),_=c&&i.viewId?i.viewId:null,M=TA(S),P=Hn(S).filter(O=>!(O.kind==="message"&&(py(O)||fy(O)||dy(O)||Bg(O)))&&!(O.kind==="view-card"&&_&&O.viewId===_)),j=AA(P,M),A=P.filter(O=>!(O.kind==="message"&&O.role==="assistant"&&!j.has(O)&&iy(O.box,O.ts,M))),$=bh(S,A).map(O=>({kind:"command-batch",id:O.id,ts:O.pending?O.ts:(O.anchorTs??O.ts)-1,anchorTs:O.anchorTs,anchorBox:O.anchorBox,agent:O.agent,boxRole:O.boxRole,commands:O.commands,pending:O.pending})).filter(O=>!iy(O.anchorBox,O.anchorTs??O.ts,u)),L=Zv(Qv([...A,...$].filter(O=>O.ts!=null).sort((O,X)=>O.ts-X.ts))),H=Eq(n),R=H.size?L.filter(O=>O.kind==="event"||!H.has(O.box??O.anchorBox)):L,T=n.boxes.find(O=>O.name===n.leadBox)||null,C=T?await nc(T.cwd,T.sessionId,{fallbackNewest:!1}):null;if(!C&&T){let O=[...S].reverse().find(X=>X.type==="context.usage"&&X.boxId===T.name);O?.payload?.window&&(C={pct:O.payload.pct??(O.payload.occupancy!=null?O.payload.occupancy/O.payload.window:null),occupancy:O.payload.occupancy??null,window:O.payload.window,windowKnown:!0,model:O.payload.model||null})}let W=[...w].reverse().find(O=>O.role==="assistant"&&O.model),B=W?.model||null,Z=[...n.events||[]].reverse().find(O=>O.type==="model-change"),xe=C?.model||B;Z&&(!W?.ts||Z.at>=W.ts)&&(xe=Z.to);let Te=T?await Ne(T.name,{lines:ze}).catch(()=>""):"",_e=T&&oo(T.agent,Te)?await Jt(T.name).catch(()=>Te):Te,Q=T?Sn(T,_e):null;if(T&&Ty(T.name,Q,_e)&&Q&&(Q={...Q,answering:!0}),Q&&T){let O=md(T,Q,_e);if(O){let X=vS(T.name,Q.promptId);X.action!=="give-up"&&(X.action==="send"&&(O.accept&&ed(T.name,_e),(!O.gate||eo(T.name,O.gate))&&Ke(T.name,O.keys,{kind:O.accept?"auto-accept":"auto-reject"}).catch(()=>{}),X.first&&N(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:T.name,provider:T.agent,payload:{ts:Date.now(),promptId:Q.promptId,rule:O.id}}).catch(()=>{})),Q=null)}}T&&(Q?.setup&&pv(T.name,_e),!Q&&cc(T.agent,Te)&&Zu(T.name)&&eo(T.name,"login-issue")&&(Qu(T.name),Qe(T.name,"/login",{enter:!0,submitDelayMs:600,kind:"login-issue"}).catch(()=>{}))),!Q&&T&&!ba(T.agent,Te)&&!Cs(n.id).length&&(Q=wh(R,{leadBoxId:T.name,provider:T.agent,isAnswered:O=>S.some(X=>X.type==="prompt.answered"&&X.payload?.promptId===O)})),Q&&pA(n,T,Q);let Xe=R.filter(O=>!(O.kind==="message"&&O.role==="assistant"&&O.ask&&!String(O.text||"").trim()&&!O.images?.length)),le=!!T&&hd(T.name,T.agent,Te)&&!Q;if(T&&!T.readyAt&&(le||Q||Te&&to(T.agent,Te))){T.readyAt=Date.now();let O=fe(await ne(),n.id)?.boxes?.find(X=>X.name===T.name);O&&!O.readyAt&&(O.readyAt=T.readyAt,await ae())}let ge=z$(T,n.createdAt),de=!!T&&!!Te&&to(T.agent,Te)&&!Q&&!cc(T.agent,Te)&&!ya(T.agent,Te),te=!1;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&T){if(de){let O=await ne(),X=fe(O,n.id);X?.setup&&!X.setup.connectedAt&&(X.setup.connectedAt=Date.now(),n.setup.connectedAt=X.setup.connectedAt,te=!0,await ae())}}else T&&de&&dv(T.name)&&(te=!0);if(te&&fv(T.name),T){let O=mv(T.name),X=uv(T.name);O.started&&N(n,{type:"provider.login.started",actor:"system",source:"pane",boxId:T.name,provider:T.agent,payload:{provider:T.agent,reason:X?.startedReason||"auth-screen",ts:Date.now()}}).catch(()=>{}),O.connected&&(await N(n,{type:"provider.connected",actor:"system",source:"pane",boxId:T.name,provider:T.agent,payload:{provider:T.agent,ts:X?.connectedAt||Date.now(),...X?.account?{account:X.account}:{},reason:X?.startedReason||"already-signed-in"}}).catch(()=>{}),n.kind!=="setup"&&X?.startedReason&&!Pq(n.id)&&qt(n.id,Y$,{kind:"login-greet"}).catch(re=>{console.warn(`[track ${n.id}] login greeting not delivered: ${re?.message||re}`)}))}let we=s?{running:!0,step:o.step,toAgent:o.toAgent||null,wait:o.wait||null}:null,Oe=xl(n.id),Ve=Oe&&!Oe.finishedAt?{running:!0,step:Oe.step||null,added:Oe.added||[],removed:Oe.removed||[]}:null,Nt=null;if(c){let O=Date.now()-i.startedAt;if(i.viewId&&!le){let X=vp(n.id);X&&(Ee(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:X.finishedAt}),await ae())}else if(Q||O>X_&&!le&&!i.viewId||O>fg){let X=Q?"needs-input":O>fg?"timeout":"no-view";vp(n.id,{error:X})&&await N(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:T?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:X}}).catch(()=>{})}else Nt={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:Xe,context:C?{pct:C.pct,occupancy:C.occupancy,window:C.window,windowKnown:C.windowKnown,model:C.model}:null,models:{current:xe,options:dw(T?.agent)},pendingPrompt:Q,working:le,stopping:Z$(n.id),leadStarting:ge,handoff:we,reshape:Ve,view:Nt,queued:Cs(n.id).filter(O=>O.kind!=="ship-notify"&&O.kind!=="prompt-answer"&&O.kind!=="login-greet"),draft:n.draft||null,draftRev:n.draftRev||0}}function Eq(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 Sy(e,t){let n=await me(e);if(!n)return null;let r=Ls(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=Hn(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=bh(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 Ne(o,{lines:ze}).catch(()=>"");u=hd(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}function _q(e,t){if(e==null)return[];if(!Array.isArray(e))throw new Error("custom answer must be a list of strings");return e.slice(0,Math.max(1,t)).map(n=>{if(n==null||n==="")return"";if(typeof n!="string")throw new Error("custom answer must be text");let r=n.replace(/\s+/g," ").trim();if(/[\x00-\x1f\x7f]/.test(r))throw new Error("custom answer can't contain control characters");if(r.length>N$)throw new Error(`custom answer is too long (max ${N$} characters)`);return r})}function Iq(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))}function Ty(e,t,n,r=Date.now()){let o=my.get(e);if(!o)return!1;let s=!!t&&t.promptId===o.promptId&&r-o.at<$q&&(t.setup?!0:J$(n)===o.paneHash);return s||my.delete(e),s}async function Oq(e,t,n){let r=n;for(let o of Rq){await rr(o);let s=await Jt(e).catch(()=>null);if(s!=null&&(r=s,s!==n))break}my.set(e,{promptId:t.promptId,paneHash:J$(r),setup:t.setup||null,at:Date.now()})}async function Yp(e,t={}){let n=il.get(e);n&&await n.catch(()=>{});let r=Mq(e,t);il.set(e,r);try{return await r}finally{il.get(e)===r&&il.delete(e)}}async function Mq(e,{promptId:t,answers:n,text:r,custom:o}={}){let s=fe(await ne(),e);if(!s)throw new Error(`track "${e}" not found`);oi(e,"prompt-answer");let a=s.boxes.find(g=>g.name===s.leadBox);if(!a)throw new Error(`track "${e}" has no lead box`);if(!await Se(s.leadBox))throw new Error(`lead box "${s.leadBox}" is not running`);let c=await Jt(a.name).catch(()=>""),l=Sn(a,c);if(l||(l=await Cq(s,a)),!l)throw new Error("no pending prompt to answer");if(t&&t!==l.promptId)throw new Error("prompt changed since it was shown \u2014 reload and answer the current prompt");if(l.answerMode!=="say"&&Ty(a.name,l,c))throw new Error("prompt already answered \u2014 waiting for the CLI to move on");let u=_q(o,l.questions?.length??1);if(u.some(Boolean)&&!l.custom)throw new Error("custom answer isn't available for this prompt \u2014 pick one of its options");let d=(n||[]).some(g=>Array.isArray(g)&&g.length>0);if(l.custom&&!d&&!u.some(Boolean)&&l.answerMode!=="text")throw new Error("no answer selected \u2014 pick an option or type your own");u.some(Boolean)&&(n=(l.questions||[]).map((g,x)=>u[x]&&!g.multiSelect?[]:Array.isArray(n?.[x])?n[x]:[]));let p;if(l.answerMode==="text"){let g=typeof r=="string"?r.trim():"";if(!g)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(g)||g.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await Qe(s.leadBox,g,{enter:!0,kind:"answer-prompt"}),p={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(l.answerMode==="esc")await Ke(s.leadBox,["Escape"],{kind:"answer-prompt"}),p={mode:"keys",value:"Escape",count:1};else if(l.answerMode==="say"){let g=zv(l,n||[],typeof r=="string"?r:"",u);if(!g)throw new Error("no answer selected \u2014 pick an option or reply in chat");await qt(s.id,g,{kind:"prompt-answer"}),p={mode:"say",value:g,count:1}}else if(u[0]&&l.provider==="claude"){let g=yS(l,n||[],u[0]);await Wm(s.leadBox,[...g.pre,{text:g.text}],{kind:"answer-prompt"});let x=!1;for(let _ of[150,300,600]){await rr(_);let M=await Jt(s.leadBox).catch(()=>""),P=Sn(a,M);if(P?.customText&&Iq(P.customText,g.text)){x=!0;break}}if(!x)throw new Error("custom answer didn't take \u2014 the widget moved; reload and answer again");await Wm(s.leadBox,g.post,{kind:"answer-prompt"});let S=_=>_.map(M=>M.key).join(" ");p={mode:"keys+text",value:`${S(g.pre)} \u2039text\u203A ${S(g.post)}`.trim(),count:g.pre.length+1+g.post.length}}else if(l.provider==="claude"||l.answerMode==="keys"){let g=Eh(l,n||[]);await Ke(s.leadBox,g,{kind:"answer-prompt"}),p={mode:"keys",value:g.join(" "),count:g.length}}else{let g=sv(l,n||[]);await Qe(s.leadBox,g,{enter:!0,kind:"answer-prompt"}),p={mode:"text",value:g,count:1}}if(l.answerMode!=="say"&&await Oq(a.name,l,c),l.answerMode==="say"){let g=l.questions||[];for(let x=0;x<g.length;x++){let S=g[x],_=new Set(Array.isArray(n?.[x])?n[x]:[]),M=[..._].map(j=>S.options?.[j]).filter(Boolean).map(j=>({label:j.label,description:j.description||""}));u[x]&&M.push({label:u[x],description:"",custom:!0});let P=(S.options||[]).map((j,A)=>_.has(A)?null:j?.label).filter(Boolean);pw(s,a,l,{...p,groupId:l.groupId||l.promptId,questionIndex:x,questionTotal:l.questionTotal??g.length,header:S.header||"",question:S.question||"",multiSelect:!!S.multiSelect,chosen:M,rejected:P})}return await ee({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:l.provider,promptId:l.promptId,...p}).catch(()=>{}),{ok:!0,promptId:l.promptId,sent:p.count}}let f=l.questions?.[0]||{},w=new Set(Array.isArray(n?.[0])?n[0]:[]),h=[...w].map(g=>f.options?.[g]).filter(Boolean).map(g=>({label:g.label,description:g.description||""}));u[0]&&h.push({label:u[0],description:"",custom:!0});let y=(f.options||[]).map((g,x)=>w.has(x)?null:g?.label).filter(Boolean),k=l.review?"review":/^claude:model-confirm:/.test(l.promptId||"")?"model-confirm":/^claude:resume-confirm:/.test(l.promptId||"")?"resume-confirm":l.setup==="continue"?"login-continue":void 0;return p={...p,groupId:l.groupId||l.promptId,questionIndex:l.questionIndex??0,questionTotal:l.questionTotal??1,header:f.header||"",question:f.question||"",multiSelect:!!f.multiSelect,chosen:h,rejected:y,...k?{control:k}:{}},await ee({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:l.provider,promptId:l.promptId,...p}).catch(()=>{}),pw(s,a,l,p),{ok:!0,promptId:l.promptId,sent:p.count}}async function Cq(e,t){if(!t)return null;let n=await K(e).catch(()=>[]);return wh(Hn(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function Ay(e,{promptId:t,questionIndex:n}={}){let r=fe(await ne(),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 Se(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await wS(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=bS(a,n);return c.length?(await Ke(r.leadBox,c,{kind:"navigate-prompt"}),await ee({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 Xp(e){let t=Ms.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},Ms.set(e,t)),t}function Pq(e){let t=Ms.get(e);return!!t&&(t.items.length>0||!!t.flushing)}function Cs(e){return(Ms.get(e)?.items??[]).map(({delivery:t,...n})=>({...n}))}function Ey(e=Date.now()){let t=0,n=0;for(let r of Ms.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 Dq(e,t,n){let r=t.filter(o=>o.delivery&&!o.delivery.settled);r.length&&(async()=>{let o=fe(await ne(),e)||null;for(let s of r)await In(o,s.delivery,`dropped:${n}`)})().catch(()=>{})}function kl(e,t="cancel"){let n=Ms.get(e);if(!n)return[];let r=n.items.splice(0);return n.idleSince=null,n.timer&&(clearInterval(n.timer),n.timer=null),Dq(e,r,t),r}async function _y(e){let t=kl(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=fe(await ne(),e);if(o)return r=ti(o,n),await ae(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function Iy(e){let t=Xp(e);t.timer||(t.timer=setInterval(()=>Bq(e).catch(()=>{}),Nq))}async function Bq(e){let t=Ms.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=fe(await ne(),e);if(!n||n.archivedAt){kl(e,"archived");return}let r=async(l,u="")=>{let d=[];for(let y of t.items)H_(y.delivery,l),u$(y,l)&&d.push(y);if(!d.length)return;t.items=t.items.filter(y=>!d.includes(y));let p=Date.now()-Math.min(...d.map(y=>y.heldSince||Date.now())),f=Math.max(1,Math.round(jg()/6e4)),w=String(u||"").split(`
229
229
  `).map(y=>y.trimEnd()).filter(y=>y.trim()).slice(-3).join(`
230
- `),h=l==="noSession"?`The scheduled prompt waited ${f} min for the box's session to come back and was dropped \u2014 open the terminal.`:`The scheduled prompt waited ${f} min for the box to become idle and was dropped \u2014 open the terminal.`;for(let y of d)y.delivery&&await In(n,y.delivery,l==="noSession"?"failed:not-running":"failed:blocked");Ee(n,"delivery-held",{box:n.leadBox,agent:o?.agent??null,reason:l,heldMs:p,producer:"loop",deliveryId:d[0]?.delivery?.id??null,message:h,...w?{detail:w}:{}}),await ae(),Ac(n,{provider:o?.agent??null,cls:"delivery-held",note:h}).catch(()=>{})},o=n.boxes.find(l=>l.name===n.leadBox),s=ii(e);if(s&&!s.finishedAt&&s.step!=="done"&&!s.error){Os(t,!1),await r("handoff");return}let a=await Se(n.leadBox);if(a&&await Wy(a)&&(a=await wl(n,o,"queue")?await Se(n.leadBox):null,await ae()),!a){Os(t,!1),await r("noSession");return}if(mo(o?.agent)){Os(t,!1),await r("cap");return}let i=await Ne(n.leadBox,{lines:ze}).catch(()=>"");if(uc(o?.agent,i)){Os(t,!1),await r("busy",i);return}if(oo(o?.agent,i)){let l=await Jt(n.leadBox).catch(()=>i);if(Sn(o,l)){Os(t,!1),await r("prompt");return}}if(!Os(t,!0)){await r("grace");return}let c=t.items.shift();t.idleSince=null,c.delivery&&(c.delivery.dequeuedAt=Date.now());try{await hy(n,o,a,c.text,c.kind??null,c.attachments??null,c.delivery??null)}catch(l){if(l?.code!=="cli-not-running")throw c.delivery&&await In(n,c.delivery,Ha(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 wl(n,o,"queue-gate")}await ae()}finally{t.flushing=!1}}}async function X$(e,t,n,r){let o=mo(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(ti(e,[n]),await ae()),JA(e.id,o))try{await N(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 Bq(e,t){let n=await Ne(e.leadBox,{lines:ze}).catch(()=>"");if(!oo(t?.agent,n))return!1;let r=await Jt(e.leadBox).catch(()=>n);return!!Sn(t,r)}async function hy(e,t,n,r,o=null,s=null,a=null){a||(a=qc({text:r,producer:Wc({kind:o}),kind:o,provider:t?.agent??null,attachments:Array.isArray(s)?s.length:0})),a.provider??=t?.agent??null,await X$(e,t,r,o);let i=pl.get(e.id)||0,c=r,l=!1,u=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(c=H$(r,e.pendingHandoffHydrate.artifact||Io),delete e.pendingHandoffHydrate,l=!0);let d=Array.isArray(s)?s.filter(h=>h&&h.rel):[];if(d.length){let h=l$(d.map(y=>y.rel));c=c.trim()?`${c.trim()}
230
+ `),h=l==="noSession"?`The scheduled prompt waited ${f} min for the box's session to come back and was dropped \u2014 open the terminal.`:`The scheduled prompt waited ${f} min for the box to become idle and was dropped \u2014 open the terminal.`;for(let y of d)y.delivery&&await In(n,y.delivery,l==="noSession"?"failed:not-running":"failed:blocked");Ee(n,"delivery-held",{box:n.leadBox,agent:o?.agent??null,reason:l,heldMs:p,producer:"loop",deliveryId:d[0]?.delivery?.id??null,message:h,...w?{detail:w}:{}}),await ae(),Tc(n,{provider:o?.agent??null,cls:"delivery-held",note:h}).catch(()=>{})},o=n.boxes.find(l=>l.name===n.leadBox),s=ii(e);if(s&&!s.finishedAt&&s.step!=="done"&&!s.error){Os(t,!1),await r("handoff");return}let a=await Se(n.leadBox);if(a&&await Wy(a)&&(a=await wl(n,o,"queue")?await Se(n.leadBox):null,await ae()),!a){Os(t,!1),await r("noSession");return}if(mo(o?.agent)){Os(t,!1),await r("cap");return}let i=await Ne(n.leadBox,{lines:ze}).catch(()=>"");if(uc(o?.agent,i)){Os(t,!1),await r("busy",i);return}if(oo(o?.agent,i)){let l=await Jt(n.leadBox).catch(()=>i);if(Sn(o,l)){Os(t,!1),await r("prompt");return}}if(!Os(t,!0)){await r("grace");return}let c=t.items.shift();t.idleSince=null,c.delivery&&(c.delivery.dequeuedAt=Date.now());try{await hy(n,o,a,c.text,c.kind??null,c.attachments??null,c.delivery??null)}catch(l){if(l?.code!=="cli-not-running")throw c.delivery&&await In(n,c.delivery,Ha(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 wl(n,o,"queue-gate")}await ae()}finally{t.flushing=!1}}}async function X$(e,t,n,r){let o=mo(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(ti(e,[n]),await ae()),JT(e.id,o))try{await N(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 Lq(e,t){let n=await Ne(e.leadBox,{lines:ze}).catch(()=>"");if(!oo(t?.agent,n))return!1;let r=await Jt(e.leadBox).catch(()=>n);return!!Sn(t,r)}async function hy(e,t,n,r,o=null,s=null,a=null){a||(a=qc({text:r,producer:Wc({kind:o}),kind:o,provider:t?.agent??null,attachments:Array.isArray(s)?s.length:0})),a.provider??=t?.agent??null,await X$(e,t,r,o);let i=pl.get(e.id)||0,c=r,l=!1,u=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(c=H$(r,e.pendingHandoffHydrate.artifact||Io),delete e.pendingHandoffHydrate,l=!0);let d=Array.isArray(s)?s.filter(h=>h&&h.rel):[];if(d.length){let h=l$(d.map(y=>y.rel));c=c.trim()?`${c.trim()}
231
231
 
232
- ${h}`:h}let p=Ee(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,deliveryId:a.id,...o?{kind:o}:{},...d.length?{attachments:d}:{}});o||ei(e,null);try{let h=Date.now(),y=null;try{y=await wr({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:Ps(n.agent),bailOnDialog:!0})}catch(g){throw Kc(a,{ms:Date.now()-h,outcome:g?.code==="cli-not-running"?"cli-not-running":"blocked"}),g}if(Kc(a,{ms:Date.now()-h,outcome:y||"up"}),(pl.get(e.id)||0)!==i){!o&&r.trim()&&(ti(e,[r]),await ae());let g=new Error("delivery stopped \u2014 the message was handed back as the draft");throw g.interrupted=!0,g}if(await Bq(e,t)){let g=Yp(e.id);a.requeued+=1,a.dequeuedAt=null;let x={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...d.length?{attachments:d}:{},delivery:a};g.items.unshift(x),Iy(e.id),await Gc(e,a,{position:1,reason:"prompt"});let S=new Error("lead is blocked on a prompt \u2014 message queued");throw S.requeued={id:x.id,position:g.items.length},S}let k=Un(t?.agent,c);a.paste=!!k.paste,await Qe(e.leadBox,c,{...k,kind:l?"lead-handoff-first-prompt":"say"})}catch(h){if(u&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=u),Ee(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 In(e,a,Ha(h)),h}let f={},w=await Qq(e,t,c,f);a.verify=f,w?await In(e,a,f.verdict==="unverified"?"unverified":"delivered"):(await Q$(e.leadBox,t?.agent,c.length+8,c).catch(()=>{}),Ee(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,reason:"unsubmitted"}),o||ti(e,[r]),await In(e,a,"unsubmitted")),l&&await ee({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function $y(e,{actions:t}={}){let n=Yp(e),r=ET(t),o=qc({text:r,producer:Wc({kind:"ship-notify"}),kind:"ship-notify"});n.items.push({id:o.id,text:r,ts:Date.now(),kind:"ship-notify",delivery:o}),Iy(e),(async()=>{let s=fe(await ne(),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 Lq(e,t,n,r){await Ke(e.leadBox,["Escape"],{kind:"dismiss-prompt"});let o="",s=!1;for(let c of[250,400,600,900]){if(await rr(c),o=await Ne(e.leadBox,{lines:ze}).catch(()=>""),!oo(t?.agent,o)){s=!0;break}let l=await Jt(e.leadBox).catch(()=>o);if(!Sn(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 ee({flow:"prompt",phase:"dismissed",sessionName:e.leadBox,agent:t?.agent,provider:n.provider,promptId:n.promptId,...i}).catch(()=>{}),s&&fT(e,t,n,i),{gone:s,pane:o}}async function qt(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"||!Ia(t))&&!a.length)throw new Error("text (string) or an attachment required");let i=fe(await ne(),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`);sf(i);let c=i.boxes.find(d=>d.name===i.leadBox),l=Ia(t),u=qc({text:l,producer:Wc({kind:n,producer:o}),kind:n,provider:c?.agent??null,attachments:a.length});try{return await jq(e,i,c,l,{kind:n,atts:a,d:u,dismissPrompt:s})}catch(d){throw await In(i,u,Ha(d)),d}}async function jq(e,t,n,r,{kind:o,atts:s,d:a,dismissPrompt:i=!1}){await X$(t,n,r,o),oi(e,"say");let c=await Se(t.leadBox);if(c&&await Wy(c)?await wl(t,n,"say")?(await ae(),c=await Se(t.leadBox)):c=null:!c&&await ai(t)&&(await ae(),c=await Se(t.leadBox)),!c)throw new Error(`lead box "${t.leadBox}" is not running`);let l=il.get(e);l&&await l.catch(()=>{});let u=Yp(e),d=await Ne(t.leadBox,{lines:ze}).catch(()=>""),p=u.items.length>0?"queue":uc(n?.agent,d)?"busy":null,f=p!=null,w=i&&!o;if((!f||p==="queue"&&w)&&oo(n?.agent,d)){let y=await Jt(t.leadBox).catch(()=>d),k=Sn(n,y);if(f||(f=!!k,f&&(p="prompt")),k&&w&&k.dismissable){let g=await Lq(t,n,k,a);g.gone&&p==="prompt"&&(d=g.pane,f=uc(n?.agent,d),p=f?"busy":null)}}if(f){let y={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...s.length?{attachments:s}:{},delivery:a};return u.items.push(y),Iy(e),o||ei(t,null),await ae(),await Gc(t,a,{position:u.items.length,reason:p}),{ok:!0,leadBox:t.leadBox,queued:!0,id:y.id,position:u.items.length,deliveryId:a.id}}let h;try{h=await hy(t,n,c,r,o,s,a)}catch(y){if(y?.code!=="cli-not-running"||!await wl(t,n,"say-gate")||(await ae(),c=await Se(t.leadBox),!c))throw y;h=await hy(t,n,c,r,o,s,a)}return await ae(),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 Ry(e,{hint:t}={}){let n=fe(await ne(),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=mg(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";Z_(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${P$}
232
+ ${h}`:h}let p=Ee(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,deliveryId:a.id,...o?{kind:o}:{},...d.length?{attachments:d}:{}});o||ei(e,null);try{let h=Date.now(),y=null;try{y=await wr({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:Ps(n.agent),bailOnDialog:!0})}catch(g){throw Kc(a,{ms:Date.now()-h,outcome:g?.code==="cli-not-running"?"cli-not-running":"blocked"}),g}if(Kc(a,{ms:Date.now()-h,outcome:y||"up"}),(pl.get(e.id)||0)!==i){!o&&r.trim()&&(ti(e,[r]),await ae());let g=new Error("delivery stopped \u2014 the message was handed back as the draft");throw g.interrupted=!0,g}if(await Lq(e,t)){let g=Xp(e.id);a.requeued+=1,a.dequeuedAt=null;let x={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...d.length?{attachments:d}:{},delivery:a};g.items.unshift(x),Iy(e.id),await Gc(e,a,{position:1,reason:"prompt"});let S=new Error("lead is blocked on a prompt \u2014 message queued");throw S.requeued={id:x.id,position:g.items.length},S}let k=Un(t?.agent,c);a.paste=!!k.paste,await Qe(e.leadBox,c,{...k,kind:l?"lead-handoff-first-prompt":"say"})}catch(h){if(u&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=u),Ee(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 In(e,a,Ha(h)),h}let f={},w=await e5(e,t,c,f);a.verify=f,w?await In(e,a,f.verdict==="unverified"?"unverified":"delivered"):(await Q$(e.leadBox,t?.agent,c.length+8,c).catch(()=>{}),Ee(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,reason:"unsubmitted"}),o||ti(e,[r]),await In(e,a,"unsubmitted")),l&&await ee({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function $y(e,{actions:t}={}){let n=Xp(e),r=EA(t),o=qc({text:r,producer:Wc({kind:"ship-notify"}),kind:"ship-notify"});n.items.push({id:o.id,text:r,ts:Date.now(),kind:"ship-notify",delivery:o}),Iy(e),(async()=>{let s=fe(await ne(),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 jq(e,t,n,r){await Ke(e.leadBox,["Escape"],{kind:"dismiss-prompt"});let o="",s=!1;for(let c of[250,400,600,900]){if(await rr(c),o=await Ne(e.leadBox,{lines:ze}).catch(()=>""),!oo(t?.agent,o)){s=!0;break}let l=await Jt(e.leadBox).catch(()=>o);if(!Sn(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 ee({flow:"prompt",phase:"dismissed",sessionName:e.leadBox,agent:t?.agent,provider:n.provider,promptId:n.promptId,...i}).catch(()=>{}),s&&fA(e,t,n,i),{gone:s,pane:o}}async function qt(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"||!Ia(t))&&!a.length)throw new Error("text (string) or an attachment required");let i=fe(await ne(),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`);af(i);let c=i.boxes.find(d=>d.name===i.leadBox),l=Ia(t),u=qc({text:l,producer:Wc({kind:n,producer:o}),kind:n,provider:c?.agent??null,attachments:a.length});try{return await Fq(e,i,c,l,{kind:n,atts:a,d:u,dismissPrompt:s})}catch(d){throw await In(i,u,Ha(d)),d}}async function Fq(e,t,n,r,{kind:o,atts:s,d:a,dismissPrompt:i=!1}){await X$(t,n,r,o),oi(e,"say");let c=await Se(t.leadBox);if(c&&await Wy(c)?await wl(t,n,"say")?(await ae(),c=await Se(t.leadBox)):c=null:!c&&await ai(t)&&(await ae(),c=await Se(t.leadBox)),!c)throw new Error(`lead box "${t.leadBox}" is not running`);let l=il.get(e);l&&await l.catch(()=>{});let u=Xp(e),d=await Ne(t.leadBox,{lines:ze}).catch(()=>""),p=u.items.length>0?"queue":uc(n?.agent,d)?"busy":null,f=p!=null,w=i&&!o;if((!f||p==="queue"&&w)&&oo(n?.agent,d)){let y=await Jt(t.leadBox).catch(()=>d),k=Sn(n,y);if(f||(f=!!k,f&&(p="prompt")),k&&w&&k.dismissable){let g=await jq(t,n,k,a);g.gone&&p==="prompt"&&(d=g.pane,f=uc(n?.agent,d),p=f?"busy":null)}}if(f){let y={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...s.length?{attachments:s}:{},delivery:a};return u.items.push(y),Iy(e),o||ei(t,null),await ae(),await Gc(t,a,{position:u.items.length,reason:p}),{ok:!0,leadBox:t.leadBox,queued:!0,id:y.id,position:u.items.length,deliveryId:a.id}}let h;try{h=await hy(t,n,c,r,o,s,a)}catch(y){if(y?.code!=="cli-not-running"||!await wl(t,n,"say-gate")||(await ae(),c=await Se(t.leadBox),!c))throw y;h=await hy(t,n,c,r,o,s,a)}return await ae(),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 Ry(e,{hint:t}={}){let n=fe(await ne(),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=mg(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";Z_(n.id,{name:s,box:n.leadBox});let a=String(t||"").trim()?`${P$}
233
233
 
234
- What to preview: ${String(t).trim()}`:P$;try{await qt(e,a,{kind:"spin-up-view"})}catch(i){throw xp(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Xp(e){let t=fe(await ne(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);pl.set(e,(pl.get(e)||0)+1);let n=kl(e,"interrupt"),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=Qa.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=ti(t,r),await ae()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=Gq(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,rr(Fq)]);let a=fe(await ne(),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 Z$(e){let t=Qa.get(e);return!!t&&!t.canceled}function oi(e,t){let n=Qa.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function Oy(e){oi(e,"track-ended"),pl.delete(e),kl(e,"track-ended")}function Gq(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}),Qa.set(e,r),(async()=>{let s=fe(await ne(),e),a=s?.boxes.find(y=>y.name===s.leadBox),i=s?await Se(s.leadBox):null,c=!1,l=!1;if(i){e:for(let y=0;y<Uq&&!r.canceled;y++){await Ke(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let k of Hq){await rr(k);let g=await Ne(s.leadBox,{lines:ze}).catch(()=>"");if(!ba(a?.agent,g)){c=!0;break e}}}if(!c){l=!0;for(let y=0;y<qq&&!r.canceled&&(await rr(Wq),!r.canceled);y++){let k=await Ne(s.leadBox,{lines:ze}).catch(()=>"");if(!ba(a?.agent,k)){c=!0;break}await Ke(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=fe(await ne(),e)||s,d=u?.boxes.find(y=>y.name===u.leadBox)||a,p=null,f=null;u&&d&&i&&c&&!r.canceled&&(p=await Jq(u,d).catch(()=>null),p||(f=await Zq(u,d).catch(()=>null)));let w=u&&i&&!r.canceled?await Vq(u).catch(()=>null):null,h=[p||f,...r.queuedTexts].filter(Boolean);u&&h.length&&(r.restored=ti(u,h),await ae()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await Kq(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 ee({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"),Qa.get(e)===r&&Qa.delete(e),o()}),r}async function Kq(e,t,n){await N(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function Vq(e){let t=qa(await K(e));if(!t?.offerId)return null;let n=t.offerType==="exists";return await N(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 Jq(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 zq){await rr(r);let o=await Ne(e.leadBox,{lines:ze}).catch(()=>""),s=fc(t.agent,o);if(s&&rd(n.text,s))return await Q$(e.leadBox,t.agent,n.text.length+8),Ee(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function Zq(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>Yq||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!He(r.text))return null;for(let s of Xq){await rr(s);let a;try{a=await Bh(t,{})}catch{return null}if(vv(a,r))return null;let i=await Ne(e.leadBox,{lines:ze}).catch(()=>"");if(fc(t.agent,i))return null}return Ee(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function Qq(e,t,n,r=null){return wc({sessionName:e.leadBox,agent:t?.agent,agentCmd:Ps(t?.agent),text:n,trackId:e.id,flow:"say",stats:r})}async function Q$(e,t,n,r=null){for(let o=0;o<3;o++){await da(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await rr(200);let s=await Ne(e,{lines:ze}).catch(()=>""),a=fc(t,s);if(!a||r&&!rd(r,a)&&!(t==="codex"&&ih(r,a)))return!0;n=a.length+8}return!1}function ei(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 ti(e,t){let n=[],r=o=>n.some(s=>He(s).includes(He(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?ei(e,n.join(`
234
+ What to preview: ${String(t).trim()}`:P$;try{await qt(e,a,{kind:"spin-up-view"})}catch(i){throw vp(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0}}async function Zp(e){let t=fe(await ne(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);pl.set(e,(pl.get(e)||0)+1);let n=kl(e,"interrupt"),r=n.filter(i=>i.text&&!i.kind).map(i=>i.text),o=Qa.get(e);if(o&&!o.canceled){o.clicks++;let i=null;return r.length&&(i=ti(t,r),await ae()),{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,restored:i,draftRev:t.draftRev||0}}let s=Kq(e,{droppedCount:n.length,droppedTexts:r});await Promise.race([s.settled,rr(Uq)]);let a=fe(await ne(),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 Z$(e){let t=Qa.get(e);return!!t&&!t.canceled}function oi(e,t){let n=Qa.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function Oy(e){oi(e,"track-ended"),pl.delete(e),kl(e,"track-ended")}function Kq(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}),Qa.set(e,r),(async()=>{let s=fe(await ne(),e),a=s?.boxes.find(y=>y.name===s.leadBox),i=s?await Se(s.leadBox):null,c=!1,l=!1;if(i){e:for(let y=0;y<Hq&&!r.canceled;y++){await Ke(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let k of Wq){await rr(k);let g=await Ne(s.leadBox,{lines:ze}).catch(()=>"");if(!ba(a?.agent,g)){c=!0;break e}}}if(!c){l=!0;for(let y=0;y<Gq&&!r.canceled&&(await rr(qq),!r.canceled);y++){let k=await Ne(s.leadBox,{lines:ze}).catch(()=>"");if(!ba(a?.agent,k)){c=!0;break}await Ke(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let u=fe(await ne(),e)||s,d=u?.boxes.find(y=>y.name===u.leadBox)||a,p=null,f=null;u&&d&&i&&c&&!r.canceled&&(p=await Yq(u,d).catch(()=>null),p||(f=await Qq(u,d).catch(()=>null)));let w=u&&i&&!r.canceled?await zq(u).catch(()=>null):null,h=[p||f,...r.queuedTexts].filter(Boolean);u&&h.length&&(r.restored=ti(u,h),await ae()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await Vq(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 ee({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"),Qa.get(e)===r&&Qa.delete(e),o()}),r}async function Vq(e,t,n){await N(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function zq(e){let t=qa(await K(e));if(!t?.offerId)return null;let n=t.offerType==="exists";return await N(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 Yq(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 Jq){await rr(r);let o=await Ne(e.leadBox,{lines:ze}).catch(()=>""),s=fc(t.agent,o);if(s&&od(n.text,s))return await Q$(e.leadBox,t.agent,n.text.length+8),Ee(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function Qq(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>Xq||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!He(r.text))return null;for(let s of Zq){await rr(s);let a;try{a=await Bh(t,{})}catch{return null}if(vv(a,r))return null;let i=await Ne(e.leadBox,{lines:ze}).catch(()=>"");if(fc(t.agent,i))return null}return Ee(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function e5(e,t,n,r=null){return wc({sessionName:e.leadBox,agent:t?.agent,agentCmd:Ps(t?.agent),text:n,trackId:e.id,flow:"say",stats:r})}async function Q$(e,t,n,r=null){for(let o=0;o<3;o++){await da(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await rr(200);let s=await Ne(e,{lines:ze}).catch(()=>""),a=fc(t,s);if(!a||r&&!od(r,a)&&!(t==="codex"&&ih(r,a)))return!0;n=a.length+8}return!1}function ei(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 ti(e,t){let n=[],r=o=>n.some(s=>He(s).includes(He(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?ei(e,n.join(`
235
235
 
236
- `),{source:"restore"})?.text??null:null}function t5(e,t){let n=He(t);if(!n)return!1;if(Cs(e.id).some(o=>He(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>e5)break;if(!(s.type!=="said"||!s.text||He(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function My(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=fe(await ne(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=Ia(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&t5(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;He(o).includes(He(i))?ei(r,o):ei(r,`${i}
236
+ `),{source:"restore"})?.text??null:null}function n5(e,t){let n=He(t);if(!n)return!1;if(Cs(e.id).some(o=>He(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>t5)break;if(!(s.type!=="said"||!s.text||He(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function My(e,t,{rev:n=null}={}){if(typeof t!="string")throw new Error("text (string) required");let r=fe(await ne(),e);if(!r)throw new Error(`track "${e}" not found`);let o=t,s=Ia(t);if(typeof n=="number"&&n<(r.draftRev||0)&&s&&n5(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;He(o).includes(He(i))?ei(r,o):ei(r,`${i}
237
237
 
238
- ${o}`,{source:"restore"})}else ei(r,o);return await ae(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function Cy(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=fe(await ne(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await Se(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=sT(a,n),l=[...r.events||[]].reverse().find(d=>d.type==="model-change")?.to??null;l||(l=(await nc(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await wr({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:Ps(o.agent)});let u=await aT(a,r.leadBox,i);return Ee(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await ae(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function eR(e){for(let t of e){if(!t||!await $a(t))continue;let n=await LA(t).catch(()=>null);if(!n)continue;if((await Y.stat(z.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function Gt(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 _s(e){let t=[];for(let n of Gt(e?.workspace)){if(!n?.dir)continue;let r=await ps(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await fs(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function Ny(e){let t=e;typeof t=="string"&&!z.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await ea(t)??await ku(t));let n=await eR([t]);if(!n){let r=typeof e=="string"&&z.isAbsolute(e)&&!await Y.stat(e).catch(()=>null);throw new Error(`tagged repo "${e}" is not a usable base (${r?"that path does not exist on this node \u2014 pick one of this node's repos or use owner/name":"need a primary checkout or a synced owner/name"})`)}return n}async function n5(e,t,n,r){let o=`track/${lf(t)}-${e}`,s=[];try{await Y.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await Ny(i);if(s.some(f=>f.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await Me(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 hs(c);await ms(c,d,o,p),s.push({name:u,dir:d,base:c,baseRef:p,repo:l})}return await si(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await $t(i.base,i.dir).catch(()=>{});throw await Y.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function Zp(e,t){let n=await ne(),r=fe(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 Ny(typeof t=="string"?t.trim():t);if((o.repos??[]).some(p=>p?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await Me(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 hs(s);await nw(s,o.branch)?await Ec(s,l,o.branch):await ms(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 si(o.dir,o.repos,o.branch),Ee(r,"retagged",{action:"add",repo:a??s,name:c,workspace:Py(o)}),await ae(),d}async function Qp(e,t){let n=await ne(),r=fe(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 Wt.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 ps(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await fs(s.dir,s.baseRef).catch(()=>0);if(a||i>0)throw new Error(`"${s.name}" has work (${a?"uncommitted changes":`${i} commit${i===1?"":"s"} ahead of ${s.baseRef??"base"}`}) \u2014 ship or discard it first`);return await $t(s.base,s.dir).catch(()=>{}),await Y.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await si(o.dir,o.repos,o.branch),Ee(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:Py(o)}),await ae(),{removed:s.name}}async function jp(e,t){let n=await ne(),r=fe(n,e);r&&(r.reshape={...r.reshape||{},...t},await ae())}async function r5(e){let t=await Y.readdir(e).catch(()=>[]);for(let n of t)if(!(n===".git"||n===".bostrat")){if(n==="AGENTS.md"){let r=await Y.readFile(z.join(e,n),"utf8").catch(()=>"");if(ll(r))continue}return!0}try{let{stdout:n}=await qp("git",["-C",e,"rev-list","--count","HEAD"]);if(Number(n.trim())>1)return!0}catch{}return!1}function D$(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 tR(e,{added:t=[]}={}){let{shape:n,dir:r,staging:o,sub:s,base:a,scratch:i}=e;for(let l of t)await $t(l.base,l.dir).catch(()=>{});let c=async(l,u)=>{await On(l)&&!await On(u)&&await Y.rename(l,u)};if(n==="worktree"&&s){let l=z.join(r,s);await On(l)&&(await c(z.join(r,".bostrat"),z.join(l,".bostrat")),await Fp(a,l,o))}if(n==="repo"&&i){let l=z.join(r,i);await On(l)&&(await On(o)&&await Y.rm(o,{recursive:!0,force:!0}),await Y.rename(l,o))}return await On(o)?(await On(r)&&(await c(z.join(r,".bostrat"),z.join(o,".bostrat")),await Y.rm(r,{recursive:!0,force:!0})),n==="worktree"?await Fp(a,o,r):await Y.rename(o,r),!0):!1}async function Dy(e,t,{skipPermissions:n=!0}={}){let r=await ne(),o=fe(r,e);if(!o)throw St(`track "${e}" not found`,404);if(o.archivedAt)throw St("track is archived \u2014 unarchive it first");try{sf(o)}catch(y){throw Object.assign(y,{status:409})}if(o.kind==="setup")throw St("setup boxes have no repos to reshape");if(String(o.name||"").startsWith("\u21BB"))throw St("this Track's repos are the loop's \u2014 propose-update the loop instead");let s=wy.get(e);if(s&&!s.finishedAt)throw St("a reshape is already running for this Track");let a=Ns.get(e);if(a&&!a.finishedAt)throw St("a lead handoff is running \u2014 retry when it settles");let i=Hp.get(e);if(i&&!i.finishedAt)throw St("a node transfer is running \u2014 retry when it settles");if(Bp.has(e))throw St("an adopt is running for this Track \u2014 retry when it settles");for(let y of Wt.values())if(y.trackId===e&&!y.finishedAt)throw St("a subtask is still running on this Track \u2014 wait for it to merge back before reshaping");let c=(Array.isArray(t)?t:[]).map(y=>typeof y=="string"?y.trim():"").filter(Boolean);if(!c.length)throw St("repos (non-empty list of paths or owner/name slugs) required",400);let l=[];for(let y of c){let k;try{k=await Ny(y)}catch(g){throw St(g?.message||String(g),400)}if(l.some(g=>g.base===k))throw St(`repo tagged twice: ${y}`,400);l.push({sel:y,base:k,slug:await Me(k).catch(()=>null)})}let u=o.workspace;if(u?.kind==="multi"){let y=(u.repos??[]).filter(Boolean),k=y.filter(S=>!l.some(_=>_.base===S.base)),g=l.filter(S=>!y.some(_=>_.base===S.base));if(!k.length&&!g.length)return{trackId:e,step:"done",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:Date.now(),error:null};for(let S of k){let _=await ps(S.dir,{ignorePlumbing:!0}).catch(()=>!1),M=await fs(S.dir,S.baseRef).catch(()=>0);if(_||M>0)throw St(`"${S.name}" has work \u2014 ship or discard it before dropping it`)}let x={trackId:e,step:"retag",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:null,error:null};for(let S of g){let _=await Zp(e,S.base);x.added.push(_.repo??_.base)}for(let S of k)await Qp(e,S.name),x.removed.push(S.repo??S.base);return x.step="done",x.finishedAt=Date.now(),x}if(u?.kind!=="worktree"&&u?.kind!=="repo")throw St(`can't reshape a "${u?.kind??"unknown"}" workspace`);let d=u.kind==="worktree"&&l.some(y=>y.base===u.base);if(u.kind==="worktree"&&!d){let y=await ps(u.dir??o.cwd,{ignorePlumbing:!0}).catch(()=>!1),k=await fs(u.dir??o.cwd,u.baseRef).catch(()=>0);if(y||k>0)throw St(`"${z.basename(u.base)}" has work (${y?"uncommitted changes":`${k} commit${k===1?"":"s"} ahead of ${u.baseRef??"base"}`}) \u2014 ship or discard it before swapping it out`)}oi(e,"reshape");let p=o.boxes.find(y=>y.name===o.leadBox)||null;if(!p)throw St("this Track has no lead box");let f=p.agent||"claude",w=await ri(f,n),h={trackId:e,step:"checkpoint",inPlace:!1,startedAt:Date.now(),finishedAt:null,error:null,added:l.filter(y=>!(u.kind==="worktree"&&y.base===u.base)).map(y=>y.slug??y.base),removed:u.kind==="worktree"&&!d?[u.repo??u.base]:[],scratch:!1,views:0,checkpoint:null};return wy.set(e,h),await jp(e,{step:h.step,startedAt:h.startedAt,finishedAt:null,error:null,added:h.added,removed:h.removed,layout:null}),o5(h,o,{desired:l,keep:d,lead:p,agent:f,agentCmd:w,skipPermissions:n}).catch(async y=>{h.error=y?.message||String(y),h.finishedAt=Date.now(),console.error(`[reshape ${e}] FAILED at step "${h.step}": ${h.error}`),await jp(e,{step:h.step,error:h.error,finishedAt:h.finishedAt}).catch(()=>{})}),h}async function o5(e,t,{desired:n,keep:r,lead:o,agent:s,agentCmd:a,skipPermissions:i}){let c=e.trackId,l=t.workspace,u=t.cwd,d=async(A,C={})=>{e.step=A,console.log(`[reshape ${c}] step \u2192 ${A}`),await jp(c,{step:A,...C})},p=await Se(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(mo(s))e.checkpoint="skipped-capped";else try{await Sd(o.name,{timeoutMs:by,quiesce:{box:o,reason:"reshape",onWait:()=>d("await-turn"),onResume:()=>d("checkpoint")}})}catch{e.checkpoint="reconstructed"}let h=null;e.checkpoint!=="llm"&&(h=await Ad(c,u,{trackName:t.name||c}).catch(()=>null)),await d("quiesce"),e.views=await kg(c).catch(()=>0),await $u(u).catch(()=>{}),p&&(await Vh(o.name,{fromAgent:s}).catch(()=>{}),await Lt(o.name).catch(()=>{}));let y=`${u}.reshape-${Date.now()}`,k=new Set([".bostrat"]),g={shape:l.kind,dir:u,staging:y,base:l.kind==="worktree"?l.base:null,sub:l.kind==="worktree"&&r?D$(l.base,l.repo??null,k):null,scratch:null},x=l.branch||`track/${lf(t.name||c)}-${c}`,S=[],_=[],M=null;try{if(await d("move",{layout:g}),l.kind==="worktree")if(await Fp(l.base,u,y),await Y.mkdir(u,{recursive:!0}),r){let C=z.join(u,g.sub);await Fp(l.base,y,C),await On(z.join(C,".bostrat"))&&await Y.rename(z.join(C,".bostrat"),z.join(u,".bostrat"));let W=z.join(C,"AGENTS.md");ll(await Y.readFile(W,"utf8").catch(()=>null))&&(await Y.rm(W,{force:!0}).catch(()=>{}),await oR(C,"/AGENTS.md").catch(()=>{})),S.push({name:g.sub,dir:C,base:l.base,baseRef:l.baseRef??null,repo:l.repo??null})}else await On(z.join(y,".bostrat"))&&await Y.rename(z.join(y,".bostrat"),z.join(u,".bostrat"));else await Y.rename(u,y),await Y.mkdir(u,{recursive:!0}),await On(z.join(y,".bostrat"))&&await Y.rename(z.join(y,".bostrat"),z.join(u,".bostrat"));await d("materialize");for(let C of n){if(l.kind==="worktree"&&C.base===l.base)continue;let W=D$(C.base,C.slug,k),B=z.join(u,W),Z=await hs(C.base);await nw(C.base,x)?await Ec(C.base,B,x):await ms(C.base,B,x,Z);let xe={name:W,dir:B,base:C.base,baseRef:Z,repo:C.slug};S.push(xe),_.push(xe)}if(l.kind==="repo"&&await r5(y)){let C="scratch";for(let W=2;k.has(C);W++)C=`scratch-${W}`;k.add(C),g.scratch=C,await jp(c,{layout:g}),await Y.rename(y,z.join(u,C)),e.scratch=!0}await si(u,S,x,{scratch:g.scratch}),await d("relaunch"),M=await jn(o.name,u,{agentCmd:a,agent:s}),await wr({cwd:u,sessionName:o.name,agent:s,agentCmd:Ps(s)}).catch(C=>{if(C?.code!=="cli-not-running")throw C});let A=await Ne(o.name,{lines:ze}).catch(()=>"");if(!to(s,A))throw new Error(`relaunched ${s} CLI never drew its composer in the hub`)}catch(A){await d("rollback",{error:A?.message||String(A)}),await Lt(o.name).catch(()=>{}),await tR(g,{added:_}).catch(Z=>{console.error(`[reshape ${c}] rollback move failed: ${Z?.message||Z}`)});let C=await ne(),W=fe(C,c),B=W?.boxes.find(Z=>Z.name===o.name)||null;try{let Z=Kp(s,f,{skipPermissions:i,cwd:u,peerName:o.name}),xe=await jn(o.name,u,{agentCmd:Z,agent:s,resumeSessionId:f,pinned:w});B&&(B.hookTokenHash=Ho(xe.hookToken),B.state="live"),rs({cwd:u,sessionName:o.name,agent:s,agentCmd:Z})}catch(Z){console.error(`[reshape ${c}] rollback relaunch failed: ${Z?.message||Z}`)}throw W&&(Ee(W,"retag-failed",{action:"reshape",box:o.name,agent:s,reason:A?.message||String(A),rolledBack:!0}),W.reshape={...W.reshape||{},step:"error",error:A?.message||String(A),finishedAt:Date.now(),recovered:"rolled-back"},await ae()),e.step="error",e.recovered="rolled-back",e.error=A?.message||String(A),e.finishedAt=Date.now(),A}await d("commit");let P=await ne(),j=fe(P,c);if(!j)throw new Error(`track "${c}" vanished mid-reshape`);let T=j.boxes.find(A=>A.name===o.name);if(!T)throw new Error(`lead box row "${o.name}" missing during reshape commit`);let $=Date.now(),L=_o(T),H=L[L.length-1];H.endedAt==null&&(H.endedAt=$),H.endReason==null&&(H.endReason="reshape");let R=await ds({agent:s,agentCmd:a});L.push({agent:s,sessionId:M.sessionId,pinned:M.pinned===!0,cliVersion:R,startedAt:$,endedAt:null}),T.cwd=u,T.agent=s,T.cliVersion=R,T.sessionId=M.sessionId,T.pinned=M.pinned===!0,T.hookTokenHash=Ho(M.hookToken),T.state="live",T.role="lead",delete T.readyAt,j.cwd=u,j.workspace={dir:u,kind:"multi",branch:x,repos:S},j.pendingHandoffHydrate={artifact:h||Io,at:$},Ee(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:M.sessionId,epoch:L.length-1,workspace:Py(j.workspace)}),j.reshape={...j.reshape||{},step:"done",finishedAt:$,error:null,checkpoint:e.checkpoint,scratch:e.scratch,views:e.views,layout:null},await ae(),rs({cwd:u,sessionName:o.name,agent:s,agentCmd:a,onReady:async()=>{T.readyAt||(T.readyAt=Date.now(),await ae())}}),await On(y)&&(l.kind==="worktree"&&await $t(l.base,y).catch(()=>{}),await Y.rm(y,{recursive:!0,force:!0}).catch(()=>{})),e.step="done",e.finishedAt=$}async function By(){let e=await ne(),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 Lt(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 Y.readdir(c).catch(()=>[])){if(d.has(f))continue;let w=z.join(c,f),h=await Y.readFile(z.join(w,".git"),"utf8").catch(()=>null),y=h&&/^gitdir:\s*(.+?)\/\.git\/worktrees\//m.exec(h);y&&p.push({base:y[1],dir:w})}s=await tR(r.layout,{added:p})}catch(c){a=c?.message||String(c),console.error(`[reshape ${n.id}] boot rollback failed: ${a}`)}o&&!jr.has(o.state)&&(o.state="stopped");let i=`interrupted by a node restart during "${r.step}"${s?" \u2014 moved back":""}${a?` (${a})`:""}`;Ee(n,"retag-failed",{action:"reshape",box:n.leadBox,agent:o?.agent??null,reason:i,rolledBack:!a,recovered:!0}),n.reshape={...r,step:"error",error:i,finishedAt:Date.now(),recovered:a?"rollback-failed":"rolled-back",layout:null}}return t&&await ae(),t}async function s5(e,t,{repo:n,repos:r,cwd:o}={}){await Y.mkdir(ul,{recursive:!0});let s=z.join(ul,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return n5(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!z.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await ea(n)??await ku(n));let i=await eR([n,o,pq]);if(i){let c=`track/${lf(t)}-${e}`;try{let l=await hs(i);await ms(i,s,c,l),await ml(s);let u=await Me(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await Y.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await Y.mkdir(s,{recursive:!0}),await rw(s),await ml(s),{dir:s,base:null,branch:null,kind:"repo"}}async function ml(e){try{await Y.writeFile(z.join(e,"AGENTS.md"),cl,{flag:"wx"})}catch{return}await l5(e,["/AGENTS.md"])}function c5(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(`
238
+ ${o}`,{source:"restore"})}else ei(r,o);return await ae(),{ok:!0,draft:r.draft||null,rev:r.draftRev||0}}async function Cy(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=fe(await ne(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await Se(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=sA(a,n),l=[...r.events||[]].reverse().find(d=>d.type==="model-change")?.to??null;l||(l=(await nc(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await wr({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:Ps(o.agent)});let u=await aA(a,r.leadBox,i);return Ee(r,"model-change",{to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified}),await ae(),{ok:!0,requested:n,leadBox:r.leadBox,...u}}async function eR(e){for(let t of e){if(!t||!await $a(t))continue;let n=await LT(t).catch(()=>null);if(!n)continue;if((await Y.stat(z.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function Gt(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 _s(e){let t=[];for(let n of Gt(e?.workspace)){if(!n?.dir)continue;let r=await ps(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await fs(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function Ny(e){let t=e;typeof t=="string"&&!z.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await ea(t)??await ku(t));let n=await eR([t]);if(!n){let r=typeof e=="string"&&z.isAbsolute(e)&&!await Y.stat(e).catch(()=>null);throw new Error(`tagged repo "${e}" is not a usable base (${r?"that path does not exist on this node \u2014 pick one of this node's repos or use owner/name":"need a primary checkout or a synced owner/name"})`)}return n}async function r5(e,t,n,r){let o=`track/${uf(t)}-${e}`,s=[];try{await Y.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await Ny(i);if(s.some(f=>f.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await Me(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 hs(c);await ms(c,d,o,p),s.push({name:u,dir:d,base:c,baseRef:p,repo:l})}return await si(n,s,o),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await $t(i.base,i.dir).catch(()=>{});throw await Y.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function Qp(e,t){let n=await ne(),r=fe(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 Ny(typeof t=="string"?t.trim():t);if((o.repos??[]).some(p=>p?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await Me(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 hs(s);await nw(s,o.branch)?await Ec(s,l,o.branch):await ms(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 si(o.dir,o.repos,o.branch),Ee(r,"retagged",{action:"add",repo:a??s,name:c,workspace:Py(o)}),await ae(),d}async function ef(e,t){let n=await ne(),r=fe(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 Wt.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 ps(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await fs(s.dir,s.baseRef).catch(()=>0);if(a||i>0)throw new Error(`"${s.name}" has work (${a?"uncommitted changes":`${i} commit${i===1?"":"s"} ahead of ${s.baseRef??"base"}`}) \u2014 ship or discard it first`);return await $t(s.base,s.dir).catch(()=>{}),await Y.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await si(o.dir,o.repos,o.branch),Ee(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:Py(o)}),await ae(),{removed:s.name}}async function Fp(e,t){let n=await ne(),r=fe(n,e);r&&(r.reshape={...r.reshape||{},...t},await ae())}async function o5(e){let t=await Y.readdir(e).catch(()=>[]);for(let n of t)if(!(n===".git"||n===".bostrat")){if(n==="AGENTS.md"){let r=await Y.readFile(z.join(e,n),"utf8").catch(()=>"");if(ll(r))continue}return!0}try{let{stdout:n}=await Gp("git",["-C",e,"rev-list","--count","HEAD"]);if(Number(n.trim())>1)return!0}catch{}return!1}function D$(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 tR(e,{added:t=[]}={}){let{shape:n,dir:r,staging:o,sub:s,base:a,scratch:i}=e;for(let l of t)await $t(l.base,l.dir).catch(()=>{});let c=async(l,u)=>{await On(l)&&!await On(u)&&await Y.rename(l,u)};if(n==="worktree"&&s){let l=z.join(r,s);await On(l)&&(await c(z.join(r,".bostrat"),z.join(l,".bostrat")),await Up(a,l,o))}if(n==="repo"&&i){let l=z.join(r,i);await On(l)&&(await On(o)&&await Y.rm(o,{recursive:!0,force:!0}),await Y.rename(l,o))}return await On(o)?(await On(r)&&(await c(z.join(r,".bostrat"),z.join(o,".bostrat")),await Y.rm(r,{recursive:!0,force:!0})),n==="worktree"?await Up(a,o,r):await Y.rename(o,r),!0):!1}async function Dy(e,t,{skipPermissions:n=!0}={}){let r=await ne(),o=fe(r,e);if(!o)throw St(`track "${e}" not found`,404);if(o.archivedAt)throw St("track is archived \u2014 unarchive it first");try{af(o)}catch(y){throw Object.assign(y,{status:409})}if(o.kind==="setup")throw St("setup boxes have no repos to reshape");if(String(o.name||"").startsWith("\u21BB"))throw St("this Track's repos are the loop's \u2014 propose-update the loop instead");let s=wy.get(e);if(s&&!s.finishedAt)throw St("a reshape is already running for this Track");let a=Ns.get(e);if(a&&!a.finishedAt)throw St("a lead handoff is running \u2014 retry when it settles");let i=Wp.get(e);if(i&&!i.finishedAt)throw St("a node transfer is running \u2014 retry when it settles");if(Lp.has(e))throw St("an adopt is running for this Track \u2014 retry when it settles");for(let y of Wt.values())if(y.trackId===e&&!y.finishedAt)throw St("a subtask is still running on this Track \u2014 wait for it to merge back before reshaping");let c=(Array.isArray(t)?t:[]).map(y=>typeof y=="string"?y.trim():"").filter(Boolean);if(!c.length)throw St("repos (non-empty list of paths or owner/name slugs) required",400);let l=[];for(let y of c){let k;try{k=await Ny(y)}catch(g){throw St(g?.message||String(g),400)}if(l.some(g=>g.base===k))throw St(`repo tagged twice: ${y}`,400);l.push({sel:y,base:k,slug:await Me(k).catch(()=>null)})}let u=o.workspace;if(u?.kind==="multi"){let y=(u.repos??[]).filter(Boolean),k=y.filter(S=>!l.some(_=>_.base===S.base)),g=l.filter(S=>!y.some(_=>_.base===S.base));if(!k.length&&!g.length)return{trackId:e,step:"done",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:Date.now(),error:null};for(let S of k){let _=await ps(S.dir,{ignorePlumbing:!0}).catch(()=>!1),M=await fs(S.dir,S.baseRef).catch(()=>0);if(_||M>0)throw St(`"${S.name}" has work \u2014 ship or discard it before dropping it`)}let x={trackId:e,step:"retag",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:null,error:null};for(let S of g){let _=await Qp(e,S.base);x.added.push(_.repo??_.base)}for(let S of k)await ef(e,S.name),x.removed.push(S.repo??S.base);return x.step="done",x.finishedAt=Date.now(),x}if(u?.kind!=="worktree"&&u?.kind!=="repo")throw St(`can't reshape a "${u?.kind??"unknown"}" workspace`);let d=u.kind==="worktree"&&l.some(y=>y.base===u.base);if(u.kind==="worktree"&&!d){let y=await ps(u.dir??o.cwd,{ignorePlumbing:!0}).catch(()=>!1),k=await fs(u.dir??o.cwd,u.baseRef).catch(()=>0);if(y||k>0)throw St(`"${z.basename(u.base)}" has work (${y?"uncommitted changes":`${k} commit${k===1?"":"s"} ahead of ${u.baseRef??"base"}`}) \u2014 ship or discard it before swapping it out`)}oi(e,"reshape");let p=o.boxes.find(y=>y.name===o.leadBox)||null;if(!p)throw St("this Track has no lead box");let f=p.agent||"claude",w=await ri(f,n),h={trackId:e,step:"checkpoint",inPlace:!1,startedAt:Date.now(),finishedAt:null,error:null,added:l.filter(y=>!(u.kind==="worktree"&&y.base===u.base)).map(y=>y.slug??y.base),removed:u.kind==="worktree"&&!d?[u.repo??u.base]:[],scratch:!1,views:0,checkpoint:null};return wy.set(e,h),await Fp(e,{step:h.step,startedAt:h.startedAt,finishedAt:null,error:null,added:h.added,removed:h.removed,layout:null}),s5(h,o,{desired:l,keep:d,lead:p,agent:f,agentCmd:w,skipPermissions:n}).catch(async y=>{h.error=y?.message||String(y),h.finishedAt=Date.now(),console.error(`[reshape ${e}] FAILED at step "${h.step}": ${h.error}`),await Fp(e,{step:h.step,error:h.error,finishedAt:h.finishedAt}).catch(()=>{})}),h}async function s5(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(T,C={})=>{e.step=T,console.log(`[reshape ${c}] step \u2192 ${T}`),await Fp(c,{step:T,...C})},p=await Se(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(mo(s))e.checkpoint="skipped-capped";else try{await Td(o.name,{timeoutMs:by,quiesce:{box:o,reason:"reshape",onWait:()=>d("await-turn"),onResume:()=>d("checkpoint")}})}catch{e.checkpoint="reconstructed"}let h=null;e.checkpoint!=="llm"&&(h=await Ad(c,u,{trackName:t.name||c}).catch(()=>null)),await d("quiesce"),e.views=await kg(c).catch(()=>0),await $u(u).catch(()=>{}),p&&(await Vh(o.name,{fromAgent:s}).catch(()=>{}),await Lt(o.name).catch(()=>{}));let y=`${u}.reshape-${Date.now()}`,k=new Set([".bostrat"]),g={shape:l.kind,dir:u,staging:y,base:l.kind==="worktree"?l.base:null,sub:l.kind==="worktree"&&r?D$(l.base,l.repo??null,k):null,scratch:null},x=l.branch||`track/${uf(t.name||c)}-${c}`,S=[],_=[],M=null;try{if(await d("move",{layout:g}),l.kind==="worktree")if(await Up(l.base,u,y),await Y.mkdir(u,{recursive:!0}),r){let C=z.join(u,g.sub);await Up(l.base,y,C),await On(z.join(C,".bostrat"))&&await Y.rename(z.join(C,".bostrat"),z.join(u,".bostrat"));let W=z.join(C,"AGENTS.md");ll(await Y.readFile(W,"utf8").catch(()=>null))&&(await Y.rm(W,{force:!0}).catch(()=>{}),await oR(C,"/AGENTS.md").catch(()=>{})),S.push({name:g.sub,dir:C,base:l.base,baseRef:l.baseRef??null,repo:l.repo??null})}else await On(z.join(y,".bostrat"))&&await Y.rename(z.join(y,".bostrat"),z.join(u,".bostrat"));else await Y.rename(u,y),await Y.mkdir(u,{recursive:!0}),await On(z.join(y,".bostrat"))&&await Y.rename(z.join(y,".bostrat"),z.join(u,".bostrat"));await d("materialize");for(let C of n){if(l.kind==="worktree"&&C.base===l.base)continue;let W=D$(C.base,C.slug,k),B=z.join(u,W),Z=await hs(C.base);await nw(C.base,x)?await Ec(C.base,B,x):await ms(C.base,B,x,Z);let xe={name:W,dir:B,base:C.base,baseRef:Z,repo:C.slug};S.push(xe),_.push(xe)}if(l.kind==="repo"&&await o5(y)){let C="scratch";for(let W=2;k.has(C);W++)C=`scratch-${W}`;k.add(C),g.scratch=C,await Fp(c,{layout:g}),await Y.rename(y,z.join(u,C)),e.scratch=!0}await si(u,S,x,{scratch:g.scratch}),await d("relaunch"),M=await jn(o.name,u,{agentCmd:a,agent:s}),await wr({cwd:u,sessionName:o.name,agent:s,agentCmd:Ps(s)}).catch(C=>{if(C?.code!=="cli-not-running")throw C});let T=await Ne(o.name,{lines:ze}).catch(()=>"");if(!to(s,T))throw new Error(`relaunched ${s} CLI never drew its composer in the hub`)}catch(T){await d("rollback",{error:T?.message||String(T)}),await Lt(o.name).catch(()=>{}),await tR(g,{added:_}).catch(Z=>{console.error(`[reshape ${c}] rollback move failed: ${Z?.message||Z}`)});let C=await ne(),W=fe(C,c),B=W?.boxes.find(Z=>Z.name===o.name)||null;try{let Z=Vp(s,f,{skipPermissions:i,cwd:u,peerName:o.name}),xe=await jn(o.name,u,{agentCmd:Z,agent:s,resumeSessionId:f,pinned:w});B&&(B.hookTokenHash=Ho(xe.hookToken),B.state="live"),rs({cwd:u,sessionName:o.name,agent:s,agentCmd:Z})}catch(Z){console.error(`[reshape ${c}] rollback relaunch failed: ${Z?.message||Z}`)}throw W&&(Ee(W,"retag-failed",{action:"reshape",box:o.name,agent:s,reason:T?.message||String(T),rolledBack:!0}),W.reshape={...W.reshape||{},step:"error",error:T?.message||String(T),finishedAt:Date.now(),recovered:"rolled-back"},await ae()),e.step="error",e.recovered="rolled-back",e.error=T?.message||String(T),e.finishedAt=Date.now(),T}await d("commit");let P=await ne(),j=fe(P,c);if(!j)throw new Error(`track "${c}" vanished mid-reshape`);let A=j.boxes.find(T=>T.name===o.name);if(!A)throw new Error(`lead box row "${o.name}" missing during reshape commit`);let $=Date.now(),L=_o(A),H=L[L.length-1];H.endedAt==null&&(H.endedAt=$),H.endReason==null&&(H.endReason="reshape");let R=await ds({agent:s,agentCmd:a});L.push({agent:s,sessionId:M.sessionId,pinned:M.pinned===!0,cliVersion:R,startedAt:$,endedAt:null}),A.cwd=u,A.agent=s,A.cliVersion=R,A.sessionId=M.sessionId,A.pinned=M.pinned===!0,A.hookTokenHash=Ho(M.hookToken),A.state="live",A.role="lead",delete A.readyAt,j.cwd=u,j.workspace={dir:u,kind:"multi",branch:x,repos:S},j.pendingHandoffHydrate={artifact:h||Io,at:$},Ee(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:M.sessionId,epoch:L.length-1,workspace:Py(j.workspace)}),j.reshape={...j.reshape||{},step:"done",finishedAt:$,error:null,checkpoint:e.checkpoint,scratch:e.scratch,views:e.views,layout:null},await ae(),rs({cwd:u,sessionName:o.name,agent:s,agentCmd:a,onReady:async()=>{A.readyAt||(A.readyAt=Date.now(),await ae())}}),await On(y)&&(l.kind==="worktree"&&await $t(l.base,y).catch(()=>{}),await Y.rm(y,{recursive:!0,force:!0}).catch(()=>{})),e.step="done",e.finishedAt=$}async function By(){let e=await ne(),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 Lt(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 Y.readdir(c).catch(()=>[])){if(d.has(f))continue;let w=z.join(c,f),h=await Y.readFile(z.join(w,".git"),"utf8").catch(()=>null),y=h&&/^gitdir:\s*(.+?)\/\.git\/worktrees\//m.exec(h);y&&p.push({base:y[1],dir:w})}s=await tR(r.layout,{added:p})}catch(c){a=c?.message||String(c),console.error(`[reshape ${n.id}] boot rollback failed: ${a}`)}o&&!jr.has(o.state)&&(o.state="stopped");let i=`interrupted by a node restart during "${r.step}"${s?" \u2014 moved back":""}${a?` (${a})`:""}`;Ee(n,"retag-failed",{action:"reshape",box:n.leadBox,agent:o?.agent??null,reason:i,rolledBack:!a,recovered:!0}),n.reshape={...r,step:"error",error:i,finishedAt:Date.now(),recovered:a?"rollback-failed":"rolled-back",layout:null}}return t&&await ae(),t}async function a5(e,t,{repo:n,repos:r,cwd:o}={}){await Y.mkdir(ul,{recursive:!0});let s=z.join(ul,e),a=Array.isArray(r)?r.map(c=>typeof c=="string"?c.trim():"").filter(Boolean):[];if(a.length>=2)return r5(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!z.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await ea(n)??await ku(n));let i=await eR([n,o,fq]);if(i){let c=`track/${uf(t)}-${e}`;try{let l=await hs(i);await ms(i,s,c,l),await ml(s);let u=await Me(i).catch(()=>null);return{dir:s,base:i,branch:c,kind:"worktree",baseRef:l,repo:u}}catch{await Y.rm(s,{recursive:!0,force:!0}).catch(()=>{})}}return await Y.mkdir(s,{recursive:!0}),await rw(s),await ml(s),{dir:s,base:null,branch:null,kind:"repo"}}async function ml(e){try{await Y.writeFile(z.join(e,"AGENTS.md"),cl,{flag:"wx"})}catch{return}await u5(e,["/AGENTS.md"])}function l5(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(`
239
239
  `),o=n?`
240
240
  \`${n}/\` is this Track's pre-repo workspace, carried over when the
241
241
  Track was reshaped onto these repos. It is not part of any tagged repo and
242
242
  cannot be shipped \u2014 move anything worth keeping into the repo it belongs to.
243
- `:"";return`${i5}
243
+ `:"";return`${c5}
244
244
 
245
245
  This directory is NOT a git repo. It is a bostrat Track workspace holding one
246
246
  git worktree per tagged repo, ALL on the same branch \`${t}\`:
@@ -252,7 +252,7 @@ push / open PRs) in each repo separately, always on that shared branch. Work
252
252
  only needs to land in the repos it actually touches \u2014 an untouched repo's
253
253
  branch simply stays at its fork point and never gets pushed. When asked to run
254
254
  or preview an app, run it from that app's own repo directory.
255
- ${o}`}async function si(e,t,n,r={}){let o=c5(t,n,r);for(let s of["CLAUDE.md","AGENTS.md"])await Y.writeFile(z.join(e,s),o).catch(()=>{})}async function rR(e){let{stdout:t}=await qp("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return z.resolve(e,t.trim())}async function l5(e,t){try{let n=await rR(e);await Y.mkdir(z.dirname(n),{recursive:!0});let r=await Y.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
255
+ ${o}`}async function si(e,t,n,r={}){let o=l5(t,n,r);for(let s of["CLAUDE.md","AGENTS.md"])await Y.writeFile(z.join(e,s),o).catch(()=>{})}async function rR(e){let{stdout:t}=await Gp("git",["-C",e,"rev-parse","--git-path","info/exclude"]);return z.resolve(e,t.trim())}async function u5(e,t){try{let n=await rR(e);await Y.mkdir(z.dirname(n),{recursive:!0});let r=await Y.readFile(n,"utf8").catch(()=>""),o=t.filter(s=>!r.split(`
256
256
  `).includes(s));o.length&&await Y.appendFile(n,(r.endsWith(`
257
257
  `)||!r?"":`
258
258
  `)+o.join(`
@@ -260,12 +260,12 @@ ${o}`}async function si(e,t,n,r={}){let o=c5(t,n,r);for(let s of["CLAUDE.md","AG
260
260
  `)}catch{}}async function oR(e,t){try{let n=await rR(e),r=await Y.readFile(n,"utf8"),o=r.split(`
261
261
  `).filter(s=>s!==t);o.length!==r.split(`
262
262
  `).length&&await Y.writeFile(n,o.join(`
263
- `))}catch{}}async function Ly(){let e={refreshed:0,removed:0,codexGlobal:null};try{await Y.mkdir(nr,{recursive:!0}),await Y.writeFile(z.join(nr,"CLAUDE.md"),a5).catch(()=>{}),await Y.writeFile(z.join(nr,"AGENTS.md"),cl).catch(()=>{});let t=process.env.CODEX_HOME||z.join(process.env.HOME||"/tmp",".codex");if((await Y.stat(t).catch(()=>null))?.isDirectory()){let r=z.join(t,"AGENTS.md"),o=await Y.readFile(r,"utf8").catch(()=>null);o===null?(await Y.writeFile(r,cy,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):ll(o)&&o!==cy&&(await Y.writeFile(r,cy).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[ul,ni]){let o=await Y.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 Y.readFile(i,"utf8").catch(()=>null);c!==null&&ll(c)&&c!==cl&&(await Y.writeFile(i,cl).catch(()=>{}),e.refreshed++);let l=z.join(a,"CLAUDE.md"),u=await Y.readFile(l,"utf8").catch(()=>null);u!==null&&ll(u)&&(await Y.rm(l,{force:!0}).catch(()=>{}),await oR(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function sR(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of Gt(t))n.base&&n.dir&&await $t(n.base,n.dir).catch(()=>{});await Y.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await $t(t.base,t.dir):await Y.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function ef({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 ri(o,a,s),c=ds({agent:o,agentCmd:i}),l=await ne(),u=Wp().slice(0,8),d=await s5(u,e,{repo:n,repos:r,cwd:t}),p=new Set(l.tracks.flatMap(y=>(y.boxes||[]).map(k=>k.name))),f=`${e.trim()} lead`;p.has(Uu(f))&&(f=`${e.trim().slice(0,50).trim()} ${u} lead`);let w=await jn(f,d.dir,{agentCmd:i,agent:o,freshWorkspace:!0}),h={id:u,name:e.trim(),cwd:w.cwd,workspace:d,leadBox:w.name,boxes:[Jy(w,"lead","live")],events:[],createdAt:Date.now()};return h.boxes[0].cliVersion=await c,Ee(h,"opened",{agent:o,...s?{model:s}:{},box:w.name,cliVersion:h.boxes[0].cliVersion,skipPermissions:a,name:h.name,cwd:h.cwd,workspace:{base:d.base??null,branch:d.branch,kind:d.kind,...d.baseRef?{baseRef:d.baseRef}:{},...d.repo?{repo:d.repo}:{},...d.repos?{repos:d.repos.map(({name:y,base:k,baseRef:g,repo:x})=>({name:y,base:k,baseRef:g,repo:x}))}:{}}}),l.tracks.push(h),await ae(),rs({cwd:w.cwd,sessionName:w.name,agent:o,agentCmd:i,onBlocked:({message:y})=>W$(h.id,{box:w.name,agent:o,message:y}).catch(()=>{}),onReady:async()=>{let y=h.boxes.find(k=>k.name===h.leadBox);!y||y.readyAt||(y.readyAt=Date.now(),await ae())}}),Zt(h)}async function jy({provider:e="claude",fresh:t=!1}={}){if(!u5.has(e))throw new Error(`unknown setup provider "${e}" (claude | codex | cursor)`);let r=(await ne()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===e&&!u.archivedAt);if(r){if(!t){let u=await Zt(r);if(u.boxes.find(p=>p.name===u.leadBox)?.state==="live")return u}await Ds(r.id).catch(()=>{})}let o=(await ri(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=Wp().slice(0,8),a=z.join(nr,"setup",s);await Y.mkdir(a,{recursive:!0});let i=await jn(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&rs({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:[Jy(i,"lead","live")],events:[],createdAt:Date.now()};return Ee(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 ne()).tracks.push(c),await ae(),Zt(c)}async function Fy(e,t,n){await $u(t.cwd).catch(()=>{}),await kg(e).catch(()=>{});let r=Ns.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),Ns.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of Ls(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await sb(a).catch(()=>{}),Wt.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 ne(),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 Lt(a.name).catch(()=>{})}async function Uy(e,{cascadeMocks:t=!0,cascadeRunbooks:n=!1}={}){let r=await ne(),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 _I(s),Oy(e),await Fy(e,s,"track deleted"),n?await o$(e).catch(()=>{}):await r$(e).catch(()=>{}),await lT(),await sR(s),t&&await II(e).catch(()=>{}),t?await GI(e).catch(()=>{}):await qI(s).catch(()=>{}),Ee(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await ae(),{ok:!0,id:e,name:s.name,boxes:s.boxes.length}}async function Ds(e){let t=await ne(),n=fe(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(),Oy(e),Ee(n,"archived",{boxes:n.boxes.length}),await ae(),n.kind==="setup"?(await aR(e),Zt(n)):(hl.add(e),f5(e).catch(()=>{}).finally(()=>hl.delete(e)),{...await Zt(n),archiving:!0})}async function f5(e){try{await m5(e)}catch{}await aR(e).catch(()=>{})}async function aR(e){let t=await ne(),n=fe(t,e);if(!(!n||!n.archivedAt)){await Fy(e,n,"track archived");for(let r of n.boxes)jr.has(r.state)||(r.state="stopped");await ae()}}async function m5(e){let t=await ne(),n=fe(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 Se(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await cA(n.leadBox,i.cwd,{timeoutMs:p5})),s="lead-cli"}catch{}if(r||(r=SA(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 N(n,{type:"track.summary.recorded",actor:"orchestrator",source:"orchestrator",boxId:n.leadBox||null,provider:i?.agent||null,payload:o.length?{text:r,items:o,source:s}:{text:r,source:s}}).catch(()=>{}),await ae()}async function Er(e,t){let n=await ft(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await Hy(n);if(r.length){for(let o of r)await ys(o.repo,o.number,!0).catch(()=>{});return!1}try{return await Ds(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function Hy(e){return(await En().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 _r(e,t){return tf(e,t,"merged")}async function Bs(e,t){let n=await ft(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 Hy(n);if(o.length){let c=[...n.followupPending||[],r];for(let l of o)await HT(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=fe(await ne(),n.trackId);if(!a)return null;let i=s[0];return Fc(await Zt(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 tf(e,t,n="merged"){let r=await ft(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 Hy(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await UT(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];if(!await MT(r.repo,r.number).catch(()=>!0))return!1;try{return await qt(r.trackId,iR(a),{kind:"merge-notify"}),!0}catch{return await bs(r.repo,r.number,!0).catch(()=>{}),!1}}function iR(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 ${B$[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 ${B$[i.outcome]??i.outcome}`).join(`
263
+ `))}catch{}}async function Ly(){let e={refreshed:0,removed:0,codexGlobal:null};try{await Y.mkdir(nr,{recursive:!0}),await Y.writeFile(z.join(nr,"CLAUDE.md"),i5).catch(()=>{}),await Y.writeFile(z.join(nr,"AGENTS.md"),cl).catch(()=>{});let t=process.env.CODEX_HOME||z.join(process.env.HOME||"/tmp",".codex");if((await Y.stat(t).catch(()=>null))?.isDirectory()){let r=z.join(t,"AGENTS.md"),o=await Y.readFile(r,"utf8").catch(()=>null);o===null?(await Y.writeFile(r,cy,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):ll(o)&&o!==cy&&(await Y.writeFile(r,cy).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[ul,ni]){let o=await Y.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 Y.readFile(i,"utf8").catch(()=>null);c!==null&&ll(c)&&c!==cl&&(await Y.writeFile(i,cl).catch(()=>{}),e.refreshed++);let l=z.join(a,"CLAUDE.md"),u=await Y.readFile(l,"utf8").catch(()=>null);u!==null&&ll(u)&&(await Y.rm(l,{force:!0}).catch(()=>{}),await oR(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function sR(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of Gt(t))n.base&&n.dir&&await $t(n.base,n.dir).catch(()=>{});await Y.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await $t(t.base,t.dir):await Y.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function tf({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 ri(o,a,s),c=ds({agent:o,agentCmd:i}),l=await ne(),u=qp().slice(0,8),d=await a5(u,e,{repo:n,repos:r,cwd:t}),p=new Set(l.tracks.flatMap(y=>(y.boxes||[]).map(k=>k.name))),f=`${e.trim()} lead`;p.has(Uu(f))&&(f=`${e.trim().slice(0,50).trim()} ${u} lead`);let w=await jn(f,d.dir,{agentCmd:i,agent:o,freshWorkspace:!0}),h={id:u,name:e.trim(),cwd:w.cwd,workspace:d,leadBox:w.name,boxes:[Jy(w,"lead","live")],events:[],createdAt:Date.now()};return h.boxes[0].cliVersion=await c,Ee(h,"opened",{agent:o,...s?{model:s}:{},box:w.name,cliVersion:h.boxes[0].cliVersion,skipPermissions:a,name:h.name,cwd:h.cwd,workspace:{base:d.base??null,branch:d.branch,kind:d.kind,...d.baseRef?{baseRef:d.baseRef}:{},...d.repo?{repo:d.repo}:{},...d.repos?{repos:d.repos.map(({name:y,base:k,baseRef:g,repo:x})=>({name:y,base:k,baseRef:g,repo:x}))}:{}}}),l.tracks.push(h),await ae(),rs({cwd:w.cwd,sessionName:w.name,agent:o,agentCmd:i,onBlocked:({message:y})=>W$(h.id,{box:w.name,agent:o,message:y}).catch(()=>{}),onReady:async()=>{let y=h.boxes.find(k=>k.name===h.leadBox);!y||y.readyAt||(y.readyAt=Date.now(),await ae())}}),Zt(h)}async function jy({provider:e="claude",fresh:t=!1}={}){if(!d5.has(e))throw new Error(`unknown setup provider "${e}" (claude | codex | cursor)`);let r=(await ne()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===e&&!u.archivedAt);if(r){if(!t){let u=await Zt(r);if(u.boxes.find(p=>p.name===u.leadBox)?.state==="live")return u}await Ds(r.id).catch(()=>{})}let o=(await ri(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=qp().slice(0,8),a=z.join(nr,"setup",s);await Y.mkdir(a,{recursive:!0});let i=await jn(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&rs({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:[Jy(i,"lead","live")],events:[],createdAt:Date.now()};return Ee(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 ne()).tracks.push(c),await ae(),Zt(c)}async function Fy(e,t,n){await $u(t.cwd).catch(()=>{}),await kg(e).catch(()=>{});let r=Ns.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),Ns.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of Ls(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await sb(a).catch(()=>{}),Wt.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 ne(),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 Lt(a.name).catch(()=>{})}async function Uy(e,{cascadeMocks:t=!0,cascadeRunbooks:n=!1}={}){let r=await ne(),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 _I(s),Oy(e),await Fy(e,s,"track deleted"),n?await o$(e).catch(()=>{}):await r$(e).catch(()=>{}),await lA(),await sR(s),t&&await II(e).catch(()=>{}),t?await GI(e).catch(()=>{}):await qI(s).catch(()=>{}),Ee(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await ae(),{ok:!0,id:e,name:s.name,boxes:s.boxes.length}}async function Ds(e){let t=await ne(),n=fe(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(),Oy(e),Ee(n,"archived",{boxes:n.boxes.length}),await ae(),n.kind==="setup"?(await aR(e),Zt(n)):(hl.add(e),m5(e).catch(()=>{}).finally(()=>hl.delete(e)),{...await Zt(n),archiving:!0})}async function m5(e){try{await h5(e)}catch{}await aR(e).catch(()=>{})}async function aR(e){let t=await ne(),n=fe(t,e);if(!(!n||!n.archivedAt)){await Fy(e,n,"track archived");for(let r of n.boxes)jr.has(r.state)||(r.state="stopped");await ae()}}async function h5(e){let t=await ne(),n=fe(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 Se(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await cT(n.leadBox,i.cwd,{timeoutMs:f5})),s="lead-cli"}catch{}if(r||(r=ST(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 N(n,{type:"track.summary.recorded",actor:"orchestrator",source:"orchestrator",boxId:n.leadBox||null,provider:i?.agent||null,payload:o.length?{text:r,items:o,source:s}:{text:r,source:s}}).catch(()=>{}),await ae()}async function Er(e,t){let n=await ft(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await Hy(n);if(r.length){for(let o of r)await ys(o.repo,o.number,!0).catch(()=>{});return!1}try{return await Ds(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function Hy(e){return(await En().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 _r(e,t){return nf(e,t,"merged")}async function Bs(e,t){let n=await ft(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 Hy(n);if(o.length){let c=[...n.followupPending||[],r];for(let l of o)await HA(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=fe(await ne(),n.trackId);if(!a)return null;let i=s[0];return Fc(await Zt(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 nf(e,t,n="merged"){let r=await ft(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 Hy(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await UA(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];if(!await MA(r.repo,r.number).catch(()=>!0))return!1;try{return await qt(r.trackId,iR(a),{kind:"merge-notify"}),!0}catch{return await bs(r.repo,r.number,!0).catch(()=>{}),!1}}function iR(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 ${B$[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 ${B$[i.outcome]??i.outcome}`).join(`
264
264
  `),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}
265
265
  ${s}
266
- ${a}`}async function Wy(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<ec()?!1:Fn(e.name)}async function wl(e,t,n){return!t||e.archivedAt||jr.has(t.state)?!1:(await ee({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 Lt(t.name).catch(()=>{}),t.state="stopped",ai(e))}async function ai(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=ly.get(r.name);if(o)return o;let s=w5(e,r,{freshSession:t,reason:n}).finally(()=>ly.delete(r.name));return ly.set(r.name,s),s}async function qy(e){let n=(await ne()).tracks.find(o=>o.leadBox===e);if(!n||n.archivedAt||n.transferredTo||Date.now()-(uy.get(e)??0)<h5)return!1;let r=await ai(n,{reason:"attach"}).catch(()=>!1);return r?(uy.delete(e),await ae()):uy.set(e,Date.now()),r}async function w5(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||jr.has(t.state)||await Se(t.name))return!1;let o=n===!0,s=o?Wp():null,a=o?Zi(yy(t.agent),s,t.name):Kp(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await Fu(a);if(i===la)return Ee(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===ua&&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(_o(t)))}:null,l=Date.now();if(o){let u=_o(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=ds({agent:t.agent,agentCmd:a}),d=await jn(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=Ho(d.hookToken),t.cliVersion=await u,_o(t)[t.epochs.length-1].cliVersion=t.cliVersion,rs({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a,onBlocked:({message:p})=>W$(e.id,{box:t.name,agent:t.agent,message:p}).catch(()=>{})}),t.state="live",o&&Ee(e,"lead-refreshed",{box:t.name,agent:t.agent,fromSessionId:c.sessionId,toSessionId:s,epoch:t.epochs.length-1,reason:r||"fresh-session",cliVersion:t.cliVersion??null,standing:await Ya(t.cwd)}),Ee(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),Ee(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function nf(e,{freshSession:t=!1}={}){let n=await ne(),r=fe(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,hl.delete(e),Ee(r,"unarchived",{}),await ai(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await ae(),Zt(r)}async function Gy(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>gy)throw new Error(`name too long (max ${gy} chars)`);let r=await ne(),o=fe(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 Zt(o);let s=o.name;return o.name=n,Ee(o,"renamed",{from:s,to:n}),await ae(),Zt(o)}async function Ky(){let e=await ne(),t=0;for(let n of e.tracks||[])n.transferredTo&&Od(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await ae(),t}async function Vy(){let e=await ne(),t=new Set((await kn()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!Ue(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(Ue(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await Lt(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):Ee(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!jr.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await ae(),r}async function rf(e,{freshSession:t=!1}={}){let n=await ne(),r=fe(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`);sf(r);let o=r.boxes.find(i=>i.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(jr.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await Se(r.leadBox)){let i=await Ne(r.leadBox,{lines:ze}).catch(()=>"");if(uc(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await Lt(r.leadBox),o.state="stopped"}let a=await ai(r,t?{freshSession:!0,reason:"loop-fire"}:{});if(await ae(),!a)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Zt(r)}async function zy(e,t,n){let r=await me(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 rf(e),await N(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 L$(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return ip({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function _o(e){return(!Array.isArray(e.epochs)||e.epochs.length===0)&&(e.epochs=[{agent:e.agent??null,sessionId:e.sessionId??null,pinned:e.pinned===!0,cliVersion:e.cliVersion??null,startedAt:e.createdAt??null,endedAt:null}]),e.epochs}async function Up(e,t){let n=await ne(),r=fe(n,e);r&&(r.handoff={...r.handoff||{},...t},await ae())}function cR(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 Yy(){let e=await ne(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=cR(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await Se(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=_o(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,y=await ds({agent:r.toAgent});d.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:h,cliVersion:y,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.cliVersion=y,l.sessionId=c.sessionId||null,l.pinned=h,l.state="live",n.pendingHandoffHydrate={artifact:Io,at:u},Ee(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,standing:await Ya(l.cwd)}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await ee({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 ee({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await Lt(i).catch(()=>{}),a&&await Lt(a).catch(()=>{})}return t&&await ae(),t}async function of(e,t,n=!0,r=null){let o=Ns.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=fe(await ne(),e);if(!s)throw new Error(`track "${e}" not found`);oi(e,"handoff");let a=await ri(t,n),i=mo(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 Se(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:q$(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return Ns.set(e,l),await Up(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),g5(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 Up(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),ee({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),ee({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function g5(e,t,n,r,o){let s=async(P,j={})=>{e.step=P,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${P}`),await Up(e.trackId,{step:P,toBox:e.toBox}),await ee({flow:"lead-handoff",phase:P,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:j.sessionName,...j})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await ne(),i=fe(a,e.trackId)?.boxes.find(P=>P.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",e.quiescence=null,mo(c))e.checkpoint="skipped-capped";else try{let P=await Sd(e.fromBox,{timeoutMs:by,quiesce:{box:i?{...i,name:e.fromBox}:n,reason:e.reason?.code||"lead-handoff",onWait:async j=>{e.wait=j,await s("await-turn",{sessionName:e.fromBox,wait:j})},onResume:async()=>{e.wait=null,await s("checkpoint",{sessionName:e.fromBox})}}});e.quiescence=Fh(P),e.waitedMs=(P.quiescence?.pre?.waitedMs||0)+(P.quiescence?.post?.waitedMs||0)}catch(P){e.checkpoint="reconstructed",e.quiescence=Fh(P),e.waitedMs=P?.quiescence?.pre?.waitedMs||0,e.wait=null,await ee({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:P?.message||String(P)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await Ad(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=ds({agent:o,agentCmd:r}),f=await zh(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let w=bv(f.launchCmd);await wr({cwd:n.cwd,sessionId:f.sessionId,sessionName:e.fromBox,agent:o,agentCmd:Ps(o),launchEcho:w}).catch(P=>{if(P?.code!=="cli-not-running")throw P});let h=td(await Ne(e.fromBox,{lines:ze}).catch(()=>""),w);if(await ee({flow:"lead-handoff",phase:"hydrate-ready",trackId:e.trackId,sessionName:e.fromBox,toAgent:o,up:to(o,h),paneTail:!0}).catch(()=>{}),!to(o,h)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let P=Kp(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await zh(e.fromBox,{agentCmd:P,agent:c,resumeSessionId:l,pinned:u});let j=await ne(),T=fe(j,e.trackId);if(T){let $=T.boxes.find(L=>L.name===e.fromBox);$&&($.state="live"),Ee(T,"lead-handoff-failed",{box:e.fromBox,fromAgent:c,toAgent:o,reason:e.reason,error:`incoming ${o} CLI never drew its composer`,rolledBack:!0,handoffStartedAt:e.startedAt}),await ae()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let y=await ne(),k=fe(y,e.trackId);if(!k)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let g=k.boxes.find(P=>P.name===e.fromBox);if(!g)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let x=Date.now(),S=_o(g),_=S[S.length-1];_.endedAt=x,e.reason&&(_.endReason=e.reason);let M=await p;S.push({agent:o,sessionId:f.sessionId,pinned:f.pinned,cliVersion:M,startedAt:x,endedAt:null}),g.agent=o,g.sessionId=f.sessionId,g.pinned=f.pinned,g.cliVersion=M,g.state="live",g.role="lead",k.pendingHandoffHydrate={artifact:e.statusArtifact||Io,at:x},Ee(k,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:f.sessionId,epoch:S.length-1,singleBox:!0,forced:f.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,cliVersion:M,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint,quiescence:e.quiescence||void 0,waitedMs:e.waitedMs||void 0,standing:await Ya(g.cwd)}),await ae(),await s("done",{sessionName:e.fromBox}),await Up(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function Qy(e){let t=Hp.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await ne(),r=fe(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=Ns.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Wt.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 Hp.set(e,s),y5(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 y5(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await Se(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&mo(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await Sd(t.leadBox,{timeoutMs:by,quiesce:{box:n,reason:"transfer-out",onWait:()=>{e.step="await-turn"},onResume:()=>{e.step="checkpoint"}}})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await Ad(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 Gt(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],Xy);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(`
267
- `)[0]}s.push(d)}e.step="wip";let a=await Ug(t,{force:!0}),i=await ne(),c=fe(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&_o(l),await ae(),e.result={name:c?.name??t.name,agent:l?.agent??null,leadBox:c?.leadBox??t.leadBox,createdAt:c?.createdAt??null,branch:o,repos:s.filter(u=>u.pushed).map(({name:u,repo:d,baseSha:p})=>({name:u,repo:d,baseSha:p})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:d,error:p})=>({name:u,repo:d,error:p})),wip:a.pushed[0]?{ref:a.pushed[0].ref,sha:a.pushed[0].sha}:null,wips:a.pushed,wipSkipped:a.skipped,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function sf(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 af(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await ne(),o=fe(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};Oy(e),await Fy(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();Od(o,{at:s,reason:n==="recover"?"node-offline":"node-transfer"});let a=await Hg(o,{ts:s}),i=a.pushed[0]??null;return o.transferredTo=t,o.transferredAt=s,Ee(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...i?{rescueRef:i.ref,rescueSha:i.sha}:{},...a.pushed.length?{rescues:a.pushed}:{}}),await ae(),{ok:!0,toNode:t,rescue:i?{ref:i.ref,sha:i.sha}:null,rescues:a.pushed}}async function eb(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await af(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 j$(e,t,n){try{await Ec(e,t,n)}catch{await Mn(e,["worktree","prune"]).catch(()=>{}),await Ec(e,t,n)}return t}function b5(e,{wip:t=null,wips:n=null}={}){let r=Gt(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 k5(e,t){try{await Mn(e,["fetch","origin",Fg(t)],Xy);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(`
268
- `)[0],advanced:null}}}function v5(e){if(typeof e!="string"||!x5.test(e)||e.includes("..")||e.includes("@{")||e.endsWith(".lock"))throw new Error("branch fails the safe-ref check")}async function tb(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&&v5(e.branch),Bp.has(t))throw new Error("an adopt is already running for this Track");Bp.set(t,{startedAt:Date.now()});try{return await S5({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{Bp.delete(t)}}async function S5({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:y=null}){let k=await ri(n,r),g=await ne(),x=fe(g,e);if(x&&!x.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);x&&(await Hg(x).catch(()=>{}),await sR(x),g.tracks.splice(g.tracks.indexOf(x),1),await ae()),await Y.mkdir(ul,{recursive:!0});let S=z.join(ul,e);await Y.rm(S,{recursive:!0,force:!0}).catch(()=>{});let _=null,M=!1,P=[];try{let j=[];if(i)for(let le of Array.isArray(c)?c:[]){let ge=typeof le=="string"?le:le?.repo;if(!ge||!/^[^/\s]+\/[^/\s]+$/.test(ge))continue;let de=await ea(ge)??await ku(ge);await Mn(de,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],Xy),j.push({slug:ge,base:de,name:typeof le=="object"?le?.name??null:null})}if(i&&j.length===1){let{base:le,slug:ge}=j[0];await j$(le,S,i),P.push({base:le,dir:S}),await ml(S);let de=await hs(le);_={dir:S,base:le,branch:i,kind:"worktree",baseRef:de,repo:ge}}else if(i&&j.length>=2){await Y.mkdir(S,{recursive:!0});let le=new Set([".bostrat"]),ge=[];for(let de of j){let te=de.name||z.basename(de.base);le.has(te)&&(te=de.slug.replace("/","-"));for(let Ve=2;le.has(te);Ve++)te=`${z.basename(de.base)}-${Ve}`;le.add(te);let we=z.join(S,te);await j$(de.base,we,i),P.push({base:de.base,dir:we});let Oe=await hs(de.base);ge.push({name:te,dir:we,base:de.base,baseRef:Oe,repo:de.slug})}await si(S,ge,i),_={dir:S,kind:"multi",branch:i,repos:ge}}else M=!0,await Y.mkdir(S,{recursive:!0}),await rw(S),await ml(S),_={dir:S,base:null,branch:null,kind:"repo"};let T=[];for(let le of b5(_,{wip:l,wips:u})){let ge=await k5(le.dir,e);T.push({name:le.name,repo:le.repo,applied:ge.applied,skipped:ge.skipped,...ge.advanced?{advanced:ge.advanced}:{}})}let $=T.some(le=>le.applied),L=T.length===1?T[0].skipped:T.filter(le=>le.skipped).map(le=>`${le.name??le.repo}: ${le.skipped}`).join("; ")||null,H=T.length===1?T[0].advanced??null:null;await y$({id:e,cwd:S}).catch(()=>({restored:!1}));let R=z.join(S,Io),A=null;(await Nu(S)).restored?A="checkpoint":typeof d=="string"&&d.trim()&&(await Y.mkdir(z.dirname(R),{recursive:!0}),await Y.writeFile(R,d),A="brief");let W=new Set(g.tracks.flatMap(le=>(le.boxes||[]).map(ge=>ge.name))),B=null;w&&!W.has(w)&&!await Se(w).catch(()=>null)?B=w:(B=`${t.trim()} lead`,W.has(Uu(B))&&(B=`${t.trim().slice(0,50).trim()} ${e} lead`));let Z=await jn(B,S,{agentCmd:k,agent:n});rs({cwd:Z.cwd,sessionName:Z.name,agent:n,agentCmd:k});let xe=Date.now(),Ae=Jy(Z,"lead","live"),_e=(Array.isArray(p)?p:[]).filter(le=>le&&typeof le=="object").map(le=>({...le})),Q=_e[_e.length-1];Q&&Q.endedAt==null&&(Q.endedAt=xe,Q.endReason==null&&(Q.endReason=o==="recover"?"node-offline":"node-transfer"));let Xe=await ds({agent:n,agentCmd:k});_e.push({agent:n,sessionId:Z.sessionId??null,pinned:Z.pinned===!0,cliVersion:Xe,startedAt:xe,endedAt:null}),Ae.epochs=_e,Ae.cliVersion=Xe;let Pe={id:e,name:t.trim(),cwd:Z.cwd,workspace:_,leadBox:Z.name,boxes:[Ae],events:[],createdAt:Number.isFinite(f)?f:xe,...A?{pendingHandoffHydrate:{artifact:Io,at:xe}}:{}};return Ee(Pe,"transferred-in",{box:Z.name,agent:n,fromNode:s,toNode:a,mode:o,reason:h,...o==="recover"?{downSince:Number.isFinite(y)?y:null}:{},branch:_.branch??null,wip:$,...H?{wipAdvanced:H}:{},..._.kind==="multi"&&T.length?{wipRepos:T}:{},epoch:_e.length-1,name:Pe.name,cwd:Pe.cwd,workspace:{base:_.base??null,branch:_.branch??null,kind:_.kind,..._.baseRef?{baseRef:_.baseRef}:{},..._.repo?{repo:_.repo}:{},..._.repos?{repos:_.repos.map(({name:le,base:ge,baseRef:de,repo:te})=>({name:le,base:ge,baseRef:de,repo:te}))}:{}}}),g.tracks.push(Pe),await ae(),{...await Zt(Pe),adopt:{wipApplied:$,wipSkipped:L,...H?{wipAdvanced:H}:{},..._.kind==="multi"?{wipRepos:T}:{},codeless:M,artifactSource:A}}}catch(j){for(let T of P)await $t(T.base,T.dir).catch(()=>{});throw await Y.rm(S,{recursive:!0,force:!0}).catch(()=>{}),j}}async function lR(e,t,n){let r=await ne(),o=fe(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await ae())}async function Za(e,t){e.step=t,await vl(e)}function uR(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 dR(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function _5(e,t,n){if(!dR(n)||Wt.has(t)||!await Se(n.box).catch(()=>null))return!1;try{await Y.access(n.dir)}catch{return!1}let o=await Se(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return Wt.set(t,s),fR(s,o).catch(a=>pR(s,a)),!0}async function nb(){let e=await ne(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Wt.has(r))continue;if(await _5(n,r,o)){t=!0,Ee(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await ee({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=uR(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!jr.has(i.state)&&(i.state="canceled"),Ee(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 ee({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await F$(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||jr.has(r.state)||Wt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?z.join(ni,`${n.id}-${r.subtaskId}`):null;await ee({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await F$(n,r.name,o)}}return t=await I5(e)||t,t&&await ae(),t}async function F$(e,t,n){if(t&&await Lt(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of Gt(e.workspace)){let s=z.join(n,o.name);await $t(o.base,s).then(()=>!0,()=>!1)||await $t(o.dir,s).catch(()=>{})}await Y.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await Se(e.leadBox).catch(()=>null);r?.cwd&&await $t(r.cwd,n).catch(()=>{})}async function I5(e){let t;try{t=await Y.readdir(ni)}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 Wt.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(ni,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of Gt(a.workspace))await $t(i.base,z.join(s,i.name)).catch(()=>{});await Y.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await Se(a.leadBox).catch(()=>null):null;i?.cwd?await $t(i.cwd,s).catch(()=>{}):await Y.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await ee({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function rb(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!Ia(n))throw new Error("task (string) required");let s=await ri(t,r),a=mo(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=fe(await ne(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await Se(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=Gt(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 $a(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 $a(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=Wp().slice(0,8),p={id:d,trackId:e,trackName:i.name,agent:t,task:Ia(n),skipPermissions:r,reason:q$(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${lf(i.name)}-${d}`,base:null,repos:u,dir:z.join(ni,`${e}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Wt.set(d,p),await vl(p),$5(p,c,s).catch(f=>pR(p,f)),p}async function pR(e,t){e.failedStep=e.step,e.error=t instanceof gl?"canceled":t?.message||String(t),e.step=t instanceof gl?"canceled":"error",e.finishedAt=Date.now(),await sb(e).catch(()=>{}),await vl(e).catch(()=>{}),await C5(e).catch(()=>{})}function uf(e){let t=Wt.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 ob(e){let t=Wt.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 $5(e,t,n){if(await Za(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await Ra(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await vl(e)}else e.base=await Ra(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await Za(e,"spawn"),await Y.mkdir(ni,{recursive:!0}),e.repos){await Y.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await ms(a.leadDir,z.join(e.dir,a.name),e.branch,a.base);let s=Gt((fe(await ne(),e.trackId)||{}).workspace);await si(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 ms(t.cwd,e.dir,e.branch,e.base),await ml(e.dir);await R5(e,t);let r=e.trackName.slice(0,38).trim(),o=await jn(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await O5(e,o),await G$(e.trackId,o.name,mq(e.task,!!e.repos),{kind:"subtask"}),await fR(e,t)}async function fR(e,t){await Za(e,"working");let n=z.join(e.dir,Lp);if(await P5(n,e),e.canceled)throw new gl;if(await Za(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 tw(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:L$({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await sw(l.leadDir,l.base,e.branch,Xa),l.files=await aw(l.leadDir,l.base,e.branch,Xa);let d=await iw(l.leadDir,l.base,e.branch,Xa);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 tw(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:L$({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await sw(t.cwd,e.base,e.branch,Xa),e.files=await aw(t.cwd,e.base,e.branch,Xa);let s=await iw(t.cwd,e.base,e.branch,Xa);e.applied=s.applied,e.conflicts=s.conflicts}await vl(e);let r=await N5(e,t,n);await Za(e,"resume"),await G$(e.trackId,e.leadBox,hq(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await Za(e,"reap"),await sb(e),e.step="done";let o=Date.now();await lR(e.trackId,e.id,{...cf(e),finishedAt:o}),await M5(e,o),e.finishedAt=o}async function R5(e,t){let n=z.join(e.dir,z.dirname(dl));await Y.mkdir(n,{recursive:!0});let r="";try{r=await Qx(t.cwd,t.sessionId)}catch{}if(!r)try{r=await Y.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}
266
+ ${a}`}async function Wy(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<ec()?!1:Fn(e.name)}async function wl(e,t,n){return!t||e.archivedAt||jr.has(t.state)?!1:(await ee({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 Lt(t.name).catch(()=>{}),t.state="stopped",ai(e))}async function ai(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=ly.get(r.name);if(o)return o;let s=g5(e,r,{freshSession:t,reason:n}).finally(()=>ly.delete(r.name));return ly.set(r.name,s),s}async function qy(e){let n=(await ne()).tracks.find(o=>o.leadBox===e);if(!n||n.archivedAt||n.transferredTo||Date.now()-(uy.get(e)??0)<w5)return!1;let r=await ai(n,{reason:"attach"}).catch(()=>!1);return r?(uy.delete(e),await ae()):uy.set(e,Date.now()),r}async function g5(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||jr.has(t.state)||await Se(t.name))return!1;let o=n===!0,s=o?qp():null,a=o?Zi(yy(t.agent),s,t.name):Vp(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await Fu(a);if(i===la)return Ee(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===ua&&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(_o(t)))}:null,l=Date.now();if(o){let u=_o(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=ds({agent:t.agent,agentCmd:a}),d=await jn(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=Ho(d.hookToken),t.cliVersion=await u,_o(t)[t.epochs.length-1].cliVersion=t.cliVersion,rs({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a,onBlocked:({message:p})=>W$(e.id,{box:t.name,agent:t.agent,message:p}).catch(()=>{})}),t.state="live",o&&Ee(e,"lead-refreshed",{box:t.name,agent:t.agent,fromSessionId:c.sessionId,toSessionId:s,epoch:t.epochs.length-1,reason:r||"fresh-session",cliVersion:t.cliVersion??null,standing:await Ya(t.cwd)}),Ee(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),Ee(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function rf(e,{freshSession:t=!1}={}){let n=await ne(),r=fe(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,hl.delete(e),Ee(r,"unarchived",{}),await ai(r,t?{freshSession:!0,reason:"loop-fire"}:{}),await ae(),Zt(r)}async function Gy(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>gy)throw new Error(`name too long (max ${gy} chars)`);let r=await ne(),o=fe(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 Zt(o);let s=o.name;return o.name=n,Ee(o,"renamed",{from:s,to:n}),await ae(),Zt(o)}async function Ky(){let e=await ne(),t=0;for(let n of e.tracks||[])n.transferredTo&&Md(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await ae(),t}async function Vy(){let e=await ne(),t=new Set((await kn()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!Ue(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(Ue(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await Lt(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):Ee(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!jr.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await ae(),r}async function of(e,{freshSession:t=!1}={}){let n=await ne(),r=fe(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`);af(r);let o=r.boxes.find(i=>i.name===r.leadBox);if(!o)throw new Error(`track "${e}" has no lead box`);if(jr.has(o.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await Se(r.leadBox)){let i=await Ne(r.leadBox,{lines:ze}).catch(()=>"");if(uc(o.agent,i))throw new Error("lead is mid-turn \u2014 retry when it goes idle");await Lt(r.leadBox),o.state="stopped"}let a=await ai(r,t?{freshSession:!0,reason:"loop-fire"}:{});if(await ae(),!a)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return Zt(r)}async function zy(e,t,n){let r=await me(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 of(e),await N(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 L$(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return cp({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function _o(e){return(!Array.isArray(e.epochs)||e.epochs.length===0)&&(e.epochs=[{agent:e.agent??null,sessionId:e.sessionId??null,pinned:e.pinned===!0,cliVersion:e.cliVersion??null,startedAt:e.createdAt??null,endedAt:null}]),e.epochs}async function Hp(e,t){let n=await ne(),r=fe(n,e);r&&(r.handoff={...r.handoff||{},...t},await ae())}function cR(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 Yy(){let e=await ne(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=cR(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await Se(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=_o(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,y=await ds({agent:r.toAgent});d.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:h,cliVersion:y,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.cliVersion=y,l.sessionId=c.sessionId||null,l.pinned=h,l.state="live",n.pendingHandoffHydrate={artifact:Io,at:u},Ee(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,standing:await Ya(l.cwd)}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await ee({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 ee({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await Lt(i).catch(()=>{}),a&&await Lt(a).catch(()=>{})}return t&&await ae(),t}async function sf(e,t,n=!0,r=null){let o=Ns.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is already running for this Track");let s=fe(await ne(),e);if(!s)throw new Error(`track "${e}" not found`);oi(e,"handoff");let a=await ri(t,n),i=mo(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 Se(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:q$(r),toBox:s.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return Ns.set(e,l),await Hp(e,{step:l.step,fromBox:l.fromBox,toAgent:t,toBox:l.toBox,skipPermissions:n,startedAt:l.startedAt,finishedAt:null,error:null}),y5(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 Hp(e,{step:l.step,error:l.error,finishedAt:l.finishedAt}).catch(()=>{}),ee({flow:"lead-handoff",phase:"failed",trackId:e,step:l.step,error:l.error,fromBox:l.fromBox,toAgent:l.toAgent,toBox:l.toBox}).catch(()=>{})}),ee({flow:"lead-handoff",phase:"started",trackId:e,fromBox:l.fromBox,toAgent:t,cwd:c.cwd}).catch(()=>{}),l}async function y5(e,t,n,r,o){let s=async(P,j={})=>{e.step=P,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${P}`),await Hp(e.trackId,{step:P,toBox:e.toBox}),await ee({flow:"lead-handoff",phase:P,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:j.sessionName,...j})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await ne(),i=fe(a,e.trackId)?.boxes.find(P=>P.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",e.quiescence=null,mo(c))e.checkpoint="skipped-capped";else try{let P=await Td(e.fromBox,{timeoutMs:by,quiesce:{box:i?{...i,name:e.fromBox}:n,reason:e.reason?.code||"lead-handoff",onWait:async j=>{e.wait=j,await s("await-turn",{sessionName:e.fromBox,wait:j})},onResume:async()=>{e.wait=null,await s("checkpoint",{sessionName:e.fromBox})}}});e.quiescence=Fh(P),e.waitedMs=(P.quiescence?.pre?.waitedMs||0)+(P.quiescence?.post?.waitedMs||0)}catch(P){e.checkpoint="reconstructed",e.quiescence=Fh(P),e.waitedMs=P?.quiescence?.pre?.waitedMs||0,e.wait=null,await ee({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:P?.message||String(P)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await Ad(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=ds({agent:o,agentCmd:r}),f=await zh(e.fromBox,{agentCmd:r,agent:o});await s("hydrate",{sessionName:e.fromBox});let w=bv(f.launchCmd);await wr({cwd:n.cwd,sessionId:f.sessionId,sessionName:e.fromBox,agent:o,agentCmd:Ps(o),launchEcho:w}).catch(P=>{if(P?.code!=="cli-not-running")throw P});let h=nd(await Ne(e.fromBox,{lines:ze}).catch(()=>""),w);if(await ee({flow:"lead-handoff",phase:"hydrate-ready",trackId:e.trackId,sessionName:e.fromBox,toAgent:o,up:to(o,h),paneTail:!0}).catch(()=>{}),!to(o,h)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let P=Vp(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox});await zh(e.fromBox,{agentCmd:P,agent:c,resumeSessionId:l,pinned:u});let j=await ne(),A=fe(j,e.trackId);if(A){let $=A.boxes.find(L=>L.name===e.fromBox);$&&($.state="live"),Ee(A,"lead-handoff-failed",{box:e.fromBox,fromAgent:c,toAgent:o,reason:e.reason,error:`incoming ${o} CLI never drew its composer`,rolledBack:!0,handoffStartedAt:e.startedAt}),await ae()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let y=await ne(),k=fe(y,e.trackId);if(!k)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let g=k.boxes.find(P=>P.name===e.fromBox);if(!g)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let x=Date.now(),S=_o(g),_=S[S.length-1];_.endedAt=x,e.reason&&(_.endReason=e.reason);let M=await p;S.push({agent:o,sessionId:f.sessionId,pinned:f.pinned,cliVersion:M,startedAt:x,endedAt:null}),g.agent=o,g.sessionId=f.sessionId,g.pinned=f.pinned,g.cliVersion=M,g.state="live",g.role="lead",k.pendingHandoffHydrate={artifact:e.statusArtifact||Io,at:x},Ee(k,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:f.sessionId,epoch:S.length-1,singleBox:!0,forced:f.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,cliVersion:M,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint,quiescence:e.quiescence||void 0,waitedMs:e.waitedMs||void 0,standing:await Ya(g.cwd)}),await ae(),await s("done",{sessionName:e.fromBox}),await Hp(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function Qy(e){let t=Wp.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await ne(),r=fe(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=Ns.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Wt.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 Wp.set(e,s),b5(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 b5(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await Se(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&mo(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await Td(t.leadBox,{timeoutMs:by,quiesce:{box:n,reason:"transfer-out",onWait:()=>{e.step="await-turn"},onResume:()=>{e.step="checkpoint"}}})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await Ad(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 Gt(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],Xy);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(`
267
+ `)[0]}s.push(d)}e.step="wip";let a=await Ug(t,{force:!0}),i=await ne(),c=fe(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&_o(l),await ae(),e.result={name:c?.name??t.name,agent:l?.agent??null,leadBox:c?.leadBox??t.leadBox,createdAt:c?.createdAt??null,branch:o,repos:s.filter(u=>u.pushed).map(({name:u,repo:d,baseSha:p})=>({name:u,repo:d,baseSha:p})),unpushed:s.filter(u=>!u.pushed).map(({name:u,repo:d,error:p})=>({name:u,repo:d,error:p})),wip:a.pushed[0]?{ref:a.pushed[0].ref,sha:a.pushed[0].sha}:null,wips:a.pushed,wipSkipped:a.skipped,checkpoint:e.checkpoint,epochs:l?.epochs??[],codeless:!o||!s.some(u=>u.pushed)},e.step="ready",e.finishedAt=Date.now()}function af(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 cf(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await ne(),o=fe(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};Oy(e),await Fy(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();Md(o,{at:s,reason:n==="recover"?"node-offline":"node-transfer"});let a=await Hg(o,{ts:s}),i=a.pushed[0]??null;return o.transferredTo=t,o.transferredAt=s,Ee(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...i?{rescueRef:i.ref,rescueSha:i.sha}:{},...a.pushed.length?{rescues:a.pushed}:{}}),await ae(),{ok:!0,toNode:t,rescue:i?{ref:i.ref,sha:i.sha}:null,rescues:a.pushed}}async function eb(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await cf(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 j$(e,t,n){try{await Ec(e,t,n)}catch{await Mn(e,["worktree","prune"]).catch(()=>{}),await Ec(e,t,n)}return t}function k5(e,{wip:t=null,wips:n=null}={}){let r=Gt(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 x5(e,t){try{await Mn(e,["fetch","origin",Fg(t)],Xy);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(`
268
+ `)[0],advanced:null}}}function S5(e){if(typeof e!="string"||!v5.test(e)||e.includes("..")||e.includes("@{")||e.endsWith(".lock"))throw new Error("branch fails the safe-ref check")}async function tb(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&&S5(e.branch),Lp.has(t))throw new Error("an adopt is already running for this Track");Lp.set(t,{startedAt:Date.now()});try{return await T5({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{Lp.delete(t)}}async function T5({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:y=null}){let k=await ri(n,r),g=await ne(),x=fe(g,e);if(x&&!x.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);x&&(await Hg(x).catch(()=>{}),await sR(x),g.tracks.splice(g.tracks.indexOf(x),1),await ae()),await Y.mkdir(ul,{recursive:!0});let S=z.join(ul,e);await Y.rm(S,{recursive:!0,force:!0}).catch(()=>{});let _=null,M=!1,P=[];try{let j=[];if(i)for(let le of Array.isArray(c)?c:[]){let ge=typeof le=="string"?le:le?.repo;if(!ge||!/^[^/\s]+\/[^/\s]+$/.test(ge))continue;let de=await ea(ge)??await ku(ge);await Mn(de,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],Xy),j.push({slug:ge,base:de,name:typeof le=="object"?le?.name??null:null})}if(i&&j.length===1){let{base:le,slug:ge}=j[0];await j$(le,S,i),P.push({base:le,dir:S}),await ml(S);let de=await hs(le);_={dir:S,base:le,branch:i,kind:"worktree",baseRef:de,repo:ge}}else if(i&&j.length>=2){await Y.mkdir(S,{recursive:!0});let le=new Set([".bostrat"]),ge=[];for(let de of j){let te=de.name||z.basename(de.base);le.has(te)&&(te=de.slug.replace("/","-"));for(let Ve=2;le.has(te);Ve++)te=`${z.basename(de.base)}-${Ve}`;le.add(te);let we=z.join(S,te);await j$(de.base,we,i),P.push({base:de.base,dir:we});let Oe=await hs(de.base);ge.push({name:te,dir:we,base:de.base,baseRef:Oe,repo:de.slug})}await si(S,ge,i),_={dir:S,kind:"multi",branch:i,repos:ge}}else M=!0,await Y.mkdir(S,{recursive:!0}),await rw(S),await ml(S),_={dir:S,base:null,branch:null,kind:"repo"};let A=[];for(let le of k5(_,{wip:l,wips:u})){let ge=await x5(le.dir,e);A.push({name:le.name,repo:le.repo,applied:ge.applied,skipped:ge.skipped,...ge.advanced?{advanced:ge.advanced}:{}})}let $=A.some(le=>le.applied),L=A.length===1?A[0].skipped:A.filter(le=>le.skipped).map(le=>`${le.name??le.repo}: ${le.skipped}`).join("; ")||null,H=A.length===1?A[0].advanced??null:null;await y$({id:e,cwd:S}).catch(()=>({restored:!1}));let R=z.join(S,Io),T=null;(await Nu(S)).restored?T="checkpoint":typeof d=="string"&&d.trim()&&(await Y.mkdir(z.dirname(R),{recursive:!0}),await Y.writeFile(R,d),T="brief");let W=new Set(g.tracks.flatMap(le=>(le.boxes||[]).map(ge=>ge.name))),B=null;w&&!W.has(w)&&!await Se(w).catch(()=>null)?B=w:(B=`${t.trim()} lead`,W.has(Uu(B))&&(B=`${t.trim().slice(0,50).trim()} ${e} lead`));let Z=await jn(B,S,{agentCmd:k,agent:n});rs({cwd:Z.cwd,sessionName:Z.name,agent:n,agentCmd:k});let xe=Date.now(),Te=Jy(Z,"lead","live"),_e=(Array.isArray(p)?p:[]).filter(le=>le&&typeof le=="object").map(le=>({...le})),Q=_e[_e.length-1];Q&&Q.endedAt==null&&(Q.endedAt=xe,Q.endReason==null&&(Q.endReason=o==="recover"?"node-offline":"node-transfer"));let Xe=await ds({agent:n,agentCmd:k});_e.push({agent:n,sessionId:Z.sessionId??null,pinned:Z.pinned===!0,cliVersion:Xe,startedAt:xe,endedAt:null}),Te.epochs=_e,Te.cliVersion=Xe;let Pe={id:e,name:t.trim(),cwd:Z.cwd,workspace:_,leadBox:Z.name,boxes:[Te],events:[],createdAt:Number.isFinite(f)?f:xe,...T?{pendingHandoffHydrate:{artifact:Io,at:xe}}:{}};return Ee(Pe,"transferred-in",{box:Z.name,agent:n,fromNode:s,toNode:a,mode:o,reason:h,...o==="recover"?{downSince:Number.isFinite(y)?y:null}:{},branch:_.branch??null,wip:$,...H?{wipAdvanced:H}:{},..._.kind==="multi"&&A.length?{wipRepos:A}:{},epoch:_e.length-1,name:Pe.name,cwd:Pe.cwd,workspace:{base:_.base??null,branch:_.branch??null,kind:_.kind,..._.baseRef?{baseRef:_.baseRef}:{},..._.repo?{repo:_.repo}:{},..._.repos?{repos:_.repos.map(({name:le,base:ge,baseRef:de,repo:te})=>({name:le,base:ge,baseRef:de,repo:te}))}:{}}}),g.tracks.push(Pe),await ae(),{...await Zt(Pe),adopt:{wipApplied:$,wipSkipped:L,...H?{wipAdvanced:H}:{},..._.kind==="multi"?{wipRepos:A}:{},codeless:M,artifactSource:T}}}catch(j){for(let A of P)await $t(A.base,A.dir).catch(()=>{});throw await Y.rm(S,{recursive:!0,force:!0}).catch(()=>{}),j}}async function lR(e,t,n){let r=await ne(),o=fe(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await ae())}async function Za(e,t){e.step=t,await vl(e)}function uR(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 dR(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function I5(e,t,n){if(!dR(n)||Wt.has(t)||!await Se(n.box).catch(()=>null))return!1;try{await Y.access(n.dir)}catch{return!1}let o=await Se(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return Wt.set(t,s),fR(s,o).catch(a=>pR(s,a)),!0}async function nb(){let e=await ne(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Wt.has(r))continue;if(await I5(n,r,o)){t=!0,Ee(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await ee({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=uR(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!jr.has(i.state)&&(i.state="canceled"),Ee(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 ee({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await F$(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||jr.has(r.state)||Wt.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?z.join(ni,`${n.id}-${r.subtaskId}`):null;await ee({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await F$(n,r.name,o)}}return t=await $5(e)||t,t&&await ae(),t}async function F$(e,t,n){if(t&&await Lt(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of Gt(e.workspace)){let s=z.join(n,o.name);await $t(o.base,s).then(()=>!0,()=>!1)||await $t(o.dir,s).catch(()=>{})}await Y.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await Se(e.leadBox).catch(()=>null);r?.cwd&&await $t(r.cwd,n).catch(()=>{})}async function $5(e){let t;try{t=await Y.readdir(ni)}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 Wt.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(ni,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of Gt(a.workspace))await $t(i.base,z.join(s,i.name)).catch(()=>{});await Y.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await Se(a.leadBox).catch(()=>null):null;i?.cwd?await $t(i.cwd,s).catch(()=>{}):await Y.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await ee({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function rb(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!Ia(n))throw new Error("task (string) required");let s=await ri(t,r),a=mo(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=fe(await ne(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await Se(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=Gt(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 $a(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 $a(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=qp().slice(0,8),p={id:d,trackId:e,trackName:i.name,agent:t,task:Ia(n),skipPermissions:r,reason:q$(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${uf(i.name)}-${d}`,base:null,repos:u,dir:z.join(ni,`${e}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Wt.set(d,p),await vl(p),R5(p,c,s).catch(f=>pR(p,f)),p}async function pR(e,t){e.failedStep=e.step,e.error=t instanceof gl?"canceled":t?.message||String(t),e.step=t instanceof gl?"canceled":"error",e.finishedAt=Date.now(),await sb(e).catch(()=>{}),await vl(e).catch(()=>{}),await N5(e).catch(()=>{})}function df(e){let t=Wt.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 ob(e){let t=Wt.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 R5(e,t,n){if(await Za(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await Ra(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await vl(e)}else e.base=await Ra(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await Za(e,"spawn"),await Y.mkdir(ni,{recursive:!0}),e.repos){await Y.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await ms(a.leadDir,z.join(e.dir,a.name),e.branch,a.base);let s=Gt((fe(await ne(),e.trackId)||{}).workspace);await si(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 ms(t.cwd,e.dir,e.branch,e.base),await ml(e.dir);await O5(e,t);let r=e.trackName.slice(0,38).trim(),o=await jn(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await M5(e,o),await G$(e.trackId,o.name,hq(e.task,!!e.repos),{kind:"subtask"}),await fR(e,t)}async function fR(e,t){await Za(e,"working");let n=z.join(e.dir,jp);if(await D5(n,e),e.canceled)throw new gl;if(await Za(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 tw(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:L$({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await sw(l.leadDir,l.base,e.branch,Xa),l.files=await aw(l.leadDir,l.base,e.branch,Xa);let d=await iw(l.leadDir,l.base,e.branch,Xa);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 tw(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:L$({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await sw(t.cwd,e.base,e.branch,Xa),e.files=await aw(t.cwd,e.base,e.branch,Xa);let s=await iw(t.cwd,e.base,e.branch,Xa);e.applied=s.applied,e.conflicts=s.conflicts}await vl(e);let r=await P5(e,t,n);await Za(e,"resume"),await G$(e.trackId,e.leadBox,wq(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume"}),await Za(e,"reap"),await sb(e),e.step="done";let o=Date.now();await lR(e.trackId,e.id,{...lf(e),finishedAt:o}),await C5(e,o),e.finishedAt=o}async function O5(e,t){let n=z.join(e.dir,z.dirname(dl));await Y.mkdir(n,{recursive:!0});let r="";try{r=await Qx(t.cwd,t.sessionId)}catch{}if(!r)try{r=await Y.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}
269
269
 
270
270
  **Delegated task:** ${e.task}
271
271
 
@@ -276,15 +276,15 @@ ${a}`}async function Wy(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<
276
276
  ## Conversation so far (lead \u2192 you)
277
277
 
278
278
  ${r}
279
- `;await Y.writeFile(z.join(e.dir,dl),o)}async function O5(e,t){let n=await ne(),r=fe(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:Ho(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),Ee(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]||{},...cf(e)},await ae())}async function M5(e,t=e.finishedAt){let n=await ne(),r=fe(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),Ee(r,"subtask-merged",{from:e.box,fromAgent:e.agent,task:e.task,subtaskId:e.id,stat:e.stat,conflicts:e.conflicts.length,files:e.files,durationMs:t?t-e.startedAt:null}),await ae()}async function C5(e){let t=await ne(),n=fe(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"),Ee(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]||{},...cf(e)},await ae()}async function N5(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=z.join(t.cwd,r);await Y.mkdir(z.dirname(o),{recursive:!0}),await Y.copyFile(n,o)}catch{}return r}async function sb(e){if(e.dir&&await $u(e.dir).catch(()=>{}),e.box&&await Lt(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await $t(t.leadDir,z.join(e.dir,t.name)).catch(()=>{});await Y.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await Se(e.leadBox).catch(()=>null))?.cwd;n&&await $t(n,e.dir).catch(()=>{})}}async function P5(e,t){let n=(t.startedAt||Date.now())+A5;for(;;){if(t.canceled||t.forceMerge)return;try{await Y.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await rr(T5)}}function rr(e){return new Promise(t=>setTimeout(t,e))}var qp,nr,U$,dq,ul,pq,Gp,yl,Eo,Io,by,fq,Lp,dl,mq,hq,Ht,oy,fe,sy,Ee,ay,iy,yq,jr,C$,xq,vq,Sq,Aq,N$,il,Iq,$q,my,J$,Cq,Ms,Y$,P$,Fq,Uq,Hq,Wq,qq,Qa,pl,zq,Yq,Xq,e5,Py,wy,xl,St,On,Fp,fl,nR,a5,cl,ll,i5,cy,u5,hl,d5,p5,B$,ly,h5,uy,gy,Jy,Ns,ii,Xy,Mn,Hp,Zy,x5,Bp,A5,T5,ni,Xa,Wt,E5,Ls,cf,vl,lf,gl,Ir=G(()=>{Wi();dt();Hh();AA();os();zr();qo();MA();xt();yn();Id();PA();Ys();zu();bd();es();_h();$h();oh();DA();mc();ch();Ju();gh();vn();Rd();Gr();an();pc();Pd();iT();fw();I_();dd();ld();R_();ng();be();sg();lp();Sp();va();gs();Qc();Va();Og();Op();Lg();Gn();wp();d$();Wg();b$();Pu();S$();Kg();Qg();ty();ry();qp=uq(lq),nr=process.env.BOSTRAT_STATE_DIR||z.join(process.env.HOME||"/tmp",".bostrat"),U$=z.join(nr,"tracks.json"),dq=z.join(nr,"events.jsonl"),ul=z.join(nr,"workspaces"),pq=process.env.BOSTRAT_DEFAULT_REPO||null,Gp={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"}},yl=Object.keys(Gp);Eo={at:0,value:null};Io=".bostrat/handoff/latest.md",by=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;fq=/\(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\.\)$/;Lp=".bostrat/handoff/subtask-result.md",dl=".bostrat/handoff/lead-context.md",mq=(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 ${dl} \u2014 read that first for context. Your scoped task:
279
+ `;await Y.writeFile(z.join(e.dir,dl),o)}async function M5(e,t){let n=await ne(),r=fe(n,e.trackId);r&&(r.boxes.push({name:t.name,agent:t.agent,role:"subtask",state:"live",cwd:t.cwd,sessionId:t.sessionId,hookTokenHash:Ho(t.hookToken),createdAt:Date.now(),subtaskId:e.id,branch:e.branch,task:e.task}),Ee(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]||{},...lf(e)},await ae())}async function C5(e,t=e.finishedAt){let n=await ne(),r=fe(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),Ee(r,"subtask-merged",{from:e.box,fromAgent:e.agent,task:e.task,subtaskId:e.id,stat:e.stat,conflicts:e.conflicts.length,files:e.files,durationMs:t?t-e.startedAt:null}),await ae()}async function N5(e){let t=await ne(),n=fe(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"),Ee(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]||{},...lf(e)},await ae()}async function P5(e,t,n){let r=`.bostrat/handoff/subtask-${e.id}.md`;try{let o=z.join(t.cwd,r);await Y.mkdir(z.dirname(o),{recursive:!0}),await Y.copyFile(n,o)}catch{}return r}async function sb(e){if(e.dir&&await $u(e.dir).catch(()=>{}),e.box&&await Lt(e.box).catch(()=>{}),e.repos&&e.dir){for(let t of e.repos)await $t(t.leadDir,z.join(e.dir,t.name)).catch(()=>{});await Y.rm(e.dir,{recursive:!0,force:!0}).catch(()=>{})}else if(e.dir){let n=(await Se(e.leadBox).catch(()=>null))?.cwd;n&&await $t(n,e.dir).catch(()=>{})}}async function D5(e,t){let n=(t.startedAt||Date.now())+A5;for(;;){if(t.canceled||t.forceMerge)return;try{await Y.access(e);return}catch{}if(Date.now()>n)throw new Error("subtask timed out without signaling completion (no result digest written)");await rr(E5)}}function rr(e){return new Promise(t=>setTimeout(t,e))}var Gp,nr,U$,pq,ul,fq,Kp,yl,Eo,Io,by,mq,jp,dl,hq,wq,Ht,oy,fe,sy,Ee,ay,iy,bq,jr,C$,vq,Sq,Tq,Aq,N$,il,$q,Rq,my,J$,Nq,Ms,Y$,P$,Uq,Hq,Wq,qq,Gq,Qa,pl,Jq,Xq,Zq,t5,Py,wy,xl,St,On,Up,fl,nR,i5,cl,ll,c5,cy,d5,hl,p5,f5,B$,ly,w5,uy,gy,Jy,Ns,ii,Xy,Mn,Wp,Zy,v5,Lp,A5,E5,ni,Xa,Wt,_5,Ls,lf,vl,uf,gl,Ir=G(()=>{Wi();dt();Hh();TT();os();zr();qo();MT();xt();yn();$d();PT();Ys();zu();kd();es();_h();$h();oh();DT();mc();ch();Yu();gh();vn();Od();Gr();an();pc();Dd();iA();fw();I_();pd();ud();R_();ng();be();sg();up();Tp();va();gs();Qc();Va();Og();Mp();Lg();Gn();gp();d$();Wg();b$();Pu();S$();Kg();Qg();ty();ry();Gp=dq(uq),nr=process.env.BOSTRAT_STATE_DIR||z.join(process.env.HOME||"/tmp",".bostrat"),U$=z.join(nr,"tracks.json"),pq=z.join(nr,"events.jsonl"),ul=z.join(nr,"workspaces"),fq=process.env.BOSTRAT_DEFAULT_REPO||null,Kp={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"}},yl=Object.keys(Kp);Eo={at:0,value:null};Io=".bostrat/handoff/latest.md",by=Number(process.env.BOSTRAT_HANDOFF_CHECKPOINT_TIMEOUT_MS)||9e4;mq=/\(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\.\)$/;jp=".bostrat/handoff/subtask-result.md",dl=".bostrat/handoff/lead-context.md",hq=(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 ${dl} \u2014 read that first for context. Your scoped task:
280
280
 
281
281
  ${e}
282
282
 
283
- 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 ${Lp} (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 ${dl} \u2014 read that first for context. Your scoped task:
283
+ 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 ${jp} (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 ${dl} \u2014 read that first for context. Your scoped task:
284
284
 
285
285
  ${e}
286
286
 
287
- 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 ${Lp} 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.`,hq=(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."),Ht=null,oy=null;fe=(e,t)=>e.tracks.find(n=>n.id===t)||null,sy=Promise.resolve();Ee=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),wq(e.id,r),uT(e,r),r};fm(async({sessionName:e,from:t,to:n,version:r,status:o,error:s})=>{let a=await ne(),i=e?a.tracks.find(l=>l.leadBox===e||(l.boxes||[]).some(u=>u.name===e)):null,c=i?[i]:o==="failed"?a.tracks.filter(l=>!l.archivedAt&&!l.transferredTo&&l.leadBox&&(l.boxes||[]).some(u=>u.name===l.leadBox&&u.agent==="codex")):[];if(c.length){for(let l of c)Ee(l,"codex-update",{box:e||l.leadBox,from:t,to:r||n,status:o,...s?{error:s}:{}});await ae().catch(()=>{})}});ay=z.join(nr,"plane-link","update-notice.json");iy=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),yq=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);jr=new Set(["merged","conflict","canceled","failed","handed-off"]),C$=new Map;xq=5e3;vq={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};Sq=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];Aq=10*6e4;N$=400;il=new Map,Iq=Math.max(1e3,Number(process.env.BOSTRAT_ANSWERING_TTL_MS)||15e3),$q=[100,200,300],my=new Map,J$=e=>cq("sha1").update(String(e||"")).digest("hex");Cq=1500,Ms=new Map;Y$="Hello. I've just logged in.";P$="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.";Fq=4e3,Uq=3,Hq=[300,350,400],Wq=1e3,qq=12,Qa=new Map,pl=new Map;zq=[250,400,500,600];Yq=3e4,Xq=[350,650,900];e5=12e4;Py=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}))});wy=new Map,xl=e=>wy.get(e)||(Ht?fe(Ht,e)?.reshape:null)||null,St=(e,t=409)=>Object.assign(new Error(e),{status:t});On=e=>Y.access(e).then(()=>!0,()=>!1),Fp=(e,t,n)=>qp("git",["-C",e,"worktree","move","--end-of-options",t,n],{timeout:6e4});fl="# bostrat workspace",nR=`${fl}
287
+ 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 ${jp} 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.`,wq=(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."),Ht=null,oy=null;fe=(e,t)=>e.tracks.find(n=>n.id===t)||null,sy=Promise.resolve();Ee=(e,t,n={})=>{let r={at:Date.now(),type:t,...n};return e.events.push(r),gq(e.id,r),uA(e,r),r};mm(async({sessionName:e,from:t,to:n,version:r,status:o,error:s})=>{let a=await ne(),i=e?a.tracks.find(l=>l.leadBox===e||(l.boxes||[]).some(u=>u.name===e)):null,c=i?[i]:o==="failed"?a.tracks.filter(l=>!l.archivedAt&&!l.transferredTo&&l.leadBox&&(l.boxes||[]).some(u=>u.name===l.leadBox&&u.agent==="codex")):[];if(c.length){for(let l of c)Ee(l,"codex-update",{box:e||l.leadBox,from:t,to:r||n,status:o,...s?{error:s}:{}});await ae().catch(()=>{})}});ay=z.join(nr,"plane-link","update-notice.json");iy=(e,t,n)=>t!=null&&n.some(r=>e===r.box&&t>=r.from&&t<=r.to),bq=new Set(["stuck","wrong-approach","too-slow","want-different-model","context-refresh","cost","parallelize","other"]);jr=new Set(["merged","conflict","canceled","failed","handed-off"]),C$=new Map;vq=5e3;Sq={claude:[/^\[Request interrupted by user(?: for tool use)?\]$/i],codex:[/^\[?Request interrupted/i,/^Conversation interrupted/i],cursor:[/^\[?Request interrupted/i]};Tq=[/^\/model(?:\s|$)/i,/<command-(?:name|message|args)>[^<]*\bmodel\b/i,/^Model changed to\b/i];Aq=10*6e4;N$=400;il=new Map,$q=Math.max(1e3,Number(process.env.BOSTRAT_ANSWERING_TTL_MS)||15e3),Rq=[100,200,300],my=new Map,J$=e=>lq("sha1").update(String(e||"")).digest("hex");Nq=1500,Ms=new Map;Y$="Hello. I've just logged in.";P$="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.";Uq=4e3,Hq=3,Wq=[300,350,400],qq=1e3,Gq=12,Qa=new Map,pl=new Map;Jq=[250,400,500,600];Xq=3e4,Zq=[350,650,900];t5=12e4;Py=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}))});wy=new Map,xl=e=>wy.get(e)||(Ht?fe(Ht,e)?.reshape:null)||null,St=(e,t=409)=>Object.assign(new Error(e),{status:t});On=e=>Y.access(e).then(()=>!0,()=>!1),Up=(e,t,n)=>Gp("git",["-C",e,"worktree","move","--end-of-options",t,n],{timeout:6e4});fl="# bostrat workspace",nR=`${fl}
288
288
 
289
289
  TRACK MEMORY: if \`.bostrat/memory/MEMORY.md\` exists in your workspace, read it
290
290
  before substantive work \u2014 it is the shared cross-provider memory for this repo
@@ -684,16 +684,16 @@ for the same follow-up at the same moment twice; run bostrat-followup ls first
684
684
  specifics (no PR numbers, URLs, SHAs, tags \u2014 the card supplies them), and HOLD
685
685
  HERE after proposing until the operator answers the card. Bostrat never runs a
686
686
  follow-up on its own; the operator's tap is the gate.
687
- `,a5=nR,cl=nR+Jv;ll=e=>typeof e=="string"&&(e===fl||e.startsWith(`${fl}
688
- `)),i5="# bostrat multi-repo workspace";cy=cl.replace(`${fl}
687
+ `,i5=nR,cl=nR+Jv;ll=e=>typeof e=="string"&&(e===fl||e.startsWith(`${fl}
688
+ `)),c5="# bostrat multi-repo workspace";cy=cl.replace(`${fl}
689
689
  `,`${fl}
690
690
 
691
691
  (Global copy managed by bostrat \u2014 rewritten on service start; edits will be lost.)
692
692
  SCOPE: these instructions apply ONLY when your working directory is under
693
693
  ~/.bostrat/workspaces/ or ~/.bostrat/worktrees/ \u2014 a bostrat-orchestrated box.
694
694
  When working anywhere else, ignore everything below.
695
- `);u5=new Set(["claude","codex","cursor"]);hl=new Set,d5=e=>hl.has(e);p5=9e4;B$={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};ly=new Map;h5=6e4,uy=new Map;gy=120;Jy=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:Ho(e.hookToken),createdAt:Date.now()});Ns=new Map,ii=e=>Ns.get(e)||(Ht?fe(Ht,e)?.handoff:null)||null;Xy=6e4,Mn=(e,t,n=15e3)=>qp("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),Hp=new Map,Zy=e=>Hp.get(e)||null;x5=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,200}$/;Bp=new Map;A5=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,T5=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,ni=z.join(nr,"worktrees"),Xa=[dl,Lp],Wt=new Map,E5=e=>Wt.get(e)||(Ht?Ht.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,Ls=e=>{let t=new Map([...Wt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=Ht?fe(Ht,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)},cf=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});vl=e=>lR(e.trackId,e.id,cf(e));lf=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",gl=class extends Error{}});dt();import Re from"node:path";import Et from"node:fs";import A3 from"node:readline";import{fileURLToPath as T3}from"node:url";import nn from"express";import rN from"node:http";import E3 from"node:https";import eu from"node:os";import{randomUUID as _3}from"node:crypto";import{WebSocketServer as I3}from"ws";dt();import i1 from"node-pty";async function Ox(e,t,n={}){if(!je(t)){Gu(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await Zr()){Gu(e,`host tmux server not running on ${zt}`),e.close(1011,"tmux server unavailable");return}if(!await Se(t)){let a=!1;if(typeof n.revive=="function"&&(Ku(e,{type:"notice",message:"Resuming the lead box\u2026"}),a=await n.revive().catch(()=>!1)),!a||!await Se(t)){Gu(e,`session "${t}" not found`),e.close(1008,"session not found");return}if(e.readyState!==e.OPEN)return}let r=Rx(n.cols,120,Mx),o=Rx(n.rows,32,Cx),s;try{s=i1.spawn(oe,["-S",zt,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){Gu(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&Ku(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(Ku(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"&&d1(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{}u1(t)})}var c1=6,l1=250;async function u1(e,t=c1,n=l1){for(let r=0;r<t;r++){if(await Xo(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var Mx=20,Cx=6;function d1(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=Mx&&Number(t)>=Cx}function Rx(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function Ku(e,t){try{e.send(JSON.stringify(t))}catch{}}function Gu(e,t){Ku(e,{type:"error",message:t})}function Nx(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}}vn();zu();Hh();Ir();import{createRequire as $3}from"node:module";var D5=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function ab({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(D5)&&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}}Qg();be();Qc();Gn();pp();an();var df=60*6e4,B5=1440*6e4,L5=new Set(["merged","closed","lost"]),Sl=(e,t,n)=>Number.isFinite(Number(e))&&n-Number(e)<=t;function j5({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)<=xg&&s.push("ship"),r>0&&s.push("create-net");for(let a of n||[]){if(!a||L5.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&&Sl(a.ciFix.delegatedAt,df,o)&&s.push(`ci-fix#${l}`),a.reconcile&&Sl(a.reconcile.delegatedAt,df,o)&&s.push(`reconcile#${l}`),a.ciFixAwait&&Sl(a.ciFixAwait.since,df,o)&&s.push(`ci-fix-await#${l}`),a.reconcileAwait&&Sl(a.reconcileAwait.since,df,o)&&s.push(`reconcile-await#${l}`);let u=a.autoMerge?.armedAt??a.armedAt??null;a.trackId===e&&(a.autoMerge||a.armedAt)&&Sl(u,B5,o)&&s.push(`auto-merge#${l}`)}return s}var pf=new Map;Ze.on("event",e=>{e?.trackId&&pf.delete(e.trackId)});async function F5(e){if(pf.has(e.id))return pf.get(e.id);let t=await K(e).catch(()=>[]),n=qa(t,-1/0);return pf.set(e.id,n),n}async function hR(e,{now:t=Date.now()}={}){let n=new Map,r=await En().catch(()=>[]);for(let o of e||[]){if(!o||Ue(o))continue;let s=j5({trackId:o.id,shipPending:await F5(o),links:r,observers:zE(o.id),now:t});s.length&&n.set(o.id,s)}return n}Kg();import _R from"node:fs";import Ro from"node:fs/promises";import sG from"node:os";import kt from"node:path";import{spawn as aG}from"node:child_process";import{createRequire as iG}from"node:module";be();Pd();import ci from"node:fs";import Tl from"node:fs/promises";import W5 from"node:http";import Ot from"node:path";import mf from"node:os";import{createRequire as q5}from"node:module";import cb from"ws";import U5 from"node:path";import H5 from"node:os";var Al=process.env.BOSTRAT_STATE_DIR||U5.join(process.env.HOME||H5.tmpdir(),".bostrat");function ib(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 wR(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=ib(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function gR(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}bm();var Cn=(()=>{try{return q5(import.meta.url)("../package.json").version||null}catch{return null}})(),ub=process.env.BOSTRAT_STATE_DIR||Ot.join(process.env.HOME||mf.tmpdir(),".bostrat"),AR=Ot.join(ub,"plane-link","removed.json");function yR(e){return typeof e!="string"||e.length<8?"\u2022\u2022\u2022\u2022":`${e.slice(0,6)}\u2026${e.slice(-4)}`}function G5(e=AR){try{let t=JSON.parse(ci.readFileSync(e,"utf8"));return t&&typeof t=="object"?t:null}catch{return null}}function js({env:e=process.env,pkgDir:t=Ot.resolve(Ot.dirname(new URL(import.meta.url).pathname),".."),exists:n=ci.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(Ot.join(t,"..",".git"))?"git-checkout":"dev"}function El(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 ff(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 K5({home:e=process.env.HOME||mf.homedir(),env:t=process.env}={}){let n=r=>{try{return ci.statSync(r),!0}catch{return!1}};return{claude:n(Ot.join(e,".claude",".credentials.json")),codex:n(Ot.join(t.CODEX_HOME||Ot.join(e,".codex"),"auth.json")),cursor:n(Ot.join(t.XDG_CONFIG_HOME||Ot.join(e,".config"),"cursor","auth.json"))}}var mt=1,bR=1e3,kR=3e4,V5=6e4,z5=1500,J5=500,$o=100,Y5=2e3,X5=25e3,Z5=2.5,Q5=6e4,TR=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},eG=TR(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),tG=3e4,xR=10*6e4,nG=400,vR=250,rG=TR(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),lb=4,oG=6e4,SR=6e4;function ER({url:e,token:t,nodeId:n=mf.hostname(),name:r=mf.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,deliverySample:c=null,onHashKey:l=null,onViewBase:u=null,metricsMs:d=oG,onUpdateAvailable:p=null,onUpdatePolicy:f=null,onHelloRefused:w=null,updatePolicy:h=null,installKind:y=js(),selfUrl:k=`http://127.0.0.1:${process.env.PORT||3362}`,apiToken:g=null,removedMarkerFile:x=AR,onRemoved:S=null,onDegraded:_=null,onRecovered:M=null,onConnected:P=null,ingestMode:j=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:T=eG,unackedRetryMs:$=Q5,pingMs:L=X5,deadLinkMs:H=Math.round(L*Z5),maxInflightEvents:R=nG,httpTimeoutMs:A=rG,stallBackoffMinMs:C=tG,fetchImpl:W=globalThis.fetch,log:B=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=gR(e);let Z=k.replace(/^http/,"ws"),xe=new Set,Ae=new Map,_e=new Map,Q=Ot.join(ub,"plane-link","cursor.json"),Xe=Ot.join(ub,"plane-link","dead-letter.ndjson"),Pe=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),le={},ge={},de=new Map,te=null,we=null,Oe=0,Ve=0,Nt=0,O=Promise.resolve(),X="ws",re=0,he=!1,Be=0,Pt=!1,tt=$o,wn=new Set,Kt=[],ht=null,wt=null,at=!1,Ti=!1,gt=bR,cr=null,Hr=null,lr=null,gn=null,ur=0,b=0,m=null,v=!1,D=0,J=!1,ie=G5(x);if(ie)if(ie.tokenPreview===yR(t))J=!0,ym({reason:ie.reason??"removed",at:ie.at??null,nodeId:ie.nodeId??n}),B.error(`[plane-link] this node was REMOVED from the plane (${ie.reason??"removed"}${ie.at?` at ${new Date(ie.at).toISOString()}`:""}) \u2014 not dialing. Re-provision it with a new node token, or delete ${x} to force a dial.`);else try{ci.unlinkSync(x),B.log("[plane-link] stale removed-marker discarded \u2014 the node token changed")}catch{}function ve({reason:F="removed",at:q=Date.now(),via:U="ctl"}={}){if(!J){J=!0,ym({reason:F,at:q,nodeId:n,via:U});try{ci.mkdirSync(Ot.dirname(x),{recursive:!0}),ci.writeFileSync(x,JSON.stringify({at:q,reason:F,via:U,nodeId:n,tokenPreview:yR(t)},null,2))}catch(I){B.error(`[plane-link] could not write ${x}: ${I?.message||I}`)}B.error(`[plane-link] the plane REMOVED this node (${F}, via ${U}) \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{S?.({reason:F,at:q,via:U})}catch{}zk({bye:!1})}}async function _t(){try{le=JSON.parse(await Tl.readFile(Q,"utf8"))}catch{le={}}}function yt(){v=!0,!lr&&(lr=setTimeout(async()=>{if(lr=null,!!v){v=!1;try{await Tl.mkdir(Ot.dirname(Q),{recursive:!0}),await Tl.writeFile(Q,JSON.stringify(le))}catch(F){B.error("[plane-link] cursor flush failed:",F?.message||F)}}},Y5),lr.unref?.())}function nt(F){return!wt||wt.readyState!==cb.OPEN?!1:(wt.send(JSON.stringify(F)),!0)}function rn(F){let q=Date.now();for(let{trackId:U,event:I}of F){let V=de.get(I.id);de.set(I.id,{trackId:U,seq:I.seq,event:I,sentAt:q,firstSentAt:V?.firstSentAt??q,retryAt:q+$,tries:(V?.tries??0)+1,nacks:V?.nacks??0})}return X==="http"?(vN(F),!0):nt({v:mt,ch:"events",type:"append",events:F})}function yN(F){let q=null;for(let U of de.values())U.trackId===F&&(q==null||U.seq<q)&&(q=U.seq);return q}function em(F){let q=ge[F];if(q==null)return;let U=yN(F),I=U==null?q:Math.min(q,U-1);I>(le[F]??0)&&(le[F]=I,yt())}function Ei(){if(te=Date.now(),we!=null){let F=Date.now()-we;B.log(`[plane-link] spine sync recovered after ${Math.round(F/1e3)}s degraded (${Oe} stall redial(s))`);let q=we;we=null,Oe=0,Ve=0,he=!1,Be=0;try{M?.({since:q,downMs:F})}catch(U){B.error(`[plane-link] onRecovered failed: ${U?.message||U}`)}}}function tm(F){if(!Array.isArray(F)||!F.length)return;let q=new Set;for(let U of F){let I=de.get(U);I&&(de.delete(U),(ge[I.trackId]??0)<I.seq&&(ge[I.trackId]=I.seq),q.add(I.trackId))}for(let U of q)em(U);Ei()}function Fk(F,q){Nt++;let U={at:Date.now(),trackId:F.trackId,seq:F.seq,id:F.event?.id??null,type:F.event?.type??null,reason:q,event:F.event??null};B.error(`[plane-link] DEAD-LETTER ${F.trackId} seq ${F.seq} (${U.type??"?"}): plane rejected it permanently (${q}) \u2014 kept in ${Xe}`),O=O.then(async()=>{await Tl.mkdir(Ot.dirname(Xe),{recursive:!0}),await Tl.appendFile(Xe,JSON.stringify(U)+`
696
- `)}).catch(I=>B.error(`[plane-link] dead-letter write failed: ${I?.message||I}`))}function Uk(F,q,U,I=null){if(!Array.isArray(F)||!F.length)return;let V=new Set,Ie=Date.now();for(let ye of F){let Le=de.get(ye);Le&&(U?(de.delete(ye),Fk(Le,q),(ge[Le.trackId]??0)<Le.seq&&(ge[Le.trackId]=Le.seq),V.add(Le.trackId)):(Le.nacks++,Le.retryAt=Ie+Math.max(1e3,Number(I)||$)))}for(let ye of V)em(ye);Ei()}function Hk(F=Date.now()){let q=1/0;for(let U of de.values())U.firstSentAt<q&&(q=U.firstSentAt);return q===1/0?0:F-q}function bN(F){if(!H||!F||F!==wt||!ur)return!1;let q=Date.now()-ur;if(q<=H)return!1;b++,B.error(`[plane-link] no frame from the plane for ${Math.round(q/1e3)}s \u2014 link is half-open; terminating and redialing`);try{F.terminate()}catch{}return!0}function Wk(){if(!at||!de.size)return;let F=Date.now(),q=Hk(F);if(q<T||te!=null&&F-te<T||X==="http"&&he||Ve>F)return;Oe++;let U=Math.min(C*2**(Oe-1),xR);if(we==null){we=F-q,B.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(q/1e3)}s with ${de.size} event(s) in flight (${X} door) \u2014 the plane is not answering appends`);try{_?.({since:we,unacked:de.size,oldestAgeMs:q,mode:X})}catch(I){B.error(`[plane-link] onDegraded failed: ${I?.message||I}`)}}if(X==="http"){he=!0,Be=F+U,B.error(`[plane-link] ingest circuit OPEN (stall #${Oe}); probing /v1/ingest/health in ${Math.round(U/1e3)}s`);return}Ve=F+U,B.error(`[plane-link] closing the link and redialing in ${Math.round(U/1e3)}s (stall redial #${Oe})`);try{wt?.terminate()}catch{}}function nm(){if(!at)return;let F=Date.now();if(X==="http"&&he)return;let q=[...de.values()].filter(I=>I.event&&I.retryAt<=F&&!(X==="http"&&wn.has(I.trackId)));if(!q.length)return;q.sort((I,V)=>I.trackId===V.trackId?I.seq-V.seq:I.trackId<V.trackId?-1:1),B.log(`[plane-link] re-sending ${q.length} unacked event(s) the plane never confirmed`);let U=X==="http"?tt:$o;if(X==="http"){let I=new Map;for(let V of q)(I.get(V.trackId)??I.set(V.trackId,[]).get(V.trackId)).push(V);for(let[,V]of I){if(re>=lb)return;rn(V.slice(0,U).map(Ie=>({trackId:Ie.trackId,event:Ie.event})))}return}for(let I=0;I<q.length;I+=U){let V=q.slice(I,I+U).map(Ie=>({trackId:Ie.trackId,event:Ie.event}));if(!rn(V))return}}async function kN(F=null){for(;;){if(!at)return!1;let q=de.size<R,U=X!=="http"||re<lb&&!he&&(!F||!wn.has(F));if(q&&U)return!0;await new Promise(I=>setTimeout(I,100))}}function rm(){if(ht=null,!at||!Kt.length)return;let F=Kt;if(Kt=[],X!=="http"){for(let U=0;U<F.length;U+=$o)rn(F.slice(U,U+$o));return}let q=new Map;for(let U of F)(q.get(U.trackId)??q.set(U.trackId,[]).get(U.trackId)).push(U);for(let[U,I]of q){if(wn.has(U)||re>=lb||he){Kt.push(...I);continue}for(let V=0;V<I.length;V+=tt)rn(I.slice(V,V+tt))}Kt.length&&!ht&&(ht=setTimeout(rm,vR),ht.unref?.())}let xN=F=>{let q=new Map;for(let{trackId:U,event:I}of F)(q.get(U)??q.set(U,[]).get(U)).push(I);return[...q].map(([U,I])=>({trackId:U,events:I}))},Uo=(F,q,U,{progress:I})=>{let V=Date.now();for(let{event:Ie}of F){let ye=de.get(Ie.id);ye&&(ye.nacks++,ye.retryAt=V+Math.max(1e3,U||$))}I&&Ei()};async function vN(F){let q=new Set(F.map(U=>U.trackId));for(let U of q)wn.add(U);re++;try{let U=await W(`${Pe}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:xN(F)}),signal:AbortSignal.timeout(A)}),I=(Number(U.headers.get("retry-after"))||0)*1e3;if(U.status===200){let V=await U.json();tt=$o;for(let Ie of V.results??[]){tm(Ie.acked??[]);let ye=(Le,ut)=>{let on=new Map;for(let it of Le??[])(on.get(it.reason)??on.set(it.reason,[]).get(it.reason)).push(it.id);for(let[it,Jk]of on)Uk(Jk,it,ut,V.retryAfterMs??null)};ye(Ie.rejected,!0),ye(Ie.deferred,!1)}tm(V.discarded??[]),Ei();return}if(U.status===429){Uo(F,"overloaded",I||5e3,{progress:!0});return}if(U.status===413&&F.length>1){tt=Math.max(1,Math.floor(F.length/2)),B.error(`[plane-link] ingest request too large (${F.length} events) \u2014 halving batches to ${tt}`),Uo(F,"too_large",1e3,{progress:!0});return}if(U.status===413){let V=de.get(F[0].event.id);V&&(de.delete(V.event.id),Fk(V,"too_large"),(ge[V.trackId]??0)<V.seq&&(ge[V.trackId]=V.seq),em(V.trackId)),Ei();return}if(U.status===410){ve({reason:"removed",via:"410"}),Uo(F,"http_410",6e4,{progress:!1});return}if(U.status===401||U.status===403){let{tripped:V,holdMs:Ie}=ta();if(V&&B.error(`[plane-link] holding every plane call for ${Math.round(Ie/6e4)} min \u2014 the ingest door refused this node's token three times in a row`),Date.now()-D>=SR){D=Date.now();let ye="";try{ye=(await U.json())?.error??""}catch{}B.error(`[plane-link] plane refused ingest (HTTP ${U.status}${ye?`: ${ye}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}Uo(F,`http_${U.status}`,Math.max(6e4,Di()),{progress:!1});return}if(U.status===400){B.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${F.length} event(s) for retry; this is a bug, not data`),Uo(F,"http_400",6e4,{progress:!1});return}Uo(F,`http_${U.status}`,I||5e3,{progress:!1})}catch(U){let I=U?.name==="TimeoutError"||U?.name==="AbortError";I&&F.length>1&&(tt=Math.max(1,Math.floor(F.length/2)),B.error(`[plane-link] ingest request of ${F.length} event(s) outlived its ${A} ms deadline \u2014 halving batches to ${tt}`)),Uo(F,I?"timeout":"network",5e3,{progress:!1})}finally{re--;for(let U of q)wn.delete(U)}}async function SN(){if(X!=="http"||!he||!at||Pt)return;let F=Date.now();if(!(Be>F||na(F))){Pt=!0;try{let q=await W(`${Pe}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(A)});if(!q.ok)throw new Error(`HTTP ${q.status}`);B.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),he=!1,Be=0,Ve=Date.now()+A+$+1e3;for(let U of de.values())U.retryAt=Math.min(U.retryAt,Date.now());nm()}catch(q){Oe++;let U=Math.min(C*2**(Oe-1),xR);Be=Date.now()+U,B.error(`[plane-link] ingest door still not answering (${q?.message||q}); next probe in ${Math.round(U/1e3)}s`)}finally{Pt=!1}}}function qk(){let F=Date.now();return{mode:X,unacked:de.size,oldestUnackedAgeMs:Hk(F),lastProgressAt:te,degradedSince:we,stallRedials:Oe,deadLettered:Nt,http:X==="http"?{inFlight:re,circuitOpen:he,nextProbeInMs:he?Math.max(0,Be-F):0,batchCap:tt}:null}}async function Gk(){if(!i)return;let F;try{F=await i()}catch(U){B.error("[plane-link] metrics sample failed:",U?.message||U);return}let q=null;try{q=c?.()??null}catch{}F&&nt({v:mt,ch:"ctl",type:"metrics",metrics:{...F,planeLink:qk(),...q?{delivery:q}:{}}})}function AN(){i&&(m&&clearInterval(m),Gk(),m=setInterval(Gk,d),m.unref?.())}async function TN(){let F;try{F=await o()}catch(q){B.error("[plane-link] backfill listTracks failed:",q?.message||q);return}nt({v:mt,ch:"ctl",type:"tracks",ids:F.filter(q=>!q.transferredTo).map(q=>q.id).filter(q=>typeof q=="string")});for(let q of F){if(!at)return;let U;try{U=await K(q)}catch{continue}let I=le[q.id]??0,V=U.filter(ye=>ye.seq>I&&typeof ye.id=="string"),Ie=X==="http"?tt:$o;for(let ye=0;ye<V.length;ye+=Ie){if(!await kN(q.id))return;let Le=V.slice(ye,ye+Math.min(Ie,X==="http"?tt:$o)).map(ut=>({trackId:q.id,event:ut}));if(!rn(Le))return}}}function Kk(F){!at||!F?.trackId||typeof F.id!="string"||(Kt.push({trackId:F.trackId,event:F}),ht||(ht=setTimeout(rm,vR),ht.unref?.()))}let _i=new Map;async function EN(F){let{reqId:q,method:U,path:I,headers:V={},body:Ie}=F,ye=Object.fromEntries(Object.entries(V).filter(([,ut])=>ut!=null)),Le=new AbortController;_i.set(q,Le);try{if(F.host){await _N(F,ye,Le);return}g&&(ye["x-bostrat-token"]=g);let ut=await fetch(k+I,{method:U,headers:ye,body:Ie?Buffer.from(Ie,"base64"):void 0,signal:Le.signal}),on=Object.fromEntries(ut.headers);for(let it of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete on[it];if(on["content-type"]||(on["content-type"]="application/octet-stream"),nt({v:mt,ch:"control",type:"http_head",reqId:q,status:ut.status,headers:on}),ut.body){for await(let it of ut.body)if(!nt({v:mt,ch:"control",type:"http_data",reqId:q,data:Buffer.from(it).toString("base64")}))break}nt({v:mt,ch:"control",type:"http_end",reqId:q,error:null})}finally{_i.delete(q)}}function _N(F,q,U){let{reqId:I,method:V,path:Ie,body:ye}=F,Le=new URL(k);return new Promise(ut=>{let on=W5.request({host:Le.hostname,port:Le.port,method:V,path:Ie,headers:{...q,host:F.host},signal:U.signal},it=>{let{connection:Jk,"keep-alive":z3,"transfer-encoding":J3,upgrade:Y3,...IN}=it.headers;nt({v:mt,ch:"control",type:"http_head",reqId:I,status:it.statusCode||502,headers:IN}),it.on("data",$N=>{nt({v:mt,ch:"control",type:"http_data",reqId:I,data:Buffer.from($N).toString("base64")})||it.destroy()}),it.on("end",()=>{nt({v:mt,ch:"control",type:"http_end",reqId:I,error:null}),ut()}),it.on("error",()=>{nt({v:mt,ch:"control",type:"http_end",reqId:I,error:"view upstream error"}),ut()})});on.on("error",it=>{nt({v:mt,ch:"control",type:"http_end",reqId:I,error:it?.message||"view request failed"}),ut()}),ye&&on.write(Buffer.from(ye,"base64")),on.end()})}function Vk(){if(Ti||J)return;wt=new cb(e,{headers:{authorization:`Bearer ${t}`}});let F=wt;ur=0,F.on("ping",()=>{ur=Date.now()}),F.on("pong",()=>{ur=Date.now()}),wt.on("open",async()=>{let U=null;try{U=await s?.()||null}catch{U=null}nt({v:mt,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:Cn,installKind:y,...typeof h=="function"?{updatePolicy:h()}:h?{updatePolicy:h}:{},providers:K5(),...U?{agents:U}:{}})}),wt.on("message",U=>{ur=Date.now();let I;try{I=JSON.parse(U)}catch{return}if(I.ch==="ctl"&&I.type==="hello_ok"){at=!0,gt=bR,cr=null,y0(),B.log(`[plane-link] connected to plane as ${n}`);try{P?.()}catch{}if(typeof I.hashKey=="string"&&I.hashKey)try{l?.(I.hashKey)}catch{}try{u?.(typeof I.viewBase=="string"&&I.viewBase?I.viewBase:null)}catch{}I.minNodeVersion&&Cn&&El(Cn,I.minNodeVersion)&&B.error(`[plane-link] this node is bostrat-node ${Cn}; the plane asks for \u2265${I.minNodeVersion} \u2014 update with: ${ff(y)}`);try{f?.(typeof I.updatePolicy=="string"?I.updatePolicy:null)}catch{}let V=typeof I.latestNodeVersion=="string"?I.latestNodeVersion:null;if(V&&Cn&&El(Cn,V)&&!xe.has(V)){xe.add(V),B.log(`[plane-link] bostrat-node ${V} is available (this node runs ${Cn}) \u2014 ${ff(y)}`);try{p?.({current:Cn,latest:V,min:I.minNodeVersion??null,installKind:y,required:!!(I.minNodeVersion&&El(Cn,I.minNodeVersion))})}catch(ye){B.error(`[plane-link] update notice failed: ${ye?.message||ye}`)}}let Ie=I.ingest==="http";X=j==="ws"?"ws":j==="http"||Ie?"http":"ws",j==="http"&&!Ie&&B.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),X==="http"&&B.log("[plane-link] spine rides the HTTPS ingest door"),he=!1,Be=0,tt=$o,gn&&clearInterval(gn),ur=Date.now(),gn=setInterval(()=>{bN(F)||(nt({v:mt,ch:"ctl",type:"ping"}),Wk(),SN().catch(()=>{}),nm(),Kt.length&&!ht&&rm())},L),gn.unref?.(),AN(),TN().catch(ye=>B.error("[plane-link] backfill failed:",ye?.message||ye));return}if(I.ch==="ctl"&&I.type==="hello_refused"){let V=typeof I.minNodeVersion=="string"?I.minNodeVersion:null,Ie=typeof I.latestNodeVersion=="string"?I.latestNodeVersion:null;B.error(`[plane-link] plane REFUSED this node: bostrat-node ${Cn??"?"} is below its minimum ${V??"?"} \u2014 ${I.fix||ff(y)}`),gt=kR,cr=0;try{w?.({current:Cn,min:V,latest:Ie,fix:I.fix||ff(y),installKind:y})}catch(ye){B.error(`[plane-link] refusal handler failed: ${ye?.message||ye}`)}return}if(I.ch==="ctl"&&I.type==="removed"){nt({v:mt,ch:"ctl",type:"removed_ack",nodeId:n}),ve({reason:typeof I.reason=="string"?I.reason:"removed",at:Number(I.at)||Date.now(),via:"ctl"});return}if(I.ch==="ctl"&&I.type==="update_policy"){try{f?.(typeof I.mode=="string"?I.mode:null)}catch{}return}if(I.ch==="ctl"&&I.type==="usage_caps"){Nd(I.caps??{},{source:"plane",updatedAt:I.updatedAt??Date.now()}).then(V=>B.log(`[plane-link] spend caps ${Object.keys(V.caps).length?`updated (${Object.keys(V.caps).join(", ")})`:"cleared"} from plane`)).catch(V=>B.error("[plane-link] spend-caps push rejected:",V?.message||V));return}if(I.ch==="ctl"&&I.type==="transferred"&&Array.isArray(I.tracks)){Promise.resolve().then(()=>a?.(I.tracks)).catch(V=>B.error("[plane-link] transfer notice failed:",V?.message||V));return}if(I.ch==="events"&&I.type==="ack"&&Array.isArray(I.ids)){tm(I.ids);return}if(I.ch==="events"&&I.type==="nack"&&Array.isArray(I.ids)){Uk(I.ids,I.reason,I.permanent===!0,I.retryAfterMs??null);return}if(I.ch==="control"&&I.type==="http_open"){EN(I).catch(V=>nt({v:mt,ch:"control",type:"http_end",reqId:I.reqId,error:V?.message||"tunnel error"}));return}if(I.ch==="control"&&I.type==="http_cancel"){_i.get(I.reqId)?.abort();return}if(I.ch==="attach"&&I.type==="open"){let V=new cb(Z+I.path,Array.isArray(I.protocols)?I.protocols:[],I.host?{headers:{host:I.host}}:void 0);Ae.set(I.streamId,V),_e.set(I.streamId,[]),V.on("open",()=>{let ye=_e.get(I.streamId)||[];_e.delete(I.streamId);for(let{buf:Le,bin:ut}of ye)V.send(Le,{binary:ut})}),V.on("message",(ye,Le)=>{let ut=Le?ye:Buffer.from(String(ye));nt({v:mt,ch:"attach",type:"data",streamId:I.streamId,data:ut.toString("base64"),...Le?{bin:!0}:{}})});let Ie=()=>{_e.delete(I.streamId),Ae.delete(I.streamId)&&nt({v:mt,ch:"attach",type:"close",streamId:I.streamId})};V.on("close",Ie),V.on("error",Ie);return}if(I.ch==="attach"&&I.type==="data"){let V=Ae.get(I.streamId);if(!V)return;let Ie=Buffer.from(I.data,"base64"),ye=I.bin===!0,Le=_e.get(I.streamId);Le?Le.push({buf:Ie,bin:ye}):V.send(Ie,{binary:ye});return}if(I.ch==="attach"&&I.type==="close"){let V=Ae.get(I.streamId);Ae.delete(I.streamId),_e.delete(I.streamId),V?.close();return}});let q=()=>{at&&B.log("[plane-link] disconnected from plane"),at=!1,gn&&(clearInterval(gn),gn=null),m&&(clearInterval(m),m=null),de.clear(),ge={},Kt=[],ht&&(clearTimeout(ht),ht=null),wn.clear();for(let V of Ae.values())V.close();Ae.clear(),_e.clear();for(let V of _i.values())V.abort();if(_i.clear(),Ti||Hr)return;cr==null&&(cr=Date.now());let U=Date.now()-cr<V5,I=Math.max(U?z5+Math.random()*J5:gt,Ve-Date.now(),Di());Hr=setTimeout(()=>{Hr=null,Vk()},I),Hr.unref?.(),U||(gt=Math.min(gt*2,kR))};wt.on("close",q),wt.on("error",U=>{let I=/Unexpected server response: (\d+)/.exec(U?.message||"")?.[1];if(I==="410"){ve({reason:"removed",via:"410"});return}if(I==="401"||I==="403"){let{tripped:V,holdMs:Ie}=ta();V?B.error(`[plane-link] holding every plane call for ${Math.round(Ie/6e4)} min \u2014 three credential refusals in a row (HTTP ${I}) 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(Ie/6e4)} min.`):Date.now()-D>=SR&&(D=Date.now(),B.error(`[plane-link] plane refused this node's credentials (HTTP ${I}) \u2014 the token was revoked or is unknown to the plane; mint a new node token and update this node's BOSTRAT_PLANE_TOKEN (still retrying)`))}q()})}Ze.on("event",Kk),_t().then(Vk);function zk({bye:F=!0}={}){Ti=!0,Ze.off("event",Kk),Hr&&clearTimeout(Hr),lr&&clearTimeout(lr),gn&&clearInterval(gn),m&&clearInterval(m),ht&&clearTimeout(ht),F&&nt({v:mt,ch:"ctl",type:"bye",reason:"shutdown"}),wt?.close()}return{stop:()=>zk(),status:()=>({connected:at,nodeId:n,cursor:{...le},inflight:de.size,...qk(),auth:b0(),dormant:J,removed:yu(),deadLinkMs:H,deadLinkRedials:b}),_tick:()=>{Wk(),nm()}}}qo();var hf=(()=>{try{return iG(import.meta.url)("../package.json").version||null}catch{return null}})(),cG=process.env.BOSTRAT_STATE_DIR||kt.join(process.env.HOME||sG.tmpdir(),".bostrat"),IR=kt.join(cG,"self-update"),wf=kt.join(IR,"status.json"),lG=1440*6e4,uG=6e4,_l=new Set(["npm-global","git-checkout"]);function $R({kind:e=js(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:_l.has(e)?e==="git-checkout"||dG(t)?"auto":"prompt":"off"}function dG(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var Qt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function pG({kind:e,to:t,from:n=hf,statusFile:r=wf,logFile:o=kt.join(IR,"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||kt.resolve(kt.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!_l.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=(y,k="")=>`write_status ${Qt(y)} ${k}`,p=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${Qt(i)}`,f=`
695
+ `);d5=new Set(["claude","codex","cursor"]);hl=new Set,p5=e=>hl.has(e);f5=9e4;B$={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};ly=new Map;w5=6e4,uy=new Map;gy=120;Jy=(e,t,n)=>({name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:Ho(e.hookToken),createdAt:Date.now()});Ns=new Map,ii=e=>Ns.get(e)||(Ht?fe(Ht,e)?.handoff:null)||null;Xy=6e4,Mn=(e,t,n=15e3)=>Gp("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),Wp=new Map,Zy=e=>Wp.get(e)||null;v5=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,200}$/;Lp=new Map;A5=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,E5=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,ni=z.join(nr,"worktrees"),Xa=[dl,jp],Wt=new Map,_5=e=>Wt.get(e)||(Ht?Ht.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,Ls=e=>{let t=new Map([...Wt.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=Ht?fe(Ht,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)},lf=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});vl=e=>lR(e.trackId,e.id,lf(e));uf=e=>e.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").toLowerCase()||"track",gl=class extends Error{}});dt();import Re from"node:path";import Et from"node:fs";import A3 from"node:readline";import{fileURLToPath as E3}from"node:url";import nn from"express";import rN from"node:http";import _3 from"node:https";import eu from"node:os";import{randomUUID as I3}from"node:crypto";import{WebSocketServer as $3}from"ws";dt();import i1 from"node-pty";async function Ox(e,t,n={}){if(!je(t)){Gu(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await Zr()){Gu(e,`host tmux server not running on ${zt}`),e.close(1011,"tmux server unavailable");return}if(!await Se(t)){let a=!1;if(typeof n.revive=="function"&&(Ku(e,{type:"notice",message:"Resuming the lead box\u2026"}),a=await n.revive().catch(()=>!1)),!a||!await Se(t)){Gu(e,`session "${t}" not found`),e.close(1008,"session not found");return}if(e.readyState!==e.OPEN)return}let r=Rx(n.cols,120,Mx),o=Rx(n.rows,32,Cx),s;try{s=i1.spawn(oe,["-S",zt,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){Gu(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&Ku(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(Ku(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"&&d1(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{}u1(t)})}var c1=6,l1=250;async function u1(e,t=c1,n=l1){for(let r=0;r<t;r++){if(await Xo(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var Mx=20,Cx=6;function d1(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=Mx&&Number(t)>=Cx}function Rx(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function Ku(e,t){try{e.send(JSON.stringify(t))}catch{}}function Gu(e,t){Ku(e,{type:"error",message:t})}function Nx(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}}vn();zu();Hh();Ir();import{createRequire as R3}from"node:module";var B5=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function ab({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(B5)&&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}}Qg();be();Qc();Gn();fp();an();var pf=60*6e4,L5=1440*6e4,j5=new Set(["merged","closed","lost"]),Sl=(e,t,n)=>Number.isFinite(Number(e))&&n-Number(e)<=t;function F5({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)<=xg&&s.push("ship"),r>0&&s.push("create-net");for(let a of n||[]){if(!a||j5.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&&Sl(a.ciFix.delegatedAt,pf,o)&&s.push(`ci-fix#${l}`),a.reconcile&&Sl(a.reconcile.delegatedAt,pf,o)&&s.push(`reconcile#${l}`),a.ciFixAwait&&Sl(a.ciFixAwait.since,pf,o)&&s.push(`ci-fix-await#${l}`),a.reconcileAwait&&Sl(a.reconcileAwait.since,pf,o)&&s.push(`reconcile-await#${l}`);let u=a.autoMerge?.armedAt??a.armedAt??null;a.trackId===e&&(a.autoMerge||a.armedAt)&&Sl(u,L5,o)&&s.push(`auto-merge#${l}`)}return s}var ff=new Map;Ze.on("event",e=>{e?.trackId&&ff.delete(e.trackId)});async function U5(e){if(ff.has(e.id))return ff.get(e.id);let t=await K(e).catch(()=>[]),n=qa(t,-1/0);return ff.set(e.id,n),n}async function hR(e,{now:t=Date.now()}={}){let n=new Map,r=await En().catch(()=>[]);for(let o of e||[]){if(!o||Ue(o))continue;let s=F5({trackId:o.id,shipPending:await U5(o),links:r,observers:zE(o.id),now:t});s.length&&n.set(o.id,s)}return n}Kg();import _R from"node:fs";import Ro from"node:fs/promises";import aG from"node:os";import kt from"node:path";import{spawn as iG}from"node:child_process";import{createRequire as cG}from"node:module";be();Dd();import ci from"node:fs";import Al from"node:fs/promises";import q5 from"node:http";import Ot from"node:path";import hf from"node:os";import{createRequire as G5}from"node:module";import cb from"ws";import H5 from"node:path";import W5 from"node:os";var Tl=process.env.BOSTRAT_STATE_DIR||H5.join(process.env.HOME||W5.tmpdir(),".bostrat");function ib(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 wR(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=ib(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function gR(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}km();var Cn=(()=>{try{return G5(import.meta.url)("../package.json").version||null}catch{return null}})(),ub=process.env.BOSTRAT_STATE_DIR||Ot.join(process.env.HOME||hf.tmpdir(),".bostrat"),TR=Ot.join(ub,"plane-link","removed.json");function yR(e){return typeof e!="string"||e.length<8?"\u2022\u2022\u2022\u2022":`${e.slice(0,6)}\u2026${e.slice(-4)}`}function K5(e=TR){try{let t=JSON.parse(ci.readFileSync(e,"utf8"));return t&&typeof t=="object"?t:null}catch{return null}}function js({env:e=process.env,pkgDir:t=Ot.resolve(Ot.dirname(new URL(import.meta.url).pathname),".."),exists:n=ci.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(Ot.join(t,"..",".git"))?"git-checkout":"dev"}function El(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 mf(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 V5({home:e=process.env.HOME||hf.homedir(),env:t=process.env}={}){let n=r=>{try{return ci.statSync(r),!0}catch{return!1}};return{claude:n(Ot.join(e,".claude",".credentials.json")),codex:n(Ot.join(t.CODEX_HOME||Ot.join(e,".codex"),"auth.json")),cursor:n(Ot.join(t.XDG_CONFIG_HOME||Ot.join(e,".config"),"cursor","auth.json"))}}var mt=1,bR=1e3,kR=3e4,z5=6e4,J5=1500,Y5=500,$o=100,X5=2e3,Z5=25e3,Q5=2.5,eG=6e4,AR=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},tG=AR(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),nG=3e4,xR=10*6e4,rG=400,vR=250,oG=AR(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),lb=4,sG=6e4,SR=6e4;function ER({url:e,token:t,nodeId:n=hf.hostname(),name:r=hf.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,sampleMetrics:i=null,deliverySample:c=null,onHashKey:l=null,onViewBase:u=null,metricsMs:d=sG,onUpdateAvailable:p=null,onUpdatePolicy:f=null,onHelloRefused:w=null,updatePolicy:h=null,installKind:y=js(),selfUrl:k=`http://127.0.0.1:${process.env.PORT||3362}`,apiToken:g=null,removedMarkerFile:x=TR,onRemoved:S=null,onDegraded:_=null,onRecovered:M=null,onConnected:P=null,ingestMode:j=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:A=tG,unackedRetryMs:$=eG,pingMs:L=Z5,deadLinkMs:H=Math.round(L*Q5),maxInflightEvents:R=rG,httpTimeoutMs:T=oG,stallBackoffMinMs:C=nG,fetchImpl:W=globalThis.fetch,log:B=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=gR(e);let Z=k.replace(/^http/,"ws"),xe=new Set,Te=new Map,_e=new Map,Q=Ot.join(ub,"plane-link","cursor.json"),Xe=Ot.join(ub,"plane-link","dead-letter.ndjson"),Pe=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),le={},ge={},de=new Map,te=null,we=null,Oe=0,Ve=0,Nt=0,O=Promise.resolve(),X="ws",re=0,he=!1,Be=0,Pt=!1,tt=$o,wn=new Set,Kt=[],ht=null,wt=null,at=!1,Ai=!1,gt=bR,cr=null,Hr=null,lr=null,gn=null,ur=0,b=0,m=null,v=!1,D=0,J=!1,ie=K5(x);if(ie)if(ie.tokenPreview===yR(t))J=!0,bm({reason:ie.reason??"removed",at:ie.at??null,nodeId:ie.nodeId??n}),B.error(`[plane-link] this node was REMOVED from the plane (${ie.reason??"removed"}${ie.at?` at ${new Date(ie.at).toISOString()}`:""}) \u2014 not dialing. Re-provision it with a new node token, or delete ${x} to force a dial.`);else try{ci.unlinkSync(x),B.log("[plane-link] stale removed-marker discarded \u2014 the node token changed")}catch{}function ve({reason:F="removed",at:q=Date.now(),via:U="ctl"}={}){if(!J){J=!0,bm({reason:F,at:q,nodeId:n,via:U});try{ci.mkdirSync(Ot.dirname(x),{recursive:!0}),ci.writeFileSync(x,JSON.stringify({at:q,reason:F,via:U,nodeId:n,tokenPreview:yR(t)},null,2))}catch(I){B.error(`[plane-link] could not write ${x}: ${I?.message||I}`)}B.error(`[plane-link] the plane REMOVED this node (${F}, via ${U}) \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{S?.({reason:F,at:q,via:U})}catch{}zk({bye:!1})}}async function _t(){try{le=JSON.parse(await Al.readFile(Q,"utf8"))}catch{le={}}}function yt(){v=!0,!lr&&(lr=setTimeout(async()=>{if(lr=null,!!v){v=!1;try{await Al.mkdir(Ot.dirname(Q),{recursive:!0}),await Al.writeFile(Q,JSON.stringify(le))}catch(F){B.error("[plane-link] cursor flush failed:",F?.message||F)}}},X5),lr.unref?.())}function nt(F){return!wt||wt.readyState!==cb.OPEN?!1:(wt.send(JSON.stringify(F)),!0)}function rn(F){let q=Date.now();for(let{trackId:U,event:I}of F){let V=de.get(I.id);de.set(I.id,{trackId:U,seq:I.seq,event:I,sentAt:q,firstSentAt:V?.firstSentAt??q,retryAt:q+$,tries:(V?.tries??0)+1,nacks:V?.nacks??0})}return X==="http"?(vN(F),!0):nt({v:mt,ch:"events",type:"append",events:F})}function yN(F){let q=null;for(let U of de.values())U.trackId===F&&(q==null||U.seq<q)&&(q=U.seq);return q}function tm(F){let q=ge[F];if(q==null)return;let U=yN(F),I=U==null?q:Math.min(q,U-1);I>(le[F]??0)&&(le[F]=I,yt())}function Ei(){if(te=Date.now(),we!=null){let F=Date.now()-we;B.log(`[plane-link] spine sync recovered after ${Math.round(F/1e3)}s degraded (${Oe} stall redial(s))`);let q=we;we=null,Oe=0,Ve=0,he=!1,Be=0;try{M?.({since:q,downMs:F})}catch(U){B.error(`[plane-link] onRecovered failed: ${U?.message||U}`)}}}function nm(F){if(!Array.isArray(F)||!F.length)return;let q=new Set;for(let U of F){let I=de.get(U);I&&(de.delete(U),(ge[I.trackId]??0)<I.seq&&(ge[I.trackId]=I.seq),q.add(I.trackId))}for(let U of q)tm(U);Ei()}function Fk(F,q){Nt++;let U={at:Date.now(),trackId:F.trackId,seq:F.seq,id:F.event?.id??null,type:F.event?.type??null,reason:q,event:F.event??null};B.error(`[plane-link] DEAD-LETTER ${F.trackId} seq ${F.seq} (${U.type??"?"}): plane rejected it permanently (${q}) \u2014 kept in ${Xe}`),O=O.then(async()=>{await Al.mkdir(Ot.dirname(Xe),{recursive:!0}),await Al.appendFile(Xe,JSON.stringify(U)+`
696
+ `)}).catch(I=>B.error(`[plane-link] dead-letter write failed: ${I?.message||I}`))}function Uk(F,q,U,I=null){if(!Array.isArray(F)||!F.length)return;let V=new Set,Ie=Date.now();for(let ye of F){let Le=de.get(ye);Le&&(U?(de.delete(ye),Fk(Le,q),(ge[Le.trackId]??0)<Le.seq&&(ge[Le.trackId]=Le.seq),V.add(Le.trackId)):(Le.nacks++,Le.retryAt=Ie+Math.max(1e3,Number(I)||$)))}for(let ye of V)tm(ye);Ei()}function Hk(F=Date.now()){let q=1/0;for(let U of de.values())U.firstSentAt<q&&(q=U.firstSentAt);return q===1/0?0:F-q}function bN(F){if(!H||!F||F!==wt||!ur)return!1;let q=Date.now()-ur;if(q<=H)return!1;b++,B.error(`[plane-link] no frame from the plane for ${Math.round(q/1e3)}s \u2014 link is half-open; terminating and redialing`);try{F.terminate()}catch{}return!0}function Wk(){if(!at||!de.size)return;let F=Date.now(),q=Hk(F);if(q<A||te!=null&&F-te<A||X==="http"&&he||Ve>F)return;Oe++;let U=Math.min(C*2**(Oe-1),xR);if(we==null){we=F-q,B.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(q/1e3)}s with ${de.size} event(s) in flight (${X} door) \u2014 the plane is not answering appends`);try{_?.({since:we,unacked:de.size,oldestAgeMs:q,mode:X})}catch(I){B.error(`[plane-link] onDegraded failed: ${I?.message||I}`)}}if(X==="http"){he=!0,Be=F+U,B.error(`[plane-link] ingest circuit OPEN (stall #${Oe}); probing /v1/ingest/health in ${Math.round(U/1e3)}s`);return}Ve=F+U,B.error(`[plane-link] closing the link and redialing in ${Math.round(U/1e3)}s (stall redial #${Oe})`);try{wt?.terminate()}catch{}}function rm(){if(!at)return;let F=Date.now();if(X==="http"&&he)return;let q=[...de.values()].filter(I=>I.event&&I.retryAt<=F&&!(X==="http"&&wn.has(I.trackId)));if(!q.length)return;q.sort((I,V)=>I.trackId===V.trackId?I.seq-V.seq:I.trackId<V.trackId?-1:1),B.log(`[plane-link] re-sending ${q.length} unacked event(s) the plane never confirmed`);let U=X==="http"?tt:$o;if(X==="http"){let I=new Map;for(let V of q)(I.get(V.trackId)??I.set(V.trackId,[]).get(V.trackId)).push(V);for(let[,V]of I){if(re>=lb)return;rn(V.slice(0,U).map(Ie=>({trackId:Ie.trackId,event:Ie.event})))}return}for(let I=0;I<q.length;I+=U){let V=q.slice(I,I+U).map(Ie=>({trackId:Ie.trackId,event:Ie.event}));if(!rn(V))return}}async function kN(F=null){for(;;){if(!at)return!1;let q=de.size<R,U=X!=="http"||re<lb&&!he&&(!F||!wn.has(F));if(q&&U)return!0;await new Promise(I=>setTimeout(I,100))}}function om(){if(ht=null,!at||!Kt.length)return;let F=Kt;if(Kt=[],X!=="http"){for(let U=0;U<F.length;U+=$o)rn(F.slice(U,U+$o));return}let q=new Map;for(let U of F)(q.get(U.trackId)??q.set(U.trackId,[]).get(U.trackId)).push(U);for(let[U,I]of q){if(wn.has(U)||re>=lb||he){Kt.push(...I);continue}for(let V=0;V<I.length;V+=tt)rn(I.slice(V,V+tt))}Kt.length&&!ht&&(ht=setTimeout(om,vR),ht.unref?.())}let xN=F=>{let q=new Map;for(let{trackId:U,event:I}of F)(q.get(U)??q.set(U,[]).get(U)).push(I);return[...q].map(([U,I])=>({trackId:U,events:I}))},Uo=(F,q,U,{progress:I})=>{let V=Date.now();for(let{event:Ie}of F){let ye=de.get(Ie.id);ye&&(ye.nacks++,ye.retryAt=V+Math.max(1e3,U||$))}I&&Ei()};async function vN(F){let q=new Set(F.map(U=>U.trackId));for(let U of q)wn.add(U);re++;try{let U=await W(`${Pe}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:xN(F)}),signal:AbortSignal.timeout(T)}),I=(Number(U.headers.get("retry-after"))||0)*1e3;if(U.status===200){let V=await U.json();tt=$o;for(let Ie of V.results??[]){nm(Ie.acked??[]);let ye=(Le,ut)=>{let on=new Map;for(let it of Le??[])(on.get(it.reason)??on.set(it.reason,[]).get(it.reason)).push(it.id);for(let[it,Jk]of on)Uk(Jk,it,ut,V.retryAfterMs??null)};ye(Ie.rejected,!0),ye(Ie.deferred,!1)}nm(V.discarded??[]),Ei();return}if(U.status===429){Uo(F,"overloaded",I||5e3,{progress:!0});return}if(U.status===413&&F.length>1){tt=Math.max(1,Math.floor(F.length/2)),B.error(`[plane-link] ingest request too large (${F.length} events) \u2014 halving batches to ${tt}`),Uo(F,"too_large",1e3,{progress:!0});return}if(U.status===413){let V=de.get(F[0].event.id);V&&(de.delete(V.event.id),Fk(V,"too_large"),(ge[V.trackId]??0)<V.seq&&(ge[V.trackId]=V.seq),tm(V.trackId)),Ei();return}if(U.status===410){ve({reason:"removed",via:"410"}),Uo(F,"http_410",6e4,{progress:!1});return}if(U.status===401||U.status===403){let{tripped:V,holdMs:Ie}=ta();if(V&&B.error(`[plane-link] holding every plane call for ${Math.round(Ie/6e4)} min \u2014 the ingest door refused this node's token three times in a row`),Date.now()-D>=SR){D=Date.now();let ye="";try{ye=(await U.json())?.error??""}catch{}B.error(`[plane-link] plane refused ingest (HTTP ${U.status}${ye?`: ${ye}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}Uo(F,`http_${U.status}`,Math.max(6e4,Di()),{progress:!1});return}if(U.status===400){B.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${F.length} event(s) for retry; this is a bug, not data`),Uo(F,"http_400",6e4,{progress:!1});return}Uo(F,`http_${U.status}`,I||5e3,{progress:!1})}catch(U){let I=U?.name==="TimeoutError"||U?.name==="AbortError";I&&F.length>1&&(tt=Math.max(1,Math.floor(F.length/2)),B.error(`[plane-link] ingest request of ${F.length} event(s) outlived its ${T} ms deadline \u2014 halving batches to ${tt}`)),Uo(F,I?"timeout":"network",5e3,{progress:!1})}finally{re--;for(let U of q)wn.delete(U)}}async function SN(){if(X!=="http"||!he||!at||Pt)return;let F=Date.now();if(!(Be>F||na(F))){Pt=!0;try{let q=await W(`${Pe}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(T)});if(!q.ok)throw new Error(`HTTP ${q.status}`);B.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),he=!1,Be=0,Ve=Date.now()+T+$+1e3;for(let U of de.values())U.retryAt=Math.min(U.retryAt,Date.now());rm()}catch(q){Oe++;let U=Math.min(C*2**(Oe-1),xR);Be=Date.now()+U,B.error(`[plane-link] ingest door still not answering (${q?.message||q}); next probe in ${Math.round(U/1e3)}s`)}finally{Pt=!1}}}function qk(){let F=Date.now();return{mode:X,unacked:de.size,oldestUnackedAgeMs:Hk(F),lastProgressAt:te,degradedSince:we,stallRedials:Oe,deadLettered:Nt,http:X==="http"?{inFlight:re,circuitOpen:he,nextProbeInMs:he?Math.max(0,Be-F):0,batchCap:tt}:null}}async function Gk(){if(!i)return;let F;try{F=await i()}catch(U){B.error("[plane-link] metrics sample failed:",U?.message||U);return}let q=null;try{q=c?.()??null}catch{}F&&nt({v:mt,ch:"ctl",type:"metrics",metrics:{...F,planeLink:qk(),...q?{delivery:q}:{}}})}function TN(){i&&(m&&clearInterval(m),Gk(),m=setInterval(Gk,d),m.unref?.())}async function AN(){let F;try{F=await o()}catch(q){B.error("[plane-link] backfill listTracks failed:",q?.message||q);return}nt({v:mt,ch:"ctl",type:"tracks",ids:F.filter(q=>!q.transferredTo).map(q=>q.id).filter(q=>typeof q=="string")});for(let q of F){if(!at)return;let U;try{U=await K(q)}catch{continue}let I=le[q.id]??0,V=U.filter(ye=>ye.seq>I&&typeof ye.id=="string"),Ie=X==="http"?tt:$o;for(let ye=0;ye<V.length;ye+=Ie){if(!await kN(q.id))return;let Le=V.slice(ye,ye+Math.min(Ie,X==="http"?tt:$o)).map(ut=>({trackId:q.id,event:ut}));if(!rn(Le))return}}}function Kk(F){!at||!F?.trackId||typeof F.id!="string"||(Kt.push({trackId:F.trackId,event:F}),ht||(ht=setTimeout(om,vR),ht.unref?.()))}let _i=new Map;async function EN(F){let{reqId:q,method:U,path:I,headers:V={},body:Ie}=F,ye=Object.fromEntries(Object.entries(V).filter(([,ut])=>ut!=null)),Le=new AbortController;_i.set(q,Le);try{if(F.host){await _N(F,ye,Le);return}g&&(ye["x-bostrat-token"]=g);let ut=await fetch(k+I,{method:U,headers:ye,body:Ie?Buffer.from(Ie,"base64"):void 0,signal:Le.signal}),on=Object.fromEntries(ut.headers);for(let it of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete on[it];if(on["content-type"]||(on["content-type"]="application/octet-stream"),nt({v:mt,ch:"control",type:"http_head",reqId:q,status:ut.status,headers:on}),ut.body){for await(let it of ut.body)if(!nt({v:mt,ch:"control",type:"http_data",reqId:q,data:Buffer.from(it).toString("base64")}))break}nt({v:mt,ch:"control",type:"http_end",reqId:q,error:null})}finally{_i.delete(q)}}function _N(F,q,U){let{reqId:I,method:V,path:Ie,body:ye}=F,Le=new URL(k);return new Promise(ut=>{let on=q5.request({host:Le.hostname,port:Le.port,method:V,path:Ie,headers:{...q,host:F.host},signal:U.signal},it=>{let{connection:Jk,"keep-alive":J3,"transfer-encoding":Y3,upgrade:X3,...IN}=it.headers;nt({v:mt,ch:"control",type:"http_head",reqId:I,status:it.statusCode||502,headers:IN}),it.on("data",$N=>{nt({v:mt,ch:"control",type:"http_data",reqId:I,data:Buffer.from($N).toString("base64")})||it.destroy()}),it.on("end",()=>{nt({v:mt,ch:"control",type:"http_end",reqId:I,error:null}),ut()}),it.on("error",()=>{nt({v:mt,ch:"control",type:"http_end",reqId:I,error:"view upstream error"}),ut()})});on.on("error",it=>{nt({v:mt,ch:"control",type:"http_end",reqId:I,error:it?.message||"view request failed"}),ut()}),ye&&on.write(Buffer.from(ye,"base64")),on.end()})}function Vk(){if(Ai||J)return;wt=new cb(e,{headers:{authorization:`Bearer ${t}`}});let F=wt;ur=0,F.on("ping",()=>{ur=Date.now()}),F.on("pong",()=>{ur=Date.now()}),wt.on("open",async()=>{let U=null;try{U=await s?.()||null}catch{U=null}nt({v:mt,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:Cn,installKind:y,...typeof h=="function"?{updatePolicy:h()}:h?{updatePolicy:h}:{},providers:V5(),...U?{agents:U}:{}})}),wt.on("message",U=>{ur=Date.now();let I;try{I=JSON.parse(U)}catch{return}if(I.ch==="ctl"&&I.type==="hello_ok"){at=!0,gt=bR,cr=null,y0(),B.log(`[plane-link] connected to plane as ${n}`);try{P?.()}catch{}if(typeof I.hashKey=="string"&&I.hashKey)try{l?.(I.hashKey)}catch{}try{u?.(typeof I.viewBase=="string"&&I.viewBase?I.viewBase:null)}catch{}I.minNodeVersion&&Cn&&El(Cn,I.minNodeVersion)&&B.error(`[plane-link] this node is bostrat-node ${Cn}; the plane asks for \u2265${I.minNodeVersion} \u2014 update with: ${mf(y)}`);try{f?.(typeof I.updatePolicy=="string"?I.updatePolicy:null)}catch{}let V=typeof I.latestNodeVersion=="string"?I.latestNodeVersion:null;if(V&&Cn&&El(Cn,V)&&!xe.has(V)){xe.add(V),B.log(`[plane-link] bostrat-node ${V} is available (this node runs ${Cn}) \u2014 ${mf(y)}`);try{p?.({current:Cn,latest:V,min:I.minNodeVersion??null,installKind:y,required:!!(I.minNodeVersion&&El(Cn,I.minNodeVersion))})}catch(ye){B.error(`[plane-link] update notice failed: ${ye?.message||ye}`)}}let Ie=I.ingest==="http";X=j==="ws"?"ws":j==="http"||Ie?"http":"ws",j==="http"&&!Ie&&B.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),X==="http"&&B.log("[plane-link] spine rides the HTTPS ingest door"),he=!1,Be=0,tt=$o,gn&&clearInterval(gn),ur=Date.now(),gn=setInterval(()=>{bN(F)||(nt({v:mt,ch:"ctl",type:"ping"}),Wk(),SN().catch(()=>{}),rm(),Kt.length&&!ht&&om())},L),gn.unref?.(),TN(),AN().catch(ye=>B.error("[plane-link] backfill failed:",ye?.message||ye));return}if(I.ch==="ctl"&&I.type==="hello_refused"){let V=typeof I.minNodeVersion=="string"?I.minNodeVersion:null,Ie=typeof I.latestNodeVersion=="string"?I.latestNodeVersion:null;B.error(`[plane-link] plane REFUSED this node: bostrat-node ${Cn??"?"} is below its minimum ${V??"?"} \u2014 ${I.fix||mf(y)}`),gt=kR,cr=0;try{w?.({current:Cn,min:V,latest:Ie,fix:I.fix||mf(y),installKind:y})}catch(ye){B.error(`[plane-link] refusal handler failed: ${ye?.message||ye}`)}return}if(I.ch==="ctl"&&I.type==="removed"){nt({v:mt,ch:"ctl",type:"removed_ack",nodeId:n}),ve({reason:typeof I.reason=="string"?I.reason:"removed",at:Number(I.at)||Date.now(),via:"ctl"});return}if(I.ch==="ctl"&&I.type==="update_policy"){try{f?.(typeof I.mode=="string"?I.mode:null)}catch{}return}if(I.ch==="ctl"&&I.type==="usage_caps"){Pd(I.caps??{},{source:"plane",updatedAt:I.updatedAt??Date.now()}).then(V=>B.log(`[plane-link] spend caps ${Object.keys(V.caps).length?`updated (${Object.keys(V.caps).join(", ")})`:"cleared"} from plane`)).catch(V=>B.error("[plane-link] spend-caps push rejected:",V?.message||V));return}if(I.ch==="ctl"&&I.type==="transferred"&&Array.isArray(I.tracks)){Promise.resolve().then(()=>a?.(I.tracks)).catch(V=>B.error("[plane-link] transfer notice failed:",V?.message||V));return}if(I.ch==="events"&&I.type==="ack"&&Array.isArray(I.ids)){nm(I.ids);return}if(I.ch==="events"&&I.type==="nack"&&Array.isArray(I.ids)){Uk(I.ids,I.reason,I.permanent===!0,I.retryAfterMs??null);return}if(I.ch==="control"&&I.type==="http_open"){EN(I).catch(V=>nt({v:mt,ch:"control",type:"http_end",reqId:I.reqId,error:V?.message||"tunnel error"}));return}if(I.ch==="control"&&I.type==="http_cancel"){_i.get(I.reqId)?.abort();return}if(I.ch==="attach"&&I.type==="open"){let V=new cb(Z+I.path,Array.isArray(I.protocols)?I.protocols:[],I.host?{headers:{host:I.host}}:void 0);Te.set(I.streamId,V),_e.set(I.streamId,[]),V.on("open",()=>{let ye=_e.get(I.streamId)||[];_e.delete(I.streamId);for(let{buf:Le,bin:ut}of ye)V.send(Le,{binary:ut})}),V.on("message",(ye,Le)=>{let ut=Le?ye:Buffer.from(String(ye));nt({v:mt,ch:"attach",type:"data",streamId:I.streamId,data:ut.toString("base64"),...Le?{bin:!0}:{}})});let Ie=()=>{_e.delete(I.streamId),Te.delete(I.streamId)&&nt({v:mt,ch:"attach",type:"close",streamId:I.streamId})};V.on("close",Ie),V.on("error",Ie);return}if(I.ch==="attach"&&I.type==="data"){let V=Te.get(I.streamId);if(!V)return;let Ie=Buffer.from(I.data,"base64"),ye=I.bin===!0,Le=_e.get(I.streamId);Le?Le.push({buf:Ie,bin:ye}):V.send(Ie,{binary:ye});return}if(I.ch==="attach"&&I.type==="close"){let V=Te.get(I.streamId);Te.delete(I.streamId),_e.delete(I.streamId),V?.close();return}});let q=()=>{at&&B.log("[plane-link] disconnected from plane"),at=!1,gn&&(clearInterval(gn),gn=null),m&&(clearInterval(m),m=null),de.clear(),ge={},Kt=[],ht&&(clearTimeout(ht),ht=null),wn.clear();for(let V of Te.values())V.close();Te.clear(),_e.clear();for(let V of _i.values())V.abort();if(_i.clear(),Ai||Hr)return;cr==null&&(cr=Date.now());let U=Date.now()-cr<z5,I=Math.max(U?J5+Math.random()*Y5:gt,Ve-Date.now(),Di());Hr=setTimeout(()=>{Hr=null,Vk()},I),Hr.unref?.(),U||(gt=Math.min(gt*2,kR))};wt.on("close",q),wt.on("error",U=>{let I=/Unexpected server response: (\d+)/.exec(U?.message||"")?.[1];if(I==="410"){ve({reason:"removed",via:"410"});return}if(I==="401"||I==="403"){let{tripped:V,holdMs:Ie}=ta();V?B.error(`[plane-link] holding every plane call for ${Math.round(Ie/6e4)} min \u2014 three credential refusals in a row (HTTP ${I}) 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(Ie/6e4)} min.`):Date.now()-D>=SR&&(D=Date.now(),B.error(`[plane-link] plane refused this node's credentials (HTTP ${I}) \u2014 the token was revoked or is unknown to the plane; mint a new node token and update this node's BOSTRAT_PLANE_TOKEN (still retrying)`))}q()})}Ze.on("event",Kk),_t().then(Vk);function zk({bye:F=!0}={}){Ai=!0,Ze.off("event",Kk),Hr&&clearTimeout(Hr),lr&&clearTimeout(lr),gn&&clearInterval(gn),m&&clearInterval(m),ht&&clearTimeout(ht),F&&nt({v:mt,ch:"ctl",type:"bye",reason:"shutdown"}),wt?.close()}return{stop:()=>zk(),status:()=>({connected:at,nodeId:n,cursor:{...le},inflight:de.size,...qk(),auth:b0(),dormant:J,removed:yu(),deadLinkMs:H,deadLinkRedials:b}),_tick:()=>{Wk(),rm()}}}qo();var wf=(()=>{try{return cG(import.meta.url)("../package.json").version||null}catch{return null}})(),lG=process.env.BOSTRAT_STATE_DIR||kt.join(process.env.HOME||aG.tmpdir(),".bostrat"),IR=kt.join(lG,"self-update"),gf=kt.join(IR,"status.json"),uG=1440*6e4,dG=6e4,_l=new Set(["npm-global","git-checkout"]);function $R({kind:e=js(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:_l.has(e)?e==="git-checkout"||pG(t)?"auto":"prompt":"off"}function pG(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}var Qt=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function fG({kind:e,to:t,from:n=wf,statusFile:r=gf,logFile:o=kt.join(IR,"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||kt.resolve(kt.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:u=Date.now()}={}){if(!_l.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=(y,k="")=>`write_status ${Qt(y)} ${k}`,p=process.platform==="darwin"?`launchctl kickstart -k gui/${c}/${i}`:`systemctl --user restart ${Qt(i)}`,f=`
697
697
  health() {
698
698
  for i in $(seq 1 45); do
699
699
  sleep 1
@@ -758,61 +758,61 @@ if [ -n "$FROM" ] && ${h("$FROM")}; then
758
758
  fi
759
759
  ${d("failed",'"deploy-pi.sh v$TO failed AND the rollback failed"')}
760
760
  exit 1
761
- `}async function li(e=wf){try{return JSON.parse(await Ro.readFile(e,"utf8"))}catch{return null}}var fG=new Set(["updating","restarting","rolling-back"]),Il=e=>!!(e&&fG.has(e.status));async function gf({to:e,from:t=hf,kind:n=js(),reason:r="manual",statusFile:o=wf,spawnImpl:s=aG,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!_l.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!El(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await li(o);if(Il(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 Ro.mkdir(kt.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?pu(await mG())||kt.resolve(kt.dirname(process.execPath),".."):null,d=pG({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),p=kt.join(kt.dirname(o),`update-${e}.sh`),f=kt.join(kt.dirname(o),"last.log");await Ro.writeFile(p,d,{mode:448}),await Ro.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let w=_R.existsSync("/run/systemd/system")&&await hG("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 Ro.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 mG(){try{return await Ro.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function hG(e){for(let t of String(process.env.PATH||"").split(kt.delimiter))try{return await Ro.access(kt.join(t,e),_R.constants.X_OK),!0}catch{}return!1}var wG=45*6e4;async function RR({statusFile:e=wf,current:t=hf,now:n=Date.now,staleMs:r=wG}={}){let o=await li(e);if(!o)return null;let s=a=>Ro.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Il(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 OR({isBusy:e,start:t=gf,onStuck:n=null,onStarted:r=null,tickMs:o=uG,stuckMs:s=lG,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=hf,kind:h=js()}){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}}}qo();be();xt();var MR=(...e)=>fetch(...e);function CR(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}async function db(e=process.env){if(!CR(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 MR(`${De(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 pb(e=process.env){if(!CR(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 MR(`${De(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 ui(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await db(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 yf(e,t,{source:n="chat"}={}){return N(e,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:t?{circuitId:t.id,circuitName:t.name??null,source:n}:{circuitId:null,source:n}})}be();xt();var gG=(...e)=>fetch(...e);async function bf(e,t,n,r=process.env){if(!(De(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 gG(`${De(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 yG(e,t=process.env){return bf("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function NR({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await yG(t,o):await ui(e,o),a=await bf("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function fb(e,t=process.env){let n=await ui(e,t),r=await bf("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function mb(e,t=process.env){return(await bf("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function PR(e,t,n,r=process.env){let{blueprint:o,items:s}=await fb(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 N(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}be();xt();var bG=(...e)=>fetch(...e);async function kG(e,t,n,r=process.env){if(!(De(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 bG(`${De(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 DR=72,hb=160;async function BR(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>DR)throw new Error(`the title is the choice as a LABEL \u2014 ${DR} 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 ${hb} chars) a reader can act on without opening the record`);if(c.length>hb)throw new Error(`the summary is one sentence \u2014 ${hb} 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 N(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 LR(e,t=process.env){return kG("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}Lg();be();import Pl from"node:fs/promises";import $f from"node:path";import w6 from"node:os";zr();import xG from"node:fs/promises";import jR from"node:path";import vG from"node:os";var FR=()=>jR.join(process.env.BOSTRAT_STATE_DIR||jR.join(process.env.HOME||vG.tmpdir(),".bostrat"),"integrations.json");async function Fr(){try{return JSON.parse(await xG.readFile(FR(),"utf8"))||{}}catch{return{}}}var kf=["linked","prOpened","prMerged","create"],wb=["prompt","auto","off"],SG={create:["prompt","off"]},UR=e=>SG[e]??wb;function xf(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of kf){let s=UR(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 Fs(){let e=await Fr(),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:xf(e),defaultTeam:n}:null}async function vf(){let e=await Fr(),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:xf(e)}}async function gb(){return xf(await Fr())}async function HR(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${kf.join(", ")}`);for(let[r,o]of t){if(!kf.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${kf.join(", ")}`);let s=UR(r);if(!s.includes(o))throw new Error(s.length<wb.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${wb.join(", ")}`)}let n=await Fr();return n.ticketFlow={...xf(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Bt(FR(),n,{mode:384}),n.ticketFlow}async function $l(){let e=(await Fr()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function AG(){let e=(await Fr()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var TG={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function Sf(){let t=(await Fr()).voiceChat||{},n=t.provider||"openai",r=TG[n];if(!r)return null;let o=n==="openai"?await AG():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function WR(){let e=(await Fr()).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 Us(){let e=(await Fr()).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}}be();Yr();fo();Va();import Ol from"node:fs/promises";import iO from"node:path";import QG from"node:os";import{randomUUID as cO}from"node:crypto";var bb={};om(bb,{createComment:()=>NG,findIssueUrl:()=>$G,issueStates:()=>BG,mdToAdf:()=>KR,moveIssue:()=>LG,parseIssueRef:()=>IG,resolveIssue:()=>RG,uploadImage:()=>PG,upsertCard:()=>OG,whoami:()=>yb});var di=e=>String(e.baseUrl||"").replace(/\/$/,""),GR=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function Hs(e,t,n,r){let o=await fetch(`${di(e)}${n}`,{method:t,headers:{authorization:GR(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 EG=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,_G=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function IG(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(EG);return r?r[1].toUpperCase():null}let n=t.match(_G);return n?n[1]:null}function $G(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 RG(e,t){let n;try{n=await Hs(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:`${di(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function OG(e,t,{url:n,title:r,subtitle:o}){await Hs(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 MG=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function CG(e){let t=[],n=0;for(let r of e.matchAll(MG)){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 KR(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
762
- `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...CG(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 NG(e,t,n){let r=await Hs(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:KR(n)});return r?.id?`${di(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function yb(e){let t=await Hs(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(di(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function PG(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(`${di(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:GR(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??`${di(e)}/rest/api/3/attachment/content/${c.id}`}var DG={new:"unstarted",indeterminate:"started",done:"completed"},qR=e=>DG[e?.key]??"started";async function BG(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([Hs(e,"GET",`/rest/api/3/issue/${n}?fields=status`),Hs(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:qR(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:qR(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function LG(e,t,n){await Hs(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var Sb={};om(Sb,{createComment:()=>KG,createIssue:()=>vb,createProject:()=>xb,findIssueUrl:()=>WG,issueStates:()=>zG,moveIssue:()=>JG,parseIssueRef:()=>HG,resolveIssue:()=>qG,teams:()=>pi,uploadImage:()=>VG,upsertCard:()=>GG,whoami:()=>kb});var jG=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function sr(e,t,n={}){let r=await fetch(jG(),{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 FG=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,UG=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function HG(e){let t=String(e||"").trim(),n=t.match(FG);if(n)return n[1].toUpperCase();let r=t.match(UG);return r?r[1]:null}function WG(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 qG(e,t){let r=(await sr(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 GG(e,t,{url:n,title:r,subtitle:o}){let s=await sr(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 KG(e,t,n){let r=await sr(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 kb(e){let t=await sr(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 VG(e,{filename:t,contentType:n,buffer:r}){let o=await sr(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
761
+ `}async function li(e=gf){try{return JSON.parse(await Ro.readFile(e,"utf8"))}catch{return null}}var mG=new Set(["updating","restarting","rolling-back"]),Il=e=>!!(e&&mG.has(e.status));async function yf({to:e,from:t=wf,kind:n=js(),reason:r="manual",statusFile:o=gf,spawnImpl:s=iG,now:a=Date.now,npmPrefix:i=void 0,log:c=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!_l.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!El(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let l=await li(o);if(Il(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 Ro.mkdir(kt.dirname(o),{recursive:!0});let u=i!==void 0?i:n==="npm-global"?pu(await hG())||kt.resolve(kt.dirname(process.execPath),".."):null,d=fG({kind:n,to:e,from:t,statusFile:o,npmPrefix:u,startedAt:a()}),p=kt.join(kt.dirname(o),`update-${e}.sh`),f=kt.join(kt.dirname(o),"last.log");await Ro.writeFile(p,d,{mode:448}),await Ro.writeFile(o,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,startedAt:a(),updatedAt:a()}));let w=_R.existsSync("/run/systemd/system")&&await wG("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 Ro.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 hG(){try{return await Ro.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function wG(e){for(let t of String(process.env.PATH||"").split(kt.delimiter))try{return await Ro.access(kt.join(t,e),_R.constants.X_OK),!0}catch{}return!1}var gG=45*6e4;async function RR({statusFile:e=gf,current:t=wf,now:n=Date.now,staleMs:r=gG}={}){let o=await li(e);if(!o)return null;let s=a=>Ro.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Il(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 OR({isBusy:e,start:t=yf,onStuck:n=null,onStarted:r=null,tickMs:o=dG,stuckMs:s=uG,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=wf,kind:h=js()}){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}}}qo();be();xt();var MR=(...e)=>fetch(...e);function CR(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}async function db(e=process.env){if(!CR(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 MR(`${De(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 pb(e=process.env){if(!CR(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 MR(`${De(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 ui(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await db(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 bf(e,t,{source:n="chat"}={}){return N(e,{type:"track.circuit.tagged",actor:"orchestrator",source:"orchestrator",payload:t?{circuitId:t.id,circuitName:t.name??null,source:n}:{circuitId:null,source:n}})}be();xt();var yG=(...e)=>fetch(...e);async function kf(e,t,n,r=process.env){if(!(De(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 yG(`${De(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 bG(e,t=process.env){return kf("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function NR({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await bG(t,o):await ui(e,o),a=await kf("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function fb(e,t=process.env){let n=await ui(e,t),r=await kf("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function mb(e,t=process.env){return(await kf("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function PR(e,t,n,r=process.env){let{blueprint:o,items:s}=await fb(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 N(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:o.id,source:"cli"}}),{blueprint:o,itemIds:n}}be();xt();var kG=(...e)=>fetch(...e);async function xG(e,t,n,r=process.env){if(!(De(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 kG(`${De(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 DR=72,hb=160;async function BR(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>DR)throw new Error(`the title is the choice as a LABEL \u2014 ${DR} 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 ${hb} chars) a reader can act on without opening the record`);if(c.length>hb)throw new Error(`the summary is one sentence \u2014 ${hb} 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 N(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 LR(e,t=process.env){return xG("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}Lg();be();import Pl from"node:fs/promises";import Rf from"node:path";import g6 from"node:os";zr();import vG from"node:fs/promises";import jR from"node:path";import SG from"node:os";var FR=()=>jR.join(process.env.BOSTRAT_STATE_DIR||jR.join(process.env.HOME||SG.tmpdir(),".bostrat"),"integrations.json");async function Fr(){try{return JSON.parse(await vG.readFile(FR(),"utf8"))||{}}catch{return{}}}var xf=["linked","prOpened","prMerged","create"],wb=["prompt","auto","off"],TG={create:["prompt","off"]},UR=e=>TG[e]??wb;function vf(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of xf){let s=UR(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 Fs(){let e=await Fr(),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:vf(e),defaultTeam:n}:null}async function Sf(){let e=await Fr(),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:vf(e)}}async function gb(){return vf(await Fr())}async function HR(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${xf.join(", ")}`);for(let[r,o]of t){if(!xf.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${xf.join(", ")}`);let s=UR(r);if(!s.includes(o))throw new Error(s.length<wb.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${wb.join(", ")}`)}let n=await Fr();return n.ticketFlow={...vf(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await Bt(FR(),n,{mode:384}),n.ticketFlow}async function $l(){let e=(await Fr()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function AG(){let e=(await Fr()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var EG={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function Tf(){let t=(await Fr()).voiceChat||{},n=t.provider||"openai",r=EG[n];if(!r)return null;let o=n==="openai"?await AG():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function WR(){let e=(await Fr()).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 Us(){let e=(await Fr()).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}}be();Yr();fo();Va();import Ol from"node:fs/promises";import iO from"node:path";import e6 from"node:os";import{randomUUID as cO}from"node:crypto";var bb={};sm(bb,{createComment:()=>PG,findIssueUrl:()=>RG,issueStates:()=>LG,mdToAdf:()=>KR,moveIssue:()=>jG,parseIssueRef:()=>$G,resolveIssue:()=>OG,uploadImage:()=>DG,upsertCard:()=>MG,whoami:()=>yb});var di=e=>String(e.baseUrl||"").replace(/\/$/,""),GR=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function Hs(e,t,n,r){let o=await fetch(`${di(e)}${n}`,{method:t,headers:{authorization:GR(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 _G=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,IG=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function $G(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(_G);return r?r[1].toUpperCase():null}let n=t.match(IG);return n?n[1]:null}function RG(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 OG(e,t){let n;try{n=await Hs(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:`${di(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function MG(e,t,{url:n,title:r,subtitle:o}){await Hs(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 CG=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function NG(e){let t=[],n=0;for(let r of e.matchAll(CG)){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 KR(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
762
+ `).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...NG(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 PG(e,t,n){let r=await Hs(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:KR(n)});return r?.id?`${di(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function yb(e){let t=await Hs(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(di(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function DG(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(`${di(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:GR(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??`${di(e)}/rest/api/3/attachment/content/${c.id}`}var BG={new:"unstarted",indeterminate:"started",done:"completed"},qR=e=>BG[e?.key]??"started";async function LG(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([Hs(e,"GET",`/rest/api/3/issue/${n}?fields=status`),Hs(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:qR(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:qR(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function jG(e,t,n){await Hs(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var Sb={};sm(Sb,{createComment:()=>VG,createIssue:()=>vb,createProject:()=>xb,findIssueUrl:()=>qG,issueStates:()=>JG,moveIssue:()=>YG,parseIssueRef:()=>WG,resolveIssue:()=>GG,teams:()=>pi,uploadImage:()=>zG,upsertCard:()=>KG,whoami:()=>kb});var FG=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function sr(e,t,n={}){let r=await fetch(FG(),{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 UG=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,HG=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function WG(e){let t=String(e||"").trim(),n=t.match(UG);if(n)return n[1].toUpperCase();let r=t.match(HG);return r?r[1]:null}function qG(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 GG(e,t){let r=(await sr(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 KG(e,t,{url:n,title:r,subtitle:o}){let s=await sr(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 VG(e,t,n){let r=await sr(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 kb(e){let t=await sr(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 zG(e,{filename:t,contentType:n,buffer:r}){let o=await sr(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
763
763
  fileUpload(contentType: $contentType, filename: $filename, size: $size) {
764
764
  success
765
765
  uploadFile { uploadUrl assetUrl headers { key value } }
766
766
  }
767
- }`,{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 zG(e,t){let n=await sr(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 JG(e,t,n){if(!(await sr(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 pi(e){return((await sr(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var VR=255;async function xb(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>VR,a=s?`${o.slice(0,VR-1).trimEnd()}\u2026`:o,i=await sr(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 vb(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await sr(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}}jc();import Af from"node:fs";import Ab from"node:path";import YG from"node:os";var XG=()=>process.env.BOSTRAT_STATE_DIR||Ab.join(process.env.HOME||YG.tmpdir(),".bostrat"),zR=()=>Ab.join(XG(),"plane-link","public-host.json"),JR="this node has no public host for Views: link it to a plane that sets PLANE_VIEW_BASE (bostrat-node init), or set BOSTRAT_PUBLIC_HOST in node.env for a plane-less node",fi=null;function YR(){if(fi)return fi;try{let e=JSON.parse(Af.readFileSync(zR(),"utf8"));fi={viewBase:typeof e?.viewBase=="string"&&e.viewBase?e.viewBase:null}}catch{fi={viewBase:null}}return fi}function XR(e,t){let n=String(e||"").trim();if(!n)return null;let r=/^(https?):\/\/(.+?)\/?$/i.exec(n),o=r?r[1].toLowerCase():t,s=(r?r[2]:n).replace(/\/.*$/,"").replace(/:\d+$/,"").toLowerCase();return s?{proto:o,host:s}:null}function ZR(e){let t=typeof e=="string"&&e.trim()?XR(e,"https").host:null;if(YR().viewBase===t)return;fi={viewBase:t};let r=zR();try{t?(Af.mkdirSync(Ab.dirname(r),{recursive:!0}),Af.writeFileSync(r,JSON.stringify({viewBase:t,learnedAt:new Date().toISOString()})+`
768
- `)):Af.rmSync(r,{force:!0})}catch{}}function Tb(){return YR().viewBase}function Eb(e=process.env.BOSTRAT_PUBLIC_HOST){return XR(e,"https")}function QR(){let e=Tb();if(e)return{proto:"https",host:e,source:"learned"};let t=Eb();return t?{...t,source:"env"}:null}function Tf(e,t){return e?`${e.proto}://${t}.${e.host}/`:null}function ZG(e=process.env.BOSTRAT_PLANE_URL){let t=String(e||"").trim();if(!t)return null;let n=/^(wss?|https?):\/\/([^/?#]+)/i.exec(t);return n?`${/^(wss|https)$/i.test(n[1])?"https":"http"}://${n[2]}`:null}function eO(){let e=String(process.env.BOSTRAT_PUBLIC_URL||"").trim().replace(/\/+$/,"");if(e)return{url:e,source:"env"};let t=ZG();return t?{url:t,source:"plane"}:null}var tO="this node has no public app URL for Track links: link it to a plane (bostrat-node init) or set BOSTRAT_PUBLIC_URL in node.env";var lO={linear:{api:Sb,config:Fs},jira:{api:bb,config:vf}};async function Cb(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(lO)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function Ws(e){let t=lO[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function Nb(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 uO=()=>process.env.BOSTRAT_STATE_DIR||iO.join(process.env.HOME||QG.tmpdir(),".bostrat"),Rb=()=>iO.join(uO(),"tickets.json"),Cl=e=>{let t=eO();if(!t)throw new Error(tO);return`${t.url}/track/${e}`},e6=e=>`http://bostrat.globopi/track/${e}`,nO=e=>{let t=0;for(let[n,r]of Object.entries(e))r&&typeof r=="object"&&!r.cardUrl&&(r.cardUrl=e6(n),t++);return t},ar=null,_b=null,Ib=Promise.resolve();async function Nl(){return ar||(_b??=Ol.readFile(Rb(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{ar=e;let n=nO(ar)>0;if(!t&&Ge()){let{records:r,source:o}=await pt("tickets").catch(()=>({records:[],source:"error"}));if(o==="plane"){for(let s of r){if(s.deletedAt||!s.data?.id)continue;let{id:a,updatedAt:i,...c}=s.data;ar[a]=c}nO(ar),n=n||Object.keys(ar).length>0}}return n&&await Ob().catch(()=>{}),ar}).finally(()=>_b=null),_b)}async function Ob(){let e=JSON.stringify({tickets:ar},null,2),t=`${Rb()}.${process.pid}.tmp`;await Ol.mkdir(uO(),{recursive:!0}),await Ol.writeFile(t,e),await Ol.rename(t,Rb())}async function Oo(e=null){if(Ib=Ib.then(Ob,Ob),await Ib.catch(()=>{}),!e)return;let t=ar?.[e];t?It("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):bn("tickets",e).catch(()=>{})}async function ir(e){return(await Nl())[e]??null}async function dO(){return{...await Nl()}}async function pO(){return(await Cb()).length>0}async function mi(e,t,{source:n="api"}={}){let r=await Cb();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(),cardUrl:Cl(e.id),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 Nl())[e.id]=c,await Oo(e.id),await N({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 Ml(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 Rl(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await hO(e.id,c,"linked"),c}async function Pb(e){let t=await Nl();return t[e]?(delete t[e],await Oo(e),!0):!1}var Mb=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function fO(e,t){if(!e.track?.cwd)return null;let n=po(await K({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function t6(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${Mb(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${Mb(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function n6(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(Mb(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function Ml(e,t){let n=await Ws(t);if(!n)return;let r=await fO(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:t.cardUrl??Cl(e),title:`Bostrat Track: ${t.track.name}`,subtitle:n6(t,r)})}function r6(e){return Tf(QR(),e)}var Ef=e=>r6(e)??"(no public URL on this node \u2014 link it to a plane)",o6={linked:"linked",opened:"prOpened",merged:"prMerged"};function s6(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 mO(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await Oo(e),await N({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 hO(e,t,n){let r=await Ws(t);if(!r)return;let o=r.cfg.ticketFlow?.[o6[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Nb(s,a),c=s6(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 mO(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await N({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:cO(),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 wO(e){let t=await ir(e);if(!t)throw new Error("no ticket linked to this Track");let n=await Ws(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=Nb(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await Oo(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 Db(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await ir(e);if(!r)throw new Error("no ticket linked to this Track");let o=await Ws(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Nb(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 Oo(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await mO(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function gO(e,t){let n=await ir(e);if(!n)throw new Error("no ticket linked to this Track");let r=await Ws(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 N({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 yO(e,t,n){if(!t)throw new Error("offerId required");return vo(`tkt:${e.id}:${t}`,()=>a6(e,t,n))}async function a6(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 Db(e.id,o.payload.to?.id,{mode:"offer"})),await N({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 rO=50;async function bO(){let e=await Fs();if(!e)throw new Error("no ticketing integration configured");return pi(e)}function i6(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>rO)throw new Error(`too many issues (${n.length}); cap is ${rO} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function c6(e,t,n,r){let o=r??await pi(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 ir(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 kO(e,t){let n=await Fs();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=i6(t),o=await pi(n),s=await c6(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=cO();return await N({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 xO(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 N({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 Fs();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let w=(await pi(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 xb(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 vb(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 N({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 N({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 ir(e.id)&&(f=await mi(e,p[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:f?f.key:null}}async function Rl(e,t){let n=await Ws(e);n&&await n.api.createComment(n.cfg,e,t)}async function l6(e,t,n){let r=await Ws(e);if(!r)return null;let o=await Mr(t);if(!o)return null;let s=$n(o,n);if(!s)return null;let a=await Ol.readFile(dn(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 oO=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),$b=new Map;function u6(e,t){if(oO()<=0)return Ml(e,t);if($b.has(e))return;let n=setTimeout(()=>{$b.delete(e),ir(e).then(r=>r?Ml(e,r):null).catch(()=>{})},oO());n.unref?.(),$b.set(e,n)}var sO=new Map;async function aO(e,t,n){let r=sO.get(e)??0;Date.now()-r<600*1e3||(sO.set(e,Date.now()),await N({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function d6(e,{resolveTrack:t=null}={}){let n=await ir(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Cb())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 mi(s,o,{source:"chat"})}catch(a){await aO(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 Oo(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await Oo(e.trackId),await Ml(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 Oo(e.trackId),await Ml(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await fO(n,e.trackId).catch(()=>null):null;await Rl(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
767
+ }`,{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 JG(e,t){let n=await sr(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 YG(e,t,n){if(!(await sr(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 pi(e){return((await sr(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var VR=255;async function xb(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>VR,a=s?`${o.slice(0,VR-1).trimEnd()}\u2026`:o,i=await sr(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 vb(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await sr(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}}jc();import Af from"node:fs";import Tb from"node:path";import XG from"node:os";var ZG=()=>process.env.BOSTRAT_STATE_DIR||Tb.join(process.env.HOME||XG.tmpdir(),".bostrat"),zR=()=>Tb.join(ZG(),"plane-link","public-host.json"),JR="this node has no public host for Views: link it to a plane that sets PLANE_VIEW_BASE (bostrat-node init), or set BOSTRAT_PUBLIC_HOST in node.env for a plane-less node",fi=null;function YR(){if(fi)return fi;try{let e=JSON.parse(Af.readFileSync(zR(),"utf8"));fi={viewBase:typeof e?.viewBase=="string"&&e.viewBase?e.viewBase:null}}catch{fi={viewBase:null}}return fi}function XR(e,t){let n=String(e||"").trim();if(!n)return null;let r=/^(https?):\/\/(.+?)\/?$/i.exec(n),o=r?r[1].toLowerCase():t,s=(r?r[2]:n).replace(/\/.*$/,"").replace(/:\d+$/,"").toLowerCase();return s?{proto:o,host:s}:null}function ZR(e){let t=typeof e=="string"&&e.trim()?XR(e,"https").host:null;if(YR().viewBase===t)return;fi={viewBase:t};let r=zR();try{t?(Af.mkdirSync(Tb.dirname(r),{recursive:!0}),Af.writeFileSync(r,JSON.stringify({viewBase:t,learnedAt:new Date().toISOString()})+`
768
+ `)):Af.rmSync(r,{force:!0})}catch{}}function Ab(){return YR().viewBase}function Eb(e=process.env.BOSTRAT_PUBLIC_HOST){return XR(e,"https")}function QR(){let e=Ab();if(e)return{proto:"https",host:e,source:"learned"};let t=Eb();return t?{...t,source:"env"}:null}function Ef(e,t){return e?`${e.proto}://${t}.${e.host}/`:null}function QG(e=process.env.BOSTRAT_PLANE_URL){let t=String(e||"").trim();if(!t)return null;let n=/^(wss?|https?):\/\/([^/?#]+)/i.exec(t);return n?`${/^(wss|https)$/i.test(n[1])?"https":"http"}://${n[2]}`:null}function eO(){let e=String(process.env.BOSTRAT_PUBLIC_URL||"").trim().replace(/\/+$/,"");if(e)return{url:e,source:"env"};let t=QG();return t?{url:t,source:"plane"}:null}var tO="this node has no public app URL for Track links: link it to a plane (bostrat-node init) or set BOSTRAT_PUBLIC_URL in node.env";var lO={linear:{api:Sb,config:Fs},jira:{api:bb,config:Sf}};async function Cb(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(lO)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function Ws(e){let t=lO[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function Nb(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 uO=()=>process.env.BOSTRAT_STATE_DIR||iO.join(process.env.HOME||e6.tmpdir(),".bostrat"),Rb=()=>iO.join(uO(),"tickets.json"),Cl=e=>{let t=eO();if(!t)throw new Error(tO);return`${t.url}/track/${e}`},t6=e=>`http://bostrat.globopi/track/${e}`,nO=e=>{let t=0;for(let[n,r]of Object.entries(e))r&&typeof r=="object"&&!r.cardUrl&&(r.cardUrl=t6(n),t++);return t},ar=null,_b=null,Ib=Promise.resolve();async function Nl(){return ar||(_b??=Ol.readFile(Rb(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{ar=e;let n=nO(ar)>0;if(!t&&Ge()){let{records:r,source:o}=await pt("tickets").catch(()=>({records:[],source:"error"}));if(o==="plane"){for(let s of r){if(s.deletedAt||!s.data?.id)continue;let{id:a,updatedAt:i,...c}=s.data;ar[a]=c}nO(ar),n=n||Object.keys(ar).length>0}}return n&&await Ob().catch(()=>{}),ar}).finally(()=>_b=null),_b)}async function Ob(){let e=JSON.stringify({tickets:ar},null,2),t=`${Rb()}.${process.pid}.tmp`;await Ol.mkdir(uO(),{recursive:!0}),await Ol.writeFile(t,e),await Ol.rename(t,Rb())}async function Oo(e=null){if(Ib=Ib.then(Ob,Ob),await Ib.catch(()=>{}),!e)return;let t=ar?.[e];t?It("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):bn("tickets",e).catch(()=>{})}async function ir(e){return(await Nl())[e]??null}async function dO(){return{...await Nl()}}async function pO(){return(await Cb()).length>0}async function mi(e,t,{source:n="api"}={}){let r=await Cb();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(),cardUrl:Cl(e.id),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 Nl())[e.id]=c,await Oo(e.id),await N({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 Ml(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 Rl(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await hO(e.id,c,"linked"),c}async function Pb(e){let t=await Nl();return t[e]?(delete t[e],await Oo(e),!0):!1}var Mb=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function fO(e,t){if(!e.track?.cwd)return null;let n=po(await K({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function n6(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${Mb(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${Mb(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function r6(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(Mb(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function Ml(e,t){let n=await Ws(t);if(!n)return;let r=await fO(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:t.cardUrl??Cl(e),title:`Bostrat Track: ${t.track.name}`,subtitle:r6(t,r)})}function o6(e){return Ef(QR(),e)}var _f=e=>o6(e)??"(no public URL on this node \u2014 link it to a plane)",s6={linked:"linked",opened:"prOpened",merged:"prMerged"};function a6(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 mO(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await Oo(e),await N({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 hO(e,t,n){let r=await Ws(t);if(!r)return;let o=r.cfg.ticketFlow?.[s6[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Nb(s,a),c=a6(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 mO(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await N({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:cO(),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 wO(e){let t=await ir(e);if(!t)throw new Error("no ticket linked to this Track");let n=await Ws(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=Nb(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await Oo(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 Db(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await ir(e);if(!r)throw new Error("no ticket linked to this Track");let o=await Ws(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Nb(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 Oo(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await mO(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function gO(e,t){let n=await ir(e);if(!n)throw new Error("no ticket linked to this Track");let r=await Ws(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 N({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 yO(e,t,n){if(!t)throw new Error("offerId required");return vo(`tkt:${e.id}:${t}`,()=>i6(e,t,n))}async function i6(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 Db(e.id,o.payload.to?.id,{mode:"offer"})),await N({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 rO=50;async function bO(){let e=await Fs();if(!e)throw new Error("no ticketing integration configured");return pi(e)}function c6(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>rO)throw new Error(`too many issues (${n.length}); cap is ${rO} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function l6(e,t,n,r){let o=r??await pi(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 ir(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 kO(e,t){let n=await Fs();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=c6(t),o=await pi(n),s=await l6(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=cO();return await N({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 xO(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 N({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 Fs();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let w=(await pi(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 xb(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 vb(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 N({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 N({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 ir(e.id)&&(f=await mi(e,p[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:f?f.key:null}}async function Rl(e,t){let n=await Ws(e);n&&await n.api.createComment(n.cfg,e,t)}async function u6(e,t,n){let r=await Ws(e);if(!r)return null;let o=await Mr(t);if(!o)return null;let s=$n(o,n);if(!s)return null;let a=await Ol.readFile(dn(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 oO=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),$b=new Map;function d6(e,t){if(oO()<=0)return Ml(e,t);if($b.has(e))return;let n=setTimeout(()=>{$b.delete(e),ir(e).then(r=>r?Ml(e,r):null).catch(()=>{})},oO());n.unref?.(),$b.set(e,n)}var sO=new Map;async function aO(e,t,n){let r=sO.get(e)??0;Date.now()-r<600*1e3||(sO.set(e,Date.now()),await N({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function p6(e,{resolveTrack:t=null}={}){let n=await ir(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Cb())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 mi(s,o,{source:"chat"})}catch(a){await aO(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 Oo(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await Oo(e.trackId),await Ml(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 Oo(e.trackId),await Ml(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await fO(n,e.trackId).catch(()=>null):null;await Rl(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
769
769
 
770
- Agent cost for this Track: ${t6(o)}.`:"")),await hO(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await l6(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await Rl(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
770
+ Agent cost for this Track: ${n6(o)}.`:"")),await hO(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await u6(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await Rl(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
771
771
 
772
- ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await Rl(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 Rl(n,`**Bostrat** \u2014 live preview **${r.name}**: ${Ef(r.slug)}
773
- _(runs on the Track's branch; a Bostrat-fronted preview, not a public deployment)_`);break}case"cost.recorded":await u6(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await aO(e.trackId,s?.cwd??null,o)}}function vO({resolveTrack:e}){Ze.on("event",t=>{d6(t,{resolveTrack:e}).catch(()=>{})})}async function SO(){if(!Ge())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await pt("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Nl(),r=0;for(let[o,s]of Object.entries(n))await It("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}gs();Va();import p6 from"ws";var AO=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function _f(e,t,n={}){let r=await fetch(`${AO()}/${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 Bb=(e,t)=>_f("chat.postMessage",e,t),qs=(e,t)=>_f("chat.update",e,t);async function Mt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function f6(e,t,n={}){let r=await fetch(`${AO()}/${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 TO(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await f6("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 _f("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var m6=2200;function EO({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 _f("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new p6(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()},m6);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 $O=()=>process.env.BOSTRAT_STATE_DIR||$f.join(process.env.HOME||w6.tmpdir(),".bostrat"),Hb=()=>$f.join($O(),"slack.json"),If=null,Lb=null,jb=Promise.resolve();async function qb(){return If||(Lb??=Pl.readFile(Hb(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>If=e).finally(()=>Lb=null),Lb)}async function _O(){let e=JSON.stringify({threads:If},null,2),t=`${Hb()}.${process.pid}.tmp`;await Pl.mkdir($O(),{recursive:!0}),await Pl.writeFile(t,e),await Pl.rename(t,Hb())}async function Nn(){jb=jb.then(_O,_O),await jb.catch(()=>{})}async function Gb(e){return(await qb())[e]??null}async function g6(e,t){let n=await qb();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var $e=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function Dl(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function y6(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return Dl(n.replace(/\n+/g," "),t)}function RO(e){let t=`*${$e(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${$e(e.repoLabel)} \xB7 \`${$e(e.branch||"?")}\` \xB7 lead *${$e(e.lead)}*`,r=e.kickoff?`> ${$e(Dl(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
774
- ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${Cl(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function Wb(e,t){await qs(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:RO(t)})}async function Co(e,t,n,r=void 0){return Bb(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var IO=new Set;function Mo(e){IO.add(e),e.catch(()=>{}).finally(()=>IO.delete(e))}var qe=e=>({response_type:"ephemeral",text:e}),b6="*/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._",k6=["claude","cursor","codex"];function Fb(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 Ub=(e,t)=>qe(`No live Track matches \u201C${$e(t)}\u201D. Live: ${e.map(n=>`\`${$e(n.name)}\``).join(" \xB7 ")||"none"}`);async function OO(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 Mt(o,{...qe(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await Mt(o,{...qe("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?$f.basename(c.base):"fresh workspace"),lead:"claude"},u=await Bb(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:RO(l),unfurl_links:!1});l.ts=u.ts,(await qb())[i.id]=l,await Nn(),await Mt(o,{...qe(`\u2713 *${$e(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await Mt(o,{...qe(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function x6(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await Gb(n.id);s&&(s.archivedAt=Date.now(),await Nn(),await Wb(t,s).catch(()=>{})),await Mt(r,{...qe(`\u2713 *${$e(n.name)}* archived.`),replace_original:!0})}catch(s){await Mt(r,{...qe(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function v6(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await Mt(o,{...qe(`\u2713 Handing *${$e(n.name)}* to ${$e(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await Mt(o,{...qe(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function S6(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 Mt(r,{...qe(`\u2713 Stopped *${$e(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 Mt(r,{...qe(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function A6(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:Dl(`${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 *${$e(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function T6(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?$f.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 *${$e(s.name)}* \u2014 ${$e(i)}${a.branch?` \`${$e(a.branch)}\``:""} \xB7 lead ${$e(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
772
+ ![${r.name}](${o})`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await Rl(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 Rl(n,`**Bostrat** \u2014 live preview **${r.name}**: ${_f(r.slug)}
773
+ _(runs on the Track's branch; a Bostrat-fronted preview, not a public deployment)_`);break}case"cost.recorded":await d6(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await aO(e.trackId,s?.cwd??null,o)}}function vO({resolveTrack:e}){Ze.on("event",t=>{p6(t,{resolveTrack:e}).catch(()=>{})})}async function SO(){if(!Ge())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await pt("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Nl(),r=0;for(let[o,s]of Object.entries(n))await It("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}gs();Va();import f6 from"ws";var TO=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function If(e,t,n={}){let r=await fetch(`${TO()}/${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 Bb=(e,t)=>If("chat.postMessage",e,t),qs=(e,t)=>If("chat.update",e,t);async function Mt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function m6(e,t,n={}){let r=await fetch(`${TO()}/${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 AO(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await m6("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 If("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var h6=2200;function EO({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 If("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new f6(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()},h6);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 $O=()=>process.env.BOSTRAT_STATE_DIR||Rf.join(process.env.HOME||g6.tmpdir(),".bostrat"),Hb=()=>Rf.join($O(),"slack.json"),$f=null,Lb=null,jb=Promise.resolve();async function qb(){return $f||(Lb??=Pl.readFile(Hb(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>$f=e).finally(()=>Lb=null),Lb)}async function _O(){let e=JSON.stringify({threads:$f},null,2),t=`${Hb()}.${process.pid}.tmp`;await Pl.mkdir($O(),{recursive:!0}),await Pl.writeFile(t,e),await Pl.rename(t,Hb())}async function Nn(){jb=jb.then(_O,_O),await jb.catch(()=>{})}async function Gb(e){return(await qb())[e]??null}async function y6(e,t){let n=await qb();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var $e=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");function Dl(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function b6(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return Dl(n.replace(/\n+/g," "),t)}function RO(e){let t=`*${$e(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${$e(e.repoLabel)} \xB7 \`${$e(e.branch||"?")}\` \xB7 lead *${$e(e.lead)}*`,r=e.kickoff?`> ${$e(Dl(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
774
+ ${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${Cl(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function Wb(e,t){await qs(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:RO(t)})}async function Co(e,t,n,r=void 0){return Bb(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var IO=new Set;function Mo(e){IO.add(e),e.catch(()=>{}).finally(()=>IO.delete(e))}var qe=e=>({response_type:"ephemeral",text:e}),k6="*/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._",x6=["claude","cursor","codex"];function Fb(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 Ub=(e,t)=>qe(`No live Track matches \u201C${$e(t)}\u201D. Live: ${e.map(n=>`\`${$e(n.name)}\``).join(" \xB7 ")||"none"}`);async function OO(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 Mt(o,{...qe(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await Mt(o,{...qe("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?Rf.basename(c.base):"fresh workspace"),lead:"claude"},u=await Bb(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:RO(l),unfurl_links:!1});l.ts=u.ts,(await qb())[i.id]=l,await Nn(),await Mt(o,{...qe(`\u2713 *${$e(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await Mt(o,{...qe(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function v6(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await Gb(n.id);s&&(s.archivedAt=Date.now(),await Nn(),await Wb(t,s).catch(()=>{})),await Mt(r,{...qe(`\u2713 *${$e(n.name)}* archived.`),replace_original:!0})}catch(s){await Mt(r,{...qe(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function S6(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await Mt(o,{...qe(`\u2713 Handing *${$e(n.name)}* to ${$e(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await Mt(o,{...qe(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function T6(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 Mt(r,{...qe(`\u2713 Stopped *${$e(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 Mt(r,{...qe(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function A6(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:Dl(`${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 *${$e(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function E6(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?Rf.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 *${$e(s.name)}* \u2014 ${$e(i)}${a.branch?` \`${$e(a.branch)}\``:""} \xB7 lead ${$e(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
775
775
  `)+(o?`
776
- _${o} archived_`:"")}async function E6(e,t){let n=await Us();if(!n)return qe("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 qe("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?(Mo(OO(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),qe(`Starting *${$e(u)}* on ${$e(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:A6(u,i)}}case"archive":{if(!a.length)return qe("Usage: `/bostrat archive <track>`");let{match:i,live:c}=Fb(await r.listTracks(),a.join(" "));return i?(Mo(x6(e,n,{track:i,responseUrl:t.response_url})),qe(`Archiving *${$e(i.name)}*\u2026`)):Ub(c,a.join(" "))}case"handoff":{let i=r.knownAgents??k6,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return qe(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:d}=Fb(await r.listTracks(),l);return u?(Mo(v6(e,n,{track:u,agent:c,responseUrl:t.response_url})),qe(`Handing *${$e(u.name)}* to ${$e(c)}\u2026`)):Ub(d,l)}case"stop":{if(!a.length)return qe("Usage: `/bostrat stop <track>`");let{match:i,live:c}=Fb(await r.listTracks(),a.join(" "));return i?(Mo(S6(e,n,{track:i,responseUrl:t.response_url})),qe(`Stopping *${$e(i.name)}*\u2026`)):Ub(c,a.join(" "))}case"list":return qe(await T6(r));default:return qe(b6)}}async function _6(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await Gb(o);try{if(await e.deps.answerPrompt(o,{promptId:s,answers:[a]}),i?.prompt?.promptId===s){let{ts:c,question:l}=i.prompt;delete i.prompt,await Nn(),await qs(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${$e(l||"question")}~
777
- \u2713 *${$e(a)}*`}}]}).catch(()=>{})}}catch(c){await Mt(n.response_url,qe(`Couldn't answer: ${c?.message||c}`))}}async function I6(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)?ho.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,Ca(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 Mt(n.response_url,qe(`Couldn't act on the offer: ${c?.message||c}`))}}async function $6(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 Mt(n.response_url,qe(`Couldn't act on the offer: ${i?.message||i}`))}}async function R6(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await Us();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 Mt(t.response_url,{...qe(`Starting *${$e(s)}*\u2026`),replace_original:!0}),Mo(OO(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"?Mo(_6(e,r,t,o)):n.action_id==="bostrat-ship"?Mo(I6(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&Mo($6(e,r,t,o))}async function O6(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 g6(t.channel,t.thread_ts);if(!n)return;let r=await Us();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await Co(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function M6(e){return async t=>{if(t.type==="slash_commands")return E6(e,t.payload);if(t.type==="interactive"){await R6(e,t.payload);return}if(t.type==="events_api"){await O6(e,t.payload?.event);return}}}var C6=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 N6(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${$e(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:Dl(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 P6(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await qs(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${$e(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await Co(e,t,r.question||"The lead needs an answer",N6(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await Nn()}async function D6(e,t,n){let r=n.payload||{};if(!t.prompt||r.promptId&&t.prompt.promptId!==r.promptId)return;let{ts:o,question:s}=t.prompt;delete t.prompt,await Nn(),await qs(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${$e(s||"question")}~
778
- \u2713 _answered_`}}]})}async function B6(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 Co(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${$e(Dl(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await Nn()}async function L6(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await Nn();let s=r.action==="dismiss"?"dismissed":r.action==="pr-exists"?`PR${r.existingPr?.number?` #${r.existingPr.number}`:""} already open \u2014 pick how to ship`:r.action==="pr"?"\u2713 opening a PR":"\u2713 pushing";await qs(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function j6(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 Co(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${$e(r.branch)})`:""} is already open. Push the update to it, or open a new PR?`}},{type:"actions",elements:[s("push",`Push to ${o}`,"primary"),s("new","Open a new PR"),s("dismiss","Not now")]}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await Nn()}async function F6(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await Nn();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await qs(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function U6(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??H6)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await TO(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${$e(o.name)}*${a}${o.group?` (group \`${$e(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${$e(a.name)}*`).join(", ");await Co(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${$e(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function H6(e,t){let n=await Mr(e);if(!n)return null;let r=$n(n,t);if(!r)return null;let o=await Pl.readFile(dn(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function W6(e,t){if(!C6.has(t.type))return;let n=await Gb(t.trackId);if(!n)return;let r=await Us();if(!r)return;let o=t.payload||{};switch(t.type){case"turn.user":if(n.kickoff||t.actor!=="user"||!o.text)return;n.kickoff=o.text,await Nn(),await Wb(r,n);return;case"turn.agent":{if(!o.text)return;let s=y6(o.text);if(!s)return;await Co(r,n,s,[{type:"section",text:{type:"mrkdwn",text:$e(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${Cl(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return P6(r,n,t);case"prompt.answered":return D6(r,n,t);case"pr.offered":return B6(r,n,t);case"pr.offer.answered":return L6(r,n,t);case"pr.exists.offered":return j6(r,n,t);case"pr.exists.answered":return F6(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 Co(r,n,`${s}${o.url?`: ${o.url}`:o.number?` (#${o.number})`:""}`);return}case"handoff.done":if(!o.toAgent||o.toAgent===n.lead)return;n.lead=o.toAgent,await Nn(),await Wb(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await Co(r,n,`Live preview ${o.name}: ${Ef(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${$e(o.name)}*: ${Ef(o.slug)}
779
- _runs on the Track's branch; a Bostrat-fronted preview, not a public deployment_`}}]);return}case"mock.state.changed":return U6(r,n,t,e.deps)}}function MO(e){let t={deps:e};Ze.on("event",s=>{W6(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await Us()||(r&&clearInterval(r),r=null,n=EO({getToken:async()=>(await Us())?.appToken,onEnvelope:M6(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}vn();be();ty();yn();Hw();yr();import q6 from"node:fs/promises";function G6(e){let t=new Map;for(let n of String(e||"").split(`
780
- `)){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 K6(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 V6=new Set(["Write","Edit","NotebookEdit"]),z6=220,J6=160;function Y6(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(V6.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,z6)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=Wo(o.command.trim().replace(/\s+/g," ")).slice(0,J6));return r}function X6(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?xn(t.cwd,t.sessionId):t?.cwd?Gm(t.cwd):null}async function NO(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 N(r,{...s,...c}))};switch(e?.hook_event_name){case"SessionStart":await i({type:"session.ready",actor:"system",payload:{sessionId:e.session_id,source:e.source??null,standing:await Ya(o?.cwd)}});break;case"UserPromptSubmit":{let c=String(e.prompt??e.user_prompt??""),l=fp(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:Y6(e,o)});break;case"Stop":await Z6(r,o,e,i);break;default:break}return a}async function Z6(e,t,n,r){let o=[],s=X6(n,t);if(s)try{o=G6(await q6.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=await K(e),c=K6(i),l=o.filter(p=>!c.has(p.messageId));if(l.length){let p=new Map;for(let f of l){let w=`${f.model||"unknown"}\0${f.speed||""}`,h=p.get(w)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},cacheWriteTtl:null,messageIds:[]};for(let y of Object.keys(h.tokens))h.tokens[y]+=f.tokens[y];f.cacheWriteTtl&&(h.cacheWriteTtl??={m5:0,h1:0},h.cacheWriteTtl.m5+=f.cacheWriteTtl.m5,h.cacheWriteTtl.h1+=f.cacheWriteTtl.h1),h.messageIds.push(f.messageId),h.speed=f.speed||null,p.set(w,h)}for(let[f,w]of p){let h=f.split("\0")[0];await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:h,usd:Wn(h,w.tokens,void 0,w.speed?{speed:w.speed}:void 0),tokens:w.tokens,...w.speed?{speed:w.speed}:{},cacheWriteTtl:w.cacheWriteTtl,messageId:w.messageIds[w.messageIds.length-1],messageIds:w.messageIds,apiCalls:w.messageIds.length}})}}let u=CO(a),d=l[0]??null;await r({type:"context.usage",actor:"system",source:"transcript",payload:{model:a.model,occupancy:u,tokens:a.tokens,first:d?{occupancy:CO(d),tokens:d.tokens}:null,calls:l.length,turnIndex:Q6(i,t)}})}var CO=e=>e.tokens.input+e.tokens.cacheWrite+e.tokens.cacheRead;function Q6(e,t){if(!t?.name)return null;let n=ji(t,Date.now()),r=n!=null?t.epochs[n]?.startedAt??null:null,o=0;for(let s of e)s.type!=="turn.user"||s.source!=="hook"||s.boxId!==t.name||r!=null&&Number(s.ts)<r||o++;return o||null}Ys();Bm();dp();be();be();fo();be();fo();yr();function Bl(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 PO=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),DO=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},Rf=e=>Math.round(e*1e4)/1e4;async function Kb(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=PO(),d=0,p=[];for(let f of e||[]){let w=await K(f),h=po(w,{boxLabels:Bl(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 y of h.unpricedModels||[])l.add(y);DO(u,h.totalTokens);for(let[y,k]of Object.entries(h.byModel))n[y]||={usd:0,events:0,tokens:PO()},n[y].usd=Rf(n[y].usd+k.usd),n[y].events+=k.events,DO(n[y].tokens,k.tokens);for(let[y,k]of Object.entries(h.byProvider))r[y]||={usd:0,events:0},r[y].usd=Rf(r[y].usd+k.usd),r[y].events+=k.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:Rf(o),asRecordedUsd:Rf(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 No=e=>`$${e.toFixed(4)}`,hi=(e,t)=>String(e).padEnd(t);function BO(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 ${No(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 ${No(t.asRecordedUsd)} \xB7 current-rates total ${No(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${No(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(` ${hi(a,26)} ${hi(No(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(` ${hi(a.name||a.id,30)} ${No(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${hi(c.label,40)} ${hi(No(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))}${hi(No(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
781
- `)}be();fw();import aK from"node:fs/promises";import iK from"node:path";od();ld();fo();var Of=e=>e.payload?.ts??e.ts,eK=12e4,fn=e=>Math.round(e*1e4)/1e4,tK=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{},byTrack:new Map});function nK(e,{since:t}){let{track:n,events:r,brief:o}=e,s=x=>Of(x)>=t,a=gr([gc(n?.name),gc(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let x of r)if(x.type==="subtask.delegated"&&x.boxId&&x.payload?.task){let S=gr(x.payload.task);S&&i.set(x.boxId,S)}let c=new Map,l=x=>{let S=x||"unattributed";return c.has(S)||c.set(S,{segments:[u(null)],lastTs:null,provider:null}),c.get(S)},u=(x,{shape:S="initial",continuation:_=!1,text:M=null,ts:P=null}={})=>({textCat:x,shape:S,continuation:_,text:M,ts:P,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),d=[...r].sort((x,S)=>Of(x)-Of(S)),p=0,f=0,w=0,h={turns:0};for(let x of d){let S=l(x.boxId),_=S.segments[S.segments.length-1],M=Of(x);switch(S.lastTs!=null&&M>S.lastTs&&s(x)&&(_.activeMs+=Math.min(M-S.lastTs,eK)),S.lastTs=M,x.provider&&(S.provider=x.provider),x.type){case"turn.user":{let P=x.payload?.text;if(x.source==="hook"||!String(P||"").trim()||x.payload?.note||kc(P))break;let j=gr(P),T=!!x.payload?.kind,$=T||Ev(P),L=u(j,{shape:T?"injected":$?"follow-up":"novel-ask",continuation:!j&&$,text:jO(P),ts:M});S.segments.push(L),s(x)&&(L.turns+=1);break}case"peer.message":{let P=x.payload?.text;if(!String(P||"").trim())break;let j=gr(P),T=u(j,{shape:"peer",continuation:!j,text:jO(P),ts:M});S.segments.push(T),s(x)&&(T.turns+=1);break}case"tool.called":{if(x.source==="transcript")break;let P=x.payload?.tool;P&&(_.tools[P]=(_.tools[P]||0)+1),s(x)&&(_.toolCalls+=1);break}case"cost.recorded":{if(!s(x))break;let{usd:P,tokens:j,model:T,unpriced:$}=sn(x);$&&(h.turns+=1),_.usd+=P,j&&(_.tokens.input+=j.input,_.tokens.output+=j.output,_.tokens.cacheRead+=j.cacheRead,_.tokens.cacheWrite+=j.cacheWrite),_.models[T]=(_.models[T]||0)+P,x.provider&&(_.provider=x.provider);break}case"handoff.done":s(x)&&(p+=1);break;case"subtask.merged":s(x)&&(f+=1);break;case"error":s(x)&&x.payload?.kind==="subtask-failed"&&(w+=1);break;default:break}}let y=new Map,k={usd:0,turns:0,byShape:{},samples:[]},g=!1;for(let[x,S]of c){let _=null;for(let M of S.segments){let P=null,j=null;if(M.textCat)P=M.textCat.category,j="text";else if(i.get(x))P=i.get(x).category,j="boxTask";else if(M.continuation&&_)P=_,j="inherited";else{let R=Tv(M.tools);R?(P=R.category,j="toolMix"):a&&(P=a.category,j="hint")}if(P&&(_=P),!(M.usd>0||M.activeMs>0||M.turns>0||M.toolCalls>0))continue;let $=P??"uncategorized";y.has($)||y.set($,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{}});let L=y.get($);L.usd+=M.usd,L.activeMs+=M.activeMs,L.turns+=M.turns,L.toolCalls+=M.toolCalls,j&&(L.provenance[j]=(L.provenance[j]||0)+M.usd);for(let[R,A]of Object.entries(M.models))L.models[R]=(L.models[R]||0)+A;let H=M.provider||S.provider;H&&(L.providers[H]=(L.providers[H]||0)+M.usd),H==="cursor"&&M.usd===0&&(g=!0),P||(k.usd+=M.usd,k.turns+=M.turns,k.byShape[M.shape]=(k.byShape[M.shape]||0)+M.usd,M.usd>0&&M.text&&k.samples.push({trackId:n?.id,track:n?.name||n?.id,shape:M.shape,usd:fn(M.usd),ts:M.ts,text:M.text}))}}return{perCategory:y,uncategorized:k,handoffs:p,merged:f,failed:w,sawCursorActivity:g,unpricedTurns:h.turns}}function Vb(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 k of e||[]){let{track:g,events:x}=k;if(!x?.length){a+=1;continue}let{perCategory:S,uncategorized:_,handoffs:M,merged:P,failed:j,sawCursorActivity:T,unpricedTurns:$}=nK(k,{since:r});T&&(i=!0),c+=$,l.usd+=_.usd,l.turns+=_.turns;for(let[H,R]of Object.entries(_.byShape))l.byShape[H]=(l.byShape[H]||0)+R;l.samples.push(..._.samples);let L={trackId:g?.id,name:g?.name||g?.id,archived:!!g?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:M,subtasksMerged:P,subtasksFailed:j};for(let[H,R]of S){L.usd+=R.usd,L.activeMs+=R.activeMs,L.turns+=R.turns,L.categories[H]={usd:fn(R.usd),activeMs:R.activeMs};for(let[W,B]of Object.entries(R.models))L.models[W]=fn((L.models[W]||0)+B);for(let[W,B]of Object.entries(R.providers))L.providers[W]=fn((L.providers[W]||0)+B);o.has(H)||o.set(H,tK());let A=o.get(H);A.usd+=R.usd,A.activeMs+=R.activeMs,A.turns+=R.turns,A.toolCalls+=R.toolCalls;for(let[W,B]of Object.entries(R.models))A.models[W]=(A.models[W]||0)+B;for(let[W,B]of Object.entries(R.providers))A.providers[W]=(A.providers[W]||0)+B;for(let[W,B]of Object.entries(R.provenance))A.provenance[W]=(A.provenance[W]||0)+B;let C=A.byTrack.get(g?.id)||{usd:0,activeMs:0};C.usd+=R.usd,C.activeMs+=R.activeMs,A.byTrack.set(g?.id,C)}(L.usd>0||L.activeMs>0||L.turns>0)&&(L.usd=fn(L.usd),L.dominantCategory=sK(L.categories),s.push(L))}let u=[...o.values()].reduce((k,g)=>k+g.usd,0),d=[...o.values()].reduce((k,g)=>k+g.activeMs,0),p=u>0?"usd":"time",f=p==="usd"?u:d,w=new Map((e||[]).map(k=>[k.track?.id,k.track?.name||k.track?.id])),h=[...o.entries()].map(([k,g])=>({category:k,sharePct:f>0?Math.round((p==="usd"?g.usd:g.activeMs)/f*100):0,shareBasis:p,usd:fn(g.usd),activeMs:g.activeMs,turns:g.turns,toolCalls:g.toolCalls,models:Ll(g.models),providers:Ll(g.providers),provenance:Ll(g.provenance),topWorkstreams:[...g.byTrack.entries()].sort((x,S)=>S[1].usd-x[1].usd||S[1].activeMs-x[1].activeMs).slice(0,2).map(([x,S])=>({trackId:x,name:w.get(x),usd:fn(S.usd),activeMs:S.activeMs}))})).sort((k,g)=>g.usd-k.usd||g.activeMs-k.activeMs);s.sort((k,g)=>g.usd-k.usd||g.activeMs-k.activeMs);let y={};for(let k of o.values())for(let[g,x]of Object.entries(k.provenance))y[g]=(y[g]||0)+x;return{since:r,capturedAt:n,totalUsd:fn(u),activeMs:d,turns:[...o.values()].reduce((k,g)=>k+g.turns,0),bullets:h,workstreams:s,provenance:Ll(y),gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c,uncategorized:{usd:fn(l.usd),turns:l.turns,sharePct:u>0?Math.round(l.usd/u*100):0,byShape:Ll(l.byShape),top:l.samples.sort((k,g)=>g.usd-k.usd).slice(0,rK)}}}}var rK=25,LO=160,jO=e=>{let t=String(e||"").replace(/\s+/g," ").trim();return t.length>LO?`${t.slice(0,LO).trimEnd()}\u2026`:t},oK=10;function FO(e,{thresholdPct:t=oK}={}){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:fn(o),totalUsd:fn(r),turns:n.turns||0,inheritedPct:r>0?Math.round((e?.provenance?.inherited||0)/r*100):0,problems:i}}var sK=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,fn(n)]));var Ks={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function cK(e){let t=String(e||"7d");return t in Ks?{key:t,ms:Ks[t]}:{key:"7d",ms:Ks["7d"]}}function lK(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=jd(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 uK(e){if(!e?.cwd)return null;try{let n=(await aK.readFile(iK.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 zb(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}:cK(t),d=[];for(let w of e||[]){let h=await K(w),y=lK(w,h);i&&c<o&&(y=y.filter(k=>(k.ts??0)<=c)),d.push({track:w,events:y,brief:await uK(w)})}let p=Vb(d,{windowMs:u,now:c}),f=l==="7d"&&c===o?p:Vb(d,{windowMs:Ks["7d"],now:o});return{window:l,...p,categorization:FO(f)}}var jl=e=>`$${Number(e||0).toFixed(2)}`,UO=e=>{let t=Math.round((e||0)/6e4);return t>=60?`${Math.floor(t/60)}h${String(t%60).padStart(2,"0")}`:`${t}m`},Gs=(e,t)=>String(e).padEnd(t);function HO(e){let t=[];t.push(`USAGE ROUNDUP \xB7 ${e.window} \xB7 ${jl(e.totalUsd)} \xB7 ${UO(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(` ${Gs(`${a.shareBasis==="time"?"~":""}${a.sharePct}%`,5)} ${Gs(a.category,15)} ${Gs(jl(a.usd),10)} ${Gs(UO(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 ${jl(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} ${jl(i)}`).join(" \xB7 ")||"none")),s.top?.length||t.push(" (nothing unmatched carried cost in this window)");for(let a of s.top||[])t.push(` ${Gs(jl(a.usd),8)} ${Gs(a.shape,10)} ${Gs(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(`
782
- `)}yr();var Po=36e5,KO=24*Po,dK=400,pK=12,Vs=e=>Math.round(e*1e4)/1e4;function Jb({window:e,from:t,to:n,now:r=Date.now()}={}){let o=Number(t),s=Number(n);if(Number.isFinite(o)&&o>0){let c=Number.isFinite(s)&&s>o?Math.min(s,r):r;return{key:"custom",since:o,until:c}}let a=String(e||"7d")in Ks?String(e||"7d"):"7d",i=Ks[a];return{key:a,since:i==null?null:r-i,until:r}}var fK=(e,t)=>e!=null&&t-e<=48*Po?Po:KO;function WO(e,t){if(t===Po)return Math.floor(e/Po)*Po;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function mK(e,t){if(t===Po)return e+Po;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var qO=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),GO=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},hK=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Vs(n)]));async function VO(e,t={}){let n=t.now??Date.now(),r=Jb({...t,now:n}),o=r.since==null?KO:fK(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=qO(),d=0,p=0,f=0,w=0,h=0,y=0,k=new Set,g=new Map,x=[],S=[],_=[],M=null;for(let T of e||[]){let L=(await K(T)).filter(A=>A.type==="cost.recorded");if(!L.length){T.archivedAt||_.push(T.name||T.id);continue}let H=[];for(let A of L){let C=A.ts??0;s(C)?H.push(A):i(C)&&(y+=sn(A).usd)}if(!H.length)continue;let R=po(H,{boxLabels:Bl(T)});d+=R.totalUsd,p+=R.turns,f+=R.repricedTurns||0,w+=R.asRecordedUsd||0,h+=R.unpricedTurns||0;for(let A of R.unpricedModels||[])k.add(A);GO(u,R.totalTokens);for(let[A,C]of Object.entries(R.byModel))c[A]||={usd:0,events:0,tokens:qO()},c[A].usd=Vs(c[A].usd+C.usd),c[A].events+=C.events,GO(c[A].tokens,C.tokens);for(let[A,C]of Object.entries(R.byProvider))l[A]||={usd:0,events:0},l[A].usd=Vs(l[A].usd+C.usd),l[A].events+=C.events;for(let A of H){let{usd:C}=sn(A);if(!C)continue;let W=WO(A.ts??0,o),B=g.get(W)??{t:W,total:0,byProvider:{}};B.total+=C;let Z=A.provider||"unknown";B.byProvider[Z]=(B.byProvider[Z]||0)+C,g.set(W,B),(M==null||W<M)&&(M=W)}x.push({id:T.id,name:T.name||T.id,archived:!!T.archivedAt,usd:R.totalUsd,turns:R.turns,providers:Object.keys(R.byProvider)});for(let[A,C]of Object.entries(R.byBox))S.push({trackId:T.id,trackName:T.name||T.id,boxId:A,...C})}let P=r.since!=null?WO(r.since,o):M,j=[];for(let T=P,$=0;T!=null&&T<r.until&&$<dK;T=mK(T,o),$++){let L=g.get(T);j.push(L?{t:T,total:Vs(L.total),byProvider:hK(L.byProvider)}:{t:T,total:0,byProvider:{}})}return x.sort((T,$)=>$.usd-T.usd),S.sort((T,$)=>$.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:Vs(d),asRecordedUsd:Vs(w),turns:p,repricedTurns:f,unpricedTurns:h,unpricedModels:[...k],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:x.length,tracksSilentLive:_},prior:a!=null?{totalUsd:Vs(y),since:r.since-a,until:r.since}:null,tracks:x.slice(0,50),boxes:S.slice(0,pK)}}lp();var wK=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),gK=20,yK=40;async function zO(e,t={}){let n=t.now??Date.now(),r=Jb({...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=Bl(l);for(let f of u){if(!wK.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=OE(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:xo,decayEndDays:Cw,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,gK),fixes:c.fixes.slice(0,yK)}}import bK from"node:fs";import JO from"node:fs/promises";import Fl from"node:os";import kK from"node:path";Sg();dt();var xK=1024*1024,Mf=e=>Math.round(e/xK);async function vK(e){try{let t=await JO.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:Mf(r),diskTotalMb:Mf(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function SK(){try{return(await kn()).filter(t=>t.isBostrat).length}catch{return null}}async function AK(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await JO.readdir(kK.join(Al,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function YO({stateDir:e=Al,now:t=Date.now}={}){let n=Fl.totalmem(),[r,o,s,a]=await Promise.all([Ep().catch(()=>null),vK(bK.existsSync(e)?e:Fl.tmpdir()),SK(),AK()]),i=Fl.cpus()?.length||null,c=Fl.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?Mf(n-r):null,memTotalMb:Mf(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(Fl.uptime())}}sg();be();lh();Wi();yr();be();yr();var TK=864e5;function EK(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=Wn(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 XO(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*TK,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=EK(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}}ng();ry();Pd();xt();an();import wi from"node:fs/promises";import _K from"node:fs";import At from"node:path";import IK from"node:os";import{execFile as $K}from"node:child_process";import{promisify as RK}from"node:util";var OK=RK($K),ZO=process.env.BOSTRAT_STATE_DIR||At.join(process.env.HOME||IK.tmpdir(),".bostrat"),Cf=!1,Yb=null;async function Xb(e,t){let n=await wi.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await wi.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await wi.mkdir(At.dirname(t),{recursive:!0}),await wi.copyFile(e,t),!0)}var MK=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 Nf(e,t,{skip:n=null}={}){let r=0,o=await wi.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(MK.has(s.name)||n?.has(s.name))continue;let a=At.join(e,s.name);s.isDirectory()?r+=await Nf(a,At.join(t,s.name)):s.isFile()&&(r+=await Xb(a,At.join(t,s.name))?1:0)}return r}async function QO({stateDir:e=ZO,dest:t=process.env.BOSTRAT_SYNC_DIR||`${ZO}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await wi.mkdir(t,{recursive:!0});let o=0;o+=await Xb(At.join(e,"tracks.json"),At.join(t,"tracks.json"))?1:0,o+=await Xb(At.join(e,"events.jsonl"),At.join(t,"events.jsonl"))?1:0,o+=await Nf(At.join(e,"events"),At.join(t,"events")),o+=await Nf(At.join(e,"memory"),At.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await Nf(At.join(u.cwd,".bostrat"),At.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>OK("git",["-C",t,...u]);_K.existsSync(At.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 vm(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||Cf))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,Cf&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),Cf=!1,Yb=null}catch(u){Cf=!0;let d=(u?.stderr||u?.message||String(u)).trim().split(`
783
- `).slice(-3).join(" | ").slice(0,300);d!==Yb&&(Yb=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)}}}Wg();vn();es();dt();$i();import{execFile as CK}from"node:child_process";import{promisify as NK}from"node:util";import{randomUUID as PK}from"node:crypto";import DK from"node:fs";import BK from"node:os";import LK from"node:path";var Bo=NK(CK),Pf=e=>new Promise(t=>setTimeout(t,e)),Lo=Fm,Zb=process.env.BOSTRAT_USAGE_PROBE_CWD||LK.join(BK.homedir(),".bostrat","usage-probe"),jK=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,FK=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,UK=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,eM=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,Do=null,Ul=null,Hl=null;async function HK(){try{return await Bo(oe,se("has-session","-t",Lo)),!0}catch{return!1}}function WK(){Do&&clearTimeout(Do),Do=setTimeout(()=>qK().catch(()=>{}),jK),Do.unref&&Do.unref()}async function qK(){Do&&(clearTimeout(Do),Do=null);try{await Bo(oe,se("kill-session","-t",Lo))}catch{}}async function GK(){let e=Date.now()+UK;for(;;){let t=await Qb().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await Pf(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await Pf(500)}}async function KK(){if(await HK())return;if(!await Zr())throw new Error("host tmux server not running \u2014 start globo-tmux.service");DK.mkdirSync(Zb,{recursive:!0}),await Wr(Zb);let e=PK();await Bo(oe,se("new-session","-d","-s",Lo,"-c",Zb,"-x","200","-y","60",...Xi()));let t=`${jm} --session-id ${e}`;await Bo(oe,se("send-keys","-t",Lo,t,"Enter")),await GK()}async function Qb(){let{stdout:e}=await Bo(oe,se("capture-pane","-t",Lo,"-p"));return e}async function VK(){await KK(),await Bo(oe,se("send-keys","-t",Lo,"-l","/usage")),await Bo(oe,se("send-keys","-t",Lo,"Enter"));let e=Date.now()+FK,t="";for(;await Pf(400),t=await Qb(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await Pf(900),t=await Qb(),await Bo(oe,se("send-keys","-t",Lo,"Escape")).catch(()=>{}),WK(),t}function zK(e){let t=String(e||"").split(`
784
- `).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 JK(e){let t=String(e||"").split(`
785
- `).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 tM({fresh:e=!1}={}){return!e&&Ul&&Date.now()-Ul.at<eM?Ul.data:Hl||(Hl=(async()=>{try{let t=await VK(),n=zK(t),r={...n,contributors:JK(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return Ul={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 Ul={at:Date.now()-(eM-3e3),data:n},n}finally{Hl=null}})(),Hl)}var YK=262144;function XK(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 ZK=new Set([300]),QK=new Set([10080]);function eV(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:ZK.has(t)?"session":QK.has(t)?"week":"other"}function tV(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 nV(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?XK((o-n)/1e3):null,resetsAt:o}}var Wl=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function rV(e,t=Date.now()){let n=String(e||"").split(`
786
- `),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 Wl(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=Wl(r);[c.primary,c.secondary].forEach((f,w)=>{let h=nV(f,l,t);if(!h)return;let y=eV(f.window_minutes);y===null&&(y=w===0?"session":"week"),y==="session"&&!u.session?u.session=h:y==="week"&&!u.week?u.week=h:(u.other??=[]).push({label:tV(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{...Wl(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return Wl(r)}return Wl(r)}async function ek(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await Zo(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 jt(n.file,YK),o=rV(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 nM(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 Df({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 ek(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await ek(null))}return n.has("cursor")&&r.push(await Df({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function Df(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?ek(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await tM({fresh:t})}}Gr();xt();xt();function oV(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}var sV=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),Bf=(e,t)=>Object.assign(new Error(e),{status:t});async function rM(e,t){if(!oV(t))throw Bf("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${De(t)}${e}`,{headers:sV(t)})}catch(o){throw Bf(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw Bf(r?.error||`plane replied ${n.status}`,n.status);return r}async function oM(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await rM(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function sM(e,{env:t=process.env}={}){if(!e)throw Bf("message id required",400);return(await rM(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}Oc();Xd();function tk(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 aV(e){let[t,n]=e.split("/"),r=tk(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 aM(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(aV).filter(Boolean)}function iV(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function iM(e){let t=aM(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:iV,allowed(r){if(n)return!0;let o=tk((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function cM(e,t){let n=aM(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=tk(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import lM from"node:crypto";import Lf from"node:fs";import cV from"node:path";function uM(e=process.env,{stateDir:t=Al,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=cV.join(t,"api-token");try{let a=Lf.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=lM.randomBytes(32).toString("base64url");try{Lf.mkdirSync(t,{recursive:!0}),Lf.writeFileSync(o,s+`
787
- `,{mode:384}),Lf.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function ql(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 dM(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:lM.timingSafeEqual(n,r)}function pM(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 lV=[/^\/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/],uV=e=>lV.some(t=>t.test(e));function fM({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=pM(o);return dM(c,e)?a():uV(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||ql(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 mM(e,t,{enforce:n=!0}={}){return!n||dM(pM(e),t)?!0:ql(e)}yn();Sp();Sp();import dV from"node:http";import pV from"node:net";function Gl(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 jf(e){let t=Gl(e.headers.host);return t?{slug:t,view:yg(t)}:null}var fV=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),mV=e=>{let t=fV(e.name);return`<!doctype html><meta charset="utf-8">
776
+ _${o} archived_`:"")}async function _6(e,t){let n=await Us();if(!n)return qe("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 qe("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?(Mo(OO(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),qe(`Starting *${$e(u)}* on ${$e(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:A6(u,i)}}case"archive":{if(!a.length)return qe("Usage: `/bostrat archive <track>`");let{match:i,live:c}=Fb(await r.listTracks(),a.join(" "));return i?(Mo(v6(e,n,{track:i,responseUrl:t.response_url})),qe(`Archiving *${$e(i.name)}*\u2026`)):Ub(c,a.join(" "))}case"handoff":{let i=r.knownAgents??x6,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return qe(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:d}=Fb(await r.listTracks(),l);return u?(Mo(S6(e,n,{track:u,agent:c,responseUrl:t.response_url})),qe(`Handing *${$e(u.name)}* to ${$e(c)}\u2026`)):Ub(d,l)}case"stop":{if(!a.length)return qe("Usage: `/bostrat stop <track>`");let{match:i,live:c}=Fb(await r.listTracks(),a.join(" "));return i?(Mo(T6(e,n,{track:i,responseUrl:t.response_url})),qe(`Stopping *${$e(i.name)}*\u2026`)):Ub(c,a.join(" "))}case"list":return qe(await E6(r));default:return qe(k6)}}async function I6(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await Gb(o);try{if(await e.deps.answerPrompt(o,{promptId:s,answers:[a]}),i?.prompt?.promptId===s){let{ts:c,question:l}=i.prompt;delete i.prompt,await Nn(),await qs(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${$e(l||"question")}~
777
+ \u2713 *${$e(a)}*`}}]}).catch(()=>{})}}catch(c){await Mt(n.response_url,qe(`Couldn't answer: ${c?.message||c}`))}}async function $6(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)?ho.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,Ca(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 Mt(n.response_url,qe(`Couldn't act on the offer: ${c?.message||c}`))}}async function R6(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 Mt(n.response_url,qe(`Couldn't act on the offer: ${i?.message||i}`))}}async function O6(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await Us();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 Mt(t.response_url,{...qe(`Starting *${$e(s)}*\u2026`),replace_original:!0}),Mo(OO(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"?Mo(I6(e,r,t,o)):n.action_id==="bostrat-ship"?Mo($6(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&Mo(R6(e,r,t,o))}async function M6(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 y6(t.channel,t.thread_ts);if(!n)return;let r=await Us();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await Co(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function C6(e){return async t=>{if(t.type==="slash_commands")return _6(e,t.payload);if(t.type==="interactive"){await O6(e,t.payload);return}if(t.type==="events_api"){await M6(e,t.payload?.event);return}}}var N6=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 P6(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${$e(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:Dl(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 D6(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await qs(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${$e(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await Co(e,t,r.question||"The lead needs an answer",P6(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await Nn()}async function B6(e,t,n){let r=n.payload||{};if(!t.prompt||r.promptId&&t.prompt.promptId!==r.promptId)return;let{ts:o,question:s}=t.prompt;delete t.prompt,await Nn(),await qs(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${$e(s||"question")}~
778
+ \u2713 _answered_`}}]})}async function L6(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 Co(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${$e(Dl(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await Nn()}async function j6(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await Nn();let s=r.action==="dismiss"?"dismissed":r.action==="pr-exists"?`PR${r.existingPr?.number?` #${r.existingPr.number}`:""} already open \u2014 pick how to ship`:r.action==="pr"?"\u2713 opening a PR":"\u2713 pushing";await qs(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function F6(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 Co(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${$e(r.branch)})`:""} is already open. Push the update to it, or open a new PR?`}},{type:"actions",elements:[s("push",`Push to ${o}`,"primary"),s("new","Open a new PR"),s("dismiss","Not now")]}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await Nn()}async function U6(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await Nn();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await qs(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function H6(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??W6)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await AO(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${$e(o.name)}*${a}${o.group?` (group \`${$e(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${$e(a.name)}*`).join(", ");await Co(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${$e(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function W6(e,t){let n=await Mr(e);if(!n)return null;let r=$n(n,t);if(!r)return null;let o=await Pl.readFile(dn(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function q6(e,t){if(!N6.has(t.type))return;let n=await Gb(t.trackId);if(!n)return;let r=await Us();if(!r)return;let o=t.payload||{};switch(t.type){case"turn.user":if(n.kickoff||t.actor!=="user"||!o.text)return;n.kickoff=o.text,await Nn(),await Wb(r,n);return;case"turn.agent":{if(!o.text)return;let s=b6(o.text);if(!s)return;await Co(r,n,s,[{type:"section",text:{type:"mrkdwn",text:$e(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${Cl(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return D6(r,n,t);case"prompt.answered":return B6(r,n,t);case"pr.offered":return L6(r,n,t);case"pr.offer.answered":return j6(r,n,t);case"pr.exists.offered":return F6(r,n,t);case"pr.exists.answered":return U6(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 Co(r,n,`${s}${o.url?`: ${o.url}`:o.number?` (#${o.number})`:""}`);return}case"handoff.done":if(!o.toAgent||o.toAgent===n.lead)return;n.lead=o.toAgent,await Nn(),await Wb(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await Co(r,n,`Live preview ${o.name}: ${_f(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${$e(o.name)}*: ${_f(o.slug)}
779
+ _runs on the Track's branch; a Bostrat-fronted preview, not a public deployment_`}}]);return}case"mock.state.changed":return H6(r,n,t,e.deps)}}function MO(e){let t={deps:e};Ze.on("event",s=>{q6(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await Us()||(r&&clearInterval(r),r=null,n=EO({getToken:async()=>(await Us())?.appToken,onEnvelope:C6(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}vn();be();ty();yn();Hw();yr();import G6 from"node:fs/promises";function K6(e){let t=new Map;for(let n of String(e||"").split(`
780
+ `)){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 V6(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 z6=new Set(["Write","Edit","NotebookEdit"]),J6=220,Y6=160;function X6(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(z6.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,J6)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=Wo(o.command.trim().replace(/\s+/g," ")).slice(0,Y6));return r}function Z6(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?xn(t.cwd,t.sessionId):t?.cwd?Km(t.cwd):null}async function NO(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 N(r,{...s,...c}))};switch(e?.hook_event_name){case"SessionStart":await i({type:"session.ready",actor:"system",payload:{sessionId:e.session_id,source:e.source??null,standing:await Ya(o?.cwd)}});break;case"UserPromptSubmit":{let c=String(e.prompt??e.user_prompt??""),l=mp(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:X6(e,o)});break;case"Stop":await Q6(r,o,e,i);break;default:break}return a}async function Q6(e,t,n,r){let o=[],s=Z6(n,t);if(s)try{o=K6(await G6.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=await K(e),c=V6(i),l=o.filter(p=>!c.has(p.messageId));if(l.length){let p=new Map;for(let f of l){let w=`${f.model||"unknown"}\0${f.speed||""}`,h=p.get(w)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},cacheWriteTtl:null,messageIds:[]};for(let y of Object.keys(h.tokens))h.tokens[y]+=f.tokens[y];f.cacheWriteTtl&&(h.cacheWriteTtl??={m5:0,h1:0},h.cacheWriteTtl.m5+=f.cacheWriteTtl.m5,h.cacheWriteTtl.h1+=f.cacheWriteTtl.h1),h.messageIds.push(f.messageId),h.speed=f.speed||null,p.set(w,h)}for(let[f,w]of p){let h=f.split("\0")[0];await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:h,usd:Wn(h,w.tokens,void 0,w.speed?{speed:w.speed}:void 0),tokens:w.tokens,...w.speed?{speed:w.speed}:{},cacheWriteTtl:w.cacheWriteTtl,messageId:w.messageIds[w.messageIds.length-1],messageIds:w.messageIds,apiCalls:w.messageIds.length}})}}let u=CO(a),d=l[0]??null;await r({type:"context.usage",actor:"system",source:"transcript",payload:{model:a.model,occupancy:u,tokens:a.tokens,first:d?{occupancy:CO(d),tokens:d.tokens}:null,calls:l.length,turnIndex:eK(i,t)}})}var CO=e=>e.tokens.input+e.tokens.cacheWrite+e.tokens.cacheRead;function eK(e,t){if(!t?.name)return null;let n=ji(t,Date.now()),r=n!=null?t.epochs[n]?.startedAt??null:null,o=0;for(let s of e)s.type!=="turn.user"||s.source!=="hook"||s.boxId!==t.name||r!=null&&Number(s.ts)<r||o++;return o||null}Ys();Lm();pp();be();be();fo();be();fo();yr();function Bl(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 PO=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),DO=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},Of=e=>Math.round(e*1e4)/1e4;async function Kb(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=PO(),d=0,p=[];for(let f of e||[]){let w=await K(f),h=po(w,{boxLabels:Bl(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 y of h.unpricedModels||[])l.add(y);DO(u,h.totalTokens);for(let[y,k]of Object.entries(h.byModel))n[y]||={usd:0,events:0,tokens:PO()},n[y].usd=Of(n[y].usd+k.usd),n[y].events+=k.events,DO(n[y].tokens,k.tokens);for(let[y,k]of Object.entries(h.byProvider))r[y]||={usd:0,events:0},r[y].usd=Of(r[y].usd+k.usd),r[y].events+=k.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:Of(o),asRecordedUsd:Of(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 No=e=>`$${e.toFixed(4)}`,hi=(e,t)=>String(e).padEnd(t);function BO(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 ${No(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 ${No(t.asRecordedUsd)} \xB7 current-rates total ${No(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${No(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(` ${hi(a,26)} ${hi(No(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(` ${hi(a.name||a.id,30)} ${No(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${hi(c.label,40)} ${hi(No(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))}${hi(No(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
781
+ `)}be();fw();import iK from"node:fs/promises";import cK from"node:path";sd();ud();fo();var Mf=e=>e.payload?.ts??e.ts,tK=12e4,fn=e=>Math.round(e*1e4)/1e4,nK=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{},byTrack:new Map});function rK(e,{since:t}){let{track:n,events:r,brief:o}=e,s=x=>Mf(x)>=t,a=gr([gc(n?.name),gc(n?.workspace?.branch),o].filter(Boolean).join(" ")),i=new Map;for(let x of r)if(x.type==="subtask.delegated"&&x.boxId&&x.payload?.task){let S=gr(x.payload.task);S&&i.set(x.boxId,S)}let c=new Map,l=x=>{let S=x||"unattributed";return c.has(S)||c.set(S,{segments:[u(null)],lastTs:null,provider:null}),c.get(S)},u=(x,{shape:S="initial",continuation:_=!1,text:M=null,ts:P=null}={})=>({textCat:x,shape:S,continuation:_,text:M,ts:P,tools:{},usd:0,tokens:{input:0,output:0,cacheRead:0,cacheWrite:0},models:{},provider:null,activeMs:0,turns:0,toolCalls:0}),d=[...r].sort((x,S)=>Mf(x)-Mf(S)),p=0,f=0,w=0,h={turns:0};for(let x of d){let S=l(x.boxId),_=S.segments[S.segments.length-1],M=Mf(x);switch(S.lastTs!=null&&M>S.lastTs&&s(x)&&(_.activeMs+=Math.min(M-S.lastTs,tK)),S.lastTs=M,x.provider&&(S.provider=x.provider),x.type){case"turn.user":{let P=x.payload?.text;if(x.source==="hook"||!String(P||"").trim()||x.payload?.note||kc(P))break;let j=gr(P),A=!!x.payload?.kind,$=A||Ev(P),L=u(j,{shape:A?"injected":$?"follow-up":"novel-ask",continuation:!j&&$,text:jO(P),ts:M});S.segments.push(L),s(x)&&(L.turns+=1);break}case"peer.message":{let P=x.payload?.text;if(!String(P||"").trim())break;let j=gr(P),A=u(j,{shape:"peer",continuation:!j,text:jO(P),ts:M});S.segments.push(A),s(x)&&(A.turns+=1);break}case"tool.called":{if(x.source==="transcript")break;let P=x.payload?.tool;P&&(_.tools[P]=(_.tools[P]||0)+1),s(x)&&(_.toolCalls+=1);break}case"cost.recorded":{if(!s(x))break;let{usd:P,tokens:j,model:A,unpriced:$}=sn(x);$&&(h.turns+=1),_.usd+=P,j&&(_.tokens.input+=j.input,_.tokens.output+=j.output,_.tokens.cacheRead+=j.cacheRead,_.tokens.cacheWrite+=j.cacheWrite),_.models[A]=(_.models[A]||0)+P,x.provider&&(_.provider=x.provider);break}case"handoff.done":s(x)&&(p+=1);break;case"subtask.merged":s(x)&&(f+=1);break;case"error":s(x)&&x.payload?.kind==="subtask-failed"&&(w+=1);break;default:break}}let y=new Map,k={usd:0,turns:0,byShape:{},samples:[]},g=!1;for(let[x,S]of c){let _=null;for(let M of S.segments){let P=null,j=null;if(M.textCat)P=M.textCat.category,j="text";else if(i.get(x))P=i.get(x).category,j="boxTask";else if(M.continuation&&_)P=_,j="inherited";else{let R=Av(M.tools);R?(P=R.category,j="toolMix"):a&&(P=a.category,j="hint")}if(P&&(_=P),!(M.usd>0||M.activeMs>0||M.turns>0||M.toolCalls>0))continue;let $=P??"uncategorized";y.has($)||y.set($,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{}});let L=y.get($);L.usd+=M.usd,L.activeMs+=M.activeMs,L.turns+=M.turns,L.toolCalls+=M.toolCalls,j&&(L.provenance[j]=(L.provenance[j]||0)+M.usd);for(let[R,T]of Object.entries(M.models))L.models[R]=(L.models[R]||0)+T;let H=M.provider||S.provider;H&&(L.providers[H]=(L.providers[H]||0)+M.usd),H==="cursor"&&M.usd===0&&(g=!0),P||(k.usd+=M.usd,k.turns+=M.turns,k.byShape[M.shape]=(k.byShape[M.shape]||0)+M.usd,M.usd>0&&M.text&&k.samples.push({trackId:n?.id,track:n?.name||n?.id,shape:M.shape,usd:fn(M.usd),ts:M.ts,text:M.text}))}}return{perCategory:y,uncategorized:k,handoffs:p,merged:f,failed:w,sawCursorActivity:g,unpricedTurns:h.turns}}function Vb(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 k of e||[]){let{track:g,events:x}=k;if(!x?.length){a+=1;continue}let{perCategory:S,uncategorized:_,handoffs:M,merged:P,failed:j,sawCursorActivity:A,unpricedTurns:$}=rK(k,{since:r});A&&(i=!0),c+=$,l.usd+=_.usd,l.turns+=_.turns;for(let[H,R]of Object.entries(_.byShape))l.byShape[H]=(l.byShape[H]||0)+R;l.samples.push(..._.samples);let L={trackId:g?.id,name:g?.name||g?.id,archived:!!g?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:M,subtasksMerged:P,subtasksFailed:j};for(let[H,R]of S){L.usd+=R.usd,L.activeMs+=R.activeMs,L.turns+=R.turns,L.categories[H]={usd:fn(R.usd),activeMs:R.activeMs};for(let[W,B]of Object.entries(R.models))L.models[W]=fn((L.models[W]||0)+B);for(let[W,B]of Object.entries(R.providers))L.providers[W]=fn((L.providers[W]||0)+B);o.has(H)||o.set(H,nK());let T=o.get(H);T.usd+=R.usd,T.activeMs+=R.activeMs,T.turns+=R.turns,T.toolCalls+=R.toolCalls;for(let[W,B]of Object.entries(R.models))T.models[W]=(T.models[W]||0)+B;for(let[W,B]of Object.entries(R.providers))T.providers[W]=(T.providers[W]||0)+B;for(let[W,B]of Object.entries(R.provenance))T.provenance[W]=(T.provenance[W]||0)+B;let C=T.byTrack.get(g?.id)||{usd:0,activeMs:0};C.usd+=R.usd,C.activeMs+=R.activeMs,T.byTrack.set(g?.id,C)}(L.usd>0||L.activeMs>0||L.turns>0)&&(L.usd=fn(L.usd),L.dominantCategory=aK(L.categories),s.push(L))}let u=[...o.values()].reduce((k,g)=>k+g.usd,0),d=[...o.values()].reduce((k,g)=>k+g.activeMs,0),p=u>0?"usd":"time",f=p==="usd"?u:d,w=new Map((e||[]).map(k=>[k.track?.id,k.track?.name||k.track?.id])),h=[...o.entries()].map(([k,g])=>({category:k,sharePct:f>0?Math.round((p==="usd"?g.usd:g.activeMs)/f*100):0,shareBasis:p,usd:fn(g.usd),activeMs:g.activeMs,turns:g.turns,toolCalls:g.toolCalls,models:Ll(g.models),providers:Ll(g.providers),provenance:Ll(g.provenance),topWorkstreams:[...g.byTrack.entries()].sort((x,S)=>S[1].usd-x[1].usd||S[1].activeMs-x[1].activeMs).slice(0,2).map(([x,S])=>({trackId:x,name:w.get(x),usd:fn(S.usd),activeMs:S.activeMs}))})).sort((k,g)=>g.usd-k.usd||g.activeMs-k.activeMs);s.sort((k,g)=>g.usd-k.usd||g.activeMs-k.activeMs);let y={};for(let k of o.values())for(let[g,x]of Object.entries(k.provenance))y[g]=(y[g]||0)+x;return{since:r,capturedAt:n,totalUsd:fn(u),activeMs:d,turns:[...o.values()].reduce((k,g)=>k+g.turns,0),bullets:h,workstreams:s,provenance:Ll(y),gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c,uncategorized:{usd:fn(l.usd),turns:l.turns,sharePct:u>0?Math.round(l.usd/u*100):0,byShape:Ll(l.byShape),top:l.samples.sort((k,g)=>g.usd-k.usd).slice(0,oK)}}}}var oK=25,LO=160,jO=e=>{let t=String(e||"").replace(/\s+/g," ").trim();return t.length>LO?`${t.slice(0,LO).trimEnd()}\u2026`:t},sK=10;function FO(e,{thresholdPct:t=sK}={}){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:fn(o),totalUsd:fn(r),turns:n.turns||0,inheritedPct:r>0?Math.round((e?.provenance?.inherited||0)/r*100):0,problems:i}}var aK=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,fn(n)]));var Ks={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function lK(e){let t=String(e||"7d");return t in Ks?{key:t,ms:Ks[t]}:{key:"7d",ms:Ks["7d"]}}function uK(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=Fd(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 dK(e){if(!e?.cwd)return null;try{let n=(await iK.readFile(cK.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 zb(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}:lK(t),d=[];for(let w of e||[]){let h=await K(w),y=uK(w,h);i&&c<o&&(y=y.filter(k=>(k.ts??0)<=c)),d.push({track:w,events:y,brief:await dK(w)})}let p=Vb(d,{windowMs:u,now:c}),f=l==="7d"&&c===o?p:Vb(d,{windowMs:Ks["7d"],now:o});return{window:l,...p,categorization:FO(f)}}var jl=e=>`$${Number(e||0).toFixed(2)}`,UO=e=>{let t=Math.round((e||0)/6e4);return t>=60?`${Math.floor(t/60)}h${String(t%60).padStart(2,"0")}`:`${t}m`},Gs=(e,t)=>String(e).padEnd(t);function HO(e){let t=[];t.push(`USAGE ROUNDUP \xB7 ${e.window} \xB7 ${jl(e.totalUsd)} \xB7 ${UO(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(` ${Gs(`${a.shareBasis==="time"?"~":""}${a.sharePct}%`,5)} ${Gs(a.category,15)} ${Gs(jl(a.usd),10)} ${Gs(UO(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 ${jl(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} ${jl(i)}`).join(" \xB7 ")||"none")),s.top?.length||t.push(" (nothing unmatched carried cost in this window)");for(let a of s.top||[])t.push(` ${Gs(jl(a.usd),8)} ${Gs(a.shape,10)} ${Gs(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(`
782
+ `)}yr();var Po=36e5,KO=24*Po,pK=400,fK=12,Vs=e=>Math.round(e*1e4)/1e4;function Jb({window:e,from:t,to:n,now:r=Date.now()}={}){let o=Number(t),s=Number(n);if(Number.isFinite(o)&&o>0){let c=Number.isFinite(s)&&s>o?Math.min(s,r):r;return{key:"custom",since:o,until:c}}let a=String(e||"7d")in Ks?String(e||"7d"):"7d",i=Ks[a];return{key:a,since:i==null?null:r-i,until:r}}var mK=(e,t)=>e!=null&&t-e<=48*Po?Po:KO;function WO(e,t){if(t===Po)return Math.floor(e/Po)*Po;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function hK(e,t){if(t===Po)return e+Po;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var qO=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),GO=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},wK=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Vs(n)]));async function VO(e,t={}){let n=t.now??Date.now(),r=Jb({...t,now:n}),o=r.since==null?KO:mK(r.since,r.until),s=A=>(r.since==null||A>=r.since)&&A<r.until,a=r.since!=null?r.until-r.since:null,i=A=>a!=null&&A>=r.since-a&&A<r.since,c={},l={},u=qO(),d=0,p=0,f=0,w=0,h=0,y=0,k=new Set,g=new Map,x=[],S=[],_=[],M=null;for(let A of e||[]){let L=(await K(A)).filter(T=>T.type==="cost.recorded");if(!L.length){A.archivedAt||_.push(A.name||A.id);continue}let H=[];for(let T of L){let C=T.ts??0;s(C)?H.push(T):i(C)&&(y+=sn(T).usd)}if(!H.length)continue;let R=po(H,{boxLabels:Bl(A)});d+=R.totalUsd,p+=R.turns,f+=R.repricedTurns||0,w+=R.asRecordedUsd||0,h+=R.unpricedTurns||0;for(let T of R.unpricedModels||[])k.add(T);GO(u,R.totalTokens);for(let[T,C]of Object.entries(R.byModel))c[T]||={usd:0,events:0,tokens:qO()},c[T].usd=Vs(c[T].usd+C.usd),c[T].events+=C.events,GO(c[T].tokens,C.tokens);for(let[T,C]of Object.entries(R.byProvider))l[T]||={usd:0,events:0},l[T].usd=Vs(l[T].usd+C.usd),l[T].events+=C.events;for(let T of H){let{usd:C}=sn(T);if(!C)continue;let W=WO(T.ts??0,o),B=g.get(W)??{t:W,total:0,byProvider:{}};B.total+=C;let Z=T.provider||"unknown";B.byProvider[Z]=(B.byProvider[Z]||0)+C,g.set(W,B),(M==null||W<M)&&(M=W)}x.push({id:A.id,name:A.name||A.id,archived:!!A.archivedAt,usd:R.totalUsd,turns:R.turns,providers:Object.keys(R.byProvider)});for(let[T,C]of Object.entries(R.byBox))S.push({trackId:A.id,trackName:A.name||A.id,boxId:T,...C})}let P=r.since!=null?WO(r.since,o):M,j=[];for(let A=P,$=0;A!=null&&A<r.until&&$<pK;A=hK(A,o),$++){let L=g.get(A);j.push(L?{t:A,total:Vs(L.total),byProvider:wK(L.byProvider)}:{t:A,total:0,byProvider:{}})}return x.sort((A,$)=>$.usd-A.usd),S.sort((A,$)=>$.usd-A.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:Vs(d),asRecordedUsd:Vs(w),turns:p,repricedTurns:f,unpricedTurns:h,unpricedModels:[...k],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:x.length,tracksSilentLive:_},prior:a!=null?{totalUsd:Vs(y),since:r.since-a,until:r.since}:null,tracks:x.slice(0,50),boxes:S.slice(0,fK)}}up();var gK=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),yK=20,bK=40;async function zO(e,t={}){let n=t.now??Date.now(),r=Jb({...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=Bl(l);for(let f of u){if(!gK.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=OE(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:xo,decayEndDays:Cw,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,yK),fixes:c.fixes.slice(0,bK)}}import kK from"node:fs";import JO from"node:fs/promises";import Fl from"node:os";import xK from"node:path";Sg();dt();var vK=1024*1024,Cf=e=>Math.round(e/vK);async function SK(e){try{let t=await JO.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:Cf(r),diskTotalMb:Cf(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function TK(){try{return(await kn()).filter(t=>t.isBostrat).length}catch{return null}}async function AK(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await JO.readdir(xK.join(Tl,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function YO({stateDir:e=Tl,now:t=Date.now}={}){let n=Fl.totalmem(),[r,o,s,a]=await Promise.all([_p().catch(()=>null),SK(kK.existsSync(e)?e:Fl.tmpdir()),TK(),AK()]),i=Fl.cpus()?.length||null,c=Fl.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?Cf(n-r):null,memTotalMb:Cf(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(Fl.uptime())}}sg();be();lh();Wi();yr();be();yr();var EK=864e5;function _K(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=Wn(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 XO(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*EK,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=_K(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}}ng();ry();Dd();xt();an();import wi from"node:fs/promises";import IK from"node:fs";import Tt from"node:path";import $K from"node:os";import{execFile as RK}from"node:child_process";import{promisify as OK}from"node:util";var MK=OK(RK),ZO=process.env.BOSTRAT_STATE_DIR||Tt.join(process.env.HOME||$K.tmpdir(),".bostrat"),Nf=!1,Yb=null;async function Xb(e,t){let n=await wi.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await wi.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await wi.mkdir(Tt.dirname(t),{recursive:!0}),await wi.copyFile(e,t),!0)}var CK=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 Pf(e,t,{skip:n=null}={}){let r=0,o=await wi.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(CK.has(s.name)||n?.has(s.name))continue;let a=Tt.join(e,s.name);s.isDirectory()?r+=await Pf(a,Tt.join(t,s.name)):s.isFile()&&(r+=await Xb(a,Tt.join(t,s.name))?1:0)}return r}async function QO({stateDir:e=ZO,dest:t=process.env.BOSTRAT_SYNC_DIR||`${ZO}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await wi.mkdir(t,{recursive:!0});let o=0;o+=await Xb(Tt.join(e,"tracks.json"),Tt.join(t,"tracks.json"))?1:0,o+=await Xb(Tt.join(e,"events.jsonl"),Tt.join(t,"events.jsonl"))?1:0,o+=await Pf(Tt.join(e,"events"),Tt.join(t,"events")),o+=await Pf(Tt.join(e,"memory"),Tt.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await Pf(Tt.join(u.cwd,".bostrat"),Tt.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>MK("git",["-C",t,...u]);IK.existsSync(Tt.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 Sm(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||Nf))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,Nf&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),Nf=!1,Yb=null}catch(u){Nf=!0;let d=(u?.stderr||u?.message||String(u)).trim().split(`
783
+ `).slice(-3).join(" | ").slice(0,300);d!==Yb&&(Yb=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)}}}Wg();vn();es();dt();$i();import{execFile as NK}from"node:child_process";import{promisify as PK}from"node:util";import{randomUUID as DK}from"node:crypto";import BK from"node:fs";import LK from"node:os";import jK from"node:path";var Bo=PK(NK),Df=e=>new Promise(t=>setTimeout(t,e)),Lo=Um,Zb=process.env.BOSTRAT_USAGE_PROBE_CWD||jK.join(LK.homedir(),".bostrat","usage-probe"),FK=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,UK=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,HK=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,eM=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,Do=null,Ul=null,Hl=null;async function WK(){try{return await Bo(oe,se("has-session","-t",Lo)),!0}catch{return!1}}function qK(){Do&&clearTimeout(Do),Do=setTimeout(()=>GK().catch(()=>{}),FK),Do.unref&&Do.unref()}async function GK(){Do&&(clearTimeout(Do),Do=null);try{await Bo(oe,se("kill-session","-t",Lo))}catch{}}async function KK(){let e=Date.now()+HK;for(;;){let t=await Qb().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await Df(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await Df(500)}}async function VK(){if(await WK())return;if(!await Zr())throw new Error("host tmux server not running \u2014 start globo-tmux.service");BK.mkdirSync(Zb,{recursive:!0}),await Wr(Zb);let e=DK();await Bo(oe,se("new-session","-d","-s",Lo,"-c",Zb,"-x","200","-y","60",...Xi()));let t=`${Fm} --session-id ${e}`;await Bo(oe,se("send-keys","-t",Lo,t,"Enter")),await KK()}async function Qb(){let{stdout:e}=await Bo(oe,se("capture-pane","-t",Lo,"-p"));return e}async function zK(){await VK(),await Bo(oe,se("send-keys","-t",Lo,"-l","/usage")),await Bo(oe,se("send-keys","-t",Lo,"Enter"));let e=Date.now()+UK,t="";for(;await Df(400),t=await Qb(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await Df(900),t=await Qb(),await Bo(oe,se("send-keys","-t",Lo,"Escape")).catch(()=>{}),qK(),t}function JK(e){let t=String(e||"").split(`
784
+ `).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 YK(e){let t=String(e||"").split(`
785
+ `).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 tM({fresh:e=!1}={}){return!e&&Ul&&Date.now()-Ul.at<eM?Ul.data:Hl||(Hl=(async()=>{try{let t=await zK(),n=JK(t),r={...n,contributors:YK(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return Ul={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 Ul={at:Date.now()-(eM-3e3),data:n},n}finally{Hl=null}})(),Hl)}var XK=262144;function ZK(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 QK=new Set([300]),eV=new Set([10080]);function tV(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:QK.has(t)?"session":eV.has(t)?"week":"other"}function nV(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 rV(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?ZK((o-n)/1e3):null,resetsAt:o}}var Wl=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function oV(e,t=Date.now()){let n=String(e||"").split(`
786
+ `),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 Wl(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=Wl(r);[c.primary,c.secondary].forEach((f,w)=>{let h=rV(f,l,t);if(!h)return;let y=tV(f.window_minutes);y===null&&(y=w===0?"session":"week"),y==="session"&&!u.session?u.session=h:y==="week"&&!u.week?u.week=h:(u.other??=[]).push({label:nV(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{...Wl(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return Wl(r)}return Wl(r)}async function ek(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await Zo(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 jt(n.file,XK),o=oV(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 nM(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 Bf({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 ek(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await ek(null))}return n.has("cursor")&&r.push(await Bf({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function Bf(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?ek(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await tM({fresh:t})}}Gr();xt();xt();function sV(e=process.env){return!!(De(e)&&e.BOSTRAT_PLANE_TOKEN)}var aV=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),Lf=(e,t)=>Object.assign(new Error(e),{status:t});async function rM(e,t){if(!sV(t))throw Lf("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${De(t)}${e}`,{headers:aV(t)})}catch(o){throw Lf(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw Lf(r?.error||`plane replied ${n.status}`,n.status);return r}async function oM(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await rM(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function sM(e,{env:t=process.env}={}){if(!e)throw Lf("message id required",400);return(await rM(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}Oc();Zd();function tk(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 iV(e){let[t,n]=e.split("/"),r=tk(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 aM(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(iV).filter(Boolean)}function cV(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function iM(e){let t=aM(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:cV,allowed(r){if(n)return!0;let o=tk((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function cM(e,t){let n=aM(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=tk(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import lM from"node:crypto";import jf from"node:fs";import lV from"node:path";function uM(e=process.env,{stateDir:t=Tl,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=lV.join(t,"api-token");try{let a=jf.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=lM.randomBytes(32).toString("base64url");try{jf.mkdirSync(t,{recursive:!0}),jf.writeFileSync(o,s+`
787
+ `,{mode:384}),jf.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function ql(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 dM(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:lM.timingSafeEqual(n,r)}function pM(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 uV=[/^\/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/],dV=e=>uV.some(t=>t.test(e));function fM({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=pM(o);return dM(c,e)?a():dV(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||ql(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 mM(e,t,{enforce:n=!0}={}){return!n||dM(pM(e),t)?!0:ql(e)}yn();Tp();Tp();import pV from"node:http";import fV from"node:net";function Gl(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 Ff(e){let t=Gl(e.headers.host);return t?{slug:t,view:yg(t)}:null}var mV=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;"),hV=e=>{let t=mV(e.name);return`<!doctype html><meta charset="utf-8">
788
788
  <meta http-equiv="refresh" content="3">
789
789
  <title>${t} \u2014 starting</title>
790
790
  <body style="font-family:system-ui;background:#0b0e14;color:#dce3f0;display:grid;place-items:center;height:100vh;margin:0">
791
791
  <div style="text-align:center"><p style="font-size:2rem;margin:0">\u23F3</p>
792
- <p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function hM(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 wM(e,t,n){let r=jf(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(mV(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=dV.request({host:"127.0.0.1",port:o.port,method:e.method,path:hM(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 gM(e,t,n){let r=jf(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
792
+ <p><b>${t}</b> is waking up\u2026</p><p style="opacity:.6">auto-refreshing</p></div>`};function hM(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 wM(e,t,n){let r=Ff(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(hV(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=pV.request({host:"127.0.0.1",port:o.port,method:e.method,path:hM(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 gM(e,t,n){let r=Ff(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
793
793
  \r
794
794
  bostrat: no live view "${s}"\r
795
- `),t.destroy(),!0;let a=pV.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${hM(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
795
+ `),t.destroy(),!0;let a=fV.connect(o.port,"127.0.0.1",()=>{let c=[`${e.method} ${hM(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
796
796
  `)+`\r
797
797
  \r
798
- `),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 nk(e){let t=typeof e=="string"?{host:e}:e||{},n=t["x-bostrat-view-base"];if(typeof n=="string"&&n)return{proto:t["x-forwarded-proto"]==="https"?"https":"http",host:n.replace(/:\d+$/,"").toLowerCase(),source:"header"};let r=Tb();if(r)return{proto:"https",host:r,source:"learned"};let o=Eb();if(o)return{...o,source:"env"};let s=String(t.host||"").replace(/:\d+$/,"").toLowerCase();if(!s||!s.includes(".")||/^[\d.]+$/.test(s))return null;let a=s.split(".");return{proto:"http",host:Gl(s)&&yg(a[0])?a.slice(1).join("."):s,source:"request"}}function yM(e,t){return Tf(nk(t),e.slug)}function bM({app:e,onUpgrade:t,extractViewSlug:n,log:r=console}){let o=s=>{r.warn?.(`[bostrat-agent] view listener refused non-view Host ${JSON.stringify(String(s||""))}`)};return{request(s,a){if(!n(s.headers.host)){o(s.headers.host),a.statusCode=403,a.setHeader("content-type","text/plain"),a.end("bostrat: this listener serves views only");return}e(s,a)},upgrade(s,a,i){if(!n(s.headers.host)){o(s.headers.host),a.write(`HTTP/1.1 403 Forbidden\r
798
+ `),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 nk(e){let t=typeof e=="string"?{host:e}:e||{},n=t["x-bostrat-view-base"];if(typeof n=="string"&&n)return{proto:t["x-forwarded-proto"]==="https"?"https":"http",host:n.replace(/:\d+$/,"").toLowerCase(),source:"header"};let r=Ab();if(r)return{proto:"https",host:r,source:"learned"};let o=Eb();if(o)return{...o,source:"env"};let s=String(t.host||"").replace(/:\d+$/,"").toLowerCase();if(!s||!s.includes(".")||/^[\d.]+$/.test(s))return null;let a=s.split(".");return{proto:"http",host:Gl(s)&&yg(a[0])?a.slice(1).join("."):s,source:"request"}}function yM(e,t){return Ef(nk(t),e.slug)}function bM({app:e,onUpgrade:t,extractViewSlug:n,log:r=console}){let o=s=>{r.warn?.(`[bostrat-agent] view listener refused non-view Host ${JSON.stringify(String(s||""))}`)};return{request(s,a){if(!n(s.headers.host)){o(s.headers.host),a.statusCode=403,a.setHeader("content-type","text/plain"),a.end("bostrat: this listener serves views only");return}e(s,a)},upgrade(s,a,i){if(!n(s.headers.host)){o(s.headers.host),a.write(`HTTP/1.1 403 Forbidden\r
799
799
  \r
800
- `),a.destroy();return}t(s,a,i)}}}function kM(e,{addr:t,port:n,log:r=console,retryMs:o=15e3,maxRetries:s=1/0}){let a=0;e.on("error",c=>{let l=c?.code||c?.message;if(e.listening){r.error?.(`[bostrat-agent] view listener on ${t}:${n}: ${l}`);return}if(a>s){r.error?.(`[bostrat-agent] view listener on ${t}:${n} failed (${l}) \u2014 giving up`);return}r.error?.(`[bostrat-agent] view listener on ${t}:${n} failed (${l}) \u2014 retrying in ${Math.round(o/1e3)}s`),setTimeout(i,o).unref?.()});let i=()=>{a++,e.listen(n,t,()=>{r.log?.(`[bostrat-agent] view listener on ${t}:${n} (view Hosts only; front-door CIDRs decide the rest)`)})};return i(),e}Va();Og();Op();Id();be();import xM from"node:os";import{randomUUID as ok}from"node:crypto";var hV=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||xM.hostname(),nodeName:e.BOSTRAT_NODE_NAME||xM.hostname()});var vM=32768,SM=120,AM=1e3,TM=new Set(["claude","codex","cursor"]),wV=new Set(["off","transition","nag"]),gV=[[0,59],[0,23],[1,31],[1,12],[0,6]];function yV(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=gV[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 Pn=e=>String(e??"").trim(),zs={name(e){let t=Pn(e);if(!t)throw new Error("a loop needs a name");if(t.length>SM)throw new Error(`name is too long (${t.length}); cap is ${SM}`);return t},schedule(e){let t=Pn(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!yV(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=Pn(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>vM)throw new Error(`prompt is too long (${t.length} chars); cap is ${vM}`);return t},expectation(e){let t=Pn(e)||null;if(t&&t.length>AM)throw new Error(`expectation is too long (${t.length}); cap is ${AM}`);return t},notify(e){let t=Pn(e)||"off";if(!wV.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=Pn(typeof t=="string"?t:t?.provider)||"claude";if(!TM.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...TM].join(", ")}`);let r=typeof t=="object"&&t&&Pn(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 bV(e,t){let n=e&&typeof e=="object"?e:{},r=zs.name(n.name),o=zs.schedule(n.schedule),s=zs.prompt(n.prompt),a=zs.expectation(n.expectation),i=zs.notify(n.notify),c=zs.assignment(n.assignment),l=Pn(t?.workspace?.repo)||Pn(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}=hV();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:d||null}}async function _M(e,t){let n=bV(t,e),r=ok();return await N({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 IM(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 N({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 N({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 N({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 rk=["name","schedule","prompt","expectation","notify","assignment","enabled"],kV=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function $M(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 RM(e,t){let n=Pn(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 xV(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=>!rk.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: ${rk.join(", ")}`)}let o={};for(let a of rk){if(!(a in n))continue;let i=zs[a](n[a]);(a==="assignment"?kV(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 OM(e,t,n){let r=$M(t),{patch:o,changed:s}=xV(n,r),a=ok(),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 N({id:e.id,cwd:e.cwd},{type:"loop.update.offered",actor:"system",source:"orchestrator",payload:i}),i}var EM=600;async function MM(e,t,n){let r=Pn(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>EM)throw new Error(`reason is too long (${r.length}); cap is ${EM}`);let o=$M(t),s=ok(),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 N({id:e.id,cwd:e.cwd},{type:"loop.delete.offered",actor:"system",source:"orchestrator",payload:a}),a}var CM=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 NM(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 CM(e,"loop.update.offered",t)).payload,a={id:e.id,cwd:e.cwd};return n==="applied"&&await N(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 N(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 PM(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 CM(e,"loop.delete.offered",t)).payload,s={id:e.id,cwd:e.cwd};return(n==="delete"||n==="pause")&&await N(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 N(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}}be();import{randomUUID as vV}from"node:crypto";var ik=20,SV=300,sk=120,DM=120,BM=2e3,Ff=new Set(["build","ops","debt","spike"]),LM=new Set(["active","done","abandoned"]),ck=new Set(["circuit.create","circuit.update","circuit.delete"]),AV=new Set(["person.create","slot.create","slot.update","slot.delete","reservation.create","reservation.update","reservation.delete"]),Kl=new Set([...ck,...AV]),TV=["name","description","status","type"],EV=["person","startDate","endDate","estUsd"],_V=["person","label","startDate","endDate"],IV=/^\d{4}-\d{2}-\d{2}$/,en=e=>String(e??"").trim(),lk=e=>typeof e=="string"&&e.startsWith("@"),UM=864e5;function HM(e){let t=Date.parse(`${e}T00:00:00Z`),n=new Date(t).getUTCDay();return new Date(t-(n+6)%7*UM).toISOString().slice(0,10)}function $V(e){return new Date(Date.parse(`${HM(e)}T00:00:00Z`)+6*UM).toISOString().slice(0,10)}var jM=(e,t)=>{let n=en(e);if(!IV.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 RV(e,t){let n=jM(e,"startDate"),r=jM(t,"endDate");if(r<n)throw new Error(`endDate ${r} is before startDate ${n}`);let o=HM(n),s=$V(r);return{startDate:o,endDate:s,snapped:o!==n||s!==r}}var FM=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},jo=(e,t,n)=>{let r=en(e);if(r.length>t)throw new Error(`${n} is too long (${r.length}); cap is ${t}`);return r};function ak(e,t){let n=en(t);if(!n)throw new Error("a circuit name or id is required");if(lk(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 OV(e,t){let n=en(t);if(!n)throw new Error('a person is required \u2014 "me", a person id, or a row label');if(n==="me"||lk(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 MV(e,t,{allow:n=Kl}={}){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>ik)throw new Error(`too many ops (${o.length}); cap is ${ik} \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=x=>{x.id&&(l.circuits[x.id]={name:x.name,status:x.status,type:x.type??"build",updatedAt:x.updatedAt??null},u[x.id]=x.name)},h=x=>{x.id&&(u[x.id]=x.label)},y=(x,S)=>{let _=en(x);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[`@${_}`]=S,_},k=o.map((x,S)=>{let _=x&&typeof x=="object"?x:{},M=en(_.op),P=`op ${S+1}`;if(!Kl.has(M))throw new Error(`${P}: unknown op "${M}" \u2014 one of ${[...Kl].join(", ")}`);if(!n.has(M))throw new Error(`${P}: "${M}" isn't a circuit op \u2014 roadmap changes go through \`bostrat-roadmap propose\` (one card, either CLI)`);let j=R=>{throw new Error(`${P} (${M}): ${R}`)},T=R=>{let A=_.set&&typeof _.set=="object"&&!Array.isArray(_.set)?_.set:null;A||j("needs a `set` object naming the fields to change");let C=Object.keys(A).filter(W=>!R.includes(W));return C.length&&j(`unknown field(s) ${C.join(", ")} \u2014 settable: ${R.join(", ")}`),Object.keys(A).length||j("`set` names no fields"),A},$=R=>{let{startDate:A,endDate:C,snapped:W}=RV(R.startDate,R.endDate);return W&&(p=!0),{startDate:A,endDate:C,snapped:W}},L=R=>{let A=OV(a,R);return en(R)==="me"&&(f=!0),h(A),{key:A.id??en(R),label:A.label}},H=(R,A,C,W,B)=>{let Z=en(R);Z||j(`needs a ${W} id`);let xe=A.find(Ae=>Ae[C]===Z);return xe||j(`no ${W} "${Z}" \u2014 see \`bostrat-roadmap ls\``),B[Z]={...xe},xe};switch(M){case"circuit.create":{let R=jo(_.name,DM,"name");R||j("a circuit needs a name");let A=en(_.type)||"build";Ff.has(A)||j(`bad type "${A}" (${[...Ff].join(" | ")})`);let C=s.find(B=>String(B.name).toLowerCase()===R.toLowerCase());C&&j(`a circuit named "${C.name}" already exists (${C.id}) \u2014 update it instead of making a twin`);let W=y(_.ref,R);return{op:M,...W?{ref:W}:{},name:R,description:jo(_.description,BM,"description"),type:A}}case"circuit.update":{let R=ak(s,_.circuit);R.id||j("can't update a circuit created in the same plan \u2014 set its fields on the create op"),w(R);let A=T(TV),C={};if(A.name!==void 0){let W=jo(A.name,DM,"name");W||j("name can't be blank"),W!==R.name&&(C.name=W)}return A.description!==void 0&&(C.description=jo(A.description,BM,"description")),A.status!==void 0&&(LM.has(A.status)||j(`bad status "${A.status}" (${[...LM].join(" | ")})`),A.status!==R.status&&(C.status=A.status)),A.type!==void 0&&(Ff.has(A.type)||j(`bad type "${A.type}" (${[...Ff].join(" | ")})`),A.type!==(R.type??"build")&&(C.type=A.type)),Object.keys(C).length||j("nothing would change \u2014 the set equals the circuit's current values"),{op:M,circuit:R.id,name:R.name,set:C}}case"circuit.delete":{let R=ak(s,_.circuit);R.id||j("can't delete a circuit created in the same plan"),w(R);let A=o.some((C,W)=>W<S&&en(C?.op)==="circuit.update"&&C?.set?.status&&C.set.status!=="active"&&en(C?.circuit)===en(_.circuit));return R.status==="active"&&!A&&j(`\u201C${R.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:M,circuit:R.id,name:R.name,status:R.status}}case"person.create":{let R=jo(_.label,sk,"label");R||j("a person row needs a label");let A=a.find(W=>String(W.label).toLowerCase()===R.toLowerCase());A&&j(`a roadmap row labelled "${A.label}" already exists (${A.personId})`);let C=y(_.ref,R);return{op:M,...C?{ref:C}:{},label:R}}case"slot.create":{let R=ak(s,_.circuit);w(R);let A=L(_.person),C=$(_);return{op:M,circuit:R.id??R.ref,circuitName:R.name,person:A.key,personLabel:A.label,...C,estUsd:FM(_.estUsd)}}case"slot.update":{let R=H(_.slot,i,"slotId","slot",l.slots),A=T(EV),C={};if(A.person!==void 0){let B=L(A.person);C.person=B.key,C.personLabel=B.label}if(A.startDate!==void 0||A.endDate!==void 0){let B=$({startDate:A.startDate??R.startDate,endDate:A.endDate??R.endDate});B.startDate!==R.startDate&&(C.startDate=B.startDate),B.endDate!==R.endDate&&(C.endDate=B.endDate)}A.estUsd!==void 0&&(C.estUsd=FM(A.estUsd)),Object.keys(C).length||j("nothing would change");let W=s.find(B=>B.id===R.circuitId);return{op:M,slot:R.slotId,circuitName:W?.name??null,set:C}}case"slot.delete":{let R=H(_.slot,i,"slotId","slot",l.slots),A=s.find(C=>C.id===R.circuitId);return{op:M,slot:R.slotId,circuitName:A?.name??null,startDate:R.startDate,endDate:R.endDate}}case"reservation.create":{let R=L(_.person),A=jo(_.label,sk,"label");return A||j("a reservation needs a label (Leave, Support rotation, \u2026)"),{op:M,person:R.key,personLabel:R.label,label:A,...$(_)}}case"reservation.update":{let R=H(_.reservation,c,"reservationId","reservation",l.reservations),A=T(_V),C={};if(A.person!==void 0){let W=L(A.person);C.person=W.key,C.personLabel=W.label}if(A.label!==void 0){let W=jo(A.label,sk,"label");W||j("label can't be blank"),W!==R.label&&(C.label=W)}if(A.startDate!==void 0||A.endDate!==void 0){let W=$({startDate:A.startDate??R.startDate,endDate:A.endDate??R.endDate});W.startDate!==R.startDate&&(C.startDate=W.startDate),W.endDate!==R.endDate&&(C.endDate=W.endDate)}return Object.keys(C).length||j("nothing would change"),{op:M,reservation:R.reservationId,label:R.label,set:C}}case"reservation.delete":{let R=H(_.reservation,c,"reservationId","reservation",l.reservations);return{op:M,reservation:R.reservationId,label:R.label,startDate:R.startDate,endDate:R.endDate}}default:return j("unhandled op")}});k.forEach((x,S)=>{for(let _ of[x.circuit,x.person,x.set?.person])if(lk(_)&&!d.has(String(_).slice(1)))throw new Error(`op ${S+1} (${x.op}): unknown ref "${_}" \u2014 no earlier op in this plan creates it`)});let g=a.some(x=>x.kind==="user"&&x.userId);return{why:jo(r.why,SV,"why"),ops:k,base:l,resolved:u,snapped:p,createsMeRow:f&&!g}}async function WM(e,t,n,r={}){let o=MV(t,n,r),s=vV(),a={ts:Date.now(),proposalId:s,...o};return await N({id:e.id,cwd:e.cwd},{type:"planning.change.offered",actor:"system",source:"orchestrator",payload:a}),a}var CV=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 qM(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 CV(e,t),s={id:e.id,cwd:e.cwd},a=o.payload;return n==="applied"&&await N(s,{type:"planning.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,why:a.why??"",results:Array.isArray(r)?r.slice(0,ik+1):[]}}),await N(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}}wp();be();Yr();be();Gn();Op();var GM=10,KM=200,NV=120,PV=24,zM=/^\d{4}-\d{2}-\d{2}$/;function uk(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var DV=(e=Date.now())=>new Date(e).toISOString().slice(0,10),Tt=(e,t="i")=>new RegExp(e,t),BV=[{re:Tt("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:Tt("\\bSPC\\b",""),reason:"business (SPC)"},{re:Tt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:Tt("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:Tt("\\bReplicas\\b",""),reason:"competitor research"},{re:Tt("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:Tt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:Tt("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],LV=[Tt("\\bSPC\\b",""),Tt("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),Tt("competitor|cloudcli|\\bkiro\\b"),Tt("\\bReplicas\\b",""),Tt("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),Tt("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),Tt("(^|[^\\w&])#\\d+\\b"),Tt("\\btrack/[\\w.-]+")];function jV({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of BV)if(o.test(n)||o.test(r))return s;return null}function VM(e){let t=String(e||"");for(let n of LV){let r=n.exec(t);if(r)return r[0].trim()}return null}function JM(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 FV=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function UV(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=rl(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(`
801
- `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,NV)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${PV}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=FV.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=VM(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>KM)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${KM}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=VM(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>GM)throw new Error(`${r.length} bullets \u2014 over the ${GM}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function HV(e,{repos:t=uk()}={}){let n=new Set(t);return(await En()).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:jV({title:r.title,headRef:r.headRef})}))}async function YM(e,t){let n=await HV(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function XM(e,{md:t,day:n=null}){let r=UV(t),o=n==null||n===""?DV():String(n);if(!zM.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await N({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 ZM(e,{day:t}){let n=String(t||"");if(!zM.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await N({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}}vs();Gn();Ss();be();vs();xt();Ir();Gn();Oc();dp();Xd();va();an();import{execFile as ez}from"node:child_process";import{promisify as tz}from"node:util";var WV=new Set(["pull_request","check_suite","workflow_run","push"]),qV=/^[^/\s]+\/[^/\s]+$/,GV=500,dk=new Set,pk=[],Uf=new Map,mn={hourStart:0,byEvent:{},duplicates:0,rejected:0};function fk(e,t,n){let r=Math.floor(e/36e5)*36e5;r!==mn.hourStart&&(mn.hourStart=r,mn.byEvent={},mn.duplicates=0,mn.rejected=0),t==="accepted"?mn.byEvent[n]=(mn.byEvent[n]||0)+1:mn[t]+=1}function KV(e){if(!e||typeof e!="object"||e.forge!=="github"||typeof e.event!="string"||!WV.has(e.event)||typeof e.repo!="string"||!qV.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 QM(e,{now:t=Date.now(),onAccept:n=null,log:r=console}={}){let o=KV(e);if(!o)return fk(t,"rejected"),{ok:!1,error:"malformed github event envelope"};if(o.deliveryId){if(dk.has(o.deliveryId))return fk(t,"duplicates"),{ok:!0,duplicate:!0,envelope:o};for(dk.add(o.deliveryId),pk.push(o.deliveryId);pk.length>GV;)dk.delete(pk.shift())}let s=o.repo.toLowerCase(),a=Uf.get(s)||{lastDeliveryAt:0,count:0};a.lastDeliveryAt=t,a.count+=1,Uf.set(s,a),fk(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 VV(e,t=Date.now()){let n=Uf.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 eC=1440*6e4;function mk(e,t=Date.now()){let n=VV(e,t);return n.covered&&n.ageMs<eC}function tC(e=Date.now()){let t={};for(let[n,r]of Uf)t[n]={lastDeliveryAt:r.lastDeliveryAt,count:r.count,covered:e-r.lastDeliveryAt<eC};return{hourStart:mn.hourStart,byEvent:{...mn.byEvent},duplicates:mn.duplicates,rejected:mn.rejected,repos:t}}be();Gn();Gr();Ir();an();function nC(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function zV(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var JV=new Set(["merged","closed","lost"]);function YV(e,t){if(!e?.blocked)return null;let n=nC(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 XV(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function ZV(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 QV(e,t,n){await N({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 Hf(e,t={}){let{now:n=Date.now(),slugOf:r=Me,lookup:o=ft,note:s=FT,tracks:a=async()=>(await ke()).filter(d=>!Ue(d)),asked:i=ZV,emitChange:c=QV}=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(!zV(f))continue;let w=await o(p,f.number).catch(()=>null);if(!w?.trackId||JV.has(w.state))continue;let{prev:h}=await s(p,f.number,{blocked:nC(f),sha:f.headSha??null,at:n});if(!h)continue;let y=YV(h,f);if(!y||XV(w,y.change))continue;u??=new Map((await a()).map(S=>[S.id,S]));let k=u.get(w.trackId);if(!k)continue;let g=f.headSha??null;if(await i(k,y.change,f.number,g,h.at||0))continue;let x={number:Number(f.number),url:f.url||w.url,title:f.title||w.title,branch:f.headRefName||w.headRef,repo:p,sha:g,delegated:!1,reason:y.reason};y.change==="ci-fixed"?x.passed=f.checks.passed:x.base=f.baseRefName||null,await c(k,y.change,x),l.push({change:y.change,number:f.number,reason:y.reason})}catch{}}return l}var gk=tz(ez),dC=3e4,nz=30*6e4,rz=dC,oz=10*6e4,sz=10080*6e4,az=60*6e4,rC=8,pC=1440*6e4,iz=3,fC="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",wk=60*6e4,cz=15*6e4,lz=9e4,uz=1440*6e4,Vl=new Map,zl=new Map,dz=360*6e4,pz=e=>e.reduce((t,n)=>({misses:Math.max(t.misses,n.brokerRefused?.misses||0),until:Math.max(t.until,n.brokerRefused?.until||0)}),{misses:0,until:0}),fz=/could not resolve|not found|no pull requests?/i,mz=e=>fz.test(String(e?.message||e||""));function hz(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<wk)}var oC={fast:rz,slow:oz,decay:az};function sC(e,t,n=mk){return mC(e,t,{grace:0})||!n(e.repo,t)&&(e.armedAt&&t-e.armedAt<nz||hz(e,t))?"fast":t-(e.firstSeen||0)>sz?"decay":"slow"}function Yl(e,t,n,r){let o=e.lanes?.get(ce(t.repo,t.number))||{};return Yd({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function wz(e,t){Sr("watch");try{let{stdout:n}=await gk("gh",["pr","view",String(t),"--repo",e,"--json",fC],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await Bn({slug:e})}});return JSON.parse(n||"null")}catch(n){throw yo(n)&&bo(n),n}}async function gz(e){Sr("watch");try{let{stdout:t}=await gk("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",fC],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await Bn({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw yo(t)&&bo(t),t}}async function yz(){let e=new Map;for(let t of await ke().catch(()=>[]))e.set(t.id,t);return e}async function bz(e,t){await N({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}}),await up(e,t).catch(()=>{})}async function kz(e,t){let n=await xs(e);return n?Ba(n,t):null}async function xz(e,t,n){let r=await xs(e);if(!r)throw new Error(`no local checkout for ${e}`);return La(r,t,{method:n})}async function vz(e,t){let n=await xs(e);if(!n)throw new Error(`no local checkout for ${e}`);return Nc(n,t)}async function Sz(e,t){await N({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 gi(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 Az=10*6e4;async function Tz(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>pC){await gi(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 gi(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await gi(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<Az)return;await gi(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 gi(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 gi(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await hC(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function yi(e,t,n){await N({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 Ez(e,t){try{return await gk("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function Jl(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 bi=(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 mC(e,t,{grace:n=lz}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=uz}async function _z(e,t,n,r){let o=r.now??Date.now();if(!mC(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||Ue(s))return!1;let a=(s.boxes||[]).find(d=>d.name===s.leadBox);return await(r.midTurn??is)(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??xr)(e.repo,e.number).catch(()=>null),!1):await(r.claim??xr)(e.repo,e.number).catch(()=>null)?(await yi(s,"opened",{...bi(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 Iz(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 Hd(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await qd(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<cz;await jT(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await LT(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await Jl(a,"pushed",e.number,d=>d.payload?.sha===s)&&await yi(a,"pushed",{...bi(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>wk)await Wd(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 Wd(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 Jl(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await yi(a,"ci-fixed",{...bi(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await Wd(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>wk)await Gd(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await Gd(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Yl(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await Jl(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await yi(a,"reconciled",{...bi(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await Gd(e.repo,e.number).catch(()=>{})}}}}async function $z(e,t,n,r){let o=Yl(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await Jl(s,"closed",e.number)&&await yi(s,"closed",{...bi(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 aC(e,t,n){Yl(n,e,"lost",null);let r=t.get(e.trackId);r&&!await Jl(r,"lost",e.number)&&await yi(r,"lost",bi(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function hC(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 iC(e={}){let{now:t=Date.now(),auth:n=vw,view:r=wz,list:o=gz,links:s=WT,trackMap:a=yz,emitMerged:i=bz,mark:c=wo,archiveIfArmed:l=Er,notifyIfArmed:u=_r,notifyIfResolved:d=tf,followupsIfMerged:p=Bs,batchThreshold:f=iz,detail:w=kz,merge:h=xz,updateBranch:y=vz,lookup:k=ft,disarm:g=Rc,emitDisarmed:x=Sz,localHasCommit:S=Ez,claim:_=xr,midTurn:M=is,only:P=null,wantDetail:j=null,covered:T=mk,verdicts:$=null,tokenFor:L=te=>ra(te),noteRefusal:H=DT,clearRefusal:R=BT}=e;if(!(await n().catch(()=>null))?.authenticated||zd()>0)return 0;let C=await s().catch(()=>[]),W=fE(C),B=te=>{try{return!!j?.(te)}catch{return!1}},Z=P?C.filter(te=>{try{return P(te)}catch{return!1}}):C.filter(te=>t-(Vl.get(ce(te.repo,te.number))||0)>=oC[sC(te,t,T)]);if(!Z.length)return 0;let xe=Date.now(),Ae=new Map,_e=new Map;for(let te of[...Z].sort(Pc)){let we=P?"event":sC(te,t,T);Ae.set(ce(te.repo,te.number),{lane:we,intervalMs:oC[we]??null}),Vl.set(ce(te.repo,te.number),t),_e.has(te.repo)||_e.set(te.repo,[]),_e.get(te.repo).push(te)}let Q=await a().catch(()=>new Map),Xe=new Map,Pe=(te,we)=>{let Oe=ce(te,we);if(!Xe.has(Oe)){let Ve=Promise.resolve().then(()=>w(te,we));Ve.catch(()=>{}),Xe.set(Oe,Ve)}return Xe.get(Oe)},le=$??((te,we)=>Hf([{path:te,prs:[we]}],{now:t,slugOf:async()=>te,tracks:async()=>[...Q.values()].filter(Oe=>!Ue(Oe))}).catch(()=>{})),ge={now:t,lanes:Ae,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,followupsIfMerged:p,detail:Pe,merge:h,updateBranch:y,lookup:k,disarm:g,emitDisarmed:x,localHasCommit:S,claim:_,midTurn:M};for(let[te,we]of _e){let Oe=pz(we);if(Oe.until>t)continue;let Ve=!1;try{if(await L(te),Oe.misses)for(let re of we)await R(re.repo,re.number).catch(()=>{})}catch(re){Ve=T0(re)}if(Ve){let re=Oe.misses+1;if(re>=rC){console.log(`[pr-watch] ${te}: not granted ${re}\xD7 \u2014 retiring ${we.length} link(s) as lost`);for(let he of we){await aC(he,Q,ge);let Be=ce(he.repo,he.number);zl.delete(Be),Vl.delete(Be)}}else for(let he of we)await H(he.repo,he.number,{misses:re,until:t+dz}).catch(()=>{});continue}let Nt,O=new Set,X=re=>re.ciFixAwait||re.reconcileAwait||B(re)?!0:!re.autoMerge||re.trackId&&W.get(re.trackId)!==ce(re.repo,re.number)?!1:t-(re.autoMerge.armedAt||0)<=pC;if(we.length>f)Nt=await o(te).catch(()=>null);else{Nt=new Map;for(let re of we){if(X(re)){let he=await Pe(te,re.number).catch(()=>null);if(he?.state){Nt.set(Number(re.number),{number:Number(re.number),url:he.url,title:he.title,headRefName:he.headRefName,headRefOid:he.headSha??null,state:he.state,mergedAt:he.mergedAt??null,closedAt:he.closedAt??null});continue}}try{let he=await r(te,re.number);he?.number!=null&&Nt.set(Number(he.number),he)}catch(he){mz(he)&&O.add(ce(re.repo,re.number))}}}if(Nt)for(let re of we){let he=ce(re.repo,re.number),Be=Nt.get(Number(re.number));if(!Be){if(O.has(he)){let Pt=(zl.get(he)||0)+1;zl.set(he,Pt),Pt>=rC&&(await aC(re,Q,ge),zl.delete(he),Vl.delete(he))}continue}if(zl.delete(he),Be.state==="MERGED"||Be.state==="CLOSED")Be.state==="MERGED"?await hC(re,Be,Q,ge):await $z(re,Be,Q,ge),Vl.delete(he);else{await _z(re,Be,Q,ge).catch(()=>{}),await Iz(re,Be,Q,ge).catch(()=>{});let Pt=!re.trackId||W.get(re.trackId)===he;re.autoMerge&&Pt&&await Tz(re,Q,ge).catch(()=>{});try{if(B(re)&&!Xe.has(he)&&Pe(re.repo,re.number),Xe.has(he)){let tt=await Xe.get(he).catch(()=>null);tt?.checks&&await le(re.repo,tt)}}catch{}}}}let de={};for(let{lane:te}of Ae.values())de[te]=(de[te]||0)+1;return console.log(`[pr-watch] probed ${Z.length} link(s) (${Object.entries(de).map(([te,we])=>`${te} ${we}`).join(", ")}) in ${Date.now()-xe}ms`),Z.length}function cC(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 hk=!1,Wf=!1,qf=[],lC=Promise.resolve();async function Rz(){for(;Wf||qf.length;){if(Wf){Wf=!1;try{await iC()}catch{}continue}let e=qf;qf=[];let t=e.map(r=>r.spec),n=Object.assign({},...e.map(r=>r.deps||{}));try{await iC({...n,only:r=>t.some(o=>cC(o,r)),wantDetail:r=>t.some(o=>o.detail&&cC(o,r))})}catch{}}}function Gf(e,t){return e===null?Wf=!0:qf.push({spec:e,deps:t}),hk||(hk=!0,lC=Rz().finally(()=>{hk=!1})),lC}function wC(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 Gf({repo:n,numbers:r,branch:e.branch||null,event:e.event||null,detail:e.detail===!0},t)}var Oz=6e4,uC=0;function gC(e=void 0){let t=e?.now??Date.now();return t-uC<Oz?Promise.resolve():(uC=t,Gf({all:!0},e))}function yC(){Gf(null),setInterval(()=>Gf(null),dC)}vs();pp();Qc();Ir();an();var Mz=new Set(["opened","reopened","closed","synchronize","ready_for_review","converted_to_draft","edited"]);async function Cz({tracks:e=ke,reconcile:t=Tp}={}){for(let n of(await e().catch(()=>[])).filter(r=>!Ue(r)))await t(n,{bypassThrottle:!0}).catch(()=>{})}function bC(e,t={}){let{invalidate:n=ln,probe:r=wC,poke:o=JE,reconcileOpened:s=Cz}=t;try{n()}catch{}let a={probe:null,poked:!1,reconciled:!1};if(!e?.repo)return a;if(e.event==="pull_request"&&Mz.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}dt();be();Ir();an();import{randomUUID as Nz}from"node:crypto";var Pz=2e4,kC=3,ki=new Map,yk=new Set;async function xC(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 Dz(e={}){let{sessions:t=null,tracks:n=null,append:r=N,read:o=K,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await kn(),i=n??await ke()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(Ue(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=(ki.get(d.name)||0)+1;ki.set(d.name,f),f===kC&&(yk.add(d.name),await xC(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:Nz(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let f=(ki.get(d.name)||0)>=kC;if(ki.delete(d.name),f||!yk.has(d.name)){yk.add(d.name);let w=await xC(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[...ki.keys()])l.has(u)||ki.delete(u)}var Xl=null,bk=!1;function vC(){return Xl?()=>{}:(Xl=setInterval(()=>{bk||(bk=!0,Dz().catch(()=>{}).finally(()=>{bk=!1}))},Pz),Xl.unref?.(),()=>{clearInterval(Xl),Xl=null})}gs();Qc();be();vs();Ss();gs();jc();import{randomUUID as Bz}from"node:crypto";async function Lz(){let e=await Promise.resolve().then(()=>(Ir(),mR));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var kk={listRepoPrs:Kn,readEvents:K,appendEvent:N,sayDeps:Lz,currentBranch:ko};async function jz(e,t=kk,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??ko)(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 xk(e,t,{actions:n,notify:r=!1}={},o=kk){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 jz(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=Bz();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 vk(e,{offerId:t,choice:n}={},r=kk){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');return vo(`prx:${e.id}:${t}`,()=>Fz(e,{offerId:t,choice:n},r))}async function Fz(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=ho.filter(d=>d!=="pr"&&(i.includes(d)||d==="push")),c=await u(e.id,Ca(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,ST(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==="push"&&Number.isFinite(Number(a.pr?.number))?{number:Number(a.pr.number)}:{},...l?{actions:l}:{}}}),n!=="dismiss"&&a.notify===!0){let{queueShipCompleteNotify:u}=await r.sayDeps();u(e.id,{actions:l})}return{say:c,choice:n}}jc();import Ur from"node:fs/promises";import xi from"node:path";import $C from"node:os";import SC from"node:fs/promises";import Kf from"node:path";import{execFile as Uz}from"node:child_process";import{promisify as Hz}from"node:util";import{fileURLToPath as Wz}from"node:url";var qz=Hz(Uz),TC=Kf.dirname(Wz(import.meta.url)),Gz=Kf.resolve(TC,"..","..","client","dist"),Kz="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",Vz=new Map([...Kz].map((e,t)=>[e,t]));function zz(e){let t=[],n=0,r=0;for(let o of e){let s=Vz.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 Jz(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=zz(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 Yz(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 AC=new Map;async function Xz(e){let t;try{t=await SC.stat(e)}catch{return null}let n=AC.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await SC.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:Jz(r.mappings||"")};return AC.set(e,o),o}catch{return null}}var Sk=null;function Zz(){return Sk||(Sk=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):qz("git",["rev-parse","--short","HEAD"],{cwd:Kf.resolve(TC,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),Sk}var Qz=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function e3(e,{distDir:t=Gz}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(Qz)){let[a,i,c,l]=s,u=await Xz(Kf.join(t,"assets",`${i}.map`)),d=u?Yz(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 EC(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await Zz();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await e3(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var t3=()=>process.env.BOSTRAT_STATE_DIR||xi.join(process.env.HOME||$C.tmpdir(),".bostrat"),Fo=()=>xi.join(t3(),"telemetry"),RC=()=>xi.join(Fo(),".relay-offsets.json"),n3=50,r3=14,o3=3e4,_C=500,tn=(e,t)=>typeof e=="string"?e.slice(0,t):"";function s3(e,t){if(!e||typeof e!="object")return null;let n=tn(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:tn(e.anonId,64),sessionId:tn(e.sessionId,64),userId:tn(e.userId,64),release:tn(e.release,64),appVersion:tn(e.appVersion,32),route:tn(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:tn(e.error.kind,256),message:tn(e.error.message,8192),stack:tn(e.error.stack,32768),fingerprint:tn(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:tn(s?.n,64),r:tn(s?.r,128)}))),o}var OC=e=>new Date(e).toISOString().slice(0,10),IC=0;async function MC(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,n3):[]).map(s=>s3(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await EC(s);await Ur.mkdir(Fo(),{recursive:!0});let o=xi.join(Fo(),`${OC(t)}.ndjson`);return await Ur.appendFile(o,r.map(s=>JSON.stringify(s)+`
802
- `).join(""),"utf8"),t-IC>6*3600*1e3&&(IC=t,a3(t).catch(()=>{})),r.length}async function a3(e=Date.now()){let t=OC(e-r3*24*3600*1e3),n=[];try{n=await Ur.readdir(Fo())}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 Ur.rm(xi.join(Fo(),s),{force:!0});let o=await NC();for(let s of r)delete o[s];await PC(o)}var Vf=new Map;function CC(e,t=Date.now()){let n=e||"unknown",r=Vf.get(n);return r||(Vf.size>512&&Vf.clear(),r={tokens:40,at:t},Vf.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 NC(){try{return JSON.parse(await Ur.readFile(RC(),"utf8"))||{}}catch{return{}}}async function PC(e){await Ur.mkdir(Fo(),{recursive:!0}),await Ur.writeFile(RC(),JSON.stringify(e),"utf8")}function i3(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||$C.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 c3({fetchImpl:e=fetch}={}){let t=await WR();if(!t)return{sent:0,disabled:!0};let n;try{n=(await Ur.readdir(Fo())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await NC(),o=0;for(let s of n){let a=xi.join(Fo(),s),i=r[s]||0,c;try{let p=await Ur.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(`
803
- `).filter(Boolean),d=[];for(let p of u)try{d.push(JSON.parse(p))}catch{}for(let p=0;p<d.length;p+=_C){let f=d.slice(p,p+_C).map(h=>i3(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 PC(r)}return{sent:o,disabled:!1}}var Ak=null,Tk=!1;function DC(){Ak||(Ak=setInterval(async()=>{if(!Tk){Tk=!0;try{await c3()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{Tk=!1}}},o3),Ak.unref?.())}import Jf from"node:fs/promises";import UC from"node:path";import l3 from"node:os";var HC=()=>process.env.BOSTRAT_STATE_DIR||UC.join(process.env.HOME||l3.tmpdir(),".bostrat"),WC=()=>UC.join(HC(),"dictation-glossary.json"),u3=100,d3=500,p3=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Yf=null,Ek=null,_k=Promise.resolve();function BC(){let e={},t=Date.now();for(let n of p3)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function qC(){return Yf||(Ek??=Jf.readFile(WC(),"utf8").then(e=>JSON.parse(e)?.terms??BC()).catch(()=>BC()).then(e=>Yf=e).finally(()=>Ek=null),Ek)}async function LC(){let e=JSON.stringify({terms:Yf},null,2),t=WC(),n=`${t}.${process.pid}.tmp`;await Jf.mkdir(HC(),{recursive:!0}),await Jf.writeFile(n,e),await Jf.rename(n,t)}function f3(){return _k=_k.then(LC,LC),_k.catch(()=>{})}async function Ik(){return Object.values(await qC()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var m3=e=>Math.max(1,Math.ceil(e.length/4));async function h3(){let e=[],t=0;for(let{term:n}of await Ik()){let r=m3(n);if(!(t+r>d3)&&(e.push(n),t+=r,e.length>=u3))break}return e}async function w3(e,t){let n=await qC(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var jC=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),zf=e=>e.toLowerCase();function FC(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function GC(e,t){let n=jC(e),r=jC(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]=zf(n[u])===zf(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;)zf(n[c])===zf(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(FC(r[l])&&i.add(r[l]),l++);for(;l<s;l++)FC(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await w3(u,"learned");return await f3(),[...i]}var Zl=null;function g3(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 KC(){if(!Zl)return null;let e=await $l();if(!e||e.apiKey.slice(-6)!==Zl.keyTail)return null;let{keyTail:t,...n}=Zl;return n}async function VC(e,t){let n=await $l();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 h3())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=g3(o.status,i);c.persistent&&(Zl={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 Zl=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}be();var $k={"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 y3(e){if(!e)return null;let t=String(e).trim();if($k[t])return t;let n=null;for(let r of Object.keys($k))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function b3(e,t={}){let n=$k[y3(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 k3(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 Ql=null;async function x3(){if(!Ql)return null;let e=await Sf();if(!e||e.apiKey.slice(-6)!==Ql.keyTail)return null;let{keyTail:t,...n}=Ql;return n}async function v3(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=k3(t.status,o);s.persistent&&(Ql={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}Ql=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 S3={openai:v3};async function zC(){let e=await Sf();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await x3()}:{configured:!1}}async function JC(){let e=await Sf();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 S3[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function YC(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=b3(t,s),i=await N(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}}an();OT(async()=>new Set((await ke()).map(e=>e.id)));var oN=Re.dirname(T3(import.meta.url)),Nk=Number(process.env.PORT)||3362,Xf=ib(process.env),sN=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,vi=iM(process.env.BOSTRAT_ALLOW_IPS),Zf=cM(process.env.BOSTRAT_VIEW_FRONT_CIDRS,jf),Dk=uM(),aN=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",E=nn();E.disable("x-powered-by");E.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),Gl(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(ql(e)||vi.allowed(vi.clientIp(e))||Zf.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});E.use(wM);E.use(fM({token:Dk,enforce:aN}));E.use("/api/mocks",nn.json({limit:"1mb"}));E.use("/api/mocks",nn.raw({type:"image/png",limit:"24mb"}));E.use("/api/mocks",nn.raw({type:["video/mp4","video/webm"],limit:"105mb"}));E.use("/api/runbooks",nn.json({limit:"1mb"}));E.use("/api/tracks/adopt",nn.json({limit:"1mb"}));E.use("/api/telemetry",nn.json({limit:"256kb"}));E.use("/api/hook",nn.json({limit:"2mb"}));E.use("/api/dictation",nn.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));E.use("/api/tracks/:id/upload",nn.raw({type:()=>!0,limit:"25mb"}));E.use(nn.json({limit:"64kb"}));E.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:zt,hostTmuxAlive:await Zr(),autoTriggerPct:sN,plane:Si?Si.status():null})});E.get("/api/sessions",async(e,t)=>{t.json({sessions:await kn()})});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 jn(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(!je(n))return t.status(400).json({error:"invalid session name"});if(!await Se(n))return t.status(404).json({error:"session not found"});try{await Lt(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(!je(n))return t.status(400).json({error:"invalid session name"});let r=await Se(n);if(!r)return t.status(404).json({error:"session not found"});let o=await nc(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(!je(n))return t.status(400).json({error:"invalid session name"});try{let r=await fA(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=vd(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 XC=10;async function iN(){let e=await ke(),[t,n]=await Promise.all([R$(e),hR(e)]);return{tracks:e,views:await gg(),queuedOf:r=>Cs(r),jobsOf:r=>t.get(r)??[],prPendingOf:r=>n.get(r)??[]}}E.get("/api/idle-guard",async(e,t)=>{try{t.json(ab(await iN()))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var hn=js(),R3=$R({kind:hn}),tu=null,Ct=()=>tu&&["auto","prompt","off"].includes(tu)?tu:R3,Pk=null,O3=_l.has(hn),cN=async({to:e,from:t})=>!O3||Il(await li())?!1:(ru.arm({to:e,from:t,kind:hn}),!0);async function M3(e){let t=Ct();tu=e??null;let n=Ct();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){ru.cancel();return}Pk&&await cN(Pk)}}var lN=(()=>{try{return $3(import.meta.url)("../package.json").version||null}catch{return null}})(),ru=OR({isBusy:async()=>ab(await iN()).busy,onStuck:({to:e,from:t})=>or({current:t,latest:e,installKind:hn,policy:Ct(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?or({current:t,latest:e,installKind:hn,policy:Ct(),status:"updating",reason:"auto"}):or({current:t,latest:e,installKind:hn,policy:Ct(),status:"failed",error:n?.reason})).catch(()=>{})});E.get("/api/node/self-update",async(e,t)=>{t.json({installKind:hn,policy:Ct(),policySource:tu?"plane":"node",current:lN,status:await li(),armed:ru.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 gf({to:n,kind:hn,reason:"manual"});if(r.ok)return ru.cancel(),or({current:r.from,latest:n,installKind:hn,policy:Ct(),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 uN(){try{let e=await RR();e&&await or({current:e.from,latest:e.to,installKind:e.kind||hn,policy:Ct(),status:e.status,error:e.error,reason:e.reason}),await ky({current:lN,installKind:hn,policy:Ct()})}catch{}}uN();setInterval(uN,3e4).unref();E.get("/api/tracks",async(e,t)=>{let n=(await ke()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>XC){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,XC).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:yl,agentAvailability:await Vp(),tickets:await dO()})});E.get("/api/cost",async(e,t)=>{try{let n=await ke();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await Kb(n);if(r.cursorUsage=tg(),e.query.format==="text")return t.type("text/plain").send(BO(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 zb(await ke(),{window:e.query.window,from:e.query.from,to:e.query.to});if(e.query.format==="text")return t.type("text/plain").send(HO(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 VO(await ke(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=tg(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=_c(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/caps",(e,t)=>{t.json(_c())});E.post("/api/usage/caps",async(e,t)=>{try{t.json(await Nd(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 nM(await ke(),{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 Zk(e.get(pr),{byToken:bl,legacy:()=>Hc(e.body?.session_id,e.body?.cwd)});if(n==="refused")return Ii("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Ii("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&&Ii("mismatch",{track:r.track.id,box:r.box.name}),Ii(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 NO(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&Iu(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 bl(e.get(pr));if(!n?.track||!n?.box)return t.status(204).end();t.send((await CE(n.track,n.box)).join(`
800
+ `),a.destroy();return}t(s,a,i)}}}function kM(e,{addr:t,port:n,log:r=console,retryMs:o=15e3,maxRetries:s=1/0}){let a=0;e.on("error",c=>{let l=c?.code||c?.message;if(e.listening){r.error?.(`[bostrat-agent] view listener on ${t}:${n}: ${l}`);return}if(a>s){r.error?.(`[bostrat-agent] view listener on ${t}:${n} failed (${l}) \u2014 giving up`);return}r.error?.(`[bostrat-agent] view listener on ${t}:${n} failed (${l}) \u2014 retrying in ${Math.round(o/1e3)}s`),setTimeout(i,o).unref?.()});let i=()=>{a++,e.listen(n,t,()=>{r.log?.(`[bostrat-agent] view listener on ${t}:${n} (view Hosts only; front-door CIDRs decide the rest)`)})};return i(),e}Va();Og();Mp();$d();be();import xM from"node:os";import{randomUUID as ok}from"node:crypto";var wV=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||xM.hostname(),nodeName:e.BOSTRAT_NODE_NAME||xM.hostname()});var vM=32768,SM=120,TM=1e3,AM=new Set(["claude","codex","cursor"]),gV=new Set(["off","transition","nag"]),yV=[[0,59],[0,23],[1,31],[1,12],[0,6]];function bV(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=yV[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 Pn=e=>String(e??"").trim(),zs={name(e){let t=Pn(e);if(!t)throw new Error("a loop needs a name");if(t.length>SM)throw new Error(`name is too long (${t.length}); cap is ${SM}`);return t},schedule(e){let t=Pn(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!bV(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=Pn(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>vM)throw new Error(`prompt is too long (${t.length} chars); cap is ${vM}`);return t},expectation(e){let t=Pn(e)||null;if(t&&t.length>TM)throw new Error(`expectation is too long (${t.length}); cap is ${TM}`);return t},notify(e){let t=Pn(e)||"off";if(!gV.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=Pn(typeof t=="string"?t:t?.provider)||"claude";if(!AM.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...AM].join(", ")}`);let r=typeof t=="object"&&t&&Pn(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 kV(e,t){let n=e&&typeof e=="object"?e:{},r=zs.name(n.name),o=zs.schedule(n.schedule),s=zs.prompt(n.prompt),a=zs.expectation(n.expectation),i=zs.notify(n.notify),c=zs.assignment(n.assignment),l=Pn(t?.workspace?.repo)||Pn(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}=wV();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:d||null}}async function _M(e,t){let n=kV(t,e),r=ok();return await N({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 IM(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 N({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 N({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 N({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 rk=["name","schedule","prompt","expectation","notify","assignment","enabled"],xV=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function $M(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 RM(e,t){let n=Pn(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 vV(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=>!rk.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: ${rk.join(", ")}`)}let o={};for(let a of rk){if(!(a in n))continue;let i=zs[a](n[a]);(a==="assignment"?xV(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 OM(e,t,n){let r=$M(t),{patch:o,changed:s}=vV(n,r),a=ok(),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 N({id:e.id,cwd:e.cwd},{type:"loop.update.offered",actor:"system",source:"orchestrator",payload:i}),i}var EM=600;async function MM(e,t,n){let r=Pn(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>EM)throw new Error(`reason is too long (${r.length}); cap is ${EM}`);let o=$M(t),s=ok(),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 N({id:e.id,cwd:e.cwd},{type:"loop.delete.offered",actor:"system",source:"orchestrator",payload:a}),a}var CM=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 NM(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 CM(e,"loop.update.offered",t)).payload,a={id:e.id,cwd:e.cwd};return n==="applied"&&await N(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 N(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 PM(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 CM(e,"loop.delete.offered",t)).payload,s={id:e.id,cwd:e.cwd};return(n==="delete"||n==="pause")&&await N(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 N(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}}be();import{randomUUID as SV}from"node:crypto";var ik=20,TV=300,sk=120,DM=120,BM=2e3,Uf=new Set(["build","ops","debt","spike"]),LM=new Set(["active","done","abandoned"]),ck=new Set(["circuit.create","circuit.update","circuit.delete"]),AV=new Set(["person.create","slot.create","slot.update","slot.delete","reservation.create","reservation.update","reservation.delete"]),Kl=new Set([...ck,...AV]),EV=["name","description","status","type"],_V=["person","startDate","endDate","estUsd"],IV=["person","label","startDate","endDate"],$V=/^\d{4}-\d{2}-\d{2}$/,en=e=>String(e??"").trim(),lk=e=>typeof e=="string"&&e.startsWith("@"),UM=864e5;function HM(e){let t=Date.parse(`${e}T00:00:00Z`),n=new Date(t).getUTCDay();return new Date(t-(n+6)%7*UM).toISOString().slice(0,10)}function RV(e){return new Date(Date.parse(`${HM(e)}T00:00:00Z`)+6*UM).toISOString().slice(0,10)}var jM=(e,t)=>{let n=en(e);if(!$V.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 OV(e,t){let n=jM(e,"startDate"),r=jM(t,"endDate");if(r<n)throw new Error(`endDate ${r} is before startDate ${n}`);let o=HM(n),s=RV(r);return{startDate:o,endDate:s,snapped:o!==n||s!==r}}var FM=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},jo=(e,t,n)=>{let r=en(e);if(r.length>t)throw new Error(`${n} is too long (${r.length}); cap is ${t}`);return r};function ak(e,t){let n=en(t);if(!n)throw new Error("a circuit name or id is required");if(lk(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 MV(e,t){let n=en(t);if(!n)throw new Error('a person is required \u2014 "me", a person id, or a row label');if(n==="me"||lk(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 CV(e,t,{allow:n=Kl}={}){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>ik)throw new Error(`too many ops (${o.length}); cap is ${ik} \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=x=>{x.id&&(l.circuits[x.id]={name:x.name,status:x.status,type:x.type??"build",updatedAt:x.updatedAt??null},u[x.id]=x.name)},h=x=>{x.id&&(u[x.id]=x.label)},y=(x,S)=>{let _=en(x);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[`@${_}`]=S,_},k=o.map((x,S)=>{let _=x&&typeof x=="object"?x:{},M=en(_.op),P=`op ${S+1}`;if(!Kl.has(M))throw new Error(`${P}: unknown op "${M}" \u2014 one of ${[...Kl].join(", ")}`);if(!n.has(M))throw new Error(`${P}: "${M}" isn't a circuit op \u2014 roadmap changes go through \`bostrat-roadmap propose\` (one card, either CLI)`);let j=R=>{throw new Error(`${P} (${M}): ${R}`)},A=R=>{let T=_.set&&typeof _.set=="object"&&!Array.isArray(_.set)?_.set:null;T||j("needs a `set` object naming the fields to change");let C=Object.keys(T).filter(W=>!R.includes(W));return C.length&&j(`unknown field(s) ${C.join(", ")} \u2014 settable: ${R.join(", ")}`),Object.keys(T).length||j("`set` names no fields"),T},$=R=>{let{startDate:T,endDate:C,snapped:W}=OV(R.startDate,R.endDate);return W&&(p=!0),{startDate:T,endDate:C,snapped:W}},L=R=>{let T=MV(a,R);return en(R)==="me"&&(f=!0),h(T),{key:T.id??en(R),label:T.label}},H=(R,T,C,W,B)=>{let Z=en(R);Z||j(`needs a ${W} id`);let xe=T.find(Te=>Te[C]===Z);return xe||j(`no ${W} "${Z}" \u2014 see \`bostrat-roadmap ls\``),B[Z]={...xe},xe};switch(M){case"circuit.create":{let R=jo(_.name,DM,"name");R||j("a circuit needs a name");let T=en(_.type)||"build";Uf.has(T)||j(`bad type "${T}" (${[...Uf].join(" | ")})`);let C=s.find(B=>String(B.name).toLowerCase()===R.toLowerCase());C&&j(`a circuit named "${C.name}" already exists (${C.id}) \u2014 update it instead of making a twin`);let W=y(_.ref,R);return{op:M,...W?{ref:W}:{},name:R,description:jo(_.description,BM,"description"),type:T}}case"circuit.update":{let R=ak(s,_.circuit);R.id||j("can't update a circuit created in the same plan \u2014 set its fields on the create op"),w(R);let T=A(EV),C={};if(T.name!==void 0){let W=jo(T.name,DM,"name");W||j("name can't be blank"),W!==R.name&&(C.name=W)}return T.description!==void 0&&(C.description=jo(T.description,BM,"description")),T.status!==void 0&&(LM.has(T.status)||j(`bad status "${T.status}" (${[...LM].join(" | ")})`),T.status!==R.status&&(C.status=T.status)),T.type!==void 0&&(Uf.has(T.type)||j(`bad type "${T.type}" (${[...Uf].join(" | ")})`),T.type!==(R.type??"build")&&(C.type=T.type)),Object.keys(C).length||j("nothing would change \u2014 the set equals the circuit's current values"),{op:M,circuit:R.id,name:R.name,set:C}}case"circuit.delete":{let R=ak(s,_.circuit);R.id||j("can't delete a circuit created in the same plan"),w(R);let T=o.some((C,W)=>W<S&&en(C?.op)==="circuit.update"&&C?.set?.status&&C.set.status!=="active"&&en(C?.circuit)===en(_.circuit));return R.status==="active"&&!T&&j(`\u201C${R.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:M,circuit:R.id,name:R.name,status:R.status}}case"person.create":{let R=jo(_.label,sk,"label");R||j("a person row needs a label");let T=a.find(W=>String(W.label).toLowerCase()===R.toLowerCase());T&&j(`a roadmap row labelled "${T.label}" already exists (${T.personId})`);let C=y(_.ref,R);return{op:M,...C?{ref:C}:{},label:R}}case"slot.create":{let R=ak(s,_.circuit);w(R);let T=L(_.person),C=$(_);return{op:M,circuit:R.id??R.ref,circuitName:R.name,person:T.key,personLabel:T.label,...C,estUsd:FM(_.estUsd)}}case"slot.update":{let R=H(_.slot,i,"slotId","slot",l.slots),T=A(_V),C={};if(T.person!==void 0){let B=L(T.person);C.person=B.key,C.personLabel=B.label}if(T.startDate!==void 0||T.endDate!==void 0){let B=$({startDate:T.startDate??R.startDate,endDate:T.endDate??R.endDate});B.startDate!==R.startDate&&(C.startDate=B.startDate),B.endDate!==R.endDate&&(C.endDate=B.endDate)}T.estUsd!==void 0&&(C.estUsd=FM(T.estUsd)),Object.keys(C).length||j("nothing would change");let W=s.find(B=>B.id===R.circuitId);return{op:M,slot:R.slotId,circuitName:W?.name??null,set:C}}case"slot.delete":{let R=H(_.slot,i,"slotId","slot",l.slots),T=s.find(C=>C.id===R.circuitId);return{op:M,slot:R.slotId,circuitName:T?.name??null,startDate:R.startDate,endDate:R.endDate}}case"reservation.create":{let R=L(_.person),T=jo(_.label,sk,"label");return T||j("a reservation needs a label (Leave, Support rotation, \u2026)"),{op:M,person:R.key,personLabel:R.label,label:T,...$(_)}}case"reservation.update":{let R=H(_.reservation,c,"reservationId","reservation",l.reservations),T=A(IV),C={};if(T.person!==void 0){let W=L(T.person);C.person=W.key,C.personLabel=W.label}if(T.label!==void 0){let W=jo(T.label,sk,"label");W||j("label can't be blank"),W!==R.label&&(C.label=W)}if(T.startDate!==void 0||T.endDate!==void 0){let W=$({startDate:T.startDate??R.startDate,endDate:T.endDate??R.endDate});W.startDate!==R.startDate&&(C.startDate=W.startDate),W.endDate!==R.endDate&&(C.endDate=W.endDate)}return Object.keys(C).length||j("nothing would change"),{op:M,reservation:R.reservationId,label:R.label,set:C}}case"reservation.delete":{let R=H(_.reservation,c,"reservationId","reservation",l.reservations);return{op:M,reservation:R.reservationId,label:R.label,startDate:R.startDate,endDate:R.endDate}}default:return j("unhandled op")}});k.forEach((x,S)=>{for(let _ of[x.circuit,x.person,x.set?.person])if(lk(_)&&!d.has(String(_).slice(1)))throw new Error(`op ${S+1} (${x.op}): unknown ref "${_}" \u2014 no earlier op in this plan creates it`)});let g=a.some(x=>x.kind==="user"&&x.userId);return{why:jo(r.why,TV,"why"),ops:k,base:l,resolved:u,snapped:p,createsMeRow:f&&!g}}async function WM(e,t,n,r={}){let o=CV(t,n,r),s=SV(),a={ts:Date.now(),proposalId:s,...o};return await N({id:e.id,cwd:e.cwd},{type:"planning.change.offered",actor:"system",source:"orchestrator",payload:a}),a}var NV=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 qM(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 NV(e,t),s={id:e.id,cwd:e.cwd},a=o.payload;return n==="applied"&&await N(s,{type:"planning.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,why:a.why??"",results:Array.isArray(r)?r.slice(0,ik+1):[]}}),await N(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}}gp();be();Yr();be();Gn();Mp();var GM=10,KM=200,PV=120,DV=24,zM=/^\d{4}-\d{2}-\d{2}$/;function uk(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var BV=(e=Date.now())=>new Date(e).toISOString().slice(0,10),At=(e,t="i")=>new RegExp(e,t),LV=[{re:At("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:At("\\bSPC\\b",""),reason:"business (SPC)"},{re:At("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:At("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:At("\\bReplicas\\b",""),reason:"competitor research"},{re:At("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:At("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:At("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],jV=[At("\\bSPC\\b",""),At("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),At("competitor|cloudcli|\\bkiro\\b"),At("\\bReplicas\\b",""),At("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),At("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),At("(^|[^\\w&])#\\d+\\b"),At("\\btrack/[\\w.-]+")];function FV({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of LV)if(o.test(n)||o.test(r))return s;return null}function VM(e){let t=String(e||"");for(let n of jV){let r=n.exec(t);if(r)return r[0].trim()}return null}function JM(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 UV=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function HV(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=rl(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(`
801
+ `)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,PV)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${DV}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=UV.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=VM(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>KM)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${KM}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=VM(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>GM)throw new Error(`${r.length} bullets \u2014 over the ${GM}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function WV(e,{repos:t=uk()}={}){let n=new Set(t);return(await En()).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:FV({title:r.title,headRef:r.headRef})}))}async function YM(e,t){let n=await WV(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function XM(e,{md:t,day:n=null}){let r=HV(t),o=n==null||n===""?BV():String(n);if(!zM.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await N({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 ZM(e,{day:t}){let n=String(t||"");if(!zM.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await N({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}}vs();Gn();Ss();be();vs();xt();Ir();Gn();Oc();pp();Zd();va();an();import{execFile as tz}from"node:child_process";import{promisify as nz}from"node:util";var qV=new Set(["pull_request","check_suite","workflow_run","push"]),GV=/^[^/\s]+\/[^/\s]+$/,KV=500,dk=new Set,pk=[],Hf=new Map,mn={hourStart:0,byEvent:{},duplicates:0,rejected:0};function fk(e,t,n){let r=Math.floor(e/36e5)*36e5;r!==mn.hourStart&&(mn.hourStart=r,mn.byEvent={},mn.duplicates=0,mn.rejected=0),t==="accepted"?mn.byEvent[n]=(mn.byEvent[n]||0)+1:mn[t]+=1}function VV(e){if(!e||typeof e!="object"||e.forge!=="github"||typeof e.event!="string"||!qV.has(e.event)||typeof e.repo!="string"||!GV.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 QM(e,{now:t=Date.now(),onAccept:n=null,log:r=console}={}){let o=VV(e);if(!o)return fk(t,"rejected"),{ok:!1,error:"malformed github event envelope"};if(o.deliveryId){if(dk.has(o.deliveryId))return fk(t,"duplicates"),{ok:!0,duplicate:!0,envelope:o};for(dk.add(o.deliveryId),pk.push(o.deliveryId);pk.length>KV;)dk.delete(pk.shift())}let s=o.repo.toLowerCase(),a=Hf.get(s)||{lastDeliveryAt:0,count:0};a.lastDeliveryAt=t,a.count+=1,Hf.set(s,a),fk(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 zV(e,t=Date.now()){let n=Hf.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 eC=1440*6e4;function mk(e,t=Date.now()){let n=zV(e,t);return n.covered&&n.ageMs<eC}function tC(e=Date.now()){let t={};for(let[n,r]of Hf)t[n]={lastDeliveryAt:r.lastDeliveryAt,count:r.count,covered:e-r.lastDeliveryAt<eC};return{hourStart:mn.hourStart,byEvent:{...mn.byEvent},duplicates:mn.duplicates,rejected:mn.rejected,repos:t}}be();Gn();Gr();Ir();an();function nC(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function JV(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var YV=new Set(["merged","closed","lost"]);function XV(e,t){if(!e?.blocked)return null;let n=nC(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 ZV(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function QV(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 ez(e,t,n){await N({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 Wf(e,t={}){let{now:n=Date.now(),slugOf:r=Me,lookup:o=ft,note:s=FA,tracks:a=async()=>(await ke()).filter(d=>!Ue(d)),asked:i=QV,emitChange:c=ez}=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(!JV(f))continue;let w=await o(p,f.number).catch(()=>null);if(!w?.trackId||YV.has(w.state))continue;let{prev:h}=await s(p,f.number,{blocked:nC(f),sha:f.headSha??null,at:n});if(!h)continue;let y=XV(h,f);if(!y||ZV(w,y.change))continue;u??=new Map((await a()).map(S=>[S.id,S]));let k=u.get(w.trackId);if(!k)continue;let g=f.headSha??null;if(await i(k,y.change,f.number,g,h.at||0))continue;let x={number:Number(f.number),url:f.url||w.url,title:f.title||w.title,branch:f.headRefName||w.headRef,repo:p,sha:g,delegated:!1,reason:y.reason};y.change==="ci-fixed"?x.passed=f.checks.passed:x.base=f.baseRefName||null,await c(k,y.change,x),l.push({change:y.change,number:f.number,reason:y.reason})}catch{}}return l}var gk=nz(tz),dC=3e4,rz=30*6e4,oz=dC,sz=10*6e4,az=10080*6e4,iz=60*6e4,rC=8,pC=1440*6e4,cz=3,fC="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",wk=60*6e4,lz=15*6e4,uz=9e4,dz=1440*6e4,Vl=new Map,zl=new Map,pz=360*6e4,fz=e=>e.reduce((t,n)=>({misses:Math.max(t.misses,n.brokerRefused?.misses||0),until:Math.max(t.until,n.brokerRefused?.until||0)}),{misses:0,until:0}),mz=/could not resolve|not found|no pull requests?/i,hz=e=>mz.test(String(e?.message||e||""));function wz(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<wk)}var oC={fast:oz,slow:sz,decay:iz};function sC(e,t,n=mk){return mC(e,t,{grace:0})||!n(e.repo,t)&&(e.armedAt&&t-e.armedAt<rz||wz(e,t))?"fast":t-(e.firstSeen||0)>az?"decay":"slow"}function Yl(e,t,n,r){let o=e.lanes?.get(ce(t.repo,t.number))||{};return Xd({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function gz(e,t){Sr("watch");try{let{stdout:n}=await gk("gh",["pr","view",String(t),"--repo",e,"--json",fC],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await Bn({slug:e})}});return JSON.parse(n||"null")}catch(n){throw yo(n)&&bo(n),n}}async function yz(e){Sr("watch");try{let{stdout:t}=await gk("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",fC],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await Bn({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw yo(t)&&bo(t),t}}async function bz(){let e=new Map;for(let t of await ke().catch(()=>[]))e.set(t.id,t);return e}async function kz(e,t){await N({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}}),await dp(e,t).catch(()=>{})}async function xz(e,t){let n=await xs(e);return n?Ba(n,t):null}async function vz(e,t,n){let r=await xs(e);if(!r)throw new Error(`no local checkout for ${e}`);return La(r,t,{method:n})}async function Sz(e,t){let n=await xs(e);if(!n)throw new Error(`no local checkout for ${e}`);return Nc(n,t)}async function Tz(e,t){await N({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 gi(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 Az=10*6e4;async function Ez(e,t,n){let r=e.autoMerge?.armedAt||0;if(r&&(n.now??Date.now())-r>pC){await gi(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 gi(e,o,t,n,`check${o.checks.failed===1?"":"s"} failed: ${a}`);return}if(o.mergeable==="CONFLICTING"){await gi(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<Az)return;await gi(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 gi(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 gi(e,o,t,n,String(a?.message||a).trim()||"merge failed");return}await hC(e,{...o,state:"MERGED"},t,n,{change:"auto-merged",githubAt:o.checks.settledAt||null})}}async function yi(e,t,n){await N({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:t,...n}})}async function _z(e,t){try{return await gk("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function Jl(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 bi=(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 mC(e,t,{grace:n=uz}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=dz}async function Iz(e,t,n,r){let o=r.now??Date.now();if(!mC(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||Ue(s))return!1;let a=(s.boxes||[]).find(d=>d.name===s.leadBox);return await(r.midTurn??is)(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??xr)(e.repo,e.number).catch(()=>null),!1):await(r.claim??xr)(e.repo,e.number).catch(()=>null)?(await yi(s,"opened",{...bi(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 $z(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 Wd(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await Gd(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<lz;await jA(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await LA(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await Jl(a,"pushed",e.number,d=>d.payload?.sha===s)&&await yi(a,"pushed",{...bi(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>wk)await qd(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 qd(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 Jl(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await yi(a,"ci-fixed",{...bi(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await qd(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>wk)await Kd(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await Kd(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){Yl(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await Jl(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await yi(a,"reconciled",{...bi(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await Kd(e.repo,e.number).catch(()=>{})}}}}async function Rz(e,t,n,r){let o=Yl(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await Jl(s,"closed",e.number)&&await yi(s,"closed",{...bi(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 aC(e,t,n){Yl(n,e,"lost",null);let r=t.get(e.trackId);r&&!await Jl(r,"lost",e.number)&&await yi(r,"lost",bi(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function hC(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 iC(e={}){let{now:t=Date.now(),auth:n=vw,view:r=gz,list:o=yz,links:s=WA,trackMap:a=bz,emitMerged:i=kz,mark:c=wo,archiveIfArmed:l=Er,notifyIfArmed:u=_r,notifyIfResolved:d=nf,followupsIfMerged:p=Bs,batchThreshold:f=cz,detail:w=xz,merge:h=vz,updateBranch:y=Sz,lookup:k=ft,disarm:g=Rc,emitDisarmed:x=Tz,localHasCommit:S=_z,claim:_=xr,midTurn:M=is,only:P=null,wantDetail:j=null,covered:A=mk,verdicts:$=null,tokenFor:L=te=>ra(te),noteRefusal:H=DA,clearRefusal:R=BA}=e;if(!(await n().catch(()=>null))?.authenticated||Jd()>0)return 0;let C=await s().catch(()=>[]),W=fE(C),B=te=>{try{return!!j?.(te)}catch{return!1}},Z=P?C.filter(te=>{try{return P(te)}catch{return!1}}):C.filter(te=>t-(Vl.get(ce(te.repo,te.number))||0)>=oC[sC(te,t,A)]);if(!Z.length)return 0;let xe=Date.now(),Te=new Map,_e=new Map;for(let te of[...Z].sort(Pc)){let we=P?"event":sC(te,t,A);Te.set(ce(te.repo,te.number),{lane:we,intervalMs:oC[we]??null}),Vl.set(ce(te.repo,te.number),t),_e.has(te.repo)||_e.set(te.repo,[]),_e.get(te.repo).push(te)}let Q=await a().catch(()=>new Map),Xe=new Map,Pe=(te,we)=>{let Oe=ce(te,we);if(!Xe.has(Oe)){let Ve=Promise.resolve().then(()=>w(te,we));Ve.catch(()=>{}),Xe.set(Oe,Ve)}return Xe.get(Oe)},le=$??((te,we)=>Wf([{path:te,prs:[we]}],{now:t,slugOf:async()=>te,tracks:async()=>[...Q.values()].filter(Oe=>!Ue(Oe))}).catch(()=>{})),ge={now:t,lanes:Te,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,followupsIfMerged:p,detail:Pe,merge:h,updateBranch:y,lookup:k,disarm:g,emitDisarmed:x,localHasCommit:S,claim:_,midTurn:M};for(let[te,we]of _e){let Oe=fz(we);if(Oe.until>t)continue;let Ve=!1;try{if(await L(te),Oe.misses)for(let re of we)await R(re.repo,re.number).catch(()=>{})}catch(re){Ve=A0(re)}if(Ve){let re=Oe.misses+1;if(re>=rC){console.log(`[pr-watch] ${te}: not granted ${re}\xD7 \u2014 retiring ${we.length} link(s) as lost`);for(let he of we){await aC(he,Q,ge);let Be=ce(he.repo,he.number);zl.delete(Be),Vl.delete(Be)}}else for(let he of we)await H(he.repo,he.number,{misses:re,until:t+pz}).catch(()=>{});continue}let Nt,O=new Set,X=re=>re.ciFixAwait||re.reconcileAwait||B(re)?!0:!re.autoMerge||re.trackId&&W.get(re.trackId)!==ce(re.repo,re.number)?!1:t-(re.autoMerge.armedAt||0)<=pC;if(we.length>f)Nt=await o(te).catch(()=>null);else{Nt=new Map;for(let re of we){if(X(re)){let he=await Pe(te,re.number).catch(()=>null);if(he?.state){Nt.set(Number(re.number),{number:Number(re.number),url:he.url,title:he.title,headRefName:he.headRefName,headRefOid:he.headSha??null,state:he.state,mergedAt:he.mergedAt??null,closedAt:he.closedAt??null});continue}}try{let he=await r(te,re.number);he?.number!=null&&Nt.set(Number(he.number),he)}catch(he){hz(he)&&O.add(ce(re.repo,re.number))}}}if(Nt)for(let re of we){let he=ce(re.repo,re.number),Be=Nt.get(Number(re.number));if(!Be){if(O.has(he)){let Pt=(zl.get(he)||0)+1;zl.set(he,Pt),Pt>=rC&&(await aC(re,Q,ge),zl.delete(he),Vl.delete(he))}continue}if(zl.delete(he),Be.state==="MERGED"||Be.state==="CLOSED")Be.state==="MERGED"?await hC(re,Be,Q,ge):await Rz(re,Be,Q,ge),Vl.delete(he);else{await Iz(re,Be,Q,ge).catch(()=>{}),await $z(re,Be,Q,ge).catch(()=>{});let Pt=!re.trackId||W.get(re.trackId)===he;re.autoMerge&&Pt&&await Ez(re,Q,ge).catch(()=>{});try{if(B(re)&&!Xe.has(he)&&Pe(re.repo,re.number),Xe.has(he)){let tt=await Xe.get(he).catch(()=>null);tt?.checks&&await le(re.repo,tt)}}catch{}}}}let de={};for(let{lane:te}of Te.values())de[te]=(de[te]||0)+1;return console.log(`[pr-watch] probed ${Z.length} link(s) (${Object.entries(de).map(([te,we])=>`${te} ${we}`).join(", ")}) in ${Date.now()-xe}ms`),Z.length}function cC(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 hk=!1,qf=!1,Gf=[],lC=Promise.resolve();async function Oz(){for(;qf||Gf.length;){if(qf){qf=!1;try{await iC()}catch{}continue}let e=Gf;Gf=[];let t=e.map(r=>r.spec),n=Object.assign({},...e.map(r=>r.deps||{}));try{await iC({...n,only:r=>t.some(o=>cC(o,r)),wantDetail:r=>t.some(o=>o.detail&&cC(o,r))})}catch{}}}function Kf(e,t){return e===null?qf=!0:Gf.push({spec:e,deps:t}),hk||(hk=!0,lC=Oz().finally(()=>{hk=!1})),lC}function wC(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 Kf({repo:n,numbers:r,branch:e.branch||null,event:e.event||null,detail:e.detail===!0},t)}var Mz=6e4,uC=0;function gC(e=void 0){let t=e?.now??Date.now();return t-uC<Mz?Promise.resolve():(uC=t,Kf({all:!0},e))}function yC(){Kf(null),setInterval(()=>Kf(null),dC)}vs();fp();Qc();Ir();an();var Cz=new Set(["opened","reopened","closed","synchronize","ready_for_review","converted_to_draft","edited"]);async function Nz({tracks:e=ke,reconcile:t=Ep}={}){for(let n of(await e().catch(()=>[])).filter(r=>!Ue(r)))await t(n,{bypassThrottle:!0}).catch(()=>{})}function bC(e,t={}){let{invalidate:n=ln,probe:r=wC,poke:o=JE,reconcileOpened:s=Nz}=t;try{n()}catch{}let a={probe:null,poked:!1,reconciled:!1};if(!e?.repo)return a;if(e.event==="pull_request"&&Cz.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}dt();be();Ir();an();import{randomUUID as Pz}from"node:crypto";var Dz=2e4,kC=3,ki=new Map,yk=new Set;async function xC(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 Bz(e={}){let{sessions:t=null,tracks:n=null,append:r=N,read:o=K,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await kn(),i=n??await ke()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(Ue(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=(ki.get(d.name)||0)+1;ki.set(d.name,f),f===kC&&(yk.add(d.name),await xC(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:Pz(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let f=(ki.get(d.name)||0)>=kC;if(ki.delete(d.name),f||!yk.has(d.name)){yk.add(d.name);let w=await xC(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[...ki.keys()])l.has(u)||ki.delete(u)}var Xl=null,bk=!1;function vC(){return Xl?()=>{}:(Xl=setInterval(()=>{bk||(bk=!0,Bz().catch(()=>{}).finally(()=>{bk=!1}))},Dz),Xl.unref?.(),()=>{clearInterval(Xl),Xl=null})}gs();Qc();be();vs();Ss();gs();jc();import{randomUUID as Lz}from"node:crypto";async function jz(){let e=await Promise.resolve().then(()=>(Ir(),mR));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var kk={listRepoPrs:Kn,readEvents:K,appendEvent:N,sayDeps:jz,currentBranch:ko};async function Fz(e,t=kk,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??ko)(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 xk(e,t,{actions:n,notify:r=!1}={},o=kk){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 Fz(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=Lz();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 vk(e,{offerId:t,choice:n}={},r=kk){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');return vo(`prx:${e.id}:${t}`,()=>Uz(e,{offerId:t,choice:n},r))}async function Uz(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=ho.filter(d=>d!=="pr"&&(i.includes(d)||d==="push")),c=await u(e.id,Ca(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,SA(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==="push"&&Number.isFinite(Number(a.pr?.number))?{number:Number(a.pr.number)}:{},...l?{actions:l}:{}}}),n!=="dismiss"&&a.notify===!0){let{queueShipCompleteNotify:u}=await r.sayDeps();u(e.id,{actions:l})}return{say:c,choice:n}}jc();import Ur from"node:fs/promises";import xi from"node:path";import $C from"node:os";import SC from"node:fs/promises";import Vf from"node:path";import{execFile as Hz}from"node:child_process";import{promisify as Wz}from"node:util";import{fileURLToPath as qz}from"node:url";var Gz=Wz(Hz),AC=Vf.dirname(qz(import.meta.url)),Kz=Vf.resolve(AC,"..","..","client","dist"),Vz="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",zz=new Map([...Vz].map((e,t)=>[e,t]));function Jz(e){let t=[],n=0,r=0;for(let o of e){let s=zz.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 Yz(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=Jz(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 Xz(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 TC=new Map;async function Zz(e){let t;try{t=await SC.stat(e)}catch{return null}let n=TC.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await SC.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:Yz(r.mappings||"")};return TC.set(e,o),o}catch{return null}}var Sk=null;function Qz(){return Sk||(Sk=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):Gz("git",["rev-parse","--short","HEAD"],{cwd:Vf.resolve(AC,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),Sk}var e3=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function t3(e,{distDir:t=Kz}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(e3)){let[a,i,c,l]=s,u=await Zz(Vf.join(t,"assets",`${i}.map`)),d=u?Xz(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 EC(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await Qz();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await t3(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var n3=()=>process.env.BOSTRAT_STATE_DIR||xi.join(process.env.HOME||$C.tmpdir(),".bostrat"),Fo=()=>xi.join(n3(),"telemetry"),RC=()=>xi.join(Fo(),".relay-offsets.json"),r3=50,o3=14,s3=3e4,_C=500,tn=(e,t)=>typeof e=="string"?e.slice(0,t):"";function a3(e,t){if(!e||typeof e!="object")return null;let n=tn(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:tn(e.anonId,64),sessionId:tn(e.sessionId,64),userId:tn(e.userId,64),release:tn(e.release,64),appVersion:tn(e.appVersion,32),route:tn(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:tn(e.error.kind,256),message:tn(e.error.message,8192),stack:tn(e.error.stack,32768),fingerprint:tn(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:tn(s?.n,64),r:tn(s?.r,128)}))),o}var OC=e=>new Date(e).toISOString().slice(0,10),IC=0;async function MC(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,r3):[]).map(s=>a3(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await EC(s);await Ur.mkdir(Fo(),{recursive:!0});let o=xi.join(Fo(),`${OC(t)}.ndjson`);return await Ur.appendFile(o,r.map(s=>JSON.stringify(s)+`
802
+ `).join(""),"utf8"),t-IC>6*3600*1e3&&(IC=t,i3(t).catch(()=>{})),r.length}async function i3(e=Date.now()){let t=OC(e-o3*24*3600*1e3),n=[];try{n=await Ur.readdir(Fo())}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 Ur.rm(xi.join(Fo(),s),{force:!0});let o=await NC();for(let s of r)delete o[s];await PC(o)}var zf=new Map;function CC(e,t=Date.now()){let n=e||"unknown",r=zf.get(n);return r||(zf.size>512&&zf.clear(),r={tokens:40,at:t},zf.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 NC(){try{return JSON.parse(await Ur.readFile(RC(),"utf8"))||{}}catch{return{}}}async function PC(e){await Ur.mkdir(Fo(),{recursive:!0}),await Ur.writeFile(RC(),JSON.stringify(e),"utf8")}function c3(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||$C.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 l3({fetchImpl:e=fetch}={}){let t=await WR();if(!t)return{sent:0,disabled:!0};let n;try{n=(await Ur.readdir(Fo())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await NC(),o=0;for(let s of n){let a=xi.join(Fo(),s),i=r[s]||0,c;try{let p=await Ur.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(`
803
+ `).filter(Boolean),d=[];for(let p of u)try{d.push(JSON.parse(p))}catch{}for(let p=0;p<d.length;p+=_C){let f=d.slice(p,p+_C).map(h=>c3(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 PC(r)}return{sent:o,disabled:!1}}var Tk=null,Ak=!1;function DC(){Tk||(Tk=setInterval(async()=>{if(!Ak){Ak=!0;try{await l3()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{Ak=!1}}},s3),Tk.unref?.())}import Yf from"node:fs/promises";import UC from"node:path";import u3 from"node:os";var HC=()=>process.env.BOSTRAT_STATE_DIR||UC.join(process.env.HOME||u3.tmpdir(),".bostrat"),WC=()=>UC.join(HC(),"dictation-glossary.json"),d3=100,p3=500,f3=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Xf=null,Ek=null,_k=Promise.resolve();function BC(){let e={},t=Date.now();for(let n of f3)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function qC(){return Xf||(Ek??=Yf.readFile(WC(),"utf8").then(e=>JSON.parse(e)?.terms??BC()).catch(()=>BC()).then(e=>Xf=e).finally(()=>Ek=null),Ek)}async function LC(){let e=JSON.stringify({terms:Xf},null,2),t=WC(),n=`${t}.${process.pid}.tmp`;await Yf.mkdir(HC(),{recursive:!0}),await Yf.writeFile(n,e),await Yf.rename(n,t)}function m3(){return _k=_k.then(LC,LC),_k.catch(()=>{})}async function Ik(){return Object.values(await qC()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var h3=e=>Math.max(1,Math.ceil(e.length/4));async function w3(){let e=[],t=0;for(let{term:n}of await Ik()){let r=h3(n);if(!(t+r>p3)&&(e.push(n),t+=r,e.length>=d3))break}return e}async function g3(e,t){let n=await qC(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var jC=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),Jf=e=>e.toLowerCase();function FC(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function GC(e,t){let n=jC(e),r=jC(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]=Jf(n[u])===Jf(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;)Jf(n[c])===Jf(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(FC(r[l])&&i.add(r[l]),l++);for(;l<s;l++)FC(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await g3(u,"learned");return await m3(),[...i]}var Zl=null;function y3(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 KC(){if(!Zl)return null;let e=await $l();if(!e||e.apiKey.slice(-6)!==Zl.keyTail)return null;let{keyTail:t,...n}=Zl;return n}async function VC(e,t){let n=await $l();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 w3())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=y3(o.status,i);c.persistent&&(Zl={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 Zl=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}be();var $k={"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 b3(e){if(!e)return null;let t=String(e).trim();if($k[t])return t;let n=null;for(let r of Object.keys($k))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function k3(e,t={}){let n=$k[b3(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 x3(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 Ql=null;async function v3(){if(!Ql)return null;let e=await Tf();if(!e||e.apiKey.slice(-6)!==Ql.keyTail)return null;let{keyTail:t,...n}=Ql;return n}async function S3(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=x3(t.status,o);s.persistent&&(Ql={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}Ql=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 T3={openai:S3};async function zC(){let e=await Tf();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await v3()}:{configured:!1}}async function JC(){let e=await Tf();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 T3[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function YC(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=k3(t,s),i=await N(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}}an();OA(async()=>new Set((await ke()).map(e=>e.id)));var oN=Re.dirname(E3(import.meta.url)),Nk=Number(process.env.PORT)||3362,Zf=ib(process.env),sN=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,vi=iM(process.env.BOSTRAT_ALLOW_IPS),Qf=cM(process.env.BOSTRAT_VIEW_FRONT_CIDRS,Ff),Dk=uM(),aN=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",E=nn();E.disable("x-powered-by");E.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),Gl(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(ql(e)||vi.allowed(vi.clientIp(e))||Qf.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});E.use(wM);E.use(fM({token:Dk,enforce:aN}));E.use("/api/mocks",nn.json({limit:"1mb"}));E.use("/api/mocks",nn.raw({type:"image/png",limit:"24mb"}));E.use("/api/mocks",nn.raw({type:["video/mp4","video/webm"],limit:"105mb"}));E.use("/api/runbooks",nn.json({limit:"1mb"}));E.use("/api/tracks/adopt",nn.json({limit:"1mb"}));E.use("/api/telemetry",nn.json({limit:"256kb"}));E.use("/api/hook",nn.json({limit:"2mb"}));E.use("/api/dictation",nn.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));E.use("/api/tracks/:id/upload",nn.raw({type:()=>!0,limit:"25mb"}));E.use(nn.json({limit:"64kb"}));E.get("/api/health",async(e,t)=>{t.json({ok:!0,tmuxSocket:zt,hostTmuxAlive:await Zr(),autoTriggerPct:sN,plane:Si?Si.status():null})});E.get("/api/sessions",async(e,t)=>{t.json({sessions:await kn()})});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 jn(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(!je(n))return t.status(400).json({error:"invalid session name"});if(!await Se(n))return t.status(404).json({error:"session not found"});try{await Lt(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(!je(n))return t.status(400).json({error:"invalid session name"});let r=await Se(n);if(!r)return t.status(404).json({error:"session not found"});let o=await nc(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(!je(n))return t.status(400).json({error:"invalid session name"});try{let r=await fT(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=Sd(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 XC=10;async function iN(){let e=await ke(),[t,n]=await Promise.all([R$(e),hR(e)]);return{tracks:e,views:await gg(),queuedOf:r=>Cs(r),jobsOf:r=>t.get(r)??[],prPendingOf:r=>n.get(r)??[]}}E.get("/api/idle-guard",async(e,t)=>{try{t.json(ab(await iN()))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var hn=js(),O3=$R({kind:hn}),tu=null,Ct=()=>tu&&["auto","prompt","off"].includes(tu)?tu:O3,Pk=null,M3=_l.has(hn),cN=async({to:e,from:t})=>!M3||Il(await li())?!1:(ru.arm({to:e,from:t,kind:hn}),!0);async function C3(e){let t=Ct();tu=e??null;let n=Ct();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){ru.cancel();return}Pk&&await cN(Pk)}}var lN=(()=>{try{return R3(import.meta.url)("../package.json").version||null}catch{return null}})(),ru=OR({isBusy:async()=>ab(await iN()).busy,onStuck:({to:e,from:t})=>or({current:t,latest:e,installKind:hn,policy:Ct(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?or({current:t,latest:e,installKind:hn,policy:Ct(),status:"updating",reason:"auto"}):or({current:t,latest:e,installKind:hn,policy:Ct(),status:"failed",error:n?.reason})).catch(()=>{})});E.get("/api/node/self-update",async(e,t)=>{t.json({installKind:hn,policy:Ct(),policySource:tu?"plane":"node",current:lN,status:await li(),armed:ru.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 yf({to:n,kind:hn,reason:"manual"});if(r.ok)return ru.cancel(),or({current:r.from,latest:n,installKind:hn,policy:Ct(),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 uN(){try{let e=await RR();e&&await or({current:e.from,latest:e.to,installKind:e.kind||hn,policy:Ct(),status:e.status,error:e.error,reason:e.reason}),await ky({current:lN,installKind:hn,policy:Ct()})}catch{}}uN();setInterval(uN,3e4).unref();E.get("/api/tracks",async(e,t)=>{let n=(await ke()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>XC){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,XC).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:yl,agentAvailability:await zp(),tickets:await dO()})});E.get("/api/cost",async(e,t)=>{try{let n=await ke();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await Kb(n);if(r.cursorUsage=tg(),e.query.format==="text")return t.type("text/plain").send(BO(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 zb(await ke(),{window:e.query.window,from:e.query.from,to:e.query.to});if(e.query.format==="text")return t.type("text/plain").send(HO(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 VO(await ke(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=tg(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=_c(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/usage/caps",(e,t)=>{t.json(_c())});E.post("/api/usage/caps",async(e,t)=>{try{t.json(await Pd(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 nM(await ke(),{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 Zk(e.get(pr),{byToken:bl,legacy:()=>Hc(e.body?.session_id,e.body?.cwd)});if(n==="refused")return Ii("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Ii("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&&Ii("mismatch",{track:r.track.id,box:r.box.name}),Ii(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 NO(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&Iu(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 bl(e.get(pr));if(!n?.track||!n?.box)return t.status(204).end();t.send((await CE(n.track,n.box)).join(`
804
804
  `)+`
805
- `)}catch{t.status(204).end()}});E.post("/api/git/committed",async(e,t)=>{try{let n=await bl(e.get(pr));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?Re.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?Re.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+Re.sep))?s:o;NE(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 me(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 DE(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 me(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,event:await BE(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 zO(await ke(),{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(!CC(vi.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await MC(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 fr(),r=new Set((await Promise.all(n.map(a=>Me(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await Li()).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 ra(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:bu(),calls:QT(),latency:rE(),webhook:tC()})});E.post("/api/github/event",nn.json({limit:"64kb"}),(e,t)=>{let n=QM(e.body,{onAccept:r=>bC(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)=>{E0(),t.json({ok:!0})});E.get("/api/gmail/search",async(e,t)=>{try{let n=await oM(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 sM(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});async function nu({repo:e=null,number:t=null,branch:n=null}){let r=e?await Me(e):null;if(r&&t!=null){let s=await ft(r,t),a=s&&await me(s.trackId);if(a)return a}if(!n)return null;let o=await ke();return np(o,n,s=>rp(s,{branch:n,repo:e,slug:r}))}async function dN({repo:e=null,number:t=null,branch:n=null}){let r=await nu({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!Ue(r))return r;if(!n)return null;let o=e?await Me(e).catch(()=>null):null,s=await ke();return np(s,n,a=>!Ue(a)&&rp(a,{branch:n,repo:e,slug:o}))}async function Dn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await nu({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await Me(s).catch(()=>null):null);await N({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 C3(e){let t=(await ke()).filter(n=>!Ue(n));for(let n of e??[]){if(!n.prs?.length)continue;let r=await Me(n.path);if(r)for(let o of n.prs){if(await ft(r,o.number))continue;let s=await np(t,o.headRefName,a=>rp(a,{branch:o.headRefName,repo:n.path,slug:r}));s&&await Yt({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 uE();await C3(n.repos).catch(()=>{}),await Hf(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 g=o||"merge";if(!Cc.has(g))throw new Error(`invalid merge method: ${g}`);let x=Number(r);if(!Number.isInteger(x)||x<=0)throw new Error("invalid PR number");let S=await Me((await Ar(n)).path);if(!S)throw new Error("repo has no GitHub remote");let _=await nu({repo:n,number:x,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 Dp(_,"merge",{count:1,summary:`arming auto-merge on PR #${x}`}),a&&await Nc(n,x),await Yt({repo:S,number:x,trackId:_.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await $c(S,x,{merge:{method:g}}))throw new Error("couldn't record the auto-merge arm");return await ys(S,x,i===!0),await bs(S,x,c===!0&&i!==!0),ln(),await Dn("auto-armed",{number:x,url:d,title:u,branch:l,repo:n,track:_,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:x,auto:!0})}p=await nu({repo:n,number:r,branch:l}).catch(()=>null),p&&(f=await Dp(p,"merge",{count:1,summary:`merging PR #${r}`}));let h=await La(n,r,{method:o||"squash"});await Dn("merged",{number:h.number,url:d,title:u,branch:l,repo:n});let y=await Me(n).catch(()=>null),k=!1;if(y&&(i===!0&&await ys(y,h.number,!0).catch(()=>{}),c===!0&&i!==!0&&await bs(y,h.number,!0).catch(()=>{}),await _r(y,h.number).catch(()=>{}),await Bs(y,h.number).catch(()=>{}),k=await Er(y,h.number).catch(()=>!1),await wo(y,h.number,"merged").catch(()=>{})),i===!0&&!k){let g=await nu({repo:n,number:h.number,branch:l}).catch(()=>null);g&&!g.archivedAt&&await Ds(g.id).catch(()=>{})}t.json(h)}catch(h){w=h;let y=h?.message||String(h),k=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(y)?400:502;t.status(k).json({error:y})}finally{p&&f&&await ny(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 Me((await Ar(n)).path).catch(()=>null),l=c?await Rc(c,i).catch(()=>null):null;try{await Tw(n,i)}catch(u){if(!l)throw u}ln(),await Dn("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 Me(n).catch(()=>null),s=await hE(n,{method:r||"merge",onMerged:a=>{Dn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&_r(o,a.number).catch(()=>{}).then(()=>Bs(o,a.number)).catch(()=>{}).then(()=>Er(o,a.number)).catch(()=>{}).then(()=>wo(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:mE()})});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(!Cc.has(u))throw new Error(`invalid merge method: ${u}`);if(!n)return t.status(400).json({error:"trackId required"});let d=await me(n);if(!d)return t.status(404).json({error:`Track ${n} isn't on this node`});i=d;let p=(await En()).filter(h=>h.trackId===d.id&&h.state!=="merged"&&h.state!=="closed").sort(Pc);if(!p.length)return t.status(409).json({error:"no open PRs on this Track"});c=await Dp(d,"merge",{count:p.length,summary:p.length===1?"merging 1 PR":`merging ${p.length} PRs`});for(let h of p)await ys(h.repo,h.number,o===!0).catch(()=>{}),await bs(h.repo,h.number,s===!0&&o!==!0).catch(()=>{});let f=[],w=[];for(let h of p){let y={repo:h.repo,number:h.number,ok:!0,action:"armed"};f.push(y);try{let k=await xs(h.repo);if(!k)throw new Error(`no local checkout for ${h.repo}`);let g=await Ba(k,h.number);w.push({r:y,l:h,repoPath:k,pr:g,plan:dE(g,{update:r!==!1})})}catch(k){y.ok=!1,y.action="failed",y.reason=k?.message||String(k)}}for(let{r:h,l:y,repoPath:k,pr:g,plan:x}of pE(w))try{if(x.action==="skip")h.action="skipped",h.reason=x.reason;else if(x.action==="merge")await La(k,y.number,{method:u}),await Dn("merged",{number:y.number,url:g.url,title:g.title,branch:g.headRefName,repo:k,track:d}),await _r(y.repo,y.number).catch(()=>{}),await Bs(y.repo,y.number).catch(()=>{}),await Er(y.repo,y.number).catch(()=>{}),await wo(y.repo,y.number,"merged").catch(()=>{}),h.action="merged";else{if(x.action==="update-arm"&&(await Nc(k,y.number).catch(()=>{}),h.action="updated-armed"),!await $c(y.repo,y.number,{merge:{method:u}}))throw new Error("couldn't record the auto-merge arm");await Dn("auto-armed",{number:y.number,url:g.url,title:g.title,branch:g.headRefName,repo:k,track:d,...h.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(S){h.ok=!1,h.action="failed",h.reason=S?.message||String(S)}if(ln(),!f.some(h=>h.ok)){if(o===!0)for(let h of p)await ys(h.repo,h.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let h of p)await bs(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 ny(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 me(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await En()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await Rc(a.repo,a.number).catch(()=>null),c=await xs(a.repo).catch(()=>null);c&&await Tw(c,a.number).catch(()=>{}),i&&(await Dn("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}))}ln(),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 me(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=Gt(i.workspace),d,p=Array.isArray(a)?a.filter(Boolean):[];if(p.length)d=p.map(h=>{let y=u.find(k=>k.name===h||k.repo===h||k.base===h||k.dir===h);if(!y)throw new Error(`invalid repo "${h}" \u2014 not tagged on this Track`);return y});else if(d=await _s(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 y=await _w(h.dir,{title:r,body:o,base:s}),k=h.repo||await Me(h.dir).catch(()=>null);k&&y.number&&await Yt({repo:k,number:y.number,trackId:i.id,url:y.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Dn("opened",{number:y.number,url:y.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:k??h.name}}),f.push({repo:h.name,slug:k??null,ok:!0,url:y.url,number:y.number})}catch(y){f.push({repo:h.name,slug:h.repo??null,ok:!1,error:y?.message||String(y)})}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 _w(i.cwd,{title:r,body:o,base:s}),l=await Me(i.cwd).catch(()=>null);l&&c.number&&await Yt({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Dn("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 me(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await _s(n),o=new Map(r.map(a=>[a.base,a])),s=Gt(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 Zp(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 Qp(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 Dy(e.params.id,n,{skipPermissions:r!==!1});t.status(o.finishedAt?200:202).json({ok:!0,...Bk(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(Bk(xl(e.params.id))??{running:!1})});function Bk(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 Ba(n,r),s=await Me(n).catch(()=>null),a=await dN({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=Gt(a.workspace).find(k=>k.base===n||s&&k.repo===s)??null,c=a.workspace?.kind==="multi",l=await wE(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?Re.join("ci",i.name):"ci",d=Re.join(a.cwd,".bostrat",u),p=Re.join(".bostrat",u,`pr-${o.number}-fail.log`);await Et.promises.mkdir(d,{recursive:!0}),await Et.promises.writeFile(Re.join(a.cwd,p),l.map(k=>`\u2550\u2550\u2550\u2550 ${k.name}${k.link?` \xB7 ${k.link}`:""} \u2550\u2550\u2550\u2550
805
+ `)}catch{t.status(204).end()}});E.post("/api/git/committed",async(e,t)=>{try{let n=await bl(e.get(pr));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?Re.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?Re.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+Re.sep))?s:o;NE(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 me(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 DE(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 me(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,event:await BE(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 zO(await ke(),{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(!CC(vi.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await MC(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 fr(),r=new Set((await Promise.all(n.map(a=>Me(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await Li()).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 ra(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:bu(),calls:QA(),latency:rE(),webhook:tC()})});E.post("/api/github/event",nn.json({limit:"64kb"}),(e,t)=>{let n=QM(e.body,{onAccept:r=>bC(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)=>{E0(),t.json({ok:!0})});E.get("/api/gmail/search",async(e,t)=>{try{let n=await oM(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 sM(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});async function nu({repo:e=null,number:t=null,branch:n=null}){let r=e?await Me(e):null;if(r&&t!=null){let s=await ft(r,t),a=s&&await me(s.trackId);if(a)return a}if(!n)return null;let o=await ke();return rp(o,n,s=>op(s,{branch:n,repo:e,slug:r}))}async function dN({repo:e=null,number:t=null,branch:n=null}){let r=await nu({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!Ue(r))return r;if(!n)return null;let o=e?await Me(e).catch(()=>null):null,s=await ke();return rp(s,n,a=>!Ue(a)&&op(a,{branch:n,repo:e,slug:o}))}async function Dn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await nu({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await Me(s).catch(()=>null):null);await N({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 N3(e){let t=(await ke()).filter(n=>!Ue(n));for(let n of e??[]){if(!n.prs?.length)continue;let r=await Me(n.path);if(r)for(let o of n.prs){if(await ft(r,o.number))continue;let s=await rp(t,o.headRefName,a=>op(a,{branch:o.headRefName,repo:n.path,slug:r}));s&&await Yt({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 uE();await N3(n.repos).catch(()=>{}),await Wf(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 g=o||"merge";if(!Cc.has(g))throw new Error(`invalid merge method: ${g}`);let x=Number(r);if(!Number.isInteger(x)||x<=0)throw new Error("invalid PR number");let S=await Me((await Tr(n)).path);if(!S)throw new Error("repo has no GitHub remote");let _=await nu({repo:n,number:x,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 Bp(_,"merge",{count:1,summary:`arming auto-merge on PR #${x}`}),a&&await Nc(n,x),await Yt({repo:S,number:x,trackId:_.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await $c(S,x,{merge:{method:g}}))throw new Error("couldn't record the auto-merge arm");return await ys(S,x,i===!0),await bs(S,x,c===!0&&i!==!0),ln(),await Dn("auto-armed",{number:x,url:d,title:u,branch:l,repo:n,track:_,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:x,auto:!0})}p=await nu({repo:n,number:r,branch:l}).catch(()=>null),p&&(f=await Bp(p,"merge",{count:1,summary:`merging PR #${r}`}));let h=await La(n,r,{method:o||"squash"});await Dn("merged",{number:h.number,url:d,title:u,branch:l,repo:n});let y=await Me(n).catch(()=>null),k=!1;if(y&&(i===!0&&await ys(y,h.number,!0).catch(()=>{}),c===!0&&i!==!0&&await bs(y,h.number,!0).catch(()=>{}),await _r(y,h.number).catch(()=>{}),await Bs(y,h.number).catch(()=>{}),k=await Er(y,h.number).catch(()=>!1),await wo(y,h.number,"merged").catch(()=>{})),i===!0&&!k){let g=await nu({repo:n,number:h.number,branch:l}).catch(()=>null);g&&!g.archivedAt&&await Ds(g.id).catch(()=>{})}t.json(h)}catch(h){w=h;let y=h?.message||String(h),k=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(y)?400:502;t.status(k).json({error:y})}finally{p&&f&&await ny(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 Me((await Tr(n)).path).catch(()=>null),l=c?await Rc(c,i).catch(()=>null):null;try{await Aw(n,i)}catch(u){if(!l)throw u}ln(),await Dn("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 Me(n).catch(()=>null),s=await hE(n,{method:r||"merge",onMerged:a=>{Dn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&_r(o,a.number).catch(()=>{}).then(()=>Bs(o,a.number)).catch(()=>{}).then(()=>Er(o,a.number)).catch(()=>{}).then(()=>wo(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:mE()})});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(!Cc.has(u))throw new Error(`invalid merge method: ${u}`);if(!n)return t.status(400).json({error:"trackId required"});let d=await me(n);if(!d)return t.status(404).json({error:`Track ${n} isn't on this node`});i=d;let p=(await En()).filter(h=>h.trackId===d.id&&h.state!=="merged"&&h.state!=="closed").sort(Pc);if(!p.length)return t.status(409).json({error:"no open PRs on this Track"});c=await Bp(d,"merge",{count:p.length,summary:p.length===1?"merging 1 PR":`merging ${p.length} PRs`});for(let h of p)await ys(h.repo,h.number,o===!0).catch(()=>{}),await bs(h.repo,h.number,s===!0&&o!==!0).catch(()=>{});let f=[],w=[];for(let h of p){let y={repo:h.repo,number:h.number,ok:!0,action:"armed"};f.push(y);try{let k=await xs(h.repo);if(!k)throw new Error(`no local checkout for ${h.repo}`);let g=await Ba(k,h.number);w.push({r:y,l:h,repoPath:k,pr:g,plan:dE(g,{update:r!==!1})})}catch(k){y.ok=!1,y.action="failed",y.reason=k?.message||String(k)}}for(let{r:h,l:y,repoPath:k,pr:g,plan:x}of pE(w))try{if(x.action==="skip")h.action="skipped",h.reason=x.reason;else if(x.action==="merge")await La(k,y.number,{method:u}),await Dn("merged",{number:y.number,url:g.url,title:g.title,branch:g.headRefName,repo:k,track:d}),await _r(y.repo,y.number).catch(()=>{}),await Bs(y.repo,y.number).catch(()=>{}),await Er(y.repo,y.number).catch(()=>{}),await wo(y.repo,y.number,"merged").catch(()=>{}),h.action="merged";else{if(x.action==="update-arm"&&(await Nc(k,y.number).catch(()=>{}),h.action="updated-armed"),!await $c(y.repo,y.number,{merge:{method:u}}))throw new Error("couldn't record the auto-merge arm");await Dn("auto-armed",{number:y.number,url:g.url,title:g.title,branch:g.headRefName,repo:k,track:d,...h.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(S){h.ok=!1,h.action="failed",h.reason=S?.message||String(S)}if(ln(),!f.some(h=>h.ok)){if(o===!0)for(let h of p)await ys(h.repo,h.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let h of p)await bs(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 ny(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 me(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await En()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await Rc(a.repo,a.number).catch(()=>null),c=await xs(a.repo).catch(()=>null);c&&await Aw(c,a.number).catch(()=>{}),i&&(await Dn("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}))}ln(),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 me(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=Gt(i.workspace),d,p=Array.isArray(a)?a.filter(Boolean):[];if(p.length)d=p.map(h=>{let y=u.find(k=>k.name===h||k.repo===h||k.base===h||k.dir===h);if(!y)throw new Error(`invalid repo "${h}" \u2014 not tagged on this Track`);return y});else if(d=await _s(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 y=await _w(h.dir,{title:r,body:o,base:s}),k=h.repo||await Me(h.dir).catch(()=>null);k&&y.number&&await Yt({repo:k,number:y.number,trackId:i.id,url:y.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Dn("opened",{number:y.number,url:y.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:k??h.name}}),f.push({repo:h.name,slug:k??null,ok:!0,url:y.url,number:y.number})}catch(y){f.push({repo:h.name,slug:h.repo??null,ok:!1,error:y?.message||String(y)})}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 _w(i.cwd,{title:r,body:o,base:s}),l=await Me(i.cwd).catch(()=>null);l&&c.number&&await Yt({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Dn("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 me(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await _s(n),o=new Map(r.map(a=>[a.base,a])),s=Gt(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 Qp(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 ef(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 Dy(e.params.id,n,{skipPermissions:r!==!1});t.status(o.finishedAt?200:202).json({ok:!0,...Bk(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(Bk(xl(e.params.id))??{running:!1})});function Bk(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 Ba(n,r),s=await Me(n).catch(()=>null),a=await dN({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=Gt(a.workspace).find(k=>k.base===n||s&&k.repo===s)??null,c=a.workspace?.kind==="multi",l=await wE(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?Re.join("ci",i.name):"ci",d=Re.join(a.cwd,".bostrat",u),p=Re.join(".bostrat",u,`pr-${o.number}-fail.log`);await Et.promises.mkdir(d,{recursive:!0}),await Et.promises.writeFile(Re.join(a.cwd,p),l.map(k=>`\u2550\u2550\u2550\u2550 ${k.name}${k.link?` \xB7 ${k.link}`:""} \u2550\u2550\u2550\u2550
806
806
  ${k.log??"(no fetchable log \u2014 see link)"}
807
807
  `).join(`
808
- `));let f=l.map(k=>k.name).join(", "),w=c&&i?` in the ${i.name}/ checkout`:"",h=await qt(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"}),y=s;y&&(await Yt({repo:y,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await CT(y,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Dn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(k=>k.name)}}),t.json({ok:!0,leadBox:h.leadBox,queued:!!h.queued,checks:l.map(k=>k.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 Ba(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await Me(n).catch(()=>null),a=await dN({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=Gt(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 qt(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 Yt({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await NT(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Dn("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=ho.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 vo(`pr:${e.params.id}:${n}`,async()=>{let a=await me(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 xk(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 qt(a.id,Ca(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 N({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&&$y(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 me(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await vk(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 ou=e=>t=>({...t,url:yM(t,e.headers)});E.get("/api/views",async(e,t)=>{try{let n=await gg({trackId:e.query.track||void 0});t.json({views:n.map(ou(e)),maxLive:Ao})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/views/:id",async(e,t)=>{let n=await tI(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:ou(e)(n),session:Wa(n.slug)})});E.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await me(n):null;if(!i&&s&&(i=(await ke()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Re.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!nk(e.headers))return t.status(412).json({error:JR});let c=await bg({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:ou(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:ou(e)(await nI(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:ou(e)(await rI(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 oI(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var N3=[["linear",Fs,kb],["jira",vf,yb]],Rk=new Map;E.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await gb(),r={};for(let[o,s,a]of N3){let i=await s();if(!i){Rk.delete(o),r[o]={configured:!1};continue}let c=Rk.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},Rk.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 gb()})}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 HR(o),i=n?await me(n):null;!i&&r&&(i=(await ke()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Re.sep)))||null),i&&await N({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 Js=async(e,t)=>{let n=e?await me(e):null;return!n&&t&&(n=(await ke()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Re.sep)))||null),n};E.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await db()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});E.get("/api/roadmap",async(e,t)=>{try{t.json(await pb())}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 Js(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 ui(o);await yf(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 Js(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await yf(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var pN=async(e,t,n)=>{if(e)return{ref:e,track:await Js(t,n)};let r=await Js(t,n),o=r?await mb(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 pN(o,n,r),l=await NR({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 pN(e.query.circuit,e.query.track,e.query.cwd);t.json(await fb(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 Js(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=await BR(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 Js(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await LR(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 Js(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await mb(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 PR(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 me(n):null;if(!s&&r&&(s=(await ke()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+Re.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 mi(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 me(r):null;if(!o&&n&&(o=(await ke()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+Re.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 pO(),ticket:await ir(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 ir(e.params.id)})});E.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await me(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await mi(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 Pb(e.params.id)})});var Qf=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 wO(e.params.id))}catch(n){let r=n?.message||String(n);t.status(Qf(r)).json({error:r})}});E.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await Db(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(Qf(r)).json({error:r})}});E.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await gO(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(Qf(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 me(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await yO(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(Qf(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 zy(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 me(n):null;if(!s&&r&&(s=(await ke()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Re.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 kO(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 bO()})}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 me(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await xO(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 nl({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 su={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=$n(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=el(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,su,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=$n(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=el(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,su,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=$n(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(dn(n,r.v).html,su,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&&_p(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 me(a):null;if(!d&&c&&(d=(await ke()).find(h=>h.cwd&&(c===h.cwd||c.startsWith(h.cwd+Re.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 xI({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&&_p(n)?n:null;try{let o=await vI(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 TI(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await qt(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 WI(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await EI(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 LI({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 jI(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 me(n):null;if(!a&&s&&(a=(await ke()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Re.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 FI({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 UI(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 HI(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 ke(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+Re.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await XI({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 Cg(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 Cg(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=JI(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 ZI(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(Dr(n,r.v),su,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});E.get("/api/loops",async(e,t)=>{t.json(await Tc())});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 ke()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+Re.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await Tc();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 Yh({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 me(n):null;if(!s&&r&&(s=(await ke()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Re.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 _M(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var Ai=async(e,t)=>{let n=e?await me(e):null;return!n&&t&&(n=(await ke()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Re.sep)))||null),n};E.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Ai(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 h_(s,o,{ship:{changedRepos:_s}})})}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 Ai(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 g_(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 Ai(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:Vw,...await x_(r)})});var ZC=new Set(["reconcile","fixing-ci","rebase","merge"]);E.get("/api/status",async(e,t)=>{let n=await Ai(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 Ai(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&&!ZC.has(l))throw new Error(`phase must be one of ${[...ZC].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=_3();await N(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,all:a}=e.body||{};try{let i=await me(e.params.id);if(!i)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await b_(i,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null,all:a===!0},{sayToLead:qt,unarchiveTrack:nf})})}catch(i){let c=i?.message||String(i),l=i?.code==="removed"?410:/unknown offer/i.test(c)?404:/already answered/i.test(c)?409:/required|not on this card|nothing to run together/i.test(c)?400:/unreachable/i.test(c)?503:502;t.status(l).json({error:c})}});E.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await me(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await w_(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 me(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await y_(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})}});Ze.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"||me(e.trackId).then(async s=>{if(s&&(n&&await Fc(s,n,o),t==="opened"||t==="pushed")){let a=k_(await K(s).catch(()=>[]));a&&await Fc(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var fN=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await me(n):null;if(!s&&r&&(s=(await ke()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Re.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await Tc();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=RM(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 fN(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await OM(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 fN(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await MM(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 Ai(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i;try{i=await pb()}catch(c){return t.status(503).json({error:c?.message||String(c)})}try{let c=s==="circuit"?ck:Kl;t.json({ok:!0,trackId:a.id,proposal:await WM(a,o,i,{allow:c})})}catch(c){t.status(400).json({error:c?.message||String(c)})}});var Lk=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 me(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await qM(s,n,r,{results:o||[]})})}catch(s){let a=s?.message||String(s);t.status(Lk(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 me(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await NM(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(Lk(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 me(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await PM(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(Lk(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 me(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await IM(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 me(n):null;if(!a&&s&&(a=(await ke()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Re.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 QI({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 e$(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 t$(e.params.id,(e.body||{}).status)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/must be/i.test(r)?400:500;t.status(o).json({error:r})}});E.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await n$(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=JM(e.query.since||null);t.json({since:n,repos:uk(),...await YM(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var mN=async({trackId:e,cwd:t})=>{let n=e?await me(e):null;return!n&&t&&(n=(await ke()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+Re.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 mN({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 XM(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 mN({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 ZM(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var P3=120,Ok=400,D3=/^[a-z0-9][a-z0-9_-]{0,23}$/,Si=null,QC=null;E.post("/api/notify",async(e,t)=>{let{title:n,body:r,urgency:o,cwd:s,trackId:a,channel:i}=e.body||{};try{let c=typeof r=="string"?r.trim():"";if(!c)return t.status(400).json({error:"body (the message) required"});let l=i==null||i===""?null:String(i).trim().toLowerCase();if(l!==null&&!D3.test(l))return t.status(400).json({error:`channel "${String(i).slice(0,40)}" is not a valid name \u2014 lowercase letters, digits, - or _, up to 24 chars`});if(c.length>Ok)return t.status(400).json({error:`message is ${c.length} chars \u2014 over the ${Ok} cap; a notification is a nudge, put the detail in chat`});let u=rl(`${n||""}
809
- ${c}`);if(u.length)return t.status(400).json({error:`notification appears to contain a secret VALUE (${u.join(", ")}) \u2014 notifications ship off-box; never put a credential in one`});let d=a?await me(a):null;if(!d&&s&&(d=(await ke()).find(y=>y.cwd&&(s===y.cwd||s.startsWith(y.cwd+Re.sep)))||null),!d)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let p=(d.boxes||[]).find(h=>h.name===d.leadBox),f=(h,y)=>String(h).replace(/\s+/g," ").trim().slice(0,y),w={title:n?f(n,P3):d.name,body:f(c,Ok),urgency:o==="high"?"high":"normal",...l?{channel:l}:{},trackName:d.name,ts:Date.now()};await N(d,{type:"notify.raised",actor:"agent",boxId:d.leadBox??null,provider:p?.agent||null,payload:w}),t.json({ok:!0,notification:w,delivered:Si?Si.status().connected:null})}catch(c){t.status(500).json({error:c?.message||String(c)})}});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 VC(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 $l(),terms:await Ik(),problem:await KC()})});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 GC(n,r)})});E.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await me(e.params.id))return t.status(404).json({error:"track not found"});t.json(await zC())});E.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await me(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 JC())}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 me(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 YC(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 ef({name:n,cwd:r,repo:o,repos:s,agent:a,model:i,skipPermissions:c!==!1}),p=null;if(l)try{await mi(d,l,{source:"create"})}catch(w){p=w?.message||String(w)}let f=null;if(u)try{await yf(d,await ui(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 me(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:hN(ii(e.params.id)),reshape:Bk(xl(e.params.id)),subtasks:Ls(e.params.id).map(au),pendingOffers:await vy(n)})});E.delete("/api/tracks/:id",async(e,t)=>{try{let n=await Uy(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await Pb(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 Ds(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 Gy(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 nf(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 zp(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 me(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}
808
+ `));let f=l.map(k=>k.name).join(", "),w=c&&i?` in the ${i.name}/ checkout`:"",h=await qt(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"}),y=s;y&&(await Yt({repo:y,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await CA(y,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Dn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(k=>k.name)}}),t.json({ok:!0,leadBox:h.leadBox,queued:!!h.queued,checks:l.map(k=>k.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 Ba(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await Me(n).catch(()=>null),a=await dN({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=Gt(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 qt(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 Yt({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await NA(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Dn("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=ho.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 vo(`pr:${e.params.id}:${n}`,async()=>{let a=await me(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 xk(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 qt(a.id,Ca(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 N({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&&$y(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 me(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await vk(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 ou=e=>t=>({...t,url:yM(t,e.headers)});E.get("/api/views",async(e,t)=>{try{let n=await gg({trackId:e.query.track||void 0});t.json({views:n.map(ou(e)),maxLive:To})}catch(n){t.status(500).json({error:n?.message||String(n)})}});E.get("/api/views/:id",async(e,t)=>{let n=await tI(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:ou(e)(n),session:Wa(n.slug)})});E.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await me(n):null;if(!i&&s&&(i=(await ke()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Re.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!nk(e.headers))return t.status(412).json({error:JR});let c=await bg({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:ou(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:ou(e)(await nI(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:ou(e)(await rI(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 oI(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var P3=[["linear",Fs,kb],["jira",Sf,yb]],Rk=new Map;E.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await gb(),r={};for(let[o,s,a]of P3){let i=await s();if(!i){Rk.delete(o),r[o]={configured:!1};continue}let c=Rk.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},Rk.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 gb()})}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 HR(o),i=n?await me(n):null;!i&&r&&(i=(await ke()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Re.sep)))||null),i&&await N({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 Js=async(e,t)=>{let n=e?await me(e):null;return!n&&t&&(n=(await ke()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Re.sep)))||null),n};E.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await db()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});E.get("/api/roadmap",async(e,t)=>{try{t.json(await pb())}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 Js(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 ui(o);await bf(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 Js(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await bf(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var pN=async(e,t,n)=>{if(e)return{ref:e,track:await Js(t,n)};let r=await Js(t,n),o=r?await mb(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 pN(o,n,r),l=await NR({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 pN(e.query.circuit,e.query.track,e.query.cwd);t.json(await fb(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 Js(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=await BR(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 Js(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await LR(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 Js(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await mb(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 PR(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 me(n):null;if(!s&&r&&(s=(await ke()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+Re.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 mi(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 me(r):null;if(!o&&n&&(o=(await ke()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+Re.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 pO(),ticket:await ir(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 ir(e.params.id)})});E.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await me(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await mi(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 Pb(e.params.id)})});var em=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 wO(e.params.id))}catch(n){let r=n?.message||String(n);t.status(em(r)).json({error:r})}});E.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await Db(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(em(r)).json({error:r})}});E.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await gO(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(em(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 me(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await yO(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(em(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 zy(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 me(n):null;if(!s&&r&&(s=(await ke()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Re.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 kO(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 bO()})}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 me(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await xO(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 nl({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 su={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=$n(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=el(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,su,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=$n(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=el(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,su,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=$n(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(dn(n,r.v).html,su,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&&Ip(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 me(a):null;if(!d&&c&&(d=(await ke()).find(h=>h.cwd&&(c===h.cwd||c.startsWith(h.cwd+Re.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 xI({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&&Ip(n)?n:null;try{let o=await vI(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 AI(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await qt(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 WI(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await EI(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 LI({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 jI(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 me(n):null;if(!a&&s&&(a=(await ke()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Re.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 FI({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 UI(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 HI(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 ke(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+Re.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await XI({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 Cg(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 Cg(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=JI(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 ZI(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(Dr(n,r.v),su,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});E.get("/api/loops",async(e,t)=>{t.json(await Ac())});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 ke()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+Re.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await Ac();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 Yh({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 me(n):null;if(!s&&r&&(s=(await ke()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+Re.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 _M(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var Ti=async(e,t)=>{let n=e?await me(e):null;return!n&&t&&(n=(await ke()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+Re.sep)))||null),n};E.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Ti(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 h_(s,o,{ship:{changedRepos:_s}})})}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 Ti(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 g_(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 Ti(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:Vw,...await x_(r)})});var ZC=new Set(["reconcile","fixing-ci","rebase","merge"]);E.get("/api/status",async(e,t)=>{let n=await Ti(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 Ti(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&&!ZC.has(l))throw new Error(`phase must be one of ${[...ZC].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=I3();await N(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,all:a}=e.body||{};try{let i=await me(e.params.id);if(!i)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await b_(i,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null,all:a===!0},{sayToLead:qt,unarchiveTrack:rf})})}catch(i){let c=i?.message||String(i),l=i?.code==="removed"?410:/unknown offer/i.test(c)?404:/already answered/i.test(c)?409:/required|not on this card|nothing to run together/i.test(c)?400:/unreachable/i.test(c)?503:502;t.status(l).json({error:c})}});E.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await me(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await w_(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 me(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await y_(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})}});Ze.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"||me(e.trackId).then(async s=>{if(s&&(n&&await Fc(s,n,o),t==="opened"||t==="pushed")){let a=k_(await K(s).catch(()=>[]));a&&await Fc(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var fN=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await me(n):null;if(!s&&r&&(s=(await ke()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+Re.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await Ac();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=RM(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 fN(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await OM(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 fN(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await MM(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 Ti(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i;try{i=await pb()}catch(c){return t.status(503).json({error:c?.message||String(c)})}try{let c=s==="circuit"?ck:Kl;t.json({ok:!0,trackId:a.id,proposal:await WM(a,o,i,{allow:c})})}catch(c){t.status(400).json({error:c?.message||String(c)})}});var Lk=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 me(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await qM(s,n,r,{results:o||[]})})}catch(s){let a=s?.message||String(s);t.status(Lk(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 me(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await NM(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(Lk(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 me(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await PM(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(Lk(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 me(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await IM(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 me(n):null;if(!a&&s&&(a=(await ke()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+Re.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 QI({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 e$(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 t$(e.params.id,(e.body||{}).status)})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/orphaned/i.test(r)?410:/must be/i.test(r)?400:500;t.status(o).json({error:r})}});E.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await n$(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=JM(e.query.since||null);t.json({since:n,repos:uk(),...await YM(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var mN=async({trackId:e,cwd:t})=>{let n=e?await me(e):null;return!n&&t&&(n=(await ke()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+Re.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 mN({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 XM(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 mN({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 ZM(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var D3=120,Ok=400,B3=/^[a-z0-9][a-z0-9_-]{0,23}$/,Si=null,QC=null;E.post("/api/notify",async(e,t)=>{let{title:n,body:r,urgency:o,cwd:s,trackId:a,channel:i}=e.body||{};try{let c=typeof r=="string"?r.trim():"";if(!c)return t.status(400).json({error:"body (the message) required"});let l=i==null||i===""?null:String(i).trim().toLowerCase();if(l!==null&&!B3.test(l))return t.status(400).json({error:`channel "${String(i).slice(0,40)}" is not a valid name \u2014 lowercase letters, digits, - or _, up to 24 chars`});if(c.length>Ok)return t.status(400).json({error:`message is ${c.length} chars \u2014 over the ${Ok} cap; a notification is a nudge, put the detail in chat`});let u=rl(`${n||""}
809
+ ${c}`);if(u.length)return t.status(400).json({error:`notification appears to contain a secret VALUE (${u.join(", ")}) \u2014 notifications ship off-box; never put a credential in one`});let d=a?await me(a):null;if(!d&&s&&(d=(await ke()).find(y=>y.cwd&&(s===y.cwd||s.startsWith(y.cwd+Re.sep)))||null),!d)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let p=(d.boxes||[]).find(h=>h.name===d.leadBox),f=(h,y)=>String(h).replace(/\s+/g," ").trim().slice(0,y),w={title:n?f(n,D3):d.name,body:f(c,Ok),urgency:o==="high"?"high":"normal",...l?{channel:l}:{},trackName:d.name,ts:Date.now()};await N(d,{type:"notify.raised",actor:"agent",boxId:d.leadBox??null,provider:p?.agent||null,payload:w}),t.json({ok:!0,notification:w,delivered:Si?Si.status().connected:null})}catch(c){t.status(500).json({error:c?.message||String(c)})}});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 VC(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 $l(),terms:await Ik(),problem:await KC()})});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 GC(n,r)})});E.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await me(e.params.id))return t.status(404).json({error:"track not found"});t.json(await zC())});E.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await me(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 JC())}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 me(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 YC(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 tf({name:n,cwd:r,repo:o,repos:s,agent:a,model:i,skipPermissions:c!==!1}),p=null;if(l)try{await mi(d,l,{source:"create"})}catch(w){p=w?.message||String(w)}let f=null;if(u)try{await bf(d,await ui(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 me(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:hN(ii(e.params.id)),reshape:Bk(xl(e.params.id)),subtasks:Ls(e.params.id).map(au),pendingOffers:await vy(n)})});E.delete("/api/tracks/:id",async(e,t)=>{try{let n=await Uy(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await Pb(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 Ds(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 Gy(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 rf(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 Jp(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 me(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}
810
810
  data: ${JSON.stringify(i)}
811
811
 
812
812
  `),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=D0(n.id,r),a=setInterval(()=>t.write(`: hb
813
813
 
814
- `),25e3);e.on("close",()=>{clearInterval(a),s()})});E.get("/api/tracks/:id/search",async(e,t)=>{let n=await me(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=yc(await K(n)),a=sd(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 Q0(),harvest:J0()})});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 ex(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 B3=["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(`
815
- `);E.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await qt(e.params.id,B3)})}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 rf(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 qt(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 me(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 c$(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 me(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=Re.basename(String(e.params.file||""));if(!r||!Dg(Re.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=Pg(n.cwd),s,a;try{s=await Et.promises.realpath(o),a=await Et.promises.realpath(Re.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+Re.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 L3=/^[0-9a-fA-F-]{8,64}$/;E.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await me(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(!L3.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=xn(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=A3.createInterface({input:Et.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?th(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 Xp(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 _y(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 Jp(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|already answered|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 jy({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 Ty(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 My(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 me(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 Df(r,{fresh:o}))});E.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await Cy(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 rb(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:au(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:Ls(e.params.id).map(au)})});E.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await Sy(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:au(uf(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:au(ob(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function au(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 of(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 Ry(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(hN(ii(e.params.id))??{running:!1})});E.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await Qy(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=Zy(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 af(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 tb({...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 hN(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:uu(),paths:a0,trace:await s0({limit:n})})});var Mk=Re.resolve(oN,"..","..","client","dist");Et.existsSync(Mk)&&(E.use(nn.static(Mk)),E.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(Re.join(Mk,"index.html"),su)));var wN=rN.createServer(E),j3=new I3({noServer:!0}),jk=(e,t,n)=>{if(!(ql(e)||vi.allowed(vi.clientIp(e))||Zf.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
814
+ `),25e3);e.on("close",()=>{clearInterval(a),s()})});E.get("/api/tracks/:id/search",async(e,t)=>{let n=await me(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=yc(await K(n)),a=ad(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 Q0(),harvest:J0()})});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 ex(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 L3=["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(`
815
+ `);E.post("/api/tracks/:id/memory/consolidate",async(e,t)=>{try{t.json({ok:!0,...await qt(e.params.id,L3)})}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 of(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 qt(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 me(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 c$(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 me(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=Re.basename(String(e.params.file||""));if(!r||!Dg(Re.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=Pg(n.cwd),s,a;try{s=await Et.promises.realpath(o),a=await Et.promises.realpath(Re.join(o,r))}catch{return t.status(404).json({error:"upload not found"})}if(!a.startsWith(s+Re.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 j3=/^[0-9a-fA-F-]{8,64}$/;E.get("/api/tracks/:id/chat-images/:box/:uuid/:idx",async(e,t)=>{try{let n=await me(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(!j3.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=xn(a.cwd,a.sessionId);if(!i)return t.status(404).json({error:"transcript not found"});let c=`"${o}"`,l=null,u=A3.createInterface({input:Et.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?nh(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 Zp(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 _y(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 Yp(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|already answered|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 jy({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 Ay(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 My(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 me(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 Bf(r,{fresh:o}))});E.post("/api/tracks/:id/model",async(e,t)=>{let{model:n}=e.body||{};try{t.json(await Cy(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 rb(e.params.id,{agent:n,task:r,skipPermissions:o!==!1,reason:s});t.json({ok:!0,subtask:au(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:Ls(e.params.id).map(au)})});E.get("/api/tracks/:id/subtask/:sid/messages",async(e,t)=>{let n=await Sy(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:au(df(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:au(ob(e.params.sid))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:409).json({error:r})}});function au(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 sf(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 Ry(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(hN(ii(e.params.id))??{running:!1})});E.post("/api/tracks/:id/transfer-out",async(e,t)=>{try{let n=await Qy(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=Zy(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 cf(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 tb({...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 hN(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:uu(),paths:a0,trace:await s0({limit:n})})});var Mk=Re.resolve(oN,"..","..","client","dist");Et.existsSync(Mk)&&(E.use(nn.static(Mk)),E.get(/^(?!\/api\/).*/,(e,t)=>t.sendFile(Re.join(Mk,"index.html"),su)));var wN=rN.createServer(E),F3=new $3({noServer:!0}),jk=(e,t,n)=>{if(!(ql(e)||vi.allowed(vi.clientIp(e))||Qf.allows(e))){t.write(`HTTP/1.1 403 Forbidden\r
816
816
  \r
817
817
  `),t.destroy();return}if(gM(e,t,n))return;if(!mM(e,Dk,{enforce:aN})){t.write(`HTTP/1.1 401 Unauthorized\r
818
818
  \r
@@ -820,6 +820,6 @@ data: ${JSON.stringify(i)}
820
820
  \r
821
821
  `),t.destroy();return}let o=r.sessionName;if(!je(o)){t.write(`HTTP/1.1 400 Bad Request\r
822
822
  \r
823
- `),t.destroy();return}let{cols:s,rows:a}=r;j3.handleUpgrade(e,t,n,i=>Ox(i,o,{cols:s,rows:a,revive:()=>qy(o)}))};wN.on("upgrade",jk);var gN=process.env.BOSTRAT_CERT_DIR||Re.join(process.env.HOME||eu.tmpdir(),".bostrat","certs"),eN=Number(process.env.BOSTRAT_TLS_PORT)||3443,tN=Re.join(gN,"bostrat.globopi.key"),nN=Re.join(gN,"bostrat.globopi.crt");if(Et.existsSync(tN)&&Et.existsSync(nN)){let e=E3.createServer({key:Et.readFileSync(tN),cert:Et.readFileSync(nN)},E);e.on("upgrade",jk),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(eN,Xf,()=>{console.log(`[bostrat-agent] https listening on ${Xf||"0.0.0.0"}:${eN}`)})}var Ck=String(process.env.BOSTRAT_VIEW_BIND||"").trim();if(Ck){Zf.active||console.warn(`[bostrat-agent] \u26A0 BOSTRAT_VIEW_BIND=${Ck} is set but BOSTRAT_VIEW_FRONT_CIDRS is not \u2014 no peer can pass the front gate on that listener, so LAN views will 403. Set both.`);let e=bM({app:E,onUpgrade:jk,extractViewSlug:Gl,log:console}),t=rN.createServer(e.request);t.on("upgrade",e.upgrade),kM(t,{addr:Ck,port:Nk,log:console})}wN.listen(Nk,Xf,()=>{console.log(`[bostrat-agent] listening on ${Xf||"0.0.0.0"}:${Nk}`);let e=wR(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: ${zt}`),console.log(`[bostrat-agent] auto-trigger default: ${sN}%`),console.log(`[bostrat-agent] ip allowlist: ${vi.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(Zf.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),Yy().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),By().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)),nb().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),Ky().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(()=>Vy()).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)),Ly().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)),V3(),O$({listTracks:ke}),A$({trackOf:xy}),H3(),W3(),K3(),d0({holdWhile:async()=>Il(await li())}),h0()&&console.log("[cli-currency] codex release sweep armed"),XA({listTracks:ke,getTrack:me}).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)),m$()&&g$({listTracks:ke}),hx().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)),yC(),vC(),vO({resolveTrack:me}),MO({listTracks:ke,createTrack:ef,archiveTrack:Ds,listRepos:fr,resolveTrack:me,sayToLead:qt,answerPrompt:Jp,startLeadHandoff:of,interruptLead:Xp,listSubtaskJobs:Ls,cancelSubtask:uf,readEvents:K,appendEvent:N,divertShip:xk,answerPrExists:vk,knownAgents:yl}),F3(),Qi().then(t=>{t||console.warn(`[boot] no host tmux server on ${zt} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),DC(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(Si=ER({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,apiToken:Dk,nodeId:process.env.BOSTRAT_NODE_ID||eu.hostname(),name:process.env.BOSTRAT_NODE_NAME||eu.hostname(),listTracks:ke,detectAgents:Vp,sampleMetrics:YO,deliverySample:()=>U_(Ey()),onHashKey:D_,onViewBase:ZR,onTracksTransferred:eb,onDegraded:({since:t,unacked:n,oldestAgeMs:r,mode:o})=>{let s=Math.round(r/6e4),a=`${process.env.BOSTRAT_NODE_NAME||eu.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(()=>{}),QC=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(()=>{}),QC=null},onConnected:()=>{gC()},onRemoved:({reason:t,via:n})=>{let r=`${process.env.BOSTRAT_NODE_NAME||eu.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{Pk={latest:t.latest,current:t.current},await or({...t,policy:Ct()}),Ct()==="auto"&&await cN({to:t.latest,from:t.current})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>M3(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await or({current:t,latest:a,min:n,installKind:o,required:!0,policy:Ct(),status:"available",reason:"refused"}),Ct()!=="off"&&a){let i=await gf({to:a,kind:hn,reason:"hard-floor"});i.ok?(ru.cancel(),await or({current:t,latest:a,min:n,installKind:o,required:!0,policy:Ct(),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:Ct}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),ca().catch(()=>{}),s$().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),SO().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),$I().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),KI().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),qT().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{Si?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function F3(){U3(),vp().catch(()=>{}),setInterval(()=>vp().catch(()=>{}),1e4)}function U3(){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=Re.resolve(oN,"..","bin",e),n=Re.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!Et.existsSync(t))continue;Et.mkdirSync(n,{recursive:!0});let r=Re.join(n,e);(Et.existsSync(r)?Et.readlinkSync(r):null)!==t&&(Et.rmSync(r,{force:!0}),Et.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 H3(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await ke(),r=await QO({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 W3(){let e=null,t=async()=>{try{let n=Ea(),r=0,o=[],s=null,a=null;try{let u=await ke(),d=await Kb(u);r=d.fleet.unpricedTurns||0,o=d.fleet.unpricedModels||[],s=await XO(u,{days:7}),a=(await zb(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(`
823
+ `),t.destroy();return}let{cols:s,rows:a}=r;F3.handleUpgrade(e,t,n,i=>Ox(i,o,{cols:s,rows:a,revive:()=>qy(o)}))};wN.on("upgrade",jk);var gN=process.env.BOSTRAT_CERT_DIR||Re.join(process.env.HOME||eu.tmpdir(),".bostrat","certs"),eN=Number(process.env.BOSTRAT_TLS_PORT)||3443,tN=Re.join(gN,"bostrat.globopi.key"),nN=Re.join(gN,"bostrat.globopi.crt");if(Et.existsSync(tN)&&Et.existsSync(nN)){let e=_3.createServer({key:Et.readFileSync(tN),cert:Et.readFileSync(nN)},E);e.on("upgrade",jk),e.on("error",t=>{console.error(`[bostrat-agent] https listener failed (${t?.code||t?.message}) \u2014 continuing HTTP-only`)}),e.listen(eN,Zf,()=>{console.log(`[bostrat-agent] https listening on ${Zf||"0.0.0.0"}:${eN}`)})}var Ck=String(process.env.BOSTRAT_VIEW_BIND||"").trim();if(Ck){Qf.active||console.warn(`[bostrat-agent] \u26A0 BOSTRAT_VIEW_BIND=${Ck} is set but BOSTRAT_VIEW_FRONT_CIDRS is not \u2014 no peer can pass the front gate on that listener, so LAN views will 403. Set both.`);let e=bM({app:E,onUpgrade:jk,extractViewSlug:Gl,log:console}),t=rN.createServer(e.request);t.on("upgrade",e.upgrade),kM(t,{addr:Ck,port:Nk,log:console})}wN.listen(Nk,Zf,()=>{console.log(`[bostrat-agent] listening on ${Zf||"0.0.0.0"}:${Nk}`);let e=wR(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: ${zt}`),console.log(`[bostrat-agent] auto-trigger default: ${sN}%`),console.log(`[bostrat-agent] ip allowlist: ${vi.open?"OPEN":process.env.BOSTRAT_ALLOW_IPS||"CLOSED (BOSTRAT_ALLOW_IPS unset)"}`+(Qf.active?` \xB7 view front-door: ${process.env.BOSTRAT_VIEW_FRONT_CIDRS} (registered views only)`:"")),Yy().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted handoff(s)")).catch(t=>console.error("[bostrat-agent] handoff reconcile failed:",t?.message||t)),By().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)),nb().then(t=>t&&console.log("[bostrat-agent] reconciled interrupted subtask(s)")).catch(t=>console.error("[bostrat-agent] subtask reconcile failed:",t?.message||t)),Ky().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(()=>Vy()).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)),Ly().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)),z3(),O$({listTracks:ke}),T$({trackOf:xy}),W3(),q3(),V3(),d0({holdWhile:async()=>Il(await li())}),h0()&&console.log("[cli-currency] codex release sweep armed"),XT({listTracks:ke,getTrack:me}).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)),m$()&&g$({listTracks:ke}),hx().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)),yC(),vC(),vO({resolveTrack:me}),MO({listTracks:ke,createTrack:tf,archiveTrack:Ds,listRepos:fr,resolveTrack:me,sayToLead:qt,answerPrompt:Yp,startLeadHandoff:sf,interruptLead:Zp,listSubtaskJobs:Ls,cancelSubtask:df,readEvents:K,appendEvent:N,divertShip:xk,answerPrExists:vk,knownAgents:yl}),U3(),Qi().then(t=>{t||console.warn(`[boot] no host tmux server on ${zt} and auto-start failed \u2014 boxes cannot spawn until one runs`)}),DC(),process.env.BOSTRAT_PLANE_URL&&process.env.BOSTRAT_PLANE_TOKEN&&(Si=ER({url:process.env.BOSTRAT_PLANE_URL,token:process.env.BOSTRAT_PLANE_TOKEN,apiToken:Dk,nodeId:process.env.BOSTRAT_NODE_ID||eu.hostname(),name:process.env.BOSTRAT_NODE_NAME||eu.hostname(),listTracks:ke,detectAgents:zp,sampleMetrics:YO,deliverySample:()=>U_(Ey()),onHashKey:D_,onViewBase:ZR,onTracksTransferred:eb,onDegraded:({since:t,unacked:n,oldestAgeMs:r,mode:o})=>{let s=Math.round(r/6e4),a=`${process.env.BOSTRAT_NODE_NAME||eu.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(()=>{}),QC=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(()=>{}),QC=null},onConnected:()=>{gC()},onRemoved:({reason:t,via:n})=>{let r=`${process.env.BOSTRAT_NODE_NAME||eu.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{Pk={latest:t.latest,current:t.current},await or({...t,policy:Ct()}),Ct()==="auto"&&await cN({to:t.latest,from:t.current})}catch(n){console.error(`[plane-link] update notice failed: ${n?.message||n}`)}},onUpdatePolicy:t=>C3(t).catch(()=>{}),onHelloRefused:async({current:t,min:n,latest:r,installKind:o,fix:s})=>{try{let a=r||n;if(await or({current:t,latest:a,min:n,installKind:o,required:!0,policy:Ct(),status:"available",reason:"refused"}),Ct()!=="off"&&a){let i=await yf({to:a,kind:hn,reason:"hard-floor"});i.ok?(ru.cancel(),await or({current:t,latest:a,min:n,installKind:o,required:!0,policy:Ct(),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:Ct}),console.log(`[bostrat-agent] plane link \u2192 ${process.env.BOSTRAT_PLANE_URL}`),ca().catch(()=>{}),s$().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} runbooks to the plane`),()=>{}),SO().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} ticket links to the plane`),()=>{}),$I().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} mocks to the plane`),()=>{}),KI().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} flows to the plane`),()=>{}),qA().then(t=>t.pushed&&console.log(`[content-plane] seeded ${t.pushed} PR links to the plane`),()=>{}))});process.on("SIGTERM",()=>{try{Si?.stop()}catch{}setTimeout(()=>process.exit(0),150)});function U3(){H3(),Sp().catch(()=>{}),setInterval(()=>Sp().catch(()=>{}),1e4)}function H3(){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=Re.resolve(oN,"..","bin",e),n=Re.join(process.env.HOME||"",".local","bin");if(!process.env.HOME||!Et.existsSync(t))continue;Et.mkdirSync(n,{recursive:!0});let r=Re.join(n,e);(Et.existsSync(r)?Et.readlinkSync(r):null)!==t&&(Et.rmSync(r,{force:!0}),Et.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 W3(){let e=!1,t=async()=>{if(!e){e=!0;try{let n=await ke(),r=await QO({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 q3(){let e=null,t=async()=>{try{let n=Ea(),r=0,o=[],s=null,a=null;try{let u=await ke(),d=await Kb(u);r=d.fleet.unpricedTurns||0,o=d.fleet.unpricedModels||[],s=await XO(u,{days:7}),a=(await zb(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(`
824
824
  `);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(`
825
- `).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 q3=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,G3=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function K3(){let e=async()=>{try{let n=await Z0();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await ke()).filter(a=>!Ue(a)&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await X0([...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,q3).unref()},G3).unref()}function V3(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await ke();for(let n of t)Ue(n)||!n.boxes?.some(r=>r.state==="live")||(await zp(n.id).catch(()=>{}),await Tp(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}
825
+ `).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 G3=Number(process.env.BOSTRAT_MEMORY_RECONCILE_MS)||5*6e4,K3=Number(process.env.BOSTRAT_MEMORY_RECONCILE_FIRST_MS)||5*6e4;function V3(){let e=async()=>{try{let n=await Z0();n.ran&&console.log(`[memory] one-time full backfill sweep: ${n.harvested} fact(s) harvested`);let o=(await ke()).filter(a=>!Ue(a)&&a.kind!=="setup").flatMap(a=>[a.cwd,...(a.boxes||[]).map(i=>i.cwd)]).filter(Boolean),s=await X0([...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,G3).unref()},K3).unref()}function z3(){let e=!1;setInterval(async()=>{if(!e){e=!0;try{let t=await ke();for(let n of t)Ue(n)||!n.boxes?.some(r=>r.state==="live")||(await Jp(n.id).catch(()=>{}),await Ep(n).catch(()=>{}))}catch{}finally{e=!1}}},4e3)}