bostrat-node 1.13.9 → 1.14.0
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.
- package/dist/index.js +59 -59
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -26,18 +26,18 @@ trust_level = "trusted"
|
|
|
26
26
|
`)){let l=Ga(c);l&&c.trim().startsWith("-")&&s.set(l,c)}let a=new Set,i=o.map(c=>{let l=Ga(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 Vv(e,t){let n=go(t,"name")||e.replace(/\.md$/,""),r=go(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function qc(e){let t=[];try{t=await we.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 zv(e,t){let n=Ce.join(e,".bostrat","memory"),r=await qc(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=Hv.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let d of r){let p=Ce.join(n,d);if(o)try{if((await we.stat(p)).mtimeMs<o-Mj)continue}catch{continue}let w;try{w=await we.readFile(p,"utf8")}catch{continue}let{fm:m}=Zd(w),
|
|
29
|
+
`)}function Vv(e,t){let n=go(t,"name")||e.replace(/\.md$/,""),r=go(t,"description")||"";return`- [${n}](${e})${r?` \u2014 ${r}`:""}`}async function qc(e){let t=[];try{t=await we.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 zv(e,t){let n=Ce.join(e,".bostrat","memory"),r=await qc(n);if(!r.length)return{harvested:0,changedByKey:new Map};let o=Hv.get(e)??0,s=Date.now(),a=new Map,i=new Map,c=0,l=new Map;for(let d of r){let p=Ce.join(n,d);if(o)try{if((await we.stat(p)).mtimeMs<o-Mj)continue}catch{continue}let w;try{w=await we.readFile(p,"utf8")}catch{continue}let{fm:m}=Zd(w),h=Kv(m,t);if(!h)continue;let g=Rs(h),y=Ce.join(g,d),b=await nr(p,w);if(l.has(g)||l.set(g,await Wc(g)),(l.get(g)[d]||0)>=b)continue;let x=await nr(y).catch(()=>0);if(await we.access(y).then(()=>!0).catch(()=>!1)&&x>=b)continue;await we.mkdir(g,{recursive:!0}),await we.writeFile(y,w),c++;let S=a.get(g);S||a.set(g,S={won:new Set,generated:new Map}),S.won.add(d),S.generated.set(d,Vv(d,m)),i.has(h)||i.set(h,new Set),i.get(h).add(d)}let u=await we.readFile(Ce.join(n,"MEMORY.md"),"utf8").catch(()=>"");for(let[d,p]of a){let w=Ce.join(d,"MEMORY.md"),m=await we.readFile(w,"utf8").catch(()=>"");await we.writeFile(w,Iw(m,u,p.won,p.generated))}return Hv.set(e,s),{harvested:c,changedByKey:i}}async function Jv(e){let t=0,n=new Map;for(let r of e||[]){if(!r||!await we.access(Ce.join(r,".bostrat","memory")).then(()=>!0).catch(()=>!1))continue;let[s]=await _w(r),a=await zv(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 Cj(){let e=Ce.join(Xd,"workspaces"),t=[];try{t=await we.readdir(e,{withFileTypes:!0})}catch{return{harvested:0,changedByKey:new Map}}return Jv(t.filter(n=>n.isDirectory()).map(n=>Ce.join(e,n.name)))}async function Dj(e,t){let n=Rs(e),r=await Wc(n),o=new Set,s=new Map,a=[],i=0;for(let c of t||[]){let l=String(c?.file||"");if(!Nj.test(l)||l==="MEMORY.md")continue;let u=Ce.join(n,l),d=await we.access(u).then(()=>!0).catch(()=>!1),p=d?await nr(u):0,w=Number(c.modified)||0;if(c.deleted){w>p&&(d&&await we.rm(u,{force:!0}),await Ew(n,[[l,w]]),d&&(a.push(l),i++));continue}d&&p>=w||(r[l]||0)>=w||(await we.mkdir(n,{recursive:!0}),await we.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=Ce.join(n,"MEMORY.md"),l=await we.readFile(c,"utf8").catch(()=>""),u=Iw(l,[...s.values()].join(`
|
|
30
30
|
`),o);if(a.length){let d=new Set(a);u=u.split(`
|
|
31
31
|
`).filter(p=>!d.has(Ga(p))).join(`
|
|
32
32
|
`)}await we.mkdir(n,{recursive:!0}),await we.writeFile(c,u)}return{changed:i,tombstoned:a.length}}async function Qd(e,t=null){let n=Rs(e),r=t?.length?t:await qc(n);if(!r.length)return{pushed:0,source:"empty"};let o=Pj(await we.readFile(Ce.join(n,"MEMORY.md"),"utf8").catch(()=>"")),s=[];for(let a of r){let i=Ce.join(n,a),c;try{c=await we.readFile(i,"utf8")}catch{continue}s.push({file:a,content:c,modified:await nr(i,c),indexLine:o.get(a)??null})}return Vd(e,s)}async function Bj(e,{timeoutMs:t}={}){let{facts:n,source:r}=await Cv(e,t?{timeoutMs:t}:{});n.length?await Dj(e,n):r==="plane"&&await Qd(e)}function Lj(e){let t=e.split(`
|
|
33
33
|
`);t.length>jv&&(t=t.slice(0,jv));let n=t.join(`
|
|
34
34
|
`);for(;Buffer.byteLength(n,"utf8")>Oj&&t.length;)t.pop(),n=t.join(`
|
|
35
|
-
`);return n}async function Fj(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=Ce.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let d=Rs(u),p=await Wc(d);for(let[g,y]of Object.entries(p)){let b=Ce.join(n,g);await we.access(b).then(()=>!0).catch(()=>!1)&&await nr(b)<=y&&(await we.rm(b,{force:!0}),o++)}let w=await qc(d);if(!w.length)continue;await we.mkdir(n,{recursive:!0});for(let g of w){let y=Ce.join(d,g),b=Ce.join(n,g),x=await nr(y),v=await nr(b).catch(()=>0);await we.access(b).then(()=>!0).catch(()=>!1)&&v>=x||(await we.copyFile(y,b),r++)}let m=await we.readFile(Ce.join(d,"MEMORY.md"),"utf8").catch(()=>""),
|
|
35
|
+
`);return n}async function Fj(e,t){if(!e||!t?.length)return{materialized:!1,reason:"no-repo-key"};let n=Ce.join(e,".bostrat","memory"),r=0,o=0,s=[];for(let u of t){let d=Rs(u),p=await Wc(d);for(let[g,y]of Object.entries(p)){let b=Ce.join(n,g);await we.access(b).then(()=>!0).catch(()=>!1)&&await nr(b)<=y&&(await we.rm(b,{force:!0}),o++)}let w=await qc(d);if(!w.length)continue;await we.mkdir(n,{recursive:!0});for(let g of w){let y=Ce.join(d,g),b=Ce.join(n,g),x=await nr(y),v=await nr(b).catch(()=>0);await we.access(b).then(()=>!0).catch(()=>!1)&&v>=x||(await we.copyFile(y,b),r++)}let m=await we.readFile(Ce.join(d,"MEMORY.md"),"utf8").catch(()=>""),h=u===$r?"## operator memory":`## repo: ${u}`;m.trim()&&s.push(t.length>1?`${h}
|
|
36
36
|
|
|
37
37
|
${m.trim()}`:m.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=Lj(i);await we.mkdir(n,{recursive:!0}),await we.writeFile(Ce.join(n,"MEMORY.md"),c);let l=Ce.join(n,"claude");return await we.mkdir(l,{recursive:!0}),await we.writeFile(Ce.join(l,"MEMORY.md"),jj,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function Yv(e){try{let t=await _w(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,$r];return await Promise.all(n.map(r=>Bj(r,{timeoutMs:Uj}))),await Fj(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function Xv(){return{...wt,pending:qa.size,queued:Tw.size}}function Zv(e){if(Jd.has(e))return Jd.get(e);Tw.add(e);let t=Wv.then(async()=>{Tw.delete(e),Jd.delete(e);let n=await $w(e);return wt.runs++,wt.lastRunAt=Date.now(),n.error?(wt.errors++,wt.lastError=n.error):wt.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return Jd.set(e,t),Wv=t.then(()=>{}),t}function ep(e,{delayMs:t=Hj}={}){if(!e||typeof e!="string")return;wt.scheduled++;let n=qa.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{qa.delete(e),Zv(e)},t);r.unref?.(),qa.set(e,r)}async function tp(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await we.access(Ce.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=qa.get(e);r&&(clearTimeout(r),qa.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([Zv(e),s])}finally{clearTimeout(o)}}async function Qv(e){return Hc||(Hc=(async()=>{try{qv||(qv=!0,await qj());let{harvested:t,changedByKey:n}=await Jv(e);for(let[r,o]of n)await Qd(r,[...o]);return wt.reconciles++,wt.lastReconcileAt=Date.now(),wt.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return wt.errors++,wt.lastError=t?.message||String(t),{harvested:0,error:wt.lastError}}finally{Hc=null}})(),Hc)}function Wj(){return Ce.join(Xd,"memory",".full-sweep-done")}async function eA(){let e=Wj();try{let t=JSON.parse(await we.readFile(e,"utf8"));return wt.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...wt.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await Cj();for(let[o,s]of n)await Qd(o,[...s]);let r={at:Date.now(),harvested:t};return await we.mkdir(Ce.dirname(e),{recursive:!0}),await we.writeFile(e,JSON.stringify(r)),wt.backfill=r,{ran:!0,...r}}catch(t){return wt.errors++,wt.lastError=t?.message||String(t),{ran:!1,error:wt.lastError}}}async function qj(){let e=0,t=[];try{t=await we.readdir(Yd(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=Ce.join(Yd(),n.name),o=Rs($r),s=new Set,a=new Map;for(let w of await qc(r)){let m=Ce.join(r,w),
|
|
40
|
+
`,c=Lj(i);await we.mkdir(n,{recursive:!0}),await we.writeFile(Ce.join(n,"MEMORY.md"),c);let l=Ce.join(n,"claude");return await we.mkdir(l,{recursive:!0}),await we.writeFile(Ce.join(l,"MEMORY.md"),jj,{flag:"wx"}).catch(()=>{}),{materialized:!0,facts:r,capped:c!==i}}async function Yv(e){try{let t=await _w(e);if(!t.length)return{materialized:!1,reason:"no-repo-key"};let n=[...t,$r];return await Promise.all(n.map(r=>Bj(r,{timeoutMs:Uj}))),await Fj(e,n)}catch(t){return{materialized:!1,reason:"error",error:t?.message||String(t)}}}function Xv(){return{...wt,pending:qa.size,queued:Tw.size}}function Zv(e){if(Jd.has(e))return Jd.get(e);Tw.add(e);let t=Wv.then(async()=>{Tw.delete(e),Jd.delete(e);let n=await $w(e);return wt.runs++,wt.lastRunAt=Date.now(),n.error?(wt.errors++,wt.lastError=n.error):wt.harvested+=n.harvested||0,n}).catch(n=>({harvested:0,error:n?.message||String(n)}));return Jd.set(e,t),Wv=t.then(()=>{}),t}function ep(e,{delayMs:t=Hj}={}){if(!e||typeof e!="string")return;wt.scheduled++;let n=qa.get(e);n&&clearTimeout(n);let r=setTimeout(()=>{qa.delete(e),Zv(e)},t);r.unref?.(),qa.set(e,r)}async function tp(e,{timeoutMs:t=3e3}={}){if(!e)return{harvested:0,skipped:"no-cwd"};if(!await we.access(Ce.join(e,".bostrat","memory")).then(()=>!0,()=>!1))return{harvested:0,skipped:"no-memory-dir"};let r=qa.get(e);r&&(clearTimeout(r),qa.delete(e));let o,s=new Promise(a=>{o=setTimeout(()=>a({harvested:0,timedOut:!0}),t),o.unref?.()});try{return await Promise.race([Zv(e),s])}finally{clearTimeout(o)}}async function Qv(e){return Hc||(Hc=(async()=>{try{qv||(qv=!0,await qj());let{harvested:t,changedByKey:n}=await Jv(e);for(let[r,o]of n)await Qd(r,[...o]);return wt.reconciles++,wt.lastReconcileAt=Date.now(),wt.harvested+=t,{harvested:t,keys:[...n.keys()]}}catch(t){return wt.errors++,wt.lastError=t?.message||String(t),{harvested:0,error:wt.lastError}}finally{Hc=null}})(),Hc)}function Wj(){return Ce.join(Xd,"memory",".full-sweep-done")}async function eA(){let e=Wj();try{let t=JSON.parse(await we.readFile(e,"utf8"));return wt.backfill={at:Number(t?.at)||0,harvested:Number(t?.harvested)||0,prior:!0},{ran:!1,...wt.backfill}}catch{}try{let{harvested:t,changedByKey:n}=await Cj();for(let[o,s]of n)await Qd(o,[...s]);let r={at:Date.now(),harvested:t};return await we.mkdir(Ce.dirname(e),{recursive:!0}),await we.writeFile(e,JSON.stringify(r)),wt.backfill=r,{ran:!0,...r}}catch(t){return wt.errors++,wt.lastError=t?.message||String(t),{ran:!1,error:wt.lastError}}}async function qj(){let e=0,t=[];try{t=await we.readdir(Yd(),{withFileTypes:!0})}catch{return{moved:e}}for(let n of t){if(!n.isDirectory())continue;let r=Ce.join(Yd(),n.name),o=Rs($r),s=new Set,a=new Map;for(let w of await qc(r)){let m=Ce.join(r,w),h;try{h=await we.readFile(m,"utf8")}catch{continue}let{fm:g}=Zd(h);if(Kv(g,n.name)!==$r)continue;let y=Ce.join(o,w),b=await nr(y).catch(()=>0),x=await nr(m,h);await we.mkdir(o,{recursive:!0}),x>b&&await we.writeFile(y,h),await we.rm(m,{force:!0}),s.add(w),a.set(w,Vv(w,g)),e++}if(!s.size)continue;let i=Date.now();await Ew(r,[...s].map(w=>[w,i])),await Vd(n.name,[...s].map(w=>({file:w,deleted:!0,modified:i})));let c=Ce.join(r,"MEMORY.md"),l=await we.readFile(c,"utf8").catch(()=>""),u=l.split(`
|
|
41
41
|
`).filter(w=>!s.has(Ga(w))).join(`
|
|
42
42
|
`);await we.writeFile(c,u).catch(()=>{});let d=Ce.join(o,"MEMORY.md"),p=await we.readFile(d,"utf8").catch(()=>"");await we.writeFile(d,Iw(p,l,s,a))}return{moved:e}}async function tA(){let e=[],t=[$r];try{for(let n of await we.readdir(Yd(),{withFileTypes:!0}))n.isDirectory()&&t.push(n.name)}catch{}for(let n of t){let r=Rs(n),o=await qc(r),s=await Wc(r);if(!o.length&&!Object.keys(s).length)continue;let a=[];for(let i of o){let c=await we.readFile(Ce.join(r,i),"utf8").catch(()=>""),{fm:l}=Zd(c);a.push({file:i,name:go(l,"name")||i.replace(/\.md$/,""),description:go(l,"description")||"",scope:go(l,"scope")||null,modified:await nr(Ce.join(r,i),c)})}e.push({key:n,facts:a,tombstones:Object.keys(s).length})}return e}async function nA(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=Rs(e),r=Ce.join(n,t);if(!await we.access(r).then(()=>!0).catch(()=>!1))throw new Error(`fact ${t} not found in ${e}`);let s=Date.now();await we.rm(r,{force:!0}),await Ew(n,[[t,s]]);let a=Ce.join(n,"MEMORY.md"),i=await we.readFile(a,"utf8").catch(()=>"");await we.writeFile(a,i.split(`
|
|
43
43
|
`).filter(l=>Ga(l)!==t).join(`
|
|
@@ -94,17 +94,17 @@ curl -sS -m 3 -X POST "$${Os}/api/deps/refresh" \\
|
|
|
94
94
|
-H 'content-type: application/json' -H "${In}: $${_n}" --data-binary '{}' >/dev/null 2>&1 || true
|
|
95
95
|
exit 0
|
|
96
96
|
`,wF=new Set(["post-merge","post-rewrite","post-checkout"])});import{execFile as SA}from"node:child_process";import{promisify as gF}from"node:util";import wn from"node:fs";import Lw from"node:os";import Rr from"node:path";import{randomUUID as dp}from"node:crypto";function xo(e){return new Promise(t=>setTimeout(t,e))}function up(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 vA(e){return`/tmp/tmux-${e}/default`}function yF({explicit:e,legacyExists:t,runtimeDir:n,uid:r}){if(e)return e;let o=vA(r);return t?o:n?`${n}/bostrat/tmux-default`:o}function el(){return process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1"?[]:["-e",`${Qc}=1`]}function xF(){return kF.flatMap(e=>["-e",`${e}=`])}function AA(){return process.env.BOSTRAT_STATE_DIR||Rr.join(process.env.HOME||Lw.tmpdir(),".bostrat")}function TA(){return process.env.BOSTRAT_SCRATCH_DIR||Rr.join(AA(),"tmp")}function SF({trackId:e=null,cwd:t=null,name:n=null}={}){if(e&&Va.test(e))return e;if(t){let r=Rr.relative(AA(),Rr.resolve(t)).split(Rr.sep),[o,s]=r;if(o&&s&&!o.startsWith("..")){if(o==="workspaces"&&Va.test(s))return s;if(o==="worktrees"){let a=s.split("-")[0];if(Va.test(a))return a}if(o==="setup"&&Va.test(s))return`setup-${s}`}}return n&&Va.test(n)?`session-${n}`:`session-${dp().slice(0,8)}`}function EA(e){return Rr.join(TA(),e)}async function Fw(e={}){let t=EA(SF(e));try{return await wn.promises.mkdir(t,{recursive:!0,mode:448}),await wn.promises.chmod(t,448).catch(()=>{}),t}catch{return null}}function vF(e){return e?tl.flatMap(t=>["-e",`${t}=${e}`]):[]}async function Uw(e){if(!e||!Va.test(e))return!1;let t=EA(e);return Rr.dirname(t)!==TA()?!1:(await wn.promises.rm(t,{recursive:!0,force:!0,maxRetries:3,retryDelay:100}).catch(()=>{}),!0)}function nl(e,t,n){let r=Ms(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&&qe(n)&&(s+=` --name ${n}`),s}function Ms(e){return/(^|\/|\s)claude(\s|$)/.test(String(e||""))}function ko(e){return/(^|\/|\s)claude(\s|$)/.test(e)?"claude":/cursor/.test(e)?"cursor":/codex/.test(e)?"codex":/gemini/.test(e)?"gemini":"agent"}function TF(e){let t=String(e||"").trim();return!t||/fake-|\.sh(\s|$)/.test(t)?!1:Ms(t)||/(^|\/|\s)codex(\s|$)/.test(t)||/cursor-agent/.test(t)||/(^|\/|\s)gemini(\s|$)/.test(t)}async function _A(e,{loginShell:t=!1,failOpen:n=!1}={}){let r=await IA(e,{loginShell:t});return r===pp?!0:r===za?!1:n}async function IA(e,{loginShell:t=!1,timeoutMs:n=Bw}={}){if(!e)return za;let r=t?process.env.SHELL||"/bin/sh":"sh",o=t?"-lic":"-c";try{return await Ne(r,[o,'command -v "$1" >/dev/null 2>&1',"_",e],{timeout:n}),pp}catch(s){return s?.killed||s?.signal?Ja:s?.code===1||s?.code===127?za:Ja}}async function fp(e,{retries:t=EF,sleep:n=_F,probe:r=IA}={}){let o=String(e||"").trim().split(/\s+/)[0],s=await r(o,{timeoutMs:Bw});for(let a=0;s===Ja&&a<t.length;a++)await n(t[a]),s=await r(o,{timeoutMs:Bw*2});return s}function se(...e){return["-S",St,...e]}async function So(){if(!wn.existsSync(St))return!1;try{return await Ne(oe,se("list-sessions")),!0}catch(e){let t=e&&e.stderr?String(e.stderr):"";return!/no server running/i.test(t)}}async function RA(){try{wn.mkdirSync(Rr.dirname(St),{recursive:!0}),await Ne(oe,se("new-session","-d","-s","keeper","-c",Zc,"sleep 2147483647"),{cwd:Zc})}catch{}return await So()}async function rl(){return await So()?!0:await RA()}async function xA({timeoutMs:e=3e3}={}){let t=Zc,n=`${$A}${process.pid}-${dp().slice(0,8)}`,r=Rr.join(Lw.tmpdir(),`${n}.txt`),s=`{ pwd -P || echo BOSTRAT_CWD_DEAD; } > ${(a=>`'${String(a).replace(/'/g,"'\\''")}'`)(r)} 2>&1`;try{await Ne(oe,se("new-session","-d","-s",n,"-c",t,s))}catch{return{verdict:"unknown",saw:null}}try{let a=Date.now()+e,i="";for(;Date.now()<a;){try{i=wn.readFileSync(r,"utf8")}catch{i=""}if(i.length)break;await xo(25)}if(!i.length)return{verdict:"unknown",saw:null};let c=i.trim();return{verdict:c===t||((u,d)=>{try{return wn.realpathSync(u)===wn.realpathSync(d)}catch{return!1}})(c,t)?"ok":"dead",saw:c}}finally{try{wn.rmSync(r,{force:!0})}catch{}Ne(oe,se("kill-session","-t",n)).catch(()=>{})}}function $F(e){return(e||[]).map(t=>typeof t=="string"?t:t?.name).filter(t=>t&&!IF.has(t)&&!t.startsWith($A))}function RF(){return Dw||(Dw=Ne(oe,["-V"]).then(({stdout:e})=>{let t=/tmux\s+(?:next-)?(\d+)\.(\d+)/.exec(String(e));return t?{major:Number(t[1]),minor:Number(t[2]),raw:String(e).trim()}:null},()=>null)),Dw}async function OF(){let e=(process.env.BOSTRAT_TMUX_CWD_PROBE||"").trim().toLowerCase();if(e==="0"||e==="off")return!1;if(e==="1"||e==="always")return!0;let t=await RF();return!!t&&(t.major>3||t.major===3&&t.minor>=7)}async function ol(){return Xc||(await OF()?(Xc=(async()=>{let{verdict:e,saw:t}=await xA();if(e!=="dead")return e;let n=$F(await sn().catch(()=>[]));if(n.length)throw new Error(`the tmux server on ${St} lost its own working directory (deleted under it \u2014 a self-update replaces the package dir it was started from), so tmux \u22653.7 opens every new pane in that dead directory and the CLI refuses to start (probe saw ${JSON.stringify(t)}). It restarts itself once nothing holds it open; ${n.length} session(s) still do: ${n.join(", ")}. Stop or archive them and retry \u2014 or restart it by hand: ${oe} -S ${St} kill-server (ends every session on it).`);if(console.warn(`[tmux] server on ${St} lost its working directory (probe saw ${JSON.stringify(t)}) \u2014 restarting it from ${Zc}`),await Ne(oe,se("kill-server")).catch(()=>{}),!await RA())throw new Error(`host tmux server on ${St} could not be restarted after losing its working directory`);let r=await xA();if(r.verdict==="dead")throw new Error(`the tmux server on ${St} still opens panes in a deleted directory after a restart from ${Zc} (probe saw ${JSON.stringify(r.saw)})`);return"restarted"})().finally(()=>{Xc=null}),Xc):"skipped")}function qe(e){return typeof e=="string"&&MF.test(e)}async function sn(){if(!wn.existsSync(St))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 Ne(oe,se("list-sessions","-F",e)),n=Date.now();return t.trim().split(`
|
|
97
|
-
`).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,d,p,w,m]=r.split("|"),
|
|
98
|
-
`).map(n=>n.trim()).includes(e)}catch{return!1}}function LF(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 jF(e,t){let n=Date.now()+sl(),r=LF(t),o=!1,s=0,a=0;for(;;){if(await xo(DF),s+=1,!await OA(e))return;let i=await Fe(e,{lines:15}),c=!o&&BF.test(i)&&!!r?.test(i),l=!o&&!!r?.test(i);if(!c&&!l&&s>1&&!await sr(e)){if(a+=1,a>1)return}else c||(a=0);if(c){o=!0,await ne({flow:"spawn",phase:"launch-retry",sessionName:e,agent:ko(t),promptHead:t.slice(0,120)}).catch(()=>{}),await Ne(oe,se("send-keys","-t",e,"C-u")),await Ne(oe,se("send-keys","-t",e,"-l",t)),await Ne(oe,se("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await ne({flow:"spawn",phase:"launch-failed",sessionName:e,agent:ko(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function or(e,t=bF,n={}){if(!PF(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=hp(r);if(!qe(o))throw new Error("resulting tmux session name is invalid");if(!await rl())throw new Error(`host tmux server not running on ${St} and auto-start failed \u2014 start one: ${oe} -S ${St} new-session -d -s keeper "sleep 2147483647"`);if(await ol(),await OA(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||jw,a=n.agent||ko(s),i=!!n.resumeSessionId,c=n.resumeSessionId||dp(),l=i?s:nl(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&Ms(s),p=n.firstRun===!0;if(a==="codex"){let y=await jd();y.waited&&await ne({flow:"cli-currency",phase:"spawn-gate",sessionName:o,...y}),Fd(o)}p||(d&&await fo(t),a==="codex"&&await Ba(t),a==="cursor"&&await ja(t),await Yv(t),n.freshWorkspace!==!0&&await ap(t));let w=d&&!p?Cd():null,m=ZS(),
|
|
97
|
+
`).filter(Boolean).map(r=>{let[o,s,a,i,c,l,u,d,p,w,m]=r.split("|"),h=Number(i),g=Number(m);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:w==="1",createdMs:Number.isFinite(g)&&g>0?g*1e3:null}}).filter(r=>!AF.has(r.name)&&!r.name.startsWith("bostrat-view-"))}catch{return[]}}async function _e(e){return(await sn()).find(n=>n.name===e)||null}function PF(e){if(typeof e!="string")return!1;let t=e.trim();return t.length>=1&&t.length<=NF&&CF.test(t)}function hp(e){return e.trim().replace(/\s+/g,"-").toLowerCase().replace(/[^A-Za-z0-9_.-]/g,"").replace(/^-+|-+$/g,"")}async function OA(e){try{let{stdout:t}=await Ne(oe,se("list-sessions","-F","#{session_name}"));return t.split(`
|
|
98
|
+
`).map(n=>n.trim()).includes(e)}catch{return!1}}function LF(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 jF(e,t){let n=Date.now()+sl(),r=LF(t),o=!1,s=0,a=0;for(;;){if(await xo(DF),s+=1,!await OA(e))return;let i=await Fe(e,{lines:15}),c=!o&&BF.test(i)&&!!r?.test(i),l=!o&&!!r?.test(i);if(!c&&!l&&s>1&&!await sr(e)){if(a+=1,a>1)return}else c||(a=0);if(c){o=!0,await ne({flow:"spawn",phase:"launch-retry",sessionName:e,agent:ko(t),promptHead:t.slice(0,120)}).catch(()=>{}),await Ne(oe,se("send-keys","-t",e,"C-u")),await Ne(oe,se("send-keys","-t",e,"-l",t)),await Ne(oe,se("send-keys","-t",e,"Enter"));continue}if(Date.now()>n){await ne({flow:"spawn",phase:"launch-failed",sessionName:e,agent:ko(t),retried:o,error:"agent CLI never started after launch was typed"}).catch(()=>{});return}}}async function or(e,t=bF,n={}){if(!PF(e))throw new Error("displayName must be 1\u201364 chars (letters, digits, space . _ -)");let r=e.trim(),o=hp(r);if(!qe(o))throw new Error("resulting tmux session name is invalid");if(!await rl())throw new Error(`host tmux server not running on ${St} and auto-start failed \u2014 start one: ${oe} -S ${St} new-session -d -s keeper "sleep 2147483647"`);if(await ol(),await OA(o))throw new Error(`tmux session "${o}" already exists`);let s=n.agentCmd||jw,a=n.agent||ko(s),i=!!n.resumeSessionId,c=n.resumeSessionId||dp(),l=i?s:nl(s,c,o),u=i?n.pinned===!0:/(^|\s)--session-id(\s|=)/.test(l),d=a==="claude"&&Ms(s),p=n.firstRun===!0;if(a==="codex"){let y=await jd();y.waited&&await ne({flow:"cli-currency",phase:"spawn-gate",sessionName:o,...y}),Fd(o)}p||(d&&await fo(t),a==="codex"&&await Ba(t),a==="cursor"&&await ja(t),await Yv(t),n.freshWorkspace!==!0&&await ap(t));let w=d&&!p?Cd():null,m=ZS(),h=["-e",`${_n}=${m}`];h.push(...yA({nodeUrl:bA()})),h.push(...xF()),w&&h.push("-e",`ANTHROPIC_API_KEY=${w}`),d&&h.push(...el());let g=await Fw({trackId:n.trackId||null,cwd:t,name:o});h.push(...vF(g));try{await Ne(oe,se("new-session","-d","-s",o,"-c",t,...h))}catch(y){throw up(w?up(y,w):y,m)}return await Cs(o),await Ne(oe,se("set-option","-t",o,"@bostrat-session","1")),await Ne(oe,se("set-option","-t",o,"@bostrat-title",r)),await Ne(oe,se("set-option","-t",o,"@bostrat-sid",c)),await Ne(oe,se("set-option","-t",o,"@bostrat-agent",a)),await Ne(oe,se("send-keys","-t",o,l,"Enter")),TF(l)&&jF(o,l).catch(()=>{}),{name:o,title:r,cwd:t,sessionId:c,agent:a,pinned:u,hookToken:m,launchCmd:l,scratchDir:g}}async function zt(e){if(!qe(e))throw new Error("invalid session name");await Ne(oe,se("kill-session","-t",e))}async function MA(e,t){if(qe(e))try{let n=t?se("set-option","-t",e,"@bostrat-sid",t):se("set-option","-u","-t",e,"@bostrat-sid");await Ne(oe,n)}catch{}}async function Fe(e,{lines:t=40}={}){if(!qe(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 Ne(oe,n);return String(r||"")}catch{return""}}async function CA(e){if(!qe(e))return[];try{let{stdout:t}=await Ne(oe,se("list-panes","-s","-t",e,"-F","#{pane_pid}"));return String(t||"").trim().split(`
|
|
99
99
|
`).map(n=>Number(n.trim())).filter(n=>Number.isFinite(n)&&n>0)}catch{return[]}}async function NA(e){if(!qe(e))return 0;try{let{stdout:t}=await Ne(oe,se("list-clients","-t",e,"-F","1"));return String(t||"").trim().split(`
|
|
100
100
|
`).filter(Boolean).length}catch{return 0}}async function Cs(e,{cols:t=HF,rows:n=WF}={}){if(!qe(e))return!0;if(await NA(e))return!1;try{let r=await PA(e);if(r.cols===t&&r.rows===n)return!0;await Ne(oe,se("resize-window","-t",e,"-x",String(t),"-y",String(n))),await Ne(oe,se("set-window-option","-t",e,"window-size","latest")),await xo(80)}catch{}return!0}async function qF(e){if(!qe(e))return 0;try{let{stdout:t}=await Ne(oe,se("display-message","-t",e,"-p","#{pane_pid}"));return Number(String(t||"").trim())||0}catch{return 0}}async function sr(e){let t=await qF(e);if(!t)return!1;try{return await Ne("pgrep",["-P",String(t)]),!1}catch(n){return n?.code===1}}async function PA(e){if(!qe(e))return{cols:0,rows:0};try{let{stdout:t}=await Ne(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 mp(e,{cols:t=FF,rows:n=UF}={}){if(qe(e)&&!await NA(e))try{let r=await PA(e),o=Math.max(r.cols,t),s=Math.max(r.rows,n);(o>r.cols||s>r.rows)&&(await Ne(oe,se("resize-window","-t",e,"-x",String(o),"-y",String(s))),await Ne(oe,se("set-window-option","-t",e,"window-size","latest")),await xo(80))}catch{}}async function an(e){return await mp(e),Fe(e,{lines:rt})}async function tt(e,t,{settleMs:n=40,kind:r}={}){if(!qe(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[t]).filter(s=>DA.has(s));for(let s=0;s<o.length;s++)await Ne(oe,se("send-keys","-t",e,o[s])),n>0&&s<o.length-1&&await xo(n);return ne({flow:"tmux",phase:"send-keys",sessionName:e,kind:r||"keys",keys:o.join(" ")}).catch(()=>{}),o.length}async function qw(e,t,{settleMs:n=40,kind:r}={}){if(!qe(e))throw new Error("invalid session name");let o=(Array.isArray(t)?t:[]).filter(a=>a&&(typeof a.key=="string"&&DA.has(a.key)||typeof a.text=="string"&&a.text.length>0)),s=a=>a.key==="BSpace"||a.key==="DC"?Math.min(al,Math.max(1,Math.floor(Number(a.count)||1))):1;for(let a=0;a<o.length;a++){let i=o[a];i.text!=null?await Ne(oe,se("send-keys","-t",e,"-l",i.text)):s(i)>1?await Ne(oe,se("send-keys","-t",e,"-N",String(s(i)),i.key)):await Ne(oe,se("send-keys","-t",e,i.key)),n>0&&a<o.length-1&&await xo(n)}return ne({flow:"tmux",phase:"send-sequence",sessionName:e,kind:r||"sequence",steps:o.map(a=>a.text!=null?`\u2039text:${a.text.length}\u203A`:s(a)>1?`${a.key}\xD7${s(a)}`:a.key).join(" ")}).catch(()=>{}),o.length}async function Ya(e,t,{kind:n}={}){if(!qe(e))throw new Error("invalid session name");let r=Math.max(0,Math.floor(Number(t)||0));return r>0&&await Ne(oe,se("send-keys","-t",e,"-N",String(r),"BSpace")),ne({flow:"tmux",phase:"send-keys",sessionName:e,kind:n||"wipe",keys:`BSpace x${r}`}).catch(()=>{}),r}async function wp(e,t,{perCharDelayMs:n=120,kind:r}={}){if(!qe(e))throw new Error("invalid session name");let o=[...String(t)];for(let s of o)await Ne(oe,se("send-keys","-t",e,"-l",s)),n>0&&await xo(n);ne({flow:"tmux",phase:"type",sessionName:e,kind:r||"type",textLen:o.length,textHead:String(t).slice(0,120)}).catch(()=>{})}function GF(e,t){return new Promise((n,r)=>{let o=SA(oe,se(...e),(s,a,i)=>{s?r(s):n({stdout:a,stderr:i})});o.stdin.on("error",()=>{}),o.stdin.end(t)})}async function KF(e,t){let n=`bostrat-${dp().slice(0,8)}`;await GF(["load-buffer","-b",n,"-"],t),await Ne(oe,se("paste-buffer","-p","-d","-b",n,"-t",e))}async function ot(e,t,{enter:n=!0,submitDelayMs:r=0,kind:o,paste:s=!1}={}){if(!qe(e))throw new Error("invalid session name");if(typeof t=="string"&&t.length>0&&(s?await KF(e,t):await Ne(oe,se("send-keys","-t",e,"-l",t))),n){let a=Number(r);Number.isFinite(a)&&a>0&&await xo(a),await Ne(oe,se("send-keys","-t",e,"Enter"))}ne({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 Ne,oe,kA,St,bF,jw,Qc,kF,tl,Va,Hw,AF,pp,za,Ja,Bw,EF,_F,Ww,Zc,IF,$A,Dw,Xc,MF,CF,NF,sl,DF,BF,FF,UF,rt,HF,WF,DA,al,kt=K(()=>{Mc();Pd();As();Ud();Gc();ip();$n();Da();Pw();Ne=gF(SA);oe=process.env.BOSTRAT_TMUX_BIN||"/usr/bin/tmux";kA=typeof process.getuid=="function"?process.getuid():0,St=yF({explicit:process.env.BOSTRAT_TMUX_SOCKET,legacyExists:(()=>{try{return wn.existsSync(vA(kA))}catch{return!1}})(),runtimeDir:process.env.XDG_RUNTIME_DIR,uid:kA}),bF=process.env.BOSTRAT_DEFAULT_CWD||process.env.HOME||"/",jw=process.env.BOSTRAT_AGENT_CMD||"claude --dangerously-skip-permissions",Qc="CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN";kF=Object.freeze(["BOSTRAT_PLANE_URL","BOSTRAT_PLANE_TOKEN"]);tl=Object.freeze(["TMPDIR","CLAUDE_CODE_TMPDIR"]);Va=/^[A-Za-z0-9._-]{1,64}$/;Hw="bostrat-usage-probe",AF=new Set([Hw]);pp="present",za="absent",Ja="unknown",Bw=5e3,EF=[250,1e3,3e3],_F=e=>new Promise(t=>setTimeout(t,e));Ww={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"};Zc=(()=>{try{let e=Lw.homedir();if(e&&wn.existsSync(e))return e}catch{}return"/"})(),IF=new Set(["keeper","_keepalive"]),$A="bostrat-cwd-probe-";Dw=null;Xc=null;MF=/^[A-Za-z0-9_.-]{1,64}$/;CF=/^[A-Za-z0-9 ._↻-]+$/,NF=64;sl=()=>Number(process.env.BOSTRAT_LAUNCH_VERIFY_MS)||12e3,DF=1e3,BF=/not found|Unknown command/i;FF=Number(process.env.BOSTRAT_PROMPT_CAPTURE_COLS)||100,UF=Number(process.env.BOSTRAT_PROMPT_CAPTURE_ROWS)||40,rt=Number(process.env.BOSTRAT_PROMPT_CAPTURE_LINES)||80,HF=Number(process.env.BOSTRAT_BOX_COLS)||120,WF=Number(process.env.BOSTRAT_BOX_ROWS)||40;DA=new Set(["Up","Down","Left","Right","Space","Enter","Tab","BTab","Escape","BSpace","DC"]);al=1600});import il from"node:fs";import ZF from"node:fs/promises";import Xa from"node:path";import QF from"node:os";function Kw(e){return e.replace(/[^A-Za-z0-9]/g,"-")}function Vw(e){let t=Xa.join(Gw,Kw(e)),n;try{n=il.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return null}let r=null;for(let o of n){let s=Xa.join(t,o);try{let{mtimeMs:a}=il.statSync(s);(!r||a>r.mtimeMs)&&(r={full:s,mtimeMs:a})}catch{}}return r?r.full:null}function On(e,t){if(!t)return null;let n=Xa.join(Gw,Kw(e),`${t}.jsonl`);return il.existsSync(n)?n:null}function WA(e){if(!e)return[];let t=Xa.join(Gw,Kw(e)),n;try{n=il.readdirSync(t).filter(o=>o.endsWith(".jsonl"))}catch{return[]}let r=[];for(let o of n)try{let s=il.statSync(Xa.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 ZF.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 tU(e){let t=e.split(`
|
|
101
101
|
`);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 cl(e,t=null,{fallbackNewest:n=!0}={}){if(!e)return null;let r,o;if(t){if(r=On(e,t),o=!0,!r)return null}else if(n){if(r=Vw(e),o=!1,!r)return null}else return null;let s;try{s=tU(await Jt(r))}catch{return null}if(!s)return null;let a=Object.prototype.hasOwnProperty.call(HA,s.model),i=HA[s.model]||eU;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 HA,eU,Gw,Mn=K(()=>{HA={"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,"claude-fable-5-1":1e6},eU=2e5,Gw=process.env.BOSTRAT_CLAUDE_PROJECTS||Xa.join(QF.homedir(),".claude","projects")});function nU(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===`
|
|
102
102
|
`){t.push(n),n="";continue}n+=s}return t.push(n),t.map(o=>o.trim()).filter(Boolean)}function ll(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 ul(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 Ge(e,t=new Set){let n=[];for(let r=1;r<e.length;r++){let o=e[r];if(o==="<<")break;if(KA(o)){t.has(o)&&r++;continue}n.push(o)}return n}function VA(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 sU(e){let t=VA(e),n=Rt(Ge(e).find(r=>!/^\d+(,\d+)?p$/.test(r)));return t&&n?t.from===t.to?`Read line ${t.from} of ${st(n)}`:`Read lines ${t.from}\u2013${t.to} of ${st(n)}`:e.includes("-i")&&n?`Edit ${st(n)}`:null}function zw(e){if(e.includes("--files")){let s=Rt(Ge(e,qA)[0]);return s&&s!=="."?`List files in ${Za(s)}`:"List files"}let t=Ge(e,qA),n=t[0];if(!n)return null;let r=Rt(t.slice(1).find(s=>s!==".")),o=Qa(n,40);return r?`Search for \u201C${o}\u201D in ${Za(r)}`:`Search for \u201C${o}\u201D`}function Jw(e){let t=Ge(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 Yw(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=Ge(e)[0];return n?`Run ${st(n)}`:null}function aU(e){let t=Ge(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 GA(e){return e.find(t=>/^https?:\/\//.test(t))||null}function lU(e){let t=ul(ll(e));if(!t.length)return null;if(/^(ba|z)?sh$/.test(st(t[0]))&&(t[1]==="-lc"||t[1]==="-c")&&t[2])return Xw(t[2]);let n=st(t[0]);if(cU.has(n))return null;if(t.includes("--version"))return`Check ${n} version`;if(n.endsWith(".sh"))return`Run ${n}`;let r=iU[n];return r?r(t.map((o,s)=>s===0?n:o)):null}function Xw(e){let t=String(e||"").trim();if(!t)return null;let n=t.indexOf("<<");if(n!==-1){let i=t.indexOf(`
|
|
103
103
|
`,n);i!==-1&&(t=t.slice(0,i))}let r=nU(t);for(let i=0;i<r.length-1;i++){let c=ul(ll(r[i])),l=ul(ll(r[i+1]));if(!(!c.length||!l.length)&&["nl","cat"].includes(st(c[0]))&&st(l[0])==="sed"){let u=VA(l),d=Ge(c)[0];if(u&&d)return Qa(u.from===u.to?`Read line ${u.from} of ${st(d)}`:`Read lines ${u.from}\u2013${u.to} of ${st(d)}`,88)}}let o=[];for(let i of r){let c=lU(i);c&&o.push({d:c,head:st(ul(ll(i))[0]||""),sub:Ge(ul(ll(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":Qa(s?s.d:o[0].d,88)}var Qa,Rt,st,Za,KA,qA,rU,oU,iU,cU,zA=K(()=>{Qa=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,Rt=e=>e&&!/[$`]/.test(e)?e:null,st=e=>e.replace(/\/+$/,"").split("/").pop()||e,Za=e=>{let t=e.replace(/\/+$/,"").split("/").filter(Boolean);return t.length>3?t.slice(-2).join("/"):e},KA=e=>e.startsWith("-"),qA=new Set(["-g","--glob","-t","--type","-A","-B","-C","-m","--max-count","-e","--regexp","-f","--file"]);rU={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 ${st(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"},oU={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"};iU={git:e=>{let t=Ge(e,new Set(["-C","-c"])),n=rU[t[0]];return n?n(t,e):null},gh:e=>{let t=Ge(e),n=oU[t[0]];return n?n(t):null},sed:sU,rg:zw,grep:zw,egrep:zw,nl:e=>{let t=Rt(Ge(e)[0]);return t?`Read ${st(t)}`:null},cat:e=>{let t=Rt(Ge(e)[0]);return t?`Read ${st(t)}`:null},head:e=>{let t=Rt(Ge(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the start of ${st(t)}`:null},tail:e=>{let t=Rt(Ge(e,new Set(["-n","-c"])).find(n=>!/^\d+$/.test(n)));return t?`Read the end of ${st(t)}`:null},wc:e=>{let t=Rt(Ge(e)[0]);return t?`Count lines in ${st(t)}`:"Count input lines"},ls:e=>{let t=Rt(Ge(e)[0]);return t&&t!=="."?`List files in ${Za(t)}`:"List files"},find:e=>Rt(e[1])&&!KA(e[1])&&e[1]!=="."?`Find files in ${Za(e[1])}`:"Find files",tree:()=>"List the directory tree",mkdir:e=>{let t=Rt(Ge(e)[0]);return t?`Create directory ${Za(t)}`:null},touch:e=>{let t=Rt(Ge(e)[0]);return t?`Create ${st(t)}`:null},rm:e=>{let t=Rt(Ge(e)[0]);return t?`Delete ${Za(t)}`:null},mv:e=>{let t=Rt(Ge(e)[0]);return t?`Move ${st(t)}`:null},cp:e=>{let t=Rt(Ge(e)[0]);return t?`Copy ${st(t)}`:null},chmod:e=>{let t=Rt(Ge(e)[1]);return t?`Change permissions on ${st(t)}`:null},diff:e=>{let t=Ge(e);return t.length>=2?`Compare ${st(t[0])} and ${st(t[1])}`:null},curl:e=>{let t=GA(e);return t?`Fetch ${Qa(t,56)}`:"Fetch a URL"},wget:e=>{let t=GA(e);return t?`Fetch ${Qa(t,56)}`:"Fetch a URL"},npm:Jw,pnpm:Jw,yarn:Jw,npx:e=>{let t=Ge(e)[0];return t?`Run ${t}`:null},node:e=>Yw(e,"Node"),python:e=>Yw(e,"Python"),python3:e=>Yw(e,"Python"),make:e=>{let t=Ge(e)[0];return t?`Run make ${t}`:"Run make"},systemctl:aU,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=Ge(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=Ge(e)[0];return t?`Locate ${t}`:null},command:e=>e[1]==="-v"&&e[2]?`Locate ${e[2]}`:null,fly:e=>{let t=Ge(e)[0];return t==="deploy"?"Deploy to Fly":t?`Run fly ${t}`:null}},cU=new Set(["pwd","echo","cd","sleep","true","false","test","[","set","export","exit","read"])});function ei(e){let t=e.split(`
|
|
104
104
|
`).map(n=>n.trim()).find(Boolean)||e;return t.length>88?`${t.slice(0,88).trimEnd()}\u2026`:t}function vo(e,t=""){let n=t.trim();return n||Xw(e)||ei(e)}function Zw(e,t){if(e){if(Array.isArray(e)){for(let n of e)Zw(n,t);return}if(typeof e=="object"){if(e.type==="tool_use"&&Qw.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))Zw(n,t)}}}async function JA(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(`
|
|
105
|
-
`)){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(Zw(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:vo(d.command,d.description),ts:u})}return o.slice(-n)}function YA(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(...uU(i,r.get(a)||[]));return s.sort((a,i)=>(a.ts||0)-(i.ts||0))}function uU(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((m,
|
|
105
|
+
`)){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(Zw(c.content,l),!l.length)continue;let u=i.timestamp?Date.parse(i.timestamp):null;for(let d of l)o.push({...d,summary:vo(d.command,d.description),ts:u})}return o.slice(-n)}function YA(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(...uU(i,r.get(a)||[]));return s.sort((a,i)=>(a.ts||0)-(i.ts||0))}function uU(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((m,h)=>h>=s&&(m.ts||0)>(l.ts||0)),d=u===-1?r.length:u,p=r.slice(s,d);if(s=d,!p.length)continue;let w=p.map(m=>({...m,n:i(m)}));o.push({id:`batch-${l.ts}-${l.box}`,anchorTs:l.ts,anchorBox:l.box,agent:l.agent,boxRole:l.boxRole,commands:w,ts:Math.max(...w.map(m=>m.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 Qw,ti=K(()=>{Mn();zA();Qw=new Set(["Bash"])});import XA from"node:fs";import tg from"node:fs/promises";import eg from"node:path";import dU from"node:os";async function ZA(e){try{return await tg.realpath(e)}catch{return e}}function fU(e=pU){let t=[],n=r=>{let o;try{o=XA.readdirSync(r,{withFileTypes:!0})}catch{return}for(let s of o){let a=eg.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:XA.statSync(a).mtimeMs})}catch{}}}};return n(e),t.sort((r,o)=>o.mtimeMs-r.mtimeMs)}async function hU(e,t=1048576){let n;try{n=await tg.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(`
|
|
106
106
|
`);if(i!==-1)return o.slice(0,i);if(s+=a,o.length>=t)break}return o}finally{await n.close()}}async function mU(e){let t=await hU(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 Ns(e,t){if(!e&&!t)return null;let n=fU();if(t){let o=n.find(s=>s.id===t);return o||null}let r=await ZA(e);for(let o of n){let s=await mU(o.file);if(s&&(s===e||await ZA(s)===r))return o}return null}async function QA(e,t,{limit:n=80,maxBytes:r=524288}={}){let o=await Ns(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(`
|
|
107
|
-
`)){let w=p.trim();if(!w||w[0]!=="{")continue;let m;try{m=JSON.parse(w)}catch{continue}if((m.type==="turn_context"&&m.payload?.model||m.type==="session_meta"&&m.payload?.model)&&(i=m.payload.model),m.type==="event_msg"){let b=m.payload?.type;b==="task_started"?(l=!0,u=!1,d=m.payload?.turn_id||null):b==="task_complete"&&l&&(l=!1,!u&&m.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:Ps,sourceId:m.payload?.turn_id||d||void 0,ts:m.timestamp?Date.parse(m.timestamp):null,model:i}));continue}if(m.type!=="response_item")continue;let
|
|
107
|
+
`)){let w=p.trim();if(!w||w[0]!=="{")continue;let m;try{m=JSON.parse(w)}catch{continue}if((m.type==="turn_context"&&m.payload?.model||m.type==="session_meta"&&m.payload?.model)&&(i=m.payload.model),m.type==="event_msg"){let b=m.payload?.type;b==="task_started"?(l=!0,u=!1,d=m.payload?.turn_id||null):b==="task_complete"&&l&&(l=!1,!u&&m.payload?.last_agent_message==null&&a.push({role:"assistant",failed:!0,text:Ps,sourceId:m.payload?.turn_id||d||void 0,ts:m.timestamp?Date.parse(m.timestamp):null,model:i}));continue}if(m.type!=="response_item")continue;let h=m.payload;if(!h)continue;if((h.type==="function_call"||h.type==="custom_tool_call")&&h.name){u=!0,ng.has(h.name)||c.push(h.name);continue}if(h.type!=="message"||h.role!=="assistant")continue;u=!0;let g=gU(h.content),y=c.length?c.slice():null;c=[],!(!g&&!y)&&a.push({role:"assistant",text:g,tools:y||void 0,ts:m.timestamp?Date.parse(m.timestamp):null,model:i})}if(i)for(let p of a)p.model||(p.model=i);return a.slice(-n)}function yU(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 bU(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+=`
|
|
108
108
|
`;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 kU(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=bU(i.slice(c.index+c[0].length).trimStart());l&&l.trim()&&o.push(l.trim())}),o}async function eT(e,t,{limit:n=400,maxBytes:r=524288}={}){let o=await Ns(e,t);if(!o)return[];let s;try{s=await Jt(o.file,r)}catch{return[]}let a=[];for(let i of s.split(`
|
|
109
109
|
`)){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"&&dl.has(u.name)){let w;try{w=JSON.parse(u.arguments||"{}")}catch{continue}let m=yU(w);m&&(d=[m])}else u.type==="custom_tool_call"&&u.name==="exec"&&(d=kU(u.input));if(!d.length)continue;let p=u.call_id||u.id||null;d.forEach((w,m)=>{a.push({id:p?m?`${p}:${m}`:p:null,tool:u.name,command:w,description:"",summary:vo(w),ts:l.timestamp?Date.parse(l.timestamp):null})})}return a.slice(-n)}async function tT(e,t){let n=await Ns(e,t);if(!n)return null;try{return Math.round((await tg.stat(n.file)).mtimeMs)}catch{return n.mtimeMs||null}}var pU,wU,gU,dl,ng,Ps,Ds=K(()=>{Mn();ti();pU=process.env.BOSTRAT_CODEX_SESSIONS||eg.join(process.env.CODEX_HOME||eg.join(dU.homedir(),".codex"),"sessions");wU=new Set(["output_text","text"]),gU=e=>typeof e=="string"?e.trim():Array.isArray(e)?e.filter(t=>t&&typeof t.text=="string"&&wU.has(t.type)).map(t=>t.text).join(`
|
|
110
110
|
`).trim():"";dl=new Set(["exec_command","shell","exec"]),ng=new Set(["wait","write_stdin"]),Ps="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 pl({error:e=null,status:t=null,text:n=""}={}){let r=String(e||"").trim().toLowerCase();if(r&&nT.has(r))return nT.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 rT(e){if(!e||e.role!=="assistant")return null;if(e.apiError){let t=e.apiError;return{cls:t.cls||pl({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===Ps?"other":pl({text:t}),code:null,status:null,requestId:null}}return null}function oT(e,{codexFailedText:t=null}={}){let n=String(e?.text||"").trim();return n?e?.model==="<synthetic>"?/^No response requested\.$/.test(n)?null:{cls:pl({text:n}),code:null,status:xU(n),requestId:null,text:n}:t&&n===t?{cls:"other",code:null,status:null,requestId:null,text:n}:null:null}function xU(e){let t=/^API Error:\s*(\d{3})\b/.exec(e);return t?Number(t[1]):null}var Tte,nT,bp=K(()=>{Ds();Tte=Object.freeze(["entitlement","auth","rate_limit","overloaded","server","other"]),nT=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 _U(e){return SU.test(String(e||"").trimStart())}function iT(e){let t=String(e||"");if(!_U(t.trimStart()))return null;let n=t.replace(vU,"").trim(),r=IU(n),o=[];for(let u of TU){let d=u.from.map(p=>ni(r.get(p))).find(p=>p&&!sT(p));d&&o.push({h:u.h,text:fl(d,AU)})}let s=ni(r.get("Current Work"))||ni(r.get("Primary Request and Intent"))||RU(n),a=xp(s),i=fl(kp(sg(a[0]||"")),EU)||"Context resumed from summary",c=[],l=a.slice(1).join(" ").trim();l&&c.push(fl(kp(sg(l)),og));for(let u of["Pending Tasks","Optional Next Step"]){let d=xp(ni(r.get(u)))[0]||"";if(!(!d||sT(d))){c.push(fl(`Left to do: ${kp(sg(d))}`,og));break}}if(!c.length){let u=xp(ni(r.get("Problem Solving"))||"")[0];u&&c.push(fl(kp(u),og))}return{kind:"resume-summary",title:i,bullets:c.slice(0,2),sections:o,rawChars:t.length}}function IU(e){let t=new Map,n=[];rg.lastIndex=0;for(let r=rg.exec(e);r;r=rg.exec(e))n.push({name:$U(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 $U(e){return aT.find(n=>n.toLowerCase()===e.toLowerCase())||e}function ni(e){return e?String(e).replace(/```[\s\S]*?(?:```|$)/g," ").split(`
|
|
@@ -113,7 +113,7 @@ exit 0
|
|
|
113
113
|
`).map(o=>o.replace(/\s+$/,"")),n=-1;for(let o=t.length-1;o>=0;o--)if(t[o]){(uT.test(t[o])||MU.test(t[o]))&&!hl.test(t[o])?n=o:hl.test(t[o])&&/\[Pasted Content \d+ chars\]/.test(t[o])&&(n=o+1);break}if(n<=0)return null;for(;n-1>0&&t[n-1]&&uT.test(t[n-1])&&!hl.test(t[n-1]);)n--;let r=[];for(let o=n-1;o>=0&&n-o<=60;o--){let s=t[o],a=s.match(hl);if(a){r.unshift(a[1]);let i=r.map(c=>c.trim()).filter(Boolean);return i.length?i.join(" "):null}if(CU.test(s))return null;r.unshift(s)}return null}function DU(e,t){let n=String(t||"");if(!/\[Pasted Content \d+ chars\]/.test(n))return!1;let r=0,o=Oe(n.replace(PU,(i,c)=>(r+=Number(c)," "))),s=[...String(e||"")].length;return o&&!Oe(e).includes(o)?!1:r+o.length<=s+Math.max(4,Math.round(s*.05))}function LU(e,t){let n=String(t||"");if(!/\[Pasted text #\d+(?: \+\d+ lines)?\]/.test(n))return!1;let r=Oe(n.replace(BU," "));return r?Oe(e).includes(r):!0}function Sp(e,t,n){return e==="codex"?DU(t,n):e==="claude"?LU(t,n):!1}function Oe(e){return String(e||"").replace(/\s+/g," ").trim()}function dT(e,t,{slackMs:n=2e4}={}){let r=Oe(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&&Oe(a.text).includes(r));return s>=0&&s<o.length-1}function pT(e,t,n,{busy:r=!1}={}){let o=Bs(e,n);return o&&vp(t,o)||o&&Sp(e,t,o)?"stuck":r&&e!=="codex"?"submitted":o&&e==="codex"&&!r&&!jU(t,n)?"unknown":o?"submitted":"unknown"}function jU(e,t){let n=Oe(e).slice(0,60);if(n.length<12)return!1;let r=String(t).replace(/\r/g,"").split(`
|
|
114
114
|
`),o=-1;for(let a=r.length-1;a>=0;a--)if(hl.test(r[a])){o=a;break}return o<=0?!1:Oe(r.slice(0,o).map(a=>a.replace(/^\s*›[ ]?/,"")).join(" ")).includes(n)}function vp(e,t){let n=Oe(e),r=Oe(t).replace(/^…\s*/,"").replace(/\s*…$/,"");return!n||!r||r.length<Math.min(n.length,12)?!1:n===r||n.includes(r)}var lT,OU,hl,uT,MU,CU,PU,BU,ri=K(()=>{lT=/^\s*─{8,}(?: [^─\n]+ ─+)?\s*$/,OU=/^❯[ ]?(.*)$/,hl=/^\s*›[ ]?(.*)$/,uT=/\S+ · \S/,MU=/^\s*(?:\? for shortcuts|tab to queue message)\b/,CU=/^\s*(?:[•■◦✶✻⚠]|╭|╰|│)/;PU=/\[Pasted Content (\d+) chars\](?: #\d+)?/g;BU=/\[Pasted text #\d+(?: \+\d+ lines)?\]/g});function mT(e){return ag.has(String(e||"").replace(/^\//,"").toLowerCase())}function wl(e){let t=String(e||"").trim();if(!t)return null;let n=iT(t);if(n)return n;let r=t.match(FU);if(r)return{kind:"skill",name:r[1].split("/").filter(Boolean).pop()||"skill"};let o=t.match(UU);if(o)return{kind:"skill",name:o[1]};let s=t.match(HU);if(s)return{kind:"skill",name:s[1].toLowerCase()};let a=t.match(WU);if(a){let c=a[1].toLowerCase();return ag.has(c)?{kind:"suppress"}:{kind:"command",command:`/${c}`}}let i=t.match(QU);if(i&&ag.has(i[1].toLowerCase()))return{kind:"suppress"};if(qU.test(t))return{kind:"suppress"};if(KU.test(t))return{kind:"suppress"};if(GU.test(t))return{kind:"suppress"};if(VU.test(t)){let c=u=>s4(t.match(u)?.[1].trim()||"")||null,l=c(ZU);return{kind:"task",summary:c(zU)||"",taskId:c(JU),toolUseId:c(YU),status:c(XU)?.toLowerCase()||null,resultHead:l?l.length>fT?`${l.slice(0,fT).trimEnd()}\u2026`:l:null}}return null}function wT(e){let t=wl(e?.text);return t||(e?.injected?{kind:"skill",name:e.injected.skill||"skill"}:null)}function gT(e){let t=String(e||""),n=t.match(e4);if(n)return{kind:"shell-input",command:n[1].trim()};let r=t.match(t4);return r?{kind:"shell-output",stdout:hT(r[1]),stderr:hT(r[2])}:null}function oi(e){let t=String(e??"");return t.includes("<pasted_content id=")?t.replace(r4,"$2").trim():t}function Ap(e,t){let n=Oe(e);if(n.length<o4)return null;let r=[];for(let i of t||[]){let c=Oe(i);c&&r.push(c)}if(r.some(i=>i===n))return null;let o=i=>({received:n.length,sent:i,head:n.slice(0,80)}),s=i=>r.find(c=>c.length>i.length&&c.endsWith(i))??null;if(ml.endsWith(n))return o(null);if(n.endsWith(ml)){let i=n.slice(0,-ml.length).trim(),c=i.match(/^(.*?)\s*\(Read \S{1,300}$/);if(c){let l=c[1].trim();if(!l)return o(null);if(r.some(d=>d===l))return null;let u=s(l);return u?o(u.length+(n.length-l.length)):null}return/^\S*$/.test(i)||/^Read \S{1,300}$/.test(i)?o(null):null}let a=s(n);return a?o(a.length):null}function s4(e){return e.replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/&/g,"&")}function ig(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==="cut-delivery"?`Only part of a Bostrat-sent message reached the agent: \u2026${e.head||""}`:e?.kind==="resume-summary"?e.title?`Context resumed from summary: ${e.title}`:"Context resumed from summary":""}function yT(e){return e?.kind==="skill"?"skill-run":e?.kind==="task"?"task-done":e?.kind==="resume-summary"?"context-resumed":e?.kind==="cut-delivery"?"delivery-cut":"command-run"}var FU,UU,HU,WU,qU,GU,KU,VU,zU,JU,YU,XU,ZU,fT,ag,QU,e4,t4,n4,hT,r4,ml,o4,si=K(()=>{cT();ri();FU=/^Base directory for this skill:\s*(\S+)/,UU=/^Run the "([^"]+)" workflow\./,HU=/^#\s*\/([a-z0-9:_-]+)\s*[—–:-]/i,WU=/<command-name>\s*\/?([a-z0-9:_-]+)\s*<\/command-name>/i,qU=/^<local-command-(?:stdout|caveat)>/i,GU=/^\[Image: original \d+x\d+, displayed at \d+x\d+\.\s*Multiply coordinates by [\d.]+ to map to original image\.\]$/,KU=/^Continue from where you left off\.$/,VU=/^<task-notification>/i,zU=/<summary>([\s\S]*?)<\/summary>/i,JU=/<task-id>([\s\S]*?)<\/task-id>/i,YU=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i,XU=/<status>([\s\S]*?)<\/status>/i,ZU=/<result>([\s\S]*?)(?:<\/result>|$)/i,fT=600,ag=new Set(["model","clear","compact","login","exit","quit"]);QU=/^\/([a-z0-9:_-]+)$/i;e4=/^\s*<bash-input>([\s\S]*?)<\/bash-input>\s*$/i,t4=/^\s*<bash-stdout>([\s\S]*?)<\/bash-stdout>\s*(?:<bash-stderr>([\s\S]*?)<\/bash-stderr>)?\s*$/i,n4=/\x1b\[[0-9;?]*[ -/]*[@-~]/g,hT=e=>String(e||"").replace(n4,"").replace(/^\n+/,"").replace(/\s+$/,"");r4=/<pasted_content id="([^"]*)">\n?([\s\S]*?)\n?<\/pasted_content(?: id="\1")?>/g;ml="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.)",o4=32});function a4(e,t){return!e||!t?null:On(e,t)}function bT(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(`
|
|
115
115
|
`).trim():""}function i4(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 c4(e){return Array.isArray(e)&&e.length>0&&e.every(t=>t&&t.type==="tool_result")}function cg(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 kT(e,t){if(!e.uuid)return null;let n=cg(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 lg(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(`
|
|
116
|
-
`)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type==="attachment"){let y=l.attachment;y?.type==="queued_command"&&y.commandMode==="task-notification"&&typeof y.prompt=="string"&&y.prompt.trim()&&o.push({role:"user",text:y.prompt.trim(),ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let u=l.message;if(!u)continue;let d=u.role||l.type;if(d!=="user"&&d!=="assistant"||d==="assistant"&&u.model==="<synthetic>"&&!l.isApiErrorMessage)continue;if(d==="assistant"&&Array.isArray(u.content))for(let y of u.content){let b=y?.type==="tool_use"?y.input?.file_path||y.input?.path:null;typeof b=="string"&&l4.test(b)&&s.set(y.id,b.split("/").pop()),y?.type==="tool_use"&&y.name==="Skill"&&y.id&&a.set(y.id,String(y.input?.skill||"").trim().replace(/^\//,"")||null)}if(c4(u.content)){let y=kT(l,s);y&&o.push({role:"assistant",text:"",images:y,ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let p=d==="user"?oi(bT(u.content)):bT(u.content),w=d==="assistant"?i4(u.content):null,m=d==="user"?kT(l,s):null;if(!p&&!w&&!m)continue;let
|
|
116
|
+
`)){let c=i.trim();if(!c||c[0]!=="{")continue;let l;try{l=JSON.parse(c)}catch{continue}if(l.type==="attachment"){let y=l.attachment;y?.type==="queued_command"&&y.commandMode==="task-notification"&&typeof y.prompt=="string"&&y.prompt.trim()&&o.push({role:"user",text:y.prompt.trim(),ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let u=l.message;if(!u)continue;let d=u.role||l.type;if(d!=="user"&&d!=="assistant"||d==="assistant"&&u.model==="<synthetic>"&&!l.isApiErrorMessage)continue;if(d==="assistant"&&Array.isArray(u.content))for(let y of u.content){let b=y?.type==="tool_use"?y.input?.file_path||y.input?.path:null;typeof b=="string"&&l4.test(b)&&s.set(y.id,b.split("/").pop()),y?.type==="tool_use"&&y.name==="Skill"&&y.id&&a.set(y.id,String(y.input?.skill||"").trim().replace(/^\//,"")||null)}if(c4(u.content)){let y=kT(l,s);y&&o.push({role:"assistant",text:"",images:y,ts:l.timestamp?Date.parse(l.timestamp):null,model:null});continue}let p=d==="user"?oi(bT(u.content)):bT(u.content),w=d==="assistant"?i4(u.content):null,m=d==="user"?kT(l,s):null;if(!p&&!w&&!m)continue;let h=d==="user"&&l.isMeta&&typeof l.sourceToolUseID=="string"&&l.sourceToolUseID?{toolUseId:l.sourceToolUseID,skill:a.get(l.sourceToolUseID)??null}:null,g=d==="assistant"&&l.isApiErrorMessage?{code:typeof l.error=="string"?l.error:null,status:Number(l.apiErrorStatus)||null,requestId:l.requestId||null,cls:pl({error:l.error,status:l.apiErrorStatus,text:p})}:null;o.push({role:d,text:p,tools:w||void 0,images:m||void 0,injected:h||void 0,ts:l.timestamp?Date.parse(l.timestamp):null,model:u.model||null,apiError:g||void 0})}return o.slice(-n)}async function xT(e,t,{turns:n=16}={}){let r=a4(e,t);if(!r)return"";let o=await lg(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}:** ${u4(s.text||c,700)} ${i}`.trim()}).join(`
|
|
117
117
|
|
|
118
118
|
`):""}var l4,u4,Tp=K(()=>{bp();Mn();si();l4=/\.(png|jpe?g|gif|webp|bmp|svg|tiff?|avif|heic|heif|ico)$/i;u4=(e,t)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e});function gl(e,t){if(e!=="claude")return!1;let n=String(t||"");if(!dg.test(n)||yl(n))return!1;let r=n.replace(/\r/g,"").split(`
|
|
119
119
|
`).filter(o=>o.trim());return d4.test(r.slice(-6).join(`
|
|
@@ -138,7 +138,7 @@ exit 0
|
|
|
138
138
|
`);for(let o=r.length-1;o>=0;o--)if(r[o].includes(n))return r.slice(o+1).join(`
|
|
139
139
|
`);return e}function Us(e){let t=String(e||"").trim();return t?t.slice(0,32):null}function li(e,t){if(!e)return;let n=String(t||"").trim();n?pg.set(e,n):pg.delete(e)}function z4(e){return e&&pg.get(e)||null}function cn(e,t){return kl(t,z4(e))}function NT(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 PT(e,t,n,{bailOnDialog:r=!1,launchEcho:o=null,onReady:s}={}){let a=Date.now()+n,i=0,c=null;await Cs(e).catch(()=>{});let l=0;for(;;){let u=kl(await Fe(e),o);if(gl(t,u)){if(l<2&&_p(e,{onDrive:!0})&&Ao(e,"login-issue")){l+=1,Ip(e),await ne({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"login-issue",attempt:l}).catch(()=>{}),await ot(e,"/login",{enter:!0,submitDelayMs:600,kind:"login-issue"});let d=Date.now()+8e3,p=!1;for(;Date.now()<d;)if(await Yt(js),ii(t,kl(await Fe(e),o))){p=!0;break}if(p&&r)return ne({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 ne({flow:"agent-ready",phase:"blocked",reason:"not-logged-in",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:d}).catch(()=>{}),new Error(d)}await Yt(js);continue}if((t==="claude"||t==="codex")&&i<3){let d=t==="codex"?Or(u):u;if(Ls(t,d)){if(!Ao(e,"login-enter")){await Yt(js);continue}i+=1,$p(e,d),await ne({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"login-enter",attempt:i}).catch(()=>{}),await ot(e,"",{enter:!0,kind:"login-enter"}),await Yt(Fs);continue}}if(V4(t,u))return await s?.(),await Yt(Fs),"up";if(lt[t]?.up&&!lt[t].up.test(u))if(await sr(e)){if(c??=Date.now(),Date.now()-c>=sl()){let d=NT(t);throw ne({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"&&j4.test(u)&&!lt.claude.up.test(u))return ne({flow:"agent-ready",phase:"dialog",sessionName:e,agent:t,dialog:"resume-confirm"}).catch(()=>{}),"dialog-bail";if(t==="codex"&&L4.test(u)&&!lt.codex.up.test(u)&&i<3){if(!Ao(e,"codex-trust")){await Yt(js);continue}i+=1,await ne({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,gate:"codex-trust",attempt:i}).catch(()=>{}),await ot(e,"",{enter:!0,kind:"codex-trust-accept"}),await Yt(Fs);continue}if(t==="cursor"&&B4.test(u)&&!lt.cursor.up.test(u)&&i<3){if(!Ao(e,"cursor-trust")){await Yt(js);continue}i+=1,await ne({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i}).catch(()=>{}),await ot(e,"a",{enter:!1,kind:"cursor-trust-accept"}),await Yt(Fs);continue}if(t==="codex"&&i<3){let d=U4(u);if(d){if(!Ao(e,`codex-update:${d.from}->${d.to}`)){await Yt(js);continue}i+=1,await ne({flow:"agent-ready",phase:"gate-accept",sessionName:e,agent:t,attempt:i,update:`${d.from} -> ${d.to}`}).catch(()=>{}),await ot(e,"3",{enter:!1,kind:"codex-update-skip"}),fw({sessionName:e,from:d.from,to:d.to}),await Yt(Fs);continue}}if(Date.now()>a){if(ii(t,u)){let d=`${t} is blocked on an interactive prompt`;throw t==="codex"?d=lt.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"&<.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"&<.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"&<.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`),ne({flow:"agent-ready",phase:"blocked",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,error:d}).catch(()=>{}),new Error(d)}if(await sr(e)){let d=NT(t);throw ne({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.`),ne({flow:"agent-ready",phase:"timeout",sessionName:e,agent:t,timeoutMs:n,gateAccepts:i,paneBlocked:!!lt[t]?.block?.test(u),paneUp:!!lt[t]?.up?.test(u),paneBusy:!!lt[t]?.busy?.test(BT(lt[t],u))}).catch(()=>{}),await Yt(Fs),"timeout"}await Yt(js)}}function vl({agent:e,agentCmd:t}={}){let n=t?ko(t):ko(e||"");return{label:n,realClaude:t?Ms(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 jT({agent:e,agentCmd:t}={}){let{realClaude:n,realCodex:r,realCursor:o}=vl({agent:e,agentCmd:t});return n||r||o||process.env.BOSTRAT_FAKE_POLL_READY==="1"}function Hs({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o,onBlocked:s}={}){let{realCodex:a,realCursor:i}=vl({agent:n,agentCmd:r});return!t||!a&&!i?null:Mr({cwd:e,sessionName:t,agent:n,agentCmd:r,onReady:o}).then(()=>{},c=>{try{J4(c,{onBlocked:s,agent:n,sessionName:t})}catch{}})}function J4(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 Mr({cwd:e,sessionId:t,sessionName:n,agent:r,agentCmd:o,timeoutMs:s=C4(),bailOnDialog:a=!1,launchEcho:i=null,onReady:c}={}){let{label:l,realClaude:u,realCodex:d,realCursor:p}=vl({agent:r,agentCmd:o});if(u&&e&&await fo(e),d&&e&&await Ba(e),p&&e&&await ja(e),(u||d||p)&&n)try{return await PT(n,l,s,{bailOnDialog:a,launchEcho:i,onReady:c})}finally{d&&pw(n)}let w=lt[r]?r:lt[l]?l:null;return process.env.BOSTRAT_FAKE_POLL_READY==="1"&&n&&w?await PT(n,w,s,{launchEcho:i}):(await Yt(Fs),"settle")}var C4,js,Fs,N4,P4,lt,B4,L4,j4,F4,H4,Cp,W4,DT,G4,K4,pg,Ws=K(()=>{kt();Mc();Pd();Ud();As();Mp();$n();bl();C4=()=>Number(process.env.BOSTRAT_AGENT_READY_TIMEOUT_MS)||9e4,js=Number(process.env.BOSTRAT_AGENT_READY_POLL_MS)||500,Fs=Number(process.env.BOSTRAT_AGENT_READY_SETTLE_MS)||800,N4=/^\s{0,4}[^\s›•■◦╭╰│]\S*(?: \S+){0,3} · \S/,P4=/^\s*tab to queue message\b/;lt={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:D4},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/}},B4=/Trust this workspace|\[a\]\s*Trust/,L4=/Do you trust the contents of this directory\?[\s\S]*›\s*1\. Yes, continue[\s\S]*Press enter to continue/,j4=/Resume from summary/i,F4=/Update available!\s*([\d][\w.-]*)\s*->\s*([\d][\w.-]*)/;H4=()=>Number(process.env.BOSTRAT_GATE_RESEND_MS)||3e3,Cp=new Map;W4=68,DT=/^\s*[─━]{10,}(?: [^─━\n]+ [─━]+)?\s*$/;G4=/\bWaiting for (\d+)\b([^\n]*?)\s+to finish\b|\/workflows to (?:stop|monitor)\b/,K4=15;pg=new Map});function Z4(e){return!(typeof e!="string"||!e||!e.includes(`
|
|
140
140
|
`)&&/^\/\S/.test(e))}function e2(e){return typeof e!="string"||!e?!1:e.includes(`
|
|
141
|
-
`)?!0:Buffer.byteLength(e,"utf8")>=Q4}function ar(e,t){return e==="codex"?{enter:!0,submitDelayMs:Y4,...Z4(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:X4,...e2(t)?{paste:!0}:{}}:{enter:!0}}var Y4,X4,Q4,Al=K(()=>{Y4=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),X4=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})();Q4=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});async function Tl({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=(L,$,C={})=>(a&&typeof a=="object"&&Object.assign(a,{verdict:L,retries:C.retries??0,ms:(i.now||Date.now)()-c,sawUp:!!C.sawUp,reason:C.reason??null}),$);if(!t2.has(t))return l("skipped",!0);let u=i.waitForUp??jT({agent:t,agentCmd:n}),d=i.capture||(L=>Fe(L,{lines:rt})),p=i.pressEnter||(L=>tt(L,["Enter"],{kind:"submit-retry"})),w=i.sleep||s2,m=i.now||Date.now,f=i.log||(L=>ne(L).catch(()=>{})),g=i.maxMs??o2(),y=m()+g,b={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},x=0,v=0,S=0,E=!1,P=null;for(await w(ui[0]);;){let L=await d(e).catch(()=>""),$=To(t,L),C=ci(t,L),U=pT(t,r,L,{busy:C});if(U==="submitted")return l("submitted",!0,{retries:x,sawUp:!0});if(u&&(!$||U==="stuck"&&C)){if(m()>=y)return U==="stuck"?(f({...b,phase:"submit-failed",reason:"stuck-at-deadline",retries:x}),l("failed",!1,{retries:x,sawUp:E,reason:"stuck-at-deadline"})):(f({...b,phase:"submit-unverified",reason:E?"cli-down":"cli-never-up",retries:x,waitedMs:g}),l("unverified",!0,{retries:x,sawUp:E,reason:E?"cli-down":"cli-never-up"}));await w(n2);continue}E=!0;let J=U==="stuck"?Oe(Bs(t,L)):null,_=J!==null&&J!==P&&J.length<Oe(r).length&&!J.includes("[Pasted ");if(P=J,U==="stuck"&&_&&m()<y){await w(ui[1]);continue}if(U==="stuck"){if(x>=r2)return f({...b,phase:"submit-failed",retries:x}),l("failed",!1,{retries:x,sawUp:!0,reason:"stuck"});x+=1,v=0,S=0,await p(e),f({...b,phase:"submit-retry",attempt:x}),await w(ui[0]);continue}if(v+=1,v>=ui.length||m()>=y)return l("assumed",!0,{retries:x,sawUp:!0});S+=1,await w(ui[Math.min(S,ui.length-1)])}}var t2,ui,n2,r2,o2,s2,mg=K(()=>{kt();Ws();ri();$n();t2=new Set(["claude","codex"]),ui=[250,450,700],n2=500,r2=2,o2=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},s2=e=>new Promise(t=>setTimeout(t,e))});function FT(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function Cr(e){let t=FT(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of a2){let o=0;for(let s of i2[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function UT(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))c2.has(r)&&(t+=o||0),l2.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function El(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 HT(e){let t=FT(e).trim();return t?d2.test(t)?!0:t.split(/\s+/).length<=u2:!1}var a2,i2,c2,l2,u2,d2,Np=K(()=>{a2=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],i2={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/,/\bwould it be (better|smarter|easier|safer)\b/,/\bhelp me (prep|prepare)\b/,/\bis (it|this|that) (even )?(a |an )?(safe|public|open[ -]?source|free|legal|allowed)\b/,/\bparity with\b/,/\b(entire|whole) [\w -]{1,40} or (just|only)\b/,/\b(does|do) [\w -]{1,40} (offer|provide|have) (the same|any|a|an|similar)\b/,/\b(chances|odds|likelihood|probability) (of|that|for|today|tonight|tomorrow|this)\b/,/\bwhat would it take\b/,/\b(is|are) (this|that|the|it|my|our) [\w -]{0,40}\bstill (running|going|alive|up|working|active|pending)\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/,/\bcan'?t seem to\b/,/\bi think\b.{1,60}\b(is|are)\b.{1,40}, not\b/,/\byou (aren'?t|are not|stopped) (giving|showing|sending|including)\b/,/\bleak(ed|ing|s)\b/],"feature-build":[/\bimplement/,/\bbuild(ing)?\b/,/\badd(ing)?\b/,/\bcreate\b/,/\bwire (it |them )?(up|in)\b/,/\bship(ping)?\b/,/\bintegrat/,/\bsupport for\b/,/\bfeature\b/,/\bendpoint\b/,/\badapter\b/,/\bprototype\b/,/\bupdate (the |this |that |my |our )?[\w-]+( [\w-]+){0,3} to\b/,/\bset up\b/,/\b(can|could) we (also |maybe )?(tag|allow for|support|enable)\b/,/\bnow needs to be\b/,/\b(tie|hook|connect) (this|it|that|them) (in)?to\b/,/\bmake (a|an) (entirely |brand |whole |completely )?new\b/,/\bseparate\b.{1,40}\bfrom (the )?(others|rest)\b/,/\bcodify (this|that|it|these|those)\b/,/\b(should|to) only (be|allow|show|accept|apply|use|include)\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/,/\bloop (to|that|which|for) (start |begin )?(check|watch|monitor|scan|sweep|poll|run)/],"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/,/\b(slides?|deck)\b/,/\btagline\b/,/\btitle (card|slide)\b/,/\b(make|leave|write) a note\b/,/\b(make|write|draft) (me |us )?(a|an|the) run ?book\b/,/\bhelp me (expand|elaborate|articulate|flesh (this |that |it )?out)\b/,/\boutline (what|how|the|a|an|your|our)\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/,/\b(cancel|kill|abort|stop) (the |all |those |these |any )?([\w-]+ ){0,2}(builds?|jobs?|runs?|deploys?|workflows?)\b/,/\brepo(sitory)? instead\b/,/\b(move|moved|store|stored|keep|kept|put|live)\b.{0,40}\b(in|to|into|over to) (a |the |its )?(other|different|new|separate|own|second)\s?repo(sitory)?\b/]};c2=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),l2=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);u2=12,d2=/^\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 KT(e){let t=El(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||p2.has(r)||n.push(r);return n}function f2(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(GT(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(GT(n,"assistant",o))}}return t}function GT(e,t,n){let r=Cr(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 _l(e){let t=f2(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=KT(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 Pp(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(KT(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,w=Math.log(1+(e.N-p+.5)/(p+.5));for(let[m,f]of d){let g=e.lengths[m],y=f+WT*(1-qT+qT*(g/(e.avgdl||1))),b=w*(f*(WT+1)/y);c.set(m,(c.get(m)||0)+b)}}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 WT,qT,p2,wg=K(()=>{Np();WT=1.5,qT=.75,p2=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 Dp from"node:fs/promises";import VT from"node:path";async function h2(e){let t=VT.join(e,".bostrat","events"),n;try{n=await Dp.readdir(t)}catch{return _l([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await Dp.readFile(VT.join(t,o),"utf8");for(let a of s.split(`
|
|
141
|
+
`)?!0:Buffer.byteLength(e,"utf8")>=Q4}function ar(e,t){return e==="codex"?{enter:!0,submitDelayMs:Y4,...Z4(t)?{paste:!0}:{}}:e==="claude"?{enter:!0,submitDelayMs:X4,...e2(t)?{paste:!0}:{}}:{enter:!0}}var Y4,X4,Q4,Al=K(()=>{Y4=(()=>{let e=Number(process.env.BOSTRAT_CODEX_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})(),X4=(()=>{let e=Number(process.env.BOSTRAT_CLAUDE_SUBMIT_SETTLE_MS??120);return Number.isFinite(e)&&e>=0?e:120})();Q4=(()=>{let e=Number(process.env.BOSTRAT_CODEX_PASTE_MIN_BYTES??512);return Number.isFinite(e)&&e>=0?e:512})()});async function Tl({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=(L,$,C={})=>(a&&typeof a=="object"&&Object.assign(a,{verdict:L,retries:C.retries??0,ms:(i.now||Date.now)()-c,sawUp:!!C.sawUp,reason:C.reason??null}),$);if(!t2.has(t))return l("skipped",!0);let u=i.waitForUp??jT({agent:t,agentCmd:n}),d=i.capture||(L=>Fe(L,{lines:rt})),p=i.pressEnter||(L=>tt(L,["Enter"],{kind:"submit-retry"})),w=i.sleep||s2,m=i.now||Date.now,h=i.log||(L=>ne(L).catch(()=>{})),g=i.maxMs??o2(),y=m()+g,b={flow:s,trackId:o,sessionName:e,agent:t,textHead:String(r).slice(0,120)},x=0,v=0,S=0,E=!1,P=null;for(await w(ui[0]);;){let L=await d(e).catch(()=>""),$=To(t,L),C=ci(t,L),U=pT(t,r,L,{busy:C});if(U==="submitted")return l("submitted",!0,{retries:x,sawUp:!0});if(u&&(!$||U==="stuck"&&C)){if(m()>=y)return U==="stuck"?(h({...b,phase:"submit-failed",reason:"stuck-at-deadline",retries:x}),l("failed",!1,{retries:x,sawUp:E,reason:"stuck-at-deadline"})):(h({...b,phase:"submit-unverified",reason:E?"cli-down":"cli-never-up",retries:x,waitedMs:g}),l("unverified",!0,{retries:x,sawUp:E,reason:E?"cli-down":"cli-never-up"}));await w(n2);continue}E=!0;let J=U==="stuck"?Oe(Bs(t,L)):null,_=J!==null&&J!==P&&J.length<Oe(r).length&&!J.includes("[Pasted ");if(P=J,U==="stuck"&&_&&m()<y){await w(ui[1]);continue}if(U==="stuck"){if(x>=r2)return h({...b,phase:"submit-failed",retries:x}),l("failed",!1,{retries:x,sawUp:!0,reason:"stuck"});x+=1,v=0,S=0,await p(e),h({...b,phase:"submit-retry",attempt:x}),await w(ui[0]);continue}if(v+=1,v>=ui.length||m()>=y)return l("assumed",!0,{retries:x,sawUp:!0});S+=1,await w(ui[Math.min(S,ui.length-1)])}}var t2,ui,n2,r2,o2,s2,mg=K(()=>{kt();Ws();ri();$n();t2=new Set(["claude","codex"]),ui=[250,450,700],n2=500,r2=2,o2=()=>{let e=Number(process.env.BOSTRAT_SUBMIT_VERIFY_MAX_MS);return Number.isFinite(e)&&e>0?e:3e4},s2=e=>new Promise(t=>setTimeout(t,e))});function FT(e){return String(e||"").replace(/[\u2018\u2019\u201A\u02BC\u0060\u00B4]/g,"'").replace(/[\u201C\u201D\u201E]/g,'"')}function Cr(e){let t=FT(e).toLowerCase();if(!t.trim())return null;let n=null;for(let r of a2){let o=0;for(let s of i2[r])s.test(t)&&o++;o>0&&(!n||o>n.score)&&(n={category:r,score:o})}return n}function UT(e){let t=0,n=0;for(let[r,o]of Object.entries(e||{}))c2.has(r)&&(t+=o||0),l2.has(r)&&(n+=o||0);return t>=5&&n===0?{category:"research",score:1}:n>=3?{category:"feature-build",score:1}:null}function El(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 HT(e){let t=FT(e).trim();return t?d2.test(t)?!0:t.split(/\s+/).length<=u2:!1}var a2,i2,c2,l2,u2,d2,Np=K(()=>{a2=["bug-fix","orchestration","design","ops-infra","docs-writing","research","feature-build"],i2={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/,/\bwould it be (better|smarter|easier|safer)\b/,/\bhelp me (prep|prepare)\b/,/\bis (it|this|that) (even )?(a |an )?(safe|public|open[ -]?source|free|legal|allowed)\b/,/\bparity with\b/,/\b(entire|whole) [\w -]{1,40} or (just|only)\b/,/\b(does|do) [\w -]{1,40} (offer|provide|have) (the same|any|a|an|similar)\b/,/\b(chances|odds|likelihood|probability) (of|that|for|today|tonight|tomorrow|this)\b/,/\bwhat would it take\b/,/\b(is|are) (this|that|the|it|my|our) [\w -]{0,40}\bstill (running|going|alive|up|working|active|pending)\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/,/\bcan'?t seem to\b/,/\bi think\b.{1,60}\b(is|are)\b.{1,40}, not\b/,/\byou (aren'?t|are not|stopped) (giving|showing|sending|including)\b/,/\bleak(ed|ing|s)\b/],"feature-build":[/\bimplement/,/\bbuild(ing)?\b/,/\badd(ing)?\b/,/\bcreate\b/,/\bwire (it |them )?(up|in)\b/,/\bship(ping)?\b/,/\bintegrat/,/\bsupport for\b/,/\bfeature\b/,/\bendpoint\b/,/\badapter\b/,/\bprototype\b/,/\bupdate (the |this |that |my |our )?[\w-]+( [\w-]+){0,3} to\b/,/\bset up\b/,/\b(can|could) we (also |maybe )?(tag|allow for|support|enable)\b/,/\bnow needs to be\b/,/\b(tie|hook|connect) (this|it|that|them) (in)?to\b/,/\bmake (a|an) (entirely |brand |whole |completely )?new\b/,/\bseparate\b.{1,40}\bfrom (the )?(others|rest)\b/,/\bcodify (this|that|it|these|those)\b/,/\b(should|to) only (be|allow|show|accept|apply|use|include)\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/,/\bloop (to|that|which|for) (start |begin )?(check|watch|monitor|scan|sweep|poll|run)/],"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/,/\b(slides?|deck)\b/,/\btagline\b/,/\btitle (card|slide)\b/,/\b(make|leave|write) a note\b/,/\b(make|write|draft) (me |us )?(a|an|the) run ?book\b/,/\bhelp me (expand|elaborate|articulate|flesh (this |that |it )?out)\b/,/\boutline (what|how|the|a|an|your|our)\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/,/\b(cancel|kill|abort|stop) (the |all |those |these |any )?([\w-]+ ){0,2}(builds?|jobs?|runs?|deploys?|workflows?)\b/,/\brepo(sitory)? instead\b/,/\b(move|moved|store|stored|keep|kept|put|live)\b.{0,40}\b(in|to|into|over to) (a |the |its )?(other|different|new|separate|own|second)\s?repo(sitory)?\b/]};c2=new Set(["Read","Grep","Glob","LS","WebSearch","WebFetch","NotebookRead"]),l2=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);u2=12,d2=/^\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 KT(e){let t=El(String(e||"")).toLowerCase(),n=[];for(let r of t.split(/[^a-z0-9]+/))r.length<2||p2.has(r)||n.push(r);return n}function f2(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(GT(n,"user",o))}else if(n.type==="turn.agent"){if(!o)continue;t.push(GT(n,"assistant",o))}}return t}function GT(e,t,n){let r=Cr(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 _l(e){let t=f2(e),n=new Map,r=new Array(t.length).fill(0),o=0;t.forEach((a,i)=>{let c=KT(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 Pp(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(KT(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,w=Math.log(1+(e.N-p+.5)/(p+.5));for(let[m,h]of d){let g=e.lengths[m],y=h+WT*(1-qT+qT*(g/(e.avgdl||1))),b=w*(h*(WT+1)/y);c.set(m,(c.get(m)||0)+b)}}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 WT,qT,p2,wg=K(()=>{Np();WT=1.5,qT=.75,p2=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 Dp from"node:fs/promises";import VT from"node:path";async function h2(e){let t=VT.join(e,".bostrat","events"),n;try{n=await Dp.readdir(t)}catch{return _l([])}let r=[];for(let o of n)if(o.endsWith(".ndjson"))try{let s=await Dp.readFile(VT.join(t,o),"utf8");for(let a of s.split(`
|
|
142
142
|
`))if(a.trim())try{r.push(JSON.parse(a))}catch{}}catch{}return _l(r)}function m2(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}
|
|
143
143
|
${o}`.trim()||t.slice(0,2e3)}function w2(e,t,{k:n=6,maxChars:r=4e3,exclude:o=null}={}){let s=Pp(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?["",`## ${zT}, 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(`
|
|
144
144
|
`):""}async function JT(e,t,n={}){let{k:r=6,maxChars:o=4e3,exclude:s=null}=n;try{let a=await Dp.readFile(t,"utf8");if(a.includes(zT))return{appended:!1,reason:"already-enriched"};let i=await h2(e);if(!i.N)return{appended:!1,reason:"empty-index"};let c=w2(i,m2(a),{k:r,maxChars:o,exclude:s});return c?(await Dp.appendFile(t,`
|
|
@@ -167,7 +167,7 @@ your turn. The operator sees the questions as an interactive card in their chat
|
|
|
167
167
|
They may instead reply in free text \u2014 treat that as the answer. Never use the block for rhetorical questions, progress updates, or
|
|
168
168
|
anything you can decide yourself; keep asking in prose for questions without
|
|
169
169
|
enumerable options.
|
|
170
|
-
`});function v2(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 nE(e,t,n){let r=xg(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 ir(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=(k,h)=>{h!=null&&(u.has(k)||u.set(k,[]),u.get(k).push(h))},p=(k,h)=>{let A=null;for(let R of[k,null])for(let q of u.get(R)||[])q>h&&(A==null||q<A)&&(A=q);return A},w=new Set,m=new Map,f=new Map,g=(k,h)=>{f.set(k,h),n.push(h)},y=k=>{let h=f.get(k);h&&(h.retired=!0)},b=new Map,x=new Map,v=/^Agent "([\s\S]+)" finished$/,S=new Map;for(let k of e||[]){if(k.type!=="tool.called"||k.source!=="transcript")continue;let h=String(k.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(h))for(let A of h.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let R=A[0].split("/").pop().toLowerCase();S.has(R)||S.set(R,[]),S.get(R).push(k.payload?.ts??k.ts)}}let E=3*6e4,P=20*6e4,L=(k,h)=>!!(k?.name&&S.get(String(k.name).toLowerCase()))?.some(R=>R>=h-E&&R<=h+P);for(let k of e||[])if(k.type==="turn.retracted"){o.add(`${k.boxId}|${k.payload?.saidTs}`);let h=Oe(k.payload?.text);h&&(s.has(k.boxId)||s.set(k.boxId,[]),s.get(k.boxId).push(h))}else if(k.type==="turn.user"&&k.source==="orchestrator"){let h=Oe(k.payload?.text);h&&(a.has(k.boxId)||a.set(k.boxId,new Set),a.get(k.boxId).add(h))}else if(k.type==="job.stalled"&&k.payload?.id)c.set(k.payload.id,{ts:ae(k),quietMs:Number(k.payload.quietMs)||null});else if(k.type==="job.stopped"&&k.payload?.id)l.has(k.payload.id)||l.set(k.payload.id,{status:"killed",summary:null,resultHead:null,ts:ae(k)});else if(k.type==="session.ready"){let h=k.payload?.source;h!=="compact"&&h!=="clear"&&d(k.boxId??null,ae(k))}else if(k.type==="handoff.done")d(k.boxId??k.payload?.from??null,ae(k));else if(k.type==="box.state.changed"&&k.payload?.change==="archived")d(null,ae(k));else if(k.type==="job.started"&&k.payload?.id)i.add(k.payload.id),(k.payload.kind||"agent")==="agent"&&k.payload.name&&w.add(k.payload.name);else if(k.type==="turn.user"&&k.payload?.note?.kind==="task"){let h=k.payload.note,A={status:h.status||null,summary:h.summary||null,resultHead:h.resultHead??null,ts:ae(k)};h.toolUseId&&l.set(h.toolUseId,A);let R=String(h.summary||"").match(v);R&&m.set(R[1],A)}let $=new Map,C=new Map,U=null,J=new Map,_=new Map,I=new Map,T=new Map,F=new Map,W=new Map,ce=new Map,z=new Map,Ke=new Map,Ie=new Map,X=new Map,re=new Map,Te=new Map,Le=new Map,ie=new Map,Pe=new Map,ve=(k,h)=>{k.arm.status=h;let A=k.line,R=A.arms.map(q=>q.status);A.status=R.includes("armed")?"armed":R.includes("offered")?"offered":R.includes("replaced")?"replaced":"cancelled"},ee=new Map,ge=[],Ve=new Set,ze=new Map,Ze=(k,h)=>{ze.delete(k);let A=n.indexOf(k);A>=0&&n.splice(A,1),h!=null&&(k.ts=h),n.push(k)},N=k=>{if(ge.push(k),!(k.box?Ve.has(k.box):Ve.size>0))return;let A=n.indexOf(k);A>=0&&n.splice(A,1),ze.set(k,"held")},le=k=>{if(!ge.length)return;let h=ae(k);for(let A of ge)A.status!=="open"||ze.get(A)==="superseded"||A.box&&A.box!==k.boxId||(A.ts??0)>h||Ze(A,h)},pe=k=>{if(!ge.length)return;let h=ae(k);for(let A of ge)ze.get(A)!=="held"||A.status!=="open"||A.box&&k.boxId&&A.box!==k.boxId||Ze(A,Math.max(A.ts??0,h))},$e=()=>{for(let[k,h]of[...ze])h==="held"&&Ze(k,null);ge.length=0,Qe.clear()},Qe=new Set,Je=k=>{for(let h of Qe){if(h.status!=="open"||h.box&&k&&h.box!==k)continue;h.status="superseded";let A=n.indexOf(h);A>=0&&n.splice(A,1),ze.set(h,"superseded"),J.delete(h.offerId)}Qe.clear()},tn=new Map,yt=new Map,nn=new Map,lo=new Map,Et=new Map,Xn=new Map,rn=new Map,ct=new Map,Gt=()=>{for(let k of ct.values())k.questions.length&&n.push(k);ct.clear()},nt=null,ys=new Map,bs=6e4,uo=new Map,po=(k,h)=>{let A=s.get(k);if(!A?.length)return!1;let R=Oe(h),q=a.get(k);return A.some(fe=>{if(!R.startsWith(fe))return!1;let Se=Oe(R.slice(fe.length));return!!Se&&!!q?.has(Se)})};for(let k of e||[]){let h=k.payload||{};switch(k.type){case"turn.user":{if(k.boxId){let R=ee.get(k.boxId);R?R.push(ae(k)):ee.set(k.boxId,[ae(k)])}if(k.source==="hook"){k.boxId&&Ve.add(k.boxId);break}if($e(),!String(h.text||"").trim()&&!h.images?.length&&!h.attachments?.length)break;{let R=gT(h.text);if(R){if(R.kind==="shell-input"){let q={id:k.id,kind:"shell",command:R.command,stdout:null,stderr:null,done:!1,ts:ae(k),box:k.boxId,agent:k.provider};n.push(q),ys.set(k.boxId,q)}else{let q=ys.get(k.boxId);q?(q.stdout=R.stdout||null,q.stderr=R.stderr||null,q.done=!0,ys.delete(k.boxId)):n.push({id:k.id,kind:"shell",command:null,stdout:R.stdout||null,stderr:R.stderr||null,done:!0,ts:ae(k),box:k.boxId,agent:k.provider})}break}}{let R=h.note||wl(h.text);if(R){if(R.kind==="task"){if(R.toolUseId&&i.has(R.toolUseId))break;let q=String(R.summary||"").match(v);if(!R.toolUseId&&q&&w.has(q[1]))break}if(R.kind==="command"&&mT(R.command))break;if(R.kind==="resume-summary"){n.push({id:k.id,kind:"resume-summary",title:R.title||"Context resumed from summary",bullets:R.bullets||[],sections:R.sections||[],rawChars:R.rawChars??null,ts:ae(k),box:k.boxId,agent:k.provider});break}R.kind!=="suppress"&&n.push({id:k.id,kind:"event",type:yT(R),name:R.name??null,command:R.command??null,summary:R.summary??null,status:R.status??null,...R.kind==="cut-delivery"?{received:R.received??null,sent:R.sent??null,head:R.head??null}:{},ts:ae(k),box:k.boxId,agent:k.provider});break}}if(o.has(`${k.boxId}|${ae(k)}`)||k.source==="transcript"&&po(k.boxId,h.text))break;let A=h.text;if(k.source==="transcript"){let R=oi(A);if(R!==A){if(a.get(k.boxId)?.has(Oe(R)))break;A=R}let q=Ap(A,a.get(k.boxId)??[]);if(q){n.push({id:k.id,kind:"event",type:"delivery-cut",received:q.received,sent:q.sent,head:q.head,ts:ae(k),box:k.boxId,agent:k.provider});break}}if(h.kind==="merge-notify"||h.kind==="ship-notify"){n.push({id:k.id,kind:"event",type:h.kind==="ship-notify"?"ship-notified":"merge-notified",text:h.text,ts:ae(k),box:k.boxId,agent:k.provider});break}if(h.kind==="item-launch"){n.push({id:k.id,kind:"event",type:"item-kickoff",text:h.text,itemId:(String(h.text||"").match(S2)||[null])[0]?.toUpperCase()??null,ts:ae(k),box:k.boxId,agent:k.provider});break}if(h.kind==="subtask-resume"){n.push({id:k.id,kind:"event",type:"subtask-finished",text:h.text,...h.detail&&typeof h.detail=="object"?h.detail:{},ts:ae(k),box:k.boxId,agent:k.provider});break}if(h.kind==="mock-picked"||h.kind==="ci-fix"||h.kind==="reconcile"||h.kind==="pr-go"||h.kind==="push-go"||h.kind==="spin-up-view"||h.kind==="prompt-answer"||h.kind==="followup-go"||h.kind==="login-greet"){h.kind==="prompt-answer"&&(nt=null);break}for(let R of J.values())R.status="stale";J.clear();for(let R of I.values())R.status="stale";I.clear();for(let R of Te.values())R.rows.some(q=>q.rowStatus==="sent")||(R.status="stale",Te.delete(R.offerId));nt&&nt.box===k.boxId&&(n.push(v2(nt)),nt=null),n.push({id:k.id,kind:"message",role:"user",text:A,ts:ae(k),box:k.boxId,agent:k.provider,boxRole:h.boxRole,...k.actor==="orchestrator"?{orchestration:h.kind||!0}:{},...h.sourceId?{sourceId:h.sourceId}:{},...h.attachments?.length?{attachments:h.attachments}:{},...h.images?.length?{images:h.images}:{}});break}case"blueprint.item.launched":{if(!h.itemId||!h.trackId)break;n.push({id:k.id,kind:"event",type:"item-launched",itemId:String(h.itemId),trackId:String(h.trackId),trackName:h.trackName??null,provider:h.provider??null,node:h.node??null,via:h.via==="voice"?"voice":"chat",ts:ae(k)});break}case"peer.message":{let A=h.from||{};n.push({id:k.id,kind:"event",type:"peer-message",text:h.text,from:A.trackName||A.boxId||A.name||null,fromTrackId:A.trackId||null,ts:ae(k),box:k.boxId,agent:k.provider});break}case"turn.agent":{if(h.model==="<synthetic>"&&/^No response requested\.$/.test(String(h.text||"").trim()))break;let A=oT(h,{codexFailedText:Ps});if(A){n.push({id:k.id,kind:"event",type:"provider-error",cls:A.cls,status:A.status??void 0,text:A.text,provider:k.provider,legacy:!0,at:ae(k),ts:ae(k),box:k.boxId,agent:k.provider});break}Gt();let R=(h.images||[]).filter(ht=>!L(ht,ae(k)));if(k.source==="hook"&&!String(h.text||"").trim()&&(pe(k),k.boxId&&Ve.delete(k.boxId)),!String(h.text||"").trim()&&!R.length)break;if(k.provider==="cursor"){let ht=`${k.boxId}|${h.text}`;if(r.has(ht))break;r.add(ht)}(!nt||nt.box===k.boxId)&&(nt=null);let q=k.provider==="codex"?(h.tools||[]).filter(ht=>!ng.has(ht)&&!dl.has(ht)):h.tools||[],fe=h.text,Se=null,We=gg(String(h.text||""));We&&(fe=We.text,Se={questions:We.questions}),n.push({id:k.id,kind:"message",role:"assistant",text:fe,ts:ae(k),box:k.boxId,agent:k.provider,boxRole:h.boxRole,...Se?{ask:Se}:{},...q.length?{tools:q}:{},...h.model?{model:h.model}:{},...h.sourceId?{sourceId:h.sourceId}:{},...R.length?{images:R}:{}}),le(k),Se&&(nt={id:k.id,groupId:yg(k.provider,h.sourceId||k.id,Se.questions),provider:k.provider,box:k.boxId,questions:Se.questions,ts:ae(k)});break}case"job.started":{if(!h.id)break;let A=ae(k),R=l.get(h.id);if(!R&&(h.kind||"agent")==="agent"&&h.name){let _r=m.get(h.name);_r&&_r.ts>=A&&(R=_r)}let q=R?null:c.get(h.id)||null,fe=R||q?null:p(k.boxId??null,A),Se={jobId:h.id,jobKind:h.kind||"agent",name:h.name||null,detail:h.detail||null,status:R?R.status==="killed"?"stopped":R.status&&R.status!=="completed"?"failed":"done":q?"stalled":fe!=null?"lost":"running",startedTs:A,finishedTs:R?.ts??q?.ts??fe??null,quietMs:q?.quietMs??null,summary:R?.summary??null,resultHead:R?.resultHead??null},We=uo.get(k.boxId),ht=We?.jobs[We.jobs.length-1]?.startedTs;if(We&&ht!=null&&A-ht<=bs)We.jobs.push(Se);else{let _r={id:k.id,kind:"job-dock",dockId:h.id,ts:A,box:k.boxId,agent:k.provider,jobs:[Se]};uo.set(k.boxId,_r),n.push(_r)}break}case"handoff.done":n.push(vt(k,"lead-handoff"));break;case"subtask.delegated":n.push({...vt(k,"subtask-delegated"),to:k.boxId,toAgent:k.provider});break;case"subtask.merged":n.push(vt(k,"subtask-merged"));break;case"pr.state.changed":{if(!h.change)break;if(h.change==="opened"){for(let R of J.values())R.status="stale";J.clear();for(let R of I.values())R.status="stale";I.clear()}let A=vt(k,`pr-${h.change}`);if(A.box=k.boxId??null,tE.has(h.change)&&h.number!=null){let R=nE($,C,h);if($.size>=2){for(let fe of C.values())for(let Se of fe)Se.grouped=!0;A.groupPrs=[...$.values()];let q=[A];for(let fe of $.keys())C.set(fe,q)}else{let q=C.get(R)??[];q.push(A),C.set(R,q)}}else if(h.change==="merged"||h.change==="closed"||h.change==="lost"){let R=xg(h),q=U&&!U.complete||$.size>=2;if($.has(R))$.delete(R),C.delete(R);else if(h.number!=null)for(let fe of[...$.keys()])fe.endsWith(`#${h.number}`)&&($.delete(fe),C.delete(fe));if(q&&h.number!=null){(!U||U.complete)&&(U={id:k.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:ae(k),ts:ae(k),box:k.boxId,agent:k.provider},n.push(U)),U.prs.push({number:h.number,url:h.url??null,title:h.title??null,repo:h.repo??null,branch:h.branch??null,change:h.change,ts:ae(k)}),U.remaining=[...$.values()],U.complete=$.size===0;break}}n.push(A);break}case"pr.offered":{if(!h.offerId)break;Je(k.boxId);for(let R of J.values())R.status="stale";J.clear();for(let R of I.values())R.status="stale";I.clear();let A={id:k.id,kind:"pr-offer",offerId:h.offerId,excerpt:h.excerpt||null,branch:h.branch||null,base:h.base||null,offered:Array.isArray(h.offered)&&h.offered.length?h.offered:null,toPr:h.toPr&&typeof h.toPr=="object"?{number:h.toPr.number??null}:null,available:Array.isArray(h.available)?h.available:null,defaults:Array.isArray(h.defaults)?h.defaults:null,prState:h.prState||null,openPr:h.openPr&&typeof h.openPr=="object"?h.openPr:null,repos:Array.isArray(h.repos)&&h.repos.length?h.repos:null,status:"open",source:k.source==="cli"||h.via==="cli"?"cli":"transcript",ts:ae(k),box:k.boxId,agent:k.provider};J.set(h.offerId,A),_.set(h.offerId,A),n.push(A),Qe.add(A),A.source==="cli"&&N(A);break}case"pr.offer.answered":{let A=_.get(h.offerId);A&&(A.status=h.action||"dismiss",A.actions=Array.isArray(h.actions)?h.actions:null,A.notify=h.notify===!0,h.existingPr&&typeof h.existingPr=="object"&&(A.existingPr={number:h.existingPr.number??null}),J.delete(h.offerId));break}case"pr.exists.offered":{if(!h.offerId)break;for(let R of I.values())R.status="stale";I.clear();let A={id:k.id,kind:"pr-exists-offer",offerId:h.offerId,srcOfferId:h.srcOfferId??null,branch:h.branch||null,base:h.base||null,pr:h.pr&&typeof h.pr=="object"?{number:h.pr.number??null,url:h.pr.url??null,title:h.pr.title??null}:null,actions:Array.isArray(h.actions)&&h.actions.length?h.actions:null,notify:h.notify===!0,status:"open",ts:ae(k),box:k.boxId,agent:k.provider};I.set(h.offerId,A),T.set(h.offerId,A),n.push(A);break}case"pr.exists.answered":{let A=T.get(h.offerId);A&&(A.status=h.choice||"dismiss",I.delete(h.offerId));break}case"box.state.changed":{let A=h.change==="model"?"model-change":h.change;if(!A||A==="cli-update"&&h.status!=="failed")break;let R=vt(k,A);if(A==="model-change"&&(R.to=h.model),A==="node-update"&&R.latest){let q=n.findIndex(fe=>fe.kind==="event"&&fe.type==="node-update"&&fe.latest===R.latest);if(q>=0){let fe=n[q];n[q]={...R,ts:fe.ts,at:fe.at,firstAt:fe.firstAt??fe.ts,updatedAt:R.ts};break}}n.push(R);break}case"track.transferred":case"track.recovered":n.push(vt(k,"track-moved"));break;case"view.state.changed":{if(h.change==="deleted"){y(`view:${h.viewId}`);break}if(h.change!=="created"||h.restarted)break;g(`view:${h.viewId}`,{id:k.id,kind:"view-card",viewId:h.viewId,name:h.name,slug:h.slug,port:h.port,origin:h.origin,ts:ae(k),box:k.boxId,agent:k.provider});break}case"deps.prepare":{if(h.status==="ready"&&h.cached)break;let A=h.batch||k.id,R=b.get(A);R||(R={id:k.id,kind:"event",type:"deps-prepare",batch:A,status:"preparing",dirs:[],at:ae(k),ts:ae(k),box:k.boxId},b.set(A,R),n.push(R));let q=h.dir||h.relDir||".",fe={dir:q,repo:h.repo??null,status:h.status==="started"?"preparing":h.status,...h.reason?{reason:h.reason}:{},...Array.isArray(h.tail)&&h.tail.length?{tail:h.tail}:{},...h.durationMs!=null?{durationMs:h.durationMs}:{},...h.sizeBytes!=null?{sizeBytes:h.sizeBytes}:{},...h.linked===!1?{linked:!1}:{},...h.cached?{cached:!0}:{}},Se=R.dirs.findIndex(We=>We.dir===q);Se>=0?R.dirs[Se]=fe:R.dirs.push(fe),R.status=R.dirs.some(We=>We.status==="preparing")?"preparing":R.dirs.some(We=>We.status==="failed")?"failed":"ready",R.updatedAt=ae(k);break}case"deps.setup":{let A=h.run||k.id,R=x.get(A);if(R||(R={id:k.id,kind:"event",type:"deps-setup",run:A,repo:h.repo??null,dir:h.dir||".",source:h.source||"bostrat-setup",command:h.command||null,status:"running",at:ae(k),ts:ae(k),box:k.boxId},x.set(A,R),n.push(R)),h.status==="output"){let q=Array.isArray(h.lines)?h.lines.filter(fe=>typeof fe=="string"&&fe.trim()):[];q.length&&(R.last=q[q.length-1].trim().slice(0,200))}else(h.status==="done"||h.status==="failed")&&(R.status=h.status,delete R.last,h.durationMs!=null&&(R.durationMs=h.durationMs),h.reason&&(R.reason=h.reason),Array.isArray(h.tail)&&h.tail.length&&(R.tail=h.tail));R.updatedAt=ae(k);break}case"view.spinup.failed":{n.push({id:k.id,kind:"view-spinup-failed",name:h.name||null,reason:h.reason||"no-view",ts:ae(k),box:k.boxId,agent:k.provider});break}case"mock.state.changed":{if(h.change==="picked"){n.push({id:k.id,kind:"mock-picked",mockId:h.mockId,name:h.name,group:h.group??null,version:h.version??null,siblings:h.siblings??[],ts:ae(k),box:k.boxId,agent:k.provider});break}if(h.change==="deleted"){y(`mock:${h.mockId}`);break}if(h.change!=="created")break;g(`mock:${h.mockId}`,{id:k.id,kind:"mock-card",mockId:h.mockId,name:h.name,group:h.group??null,ts:ae(k),box:k.boxId,agent:k.provider});break}case"flow.state.changed":{if(h.change==="deleted"){y(`flow:${h.flowId}`);break}if(h.change!=="created")break;g(`flow:${h.flowId}`,{id:k.id,kind:"flow-card",flowId:h.flowId,name:h.name,stepCount:h.stepCount??null,mockIds:h.mockIds??[],ts:ae(k),box:k.boxId,agent:k.provider});break}case"runbook.state.changed":{if(h.change==="deleted"){y(`runbook:${h.runbookId}`);break}if(h.change!=="created")break;g(`runbook:${h.runbookId}`,{id:k.id,kind:"runbook-card",runbookId:h.runbookId,name:h.name,ts:ae(k),box:k.boxId,agent:k.provider});break}case"ticket.linked":{n.push({id:k.id,kind:"ticket-card",provider:h.provider||"linear",key:h.key,url:h.url,title:h.title??null,linkSource:h.linkSource??null,ts:ae(k),box:k.boxId,agent:k.provider});break}case"box.fullscreen.detected":case"box.stuck.detected":{if(!h.offerId)break;for(let R of ce.values())R.box===(h.box||k.boxId)&&(R.status="stale",ce.delete(R.offerId));let A={id:k.id,kind:"fullscreen-offer",reason:k.type==="box.stuck.detected"?"stuck":"fullscreen",offerId:h.offerId,status:"open",ts:ae(k),box:h.box||k.boxId,agent:h.agent||k.provider,...k.type==="box.stuck.detected"?{escSends:h.escSends??null,kept:h.kept??0}:{}};ce.set(h.offerId,A),z.set(h.offerId,A),n.push(A);break}case"box.fullscreen.answered":case"box.stuck.answered":{let A=z.get(h.offerId);A&&(A.status=h.action==="restarted"?"restarted":h.action==="cleared"?"cleared":"dismiss",ce.delete(h.offerId));break}case"ticket.move.offered":{if(!h.offerId)break;for(let R of F.values())R.key===h.key&&(R.status="stale",F.delete(R.offerId));let A={id:k.id,kind:"ticket-offer",offerId:h.offerId,provider:h.provider||"linear",key:h.key,url:h.url??null,phase:h.phase??null,from:h.from??null,to:h.to?.name??null,prNumber:h.prNumber??null,status:"open",ts:ae(k),box:k.boxId,agent:k.provider};F.set(h.offerId,A),W.set(h.offerId,A),n.push(A);break}case"ticket.move.answered":{let A=W.get(h.offerId);A&&(A.status=h.action==="moved"?"moved":"dismiss",F.delete(h.offerId));break}case"ticket.state.changed":{for(let A of F.values())A.key===h.key&&A.to===h.to&&(A.status="stale",F.delete(A.offerId));if(h.mode==="offer")break;n.push(vt(k,"ticket-state"));break}case"ticket.commented":{n.push({id:k.id,kind:"ticket-comment",key:h.key,url:h.url??null,excerpt:h.excerpt??null,ts:ae(k),box:k.boxId,agent:k.provider});break}case"ticket.flow.changed":n.push(vt(k,"ticket-flow"));break;case"ticket.create.offered":{if(!h.proposalId)break;for(let R of Ke.values())R.status="stale";Ke.clear();let A={id:k.id,kind:"ticket-create-offer",proposalId:h.proposalId,provider:h.provider||"linear",epic:h.epic??null,issues:Array.isArray(h.issues)?h.issues:[],team:h.team??null,needsTeam:!!h.needsTeam,linkCurrentTrack:!!h.linkCurrentTrack,status:"open",ts:ae(k),box:k.boxId,agent:k.provider};Ke.set(h.proposalId,A),Ie.set(h.proposalId,A),n.push(A),N(A);break}case"ticket.create.answered":{let A=Ie.get(h.proposalId);A&&(A.status=h.action==="created"?"created":"dismiss",A.createdCount=h.createdCount??null,A.failedCount=h.failedCount??null,Ke.delete(h.proposalId));break}case"loop.create.offered":{if(!h.proposalId)break;for(let R of X.values())R.status="stale";X.clear();let A={id:k.id,kind:"loop-create-offer",proposalId:h.proposalId,name:h.name??"",schedule:h.schedule??"",prompt:h.prompt??"",expectation:h.expectation??null,notify:h.notify??"off",assignment:h.assignment??{provider:"claude"},repo:h.repo??null,nodeId:h.nodeId??null,nodeName:h.nodeName??null,status:"open",ts:ae(k),box:k.boxId,agent:k.provider};X.set(h.proposalId,A),re.set(h.proposalId,A),n.push(A),N(A);break}case"loop.create.answered":{let A=re.get(h.proposalId);A&&(A.status=h.action==="created"?"created":"dismiss",X.delete(h.proposalId));break}case"followup.armed":{if(!h.armId)break;let A=h.replaces?ie.get(h.replaces):null;A&&A.arm.status==="armed"&&ve(A,"replaced");let R={armId:h.armId,seq:Number.isInteger(h.seq)?h.seq:0,label:h.label??"",prompt:h.prompt??"",why:h.why??null,standing:h.standing==="never"?"never":"offerable",status:"armed"},q=h.groupId??null,fe=q?Pe.get(q):null;fe||(fe={id:k.id,kind:"followup-armed",groupId:q,armId:R.armId,trigger:h.trigger??"now",label:R.label,prompt:R.prompt,why:R.why,planWhy:h.planWhy??null,arms:[],status:"armed",ts:ae(k),box:k.boxId,agent:k.provider},q&&Pe.set(q,fe),fe.trigger!=="now"&&n.push(fe)),fe.arms.push(R),ie.set(h.armId,{arm:R,line:fe});break}case"followup.armed.cancelled":{let A=ie.get(h.armId);A&&A.arm.status==="armed"&&ve(A,"cancelled");break}case"followup.offered":{if(!h.offerId)break;for(let q of Te.values())q.trigger===h.trigger&&(q.status="stale",Te.delete(q.offerId));let A=Array.isArray(h.rows)?h.rows:[];for(let q of A){let fe=q.armId?ie.get(q.armId):null;fe&&fe.arm.status==="armed"&&ve(fe,"offered")}let R={id:k.id,kind:"followup-offer",offerId:h.offerId,trigger:h.trigger??"now",repo:h.repo??null,context:h.context&&typeof h.context=="object"?h.context:{},groupId:h.groupId??null,why:h.why??null,rows:A.map(q=>({followupId:q.followupId??null,armId:q.armId??null,label:q.label??"",prompt:q.prompt??null,promptPreview:q.promptPreview??null,promptHash:q.promptHash??null,origin:q.origin??"operator",why:q.why??null,groupId:q.groupId??null,seq:Number.isInteger(q.seq)?q.seq:0,standing:q.standing==="never"?"never":"offerable",promotable:q.armId?q.promotable!==!1:!1,promotableReason:q.promotableReason??null,rowStatus:"open",saved:null})),status:"open",answer:null,answers:[],ts:ae(k),box:k.boxId,agent:k.provider};Te.set(h.offerId,R),Le.set(h.offerId,R),n.push(R),R.trigger==="now"&&N(R);break}case"followup.arm.saved":{let A=Le.get(h.offerId);if(!A)break;let R=A.rows.find(q=>q.armId&&q.armId===h.armId);R&&(R.saved=h.followupId??null);break}case"followup.answered":{let A=Le.get(h.offerId);if(!A)break;let R=new Set;h.armId&&R.add(`arm:${h.armId}`),h.followupId&&R.add(`fu:${h.followupId}`);for(let Se of Array.isArray(h.armIds)?h.armIds:[])R.add(`arm:${Se}`);for(let Se of Array.isArray(h.followupIds)?h.followupIds:[])R.add(`fu:${Se}`);let q=h.action==="sent"?"sent":h.action==="removed"?"removed":"dismiss";for(let Se of A.rows){if(Se.rowStatus!=="open")continue;let We=Se.armId?`arm:${Se.armId}`:`fu:${Se.followupId}`;R.size&&!R.has(We)||(Se.rowStatus=q)}let fe={followupId:h.followupId??null,armId:h.armId??null,label:h.label??null,promoted:h.promoted??null,revived:h.revived===!0,action:q,batchId:h.batchId??null,edited:h.edited===!0,order:Number.isInteger(h.order)?h.order:null,reordered:h.reordered===!0};A.answers.push(fe),A.answer=fe,A.rows.some(Se=>Se.rowStatus==="open")?A.status="open":(A.status=A.rows.some(Se=>Se.rowStatus==="sent")?"sent":A.rows.some(Se=>Se.rowStatus==="removed")?"removed":"dismiss",Te.delete(h.offerId));break}case"followup.create.offered":{if(!h.proposalId)break;for(let R of tn.values())R.status="stale";tn.clear();let A={id:k.id,kind:"followup-create-offer",proposalId:h.proposalId,label:h.label??"",prompt:h.prompt??"",trigger:h.trigger??"pr.merged",repo:h.repo??null,why:h.why??null,status:"open",created:null,ts:ae(k),box:k.boxId,agent:k.provider};tn.set(h.proposalId,A),yt.set(h.proposalId,A),n.push(A),N(A);break}case"followup.create.answered":{let A=yt.get(h.proposalId);A&&(A.status=h.action==="created"?"created":"dismiss",tn.delete(h.proposalId));break}case"followup.created":{let A=h.proposalId?yt.get(h.proposalId):null;A&&(A.created={followupId:h.followupId??null});break}case"loop.created":{let A=h.proposalId?re.get(h.proposalId):null;A&&(A.created={loopId:h.loopId??null,nextFireAt:Number.isFinite(Number(h.nextFireAt))?Number(h.nextFireAt):null}),n.push(vt(k,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!h.proposalId||!h.loopId)break;for(let q of nn.values())q.loopId===h.loopId&&(q.status="stale",q.staleReason="superseded",nn.delete(q.proposalId));let A=k.type==="loop.update.offered",R={id:k.id,kind:A?"loop-update-offer":"loop-delete-offer",proposalId:h.proposalId,loopId:String(h.loopId),name:h.name??h.base?.name??"",base:h.base??null,...A?{patch:h.patch??{},changed:Array.isArray(h.changed)?h.changed:Object.keys(h.patch||{})}:{reason:h.reason??""},selfEdit:!!h.selfEdit,status:"open",staleReason:null,ts:ae(k),box:k.boxId,agent:k.provider};nn.set(h.proposalId,R),lo.set(h.proposalId,R),n.push(R),N(R);break}case"loop.update.answered":{let A=lo.get(h.proposalId);A&&(h.action==="moved"?(A.status="stale",A.staleReason="moved"):A.status=h.action==="applied"?"applied":"dismiss",nn.delete(h.proposalId));break}case"loop.delete.answered":{let A=lo.get(h.proposalId);A&&(h.action==="moved"?(A.status="stale",A.staleReason="moved"):A.status=h.action==="delete"?"deleted":h.action==="pause"?"paused":"keep",nn.delete(h.proposalId));break}case"loop.updated":{let A=h.proposalId?lo.get(h.proposalId):null;A&&(A.applied={changed:Array.isArray(h.changed)?h.changed:[],nextFireAt:Number.isFinite(Number(h.nextFireAt))?Number(h.nextFireAt):null}),n.push(vt(k,"loop-updated"));break}case"loop.deleted":n.push(vt(k,"loop-deleted"));break;case"loop.paused":n.push(vt(k,"loop-paused"));break;case"planning.change.offered":{if(!h.proposalId||!Array.isArray(h.ops)||!h.ops.length)break;for(let R of Et.values())R.status="stale",R.staleReason="superseded",Et.delete(R.proposalId);let A={id:k.id,kind:"planning-offer",proposalId:h.proposalId,why:h.why??"",ops:h.ops,base:h.base??{},resolved:h.resolved??{},snapped:!!h.snapped,createsMeRow:!!h.createsMeRow,status:"open",staleReason:null,applied:null,ts:ae(k),box:k.boxId,agent:k.provider};Et.set(h.proposalId,A),Xn.set(h.proposalId,A),n.push(A),N(A);break}case"planning.change.answered":{let A=Xn.get(h.proposalId);A&&(h.action==="moved"?(A.status="stale",A.staleReason="moved"):A.status=h.action==="applied"?"applied":"dismiss",Et.delete(h.proposalId));break}case"planning.changed":{let A=h.proposalId?Xn.get(h.proposalId):null;A&&(A.applied={results:Array.isArray(h.results)?h.results:[]}),n.push(vt(k,"planning-changed"));break}case"rework.cause.offered":{if(!h.sha||rn.has(h.sha))break;let A={id:k.id,kind:"rework-cause-offer",sha:h.sha,subject:h.subject??"",linesReworked:Number(h.linesReworked)||0,origins:Array.isArray(h.origins)?h.origins:[],heuristic:h.heuristic??null,intent:h.intent??null,shas:Array.isArray(h.shas)?h.shas:null,pr:h.pr??null,retracts:0,status:"open",cause:null,ts:ae(k),box:k.boxId,agent:k.provider};rn.set(h.sha,A),n.push(A);break}case"rework.cause.answered":{let A=h.sha?rn.get(h.sha):null;A&&(A.status="answered",A.cause=h.cause??null);break}case"rework.cause.retracted":{let A=h.sha?rn.get(h.sha):null;A&&(A.status="open",A.cause=null,A.retracts=(A.retracts??0)+1);break}case"ticket.created":{let A={items:Array.isArray(h.items)?h.items:[],failed:Array.isArray(h.failed)?h.failed:[],team:h.team??null},R=h.proposalId?Ie.get(h.proposalId):null;if(R){R.created=A;break}n.push({id:k.id,kind:"ticket-created",...A,ts:ae(k),box:k.boxId,agent:k.provider});break}case"error":{if(!h.kind)break;n.push(vt(k,h.kind));break}case"turn.aborted":{(h.cause==="cli-exited"||h.cause==="session-gone")&&n.push(vt(k,"turn-aborted"));break}case"provider.error":n.push({...vt(k,"provider-error"),provider:k.provider,box:k.boxId,agent:k.provider});break;case"usage.cap.hit":n.push(vt(k,"usage-cap-hit"));break;case"usage.cap.warning":n.push(vt(k,"usage-cap-warning"));break;case"provider.connected":{n.push({id:k.id,kind:"event",type:"provider-connected",provider:h.provider||k.provider,account:h.account||null,reason:h.reason||null,ts:ae(k),at:ae(k),box:k.boxId,agent:k.provider});break}case"provider.login.started":break;case"prompt.answered":{if(nt=null,h.control||!h.question)break;let A=h.groupId||h.promptId;if(!A)break;let R=ct.get(A);R||(R={id:k.id,kind:"prompt",groupId:A,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:h.questionTotal??1,questions:[],ts:ae(k)},ct.set(A,R));let q=h.questionIndex??0,fe={index:q,header:h.header||"",question:h.question,multiSelect:!!h.multiSelect,chosen:Array.isArray(h.chosen)?h.chosen:[]},Se=R.questions.findIndex(ht=>ht.index===q&&Oe(ht.question)===Oe(fe.question));Se>=0?R.questions[Se]=fe:R.questions.push(fe),R.questions.sort((ht,Od)=>ht.index-Od.index),R.questionTotal=Math.max(R.questionTotal,h.questionTotal??1),R.questions.length>=R.questionTotal&&(n.push(R),ct.delete(A));break}case"prompt.dismissed":{nt=null;let A=h.groupId||h.promptId;if(!A||!h.question)break;let q=ct.get(A)||{id:k.id,kind:"prompt",groupId:A,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:h.questionTotal??1,questions:[],ts:ae(k)},fe=h.questionIndex??0;q.questions.some(Se=>Se.index===fe&&Oe(Se.question)===Oe(h.question))||(q.questions.push({index:fe,header:h.header||"",question:h.question,multiSelect:!!h.multiSelect,chosen:[]}),q.questions.sort((Se,We)=>Se.index-We.index)),q.answeredVia="chat",n.push(q),ct.delete(A);break}default:break}}for(let[k,h]of[...ze]){if(h==="superseded"){k.status!=="superseded"&&Ze(k,null);continue}(k.status!=="open"||t-(k.ts??0)>=A2)&&Ze(k,null)}let Zn=f.size?n.filter(k=>!k.retired):n;return Zn.sort((k,h)=>(k.ts??0)-(h.ts??0)),T2(Zn,ee),_2(Zn)}function T2(e,t){if(!t.size)return;let n=new Map,r=new Map;for(let s of t.values())s.sort((a,i)=>a-i);let o=(s,a)=>{let i=t.get(s),c=n.get(s);if(!i||!c)return;let l=r.get(s)??0;for(;l<i.length&&i[l]<=(c.ts??0);)l++;r.set(s,l),l<i.length&&i[l]<=a&&(c.closing=!0)};for(let s of e)s.kind!=="message"||s.role!=="assistant"||!s.box||!String(s.text||"").trim()||(o(s.box,s.ts??0),n.set(s.box,s));for(let s of n.keys())o(s,1/0)}function _2(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<=E2){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 Sg(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:I2(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??ir(e)).filter(o=>o.kind==="message");return YA(n,r)}function I2(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==ei(e.command)?t:vo(e.command,e.description||"")}function vt(e,t){let{ts:n,change:r,kind:o,...s}=e.payload||{};return{id:e.id,kind:"event",type:t,...s,at:ae(e),ts:ae(e)}}function rE(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)+$2,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&R2.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function oE(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!M2.has(r.type)||!r.box)continue;let o=(r.ts??0)+O2,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 Bp(e){return(e||[]).filter(t=>C2.has(t?.kind)&&t.status==="open")}function sE(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(tE.has(o.change)&&o.number!=null)nE(t,n,o);else if(o.change==="merged"||o.change==="closed"||o.change==="lost"){let s=xg(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 S2,ae,tE,xg,A2,E2,$2,R2,O2,M2,C2,Lp=K(()=>{ti();Ds();bp();ri();si();kg();S2=/\bBP-[A-Z0-9]+(?:-[A-Z0-9]+)*\b/i,ae=e=>e.payload?.ts??e.ts;tE=new Set(["opened","ci-fixed","reconciled","pushed"]),xg=e=>`${e.repo??""}#${e.number}`;A2=3e4;E2=2*6e4;$2=12e4,R2=new Set(["archived","unarchived","opened"]);O2=2500,M2=new Set(["pr-opened","pr-merged","pr-auto-armed"]);C2=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 L2(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 F2(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 U2(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<D2&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<B2&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function lE(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=L2(e),s=F2(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=ir(e??[]).filter(p=>p?.kind==="message"&&typeof p.text=="string"&&p.text.trim()).slice(-N2);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(cE[r]??cE.failover),l.push(""),o.lastPush?.sha){let p=iE(n,o.lastPush.ts),w=p?` (~${p} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${w}`+(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=iE(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=U2(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"}:** ${j2(p.text,P2)}`),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(`
|
|
170
|
+
`});function v2(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 nE(e,t,n){let r=xg(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 ir(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=(k,f)=>{f!=null&&(u.has(k)||u.set(k,[]),u.get(k).push(f))},p=(k,f)=>{let A=null;for(let R of[k,null])for(let q of u.get(R)||[])q>f&&(A==null||q<A)&&(A=q);return A},w=new Set,m=new Map,h=new Map,g=(k,f)=>{h.set(k,f),n.push(f)},y=k=>{let f=h.get(k);f&&(f.retired=!0)},b=new Map,x=new Map,v=/^Agent "([\s\S]+)" finished$/,S=new Map;for(let k of e||[]){if(k.type!=="tool.called"||k.source!=="transcript")continue;let f=String(k.payload?.command||"");if(/\bbostrat-mock\s+(?:add|update)\b/.test(f))for(let A of f.matchAll(/[\w./~-]+\.(?:png|jpe?g|gif|webp|bmp|svg)\b/gi)){let R=A[0].split("/").pop().toLowerCase();S.has(R)||S.set(R,[]),S.get(R).push(k.payload?.ts??k.ts)}}let E=3*6e4,P=20*6e4,L=(k,f)=>!!(k?.name&&S.get(String(k.name).toLowerCase()))?.some(R=>R>=f-E&&R<=f+P);for(let k of e||[])if(k.type==="turn.retracted"){o.add(`${k.boxId}|${k.payload?.saidTs}`);let f=Oe(k.payload?.text);f&&(s.has(k.boxId)||s.set(k.boxId,[]),s.get(k.boxId).push(f))}else if(k.type==="turn.user"&&k.source==="orchestrator"){let f=Oe(k.payload?.text);f&&(a.has(k.boxId)||a.set(k.boxId,new Set),a.get(k.boxId).add(f))}else if(k.type==="job.stalled"&&k.payload?.id)c.set(k.payload.id,{ts:ae(k),quietMs:Number(k.payload.quietMs)||null});else if(k.type==="job.stopped"&&k.payload?.id)l.has(k.payload.id)||l.set(k.payload.id,{status:"killed",summary:null,resultHead:null,ts:ae(k)});else if(k.type==="session.ready"){let f=k.payload?.source;f!=="compact"&&f!=="clear"&&d(k.boxId??null,ae(k))}else if(k.type==="handoff.done")d(k.boxId??k.payload?.from??null,ae(k));else if(k.type==="box.state.changed"&&k.payload?.change==="archived")d(null,ae(k));else if(k.type==="job.started"&&k.payload?.id)i.add(k.payload.id),(k.payload.kind||"agent")==="agent"&&k.payload.name&&w.add(k.payload.name);else if(k.type==="turn.user"&&k.payload?.note?.kind==="task"){let f=k.payload.note,A={status:f.status||null,summary:f.summary||null,resultHead:f.resultHead??null,ts:ae(k)};f.toolUseId&&l.set(f.toolUseId,A);let R=String(f.summary||"").match(v);R&&m.set(R[1],A)}let $=new Map,C=new Map,U=null,J=new Map,_=new Map,I=new Map,T=new Map,F=new Map,W=new Map,ce=new Map,z=new Map,Ke=new Map,Ie=new Map,X=new Map,re=new Map,Te=new Map,Le=new Map,ie=new Map,Pe=new Map,ve=(k,f)=>{k.arm.status=f;let A=k.line,R=A.arms.map(q=>q.status);A.status=R.includes("armed")?"armed":R.includes("offered")?"offered":R.includes("replaced")?"replaced":"cancelled"},ee=new Map,ge=[],Ve=new Set,ze=new Map,Ze=(k,f)=>{ze.delete(k);let A=n.indexOf(k);A>=0&&n.splice(A,1),f!=null&&(k.ts=f),n.push(k)},N=k=>{if(ge.push(k),!(k.box?Ve.has(k.box):Ve.size>0))return;let A=n.indexOf(k);A>=0&&n.splice(A,1),ze.set(k,"held")},le=k=>{if(!ge.length)return;let f=ae(k);for(let A of ge)A.status!=="open"||ze.get(A)==="superseded"||A.box&&A.box!==k.boxId||(A.ts??0)>f||Ze(A,f)},pe=k=>{if(!ge.length)return;let f=ae(k);for(let A of ge)ze.get(A)!=="held"||A.status!=="open"||A.box&&k.boxId&&A.box!==k.boxId||Ze(A,Math.max(A.ts??0,f))},$e=()=>{for(let[k,f]of[...ze])f==="held"&&Ze(k,null);ge.length=0,Qe.clear()},Qe=new Set,Je=k=>{for(let f of Qe){if(f.status!=="open"||f.box&&k&&f.box!==k)continue;f.status="superseded";let A=n.indexOf(f);A>=0&&n.splice(A,1),ze.set(f,"superseded"),J.delete(f.offerId)}Qe.clear()},tn=new Map,yt=new Map,nn=new Map,lo=new Map,Et=new Map,Xn=new Map,rn=new Map,ct=new Map,Gt=()=>{for(let k of ct.values())k.questions.length&&n.push(k);ct.clear()},nt=null,ys=new Map,bs=6e4,uo=new Map,po=(k,f)=>{let A=s.get(k);if(!A?.length)return!1;let R=Oe(f),q=a.get(k);return A.some(fe=>{if(!R.startsWith(fe))return!1;let Se=Oe(R.slice(fe.length));return!!Se&&!!q?.has(Se)})};for(let k of e||[]){let f=k.payload||{};switch(k.type){case"turn.user":{if(k.boxId){let R=ee.get(k.boxId);R?R.push(ae(k)):ee.set(k.boxId,[ae(k)])}if(k.source==="hook"){k.boxId&&Ve.add(k.boxId);break}if($e(),!String(f.text||"").trim()&&!f.images?.length&&!f.attachments?.length)break;{let R=gT(f.text);if(R){if(R.kind==="shell-input"){let q={id:k.id,kind:"shell",command:R.command,stdout:null,stderr:null,done:!1,ts:ae(k),box:k.boxId,agent:k.provider};n.push(q),ys.set(k.boxId,q)}else{let q=ys.get(k.boxId);q?(q.stdout=R.stdout||null,q.stderr=R.stderr||null,q.done=!0,ys.delete(k.boxId)):n.push({id:k.id,kind:"shell",command:null,stdout:R.stdout||null,stderr:R.stderr||null,done:!0,ts:ae(k),box:k.boxId,agent:k.provider})}break}}{let R=f.note||wl(f.text);if(R){if(R.kind==="task"){if(R.toolUseId&&i.has(R.toolUseId))break;let q=String(R.summary||"").match(v);if(!R.toolUseId&&q&&w.has(q[1]))break}if(R.kind==="command"&&mT(R.command))break;if(R.kind==="resume-summary"){n.push({id:k.id,kind:"resume-summary",title:R.title||"Context resumed from summary",bullets:R.bullets||[],sections:R.sections||[],rawChars:R.rawChars??null,ts:ae(k),box:k.boxId,agent:k.provider});break}R.kind!=="suppress"&&n.push({id:k.id,kind:"event",type:yT(R),name:R.name??null,command:R.command??null,summary:R.summary??null,status:R.status??null,...R.kind==="cut-delivery"?{received:R.received??null,sent:R.sent??null,head:R.head??null}:{},ts:ae(k),box:k.boxId,agent:k.provider});break}}if(o.has(`${k.boxId}|${ae(k)}`)||k.source==="transcript"&&po(k.boxId,f.text))break;let A=f.text;if(k.source==="transcript"){let R=oi(A);if(R!==A){if(a.get(k.boxId)?.has(Oe(R)))break;A=R}let q=Ap(A,a.get(k.boxId)??[]);if(q){n.push({id:k.id,kind:"event",type:"delivery-cut",received:q.received,sent:q.sent,head:q.head,ts:ae(k),box:k.boxId,agent:k.provider});break}}if(f.kind==="merge-notify"||f.kind==="ship-notify"){n.push({id:k.id,kind:"event",type:f.kind==="ship-notify"?"ship-notified":"merge-notified",text:f.text,ts:ae(k),box:k.boxId,agent:k.provider});break}if(f.kind==="item-launch"){n.push({id:k.id,kind:"event",type:"item-kickoff",text:f.text,itemId:(String(f.text||"").match(S2)||[null])[0]?.toUpperCase()??null,ts:ae(k),box:k.boxId,agent:k.provider});break}if(f.kind==="subtask-resume"){n.push({id:k.id,kind:"event",type:"subtask-finished",text:f.text,...f.detail&&typeof f.detail=="object"?f.detail:{},ts:ae(k),box:k.boxId,agent:k.provider});break}if(f.kind==="mock-picked"||f.kind==="ci-fix"||f.kind==="reconcile"||f.kind==="pr-go"||f.kind==="push-go"||f.kind==="spin-up-view"||f.kind==="prompt-answer"||f.kind==="followup-go"||f.kind==="login-greet"){f.kind==="prompt-answer"&&(nt=null);break}for(let R of J.values())R.status="stale";J.clear();for(let R of I.values())R.status="stale";I.clear();for(let R of Te.values())R.rows.some(q=>q.rowStatus==="sent")||(R.status="stale",Te.delete(R.offerId));nt&&nt.box===k.boxId&&(n.push(v2(nt)),nt=null),n.push({id:k.id,kind:"message",role:"user",text:A,ts:ae(k),box:k.boxId,agent:k.provider,boxRole:f.boxRole,...k.actor==="orchestrator"?{orchestration:f.kind||!0}:{},...f.sourceId?{sourceId:f.sourceId}:{},...f.attachments?.length?{attachments:f.attachments}:{},...f.images?.length?{images:f.images}:{},...f.producer==="voice"?{via:"voice"}:{}});break}case"blueprint.item.launched":{if(!f.itemId||!f.trackId)break;n.push({id:k.id,kind:"event",type:"item-launched",itemId:String(f.itemId),trackId:String(f.trackId),trackName:f.trackName??null,provider:f.provider??null,node:f.node??null,via:f.via==="voice"?"voice":"chat",ts:ae(k)});break}case"peer.message":{let A=f.from||{};n.push({id:k.id,kind:"event",type:"peer-message",text:f.text,from:A.trackName||A.boxId||A.name||null,fromTrackId:A.trackId||null,ts:ae(k),box:k.boxId,agent:k.provider});break}case"turn.agent":{if(f.model==="<synthetic>"&&/^No response requested\.$/.test(String(f.text||"").trim()))break;let A=oT(f,{codexFailedText:Ps});if(A){n.push({id:k.id,kind:"event",type:"provider-error",cls:A.cls,status:A.status??void 0,text:A.text,provider:k.provider,legacy:!0,at:ae(k),ts:ae(k),box:k.boxId,agent:k.provider});break}Gt();let R=(f.images||[]).filter(ht=>!L(ht,ae(k)));if(k.source==="hook"&&!String(f.text||"").trim()&&(pe(k),k.boxId&&Ve.delete(k.boxId)),!String(f.text||"").trim()&&!R.length)break;if(k.provider==="cursor"){let ht=`${k.boxId}|${f.text}`;if(r.has(ht))break;r.add(ht)}(!nt||nt.box===k.boxId)&&(nt=null);let q=k.provider==="codex"?(f.tools||[]).filter(ht=>!ng.has(ht)&&!dl.has(ht)):f.tools||[],fe=f.text,Se=null,We=gg(String(f.text||""));We&&(fe=We.text,Se={questions:We.questions}),n.push({id:k.id,kind:"message",role:"assistant",text:fe,ts:ae(k),box:k.boxId,agent:k.provider,boxRole:f.boxRole,...Se?{ask:Se}:{},...q.length?{tools:q}:{},...f.model?{model:f.model}:{},...f.sourceId?{sourceId:f.sourceId}:{},...R.length?{images:R}:{}}),le(k),Se&&(nt={id:k.id,groupId:yg(k.provider,f.sourceId||k.id,Se.questions),provider:k.provider,box:k.boxId,questions:Se.questions,ts:ae(k)});break}case"job.started":{if(!f.id)break;let A=ae(k),R=l.get(f.id);if(!R&&(f.kind||"agent")==="agent"&&f.name){let _r=m.get(f.name);_r&&_r.ts>=A&&(R=_r)}let q=R?null:c.get(f.id)||null,fe=R||q?null:p(k.boxId??null,A),Se={jobId:f.id,jobKind:f.kind||"agent",name:f.name||null,detail:f.detail||null,status:R?R.status==="killed"?"stopped":R.status&&R.status!=="completed"?"failed":"done":q?"stalled":fe!=null?"lost":"running",startedTs:A,finishedTs:R?.ts??q?.ts??fe??null,quietMs:q?.quietMs??null,summary:R?.summary??null,resultHead:R?.resultHead??null},We=uo.get(k.boxId),ht=We?.jobs[We.jobs.length-1]?.startedTs;if(We&&ht!=null&&A-ht<=bs)We.jobs.push(Se);else{let _r={id:k.id,kind:"job-dock",dockId:f.id,ts:A,box:k.boxId,agent:k.provider,jobs:[Se]};uo.set(k.boxId,_r),n.push(_r)}break}case"handoff.done":n.push(vt(k,"lead-handoff"));break;case"subtask.delegated":n.push({...vt(k,"subtask-delegated"),to:k.boxId,toAgent:k.provider});break;case"subtask.merged":n.push(vt(k,"subtask-merged"));break;case"pr.state.changed":{if(!f.change)break;if(f.change==="opened"){for(let R of J.values())R.status="stale";J.clear();for(let R of I.values())R.status="stale";I.clear()}let A=vt(k,`pr-${f.change}`);if(A.box=k.boxId??null,tE.has(f.change)&&f.number!=null){let R=nE($,C,f);if($.size>=2){for(let fe of C.values())for(let Se of fe)Se.grouped=!0;A.groupPrs=[...$.values()];let q=[A];for(let fe of $.keys())C.set(fe,q)}else{let q=C.get(R)??[];q.push(A),C.set(R,q)}}else if(f.change==="merged"||f.change==="closed"||f.change==="lost"){let R=xg(f),q=U&&!U.complete||$.size>=2;if($.has(R))$.delete(R),C.delete(R);else if(f.number!=null)for(let fe of[...$.keys()])fe.endsWith(`#${f.number}`)&&($.delete(fe),C.delete(fe));if(q&&f.number!=null){(!U||U.complete)&&(U={id:k.id,kind:"event",type:"pr-group-settled",prs:[],remaining:[],complete:!1,at:ae(k),ts:ae(k),box:k.boxId,agent:k.provider},n.push(U)),U.prs.push({number:f.number,url:f.url??null,title:f.title??null,repo:f.repo??null,branch:f.branch??null,change:f.change,ts:ae(k)}),U.remaining=[...$.values()],U.complete=$.size===0;break}}n.push(A);break}case"pr.offered":{if(!f.offerId)break;Je(k.boxId);for(let R of J.values())R.status="stale";J.clear();for(let R of I.values())R.status="stale";I.clear();let A={id:k.id,kind:"pr-offer",offerId:f.offerId,excerpt:f.excerpt||null,branch:f.branch||null,base:f.base||null,offered:Array.isArray(f.offered)&&f.offered.length?f.offered:null,toPr:f.toPr&&typeof f.toPr=="object"?{number:f.toPr.number??null}:null,available:Array.isArray(f.available)?f.available:null,defaults:Array.isArray(f.defaults)?f.defaults:null,prState:f.prState||null,openPr:f.openPr&&typeof f.openPr=="object"?f.openPr:null,repos:Array.isArray(f.repos)&&f.repos.length?f.repos:null,status:"open",source:k.source==="cli"||f.via==="cli"?"cli":"transcript",ts:ae(k),box:k.boxId,agent:k.provider};J.set(f.offerId,A),_.set(f.offerId,A),n.push(A),Qe.add(A),A.source==="cli"&&N(A);break}case"pr.offer.answered":{let A=_.get(f.offerId);A&&(A.status=f.action||"dismiss",A.actions=Array.isArray(f.actions)?f.actions:null,A.notify=f.notify===!0,f.existingPr&&typeof f.existingPr=="object"&&(A.existingPr={number:f.existingPr.number??null}),J.delete(f.offerId));break}case"pr.exists.offered":{if(!f.offerId)break;for(let R of I.values())R.status="stale";I.clear();let A={id:k.id,kind:"pr-exists-offer",offerId:f.offerId,srcOfferId:f.srcOfferId??null,branch:f.branch||null,base:f.base||null,pr:f.pr&&typeof f.pr=="object"?{number:f.pr.number??null,url:f.pr.url??null,title:f.pr.title??null}:null,actions:Array.isArray(f.actions)&&f.actions.length?f.actions:null,notify:f.notify===!0,status:"open",ts:ae(k),box:k.boxId,agent:k.provider};I.set(f.offerId,A),T.set(f.offerId,A),n.push(A);break}case"pr.exists.answered":{let A=T.get(f.offerId);A&&(A.status=f.choice||"dismiss",I.delete(f.offerId));break}case"box.state.changed":{let A=f.change==="model"?"model-change":f.change;if(!A||A==="cli-update"&&f.status!=="failed")break;let R=vt(k,A);if(A==="model-change"&&(R.to=f.model),A==="node-update"&&R.latest){let q=n.findIndex(fe=>fe.kind==="event"&&fe.type==="node-update"&&fe.latest===R.latest);if(q>=0){let fe=n[q];n[q]={...R,ts:fe.ts,at:fe.at,firstAt:fe.firstAt??fe.ts,updatedAt:R.ts};break}}n.push(R);break}case"track.transferred":case"track.recovered":n.push(vt(k,"track-moved"));break;case"view.state.changed":{if(f.change==="deleted"){y(`view:${f.viewId}`);break}if(f.change!=="created"||f.restarted)break;g(`view:${f.viewId}`,{id:k.id,kind:"view-card",viewId:f.viewId,name:f.name,slug:f.slug,port:f.port,origin:f.origin,ts:ae(k),box:k.boxId,agent:k.provider});break}case"deps.prepare":{if(f.status==="ready"&&f.cached)break;let A=f.batch||k.id,R=b.get(A);R||(R={id:k.id,kind:"event",type:"deps-prepare",batch:A,status:"preparing",dirs:[],at:ae(k),ts:ae(k),box:k.boxId},b.set(A,R),n.push(R));let q=f.dir||f.relDir||".",fe={dir:q,repo:f.repo??null,status:f.status==="started"?"preparing":f.status,...f.reason?{reason:f.reason}:{},...Array.isArray(f.tail)&&f.tail.length?{tail:f.tail}:{},...f.durationMs!=null?{durationMs:f.durationMs}:{},...f.sizeBytes!=null?{sizeBytes:f.sizeBytes}:{},...f.linked===!1?{linked:!1}:{},...f.cached?{cached:!0}:{}},Se=R.dirs.findIndex(We=>We.dir===q);Se>=0?R.dirs[Se]=fe:R.dirs.push(fe),R.status=R.dirs.some(We=>We.status==="preparing")?"preparing":R.dirs.some(We=>We.status==="failed")?"failed":"ready",R.updatedAt=ae(k);break}case"deps.setup":{let A=f.run||k.id,R=x.get(A);if(R||(R={id:k.id,kind:"event",type:"deps-setup",run:A,repo:f.repo??null,dir:f.dir||".",source:f.source||"bostrat-setup",command:f.command||null,status:"running",at:ae(k),ts:ae(k),box:k.boxId},x.set(A,R),n.push(R)),f.status==="output"){let q=Array.isArray(f.lines)?f.lines.filter(fe=>typeof fe=="string"&&fe.trim()):[];q.length&&(R.last=q[q.length-1].trim().slice(0,200))}else(f.status==="done"||f.status==="failed")&&(R.status=f.status,delete R.last,f.durationMs!=null&&(R.durationMs=f.durationMs),f.reason&&(R.reason=f.reason),Array.isArray(f.tail)&&f.tail.length&&(R.tail=f.tail));R.updatedAt=ae(k);break}case"view.spinup.failed":{n.push({id:k.id,kind:"view-spinup-failed",name:f.name||null,reason:f.reason||"no-view",ts:ae(k),box:k.boxId,agent:k.provider});break}case"mock.state.changed":{if(f.change==="picked"){n.push({id:k.id,kind:"mock-picked",mockId:f.mockId,name:f.name,group:f.group??null,version:f.version??null,siblings:f.siblings??[],ts:ae(k),box:k.boxId,agent:k.provider});break}if(f.change==="deleted"){y(`mock:${f.mockId}`);break}if(f.change!=="created")break;g(`mock:${f.mockId}`,{id:k.id,kind:"mock-card",mockId:f.mockId,name:f.name,group:f.group??null,ts:ae(k),box:k.boxId,agent:k.provider});break}case"flow.state.changed":{if(f.change==="deleted"){y(`flow:${f.flowId}`);break}if(f.change!=="created")break;g(`flow:${f.flowId}`,{id:k.id,kind:"flow-card",flowId:f.flowId,name:f.name,stepCount:f.stepCount??null,mockIds:f.mockIds??[],ts:ae(k),box:k.boxId,agent:k.provider});break}case"runbook.state.changed":{if(f.change==="deleted"){y(`runbook:${f.runbookId}`);break}if(f.change!=="created")break;g(`runbook:${f.runbookId}`,{id:k.id,kind:"runbook-card",runbookId:f.runbookId,name:f.name,ts:ae(k),box:k.boxId,agent:k.provider});break}case"ticket.linked":{n.push({id:k.id,kind:"ticket-card",provider:f.provider||"linear",key:f.key,url:f.url,title:f.title??null,linkSource:f.linkSource??null,ts:ae(k),box:k.boxId,agent:k.provider});break}case"box.fullscreen.detected":case"box.stuck.detected":{if(!f.offerId)break;for(let R of ce.values())R.box===(f.box||k.boxId)&&(R.status="stale",ce.delete(R.offerId));let A={id:k.id,kind:"fullscreen-offer",reason:k.type==="box.stuck.detected"?"stuck":"fullscreen",offerId:f.offerId,status:"open",ts:ae(k),box:f.box||k.boxId,agent:f.agent||k.provider,...k.type==="box.stuck.detected"?{escSends:f.escSends??null,kept:f.kept??0}:{}};ce.set(f.offerId,A),z.set(f.offerId,A),n.push(A);break}case"box.fullscreen.answered":case"box.stuck.answered":{let A=z.get(f.offerId);A&&(A.status=f.action==="restarted"?"restarted":f.action==="cleared"?"cleared":"dismiss",ce.delete(f.offerId));break}case"ticket.move.offered":{if(!f.offerId)break;for(let R of F.values())R.key===f.key&&(R.status="stale",F.delete(R.offerId));let A={id:k.id,kind:"ticket-offer",offerId:f.offerId,provider:f.provider||"linear",key:f.key,url:f.url??null,phase:f.phase??null,from:f.from??null,to:f.to?.name??null,prNumber:f.prNumber??null,status:"open",ts:ae(k),box:k.boxId,agent:k.provider};F.set(f.offerId,A),W.set(f.offerId,A),n.push(A);break}case"ticket.move.answered":{let A=W.get(f.offerId);A&&(A.status=f.action==="moved"?"moved":"dismiss",F.delete(f.offerId));break}case"ticket.state.changed":{for(let A of F.values())A.key===f.key&&A.to===f.to&&(A.status="stale",F.delete(A.offerId));if(f.mode==="offer")break;n.push(vt(k,"ticket-state"));break}case"ticket.commented":{n.push({id:k.id,kind:"ticket-comment",key:f.key,url:f.url??null,excerpt:f.excerpt??null,ts:ae(k),box:k.boxId,agent:k.provider});break}case"ticket.flow.changed":n.push(vt(k,"ticket-flow"));break;case"ticket.create.offered":{if(!f.proposalId)break;for(let R of Ke.values())R.status="stale";Ke.clear();let A={id:k.id,kind:"ticket-create-offer",proposalId:f.proposalId,provider:f.provider||"linear",epic:f.epic??null,issues:Array.isArray(f.issues)?f.issues:[],team:f.team??null,needsTeam:!!f.needsTeam,linkCurrentTrack:!!f.linkCurrentTrack,status:"open",ts:ae(k),box:k.boxId,agent:k.provider};Ke.set(f.proposalId,A),Ie.set(f.proposalId,A),n.push(A),N(A);break}case"ticket.create.answered":{let A=Ie.get(f.proposalId);A&&(A.status=f.action==="created"?"created":"dismiss",A.createdCount=f.createdCount??null,A.failedCount=f.failedCount??null,Ke.delete(f.proposalId));break}case"loop.create.offered":{if(!f.proposalId)break;for(let R of X.values())R.status="stale";X.clear();let A={id:k.id,kind:"loop-create-offer",proposalId:f.proposalId,name:f.name??"",schedule:f.schedule??"",prompt:f.prompt??"",expectation:f.expectation??null,notify:f.notify??"off",assignment:f.assignment??{provider:"claude"},repo:f.repo??null,nodeId:f.nodeId??null,nodeName:f.nodeName??null,status:"open",ts:ae(k),box:k.boxId,agent:k.provider};X.set(f.proposalId,A),re.set(f.proposalId,A),n.push(A),N(A);break}case"loop.create.answered":{let A=re.get(f.proposalId);A&&(A.status=f.action==="created"?"created":"dismiss",X.delete(f.proposalId));break}case"followup.armed":{if(!f.armId)break;let A=f.replaces?ie.get(f.replaces):null;A&&A.arm.status==="armed"&&ve(A,"replaced");let R={armId:f.armId,seq:Number.isInteger(f.seq)?f.seq:0,label:f.label??"",prompt:f.prompt??"",why:f.why??null,standing:f.standing==="never"?"never":"offerable",status:"armed"},q=f.groupId??null,fe=q?Pe.get(q):null;fe||(fe={id:k.id,kind:"followup-armed",groupId:q,armId:R.armId,trigger:f.trigger??"now",label:R.label,prompt:R.prompt,why:R.why,planWhy:f.planWhy??null,arms:[],status:"armed",ts:ae(k),box:k.boxId,agent:k.provider},q&&Pe.set(q,fe),fe.trigger!=="now"&&n.push(fe)),fe.arms.push(R),ie.set(f.armId,{arm:R,line:fe});break}case"followup.armed.cancelled":{let A=ie.get(f.armId);A&&A.arm.status==="armed"&&ve(A,"cancelled");break}case"followup.offered":{if(!f.offerId)break;for(let q of Te.values())q.trigger===f.trigger&&(q.status="stale",Te.delete(q.offerId));let A=Array.isArray(f.rows)?f.rows:[];for(let q of A){let fe=q.armId?ie.get(q.armId):null;fe&&fe.arm.status==="armed"&&ve(fe,"offered")}let R={id:k.id,kind:"followup-offer",offerId:f.offerId,trigger:f.trigger??"now",repo:f.repo??null,context:f.context&&typeof f.context=="object"?f.context:{},groupId:f.groupId??null,why:f.why??null,rows:A.map(q=>({followupId:q.followupId??null,armId:q.armId??null,label:q.label??"",prompt:q.prompt??null,promptPreview:q.promptPreview??null,promptHash:q.promptHash??null,origin:q.origin??"operator",why:q.why??null,groupId:q.groupId??null,seq:Number.isInteger(q.seq)?q.seq:0,standing:q.standing==="never"?"never":"offerable",promotable:q.armId?q.promotable!==!1:!1,promotableReason:q.promotableReason??null,rowStatus:"open",saved:null})),status:"open",answer:null,answers:[],ts:ae(k),box:k.boxId,agent:k.provider};Te.set(f.offerId,R),Le.set(f.offerId,R),n.push(R),R.trigger==="now"&&N(R);break}case"followup.arm.saved":{let A=Le.get(f.offerId);if(!A)break;let R=A.rows.find(q=>q.armId&&q.armId===f.armId);R&&(R.saved=f.followupId??null);break}case"followup.answered":{let A=Le.get(f.offerId);if(!A)break;let R=new Set;f.armId&&R.add(`arm:${f.armId}`),f.followupId&&R.add(`fu:${f.followupId}`);for(let Se of Array.isArray(f.armIds)?f.armIds:[])R.add(`arm:${Se}`);for(let Se of Array.isArray(f.followupIds)?f.followupIds:[])R.add(`fu:${Se}`);let q=f.action==="sent"?"sent":f.action==="removed"?"removed":"dismiss";for(let Se of A.rows){if(Se.rowStatus!=="open")continue;let We=Se.armId?`arm:${Se.armId}`:`fu:${Se.followupId}`;R.size&&!R.has(We)||(Se.rowStatus=q)}let fe={followupId:f.followupId??null,armId:f.armId??null,label:f.label??null,promoted:f.promoted??null,revived:f.revived===!0,action:q,batchId:f.batchId??null,edited:f.edited===!0,order:Number.isInteger(f.order)?f.order:null,reordered:f.reordered===!0};A.answers.push(fe),A.answer=fe,A.rows.some(Se=>Se.rowStatus==="open")?A.status="open":(A.status=A.rows.some(Se=>Se.rowStatus==="sent")?"sent":A.rows.some(Se=>Se.rowStatus==="removed")?"removed":"dismiss",Te.delete(f.offerId));break}case"followup.create.offered":{if(!f.proposalId)break;for(let R of tn.values())R.status="stale";tn.clear();let A={id:k.id,kind:"followup-create-offer",proposalId:f.proposalId,label:f.label??"",prompt:f.prompt??"",trigger:f.trigger??"pr.merged",repo:f.repo??null,why:f.why??null,status:"open",created:null,ts:ae(k),box:k.boxId,agent:k.provider};tn.set(f.proposalId,A),yt.set(f.proposalId,A),n.push(A),N(A);break}case"followup.create.answered":{let A=yt.get(f.proposalId);A&&(A.status=f.action==="created"?"created":"dismiss",tn.delete(f.proposalId));break}case"followup.created":{let A=f.proposalId?yt.get(f.proposalId):null;A&&(A.created={followupId:f.followupId??null});break}case"loop.created":{let A=f.proposalId?re.get(f.proposalId):null;A&&(A.created={loopId:f.loopId??null,nextFireAt:Number.isFinite(Number(f.nextFireAt))?Number(f.nextFireAt):null}),n.push(vt(k,"loop-created"));break}case"loop.update.offered":case"loop.delete.offered":{if(!f.proposalId||!f.loopId)break;for(let q of nn.values())q.loopId===f.loopId&&(q.status="stale",q.staleReason="superseded",nn.delete(q.proposalId));let A=k.type==="loop.update.offered",R={id:k.id,kind:A?"loop-update-offer":"loop-delete-offer",proposalId:f.proposalId,loopId:String(f.loopId),name:f.name??f.base?.name??"",base:f.base??null,...A?{patch:f.patch??{},changed:Array.isArray(f.changed)?f.changed:Object.keys(f.patch||{})}:{reason:f.reason??""},selfEdit:!!f.selfEdit,status:"open",staleReason:null,ts:ae(k),box:k.boxId,agent:k.provider};nn.set(f.proposalId,R),lo.set(f.proposalId,R),n.push(R),N(R);break}case"loop.update.answered":{let A=lo.get(f.proposalId);A&&(f.action==="moved"?(A.status="stale",A.staleReason="moved"):A.status=f.action==="applied"?"applied":"dismiss",nn.delete(f.proposalId));break}case"loop.delete.answered":{let A=lo.get(f.proposalId);A&&(f.action==="moved"?(A.status="stale",A.staleReason="moved"):A.status=f.action==="delete"?"deleted":f.action==="pause"?"paused":"keep",nn.delete(f.proposalId));break}case"loop.updated":{let A=f.proposalId?lo.get(f.proposalId):null;A&&(A.applied={changed:Array.isArray(f.changed)?f.changed:[],nextFireAt:Number.isFinite(Number(f.nextFireAt))?Number(f.nextFireAt):null}),n.push(vt(k,"loop-updated"));break}case"loop.deleted":n.push(vt(k,"loop-deleted"));break;case"loop.paused":n.push(vt(k,"loop-paused"));break;case"planning.change.offered":{if(!f.proposalId||!Array.isArray(f.ops)||!f.ops.length)break;for(let R of Et.values())R.status="stale",R.staleReason="superseded",Et.delete(R.proposalId);let A={id:k.id,kind:"planning-offer",proposalId:f.proposalId,why:f.why??"",ops:f.ops,base:f.base??{},resolved:f.resolved??{},snapped:!!f.snapped,createsMeRow:!!f.createsMeRow,status:"open",staleReason:null,applied:null,ts:ae(k),box:k.boxId,agent:k.provider};Et.set(f.proposalId,A),Xn.set(f.proposalId,A),n.push(A),N(A);break}case"planning.change.answered":{let A=Xn.get(f.proposalId);A&&(f.action==="moved"?(A.status="stale",A.staleReason="moved"):A.status=f.action==="applied"?"applied":"dismiss",Et.delete(f.proposalId));break}case"planning.changed":{let A=f.proposalId?Xn.get(f.proposalId):null;A&&(A.applied={results:Array.isArray(f.results)?f.results:[]}),n.push(vt(k,"planning-changed"));break}case"rework.cause.offered":{if(!f.sha||rn.has(f.sha))break;let A={id:k.id,kind:"rework-cause-offer",sha:f.sha,subject:f.subject??"",linesReworked:Number(f.linesReworked)||0,origins:Array.isArray(f.origins)?f.origins:[],heuristic:f.heuristic??null,intent:f.intent??null,shas:Array.isArray(f.shas)?f.shas:null,pr:f.pr??null,retracts:0,status:"open",cause:null,ts:ae(k),box:k.boxId,agent:k.provider};rn.set(f.sha,A),n.push(A);break}case"rework.cause.answered":{let A=f.sha?rn.get(f.sha):null;A&&(A.status="answered",A.cause=f.cause??null);break}case"rework.cause.retracted":{let A=f.sha?rn.get(f.sha):null;A&&(A.status="open",A.cause=null,A.retracts=(A.retracts??0)+1);break}case"ticket.created":{let A={items:Array.isArray(f.items)?f.items:[],failed:Array.isArray(f.failed)?f.failed:[],team:f.team??null},R=f.proposalId?Ie.get(f.proposalId):null;if(R){R.created=A;break}n.push({id:k.id,kind:"ticket-created",...A,ts:ae(k),box:k.boxId,agent:k.provider});break}case"error":{if(!f.kind)break;n.push(vt(k,f.kind));break}case"turn.aborted":{(f.cause==="cli-exited"||f.cause==="session-gone")&&n.push(vt(k,"turn-aborted"));break}case"provider.error":n.push({...vt(k,"provider-error"),provider:k.provider,box:k.boxId,agent:k.provider});break;case"usage.cap.hit":n.push(vt(k,"usage-cap-hit"));break;case"usage.cap.warning":n.push(vt(k,"usage-cap-warning"));break;case"provider.connected":{n.push({id:k.id,kind:"event",type:"provider-connected",provider:f.provider||k.provider,account:f.account||null,reason:f.reason||null,ts:ae(k),at:ae(k),box:k.boxId,agent:k.provider});break}case"provider.login.started":break;case"prompt.answered":{if(nt=null,f.control||!f.question)break;let A=f.groupId||f.promptId;if(!A)break;let R=ct.get(A);R||(R={id:k.id,kind:"prompt",groupId:A,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:f.questionTotal??1,questions:[],ts:ae(k)},ct.set(A,R));let q=f.questionIndex??0,fe={index:q,header:f.header||"",question:f.question,multiSelect:!!f.multiSelect,chosen:Array.isArray(f.chosen)?f.chosen:[]},Se=R.questions.findIndex(ht=>ht.index===q&&Oe(ht.question)===Oe(fe.question));Se>=0?R.questions[Se]=fe:R.questions.push(fe),R.questions.sort((ht,Od)=>ht.index-Od.index),R.questionTotal=Math.max(R.questionTotal,f.questionTotal??1),R.questions.length>=R.questionTotal&&(n.push(R),ct.delete(A));break}case"prompt.dismissed":{nt=null;let A=f.groupId||f.promptId;if(!A||!f.question)break;let q=ct.get(A)||{id:k.id,kind:"prompt",groupId:A,provider:k.provider,box:k.boxId,agent:k.provider,questionTotal:f.questionTotal??1,questions:[],ts:ae(k)},fe=f.questionIndex??0;q.questions.some(Se=>Se.index===fe&&Oe(Se.question)===Oe(f.question))||(q.questions.push({index:fe,header:f.header||"",question:f.question,multiSelect:!!f.multiSelect,chosen:[]}),q.questions.sort((Se,We)=>Se.index-We.index)),q.answeredVia="chat",n.push(q),ct.delete(A);break}default:break}}for(let[k,f]of[...ze]){if(f==="superseded"){k.status!=="superseded"&&Ze(k,null);continue}(k.status!=="open"||t-(k.ts??0)>=A2)&&Ze(k,null)}let Zn=h.size?n.filter(k=>!k.retired):n;return Zn.sort((k,f)=>(k.ts??0)-(f.ts??0)),T2(Zn,ee),_2(Zn)}function T2(e,t){if(!t.size)return;let n=new Map,r=new Map;for(let s of t.values())s.sort((a,i)=>a-i);let o=(s,a)=>{let i=t.get(s),c=n.get(s);if(!i||!c)return;let l=r.get(s)??0;for(;l<i.length&&i[l]<=(c.ts??0);)l++;r.set(s,l),l<i.length&&i[l]<=a&&(c.closing=!0)};for(let s of e)s.kind!=="message"||s.role!=="assistant"||!s.box||!String(s.text||"").trim()||(o(s.box,s.ts??0),n.set(s.box,s));for(let s of n.keys())o(s,1/0)}function _2(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<=E2){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 Sg(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:I2(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??ir(e)).filter(o=>o.kind==="message");return YA(n,r)}function I2(e){let t=String(e.summary||"").trim();return t&&t!==e.command&&t!==ei(e.command)?t:vo(e.command,e.description||"")}function vt(e,t){let{ts:n,change:r,kind:o,...s}=e.payload||{};return{id:e.id,kind:"event",type:t,...s,at:ae(e),ts:ae(e)}}function rE(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)+$2,s=n;for(;s+1<t.length;){let a=t[s+1];if((a?.ts??0)>o||a?.kind==="event"&&R2.has(a.type))break;s++}s>n&&t.splice(s,0,...t.splice(n,1)),n=s}return t}function oE(e){let t=[...e];for(let n=0;n<t.length;n++){let r=t[n];if(r?.kind!=="event"||!M2.has(r.type)||!r.box)continue;let o=(r.ts??0)+O2,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 Bp(e){return(e||[]).filter(t=>C2.has(t?.kind)&&t.status==="open")}function sE(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(tE.has(o.change)&&o.number!=null)nE(t,n,o);else if(o.change==="merged"||o.change==="closed"||o.change==="lost"){let s=xg(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 S2,ae,tE,xg,A2,E2,$2,R2,O2,M2,C2,Lp=K(()=>{ti();Ds();bp();ri();si();kg();S2=/\bBP-[A-Z0-9]+(?:-[A-Z0-9]+)*\b/i,ae=e=>e.payload?.ts??e.ts;tE=new Set(["opened","ci-fixed","reconciled","pushed"]),xg=e=>`${e.repo??""}#${e.number}`;A2=3e4;E2=2*6e4;$2=12e4,R2=new Set(["archived","unarchived","opened"]);O2=2500,M2=new Set(["pr-opened","pr-merged","pr-auto-armed"]);C2=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 L2(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 F2(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 U2(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<D2&&(o.add(c.path),n.push(c.path)),c.head&&!s.has(c.head)&&r.length<B2&&(s.add(c.head),r.push(c.head))}return{files:n,heads:r}}function lE(e,{trackName:t="this Track",now:n=null,mode:r="failover"}={}){let o=L2(e),s=F2(e),a=s?.payload?.content??null,i=s?s.payload?.ts??s.ts??null:null,c=ir(e??[]).filter(p=>p?.kind==="message"&&typeof p.text=="string"&&p.text.trim()).slice(-N2);if(!a&&!c.length)return null;let l=[];if(l.push(`# Reconstructed resume brief \u2014 ${t}`),l.push(""),l.push(cE[r]??cE.failover),l.push(""),o.lastPush?.sha){let p=iE(n,o.lastPush.ts),w=p?` (~${p} min before the loss)`:"";l.push(`**Code state:** last pushed ref \`${o.lastPush.ref}\` @ \`${o.lastPush.sha.slice(0,12)}\`${w}`+(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=iE(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=U2(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"}:** ${j2(p.text,P2)}`),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(`
|
|
171
171
|
`);return d.length<=aE?d:`${d.slice(0,aE)}
|
|
172
172
|
|
|
173
173
|
[\u2026 brief truncated]`}var N2,P2,aE,D2,B2,j2,iE,cE,uE=K(()=>{Lp();N2=12,P2=2e3,aE=48e3,D2=30,B2=10;j2=(e,t)=>{let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1)}\u2026`},iE=(e,t)=>e&&t?Math.max(1,Math.round((e-t)/6e4)):null;cE={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 _o(e){let t=e.search(Up);return(t>=0?e.slice(0,t):e).trim()}function G2(e){if(!e)return"";let t=e.replace(/[│┌└├─┘┤┬┴┼─✂].*$/,"").trim();return!t||/hidden|\d+\s+lines?/i.test(t)?"":t}function K2(e){let t=String(e).trim();return!!(!t||Eo.test(e)||Up.test(t)||/hidden|\d+\s+lines?/i.test(t)||/notespress|press n to add/i.test(t)||/^\s*notes?\s*$/i.test(t))}function V2(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=z2(n,t);return n.forEach((a,i)=>{a.current=i===s}),{tabs:n,questionIndex:s,questionTotal:n.length,currentTabLabel:n[s].label}}function z2(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 pE(e){return e.replace(/[←→✔☐☒●▶]/g," ").replace(/\bSubmit\b/g," ").replace(/\s+/g," ").trim()}function Eg(e,t=""){let n=String(e);if(!wE.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
@@ -180,19 +180,19 @@ enumerable options.
|
|
|
180
180
|
`),o="";for(let s=0;s<r.length;s++)if(/^\s*https:\/\//.test(r[s])){o=rH(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 aH(e,t=""){let n=String(e);if(!Ag.test(n)||!sH.test(n)||Gs.test(n))return null;let s=([...n.replace(/\r/g,"").split(`
|
|
181
181
|
`)].reverse().find(a=>Ag.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 iH(e,t=""){let n=String(e);if(!xE.test(n)||Gs.test(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
182
182
|
`),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:_g(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:_o(a.label),description:""}))}]}:null}function cH(e,t=""){let n=String(e);if(Gs.test(n)&&!yl(n))return null;let r=n.replace(/\r/g,"").split(`
|
|
183
|
-
`),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(SE);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(Eo.test(r[l])||Up.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 lH(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(Tg.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 uH(e,t,{customIndex:n,textEdit:r}={}){let o=e.find(
|
|
184
|
-
`),s=lH(o);if(!s)return null;let{headerLine:a,chatLine:i,optStart:c,optEnd:l}=s,u=[],d=-1;for(let _=c;_<l;_++){let I=o[_].match(qs);I&&(d<0&&(d=_),u.push({line:_,cursor:!!I[1],checked:I[3]!=null&&I[3]!==" ",hasCheckbox:I[3]!=null,label:I[4].trim().replace(dE,""),desc:""}))}if(!u.length)return null;for(let _ of u)for(let I=_.line+1;I<Math.min(o.length,_.line+4)&&!(qs.test(o[I])||Eo.test(o[I]));I++){let T=o[I].trim();if(!(!T||K2(o[I])||jp.test(T))){_.desc=G2(T);break}}let p=o.slice(i+1).some(_=>H2.test(_)),w=uH(u,o,{customIndex:n,textEdit:p}),m=u.filter(_=>_!==w&&!jp.test(_.label));if(!m.length)return null;let
|
|
183
|
+
`),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(SE);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(Eo.test(r[l])||Up.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 lH(e){let t=-1;for(let r=e.length-1;r>=0;r--)if(Tg.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 uH(e,t,{customIndex:n,textEdit:r}={}){let o=e.find(h=>/^type something\b/i.test(h.label));if(o)return o;if(e.length<2)return null;let s=e[e.length-1];if(jp.test(s.label))return null;let a=[],i=-1;for(let h=s.line+1;h<Math.min(t.length,s.line+2+W2);h++){if(Eo.test(t[h])){i=h;break}t[h].trim()&&a.push(h)}if(!a.length)return i>=0&&i<=s.line+2?s:null;let c=h=>t[h].replace(/^\s*❯/,"").trim();if(a[0]<=s.line+2&&mE.test(c(a[0]))&&a.length===1)return s;if(i<0)return null;let l=/^(submit|next)$/i.test(c(a[a.length-1]))?a.slice(0,-1):a;if(!l.length)return s;if(fE(t[s.line])||l.some(h=>fE(t[h])))return null;let u=Number.isInteger(n)&&n===e.length-1,d=!!r&&s.cursor,p=Fp(t[i].trimEnd()),w=t[l[0]].trim().split(/\s+/)[0]||"",m=Fp(t[s.line].trimEnd())+1+Fp(w)>p-q2;return!u&&!d&&!m?null:(s.wrapped=l,s)}function dH(e,t){if(!e)return null;let n=e.wrapped?.length?e.wrapped[e.wrapped.length-1]:e.line;for(let r=n+1;r<Math.min(t.length,n+3);r++){let o=t[r],s=o.replace(/^\s*❯/,"").trim();if(s)return mE.test(s)?{cursor:/^\s*❯/.test(o)}:null}return null}function pH(e,t="",{customIndex:n}={}){let r=String(e);if(!hE.test(r)||!Tg.test(r))return null;let o=r.replace(/\r/g,"").split(`
|
|
184
|
+
`),s=lH(o);if(!s)return null;let{headerLine:a,chatLine:i,optStart:c,optEnd:l}=s,u=[],d=-1;for(let _=c;_<l;_++){let I=o[_].match(qs);I&&(d<0&&(d=_),u.push({line:_,cursor:!!I[1],checked:I[3]!=null&&I[3]!==" ",hasCheckbox:I[3]!=null,label:I[4].trim().replace(dE,""),desc:""}))}if(!u.length)return null;for(let _ of u)for(let I=_.line+1;I<Math.min(o.length,_.line+4)&&!(qs.test(o[I])||Eo.test(o[I]));I++){let T=o[I].trim();if(!(!T||K2(o[I])||jp.test(T))){_.desc=G2(T);break}}let p=o.slice(i+1).some(_=>H2.test(_)),w=uH(u,o,{customIndex:n,textEdit:p}),m=u.filter(_=>_!==w&&!jp.test(_.label));if(!m.length)return null;let h=m.some(_=>_.hasCheckbox),g=h?dH(w,o):null,y=g?.cursor?m.length+1:w?.cursor?m.length:Math.max(0,m.findIndex(_=>_.cursor)),b=w&&!jp.test(w.label)?[w.label,...(w.wrapped||[]).map(_=>o[_])].map(_=>_o(_)).filter(Boolean).join(" ").replace(dE,""):"",x=a>=0?a+1:0,v=[];for(let _=x;_<d;_++){let I=o[_].trim();I&&!Eo.test(o[_])&&!/[☐☒]/.test(o[_])&&v.push(I)}let S=v.join(" ")||(a>=0?pE(o[a]):"")||"The agent is asking a question",E=a>=0?V2(o[a],S):null,P=E?.currentTabLabel||(a>=0?pE(o[a]):""),L=m.map(_=>({label:_o(_.label),description:_.desc,...h?{checked:!!_.checked}:{}})),$=L.map(_=>_.label).join("|"),U=`claude:${E?`q${E.questionIndex+1}/${E.questionTotal}`:"q1/1"}:${P}:${S}:${$}`.slice(0,240),J=E?`claude:ask:${E.tabs.map(_=>_.label).join("|")}`.slice(0,240):U;return{provider:"claude",box:t,multiSelect:h,cursorIndex:y,promptId:U,groupId:J,...w?{custom:!0,customIndex:m.length,customText:b}:{},...g?{commitIndex:m.length+1}:{},dismissable:!0,...E?{questionIndex:E.questionIndex,questionTotal:E.questionTotal,currentTabLabel:E.currentTabLabel,tabs:E.tabs}:{},questions:[{question:S,header:P,multiSelect:h,options:L}]}}function Io(e,t){let n=String(t||"");return n?e==="claude"?hE.test(n)&&Tg.test(n)||wE.test(n)||vg.test(n)||gE.test(n.trimEnd().split(`
|
|
185
185
|
`).pop()||"")||yl(n)?!0:Gs.test(n)?!1:yE.test(n)&&bE.test(n)||kE.test(n)||Ig.test(n)||Ag.test(n)||xE.test(n)||SE.test(n.trimEnd().split(`
|
|
186
186
|
`).pop()||""):e==="codex"&&(Ls("codex",n)||/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 Cn(e,t,{customIndex:n}={}){return!e||!t?null:e.agent==="claude"?X2(t,e.name)||pH(t,e.name,{customIndex:n})||Eg(t,e.name)||Q2(t,e.name)||aH(t,e.name)||oH(t,e.name)||tH(t,e.name)||eH(t,e.name)||iH(t,e.name)||cH(t,e.name)||Y2(t,e.name):e.agent==="cursor"||e.agent==="codex"?MT(e.agent,t,e.name):null}async function vE(e){if(!e)return null;let t=await an(e.name).catch(()=>"");return Cn(e,t)}function $g(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 AE(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 AE(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 TE(e,t,n=""){let r=typeof n=="string"?n.trim():"";if(!r||!e?.custom)return{pre:$g(e,t).map(p=>({key:p})),text:"",post:[]};let o=Array.isArray(t?.[0])?t[0].filter(p=>Number.isInteger(p)&&p>=0):[],s=Number.isInteger(e.customIndex)?e.customIndex:e.questions?.[0]?.options?.length??0,a=Number.isInteger(e.cursorIndex)?e.cursorIndex:0,i=(p,w)=>{let m=w-p;return Array.from({length:Math.abs(m)},()=>({key:m>0?"Down":"Up"}))},c=[],l=a,u=typeof e.customText=="string"?Fp(e.customText):0,d=u>0?[{key:"BSpace",count:u+2},{key:"DC",count:u+2}]:[];if(e.multiSelect){for(let p of AE(e,o))c.push(...i(l,p),{key:"Enter"}),l=p;return c.push(...i(l,s),...d),{pre:c,text:r,post:[{key:"Down"},{key:"Enter"}]}}return c.push(...i(l,s),...d),{pre:c,text:r,post:[{key:"Enter"}]}}function EE(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 hE,Tg,qs,jp,mE,Eo,H2,dE,W2,q2,Fp,Up,wE,gE,J2,vg,Z2,Gs,yE,bE,kE,Ig,nH,Ag,sH,xE,SE,fE,Hp=K(()=>{kt();bl();Mp();hE=/to navigate\b.*\bEsc to cancel|Enter to select\b/,Tg=/Chat about this/i,qs=/^\s*(❯)?\s*(\d+)\.\s+(?:\[([ xX✔])\]\s+)?(.+?)\s*$/,jp=/^(type something|chat about this|submit|next)\b/i,mE=/^(submit|next)\b/i,Eo=/^[─—-]{6,}\s*$/,H2=/ctrl\+g to edit\b/i,dE=/\s+✔$/,W2=12,q2=6,Fp=e=>[...String(e)].length,Up=/[\u2500-\u257F\u2550-\u256F┌┐└┘├┤│┬┴┼─✂]/;wE=/^\s*Switch model\?\s*$/m;gE=/^\s*Enter to confirm\s*·\s*Esc to cancel\s*$/,J2=/^\s*[─—▔-]{6,}\s*$/;vg=/Resume from summary/i,Z2=/^\s*This session is\b/;Gs=/shift\+tab to cycle|⏵⏵ bypass permissions on|⏸ manual mode on/;yE=/Choose the text style that looks best with your terminal/,bE=/Let's get started\./;kE=/Select login method:/;Ig=/Paste code here if prompted/,nH=/^[A-Za-z0-9%&=+._~#?/:\-]+$/;Ag=/OAuth error:/,sH=/Press Enter to retry\./;xE=/Quick safety check:\s+Is this a project you created or one you trust/;SE=/^(.{0,60}?)Press\s+Enter\s+to\s+continue\s*[.…]{0,3}\s*$/;fE=e=>Up.test(e)||/notes\s*press|press n to add/i.test(e)||/^\s*notes?\s*$/i.test(e)});function Wp(e,t,n){if(!e||!t)return null;for(let r of fH)if(r.provider===e.agent)try{if(r.match(t,n))return r}catch{}return null}function mH(e){let t=Rg.get(e);return t||(t={sentAt:[],last:0,emitted:new Set},Rg.set(e,t)),t}function $E(e,t,n=Date.now()){let r=mH(e);if(r.sentAt=r.sentAt.filter(s=>n-s<IE),r.sentAt.length>=_E)return{action:"give-up"};if(n-r.last<hH)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 RE(e,t=Date.now()){let n=Rg.get(e);return n?n.sentAt.filter(r=>t-r<IE).length>=_E:!1}var fH,hH,_E,IE,Rg,Og=K(()=>{fH=[{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||""}
|
|
187
187
|
${String(t||"")}`;return/Try the new fullscreen renderer|Flicker-free output/i.test(o)},keys:["Escape"]}];hH=5e3,_E=5,IE=3600*1e3,Rg=new Map});function CE(e,t){let n=pi.get(e);return!n||Date.now()-n.at>t?null:{busy:n.busy,at:n.at}}function qp(e,t,n){let{state:r,reason:o}=xl(t,cn(e,n));if(r!=="unknown"){if(e){let a=Date.now();for(let[i,c]of pi)a-c.at>=OE()&&pi.delete(i);pi.set(e,{busy:r==="busy",at:a}),r==="busy"&&Mg.set(e,a)}return r==="busy"}if(o!=="narrow"||!e)return!1;let s=pi.get(e);return s?Date.now()-s.at>=OE()?(pi.delete(e),!1):s.busy:!1}async function $o(e,t){let n={working:!1,prompted:!1,awaitingBackground:null};if(!e)return n;let r=cn(e,await Fe(e,{lines:rt}).catch(()=>""));if(!qp(e,t,r)){let o=hg(t,r);return o?{working:!1,prompted:!1,awaitingBackground:o}:n}if(Io(t,r)){let o=await an(e).catch(()=>r),s=Cn({name:e,agent:t},o);if(s)return!Wp({name:e,agent:t},s,o)||RE(e)?(Mg.set(e,Date.now()),{working:!1,prompted:!0,awaitingBackground:null}):n}return{working:!0,prompted:!1,awaitingBackground:null}}async function Ks(e,t){let n=await $o(e,t);return n.working||n.awaitingBackground!=null}var OE,pi,Mg,ME,Vs=K(()=>{kt();Ws();Hp();Og();OE=()=>Number(process.env.BOSTRAT_NARROW_CARRY_MS)||9e4,pi=new Map,Mg=new Map,ME=e=>Mg.get(e)??null});function vH(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 TH(e){if(e.type==="queue-operation"&&e.operation==="enqueue")return NE.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"&&NE.test(t)?t:null}async function PE(e,t={}){return(await BE(e,t)).launches}async function DE(e,t={}){let{launches:n,done:r}=await BE(e,t);return n.filter(o=>!r.has(o.id))}async function BE(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(`
|
|
188
|
-
`)){let w=p.trim();if(!w||w[0]!=="{")continue;let m;try{m=JSON.parse(w)}catch{continue}if(m.isSidechain)continue;let
|
|
189
|
-
`).trim():"",LH=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],HE=process.getBuiltinModule?.("node:sqlite"),hi={turns:[],trailingCommands:[],model:null,requestIds:[]}});import jH from"node:fs/promises";function jg(e){return YE.set(e.agent,e),e}function Oo(e){return YE.get(e)||FH}async function Fg(e,t={}){return(await Oo(e.agent).readMessages(e,t)).map(Vp(e))}async function XE(e,t={}){return(await Oo(e.agent).readCommands(e,t)).map(Vp(e))}async function ZE(e,t={}){return(await Oo(e.agent).readJobs(e,t)).map(Vp(e))}async function zp(e,t={}){return(await Oo(e.agent).readOpenJobs(e,t)).map(Vp(e))}var mi,Dg,Bg,Lg,FH,YE,Vp,Jp=K(()=>{Mn();Tp();ti();LE();Pg();Ds();mi=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}},Dg=class extends mi{transcript(t){return!t?.cwd||!t?.sessionId?null:On(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?lg(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?JA(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?PE(r,n):[]}async readOpenJobs(t,n){let r=this.transcript(t);return r?DE(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await jH.stat(n)).mtimeMs)}catch{return null}}},Bg=class extends mi{async readMessages(t,n){return KE(t.cwd,t.sessionId,n)}async readCommands(t,n){return zE(t.cwd,t.sessionId,n)}async updatedAt(t){return JE(t.cwd,t.sessionId)}},Lg=class extends mi{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return QA(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return eT(t.cwd,this.sessionId(t),n)}async updatedAt(t){return tT(t.cwd,this.sessionId(t))}},FH=new mi("unknown"),YE=new Map;jg(new Dg("claude",Qw));jg(new Bg("cursor",Gp));jg(new Lg("codex",dl));Vp=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function Ug(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 QE(e,{timeoutMs:t,reason:n=null,onWait:r=null,deps:o=null}={}){let s={...GH,...o||{}},a=e?.name,i=e?.agent||null;if(!a)throw new Error("awaitQuiescence: box.name is required");let c=Number(t)||UH(),l=HH(),u=s.now(),d=0,p=0,w=!1,m=null;for(;;){p++;let
|
|
188
|
+
`)){let w=p.trim();if(!w||w[0]!=="{")continue;let m;try{m=JSON.parse(w)}catch{continue}if(m.isSidechain)continue;let h=TH(m);if(h){let b=h.match(AH)?.[1]?.trim();b&&a.add(b);continue}let g=m.message?.content;if(!Array.isArray(g))continue;let y=m.timestamp?Date.parse(m.timestamp):null;for(let b of g)if(!(!b||typeof b!="object")){if(b.type==="tool_use"&&b.id){if(b.name==="Agent"){let x=b.input||{};o.set(b.id,{id:b.id,kind:"agent",name:String(x.description||"").trim()||null,detail:String(x.subagent_type||"").trim()||null,ts:y,proven:!1})}else if(b.name==="Bash"){let x=String(b.input?.command||"").trim(),v={id:b.id,kind:"command",name:String(b.input?.description||"").trim()||(x?ei(x):null),detail:x?ei(x):null,ts:y,proven:b.input?.run_in_background===!0};v.proven?o.set(b.id,v):c.set(b.id,v)}else if(xH.has(b.name)){let x=b.input?.task_id??b.input?.shell_id??b.input?.bash_id;x&&u.set(b.id,{taskId:String(x),ts:y})}}else if(b.type==="tool_result"&&b.tool_use_id){let x=EH(b.content);if(wH.test(x)){s.add(b.tool_use_id);let P=x.match(kH)?.[1];P&&l.set(P,b.tool_use_id)}let v=x.match(bH)?.[1];v&&l.set(v,b.tool_use_id);let S=x.match(gH);if(S){l.set(S[1].trim(),b.tool_use_id);let P=c.get(b.tool_use_id);P&&(c.delete(b.tool_use_id),P.proven=!0,P.outputFile=x.match(yH)?.[1]?.replace(/\.$/,"")||null,o.set(P.id,P))}let E=u.get(b.tool_use_id);if(E){u.delete(b.tool_use_id);let{message:P,taskId:L}=vH(x);if(!b.is_error&&SH.test(P)){let $=l.get(E.taskId)??(L?l.get(L):void 0);$&&(a.add($),i.set($,y??E.ts??null))}}}}}let d=[];for(let p of o.values()){if(!p.proven&&!s.has(p.id))continue;let{proven:w,...m}=p;m.stoppedTs=i.has(p.id)?i.get(p.id):null,d.push(m)}return{launches:d.slice(-n),done:a,stopped:i}}var wH,gH,yH,bH,kH,xH,SH,NE,AH,EH,LE=K(()=>{Mn();ti();wH=/^Async (?:agent|task) launched/i,gH=/^Command did not complete within its [^\n]*?moved to the background \(ID: ([^)]+)\)/i,yH=/Output is being written to:\s*(\S+)/i,bH=/^Command running in background with ID:\s*([^\s.]+)/i,kH=/\bagentId:\s*([A-Za-z0-9_-]+)/,xH=new Set(["TaskStop","KillShell"]),SH=/^Successfully (?:stopped|killed)\b/i;NE=/^\s*<task-notification>/i,AH=/<tool-use-id>([\s\S]*?)<\/tool-use-id>/i;EH=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 Ro(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 _H(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 jE(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:Nn(`read ${Ro(r,n)}${o?` (lines ${o}\u2013${s??"end"})`:""}`,140),description:o?`Read lines ${o}\u2013${s??"end"} of ${fi(r)}`:`Read ${fi(r)}`}}case"Grep":{let r=t?.pattern;if(!r)return null;let o=t?.path?Ro(t.path,n):null,s=t?.glob?` --glob ${Cg(t.glob)}`:"",a=Nn(String(r),40);return{command:Nn(`grep ${Cg(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?Ro(t.target_directory,n):null;return{command:Nn(`glob ${Cg(r)}${o&&o!=="."?` ${o}`:""}`,140),description:`Find files matching \u201C${Nn(String(r),40)}\u201D`}}case"StrReplace":return t?.path?{command:Nn(`edit ${Ro(t.path,n)}`,140),description:`Edit ${fi(t.path)}`}:null;case"Write":return t?.path?{command:Nn(`write ${Ro(t.path,n)}`,140),description:`Write ${fi(t.path)}`}:null;case"Delete":return t?.path?{command:Nn(`delete ${Ro(t.path,n)}`,140),description:`Delete ${fi(t.path)}`}:null;case"ReadLints":{let o=(Array.isArray(t?.paths)?t.paths:[]).map(s=>Ro(s,n)).filter(Boolean);return{command:Nn(o.length?`lints ${o.join(" ")}`:"lints",140),description:"Check lints"}}case"ApplyPatch":{let r=_H(t);if(!r.length)return null;let o=r.length>1?` (+${r.length-1} more)`:"";return{command:Nn(`apply_patch ${Ro(r[0],n)}${o}`,140),description:r.length>1?`Patch ${r.length} files`:`Patch ${fi(r[0])}`}}case"Await":{let r=t?.shell_id??t?.task_id;return{command:Nn(`await ${r??"background output"}`,140),description:"Wait for a background command"}}default:return null}}var Gp,Nn,fi,Cg,FE=K(()=>{Gp=new Set(["Shell","Read","Grep","Glob","StrReplace","Write","ReadLints","Delete","ApplyPatch","Await"]),Nn=(e,t=88)=>e.length>t?`${e.slice(0,t).trimEnd()}\u2026`:e,fi=e=>String(e).replace(/\/+$/,"").split("/").pop()||String(e);Cg=e=>`"${String(e).replace(/"/g,'\\"')}"`});import Il from"node:fs";import IH from"node:fs/promises";import zs from"node:path";import $H from"node:os";import RH from"node:crypto";import OH from"node:zlib";function WE(e){let t=RH.createHash("md5").update(String(e)).digest("hex");return zs.join(MH,t)}function qE(e){try{let t=JSON.parse(Il.readFileSync(zs.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 CH(e){let t=WE(e),n;try{n=Il.readdirSync(t,{withFileTypes:!0}).filter(o=>o.isDirectory())}catch{return null}let r=null;for(let o of n){let s=zs.join(t,o.name),a=zs.join(s,"store.db");if(!Il.existsSync(a))continue;let i=qE(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 Kp(e,t){if(!e)return null;if(t){let n=zs.join(WE(e),t),r=zs.join(n,"store.db");if(Il.existsSync(r))return{id:t,dir:n,store:r,...qE(n)||{createdAtMs:null,updatedAtMs:null}}}return CH(e)}function UE(e,t){let n=e.prepare("SELECT data FROM blobs WHERE id = ?").get(t);return n?Buffer.from(n.data):null}function NH(e){if(!e)return null;let t=e;if(t.length>1&&t[0]===31&&t[1]===139)try{t=OH.gunzipSync(t)}catch{}try{return JSON.parse(t.toString("utf8"))}catch{return null}}function PH(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 DH(e,t){if(!Array.isArray(e))return[];let n=[];for(let r of e){if(!r||r.type!=="tool-call"||!Gp.has(r.toolName))continue;let o=jE(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 Ng(e,t){if(!HE)return hi;let{DatabaseSync:n}=HE,r;try{r=new n(e,{readOnly:!0})}catch{return hi}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 hi;let s;try{s=JSON.parse(Buffer.from(String(o.value),"hex").toString("utf8"))}catch{return hi}let a=s.lastUsedModel||null,i=s.latestRootBlobId?UE(r,s.latestRootBlobId):null;if(!i)return{...hi,model:a};let c=[],l=[],u=[],d=null,p=[];for(let w of PH(i)){let m=NH(UE(r,w));if(!m)continue;let h=m.providerOptions?.cursor;if(h?.requestId&&p.push(h.requestId),h?.modelProviderMessageId&&p.push(h.modelProviderMessageId),m.role!=="assistant")continue;if(Array.isArray(m.content))for(let b of m.content){let x=b?.providerOptions?.cursor?.modelName;x&&(d=x)}l.push(...DH(m.content,t).map((b,x)=>({...b,id:b.id||`${w}:${x}`}))),u.push(...LH(m.content));let g=BH(m.content);if(!g)continue;let y=[...new Set(u)];u=[],c.push({id:w,text:g,tools:y.length?y:void 0,commands:l,model:d}),l=[]}return{turns:c,trailingCommands:l,model:a,requestIds:p}}catch{return hi}finally{try{r.close()}catch{}}}function GE(e,t){let n=e.updatedAtMs;if(!n)try{n=Math.round(Il.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 KE(e,t,{limit:n=80}={}){let r=Kp(e,t);if(!r)return[];let{turns:o,model:s}=await Ng(r.store,e);if(!o.length)return[];let a=o.slice(-n),{tsAt:i}=GE(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 VE(e,t){let n=Kp(e,t);if(!n)return null;let{turns:r,requestIds:o,model:s}=await Ng(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 zE(e,t,{limit:n=80}={}){let r=Kp(e,t);if(!r)return[];let{turns:o,trailingCommands:s}=await Ng(r.store,e);if(!o.length&&!s.length)return[];let a=o.slice(-n),{end:i,tsAt:c}=GE(r,a.length||1),l=[];a.forEach((u,d)=>{for(let p of u.commands)l.push({...p,summary:vo(p.command,p.description),ts:c(d)})});for(let u of s)l.push({...u,summary:vo(u.command,u.description),ts:i+1});return l}async function JE(e,t){let n=Kp(e,t);if(!n)return null;if(n.updatedAtMs)return n.updatedAtMs;try{return Math.round((await IH.stat(n.store)).mtimeMs)}catch{return null}}var MH,BH,LH,HE,hi,Pg=K(()=>{ti();FE();MH=process.env.BOSTRAT_CURSOR_CHATS||zs.join($H.homedir(),".cursor","chats");BH=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(`
|
|
189
|
+
`).trim():"",LH=e=>Array.isArray(e)?e.filter(t=>t&&t.type==="tool-call"&&t.toolName).map(t=>t.toolName):[],HE=process.getBuiltinModule?.("node:sqlite"),hi={turns:[],trailingCommands:[],model:null,requestIds:[]}});import jH from"node:fs/promises";function jg(e){return YE.set(e.agent,e),e}function Oo(e){return YE.get(e)||FH}async function Fg(e,t={}){return(await Oo(e.agent).readMessages(e,t)).map(Vp(e))}async function XE(e,t={}){return(await Oo(e.agent).readCommands(e,t)).map(Vp(e))}async function ZE(e,t={}){return(await Oo(e.agent).readJobs(e,t)).map(Vp(e))}async function zp(e,t={}){return(await Oo(e.agent).readOpenJobs(e,t)).map(Vp(e))}var mi,Dg,Bg,Lg,FH,YE,Vp,Jp=K(()=>{Mn();Tp();ti();LE();Pg();Ds();mi=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}},Dg=class extends mi{transcript(t){return!t?.cwd||!t?.sessionId?null:On(t.cwd,t.sessionId)}async readMessages(t,n){let r=this.transcript(t);return r?lg(r,n):[]}async readCommands(t,n){let r=this.transcript(t);return r?JA(r,n):[]}async readJobs(t,n){let r=this.transcript(t);return r?PE(r,n):[]}async readOpenJobs(t,n){let r=this.transcript(t);return r?DE(r,n):[]}async updatedAt(t){let n=this.transcript(t);if(!n)return null;try{return Math.round((await jH.stat(n)).mtimeMs)}catch{return null}}},Bg=class extends mi{async readMessages(t,n){return KE(t.cwd,t.sessionId,n)}async readCommands(t,n){return zE(t.cwd,t.sessionId,n)}async updatedAt(t){return JE(t.cwd,t.sessionId)}},Lg=class extends mi{sessionId(t){return t?.pinned?t.sessionId:null}async readMessages(t,n){return QA(t.cwd,this.sessionId(t),n)}async readCommands(t,n){return eT(t.cwd,this.sessionId(t),n)}async updatedAt(t){return tT(t.cwd,this.sessionId(t))}},FH=new mi("unknown"),YE=new Map;jg(new Dg("claude",Qw));jg(new Bg("cursor",Gp));jg(new Lg("codex",dl));Vp=e=>t=>({...t,box:e.name,agent:e.agent,boxRole:e.role})});function Ug(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 QE(e,{timeoutMs:t,reason:n=null,onWait:r=null,deps:o=null}={}){let s={...GH,...o||{}},a=e?.name,i=e?.agent||null;if(!a)throw new Error("awaitQuiescence: box.name is required");let c=Number(t)||UH(),l=HH(),u=s.now(),d=0,p=0,w=!1,m=null;for(;;){p++;let h=await s.capture(a),g=s.busyRead(i,h);if(g.reason==="blocked"){let b=new Error(`${i||"the agent"} in "${a}" is sitting at a login or trust gate \u2014 answer it in the terminal, then retry`);throw b.code="quiescence-blocked",b.detail={blocked:!0},b}if(m={busy:g.state==="busy",unknown:g.state==="unknown",awaitingBackground:s.awaitingBackground(i,h),prompted:!1,jobs:[]},m.busy){let b=await s.turnState(a,i).catch(()=>({prompted:!1}));m.prompted=b?.prompted===!0}if(!m.busy&&!m.unknown&&!m.awaitingBackground){let b=await s.openJobs(e).catch(()=>[]);m.jobs=(Array.isArray(b)?b:[]).map(x=>({id:x.id??null,name:x.name??null,kind:x.kind??null}))}let y=!m.busy&&!m.unknown&&!m.awaitingBackground&&!m.prompted&&m.jobs.length===0;if(d=y?d+1:0,d>=WH){let b=s.now()-u;return w&&ne({flow:"quiescence",phase:"quiet",sessionName:a,agent:i,reason:n,waitedMs:b,reads:p}).catch(()=>{}),{waitedMs:b,reads:p,waited:w,detail:m}}if(!y&&!w&&(w=!0,ne({flow:"quiescence",phase:"waiting",sessionName:a,agent:i,reason:n,detail:m}).catch(()=>{}),r&&await r(m)),s.now()-u>=c){let b=new Error(`waited ${Math.round(c/1e3)}s for ${Ug(m)} in "${a}" to finish`);throw b.code="quiescence-timeout",b.detail=m,b.waitedMs=s.now()-u,ne({flow:"quiescence",phase:"timeout",sessionName:a,agent:i,reason:n,waitedMs:b.waitedMs,reads:p,detail:m,error:b.message}).catch(()=>{}),b}await s.sleep(l)}}var UH,HH,WH,qH,GH,e_=K(()=>{kt();Ws();Vs();Jp();$n();UH=()=>Number(process.env.BOSTRAT_QUIESCENCE_TIMEOUT_MS)||6e5,HH=()=>Number(process.env.BOSTRAT_QUIESCENCE_POLL_MS)||1500,WH=2,qH=e=>new Promise(t=>setTimeout(t,e)),GH={capture:async e=>cn(e,await Fe(e,{lines:rt})),busyRead:xl,awaitingBackground:LT,turnState:$o,openJobs:zp,now:()=>Date.now(),sleep:qH}});import KH from"node:fs";import Mo from"node:fs/promises";import Co from"node:path";function l_(e){let t=vs(String(e??"")),n=Buffer.byteLength(t,"utf8");return n<=t_?{content:t,bytes:n,truncated:!1}:{content:`${Buffer.from(t,"utf8").subarray(0,t_).toString("utf8").replace(/�+$/,"")}
|
|
190
190
|
|
|
191
|
-
[\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function tW(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(r_.test(s)){if(r.length>=m_)continue;let a=eW(s.replace(r_,"").replace(/[.;,:]+$/,""),w_,ZH);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>n_&&(o=`${o.slice(0,n_-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function g_(e,t,{timeoutMs:n=9e4}={}){let r=Co.join(t,YH),o=Co.join(r,XH);await Mo.mkdir(r,{recursive:!0});let s=await Yp(o),a=await _e(e);if(!a)throw new Error(`session "${e}" not found`);return await Xp(e,a,QH(o)),await A_(o,s,n),tW(await Mo.readFile(o,"utf8"))}function y_(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===d_||n===h_;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(u_)||n===VH||r.startsWith(p_)||r.startsWith(f_)}function b_(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-nW;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 k_(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 x_(e,{windows:t=[]}={}){if(y_(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 Zp(e){return Hg.get(e)||null}async function S_(e){let t=Hg.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await _e(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,i_,c_)};return Hg.set(e,r),sW(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function sW(e,t){e.step="summarize",await v_(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 _e(e.name);await Xp(e.name,n,"/clear"),await qg(rW),e.step="resume",await Xp(e.name,n,JH),e.step="done",e.finishedAt=Date.now()}async function o_(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 QE({...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||aW)===iW)throw i;return await ne({flow:"checkpoint",phase:"quiescence-timeout",sessionName:t,gate:e,waitedMs:i.waitedMs,detail:i.detail,still:Ug(i.detail),paneTail:!0}),r.onResume&&await r.onResume(e),{outcome:"timeout",waitedMs:i.waitedMs,waited:!0,detail:i.detail}}}async function v_(e,t,{timeoutMs:n=oW,quiesce:r=null}={}){let o=Co.join(t,i_),s=Co.join(o,c_);await Mo.mkdir(o,{recursive:!0});let a=await _e(e),i=await o_("pre-drive",e,a,r),c=await Yp(s);await ne({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:s,beforeMtime:c,quiescence:i.outcome,waitedMs:i.waitedMs});try{await Xp(e,a,zH(s)),await A_(s,c,n)}catch(w){throw w&&typeof w=="object"&&(w.quiescence={pre:i,post:{outcome:"skipped"}}),w}let l=await o_("post-write",e,a,r);await ne({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:s,afterMtime:await Yp(s),quiescence:l.outcome,waitedMs:l.waitedMs});let u=await JT(t,s,{exclude:w=>y_(w.role,w.text)});await ne({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:s,...u});let d=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(d){await D({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 w=await Mo.readFile(s,"utf8");await D({id:d,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...l_(w),ts:Date.now()}})}catch{}}await $w(t);let p=await cW(o,s);return d&&await mA(d,p||s,{box:e,agent:a?.agent??null}),{file:s,quiescence:{pre:i,post:l}}}async function Qp(e,{timeoutMs:t,quiesce:n=null}={}){let r=await _e(e);if(!r)throw new Error(`session "${e}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${e}"`);return v_(e,r.cwd,{...t?{timeoutMs:t}:{},quiesce:n})}function Wg(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 ef(e,t,{trackName:n="this Track"}={}){let r=await V({id:e,cwd:t}),o=lE(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=Co.join(t,s_);return await Mo.mkdir(Co.dirname(s),{recursive:!0}),await Mo.writeFile(s,o,"utf8"),await D({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...l_(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),s_}async function Yp(e){try{return(await Mo.stat(e)).mtimeMs}catch{return 0}}async function A_(e,t,n){let r=Date.now()+n;for(;;){if(await Yp(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await qg(2e3)}}async function cW(e,t){try{if(!KH.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=Co.join(e,`${n}.md`);return await Mo.copyFile(t,r),r}catch{return null}}function qg(e){return new Promise(t=>setTimeout(t,e))}function a_(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 Xp(e,t,n){if(t){let o=a_(t.agent);await Mr({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await _e(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await tt(e,["Escape"],{kind:"drive-wipe"}),await qg(150),await Ya(e,al,{kind:"drive-wipe"}),await ot(e,n,{kind:"orchestration-drive",...ar(r.agent,n)}),await Tl({sessionName:e,agent:r.agent,agentCmd:a_(r.agent),text:n,flow:"orchestration-drive"})}var i_,c_,t_,u_,d_,p_,VH,zH,JH,f_,h_,YH,XH,n_,m_,w_,ZH,QH,r_,eW,nW,rW,oW,Hg,aW,iW,s_,Gg=K(()=>{kt();Ws();$n();Al();mg();YT();Gc();be();ip();uE();e_();i_=".bostrat/handoff",c_="latest.md",t_=32*1024;u_="Checkpoint: write a work-in-progress handoff",d_="HANDOFF WRITTEN",p_="Resume from .bostrat/handoff/latest.md",VH="/clear",zH=e=>`${u_} 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 ${d_} and take no further action.`,JH=`${p_}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,f_="Beat: write a",h_="BEAT WRITTEN",YH=".bostrat/arc",XH="beat.txt",n_=200,m_=4,w_=5,ZH=36,QH=e=>`${f_} 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 ${m_} further lines, each starting with "- " and naming ONE piece in at most ${w_} 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 ${h_} and take no further action.`,r_=/^(?:[-–—*•·]|\d+[.)])\s+/,eW=(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};nW=6e5;rW=3500,oW=3e5,Hg=new Map;aW="proceed",iW="reject";s_=".bostrat/handoff/status-latest.md"});var cr,T_=K(()=>{cr=e=>e.trim().normalize("NFKD").replace(/[\u0300-\u036f]/g,"").replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").replace(/\.{2,}/g,"-").replace(/^[.-]+|[.-]+$/g,"").toLowerCase().slice(0,100).replace(/[.-]+$/g,"")||"track"});function Po(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!tf.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 I_(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:Po(o.from,"from",n),toMs:Po(o.to,"to",n)}))}return t}function Vg(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 uW(e){if(!e)return null;let t=String(e).trim();if(No[t])return t;if(E_[t])return E_[t];let n=null;for(let r of Object.keys(No))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function dW(e){if(!e||e===No)return lW;let t=__.get(e);return t||(t=I_(e),__.set(e,t)),t}function $_(e,t,n={}){let{table:r,speed:o}=n,s=dW(r),a=r&&r!==No?s[e]?e:null:uW(e);if(!a)return null;let i=Vg(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 lr(e,t={},n,r){let o=$_(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 pW(e=No){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:Po(a.from,"from",n),toMs:Po(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`),tf.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 hW({now:e=Date.now(),table:t=No,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...fW,...n},a=[],i=Vg(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:Po(d.from,"from",c),toMs:Po(d.to,"to",c),verifiedMs:tf.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,w=d.fromMs>i&&d.fromMs-i<=o*Kg;p&&i-d.verifiedMs>r*Kg&&a.push(`${c}: current rate last verified ${d.verifiedAt} (>${r}d) \u2014 re-check the vendor page and bump verifiedAt`),w&&d.fromMs-d.verifiedMs>s*Kg&&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 wi({now:e=Date.now(),table:t=No,...n}={}){let r=Vg(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=Po(l.from,"from",i),d=Po(l.to,"to",i);r>=u&&r<=d&&tf.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=[...pW(t),...hW({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var No,E_,tf,lW,__,R_,fW,Kg,Nr=K(()=>{No={"claude-opus-5-5":[{from:null,to:null,input:4,output:20,cacheWrite:8,cacheRead:.2,cacheReadX:.05,fast:{input:8,output:40,cacheWrite:16,cacheRead:.4},verifiedAt:"2026-09-28",note:"verified 2026-09-28 against platform.claude.com/docs/en/about-claude/pricing: $4/$20, 1h cache write $8 (2\xD7), cache hits $0.20 (0.05\xD7 \u2014 footnote 2), fast $8/$40; added before any fleet turn was recorded."}],"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)."}]},E_={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"},tf=/^\d{4}-\d{2}-\d{2}$/;lW=I_(No);__=new WeakMap;R_=(e,t,n)=>$_(e,t,n)!==null;fW=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),Kg=864e5});function mW(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function M_(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function gn(e){let t=e.payload?.model||"unknown",n=mW(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=lr(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&&!R_(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function Do(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=O_();for(let p of n){let{usd:w,model:m,tokens:f,repriced:g,unpriced:y,asRecorded:b}=gn(p);i+=b;let x=p.provider||"unknown",v=p.boxId||"unattributed";if(g&&c++,y&&(l++,u.add(m)),a+=w,M_(d,f),r[m]||={usd:0,tokens:O_(),events:0},r[m].usd+=w,r[m].events+=1,M_(r[m].tokens,f),o[x]||={usd:0,events:0},o[x].usd+=w,o[x].events+=1,s[v]||={usd:0,events:0,provider:x,models:new Set,label:t[v]||v},s[v].usd+=w,s[v].events+=1,m!=="unknown"&&s[v].models.add(m),p.epoch!=null){let S=(s[v].epochs||={})[p.epoch]||={usd:0,events:0,provider:x,models:new Set};S.usd+=w,S.events+=1,S.provider=x,m!=="unknown"&&S.models.add(m)}}return{totalUsd:gi(a),asRecordedUsd:gi(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:nf(r,p=>({...p,usd:gi(p.usd)})),byProvider:nf(o,p=>({...p,usd:gi(p.usd)})),byBox:nf(s,p=>({usd:gi(p.usd),events:p.events,provider:p.provider,label:p.label,models:[...p.models],...p.epochs?{epochs:nf(p.epochs,w=>({usd:gi(w.usd),events:w.events,provider:w.provider,models:[...w.models]}))}:{}}))}}var O_,gi,nf,Bo=K(()=>{Nr();O_=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});gi=e=>Math.round(e*1e4)/1e4,nf=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function wW(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 C_(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,w]=d.split("#");return`${p.split("/").pop()}#${w}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(zg(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(zg(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(`${zg(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=Do(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?wW(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var zg,N_=K(()=>{Bo();zg=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as gW}from"node:child_process";import{promisify as yW}from"node:util";import{randomUUID as bW}from"node:crypto";import P_ from"node:fs/promises";async function Yg(e,t){let n=Date.now()+t;for(;;){if(await sr(e))return!0;if(Date.now()>n)return!1;await jo(j_)}}function TW(e){let t=String(e||"").split(`
|
|
191
|
+
[\u2026 truncated by bostrat at 32 KiB \u2014 full artifact in the workspace]`,bytes:n,truncated:!0}}function tW(e){let t=String(e||"").split(/\r?\n/).map(s=>s.trim()).filter(Boolean),n=[],r=[];for(let s of t)if(r_.test(s)){if(r.length>=m_)continue;let a=eW(s.replace(r_,"").replace(/[.;,:]+$/,""),w_,ZH);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>n_&&(o=`${o.slice(0,n_-1).trimEnd()}\u2026`),{text:o,items:r.length>1?r:[]}}async function g_(e,t,{timeoutMs:n=9e4}={}){let r=Co.join(t,YH),o=Co.join(r,XH);await Mo.mkdir(r,{recursive:!0});let s=await Yp(o),a=await _e(e);if(!a)throw new Error(`session "${e}" not found`);return await Xp(e,a,QH(o)),await A_(o,s,n),tW(await Mo.readFile(o,"utf8"))}function y_(e,t){let n=(t||"").trim();if(!n)return!1;if(e==="assistant")return n===d_||n===h_;let r=n.replace(/^\/[a-z0-9:_-]+\s+/i,"");return r.startsWith(u_)||n===VH||r.startsWith(p_)||r.startsWith(f_)}function b_(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-nW;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 k_(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 x_(e,{windows:t=[]}={}){if(y_(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 Zp(e){return Hg.get(e)||null}async function S_(e){let t=Hg.get(e);if(t&&!t.finishedAt)throw new Error("a handoff is already running for this session");let n=await _e(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,i_,c_)};return Hg.set(e,r),sW(r,n.cwd).catch(o=>{r.error=o?.message||String(o),r.finishedAt=Date.now()}),r}async function sW(e,t){e.step="summarize",await v_(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 _e(e.name);await Xp(e.name,n,"/clear"),await qg(rW),e.step="resume",await Xp(e.name,n,JH),e.step="done",e.finishedAt=Date.now()}async function o_(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 QE({...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||aW)===iW)throw i;return await ne({flow:"checkpoint",phase:"quiescence-timeout",sessionName:t,gate:e,waitedMs:i.waitedMs,detail:i.detail,still:Ug(i.detail),paneTail:!0}),r.onResume&&await r.onResume(e),{outcome:"timeout",waitedMs:i.waitedMs,waited:!0,detail:i.detail}}}async function v_(e,t,{timeoutMs:n=oW,quiesce:r=null}={}){let o=Co.join(t,i_),s=Co.join(o,c_);await Mo.mkdir(o,{recursive:!0});let a=await _e(e),i=await o_("pre-drive",e,a,r),c=await Yp(s);await ne({flow:"checkpoint",phase:"summarize-start",sessionName:e,cwd:t,file:s,beforeMtime:c,quiescence:i.outcome,waitedMs:i.waitedMs});try{await Xp(e,a,zH(s)),await A_(s,c,n)}catch(w){throw w&&typeof w=="object"&&(w.quiescence={pre:i,post:{outcome:"skipped"}}),w}let l=await o_("post-write",e,a,r);await ne({flow:"checkpoint",phase:"summarize-done",sessionName:e,file:s,afterMtime:await Yp(s),quiescence:l.outcome,waitedMs:l.waitedMs});let u=await JT(t,s,{exclude:w=>y_(w.role,w.text)});await ne({flow:"checkpoint",phase:"seed-enriched",sessionName:e,file:s,...u});let d=/workspaces[/\\]([0-9a-f]{8})$/.exec(t||"")?.[1];if(d){await D({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 w=await Mo.readFile(s,"utf8");await D({id:d,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...l_(w),ts:Date.now()}})}catch{}}await $w(t);let p=await cW(o,s);return d&&await mA(d,p||s,{box:e,agent:a?.agent??null}),{file:s,quiescence:{pre:i,post:l}}}async function Qp(e,{timeoutMs:t,quiesce:n=null}={}){let r=await _e(e);if(!r)throw new Error(`session "${e}" not found`);if(!r.cwd)throw new Error(`can't resolve cwd for "${e}"`);return v_(e,r.cwd,{...t?{timeoutMs:t}:{},quiesce:n})}function Wg(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 ef(e,t,{trackName:n="this Track"}={}){let r=await V({id:e,cwd:t}),o=lE(r,{trackName:n,now:Date.now(),mode:"in-place"});if(!o)return null;let s=Co.join(t,s_);return await Mo.mkdir(Co.dirname(s),{recursive:!0}),await Mo.writeFile(s,o,"utf8"),await D({id:e,cwd:t},{type:"handoff.artifact",actor:"orchestrator",payload:{...l_(o),reconstructed:!0,ts:Date.now()}}).catch(()=>{}),s_}async function Yp(e){try{return(await Mo.stat(e)).mtimeMs}catch{return 0}}async function A_(e,t,n){let r=Date.now()+n;for(;;){if(await Yp(e)>t)return;if(Date.now()>r)throw new Error(`timed out waiting for the handoff file to be written (${e})`);await qg(2e3)}}async function cW(e,t){try{if(!KH.existsSync(t))return null;let n=new Date().toISOString().replace(/[:.]/g,"-"),r=Co.join(e,`${n}.md`);return await Mo.copyFile(t,r),r}catch{return null}}function qg(e){return new Promise(t=>setTimeout(t,e))}function a_(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 Xp(e,t,n){if(t){let o=a_(t.agent);await Mr({cwd:t.cwd,sessionId:t.sessionId,sessionName:e,agent:t.agent,agentCmd:o})}let r=await _e(e);if(!r)throw new Error(`session "${e}" disappeared before the orchestration prompt could be sent`);await tt(e,["Escape"],{kind:"drive-wipe"}),await qg(150),await Ya(e,al,{kind:"drive-wipe"}),await ot(e,n,{kind:"orchestration-drive",...ar(r.agent,n)}),await Tl({sessionName:e,agent:r.agent,agentCmd:a_(r.agent),text:n,flow:"orchestration-drive"})}var i_,c_,t_,u_,d_,p_,VH,zH,JH,f_,h_,YH,XH,n_,m_,w_,ZH,QH,r_,eW,nW,rW,oW,Hg,aW,iW,s_,Gg=K(()=>{kt();Ws();$n();Al();mg();YT();Gc();be();ip();uE();e_();i_=".bostrat/handoff",c_="latest.md",t_=32*1024;u_="Checkpoint: write a work-in-progress handoff",d_="HANDOFF WRITTEN",p_="Resume from .bostrat/handoff/latest.md",VH="/clear",zH=e=>`${u_} 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 ${d_} and take no further action.`,JH=`${p_}: read it, restate the Objective and the single next step in one line, then continue the work from 'Next steps'.`,f_="Beat: write a",h_="BEAT WRITTEN",YH=".bostrat/arc",XH="beat.txt",n_=200,m_=4,w_=5,ZH=36,QH=e=>`${f_} 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 ${m_} further lines, each starting with "- " and naming ONE piece in at most ${w_} 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 ${h_} and take no further action.`,r_=/^(?:[-–—*•·]|\d+[.)])\s+/,eW=(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};nW=6e5;rW=3500,oW=3e5,Hg=new Map;aW="proceed",iW="reject";s_=".bostrat/handoff/status-latest.md"});var cr,T_=K(()=>{cr=e=>e.trim().normalize("NFKD").replace(/[\u0300-\u036f]/g,"").replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"").replace(/\.{2,}/g,"-").replace(/^[.-]+|[.-]+$/g,"").toLowerCase().slice(0,100).replace(/[.-]+$/g,"")||"track"});function Po(e,t,n){if(e==null)return t==="from"?-1/0:1/0;if(!tf.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 I_(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:Po(o.from,"from",n),toMs:Po(o.to,"to",n)}))}return t}function Vg(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 uW(e){if(!e)return null;let t=String(e).trim();if(No[t])return t;if(E_[t])return E_[t];let n=null;for(let r of Object.keys(No))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function dW(e){if(!e||e===No)return lW;let t=__.get(e);return t||(t=I_(e),__.set(e,t)),t}function $_(e,t,n={}){let{table:r,speed:o}=n,s=dW(r),a=r&&r!==No?s[e]?e:null:uW(e);if(!a)return null;let i=Vg(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 lr(e,t={},n,r){let o=$_(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 pW(e=No){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:Po(a.from,"from",n),toMs:Po(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`),tf.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 hW({now:e=Date.now(),table:t=No,...n}={}){let{staleDays:r,leadDays:o,confirmDays:s}={...fW,...n},a=[],i=Vg(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:Po(d.from,"from",c),toMs:Po(d.to,"to",c),verifiedMs:tf.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,w=d.fromMs>i&&d.fromMs-i<=o*Kg;p&&i-d.verifiedMs>r*Kg&&a.push(`${c}: current rate last verified ${d.verifiedAt} (>${r}d) \u2014 re-check the vendor page and bump verifiedAt`),w&&d.fromMs-d.verifiedMs>s*Kg&&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 wi({now:e=Date.now(),table:t=No,...n}={}){let r=Vg(e)??Date.now(),o=null,s=[];for(let[i,c]of Object.entries(t))for(let l of c){let u=Po(l.from,"from",i),d=Po(l.to,"to",i);r>=u&&r<=d&&tf.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=[...pW(t),...hW({now:r,table:t,...n})];return{tableVerifiedAt:o,upcomingChanges:s,problems:a,ok:a.length===0}}var No,E_,tf,lW,__,R_,fW,Kg,Nr=K(()=>{No={"claude-opus-5-5":[{from:null,to:null,input:4,output:20,cacheWrite:8,cacheRead:.2,cacheReadX:.05,fast:{input:8,output:40,cacheWrite:16,cacheRead:.4},verifiedAt:"2026-09-28",note:"verified 2026-09-28 against platform.claude.com/docs/en/about-claude/pricing: $4/$20, 1h cache write $8 (2\xD7), cache hits $0.20 (0.05\xD7 \u2014 footnote 2), fast $8/$40; added before any fleet turn was recorded."}],"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)."}]},E_={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"},tf=/^\d{4}-\d{2}-\d{2}$/;lW=I_(No);__=new WeakMap;R_=(e,t,n)=>$_(e,t,n)!==null;fW=Object.freeze({staleDays:90,leadDays:14,confirmDays:30}),Kg=864e5});function mW(e){return e?{input:e.input||0,output:e.output||0,cacheRead:e.cacheRead||0,cacheWrite:e.cacheWrite??e.cacheCreation??0}:null}function M_(e,t){t&&(e.input+=t.input,e.output+=t.output,e.cacheRead+=t.cacheRead,e.cacheCreation+=t.cacheWrite)}function gn(e){let t=e.payload?.model||"unknown",n=mW(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=lr(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&&!R_(t,e.ts,o?{speed:o}:void 0);return{usd:a,model:t,tokens:n,repriced:i,unpriced:l,asRecorded:r}}function Do(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=O_();for(let p of n){let{usd:w,model:m,tokens:h,repriced:g,unpriced:y,asRecorded:b}=gn(p);i+=b;let x=p.provider||"unknown",v=p.boxId||"unattributed";if(g&&c++,y&&(l++,u.add(m)),a+=w,M_(d,h),r[m]||={usd:0,tokens:O_(),events:0},r[m].usd+=w,r[m].events+=1,M_(r[m].tokens,h),o[x]||={usd:0,events:0},o[x].usd+=w,o[x].events+=1,s[v]||={usd:0,events:0,provider:x,models:new Set,label:t[v]||v},s[v].usd+=w,s[v].events+=1,m!=="unknown"&&s[v].models.add(m),p.epoch!=null){let S=(s[v].epochs||={})[p.epoch]||={usd:0,events:0,provider:x,models:new Set};S.usd+=w,S.events+=1,S.provider=x,m!=="unknown"&&S.models.add(m)}}return{totalUsd:gi(a),asRecordedUsd:gi(i),totalTokens:d,turns:n.length,repricedTurns:c,unpricedTurns:l,unpricedModels:[...u],byModel:nf(r,p=>({...p,usd:gi(p.usd)})),byProvider:nf(o,p=>({...p,usd:gi(p.usd)})),byBox:nf(s,p=>({usd:gi(p.usd),events:p.events,provider:p.provider,label:p.label,models:[...p.models],...p.epochs?{epochs:nf(p.epochs,w=>({usd:gi(w.usd),events:w.events,provider:w.provider,models:[...w.models]}))}:{}}))}}var O_,gi,nf,Bo=K(()=>{Nr();O_=()=>({input:0,output:0,cacheRead:0,cacheCreation:0});gi=e=>Math.round(e*1e4)/1e4,nf=(e,t)=>Object.fromEntries(Object.entries(e).map(([n,r])=>[n,t(r)]))});function wW(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 C_(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,w]=d.split("#");return`${p.split("/").pop()}#${w}`});n.push(`Merged ${u.slice(0,4).join(", ")}${u.length>4?` +${u.length-4}`:""}`)}else s&&n.push(zg(s,"PR")+" opened");let a=Object.keys(e?.subtasks||{}).length||r.filter(u=>u.type==="subtask-delegated").length;a&&n.push(zg(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(`${zg(i.length,"handoff")} ${u}${i.length>3?"\u2026":""}`)}let c=Do(t);c.totalUsd>=.01&&n.push(`$${c.totalUsd.toFixed(2)}`);let l=Number.isFinite(e?.archivedAt)&&Number.isFinite(e?.createdAt)?wW(e.archivedAt-e.createdAt):null;return n.length&&l&&n.push(l),n.length?n.join(" \xB7 "):null}var zg,N_=K(()=>{Bo();zg=(e,t)=>`${e} ${t}${e===1?"":"s"}`});import{execFile as gW}from"node:child_process";import{promisify as yW}from"node:util";import{randomUUID as bW}from"node:crypto";import P_ from"node:fs/promises";async function Yg(e,t){let n=Date.now()+t;for(;;){if(await sr(e))return!0;if(Date.now()>n)return!1;await jo(j_)}}function TW(e){let t=String(e||"").split(`
|
|
192
192
|
`).map(n=>n.trimEnd()).filter(n=>n.trim());return!t.length||!SW.test(t[t.length-1])?!1:xW.test(t.slice(-vW).join(`
|
|
193
|
-
`))}async function EW(e,t){if(t!=="claude")return null;let n=Date.now()+AW;for(;;){if(await sr(e))return null;let r=await Fe(e,{lines:30});if(TW(r))return await ne({flow:"swap",phase:"exit-chooser",sessionName:e,from:t,paneTail:!0}),await tt(e,["Enter"],{kind:"swap-exit"}),"answered";if(Date.now()>n)return null;await jo(j_)}}async function _W(e,t){let n=D_[t]||D_.default;n.escape&&(await tt(e,["Escape"],{kind:"swap-exit"}),await jo(150)),n.wipe&&await Ya(e,al,{kind:"swap-exit"}),await wp(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=ar(t).submitDelayMs||0;return await jo(Math.max(r,250)),await tt(e,["Enter"],{kind:"swap-exit"}),{chooser:await EW(e,t)}}async function OW(e,{settleMs:t=IW,timeoutMs:n=$W,parse:r=!0}={}){let o=Date.now(),s=null,a=null;for(;;){let i=null,c=!0;try{let u=await P_.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 P_.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 jo(RW)}}async function Jg(e,t){try{let{stdout:n}=await Lo(oe,se("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function F_(e){await Lo(oe,se("respawn-pane","-k","-t",e))}async function Xg(e,{exitTimeoutMs:t=B_,fromAgent:n=null}={}){if(!qe(e))throw new Error("invalid session name");let r=!1;if(await sr(e))return{forced:r,chooser:null};let o=n||(await _e(e))?.agent||"agent",{chooser:s}=await _W(e,o),a=await Yg(e,t);if(await ne({flow:"swap",phase:"exit",sessionName:e,from:o,graceful:a,chooser:s,paneTail:!0}),!a&&(r=!0,await ne({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await F_(e),!await Yg(e,L_)))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);return{forced:r,chooser:s}}async function Zg(e,t={}){if(!qe(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await _e(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||ko(n),a=Number(t.exitTimeoutMs)||B_;if(await ne({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd}),s==="codex"){let b=await jd();b.waited&&await ne({flow:"cli-currency",phase:"spawn-gate",sessionName:e,...b}),Fd(e)}let{forced:i,chooser:c}=await Xg(e,{exitTimeoutMs:a,fromAgent:o});if(o==="claude"){let b=await OW(sw());await ne({flow:"swap",phase:"config-settled",sessionName:e,from:o,...b})}let l=s==="claude"&&Ms(n),u=l?Cd():null,d=await Jg(e,"ANTHROPIC_API_KEY"),p=!1;try{u?(await Lo(oe,se("set-environment","-t",e,"ANTHROPIC_API_KEY",u)),p=!0):d&&(await Lo(oe,se("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),p=!0)}catch(b){throw u?up(b,u):b}if(p&&!i&&(await F_(e),!await Yg(e,L_)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let w=!!t.resumeSessionId,m=t.resumeSessionId||bW(),f=w?n:nl(n,m,e),g=w?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(f);l&&await fo(r.cwd),s==="codex"&&await Ba(r.cwd),s==="cursor"&&await ja(r.cwd),await Cs(e),await Lo(oe,se("set-option","-t",e,"@bostrat-sid",m)),await Lo(oe,se("set-option","-t",e,"@bostrat-agent",s)),await jo(kW),l&&el().length&&(await Jg(e,Qc)||await Lo(oe,se("set-environment","-t",e,Qc,"1")).catch(()=>{}),await ot(e,`export ${Qc}=1`,{kind:"swap-env"}),await jo(150));let y=await Fw({cwd:r.cwd,name:e});if(y&&!await Jg(e,tl[1])){for(let x of tl)await Lo(oe,se("set-environment","-t",e,x,y)).catch(()=>{});let b=`'${y.replace(/'/g,"'\\''")}'`;await ot(e,`export ${tl.map(x=>`${x}=${b}`).join(" ")}`,{kind:"swap-env"}),await jo(150)}return await ot(e,f,{kind:"swap-launch"}),await ne({flow:"swap",phase:"launched",sessionName:e,from:o,to:s,paneTail:!0}),await ne({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:m,forced:i,chooser:c,envRespawned:p}),{name:e,cwd:r.cwd,sessionId:m,agent:s,pinned:g,forced:i,chooser:c,envRespawned:p,launchCmd:f}}var Lo,jo,B_,L_,j_,kW,D_,xW,SW,vW,AW,IW,$W,RW,U_=K(()=>{kt();Mc();Pd();As();Ud();Al();$n();Lo=yW(gW),jo=e=>new Promise(t=>setTimeout(t,e)),B_=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,L_=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,j_=250,kW=400,D_={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"}};xW=/Background work is running/,SW=/Enter to confirm\s*·\s*Esc to cancel/,vW=12,AW=Number(process.env.BOSTRAT_SWAP_CHOOSER_WAIT_MS)||3e3;IW=Number(process.env.BOSTRAT_CLAUDE_CONFIG_SETTLE_MS)||500,$W=Number(process.env.BOSTRAT_CLAUDE_CONFIG_SETTLE_TIMEOUT_MS)||5e3,RW=100});function Qg(e=process.env){return!!(Ue(e)&&e.BOSTRAT_PLANE_TOKEN)}async function ey({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!Qg(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),H_);try{let a=await W_(`${Ue(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 Js(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(!Qg(a))return{ok:!1,source:"unconfigured"};let c=rf.get(e.id)||0;if(i()-c<MW)return{ok:!1,source:"debounced"};rf.set(e.id,i());let l=await $l({env:a}),u=l.loops.find(w=>w.trackId===e.id);if(!u)return rf.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 ey({loopId:u.id,outcome:"errored",note:d.slice(0,500),env:a});return p.ok||rf.delete(e.id),{...p,loop:{id:u.id,name:u.name}}}async function $l({env:e=process.env}={}){if(!Qg(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),H_);try{let r=await W_(`${Ue(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 H_,W_,MW,rf,Rl=K(()=>{_t();H_=1e4,W_=(...e)=>fetch(...e);MW=10*6e4,rf=new Map});import{execFile as CW}from"node:child_process";import of from"node:fs/promises";import ty from"node:path";import{promisify as NW}from"node:util";function UW(e){let n=String(e||"").trim().match(/\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]+)?/);return n?n[0]:null}async function HW(e,{env:t=process.env}={}){let n=String(e||"").trim();if(!n)return null;let r=n.includes("/")?[ty.resolve(n)]:String(t.PATH||"").split(ty.delimiter).filter(Boolean).map(o=>ty.join(o,n));for(let o of r)try{await of.access(o,of.constants.X_OK);let s=await of.realpath(o),a=await of.stat(s);if(!a.isFile())continue;return{path:s,mtimeMs:a.mtimeMs}}catch{}return null}async function Ys({agent:e=null,agentCmd:t=null,env:n=process.env}={}){let r=String(t||(e?n[LW[e]]||BW[e]:"")||"").trim();if(!r)return null;let{realClaude:o,realCodex:s,realCursor:a}=vl({agent:e,agentCmd:r});if(!(o||s||a))return null;let i=await HW(r.split(/\s+/)[0],{env:n});if(!i)return null;let c=`${i.path}@${i.mtimeMs}`;return ny.has(c)||ny.set(c,Promise.resolve().then(()=>FW(i.path,{agent:e})).then(l=>UW(l)).catch(()=>null)),ny.get(c)}var PW,DW,BW,LW,ny,jW,FW,q_=K(()=>{Ws();PW=NW(CW),DW=8e3,BW={claude:"claude",codex:"codex",cursor:"cursor-agent"},LW={claude:"BOSTRAT_AGENT_CMD",codex:"BOSTRAT_CODEX_CMD",cursor:"BOSTRAT_CURSOR_CMD"},ny=new Map,jW=async e=>(await PW(e,["--version"],{timeout:DW})).stdout,FW=jW});function Fo(e){return typeof e=="string"?e.trim():""}var G_=K(()=>{});import ke from"node:fs/promises";import V_ from"node:os";import Q from"node:path";import{createHash as WW,randomUUID as ay}from"node:crypto";import{execFile as qW,spawn as GW}from"node:child_process";import{promisify as KW}from"node:util";function It(e=process.env){return{enabled:String(e.BOSTRAT_DEPS||"").toLowerCase()!=="off",root:e.BOSTRAT_DEPS_DIR||Q.join(QW(e),"deps"),capBytes:String(e.BOSTRAT_DEPS_CAP_GB??"").trim()===""?null:Math.max(0,Ol(e.BOSTRAT_DEPS_CAP_GB,5))*cy,generations:Math.max(1,Math.floor(Ol(e.BOSTRAT_DEPS_GENERATIONS,2))),timeoutMs:Math.max(1e3,Ol(e.BOSTRAT_DEPS_TIMEOUT_MS,20*6e4)),setup:String(e.BOSTRAT_DEPS_SETUP||"").toLowerCase()!=="off",devcontainer:String(e.BOSTRAT_DEPS_DEVCONTAINER||"").toLowerCase()!=="off",setupTimeoutMs:Math.max(1e3,Ol(e.BOSTRAT_DEPS_SETUP_TIMEOUT_MS,15*6e4)),retryMs:Math.max(0,Ol(e.BOSTRAT_DEPS_RETRY_MS,30*6e4)),bins:{npm:e.BOSTRAT_DEPS_NPM||null,pnpm:e.BOSTRAT_DEPS_PNPM||null,yarn:e.BOSTRAT_DEPS_YARN||null}}}function eq(e){return!Number.isFinite(e)||e<=0?ry:Math.min(ry,Math.floor(e*ZW))}async function tq(e=It(),{statfs:t=ke.statfs}={}){if(e.capBytes!=null)return e.capBytes;let n=Q.resolve(e.root);for(;;)try{let r=await t(n);return eq(Number(r.bsize)*Number(r.blocks))}catch{let r=Q.dirname(n);if(r===n)return ry;n=r}}function uy({repoId:e,relDir:t,lockHash:n,nodeMajor:r=nq},o=It()){let s=String(e).toLowerCase(),a=t||".",i=`${r}-${n}`,c=Q.join(o.root,...s.split("/").map(ly),rq(a));return{repo:s,relDir:a,gen:i,key:`${s}:${a}:${i}`,group:c,dir:Q.join(c,i)}}async function dy(e,t=null){let n=[];for(let[c,l]of Object.entries(Pn))(t?t.includes(l.lockfile):await ke.lstat(Q.join(e,l.lockfile)).catch(()=>null)!==null)&&n.push(c);if(!n.length)return null;let r=null;if(n.length>1){let c=await Cl(Q.join(e,cf)).then(l=>JSON.parse(l),()=>null).catch(()=>null);r=n.find(l=>String(c?.packageManager??"").startsWith(`${l}@`))??null}let o=r??n[0],s=Pn[o];if(o!=="yarn")return{tool:o,lockfile:s.lockfile,command:s.command};let a=(await Cl(Q.join(e,s.lockfile))??"").slice(0,2e3),i=/^__metadata:/m.test(a);return{tool:o,lockfile:s.lockfile,flavor:i?"berry":"classic",command:i?s.berry.command:s.command}}async function oq(e,t,n){let r;try{r=JSON.parse(n)}catch{return Dt("unparseable manifest or lockfile")}return t.workspaces||r?.packages?.[""]?.workspaces?Dt("npm workspaces"):[...Object.values(r?.packages??{}),...Object.values(r?.dependencies??{})].some(a=>a&&(a.link===!0||/^file:/.test(String(a.resolved??""))||/^file:/.test(String(a.version??""))))?Dt(uf):{configs:[{name:".npmrc",ephemeral:!0}]}}async function sq(e,t,n){let r=await Cl(Q.join(e,"pnpm-workspace.yaml"));return t.workspaces||r!==null&&/^packages\s*:/m.test(r)?Dt("pnpm workspace"):/^\s+(?:specifier|version):\s*['"]?(?:link|file|workspace):/m.test(n)||/@(?:file|link):/.test(n)?Dt(uf):{configs:[{name:".npmrc",ephemeral:!0},{name:"pnpm-workspace.yaml"},{name:".pnpmfile.cjs"}]}}async function aq(e,t,n,r){if(t.workspaces)return Dt("yarn workspaces");if(r==="classic")return/@(?:file|link):/.test(n)||/^\s+resolved "file:/m.test(n)?Dt(uf):{configs:[{name:".npmrc",ephemeral:!0},{name:".yarnrc",ephemeral:!0}]};let o=await Cl(Q.join(e,".yarnrc.yml"))??"";return/^nodeLinker:\s*["']?node-modules["']?\s*$/m.test(o)?/^(?:yarnPath|plugins)\s*:/m.test(o)?Dt("yarn is vendored in the repo (yarnPath / plugins)"):/@(?:portal|link|file):/.test(n)||/@workspace:(?!\.["',\s])/.test(n)?Dt(uf):{configs:[{name:".yarnrc.yml",ephemeral:!0}]}:Dt("yarn Plug'n'Play (no node_modules to share)")}async function py(e,t=null){let n=await dy(e,t);if(!n)return Dt("no lockfile");let r={tool:n.tool,command:n.command},o=await Cl(Q.join(e,cf));if(o===null)return Dt(`no ${cf}`,r);let s=await ke.readFile(Q.join(e,n.lockfile)).catch(()=>null);if(s===null)return Dt(`no ${n.lockfile}`,r);let a;try{a=JSON.parse(o)}catch{return Dt("unparseable manifest or lockfile",r)}if(!a||typeof a!="object"||Array.isArray(a))return Dt("unparseable manifest or lockfile",r);let i=s.toString("utf8"),c=n.tool==="npm"?await oq(e,a,i):n.tool==="pnpm"?await sq(e,a,i):await aq(e,a,i,n.flavor);if(c.storable===!1)return{...c,...r};let{scripts:l,...u}=a,d=[{name:n.lockfile,data:s}];for(let p of c.configs){let w=await ke.readFile(Q.join(e,p.name)).catch(()=>null);w!==null&&d.push({name:p.name,data:w,ephemeral:p.ephemeral===!0})}return{storable:!0,...r,lockHash:WW("sha256").update(s).digest("hex").slice(0,12),inputs:{tool:n.tool,flavor:n.flavor??null,command:n.command,manifest:JSON.stringify(u,null,2)+`
|
|
194
|
-
`,files:d}}}async function bi(e){let t=await hf(Q.join(e.dir,ff));return!t||t.relDir!==e.relDir||t.repo!==e.repo?null:await Nl(Q.join(e.dir,"node_modules"))?t:null}async function fy(e,t=It()){let n=await hf(oy(e));return n?.at?{...n,fresh:Date.now()-n.at<t.retryMs}:null}async function cq(e=It()){let t=[],n=async(r,o)=>{let s=await ke.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let a of s){if(!a.isDirectory()||a.name.startsWith("."))continue;let i=Q.join(r,a.name),c=await hf(Q.join(i,ff));c?t.push({dir:i,group:r,meta:c,sizeBytes:c.sizeBytes||0,lastUsed:await iq(i,c)}):o<6&&await n(i,o+1)}};return await n(e.root,0),t.sort((r,o)=>r.lastUsed-o.lastUsed)}function J_(e){sy++;let t=df.then(e);return df=t.then(()=>{},()=>{}).finally(()=>{sy--}),t}async function lq(e,t){for(let n of(t||"").split(Q.delimiter).filter(Boolean)){let r=Q.join(n,e);if(await ke.access(r,ke.constants.X_OK).then(()=>!0,()=>!1))return r}return null}async function uq(e,t=It(),{runtimeDir:n=Q.dirname(process.execPath),pathEnv:r=process.env.PATH}={}){if(t.bins?.[e])return{bin:t.bins[e],pre:[]};if(await Nl(Q.join(n,e)))return{bin:Q.join(n,e),pre:[]};if(e!=="npm"&&await Nl(Q.join(n,"corepack")))return{bin:Q.join(n,"corepack"),pre:[e]};let o=await lq(e,r);return o?{bin:o,pre:[]}:e==="npm"?{bin:"npm",pre:[]}:null}function wf(e,t=JW){return dq(String(e||"")).split(/\r?\n/).map(n=>n.trimEnd()).filter(n=>n.trim()).slice(-t)}function mq(e,{code:t=null,signal:n=null,timedOut:r=!1,timeoutMs:o=0,command:s=Pn.npm.command}={}){let a=s.split(" ").slice(0,2).join(" ");if(r)return`${a} timed out after ${Math.max(1,Math.round(o/6e4))} min`;let i=d=>d.length>lf?`${d.slice(0,lf-1)}\u2026`:d,c=e.find(d=>pq.test(d));if(c)return i(c.trim());let l=e.map(d=>hq.map(p=>p.exec(d.trim())?.[1]?.trim()).find(Boolean)).filter(Boolean),u=l.find(d=>!fq.test(d))??l.find(d=>/^code\b/.test(d));return u?i(`${a}: ${u}`):n?`${a} was killed (${n})`:`${a} exited with code ${t??"?"}`}function hy(e=It(),t=process.env){let n={};for(let[r,o]of Object.entries(t))o==null||/^BOSTRAT_/i.test(r)||gq.test(r)&&!wq.has(r)||(n[r]=o);return n.PATH=[Q.dirname(process.execPath),t.PATH||""].filter(Boolean).join(Q.delimiter),n.TMPDIR=Q.join(e.root,".tmp"),n}function my(e,t,{cwd:n,env:r,timeoutMs:o,onChunk:s=null}){return new Promise(a=>{let i="",c=!1,l;try{l=GW(e,t,{cwd:n,env:r,stdio:["ignore","pipe","pipe"],detached:!0})}catch(m){return a({code:null,signal:null,timedOut:c,out:String(m?.message||m)})}af=l;try{V_.setPriority(l.pid,10)}catch{}let u=m=>{let
|
|
195
|
-
${m?.message||m}`)),l.on("close",(m,
|
|
193
|
+
`))}async function EW(e,t){if(t!=="claude")return null;let n=Date.now()+AW;for(;;){if(await sr(e))return null;let r=await Fe(e,{lines:30});if(TW(r))return await ne({flow:"swap",phase:"exit-chooser",sessionName:e,from:t,paneTail:!0}),await tt(e,["Enter"],{kind:"swap-exit"}),"answered";if(Date.now()>n)return null;await jo(j_)}}async function _W(e,t){let n=D_[t]||D_.default;n.escape&&(await tt(e,["Escape"],{kind:"swap-exit"}),await jo(150)),n.wipe&&await Ya(e,al,{kind:"swap-exit"}),await wp(e,n.text,{perCharDelayMs:90,kind:"swap-exit"});let r=ar(t).submitDelayMs||0;return await jo(Math.max(r,250)),await tt(e,["Enter"],{kind:"swap-exit"}),{chooser:await EW(e,t)}}async function OW(e,{settleMs:t=IW,timeoutMs:n=$W,parse:r=!0}={}){let o=Date.now(),s=null,a=null;for(;;){let i=null,c=!0;try{let u=await P_.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 P_.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 jo(RW)}}async function Jg(e,t){try{let{stdout:n}=await Lo(oe,se("show-environment","-t",e,t));return!String(n||"").trimStart().startsWith("-")}catch{return!1}}async function F_(e){await Lo(oe,se("respawn-pane","-k","-t",e))}async function Xg(e,{exitTimeoutMs:t=B_,fromAgent:n=null}={}){if(!qe(e))throw new Error("invalid session name");let r=!1;if(await sr(e))return{forced:r,chooser:null};let o=n||(await _e(e))?.agent||"agent",{chooser:s}=await _W(e,o),a=await Yg(e,t);if(await ne({flow:"swap",phase:"exit",sessionName:e,from:o,graceful:a,chooser:s,paneTail:!0}),!a&&(r=!0,await ne({flow:"swap",phase:"respawn-forced",sessionName:e,from:o}),await F_(e),!await Yg(e,L_)))throw new Error(`pane shell did not come back after respawn-pane in "${e}"`);return{forced:r,chooser:s}}async function Zg(e,t={}){if(!qe(e))throw new Error("invalid session name");let n=String(t.agentCmd||"").trim();if(!n)throw new Error("agentCmd is required");let r=await _e(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||ko(n),a=Number(t.exitTimeoutMs)||B_;if(await ne({flow:"swap",phase:"start",sessionName:e,from:o,to:s,cwd:r.cwd}),s==="codex"){let b=await jd();b.waited&&await ne({flow:"cli-currency",phase:"spawn-gate",sessionName:e,...b}),Fd(e)}let{forced:i,chooser:c}=await Xg(e,{exitTimeoutMs:a,fromAgent:o});if(o==="claude"){let b=await OW(sw());await ne({flow:"swap",phase:"config-settled",sessionName:e,from:o,...b})}let l=s==="claude"&&Ms(n),u=l?Cd():null,d=await Jg(e,"ANTHROPIC_API_KEY"),p=!1;try{u?(await Lo(oe,se("set-environment","-t",e,"ANTHROPIC_API_KEY",u)),p=!0):d&&(await Lo(oe,se("set-environment","-u","-t",e,"ANTHROPIC_API_KEY")),p=!0)}catch(b){throw u?up(b,u):b}if(p&&!i&&(await F_(e),!await Yg(e,L_)))throw new Error(`pane shell did not come back after env respawn in "${e}"`);let w=!!t.resumeSessionId,m=t.resumeSessionId||bW(),h=w?n:nl(n,m,e),g=w?t.pinned===!0:/(^|\s)--session-id(\s|=)/.test(h);l&&await fo(r.cwd),s==="codex"&&await Ba(r.cwd),s==="cursor"&&await ja(r.cwd),await Cs(e),await Lo(oe,se("set-option","-t",e,"@bostrat-sid",m)),await Lo(oe,se("set-option","-t",e,"@bostrat-agent",s)),await jo(kW),l&&el().length&&(await Jg(e,Qc)||await Lo(oe,se("set-environment","-t",e,Qc,"1")).catch(()=>{}),await ot(e,`export ${Qc}=1`,{kind:"swap-env"}),await jo(150));let y=await Fw({cwd:r.cwd,name:e});if(y&&!await Jg(e,tl[1])){for(let x of tl)await Lo(oe,se("set-environment","-t",e,x,y)).catch(()=>{});let b=`'${y.replace(/'/g,"'\\''")}'`;await ot(e,`export ${tl.map(x=>`${x}=${b}`).join(" ")}`,{kind:"swap-env"}),await jo(150)}return await ot(e,h,{kind:"swap-launch"}),await ne({flow:"swap",phase:"launched",sessionName:e,from:o,to:s,paneTail:!0}),await ne({flow:"swap",phase:"done",sessionName:e,from:o,to:s,sid:m,forced:i,chooser:c,envRespawned:p}),{name:e,cwd:r.cwd,sessionId:m,agent:s,pinned:g,forced:i,chooser:c,envRespawned:p,launchCmd:h}}var Lo,jo,B_,L_,j_,kW,D_,xW,SW,vW,AW,IW,$W,RW,U_=K(()=>{kt();Mc();Pd();As();Ud();Al();$n();Lo=yW(gW),jo=e=>new Promise(t=>setTimeout(t,e)),B_=Number(process.env.BOSTRAT_SWAP_EXIT_TIMEOUT_MS)||15e3,L_=Number(process.env.BOSTRAT_SWAP_SHELL_TIMEOUT_MS)||8e3,j_=250,kW=400,D_={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"}};xW=/Background work is running/,SW=/Enter to confirm\s*·\s*Esc to cancel/,vW=12,AW=Number(process.env.BOSTRAT_SWAP_CHOOSER_WAIT_MS)||3e3;IW=Number(process.env.BOSTRAT_CLAUDE_CONFIG_SETTLE_MS)||500,$W=Number(process.env.BOSTRAT_CLAUDE_CONFIG_SETTLE_TIMEOUT_MS)||5e3,RW=100});function Qg(e=process.env){return!!(Ue(e)&&e.BOSTRAT_PLANE_TOKEN)}async function ey({loopId:e,outcome:t,note:n=null,env:r=process.env}={}){if(!Qg(r))return{ok:!1,source:"unconfigured"};let o=new AbortController,s=setTimeout(()=>o.abort(),H_);try{let a=await W_(`${Ue(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 Js(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(!Qg(a))return{ok:!1,source:"unconfigured"};let c=rf.get(e.id)||0;if(i()-c<MW)return{ok:!1,source:"debounced"};rf.set(e.id,i());let l=await $l({env:a}),u=l.loops.find(w=>w.trackId===e.id);if(!u)return rf.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 ey({loopId:u.id,outcome:"errored",note:d.slice(0,500),env:a});return p.ok||rf.delete(e.id),{...p,loop:{id:u.id,name:u.name}}}async function $l({env:e=process.env}={}){if(!Qg(e))return{loops:[],source:"unconfigured"};let t=new AbortController,n=setTimeout(()=>t.abort(),H_);try{let r=await W_(`${Ue(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 H_,W_,MW,rf,Rl=K(()=>{_t();H_=1e4,W_=(...e)=>fetch(...e);MW=10*6e4,rf=new Map});import{execFile as CW}from"node:child_process";import of from"node:fs/promises";import ty from"node:path";import{promisify as NW}from"node:util";function UW(e){let n=String(e||"").trim().match(/\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]+)?/);return n?n[0]:null}async function HW(e,{env:t=process.env}={}){let n=String(e||"").trim();if(!n)return null;let r=n.includes("/")?[ty.resolve(n)]:String(t.PATH||"").split(ty.delimiter).filter(Boolean).map(o=>ty.join(o,n));for(let o of r)try{await of.access(o,of.constants.X_OK);let s=await of.realpath(o),a=await of.stat(s);if(!a.isFile())continue;return{path:s,mtimeMs:a.mtimeMs}}catch{}return null}async function Ys({agent:e=null,agentCmd:t=null,env:n=process.env}={}){let r=String(t||(e?n[LW[e]]||BW[e]:"")||"").trim();if(!r)return null;let{realClaude:o,realCodex:s,realCursor:a}=vl({agent:e,agentCmd:r});if(!(o||s||a))return null;let i=await HW(r.split(/\s+/)[0],{env:n});if(!i)return null;let c=`${i.path}@${i.mtimeMs}`;return ny.has(c)||ny.set(c,Promise.resolve().then(()=>FW(i.path,{agent:e})).then(l=>UW(l)).catch(()=>null)),ny.get(c)}var PW,DW,BW,LW,ny,jW,FW,q_=K(()=>{Ws();PW=NW(CW),DW=8e3,BW={claude:"claude",codex:"codex",cursor:"cursor-agent"},LW={claude:"BOSTRAT_AGENT_CMD",codex:"BOSTRAT_CODEX_CMD",cursor:"BOSTRAT_CURSOR_CMD"},ny=new Map,jW=async e=>(await PW(e,["--version"],{timeout:DW})).stdout,FW=jW});function Fo(e){return typeof e=="string"?e.trim():""}var G_=K(()=>{});import ke from"node:fs/promises";import V_ from"node:os";import Q from"node:path";import{createHash as WW,randomUUID as ay}from"node:crypto";import{execFile as qW,spawn as GW}from"node:child_process";import{promisify as KW}from"node:util";function It(e=process.env){return{enabled:String(e.BOSTRAT_DEPS||"").toLowerCase()!=="off",root:e.BOSTRAT_DEPS_DIR||Q.join(QW(e),"deps"),capBytes:String(e.BOSTRAT_DEPS_CAP_GB??"").trim()===""?null:Math.max(0,Ol(e.BOSTRAT_DEPS_CAP_GB,5))*cy,generations:Math.max(1,Math.floor(Ol(e.BOSTRAT_DEPS_GENERATIONS,2))),timeoutMs:Math.max(1e3,Ol(e.BOSTRAT_DEPS_TIMEOUT_MS,20*6e4)),setup:String(e.BOSTRAT_DEPS_SETUP||"").toLowerCase()!=="off",devcontainer:String(e.BOSTRAT_DEPS_DEVCONTAINER||"").toLowerCase()!=="off",setupTimeoutMs:Math.max(1e3,Ol(e.BOSTRAT_DEPS_SETUP_TIMEOUT_MS,15*6e4)),retryMs:Math.max(0,Ol(e.BOSTRAT_DEPS_RETRY_MS,30*6e4)),bins:{npm:e.BOSTRAT_DEPS_NPM||null,pnpm:e.BOSTRAT_DEPS_PNPM||null,yarn:e.BOSTRAT_DEPS_YARN||null}}}function eq(e){return!Number.isFinite(e)||e<=0?ry:Math.min(ry,Math.floor(e*ZW))}async function tq(e=It(),{statfs:t=ke.statfs}={}){if(e.capBytes!=null)return e.capBytes;let n=Q.resolve(e.root);for(;;)try{let r=await t(n);return eq(Number(r.bsize)*Number(r.blocks))}catch{let r=Q.dirname(n);if(r===n)return ry;n=r}}function uy({repoId:e,relDir:t,lockHash:n,nodeMajor:r=nq},o=It()){let s=String(e).toLowerCase(),a=t||".",i=`${r}-${n}`,c=Q.join(o.root,...s.split("/").map(ly),rq(a));return{repo:s,relDir:a,gen:i,key:`${s}:${a}:${i}`,group:c,dir:Q.join(c,i)}}async function dy(e,t=null){let n=[];for(let[c,l]of Object.entries(Pn))(t?t.includes(l.lockfile):await ke.lstat(Q.join(e,l.lockfile)).catch(()=>null)!==null)&&n.push(c);if(!n.length)return null;let r=null;if(n.length>1){let c=await Cl(Q.join(e,cf)).then(l=>JSON.parse(l),()=>null).catch(()=>null);r=n.find(l=>String(c?.packageManager??"").startsWith(`${l}@`))??null}let o=r??n[0],s=Pn[o];if(o!=="yarn")return{tool:o,lockfile:s.lockfile,command:s.command};let a=(await Cl(Q.join(e,s.lockfile))??"").slice(0,2e3),i=/^__metadata:/m.test(a);return{tool:o,lockfile:s.lockfile,flavor:i?"berry":"classic",command:i?s.berry.command:s.command}}async function oq(e,t,n){let r;try{r=JSON.parse(n)}catch{return Dt("unparseable manifest or lockfile")}return t.workspaces||r?.packages?.[""]?.workspaces?Dt("npm workspaces"):[...Object.values(r?.packages??{}),...Object.values(r?.dependencies??{})].some(a=>a&&(a.link===!0||/^file:/.test(String(a.resolved??""))||/^file:/.test(String(a.version??""))))?Dt(uf):{configs:[{name:".npmrc",ephemeral:!0}]}}async function sq(e,t,n){let r=await Cl(Q.join(e,"pnpm-workspace.yaml"));return t.workspaces||r!==null&&/^packages\s*:/m.test(r)?Dt("pnpm workspace"):/^\s+(?:specifier|version):\s*['"]?(?:link|file|workspace):/m.test(n)||/@(?:file|link):/.test(n)?Dt(uf):{configs:[{name:".npmrc",ephemeral:!0},{name:"pnpm-workspace.yaml"},{name:".pnpmfile.cjs"}]}}async function aq(e,t,n,r){if(t.workspaces)return Dt("yarn workspaces");if(r==="classic")return/@(?:file|link):/.test(n)||/^\s+resolved "file:/m.test(n)?Dt(uf):{configs:[{name:".npmrc",ephemeral:!0},{name:".yarnrc",ephemeral:!0}]};let o=await Cl(Q.join(e,".yarnrc.yml"))??"";return/^nodeLinker:\s*["']?node-modules["']?\s*$/m.test(o)?/^(?:yarnPath|plugins)\s*:/m.test(o)?Dt("yarn is vendored in the repo (yarnPath / plugins)"):/@(?:portal|link|file):/.test(n)||/@workspace:(?!\.["',\s])/.test(n)?Dt(uf):{configs:[{name:".yarnrc.yml",ephemeral:!0}]}:Dt("yarn Plug'n'Play (no node_modules to share)")}async function py(e,t=null){let n=await dy(e,t);if(!n)return Dt("no lockfile");let r={tool:n.tool,command:n.command},o=await Cl(Q.join(e,cf));if(o===null)return Dt(`no ${cf}`,r);let s=await ke.readFile(Q.join(e,n.lockfile)).catch(()=>null);if(s===null)return Dt(`no ${n.lockfile}`,r);let a;try{a=JSON.parse(o)}catch{return Dt("unparseable manifest or lockfile",r)}if(!a||typeof a!="object"||Array.isArray(a))return Dt("unparseable manifest or lockfile",r);let i=s.toString("utf8"),c=n.tool==="npm"?await oq(e,a,i):n.tool==="pnpm"?await sq(e,a,i):await aq(e,a,i,n.flavor);if(c.storable===!1)return{...c,...r};let{scripts:l,...u}=a,d=[{name:n.lockfile,data:s}];for(let p of c.configs){let w=await ke.readFile(Q.join(e,p.name)).catch(()=>null);w!==null&&d.push({name:p.name,data:w,ephemeral:p.ephemeral===!0})}return{storable:!0,...r,lockHash:WW("sha256").update(s).digest("hex").slice(0,12),inputs:{tool:n.tool,flavor:n.flavor??null,command:n.command,manifest:JSON.stringify(u,null,2)+`
|
|
194
|
+
`,files:d}}}async function bi(e){let t=await hf(Q.join(e.dir,ff));return!t||t.relDir!==e.relDir||t.repo!==e.repo?null:await Nl(Q.join(e.dir,"node_modules"))?t:null}async function fy(e,t=It()){let n=await hf(oy(e));return n?.at?{...n,fresh:Date.now()-n.at<t.retryMs}:null}async function cq(e=It()){let t=[],n=async(r,o)=>{let s=await ke.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let a of s){if(!a.isDirectory()||a.name.startsWith("."))continue;let i=Q.join(r,a.name),c=await hf(Q.join(i,ff));c?t.push({dir:i,group:r,meta:c,sizeBytes:c.sizeBytes||0,lastUsed:await iq(i,c)}):o<6&&await n(i,o+1)}};return await n(e.root,0),t.sort((r,o)=>r.lastUsed-o.lastUsed)}function J_(e){sy++;let t=df.then(e);return df=t.then(()=>{},()=>{}).finally(()=>{sy--}),t}async function lq(e,t){for(let n of(t||"").split(Q.delimiter).filter(Boolean)){let r=Q.join(n,e);if(await ke.access(r,ke.constants.X_OK).then(()=>!0,()=>!1))return r}return null}async function uq(e,t=It(),{runtimeDir:n=Q.dirname(process.execPath),pathEnv:r=process.env.PATH}={}){if(t.bins?.[e])return{bin:t.bins[e],pre:[]};if(await Nl(Q.join(n,e)))return{bin:Q.join(n,e),pre:[]};if(e!=="npm"&&await Nl(Q.join(n,"corepack")))return{bin:Q.join(n,"corepack"),pre:[e]};let o=await lq(e,r);return o?{bin:o,pre:[]}:e==="npm"?{bin:"npm",pre:[]}:null}function wf(e,t=JW){return dq(String(e||"")).split(/\r?\n/).map(n=>n.trimEnd()).filter(n=>n.trim()).slice(-t)}function mq(e,{code:t=null,signal:n=null,timedOut:r=!1,timeoutMs:o=0,command:s=Pn.npm.command}={}){let a=s.split(" ").slice(0,2).join(" ");if(r)return`${a} timed out after ${Math.max(1,Math.round(o/6e4))} min`;let i=d=>d.length>lf?`${d.slice(0,lf-1)}\u2026`:d,c=e.find(d=>pq.test(d));if(c)return i(c.trim());let l=e.map(d=>hq.map(p=>p.exec(d.trim())?.[1]?.trim()).find(Boolean)).filter(Boolean),u=l.find(d=>!fq.test(d))??l.find(d=>/^code\b/.test(d));return u?i(`${a}: ${u}`):n?`${a} was killed (${n})`:`${a} exited with code ${t??"?"}`}function hy(e=It(),t=process.env){let n={};for(let[r,o]of Object.entries(t))o==null||/^BOSTRAT_/i.test(r)||gq.test(r)&&!wq.has(r)||(n[r]=o);return n.PATH=[Q.dirname(process.execPath),t.PATH||""].filter(Boolean).join(Q.delimiter),n.TMPDIR=Q.join(e.root,".tmp"),n}function my(e,t,{cwd:n,env:r,timeoutMs:o,onChunk:s=null}){return new Promise(a=>{let i="",c=!1,l;try{l=GW(e,t,{cwd:n,env:r,stdio:["ignore","pipe","pipe"],detached:!0})}catch(m){return a({code:null,signal:null,timedOut:c,out:String(m?.message||m)})}af=l;try{V_.setPriority(l.pid,10)}catch{}let u=m=>{let h=m.toString("utf8");i=(i+h).slice(-zW);try{s?.(h)}catch{}};l.stdout.on("data",u),l.stderr.on("data",u);let d=m=>{try{process.kill(-l.pid,m)}catch{try{l.kill(m)}catch{}}},p=setTimeout(()=>{c=!0,d("SIGTERM"),setTimeout(()=>d("SIGKILL"),YW).unref()},o);p.unref();let w=(m,h,g="")=>{clearTimeout(p),af===l&&(af=null),a({code:m,signal:h,timedOut:c,out:i+g})};l.on("error",m=>w(null,null,`
|
|
195
|
+
${m?.message||m}`)),l.on("close",(m,h)=>w(m,h))})}function yq({bin:e,pre:t},n,r,o){let s={...hy(o),COREPACK_ENABLE_DOWNLOAD_PROMPT:"0",YARN_ENABLE_TELEMETRY:"0",npm_config_audit:"false",npm_config_fund:"false",npm_config_progress:"false",npm_config_update_notifier:"false"};return my(e,[...t,...n],{cwd:r,env:s,timeoutMs:o.timeoutMs})}async function bq(e){try{let{stdout:t}=await VW("du",["-sk",e],{timeout:6e4});return(parseInt(t,10)||0)*1024}catch{return 0}}async function kq(e,t,n){let r=Date.now(),o=async(l,u=[])=>(await ke.mkdir(e.group,{recursive:!0}).catch(()=>{}),await dt(oy(e),{key:e.key,at:Date.now(),reason:l,tail:u}).catch(()=>{}),{status:"failed",reason:l,tail:u,durationMs:Date.now()-r}),s=await bi(e);if(s)return{status:"ready",cached:!0,sizeBytes:s.sizeBytes||0,durationMs:0};let{totalBytes:a,capBytes:i}=await tI({cfg:n});if(i&&a>=i)return o(`the dependency store is full (${(i/cy).toFixed(1)} GB cap, all of it in use) \u2014 install in place`);let c=Q.join(n.root,".staging",`${ly(e.key)}-${process.pid}-${ay().slice(0,8)}`);try{await ke.mkdir(c,{recursive:!0}),await ke.mkdir(Q.join(n.root,".tmp"),{recursive:!0}),await ke.writeFile(Q.join(c,cf),t.manifest);for(let m of t.files)await ke.writeFile(Q.join(c,m.name),m.data,m.ephemeral?{mode:384}:void 0);let l=t.tool??"npm",u=await uq(l,n);if(!u)return await o(`${l} is not available on this node \u2014 run \`${t.command}\` in place once it is installed`);let d=t.flavor==="berry"?Pn.yarn.berry.args:Pn[l].args,p=await yq(u,d,c,n);for(let m of t.files)m.ephemeral&&await ke.rm(Q.join(c,m.name),{force:!0}).catch(()=>{});if(p.code!==0||p.timedOut){let m=wf(p.out);return await o(mq(m,{...p,timeoutMs:n.timeoutMs,command:t.command}),m)}await ke.mkdir(Q.join(c,"node_modules"),{recursive:!0});let w=await bq(c);await dt(Q.join(c,ff),{key:e.key,repo:e.repo,relDir:e.relDir,gen:e.gen,tool:l,node:process.version,preparedAt:Date.now(),sizeBytes:w}),await ke.writeFile(Q.join(c,yi),""),await ke.mkdir(e.group,{recursive:!0});try{await ke.rename(c,e.dir)}catch{await bi(e)||(await ke.rm(e.dir,{recursive:!0,force:!0}),await ke.rename(c,e.dir))}return await ke.rm(oy(e),{force:!0}).catch(()=>{}),{status:"ready",cached:!1,sizeBytes:w,durationMs:Date.now()-r}}catch(l){return await o(`could not prepare the store: ${String(l?.message||l).slice(0,lf-30)}`)}finally{await ke.rm(c,{recursive:!0,force:!0}).catch(()=>{})}}function wy(e,t,{cfg:n=It()}={}){let r=Ml.get(e.key);if(r)return r;let s=df.then(()=>kq(e,t,n)).catch(a=>({status:"failed",reason:String(a?.message||a).slice(0,lf),tail:[],durationMs:0})).then(async a=>(Ml.delete(e.key),a.status==="ready"&&!a.cached&&await tI({cfg:n,keep:[e.dir]}).catch(()=>{}),a));return df=s.then(()=>{},()=>{}),Ml.set(e.key,s),s}function gy(){let e=af;if(e?.pid)try{process.kill(-e.pid,"SIGTERM")}catch{try{e.kill("SIGTERM")}catch{}}}async function Y_(e=It()){for(let t of[".staging",".tmp",".trash"])await ke.rm(Q.join(e.root,t),{recursive:!0,force:!0}).catch(()=>{})}async function ki(e){let t=Q.join(e,"node_modules"),n=await hf(Q.join(t,iy));if(!n?.store||!n?.key)return null;let r=o=>({key:n.key,store:n.store,links:o});for(let o of await ke.readdir(t,{withFileTypes:!0}).catch(()=>[]))if(!(o.name.startsWith(".")||o.isSymbolicLink())){if(!o.isDirectory()||!o.name.startsWith("@"))return r("replaced");for(let s of await ke.readdir(Q.join(t,o.name),{withFileTypes:!0}).catch(()=>[]))if(!s.isSymbolicLink())return r("replaced")}if(n.probe){let o=Q.join(t,n.probe),s=await ke.readlink(o).catch(()=>null),a=s===null?null:Q.resolve(Q.dirname(o),s);if(a===null||!X_(Q.join(n.store,"node_modules"),a))return r("replaced")}return r(await Nl(Q.join(n.store,ff))?"intact":"dangling")}async function xq(e,t){let n=async r=>{for(let o of await ke.readdir(r,{withFileTypes:!0}).catch(()=>[])){if(!o.isSymbolicLink())continue;let s=await ke.readlink(Q.join(r,o.name)).catch(()=>null);s&&X_(t,Q.resolve(r,s))&&await ke.rm(Q.join(r,o.name),{force:!0})}};for(let r of await ke.readdir(e,{withFileTypes:!0}).catch(()=>[]))r.isDirectory()&&(r.name===".bin"||r.name.startsWith("@"))&&(await n(Q.join(e,r.name)),await ke.rmdir(Q.join(e,r.name)).catch(()=>{}));await n(e),await ke.rm(Q.join(e,iy),{force:!0}).catch(()=>{})}async function K_(e,t){let n=Q.join(t.dir,"node_modules"),r=(s,a)=>ke.symlink(s,a).catch(i=>{if(i?.code!=="EEXIST")throw i}),o=null;for(let s of await ke.readdir(n,{withFileTypes:!0}))if(!(s.name.startsWith(".")&&s.name!==".bin")){if(s.isDirectory()&&(s.name===".bin"||s.name.startsWith("@"))){await ke.mkdir(Q.join(e,s.name),{recursive:!0});for(let a of await ke.readdir(Q.join(n,s.name)))await r(Q.join(n,s.name,a),Q.join(e,s.name,a)),!o&&s.name!==".bin"&&(o=Q.join(s.name,a));continue}await r(Q.join(n,s.name),Q.join(e,s.name)),!o&&!s.name.startsWith(".")&&(o=s.name)}await ke.writeFile(Q.join(e,iy),JSON.stringify({key:t.key,store:t.dir,probe:o,linkedAt:Date.now()},null,2)+`
|
|
196
196
|
`)}async function yy(e,t,n=It()){if(!await bi(e))return{linked:!1,why:"store not ready"};let r=Q.join(t,"node_modules"),o=await ke.lstat(r).catch(()=>null);if(o){let a=o.isDirectory()?await ki(t):null;return a?a.links==="replaced"?{linked:!1,why:"node_modules exists"}:a.links==="intact"&&a.key===e.key?(await sf(Q.join(e.dir,yi)),{linked:!0,already:!0}):(await xq(r,n.root),await K_(r,e),await sf(Q.join(e.dir,yi)),{linked:!0,relinked:!0}):{linked:!1,why:"node_modules exists"}}let s=`${r}.bostrat-${ay().slice(0,8)}`;try{await ke.mkdir(s),await K_(s,e),await ke.rename(s,r)}catch(a){return await ke.rm(s,{recursive:!0,force:!0}).catch(()=>{}),await Nl(r)?{linked:!1,why:"node_modules exists"}:{linked:!1,why:String(a?.message||a)}}return await sf(Q.join(e.dir,yi)),{linked:!0}}function eI({referenced:e}={}){typeof e=="function"&&(Q_=e)}async function Sq(e,t){let n=Q.join(t.root,".trash",`${Q.basename(e)}-${ay().slice(0,8)}`);await ke.mkdir(Q.dirname(n),{recursive:!0}),await ke.rename(e,n),await ke.rm(n,{recursive:!0,force:!0}).catch(()=>{})}async function tI({cfg:e=It(),keep:t=[]}={}){let n=new Set([...await Q_().catch(()=>[]),...t].map(l=>Q.resolve(l))),r=await cq(e);for(let l of r)Date.now()-(l.meta.preparedAt||0)<XW&&n.add(Q.resolve(l.dir));let o=[],s=async l=>{try{await Sq(l.dir,e),o.push(l.dir),l.gone=!0}catch{}},a=new Map;for(let l of r)a.set(l.group,[...a.get(l.group)??[],l]);for(let l of a.values())for(let u of l){if(l.filter(p=>!p.gone).length<=e.generations)break;n.has(Q.resolve(u.dir))||await s(u)}let i=()=>r.filter(l=>!l.gone).reduce((l,u)=>l+u.sizeBytes,0),c=await tq(e);if(c)for(let l of r){if(i()<=c)break;!l.gone&&!n.has(Q.resolve(l.dir))&&await s(l)}return{removed:o,totalBytes:i(),capBytes:c,count:r.filter(l=>!l.gone).length}}var VW,Pn,pf,Yre,cf,iy,ff,yi,cy,zW,JW,lf,YW,XW,ry,ZW,QW,Ol,nq,ly,rq,Cl,Dt,uf,hf,Nl,oy,sf,iq,Ml,df,af,sy,mf,z_,dq,pq,fq,hq,wq,gq,X_,Z_,Q_,gf=K(()=>{rr();VW=KW(qW),Pn=Object.freeze({npm:{lockfile:"package-lock.json",command:"npm ci",args:["ci"]},pnpm:{lockfile:"pnpm-lock.yaml",command:"pnpm install --frozen-lockfile",args:["install","--frozen-lockfile","--package-import-method=copy"]},yarn:{lockfile:"yarn.lock",command:"yarn install --frozen-lockfile",args:["install","--frozen-lockfile","--non-interactive"],berry:{command:"yarn install --immutable",args:["install","--immutable"]}}}),pf=Object.freeze(Object.values(Pn).map(e=>e.lockfile)),Yre=Pn.npm.lockfile,cf="package.json",iy=".bostrat-deps.json",ff="meta.json",yi=".last-used",cy=1024**3,zW=16*1024,JW=30,lf=160,YW=5e3,XW=10*6e4,ry=5*cy,ZW=.25,QW=e=>e.BOSTRAT_STATE_DIR||Q.join(e.HOME||V_.tmpdir(),".bostrat"),Ol=(e,t)=>Number.isFinite(Number(e))&&String(e??"").trim()!==""?Number(e):t;nq=process.versions.node.split(".")[0],ly=e=>{let t=String(e).replace(/[^A-Za-z0-9._-]/g,"_");return!t||t.startsWith(".")?`_${t}`:t},rq=e=>e==="."||!e?"_root":e.split("/").map(ly).join("__");Cl=e=>ke.readFile(e,"utf8").catch(()=>null);Dt=(e,t={})=>({storable:!1,why:e,...t}),uf="local file: dependency";hf=e=>ke.readFile(e,"utf8").then(JSON.parse,()=>null),Nl=e=>ke.lstat(e).then(()=>!0,()=>!1);oy=e=>`${e.dir}.failed.json`;sf=e=>{let t=new Date;return ke.utimes(e,t,t).catch(()=>ke.writeFile(e,"").catch(()=>{}))},iq=async(e,t)=>(await ke.stat(Q.join(e,yi)).catch(()=>null))?.mtimeMs??t?.preparedAt??0;Ml=new Map,df=Promise.resolve(),af=null,sy=0,mf=e=>Ml.has(e),z_=()=>Ml.size>0||sy>0;dq=e=>e.replace(/\u001b\[[0-9;?]*[ -/]*[@-~]/g,"");pq=/gyp ERR! find Python|not found: make|make: .*not found|g\+\+: .*not found|g\+\+: not found|ENOSPC|ENOTFOUND|EAI_AGAIN|ETIMEDOUT|ECONNRESET|EINTEGRITY|in sync|E40[134]|ERR_PNPM_\w+|lockfile needs to be updated|YN0028/,fq=/^(code|errno|syscall|path|dest|command|cwd|node|A complete log of this run)\b/,hq=[/^npm (?:error|ERR!)\s+(.*)$/,/^error\s+(.*)$/i,/^➤ YN(?!0000)\d{4}: [│┌└ ]*(.*)$/];wq=new Set(["NPM_TOKEN","NODE_AUTH_TOKEN"]),gq=/(TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIALS?|API_?KEY|PRIVATE_?KEY)$/i;X_=(e,t)=>t===e||t.startsWith(e+Q.sep);Z_=e=>sf(Q.join(e,yi)),Q_=async()=>[]});import Pr from"node:fs/promises";import Bt from"node:path";import{execFile as vq}from"node:child_process";import{promisify as Aq}from"node:util";function Pl(e,t=80){let n=[],r="";for(let o of e.match(/`[^`]*`\S*|\S+/g)??[])r&&r.length+1+o.length>t?(n.push(r),r=o):r=r?`${r} ${o}`:o;return r&&n.push(r),n.join(`
|
|
197
197
|
`)}async function by(e){if(await nI(Bt.join(e,".git")))return[{name:null,dir:e}];let t=await Pr.readdir(e,{withFileTypes:!0}).catch(()=>[]),n=[];for(let r of t.sort((o,s)=>o.name.localeCompare(s.name))){if(!r.isDirectory()||r.name.startsWith("."))continue;let o=Bt.join(e,r.name);await nI(Bt.join(o,".git"))&&n.push({name:r.name,dir:o})}return n}async function Rq(e){try{let{stdout:t}=await Tq("git",["-C",e,"ls-files","-z","--",...pf.flatMap(r=>[r,`*/${r}`])],{timeout:Iq,maxBuffer:4194304}),n=new Map;for(let r of t.split("\0")){if(!r||!pf.includes(Bt.posix.basename(r))||r.split("/").includes("node_modules"))continue;let o=Bt.posix.dirname(r);n.set(o,[...n.get(o)??[],Bt.posix.basename(r)])}return[...n.entries()].map(([r,o])=>({rel:r,lockfiles:o})).sort((r,o)=>r.rel==="."?-1:o.rel==="."?1:r.rel.localeCompare(o.rel))}catch{return[]}}async function Oq(e){let t=await Pr.lstat(Bt.join(e,"node_modules")).catch(()=>null);if(!t)return"missing";if(t.isSymbolicLink())return await Pr.stat(Bt.join(e,"node_modules")).catch(()=>null)?"linked":"missing";if(!t.isDirectory())return"missing";let n=await ki(e);return n?.links==="intact"?"linked":n?.links==="dangling"?"missing":"installed"}async function Dl(e){let t=[];for(let n of await by(e))for(let{rel:r,lockfiles:o}of await Rq(n.dir)){let s=Bt.posix.join(n.name??".",r),a=Bt.join(e,s),i=await dy(a,o).catch(()=>null);t.push({dir:s,relDir:r,repoDir:n.dir,repoName:n.name,pkgDir:a,lockfiles:o,tool:i?.tool??"npm",command:i?.command??kf})}return t}async function Mq(e){let t=[];for(let n of await Dl(e))t.push({dir:n.dir,status:await Oq(n.pkgDir),...n.command!==kf?{command:n.command}:{}});return t}async function Cq(e=process.env.PATH||""){let t=e.split(Bt.delimiter).filter(Boolean),n=[];for(let r of Eq){let o=!1;for(let s of t)if(await Pr.access(Bt.join(s,r),Pr.constants.X_OK).then(()=>!0,()=>!1)){o=!0;break}o||n.push(r)}return n}function Bq(e){return e?.length?`
|
|
198
198
|
Setup \u2014 a repo that carries its own is set up by it, once per workspace, instead
|
|
@@ -271,30 +271,30 @@ not copy or rebuild the module from a different Node.
|
|
|
271
271
|
`).length&&await Bl.writeFile(n,o.join(`
|
|
272
272
|
`))}catch{}}var xf,uI,Fl=K(()=>{xf=Fq(jq),uI=64*1024*1024});import Ul from"node:fs/promises";import Ny from"node:path";import{createHash as qq}from"node:crypto";import{execFile as Gq}from"node:child_process";import{promisify as Kq}from"node:util";function Qq(e){let t="",n=!1;for(let r=0;r<e.length;r++){let o=e[r];if(n)t+=o,o==="\\"?t+=e[++r]??"":o==='"'&&(n=!1);else if(o==='"')n=!0,t+=o;else if(o==="/"&&e[r+1]==="/"){for(;r<e.length&&e[r]!==`
|
|
273
273
|
`;)r++;t+=`
|
|
274
|
-
`}else if(o==="/"&&e[r+1]==="*"){for(r+=2;r<e.length&&!(e[r]==="*"&&e[r+1]==="/");)r++;r++}else t+=o}return JSON.parse(t.replace(/,(\s*[}\]])/g,"$1"))}async function mI(e,t=It()){if(!t.setup)return null;if(await hI(e,Sf)){let n=Ny.join(e,Sf),r=await Ul.readFile(n,"utf8").catch(()=>null);if(r!==null){let o=await Ul.access(n,Ul.constants.X_OK).then(()=>!0,()=>!1);return{source:"bostrat-setup",file:Sf,...o?{bin:n,args:[]}:{bin:"sh",args:[n]},display:Sf,hash:Cy(r)}}}if(!t.devcontainer)return null;for(let n of zq){if(!await hI(e,n))continue;let r;try{r=Qq(await Ul.readFile(Ny.join(e,n),"utf8"))}catch{continue}let o=r?.postCreateCommand;if(typeof o=="string"&&o.trim())return{source:"devcontainer",file:n,bin:"sh",args:["-c",o],display:o.trim(),hash:Cy(`s:${o}`)};if(Array.isArray(o)&&o.length&&o.every(s=>typeof s=="string"))return{source:"devcontainer",file:n,bin:o[0],args:o.slice(1),display:o.join(" "),hash:Cy(`a:${JSON.stringify(o)}`)}}return null}function e5(e,t,n){if(e.timedOut)return`timed out after ${Math.max(1,Math.round(n.setupTimeoutMs/6e4))} min`;let r=[...t].reverse().find(a=>a.trim()),o=e.signal?`was killed (${e.signal})`:`exited with code ${e.code??"?"}`,s=r?`${o}: ${r.trim()}`:o;return s.length>fI?`${s.slice(0,fI-1)}\u2026`:s}async function wI(e,t,{cfg:n=It(),onOutput:r=null}={}){let o=Date.now(),s="",a=0,i=0,c=!1,l=m=>{if(!r||!s.trim()||!m&&Date.now()-i<Jq)return;if(a>=Yq){c||(c=!0,r({lines:["\u2026 further output is not streamed; the tail rides the final event"],truncated:!0})),s="";return}let
|
|
275
|
-
`);for(;g.length>Zq&&
|
|
276
|
-
`);s="",a++,i=Date.now(),r({lines:f})};await Ul.mkdir(Ny.join(n.root,".tmp"),{recursive:!0}).catch(()=>{});let u={...hy(n),COREPACK_ENABLE_DOWNLOAD_PROMPT:"0",BOSTRAT_SETUP:e.source},d=await my(e.bin,e.args,{cwd:t,env:u,timeoutMs:n.setupTimeoutMs,onChunk:m=>{s=(s+m).slice(-8*1024),l(!1)}});c||l(!0);let p=wf(d.out),w=Date.now()-o;return d.code===0&&!d.timedOut?{status:"done",durationMs:w,exitCode:0,tail:p}:{status:"failed",durationMs:w,exitCode:d.code,timedOut:d.timedOut,reason:e5(d,p,n),tail:p}}var Vq,Sf,zq,fI,Jq,Yq,Xq,Zq,hI,Cy,gI=K(()=>{gf();Vq=Kq(Gq),Sf=".bostrat/setup",zq=[".devcontainer/devcontainer.json",".devcontainer.json"],fI=160,Jq=3e3,Yq=40,Xq=20,Zq=1500,hI=(e,t)=>Vq("git",["-C",e,"ls-files","--error-unmatch","--",t],{timeout:5e3}).then(()=>!0,()=>!1);Cy=e=>qq("sha256").update(e).digest("hex").slice(0,12)});import Dn from"node:fs/promises";import jt from"node:path";import{createHash as kI,randomUUID as xI}from"node:crypto";import{execFile as t5}from"node:child_process";import{promisify as n5}from"node:util";function _I({workspaces:e,linkedRepos:t}={}){typeof e=="function"&&(TI=e),typeof t=="function"&&(EI=t)}async function $I(e){let t=await Re(e).catch(()=>null);if(t)return t;if(Py.has(e))return Py.get(e);let n=null;try{let{stdout:r}=await r5("git",["-C",e,"rev-parse","--git-common-dir"],{timeout:5e3}),o=await Dn.realpath(jt.resolve(e,r.trim()));n=`_local/${jt.basename(o)===".git"?jt.basename(jt.dirname(o)):jt.basename(o)}-${kI("sha256").update(o).digest("hex").slice(0,8)}`}catch{n=null}return Py.set(e,n),n}async function ql(e,t,n,r,o={}){if(!e?.track?.id)return;let s=By.get(e.workspaceDir)??new Set,a=`${n.key}:${r}`;if(!s.has(a)){if(r==="started")for(let i of["ready","failed"])s.delete(`${n.key}:${i}`);else s.delete(`${n.key}:started`);s.add(a),By.set(e.workspaceDir,s),await Hl(e,"deps.prepare",{repo:n.repo,relDir:n.relDir,dir:t.dir,key:n.key,status:r,batch:e.batch,...o})}}async function Hl(e,t,n){if(!e?.track?.id)return;let r=()=>D(e.track,{type:t,actor:"orchestrator",source:"orchestrator",boxId:e.boxId??null,payload:n}).catch(s=>console.warn(`[deps] ${e.track.id}: ${t} not recorded: ${s?.message||s}`)),o=vi.get(e.workspaceDir);o?o.events.push(r):await r()}async function Ly(e){let t=jt.resolve(e),n=vi.get(t);if(!n)return 0;vi.delete(t),clearTimeout(n.timer);for(let r of n.events)await r();return n.events.length}function s5(e){if(vi.has(e))return;let t=setTimeout(()=>vi.delete(e),o5);t.unref(),vi.set(e,{events:[],timer:t})}function Tf(e){let t={},n=r=>{t[r.workspaceDir]={track:r.track?{id:r.track.id,cwd:r.track.cwd??null}:null,boxId:r.boxId??null,batch:r.batch}};for(let r of Wl.values())for(let o of r.values())n(o.ctx);for(let r of Af.values())n(r.ctx);return Dy=Dy.then(()=>dt(AI(e),{version:1,workspaces:t})).catch(()=>{}),Dy}async function OI(e,t){let n=await Dn.readFile(RI(e,t),"utf8").then(JSON.parse,()=>null);return n?.workspace===t&&n.repos?n:{workspace:t,repos:{}}}async function yI(e,t,n,r){let o=await OI(e,t);o.repos[n]=r,await dt(RI(e,t),o).catch(()=>{})}async function a5(){try{return new Set((await EI()).map(e=>String(e).toLowerCase()))}catch{return new Set}}function i5(e,t,n,r,o,s){let a=`${e.workspaceDir}\0${t.dir}`,i=xI().slice(0,8),c={repo:r.toLowerCase(),dir:t.dir,source:n.source,command:n.display,run:i},l={source:n.source,display:n.display,hash:n.hash,status:"running",run:i,startedAt:Date.now()};Af.set(a,{ctx:e,entry:l});let u=(async()=>{s?.status==="running"&&s.run&&await Hl(e,"deps.setup",{...c,run:s.run,status:"failed",reason:"interrupted by a node restart \u2014 run again",tail:[]}),await yI(o,e.workspaceDir,t.dir,l),await Hl(e,"deps.setup",{...c,status:"started"})})();return J_(async()=>(await u,wI(n,t.repoDir,{cfg:o,onOutput:({lines:d,truncated:p})=>{Hl(e,"deps.setup",{...c,status:"output",lines:d,...p?{truncated:!0}:{}})}}))).catch(d=>({status:"failed",reason:String(d?.message||d).slice(0,160),tail:[],durationMs:0,exitCode:null})).then(async d=>{let p={...l,status:d.status,finishedAt:Date.now(),durationMs:d.durationMs,...d.reason?{reason:d.reason}:{}};await yI(o,e.workspaceDir,t.dir,p),Af.delete(a),await Hl(e,"deps.setup",{...c,status:d.status,durationMs:d.durationMs,exitCode:d.exitCode,...d.status==="failed"?{reason:d.reason,tail:(d.tail??[]).slice(-vI)}:{}}),await Dn.stat(e.workspaceDir).catch(()=>null)&&await jy(e,{kick:!1}),await Tf(o)}).catch(d=>console.warn(`[deps] ${e.workspaceDir}: setup settle failed: ${d?.message||d}`)),l}async function c5(e,t,{kick:n}){let r=[],o=new Set,s=!1;if(!t.setup)return{rows:r,handled:o,started:s};let a=null,i=null;for(let c of await by(e.workspaceDir)){let l=await mI(c.dir,t);if(!l)continue;let u={dir:c.name??".",repoDir:c.dir},d=await Re(c.dir).catch(()=>null);a??=await a5();let p={dir:u.dir,source:l.source,display:l.display};if(!d||!a.has(d.toLowerCase())){r.push({...p,status:"not-linked"});continue}if(o.add(c.dir),Af.get(`${e.workspaceDir}\0${u.dir}`)){r.push({...p,status:"running"});continue}i??=await OI(t,e.workspaceDir);let m=i.repos[u.dir]??null,f=m&&m.hash===l.hash&&(m.status==="done"||m.status==="failed"),g=f&&m.status==="failed"&&Date.now()-(m.finishedAt||0)>=t.retryMs;if(f&&!g){r.push({...p,status:m.status,reason:m.reason,durationMs:m.durationMs});continue}if(!n){r.push({...p,status:"pending"});continue}i5(e,u,l,d,t,m),s=!0,r.push({...p,status:"running"})}return{rows:r,handled:o,started:s}}async function MI(e){let t=e.relDir==="."?"node_modules":`${e.relDir}/node_modules`;await jl(e.repoDir,[`/${t}`])}async function CI(e,t,n){let r=Wl.get(e.key);Wl.delete(e.key);for(let o of r?.values()??[])try{if(!await Dn.stat(o.ctx.workspaceDir).catch(()=>null))continue;if(n.status==="ready"){let s=await yy(e,o.pkg.pkgDir,t);s.linked&&await MI(o.pkg),await ql(o.ctx,o.pkg,e,"ready",{linked:s.linked,durationMs:n.durationMs,sizeBytes:n.sizeBytes})}else await ql(o.ctx,o.pkg,e,"failed",{reason:n.reason,tail:(n.tail??[]).slice(-vI),durationMs:n.durationMs});await jy(o.ctx,{kick:!1})}catch(s){console.warn(`[deps] ${o.ctx.workspaceDir}: settle failed: ${s?.message||s}`)}await Tf(t)}function bI(e,t,n,r,o,{announce:s}){let a=Wl.get(e.key)??new Map,i=!a.has(r.workspaceDir);return a.set(r.workspaceDir,{pkg:n,ctx:r}),Wl.set(e.key,a),mf(e.key)||wy(e,t,{cfg:o}).then(c=>CI(e,o,c)),i&&s?ql(r,n,e,"started"):null}async function l5(e,{kick:t,announce:n}){let r=It(),{workspaceDir:o}=e;if(!r.enabled)return ky(o);let s=new Map,a=0,i=await c5(e,r,{kick:t}),c=i.started,l=new Set(i.rows.filter(u=>u.status==="running").map(u=>u.dir));for(let u of await Dl(o)){if(i.handled.has(u.repoDir)){l.has(u.repoName??".")&&s.set(u.dir,{status:"setup"});continue}let d=await Dn.lstat(jt.join(u.pkgDir,"node_modules")).catch(()=>null),p=d?.isDirectory()?await ki(u.pkgDir):null;if(d&&(!p||p.links==="replaced"))continue;let w=await $I(u.repoDir),m=w?await py(u.pkgDir,u.lockfiles):{storable:!1};if(!m.storable)continue;let f=uy({repoId:w,relDir:u.relDir,lockHash:m.lockHash},r);if(p?.links==="intact"&&p.key===f.key){await Z_(p.store);continue}let g=p?.links==="intact";if(await bi(f)){let b=await yy(f,u.pkgDir,r);b.linked&&(await MI(u),b.already||await ql(e,u,f,"ready",{linked:!0,cached:!0}));continue}if(mf(f.key)){await bI(f,m.inputs,u,e,r,{announce:n}),c=!0,s.set(u.dir,g?{stale:!0}:{status:"preparing"});continue}let y=await fy(f,r);if(t&&!y?.fresh&&a<SI){a++,await bI(f,m.inputs,u,e,r,{announce:n}),c=!0,s.set(u.dir,g?{stale:!0}:{status:"preparing"});continue}y&&(g||s.set(u.dir,{status:"failed",reason:y.reason}),t&&await ql(e,u,f,"failed",{reason:y.reason,tail:y.tail??[],cached:!0}))}return c&&await Tf(r),ky(o,{overlay:s,setups:i.rows})}function jy(e,t){let r=(vf.get(e.workspaceDir)??Promise.resolve()).then(()=>l5(e,t)).catch(s=>(console.warn(`[deps] ${e.workspaceDir}: provisioning failed: ${s?.message||s}`),null)),o=r.then(()=>{vf.get(e.workspaceDir)===o&&vf.delete(e.workspaceDir)});return vf.set(e.workspaceDir,o),r}function Gl(e,{track:t=null,boxId:n=null,kick:r=!0,batch:o=null,announce:s=!0,hold:a=!1}={}){a&&t?.id&&s5(jt.resolve(e));let i={workspaceDir:jt.resolve(e),track:t?.id?{id:t.id,cwd:t.cwd??null}:null,boxId:n,batch:o||xI().slice(0,8)};return jy(i,{kick:r,announce:s})}async function NI(e){let t=It();if(!t.enabled)return 0;let n=0;try{let r=await $I(e);if(!r)return 0;for(let o of await Dl(e)){if(n>=SI)break;let s=await py(o.pkgDir,o.lockfiles);if(!s.storable)continue;let a=uy({repoId:r,relDir:o.relDir,lockHash:s.lockHash},t);await bi(a)||mf(a.key)||(await fy(a,t))?.fresh||(n++,wy(a,s.inputs,{cfg:t}).then(i=>CI(a,t,i)))}}catch(r){console.warn(`[deps] prewarm of ${e} failed: ${r?.message||r}`)}return n}async function PI(){let e=It();if(!e.enabled)return 0;await Y_(e);let t=jt.join(e.root,".setup");for(let o of await Dn.readdir(t).catch(()=>[])){let s=await Dn.readFile(jt.join(t,o),"utf8").then(JSON.parse,()=>null);(!s?.workspace||!await Dn.stat(s.workspace).catch(()=>null))&&await Dn.rm(jt.join(t,o),{force:!0}).catch(()=>{})}let n=await Dn.readFile(AI(e),"utf8").then(JSON.parse,()=>null),r=0;for(let[o,s]of Object.entries(n?.workspaces??{}))await Dn.stat(o).catch(()=>null)&&(By.set(jt.resolve(o),new Set),r++,Gl(o,{track:s.track,boxId:s.boxId,batch:s.batch,kick:!0,announce:!1}));return r||await Tf(e),r}var r5,SI,vI,AI,Wl,By,vf,vi,o5,Af,TI,EI,II,Py,Dy,RI,Fy=K(()=>{be();Fl();er();rr();xy();gI();gf();r5=n5(t5),SI=12,vI=20,AI=e=>jt.join(e.root,"pending.json"),Wl=new Map,By=new Map,vf=new Map,vi=new Map,o5=2*6e4,Af=new Map,TI=async()=>[],EI=async()=>[];eI({referenced:async()=>{let e=new Set;for(let t of await TI().catch(()=>[]))for(let n of await Dl(t).catch(()=>[])){let r=await ki(n.pkgDir).catch(()=>null);r?.links==="intact"&&e.add(r.store)}return[...e]}});II=()=>z_(),Py=new Map;Dy=Promise.resolve();RI=(e,t)=>jt.join(e.root,".setup",`${kI("sha256").update(t).digest("hex").slice(0,16)}.json`)});function Ef(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!u5.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 He,u5,yn=K(()=>{He=e=>!!(e&&(e.archivedAt||e.transferredTo)),u5=new Set(["merged","conflict","canceled","failed","handed-off"])});import Uy from"node:fs/promises";import BI from"node:path";import d5 from"node:os";function UI(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function HI(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function WI(e){let t=new Date(UI(e));return t.setDate(t.getDate()+7),t.getTime()}function qI(e){let t=new Date(HI(e));return t.setMonth(t.getMonth()+1),t.getTime()}function If(e=Date.now()){for(let[t,n]of Object.entries(Ai)){let r=n.startOf(e);if(r!==Dr[t]){Dr[t]=r;for(let o of ta.values())o[t]=0;for(let o of Ti)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&Ti.delete(o)}}}function GI(e,t){let n=Bn?.caps?.[e]?.[Ai[t].capKey];return Number.isFinite(n)&&n>0?n:null}function Uo(e,t=Date.now()){if(!e||!Wy||!Bn?.caps)return null;If(t);let n=ta.get(e);for(let r of Object.keys(Ai)){let o=GI(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:_f(s),resetsAt:Ai[r].nextStart(t)}}return null}function KI(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${Dr[t.window]}`;return Ti.has(n)?!1:(Ti.add(n),!0)}function DI(e,t,n,r=Date.now()){if(!e||!t)return;If(r);let o=p5(e);for(let[s,a]of Object.entries(Ai))n>=Dr[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function f5(e,t,n=Date.now()){if(!Bn?.caps||!Hy)return;let r=ta.get(e);if(r)for(let[o,s]of Object.entries(Ai)){let a=GI(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*FI||i>=a)continue;let c=`warn:${e}:${o}:${Dr[o]}`;if(!Ti.has(c)){Ti.add(c);try{let l=await Hy(t);if(!l)continue;await D(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:_f(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function VI(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 $f(e,{source:t="local",updatedAt:n=Date.now()}={}){Bn={caps:VI(e),updatedAt:n,source:t};try{await Uy.mkdir(LI,{recursive:!0}),await Uy.writeFile(jI(),JSON.stringify(Bn,null,2))}catch{}return Kl()}function Kl(e=Date.now()){If(e);let t=new Set([...ta.keys(),...Object.keys(Bn?.caps||{})]),n={};for(let r of t){let o=ta.get(r);n[r]={weeklyUsd:_f(o?.weekly||0),monthlyUsd:_f(o?.monthly||0)}}return{caps:Bn?.caps||{},configured:!!Bn,seeded:Wy,updatedAt:Bn?.updatedAt??null,spent:n,windows:{weekly:{start:Dr.weekly,resetsAt:WI(e)},monthly:{start:Dr.monthly,resetsAt:qI(e)}},warnPct:FI}}async function zI({listTracks:e,getTrack:t}={}){Hy=t||null,If();try{let o=JSON.parse(await Uy.readFile(jI(),"utf8"));Bn={caps:VI(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{Bn=null}let n=Date.now();at.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=gn(o);DI(o.provider||"unknown",s,o.ts??Date.now()),f5(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(Dr.weekly,Dr.monthly);for(let o of await e?.()||[]){let s;try{s=await V(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||DI(a.provider||"unknown",gn(a).usd,i,n)}}return Wy=!0,Kl()}var LI,jI,FI,Ai,Bn,Wy,Dr,ta,Ti,Hy,p5,_f,Rf=K(()=>{be();Bo();LI=process.env.BOSTRAT_STATE_DIR||BI.join(process.env.HOME||d5.tmpdir(),".bostrat"),jI=()=>BI.join(LI,"usage-caps.json"),FI=.8;Ai={weekly:{startOf:UI,nextStart:WI,capKey:"weeklyUsd"},monthly:{startOf:HI,nextStart:qI,capKey:"monthlyUsd"}},Bn=null,Wy=!1,Dr={weekly:0,monthly:0},ta=new Map,Ti=new Set,Hy=null,p5=e=>{let t=ta.get(e);return t||(t={weekly:0,monthly:0},ta.set(e,t)),t};_f=e=>Math.round(e*1e4)/1e4});import h5 from"node:fs/promises";import m5 from"node:os";import JI from"node:path";function qy(e){return e==="codex"?b5:e==="cursor"?t$:QI}function YI(e){let t=String(e||"").split(`
|
|
274
|
+
`}else if(o==="/"&&e[r+1]==="*"){for(r+=2;r<e.length&&!(e[r]==="*"&&e[r+1]==="/");)r++;r++}else t+=o}return JSON.parse(t.replace(/,(\s*[}\]])/g,"$1"))}async function mI(e,t=It()){if(!t.setup)return null;if(await hI(e,Sf)){let n=Ny.join(e,Sf),r=await Ul.readFile(n,"utf8").catch(()=>null);if(r!==null){let o=await Ul.access(n,Ul.constants.X_OK).then(()=>!0,()=>!1);return{source:"bostrat-setup",file:Sf,...o?{bin:n,args:[]}:{bin:"sh",args:[n]},display:Sf,hash:Cy(r)}}}if(!t.devcontainer)return null;for(let n of zq){if(!await hI(e,n))continue;let r;try{r=Qq(await Ul.readFile(Ny.join(e,n),"utf8"))}catch{continue}let o=r?.postCreateCommand;if(typeof o=="string"&&o.trim())return{source:"devcontainer",file:n,bin:"sh",args:["-c",o],display:o.trim(),hash:Cy(`s:${o}`)};if(Array.isArray(o)&&o.length&&o.every(s=>typeof s=="string"))return{source:"devcontainer",file:n,bin:o[0],args:o.slice(1),display:o.join(" "),hash:Cy(`a:${JSON.stringify(o)}`)}}return null}function e5(e,t,n){if(e.timedOut)return`timed out after ${Math.max(1,Math.round(n.setupTimeoutMs/6e4))} min`;let r=[...t].reverse().find(a=>a.trim()),o=e.signal?`was killed (${e.signal})`:`exited with code ${e.code??"?"}`,s=r?`${o}: ${r.trim()}`:o;return s.length>fI?`${s.slice(0,fI-1)}\u2026`:s}async function wI(e,t,{cfg:n=It(),onOutput:r=null}={}){let o=Date.now(),s="",a=0,i=0,c=!1,l=m=>{if(!r||!s.trim()||!m&&Date.now()-i<Jq)return;if(a>=Yq){c||(c=!0,r({lines:["\u2026 further output is not streamed; the tail rides the final event"],truncated:!0})),s="";return}let h=wf(s,Xq).map(y=>y.slice(0,300)),g=h.join(`
|
|
275
|
+
`);for(;g.length>Zq&&h.length>1;)h.shift(),g=h.join(`
|
|
276
|
+
`);s="",a++,i=Date.now(),r({lines:h})};await Ul.mkdir(Ny.join(n.root,".tmp"),{recursive:!0}).catch(()=>{});let u={...hy(n),COREPACK_ENABLE_DOWNLOAD_PROMPT:"0",BOSTRAT_SETUP:e.source},d=await my(e.bin,e.args,{cwd:t,env:u,timeoutMs:n.setupTimeoutMs,onChunk:m=>{s=(s+m).slice(-8*1024),l(!1)}});c||l(!0);let p=wf(d.out),w=Date.now()-o;return d.code===0&&!d.timedOut?{status:"done",durationMs:w,exitCode:0,tail:p}:{status:"failed",durationMs:w,exitCode:d.code,timedOut:d.timedOut,reason:e5(d,p,n),tail:p}}var Vq,Sf,zq,fI,Jq,Yq,Xq,Zq,hI,Cy,gI=K(()=>{gf();Vq=Kq(Gq),Sf=".bostrat/setup",zq=[".devcontainer/devcontainer.json",".devcontainer.json"],fI=160,Jq=3e3,Yq=40,Xq=20,Zq=1500,hI=(e,t)=>Vq("git",["-C",e,"ls-files","--error-unmatch","--",t],{timeout:5e3}).then(()=>!0,()=>!1);Cy=e=>qq("sha256").update(e).digest("hex").slice(0,12)});import Dn from"node:fs/promises";import jt from"node:path";import{createHash as kI,randomUUID as xI}from"node:crypto";import{execFile as t5}from"node:child_process";import{promisify as n5}from"node:util";function _I({workspaces:e,linkedRepos:t}={}){typeof e=="function"&&(TI=e),typeof t=="function"&&(EI=t)}async function $I(e){let t=await Re(e).catch(()=>null);if(t)return t;if(Py.has(e))return Py.get(e);let n=null;try{let{stdout:r}=await r5("git",["-C",e,"rev-parse","--git-common-dir"],{timeout:5e3}),o=await Dn.realpath(jt.resolve(e,r.trim()));n=`_local/${jt.basename(o)===".git"?jt.basename(jt.dirname(o)):jt.basename(o)}-${kI("sha256").update(o).digest("hex").slice(0,8)}`}catch{n=null}return Py.set(e,n),n}async function ql(e,t,n,r,o={}){if(!e?.track?.id)return;let s=By.get(e.workspaceDir)??new Set,a=`${n.key}:${r}`;if(!s.has(a)){if(r==="started")for(let i of["ready","failed"])s.delete(`${n.key}:${i}`);else s.delete(`${n.key}:started`);s.add(a),By.set(e.workspaceDir,s),await Hl(e,"deps.prepare",{repo:n.repo,relDir:n.relDir,dir:t.dir,key:n.key,status:r,batch:e.batch,...o})}}async function Hl(e,t,n){if(!e?.track?.id)return;let r=()=>D(e.track,{type:t,actor:"orchestrator",source:"orchestrator",boxId:e.boxId??null,payload:n}).catch(s=>console.warn(`[deps] ${e.track.id}: ${t} not recorded: ${s?.message||s}`)),o=vi.get(e.workspaceDir);o?o.events.push(r):await r()}async function Ly(e){let t=jt.resolve(e),n=vi.get(t);if(!n)return 0;vi.delete(t),clearTimeout(n.timer);for(let r of n.events)await r();return n.events.length}function s5(e){if(vi.has(e))return;let t=setTimeout(()=>vi.delete(e),o5);t.unref(),vi.set(e,{events:[],timer:t})}function Tf(e){let t={},n=r=>{t[r.workspaceDir]={track:r.track?{id:r.track.id,cwd:r.track.cwd??null}:null,boxId:r.boxId??null,batch:r.batch}};for(let r of Wl.values())for(let o of r.values())n(o.ctx);for(let r of Af.values())n(r.ctx);return Dy=Dy.then(()=>dt(AI(e),{version:1,workspaces:t})).catch(()=>{}),Dy}async function OI(e,t){let n=await Dn.readFile(RI(e,t),"utf8").then(JSON.parse,()=>null);return n?.workspace===t&&n.repos?n:{workspace:t,repos:{}}}async function yI(e,t,n,r){let o=await OI(e,t);o.repos[n]=r,await dt(RI(e,t),o).catch(()=>{})}async function a5(){try{return new Set((await EI()).map(e=>String(e).toLowerCase()))}catch{return new Set}}function i5(e,t,n,r,o,s){let a=`${e.workspaceDir}\0${t.dir}`,i=xI().slice(0,8),c={repo:r.toLowerCase(),dir:t.dir,source:n.source,command:n.display,run:i},l={source:n.source,display:n.display,hash:n.hash,status:"running",run:i,startedAt:Date.now()};Af.set(a,{ctx:e,entry:l});let u=(async()=>{s?.status==="running"&&s.run&&await Hl(e,"deps.setup",{...c,run:s.run,status:"failed",reason:"interrupted by a node restart \u2014 run again",tail:[]}),await yI(o,e.workspaceDir,t.dir,l),await Hl(e,"deps.setup",{...c,status:"started"})})();return J_(async()=>(await u,wI(n,t.repoDir,{cfg:o,onOutput:({lines:d,truncated:p})=>{Hl(e,"deps.setup",{...c,status:"output",lines:d,...p?{truncated:!0}:{}})}}))).catch(d=>({status:"failed",reason:String(d?.message||d).slice(0,160),tail:[],durationMs:0,exitCode:null})).then(async d=>{let p={...l,status:d.status,finishedAt:Date.now(),durationMs:d.durationMs,...d.reason?{reason:d.reason}:{}};await yI(o,e.workspaceDir,t.dir,p),Af.delete(a),await Hl(e,"deps.setup",{...c,status:d.status,durationMs:d.durationMs,exitCode:d.exitCode,...d.status==="failed"?{reason:d.reason,tail:(d.tail??[]).slice(-vI)}:{}}),await Dn.stat(e.workspaceDir).catch(()=>null)&&await jy(e,{kick:!1}),await Tf(o)}).catch(d=>console.warn(`[deps] ${e.workspaceDir}: setup settle failed: ${d?.message||d}`)),l}async function c5(e,t,{kick:n}){let r=[],o=new Set,s=!1;if(!t.setup)return{rows:r,handled:o,started:s};let a=null,i=null;for(let c of await by(e.workspaceDir)){let l=await mI(c.dir,t);if(!l)continue;let u={dir:c.name??".",repoDir:c.dir},d=await Re(c.dir).catch(()=>null);a??=await a5();let p={dir:u.dir,source:l.source,display:l.display};if(!d||!a.has(d.toLowerCase())){r.push({...p,status:"not-linked"});continue}if(o.add(c.dir),Af.get(`${e.workspaceDir}\0${u.dir}`)){r.push({...p,status:"running"});continue}i??=await OI(t,e.workspaceDir);let m=i.repos[u.dir]??null,h=m&&m.hash===l.hash&&(m.status==="done"||m.status==="failed"),g=h&&m.status==="failed"&&Date.now()-(m.finishedAt||0)>=t.retryMs;if(h&&!g){r.push({...p,status:m.status,reason:m.reason,durationMs:m.durationMs});continue}if(!n){r.push({...p,status:"pending"});continue}i5(e,u,l,d,t,m),s=!0,r.push({...p,status:"running"})}return{rows:r,handled:o,started:s}}async function MI(e){let t=e.relDir==="."?"node_modules":`${e.relDir}/node_modules`;await jl(e.repoDir,[`/${t}`])}async function CI(e,t,n){let r=Wl.get(e.key);Wl.delete(e.key);for(let o of r?.values()??[])try{if(!await Dn.stat(o.ctx.workspaceDir).catch(()=>null))continue;if(n.status==="ready"){let s=await yy(e,o.pkg.pkgDir,t);s.linked&&await MI(o.pkg),await ql(o.ctx,o.pkg,e,"ready",{linked:s.linked,durationMs:n.durationMs,sizeBytes:n.sizeBytes})}else await ql(o.ctx,o.pkg,e,"failed",{reason:n.reason,tail:(n.tail??[]).slice(-vI),durationMs:n.durationMs});await jy(o.ctx,{kick:!1})}catch(s){console.warn(`[deps] ${o.ctx.workspaceDir}: settle failed: ${s?.message||s}`)}await Tf(t)}function bI(e,t,n,r,o,{announce:s}){let a=Wl.get(e.key)??new Map,i=!a.has(r.workspaceDir);return a.set(r.workspaceDir,{pkg:n,ctx:r}),Wl.set(e.key,a),mf(e.key)||wy(e,t,{cfg:o}).then(c=>CI(e,o,c)),i&&s?ql(r,n,e,"started"):null}async function l5(e,{kick:t,announce:n}){let r=It(),{workspaceDir:o}=e;if(!r.enabled)return ky(o);let s=new Map,a=0,i=await c5(e,r,{kick:t}),c=i.started,l=new Set(i.rows.filter(u=>u.status==="running").map(u=>u.dir));for(let u of await Dl(o)){if(i.handled.has(u.repoDir)){l.has(u.repoName??".")&&s.set(u.dir,{status:"setup"});continue}let d=await Dn.lstat(jt.join(u.pkgDir,"node_modules")).catch(()=>null),p=d?.isDirectory()?await ki(u.pkgDir):null;if(d&&(!p||p.links==="replaced"))continue;let w=await $I(u.repoDir),m=w?await py(u.pkgDir,u.lockfiles):{storable:!1};if(!m.storable)continue;let h=uy({repoId:w,relDir:u.relDir,lockHash:m.lockHash},r);if(p?.links==="intact"&&p.key===h.key){await Z_(p.store);continue}let g=p?.links==="intact";if(await bi(h)){let b=await yy(h,u.pkgDir,r);b.linked&&(await MI(u),b.already||await ql(e,u,h,"ready",{linked:!0,cached:!0}));continue}if(mf(h.key)){await bI(h,m.inputs,u,e,r,{announce:n}),c=!0,s.set(u.dir,g?{stale:!0}:{status:"preparing"});continue}let y=await fy(h,r);if(t&&!y?.fresh&&a<SI){a++,await bI(h,m.inputs,u,e,r,{announce:n}),c=!0,s.set(u.dir,g?{stale:!0}:{status:"preparing"});continue}y&&(g||s.set(u.dir,{status:"failed",reason:y.reason}),t&&await ql(e,u,h,"failed",{reason:y.reason,tail:y.tail??[],cached:!0}))}return c&&await Tf(r),ky(o,{overlay:s,setups:i.rows})}function jy(e,t){let r=(vf.get(e.workspaceDir)??Promise.resolve()).then(()=>l5(e,t)).catch(s=>(console.warn(`[deps] ${e.workspaceDir}: provisioning failed: ${s?.message||s}`),null)),o=r.then(()=>{vf.get(e.workspaceDir)===o&&vf.delete(e.workspaceDir)});return vf.set(e.workspaceDir,o),r}function Gl(e,{track:t=null,boxId:n=null,kick:r=!0,batch:o=null,announce:s=!0,hold:a=!1}={}){a&&t?.id&&s5(jt.resolve(e));let i={workspaceDir:jt.resolve(e),track:t?.id?{id:t.id,cwd:t.cwd??null}:null,boxId:n,batch:o||xI().slice(0,8)};return jy(i,{kick:r,announce:s})}async function NI(e){let t=It();if(!t.enabled)return 0;let n=0;try{let r=await $I(e);if(!r)return 0;for(let o of await Dl(e)){if(n>=SI)break;let s=await py(o.pkgDir,o.lockfiles);if(!s.storable)continue;let a=uy({repoId:r,relDir:o.relDir,lockHash:s.lockHash},t);await bi(a)||mf(a.key)||(await fy(a,t))?.fresh||(n++,wy(a,s.inputs,{cfg:t}).then(i=>CI(a,t,i)))}}catch(r){console.warn(`[deps] prewarm of ${e} failed: ${r?.message||r}`)}return n}async function PI(){let e=It();if(!e.enabled)return 0;await Y_(e);let t=jt.join(e.root,".setup");for(let o of await Dn.readdir(t).catch(()=>[])){let s=await Dn.readFile(jt.join(t,o),"utf8").then(JSON.parse,()=>null);(!s?.workspace||!await Dn.stat(s.workspace).catch(()=>null))&&await Dn.rm(jt.join(t,o),{force:!0}).catch(()=>{})}let n=await Dn.readFile(AI(e),"utf8").then(JSON.parse,()=>null),r=0;for(let[o,s]of Object.entries(n?.workspaces??{}))await Dn.stat(o).catch(()=>null)&&(By.set(jt.resolve(o),new Set),r++,Gl(o,{track:s.track,boxId:s.boxId,batch:s.batch,kick:!0,announce:!1}));return r||await Tf(e),r}var r5,SI,vI,AI,Wl,By,vf,vi,o5,Af,TI,EI,II,Py,Dy,RI,Fy=K(()=>{be();Fl();er();rr();xy();gI();gf();r5=n5(t5),SI=12,vI=20,AI=e=>jt.join(e.root,"pending.json"),Wl=new Map,By=new Map,vf=new Map,vi=new Map,o5=2*6e4,Af=new Map,TI=async()=>[],EI=async()=>[];eI({referenced:async()=>{let e=new Set;for(let t of await TI().catch(()=>[]))for(let n of await Dl(t).catch(()=>[])){let r=await ki(n.pkgDir).catch(()=>null);r?.links==="intact"&&e.add(r.store)}return[...e]}});II=()=>z_(),Py=new Map;Dy=Promise.resolve();RI=(e,t)=>jt.join(e.root,".setup",`${kI("sha256").update(t).digest("hex").slice(0,16)}.json`)});function Ef(e,{at:t=Date.now(),reason:n="node-transfer"}={}){let r=!1;for(let o of e?.boxes||[]){if(!o||typeof o!="object")continue;!u5.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 He,u5,yn=K(()=>{He=e=>!!(e&&(e.archivedAt||e.transferredTo)),u5=new Set(["merged","conflict","canceled","failed","handed-off"])});import Uy from"node:fs/promises";import BI from"node:path";import d5 from"node:os";function UI(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(t.getDate()-(t.getDay()+6)%7),t.getTime()}function HI(e){let t=new Date(e);return t.setHours(0,0,0,0),t.setDate(1),t.getTime()}function WI(e){let t=new Date(UI(e));return t.setDate(t.getDate()+7),t.getTime()}function qI(e){let t=new Date(HI(e));return t.setMonth(t.getMonth()+1),t.getTime()}function If(e=Date.now()){for(let[t,n]of Object.entries(Ai)){let r=n.startOf(e);if(r!==Dr[t]){Dr[t]=r;for(let o of ta.values())o[t]=0;for(let o of Ti)o.includes(`:${t}:`)&&!o.endsWith(`:${r}`)&&Ti.delete(o)}}}function GI(e,t){let n=Bn?.caps?.[e]?.[Ai[t].capKey];return Number.isFinite(n)&&n>0?n:null}function Uo(e,t=Date.now()){if(!e||!Wy||!Bn?.caps)return null;If(t);let n=ta.get(e);for(let r of Object.keys(Ai)){let o=GI(e,r);if(o==null)continue;let s=n?.[r]||0;if(s>=o)return{provider:e,window:r,limitUsd:o,spentUsd:_f(s),resetsAt:Ai[r].nextStart(t)}}return null}function KI(e,t){let n=`hit:${e}:${t.provider}:${t.window}:${Dr[t.window]}`;return Ti.has(n)?!1:(Ti.add(n),!0)}function DI(e,t,n,r=Date.now()){if(!e||!t)return;If(r);let o=p5(e);for(let[s,a]of Object.entries(Ai))n>=Dr[s]&&n<a.nextStart(r)&&(o[s]+=t)}async function f5(e,t,n=Date.now()){if(!Bn?.caps||!Hy)return;let r=ta.get(e);if(r)for(let[o,s]of Object.entries(Ai)){let a=GI(e,o);if(a==null)continue;let i=r[o]||0;if(i<a*FI||i>=a)continue;let c=`warn:${e}:${o}:${Dr[o]}`;if(!Ti.has(c)){Ti.add(c);try{let l=await Hy(t);if(!l)continue;await D(l,{type:"usage.cap.warning",actor:"system",provider:e,payload:{provider:e,window:o,limitUsd:a,spentUsd:_f(i),pct:Math.round(i/a*100),resetsAt:s.nextStart(n)}})}catch{}}}}function VI(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 $f(e,{source:t="local",updatedAt:n=Date.now()}={}){Bn={caps:VI(e),updatedAt:n,source:t};try{await Uy.mkdir(LI,{recursive:!0}),await Uy.writeFile(jI(),JSON.stringify(Bn,null,2))}catch{}return Kl()}function Kl(e=Date.now()){If(e);let t=new Set([...ta.keys(),...Object.keys(Bn?.caps||{})]),n={};for(let r of t){let o=ta.get(r);n[r]={weeklyUsd:_f(o?.weekly||0),monthlyUsd:_f(o?.monthly||0)}}return{caps:Bn?.caps||{},configured:!!Bn,seeded:Wy,updatedAt:Bn?.updatedAt??null,spent:n,windows:{weekly:{start:Dr.weekly,resetsAt:WI(e)},monthly:{start:Dr.monthly,resetsAt:qI(e)}},warnPct:FI}}async function zI({listTracks:e,getTrack:t}={}){Hy=t||null,If();try{let o=JSON.parse(await Uy.readFile(jI(),"utf8"));Bn={caps:VI(o?.caps),updatedAt:o?.updatedAt??null,source:o?.source??"file"}}catch{Bn=null}let n=Date.now();at.on("event",o=>{if(o?.type!=="cost.recorded")return;let{usd:s}=gn(o);DI(o.provider||"unknown",s,o.ts??Date.now()),f5(o.provider||"unknown",o.trackId).catch(()=>{})});let r=Math.min(Dr.weekly,Dr.monthly);for(let o of await e?.()||[]){let s;try{s=await V(o)}catch{continue}for(let a of s){if(a.type!=="cost.recorded")continue;let i=a.ts??0;i<r||i>=n||DI(a.provider||"unknown",gn(a).usd,i,n)}}return Wy=!0,Kl()}var LI,jI,FI,Ai,Bn,Wy,Dr,ta,Ti,Hy,p5,_f,Rf=K(()=>{be();Bo();LI=process.env.BOSTRAT_STATE_DIR||BI.join(process.env.HOME||d5.tmpdir(),".bostrat"),jI=()=>BI.join(LI,"usage-caps.json"),FI=.8;Ai={weekly:{startOf:UI,nextStart:WI,capKey:"weeklyUsd"},monthly:{startOf:HI,nextStart:qI,capKey:"monthlyUsd"}},Bn=null,Wy=!1,Dr={weekly:0,monthly:0},ta=new Map,Ti=new Set,Hy=null,p5=e=>{let t=ta.get(e);return t||(t={weekly:0,monthly:0},ta.set(e,t)),t};_f=e=>Math.round(e*1e4)/1e4});import h5 from"node:fs/promises";import m5 from"node:os";import JI from"node:path";function qy(e){return e==="codex"?b5:e==="cursor"?t$:QI}function YI(e){let t=String(e||"").split(`
|
|
277
277
|
`),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 XI(e){let t=String(e||"").split(`
|
|
278
278
|
`),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 k5(e){let t=String(e||"").split(`
|
|
279
279
|
`);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 ZI(e){let t=String(e||"").split(`
|
|
280
280
|
`),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 n$(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&&!e$.has(o))throw new Error(`unknown codex effort "${o}" (low | medium | high | xhigh)`);return{model:r,effort:o||null}}if(e==="cursor"){let r=t$.find(o=>o.alias===n);return{model:n,filter:r?r.label:n}}if(!y5.has(n))throw new Error(`unknown model "${n}"`);return{model:n}}async function Ei(e,t,{timeoutMs:n=w5}={}){let r=Date.now()+n;for(;;){let o=await Fe(e,{lines:80}).catch(()=>""),s=t(o);if(s)return s;if(Date.now()>r)return null;await Of(g5)}}function _i(e,t){return String(e||"").split(`
|
|
281
|
-
`).filter(n=>t.test(n)).length}function x5(e,t={set:0,ask:0}){return Eg(e)&&_i(e,o$)>(t.ask||0)?"confirm":_i(e,r$)>(t.set||0)?"set":null}async function v5(e,t){let n=await Fe(e,{lines:80}).catch(()=>""),r={set:_i(n,r$),ask:_i(n,o$)};await ot(e,`/model ${t.model}`,ar("claude"));let o=await Ei(e,s=>x5(s,r),{timeoutMs:S5});return o==="confirm"?{verified:!1,awaitingConfirm:!0,note:"claude asked to confirm the switch"}:o==="set"?{verified:!0}:{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function A5(e,t){await mp(e),await ot(e,"/model",{enter:!1}),await Of(250),await tt(e,["Enter"],{kind:"model-switch"});let n=await Ei(e,YI);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await tt(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=k5(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await ot(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await Ei(e,i=>XI(i)||!YI(i)&&o(i)&&{done:o(i)});if(!s)throw await tt(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?e$.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 tt(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await ot(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Ei(e,i=>!XI(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 T5(){let e=JI.join(process.env.CURSOR_CONFIG_DIR||JI.join(m5.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await h5.readFile(e,"utf8"))?.model||null}catch{return null}}async function E5(e,t){await mp(e),await wp(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await Ei(e,ZI),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 Ei(e,ZI,{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 tt(e,["Down"],{kind:"model-switch"}),await Of(250)}if(!n||!s||!o(s)){await tt(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await tt(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 tt(e,["Enter"],{kind:"model-switch"}),await Of(800);let a=await T5();return{verified:!!a&&(a.modelId===t.model||a.displayModelId===t.model||r(a.displayName).startsWith(r(t.filter))),model:a?.modelId||null,note:"cursor applies this as the global default for new sessions too"}}async function s$(e,t,n){return e==="codex"?A5(t,n):e==="cursor"?E5(t,n):v5(t,n)}var Of,w5,g5,QI,y5,b5,e$,t$,r$,o$,S5,a$=K(()=>{kt();Al();Hp();Of=e=>new Promise(t=>setTimeout(t,e)),w5=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,g5=300,QI=[{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"}],y5=new Set([...QI.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"]),b5=[{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"}],e$=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),t$=[{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"}];r$=/\bSet model to\b/,o$=/^\s*Switch model\?\s*$/;S5=Number(process.env.BOSTRAT_CLAUDE_MODEL_OUTCOME_MS)||3e3});function Nf(e){let t=e||{},n=_5(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function _5(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{text:e.text,boxRole:e.boxRole,...e.kind?{kind:e.kind}:{},...e.attachments?.length?{attachments:e.attachments}:{},...e.deliveryId?{deliveryId:e.deliveryId}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{saidTs:e.saidTs,text:e.text,boxRole:e.boxRole}};case"orchestration-prompt":return{type:"turn.user",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{text:e.prompt,kind:e.kind,boxRole:e.boxRole,...e.deliveryId?{deliveryId:e.deliveryId}:{},...e.detail?{detail:e.detail}:{}}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:gt(e.toAgent),payload:{from:e.from,fromAgent:e.fromAgent,to:e.to,toAgent:e.toAgent,reason:e.reason,handoffStartedAt:e.handoffStartedAt,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,singleBox:e.singleBox,forced:e.forced,recovered:e.recovered,checkpoint:e.checkpoint,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:gt(e.toAgent),payload:{box:e.box,fromAgent:e.fromAgent,toAgent:e.toAgent,reason:e.reason,error:e.error,rolledBack:e.rolledBack,handoffStartedAt:e.handoffStartedAt}};case"subtask-delegated":return{type:"subtask.delegated",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:gt(e.toAgent),payload:{task:e.task,subtaskId:e.subtaskId,reason:e.reason}};case"subtask-merged":return{type:"subtask.merged",actor:"orchestrator",source:"orchestrator",boxId:e.box||e.from,provider:gt(e.agent),payload:{...ur(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:gt(e.agent||e.toAgent),payload:{kind:"subtask-failed",...ur(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{change:"subtask-resumed",...ur(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",...ur(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...ur(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...ur(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{change:"rehydrated",...e.fresh?{fresh:!0}:{}}};case"lead-refreshed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{change:"lead-refreshed",box:e.box,agent:e.agent,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,reason:e.reason,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:gt(e.agent),payload:{...ur(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...ur(e)}};case"retag-failed":return{type:"error",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(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:gt(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};case"delivery-held":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{kind:"delivery-held",...ur(e)}};case"startup-gate":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{kind:"startup-gate",...ur(e)}};default:return null}}function l$(e,t){let n=Nf(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;Pf(()=>D(r,n))}async function u$(e){if(!(!e?.id||i$.has(e.id))){i$.add(e.id);try{let t=await V(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=Nf(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await D(e,o)}}catch{}}}function ur(e){let{type:t,at:n,...r}=e;return r}function d$(e,t,n){!n?.promptId||Cf.get(e.id)===n.promptId||(Cf.set(e.id,n.promptId),Pf(()=>D(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:gt(n.provider||t?.agent),payload:{promptId:n.promptId,question:n.question||n.title||null,options:(n.options||[]).map(r=>r?.label??r).slice(0,12)}})))}function p$(e,t,n,r={}){Cf.delete(e.id),Pf(()=>D(e,{type:"prompt.dismissed",actor:"user",source:"orchestrator",boxId:t?.name,provider:gt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}function Gy(e,t,n,r={}){Cf.delete(e.id),Pf(()=>D(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:gt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var gt,Mf,Pf,c$,i$,Cf,Ky=K(()=>{be();gt=e=>e||null;Mf=Promise.resolve(),Pf=e=>(Mf=Mf.then(e).catch(()=>{}),Mf),c$=()=>Mf;i$=new Set;Cf=new Map});import I5 from"node:crypto";import Df from"node:fs/promises";import f$ from"node:path";import $5 from"node:os";function g$(e){w$=typeof e=="function"?e:async()=>new Set}function R5(e,t,n){if(e.originNode&&e.originNode===t)return!0;let r=e.data?.trackId;return!!r&&n.has(r)}async function Ye(){return Br||(Vy??=Df.readFile(Jy,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(Br=e,!t&&et()){let{records:n,source:r}=await xt("prlinks").catch(()=>({records:[],source:"error"}));if(r==="plane"){let o=pA(),s=await w$().catch(()=>new Set),a=0;for(let i of n){if(i.deletedAt||!i.data?.repo||i.data?.number==null)continue;if(!R5(i,o,s)){a++;continue}let{id:c,updatedAt:l,...u}=i.data;Br[me(u.repo,u.number)]=u}a&&console.log(`[pr-links] restore: ${Object.keys(Br).length} link(s) re-seeded, ${a} other-node record(s) left on the plane`),Object.keys(Br).length&&await Yy().catch(()=>{})}}return Br}).finally(()=>Vy=null),Vy)}async function Yy(){let e=JSON.stringify({links:Br},null,2),t=`${Jy}.${process.pid}.tmp`;await Df.mkdir(h$,{recursive:!0}),await Df.writeFile(t,e),await Df.rename(t,Jy)}async function it(e){zy=zy.then(Yy,Yy),await zy.catch(()=>{});let t=Br?.[e];t&&Pt("prlinks",{id:m$(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function ln({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 Ye(),c=me(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:O5.has(a),firstSeen:Date.now()},await it(me(e,t)),{link:i[c],created:!0})}async function Lr(e,t){if(!e||t==null)return null;let n=(await Ye())[me(e,t)];return!n||n.announced?null:(n.announced=!0,await it(me(e,t)),n)}async function y$(e,t){if(!e||t==null)return!1;let n=(await Ye())[me(e,t)];return n?.notifyOnMerge?(delete n.notifyOnMerge,await it(me(e,t)),!0):!1}async function pt(e,t){return!e||t==null?null:(await Ye())[me(e,t)]??null}async function Ho(e,t,n){if(!e||t==null)return null;let r=(await Ye())[me(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 it(me(e,t)),r):null}async function b$(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ye())[me(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await it(me(e,t)),o):null}async function k$(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ye())[me(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await it(me(e,t)),o):null}async function Bf(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ye())[me(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await it(me(e,t)),r)}async function Lf(e,t){if(!e||t==null)return null;let n=(await Ye())[me(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await it(me(e,t)),n)}async function jf(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ye())[me(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await it(me(e,t)),r)}async function Ff(e,t){if(!e||t==null)return null;let n=(await Ye())[me(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await it(me(e,t)),n)}async function x$(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await Ye())[me(e,t)];return r?(r.baseFoldAt=n,await it(me(e,t)),r):null}async function S$(e,t,{misses:n,until:r}){if(!e||t==null)return null;let o=(await Ye())[me(e,t)];return o?(o.brokerRefused={misses:Number(n)||0,until:Number(r)||0},await it(me(e,t)),o):null}async function v$(e,t){if(!e||t==null)return null;let n=(await Ye())[me(e,t)];return n?.brokerRefused?(delete n.brokerRefused,await it(me(e,t)),n):null}async function A$(e,t){if(!e||t==null)return null;let n=(await Ye())[me(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await it(me(e,t)),n)}async function Xy(e,t,n){if(!e||t==null||!n)return null;let r=(await Ye())[me(e,t)];return r?(r.lastHeadSha=n,await it(me(e,t)),r):null}async function T$(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await Ye())[me(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 it(me(e,t))),{prev:o,link:r}}async function Vl(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await Ye())[me(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await it(me(e,t)),r):null}async function na(e,t,n=!0){if(!e||t==null)return null;let r=(await Ye())[me(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await it(me(e,t)),r):null}async function ra(e,t,n=!0){if(!e||t==null)return null;let r=(await Ye())[me(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await it(me(e,t)),r):null}async function E$(e,t,n){if(!e||t==null)return null;let r=(await Ye())[me(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 it(me(e,t)),r}async function _$(e,t,n){if(!e||t==null)return null;let r=(await Ye())[me(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 it(me(e,t)),r}async function zl(e,t){if(!e||t==null)return null;let n=(await Ye())[me(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 it(me(e,t)),n)}async function I$(){return Object.values(await Ye()).filter(e=>!M5.has(e.state))}async function Ln(){return Object.values(await Ye()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function $$(){if(!et())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await xt("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Ye(),r=0;for(let[o,s]of Object.entries(n))await Pt("prlinks",{id:m$(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var h$,Jy,me,m$,Br,Vy,zy,w$,O5,M5,jn=K(()=>{bo();h$=process.env.BOSTRAT_STATE_DIR||f$.join(process.env.HOME||$5.tmpdir(),".bostrat"),Jy=f$.join(h$,"pr-links.json"),me=(e,t)=>`${e}#${Number(t)}`,m$=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=I5.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},Br=null,Vy=null,zy=Promise.resolve(),w$=async()=>new Set;O5=new Set(["api","observed","reconciled"]);M5=new Set(["merged","closed","lost"])});import C5 from"node:fs";import Zy from"node:fs/promises";import C$ from"node:path";import N5 from"node:os";function D$(e,t=!1){if(!t&&e-O$<P5)return;O$=e;let n=JSON.stringify({windowStart:Ii,byCaller:Object.fromEntries(jr),lastHour:Wo});M$=M$.then(()=>Zy.mkdir(N$,{recursive:!0})).then(()=>Zy.writeFile(`${Uf}.tmp`,n)).then(()=>Zy.rename(`${Uf}.tmp`,Uf)).catch(()=>{})}function B$(e){e-Ii<P$||(Wo={start:Ii,total:Hf(jr),byCaller:Object.fromEntries(jr)},Wo.total&&console.log(`[github] ${Wo.total} calls last hour`,Wo.byCaller),Ii=e,jr=new Map,D$(e,!0))}function Fr(e="other",t=Date.now()){B$(t),jr.set(e,(jr.get(e)||0)+1),D$(t)}function L$(e=Date.now()){return B$(e),{windowStart:Ii,total:Hf(jr),byCaller:Object.fromEntries(jr),lastHour:Wo,backoffUntil:oa>e?oa:null}}function qo(e){return D5.test(String(e?.message||e||""))}function Go(e,t=Date.now()){return oa<=t&&console.warn(`[github] rate limited \u2014 backing off ${R$/6e4} min:`,String(e?.message||e||"").slice(0,200)),oa=Math.max(oa,t+R$),oa}function Wf(e=Date.now()){return Math.max(0,oa-e)}var N$,Uf,P$,R$,P5,Ii,jr,Wo,oa,O$,Hf,M$,D5,Jl=K(()=>{N$=process.env.BOSTRAT_STATE_DIR||C$.join(process.env.HOME||N5.tmpdir(),".bostrat"),Uf=C$.join(N$,"github-metrics.json"),P$=60*6e4,R$=5*6e4,P5=6e4,Ii=Date.now(),jr=new Map,Wo=null,oa=0,O$=0,Hf=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(C5.readFileSync(Uf,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<P$?(Ii=e.windowStart,jr=new Map(Object.entries(e.byCaller||{})),Wo=e.lastHour||null):Hf(new Map(Object.entries(e.byCaller||{})))&&(Wo={start:e.windowStart,total:Hf(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}M$=Promise.resolve();D5=/rate limit|too quickly|abuse detection|HTTP 429/i});import j$ from"node:fs/promises";import F$ from"node:path";import B5 from"node:os";function $i({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};qf.push(l),qf.length>j5&&qf.shift();let u=Qy.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)),Qy.set(e,u),F5(l),l}async function F5(e){try{await j$.mkdir(U$,{recursive:!0}),await j$.appendFile(L5,JSON.stringify(e)+`
|
|
282
|
-
`)}catch{}}function H$(){let e={};for(let[t,n]of Qy)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:qf.slice(-20)}}var U$,L5,j5,qf,Qy,Gf=K(()=>{U$=process.env.BOSTRAT_STATE_DIR||F$.join(process.env.HOME||B5.tmpdir(),".bostrat"),L5=F$.join(U$,"github-latency.ndjson"),j5=100,qf=[],Qy=new Map});import{execFile as U5}from"node:child_process";import{promisify as H5}from"node:util";import W$ from"node:fs/promises";import q$ from"node:path";async function W5(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([Oi("git",["-C",e,"rev-parse","HEAD"]),Oi("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await D({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function bn(e,t,n={}){let{caller:r="prs",...o}=n,s=await tr({cwd:e});Fr(r);try{let{stdout:a}=await Oi("gh",t,{cwd:e,...q5,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw qo(a)&&Go(a),a}}async function Xl(){if(Kf&&Date.now()-Kf.at<6e4)return Kf.data;let e;try{Fr("auth");let t=await Oi("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 $s();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return Kf={at:Date.now(),data:e},e}async function G5(e){try{let{stdout:t}=await Oi("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function V$(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 eb(e){let t=(e||[]).map(V$),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 V5(e,{expectsChecks:t=!1,headAt:n=0,now:r=Date.now(),windowMs:o=K5}={}){return!e||e.total>0||e.unavailable?null:t&&n>0&&r-n<o?"awaiting":"none"}async function J5(e,t=Date.now()){let n=G$.get(e);if(n&&t-n.at<z5)return n.expects;let r=!1;try{let o=q$.join(e,".github","workflows");for(let s of await W$.readdir(o)){if(!/\.ya?ml$/.test(s))continue;let a=await W$.readFile(q$.join(o,s),"utf8").catch(()=>"");if(/\bpull_request(_target)?\b/.test(a)){r=!0;break}}}catch{}return G$.set(e,{at:t,expects:r}),r}async function J$(e,t=Date.now()){return e?z$.has(e)?!0:J5(e,t):!1}function Y$(e,t,{now:n=Date.now(),slug:r=null,reap:o=!0}={}){let s=new Set;for(let a of t){let i=`${e}#${a.number}`;s.add(i),a.checks?.total>0&&z$.add(e);let c=Yl.get(i);a.headSha&&(!c||c.sha!==a.headSha)&&Yl.set(i,{sha:a.headSha,at:c?n:null});let l=sa.get(i);if(l&&a.checks?.total>0){sa.delete(i);let u=r||e;$i({change:"checks-registered",repo:u,number:a.number,githubAt:l.headAt,observedAt:n,source:"tab"}),console.log(`[pr-checks] ${u}#${a.number} checks registered ${n-l.headAt}ms after its head moved (${String(l.sha).slice(0,8)})`)}}if(o){for(let a of Yl.keys())a.startsWith(`${e}#`)&&!s.has(a)&&Yl.delete(a);for(let a of sa.keys())a.startsWith(`${e}#`)&&!s.has(a)&&sa.delete(a)}}function Y5(e,t){let n=Yl.get(`${e}#${t.number}`),r=n&&n.sha===t.headSha&&n.at||0;return Math.max(Date.parse(t.updatedAt||"")||0,r)}function X$(e,t,{expectsChecks:n,now:r=Date.now(),slug:o=null}){return(t||[]).map(s=>{if(!s.checks)return s;let a=Y5(e,s),i=V5(s.checks,{expectsChecks:n,headAt:a,now:r}),c=`${e}#${s.number}`;return i==="none"&&sa.delete(c),i==="awaiting"&&sa.get(c)?.sha!==s.headSha&&(sa.set(c,{sha:s.headSha,headAt:a}),console.log(`[pr-checks] ${o||e}#${s.number} head ${String(s.headSha).slice(0,8)} has no checks yet \u2014 awaiting registration`)),i?{...s,checks:{...s.checks,verdict:i}}:s})}function rb(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function Q$(e,t){if(!t)return null;let n=await Re(e);if(!n)return null;try{let r=await bn(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 eR(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 tR(e,t){let n=await Q$(e,t);return n===null?{...eb([]),unavailable:!0}:eb(eR(n))}function zf(e,t=eb(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 Z5(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){Ri.delete(s);continue}r.add(s),Ri.has(s)||Ri.set(s,n),o.mergeabilityPending=n-Ri.get(s)<X5}for(let o of Ri.keys())o.startsWith(`${e}#`)&&!r.has(o)&&Ri.delete(o);return t}async function Mi(e,t){let n=await Wr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let a=await bn(n.path,["pr","view",String(r),"--json",nb]);o=zf(JSON.parse(a))}catch(a){if(!rb(a))throw a;let i=await bn(n.path,["pr","view",String(r),"--json",Z$]),c=JSON.parse(i);o=zf(c,await tR(n.path,c.headRefOid))}let s=Date.now();return Y$(n.path,[o],{now:s,reap:!1}),X$(n.path,[o],{expectsChecks:await J$(n.path,s),now:s})[0]}async function kn(e,{caller:t="prs"}={}){try{let n=await bn(e,["pr","list","--json",nb,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>zf(r)).sort(K$)}catch(n){if(!rb(n))throw n;let r=await bn(e,["pr","list","--json",Z$,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>zf(o,await tR(e,o.headRefOid))))).sort(K$)}}function xn(){aa.clear()}function ob(e=Date.now()){for(let[t,n]of Ur){let r=Math.min(n.announcedAt??1/0,n.webhookAt??1/0);(r===1/0||e-r>t6)&&Ur.delete(t)}}async function Hr({repo:e,number:t,via:n="unknown",at:r=Date.now()}={}){if(!rR(e,t))return null;ob(r);let o=nR(e,t);o.announcedAt=r,o.via=n;let s=await Ts(e).catch(()=>null);return s?aa.delete(s):aa.clear(),console.log(`[pr-open] ${e}#${t} opened card announced via ${n}`+(o.webhookAt?` (opened webhook already in, ${r-o.webhookAt}ms ago)`:"")+` \u2014 ${s?"repo":"whole"} PR cache dropped`),o}function oR({repo:e,number:t,at:n=Date.now()}={}){if(!rR(e,t))return null;ob(n);let r=nR(e,t);return r.webhookAt==null&&(r.webhookAt=n),console.log(`[pr-open] ${e}#${t} opened webhook received`+(r.announcedAt?` ${n-r.announcedAt}ms after its card`:" (card not announced yet)")),r}function sR(e=Date.now()){return ob(e),[...Ur.values()].map(t=>({...t}))}function r6(e){if(!e)return;let t=`${String(e).toLowerCase()}#`,n;for(let[r,o]of Ur)!r.startsWith(t)||o.webhookAt==null||((n??={})[String(o.number)]=o.webhookAt);return n}function Vf(e,{fromCache:t,slug:n,expectsChecks:r=!1,now:o=Date.now()}){let s=r6(n),a=X$(e.path,e.prs,{expectsChecks:r,now:o,slug:n});return{...e,prs:a,readAt:e.readAt??null,fromCache:t,...s?{openedWebhooks:s}:{}}}function o6(e,t,n,r){if(!e)return;let o=`${String(e).toLowerCase()}#`;for(let[s,a]of Ur)!s.startsWith(o)||a.announcedAt==null||(t.prs||[]).some(i=>i.number===a.number)||(a.staleServes+=1,a.staleServes===1&&console.log(`[pr-open] ${e}#${a.number} poll served from cache (read ${r-n}ms old) without it, ${r-a.announcedAt}ms after its opened card`))}function s6(e,t,n){if(!e)return;let r=`${String(e).toLowerCase()}#`;for(let[o,s]of Ur){if(!o.startsWith(r))continue;if(!(t||[]).some(i=>i.number===s.number)){s.announcedAt!=null&&(s.freshMisses+=1,console.log(`[pr-open] ${e}#${s.number} fresh poll read still lacks it ${n-s.announcedAt}ms after its opened card`+(s.webhookAt?` (opened webhook seen ${n-s.webhookAt}ms ago)`:" (no opened webhook yet)")));continue}s.announcedAt!=null&&($i({change:"opened-listed",repo:e,number:s.number,githubAt:s.announcedAt,observedAt:n,lane:s.webhookAt!=null?"event":null,source:"tab"}),console.log(`[pr-open] ${e}#${s.number} listed ${n-s.announcedAt}ms after its opened card (${s.staleServes} cache read(s) and ${s.freshMisses} fresh read(s) served without it`+(s.webhookAt?`, opened webhook ${s.webhookAt-s.announcedAt}ms after the card)`:", no opened webhook seen)"))),Ur.delete(o)}}async function a6(e,t){if(!e)return t;for(let n of t){let r=await pt(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 Bf(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await jf(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function aR(){let e=await Xl();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await Ir())await G5(a.path)&&t.push(a);let n=Date.now(),r=Wf(n)>0,o=await Promise.all(t.map(async a=>{let i=aa.get(a.path),c=await Re(a.path).catch(()=>null),l=await J$(a.path,n),u=i?.pending?e6:Q5;if(i&&(r||n-i.at<u))return o6(c,i.entry,i.at,n),Vf(i.entry,{fromCache:!0,slug:c,expectsChecks:l,now:n});try{let d=Date.now(),p=Z5(a.path,await kn(a.path,{caller:"tab"}),n);if(Y$(a.path,p,{now:Date.now(),slug:c}),await a6(c,p),s6(c,p,Date.now()),i?.entry?.prs)for(let g of p)i.entry.prs.find(b=>b.number===g.number)?.checks?.pending>0&&g.checks.total>0&&g.checks.pending===0&&$i({change:g.checks.failed>0?"checks-failed":"checks-green",repo:c||a.name,number:g.number,githubAt:g.checks.settledAt,source:"tab"});let w={name:a.name,path:a.path,prs:p,readAt:d},m=Vf(w,{fromCache:!1,slug:c,expectsChecks:l}),f=m.prs.some(g=>g.mergeabilityPending||g.checks.pending>0||g.autoMergeArmed||g.checks.verdict==="awaiting");return aa.set(a.path,{at:Date.now(),entry:w,pending:f}),m}catch(d){return i?Vf(i.entry,{fromCache:!0,slug:c,expectsChecks:l,now:n}):Vf({name:a.name,path:a.path,prs:[],error:dr(d),readAt:null},{fromCache:!1,slug:c})}})),s=new Set(t.map(a=>a.path));for(let a of aa.keys())s.has(a)||aa.delete(a);return{auth:e,repos:o}}async function Wr(e){let t=(await Ir()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function ia(e){return Ts(e)}async function Ci(e,t,{method:n="squash"}={}){let r=await Wr(e);if(!Zl.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 tr({cwd:r.path})).GH_TOKEN){let a=await bw().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await bn(r.path,s)}catch(a){throw new Error(dr(a))}finally{xn()}return{ok:!0,number:o}}async function Ql(e,t){let n=await Wr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await bn(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(dr(s))}finally{xn()}let o=await Re(n.path).catch(()=>null);return o&&await x$(o,r).catch(()=>{}),{ok:!0,number:r}}async function sb(e,t){let n=await Wr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await bn(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(dr(o))}finally{xn()}return{ok:!0,number:r}}function ab(e){return e.green&&!e.isDraft}function u6(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 iR(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:ab(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function cR(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function eu(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 uR(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(eu)){let r=lR(n.trackId,n.repo);t.has(r)||t.set(r,`${n.repo}#${n.number}`)}return t}function dR(e,t){return t?.trackId?e.get(lR(t.trackId,t.repo))===`${t.repo}#${t.number}`:!0}function pR(){let e={};for(let[t,n]of tb)e[t]={...n};return e}async function fR(e,{method:t="merge",onMerged:n=null}={}){let r=await Wr(e);if(!Zl.has(t))throw new Error(`invalid merge method: ${t}`);if(tb.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await kn(r.path)).filter(ab).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 tb.set(r.path,s),p6(s,o,{listPrs:()=>kn(r.path),merge:a=>Ci(r.path,a,{method:t}),sleep:l6,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function d6(e,t){let n=Date.now()+(t.settleMaxMs??c6),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(i6)}}async function p6(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 d6(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: ${dr(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(!ab(a)){e.skipped.push({number:a.number,title:a.title,reason:u6(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:dr(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),xn()}}async function ib(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await Oi("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${dr(l)}`)}await W5(e);let o=n||"";if((await tr({cwd:e})).GH_TOKEN){let l=await bw().catch(()=>null);l&&(o=`${o?`${o}
|
|
281
|
+
`).filter(n=>t.test(n)).length}function x5(e,t={set:0,ask:0}){return Eg(e)&&_i(e,o$)>(t.ask||0)?"confirm":_i(e,r$)>(t.set||0)?"set":null}async function v5(e,t){let n=await Fe(e,{lines:80}).catch(()=>""),r={set:_i(n,r$),ask:_i(n,o$)};await ot(e,`/model ${t.model}`,ar("claude"));let o=await Ei(e,s=>x5(s,r),{timeoutMs:S5});return o==="confirm"?{verified:!1,awaitingConfirm:!0,note:"claude asked to confirm the switch"}:o==="set"?{verified:!0}:{verified:!1,note:"confirmed when the next turn's transcript model flips"}}async function A5(e,t){await mp(e),await ot(e,"/model",{enter:!1}),await Of(250),await tt(e,["Enter"],{kind:"model-switch"});let n=await Ei(e,YI);if(!n)throw new Error("codex model picker didn't open");let r=n.find(i=>i.id===t.model);if(!r)throw await tt(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=k5(i);return!c||c.model!==t.model||t.effort&&c.effort&&c.effort.toLowerCase()!==t.effort.toLowerCase()?null:c};await ot(e,String(r.n),{enter:!1,kind:"model-switch"});let s=await Ei(e,i=>XI(i)||!YI(i)&&o(i)&&{done:o(i)});if(!s)throw await tt(e,["Escape"],{kind:"model-switch"}).catch(()=>{}),new Error("codex reasoning-level picker didn't open");if(!s.done){let i=t.effort?e$.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 tt(e,["Escape","Escape"],{kind:"model-switch"}).catch(()=>{}),new Error(`codex doesn't offer effort "${t.effort}" for ${t.model}`);await ot(e,String(c.n),{enter:!1,kind:"model-switch"})}let a=s.done||await Ei(e,i=>!XI(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 T5(){let e=JI.join(process.env.CURSOR_CONFIG_DIR||JI.join(m5.homedir(),".cursor"),"cli-config.json");try{return JSON.parse(await h5.readFile(e,"utf8"))?.model||null}catch{return null}}async function E5(e,t){await mp(e),await wp(e,`/model ${t.filter}`,{kind:"model-switch"});let n=await Ei(e,ZI),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 Ei(e,ZI,{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 tt(e,["Down"],{kind:"model-switch"}),await Of(250)}if(!n||!s||!o(s)){await tt(e,["Escape"],{kind:"model-switch"}).catch(()=>{});let c=Array(`/model ${t.filter}`.length).fill("BSpace");throw await tt(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 tt(e,["Enter"],{kind:"model-switch"}),await Of(800);let a=await T5();return{verified:!!a&&(a.modelId===t.model||a.displayModelId===t.model||r(a.displayName).startsWith(r(t.filter))),model:a?.modelId||null,note:"cursor applies this as the global default for new sessions too"}}async function s$(e,t,n){return e==="codex"?A5(t,n):e==="cursor"?E5(t,n):v5(t,n)}var Of,w5,g5,QI,y5,b5,e$,t$,r$,o$,S5,a$=K(()=>{kt();Al();Hp();Of=e=>new Promise(t=>setTimeout(t,e)),w5=Number(process.env.BOSTRAT_MODEL_PICKER_TIMEOUT_MS)||8e3,g5=300,QI=[{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"}],y5=new Set([...QI.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"]),b5=[{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"}],e$=new Map([["low","Low"],["medium","Medium"],["high","High"],["xhigh","Extra high"]]),t$=[{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"}];r$=/\bSet model to\b/,o$=/^\s*Switch model\?\s*$/;S5=Number(process.env.BOSTRAT_CLAUDE_MODEL_OUTCOME_MS)||3e3});function Nf(e){let t=e||{},n=_5(t);return n&&(n.payload={ts:t.at,...n.payload}),n}function _5(e){switch(e.type){case"said":return{type:"turn.user",actor:"user",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{text:e.text,boxRole:e.boxRole,...e.kind?{kind:e.kind}:{},...e.attachments?.length?{attachments:e.attachments}:{},...e.deliveryId?{deliveryId:e.deliveryId}:{},...e.producer?{producer:e.producer}:{}}};case"unsaid":return{type:"turn.retracted",actor:"user",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{saidTs:e.saidTs,text:e.text,boxRole:e.boxRole}};case"orchestration-prompt":return{type:"turn.user",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{text:e.prompt,kind:e.kind,boxRole:e.boxRole,...e.deliveryId?{deliveryId:e.deliveryId}:{},...e.detail?{detail:e.detail}:{}}};case"lead-handoff":return{type:"handoff.done",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:gt(e.toAgent),payload:{from:e.from,fromAgent:e.fromAgent,to:e.to,toAgent:e.toAgent,reason:e.reason,handoffStartedAt:e.handoffStartedAt,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,singleBox:e.singleBox,forced:e.forced,recovered:e.recovered,checkpoint:e.checkpoint,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:gt(e.toAgent),payload:{box:e.box,fromAgent:e.fromAgent,toAgent:e.toAgent,reason:e.reason,error:e.error,rolledBack:e.rolledBack,handoffStartedAt:e.handoffStartedAt}};case"subtask-delegated":return{type:"subtask.delegated",actor:"orchestrator",source:"orchestrator",boxId:e.to,provider:gt(e.toAgent),payload:{task:e.task,subtaskId:e.subtaskId,reason:e.reason}};case"subtask-merged":return{type:"subtask.merged",actor:"orchestrator",source:"orchestrator",boxId:e.box||e.from,provider:gt(e.agent),payload:{...ur(e)}};case"subtask-failed":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box||e.to,provider:gt(e.agent||e.toAgent),payload:{kind:"subtask-failed",...ur(e)}};case"subtask-resumed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{change:"subtask-resumed",...ur(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",...ur(e)}};case"opened":return{type:"box.state.changed",actor:"user",source:"orchestrator",boxId:e.box,payload:{change:"opened",...ur(e)}};case"archived":case"unarchived":case"track-deleted":case"renamed":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:e.type,...ur(e)}};case"rehydrated":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{change:"rehydrated",...e.fresh?{fresh:!0}:{}}};case"lead-refreshed":return{type:"box.state.changed",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{change:"lead-refreshed",box:e.box,agent:e.agent,fromSessionId:e.fromSessionId,toSessionId:e.toSessionId,epoch:e.epoch,reason:e.reason,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:gt(e.agent),payload:{...ur(e)}};case"transferred-out":return null;case"retagged":return{type:"box.state.changed",actor:"user",source:"orchestrator",payload:{change:"retagged",...ur(e)}};case"retag-failed":return{type:"error",actor:"orchestrator",source:"orchestrator",boxId:e.box,provider:gt(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:gt(e.agent),payload:{kind:"rehydrate-failed",reason:e.reason}};case"delivery-held":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{kind:"delivery-held",...ur(e)}};case"startup-gate":return{type:"error",actor:"system",source:"orchestrator",boxId:e.box,provider:gt(e.agent),payload:{kind:"startup-gate",...ur(e)}};default:return null}}function l$(e,t){let n=Nf(t);if(!n)return;let r=t?.type==="track-deleted"?{id:e.id}:e;Pf(()=>D(r,n))}async function u$(e){if(!(!e?.id||i$.has(e.id))){i$.add(e.id);try{let t=await V(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=Nf(r);!o||n.has(`${o.type}|${o.payload?.ts??"?"}`)||await D(e,o)}}catch{}}}function ur(e){let{type:t,at:n,...r}=e;return r}function d$(e,t,n){!n?.promptId||Cf.get(e.id)===n.promptId||(Cf.set(e.id,n.promptId),Pf(()=>D(e,{type:"prompt.raised",actor:"agent",source:"pane",boxId:t?.name,provider:gt(n.provider||t?.agent),payload:{promptId:n.promptId,question:n.question||n.title||null,options:(n.options||[]).map(r=>r?.label??r).slice(0,12)}})))}function p$(e,t,n,r={}){Cf.delete(e.id),Pf(()=>D(e,{type:"prompt.dismissed",actor:"user",source:"orchestrator",boxId:t?.name,provider:gt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}function Gy(e,t,n,r={}){Cf.delete(e.id),Pf(()=>D(e,{type:"prompt.answered",actor:"user",source:"orchestrator",boxId:t?.name,provider:gt(n?.provider||t?.agent),payload:{promptId:n?.promptId,...r}}))}var gt,Mf,Pf,c$,i$,Cf,Ky=K(()=>{be();gt=e=>e||null;Mf=Promise.resolve(),Pf=e=>(Mf=Mf.then(e).catch(()=>{}),Mf),c$=()=>Mf;i$=new Set;Cf=new Map});import I5 from"node:crypto";import Df from"node:fs/promises";import f$ from"node:path";import $5 from"node:os";function g$(e){w$=typeof e=="function"?e:async()=>new Set}function R5(e,t,n){if(e.originNode&&e.originNode===t)return!0;let r=e.data?.trackId;return!!r&&n.has(r)}async function Ye(){return Br||(Vy??=Df.readFile(Jy,"utf8").then(e=>({links:JSON.parse(e)?.links??{},existed:!0})).catch(()=>({links:{},existed:!1})).then(async({links:e,existed:t})=>{if(Br=e,!t&&et()){let{records:n,source:r}=await xt("prlinks").catch(()=>({records:[],source:"error"}));if(r==="plane"){let o=pA(),s=await w$().catch(()=>new Set),a=0;for(let i of n){if(i.deletedAt||!i.data?.repo||i.data?.number==null)continue;if(!R5(i,o,s)){a++;continue}let{id:c,updatedAt:l,...u}=i.data;Br[me(u.repo,u.number)]=u}a&&console.log(`[pr-links] restore: ${Object.keys(Br).length} link(s) re-seeded, ${a} other-node record(s) left on the plane`),Object.keys(Br).length&&await Yy().catch(()=>{})}}return Br}).finally(()=>Vy=null),Vy)}async function Yy(){let e=JSON.stringify({links:Br},null,2),t=`${Jy}.${process.pid}.tmp`;await Df.mkdir(h$,{recursive:!0}),await Df.writeFile(t,e),await Df.rename(t,Jy)}async function it(e){zy=zy.then(Yy,Yy),await zy.catch(()=>{});let t=Br?.[e];t&&Pt("prlinks",{id:m$(e),updatedAt:Date.now(),...t},{trackId:t.trackId??null}).catch(()=>{})}async function ln({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 Ye(),c=me(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:O5.has(a),firstSeen:Date.now()},await it(me(e,t)),{link:i[c],created:!0})}async function Lr(e,t){if(!e||t==null)return null;let n=(await Ye())[me(e,t)];return!n||n.announced?null:(n.announced=!0,await it(me(e,t)),n)}async function y$(e,t){if(!e||t==null)return!1;let n=(await Ye())[me(e,t)];return n?.notifyOnMerge?(delete n.notifyOnMerge,await it(me(e,t)),!0):!1}async function pt(e,t){return!e||t==null?null:(await Ye())[me(e,t)]??null}async function Ho(e,t,n){if(!e||t==null)return null;let r=(await Ye())[me(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 it(me(e,t)),r):null}async function b$(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ye())[me(e,t)];return o?(o.ciFix={delegatedAt:Date.now(),headSha:n,trackId:r},await it(me(e,t)),o):null}async function k$(e,t,{headSha:n=null,trackId:r=null}={}){if(!e||t==null)return null;let o=(await Ye())[me(e,t)];return o?(o.reconcile={delegatedAt:Date.now(),headSha:n,trackId:r},await it(me(e,t)),o):null}async function Bf(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ye())[me(e,t)];return!r||!r.ciFix?null:(r.ciFixAwait={since:Date.now(),trackId:r.ciFix.trackId??null,headSha:n},delete r.ciFix,await it(me(e,t)),r)}async function Lf(e,t){if(!e||t==null)return null;let n=(await Ye())[me(e,t)];return!n||!n.ciFixAwait?null:(delete n.ciFixAwait,await it(me(e,t)),n)}async function jf(e,t,{headSha:n=null}={}){if(!e||t==null)return null;let r=(await Ye())[me(e,t)];return!r||!r.reconcile?null:(r.reconcileAwait={since:Date.now(),trackId:r.reconcile.trackId??null,headSha:n},delete r.reconcile,await it(me(e,t)),r)}async function Ff(e,t){if(!e||t==null)return null;let n=(await Ye())[me(e,t)];return!n||!n.reconcileAwait?null:(delete n.reconcileAwait,await it(me(e,t)),n)}async function x$(e,t,{at:n=Date.now()}={}){if(!e||t==null)return null;let r=(await Ye())[me(e,t)];return r?(r.baseFoldAt=n,await it(me(e,t)),r):null}async function S$(e,t,{misses:n,until:r}){if(!e||t==null)return null;let o=(await Ye())[me(e,t)];return o?(o.brokerRefused={misses:Number(n)||0,until:Number(r)||0},await it(me(e,t)),o):null}async function v$(e,t){if(!e||t==null)return null;let n=(await Ye())[me(e,t)];return n?.brokerRefused?(delete n.brokerRefused,await it(me(e,t)),n):null}async function A$(e,t){if(!e||t==null)return null;let n=(await Ye())[me(e,t)];return!n||!n.baseFoldAt?null:(delete n.baseFoldAt,await it(me(e,t)),n)}async function Xy(e,t,n){if(!e||t==null||!n)return null;let r=(await Ye())[me(e,t)];return r?(r.lastHeadSha=n,await it(me(e,t)),r):null}async function T$(e,t,n){if(!e||t==null||!n)return{prev:null,link:null};let r=(await Ye())[me(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 it(me(e,t))),{prev:o,link:r}}async function Vl(e,t,{merge:n=null}={}){if(!e||t==null)return null;let r=(await Ye())[me(e,t)];return r?(r.armedAt=Date.now(),n&&(r.autoMerge={method:n.method||"merge",armedAt:r.armedAt}),await it(me(e,t)),r):null}async function na(e,t,n=!0){if(!e||t==null)return null;let r=(await Ye())[me(e,t)];return r?(n?r.archiveOnMerge=!0:delete r.archiveOnMerge,await it(me(e,t)),r):null}async function ra(e,t,n=!0){if(!e||t==null)return null;let r=(await Ye())[me(e,t)];return r?(n?r.notifyOnMerge=!0:delete r.notifyOnMerge,await it(me(e,t)),r):null}async function E$(e,t,n){if(!e||t==null)return null;let r=(await Ye())[me(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 it(me(e,t)),r}async function _$(e,t,n){if(!e||t==null)return null;let r=(await Ye())[me(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 it(me(e,t)),r}async function zl(e,t){if(!e||t==null)return null;let n=(await Ye())[me(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 it(me(e,t)),n)}async function I$(){return Object.values(await Ye()).filter(e=>!M5.has(e.state))}async function Ln(){return Object.values(await Ye()).sort((e,t)=>t.firstSeen-e.firstSeen)}async function $$(){if(!et())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await xt("prlinks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Ye(),r=0;for(let[o,s]of Object.entries(n))await Pt("prlinks",{id:m$(o),updatedAt:Date.now(),...s},{trackId:s.trackId??null}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}var h$,Jy,me,m$,Br,Vy,zy,w$,O5,M5,jn=K(()=>{bo();h$=process.env.BOSTRAT_STATE_DIR||f$.join(process.env.HOME||$5.tmpdir(),".bostrat"),Jy=f$.join(h$,"pr-links.json"),me=(e,t)=>`${e}#${Number(t)}`,m$=e=>{let t=e.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^[^A-Za-z0-9]+/,"").slice(0,55),n=I5.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t||"pr"}-${n}`},Br=null,Vy=null,zy=Promise.resolve(),w$=async()=>new Set;O5=new Set(["api","observed","reconciled"]);M5=new Set(["merged","closed","lost"])});import C5 from"node:fs";import Zy from"node:fs/promises";import C$ from"node:path";import N5 from"node:os";function D$(e,t=!1){if(!t&&e-O$<P5)return;O$=e;let n=JSON.stringify({windowStart:Ii,byCaller:Object.fromEntries(jr),lastHour:Wo});M$=M$.then(()=>Zy.mkdir(N$,{recursive:!0})).then(()=>Zy.writeFile(`${Uf}.tmp`,n)).then(()=>Zy.rename(`${Uf}.tmp`,Uf)).catch(()=>{})}function B$(e){e-Ii<P$||(Wo={start:Ii,total:Hf(jr),byCaller:Object.fromEntries(jr)},Wo.total&&console.log(`[github] ${Wo.total} calls last hour`,Wo.byCaller),Ii=e,jr=new Map,D$(e,!0))}function Fr(e="other",t=Date.now()){B$(t),jr.set(e,(jr.get(e)||0)+1),D$(t)}function L$(e=Date.now()){return B$(e),{windowStart:Ii,total:Hf(jr),byCaller:Object.fromEntries(jr),lastHour:Wo,backoffUntil:oa>e?oa:null}}function qo(e){return D5.test(String(e?.message||e||""))}function Go(e,t=Date.now()){return oa<=t&&console.warn(`[github] rate limited \u2014 backing off ${R$/6e4} min:`,String(e?.message||e||"").slice(0,200)),oa=Math.max(oa,t+R$),oa}function Wf(e=Date.now()){return Math.max(0,oa-e)}var N$,Uf,P$,R$,P5,Ii,jr,Wo,oa,O$,Hf,M$,D5,Jl=K(()=>{N$=process.env.BOSTRAT_STATE_DIR||C$.join(process.env.HOME||N5.tmpdir(),".bostrat"),Uf=C$.join(N$,"github-metrics.json"),P$=60*6e4,R$=5*6e4,P5=6e4,Ii=Date.now(),jr=new Map,Wo=null,oa=0,O$=0,Hf=e=>[...e.values()].reduce((t,n)=>t+n,0);try{let e=JSON.parse(C5.readFileSync(Uf,"utf8"));e?.windowStart&&(Date.now()-e.windowStart<P$?(Ii=e.windowStart,jr=new Map(Object.entries(e.byCaller||{})),Wo=e.lastHour||null):Hf(new Map(Object.entries(e.byCaller||{})))&&(Wo={start:e.windowStart,total:Hf(new Map(Object.entries(e.byCaller||{}))),byCaller:e.byCaller||{}}))}catch{}M$=Promise.resolve();D5=/rate limit|too quickly|abuse detection|HTTP 429/i});import j$ from"node:fs/promises";import F$ from"node:path";import B5 from"node:os";function $i({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};qf.push(l),qf.length>j5&&qf.shift();let u=Qy.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)),Qy.set(e,u),F5(l),l}async function F5(e){try{await j$.mkdir(U$,{recursive:!0}),await j$.appendFile(L5,JSON.stringify(e)+`
|
|
282
|
+
`)}catch{}}function H$(){let e={};for(let[t,n]of Qy)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:qf.slice(-20)}}var U$,L5,j5,qf,Qy,Gf=K(()=>{U$=process.env.BOSTRAT_STATE_DIR||F$.join(process.env.HOME||B5.tmpdir(),".bostrat"),L5=F$.join(U$,"github-latency.ndjson"),j5=100,qf=[],Qy=new Map});import{execFile as U5}from"node:child_process";import{promisify as H5}from"node:util";import W$ from"node:fs/promises";import q$ from"node:path";async function W5(e){let t=/workspaces[/\\]([0-9a-f]{8})(?:[/\\]|$)/.exec(e||"")?.[1];if(t)try{let[{stdout:n},{stdout:r}]=await Promise.all([Oi("git",["-C",e,"rev-parse","HEAD"]),Oi("git",["-C",e,"rev-parse","--abbrev-ref","HEAD"])]);await D({id:t,cwd:e},{type:"code.pushed",actor:"orchestrator",payload:{ref:r.trim(),sha:n.trim(),wip:!1,ts:Date.now()}})}catch{}}async function bn(e,t,n={}){let{caller:r="prs",...o}=n,s=await tr({cwd:e});Fr(r);try{let{stdout:a}=await Oi("gh",t,{cwd:e,...q5,...o,env:{...process.env,...s,...o.env||{}}});return String(a||"")}catch(a){throw qo(a)&&Go(a),a}}async function Xl(){if(Kf&&Date.now()-Kf.at<6e4)return Kf.data;let e;try{Fr("auth");let t=await Oi("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 $s();t.configured&&(e={installed:!0,authenticated:!0,login:t.username,via:"broker"})}catch{}return Kf={at:Date.now(),data:e},e}async function G5(e){try{let{stdout:t}=await Oi("git",["-C",e,"config","--get","remote.origin.url"],{timeout:5e3});return/github\.com/.test(t)}catch{return!1}}function V$(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 eb(e){let t=(e||[]).map(V$),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 V5(e,{expectsChecks:t=!1,headAt:n=0,now:r=Date.now(),windowMs:o=K5}={}){return!e||e.total>0||e.unavailable?null:t&&n>0&&r-n<o?"awaiting":"none"}async function J5(e,t=Date.now()){let n=G$.get(e);if(n&&t-n.at<z5)return n.expects;let r=!1;try{let o=q$.join(e,".github","workflows");for(let s of await W$.readdir(o)){if(!/\.ya?ml$/.test(s))continue;let a=await W$.readFile(q$.join(o,s),"utf8").catch(()=>"");if(/\bpull_request(_target)?\b/.test(a)){r=!0;break}}}catch{}return G$.set(e,{at:t,expects:r}),r}async function J$(e,t=Date.now()){return e?z$.has(e)?!0:J5(e,t):!1}function Y$(e,t,{now:n=Date.now(),slug:r=null,reap:o=!0}={}){let s=new Set;for(let a of t){let i=`${e}#${a.number}`;s.add(i),a.checks?.total>0&&z$.add(e);let c=Yl.get(i);a.headSha&&(!c||c.sha!==a.headSha)&&Yl.set(i,{sha:a.headSha,at:c?n:null});let l=sa.get(i);if(l&&a.checks?.total>0){sa.delete(i);let u=r||e;$i({change:"checks-registered",repo:u,number:a.number,githubAt:l.headAt,observedAt:n,source:"tab"}),console.log(`[pr-checks] ${u}#${a.number} checks registered ${n-l.headAt}ms after its head moved (${String(l.sha).slice(0,8)})`)}}if(o){for(let a of Yl.keys())a.startsWith(`${e}#`)&&!s.has(a)&&Yl.delete(a);for(let a of sa.keys())a.startsWith(`${e}#`)&&!s.has(a)&&sa.delete(a)}}function Y5(e,t){let n=Yl.get(`${e}#${t.number}`),r=n&&n.sha===t.headSha&&n.at||0;return Math.max(Date.parse(t.updatedAt||"")||0,r)}function X$(e,t,{expectsChecks:n,now:r=Date.now(),slug:o=null}){return(t||[]).map(s=>{if(!s.checks)return s;let a=Y5(e,s),i=V5(s.checks,{expectsChecks:n,headAt:a,now:r}),c=`${e}#${s.number}`;return i==="none"&&sa.delete(c),i==="awaiting"&&sa.get(c)?.sha!==s.headSha&&(sa.set(c,{sha:s.headSha,headAt:a}),console.log(`[pr-checks] ${o||e}#${s.number} head ${String(s.headSha).slice(0,8)} has no checks yet \u2014 awaiting registration`)),i?{...s,checks:{...s.checks,verdict:i}}:s})}function rb(e){return/Resource not accessible by personal access token/.test(String(e?.stderr||e?.message||""))}async function Q$(e,t){if(!t)return null;let n=await Re(e);if(!n)return null;try{let r=await bn(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 eR(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 tR(e,t){let n=await Q$(e,t);return n===null?{...eb([]),unavailable:!0}:eb(eR(n))}function zf(e,t=eb(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 Z5(e,t,n){let r=new Set;for(let o of t){let s=`${e}#${o.number}`;if(o.mergeable!=="UNKNOWN"&&o.mergeStateStatus!=="UNKNOWN"){Ri.delete(s);continue}r.add(s),Ri.has(s)||Ri.set(s,n),o.mergeabilityPending=n-Ri.get(s)<X5}for(let o of Ri.keys())o.startsWith(`${e}#`)&&!r.has(o)&&Ri.delete(o);return t}async function Mi(e,t){let n=await Wr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let a=await bn(n.path,["pr","view",String(r),"--json",nb]);o=zf(JSON.parse(a))}catch(a){if(!rb(a))throw a;let i=await bn(n.path,["pr","view",String(r),"--json",Z$]),c=JSON.parse(i);o=zf(c,await tR(n.path,c.headRefOid))}let s=Date.now();return Y$(n.path,[o],{now:s,reap:!1}),X$(n.path,[o],{expectsChecks:await J$(n.path,s),now:s})[0]}async function kn(e,{caller:t="prs"}={}){try{let n=await bn(e,["pr","list","--json",nb,"--limit","50"],{caller:t});return JSON.parse(n||"[]").map(r=>zf(r)).sort(K$)}catch(n){if(!rb(n))throw n;let r=await bn(e,["pr","list","--json",Z$,"--limit","50"],{caller:t});return(await Promise.all(JSON.parse(r||"[]").map(async o=>zf(o,await tR(e,o.headRefOid))))).sort(K$)}}function xn(){aa.clear()}function ob(e=Date.now()){for(let[t,n]of Ur){let r=Math.min(n.announcedAt??1/0,n.webhookAt??1/0);(r===1/0||e-r>t6)&&Ur.delete(t)}}async function Hr({repo:e,number:t,via:n="unknown",at:r=Date.now()}={}){if(!rR(e,t))return null;ob(r);let o=nR(e,t);o.announcedAt=r,o.via=n;let s=await Ts(e).catch(()=>null);return s?aa.delete(s):aa.clear(),console.log(`[pr-open] ${e}#${t} opened card announced via ${n}`+(o.webhookAt?` (opened webhook already in, ${r-o.webhookAt}ms ago)`:"")+` \u2014 ${s?"repo":"whole"} PR cache dropped`),o}function oR({repo:e,number:t,at:n=Date.now()}={}){if(!rR(e,t))return null;ob(n);let r=nR(e,t);return r.webhookAt==null&&(r.webhookAt=n),console.log(`[pr-open] ${e}#${t} opened webhook received`+(r.announcedAt?` ${n-r.announcedAt}ms after its card`:" (card not announced yet)")),r}function sR(e=Date.now()){return ob(e),[...Ur.values()].map(t=>({...t}))}function r6(e){if(!e)return;let t=`${String(e).toLowerCase()}#`,n;for(let[r,o]of Ur)!r.startsWith(t)||o.webhookAt==null||((n??={})[String(o.number)]=o.webhookAt);return n}function Vf(e,{fromCache:t,slug:n,expectsChecks:r=!1,now:o=Date.now()}){let s=r6(n),a=X$(e.path,e.prs,{expectsChecks:r,now:o,slug:n});return{...e,prs:a,readAt:e.readAt??null,fromCache:t,...s?{openedWebhooks:s}:{}}}function o6(e,t,n,r){if(!e)return;let o=`${String(e).toLowerCase()}#`;for(let[s,a]of Ur)!s.startsWith(o)||a.announcedAt==null||(t.prs||[]).some(i=>i.number===a.number)||(a.staleServes+=1,a.staleServes===1&&console.log(`[pr-open] ${e}#${a.number} poll served from cache (read ${r-n}ms old) without it, ${r-a.announcedAt}ms after its opened card`))}function s6(e,t,n){if(!e)return;let r=`${String(e).toLowerCase()}#`;for(let[o,s]of Ur){if(!o.startsWith(r))continue;if(!(t||[]).some(i=>i.number===s.number)){s.announcedAt!=null&&(s.freshMisses+=1,console.log(`[pr-open] ${e}#${s.number} fresh poll read still lacks it ${n-s.announcedAt}ms after its opened card`+(s.webhookAt?` (opened webhook seen ${n-s.webhookAt}ms ago)`:" (no opened webhook yet)")));continue}s.announcedAt!=null&&($i({change:"opened-listed",repo:e,number:s.number,githubAt:s.announcedAt,observedAt:n,lane:s.webhookAt!=null?"event":null,source:"tab"}),console.log(`[pr-open] ${e}#${s.number} listed ${n-s.announcedAt}ms after its opened card (${s.staleServes} cache read(s) and ${s.freshMisses} fresh read(s) served without it`+(s.webhookAt?`, opened webhook ${s.webhookAt-s.announcedAt}ms after the card)`:", no opened webhook seen)"))),Ur.delete(o)}}async function a6(e,t){if(!e)return t;for(let n of t){let r=await pt(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 Bf(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.ciFix={delegatedAt:r.ciFix.delegatedAt,trackId:r.ciFix.trackId??null}),r.reconcile&&(o(r.reconcile)?await jf(e,n.number,{headSha:n.headSha}).catch(()=>{}):n.reconcile={delegatedAt:r.reconcile.delegatedAt,trackId:r.reconcile.trackId??null})}return t}async function aR(){let e=await Xl();if(!e.authenticated)return{auth:e,repos:[]};let t=[];for(let a of await Ir())await G5(a.path)&&t.push(a);let n=Date.now(),r=Wf(n)>0,o=await Promise.all(t.map(async a=>{let i=aa.get(a.path),c=await Re(a.path).catch(()=>null),l=await J$(a.path,n),u=i?.pending?e6:Q5;if(i&&(r||n-i.at<u))return o6(c,i.entry,i.at,n),Vf(i.entry,{fromCache:!0,slug:c,expectsChecks:l,now:n});try{let d=Date.now(),p=Z5(a.path,await kn(a.path,{caller:"tab"}),n);if(Y$(a.path,p,{now:Date.now(),slug:c}),await a6(c,p),s6(c,p,Date.now()),i?.entry?.prs)for(let g of p)i.entry.prs.find(b=>b.number===g.number)?.checks?.pending>0&&g.checks.total>0&&g.checks.pending===0&&$i({change:g.checks.failed>0?"checks-failed":"checks-green",repo:c||a.name,number:g.number,githubAt:g.checks.settledAt,source:"tab"});let w={name:a.name,path:a.path,prs:p,readAt:d},m=Vf(w,{fromCache:!1,slug:c,expectsChecks:l}),h=m.prs.some(g=>g.mergeabilityPending||g.checks.pending>0||g.autoMergeArmed||g.checks.verdict==="awaiting");return aa.set(a.path,{at:Date.now(),entry:w,pending:h}),m}catch(d){return i?Vf(i.entry,{fromCache:!0,slug:c,expectsChecks:l,now:n}):Vf({name:a.name,path:a.path,prs:[],error:dr(d),readAt:null},{fromCache:!1,slug:c})}})),s=new Set(t.map(a=>a.path));for(let a of aa.keys())s.has(a)||aa.delete(a);return{auth:e,repos:o}}async function Wr(e){let t=(await Ir()).find(n=>n.path===e);if(!t)throw new Error(`unknown repo: ${e}`);return t}async function ia(e){return Ts(e)}async function Ci(e,t,{method:n="squash"}={}){let r=await Wr(e);if(!Zl.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 tr({cwd:r.path})).GH_TOKEN){let a=await bw().catch(()=>null);a&&s.push("--body",`Merged by bostrat on behalf of @${a}`)}try{await bn(r.path,s)}catch(a){throw new Error(dr(a))}finally{xn()}return{ok:!0,number:o}}async function Ql(e,t){let n=await Wr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await bn(n.path,["api","-X","PUT",`repos/{owner}/{repo}/pulls/${r}/update-branch`])}catch(s){throw new Error(dr(s))}finally{xn()}let o=await Re(n.path).catch(()=>null);return o&&await x$(o,r).catch(()=>{}),{ok:!0,number:r}}async function sb(e,t){let n=await Wr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");try{await bn(n.path,["pr","merge",String(r),"--disable-auto"])}catch(o){throw new Error(dr(o))}finally{xn()}return{ok:!0,number:r}}function ab(e){return e.green&&!e.isDraft}function u6(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 iR(e,{update:t=!0}={}){return e.isDraft?{action:"skip",reason:"draft"}:ab(e)?{action:"merge"}:t&&e.mergeStateStatus==="BEHIND"&&e.mergeable!=="CONFLICTING"&&e.checks.failed===0?{action:"update-arm"}:{action:"arm"}}function cR(e){return[...e.filter(t=>t.plan.action!=="merge"),...e.filter(t=>t.plan.action==="merge")]}function eu(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 uR(e){let t=new Map;for(let n of[...e].filter(r=>r?.autoMerge&&r?.trackId).sort(eu)){let r=lR(n.trackId,n.repo);t.has(r)||t.set(r,`${n.repo}#${n.number}`)}return t}function dR(e,t){return t?.trackId?e.get(lR(t.trackId,t.repo))===`${t.repo}#${t.number}`:!0}function pR(){let e={};for(let[t,n]of tb)e[t]={...n};return e}async function fR(e,{method:t="merge",onMerged:n=null}={}){let r=await Wr(e);if(!Zl.has(t))throw new Error(`invalid merge method: ${t}`);if(tb.get(r.path)?.running)throw new Error("a merge-all is already running for this repo");let o=(await kn(r.path)).filter(ab).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 tb.set(r.path,s),p6(s,o,{listPrs:()=>kn(r.path),merge:a=>Ci(r.path,a,{method:t}),sleep:l6,onMerged:n}).catch(()=>{}),{ok:!0,repo:r.path,total:s.total,queue:o.map(a=>a.number)}}async function d6(e,t){let n=Date.now()+(t.settleMaxMs??c6),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(i6)}}async function p6(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 d6(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: ${dr(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(!ab(a)){e.skipped.push({number:a.number,title:a.title,reason:u6(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:dr(i)})}}}finally{e.current=null,e.running=!1,e.finishedAt=Date.now(),xn()}}async function ib(e,{title:t,body:n="",base:r=null}={}){if(typeof t!="string"||!t.trim())throw new Error("title required");try{await Oi("git",["-C",e,"push","-u","origin","HEAD"],{timeout:12e4,maxBuffer:4*1024*1024})}catch(l){throw new Error(`push failed: ${dr(l)}`)}await W5(e);let o=n||"";if((await tr({cwd:e})).GH_TOKEN){let l=await bw().catch(()=>null);l&&(o=`${o?`${o}
|
|
283
283
|
|
|
284
284
|
`:""}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 bn(e,s)}catch(l){throw new Error(dr(l))}finally{xn()}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 hR(e,t){let n=await Wr(e),r=Number(t);if(!Number.isInteger(r)||r<=0)throw new Error("invalid PR number");let o;try{let i;try{i=await bn(n.path,["pr","checks",String(r),"--json","name,state,link,bucket"])}catch(c){if(i=String(c?.stdout||""),!i.trim())throw new Error(dr(c))}o=JSON.parse(i||"[]").filter(c=>c.bucket==="fail")}catch(i){if(!rb(i))throw i;let c=await bn(n.path,["pr","view",String(r),"--json","headRefOid"]),l=await Q$(n.path,JSON.parse(c).headRefOid);if(l===null)throw new Error(dr(i));o=eR(l).map(V$).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=f6(i.link),l=null;c&&!s.has(c)&&(s.add(c),l=await bn(n.path,["run","view",c,"--log-failed"]).then(u=>h6(u)).catch(()=>null)),a.push({name:i.name,link:i.link||null,log:l})}return a}function f6(e){return String(e||"").match(/\/actions\/runs\/(\d+)/)?.[1]??null}function h6(e,{maxLines:t=400,maxBytes:n=64*1024}={}){let r=String(e||""),o=r.split(`
|
|
285
285
|
`);return o.length>t&&(r=`\u2026 (${o.length-t} earlier lines truncated)
|
|
286
286
|
`+o.slice(-t).join(`
|
|
287
287
|
`)),Buffer.byteLength(r)>n&&(r=`\u2026 (truncated)
|
|
288
288
|
`+r.slice(-n)),r}function dr(e){return String(e?.stderr||e?.message||e||"").trim().split(`
|
|
289
|
-
`).find(n=>n.trim())||"gh failed"}var Oi,q5,Kf,K5,Yl,z$,z5,G$,sa,nb,Z$,X5,Ri,K$,Q5,e6,aa,t6,Ur,n6,nR,rR,Zl,i6,c6,l6,lR,tb,pr=K(()=>{er();_t();jn();Jl();Gf();be();Oi=H5(U5),q5={timeout:3e4,maxBuffer:8*1024*1024};Kf=null;K5=3*6e4;Yl=new Map,z$=new Set,z5=5*6e4,G$=new Map,sa=new Map;nb="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt,state,mergedAt,closedAt",Z$=nb.replace("statusCheckRollup,","");X5=9e4,Ri=new Map;K$=(e,t)=>e.number-t.number;Q5=3e4,e6=1500,aa=new Map;t6=10*6e4,Ur=new Map,n6=(e,t)=>`${String(e).toLowerCase()}#${Number(t)}`,nR=(e,t)=>{let n=n6(e,t),r=Ur.get(n);return r||(r={repo:e,number:Number(t),announcedAt:null,via:null,webhookAt:null,staleServes:0,freshMisses:0},Ur.set(n,r)),r};rR=(e,t)=>!!e&&Number.isInteger(Number(t))&&Number(t)>0;Zl=new Set(["squash","merge","rebase"]);i6=2500,c6=9e4,l6=e=>new Promise(t=>setTimeout(t,e));lR=(e,t)=>`${e}\0${String(t||"").toLowerCase()}`;tb=new Map});function k6(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function kR(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-m6);for(let r of k6(n).reverse()){if(!w6.test(r))continue;let o=r.endsWith("?")&&r.length<=b6&&y6.test(r);if(g6.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function SR(e){let t=String(e||""),n=[];x6.test(t)&&n.push("commit"),xR.test(t)&&n.push("rebase"),S6.test(t)&&n.push("push");let r=A6.test(t);!r&&v6.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 vR(e){return xR.test(String(e||""))}function Ni(e,{branch:t=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1,forge:a=null}={}){Array.isArray(e)||(e=e==="push"?["commit","push"]:["commit","push","pr"]);let i=new Set(e),c=Array.isArray(o)&&o.length>0,l=c?o.map(m=>`${m.name}/`).join(", "):null,u=t?` on this branch (${t})`:"",d=[];if(i.has("commit")&&d.push(c?`commit the work in each changed checkout (${l})${u} with a clear commit message per repo`:`commit the work${u} with a clear commit message`),i.has("rebase")){let m=i.has("commit")?"the branch":`this branch${t?` (${t})`:""}`;d.push(c?`rebase ${m} in each changed checkout (${l}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${m} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`)}if(i.has("push")||i.has("pr")){let m=r&&!i.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",f=i.has("rebase")?" with `--force-with-lease` (the rebase rewrote history)":"";c?d.push(i.has("commit")||i.has("rebase")?`push each one to its remote${f}${m}`:`push this branch${t?` (${t})`:""} from each changed checkout (${l}) to its remote${m}`):d.push(i.has("commit")||i.has("rebase")?`push it to the remote${f}${m}`:`push this branch${u} to the remote${m}`)}i.has("pr")&&d.push(c?"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 p=[];i.has("commit")||p.push("don't create any new commits \u2014 ship what's already committed"),s&&!i.has("rebase")&&p.push("don't rebase \u2014 leave the branch's history as it is"),!i.has("push")&&!i.has("pr")&&p.push("don't push"),i.has("pr")||p.push("don't open a pull request");let w=`Yes \u2014 go ahead: ${d.join(", then ")}.`;return p.length&&(w+=` ${p.join(", and ").replace(/^./,m=>m.toUpperCase())}.`),i.has("pr")&&(w+=c?" 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."),(i.has("push")||i.has("pr"))&&(w+=AR(a)),w}function AR(e){if(!e||typeof e!="object")return"";let t=Array.isArray(e.unreadable)?e.unreadable.filter(Boolean):[];if(e.watched===!0&&!t.length)return" Then stop: Bostrat watches the checks and the merge from here, so don't wait on them or report on them.";if(e.watched===!1||t.length){let n=t.length?t.join(", "):"this repo",r=t.length>1,o=` Bostrat cannot read ${n} on the forge, so it is not watching ${r?"those PRs":"this PR"}.`;return e.watched===!0&&(o+=" The other repos' PRs it does watch \u2014 don't wait on those or report on them."),o}return""}async function tu(e,{auth:t=Xl,tokenFor:n=wo,notGranted:r=Kd}={}){try{let o=(Array.isArray(e)?e:[]).map(i=>({name:i?.name||i?.slug||"this repo",slug:i?.slug||null}));if(!o.length)return null;if(!(await t())?.authenticated)return{watched:!1,unreadable:o.map(i=>i.name)};let a=[];for(let i of o){if(!i.slug){a.push(i.name);continue}try{await n(i.slug)}catch(c){r(c)&&a.push(i.name)}}return{watched:a.length<o.length,unreadable:a}}catch{return null}}function TR(e,{branch:t=null,base:n=null,prNumber:r=null,offeredRebase:o=!1,forge:s=null}={}){let a=new Set(Array.isArray(e)?e:["commit","push","pr"]),i=t?` on this branch (${t})`:"",c=[];a.has("commit")&&c.push(`commit the work${i} with a clear commit message`),a.has("rebase")&&c.push(`rebase ${a.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`),c.push("move the work to a fresh branch (branch off the current HEAD with a clear new name)"),c.push("push the new branch to the remote"),c.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 l=[];a.has("commit")||l.push("don't create any new commits \u2014 ship what's already committed"),o&&!a.has("rebase")&&l.push("don't rebase \u2014 leave the branch's history as it is");let u=`Yes \u2014 go ahead, as a NEW pull request: ${c.join(", then ")}.`;return l.length&&(u+=` ${l.join(", and ").replace(/^./,d=>d.toUpperCase())}.`),u+=` 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.`,u+=AR(s),u}function ER(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<=T6&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function _R(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+E6||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function IR(e){let t=(Array.isArray(e)?e:[]).filter(r=>mR[r]).map(r=>mR[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. Don't wait on the PR's checks \u2014 Bostrat watches them.`}var m6,wR,gR,yR,bR,w6,g6,y6,b6,Ko,x6,xR,S6,v6,A6,T6,E6,mR,ca=K(()=>{pr();_t();m6=600,wR=/(?<!\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,gR=/(?<!\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,yR=/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,bR=/(?<!\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,w6=new RegExp(`\\b(?:${wR}|${gR}|${yR}|${bR})\\b`,"i"),g6=/\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,y6=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,b6=90;Ko=["commit","rebase","push","pr"],x6=new RegExp(`\\b(?:${wR})\\b`,"i"),xR=new RegExp(`\\b(?:${bR})\\b`,"i"),S6=new RegExp(`\\b(?:${gR})\\b`,"i"),v6=new RegExp(`\\b(?:${yR})\\b`,"i"),A6=/\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;T6=3e4;E6=2500;mR={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import{execFile as _6}from"node:child_process";import{promisify as I6}from"node:util";async function R6(e,t){try{let{stdout:n}=await $6("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function O6(e,t,n,{rebase:r=!1,listPrs:o=kn}={}){let s=await Xs(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await Zs(e.dir,n).catch(()=>0),i=t?await R6(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(f=>f.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 w=p.filter(m=>!(m==="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:Jf.filter(m=>p.includes(m)),defaults:Jf.filter(m=>w.includes(m))}}async function Yf(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 xi(s[0].dir).catch(()=>!1))return null;let a=[];for(let p of s)a.push(await O6(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=Jf.filter(p=>c.some(w=>w.available.includes(p))),u=Jf.filter(p=>c.some(w=>w.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 $6,Jf,cb=K(()=>{Fl();pr();$6=I6(_6),Jf=["commit","rebase","push","pr"]});import{execFile as M6}from"node:child_process";import{promisify as C6}from"node:util";async function fr(e){if(!e)return null;let t=$R.get(e);if(t&&Date.now()-t.at<P6)return t.branch;let n=null;try{let{stdout:r}=await N6("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return $R.set(e,{at:Date.now(),branch:n}),n}function RR(e){return String(e||"").match(D6)?.[1]??null}function OR(e,t){let n=RR(e);return!!n&&!!t&&n===t}function MR(e,t){let n=RR(e);return!!n&&n!==t}function B6(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 Pi(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of B6(e))n(await fr(r));return t}async function Xf(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=>OR(t,a.id));if(s)return s;for(let a of r)if(!He(a)&&(await Pi(a)).includes(t))return a;return null}function L6(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 Zf(e,{branch:t=null,repo:n=null,slug:r=null}={}){return OR(t,e?.id)?!0:L6(e,n,r)}var N6,P6,$R,D6,Vo=K(()=>{yn();N6=C6(M6),P6=5e3,$R=new Map;D6=/^track\/.+-([0-9a-f]{8})$/});import{execFile as j6}from"node:child_process";import{promisify as F6}from"node:util";function Di({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function eh(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function nh({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?K6[r]:null;return a&&s.push(a),s.push(`${BR}: ${Di({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${LR}: ${String(o).trim()}`),s}function CR(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
|
|
289
|
+
`).find(n=>n.trim())||"gh failed"}var Oi,q5,Kf,K5,Yl,z$,z5,G$,sa,nb,Z$,X5,Ri,K$,Q5,e6,aa,t6,Ur,n6,nR,rR,Zl,i6,c6,l6,lR,tb,pr=K(()=>{er();_t();jn();Jl();Gf();be();Oi=H5(U5),q5={timeout:3e4,maxBuffer:8*1024*1024};Kf=null;K5=3*6e4;Yl=new Map,z$=new Set,z5=5*6e4,G$=new Map,sa=new Map;nb="number,title,url,headRefName,headRefOid,baseRefName,isDraft,author,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup,autoMergeRequest,additions,deletions,createdAt,updatedAt,state,mergedAt,closedAt",Z$=nb.replace("statusCheckRollup,","");X5=9e4,Ri=new Map;K$=(e,t)=>e.number-t.number;Q5=3e4,e6=1500,aa=new Map;t6=10*6e4,Ur=new Map,n6=(e,t)=>`${String(e).toLowerCase()}#${Number(t)}`,nR=(e,t)=>{let n=n6(e,t),r=Ur.get(n);return r||(r={repo:e,number:Number(t),announcedAt:null,via:null,webhookAt:null,staleServes:0,freshMisses:0},Ur.set(n,r)),r};rR=(e,t)=>!!e&&Number.isInteger(Number(t))&&Number(t)>0;Zl=new Set(["squash","merge","rebase"]);i6=2500,c6=9e4,l6=e=>new Promise(t=>setTimeout(t,e));lR=(e,t)=>`${e}\0${String(t||"").toLowerCase()}`;tb=new Map});function k6(e){return String(e).split(/(?<=[.?!])\s+|\n+/).map(t=>t.trim()).filter(Boolean)}function kR(e){let t=String(e||"").trim();if(!t)return null;let n=t.slice(-m6);for(let r of k6(n).reverse()){if(!w6.test(r))continue;let o=r.endsWith("?")&&r.length<=b6&&y6.test(r);if(g6.test(r)||o)return r.length>200?r.slice(0,197)+"\u2026":r}return null}function SR(e){let t=String(e||""),n=[];x6.test(t)&&n.push("commit"),xR.test(t)&&n.push("rebase"),S6.test(t)&&n.push("push");let r=A6.test(t);!r&&v6.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 vR(e){return xR.test(String(e||""))}function Ni(e,{branch:t=null,base:n=null,toPr:r=null,repos:o=null,offeredRebase:s=!1,forge:a=null}={}){Array.isArray(e)||(e=e==="push"?["commit","push"]:["commit","push","pr"]);let i=new Set(e),c=Array.isArray(o)&&o.length>0,l=c?o.map(m=>`${m.name}/`).join(", "):null,u=t?` on this branch (${t})`:"",d=[];if(i.has("commit")&&d.push(c?`commit the work in each changed checkout (${l})${u} with a clear commit message per repo`:`commit the work${u} with a clear commit message`),i.has("rebase")){let m=i.has("commit")?"the branch":`this branch${t?` (${t})`:""}`;d.push(c?`rebase ${m} in each changed checkout (${l}) onto its own base branch (fetch origin first), resolving any conflicts so both sides' intent is preserved`:`rebase ${m} onto ${n?`the latest ${n}`:"its base branch"} (fetch origin first), resolving any conflicts so both sides' intent is preserved`)}if(i.has("push")||i.has("pr")){let m=r&&!i.has("pr")?` (the open PR${r.number?` #${r.number}`:""} picks it up)`:"",h=i.has("rebase")?" with `--force-with-lease` (the rebase rewrote history)":"";c?d.push(i.has("commit")||i.has("rebase")?`push each one to its remote${h}${m}`:`push this branch${t?` (${t})`:""} from each changed checkout (${l}) to its remote${m}`):d.push(i.has("commit")||i.has("rebase")?`push it to the remote${h}${m}`:`push this branch${u} to the remote${m}`)}i.has("pr")&&d.push(c?"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 p=[];i.has("commit")||p.push("don't create any new commits \u2014 ship what's already committed"),s&&!i.has("rebase")&&p.push("don't rebase \u2014 leave the branch's history as it is"),!i.has("push")&&!i.has("pr")&&p.push("don't push"),i.has("pr")||p.push("don't open a pull request");let w=`Yes \u2014 go ahead: ${d.join(", then ")}.`;return p.length&&(w+=` ${p.join(", and ").replace(/^./,m=>m.toUpperCase())}.`),i.has("pr")&&(w+=c?" 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."),(i.has("push")||i.has("pr"))&&(w+=AR(a)),w}function AR(e){if(!e||typeof e!="object")return"";let t=Array.isArray(e.unreadable)?e.unreadable.filter(Boolean):[];if(e.watched===!0&&!t.length)return" Then stop: Bostrat watches the checks and the merge from here, so don't wait on them or report on them.";if(e.watched===!1||t.length){let n=t.length?t.join(", "):"this repo",r=t.length>1,o=` Bostrat cannot read ${n} on the forge, so it is not watching ${r?"those PRs":"this PR"}.`;return e.watched===!0&&(o+=" The other repos' PRs it does watch \u2014 don't wait on those or report on them."),o}return""}async function tu(e,{auth:t=Xl,tokenFor:n=wo,notGranted:r=Kd}={}){try{let o=(Array.isArray(e)?e:[]).map(i=>({name:i?.name||i?.slug||"this repo",slug:i?.slug||null}));if(!o.length)return null;if(!(await t())?.authenticated)return{watched:!1,unreadable:o.map(i=>i.name)};let a=[];for(let i of o){if(!i.slug){a.push(i.name);continue}try{await n(i.slug)}catch(c){r(c)&&a.push(i.name)}}return{watched:a.length<o.length,unreadable:a}}catch{return null}}function TR(e,{branch:t=null,base:n=null,prNumber:r=null,offeredRebase:o=!1,forge:s=null}={}){let a=new Set(Array.isArray(e)?e:["commit","push","pr"]),i=t?` on this branch (${t})`:"",c=[];a.has("commit")&&c.push(`commit the work${i} with a clear commit message`),a.has("rebase")&&c.push(`rebase ${a.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`),c.push("move the work to a fresh branch (branch off the current HEAD with a clear new name)"),c.push("push the new branch to the remote"),c.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 l=[];a.has("commit")||l.push("don't create any new commits \u2014 ship what's already committed"),o&&!a.has("rebase")&&l.push("don't rebase \u2014 leave the branch's history as it is");let u=`Yes \u2014 go ahead, as a NEW pull request: ${c.join(", then ")}.`;return l.length&&(u+=` ${l.join(", and ").replace(/^./,d=>d.toUpperCase())}.`),u+=` 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.`,u+=AR(s),u}function ER(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<=T6&&n.push({box:r.box,from:r.from,to:t+1e12}),n}function _R(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+E6||(!o||s.ts>=o.ts)&&(o=s);o&&n.add(o)}return n}function IR(e){let t=(Array.isArray(e)?e:[]).filter(r=>mR[r]).map(r=>mR[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. Don't wait on the PR's checks \u2014 Bostrat watches them.`}var m6,wR,gR,yR,bR,w6,g6,y6,b6,Ko,x6,xR,S6,v6,A6,T6,E6,mR,ca=K(()=>{pr();_t();m6=600,wR=/(?<!\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,gR=/(?<!\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,yR=/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,bR=/(?<!\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,w6=new RegExp(`\\b(?:${wR}|${gR}|${yR}|${bR})\\b`,"i"),g6=/\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,y6=/^(?:commit|push|open|create|raise|rebase|ready|ok(?:ay)?\s+to|good\s+to)\b/i,b6=90;Ko=["commit","rebase","push","pr"],x6=new RegExp(`\\b(?:${wR})\\b`,"i"),xR=new RegExp(`\\b(?:${bR})\\b`,"i"),S6=new RegExp(`\\b(?:${gR})\\b`,"i"),v6=new RegExp(`\\b(?:${yR})\\b`,"i"),A6=/\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;T6=3e4;E6=2500;mR={commit:"commit",rebase:"rebase",push:"push",pr:"open a PR"}});import{execFile as _6}from"node:child_process";import{promisify as I6}from"node:util";async function R6(e,t){try{let{stdout:n}=await $6("git",["-C",e,"rev-list","--count",t]);return Number(n.trim())||0}catch{return null}}async function O6(e,t,n,{rebase:r=!1,listPrs:o=kn}={}){let s=await Xs(e.dir,{ignorePlumbing:!0}).catch(()=>!1),a=await Zs(e.dir,n).catch(()=>0),i=t?await R6(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 w=p.filter(m=>!(m==="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:Jf.filter(m=>p.includes(m)),defaults:Jf.filter(m=>w.includes(m))}}async function Yf(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 xi(s[0].dir).catch(()=>!1))return null;let a=[];for(let p of s)a.push(await O6(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=Jf.filter(p=>c.some(w=>w.available.includes(p))),u=Jf.filter(p=>c.some(w=>w.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 $6,Jf,cb=K(()=>{Fl();pr();$6=I6(_6),Jf=["commit","rebase","push","pr"]});import{execFile as M6}from"node:child_process";import{promisify as C6}from"node:util";async function fr(e){if(!e)return null;let t=$R.get(e);if(t&&Date.now()-t.at<P6)return t.branch;let n=null;try{let{stdout:r}=await N6("git",["-C",e,"symbolic-ref","--short","-q","HEAD"],{timeout:5e3});n=r.trim()||null}catch{n=null}return $R.set(e,{at:Date.now(),branch:n}),n}function RR(e){return String(e||"").match(D6)?.[1]??null}function OR(e,t){let n=RR(e);return!!n&&!!t&&n===t}function MR(e,t){let n=RR(e);return!!n&&n!==t}function B6(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 Pi(e){let t=[],n=r=>{r&&!t.includes(r)&&t.push(r)};n(e?.workspace?.branch??null);for(let r of B6(e))n(await fr(r));return t}async function Xf(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=>OR(t,a.id));if(s)return s;for(let a of r)if(!He(a)&&(await Pi(a)).includes(t))return a;return null}function L6(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 Zf(e,{branch:t=null,repo:n=null,slug:r=null}={}){return OR(t,e?.id)?!0:L6(e,n,r)}var N6,P6,$R,D6,Vo=K(()=>{yn();N6=C6(M6),P6=5e3,$R=new Map;D6=/^track\/.+-([0-9a-f]{8})$/});import{execFile as j6}from"node:child_process";import{promisify as F6}from"node:util";function Di({trackId:e,boxId:t,epoch:n}){return`${e}/${t}/${Number.isFinite(Number(n))?Number(n):0}`}function eh(e){let t=/^([^/\s]+)\/([^/\s]+)\/(\d+)$/.exec(String(e||"").trim());return t?{trackId:t[1],boxId:t[2],epoch:Number(t[3])}:null}function nh({trackId:e,boxId:t,epoch:n=0,provider:r=null,model:o=null}){let s=[],a=r?K6[r]:null;return a&&s.push(a),s.push(`${BR}: ${Di({trackId:e,boxId:t,epoch:n})}`),o&&s.push(`${LR}: ${String(o).trim()}`),s}function CR(e){let t={epoch:null,model:null,provider:null,cause:null};for(let n of String(e||"").split(`
|
|
290
290
|
`)){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===BR.toLowerCase()&&!t.epoch)t.epoch=eh(a);else if(s===LR.toLowerCase()&&!t.model)t.model=a;else if(s===jR.toLowerCase()&&!t.cause){let i=a.toLowerCase();nu.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 V6(e,t=zo){return e<=t?"rework":"drift"}function z6(e,{window:t=zo,end:n=fb}={}){return!Number.isFinite(e)||e<=t?1:e>=n?0:1-(e-t)/(n-t)}function rh({subject:e="",trailerCause:t=null,wallReason:n=null,fixerCategory:r=null,ciFix:o=!1}={}){let s=String(e||"");return J6.test(s)?{cause:"defect",level:"A",basis:"revert"}:o?{cause:"defect",level:"A",basis:"ci-fix"}:t?{cause:t,level:"E",basis:`${jR} trailer`}:X6.test(s)&&!NR.test(s)?{cause:"style",level:"C",basis:"subject"}:NR.test(s)?{cause:"defect",level:"C",basis:"subject"}:Y6.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 mb({heuristic:e=null,subject:t="",ref:n=null,promptKind:r=null,fixerCategory:o=null,ticketKind:s=null}={}){let a=String(t||""),i=Z6.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&&Q6.has(c)?{intent:"fix",basis:`subject prefix: ${c}:`}:c&&eG.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"}:PR.test(String(n||""))||PR.test(a)?{intent:"planned",basis:"blueprint item"}:o&&tG.has(o)?{intent:"planned",basis:`prompt: ${o}`}:{intent:"unknown",basis:null}}function sG(e){let t=String(e||"");return nG.some(n=>n.test(t))?"excluded":rG.some(n=>n.test(t))?"docs":oG.some(n=>n.test(t))?"config":"code"}function aG(e){let t=[],n=null,r=null;for(let o of String(e||"").split(`
|
|
291
291
|
`)){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 iG(e,t){let n=pb(e),r=pb(t);if(n===r)return 1;if(!n.length||!r.length)return 0;n.length>Qf&&(n=n.slice(0,Qf)),r.length>Qf&&(r=r.slice(0,Qf));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 cG(e,t=FR){let n=new Set,r=e?.del||[],o=e?.add||[];for(let s=0;s<r.length;s++){let a=e.oldStart+s;if(!pb(r[s]).length){n.add(a);continue}s<o.length&&iG(r[s],o[s])>=t&&n.add(a)}return n}function lG(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 uG(e){let t=new Map,n=null;for(let r of String(e||"").split(`
|
|
292
292
|
`)){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 DR(e,t){let{stdout:n}=await db(e,["show","-s","--format=%H%n%P%n%ct%n%s%n%B",t]),[r,o,s,a,...i]=n.split(`
|
|
293
293
|
`);return{sha:r.trim(),parents:o.trim()?o.trim().split(" "):[],ts:Number(s)*1e3,subject:a??"",message:i.join(`
|
|
294
|
-
`)}}async function UR(e,t,{fixKey:n=null,window:r=zo,resolveOrigin:o=null,context:s={}}={}){let a=await DR(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=CR(a.message),l=n?eh(n):c.epoch,u=l?Di(l):null,{stdout:d}=await db(e,["diff","-U0","--no-color","-M","-C",i,t]),p=aG(d),w=0,m=0,f=0,g=0,y=0,b=0,x=0,v=new Map;for(let C of p){if(C.binary)continue;let U=C.oldPath||C.newPath||"",J=C.deleted.reduce((W,[,ce])=>W+ce,0),_=sG(U);if(_==="excluded"){f+=J;continue}if(_==="docs"){g+=J,y+=C.added;continue}if(_==="config"){b+=J;continue}w+=C.added;let I=new Set;for(let W of C.hunks||[])for(let ce of cG(W))I.add(ce);x+=I.size;let T=[];for(let[W,ce]of C.deleted)for(let z=W;z<W+ce;z++)I.has(z)||T.push(z);if(m+=T.length,!C.oldPath||!T.length)continue;let F;try{let W=["blame","-w","-M","-C","--line-porcelain"];for(let[ce,z]of lG(T))W.push("-L",`${ce},${ce+z-1}`);W.push(i,"--",C.oldPath),F=uG((await db(e,W)).stdout)}catch{continue}for(let{sha:W,time:ce}of F.values()){let z=v.get(W)??{lines:0,time:ce};z.lines+=1,v.set(W,z)}}let S=[],E=0,P=new Map;for(let[C,{lines:U,time:J}]of v){let _=P.get(C);if(!_){try{_=await DR(e,C)}catch{_=null}P.set(C,_)}let I=_?CR(_.message):{epoch:null},T=I.epoch,F=I.provider,W=I.model;if(!T&&o){let X=await o(C,_);X?.trackId&&X?.boxId!=null&&(T={trackId:X.trackId,boxId:X.boxId,epoch:X.epoch??0},F=F??X.provider??null,W=W??X.model??null)}if(!T){E+=U;continue}let ce=Number.isFinite(J)?J:_?.ts??a.ts,z=Math.max(0,(a.ts-ce)/W6),Ke=Di(T),Ie=Ke===u?"self":V6(z,r);S.push({sha:C,key:Ke,trackId:T.trackId,boxId:T.boxId,epoch:T.epoch,provider:F??null,model:W??null,lines:U,ageDays:Math.round(z*100)/100,class:Ie,decay:Ie==="rework"?1:Ie==="drift"?Math.round(z6(z,{window:r})*1e3)/1e3:0})}S.sort((C,U)=>U.lines-C.lines);let L=rh({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),$=mb({heuristic:L,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:w,deleted:m,excludedDeleted:f,cosmeticDeleted:x,docsDeleted:g,docsAdded:y,configDeleted:b,codeDelta:w+m+x>0,origins:S,unattributedLines:E,ghost:m===0&&w>0,heuristic:L,intent:$}}function HR(e,{minLines:t=hb}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return Bi.has(n)?ru(e)>=t:!1}function ru(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function ub(e){let t=e.genUsd;return{...e,genUsd:Fn(t),reworkChargedUsd:Fn(e.reworkChargedUsd),reworkPendingUsd:Fn(e.reworkPendingUsd),trueUsd:Fn(t+e.reworkChargedUsd),multiplier:t>0?Fn((t+e.reworkChargedUsd)/t):null}}function WR(e,{window:t=zo,boxMeta:n={}}={}){let r=e||[],o=r.filter($=>$.type==="cost.recorded"),s=r.filter($=>$.type==="code.committed"),a=r.filter($=>$.type==="code.rework"),i=$=>Array.isArray($?.shas)&&$.shas.length?$.shas:$?.sha?[$.sha]:[],c=new Map,l=new Set;for(let $ of r)if($.type==="rework.cause.offered")for(let C of i($.payload))l.add(C);else if($.type==="rework.cause.answered"&&$.payload?.cause)for(let C of i($.payload))c.set(C,$.payload.cause);else if($.type==="rework.cause.retracted")for(let C of i($.payload))c.delete(C);let u={},d=($,C,U)=>Di({trackId:$,boxId:C,epoch:U??0}),p=($,C={})=>{if(!u[$]){let J=eh($)||{};u[$]={key:$,...J,provider:null,model:null,...lb()}}let U=u[$];return C.provider&&!U.provider&&(U.provider=C.provider),C.model&&!U.model&&(U.model=C.model),U};for(let $ of o){if(!$.boxId)continue;let C=d($.trackId,$.boxId,$.epoch),{usd:U,model:J}=gn($),_=p(C,{provider:$.provider,model:J!=="unknown"?J:null});_.genUsd+=U}let w=new Map;for(let $ of s){let C=`${$.trackId}/${$.boxId}`;(w.get(C)??w.set(C,[]).get(C)).push({...$,ts:$.payload?.ts??$.ts})}for(let $ of w.values())$.sort((C,U)=>C.ts-U.ts);let m=($,C,U,J)=>{let _=w.get(`${$}/${C}`)||[],I=-1/0;for(let W of _)W.ts<J&&(I=W.ts);let T=0,F=0;for(let W of o)W.trackId!==$||W.boxId!==C||(W.epoch??0)===(U??0)&&(W.ts<=I||W.ts>J||(T+=gn(W).usd,F++));return{usd:T,turns:F,from:Number.isFinite(I)?I:null}},f={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0,planned:0},g={A:0,B:0,C:0,E:0,none:0},y={fix:0,"likely-fix":0,planned:0,unknown:0},b=0,x=[],v=[],S={},E={},P=new Set;for(let $ of a){let C=$.payload||{};if(!C.sha||P.has(C.sha))continue;if(P.add(C.sha),C.codeDelta===!1){b++;continue}let U=eh(C.fixKey)||{trackId:$.trackId,boxId:$.boxId,epoch:$.epoch??0},{usd:J,turns:_}=m(U.trackId,U.boxId,U.epoch,C.ts??$.ts),I=G6.includes(C.intent?.intent)?C.intent.intent:"unknown";y[I]+=1;let T=null;c.has(C.sha)?T={cause:c.get(C.sha),level:"B",basis:"operator"}:(C.heuristic?.level&&C.heuristic.level!=="C"||C.heuristic)&&(T=C.heuristic);let F=T?.level??"none";g[F]=(g[F]||0)+1;let W=q6.has(F),ce=Number(C.deleted)||0,z=Array.isArray(C.origins)?C.origins:[],Ke=z.filter(X=>X.class==="rework").reduce((X,re)=>X+re.lines,0),Ie={sha:C.sha,subject:C.subject??"",ts:C.ts??$.ts,trackId:$.trackId,fixKey:C.fixKey??null,fixProvider:C.fixProvider??$.provider??null,fixUsd:Fn(J),fixTurns:_,linesReworked:Ke,unattributedLines:Number(C.unattributedLines)||0,ghost:C.ghost===!0,intent:{intent:I,basis:C.intent?.basis??null},verdict:T?{cause:T.cause,level:F,basis:T.basis??null}:null,charged:Fn(0),origins:[]};if(I==="planned"||T?.cause===th){f.planned+=J;for(let X of z)X.class==="rework"&&Ie.origins.push({key:X.key,provider:X.provider??null,model:X.model??null,lines:X.lines,ageDays:X.ageDays,class:X.class,usd:0})}else if(C.ghost||ce===0)f.ghost+=J;else{let X=0;for(let Te of z){let Le=Te.lines/ce,ie=J*Le;if(X+=ie,Te.class==="self"){f.self+=ie;continue}let Pe=Te.class==="rework"?1:Number(Te.decay)||0,ve=ie*Pe;if(f.decayed+=ie-ve,ve<=0)continue;let ee=p(Te.key,{provider:Te.provider,model:Te.model});ee.fixes+=1,ee.linesReworked+=Te.class==="rework"?Te.lines:0;let ge=T?.cause&&nu.includes(T.cause)?T.cause:"unclassified";ee.causes[ge]+=1,W?(ee.reworkChargedUsd+=ve,f.charged+=ve,Ie.charged=Fn(Ie.charged+ve)):(ee.reworkPendingUsd+=ve,f.pending+=ve),Ie.origins.push({key:Te.key,provider:ee.provider,model:ee.model,lines:Te.lines,ageDays:Te.ageDays,class:Te.class,usd:Fn(ve)})}let re=Math.max(0,J-X);f.unattributed+=re}x.push(Ie),!c.has(C.sha)&&l.has(C.sha)&&v.push(C.sha)}for(let $ of Object.values(u)){let C=$.provider||"unknown",U=$.model||"unknown",J=_=>{_.genUsd+=$.genUsd,_.reworkChargedUsd+=$.reworkChargedUsd,_.reworkPendingUsd+=$.reworkPendingUsd,_.linesReworked+=$.linesReworked,_.fixes+=$.fixes;for(let I of Object.keys(_.causes))_.causes[I]+=$.causes[I]};J(S[C]||=lb()),J(E[U]||=lb())}x.sort(($,C)=>C.ts-$.ts);let L=Object.values(u).map($=>{let C=n[`${$.trackId}/${$.boxId}`]||{};return ub({...$,trackName:C.trackName??null,label:C.label??null})}).sort(($,C)=>C.reworkChargedUsd+C.reworkPendingUsd-($.reworkChargedUsd+$.reworkPendingUsd)||C.genUsd-$.genUsd);return{window:t,basis:`rework = code lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old (docs/config churn and in-place updates \u2265${FR} similar are counted, not blamed); fix cost = the fixing box's turns since its previous commit; charged only on an authoritative / operator / self-reported cause; planned work (follow-up, blueprint item, feat:/docs: prefix, non-fix prompt) is generation cost`,intents:y,noCodeDelta:b,byEpoch:Object.fromEntries(L.map($=>[$.key,$])),epochs:L,byProvider:Object.fromEntries(Object.entries(S).map(([$,C])=>[$,ub(C)])),byModel:Object.fromEntries(Object.entries(E).map(([$,C])=>[$,ub(C)])),buckets:Object.fromEntries(Object.entries(f).map(([$,C])=>[$,Fn(C)])),fixUsdTotal:Fn(Object.values(f).reduce(($,C)=>$+C,0)),fixes:x,verdicts:g,pendingTaps:v,commits:s.length}}var U6,H6,db,BR,LR,jR,W6,zo,fb,hb,nu,th,q6,G6,Bi,FR,K6,J6,NR,Y6,X6,Z6,Q6,eG,PR,tG,nG,rG,oG,pb,Qf,Fn,lb,oh=K(()=>{Bo();U6=F6(j6),H6=64*1024*1024,db=(e,t)=>U6("git",["-C",e,...t],{maxBuffer:H6,timeout:6e4}),BR="Bostrat-Epoch",LR="Bostrat-Model",jR="Bostrat-Fix-Cause",W6=24*36e5,zo=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,fb=90,hb=3,nu=Object.freeze(["defect","design","requirements","style"]),th="not-a-fix",q6=new Set(["A","B","E"]),G6=Object.freeze(["fix","likely-fix","planned","unknown"]),Bi=new Set(["fix","likely-fix"]),FR=.8;K6={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};J6=/^revert\b|^revert "/i,NR=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,Y6=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,X6=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;Z6=/^([a-z]+)(\([^)]*\))?!?:\s/i,Q6=new Set(["fix","hotfix","bugfix","revert"]),eG=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),PR=/\bBP-[A-Z0-9]+(?:-[A-Z0-9]+)*\b/i,tG=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);nG=[/(^|\/)\.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)\//],rG=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],oG=[/\.(json|jsonc|json5|ya?ml|toml|ini|cfg|conf|properties|env|example)$/i,/(^|\/)\.[^/]+$/,/(^|\/)\.github\//,/(^|\/)(Dockerfile|Makefile|Procfile|fly\.toml)$/];pb=e=>String(e??"").replace(/\s+/g," ").trim(),Qf=400;Fn=e=>Math.round(e*1e4)/1e4,lb=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as dG}from"node:child_process";import{promisify as pG}from"node:util";function qR(e,t=Date.now()){return Uc(e,t)??0}function hG(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 GR(e,t,{now:n=Date.now()}={}){let r=qR(t,n),o=await V(e);return nh({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:hG(o,t.name,r)})}function mG(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 wG(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=mG(n,t.name),c=i?Cr(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function gG(e,t){try{let{stdout:n}=await wb(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 yG(e){try{let{stdout:t}=await wb(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function KR(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 V(e);if(a.some(f=>f.type==="code.committed"&&f.payload?.sha===n))return{recorded:!1,reason:"duplicate"};let i=s,c=null;try{let{stdout:f}=await wb(r,["show","-s","--format=%ct%n%s",n]),[g,...y]=f.split(`
|
|
294
|
+
`)}}async function UR(e,t,{fixKey:n=null,window:r=zo,resolveOrigin:o=null,context:s={}}={}){let a=await DR(e,t);if(a.parents.length!==1)return null;let i=a.parents[0],c=CR(a.message),l=n?eh(n):c.epoch,u=l?Di(l):null,{stdout:d}=await db(e,["diff","-U0","--no-color","-M","-C",i,t]),p=aG(d),w=0,m=0,h=0,g=0,y=0,b=0,x=0,v=new Map;for(let C of p){if(C.binary)continue;let U=C.oldPath||C.newPath||"",J=C.deleted.reduce((W,[,ce])=>W+ce,0),_=sG(U);if(_==="excluded"){h+=J;continue}if(_==="docs"){g+=J,y+=C.added;continue}if(_==="config"){b+=J;continue}w+=C.added;let I=new Set;for(let W of C.hunks||[])for(let ce of cG(W))I.add(ce);x+=I.size;let T=[];for(let[W,ce]of C.deleted)for(let z=W;z<W+ce;z++)I.has(z)||T.push(z);if(m+=T.length,!C.oldPath||!T.length)continue;let F;try{let W=["blame","-w","-M","-C","--line-porcelain"];for(let[ce,z]of lG(T))W.push("-L",`${ce},${ce+z-1}`);W.push(i,"--",C.oldPath),F=uG((await db(e,W)).stdout)}catch{continue}for(let{sha:W,time:ce}of F.values()){let z=v.get(W)??{lines:0,time:ce};z.lines+=1,v.set(W,z)}}let S=[],E=0,P=new Map;for(let[C,{lines:U,time:J}]of v){let _=P.get(C);if(!_){try{_=await DR(e,C)}catch{_=null}P.set(C,_)}let I=_?CR(_.message):{epoch:null},T=I.epoch,F=I.provider,W=I.model;if(!T&&o){let X=await o(C,_);X?.trackId&&X?.boxId!=null&&(T={trackId:X.trackId,boxId:X.boxId,epoch:X.epoch??0},F=F??X.provider??null,W=W??X.model??null)}if(!T){E+=U;continue}let ce=Number.isFinite(J)?J:_?.ts??a.ts,z=Math.max(0,(a.ts-ce)/W6),Ke=Di(T),Ie=Ke===u?"self":V6(z,r);S.push({sha:C,key:Ke,trackId:T.trackId,boxId:T.boxId,epoch:T.epoch,provider:F??null,model:W??null,lines:U,ageDays:Math.round(z*100)/100,class:Ie,decay:Ie==="rework"?1:Ie==="drift"?Math.round(z6(z,{window:r})*1e3)/1e3:0})}S.sort((C,U)=>U.lines-C.lines);let L=rh({subject:a.subject,trailerCause:c.cause,wallReason:s.wallReason??null,fixerCategory:s.fixerCategory??null,ciFix:s.ciFix===!0}),$=mb({heuristic:L,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:w,deleted:m,excludedDeleted:h,cosmeticDeleted:x,docsDeleted:g,docsAdded:y,configDeleted:b,codeDelta:w+m+x>0,origins:S,unattributedLines:E,ghost:m===0&&w>0,heuristic:L,intent:$}}function HR(e,{minLines:t=hb}={}){if(!e)return!1;let n=e.intent?.intent??"unknown";return Bi.has(n)?ru(e)>=t:!1}function ru(e){return(e?.origins||[]).filter(t=>t.class==="rework").reduce((t,n)=>t+n.lines,0)}function ub(e){let t=e.genUsd;return{...e,genUsd:Fn(t),reworkChargedUsd:Fn(e.reworkChargedUsd),reworkPendingUsd:Fn(e.reworkPendingUsd),trueUsd:Fn(t+e.reworkChargedUsd),multiplier:t>0?Fn((t+e.reworkChargedUsd)/t):null}}function WR(e,{window:t=zo,boxMeta:n={}}={}){let r=e||[],o=r.filter($=>$.type==="cost.recorded"),s=r.filter($=>$.type==="code.committed"),a=r.filter($=>$.type==="code.rework"),i=$=>Array.isArray($?.shas)&&$.shas.length?$.shas:$?.sha?[$.sha]:[],c=new Map,l=new Set;for(let $ of r)if($.type==="rework.cause.offered")for(let C of i($.payload))l.add(C);else if($.type==="rework.cause.answered"&&$.payload?.cause)for(let C of i($.payload))c.set(C,$.payload.cause);else if($.type==="rework.cause.retracted")for(let C of i($.payload))c.delete(C);let u={},d=($,C,U)=>Di({trackId:$,boxId:C,epoch:U??0}),p=($,C={})=>{if(!u[$]){let J=eh($)||{};u[$]={key:$,...J,provider:null,model:null,...lb()}}let U=u[$];return C.provider&&!U.provider&&(U.provider=C.provider),C.model&&!U.model&&(U.model=C.model),U};for(let $ of o){if(!$.boxId)continue;let C=d($.trackId,$.boxId,$.epoch),{usd:U,model:J}=gn($),_=p(C,{provider:$.provider,model:J!=="unknown"?J:null});_.genUsd+=U}let w=new Map;for(let $ of s){let C=`${$.trackId}/${$.boxId}`;(w.get(C)??w.set(C,[]).get(C)).push({...$,ts:$.payload?.ts??$.ts})}for(let $ of w.values())$.sort((C,U)=>C.ts-U.ts);let m=($,C,U,J)=>{let _=w.get(`${$}/${C}`)||[],I=-1/0;for(let W of _)W.ts<J&&(I=W.ts);let T=0,F=0;for(let W of o)W.trackId!==$||W.boxId!==C||(W.epoch??0)===(U??0)&&(W.ts<=I||W.ts>J||(T+=gn(W).usd,F++));return{usd:T,turns:F,from:Number.isFinite(I)?I:null}},h={charged:0,pending:0,self:0,decayed:0,unattributed:0,ghost:0,planned:0},g={A:0,B:0,C:0,E:0,none:0},y={fix:0,"likely-fix":0,planned:0,unknown:0},b=0,x=[],v=[],S={},E={},P=new Set;for(let $ of a){let C=$.payload||{};if(!C.sha||P.has(C.sha))continue;if(P.add(C.sha),C.codeDelta===!1){b++;continue}let U=eh(C.fixKey)||{trackId:$.trackId,boxId:$.boxId,epoch:$.epoch??0},{usd:J,turns:_}=m(U.trackId,U.boxId,U.epoch,C.ts??$.ts),I=G6.includes(C.intent?.intent)?C.intent.intent:"unknown";y[I]+=1;let T=null;c.has(C.sha)?T={cause:c.get(C.sha),level:"B",basis:"operator"}:(C.heuristic?.level&&C.heuristic.level!=="C"||C.heuristic)&&(T=C.heuristic);let F=T?.level??"none";g[F]=(g[F]||0)+1;let W=q6.has(F),ce=Number(C.deleted)||0,z=Array.isArray(C.origins)?C.origins:[],Ke=z.filter(X=>X.class==="rework").reduce((X,re)=>X+re.lines,0),Ie={sha:C.sha,subject:C.subject??"",ts:C.ts??$.ts,trackId:$.trackId,fixKey:C.fixKey??null,fixProvider:C.fixProvider??$.provider??null,fixUsd:Fn(J),fixTurns:_,linesReworked:Ke,unattributedLines:Number(C.unattributedLines)||0,ghost:C.ghost===!0,intent:{intent:I,basis:C.intent?.basis??null},verdict:T?{cause:T.cause,level:F,basis:T.basis??null}:null,charged:Fn(0),origins:[]};if(I==="planned"||T?.cause===th){h.planned+=J;for(let X of z)X.class==="rework"&&Ie.origins.push({key:X.key,provider:X.provider??null,model:X.model??null,lines:X.lines,ageDays:X.ageDays,class:X.class,usd:0})}else if(C.ghost||ce===0)h.ghost+=J;else{let X=0;for(let Te of z){let Le=Te.lines/ce,ie=J*Le;if(X+=ie,Te.class==="self"){h.self+=ie;continue}let Pe=Te.class==="rework"?1:Number(Te.decay)||0,ve=ie*Pe;if(h.decayed+=ie-ve,ve<=0)continue;let ee=p(Te.key,{provider:Te.provider,model:Te.model});ee.fixes+=1,ee.linesReworked+=Te.class==="rework"?Te.lines:0;let ge=T?.cause&&nu.includes(T.cause)?T.cause:"unclassified";ee.causes[ge]+=1,W?(ee.reworkChargedUsd+=ve,h.charged+=ve,Ie.charged=Fn(Ie.charged+ve)):(ee.reworkPendingUsd+=ve,h.pending+=ve),Ie.origins.push({key:Te.key,provider:ee.provider,model:ee.model,lines:Te.lines,ageDays:Te.ageDays,class:Te.class,usd:Fn(ve)})}let re=Math.max(0,J-X);h.unattributed+=re}x.push(Ie),!c.has(C.sha)&&l.has(C.sha)&&v.push(C.sha)}for(let $ of Object.values(u)){let C=$.provider||"unknown",U=$.model||"unknown",J=_=>{_.genUsd+=$.genUsd,_.reworkChargedUsd+=$.reworkChargedUsd,_.reworkPendingUsd+=$.reworkPendingUsd,_.linesReworked+=$.linesReworked,_.fixes+=$.fixes;for(let I of Object.keys(_.causes))_.causes[I]+=$.causes[I]};J(S[C]||=lb()),J(E[U]||=lb())}x.sort(($,C)=>C.ts-$.ts);let L=Object.values(u).map($=>{let C=n[`${$.trackId}/${$.boxId}`]||{};return ub({...$,trackName:C.trackName??null,label:C.label??null})}).sort(($,C)=>C.reworkChargedUsd+C.reworkPendingUsd-($.reworkChargedUsd+$.reworkPendingUsd)||C.genUsd-$.genUsd);return{window:t,basis:`rework = code lines a fix deletes/modifies that blame to another epoch's commit \u2264${t} d old (docs/config churn and in-place updates \u2265${FR} similar are counted, not blamed); fix cost = the fixing box's turns since its previous commit; charged only on an authoritative / operator / self-reported cause; planned work (follow-up, blueprint item, feat:/docs: prefix, non-fix prompt) is generation cost`,intents:y,noCodeDelta:b,byEpoch:Object.fromEntries(L.map($=>[$.key,$])),epochs:L,byProvider:Object.fromEntries(Object.entries(S).map(([$,C])=>[$,ub(C)])),byModel:Object.fromEntries(Object.entries(E).map(([$,C])=>[$,ub(C)])),buckets:Object.fromEntries(Object.entries(h).map(([$,C])=>[$,Fn(C)])),fixUsdTotal:Fn(Object.values(h).reduce(($,C)=>$+C,0)),fixes:x,verdicts:g,pendingTaps:v,commits:s.length}}var U6,H6,db,BR,LR,jR,W6,zo,fb,hb,nu,th,q6,G6,Bi,FR,K6,J6,NR,Y6,X6,Z6,Q6,eG,PR,tG,nG,rG,oG,pb,Qf,Fn,lb,oh=K(()=>{Bo();U6=F6(j6),H6=64*1024*1024,db=(e,t)=>U6("git",["-C",e,...t],{maxBuffer:H6,timeout:6e4}),BR="Bostrat-Epoch",LR="Bostrat-Model",jR="Bostrat-Fix-Cause",W6=24*36e5,zo=Number(process.env.BOSTRAT_REWORK_WINDOW_DAYS)||21,fb=90,hb=3,nu=Object.freeze(["defect","design","requirements","style"]),th="not-a-fix",q6=new Set(["A","B","E"]),G6=Object.freeze(["fix","likely-fix","planned","unknown"]),Bi=new Set(["fix","likely-fix"]),FR=.8;K6={claude:"Co-Authored-By: Claude <noreply@anthropic.com>",codex:"Co-authored-by: Codex <noreply@openai.com>",cursor:"Made-with: Cursor"};J6=/^revert\b|^revert "/i,NR=/\b(fix(es|ed)?|bug|hotfix|regression|crash|broken|npe|null ?pointer|off[- ]by[- ]one|leak)\b/i,Y6=/\b(refactor|rearchitect|re-architect|restructure|rework|rewrite|redesign|simplif(y|ied)|clean ?up)\b/i,X6=/\b(lint|format(ting)?|prettier|typo|whitespace|rename)\b/i;Z6=/^([a-z]+)(\([^)]*\))?!?:\s/i,Q6=new Set(["fix","hotfix","bugfix","revert"]),eG=new Set(["feat","feature","docs","doc","test","tests","build","ci","chore"]),PR=/\bBP-[A-Z0-9]+(?:-[A-Z0-9]+)*\b/i,tG=new Set(["feature-build","docs-writing","research","design","ops-infra","orchestration"]);nG=[/(^|\/)\.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)\//],rG=[/\.(md|mdx|markdown|rst|txt|adoc|asciidoc)$/i,/(^|\/)(docs?|notes|business|design)\//i,/(^|\/)(README|CHANGELOG|CHANGES|LICENSE|CONTRIBUTING|AUTHORS|NOTICE)(\.[a-z]+)?$/i],oG=[/\.(json|jsonc|json5|ya?ml|toml|ini|cfg|conf|properties|env|example)$/i,/(^|\/)\.[^/]+$/,/(^|\/)\.github\//,/(^|\/)(Dockerfile|Makefile|Procfile|fly\.toml)$/];pb=e=>String(e??"").replace(/\s+/g," ").trim(),Qf=400;Fn=e=>Math.round(e*1e4)/1e4,lb=()=>({genUsd:0,reworkChargedUsd:0,reworkPendingUsd:0,linesReworked:0,fixes:0,causes:{defect:0,design:0,requirements:0,style:0,unclassified:0}})});import{execFile as dG}from"node:child_process";import{promisify as pG}from"node:util";function qR(e,t=Date.now()){return Uc(e,t)??0}function hG(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 GR(e,t,{now:n=Date.now()}={}){let r=qR(t,n),o=await V(e);return nh({trackId:e.id,boxId:t.name,epoch:r,provider:t.agent??null,model:hG(o,t.name,r)})}function mG(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 wG(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=mG(n,t.name),c=i?Cr(i.text)?.category??null:null;return{wallReason:a,fixerCategory:c,promptKind:i?.kind??null}}async function gG(e,t){try{let{stdout:n}=await wb(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 yG(e){try{let{stdout:t}=await wb(e,["rev-parse","--abbrev-ref","HEAD"]);return t.trim()||null}catch{return null}}async function KR(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 V(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 wb(r,["show","-s","--format=%ct%n%s",n]),[g,...y]=h.split(`
|
|
295
295
|
`),b=Number(g.trim())*1e3;Number.isFinite(b)&&b>0&&(i=b),c=y.join(`
|
|
296
|
-
`).trim().slice(0,300)||null}catch{return{recorded:!1,reason:"unknown-sha"}}let l=qR(t,i),u=await gG(r,n),d=await yG(r),p=await D(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}}),w=null,m=!1;try{let
|
|
297
|
-
`,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+$G(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 yb(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function rO(e){let t=tO(e),n=t.match(EG);if(!n)return null;let r=yb(t,n.index);return IG.test(r)?null:{repo:r.match(nO)?.[1]??null,head:r.match(RG)?.[1]??null}}function oO(e){let t=tO(e),n=t.match(_G);if(!n)return null;let r=yb(t,n.index),o=yb(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("-")){MG.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(nO)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function NG(e,t,{exclude:n=()=>!1}={}){let r=async i=>{Fr("observer");let{stdout:c}=await XR("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",CG],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw qo(l)&&Go(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-vG&&!n(c)),s=await tr({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 PG(e,t){if(t)return[t];let n=[];for(let r of sO(e)){let o=await Re(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await Ir().catch(()=>[])){let o=await Re(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function sO(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 DG(e,t,n){let r=await Pi(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)||OG(c.headRefName,e.id),i=[];for(let c of await PG(e,t?.repo??null)){let l;try{l=await NG(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await pt(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 aO(e){if(!e)return 0;let t=0;for(let n of qr)n.startsWith(`${e}|`)&&t++;return t}function iO(){for(let e of[...bb])e()}function cO(e,t,{delays:n=ZR,turnEnd:r}={}){let o=rO(t.command);if(!o)return null;let s=!!oO(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(qr.has(a))return null;qr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(f=>{let g=()=>{clearTimeout(y),bb.delete(g),f()},y=setTimeout(g,l);bb.add(g)});let u=await DG(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:p}=u,{link:w,created:m}=await ln({repo:d,number:p.number,trackId:e.id,url:p.url,headRef:p.headRefName,title:p.title,source:"observed"});return!m&&!(w?.trackId===e.id&&await Lr(d,p.number))?null:(await gb(t.box,t.agent,r),await Hr({repo:d,number:p.number,via:"observer"}).catch(()=>{}),await D({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{qr.delete(a)}})();return c.catch(()=>qr.delete(a)),c}function lO(e,t,{delays:n=ZR,turnEnd:r,openedWait:o}={}){let s=oO(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(qr.has(a))return null;qr.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 m=sO(e);if(m.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let f of m){let g=await Re(f).catch(()=>null);g&&!d.includes(g)&&d.push(g)}}if(l||=(await Pi(e).catch(()=>[])).filter(m=>m!==e.workspace?.branch)[0]||e.workspace?.branch,!d.length||!l)return null;c=d[0];let p=async(m,f)=>{let g=await pt(c,m.number);return g&&g.trackId!==e.id?null:(g||await ln({repo:c,number:m.number,trackId:e.id,url:m.url,headRef:m.headRefName,title:m.title,source:"merge-observed"}),await Vl(c,m.number),f&&((await V(e).catch(()=>[])).some(x=>x.type==="pr.state.changed"&&(x.payload?.change==="auto-armed"||x.payload?.change==="merged")&&x.payload?.number===m.number)||(await gb(t.box,t.agent,r),await D({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:m.number,url:m.url,title:m.title,branch:m.headRefName,repo:c}}))),m)},w=null;for(let m of n){await new Promise(E=>setTimeout(E,m));let f=[];for(let E of d)try{Fr("observer");let{stdout:P}=await XR("gh",["pr","view",String(l),"--repo",E,"--json",BG],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await tr({slug:E})}}),L=JSON.parse(P||"null");L?.number&&f.push({slug:E,pr:L})}catch(P){qo(P)&&Go(P)}let g=f.find(E=>E.pr.state==="MERGED")??(f.length===1?f[0]:null);if(!g)continue;c=g.slug;let y=g.pr;if(!y?.number)continue;if(y.state==="CLOSED")return null;if(y.state!=="MERGED"){if(w=y,s.auto)return p(y,!0);continue}let b=await pt(c,y.number);if(b&&b.trackId!==e.id)return null;b||await ln({repo:c,number:y.number,trackId:e.id,url:y.url,headRef:y.headRefName,title:y.title,source:"merge-observed"}),await gb(t.box,t.agent,r);let x=await V(e).catch(()=>[]);if(x.some(E=>E.type==="pr.state.changed"&&E.payload?.change==="merged"&&E.payload?.number===y.number))return null;let v=E=>E.some(P=>P.type==="pr.state.changed"&&P.payload?.change==="opened"&&P.payload?.number===y.number),S=0;if(!v(x)){if(rO(t.command)&&await Lr(c,y.number)){await Hr({repo:c,number:y.number,via:"observer-merge"}).catch(()=>{});let E=Date.now();S=E+1,await D({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:E,change:"opened",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c,selfMerge:!0}})}else if((await pt(c,y.number))?.announced){let E=o?.capMs??AG,P=o?.pollMs??TG,L=Date.now()+E;for(;Date.now()<L&&(await new Promise($=>setTimeout($,P)),!v(await V(e).catch(()=>[]))););}}return await D({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(),S),change:"merged",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c}}),await sh(e,{repo:c,number:y.number,title:y.title,branch:y.headRefName,url:y.url}).catch(()=>{}),await Kr(c,y.number).catch(()=>{}),await Gr(c,y.number).catch(()=>{}),await Ho(c,y.number,"merged"),y}return w?p(w,!1):null}finally{qr.delete(a)}})();return i.catch(()=>qr.delete(a)),i}var XR,ZR,xG,SG,vG,AG,TG,QR,eO,EG,_G,IG,YR,$G,nO,RG,OG,MG,CG,qr,bb,BG,ih=K(()=>{be();er();_t();Jl();jn();pr();Vr();Vs();Vo();ah();XR=kG(bG),ZR=[4e3,15e3,45e3],xG=2500,SG=5*6e4;vG=15e3,AG=9e4,TG=2e3,QR=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,eO=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,EG=new RegExp(`${QR}${eO}create\\b`),_G=new RegExp(`${QR}${eO}merge\\b`),IG=/\s--web\b/,YR=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,$G=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");nO=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,RG=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,OG=MR;MG=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);CG="number,url,title,headRefName,createdAt";qr=new Set;bb=new Set;BG="number,url,title,headRefName,state"});import LG from"node:fs/promises";import xb from"node:path";import jG from"node:os";function kb(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function ch(e){let t=FG.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=kb(n,"from"),s=o?o.replace(/^uds:/,""):null,a=uO(s);return{socket:s,pid:a,name:kb(n,"from-name"),mode:kb(n,"from-mode"),text:r.trim()}}function uO(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function UG(){return process.env.CLAUDE_CONFIG_DIR?xb.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):xb.join(jG.homedir(),".claude","sessions")}async function HG(e){let t=uO(e);if(!t)return null;try{let n=await LG.readFile(xb.join(UG(),`${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 dO(e,t){let n=await HG(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 FG,Sb=K(()=>{FG=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function WG(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 qG(e,t,n){let r=WG(t,n);return r?D(e,{type:"track.obligations.changed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),open:r.open,since:r.since}}).catch(()=>null):null}function la(e){let t=r=>Number(r.payload?.ts??r.ts??0)||0,n={askedAt:0,closedAt:0,hookClosedAt:0,abortedAt:0};for(let r of e||[])r&&(r.type==="turn.user"||r.type==="peer.message"?n.askedAt=Math.max(n.askedAt,t(r)):r.type==="turn.agent"?(n.closedAt=Math.max(n.closedAt,t(r)),r.source==="hook"&&(n.hookClosedAt=Math.max(n.hookClosedAt,t(r)))):r.type==="turn.aborted"&&(n.abortedAt=Math.max(n.abortedAt,t(r))));return n}function hO(e){let t=la(e);return t.askedAt?t.askedAt>Math.max(t.closedAt,t.abortedAt):!1}function KG(e,{epochStartedAt:t=null}={}){let n=l=>Number(l.payload?.ts??l.ts??0)||0,r=la(e),o=null,s=null,a=null;for(let l of e||[]){if(!l)continue;let u=l.payload||{};l.type==="turn.interrupted"?(u.result==="stopped"||u.result==="stopped-late")&&u.busyAtClick!==!1&&n(l)>=(o?.at||0)&&(o={at:n(l),unsent:!!u.unsent,busyAtClick:u.busyAtClick===!0}):l.type==="turn.aborted"?n(l)>=(s?.at||0)&&(s={at:n(l),cause:u.cause||"cli-exited",agent:u.agent||l.provider||null}):l.type==="provider.error"&&n(l)>=(a?.at||0)&&(a={at:n(l),cls:u.cls||"other",provider:l.provider||null})}let i=Math.max(r.askedAt,Number(t)||0),c=[];if(o&&o.at>i&&(r.askedAt||o.busyAtClick)&&c.push({at:o.at,source:"stop",summary:o.unsent?"stopped before it started \u2014 your message is back in the composer":"you stopped the agent"}),s&&s.at>i&&c.push({at:s.at,source:`abort:${s.cause}`,summary:pO[s.cause]||pO["cli-exited"]}),a&&r.askedAt&&a.at>i&&a.at>r.closedAt){let l=GG[a.cls]||"returned an error";c.push({at:a.at,source:"provider-error",summary:`${a.provider||"the provider"} ${l} instead of finishing the turn`})}return c.length?c.reduce((l,u)=>u.at>l.at?u:l):null}function ZG(e){let t=String(e||"").split(/\r?\n/).map(a=>a.trim()).filter(Boolean),n=t[t.length-1];if(!n||/^(?:>|\||```|~~~)/.test(n))return null;let r=n.replace(/[\s*_~]+$/,"");if(!r.endsWith("?"))return null;let o=r.replace(/^(?:[-*+]|\d+[.)])\s+/,"").split(/(?<=[.?!])\s+/).filter(Boolean),s=o.pop()||"";return s.length<VG&&o.length&&(s=`${o.pop()} ${s}`),s=s.replace(/\*\*|__/g,"").trim(),s?s.length>fO?s.slice(0,fO-1)+"\u2026":s:null}function QG(e,{leadBox:t=null,epochStartedAt:n=null}={}){let r=c=>Number(c.payload?.ts??c.ts??0)||0,o=Math.max(la(e).askedAt,Number(n)||0),s=null,a=0;for(let c of e||[])if(!(!c||r(c)<=o)){if(XG(c))return null;c.type!=="turn.agent"||t&&c.boxId&&c.boxId!==t||(c.source==="hook"?a=Math.max(a,r(c)):!c.payload?.note&&String(c.payload?.text||"").trim()&&r(c)>=(s?.at||0)&&(s={at:r(c),text:c.payload.text,provider:c.provider||null}))}if(!s||s.provider==="claude"&&(a<s.at-JG||a-s.at>zG))return null;let i=ZG(s.text);return i?{at:s.at,source:"question",summary:i}:null}function eK(e,t){let n=null;for(let o of e||[]){if(o?.type!=="track.interrupted.changed")continue;let s=o.payload||{};n=s.at?{at:Number(s.at)||0,source:s.source||null}:null}let r=t?.at?{at:t.at,source:t.source||null}:null;return!r&&!n||r&&n&&r.at===n.at&&r.source===n.source?null:{at:r?.at??null,source:r?.source??null,summary:t?.summary??null}}async function tK(e,t,n){let r=eK(t,n);return r?D(e,{type:"track.interrupted.changed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),...r}}).catch(()=>null):null}async function vb(e){if(lh.has(e.id))return lh.get(e.id);let t=await V(e).catch(()=>[]),n=[];try{n=ir(t)}catch{}let r=Bp(n),o=n.filter(y=>y?.kind==="followup-offer"&&y.status==="open"),s=new Set(t.filter(y=>y.type==="prompt.answered").map(y=>y.payload?.promptId)),a=t.filter(y=>y.type==="prompt.raised"&&y.payload?.promptId&&!s.has(y.payload.promptId)),i=(e.boxes||[]).find(y=>y.name===e.leadBox),c=Array.isArray(i?.epochs)&&i.epochs.length?i.epochs[i.epochs.length-1]:null,l=KG(t,{epochStartedAt:c?.startedAt??null}),u=l||e.archivedAt?null:QG(t,{leadBox:e.leadBox,epochStartedAt:c?.startedAt??null}),d=[...r,...o,...a.map(y=>({ts:y.payload?.ts??y.ts})),...u?[{ts:u.at}]:[]],p=null;for(let y of t){if(y.type!=="track.phase.changed")continue;let b=y.payload||{};p=b.phase?{phase:b.phase,summary:b.summary??null,scope:b.scope??null,phaseId:b.phaseId??null,at:b.ts??y.ts}:null}let w=n.flatMap(y=>y?.kind==="job-dock"?y.jobs||[]:[]).filter(y=>y?.status==="running"),m=t.reduce((y,b)=>b.type==="turn.agent"?Math.max(y,b.payload?.ts??b.ts??0):y,0)||null,f=t.reduce((y,b)=>b.type==="turn.user"?Math.max(y,b.payload?.ts??b.ts??0):y,0)||null,g={openActions:d.length,openActionSince:d.length?Math.min(...d.map(y=>y.ts||Date.now())):null,phase:p,completedTurnAt:m,currentTurnAt:f,interrupted:l,question:u,runningJobs:w.length,runningJobsSince:w.length?Math.min(...w.map(y=>y.startedTs||Date.now())):null};return lh.set(e.id,g),!He(e)&&e.kind!=="setup"&&(qG(e,t,g),tK(e,t,l)),g}function mO({trackOf:e,debounceMs:t=nK,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(ou.get(s));let a=setTimeout(()=>{ou.delete(s),Promise.resolve(e(s)).then(i=>i&&!He(i)&&i.kind!=="setup"?vb(i):null).catch(i=>n.warn?.(`[obligations] fold ${s} failed: ${i?.message||i}`))},t);a.unref?.(),ou.set(s,a)};return at.on("event",r),()=>{at.off("event",r);for(let o of ou.values())clearTimeout(o);ou.clear()}}var lh,pO,GG,fO,VG,zG,JG,YG,XG,nK,ou,su=K(()=>{be();Lp();yn();lh=new Map;at.on("event",e=>{e?.trackId&&lh.delete(e.trackId)});pO={"cli-exited":"the agent exited before finishing","session-gone":"the agent's session is gone before it finished","terminal-esc":"interrupted with Esc in the terminal"},GG={rate_limit:"hit a rate limit",entitlement:"refused the request (plan / credits)",auth:"needs a login",overloaded:"was overloaded",server:"returned a server error"};fO=200,VG=24,zG=15e3,JG=5e3,YG=new Set(["pr.offered","ticket.create.offered","loop.create.offered","loop.update.offered","loop.delete.offered","followup.create.offered","planning.change.offered"]),XG=e=>YG.has(e.type)||e.type==="followup.offered"&&e.payload?.trigger==="now";nK=750,ou=new Map});function wO(e=process.env){return!!(Ue(e)&&e.BOSTRAT_PLANE_TOKEN)}async function gO(e,t,n=Ab){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await oK(`${Ue(t)}${e}`,{headers:sK(t),signal:r.signal})}finally{clearTimeout(o)}}async function au({env:e=process.env,force:t=!1,timeoutMs:n=Ab}={}){if(!wO(e))return{followups:[],source:"unconfigured"};if(!t&&ua&&Date.now()-ua.at<rK)return{followups:ua.followups,source:"cache"};try{let r=await gO("/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 ua={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return ua?{followups:ua.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function yO(e,{env:t=process.env,timeoutMs:n=Ab}={}){if(!e)return{followup:null,source:"unconfigured"};if(!wO(t))return{followup:null,source:"unconfigured"};try{let r=await gO(`/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=ua?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var rK,Ab,ua,oK,sK,bO=K(()=>{_t();rK=6e4,Ab=5e3,ua=null,oK=(...e)=>fetch(...e);sK=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});async function Jo(e,t){if(Tb.has(e)){let n=new Error("offer already answered (answer in flight)");throw n.code="answer-in-flight",n}Tb.add(e);try{return await t()}finally{Tb.delete(e)}}var Tb,iu=K(()=>{Tb=new Set});import{randomUUID as pa,createHash as aK}from"node:crypto";function uh(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function $O(e){for(let[t,n]of uK)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 vO(e,{at:t="",promptRequired:n=!0,standing:r=!1}={}){let o=e&&typeof e=="object"?e:{},s=fa(o.label).replace(/\s+/g," ");if(!s)throw new Error(`${t}label required (\u2264${Eb} chars, e.g. "Deploy to Pi")`);if(s.length>Eb)throw new Error(`${t}label must be \u2264${Eb} characters`);let a=fa(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")>kO)throw new Error(`${t}prompt must be \u2264${kO} bytes`);if(r){let l=$O(a);if(l)throw new Error(`${t}${l}`)}let i=o.standing==null||o.standing===""?"offerable":String(o.standing).trim().toLowerCase();if(!lK.includes(i))throw new Error(`${t}standing must be "offerable" or "never", got "${o.standing}"`);let c=fa(o.why).slice(0,EO)||null;return{label:s,prompt:a,why:c,standing:i}}function RO(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=fa(n.trigger)||(n.ship?"now":""),o=t?iK:_O.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"?fK(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>SO)throw new Error(`items must be \u2264${SO} \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((w,m)=>vO(w,{at:`items[${m}]: `,standing:t})),c=fa(n.why).slice(0,EO)||null;let p=new Set;for(let w of i){let m=uh(w.label);if(p.has(m))throw new Error(`items must have distinct labels ("${w.label}" appears twice)`);p.add(m)}}else i=[vO(n,{promptRequired:!s,standing:t})];let l=i[0],u=c??l.why,d=t?pK(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 dK(e){return e.standing==="never"?{promotable:!1,promotableReason:"one-off"}:$O(e.prompt)?{promotable:!1,promotableReason:"specifics"}:{promotable:!0,promotableReason:null}}function pK(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 fK(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):_b.slice();for(let i of n)if(!_b.includes(i))throw new Error(`ship.actions may only contain ${_b.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=fa(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=>fa(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function dh(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 OO(e){return{armId:e.armId,label:e.label,prompt:e.prompt,promptHash:IO(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",...dK(e)}}async function MO(e,t,{pull:n=au,ship:r={}}={}){let o=RO(t);if(o.ship)return{kind:"ship",...await bK(e,o,r)};if(Rb(e))throw new Error("follow-ups don't fire on a loop's run Track \u2014 report the outcome with `bostrat-loop report` instead (a ship offer via `bostrat-ship offer` is fine)");let s={id:e.id,cwd:e.cwd},a=(e.boxes||[]).find(b=>b.name===e.leadBox)||null,i={boxId:e.leadBox??null,provider:a?.agent??null},c=pa(),l=(b,x,v={})=>({ts:Date.now(),armId:pa(),trigger:o.trigger,label:b.label,prompt:b.prompt,why:b.why,standing:b.standing,groupId:c,seq:x,...o.planWhy?{planWhy:o.planWhy}:{},...v}),u={groupId:c,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,planWhy:o.planWhy};if(o.trigger==="now"){let b=pa(),x=[];for(let[v,S]of o.items.entries()){let E=l(S,v);await D(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:E}),x.push(E)}return await D(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:b,trigger:"now",repo:e.workspace?.repo||null,context:{},groupId:c,why:o.planWhy,rows:x.map(OO)}}),{kind:"now",offerId:b,armId:x[0].armId,items:x.map(v=>({armId:v.armId,label:v.label,standing:v.standing})),...u}}let d=e.workspace?.repo||null,{followups:p}=await n().catch(()=>({followups:[]})),w=await V(s),m=dh(w,{trigger:o.trigger}),f=[],g=0;for(let b of o.items){let x=uh(b.label),v=p.find(L=>L.status==="active"&&L.mode!=="off"&&L.trigger===o.trigger&&(L.repo==null||L.repo===d)&&L.dedupeKey===x);if(v){f.push({label:b.label,standing:b.standing,covered:{id:v.id,label:v.label}});continue}let S=m.filter(L=>uh(L.label)===x),E=S.length?S[S.length-1].armId:null,P=l(b,g++,E?{replaces:E}:{});await D(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:P}),f.push({armId:P.armId,label:b.label,standing:b.standing,replaces:E})}let y=f.filter(b=>b.armId);return y.length?{kind:"armed",armId:y[0].armId,replaces:y[0].replaces,items:f,...u}:{kind:"covered",covered:f[0].covered,items:f,...u}}async function CO(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await V(n);if(!dh(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await D(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function NO(e,t,{pull:n=au}={}){if(Rb(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=RO(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await V(s)).reduce((g,y)=>y.type==="followup.create.offered"?y.payload?.proposalId??g:y.type==="followup.create.answered"&&y.payload?.proposalId===g?null:g,null))throw new Error("a follow-up proposal is already waiting on the operator in this Track \u2014 one at a time");let{followups:c,source:l}=await n().catch(()=>({followups:[],source:"unreachable"}));if(l==="unreachable")throw new Error("plane unreachable \u2014 standing follow-ups live in the plane; try again shortly");let u=uh(r.label),d=c.filter(g=>g.dedupeKey===u&&g.trigger===r.trigger),p=d.find(g=>g.status==="deleted"),w=d.find(g=>g.status!=="deleted");if(w)throw new Error(`"${w.label}" (${$b[w.trigger]||w.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(p){let g=p.deletedAt?new Date(p.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${p.label}" on ${g} \u2014 do not re-propose it`)}let m=pa(),f=(e.boxes||[]).find(g=>g.name===e.leadBox)||null;return await D(s,{type:"followup.create.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:f?.agent??null,payload:{ts:Date.now(),proposalId:m,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why,origin:"agent"}}),{proposalId:m,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why}}async function PO(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await V(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 D(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 D(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 D(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 cu(e,t,n={},{pull:r=au}={}){if(!e||Rb(e))return null;let o={id:e.id,cwd:e.cwd},s=await V(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null;if(t==="pr.merged"){let b=S=>{let E=(S?.prs||[]).filter(P=>Number.isFinite(Number(P?.number))).map(P=>`${P?.repo??S?.repo??""}#${Number(P.number)}`);return Number.isFinite(Number(S?.prNumber))&&E.push(`${S?.repo??""}#${Number(S.prNumber)}`),E},x=new Set(b(n));if(s.some(S=>S.type==="followup.offered"&&S.payload?.trigger==="pr.merged"&&b(S.payload?.context).some(E=>x.has(E))))return null}let i=dh(s,{trigger:t}),c=i.length?i[i.length-1].groupId??null:null,l=i.slice(0,xO).map(OO),u=c?i.find(b=>b.groupId===c&&b.planWhy)?.planWhy??null:null,d=[];if(t!=="now"){let{followups:b}=await r().catch(()=>({followups:[]}));d=b.filter(x=>x.status==="active"&&x.mode!=="off"&&x.trigger===t&&(x.repo==null||x.repo===a)).sort((x,v)=>{let S=E=>E.stats?.offered?(E.stats.accepted||0)/E.stats.offered:0;return S(v)-S(x)||(x.origin==="operator"?-1:0)-(v.origin==="operator"?-1:0)||(v.createdAt||0)-(x.createdAt||0)}).slice(0,cK).map(x=>({followupId:x.id,label:x.label,promptPreview:hK(x.prompt),promptHash:IO(x.prompt),origin:x.origin,repo:x.repo??null}))}let p=[...l,...d].slice(0,xO);if(!p.length)return null;let w=pa(),m={ts:Date.now(),offerId:w,trigger:t,repo:a,context:{...n,repo:a},groupId:c,why:u,rows:p},f=(e.boxes||[]).find(b=>b.name===e.leadBox)||null,g=i.find(b=>b.provider)?.provider??f?.agent??null,y=i.find(b=>b.boxId)?.boxId??e.leadBox??null;return await D(o,{type:"followup.offered",actor:"system",source:"orchestrator",boxId:y,provider:g,payload:m}),m}function mK(e,t){let n=t?.rows||[],r=new Map(n.map(s=>[da(s),null])),o=(s,a)=>{r.has(s)&&r.get(s)==null&&r.set(s,a)};for(let s of e){if(s.type!=="followup.answered"||s.payload?.offerId!==t.offerId)continue;let a=s.payload,i=[];a.armId&&i.push(`arm:${a.armId}`),a.followupId&&i.push(`fu:${a.followupId}`);for(let c of Array.isArray(a.armIds)?a.armIds:[])i.push(`arm:${c}`);for(let c of Array.isArray(a.followupIds)?a.followupIds:[])i.push(`fu:${c}`);if(i.length)for(let c of i)o(c,a.action);else for(let c of r.keys())o(c,a.action)}return r}function Ib(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 DO(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null,all:s=!1,rows:a=null,prompt:i=null,prompts:c=null,reordered:l=!1}={},u={}){if(!t)throw new Error("offerId required");if(a!=null&&!Array.isArray(a))throw new Error("rows must be an array of row keys");if(i!=null&&typeof i!="string")throw new Error("prompt must be a string");if(c!=null&&(typeof c!="object"||Array.isArray(c)))throw new Error("prompts must be an object of row key \u2192 text");return Jo(`fu:${e.id}:${t}`,()=>yK(e,{offerId:t,followupId:n,armId:r,promoted:o,all:s===!0,rows:a,prompt:i,prompts:c,reordered:l===!0},u))}function TO(e,t){if(e==null)return null;let n=String(e).replace(/\u0000/g,"").trim();if(!n)throw new Error("an edited prompt can't be empty \u2014 Reset it or type the step");if(n.length>AO)throw new Error(`an edited prompt must be \u2264${AO} characters`);return n===String(t??"").trim()?null:n}async function BO(e,{offerId:t,armId:n,followupId:r}={}){if(!t||!n||!r)throw new Error("offerId, armId and followupId required");let o={id:e.id,cwd:e.cwd},s=await V(o),a=s.find(c=>c.type==="followup.offered"&&c.payload?.offerId===t);if(!a)throw new Error("unknown offer");if(!(a.payload.rows||[]).find(c=>c.armId===n))throw new Error("that arm is not on this card");if(s.some(c=>c.type==="followup.arm.saved"&&c.payload?.armId===n))throw new Error("that row is already saved");return await D(o,{type:"followup.arm.saved",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,armId:n,followupId:String(r)}}),{offerId:t,armId:n,followupId:String(r)}}async function yK(e,{offerId:t,followupId:n,armId:r,promoted:o,all:s,rows:a,prompt:i,prompts:c,reordered:l},u){let{sayToLead:d,unarchiveTrack:p,getFollowup:w=yO}=u,m={id:e.id,cwd:e.cwd},f=await V(m),g=f.find(I=>I.type==="followup.offered"&&I.payload?.offerId===t);if(!g)throw new Error("unknown offer");let y=g.payload.rows||[],b=mK(f,g.payload),x=wK(b,y);if(!x.length)throw new Error("offer already answered");let v=I=>D(m,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...I}}),S=async()=>{if(!e.archivedAt)return!1;if(!p)throw new Error("this Track is archived");return await p(e.id,{freshSession:!0}),e={...e,archivedAt:null},!0},E=I=>{let F=f.find(W=>W.type==="followup.armed"&&W.payload?.armId===I.armId)?.payload?.prompt??I.prompt;if(!F)throw new Error("the arm's prompt is missing from the log");return F};if(s||a){let I,T=!1;if(a){let X=[...new Set(a.map(Le=>String(Le)))];if(!X.length)throw new Error("rows must name at least one item");let re=new Map(y.map(Le=>[da(Le),Le]));for(let Le of X){let ie=re.get(Le);if(!ie)throw new Error(`${Le} is not on this card`);if(!ie.armId)throw new Error("a standing follow-up runs on its own \u2014 it is not part of a batch");if(b.get(Le)!=null)throw new Error("that row is already answered")}let Te=y.filter(Le=>X.includes(da(Le)));I=l?X.map(Le=>re.get(Le)):Te,T=l&&I.some((Le,ie)=>Le!==Te[ie])}else I=x.filter(X=>X.armId);if(!I.length)throw new Error("nothing to run together \u2014 no open items from this plan remain on the card");let F=new Map;if(c){let X=new Map(I.map(re=>[da(re),re]));for(let[re,Te]of Object.entries(c)){let Le=X.get(re);if(!Le)throw new Error(`${re} is not in this batch \u2014 prompts can only edit the rows being sent`);let ie=TO(Te,E(Le));ie!=null&&F.set(re,ie)}}let W=I.map(X=>({row:X,key:da(X),prompt:F.get(da(X))??E(X)})),ce=await S();if(!d)throw new Error("sayToLead unavailable");let z=W.length===1?`${Ib(g.payload)}
|
|
296
|
+
`).trim().slice(0,300)||null}catch{return{recorded:!1,reason:"unknown-sha"}}let l=qR(t,i),u=await gG(r,n),d=await yG(r),p=await D(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}}),w=null,m=!1;try{let h=await UR(r,n,{fixKey:Di({trackId:e.id,boxId:t.name,epoch:l}),window:zo,context:{...wG(e,t,a,l),ref:d,provider:t.agent??null}});if(h&&(w=await D(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)&&HR(h))){let y=ru(h),b=h.origins.filter(x=>x.class==="rework").slice(0,3);await D(e,{type:"rework.cause.offered",actor:"orchestrator",source:"orchestrator",boxId:t.name,provider:t.agent??null,causationId:w.id,payload:{sha:n,subject:h.subject,linesReworked:y,origins:b.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}}),m=!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:w,offered:m}}function VR(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 zR(e,t,n){if(!nu.includes(n)&&n!==th)throw new Error(`bad cause "${n}" (${nu.join("|")}|${th})`);let r=await V(e),o=r.find(s=>s.type==="rework.cause.offered"&&s.payload?.sha===t);if(!o)throw new Error("unknown rework offer");if(VR(r,t))throw new Error("already answered");return D(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 JR(e,t){let n=await V(e);if(!VR(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 D(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 sh(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 V(e);if(c.some(b=>b.type==="rework.cause.offered"&&b.payload?.pr?.number===n&&(t==null||b.payload.pr.repo===t)))return{offered:!1,reason:"duplicate"};let l=new Set;for(let b of c)if(b.type==="rework.cause.offered")for(let x of Array.isArray(b.payload?.shas)?b.payload.shas:[b.payload?.sha])x&&l.add(x);let u=new Map;for(let b of c)b.type==="code.committed"&&b.payload?.sha&&u.set(b.payload.sha,b.payload.ref??null);let d=mb({heuristic:rh({subject:r}),subject:r,ref:o}),p=[];for(let b of c){if(b.type!=="code.rework")continue;let x=b.payload||{};if(!x.sha||l.has(x.sha)||x.codeDelta===!1||o&&u.has(x.sha)&&u.get(x.sha)!==o)continue;let v=x.intent?.intent??"unknown";(Bi.has(v)||v==="unknown"&&Bi.has(d.intent))&&ru(x)!==0&&p.push(x)}let w=p.reduce((b,x)=>b+ru(x),0);if(w<hb)return{offered:!1,reason:"below-threshold"};let m=new Map;for(let b of p)for(let x of b.origins??[]){if(x.class!=="rework")continue;let v=m.get(x.key)??{key:x.key,provider:x.provider??null,model:x.model??null,lines:0,ageDays:x.ageDays};v.lines+=x.lines,v.ageDays=Math.min(v.ageDays,x.ageDays),m.set(x.key,v)}let h=p.map(b=>b.sha),g=p.map(b=>b.heuristic).find(b=>b&&b.level!=="C")??rh({subject:r})??p.map(b=>b.heuristic).find(Boolean)??null,y=Bi.has(d.intent)?d:p.find(b=>Bi.has(b.intent?.intent))?.intent??d;return await D(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:w,origins:[...m.values()].sort((b,x)=>x.lines-b.lines).slice(0,3),heuristic:g,intent:y,ts:i}}),{offered:!0,shas:h}}catch(c){return a.warn?.(`[rework] ${e?.id}: PR-level offer for #${n} failed: ${c?.message||c}`),{offered:!1,reason:"error"}}}var fG,wb,ah=K(()=>{be();Np();oh();fG=pG(dG),wb=(e,t)=>fG("git",["-C",e,...t],{maxBuffer:16*1024*1024,timeout:3e4})});import{execFile as bG}from"node:child_process";import{promisify as kG}from"node:util";async function gb(e,t,{midTurn:n=Ks,pollMs:r=xG,capMs:o=SG}={}){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 tO(e){let t=String(e||""),n=0;for(let r=0;r<64;r++){YR.lastIndex=n;let o=YR.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(`
|
|
297
|
+
`,o.index);if(i<0)break;let l=new RegExp("^"+(s?"\\t*":"")+$G(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 yb(e,t){return e.slice(t).replace(/^[\s;&|)]+/,"").replace(/"[^"]*"|'[^']*'/g,'""').split(/[;&|\n]/)[0]}function rO(e){let t=tO(e),n=t.match(EG);if(!n)return null;let r=yb(t,n.index);return IG.test(r)?null:{repo:r.match(nO)?.[1]??null,head:r.match(RG)?.[1]??null}}function oO(e){let t=tO(e),n=t.match(_G);if(!n)return null;let r=yb(t,n.index),o=yb(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("-")){MG.has(c)&&i++;continue}s=c.replace(/^["']+|["']+$/g,"")||null;break}return{repo:r.match(nO)?.[1]??null,selector:s,auto:/\s--auto\b/.test(r)}}async function NG(e,t,{exclude:n=()=>!1}={}){let r=async i=>{Fr("observer");let{stdout:c}=await XR("gh",["pr","list","--repo",e,"--author","@me","--state","all","--limit","10","--json",CG],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...i}}).catch(l=>{throw qo(l)&&Go(l),l});return JSON.parse(c||"[]")},o=i=>(i||[]).filter(c=>Date.parse(c.createdAt)>=t-vG&&!n(c)),s=await tr({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 PG(e,t){if(t)return[t];let n=[];for(let r of sO(e)){let o=await Re(r).catch(()=>null);o&&!n.includes(o)&&n.push(o)}for(let r of await Ir().catch(()=>[])){let o=await Re(r.path).catch(()=>null);o&&!n.includes(o)&&n.push(o)}return n}function sO(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 DG(e,t,n){let r=await Pi(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)||OG(c.headRefName,e.id),i=[];for(let c of await PG(e,t?.repo??null)){let l;try{l=await NG(c,n,{exclude:a})}catch{continue}for(let u of l){let d=await pt(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 aO(e){if(!e)return 0;let t=0;for(let n of qr)n.startsWith(`${e}|`)&&t++;return t}function iO(){for(let e of[...bb])e()}function cO(e,t,{delays:n=ZR,turnEnd:r}={}){let o=rO(t.command);if(!o)return null;let s=!!oO(t.command),a=`${e.id}|${t.id??t.ts??t.command}`;if(qr.has(a))return null;qr.add(a);let i=t.ts??Date.now(),c=(async()=>{try{for(let l of n){await new Promise(h=>{let g=()=>{clearTimeout(y),bb.delete(g),h()},y=setTimeout(g,l);bb.add(g)});let u=await DG(e,o,i).catch(()=>null);if(u?.settled)return null;if(!u)continue;let{slug:d,pr:p}=u,{link:w,created:m}=await ln({repo:d,number:p.number,trackId:e.id,url:p.url,headRef:p.headRefName,title:p.title,source:"observed"});return!m&&!(w?.trackId===e.id&&await Lr(d,p.number))?null:(await gb(t.box,t.agent,r),await Hr({repo:d,number:p.number,via:"observer"}).catch(()=>{}),await D({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{qr.delete(a)}})();return c.catch(()=>qr.delete(a)),c}function lO(e,t,{delays:n=ZR,turnEnd:r,openedWait:o}={}){let s=oO(t.command);if(!s)return null;let a=`merge|${e.id}|${t.id??t.ts??t.command}`;if(qr.has(a))return null;qr.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 m=sO(e);if(m.length>1&&/^\d+$/.test(String(s.selector??"")))return null;for(let h of m){let g=await Re(h).catch(()=>null);g&&!d.includes(g)&&d.push(g)}}if(l||=(await Pi(e).catch(()=>[])).filter(m=>m!==e.workspace?.branch)[0]||e.workspace?.branch,!d.length||!l)return null;c=d[0];let p=async(m,h)=>{let g=await pt(c,m.number);return g&&g.trackId!==e.id?null:(g||await ln({repo:c,number:m.number,trackId:e.id,url:m.url,headRef:m.headRefName,title:m.title,source:"merge-observed"}),await Vl(c,m.number),h&&((await V(e).catch(()=>[])).some(x=>x.type==="pr.state.changed"&&(x.payload?.change==="auto-armed"||x.payload?.change==="merged")&&x.payload?.number===m.number)||(await gb(t.box,t.agent,r),await D({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:m.number,url:m.url,title:m.title,branch:m.headRefName,repo:c}}))),m)},w=null;for(let m of n){await new Promise(E=>setTimeout(E,m));let h=[];for(let E of d)try{Fr("observer");let{stdout:P}=await XR("gh",["pr","view",String(l),"--repo",E,"--json",BG],{timeout:3e4,maxBuffer:4*1024*1024,env:{...process.env,...await tr({slug:E})}}),L=JSON.parse(P||"null");L?.number&&h.push({slug:E,pr:L})}catch(P){qo(P)&&Go(P)}let g=h.find(E=>E.pr.state==="MERGED")??(h.length===1?h[0]:null);if(!g)continue;c=g.slug;let y=g.pr;if(!y?.number)continue;if(y.state==="CLOSED")return null;if(y.state!=="MERGED"){if(w=y,s.auto)return p(y,!0);continue}let b=await pt(c,y.number);if(b&&b.trackId!==e.id)return null;b||await ln({repo:c,number:y.number,trackId:e.id,url:y.url,headRef:y.headRefName,title:y.title,source:"merge-observed"}),await gb(t.box,t.agent,r);let x=await V(e).catch(()=>[]);if(x.some(E=>E.type==="pr.state.changed"&&E.payload?.change==="merged"&&E.payload?.number===y.number))return null;let v=E=>E.some(P=>P.type==="pr.state.changed"&&P.payload?.change==="opened"&&P.payload?.number===y.number),S=0;if(!v(x)){if(rO(t.command)&&await Lr(c,y.number)){await Hr({repo:c,number:y.number,via:"observer-merge"}).catch(()=>{});let E=Date.now();S=E+1,await D({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"agent",source:"transcript",boxId:t.box??null,provider:t.agent??null,payload:{ts:E,change:"opened",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c,selfMerge:!0}})}else if((await pt(c,y.number))?.announced){let E=o?.capMs??AG,P=o?.pollMs??TG,L=Date.now()+E;for(;Date.now()<L&&(await new Promise($=>setTimeout($,P)),!v(await V(e).catch(()=>[]))););}}return await D({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(),S),change:"merged",number:y.number,url:y.url,title:y.title,branch:y.headRefName,repo:c}}),await sh(e,{repo:c,number:y.number,title:y.title,branch:y.headRefName,url:y.url}).catch(()=>{}),await Kr(c,y.number).catch(()=>{}),await Gr(c,y.number).catch(()=>{}),await Ho(c,y.number,"merged"),y}return w?p(w,!1):null}finally{qr.delete(a)}})();return i.catch(()=>qr.delete(a)),i}var XR,ZR,xG,SG,vG,AG,TG,QR,eO,EG,_G,IG,YR,$G,nO,RG,OG,MG,CG,qr,bb,BG,ih=K(()=>{be();er();_t();Jl();jn();pr();Vr();Vs();Vo();ah();XR=kG(bG),ZR=[4e3,15e3,45e3],xG=2500,SG=5*6e4;vG=15e3,AG=9e4,TG=2e3,QR=/(?:^|[;&|\n({`]\s*|\)\s*)(?:(?:then|do|else|elif|if|while|until|time)\s+)?/.source,eO=/gh\s+(?:[^\s;&|"'`$]+\s+)*?pr\s+/.source,EG=new RegExp(`${QR}${eO}create\\b`),_G=new RegExp(`${QR}${eO}merge\\b`),IG=/\s--web\b/,YR=/<<(-?)\s*(?:'([^'\n]+)'|"([^"\n]+)"|\\?([A-Za-z_][\w-]*))/g,$G=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");nO=/(?:--repo|-R)[\s=]+([\w.-]+\/[\w.-]+)/,RG=/(?:--head|-H)[\s=]+([^\s"'`;&|]+)/,OG=MR;MG=new Set(["--subject","-t","--body","-b","--body-file","-F","--match-head-commit","--author-email","-A","--repo","-R"]);CG="number,url,title,headRefName,createdAt";qr=new Set;bb=new Set;BG="number,url,title,headRefName,state"});import LG from"node:fs/promises";import xb from"node:path";import jG from"node:os";function kb(e,t){let n=new RegExp(`\\b${t}="([^"]*)"`).exec(e);return n?n[1]:null}function ch(e){let t=FG.exec(String(e||""));if(!t)return null;let[,n,r]=t,o=kb(n,"from"),s=o?o.replace(/^uds:/,""):null,a=uO(s);return{socket:s,pid:a,name:kb(n,"from-name"),mode:kb(n,"from-mode"),text:r.trim()}}function uO(e){let t=/(\d+)\.sock$/.exec(String(e||""));return t?Number(t[1]):null}function UG(){return process.env.CLAUDE_CONFIG_DIR?xb.join(process.env.CLAUDE_CONFIG_DIR,"sessions"):xb.join(jG.homedir(),".claude","sessions")}async function HG(e){let t=uO(e);if(!t)return null;try{let n=await LG.readFile(xb.join(UG(),`${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 dO(e,t){let n=await HG(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 FG,Sb=K(()=>{FG=/<cross-session-message\b([^>]*)>([\s\S]*?)<\/cross-session-message>/});function WG(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 qG(e,t,n){let r=WG(t,n);return r?D(e,{type:"track.obligations.changed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),open:r.open,since:r.since}}).catch(()=>null):null}function la(e){let t=r=>Number(r.payload?.ts??r.ts??0)||0,n={askedAt:0,closedAt:0,hookClosedAt:0,abortedAt:0};for(let r of e||[])r&&(r.type==="turn.user"||r.type==="peer.message"?n.askedAt=Math.max(n.askedAt,t(r)):r.type==="turn.agent"?(n.closedAt=Math.max(n.closedAt,t(r)),r.source==="hook"&&(n.hookClosedAt=Math.max(n.hookClosedAt,t(r)))):r.type==="turn.aborted"&&(n.abortedAt=Math.max(n.abortedAt,t(r))));return n}function hO(e){let t=la(e);return t.askedAt?t.askedAt>Math.max(t.closedAt,t.abortedAt):!1}function KG(e,{epochStartedAt:t=null}={}){let n=l=>Number(l.payload?.ts??l.ts??0)||0,r=la(e),o=null,s=null,a=null;for(let l of e||[]){if(!l)continue;let u=l.payload||{};l.type==="turn.interrupted"?(u.result==="stopped"||u.result==="stopped-late")&&u.busyAtClick!==!1&&n(l)>=(o?.at||0)&&(o={at:n(l),unsent:!!u.unsent,busyAtClick:u.busyAtClick===!0}):l.type==="turn.aborted"?n(l)>=(s?.at||0)&&(s={at:n(l),cause:u.cause||"cli-exited",agent:u.agent||l.provider||null}):l.type==="provider.error"&&n(l)>=(a?.at||0)&&(a={at:n(l),cls:u.cls||"other",provider:l.provider||null})}let i=Math.max(r.askedAt,Number(t)||0),c=[];if(o&&o.at>i&&(r.askedAt||o.busyAtClick)&&c.push({at:o.at,source:"stop",summary:o.unsent?"stopped before it started \u2014 your message is back in the composer":"you stopped the agent"}),s&&s.at>i&&c.push({at:s.at,source:`abort:${s.cause}`,summary:pO[s.cause]||pO["cli-exited"]}),a&&r.askedAt&&a.at>i&&a.at>r.closedAt){let l=GG[a.cls]||"returned an error";c.push({at:a.at,source:"provider-error",summary:`${a.provider||"the provider"} ${l} instead of finishing the turn`})}return c.length?c.reduce((l,u)=>u.at>l.at?u:l):null}function ZG(e){let t=String(e||"").split(/\r?\n/).map(a=>a.trim()).filter(Boolean),n=t[t.length-1];if(!n||/^(?:>|\||```|~~~)/.test(n))return null;let r=n.replace(/[\s*_~]+$/,"");if(!r.endsWith("?"))return null;let o=r.replace(/^(?:[-*+]|\d+[.)])\s+/,"").split(/(?<=[.?!])\s+/).filter(Boolean),s=o.pop()||"";return s.length<VG&&o.length&&(s=`${o.pop()} ${s}`),s=s.replace(/\*\*|__/g,"").trim(),s?s.length>fO?s.slice(0,fO-1)+"\u2026":s:null}function QG(e,{leadBox:t=null,epochStartedAt:n=null}={}){let r=c=>Number(c.payload?.ts??c.ts??0)||0,o=Math.max(la(e).askedAt,Number(n)||0),s=null,a=0;for(let c of e||[])if(!(!c||r(c)<=o)){if(XG(c))return null;c.type!=="turn.agent"||t&&c.boxId&&c.boxId!==t||(c.source==="hook"?a=Math.max(a,r(c)):!c.payload?.note&&String(c.payload?.text||"").trim()&&r(c)>=(s?.at||0)&&(s={at:r(c),text:c.payload.text,provider:c.provider||null}))}if(!s||s.provider==="claude"&&(a<s.at-JG||a-s.at>zG))return null;let i=ZG(s.text);return i?{at:s.at,source:"question",summary:i}:null}function eK(e,t){let n=null;for(let o of e||[]){if(o?.type!=="track.interrupted.changed")continue;let s=o.payload||{};n=s.at?{at:Number(s.at)||0,source:s.source||null}:null}let r=t?.at?{at:t.at,source:t.source||null}:null;return!r&&!n||r&&n&&r.at===n.at&&r.source===n.source?null:{at:r?.at??null,source:r?.source??null,summary:t?.summary??null}}async function tK(e,t,n){let r=eK(t,n);return r?D(e,{type:"track.interrupted.changed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),...r}}).catch(()=>null):null}async function vb(e){if(lh.has(e.id))return lh.get(e.id);let t=await V(e).catch(()=>[]),n=[];try{n=ir(t)}catch{}let r=Bp(n),o=n.filter(y=>y?.kind==="followup-offer"&&y.status==="open"),s=new Set(t.filter(y=>y.type==="prompt.answered").map(y=>y.payload?.promptId)),a=t.filter(y=>y.type==="prompt.raised"&&y.payload?.promptId&&!s.has(y.payload.promptId)),i=(e.boxes||[]).find(y=>y.name===e.leadBox),c=Array.isArray(i?.epochs)&&i.epochs.length?i.epochs[i.epochs.length-1]:null,l=KG(t,{epochStartedAt:c?.startedAt??null}),u=l||e.archivedAt?null:QG(t,{leadBox:e.leadBox,epochStartedAt:c?.startedAt??null}),d=[...r,...o,...a.map(y=>({ts:y.payload?.ts??y.ts})),...u?[{ts:u.at}]:[]],p=null;for(let y of t){if(y.type!=="track.phase.changed")continue;let b=y.payload||{};p=b.phase?{phase:b.phase,summary:b.summary??null,scope:b.scope??null,phaseId:b.phaseId??null,at:b.ts??y.ts}:null}let w=n.flatMap(y=>y?.kind==="job-dock"?y.jobs||[]:[]).filter(y=>y?.status==="running"),m=t.reduce((y,b)=>b.type==="turn.agent"?Math.max(y,b.payload?.ts??b.ts??0):y,0)||null,h=t.reduce((y,b)=>b.type==="turn.user"?Math.max(y,b.payload?.ts??b.ts??0):y,0)||null,g={openActions:d.length,openActionSince:d.length?Math.min(...d.map(y=>y.ts||Date.now())):null,phase:p,completedTurnAt:m,currentTurnAt:h,interrupted:l,question:u,runningJobs:w.length,runningJobsSince:w.length?Math.min(...w.map(y=>y.startedTs||Date.now())):null};return lh.set(e.id,g),!He(e)&&e.kind!=="setup"&&(qG(e,t,g),tK(e,t,l)),g}function mO({trackOf:e,debounceMs:t=nK,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(ou.get(s));let a=setTimeout(()=>{ou.delete(s),Promise.resolve(e(s)).then(i=>i&&!He(i)&&i.kind!=="setup"?vb(i):null).catch(i=>n.warn?.(`[obligations] fold ${s} failed: ${i?.message||i}`))},t);a.unref?.(),ou.set(s,a)};return at.on("event",r),()=>{at.off("event",r);for(let o of ou.values())clearTimeout(o);ou.clear()}}var lh,pO,GG,fO,VG,zG,JG,YG,XG,nK,ou,su=K(()=>{be();Lp();yn();lh=new Map;at.on("event",e=>{e?.trackId&&lh.delete(e.trackId)});pO={"cli-exited":"the agent exited before finishing","session-gone":"the agent's session is gone before it finished","terminal-esc":"interrupted with Esc in the terminal"},GG={rate_limit:"hit a rate limit",entitlement:"refused the request (plan / credits)",auth:"needs a login",overloaded:"was overloaded",server:"returned a server error"};fO=200,VG=24,zG=15e3,JG=5e3,YG=new Set(["pr.offered","ticket.create.offered","loop.create.offered","loop.update.offered","loop.delete.offered","followup.create.offered","planning.change.offered"]),XG=e=>YG.has(e.type)||e.type==="followup.offered"&&e.payload?.trigger==="now";nK=750,ou=new Map});function wO(e=process.env){return!!(Ue(e)&&e.BOSTRAT_PLANE_TOKEN)}async function gO(e,t,n=Ab){let r=new AbortController,o=setTimeout(()=>r.abort(),n);try{return await oK(`${Ue(t)}${e}`,{headers:sK(t),signal:r.signal})}finally{clearTimeout(o)}}async function au({env:e=process.env,force:t=!1,timeoutMs:n=Ab}={}){if(!wO(e))return{followups:[],source:"unconfigured"};if(!t&&ua&&Date.now()-ua.at<rK)return{followups:ua.followups,source:"cache"};try{let r=await gO("/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 ua={at:Date.now(),followups:s},{followups:s,source:"plane"}}catch(r){return ua?{followups:ua.followups,source:"stale",error:r?.message}:{followups:[],source:"unreachable",error:r?.message}}}async function yO(e,{env:t=process.env,timeoutMs:n=Ab}={}){if(!e)return{followup:null,source:"unconfigured"};if(!wO(t))return{followup:null,source:"unconfigured"};try{let r=await gO(`/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=ua?.followups.find(s=>s.id===e)??null;return o?{followup:o,source:"stale",error:r?.message}:{followup:null,source:"unreachable",error:r?.message}}}var rK,Ab,ua,oK,sK,bO=K(()=>{_t();rK=6e4,Ab=5e3,ua=null,oK=(...e)=>fetch(...e);sK=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`})});async function Jo(e,t){if(Tb.has(e)){let n=new Error("offer already answered (answer in flight)");throw n.code="answer-in-flight",n}Tb.add(e);try{return await t()}finally{Tb.delete(e)}}var Tb,iu=K(()=>{Tb=new Set});import{randomUUID as pa,createHash as aK}from"node:crypto";function uh(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function $O(e){for(let[t,n]of uK)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 vO(e,{at:t="",promptRequired:n=!0,standing:r=!1}={}){let o=e&&typeof e=="object"?e:{},s=fa(o.label).replace(/\s+/g," ");if(!s)throw new Error(`${t}label required (\u2264${Eb} chars, e.g. "Deploy to Pi")`);if(s.length>Eb)throw new Error(`${t}label must be \u2264${Eb} characters`);let a=fa(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")>kO)throw new Error(`${t}prompt must be \u2264${kO} bytes`);if(r){let l=$O(a);if(l)throw new Error(`${t}${l}`)}let i=o.standing==null||o.standing===""?"offerable":String(o.standing).trim().toLowerCase();if(!lK.includes(i))throw new Error(`${t}standing must be "offerable" or "never", got "${o.standing}"`);let c=fa(o.why).slice(0,EO)||null;return{label:s,prompt:a,why:c,standing:i}}function RO(e,{standing:t=!1}={}){let n=e&&typeof e=="object"?e:{},r=fa(n.trigger)||(n.ship?"now":""),o=t?iK:_O.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"?fK(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>SO)throw new Error(`items must be \u2264${SO} \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((w,m)=>vO(w,{at:`items[${m}]: `,standing:t})),c=fa(n.why).slice(0,EO)||null;let p=new Set;for(let w of i){let m=uh(w.label);if(p.has(m))throw new Error(`items must have distinct labels ("${w.label}" appears twice)`);p.add(m)}}else i=[vO(n,{promptRequired:!s,standing:t})];let l=i[0],u=c??l.why,d=t?pK(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 dK(e){return e.standing==="never"?{promotable:!1,promotableReason:"one-off"}:$O(e.prompt)?{promotable:!1,promotableReason:"specifics"}:{promotable:!0,promotableReason:null}}function pK(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 fK(e){let t=e&&typeof e=="object"?e:{},n=Array.isArray(t.actions)?t.actions.map(i=>String(i).trim().toLowerCase()):_b.slice();for(let i of n)if(!_b.includes(i))throw new Error(`ship.actions may only contain ${_b.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=fa(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=>fa(i)).filter(Boolean),a.length||(a=null)}return{actions:[...new Set(n)],rebase:r,toPr:o,base:s,repos:a}}function dh(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 OO(e){return{armId:e.armId,label:e.label,prompt:e.prompt,promptHash:IO(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",...dK(e)}}async function MO(e,t,{pull:n=au,ship:r={}}={}){let o=RO(t);if(o.ship)return{kind:"ship",...await bK(e,o,r)};if(Rb(e))throw new Error("follow-ups don't fire on a loop's run Track \u2014 report the outcome with `bostrat-loop report` instead (a ship offer via `bostrat-ship offer` is fine)");let s={id:e.id,cwd:e.cwd},a=(e.boxes||[]).find(b=>b.name===e.leadBox)||null,i={boxId:e.leadBox??null,provider:a?.agent??null},c=pa(),l=(b,x,v={})=>({ts:Date.now(),armId:pa(),trigger:o.trigger,label:b.label,prompt:b.prompt,why:b.why,standing:b.standing,groupId:c,seq:x,...o.planWhy?{planWhy:o.planWhy}:{},...v}),u={groupId:c,trigger:o.trigger,label:o.label,prompt:o.prompt,why:o.why,planWhy:o.planWhy};if(o.trigger==="now"){let b=pa(),x=[];for(let[v,S]of o.items.entries()){let E=l(S,v);await D(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:E}),x.push(E)}return await D(s,{type:"followup.offered",actor:"system",source:"orchestrator",...i,payload:{ts:Date.now(),offerId:b,trigger:"now",repo:e.workspace?.repo||null,context:{},groupId:c,why:o.planWhy,rows:x.map(OO)}}),{kind:"now",offerId:b,armId:x[0].armId,items:x.map(v=>({armId:v.armId,label:v.label,standing:v.standing})),...u}}let d=e.workspace?.repo||null,{followups:p}=await n().catch(()=>({followups:[]})),w=await V(s),m=dh(w,{trigger:o.trigger}),h=[],g=0;for(let b of o.items){let x=uh(b.label),v=p.find(L=>L.status==="active"&&L.mode!=="off"&&L.trigger===o.trigger&&(L.repo==null||L.repo===d)&&L.dedupeKey===x);if(v){h.push({label:b.label,standing:b.standing,covered:{id:v.id,label:v.label}});continue}let S=m.filter(L=>uh(L.label)===x),E=S.length?S[S.length-1].armId:null,P=l(b,g++,E?{replaces:E}:{});await D(s,{type:"followup.armed",actor:"agent",source:"cli",...i,payload:P}),h.push({armId:P.armId,label:b.label,standing:b.standing,replaces:E})}let y=h.filter(b=>b.armId);return y.length?{kind:"armed",armId:y[0].armId,replaces:y[0].replaces,items:h,...u}:{kind:"covered",covered:h[0].covered,items:h,...u}}async function CO(e,t){if(!t)throw new Error("armId required");let n={id:e.id,cwd:e.cwd},r=await V(n);if(!dh(r).some(o=>o.armId===t))throw new Error("unknown or already-settled arm");return await D(n,{type:"followup.armed.cancelled",actor:"user",source:"orchestrator",payload:{ts:Date.now(),armId:t}}),{armId:t}}async function NO(e,t,{pull:n=au}={}){if(Rb(e))throw new Error("propose from a lead Track, not a loop's run Track");let r=RO(t,{standing:!0}),o=r.repo??e.workspace?.repo??null,s={id:e.id,cwd:e.cwd};if((await V(s)).reduce((g,y)=>y.type==="followup.create.offered"?y.payload?.proposalId??g:y.type==="followup.create.answered"&&y.payload?.proposalId===g?null:g,null))throw new Error("a follow-up proposal is already waiting on the operator in this Track \u2014 one at a time");let{followups:c,source:l}=await n().catch(()=>({followups:[],source:"unreachable"}));if(l==="unreachable")throw new Error("plane unreachable \u2014 standing follow-ups live in the plane; try again shortly");let u=uh(r.label),d=c.filter(g=>g.dedupeKey===u&&g.trigger===r.trigger),p=d.find(g=>g.status==="deleted"),w=d.find(g=>g.status!=="deleted");if(w)throw new Error(`"${w.label}" (${$b[w.trigger]||w.trigger}) already exists as a standing follow-up \u2014 not re-proposed`);if(p){let g=p.deletedAt?new Date(p.deletedAt).toISOString().slice(0,10):"earlier";throw new Error(`the operator deleted "${p.label}" on ${g} \u2014 do not re-propose it`)}let m=pa(),h=(e.boxes||[]).find(g=>g.name===e.leadBox)||null;return await D(s,{type:"followup.create.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:h?.agent??null,payload:{ts:Date.now(),proposalId:m,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why,origin:"agent"}}),{proposalId:m,label:r.label,prompt:r.prompt,trigger:r.trigger,repo:o,why:r.why}}async function PO(e,t,n,{followupId:r=null}={}){if(!t)throw new Error("proposalId required");let o={id:e.id,cwd:e.cwd},s=await V(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 D(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 D(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 D(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 cu(e,t,n={},{pull:r=au}={}){if(!e||Rb(e))return null;let o={id:e.id,cwd:e.cwd},s=await V(o).catch(()=>[]),a=n.repo??e.workspace?.repo??null;if(t==="pr.merged"){let b=S=>{let E=(S?.prs||[]).filter(P=>Number.isFinite(Number(P?.number))).map(P=>`${P?.repo??S?.repo??""}#${Number(P.number)}`);return Number.isFinite(Number(S?.prNumber))&&E.push(`${S?.repo??""}#${Number(S.prNumber)}`),E},x=new Set(b(n));if(s.some(S=>S.type==="followup.offered"&&S.payload?.trigger==="pr.merged"&&b(S.payload?.context).some(E=>x.has(E))))return null}let i=dh(s,{trigger:t}),c=i.length?i[i.length-1].groupId??null:null,l=i.slice(0,xO).map(OO),u=c?i.find(b=>b.groupId===c&&b.planWhy)?.planWhy??null:null,d=[];if(t!=="now"){let{followups:b}=await r().catch(()=>({followups:[]}));d=b.filter(x=>x.status==="active"&&x.mode!=="off"&&x.trigger===t&&(x.repo==null||x.repo===a)).sort((x,v)=>{let S=E=>E.stats?.offered?(E.stats.accepted||0)/E.stats.offered:0;return S(v)-S(x)||(x.origin==="operator"?-1:0)-(v.origin==="operator"?-1:0)||(v.createdAt||0)-(x.createdAt||0)}).slice(0,cK).map(x=>({followupId:x.id,label:x.label,promptPreview:hK(x.prompt),promptHash:IO(x.prompt),origin:x.origin,repo:x.repo??null}))}let p=[...l,...d].slice(0,xO);if(!p.length)return null;let w=pa(),m={ts:Date.now(),offerId:w,trigger:t,repo:a,context:{...n,repo:a},groupId:c,why:u,rows:p},h=(e.boxes||[]).find(b=>b.name===e.leadBox)||null,g=i.find(b=>b.provider)?.provider??h?.agent??null,y=i.find(b=>b.boxId)?.boxId??e.leadBox??null;return await D(o,{type:"followup.offered",actor:"system",source:"orchestrator",boxId:y,provider:g,payload:m}),m}function mK(e,t){let n=t?.rows||[],r=new Map(n.map(s=>[da(s),null])),o=(s,a)=>{r.has(s)&&r.get(s)==null&&r.set(s,a)};for(let s of e){if(s.type!=="followup.answered"||s.payload?.offerId!==t.offerId)continue;let a=s.payload,i=[];a.armId&&i.push(`arm:${a.armId}`),a.followupId&&i.push(`fu:${a.followupId}`);for(let c of Array.isArray(a.armIds)?a.armIds:[])i.push(`arm:${c}`);for(let c of Array.isArray(a.followupIds)?a.followupIds:[])i.push(`fu:${c}`);if(i.length)for(let c of i)o(c,a.action);else for(let c of r.keys())o(c,a.action)}return r}function Ib(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 DO(e,{offerId:t,followupId:n=null,armId:r=null,promoted:o=null,all:s=!1,rows:a=null,prompt:i=null,prompts:c=null,reordered:l=!1}={},u={}){if(!t)throw new Error("offerId required");if(a!=null&&!Array.isArray(a))throw new Error("rows must be an array of row keys");if(i!=null&&typeof i!="string")throw new Error("prompt must be a string");if(c!=null&&(typeof c!="object"||Array.isArray(c)))throw new Error("prompts must be an object of row key \u2192 text");return Jo(`fu:${e.id}:${t}`,()=>yK(e,{offerId:t,followupId:n,armId:r,promoted:o,all:s===!0,rows:a,prompt:i,prompts:c,reordered:l===!0},u))}function TO(e,t){if(e==null)return null;let n=String(e).replace(/\u0000/g,"").trim();if(!n)throw new Error("an edited prompt can't be empty \u2014 Reset it or type the step");if(n.length>AO)throw new Error(`an edited prompt must be \u2264${AO} characters`);return n===String(t??"").trim()?null:n}async function BO(e,{offerId:t,armId:n,followupId:r}={}){if(!t||!n||!r)throw new Error("offerId, armId and followupId required");let o={id:e.id,cwd:e.cwd},s=await V(o),a=s.find(c=>c.type==="followup.offered"&&c.payload?.offerId===t);if(!a)throw new Error("unknown offer");if(!(a.payload.rows||[]).find(c=>c.armId===n))throw new Error("that arm is not on this card");if(s.some(c=>c.type==="followup.arm.saved"&&c.payload?.armId===n))throw new Error("that row is already saved");return await D(o,{type:"followup.arm.saved",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,armId:n,followupId:String(r)}}),{offerId:t,armId:n,followupId:String(r)}}async function yK(e,{offerId:t,followupId:n,armId:r,promoted:o,all:s,rows:a,prompt:i,prompts:c,reordered:l},u){let{sayToLead:d,unarchiveTrack:p,getFollowup:w=yO}=u,m={id:e.id,cwd:e.cwd},h=await V(m),g=h.find(I=>I.type==="followup.offered"&&I.payload?.offerId===t);if(!g)throw new Error("unknown offer");let y=g.payload.rows||[],b=mK(h,g.payload),x=wK(b,y);if(!x.length)throw new Error("offer already answered");let v=I=>D(m,{type:"followup.answered",actor:"user",source:"orchestrator",payload:{ts:Date.now(),offerId:t,...I}}),S=async()=>{if(!e.archivedAt)return!1;if(!p)throw new Error("this Track is archived");return await p(e.id,{freshSession:!0}),e={...e,archivedAt:null},!0},E=I=>{let F=h.find(W=>W.type==="followup.armed"&&W.payload?.armId===I.armId)?.payload?.prompt??I.prompt;if(!F)throw new Error("the arm's prompt is missing from the log");return F};if(s||a){let I,T=!1;if(a){let X=[...new Set(a.map(Le=>String(Le)))];if(!X.length)throw new Error("rows must name at least one item");let re=new Map(y.map(Le=>[da(Le),Le]));for(let Le of X){let ie=re.get(Le);if(!ie)throw new Error(`${Le} is not on this card`);if(!ie.armId)throw new Error("a standing follow-up runs on its own \u2014 it is not part of a batch");if(b.get(Le)!=null)throw new Error("that row is already answered")}let Te=y.filter(Le=>X.includes(da(Le)));I=l?X.map(Le=>re.get(Le)):Te,T=l&&I.some((Le,ie)=>Le!==Te[ie])}else I=x.filter(X=>X.armId);if(!I.length)throw new Error("nothing to run together \u2014 no open items from this plan remain on the card");let F=new Map;if(c){let X=new Map(I.map(re=>[da(re),re]));for(let[re,Te]of Object.entries(c)){let Le=X.get(re);if(!Le)throw new Error(`${re} is not in this batch \u2014 prompts can only edit the rows being sent`);let ie=TO(Te,E(Le));ie!=null&&F.set(re,ie)}}let W=I.map(X=>({row:X,key:da(X),prompt:F.get(da(X))??E(X)})),ce=await S();if(!d)throw new Error("sayToLead unavailable");let z=W.length===1?`${Ib(g.payload)}
|
|
298
298
|
|
|
299
299
|
${W[0].prompt}`:`${Ib(g.payload).replace(/:$/,"")} \u2014 ${W.length} steps, in order:${T?`
|
|
300
300
|
${gK}`:""}
|
|
@@ -304,33 +304,33 @@ ${X.prompt}`).join(`
|
|
|
304
304
|
|
|
305
305
|
`)}`,Ke=await d(e.id,z,{kind:"followup-go"}),Ie=pa();for(let[X,re]of W.entries())await v({action:"sent",armId:re.row.armId,label:re.row.label,batchId:Ie,...W.length>1?{order:X+1}:{},...T?{reordered:!0}:{},...F.has(re.key)?{edited:!0,prompt:re.prompt}:{},...X===0&&ce?{revived:!0}:{},source:`arm:${re.row.armId}`});return{offerId:t,action:"sent",all:!a,rows:W.map(X=>X.key),batchId:Ie,armIds:W.map(X=>X.row.armId),reordered:T,edited:W.filter(X=>F.has(X.key)).map(X=>X.key),revived:ce,remaining:x.length-W.length,queued:!!Ke?.queued}}if(!n&&!r)return await v({action:"dismiss",followupIds:x.map(I=>I.followupId).filter(Boolean),armIds:x.map(I=>I.armId).filter(Boolean)}),{offerId:t,action:"dismiss",remaining:0};let P=null,L=null,$=!1,C=n?`fu:${n}`:`arm:${r}`;if(n){if(i!=null)throw new Error("a standing follow-up's text comes from Settings \u2014 edit it there");if(!y.find(W=>W.followupId===n))throw new Error("that follow-up is not on this card");if(b.get(C)!=null)throw new Error("that row is already answered");let{followup:T,source:F}=await w(n);if(F==="unreachable")throw new Error("plane unreachable \u2014 the follow-up's current prompt can't be read; try again shortly");if(!T||T.status!=="active"){await v({action:"removed",followupId:n});let W=new Error("removed in Settings since it was offered");throw W.code="removed",W}P=T.prompt,L=T.label}else{let I=y.find(F=>F.armId===r);if(!I)throw new Error("that arm is not on this card");if(b.get(C)!=null)throw new Error("that row is already answered");P=E(I),L=I.label;let T=TO(i,P);T!=null&&(P=T,$=!0)}let U=await S();if(!d)throw new Error("sayToLead unavailable");let J=`${Ib(g.payload)}
|
|
306
306
|
|
|
307
|
-
${P}`,_=await d(e.id,J,{kind:"followup-go"});return await v({action:"sent",...n?{followupId:n}:{armId:r},label:L,...o?{promoted:String(o)}:{},...$?{edited:!0,prompt:P}:{},...U?{revived:!0}:{},source:n?`followup:${n}`:`arm:${r}`}),{offerId:t,action:"sent",followupId:n,armId:r,promoted:o,edited:$,revived:U,remaining:x.length-1,queued:!!_?.queued}}async function bK(e,t,{changedRepos:n=null,probe:r=Yf,branchOf:o=fr}={}){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(y=>y.name===e.leadBox)||null,c=e.workspace?.kind==="multi",l;if(c&&n){let y=await n(e).catch(()=>[]),b=s.repos?y.filter(x=>s.repos.includes(x.name)):y;l=b.length?b.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),w=[...d?["rebase"]:[],...s.actions].filter(y=>Ko.includes(y));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 m=pa(),
|
|
307
|
+
${P}`,_=await d(e.id,J,{kind:"followup-go"});return await v({action:"sent",...n?{followupId:n}:{armId:r},label:L,...o?{promoted:String(o)}:{},...$?{edited:!0,prompt:P}:{},...U?{revived:!0}:{},source:n?`followup:${n}`:`arm:${r}`}),{offerId:t,action:"sent",followupId:n,armId:r,promoted:o,edited:$,revived:U,remaining:x.length-1,queued:!!_?.queued}}async function bK(e,t,{changedRepos:n=null,probe:r=Yf,branchOf:o=fr}={}){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(y=>y.name===e.leadBox)||null,c=e.workspace?.kind==="multi",l;if(c&&n){let y=await n(e).catch(()=>[]),b=s.repos?y.filter(x=>s.repos.includes(x.name)):y;l=b.length?b.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),w=[...d?["rebase"]:[],...s.actions].filter(y=>Ko.includes(y));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 m=pa(),h=t.why?`${t.label} \u2014 ${t.why}`:t.label,g=Ob(await V(a).catch(()=>[]));return await D(a,{type:"pr.offered",actor:"agent",source:"cli",boxId:e.leadBox??null,provider:i?.agent??null,payload:{offerId:m,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(y=>w.includes(y)||y==="rebase"):void 0,prState:p?.prState,openPr:p?.openPr||void 0,repos:p?.repos||l,offered:p?w.filter(y=>p.available.includes(y)):w,toPr:s.toPr?{number:s.toPr}:void 0}}),{offerId:m,branch:u,offered:w,available:p?.available??null,prState:p?.prState??null,replaced:g}}function Ob(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 LO(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 jO(e,{pull:t=au}={}){let{followups:n,source:r,error:o}=await t().catch(a=>({followups:[],source:"unreachable",error:a?.message})),s=e?await V({id:e.id,cwd:e.cwd}).catch(()=>[]):[];return{followups:n,source:r,error:o,arms:e?dh(s):[]}}var Eb,kO,EO,_O,iK,$b,cK,xO,SO,lK,_b,IO,fa,uK,Rb,hK,wK,da,AO,gK,ph=K(()=>{be();ca();cb();Vo();bO();iu();Eb=60,kO=8*1024,EO=200,_O=["now","pr.merged","ship.done","pr.opened","checks.green","track.opened"],iK=_O.filter(e=>e!=="now"&&e!=="track.opened"),$b={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"},cK=3,xO=6,SO=5,lK=["offerable","never"],_b=["commit","push","pr"];IO=e=>aK("sha256").update(String(e)).digest("hex").slice(0,16),fa=e=>typeof e=="string"?e.trim():"",uK=[[/(^|[^\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"]];Rb=e=>String(e?.name||"").startsWith("\u21BB");hK=e=>String(e||"").split(`
|
|
308
308
|
`).slice(0,3).join(`
|
|
309
|
-
`).slice(0,400);wK=(e,t)=>t.filter(n=>e.get(da(n))==null);da=e=>e.armId?`arm:${e.armId}`:`fu:${e.followupId}`;AO=16*1024;gK="The operator reordered these from your suggested order \u2014 run them in the order below."});import{randomUUID as kK}from"node:crypto";function lu(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function FO(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function UO(e){return`job|${e.box}|id:${e.id}`}function HO(e){return`jobstop|${e.box}|id:${e.id}`}async function hh(e){return Mb.has(e.id)?Mb.get(e.id):(fh.has(e.id)||fh.set(e.id,V(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(lu({role:o,sourceId:r.payload.sourceId})),n.keys.add(lu({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(lu({role:"user",sourceId:r.payload.sourceId})),n.keys.add(lu({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(FO({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==="turn.aborted"&&r.payload?.cause==="terminal-esc"?n.keys.add(WO({box:r.boxId,ts:r.payload.ts})):r.type==="job.started"&&r.payload?.id?n.keys.add(UO({id:r.payload.id,box:r.boxId})):r.type==="job.stopped"&&r.payload?.id&&n.keys.add(HO({id:r.payload.id,box:r.boxId}));return Mb.set(e.id,n),n}).finally(()=>fh.delete(e.id))),fh.get(e.id))}function WO(e){return`esc|${e.box}|${e.ts}`}async function qO(e,t){try{if(!t?.length)return;let n=(await hh(e)).keys,r=null;for(let o of t){if(!o||o.ts==null||!o.box)continue;let s=WO(o);if(n.has(s)||(n.add(s),Date.now()-o.ts>xK)||du(e.id)||(r??=await V(e).catch(()=>[]),r.some(c=>c.type==="turn.interrupted"&&Math.abs((c.payload?.ts??c.ts??0)-o.ts)<SK)))continue;let i=la(r);await D(e,{type:"turn.aborted",actor:"user",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{ts:o.ts,cause:"terminal-esc",turnTs:i.askedAt||null,box:o.box,agent:o.agent||null}}),r=null}}catch{}}async function GO(e,t){let n=new Set;try{let r=(await hh(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=lu(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?ch(o.text):null;if(a){await D(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 dO(a,uu),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=rT(o);if(i){await D(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}}),Js(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 D(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=kR(o.text);if(c&&Ob(await V(e).catch(()=>[])))continue;if(c){let l=vR(c),u;if(e.workspace?.kind==="multi"){let m=await ha(e).catch(()=>[]);u=m.length?m.map(
|
|
309
|
+
`).slice(0,400);wK=(e,t)=>t.filter(n=>e.get(da(n))==null);da=e=>e.armId?`arm:${e.armId}`:`fu:${e.followupId}`;AO=16*1024;gK="The operator reordered these from your suggested order \u2014 run them in the order below."});import{randomUUID as kK}from"node:crypto";function lu(e){return e.sourceId?`${e.role}|id:${e.sourceId}`:`${e.role}|${e.ts??"?"}|${String(e.text||"").slice(0,40)}`}function FO(e){return e.id?`cmd|${e.box}|id:${e.id}`:`cmd|${e.box}|${e.ts??"?"}|${String(e.command||"").slice(0,40)}`}function UO(e){return`job|${e.box}|id:${e.id}`}function HO(e){return`jobstop|${e.box}|id:${e.id}`}async function hh(e){return Mb.has(e.id)?Mb.get(e.id):(fh.has(e.id)||fh.set(e.id,V(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(lu({role:o,sourceId:r.payload.sourceId})),n.keys.add(lu({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(lu({role:"user",sourceId:r.payload.sourceId})),n.keys.add(lu({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(FO({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==="turn.aborted"&&r.payload?.cause==="terminal-esc"?n.keys.add(WO({box:r.boxId,ts:r.payload.ts})):r.type==="job.started"&&r.payload?.id?n.keys.add(UO({id:r.payload.id,box:r.boxId})):r.type==="job.stopped"&&r.payload?.id&&n.keys.add(HO({id:r.payload.id,box:r.boxId}));return Mb.set(e.id,n),n}).finally(()=>fh.delete(e.id))),fh.get(e.id))}function WO(e){return`esc|${e.box}|${e.ts}`}async function qO(e,t){try{if(!t?.length)return;let n=(await hh(e)).keys,r=null;for(let o of t){if(!o||o.ts==null||!o.box)continue;let s=WO(o);if(n.has(s)||(n.add(s),Date.now()-o.ts>xK)||du(e.id)||(r??=await V(e).catch(()=>[]),r.some(c=>c.type==="turn.interrupted"&&Math.abs((c.payload?.ts??c.ts??0)-o.ts)<SK)))continue;let i=la(r);await D(e,{type:"turn.aborted",actor:"user",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{ts:o.ts,cause:"terminal-esc",turnTs:i.askedAt||null,box:o.box,agent:o.agent||null}}),r=null}}catch{}}async function GO(e,t){let n=new Set;try{let r=(await hh(e)).keys;for(let o of t||[]){if(!o||o.ts==null||!String(o.text||"").trim()&&!o.images?.length)continue;let s=lu(o);if(r.has(s))continue;r.add(s);let a=o.role==="user"?ch(o.text):null;if(a){await D(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 dO(a,uu),boxRole:o.boxRole,sourceId:o.sourceId||void 0}});continue}let i=rT(o);if(i){await D(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}}),Js(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 D(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=kR(o.text);if(c&&Ob(await V(e).catch(()=>[])))continue;if(c){let l=vR(c),u;if(e.workspace?.kind==="multi"){let m=await ha(e).catch(()=>[]);u=m.length?m.map(h=>({name:h.name,slug:h.repo??null})):void 0}let d=(e.workspace?.kind==="multi"?null:await fr(e.cwd).catch(()=>null))||e.workspace.branch,p=await Yf(e,{branch:d,rebase:l}).catch(()=>null),w=p?null:SR(c);if(p&&p.available.length===0)continue;await D(e,{type:"pr.offered",actor:"agent",source:"transcript",boxId:o.box,provider:o.agent||null,payload:{offerId:kK(),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||w?.offered||void 0,toPr:w?.toPr||void 0}})}}}}catch{}return{agentTurnBoxes:n}}async function KO(e,t){try{let n=await hh(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=FO(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 D(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}}),cO(e,o),lO(e,o)}}catch{}}async function VO(e,t){try{let n=await hh(e),r=[...t||[]].filter(o=>o&&o.id).sort((o,s)=>(o.ts||0)-(s.ts||0));for(let o of r){let s=UO(o);if(n.keys.has(s)||(n.keys.add(s),await D(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=HO(o);n.keys.has(a)||(n.keys.add(a),await D(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 Mb,fh,xK,SK,zO=K(()=>{be();ca();cb();ih();Vo();Sb();Vr();su();bp();Rl();ph();Mb=new Map,fh=new Map;xK=60*6e4,SK=6e4});function vK(e){let t=[],n=null;for(let r of String(e||"").split(`
|
|
310
310
|
`)){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 AK(e,t){let n=`${e.id}:${t.name}`;if(!Cb.has(n)){let r=await V(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);Cb.set(n,o)}return Cb.get(n)}async function JO(e,t){try{if(t?.agent!=="codex"||!t.cwd)return;let n=await Ns(t.cwd,t.pinned?t.sessionId:null);if(!n)return;let r=await AK(e,t),o=vK(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 D(e,{type:"cost.recorded",actor:"agent",source:"transcript",boxId:t.name,provider:"codex",payload:{usd:lr(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 D(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 Cb,YO=K(()=>{be();Ds();Mn();Nr();Cb=new Map});import mh from"node:fs";import Pb from"node:path";import TK from"node:os";async function IK({sinceMs:e,cookie:t,fetchImpl:n=fetch}){let r=[];for(let o=1;o<=20;o++){let s=await n(_K,{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:XO})});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<XO)break}return r}function $K(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 QO(){try{return JSON.parse(mh.readFileSync(wh(),"utf8"))}catch{return{sinceMs:0,seen:[]}}}function OK(e){try{mh.mkdirSync(Pb.dirname(wh()),{recursive:!0});let t=wh()+".tmp";mh.writeFileSync(t,JSON.stringify(e)),mh.renameSync(t,wh())}catch{}}async function CK({fetchImpl:e,now:t=Date.now()}={}){if(Yo.rows&&t-Yo.at<RK)return Yo.rows;let n=process.env.BOSTRAT_CURSOR_USAGE_COOKIE;if(!n)return null;let r=QO(),o=Math.max(r.sinceMs-6e4,t-24*36e5);try{let s=await IK({sinceMs:o,cookie:n,fetchImpl:e});Yo={at:t,rows:s.map($K).filter(Boolean),error:null}}catch(s){Yo={at:t,rows:null,error:String(s?.message||s)}}return Yo.rows}async function NK(e,t){let n=`${e.id}:${t.name}`;if(!Nb.has(n)){let r=await V(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);Nb.set(n,o)}return Nb.get(n)}async function eM(e,t,{fetchImpl:n}={}){try{if(t?.agent!=="cursor"||!t.cwd||!ZO())return;let r=await CK({fetchImpl:n});if(!r||!r.length)return;let o=await VE(t.cwd,t.pinned?t.sessionId:null);if(!o?.chatId)return;let s=await NK(e,t),a=QO(),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=lr(u,d,l.ts??void 0)),!p&&l.chargedCents!=null&&(p=l.chargedCents/100),await D(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}})}OK({sinceMs:c,seen:[...i].slice(-MK)})}catch{}}var EK,ZO,_K,XO,RK,Yo,wh,MK,Db,Nb,Bb=K(()=>{be();Pg();Nr();EK=process.env.BOSTRAT_STATE_DIR||Pb.join(process.env.HOME||TK.tmpdir(),".bostrat"),ZO=(e=process.env)=>!!e.BOSTRAT_CURSOR_USAGE_COOKIE,_K="https://cursor.com/api/dashboard/get-filtered-usage-events",XO=100;RK=5*6e4,Yo={at:0,rows:null,error:null},wh=()=>Pb.join(EK,"cursor-usage.json");MK=5e3;Db=()=>({enabled:ZO(),lastPollAt:Yo.at||null,error:Yo.error}),Nb=new Map});import{randomUUID as PK,createHmac as DK}from"node:crypto";function nM(e){jb=typeof e=="string"&&e?e:null}function BK(e){if(!jb)return null;let t=Oe(e);return t?DK("sha256",Buffer.from(jb,"base64url")).update(t,"utf8").digest("hex").slice(0,16):null}function sM(){let e={};for(let t of oM)e[String(t)]=0;return e.inf=0,{buckets:e,sumMs:0,count:0}}function tM(e,t){let n=Math.max(0,Number(t)||0);for(let r of oM)n<=r&&(e.buckets[String(r)]+=1);e.buckets.inf+=1,e.sumMs+=n,e.count+=1}function aM(){let e={};for(let t of rM)e[t]=0;return e}function jK(){hr={total:new Map,holds:aM(),queueWaitMs:sM(),readyWaitMs:new Map,verify:new Map,retries:new Map}}function iM({queueDepth:e=0,queueOldestAgeMs:t=0}={}){let n=hr;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 pu({kind:e=null,producer:t=null,orchestration:n=!1}={}){return n?`orchestration:${e||"orchestration"}`:e?`scripted:${e}`:LK.has(t)?t:"composer"}function fu({text:e="",producer:t="composer",kind:n=null,provider:r=null,attachments:o=0,now:s=Date.now}={}){let a=s();return{id:PK(),producer:t,kind:n||null,provider:r||null,textBytes:Buffer.byteLength(String(e||""),"utf8"),textHmac16:BK(e),attachments:Number(o)||0,paste:null,t0:a,queuedAt:null,dequeuedAt:null,holds:aM(),requeued:0,readyWaitMs:null,readyOutcome:null,verify:null,settled:!1,outcome:null}}async function hu(e,t,{position:n=null,reason:r="busy"}={}){!t||!e||(t.queuedAt=Date.now(),await D(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 cM(e,t){rM.includes(t)&&(e?.holds&&(e.holds[t]+=1),hr.holds[t]+=1)}function mu(e,{ms:t,outcome:n}){e&&(e.readyWaitMs=Math.max(0,Number(t)||0),e.readyOutcome=n||null)}function FK(e){let t=e?.boxes?.find?.(n=>n.name===e.leadBox);return typeof t?.cliVersion=="string"&&t.cliVersion?t.cliVersion:null}async function Un(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(Lb(hr.total,`${s}|${t.producer}|${n}`),a&&tM(hr.queueWaitMs,i),t.readyWaitMs!=null){let u=`${s}|${t.readyOutcome||"unknown"}`;hr.readyWaitMs.has(u)||hr.readyWaitMs.set(u,sM()),tM(hr.readyWaitMs.get(u),t.readyWaitMs)}let c=FK(e);t.verify?.verdict&&(Lb(hr.verify,`${s}|${t.verify.verdict}|${c||""}`),t.verify.retries&&Lb(hr.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 D(e,{type:"delivery.settled",actor:"system",source:"orchestrator",boxId:e.leadBox??null,provider:t.provider,payload:l}).catch(()=>{}),l}function Li(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 jb,rM,oM,LK,hr,Lb,Fb=K(()=>{be();ri();jb=null;rM=["busy","prompt","handoff","noSession","cap","grace"],oM=[500,2e3,1e4,6e4,6e5],LK=new Set(["composer","voice","loop"]);hr=null;jK();Lb=(e,t,n=1)=>e.set(t,(e.get(t)||0)+n)});import yu from"node:fs/promises";import Xt from"node:path";import UK from"node:os";import HK from"node:net";import{randomUUID as WK}from"node:crypto";import{execFile as qK}from"node:child_process";import{promisify as GK}from"node:util";function ZK(e){for(let t of Vb(e))if(!hM.test(t))return t;return null}function mM(e){let t=Vb(e),n=t.indexOf("--");return n===-1?t:t.slice(0,n)}function QK(e,t){let n=mM(t);for(let r=0;r<n.length;r++){let o=/^--prefix=(.+)$/.exec(n[r]);if(o)return Xt.resolve(e,o[1]);if(n[r]==="--prefix"&&n[r+1])return Xt.resolve(e,n[r+1])}return e}function tV(e){let t=!1,n=!1;for(let r of Vb(e)){if(!t){if(hM.test(r))continue;t=!0;continue}if(r.startsWith("-")){let o=r.indexOf("="),s=o===-1?null:r.slice(o+1);if(s&&Ub(s))return`serves the filesystem root ("${s}")`;n=o===-1;continue}if(n){if(n=!1,Ub(r))return`serves the filesystem root ("${r}")`;continue}if(Ub(r))return`serves the filesystem root ("${r}")`;if(eV(r))return`serves a path that escapes the workspace ("${r}")`}return null}async function rV(e,t){if(Xt.resolve(e)===Xt.resolve(t))return!0;let[n,r]=await Promise.all([gh(e),gh(t)]);return n===r}async function oV(e){let n=(await yu.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 wM(Xt.join(e,o.name,qb))?`./${o.name}`:null))).filter(Boolean)}async function sV(e,t){let[n,r]=await Promise.all([gh(e),gh(t)]),o=Xt.relative(n,r);if(o&&(o.startsWith("..")||Xt.isAbsolute(o)))throw wu(`serve directory escapes the Track workspace: ${t}`)}async function aV(e,t){let n=tV(t);if(n)throw wu(`refusing this view: the command ${n} \u2014 serve a build dir, not the filesystem root`);if(!await nV(e))throw wu(`serve directory does not exist: ${e}`);let r=ZK(t);if(!r)return;if(!r.includes("/")&&!await _A(r,{loginShell:!0,failOpen:!0}))throw wu(`\`${r}\` is not on the box's PATH \u2014 install it in the box first`);if(JK.test(t)||YK.has(r)||!zK.has(r)||!mM(t).includes("run")||XK.test(t))return;let o=QK(e,t);if(await wM(Xt.join(o,qb)))return;let s=await oV(o),a=s.length?` \u2014 found one in ${s.join(", ")}; run bostrat-view from there`:"";throw wu(`no ${qb} in ${o}${a}`)}async function Yr(){return Hn||(Hb||=(async()=>{try{Hn=JSON.parse(await yu.readFile(fM,"utf8"))}catch{Hn={views:[],adoptWatermarks:{}}}finally{Hb=null}return Hn.views||=[],Hn.adoptWatermarks||={},Hn})(),Hb)}async function wr(){await dt(fM,Hn)}function Jr(e,t,n={}){return D({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 Jb(e){return gu.get(e)||null}function yM(e,{name:t,box:n}={}){let r=gu.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 gu.set(e,o),o}function Gb(e,t){let n=gu.get(e);n&&!n.finishedAt&&!n.viewId&&(n.viewId=t,n.step="booting")}function yh(e,{error:t=null}={}){let n=gu.get(e);return!n||n.finishedAt?null:(n.finishedAt=Date.now(),t&&(n.error=t),n)}function bM(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 Kb(e){return String(e||"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40).replace(/-+$/g,"")||"view"}function iV(e,t){let n=Kb(t),r=new Set(e.views.map(o=>o.slug));if(!r.has(n)&&!dM.has(n))return n;for(let o=2;;o++){let s=`${n}-${o}`;if(!r.has(s)&&!dM.has(s))return s}}function bu(e,{timeoutMs:t=1200}={}){return new Promise(n=>{let r=HK.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 Yb(e){if(process.platform!=="darwin"){await mr("fuser",["-k",`${e}/tcp`]).catch(()=>{});return}let t="";try{({stdout:t}=await mr("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 kM(e=process.env){return new Set([Number(e.PORT)||3362,Number(e.BOSTRAT_TLS_PORT)||3443])}async function cV(e,t){let n=new Set(e.views.map(o=>o.port)),r=kM();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=lM;o<=uM;o++)if(!(n.has(o)||r.has(o))&&!await bu(o,{timeoutMs:250}))return o;throw new Error(`no free view port in ${lM}-${uM}`)}async function lV(e){try{let{stdout:t}=await mr(oe,se("list-sessions","-F","#{session_name}"));return t.split(`
|
|
311
311
|
`).some(n=>n.trim()===ji(e))}catch{return!1}}async function ku(e){try{await mr(oe,se("kill-session","-t",ji(e)))}catch{}}async function Xb(e){if(!await rl())throw new Error("host tmux server not running and auto-start failed \u2014 cannot spawn a view server");await ol();let t=ji(e.slug),n=e.serveCwd??e.cwd,r=Xt.dirname(process.execPath);await mr(oe,se("new-session","-d","-s",t,"-c",n)),await mr(oe,se("send-keys","-t",t,"-l",`export PORT=${e.port} PATH="${r}:$PATH"`)),await mr(oe,se("send-keys","-t",t,"Enter")),await mr(oe,se("send-keys","-t",t,"-l",e.cmd)),await mr(oe,se("send-keys","-t",t,"Enter"))}async function pM(e,t=12){try{let{stdout:n}=await mr(oe,se("capture-pane","-t",ji(e),"-p"));return String(n||"").trimEnd().split(`
|
|
312
312
|
`).filter(Boolean).slice(-t).join(`
|
|
313
|
-
`)}catch{return""}}async function dV(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await lV(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await pM(e.slug)||"server exited before listening"),zr.delete(e.id),await Jr(e,e.state,e.error?{error:e.error}:{}),!0}if(await bu(e.port))return zr.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await Jr(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>uV?(e.state="error",e.error=await pM(e.slug)||"never started listening",await Jr(e,"error",{error:e.error}),!0):!1;let o=(zr.get(e.id)||0)+1;return zr.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function bh(){if(!Wb){Wb=!0;try{let e=await Yr(),t=!1;for(let n of e.views)await dV(n)&&(t=!0);t&&await wr()}finally{Wb=!1}}}async function kh({trackId:e}={}){await bh();let t=await Yr();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function xM(e){let n=(await Yr()).views.find(r=>r.id===e);return n?{...n}:null}function Zb(e){return Hn&&Hn.views.find(t=>t.slug===e)||null}function Qb(e,t=Date.now()){let n=Hn?.views.find(r=>r.id===e);n&&(n.lastAccessAt=t)}async function ek({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=Xt.resolve(r,o??"."),d=i==="detected"?null:async()=>{await sV(r,u),await aV(u,n)},p=await Yr();if(i!=="detected"){let f=Kb(t),g=String(n).trim(),y=p.views.find(b=>b.trackId===e&&(b.slug===f||Kb(b.name)===f||b.cmd===g&&Xt.resolve(b.serveCwd??b.cwd)===u));if(y)return pV(p,y,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:d})}if(d&&await d(),p.views.filter(f=>f.state==="live"||f.state==="starting").length>=Xo)throw new Error(`view cap reached (${Xo} live) \u2014 stop one first`);let m={id:WK().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:iV(p,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await cV(p,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await Xb(m),p.views.push(m),await wr(),await Jr(m,"created",{origin:i}),Gb(e,m.id),i==="detected"&&await bu(m.port)&&(m.state="live",m.lastHealthyAt=Date.now(),await wr(),await Jr(m,"live")),{...m}}async function pV(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 rV(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await bu(t.port))return t.lastAccessAt=Date.now(),await wr(),Gb(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>=Xo)throw new Error(`view cap reached (${Xo} live) \u2014 stop one first`);return t.origin==="detected"?(await Yb(t.port),t.origin="agent"):await ku(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.stoppedReason=null,t.createdAt=Date.now(),zr.delete(t.id),await Xb(t),await wr(),await Jr(t,"created",{restarted:!0,reused:!0}),Gb(t.trackId,t.id),{...t,reused:!0}}async function tk(e,{reason:t=null,idleMs:n=null}={}){let o=(await Yr()).views.find(s=>s.id===e);if(!o)throw new Error("view not found");return o.origin==="detected"?await Yb(o.port):await ku(o.slug),o.state!=="stopped"&&(o.state="stopped",o.stoppedReason=t,zr.delete(o.id),await wr(),await Jr(o,"stopped",t?{reason:t,...n?{idleMs:n}:{}}:{})),{...o}}async function SM(e){let t=await Yr(),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>=Xo)throw new Error(`view cap reached (${Xo} live) \u2014 stop one first`);return await ku(n.slug),n.state="starting",n.error=null,n.stoppedReason=null,n.createdAt=Date.now(),zr.delete(n.id),await Xb(n),await wr(),await Jr(n,"created",{restarted:!0}),{...n}}async function vM(e){let t=await Yr(),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 Yb(r.port):await ku(r.slug),t.views.splice(n,1),zr.delete(r.id),await wr(),await Jr(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function nk(e){let t=await Yr(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await ku(r.slug),zr.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await wr()),n.length}async function AM(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await Yr(),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 wr()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(fV)){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(!kM().has(c)&&!n.views.some(l=>l.port===c)&&await bu(c))try{i.push(await ek({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 mr,KK,fM,lM,uM,Xo,VK,ji,dM,wu,zK,qb,JK,YK,XK,Vb,hM,Ub,eV,nV,wM,gh,Hn,Hb,gu,zb,gM,zr,uV,Wb,fV,xh=K(()=>{kt();be();rr();mr=GK(qK),KK=process.env.BOSTRAT_STATE_DIR||Xt.join(process.env.HOME||UK.tmpdir(),".bostrat"),fM=Xt.join(KK,"views.json"),[lM,uM]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),Xo=Number(process.env.BOSTRAT_VIEW_MAX)||3,VK="bostrat-view-",ji=e=>`${VK}${e}`,dM=new Set(["bostrat","www","api","views","app"]),wu=e=>Object.assign(new Error(e),{status:400}),zK=new Set(["npm","pnpm","yarn","bun"]),qb="package.json",JK=/[|;&`]|\$\(/,YK=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),XK=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,Vb=e=>String(e).trim().split(/\s+/).filter(Boolean),hM=/^[A-Za-z_][A-Za-z0-9_]*=/;Ub=e=>e==="/",eV=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");nV=e=>yu.stat(e).then(t=>t.isDirectory(),()=>!1),wM=e=>yu.stat(e).then(t=>t.isFile(),()=>!1),gh=e=>yu.realpath(e).catch(()=>Xt.resolve(e));Hn=null,Hb=null;gu=new Map,zb=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,gM=12e3;zr=new Map,uV=12e4;Wb=!1;fV=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});import{execFile as hV}from"node:child_process";import{promisify as mV}from"node:util";function yV(e){return rk(e?.toPr?.number??e?.openPr?.number)}function rk(e){if(e==null||e==="")return null;let t=Number(e);return Number.isFinite(t)&&t>0?t:null}function bV(e){return Array.isArray(e?.actions)?e.actions.includes("push")||e.actions.includes("pr"):e?.action==="push"||e?.action==="pr"}function Zo(e,t=Date.now()){let n=null,r=new Map,o=new Set;for(let s of e||[]){let a=s.payload?.ts??s.ts;if(s.type==="pr.state.changed"&&s.payload?.sha&&s.payload?.number!=null&&o.add(`${Number(s.payload.number)}:${s.payload.sha}`),s.type==="pr.offered"){s.payload?.offerId&&r.set(s.payload.offerId,s.payload);continue}if(s.type==="pr.offer.answered"){let i=s.payload||{},c=r.get(i.offerId)||null,l=yV(c),u=Array.isArray(i.actions)&&i.actions.includes("rebase"),d=c?.base??null;i.action==="pr"?n={ts:a,offerId:i.offerId??null,box:s.boxId??null,offerType:"offer",toPr:l,base:d,rebase:u}:i.action!=="dismiss"&&i.action!=="pr-exists"&&l!=null&&bV(i)?n={ts:a,offerId:i.offerId??null,box:s.boxId??null,offerType:"offer",toPr:l,base:d,rebase:u}:n=null}else if(s.type==="pr.exists.answered"){let i=s.payload||{};n=i.choice==="push"?{ts:a,offerId:i.offerId??null,box:s.boxId??null,offerType:"exists",toPr:rk(i.number),base:null,rebase:Array.isArray(i.actions)&&i.actions.includes("rebase")}:null}else if(s.type==="pr.update.reported"){let i=s.payload||{},c=rk(i.number);!(n!=null&&n.offerType!=="report"&&(n.toPr==null||n.toPr===c))&&c!=null&&!(i.sha&&o.has(`${c}:${i.sha}`))&&(n={ts:a,offerId:null,box:s.boxId??null,offerType:"report",toPr:c,base:i.base??null,rebase:i.rebased===!0})}else s.type==="pr.state.changed"&&(s.payload?.change==="opened"||s.payload?.change==="pushed")&&n!=null&&a>=n.ts&&(n=null)}return n!=null&&t-n.ts>ok?null:n}function kV(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function vh(e,{bypassThrottle:t=!1}={}){let n=e?.workspace?.branch;if(!n)return;let r;try{r=await V(e)}catch{return}let o=Zo(r);if(o==null)return;let s=(e.boxes||[]).find(p=>p.name===e.leadBox);if(await Ks(e.leadBox,s?.agent).catch(()=>!1))return;let a=Date.now();if(!t&&a<(xu.get(e.id)||0))return;xu.set(e.id,a+TM);let i;try{i=await kn(e.cwd,{caller:"reconcile"})}catch{return}let c=await Pi(e).catch(()=>[n]),l=o.toPr!=null&&(i||[]).find(p=>Number(p.number)===o.toPr&&c.includes(p.headRefName))||(i||[]).find(p=>c.includes(p.headRefName));if(!l)return;let u=l.headRefName||n,d=await Re(e.cwd).catch(()=>null);if(d){let{link:p,created:w}=await ln({repo:d,number:l.number,trackId:e.id,url:l.url,headRef:l.headRefName||n,title:l.title,source:"reconciled"});if(!w&&!(p?.trackId===e.id&&await Lr(d,l.number))){if(!kV(p,o))return;let m=await SV(e);if(m&&l.headSha&&m!==l.headSha){let g=Math.min(gV,(Sh.get(e.id)||TM)*2);Sh.set(e.id,g),xu.set(e.id,a+g);return}let f=await V(e).catch(()=>null);if(f&&Zo(f)==null)return;await D(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:vV(o,l,{branch:u,repo:d})}),xu.delete(e.id),Sh.delete(e.id);return}}await Hr({repo:d,number:l.number,via:"reconcile"}).catch(()=>{}),await D(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:xV(l,{branch:u,repo:d})}).catch(()=>{}),xu.delete(e.id),Sh.delete(e.id)}function xV(e,{branch:t=null,repo:n=null,now:r=Date.now()}={}){return{ts:r,change:"opened",number:e.number,url:e.url,title:e.title,branch:e.headRefName||t,...n?{repo:n}:{}}}async function SV(e){try{let{stdout:t}=await wV("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 vV(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:t.headRefName||n,...r?{repo:r}:{},...t.headSha?{sha:t.headSha}:{},via:e?.offerType==="report"?"lead":"ship",...e?.rebase?{rebased:!0}:{},...e?.base?{base:e.base}:{}}}var wV,TM,xu,gV,Sh,ok,Fi=K(()=>{be();pr();er();jn();Vs();Vo();wV=mV(hV),TM=6e3,xu=new Map,gV=5*6e4,Sh=new Map,ok=30*6e4});import sk from"node:os";import{execFile as AV}from"node:child_process";import{promisify as TV}from"node:util";async function Ah(){if(process.platform!=="darwin")return sk.freemem();try{let{stdout:e}=await EV("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:sk.freemem()}catch{return sk.freemem()}}var EV,ak=K(()=>{EV=TV(AV)});import ut from"node:fs/promises";import ft from"node:path";import $M from"node:os";import{randomUUID as _V}from"node:crypto";import{execFile as IV}from"node:child_process";import{promisify as $V}from"node:util";import{chromium as RV}from"playwright-core";async function br(){return ma||(ik||=(async()=>{try{ma=JSON.parse(await ut.readFile(OM,"utf8"))}catch{ma={mocks:[]}}finally{ik=null}return ma.mocks||=[],ma})(),ik)}async function Sn(){await dt(OM,ma)}function PM(e,t){yr(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&yr(e,t.v,"png")}function Ft(e,t,n={}){return D({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 vn(e,t){let n=vu(e.cwd);return{html:ft.join(n,`${e.id}.v${t}.html`),png:ft.join(n,`${e.id}.v${t}.png`)}}function Su(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?ft.join(e.cwd,r):null}function Wn(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 uk(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function Th(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(BV)}function LV(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 jV(e){let t=Buffer.alloc(24),n=await ut.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function FV({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 UV(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((m,f)=>{r.onload=m,r.onerror=()=>f(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,w=-1;for(let m=0;m<s;m++)for(let f=m*o*4,g=0;g<o;g++,f+=4)Math.abs(c[f]-l[0])+Math.abs(c[f+1]-l[1])+Math.abs(c[f+2]-l[2])>24&&(g<u&&(u=g),g>p&&(p=g),m<d&&(d=m),w=m);return p<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:d,right:p,bottom:w}}},t.toString("base64"))}async function HV(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 WV({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await RV.launch({executablePath:MM,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new un("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:Ui})).newPage();a.setDefaultTimeout(Hi),await a.goto(`file://${e}`,{waitUntil:"load",timeout:Hi}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:Hi});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await UV(a,i),u=l&&FV({...l,pad:CV*Ui,align:Ui});u&&(i=await HV(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<CM)throw new un(`capture produced a ${i.length}-byte image`);let c=uk(i);if(!c)throw new un("output is not a PNG");return await ut.writeFile(t,i),{width:Math.round(c.width/Ui),height:Math.round(c.height/Ui),dpr:Ui,renderMs:Date.now()-r}}catch(s){throw s instanceof un?s:new un(/timeout/i.test(s?.message||"")?`render timed out after ${Hi}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function IM({htmlPath:e,outPath:t,width:n}){let r=await ut.mkdtemp(ft.join($M.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await lk(EM,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:Hi,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new un(`firefox not found (${EM})`,""):new un(c?.killed?`render timed out after ${Hi}ms`:"firefox exited non-zero",s)}let a=await ut.stat(t).catch(()=>null);if(!a||a.size<CM)throw new un(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=uk(await jV(t));if(!i)throw new un("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await ut.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function qV(e){if(OV==="firefox")return IM(e);try{return await WV(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await IM(e)}catch(n){throw/not found/.test(n?.message||"")?new un(`no browser installed \u2014 chromium missing at ${MM} 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 DM(e){return ck=ck.then(e,e),ck}async function BM(e,t){let n=await br(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Sn(),await Ft(r,"rendering",{version:t});try{let o=await Ah();if(o<NV)throw new un(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=vn(r,t),a=await GV({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await ut.rm(s.png,{force:!0}).catch(()=>{});return}dk(r,{v:t,source:"html",htmlRel:ft.relative(r.cwd,s.html),pngRel:ft.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Sn(),await Ft(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),gr(r),yr(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Sn(),await Ft(r,"error",{version:t,error:r.error}),gr(r)}}}function dk(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 KV({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?MV:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function Au({trackId:e,group:t}={}){let n=await br(),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 Xr(e){let n=(await br()).mocks.find(r=>r.id===e);return n?{...n}:null}function LM({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&&!Th(t))throw new Error("image must be a PNG");if(n){let o=LV(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>_M)throw new Error(`video must be ${_M/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function jM({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=KV({trackId:e,name:t,cwd:s,width:a}),p=typeof n=="string"&&n.trim(),w=LM({html:n,image:r,video:o}),m=await br(),f={id:_V().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 ut.mkdir(vu(s),{recursive:!0}),m.mocks.push(f),p?(await ut.writeFile(vn(f,1).html,n),await Sn(),await Ft(f,"created"),gr(f),yr(f,1,"html"),DM(()=>BM(f.id,1))):o?(await UM(f,1,o,w),await Sn(),await Ft(f,"created"),await Ft(f,"ready",{version:1,width:f.width,height:f.height,dpr:f.dpr,durationS:f.versions[0]?.durationS??null}),gr(f),PM(f,f.versions[0])):(await HM(f,1,r),await Sn(),await Ft(f,"created"),await Ft(f,"ready",{version:1,width:f.width,height:f.height,dpr:f.dpr}),gr(f),yr(f,1,"png")),{...f}}async function FM(e,{html:t,image:n,video:r,width:o}={}){let a=(await br()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=LM({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 ut.mkdir(vu(a.cwd),{recursive:!0}),i?(a.state="queued",await ut.writeFile(vn(a,l).html,t),await Sn(),await Ft(a,"updated",{version:l}),gr(a),yr(a,l,"html"),DM(()=>BM(a.id,l))):r?(await UM(a,l,r,c),await Sn(),await Ft(a,"updated",{version:l}),await Ft(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:Wn(a)?.durationS??null}),gr(a),PM(a,a.versions.find(u=>u.v===l))):(await HM(a,l,n),await Sn(),await Ft(a,"updated",{version:l}),await Ft(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),gr(a),yr(a,l,"png")),{...a}}async function VV(e){try{let{stdout:t}=await lk(PV,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:NM,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 zV(e,t){try{await lk(DV,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:NM,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await ut.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function UM(e,t,n,r){let o=vu(e.cwd),s=ft.join(o,`${e.id}.v${t}.${r.ext}`),a=ft.join(o,`${e.id}.v${t}.poster.png`);await ut.writeFile(s,n);let i=await VV(s),c=await zV(s,a);dk(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:ft.relative(e.cwd,s),posterRel:c?ft.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 HM(e,t,n){let r=uk(n);if(!r)throw new Error("image must be a PNG");let o=vn(e,t);await ut.writeFile(o.png,n),dk(e,{v:t,source:"image",htmlRel:null,pngRel:ft.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function WM(e){let t=await br(),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 Ft(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function qM(e){let t=await br(),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=vn(r,o);await ut.rm(s.html,{force:!0}).catch(()=>{}),await ut.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await ut.rm(ft.join(r.cwd,s),{force:!0}).catch(()=>{});return await Sn(),await Ft(r,"deleted"),Rn("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function GM(e){let n=(await br()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=ft.join(RM,"mock-archive",e.id),o=vu(e.cwd),s=ft.join(r,".bostrat","mocks");await ut.mkdir(s,{recursive:!0});let a=await ut.readdir(o).catch(()=>[]);for(let i of a)await ut.copyFile(ft.join(o,i),ft.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 ut.stat(ft.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(),gr(i)}return await Sn(),n.length}async function KM(e){let t=await br(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Sn();for(let r of n)Rn("mocks",r.id).catch(()=>{})}return n.length}async function VM(){if(!et())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await xt("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await br();for(let r of n.mocks){await gr(r);for(let o of r.versions||[])o.htmlRel&&await yr(r,o.v,"html"),(o.pngRel||o.posterRel)&&await yr(r,o.v,"png"),o.videoRel&&await yr(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var lk,RM,OM,OV,MM,EM,MV,Ui,CV,CM,Hi,NV,_M,PV,DV,NM,un,ma,ik,gr,yr,vu,BV,GV,ck,Wi=K(()=>{be();rr();ak();bo();lk=$V(IV),RM=process.env.BOSTRAT_STATE_DIR||ft.join(process.env.HOME||$M.tmpdir(),".bostrat"),OM=ft.join(RM,"mocks.json"),OV=process.env.BOSTRAT_MOCK_ENGINE||"chromium",MM=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",EM=process.env.BOSTRAT_FIREFOX_BIN||"firefox",MV=1300,Ui=2,CV=32,CM=1500,Hi=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,NV=700*1024*1024,_M=100*1024*1024,PV=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",DV=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",NM=2e4,un=class extends Error{constructor(t,n=""){super(n?`${t}
|
|
313
|
+
`)}catch{return""}}async function dV(e){if(e.state==="stopped"||e.state==="error")return!1;let t=e.origin!=="detected",n=t?await lV(e.slug):!0;if(t&&!n){let s=e.state==="starting";return e.state=s?"error":"stopped",s&&(e.error=await pM(e.slug)||"server exited before listening"),zr.delete(e.id),await Jr(e,e.state,e.error?{error:e.error}:{}),!0}if(await bu(e.port))return zr.delete(e.id),e.lastHealthyAt=Date.now(),e.state!=="live"?(e.state="live",e.error=null,await Jr(e,"live"),!0):!1;if(e.state==="starting")return Date.now()-e.createdAt>uV?(e.state="error",e.error=await pM(e.slug)||"never started listening",await Jr(e,"error",{error:e.error}),!0):!1;let o=(zr.get(e.id)||0)+1;return zr.set(e.id,o),o>=3&&e.state==="live"?(e.state="unhealthy",!0):!1}async function bh(){if(!Wb){Wb=!0;try{let e=await Yr(),t=!1;for(let n of e.views)await dV(n)&&(t=!0);t&&await wr()}finally{Wb=!1}}}async function kh({trackId:e}={}){await bh();let t=await Yr();return(e?t.views.filter(r=>r.trackId===e):t.views).map(r=>({...r}))}async function xM(e){let n=(await Yr()).views.find(r=>r.id===e);return n?{...n}:null}function Zb(e){return Hn&&Hn.views.find(t=>t.slug===e)||null}function Qb(e,t=Date.now()){let n=Hn?.views.find(r=>r.id===e);n&&(n.lastAccessAt=t)}async function ek({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=Xt.resolve(r,o??"."),d=i==="detected"?null:async()=>{await sV(r,u),await aV(u,n)},p=await Yr();if(i!=="detected"){let h=Kb(t),g=String(n).trim(),y=p.views.find(b=>b.trackId===e&&(b.slug===h||Kb(b.name)===h||b.cmd===g&&Xt.resolve(b.serveCwd??b.cwd)===u));if(y)return pV(p,y,{cmd:g,box:a,branch:c,serveCwd:l?u:void 0,validate:d})}if(d&&await d(),p.views.filter(h=>h.state==="live"||h.state==="starting").length>=Xo)throw new Error(`view cap reached (${Xo} live) \u2014 stop one first`);let m={id:WK().slice(0,8),trackId:e,box:a||null,name:t.trim(),slug:iV(p,t),cmd:n?String(n).trim():null,cwd:r,serveCwd:u,branch:c,port:await cV(p,s),origin:i,state:"starting",error:null,createdAt:Date.now(),lastHealthyAt:null};return i!=="detected"&&await Xb(m),p.views.push(m),await wr(),await Jr(m,"created",{origin:i}),Gb(e,m.id),i==="detected"&&await bu(m.port)&&(m.state="live",m.lastHealthyAt=Date.now(),await wr(),await Jr(m,"live")),{...m}}async function pV(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 rV(t.serveCwd??t.cwd,s);if((t.state==="live"||t.state==="starting")&&!i&&!c&&await bu(t.port))return t.lastAccessAt=Date.now(),await wr(),Gb(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>=Xo)throw new Error(`view cap reached (${Xo} live) \u2014 stop one first`);return t.origin==="detected"?(await Yb(t.port),t.origin="agent"):await ku(t.slug),t.cmd=n,s!==void 0&&(t.serveCwd=s),t.state="starting",t.error=null,t.stoppedReason=null,t.createdAt=Date.now(),zr.delete(t.id),await Xb(t),await wr(),await Jr(t,"created",{restarted:!0,reused:!0}),Gb(t.trackId,t.id),{...t,reused:!0}}async function tk(e,{reason:t=null,idleMs:n=null}={}){let o=(await Yr()).views.find(s=>s.id===e);if(!o)throw new Error("view not found");return o.origin==="detected"?await Yb(o.port):await ku(o.slug),o.state!=="stopped"&&(o.state="stopped",o.stoppedReason=t,zr.delete(o.id),await wr(),await Jr(o,"stopped",t?{reason:t,...n?{idleMs:n}:{}}:{})),{...o}}async function SM(e){let t=await Yr(),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>=Xo)throw new Error(`view cap reached (${Xo} live) \u2014 stop one first`);return await ku(n.slug),n.state="starting",n.error=null,n.stoppedReason=null,n.createdAt=Date.now(),zr.delete(n.id),await Xb(n),await wr(),await Jr(n,"created",{restarted:!0}),{...n}}async function vM(e){let t=await Yr(),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 Yb(r.port):await ku(r.slug),t.views.splice(n,1),zr.delete(r.id),await wr(),await Jr(r,"deleted"),{ok:!0,id:e,slug:r.slug}}async function nk(e){let t=await Yr(),n=t.views.filter(r=>r.trackId===e);for(let r of n)r.origin!=="detected"&&await ku(r.slug),zr.delete(r.id);return n.length&&(t.views=t.views.filter(r=>r.trackId!==e),await wr()),n.length}async function AM(e,t){if(!e?.id||!Array.isArray(t)||!t.length)return[];let n=await Yr(),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 wr()),!o.length)return[];let a=new Set;for(let c of o)for(let l of String(c.text||"").matchAll(fV)){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(!kM().has(c)&&!n.views.some(l=>l.port===c)&&await bu(c))try{i.push(await ek({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 mr,KK,fM,lM,uM,Xo,VK,ji,dM,wu,zK,qb,JK,YK,XK,Vb,hM,Ub,eV,nV,wM,gh,Hn,Hb,gu,zb,gM,zr,uV,Wb,fV,xh=K(()=>{kt();be();rr();mr=GK(qK),KK=process.env.BOSTRAT_STATE_DIR||Xt.join(process.env.HOME||UK.tmpdir(),".bostrat"),fM=Xt.join(KK,"views.json"),[lM,uM]=(process.env.BOSTRAT_VIEW_PORTS||"4300-4349").split("-").map(e=>Number(e)||0),Xo=Number(process.env.BOSTRAT_VIEW_MAX)||3,VK="bostrat-view-",ji=e=>`${VK}${e}`,dM=new Set(["bostrat","www","api","views","app"]),wu=e=>Object.assign(new Error(e),{status:400}),zK=new Set(["npm","pnpm","yarn","bun"]),qb="package.json",JK=/[|;&`]|\$\(/,YK=new Set(["sh","bash","zsh","dash","env","exec","nohup","time"]),XK=/(^|\s)(-C|--cwd|--manifest-path|--dir)(=|\s)/,Vb=e=>String(e).trim().split(/\s+/).filter(Boolean),hM=/^[A-Za-z_][A-Za-z0-9_]*=/;Ub=e=>e==="/",eV=e=>e===".."||e.startsWith("../")||e.includes("/../")||e.endsWith("/..");nV=e=>yu.stat(e).then(t=>t.isDirectory(),()=>!1),wM=e=>yu.stat(e).then(t=>t.isFile(),()=>!1),gh=e=>yu.realpath(e).catch(()=>Xt.resolve(e));Hn=null,Hb=null;gu=new Map,zb=Number(process.env.BOSTRAT_VIEW_JOB_TIMEOUT)||3e5,gM=12e3;zr=new Map,uV=12e4;Wb=!1;fV=/https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d{2,5}))?(?:\/|\b)/g});import{execFile as hV}from"node:child_process";import{promisify as mV}from"node:util";function yV(e){return rk(e?.toPr?.number??e?.openPr?.number)}function rk(e){if(e==null||e==="")return null;let t=Number(e);return Number.isFinite(t)&&t>0?t:null}function bV(e){return Array.isArray(e?.actions)?e.actions.includes("push")||e.actions.includes("pr"):e?.action==="push"||e?.action==="pr"}function Zo(e,t=Date.now()){let n=null,r=new Map,o=new Set;for(let s of e||[]){let a=s.payload?.ts??s.ts;if(s.type==="pr.state.changed"&&s.payload?.sha&&s.payload?.number!=null&&o.add(`${Number(s.payload.number)}:${s.payload.sha}`),s.type==="pr.offered"){s.payload?.offerId&&r.set(s.payload.offerId,s.payload);continue}if(s.type==="pr.offer.answered"){let i=s.payload||{},c=r.get(i.offerId)||null,l=yV(c),u=Array.isArray(i.actions)&&i.actions.includes("rebase"),d=c?.base??null;i.action==="pr"?n={ts:a,offerId:i.offerId??null,box:s.boxId??null,offerType:"offer",toPr:l,base:d,rebase:u}:i.action!=="dismiss"&&i.action!=="pr-exists"&&l!=null&&bV(i)?n={ts:a,offerId:i.offerId??null,box:s.boxId??null,offerType:"offer",toPr:l,base:d,rebase:u}:n=null}else if(s.type==="pr.exists.answered"){let i=s.payload||{};n=i.choice==="push"?{ts:a,offerId:i.offerId??null,box:s.boxId??null,offerType:"exists",toPr:rk(i.number),base:null,rebase:Array.isArray(i.actions)&&i.actions.includes("rebase")}:null}else if(s.type==="pr.update.reported"){let i=s.payload||{},c=rk(i.number);!(n!=null&&n.offerType!=="report"&&(n.toPr==null||n.toPr===c))&&c!=null&&!(i.sha&&o.has(`${c}:${i.sha}`))&&(n={ts:a,offerId:null,box:s.boxId??null,offerType:"report",toPr:c,base:i.base??null,rebase:i.rebased===!0})}else s.type==="pr.state.changed"&&(s.payload?.change==="opened"||s.payload?.change==="pushed")&&n!=null&&a>=n.ts&&(n=null)}return n!=null&&t-n.ts>ok?null:n}function kV(e,t){return e?.firstSeen==null||t?.ts==null||e.firstSeen<t.ts}async function vh(e,{bypassThrottle:t=!1}={}){let n=e?.workspace?.branch;if(!n)return;let r;try{r=await V(e)}catch{return}let o=Zo(r);if(o==null)return;let s=(e.boxes||[]).find(p=>p.name===e.leadBox);if(await Ks(e.leadBox,s?.agent).catch(()=>!1))return;let a=Date.now();if(!t&&a<(xu.get(e.id)||0))return;xu.set(e.id,a+TM);let i;try{i=await kn(e.cwd,{caller:"reconcile"})}catch{return}let c=await Pi(e).catch(()=>[n]),l=o.toPr!=null&&(i||[]).find(p=>Number(p.number)===o.toPr&&c.includes(p.headRefName))||(i||[]).find(p=>c.includes(p.headRefName));if(!l)return;let u=l.headRefName||n,d=await Re(e.cwd).catch(()=>null);if(d){let{link:p,created:w}=await ln({repo:d,number:l.number,trackId:e.id,url:l.url,headRef:l.headRefName||n,title:l.title,source:"reconciled"});if(!w&&!(p?.trackId===e.id&&await Lr(d,l.number))){if(!kV(p,o))return;let m=await SV(e);if(m&&l.headSha&&m!==l.headSha){let g=Math.min(gV,(Sh.get(e.id)||TM)*2);Sh.set(e.id,g),xu.set(e.id,a+g);return}let h=await V(e).catch(()=>null);if(h&&Zo(h)==null)return;await D(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:vV(o,l,{branch:u,repo:d})}),xu.delete(e.id),Sh.delete(e.id);return}}await Hr({repo:d,number:l.number,via:"reconcile"}).catch(()=>{}),await D(e,{type:"pr.state.changed",actor:"agent",source:"orchestrator",boxId:e.leadBox,payload:xV(l,{branch:u,repo:d})}).catch(()=>{}),xu.delete(e.id),Sh.delete(e.id)}function xV(e,{branch:t=null,repo:n=null,now:r=Date.now()}={}){return{ts:r,change:"opened",number:e.number,url:e.url,title:e.title,branch:e.headRefName||t,...n?{repo:n}:{}}}async function SV(e){try{let{stdout:t}=await wV("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 vV(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:t.headRefName||n,...r?{repo:r}:{},...t.headSha?{sha:t.headSha}:{},via:e?.offerType==="report"?"lead":"ship",...e?.rebase?{rebased:!0}:{},...e?.base?{base:e.base}:{}}}var wV,TM,xu,gV,Sh,ok,Fi=K(()=>{be();pr();er();jn();Vs();Vo();wV=mV(hV),TM=6e3,xu=new Map,gV=5*6e4,Sh=new Map,ok=30*6e4});import sk from"node:os";import{execFile as AV}from"node:child_process";import{promisify as TV}from"node:util";async function Ah(){if(process.platform!=="darwin")return sk.freemem();try{let{stdout:e}=await EV("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:sk.freemem()}catch{return sk.freemem()}}var EV,ak=K(()=>{EV=TV(AV)});import ut from"node:fs/promises";import ft from"node:path";import $M from"node:os";import{randomUUID as _V}from"node:crypto";import{execFile as IV}from"node:child_process";import{promisify as $V}from"node:util";import{chromium as RV}from"playwright-core";async function br(){return ma||(ik||=(async()=>{try{ma=JSON.parse(await ut.readFile(OM,"utf8"))}catch{ma={mocks:[]}}finally{ik=null}return ma.mocks||=[],ma})(),ik)}async function Sn(){await dt(OM,ma)}function PM(e,t){yr(e,t.v,t.videoRel?.endsWith(".webm")?"webm":"mp4"),t.posterRel&&yr(e,t.v,"png")}function Ft(e,t,n={}){return D({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 vn(e,t){let n=vu(e.cwd);return{html:ft.join(n,`${e.id}.v${t}.html`),png:ft.join(n,`${e.id}.v${t}.png`)}}function Su(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?ft.join(e.cwd,r):null}function Wn(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 uk(e){return e.length<24||e.readUInt32BE(12)!==1229472850?null:{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function Th(e){return Buffer.isBuffer(e)&&e.length>24&&e.subarray(0,8).equals(BV)}function LV(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 jV(e){let t=Buffer.alloc(24),n=await ut.open(e,"r");try{await n.read(t,0,24,0)}finally{await n.close()}return t}function FV({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 UV(e,t){return e.evaluate(async n=>{let r=new Image;await new Promise((m,h)=>{r.onload=m,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,w=-1;for(let m=0;m<s;m++)for(let h=m*o*4,g=0;g<o;g++,h+=4)Math.abs(c[h]-l[0])+Math.abs(c[h+1]-l[1])+Math.abs(c[h+2]-l[2])>24&&(g<u&&(u=g),g>p&&(p=g),m<d&&(d=m),w=m);return p<0?null:{imgW:o,imgH:s,bg:l,bbox:{left:u,top:d,right:p,bottom:w}}},t.toString("base64"))}async function HV(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 WV({htmlPath:e,outPath:t,width:n}){let r=Date.now(),o;try{o=await RV.launch({executablePath:MM,args:["--disable-gpu"],timeout:3e4})}catch(s){throw new un("chromium failed to launch",s?.message||"")}try{let a=await(await o.newContext({viewport:{width:n,height:800},deviceScaleFactor:Ui})).newPage();a.setDefaultTimeout(Hi),await a.goto(`file://${e}`,{waitUntil:"load",timeout:Hi}),await a.waitForTimeout(250);let i;for(let l=1;;l++)try{i=await a.screenshot({fullPage:!0,timeout:Hi});break}catch(u){if(l>=3||!/captureScreenshot|Unable to capture/i.test(u?.message||""))throw u;await a.waitForTimeout(500)}try{let l=await UV(a,i),u=l&&FV({...l,pad:CV*Ui,align:Ui});u&&(i=await HV(a,i,{bg:l.bg,crop:u}))}catch{}if(i.length<CM)throw new un(`capture produced a ${i.length}-byte image`);let c=uk(i);if(!c)throw new un("output is not a PNG");return await ut.writeFile(t,i),{width:Math.round(c.width/Ui),height:Math.round(c.height/Ui),dpr:Ui,renderMs:Date.now()-r}}catch(s){throw s instanceof un?s:new un(/timeout/i.test(s?.message||"")?`render timed out after ${Hi}ms`:"chromium render failed",s?.message||"")}finally{await o.close().catch(()=>{})}}async function IM({htmlPath:e,outPath:t,width:n}){let r=await ut.mkdtemp(ft.join($M.tmpdir(),"bostrat-mock-profile-")),o=Date.now(),s="";try{try{s=(await lk(EM,["--headless","--no-remote","--profile",r,`--window-size=${n}`,"--screenshot",t,`file://${e}`],{env:{...process.env,MOZ_HEADLESS:"1"},timeout:Hi,killSignal:"SIGKILL",maxBuffer:4194304})).stderr||""}catch(c){throw s=c?.stderr||"",c?.code==="ENOENT"?new un(`firefox not found (${EM})`,""):new un(c?.killed?`render timed out after ${Hi}ms`:"firefox exited non-zero",s)}let a=await ut.stat(t).catch(()=>null);if(!a||a.size<CM)throw new un(`render produced ${a?`a ${a.size}-byte file`:"no file"} (silent no-op \u2014 another firefox holding the profile?)`,s);let i=uk(await jV(t));if(!i)throw new un("output is not a PNG",s);return{width:i.width,height:i.height,dpr:1,renderMs:Date.now()-o}}finally{await ut.rm(r,{recursive:!0,force:!0}).catch(()=>{})}}async function qV(e){if(OV==="firefox")return IM(e);try{return await WV(e)}catch(t){if(!/failed to launch/i.test(t?.message||""))throw t;try{return await IM(e)}catch(n){throw/not found/.test(n?.message||"")?new un(`no browser installed \u2014 chromium missing at ${MM} 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 DM(e){return ck=ck.then(e,e),ck}async function BM(e,t){let n=await br(),r=n.mocks.find(o=>o.id===e);if(r){r.state="rendering",await Sn(),await Ft(r,"rendering",{version:t});try{let o=await Ah();if(o<NV)throw new un(`box is low on memory (${Math.round(o/1e6)} MB available) \u2014 not spawning a browser`);let s=vn(r,t),a=await GV({htmlPath:s.html,outPath:s.png,width:r.width});if(!n.mocks.some(i=>i.id===e)){await ut.rm(s.png,{force:!0}).catch(()=>{});return}dk(r,{v:t,source:"html",htmlRel:ft.relative(r.cwd,s.html),pngRel:ft.relative(r.cwd,s.png),width:a.width,height:a.height,dpr:a.dpr,renderMs:a.renderMs,createdAt:Date.now()}),await Sn(),await Ft(r,"ready",{version:t,width:a.width,height:a.height,dpr:a.dpr}),gr(r),yr(r,t,"png")}catch(o){if(!n.mocks.some(s=>s.id===e))return;r.state="error",r.error=o?.message||String(o),await Sn(),await Ft(r,"error",{version:t,error:r.error}),gr(r)}}}function dk(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 KV({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?MV:Number(r);if(!Number.isInteger(o)||o<320||o>4e3)throw new Error("invalid width (320-4000)");return o}async function Au({trackId:e,group:t}={}){let n=await br(),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 Xr(e){let n=(await br()).mocks.find(r=>r.id===e);return n?{...n}:null}function LM({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&&!Th(t))throw new Error("image must be a PNG");if(n){let o=LV(n);if(!o)throw new Error("video must be an mp4 or webm (magic-byte check failed)");if(n.length>_M)throw new Error(`video must be ${_M/(1024*1024)} MB or smaller (got ${Math.round(n.length/(1024*1024))} MB)`);return o}return null}async function jM({trackId:e,name:t,html:n,image:r,video:o,cwd:s,width:a,group:i,box:c,agent:l,prompt:u}){let d=KV({trackId:e,name:t,cwd:s,width:a}),p=typeof n=="string"&&n.trim(),w=LM({html:n,image:r,video:o}),m=await br(),h={id:_V().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 ut.mkdir(vu(s),{recursive:!0}),m.mocks.push(h),p?(await ut.writeFile(vn(h,1).html,n),await Sn(),await Ft(h,"created"),gr(h),yr(h,1,"html"),DM(()=>BM(h.id,1))):o?(await UM(h,1,o,w),await Sn(),await Ft(h,"created"),await Ft(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr,durationS:h.versions[0]?.durationS??null}),gr(h),PM(h,h.versions[0])):(await HM(h,1,r),await Sn(),await Ft(h,"created"),await Ft(h,"ready",{version:1,width:h.width,height:h.height,dpr:h.dpr}),gr(h),yr(h,1,"png")),{...h}}async function FM(e,{html:t,image:n,video:r,width:o}={}){let a=(await br()).mocks.find(u=>u.id===e);if(!a)throw new Error("mock not found");let i=typeof t=="string"&&t.trim(),c=LM({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 ut.mkdir(vu(a.cwd),{recursive:!0}),i?(a.state="queued",await ut.writeFile(vn(a,l).html,t),await Sn(),await Ft(a,"updated",{version:l}),gr(a),yr(a,l,"html"),DM(()=>BM(a.id,l))):r?(await UM(a,l,r,c),await Sn(),await Ft(a,"updated",{version:l}),await Ft(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr,durationS:Wn(a)?.durationS??null}),gr(a),PM(a,a.versions.find(u=>u.v===l))):(await HM(a,l,n),await Sn(),await Ft(a,"updated",{version:l}),await Ft(a,"ready",{version:l,width:a.width,height:a.height,dpr:a.dpr}),gr(a),yr(a,l,"png")),{...a}}async function VV(e){try{let{stdout:t}=await lk(PV,["-v","error","-print_format","json","-show_format","-show_streams",e],{timeout:NM,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 zV(e,t){try{await lk(DV,["-y","-v","error","-i",e,"-frames:v","1","-f","image2",t],{timeout:NM,killSignal:"SIGKILL",maxBuffer:4*1024*1024});let n=await ut.stat(t).catch(()=>null);return!!n&&n.size>0}catch{return!1}}async function UM(e,t,n,r){let o=vu(e.cwd),s=ft.join(o,`${e.id}.v${t}.${r.ext}`),a=ft.join(o,`${e.id}.v${t}.poster.png`);await ut.writeFile(s,n);let i=await VV(s),c=await zV(s,a);dk(e,{v:t,source:"video",htmlRel:null,pngRel:null,videoRel:ft.relative(e.cwd,s),posterRel:c?ft.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 HM(e,t,n){let r=uk(n);if(!r)throw new Error("image must be a PNG");let o=vn(e,t);await ut.writeFile(o.png,n),dk(e,{v:t,source:"image",htmlRel:null,pngRel:ft.relative(e.cwd,o.png),width:r.width,height:r.height,dpr:1,renderMs:null,createdAt:Date.now()}),e.width=r.width}async function WM(e){let t=await br(),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 Ft(n,"picked",{version:n.readyVersion,siblings:r}),{mock:{...n},siblings:r}}async function qM(e){let t=await br(),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=vn(r,o);await ut.rm(s.html,{force:!0}).catch(()=>{}),await ut.rm(s.png,{force:!0}).catch(()=>{})}for(let o of r.versions||[])for(let s of[o.videoRel,o.posterRel])s&&await ut.rm(ft.join(r.cwd,s),{force:!0}).catch(()=>{});return await Sn(),await Ft(r,"deleted"),Rn("mocks",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function GM(e){let n=(await br()).mocks.filter(i=>i.trackId===e.id);if(!n.length)return 0;let r=ft.join(RM,"mock-archive",e.id),o=vu(e.cwd),s=ft.join(r,".bostrat","mocks");await ut.mkdir(s,{recursive:!0});let a=await ut.readdir(o).catch(()=>[]);for(let i of a)await ut.copyFile(ft.join(o,i),ft.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 ut.stat(ft.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(),gr(i)}return await Sn(),n.length}async function KM(e){let t=await br(),n=t.mocks.filter(r=>r.trackId===e);if(n.length){t.mocks=t.mocks.filter(r=>r.trackId!==e),await Sn();for(let r of n)Rn("mocks",r.id).catch(()=>{})}return n.length}async function VM(){if(!et())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await xt("mocks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await br();for(let r of n.mocks){await gr(r);for(let o of r.versions||[])o.htmlRel&&await yr(r,o.v,"html"),(o.pngRel||o.posterRel)&&await yr(r,o.v,"png"),o.videoRel&&await yr(r,o.v,o.videoRel.endsWith(".webm")?"webm":"mp4")}return{pushed:n.mocks.length,source:"plane"}}var lk,RM,OM,OV,MM,EM,MV,Ui,CV,CM,Hi,NV,_M,PV,DV,NM,un,ma,ik,gr,yr,vu,BV,GV,ck,Wi=K(()=>{be();rr();ak();bo();lk=$V(IV),RM=process.env.BOSTRAT_STATE_DIR||ft.join(process.env.HOME||$M.tmpdir(),".bostrat"),OM=ft.join(RM,"mocks.json"),OV=process.env.BOSTRAT_MOCK_ENGINE||"chromium",MM=process.env.BOSTRAT_CHROMIUM_BIN||"/usr/bin/chromium",EM=process.env.BOSTRAT_FIREFOX_BIN||"firefox",MV=1300,Ui=2,CV=32,CM=1500,Hi=Number(process.env.BOSTRAT_MOCK_TIMEOUT_MS)||75e3,NV=700*1024*1024,_M=100*1024*1024,PV=process.env.BOSTRAT_FFPROBE_BIN||"ffprobe",DV=process.env.BOSTRAT_FFMPEG_BIN||"ffmpeg",NM=2e4,un=class extends Error{constructor(t,n=""){super(n?`${t}
|
|
314
314
|
${n.trim().split(`
|
|
315
315
|
`).slice(-6).join(`
|
|
316
|
-
`)}`:t),this.name="MockRenderError"}},ma=null,ik=null;gr=e=>Pt("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),yr=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?Su(e,r,"video"):r&&Su(e,r,n)||(n==="html"?vn(e,t).html:null);return o?yo("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};vu=e=>ft.join(e,".bostrat","mocks");BV=Buffer.from([137,80,78,71,13,10,26,10]);GV=qV,ck=Promise.resolve()});import JV from"node:fs/promises";import ZM from"node:path";import YV from"node:os";import{randomUUID as QM}from"node:crypto";async function Qr(){return Zr||(pk||=(async()=>{let e=!0;try{Zr=JSON.parse(await JV.readFile(eC,"utf8"))}catch{Zr={flows:[]},e=!1}finally{pk=null}if(Zr.flows||=[],!e&&et()){let{records:t,source:n}=await xt("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&Zr.flows.push(r.data);Zr.flows.length&&await qi().catch(()=>{})}}return Zr})(),pk)}async function qi(){await dt(eC,Zr)}function fk(e,t,n={}){return D({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 tC({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>zM)throw new Error(`steps must be an array of 1-${zM}`);let r=await Au({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>YM)throw new Error(`${l}: caption over ${YM} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>XM)throw new Error(`${l}: title over ${XM} chars`);let p=String(c.mock??"").trim().replace(/^mock:/,"");if(!p)throw new Error(`${l}: mock (name or id) required`);let w=r.filter(b=>b.id===p);if(w.length||(w=r.filter(b=>b.name.toLowerCase()===p.toLowerCase())),!w.length)throw new Error(`${l}: no mock matching "${p}" in this Track \u2014 see \`bostrat-mock ls\``);if(w.length>1)throw new Error(`${l}: "${p}" is ambiguous (${w.map(b=>`mock:${b.id}`).join(", ")}) \u2014 use the id`);let m=w[0],f=null;if(c.v!=null&&(f=Number(c.v),!Number.isInteger(f)||!(m.versions||[]).some(b=>b.v===f)))throw new Error(`${l}: "${m.name}" has no captured v${c.v} to pin`);let g=o.findIndex(b=>b.mockId===m.id),y=g>=0?o.splice(g,1)[0].id:QM().slice(0,8);s.push({id:y,mockId:m.id,caption:u,title:d,v:f})}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 ZV(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>JM)throw new Error(`name over ${JM} chars`);return e.trim()}async function nC({trackId:e}={}){let t=await Qr();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function QV(e){let n=(await Qr()).flows.find(r=>r.id===e);return n?{...n}:null}async function rC(e){let t=await QV(e);if(!t)return null;let n=new Map((await Au({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=Wn(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 oC({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=ZV(t),i=await Qr(),c=i.flows.find(w=>w.trackId===e&&w.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 tC({trackId:e,steps:n}),d=Date.now(),p={id:QM().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 qi(),await fk(p,"created"),Eh(p),{...p}}async function sC(e,{steps:t,note:n}={}){let o=(await Qr()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await tC({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 qi(),await fk(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),Eh(o),{...o}}async function aC(e){let t=await Qr(),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 qi(),await fk(r,"deleted"),Rn("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function iC(e){return(await Qr()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function cC(e){let n=(await Qr()).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(),Eh(r);return n.length&&await qi(),n.length}async function lC(e){let t=await Qr(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await qi();for(let r of n)Rn("flows",r.id).catch(()=>{})}return n.length}async function uC(){if(!et())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await xt("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Qr();for(let r of n.flows)await Eh(r);return{pushed:n.flows.length,source:"plane"}}var XV,eC,zM,JM,YM,XM,Zr,pk,Eh,hk=K(()=>{be();rr();Wi();bo();XV=process.env.BOSTRAT_STATE_DIR||ZM.join(process.env.HOME||YV.tmpdir(),".bostrat"),eC=ZM.join(XV,"flows.json"),zM=20,JM=80,YM=500,XM=80,Zr=null,pk=null;Eh=e=>Pt("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import no from"node:fs/promises";import ro from"node:path";import ez from"node:os";import{randomUUID as tz}from"node:crypto";function Tu(e){return nz.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function kr(){return eo||(mk||=(async()=>{let e=!0;try{eo=JSON.parse(await no.readFile(pC,"utf8"))}catch{eo={runbooks:[]},e=!1}finally{mk=null}return eo.runbooks||=[],!e&&et()&&await rz().catch(()=>{}),eo})(),mk)}async function ga(){await dt(pC,eo)}function Ih(e){return Eu(Pt("runbooks",{...e},{trackId:e.trackId}))}async function rz(){let{records:e,source:t}=await xt("runbooks");if(!(t!=="plane"||!e.length)){await no.mkdir(_h,{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 Jc("runbooks",r.id,o.v,"md");typeof s=="string"&&await no.writeFile(to(r,o.v),s).catch(()=>{})}eo.runbooks.push(r)}eo.runbooks.length&&await ga()}}function Gi(e,t,n={}){return D({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 to(e,t){return ro.join(_h,`${e.id}.v${t}.md`)}function fC(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 hC(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>dC)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${dC/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=Tu(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 oz(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function sz({trackId:e,status:t}={}){let n=await kr(),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 mC({trackId:e,status:t}={}){let n=await kr(),r=await sz({trackId:e,status:t});if(!et())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await xt("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 wk(e){let t=await az(e);if(t)return t;if(!et())return null;let{records:n,source:r}=await xt("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 wC(e,t){let n=await Jc("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function az(e){let n=(await kr()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function gC({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=hC(r),c=await kr(),l={id:tz().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 no.mkdir(_h,{recursive:!0}),await no.writeFile(to(l,1),r),l.versions.push({v:1,mdRel:ro.relative(wa,to(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await ga(),await Gi(l,"created",{version:1}),Ih(l),Eu(yo("runbooks",l.id,1,"md",to(l,1))),{...l}}async function yC(e,{md:t,note:n}={}){let o=(await kr()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");oz(o,"update");let s=hC(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await no.mkdir(_h,{recursive:!0}),await no.writeFile(to(o,a),t),o.versions.push({v:a,mdRel:ro.relative(wa,to(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await ga(),await Gi(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),Ih(o),Eu(yo("runbooks",o.id,a,"md",to(o,a))),{...o}}async function bC(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await kr()).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 ga(),await Gi(r,t==="done"?"done":"reopened"),Ih(r),{...r})}async function kC(e){let t=await kr(),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 no.rm(ro.join(wa,o.mdRel),{force:!0}).catch(()=>{});return await ga(),r.trackDeletedAt||await Gi(r,"deleted"),Eu(Rn("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function xC(e){let n=(await kr()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await Gi(r,"orphaned"),r.cwd=null,Ih(r);return n.length&&await ga(),n.length}async function SC(e){let t=await kr(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await Gi(r,"deleted");for(let o of r.versions||[])await no.rm(ro.join(wa,o.mdRel),{force:!0}).catch(()=>{});Eu(Rn("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await ga()),n.length}async function vC(){if(!et())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await xt("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await kr();for(let r of n.runbooks){await Pt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await yo("runbooks",r.id,o.v,"md",ro.join(wa,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var wa,pC,_h,dC,nz,eo,mk,Eu,$h=K(()=>{rr();be();bo();wa=process.env.BOSTRAT_STATE_DIR||ro.join(process.env.HOME||ez.tmpdir(),".bostrat"),pC=ro.join(wa,"runbooks.json"),_h=ro.join(wa,"runbooks"),dC=256*1024,nz=[{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/}];eo=null,mk=null;Eu=e=>Promise.resolve(e).catch(()=>{})});import gk from"node:fs/promises";import _u from"node:path";import{randomUUID as iz}from"node:crypto";function bk(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return cz.has(t)?"image":lz.has(t)?"doc":null}function uz(e){let r=_u.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 EC(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>AC)throw new Error(`file too large \u2014 max ${Math.floor(AC/(1024*1024))} MB`);let r=uz(t),o=_u.extname(r).slice(1),s=bk(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=iz().slice(0,8),i=yk(e);await gk.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await gk.writeFile(_u.join(i,c),n,{mode:384}),await gk.chmod(_u.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${TC}/${c}`,kind:s,size:n.length}}function _C(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function kk(e){return e.role==="user"&&dz.test((e.text||"").trim())}var TC,yk,AC,cz,lz,dz,xk=K(()=>{TC=".bostrat/uploads",yk=e=>_u.join(e,TC),AC=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,cz=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),lz=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"]);dz=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function Qo(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}function Sk(){let e=Number(process.env.BOSTRAT_LOOP_QUEUE_HOLD_MS);return Number.isFinite(e)&&e>0?e:pz}function hz(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 IC(e,t,{capMs:n=Sk(),now:r=Date.now()}={}){if(!e)return!1;let o=hz(e,t,r);return e.delivery?.producer!=="loop"||!fz.has(t)?!1:o>=n}var pz,fz,$C=K(()=>{pz=5*6e4,fz=new Set(["busy","noSession"])});import{execFile as mz}from"node:child_process";import{promisify as wz}from"node:util";function vk(e){return`refs/bostrat/wip/${e}`}function bz(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function MC(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function kz(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:yz}function CC(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 xz(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 es(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await es(s,["remote","get-url","origin"])}catch{return RC.has(s)||(RC.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 Si(s,"bostrat: wip snapshot"),{stdout:c}=await es(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(!n&&Rh.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=vk(o);return await es(s,["push","--force","origin",`${i}:${u}`],OC),Rh.set(s,l),await D(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,wip:!0,...NC(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(`
|
|
316
|
+
`)}`:t),this.name="MockRenderError"}},ma=null,ik=null;gr=e=>Pt("mocks",{...e},{trackId:e.trackId}).catch(()=>{}),yr=(e,t,n)=>{let r=(e.versions||[]).find(s=>s.v===t),o=n==="mp4"||n==="webm"?Su(e,r,"video"):r&&Su(e,r,n)||(n==="html"?vn(e,t).html:null);return o?yo("mocks",e.id,t,n,o).catch(()=>{}):Promise.resolve()};vu=e=>ft.join(e,".bostrat","mocks");BV=Buffer.from([137,80,78,71,13,10,26,10]);GV=qV,ck=Promise.resolve()});import JV from"node:fs/promises";import ZM from"node:path";import YV from"node:os";import{randomUUID as QM}from"node:crypto";async function Qr(){return Zr||(pk||=(async()=>{let e=!0;try{Zr=JSON.parse(await JV.readFile(eC,"utf8"))}catch{Zr={flows:[]},e=!1}finally{pk=null}if(Zr.flows||=[],!e&&et()){let{records:t,source:n}=await xt("flows").catch(()=>({records:[],source:"error"}));if(n==="plane"){for(let r of t)!r.deletedAt&&r.data?.id&&Zr.flows.push(r.data);Zr.flows.length&&await qi().catch(()=>{})}}return Zr})(),pk)}async function qi(){await dt(eC,Zr)}function fk(e,t,n={}){return D({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 tC({trackId:e,steps:t,prevSteps:n=[]}){if(!Array.isArray(t)||t.length<1||t.length>zM)throw new Error(`steps must be an array of 1-${zM}`);let r=await Au({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>YM)throw new Error(`${l}: caption over ${YM} chars`);let d=c.title==null?null:String(c.title).trim()||null;if(d&&d.length>XM)throw new Error(`${l}: title over ${XM} chars`);let p=String(c.mock??"").trim().replace(/^mock:/,"");if(!p)throw new Error(`${l}: mock (name or id) required`);let w=r.filter(b=>b.id===p);if(w.length||(w=r.filter(b=>b.name.toLowerCase()===p.toLowerCase())),!w.length)throw new Error(`${l}: no mock matching "${p}" in this Track \u2014 see \`bostrat-mock ls\``);if(w.length>1)throw new Error(`${l}: "${p}" is ambiguous (${w.map(b=>`mock:${b.id}`).join(", ")}) \u2014 use the id`);let m=w[0],h=null;if(c.v!=null&&(h=Number(c.v),!Number.isInteger(h)||!(m.versions||[]).some(b=>b.v===h)))throw new Error(`${l}: "${m.name}" has no captured v${c.v} to pin`);let g=o.findIndex(b=>b.mockId===m.id),y=g>=0?o.splice(g,1)[0].id:QM().slice(0,8);s.push({id:y,mockId:m.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 ZV(e){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>JM)throw new Error(`name over ${JM} chars`);return e.trim()}async function nC({trackId:e}={}){let t=await Qr();return(e?t.flows.filter(r=>r.trackId===e):t.flows).map(r=>({...r}))}async function QV(e){let n=(await Qr()).flows.find(r=>r.id===e);return n?{...n}:null}async function rC(e){let t=await QV(e);if(!t)return null;let n=new Map((await Au({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=Wn(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 oC({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=ZV(t),i=await Qr(),c=i.flows.find(w=>w.trackId===e&&w.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 tC({trackId:e,steps:n}),d=Date.now(),p={id:QM().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 qi(),await fk(p,"created"),Eh(p),{...p}}async function sC(e,{steps:t,note:n}={}){let o=(await Qr()).flows.find(i=>i.id===e);if(!o)throw new Error("flow not found");let{steps:s,resolved:a}=await tC({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 qi(),await fk(o,"updated",{version:o.version,...n?{note:String(n).slice(0,200)}:{}}),Eh(o),{...o}}async function aC(e){let t=await Qr(),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 qi(),await fk(r,"deleted"),Rn("flows",r.id).catch(()=>{}),{ok:!0,id:e,name:r.name}}async function iC(e){return(await Qr()).flows.filter(n=>n.steps.some(r=>r.mockId===e)).map(n=>({...n}))}async function cC(e){let n=(await Qr()).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(),Eh(r);return n.length&&await qi(),n.length}async function lC(e){let t=await Qr(),n=t.flows.filter(r=>r.trackId===e);if(n.length){t.flows=t.flows.filter(r=>r.trackId!==e),await qi();for(let r of n)Rn("flows",r.id).catch(()=>{})}return n.length}async function uC(){if(!et())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await xt("flows");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await Qr();for(let r of n.flows)await Eh(r);return{pushed:n.flows.length,source:"plane"}}var XV,eC,zM,JM,YM,XM,Zr,pk,Eh,hk=K(()=>{be();rr();Wi();bo();XV=process.env.BOSTRAT_STATE_DIR||ZM.join(process.env.HOME||YV.tmpdir(),".bostrat"),eC=ZM.join(XV,"flows.json"),zM=20,JM=80,YM=500,XM=80,Zr=null,pk=null;Eh=e=>Pt("flows",{...e},{trackId:e.trackId}).catch(()=>{})});import no from"node:fs/promises";import ro from"node:path";import ez from"node:os";import{randomUUID as tz}from"node:crypto";function Tu(e){return nz.filter(({re:t})=>t.test(e)).map(({label:t})=>t)}async function kr(){return eo||(mk||=(async()=>{let e=!0;try{eo=JSON.parse(await no.readFile(pC,"utf8"))}catch{eo={runbooks:[]},e=!1}finally{mk=null}return eo.runbooks||=[],!e&&et()&&await rz().catch(()=>{}),eo})(),mk)}async function ga(){await dt(pC,eo)}function Ih(e){return Eu(Pt("runbooks",{...e},{trackId:e.trackId}))}async function rz(){let{records:e,source:t}=await xt("runbooks");if(!(t!=="plane"||!e.length)){await no.mkdir(_h,{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 Jc("runbooks",r.id,o.v,"md");typeof s=="string"&&await no.writeFile(to(r,o.v),s).catch(()=>{})}eo.runbooks.push(r)}eo.runbooks.length&&await ga()}}function Gi(e,t,n={}){return D({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 to(e,t){return ro.join(_h,`${e.id}.v${t}.md`)}function fC(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 hC(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Buffer.byteLength(e,"utf8");if(t>dC)throw new Error(`runbook is ${Math.round(t/1024)} KB \u2014 over the ${dC/1024} KB cap; a doc that size belongs in the repo, not a runbook`);let n=Tu(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 oz(e,t){if(e.trackDeletedAt)throw new Error(`runbook is orphaned (its Track was deleted) \u2014 cannot ${t} it`)}async function sz({trackId:e,status:t}={}){let n=await kr(),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 mC({trackId:e,status:t}={}){let n=await kr(),r=await sz({trackId:e,status:t});if(!et())return{runbooks:r,fleetDegraded:!1};let{records:o,source:s}=await xt("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 wk(e){let t=await az(e);if(t)return t;if(!et())return null;let{records:n,source:r}=await xt("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 wC(e,t){let n=await Jc("runbooks",e.id,t,"md");return typeof n=="string"?n:null}async function az(e){let n=(await kr()).runbooks.find(r=>r.id===e);return n?{...n}:null}async function gC({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=hC(r),c=await kr(),l={id:tz().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 no.mkdir(_h,{recursive:!0}),await no.writeFile(to(l,1),r),l.versions.push({v:1,mdRel:ro.relative(wa,to(l,1)),bytes:i,note:null,createdAt:Date.now()}),c.runbooks.push(l),await ga(),await Gi(l,"created",{version:1}),Ih(l),Eu(yo("runbooks",l.id,1,"md",to(l,1))),{...l}}async function yC(e,{md:t,note:n}={}){let o=(await kr()).runbooks.find(i=>i.id===e);if(!o)throw new Error("runbook not found");oz(o,"update");let s=hC(t),a=o.version+1;return o.version=a,o.updatedAt=Date.now(),await no.mkdir(_h,{recursive:!0}),await no.writeFile(to(o,a),t),o.versions.push({v:a,mdRel:ro.relative(wa,to(o,a)),bytes:s,note:n?String(n).slice(0,200):null,createdAt:Date.now()}),await ga(),await Gi(o,"updated",{version:a,...n?{note:String(n).slice(0,200)}:{}}),Ih(o),Eu(yo("runbooks",o.id,a,"md",to(o,a))),{...o}}async function bC(e,t){if(t!=="open"&&t!=="done")throw new Error('status must be "open" or "done"');let r=(await kr()).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 ga(),await Gi(r,t==="done"?"done":"reopened"),Ih(r),{...r})}async function kC(e){let t=await kr(),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 no.rm(ro.join(wa,o.mdRel),{force:!0}).catch(()=>{});return await ga(),r.trackDeletedAt||await Gi(r,"deleted"),Eu(Rn("runbooks",r.id)),{ok:!0,id:e,name:r.name}}async function xC(e){let n=(await kr()).runbooks.filter(r=>r.trackId===e&&!r.trackDeletedAt);for(let r of n)r.trackDeletedAt=Date.now(),r.updatedAt=Date.now(),await Gi(r,"orphaned"),r.cwd=null,Ih(r);return n.length&&await ga(),n.length}async function SC(e){let t=await kr(),n=t.runbooks.filter(r=>r.trackId===e);for(let r of n){await Gi(r,"deleted");for(let o of r.versions||[])await no.rm(ro.join(wa,o.mdRel),{force:!0}).catch(()=>{});Eu(Rn("runbooks",r.id))}return n.length&&(t.runbooks=t.runbooks.filter(r=>r.trackId!==e),await ga()),n.length}async function vC(){if(!et())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await xt("runbooks");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await kr();for(let r of n.runbooks){await Pt("runbooks",{...r},{trackId:r.trackId}).catch(()=>{});for(let o of r.versions||[])await yo("runbooks",r.id,o.v,"md",ro.join(wa,o.mdRel)).catch(()=>{})}return{pushed:n.runbooks.length,source:"plane"}}var wa,pC,_h,dC,nz,eo,mk,Eu,$h=K(()=>{rr();be();bo();wa=process.env.BOSTRAT_STATE_DIR||ro.join(process.env.HOME||ez.tmpdir(),".bostrat"),pC=ro.join(wa,"runbooks.json"),_h=ro.join(wa,"runbooks"),dC=256*1024,nz=[{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/}];eo=null,mk=null;Eu=e=>Promise.resolve(e).catch(()=>{})});import gk from"node:fs/promises";import _u from"node:path";import{randomUUID as iz}from"node:crypto";function bk(e){let t=String(e||"").toLowerCase().replace(/^\./,"");return cz.has(t)?"image":lz.has(t)?"doc":null}function uz(e){let r=_u.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 EC(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>AC)throw new Error(`file too large \u2014 max ${Math.floor(AC/(1024*1024))} MB`);let r=uz(t),o=_u.extname(r).slice(1),s=bk(o);if(!s)throw new Error(`unsupported file type "${o||"unknown"}" \u2014 attach an image or a document`);let a=iz().slice(0,8),i=yk(e);await gk.mkdir(i,{recursive:!0});let c=`${a}-${r}`;return await gk.writeFile(_u.join(i,c),n,{mode:384}),await gk.chmod(_u.join(i,c),384).catch(()=>{}),{id:a,name:r,rel:`${TC}/${c}`,kind:s,size:n.length}}function _C(e){let t=e.map(r=>`\`${r}\``).join(", ");return`[Attached \u2014 please read ${e.length===1?"this file":`these ${e.length} files`}: ${t}]`}function kk(e){return e.role==="user"&&dz.test((e.text||"").trim())}var TC,yk,AC,cz,lz,dz,xk=K(()=>{TC=".bostrat/uploads",yk=e=>_u.join(e,TC),AC=Number(process.env.BOSTRAT_MAX_UPLOAD_BYTES)||24*1024*1024,cz=new Set(["png","jpg","jpeg","gif","webp","svg","bmp","tif","tiff","heic","heif","avif","ico"]),lz=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"]);dz=/\[Attached — please read (?:this file|these \d+ files): [^\]]*\]$/});function Qo(e,t,n=Date.now()){return t?e.idleSince==null?(e.idleSince=n,!1):n-e.idleSince>=6500:(e.idleSince=null,!1)}function Sk(){let e=Number(process.env.BOSTRAT_LOOP_QUEUE_HOLD_MS);return Number.isFinite(e)&&e>0?e:pz}function hz(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 IC(e,t,{capMs:n=Sk(),now:r=Date.now()}={}){if(!e)return!1;let o=hz(e,t,r);return e.delivery?.producer!=="loop"||!fz.has(t)?!1:o>=n}var pz,fz,$C=K(()=>{pz=5*6e4,fz=new Set(["busy","noSession"])});import{execFile as mz}from"node:child_process";import{promisify as wz}from"node:util";function vk(e){return`refs/bostrat/wip/${e}`}function bz(e,t=Date.now()){return`refs/bostrat/rescue/${e}-${t}`}function MC(e=process.env){let t=String(e.BOSTRAT_WIP_SYNC_MS??"").trim().toLowerCase();return t!=="0"&&t!=="off"&&t!=="false"}function kz(e=process.env){let t=Number(e.BOSTRAT_WIP_SYNC_MS);return Number.isFinite(t)&&t>0?t:yz}function CC(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 xz(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 es(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await es(s,["remote","get-url","origin"])}catch{return RC.has(s)||(RC.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 Si(s,"bostrat: wip snapshot"),{stdout:c}=await es(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(!n&&Rh.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=vk(o);return await es(s,["push","--force","origin",`${i}:${u}`],OC),Rh.set(s,l),await D(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,wip:!0,...NC(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(`
|
|
317
317
|
`)[0]}`),{pushed:!1,reason:"push-failed"}}}async function Ak(e,{log:t=console,force:n=!1}={}){let r=[],o=[];for(let s of CC(e)){let a=await xz(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 Sz(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 es(s,["rev-parse","--git-dir"])}catch{return{pushed:!1,reason:"not-a-repo"}}try{await es(s,["remote","get-url","origin"])}catch{return{pushed:!1,reason:"no-origin"}}try{let i=await Si(s,"bostrat: transfer rescue snapshot"),{stdout:c}=await es(s,["rev-parse",`${i}^{tree}`]),l=c.trim();if(Rh.get(s)===l)return{pushed:!1,reason:"unchanged"};let u=bz(o,r);return await es(s,["push","origin",`${i}:${u}`],OC),Rh.set(s,l),await D(e,{type:"code.pushed",actor:"orchestrator",boxId:e.leadBox??null,payload:{ref:u,sha:i,rescue:!0,...NC(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(`
|
|
318
|
-
`)[0]}`),{pushed:!1,reason:"push-failed"}}}async function Tk(e,{log:t=console,ts:n=Date.now()}={}){let r=[],o=[];for(let s of CC(e)){let a=await Sz(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 PC({listTracks:e,sweepMs:t=kz(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)He(i)||i?.kind==="setup"||await Ak(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 gz,yz,OC,es,Rh,RC,NC,Ek=K(()=>{Fl();be();yn();gz=wz(mz),yz=12e4,OC=6e4;es=(e,t,n=15e3)=>gz("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),Rh=new Map,RC=new Set,NC=e=>e?.name||e?.repo?{name:e.name??null,repo:e.repo??null}:{}});import vz from"node:fs";import _k from"node:fs/promises";import Az from"node:path";function Iz(e=process.env){return!!(Ue(e)&&e.BOSTRAT_PLANE_TOKEN)}async function DC(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(!Iz(t))return{restored:!1,reason:"plane not configured"};let s=Wa(e),a=Az.join(s,`${o}.ndjson`);try{if(vz.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=Ue(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let p=new AbortController,w=setTimeout(()=>p.abort(),_z),m;try{m=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${Tz}`,{headers:c,signal:p.signal})}finally{clearTimeout(w)}if(m.status===404)return{restored:!1,reason:"unknown to plane"};if(!m.ok)return{restored:!1,reason:`plane ${m.status}`};let
|
|
318
|
+
`)[0]}`),{pushed:!1,reason:"push-failed"}}}async function Tk(e,{log:t=console,ts:n=Date.now()}={}){let r=[],o=[];for(let s of CC(e)){let a=await Sz(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 PC({listTracks:e,sweepMs:t=kz(),log:n=console}){let r=!1,o=async()=>{if(!r){r=!0;try{let a=await e()??[];for(let i of a)He(i)||i?.kind==="setup"||await Ak(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 gz,yz,OC,es,Rh,RC,NC,Ek=K(()=>{Fl();be();yn();gz=wz(mz),yz=12e4,OC=6e4;es=(e,t,n=15e3)=>gz("git",["-C",e,...t],{timeout:n,maxBuffer:4*1024*1024}),Rh=new Map,RC=new Set,NC=e=>e?.name||e?.repo?{name:e.name??null,repo:e.repo??null}:{}});import vz from"node:fs";import _k from"node:fs/promises";import Az from"node:path";function Iz(e=process.env){return!!(Ue(e)&&e.BOSTRAT_PLANE_TOKEN)}async function DC(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(!Iz(t))return{restored:!1,reason:"plane not configured"};let s=Wa(e),a=Az.join(s,`${o}.ndjson`);try{if(vz.statSync(a).size>0)return{restored:!1,reason:"log not empty"}}catch{}let i=Ue(t),c={authorization:`Bearer ${t.BOSTRAT_PLANE_TOKEN||""}`},l=[],u=0;for(;;){let p=new AbortController,w=setTimeout(()=>p.abort(),_z),m;try{m=await n(`${i}/v1/spine/${encodeURIComponent(o)}?after=${u}&limit=${Tz}`,{headers:c,signal:p.signal})}finally{clearTimeout(w)}if(m.status===404)return{restored:!1,reason:"unknown to plane"};if(!m.ok)return{restored:!1,reason:`plane ${m.status}`};let h=await m.json();for(let g of h.events||[])l.push(JSON.stringify(g));if(l.length>Ez)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 _k.mkdir(s,{recursive:!0});let d=`${a}.pull-${process.pid}-${Date.now()}`;return await _k.writeFile(d,l.join(`
|
|
319
319
|
`)+`
|
|
320
|
-
`),await _k.rename(d,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var Tz,Ez,_z,BC=K(()=>{_t();be();Tz=1e3,Ez=5e5,_z=3e4});function LC(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 jC(e){let t=(e||[]).filter(n=>!$z.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 FC({archivedAt:e=null,archiving:t=!1,prompted:n=!1,openActions:r=0,openActionSince:o=null,loopAttention:s=!1,question:a=null,prDecisions:i=null,operation:c=null,phase:l=null,working:u=!1,workingSince:d=null,pending:p=null,interrupted:w=null,completedTurnAt:m=null,live:f=!1,now:g=Date.now()}={}){if(e&&!t)return dn("archived","lifecycle",e);if(n)return dn("needs-you","pane",o||g,{count:r||1});if(t)return dn("archiving","lifecycle",e||g);if(c?.status==="working")return dn("working","operation",c.since,{summary:c.summary??null,count:c.count??null});if((u||n)&&l?.phase)return dn("working","agent-phase",l.at,{summary:l.summary??null});if(u)return dn("working","pane",d||g);if(r>0||s||a?.at){let y=a?.at&&!s&&r<=1;return dn("needs-you",s?"loop":y?"question":"obligations",(y?a.at:o)||g,{count:r||1,...y?{summary:a.summary??null}:{}})}if(i?.count)return dn("needs-you","pr",i.since,{count:i.count,summary:i.summary??null});if(w?.at){let y=c?.status==="waiting"?c.summary:p?.count?p.summary:null,b=[w.summary,y].filter(Boolean).join(" \xB7 ")||null;return dn("interrupted",w.source||"interrupted",w.at,{summary:b})}return c?.status==="waiting"?dn("waiting","operation",c.since,{summary:c.summary??null,count:c.count??null}):p?.count?dn("waiting",p.source||"pending",p.since,{summary:p.summary??null,count:p.count}):m&&f?dn("settled","obligations",m,{summary:"no open actions"}):dn("idle","fallback",m||g)}var dn,$z,UC=K(()=>{dn=(e,t,n,r={})=>({kind:e,source:t,since:n||0,...r});$z=new Set(["merged","closed","lost"])});import Ik from"node:fs/promises";async function Oz(e){let t;try{t=await Ik.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/Rz*1e3,ioBytes:await Mz(e)}}async function Mz(e){let t;try{t=await Ik.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 HC(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 Ik.readdir("/proc")}catch{return null}let r=new Map;await Promise.all(n.map(async l=>{if(!/^\d+$/.test(l))return;let u=await Oz(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 Rz,WC=K(()=>{Rz=100});import Cz from"node:fs/promises";function Mk(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 Ck(e,t,n){let r=null;try{r=await n.updatedAt(e)}catch{r=null}let o=qC.get(e.name);if(o&&o.mtime===r&&t-o.at<Lz)return o.jobs;let s=[];try{s=await n.readOpenJobs(e)}catch{s=[]}return qC.set(e.name,{at:t,mtime:r,jobs:s}),s}async function jz(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 Fz(e,t){return e?.outputFile?await t.statFile(e.outputFile):null}function Uz(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>=Dz||t.ioBytes!=null&&e.ioBytes!=null&&(t.ioBytes-e.ioBytes)/n>=Bz}function GC(e,t,n,r){let o=[];for(let s of n){let a=Ok(e.id,t.name,s.id),i=qn.get(a);i?i.job=s:qn.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 KC(e,{now:t=Date.now(),deps:n=Rk}={}){let o=(await Promise.all(Mk([e]).map(({box:s})=>Ck(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 VC(e,{now:t=Date.now(),deps:n=Rk}={}){let r=new Map,o=new Set;for(let{track:s,box:a}of Mk(e)){let i=await Ck(a,t,n);for(let l of i)o.add(Ok(s.id,a.name,l.id));let c=GC(s,a,i,t).filter(l=>!qn.get(l).stalled).map(l=>qn.get(l).job);c.length&&r.set(s.id,[...r.get(s.id)??[],...c])}for(let s of[...qn.keys()])o.has(s)||qn.delete(s);return r}async function Hz(e,{now:t=Date.now(),deps:n=Rk}={}){let r={checked:0,progressing:0,quiet:0,stalled:[]},o=Mk(e),s=new Set(o.map(({box:a})=>a.name));for(let[a,i]of[...qn])s.has(i.boxName)||qn.delete(a);for(let{track:a,box:i}of o){let c=await Ck(i,t,n),l=new Set(c.map(m=>Ok(a.id,i.name,m.id)));for(let[m,f]of[...qn])f.boxName===i.name&&!l.has(m)&&qn.delete(m);if(!c.length){$k.delete(i.name);continue}let u=GC(a,i,c,t),d=await jz(i,t,n),p=$k.get(i.name);$k.set(i.name,d);let w=Uz(p,d);for(let m of u){let f=qn.get(m);r.checked++;let g=await Fz(f.job,n),y=!!g&&!!f.file&&(g.size>f.file.size||g.mtimeMs>f.file.mtimeMs),b=!!g&&!f.file;if(f.file=g??f.file,w||y||b){f.quiet=0,f.lastProgressAt=t,f.stalled=!1,r.progressing++;continue}if(f.stalled||(f.quiet++,r.quiet++,f.quiet<Pz))continue;f.stalled=!0,f.stalledAt=t,r.stalled.push(m);let v=t-(f.lastProgressAt??f.firstSeenAt);try{await n.appendEvent(a,{type:"job.stalled",actor:"orchestrator",source:"orchestrator",boxId:i.name,provider:i.agent||null,payload:{id:f.job.id,kind:f.job.kind||"agent",name:f.job.name||null,detail:f.job.detail||null,startedTs:f.job.ts??f.firstSeenAt,quietMs:v,checks:f.quiet}})}catch{}console.log(`[job-watch] ${a.id}/${i.name} job ${f.job.id} (${f.job.name||f.job.kind}) quiet for ${Math.round(v/6e4)}m over ${f.quiet} check(s) \u2014 released; the node may sleep`)}}return r}function zC({listTracks:e,intervalMs:t=Nz}={}){let n=!1,o=setInterval(async()=>{if(!n){n=!0;try{await Hz(await e())}catch(s){console.error(`[job-watch] sweep: ${s?.message||s}`)}finally{n=!1}}},t);return o.unref?.(),o}var Nz,Pz,Dz,Bz,Lz,Rk,qn,qC,$k,Ok,Nk=K(()=>{be();Jp();kt();WC();Nz=Number(process.env.BOSTRAT_JOB_CHECK_MS)||15*6e4,Pz=Number(process.env.BOSTRAT_JOB_STALL_CHECKS)||3,Dz=Number(process.env.BOSTRAT_JOB_CPU_RATE_MIN)||25,Bz=Number(process.env.BOSTRAT_JOB_IO_RATE_MIN)||64*1024,Lz=5*6e4,Rk={readOpenJobs:zp,statFile:async e=>{try{let t=await Cz.stat(e);return{size:t.size,mtimeMs:Math.round(t.mtimeMs)}}catch{return null}},updatedAt:e=>Oo(e.agent).updatedAt(e),panePids:CA,treeStats:HC,appendEvent:D},qn=new Map,qC=new Map,$k=new Map,Ok=(e,t,n)=>`${e}|${t}|${n}`});import Wz from"node:fs/promises";import qz from"node:os";import Oh from"node:path";async function Pk(e){try{return(await Wz.stat(e)).size}catch{return null}}async function Ki(e){let[t,n,r]=await Promise.all([Pk(Oh.join(Gz,"CLAUDE.md")),e?Pk(Oh.join(e,"CLAUDE.md")):null,e?Pk(Oh.join(e,".bostrat","memory","MEMORY.md")):null]);return{bostratClaudeMd:t,repoClaudeMd:n,memoryIndex:r}}var Gz,Dk=K(()=>{Gz=process.env.BOSTRAT_STATE_DIR||Oh.join(process.env.HOME||qz.tmpdir(),".bostrat")});import{randomUUID as Kz}from"node:crypto";async function Ch(e,t,n={}){let r={operationId:Kz(),kind:t,startedAt:Date.now(),...n};return Mh.set(e.id,r),await D(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:r.startedAt,state:"started",...r}}).catch(()=>{}),r}async function Bk(e,t,n="completed",r=null){Mh.get(e.id)?.operationId===t?.operationId&&Mh.delete(e.id),await D(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 Mh,JC,Lk=K(()=>{be();Mh=new Map;JC=e=>Mh.get(e)||null});var CN={};nw(CN,{HANDOFF_LATEST_REL:()=>rs,KNOWN_AGENTS:()=>Wu,LOGIN_GREETING:()=>fN,TRACK_NAME_MAX:()=>Fu,_resetRestartRefusalsForTest:()=>s8,addTrackRepo:()=>zh,adoptTrack:()=>U0,agentAvailability:()=>Hh,announceNodeUpdate:()=>vr,answerFullscreenOffer:()=>O0,answerPrompt:()=>qh,answeringFor:()=>s0,archiveTrack:()=>xa,archiveTrackForMergedPr:()=>Gr,augmentFirstPromptAfterHandoff:()=>sN,buildAgentCmd:()=>Qk,canResumeSubtask:()=>RN,cancelQueued:()=>Kh,cancelQueuedToDraft:()=>c0,cancelQueuedWhere:()=>mN,cancelStopJob:()=>ka,cancelSubtask:()=>rm,changedRepos:()=>ha,commitTransferOut:()=>tm,createSetupTrack:()=>v0,createTrack:()=>Xh,deleteTrack:()=>T0,demoteTransferredTracks:()=>j0,ensureLeadEpochs:()=>ns,forceMergeSubtask:()=>q0,getHandoffJob:()=>ac,getReshapeJob:()=>qu,getSubtaskJob:()=>w8,getTrack:()=>ye,getTransferOutJob:()=>P0,healDeadLead:()=>ju,interruptLead:()=>Vh,isArchiving:()=>Z3,isHandoffNoteEcho:()=>Kk,isInterruptEcho:()=>Vk,isLeadStarting:()=>dN,isModelSwitchEcho:()=>zk,leadCliDead:()=>Gu,listSubtaskJobs:()=>va,listTracks:()=>xe,matchTranscriptsToBoxes:()=>lN,mergeNotifyMessage:()=>EN,navigatePrompt:()=>a0,notifyTrackForMergedPr:()=>Kr,notifyTrackForResolvedPr:()=>Zh,offerFollowupsForMergedPr:()=>Sa,pendingOffers:()=>r0,queueGauges:()=>i0,queueShipCompleteNotify:()=>d0,queuedMessages:()=>ss,rawTrack:()=>n0,reapArchivedOrphans:()=>R0,reconcileDemotedTracks:()=>$0,reconcileHandoffOutcome:()=>_N,reconcileInterruptedHandoffs:()=>C0,reconcileInterruptedReshapes:()=>k0,reconcileInterruptedSubtasks:()=>H0,reconcileMoveBeliefs:()=>L0,reconcileNodeUpdateNotices:()=>t0,reconcileSubtaskOutcome:()=>$N,refreshStandingInstructions:()=>S0,refuseIfTransferred:()=>ic,rehydrateLead:()=>oc,removeTrackRepo:()=>Jh,renameTrack:()=>I0,reposOf:()=>Qt,reshapeTrack:()=>b0,resolveTrackBox:()=>uu,resolveTrackBoxByHookToken:()=>nc,restartLead:()=>Qh,resumeAgentCmd:()=>Uh,reviveLeadForSession:()=>_0,sayToLead:()=>Ht,sendOptionsForAgent:()=>ar,setTrackDraft:()=>m0,setTrackModel:()=>w0,staleTransferNotice:()=>B0,startLeadHandoff:()=>em,startSpinUpView:()=>p0,startSubtask:()=>W0,startTransferOut:()=>D0,stopJobActive:()=>du,subtaskMessages:()=>o0,trackMessages:()=>Wh,unarchiveTrack:()=>sc});import Z from"node:fs/promises";import Y from"node:path";import{randomUUID as Hu,createHash as Vz}from"node:crypto";import{execFile as zz}from"node:child_process";import{promisify as Jz}from"node:util";function Qk(e,{skipPermissions:t=!0,model:n=null}={}){let r=Fh[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=qy(e).find(i=>i.alias===n);if(!a)throw new Error(`unknown ${e} launch model "${n}"`);s+=` --model ${a.alias}`}return s}function Uh(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=Fh[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&&!On(r,t)){let c=o&&qe(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 ba(e){let t=Fh[e];if(t)return process.env[t.envVar]||t.base}async function Hh({maxAgeMs:e=6e4}={}){if(ts.value&&Date.now()-ts.at<e)return ts.value;let t=ts.value,n=await Promise.all(Wu.map(async r=>{let o=await fp(ba(r),{retries:[]});return o===Ja?[r,t?.[r]??!0]:[r,o===pp]}));return ts.value=Object.fromEntries(n),ts.at=Date.now(),ts.value}async function tc(e,t=!0,n=null){let r=Qk(e,{skipPermissions:t,model:n});if(await fp(r)===za){ts.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.":Ww[o]?`Install it on this node: ${Ww[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 sN(e,t=rs){return`${e.trim()}
|
|
320
|
+
`),await _k.rename(d,a),r.log?.(`[spine-pull] rehydrated ${o}: ${l.length} event(s) \u2192 ${a}`),{restored:!0,rows:l.length}}var Tz,Ez,_z,BC=K(()=>{_t();be();Tz=1e3,Ez=5e5,_z=3e4});function LC(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 jC(e){let t=(e||[]).filter(n=>!$z.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 FC({archivedAt:e=null,archiving:t=!1,prompted:n=!1,openActions:r=0,openActionSince:o=null,loopAttention:s=!1,question:a=null,prDecisions:i=null,operation:c=null,phase:l=null,working:u=!1,workingSince:d=null,pending:p=null,interrupted:w=null,completedTurnAt:m=null,live:h=!1,now:g=Date.now()}={}){if(e&&!t)return dn("archived","lifecycle",e);if(n)return dn("needs-you","pane",o||g,{count:r||1});if(t)return dn("archiving","lifecycle",e||g);if(c?.status==="working")return dn("working","operation",c.since,{summary:c.summary??null,count:c.count??null});if((u||n)&&l?.phase)return dn("working","agent-phase",l.at,{summary:l.summary??null});if(u)return dn("working","pane",d||g);if(r>0||s||a?.at){let y=a?.at&&!s&&r<=1;return dn("needs-you",s?"loop":y?"question":"obligations",(y?a.at:o)||g,{count:r||1,...y?{summary:a.summary??null}:{}})}if(i?.count)return dn("needs-you","pr",i.since,{count:i.count,summary:i.summary??null});if(w?.at){let y=c?.status==="waiting"?c.summary:p?.count?p.summary:null,b=[w.summary,y].filter(Boolean).join(" \xB7 ")||null;return dn("interrupted",w.source||"interrupted",w.at,{summary:b})}return c?.status==="waiting"?dn("waiting","operation",c.since,{summary:c.summary??null,count:c.count??null}):p?.count?dn("waiting",p.source||"pending",p.since,{summary:p.summary??null,count:p.count}):m&&h?dn("settled","obligations",m,{summary:"no open actions"}):dn("idle","fallback",m||g)}var dn,$z,UC=K(()=>{dn=(e,t,n,r={})=>({kind:e,source:t,since:n||0,...r});$z=new Set(["merged","closed","lost"])});import Ik from"node:fs/promises";async function Oz(e){let t;try{t=await Ik.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/Rz*1e3,ioBytes:await Mz(e)}}async function Mz(e){let t;try{t=await Ik.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 HC(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 Ik.readdir("/proc")}catch{return null}let r=new Map;await Promise.all(n.map(async l=>{if(!/^\d+$/.test(l))return;let u=await Oz(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 Rz,WC=K(()=>{Rz=100});import Cz from"node:fs/promises";function Mk(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 Ck(e,t,n){let r=null;try{r=await n.updatedAt(e)}catch{r=null}let o=qC.get(e.name);if(o&&o.mtime===r&&t-o.at<Lz)return o.jobs;let s=[];try{s=await n.readOpenJobs(e)}catch{s=[]}return qC.set(e.name,{at:t,mtime:r,jobs:s}),s}async function jz(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 Fz(e,t){return e?.outputFile?await t.statFile(e.outputFile):null}function Uz(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>=Dz||t.ioBytes!=null&&e.ioBytes!=null&&(t.ioBytes-e.ioBytes)/n>=Bz}function GC(e,t,n,r){let o=[];for(let s of n){let a=Ok(e.id,t.name,s.id),i=qn.get(a);i?i.job=s:qn.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 KC(e,{now:t=Date.now(),deps:n=Rk}={}){let o=(await Promise.all(Mk([e]).map(({box:s})=>Ck(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 VC(e,{now:t=Date.now(),deps:n=Rk}={}){let r=new Map,o=new Set;for(let{track:s,box:a}of Mk(e)){let i=await Ck(a,t,n);for(let l of i)o.add(Ok(s.id,a.name,l.id));let c=GC(s,a,i,t).filter(l=>!qn.get(l).stalled).map(l=>qn.get(l).job);c.length&&r.set(s.id,[...r.get(s.id)??[],...c])}for(let s of[...qn.keys()])o.has(s)||qn.delete(s);return r}async function Hz(e,{now:t=Date.now(),deps:n=Rk}={}){let r={checked:0,progressing:0,quiet:0,stalled:[]},o=Mk(e),s=new Set(o.map(({box:a})=>a.name));for(let[a,i]of[...qn])s.has(i.boxName)||qn.delete(a);for(let{track:a,box:i}of o){let c=await Ck(i,t,n),l=new Set(c.map(m=>Ok(a.id,i.name,m.id)));for(let[m,h]of[...qn])h.boxName===i.name&&!l.has(m)&&qn.delete(m);if(!c.length){$k.delete(i.name);continue}let u=GC(a,i,c,t),d=await jz(i,t,n),p=$k.get(i.name);$k.set(i.name,d);let w=Uz(p,d);for(let m of u){let h=qn.get(m);r.checked++;let g=await Fz(h.job,n),y=!!g&&!!h.file&&(g.size>h.file.size||g.mtimeMs>h.file.mtimeMs),b=!!g&&!h.file;if(h.file=g??h.file,w||y||b){h.quiet=0,h.lastProgressAt=t,h.stalled=!1,r.progressing++;continue}if(h.stalled||(h.quiet++,r.quiet++,h.quiet<Pz))continue;h.stalled=!0,h.stalledAt=t,r.stalled.push(m);let v=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:v,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(v/6e4)}m over ${h.quiet} check(s) \u2014 released; the node may sleep`)}}return r}function zC({listTracks:e,intervalMs:t=Nz}={}){let n=!1,o=setInterval(async()=>{if(!n){n=!0;try{await Hz(await e())}catch(s){console.error(`[job-watch] sweep: ${s?.message||s}`)}finally{n=!1}}},t);return o.unref?.(),o}var Nz,Pz,Dz,Bz,Lz,Rk,qn,qC,$k,Ok,Nk=K(()=>{be();Jp();kt();WC();Nz=Number(process.env.BOSTRAT_JOB_CHECK_MS)||15*6e4,Pz=Number(process.env.BOSTRAT_JOB_STALL_CHECKS)||3,Dz=Number(process.env.BOSTRAT_JOB_CPU_RATE_MIN)||25,Bz=Number(process.env.BOSTRAT_JOB_IO_RATE_MIN)||64*1024,Lz=5*6e4,Rk={readOpenJobs:zp,statFile:async e=>{try{let t=await Cz.stat(e);return{size:t.size,mtimeMs:Math.round(t.mtimeMs)}}catch{return null}},updatedAt:e=>Oo(e.agent).updatedAt(e),panePids:CA,treeStats:HC,appendEvent:D},qn=new Map,qC=new Map,$k=new Map,Ok=(e,t,n)=>`${e}|${t}|${n}`});import Wz from"node:fs/promises";import qz from"node:os";import Oh from"node:path";async function Pk(e){try{return(await Wz.stat(e)).size}catch{return null}}async function Ki(e){let[t,n,r]=await Promise.all([Pk(Oh.join(Gz,"CLAUDE.md")),e?Pk(Oh.join(e,"CLAUDE.md")):null,e?Pk(Oh.join(e,".bostrat","memory","MEMORY.md")):null]);return{bostratClaudeMd:t,repoClaudeMd:n,memoryIndex:r}}var Gz,Dk=K(()=>{Gz=process.env.BOSTRAT_STATE_DIR||Oh.join(process.env.HOME||qz.tmpdir(),".bostrat")});import{randomUUID as Kz}from"node:crypto";async function Ch(e,t,n={}){let r={operationId:Kz(),kind:t,startedAt:Date.now(),...n};return Mh.set(e.id,r),await D(e,{type:"track.operation.changed",actor:"orchestrator",source:"orchestrator",payload:{ts:r.startedAt,state:"started",...r}}).catch(()=>{}),r}async function Bk(e,t,n="completed",r=null){Mh.get(e.id)?.operationId===t?.operationId&&Mh.delete(e.id),await D(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 Mh,JC,Lk=K(()=>{be();Mh=new Map;JC=e=>Mh.get(e)||null});var CN={};nw(CN,{HANDOFF_LATEST_REL:()=>rs,KNOWN_AGENTS:()=>Wu,LOGIN_GREETING:()=>fN,TRACK_NAME_MAX:()=>Fu,_resetRestartRefusalsForTest:()=>s8,addTrackRepo:()=>zh,adoptTrack:()=>U0,agentAvailability:()=>Hh,announceNodeUpdate:()=>vr,answerFullscreenOffer:()=>O0,answerPrompt:()=>qh,answeringFor:()=>s0,archiveTrack:()=>xa,archiveTrackForMergedPr:()=>Gr,augmentFirstPromptAfterHandoff:()=>sN,buildAgentCmd:()=>Qk,canResumeSubtask:()=>RN,cancelQueued:()=>Kh,cancelQueuedToDraft:()=>c0,cancelQueuedWhere:()=>mN,cancelStopJob:()=>ka,cancelSubtask:()=>rm,changedRepos:()=>ha,commitTransferOut:()=>tm,createSetupTrack:()=>v0,createTrack:()=>Xh,deleteTrack:()=>T0,demoteTransferredTracks:()=>j0,ensureLeadEpochs:()=>ns,forceMergeSubtask:()=>q0,getHandoffJob:()=>ac,getReshapeJob:()=>qu,getSubtaskJob:()=>w8,getTrack:()=>ye,getTransferOutJob:()=>P0,healDeadLead:()=>ju,interruptLead:()=>Vh,isArchiving:()=>Z3,isHandoffNoteEcho:()=>Kk,isInterruptEcho:()=>Vk,isLeadStarting:()=>dN,isModelSwitchEcho:()=>zk,leadCliDead:()=>Gu,listSubtaskJobs:()=>va,listTracks:()=>xe,matchTranscriptsToBoxes:()=>lN,mergeNotifyMessage:()=>EN,navigatePrompt:()=>a0,notifyTrackForMergedPr:()=>Kr,notifyTrackForResolvedPr:()=>Zh,offerFollowupsForMergedPr:()=>Sa,pendingOffers:()=>r0,queueGauges:()=>i0,queueShipCompleteNotify:()=>d0,queuedMessages:()=>ss,rawTrack:()=>n0,reapArchivedOrphans:()=>R0,reconcileDemotedTracks:()=>$0,reconcileHandoffOutcome:()=>_N,reconcileInterruptedHandoffs:()=>C0,reconcileInterruptedReshapes:()=>k0,reconcileInterruptedSubtasks:()=>H0,reconcileMoveBeliefs:()=>L0,reconcileNodeUpdateNotices:()=>t0,reconcileSubtaskOutcome:()=>$N,refreshStandingInstructions:()=>S0,refuseIfTransferred:()=>ic,rehydrateLead:()=>oc,removeTrackRepo:()=>Jh,renameTrack:()=>I0,reposOf:()=>Qt,reshapeTrack:()=>b0,resolveTrackBox:()=>uu,resolveTrackBoxByHookToken:()=>nc,restartLead:()=>Qh,resumeAgentCmd:()=>Uh,reviveLeadForSession:()=>_0,sayToLead:()=>Ht,sendOptionsForAgent:()=>ar,setTrackDraft:()=>m0,setTrackModel:()=>w0,staleTransferNotice:()=>B0,startLeadHandoff:()=>em,startSpinUpView:()=>p0,startSubtask:()=>W0,startTransferOut:()=>D0,stopJobActive:()=>du,subtaskMessages:()=>o0,trackMessages:()=>Wh,unarchiveTrack:()=>sc});import Z from"node:fs/promises";import Y from"node:path";import{randomUUID as Hu,createHash as Vz}from"node:crypto";import{execFile as zz}from"node:child_process";import{promisify as Jz}from"node:util";function Qk(e,{skipPermissions:t=!0,model:n=null}={}){let r=Fh[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=qy(e).find(i=>i.alias===n);if(!a)throw new Error(`unknown ${e} launch model "${n}"`);s+=` --model ${a.alias}`}return s}function Uh(e,t,{skipPermissions:n=!0,cwd:r=null,peerName:o=null}={}){let s=Fh[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&&!On(r,t)){let c=o&&qe(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 ba(e){let t=Fh[e];if(t)return process.env[t.envVar]||t.base}async function Hh({maxAgeMs:e=6e4}={}){if(ts.value&&Date.now()-ts.at<e)return ts.value;let t=ts.value,n=await Promise.all(Wu.map(async r=>{let o=await fp(ba(r),{retries:[]});return o===Ja?[r,t?.[r]??!0]:[r,o===pp]}));return ts.value=Object.fromEntries(n),ts.at=Date.now(),ts.value}async function tc(e,t=!0,n=null){let r=Qk(e,{skipPermissions:t,model:n});if(await fp(r)===za){ts.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.":Ww[o]?`Install it on this node: ${Ww[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 sN(e,t=rs){return`${e.trim()}
|
|
321
321
|
|
|
322
322
|
(Read ${t} ${ml}`}function Kk(e){return e.role==="user"&&Zz.test((e.text||"").trim())}async function te(){return Zt||(jk||=(async()=>{try{Zt=JSON.parse(await Z.readFile(oN,"utf8"))}catch{Zt={tracks:[]}}finally{jk=null}return Zt})(),jk)}async function de(){await dt(oN,Zt)}function t3(e,t){let n=JSON.stringify({trackId:e,...t})+`
|
|
323
|
-
`;return Fk=Fk.then(()=>Z.mkdir(xr,{recursive:!0})).then(()=>Z.appendFile(Yz,n)).catch(()=>{}),Fk}async function aN(e,{box:t,agent:n,message:r}){let o=he(await te(),e);!o||o.archivedAt||(Me(o,"startup-gate",{box:t,agent:n??null,message:r}),await de(),Js(o,{provider:n??null,cls:"startup-gate",note:r}).catch(()=>{}))}async function vr({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 Z.readFile(Uk,"utf8"))}catch{}if(d?.latest===t&&d?.current===e)return{announced:0,deduped:!0}}let l=await te(),u=0;for(let d of l.tracks)He(d)||!d.leadBox||(Me(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 de().catch(()=>{}),s==="available")try{await Z.mkdir(Y.dirname(Uk),{recursive:!0}),await Z.writeFile(Uk,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function t0({current:e,installKind:t=null,policy:n=null}={}){if(!e)return{reconciled:!1,announced:0,targets:[]};let r=await te(),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)||n3(e,c)||(Me(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 de().catch(()=>{}),{reconciled:o>0,announced:o,targets:[...s]}}function n3(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 iN(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=>r3.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 cN(e,t,n,{kind:r,detail:o}={}){let s=await _e(t);if(!s)throw new Error(`box "${t}" is not running`);let a=ba(s.agent),i=fu({text:n,producer:pu({kind:r,orchestration:!0}),kind:r||"orchestration",provider:s.agent}),c=he(await te(),e)||null,l=Date.now(),u=null;try{u=await Mr({cwd:s.cwd,sessionId:s.sessionId,sessionName:t,agent:s.agent,agentCmd:a})}catch(y){throw mu(i,{ms:Date.now()-l,outcome:y?.code==="cli-not-running"?"cli-not-running":"blocked"}),await Un(c,i,Li(y)),y}mu(i,{ms:Date.now()-l,outcome:u||"up"});let d=ar(s.agent,n);i.paste=!!d.paste;try{await ot(t,n,{...d,kind:r||"orchestration"})}catch(y){throw await Un(c,i,Li(y)),y}let p={},w=await Tl({sessionName:t,agent:s.agent,agentCmd:a,text:n,trackId:e,flow:"orchestration",stats:p});i.verify=p,await Un(c,i,w?p.verdict==="unverified"?"unverified":"delivered":"unsubmitted"),await ne({flow:"orchestration",phase:"sent",submitted:w,trackId:e,sessionName:t,agent:s.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let m=await te(),f=he(m,e);if(!f)return;let g=f.boxes.find(y=>y.name===t);Me(f,"orchestration-prompt",{box:t,agent:g?.agent||s.agent,boxRole:g?.role,prompt:n,kind:r||"orchestration",deliveryId:i.id,...o?{detail:o}:{}}),await de()}async function o3(e){let t=Y.join(Wa(e),`${e.id}.ndjson`),n;try{n=await Z.stat(t)}catch{return null}let r=YC.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await V(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return YC.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function s3(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:$o(n.name,n.agent)}async function pn(e,t=null,n=null){let r=t??new Map((await sn()).map(S=>[S.name,S])),o=!!e.transferredTo,s=e.boxes.map(S=>{S.launchEcho&&!o&&li(S.name,S.launchEcho);let E=o?null:r.get(S.name),P=oo.has(S.state)?S.state:E?S.role==="lead"?"live":S.state:"stopped";return{...S,state:P,cwd:E?.cwd||S.cwd,agent:E?.agent||S.agent,sessionId:E?.sessionId||S.sessionId}}),[a,{working:i,prompted:c,awaitingBackground:l=null},u,d,p]=await Promise.all([o3(e),s3(e,s),vb(e),n??Ln().catch(()=>[]),KC({...e,boxes:s})]),w=Lu.has(e.id),m=(d||[]).filter(S=>S.trackId===e.id&&!["merged","closed","lost"].includes(S.state)),f=JC(e.id),g=f&&{status:"waiting",since:f.startedAt,summary:f.summary??null,count:f.count??null}||LC(m),y=s.find(S=>S.name===e.leadBox)?.state==="live",b=y?ss(e.id).filter(S=>S.kind!=="ship-notify"&&S.kind!=="prompt-answer"&&S.kind!=="login-greet"):[],x=p||(y&&l?{source:"pane",count:l.count||1,since:u.completedTurnAt||a||Date.now(),summary:l.summary||"waiting for background jobs to finish"}:y&&u.runningJobs?{source:"jobs",count:u.runningJobs,since:u.runningJobsSince,summary:u.runningJobs===1?"a background job is still running":`${u.runningJobs} background jobs are still running`}:b.length?{source:"queue",count:b.length,since:Math.min(...b.map(S=>S.ts||Date.now())),summary:"a queued message is about to send"}:null),v=FC({archivedAt:e.archivedAt,archiving:w,prompted:c,openActions:u.openActions,openActionSince:u.openActionSince,question:u.question,prDecisions:jC(m),operation:g,phase:u.phase,working:i,workingSince:u.currentTurnAt,pending:x,interrupted:u.interrupted,completedTurnAt:u.completedTurnAt||a,live:y});return{...e,boxes:s,lastResponseAt:a,working:i,prompted:c,archiving:w,status:v}}function lN(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-a3,p=r[u+1]?.createdAt??1/0,w=o.find(m=>!s.has(m.id)&&m.birthMs>=d&&m.birthMs<p);w&&(s.add(w.id),c.push({box:l.name,sessionId:w.id}))}return c}async function uN(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=WA(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=lN(u,a,p=>i.has(p));for(let p of d){let w=u.find(m=>m.name===p.box);w&&(w.sessionId=p.sessionId),await MA(p.box,p.sessionId),n=!0}}return n}async function xe(){let e=await te();await uN(e)&&await de();let t=new Map((await sn()).map(r=>[r.name,r])),n=await Ln().catch(()=>[]);return Promise.all(e.tracks.map(r=>pn(r,t,n)))}async function uu(e,t){let n=await te();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 nc(e){let t=Ss(e);if(!t)return null;let n=await te();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&QS(o.hookTokenHash,t))return{track:r,box:o};return null}async function n0(e){return he(await te(),e)??null}async function ye(e){let t=await te(),n=he(t,e);return n?(await uN(t)&&await de(),pn(n)):null}async function r0(e){let t=await V(e).catch(()=>[]),n;try{n=ir(t)}catch{return[]}let r=Bp(n).map(s=>({kind:s.kind,id:s.offerId??s.proposalId??s.id,ts:s.ts??null})),o=[];try{o=sE(t)}catch{o=[]}return r.concat(o.map(s=>({kind:"pr-open",id:`${s.repo??""}#${s.number}`,ts:null})))}function Vk(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(i3[e.agent]||[]).some(n=>n.test(t))}function zk(e){let t=(e.text||"").trim();return t?c3.some(n=>n.test(t)):!1}function dN(e,t,n=Date.now()){return!e||e.readyAt||e.state!=="live"?!1:n-(t||0)<l3}async function Wh(e,t={}){let n=await ye(e);if(!n)return null;let r=new Set([...n.events.filter(N=>N.type==="orchestration-prompt"&&N.prompt).map(N=>String(N.prompt).trim()),...n.events.filter(N=>N.type==="said"&&N.text).map(N=>String(N.text).trim())]),o=ac(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=Jb(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...bM(n),...l],p={windows:[...b_(n),...k_(n,Zp),...a,...u]},m=(await Promise.all(n.boxes.map(N=>Fg(N,t)))).flat(),f=[],g=m.map(N=>{let le={kind:"message",...N};if(le.role==="assistant"&&(le.text||"").trim()&&le.tools?.length){let pe=Oo(le.agent).cliTools,$e=le.tools.filter(Qe=>!pe.has(Qe));return{...le,tools:$e.length?$e:void 0}}return le}).map(N=>{if(N.role!=="user")return N;let le=wT(N);return le?le.kind==="suppress"?null:{...N,note:le,text:ig(le)}:N}).filter(Boolean).filter(N=>!(N.role==="user"&&r.has((N.text||"").trim()))).map(N=>{if(N.role!=="user"||N.note)return N;let le=Ap(N.text,r);if(!le)return N;let pe={kind:"cut-delivery",...le};return{...N,note:pe,text:ig(pe)}}).filter(N=>Vk(N)?(f.push(N),!1):!0).filter(N=>!zk(N)).filter(N=>!Kk(N)).filter(N=>!kk(N)).filter(N=>N.role!=="assistant"||!!(N.text||"").trim()||!!N.images?.length).filter(N=>!x_(N,p)),y=g.filter(N=>N.failed&&N.text===Ps);if(y.length){let N=new Map;for(let le of y){if(!N.has(le.box)){let Qe=[...(await Fe(le.box,{lines:rt}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(Je=>Je[1]);N.set(le.box,Qe.length?Qe[Qe.length-1]:null)}let pe=N.get(le.box);pe&&(le.text=`\u25A0 ${pe}`)}}let b=await Promise.all(n.boxes.map(N=>ZE(N,t)));await VO(n,b.flat());let{agentTurnBoxes:x}=await GO(n,g);await qO(n,f);for(let N of n.boxes)x.has(N.name)&&N.cwd&&ep(N.cwd);await u$(n),await AM(n,g).catch(()=>{});for(let N of n.boxes)N.agent==="codex"&&N.state==="live"&&await JO(n,N),N.agent==="cursor"&&N.state==="live"&&await eM(n,N);let v=await Promise.all(n.boxes.map(N=>XE(N,t)));await KO(n,v.flat().filter(N=>!Hk(N.box,N.ts,u)));let S=await V(n),E=c&&i.viewId?i.viewId:null,P=ER(S),L=ir(S).filter(N=>!(N.kind==="message"&&(Vk(N)||zk(N)||Kk(N)||kk(N)))&&!(N.kind==="view-card"&&E&&N.viewId===E)),$=_R(L,P),C=L.filter(N=>!(N.kind==="message"&&N.role==="assistant"&&!$.has(N)&&Hk(N.box,N.ts,P))),U=Sg(S,C).map(N=>({kind:"command-batch",id:N.id,ts:N.pending?N.ts:(N.anchorTs??N.ts)-1,anchorTs:N.anchorTs,anchorBox:N.anchorBox,agent:N.agent,boxRole:N.boxRole,commands:N.commands,pending:N.pending})).filter(N=>!Hk(N.anchorBox,N.anchorTs??N.ts,u)),J=rE(oE([...C,...U].filter(N=>N.ts!=null).sort((N,le)=>N.ts-le.ts))),_=u3(n),I=_.size?J.filter(N=>N.kind==="event"||!_.has(N.box??N.anchorBox)):J,T=n.boxes.find(N=>N.name===n.leadBox)||null,F=T?await cl(T.cwd,T.sessionId,{fallbackNewest:!1}):null;if(!F&&T){let N=[...S].reverse().find(le=>le.type==="context.usage"&&le.boxId===T.name);N?.payload?.window&&(F={pct:N.payload.pct??(N.payload.occupancy!=null?N.payload.occupancy/N.payload.window:null),occupancy:N.payload.occupancy??null,window:N.payload.window,windowKnown:!0,model:N.payload.model||null})}let W=[...m].reverse().find(N=>N.role==="assistant"&&N.model),ce=W?.model||null,z=[...n.events||[]].reverse().find(N=>N.type==="model-change"),Ke=F?.model||ce;z&&(!W?.ts||z.at>=W.ts)&&(Ke=z.to);let Ie=T?cn(T.name,await Fe(T.name,{lines:rt}).catch(()=>"")):"",X=T&&Io(T.agent,Ie)?await an(T.name).catch(()=>Ie):Ie,re=T?Cn(T,X):null;if(T&&so.has(n.id)){let N=/^claude:model-confirm:/.test(re?.promptId||"");await W3(n.id,X,N).catch(()=>{})}if(T&&s0(T.name,re,X)&&re&&(re={...re,answering:!0}),re&&T){let N=Wp(T,re,X);if(N){let le=$E(T.name,re.promptId);le.action!=="give-up"&&(le.action==="send"&&(N.accept&&$p(T.name,X),(!N.gate||Ao(T.name,N.gate))&&tt(T.name,N.keys,{kind:N.accept?"auto-accept":"auto-reject"}).catch(()=>{}),le.first&&D(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:T.name,provider:T.agent,payload:{ts:Date.now(),promptId:re.promptId,rule:N.id}}).catch(()=>{})),re=null)}}T&&(re?.setup&&TT(T.name,X),!re&&gl(T.agent,Ie)&&_p(T.name)&&Ao(T.name,"login-issue")&&(Ip(T.name),ot(T.name,"/login",{enter:!0,submitDelayMs:600,kind:"login-issue"}).catch(()=>{}))),!re&&T&&!ci(T.agent,Ie)&&!ss(n.id).length&&(re=bg(I,{leadBoxId:T.name,provider:T.agent,isAnswered:N=>S.some(le=>le.type==="prompt.answered"&&le.payload?.promptId===N)})),re&&d$(n,T,re);let Te=I.filter(N=>!(N.kind==="message"&&N.role==="assistant"&&N.ask&&!String(N.text||"").trim()&&!N.images?.length)),ie=!!T&&qp(T.name,T.agent,Ie)&&!re;if(T&&!T.readyAt&&(ie||re||Ie&&To(T.agent,Ie))){T.readyAt=Date.now();let N=he(await te(),n.id)?.boxes?.find(le=>le.name===T.name);N&&!N.readyAt&&(N.readyAt=T.readyAt,await de())}let Pe=dN(T,n.createdAt),ve=!!T&&!!Ie&&To(T.agent,Ie)&&!re&&!gl(T.agent,Ie)&&!ii(T.agent,Ie),ee=!1;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&T){if(ve){let N=await te(),le=he(N,n.id);le?.setup&&!le.setup.connectedAt&&(le.setup.connectedAt=Date.now(),n.setup.connectedAt=le.setup.connectedAt,ee=!0,await de())}}else T&&ve&&AT(T.name)&&(ee=!0);if(ee&&ET(T.name),T){let N=_T(T.name),le=vT(T.name);N.started&&D(n,{type:"provider.login.started",actor:"system",source:"pane",boxId:T.name,provider:T.agent,payload:{provider:T.agent,reason:le?.startedReason||"auth-screen",ts:Date.now()}}).catch(()=>{}),N.connected&&(await D(n,{type:"provider.connected",actor:"system",source:"pane",boxId:T.name,provider:T.agent,payload:{provider:T.agent,ts:le?.connectedAt||Date.now(),...le?.account?{account:le.account}:{},reason:le?.startedReason||"already-signed-in"}}).catch(()=>{}),n.kind!=="setup"&&le?.startedReason&&!b3(n.id)&&Ht(n.id,fN,{kind:"login-greet"}).catch(pe=>{console.warn(`[track ${n.id}] login greeting not delivered: ${pe?.message||pe}`)}))}let ge=s?{running:!0,step:o.step,toAgent:o.toAgent||null,wait:o.wait||null}:null,Ve=qu(n.id),ze=Ve&&!Ve.finishedAt?{running:!0,step:Ve.step||null,added:Ve.added||[],removed:Ve.removed||[]}:null,Ze=null;if(c){let N=Date.now()-i.startedAt;if(i.viewId&&!ie){let le=yh(n.id);le&&(Me(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:le.finishedAt}),await de())}else if(re||N>gM&&!ie&&!i.viewId||N>zb){let le=re?"needs-input":N>zb?"timeout":"no-view";yh(n.id,{error:le})&&await D(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:T?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:le}}).catch(()=>{})}else Ze={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:Te,context:F?{pct:F.pct,occupancy:F.occupancy,window:F.window,windowKnown:F.windowKnown,model:F.model}:null,models:{current:Ke,options:qy(T?.agent)},pendingPrompt:re,working:ie,stopping:du(n.id),leadStarting:Pe,handoff:ge,reshape:ze,view:Ze,queued:ss(n.id).filter(N=>N.kind!=="ship-notify"&&N.kind!=="prompt-answer"&&N.kind!=="login-greet"),draft:n.draft||null,draftRev:n.draftRev||0}}function u3(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 o0(e,t){let n=await ye(e);if(!n)return null;let r=va(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 V(n),a=ir(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=Sg(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 Fe(o,{lines:rt}).catch(()=>"");u=qp(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}function d3(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>XC)throw new Error(`custom answer is too long (max ${XC} characters)`);return r})}function p3(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 s0(e,t,n,r=Date.now()){let o=Jk.get(e);if(!o)return!1;let s=!!t&&t.promptId===o.promptId&&r-o.at<f3&&(t.setup?!0:pN(n)===o.paneHash);return s||Jk.delete(e),s}async function m3(e,t,n){let r=n;for(let o of h3){await Sr(o);let s=await an(e).catch(()=>null);if(s!=null&&(r=s,s!==n))break}Jk.set(e,{promptId:t.promptId,paneHash:pN(r),setup:t.setup||null,at:Date.now()})}async function qh(e,t={}){let n=Iu.get(e);n&&await n.catch(()=>{});let r=w3(e,t);Iu.set(e,r);try{return await r}catch(o){let s=so.get(e);throw s&&(s.answering=!1),o}finally{Iu.get(e)===r&&Iu.delete(e)}}async function w3(e,{promptId:t,answers:n,text:r,custom:o}={}){let s=he(await te(),e);if(!s)throw new Error(`track "${e}" not found`);ka(e,"prompt-answer");let a=s.boxes.find(v=>v.name===s.leadBox);if(!a)throw new Error(`track "${e}" has no lead box`);if(!await _e(s.leadBox))throw new Error(`lead box "${s.leadBox}" is not running`);let c=await an(a.name).catch(()=>""),l=Cn(a,c);if(l||(l=await g3(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");let d=/^claude:model-confirm:/.test(l.promptId||"")?so.get(s.id):null;if(d&&(d.answering=!0),l.answerMode!=="say"&&s0(a.name,l,c))throw new Error("prompt already answered \u2014 waiting for the CLI to move on");let p=d3(o,l.questions?.length??1);if(p.some(Boolean)&&!l.custom)throw new Error("custom answer isn't available for this prompt \u2014 pick one of its options");let w=(n||[]).some(v=>Array.isArray(v)&&v.length>0);if(l.custom&&!w&&!p.some(Boolean)&&l.answerMode!=="text")throw new Error("no answer selected \u2014 pick an option or type your own");p.some(Boolean)&&(n=(l.questions||[]).map((v,S)=>p[S]&&!v.multiSelect?[]:Array.isArray(n?.[S])?n[S]:[]));let m;if(l.answerMode==="text"){let v=typeof r=="string"?r.trim():"";if(!v)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(v)||v.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await ot(s.leadBox,v,{enter:!0,kind:"answer-prompt"}),m={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(l.answerMode==="esc")await tt(s.leadBox,["Escape"],{kind:"answer-prompt"}),m={mode:"keys",value:"Escape",count:1};else if(l.answerMode==="say"){let v=QT(l,n||[],typeof r=="string"?r:"",p);if(!v)throw new Error("no answer selected \u2014 pick an option or reply in chat");await Ht(s.id,v,{kind:"prompt-answer"}),m={mode:"say",value:v,count:1}}else if(p[0]&&l.provider==="claude"){let v=TE(l,n||[],p[0]);await qw(s.leadBox,[...v.pre,{text:v.text}],{kind:"answer-prompt"});let S=!1;for(let P of[150,300,600]){await Sr(P);let L=await an(s.leadBox).catch(()=>""),$=Cn(a,L,{customIndex:l.customIndex});if($?.customText&&p3($.customText,v.text)){S=!0;break}}if(!S)throw new Error("custom answer didn't take \u2014 the widget moved; reload and answer again");await qw(s.leadBox,v.post,{kind:"answer-prompt"});let E=P=>P.map(L=>L.count>1?`${L.key}\xD7${L.count}`:L.key).join(" ");m={mode:"keys+text",value:`${E(v.pre)} \u2039text\u203A ${E(v.post)}`.trim(),count:v.pre.length+1+v.post.length}}else if(l.provider==="claude"||l.answerMode==="keys"){let v=$g(l,n||[]);await tt(s.leadBox,v,{kind:"answer-prompt"}),m={mode:"keys",value:v.join(" "),count:v.length}}else{let v=CT(l,n||[]);await ot(s.leadBox,v,{enter:!0,kind:"answer-prompt"}),m={mode:"text",value:v,count:1}}if(l.answerMode!=="say"&&await m3(a.name,l,c),l.answerMode==="say"){let v=l.questions||[];for(let S=0;S<v.length;S++){let E=v[S],P=new Set(Array.isArray(n?.[S])?n[S]:[]),L=[...P].map(C=>E.options?.[C]).filter(Boolean).map(C=>({label:C.label,description:C.description||""}));p[S]&&L.push({label:p[S],description:"",custom:!0});let $=(E.options||[]).map((C,U)=>P.has(U)?null:C?.label).filter(Boolean);Gy(s,a,l,{...m,groupId:l.groupId||l.promptId,questionIndex:S,questionTotal:l.questionTotal??v.length,header:E.header||"",question:E.question||"",multiSelect:!!E.multiSelect,chosen:L,rejected:$})}return await ne({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:l.provider,promptId:l.promptId,...m}).catch(()=>{}),{ok:!0,promptId:l.promptId,sent:m.count}}let f=l.questions?.[0]||{},g=new Set(Array.isArray(n?.[0])?n[0]:[]),y=[...g].map(v=>f.options?.[v]).filter(Boolean).map(v=>({label:v.label,description:v.description||""}));p[0]&&y.push({label:p[0],description:"",custom:!0});let b=(f.options||[]).map((v,S)=>g.has(S)?null:v?.label).filter(Boolean),x=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;if(m={...m,groupId:l.groupId||l.promptId,questionIndex:l.questionIndex??0,questionTotal:l.questionTotal??1,header:f.header||"",question:f.question||"",multiSelect:!!f.multiSelect,chosen:y,rejected:b,...x?{control:x}:{}},await ne({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:l.provider,promptId:l.promptId,...m}).catch(()=>{}),Gy(s,a,l,m),d){let v=y.some(S=>/^yes\b/i.test(S.label));kN(s,v)&&await de()}return{ok:!0,promptId:l.promptId,sent:m.count}}async function g3(e,t){if(!t)return null;let n=await V(e).catch(()=>[]);return bg(ir(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function a0(e,{promptId:t,questionIndex:n}={}){let r=he(await te(),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 _e(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await vE(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=EE(a,n);return c.length?(await tt(r.leadBox,c,{kind:"navigate-prompt"}),await ne({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 Gh(e){let t=os.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},os.set(e,t)),t}function b3(e){let t=os.get(e);return!!t&&(t.items.length>0||!!t.flushing)}function ss(e){return(os.get(e)?.items??[]).map(({delivery:t,...n})=>({...n}))}function i0(e=Date.now()){let t=0,n=0;for(let r of os.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 hN(e,t,n){let r=t.filter(o=>o.delivery&&!o.delivery.settled);r.length&&(async()=>{let o=he(await te(),e)||null;for(let s of r)await Un(o,s.delivery,`dropped:${n}`)})().catch(()=>{})}function Kh(e,t="cancel"){let n=os.get(e);if(!n)return[];let r=n.items.splice(0);return n.idleSince=null,n.timer&&(clearInterval(n.timer),n.timer=null),hN(e,r,t),r}function mN(e,t,n){let r=os.get(e);if(!r)return[];let o=r.items.filter(s=>n(s));return o.length?(r.items=r.items.filter(s=>!n(s)),r.items.length||(r.idleSince=null,r.timer&&(clearInterval(r.timer),r.timer=null)),hN(e,o,t),o):[]}async function c0(e){let t=Kh(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=he(await te(),e);if(o)return r=Pu(o,n),await de(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function l0(e){let t=Gh(e);t.timer||(t.timer=setInterval(()=>k3(e).catch(()=>{}),y3))}async function k3(e){let t=os.get(e);if(!(!t||t.flushing)){if(!t.items.length){t.timer&&(clearInterval(t.timer),t.timer=null);return}t.flushing=!0;try{let n=he(await te(),e);if(!n||n.archivedAt){Kh(e,"archived");return}let r=async(l,u="")=>{let d=[];for(let g of t.items)cM(g.delivery,l),IC(g,l)&&d.push(g);if(!d.length)return;t.items=t.items.filter(g=>!d.includes(g));let p=Date.now()-Math.min(...d.map(g=>g.heldSince||Date.now())),w=Math.max(1,Math.round(Sk()/6e4)),m=String(u||"").split(`
|
|
323
|
+
`;return Fk=Fk.then(()=>Z.mkdir(xr,{recursive:!0})).then(()=>Z.appendFile(Yz,n)).catch(()=>{}),Fk}async function aN(e,{box:t,agent:n,message:r}){let o=he(await te(),e);!o||o.archivedAt||(Me(o,"startup-gate",{box:t,agent:n??null,message:r}),await de(),Js(o,{provider:n??null,cls:"startup-gate",note:r}).catch(()=>{}))}async function vr({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 Z.readFile(Uk,"utf8"))}catch{}if(d?.latest===t&&d?.current===e)return{announced:0,deduped:!0}}let l=await te(),u=0;for(let d of l.tracks)He(d)||!d.leadBox||(Me(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 de().catch(()=>{}),s==="available")try{await Z.mkdir(Y.dirname(Uk),{recursive:!0}),await Z.writeFile(Uk,JSON.stringify({current:e,latest:t,at:Date.now()}))}catch{}return{announced:u}}async function t0({current:e,installKind:t=null,policy:n=null}={}){if(!e)return{reconciled:!1,announced:0,targets:[]};let r=await te(),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)||n3(e,c)||(Me(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 de().catch(()=>{}),{reconciled:o>0,announced:o,targets:[...s]}}function n3(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 iN(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=>r3.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 cN(e,t,n,{kind:r,detail:o}={}){let s=await _e(t);if(!s)throw new Error(`box "${t}" is not running`);let a=ba(s.agent),i=fu({text:n,producer:pu({kind:r,orchestration:!0}),kind:r||"orchestration",provider:s.agent}),c=he(await te(),e)||null,l=Date.now(),u=null;try{u=await Mr({cwd:s.cwd,sessionId:s.sessionId,sessionName:t,agent:s.agent,agentCmd:a})}catch(y){throw mu(i,{ms:Date.now()-l,outcome:y?.code==="cli-not-running"?"cli-not-running":"blocked"}),await Un(c,i,Li(y)),y}mu(i,{ms:Date.now()-l,outcome:u||"up"});let d=ar(s.agent,n);i.paste=!!d.paste;try{await ot(t,n,{...d,kind:r||"orchestration"})}catch(y){throw await Un(c,i,Li(y)),y}let p={},w=await Tl({sessionName:t,agent:s.agent,agentCmd:a,text:n,trackId:e,flow:"orchestration",stats:p});i.verify=p,await Un(c,i,w?p.verdict==="unverified"?"unverified":"delivered":"unsubmitted"),await ne({flow:"orchestration",phase:"sent",submitted:w,trackId:e,sessionName:t,agent:s.agent,kind:r||"orchestration",promptHead:n.slice(0,160)});let m=await te(),h=he(m,e);if(!h)return;let g=h.boxes.find(y=>y.name===t);Me(h,"orchestration-prompt",{box:t,agent:g?.agent||s.agent,boxRole:g?.role,prompt:n,kind:r||"orchestration",deliveryId:i.id,...o?{detail:o}:{}}),await de()}async function o3(e){let t=Y.join(Wa(e),`${e.id}.ndjson`),n;try{n=await Z.stat(t)}catch{return null}let r=YC.get(e.id);if(r&&r.mtimeMs===n.mtimeMs)return r.at;let o=null;for(let s of await V(e)){if(s.type!=="turn.agent")continue;let a=s.payload?.ts??s.ts;a&&(!o||a>o)&&(o=a)}return YC.set(e.id,{mtimeMs:n.mtimeMs,at:o}),o}async function s3(e,t){let n=t.find(r=>r.name===e.leadBox);return n?.state!=="live"?{working:!1,prompted:!1}:$o(n.name,n.agent)}async function pn(e,t=null,n=null){let r=t??new Map((await sn()).map(S=>[S.name,S])),o=!!e.transferredTo,s=e.boxes.map(S=>{S.launchEcho&&!o&&li(S.name,S.launchEcho);let E=o?null:r.get(S.name),P=oo.has(S.state)?S.state:E?S.role==="lead"?"live":S.state:"stopped";return{...S,state:P,cwd:E?.cwd||S.cwd,agent:E?.agent||S.agent,sessionId:E?.sessionId||S.sessionId}}),[a,{working:i,prompted:c,awaitingBackground:l=null},u,d,p]=await Promise.all([o3(e),s3(e,s),vb(e),n??Ln().catch(()=>[]),KC({...e,boxes:s})]),w=Lu.has(e.id),m=(d||[]).filter(S=>S.trackId===e.id&&!["merged","closed","lost"].includes(S.state)),h=JC(e.id),g=h&&{status:"waiting",since:h.startedAt,summary:h.summary??null,count:h.count??null}||LC(m),y=s.find(S=>S.name===e.leadBox)?.state==="live",b=y?ss(e.id).filter(S=>S.kind!=="ship-notify"&&S.kind!=="prompt-answer"&&S.kind!=="login-greet"):[],x=p||(y&&l?{source:"pane",count:l.count||1,since:u.completedTurnAt||a||Date.now(),summary:l.summary||"waiting for background jobs to finish"}:y&&u.runningJobs?{source:"jobs",count:u.runningJobs,since:u.runningJobsSince,summary:u.runningJobs===1?"a background job is still running":`${u.runningJobs} background jobs are still running`}:b.length?{source:"queue",count:b.length,since:Math.min(...b.map(S=>S.ts||Date.now())),summary:"a queued message is about to send"}:null),v=FC({archivedAt:e.archivedAt,archiving:w,prompted:c,openActions:u.openActions,openActionSince:u.openActionSince,question:u.question,prDecisions:jC(m),operation:g,phase:u.phase,working:i,workingSince:u.currentTurnAt,pending:x,interrupted:u.interrupted,completedTurnAt:u.completedTurnAt||a,live:y});return{...e,boxes:s,lastResponseAt:a,working:i,prompted:c,archiving:w,status:v}}function lN(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-a3,p=r[u+1]?.createdAt??1/0,w=o.find(m=>!s.has(m.id)&&m.birthMs>=d&&m.birthMs<p);w&&(s.add(w.id),c.push({box:l.name,sessionId:w.id}))}return c}async function uN(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=WA(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=lN(u,a,p=>i.has(p));for(let p of d){let w=u.find(m=>m.name===p.box);w&&(w.sessionId=p.sessionId),await MA(p.box,p.sessionId),n=!0}}return n}async function xe(){let e=await te();await uN(e)&&await de();let t=new Map((await sn()).map(r=>[r.name,r])),n=await Ln().catch(()=>[]);return Promise.all(e.tracks.map(r=>pn(r,t,n)))}async function uu(e,t){let n=await te();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 nc(e){let t=Ss(e);if(!t)return null;let n=await te();for(let r of n.tracks||[])for(let o of r.boxes||[])if(o.hookTokenHash&&QS(o.hookTokenHash,t))return{track:r,box:o};return null}async function n0(e){return he(await te(),e)??null}async function ye(e){let t=await te(),n=he(t,e);return n?(await uN(t)&&await de(),pn(n)):null}async function r0(e){let t=await V(e).catch(()=>[]),n;try{n=ir(t)}catch{return[]}let r=Bp(n).map(s=>({kind:s.kind,id:s.offerId??s.proposalId??s.id,ts:s.ts??null})),o=[];try{o=sE(t)}catch{o=[]}return r.concat(o.map(s=>({kind:"pr-open",id:`${s.repo??""}#${s.number}`,ts:null})))}function Vk(e){if(e.role!=="user")return!1;let t=(e.text||"").trim();return(i3[e.agent]||[]).some(n=>n.test(t))}function zk(e){let t=(e.text||"").trim();return t?c3.some(n=>n.test(t)):!1}function dN(e,t,n=Date.now()){return!e||e.readyAt||e.state!=="live"?!1:n-(t||0)<l3}async function Wh(e,t={}){let n=await ye(e);if(!n)return null;let r=new Set([...n.events.filter(N=>N.type==="orchestration-prompt"&&N.prompt).map(N=>String(N.prompt).trim()),...n.events.filter(N=>N.type==="said"&&N.text).map(N=>String(N.text).trim())]),o=ac(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=Jb(n.id),c=!!(i&&!i.finishedAt),l=c&&i.startedAt&&i.box?[{box:i.box,from:i.startedAt,to:Date.now()+1e12}]:[],u=[...bM(n),...l],p={windows:[...b_(n),...k_(n,Zp),...a,...u]},m=(await Promise.all(n.boxes.map(N=>Fg(N,t)))).flat(),h=[],g=m.map(N=>{let le={kind:"message",...N};if(le.role==="assistant"&&(le.text||"").trim()&&le.tools?.length){let pe=Oo(le.agent).cliTools,$e=le.tools.filter(Qe=>!pe.has(Qe));return{...le,tools:$e.length?$e:void 0}}return le}).map(N=>{if(N.role!=="user")return N;let le=wT(N);return le?le.kind==="suppress"?null:{...N,note:le,text:ig(le)}:N}).filter(Boolean).filter(N=>!(N.role==="user"&&r.has((N.text||"").trim()))).map(N=>{if(N.role!=="user"||N.note)return N;let le=Ap(N.text,r);if(!le)return N;let pe={kind:"cut-delivery",...le};return{...N,note:pe,text:ig(pe)}}).filter(N=>Vk(N)?(h.push(N),!1):!0).filter(N=>!zk(N)).filter(N=>!Kk(N)).filter(N=>!kk(N)).filter(N=>N.role!=="assistant"||!!(N.text||"").trim()||!!N.images?.length).filter(N=>!x_(N,p)),y=g.filter(N=>N.failed&&N.text===Ps);if(y.length){let N=new Map;for(let le of y){if(!N.has(le.box)){let Qe=[...(await Fe(le.box,{lines:rt}).catch(()=>"")).matchAll(/^\s*■\s+(.+?)\s*$/gm)].map(Je=>Je[1]);N.set(le.box,Qe.length?Qe[Qe.length-1]:null)}let pe=N.get(le.box);pe&&(le.text=`\u25A0 ${pe}`)}}let b=await Promise.all(n.boxes.map(N=>ZE(N,t)));await VO(n,b.flat());let{agentTurnBoxes:x}=await GO(n,g);await qO(n,h);for(let N of n.boxes)x.has(N.name)&&N.cwd&&ep(N.cwd);await u$(n),await AM(n,g).catch(()=>{});for(let N of n.boxes)N.agent==="codex"&&N.state==="live"&&await JO(n,N),N.agent==="cursor"&&N.state==="live"&&await eM(n,N);let v=await Promise.all(n.boxes.map(N=>XE(N,t)));await KO(n,v.flat().filter(N=>!Hk(N.box,N.ts,u)));let S=await V(n),E=c&&i.viewId?i.viewId:null,P=ER(S),L=ir(S).filter(N=>!(N.kind==="message"&&(Vk(N)||zk(N)||Kk(N)||kk(N)))&&!(N.kind==="view-card"&&E&&N.viewId===E)),$=_R(L,P),C=L.filter(N=>!(N.kind==="message"&&N.role==="assistant"&&!$.has(N)&&Hk(N.box,N.ts,P))),U=Sg(S,C).map(N=>({kind:"command-batch",id:N.id,ts:N.pending?N.ts:(N.anchorTs??N.ts)-1,anchorTs:N.anchorTs,anchorBox:N.anchorBox,agent:N.agent,boxRole:N.boxRole,commands:N.commands,pending:N.pending})).filter(N=>!Hk(N.anchorBox,N.anchorTs??N.ts,u)),J=rE(oE([...C,...U].filter(N=>N.ts!=null).sort((N,le)=>N.ts-le.ts))),_=u3(n),I=_.size?J.filter(N=>N.kind==="event"||!_.has(N.box??N.anchorBox)):J,T=n.boxes.find(N=>N.name===n.leadBox)||null,F=T?await cl(T.cwd,T.sessionId,{fallbackNewest:!1}):null;if(!F&&T){let N=[...S].reverse().find(le=>le.type==="context.usage"&&le.boxId===T.name);N?.payload?.window&&(F={pct:N.payload.pct??(N.payload.occupancy!=null?N.payload.occupancy/N.payload.window:null),occupancy:N.payload.occupancy??null,window:N.payload.window,windowKnown:!0,model:N.payload.model||null})}let W=[...m].reverse().find(N=>N.role==="assistant"&&N.model),ce=W?.model||null,z=[...n.events||[]].reverse().find(N=>N.type==="model-change"),Ke=F?.model||ce;z&&(!W?.ts||z.at>=W.ts)&&(Ke=z.to);let Ie=T?cn(T.name,await Fe(T.name,{lines:rt}).catch(()=>"")):"",X=T&&Io(T.agent,Ie)?await an(T.name).catch(()=>Ie):Ie,re=T?Cn(T,X):null;if(T&&so.has(n.id)){let N=/^claude:model-confirm:/.test(re?.promptId||"");await W3(n.id,X,N).catch(()=>{})}if(T&&s0(T.name,re,X)&&re&&(re={...re,answering:!0}),re&&T){let N=Wp(T,re,X);if(N){let le=$E(T.name,re.promptId);le.action!=="give-up"&&(le.action==="send"&&(N.accept&&$p(T.name,X),(!N.gate||Ao(T.name,N.gate))&&tt(T.name,N.keys,{kind:N.accept?"auto-accept":"auto-reject"}).catch(()=>{}),le.first&&D(n,{type:"prompt.autoRejected",actor:"system",source:"pane",boxId:T.name,provider:T.agent,payload:{ts:Date.now(),promptId:re.promptId,rule:N.id}}).catch(()=>{})),re=null)}}T&&(re?.setup&&TT(T.name,X),!re&&gl(T.agent,Ie)&&_p(T.name)&&Ao(T.name,"login-issue")&&(Ip(T.name),ot(T.name,"/login",{enter:!0,submitDelayMs:600,kind:"login-issue"}).catch(()=>{}))),!re&&T&&!ci(T.agent,Ie)&&!ss(n.id).length&&(re=bg(I,{leadBoxId:T.name,provider:T.agent,isAnswered:N=>S.some(le=>le.type==="prompt.answered"&&le.payload?.promptId===N)})),re&&d$(n,T,re);let Te=I.filter(N=>!(N.kind==="message"&&N.role==="assistant"&&N.ask&&!String(N.text||"").trim()&&!N.images?.length)),ie=!!T&&qp(T.name,T.agent,Ie)&&!re;if(T&&!T.readyAt&&(ie||re||Ie&&To(T.agent,Ie))){T.readyAt=Date.now();let N=he(await te(),n.id)?.boxes?.find(le=>le.name===T.name);N&&!N.readyAt&&(N.readyAt=T.readyAt,await de())}let Pe=dN(T,n.createdAt),ve=!!T&&!!Ie&&To(T.agent,Ie)&&!re&&!gl(T.agent,Ie)&&!ii(T.agent,Ie),ee=!1;if(n.kind==="setup"&&n.setup?.provider&&!n.setup.connectedAt&&T){if(ve){let N=await te(),le=he(N,n.id);le?.setup&&!le.setup.connectedAt&&(le.setup.connectedAt=Date.now(),n.setup.connectedAt=le.setup.connectedAt,ee=!0,await de())}}else T&&ve&&AT(T.name)&&(ee=!0);if(ee&&ET(T.name),T){let N=_T(T.name),le=vT(T.name);N.started&&D(n,{type:"provider.login.started",actor:"system",source:"pane",boxId:T.name,provider:T.agent,payload:{provider:T.agent,reason:le?.startedReason||"auth-screen",ts:Date.now()}}).catch(()=>{}),N.connected&&(await D(n,{type:"provider.connected",actor:"system",source:"pane",boxId:T.name,provider:T.agent,payload:{provider:T.agent,ts:le?.connectedAt||Date.now(),...le?.account?{account:le.account}:{},reason:le?.startedReason||"already-signed-in"}}).catch(()=>{}),n.kind!=="setup"&&le?.startedReason&&!b3(n.id)&&Ht(n.id,fN,{kind:"login-greet"}).catch(pe=>{console.warn(`[track ${n.id}] login greeting not delivered: ${pe?.message||pe}`)}))}let ge=s?{running:!0,step:o.step,toAgent:o.toAgent||null,wait:o.wait||null}:null,Ve=qu(n.id),ze=Ve&&!Ve.finishedAt?{running:!0,step:Ve.step||null,added:Ve.added||[],removed:Ve.removed||[]}:null,Ze=null;if(c){let N=Date.now()-i.startedAt;if(i.viewId&&!ie){let le=yh(n.id);le&&(Me(n,"view-spinup",{box:i.box,startedAt:i.startedAt,endedAt:le.finishedAt}),await de())}else if(re||N>gM&&!ie&&!i.viewId||N>zb){let le=re?"needs-input":N>zb?"timeout":"no-view";yh(n.id,{error:le})&&await D(n,{type:"view.spinup.failed",actor:"orchestrator",source:"orchestrator",boxId:i.box,provider:T?.agent||null,payload:{ts:i.startedAt,name:i.name,reason:le}}).catch(()=>{})}else Ze={running:!0,step:i.step,name:i.name}}return{trackId:n.id,leadBox:n.leadBox,items:Te,context:F?{pct:F.pct,occupancy:F.occupancy,window:F.window,windowKnown:F.windowKnown,model:F.model}:null,models:{current:Ke,options:qy(T?.agent)},pendingPrompt:re,working:ie,stopping:du(n.id),leadStarting:Pe,handoff:ge,reshape:ze,view:Ze,queued:ss(n.id).filter(N=>N.kind!=="ship-notify"&&N.kind!=="prompt-answer"&&N.kind!=="login-greet"),draft:n.draft||null,draftRev:n.draftRev||0}}function u3(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 o0(e,t){let n=await ye(e);if(!n)return null;let r=va(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 V(n),a=ir(s).filter(d=>d.box===o&&!(d.kind==="message"&&d.role==="assistant"&&d.ask&&!String(d.text||"").trim()&&!d.images?.length)),i=Sg(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 Fe(o,{lines:rt}).catch(()=>"");u=qp(o,l.agent||r.agent,d)}return{items:c,working:u,box:o,agent:r.agent,task:r.task}}function d3(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>XC)throw new Error(`custom answer is too long (max ${XC} characters)`);return r})}function p3(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 s0(e,t,n,r=Date.now()){let o=Jk.get(e);if(!o)return!1;let s=!!t&&t.promptId===o.promptId&&r-o.at<f3&&(t.setup?!0:pN(n)===o.paneHash);return s||Jk.delete(e),s}async function m3(e,t,n){let r=n;for(let o of h3){await Sr(o);let s=await an(e).catch(()=>null);if(s!=null&&(r=s,s!==n))break}Jk.set(e,{promptId:t.promptId,paneHash:pN(r),setup:t.setup||null,at:Date.now()})}async function qh(e,t={}){let n=Iu.get(e);n&&await n.catch(()=>{});let r=w3(e,t);Iu.set(e,r);try{return await r}catch(o){let s=so.get(e);throw s&&(s.answering=!1),o}finally{Iu.get(e)===r&&Iu.delete(e)}}async function w3(e,{promptId:t,answers:n,text:r,custom:o}={}){let s=he(await te(),e);if(!s)throw new Error(`track "${e}" not found`);ka(e,"prompt-answer");let a=s.boxes.find(v=>v.name===s.leadBox);if(!a)throw new Error(`track "${e}" has no lead box`);if(!await _e(s.leadBox))throw new Error(`lead box "${s.leadBox}" is not running`);let c=await an(a.name).catch(()=>""),l=Cn(a,c);if(l||(l=await g3(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");let d=/^claude:model-confirm:/.test(l.promptId||"")?so.get(s.id):null;if(d&&(d.answering=!0),l.answerMode!=="say"&&s0(a.name,l,c))throw new Error("prompt already answered \u2014 waiting for the CLI to move on");let p=d3(o,l.questions?.length??1);if(p.some(Boolean)&&!l.custom)throw new Error("custom answer isn't available for this prompt \u2014 pick one of its options");let w=(n||[]).some(v=>Array.isArray(v)&&v.length>0);if(l.custom&&!w&&!p.some(Boolean)&&l.answerMode!=="text")throw new Error("no answer selected \u2014 pick an option or type your own");p.some(Boolean)&&(n=(l.questions||[]).map((v,S)=>p[S]&&!v.multiSelect?[]:Array.isArray(n?.[S])?n[S]:[]));let m;if(l.answerMode==="text"){let v=typeof r=="string"?r.trim():"";if(!v)throw new Error("this prompt needs a code \u2014 paste it into the card");if(/\s/.test(v)||v.length>2048)throw new Error("that doesn't look like a sign-in code \u2014 paste the code exactly as shown");await ot(s.leadBox,v,{enter:!0,kind:"answer-prompt"}),m={mode:"text-input",value:"\u2039code\u203A",count:1,redacted:!0}}else if(l.answerMode==="esc")await tt(s.leadBox,["Escape"],{kind:"answer-prompt"}),m={mode:"keys",value:"Escape",count:1};else if(l.answerMode==="say"){let v=QT(l,n||[],typeof r=="string"?r:"",p);if(!v)throw new Error("no answer selected \u2014 pick an option or reply in chat");await Ht(s.id,v,{kind:"prompt-answer"}),m={mode:"say",value:v,count:1}}else if(p[0]&&l.provider==="claude"){let v=TE(l,n||[],p[0]);await qw(s.leadBox,[...v.pre,{text:v.text}],{kind:"answer-prompt"});let S=!1;for(let P of[150,300,600]){await Sr(P);let L=await an(s.leadBox).catch(()=>""),$=Cn(a,L,{customIndex:l.customIndex});if($?.customText&&p3($.customText,v.text)){S=!0;break}}if(!S)throw new Error("custom answer didn't take \u2014 the widget moved; reload and answer again");await qw(s.leadBox,v.post,{kind:"answer-prompt"});let E=P=>P.map(L=>L.count>1?`${L.key}\xD7${L.count}`:L.key).join(" ");m={mode:"keys+text",value:`${E(v.pre)} \u2039text\u203A ${E(v.post)}`.trim(),count:v.pre.length+1+v.post.length}}else if(l.provider==="claude"||l.answerMode==="keys"){let v=$g(l,n||[]);await tt(s.leadBox,v,{kind:"answer-prompt"}),m={mode:"keys",value:v.join(" "),count:v.length}}else{let v=CT(l,n||[]);await ot(s.leadBox,v,{enter:!0,kind:"answer-prompt"}),m={mode:"text",value:v,count:1}}if(l.answerMode!=="say"&&await m3(a.name,l,c),l.answerMode==="say"){let v=l.questions||[];for(let S=0;S<v.length;S++){let E=v[S],P=new Set(Array.isArray(n?.[S])?n[S]:[]),L=[...P].map(C=>E.options?.[C]).filter(Boolean).map(C=>({label:C.label,description:C.description||""}));p[S]&&L.push({label:p[S],description:"",custom:!0});let $=(E.options||[]).map((C,U)=>P.has(U)?null:C?.label).filter(Boolean);Gy(s,a,l,{...m,groupId:l.groupId||l.promptId,questionIndex:S,questionTotal:l.questionTotal??v.length,header:E.header||"",question:E.question||"",multiSelect:!!E.multiSelect,chosen:L,rejected:$})}return await ne({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:l.provider,promptId:l.promptId,...m}).catch(()=>{}),{ok:!0,promptId:l.promptId,sent:m.count}}let h=l.questions?.[0]||{},g=new Set(Array.isArray(n?.[0])?n[0]:[]),y=[...g].map(v=>h.options?.[v]).filter(Boolean).map(v=>({label:v.label,description:v.description||""}));p[0]&&y.push({label:p[0],description:"",custom:!0});let b=(h.options||[]).map((v,S)=>g.has(S)?null:v?.label).filter(Boolean),x=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;if(m={...m,groupId:l.groupId||l.promptId,questionIndex:l.questionIndex??0,questionTotal:l.questionTotal??1,header:h.header||"",question:h.question||"",multiSelect:!!h.multiSelect,chosen:y,rejected:b,...x?{control:x}:{}},await ne({flow:"prompt",phase:"answered",sessionName:s.leadBox,agent:a.agent,provider:l.provider,promptId:l.promptId,...m}).catch(()=>{}),Gy(s,a,l,m),d){let v=y.some(S=>/^yes\b/i.test(S.label));kN(s,v)&&await de()}return{ok:!0,promptId:l.promptId,sent:m.count}}async function g3(e,t){if(!t)return null;let n=await V(e).catch(()=>[]);return bg(ir(n),{leadBoxId:t.name,provider:t.agent,isAnswered:r=>n.some(o=>o.type==="prompt.answered"&&o.payload?.promptId===r)})}async function a0(e,{promptId:t,questionIndex:n}={}){let r=he(await te(),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 _e(r.leadBox))throw new Error(`lead box "${r.leadBox}" is not running`);let a=await vE(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=EE(a,n);return c.length?(await tt(r.leadBox,c,{kind:"navigate-prompt"}),await ne({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 Gh(e){let t=os.get(e);return t||(t={items:[],timer:null,flushing:!1,idleSince:null},os.set(e,t)),t}function b3(e){let t=os.get(e);return!!t&&(t.items.length>0||!!t.flushing)}function ss(e){return(os.get(e)?.items??[]).map(({delivery:t,...n})=>({...n}))}function i0(e=Date.now()){let t=0,n=0;for(let r of os.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 hN(e,t,n){let r=t.filter(o=>o.delivery&&!o.delivery.settled);r.length&&(async()=>{let o=he(await te(),e)||null;for(let s of r)await Un(o,s.delivery,`dropped:${n}`)})().catch(()=>{})}function Kh(e,t="cancel"){let n=os.get(e);if(!n)return[];let r=n.items.splice(0);return n.idleSince=null,n.timer&&(clearInterval(n.timer),n.timer=null),hN(e,r,t),r}function mN(e,t,n){let r=os.get(e);if(!r)return[];let o=r.items.filter(s=>n(s));return o.length?(r.items=r.items.filter(s=>!n(s)),r.items.length||(r.idleSince=null,r.timer&&(clearInterval(r.timer),r.timer=null)),hN(e,o,t),o):[]}async function c0(e){let t=Kh(e),n=t.filter(o=>o.text&&!o.kind).map(o=>o.text),r=null;if(n.length){let o=he(await te(),e);if(o)return r=Pu(o,n),await de(),{removed:t,restored:r,draftRev:o.draftRev||0}}return{removed:t,restored:r,draftRev:null}}function l0(e){let t=Gh(e);t.timer||(t.timer=setInterval(()=>k3(e).catch(()=>{}),y3))}async function k3(e){let t=os.get(e);if(!(!t||t.flushing)){if(!t.items.length){t.timer&&(clearInterval(t.timer),t.timer=null);return}t.flushing=!0;try{let n=he(await te(),e);if(!n||n.archivedAt){Kh(e,"archived");return}let r=async(l,u="")=>{let d=[];for(let g of t.items)cM(g.delivery,l),IC(g,l)&&d.push(g);if(!d.length)return;t.items=t.items.filter(g=>!d.includes(g));let p=Date.now()-Math.min(...d.map(g=>g.heldSince||Date.now())),w=Math.max(1,Math.round(Sk()/6e4)),m=String(u||"").split(`
|
|
324
324
|
`).map(g=>g.trimEnd()).filter(g=>g.trim()).slice(-3).join(`
|
|
325
|
-
`),
|
|
325
|
+
`),h=l==="noSession"?`The scheduled prompt waited ${w} min for the box's session to come back and was dropped \u2014 open the terminal.`:`The scheduled prompt waited ${w} min for the box to become idle and was dropped \u2014 open the terminal.`;for(let g of d)g.delivery&&await Un(n,g.delivery,l==="noSession"?"failed:not-running":"failed:blocked");Me(n,"delivery-held",{box:n.leadBox,agent:o?.agent??null,reason:l,heldMs:p,producer:"loop",deliveryId:d[0]?.delivery?.id??null,message:h,...m?{detail:m}:{}}),await de(),Js(n,{provider:o?.agent??null,cls:"delivery-held",note:h}).catch(()=>{})},o=n.boxes.find(l=>l.name===n.leadBox),s=ac(e);if(s&&!s.finishedAt&&s.step!=="done"&&!s.error){Qo(t,!1),await r("handoff");return}if(du(e)){Qo(t,!1),await r("busy");return}let a=await _e(n.leadBox);if(a&&await Gu(a)&&(a=await ju(n,o,"queue")?await _e(n.leadBox):null,await de()),!a){Qo(t,!1),await r("noSession");return}if(Uo(o?.agent)){Qo(t,!1),await r("cap");return}let i=cn(n.leadBox,await Fe(n.leadBox,{lines:rt}).catch(()=>""));if(Sl(o?.agent,i)){Qo(t,!1),await r("busy",i);return}if(Io(o?.agent,i)){let l=await an(n.leadBox).catch(()=>i);if(Cn(o,l)){Qo(t,!1),await r("prompt");return}}if(!Qo(t,!0)){await r("grace");return}let c=t.items.shift();t.idleSince=null,c.delivery&&(c.delivery.dequeuedAt=Date.now());try{await Yk(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 Un(n,c.delivery,Li(l)),l;t.items.unshift(c),c.delivery&&(c.delivery.requeued+=1,c.delivery.dequeuedAt=null,await hu(n,c.delivery,{position:1,reason:"requeue"})),await ju(n,o,"queue-gate")}await de()}finally{t.flushing=!1}}}async function u0(e,t,n,r){let o=Uo(t?.agent);if(!o)return;if(!r&&typeof n=="string"&&n.trim()&&(Pu(e,[n]),await de()),KI(e.id,o))try{await D(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 x3(e,t){let n=cn(e.leadBox,await Fe(e.leadBox,{lines:rt}).catch(()=>""));if(!Io(t?.agent,n))return!1;let r=await an(e.leadBox).catch(()=>n);return!!Cn(t,r)}async function Yk(e,t,n,r,o=null,s=null,a=null){a||(a=fu({text:r,producer:pu({kind:o}),kind:o,provider:t?.agent??null,attachments:Array.isArray(s)?s.length:0})),a.provider??=t?.agent??null,await u0(e,t,r,o);let i=Nu.get(e.id)||0,c=r,l=!1,u=e.pendingHandoffHydrate||null;e.pendingHandoffHydrate&&(c=sN(r,e.pendingHandoffHydrate.artifact||rs),delete e.pendingHandoffHydrate,l=!0);let d=Array.isArray(s)?s.filter(h=>h&&h.rel):[];if(d.length){let h=_C(d.map(g=>g.rel));c=c.trim()?`${c.trim()}
|
|
326
326
|
|
|
327
|
-
${
|
|
327
|
+
${h}`:h}let p=Me(e,"said",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,text:r,deliveryId:a.id,...o?{kind:o}:{},...d.length?{attachments:d}:{},...a.producer&&a.producer!=="composer"&&!o?{producer:a.producer}:{}});o||Yi(e,null);try{let h=Date.now(),g=null;try{g=await Mr({cwd:n.cwd,sessionId:n.sessionId,sessionName:e.leadBox,agent:n.agent,agentCmd:ba(n.agent),bailOnDialog:!0})}catch(b){throw mu(a,{ms:Date.now()-h,outcome:b?.code==="cli-not-running"?"cli-not-running":"blocked"}),b}if(mu(a,{ms:Date.now()-h,outcome:g||"up"}),(Nu.get(e.id)||0)!==i){!o&&r.trim()&&(Pu(e,[r]),await de());let b=new Error("delivery stopped \u2014 the message was handed back as the draft");throw b.interrupted=!0,b}if(await x3(e,t)){let b=Gh(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}:{},...a.producer&&a.producer!=="composer"&&!o?{producer:a.producer}:{},delivery:a};b.items.unshift(x),l0(e.id),await hu(e,a,{position:1,reason:"prompt"});let v=new Error("lead is blocked on a prompt \u2014 message queued");throw v.requeued={id:x.id,position:b.items.length},v}let y=ar(t?.agent,c);a.paste=!!y.paste,await ot(e.leadBox,c,{...y,kind:l?"lead-handoff-first-prompt":"say"})}catch(h){if(u&&!e.pendingHandoffHydrate&&(e.pendingHandoffHydrate=u),Me(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 Un(e,a,Li(h)),h}let w={},m=await j3(e,t,c,w);a.verify=w,m?await Un(e,a,w.verdict==="unverified"?"unverified":"delivered"):(await wN(e.leadBox,t?.agent,c.length+8,c).catch(()=>{}),Me(e,"unsaid",{box:e.leadBox,agent:t?.agent,boxRole:t?.role,saidTs:p.at,text:r,reason:"unsubmitted"}),o||Pu(e,[r]),await Un(e,a,"unsubmitted")),l&&await ne({flow:"lead-handoff",phase:"first-prompt",trackId:e.id,sessionName:e.leadBox,agent:t?.agent,userTextLen:r.length})}function d0(e,{actions:t}={}){let n=Gh(e),r=IR(t),o=fu({text:r,producer:pu({kind:"ship-notify"}),kind:"ship-notify"});n.items.push({id:o.id,text:r,ts:Date.now(),kind:"ship-notify",delivery:o}),l0(e),(async()=>{let s=he(await te(),e);s&&(o.provider=s.boxes.find(a=>a.name===s.leadBox)?.agent??null,await hu(s,o,{position:n.items.length,reason:"queue"}))})().catch(()=>{})}async function S3(e,t,n,r){await tt(e.leadBox,["Escape"],{kind:"dismiss-prompt"});let o="",s=!1;for(let c of[250,400,600,900]){if(await Sr(c),o=await Fe(e.leadBox,{lines:rt}).catch(()=>""),!Io(t?.agent,o)){s=!0;break}let l=await an(e.leadBox).catch(()=>o);if(!Cn(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 ne({flow:"prompt",phase:"dismissed",sessionName:e.leadBox,agent:t?.agent,provider:n.provider,promptId:n.promptId,...i}).catch(()=>{}),s&&p$(e,t,n,i),{gone:s,pane:o}}async function Ht(e,t,{kind:n=null,attachments:r=null,producer:o=null,dismissPrompt:s=!1}={}){let a=Array.isArray(r)?r.filter(p=>p&&typeof p.rel=="string"):[];if((typeof t!="string"||!Fo(t))&&!a.length)throw new Error("text (string) or an attachment required");let i=he(await te(),e);if(!i)throw new Error(`track "${e}" not found`);ic(i);let c=i.boxes.find(p=>p.name===i.leadBox),l=Fo(t),u=!1;if(i.archivedAt){let p=A3(n);if(!p)throw new Error(`track "${e}" is archived \u2014 restore it before driving it`);await u0(i,c,l,n),await sc(e,{reason:p}),i=he(await te(),e),c=i.boxes.find(w=>w.name===i.leadBox),u=!0}let d=fu({text:l,producer:pu({kind:n,producer:o}),kind:n,provider:c?.agent??null,attachments:a.length});n||gN(i.id,l);try{let p=await T3(e,i,c,l,{kind:n,atts:a,d,dismissPrompt:s});return u?{...p,revived:!0}:p}catch(p){throw n||yN(i.id,l),await Un(i,d,Li(p)),p}}async function T3(e,t,n,r,{kind:o,atts:s,d:a,dismissPrompt:i=!1}){await u0(t,n,r,o),ka(e,"say");let c=await _e(t.leadBox);if(c&&await Gu(c)?await ju(t,n,"say")?(await de(),c=await _e(t.leadBox)):c=null:!c&&await oc(t)&&(await de(),c=await _e(t.leadBox)),!c)throw new Error(`lead box "${t.leadBox}" is not running`);let l=Iu.get(e);l&&await l.catch(()=>{});let u=Gh(e),d=cn(t.leadBox,await Fe(t.leadBox,{lines:rt}).catch(()=>"")),p=u.items.length>0?"queue":Sl(n?.agent,d)?"busy":null,w=p!=null,m=i&&!o;if((!w||p==="queue"&&m)&&Io(n?.agent,d)){let g=await an(t.leadBox).catch(()=>d),y=Cn(n,g);if(w||(w=!!y,w&&(p="prompt")),y&&m&&y.dismissable){let b=await S3(t,n,y,a);b.gone&&p==="prompt"&&(d=b.pane,w=Sl(n?.agent,d),p=w?"busy":null)}}if(w){let g={id:a.id,text:r,ts:Date.now(),...o?{kind:o}:{},...s.length?{attachments:s}:{},...a.producer&&a.producer!=="composer"&&!o?{producer:a.producer}:{},delivery:a};return u.items.push(g),l0(e),o||Yi(t,null),await de(),await hu(t,a,{position:u.items.length,reason:p}),{ok:!0,leadBox:t.leadBox,queued:!0,id:g.id,position:u.items.length,deliveryId:a.id}}let h;try{h=await Yk(t,n,c,r,o,s,a)}catch(g){if(g?.code!=="cli-not-running"||!await ju(t,n,"say-gate")||(await de(),c=await _e(t.leadBox),!c))throw g;h=await Yk(t,n,c,r,o,s,a)}return await de(),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 p0(e,{hint:t}={}){let n=he(await te(),e);if(!n)throw new Error(`track "${e}" not found`);ic(n);let r=Jb(n.id);if(r&&!r.finishedAt)throw new Error("a view is already being spun up for this Track");let o=String(t||"").trim()?String(t).trim().slice(0,40):"preview";yM(n.id,{name:o,box:n.leadBox});let s=String(t||"").trim()?`${ZC}
|
|
328
328
|
|
|
329
|
-
What to preview: ${String(t).trim()}`:ZC,a;try{a=await Ht(e,s,{kind:"spin-up-view"})}catch(i){throw yh(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0,...a?.revived?{revived:!0}:{}}}async function Vh(e){let t=he(await te(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);Nu.set(e,(Nu.get(e)||0)+1);let n=mN(e,"interrupt",i=>!!i.kind),r=ss(e).filter(i=>!i.kind).length,o=Ji.get(e);if(o&&!o.canceled)return o.clicks++,{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,kept:r,restored:null,draftRev:t.draftRev||0};let s=O3(e,{droppedCount:n.length,keptCount:r});await Promise.race([s.settled,Sr(E3)]);let a=he(await te(),e)||t;return{ok:!0,interrupted:s.result!=="no-session",stopped:s.result==="stopped"||s.result==="stopped-late",stopping:!s.result,dropped:n.length,kept:r,restored:s.restored,draftRev:a.draftRev||0,stuckOfferId:s.stuckOfferId??null}}function du(e){let t=Ji.get(e);return!!t&&!t.canceled}function ka(e,t){let n=Ji.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function f0(e){ka(e,"track-ended"),Nu.delete(e),Kh(e,"track-ended")}function O3(e,{droppedCount:t,keptCount:n=0}){let r={startedAt:Date.now(),clicks:1,escSends:0,bgSends:0,keptCount:n,canceled:!1,cancelReason:null,result:null,restored:null,stuckOfferId:null},o;return r.settled=new Promise(s=>{o=s}),Ji.set(e,r),(async()=>{let s=he(await te(),e),a=s?.boxes.find(y=>y.name===s.leadBox),i=s?await _e(s.leadBox):null,c=!1,l=!1,u=null;if(i){u=await $o(s.leadBox,a?.agent).then(y=>y.working||y.prompted).catch(()=>null);e:for(let y=0;y<_3&&!r.canceled;y++){await tt(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let b of I3){await Sr(b);let x=cn(s.leadBox,await Fe(s.leadBox,{lines:rt}).catch(()=>""));if(!ci(a?.agent,x)){c=!0;break e}}}if(!c){l=!0;for(let y=0;y<R3&&!r.canceled&&(await Sr($3),!r.canceled);y++){let b=cn(s.leadBox,await Fe(s.leadBox,{lines:rt}).catch(()=>""));if(!ci(a?.agent,b)){c=!0;break}await tt(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let d=he(await te(),e)||s,p=d?.boxes.find(y=>y.name===d.leadBox)||a,w=null,m=null;d&&p&&i&&c&&!r.canceled&&(w=await P3(d,p).catch(()=>null),w||(m=await L3(d,p).catch(()=>null)));let
|
|
329
|
+
What to preview: ${String(t).trim()}`:ZC,a;try{a=await Ht(e,s,{kind:"spin-up-view"})}catch(i){throw yh(n.id,{error:"drive-failed"}),i}return{ok:!0,running:!0,...a?.revived?{revived:!0}:{}}}async function Vh(e){let t=he(await te(),e);if(!t)throw new Error(`track "${e}" not found`);if(t.archivedAt)throw new Error(`track "${e}" is archived`);Nu.set(e,(Nu.get(e)||0)+1);let n=mN(e,"interrupt",i=>!!i.kind),r=ss(e).filter(i=>!i.kind).length,o=Ji.get(e);if(o&&!o.canceled)return o.clicks++,{ok:!0,interrupted:!0,stopped:!1,stopping:!0,dropped:n.length,kept:r,restored:null,draftRev:t.draftRev||0};let s=O3(e,{droppedCount:n.length,keptCount:r});await Promise.race([s.settled,Sr(E3)]);let a=he(await te(),e)||t;return{ok:!0,interrupted:s.result!=="no-session",stopped:s.result==="stopped"||s.result==="stopped-late",stopping:!s.result,dropped:n.length,kept:r,restored:s.restored,draftRev:a.draftRev||0,stuckOfferId:s.stuckOfferId??null}}function du(e){let t=Ji.get(e);return!!t&&!t.canceled}function ka(e,t){let n=Ji.get(e);n&&!n.canceled&&(n.canceled=!0,n.cancelReason=t||null)}function f0(e){ka(e,"track-ended"),Nu.delete(e),Kh(e,"track-ended")}function O3(e,{droppedCount:t,keptCount:n=0}){let r={startedAt:Date.now(),clicks:1,escSends:0,bgSends:0,keptCount:n,canceled:!1,cancelReason:null,result:null,restored:null,stuckOfferId:null},o;return r.settled=new Promise(s=>{o=s}),Ji.set(e,r),(async()=>{let s=he(await te(),e),a=s?.boxes.find(y=>y.name===s.leadBox),i=s?await _e(s.leadBox):null,c=!1,l=!1,u=null;if(i){u=await $o(s.leadBox,a?.agent).then(y=>y.working||y.prompted).catch(()=>null);e:for(let y=0;y<_3&&!r.canceled;y++){await tt(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.escSends++;for(let b of I3){await Sr(b);let x=cn(s.leadBox,await Fe(s.leadBox,{lines:rt}).catch(()=>""));if(!ci(a?.agent,x)){c=!0;break e}}}if(!c){l=!0;for(let y=0;y<R3&&!r.canceled&&(await Sr($3),!r.canceled);y++){let b=cn(s.leadBox,await Fe(s.leadBox,{lines:rt}).catch(()=>""));if(!ci(a?.agent,b)){c=!0;break}await tt(s.leadBox,["Escape"],{kind:"interrupt"}).catch(()=>{}),r.bgSends++}}}let d=he(await te(),e)||s,p=d?.boxes.find(y=>y.name===d.leadBox)||a,w=null,m=null;d&&p&&i&&c&&!r.canceled&&(w=await P3(d,p).catch(()=>null),w||(m=await L3(d,p).catch(()=>null)));let h=d&&i&&!r.canceled?await C3(d).catch(()=>null):null,g=[w||m].filter(Boolean);d&&g.length&&(r.restored=Pu(d,g),await de()),r.result=i?r.canceled?"canceled":c?l?"stopped-late":"stopped":"gave-up":"no-session",await M3(d||s,p,{ts:r.startedAt,result:r.result,dropped:t,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!w,lostRestored:!!m,queuedKept:r.keptCount,shipDismissed:!!h,durationMs:Date.now()-r.startedAt,busyAtClick:u,...r.cancelReason?{cancelReason:r.cancelReason}:{}}),d&&i&&r.result==="gave-up"&&!r.canceled&&(r.stuckOfferId=await a8(d,p,{escSends:r.escSends+r.bgSends,kept:r.keptCount}).catch(()=>null)),await ne({flow:"interrupt",phase:r.result==="gave-up"?"failed":"done",trackId:e,sessionName:d?.leadBox,agent:p?.agent,result:r.result,escSends:r.escSends,bgSends:r.bgSends,clicks:r.clicks,unsent:!!w,lostRestored:!!m,queuedKept:r.keptCount,shipDismissed:!!h,stuckOfferId:r.stuckOfferId}).catch(()=>{})})().catch(()=>{}).finally(()=>{r.result||(r.result=r.canceled?"canceled":"gave-up"),Ji.get(e)===r&&Ji.delete(e),o()}),r}async function M3(e,t,n){await D(e,{type:"turn.interrupted",actor:"user",source:"orchestrator",boxId:e.leadBox,provider:t?.agent||null,payload:n}).catch(()=>{})}async function C3(e){let t=Zo(await V(e));if(!t?.offerId)return null;let n=t.offerType==="exists";return await D(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 P3(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 N3){await Sr(r);let o=await Fe(e.leadBox,{lines:rt}).catch(()=>""),s=Bs(t.agent,o);if(s&&(vp(n.text,s)||Sp(t.agent,n.text,s)))return await wN(e.leadBox,t.agent,n.text.length+8),Me(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:n.at,text:n.text}),n.text}return null}async function L3(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>D3||n.some(s=>s.type==="unsaid"&&s.saidTs===r.at)||!Oe(r.text))return null;for(let s of B3){await Sr(s);let a;try{a=await Fg(t,{})}catch{return null}if(dT(a,r))return null;let i=await Fe(e.leadBox,{lines:rt}).catch(()=>"");if(Bs(t.agent,i))return null}return Me(e,"unsaid",{box:e.leadBox,agent:t.agent,boxRole:t.role,saidTs:r.at,text:r.text,reason:"lost"}),r.text}async function j3(e,t,n,r=null){return Tl({sessionName:e.leadBox,agent:t?.agent,agentCmd:ba(t?.agent),text:n,trackId:e.id,flow:"say",stats:r})}async function wN(e,t,n,r=null){for(let o=0;o<3;o++){await Ya(e,n,{kind:"unsend-wipe"}).catch(()=>{}),await Sr(200);let s=await Fe(e,{lines:rt}).catch(()=>""),a=Bs(t,s);if(!a||r&&!vp(r,a)&&!Sp(t,r,a))return!0;n=a.length+8}return!1}function Yi(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 Pu(e,t){for(let o of t)yN(e.id,o);let n=[],r=o=>n.some(s=>Oe(s).includes(Oe(o)));for(let o of[e.draft?.text,...t])o&&o.trim()&&!r(o)&&n.push(o);return n.length?Yi(e,n.join(`
|
|
330
330
|
|
|
331
331
|
`),{source:"restore"})?.text??null:null}function gN(e,t){let n=Oe(t||"");if(!n)return;let r=Date.now(),o=(Xi.get(e)||[]).filter(s=>r-s.at<=h0&&s.text!==n);o.push({text:n,at:r}),Xi.set(e,o)}function yN(e,t){let n=Oe(t||""),r=Xi.get(e);if(!n||!r)return;let o=r.filter(s=>s.text!==n);o.length?Xi.set(e,o):Xi.delete(e)}function bN(e,t){let n=Oe(t||""),r=Xi.get(e);if(!n||!r)return!1;let o=Date.now();return r.some(s=>s.text===n&&o-s.at<=h0)}function F3(e,t){let n=Oe(t);if(!n)return!1;if(bN(e.id,t)||ss(e.id).some(o=>Oe(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>h0)break;if(!(s.type!=="said"||!s.text||Oe(s.text)!==n))return!r.some(a=>a.type==="unsaid"&&a.saidTs===s.at)}return!1}async function m0(e,t,{rev:n=null,consumed:r=null}={}){if(typeof t!="string")throw new Error("text (string) required");let o=he(await te(),e);if(!o)throw new Error(`track "${e}" not found`);typeof r=="string"&&Fo(r)&&gN(o.id,Fo(r));let s=t,a=Fo(t);if(typeof n=="number"&&n<(o.draftRev||0)&&a&&F3(o,a))return{ok:!0,draft:o.draft||null,rev:null,ignored:"already-sent"};if(typeof n=="number"&&n<(o.draftRev||0)&&!s.trim()&&o.draft?.text&&!bN(o.id,o.draft.text))return{ok:!0,draft:o.draft,rev:o.draftRev||0,ignored:"stale-clear"};if(typeof n=="number"&&n<(o.draftRev||0)&&o.draft?.source==="restore"){let c=o.draft.text;Oe(s).includes(Oe(c))?Yi(o,s):Yi(o,`${c}
|
|
332
332
|
|
|
333
|
-
${s}`,{source:"restore"})}else Yi(o,s);return await de(),{ok:!0,draft:o.draft||null,rev:o.draftRev||0}}async function w0(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=he(await te(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await _e(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(p=>p.name===r.leadBox)?.agent||o.agent||"claude",i=n$(a,n),l=[...r.events||[]].reverse().find(p=>p.type==="model-change")?.to??null;l||(l=(await cl(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await Mr({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:ba(o.agent)});let u=await s$(a,r.leadBox,i),d={to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified};return u.awaitingConfirm?(so.set(r.id,{detail:d,at:Date.now(),setAcks:null}),{ok:!0,requested:n,leadBox:r.leadBox,...u}):(so.delete(r.id),Me(r,"model-change",d),await de(),{ok:!0,requested:n,leadBox:r.leadBox,...u})}function kN(e,t,n={}){let r=so.get(e.id);return!r||(so.delete(e.id),!t)?!1:(Me(e,"model-change",{...r.detail,verified:!0,...n}),!0)}async function W3(e,t,n){let r=so.get(e);if(!r||r.answering)return;let o=_i(t,H3);if(n){r.setAcks=o;return}if(Date.now()-r.at<U3)return;let s=he(await te(),e);if(!s)return so.delete(e);let a=r.setAcks==null?o>0:o>r.setAcks;kN(s,a,r.setAcks==null?{verified:!1}:{})&&await de()}async function xN(e){for(let t of e){if(!t||!await xi(t))continue;let n=await dI(t).catch(()=>null);if(!n)continue;if((await Z.stat(Y.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function Qt(e){let t=e;return t?t.kind==="multi"?Array.isArray(t.repos)?t.repos.filter(Boolean):[]:t.base?[{name:Y.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function ha(e){let t=[];for(let n of Qt(e?.workspace)){if(!n?.dir)continue;let r=await Xs(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await Zs(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function g0(e){let t=e;typeof t=="string"&&!Y.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await Ts(t)??await F0(t));let n=await xN([t]);if(!n){let r=typeof e=="string"&&Y.isAbsolute(e)&&!await Z.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 await _y(n),n}async function q3(e,t,n,r){let o=`track/${cr(t)}-${e}`,s=[];try{await Z.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await g0(i);if(s.some(w=>w.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await Re(c).catch(()=>null),u=Y.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let w=2;a.has(u);w++)u=`${Y.basename(c)}-${w}`;a.add(u);let d=Y.join(n,u),p=await ea(c);await Qs(c,d,o,p),s.push({name:u,dir:d,base:c,baseRef:p,repo:l})}return await rc(n,s,o,{deps:Zi(e,n)}),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await Lt(i.base,i.dir).catch(()=>{});throw await Z.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function zh(e,t){let n=await te(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 unarchive it first");let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track \u2014 a single-repo Track's workspace IS its repo checkout; create the Track with multiple repos tagged instead");let s=await g0(typeof t=="string"?t.trim():t);if((o.repos??[]).some(p=>p?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await Re(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(p=>p?.name).filter(Boolean)]),c=Y.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let p=2;i.has(c);p++)c=`${Y.basename(s)}-${p}`;let l=Y.join(o.dir,c),u=await ea(s);await Ay(s,o.branch)?await Ll(s,l,o.branch):await Qs(s,l,o.branch,u);let d={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),d],await rc(o.dir,o.repos,o.branch,{deps:x0(r)}),Me(r,"retagged",{action:"add",repo:a??s,name:c,workspace:y0(o)}),await de(),d}async function Jh(e,t){let n=await te(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track");let s=(o.repos??[]).find(c=>c&&(c.name===t||c.repo===t||c.base===t));if(!s)throw new Error(`repo "${t}" is not tagged on this Track`);if((o.repos??[]).filter(Boolean).length<=1)throw new Error("can't untag the last repo \u2014 archive or delete the Track instead");for(let c of Ut.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 Xs(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await Zs(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 Lt(s.base,s.dir).catch(()=>{}),await Z.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await rc(o.dir,o.repos,o.branch,{deps:x0(r)}),Me(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:y0(o)}),await de(),{removed:s.name}}async function Dh(e,t){let n=await te(),r=he(n,e);r&&(r.reshape={...r.reshape||{},...t},await de())}async function G3(e){let t=await Z.readdir(e).catch(()=>[]);for(let n of t)if(!(n===".git"||n===".bostrat")){if(n==="AGENTS.md"){let r=await Z.readFile(Y.join(e,n),"utf8").catch(()=>"");if(Ou(r))continue}return!0}try{let{stdout:n}=await Zk("git",["-C",e,"rev-list","--count","HEAD"]);if(Number(n.trim())>1)return!0}catch{}return!1}function QC(e,t,n){let r=Y.basename(e);n.has(r)&&t&&(r=t.replace("/","-"));for(let o=2;n.has(r);o++)r=`${Y.basename(e)}-${o}`;return n.add(r),r}async function SN(e,{added:t=[]}={}){let{shape:n,dir:r,staging:o,sub:s,base:a,scratch:i}=e;for(let l of t)await Lt(l.base,l.dir).catch(()=>{});let c=async(l,u)=>{await Gn(l)&&!await Gn(u)&&await Z.rename(l,u)};if(n==="worktree"&&s){let l=Y.join(r,s);await Gn(l)&&(await c(Y.join(r,".bostrat"),Y.join(l,".bostrat")),await Bh(a,l,o))}if(n==="repo"&&i){let l=Y.join(r,i);await Gn(l)&&(await Gn(o)&&await Z.rm(o,{recursive:!0,force:!0}),await Z.rename(l,o))}return await Gn(o)?(await Gn(r)&&(await c(Y.join(r,".bostrat"),Y.join(o,".bostrat")),await Z.rm(r,{recursive:!0,force:!0})),n==="worktree"?await Bh(a,o,r):await Z.rename(o,r),!0):!1}async function b0(e,t,{skipPermissions:n=!0}={}){let r=await te(),o=he(r,e);if(!o)throw Ot(`track "${e}" not found`,404);if(o.archivedAt)throw Ot("track is archived \u2014 unarchive it first");try{ic(o)}catch(g){throw Object.assign(g,{status:409})}if(o.kind==="setup")throw Ot("setup boxes have no repos to reshape");if(String(o.name||"").startsWith("\u21BB"))throw Ot("this Track's repos are the loop's \u2014 propose-update the loop instead");let s=Xk.get(e);if(s&&!s.finishedAt)throw Ot("a reshape is already running for this Track");let a=ya.get(e);if(a&&!a.finishedAt)throw Ot("a lead handoff is running \u2014 retry when it settles");let i=jh.get(e);if(i&&!i.finishedAt)throw Ot("a node transfer is running \u2014 retry when it settles");if(Nh.has(e))throw Ot("an adopt is running for this Track \u2014 retry when it settles");for(let g of Ut.values())if(g.trackId===e&&!g.finishedAt)throw Ot("a subtask is still running on this Track \u2014 wait for it to merge back before reshaping");let c=(Array.isArray(t)?t:[]).map(g=>typeof g=="string"?g.trim():"").filter(Boolean);if(!c.length)throw Ot("repos (non-empty list of paths or owner/name slugs) required",400);let l=[];for(let g of c){let y;try{y=await g0(g)}catch(b){throw Ot(b?.message||String(b),400)}if(l.some(b=>b.base===y))throw Ot(`repo tagged twice: ${g}`,400);l.push({sel:g,base:y,slug:await Re(y).catch(()=>null)})}let u=o.workspace;if(u?.kind==="multi"){let g=(u.repos??[]).filter(Boolean),y=g.filter(v=>!l.some(S=>S.base===v.base)),b=l.filter(v=>!g.some(S=>S.base===v.base));if(!y.length&&!b.length)return{trackId:e,step:"done",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:Date.now(),error:null};for(let v of y){let S=await Xs(v.dir,{ignorePlumbing:!0}).catch(()=>!1),E=await Zs(v.dir,v.baseRef).catch(()=>0);if(S||E>0)throw Ot(`"${v.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 v of b){let S=await zh(e,v.base);x.added.push(S.repo??S.base)}for(let v of y)await Jh(e,v.name),x.removed.push(v.repo??v.base);return x.step="done",x.finishedAt=Date.now(),x}if(u?.kind!=="worktree"&&u?.kind!=="repo")throw Ot(`can't reshape a "${u?.kind??"unknown"}" workspace`);let d=u.kind==="worktree"&&l.some(g=>g.base===u.base);if(u.kind==="worktree"&&!d){let g=await Xs(u.dir??o.cwd,{ignorePlumbing:!0}).catch(()=>!1),y=await Zs(u.dir??o.cwd,u.baseRef).catch(()=>0);if(g||y>0)throw Ot(`"${Y.basename(u.base)}" has work (${g?"uncommitted changes":`${y} commit${y===1?"":"s"} ahead of ${u.baseRef??"base"}`}) \u2014 ship or discard it before swapping it out`)}ka(e,"reshape");let p=o.boxes.find(g=>g.name===o.leadBox)||null;if(!p)throw Ot("this Track has no lead box");let w=p.agent||"claude",m=await tc(w,n),f={trackId:e,step:"checkpoint",inPlace:!1,startedAt:Date.now(),finishedAt:null,error:null,added:l.filter(g=>!(u.kind==="worktree"&&g.base===u.base)).map(g=>g.slug??g.base),removed:u.kind==="worktree"&&!d?[u.repo??u.base]:[],scratch:!1,views:0,checkpoint:null};return Xk.set(e,f),await Dh(e,{step:f.step,startedAt:f.startedAt,finishedAt:null,error:null,added:f.added,removed:f.removed,layout:null}),K3(f,o,{desired:l,keep:d,lead:p,agent:w,agentCmd:m,skipPermissions:n}).catch(async g=>{f.error=g?.message||String(g),f.finishedAt=Date.now(),console.error(`[reshape ${e}] FAILED at step "${f.step}": ${f.error}`),await Dh(e,{step:f.step,error:f.error,finishedAt:f.finishedAt}).catch(()=>{})}),f}async function K3(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(I,T={})=>{e.step=I,console.log(`[reshape ${c}] step \u2192 ${I}`),await Dh(c,{step:I,...T})},p=await _e(o.name).catch(()=>null),w=o.sessionId??p?.sessionId??null,m=o.pinned===!0;if(await d("checkpoint"),e.checkpoint="llm",!p)e.checkpoint="skipped-dead";else if(Uo(s))e.checkpoint="skipped-capped";else try{await Qp(o.name,{timeoutMs:e0,quiesce:{box:o,reason:"reshape",onWait:()=>d("await-turn"),onResume:()=>d("checkpoint")}})}catch{e.checkpoint="reconstructed"}let f=null;e.checkpoint!=="llm"&&(f=await ef(c,u,{trackName:t.name||c}).catch(()=>null)),await d("quiesce"),e.views=await nk(c).catch(()=>0),await tp(u).catch(()=>{}),p&&(await Xg(o.name,{fromAgent:s}).catch(()=>{}),await zt(o.name).catch(()=>{}));let g=`${u}.reshape-${Date.now()}`,y=new Set([".bostrat"]),b={shape:l.kind,dir:u,staging:g,base:l.kind==="worktree"?l.base:null,sub:l.kind==="worktree"&&r?QC(l.base,l.repo??null,y):null,scratch:null},x=l.branch||`track/${cr(t.name||c)}-${c}`,v=[],S=[],E=null;try{if(await d("move",{layout:b}),l.kind==="worktree")if(await Bh(l.base,u,g),await Z.mkdir(u,{recursive:!0}),r){let T=Y.join(u,b.sub);await Bh(l.base,g,T),await Gn(Y.join(T,".bostrat"))&&await Z.rename(Y.join(T,".bostrat"),Y.join(u,".bostrat"));let F=Y.join(T,"AGENTS.md");Ou(await Z.readFile(F,"utf8").catch(()=>null))&&(await Z.rm(F,{force:!0}).catch(()=>{}),await My(T,"/AGENTS.md").catch(()=>{})),v.push({name:b.sub,dir:T,base:l.base,baseRef:l.baseRef??null,repo:l.repo??null})}else await Gn(Y.join(g,".bostrat"))&&await Z.rename(Y.join(g,".bostrat"),Y.join(u,".bostrat"));else await Z.rename(u,g),await Z.mkdir(u,{recursive:!0}),await Gn(Y.join(g,".bostrat"))&&await Z.rename(Y.join(g,".bostrat"),Y.join(u,".bostrat"));await d("materialize");for(let T of n){if(l.kind==="worktree"&&T.base===l.base)continue;let F=QC(T.base,T.slug,y),W=Y.join(u,F),ce=await ea(T.base);await Ay(T.base,x)?await Ll(T.base,W,x):await Qs(T.base,W,x,ce);let z={name:F,dir:W,base:T.base,baseRef:ce,repo:T.slug};v.push(z),S.push(z)}if(l.kind==="repo"&&await G3(g)){let T="scratch";for(let F=2;y.has(T);F++)T=`scratch-${F}`;y.add(T),b.scratch=T,await Dh(c,{layout:b}),await Z.rename(g,Y.join(u,T)),e.scratch=!0}await rc(u,v,x,{scratch:b.scratch,deps:{track:{id:c,cwd:u}}}),await d("relaunch"),E=await or(o.name,u,{agentCmd:a,agent:s}),await Mr({cwd:u,sessionName:o.name,agent:s,agentCmd:ba(s)}).catch(T=>{if(T?.code!=="cli-not-running")throw T});let I=await Fe(o.name,{lines:rt}).catch(()=>"");if(!To(s,I))throw new Error(`relaunched ${s} CLI never drew its composer in the hub`)}catch(I){await d("rollback",{error:I?.message||String(I)}),await zt(o.name).catch(()=>{}),await SN(b,{added:S}).catch(ce=>{console.error(`[reshape ${c}] rollback move failed: ${ce?.message||ce}`)});let T=await te(),F=he(T,c),W=F?.boxes.find(ce=>ce.name===o.name)||null;try{let ce=Uh(s,w,{skipPermissions:i,cwd:u,peerName:o.name}),z=await or(o.name,u,{agentCmd:ce,agent:s,resumeSessionId:w,pinned:m});W&&(W.hookTokenHash=Ss(z.hookToken),Qi(W,z.launchCmd),W.state="live"),Hs({cwd:u,sessionName:o.name,agent:s,agentCmd:ce})}catch(ce){console.error(`[reshape ${c}] rollback relaunch failed: ${ce?.message||ce}`)}throw F&&(Me(F,"retag-failed",{action:"reshape",box:o.name,agent:s,reason:I?.message||String(I),rolledBack:!0}),F.reshape={...F.reshape||{},step:"error",error:I?.message||String(I),finishedAt:Date.now(),recovered:"rolled-back"},await de()),e.step="error",e.recovered="rolled-back",e.error=I?.message||String(I),e.finishedAt=Date.now(),I}await d("commit");let P=await te(),L=he(P,c);if(!L)throw new Error(`track "${c}" vanished mid-reshape`);let $=L.boxes.find(I=>I.name===o.name);if(!$)throw new Error(`lead box row "${o.name}" missing during reshape commit`);let C=Date.now(),U=ns($),J=U[U.length-1];J.endedAt==null&&(J.endedAt=C),J.endReason==null&&(J.endReason="reshape");let _=await Ys({agent:s,agentCmd:a});U.push({agent:s,sessionId:E.sessionId,pinned:E.pinned===!0,cliVersion:_,startedAt:C,endedAt:null}),$.cwd=u,$.agent=s,$.cliVersion=_,$.sessionId=E.sessionId,$.pinned=E.pinned===!0,$.hookTokenHash=Ss(E.hookToken),Qi($,E.launchCmd),$.state="live",$.role="lead",delete $.readyAt,L.cwd=u,L.workspace={dir:u,kind:"multi",branch:x,repos:v},L.pendingHandoffHydrate={artifact:f||rs,at:C},Me(L,"retagged",{action:"reshape",added:e.added,removed:e.removed,scratch:e.scratch,checkpoint:e.checkpoint,views:e.views,box:o.name,agent:s,fromSessionId:w,toSessionId:E.sessionId,epoch:U.length-1,workspace:y0(L.workspace)}),L.reshape={...L.reshape||{},step:"done",finishedAt:C,error:null,checkpoint:e.checkpoint,scratch:e.scratch,views:e.views,layout:null},await de(),Hs({cwd:u,sessionName:o.name,agent:s,agentCmd:a,onReady:async()=>{$.readyAt||($.readyAt=Date.now(),await de())}}),await Gn(g)&&(l.kind==="worktree"&&await Lt(l.base,g).catch(()=>{}),await Z.rm(g,{recursive:!0,force:!0}).catch(()=>{})),e.step="done",e.finishedAt=C}async function k0(){let e=await te(),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 zt(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 w of await Z.readdir(c).catch(()=>[])){if(d.has(w))continue;let m=Y.join(c,w),f=await Z.readFile(Y.join(m,".git"),"utf8").catch(()=>null),g=f&&/^gitdir:\s*(.+?)\/\.git\/worktrees\//m.exec(f);g&&p.push({base:g[1],dir:m})}s=await SN(r.layout,{added:p})}catch(c){a=c?.message||String(c),console.error(`[reshape ${n.id}] boot rollback failed: ${a}`)}o&&!oo.has(o.state)&&(o.state="stopped");let i=`interrupted by a node restart during "${r.step}"${s?" \u2014 moved back":""}${a?` (${a})`:""}`;Me(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 de(),t}async function V3(e,t,{repo:n,repos:r,cwd:o}={}){await Z.mkdir(Mu,{recursive:!0});let s=Y.join(Mu,e),a=Array.isArray(r)?r.map(l=>typeof l=="string"?l.trim():"").filter(Boolean):[];if(a.length>=2)return q3(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!Y.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await Ts(n)??await F0(n));let i=!!(n||o),c=await xN([n,o,Xz]);if(c){let l=`track/${cr(t)}-${e}`;try{await _y(c);let u=await ea(c);await Qs(c,s,l,u),await Bu(s,Zi(e,s));let d=await Re(c).catch(()=>null);return{dir:s,base:c,branch:l,kind:"worktree",baseRef:u,repo:d}}catch(u){if(await Z.rm(s,{recursive:!0,force:!0}).catch(()=>{}),i)throw new Error(`could not open a worktree off ${c}: ${Ey(u)}`)}}return await Z.mkdir(s,{recursive:!0}),await Ty(s),await Bu(s,Zi(e,s)),{dir:s,base:null,branch:null,kind:"repo"}}async function Yh(e,t={}){return await Z.lstat(Y.join(e,".git")).catch(()=>null)&&await jl(e,[`/${bf.split(Y.sep).join("/")}`]),Gl(e,t)}async function Bu(e,t={}){await Yh(e,t);try{await Z.writeFile(Y.join(e,"AGENTS.md"),Ru,{flag:"wx"})}catch{return}await jl(e,["/AGENTS.md"])}function Y3(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(`
|
|
333
|
+
${s}`,{source:"restore"})}else Yi(o,s);return await de(),{ok:!0,draft:o.draft||null,rev:o.draftRev||0}}async function w0(e,t){if(typeof t!="string"||!t.trim())throw new Error("model (string) required");let n=t.trim(),r=he(await te(),e);if(!r)throw new Error(`track "${e}" not found`);let o=await _e(r.leadBox);if(!o)throw new Error(`lead box "${r.leadBox}" is not running`);let a=r.boxes.find(p=>p.name===r.leadBox)?.agent||o.agent||"claude",i=n$(a,n),l=[...r.events||[]].reverse().find(p=>p.type==="model-change")?.to??null;l||(l=(await cl(o.cwd,o.sessionId,{fallbackNewest:!1}).catch(()=>null))?.model??null),await Mr({cwd:o.cwd,sessionId:o.sessionId,sessionName:r.leadBox,agent:o.agent,agentCmd:ba(o.agent)});let u=await s$(a,r.leadBox,i),d={to:n,from:l,box:r.leadBox,agent:a,verified:!!u.verified};return u.awaitingConfirm?(so.set(r.id,{detail:d,at:Date.now(),setAcks:null}),{ok:!0,requested:n,leadBox:r.leadBox,...u}):(so.delete(r.id),Me(r,"model-change",d),await de(),{ok:!0,requested:n,leadBox:r.leadBox,...u})}function kN(e,t,n={}){let r=so.get(e.id);return!r||(so.delete(e.id),!t)?!1:(Me(e,"model-change",{...r.detail,verified:!0,...n}),!0)}async function W3(e,t,n){let r=so.get(e);if(!r||r.answering)return;let o=_i(t,H3);if(n){r.setAcks=o;return}if(Date.now()-r.at<U3)return;let s=he(await te(),e);if(!s)return so.delete(e);let a=r.setAcks==null?o>0:o>r.setAcks;kN(s,a,r.setAcks==null?{verified:!1}:{})&&await de()}async function xN(e){for(let t of e){if(!t||!await xi(t))continue;let n=await dI(t).catch(()=>null);if(!n)continue;if((await Z.stat(Y.join(n,".git")).catch(()=>null))?.isDirectory())return n}return null}function Qt(e){let t=e;return t?t.kind==="multi"?Array.isArray(t.repos)?t.repos.filter(Boolean):[]:t.base?[{name:Y.basename(t.base),dir:t.dir??null,base:t.base,baseRef:t.baseRef??null,repo:t.repo??null}]:[]:[]}async function ha(e){let t=[];for(let n of Qt(e?.workspace)){if(!n?.dir)continue;let r=await Xs(n.dir,{ignorePlumbing:!0}).catch(()=>!1),o=await Zs(n.dir,n.baseRef).catch(()=>0);(r||o>0)&&t.push({...n,dirty:r,ahead:o})}return t}async function g0(e){let t=e;typeof t=="string"&&!Y.isAbsolute(t)&&/^[^/\s]+\/[^/\s]+$/.test(t)&&(t=await Ts(t)??await F0(t));let n=await xN([t]);if(!n){let r=typeof e=="string"&&Y.isAbsolute(e)&&!await Z.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 await _y(n),n}async function q3(e,t,n,r){let o=`track/${cr(t)}-${e}`,s=[];try{await Z.mkdir(n,{recursive:!0});let a=new Set([".bostrat"]);for(let i of r){let c=await g0(i);if(s.some(w=>w.base===c))throw new Error(`repo tagged twice: ${i}`);let l=await Re(c).catch(()=>null),u=Y.basename(c);a.has(u)&&l&&(u=l.replace("/","-"));for(let w=2;a.has(u);w++)u=`${Y.basename(c)}-${w}`;a.add(u);let d=Y.join(n,u),p=await ea(c);await Qs(c,d,o,p),s.push({name:u,dir:d,base:c,baseRef:p,repo:l})}return await rc(n,s,o,{deps:Zi(e,n)}),{dir:n,kind:"multi",branch:o,repos:s}}catch(a){for(let i of s)await Lt(i.base,i.dir).catch(()=>{});throw await Z.rm(n,{recursive:!0,force:!0}).catch(()=>{}),a}}async function zh(e,t){let n=await te(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 unarchive it first");let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track \u2014 a single-repo Track's workspace IS its repo checkout; create the Track with multiple repos tagged instead");let s=await g0(typeof t=="string"?t.trim():t);if((o.repos??[]).some(p=>p?.base===s))throw new Error(`repo already tagged: ${t}`);let a=await Re(s).catch(()=>null),i=new Set([".bostrat",...(o.repos??[]).map(p=>p?.name).filter(Boolean)]),c=Y.basename(s);i.has(c)&&a&&(c=a.replace("/","-"));for(let p=2;i.has(c);p++)c=`${Y.basename(s)}-${p}`;let l=Y.join(o.dir,c),u=await ea(s);await Ay(s,o.branch)?await Ll(s,l,o.branch):await Qs(s,l,o.branch,u);let d={name:c,dir:l,base:s,baseRef:u,repo:a};return o.repos=[...(o.repos??[]).filter(Boolean),d],await rc(o.dir,o.repos,o.branch,{deps:x0(r)}),Me(r,"retagged",{action:"add",repo:a??s,name:c,workspace:y0(o)}),await de(),d}async function Jh(e,t){let n=await te(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);let o=r.workspace;if(o?.kind!=="multi")throw new Error("live re-tagging needs a multi-repo Track");let s=(o.repos??[]).find(c=>c&&(c.name===t||c.repo===t||c.base===t));if(!s)throw new Error(`repo "${t}" is not tagged on this Track`);if((o.repos??[]).filter(Boolean).length<=1)throw new Error("can't untag the last repo \u2014 archive or delete the Track instead");for(let c of Ut.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 Xs(s.dir,{ignorePlumbing:!0}).catch(()=>!1),i=await Zs(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 Lt(s.base,s.dir).catch(()=>{}),await Z.rm(s.dir,{recursive:!0,force:!0}).catch(()=>{}),o.repos=(o.repos??[]).filter(c=>c&&c!==s),await rc(o.dir,o.repos,o.branch,{deps:x0(r)}),Me(r,"retagged",{action:"remove",repo:s.repo??s.base,name:s.name,workspace:y0(o)}),await de(),{removed:s.name}}async function Dh(e,t){let n=await te(),r=he(n,e);r&&(r.reshape={...r.reshape||{},...t},await de())}async function G3(e){let t=await Z.readdir(e).catch(()=>[]);for(let n of t)if(!(n===".git"||n===".bostrat")){if(n==="AGENTS.md"){let r=await Z.readFile(Y.join(e,n),"utf8").catch(()=>"");if(Ou(r))continue}return!0}try{let{stdout:n}=await Zk("git",["-C",e,"rev-list","--count","HEAD"]);if(Number(n.trim())>1)return!0}catch{}return!1}function QC(e,t,n){let r=Y.basename(e);n.has(r)&&t&&(r=t.replace("/","-"));for(let o=2;n.has(r);o++)r=`${Y.basename(e)}-${o}`;return n.add(r),r}async function SN(e,{added:t=[]}={}){let{shape:n,dir:r,staging:o,sub:s,base:a,scratch:i}=e;for(let l of t)await Lt(l.base,l.dir).catch(()=>{});let c=async(l,u)=>{await Gn(l)&&!await Gn(u)&&await Z.rename(l,u)};if(n==="worktree"&&s){let l=Y.join(r,s);await Gn(l)&&(await c(Y.join(r,".bostrat"),Y.join(l,".bostrat")),await Bh(a,l,o))}if(n==="repo"&&i){let l=Y.join(r,i);await Gn(l)&&(await Gn(o)&&await Z.rm(o,{recursive:!0,force:!0}),await Z.rename(l,o))}return await Gn(o)?(await Gn(r)&&(await c(Y.join(r,".bostrat"),Y.join(o,".bostrat")),await Z.rm(r,{recursive:!0,force:!0})),n==="worktree"?await Bh(a,o,r):await Z.rename(o,r),!0):!1}async function b0(e,t,{skipPermissions:n=!0}={}){let r=await te(),o=he(r,e);if(!o)throw Ot(`track "${e}" not found`,404);if(o.archivedAt)throw Ot("track is archived \u2014 unarchive it first");try{ic(o)}catch(g){throw Object.assign(g,{status:409})}if(o.kind==="setup")throw Ot("setup boxes have no repos to reshape");if(String(o.name||"").startsWith("\u21BB"))throw Ot("this Track's repos are the loop's \u2014 propose-update the loop instead");let s=Xk.get(e);if(s&&!s.finishedAt)throw Ot("a reshape is already running for this Track");let a=ya.get(e);if(a&&!a.finishedAt)throw Ot("a lead handoff is running \u2014 retry when it settles");let i=jh.get(e);if(i&&!i.finishedAt)throw Ot("a node transfer is running \u2014 retry when it settles");if(Nh.has(e))throw Ot("an adopt is running for this Track \u2014 retry when it settles");for(let g of Ut.values())if(g.trackId===e&&!g.finishedAt)throw Ot("a subtask is still running on this Track \u2014 wait for it to merge back before reshaping");let c=(Array.isArray(t)?t:[]).map(g=>typeof g=="string"?g.trim():"").filter(Boolean);if(!c.length)throw Ot("repos (non-empty list of paths or owner/name slugs) required",400);let l=[];for(let g of c){let y;try{y=await g0(g)}catch(b){throw Ot(b?.message||String(b),400)}if(l.some(b=>b.base===y))throw Ot(`repo tagged twice: ${g}`,400);l.push({sel:g,base:y,slug:await Re(y).catch(()=>null)})}let u=o.workspace;if(u?.kind==="multi"){let g=(u.repos??[]).filter(Boolean),y=g.filter(v=>!l.some(S=>S.base===v.base)),b=l.filter(v=>!g.some(S=>S.base===v.base));if(!y.length&&!b.length)return{trackId:e,step:"done",inPlace:!0,added:[],removed:[],startedAt:Date.now(),finishedAt:Date.now(),error:null};for(let v of y){let S=await Xs(v.dir,{ignorePlumbing:!0}).catch(()=>!1),E=await Zs(v.dir,v.baseRef).catch(()=>0);if(S||E>0)throw Ot(`"${v.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 v of b){let S=await zh(e,v.base);x.added.push(S.repo??S.base)}for(let v of y)await Jh(e,v.name),x.removed.push(v.repo??v.base);return x.step="done",x.finishedAt=Date.now(),x}if(u?.kind!=="worktree"&&u?.kind!=="repo")throw Ot(`can't reshape a "${u?.kind??"unknown"}" workspace`);let d=u.kind==="worktree"&&l.some(g=>g.base===u.base);if(u.kind==="worktree"&&!d){let g=await Xs(u.dir??o.cwd,{ignorePlumbing:!0}).catch(()=>!1),y=await Zs(u.dir??o.cwd,u.baseRef).catch(()=>0);if(g||y>0)throw Ot(`"${Y.basename(u.base)}" has work (${g?"uncommitted changes":`${y} commit${y===1?"":"s"} ahead of ${u.baseRef??"base"}`}) \u2014 ship or discard it before swapping it out`)}ka(e,"reshape");let p=o.boxes.find(g=>g.name===o.leadBox)||null;if(!p)throw Ot("this Track has no lead box");let w=p.agent||"claude",m=await tc(w,n),h={trackId:e,step:"checkpoint",inPlace:!1,startedAt:Date.now(),finishedAt:null,error:null,added:l.filter(g=>!(u.kind==="worktree"&&g.base===u.base)).map(g=>g.slug??g.base),removed:u.kind==="worktree"&&!d?[u.repo??u.base]:[],scratch:!1,views:0,checkpoint:null};return Xk.set(e,h),await Dh(e,{step:h.step,startedAt:h.startedAt,finishedAt:null,error:null,added:h.added,removed:h.removed,layout:null}),K3(h,o,{desired:l,keep:d,lead:p,agent:w,agentCmd:m,skipPermissions:n}).catch(async g=>{h.error=g?.message||String(g),h.finishedAt=Date.now(),console.error(`[reshape ${e}] FAILED at step "${h.step}": ${h.error}`),await Dh(e,{step:h.step,error:h.error,finishedAt:h.finishedAt}).catch(()=>{})}),h}async function K3(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(I,T={})=>{e.step=I,console.log(`[reshape ${c}] step \u2192 ${I}`),await Dh(c,{step:I,...T})},p=await _e(o.name).catch(()=>null),w=o.sessionId??p?.sessionId??null,m=o.pinned===!0;if(await d("checkpoint"),e.checkpoint="llm",!p)e.checkpoint="skipped-dead";else if(Uo(s))e.checkpoint="skipped-capped";else try{await Qp(o.name,{timeoutMs:e0,quiesce:{box:o,reason:"reshape",onWait:()=>d("await-turn"),onResume:()=>d("checkpoint")}})}catch{e.checkpoint="reconstructed"}let h=null;e.checkpoint!=="llm"&&(h=await ef(c,u,{trackName:t.name||c}).catch(()=>null)),await d("quiesce"),e.views=await nk(c).catch(()=>0),await tp(u).catch(()=>{}),p&&(await Xg(o.name,{fromAgent:s}).catch(()=>{}),await zt(o.name).catch(()=>{}));let g=`${u}.reshape-${Date.now()}`,y=new Set([".bostrat"]),b={shape:l.kind,dir:u,staging:g,base:l.kind==="worktree"?l.base:null,sub:l.kind==="worktree"&&r?QC(l.base,l.repo??null,y):null,scratch:null},x=l.branch||`track/${cr(t.name||c)}-${c}`,v=[],S=[],E=null;try{if(await d("move",{layout:b}),l.kind==="worktree")if(await Bh(l.base,u,g),await Z.mkdir(u,{recursive:!0}),r){let T=Y.join(u,b.sub);await Bh(l.base,g,T),await Gn(Y.join(T,".bostrat"))&&await Z.rename(Y.join(T,".bostrat"),Y.join(u,".bostrat"));let F=Y.join(T,"AGENTS.md");Ou(await Z.readFile(F,"utf8").catch(()=>null))&&(await Z.rm(F,{force:!0}).catch(()=>{}),await My(T,"/AGENTS.md").catch(()=>{})),v.push({name:b.sub,dir:T,base:l.base,baseRef:l.baseRef??null,repo:l.repo??null})}else await Gn(Y.join(g,".bostrat"))&&await Z.rename(Y.join(g,".bostrat"),Y.join(u,".bostrat"));else await Z.rename(u,g),await Z.mkdir(u,{recursive:!0}),await Gn(Y.join(g,".bostrat"))&&await Z.rename(Y.join(g,".bostrat"),Y.join(u,".bostrat"));await d("materialize");for(let T of n){if(l.kind==="worktree"&&T.base===l.base)continue;let F=QC(T.base,T.slug,y),W=Y.join(u,F),ce=await ea(T.base);await Ay(T.base,x)?await Ll(T.base,W,x):await Qs(T.base,W,x,ce);let z={name:F,dir:W,base:T.base,baseRef:ce,repo:T.slug};v.push(z),S.push(z)}if(l.kind==="repo"&&await G3(g)){let T="scratch";for(let F=2;y.has(T);F++)T=`scratch-${F}`;y.add(T),b.scratch=T,await Dh(c,{layout:b}),await Z.rename(g,Y.join(u,T)),e.scratch=!0}await rc(u,v,x,{scratch:b.scratch,deps:{track:{id:c,cwd:u}}}),await d("relaunch"),E=await or(o.name,u,{agentCmd:a,agent:s}),await Mr({cwd:u,sessionName:o.name,agent:s,agentCmd:ba(s)}).catch(T=>{if(T?.code!=="cli-not-running")throw T});let I=await Fe(o.name,{lines:rt}).catch(()=>"");if(!To(s,I))throw new Error(`relaunched ${s} CLI never drew its composer in the hub`)}catch(I){await d("rollback",{error:I?.message||String(I)}),await zt(o.name).catch(()=>{}),await SN(b,{added:S}).catch(ce=>{console.error(`[reshape ${c}] rollback move failed: ${ce?.message||ce}`)});let T=await te(),F=he(T,c),W=F?.boxes.find(ce=>ce.name===o.name)||null;try{let ce=Uh(s,w,{skipPermissions:i,cwd:u,peerName:o.name}),z=await or(o.name,u,{agentCmd:ce,agent:s,resumeSessionId:w,pinned:m});W&&(W.hookTokenHash=Ss(z.hookToken),Qi(W,z.launchCmd),W.state="live"),Hs({cwd:u,sessionName:o.name,agent:s,agentCmd:ce})}catch(ce){console.error(`[reshape ${c}] rollback relaunch failed: ${ce?.message||ce}`)}throw F&&(Me(F,"retag-failed",{action:"reshape",box:o.name,agent:s,reason:I?.message||String(I),rolledBack:!0}),F.reshape={...F.reshape||{},step:"error",error:I?.message||String(I),finishedAt:Date.now(),recovered:"rolled-back"},await de()),e.step="error",e.recovered="rolled-back",e.error=I?.message||String(I),e.finishedAt=Date.now(),I}await d("commit");let P=await te(),L=he(P,c);if(!L)throw new Error(`track "${c}" vanished mid-reshape`);let $=L.boxes.find(I=>I.name===o.name);if(!$)throw new Error(`lead box row "${o.name}" missing during reshape commit`);let C=Date.now(),U=ns($),J=U[U.length-1];J.endedAt==null&&(J.endedAt=C),J.endReason==null&&(J.endReason="reshape");let _=await Ys({agent:s,agentCmd:a});U.push({agent:s,sessionId:E.sessionId,pinned:E.pinned===!0,cliVersion:_,startedAt:C,endedAt:null}),$.cwd=u,$.agent=s,$.cliVersion=_,$.sessionId=E.sessionId,$.pinned=E.pinned===!0,$.hookTokenHash=Ss(E.hookToken),Qi($,E.launchCmd),$.state="live",$.role="lead",delete $.readyAt,L.cwd=u,L.workspace={dir:u,kind:"multi",branch:x,repos:v},L.pendingHandoffHydrate={artifact:h||rs,at:C},Me(L,"retagged",{action:"reshape",added:e.added,removed:e.removed,scratch:e.scratch,checkpoint:e.checkpoint,views:e.views,box:o.name,agent:s,fromSessionId:w,toSessionId:E.sessionId,epoch:U.length-1,workspace:y0(L.workspace)}),L.reshape={...L.reshape||{},step:"done",finishedAt:C,error:null,checkpoint:e.checkpoint,scratch:e.scratch,views:e.views,layout:null},await de(),Hs({cwd:u,sessionName:o.name,agent:s,agentCmd:a,onReady:async()=>{$.readyAt||($.readyAt=Date.now(),await de())}}),await Gn(g)&&(l.kind==="worktree"&&await Lt(l.base,g).catch(()=>{}),await Z.rm(g,{recursive:!0,force:!0}).catch(()=>{})),e.step="done",e.finishedAt=C}async function k0(){let e=await te(),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 zt(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 w of await Z.readdir(c).catch(()=>[])){if(d.has(w))continue;let m=Y.join(c,w),h=await Z.readFile(Y.join(m,".git"),"utf8").catch(()=>null),g=h&&/^gitdir:\s*(.+?)\/\.git\/worktrees\//m.exec(h);g&&p.push({base:g[1],dir:m})}s=await SN(r.layout,{added:p})}catch(c){a=c?.message||String(c),console.error(`[reshape ${n.id}] boot rollback failed: ${a}`)}o&&!oo.has(o.state)&&(o.state="stopped");let i=`interrupted by a node restart during "${r.step}"${s?" \u2014 moved back":""}${a?` (${a})`:""}`;Me(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 de(),t}async function V3(e,t,{repo:n,repos:r,cwd:o}={}){await Z.mkdir(Mu,{recursive:!0});let s=Y.join(Mu,e),a=Array.isArray(r)?r.map(l=>typeof l=="string"?l.trim():"").filter(Boolean):[];if(a.length>=2)return q3(e,t,s,a);a.length===1&&!n&&(n=a[0]),typeof n=="string"&&!Y.isAbsolute(n)&&/^[^/\s]+\/[^/\s]+$/.test(n)&&(n=await Ts(n)??await F0(n));let i=!!(n||o),c=await xN([n,o,Xz]);if(c){let l=`track/${cr(t)}-${e}`;try{await _y(c);let u=await ea(c);await Qs(c,s,l,u),await Bu(s,Zi(e,s));let d=await Re(c).catch(()=>null);return{dir:s,base:c,branch:l,kind:"worktree",baseRef:u,repo:d}}catch(u){if(await Z.rm(s,{recursive:!0,force:!0}).catch(()=>{}),i)throw new Error(`could not open a worktree off ${c}: ${Ey(u)}`)}}return await Z.mkdir(s,{recursive:!0}),await Ty(s),await Bu(s,Zi(e,s)),{dir:s,base:null,branch:null,kind:"repo"}}async function Yh(e,t={}){return await Z.lstat(Y.join(e,".git")).catch(()=>null)&&await jl(e,[`/${bf.split(Y.sep).join("/")}`]),Gl(e,t)}async function Bu(e,t={}){await Yh(e,t);try{await Z.writeFile(Y.join(e,"AGENTS.md"),Ru,{flag:"wx"})}catch{return}await jl(e,["/AGENTS.md"])}function Y3(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(`
|
|
334
334
|
`),o=n?`
|
|
335
335
|
\`${n}/\` is this Track's pre-repo workspace, carried over when the
|
|
336
336
|
Track was reshaped onto these repos. It is not part of any tagged repo and
|
|
@@ -352,12 +352,12 @@ Dependencies: none of these checkouts has installed dependencies until someone
|
|
|
352
352
|
installs them. \`${bf}\` in this directory lists every package
|
|
353
353
|
directory across the repos above with its state and install command \u2014 read it
|
|
354
354
|
before running a test, a build or a view.
|
|
355
|
-
${o}`}async function rc(e,t,n,r={}){let o=Y3(t,n,r);for(let s of["CLAUDE.md","AGENTS.md"])await Z.writeFile(Y.join(e,s),o).catch(()=>{});await Yh(e,r.deps)}async function S0(){let e={refreshed:0,removed:0,deps:0,codexGlobal:null};try{await Z.mkdir(xr,{recursive:!0}),await Z.writeFile(Y.join(xr,"CLAUDE.md"),z3).catch(()=>{}),await Z.writeFile(Y.join(xr,"AGENTS.md"),Ru).catch(()=>{});let t=process.env.CODEX_HOME||Y.join(process.env.HOME||"/tmp",".codex");if((await Z.stat(t).catch(()=>null))?.isDirectory()){let r=Y.join(t,"AGENTS.md"),o=await Z.readFile(r,"utf8").catch(()=>null);o===null?(await Z.writeFile(r,Wk,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):Ou(o)&&o!==Wk&&(await Z.writeFile(r,Wk).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[Mu,ec]){let o=await Z.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=Y.join(r,s.name);await Yh(a,{kick:!1})&&e.deps++;let i=Y.join(a,"AGENTS.md"),c=await Z.readFile(i,"utf8").catch(()=>null);c!==null&&Ou(c)&&c!==Ru&&(await Z.writeFile(i,Ru).catch(()=>{}),e.refreshed++);let l=Y.join(a,"CLAUDE.md"),u=await Z.readFile(l,"utf8").catch(()=>null);u!==null&&Ou(u)&&(await Z.rm(l,{force:!0}).catch(()=>{}),await My(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function AN(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of Qt(t))n.base&&n.dir&&await Lt(n.base,n.dir).catch(()=>{});await Z.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await Lt(t.base,t.dir):await Z.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function Xh({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");if(e.trim().length>Fu)throw new Error(`name too long (max ${Fu} chars)`);let
|
|
355
|
+
${o}`}async function rc(e,t,n,r={}){let o=Y3(t,n,r);for(let s of["CLAUDE.md","AGENTS.md"])await Z.writeFile(Y.join(e,s),o).catch(()=>{});await Yh(e,r.deps)}async function S0(){let e={refreshed:0,removed:0,deps:0,codexGlobal:null};try{await Z.mkdir(xr,{recursive:!0}),await Z.writeFile(Y.join(xr,"CLAUDE.md"),z3).catch(()=>{}),await Z.writeFile(Y.join(xr,"AGENTS.md"),Ru).catch(()=>{});let t=process.env.CODEX_HOME||Y.join(process.env.HOME||"/tmp",".codex");if((await Z.stat(t).catch(()=>null))?.isDirectory()){let r=Y.join(t,"AGENTS.md"),o=await Z.readFile(r,"utf8").catch(()=>null);o===null?(await Z.writeFile(r,Wk,{flag:"wx"}).catch(()=>{}),e.codexGlobal="created"):Ou(o)&&o!==Wk&&(await Z.writeFile(r,Wk).catch(()=>{}),e.codexGlobal="refreshed")}for(let r of[Mu,ec]){let o=await Z.readdir(r,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if(!s.isDirectory())continue;let a=Y.join(r,s.name);await Yh(a,{kick:!1})&&e.deps++;let i=Y.join(a,"AGENTS.md"),c=await Z.readFile(i,"utf8").catch(()=>null);c!==null&&Ou(c)&&c!==Ru&&(await Z.writeFile(i,Ru).catch(()=>{}),e.refreshed++);let l=Y.join(a,"CLAUDE.md"),u=await Z.readFile(l,"utf8").catch(()=>null);u!==null&&Ou(u)&&(await Z.rm(l,{force:!0}).catch(()=>{}),await My(a,"/CLAUDE.md"),e.removed++)}}}catch{}return e}async function AN(e){let t=e.workspace;if(!(!t||!t.dir))try{if(t.kind==="multi"){for(let n of Qt(t))n.base&&n.dir&&await Lt(n.base,n.dir).catch(()=>{});await Z.rm(t.dir,{recursive:!0,force:!0})}else t.kind==="worktree"&&t.base?await Lt(t.base,t.dir):await Z.rm(t.dir,{recursive:!0,force:!0})}catch{}}async function Xh({name:e,cwd:t,repo:n,repos:r,agent:o="claude",model:s=null,skipPermissions:a=!0,launchedFrom:i=null}){if(typeof e!="string"||!e.trim())throw new Error("name (string) required");if(e.trim().length>Fu)throw new Error(`name too long (max ${Fu} chars)`);let c=await tc(o,a,s),l=Ys({agent:o,agentCmd:c}),u=await te(),d=Hu().slice(0,8),p=await V3(d,e,{repo:n,repos:r,cwd:t}),w=new Set(u.tracks.flatMap(y=>(y.boxes||[]).map(b=>b.name))),m=`${cr(e).slice(0,50)} lead`;w.has(hp(m))&&(m=`${cr(e).slice(0,50)} ${d} lead`);let h=await or(m,p.dir,{agentCmd:c,agent:o,trackId:d,freshWorkspace:!0}),g={id:d,name:e.trim(),cwd:h.cwd,workspace:p,leadBox:h.name,boxes:[M0(h,"lead","live")],events:[],createdAt:Date.now()};return g.boxes[0].cliVersion=await l,Me(g,"opened",{agent:o,...s?{model:s}:{},box:h.name,cliVersion:g.boxes[0].cliVersion,skipPermissions:a,...i?{launchedFrom:i}:{},name:g.name,cwd:g.cwd,workspace:{base:p.base??null,branch:p.branch,kind:p.kind,...p.baseRef?{baseRef:p.baseRef}:{},...p.repo?{repo:p.repo}:{},...p.repos?{repos:p.repos.map(({name:y,base:b,baseRef:x,repo:v})=>({name:y,base:b,baseRef:x,repo:v}))}:{}}}),u.tracks.push(g),await de(),Ly(p.dir).catch(()=>{}),Hs({cwd:h.cwd,sessionName:h.name,agent:o,agentCmd:c,onBlocked:({message:y})=>aN(g.id,{box:h.name,agent:o,message:y}).catch(()=>{}),onReady:async()=>{let y=g.boxes.find(b=>b.name===g.leadBox);!y||y.readyAt||(y.readyAt=Date.now(),await de())}}),pn(g)}async function v0({provider:e="claude",fresh:t=!1}={}){if(!X3.has(e))throw new Error(`unknown setup provider "${e}" (claude | codex | cursor)`);let r=(await te()).tracks.find(u=>u.kind==="setup"&&u.setup?.provider===e&&!u.archivedAt);if(r){if(!t){let u=await pn(r);if(u.boxes.find(p=>p.name===u.leadBox)?.state==="live")return u}await xa(r.id).catch(()=>{})}let o=(await tc(e,!1)).replace(/\s+--(?:dangerously-skip-permissions|dangerously-bypass-approvals-and-sandbox)\b/g,""),s=Hu().slice(0,8),a=Y.join(xr,"setup",s);await Z.mkdir(a,{recursive:!0});let i=await or(`Connect ${e} ${s}`,a,{agentCmd:o,agent:e,firstRun:!0});e==="codex"&&Hs({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:[M0(i,"lead","live")],events:[],createdAt:Date.now()};return Me(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 te()).tracks.push(c),await de(),pn(c)}async function A0(e,t,n){await tp(t.cwd).catch(()=>{}),await nk(e).catch(()=>{});let r=ya.get(e);r&&!r.finishedAt&&(r.error=n,r.finishedAt=Date.now()),ya.delete(e),t.handoff&&!t.handoff.finishedAt&&(t.handoff.step="error",t.handoff.error=n,t.handoff.finishedAt=Date.now());for(let a of va(e))a.finishedAt||(a.canceled=!0,a.finishedAt=Date.now()),await G0(a).catch(()=>{}),Ut.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 te(),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 zt(a.name).catch(()=>{})}async function T0(e,{cascadeMocks:t=!0,cascadeRunbooks:n=!1}={}){let r=await te(),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 GM(s),f0(e),await A0(e,s,"track deleted"),n?await SC(e).catch(()=>{}):await xC(e).catch(()=>{}),await c$(),await AN(s),await Uw(s.id),t&&await KM(e).catch(()=>{}),t?await lC(e).catch(()=>{}):await cC(s).catch(()=>{}),Me(s,"track-deleted",{name:s.name,boxes:s.boxes.length,ageMs:s.createdAt?Date.now()-s.createdAt:null}),r.tracks.splice(o,1),await de(),{ok:!0,id:e,name:s.name,boxes:s.boxes.length}}async function xa(e){let t=await te(),n=he(t,e);if(!n)throw new Error(`track "${e}" not found`);if(n.archivedAt)throw new Error(`track "${e}" is already archived`);if(n.archivedAt=Date.now(),f0(e),Me(n,"archived",{boxes:n.boxes.length}),await de(),n.kind==="setup")return await TN(e),pn(n);Lu.add(e);let r=await pn(n);return e8(e).catch(()=>{}).finally(()=>Lu.delete(e)),{...r,archiving:!0}}async function e8(e){try{await t8(e)}catch{}await TN(e).catch(()=>{})}async function TN(e){let t=await te(),n=he(t,e);if(!(!n||!n.archivedAt)){await A0(e,n,"track archived"),await Uw(e);for(let r of n.boxes)oo.has(r.state)||(r.state="stopped");await de()}}async function t8(e){let t=await te(),n=he(t,e);if(!n||!n.archivedAt)return;let r=null,o=[],s="derived",a=(n.events||[]).some(l=>l.type==="said"),i=n.leadBox?await _e(n.leadBox).catch(()=>null):null;if(i?.cwd&&a)try{({text:r,items:o}=await g_(n.leadBox,i.cwd,{timeoutMs:Q3})),s="lead-cli"}catch{}if(r||(r=C_(n,await V(n).catch(()=>[]))),!r)return;let c={text:r,source:s,at:Date.now()};o.length&&(c.items=o),n.beat=c,await D(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 de()}async function Gr(e,t){let n=await pt(e,t).catch(()=>null);if(!n?.archiveOnMerge||!n.trackId)return!1;let r=await E0(n);if(r.length){for(let o of r)await na(o.repo,o.number,!0).catch(()=>{});return!1}try{return await xa(n.trackId),!0}catch(o){if(/already archived/i.test(String(o?.message||o)))return!1;throw o}}async function E0(e){return(await Ln().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 Kr(e,t){return Zh(e,t,"merged")}async function Sa(e,t){let n=await pt(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 E0(n);if(o.length){let c=[...n.followupPending||[],r];for(let l of o)await _$(l.repo,l.number,c).catch(()=>{});return null}let s=[...n.followupPending||[],r],a=he(await te(),n.trackId);if(!a)return null;let i=s[0];return cu(await pn(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 Zh(e,t,n="merged"){let r=await pt(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 E0(r);if(s.length){let i=[...r.notifyPending||[],o];for(let c of s)await E$(c.repo,c.number,i).catch(()=>{});return!1}let a=[...r.notifyPending||[],o];if(!await y$(r.repo,r.number).catch(()=>!0))return!1;try{return await Ht(r.trackId,EN(a),{kind:"merge-notify"}),!0}catch{return await ra(r.repo,r.number,!0).catch(()=>{}),!1}}function EN(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 ${eN[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 ${eN[i.outcome]??i.outcome}`).join(`
|
|
356
356
|
`),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}
|
|
357
357
|
${s}
|
|
358
|
-
${a}`}async function Gu(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<sl()?!1:sr(e.name)}async function ju(e,t,n){return!t||e.archivedAt||oo.has(t.state)?!1:(await ne({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 zt(t.name).catch(()=>{}),t.state="stopped",oc(e))}async function oc(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=qk.get(r.name);if(o)return o;let s=r8(e,r,{freshSession:t,reason:n}).finally(()=>qk.delete(r.name));return qk.set(r.name,s),s}async function _0(e){let n=(await te()).tracks.find(o=>o.leadBox===e);if(!n||n.archivedAt||n.transferredTo||Date.now()-(Gk.get(e)??0)<n8)return!1;let r=await oc(n,{reason:"attach"}).catch(()=>!1);return r?(Gk.delete(e),await de()):Gk.set(e,Date.now()),r}async function r8(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||oo.has(t.state)||await _e(t.name))return!1;let o=n===!0,s=o?Hu():null,a=o?nl(Qk(t.agent),s,t.name):Uh(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await fp(a);if(i===za)return Me(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===Ja&&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(ns(t)))}:null,l=Date.now();if(o){let u=ns(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=Ys({agent:t.agent,agentCmd:a}),d=await or(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=Ss(d.hookToken),Qi(t,d.launchCmd),t.cliVersion=await u,ns(t)[t.epochs.length-1].cliVersion=t.cliVersion,Hs({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a,onBlocked:({message:p})=>aN(e.id,{box:t.name,agent:t.agent,message:p}).catch(()=>{})}),t.state="live",o&&Me(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 Ki(t.cwd)}),Me(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),Me(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function sc(e,{freshSession:t=!1,reason:n=null}={}){let r=await te(),o=he(r,e);if(!o)throw new Error(`track "${e}" not found`);if(!o.archivedAt)throw new Error(`track "${e}" is not archived`);return delete o.archivedAt,Lu.delete(e),Me(o,"unarchived",n?{reason:n}:{}),o.workspace?.dir&&await Yh(o.workspace.dir,x0(o)).catch(()=>{}),await oc(o,t?{freshSession:!0,reason:"loop-fire"}:{}),await de(),pn(o)}async function I0(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>Fu)throw new Error(`name too long (max ${Fu} chars)`);let r=await te(),o=he(r,e);if(!o)throw new Error(`track "${e}" not found`);if(String(o.name||"").startsWith("\u21BB"))throw new Error("loop run Tracks are named by their loop \u2014 rename the loop on the Loops tab");if(n===o.name)return pn(o);let s=o.name;return o.name=n,Me(o,"renamed",{from:s,to:n}),await de(),pn(o)}async function $0(){let e=await te(),t=0;for(let n of e.tracks||[])n.transferredTo&&Ef(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await de(),t}async function R0(){let e=await te(),t=new Set((await sn()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!He(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(He(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await zt(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):Me(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!oo.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await de(),r}function s8(){$u.clear()}async function Qh(e,{freshSession:t=!1,force:n=!1}={}){let r=await te(),o=he(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before restarting the lead`);ic(o);let s=o.boxes.find(c=>c.name===o.leadBox);if(!s)throw new Error(`track "${e}" has no lead box`);if(oo.has(s.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await _e(o.leadBox)){let c=cn(o.leadBox,await Fe(o.leadBox,{lines:rt}).catch(()=>"")),l=Sl(s.agent,c);if(l&&!n){let u=$u.get(e),d=Date.now(),p=u&&d-u.at<o8?u.count+1:1;$u.set(e,{count:p,at:d});let w=new Error(p>=2?"lead is mid-turn \u2014 retry when it goes idle, or restart anyway if the screen is stuck":"lead is mid-turn \u2014 retry when it goes idle");throw w.code="lead-mid-turn",w.refusals=p,w.forceAvailable=p>=2,w}$u.delete(e),n&&(ka(e,"restart"),await ne({flow:"restart",phase:"forced",trackId:e,sessionName:o.leadBox,agent:s.agent,busy:l,paneTail:!0}).catch(()=>{})),await zt(o.leadBox),s.state="stopped"}else $u.delete(e);let i=await oc(o,t?{freshSession:!0,reason:"loop-fire"}:{});if(await de(),!i)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return pn(o)}async function a8(e,t,{escSends:n=0,kept:r=0}={}){if(!e||!t)return null;let o=Hu();return await D(e,{type:"box.stuck.detected",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent,payload:{ts:Date.now(),offerId:o,box:t.name,agent:t.agent,escSends:n,kept:r}}),o}async function O0(e,t,n,{force:r=!1}={}){let o=await ye(e);if(!o)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let s=await V(o).catch(()=>[]),a=s.find(d=>(d.type==="box.fullscreen.detected"||d.type==="box.stuck.detected")&&d.payload?.offerId===t);if(!a)throw new Error("unknown offer");let i=a.type==="box.stuck.detected",c=i?"box.stuck.answered":"box.fullscreen.answered";if(s.some(d=>d.type===c&&d.payload?.offerId===t))throw new Error("offer already answered");let u=n&&(i||r===!0);return n&&await Qh(e,{force:u}),await D(o,{type:c,actor:"user",source:"orchestrator",boxId:o.leadBox,payload:{ts:Date.now(),offerId:t,action:n?"restarted":"dismiss",...u?{forced:!0}:{}}}).catch(()=>{}),{ok:!0,action:n?"restarted":"dismiss",forced:u}}function Qi(e,t){if(!e)return null;let n=Us(t);return e.launchEcho=n,li(e.name,n),n}function M0(e,t,n){let r={name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:Ss(e.hookToken),createdAt:Date.now()};return Qi(r,e.launchCmd),r}function tN(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return nh({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function ns(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 Lh(e,t){let n=await te(),r=he(n,e);r&&(r.handoff={...r.handoff||{},...t},await de())}function _N(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 C0(){let e=await te(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=_N(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await _e(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=ns(l),p=d[d.length-1],w=p.agent,m=p.sessionId??null;p.endedAt=u,r.reason&&(p.endReason=r.reason);let f=c.agent==="claude"&&!!c.sessionId,g=await Ys({agent:r.toAgent});d.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:f,cliVersion:g,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.cliVersion=g,l.sessionId=c.sessionId||null,l.pinned=f,l.state="live",n.pendingHandoffHydrate={artifact:rs,at:u},Me(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:w,toAgent:r.toAgent,fromSessionId:m,toSessionId:c.sessionId||null,epoch:d.length-1,singleBox:!0,skipPermissions:r.skipPermissions,reason:r.reason??null,handoffStartedAt:r.startedAt,recovered:!0,standing:await Ki(l.cwd)}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await ne({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 ne({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await zt(i).catch(()=>{}),a&&await zt(a).catch(()=>{})}return t&&await de(),t}async function em(e,t,n=!0,r=null,{reviveArchived:o=!1}={}){let s=ya.get(e);if(s&&!s.finishedAt)throw new Error("a lead handoff is already running for this Track");let a=he(await te(),e);if(!a)throw new Error(`track "${e}" not found`);if(a.archivedAt&&!o)throw new Error(`track "${e}" is archived \u2014 restore it before handing off`);ic(a),ka(e,"handoff");let i=await tc(t,n),c=Uo(t);if(c){let w=new Error(`can't hand off to ${t} \u2014 its ${c.window} spend limit is reached ($${c.spentUsd.toFixed(2)} of $${c.limitUsd.toFixed(2)})`);throw w.usageCap=c,w}let l=iN(r),u=!1;a.archivedAt&&(await sc(e,{reason:l?.code==="context-refresh"?"context-refresh":"lead-handoff"}),a=he(await te(),e),u=!0);let d=await _e(a.leadBox);if(!d)throw new Error(`lead box "${a.leadBox}" is not running`);let p={trackId:e,step:"checkpoint",fromBox:a.leadBox,toAgent:t,skipPermissions:n,reason:l,revived:u,toBox:a.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return ya.set(e,p),await Lh(e,{step:p.step,fromBox:p.fromBox,toAgent:t,toBox:p.toBox,skipPermissions:n,startedAt:p.startedAt,finishedAt:null,error:null}),i8(p,a,d,i,t).catch(async w=>{p.error=w?.message||String(w),p.finishedAt=Date.now(),console.error(`[lead-handoff ${e}] FAILED at step "${p.step}": ${p.error}`),await Lh(e,{step:p.step,error:p.error,finishedAt:p.finishedAt}).catch(()=>{}),ne({flow:"lead-handoff",phase:"failed",trackId:e,step:p.step,error:p.error,fromBox:p.fromBox,toAgent:p.toAgent,toBox:p.toBox}).catch(()=>{})}),ne({flow:"lead-handoff",phase:"started",trackId:e,fromBox:p.fromBox,toAgent:t,cwd:d.cwd}).catch(()=>{}),p}async function i8(e,t,n,r,o){let s=async(P,L={})=>{e.step=P,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${P}`),await Lh(e.trackId,{step:P,toBox:e.toBox}),await ne({flow:"lead-handoff",phase:P,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:L.sessionName,...L})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await te(),i=he(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,Uo(c))e.checkpoint="skipped-capped";else try{let P=await Qp(e.fromBox,{timeoutMs:e0,quiesce:{box:i?{...i,name:e.fromBox}:n,reason:e.reason?.code||"lead-handoff",onWait:async L=>{e.wait=L,await s("await-turn",{sessionName:e.fromBox,wait:L})},onResume:async()=>{e.wait=null,await s("checkpoint",{sessionName:e.fromBox})}}});e.quiescence=Wg(P),e.waitedMs=(P.quiescence?.pre?.waitedMs||0)+(P.quiescence?.post?.waitedMs||0)}catch(P){e.checkpoint="reconstructed",e.quiescence=Wg(P),e.waitedMs=P?.quiescence?.pre?.waitedMs||0,e.wait=null,await ne({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:P?.message||String(P)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await ef(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=Ys({agent:o,agentCmd:r}),w=await Zg(e.fromBox,{agentCmd:r,agent:o});li(e.fromBox,Us(w.launchCmd)),await s("hydrate",{sessionName:e.fromBox});let m=Us(w.launchCmd);await Mr({cwd:n.cwd,sessionId:w.sessionId,sessionName:e.fromBox,agent:o,agentCmd:ba(o),launchEcho:m}).catch(P=>{if(P?.code!=="cli-not-running")throw P});let f=kl(await Fe(e.fromBox,{lines:rt}).catch(()=>""),m);if(await ne({flow:"lead-handoff",phase:"hydrate-ready",trackId:e.trackId,sessionName:e.fromBox,toAgent:o,up:To(o,f),paneTail:!0}).catch(()=>{}),!To(o,f)){await s("rollback",{sessionName:e.fromBox,fromAgent:c});let P=Uh(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox}),L=await Zg(e.fromBox,{agentCmd:P,agent:c,resumeSessionId:l,pinned:u});li(e.fromBox,Us(L.launchCmd));let $=await te(),C=he($,e.trackId);if(C){let U=C.boxes.find(J=>J.name===e.fromBox);U&&(U.state="live",Qi(U,L.launchCmd)),Me(C,"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 de()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let g=await te(),y=he(g,e.trackId);if(!y)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let b=y.boxes.find(P=>P.name===e.fromBox);if(!b)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let x=Date.now(),v=ns(b),S=v[v.length-1];S.endedAt=x,e.reason&&(S.endReason=e.reason);let E=await p;v.push({agent:o,sessionId:w.sessionId,pinned:w.pinned,cliVersion:E,startedAt:x,endedAt:null}),b.agent=o,b.sessionId=w.sessionId,b.pinned=w.pinned,b.cliVersion=E,Qi(b,w.launchCmd),b.state="live",b.role="lead",y.pendingHandoffHydrate={artifact:e.statusArtifact||rs,at:x},Me(y,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:w.sessionId,epoch:v.length-1,singleBox:!0,forced:w.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,cliVersion:E,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint,quiescence:e.quiescence||void 0,waitedMs:e.waitedMs||void 0,standing:await Ki(b.cwd)}),await de(),await s("done",{sessionName:e.fromBox}),await Lh(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function D0(e){let t=jh.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await te(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 restore it before moving it");if(r.kind==="setup")throw new Error("setup boxes don't move");if(r.transferredTo)throw new Error(`track already transferred to ${r.transferredTo}`);let o=ya.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Ut.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 jh.set(e,s),c8(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 c8(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await _e(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&Uo(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await Qp(t.leadBox,{timeoutMs:e0,quiesce:{box:n,reason:"transfer-out",onWait:()=>{e.step="await-turn"},onResume:()=>{e.step="checkpoint"}}})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await ef(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 Qt(t.workspace)){if(!u?.dir)continue;let d={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await Kn(u.dir,["push","origin",o],N0);let{stdout:p}=await Kn(u.dir,["rev-parse","HEAD"]);d.baseSha=p.trim(),d.pushed=!0}catch(p){d.error=String(p?.message||p).split(`
|
|
358
|
+
${a}`}async function Gu(e){return!e?.name||!e.createdMs||Date.now()-e.createdMs<sl()?!1:sr(e.name)}async function ju(e,t,n){return!t||e.archivedAt||oo.has(t.state)?!1:(await ne({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 zt(t.name).catch(()=>{}),t.state="stopped",oc(e))}async function oc(e,{freshSession:t=!1,reason:n=null}={}){let r=e.boxes.find(a=>a.name===e.leadBox);if(!r)return!1;let o=qk.get(r.name);if(o)return o;let s=r8(e,r,{freshSession:t,reason:n}).finally(()=>qk.delete(r.name));return qk.set(r.name,s),s}async function _0(e){let n=(await te()).tracks.find(o=>o.leadBox===e);if(!n||n.archivedAt||n.transferredTo||Date.now()-(Gk.get(e)??0)<n8)return!1;let r=await oc(n,{reason:"attach"}).catch(()=>!1);return r?(Gk.delete(e),await de()):Gk.set(e,Date.now()),r}async function r8(e,t,{freshSession:n=!1,reason:r=null}={}){if(e.archivedAt||e.transferredTo||oo.has(t.state)||await _e(t.name))return!1;let o=n===!0,s=o?Hu():null,a=o?nl(Qk(t.agent),s,t.name):Uh(t.agent,t.sessionId,{cwd:t.cwd,peerName:t.name}),i=await fp(a);if(i===za)return Me(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:`agent "${t.agent}" is not installed on this box`}),!1;i===Ja&&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(ns(t)))}:null,l=Date.now();if(o){let u=ns(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=Ys({agent:t.agent,agentCmd:a}),d=await or(t.name,t.cwd,{agentCmd:a,agent:t.agent,resumeSessionId:t.sessionId,pinned:t.pinned===!0});return t.hookTokenHash=Ss(d.hookToken),Qi(t,d.launchCmd),t.cliVersion=await u,ns(t)[t.epochs.length-1].cliVersion=t.cliVersion,Hs({cwd:t.cwd,sessionName:t.name,agent:t.agent,agentCmd:a,onBlocked:({message:p})=>aN(e.id,{box:t.name,agent:t.agent,message:p}).catch(()=>{})}),t.state="live",o&&Me(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 Ki(t.cwd)}),Me(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),Me(e,"rehydrate-failed",{box:t.name,agent:t.agent,reason:String(u?.message||u)}),!1}}async function sc(e,{freshSession:t=!1,reason:n=null}={}){let r=await te(),o=he(r,e);if(!o)throw new Error(`track "${e}" not found`);if(!o.archivedAt)throw new Error(`track "${e}" is not archived`);return delete o.archivedAt,Lu.delete(e),Me(o,"unarchived",n?{reason:n}:{}),o.workspace?.dir&&await Yh(o.workspace.dir,x0(o)).catch(()=>{}),await oc(o,t?{freshSession:!0,reason:"loop-fire"}:{}),await de(),pn(o)}async function I0(e,t){let n=typeof t=="string"?t.trim():"";if(!n)throw new Error("name (non-empty string) required");if(n.length>Fu)throw new Error(`name too long (max ${Fu} chars)`);let r=await te(),o=he(r,e);if(!o)throw new Error(`track "${e}" not found`);if(String(o.name||"").startsWith("\u21BB"))throw new Error("loop run Tracks are named by their loop \u2014 rename the loop on the Loops tab");if(n===o.name)return pn(o);let s=o.name;return o.name=n,Me(o,"renamed",{from:s,to:n}),await de(),pn(o)}async function $0(){let e=await te(),t=0;for(let n of e.tracks||[])n.transferredTo&&Ef(n,{at:n.transferredAt??Date.now()})&&t++;return t&&await de(),t}async function R0(){let e=await te(),t=new Set((await sn()).map(s=>s.name)),n=new Set((e.tracks||[]).filter(s=>!He(s)).flatMap(s=>(s.boxes||[]).map(a=>a.name))),r=0,o=!1;for(let s of e.tracks||[])if(He(s))for(let a of s.boxes)t.has(a.name)&&!n.has(a.name)&&(await zt(a.name).catch(()=>{}),s.transferredTo?console.log(`[track] reaped orphan box ${a.name} on transferred-away track ${s.id} (\u2192 ${s.transferredTo})`):Me(s,"orphan-reaped",{box:a.name,agent:a.agent}),r++,o=!0),!oo.has(a.state)&&a.state!=="stopped"&&(a.state="stopped",o=!0);return o&&await de(),r}function s8(){$u.clear()}async function Qh(e,{freshSession:t=!1,force:n=!1}={}){let r=await te(),o=he(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.archivedAt)throw new Error(`track "${e}" is archived \u2014 restore it before restarting the lead`);ic(o);let s=o.boxes.find(c=>c.name===o.leadBox);if(!s)throw new Error(`track "${e}" has no lead box`);if(oo.has(s.state))throw new Error("lead box is terminal \u2014 nothing to restart");if(await _e(o.leadBox)){let c=cn(o.leadBox,await Fe(o.leadBox,{lines:rt}).catch(()=>"")),l=Sl(s.agent,c);if(l&&!n){let u=$u.get(e),d=Date.now(),p=u&&d-u.at<o8?u.count+1:1;$u.set(e,{count:p,at:d});let w=new Error(p>=2?"lead is mid-turn \u2014 retry when it goes idle, or restart anyway if the screen is stuck":"lead is mid-turn \u2014 retry when it goes idle");throw w.code="lead-mid-turn",w.refusals=p,w.forceAvailable=p>=2,w}$u.delete(e),n&&(ka(e,"restart"),await ne({flow:"restart",phase:"forced",trackId:e,sessionName:o.leadBox,agent:s.agent,busy:l,paneTail:!0}).catch(()=>{})),await zt(o.leadBox),s.state="stopped"}else $u.delete(e);let i=await oc(o,t?{freshSession:!0,reason:"loop-fire"}:{});if(await de(),!i)throw new Error("rehydrate failed \u2014 see the track's rehydrate-failed event");return pn(o)}async function a8(e,t,{escSends:n=0,kept:r=0}={}){if(!e||!t)return null;let o=Hu();return await D(e,{type:"box.stuck.detected",actor:"system",source:"orchestrator",boxId:t.name,provider:t.agent,payload:{ts:Date.now(),offerId:o,box:t.name,agent:t.agent,escSends:n,kept:r}}),o}async function O0(e,t,n,{force:r=!1}={}){let o=await ye(e);if(!o)throw new Error(`track "${e}" not found`);if(!t)throw new Error("unknown offer");let s=await V(o).catch(()=>[]),a=s.find(d=>(d.type==="box.fullscreen.detected"||d.type==="box.stuck.detected")&&d.payload?.offerId===t);if(!a)throw new Error("unknown offer");let i=a.type==="box.stuck.detected",c=i?"box.stuck.answered":"box.fullscreen.answered";if(s.some(d=>d.type===c&&d.payload?.offerId===t))throw new Error("offer already answered");let u=n&&(i||r===!0);return n&&await Qh(e,{force:u}),await D(o,{type:c,actor:"user",source:"orchestrator",boxId:o.leadBox,payload:{ts:Date.now(),offerId:t,action:n?"restarted":"dismiss",...u?{forced:!0}:{}}}).catch(()=>{}),{ok:!0,action:n?"restarted":"dismiss",forced:u}}function Qi(e,t){if(!e)return null;let n=Us(t);return e.launchEcho=n,li(e.name,n),n}function M0(e,t,n){let r={name:e.name,agent:e.agent,role:t,state:n,cwd:e.cwd,sessionId:e.sessionId,pinned:e.pinned===!0,hookTokenHash:Ss(e.hookToken),createdAt:Date.now()};return Qi(r,e.launchCmd),r}function tN(e,t){if(!e?.id||!t?.box)return[];let n=(e.boxes||[]).find(r=>r.name===t.box);return nh({trackId:e.id,boxId:t.box,epoch:0,provider:n?.agent??t.agent??null})}function ns(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 Lh(e,t){let n=await te(),r=he(n,e);r&&(r.handoff={...r.handoff||{},...t},await de())}function _N(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 C0(){let e=await te(),t=!1;for(let n of e.tracks||[]){let r=n.handoff,o=_N(n);if(!o)continue;t=!0;let s=!!r.toBox&&r.toBox===r.fromBox;if(s&&o.step==="error"){let c=await _e(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=ns(l),p=d[d.length-1],w=p.agent,m=p.sessionId??null;p.endedAt=u,r.reason&&(p.endReason=r.reason);let h=c.agent==="claude"&&!!c.sessionId,g=await Ys({agent:r.toAgent});d.push({agent:r.toAgent,sessionId:c.sessionId||null,pinned:h,cliVersion:g,startedAt:u,endedAt:null}),l.agent=r.toAgent,l.cliVersion=g,l.sessionId=c.sessionId||null,l.pinned=h,l.state="live",n.pendingHandoffHydrate={artifact:rs,at:u},Me(n,"lead-handoff",{from:r.fromBox,to:r.fromBox,fromAgent:w,toAgent:r.toAgent,fromSessionId:m,toSessionId:c.sessionId||null,epoch:d.length-1,singleBox:!0,skipPermissions:r.skipPermissions,reason:r.reason??null,handoffStartedAt:r.startedAt,recovered:!0,standing:await Ki(l.cwd)}),n.handoff={...r,step:"done",finishedAt:u,recovered:"swap adopted from live tmux tags after restart"},await ne({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 ne({flow:"lead-handoff",phase:"reconciled",trackId:n.id,outcome:o.step,recovered:o.recovered,fromBox:o.fromBox,toBox:o.toBox}).catch(()=>{}),i&&await zt(i).catch(()=>{}),a&&await zt(a).catch(()=>{})}return t&&await de(),t}async function em(e,t,n=!0,r=null,{reviveArchived:o=!1}={}){let s=ya.get(e);if(s&&!s.finishedAt)throw new Error("a lead handoff is already running for this Track");let a=he(await te(),e);if(!a)throw new Error(`track "${e}" not found`);if(a.archivedAt&&!o)throw new Error(`track "${e}" is archived \u2014 restore it before handing off`);ic(a),ka(e,"handoff");let i=await tc(t,n),c=Uo(t);if(c){let w=new Error(`can't hand off to ${t} \u2014 its ${c.window} spend limit is reached ($${c.spentUsd.toFixed(2)} of $${c.limitUsd.toFixed(2)})`);throw w.usageCap=c,w}let l=iN(r),u=!1;a.archivedAt&&(await sc(e,{reason:l?.code==="context-refresh"?"context-refresh":"lead-handoff"}),a=he(await te(),e),u=!0);let d=await _e(a.leadBox);if(!d)throw new Error(`lead box "${a.leadBox}" is not running`);let p={trackId:e,step:"checkpoint",fromBox:a.leadBox,toAgent:t,skipPermissions:n,reason:l,revived:u,toBox:a.leadBox,startedAt:Date.now(),finishedAt:null,error:null};return ya.set(e,p),await Lh(e,{step:p.step,fromBox:p.fromBox,toAgent:t,toBox:p.toBox,skipPermissions:n,startedAt:p.startedAt,finishedAt:null,error:null}),i8(p,a,d,i,t).catch(async w=>{p.error=w?.message||String(w),p.finishedAt=Date.now(),console.error(`[lead-handoff ${e}] FAILED at step "${p.step}": ${p.error}`),await Lh(e,{step:p.step,error:p.error,finishedAt:p.finishedAt}).catch(()=>{}),ne({flow:"lead-handoff",phase:"failed",trackId:e,step:p.step,error:p.error,fromBox:p.fromBox,toAgent:p.toAgent,toBox:p.toBox}).catch(()=>{})}),ne({flow:"lead-handoff",phase:"started",trackId:e,fromBox:p.fromBox,toAgent:t,cwd:d.cwd}).catch(()=>{}),p}async function i8(e,t,n,r,o){let s=async(P,L={})=>{e.step=P,console.log(`[lead-handoff ${e.trackId}] step \u2192 ${P}`),await Lh(e.trackId,{step:P,toBox:e.toBox}),await ne({flow:"lead-handoff",phase:P,trackId:e.trackId,fromBox:e.fromBox,toBox:e.toBox,toAgent:o,sessionName:L.sessionName,...L})};console.log(`[lead-handoff ${e.trackId}] ${e.fromBox}: ${n.agent} \u2192 ${o} IN PLACE`);let a=await te(),i=he(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,Uo(c))e.checkpoint="skipped-capped";else try{let P=await Qp(e.fromBox,{timeoutMs:e0,quiesce:{box:i?{...i,name:e.fromBox}:n,reason:e.reason?.code||"lead-handoff",onWait:async L=>{e.wait=L,await s("await-turn",{sessionName:e.fromBox,wait:L})},onResume:async()=>{e.wait=null,await s("checkpoint",{sessionName:e.fromBox})}}});e.quiescence=Wg(P),e.waitedMs=(P.quiescence?.pre?.waitedMs||0)+(P.quiescence?.post?.waitedMs||0)}catch(P){e.checkpoint="reconstructed",e.quiescence=Wg(P),e.waitedMs=P?.quiescence?.pre?.waitedMs||0,e.wait=null,await ne({flow:"lead-handoff",phase:"checkpoint-fallback",trackId:e.trackId,fromBox:e.fromBox,error:P?.message||String(P)}).catch(()=>{})}e.checkpoint!=="llm"&&(e.statusArtifact=await ef(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=Ys({agent:o,agentCmd:r}),w=await Zg(e.fromBox,{agentCmd:r,agent:o});li(e.fromBox,Us(w.launchCmd)),await s("hydrate",{sessionName:e.fromBox});let m=Us(w.launchCmd);await Mr({cwd:n.cwd,sessionId:w.sessionId,sessionName:e.fromBox,agent:o,agentCmd:ba(o),launchEcho:m}).catch(P=>{if(P?.code!=="cli-not-running")throw P});let h=kl(await Fe(e.fromBox,{lines:rt}).catch(()=>""),m);if(await ne({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=Uh(c,l,{skipPermissions:e.skipPermissions,cwd:n.cwd,peerName:e.fromBox}),L=await Zg(e.fromBox,{agentCmd:P,agent:c,resumeSessionId:l,pinned:u});li(e.fromBox,Us(L.launchCmd));let $=await te(),C=he($,e.trackId);if(C){let U=C.boxes.find(J=>J.name===e.fromBox);U&&(U.state="live",Qi(U,L.launchCmd)),Me(C,"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 de()}throw new Error(`incoming ${o} CLI never drew its composer \u2014 rolled back to ${c} (--resume, context intact)`)}await s("commit");let g=await te(),y=he(g,e.trackId);if(!y)throw new Error(`track "${e.trackId}" not found during handoff commit \u2014 was it deleted or archived mid-flight?`);let b=y.boxes.find(P=>P.name===e.fromBox);if(!b)throw new Error(`lead box row "${e.fromBox}" missing during handoff commit`);let x=Date.now(),v=ns(b),S=v[v.length-1];S.endedAt=x,e.reason&&(S.endReason=e.reason);let E=await p;v.push({agent:o,sessionId:w.sessionId,pinned:w.pinned,cliVersion:E,startedAt:x,endedAt:null}),b.agent=o,b.sessionId=w.sessionId,b.pinned=w.pinned,b.cliVersion=E,Qi(b,w.launchCmd),b.state="live",b.role="lead",y.pendingHandoffHydrate={artifact:e.statusArtifact||rs,at:x},Me(y,"lead-handoff",{from:e.fromBox,to:e.fromBox,fromAgent:c,toAgent:o,fromSessionId:l,toSessionId:w.sessionId,epoch:v.length-1,singleBox:!0,forced:w.forced||void 0,skipPermissions:e.skipPermissions,reason:e.reason,cliVersion:E,handoffStartedAt:e.startedAt,checkpoint:e.checkpoint,quiescence:e.quiescence||void 0,waitedMs:e.waitedMs||void 0,standing:await Ki(b.cwd)}),await de(),await s("done",{sessionName:e.fromBox}),await Lh(e.trackId,{finishedAt:Date.now(),error:null}),e.finishedAt=Date.now()}async function D0(e){let t=jh.get(e);if(t&&!t.finishedAt)throw new Error("a transfer is already running for this Track");let n=await te(),r=he(n,e);if(!r)throw new Error(`track "${e}" not found`);if(r.archivedAt)throw new Error("track is archived \u2014 restore it before moving it");if(r.kind==="setup")throw new Error("setup boxes don't move");if(r.transferredTo)throw new Error(`track already transferred to ${r.transferredTo}`);let o=ya.get(e);if(o&&!o.finishedAt)throw new Error("a lead handoff is running \u2014 retry when it settles");for(let a of Ut.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 jh.set(e,s),c8(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 c8(e,t){let n=t.boxes.find(u=>u.name===t.leadBox)||null,r=n?await _e(n.name).catch(()=>null):null;if(e.checkpoint="llm",!r||n&&Uo(n.agent))e.checkpoint=r?"skipped-capped":"skipped-dead";else try{await Qp(t.leadBox,{timeoutMs:e0,quiesce:{box:n,reason:"transfer-out",onWait:()=>{e.step="await-turn"},onResume:()=>{e.step="checkpoint"}}})}catch{e.checkpoint="reconstructed"}e.checkpoint!=="llm"&&await ef(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 Qt(t.workspace)){if(!u?.dir)continue;let d={name:u.name??null,repo:u.repo??null,baseSha:null,pushed:!1};try{await Kn(u.dir,["push","origin",o],N0);let{stdout:p}=await Kn(u.dir,["rev-parse","HEAD"]);d.baseSha=p.trim(),d.pushed=!0}catch(p){d.error=String(p?.message||p).split(`
|
|
359
359
|
`)[0]}s.push(d)}e.step="wip";let a=await Ak(t,{force:!0}),i=await te(),c=he(i,t.id),l=c?.boxes.find(u=>u.name===c.leadBox)||null;l&&ns(l),await de(),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 ic(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 tm(e,{toNode:t,mode:n="transfer"}={}){if(!t||typeof t!="string")throw new Error("toNode required");let r=await te(),o=he(r,e);if(!o)throw new Error(`track "${e}" not found`);if(o.transferredTo)return{ok:!0,alreadyTransferred:o.transferredTo};f0(e),await A0(e,o,n==="recover"?"track recovered onto another node":"track transferred to another node");let s=Date.now();Ef(o,{at:s,reason:n==="recover"?"node-offline":"node-transfer"});let a=await Tk(o,{ts:s}),i=a.pushed[0]??null;return o.transferredTo=t,o.transferredAt=s,Me(o,"transferred-out",{toNode:t,mode:n,box:o.leadBox,...i?{rescueRef:i.ref,rescueSha:i.sha}:{},...a.pushed.length?{rescues:a.pushed}:{}}),await de(),{ok:!0,toNode:t,rescue:i?{ref:i.ref,sha:i.sha}:null,rescues:a.pushed}}function B0(e,t){if(!e||e.transferredTo)return null;let n=(e.events||[]).filter(a=>a?.type==="transferred-in");if(!n.length)return null;let r=n[n.length-1],o=Number(r.at)||null,s=Number(t?.at)||null;return o!=null&&s!=null&&o>s?{since:o,fromNode:r.fromNode??null}:s==null&&r.fromNode&&r.fromNode===t?.toNode?{since:o,fromNode:r.fromNode}:null}async function L0(e){let t=[],n=await te();for(let r of Array.isArray(e)?e:[]){if(!r?.id)continue;let o=B0(he(n,r.id),r);o&&(console.error(`[transfer] plane's move record for ${r.id} (\u2192 ${r.toNode??"?"}${r.at?` at ${new Date(r.at).toISOString()}`:""}) predates this node's adoption${o.fromNode?` from ${o.fromNode}`:""} at ${new Date(o.since).toISOString()} \u2014 re-sending the move-commit`),t.push({id:r.id,stale:!0,since:o.since,toNode:r.toNode??null}))}return t}async function j0(e){let t=[];for(let n of Array.isArray(e)?e:[])if(!(!n?.id||!n?.toNode))try{let r=await te(),o=B0(he(r,n.id),n);if(o){console.error(`[transfer] IGNORING stale demote notice for ${n.id} (plane says it moved to ${n.toNode}${n.at?` at ${new Date(n.at).toISOString()}`:""}; this node adopted it${o.fromNode?` from ${o.fromNode}`:""} at ${new Date(o.since).toISOString()}) \u2014 keeping the live copy; re-sending the move-commit`),t.push({id:n.id,stale:!0,since:o.since,toNode:n.toNode});continue}let s=await tm(n.id,{toNode:n.toNode,mode:n.mode==="recover"?"recover":"transfer"});t.push({id:n.id,...s})}catch(r){/not found/i.test(String(r?.message))||console.error(`[transfer] demote of ${n.id} failed: ${r?.message||r}`)}return t}async function F0(e){let t=!await Z.lstat(Y.join(kw(e),".git")).catch(()=>null),n=await Iv(e);return t&&NI(n).catch(()=>{}),n}async function nN(e,t,n){try{await Ll(e,t,n)}catch{await Kn(e,["worktree","prune"]).catch(()=>{}),await Ll(e,t,n)}return t}function l8(e,{wip:t=null,wips:n=null}={}){let r=Qt(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 u8(e,t){try{await Kn(e,["fetch","origin",vk(t)],N0);let{stdout:n}=await Kn(e,["rev-parse","FETCH_HEAD^"]),{stdout:r}=await Kn(e,["rev-parse","HEAD"]),o=null,s=n.trim()===r.trim();return s||await Kn(e,["merge-base","--is-ancestor",r.trim(),n.trim()]).then(()=>!0,()=>!1)&&(await Kn(e,["reset","--hard",n.trim()]),o={from:r.trim(),to:n.trim()},s=!0),s?(await Kn(e,["read-tree","--reset","-u","FETCH_HEAD"]),await Kn(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(`
|
|
360
|
-
`)[0],advanced:null}}}function p8(e){if(typeof e!="string"||!d8.test(e)||e.includes("..")||e.includes("@{")||e.endsWith(".lock"))throw new Error("branch fails the safe-ref check")}async function U0(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&&p8(e.branch),Nh.has(t))throw new Error("an adopt is already running for this Track");Nh.set(t,{startedAt:Date.now()});try{return await f8({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{Nh.delete(t)}}async function f8({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:w=null,leadBox:m=null,reason:f=null,downSince:g=null,fallback:y=null}){let b=await tc(n,r),x=await te(),v=he(x,e);if(v&&!v.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);v&&(await Tk(v).catch(()=>{}),await AN(v),x.tracks.splice(x.tracks.indexOf(v),1),await de()),await Z.mkdir(Mu,{recursive:!0});let S=Y.join(Mu,e);await Z.rm(S,{recursive:!0,force:!0}).catch(()=>{});let E=null,P=!1,L=[];try{let $=[];if(i)for(let ie of Array.isArray(c)?c:[]){let Pe=typeof ie=="string"?ie:ie?.repo;if(!Pe||!/^[^/\s]+\/[^/\s]+$/.test(Pe))continue;let ve=await Ts(Pe)??await F0(Pe);await Kn(ve,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],N0),$.push({slug:Pe,base:ve,name:typeof ie=="object"?ie?.name??null:null})}if(i&&$.length===1){let{base:ie,slug:Pe}=$[0];await nN(ie,S,i),L.push({base:ie,dir:S}),await Bu(S,Zi(e,S));let ve=await ea(ie);E={dir:S,base:ie,branch:i,kind:"worktree",baseRef:ve,repo:Pe}}else if(i&&$.length>=2){await Z.mkdir(S,{recursive:!0});let ie=new Set([".bostrat"]),Pe=[];for(let ve of $){let ee=ve.name||Y.basename(ve.base);ie.has(ee)&&(ee=ve.slug.replace("/","-"));for(let ze=2;ie.has(ee);ze++)ee=`${Y.basename(ve.base)}-${ze}`;ie.add(ee);let ge=Y.join(S,ee);await nN(ve.base,ge,i),L.push({base:ve.base,dir:ge});let Ve=await ea(ve.base);Pe.push({name:ee,dir:ge,base:ve.base,baseRef:Ve,repo:ve.slug})}await rc(S,Pe,i,{deps:Zi(e,S)}),E={dir:S,kind:"multi",branch:i,repos:Pe}}else P=!0,await Z.mkdir(S,{recursive:!0}),await Ty(S),await Bu(S,Zi(e,S)),E={dir:S,base:null,branch:null,kind:"repo"};let C=[];for(let ie of l8(E,{wip:l,wips:u})){let Pe=await u8(ie.dir,e);C.push({name:ie.name,repo:ie.repo,applied:Pe.applied,skipped:Pe.skipped,...Pe.advanced?{advanced:Pe.advanced}:{}})}let U=C.some(ie=>ie.applied),J=C.length===1?C[0].skipped:C.filter(ie=>ie.skipped).map(ie=>`${ie.name??ie.repo}: ${ie.skipped}`).join("; ")||null,_=C.length===1?C[0].advanced??null:null;await DC({id:e,cwd:S}).catch(()=>({restored:!1}));let I=Y.join(S,rs),T=null;(await ap(S)).restored?T="checkpoint":typeof d=="string"&&d.trim()&&(await Z.mkdir(Y.dirname(I),{recursive:!0}),await Z.writeFile(I,d),T="brief");let W=new Set(x.tracks.flatMap(ie=>(ie.boxes||[]).map(Pe=>Pe.name))),ce=null;m&&!W.has(m)&&!await _e(m).catch(()=>null)?ce=m:(ce=`${cr(t).slice(0,50)} lead`,W.has(hp(ce))&&(ce=`${cr(t).slice(0,50)} ${e} lead`));let z=await or(ce,S,{agentCmd:b,agent:n,trackId:e});Hs({cwd:z.cwd,sessionName:z.name,agent:n,agentCmd:b});let Ke=Date.now(),Ie=M0(z,"lead","live"),X=(Array.isArray(p)?p:[]).filter(ie=>ie&&typeof ie=="object").map(ie=>({...ie})),re=X[X.length-1];re&&re.endedAt==null&&(re.endedAt=Ke,re.endReason==null&&(re.endReason=o==="recover"?"node-offline":"node-transfer"));let Te=await Ys({agent:n,agentCmd:b});X.push({agent:n,sessionId:z.sessionId??null,pinned:z.pinned===!0,cliVersion:Te,startedAt:Ke,endedAt:null}),Ie.epochs=X,Ie.cliVersion=Te;let Le={id:e,name:t.trim(),cwd:z.cwd,workspace:E,leadBox:z.name,boxes:[Ie],events:[],createdAt:Number.isFinite(w)?w:Ke,...T?{pendingHandoffHydrate:{artifact:rs,at:Ke}}:{}};return Me(Le,"transferred-in",{box:z.name,agent:n,fromNode:s,toNode:a,mode:o,reason:f,...o==="recover"?{downSince:Number.isFinite(g)?g:null}:{},...y&&typeof y=="object"?{fallback:{from:String(y.from??"transfer"),step:y.step??null,error:typeof y.error=="string"?y.error.slice(0,300):null,at:Number.isFinite(y.at)?y.at:null}}:{},branch:E.branch??null,wip:U,..._?{wipAdvanced:_}:{},...E.kind==="multi"&&C.length?{wipRepos:C}:{},epoch:X.length-1,name:Le.name,cwd:Le.cwd,workspace:{base:E.base??null,branch:E.branch??null,kind:E.kind,...E.baseRef?{baseRef:E.baseRef}:{},...E.repo?{repo:E.repo}:{},...E.repos?{repos:E.repos.map(({name:ie,base:Pe,baseRef:ve,repo:ee})=>({name:ie,base:Pe,baseRef:ve,repo:ee}))}:{}}}),x.tracks.push(Le),await de(),Ly(E.dir).catch(()=>{}),{...await pn(Le),adopt:{wipApplied:U,wipSkipped:J,..._?{wipAdvanced:_}:{},...E.kind==="multi"?{wipRepos:C}:{},codeless:P,artifactSource:T}}}catch($){for(let C of L)await Lt(C.base,C.dir).catch(()=>{});throw await Z.rm(S,{recursive:!0,force:!0}).catch(()=>{}),$}}async function IN(e,t,n){let r=await te(),o=he(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await de())}async function zi(e,t){e.step=t,await Ku(e)}function $N(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 RN(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function g8(e,t,n){if(!RN(n)||Ut.has(t)||!await _e(n.box).catch(()=>null))return!1;try{await Z.access(n.dir)}catch{return!1}let o=await _e(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return Ut.set(t,s),MN(s,o).catch(a=>ON(s,a)),!0}async function H0(){let e=await te(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Ut.has(r))continue;if(await g8(n,r,o)){t=!0,Me(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await ne({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=$N(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!oo.has(i.state)&&(i.state="canceled"),Me(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 ne({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await rN(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||oo.has(r.state)||Ut.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?Y.join(ec,`${n.id}-${r.subtaskId}`):null;await ne({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await rN(n,r.name,o)}}return t=await y8(e)||t,t&&await de(),t}async function rN(e,t,n){if(t&&await zt(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of Qt(e.workspace)){let s=Y.join(n,o.name);await Lt(o.base,s).then(()=>!0,()=>!1)||await Lt(o.dir,s).catch(()=>{})}await Z.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await _e(e.leadBox).catch(()=>null);r?.cwd&&await Lt(r.cwd,n).catch(()=>{})}async function y8(e){let t;try{t=await Z.readdir(ec)}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 Ut.values())o.dir&&n.add(Y.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=Y.join(ec,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of Qt(a.workspace))await Lt(i.base,Y.join(s,i.name)).catch(()=>{});await Z.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await _e(a.leadBox).catch(()=>null):null;i?.cwd?await Lt(i.cwd,s).catch(()=>{}):await Z.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await ne({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function W0(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!Fo(n))throw new Error("task (string) required");let s=await tc(t,r),a=Uo(t);if(a){let w=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 w.usageCap=a,w}let i=he(await te(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await _e(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 w=Qt(i.workspace);if(!w.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let m of w)if(!m?.dir||!await xi(m.dir))throw new Error(`tagged checkout "${m?.name??"?"}" is missing from the lead workspace (${m?.dir??"no dir"})`);u=w.map(m=>({name:m.name,leadDir:m.dir,base:null}))}else if(!await xi(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=Hu().slice(0,8),p={id:d,trackId:e,trackName:i.name,agent:t,task:Fo(n),skipPermissions:r,reason:iN(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${cr(i.name)}-${d}`,base:null,repos:u,dir:Y.join(ec,`${e}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Ut.set(d,p),await Ku(p),b8(p,c,s).catch(w=>ON(p,w)),p}async function ON(e,t){e.failedStep=e.step,e.error=t instanceof Uu?"canceled":t?.message||String(t),e.step=t instanceof Uu?"canceled":"error",e.finishedAt=Date.now(),await G0(e).catch(()=>{}),await Ku(e).catch(()=>{}),await v8(e).catch(()=>{})}function rm(e){let t=Ut.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 q0(e){let t=Ut.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 b8(e,t,n){if(await zi(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await Si(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await Ku(e)}else e.base=await Si(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await zi(e,"spawn"),await Z.mkdir(ec,{recursive:!0}),e.repos){await Z.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await Qs(a.leadDir,Y.join(e.dir,a.name),e.branch,a.base);let s=Qt((he(await te(),e.trackId)||{}).workspace);await rc(e.dir,e.repos.map(a=>{let i=s.find(c=>c?.name===a.name);return{name:a.name,repo:i?.repo??null,baseRef:null}}),e.branch,{deps:{track:{id:e.trackId,cwd:t.cwd}}})}else await Qs(t.cwd,e.dir,e.branch,e.base),await Bu(e.dir,{track:{id:e.trackId,cwd:t.cwd}});await k8(e,t);let r=cr(e.trackName).slice(0,38),o=await or(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await x8(e,o),await cN(e.trackId,o.name,Qz(e.task,!!e.repos),{kind:"subtask"}),await MN(e,t)}async function MN(e,t){await zi(e,"working");let n=Y.join(e.dir,Ph);if(await T8(n,e),e.canceled)throw new Uu;if(await zi(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=Y.join(e.dir,l.name);await vy(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:tN({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await $y(l.leadDir,l.base,e.branch,Vi),l.files=await Ry(l.leadDir,l.base,e.branch,Vi);let d=await Oy(l.leadDir,l.base,e.branch,Vi);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=>Y.join(l.name,p))),i.push(...l.conflicts.map(p=>p.startsWith("patch did not apply cleanly")?`${l.name}: ${p}`:Y.join(l.name,p))),d.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await vy(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:tN({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await $y(t.cwd,e.base,e.branch,Vi),e.files=await Ry(t.cwd,e.base,e.branch,Vi);let s=await Oy(t.cwd,e.base,e.branch,Vi);e.applied=s.applied,e.conflicts=s.conflicts}await Ku(e);let r=await A8(e,t,n);await zi(e,"resume"),await cN(e.trackId,e.leadBox,e3(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume",detail:{subtaskId:e.id,from:e.box,fromAgent:e.agent,task:e.task,stat:e.stat,conflicts:e.conflicts,resultRel:r}}),await zi(e,"reap"),await G0(e),e.step="done";let o=Date.now();await IN(e.trackId,e.id,{...nm(e),finishedAt:o}),await S8(e,o),e.finishedAt=o}async function k8(e,t){let n=Y.join(e.dir,Y.dirname(Cu));await Z.mkdir(n,{recursive:!0});let r="";try{r=await xT(t.cwd,t.sessionId)}catch{}if(!r)try{r=await Z.readFile(Y.join(t.cwd,".bostrat/handoff/latest.md"),"utf8")}catch{r="_(no prior conversation digest available \u2014 rely on the working tree.)_"}let o=`# Lead context for subtask ${e.id}
|
|
360
|
+
`)[0],advanced:null}}}function p8(e){if(typeof e!="string"||!d8.test(e)||e.includes("..")||e.includes("@{")||e.endsWith(".lock"))throw new Error("branch fails the safe-ref check")}async function U0(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&&p8(e.branch),Nh.has(t))throw new Error("an adopt is already running for this Track");Nh.set(t,{startedAt:Date.now()});try{return await f8({...e,trackId:t,name:n,agent:r,skipPermissions:o,mode:s})}finally{Nh.delete(t)}}async function f8({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:w=null,leadBox:m=null,reason:h=null,downSince:g=null,fallback:y=null}){let b=await tc(n,r),x=await te(),v=he(x,e);if(v&&!v.transferredTo)throw new Error(`track "${e}" is already hosted on this node`);v&&(await Tk(v).catch(()=>{}),await AN(v),x.tracks.splice(x.tracks.indexOf(v),1),await de()),await Z.mkdir(Mu,{recursive:!0});let S=Y.join(Mu,e);await Z.rm(S,{recursive:!0,force:!0}).catch(()=>{});let E=null,P=!1,L=[];try{let $=[];if(i)for(let ie of Array.isArray(c)?c:[]){let Pe=typeof ie=="string"?ie:ie?.repo;if(!Pe||!/^[^/\s]+\/[^/\s]+$/.test(Pe))continue;let ve=await Ts(Pe)??await F0(Pe);await Kn(ve,["fetch","origin",`+refs/heads/${i}:refs/heads/${i}`],N0),$.push({slug:Pe,base:ve,name:typeof ie=="object"?ie?.name??null:null})}if(i&&$.length===1){let{base:ie,slug:Pe}=$[0];await nN(ie,S,i),L.push({base:ie,dir:S}),await Bu(S,Zi(e,S));let ve=await ea(ie);E={dir:S,base:ie,branch:i,kind:"worktree",baseRef:ve,repo:Pe}}else if(i&&$.length>=2){await Z.mkdir(S,{recursive:!0});let ie=new Set([".bostrat"]),Pe=[];for(let ve of $){let ee=ve.name||Y.basename(ve.base);ie.has(ee)&&(ee=ve.slug.replace("/","-"));for(let ze=2;ie.has(ee);ze++)ee=`${Y.basename(ve.base)}-${ze}`;ie.add(ee);let ge=Y.join(S,ee);await nN(ve.base,ge,i),L.push({base:ve.base,dir:ge});let Ve=await ea(ve.base);Pe.push({name:ee,dir:ge,base:ve.base,baseRef:Ve,repo:ve.slug})}await rc(S,Pe,i,{deps:Zi(e,S)}),E={dir:S,kind:"multi",branch:i,repos:Pe}}else P=!0,await Z.mkdir(S,{recursive:!0}),await Ty(S),await Bu(S,Zi(e,S)),E={dir:S,base:null,branch:null,kind:"repo"};let C=[];for(let ie of l8(E,{wip:l,wips:u})){let Pe=await u8(ie.dir,e);C.push({name:ie.name,repo:ie.repo,applied:Pe.applied,skipped:Pe.skipped,...Pe.advanced?{advanced:Pe.advanced}:{}})}let U=C.some(ie=>ie.applied),J=C.length===1?C[0].skipped:C.filter(ie=>ie.skipped).map(ie=>`${ie.name??ie.repo}: ${ie.skipped}`).join("; ")||null,_=C.length===1?C[0].advanced??null:null;await DC({id:e,cwd:S}).catch(()=>({restored:!1}));let I=Y.join(S,rs),T=null;(await ap(S)).restored?T="checkpoint":typeof d=="string"&&d.trim()&&(await Z.mkdir(Y.dirname(I),{recursive:!0}),await Z.writeFile(I,d),T="brief");let W=new Set(x.tracks.flatMap(ie=>(ie.boxes||[]).map(Pe=>Pe.name))),ce=null;m&&!W.has(m)&&!await _e(m).catch(()=>null)?ce=m:(ce=`${cr(t).slice(0,50)} lead`,W.has(hp(ce))&&(ce=`${cr(t).slice(0,50)} ${e} lead`));let z=await or(ce,S,{agentCmd:b,agent:n,trackId:e});Hs({cwd:z.cwd,sessionName:z.name,agent:n,agentCmd:b});let Ke=Date.now(),Ie=M0(z,"lead","live"),X=(Array.isArray(p)?p:[]).filter(ie=>ie&&typeof ie=="object").map(ie=>({...ie})),re=X[X.length-1];re&&re.endedAt==null&&(re.endedAt=Ke,re.endReason==null&&(re.endReason=o==="recover"?"node-offline":"node-transfer"));let Te=await Ys({agent:n,agentCmd:b});X.push({agent:n,sessionId:z.sessionId??null,pinned:z.pinned===!0,cliVersion:Te,startedAt:Ke,endedAt:null}),Ie.epochs=X,Ie.cliVersion=Te;let Le={id:e,name:t.trim(),cwd:z.cwd,workspace:E,leadBox:z.name,boxes:[Ie],events:[],createdAt:Number.isFinite(w)?w:Ke,...T?{pendingHandoffHydrate:{artifact:rs,at:Ke}}:{}};return Me(Le,"transferred-in",{box:z.name,agent:n,fromNode:s,toNode:a,mode:o,reason:h,...o==="recover"?{downSince:Number.isFinite(g)?g:null}:{},...y&&typeof y=="object"?{fallback:{from:String(y.from??"transfer"),step:y.step??null,error:typeof y.error=="string"?y.error.slice(0,300):null,at:Number.isFinite(y.at)?y.at:null}}:{},branch:E.branch??null,wip:U,..._?{wipAdvanced:_}:{},...E.kind==="multi"&&C.length?{wipRepos:C}:{},epoch:X.length-1,name:Le.name,cwd:Le.cwd,workspace:{base:E.base??null,branch:E.branch??null,kind:E.kind,...E.baseRef?{baseRef:E.baseRef}:{},...E.repo?{repo:E.repo}:{},...E.repos?{repos:E.repos.map(({name:ie,base:Pe,baseRef:ve,repo:ee})=>({name:ie,base:Pe,baseRef:ve,repo:ee}))}:{}}}),x.tracks.push(Le),await de(),Ly(E.dir).catch(()=>{}),{...await pn(Le),adopt:{wipApplied:U,wipSkipped:J,..._?{wipAdvanced:_}:{},...E.kind==="multi"?{wipRepos:C}:{},codeless:P,artifactSource:T}}}catch($){for(let C of L)await Lt(C.base,C.dir).catch(()=>{});throw await Z.rm(S,{recursive:!0,force:!0}).catch(()=>{}),$}}async function IN(e,t,n){let r=await te(),o=he(r,e);o&&(o.subtasks=o.subtasks||{},o.subtasks[t]={...o.subtasks[t]||{},...n},await de())}async function zi(e,t){e.step=t,await Ku(e)}function $N(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 RN(e){return!!e&&!e.finishedAt&&!e.canceled&&e.step==="working"&&!!e.box&&!!e.dir&&!!e.base&&!!e.branch}async function g8(e,t,n){if(!RN(n)||Ut.has(t)||!await _e(n.box).catch(()=>null))return!1;try{await Z.access(n.dir)}catch{return!1}let o=await _e(e.leadBox).catch(()=>null);if(!o?.cwd)return!1;let s={...n,id:t,leadBox:e.leadBox,step:"working",canceled:!1,forceMerge:!1};return Ut.set(t,s),MN(s,o).catch(a=>ON(s,a)),!0}async function H0(){let e=await te(),t=!1;for(let n of e.tracks||[]){for(let[r,o]of Object.entries(n.subtasks||{})){if(Ut.has(r))continue;if(await g8(n,r,o)){t=!0,Me(n,"subtask-resumed",{box:o.box,agent:o.agent,task:o.task,subtaskId:r,resumedStep:o.step}),await ne({flow:"subtask",phase:"resumed",trackId:n.id,subtaskId:r,box:o.box,branch:o.branch}).catch(()=>{});continue}let s=o.step,a=$N(o);if(!a)continue;t=!0,n.subtasks[r]=a;let i=n.boxes.find(c=>c.subtaskId===r);i&&!oo.has(i.state)&&(i.state="canceled"),Me(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 ne({flow:"subtask",phase:"reconciled",trackId:n.id,subtaskId:r,outcome:a.step,recovered:a.recovered,box:o.box,branch:o.branch}).catch(()=>{}),await rN(n,o.box,o.dir)}for(let r of n.boxes){if(r.role!=="subtask"||oo.has(r.state)||Ut.has(r.subtaskId)||n.subtasks?.[r.subtaskId])continue;t=!0,r.state="canceled";let o=r.subtaskId?Y.join(ec,`${n.id}-${r.subtaskId}`):null;await ne({flow:"subtask",phase:"reaped-legacy-orphan",trackId:n.id,subtaskId:r.subtaskId,box:r.name}).catch(()=>{}),await rN(n,r.name,o)}}return t=await y8(e)||t,t&&await de(),t}async function rN(e,t,n){if(t&&await zt(t).catch(()=>{}),!n)return;if(e.workspace?.kind==="multi"){for(let o of Qt(e.workspace)){let s=Y.join(n,o.name);await Lt(o.base,s).then(()=>!0,()=>!1)||await Lt(o.dir,s).catch(()=>{})}await Z.rm(n,{recursive:!0,force:!0}).catch(()=>{});return}let r=await _e(e.leadBox).catch(()=>null);r?.cwd&&await Lt(r.cwd,n).catch(()=>{})}async function y8(e){let t;try{t=await Z.readdir(ec)}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 Ut.values())o.dir&&n.add(Y.basename(o.dir));let r=!1;for(let o of t){if(n.has(o))continue;let s=Y.join(ec,o),a=(e.tracks||[]).find(i=>o.startsWith(`${i.id}-`));if(a?.workspace?.kind==="multi"){for(let i of Qt(a.workspace))await Lt(i.base,Y.join(s,i.name)).catch(()=>{});await Z.rm(s,{recursive:!0,force:!0}).catch(()=>{})}else{let i=a?await _e(a.leadBox).catch(()=>null):null;i?.cwd?await Lt(i.cwd,s).catch(()=>{}):await Z.rm(s,{recursive:!0,force:!0}).catch(()=>{})}await ne({flow:"subtask",phase:"swept-orphan-worktree",dir:s}).catch(()=>{}),r=!0}return r}async function W0(e,{agent:t,task:n,skipPermissions:r=!0,reason:o=null}={}){if(typeof n!="string"||!Fo(n))throw new Error("task (string) required");let s=await tc(t,r),a=Uo(t);if(a){let w=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 w.usageCap=a,w}let i=he(await te(),e);if(!i)throw new Error(`track "${e}" not found`);let c=await _e(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 w=Qt(i.workspace);if(!w.length)throw new Error("this multi-repo Track has no tagged repos to delegate into");for(let m of w)if(!m?.dir||!await xi(m.dir))throw new Error(`tagged checkout "${m?.name??"?"}" is missing from the lead workspace (${m?.dir??"no dir"})`);u=w.map(m=>({name:m.name,leadDir:m.dir,base:null}))}else if(!await xi(c.cwd))throw new Error(`subtask delegation needs the lead's workspace to be a git repo (got ${c.cwd})`);let d=Hu().slice(0,8),p={id:d,trackId:e,trackName:i.name,agent:t,task:Fo(n),skipPermissions:r,reason:iN(o),step:"snapshot",leadBox:i.leadBox,box:null,branch:`bostrat/${cr(i.name)}-${d}`,base:null,repos:u,dir:Y.join(ec,`${e}-${d}`),stat:null,conflicts:[],applied:null,startedAt:Date.now(),finishedAt:null,error:null,canceled:!1,forceMerge:!1};return Ut.set(d,p),await Ku(p),b8(p,c,s).catch(w=>ON(p,w)),p}async function ON(e,t){e.failedStep=e.step,e.error=t instanceof Uu?"canceled":t?.message||String(t),e.step=t instanceof Uu?"canceled":"error",e.finishedAt=Date.now(),await G0(e).catch(()=>{}),await Ku(e).catch(()=>{}),await v8(e).catch(()=>{})}function rm(e){let t=Ut.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 q0(e){let t=Ut.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 b8(e,t,n){if(await zi(e,"snapshot"),e.repos){for(let s of e.repos)s.base=await Si(s.leadDir,`bostrat: snapshot for subtask ${e.id}`);await Ku(e)}else e.base=await Si(t.cwd,`bostrat: snapshot for subtask ${e.id}`);if(await zi(e,"spawn"),await Z.mkdir(ec,{recursive:!0}),e.repos){await Z.mkdir(e.dir,{recursive:!0});for(let a of e.repos)await Qs(a.leadDir,Y.join(e.dir,a.name),e.branch,a.base);let s=Qt((he(await te(),e.trackId)||{}).workspace);await rc(e.dir,e.repos.map(a=>{let i=s.find(c=>c?.name===a.name);return{name:a.name,repo:i?.repo??null,baseRef:null}}),e.branch,{deps:{track:{id:e.trackId,cwd:t.cwd}}})}else await Qs(t.cwd,e.dir,e.branch,e.base),await Bu(e.dir,{track:{id:e.trackId,cwd:t.cwd}});await k8(e,t);let r=cr(e.trackName).slice(0,38),o=await or(`${r} ${e.agent} sub ${e.id}`,e.dir,{agentCmd:n,agent:e.agent});e.box=o.name,await x8(e,o),await cN(e.trackId,o.name,Qz(e.task,!!e.repos),{kind:"subtask"}),await MN(e,t)}async function MN(e,t){await zi(e,"working");let n=Y.join(e.dir,Ph);if(await T8(n,e),e.canceled)throw new Uu;if(await zi(e,"merge"),e.repos){let s={files:0,insertions:0,deletions:0},a=[],i=[],c=!0;for(let l of e.repos){let u=Y.join(e.dir,l.name);await vy(u,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:tN({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),l.stat=await $y(l.leadDir,l.base,e.branch,Vi),l.files=await Ry(l.leadDir,l.base,e.branch,Vi);let d=await Oy(l.leadDir,l.base,e.branch,Vi);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=>Y.join(l.name,p))),i.push(...l.conflicts.map(p=>p.startsWith("patch did not apply cleanly")?`${l.name}: ${p}`:Y.join(l.name,p))),d.applied||(c=!1)}e.stat=s,e.files=a,e.conflicts=i,e.applied=c}else{await vy(e.dir,`bostrat: subtask ${e.id} result (auto-committed)`,{trailers:tN({id:e.trackId,boxes:[{name:e.box,agent:e.agent}]},e)}),e.stat=await $y(t.cwd,e.base,e.branch,Vi),e.files=await Ry(t.cwd,e.base,e.branch,Vi);let s=await Oy(t.cwd,e.base,e.branch,Vi);e.applied=s.applied,e.conflicts=s.conflicts}await Ku(e);let r=await A8(e,t,n);await zi(e,"resume"),await cN(e.trackId,e.leadBox,e3(e.task,e.stat,e.conflicts,r),{kind:"subtask-resume",detail:{subtaskId:e.id,from:e.box,fromAgent:e.agent,task:e.task,stat:e.stat,conflicts:e.conflicts,resultRel:r}}),await zi(e,"reap"),await G0(e),e.step="done";let o=Date.now();await IN(e.trackId,e.id,{...nm(e),finishedAt:o}),await S8(e,o),e.finishedAt=o}async function k8(e,t){let n=Y.join(e.dir,Y.dirname(Cu));await Z.mkdir(n,{recursive:!0});let r="";try{r=await xT(t.cwd,t.sessionId)}catch{}if(!r)try{r=await Z.readFile(Y.join(t.cwd,".bostrat/handoff/latest.md"),"utf8")}catch{r="_(no prior conversation digest available \u2014 rely on the working tree.)_"}let o=`# Lead context for subtask ${e.id}
|
|
361
361
|
|
|
362
362
|
**Delegated task:** ${e.task}
|
|
363
363
|
|
|
@@ -833,8 +833,8 @@ mid-message, above a closing statement, reads settled and goes unanswered.
|
|
|
833
833
|
SCOPE: these instructions apply ONLY when your working directory is under
|
|
834
834
|
~/.bostrat/workspaces/ or ~/.bostrat/worktrees/ \u2014 a bostrat-orchestrated box.
|
|
835
835
|
When working anywhere else, ignore everything below.
|
|
836
|
-
`);X3=new Set(["claude","codex","cursor"]);Lu=new Set,Z3=e=>Lu.has(e);Q3=9e4;eN={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};qk=new Map;n8=6e4,Gk=new Map;Fu=120;o8=10*6e4,$u=new Map;ya=new Map,ac=e=>ya.get(e)||(Zt?he(Zt,e)?.handoff:null)||null;N0=6e4,Kn=(e,t,n=15e3)=>Zk("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),jh=new Map,P0=e=>jh.get(e)||null;d8=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,200}$/;Nh=new Map;h8=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,m8=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,ec=Y.join(xr,"worktrees"),Vi=[Cu,Ph],Ut=new Map;_I({linkedRepos:async()=>((await $s()).repos??[]).map(e=>e.slug).filter(Boolean),workspaces:async()=>{let e=await te(),t=[];for(let n of e.tracks)n.archivedAt||n.transferredTo||!n.workspace?.dir||t.push(n.workspace.dir);for(let n of Ut.values())!n.finishedAt&&n.dir&&t.push(n.dir);return t}});w8=e=>Ut.get(e)||(Zt?Zt.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,va=e=>{let t=new Map([...Ut.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=Zt?he(Zt,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)},nm=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});Ku=e=>IN(e.trackId,e.id,nm(e));Uu=class extends Error{}});kt();import De from"node:path";import $t from"node:fs";import qZ from"node:readline";import{fileURLToPath as GZ}from"node:url";import en from"express";import BB from"node:http";import KZ from"node:https";import Ac from"node:os";import{randomUUID as VZ}from"node:crypto";import{WebSocketServer as zZ}from"ws";kt();import VF from"node-pty";async function LA(e,t,n={}){if(!qe(t)){gp(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await So()){gp(e,`host tmux server not running on ${St}`),e.close(1011,"tmux server unavailable");return}if(!await _e(t)){let a=!1;if(typeof n.revive=="function"&&(yp(e,{type:"notice",message:"Resuming the lead box\u2026"}),a=await n.revive().catch(()=>!1)),!a||!await _e(t)){gp(e,`session "${t}" not found`),e.close(1008,"session not found");return}if(e.readyState!==e.OPEN)return}let r=BA(n.cols,120,jA),o=BA(n.rows,32,FA),s;try{s=VF.spawn(oe,["-S",St,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){gp(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&yp(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(yp(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"&&XF(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{}YF(t)})}var zF=6,JF=250;async function YF(e,t=zF,n=JF){for(let r=0;r<t;r++){if(await Cs(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var jA=20,FA=6;function XF(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=jA&&Number(t)>=FA}function BA(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function yp(e,t){try{e.send(JSON.stringify(t))}catch{}}function gp(e,t){yp(e,{type:"error",message:t})}function UA(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}}Mn();Tp();Gg();Vr();import{createRequire as JZ}from"node:module";var E8=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function K0(e,{queuedOf:t=()=>[],jobsOf:n=()=>[],prPendingOf:r=()=>[]}={}){let o=[];return!e||e.archivedAt&&!e.archiving||e.transferredTo||(e.working&&o.push(`working:${e.id}`),e.prompted&&o.push(`prompted:${e.id}`),(t(e.id)??[]).length&&o.push(`queued:${e.id}`),(e.boxes||[]).some(s=>s?.role==="subtask"&&s?.state==="live")&&o.push(`subtask:${e.id}`),(n(e.id)??[]).length&&o.push(`job:${e.id}`),Object.values(e.subtasks||{}).some(E8)&&o.push(`merge-back:${e.id}`),(r(e.id)??[]).length&&o.push(`pr:${e.id}`)),o}function V0({tracks:e=[],views:t=[],queuedOf:n=()=>[],jobsOf:r=()=>[],prPendingOf:o=()=>[],deps:s=!1}={}){let a=[];for(let i of e)a.push(...K0(i,{queuedOf:n,jobsOf:r,prPendingOf:o}));return t.some(i=>i?.state==="live"||i?.state==="starting")&&a.push("views"),s&&a.push("deps"),{busy:a.length>0,reasons:a}}Nk();be();Fi();jn();ih();yn();var om=60*6e4,_8=1440*6e4,I8=new Set(["merged","closed","lost"]),Vu=(e,t,n)=>Number.isFinite(Number(e))&&n-Number(e)<=t;function $8({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)<=ok&&s.push("ship"),r>0&&s.push("create-net");for(let a of n||[]){if(!a||I8.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&&Vu(a.ciFix.delegatedAt,om,o)&&s.push(`ci-fix#${l}`),a.reconcile&&Vu(a.reconcile.delegatedAt,om,o)&&s.push(`reconcile#${l}`),a.ciFixAwait&&Vu(a.ciFixAwait.since,om,o)&&s.push(`ci-fix-await#${l}`),a.reconcileAwait&&Vu(a.reconcileAwait.since,om,o)&&s.push(`reconcile-await#${l}`);let u=a.autoMerge?.armedAt??a.armedAt??null;a.trackId===e&&(a.autoMerge||a.armedAt)&&Vu(u,_8,o)&&s.push(`auto-merge#${l}`)}return s}var sm=new Map;at.on("event",e=>{e?.trackId&&sm.delete(e.trackId)});async function R8(e){if(sm.has(e.id))return sm.get(e.id);let t=await V(e).catch(()=>[]),n=Zo(t,-1/0);return sm.set(e.id,n),n}async function NN(e,{now:t=Date.now()}={}){let n=new Map,r=await Ln().catch(()=>[]);for(let o of e||[]){if(!o||He(o))continue;let s=$8({trackId:o.id,shipPending:await R8(o),links:r,observers:aO(o.id),now:t});s.length&&n.set(o.id,s)}return n}su();import Xu from"node:fs";import is from"node:fs/promises";import X8 from"node:os";import Tt from"node:path";import{spawn as Z8,execFileSync as Q8}from"node:child_process";import{createRequire as eJ}from"node:module";be();Rf();import cc from"node:fs";import Ju from"node:fs/promises";import C8 from"node:http";import Wt from"node:path";import im from"node:os";import{createRequire as N8}from"node:module";import J0 from"ws";import O8 from"node:path";import M8 from"node:os";var zu=process.env.BOSTRAT_STATE_DIR||O8.join(process.env.HOME||M8.tmpdir(),".bostrat");function z0(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 PN(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=z0(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function DN(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}gw();var Vn=(()=>{try{return N8(import.meta.url)("../package.json").version||null}catch{return null}})(),Z0=process.env.BOSTRAT_STATE_DIR||Wt.join(process.env.HOME||im.tmpdir(),".bostrat"),WN=Wt.join(Z0,"plane-link","removed.json");function BN(e){return typeof e!="string"||e.length<8?"\u2022\u2022\u2022\u2022":`${e.slice(0,6)}\u2026${e.slice(-4)}`}function P8(e=WN){try{let t=JSON.parse(cc.readFileSync(e,"utf8"));return t&&typeof t=="object"?t:null}catch{return null}}function Aa({env:e=process.env,pkgDir:t=Wt.resolve(Wt.dirname(new URL(import.meta.url).pathname),".."),exists:n=cc.existsSync}={}){let r=String(e.BOSTRAT_INSTALL_KIND||"").trim();return["container","npm-global","git-checkout","dev"].includes(r)?r:/\/lib\/node_modules\/bostrat-node(?:\/|$)/.test(t.replace(/\\/g,"/"))?"npm-global":n(Wt.join(t,"..",".git"))?"git-checkout":"dev"}function Yu(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 am(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 D8({home:e=process.env.HOME||im.homedir(),env:t=process.env}={}){let n=r=>{try{return cc.statSync(r),!0}catch{return!1}};return{claude:n(Wt.join(e,".claude",".credentials.json")),codex:n(Wt.join(t.CODEX_HOME||Wt.join(e,".codex"),"auth.json")),cursor:n(Wt.join(t.XDG_CONFIG_HOME||Wt.join(e,".config"),"cursor","auth.json"))}}var At=1,LN=1e3,jN=3e4,B8=6e4,L8=1500,j8=500,as=100,F8=2e3,U8=25e3,H8=2.5,W8=6e4,qN=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},q8=qN(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),Y0="refused:",G8={forgedUserId:"this node's events carry a userId the plane's token does not own \u2014 remove BOSTRAT_OWNER from node.env and the shell environment, then restart the node (current releases never stamp one)",foreignTrack:"the Track belongs to another user's node \u2014 this node must not append to it",squattedTrack:"the Track id is already claimed by another user \u2014 a local Track collided with theirs",transferredAway:"the Track moved to another node \u2014 this copy is stale; it should be demoted, not resumed",slugHijack:"a View slug belongs to another owner \u2014 pick a different slug"},K8=e=>{if(!e||e.userId===void 0)return e;let{userId:t,...n}=e;return n},V8=3e4,FN=10*6e4,z8=400,UN=250,J8=qN(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),X0=4,Y8=6e4,HN=6e4;function GN({url:e,token:t,nodeId:n=im.hostname(),name:r=im.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,onTracksMoves:i=null,sampleMetrics:c=null,deliverySample:l=null,onHashKey:u=null,onViewBase:d=null,metricsMs:p=Y8,onUpdateAvailable:w=null,onUpdatePolicy:m=null,onHelloRefused:f=null,updatePolicy:g=null,installKind:y=Aa(),selfUrl:b=`http://127.0.0.1:${process.env.PORT||3362}`,apiToken:x=null,removedMarkerFile:v=WN,onRemoved:S=null,onDegraded:E=null,onRecovered:P=null,onRefused:L=null,onConnected:$=null,ingestMode:C=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:U=q8,unackedRetryMs:J=W8,pingMs:_=U8,deadLinkMs:I=Math.round(_*H8),maxInflightEvents:T=z8,httpTimeoutMs:F=J8,stallBackoffMinMs:W=V8,fetchImpl:ce=globalThis.fetch,log:z=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=DN(e);let Ke=b.replace(/^http/,"ws"),Ie=new Set,X=B=>{let H=typeof B.latestNodeVersion=="string"?B.latestNodeVersion:null;if(!(!(H&&Vn&&Yu(Vn,H))||Ie.has(H))){Ie.add(H),z.log(`[plane-link] bostrat-node ${H} is available (this node runs ${Vn}) \u2014 ${am(y)}`);try{w?.({current:Vn,latest:H,min:B.minNodeVersion??null,installKind:y,required:!!(B.minNodeVersion&&Yu(Vn,B.minNodeVersion))})}catch(j){z.error(`[plane-link] update notice failed: ${j?.message||j}`)}}},re=new Map,Te=new Map,Le=Wt.join(Z0,"plane-link","cursor.json"),ie=Wt.join(Z0,"plane-link","dead-letter.ndjson"),Pe=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),ve={},ee={},ge=new Map,Ve=null,ze=null,Ze=0,N=0,le=0,pe={},$e=new Set,Qe=Promise.resolve(),Je="ws",tn=0,yt=!1,nn=0,lo=!1,Et=as,Xn=new Set,rn=[],ct=null,Gt=null,nt=!1,ys=!1,bs=LN,uo=null,po=null,Zn=null,k=null,h=0,A=0,R=null,q=!1,fe=0,Se=!1,We=P8(v);if(We)if(We.tokenPreview===BN(t))Se=!0,ww({reason:We.reason??"removed",at:We.at??null,nodeId:We.nodeId??n}),z.error(`[plane-link] this node was REMOVED from the plane (${We.reason??"removed"}${We.at?` at ${new Date(We.at).toISOString()}`:""}) \u2014 not dialing. Re-provision it with a new node token, or delete ${v} to force a dial.`);else try{cc.unlinkSync(v),z.log("[plane-link] stale removed-marker discarded \u2014 the node token changed")}catch{}function ht({reason:B="removed",at:H=Date.now(),via:j="ctl"}={}){if(!Se){Se=!0,ww({reason:B,at:H,nodeId:n,via:j});try{cc.mkdirSync(Wt.dirname(v),{recursive:!0}),cc.writeFileSync(v,JSON.stringify({at:H,reason:B,via:j,nodeId:n,tokenPreview:BN(t)},null,2))}catch(M){z.error(`[plane-link] could not write ${v}: ${M?.message||M}`)}z.error(`[plane-link] the plane REMOVED this node (${B}, via ${j}) \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:B,at:H,via:j})}catch{}YS({bye:!1})}}async function Od(){try{ve=JSON.parse(await Ju.readFile(Le,"utf8"))}catch{ve={}}}function _r(){q=!0,!Zn&&(Zn=setTimeout(async()=>{if(Zn=null,!!q){q=!1;try{await Ju.mkdir(Wt.dirname(Le),{recursive:!0}),await Ju.writeFile(Le,JSON.stringify(ve))}catch(B){z.error("[plane-link] cursor flush failed:",B?.message||B)}}},F8),Zn.unref?.())}function bt(B){return!Gt||Gt.readyState!==J0.OPEN?!1:(Gt.send(JSON.stringify(B)),!0)}function Ic(B){let H=Date.now();for(let{trackId:M,event:G}of B){let ue=ge.get(G.id);ge.set(G.id,{trackId:M,seq:G.seq,event:G,sentAt:H,firstSentAt:ue?.firstSentAt??H,retryAt:H+J,tries:(ue?.tries??0)+1,nacks:ue?.nacks??0})}let j=B.map(({trackId:M,event:G})=>({trackId:M,event:K8(G)}));return Je==="http"?(tL(j),!0):bt({v:At,ch:"events",type:"append",events:j})}function YB(B){let H=null;for(let j of ge.values())j.trackId===B&&(H==null||j.seq<H)&&(H=j.seq);return H}function Ym(B){let H=ee[B];if(H==null)return;let j=YB(B),M=j==null?H:Math.min(H,j-1);M>(ve[B]??0)&&(ve[B]=M,_r())}function $c(){if(Ve=Date.now(),ze!=null){let B=Date.now()-ze;z.log(`[plane-link] spine sync recovered after ${Math.round(B/1e3)}s degraded (${Ze} stall redial(s))`);let H=ze;ze=null,Ze=0,N=0,yt=!1,nn=0;try{P?.({since:H,downMs:B})}catch(j){z.error(`[plane-link] onRecovered failed: ${j?.message||j}`)}}}function Xm(B){if(!Array.isArray(B)||!B.length)return;let H=new Set;for(let j of B){let M=ge.get(j);M&&(ge.delete(j),(ee[M.trackId]??0)<M.seq&&(ee[M.trackId]=M.seq),H.add(M.trackId))}for(let j of H)Ym(j);$c()}function US(B,H){le++;let j={at:Date.now(),trackId:B.trackId,seq:B.seq,id:B.event?.id??null,type:B.event?.type??null,reason:H,event:B.event??null};z.error(`[plane-link] DEAD-LETTER ${B.trackId} seq ${B.seq} (${j.type??"?"}): plane rejected it permanently (${H}) \u2014 kept in ${ie}`),Qe=Qe.then(async()=>{await Ju.mkdir(Wt.dirname(ie),{recursive:!0}),await Ju.appendFile(ie,JSON.stringify(j)+`
|
|
837
|
-
`)}).catch(M=>z.error(`[plane-link] dead-letter write failed: ${M?.message||M}`))}function XB(B,H){if(pe[B]=(pe[B]??0)+1,$e.has(B))return;$e.add(B);let j=G8[B]??"see the plane's tenancy alarm ring (GET /plane/tenancy/alarms)";z.error(`[plane-link] REFUSED by the plane (${B}) on track ${H}: events are being dropped, not stored \u2014 ${j}`);try{L?.({reason:B,trackId:H,count:pe[B],hint:j})}catch(M){z.error(`[plane-link] onRefused failed: ${M?.message||M}`)}}function Zm(B,H,j,M=null){if(!Array.isArray(B)||!B.length)return;let G=new Set,ue=Date.now();for(let Ee of B){let Ae=ge.get(Ee);Ae&&(j?(ge.delete(Ee),US(Ae,H),String(H).startsWith(Y0)&&XB(String(H).slice(Y0.length),Ae.trackId),(ee[Ae.trackId]??0)<Ae.seq&&(ee[Ae.trackId]=Ae.seq),G.add(Ae.trackId)):(Ae.nacks++,Ae.retryAt=ue+Math.max(1e3,Number(M)||J)))}for(let Ee of G)Ym(Ee);$c()}function HS(B=Date.now()){let H=1/0;for(let j of ge.values())j.firstSentAt<H&&(H=j.firstSentAt);return H===1/0?0:B-H}function ZB(B){if(!I||!B||B!==Gt||!h)return!1;let H=Date.now()-h;if(H<=I)return!1;A++,z.error(`[plane-link] no frame from the plane for ${Math.round(H/1e3)}s \u2014 link is half-open; terminating and redialing`);try{B.terminate()}catch{}return!0}function WS(){if(!nt||!ge.size)return;let B=Date.now(),H=HS(B);if(H<U||Ve!=null&&B-Ve<U||Je==="http"&&yt||N>B)return;Ze++;let j=Math.min(W*2**(Ze-1),FN);if(ze==null){ze=B-H,z.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(H/1e3)}s with ${ge.size} event(s) in flight (${Je} door) \u2014 the plane is not answering appends`);try{E?.({since:ze,unacked:ge.size,oldestAgeMs:H,mode:Je})}catch(M){z.error(`[plane-link] onDegraded failed: ${M?.message||M}`)}}if(Je==="http"){yt=!0,nn=B+j,z.error(`[plane-link] ingest circuit OPEN (stall #${Ze}); probing /v1/ingest/health in ${Math.round(j/1e3)}s`);return}N=B+j,z.error(`[plane-link] closing the link and redialing in ${Math.round(j/1e3)}s (stall redial #${Ze})`);try{Gt?.terminate()}catch{}}function Qm(){if(!nt)return;let B=Date.now();if(Je==="http"&&yt)return;let H=[...ge.values()].filter(M=>M.event&&M.retryAt<=B&&!(Je==="http"&&Xn.has(M.trackId)));if(!H.length)return;H.sort((M,G)=>M.trackId===G.trackId?M.seq-G.seq:M.trackId<G.trackId?-1:1),z.log(`[plane-link] re-sending ${H.length} unacked event(s) the plane never confirmed`);let j=Je==="http"?Et:as;if(Je==="http"){let M=new Map;for(let G of H)(M.get(G.trackId)??M.set(G.trackId,[]).get(G.trackId)).push(G);for(let[,G]of M){if(tn>=X0)return;Ic(G.slice(0,j).map(ue=>({trackId:ue.trackId,event:ue.event})))}return}for(let M=0;M<H.length;M+=j){let G=H.slice(M,M+j).map(ue=>({trackId:ue.trackId,event:ue.event}));if(!Ic(G))return}}async function QB(B=null){for(;;){if(!nt)return!1;let H=ge.size<T,j=Je!=="http"||tn<X0&&!yt&&(!B||!Xn.has(B));if(H&&j)return!0;await new Promise(M=>setTimeout(M,100))}}function ew(){if(ct=null,!nt||!rn.length)return;let B=rn;if(rn=[],Je!=="http"){for(let j=0;j<B.length;j+=as)Ic(B.slice(j,j+as));return}let H=new Map;for(let j of B)(H.get(j.trackId)??H.set(j.trackId,[]).get(j.trackId)).push(j);for(let[j,M]of H){if(Xn.has(j)||tn>=X0||yt){rn.push(...M);continue}for(let G=0;G<M.length;G+=Et)Ic(M.slice(G,G+Et))}rn.length&&!ct&&(ct=setTimeout(ew,UN),ct.unref?.())}let eL=B=>{let H=new Map;for(let{trackId:j,event:M}of B)(H.get(j)??H.set(j,[]).get(j)).push(M);return[...H].map(([j,M])=>({trackId:j,events:M}))},ks=(B,H,j,{progress:M})=>{let G=Date.now();for(let{event:ue}of B){let Ee=ge.get(ue.id);Ee&&(Ee.nacks++,Ee.retryAt=G+Math.max(1e3,j||J))}M&&$c()};async function tL(B){let H=new Set(B.map(j=>j.trackId));for(let j of H)Xn.add(j);tn++;try{let j=await ce(`${Pe}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:eL(B)}),signal:AbortSignal.timeout(F)}),M=(Number(j.headers.get("retry-after"))||0)*1e3;if(j.status===200){let G=await j.json();Et=as;for(let Ae of G.results??[]){Xm(Ae.acked??[]);let mt=(Qn,Kt)=>{let Md=new Map;for(let xs of Qn??[])(Md.get(xs.reason)??Md.set(xs.reason,[]).get(xs.reason)).push(xs.id);for(let[xs,XS]of Md)Zm(XS,xs,Kt,G.retryAfterMs??null)};mt(Ae.rejected,!0),mt(Ae.deferred,!1)}let ue=new Set,Ee=new Map;for(let Ae of Array.isArray(G.refused)?G.refused:[])!Ae||typeof Ae.id!="string"||(ue.add(Ae.id),(Ee.get(Ae.reason)??Ee.set(Ae.reason,[]).get(Ae.reason)).push(Ae.id));for(let[Ae,mt]of Ee)Zm(mt,`${Y0}${Ae}`,!0);Xm((G.discarded??[]).filter(Ae=>!ue.has(Ae))),$c();return}if(j.status===429){ks(B,"overloaded",M||5e3,{progress:!0});return}if(j.status===413&&B.length>1){Et=Math.max(1,Math.floor(B.length/2)),z.error(`[plane-link] ingest request too large (${B.length} events) \u2014 halving batches to ${Et}`),ks(B,"too_large",1e3,{progress:!0});return}if(j.status===413){let G=ge.get(B[0].event.id);G&&(ge.delete(G.event.id),US(G,"too_large"),(ee[G.trackId]??0)<G.seq&&(ee[G.trackId]=G.seq),Ym(G.trackId)),$c();return}if(j.status===410){ht({reason:"removed",via:"410"}),ks(B,"http_410",6e4,{progress:!1});return}if(j.status===401||j.status===403){let{tripped:G,holdMs:ue}=Fa();if(G&&z.error(`[plane-link] holding every plane call for ${Math.round(ue/6e4)} min \u2014 the ingest door refused this node's token three times in a row`),Date.now()-fe>=HN){fe=Date.now();let Ee="";try{Ee=(await j.json())?.error??""}catch{}z.error(`[plane-link] plane refused ingest (HTTP ${j.status}${Ee?`: ${Ee}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}ks(B,`http_${j.status}`,Math.max(6e4,jc()),{progress:!1});return}if(j.status===400){z.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${B.length} event(s) for retry; this is a bug, not data`),ks(B,"http_400",6e4,{progress:!1});return}ks(B,`http_${j.status}`,M||5e3,{progress:!1})}catch(j){let M=j?.name==="TimeoutError"||j?.name==="AbortError";M&&B.length>1&&(Et=Math.max(1,Math.floor(B.length/2)),z.error(`[plane-link] ingest request of ${B.length} event(s) outlived its ${F} ms deadline \u2014 halving batches to ${Et}`)),ks(B,M?"timeout":"network",5e3,{progress:!1})}finally{tn--;for(let j of H)Xn.delete(j)}}async function nL(){if(Je!=="http"||!yt||!nt||lo)return;let B=Date.now();if(!(nn>B||Ua(B))){lo=!0;try{let H=await ce(`${Pe}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(F)});if(!H.ok)throw new Error(`HTTP ${H.status}`);z.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),yt=!1,nn=0,N=Date.now()+F+J+1e3;for(let j of ge.values())j.retryAt=Math.min(j.retryAt,Date.now());Qm()}catch(H){Ze++;let j=Math.min(W*2**(Ze-1),FN);nn=Date.now()+j,z.error(`[plane-link] ingest door still not answering (${H?.message||H}); next probe in ${Math.round(j/1e3)}s`)}finally{lo=!1}}}function qS(){let B=Date.now();return{mode:Je,unacked:ge.size,oldestUnackedAgeMs:HS(B),lastProgressAt:Ve,degradedSince:ze,stallRedials:Ze,deadLettered:le,http:Je==="http"?{inFlight:tn,circuitOpen:yt,nextProbeInMs:yt?Math.max(0,nn-B):0,batchCap:Et}:null}}async function GS(){if(!c)return;let B;try{B=await c()}catch(j){z.error("[plane-link] metrics sample failed:",j?.message||j);return}let H=null;try{H=l?.()??null}catch{}B&&bt({v:At,ch:"ctl",type:"metrics",metrics:{...B,planeLink:qS(),...H?{delivery:H}:{}}})}function rL(){c&&(R&&clearInterval(R),GS(),R=setInterval(GS,p),R.unref?.())}async function oL(){let B;try{B=await o()}catch(H){z.error("[plane-link] backfill listTracks failed:",H?.message||H);return}bt({v:At,ch:"ctl",type:"tracks",ids:B.filter(H=>!H.transferredTo).map(H=>H.id).filter(H=>typeof H=="string")});for(let H of B)if(!nt||!await KS(H))return}async function KS(B){let H;try{H=await V(B)}catch{return!0}let j=ve[B.id]??0,M=H.filter(ue=>ue.seq>j&&typeof ue.id=="string"),G=Je==="http"?Et:as;for(let ue=0;ue<M.length;ue+=G){if(!await QB(B.id))return!1;let Ee=M.slice(ue,ue+Math.min(G,Je==="http"?Et:as)).map(Ae=>({trackId:B.id,event:Ae}));if(!Ic(Ee))return!1}return!0}let tw=new Map;async function VS(B,H){if(tw.get(B)===H)return!1;tw.set(B,H);let j=null;try{j=(await o()).find(Ee=>Ee?.id===B)??null}catch{return!1}if(!j)return!1;let M;try{M=await V(j)}catch{return!1}let G=[...M].reverse().find(Ee=>(Ee?.type==="track.transferred"||Ee?.type==="track.recovered")&&Ee.payload?.toNode===n);if(!G||!Number.isFinite(G.seq))return!1;let ue=G.seq-1;return(ve[B]??0)>ue&&(ve[B]=ue,_r()),(ee[B]??0)>ue&&(ee[B]=ue),z.log(`[plane-link] re-sending ${B}'s move-commit (seq ${G.seq}, ${G.type}) \u2014 the plane's move record predates this node's adoption`),nt?KS(j):!1}function zS(B){!nt||!B?.trackId||typeof B.id!="string"||(rn.push({trackId:B.trackId,event:B}),ct||(ct=setTimeout(ew,UN),ct.unref?.()))}let Rc=new Map;async function sL(B){let{reqId:H,method:j,path:M,headers:G={},body:ue}=B,Ee=Object.fromEntries(Object.entries(G).filter(([,mt])=>mt!=null)),Ae=new AbortController;Rc.set(H,Ae);try{if(B.host){await aL(B,Ee,Ae);return}x&&(Ee["x-bostrat-token"]=x);let mt=await fetch(b+M,{method:j,headers:Ee,body:ue?Buffer.from(ue,"base64"):void 0,signal:Ae.signal}),Qn=Object.fromEntries(mt.headers);for(let Kt of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete Qn[Kt];if(Qn["content-type"]||(Qn["content-type"]="application/octet-stream"),bt({v:At,ch:"control",type:"http_head",reqId:H,status:mt.status,headers:Qn}),mt.body){for await(let Kt of mt.body)if(!bt({v:At,ch:"control",type:"http_data",reqId:H,data:Buffer.from(Kt).toString("base64")}))break}bt({v:At,ch:"control",type:"http_end",reqId:H,error:null})}finally{Rc.delete(H)}}function aL(B,H,j){let{reqId:M,method:G,path:ue,body:Ee}=B,Ae=new URL(b);return new Promise(mt=>{let Qn=C8.request({host:Ae.hostname,port:Ae.port,method:G,path:ue,headers:{...H,host:B.host},signal:j.signal},Kt=>{let{connection:Md,"keep-alive":xs,"transfer-encoding":XS,upgrade:gQ,...iL}=Kt.headers;bt({v:At,ch:"control",type:"http_head",reqId:M,status:Kt.statusCode||502,headers:iL}),Kt.on("data",cL=>{bt({v:At,ch:"control",type:"http_data",reqId:M,data:Buffer.from(cL).toString("base64")})||Kt.destroy()}),Kt.on("end",()=>{bt({v:At,ch:"control",type:"http_end",reqId:M,error:null}),mt()}),Kt.on("error",()=>{bt({v:At,ch:"control",type:"http_end",reqId:M,error:"view upstream error"}),mt()})});Qn.on("error",Kt=>{bt({v:At,ch:"control",type:"http_end",reqId:M,error:Kt?.message||"view request failed"}),mt()}),Ee&&Qn.write(Buffer.from(Ee,"base64")),Qn.end()})}function JS(){if(ys||Se)return;Gt=new J0(e,{headers:{authorization:`Bearer ${t}`}});let B=Gt;h=0,B.on("ping",()=>{h=Date.now()}),B.on("pong",()=>{h=Date.now()}),Gt.on("open",async()=>{let j=null;try{j=await s?.()||null}catch{j=null}bt({v:At,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:Vn,installKind:y,...typeof g=="function"?{updatePolicy:g()}:g?{updatePolicy:g}:{},providers:D8(),...j?{agents:j}:{}})}),Gt.on("message",j=>{h=Date.now();let M;try{M=JSON.parse(j)}catch{return}if(M.ch==="ctl"&&M.type==="hello_ok"){tw.clear(),nt=!0,bs=LN,uo=null,kv(),z.log(`[plane-link] connected to plane as ${n}`);try{$?.()}catch{}if(typeof M.hashKey=="string"&&M.hashKey)try{u?.(M.hashKey)}catch{}try{d?.(typeof M.viewBase=="string"&&M.viewBase?M.viewBase:null)}catch{}M.minNodeVersion&&Vn&&Yu(Vn,M.minNodeVersion)&&z.error(`[plane-link] this node is bostrat-node ${Vn}; the plane asks for \u2265${M.minNodeVersion} \u2014 update with: ${am(y)}`);try{m?.(typeof M.updatePolicy=="string"?M.updatePolicy:null)}catch{}X(M);let G=M.ingest==="http";Je=C==="ws"?"ws":C==="http"||G?"http":"ws",C==="http"&&!G&&z.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),Je==="http"&&z.log("[plane-link] spine rides the HTTPS ingest door"),yt=!1,nn=0,Et=as,k&&clearInterval(k),h=Date.now(),k=setInterval(()=>{ZB(B)||(bt({v:At,ch:"ctl",type:"ping"}),WS(),nL().catch(()=>{}),Qm(),rn.length&&!ct&&ew())},_),k.unref?.(),rL(),oL().catch(ue=>z.error("[plane-link] backfill failed:",ue?.message||ue));return}if(M.ch==="ctl"&&M.type==="hello_refused"){let G=typeof M.minNodeVersion=="string"?M.minNodeVersion:null,ue=typeof M.latestNodeVersion=="string"?M.latestNodeVersion:null;z.error(`[plane-link] plane REFUSED this node: bostrat-node ${Vn??"?"} is below its minimum ${G??"?"} \u2014 ${M.fix||am(y)}`),bs=jN,uo=0;try{f?.({current:Vn,min:G,latest:ue,fix:M.fix||am(y),installKind:y})}catch(Ee){z.error(`[plane-link] refusal handler failed: ${Ee?.message||Ee}`)}return}if(M.ch==="ctl"&&M.type==="removed"){bt({v:At,ch:"ctl",type:"removed_ack",nodeId:n}),ht({reason:typeof M.reason=="string"?M.reason:"removed",at:Number(M.at)||Date.now(),via:"ctl"});return}if(M.ch==="ctl"&&M.type==="update_available"){X(M);return}if(M.ch==="ctl"&&M.type==="update_policy"){try{m?.(typeof M.mode=="string"?M.mode:null)}catch{}return}if(M.ch==="ctl"&&M.type==="usage_caps"){$f(M.caps??{},{source:"plane",updatedAt:M.updatedAt??Date.now()}).then(G=>z.log(`[plane-link] spend caps ${Object.keys(G.caps).length?`updated (${Object.keys(G.caps).join(", ")})`:"cleared"} from plane`)).catch(G=>z.error("[plane-link] spend-caps push rejected:",G?.message||G));return}if(M.ch==="ctl"&&M.type==="transferred"&&Array.isArray(M.tracks)){Promise.resolve().then(()=>a?.(M.tracks)).then(async G=>{for(let ue of Array.isArray(G)?G:[])ue?.stale&&ue.id&&await VS(ue.id,ue.since??null)}).catch(G=>z.error("[plane-link] transfer notice failed:",G?.message||G));return}if(M.ch==="ctl"&&M.type==="moves"&&Array.isArray(M.tracks)){Promise.resolve().then(()=>i?.(M.tracks)).then(async G=>{for(let ue of Array.isArray(G)?G:[])ue?.stale&&ue.id&&await VS(ue.id,ue.since??null)}).catch(G=>z.error("[plane-link] move-record reconcile failed:",G?.message||G));return}if(M.ch==="events"&&M.type==="ack"&&Array.isArray(M.ids)){Xm(M.ids);return}if(M.ch==="events"&&M.type==="nack"&&Array.isArray(M.ids)){Zm(M.ids,M.reason,M.permanent===!0,M.retryAfterMs??null);return}if(M.ch==="control"&&M.type==="http_open"){sL(M).catch(G=>bt({v:At,ch:"control",type:"http_end",reqId:M.reqId,error:G?.message||"tunnel error"}));return}if(M.ch==="control"&&M.type==="http_cancel"){Rc.get(M.reqId)?.abort();return}if(M.ch==="attach"&&M.type==="open"){let G=new J0(Ke+M.path,Array.isArray(M.protocols)?M.protocols:[],M.host?{headers:{host:M.host}}:void 0);re.set(M.streamId,G),Te.set(M.streamId,[]),G.on("open",()=>{let Ee=Te.get(M.streamId)||[];Te.delete(M.streamId);for(let{buf:Ae,bin:mt}of Ee)G.send(Ae,{binary:mt})}),G.on("message",(Ee,Ae)=>{let mt=Ae?Ee:Buffer.from(String(Ee));bt({v:At,ch:"attach",type:"data",streamId:M.streamId,data:mt.toString("base64"),...Ae?{bin:!0}:{}})});let ue=()=>{Te.delete(M.streamId),re.delete(M.streamId)&&bt({v:At,ch:"attach",type:"close",streamId:M.streamId})};G.on("close",ue),G.on("error",ue);return}if(M.ch==="attach"&&M.type==="data"){let G=re.get(M.streamId);if(!G)return;let ue=Buffer.from(M.data,"base64"),Ee=M.bin===!0,Ae=Te.get(M.streamId);Ae?Ae.push({buf:ue,bin:Ee}):G.send(ue,{binary:Ee});return}if(M.ch==="attach"&&M.type==="close"){let G=re.get(M.streamId);re.delete(M.streamId),Te.delete(M.streamId),G?.close();return}});let H=()=>{nt&&z.log("[plane-link] disconnected from plane"),nt=!1,k&&(clearInterval(k),k=null),R&&(clearInterval(R),R=null),ge.clear(),ee={},rn=[],ct&&(clearTimeout(ct),ct=null),Xn.clear();for(let G of re.values())G.close();re.clear(),Te.clear();for(let G of Rc.values())G.abort();if(Rc.clear(),ys||po)return;uo==null&&(uo=Date.now());let j=Date.now()-uo<B8,M=Math.max(j?L8+Math.random()*j8:bs,N-Date.now(),jc());po=setTimeout(()=>{po=null,JS()},M),po.unref?.(),j||(bs=Math.min(bs*2,jN))};Gt.on("close",H),Gt.on("error",j=>{let M=/Unexpected server response: (\d+)/.exec(j?.message||"")?.[1];if(M==="410"){ht({reason:"removed",via:"410"});return}if(M==="401"||M==="403"){let{tripped:G,holdMs:ue}=Fa();G?z.error(`[plane-link] holding every plane call for ${Math.round(ue/6e4)} min \u2014 three credential refusals in a row (HTTP ${M}) 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(ue/6e4)} min.`):Date.now()-fe>=HN&&(fe=Date.now(),z.error(`[plane-link] plane refused this node's credentials (HTTP ${M}) \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)`))}H()})}at.on("event",zS),Od().then(JS);function YS({bye:B=!0}={}){ys=!0,at.off("event",zS),po&&clearTimeout(po),Zn&&clearTimeout(Zn),k&&clearInterval(k),R&&clearInterval(R),ct&&clearTimeout(ct),B&&bt({v:At,ch:"ctl",type:"bye",reason:"shutdown"}),Gt?.close()}return{stop:()=>YS(),status:()=>({connected:nt,nodeId:n,cursor:{...ve},inflight:ge.size,...qS(),auth:xv(),dormant:Se,removed:qd(),deadLinkMs:I,deadLinkRedials:A,refused:{...pe}}),_tick:()=>{WS(),Qm()}}}As();var cm=(()=>{try{return eJ(import.meta.url)("../package.json").version||null}catch{return null}})(),tJ=process.env.BOSTRAT_STATE_DIR||Tt.join(process.env.HOME||X8.tmpdir(),".bostrat"),ex=Tt.join(tJ,"self-update"),lm=Tt.join(ex,"status.json"),nJ=1440*6e4,rJ=6e4,KN=60,VN=15,um=3,Q0=6,oJ=20,sJ=Tt.join(ex,"supervisor.pid"),aJ="SIGUSR2",Zu=new Set(["npm-global","git-checkout"]);function zN({kind:e=Aa(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:Zu.has(e)?e==="git-checkout"||JN(t)?"auto":"prompt":"off"}function JN(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}function YN({env:e=process.env,platform:t=process.platform,uid:n=typeof process.getuid=="function"?process.getuid():0,serviceName:r=t==="darwin"?"com.bostrat.node":"bostrat-node.service",pidFile:o=sJ,readFile:s=i=>Xu.readFileSync(i,"utf8"),alive:a=iJ}={}){let i=t==="darwin"?{mode:"launchd",uid:n,serviceName:r}:{mode:"systemd",serviceName:r};if(JN(e))return i;let c=Number(e.BOSTRAT_RUN_SUPERVISOR_PID);if(!(Number.isInteger(c)&&c>0)){try{c=Number(String(s(o)).trim())}catch{c=NaN}Number.isInteger(c)&&c>0&&a(c)||(c=NaN)}return Number.isInteger(c)&&c>0?{mode:"supervisor",pid:c}:i}function iJ(e){try{process.kill(e,0)}catch{return!1}try{let t=Q8("ps",["-p",String(e),"-o","command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return/bostrat-node|\/cli\.js|node-cli\.js/.test(t)}catch{return!1}}function cJ(e){switch(e?.mode){case"systemd":return`systemctl --user restart ${An(e.serviceName||"bostrat-node.service")}`;case"launchd":return`launchctl kickstart -k gui/${Number(e.uid)||0}/${e.serviceName||"com.bostrat.node"}`;case"supervisor":return`kill -${aJ.replace(/^SIG/,"")} ${Number(e.pid)}`;default:throw new Error(`self-update: unknown restart strategy "${e?.mode}"`)}}var An=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function lJ({kind:e,to:t,from:n=cm,statusFile:r=lm,logFile:o=Tt.join(ex,"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,restart:l=YN({env:{},platform:process.platform,uid:c,serviceName:i,readFile:()=>{throw new Error("no pidfile")}}),liveDir:u=process.env.BOSTRAT_LIVE_CHECKOUT||Tt.resolve(Tt.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:d=Date.now(),attempts:p=1}={}){if(!Zu.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 w=(b,x="")=>`write_status ${An(b)} ${x}`,m=cJ(l),f=`
|
|
836
|
+
`);X3=new Set(["claude","codex","cursor"]);Lu=new Set,Z3=e=>Lu.has(e);Q3=9e4;eN={merged:"merged",closed:"closed on GitHub WITHOUT merging",lost:"no longer found on GitHub (deleted, or its repo left the grant)"};qk=new Map;n8=6e4,Gk=new Map;Fu=120;o8=10*6e4,$u=new Map;ya=new Map,ac=e=>ya.get(e)||(Zt?he(Zt,e)?.handoff:null)||null;N0=6e4,Kn=(e,t,n=15e3)=>Zk("git",["-C",e,...t],{timeout:n,maxBuffer:8*1024*1024}),jh=new Map,P0=e=>jh.get(e)||null;d8=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,200}$/;Nh=new Map;h8=Number(process.env.BOSTRAT_SUBTASK_TIMEOUT_MS)||18e5,m8=Number(process.env.BOSTRAT_SUBTASK_POLL_MS)||3e3,ec=Y.join(xr,"worktrees"),Vi=[Cu,Ph],Ut=new Map;_I({linkedRepos:async()=>((await $s()).repos??[]).map(e=>e.slug).filter(Boolean),workspaces:async()=>{let e=await te(),t=[];for(let n of e.tracks)n.archivedAt||n.transferredTo||!n.workspace?.dir||t.push(n.workspace.dir);for(let n of Ut.values())!n.finishedAt&&n.dir&&t.push(n.dir);return t}});w8=e=>Ut.get(e)||(Zt?Zt.tracks.map(t=>t.subtasks?.[e]).find(Boolean):null)||null,va=e=>{let t=new Map([...Ut.values()].filter(r=>r.trackId===e).map(r=>[r.id,r])),n=Zt?he(Zt,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)},nm=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});Ku=e=>IN(e.trackId,e.id,nm(e));Uu=class extends Error{}});kt();import De from"node:path";import $t from"node:fs";import qZ from"node:readline";import{fileURLToPath as GZ}from"node:url";import en from"express";import BB from"node:http";import KZ from"node:https";import Ac from"node:os";import{randomUUID as VZ}from"node:crypto";import{WebSocketServer as zZ}from"ws";kt();import VF from"node-pty";async function LA(e,t,n={}){if(!qe(t)){gp(e,`invalid session name: ${t}`),e.close(1008,"invalid session name");return}if(!await So()){gp(e,`host tmux server not running on ${St}`),e.close(1011,"tmux server unavailable");return}if(!await _e(t)){let a=!1;if(typeof n.revive=="function"&&(yp(e,{type:"notice",message:"Resuming the lead box\u2026"}),a=await n.revive().catch(()=>!1)),!a||!await _e(t)){gp(e,`session "${t}" not found`),e.close(1008,"session not found");return}if(e.readyState!==e.OPEN)return}let r=BA(n.cols,120,jA),o=BA(n.rows,32,FA),s;try{s=VF.spawn(oe,["-S",St,"attach-session","-d","-t",t],{name:"xterm-256color",cols:r,rows:o,cwd:process.env.HOME||"/",env:{...process.env,TERM:"xterm-256color"}})}catch(a){gp(e,`failed to spawn tmux attach: ${a.message}`),e.close(1011,"spawn failed");return}s.onData(a=>{e.readyState===e.OPEN&&yp(e,{type:"data",data:a})}),s.onExit(({exitCode:a,signal:i})=>{e.readyState===e.OPEN&&(yp(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"&&XF(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{}YF(t)})}var zF=6,JF=250;async function YF(e,t=zF,n=JF){for(let r=0;r<t;r++){if(await Cs(e).catch(()=>!0))return!0;await new Promise(o=>setTimeout(o,n))}return!1}var jA=20,FA=6;function XF(e,t){return Number.isFinite(Number(e))&&Number.isFinite(Number(t))&&Number(e)>=jA&&Number(t)>=FA}function BA(e,t,n){let r=Number(e);return!Number.isFinite(r)||r<n?t:Math.min(500,r|0)}function yp(e,t){try{e.send(JSON.stringify(t))}catch{}}function gp(e,t){yp(e,{type:"error",message:t})}function UA(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}}Mn();Tp();Gg();Vr();import{createRequire as JZ}from"node:module";var E8=e=>!!e&&!e.finishedAt&&!e.canceled&&!e.error;function K0(e,{queuedOf:t=()=>[],jobsOf:n=()=>[],prPendingOf:r=()=>[]}={}){let o=[];return!e||e.archivedAt&&!e.archiving||e.transferredTo||(e.working&&o.push(`working:${e.id}`),e.prompted&&o.push(`prompted:${e.id}`),(t(e.id)??[]).length&&o.push(`queued:${e.id}`),(e.boxes||[]).some(s=>s?.role==="subtask"&&s?.state==="live")&&o.push(`subtask:${e.id}`),(n(e.id)??[]).length&&o.push(`job:${e.id}`),Object.values(e.subtasks||{}).some(E8)&&o.push(`merge-back:${e.id}`),(r(e.id)??[]).length&&o.push(`pr:${e.id}`)),o}function V0({tracks:e=[],views:t=[],queuedOf:n=()=>[],jobsOf:r=()=>[],prPendingOf:o=()=>[],deps:s=!1}={}){let a=[];for(let i of e)a.push(...K0(i,{queuedOf:n,jobsOf:r,prPendingOf:o}));return t.some(i=>i?.state==="live"||i?.state==="starting")&&a.push("views"),s&&a.push("deps"),{busy:a.length>0,reasons:a}}Nk();be();Fi();jn();ih();yn();var om=60*6e4,_8=1440*6e4,I8=new Set(["merged","closed","lost"]),Vu=(e,t,n)=>Number.isFinite(Number(e))&&n-Number(e)<=t;function $8({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)<=ok&&s.push("ship"),r>0&&s.push("create-net");for(let a of n||[]){if(!a||I8.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&&Vu(a.ciFix.delegatedAt,om,o)&&s.push(`ci-fix#${l}`),a.reconcile&&Vu(a.reconcile.delegatedAt,om,o)&&s.push(`reconcile#${l}`),a.ciFixAwait&&Vu(a.ciFixAwait.since,om,o)&&s.push(`ci-fix-await#${l}`),a.reconcileAwait&&Vu(a.reconcileAwait.since,om,o)&&s.push(`reconcile-await#${l}`);let u=a.autoMerge?.armedAt??a.armedAt??null;a.trackId===e&&(a.autoMerge||a.armedAt)&&Vu(u,_8,o)&&s.push(`auto-merge#${l}`)}return s}var sm=new Map;at.on("event",e=>{e?.trackId&&sm.delete(e.trackId)});async function R8(e){if(sm.has(e.id))return sm.get(e.id);let t=await V(e).catch(()=>[]),n=Zo(t,-1/0);return sm.set(e.id,n),n}async function NN(e,{now:t=Date.now()}={}){let n=new Map,r=await Ln().catch(()=>[]);for(let o of e||[]){if(!o||He(o))continue;let s=$8({trackId:o.id,shipPending:await R8(o),links:r,observers:aO(o.id),now:t});s.length&&n.set(o.id,s)}return n}su();import Xu from"node:fs";import is from"node:fs/promises";import X8 from"node:os";import Tt from"node:path";import{spawn as Z8,execFileSync as Q8}from"node:child_process";import{createRequire as eJ}from"node:module";be();Rf();import cc from"node:fs";import Ju from"node:fs/promises";import C8 from"node:http";import Wt from"node:path";import im from"node:os";import{createRequire as N8}from"node:module";import J0 from"ws";import O8 from"node:path";import M8 from"node:os";var zu=process.env.BOSTRAT_STATE_DIR||O8.join(process.env.HOME||M8.tmpdir(),".bostrat");function z0(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 PN(e=process.env){if(!e.BOSTRAT_PLANE_URL)return null;let t=z0(e);return t==="127.0.0.1"||t==="::1"||t==="localhost"?null:{host:t}}function DN(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}gw();var Vn=(()=>{try{return N8(import.meta.url)("../package.json").version||null}catch{return null}})(),Z0=process.env.BOSTRAT_STATE_DIR||Wt.join(process.env.HOME||im.tmpdir(),".bostrat"),WN=Wt.join(Z0,"plane-link","removed.json");function BN(e){return typeof e!="string"||e.length<8?"\u2022\u2022\u2022\u2022":`${e.slice(0,6)}\u2026${e.slice(-4)}`}function P8(e=WN){try{let t=JSON.parse(cc.readFileSync(e,"utf8"));return t&&typeof t=="object"?t:null}catch{return null}}function Aa({env:e=process.env,pkgDir:t=Wt.resolve(Wt.dirname(new URL(import.meta.url).pathname),".."),exists:n=cc.existsSync}={}){let r=String(e.BOSTRAT_INSTALL_KIND||"").trim();return["container","npm-global","git-checkout","dev"].includes(r)?r:/\/lib\/node_modules\/bostrat-node(?:\/|$)/.test(t.replace(/\\/g,"/"))?"npm-global":n(Wt.join(t,"..",".git"))?"git-checkout":"dev"}function Yu(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 am(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 D8({home:e=process.env.HOME||im.homedir(),env:t=process.env}={}){let n=r=>{try{return cc.statSync(r),!0}catch{return!1}};return{claude:n(Wt.join(e,".claude",".credentials.json")),codex:n(Wt.join(t.CODEX_HOME||Wt.join(e,".codex"),"auth.json")),cursor:n(Wt.join(t.XDG_CONFIG_HOME||Wt.join(e,".config"),"cursor","auth.json"))}}var At=1,LN=1e3,jN=3e4,B8=6e4,L8=1500,j8=500,as=100,F8=2e3,U8=25e3,H8=2.5,W8=6e4,qN=(e,t)=>{let n=Number(e);return Number.isFinite(n)&&n>0?n:t},q8=qN(process.env.BOSTRAT_PLANE_DELIVERY_TIMEOUT_MS,18e4),Y0="refused:",G8={forgedUserId:"this node's events carry a userId the plane's token does not own \u2014 remove BOSTRAT_OWNER from node.env and the shell environment, then restart the node (current releases never stamp one)",foreignTrack:"the Track belongs to another user's node \u2014 this node must not append to it",squattedTrack:"the Track id is already claimed by another user \u2014 a local Track collided with theirs",transferredAway:"the Track moved to another node \u2014 this copy is stale; it should be demoted, not resumed",slugHijack:"a View slug belongs to another owner \u2014 pick a different slug"},K8=e=>{if(!e||e.userId===void 0)return e;let{userId:t,...n}=e;return n},V8=3e4,FN=10*6e4,z8=400,UN=250,J8=qN(process.env.BOSTRAT_PLANE_INGEST_TIMEOUT_MS,1e4),X0=4,Y8=6e4,HN=6e4;function GN({url:e,token:t,nodeId:n=im.hostname(),name:r=im.hostname(),listTracks:o,detectAgents:s=null,onTracksTransferred:a=null,onTracksMoves:i=null,sampleMetrics:c=null,deliverySample:l=null,onHashKey:u=null,onViewBase:d=null,metricsMs:p=Y8,onUpdateAvailable:w=null,onUpdatePolicy:m=null,onHelloRefused:h=null,updatePolicy:g=null,installKind:y=Aa(),selfUrl:b=`http://127.0.0.1:${process.env.PORT||3362}`,apiToken:x=null,removedMarkerFile:v=WN,onRemoved:S=null,onDegraded:E=null,onRecovered:P=null,onRefused:L=null,onConnected:$=null,ingestMode:C=["ws","http","auto"].includes(process.env.BOSTRAT_PLANE_INGEST)?process.env.BOSTRAT_PLANE_INGEST:"auto",deliveryTimeoutMs:U=q8,unackedRetryMs:J=W8,pingMs:_=U8,deadLinkMs:I=Math.round(_*H8),maxInflightEvents:T=z8,httpTimeoutMs:F=J8,stallBackoffMinMs:W=V8,fetchImpl:ce=globalThis.fetch,log:z=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=DN(e);let Ke=b.replace(/^http/,"ws"),Ie=new Set,X=B=>{let H=typeof B.latestNodeVersion=="string"?B.latestNodeVersion:null;if(!(!(H&&Vn&&Yu(Vn,H))||Ie.has(H))){Ie.add(H),z.log(`[plane-link] bostrat-node ${H} is available (this node runs ${Vn}) \u2014 ${am(y)}`);try{w?.({current:Vn,latest:H,min:B.minNodeVersion??null,installKind:y,required:!!(B.minNodeVersion&&Yu(Vn,B.minNodeVersion))})}catch(j){z.error(`[plane-link] update notice failed: ${j?.message||j}`)}}},re=new Map,Te=new Map,Le=Wt.join(Z0,"plane-link","cursor.json"),ie=Wt.join(Z0,"plane-link","dead-letter.ndjson"),Pe=e.replace(/^ws(s?):\/\//,"http$1://").replace(/\/v1\/node\/?$/,""),ve={},ee={},ge=new Map,Ve=null,ze=null,Ze=0,N=0,le=0,pe={},$e=new Set,Qe=Promise.resolve(),Je="ws",tn=0,yt=!1,nn=0,lo=!1,Et=as,Xn=new Set,rn=[],ct=null,Gt=null,nt=!1,ys=!1,bs=LN,uo=null,po=null,Zn=null,k=null,f=0,A=0,R=null,q=!1,fe=0,Se=!1,We=P8(v);if(We)if(We.tokenPreview===BN(t))Se=!0,ww({reason:We.reason??"removed",at:We.at??null,nodeId:We.nodeId??n}),z.error(`[plane-link] this node was REMOVED from the plane (${We.reason??"removed"}${We.at?` at ${new Date(We.at).toISOString()}`:""}) \u2014 not dialing. Re-provision it with a new node token, or delete ${v} to force a dial.`);else try{cc.unlinkSync(v),z.log("[plane-link] stale removed-marker discarded \u2014 the node token changed")}catch{}function ht({reason:B="removed",at:H=Date.now(),via:j="ctl"}={}){if(!Se){Se=!0,ww({reason:B,at:H,nodeId:n,via:j});try{cc.mkdirSync(Wt.dirname(v),{recursive:!0}),cc.writeFileSync(v,JSON.stringify({at:H,reason:B,via:j,nodeId:n,tokenPreview:BN(t)},null,2))}catch(M){z.error(`[plane-link] could not write ${v}: ${M?.message||M}`)}z.error(`[plane-link] the plane REMOVED this node (${B}, via ${j}) \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:B,at:H,via:j})}catch{}YS({bye:!1})}}async function Od(){try{ve=JSON.parse(await Ju.readFile(Le,"utf8"))}catch{ve={}}}function _r(){q=!0,!Zn&&(Zn=setTimeout(async()=>{if(Zn=null,!!q){q=!1;try{await Ju.mkdir(Wt.dirname(Le),{recursive:!0}),await Ju.writeFile(Le,JSON.stringify(ve))}catch(B){z.error("[plane-link] cursor flush failed:",B?.message||B)}}},F8),Zn.unref?.())}function bt(B){return!Gt||Gt.readyState!==J0.OPEN?!1:(Gt.send(JSON.stringify(B)),!0)}function Ic(B){let H=Date.now();for(let{trackId:M,event:G}of B){let ue=ge.get(G.id);ge.set(G.id,{trackId:M,seq:G.seq,event:G,sentAt:H,firstSentAt:ue?.firstSentAt??H,retryAt:H+J,tries:(ue?.tries??0)+1,nacks:ue?.nacks??0})}let j=B.map(({trackId:M,event:G})=>({trackId:M,event:K8(G)}));return Je==="http"?(tL(j),!0):bt({v:At,ch:"events",type:"append",events:j})}function YB(B){let H=null;for(let j of ge.values())j.trackId===B&&(H==null||j.seq<H)&&(H=j.seq);return H}function Ym(B){let H=ee[B];if(H==null)return;let j=YB(B),M=j==null?H:Math.min(H,j-1);M>(ve[B]??0)&&(ve[B]=M,_r())}function $c(){if(Ve=Date.now(),ze!=null){let B=Date.now()-ze;z.log(`[plane-link] spine sync recovered after ${Math.round(B/1e3)}s degraded (${Ze} stall redial(s))`);let H=ze;ze=null,Ze=0,N=0,yt=!1,nn=0;try{P?.({since:H,downMs:B})}catch(j){z.error(`[plane-link] onRecovered failed: ${j?.message||j}`)}}}function Xm(B){if(!Array.isArray(B)||!B.length)return;let H=new Set;for(let j of B){let M=ge.get(j);M&&(ge.delete(j),(ee[M.trackId]??0)<M.seq&&(ee[M.trackId]=M.seq),H.add(M.trackId))}for(let j of H)Ym(j);$c()}function US(B,H){le++;let j={at:Date.now(),trackId:B.trackId,seq:B.seq,id:B.event?.id??null,type:B.event?.type??null,reason:H,event:B.event??null};z.error(`[plane-link] DEAD-LETTER ${B.trackId} seq ${B.seq} (${j.type??"?"}): plane rejected it permanently (${H}) \u2014 kept in ${ie}`),Qe=Qe.then(async()=>{await Ju.mkdir(Wt.dirname(ie),{recursive:!0}),await Ju.appendFile(ie,JSON.stringify(j)+`
|
|
837
|
+
`)}).catch(M=>z.error(`[plane-link] dead-letter write failed: ${M?.message||M}`))}function XB(B,H){if(pe[B]=(pe[B]??0)+1,$e.has(B))return;$e.add(B);let j=G8[B]??"see the plane's tenancy alarm ring (GET /plane/tenancy/alarms)";z.error(`[plane-link] REFUSED by the plane (${B}) on track ${H}: events are being dropped, not stored \u2014 ${j}`);try{L?.({reason:B,trackId:H,count:pe[B],hint:j})}catch(M){z.error(`[plane-link] onRefused failed: ${M?.message||M}`)}}function Zm(B,H,j,M=null){if(!Array.isArray(B)||!B.length)return;let G=new Set,ue=Date.now();for(let Ee of B){let Ae=ge.get(Ee);Ae&&(j?(ge.delete(Ee),US(Ae,H),String(H).startsWith(Y0)&&XB(String(H).slice(Y0.length),Ae.trackId),(ee[Ae.trackId]??0)<Ae.seq&&(ee[Ae.trackId]=Ae.seq),G.add(Ae.trackId)):(Ae.nacks++,Ae.retryAt=ue+Math.max(1e3,Number(M)||J)))}for(let Ee of G)Ym(Ee);$c()}function HS(B=Date.now()){let H=1/0;for(let j of ge.values())j.firstSentAt<H&&(H=j.firstSentAt);return H===1/0?0:B-H}function ZB(B){if(!I||!B||B!==Gt||!f)return!1;let H=Date.now()-f;if(H<=I)return!1;A++,z.error(`[plane-link] no frame from the plane for ${Math.round(H/1e3)}s \u2014 link is half-open; terminating and redialing`);try{B.terminate()}catch{}return!0}function WS(){if(!nt||!ge.size)return;let B=Date.now(),H=HS(B);if(H<U||Ve!=null&&B-Ve<U||Je==="http"&&yt||N>B)return;Ze++;let j=Math.min(W*2**(Ze-1),FN);if(ze==null){ze=B-H,z.error(`[plane-link] DEGRADED: no ack or nack for ${Math.round(H/1e3)}s with ${ge.size} event(s) in flight (${Je} door) \u2014 the plane is not answering appends`);try{E?.({since:ze,unacked:ge.size,oldestAgeMs:H,mode:Je})}catch(M){z.error(`[plane-link] onDegraded failed: ${M?.message||M}`)}}if(Je==="http"){yt=!0,nn=B+j,z.error(`[plane-link] ingest circuit OPEN (stall #${Ze}); probing /v1/ingest/health in ${Math.round(j/1e3)}s`);return}N=B+j,z.error(`[plane-link] closing the link and redialing in ${Math.round(j/1e3)}s (stall redial #${Ze})`);try{Gt?.terminate()}catch{}}function Qm(){if(!nt)return;let B=Date.now();if(Je==="http"&&yt)return;let H=[...ge.values()].filter(M=>M.event&&M.retryAt<=B&&!(Je==="http"&&Xn.has(M.trackId)));if(!H.length)return;H.sort((M,G)=>M.trackId===G.trackId?M.seq-G.seq:M.trackId<G.trackId?-1:1),z.log(`[plane-link] re-sending ${H.length} unacked event(s) the plane never confirmed`);let j=Je==="http"?Et:as;if(Je==="http"){let M=new Map;for(let G of H)(M.get(G.trackId)??M.set(G.trackId,[]).get(G.trackId)).push(G);for(let[,G]of M){if(tn>=X0)return;Ic(G.slice(0,j).map(ue=>({trackId:ue.trackId,event:ue.event})))}return}for(let M=0;M<H.length;M+=j){let G=H.slice(M,M+j).map(ue=>({trackId:ue.trackId,event:ue.event}));if(!Ic(G))return}}async function QB(B=null){for(;;){if(!nt)return!1;let H=ge.size<T,j=Je!=="http"||tn<X0&&!yt&&(!B||!Xn.has(B));if(H&&j)return!0;await new Promise(M=>setTimeout(M,100))}}function ew(){if(ct=null,!nt||!rn.length)return;let B=rn;if(rn=[],Je!=="http"){for(let j=0;j<B.length;j+=as)Ic(B.slice(j,j+as));return}let H=new Map;for(let j of B)(H.get(j.trackId)??H.set(j.trackId,[]).get(j.trackId)).push(j);for(let[j,M]of H){if(Xn.has(j)||tn>=X0||yt){rn.push(...M);continue}for(let G=0;G<M.length;G+=Et)Ic(M.slice(G,G+Et))}rn.length&&!ct&&(ct=setTimeout(ew,UN),ct.unref?.())}let eL=B=>{let H=new Map;for(let{trackId:j,event:M}of B)(H.get(j)??H.set(j,[]).get(j)).push(M);return[...H].map(([j,M])=>({trackId:j,events:M}))},ks=(B,H,j,{progress:M})=>{let G=Date.now();for(let{event:ue}of B){let Ee=ge.get(ue.id);Ee&&(Ee.nacks++,Ee.retryAt=G+Math.max(1e3,j||J))}M&&$c()};async function tL(B){let H=new Set(B.map(j=>j.trackId));for(let j of H)Xn.add(j);tn++;try{let j=await ce(`${Pe}/v1/ingest`,{method:"POST",headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},body:JSON.stringify({node:n,batches:eL(B)}),signal:AbortSignal.timeout(F)}),M=(Number(j.headers.get("retry-after"))||0)*1e3;if(j.status===200){let G=await j.json();Et=as;for(let Ae of G.results??[]){Xm(Ae.acked??[]);let mt=(Qn,Kt)=>{let Md=new Map;for(let xs of Qn??[])(Md.get(xs.reason)??Md.set(xs.reason,[]).get(xs.reason)).push(xs.id);for(let[xs,XS]of Md)Zm(XS,xs,Kt,G.retryAfterMs??null)};mt(Ae.rejected,!0),mt(Ae.deferred,!1)}let ue=new Set,Ee=new Map;for(let Ae of Array.isArray(G.refused)?G.refused:[])!Ae||typeof Ae.id!="string"||(ue.add(Ae.id),(Ee.get(Ae.reason)??Ee.set(Ae.reason,[]).get(Ae.reason)).push(Ae.id));for(let[Ae,mt]of Ee)Zm(mt,`${Y0}${Ae}`,!0);Xm((G.discarded??[]).filter(Ae=>!ue.has(Ae))),$c();return}if(j.status===429){ks(B,"overloaded",M||5e3,{progress:!0});return}if(j.status===413&&B.length>1){Et=Math.max(1,Math.floor(B.length/2)),z.error(`[plane-link] ingest request too large (${B.length} events) \u2014 halving batches to ${Et}`),ks(B,"too_large",1e3,{progress:!0});return}if(j.status===413){let G=ge.get(B[0].event.id);G&&(ge.delete(G.event.id),US(G,"too_large"),(ee[G.trackId]??0)<G.seq&&(ee[G.trackId]=G.seq),Ym(G.trackId)),$c();return}if(j.status===410){ht({reason:"removed",via:"410"}),ks(B,"http_410",6e4,{progress:!1});return}if(j.status===401||j.status===403){let{tripped:G,holdMs:ue}=Fa();if(G&&z.error(`[plane-link] holding every plane call for ${Math.round(ue/6e4)} min \u2014 the ingest door refused this node's token three times in a row`),Date.now()-fe>=HN){fe=Date.now();let Ee="";try{Ee=(await j.json())?.error??""}catch{}z.error(`[plane-link] plane refused ingest (HTTP ${j.status}${Ee?`: ${Ee}`:""}) \u2014 events are held locally and retried; check this node's token/binding`)}ks(B,`http_${j.status}`,Math.max(6e4,jc()),{progress:!1});return}if(j.status===400){z.error(`[plane-link] plane rejected an ingest request as malformed (400) \u2014 holding ${B.length} event(s) for retry; this is a bug, not data`),ks(B,"http_400",6e4,{progress:!1});return}ks(B,`http_${j.status}`,M||5e3,{progress:!1})}catch(j){let M=j?.name==="TimeoutError"||j?.name==="AbortError";M&&B.length>1&&(Et=Math.max(1,Math.floor(B.length/2)),z.error(`[plane-link] ingest request of ${B.length} event(s) outlived its ${F} ms deadline \u2014 halving batches to ${Et}`)),ks(B,M?"timeout":"network",5e3,{progress:!1})}finally{tn--;for(let j of H)Xn.delete(j)}}async function nL(){if(Je!=="http"||!yt||!nt||lo)return;let B=Date.now();if(!(nn>B||Ua(B))){lo=!0;try{let H=await ce(`${Pe}/v1/ingest/health`,{headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(F)});if(!H.ok)throw new Error(`HTTP ${H.status}`);z.log("[plane-link] ingest door answering \u2014 closing the circuit and re-sending"),yt=!1,nn=0,N=Date.now()+F+J+1e3;for(let j of ge.values())j.retryAt=Math.min(j.retryAt,Date.now());Qm()}catch(H){Ze++;let j=Math.min(W*2**(Ze-1),FN);nn=Date.now()+j,z.error(`[plane-link] ingest door still not answering (${H?.message||H}); next probe in ${Math.round(j/1e3)}s`)}finally{lo=!1}}}function qS(){let B=Date.now();return{mode:Je,unacked:ge.size,oldestUnackedAgeMs:HS(B),lastProgressAt:Ve,degradedSince:ze,stallRedials:Ze,deadLettered:le,http:Je==="http"?{inFlight:tn,circuitOpen:yt,nextProbeInMs:yt?Math.max(0,nn-B):0,batchCap:Et}:null}}async function GS(){if(!c)return;let B;try{B=await c()}catch(j){z.error("[plane-link] metrics sample failed:",j?.message||j);return}let H=null;try{H=l?.()??null}catch{}B&&bt({v:At,ch:"ctl",type:"metrics",metrics:{...B,planeLink:qS(),...H?{delivery:H}:{}}})}function rL(){c&&(R&&clearInterval(R),GS(),R=setInterval(GS,p),R.unref?.())}async function oL(){let B;try{B=await o()}catch(H){z.error("[plane-link] backfill listTracks failed:",H?.message||H);return}bt({v:At,ch:"ctl",type:"tracks",ids:B.filter(H=>!H.transferredTo).map(H=>H.id).filter(H=>typeof H=="string")});for(let H of B)if(!nt||!await KS(H))return}async function KS(B){let H;try{H=await V(B)}catch{return!0}let j=ve[B.id]??0,M=H.filter(ue=>ue.seq>j&&typeof ue.id=="string"),G=Je==="http"?Et:as;for(let ue=0;ue<M.length;ue+=G){if(!await QB(B.id))return!1;let Ee=M.slice(ue,ue+Math.min(G,Je==="http"?Et:as)).map(Ae=>({trackId:B.id,event:Ae}));if(!Ic(Ee))return!1}return!0}let tw=new Map;async function VS(B,H){if(tw.get(B)===H)return!1;tw.set(B,H);let j=null;try{j=(await o()).find(Ee=>Ee?.id===B)??null}catch{return!1}if(!j)return!1;let M;try{M=await V(j)}catch{return!1}let G=[...M].reverse().find(Ee=>(Ee?.type==="track.transferred"||Ee?.type==="track.recovered")&&Ee.payload?.toNode===n);if(!G||!Number.isFinite(G.seq))return!1;let ue=G.seq-1;return(ve[B]??0)>ue&&(ve[B]=ue,_r()),(ee[B]??0)>ue&&(ee[B]=ue),z.log(`[plane-link] re-sending ${B}'s move-commit (seq ${G.seq}, ${G.type}) \u2014 the plane's move record predates this node's adoption`),nt?KS(j):!1}function zS(B){!nt||!B?.trackId||typeof B.id!="string"||(rn.push({trackId:B.trackId,event:B}),ct||(ct=setTimeout(ew,UN),ct.unref?.()))}let Rc=new Map;async function sL(B){let{reqId:H,method:j,path:M,headers:G={},body:ue}=B,Ee=Object.fromEntries(Object.entries(G).filter(([,mt])=>mt!=null)),Ae=new AbortController;Rc.set(H,Ae);try{if(B.host){await aL(B,Ee,Ae);return}x&&(Ee["x-bostrat-token"]=x);let mt=await fetch(b+M,{method:j,headers:Ee,body:ue?Buffer.from(ue,"base64"):void 0,signal:Ae.signal}),Qn=Object.fromEntries(mt.headers);for(let Kt of["connection","keep-alive","transfer-encoding","upgrade","content-encoding","content-length"])delete Qn[Kt];if(Qn["content-type"]||(Qn["content-type"]="application/octet-stream"),bt({v:At,ch:"control",type:"http_head",reqId:H,status:mt.status,headers:Qn}),mt.body){for await(let Kt of mt.body)if(!bt({v:At,ch:"control",type:"http_data",reqId:H,data:Buffer.from(Kt).toString("base64")}))break}bt({v:At,ch:"control",type:"http_end",reqId:H,error:null})}finally{Rc.delete(H)}}function aL(B,H,j){let{reqId:M,method:G,path:ue,body:Ee}=B,Ae=new URL(b);return new Promise(mt=>{let Qn=C8.request({host:Ae.hostname,port:Ae.port,method:G,path:ue,headers:{...H,host:B.host},signal:j.signal},Kt=>{let{connection:Md,"keep-alive":xs,"transfer-encoding":XS,upgrade:gQ,...iL}=Kt.headers;bt({v:At,ch:"control",type:"http_head",reqId:M,status:Kt.statusCode||502,headers:iL}),Kt.on("data",cL=>{bt({v:At,ch:"control",type:"http_data",reqId:M,data:Buffer.from(cL).toString("base64")})||Kt.destroy()}),Kt.on("end",()=>{bt({v:At,ch:"control",type:"http_end",reqId:M,error:null}),mt()}),Kt.on("error",()=>{bt({v:At,ch:"control",type:"http_end",reqId:M,error:"view upstream error"}),mt()})});Qn.on("error",Kt=>{bt({v:At,ch:"control",type:"http_end",reqId:M,error:Kt?.message||"view request failed"}),mt()}),Ee&&Qn.write(Buffer.from(Ee,"base64")),Qn.end()})}function JS(){if(ys||Se)return;Gt=new J0(e,{headers:{authorization:`Bearer ${t}`}});let B=Gt;f=0,B.on("ping",()=>{f=Date.now()}),B.on("pong",()=>{f=Date.now()}),Gt.on("open",async()=>{let j=null;try{j=await s?.()||null}catch{j=null}bt({v:At,ch:"ctl",type:"hello",nodeId:n,name:r,platform:process.platform,version:Vn,installKind:y,...typeof g=="function"?{updatePolicy:g()}:g?{updatePolicy:g}:{},providers:D8(),...j?{agents:j}:{}})}),Gt.on("message",j=>{f=Date.now();let M;try{M=JSON.parse(j)}catch{return}if(M.ch==="ctl"&&M.type==="hello_ok"){tw.clear(),nt=!0,bs=LN,uo=null,kv(),z.log(`[plane-link] connected to plane as ${n}`);try{$?.()}catch{}if(typeof M.hashKey=="string"&&M.hashKey)try{u?.(M.hashKey)}catch{}try{d?.(typeof M.viewBase=="string"&&M.viewBase?M.viewBase:null)}catch{}M.minNodeVersion&&Vn&&Yu(Vn,M.minNodeVersion)&&z.error(`[plane-link] this node is bostrat-node ${Vn}; the plane asks for \u2265${M.minNodeVersion} \u2014 update with: ${am(y)}`);try{m?.(typeof M.updatePolicy=="string"?M.updatePolicy:null)}catch{}X(M);let G=M.ingest==="http";Je=C==="ws"?"ws":C==="http"||G?"http":"ws",C==="http"&&!G&&z.error("[plane-link] BOSTRAT_PLANE_INGEST=http but this plane offers no HTTPS ingest door \u2014 events will fail until it does"),Je==="http"&&z.log("[plane-link] spine rides the HTTPS ingest door"),yt=!1,nn=0,Et=as,k&&clearInterval(k),f=Date.now(),k=setInterval(()=>{ZB(B)||(bt({v:At,ch:"ctl",type:"ping"}),WS(),nL().catch(()=>{}),Qm(),rn.length&&!ct&&ew())},_),k.unref?.(),rL(),oL().catch(ue=>z.error("[plane-link] backfill failed:",ue?.message||ue));return}if(M.ch==="ctl"&&M.type==="hello_refused"){let G=typeof M.minNodeVersion=="string"?M.minNodeVersion:null,ue=typeof M.latestNodeVersion=="string"?M.latestNodeVersion:null;z.error(`[plane-link] plane REFUSED this node: bostrat-node ${Vn??"?"} is below its minimum ${G??"?"} \u2014 ${M.fix||am(y)}`),bs=jN,uo=0;try{h?.({current:Vn,min:G,latest:ue,fix:M.fix||am(y),installKind:y})}catch(Ee){z.error(`[plane-link] refusal handler failed: ${Ee?.message||Ee}`)}return}if(M.ch==="ctl"&&M.type==="removed"){bt({v:At,ch:"ctl",type:"removed_ack",nodeId:n}),ht({reason:typeof M.reason=="string"?M.reason:"removed",at:Number(M.at)||Date.now(),via:"ctl"});return}if(M.ch==="ctl"&&M.type==="update_available"){X(M);return}if(M.ch==="ctl"&&M.type==="update_policy"){try{m?.(typeof M.mode=="string"?M.mode:null)}catch{}return}if(M.ch==="ctl"&&M.type==="usage_caps"){$f(M.caps??{},{source:"plane",updatedAt:M.updatedAt??Date.now()}).then(G=>z.log(`[plane-link] spend caps ${Object.keys(G.caps).length?`updated (${Object.keys(G.caps).join(", ")})`:"cleared"} from plane`)).catch(G=>z.error("[plane-link] spend-caps push rejected:",G?.message||G));return}if(M.ch==="ctl"&&M.type==="transferred"&&Array.isArray(M.tracks)){Promise.resolve().then(()=>a?.(M.tracks)).then(async G=>{for(let ue of Array.isArray(G)?G:[])ue?.stale&&ue.id&&await VS(ue.id,ue.since??null)}).catch(G=>z.error("[plane-link] transfer notice failed:",G?.message||G));return}if(M.ch==="ctl"&&M.type==="moves"&&Array.isArray(M.tracks)){Promise.resolve().then(()=>i?.(M.tracks)).then(async G=>{for(let ue of Array.isArray(G)?G:[])ue?.stale&&ue.id&&await VS(ue.id,ue.since??null)}).catch(G=>z.error("[plane-link] move-record reconcile failed:",G?.message||G));return}if(M.ch==="events"&&M.type==="ack"&&Array.isArray(M.ids)){Xm(M.ids);return}if(M.ch==="events"&&M.type==="nack"&&Array.isArray(M.ids)){Zm(M.ids,M.reason,M.permanent===!0,M.retryAfterMs??null);return}if(M.ch==="control"&&M.type==="http_open"){sL(M).catch(G=>bt({v:At,ch:"control",type:"http_end",reqId:M.reqId,error:G?.message||"tunnel error"}));return}if(M.ch==="control"&&M.type==="http_cancel"){Rc.get(M.reqId)?.abort();return}if(M.ch==="attach"&&M.type==="open"){let G=new J0(Ke+M.path,Array.isArray(M.protocols)?M.protocols:[],M.host?{headers:{host:M.host}}:void 0);re.set(M.streamId,G),Te.set(M.streamId,[]),G.on("open",()=>{let Ee=Te.get(M.streamId)||[];Te.delete(M.streamId);for(let{buf:Ae,bin:mt}of Ee)G.send(Ae,{binary:mt})}),G.on("message",(Ee,Ae)=>{let mt=Ae?Ee:Buffer.from(String(Ee));bt({v:At,ch:"attach",type:"data",streamId:M.streamId,data:mt.toString("base64"),...Ae?{bin:!0}:{}})});let ue=()=>{Te.delete(M.streamId),re.delete(M.streamId)&&bt({v:At,ch:"attach",type:"close",streamId:M.streamId})};G.on("close",ue),G.on("error",ue);return}if(M.ch==="attach"&&M.type==="data"){let G=re.get(M.streamId);if(!G)return;let ue=Buffer.from(M.data,"base64"),Ee=M.bin===!0,Ae=Te.get(M.streamId);Ae?Ae.push({buf:ue,bin:Ee}):G.send(ue,{binary:Ee});return}if(M.ch==="attach"&&M.type==="close"){let G=re.get(M.streamId);re.delete(M.streamId),Te.delete(M.streamId),G?.close();return}});let H=()=>{nt&&z.log("[plane-link] disconnected from plane"),nt=!1,k&&(clearInterval(k),k=null),R&&(clearInterval(R),R=null),ge.clear(),ee={},rn=[],ct&&(clearTimeout(ct),ct=null),Xn.clear();for(let G of re.values())G.close();re.clear(),Te.clear();for(let G of Rc.values())G.abort();if(Rc.clear(),ys||po)return;uo==null&&(uo=Date.now());let j=Date.now()-uo<B8,M=Math.max(j?L8+Math.random()*j8:bs,N-Date.now(),jc());po=setTimeout(()=>{po=null,JS()},M),po.unref?.(),j||(bs=Math.min(bs*2,jN))};Gt.on("close",H),Gt.on("error",j=>{let M=/Unexpected server response: (\d+)/.exec(j?.message||"")?.[1];if(M==="410"){ht({reason:"removed",via:"410"});return}if(M==="401"||M==="403"){let{tripped:G,holdMs:ue}=Fa();G?z.error(`[plane-link] holding every plane call for ${Math.round(ue/6e4)} min \u2014 three credential refusals in a row (HTTP ${M}) 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(ue/6e4)} min.`):Date.now()-fe>=HN&&(fe=Date.now(),z.error(`[plane-link] plane refused this node's credentials (HTTP ${M}) \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)`))}H()})}at.on("event",zS),Od().then(JS);function YS({bye:B=!0}={}){ys=!0,at.off("event",zS),po&&clearTimeout(po),Zn&&clearTimeout(Zn),k&&clearInterval(k),R&&clearInterval(R),ct&&clearTimeout(ct),B&&bt({v:At,ch:"ctl",type:"bye",reason:"shutdown"}),Gt?.close()}return{stop:()=>YS(),status:()=>({connected:nt,nodeId:n,cursor:{...ve},inflight:ge.size,...qS(),auth:xv(),dormant:Se,removed:qd(),deadLinkMs:I,deadLinkRedials:A,refused:{...pe}}),_tick:()=>{WS(),Qm()}}}As();var cm=(()=>{try{return eJ(import.meta.url)("../package.json").version||null}catch{return null}})(),tJ=process.env.BOSTRAT_STATE_DIR||Tt.join(process.env.HOME||X8.tmpdir(),".bostrat"),ex=Tt.join(tJ,"self-update"),lm=Tt.join(ex,"status.json"),nJ=1440*6e4,rJ=6e4,KN=60,VN=15,um=3,Q0=6,oJ=20,sJ=Tt.join(ex,"supervisor.pid"),aJ="SIGUSR2",Zu=new Set(["npm-global","git-checkout"]);function zN({kind:e=Aa(),env:t=process.env}={}){let n=String(t.BOSTRAT_UPDATE_POLICY||"").trim();return["auto","prompt","off"].includes(n)?n:Zu.has(e)?e==="git-checkout"||JN(t)?"auto":"prompt":"off"}function JN(e=process.env){return!!(e.INVOCATION_ID||e.XPC_SERVICE_NAME&&e.XPC_SERVICE_NAME!=="0")}function YN({env:e=process.env,platform:t=process.platform,uid:n=typeof process.getuid=="function"?process.getuid():0,serviceName:r=t==="darwin"?"com.bostrat.node":"bostrat-node.service",pidFile:o=sJ,readFile:s=i=>Xu.readFileSync(i,"utf8"),alive:a=iJ}={}){let i=t==="darwin"?{mode:"launchd",uid:n,serviceName:r}:{mode:"systemd",serviceName:r};if(JN(e))return i;let c=Number(e.BOSTRAT_RUN_SUPERVISOR_PID);if(!(Number.isInteger(c)&&c>0)){try{c=Number(String(s(o)).trim())}catch{c=NaN}Number.isInteger(c)&&c>0&&a(c)||(c=NaN)}return Number.isInteger(c)&&c>0?{mode:"supervisor",pid:c}:i}function iJ(e){try{process.kill(e,0)}catch{return!1}try{let t=Q8("ps",["-p",String(e),"-o","command="],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return/bostrat-node|\/cli\.js|node-cli\.js/.test(t)}catch{return!1}}function cJ(e){switch(e?.mode){case"systemd":return`systemctl --user restart ${An(e.serviceName||"bostrat-node.service")}`;case"launchd":return`launchctl kickstart -k gui/${Number(e.uid)||0}/${e.serviceName||"com.bostrat.node"}`;case"supervisor":return`kill -${aJ.replace(/^SIG/,"")} ${Number(e.pid)}`;default:throw new Error(`self-update: unknown restart strategy "${e?.mode}"`)}}var An=e=>`'${String(e).replace(/'/g,"'\\''")}'`;function lJ({kind:e,to:t,from:n=cm,statusFile:r=lm,logFile:o=Tt.join(ex,"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,restart:l=YN({env:{},platform:process.platform,uid:c,serviceName:i,readFile:()=>{throw new Error("no pidfile")}}),liveDir:u=process.env.BOSTRAT_LIVE_CHECKOUT||Tt.resolve(Tt.dirname(new URL(import.meta.url).pathname),"..",".."),startedAt:d=Date.now(),attempts:p=1}={}){if(!Zu.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 w=(b,x="")=>`write_status ${An(b)} ${x}`,m=cJ(l),h=`
|
|
838
838
|
health() {
|
|
839
839
|
for i in $(seq 1 45); do
|
|
840
840
|
sleep 1
|
|
@@ -857,7 +857,7 @@ write_status() { # <status> [error] [retryable]
|
|
|
857
857
|
"$1" "$FROM" "$TO" ${An(e)} "$ATTEMPTS" "$STARTED_AT" "$(date +%s000)" \\
|
|
858
858
|
"\${err:+,\\"error\\":\\"$err\\"}" "\${3:+,\\"retryable\\":true}" > "$STATUS_FILE.tmp" && mv "$STATUS_FILE.tmp" "$STATUS_FILE"
|
|
859
859
|
}
|
|
860
|
-
${
|
|
860
|
+
${h}
|
|
861
861
|
`;if(e==="npm-global"){let b=a?Tt.join(a,"bin","npm"):"npm",x=a?`export PATH=${An(Tt.join(a,"bin"))}:"$PATH"
|
|
862
862
|
`:"",v=a?` --prefix ${An(a)}`:"",S=L=>`${An(b)} install -g "bostrat-node@${L}" --no-audit --no-fund${v}`,E=`
|
|
863
863
|
install_target() {
|
|
@@ -918,33 +918,33 @@ if [ -n "$FROM" ] && ${y("$FROM")}; then
|
|
|
918
918
|
fi
|
|
919
919
|
${w("failed",'"deploy-pi.sh v$TO failed AND the rollback failed"')}
|
|
920
920
|
exit 1
|
|
921
|
-
`}async function lc(e=lm){try{return JSON.parse(await is.readFile(e,"utf8"))}catch{return null}}var uJ=new Set(["updating","restarting","rolling-back"]),Qu=e=>!!(e&&uJ.has(e.status));async function dm({to:e,from:t=cm,kind:n=Aa(),reason:r="manual",force:o=!1,statusFile:s=lm,spawnImpl:a=Z8,now:i=Date.now,npmPrefix:c=void 0,log:l=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!Zu.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!Yu(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let u=await lc(s);if(Qu(u))return{ok:!1,reason:`an update to ${u.to} is already in flight`,status:u};let d=u?.to===e?Number(u.attempts)||1:0;if(!o&&u&&u.to===e&&(u.status==="failed"||u.status==="rolled-back")&&!(u.status==="failed"&&u.retryable===!0&&d<um))return{ok:!1,reason:`update to ${e} already ${u.status} (${u.error||"no detail"}) \u2014 retried when a newer release exists, or tap Update now / Try again to retry it`,status:u};let p=u?.to===e&&(u.status==="failed"||u.status==="rolled-back")?d+1:1;await is.mkdir(Tt.dirname(s),{recursive:!0});let w=c!==void 0?c:n==="npm-global"?Ld(await dJ())||Tt.resolve(Tt.dirname(process.execPath),".."):null,m=YN(),f=lJ({kind:n,to:e,from:t,statusFile:s,npmPrefix:w,startedAt:i(),attempts:p,restart:m}),g=Tt.join(Tt.dirname(s),`update-${e}.sh`),y=Tt.join(Tt.dirname(s),"last.log");await is.writeFile(g,f,{mode:448}),await is.writeFile(s,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,attempts:p,startedAt:i(),updatedAt:i()}));let b=Xu.existsSync("/run/systemd/system")&&await pJ("systemd-run"),x=b?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",g]]:["bash",[g]],v=async E=>{let P=`could not spawn updater: ${E?.message||E}`;return await is.writeFile(s,JSON.stringify({status:"failed",from:t,to:e,kind:n,reason:r,attempts:p,startedAt:i(),updatedAt:i(),error:P})).catch(()=>{}),l.error?.(`[self-update] ${P}`),P},S=null;try{b||(S=Xu.openSync(y,"a"));let E=a(x[0],x[1],{detached:!0,stdio:b?"ignore":["ignore",S,S]});E.on?.("error",P=>{v(P)}),E.unref?.()}catch(E){return{ok:!1,reason:await v(E)}}finally{S!==null&&Xu.closeSync(S)}return l.log?.(`[self-update] ${t??"?"} \u2192 ${e} (${n}, ${r}, restart via ${m.mode}) started \u2014 status ${s}`),{ok:!0,to:e,from:t,kind:n,scriptFile:g,statusFile:s}}async function dJ(){try{return await is.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function pJ(e){for(let t of String(process.env.PATH||"").split(Tt.delimiter))try{return await is.access(Tt.join(t,e),Xu.constants.X_OK),!0}catch{}return!1}var fJ=45*6e4;async function XN({statusFile:e=lm,current:t=cm,now:n=Date.now,staleMs:r=fJ}={}){let o=await lc(e);if(!o)return null;let s=a=>is.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Qu(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 ZN({isBusy:e,start:t=dm,onStuck:n=null,onStarted:r=null,tickMs:o=rJ,stuckMs:s=nJ,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 w=!0;try{w=await e()!==!1}catch{w=!0}if(w){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 m=u;d();let f=await t({to:m.to,from:m.from,kind:m.kind,reason:"auto"});l.log?.(`[self-update] stasis reached \u2192 ${f.ok?"started":`not started: ${f.reason}`}`);try{await r?.({...m,result:f})}catch{}};return{arm({to:w,from:m=cm,kind:f=Aa()}){return u?.to===w?!1:(d(),u={to:w,from:m,kind:f,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}}}As();be();_t();var QN=(...e)=>fetch(...e);function eP(e=process.env){return!!(Ue(e)&&e.BOSTRAT_PLANE_TOKEN)}async function tx(e=process.env){if(!eP(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 QN(`${Ue(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 nx(e=process.env){if(!eP(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 QN(`${Ue(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 uc(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await tx(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 pm(e,t,{source:n="chat"}={}){return D(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();_t();var hJ=(...e)=>fetch(...e);async function fm(e,t,n,r=process.env){if(!(Ue(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 hJ(`${Ue(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 mJ(e,t=process.env){return fm("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function nP({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await mJ(t,o):await uc(e,o),a=await fm("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function rx(e,t=process.env){let n=await uc(e,t),r=await fm("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function ox(e,t=process.env){return(await fm("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function sx(e,t,n,r=process.env,{source:o="cli"}={}){let{blueprint:s,items:a}=await rx(t,r),i=new Map(a.map(l=>[l.itemId,l])),c=n.filter(l=>!i.get(l)?.bindable);if(c.length){let l=a.filter(u=>u.bindable).map(u=>u.itemId);throw new Error(`unknown/unbindable item(s): ${c.join(", ")} \u2014 bindable ids: ${l.join(", ")||"(none)"}`)}return await D(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:s.id,source:o}}),{blueprint:s,itemIds:n}}var rP=/^BP-[A-Z0-9]+(?:-[A-Z0-9]+)*$/i,tP=4e3;function oP({blueprintItems:e,kickoff:t,launchedFrom:n}={}){if(e==null&&t==null&&n==null)return null;let r=[...new Set((Array.isArray(e)?e:[]).map(i=>String(i).trim()).filter(Boolean))],o=r.filter(i=>!rP.test(i));if(o.length)throw new Error(`invalid blueprint item id(s): ${o.join(", ")}`);if(r.length>8)throw new Error("blueprintItems must be 8 ids or fewer");let s=typeof t?.text=="string"?t.text.trim():"";if(t!=null&&!s)throw new Error("kickoff.text (string) required");if(s.length>tP)throw new Error(`kickoff.text must be ${tP} chars or fewer`);let a=n&&typeof n=="object"?{trackId:n.trackId?String(n.trackId).slice(0,64):null,itemId:n.itemId?String(n.itemId).slice(0,64):null,via:n.via==="voice"?"voice":"chat"}:null;return{itemIds:r,kickoff:s||null,launchedFrom:a}}async function sP(e,{itemId:t,trackId:n,trackName:r=null,provider:o=null,node:s=null,via:a="chat"}={}){let i=String(t||"").trim();if(!rP.test(i))throw new Error("itemId (BP-\u2026 id) required");if(!n)throw new Error("trackId (the launched Track) required");let c={itemId:i.toUpperCase(),trackId:String(n).slice(0,64),trackName:r?String(r).slice(0,120):null,provider:o?String(o).slice(0,32):null,node:s?String(s).slice(0,64):null,via:a==="voice"?"voice":"chat"};return await D(e,{type:"blueprint.item.launched",actor:"orchestrator",source:"orchestrator",payload:c}),c}be();_t();var wJ=(...e)=>fetch(...e);async function gJ(e,t,n,r=process.env){if(!(Ue(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 wJ(`${Ue(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 aP=72,ax=160;async function iP(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>aP)throw new Error(`the title is the choice as a LABEL \u2014 ${aP} 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 ${ax} chars) a reader can act on without opening the record`);if(c.length>ax)throw new Error(`the summary is one sentence \u2014 ${ax} 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 D(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 cP(e,t=process.env){return gJ("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}xk();be();import ad from"node:fs/promises";import vm from"node:path";import fY from"node:os";rr();import yJ from"node:fs/promises";import lP from"node:path";import bJ from"node:os";var uP=()=>lP.join(process.env.BOSTRAT_STATE_DIR||lP.join(process.env.HOME||bJ.tmpdir(),".bostrat"),"integrations.json");async function ao(){try{return JSON.parse(await yJ.readFile(uP(),"utf8"))||{}}catch{return{}}}var hm=["linked","prOpened","prMerged","create"],ix=["prompt","auto","off"],kJ={create:["prompt","off"]},dP=e=>kJ[e]??ix;function mm(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of hm){let s=dP(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 Ta(){let e=await ao(),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:mm(e),defaultTeam:n}:null}async function wm(){let e=await ao(),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:mm(e)}}async function cx(){return mm(await ao())}async function pP(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${hm.join(", ")}`);for(let[r,o]of t){if(!hm.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${hm.join(", ")}`);let s=dP(r);if(!s.includes(o))throw new Error(s.length<ix.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${ix.join(", ")}`)}let n=await ao();return n.ticketFlow={...mm(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await dt(uP(),n,{mode:384}),n.ticketFlow}async function ed(){let e=(await ao()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function xJ(){let e=(await ao()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var SJ={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function gm(){let t=(await ao()).voiceChat||{},n=t.provider||"openai",r=SJ[n];if(!r)return null;let o=n==="openai"?await xJ():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function fP(){let e=(await ao()).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 Ea(){let e=(await ao()).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();bo();Bo();Wi();import nd from"node:fs/promises";import OP from"node:path";import YJ from"node:os";import{randomUUID as MP}from"node:crypto";var ux={};nw(ux,{createComment:()=>OJ,findIssueUrl:()=>EJ,issueStates:()=>NJ,mdToAdf:()=>wP,moveIssue:()=>PJ,parseIssueRef:()=>TJ,resolveIssue:()=>_J,uploadImage:()=>MJ,upsertCard:()=>IJ,whoami:()=>lx});var dc=e=>String(e.baseUrl||"").replace(/\/$/,""),mP=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function _a(e,t,n,r){let o=await fetch(`${dc(e)}${n}`,{method:t,headers:{authorization:mP(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 vJ=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,AJ=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function TJ(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(vJ);return r?r[1].toUpperCase():null}let n=t.match(AJ);return n?n[1]:null}function EJ(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 _J(e,t){let n;try{n=await _a(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:`${dc(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function IJ(e,t,{url:n,title:r,subtitle:o}){await _a(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 $J=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function RJ(e){let t=[],n=0;for(let r of e.matchAll($J)){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 wP(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
|
|
921
|
+
`}async function lc(e=lm){try{return JSON.parse(await is.readFile(e,"utf8"))}catch{return null}}var uJ=new Set(["updating","restarting","rolling-back"]),Qu=e=>!!(e&&uJ.has(e.status));async function dm({to:e,from:t=cm,kind:n=Aa(),reason:r="manual",force:o=!1,statusFile:s=lm,spawnImpl:a=Z8,now:i=Date.now,npmPrefix:c=void 0,log:l=console}={}){if(!e)return{ok:!1,reason:"no target version"};if(!Zu.has(n))return{ok:!1,reason:`install kind "${n}" updates elsewhere`};if(t&&!Yu(t,e))return{ok:!1,reason:`already on ${t} (target ${e})`};let u=await lc(s);if(Qu(u))return{ok:!1,reason:`an update to ${u.to} is already in flight`,status:u};let d=u?.to===e?Number(u.attempts)||1:0;if(!o&&u&&u.to===e&&(u.status==="failed"||u.status==="rolled-back")&&!(u.status==="failed"&&u.retryable===!0&&d<um))return{ok:!1,reason:`update to ${e} already ${u.status} (${u.error||"no detail"}) \u2014 retried when a newer release exists, or tap Update now / Try again to retry it`,status:u};let p=u?.to===e&&(u.status==="failed"||u.status==="rolled-back")?d+1:1;await is.mkdir(Tt.dirname(s),{recursive:!0});let w=c!==void 0?c:n==="npm-global"?Ld(await dJ())||Tt.resolve(Tt.dirname(process.execPath),".."):null,m=YN(),h=lJ({kind:n,to:e,from:t,statusFile:s,npmPrefix:w,startedAt:i(),attempts:p,restart:m}),g=Tt.join(Tt.dirname(s),`update-${e}.sh`),y=Tt.join(Tt.dirname(s),"last.log");await is.writeFile(g,h,{mode:448}),await is.writeFile(s,JSON.stringify({status:"updating",from:t,to:e,kind:n,reason:r,attempts:p,startedAt:i(),updatedAt:i()}));let b=Xu.existsSync("/run/systemd/system")&&await pJ("systemd-run"),x=b?["systemd-run",["--user","--collect","--quiet",`--unit=bostrat-self-update-${e}`,"--property=KillMode=process","bash",g]]:["bash",[g]],v=async E=>{let P=`could not spawn updater: ${E?.message||E}`;return await is.writeFile(s,JSON.stringify({status:"failed",from:t,to:e,kind:n,reason:r,attempts:p,startedAt:i(),updatedAt:i(),error:P})).catch(()=>{}),l.error?.(`[self-update] ${P}`),P},S=null;try{b||(S=Xu.openSync(y,"a"));let E=a(x[0],x[1],{detached:!0,stdio:b?"ignore":["ignore",S,S]});E.on?.("error",P=>{v(P)}),E.unref?.()}catch(E){return{ok:!1,reason:await v(E)}}finally{S!==null&&Xu.closeSync(S)}return l.log?.(`[self-update] ${t??"?"} \u2192 ${e} (${n}, ${r}, restart via ${m.mode}) started \u2014 status ${s}`),{ok:!0,to:e,from:t,kind:n,scriptFile:g,statusFile:s}}async function dJ(){try{return await is.realpath(new URL(import.meta.url).pathname)}catch{return""}}async function pJ(e){for(let t of String(process.env.PATH||"").split(Tt.delimiter))try{return await is.access(Tt.join(t,e),Xu.constants.X_OK),!0}catch{}return!1}var fJ=45*6e4;async function XN({statusFile:e=lm,current:t=cm,now:n=Date.now,staleMs:r=fJ}={}){let o=await lc(e);if(!o)return null;let s=a=>is.writeFile(e,JSON.stringify(a)).catch(()=>{});if(Qu(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 ZN({isBusy:e,start:t=dm,onStuck:n=null,onStarted:r=null,tickMs:o=rJ,stuckMs:s=nJ,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 w=!0;try{w=await e()!==!1}catch{w=!0}if(w){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 m=u;d();let h=await t({to:m.to,from:m.from,kind:m.kind,reason:"auto"});l.log?.(`[self-update] stasis reached \u2192 ${h.ok?"started":`not started: ${h.reason}`}`);try{await r?.({...m,result:h})}catch{}};return{arm({to:w,from:m=cm,kind:h=Aa()}){return u?.to===w?!1:(d(),u={to:w,from:m,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}}}As();be();_t();var QN=(...e)=>fetch(...e);function eP(e=process.env){return!!(Ue(e)&&e.BOSTRAT_PLANE_TOKEN)}async function tx(e=process.env){if(!eP(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 QN(`${Ue(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 nx(e=process.env){if(!eP(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 QN(`${Ue(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 uc(e,t=process.env){let n=String(e??"").trim();if(!n)throw new Error("a circuit name or id is required");let r=await tx(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 pm(e,t,{source:n="chat"}={}){return D(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();_t();var hJ=(...e)=>fetch(...e);async function fm(e,t,n,r=process.env){if(!(Ue(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 hJ(`${Ue(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 mJ(e,t=process.env){return fm("POST","/v1/circuits",{name:e},t).then(n=>n.circuit)}async function nP({circuitRef:e,newCircuitName:t,name:n,markdown:r},o=process.env){let s=t?await mJ(t,o):await uc(e,o),a=await fm("POST","/v1/blueprints",{circuitId:s.id,name:n,markdown:r},o);return{circuit:s,...a}}async function rx(e,t=process.env){let n=await uc(e,t),r=await fm("GET",`/v1/blueprints/${encodeURIComponent(n.id)}`,null,t);return{circuit:n,...r}}async function ox(e,t=process.env){return(await fm("GET","/v1/circuits",null,t)).memberships?.[e]??null}async function sx(e,t,n,r=process.env,{source:o="cli"}={}){let{blueprint:s,items:a}=await rx(t,r),i=new Map(a.map(l=>[l.itemId,l])),c=n.filter(l=>!i.get(l)?.bindable);if(c.length){let l=a.filter(u=>u.bindable).map(u=>u.itemId);throw new Error(`unknown/unbindable item(s): ${c.join(", ")} \u2014 bindable ids: ${l.join(", ")||"(none)"}`)}return await D(e,{type:"blueprint.item.bound",actor:"orchestrator",source:"orchestrator",payload:{itemIds:n,blueprintId:s.id,source:o}}),{blueprint:s,itemIds:n}}var rP=/^BP-[A-Z0-9]+(?:-[A-Z0-9]+)*$/i,tP=4e3;function oP({blueprintItems:e,kickoff:t,launchedFrom:n}={}){if(e==null&&t==null&&n==null)return null;let r=[...new Set((Array.isArray(e)?e:[]).map(i=>String(i).trim()).filter(Boolean))],o=r.filter(i=>!rP.test(i));if(o.length)throw new Error(`invalid blueprint item id(s): ${o.join(", ")}`);if(r.length>8)throw new Error("blueprintItems must be 8 ids or fewer");let s=typeof t?.text=="string"?t.text.trim():"";if(t!=null&&!s)throw new Error("kickoff.text (string) required");if(s.length>tP)throw new Error(`kickoff.text must be ${tP} chars or fewer`);let a=n&&typeof n=="object"?{trackId:n.trackId?String(n.trackId).slice(0,64):null,itemId:n.itemId?String(n.itemId).slice(0,64):null,via:n.via==="voice"?"voice":"chat"}:null;return{itemIds:r,kickoff:s||null,launchedFrom:a}}async function sP(e,{itemId:t,trackId:n,trackName:r=null,provider:o=null,node:s=null,via:a="chat"}={}){let i=String(t||"").trim();if(!rP.test(i))throw new Error("itemId (BP-\u2026 id) required");if(!n)throw new Error("trackId (the launched Track) required");let c={itemId:i.toUpperCase(),trackId:String(n).slice(0,64),trackName:r?String(r).slice(0,120):null,provider:o?String(o).slice(0,32):null,node:s?String(s).slice(0,64):null,via:a==="voice"?"voice":"chat"};return await D(e,{type:"blueprint.item.launched",actor:"orchestrator",source:"orchestrator",payload:c}),c}be();_t();var wJ=(...e)=>fetch(...e);async function gJ(e,t,n,r=process.env){if(!(Ue(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 wJ(`${Ue(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 aP=72,ax=160;async function iP(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>aP)throw new Error(`the title is the choice as a LABEL \u2014 ${aP} 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 ${ax} chars) a reader can act on without opening the record`);if(c.length>ax)throw new Error(`the summary is one sentence \u2014 ${ax} 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 D(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 cP(e,t=process.env){return gJ("GET",`/v1/decisions?track=${encodeURIComponent(e)}`,null,t)}xk();be();import ad from"node:fs/promises";import vm from"node:path";import fY from"node:os";rr();import yJ from"node:fs/promises";import lP from"node:path";import bJ from"node:os";var uP=()=>lP.join(process.env.BOSTRAT_STATE_DIR||lP.join(process.env.HOME||bJ.tmpdir(),".bostrat"),"integrations.json");async function ao(){try{return JSON.parse(await yJ.readFile(uP(),"utf8"))||{}}catch{return{}}}var hm=["linked","prOpened","prMerged","create"],ix=["prompt","auto","off"],kJ={create:["prompt","off"]},dP=e=>kJ[e]??ix;function mm(e){let t=e.linear||{},n=t.transitions===!0?"auto":"prompt",r={};for(let o of hm){let s=dP(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 Ta(){let e=await ao(),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:mm(e),defaultTeam:n}:null}async function wm(){let e=await ao(),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:mm(e)}}async function cx(){return mm(await ao())}async function pP(e){let t=Object.entries(e||{});if(!t.length)throw new Error(`nothing to set \u2014 phases: ${hm.join(", ")}`);for(let[r,o]of t){if(!hm.includes(r))throw new Error(`unknown phase "${r}" \u2014 configurable phases: ${hm.join(", ")}`);let s=dP(r);if(!s.includes(o))throw new Error(s.length<ix.length?`mode "${o}" not allowed for "${r}" \u2014 ${r} is always confirmed (modes: ${s.join(", ")})`:`unknown mode "${o}" \u2014 modes: ${ix.join(", ")}`)}let n=await ao();return n.ticketFlow={...mm(n),...Object.fromEntries(t)},n.linear&&(delete n.linear.ticketFlow,delete n.linear.transitions),await dt(uP(),n,{mode:384}),n.ticketFlow}async function ed(){let e=(await ao()).deepgram||{},t=process.env.DEEPGRAM_API_KEY||e.apiKey;return t?{apiKey:t}:null}async function xJ(){let e=(await ao()).openai||{},t=process.env.BOSTRAT_OPENAI_API_KEY||e.apiKey;return t?{apiKey:t}:null}var SJ={openai:{model:"gpt-realtime-2.1-mini",voice:"marin"}};async function gm(){let t=(await ao()).voiceChat||{},n=t.provider||"openai",r=SJ[n];if(!r)return null;let o=n==="openai"?await xJ():null;return o?{provider:n,model:t.model||r.model,voice:t.voice||r.voice,apiKey:o.apiKey}:null}async function fP(){let e=(await ao()).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 Ea(){let e=(await ao()).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();bo();Bo();Wi();import nd from"node:fs/promises";import OP from"node:path";import YJ from"node:os";import{randomUUID as MP}from"node:crypto";var ux={};nw(ux,{createComment:()=>OJ,findIssueUrl:()=>EJ,issueStates:()=>NJ,mdToAdf:()=>wP,moveIssue:()=>PJ,parseIssueRef:()=>TJ,resolveIssue:()=>_J,uploadImage:()=>MJ,upsertCard:()=>IJ,whoami:()=>lx});var dc=e=>String(e.baseUrl||"").replace(/\/$/,""),mP=e=>`Basic ${Buffer.from(`${e.email}:${e.apiToken}`).toString("base64")}`;async function _a(e,t,n,r){let o=await fetch(`${dc(e)}${n}`,{method:t,headers:{authorization:mP(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 vJ=/\/browse\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,AJ=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function TJ(e){let t=String(e||"").trim();if(/^https?:\/\//i.test(t)){let r=t.match(vJ);return r?r[1].toUpperCase():null}let n=t.match(AJ);return n?n[1]:null}function EJ(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 _J(e,t){let n;try{n=await _a(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:`${dc(e)}/browse/${n.key}`,state:n.fields?.status?.name??null}}async function IJ(e,t,{url:n,title:r,subtitle:o}){await _a(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 $J=/(!\[[^\]]*\]\([^)\s]+\)|\*\*[^*\n]+\*\*|`[^`\n]+`|_[^_\n]+_|https?:\/\/[^\s)]+)/g;function RJ(e){let t=[],n=0;for(let r of e.matchAll($J)){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 wP(e){let t=String(e??"").split(/\n{2,}/).map(n=>n.trim()).filter(Boolean).map(n=>{let r=[];return n.split(`
|
|
922
922
|
`).forEach((o,s)=>{s>0&&r.push({type:"hardBreak"}),r.push(...RJ(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 OJ(e,t,n){let r=await _a(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/comment`,{body:wP(n)});return r?.id?`${dc(e)}/browse/${t.key}?focusedCommentId=${r.id}`:null}async function lx(e){let t=await _a(e,"GET","/rest/api/3/myself"),n=null;try{n=new URL(dc(e)).host}catch{n=e.baseUrl??null}return{user:t?.displayName??t?.emailAddress??null,org:n}}async function MJ(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(`${dc(e)}/rest/api/3/issue/${encodeURIComponent(t)}/attachments`,{method:"POST",headers:{authorization:mP(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??`${dc(e)}/rest/api/3/attachment/content/${c.id}`}var CJ={new:"unstarted",indeterminate:"started",done:"completed"},hP=e=>CJ[e?.key]??"started";async function NJ(e,t){let n=encodeURIComponent(t.key),[r,o]=await Promise.all([_a(e,"GET",`/rest/api/3/issue/${n}?fields=status`),_a(e,"GET",`/rest/api/3/issue/${n}/transitions`)]),s=r?.fields?.status??null,a=s?{id:`status:${s.id}`,name:s.name,type:hP(s.statusCategory)}:null,i=(o?.transitions??[]).map((c,l)=>({id:c.id,name:c.to?.name??c.name,type:hP(c.to?.statusCategory),position:l}));return{current:a,states:i}}async function PJ(e,t,n){await _a(e,"POST",`/rest/api/3/issue/${encodeURIComponent(t.key)}/transitions`,{transition:{id:String(n)}})}var hx={};nw(hx,{createComment:()=>WJ,createIssue:()=>fx,createProject:()=>px,findIssueUrl:()=>FJ,issueStates:()=>GJ,moveIssue:()=>KJ,parseIssueRef:()=>jJ,resolveIssue:()=>UJ,teams:()=>pc,uploadImage:()=>qJ,upsertCard:()=>HJ,whoami:()=>dx});var DJ=()=>process.env.BOSTRAT_LINEAR_API_URL||"https://api.linear.app/graphql";async function Ar(e,t,n={}){let r=await fetch(DJ(),{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 BJ=/linear\.app\/[^/\s]+\/issue\/([A-Za-z][A-Za-z0-9]{0,9}-\d+)/,LJ=/^([A-Z][A-Z0-9]{0,9}-\d+)$/;function jJ(e){let t=String(e||"").trim(),n=t.match(BJ);if(n)return n[1].toUpperCase();let r=t.match(LJ);return r?r[1]:null}function FJ(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 UJ(e,t){let r=(await Ar(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 HJ(e,t,{url:n,title:r,subtitle:o}){let s=await Ar(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 WJ(e,t,n){let r=await Ar(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 dx(e){let t=await Ar(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 qJ(e,{filename:t,contentType:n,buffer:r}){let o=await Ar(e,`mutation($contentType: String!, $filename: String!, $size: Int!) {
|
|
923
923
|
fileUpload(contentType: $contentType, filename: $filename, size: $size) {
|
|
924
924
|
success
|
|
925
925
|
uploadFile { uploadUrl assetUrl headers { key value } }
|
|
926
926
|
}
|
|
927
927
|
}`,{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 GJ(e,t){let n=await Ar(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 KJ(e,t,n){if(!(await Ar(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 pc(e){return((await Ar(e,"query { teams(first: 100) { nodes { id key name } } }")).teams?.nodes??[]).map(n=>({id:n.id,key:n.key,name:n.name}))}var gP=255;async function px(e,{teamId:t,name:n,description:r}){let o=r||null,s=!!o&&o.length>gP,a=s?`${o.slice(0,gP-1).trimEnd()}\u2026`:o,i=await Ar(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 fx(e,{teamId:t,title:n,description:r,projectId:o,priority:s}){let a=await Ar(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}}iu();import ym from"node:fs";import mx from"node:path";import VJ from"node:os";var zJ=()=>process.env.BOSTRAT_STATE_DIR||mx.join(process.env.HOME||VJ.tmpdir(),".bostrat"),yP=()=>mx.join(zJ(),"plane-link","public-host.json"),bP="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",fc=null;function kP(){if(fc)return fc;try{let e=JSON.parse(ym.readFileSync(yP(),"utf8"));fc={viewBase:typeof e?.viewBase=="string"&&e.viewBase?e.viewBase:null}}catch{fc={viewBase:null}}return fc}function xP(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 SP(e){let t=typeof e=="string"&&e.trim()?xP(e,"https").host:null;if(kP().viewBase===t)return;fc={viewBase:t};let r=yP();try{t?(ym.mkdirSync(mx.dirname(r),{recursive:!0}),ym.writeFileSync(r,JSON.stringify({viewBase:t,learnedAt:new Date().toISOString()})+`
|
|
928
|
-
`)):ym.rmSync(r,{force:!0})}catch{}}function wx(){return kP().viewBase}function gx(e=process.env.BOSTRAT_PUBLIC_HOST){return xP(e,"https")}function vP(){let e=wx();if(e)return{proto:"https",host:e,source:"learned"};let t=gx();return t?{...t,source:"env"}:null}function bm(e,t){return e?`${e.proto}://${t}.${e.host}/`:null}function JJ(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 AP(){let e=String(process.env.BOSTRAT_PUBLIC_URL||"").trim().replace(/\/+$/,"");if(e)return{url:e,source:"env"};let t=JJ();return t?{url:t,source:"plane"}:null}var TP="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 CP={linear:{api:hx,config:Ta},jira:{api:ux,config:wm}};async function Ax(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(CP)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function Ia(e){let t=CP[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function Tx(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 NP=()=>process.env.BOSTRAT_STATE_DIR||OP.join(process.env.HOME||YJ.tmpdir(),".bostrat"),xx=()=>OP.join(NP(),"tickets.json"),od=e=>{let t=AP();if(!t)throw new Error(TP);return`${t.url}/track/${e}`},XJ=e=>`http://bostrat.globopi/track/${e}`,EP=e=>{let t=0;for(let[n,r]of Object.entries(e))r&&typeof r=="object"&&!r.cardUrl&&(r.cardUrl=XJ(n),t++);return t},Tr=null,yx=null,bx=Promise.resolve();async function sd(){return Tr||(yx??=nd.readFile(xx(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{Tr=e;let n=EP(Tr)>0;if(!t&&et()){let{records:r,source:o}=await xt("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;Tr[a]=c}EP(Tr),n=n||Object.keys(Tr).length>0}}return n&&await Sx().catch(()=>{}),Tr}).finally(()=>yx=null),yx)}async function Sx(){let e=JSON.stringify({tickets:Tr},null,2),t=`${xx()}.${process.pid}.tmp`;await nd.mkdir(NP(),{recursive:!0}),await nd.writeFile(t,e),await nd.rename(t,xx())}async function cs(e=null){if(bx=bx.then(Sx,Sx),await bx.catch(()=>{}),!e)return;let t=Tr?.[e];t?Pt("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):Rn("tickets",e).catch(()=>{})}async function Er(e){return(await sd())[e]??null}async function PP(){return{...await sd()}}async function DP(){return(await Ax()).length>0}async function hc(e,t,{source:n="api"}={}){let r=await Ax();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:od(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 sd())[e.id]=c,await cs(e.id),await D({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 rd(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 td(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await jP(e.id,c,"linked"),c}async function Ex(e){let t=await sd();return t[e]?(delete t[e],await cs(e),!0):!1}var vx=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function BP(e,t){if(!e.track?.cwd)return null;let n=Do(await V({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function ZJ(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${vx(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${vx(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function QJ(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(vx(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function rd(e,t){let n=await Ia(t);if(!n)return;let r=await BP(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:t.cardUrl??od(e),title:`Bostrat Track: ${t.track.name}`,subtitle:QJ(t,r)})}function eY(e){return bm(vP(),e)}var km=e=>eY(e)??"(no public URL on this node \u2014 link it to a plane)",tY={linked:"linked",opened:"prOpened",merged:"prMerged"};function nY(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 LP(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await cs(e),await D({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 jP(e,t,n){let r=await Ia(t);if(!r)return;let o=r.cfg.ticketFlow?.[tY[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Tx(s,a),c=nY(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 LP(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await D({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:MP(),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 FP(e){let t=await Er(e);if(!t)throw new Error("no ticket linked to this Track");let n=await Ia(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=Tx(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await cs(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 _x(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await Er(e);if(!r)throw new Error("no ticket linked to this Track");let o=await Ia(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Tx(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 cs(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await LP(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function UP(e,t){let n=await Er(e);if(!n)throw new Error("no ticket linked to this Track");let r=await Ia(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 D({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 HP(e,t,n){if(!t)throw new Error("offerId required");return Jo(`tkt:${e.id}:${t}`,()=>rY(e,t,n))}async function rY(e,t,n){let r=await V({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 _x(e.id,o.payload.to?.id,{mode:"offer"})),await D({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 _P=50;async function WP(){let e=await Ta();if(!e)throw new Error("no ticketing integration configured");return pc(e)}function oY(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>_P)throw new Error(`too many issues (${n.length}); cap is ${_P} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function sY(e,t,n,r){let o=r??await pc(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 Er(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 qP(e,t){let n=await Ta();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=oY(t),o=await pc(n),s=await sY(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=MP();return await D({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 GP(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await V({id:e.id,cwd:e.cwd}),s=o.find(m=>m.type==="ticket.create.offered"&&m.payload?.proposalId===t);if(!s)throw new Error("unknown proposal");if(o.some(m=>m.type==="ticket.create.answered"&&m.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await D({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 Ta();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let m=(await pc(a)).find(f=>f.id===r);if(!m)throw new Error("unknown team");c={id:m.id,key:m.key,name:m.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],d=null;if(i.epic){let m=await px(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});d=m.id,l.push({kind:"epic",title:m.name,url:m.url})}for(let m of i.issues||[])try{let f=await fx(a,{teamId:c.id,title:m.title,description:m.description,projectId:d,priority:m.priority});l.push({kind:"issue",key:f.key,title:f.title,url:f.url})}catch(f){u.push({title:m.title,message:f?.message||String(f)})}await D({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 D({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(m=>m.kind==="issue"),w=null;return i.linkCurrentTrack&&p.length===1&&!await Er(e.id)&&(w=await hc(e,p[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:w?w.key:null}}async function td(e,t){let n=await Ia(e);n&&await n.api.createComment(n.cfg,e,t)}async function aY(e,t,n){let r=await Ia(e);if(!r)return null;let o=await Xr(t);if(!o)return null;let s=Wn(o,n);if(!s)return null;let a=await nd.readFile(vn(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 IP=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),kx=new Map;function iY(e,t){if(IP()<=0)return rd(e,t);if(kx.has(e))return;let n=setTimeout(()=>{kx.delete(e),Er(e).then(r=>r?rd(e,r):null).catch(()=>{})},IP());n.unref?.(),kx.set(e,n)}var $P=new Map;async function RP(e,t,n){let r=$P.get(e)??0;Date.now()-r<600*1e3||($P.set(e,Date.now()),await D({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function cY(e,{resolveTrack:t=null}={}){let n=await Er(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Ax())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 hc(s,o,{source:"chat"})}catch(a){await RP(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 cs(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await cs(e.trackId),await rd(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 cs(e.trackId),await rd(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await BP(n,e.trackId).catch(()=>null):null;await td(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
|
|
928
|
+
`)):ym.rmSync(r,{force:!0})}catch{}}function wx(){return kP().viewBase}function gx(e=process.env.BOSTRAT_PUBLIC_HOST){return xP(e,"https")}function vP(){let e=wx();if(e)return{proto:"https",host:e,source:"learned"};let t=gx();return t?{...t,source:"env"}:null}function bm(e,t){return e?`${e.proto}://${t}.${e.host}/`:null}function JJ(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 AP(){let e=String(process.env.BOSTRAT_PUBLIC_URL||"").trim().replace(/\/+$/,"");if(e)return{url:e,source:"env"};let t=JJ();return t?{url:t,source:"plane"}:null}var TP="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 CP={linear:{api:hx,config:Ta},jira:{api:ux,config:wm}};async function Ax(){let e=[];for(let[t,{api:n,config:r}]of Object.entries(CP)){let o=await r();o&&e.push({name:t,api:n,cfg:o})}return e}async function Ia(e){let t=CP[e?.provider];if(!t)return null;let n=await t.config();return n?{name:e.provider,api:t.api,cfg:n}:null}function Tx(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 NP=()=>process.env.BOSTRAT_STATE_DIR||OP.join(process.env.HOME||YJ.tmpdir(),".bostrat"),xx=()=>OP.join(NP(),"tickets.json"),od=e=>{let t=AP();if(!t)throw new Error(TP);return`${t.url}/track/${e}`},XJ=e=>`http://bostrat.globopi/track/${e}`,EP=e=>{let t=0;for(let[n,r]of Object.entries(e))r&&typeof r=="object"&&!r.cardUrl&&(r.cardUrl=XJ(n),t++);return t},Tr=null,yx=null,bx=Promise.resolve();async function sd(){return Tr||(yx??=nd.readFile(xx(),"utf8").then(e=>({tickets:JSON.parse(e)?.tickets??{},existed:!0})).catch(()=>({tickets:{},existed:!1})).then(async({tickets:e,existed:t})=>{Tr=e;let n=EP(Tr)>0;if(!t&&et()){let{records:r,source:o}=await xt("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;Tr[a]=c}EP(Tr),n=n||Object.keys(Tr).length>0}}return n&&await Sx().catch(()=>{}),Tr}).finally(()=>yx=null),yx)}async function Sx(){let e=JSON.stringify({tickets:Tr},null,2),t=`${xx()}.${process.pid}.tmp`;await nd.mkdir(NP(),{recursive:!0}),await nd.writeFile(t,e),await nd.rename(t,xx())}async function cs(e=null){if(bx=bx.then(Sx,Sx),await bx.catch(()=>{}),!e)return;let t=Tr?.[e];t?Pt("tickets",{id:e,updatedAt:Date.now(),...t},{trackId:e}).catch(()=>{}):Rn("tickets",e).catch(()=>{})}async function Er(e){return(await sd())[e]??null}async function PP(){return{...await sd()}}async function DP(){return(await Ax()).length>0}async function hc(e,t,{source:n="api"}={}){let r=await Ax();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:od(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 sd())[e.id]=c,await cs(e.id),await D({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 rd(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 td(c,`**Bostrat** \u2014 Track **${c.track.name}** linked${l.length?` (${l.join(", ")})`:""}.`),await jP(e.id,c,"linked"),c}async function Ex(e){let t=await sd();return t[e]?(delete t[e],await cs(e),!0):!1}var vx=e=>`$${e>=100?Math.round(e):e.toFixed(2)}`;async function BP(e,t){if(!e.track?.cwd)return null;let n=Do(await V({id:t,cwd:e.track.cwd}));return!n.totalUsd||n.totalUsd<.01?null:n}function ZJ(e){let t=Object.entries(e.byProvider).sort((r,o)=>o[1].usd-r[1].usd).map(([r,o])=>`${r} ${vx(o.usd)}`).join(" \xB7 "),n=Object.keys(e.byBox).length;return`${vx(e.totalUsd)}${t?` (${t})`:""}${n>1?` across ${n} boxes`:""}`}function QJ(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(vx(t.totalUsd)),n.join(" \xB7 ")||"linked"}async function rd(e,t){let n=await Ia(t);if(!n)return;let r=await BP(t,e).catch(()=>null);await n.api.upsertCard(n.cfg,t,{url:t.cardUrl??od(e),title:`Bostrat Track: ${t.track.name}`,subtitle:QJ(t,r)})}function eY(e){return bm(vP(),e)}var km=e=>eY(e)??"(no public URL on this node \u2014 link it to a plane)",tY={linked:"linked",opened:"prOpened",merged:"prMerged"};function nY(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 LP(e,t,{from:n,to:r,mode:o,phase:s=null,actor:a="user"}){t.state=r,await cs(e),await D({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 jP(e,t,n){let r=await Ia(t);if(!r)return;let o=r.cfg.ticketFlow?.[tY[n]]??"prompt";if(o==="off")return;let{current:s,states:a}=await r.api.issueStates(r.cfg,t),i=Tx(s,a),c=nY(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 LP(e,t,{from:l,to:c.name,mode:"auto",phase:n,actor:"system"});return}await D({id:e,cwd:t.track?.cwd},{type:"ticket.move.offered",actor:"system",source:"orchestrator",payload:{ts:Date.now(),offerId:MP(),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 FP(e){let t=await Er(e);if(!t)throw new Error("no ticket linked to this Track");let n=await Ia(t);if(!n)throw new Error("no ticketing integration configured");let{current:r,states:o}=await n.api.issueStates(n.cfg,t),s=Tx(r,o);return s?.name&&t.state!==s.name&&(t.state=s.name,await cs(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 _x(e,t,{mode:n="manual"}={}){if(!t)throw new Error("stateId required");let r=await Er(e);if(!r)throw new Error("no ticket linked to this Track");let o=await Ia(r);if(!o)throw new Error("no ticketing integration configured");let{current:s,states:a}=await o.api.issueStates(o.cfg,r),i=Tx(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 cs(e)),{key:r.key,from:l,to:c.name,moved:!1}):(await o.api.moveIssue(o.cfg,r,c.id),await LP(e,r,{from:l,to:c.name,mode:n}),{key:r.key,from:l,to:c.name,moved:!0})}async function UP(e,t){let n=await Er(e);if(!n)throw new Error("no ticket linked to this Track");let r=await Ia(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 D({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 HP(e,t,n){if(!t)throw new Error("offerId required");return Jo(`tkt:${e.id}:${t}`,()=>rY(e,t,n))}async function rY(e,t,n){let r=await V({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 _x(e.id,o.payload.to?.id,{mode:"offer"})),await D({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 _P=50;async function WP(){let e=await Ta();if(!e)throw new Error("no ticketing integration configured");return pc(e)}function oY(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>_P)throw new Error(`too many issues (${n.length}); cap is ${_P} per proposal`);return{epic:r,issues:n,team:t.team?String(t.team).trim():null,linkCurrentTrack:t.linkCurrentTrack===!0}}async function sY(e,t,n,r){let o=r??await pc(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 Er(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 qP(e,t){let n=await Ta();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=oY(t),o=await pc(n),s=await sY(n,r,e,o),a=s?{id:s.id,key:s.key,name:s.name}:null,i=MP();return await D({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 GP(e,t,n,{teamId:r=null}={}){if(!t)throw new Error("proposalId required");let o=await V({id:e.id,cwd:e.cwd}),s=o.find(m=>m.type==="ticket.create.offered"&&m.payload?.proposalId===t);if(!s)throw new Error("unknown proposal");if(o.some(m=>m.type==="ticket.create.answered"&&m.payload?.proposalId===t))throw new Error("proposal already answered");if(!n)return await D({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 Ta();if(!a)throw new Error("no ticketing integration configured");let i=s.payload,c=i.team??null;if(!c&&r){let m=(await pc(a)).find(h=>h.id===r);if(!m)throw new Error("unknown team");c={id:m.id,key:m.key,name:m.name}}if(!c)throw new Error("a team is required to create \u2014 pick one");let l=[],u=[],d=null;if(i.epic){let m=await px(a,{teamId:c.id,name:i.epic.name,description:i.epic.description});d=m.id,l.push({kind:"epic",title:m.name,url:m.url})}for(let m of i.issues||[])try{let h=await fx(a,{teamId:c.id,title:m.title,description:m.description,projectId:d,priority:m.priority});l.push({kind:"issue",key:h.key,title:h.title,url:h.url})}catch(h){u.push({title:m.title,message:h?.message||String(h)})}await D({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 D({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(m=>m.kind==="issue"),w=null;return i.linkCurrentTrack&&p.length===1&&!await Er(e.id)&&(w=await hc(e,p[0].key,{source:"created"}).catch(()=>null)),{proposalId:t,action:"created",created:l,failed:u,linked:w?w.key:null}}async function td(e,t){let n=await Ia(e);n&&await n.api.createComment(n.cfg,e,t)}async function aY(e,t,n){let r=await Ia(e);if(!r)return null;let o=await Xr(t);if(!o)return null;let s=Wn(o,n);if(!s)return null;let a=await nd.readFile(vn(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 IP=()=>Number(process.env.BOSTRAT_TICKET_COST_SYNC_MS??12e4),kx=new Map;function iY(e,t){if(IP()<=0)return rd(e,t);if(kx.has(e))return;let n=setTimeout(()=>{kx.delete(e),Er(e).then(r=>r?rd(e,r):null).catch(()=>{})},IP());n.unref?.(),kx.set(e,n)}var $P=new Map;async function RP(e,t,n){let r=$P.get(e)??0;Date.now()-r<600*1e3||($P.set(e,Date.now()),await D({id:e,cwd:t},{type:"ticket.sync.failed",actor:"system",source:"orchestrator",payload:{ts:Date.now(),message:n?.message||String(n)}}).catch(()=>{}))}async function cY(e,{resolveTrack:t=null}={}){let n=await Er(e.trackId),r=e.payload||{};if(!n){if(e.type!=="turn.user"||e.actor!=="user")return;let o=null;for(let a of await Ax())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 hc(s,o,{source:"chat"})}catch(a){await RP(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 cs(e.trackId))}try{switch(e.type){case"handoff.done":n.track.leadAgent=r.toAgent??n.track.leadAgent,await cs(e.trackId),await rd(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 cs(e.trackId),await rd(e.trackId,n),r.change==="opened"||r.change==="merged"){let o=r.change==="merged"?await BP(n,e.trackId).catch(()=>null):null;await td(n,`**Bostrat** \u2014 PR ${r.change} for **${n.track.name}**${r.url?`: ${r.url}`:r.number?` (#${r.number})`:""}`+(o?`
|
|
929
929
|
|
|
930
930
|
Agent cost for this Track: ${ZJ(o)}.`:"")),await jP(e.trackId,n,r.change)}break}case"mock.state.changed":{if(r.change==="ready"&&r.mockId){let o=await aY(n,r.mockId,r.version??null);if(!o)break;let s=(r.version??1)>1?` revised (v${r.version})`:"";await td(n,`**Bostrat** \u2014 mock **${r.name}**${s}${r.group?` (group \`${r.group}\`)`:""}:
|
|
931
931
|
|
|
932
932
|
`)}else if(r.change==="picked"){let o=(r.siblings??[]).map(s=>`**${s.name}**`).join(", ");await td(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 td(n,`**Bostrat** \u2014 live preview **${r.name}**: ${km(r.slug)}
|
|
933
|
-
_(runs on the Track's branch; a Bostrat-fronted preview, not a public deployment)_`);break}case"cost.recorded":await iY(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await RP(e.trackId,s?.cwd??null,o)}}function KP({resolveTrack:e}){at.on("event",t=>{cY(t,{resolveTrack:e}).catch(()=>{})})}async function VP(){if(!et())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await xt("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await sd(),r=0;for(let[o,s]of Object.entries(n))await Pt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}ca();Wi();import lY from"ws";var zP=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function xm(e,t,n={}){let r=await fetch(`${zP()}/${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 Ix=(e,t)=>xm("chat.postMessage",e,t),$a=(e,t)=>xm("chat.update",e,t);async function qt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function uY(e,t,n={}){let r=await fetch(`${zP()}/${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 JP(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await uY("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 xm("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var dY=2200;function YP({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 xm("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new lY(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=
|
|
933
|
+
_(runs on the Track's branch; a Bostrat-fronted preview, not a public deployment)_`);break}case"cost.recorded":await iY(e.trackId,n);break;default:break}}catch(o){let s=t?await t(e.trackId).catch(()=>null):null;await RP(e.trackId,s?.cwd??null,o)}}function KP({resolveTrack:e}){at.on("event",t=>{cY(t,{resolveTrack:e}).catch(()=>{})})}async function VP(){if(!et())return{pushed:0,source:"unconfigured"};let{records:e,source:t}=await xt("tickets");if(t!=="plane"||e.length)return{pushed:0,source:t};let n=await sd(),r=0;for(let[o,s]of Object.entries(n))await Pt("tickets",{id:o,updatedAt:Date.now(),...s},{trackId:o}).catch(()=>{}),r++;return{pushed:r,source:"plane"}}ca();Wi();import lY from"ws";var zP=()=>process.env.BOSTRAT_SLACK_API_BASE||"https://slack.com/api";async function xm(e,t,n={}){let r=await fetch(`${zP()}/${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 Ix=(e,t)=>xm("chat.postMessage",e,t),$a=(e,t)=>xm("chat.update",e,t);async function qt(e,t){await fetch(e,{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify(t)}).catch(()=>{})}async function uY(e,t,n={}){let r=await fetch(`${zP()}/${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 JP(e,{filename:t,buffer:n,title:r,channelId:o,threadTs:s,initialComment:a}){let{upload_url:i,file_id:c}=await uY("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 xm("files.completeUploadExternal",e,{files:[{id:c,title:r}],channel_id:o,thread_ts:s,...a?{initial_comment:a}:{}})}var dY=2200;function YP({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 xm("apps.connections.open",u))}catch(u){return n(`connections.open failed: ${u?.message||u}`),c()}o=new lY(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{}},w=!1,m=setTimeout(()=>{w=!0,p()},dY);Promise.resolve().then(()=>t(d)).then(h=>{clearTimeout(m),!w&&(w=!0,p(d.accepts_response_payload?h:void 0))},h=>{clearTimeout(m),w||(w=!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 QP=()=>process.env.BOSTRAT_STATE_DIR||vm.join(process.env.HOME||fY.tmpdir(),".bostrat"),Cx=()=>vm.join(QP(),"slack.json"),Sm=null,$x=null,Rx=Promise.resolve();async function Px(){return Sm||($x??=ad.readFile(Cx(),"utf8").then(e=>JSON.parse(e)?.threads??{}).catch(()=>({})).then(e=>Sm=e).finally(()=>$x=null),$x)}async function XP(){let e=JSON.stringify({threads:Sm},null,2),t=`${Cx()}.${process.pid}.tmp`;await ad.mkdir(QP(),{recursive:!0}),await ad.writeFile(t,e),await ad.rename(t,Cx())}async function zn(){Rx=Rx.then(XP,XP),await Rx.catch(()=>{})}async function Dx(e){return(await Px())[e]??null}async function hY(e,t){let n=await Px();for(let[r,o]of Object.entries(n))if(o.channel===e&&o.ts===t)return{trackId:r,rec:o};return null}var Be=e=>String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");function id(e,t){let n=String(e??"").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function mY(e,t=500){let n=String(e??"").trim().split(/\n\s*\n/)[0]??"";return id(n.replace(/\n+/g," "),t)}function eD(e){let t=`*${Be(e.name)}*${e.archivedAt?" \xB7 _archived_":""}`,n=`${Be(e.repoLabel)} \xB7 \`${Be(e.branch||"?")}\` \xB7 lead *${Be(e.lead)}*`,r=e.kickoff?`> ${Be(id(e.kickoff,300))}`:"_no kickoff yet \u2014 reply in this thread to steer the lead_";return[{type:"section",text:{type:"mrkdwn",text:`${t}
|
|
934
934
|
${n}`}},{type:"section",text:{type:"mrkdwn",text:r}},{type:"context",elements:[{type:"mrkdwn",text:`<${od(e.trackId)}|open the Track> \xB7 reachable on the operator's private network only`}]}]}async function Nx(e,t){await $a(e.botToken,{channel:t.channel,ts:t.ts,text:`Track: ${t.name}`,blocks:eD(t)})}async function us(e,t,n,r=void 0){return Ix(e.botToken,{channel:t.channel,thread_ts:t.ts,text:n,...r?{blocks:r}:{},unfurl_links:!1})}var ZP=new Set;function ls(e){ZP.add(e),e.catch(()=>{}).finally(()=>ZP.delete(e))}var Xe=e=>({response_type:"ephemeral",text:e}),wY="*/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._",gY=["claude","cursor","codex"];function Ox(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 Mx=(e,t)=>Xe(`No live Track matches \u201C${Be(t)}\u201D. Live: ${e.map(n=>`\`${Be(n.name)}\``).join(" \xB7 ")||"none"}`);async function tD(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 qt(o,{...Xe(`At capacity \u2014 ${a.length} live Tracks (limit ${t.maxConcurrent}). Archive or stop something first.`),replace_original:!0});return}if(!t.channel){await qt(o,{...Xe("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?vm.basename(c.base):"fresh workspace"),lead:"claude"},u=await Ix(t.botToken,{channel:t.channel,text:`Track started: ${l.name}`,blocks:eD(l),unfurl_links:!1});l.ts=u.ts,(await Px())[i.id]=l,await zn(),await qt(o,{...Xe(`\u2713 *${Be(l.name)}* started \u2014 root message posted.`),replace_original:!0})}catch(a){await qt(o,{...Xe(`Start failed: ${a?.message||a}`),replace_original:!0})}}async function yY(e,t,{track:n,responseUrl:r}){let o=e.deps;try{await o.archiveTrack(n.id);let s=await Dx(n.id);s&&(s.archivedAt=Date.now(),await zn(),await Nx(t,s).catch(()=>{})),await qt(r,{...Xe(`\u2713 *${Be(n.name)}* archived.`),replace_original:!0})}catch(s){await qt(r,{...Xe(`Archive failed: ${s?.message||s}`),replace_original:!0})}}async function bY(e,t,{track:n,agent:r,responseUrl:o}){try{await e.deps.startLeadHandoff(n.id,r),await qt(o,{...Xe(`\u2713 Handing *${Be(n.name)}* to ${Be(r)} \u2014 the root message updates when the baton lands.`),replace_original:!0})}catch(s){await qt(o,{...Xe(`Handoff failed: ${s?.message||s}`),replace_original:!0})}}async function kY(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 qt(r,{...Xe(`\u2713 Stopped *${Be(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 qt(r,{...Xe(`Stop failed: ${s?.message||s}`),replace_original:!0})}}function xY(e,t){let n=[...t.slice(0,99).map(r=>({text:{type:"plain_text",text:id(`${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 *${Be(e)}*:`},accessory:{type:"static_select",action_id:"bostrat-start-repo",placeholder:{type:"plain_text",text:"Choose a repo"},options:n}}]}async function SY(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?vm.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 *${Be(s.name)}* \u2014 ${Be(i)}${a.branch?` \`${Be(a.branch)}\``:""} \xB7 lead ${Be(c)} \xB7 ${l}`}),o=t.length-n.length;return r.join(`
|
|
935
935
|
`)+(o?`
|
|
936
936
|
_${o} archived_`:"")}async function vY(e,t){let n=await Ea();if(!n)return Xe("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 Xe("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?(ls(tD(e,n,{name:u,repo:l.path,responseUrl:t.response_url})),Xe(`Starting *${Be(u)}* on ${Be(l.name)}\u2026`)):{response_type:"ephemeral",text:`Pick a repo for \u201C${u}\u201D`,blocks:xY(u,i)}}case"archive":{if(!a.length)return Xe("Usage: `/bostrat archive <track>`");let{match:i,live:c}=Ox(await r.listTracks(),a.join(" "));return i?(ls(yY(e,n,{track:i,responseUrl:t.response_url})),Xe(`Archiving *${Be(i.name)}*\u2026`)):Mx(c,a.join(" "))}case"handoff":{let i=r.knownAgents??gY,c=a.at(-1)?.toLowerCase();if(a.length<2||!i.includes(c))return Xe(`Usage: \`/bostrat handoff <track> <${i.join("|")}>\``);let l=a.slice(0,-1).join(" "),{match:u,live:d}=Ox(await r.listTracks(),l);return u?(ls(bY(e,n,{track:u,agent:c,responseUrl:t.response_url})),Xe(`Handing *${Be(u.name)}* to ${Be(c)}\u2026`)):Mx(d,l)}case"stop":{if(!a.length)return Xe("Usage: `/bostrat stop <track>`");let{match:i,live:c}=Ox(await r.listTracks(),a.join(" "));return i?(ls(kY(e,n,{track:i,responseUrl:t.response_url})),Xe(`Stopping *${Be(i.name)}*\u2026`)):Mx(c,a.join(" "))}case"list":return Xe(await SY(r));default:return Xe(wY)}}async function AY(e,t,n,r){let{trackId:o,promptId:s,label:a}=r,i=await Dx(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 zn(),await $a(t.botToken,{channel:i.channel,ts:c,text:`\u2713 ${a}`,blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Be(l||"question")}~
|
|
937
937
|
\u2713 *${Be(a)}*`}}]}).catch(()=>{})}}catch(c){await qt(n.response_url,Xe(`Couldn't answer: ${c?.message||c}`))}}async function TY(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)?Ko.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,Ni(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 qt(n.response_url,Xe(`Couldn't act on the offer: ${c?.message||c}`))}}async function EY(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 qt(n.response_url,Xe(`Couldn't act on the offer: ${i?.message||i}`))}}async function _Y(e,t){let n=t.actions?.[0];if(!n?.action_id)return;let r=await Ea();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 qt(t.response_url,{...Xe(`Starting *${Be(s)}*\u2026`),replace_original:!0}),ls(tD(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"?ls(AY(e,r,t,o)):n.action_id==="bostrat-ship"?ls(TY(e,r,t,o)):n.action_id==="bostrat-pr-exists"&&ls(EY(e,r,t,o))}async function IY(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 hY(t.channel,t.thread_ts);if(!n)return;let r=await Ea();if(r)try{await e.deps.sayToLead(n.trackId,t.text.trim())}catch(o){await us(r,n.rec,`Couldn't deliver that to the lead: ${o?.message||o}`).catch(()=>{})}}function $Y(e){return async t=>{if(t.type==="slash_commands")return vY(e,t.payload);if(t.type==="interactive"){await _Y(e,t.payload);return}if(t.type==="events_api"){await IY(e,t.payload?.event);return}}}var RY=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 OY(e,t){let n=[{type:"section",text:{type:"mrkdwn",text:`\u2753 ${Be(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:id(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 MY(e,t,n){let r=n.payload||{};if(!r.promptId||t.prompt?.promptId===r.promptId)return;t.prompt&&await $a(e.botToken,{channel:t.channel,ts:t.prompt.ts,text:"superseded",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Be(t.prompt.question||"question")}~ _superseded_`}}]}).catch(()=>{});let o=await us(e,t,r.question||"The lead needs an answer",OY(n.trackId,r));t.prompt={promptId:r.promptId,ts:o.ts,question:r.question||null},await zn()}async function CY(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 zn(),await $a(e.botToken,{channel:t.channel,ts:o,text:"answered",blocks:[{type:"section",text:{type:"mrkdwn",text:`~${Be(s||"question")}~
|
|
938
938
|
\u2713 _answered_`}}]})}async function NY(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 us(e,t,r.excerpt||"Ship it?",[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${Be(id(r.excerpt||"The lead offered to ship.",300))}`}},{type:"actions",elements:s}]);t.offers=t.offers||{},t.offers[r.offerId]=a.ts,await zn()}async function PY(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await zn();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 $a(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function DY(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 us(e,t,`PR ${o} already open \u2014 push or new PR?`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${o}${r.branch?` (${Be(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 zn()}async function BY(e,t,n){let r=n.payload||{},o=t.offers?.[r.offerId];if(!o)return;delete t.offers[r.offerId],await zn();let s=r.choice==="dismiss"?"dismissed":r.choice==="new"?"\u2713 opening a new PR":"\u2713 pushing to the open PR";await $a(e.botToken,{channel:t.channel,ts:o,text:s,blocks:[{type:"section",text:{type:"mrkdwn",text:`\u{1F6A2} ${s}`}}]})}async function LY(e,t,n,r){let o=n.payload||{};if(o.change==="ready"&&o.mockId){let s=await(r.readMockPng??jY)(o.mockId,o.version??null);if(!s)return;let a=(o.version??1)>1?` (v${o.version})`:"";await JP(e.botToken,{filename:s.filename,buffer:s.buffer,title:`${o.name}${a}`,channelId:t.channel,threadTs:t.ts,initialComment:`\u{1F3A8} mock *${Be(o.name)}*${a}${o.group?` (group \`${Be(o.group)}\`)`:""}`})}else if(o.change==="picked"){let s=(o.siblings??[]).map(a=>`*${Be(a.name)}*`).join(", ");await us(e,t,`Design decision: ${o.name} picked`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F3A8} design decision: *${Be(o.name)}* picked${s?` over ${s}`:""}`}}])}}async function jY(e,t){let n=await Xr(e);if(!n)return null;let r=Wn(n,t);if(!r)return null;let o=await ad.readFile(vn(n,r.v).png).catch(()=>null);return o?{filename:`${n.name.replace(/[^\w.-]+/g,"-")}.v${r.v}.png`,buffer:o}:null}async function FY(e,t){if(!RY.has(t.type))return;let n=await Dx(t.trackId);if(!n)return;let r=await Ea();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 zn(),await Nx(r,n);return;case"turn.agent":{if(!o.text)return;let s=mY(o.text);if(!s)return;await us(r,n,s,[{type:"section",text:{type:"mrkdwn",text:Be(s)}},{type:"context",elements:[{type:"mrkdwn",text:`<${od(t.trackId)}|full turn \u2192>`}]}]);return}case"prompt.raised":return MY(r,n,t);case"prompt.answered":return CY(r,n,t);case"pr.offered":return NY(r,n,t);case"pr.offer.answered":return PY(r,n,t);case"pr.exists.offered":return DY(r,n,t);case"pr.exists.answered":return BY(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 us(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 zn(),await Nx(r,n);return;case"view.state.changed":{if(o.change!=="created"||o.restarted||!o.slug)return;await us(r,n,`Live preview ${o.name}: ${km(o.slug)}`,[{type:"section",text:{type:"mrkdwn",text:`\u{1F50D} live preview *${Be(o.name)}*: ${km(o.slug)}
|
|
939
939
|
_runs on the Track's branch; a Bostrat-fronted preview, not a public deployment_`}}]);return}case"mock.state.changed":return LY(r,n,t,e.deps)}}function nD(e){let t={deps:e};at.on("event",s=>{FY(t,s).catch(()=>{})});let n=null,r=null,o=async()=>{n||!await Ea()||(r&&clearInterval(r),r=null,n=YP({getToken:async()=>(await Ea())?.appToken,onEnvelope:$Y(t),log:s=>console.log(`[slack] ${s}`)}))};return r=setInterval(()=>o().catch(()=>{}),3e4),r.unref?.(),o().catch(()=>{}),()=>{r&&clearInterval(r),n?.()}}Mn();be();Dk();$n();Sb();si();Nr();import UY from"node:fs/promises";function HY(e){let t=new Map;for(let n of String(e||"").split(`
|
|
940
|
-
`)){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 WY(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 qY=new Set(["Write","Edit","NotebookEdit"]),GY=220,KY=160;function VY(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(qY.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,GY)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=vs(o.command.trim().replace(/\s+/g," ")).slice(0,KY));return r}function zY(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?On(t.cwd,t.sessionId):t?.cwd?Vw(t.cwd):null}async function oD(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 D(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 Ki(o?.cwd)}});break;case"UserPromptSubmit":{let c=oi(String(e.prompt??e.user_prompt??"")),l=ch(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:VY(e,o)});break;case"Stop":await JY(r,o,e,i);break;default:break}return a}async function JY(e,t,n,r){let o=[],s=zY(n,t);if(s)try{o=HY(await UY.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 V(e),c=WY(i),l=o.filter(p=>!c.has(p.messageId));if(l.length){let p=new Map;for(let w of l){let m=`${w.model||"unknown"}\0${w.speed||""}`,
|
|
941
|
-
`)}be();Ky();import rX from"node:fs/promises";import oX from"node:path";Np();si();Bo();var Tm=e=>e.payload?.ts??e.ts,XY=12e4,Tn=e=>Math.round(e*1e4)/1e4,ZY=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{},byTrack:new Map});function QY(e,{since:t}){let{track:n,events:r,brief:o}=e,s=x=>Tm(x)>=t,a=Cr([El(n?.name),El(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 v=Cr(x.payload.task);v&&i.set(x.boxId,v)}let c=new Map,l=x=>{let v=x||"unattributed";return c.has(v)||c.set(v,{segments:[u(null)],lastTs:null,provider:null}),c.get(v)},u=(x,{shape:v="initial",continuation:S=!1,text:E=null,ts:P=null}={})=>({textCat:x,shape:v,continuation:S,text:E,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,v)=>Tm(x)-Tm(v)),p=0,w=0,m=0,f={turns:0};for(let x of d){let v=l(x.boxId),S=v.segments[v.segments.length-1],E=Tm(x);switch(v.lastTs!=null&&E>v.lastTs&&s(x)&&(S.activeMs+=Math.min(E-v.lastTs,XY)),v.lastTs=E,x.provider&&(v.provider=x.provider),x.type){case"turn.user":{let P=x.payload?.text;if(x.source==="hook"||!String(P||"").trim()||x.payload?.note||wl(P))break;let L=Cr(P),$=!!x.payload?.kind,C=v.segments.some(_=>_.shape!=="initial"),U=$||C&&HT(P),J=u(L,{shape:$?"injected":U?"follow-up":"novel-ask",continuation:!L&&U,text:lD(P),ts:E});v.segments.push(J),s(x)&&(J.turns+=1);break}case"peer.message":{let P=x.payload?.text;if(!String(P||"").trim())break;let L=Cr(P),$=u(L,{shape:"peer",continuation:!L,text:lD(P),ts:E});v.segments.push($),s(x)&&($.turns+=1);break}case"tool.called":{if(x.source==="transcript")break;let P=x.payload?.tool;P&&(S.tools[P]=(S.tools[P]||0)+1),s(x)&&(S.toolCalls+=1);break}case"cost.recorded":{if(!s(x))break;let{usd:P,tokens:L,model:$,unpriced:C}=gn(x);C&&(f.turns+=1),S.usd+=P,L&&(S.tokens.input+=L.input,S.tokens.output+=L.output,S.tokens.cacheRead+=L.cacheRead,S.tokens.cacheWrite+=L.cacheWrite),S.models[$]=(S.models[$]||0)+P,x.provider&&(S.provider=x.provider);break}case"handoff.done":s(x)&&(p+=1);break;case"subtask.merged":s(x)&&(w+=1);break;case"error":s(x)&&x.payload?.kind==="subtask-failed"&&(m+=1);break;default:break}}let g=new Map,y={usd:0,turns:0,byShape:{},samples:[]},b=!1;for(let[x,v]of c){let S=null;for(let E of v.segments){let P=null,L=null;if(E.textCat)P=E.textCat.category,L="text";else if(i.get(x))P=i.get(x).category,L="boxTask";else if(E.continuation&&S)P=S,L="inherited";else{let _=UT(E.tools);_?(P=_.category,L="toolMix"):a&&(P=a.category,L="hint")}if(P&&(S=P),!(E.usd>0||E.activeMs>0||E.turns>0||E.toolCalls>0))continue;let C=P??"uncategorized";g.has(C)||g.set(C,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{}});let U=g.get(C);U.usd+=E.usd,U.activeMs+=E.activeMs,U.turns+=E.turns,U.toolCalls+=E.toolCalls,L&&(U.provenance[L]=(U.provenance[L]||0)+E.usd);for(let[_,I]of Object.entries(E.models))U.models[_]=(U.models[_]||0)+I;let J=E.provider||v.provider;J&&(U.providers[J]=(U.providers[J]||0)+E.usd),J==="cursor"&&E.usd===0&&(b=!0),P||(y.usd+=E.usd,y.turns+=E.turns,y.byShape[E.shape]=(y.byShape[E.shape]||0)+E.usd,E.usd>0&&E.text&&y.samples.push({trackId:n?.id,track:n?.name||n?.id,shape:E.shape,usd:Tn(E.usd),ts:E.ts,text:E.text}))}}return{perCategory:g,uncategorized:y,handoffs:p,merged:w,failed:m,sawCursorActivity:b,unpricedTurns:f.turns}}function Lx(e,{windowMs:t=null,now:n=Date.now()}={}){let r=t==null?0:n-t,o=new Map,s=[],a=0,i=!1,c=0,l={usd:0,turns:0,byShape:{},samples:[]};for(let y of e||[]){let{track:b,events:x}=y;if(!x?.length){a+=1;continue}let{perCategory:v,uncategorized:S,handoffs:E,merged:P,failed:L,sawCursorActivity:$,unpricedTurns:C}=QY(y,{since:r});$&&(i=!0),c+=C,l.usd+=S.usd,l.turns+=S.turns;for(let[J,_]of Object.entries(S.byShape))l.byShape[J]=(l.byShape[J]||0)+_;l.samples.push(...S.samples);let U={trackId:b?.id,name:b?.name||b?.id,archived:!!b?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:E,subtasksMerged:P,subtasksFailed:L};for(let[J,_]of v){U.usd+=_.usd,U.activeMs+=_.activeMs,U.turns+=_.turns,U.categories[J]={usd:Tn(_.usd),activeMs:_.activeMs};for(let[F,W]of Object.entries(_.models))U.models[F]=Tn((U.models[F]||0)+W);for(let[F,W]of Object.entries(_.providers))U.providers[F]=Tn((U.providers[F]||0)+W);o.has(J)||o.set(J,ZY());let I=o.get(J);I.usd+=_.usd,I.activeMs+=_.activeMs,I.turns+=_.turns,I.toolCalls+=_.toolCalls;for(let[F,W]of Object.entries(_.models))I.models[F]=(I.models[F]||0)+W;for(let[F,W]of Object.entries(_.providers))I.providers[F]=(I.providers[F]||0)+W;for(let[F,W]of Object.entries(_.provenance))I.provenance[F]=(I.provenance[F]||0)+W;let T=I.byTrack.get(b?.id)||{usd:0,activeMs:0};T.usd+=_.usd,T.activeMs+=_.activeMs,I.byTrack.set(b?.id,T)}(U.usd>0||U.activeMs>0||U.turns>0)&&(U.usd=Tn(U.usd),U.dominantCategory=nX(U.categories),s.push(U))}let u=[...o.values()].reduce((y,b)=>y+b.usd,0),d=[...o.values()].reduce((y,b)=>y+b.activeMs,0),p=u>0?"usd":"time",w=p==="usd"?u:d,m=new Map((e||[]).map(y=>[y.track?.id,y.track?.name||y.track?.id])),f=[...o.entries()].map(([y,b])=>({category:y,sharePct:w>0?Math.round((p==="usd"?b.usd:b.activeMs)/w*100):0,shareBasis:p,usd:Tn(b.usd),activeMs:b.activeMs,turns:b.turns,toolCalls:b.toolCalls,models:ld(b.models),providers:ld(b.providers),provenance:ld(b.provenance),topWorkstreams:[...b.byTrack.entries()].sort((x,v)=>v[1].usd-x[1].usd||v[1].activeMs-x[1].activeMs).slice(0,2).map(([x,v])=>({trackId:x,name:m.get(x),usd:Tn(v.usd),activeMs:v.activeMs}))})).sort((y,b)=>b.usd-y.usd||b.activeMs-y.activeMs);s.sort((y,b)=>b.usd-y.usd||b.activeMs-y.activeMs);let g={};for(let y of o.values())for(let[b,x]of Object.entries(y.provenance))g[b]=(g[b]||0)+x;return{since:r,capturedAt:n,totalUsd:Tn(u),activeMs:d,turns:[...o.values()].reduce((y,b)=>y+b.turns,0),bullets:f,workstreams:s,provenance:ld(g),gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c,uncategorized:{usd:Tn(l.usd),turns:l.turns,sharePct:u>0?Math.round(l.usd/u*100):0,byShape:ld(l.byShape),top:l.samples.sort((y,b)=>b.usd-y.usd).slice(0,eX)}}}}var eX=25,cD=160,lD=e=>{let t=String(e||"").replace(/\s+/g," ").trim();return t.length>cD?`${t.slice(0,cD).trimEnd()}\u2026`:t},tX=10;function uD(e,{thresholdPct:t=tX}={}){let n=e?.gaps?.uncategorized||{usd:0,turns:0},r=e?.totalUsd||0,o=n.usd||0,s=r>0?o/r*100:0,a=s<=t,i=a?[]:[`${s.toFixed(1)}% of the last 7d ($${o.toFixed(2)} of $${r.toFixed(2)}) is uncategorized (threshold ${t}%) \u2014 run \`npm run cost -- --uncategorized\` and add classifier table lines for the top asks`];return{ok:a,sharePct:Math.round(s*10)/10,thresholdPct:t,usd:Tn(o),totalUsd:Tn(r),turns:n.turns||0,inheritedPct:r>0?Math.round((e?.provenance?.inherited||0)/r*100):0,problems:i}}var nX=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},ld=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Tn(n)]));var Oa={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function sX(e){let t=String(e||"7d");return t in Oa?{key:t,ms:Oa[t]}:{key:"7d",ms:Oa["7d"]}}function aX(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=Nf(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 iX(e){if(!e?.cwd)return null;try{let n=(await rX.readFile(oX.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 jx(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}:sX(t),d=[];for(let m of e||[]){let f=await V(m),g=aX(m,f);i&&c<o&&(g=g.filter(y=>(y.ts??0)<=c)),d.push({track:m,events:g,brief:await iX(m)})}let p=Lx(d,{windowMs:u,now:c}),w=l==="7d"&&c===o?p:Lx(d,{windowMs:Oa["7d"],now:o});return{window:l,...p,categorization:uD(w)}}var ud=e=>`$${Number(e||0).toFixed(2)}`,dD=e=>{let t=Math.round((e||0)/6e4);return t>=60?`${Math.floor(t/60)}h${String(t%60).padStart(2,"0")}`:`${t}m`},Ra=(e,t)=>String(e).padEnd(t);function pD(e){let t=[];t.push(`USAGE ROUNDUP \xB7 ${e.window} \xB7 ${ud(e.totalUsd)} \xB7 ${dD(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(` ${Ra(`${a.shareBasis==="time"?"~":""}${a.sharePct}%`,5)} ${Ra(a.category,15)} ${Ra(ud(a.usd),10)} ${Ra(dD(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 ${ud(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} ${ud(i)}`).join(" \xB7 ")||"none")),s.top?.length||t.push(" (nothing unmatched carried cost in this window)");for(let a of s.top||[])t.push(` ${Ra(ud(a.usd),8)} ${Ra(a.shape,10)} ${Ra(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(`
|
|
942
|
-
`)}Nr();var ps=36e5,wD=24*ps,cX=400,lX=12,Ma=e=>Math.round(e*1e4)/1e4;function Fx({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 Oa?String(e||"7d"):"7d",i=Oa[a];return{key:a,since:i==null?null:r-i,until:r}}var uX=(e,t)=>e!=null&&t-e<=48*ps?ps:wD;function fD(e,t){if(t===ps)return Math.floor(e/ps)*ps;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function dX(e,t){if(t===ps)return e+ps;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var hD=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),mD=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},pX=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Ma(n)]));async function gD(e,t={}){let n=t.now??Date.now(),r=Fx({...t,now:n}),o=r.since==null?wD:uX(r.since,r.until),s=$=>(r.since==null||$>=r.since)&&$<r.until,a=r.since!=null?r.until-r.since:null,i=$=>a!=null&&$>=r.since-a&&$<r.since,c={},l={},u=hD(),d=0,p=0,w=0,m=0,
|
|
940
|
+
`)){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 WY(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 qY=new Set(["Write","Edit","NotebookEdit"]),GY=220,KY=160;function VY(e,t){let n=e?.tool_name??null,r={tool:n},o=e?.tool_input;if(!o||typeof o!="object")return r;if(qY.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,GY)}else n==="Bash"&&typeof o.command=="string"&&o.command.trim()&&(r.head=vs(o.command.trim().replace(/\s+/g," ")).slice(0,KY));return r}function zY(e,t){return e?.transcript_path?e.transcript_path:t?.cwd&&t?.sessionId?On(t.cwd,t.sessionId):t?.cwd?Vw(t.cwd):null}async function oD(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 D(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 Ki(o?.cwd)}});break;case"UserPromptSubmit":{let c=oi(String(e.prompt??e.user_prompt??"")),l=ch(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:VY(e,o)});break;case"Stop":await JY(r,o,e,i);break;default:break}return a}async function JY(e,t,n,r){let o=[],s=zY(n,t);if(s)try{o=HY(await UY.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 V(e),c=WY(i),l=o.filter(p=>!c.has(p.messageId));if(l.length){let p=new Map;for(let w of l){let m=`${w.model||"unknown"}\0${w.speed||""}`,h=p.get(m)||{tokens:{input:0,output:0,cacheWrite:0,cacheRead:0},cacheWriteTtl:null,messageIds:[]};for(let g of Object.keys(h.tokens))h.tokens[g]+=w.tokens[g];w.cacheWriteTtl&&(h.cacheWriteTtl??={m5:0,h1:0},h.cacheWriteTtl.m5+=w.cacheWriteTtl.m5,h.cacheWriteTtl.h1+=w.cacheWriteTtl.h1),h.messageIds.push(w.messageId),h.speed=w.speed||null,p.set(m,h)}for(let[w,m]of p){let h=w.split("\0")[0];await r({type:"cost.recorded",actor:"system",source:"transcript",payload:{model:h,usd:lr(h,m.tokens,void 0,m.speed?{speed:m.speed}:void 0),tokens:m.tokens,...m.speed?{speed:m.speed}:{},cacheWriteTtl:m.cacheWriteTtl,messageId:m.messageIds[m.messageIds.length-1],messageIds:m.messageIds,apiCalls:m.messageIds.length}})}}let u=rD(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:rD(d),tokens:d.tokens}:null,calls:l.length,turnIndex:YY(i,t)}})}var rD=e=>e.tokens.input+e.tokens.cacheWrite+e.tokens.cacheRead;function YY(e,t){if(!t?.name)return null;let n=Uc(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}Da();Pw();ah();Fy();be();be();Bo();be();Bo();Nr();function cd(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 sD=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),aD=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},Am=e=>Math.round(e*1e4)/1e4;async function Bx(e){let t=[],n={},r={},o=0,s=0,a=0,i=0,c=0,l=new Set,u=sD(),d=0,p=[];for(let w of e||[]){let m=await V(w),h=Do(m,{boxLabels:cd(w)});if(h.turns===0){w.archivedAt?d++:p.push(w.name||w.id);continue}o+=h.totalUsd,s+=h.turns,a+=h.repricedTurns||0,i+=h.asRecordedUsd||0,c+=h.unpricedTurns||0;for(let g of h.unpricedModels||[])l.add(g);aD(u,h.totalTokens);for(let[g,y]of Object.entries(h.byModel))n[g]||={usd:0,events:0,tokens:sD()},n[g].usd=Am(n[g].usd+y.usd),n[g].events+=y.events,aD(n[g].tokens,y.tokens);for(let[g,y]of Object.entries(h.byProvider))r[g]||={usd:0,events:0},r[g].usd=Am(r[g].usd+y.usd),r[g].events+=y.events;t.push({id:w.id,name:w.name,usd:h.totalUsd,rollup:h})}return t.sort((w,m)=>m.usd-w.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:wi(),fleet:{totalUsd:Am(o),asRecordedUsd:Am(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 ds=e=>`$${e.toFixed(4)}`,mc=(e,t)=>String(e).padEnd(t);function iD(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 ${ds(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 ${ds(t.asRecordedUsd)} \xB7 current-rates total ${ds(t.totalUsd)} (${t.totalUsd>=t.asRecordedUsd?"+":""}${ds(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(` ${mc(a,26)} ${mc(ds(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(` ${mc(a.name||a.id,30)} ${ds(a.usd)}`);let i=Object.values(a.rollup.byBox).sort((c,l)=>l.usd-c.usd);for(let c of i)if(r.push(` ${mc(c.label,40)} ${mc(ds(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))}${mc(ds(u.usd),10)} ${u.models.join(",")||"?"}`)}return r.join(`
|
|
941
|
+
`)}be();Ky();import rX from"node:fs/promises";import oX from"node:path";Np();si();Bo();var Tm=e=>e.payload?.ts??e.ts,XY=12e4,Tn=e=>Math.round(e*1e4)/1e4,ZY=()=>({usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{},byTrack:new Map});function QY(e,{since:t}){let{track:n,events:r,brief:o}=e,s=x=>Tm(x)>=t,a=Cr([El(n?.name),El(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 v=Cr(x.payload.task);v&&i.set(x.boxId,v)}let c=new Map,l=x=>{let v=x||"unattributed";return c.has(v)||c.set(v,{segments:[u(null)],lastTs:null,provider:null}),c.get(v)},u=(x,{shape:v="initial",continuation:S=!1,text:E=null,ts:P=null}={})=>({textCat:x,shape:v,continuation:S,text:E,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,v)=>Tm(x)-Tm(v)),p=0,w=0,m=0,h={turns:0};for(let x of d){let v=l(x.boxId),S=v.segments[v.segments.length-1],E=Tm(x);switch(v.lastTs!=null&&E>v.lastTs&&s(x)&&(S.activeMs+=Math.min(E-v.lastTs,XY)),v.lastTs=E,x.provider&&(v.provider=x.provider),x.type){case"turn.user":{let P=x.payload?.text;if(x.source==="hook"||!String(P||"").trim()||x.payload?.note||wl(P))break;let L=Cr(P),$=!!x.payload?.kind,C=v.segments.some(_=>_.shape!=="initial"),U=$||C&&HT(P),J=u(L,{shape:$?"injected":U?"follow-up":"novel-ask",continuation:!L&&U,text:lD(P),ts:E});v.segments.push(J),s(x)&&(J.turns+=1);break}case"peer.message":{let P=x.payload?.text;if(!String(P||"").trim())break;let L=Cr(P),$=u(L,{shape:"peer",continuation:!L,text:lD(P),ts:E});v.segments.push($),s(x)&&($.turns+=1);break}case"tool.called":{if(x.source==="transcript")break;let P=x.payload?.tool;P&&(S.tools[P]=(S.tools[P]||0)+1),s(x)&&(S.toolCalls+=1);break}case"cost.recorded":{if(!s(x))break;let{usd:P,tokens:L,model:$,unpriced:C}=gn(x);C&&(h.turns+=1),S.usd+=P,L&&(S.tokens.input+=L.input,S.tokens.output+=L.output,S.tokens.cacheRead+=L.cacheRead,S.tokens.cacheWrite+=L.cacheWrite),S.models[$]=(S.models[$]||0)+P,x.provider&&(S.provider=x.provider);break}case"handoff.done":s(x)&&(p+=1);break;case"subtask.merged":s(x)&&(w+=1);break;case"error":s(x)&&x.payload?.kind==="subtask-failed"&&(m+=1);break;default:break}}let g=new Map,y={usd:0,turns:0,byShape:{},samples:[]},b=!1;for(let[x,v]of c){let S=null;for(let E of v.segments){let P=null,L=null;if(E.textCat)P=E.textCat.category,L="text";else if(i.get(x))P=i.get(x).category,L="boxTask";else if(E.continuation&&S)P=S,L="inherited";else{let _=UT(E.tools);_?(P=_.category,L="toolMix"):a&&(P=a.category,L="hint")}if(P&&(S=P),!(E.usd>0||E.activeMs>0||E.turns>0||E.toolCalls>0))continue;let C=P??"uncategorized";g.has(C)||g.set(C,{usd:0,activeMs:0,turns:0,toolCalls:0,models:{},providers:{},provenance:{}});let U=g.get(C);U.usd+=E.usd,U.activeMs+=E.activeMs,U.turns+=E.turns,U.toolCalls+=E.toolCalls,L&&(U.provenance[L]=(U.provenance[L]||0)+E.usd);for(let[_,I]of Object.entries(E.models))U.models[_]=(U.models[_]||0)+I;let J=E.provider||v.provider;J&&(U.providers[J]=(U.providers[J]||0)+E.usd),J==="cursor"&&E.usd===0&&(b=!0),P||(y.usd+=E.usd,y.turns+=E.turns,y.byShape[E.shape]=(y.byShape[E.shape]||0)+E.usd,E.usd>0&&E.text&&y.samples.push({trackId:n?.id,track:n?.name||n?.id,shape:E.shape,usd:Tn(E.usd),ts:E.ts,text:E.text}))}}return{perCategory:g,uncategorized:y,handoffs:p,merged:w,failed:m,sawCursorActivity:b,unpricedTurns:h.turns}}function Lx(e,{windowMs:t=null,now:n=Date.now()}={}){let r=t==null?0:n-t,o=new Map,s=[],a=0,i=!1,c=0,l={usd:0,turns:0,byShape:{},samples:[]};for(let y of e||[]){let{track:b,events:x}=y;if(!x?.length){a+=1;continue}let{perCategory:v,uncategorized:S,handoffs:E,merged:P,failed:L,sawCursorActivity:$,unpricedTurns:C}=QY(y,{since:r});$&&(i=!0),c+=C,l.usd+=S.usd,l.turns+=S.turns;for(let[J,_]of Object.entries(S.byShape))l.byShape[J]=(l.byShape[J]||0)+_;l.samples.push(...S.samples);let U={trackId:b?.id,name:b?.name||b?.id,archived:!!b?.archivedAt,usd:0,activeMs:0,turns:0,categories:{},models:{},providers:{},handoffs:E,subtasksMerged:P,subtasksFailed:L};for(let[J,_]of v){U.usd+=_.usd,U.activeMs+=_.activeMs,U.turns+=_.turns,U.categories[J]={usd:Tn(_.usd),activeMs:_.activeMs};for(let[F,W]of Object.entries(_.models))U.models[F]=Tn((U.models[F]||0)+W);for(let[F,W]of Object.entries(_.providers))U.providers[F]=Tn((U.providers[F]||0)+W);o.has(J)||o.set(J,ZY());let I=o.get(J);I.usd+=_.usd,I.activeMs+=_.activeMs,I.turns+=_.turns,I.toolCalls+=_.toolCalls;for(let[F,W]of Object.entries(_.models))I.models[F]=(I.models[F]||0)+W;for(let[F,W]of Object.entries(_.providers))I.providers[F]=(I.providers[F]||0)+W;for(let[F,W]of Object.entries(_.provenance))I.provenance[F]=(I.provenance[F]||0)+W;let T=I.byTrack.get(b?.id)||{usd:0,activeMs:0};T.usd+=_.usd,T.activeMs+=_.activeMs,I.byTrack.set(b?.id,T)}(U.usd>0||U.activeMs>0||U.turns>0)&&(U.usd=Tn(U.usd),U.dominantCategory=nX(U.categories),s.push(U))}let u=[...o.values()].reduce((y,b)=>y+b.usd,0),d=[...o.values()].reduce((y,b)=>y+b.activeMs,0),p=u>0?"usd":"time",w=p==="usd"?u:d,m=new Map((e||[]).map(y=>[y.track?.id,y.track?.name||y.track?.id])),h=[...o.entries()].map(([y,b])=>({category:y,sharePct:w>0?Math.round((p==="usd"?b.usd:b.activeMs)/w*100):0,shareBasis:p,usd:Tn(b.usd),activeMs:b.activeMs,turns:b.turns,toolCalls:b.toolCalls,models:ld(b.models),providers:ld(b.providers),provenance:ld(b.provenance),topWorkstreams:[...b.byTrack.entries()].sort((x,v)=>v[1].usd-x[1].usd||v[1].activeMs-x[1].activeMs).slice(0,2).map(([x,v])=>({trackId:x,name:m.get(x),usd:Tn(v.usd),activeMs:v.activeMs}))})).sort((y,b)=>b.usd-y.usd||b.activeMs-y.activeMs);s.sort((y,b)=>b.usd-y.usd||b.activeMs-y.activeMs);let g={};for(let y of o.values())for(let[b,x]of Object.entries(y.provenance))g[b]=(g[b]||0)+x;return{since:r,capturedAt:n,totalUsd:Tn(u),activeMs:d,turns:[...o.values()].reduce((y,b)=>y+b.turns,0),bullets:h,workstreams:s,provenance:ld(g),gaps:{tracksWithoutEvents:a,cursorCostUnknown:i,unpricedTurns:c,uncategorized:{usd:Tn(l.usd),turns:l.turns,sharePct:u>0?Math.round(l.usd/u*100):0,byShape:ld(l.byShape),top:l.samples.sort((y,b)=>b.usd-y.usd).slice(0,eX)}}}}var eX=25,cD=160,lD=e=>{let t=String(e||"").replace(/\s+/g," ").trim();return t.length>cD?`${t.slice(0,cD).trimEnd()}\u2026`:t},tX=10;function uD(e,{thresholdPct:t=tX}={}){let n=e?.gaps?.uncategorized||{usd:0,turns:0},r=e?.totalUsd||0,o=n.usd||0,s=r>0?o/r*100:0,a=s<=t,i=a?[]:[`${s.toFixed(1)}% of the last 7d ($${o.toFixed(2)} of $${r.toFixed(2)}) is uncategorized (threshold ${t}%) \u2014 run \`npm run cost -- --uncategorized\` and add classifier table lines for the top asks`];return{ok:a,sharePct:Math.round(s*10)/10,thresholdPct:t,usd:Tn(o),totalUsd:Tn(r),turns:n.turns||0,inheritedPct:r>0?Math.round((e?.provenance?.inherited||0)/r*100):0,problems:i}}var nX=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},ld=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Tn(n)]));var Oa={"24h":24*36e5,"7d":168*36e5,"30d":720*36e5,all:null};function sX(e){let t=String(e||"7d");return t in Oa?{key:t,ms:Oa[t]}:{key:"7d",ms:Oa["7d"]}}function aX(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=Nf(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 iX(e){if(!e?.cwd)return null;try{let n=(await rX.readFile(oX.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 jx(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}:sX(t),d=[];for(let m of e||[]){let h=await V(m),g=aX(m,h);i&&c<o&&(g=g.filter(y=>(y.ts??0)<=c)),d.push({track:m,events:g,brief:await iX(m)})}let p=Lx(d,{windowMs:u,now:c}),w=l==="7d"&&c===o?p:Lx(d,{windowMs:Oa["7d"],now:o});return{window:l,...p,categorization:uD(w)}}var ud=e=>`$${Number(e||0).toFixed(2)}`,dD=e=>{let t=Math.round((e||0)/6e4);return t>=60?`${Math.floor(t/60)}h${String(t%60).padStart(2,"0")}`:`${t}m`},Ra=(e,t)=>String(e).padEnd(t);function pD(e){let t=[];t.push(`USAGE ROUNDUP \xB7 ${e.window} \xB7 ${ud(e.totalUsd)} \xB7 ${dD(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(` ${Ra(`${a.shareBasis==="time"?"~":""}${a.sharePct}%`,5)} ${Ra(a.category,15)} ${Ra(ud(a.usd),10)} ${Ra(dD(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 ${ud(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} ${ud(i)}`).join(" \xB7 ")||"none")),s.top?.length||t.push(" (nothing unmatched carried cost in this window)");for(let a of s.top||[])t.push(` ${Ra(ud(a.usd),8)} ${Ra(a.shape,10)} ${Ra(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(`
|
|
942
|
+
`)}Nr();var ps=36e5,wD=24*ps,cX=400,lX=12,Ma=e=>Math.round(e*1e4)/1e4;function Fx({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 Oa?String(e||"7d"):"7d",i=Oa[a];return{key:a,since:i==null?null:r-i,until:r}}var uX=(e,t)=>e!=null&&t-e<=48*ps?ps:wD;function fD(e,t){if(t===ps)return Math.floor(e/ps)*ps;let n=new Date(e);return n.setHours(0,0,0,0),n.getTime()}function dX(e,t){if(t===ps)return e+ps;let n=new Date(e);return n.setDate(n.getDate()+1),n.setHours(0,0,0,0),n.getTime()}var hD=()=>({input:0,output:0,cacheRead:0,cacheCreation:0}),mD=(e,t)=>{for(let n of Object.keys(e))e[n]+=t?.[n]||0},pX=e=>Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Ma(n)]));async function gD(e,t={}){let n=t.now??Date.now(),r=Fx({...t,now:n}),o=r.since==null?wD:uX(r.since,r.until),s=$=>(r.since==null||$>=r.since)&&$<r.until,a=r.since!=null?r.until-r.since:null,i=$=>a!=null&&$>=r.since-a&&$<r.since,c={},l={},u=hD(),d=0,p=0,w=0,m=0,h=0,g=0,y=new Set,b=new Map,x=[],v=[],S=[],E=null;for(let $ of e||[]){let U=(await V($)).filter(I=>I.type==="cost.recorded");if(!U.length){$.archivedAt||S.push($.name||$.id);continue}let J=[];for(let I of U){let T=I.ts??0;s(T)?J.push(I):i(T)&&(g+=gn(I).usd)}if(!J.length)continue;let _=Do(J,{boxLabels:cd($)});d+=_.totalUsd,p+=_.turns,w+=_.repricedTurns||0,m+=_.asRecordedUsd||0,h+=_.unpricedTurns||0;for(let I of _.unpricedModels||[])y.add(I);mD(u,_.totalTokens);for(let[I,T]of Object.entries(_.byModel))c[I]||={usd:0,events:0,tokens:hD()},c[I].usd=Ma(c[I].usd+T.usd),c[I].events+=T.events,mD(c[I].tokens,T.tokens);for(let[I,T]of Object.entries(_.byProvider))l[I]||={usd:0,events:0},l[I].usd=Ma(l[I].usd+T.usd),l[I].events+=T.events;for(let I of J){let{usd:T}=gn(I);if(!T)continue;let F=fD(I.ts??0,o),W=b.get(F)??{t:F,total:0,byProvider:{}};W.total+=T;let ce=I.provider||"unknown";W.byProvider[ce]=(W.byProvider[ce]||0)+T,b.set(F,W),(E==null||F<E)&&(E=F)}x.push({id:$.id,name:$.name||$.id,archived:!!$.archivedAt,usd:_.totalUsd,turns:_.turns,providers:Object.keys(_.byProvider)});for(let[I,T]of Object.entries(_.byBox))v.push({trackId:$.id,trackName:$.name||$.id,boxId:I,...T})}let P=r.since!=null?fD(r.since,o):E,L=[];for(let $=P,C=0;$!=null&&$<r.until&&C<cX;$=dX($,o),C++){let U=b.get($);L.push(U?{t:$,total:Ma(U.total),byProvider:pX(U.byProvider)}:{t:$,total:0,byProvider:{}})}return x.sort(($,C)=>C.usd-$.usd),v.sort(($,C)=>C.usd-$.usd),{generatedAt:new Date().toISOString(),pricingBasis:"api-equivalent (subscription usage priced at public API rates)",pricing:wi(),window:r.key,since:r.since,until:r.until,bucketMs:o,series:L,fleet:{totalUsd:Ma(d),asRecordedUsd:Ma(m),turns:p,repricedTurns:w,unpricedTurns:h,unpricedModels:[...y],totalTokens:u,byModel:c,byProvider:l,tracksWithCost:x.length,tracksSilentLive:S},prior:a!=null?{totalUsd:Ma(g),since:r.since-a,until:r.since}:null,tracks:x.slice(0,50),boxes:v.slice(0,lX)}}oh();var fX=new Set(["cost.recorded","code.committed","code.rework","rework.cause.offered","rework.cause.answered"]),hX=20,mX=40;async function yD(e,t={}){let n=t.now??Date.now(),r=Fx({...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 V(l),d=0,p=cd(l);for(let w of u){if(!fX.has(w.type))continue;let m=w.type==="code.rework"?w.payload?.ts??w.ts:w.ts;w.type!=="rework.cause.answered"&&!o(m??0)||(w.type==="code.committed"&&d++,s.push(w.trackId?w:{...w,trackId:l.id}))}d&&i++;for(let w of l.boxes||[])a[`${l.id}/${w.name}`]={trackName:l.name||l.id,label:p[w.name]||w.name}}let c=WR(s,{boxMeta:a});return{generatedAt:new Date().toISOString(),window:r.key,since:r.since,until:r.until,reworkWindowDays:zo,decayEndDays:fb,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,hX),fixes:c.fixes.slice(0,mX)}}import wX from"node:fs";import bD from"node:fs/promises";import dd from"node:os";import gX from"node:path";ak();kt();var yX=1024*1024,Em=e=>Math.round(e/yX);async function bX(e){try{let t=await bD.statfs(e),n=t.blocks*t.bsize,r=n-t.bavail*t.bsize;return{diskUsedMb:Em(r),diskTotalMb:Em(n)}}catch{return{diskUsedMb:null,diskTotalMb:null}}}async function kX(){try{return(await sn()).filter(t=>t.isBostrat).length}catch{return null}}async function xX(){let e=0,t=!1;for(let n of["workspaces","worktrees"])try{let r=await bD.readdir(gX.join(zu,n),{withFileTypes:!0});e+=r.filter(o=>o.isDirectory()).length,t=!0}catch{}return t?e:null}async function kD({stateDir:e=zu,now:t=Date.now}={}){let n=dd.totalmem(),[r,o,s,a]=await Promise.all([Ah().catch(()=>null),bX(wX.existsSync(e)?e:dd.tmpdir()),kX(),xX()]),i=dd.cpus()?.length||null,c=dd.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?Em(n-r):null,memTotalMb:Em(n),...o,boxes:s,worktrees:a,procUptimeS:Math.round(process.uptime()),osUptimeS:Math.round(dd.uptime())}}Fb();be();wg();Gc();Nr();be();Nr();var SX=864e5;function vX(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=lr(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 xD(e,{days:t=14,tolerance:n=.005,now:r=Date.now()}={}){let o=r-t*SX,s={},a=0,i=0,c=[];for(let u of e||[]){let d=await V(u);for(let p of d){if(!p.ts||p.ts<o)continue;let w=vX(p,{tolerance:n});if(!w)continue;a++;let m=w.speed?`${w.model} (${w.speed})`:w.model,h=s[m]||={rows:0,divergent:0,asRecordedUsd:0,expectedUsd:0};h.rows++,h.asRecordedUsd+=w.asRecorded,h.expectedUsd+=w.expected,w.divergent&&(i++,h.divergent++,c.length<10&&c.push({track:u.name||u.id,...w}))}}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}}Bb();Lk();Rf();_t();yn();import wc from"node:fs/promises";import AX from"node:fs";import Mt from"node:path";import TX from"node:os";import{execFile as EX}from"node:child_process";import{promisify as _X}from"node:util";var IX=_X(EX),SD=process.env.BOSTRAT_STATE_DIR||Mt.join(process.env.HOME||TX.tmpdir(),".bostrat"),_m=!1,Ux=null;async function Hx(e,t){let n=await wc.stat(e).catch(()=>null);if(!n?.isFile())return!1;let r=await wc.stat(t).catch(()=>null);return r&&r.size===n.size&&r.mtimeMs>=n.mtimeMs?!1:(await wc.mkdir(Mt.dirname(t),{recursive:!0}),await wc.copyFile(e,t),!0)}var $X=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 Im(e,t,{skip:n=null}={}){let r=0,o=await wc.readdir(e,{withFileTypes:!0}).catch(()=>[]);for(let s of o){if($X.has(s.name)||n?.has(s.name))continue;let a=Mt.join(e,s.name);s.isDirectory()?r+=await Im(a,Mt.join(t,s.name)):s.isFile()&&(r+=await Hx(a,Mt.join(t,s.name))?1:0)}return r}async function vD({stateDir:e=SD,dest:t=process.env.BOSTRAT_SYNC_DIR||`${SD}-sync`,remote:n=process.env.BOSTRAT_STATE_REMOTE||null,tracks:r=null}={}){try{await wc.mkdir(t,{recursive:!0});let o=0;o+=await Hx(Mt.join(e,"tracks.json"),Mt.join(t,"tracks.json"))?1:0,o+=await Hx(Mt.join(e,"events.jsonl"),Mt.join(t,"events.jsonl"))?1:0,o+=await Im(Mt.join(e,"events"),Mt.join(t,"events")),o+=await Im(Mt.join(e,"memory"),Mt.join(t,"memory"));let s=new Set(["mocks"]);for(let u of r||[])!u?.cwd||!u?.id||(o+=await Im(Mt.join(u.cwd,".bostrat"),Mt.join(t,"workspaces",u.id,".bostrat"),{skip:s}));let a=(...u)=>IX("git",["-C",t,...u]);AX.existsSync(Mt.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 xw(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||_m))try{await a("push","-q",n,"HEAD:refs/heads/main"),l=!0,_m&&console.log("[state-sync] push recovered \u2014 off-box copy is current again"),_m=!1,Ux=null}catch(u){_m=!0;let d=(u?.stderr||u?.message||String(u)).trim().split(`
|
|
943
943
|
`).slice(-3).join(" | ").slice(0,300);d!==Ux&&(Ux=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)}}}Ek();Mn();Ds();kt();Mc();import{execFile as RX}from"node:child_process";import{promisify as OX}from"node:util";import{randomUUID as MX}from"node:crypto";import CX from"node:fs";import NX from"node:os";import PX from"node:path";var hs=OX(RX),$m=e=>new Promise(t=>setTimeout(t,e)),ms=Hw,Wx=process.env.BOSTRAT_USAGE_PROBE_CWD||PX.join(NX.homedir(),".bostrat","usage-probe"),DX=Number(process.env.BOSTRAT_USAGE_IDLE_REAP_MS)||5*6e4,BX=Number(process.env.BOSTRAT_USAGE_PANEL_TIMEOUT_MS)||15e3,LX=Number(process.env.BOSTRAT_USAGE_READY_TIMEOUT_MS)||45e3,AD=Number(process.env.BOSTRAT_USAGE_CACHE_MS)||2e4,fs=null,pd=null,fd=null;async function jX(){try{return await hs(oe,se("has-session","-t",ms)),!0}catch{return!1}}function FX(){fs&&clearTimeout(fs),fs=setTimeout(()=>UX().catch(()=>{}),DX),fs.unref&&fs.unref()}async function UX(){fs&&(clearTimeout(fs),fs=null);try{await hs(oe,se("kill-session","-t",ms))}catch{}}async function HX(){let e=Date.now()+LX;for(;;){let t=await qx().catch(()=>"");if(/for agents|for shortcuts|bypass permissions on/i.test(t)){await $m(500);return}if(Date.now()>e)throw new Error("usage probe didn't reach the prompt (trust/onboarding may be blocking)");await $m(500)}}async function WX(){if(await jX())return;if(!await So())throw new Error("host tmux server not running \u2014 start globo-tmux.service");CX.mkdirSync(Wx,{recursive:!0}),await fo(Wx);let e=MX();await hs(oe,se("new-session","-d","-s",ms,"-c",Wx,"-x","200","-y","60",...el()));let t=`${jw} --session-id ${e}`;await hs(oe,se("send-keys","-t",ms,t,"Enter")),await HX()}async function qx(){let{stdout:e}=await hs(oe,se("capture-pane","-t",ms,"-p"));return e}async function qX(){await WX(),await hs(oe,se("send-keys","-t",ms,"-l","/usage")),await hs(oe,se("send-keys","-t",ms,"Enter"));let e=Date.now()+BX,t="";for(;await $m(400),t=await qx(),!(/Current\s+(session|week)/i.test(t)||/\d+%\s*used/i.test(t)||Date.now()>e););return await $m(900),t=await qx(),await hs(oe,se("send-keys","-t",ms,"Escape")).catch(()=>{}),FX(),t}function GX(e){let t=String(e||"").split(`
|
|
944
944
|
`).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 KX(e){let t=String(e||"").split(`
|
|
945
945
|
`).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 TD({fresh:e=!1}={}){return!e&&pd&&Date.now()-pd.at<AD?pd.data:fd||(fd=(async()=>{try{let t=await qX(),n=GX(t),r={...n,contributors:KX(t),subscription:!!(n.session||n.week||n.weekModels),capturedAt:Date.now()};return pd={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 pd={at:Date.now()-(AD-3e3),data:n},n}finally{fd=null}})(),fd)}var VX=262144;function zX(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 JX=new Set([300]),YX=new Set([10080]);function XX(e){let t=Number(e);return!Number.isFinite(t)||t<=0?null:JX.has(t)?"session":YX.has(t)?"week":"other"}function ZX(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 QX(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?zX((o-n)/1e3):null,resetsAt:o}}var hd=e=>({session:null,week:null,other:null,planType:null,credits:null,limitReached:null,sawTokenCount:e});function e9(e,t=Date.now()){let n=String(e||"").split(`
|
|
946
|
-
`),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 hd(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=hd(r);[c.primary,c.secondary].forEach((w,m)=>{let
|
|
947
|
-
`,{mode:384}),Mm.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function md(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 PD(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:CD.timingSafeEqual(n,r)}function DD(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 a9=[/^\/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/],i9=e=>a9.some(t=>t.test(e));function BD({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=DD(o);return PD(c,e)?a():i9(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||md(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 LD(e,t,{enforce:n=!0}={}){return!n||PD(DD(e),t)?!0:md(e)}$n();xh();var c9=30,l9=6e4;function jD({kind:e,env:t=process.env}={}){let n=String(t.BOSTRAT_VIEW_IDLE_STOP_MIN??"").trim().toLowerCase();if(n){if(n==="off")return 0;let r=Number(n);if(Number.isFinite(r)&&r>=0)return Math.round(r*6e4)}return e==="container"?0:c9*6e4}var FD=e=>e&&e.origin!=="detected"&&(e.state==="live"||e.state==="unhealthy");function u9({views:e=[],tracks:t=[],busyTracks:n=new Set,lastBusyAt:r=new Map,now:o=Date.now(),idleMs:s,since:a=0}={}){if(!(s>0))return[];let i=new Map(t.map(l=>[l?.id,l])),c=[];for(let l of e){if(!FD(l)||n.has(l.trackId))continue;let u=Math.max(a,Number(l.lastAccessAt)||0,Number(l.createdAt)||0,Number(i.get(l.trackId)?.lastResponseAt)||0,r.get(l.trackId)||0);o-u>=s&&c.push({view:l,idleSince:u})}return c}function UD({idleMs:e,input:t,listViews:n=null,stop:r,onStopped:o=null,now:s=Date.now,since:a=s(),tickMs:i=l9,setIntervalImpl:c=setInterval,clearIntervalImpl:l=clearInterval,log:u=console}={}){let d=new Map,p=null,w=!1,m=async()=>{if(w||!(e>0))return[];w=!0;try{if(n&&!(await n()).some(FD))return[];let{tracks:
|
|
946
|
+
`),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 hd(r);if(c.primary||c.secondary){let l=Date.parse(a.timestamp)||null,u=hd(r);[c.primary,c.secondary].forEach((w,m)=>{let h=QX(w,l,t);if(!h)return;let g=XX(w.window_minutes);g===null&&(g=m===0?"session":"week"),g==="session"&&!u.session?u.session=h:g==="week"&&!u.week?u.week=h:(u.other??=[]).push({label:ZX(w.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{...hd(r),session:l(c.primary_used_percent),week:l(c.secondary_used_percent)}}return hd(r)}return hd(r)}async function Gx(e){let t={provider:"codex",supported:!0,contributors:null};try{let n=await Ns(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,VX),o=e9(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 ED(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 Rm({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 Gx(i);if(c.subscription){a=c;break}(!a||a.error&&!c.error)&&(a=c)}r.push(a||await Gx(null))}return n.has("cursor")&&r.push(await Rm({agent:"cursor"})),{providers:r,capturedAt:Date.now()}}async function Rm(e,{fresh:t=!1}={}){let n=e?.agent||"claude";return n==="codex"?Gx(e):n==="cursor"?{provider:"cursor",supported:!1,subscription:!1,session:null,week:null,contributors:null,capturedAt:Date.now()}:{provider:"claude",supported:!0,...await TD({fresh:t})}}er();_t();_t();function t9(e=process.env){return!!(Ue(e)&&e.BOSTRAT_PLANE_TOKEN)}var n9=e=>({authorization:`Bearer ${e.BOSTRAT_PLANE_TOKEN||""}`}),Om=(e,t)=>Object.assign(new Error(e),{status:t});async function _D(e,t){if(!t9(t))throw Om("node is not plane-linked \u2014 Gmail unavailable",503);let n;try{n=await fetch(`${Ue(t)}${e}`,{headers:n9(t)})}catch(o){throw Om(`plane unreachable \u2014 Gmail unavailable (${o?.message||o})`,503)}let r=await n.json().catch(()=>({}));if(!n.ok)throw Om(r?.error||`plane replied ${n.status}`,n.status);return r}async function ID(e,{max:t=10,env:n=process.env}={}){let r=new URLSearchParams({q:e||""});return t&&r.set("max",String(t)),(await _D(`/v1/gmail/messages?${r.toString()}`,n)).messages||[]}async function $D(e,{env:t=process.env}={}){if(!e)throw Om("message id required",400);return(await _D(`/v1/gmail/messages/${encodeURIComponent(e)}`,t)).message}Jl();Gf();function Kx(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 r9(e){let[t,n]=e.split("/"),r=Kx(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 RD(e){return(e||"").split(",").map(t=>t.trim()).filter(Boolean).map(r9).filter(Boolean)}function o9(e){let t=e.headers["fly-client-ip"];return typeof t=="string"&&t.trim()?t.trim():(e.socket&&e.socket.remoteAddress||"").replace(/^::ffff:/,"")}function OD(e){let t=RD(e),n=String(e||"").trim().toLowerCase()==="open";return{open:n,clientIp:o9,allowed(r){if(n)return!0;let o=Kx((r||"").replace(/^::ffff:/,""));return o==null?!1:t.some(s=>s(o))}}}function MD(e,t){let n=RD(e);return{active:n.length>0,allows(r){if(!n.length)return!1;let o=(r.socket&&r.socket.remoteAddress||"").replace(/^::ffff:/,""),s=Kx(o);if(s==null||!n.some(i=>i(s)))return!1;let a=t(r);return!!(a&&a.view)}}}import CD from"node:crypto";import Mm from"node:fs";import s9 from"node:path";function ND(e=process.env,{stateDir:t=zu,log:n=console}={}){let r=String(e.BOSTRAT_NODE_API_TOKEN||"").trim();if(r)return r;let o=s9.join(t,"api-token");try{let a=Mm.readFileSync(o,"utf8").trim();if(a)return a}catch{}let s=CD.randomBytes(32).toString("base64url");try{Mm.mkdirSync(t,{recursive:!0}),Mm.writeFileSync(o,s+`
|
|
947
|
+
`,{mode:384}),Mm.chmodSync(o,384)}catch(a){n.error?.(`[bostrat-agent] could not persist the node API token: ${a?.message||a}`)}return s}function md(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 PD(e,t){if(!e||!t)return!1;let n=Buffer.from(String(e)),r=Buffer.from(String(t));return n.length!==r.length?!1:CD.timingSafeEqual(n,r)}function DD(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 a9=[/^\/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/],i9=e=>a9.some(t=>t.test(e));function BD({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=DD(o);return PD(c,e)?a():i9(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||md(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 LD(e,t,{enforce:n=!0}={}){return!n||PD(DD(e),t)?!0:md(e)}$n();xh();var c9=30,l9=6e4;function jD({kind:e,env:t=process.env}={}){let n=String(t.BOSTRAT_VIEW_IDLE_STOP_MIN??"").trim().toLowerCase();if(n){if(n==="off")return 0;let r=Number(n);if(Number.isFinite(r)&&r>=0)return Math.round(r*6e4)}return e==="container"?0:c9*6e4}var FD=e=>e&&e.origin!=="detected"&&(e.state==="live"||e.state==="unhealthy");function u9({views:e=[],tracks:t=[],busyTracks:n=new Set,lastBusyAt:r=new Map,now:o=Date.now(),idleMs:s,since:a=0}={}){if(!(s>0))return[];let i=new Map(t.map(l=>[l?.id,l])),c=[];for(let l of e){if(!FD(l)||n.has(l.trackId))continue;let u=Math.max(a,Number(l.lastAccessAt)||0,Number(l.createdAt)||0,Number(i.get(l.trackId)?.lastResponseAt)||0,r.get(l.trackId)||0);o-u>=s&&c.push({view:l,idleSince:u})}return c}function UD({idleMs:e,input:t,listViews:n=null,stop:r,onStopped:o=null,now:s=Date.now,since:a=s(),tickMs:i=l9,setIntervalImpl:c=setInterval,clearIntervalImpl:l=clearInterval,log:u=console}={}){let d=new Map,p=null,w=!1,m=async()=>{if(w||!(e>0))return[];w=!0;try{if(n&&!(await n()).some(FD))return[];let{tracks:h=[],views:g=[],queuedOf:y,jobsOf:b,prPendingOf:x}=await t(),v=new Set;for(let P of h)K0(P,{queuedOf:y,jobsOf:b,prPendingOf:x}).length&&(v.add(P.id),d.set(P.id,s()));let S=u9({views:g,tracks:h,busyTracks:v,lastBusyAt:d,now:s(),idleMs:e,since:a}),E=[];for(let{view:P,idleSince:L}of S)try{await r(P.id,{reason:"idle",idleMs:e}),E.push(P),u.log?.(`[views] stopped "${P.name}" (${P.slug}) \u2014 unused for ${Math.round((s()-L)/6e4)} min with no agent turn in flight on Track ${P.trackId}`)}catch($){u.error?.(`[views] idle stop of "${P.name}" failed: ${$?.message||$}`)}if(E.length)try{await o?.(E)}catch{}return E}catch{return[]}finally{w=!1}};return{start(){return p||!(e>0)?!1:(p=c(m,i),p.unref?.(),!0)},stop(){p&&l(p),p=null},tick:m}}xh();import d9 from"node:http";import p9 from"node:net";function wd(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 Cm(e){let t=wd(e.headers.host);return t?{slug:t,view:Zb(t)}:null}var f9=e=>String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),h9=e=>{let t=f9(e.name);return`<!doctype html><meta charset="utf-8">
|
|
948
948
|
<meta http-equiv="refresh" content="3">
|
|
949
949
|
<title>${t} \u2014 starting</title>
|
|
950
950
|
<body style="font-family:system-ui;background:#0b0e14;color:#dce3f0;display:grid;place-items:center;height:100vh;margin:0">
|
|
@@ -957,18 +957,18 @@ bostrat: no live view "${s}"\r
|
|
|
957
957
|
\r
|
|
958
958
|
`),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 Vx(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=wx();if(r)return{proto:"https",host:r,source:"learned"};let o=gx();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:wd(s)&&Zb(a[0])?a.slice(1).join("."):s,source:"request"}}function GD(e,t){return bm(Vx(t),e.slug)}function KD({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
|
|
959
959
|
\r
|
|
960
|
-
`),a.destroy();return}t(s,a,i)}}}function VD(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}Wi();hk();$h();Rl();be();import zD from"node:os";import{randomUUID as Jx}from"node:crypto";var m9=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||zD.hostname(),nodeName:e.BOSTRAT_NODE_NAME||zD.hostname()});var JD=32768,YD=120,XD=1e3,ZD=new Set(["claude","codex","cursor"]),w9=new Set(["off","transition","nag"]),g9=[[0,59],[0,23],[1,31],[1,12],[0,6]];function y9(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=g9[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 Jn=e=>String(e??"").trim(),Ca={name(e){let t=Jn(e);if(!t)throw new Error("a loop needs a name");if(t.length>YD)throw new Error(`name is too long (${t.length}); cap is ${YD}`);return t},schedule(e){let t=Jn(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!y9(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=Jn(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>JD)throw new Error(`prompt is too long (${t.length} chars); cap is ${JD}`);return t},expectation(e){let t=Jn(e)||null;if(t&&t.length>XD)throw new Error(`expectation is too long (${t.length}); cap is ${XD}`);return t},notify(e){let t=Jn(e)||"off";if(!w9.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=Jn(typeof t=="string"?t:t?.provider)||"claude";if(!ZD.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...ZD].join(", ")}`);let r=typeof t=="object"&&t&&Jn(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 b9(e,t){let n=e&&typeof e=="object"?e:{},r=Ca.name(n.name),o=Ca.schedule(n.schedule),s=Ca.prompt(n.prompt),a=Ca.expectation(n.expectation),i=Ca.notify(n.notify),c=Ca.assignment(n.assignment),l=Jn(t?.workspace?.repo)||Jn(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}=m9();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:d||null}}async function e1(e,t){let n=b9(t,e),r=Jx();return await D({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 t1(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await V({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 D({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 D({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 D({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 zx=["name","schedule","prompt","expectation","notify","assignment","enabled"],k9=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function n1(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 r1(e,t){let n=Jn(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 x9(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=>!zx.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: ${zx.join(", ")}`)}let o={};for(let a of zx){if(!(a in n))continue;let i=Ca[a](n[a]);(a==="assignment"?k9(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 o1(e,t,n){let r=n1(t),{patch:o,changed:s}=x9(n,r),a=Jx(),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 D({id:e.id,cwd:e.cwd},{type:"loop.update.offered",actor:"system",source:"orchestrator",payload:i}),i}var QD=600;async function s1(e,t,n){let r=Jn(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>QD)throw new Error(`reason is too long (${r.length}); cap is ${QD}`);let o=n1(t),s=Jx(),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 D({id:e.id,cwd:e.cwd},{type:"loop.delete.offered",actor:"system",source:"orchestrator",payload:a}),a}var a1=async(e,t,n)=>{if(!n)throw new Error("proposalId required");let r=await V({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 i1(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 a1(e,"loop.update.offered",t)).payload,a={id:e.id,cwd:e.cwd};return n==="applied"&&await D(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 D(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 c1(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 a1(e,"loop.delete.offered",t)).payload,s={id:e.id,cwd:e.cwd};return(n==="delete"||n==="pause")&&await D(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 D(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 S9}from"node:crypto";var Zx=20,v9=300,Yx=120,l1=120,u1=2e3,Nm=new Set(["build","ops","debt","spike"]),d1=new Set(["active","done","abandoned"]),Qx=new Set(["circuit.create","circuit.update","circuit.delete"]),A9=new Set(["person.create","slot.create","slot.update","slot.delete","reservation.create","reservation.update","reservation.delete"]),gd=new Set([...Qx,...A9]),T9=["name","description","status","type"],E9=["person","startDate","endDate","estUsd"],_9=["person","label","startDate","endDate"],I9=/^\d{4}-\d{2}-\d{2}$/,fn=e=>String(e??"").trim(),eS=e=>typeof e=="string"&&e.startsWith("@"),h1=864e5;function m1(e){let t=Date.parse(`${e}T00:00:00Z`),n=new Date(t).getUTCDay();return new Date(t-(n+6)%7*h1).toISOString().slice(0,10)}function $9(e){return new Date(Date.parse(`${m1(e)}T00:00:00Z`)+6*h1).toISOString().slice(0,10)}var p1=(e,t)=>{let n=fn(e);if(!I9.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 R9(e,t){let n=p1(e,"startDate"),r=p1(t,"endDate");if(r<n)throw new Error(`endDate ${r} is before startDate ${n}`);let o=m1(n),s=$9(r);return{startDate:o,endDate:s,snapped:o!==n||s!==r}}var f1=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},ws=(e,t,n)=>{let r=fn(e);if(r.length>t)throw new Error(`${n} is too long (${r.length}); cap is ${t}`);return r};function Xx(e,t){let n=fn(t);if(!n)throw new Error("a circuit name or id is required");if(eS(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 O9(e,t){let n=fn(t);if(!n)throw new Error('a person is required \u2014 "me", a person id, or a row label');if(n==="me"||eS(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 M9(e,t,{allow:n=gd}={}){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>Zx)throw new Error(`too many ops (${o.length}); cap is ${Zx} \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,w=!1,m=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)},f=x=>{x.id&&(u[x.id]=x.label)},g=(x,v)=>{let S=fn(x);if(!S)return null;if(d.has(S))throw new Error(`ref "${S}" is used by two ops \u2014 each ref names one thing`);return d.add(S),u[`@${S}`]=v,S},y=o.map((x,v)=>{let S=x&&typeof x=="object"?x:{},E=fn(S.op),P=`op ${v+1}`;if(!gd.has(E))throw new Error(`${P}: unknown op "${E}" \u2014 one of ${[...gd].join(", ")}`);if(!n.has(E))throw new Error(`${P}: "${E}" isn't a circuit op \u2014 roadmap changes go through \`bostrat-roadmap propose\` (one card, either CLI)`);let L=_=>{throw new Error(`${P} (${E}): ${_}`)},$=_=>{let I=S.set&&typeof S.set=="object"&&!Array.isArray(S.set)?S.set:null;I||L("needs a `set` object naming the fields to change");let T=Object.keys(I).filter(F=>!_.includes(F));return T.length&&L(`unknown field(s) ${T.join(", ")} \u2014 settable: ${_.join(", ")}`),Object.keys(I).length||L("`set` names no fields"),I},C=_=>{let{startDate:I,endDate:T,snapped:F}=R9(_.startDate,_.endDate);return F&&(p=!0),{startDate:I,endDate:T,snapped:F}},U=_=>{let I=O9(a,_);return fn(_)==="me"&&(w=!0),f(I),{key:I.id??fn(_),label:I.label}},J=(_,I,T,F,W)=>{let ce=fn(_);ce||L(`needs a ${F} id`);let z=I.find(Ke=>Ke[T]===ce);return z||L(`no ${F} "${ce}" \u2014 see \`bostrat-roadmap ls\``),W[ce]={...z},z};switch(E){case"circuit.create":{let _=ws(S.name,l1,"name");_||L("a circuit needs a name");let I=fn(S.type)||"build";Nm.has(I)||L(`bad type "${I}" (${[...Nm].join(" | ")})`);let T=s.find(W=>String(W.name).toLowerCase()===_.toLowerCase());T&&L(`a circuit named "${T.name}" already exists (${T.id}) \u2014 update it instead of making a twin`);let F=g(S.ref,_);return{op:E,...F?{ref:F}:{},name:_,description:ws(S.description,u1,"description"),type:I}}case"circuit.update":{let _=Xx(s,S.circuit);_.id||L("can't update a circuit created in the same plan \u2014 set its fields on the create op"),m(_);let I=$(T9),T={};if(I.name!==void 0){let F=ws(I.name,l1,"name");F||L("name can't be blank"),F!==_.name&&(T.name=F)}return I.description!==void 0&&(T.description=ws(I.description,u1,"description")),I.status!==void 0&&(d1.has(I.status)||L(`bad status "${I.status}" (${[...d1].join(" | ")})`),I.status!==_.status&&(T.status=I.status)),I.type!==void 0&&(Nm.has(I.type)||L(`bad type "${I.type}" (${[...Nm].join(" | ")})`),I.type!==(_.type??"build")&&(T.type=I.type)),Object.keys(T).length||L("nothing would change \u2014 the set equals the circuit's current values"),{op:E,circuit:_.id,name:_.name,set:T}}case"circuit.delete":{let _=Xx(s,S.circuit);_.id||L("can't delete a circuit created in the same plan"),m(_);let I=o.some((T,F)=>F<v&&fn(T?.op)==="circuit.update"&&T?.set?.status&&T.set.status!=="active"&&fn(T?.circuit)===fn(S.circuit));return _.status==="active"&&!I&&L(`\u201C${_.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:E,circuit:_.id,name:_.name,status:_.status}}case"person.create":{let _=ws(S.label,Yx,"label");_||L("a person row needs a label");let I=a.find(F=>String(F.label).toLowerCase()===_.toLowerCase());I&&L(`a roadmap row labelled "${I.label}" already exists (${I.personId})`);let T=g(S.ref,_);return{op:E,...T?{ref:T}:{},label:_}}case"slot.create":{let _=Xx(s,S.circuit);m(_);let I=U(S.person),T=C(S);return{op:E,circuit:_.id??_.ref,circuitName:_.name,person:I.key,personLabel:I.label,...T,estUsd:f1(S.estUsd)}}case"slot.update":{let _=J(S.slot,i,"slotId","slot",l.slots),I=$(E9),T={};if(I.person!==void 0){let W=U(I.person);T.person=W.key,T.personLabel=W.label}if(I.startDate!==void 0||I.endDate!==void 0){let W=C({startDate:I.startDate??_.startDate,endDate:I.endDate??_.endDate});W.startDate!==_.startDate&&(T.startDate=W.startDate),W.endDate!==_.endDate&&(T.endDate=W.endDate)}I.estUsd!==void 0&&(T.estUsd=f1(I.estUsd)),Object.keys(T).length||L("nothing would change");let F=s.find(W=>W.id===_.circuitId);return{op:E,slot:_.slotId,circuitName:F?.name??null,set:T}}case"slot.delete":{let _=J(S.slot,i,"slotId","slot",l.slots),I=s.find(T=>T.id===_.circuitId);return{op:E,slot:_.slotId,circuitName:I?.name??null,startDate:_.startDate,endDate:_.endDate}}case"reservation.create":{let _=U(S.person),I=ws(S.label,Yx,"label");return I||L("a reservation needs a label (Leave, Support rotation, \u2026)"),{op:E,person:_.key,personLabel:_.label,label:I,...C(S)}}case"reservation.update":{let _=J(S.reservation,c,"reservationId","reservation",l.reservations),I=$(_9),T={};if(I.person!==void 0){let F=U(I.person);T.person=F.key,T.personLabel=F.label}if(I.label!==void 0){let F=ws(I.label,Yx,"label");F||L("label can't be blank"),F!==_.label&&(T.label=F)}if(I.startDate!==void 0||I.endDate!==void 0){let F=C({startDate:I.startDate??_.startDate,endDate:I.endDate??_.endDate});F.startDate!==_.startDate&&(T.startDate=F.startDate),F.endDate!==_.endDate&&(T.endDate=F.endDate)}return Object.keys(T).length||L("nothing would change"),{op:E,reservation:_.reservationId,label:_.label,set:T}}case"reservation.delete":{let _=J(S.reservation,c,"reservationId","reservation",l.reservations);return{op:E,reservation:_.reservationId,label:_.label,startDate:_.startDate,endDate:_.endDate}}default:return L("unhandled op")}});y.forEach((x,v)=>{for(let S of[x.circuit,x.person,x.set?.person])if(eS(S)&&!d.has(String(S).slice(1)))throw new Error(`op ${v+1} (${x.op}): unknown ref "${S}" \u2014 no earlier op in this plan creates it`)});let b=a.some(x=>x.kind==="user"&&x.userId);return{why:ws(r.why,v9,"why"),ops:y,base:l,resolved:u,snapped:p,createsMeRow:w&&!b}}async function w1(e,t,n,r={}){let o=M9(t,n,r),s=S9(),a={ts:Date.now(),proposalId:s,...o};return await D({id:e.id,cwd:e.cwd},{type:"planning.change.offered",actor:"system",source:"orchestrator",payload:a}),a}var C9=async(e,t)=>{if(!t)throw new Error("proposalId required");let n=await V({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 g1(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 C9(e,t),s={id:e.id,cwd:e.cwd},a=o.payload;return n==="applied"&&await D(s,{type:"planning.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,why:a.why??"",results:Array.isArray(r)?r.slice(0,Zx+1):[]}}),await D(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}}ph();be();bo();be();jn();$h();var y1=10,b1=200,N9=120,P9=24,x1=/^\d{4}-\d{2}-\d{2}$/;function tS(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var D9=(e=Date.now())=>new Date(e).toISOString().slice(0,10),Ct=(e,t="i")=>new RegExp(e,t),B9=[{re:Ct("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:Ct("\\bSPC\\b",""),reason:"business (SPC)"},{re:Ct("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:Ct("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:Ct("\\bReplicas\\b",""),reason:"competitor research"},{re:Ct("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:Ct("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:Ct("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],L9=[Ct("\\bSPC\\b",""),Ct("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),Ct("competitor|cloudcli|\\bkiro\\b"),Ct("\\bReplicas\\b",""),Ct("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),Ct("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),Ct("(^|[^\\w&])#\\d+\\b"),Ct("\\btrack/[\\w.-]+")];function j9({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of B9)if(o.test(n)||o.test(r))return s;return null}function k1(e){let t=String(e||"");for(let n of L9){let r=n.exec(t);if(r)return r[0].trim()}return null}function S1(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 F9=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function U9(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Tu(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(`
|
|
961
|
-
`)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,N9)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${P9}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=F9.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=k1(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>b1)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${b1}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=k1(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>y1)throw new Error(`${r.length} bullets \u2014 over the ${y1}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function H9(e,{repos:t=tS()}={}){let n=new Set(t);return(await Ln()).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:j9({title:r.title,headRef:r.headRef})}))}async function v1(e,t){let n=await H9(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function A1(e,{md:t,day:n=null}){let r=U9(t),o=n==null||n===""?D9():String(n);if(!x1.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await D({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 T1(e,{day:t}){let n=String(t||"");if(!x1.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await D({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}}pr();jn();Vo();be();pr();_t();Vr();jn();Jl();ah();Gf();Vs();yn();import{execFile as e7}from"node:child_process";import{promisify as t7}from"node:util";var W9=new Set(["pull_request","check_suite","workflow_run","push"]),q9=/^[^/\s]+\/[^/\s]+$/,G9=500,nS=new Set,rS=[],Pm=new Map,En={hourStart:0,byEvent:{},duplicates:0,rejected:0};function oS(e,t,n){let r=Math.floor(e/36e5)*36e5;r!==En.hourStart&&(En.hourStart=r,En.byEvent={},En.duplicates=0,En.rejected=0),t==="accepted"?En.byEvent[n]=(En.byEvent[n]||0)+1:En[t]+=1}function K9(e){if(!e||typeof e!="object"||e.forge!=="github"||typeof e.event!="string"||!W9.has(e.event)||typeof e.repo!="string"||!q9.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 E1(e,{now:t=Date.now(),onAccept:n=null,log:r=console}={}){let o=K9(e);if(!o)return oS(t,"rejected"),{ok:!1,error:"malformed github event envelope"};if(o.deliveryId){if(nS.has(o.deliveryId))return oS(t,"duplicates"),{ok:!0,duplicate:!0,envelope:o};for(nS.add(o.deliveryId),rS.push(o.deliveryId);rS.length>G9;)nS.delete(rS.shift())}let s=o.repo.toLowerCase(),a=Pm.get(s)||{lastDeliveryAt:0,count:0};a.lastDeliveryAt=t,a.count+=1,Pm.set(s,a),oS(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 V9(e,t=Date.now()){let n=Pm.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 _1=1440*6e4;function sS(e,t=Date.now()){let n=V9(e,t);return n.covered&&n.ageMs<_1}function I1(e=Date.now()){let t={};for(let[n,r]of Pm)t[n]={lastDeliveryAt:r.lastDeliveryAt,count:r.count,covered:e-r.lastDeliveryAt<_1};return{hourStart:En.hourStart,byEvent:{...En.byEvent},duplicates:En.duplicates,rejected:En.rejected,repos:t}}be();jn();er();Vr();yn();function $1(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function z9(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var J9=new Set(["merged","closed","lost"]);function Y9(e,t){if(!e?.blocked)return null;let n=$1(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 X9(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function Z9(e,t,n,r,o){return(await V(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 Q9(e,t,n){await D({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 Dm(e,t={}){let{now:n=Date.now(),slugOf:r=Re,lookup:o=pt,note:s=T$,tracks:a=async()=>(await xe()).filter(d=>!He(d)),asked:i=Z9,emitChange:c=Q9}=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 w of d.prs)try{if(!z9(w))continue;let m=await o(p,w.number).catch(()=>null);if(!m?.trackId||J9.has(m.state))continue;let{prev:f}=await s(p,w.number,{blocked:$1(w),sha:w.headSha??null,at:n});if(!f)continue;let g=Y9(f,w);if(!g||X9(m,g.change))continue;u??=new Map((await a()).map(v=>[v.id,v]));let y=u.get(m.trackId);if(!y)continue;let b=w.headSha??null;if(await i(y,g.change,w.number,b,f.at||0))continue;let x={number:Number(w.number),url:w.url||m.url,title:w.title||m.title,branch:w.headRefName||m.headRef,repo:p,sha:b,delegated:!1,reason:g.reason};g.change==="ci-fixed"?x.passed=w.checks.passed:x.base=w.baseRefName||null,await c(y,g.change,x),l.push({change:g.change,number:w.number,reason:g.reason})}catch{}}return l}var pS=t7(e7),j1=3e4,n7=30*6e4,r7=j1,o7=10*6e4,s7=10080*6e4,a7=60*6e4,R1=8,F1=1440*6e4,i7=3,U1="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",lS=60*6e4,c7=15*6e4,l7=9e4,u7=1440*6e4,bc=new Map,yd=new Map,d7=360*6e4,p7=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}),f7=/could not resolve|not found|no pull requests?/i,h7=e=>f7.test(String(e?.message||e||""));function m7(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<lS)}var O1={fast:r7,slow:o7,decay:a7};function M1(e,t,n=sS){return H1(e,t,{grace:0})||!n(e.repo,t)&&(e.armedAt&&t-e.armedAt<n7||m7(e,t))?"fast":t-(e.firstSeen||0)>s7?"decay":"slow"}function xd(e,t,n,r){let o=e.lanes?.get(me(t.repo,t.number))||{};return $i({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function w7(e,t){Fr("watch");try{let{stdout:n}=await pS("gh",["pr","view",String(t),"--repo",e,"--json",U1],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await tr({slug:e})}});return JSON.parse(n||"null")}catch(n){throw qo(n)&&Go(n),n}}async function g7(e){Fr("watch");try{let{stdout:t}=await pS("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",U1],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await tr({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw qo(t)&&Go(t),t}}async function y7(){let e=new Map;for(let t of await xe().catch(()=>[]))e.set(t.id,t);return e}async function b7(e,t){await D({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}}),await sh(e,t).catch(()=>{})}async function k7(e,t){let n=await ia(e);return n?Mi(n,t):null}async function x7(e,t,n){let r=await ia(e);if(!r)throw new Error(`no local checkout for ${e}`);return Ci(r,t,{method:n})}async function S7(e,t){let n=await ia(e);if(!n)throw new Error(`no local checkout for ${e}`);return Ql(n,t)}async function v7(e,t){await D({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 gc(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 A7=10*6e4,C1=2*6e4,T7=2,E7=5*6e4,Bm=new Map,uS=new Map,bd=new Map,dS=new Map;function yc(e,t){let n=dS.get(e)??t;return dS.set(e,n),t-n>E7?!1:(bc.delete(e),!0)}function aS(e){dS.delete(e)}function _7(e,t,n,r){let o=n.headSha||null;if(!o||t==null)return!0;if(o!==t)return Bm.set(e,{sha:o,at:r}),!1;if(uS.get(e)===o)return!0;let s=Bm.get(e);if(s?.sha===o)return r-s.at>=C1;let a=Date.parse(n.updatedAt||"")||0;return a&&r-a<C1?(Bm.set(e,{sha:o,at:r}),!1):!0}function iS(e,t,n,r){let o=bd.get(e),s=o&&o.kind===t&&o.sha===(n||null)?o.count+1:1;return bd.set(e,{sha:n||null,kind:t,message:r,count:s}),s>=T7}async function I7(e,t,n,{isHead:r=!0,prevHead:o=null}={}){let s=n.now??Date.now(),a=me(e.repo,e.number),i=e.autoMerge?.armedAt||0;if(i&&s-i>F1){await gc(e,null,t,n,"auto-merge expired \u2014 checks never settled within 24h");return}let c=await n.detail(e.repo,e.number).catch(()=>null);if(!c)return;if(c.headSha&&e.lastHeadSha!==c.headSha&&await Xy(e.repo,e.number,c.headSha).catch(()=>{}),c.checks.failed>0){let u=c.checks.failing.map(d=>d.name).join(", ");await gc(e,c,t,n,`check${c.checks.failed===1?"":"s"} failed: ${u}`);return}if(c.mergeable==="CONFLICTING"){await gc(e,c,t,n,`conflicts with ${c.baseRefName}`);return}if(!c.checks.total){let u=Math.max(e.autoMerge?.armedAt||0,Date.parse(c.updatedAt||"")||0);if(s-u<A7)return;if(!iS(a,"no-checks",c.headSha,null)){yc(a,s);return}await gc(e,c,t,n,c.checks.unavailable?"this token can't read the checks":"no CI checks appeared");return}if(c.checks.pending>0){c.headSha&&uS.set(a,c.headSha),bd.delete(a),aS(a);return}if(c.mergeable==="UNKNOWN"||c.mergeStateStatus==="UNKNOWN"){yc(a,s);return}if(c.isDraft)return;if(!_7(a,o,c,s)){yc(a,s);return}let l=await n.lookup(e.repo,e.number).catch(()=>null);if(l?.autoMerge){if(c.mergeStateStatus==="BEHIND"){if(!r)return;try{await n.updateBranch(e.repo,e.number),bd.delete(a),aS(a)}catch(u){let d=String(u?.message||u).trim();if(/no new commits|already up.to.date/i.test(d))return;if(!iS(a,"update",c.headSha,d)){yc(a,s);return}await gc(e,c,t,n,d||`couldn't update with ${c.baseRefName}`)}return}if(n.mergedRepos?.has(String(e.repo||"").toLowerCase())){yc(a,s);return}try{await n.merge(e.repo,e.number,l.autoMerge.method||"merge")}catch(u){let d=String(u?.message||u).trim();if(/already merged|not open|is closed/i.test(d))return;if(!iS(a,"merge",c.headSha,d)){yc(a,s);return}await gc(e,c,t,n,d||"merge failed");return}return n.mergedRepos?.add(String(e.repo||"").toLowerCase()),bd.delete(a),aS(a),Bm.delete(a),uS.delete(a),await W1(e,{...c,state:"MERGED"},t,n,{change:"auto-merged",githubAt:c.checks.settledAt||null}),"merged"}}async function kc(e,t,n){await D({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 $7(e,t){try{return await pS("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function kd(e,t,n,r=()=>!0){return(await V(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var xc=(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 H1(e,t,{grace:n=l7}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=u7}async function R7(e,t,n,r){let o=r.now??Date.now();if(!H1(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||He(s))return!1;let a=(s.boxes||[]).find(d=>d.name===s.leadBox);return await(r.midTurn??Ks)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await V(s).catch(()=>[])).some(d=>d.type==="pr.state.changed"&&d.payload?.number===Number(e.number))?(await(r.claim??Lr)(e.repo,e.number).catch(()=>null),!1):await(r.claim??Lr)(e.repo,e.number).catch(()=>null)?(await Hr({repo:e.repo,number:e.number,via:"watch"}).catch(()=>{}),await kc(s,"opened",{...xc(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 O7(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 Bf(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await jf(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<c7;await Xy(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await A$(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await kd(a,"pushed",e.number,d=>d.payload?.sha===s)&&await kc(a,"pushed",{...xc(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>lS)await Lf(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 Lf(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=xd(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await kd(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await kc(a,"ci-fixed",{...xc(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await Lf(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>lS)await Ff(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await Ff(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){xd(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await kd(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await kc(a,"reconciled",{...xc(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await Ff(e.repo,e.number).catch(()=>{})}}}}async function M7(e,t,n,r){let o=xd(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await kd(s,"closed",e.number)&&await kc(s,"closed",{...xc(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 N1(e,t,n){xd(n,e,"lost",null);let r=t.get(e.trackId);r&&!await kd(r,"lost",e.number)&&await kc(r,"lost",xc(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function W1(e,t,n,r,o={}){let s=xd(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await V(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 P1(e={}){let{now:t=Date.now(),auth:n=Xl,view:r=w7,list:o=g7,links:s=I$,trackMap:a=y7,emitMerged:i=b7,mark:c=Ho,archiveIfArmed:l=Gr,notifyIfArmed:u=Kr,notifyIfResolved:d=Zh,followupsIfMerged:p=Sa,batchThreshold:w=i7,detail:m=k7,merge:f=x7,updateBranch:g=S7,lookup:y=pt,disarm:b=zl,emitDisarmed:x=v7,localHasCommit:v=$7,claim:S=Lr,midTurn:E=Ks,only:P=null,wantDetail:L=null,covered:$=sS,verdicts:C=null,tokenFor:U=ee=>wo(ee),noteRefusal:J=S$,clearRefusal:_=v$}=e;if(!(await n().catch(()=>null))?.authenticated||Wf()>0)return 0;let T=await s().catch(()=>[]),F=uR(T),W=ee=>{try{return!!L?.(ee)}catch{return!1}},ce=P?T.filter(ee=>{try{return P(ee)}catch{return!1}}):T.filter(ee=>t-(bc.get(me(ee.repo,ee.number))||0)>=O1[M1(ee,t,$)]);if(!ce.length)return 0;let z=Date.now(),Ke=new Map,Ie=new Map;for(let ee of[...ce].sort(eu)){let ge=P?"event":M1(ee,t,$);Ke.set(me(ee.repo,ee.number),{lane:ge,intervalMs:O1[ge]??null}),bc.set(me(ee.repo,ee.number),t),Ie.has(ee.repo)||Ie.set(ee.repo,[]),Ie.get(ee.repo).push(ee)}let X=await a().catch(()=>new Map),re=new Map,Te=(ee,ge)=>{let Ve=me(ee,ge);if(!re.has(Ve)){let ze=Promise.resolve().then(()=>m(ee,ge));ze.catch(()=>{}),re.set(Ve,ze)}return re.get(Ve)},Le=C??((ee,ge)=>Dm([{path:ee,prs:[ge]}],{now:t,slugOf:async()=>ee,tracks:async()=>[...X.values()].filter(Ve=>!He(Ve))}).catch(()=>{})),Pe={now:t,lanes:Ke,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,followupsIfMerged:p,detail:Te,merge:f,updateBranch:g,lookup:y,disarm:b,emitDisarmed:x,localHasCommit:v,claim:S,midTurn:E,mergedRepos:new Set};for(let[ee,ge]of Ie){let Ve=p7(ge);if(Ve.until>t)continue;let ze=!1;try{if(await U(ee),Ve.misses)for(let pe of ge)await _(pe.repo,pe.number).catch(()=>{})}catch(pe){ze=Kd(pe)}if(ze){let pe=Ve.misses+1;if(pe>=R1){console.log(`[pr-watch] ${ee}: not granted ${pe}\xD7 \u2014 retiring ${ge.length} link(s) as lost`);for(let $e of ge){await N1($e,X,Pe);let Qe=me($e.repo,$e.number);yd.delete(Qe),bc.delete(Qe)}}else for(let $e of ge)await J($e.repo,$e.number,{misses:pe,until:t+d7}).catch(()=>{});continue}let Ze,N=new Set,le=pe=>pe.ciFixAwait||pe.reconcileAwait||W(pe)?!0:pe.autoMerge?t-(pe.autoMerge.armedAt||0)<=F1:!1;if(ge.length>w)Ze=await o(ee).catch(()=>null);else{Ze=new Map;for(let pe of ge){if(le(pe)){let $e=await Te(ee,pe.number).catch(()=>null);if($e?.state){Ze.set(Number(pe.number),{number:Number(pe.number),url:$e.url,title:$e.title,headRefName:$e.headRefName,headRefOid:$e.headSha??null,state:$e.state,mergedAt:$e.mergedAt??null,closedAt:$e.closedAt??null});continue}}try{let $e=await r(ee,pe.number);$e?.number!=null&&Ze.set(Number($e.number),$e)}catch($e){h7($e)&&N.add(me(pe.repo,pe.number))}}}if(Ze)for(let pe of ge){let $e=me(pe.repo,pe.number),Qe=Ze.get(Number(pe.number));if(!Qe){if(N.has($e)){let Je=(yd.get($e)||0)+1;yd.set($e,Je),Je>=R1&&(await N1(pe,X,Pe),yd.delete($e),bc.delete($e))}continue}if(yd.delete($e),Qe.state==="MERGED"||Qe.state==="CLOSED")Qe.state==="MERGED"?await W1(pe,Qe,X,Pe):await M7(pe,Qe,X,Pe),bc.delete($e);else{let Je=pe.lastHeadSha??null;await R7(pe,Qe,X,Pe).catch(()=>{}),await O7(pe,Qe,X,Pe).catch(()=>{});let tn=dR(F,pe);pe.autoMerge&&await I7(pe,X,Pe,{isHead:tn,prevHead:Je}).catch(()=>{});try{if(W(pe)&&!re.has($e)&&Te(pe.repo,pe.number),re.has($e)){let yt=await re.get($e).catch(()=>null);yt?.checks&&await Le(pe.repo,yt)}}catch{}}}}let ve={};for(let{lane:ee}of Ke.values())ve[ee]=(ve[ee]||0)+1;return console.log(`[pr-watch] probed ${ce.length} link(s) (${Object.entries(ve).map(([ee,ge])=>`${ee} ${ge}`).join(", ")}) in ${Date.now()-z}ms`),ce.length}function D1(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 cS=!1,Lm=!1,jm=[],B1=Promise.resolve();async function C7(){for(;Lm||jm.length;){if(Lm){Lm=!1;try{await P1()}catch{}continue}let e=jm;jm=[];let t=e.map(r=>r.spec),n=Object.assign({},...e.map(r=>r.deps||{}));try{await P1({...n,only:r=>t.some(o=>D1(o,r)),wantDetail:r=>t.some(o=>o.detail&&D1(o,r))})}catch{}}}function Fm(e,t){return e===null?Lm=!0:jm.push({spec:e,deps:t}),cS||(cS=!0,B1=C7().finally(()=>{cS=!1})),B1}function q1(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 Fm({repo:n,numbers:r,branch:e.branch||null,event:e.event||null,detail:e.detail===!0},t)}var N7=6e4,L1=0;function G1(e=void 0){let t=e?.now??Date.now();return t-L1<N7?Promise.resolve():(L1=t,Fm({all:!0},e))}function K1(){Fm(null),setInterval(()=>Fm(null),j1)}pr();ih();Fi();Vr();yn();var P7=new Set(["opened","reopened","closed","synchronize","ready_for_review","converted_to_draft","edited"]);async function D7({tracks:e=xe,reconcile:t=vh}={}){for(let n of(await e().catch(()=>[])).filter(r=>!He(r)))await t(n,{bypassThrottle:!0}).catch(()=>{})}function V1(e,t={}){let{invalidate:n=xn,probe:r=q1,poke:o=iO,reconcileOpened:s=D7,noteOpenedWebhook:a=oR}=t;try{n()}catch{}let i={probe:null,poked:!1,reconciled:!1};if(!e?.repo)return i;if(e.event==="pull_request"&&P7.has(e.action)){if(e.action==="opened"||e.action==="reopened"){i.poked=!0,i.reconciled=!0;for(let c of e.numbers||[])try{a({repo:e.repo,number:c})}catch{}try{o()}catch{}s()}i.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"?i.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event,detail:!0}:e.event==="push"&&!e.deleted&&(i.probe={repo:e.repo,branch:e.headRef||null,event:"push"});return i.probe&&r(i.probe),i}kt();be();Vr();yn();Vs();su();Rl();import{randomUUID as B7}from"node:crypto";var wS=2e4,z1=3,Sc=new Map,fS=new Set;async function J1(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 L7(e={}){let{sessions:t=null,tracks:n=null,append:r=D,read:o=V,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await sn(),i=n??await xe()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(He(u)||!u.leadBox)continue;let d=(u.boxes||[]).find(w=>w.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 w=(Sc.get(d.name)||0)+1;Sc.set(d.name,w),w===z1&&(fS.add(d.name),await J1(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:B7(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let w=(Sc.get(d.name)||0)>=z1;if(Sc.delete(d.name),w||!fS.has(d.name)){fS.add(d.name);let m=await J1(u,d.name,o);m&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:m,action:"cleared"}}).catch(()=>{})}}}for(let u of[...Sc.keys()])l.has(u)||Sc.delete(u)}var j7=2,hS=12e4,F7=360*6e4,U7=new Set(["merged","conflict","canceled","failed","handed-off"]),io=new Map;async function H7(e={}){let{sessions:t=null,tracks:n=null,append:r=D,read:o=V,now:s=Date.now(),turnState:a=$o,recentRead:i=CE,cliDead:c=Gu,busyAt:l=ME,reportLoop:u=Js,boot:d=!1}=e,p,w;try{p=t??await sn(),w=n??await xe()}catch{return}let m=new Map(p.map(g=>[g.name,g])),f=new Set;for(let g of w){if(He(g)||!g.leadBox||g.archivedAt||g.transferredTo)continue;let y=(g.boxes||[]).find(_=>_.name===g.leadBox);if(!y||U7.has(y.state))continue;let b=m.get(y.name),x=l(y.name),v=x!=null&&s-x<=hS,S=null;if(b){f.add(y.name);let _=i(y.name,wS),I=_?{working:_.busy,prompted:!1}:await a(y.name,y.agent).catch(()=>({working:!1,prompted:!1}));if(I.working||I.prompted||I.awaitingBackground){io.delete(y.name);continue}let T=l(y.name);if(!(T!=null&&s-T<=hS)&&!d){io.delete(y.name);continue}if(!await c(b).catch(()=>!1)){io.delete(y.name);continue}let W=(io.get(y.name)||0)+1;if(io.set(y.name,W),W<j7)continue;S="cli-exited"}else{if(!v&&!d)continue;S="session-gone"}let E=await o(g).catch(()=>[]),P=la(E),L=0;for(let _ of E)_.type==="turn.interrupted"&&(_.payload?.result==="stopped"||_.payload?.result==="stopped-late")&&(L=Math.max(L,_.payload?.ts??_.ts??0));if(Math.max(P.abortedAt,L)>P.askedAt)continue;let $=l(y.name),C=y.agent==="claude"?P.hookClosedAt:P.closedAt,U=$!=null&&s-$<=hS&&C<=$,J=d&&hO(E)&&s-P.askedAt<=F7;if(!U&&!J){io.delete(y.name);continue}await r(g,{type:"turn.aborted",actor:"system",source:"orchestrator",boxId:y.name,provider:y.agent,payload:{ts:s,cause:S,turnTs:P.askedAt||null,box:y.name,agent:y.agent,evidence:U?"busy-read":"log",...b?.createdMs?{sessionAgeMs:s-b.createdMs}:{}}}).catch(()=>{}),io.delete(y.name),String(g.name||"").startsWith("\u21BB")&&u(g,{provider:y.agent,note:`run ${S==="session-gone"?"lost its session":"CLI exited"} mid-turn`}).catch(()=>{})}for(let g of[...io.keys()])f.has(g)||io.delete(g)}var Sd=null,mS=!1,Um=null;function Y1(){if(Sd)return()=>{};let e=(t=!1)=>{mS||(mS=!0,L7().catch(()=>{}).then(()=>H7({boot:t})).catch(()=>{}).finally(()=>{mS=!1}))};return Sd=setInterval(()=>e(!1),wS),Sd.unref?.(),Um=setTimeout(()=>e(!0),Math.min(wS,15e3)),Um.unref?.(),()=>{clearInterval(Sd),clearTimeout(Um),Sd=null,Um=null}}ca();var gS=String.raw`gh\s+(?:pr\s+(?:checks|view|status|list|merge)|run\s+(?:list|view|watch)|api\b)`,W7=/gh\s+pr\s+checks\b[^\n;|&]*--watch/,q7=/gh\s+run\s+watch\b/,G7=new RegExp(String.raw`\b(?:until|while|for)\b(?:[\s\S]{0,300}?${gS}[\s\S]{0,300}?\bsleep\s+\d|[\s\S]{0,300}?\bsleep\s+\d[\s\S]{0,300}?${gS})`),K7=new RegExp(String.raw`\bsleep\s+\d+\s*(?:;|&&)\s*(?:timeout\s+\d+\s+)?${gS}`),yS=["watch","run","loop","sleep"];function V7(e){let t=String(e??""),n="",r=0,o=/<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/g,s;for(;s=o.exec(t);){if(s.index<r)continue;let a=t.indexOf(`
|
|
960
|
+
`),a.destroy();return}t(s,a,i)}}}function VD(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}Wi();hk();$h();Rl();be();import zD from"node:os";import{randomUUID as Jx}from"node:crypto";var m9=(e=process.env)=>({nodeId:e.BOSTRAT_NODE_ID||zD.hostname(),nodeName:e.BOSTRAT_NODE_NAME||zD.hostname()});var JD=32768,YD=120,XD=1e3,ZD=new Set(["claude","codex","cursor"]),w9=new Set(["off","transition","nag"]),g9=[[0,59],[0,23],[1,31],[1,12],[0,6]];function y9(e){let t=String(e??"").trim().split(/\s+/);return t.length!==5?!1:t.every((n,r)=>{let[o,s]=g9[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 Jn=e=>String(e??"").trim(),Ca={name(e){let t=Jn(e);if(!t)throw new Error("a loop needs a name");if(t.length>YD)throw new Error(`name is too long (${t.length}); cap is ${YD}`);return t},schedule(e){let t=Jn(e);if(!t)throw new Error('a loop needs a schedule (5-field UTC crontab, e.g. "0 7 * * *")');if(!y9(t))throw new Error(`invalid cron schedule: "${t}" \u2014 5 UTC fields, e.g. "0 7 * * *"`);return t},prompt(e){let t=Jn(e);if(!t)throw new Error("a loop needs a prompt \u2014 it is what the run does");if(t.length>JD)throw new Error(`prompt is too long (${t.length} chars); cap is ${JD}`);return t},expectation(e){let t=Jn(e)||null;if(t&&t.length>XD)throw new Error(`expectation is too long (${t.length}); cap is ${XD}`);return t},notify(e){let t=Jn(e)||"off";if(!w9.has(t))throw new Error(`notify must be one of off | transition | nag, got "${e}"`);return t},assignment(e){let t=e??null,n=Jn(typeof t=="string"?t:t?.provider)||"claude";if(!ZD.has(n))throw new Error(`unknown provider "${n}" \u2014 one of ${[...ZD].join(", ")}`);let r=typeof t=="object"&&t&&Jn(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 b9(e,t){let n=e&&typeof e=="object"?e:{},r=Ca.name(n.name),o=Ca.schedule(n.schedule),s=Ca.prompt(n.prompt),a=Ca.expectation(n.expectation),i=Ca.notify(n.notify),c=Ca.assignment(n.assignment),l=Jn(t?.workspace?.repo)||Jn(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}=m9();return{name:r,schedule:o,prompt:s,expectation:a,notify:i,assignment:c,repo:l,nodeId:u||null,nodeName:d||null}}async function e1(e,t){let n=b9(t,e),r=Jx();return await D({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 t1(e,t,n,{loopId:r=null,nextFireAt:o=null}={}){if(!t)throw new Error("proposalId required");let s=await V({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 D({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 D({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 D({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 zx=["name","schedule","prompt","expectation","notify","assignment","enabled"],k9=(e,t)=>(e?.provider??"claude")===(t?.provider??"claude")&&(e?.model??null)===(t?.model??null);function n1(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 r1(e,t){let n=Jn(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 x9(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=>!zx.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: ${zx.join(", ")}`)}let o={};for(let a of zx){if(!(a in n))continue;let i=Ca[a](n[a]);(a==="assignment"?k9(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 o1(e,t,n){let r=n1(t),{patch:o,changed:s}=x9(n,r),a=Jx(),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 D({id:e.id,cwd:e.cwd},{type:"loop.update.offered",actor:"system",source:"orchestrator",payload:i}),i}var QD=600;async function s1(e,t,n){let r=Jn(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>QD)throw new Error(`reason is too long (${r.length}); cap is ${QD}`);let o=n1(t),s=Jx(),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 D({id:e.id,cwd:e.cwd},{type:"loop.delete.offered",actor:"system",source:"orchestrator",payload:a}),a}var a1=async(e,t,n)=>{if(!n)throw new Error("proposalId required");let r=await V({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 i1(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 a1(e,"loop.update.offered",t)).payload,a={id:e.id,cwd:e.cwd};return n==="applied"&&await D(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 D(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 c1(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 a1(e,"loop.delete.offered",t)).payload,s={id:e.id,cwd:e.cwd};return(n==="delete"||n==="pause")&&await D(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 D(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 S9}from"node:crypto";var Zx=20,v9=300,Yx=120,l1=120,u1=2e3,Nm=new Set(["build","ops","debt","spike"]),d1=new Set(["active","done","abandoned"]),Qx=new Set(["circuit.create","circuit.update","circuit.delete"]),A9=new Set(["person.create","slot.create","slot.update","slot.delete","reservation.create","reservation.update","reservation.delete"]),gd=new Set([...Qx,...A9]),T9=["name","description","status","type"],E9=["person","startDate","endDate","estUsd"],_9=["person","label","startDate","endDate"],I9=/^\d{4}-\d{2}-\d{2}$/,fn=e=>String(e??"").trim(),eS=e=>typeof e=="string"&&e.startsWith("@"),h1=864e5;function m1(e){let t=Date.parse(`${e}T00:00:00Z`),n=new Date(t).getUTCDay();return new Date(t-(n+6)%7*h1).toISOString().slice(0,10)}function $9(e){return new Date(Date.parse(`${m1(e)}T00:00:00Z`)+6*h1).toISOString().slice(0,10)}var p1=(e,t)=>{let n=fn(e);if(!I9.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 R9(e,t){let n=p1(e,"startDate"),r=p1(t,"endDate");if(r<n)throw new Error(`endDate ${r} is before startDate ${n}`);let o=m1(n),s=$9(r);return{startDate:o,endDate:s,snapped:o!==n||s!==r}}var f1=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},ws=(e,t,n)=>{let r=fn(e);if(r.length>t)throw new Error(`${n} is too long (${r.length}); cap is ${t}`);return r};function Xx(e,t){let n=fn(t);if(!n)throw new Error("a circuit name or id is required");if(eS(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 O9(e,t){let n=fn(t);if(!n)throw new Error('a person is required \u2014 "me", a person id, or a row label');if(n==="me"||eS(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 M9(e,t,{allow:n=gd}={}){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>Zx)throw new Error(`too many ops (${o.length}); cap is ${Zx} \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,w=!1,m=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)},g=(x,v)=>{let S=fn(x);if(!S)return null;if(d.has(S))throw new Error(`ref "${S}" is used by two ops \u2014 each ref names one thing`);return d.add(S),u[`@${S}`]=v,S},y=o.map((x,v)=>{let S=x&&typeof x=="object"?x:{},E=fn(S.op),P=`op ${v+1}`;if(!gd.has(E))throw new Error(`${P}: unknown op "${E}" \u2014 one of ${[...gd].join(", ")}`);if(!n.has(E))throw new Error(`${P}: "${E}" isn't a circuit op \u2014 roadmap changes go through \`bostrat-roadmap propose\` (one card, either CLI)`);let L=_=>{throw new Error(`${P} (${E}): ${_}`)},$=_=>{let I=S.set&&typeof S.set=="object"&&!Array.isArray(S.set)?S.set:null;I||L("needs a `set` object naming the fields to change");let T=Object.keys(I).filter(F=>!_.includes(F));return T.length&&L(`unknown field(s) ${T.join(", ")} \u2014 settable: ${_.join(", ")}`),Object.keys(I).length||L("`set` names no fields"),I},C=_=>{let{startDate:I,endDate:T,snapped:F}=R9(_.startDate,_.endDate);return F&&(p=!0),{startDate:I,endDate:T,snapped:F}},U=_=>{let I=O9(a,_);return fn(_)==="me"&&(w=!0),h(I),{key:I.id??fn(_),label:I.label}},J=(_,I,T,F,W)=>{let ce=fn(_);ce||L(`needs a ${F} id`);let z=I.find(Ke=>Ke[T]===ce);return z||L(`no ${F} "${ce}" \u2014 see \`bostrat-roadmap ls\``),W[ce]={...z},z};switch(E){case"circuit.create":{let _=ws(S.name,l1,"name");_||L("a circuit needs a name");let I=fn(S.type)||"build";Nm.has(I)||L(`bad type "${I}" (${[...Nm].join(" | ")})`);let T=s.find(W=>String(W.name).toLowerCase()===_.toLowerCase());T&&L(`a circuit named "${T.name}" already exists (${T.id}) \u2014 update it instead of making a twin`);let F=g(S.ref,_);return{op:E,...F?{ref:F}:{},name:_,description:ws(S.description,u1,"description"),type:I}}case"circuit.update":{let _=Xx(s,S.circuit);_.id||L("can't update a circuit created in the same plan \u2014 set its fields on the create op"),m(_);let I=$(T9),T={};if(I.name!==void 0){let F=ws(I.name,l1,"name");F||L("name can't be blank"),F!==_.name&&(T.name=F)}return I.description!==void 0&&(T.description=ws(I.description,u1,"description")),I.status!==void 0&&(d1.has(I.status)||L(`bad status "${I.status}" (${[...d1].join(" | ")})`),I.status!==_.status&&(T.status=I.status)),I.type!==void 0&&(Nm.has(I.type)||L(`bad type "${I.type}" (${[...Nm].join(" | ")})`),I.type!==(_.type??"build")&&(T.type=I.type)),Object.keys(T).length||L("nothing would change \u2014 the set equals the circuit's current values"),{op:E,circuit:_.id,name:_.name,set:T}}case"circuit.delete":{let _=Xx(s,S.circuit);_.id||L("can't delete a circuit created in the same plan"),m(_);let I=o.some((T,F)=>F<v&&fn(T?.op)==="circuit.update"&&T?.set?.status&&T.set.status!=="active"&&fn(T?.circuit)===fn(S.circuit));return _.status==="active"&&!I&&L(`\u201C${_.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:E,circuit:_.id,name:_.name,status:_.status}}case"person.create":{let _=ws(S.label,Yx,"label");_||L("a person row needs a label");let I=a.find(F=>String(F.label).toLowerCase()===_.toLowerCase());I&&L(`a roadmap row labelled "${I.label}" already exists (${I.personId})`);let T=g(S.ref,_);return{op:E,...T?{ref:T}:{},label:_}}case"slot.create":{let _=Xx(s,S.circuit);m(_);let I=U(S.person),T=C(S);return{op:E,circuit:_.id??_.ref,circuitName:_.name,person:I.key,personLabel:I.label,...T,estUsd:f1(S.estUsd)}}case"slot.update":{let _=J(S.slot,i,"slotId","slot",l.slots),I=$(E9),T={};if(I.person!==void 0){let W=U(I.person);T.person=W.key,T.personLabel=W.label}if(I.startDate!==void 0||I.endDate!==void 0){let W=C({startDate:I.startDate??_.startDate,endDate:I.endDate??_.endDate});W.startDate!==_.startDate&&(T.startDate=W.startDate),W.endDate!==_.endDate&&(T.endDate=W.endDate)}I.estUsd!==void 0&&(T.estUsd=f1(I.estUsd)),Object.keys(T).length||L("nothing would change");let F=s.find(W=>W.id===_.circuitId);return{op:E,slot:_.slotId,circuitName:F?.name??null,set:T}}case"slot.delete":{let _=J(S.slot,i,"slotId","slot",l.slots),I=s.find(T=>T.id===_.circuitId);return{op:E,slot:_.slotId,circuitName:I?.name??null,startDate:_.startDate,endDate:_.endDate}}case"reservation.create":{let _=U(S.person),I=ws(S.label,Yx,"label");return I||L("a reservation needs a label (Leave, Support rotation, \u2026)"),{op:E,person:_.key,personLabel:_.label,label:I,...C(S)}}case"reservation.update":{let _=J(S.reservation,c,"reservationId","reservation",l.reservations),I=$(_9),T={};if(I.person!==void 0){let F=U(I.person);T.person=F.key,T.personLabel=F.label}if(I.label!==void 0){let F=ws(I.label,Yx,"label");F||L("label can't be blank"),F!==_.label&&(T.label=F)}if(I.startDate!==void 0||I.endDate!==void 0){let F=C({startDate:I.startDate??_.startDate,endDate:I.endDate??_.endDate});F.startDate!==_.startDate&&(T.startDate=F.startDate),F.endDate!==_.endDate&&(T.endDate=F.endDate)}return Object.keys(T).length||L("nothing would change"),{op:E,reservation:_.reservationId,label:_.label,set:T}}case"reservation.delete":{let _=J(S.reservation,c,"reservationId","reservation",l.reservations);return{op:E,reservation:_.reservationId,label:_.label,startDate:_.startDate,endDate:_.endDate}}default:return L("unhandled op")}});y.forEach((x,v)=>{for(let S of[x.circuit,x.person,x.set?.person])if(eS(S)&&!d.has(String(S).slice(1)))throw new Error(`op ${v+1} (${x.op}): unknown ref "${S}" \u2014 no earlier op in this plan creates it`)});let b=a.some(x=>x.kind==="user"&&x.userId);return{why:ws(r.why,v9,"why"),ops:y,base:l,resolved:u,snapped:p,createsMeRow:w&&!b}}async function w1(e,t,n,r={}){let o=M9(t,n,r),s=S9(),a={ts:Date.now(),proposalId:s,...o};return await D({id:e.id,cwd:e.cwd},{type:"planning.change.offered",actor:"system",source:"orchestrator",payload:a}),a}var C9=async(e,t)=>{if(!t)throw new Error("proposalId required");let n=await V({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 g1(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 C9(e,t),s={id:e.id,cwd:e.cwd},a=o.payload;return n==="applied"&&await D(s,{type:"planning.changed",actor:"user",source:"orchestrator",payload:{ts:Date.now(),proposalId:t,why:a.why??"",results:Array.isArray(r)?r.slice(0,Zx+1):[]}}),await D(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}}ph();be();bo();be();jn();$h();var y1=10,b1=200,N9=120,P9=24,x1=/^\d{4}-\d{2}-\d{2}$/;function tS(e=process.env){return(e.CHANGELOG_REPOS||"globocodes/bostrat").split(",").map(t=>t.trim()).filter(Boolean)}var D9=(e=Date.now())=>new Date(e).toISOString().slice(0,10),Ct=(e,t="i")=>new RegExp(e,t),B9=[{re:Ct("^(business|docs|chore|ci|refactor|test|security|sec)(\\([^)]*\\))?!?:"),reason:"non-product PR prefix"},{re:Ct("\\bSPC\\b",""),reason:"business (SPC)"},{re:Ct("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),reason:"business"},{re:Ct("competitor|cloudcli|\\bkiro\\b"),reason:"competitor research"},{re:Ct("\\bReplicas\\b",""),reason:"competitor research"},{re:Ct("tenanc|tenant|perimeter|ip[- ]gate|access[- ]code|vulnerab|\\bCVE\\b|audit|hardening|security|\\bsweep\\b"),reason:"security / tenancy"},{re:Ct("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),reason:"internal codename"},{re:Ct("^track/(business|security|spc|sec)-"),reason:"non-product branch"}],L9=[Ct("\\bSPC\\b",""),Ct("kickstarter|pitch deck|investor|fundrais|commercial ladder|/seat\\b|price[- ]test"),Ct("competitor|cloudcli|\\bkiro\\b"),Ct("\\bReplicas\\b",""),Ct("tenanc|\\btenants?\\b|cross-tenant|perimeter|ip[- ]gate|vulnerab|\\bCVE\\b|hardening|security register|audit finding"),Ct("\\bF-\\d+\\b|\\bBOS-\\d+\\b|\\bAC-D\\d"),Ct("(^|[^\\w&])#\\d+\\b"),Ct("\\btrack/[\\w.-]+")];function j9({title:e="",headRef:t=""}={}){let n=String(e||""),r=String(t||"");for(let{re:o,reason:s}of B9)if(o.test(n)||o.test(r))return s;return null}function k1(e){let t=String(e||"");for(let n of L9){let r=n.exec(t);if(r)return r[0].trim()}return null}function S1(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 F9=/^\*\*([^*]+?)\*\*\s*[:.]?\s*[—–-]?\s*(.*)$/;function U9(e){if(typeof e!="string"||!e.trim())throw new Error("md (markdown string) required");let t=Tu(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(`
|
|
961
|
+
`)){let s=o.trim();if(!s)continue;if(s.startsWith("#")){n==null&&(n=s.replace(/^#+\s*/,"").trim().slice(0,N9)||null);continue}let a=/^[-*]\s+(.*)$/.exec(s);if(!a)continue;let i=a[1].trim(),c=null,l=new RegExp(`^\\[([^\\]]{1,${P9}})\\]\\s+(.*)$`).exec(i);if(l&&(c=l[1].trim(),i=l[2].trim()),!i)continue;let u=F9.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=k1(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>b1)throw new Error(`bullet ${r.length+1} is ${i.length} chars \u2014 over the ${b1}-char cap; a changelog bullet is one line`);r.push({text:i,...c?{area:c}:{}})}if(n){let o=k1(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>y1)throw new Error(`${r.length} bullets \u2014 over the ${y1}-bullet cap; group related changes into one line`);return{title:n||null,bullets:r}}async function H9(e,{repos:t=tS()}={}){let n=new Set(t);return(await Ln()).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:j9({title:r.title,headRef:r.headRef})}))}async function v1(e,t){let n=await H9(e,t);return{prs:n.filter(r=>!r.excluded),excluded:n.filter(r=>r.excluded)}}async function A1(e,{md:t,day:n=null}){let r=U9(t),o=n==null||n===""?D9():String(n);if(!x1.test(o)||Number.isNaN(Date.parse(o)))throw new Error(`invalid day "${n}" \u2014 expected YYYY-MM-DD`);let s=await D({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 T1(e,{day:t}){let n=String(t||"");if(!x1.test(n)||Number.isNaN(Date.parse(n)))throw new Error(`invalid day "${t}" \u2014 expected YYYY-MM-DD`);let r=await D({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}}pr();jn();Vo();be();pr();_t();Vr();jn();Jl();ah();Gf();Vs();yn();import{execFile as e7}from"node:child_process";import{promisify as t7}from"node:util";var W9=new Set(["pull_request","check_suite","workflow_run","push"]),q9=/^[^/\s]+\/[^/\s]+$/,G9=500,nS=new Set,rS=[],Pm=new Map,En={hourStart:0,byEvent:{},duplicates:0,rejected:0};function oS(e,t,n){let r=Math.floor(e/36e5)*36e5;r!==En.hourStart&&(En.hourStart=r,En.byEvent={},En.duplicates=0,En.rejected=0),t==="accepted"?En.byEvent[n]=(En.byEvent[n]||0)+1:En[t]+=1}function K9(e){if(!e||typeof e!="object"||e.forge!=="github"||typeof e.event!="string"||!W9.has(e.event)||typeof e.repo!="string"||!q9.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 E1(e,{now:t=Date.now(),onAccept:n=null,log:r=console}={}){let o=K9(e);if(!o)return oS(t,"rejected"),{ok:!1,error:"malformed github event envelope"};if(o.deliveryId){if(nS.has(o.deliveryId))return oS(t,"duplicates"),{ok:!0,duplicate:!0,envelope:o};for(nS.add(o.deliveryId),rS.push(o.deliveryId);rS.length>G9;)nS.delete(rS.shift())}let s=o.repo.toLowerCase(),a=Pm.get(s)||{lastDeliveryAt:0,count:0};a.lastDeliveryAt=t,a.count+=1,Pm.set(s,a),oS(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 V9(e,t=Date.now()){let n=Pm.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 _1=1440*6e4;function sS(e,t=Date.now()){let n=V9(e,t);return n.covered&&n.ageMs<_1}function I1(e=Date.now()){let t={};for(let[n,r]of Pm)t[n]={lastDeliveryAt:r.lastDeliveryAt,count:r.count,covered:e-r.lastDeliveryAt<_1};return{hourStart:En.hourStart,byEvent:{...En.byEvent},duplicates:En.duplicates,rejected:En.rejected,repos:t}}be();jn();er();Vr();yn();function $1(e){return(e?.checks?.failed??0)>0?"red":e?.mergeable==="CONFLICTING"?"conflict":e?.mergeStateStatus==="BEHIND"?"behind":null}function z9(e){return!(!e?.checks||e.checks.pending>0||e.mergeabilityPending||e.mergeable==="UNKNOWN"||e.mergeStateStatus==="UNKNOWN")}var J9=new Set(["merged","closed","lost"]);function Y9(e,t){if(!e?.blocked)return null;let n=$1(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 X9(e,t){return e.autoMerge?!0:t==="ci-fixed"?!!(e.ciFix||e.ciFixAwait):t==="reconciled"?!!(e.reconcile||e.reconcileAwait):!1}async function Z9(e,t,n,r,o){return(await V(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 Q9(e,t,n){await D({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 Dm(e,t={}){let{now:n=Date.now(),slugOf:r=Re,lookup:o=pt,note:s=T$,tracks:a=async()=>(await xe()).filter(d=>!He(d)),asked:i=Z9,emitChange:c=Q9}=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 w of d.prs)try{if(!z9(w))continue;let m=await o(p,w.number).catch(()=>null);if(!m?.trackId||J9.has(m.state))continue;let{prev:h}=await s(p,w.number,{blocked:$1(w),sha:w.headSha??null,at:n});if(!h)continue;let g=Y9(h,w);if(!g||X9(m,g.change))continue;u??=new Map((await a()).map(v=>[v.id,v]));let y=u.get(m.trackId);if(!y)continue;let b=w.headSha??null;if(await i(y,g.change,w.number,b,h.at||0))continue;let x={number:Number(w.number),url:w.url||m.url,title:w.title||m.title,branch:w.headRefName||m.headRef,repo:p,sha:b,delegated:!1,reason:g.reason};g.change==="ci-fixed"?x.passed=w.checks.passed:x.base=w.baseRefName||null,await c(y,g.change,x),l.push({change:g.change,number:w.number,reason:g.reason})}catch{}}return l}var pS=t7(e7),j1=3e4,n7=30*6e4,r7=j1,o7=10*6e4,s7=10080*6e4,a7=60*6e4,R1=8,F1=1440*6e4,i7=3,U1="number,url,title,headRefName,headRefOid,state,mergedAt,closedAt",lS=60*6e4,c7=15*6e4,l7=9e4,u7=1440*6e4,bc=new Map,yd=new Map,d7=360*6e4,p7=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}),f7=/could not resolve|not found|no pull requests?/i,h7=e=>f7.test(String(e?.message||e||""));function m7(e,t){return[e.ciFix?.delegatedAt,e.reconcile?.delegatedAt,e.ciFixAwait?.since,e.reconcileAwait?.since].some(n=>n&&t-n<lS)}var O1={fast:r7,slow:o7,decay:a7};function M1(e,t,n=sS){return H1(e,t,{grace:0})||!n(e.repo,t)&&(e.armedAt&&t-e.armedAt<n7||m7(e,t))?"fast":t-(e.firstSeen||0)>s7?"decay":"slow"}function xd(e,t,n,r){let o=e.lanes?.get(me(t.repo,t.number))||{};return $i({change:n,repo:t.repo,number:Number(t.number),githubAt:r||null,lane:o.lane||null,intervalMs:o.intervalMs||null,source:"watch"})}async function w7(e,t){Fr("watch");try{let{stdout:n}=await pS("gh",["pr","view",String(t),"--repo",e,"--json",U1],{timeout:3e4,maxBuffer:4194304,env:{...process.env,...await tr({slug:e})}});return JSON.parse(n||"null")}catch(n){throw qo(n)&&Go(n),n}}async function g7(e){Fr("watch");try{let{stdout:t}=await pS("gh",["pr","list","--repo",e,"--state","all","--limit","100","--json",U1],{timeout:3e4,maxBuffer:8388608,env:{...process.env,...await tr({slug:e})}}),n=new Map;for(let r of JSON.parse(t||"[]"))n.set(Number(r.number),r);return n}catch(t){throw qo(t)&&Go(t),t}}async function y7(){let e=new Map;for(let t of await xe().catch(()=>[]))e.set(t.id,t);return e}async function b7(e,t){await D({id:e.id,cwd:e.cwd},{type:"pr.state.changed",actor:"user",source:"orchestrator",boxId:null,payload:{ts:Date.now(),change:"merged",...t}}),await sh(e,t).catch(()=>{})}async function k7(e,t){let n=await ia(e);return n?Mi(n,t):null}async function x7(e,t,n){let r=await ia(e);if(!r)throw new Error(`no local checkout for ${e}`);return Ci(r,t,{method:n})}async function S7(e,t){let n=await ia(e);if(!n)throw new Error(`no local checkout for ${e}`);return Ql(n,t)}async function v7(e,t){await D({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 gc(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 A7=10*6e4,C1=2*6e4,T7=2,E7=5*6e4,Bm=new Map,uS=new Map,bd=new Map,dS=new Map;function yc(e,t){let n=dS.get(e)??t;return dS.set(e,n),t-n>E7?!1:(bc.delete(e),!0)}function aS(e){dS.delete(e)}function _7(e,t,n,r){let o=n.headSha||null;if(!o||t==null)return!0;if(o!==t)return Bm.set(e,{sha:o,at:r}),!1;if(uS.get(e)===o)return!0;let s=Bm.get(e);if(s?.sha===o)return r-s.at>=C1;let a=Date.parse(n.updatedAt||"")||0;return a&&r-a<C1?(Bm.set(e,{sha:o,at:r}),!1):!0}function iS(e,t,n,r){let o=bd.get(e),s=o&&o.kind===t&&o.sha===(n||null)?o.count+1:1;return bd.set(e,{sha:n||null,kind:t,message:r,count:s}),s>=T7}async function I7(e,t,n,{isHead:r=!0,prevHead:o=null}={}){let s=n.now??Date.now(),a=me(e.repo,e.number),i=e.autoMerge?.armedAt||0;if(i&&s-i>F1){await gc(e,null,t,n,"auto-merge expired \u2014 checks never settled within 24h");return}let c=await n.detail(e.repo,e.number).catch(()=>null);if(!c)return;if(c.headSha&&e.lastHeadSha!==c.headSha&&await Xy(e.repo,e.number,c.headSha).catch(()=>{}),c.checks.failed>0){let u=c.checks.failing.map(d=>d.name).join(", ");await gc(e,c,t,n,`check${c.checks.failed===1?"":"s"} failed: ${u}`);return}if(c.mergeable==="CONFLICTING"){await gc(e,c,t,n,`conflicts with ${c.baseRefName}`);return}if(!c.checks.total){let u=Math.max(e.autoMerge?.armedAt||0,Date.parse(c.updatedAt||"")||0);if(s-u<A7)return;if(!iS(a,"no-checks",c.headSha,null)){yc(a,s);return}await gc(e,c,t,n,c.checks.unavailable?"this token can't read the checks":"no CI checks appeared");return}if(c.checks.pending>0){c.headSha&&uS.set(a,c.headSha),bd.delete(a),aS(a);return}if(c.mergeable==="UNKNOWN"||c.mergeStateStatus==="UNKNOWN"){yc(a,s);return}if(c.isDraft)return;if(!_7(a,o,c,s)){yc(a,s);return}let l=await n.lookup(e.repo,e.number).catch(()=>null);if(l?.autoMerge){if(c.mergeStateStatus==="BEHIND"){if(!r)return;try{await n.updateBranch(e.repo,e.number),bd.delete(a),aS(a)}catch(u){let d=String(u?.message||u).trim();if(/no new commits|already up.to.date/i.test(d))return;if(!iS(a,"update",c.headSha,d)){yc(a,s);return}await gc(e,c,t,n,d||`couldn't update with ${c.baseRefName}`)}return}if(n.mergedRepos?.has(String(e.repo||"").toLowerCase())){yc(a,s);return}try{await n.merge(e.repo,e.number,l.autoMerge.method||"merge")}catch(u){let d=String(u?.message||u).trim();if(/already merged|not open|is closed/i.test(d))return;if(!iS(a,"merge",c.headSha,d)){yc(a,s);return}await gc(e,c,t,n,d||"merge failed");return}return n.mergedRepos?.add(String(e.repo||"").toLowerCase()),bd.delete(a),aS(a),Bm.delete(a),uS.delete(a),await W1(e,{...c,state:"MERGED"},t,n,{change:"auto-merged",githubAt:c.checks.settledAt||null}),"merged"}}async function kc(e,t,n){await D({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 $7(e,t){try{return await pS("git",["-C",e.cwd,"cat-file","-e",`${t}^{commit}`],{timeout:1e4}),!0}catch{return!1}}async function kd(e,t,n,r=()=>!0){return(await V(e).catch(()=>[])).some(s=>s.type==="pr.state.changed"&&s.payload?.change===t&&s.payload?.number===Number(n)&&r(s))}var xc=(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 H1(e,t,{grace:n=l7}={}){if(e.announced!==!1)return!1;let r=t-(e.firstSeen||0);return r>=n&&r<=u7}async function R7(e,t,n,r){let o=r.now??Date.now();if(!H1(e,o))return!1;let s=n.get(e.trackId)||null;if(!s||He(s))return!1;let a=(s.boxes||[]).find(d=>d.name===s.leadBox);return await(r.midTurn??Ks)(s.leadBox,a?.agent).catch(()=>!1)?!1:(await V(s).catch(()=>[])).some(d=>d.type==="pr.state.changed"&&d.payload?.number===Number(e.number))?(await(r.claim??Lr)(e.repo,e.number).catch(()=>null),!1):await(r.claim??Lr)(e.repo,e.number).catch(()=>null)?(await Hr({repo:e.repo,number:e.number,via:"watch"}).catch(()=>{}),await kc(s,"opened",{...xc(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 O7(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 Bf(e.repo,e.number,{headSha:s}).catch(()=>{}),e.reconcile?.headSha&&s!==e.reconcile.headSha&&await jf(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<c7;await Xy(e.repo,e.number,s).catch(()=>{}),e.baseFoldAt&&await A$(e.repo,e.number).catch(()=>{}),!i&&!c&&!l&&a&&!await r.localHasCommit(a,s).catch(()=>!1)&&!await kd(a,"pushed",e.number,d=>d.payload?.sha===s)&&await kc(a,"pushed",{...xc(e,t),sha:s}).catch(()=>{})}if(e.ciFixAwait)if(o-(e.ciFixAwait.since||0)>lS)await Lf(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 Lf(e.repo,e.number).catch(()=>{});else if(i.checks.total>0&&i.checks.pending===0){let c=xd(r,e,"ci-fixed",i.checks.settledAt||null),l=e.ciFixAwait.since||0;a&&!await kd(a,"ci-fixed",e.number,u=>(u.payload?.ts||0)>=l)&&await kc(a,"ci-fixed",{...xc(e,t),sha:s,delegated:!0,passed:i.checks.passed,githubAt:c.githubAt,latencyMs:c.latencyMs,lane:c.lane}).catch(()=>{}),await Lf(e.repo,e.number).catch(()=>{})}}}if(e.reconcileAwait)if(o-(e.reconcileAwait.since||0)>lS)await Ff(e.repo,e.number).catch(()=>{});else{let i=await r.detail(e.repo,e.number).catch(()=>null);if(i){if(i.mergeable==="CONFLICTING")await Ff(e.repo,e.number).catch(()=>{});else if(i.mergeable==="MERGEABLE"){xd(r,e,"reconciled",null);let c=e.reconcileAwait.since||0;a&&!await kd(a,"reconciled",e.number,l=>(l.payload?.ts||0)>=c)&&await kc(a,"reconciled",{...xc(e,t),sha:s,delegated:!0,base:i.baseRefName||null}).catch(()=>{}),await Ff(e.repo,e.number).catch(()=>{})}}}}async function M7(e,t,n,r){let o=xd(r,e,"closed",Date.parse(t?.closedAt||"")||null),s=n.get(e.trackId);s&&!await kd(s,"closed",e.number)&&await kc(s,"closed",{...xc(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 N1(e,t,n){xd(n,e,"lost",null);let r=t.get(e.trackId);r&&!await kd(r,"lost",e.number)&&await kc(r,"lost",xc(e,null)).catch(()=>{}),await n.notifyIfResolved(e.repo,e.number,"lost").catch(()=>{}),await n.mark(e.repo,e.number,"lost").catch(()=>{})}async function W1(e,t,n,r,o={}){let s=xd(r,e,o.change||"merged",o.githubAt??(Date.parse(t.mergedAt||"")||null)),a=n.get(e.trackId);a&&((await V(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 P1(e={}){let{now:t=Date.now(),auth:n=Xl,view:r=w7,list:o=g7,links:s=I$,trackMap:a=y7,emitMerged:i=b7,mark:c=Ho,archiveIfArmed:l=Gr,notifyIfArmed:u=Kr,notifyIfResolved:d=Zh,followupsIfMerged:p=Sa,batchThreshold:w=i7,detail:m=k7,merge:h=x7,updateBranch:g=S7,lookup:y=pt,disarm:b=zl,emitDisarmed:x=v7,localHasCommit:v=$7,claim:S=Lr,midTurn:E=Ks,only:P=null,wantDetail:L=null,covered:$=sS,verdicts:C=null,tokenFor:U=ee=>wo(ee),noteRefusal:J=S$,clearRefusal:_=v$}=e;if(!(await n().catch(()=>null))?.authenticated||Wf()>0)return 0;let T=await s().catch(()=>[]),F=uR(T),W=ee=>{try{return!!L?.(ee)}catch{return!1}},ce=P?T.filter(ee=>{try{return P(ee)}catch{return!1}}):T.filter(ee=>t-(bc.get(me(ee.repo,ee.number))||0)>=O1[M1(ee,t,$)]);if(!ce.length)return 0;let z=Date.now(),Ke=new Map,Ie=new Map;for(let ee of[...ce].sort(eu)){let ge=P?"event":M1(ee,t,$);Ke.set(me(ee.repo,ee.number),{lane:ge,intervalMs:O1[ge]??null}),bc.set(me(ee.repo,ee.number),t),Ie.has(ee.repo)||Ie.set(ee.repo,[]),Ie.get(ee.repo).push(ee)}let X=await a().catch(()=>new Map),re=new Map,Te=(ee,ge)=>{let Ve=me(ee,ge);if(!re.has(Ve)){let ze=Promise.resolve().then(()=>m(ee,ge));ze.catch(()=>{}),re.set(Ve,ze)}return re.get(Ve)},Le=C??((ee,ge)=>Dm([{path:ee,prs:[ge]}],{now:t,slugOf:async()=>ee,tracks:async()=>[...X.values()].filter(Ve=>!He(Ve))}).catch(()=>{})),Pe={now:t,lanes:Ke,emitMerged:i,mark:c,archiveIfArmed:l,notifyIfArmed:u,notifyIfResolved:d,followupsIfMerged:p,detail:Te,merge:h,updateBranch:g,lookup:y,disarm:b,emitDisarmed:x,localHasCommit:v,claim:S,midTurn:E,mergedRepos:new Set};for(let[ee,ge]of Ie){let Ve=p7(ge);if(Ve.until>t)continue;let ze=!1;try{if(await U(ee),Ve.misses)for(let pe of ge)await _(pe.repo,pe.number).catch(()=>{})}catch(pe){ze=Kd(pe)}if(ze){let pe=Ve.misses+1;if(pe>=R1){console.log(`[pr-watch] ${ee}: not granted ${pe}\xD7 \u2014 retiring ${ge.length} link(s) as lost`);for(let $e of ge){await N1($e,X,Pe);let Qe=me($e.repo,$e.number);yd.delete(Qe),bc.delete(Qe)}}else for(let $e of ge)await J($e.repo,$e.number,{misses:pe,until:t+d7}).catch(()=>{});continue}let Ze,N=new Set,le=pe=>pe.ciFixAwait||pe.reconcileAwait||W(pe)?!0:pe.autoMerge?t-(pe.autoMerge.armedAt||0)<=F1:!1;if(ge.length>w)Ze=await o(ee).catch(()=>null);else{Ze=new Map;for(let pe of ge){if(le(pe)){let $e=await Te(ee,pe.number).catch(()=>null);if($e?.state){Ze.set(Number(pe.number),{number:Number(pe.number),url:$e.url,title:$e.title,headRefName:$e.headRefName,headRefOid:$e.headSha??null,state:$e.state,mergedAt:$e.mergedAt??null,closedAt:$e.closedAt??null});continue}}try{let $e=await r(ee,pe.number);$e?.number!=null&&Ze.set(Number($e.number),$e)}catch($e){h7($e)&&N.add(me(pe.repo,pe.number))}}}if(Ze)for(let pe of ge){let $e=me(pe.repo,pe.number),Qe=Ze.get(Number(pe.number));if(!Qe){if(N.has($e)){let Je=(yd.get($e)||0)+1;yd.set($e,Je),Je>=R1&&(await N1(pe,X,Pe),yd.delete($e),bc.delete($e))}continue}if(yd.delete($e),Qe.state==="MERGED"||Qe.state==="CLOSED")Qe.state==="MERGED"?await W1(pe,Qe,X,Pe):await M7(pe,Qe,X,Pe),bc.delete($e);else{let Je=pe.lastHeadSha??null;await R7(pe,Qe,X,Pe).catch(()=>{}),await O7(pe,Qe,X,Pe).catch(()=>{});let tn=dR(F,pe);pe.autoMerge&&await I7(pe,X,Pe,{isHead:tn,prevHead:Je}).catch(()=>{});try{if(W(pe)&&!re.has($e)&&Te(pe.repo,pe.number),re.has($e)){let yt=await re.get($e).catch(()=>null);yt?.checks&&await Le(pe.repo,yt)}}catch{}}}}let ve={};for(let{lane:ee}of Ke.values())ve[ee]=(ve[ee]||0)+1;return console.log(`[pr-watch] probed ${ce.length} link(s) (${Object.entries(ve).map(([ee,ge])=>`${ee} ${ge}`).join(", ")}) in ${Date.now()-z}ms`),ce.length}function D1(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 cS=!1,Lm=!1,jm=[],B1=Promise.resolve();async function C7(){for(;Lm||jm.length;){if(Lm){Lm=!1;try{await P1()}catch{}continue}let e=jm;jm=[];let t=e.map(r=>r.spec),n=Object.assign({},...e.map(r=>r.deps||{}));try{await P1({...n,only:r=>t.some(o=>D1(o,r)),wantDetail:r=>t.some(o=>o.detail&&D1(o,r))})}catch{}}}function Fm(e,t){return e===null?Lm=!0:jm.push({spec:e,deps:t}),cS||(cS=!0,B1=C7().finally(()=>{cS=!1})),B1}function q1(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 Fm({repo:n,numbers:r,branch:e.branch||null,event:e.event||null,detail:e.detail===!0},t)}var N7=6e4,L1=0;function G1(e=void 0){let t=e?.now??Date.now();return t-L1<N7?Promise.resolve():(L1=t,Fm({all:!0},e))}function K1(){Fm(null),setInterval(()=>Fm(null),j1)}pr();ih();Fi();Vr();yn();var P7=new Set(["opened","reopened","closed","synchronize","ready_for_review","converted_to_draft","edited"]);async function D7({tracks:e=xe,reconcile:t=vh}={}){for(let n of(await e().catch(()=>[])).filter(r=>!He(r)))await t(n,{bypassThrottle:!0}).catch(()=>{})}function V1(e,t={}){let{invalidate:n=xn,probe:r=q1,poke:o=iO,reconcileOpened:s=D7,noteOpenedWebhook:a=oR}=t;try{n()}catch{}let i={probe:null,poked:!1,reconciled:!1};if(!e?.repo)return i;if(e.event==="pull_request"&&P7.has(e.action)){if(e.action==="opened"||e.action==="reopened"){i.poked=!0,i.reconciled=!0;for(let c of e.numbers||[])try{a({repo:e.repo,number:c})}catch{}try{o()}catch{}s()}i.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"?i.probe={repo:e.repo,numbers:e.numbers,branch:e.headRef||null,event:e.event,detail:!0}:e.event==="push"&&!e.deleted&&(i.probe={repo:e.repo,branch:e.headRef||null,event:"push"});return i.probe&&r(i.probe),i}kt();be();Vr();yn();Vs();su();Rl();import{randomUUID as B7}from"node:crypto";var wS=2e4,z1=3,Sc=new Map,fS=new Set;async function J1(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 L7(e={}){let{sessions:t=null,tracks:n=null,append:r=D,read:o=V,now:s=Date.now()}=e;if(process.env.BOSTRAT_CLAUDE_ALT_SCREEN==="1")return;let a,i;try{a=t??await sn(),i=n??await xe()}catch{return}let c=new Map(a.map(u=>[u.name,u])),l=new Set;for(let u of i){if(He(u)||!u.leadBox)continue;let d=(u.boxes||[]).find(w=>w.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 w=(Sc.get(d.name)||0)+1;Sc.set(d.name,w),w===z1&&(fS.add(d.name),await J1(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:B7(),box:d.name,agent:d.agent}}).catch(()=>{}))}else{let w=(Sc.get(d.name)||0)>=z1;if(Sc.delete(d.name),w||!fS.has(d.name)){fS.add(d.name);let m=await J1(u,d.name,o);m&&await r(u,{type:"box.fullscreen.answered",actor:"system",source:"orchestrator",boxId:d.name,provider:d.agent,payload:{ts:s,offerId:m,action:"cleared"}}).catch(()=>{})}}}for(let u of[...Sc.keys()])l.has(u)||Sc.delete(u)}var j7=2,hS=12e4,F7=360*6e4,U7=new Set(["merged","conflict","canceled","failed","handed-off"]),io=new Map;async function H7(e={}){let{sessions:t=null,tracks:n=null,append:r=D,read:o=V,now:s=Date.now(),turnState:a=$o,recentRead:i=CE,cliDead:c=Gu,busyAt:l=ME,reportLoop:u=Js,boot:d=!1}=e,p,w;try{p=t??await sn(),w=n??await xe()}catch{return}let m=new Map(p.map(g=>[g.name,g])),h=new Set;for(let g of w){if(He(g)||!g.leadBox||g.archivedAt||g.transferredTo)continue;let y=(g.boxes||[]).find(_=>_.name===g.leadBox);if(!y||U7.has(y.state))continue;let b=m.get(y.name),x=l(y.name),v=x!=null&&s-x<=hS,S=null;if(b){h.add(y.name);let _=i(y.name,wS),I=_?{working:_.busy,prompted:!1}:await a(y.name,y.agent).catch(()=>({working:!1,prompted:!1}));if(I.working||I.prompted||I.awaitingBackground){io.delete(y.name);continue}let T=l(y.name);if(!(T!=null&&s-T<=hS)&&!d){io.delete(y.name);continue}if(!await c(b).catch(()=>!1)){io.delete(y.name);continue}let W=(io.get(y.name)||0)+1;if(io.set(y.name,W),W<j7)continue;S="cli-exited"}else{if(!v&&!d)continue;S="session-gone"}let E=await o(g).catch(()=>[]),P=la(E),L=0;for(let _ of E)_.type==="turn.interrupted"&&(_.payload?.result==="stopped"||_.payload?.result==="stopped-late")&&(L=Math.max(L,_.payload?.ts??_.ts??0));if(Math.max(P.abortedAt,L)>P.askedAt)continue;let $=l(y.name),C=y.agent==="claude"?P.hookClosedAt:P.closedAt,U=$!=null&&s-$<=hS&&C<=$,J=d&&hO(E)&&s-P.askedAt<=F7;if(!U&&!J){io.delete(y.name);continue}await r(g,{type:"turn.aborted",actor:"system",source:"orchestrator",boxId:y.name,provider:y.agent,payload:{ts:s,cause:S,turnTs:P.askedAt||null,box:y.name,agent:y.agent,evidence:U?"busy-read":"log",...b?.createdMs?{sessionAgeMs:s-b.createdMs}:{}}}).catch(()=>{}),io.delete(y.name),String(g.name||"").startsWith("\u21BB")&&u(g,{provider:y.agent,note:`run ${S==="session-gone"?"lost its session":"CLI exited"} mid-turn`}).catch(()=>{})}for(let g of[...io.keys()])h.has(g)||io.delete(g)}var Sd=null,mS=!1,Um=null;function Y1(){if(Sd)return()=>{};let e=(t=!1)=>{mS||(mS=!0,L7().catch(()=>{}).then(()=>H7({boot:t})).catch(()=>{}).finally(()=>{mS=!1}))};return Sd=setInterval(()=>e(!1),wS),Sd.unref?.(),Um=setTimeout(()=>e(!0),Math.min(wS,15e3)),Um.unref?.(),()=>{clearInterval(Sd),clearTimeout(Um),Sd=null,Um=null}}ca();var gS=String.raw`gh\s+(?:pr\s+(?:checks|view|status|list|merge)|run\s+(?:list|view|watch)|api\b)`,W7=/gh\s+pr\s+checks\b[^\n;|&]*--watch/,q7=/gh\s+run\s+watch\b/,G7=new RegExp(String.raw`\b(?:until|while|for)\b(?:[\s\S]{0,300}?${gS}[\s\S]{0,300}?\bsleep\s+\d|[\s\S]{0,300}?\bsleep\s+\d[\s\S]{0,300}?${gS})`),K7=new RegExp(String.raw`\bsleep\s+\d+\s*(?:;|&&)\s*(?:timeout\s+\d+\s+)?${gS}`),yS=["watch","run","loop","sleep"];function V7(e){let t=String(e??""),n="",r=0,o=/<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/g,s;for(;s=o.exec(t);){if(s.index<r)continue;let a=t.indexOf(`
|
|
962
962
|
`,s.index);if(a<0)return n+t.slice(r,s.index);n+=t.slice(r,a+1);let i=new RegExp(`^\\t*${s[2]}[ \\t]*$`,"m"),c=t.slice(a+1),l=i.exec(c);if(!l)return n;r=a+1+l.index+l[0].length,t[r]===`
|
|
963
|
-
`&&(r+=1),o.lastIndex=r}return n+t.slice(r)}var z7=/'[^']*'/g;function J7(e){let t=V7(e).replace(z7,"''");return t.trim()?W7.test(t)?"watch":q7.test(t)?"run":G7.test(t)?"loop":K7.test(t)?"sleep":null:null}var X1=10080*6e4;function Z1(e,{since:t=0,until:n=1/0,trackId:r=null,maxRows:o=50}={}){let s=Object.fromEntries(yS.map(d=>[d,0])),a={},i=[],c=0,l=new Set,u=new Set;for(let d of e||[])d?.type==="job.started"&&d.payload?.id&&u.add(d.payload.id);for(let d of e||[]){if(d?.type!=="tool.called"||d.source!=="transcript")continue;let p=d.payload||{};if(typeof p.command!="string")continue;let w=Number(p.ts??d.ts)||0;if(w<t||w>n||p.id&&l.has(p.id))continue;p.id&&l.add(p.id);let m=J7(p.command);if(!m)continue;c+=1,s[m]+=1;let f=d.provider||"unknown";a[f]=(a[f]||0)+1,i.length<o&&i.push({ts:w,trackId:r??d.trackId??null,provider:f,shape:m,background:!!p.id&&u.has(p.id),command:p.command.slice(0,160)})}return{total:c,byShape:s,byProvider:a,rows:i}}function Q1(e,{since:t,until:n=Date.now()}={}){let r=Object.fromEntries(yS.map(c=>[c,0])),o={},s=0,a=[],i=[];for(let c of e||[])if(c?.total){s+=c.total;for(let l of yS)r[l]+=c.byShape?.[l]||0;for(let[l,u]of Object.entries(c.byProvider||{}))o[l]=(o[l]||0)+u;a.push({trackId:c.trackId,name:c.name??null,total:c.total}),i.push(...(c.rows||[]).map(l=>({...l,trackId:l.trackId??c.trackId,name:c.name??null})))}return a.sort((c,l)=>l.total-c.total),i.sort((c,l)=>l.ts-c.ts),{since:t,until:n,days:Math.round((n-t)/X1*7),total:s,byShape:r,byProvider:o,tracks:a,rows:i.slice(0,50)}}var eB=(e=7,t=Date.now())=>({since:t-e*(X1/7),until:t});Fi();be();pr();Vo();ca();iu();import{randomUUID as Y7}from"node:crypto";async function X7(){let e=await Promise.resolve().then(()=>(Vr(),CN));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var bS={listRepoPrs:kn,readEvents:V,appendEvent:D,sayDeps:X7,currentBranch:fr,forgeWatch:tu};async function Z7(e,t=bS,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??fr)(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 kS(e,t,{actions:n,notify:r=!1}={},o=bS){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 Z7(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=Y7();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 xS(e,{offerId:t,choice:n}={},r=bS){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');return Jo(`prx:${e.id}:${t}`,()=>Q7(e,{offerId:t,choice:n},r))}async function Q7(e,{offerId:t,choice:n},r){let o=await r.readEvents(e),s=o.find(d=>d.type==="pr.exists.offered"&&d.payload?.offerId===t);if(!s)throw new Error("unknown offer");if(o.some(d=>d.type==="pr.exists.answered"&&d.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,u=()=>(r.forgeWatch??tu)([{name:e.workspace?.repo??null,slug:e.workspace?.repo??null}]);if(n==="push"){let{sayToLead:d}=await r.sayDeps();l=Ko.filter(p=>p!=="pr"&&(i.includes(p)||p==="push")),c=await d(e.id,Ni(l,{branch:a.branch??null,base:a.base??null,toPr:{number:a.pr?.number??null},offeredRebase:a.offeredRebase===!0,forge:await u()}),{kind:"push-go"})}else if(n==="new"){let{sayToLead:d}=await r.sayDeps();l=i,c=await d(e.id,TR(i,{branch:a.branch??null,base:a.base??null,prNumber:a.pr?.number??null,offeredRebase:a.offeredRebase===!0,forge:await u()}),{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:d}=await r.sayDeps();d(e.id,{actions:l})}return{say:c,choice:n}}be();pr();er();jn();Fi();Vo();import{execFile as eZ}from"node:child_process";import{promisify as tZ}from"node:util";var nZ=tZ(eZ);async function tB(e,t){let{stdout:n}=await nZ("git",["-C",e,...t],{timeout:1e4});return String(n||"").trim()}async function rZ(e){let t=await tB(e,["rev-parse","HEAD"]).catch(()=>null),n=await tB(e,["rev-parse","@{u}"]).catch(()=>null);return{head:t,upstream:n}}var oZ={listRepoPrs:kn,readEvents:V,appendEvent:D,currentBranch:fr,headShas:rZ,repoSlug:Re,lookupPr:pt},sZ=new Set(["opened","pushed","ci-fixed","reconciled"]);function aZ(e,t,n=null,r=Date.now()){let o=Number(t?.number),s=Zo(e,r);if(s&&s.offerType!=="report"){if(s.toPr==null)return`an answered ship card is opening this branch's PR, and its PR-opened card (posted when the turn ends) announces #${o} at its final head`;if(s.toPr===o)return`an answered ship card is already settling #${o}, and its card posts when the turn ends`}let a=null,i=!1;for(let u of e||[])u.type==="turn.user"&&u.source!=="hook"?a=u.payload?.ts??u.ts??a:u.type==="pr.state.changed"&&u.payload?.change==="opened"&&Number(u.payload?.number)===o&&(i=!0);if(i||a==null)return null;let c=Date.parse(t?.createdAt??"");return n?.firstSeen!=null&&n.firstSeen>=a||Number.isFinite(c)&&c>=a?`#${o} was opened during this turn, so its PR-opened card (posted when the turn ends) announces it at its final head`:null}async function nB(e,{number:t=null,rebased:n=!1,base:r=null}={},o=oZ){if(!e?.cwd)throw new Error("no Track workspace to read");if(e.workspace?.kind==="multi")throw new Error("run this from inside the checkout whose PR you updated, not the multi-repo hub");let s=await o.currentBranch(e.cwd).catch(()=>null)||e.workspace?.branch||null;if(!s)throw new Error("HEAD is detached \u2014 check out the PR's branch first");let{head:a,upstream:i}=await o.headShas(e.cwd);if(!a)throw new Error("couldn't read HEAD in the Track workspace");if(!i)throw new Error(`${s} has no upstream \u2014 push it first (git push -u origin ${s})`);if(i!==a)throw new Error(`HEAD isn't on the remote yet \u2014 push ${s} first, then report`);let c;try{c=await o.listRepoPrs(e.cwd,{caller:"pr-update-report"})}catch(g){throw new Error(`couldn't read the open PRs (${g?.message||g}) \u2014 try again`)}let l=t!=null?Number(t):null,u=(c||[]).find(g=>g.headRefName===s&&(l==null||Number(g.number)===l));if(!u)throw new Error(l!=null?`#${l} isn't an open PR on ${s}`:`${s} has no open PR \u2014 a newly opened PR is announced automatically; this is only for updating one that is already open`);let d=await o.readEvents(e).catch(()=>[]);if(d.some(g=>(g.type==="pr.state.changed"&&sZ.has(g.payload?.change)||g.type==="pr.update.reported")&&Number(g.payload?.number)===Number(u.number)&&g.payload?.sha===a))return{skipped:!0,reason:`#${u.number} already has a card for ${a.slice(0,7)}`};let w=await o.repoSlug(e.cwd).catch(()=>null),m=w?await o.lookupPr(w,u.number).catch(()=>null):null,f=aZ(d,u,m);return f?{skipped:!0,reason:f}:(await o.appendEvent(e,{type:"pr.update.reported",actor:"agent",source:"cli",boxId:e.leadBox,payload:{ts:Date.now(),number:u.number,url:u.url??null,title:u.title??null,branch:u.headRefName||s,...w?{repo:w}:{},sha:a,...n?{rebased:!0}:{},...r?{base:String(r)}:{}}}),{reported:!0,number:u.number,url:u.url??null,sha:a})}iu();import co from"node:fs/promises";import vc from"node:path";import lB from"node:os";import rB from"node:fs/promises";import Hm from"node:path";import{execFile as iZ}from"node:child_process";import{promisify as cZ}from"node:util";import{fileURLToPath as lZ}from"node:url";var uZ=cZ(iZ),sB=Hm.dirname(lZ(import.meta.url)),dZ=Hm.resolve(sB,"..","..","client","dist"),pZ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fZ=new Map([...pZ].map((e,t)=>[e,t]));function hZ(e){let t=[],n=0,r=0;for(let o of e){let s=fZ.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 mZ(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=hZ(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 wZ(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 oB=new Map;async function gZ(e){let t;try{t=await rB.stat(e)}catch{return null}let n=oB.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await rB.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:mZ(r.mappings||"")};return oB.set(e,o),o}catch{return null}}var SS=null;function yZ(){return SS||(SS=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):uZ("git",["rev-parse","--short","HEAD"],{cwd:Hm.resolve(sB,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),SS}var bZ=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function kZ(e,{distDir:t=dZ}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(bZ)){let[a,i,c,l]=s,u=await gZ(Hm.join(t,"assets",`${i}.map`)),d=u?wZ(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 aB(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await yZ();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await kZ(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var xZ=()=>process.env.BOSTRAT_STATE_DIR||vc.join(process.env.HOME||lB.tmpdir(),".bostrat"),gs=()=>vc.join(xZ(),"telemetry"),uB=()=>vc.join(gs(),".relay-offsets.json"),SZ=50,vZ=14,AZ=3e4,iB=500,hn=(e,t)=>typeof e=="string"?e.slice(0,t):"";function TZ(e,t){if(!e||typeof e!="object")return null;let n=hn(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:hn(e.anonId,64),sessionId:hn(e.sessionId,64),userId:hn(e.userId,64),release:hn(e.release,64),appVersion:hn(e.appVersion,32),route:hn(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:hn(e.error.kind,256),message:hn(e.error.message,8192),stack:hn(e.error.stack,32768),fingerprint:hn(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:hn(s?.n,64),r:hn(s?.r,128)}))),o}var dB=e=>new Date(e).toISOString().slice(0,10),cB=0;async function pB(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,SZ):[]).map(s=>TZ(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await aB(s);await co.mkdir(gs(),{recursive:!0});let o=vc.join(gs(),`${dB(t)}.ndjson`);return await co.appendFile(o,r.map(s=>JSON.stringify(s)+`
|
|
963
|
+
`&&(r+=1),o.lastIndex=r}return n+t.slice(r)}var z7=/'[^']*'/g;function J7(e){let t=V7(e).replace(z7,"''");return t.trim()?W7.test(t)?"watch":q7.test(t)?"run":G7.test(t)?"loop":K7.test(t)?"sleep":null:null}var X1=10080*6e4;function Z1(e,{since:t=0,until:n=1/0,trackId:r=null,maxRows:o=50}={}){let s=Object.fromEntries(yS.map(d=>[d,0])),a={},i=[],c=0,l=new Set,u=new Set;for(let d of e||[])d?.type==="job.started"&&d.payload?.id&&u.add(d.payload.id);for(let d of e||[]){if(d?.type!=="tool.called"||d.source!=="transcript")continue;let p=d.payload||{};if(typeof p.command!="string")continue;let w=Number(p.ts??d.ts)||0;if(w<t||w>n||p.id&&l.has(p.id))continue;p.id&&l.add(p.id);let m=J7(p.command);if(!m)continue;c+=1,s[m]+=1;let h=d.provider||"unknown";a[h]=(a[h]||0)+1,i.length<o&&i.push({ts:w,trackId:r??d.trackId??null,provider:h,shape:m,background:!!p.id&&u.has(p.id),command:p.command.slice(0,160)})}return{total:c,byShape:s,byProvider:a,rows:i}}function Q1(e,{since:t,until:n=Date.now()}={}){let r=Object.fromEntries(yS.map(c=>[c,0])),o={},s=0,a=[],i=[];for(let c of e||[])if(c?.total){s+=c.total;for(let l of yS)r[l]+=c.byShape?.[l]||0;for(let[l,u]of Object.entries(c.byProvider||{}))o[l]=(o[l]||0)+u;a.push({trackId:c.trackId,name:c.name??null,total:c.total}),i.push(...(c.rows||[]).map(l=>({...l,trackId:l.trackId??c.trackId,name:c.name??null})))}return a.sort((c,l)=>l.total-c.total),i.sort((c,l)=>l.ts-c.ts),{since:t,until:n,days:Math.round((n-t)/X1*7),total:s,byShape:r,byProvider:o,tracks:a,rows:i.slice(0,50)}}var eB=(e=7,t=Date.now())=>({since:t-e*(X1/7),until:t});Fi();be();pr();Vo();ca();iu();import{randomUUID as Y7}from"node:crypto";async function X7(){let e=await Promise.resolve().then(()=>(Vr(),CN));return{sayToLead:e.sayToLead,queueShipCompleteNotify:e.queueShipCompleteNotify}}var bS={listRepoPrs:kn,readEvents:V,appendEvent:D,sayDeps:X7,currentBranch:fr,forgeWatch:tu};async function Z7(e,t=bS,{branch:n=null}={}){if(!e?.cwd)return null;let r=n||await(t.currentBranch??fr)(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 kS(e,t,{actions:n,notify:r=!1}={},o=bS){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 Z7(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=Y7();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 xS(e,{offerId:t,choice:n}={},r=bS){if(!t)throw new Error("offerId required");if(!["push","new","dismiss"].includes(n))throw new Error('choice "push" | "new" | "dismiss" required');return Jo(`prx:${e.id}:${t}`,()=>Q7(e,{offerId:t,choice:n},r))}async function Q7(e,{offerId:t,choice:n},r){let o=await r.readEvents(e),s=o.find(d=>d.type==="pr.exists.offered"&&d.payload?.offerId===t);if(!s)throw new Error("unknown offer");if(o.some(d=>d.type==="pr.exists.answered"&&d.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,u=()=>(r.forgeWatch??tu)([{name:e.workspace?.repo??null,slug:e.workspace?.repo??null}]);if(n==="push"){let{sayToLead:d}=await r.sayDeps();l=Ko.filter(p=>p!=="pr"&&(i.includes(p)||p==="push")),c=await d(e.id,Ni(l,{branch:a.branch??null,base:a.base??null,toPr:{number:a.pr?.number??null},offeredRebase:a.offeredRebase===!0,forge:await u()}),{kind:"push-go"})}else if(n==="new"){let{sayToLead:d}=await r.sayDeps();l=i,c=await d(e.id,TR(i,{branch:a.branch??null,base:a.base??null,prNumber:a.pr?.number??null,offeredRebase:a.offeredRebase===!0,forge:await u()}),{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:d}=await r.sayDeps();d(e.id,{actions:l})}return{say:c,choice:n}}be();pr();er();jn();Fi();Vo();import{execFile as eZ}from"node:child_process";import{promisify as tZ}from"node:util";var nZ=tZ(eZ);async function tB(e,t){let{stdout:n}=await nZ("git",["-C",e,...t],{timeout:1e4});return String(n||"").trim()}async function rZ(e){let t=await tB(e,["rev-parse","HEAD"]).catch(()=>null),n=await tB(e,["rev-parse","@{u}"]).catch(()=>null);return{head:t,upstream:n}}var oZ={listRepoPrs:kn,readEvents:V,appendEvent:D,currentBranch:fr,headShas:rZ,repoSlug:Re,lookupPr:pt},sZ=new Set(["opened","pushed","ci-fixed","reconciled"]);function aZ(e,t,n=null,r=Date.now()){let o=Number(t?.number),s=Zo(e,r);if(s&&s.offerType!=="report"){if(s.toPr==null)return`an answered ship card is opening this branch's PR, and its PR-opened card (posted when the turn ends) announces #${o} at its final head`;if(s.toPr===o)return`an answered ship card is already settling #${o}, and its card posts when the turn ends`}let a=null,i=!1;for(let u of e||[])u.type==="turn.user"&&u.source!=="hook"?a=u.payload?.ts??u.ts??a:u.type==="pr.state.changed"&&u.payload?.change==="opened"&&Number(u.payload?.number)===o&&(i=!0);if(i||a==null)return null;let c=Date.parse(t?.createdAt??"");return n?.firstSeen!=null&&n.firstSeen>=a||Number.isFinite(c)&&c>=a?`#${o} was opened during this turn, so its PR-opened card (posted when the turn ends) announces it at its final head`:null}async function nB(e,{number:t=null,rebased:n=!1,base:r=null}={},o=oZ){if(!e?.cwd)throw new Error("no Track workspace to read");if(e.workspace?.kind==="multi")throw new Error("run this from inside the checkout whose PR you updated, not the multi-repo hub");let s=await o.currentBranch(e.cwd).catch(()=>null)||e.workspace?.branch||null;if(!s)throw new Error("HEAD is detached \u2014 check out the PR's branch first");let{head:a,upstream:i}=await o.headShas(e.cwd);if(!a)throw new Error("couldn't read HEAD in the Track workspace");if(!i)throw new Error(`${s} has no upstream \u2014 push it first (git push -u origin ${s})`);if(i!==a)throw new Error(`HEAD isn't on the remote yet \u2014 push ${s} first, then report`);let c;try{c=await o.listRepoPrs(e.cwd,{caller:"pr-update-report"})}catch(g){throw new Error(`couldn't read the open PRs (${g?.message||g}) \u2014 try again`)}let l=t!=null?Number(t):null,u=(c||[]).find(g=>g.headRefName===s&&(l==null||Number(g.number)===l));if(!u)throw new Error(l!=null?`#${l} isn't an open PR on ${s}`:`${s} has no open PR \u2014 a newly opened PR is announced automatically; this is only for updating one that is already open`);let d=await o.readEvents(e).catch(()=>[]);if(d.some(g=>(g.type==="pr.state.changed"&&sZ.has(g.payload?.change)||g.type==="pr.update.reported")&&Number(g.payload?.number)===Number(u.number)&&g.payload?.sha===a))return{skipped:!0,reason:`#${u.number} already has a card for ${a.slice(0,7)}`};let w=await o.repoSlug(e.cwd).catch(()=>null),m=w?await o.lookupPr(w,u.number).catch(()=>null):null,h=aZ(d,u,m);return h?{skipped:!0,reason:h}:(await o.appendEvent(e,{type:"pr.update.reported",actor:"agent",source:"cli",boxId:e.leadBox,payload:{ts:Date.now(),number:u.number,url:u.url??null,title:u.title??null,branch:u.headRefName||s,...w?{repo:w}:{},sha:a,...n?{rebased:!0}:{},...r?{base:String(r)}:{}}}),{reported:!0,number:u.number,url:u.url??null,sha:a})}iu();import co from"node:fs/promises";import vc from"node:path";import lB from"node:os";import rB from"node:fs/promises";import Hm from"node:path";import{execFile as iZ}from"node:child_process";import{promisify as cZ}from"node:util";import{fileURLToPath as lZ}from"node:url";var uZ=cZ(iZ),sB=Hm.dirname(lZ(import.meta.url)),dZ=Hm.resolve(sB,"..","..","client","dist"),pZ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fZ=new Map([...pZ].map((e,t)=>[e,t]));function hZ(e){let t=[],n=0,r=0;for(let o of e){let s=fZ.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 mZ(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=hZ(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 wZ(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 oB=new Map;async function gZ(e){let t;try{t=await rB.stat(e)}catch{return null}let n=oB.get(e);if(n&&n.mtimeMs===t.mtimeMs)return n;try{let r=JSON.parse(await rB.readFile(e,"utf8")),o={mtimeMs:t.mtimeMs,sources:r.sources||[],lines:mZ(r.mappings||"")};return oB.set(e,o),o}catch{return null}}var SS=null;function yZ(){return SS||(SS=process.env.BOSTRAT_RELEASE?Promise.resolve(process.env.BOSTRAT_RELEASE):uZ("git",["rev-parse","--short","HEAD"],{cwd:Hm.resolve(sB,"..","..")}).then(e=>e.stdout.trim()).catch(()=>null)),SS}var bZ=/(?:https?:\/\/[^\s()]*)?\/assets\/([^\s()/]+\.js):(\d+):(\d+)/g;async function kZ(e,{distDir:t=dZ}={}){let n=[],r=0,o=!1;for(let s of e.matchAll(bZ)){let[a,i,c,l]=s,u=await gZ(Hm.join(t,"assets",`${i}.map`)),d=u?wZ(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 aB(e,t={}){try{if(!e?.error?.stack||!e.release||e.release==="unknown")return e;let n=t.release??await yZ();if(!n||e.release!==n)return e;let{stack:r,symbolicated:o}=await kZ(e.error.stack,t);o&&(e.error.stack=r,e.error.symbolicated=!0)}catch{}return e}var xZ=()=>process.env.BOSTRAT_STATE_DIR||vc.join(process.env.HOME||lB.tmpdir(),".bostrat"),gs=()=>vc.join(xZ(),"telemetry"),uB=()=>vc.join(gs(),".relay-offsets.json"),SZ=50,vZ=14,AZ=3e4,iB=500,hn=(e,t)=>typeof e=="string"?e.slice(0,t):"";function TZ(e,t){if(!e||typeof e!="object")return null;let n=hn(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:hn(e.anonId,64),sessionId:hn(e.sessionId,64),userId:hn(e.userId,64),release:hn(e.release,64),appVersion:hn(e.appVersion,32),route:hn(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:hn(e.error.kind,256),message:hn(e.error.message,8192),stack:hn(e.error.stack,32768),fingerprint:hn(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:hn(s?.n,64),r:hn(s?.r,128)}))),o}var dB=e=>new Date(e).toISOString().slice(0,10),cB=0;async function pB(e,t=Date.now()){let r=(Array.isArray(e?.events)?e.events.slice(0,SZ):[]).map(s=>TZ(s,t)).filter(Boolean);if(!r.length)return 0;for(let s of r)s.error?.stack&&await aB(s);await co.mkdir(gs(),{recursive:!0});let o=vc.join(gs(),`${dB(t)}.ndjson`);return await co.appendFile(o,r.map(s=>JSON.stringify(s)+`
|
|
964
964
|
`).join(""),"utf8"),t-cB>6*3600*1e3&&(cB=t,EZ(t).catch(()=>{})),r.length}async function EZ(e=Date.now()){let t=dB(e-vZ*24*3600*1e3),n=[];try{n=await co.readdir(gs())}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 co.rm(vc.join(gs(),s),{force:!0});let o=await hB();for(let s of r)delete o[s];await mB(o)}var Wm=new Map;function fB(e,t=Date.now()){let n=e||"unknown",r=Wm.get(n);return r||(Wm.size>512&&Wm.clear(),r={tokens:40,at:t},Wm.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 hB(){try{return JSON.parse(await co.readFile(uB(),"utf8"))||{}}catch{return{}}}async function mB(e){await co.mkdir(gs(),{recursive:!0}),await co.writeFile(uB(),JSON.stringify(e),"utf8")}function _Z(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||lB.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 IZ({fetchImpl:e=fetch}={}){let t=await fP();if(!t)return{sent:0,disabled:!0};let n;try{n=(await co.readdir(gs())).filter(s=>s.endsWith(".ndjson")).sort()}catch{return{sent:0,disabled:!1}}let r=await hB(),o=0;for(let s of n){let a=vc.join(gs(),s),i=r[s]||0,c;try{let p=await co.open(a,"r");try{let w=(await p.stat()).size;if(w<=i)continue;c=Buffer.alloc(w-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(`
|
|
965
|
-
`).filter(Boolean),d=[];for(let p of u)try{d.push(JSON.parse(p))}catch{}for(let p=0;p<d.length;p+=iB){let w=d.slice(p,p+iB).map(f=>_Z(f)),m=await e(`${t.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${t.ingestKey}`},body:JSON.stringify({events:w})}).catch(()=>null);if(!m||!m.ok)return{sent:o,disabled:!1};o+=w.length}r[s]=i+l+1,await mB(r)}return{sent:o,disabled:!1}}var vS=null,AS=!1;function wB(){vS||(vS=setInterval(async()=>{if(!AS){AS=!0;try{await IZ()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{AS=!1}}},AZ),vS.unref?.())}import Gm from"node:fs/promises";import xB from"node:path";import $Z from"node:os";var SB=()=>process.env.BOSTRAT_STATE_DIR||xB.join(process.env.HOME||$Z.tmpdir(),".bostrat"),vB=()=>xB.join(SB(),"dictation-glossary.json"),RZ=100,OZ=500,MZ=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Km=null,TS=null,ES=Promise.resolve();function gB(){let e={},t=Date.now();for(let n of MZ)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function AB(){return Km||(TS??=Gm.readFile(vB(),"utf8").then(e=>JSON.parse(e)?.terms??gB()).catch(()=>gB()).then(e=>Km=e).finally(()=>TS=null),TS)}async function yB(){let e=JSON.stringify({terms:Km},null,2),t=vB(),n=`${t}.${process.pid}.tmp`;await Gm.mkdir(SB(),{recursive:!0}),await Gm.writeFile(n,e),await Gm.rename(n,t)}function CZ(){return ES=ES.then(yB,yB),ES.catch(()=>{})}async function _S(){return Object.values(await AB()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var NZ=e=>Math.max(1,Math.ceil(e.length/4));async function PZ(){let e=[],t=0;for(let{term:n}of await _S()){let r=NZ(n);if(!(t+r>OZ)&&(e.push(n),t+=r,e.length>=RZ))break}return e}async function DZ(e,t){let n=await AB(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var bB=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),qm=e=>e.toLowerCase();function kB(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function TB(e,t){let n=bB(e),r=bB(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]=qm(n[u])===qm(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;)qm(n[c])===qm(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(kB(r[l])&&i.add(r[l]),l++);for(;l<s;l++)kB(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await DZ(u,"learned");return await CZ(),[...i]}var vd=null;function BZ(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 EB(){if(!vd)return null;let e=await ed();if(!e||e.apiKey.slice(-6)!==vd.keyTail)return null;let{keyTail:t,...n}=vd;return n}async function _B(e,t){let n=await ed();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 PZ())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=BZ(o.status,i);c.persistent&&(vd={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 vd=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}be();var IS={"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 LZ(e){if(!e)return null;let t=String(e).trim();if(IS[t])return t;let n=null;for(let r of Object.keys(IS))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function jZ(e,t={}){let n=IS[LZ(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 FZ(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 Ad=null;async function UZ(){if(!Ad)return null;let e=await gm();if(!e||e.apiKey.slice(-6)!==Ad.keyTail)return null;let{keyTail:t,...n}=Ad;return n}async function HZ(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=FZ(t.status,o);s.persistent&&(Ad={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}Ad=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 WZ={openai:HZ};async function IB(){let e=await gm();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await UZ()}:{configured:!1}}async function $B(){let e=await gm();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 WZ[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function RB(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=jZ(t,s),i=await D(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}}yn();g$(async()=>new Set((await xe()).map(e=>e.id)));var NS=De.dirname(GZ(import.meta.url)),CS=Number(process.env.PORT)||3362,Vm=z0(process.env),LB=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,Tc=OD(process.env.BOSTRAT_ALLOW_IPS),zm=MD(process.env.BOSTRAT_VIEW_FRONT_CIDRS,Cm),PS=ND(),jB=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",O=en();O.disable("x-powered-by");O.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),wd(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});O.use((e,t,n)=>{if(md(e)||Tc.allowed(Tc.clientIp(e))||zm.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});O.use(WD);O.use(BD({token:PS,enforce:jB}));O.use("/api/mocks",en.json({limit:"1mb"}));O.use("/api/mocks",en.raw({type:"image/png",limit:"24mb"}));O.use("/api/mocks",en.raw({type:["video/mp4","video/webm"],limit:"105mb"}));O.use("/api/runbooks",en.json({limit:"1mb"}));O.use("/api/blueprints",en.json({limit:"1mb"}));O.use("/api/tracks/adopt",en.json({limit:"1mb"}));O.use("/api/telemetry",en.json({limit:"256kb"}));O.use("/api/hook",en.json({limit:"2mb"}));O.use("/api/dictation",en.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));O.use("/api/tracks/:id/upload",en.raw({type:()=>!0,limit:"25mb"}));O.use(en.json({limit:"64kb"}));var YZ=(()=>{try{let e=JSON.parse($t.readFileSync(De.resolve(NS,"..","..","client","dist","build.json"),"utf8")),t=typeof e?.sha=="string"?e.sha.trim():"";return!t||t==="unknown"?null:{sha:t,version:typeof e.version=="string"&&e.version.trim()?e.version.trim():null}}catch{return null}})();O.get("/api/health",async(e,t)=>{t.json({ok:!0,build:YZ,tmuxSocket:St,hostTmuxAlive:await So(),autoTriggerPct:LB,plane:Ec?Ec.status():null})});O.get("/api/sessions",async(e,t)=>{t.json({sessions:await sn()})});O.post("/api/sessions",async(e,t)=>{let{displayName:n,cwd:r}=e.body||{};if(typeof n!="string")return t.status(400).json({error:"displayName (string) required"});try{let o=await or(n,r||void 0);t.json({ok:!0,...o})}catch(o){let s=o?.message||String(o),a=/already exists/i.test(s)?409:/must be|invalid/i.test(s)?400:500;t.status(a).json({error:s})}});O.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!qe(n))return t.status(400).json({error:"invalid session name"});if(!await _e(n))return t.status(404).json({error:"session not found"});try{await zt(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});O.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!qe(n))return t.status(400).json({error:"invalid session name"});let r=await _e(n);if(!r)return t.status(404).json({error:"session not found"});let o=await cl(r.cwd,r.sessionId);if(!o)return t.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});t.json({available:!0,...o})});O.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!qe(n))return t.status(400).json({error:"invalid session name"});try{let r=await S_(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)})}});O.get("/api/handoff/:name",(e,t)=>{let n=decodeURIComponent(e.params.name),r=Zp(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 OB=10;async function DS(){let e=await xe(),[t,n]=await Promise.all([VC(e),NN(e)]);return{tracks:e,views:await kh(),queuedOf:r=>ss(r),jobsOf:r=>t.get(r)??[],prPendingOf:r=>n.get(r)??[],deps:II()}}O.get("/api/idle-guard",async(e,t)=>{try{t.json(V0(await DS()))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var mn=Aa(),XZ=zN({kind:mn}),Td=null,Nt=()=>Td&&["auto","prompt","off"].includes(Td)?Td:XZ,_d=null,ZZ=Zu.has(mn),BS=async({to:e,from:t})=>!ZZ||Qu(await lc())?!1:(_c.arm({to:e,from:t,kind:mn}),!0);async function QZ(e){let t=Nt();Td=e??null;let n=Nt();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){_c.cancel();return}_d&&await BS(_d)}}var FB=(()=>{try{return JZ(import.meta.url)("../package.json").version||null}catch{return null}})(),_c=ZN({isBusy:async()=>V0(await DS()).busy,onStuck:({to:e,from:t})=>vr({current:t,latest:e,installKind:mn,policy:Nt(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?vr({current:t,latest:e,installKind:mn,policy:Nt(),status:"updating",reason:"auto"}):vr({current:t,latest:e,installKind:mn,policy:Nt(),status:"failed",error:n?.reason})).catch(()=>{})}),eQ=UD({idleMs:jD({kind:mn}),input:DS,listViews:kh,stop:tk,onStopped:()=>_c.tick()});O.get("/api/node/self-update",async(e,t)=>{t.json({installKind:mn,policy:Nt(),policySource:Td?"plane":"node",current:FB,status:await lc(),armed:_c.armed})});O.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 dm({to:n,kind:mn,reason:"manual",force:!0});if(r.ok)return _c.cancel(),vr({current:r.from,latest:n,installKind:mn,policy:Nt(),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 UB(){try{let e=await XN();e&&await vr({current:e.from,latest:e.to,installKind:e.kind||mn,policy:Nt(),status:e.status,error:e.error,reason:e.reason}),e?.status==="failed"&&e.retryable===!0&&Nt()==="auto"&&_d?.latest===e.to&&await BS({to:e.to,from:_d.current})&&console.log(`[self-update] ${e.to} is not on the npm registry yet \u2014 re-armed for the next stasis (attempt ${Number(e.attempts)||1} of ${um} used)`),await t0({current:FB,installKind:mn,policy:Nt()})}catch{}}UB();setInterval(UB,3e4).unref();O.get("/api/tracks",async(e,t)=>{let n=(await xe()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>OB){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,OB).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:Wu,agentAvailability:await Hh(),tickets:await PP()})});O.get("/api/cost",async(e,t)=>{try{let n=await xe();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await Bx(n);if(r.cursorUsage=Db(),e.query.format==="text")return t.type("text/plain").send(iD(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/usage/roundup",async(e,t)=>{try{let n=await jx(await xe(),{window:e.query.window,from:e.query.from,to:e.query.to});if(e.query.format==="text")return t.type("text/plain").send(pD(n));t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/usage/spend",async(e,t)=>{try{let n=await gD(await xe(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=Db(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=Kl(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/usage/caps",(e,t)=>{t.json(Kl())});O.post("/api/usage/caps",async(e,t)=>{try{t.json(await $f(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});O.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await ED(await xe(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await ev(e.get(In),{byToken:nc,legacy:()=>uu(e.body?.session_id,e.body?.cwd)});if(n==="refused")return Oc("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Oc("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&&Oc("mismatch",{track:r.track.id,box:r.box.name}),Oc(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 oD(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&ep(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});O.get("/api/git/trailers",async(e,t)=>{t.type("text/plain");try{let n=await nc(e.get(In));if(!n?.track||!n?.box)return t.status(204).end();t.send((await GR(n.track,n.box)).join(`
|
|
965
|
+
`).filter(Boolean),d=[];for(let p of u)try{d.push(JSON.parse(p))}catch{}for(let p=0;p<d.length;p+=iB){let w=d.slice(p,p+iB).map(h=>_Z(h)),m=await e(`${t.url.replace(/\/$/,"")}/v1/logs`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${t.ingestKey}`},body:JSON.stringify({events:w})}).catch(()=>null);if(!m||!m.ok)return{sent:o,disabled:!1};o+=w.length}r[s]=i+l+1,await mB(r)}return{sent:o,disabled:!1}}var vS=null,AS=!1;function wB(){vS||(vS=setInterval(async()=>{if(!AS){AS=!0;try{await IZ()}catch(e){console.error("[telemetry] relay failed:",e?.message||e)}finally{AS=!1}}},AZ),vS.unref?.())}import Gm from"node:fs/promises";import xB from"node:path";import $Z from"node:os";var SB=()=>process.env.BOSTRAT_STATE_DIR||xB.join(process.env.HOME||$Z.tmpdir(),".bostrat"),vB=()=>xB.join(SB(),"dictation-glossary.json"),RZ=100,OZ=500,MZ=["bostrat","globopi","codex","tmux","worktree","Deepgram","Linear","Firecracker","Tigris","WireGuard","misous","postyx","cedar","gerbil","Anthropic","Opus","Haiku","Sonnet","keyterm","monorepo","dogfood"],Km=null,TS=null,ES=Promise.resolve();function gB(){let e={},t=Date.now();for(let n of MZ)e[n.toLowerCase()]={term:n,count:1,lastUsed:t,source:"seed"};return e}async function AB(){return Km||(TS??=Gm.readFile(vB(),"utf8").then(e=>JSON.parse(e)?.terms??gB()).catch(()=>gB()).then(e=>Km=e).finally(()=>TS=null),TS)}async function yB(){let e=JSON.stringify({terms:Km},null,2),t=vB(),n=`${t}.${process.pid}.tmp`;await Gm.mkdir(SB(),{recursive:!0}),await Gm.writeFile(n,e),await Gm.rename(n,t)}function CZ(){return ES=ES.then(yB,yB),ES.catch(()=>{})}async function _S(){return Object.values(await AB()).sort((t,n)=>n.count-t.count||n.lastUsed-t.lastUsed)}var NZ=e=>Math.max(1,Math.ceil(e.length/4));async function PZ(){let e=[],t=0;for(let{term:n}of await _S()){let r=NZ(n);if(!(t+r>OZ)&&(e.push(n),t+=r,e.length>=RZ))break}return e}async function DZ(e,t){let n=await AB(),r=e.toLowerCase(),o=n[r];n[r]={term:e,count:(o?.count??0)+1,lastUsed:Date.now(),source:o?.source??t}}var bB=e=>(e||"").split(/\s+/).map(t=>t.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"")).filter(Boolean),qm=e=>e.toLowerCase();function kB(e){return!new RegExp("\\p{L}","u").test(e)||e.length<3?!1:/^[a-z]+$/.test(e)?e.length>=4:!0}async function TB(e,t){let n=bB(e),r=bB(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]=qm(n[u])===qm(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;)qm(n[c])===qm(r[l])?(c++,l++):a[c+1][l]>=a[c][l+1]?c++:(kB(r[l])&&i.add(r[l]),l++);for(;l<s;l++)kB(r[l])&&i.add(r[l]);if(!i.size)return[];for(let u of i)await DZ(u,"learned");return await CZ(),[...i]}var vd=null;function BZ(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 EB(){if(!vd)return null;let e=await ed();if(!e||e.apiKey.slice(-6)!==vd.keyTail)return null;let{keyTail:t,...n}=vd;return n}async function _B(e,t){let n=await ed();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 PZ())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=BZ(o.status,i);c.persistent&&(vd={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 vd=null,{transcript:(await o.json())?.results?.channels?.[0]?.alternatives?.[0]?.transcript??""}}be();var IS={"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 LZ(e){if(!e)return null;let t=String(e).trim();if(IS[t])return t;let n=null;for(let r of Object.keys(IS))t.startsWith(r)&&(!n||r.length>n.length)&&(n=r);return n}function jZ(e,t={}){let n=IS[LZ(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 FZ(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 Ad=null;async function UZ(){if(!Ad)return null;let e=await gm();if(!e||e.apiKey.slice(-6)!==Ad.keyTail)return null;let{keyTail:t,...n}=Ad;return n}async function HZ(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=FZ(t.status,o);s.persistent&&(Ad={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}Ad=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 WZ={openai:HZ};async function IB(){let e=await gm();return e?{configured:!0,provider:e.provider,model:e.model,voice:e.voice,problem:await UZ()}:{configured:!1}}async function $B(){let e=await gm();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 WZ[e.provider](e);return{provider:e.provider,model:e.model,voice:e.voice,...t}}async function RB(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=jZ(t,s),i=await D(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}}yn();g$(async()=>new Set((await xe()).map(e=>e.id)));var NS=De.dirname(GZ(import.meta.url)),CS=Number(process.env.PORT)||3362,Vm=z0(process.env),LB=Number(process.env.BOSTRAT_AUTO_TRIGGER_PCT)||80,Tc=OD(process.env.BOSTRAT_ALLOW_IPS),zm=MD(process.env.BOSTRAT_VIEW_FRONT_CIDRS,Cm),PS=ND(),jB=process.env.BOSTRAT_ALLOW_LAN_TOKENLESS!=="1",O=en();O.disable("x-powered-by");O.use((e,t,n)=>{t.setHeader("x-content-type-options","nosniff"),wd(e.headers.host)||(t.setHeader("x-frame-options","DENY"),t.setHeader("referrer-policy","strict-origin-when-cross-origin")),n()});O.use((e,t,n)=>{if(md(e)||Tc.allowed(Tc.clientIp(e))||zm.allows(e))return n();t.status(403).type("text/plain").send("bostrat: access restricted to the allowlist")});O.use(WD);O.use(BD({token:PS,enforce:jB}));O.use("/api/mocks",en.json({limit:"1mb"}));O.use("/api/mocks",en.raw({type:"image/png",limit:"24mb"}));O.use("/api/mocks",en.raw({type:["video/mp4","video/webm"],limit:"105mb"}));O.use("/api/runbooks",en.json({limit:"1mb"}));O.use("/api/blueprints",en.json({limit:"1mb"}));O.use("/api/tracks/adopt",en.json({limit:"1mb"}));O.use("/api/telemetry",en.json({limit:"256kb"}));O.use("/api/hook",en.json({limit:"2mb"}));O.use("/api/dictation",en.raw({type:["audio/*","video/mp4","application/octet-stream"],limit:"32mb"}));O.use("/api/tracks/:id/upload",en.raw({type:()=>!0,limit:"25mb"}));O.use(en.json({limit:"64kb"}));var YZ=(()=>{try{let e=JSON.parse($t.readFileSync(De.resolve(NS,"..","..","client","dist","build.json"),"utf8")),t=typeof e?.sha=="string"?e.sha.trim():"";return!t||t==="unknown"?null:{sha:t,version:typeof e.version=="string"&&e.version.trim()?e.version.trim():null}}catch{return null}})();O.get("/api/health",async(e,t)=>{t.json({ok:!0,build:YZ,tmuxSocket:St,hostTmuxAlive:await So(),autoTriggerPct:LB,plane:Ec?Ec.status():null})});O.get("/api/sessions",async(e,t)=>{t.json({sessions:await sn()})});O.post("/api/sessions",async(e,t)=>{let{displayName:n,cwd:r}=e.body||{};if(typeof n!="string")return t.status(400).json({error:"displayName (string) required"});try{let o=await or(n,r||void 0);t.json({ok:!0,...o})}catch(o){let s=o?.message||String(o),a=/already exists/i.test(s)?409:/must be|invalid/i.test(s)?400:500;t.status(a).json({error:s})}});O.delete("/api/sessions/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!qe(n))return t.status(400).json({error:"invalid session name"});if(!await _e(n))return t.status(404).json({error:"session not found"});try{await zt(n),t.json({ok:!0})}catch(r){t.status(500).json({error:`failed to kill: ${r?.message||r}`})}});O.get("/api/context/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!qe(n))return t.status(400).json({error:"invalid session name"});let r=await _e(n);if(!r)return t.status(404).json({error:"session not found"});let o=await cl(r.cwd,r.sessionId);if(!o)return t.json({available:!1,cwd:r.cwd,sessionId:r.sessionId||null});t.json({available:!0,...o})});O.post("/api/handoff/:name",async(e,t)=>{let n=decodeURIComponent(e.params.name);if(!qe(n))return t.status(400).json({error:"invalid session name"});try{let r=await S_(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)})}});O.get("/api/handoff/:name",(e,t)=>{let n=decodeURIComponent(e.params.name),r=Zp(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 OB=10;async function DS(){let e=await xe(),[t,n]=await Promise.all([VC(e),NN(e)]);return{tracks:e,views:await kh(),queuedOf:r=>ss(r),jobsOf:r=>t.get(r)??[],prPendingOf:r=>n.get(r)??[],deps:II()}}O.get("/api/idle-guard",async(e,t)=>{try{t.json(V0(await DS()))}catch{t.status(500).json({busy:!0,reasons:["error"]})}});var mn=Aa(),XZ=zN({kind:mn}),Td=null,Nt=()=>Td&&["auto","prompt","off"].includes(Td)?Td:XZ,_d=null,ZZ=Zu.has(mn),BS=async({to:e,from:t})=>!ZZ||Qu(await lc())?!1:(_c.arm({to:e,from:t,kind:mn}),!0);async function QZ(e){let t=Nt();Td=e??null;let n=Nt();if(t!==n){if(console.log(`[self-update] policy ${t} \u2192 ${n} (${e?"plane row":"node default"})`),n!=="auto"){_c.cancel();return}_d&&await BS(_d)}}var FB=(()=>{try{return JZ(import.meta.url)("../package.json").version||null}catch{return null}})(),_c=ZN({isBusy:async()=>V0(await DS()).busy,onStuck:({to:e,from:t})=>vr({current:t,latest:e,installKind:mn,policy:Nt(),status:"stuck"}).catch(()=>{}),onStarted:({to:e,from:t,result:n})=>(n?.ok?vr({current:t,latest:e,installKind:mn,policy:Nt(),status:"updating",reason:"auto"}):vr({current:t,latest:e,installKind:mn,policy:Nt(),status:"failed",error:n?.reason})).catch(()=>{})}),eQ=UD({idleMs:jD({kind:mn}),input:DS,listViews:kh,stop:tk,onStopped:()=>_c.tick()});O.get("/api/node/self-update",async(e,t)=>{t.json({installKind:mn,policy:Nt(),policySource:Td?"plane":"node",current:FB,status:await lc(),armed:_c.armed})});O.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 dm({to:n,kind:mn,reason:"manual",force:!0});if(r.ok)return _c.cancel(),vr({current:r.from,latest:n,installKind:mn,policy:Nt(),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 UB(){try{let e=await XN();e&&await vr({current:e.from,latest:e.to,installKind:e.kind||mn,policy:Nt(),status:e.status,error:e.error,reason:e.reason}),e?.status==="failed"&&e.retryable===!0&&Nt()==="auto"&&_d?.latest===e.to&&await BS({to:e.to,from:_d.current})&&console.log(`[self-update] ${e.to} is not on the npm registry yet \u2014 re-armed for the next stasis (attempt ${Number(e.attempts)||1} of ${um} used)`),await t0({current:FB,installKind:mn,policy:Nt()})}catch{}}UB();setInterval(UB,3e4).unref();O.get("/api/tracks",async(e,t)=>{let n=(await xe()).filter(s=>!s.transferredTo),r=n.filter(s=>s.archivedAt&&!s.archiving),o=n;if(e.query.archived!=="all"&&r.length>OB){let s=new Set([...r].sort((a,i)=>(i.archivedAt||0)-(a.archivedAt||0)).slice(0,OB).map(a=>a.id));o=n.filter(a=>!a.archivedAt||a.archiving||s.has(a.id))}t.json({tracks:o,archivedTotal:r.length,agents:Wu,agentAvailability:await Hh(),tickets:await PP()})});O.get("/api/cost",async(e,t)=>{try{let n=await xe();e.query.track&&(n=n.filter(o=>o.id===e.query.track));let r=await Bx(n);if(r.cursorUsage=Db(),e.query.format==="text")return t.type("text/plain").send(iD(r));t.json(r)}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/usage/roundup",async(e,t)=>{try{let n=await jx(await xe(),{window:e.query.window,from:e.query.from,to:e.query.to});if(e.query.format==="text")return t.type("text/plain").send(pD(n));t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/usage/spend",async(e,t)=>{try{let n=await gD(await xe(),{window:e.query.window,from:e.query.from,to:e.query.to});n.cursorUsage=Db(),n.subscriptionMonthlyUsd=Number(process.env.BOSTRAT_SUBSCRIPTION_MONTHLY_USD)||null,n.caps=Kl(),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/usage/caps",(e,t)=>{t.json(Kl())});O.post("/api/usage/caps",async(e,t)=>{try{t.json(await $f(e.body?.caps??{},{source:"local"}))}catch(n){t.status(400).json({error:n?.message||String(n)})}});O.get("/api/usage/limits",async(e,t)=>{try{let n=e.query.fresh==="1"||e.query.fresh==="true";t.json(await ED(await xe(),{fresh:n}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.post("/api/hook",async(e,t)=>{try{let{mode:n,target:r}=await ev(e.get(In),{byToken:nc,legacy:()=>uu(e.body?.session_id,e.body?.cwd)});if(n==="refused")return Oc("refused",{reason:"unknown-token",hook:e.body?.hook_event_name}),t.json({ok:!1,error:"unknown hook token"});if(n==="legacy-denied")return Oc("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&&Oc("mismatch",{track:r.track.id,box:r.box.name}),Oc(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 oD(e.body||{},()=>r);e.body?.hook_event_name==="Stop"&&r?.box?.cwd&&ep(r.box.cwd),t.json({ok:!0,events:o.length})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});O.get("/api/git/trailers",async(e,t)=>{t.type("text/plain");try{let n=await nc(e.get(In));if(!n?.track||!n?.box)return t.status(204).end();t.send((await GR(n.track,n.box)).join(`
|
|
966
966
|
`)+`
|
|
967
|
-
`)}catch{t.status(204).end()}});O.post("/api/git/committed",async(e,t)=>{try{let n=await nc(e.get(In));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?De.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?De.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+De.sep))?s:o;KR(n.track,n.box,r,{cwd:a}).catch(i=>console.warn(`[rework] ${n.track.id}: recordCommit failed: ${i?.message||i}`)),HB(n)}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});function HB(e){let t=e?.box?.cwd;!t||!e?.track?.id||Gl(t,{track:{id:e.track.id,cwd:e.track.cwd},boxId:e.box.name}).catch(()=>{})}O.post("/api/deps/refresh",async(e,t)=>{try{let n=await nc(e.get(In));if(!n?.track||!n?.box)return t.json({ok:!1,error:"unknown hook token"});t.json({ok:!0}),HB(n)}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});O.post("/api/tracks/:id/rework-cause",async(e,t)=>{try{let n=await ye(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 zR(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})}});O.post("/api/tracks/:id/rework-cause/retract",async(e,t)=>{try{let n=await ye(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,event:await JR(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})}});O.get("/api/usage/rework",async(e,t)=>{try{t.json(await yD(await xe(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/usage/forge-polls",async(e,t)=>{try{let n=Math.min(Math.max(Number(e.query.days)||7,1),90),r=eB(n),o=await Promise.all((await xe()).map(async s=>({trackId:s.id,name:s.name??null,...Z1(await V(s).catch(()=>[]),{...r,trackId:s.id})})));t.json(Q1(o,r))}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.post("/api/telemetry",async(e,t)=>{try{if(!fB(Tc.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await pB(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});O.get("/api/repos",async(e,t)=>{try{let n=await Ir(),r=new Set((await Promise.all(n.map(a=>Re(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await $s()).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)})}});O.get("/api/github/token",async(e,t)=>{try{t.json(await wo(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});O.get("/api/github/status",(e,t)=>{t.json({configured:Gd(),calls:L$(),latency:H$(),webhook:I1(),openedTrail:sR()})});O.post("/api/github/event",en.json({limit:"64kb"}),(e,t)=>{let n=E1(e.body,{onAccept:r=>V1(r)});if(!n.ok)return t.status(400).json({error:n.error});t.json({ok:!0,duplicate:n.duplicate})});O.post("/api/github/refresh",(e,t)=>{_v(),t.json({ok:!0})});O.get("/api/gmail/search",async(e,t)=>{try{let n=await ID(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)})}});O.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await $D(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});async function Ed({repo:e=null,number:t=null,branch:n=null}){let r=e?await Re(e):null;if(r&&t!=null){let s=await pt(r,t),a=s&&await ye(s.trackId);if(a)return a}if(!n)return null;let o=await xe();return Xf(o,n,s=>Zf(s,{branch:n,repo:e,slug:r}))}async function WB({repo:e=null,number:t=null,branch:n=null}){let r=await Ed({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!He(r))return r;if(!n)return null;let o=e?await Re(e).catch(()=>null):null,s=await xe();return Xf(s,n,a=>!He(a)&&Zf(a,{branch:n,repo:e,slug:o}))}async function Yn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await Ed({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await Re(s).catch(()=>null):null);e==="opened"&&await Hr({repo:l,number:t,via:"api"}).catch(()=>{}),await D({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 tQ(e){let t=(await xe()).filter(n=>!He(n));for(let n of e??[]){if(!n.prs?.length)continue;let r=await Re(n.path);if(r)for(let o of n.prs){if(await pt(r,o.number))continue;let s=await Xf(t,o.headRefName,a=>Zf(a,{branch:o.headRefName,repo:n.path,slug:r}));s&&await ln({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}O.get("/api/git/prs",async(e,t)=>{try{let n=await aR();await tQ(n.repos).catch(()=>{}),await Dm(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.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,w=null,m=null;try{if(s){let b=o||"merge";if(!Zl.has(b))throw new Error(`invalid merge method: ${b}`);let x=Number(r);if(!Number.isInteger(x)||x<=0)throw new Error("invalid PR number");let v=await Re((await Wr(n)).path);if(!v)throw new Error("repo has no GitHub remote");let S=await Ed({repo:n,number:x,branch:l}).catch(()=>null);if(!S)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(p=S,w=await Ch(S,"merge",{count:1,summary:`arming auto-merge on PR #${x}`}),a&&await Ql(n,x),await ln({repo:v,number:x,trackId:S.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await Vl(v,x,{merge:{method:b}}))throw new Error("couldn't record the auto-merge arm");return await na(v,x,i===!0),await ra(v,x,c===!0&&i!==!0),xn(),await Yn("auto-armed",{number:x,url:d,title:u,branch:l,repo:n,track:S,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:x,auto:!0})}p=await Ed({repo:n,number:r,branch:l}).catch(()=>null),p&&(w=await Ch(p,"merge",{count:1,summary:`merging PR #${r}`}));let f=await Ci(n,r,{method:o||"squash"});await Yn("merged",{number:f.number,url:d,title:u,branch:l,repo:n});let g=await Re(n).catch(()=>null),y=!1;if(g&&(i===!0&&await na(g,f.number,!0).catch(()=>{}),c===!0&&i!==!0&&await ra(g,f.number,!0).catch(()=>{}),await Kr(g,f.number).catch(()=>{}),await Sa(g,f.number).catch(()=>{}),y=await Gr(g,f.number).catch(()=>!1),await Ho(g,f.number,"merged").catch(()=>{})),i===!0&&!y){let b=await Ed({repo:n,number:f.number,branch:l}).catch(()=>null);b&&!b.archivedAt&&await xa(b.id).catch(()=>{})}t.json(f)}catch(f){m=f;let g=f?.message||String(f),y=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(g)?400:502;t.status(y).json({error:g})}finally{p&&w&&await Bk(p,w,m?"failed":"completed",m).catch(()=>{})}});O.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 Re((await Wr(n)).path).catch(()=>null),l=c?await zl(c,i).catch(()=>null):null;try{await sb(n,i)}catch(u){if(!l)throw u}xn(),await Yn("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})}});O.post("/api/git/prs/merge-all",async(e,t)=>{let{repo:n,method:r}=e.body||{};try{let o=await Re(n).catch(()=>null),s=await fR(n,{method:r||"merge",onMerged:a=>{Yn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&Kr(o,a.number).catch(()=>{}).then(()=>Sa(o,a.number)).catch(()=>{}).then(()=>Gr(o,a.number)).catch(()=>{}).then(()=>Ho(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})}});O.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:pR()})});O.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(!Zl.has(u))throw new Error(`invalid merge method: ${u}`);if(!n)return t.status(400).json({error:"trackId required"});let d=await ye(n);if(!d)return t.status(404).json({error:`Track ${n} isn't on this node`});i=d;let p=(await Ln()).filter(f=>f.trackId===d.id&&f.state!=="merged"&&f.state!=="closed").sort(eu);if(!p.length)return t.status(409).json({error:"no open PRs on this Track"});c=await Ch(d,"merge",{count:p.length,summary:p.length===1?"merging 1 PR":`merging ${p.length} PRs`});for(let f of p)await na(f.repo,f.number,o===!0).catch(()=>{}),await ra(f.repo,f.number,s===!0&&o!==!0).catch(()=>{});let w=[],m=[];for(let f of p){let g={repo:f.repo,number:f.number,ok:!0,action:"armed"};w.push(g);try{let y=await ia(f.repo);if(!y)throw new Error(`no local checkout for ${f.repo}`);let b=await Mi(y,f.number);m.push({r:g,l:f,repoPath:y,pr:b,plan:iR(b,{update:r!==!1})})}catch(y){g.ok=!1,g.action="failed",g.reason=y?.message||String(y)}}for(let{r:f,l:g,repoPath:y,pr:b,plan:x}of cR(m))try{if(x.action==="skip")f.action="skipped",f.reason=x.reason;else if(x.action==="merge")await Ci(y,g.number,{method:u}),await Yn("merged",{number:g.number,url:b.url,title:b.title,branch:b.headRefName,repo:y,track:d}),await Kr(g.repo,g.number).catch(()=>{}),await Sa(g.repo,g.number).catch(()=>{}),await Gr(g.repo,g.number).catch(()=>{}),await Ho(g.repo,g.number,"merged").catch(()=>{}),f.action="merged";else{if(x.action==="update-arm"&&(await Ql(y,g.number).catch(()=>{}),f.action="updated-armed"),!await Vl(g.repo,g.number,{merge:{method:u}}))throw new Error("couldn't record the auto-merge arm");await Yn("auto-armed",{number:g.number,url:b.url,title:b.title,branch:b.headRefName,repo:y,track:d,...f.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(v){f.ok=!1,f.action="failed",f.reason=v?.message||String(v)}if(xn(),!w.some(f=>f.ok)){if(o===!0)for(let f of p)await na(f.repo,f.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let f of p)await ra(f.repo,f.number,!1).catch(()=>{});return t.status(502).json({error:w.map(f=>`${f.repo}#${f.number}: ${f.reason}`).join("; "),results:w})}t.json({ok:!0,trackId:d.id,results:w})}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 Bk(i,c,l?"failed":"completed",l).catch(()=>{})}});O.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 ye(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await Ln()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await zl(a.repo,a.number).catch(()=>null),c=await ia(a.repo).catch(()=>null);c&&await sb(c,a.number).catch(()=>{}),i&&(await Yn("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}))}xn(),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})}});O.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 ye(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=Qt(i.workspace),d,p=Array.isArray(a)?a.filter(Boolean):[];if(p.length)d=p.map(f=>{let g=u.find(y=>y.name===f||y.repo===f||y.base===f||y.dir===f);if(!g)throw new Error(`invalid repo "${f}" \u2014 not tagged on this Track`);return g});else if(d=await ha(i),!d.length)return t.status(409).json({error:"no tagged repo has work to ship"});let w=[];for(let f of d)try{let g=await ib(f.dir,{title:r,body:o,base:s}),y=f.repo||await Re(f.dir).catch(()=>null);y&&g.number&&await ln({repo:y,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Yn("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:y??f.name}}),w.push({repo:f.name,slug:y??null,ok:!0,url:g.url,number:g.number})}catch(g){w.push({repo:f.name,slug:f.repo??null,ok:!1,error:g?.message||String(g)})}let m=w.filter(f=>f.ok);return m.length?t.json({ok:!0,multi:!0,results:w,url:m[0].url,number:m[0].number}):t.status(502).json({error:w.map(f=>`${f.repo}: ${f.error}`).join("; "),results:w})}let c=await ib(i.cwd,{title:r,body:o,base:s}),l=await Re(i.cwd).catch(()=>null);l&&c.number&&await ln({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Yn("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})}});O.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await ye(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await ha(n),o=new Map(r.map(a=>[a.base,a])),s=Qt(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)})}});O.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 zh(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})}});O.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await Jh(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})}});O.post("/api/tracks/:id/reshape",async(e,t)=>{let{repos:n,skipPermissions:r}=e.body||{};try{let o=await b0(e.params.id,n,{skipPermissions:r!==!1});t.status(o.finishedAt?200:202).json({ok:!0,...LS(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})}});O.get("/api/tracks/:id/reshape",(e,t)=>{t.json(LS(qu(e.params.id))??{running:!1})});function LS(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}O.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Mi(n,r),s=await Re(n).catch(()=>null),a=await WB({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=Qt(a.workspace).find(y=>y.base===n||s&&y.repo===s)??null,c=a.workspace?.kind==="multi",l=await hR(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?De.join("ci",i.name):"ci",d=De.join(a.cwd,".bostrat",u),p=De.join(".bostrat",u,`pr-${o.number}-fail.log`);await $t.promises.mkdir(d,{recursive:!0}),await $t.promises.writeFile(De.join(a.cwd,p),l.map(y=>`\u2550\u2550\u2550\u2550 ${y.name}${y.link?` \xB7 ${y.link}`:""} \u2550\u2550\u2550\u2550
|
|
967
|
+
`)}catch{t.status(204).end()}});O.post("/api/git/committed",async(e,t)=>{try{let n=await nc(e.get(In));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?De.resolve(n.box.cwd):null,s=typeof e.body?.cwd=="string"&&e.body.cwd?De.resolve(e.body.cwd):null,a=o&&s&&(s===o||s.startsWith(o+De.sep))?s:o;KR(n.track,n.box,r,{cwd:a}).catch(i=>console.warn(`[rework] ${n.track.id}: recordCommit failed: ${i?.message||i}`)),HB(n)}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});function HB(e){let t=e?.box?.cwd;!t||!e?.track?.id||Gl(t,{track:{id:e.track.id,cwd:e.track.cwd},boxId:e.box.name}).catch(()=>{})}O.post("/api/deps/refresh",async(e,t)=>{try{let n=await nc(e.get(In));if(!n?.track||!n?.box)return t.json({ok:!1,error:"unknown hook token"});t.json({ok:!0}),HB(n)}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});O.post("/api/tracks/:id/rework-cause",async(e,t)=>{try{let n=await ye(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 zR(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})}});O.post("/api/tracks/:id/rework-cause/retract",async(e,t)=>{try{let n=await ye(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,event:await JR(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})}});O.get("/api/usage/rework",async(e,t)=>{try{t.json(await yD(await xe(),{window:e.query.window,from:e.query.from,to:e.query.to}))}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/usage/forge-polls",async(e,t)=>{try{let n=Math.min(Math.max(Number(e.query.days)||7,1),90),r=eB(n),o=await Promise.all((await xe()).map(async s=>({trackId:s.id,name:s.name??null,...Z1(await V(s).catch(()=>[]),{...r,trackId:s.id})})));t.json(Q1(o,r))}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.post("/api/telemetry",async(e,t)=>{try{if(!fB(Tc.clientIp(e)))return t.json({ok:!0,dropped:!0});let n=await pB(e.body||{});t.json({ok:!0,events:n})}catch(n){t.json({ok:!1,error:n?.message||String(n)})}});O.get("/api/repos",async(e,t)=>{try{let n=await Ir(),r=new Set((await Promise.all(n.map(a=>Re(a.path)))).filter(Boolean).map(a=>a.toLowerCase())),s=((await $s()).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)})}});O.get("/api/github/token",async(e,t)=>{try{t.json(await wo(String(e.query.repo||"")))}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});O.get("/api/github/status",(e,t)=>{t.json({configured:Gd(),calls:L$(),latency:H$(),webhook:I1(),openedTrail:sR()})});O.post("/api/github/event",en.json({limit:"64kb"}),(e,t)=>{let n=E1(e.body,{onAccept:r=>V1(r)});if(!n.ok)return t.status(400).json({error:n.error});t.json({ok:!0,duplicate:n.duplicate})});O.post("/api/github/refresh",(e,t)=>{_v(),t.json({ok:!0})});O.get("/api/gmail/search",async(e,t)=>{try{let n=await ID(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)})}});O.get("/api/gmail/messages/:id",async(e,t)=>{try{t.json({message:await $D(String(e.params.id))})}catch(n){t.status(n?.status||502).json({error:n?.message||String(n)})}});async function Ed({repo:e=null,number:t=null,branch:n=null}){let r=e?await Re(e):null;if(r&&t!=null){let s=await pt(r,t),a=s&&await ye(s.trackId);if(a)return a}if(!n)return null;let o=await xe();return Xf(o,n,s=>Zf(s,{branch:n,repo:e,slug:r}))}async function WB({repo:e=null,number:t=null,branch:n=null}){let r=await Ed({repo:e,number:t,branch:n}).catch(()=>null);if(r&&!He(r))return r;if(!n)return null;let o=e?await Re(e).catch(()=>null):null,s=await xe();return Xf(s,n,a=>!He(a)&&Zf(a,{branch:n,repo:e,slug:o}))}async function Yn(e,{number:t,url:n=null,title:r=null,branch:o=null,repo:s=null,track:a=null,extra:i={}}){let c=a||await Ed({repo:s,number:t,branch:o}).catch(()=>null);if(!c)return;let l=i.repo??(s?await Re(s).catch(()=>null):null);e==="opened"&&await Hr({repo:l,number:t,via:"api"}).catch(()=>{}),await D({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 tQ(e){let t=(await xe()).filter(n=>!He(n));for(let n of e??[]){if(!n.prs?.length)continue;let r=await Re(n.path);if(r)for(let o of n.prs){if(await pt(r,o.number))continue;let s=await Xf(t,o.headRefName,a=>Zf(a,{branch:o.headRefName,repo:n.path,slug:r}));s&&await ln({repo:r,number:o.number,trackId:s.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"})}}}O.get("/api/git/prs",async(e,t)=>{try{let n=await aR();await tQ(n.repos).catch(()=>{}),await Dm(n.repos).catch(()=>{}),t.json(n)}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.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,w=null,m=null;try{if(s){let b=o||"merge";if(!Zl.has(b))throw new Error(`invalid merge method: ${b}`);let x=Number(r);if(!Number.isInteger(x)||x<=0)throw new Error("invalid PR number");let v=await Re((await Wr(n)).path);if(!v)throw new Error("repo has no GitHub remote");let S=await Ed({repo:n,number:x,branch:l}).catch(()=>null);if(!S)throw new Error("auto-merge needs a Track to watch this PR \u2014 none owns it");if(p=S,w=await Ch(S,"merge",{count:1,summary:`arming auto-merge on PR #${x}`}),a&&await Ql(n,x),await ln({repo:v,number:x,trackId:S.id,url:d,headRef:l,title:u,source:"matched"}).catch(()=>{}),!await Vl(v,x,{merge:{method:b}}))throw new Error("couldn't record the auto-merge arm");return await na(v,x,i===!0),await ra(v,x,c===!0&&i!==!0),xn(),await Yn("auto-armed",{number:x,url:d,title:u,branch:l,repo:n,track:S,...a?{extra:{updated:!0}}:{}}),t.json({ok:!0,number:x,auto:!0})}p=await Ed({repo:n,number:r,branch:l}).catch(()=>null),p&&(w=await Ch(p,"merge",{count:1,summary:`merging PR #${r}`}));let h=await Ci(n,r,{method:o||"squash"});await Yn("merged",{number:h.number,url:d,title:u,branch:l,repo:n});let g=await Re(n).catch(()=>null),y=!1;if(g&&(i===!0&&await na(g,h.number,!0).catch(()=>{}),c===!0&&i!==!0&&await ra(g,h.number,!0).catch(()=>{}),await Kr(g,h.number).catch(()=>{}),await Sa(g,h.number).catch(()=>{}),y=await Gr(g,h.number).catch(()=>!1),await Ho(g,h.number,"merged").catch(()=>{})),i===!0&&!y){let b=await Ed({repo:n,number:h.number,branch:l}).catch(()=>null);b&&!b.archivedAt&&await xa(b.id).catch(()=>{})}t.json(h)}catch(h){m=h;let g=h?.message||String(h),y=/invalid|unknown repo|required|needs a Track|no GitHub remote/i.test(g)?400:502;t.status(y).json({error:g})}finally{p&&w&&await Bk(p,w,m?"failed":"completed",m).catch(()=>{})}});O.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 Re((await Wr(n)).path).catch(()=>null),l=c?await zl(c,i).catch(()=>null):null;try{await sb(n,i)}catch(u){if(!l)throw u}xn(),await Yn("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})}});O.post("/api/git/prs/merge-all",async(e,t)=>{let{repo:n,method:r}=e.body||{};try{let o=await Re(n).catch(()=>null),s=await fR(n,{method:r||"merge",onMerged:a=>{Yn("merged",{number:a.number,url:a.url,title:a.title,branch:a.headRefName,repo:n}),o&&Kr(o,a.number).catch(()=>{}).then(()=>Sa(o,a.number)).catch(()=>{}).then(()=>Gr(o,a.number)).catch(()=>{}).then(()=>Ho(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})}});O.get("/api/git/prs/merge-all",(e,t)=>{t.json({jobs:pR()})});O.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(!Zl.has(u))throw new Error(`invalid merge method: ${u}`);if(!n)return t.status(400).json({error:"trackId required"});let d=await ye(n);if(!d)return t.status(404).json({error:`Track ${n} isn't on this node`});i=d;let p=(await Ln()).filter(h=>h.trackId===d.id&&h.state!=="merged"&&h.state!=="closed").sort(eu);if(!p.length)return t.status(409).json({error:"no open PRs on this Track"});c=await Ch(d,"merge",{count:p.length,summary:p.length===1?"merging 1 PR":`merging ${p.length} PRs`});for(let h of p)await na(h.repo,h.number,o===!0).catch(()=>{}),await ra(h.repo,h.number,s===!0&&o!==!0).catch(()=>{});let w=[],m=[];for(let h of p){let g={repo:h.repo,number:h.number,ok:!0,action:"armed"};w.push(g);try{let y=await ia(h.repo);if(!y)throw new Error(`no local checkout for ${h.repo}`);let b=await Mi(y,h.number);m.push({r:g,l:h,repoPath:y,pr:b,plan:iR(b,{update:r!==!1})})}catch(y){g.ok=!1,g.action="failed",g.reason=y?.message||String(y)}}for(let{r:h,l:g,repoPath:y,pr:b,plan:x}of cR(m))try{if(x.action==="skip")h.action="skipped",h.reason=x.reason;else if(x.action==="merge")await Ci(y,g.number,{method:u}),await Yn("merged",{number:g.number,url:b.url,title:b.title,branch:b.headRefName,repo:y,track:d}),await Kr(g.repo,g.number).catch(()=>{}),await Sa(g.repo,g.number).catch(()=>{}),await Gr(g.repo,g.number).catch(()=>{}),await Ho(g.repo,g.number,"merged").catch(()=>{}),h.action="merged";else{if(x.action==="update-arm"&&(await Ql(y,g.number).catch(()=>{}),h.action="updated-armed"),!await Vl(g.repo,g.number,{merge:{method:u}}))throw new Error("couldn't record the auto-merge arm");await Yn("auto-armed",{number:g.number,url:b.url,title:b.title,branch:b.headRefName,repo:y,track:d,...h.action==="updated-armed"?{extra:{updated:!0}}:{}})}}catch(v){h.ok=!1,h.action="failed",h.reason=v?.message||String(v)}if(xn(),!w.some(h=>h.ok)){if(o===!0)for(let h of p)await na(h.repo,h.number,!1).catch(()=>{});if(s===!0&&o!==!0)for(let h of p)await ra(h.repo,h.number,!1).catch(()=>{});return t.status(502).json({error:w.map(h=>`${h.repo}#${h.number}: ${h.reason}`).join("; "),results:w})}t.json({ok:!0,trackId:d.id,results:w})}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 Bk(i,c,l?"failed":"completed",l).catch(()=>{})}});O.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 ye(n);if(!r)return t.status(404).json({error:`Track ${n} isn't on this node`});let o=(await Ln()).filter(a=>a.trackId===r.id&&a.state!=="merged"&&a.state!=="closed"),s=[];for(let a of o){let i=await zl(a.repo,a.number).catch(()=>null),c=await ia(a.repo).catch(()=>null);c&&await sb(c,a.number).catch(()=>{}),i&&(await Yn("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}))}xn(),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})}});O.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 ye(n);if(!i)return t.status(404).json({error:`Track ${n} isn't on this node`});if(i.workspace?.kind==="multi"){let u=Qt(i.workspace),d,p=Array.isArray(a)?a.filter(Boolean):[];if(p.length)d=p.map(h=>{let g=u.find(y=>y.name===h||y.repo===h||y.base===h||y.dir===h);if(!g)throw new Error(`invalid repo "${h}" \u2014 not tagged on this Track`);return g});else if(d=await ha(i),!d.length)return t.status(409).json({error:"no tagged repo has work to ship"});let w=[];for(let h of d)try{let g=await ib(h.dir,{title:r,body:o,base:s}),y=h.repo||await Re(h.dir).catch(()=>null);y&&g.number&&await ln({repo:y,number:g.number,trackId:i.id,url:g.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Yn("opened",{number:g.number,url:g.url,title:r,track:i,branch:i.workspace?.branch,extra:{repo:y??h.name}}),w.push({repo:h.name,slug:y??null,ok:!0,url:g.url,number:g.number})}catch(g){w.push({repo:h.name,slug:h.repo??null,ok:!1,error:g?.message||String(g)})}let m=w.filter(h=>h.ok);return m.length?t.json({ok:!0,multi:!0,results:w,url:m[0].url,number:m[0].number}):t.status(502).json({error:w.map(h=>`${h.repo}: ${h.error}`).join("; "),results:w})}let c=await ib(i.cwd,{title:r,body:o,base:s}),l=await Re(i.cwd).catch(()=>null);l&&c.number&&await ln({repo:l,number:c.number,trackId:i.id,url:c.url,headRef:i.workspace?.branch??null,title:r,source:"api"}),await Yn("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})}});O.get("/api/tracks/:id/repos",async(e,t)=>{try{let n=await ye(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await ha(n),o=new Map(r.map(a=>[a.base,a])),s=Qt(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)})}});O.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 zh(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})}});O.delete("/api/tracks/:id/repos/:name",async(e,t)=>{try{let n=await Jh(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})}});O.post("/api/tracks/:id/reshape",async(e,t)=>{let{repos:n,skipPermissions:r}=e.body||{};try{let o=await b0(e.params.id,n,{skipPermissions:r!==!1});t.status(o.finishedAt?200:202).json({ok:!0,...LS(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})}});O.get("/api/tracks/:id/reshape",(e,t)=>{t.json(LS(qu(e.params.id))??{running:!1})});function LS(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}O.post("/api/git/prs/fix",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Mi(n,r),s=await Re(n).catch(()=>null),a=await WB({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=Qt(a.workspace).find(y=>y.base===n||s&&y.repo===s)??null,c=a.workspace?.kind==="multi",l=await hR(n,o.number);if(!l.length)return t.status(409).json({error:"no failing checks on this PR"});let u=c&&i?De.join("ci",i.name):"ci",d=De.join(a.cwd,".bostrat",u),p=De.join(".bostrat",u,`pr-${o.number}-fail.log`);await $t.promises.mkdir(d,{recursive:!0}),await $t.promises.writeFile(De.join(a.cwd,p),l.map(y=>`\u2550\u2550\u2550\u2550 ${y.name}${y.link?` \xB7 ${y.link}`:""} \u2550\u2550\u2550\u2550
|
|
968
968
|
${y.log??"(no fetchable log \u2014 see link)"}
|
|
969
969
|
`).join(`
|
|
970
|
-
`));let w=l.map(y=>y.name).join(", "),m=c&&i?` in the ${i.name}/ checkout`:"",f=await Ht(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${m}. Failing check${l.length===1?"":"s"}: ${w}. 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. Once the push lands, stop: Bostrat reports whether the checks went green. If you could not reproduce the failure locally, say so.`,{kind:"ci-fix"}),g=s;g&&(await ln({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await b$(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Yn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(y=>y.name)}}),t.json({ok:!0,leadBox:f.leadBox,queued:!!f.queued,checks:l.map(y=>y.name),log:p})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});O.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Mi(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await Re(n).catch(()=>null),a=await WB({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=Qt(a.workspace).find(d=>d.base===n||s&&d.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await Ht(a.id,`PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName} \u2014 has merge conflicts with ${o.baseRefName}.${c} Bring ${o.baseRefName} into this branch (fetch origin, then merge origin/${o.baseRefName} \u2014 don't rebase this pushed PR branch), and resolve every conflict so that BOTH sides' intent is preserved. Run the relevant tests, then commit and push to update the PR. If any conflict is a genuine ambiguity \u2014 where you can't confidently tell which side's behavior should win, or reconciling would drop work from either side \u2014 STOP and ask me here rather than guessing, laying out the specific choice and your recommendation. Once the push lands, stop: Bostrat reports whether the PR is mergeable.`,{kind:"reconcile"}),u=s;u&&(await ln({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await k$(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Yn("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})}});O.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=Ko.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 Jo(`pr:${e.params.id}:${n}`,async()=>{let a=await ye(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await V(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 kS(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;if(o){let d=c.payload.repos||null,p=o.includes("push")||o.includes("pr")?await tu(d??[{name:a.workspace?.repo??(a.workspace?.base?De.basename(a.workspace.base):null),slug:a.workspace?.repo??null}]):null;l=await Ht(a.id,Ni(o,{branch:c.payload.branch,base:c.payload.base,toPr:c.payload.toPr||null,repos:d,offeredRebase:Array.isArray(c.payload.offered)&&c.payload.offered.includes("rebase"),forge:p}),{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 D({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&&d0(a.id,{actions:o}),t.json({ok:!0,offerId:n,action:u,actions:o,notify:s,queued:!!l?.queued,...l?.revived?{revived:!0}:{}})})}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})}});O.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await ye(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await xS(o,{offerId:n,choice:r});t.json({ok:!0,offerId:n,choice:r,queued:!!s?.queued,...s?.revived?{revived:!0}:{}})}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 Id=e=>t=>({...t,url:GD(t,e.headers)});O.get("/api/views",async(e,t)=>{try{let n=await kh({trackId:e.query.track||void 0});t.json({views:n.map(Id(e)),maxLive:Xo})}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/views/:id",async(e,t)=>{let n=await xM(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:Id(e)(n),session:ji(n.slug)})});O.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await ye(n):null;if(!i&&s&&(i=(await xe()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+De.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!Vx(e.headers))return t.status(412).json({error:bP});let c=await ek({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:Id(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})}});O.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:Id(e)(await tk(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});O.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:Id(e)(await SM(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})}});O.delete("/api/views/:id",async(e,t)=>{try{t.json(await vM(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var nQ=[["linear",Ta,dx],["jira",wm,lx]],$S=new Map;O.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await cx(),r={};for(let[o,s,a]of nQ){let i=await s();if(!i){$S.delete(o),r[o]={configured:!1};continue}let c=$S.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},$S.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)})}});O.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await cx()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await pP(o),i=n?await ye(n):null;!i&&r&&(i=(await xe()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+De.sep)))||null),i&&await D({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 Na=async(e,t)=>{let n=e?await ye(e):null;return!n&&t&&(n=(await xe()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+De.sep)))||null),n};O.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await tx()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});O.get("/api/roadmap",async(e,t)=>{try{t.json(await nx())}catch(n){t.status(502).json({error:n?.message||String(n)})}});O.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await Na(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 uc(o);await pm(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})}});O.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await Na(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await pm(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var qB=async(e,t,n)=>{if(e)return{ref:e,track:await Na(t,n)};let r=await Na(t,n),o=r?await ox(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}};O.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 qB(o,n,r),l=await nP({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})}});O.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await qB(e.query.circuit,e.query.track,e.query.cwd);t.json(await rx(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})}});O.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 Na(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=await iP(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})}});O.get("/api/decisions",async(e,t)=>{try{let n=await Na(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await cP(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})}});O.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 Na(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await ox(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 sx(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})}});O.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await ye(n):null;if(!s&&r&&(s=(await xe()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+De.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 hc(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})}});O.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await ye(r):null;if(!o&&n&&(o=(await xe()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+De.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 DP(),ticket:await Er(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});O.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await Er(e.params.id)})});O.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await ye(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await hc(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})}});O.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await Ex(e.params.id)})});var Jm=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;O.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await FP(e.params.id))}catch(n){let r=n?.message||String(n);t.status(Jm(r)).json({error:r})}});O.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await _x(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(Jm(r)).json({error:r})}});O.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await UP(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(Jm(r)).json({error:r})}});O.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await ye(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await HP(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(Jm(s)).json({error:s})}});O.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r,force:o}=e.body||{};try{t.json(await O0(e.params.id,n,r===!0,{force:o===!0}))}catch(s){let a=s?.message||String(s),i=/not found|unknown offer/.test(a)?404:/already answered/.test(a)||/mid-turn/.test(a)?409:500;t.status(i).json({error:a,...s?.code?{code:s.code}:{},...s?.refusals!=null?{refusals:s.refusals,forceAvailable:s.forceAvailable===!0}:{}})}});O.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ye(n):null;if(!s&&r&&(s=(await xe()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+De.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 qP(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})}});O.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await WP()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});O.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await ye(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await GP(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})}});O.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await Au({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/mocks/:id",async(e,t)=>{let n=await Xr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var $d={dotfiles:"allow"};O.get("/api/mocks/:id/png",async(e,t)=>{let n=await Xr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Wn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Su(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,$d,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});O.get("/api/mocks/:id/media",async(e,t)=>{let n=await Xr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Wn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Su(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,$d,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});O.get("/api/mocks/:id/html",async(e,t)=>{let n=await Xr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Wn(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(vn(n,r.v).html,$d,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});O.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Th(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 ye(a):null;if(!d&&c&&(d=(await xe()).find(f=>f.cwd&&(c===f.cwd||c.startsWith(f.cwd+De.sep)))||null),!d)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let p=(d.boxes||[]).find(m=>m.name===d.leadBox),w=await jM({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:w})}catch(d){let p=d?.message||String(d);t.status(/required|invalid|must be/i.test(p)?400:500).json({error:p})}});O.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Th(n)?n:null;try{let o=await FM(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})}});O.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await WM(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await Ht(n.trackId,`Design decision: go with "${n.name}" (mock:${n.id})${o} \u2014 proceed with this design.`,{kind:"mock-picked"}).catch(()=>{}),t.json({ok:!0,mock:n,siblings:r})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/nothing to pick/i.test(r)?409:500;t.status(o).json({error:r})}});O.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await iC(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await qM(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})}});O.get("/api/flows",async(e,t)=>{try{t.json({flows:await nC({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/flows/:id",async(e,t)=>{let n=await rC(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});O.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await ye(n):null;if(!a&&s&&(a=(await xe()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+De.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 oC({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})}});O.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await sC(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})}});O.delete("/api/flows/:id",async(e,t)=>{try{t.json(await aC(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});O.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await xe(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+De.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await mC({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)})}});O.get("/api/runbooks/:id",async(e,t)=>{let n=await wk(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});O.get("/api/runbooks/:id/md",async(e,t)=>{let n=await wk(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=fC(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 wC(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(to(n,r.v),$d,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});O.get("/api/loops",async(e,t)=>{t.json(await $l())});O.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 xe()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+De.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await $l();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 ey({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})});O.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ye(n):null;if(!s&&r&&(s=(await xe()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+De.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 e1(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var Pa=async(e,t)=>{let n=e?await ye(e):null;return!n&&t&&(n=(await xe()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+De.sep)))||null),n};O.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Pa(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 MO(s,o,{ship:{changedRepos:ha}})})}catch(s){t.status(400).json({error:s?.message||String(s)})}});O.post("/api/ship/updated",async(e,t)=>{let{trackId:n,cwd:r,number:o,rebased:s,base:a}=e.body||{};try{let i=await Pa(n,r);if(!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:i.id,result:await nB(i,{number:o??null,rebased:s===!0,base:a??null})})}catch(i){t.status(400).json({error:i?.message||String(i)})}});O.post("/api/followups/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Pa(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 NO(s,o)})}catch(s){let a=s?.message||String(s);t.status(/unreachable/i.test(a)?503:400).json({error:a})}});O.get("/api/followups",async(e,t)=>{let n=typeof e.query?.cwd=="string"?e.query.cwd:null,r=await Pa(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:$b,...await jO(r)})});var MB=new Set(["reconcile","fixing-ci","rebase","merge"]);O.get("/api/status",async(e,t)=>{let n=await Pa(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})});O.post("/api/status",async(e,t)=>{try{let{trackId:n,cwd:r,phase:o,summary:s,scope:a,reason:i}=e.body||{},c=await Pa(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&&!MB.has(l))throw new Error(`phase must be one of ${[...MB].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=VZ();await D(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)})}});O.post("/api/tracks/:id/followup-offer",async(e,t)=>{let{offerId:n,followupId:r,armId:o,promoted:s,all:a,rows:i,prompt:c,prompts:l,reordered:u}=e.body||{};try{let d=await ye(e.params.id);if(!d)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await DO(d,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null,all:a===!0,rows:Array.isArray(i)?i:null,prompt:typeof c=="string"?c:null,prompts:l&&typeof l=="object"&&!Array.isArray(l)?l:null,reordered:u===!0},{sayToLead:Ht,unarchiveTrack:sc})})}catch(d){let p=d?.message||String(d),w=d?.code==="removed"?410:/unknown offer/i.test(p)?404:/already answered/i.test(p)?409:/required|not on this card|nothing to run together|rows must|not part of a batch|not in this batch|prompt must|prompts must|edited prompt|comes from Settings/i.test(p)?400:/unreachable/i.test(p)?503:502;t.status(w).json({error:p})}});O.post("/api/tracks/:id/followup-arm-save",async(e,t)=>{let{offerId:n,armId:r,followupId:o}=e.body||{};try{let s=await ye(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await BO(s,{offerId:n,armId:r,followupId:o})})}catch(s){let a=s?.message||String(s);t.status(/unknown offer/i.test(a)?404:/already saved/i.test(a)?409:400).json({error:a})}});O.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await ye(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await CO(n,e.body?.armId)})}catch(n){let r=n?.message||String(n);t.status(/unknown/i.test(r)?404:400).json({error:r})}});O.post("/api/tracks/:id/followup-create-offer",async(e,t)=>{let{proposalId:n,accept:r,followupId:o}=e.body||{};try{let s=await ye(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await PO(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})}});at.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"||ye(e.trackId).then(async s=>{if(s&&(n&&await cu(s,n,o),t==="opened"||t==="pushed")){let a=LO(await V(s).catch(()=>[]));a&&await cu(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var GB=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await ye(n):null;if(!s&&r&&(s=(await xe()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+De.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await $l();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=r1(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}};O.post("/api/loops/propose-update",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await GB(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await o1(s.track,s.loop,e.body?.patch)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});O.post("/api/loops/propose-delete",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await GB(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await s1(s.track,s.loop,e.body?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});O.post("/api/planning/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o,scope:s}=e.body||{},a=await Pa(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i;try{i=await nx()}catch(c){return t.status(503).json({error:c?.message||String(c)})}try{let c=s==="circuit"?Qx:gd;t.json({ok:!0,trackId:a.id,proposal:await w1(a,o,i,{allow:c})})}catch(c){t.status(400).json({error:c?.message||String(c)})}});var jS=e=>/unknown proposal/i.test(e)?404:/already answered/i.test(e)?409:400;O.post("/api/tracks/:id/planning-offer",async(e,t)=>{let{proposalId:n,action:r,results:o}=e.body||{};try{let s=await ye(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await g1(s,n,r,{results:o||[]})})}catch(s){let a=s?.message||String(s);t.status(jS(a)).json({error:a})}});O.post("/api/tracks/:id/loop-update-offer",async(e,t)=>{let{proposalId:n,action:r,nextFireAt:o}=e.body||{};try{let s=await ye(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await i1(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(jS(a)).json({error:a})}});O.post("/api/tracks/:id/loop-delete-offer",async(e,t)=>{let{proposalId:n,action:r}=e.body||{};try{let o=await ye(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await c1(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(jS(s)).json({error:s})}});O.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 ye(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await t1(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})}});O.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await ye(n):null;if(!a&&s&&(a=(await xe()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+De.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 gC({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})}});O.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await yC(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})}});O.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await bC(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})}});O.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await kC(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});O.get("/api/changelog/draft",async(e,t)=>{try{let n=S1(e.query.since||null);t.json({since:n,repos:tS(),...await v1(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var KB=async({trackId:e,cwd:t})=>{let n=e?await ye(e):null;return!n&&t&&(n=(await xe()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+De.sep)))||null),n};O.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await KB({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 A1(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})}});O.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await KB({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 T1(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var rQ=120,RS=400,oQ=/^[a-z0-9][a-z0-9_-]{0,23}$/,Ec=null,CB=null;O.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&&!oQ.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>RS)return t.status(400).json({error:`message is ${c.length} chars \u2014 over the ${RS} cap; a notification is a nudge, put the detail in chat`});let u=Tu(`${n||""}
|
|
971
|
-
${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 ye(a):null;if(!d&&s&&(d=(await xe()).find(g=>g.cwd&&(s===g.cwd||s.startsWith(g.cwd+De.sep)))||null),!d)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let p=(d.boxes||[]).find(
|
|
970
|
+
`));let w=l.map(y=>y.name).join(", "),m=c&&i?` in the ${i.name}/ checkout`:"",h=await Ht(a.id,`CI is red on PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName}${m}. Failing check${l.length===1?"":"s"}: ${w}. 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. Once the push lands, stop: Bostrat reports whether the checks went green. If you could not reproduce the failure locally, say so.`,{kind:"ci-fix"}),g=s;g&&(await ln({repo:g,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await b$(g,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Yn("fix-delegated",{number:o.number,url:o.url,title:o.title,branch:o.headRefName,repo:n,track:a,extra:{checks:l.map(y=>y.name)}}),t.json({ok:!0,leadBox:h.leadBox,queued:!!h.queued,checks:l.map(y=>y.name),log:p})}catch(o){let s=o?.message||String(o),a=/unknown repo|invalid|required/i.test(s)?400:/not found|no active Track/i.test(s)?404:502;t.status(a).json({error:s})}});O.post("/api/git/prs/reconcile",async(e,t)=>{let{repo:n,number:r}=e.body||{};try{let o=await Mi(n,r);if(o.mergeable!=="CONFLICTING")return t.status(409).json({error:"this PR does not conflict with its base branch"});let s=await Re(n).catch(()=>null),a=await WB({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=Qt(a.workspace).find(d=>d.base===n||s&&d.repo===s)??null,c=a.workspace?.kind==="multi"&&i?` In the ${i.name}/ checkout:`:"",l=await Ht(a.id,`PR #${o.number} "${o.title}" (${o.url}) \u2014 branch ${o.headRefName} \u2014 has merge conflicts with ${o.baseRefName}.${c} Bring ${o.baseRefName} into this branch (fetch origin, then merge origin/${o.baseRefName} \u2014 don't rebase this pushed PR branch), and resolve every conflict so that BOTH sides' intent is preserved. Run the relevant tests, then commit and push to update the PR. If any conflict is a genuine ambiguity \u2014 where you can't confidently tell which side's behavior should win, or reconciling would drop work from either side \u2014 STOP and ask me here rather than guessing, laying out the specific choice and your recommendation. Once the push lands, stop: Bostrat reports whether the PR is mergeable.`,{kind:"reconcile"}),u=s;u&&(await ln({repo:u,number:o.number,trackId:a.id,url:o.url,headRef:o.headRefName,title:o.title,source:"matched"}),await k$(u,o.number,{headSha:o.headSha,trackId:a.id}).catch(()=>{})),await Yn("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})}});O.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=Ko.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 Jo(`pr:${e.params.id}:${n}`,async()=>{let a=await ye(e.params.id);if(!a)return t.status(404).json({error:"track not found"});let i=await V(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 kS(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;if(o){let d=c.payload.repos||null,p=o.includes("push")||o.includes("pr")?await tu(d??[{name:a.workspace?.repo??(a.workspace?.base?De.basename(a.workspace.base):null),slug:a.workspace?.repo??null}]):null;l=await Ht(a.id,Ni(o,{branch:c.payload.branch,base:c.payload.base,toPr:c.payload.toPr||null,repos:d,offeredRebase:Array.isArray(c.payload.offered)&&c.payload.offered.includes("rebase"),forge:p}),{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 D({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&&d0(a.id,{actions:o}),t.json({ok:!0,offerId:n,action:u,actions:o,notify:s,queued:!!l?.queued,...l?.revived?{revived:!0}:{}})})}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})}});O.post("/api/tracks/:id/pr-exists",async(e,t)=>{let{offerId:n,choice:r}=e.body||{};try{let o=await ye(e.params.id);if(!o)return t.status(404).json({error:"track not found"});let{say:s}=await xS(o,{offerId:n,choice:r});t.json({ok:!0,offerId:n,choice:r,queued:!!s?.queued,...s?.revived?{revived:!0}:{}})}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 Id=e=>t=>({...t,url:GD(t,e.headers)});O.get("/api/views",async(e,t)=>{try{let n=await kh({trackId:e.query.track||void 0});t.json({views:n.map(Id(e)),maxLive:Xo})}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/views/:id",async(e,t)=>{let n=await xM(e.params.id);if(!n)return t.status(404).json({error:"view not found"});t.json({view:Id(e)(n),session:ji(n.slug)})});O.post("/api/views",async(e,t)=>{let{trackId:n,name:r,cmd:o,cwd:s,port:a}=e.body||{};try{let i=n?await ye(n):null;if(!i&&s&&(i=(await xe()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+De.sep)))||null),!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});if(!Vx(e.headers))return t.status(412).json({error:bP});let c=await ek({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:Id(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})}});O.post("/api/views/:id/stop",async(e,t)=>{try{t.json({ok:!0,view:Id(e)(await tk(e.params.id))})}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});O.post("/api/views/:id/restart",async(e,t)=>{try{t.json({ok:!0,view:Id(e)(await SM(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})}});O.delete("/api/views/:id",async(e,t)=>{try{t.json(await vM(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});var nQ=[["linear",Ta,dx],["jira",wm,lx]],$S=new Map;O.get("/api/integrations/ticketing",async(e,t)=>{try{let n=await cx(),r={};for(let[o,s,a]of nQ){let i=await s();if(!i){$S.delete(o),r[o]={configured:!1};continue}let c=$S.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},$S.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)})}});O.get("/api/tickets/flow",async(e,t)=>{try{t.json({flow:await cx()})}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.post("/api/tickets/flow",async(e,t)=>{let{trackId:n,cwd:r,set:o,actor:s}=e.body||{};try{let a=await pP(o),i=n?await ye(n):null;!i&&r&&(i=(await xe()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+De.sep)))||null),i&&await D({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 Na=async(e,t)=>{let n=e?await ye(e):null;return!n&&t&&(n=(await xe()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+De.sep)))||null),n};O.get("/api/circuits",async(e,t)=>{try{t.json({circuits:await tx()})}catch(n){t.status(502).json({error:n?.message||String(n)})}});O.get("/api/roadmap",async(e,t)=>{try{t.json(await nx())}catch(n){t.status(502).json({error:n?.message||String(n)})}});O.post("/api/circuits/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=await Na(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 uc(o);await pm(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})}});O.post("/api/circuits/unlink",async(e,t)=>{let{trackId:n,cwd:r}=e.body||{};try{let o=await Na(n,r);if(!o)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});await pm(o,null,{source:"chat"}),t.json({ok:!0,trackId:o.id})}catch(o){t.status(502).json({error:o?.message||String(o)})}});var qB=async(e,t,n)=>{if(e)return{ref:e,track:await Na(t,n)};let r=await Na(t,n),o=r?await ox(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}};O.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 qB(o,n,r),l=await nP({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})}});O.get("/api/blueprints/show",async(e,t)=>{try{let{ref:n}=await qB(e.query.circuit,e.query.track,e.query.cwd);t.json(await rx(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})}});O.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 Na(n,r);if(!u)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let d=await iP(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})}});O.get("/api/decisions",async(e,t)=>{try{let n=await Na(e.query.track,e.query.cwd);if(!n)return t.status(400).json({error:"run from inside a Track workspace"});t.json(await cP(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})}});O.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 Na(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i=await ox(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 sx(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})}});O.post("/api/tickets/link",async(e,t)=>{let{trackId:n,cwd:r,ref:o}=e.body||{};try{let s=n?await ye(n):null;if(!s&&r&&(s=(await xe()).find(c=>c.cwd&&(r===c.cwd||r.startsWith(c.cwd+De.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 hc(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})}});O.get("/api/tickets/status",async(e,t)=>{let{cwd:n,track:r}=e.query;try{let o=r?await ye(r):null;if(!o&&n&&(o=(await xe()).find(a=>a.cwd&&(n===a.cwd||String(n).startsWith(a.cwd+De.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 DP(),ticket:await Er(o.id)})}catch(o){t.status(500).json({error:o?.message||String(o)})}});O.get("/api/tracks/:id/ticket",async(e,t)=>{t.json({ticket:await Er(e.params.id)})});O.post("/api/tracks/:id/ticket",async(e,t)=>{try{let n=await ye(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let r=await hc(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})}});O.delete("/api/tracks/:id/ticket",async(e,t)=>{t.json({ok:!0,removed:await Ex(e.params.id)})});var Jm=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;O.get("/api/tracks/:id/ticket/states",async(e,t)=>{try{t.json(await FP(e.params.id))}catch(n){let r=n?.message||String(n);t.status(Jm(r)).json({error:r})}});O.post("/api/tracks/:id/ticket/state",async(e,t)=>{try{t.json({ok:!0,...await _x(e.params.id,(e.body||{}).stateId)})}catch(n){let r=n?.message||String(n);t.status(Jm(r)).json({error:r})}});O.post("/api/tracks/:id/ticket/comment",async(e,t)=>{try{t.json({ok:!0,...await UP(e.params.id,(e.body||{}).body)})}catch(n){let r=n?.message||String(n);t.status(Jm(r)).json({error:r})}});O.post("/api/tracks/:id/ticket-offer",async(e,t)=>{let{offerId:n,accept:r}=e.body||{};try{let o=await ye(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await HP(o,n,r===!0)})}catch(o){let s=o?.message||String(o);t.status(Jm(s)).json({error:s})}});O.post("/api/tracks/:id/fullscreen-offer",async(e,t)=>{let{offerId:n,accept:r,force:o}=e.body||{};try{t.json(await O0(e.params.id,n,r===!0,{force:o===!0}))}catch(s){let a=s?.message||String(s),i=/not found|unknown offer/.test(a)?404:/already answered/.test(a)||/mid-turn/.test(a)?409:500;t.status(i).json({error:a,...s?.code?{code:s.code}:{},...s?.refusals!=null?{refusals:s.refusals,forceAvailable:s.forceAvailable===!0}:{}})}});O.post("/api/tickets/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ye(n):null;if(!s&&r&&(s=(await xe()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+De.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 qP(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})}});O.get("/api/tickets/teams",async(e,t)=>{try{t.json({teams:await WP()})}catch(n){let r=n?.message||String(n);t.status(/no ticketing/i.test(r)?400:502).json({error:r})}});O.post("/api/tracks/:id/ticket-create-offer",async(e,t)=>{let{proposalId:n,accept:r,teamId:o}=e.body||{};try{let s=await ye(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await GP(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})}});O.get("/api/mocks",async(e,t)=>{try{t.json({mocks:await Au({trackId:e.query.track||void 0,group:e.query.group||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/mocks/:id",async(e,t)=>{let n=await Xr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});t.json({mock:n})});var $d={dotfiles:"allow"};O.get("/api/mocks/:id/png",async(e,t)=>{let n=await Xr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Wn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Su(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,$d,s=>{s&&!t.headersSent&&t.status(404).json({error:"rendered artifact missing"})})});O.get("/api/mocks/:id/media",async(e,t)=>{let n=await Xr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Wn(n,e.query.v??null);if(!r)return t.status(409).json({error:`mock is ${n.state} \u2014 no captured version yet`});let o=Su(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,$d,s=>{s&&!t.headersSent&&t.status(404).json({error:"video artifact missing"})})});O.get("/api/mocks/:id/html",async(e,t)=>{let n=await Xr(e.params.id);if(!n)return t.status(404).json({error:"mock not found"});let r=Wn(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(vn(n,r.v).html,$d,o=>{o&&!t.headersSent&&t.status(404).json({error:"source artifact missing"})})});O.post("/api/mocks",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Th(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 ye(a):null;if(!d&&c&&(d=(await xe()).find(h=>h.cwd&&(c===h.cwd||c.startsWith(h.cwd+De.sep)))||null),!d)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let p=(d.boxes||[]).find(m=>m.name===d.leadBox),w=await jM({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:w})}catch(d){let p=d?.message||String(d);t.status(/required|invalid|must be/i.test(p)?400:500).json({error:p})}});O.post("/api/mocks/:id/update",async(e,t)=>{let n=Buffer.isBuffer(e.body)?e.body:null,r=n&&Th(n)?n:null;try{let o=await FM(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})}});O.post("/api/mocks/:id/pick",async(e,t)=>{try{let{mock:n,siblings:r}=await WM(e.params.id),o=r.length?` over ${r.map(s=>`"${s.name}"`).join(", ")}`:"";await Ht(n.trackId,`Design decision: go with "${n.name}" (mock:${n.id})${o} \u2014 proceed with this design.`,{kind:"mock-picked"}).catch(()=>{}),t.json({ok:!0,mock:n,siblings:r})}catch(n){let r=n?.message||String(n),o=/not found/i.test(r)?404:/nothing to pick/i.test(r)?409:500;t.status(o).json({error:r})}});O.delete("/api/mocks/:id",async(e,t)=>{try{let n=(await iC(e.params.id)).map(r=>({id:r.id,name:r.name}));t.json({...await qM(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})}});O.get("/api/flows",async(e,t)=>{try{t.json({flows:await nC({trackId:e.query.track||void 0})})}catch(n){t.status(500).json({error:n?.message||String(n)})}});O.get("/api/flows/:id",async(e,t)=>{let n=await rC(e.params.id);if(!n)return t.status(404).json({error:"flow not found"});t.json({flow:n})});O.post("/api/flows",async(e,t)=>{let{trackId:n,name:r,steps:o,cwd:s}=e.body||{};try{let a=n?await ye(n):null;if(!a&&s&&(a=(await xe()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+De.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 oC({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})}});O.post("/api/flows/:id/update",async(e,t)=>{try{let{steps:n,note:r}=e.body||{};t.json({ok:!0,flow:await sC(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})}});O.delete("/api/flows/:id",async(e,t)=>{try{t.json(await aC(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});O.get("/api/runbooks",async(e,t)=>{try{let n=e.query.track||void 0;if(!n&&e.query.cwd){let s=await xe(),a=String(e.query.cwd);if(n=s.find(i=>i.cwd&&(a===i.cwd||a.startsWith(i.cwd+De.sep)))?.id,!n)return t.json({runbooks:[]})}let{runbooks:r,fleetDegraded:o}=await mC({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)})}});O.get("/api/runbooks/:id",async(e,t)=>{let n=await wk(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});t.json({runbook:n})});O.get("/api/runbooks/:id/md",async(e,t)=>{let n=await wk(e.params.id);if(!n)return t.status(404).json({error:"runbook not found"});let r=fC(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 wC(n,r.v);return typeof o!="string"?t.status(404).json({error:"runbook artifact missing"}):t.send(o)}t.sendFile(to(n,r.v),$d,o=>{o&&!t.headersSent&&t.status(404).json({error:"runbook artifact missing"})})});O.get("/api/loops",async(e,t)=>{t.json(await $l())});O.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 xe()).find(u=>u.cwd&&(o===u.cwd||o.startsWith(u.cwd+De.sep)))||null;if(!a)return t.status(400).json({error:"cwd is not inside a Track workspace"});let i=await $l();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 ey({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})});O.post("/api/loops/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=n?await ye(n):null;if(!s&&r&&(s=(await xe()).find(i=>i.cwd&&(r===i.cwd||r.startsWith(i.cwd+De.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 e1(s,o)})}catch(s){t.status(400).json({error:s?.message||String(s)})}});var Pa=async(e,t)=>{let n=e?await ye(e):null;return!n&&t&&(n=(await xe()).find(o=>o.cwd&&(t===o.cwd||t.startsWith(o.cwd+De.sep)))||null),n};O.post("/api/followups/offer",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Pa(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 MO(s,o,{ship:{changedRepos:ha}})})}catch(s){t.status(400).json({error:s?.message||String(s)})}});O.post("/api/ship/updated",async(e,t)=>{let{trackId:n,cwd:r,number:o,rebased:s,base:a}=e.body||{};try{let i=await Pa(n,r);if(!i)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});t.json({ok:!0,trackId:i.id,result:await nB(i,{number:o??null,rebased:s===!0,base:a??null})})}catch(i){t.status(400).json({error:i?.message||String(i)})}});O.post("/api/followups/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o}=e.body||{};try{let s=await Pa(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 NO(s,o)})}catch(s){let a=s?.message||String(s);t.status(/unreachable/i.test(a)?503:400).json({error:a})}});O.get("/api/followups",async(e,t)=>{let n=typeof e.query?.cwd=="string"?e.query.cwd:null,r=await Pa(null,n).catch(()=>null);t.json({ok:!0,trackId:r?.id??null,triggers:$b,...await jO(r)})});var MB=new Set(["reconcile","fixing-ci","rebase","merge"]);O.get("/api/status",async(e,t)=>{let n=await Pa(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})});O.post("/api/status",async(e,t)=>{try{let{trackId:n,cwd:r,phase:o,summary:s,scope:a,reason:i}=e.body||{},c=await Pa(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&&!MB.has(l))throw new Error(`phase must be one of ${[...MB].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=VZ();await D(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)})}});O.post("/api/tracks/:id/followup-offer",async(e,t)=>{let{offerId:n,followupId:r,armId:o,promoted:s,all:a,rows:i,prompt:c,prompts:l,reordered:u}=e.body||{};try{let d=await ye(e.params.id);if(!d)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await DO(d,{offerId:n,followupId:r||null,armId:o||null,promoted:s||null,all:a===!0,rows:Array.isArray(i)?i:null,prompt:typeof c=="string"?c:null,prompts:l&&typeof l=="object"&&!Array.isArray(l)?l:null,reordered:u===!0},{sayToLead:Ht,unarchiveTrack:sc})})}catch(d){let p=d?.message||String(d),w=d?.code==="removed"?410:/unknown offer/i.test(p)?404:/already answered/i.test(p)?409:/required|not on this card|nothing to run together|rows must|not part of a batch|not in this batch|prompt must|prompts must|edited prompt|comes from Settings/i.test(p)?400:/unreachable/i.test(p)?503:502;t.status(w).json({error:p})}});O.post("/api/tracks/:id/followup-arm-save",async(e,t)=>{let{offerId:n,armId:r,followupId:o}=e.body||{};try{let s=await ye(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await BO(s,{offerId:n,armId:r,followupId:o})})}catch(s){let a=s?.message||String(s);t.status(/unknown offer/i.test(a)?404:/already saved/i.test(a)?409:400).json({error:a})}});O.post("/api/tracks/:id/followup-arm-cancel",async(e,t)=>{try{let n=await ye(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await CO(n,e.body?.armId)})}catch(n){let r=n?.message||String(n);t.status(/unknown/i.test(r)?404:400).json({error:r})}});O.post("/api/tracks/:id/followup-create-offer",async(e,t)=>{let{proposalId:n,accept:r,followupId:o}=e.body||{};try{let s=await ye(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await PO(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})}});at.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"||ye(e.trackId).then(async s=>{if(s&&(n&&await cu(s,n,o),t==="opened"||t==="pushed")){let a=LO(await V(s).catch(()=>[]));a&&await cu(s,"ship.done",{...o,shipOfferId:a})}}).catch(()=>{})});var GB=async(e,t,{trackId:n,cwd:r,loop:o})=>{let s=n?await ye(n):null;if(!s&&r&&(s=(await xe()).find(l=>l.cwd&&(r===l.cwd||r.startsWith(l.cwd+De.sep)))||null),!s)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"}),null;let a=await $l();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=r1(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}};O.post("/api/loops/propose-update",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await GB(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await o1(s.track,s.loop,e.body?.patch)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});O.post("/api/loops/propose-delete",async(e,t)=>{let{trackId:n,cwd:r,loop:o}=e.body||{},s=await GB(e,t,{trackId:n,cwd:r,loop:o});if(s)try{t.json({ok:!0,trackId:s.track.id,proposal:await s1(s.track,s.loop,e.body?.reason)})}catch(a){t.status(400).json({error:a?.message||String(a)})}});O.post("/api/planning/propose",async(e,t)=>{let{trackId:n,cwd:r,plan:o,scope:s}=e.body||{},a=await Pa(n,r);if(!a)return t.status(400).json({error:"trackId (or a cwd inside a Track workspace) required"});let i;try{i=await nx()}catch(c){return t.status(503).json({error:c?.message||String(c)})}try{let c=s==="circuit"?Qx:gd;t.json({ok:!0,trackId:a.id,proposal:await w1(a,o,i,{allow:c})})}catch(c){t.status(400).json({error:c?.message||String(c)})}});var jS=e=>/unknown proposal/i.test(e)?404:/already answered/i.test(e)?409:400;O.post("/api/tracks/:id/planning-offer",async(e,t)=>{let{proposalId:n,action:r,results:o}=e.body||{};try{let s=await ye(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await g1(s,n,r,{results:o||[]})})}catch(s){let a=s?.message||String(s);t.status(jS(a)).json({error:a})}});O.post("/api/tracks/:id/loop-update-offer",async(e,t)=>{let{proposalId:n,action:r,nextFireAt:o}=e.body||{};try{let s=await ye(e.params.id);if(!s)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await i1(s,n,r,{nextFireAt:o??null})})}catch(s){let a=s?.message||String(s);t.status(jS(a)).json({error:a})}});O.post("/api/tracks/:id/loop-delete-offer",async(e,t)=>{let{proposalId:n,action:r}=e.body||{};try{let o=await ye(e.params.id);if(!o)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await c1(o,n,r)})}catch(o){let s=o?.message||String(o);t.status(jS(s)).json({error:s})}});O.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 ye(e.params.id);if(!a)return t.status(404).json({error:"track not found"});t.json({ok:!0,...await t1(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})}});O.post("/api/runbooks",async(e,t)=>{let{trackId:n,name:r,md:o,cwd:s}=e.body||{};try{let a=n?await ye(n):null;if(!a&&s&&(a=(await xe()).find(u=>u.cwd&&(s===u.cwd||s.startsWith(u.cwd+De.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 gC({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})}});O.post("/api/runbooks/:id/update",async(e,t)=>{try{let{md:n,note:r}=e.body||{};t.json({ok:!0,runbook:await yC(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})}});O.post("/api/runbooks/:id/status",async(e,t)=>{try{t.json({ok:!0,runbook:await bC(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})}});O.delete("/api/runbooks/:id",async(e,t)=>{try{t.json(await kC(e.params.id))}catch(n){let r=n?.message||String(n);t.status(/not found/i.test(r)?404:500).json({error:r})}});O.get("/api/changelog/draft",async(e,t)=>{try{let n=S1(e.query.since||null);t.json({since:n,repos:tS(),...await v1(n)})}catch(n){let r=n?.message||String(n);t.status(/unparseable/i.test(r)?400:500).json({error:r})}});var KB=async({trackId:e,cwd:t})=>{let n=e?await ye(e):null;return!n&&t&&(n=(await xe()).find(o=>o.cwd&&(t===o.cwd||String(t).startsWith(o.cwd+De.sep)))||null),n};O.post("/api/changelog/publish",async(e,t)=>{let{md:n,day:r,trackId:o,cwd:s}=e.body||{};try{let a=await KB({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 A1(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})}});O.post("/api/changelog/retract",async(e,t)=>{let{day:n,trackId:r,cwd:o}=e.body||{};try{let s=await KB({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 T1(s,{day:n})})}catch(s){let a=s?.message||String(s);t.status(/required|invalid/i.test(a)?400:500).json({error:a})}});var rQ=120,RS=400,oQ=/^[a-z0-9][a-z0-9_-]{0,23}$/,Ec=null,CB=null;O.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&&!oQ.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>RS)return t.status(400).json({error:`message is ${c.length} chars \u2014 over the ${RS} cap; a notification is a nudge, put the detail in chat`});let u=Tu(`${n||""}
|
|
971
|
+
${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 ye(a):null;if(!d&&s&&(d=(await xe()).find(g=>g.cwd&&(s===g.cwd||s.startsWith(g.cwd+De.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),w=(h,g)=>String(h).replace(/\s+/g," ").trim().slice(0,g),m={title:n?w(n,rQ):d.name,body:w(c,RS),urgency:o==="high"?"high":"normal",...l?{channel:l}:{},trackName:d.name,ts:Date.now()};await D(d,{type:"notify.raised",actor:"agent",boxId:d.leadBox??null,provider:p?.agent||null,payload:m}),t.json({ok:!0,notification:m,delivered:Ec?Ec.status().connected:null})}catch(c){t.status(500).json({error:c?.message||String(c)})}});O.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 _B(e.body,e.headers["content-type"]))}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});O.get("/api/dictation/glossary",async(e,t)=>{t.json({configured:!!await ed(),terms:await _S(),problem:await EB()})});O.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 TB(n,r)})});O.get("/api/tracks/:id/voice-chat",async(e,t)=>{if(!await ye(e.params.id))return t.status(404).json({error:"track not found"});t.json(await IB())});O.post("/api/tracks/:id/voice-chat/session",async(e,t)=>{try{let n=await ye(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 $B())}catch(n){t.status(n?.status||500).json({error:n?.message||String(n),code:n?.code})}});O.post("/api/tracks/:id/voice-chat/usage",async(e,t)=>{try{let n=await ye(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 RB(n,{model:r,usage:o,seconds:s})})}catch(n){t.status(n?.status||500).json({error:n?.message||String(n)})}});var sQ=Number(process.env.BOSTRAT_KICKOFF_GRACE_MS)||1500;O.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,blueprintItems:d,kickoff:p,launchedFrom:w}=e.body||{};try{let m=oP({blueprintItems:d,kickoff:p,launchedFrom:w}),h=await Xh({name:n,cwd:r,repo:o,repos:s,agent:a,model:i,skipPermissions:c!==!1,launchedFrom:m?.launchedFrom??null}),g=null;if(l)try{await hc(h,l,{source:"create"})}catch(S){g=S?.message||String(S)}let y=null;if(u)try{await pm(h,await uc(u),{source:"picker"})}catch(S){y=S?.message||String(S)}let b=null,x=null,v=null;if(m?.itemIds.length)if(!u)b="no circuit named \u2014 an item binds through the Track's circuit";else if(y)b="not bound \u2014 the circuit tag failed";else try{await sx(h,u,m.itemIds,process.env,{source:"launch"})}catch(S){b=S?.message||String(S)}if(m?.kickoff){let S=Ht(h.id,m.kickoff,{kind:"item-launch"}).then(P=>({ok:!0,r:P}),P=>({ok:!1,e:P})),E=await Promise.race([S,new Promise(P=>setTimeout(()=>P(null),sQ))]);E?E.ok?v=E.r?.queued?"queued":"sent":x=E.e?.usageCap?`spend cap reached \u2014 ${E.e.message}`:E.e?.message||String(E.e):(v="sending",S.then(P=>{P.ok||console.error(`[launch] kickoff for track ${h.id} failed after the create answered: ${P.e?.message||P.e}`)}))}t.json({ok:!0,track:h,...g?{ticketWarning:g}:{},...y?{circuitWarning:y}:{},...b?{bindWarning:b}:{},...v?{kickoff:v}:{},...x?{kickoffWarning:x}:{}})}catch(m){let h=m?.message||String(m);t.status(/required|unknown agent|invalid|must be/i.test(h)?400:500).json({error:h})}});O.post("/api/tracks/:id/launches",async(e,t)=>{try{let n=await ye(e.params.id);if(!n)return t.status(404).json({error:"track not found"});let{itemId:r,launchedTrackId:o,trackName:s,provider:a,node:i,via:c}=e.body||{};t.json({ok:!0,launch:await sP(n,{itemId:r,trackId:o,trackName:s,provider:a,node:i,via:c})})}catch(n){let r=n?.message||String(n);t.status(/required/i.test(r)?400:500).json({error:r})}});O.get("/api/tracks/:id",async(e,t)=>{let n=await ye(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json({track:n,handoff:VB(ac(e.params.id)),reshape:LS(qu(e.params.id)),subtasks:va(e.params.id).map(Rd),pendingOffers:await r0(n)})});O.delete("/api/tracks/:id",async(e,t)=>{try{let n=await T0(e.params.id,{cascadeMocks:e.query.mocks!=="0",cascadeRunbooks:e.query.runbooks==="1"});await Ex(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})}});O.post("/api/tracks/:id/archive",async(e,t)=>{try{t.json({ok:!0,track:await xa(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})}});O.post("/api/tracks/:id/rename",async(e,t)=>{try{t.json({ok:!0,track:await I0(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})}});O.post("/api/tracks/:id/unarchive",async(e,t)=>{try{t.json({ok:!0,track:await sc(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})}});O.get("/api/tracks/:id/messages",async(e,t)=>{let n=await Wh(e.params.id);if(!n)return t.status(404).json({error:"track not found"});t.json(n)});O.get("/api/tracks/:id/events",async(e,t)=>{let n=await ye(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}
|
|
972
972
|
data: ${JSON.stringify(i)}
|
|
973
973
|
|
|
974
974
|
`),o=Number(e.query.since??e.headers["last-event-id"])||0;for(let i of await V(n))i.seq>o&&r(i);let s=Lv(n.id,r),a=setInterval(()=>t.write(`: hb
|