thinkpool-pair 0.7.372 → 0.7.373
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/README.md +2 -1
- package/account.mjs +1 -1
- package/bridge.mjs +1 -1
- package/command-catalog.mjs +1 -1
- package/host-capacity.mjs +1 -0
- package/package.json +2 -1
- package/publish-manifest.json +10 -9
package/README.md
CHANGED
|
@@ -233,7 +233,8 @@ the preview server’s loopback origin for page requests.
|
|
|
233
233
|
| `TP_ANTHROPIC_BASE_URL` / `TP_ANTHROPIC_AUTH_TOKEN` / `TP_ANTHROPIC_MODEL` | Override the Claude-compatible provider without writing provider config |
|
|
234
234
|
| `TP_CONTEXT_MAX` | Override the context-window size used by the room meter |
|
|
235
235
|
| `TP_BROWSER_PATH` | Point preview capture at a non-standard Chrome/Chromium binary |
|
|
236
|
-
| `TP_FLOW_OFF=1` | Disable
|
|
236
|
+
| `TP_FLOW_OFF=1` | Disable Dispatch on this bridge (legacy environment-variable name) |
|
|
237
|
+
| `TP_HOST_LIVE_LANES` | Lower the shared parent-and-worker host ceiling from its safety maximum of 12 |
|
|
237
238
|
| `TP_SPAWN_OFF=1` | Disable agent-spawned worker lanes |
|
|
238
239
|
| `TP_PAIRBUS_OFF=1` | Disable the paired-room bus |
|
|
239
240
|
| `TP_CROSSROOM_OFF=1` | Disable cross-session reach |
|
package/account.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{spawn as e}from"node:child_process";import{fileURLToPath as r}from"node:url";import{randomUUID as t}from"node:crypto";import o from"node:path";import n from"node:fs";import{createClient as s}from"@supabase/supabase-js";import i from"node:os";import{saveAuth as a,loadAuth as c,markAuthReconnectRequired as d,loadDirs as l,bindDir as p,loadServed as u,rememberServed as m,loadDefaultDir as f,saveDefaultDir as h,claudeRecentProjectDir as y}from"./auth-store.mjs";import{isSafeToRestart as v}from"./update-gate.mjs";import{makeThrottledTrack as g,presenceRecoveryEligible as w,presenceSelfEchoObservation as _,recoveryBackoffMs as b,reducePresenceChannelEvidence as k,subscribeWithoutStartupDeadlock as $}from"./presence.mjs";import{publicKeyB64 as R,announceProviders as S,listProviders as T,addProvider as I,addProviderModel as O,removeProvider as x,unseal as C}from"./providers.mjs";import{supervisorServes as A,supervisorRoomsToStop as P}from"./serve-consent.mjs";import{resolveServeDir as N}from"./serve-dir.mjs";import{pairKeyFor as E,pairTopic as q,CROSSROOM_BUS as M}from"./cross-terminal.mjs";import{installedAgentCommands as U}from"./agent-detect.mjs";import{agentVisibilityStates as D,setAgentPickerVisibility as j}from"./agent-visibility.mjs";import{hostMemoryAdmission as F}from"./host-memory.mjs";import{createPairBusBroker as L,mergePairRoomRoster as H,pairBusStatusFromRealtime as B,PAIR_BUS_STATUS as G}from"./pair-bus.mjs";import{clearSupervisorReady as z,supervisorPresenceEchoed as K,writeSupervisorReady as W}from"./supervisor-ready.mjs";import{PAIR_CLI as J,pairCli as V}from"./command-guidance.mjs";import{syncRealtimeAuth as X}from"./design-edit.mjs";const Y=(()=>{try{return JSON.parse(n.readFileSync(new URL("./package.json",import.meta.url),"utf8")).version}catch{return null}})(),Z=r(new URL("./bridge.mjs",import.meta.url));export function createStartupAnchor({set:e=setInterval,clear:r=clearInterval}={}){const t=e(()=>{},6e4);let o=!1;return()=>{o||(o=!0,r(t))}}const Q=o.join(i.homedir(),".thinkpool-pair","account.lock");function ee(e){if(!e||e===process.pid)return!1;try{return process.kill(e,0),!0}catch(e){return"EPERM"===e.code}}export function acquireSingleton(e=Q){try{n.mkdirSync(o.dirname(e),{recursive:!0})}catch{return!1}for(let r=0;r<3;r++)try{const r=n.openSync(e,"wx");return n.writeSync(r,String(process.pid)),n.closeSync(r),!0}catch(r){if("EEXIST"!==r.code)return!1;let t=0;try{t=parseInt(n.readFileSync(e,"utf8").trim(),10)||0}catch{return!1}if(ee(t))return!1;try{n.rmSync(e,{force:!0})}catch{return!1}}return!1}export function releaseSingleton(e=Q){try{(parseInt(n.readFileSync(e,"utf8").trim(),10)||0)===process.pid&&n.rmSync(e,{force:!0})}catch{}}export function acquireMachineLock(e=Q){return acquireSingleton(e)}export function releaseMachineLock(e=Q){return releaseSingleton(e)}export function shouldHoldMachineLock(e=process.env){return"1"!==e.THINKPOOL_PAIR_ACCOUNT_CHILD}export async function runLogin(e,r,t){const o=s(e,r,{auth:{persistSession:!1}}),{data:n,error:i}=await o.rpc("start_device_code"),c=Array.isArray(n)?n[0]:n;!i&&c?.device_code||(process.stderr.write(`\n ✗ couldn't start login: ${i?.message||"no response"}\n`),process.exit(1));const{device_code:d,user_code:l}=c,p=`${t}/code/link?c=${encodeURIComponent(l)}`;process.stderr.write(`\n ◆ Link this device to your thinkpool account.\n Open (signed in) and approve:\n\n ${p}\n\n code: ${l}\n\n Waiting…\n`);const u=Date.now(),m=async()=>{Date.now()-u>3e5&&(process.stderr.write(`\n ◇ link timed out — run \`${V("login")}\` again.\n`),process.exit(1));try{const{data:e}=await o.rpc("claim_device_code",{p_device_code:d});"approved"===e?.status&&e.session?.refresh_token&&(a(e.session),process.stderr.write(`\n ◆ linked as ${e.session.email||"your account"}. You can close the browser tab.\n Now run: ${J}\n`),process.exit(0)),"expired"!==e?.status&&"not_found"!==e?.status||(process.stderr.write(`\n ◇ link expired — run \`${V("login")}\` again.\n`),process.exit(1))}catch{}setTimeout(m,3e3)};m(),await new Promise(()=>{})}const re=e=>new Promise(r=>{const t=setTimeout(r,e);t.unref?.()});export function withTimeout(e,r,t="op"){return new Promise((o,n)=>{const s=setTimeout(()=>n(new Error(`${t} timed out after ${r}ms`)),r);s.unref?.(),Promise.resolve(e).then(e=>{clearTimeout(s),o(e)},e=>{clearTimeout(s),n(e)})})}export function savedTokenStillValid(e,r=Math.floor(Date.now()/1e3),t=300){if(!e?.access_token)return!1;const o=e.expires_at||function(e){try{const r=String(e).split(".")[1],t=Buffer.from(r.replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"),o=JSON.parse(t)?.exp;return"number"==typeof o?o:0}catch{return 0}}(e.access_token);return!!o&&o-r>t}const te=o.join(i.homedir(),".thinkpool-pair","refresh.lock");export function acquireRefreshLock(e=te,r=3e4){try{n.mkdirSync(o.dirname(e),{recursive:!0})}catch{}for(let t=0;t<2;t++)try{const r=n.openSync(e,"wx");return n.writeSync(r,JSON.stringify({pid:process.pid,at:Date.now()})),n.closeSync(r),!0}catch(t){if("EEXIST"!==t.code)return!0;let o=1/0;try{o=Date.now()-(JSON.parse(n.readFileSync(e,"utf8"))?.at||0)}catch{o=1/0}if(o<r)return!1;try{n.rmSync(e,{force:!0})}catch{return!0}}return!1}export function releaseRefreshLock(e=te){try{n.rmSync(e,{force:!0})}catch{}}async function oe(e,r){if(!r?.access_token||!r?.refresh_token)return null;try{const{data:t,error:o}=await e.auth.setSession({access_token:r.access_token,refresh_token:r.refresh_token});return o||!t?.session?null:t.session}catch{return null}}export async function refreshAccountSession(e,r,t={}){const{load:o=c,save:n=a,acquire:s=acquireRefreshLock,release:i=releaseRefreshLock,wait:d=re}=t,l=async r=>{const t=o();if(t?.refresh_token&&r&&t.refresh_token!==r){const r=await oe(e,t);if(r)return{session:r,adopted:!0}}return null};let p=await l(r);if(p)return p;const u=o()?.refresh_token||r;if(!u)return null;let m=s();if(!m){for(let e=0;e<20;e++){if(await d(250),p=await l(u),p)return p;if(s()){m=!0;break}}if(!m)return null}try{if(p=await l(u),p)return p;const r=o()?.refresh_token||u,{data:t,error:s}=await e.auth.refreshSession({refresh_token:r});return s||!t?.session?{session:null,error:s||null}:(n(t.session),{session:t.session,adopted:!1})}finally{m&&i()}}export const ACCOUNT_RECONNECT_ERROR_CODES=new Set(["refresh_token_not_found","refresh_token_already_used","session_not_found"]);export function accountRefreshNeedsReconnect(e){return ACCOUNT_RECONNECT_ERROR_CODES.has(String(e?.code||""))}export async function authedClient(e,r){const t=c();if(!t?.refresh_token)return null;if(t.reconnect_required)return{reconnectRequired:!0};const o=s(e,r,{auth:{persistSession:!1,autoRefreshToken:!1}});if(savedTokenStillValid(t)){const e=await oe(o,t);if(e)return{sb:o,session:e}}const n=await refreshAccountSession(o,t.refresh_token);return n?.session?{sb:o,session:n.session}:accountRefreshNeedsReconnect(n?.error)?(d(n.error.code),{reconnectRequired:!0}):null}export async function authedClientWithRetry(e,r,t={}){const{attempt:o=authedClient,load:n=c,wait:s=re,onRetry:i=null,maxAttempts:a=1/0,baseMs:d=15e3,capMs:l=3e5}=t;let p=d;for(let t=1;t<=a;t++){const c=await o(e,r);if(c?.reconnectRequired)return c;if(c)return c;if(!n()?.refresh_token)return null;if(t>=a)break;i?.(p,t),await s(p),p=Math.min(2*p,l)}return null}export function claimLoopWedged({lastClaimOkAt:e,now:r,quietMsThreshold:t=4e4}){return r-e>=t}export function scheduleTokenRefresh({sb:e,session:r,onRefreshed:t,onReconnectRequired:o,skewMs:n=9e4,forceMs:s=0,retryMs:i=3e4,refresh:a=refreshAccountSession}){let c=null,d=r,l=!1,p=!1;const u=e=>{l||(clearTimeout(c),c=setTimeout(f,Math.max(1e3,e)),c?.unref&&c.unref())},m=()=>{if(s)return s;const e=d?.expires_at?1e3*d.expires_at:Date.now()+36e5;return Math.max(3e4,e-Date.now()-n)};async function f(){if(!l)try{const r=await a(e,d.refresh_token);if(!r?.session){if(accountRefreshNeedsReconnect(r?.error)&&!p){p=!0;try{await(o?.(r.error))}catch{}}throw r?.error||new Error("no session")}d=r.session;try{e.realtime?.setAuth?.(d.access_token)}catch{}p=!1;try{await(t?.(d))}catch{}u(m())}catch{u(i)}}return u(m()),{cancel:()=>{l=!0,clearTimeout(c)},_tick:f}}export function runBind(e,r){const t=(e||"").toUpperCase().trim();t||(console.error(`usage: ${V("bind","<ROOM>","<directory>")}`),process.exit(1));const s=o.resolve(r||".");n.existsSync(s)&&n.statSync(s).isDirectory()||(console.error(`✗ not a directory: ${s}`),process.exit(1)),p(t,s),console.error(`✓ bound ${t} → ${s}\n Run \`${J}\` (or restart it) to serve this session.`),process.exit(0)}export async function runAccount(r,s){acquireSingleton()||(console.error(`\n ◇ An account bridge is already running on this machine\n (~/.thinkpool-pair/account.lock). Not starting a second — two would race\n your saved login. Stop the other one first, or share a single room with\n \`${V("<ROOM>")}\`.\n`),process.exit(0)),z();const c=createStartupAnchor(),J=await authedClientWithRetry(r,s,{onRetry:e=>process.stderr.write(`\n ◇ Couldn't refresh your account session yet (offline, or another bridge is mid-rotation) — retrying in ${Math.round(e/1e3)}s. Saved login left in place.\n`)});J||(releaseSingleton(),console.error(`\n ◇ Not linked to a thinkpool account on this machine.\n Link it: ${V("login")}\n`),process.exit(0)),J.reconnectRequired&&(c(),releaseSingleton(),console.error("\n ◇ This bridge lost its thinkpool account link.\n Reconnect it: npx thinkpool-pair@latest login\n"),process.exit(0));const{sb:Q,session:ee}=J,re=ee.user?.email||"your account";let te=ee.access_token||null;const oe=process.cwd();let ne=!1;try{const e=await import("./service.mjs");ne=e.serviceActive(null)}catch{}const se=()=>"1"===process.env.THINKPOOL_PAIR_AUTOUPDATE||ne,ie="1"===process.env.THINKPOOL_PAIR_AUTOUPDATE?" (auto-updating background service — survives reboot, tracks @latest)\n":ne?" (background service — survives reboot, restarts on crash, pinned to this version)\n":` (run hands-off + auto-updating: ${V("install-service")})\n`,ae=f()||y()||oe;process.stderr.write(`\n ◆ thinkpool-pair — account mode · ${re}\n New sessions auto-serve from ${ae}${f()?" (your default)":y()?" (your most-recent Claude Code project)":""}\n (change it: ${V("set-default-dir","<dir>")} · one room: ${V("bind","<code>","<dir>")})\n${ie}`);const ce=new Map,de=new Map,le=new Map,pe=new Map,ue=new Set,me=new Map,fe=new Map,he=new Map,ye=new Map,ve=new Map;let ge=!1,we=null,_e=!1;const be=new Map,ke=new Set,$e=new Map,Re=i.hostname().replace(/\.local$/,""),Se=(t?.()||"").slice(0,8);let Te=null;console.log(`◇ supervisor boot sup=${Se} host=${Re} pid=${process.pid} npx=${Y||"dev"}`),await X(Q,te,s)||process.stderr.write("\n ⚠ realtime auth could not be initialized; private bridge control is unavailable.\n");const Ie=Q.channel(`tpacct:${ee.user.id}`,{config:{presence:{key:Re},broadcast:{self:!1}}}),Oe=Q.channel(`tpacct-control:${ee.user.id}`,{config:{private:!0,broadcast:{self:!1}}}),xe=t();let Ce=!1,Ae=()=>{};Oe.on("broadcast",{event:"bind-room"},({payload:e})=>{const r=String(e?.code||"").toUpperCase().trim();let t=String(e?.dir||"").trim();t.startsWith("~")&&(t=o.join(i.homedir(),t.slice(1))),r&&t&&(n.existsSync(t)?(p(r,t),e?.setDefault&&(h(t),process.stderr.write(`\n ◆ default project dir set → ${t}\n`)),process.stderr.write(`\n ◆ ${r} bound → ${t} (from the web). Serving…\n`),Ae()):process.stderr.write(`\n ◇ bind ${r}: directory not found (${t}) — ignored.\n`))}),Oe.on("broadcast",{event:"serve-room"},({payload:e})=>{const r=String(e?.code||"").toUpperCase().trim();/^[A-Z0-9]{4,12}$/.test(r)&&Ae()}),Oe.on("broadcast",{event:"shutdown"},async()=>{if(process.stderr.write("\n ◇ disconnect requested from the dashboard — stopping bridge.\n"),setTimeout(()=>{try{releaseSingleton()}catch{}process.exit(0)},2500),se())try{(await import("./service.mjs")).uninstallService(null)}catch{}process.kill(process.pid,"SIGTERM")});let Pe=!1;Oe.on("broadcast",{event:"restart"},async({payload:e}={})=>{const r=e?.nonce,t=async(e,t)=>{try{await Oe.send({type:"broadcast",event:"restart-status",payload:{nonce:r,ok:e,error:t}})}catch{}};if(Pe||_e)await t(!1,"a bridge update is already being prepared");else{Pe=!0;try{const r=await import("./service.mjs"),o=r.serviceActive(null),n=o?r.stageServiceUpdate(null):null;if(o&&!n)return void await t(!1,"the published runtime could not be staged; the existing bridge was left running");we=n||("string"==typeof e?.version?e.version:Y)||"restart",ge=!0,await t(!0)}catch(e){return void await t(!1,`restart preparation failed: ${e?.message||e}`)}finally{Pe=!1}gr()}});let Ne="init",Ee="connected";const qe=g(Ie,{minMs:5e3,onStatus:e=>{Ne=e}}),Me=R(),Ue=()=>qe({name:Re,bridgeId:xe,version:Y,rooms:[...ce.keys()],readyRooms:[...ue],refused:[...$e].map(([e,r])=>({code:e,reason:r})),service:se(),providerPubKey:Me,providers:S(),agents:D(U()),accountAuthState:Ee,ts:Date.now()}),De=async e=>{try{await withTimeout(Q.rpc("report_bridge_auth_state",{p_bridge_id:xe,p_state:e}),5e3,"report_bridge_auth_state")}catch{}},je=(e,r)=>{try{Oe.send({type:"broadcast",event:e,payload:r})}catch{}};Oe.on("broadcast",{event:"provider-add"},async({payload:e})=>{const r=e?.nonce;let t;try{t=C(e?.sealed)}catch{return je("provider-add-res",{nonce:r,ok:!1,error:"could not decrypt the sealed payload"})}const o=I(t);o.ok&&(Ue(),process.stderr.write(`\n ◆ provider added (${String(t?.name||"").slice(0,40)}) — re-announced.\n`)),je("provider-add-res",{nonce:r,ok:o.ok,error:o.ok?void 0:o.error,id:o.ok?o.id:void 0})}),Oe.on("broadcast",{event:"provider-add-model"},async({payload:e})=>{const r=e?.nonce,t=O({id:e?.id,model:e?.model,name:e?.name});t.ok&&(Ue(),process.stderr.write(`\n ◆ model added to an existing provider (${String(e?.model||"").slice(0,40)}) — re-announced.\n`)),je("provider-add-model-res",{nonce:r,ok:t.ok,error:t.ok?void 0:t.error,id:t.ok?t.id:void 0})}),Oe.on("broadcast",{event:"provider-remove"},async({payload:e})=>{const r=e?.nonce,t=x(e?.id);t.ok&&(Ue(),process.stderr.write("\n ◆ provider removed — re-announced.\n")),je("provider-remove-res",{nonce:r,ok:t.ok,error:t.ok?void 0:t.error})}),Oe.on("broadcast",{event:"providers-list-req"},async({payload:e})=>{const r=e?.nonce;je("providers-list-res",{nonce:r,ok:!0,providers:T()})}),Oe.on("broadcast",{event:"agent-visibility-set"},async({payload:e})=>{const r=e?.nonce,t=U(),o=j(e?.cmd,!0===e?.enabled,{installed:t});if(o.ok){Ue();for(const e of ce.values())try{e.send({t:"agent-visibility-changed"})}catch{}process.stderr.write(`\n ◆ terminal picker agents updated — ${o.agents.filter(e=>e.enabled).map(e=>e.cmd).join(", ")} visible.\n`)}je("agent-visibility-res",{nonce:r,ok:o.ok,error:o.ok?void 0:o.error,agents:o.ok?o.agents:void 0})});let Fe=k(),Le=!1,He=!1;const Be=()=>{if(He||!Le)return;let e=!1;try{e=K(Ie.presenceState?.(),Re,xe,Y)}catch{e=!1}e&&(He=W({version:Y,bridgeId:xe}),He||process.stderr.write("\n ◇ Could not record local supervisor readiness; the bridge remains running but installers will not claim it was confirmed.\n"))};Ie.on("presence",{event:"sync"},()=>{Fe=k(Fe,"sync"),Be()});const Ge=await $(Ie,e=>{if("SUBSCRIBED"===e)Fe=k(Fe,e),Ue();else if("CLOSED"===e||"CHANNEL_ERROR"===e||"TIMED_OUT"===e){Fe=k(Fe,e);try{Q.realtime?.connect?.()}catch{}}});Ge.connected||process.stderr.write(`\n ◇ account realtime not ready at startup (${Ge.status}) — staying alive and recovering in process.\n`);const ze=await $(Oe,e=>{"CLOSED"!==e&&"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e||process.stderr.write(`\n ⚠ private account control ${e}; host-changing dashboard actions are unavailable until Realtime reconnects.\n`)});ze.connected||process.stderr.write(`\n ◇ private account control not ready at startup (${ze.status}) — presence remains available.\n`);const Ke=scheduleTokenRefresh({sb:Q,session:ee,onRefreshed:async e=>{Ee="connected",a(e),Ue(),await De("connected"),te=e.access_token||te;for(const e of ce.values())try{e.send({t:"token",accessToken:te})}catch{}},onReconnectRequired:async e=>{Ee="reconnect-required",d(e?.code||"refresh-token-invalid"),Ue(),await De("reconnect-required"),process.stderr.write("\n ◇ This bridge lost its thinkpool account link.\n Reconnect it: npx thinkpool-pair@latest login\n")},forceMs:parseInt(process.env.TP_TOKEN_REFRESH_FORCE_MS,10)||0});let We=!1,Je=0,Ve=null,Xe=Date.now(),Ye=0,Ze=0;const Qe=async()=>{try{const{data:e}=await withTimeout(Q.rpc("claim_bridge",{p_bridge_id:xe,p_hostname:Re}),1e4,"claim_bridge");Xe=Date.now();const r=Array.isArray(e)?e[0]:e,t=!!r?.held,o=r?.holder_host||"?";return t&&!We?process.stderr.write("\n ◆ holding this account — serving your sessions (single active bridge).\n"):!t&&We?process.stderr.write(`\n ◇ another device (${o}) took over this account — standing by.\n`):t||Ve===o||process.stderr.write(`\n ◇ another device (${o}) is serving this account — standing by.\n (this Mac takes over automatically if that device goes offline.)\n`),We=t,Je=t&&Number.isSafeInteger(Number(r?.fencing))&&Number(r.fencing)>0?Number(r.fencing):0,Ve=t?null:o,Te!==t&&(console.log(`claim_tick sup=${Se} held=${t} holder=${t?Re:o}`),Te=t),t}catch{return We}},er=L({channels:ye,randomId:t}),rr=e=>er.resolve(e),tr=(e,r,t)=>er.requestFirst(e,r,t),or=(e,r,t)=>er.requestCollect(e,r,t),nr=async e=>{try{const r=await withTimeout(Q.rpc("list_pair_rooms",{p_code:e}),2500,"paired-room roster");return r?.error||!Array.isArray(r?.data)?{verified:!1,rooms:[]}:{verified:!0,rooms:r.data}}catch{return{verified:!1,rooms:[]}}},sr=(e,r)=>{if(!e||ye.has(e))return;const o=q(r);if(!o)return;const n=Q.channel(o,{config:{private:!0,broadcast:{self:!1}}}),s={channel:n,key:r,status:G.JOINING};n.on("broadcast",{event:"peer-list-req"},({payload:r})=>((e,r,t)=>{if("1"===process.env.TP_PAIRBUS_OFF||"1"===process.env.TP_CROSSROOM_OFF)return;const o=[...ce.keys()].filter(r=>he.get(r)===e).map(e=>({code:e,name:me.get(e)||null,host:Re}));try{r.send({type:"broadcast",event:"peer-list-res",payload:{nonce:t?.nonce,rooms:o}})}catch{}})(e,n,r)).on("broadcast",{event:"peer-list-res"},({payload:e})=>rr(e)).on("broadcast",{event:"peer-peek-req"},({payload:r})=>((e,r,o)=>{const n=e=>{try{r.send({type:"broadcast",event:"peer-peek-res",payload:{nonce:o?.nonce,...e}})}catch{}};if("1"===process.env.TP_PAIRBUS_OFF||"1"===process.env.TP_CROSSROOM_OFF)return n({error:"Cross-session reach is off on this device."});const s=String(o?.targetRoom||"").toUpperCase().trim(),i=ce.get(s);if(!i||he.get(s)!==e)return n({error:`Room ${s} is not a room this device shares with you.`});const a=t();fe.set(a,{reply:e=>n({text:e.text,error:e.error}),askerRoom:null});try{i.send({t:"pair-peek-local",reqId:a,terminal:o.terminal,lines:o.lines})}catch{fe.delete(a),n({error:`Could not reach room ${s}.`})}})(e,n,r)).on("broadcast",{event:"peer-peek-res"},({payload:e})=>rr(e)).on("broadcast",{event:"peer-post-req"},({payload:r})=>((e,r,o)=>{const n=e=>{try{r.send({type:"broadcast",event:"peer-post-res",payload:{nonce:o?.nonce,...e}})}catch{}};if("1"===process.env.TP_PAIRBUS_OFF)return n({error:"Cross-room posting is off on this device."});if(!(e=>{const r=Date.now();let t=ve.get(e);return(!t||r>=t.resetAt)&&(t={count:0,resetAt:r+6e4},ve.set(e,t)),!(t.count>=6||(t.count++,0))})(e))return n({error:"Too many cross-room posts to this device right now — try again shortly."});const s=String(o?.targetRoom||"").toUpperCase().trim(),i=ce.get(s);if(!i||he.get(s)!==e)return n({error:`Room ${s} is not a room this device shares with you.`});const a=t();fe.set(a,{reply:e=>n({ok:e.ok,ref:e.ref,error:e.error}),askerRoom:null});try{i.send({t:"pair-post-local",reqId:a,fromRoom:o.fromRoom,fromHost:o.fromHost,fromTerminalName:o.fromTerminalName,text:o.text,terminal:o.terminal})}catch{fe.delete(a),n({error:`Could not reach room ${s}.`})}})(e,n,r)).on("broadcast",{event:"peer-post-res"},({payload:e})=>rr(e)).subscribe(e=>{s.status=B(e),"SUBSCRIBED"===e?process.stderr.write("\n ◆ pair bus subscribed — cross-machine Ensemble reach with your partner.\n"):"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e||process.stderr.write(`\n ◇ pair bus ${e.toLowerCase().replace("_"," ")} — partner sessions are offline until it reconnects.\n`)}),ye.set(e,s)};let ir=0;const ar=async()=>{const e=Date.now();if(!(ir&&e-ir<6e4)){ir=e;try{await cr()}finally{ir===e&&(ir=0)}}};Ae=()=>{ar().catch(()=>{})};const cr=async()=>{if(!await Qe()){if(ce.size)for(const[,e]of ce)try{e.kill("SIGTERM")}catch{}return void Ue()}let r=[],s=!1;const a=ee.user.id;try{const{data:e,error:t}=await Q.from("code_sessions").select("code,name,last_active_at,owner_id,participants,closed_at").eq("owner_id",a).is("closed_at",null).order("last_active_at",{ascending:!1}).limit(20);if(t)throw t;r=e||[],s=!0;const o=new Set(r.map(e=>e.code));for(const e of[...$e.keys()])o.has(e)||$e.delete(e)}catch{}if(s)for(const e of P({rooms:r,childRooms:ce.keys(),myUid:a})){const r=ce.get(e);if(r){console.log(`child_retire sup=${Se} room=${e} pid=${r.pid||"?"} reason=not-active-owned`);try{r.kill("SIGTERM")}catch{}}}const c=l(),d=u();for(const s of r){const r=s.code;if(!r||ce.has(r)){r&&$e.delete(r);continue}if(!A({ownerId:s.owner_id,myUid:a,closedAt:s.closed_at}))continue;const l=N({bound:c[r],remembered:d[r],defaultDir:f()||y()||oe,home:i.homedir()});if(l.refuse){if($e.set(r,l.reason),!ke.has(r)){ke.add(r);const e="home"===l.reason?`no project directory set — refusing to serve it from your home folder (${l.dir}); the agent would lose its session context and the room would show "${o.basename(l.dir)}" as the repo.`:"no directory to serve it from.";process.stderr.write(`\n ◇ ${r}: ${e}\n Bind it to its repo: ${V("bind",r,"<repo-dir>")}\n`)}continue}const p=l.dir;if(!n.existsSync(p)){$e.set(r,"dir-gone"),ke.has(r)||(ke.add(r),process.stderr.write(`\n ◇ ${r}: bound directory is gone (${p}) — re-bind it.\n`));continue}ke.delete(r),$e.delete(r),l.fromDefault&&m(r,p),me.set(r,s.name||null),process.stderr.write(`\n ◆ serving ${r}${s.name?` "${s.name}"`:""} → ${p}${c[r]?"":" (default)"}\n`);const u={...process.env,THINKPOOL_PAIR_ACCOUNT_CHILD:"1",TP_ACCOUNT_BRIDGE_ID:xe,TP_ACCOUNT_BRIDGE_FENCING:String(Je)};delete u.THINKPOOL_PAIR_AUTOUPDATE,te&&(u.TP_ACCESS_TOKEN=te);const h=ce.has(r),v=F(`spawn the room bridge for ${r}`);if(!v.ok){ke.has(`memory:${r}`)||(ke.add(`memory:${r}`),process.stderr.write(`\n ◇ ${r}: ${v.reason}\n`)),$e.set(r,"host-memory");continue}ke.delete(`memory:${r}`);const g=e(process.execPath,[Z,r,"--headless","--auto=claude"],{cwd:p,stdio:["inherit","inherit","inherit","ipc"],env:u});console.log(`child_spawn sup=${Se} room=${r} pid=${g.pid} dir=${p} had_prior=${h}`),ce.set(r,g),ue.delete(r),de.set(r,!1),le.set(r,!1),pe.set(r,!1),g.on("message",e=>{if(e)if("room-ready"===e.t)ue.add(r),console.log(`child_ready sup=${Se} room=${r} pid=${g.pid}`),Ue();else if("idle"===e.t)de.set(r,!!e.idle),le.set(r,null!=e.between?!!e.between:!!e.idle),pe.set(r,!!e.webPeer),gr();else if("busy"===e.t)de.set(r,!1),le.set(r,!1);else if("restart-probe-result"===e.t){const t=be.get(e.nonce);if(!t||!t.pending.has(r)||ce.get(r)!==g)return;t.pending.delete(r),t.ok=t.ok&&!0===e.between,le.set(r,!0===e.between),t.pending.size||(clearTimeout(t.timer),be.delete(e.nonce),t.resolve(t.ok))}else if("apply-update"===e.t)ge=!0,gr();else if("pair-list-req"===e.t)(async()=>{if("1"===process.env.TP_CROSSROOM_OFF){try{g.send({t:"pair-list-res",reqId:e.reqId,rooms:[],error:"Cross-session reach is turned off on this bridge."})}catch{}return}const t=[...ce.keys()].filter(e=>e!==r).map(e=>({code:e,name:me.get(e)||null}));let o=[],n=[];if("1"!==process.env.TP_PAIRBUS_OFF){const e=await Promise.all([nr(r),ye.size?or("peer-list-req",{},1200):Promise.resolve([])]);o=e[0].rooms,n=e[1]}const s=H({authorized:o,replies:n,myUid:ee.user.id,localCodes:ce.keys()});try{g.send({t:"pair-list-res",reqId:e.reqId,rooms:[...t,...s]})}catch{}})();else if("pair-peek-req"===e.t)(async()=>{const o=r=>{try{g.send({t:"pair-peek-res",reqId:e.reqId,...r})}catch{}};if("1"===process.env.TP_CROSSROOM_OFF)return o({error:"Cross-session reach is turned off on this bridge."});const n=String(e.targetRoom||"").toUpperCase().trim();if(!n||n===r)return o({error:`${n||"That"} is not another of your active sessions.`});const s=ce.get(n);if(s){const i=t();fe.set(i,{reply:e=>o({text:e.text,error:e.error}),askerRoom:r});try{s.send({t:"pair-peek-local",reqId:i,terminal:e.terminal,lines:e.lines})}catch{fe.delete(i),o({error:`Could not reach session ${n}.`})}return}if("1"===process.env.TP_PAIRBUS_OFF)return o({error:"Cross-session reach is turned off on this bridge."});const[i,a]=await Promise.all([nr(r),ye.size?or("peer-list-req",{},800):Promise.resolve([])]);if(i.verified&&!i.rooms.some(e=>e?.code===n&&e?.owner_id!==ee.user.id))return o({error:`Room ${n} is not shared with this pair.`});if(!ye.size)return o({error:i.verified?`Room ${n} is paired with you, but its host bridge is offline.`:`Session ${n} is not running on this machine, and no pair bus is open to reach it.`});if(!a.some(e=>e?.rooms?.some(e=>e?.code===n)))return o({error:`Room ${n} is paired with you, but its host bridge is offline.`});const c=await(d=n,l=e.terminal,p=e.lines,tr("peer-peek-req",{targetRoom:d,terminal:l,lines:p},M.busTimeoutMs));var d,l,p;if(!c)return o({error:`Room ${n} did not respond — it may be offline, or not shared with you.`});o({text:c.text,error:c.error})})();else if("pair-post-req"===e.t)(async()=>{const o=r=>{try{g.send({t:"pair-post-res",reqId:e.reqId,...r})}catch{}};if("1"===process.env.TP_PAIRBUS_OFF)return o({error:"Cross-room posting is turned off on this bridge."});const n=String(e.targetRoom||"").toUpperCase().trim();if(!n||n===r)return o({error:`${n||"That"} is not another of your sessions.`});const s=ce.get(n);if(s){const i=t();fe.set(i,{reply:e=>o({ok:e.ok,ref:e.ref,error:e.error}),askerRoom:r});try{s.send({t:"pair-post-local",reqId:i,fromRoom:r,fromHost:Re,fromTerminalName:e.fromTerminalName,text:e.text,terminal:e.terminal})}catch{fe.delete(i),o({error:`Could not reach session ${n}.`})}return}const[i,a]=await Promise.all([nr(r),ye.size?or("peer-list-req",{},1200):Promise.resolve([])]);if(i.verified&&!i.rooms.some(e=>e?.code===n&&e?.owner_id!==ee.user.id))return o({error:`Room ${n} is not shared with this pair.`});if(!ye.size)return o({error:i.verified?`Room ${n} is paired with you, but its host bridge is offline.`:`Room ${n} is not on this machine, and no pair bus is open to reach it.`});if(!a.some(e=>e?.rooms?.some(e=>e?.code===n)))return o({error:`Room ${n} is paired with you, but its host bridge is offline — no recipient approval card can be raised yet.`});const c=await(d=n,l=e.terminal,p=e.text,u=r,m=e.fromTerminalName,tr("peer-post-req",{targetRoom:d,terminal:l,text:p,fromRoom:u,fromHost:Re,fromTerminalName:m},18e4));var d,l,p,u,m;if(!c)return o({error:`Room ${n} did not respond to the hand-off in time.`});o({ok:c.ok,ref:c.ref,error:c.error})})();else if("pair-peek-res"===e.t||"pair-post-res"===e.t){const r=fe.get(e.reqId);if(!r)return;fe.delete(e.reqId);try{r.reply(e)}catch{}}});const w=e=>{console.log(`child_exit sup=${Se} room=${r} pid=${g?.pid||"?"} code=${e||"?"}`),ce.delete(r),ue.delete(r),de.delete(r),le.delete(r),pe.delete(r),me.delete(r),he.delete(r);for(const[e,t]of fe)t?.askerRoom===r&&fe.delete(e)};if(g.on("exit",e=>w(e)),g.on("error",e=>{w();try{process.stderr.write(`\n ◇ ${r}: failed to launch its bridge (${e?.message||e}) — retrying next tick.\n`)}catch{}}),we)try{g.send({t:"update-available",version:we})}catch{}}if("1"!==process.env.TP_PAIRBUS_OFF)for(const e of r){if(!e?.code||!ce.has(e.code))continue;const r=Array.isArray(e.participants)?e.participants:[],t=2===r.length?r.find(e=>e&&e!==ee.user.id):null;if(!t){he.delete(e.code);continue}he.set(e.code,t);const o=E(ee.user.id,t);o&&sr(t,o)}Ue()};await ar();const dr=setInterval(ar,15e3);Le=!0,Be(),c();const lr=[];let pr=!1,ur=0,mr=0,fr=!1;const hr=setInterval(async()=>{if(pr)return;const e=Date.now();if(!claimLoopWedged({lastClaimOkAt:Xe,now:e}))return ur=0,void(mr=0);if(fr||e<mr)return;fr=!0;const r=b(ur);mr=e+r,ur+=1,console.log(`claim_watchdog sup=${Se} quiet_ms=${e-Xe} attempt=${ur} next_ms=${r} — reconnecting realtime + re-claiming`);try{Q.realtime?.connect?.()}catch{}ir=0;try{await Qe(),Ue()}catch{}finally{fr=!1}},2e4);hr.unref?.();const yr=setInterval(()=>{if(pr)return;const e=Date.now(),r=w({claimHeld:We,lastClaimOkAt:Xe,now:e});let t=!1;try{t=!!Ie.presenceState?.()[Re]}catch{t=!1}const o=_({tracking:r,subscribedAt:Math.max(Fe.subscribedAt,Xe),syncSeenAt:Fe.syncSeenAt,present:t,missingSince:Ye,now:e});if(Ye=o.missingSince,!Ye)return void(Ze=0);const n=o.verdict;if("recycle"===n){if(Ze===Ye)return;Ze=Ye,console.log(`presence_watchdog sup=${Se} action=recycle missing_ms=${e-Ye} track=${Ne} — full realtime disconnect+reconnect`);try{Q.realtime?.disconnect?.()}catch{}try{Q.realtime?.connect?.()}catch{}try{Ue()}catch{}}else"respawn"===n&&(console.log(`presence_watchdog sup=${Se} action=respawn missing_ms=${e-Ye} track=${Ne} — recycle failed, exiting for a clean supervisor respawn`),process.exit(1))},15e3);yr.unref?.();const vr=e=>{if(pr)return;pr=!0;const r=Ce?1:0;console.log(`supervisor_stop sup=${Se} reason=${e||"unknown"} restarting=${Ce} children=${ce.size}`),clearInterval(dr),clearInterval(hr),clearInterval(yr);for(const e of lr)try{clearInterval(e)}catch{}Ke.cancel(),z({pid:process.pid}),releaseSingleton();for(const r of ce.values())try{r.kill(e||"SIGTERM")}catch{}er.close();for(const{channel:e}of ye.values())try{Q.removeChannel(e)}catch{}(async()=>{try{We&&await Q.rpc("release_bridge",{p_bridge_id:xe})}catch{}try{await Ie.untrack()}catch{}try{await Q.removeChannel(Oe)}catch{}try{await Q.removeChannel(Ie)}catch{}process.exit(r)})(),setTimeout(()=>process.exit(r),1500)};for(const e of["SIGINT","SIGTERM","SIGHUP"])process.on(e,()=>vr(e));async function gr(){if(!_e&&v({pendingUpdate:we,stopping:pr,childIdle:de,childBetween:le,childPeer:pe,requested:ge})){if(_e=!0,!await function(e=2500){const r=[...ce.entries()];if(!r.length)return Promise.resolve(!0);const o=t();return new Promise(t=>{const n={pending:new Set(r.map(([e])=>e)),ok:!0,resolve:t,timer:null};n.timer=setTimeout(()=>{be.delete(o),t(!1)},e),n.timer.unref?.(),be.set(o,n);for(const[e,t]of r)try{t.send({t:"restart-probe",nonce:o})}catch{n.pending.delete(e),n.ok=!1}n.pending.size||(clearTimeout(n.timer),be.delete(o),t(n.ok))})}())return _e=!1,void process.stderr.write("\n ◆ bridge update still queued — an agent became active before the restart boundary.\n");process.stderr.write(`\n ◆ thinkpool-pair ${we} ready (running ${Y}) — restarting account bridge to update; sessions resume.\n`);try{const e=await import("./service.mjs");if(e.serviceActive(null)&&!1!==e.applyStagedServiceUpdate(null,we))return}catch{}if(_e=!1,Ce=!0,!se())try{e(process.execPath,[process.argv[1]],{detached:!0,stdio:"ignore",env:process.env}).unref()}catch{}vr("SIGTERM")}}if("1"===process.env.THINKPOOL_PAIR_AUTOUPDATE&&Y){const e=1e3*Math.max(60,parseInt(process.env.THINKPOOL_PAIR_UPDATE_INTERVAL,10)||1800),r=(e,r)=>{const t=e=>String(e).split("-")[0].split(".").map(e=>parseInt(e,10)||0),o=t(e),n=t(r);for(let e=0;e<3;e++){if((o[e]||0)>(n[e]||0))return!0;if((o[e]||0)<(n[e]||0))return!1}return!1},t=async()=>{const e=new AbortController,r=setTimeout(()=>e.abort(),8e3);try{const r=await fetch("https://registry.npmjs.org/thinkpool-pair/latest",{signal:e.signal,headers:{accept:"application/json"}});if(!r.ok)return null;const t=await r.json();return"string"==typeof t?.version?t.version:null}catch{return null}finally{clearTimeout(r)}},o=async()=>{const e=await t();if(e&&r(e,Y)){we||process.stderr.write(`\n ◆ thinkpool-pair ${e} published — "update ready" surfaced to each room; applies between turns.\n`);try{(await import("./service.mjs")).provisionRuntime(e)}catch(r){return void process.stderr.write(`\n ⚠ bridge ${e} could not be staged yet: ${r?.message||r}\n`)}we=e;for(const r of ce.values())try{r.send({t:"update-available",version:e})}catch{}gr()}};lr.push(setInterval(o,e).unref()),lr.push(setInterval(gr,15e3).unref()),lr.push(setTimeout(o,6e4).unref())}await new Promise(()=>{})}
|
|
1
|
+
import{spawn as e}from"node:child_process";import{fileURLToPath as r}from"node:url";import{randomUUID as t}from"node:crypto";import o from"node:path";import n from"node:fs";import{createClient as s}from"@supabase/supabase-js";import i from"node:os";import{saveAuth as a,loadAuth as c,markAuthReconnectRequired as d,loadDirs as l,bindDir as p,loadServed as u,rememberServed as m,loadDefaultDir as f,saveDefaultDir as h,claudeRecentProjectDir as y}from"./auth-store.mjs";import{isSafeToRestart as v}from"./update-gate.mjs";import{makeThrottledTrack as g,presenceRecoveryEligible as w,presenceSelfEchoObservation as _,recoveryBackoffMs as b,reducePresenceChannelEvidence as k,subscribeWithoutStartupDeadlock as $}from"./presence.mjs";import{publicKeyB64 as R,announceProviders as S,listProviders as T,addProvider as I,addProviderModel as O,removeProvider as x,unseal as C}from"./providers.mjs";import{supervisorServes as A,supervisorRoomsToStop as P}from"./serve-consent.mjs";import{resolveServeDir as q}from"./serve-dir.mjs";import{pairKeyFor as N,pairTopic as E,CROSSROOM_BUS as M}from"./cross-terminal.mjs";import{installedAgentCommands as U}from"./agent-detect.mjs";import{agentVisibilityStates as D,setAgentPickerVisibility as j}from"./agent-visibility.mjs";import{hostMemoryAdmission as F}from"./host-memory.mjs";import{HostCapacityAuthority as L}from"./host-capacity.mjs";import{createPairBusBroker as H,mergePairRoomRoster as B,pairBusStatusFromRealtime as G,PAIR_BUS_STATUS as z}from"./pair-bus.mjs";import{clearSupervisorReady as K,supervisorPresenceEchoed as W,writeSupervisorReady as J}from"./supervisor-ready.mjs";import{PAIR_CLI as V,pairCli as X}from"./command-guidance.mjs";import{syncRealtimeAuth as Y}from"./design-edit.mjs";const Z=(()=>{try{return JSON.parse(n.readFileSync(new URL("./package.json",import.meta.url),"utf8")).version}catch{return null}})(),Q=r(new URL("./bridge.mjs",import.meta.url));export function createStartupAnchor({set:e=setInterval,clear:r=clearInterval}={}){const t=e(()=>{},6e4);let o=!1;return()=>{o||(o=!0,r(t))}}const ee=o.join(i.homedir(),".thinkpool-pair","account.lock");function re(e){if(!e||e===process.pid)return!1;try{return process.kill(e,0),!0}catch(e){return"EPERM"===e.code}}export function acquireSingleton(e=ee){try{n.mkdirSync(o.dirname(e),{recursive:!0})}catch{return!1}for(let r=0;r<3;r++)try{const r=n.openSync(e,"wx");return n.writeSync(r,String(process.pid)),n.closeSync(r),!0}catch(r){if("EEXIST"!==r.code)return!1;let t=0;try{t=parseInt(n.readFileSync(e,"utf8").trim(),10)||0}catch{return!1}if(re(t))return!1;try{n.rmSync(e,{force:!0})}catch{return!1}}return!1}export function releaseSingleton(e=ee){try{(parseInt(n.readFileSync(e,"utf8").trim(),10)||0)===process.pid&&n.rmSync(e,{force:!0})}catch{}}export function acquireMachineLock(e=ee){return acquireSingleton(e)}export function releaseMachineLock(e=ee){return releaseSingleton(e)}export function shouldHoldMachineLock(e=process.env){return"1"!==e.THINKPOOL_PAIR_ACCOUNT_CHILD}export async function runLogin(e,r,t){const o=s(e,r,{auth:{persistSession:!1}}),{data:n,error:i}=await o.rpc("start_device_code"),c=Array.isArray(n)?n[0]:n;!i&&c?.device_code||(process.stderr.write(`\n ✗ couldn't start login: ${i?.message||"no response"}\n`),process.exit(1));const{device_code:d,user_code:l}=c,p=`${t}/code/link?c=${encodeURIComponent(l)}`;process.stderr.write(`\n ◆ Link this device to your thinkpool account.\n Open (signed in) and approve:\n\n ${p}\n\n code: ${l}\n\n Waiting…\n`);const u=Date.now(),m=async()=>{Date.now()-u>3e5&&(process.stderr.write(`\n ◇ link timed out — run \`${X("login")}\` again.\n`),process.exit(1));try{const{data:e}=await o.rpc("claim_device_code",{p_device_code:d});"approved"===e?.status&&e.session?.refresh_token&&(a(e.session),process.stderr.write(`\n ◆ linked as ${e.session.email||"your account"}. You can close the browser tab.\n Now run: ${V}\n`),process.exit(0)),"expired"!==e?.status&&"not_found"!==e?.status||(process.stderr.write(`\n ◇ link expired — run \`${X("login")}\` again.\n`),process.exit(1))}catch{}setTimeout(m,3e3)};m(),await new Promise(()=>{})}const te=e=>new Promise(r=>{const t=setTimeout(r,e);t.unref?.()});export function withTimeout(e,r,t="op"){return new Promise((o,n)=>{const s=setTimeout(()=>n(new Error(`${t} timed out after ${r}ms`)),r);s.unref?.(),Promise.resolve(e).then(e=>{clearTimeout(s),o(e)},e=>{clearTimeout(s),n(e)})})}export function savedTokenStillValid(e,r=Math.floor(Date.now()/1e3),t=300){if(!e?.access_token)return!1;const o=e.expires_at||function(e){try{const r=String(e).split(".")[1],t=Buffer.from(r.replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"),o=JSON.parse(t)?.exp;return"number"==typeof o?o:0}catch{return 0}}(e.access_token);return!!o&&o-r>t}const oe=o.join(i.homedir(),".thinkpool-pair","refresh.lock");export function acquireRefreshLock(e=oe,r=3e4){try{n.mkdirSync(o.dirname(e),{recursive:!0})}catch{}for(let t=0;t<2;t++)try{const r=n.openSync(e,"wx");return n.writeSync(r,JSON.stringify({pid:process.pid,at:Date.now()})),n.closeSync(r),!0}catch(t){if("EEXIST"!==t.code)return!0;let o=1/0;try{o=Date.now()-(JSON.parse(n.readFileSync(e,"utf8"))?.at||0)}catch{o=1/0}if(o<r)return!1;try{n.rmSync(e,{force:!0})}catch{return!0}}return!1}export function releaseRefreshLock(e=oe){try{n.rmSync(e,{force:!0})}catch{}}async function ne(e,r){if(!r?.access_token||!r?.refresh_token)return null;try{const{data:t,error:o}=await e.auth.setSession({access_token:r.access_token,refresh_token:r.refresh_token});return o||!t?.session?null:t.session}catch{return null}}export async function refreshAccountSession(e,r,t={}){const{load:o=c,save:n=a,acquire:s=acquireRefreshLock,release:i=releaseRefreshLock,wait:d=te}=t,l=async r=>{const t=o();if(t?.refresh_token&&r&&t.refresh_token!==r){const r=await ne(e,t);if(r)return{session:r,adopted:!0}}return null};let p=await l(r);if(p)return p;const u=o()?.refresh_token||r;if(!u)return null;let m=s();if(!m){for(let e=0;e<20;e++){if(await d(250),p=await l(u),p)return p;if(s()){m=!0;break}}if(!m)return null}try{if(p=await l(u),p)return p;const r=o()?.refresh_token||u,{data:t,error:s}=await e.auth.refreshSession({refresh_token:r});return s||!t?.session?{session:null,error:s||null}:(n(t.session),{session:t.session,adopted:!1})}finally{m&&i()}}export const ACCOUNT_RECONNECT_ERROR_CODES=new Set(["refresh_token_not_found","refresh_token_already_used","session_not_found"]);export function accountRefreshNeedsReconnect(e){return ACCOUNT_RECONNECT_ERROR_CODES.has(String(e?.code||""))}export async function authedClient(e,r){const t=c();if(!t?.refresh_token)return null;if(t.reconnect_required)return{reconnectRequired:!0};const o=s(e,r,{auth:{persistSession:!1,autoRefreshToken:!1}});if(savedTokenStillValid(t)){const e=await ne(o,t);if(e)return{sb:o,session:e}}const n=await refreshAccountSession(o,t.refresh_token);return n?.session?{sb:o,session:n.session}:accountRefreshNeedsReconnect(n?.error)?(d(n.error.code),{reconnectRequired:!0}):null}export async function authedClientWithRetry(e,r,t={}){const{attempt:o=authedClient,load:n=c,wait:s=te,onRetry:i=null,maxAttempts:a=1/0,baseMs:d=15e3,capMs:l=3e5}=t;let p=d;for(let t=1;t<=a;t++){const c=await o(e,r);if(c?.reconnectRequired)return c;if(c)return c;if(!n()?.refresh_token)return null;if(t>=a)break;i?.(p,t),await s(p),p=Math.min(2*p,l)}return null}export function claimLoopWedged({lastClaimOkAt:e,now:r,quietMsThreshold:t=4e4}){return r-e>=t}export function scheduleTokenRefresh({sb:e,session:r,onRefreshed:t,onReconnectRequired:o,skewMs:n=9e4,forceMs:s=0,retryMs:i=3e4,refresh:a=refreshAccountSession}){let c=null,d=r,l=!1,p=!1;const u=e=>{l||(clearTimeout(c),c=setTimeout(f,Math.max(1e3,e)),c?.unref&&c.unref())},m=()=>{if(s)return s;const e=d?.expires_at?1e3*d.expires_at:Date.now()+36e5;return Math.max(3e4,e-Date.now()-n)};async function f(){if(!l)try{const r=await a(e,d.refresh_token);if(!r?.session){if(accountRefreshNeedsReconnect(r?.error)&&!p){p=!0;try{await(o?.(r.error))}catch{}}throw r?.error||new Error("no session")}d=r.session;try{e.realtime?.setAuth?.(d.access_token)}catch{}p=!1;try{await(t?.(d))}catch{}u(m())}catch{u(i)}}return u(m()),{cancel:()=>{l=!0,clearTimeout(c)},_tick:f}}export function runBind(e,r){const t=(e||"").toUpperCase().trim();t||(console.error(`usage: ${X("bind","<ROOM>","<directory>")}`),process.exit(1));const s=o.resolve(r||".");n.existsSync(s)&&n.statSync(s).isDirectory()||(console.error(`✗ not a directory: ${s}`),process.exit(1)),p(t,s),console.error(`✓ bound ${t} → ${s}\n Run \`${V}\` (or restart it) to serve this session.`),process.exit(0)}export async function runAccount(r,s){acquireSingleton()||(console.error(`\n ◇ An account bridge is already running on this machine\n (~/.thinkpool-pair/account.lock). Not starting a second — two would race\n your saved login. Stop the other one first, or share a single room with\n \`${X("<ROOM>")}\`.\n`),process.exit(0)),K();const c=createStartupAnchor(),V=await authedClientWithRetry(r,s,{onRetry:e=>process.stderr.write(`\n ◇ Couldn't refresh your account session yet (offline, or another bridge is mid-rotation) — retrying in ${Math.round(e/1e3)}s. Saved login left in place.\n`)});V||(releaseSingleton(),console.error(`\n ◇ Not linked to a thinkpool account on this machine.\n Link it: ${X("login")}\n`),process.exit(0)),V.reconnectRequired&&(c(),releaseSingleton(),console.error("\n ◇ This bridge lost its thinkpool account link.\n Reconnect it: npx thinkpool-pair@latest login\n"),process.exit(0));const{sb:ee,session:re}=V,te=re.user?.email||"your account";let oe=re.access_token||null;const ne=process.cwd();let se=!1;try{const e=await import("./service.mjs");se=e.serviceActive(null)}catch{}const ie=()=>"1"===process.env.THINKPOOL_PAIR_AUTOUPDATE||se,ae="1"===process.env.THINKPOOL_PAIR_AUTOUPDATE?" (auto-updating background service — survives reboot, tracks @latest)\n":se?" (background service — survives reboot, restarts on crash, pinned to this version)\n":` (run hands-off + auto-updating: ${X("install-service")})\n`,ce=f()||y()||ne;process.stderr.write(`\n ◆ thinkpool-pair — account mode · ${te}\n New sessions auto-serve from ${ce}${f()?" (your default)":y()?" (your most-recent Claude Code project)":""}\n (change it: ${X("set-default-dir","<dir>")} · one room: ${X("bind","<code>","<dir>")})\n${ae}`);const de=new Map,le=new L,pe=new Map,ue=new Map,me=new Map,fe=new Set,he=new Map,ye=new Map,ve=new Map,ge=new Map,we=new Map;let _e=!1,be=null,ke=!1;const $e=new Map,Re=new Set,Se=new Map,Te=i.hostname().replace(/\.local$/,""),Ie=(t?.()||"").slice(0,8);let Oe=null;console.log(`◇ supervisor boot sup=${Ie} host=${Te} pid=${process.pid} npx=${Z||"dev"}`),await Y(ee,oe,s)||process.stderr.write("\n ⚠ realtime auth could not be initialized; private bridge control is unavailable.\n");const xe=ee.channel(`tpacct:${re.user.id}`,{config:{presence:{key:Te},broadcast:{self:!1}}}),Ce=ee.channel(`tpacct-control:${re.user.id}`,{config:{private:!0,broadcast:{self:!1}}}),Ae=t();let Pe=!1,qe=()=>{};Ce.on("broadcast",{event:"bind-room"},({payload:e})=>{const r=String(e?.code||"").toUpperCase().trim();let t=String(e?.dir||"").trim();t.startsWith("~")&&(t=o.join(i.homedir(),t.slice(1))),r&&t&&(n.existsSync(t)?(p(r,t),e?.setDefault&&(h(t),process.stderr.write(`\n ◆ default project dir set → ${t}\n`)),process.stderr.write(`\n ◆ ${r} bound → ${t} (from the web). Serving…\n`),qe()):process.stderr.write(`\n ◇ bind ${r}: directory not found (${t}) — ignored.\n`))}),Ce.on("broadcast",{event:"serve-room"},({payload:e})=>{const r=String(e?.code||"").toUpperCase().trim();/^[A-Z0-9]{4,12}$/.test(r)&&qe()}),Ce.on("broadcast",{event:"shutdown"},async()=>{if(process.stderr.write("\n ◇ disconnect requested from the dashboard — stopping bridge.\n"),setTimeout(()=>{try{releaseSingleton()}catch{}process.exit(0)},2500),ie())try{(await import("./service.mjs")).uninstallService(null)}catch{}process.kill(process.pid,"SIGTERM")});let Ne=!1;Ce.on("broadcast",{event:"restart"},async({payload:e}={})=>{const r=e?.nonce,t=async(e,t)=>{try{await Ce.send({type:"broadcast",event:"restart-status",payload:{nonce:r,ok:e,error:t}})}catch{}};if(Ne||ke)await t(!1,"a bridge update is already being prepared");else{Ne=!0;try{const r=await import("./service.mjs"),o=r.serviceActive(null),n=o?r.stageServiceUpdate(null):null;if(o&&!n)return void await t(!1,"the published runtime could not be staged; the existing bridge was left running");be=n||("string"==typeof e?.version?e.version:Z)||"restart",_e=!0,await t(!0)}catch(e){return void await t(!1,`restart preparation failed: ${e?.message||e}`)}finally{Ne=!1}_r()}});let Ee="init",Me="connected";const Ue=g(xe,{minMs:5e3,onStatus:e=>{Ee=e}}),De=R(),je=()=>Ue({name:Te,bridgeId:Ae,version:Z,rooms:[...de.keys()],readyRooms:[...fe],refused:[...Se].map(([e,r])=>({code:e,reason:r})),service:ie(),providerPubKey:De,providers:S(),agents:D(U()),accountAuthState:Me,ts:Date.now()}),Fe=async e=>{try{await withTimeout(ee.rpc("report_bridge_auth_state",{p_bridge_id:Ae,p_state:e}),5e3,"report_bridge_auth_state")}catch{}},Le=(e,r)=>{try{Ce.send({type:"broadcast",event:e,payload:r})}catch{}};Ce.on("broadcast",{event:"provider-add"},async({payload:e})=>{const r=e?.nonce;let t;try{t=C(e?.sealed)}catch{return Le("provider-add-res",{nonce:r,ok:!1,error:"could not decrypt the sealed payload"})}const o=I(t);o.ok&&(je(),process.stderr.write(`\n ◆ provider added (${String(t?.name||"").slice(0,40)}) — re-announced.\n`)),Le("provider-add-res",{nonce:r,ok:o.ok,error:o.ok?void 0:o.error,id:o.ok?o.id:void 0})}),Ce.on("broadcast",{event:"provider-add-model"},async({payload:e})=>{const r=e?.nonce,t=O({id:e?.id,model:e?.model,name:e?.name});t.ok&&(je(),process.stderr.write(`\n ◆ model added to an existing provider (${String(e?.model||"").slice(0,40)}) — re-announced.\n`)),Le("provider-add-model-res",{nonce:r,ok:t.ok,error:t.ok?void 0:t.error,id:t.ok?t.id:void 0})}),Ce.on("broadcast",{event:"provider-remove"},async({payload:e})=>{const r=e?.nonce,t=x(e?.id);t.ok&&(je(),process.stderr.write("\n ◆ provider removed — re-announced.\n")),Le("provider-remove-res",{nonce:r,ok:t.ok,error:t.ok?void 0:t.error})}),Ce.on("broadcast",{event:"providers-list-req"},async({payload:e})=>{const r=e?.nonce;Le("providers-list-res",{nonce:r,ok:!0,providers:T()})}),Ce.on("broadcast",{event:"agent-visibility-set"},async({payload:e})=>{const r=e?.nonce,t=U(),o=j(e?.cmd,!0===e?.enabled,{installed:t});if(o.ok){je();for(const e of de.values())try{e.send({t:"agent-visibility-changed"})}catch{}process.stderr.write(`\n ◆ terminal picker agents updated — ${o.agents.filter(e=>e.enabled).map(e=>e.cmd).join(", ")} visible.\n`)}Le("agent-visibility-res",{nonce:r,ok:o.ok,error:o.ok?void 0:o.error,agents:o.ok?o.agents:void 0})});let He=k(),Be=!1,Ge=!1;const ze=()=>{if(Ge||!Be)return;let e=!1;try{e=W(xe.presenceState?.(),Te,Ae,Z)}catch{e=!1}e&&(Ge=J({version:Z,bridgeId:Ae}),Ge||process.stderr.write("\n ◇ Could not record local supervisor readiness; the bridge remains running but installers will not claim it was confirmed.\n"))};xe.on("presence",{event:"sync"},()=>{He=k(He,"sync"),ze()});const Ke=await $(xe,e=>{if("SUBSCRIBED"===e)He=k(He,e),je();else if("CLOSED"===e||"CHANNEL_ERROR"===e||"TIMED_OUT"===e){He=k(He,e);try{ee.realtime?.connect?.()}catch{}}});Ke.connected||process.stderr.write(`\n ◇ account realtime not ready at startup (${Ke.status}) — staying alive and recovering in process.\n`);const We=await $(Ce,e=>{"CLOSED"!==e&&"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e||process.stderr.write(`\n ⚠ private account control ${e}; host-changing dashboard actions are unavailable until Realtime reconnects.\n`)});We.connected||process.stderr.write(`\n ◇ private account control not ready at startup (${We.status}) — presence remains available.\n`);const Je=scheduleTokenRefresh({sb:ee,session:re,onRefreshed:async e=>{Me="connected",a(e),je(),await Fe("connected"),oe=e.access_token||oe;for(const e of de.values())try{e.send({t:"token",accessToken:oe})}catch{}},onReconnectRequired:async e=>{Me="reconnect-required",d(e?.code||"refresh-token-invalid"),je(),await Fe("reconnect-required"),process.stderr.write("\n ◇ This bridge lost its thinkpool account link.\n Reconnect it: npx thinkpool-pair@latest login\n")},forceMs:parseInt(process.env.TP_TOKEN_REFRESH_FORCE_MS,10)||0});let Ve=!1,Xe=0,Ye=null,Ze=Date.now(),Qe=0,er=0;const rr=async()=>{try{const{data:e}=await withTimeout(ee.rpc("claim_bridge",{p_bridge_id:Ae,p_hostname:Te}),1e4,"claim_bridge");Ze=Date.now();const r=Array.isArray(e)?e[0]:e,t=!!r?.held,o=r?.holder_host||"?";return t&&!Ve?process.stderr.write("\n ◆ holding this account — serving your sessions (single active bridge).\n"):!t&&Ve?process.stderr.write(`\n ◇ another device (${o}) took over this account — standing by.\n`):t||Ye===o||process.stderr.write(`\n ◇ another device (${o}) is serving this account — standing by.\n (this Mac takes over automatically if that device goes offline.)\n`),Ve=t,Xe=t&&Number.isSafeInteger(Number(r?.fencing))&&Number(r.fencing)>0?Number(r.fencing):0,Ye=t?null:o,Oe!==t&&(console.log(`claim_tick sup=${Ie} held=${t} holder=${t?Te:o}`),Oe=t),t}catch{return Ve}},tr=H({channels:ge,randomId:t}),or=e=>tr.resolve(e),nr=(e,r,t)=>tr.requestFirst(e,r,t),sr=(e,r,t)=>tr.requestCollect(e,r,t),ir=async e=>{try{const r=await withTimeout(ee.rpc("list_pair_rooms",{p_code:e}),2500,"paired-room roster");return r?.error||!Array.isArray(r?.data)?{verified:!1,rooms:[]}:{verified:!0,rooms:r.data}}catch{return{verified:!1,rooms:[]}}},ar=(e,r)=>{if(!e||ge.has(e))return;const o=E(r);if(!o)return;const n=ee.channel(o,{config:{private:!0,broadcast:{self:!1}}}),s={channel:n,key:r,status:z.JOINING};n.on("broadcast",{event:"peer-list-req"},({payload:r})=>((e,r,t)=>{if("1"===process.env.TP_PAIRBUS_OFF||"1"===process.env.TP_CROSSROOM_OFF)return;const o=[...de.keys()].filter(r=>ve.get(r)===e).map(e=>({code:e,name:he.get(e)||null,host:Te}));try{r.send({type:"broadcast",event:"peer-list-res",payload:{nonce:t?.nonce,rooms:o}})}catch{}})(e,n,r)).on("broadcast",{event:"peer-list-res"},({payload:e})=>or(e)).on("broadcast",{event:"peer-peek-req"},({payload:r})=>((e,r,o)=>{const n=e=>{try{r.send({type:"broadcast",event:"peer-peek-res",payload:{nonce:o?.nonce,...e}})}catch{}};if("1"===process.env.TP_PAIRBUS_OFF||"1"===process.env.TP_CROSSROOM_OFF)return n({error:"Cross-session reach is off on this device."});const s=String(o?.targetRoom||"").toUpperCase().trim(),i=de.get(s);if(!i||ve.get(s)!==e)return n({error:`Room ${s} is not a room this device shares with you.`});const a=t();ye.set(a,{reply:e=>n({text:e.text,error:e.error}),askerRoom:null});try{i.send({t:"pair-peek-local",reqId:a,terminal:o.terminal,lines:o.lines})}catch{ye.delete(a),n({error:`Could not reach room ${s}.`})}})(e,n,r)).on("broadcast",{event:"peer-peek-res"},({payload:e})=>or(e)).on("broadcast",{event:"peer-post-req"},({payload:r})=>((e,r,o)=>{const n=e=>{try{r.send({type:"broadcast",event:"peer-post-res",payload:{nonce:o?.nonce,...e}})}catch{}};if("1"===process.env.TP_PAIRBUS_OFF)return n({error:"Cross-room posting is off on this device."});if(!(e=>{const r=Date.now();let t=we.get(e);return(!t||r>=t.resetAt)&&(t={count:0,resetAt:r+6e4},we.set(e,t)),!(t.count>=6||(t.count++,0))})(e))return n({error:"Too many cross-room posts to this device right now — try again shortly."});const s=String(o?.targetRoom||"").toUpperCase().trim(),i=de.get(s);if(!i||ve.get(s)!==e)return n({error:`Room ${s} is not a room this device shares with you.`});const a=t();ye.set(a,{reply:e=>n({ok:e.ok,ref:e.ref,error:e.error}),askerRoom:null});try{i.send({t:"pair-post-local",reqId:a,fromRoom:o.fromRoom,fromHost:o.fromHost,fromTerminalName:o.fromTerminalName,text:o.text,terminal:o.terminal})}catch{ye.delete(a),n({error:`Could not reach room ${s}.`})}})(e,n,r)).on("broadcast",{event:"peer-post-res"},({payload:e})=>or(e)).subscribe(e=>{s.status=G(e),"SUBSCRIBED"===e?process.stderr.write("\n ◆ pair bus subscribed — cross-machine Ensemble reach with your partner.\n"):"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e||process.stderr.write(`\n ◇ pair bus ${e.toLowerCase().replace("_"," ")} — partner sessions are offline until it reconnects.\n`)}),ge.set(e,s)};let cr=0;const dr=async()=>{const e=Date.now();if(!(cr&&e-cr<6e4)){cr=e;try{await lr()}finally{cr===e&&(cr=0)}}};qe=()=>{dr().catch(()=>{})};const lr=async()=>{if(!await rr()){if(de.size)for(const[,e]of de)try{e.kill("SIGTERM")}catch{}return void je()}let r=[],s=!1;const a=re.user.id;try{const{data:e,error:t}=await ee.from("code_sessions").select("code,name,last_active_at,owner_id,participants,closed_at").eq("owner_id",a).is("closed_at",null).order("last_active_at",{ascending:!1}).limit(20);if(t)throw t;r=e||[],s=!0;const o=new Set(r.map(e=>e.code));for(const e of[...Se.keys()])o.has(e)||Se.delete(e)}catch{}if(s)for(const e of P({rooms:r,childRooms:de.keys(),myUid:a})){const r=de.get(e);if(r){console.log(`child_retire sup=${Ie} room=${e} pid=${r.pid||"?"} reason=not-active-owned`);try{r.kill("SIGTERM")}catch{}}}const c=l(),d=u();for(const s of r){const r=s.code;if(!r||de.has(r)){r&&Se.delete(r);continue}if(!A({ownerId:s.owner_id,myUid:a,closedAt:s.closed_at}))continue;const l=q({bound:c[r],remembered:d[r],defaultDir:f()||y()||ne,home:i.homedir()});if(l.refuse){if(Se.set(r,l.reason),!Re.has(r)){Re.add(r);const e="home"===l.reason?`no project directory set — refusing to serve it from your home folder (${l.dir}); the agent would lose its session context and the room would show "${o.basename(l.dir)}" as the repo.`:"no directory to serve it from.";process.stderr.write(`\n ◇ ${r}: ${e}\n Bind it to its repo: ${X("bind",r,"<repo-dir>")}\n`)}continue}const p=l.dir;if(!n.existsSync(p)){Se.set(r,"dir-gone"),Re.has(r)||(Re.add(r),process.stderr.write(`\n ◇ ${r}: bound directory is gone (${p}) — re-bind it.\n`));continue}Re.delete(r),Se.delete(r),l.fromDefault&&m(r,p),he.set(r,s.name||null),process.stderr.write(`\n ◆ serving ${r}${s.name?` "${s.name}"`:""} → ${p}${c[r]?"":" (default)"}\n`);const u={...process.env,THINKPOOL_PAIR_ACCOUNT_CHILD:"1",TP_ACCOUNT_BRIDGE_ID:Ae,TP_ACCOUNT_BRIDGE_FENCING:String(Xe)};delete u.THINKPOOL_PAIR_AUTOUPDATE,oe&&(u.TP_ACCESS_TOKEN=oe);const h=de.has(r),v=F(`spawn the room bridge for ${r}`);if(!v.ok){Re.has(`memory:${r}`)||(Re.add(`memory:${r}`),process.stderr.write(`\n ◇ ${r}: ${v.reason}\n`)),Se.set(r,"host-memory");continue}Re.delete(`memory:${r}`);const g=e(process.execPath,[Q,r,"--headless","--auto=claude"],{cwd:p,stdio:["inherit","inherit","inherit","ipc"],env:u});console.log(`child_spawn sup=${Ie} room=${r} pid=${g.pid} dir=${p} had_prior=${h}`),de.set(r,g),fe.delete(r),pe.set(r,!1),ue.set(r,!1),me.set(r,!1),g.on("message",e=>{if(e)if("room-ready"===e.t)fe.add(r),console.log(`child_ready sup=${Ie} room=${r} pid=${g.pid}`),je();else if("idle"===e.t)pe.set(r,!!e.idle),ue.set(r,null!=e.between?!!e.between:!!e.idle),me.set(r,!!e.webPeer),_r();else if("busy"===e.t)pe.set(r,!1),ue.set(r,!1);else if("capacity-acquire"===e.t){const t=le.acquire({room:r,terminalId:e.terminalId});try{g.send({t:"capacity-acquire-result",reqId:e.reqId,...t})}catch{t.ok&&le.release({room:r,terminalId:e.terminalId})}}else if("capacity-release"===e.t){if(le.release({room:r,terminalId:e.terminalId}))for(const e of de.values())try{e.send({t:"capacity-changed"})}catch{}}else if("restart-probe-result"===e.t){const t=$e.get(e.nonce);if(!t||!t.pending.has(r)||de.get(r)!==g)return;t.pending.delete(r),t.ok=t.ok&&!0===e.between,ue.set(r,!0===e.between),t.pending.size||(clearTimeout(t.timer),$e.delete(e.nonce),t.resolve(t.ok))}else if("apply-update"===e.t)_e=!0,_r();else if("pair-list-req"===e.t)(async()=>{if("1"===process.env.TP_CROSSROOM_OFF){try{g.send({t:"pair-list-res",reqId:e.reqId,rooms:[],error:"Cross-session reach is turned off on this bridge."})}catch{}return}const t=[...de.keys()].filter(e=>e!==r).map(e=>({code:e,name:he.get(e)||null}));let o=[],n=[];if("1"!==process.env.TP_PAIRBUS_OFF){const e=await Promise.all([ir(r),ge.size?sr("peer-list-req",{},1200):Promise.resolve([])]);o=e[0].rooms,n=e[1]}const s=B({authorized:o,replies:n,myUid:re.user.id,localCodes:de.keys()});try{g.send({t:"pair-list-res",reqId:e.reqId,rooms:[...t,...s]})}catch{}})();else if("pair-peek-req"===e.t)(async()=>{const o=r=>{try{g.send({t:"pair-peek-res",reqId:e.reqId,...r})}catch{}};if("1"===process.env.TP_CROSSROOM_OFF)return o({error:"Cross-session reach is turned off on this bridge."});const n=String(e.targetRoom||"").toUpperCase().trim();if(!n||n===r)return o({error:`${n||"That"} is not another of your active sessions.`});const s=de.get(n);if(s){const i=t();ye.set(i,{reply:e=>o({text:e.text,error:e.error}),askerRoom:r});try{s.send({t:"pair-peek-local",reqId:i,terminal:e.terminal,lines:e.lines})}catch{ye.delete(i),o({error:`Could not reach session ${n}.`})}return}if("1"===process.env.TP_PAIRBUS_OFF)return o({error:"Cross-session reach is turned off on this bridge."});const[i,a]=await Promise.all([ir(r),ge.size?sr("peer-list-req",{},800):Promise.resolve([])]);if(i.verified&&!i.rooms.some(e=>e?.code===n&&e?.owner_id!==re.user.id))return o({error:`Room ${n} is not shared with this pair.`});if(!ge.size)return o({error:i.verified?`Room ${n} is paired with you, but its host bridge is offline.`:`Session ${n} is not running on this machine, and no pair bus is open to reach it.`});if(!a.some(e=>e?.rooms?.some(e=>e?.code===n)))return o({error:`Room ${n} is paired with you, but its host bridge is offline.`});const c=await(d=n,l=e.terminal,p=e.lines,nr("peer-peek-req",{targetRoom:d,terminal:l,lines:p},M.busTimeoutMs));var d,l,p;if(!c)return o({error:`Room ${n} did not respond — it may be offline, or not shared with you.`});o({text:c.text,error:c.error})})();else if("pair-post-req"===e.t)(async()=>{const o=r=>{try{g.send({t:"pair-post-res",reqId:e.reqId,...r})}catch{}};if("1"===process.env.TP_PAIRBUS_OFF)return o({error:"Cross-room posting is turned off on this bridge."});const n=String(e.targetRoom||"").toUpperCase().trim();if(!n||n===r)return o({error:`${n||"That"} is not another of your sessions.`});const s=de.get(n);if(s){const i=t();ye.set(i,{reply:e=>o({ok:e.ok,ref:e.ref,error:e.error}),askerRoom:r});try{s.send({t:"pair-post-local",reqId:i,fromRoom:r,fromHost:Te,fromTerminalName:e.fromTerminalName,text:e.text,terminal:e.terminal})}catch{ye.delete(i),o({error:`Could not reach session ${n}.`})}return}const[i,a]=await Promise.all([ir(r),ge.size?sr("peer-list-req",{},1200):Promise.resolve([])]);if(i.verified&&!i.rooms.some(e=>e?.code===n&&e?.owner_id!==re.user.id))return o({error:`Room ${n} is not shared with this pair.`});if(!ge.size)return o({error:i.verified?`Room ${n} is paired with you, but its host bridge is offline.`:`Room ${n} is not on this machine, and no pair bus is open to reach it.`});if(!a.some(e=>e?.rooms?.some(e=>e?.code===n)))return o({error:`Room ${n} is paired with you, but its host bridge is offline — no recipient approval card can be raised yet.`});const c=await(d=n,l=e.terminal,p=e.text,u=r,m=e.fromTerminalName,nr("peer-post-req",{targetRoom:d,terminal:l,text:p,fromRoom:u,fromHost:Te,fromTerminalName:m},18e4));var d,l,p,u,m;if(!c)return o({error:`Room ${n} did not respond to the hand-off in time.`});o({ok:c.ok,ref:c.ref,error:c.error})})();else if("pair-peek-res"===e.t||"pair-post-res"===e.t){const r=ye.get(e.reqId);if(!r)return;ye.delete(e.reqId);try{r.reply(e)}catch{}}});const w=e=>{if(console.log(`child_exit sup=${Ie} room=${r} pid=${g?.pid||"?"} code=${e||"?"}`),de.delete(r),fe.delete(r),pe.delete(r),ue.delete(r),me.delete(r),he.delete(r),ve.delete(r),le.releaseRoom(r))for(const e of de.values())try{e.send({t:"capacity-changed"})}catch{}for(const[e,t]of ye)t?.askerRoom===r&&ye.delete(e)};if(g.on("exit",e=>w(e)),g.on("error",e=>{w();try{process.stderr.write(`\n ◇ ${r}: failed to launch its bridge (${e?.message||e}) — retrying next tick.\n`)}catch{}}),be)try{g.send({t:"update-available",version:be})}catch{}}if("1"!==process.env.TP_PAIRBUS_OFF)for(const e of r){if(!e?.code||!de.has(e.code))continue;const r=Array.isArray(e.participants)?e.participants:[],t=2===r.length?r.find(e=>e&&e!==re.user.id):null;if(!t){ve.delete(e.code);continue}ve.set(e.code,t);const o=N(re.user.id,t);o&&ar(t,o)}je()};await dr();const pr=setInterval(dr,15e3);Be=!0,ze(),c();const ur=[];let mr=!1,fr=0,hr=0,yr=!1;const vr=setInterval(async()=>{if(mr)return;const e=Date.now();if(!claimLoopWedged({lastClaimOkAt:Ze,now:e}))return fr=0,void(hr=0);if(yr||e<hr)return;yr=!0;const r=b(fr);hr=e+r,fr+=1,console.log(`claim_watchdog sup=${Ie} quiet_ms=${e-Ze} attempt=${fr} next_ms=${r} — reconnecting realtime + re-claiming`);try{ee.realtime?.connect?.()}catch{}cr=0;try{await rr(),je()}catch{}finally{yr=!1}},2e4);vr.unref?.();const gr=setInterval(()=>{if(mr)return;const e=Date.now(),r=w({claimHeld:Ve,lastClaimOkAt:Ze,now:e});let t=!1;try{t=!!xe.presenceState?.()[Te]}catch{t=!1}const o=_({tracking:r,subscribedAt:Math.max(He.subscribedAt,Ze),syncSeenAt:He.syncSeenAt,present:t,missingSince:Qe,now:e});if(Qe=o.missingSince,!Qe)return void(er=0);const n=o.verdict;if("recycle"===n){if(er===Qe)return;er=Qe,console.log(`presence_watchdog sup=${Ie} action=recycle missing_ms=${e-Qe} track=${Ee} — full realtime disconnect+reconnect`);try{ee.realtime?.disconnect?.()}catch{}try{ee.realtime?.connect?.()}catch{}try{je()}catch{}}else"respawn"===n&&(console.log(`presence_watchdog sup=${Ie} action=respawn missing_ms=${e-Qe} track=${Ee} — recycle failed, exiting for a clean supervisor respawn`),process.exit(1))},15e3);gr.unref?.();const wr=e=>{if(mr)return;mr=!0;const r=Pe?1:0;console.log(`supervisor_stop sup=${Ie} reason=${e||"unknown"} restarting=${Pe} children=${de.size}`),clearInterval(pr),clearInterval(vr),clearInterval(gr);for(const e of ur)try{clearInterval(e)}catch{}Je.cancel(),K({pid:process.pid}),releaseSingleton();for(const r of de.values())try{r.kill(e||"SIGTERM")}catch{}tr.close();for(const{channel:e}of ge.values())try{ee.removeChannel(e)}catch{}(async()=>{try{Ve&&await ee.rpc("release_bridge",{p_bridge_id:Ae})}catch{}try{await xe.untrack()}catch{}try{await ee.removeChannel(Ce)}catch{}try{await ee.removeChannel(xe)}catch{}process.exit(r)})(),setTimeout(()=>process.exit(r),1500)};for(const e of["SIGINT","SIGTERM","SIGHUP"])process.on(e,()=>wr(e));async function _r(){if(!ke&&v({pendingUpdate:be,stopping:mr,childIdle:pe,childBetween:ue,childPeer:me,requested:_e})){if(ke=!0,!await function(e=2500){const r=[...de.entries()];if(!r.length)return Promise.resolve(!0);const o=t();return new Promise(t=>{const n={pending:new Set(r.map(([e])=>e)),ok:!0,resolve:t,timer:null};n.timer=setTimeout(()=>{$e.delete(o),t(!1)},e),n.timer.unref?.(),$e.set(o,n);for(const[e,t]of r)try{t.send({t:"restart-probe",nonce:o})}catch{n.pending.delete(e),n.ok=!1}n.pending.size||(clearTimeout(n.timer),$e.delete(o),t(n.ok))})}())return ke=!1,void process.stderr.write("\n ◆ bridge update still queued — an agent became active before the restart boundary.\n");process.stderr.write(`\n ◆ thinkpool-pair ${be} ready (running ${Z}) — restarting account bridge to update; sessions resume.\n`);try{const e=await import("./service.mjs");if(e.serviceActive(null)&&!1!==e.applyStagedServiceUpdate(null,be))return}catch{}if(ke=!1,Pe=!0,!ie())try{e(process.execPath,[process.argv[1]],{detached:!0,stdio:"ignore",env:process.env}).unref()}catch{}wr("SIGTERM")}}if("1"===process.env.THINKPOOL_PAIR_AUTOUPDATE&&Z){const e=1e3*Math.max(60,parseInt(process.env.THINKPOOL_PAIR_UPDATE_INTERVAL,10)||1800),r=(e,r)=>{const t=e=>String(e).split("-")[0].split(".").map(e=>parseInt(e,10)||0),o=t(e),n=t(r);for(let e=0;e<3;e++){if((o[e]||0)>(n[e]||0))return!0;if((o[e]||0)<(n[e]||0))return!1}return!1},t=async()=>{const e=new AbortController,r=setTimeout(()=>e.abort(),8e3);try{const r=await fetch("https://registry.npmjs.org/thinkpool-pair/latest",{signal:e.signal,headers:{accept:"application/json"}});if(!r.ok)return null;const t=await r.json();return"string"==typeof t?.version?t.version:null}catch{return null}finally{clearTimeout(r)}},o=async()=>{const e=await t();if(e&&r(e,Z)){be||process.stderr.write(`\n ◆ thinkpool-pair ${e} published — "update ready" surfaced to each room; applies between turns.\n`);try{(await import("./service.mjs")).provisionRuntime(e)}catch(r){return void process.stderr.write(`\n ⚠ bridge ${e} could not be staged yet: ${r?.message||r}\n`)}be=e;for(const r of de.values())try{r.send({t:"update-available",version:e})}catch{}_r()}};ur.push(setInterval(o,e).unref()),ur.push(setInterval(_r,15e3).unref()),ur.push(setTimeout(o,6e4).unref())}await new Promise(()=>{})}
|
package/bridge.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import e from"node:os";import t from"node:fs";import r from"node:path";import o from"node:readline";import{spawn as n,execFileSync as s}from"node:child_process";import{fileURLToPath as i}from"node:url";import{createRequire as a}from"node:module";import{randomUUID as c}from"node:crypto";import{createClient as l}from"@supabase/supabase-js";import{serveDecision as d,fetchServeRow as u,refusalMessage as m,gateFailAction as p}from"./serve-consent.mjs";import{reapTerminalRow as h}from"./reap-terminal.mjs";import{reconcileTerminalRows as f}from"./terminal-row-reconcile.mjs";import{cancelDurableDispatchPermissions as w,cancelDurablePermissions as g}from"./dispatch-permission-cleanup.mjs";import{createPermNotifier as v,shouldNotifyTurnDone as y,shouldRecordTurnDone as k,permissionSummary as b,clipSummary as $,isUserFacingLane as T,DEFAULT_MIN_TURN_MS as R}from"./agent-notify.mjs";import{resolveProviderEnv as S,resolveProviderRef as I,resolveProviderResiliencePolicy as C,providerNameMap as x,publicKeyB64 as _,bridgeHostId as A,announceProviders as P,listProviders as N,effectiveLaneModel as O,sameProviderEnv as E,providerModel as j}from"./providers.mjs";import{createMemoryCircuit as D,providerResilienceCapAdmission as F}from"./provider-resilience.mjs";import{validateProviderSwitch as q,providerSwitchPlan as K,BUILTIN_PROVIDER as M}from"./switch-provider.mjs";import{createSdkMcpServer as U,tool as B}from"@anthropic-ai/claude-agent-sdk";import{z as L}from"zod";import{readCodexDefaultModel as W,readCodexModels as H,codexConfigForMode as z,codexThreadCanResume as J}from"./codex-session.mjs";import{codexAccountUsageLine as G,codexCreditsReportLine as Y,codexLimitReportLine as V}from"./codex-commands.mjs";import{withMcpSessionFactory as Q}from"./codex-mcp-http.mjs";import{startStructuredSession as X}from"./runtime-session.mjs";import{admitRuntimeCapability as Z}from"./runtime-contract.mjs";import{cleanTerminalName as ee,modelTerminalNameInput as te}from"./terminal-name.mjs";import{defaultStructuredMode as re,normalizeStructuredEffort as oe,shouldDeferStructuredRuntime as ne,structuredModeForSlice as se,structuredModeLocked as ie,structuredModesForLane as ae,structuredRuntimeForCommand as ce,structuredRuntimeMetadata as le,structuredRuntimeSupportsMode as de}from"./runtime-registry.mjs";import{commandCatalogForRuntime as ue,commandHelpLine as me,reconcileCommandCatalog as pe}from"./command-catalog.mjs";import{gitDiffReport as he}from"./git-diff-report.mjs";import{repoSearch as fe}from"./repo-search.mjs";import{probeHermesRuntime as we}from"./hermes-probe.mjs";import{hermesRequiredMcpTools as ge,hermesRoleFor as ve}from"./hermes-policy.mjs";import{canonicalRoomFilePath as ye,waitForNativeImages as ke}from"./codex-images.mjs";import{createManagedLaneWorktree as be,removeManagedLaneWorktree as $e}from"./lane-worktree.mjs";import{commandOnPath as Te}from"./agent-detect.mjs";import{agentVisibilityStates as Re}from"./agent-visibility.mjs";import{requiresSdkAdmission as Se,sdkSmokePassed as Ie}from"./sdk-admission.mjs";import{hermesUserInputResponse as Ce}from"./question-response.mjs";import{hostMemoryAdmission as xe}from"./host-memory.mjs";import{admitAbortRequest as _e,queueAbortBarrier as Ae,takePendingAbortRequest as Pe,waitForAbortBarrier as Ne}from"./abort-turn-barrier.mjs";import{PAIR_CLI as Oe,pairCli as Ee}from"./command-guidance.mjs";import{explicitKeepAwakeChoice as je,keepAwakeEnabled as De,saveKeepAwakePreference as Fe,startKeepAwake as qe}from"./keep-awake.mjs";const Ke=new Set(["default","acceptEdits","plan","review","bypassPermissions"]);import{FLOW_CONDUCTOR_PROMPT as Me,FLOW_LANE_PROMPT as Ue,FLOW_CODEX_CONDUCTOR_PROMPT as Be,FLOW_CODEX_LANE_PROMPT as Le,buildConductorEnv as We,assembleCrossWaveContext as He,buildLanePrompt as ze}from"./flow-conductor.mjs";import{legacyBuilderCompletionAllowed as Je,normalizeBaselineEvidence as Ge,normalizePlanOutput as Ye,validatePlanForRuntime as Ve,validateTaskContractSeal as Qe,validReviewTargetShape as Xe}from"./flow-task-graph.mjs";import{normalizeFlowRuntime as Ze,flowLaneModelFor as et,flowConductorModelFor as tt,spawnedLaneModelFor as rt,modelCatalogValues as ot,resolveCodexModel as nt,resolveHermesOpenModel as st,assertRuntimeModelCompatible as it}from"./flow-models.mjs";import{writeLaneArtifact as at,digestSlice as ct,appendDigest as lt,resumeLane as dt}from"./flow-context-store.mjs";import{createFlowWorktree as ut,worktreeSpec as mt}from"./flow-worktree.mjs";import{startPreview as pt,stopAllPreviews as ht,previews as ft}from"./flow-preview.mjs";import{ViewportManager as wt,createViewportTools as gt,sharedViewportBrowser as vt}from"./viewport.mjs";import{deleteDesignAssetDraft as yt,designPrompt as kt,designTranscript as bt,materializeDesignAsset as $t,refreshDesignSource as Tt,resolveManifestDesignSource as Rt,resolveManifestDisplaySource as St,restoreDesignSources as It,syncRealtimeAuth as Ct,validateDesignBatchRequest as xt}from"./design-edit.mjs";function _t(e,t=null){for(const[r,o]of ft)if("string"==typeof r&&(t?r===`lane:${e}:${t}`:r.startsWith(`lane:${e}:`)))try{o.stop()}catch{}}import{FLOW_REVIEWER_PROMPT as At,FLOW_CODEX_REVIEWER_PROMPT as Pt,revertLane as Nt,parseReviewVerdict as Ot,reviewVerdictToReflection as Et}from"./flow-review.mjs";import{createFlowReviewReceipt as jt,createFlowReviewSingleFlight as Dt,isFlowReviewReceipt as Ft}from"./flow-receipt.mjs";import{collectFlowScopeEvidence as qt,normalizeFlowScopeEvidence as Kt}from"./flow-scope-evidence.mjs";import{formatPastWorkSearch as Mt,searchPastWork as Ut}from"./past-work-search.mjs";import{reviewGateDecision as Bt}from"./flow-review-gate.mjs";import{IMMUTABLE_REVIEW_READ_TOOL_EXTRAS as Lt,UNSANDBOXED_REVIEW_CHECK_TOOL_EXTRAS as Wt,readReviewFile as Ht,runReviewCheck as zt}from"./review-check.mjs";import{pairAdjudicationPrompt as Jt,reviewReflectionDecision as Gt,REVIEW_DEFAULTS as Yt}from"./flow-review-reflect.mjs";import{mergeWorktrees as Vt,inlineSingleHtml as Qt,initRepo as Xt}from"./flow-assembly.mjs";import{canDispatch as Zt,makeBudget as er,recordSpend as tr,killSwitchEnv as rr}from"./flow-budget.mjs";import{prepareRedispatch as or,redispatchKey as nr}from"./flow-redispatch.mjs";import{sanitizeSession as sr}from"./transcript-sanitize.mjs";import{boundStructuredLog as ir,STRUCTURED_LOG_BYTE_CAP as ar}from"./event-bounds.mjs";import{executeFlowRevert as cr}from"./flow-host-revert.mjs";const lr=new Map,dr=new Map,ur=(e,t,r)=>{if(!e||!t||!r)return null;try{return s("git",["-C",e,"diff","--name-only","--diff-filter=ACMRD",`${t}..${r}`],{encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]}).split("\n").map(e=>e.trim()).filter(Boolean)}catch{return null}};import{formatPeek as mr,PEEK as pr,readTerminalTurnBudgetDecision as hr,siblingsOf as fr,resolveSibling as wr,crossPostDecision as gr,CROSSPOST as vr,spawnDecision as yr,SPAWN as kr,CROSSROOM as br,CROSSROOM_BUS as $r,formatPairRoster as Tr,crossRoomPostDecision as Rr,formatRoomNow as Sr,formatClosableHint as Ir,closeLaneDecision as Cr,laneBusyOf as xr,laneStatusOf as _r,settleLaneBusy as Ar,settleLaneControl as Pr,nativeClaudeFallbackHint as Nr,buildDispatchPreview as Or,authorizeDirectDispatch as Er,activeWorkerCapacityDecision as jr,machineCapacityDecision as Dr,countActiveDispatchedWorkers as Fr,maxSpawnedFor as qr}from"./cross-terminal.mjs";import{createStandalonePairResponder as Kr,standalonePairIdentity as Mr}from"./direct-pair-room.mjs";import{dispatchPendingRecap as Ur,recoverInterruptedTurn as Br,recoverMissingResumeOnce as Lr,sendInterruptedContinue as Wr,shouldAttemptNativeResume as Hr,supersedeInterruptedResume as zr}from"./interrupted-resume.mjs";import{supersedeDispatchLease as Jr}from"./dispatch-lease.mjs";import{realtimeRecoveryDecision as Gr,turnInFlight as Yr}from"./update-gate.mjs";import{saveSession as Vr,flushSession as Qr,deleteSession as Xr,loadAll as Zr,loadArchived as eo,canResume as to,loadPtyId as ro,savePtyId as oo,loadNames as no,saveNames as so,appendDurableEvents as io,seedDurableEvents as ao,readDurablePage as co,readDurableOldestSeq as lo,hasDurableArchive as uo,servesHistoryPage as mo,acknowledgePendingScheduledOutcome as po,commitRecordedScheduledOutcome as ho,deletePendingScheduledOutcome as fo,loadPendingScheduledOutcome as wo,loadPendingScheduledOutcomes as go,savePendingScheduledOutcome as vo}from"./session-store.mjs";import{stampEvent as yo,makeSeqCounter as ko,maxSeq as bo,seqable as $o,capReplayEvents as To,chunkReplayEvents as Ro,boundEventForBroadcast as So,inlineImageBlocks as Io,ImageEventQueue as Co,imageQueueConfig as xo,uploadCodeImage as _o,usageReportLine as Ao,codexUsageReportLine as Po,appendCurrentPersonRequest as No,buildCheckpointFromLog as Oo,buildRecapFromLog as Eo,resolveCheckpointCarry as jo,RECAP_CAP as Do,trimmedBeforeSeq as Fo,firstSeq as qo}from"./event-id.mjs";import{createLatestReplayPump as Ko,requestedReplayIds as Mo}from"./replay-transport.mjs";import{createEventDeliveryQueue as Uo}from"./event-delivery-queue.mjs";import{formatMcpFlight as Bo,normalizeMcpFlight as Lo,recordMcpFlightEvent as Wo}from"./mcp-flight-recorder.mjs";import{classifyCodeEvent as Ho,unknownCodeEventNotice as zo}from"./code-event-contract.mjs";import{fetchPairControlDeliveryAuthority as Jo}from"./pair-control-authority.mjs";import{finishScheduledRunWithRetry as Go,pollDueScheduledRuns as Yo,sanitizeScheduledOutcomeIntent as Vo,scheduledOutcomeReconciliationComplete as Qo,scheduledRunDeadlineRequired as Xo,scheduledRunSpawnAdmission as Zo,scheduledRunsCapability as en,scheduledRunsEnabled as tn}from"./scheduled-runs.mjs";import{acquireScheduledRunAdmission as rn,releaseScheduledRunAdmission as on}from"./scheduled-run-admission.mjs";import{SIDE_HANDOFF_PROMPT as nn,SIDE_ROLE_PROMPT as sn,appendSideContext as an,assistantTextSince as cn,dispatchSideContexts as ln,sideContextBlock as dn,sideSnapshot as un}from"./side-lane.mjs";import{acknowledgeWorkerCompletions as mn,enqueueWorkerCompletion as pn,workerCompletionPrompt as hn,workerCompletionRecord as fn}from"./worker-completion.mjs";import{planMeterLine as wn}from"./plan-meters.mjs";import{priceForModel as gn}from"./model-prices.mjs";import{loadHermesModelCache as vn,saveHermesModelCache as yn}from"./hermes-model-cache.mjs";import{makeThrottledTrack as kn,recoveryBackoffMs as bn}from"./presence.mjs";import{MockupDeliveryQueue as $n,completeMockupManifest as Tn,isMockupDeliveryBoundary as Rn}from"./mockup-delivery.mjs";import{resolveAnonKey as Sn,DEFAULT_SUPABASE_URL as In}from"./supabase-key.mjs";import{buildTerminalRolePrompt as Cn,HERMES_VISIBLE_WORKER_FALLBACK_RULE as xn,THINKPOOL_PROMPT_BUNDLE as _n}from"./thinkpool-room-prompt.mjs";const An=process.env.TP_SUPABASE_URL||In,Pn=process.env.TP_WEB_BASE||"https://thinkpool.io",Nn=xo();let On=vn();const{key:En,source:jn}=await Sn({supabaseUrl:An,webBase:Pn,log:e=>{process.env.TP_DEBUG&&console.error(` ◇ ${e}`)}});process.env.TP_DEBUG&&console.error(` ◇ supabase anon key source: ${jn}`);let Dn=process.env.TP_ACCESS_TOKEN||null,Fn=null;try{Fn=(await import("node-pty")).default??await import("node-pty")}catch{console.error("\n ⚠ node-pty not built — raw terminal sharing is off (structured Claude still works).\n For PTY mode (bash / aider / codex / TP_PTY=1): install a C toolchain, then `npm i` in the bridge.\n (Xcode CLT on mac · build-essential on linux · VS Build Tools on Windows.)\n")}const qn=[{label:"Claude Code",cmd:"claude",resume:{args:["--continue"],probe:function(){try{const o=r.resolve(process.cwd()).replace(/[/\\.:]/g,"-");return t.readdirSync(r.join(e.homedir(),".claude","projects",o)).length>0}catch{return!1}}}},{label:"Codex CLI",cmd:"codex"},{label:"Hermes Agent",cmd:"thinkpool",availability:()=>we().available},{label:"Gemini CLI",cmd:"gemini"},{label:"Aider",cmd:"aider"},{label:"Cursor CLI",cmd:"cursor-agent"},{label:"opencode",cmd:"opencode"},{label:"Copilot CLI",cmd:"copilot"},{label:"Goose",cmd:"goose"},{label:"Crush",cmd:"crush"},{label:"Qwen Code",cmd:"qwen"}],Kn=process.argv.slice(2);if("install-service"===Kn[0]||"restart-service"===Kn[0]){const e=je(Kn);null===e||Fe(e)||(process.stderr.write(" ⚠ could not save the keep-awake setting; service left unchanged.\n"),process.exit(1))}if("privacy-report"===Kn[0]){const{runPrivacyReport:e}=await import("./privacy-report.mjs");e(),process.exit(0)}if("install-service"===Kn[0]||"uninstall-service"===Kn[0]){const e=Kn[1]||"",t=!e||e.startsWith("-")?null:e.toUpperCase().trim(),r=Kn.indexOf("--"),o=r>=0?Kn.slice(r+1):[],n=Kn.includes("--auto-update"),s=await import("./service.mjs");if("install-service"===Kn[0]){const e=n?s.installService(t,o,{autoUpdate:n}):await s.installAndConfirmService(t,o);process.exit(!1===e?1:0)}else s.uninstallService(t);process.exit(0)}if("restart-service"===Kn[0]){const e=Kn[1]||"",t=!e||e.startsWith("-")?null:e.toUpperCase().trim(),r=await import("./service.mjs"),o=Kn.includes("--current")?r.restartService(t):await r.updateAndConfirmService(t);process.exit(o?0:1)}const{applyProviderEnv:Mn}=await import("./provider.mjs"),Un=Mn();if("login"===Kn[0]){const{runLogin:e}=await import("./account.mjs");await e(An,En,Pn)}if("bind"===Kn[0]){const{runBind:e}=await import("./account.mjs");e(Kn[1],Kn[2])}if("set-default-dir"===Kn[0]){const{saveDefaultDir:t}=await import("./auth-store.mjs");let r=(Kn[1]||"").trim();r.startsWith("~")&&(r=r.replace(/^~/,e.homedir())),r||(console.error(` usage: ${Ee("set-default-dir","<dir>")}`),process.exit(1)),t(r),console.log(` ◆ default project dir set → ${r}\n New/unbound sessions auto-serve from here — no per-session bind. Takes effect next serve tick.`),process.exit(0)}if("provider"===Kn[0]){const{runProvider:e}=await import("./provider.mjs");await e(Kn.slice(1)),process.exit(0)}if("setup-hermes"===Kn[0]){const e=Kn.includes("--clone"),t=Kn.includes("--clean");e&&t&&(console.error(" choose one Hermes setup mode: --clone or --clean"),process.exit(1));let r=e?"clone":t?"clean":void 0;if(!r&&process.stdin.isTTY){const e=await new Promise(e=>{const t=o.createInterface({input:process.stdin,output:process.stderr});t.question("\n Clone your active Hermes provider/config into an isolated thinkpool profile? [Y/n] ",r=>{t.close(),e(String(r).trim())})});r=/^n/i.test(e)?"clean":"clone"}try{const{setupHermesRuntime:e}=await import("./hermes-setup.mjs"),t=e({mode:r});process.stderr.write(`\n ◆ Hermes ${t.version||""} is ready for thinkpool ordinary lanes.\n profile: ${t.profile} (${t.created?`${t.mode} created`:"existing"})\n hidden delegation: blocked\n${t.created&&"clean"===t.mode?" provider: run `thinkpool setup` before the first model turn\n":""}\n`),process.exit(0)}catch(e){console.error(`\n ◇ Hermes setup failed: ${e?.message||e}\n New profile: npx thinkpool-pair@latest setup-hermes --clone\n Clean profile: npx thinkpool-pair@latest setup-hermes --clean\n`),process.exit(1)}}if("verify-hermes-isolation"===Kn[0])try{const{verifyHermesMcpIsolation:e}=await import("./hermes-isolation.mjs"),t=await e({rounds:2});process.stderr.write(`\n ◆ Hermes MCP isolation HELD for ${t.length} consecutive two-lane rounds.\n Each ACP session advertised only its lane-bound marker endpoint.\n No model inference was used.\n\n`),process.exit(0)}catch(e){console.error(`\n ◇ Hermes MCP isolation VIOLATED or unproven: ${e?.message||e}\n`),process.exit(1)}if((!Kn[0]||"setup"===Kn[0])&&process.stdin.isTTY){const{runLauncher:e,detectState:t}=await import("./launcher.mjs"),r=await import("./service.mjs"),s=i(import.meta.url),a={print:e=>process.stderr.write(e+"\n"),ask:e=>new Promise(t=>{const r=o.createInterface({input:process.stdin,output:process.stderr});r.question(e,e=>{r.close(),t(String(e).trim())})})},c={pairRoom:({room:e,agentCmd:t,resumeArgs:r=[],headless:o})=>new Promise(()=>{const i=[s,e,...o?["--headless"]:[],"--",t,...r];n(process.execPath,i,{stdio:"inherit"}).on("exit",e=>process.exit(null==e?0:e))}),serveAccountForeground:async()=>{qe({enabled:De([])});const{runAccount:e}=await import("./account.mjs");await e(An,En)},installService:({room:e=null,agentCmd:t}={})=>r.installAndConfirmService(e,t?[t]:[]),uninstallService:({room:e=null}={})=>{r.uninstallService(e)},restartService:({room:e=null}={})=>{r.restartService(e)},restartUpdateService:async({room:e=null}={})=>"win32"===process.platform?r.updateService(e):r.updateAndConfirmService(e),relaunchLauncher:async()=>{const e=r.serviceRuntimeVersion(null);if(!e)return a.print("\n ⚠ the managed runtime was confirmed earlier but could not be resolved for launcher handoff; staying in this launcher."),!1;let t="";try{t=r.provisionRuntime(e)}catch(t){return a.print(`\n ⚠ could not open the verified v${e} launcher: ${t?.message||t}`),!1}return new Promise(e=>{const r=n(process.execPath,[t],{stdio:"inherit",cwd:process.cwd(),env:process.env});r.once("error",t=>{a.print(`\n ⚠ launcher handoff failed: ${t?.message||t}`),e(!1)}),r.once("exit",()=>e(!0))})},login:async()=>{const{runLogin:e}=await import("./account.mjs");await e(An,En,Pn)},setProvider:async({kind:e,base:t,token:r,model:o})=>{const{runProvider:n}=await import("./provider.mjs"),s="custom"===e?["custom","--base",t,"--token",r,...o?["--model",o]:[]]:["anthropic"];await n(s)},setKeepAwake:async({enabled:e})=>Fe(e)?(r.isServiceInstalled(null)&&r.restartService(null),!0):(a.print("\n ⚠ could not save the keep-awake setting; nothing was changed."),!1),setupHermes:async({mode:e})=>{const{setupHermesRuntime:t}=await import("./hermes-setup.mjs"),r=t({mode:e});a.print(`\n ✓ Hermes ${r.version||""} ready — isolated profile, ACP healthy, hidden delegation blocked.`),r.created&&"clean"===r.mode&&a.print(" Run `thinkpool setup` once to choose a provider before the first model turn.")}};await e({actions:c,io:a,refresh:t}),process.exit(0)}const Bn=process.env.TP_SDK_SMOKE_PATH||r.join(r.dirname(i(import.meta.url)),"sdk-smoke.mjs");let Ln={ok:null,version:"unknown",reason:""};function Wn(){try{const e=a(import.meta.url);let o=r.dirname(e.resolve("@anthropic-ai/claude-agent-sdk"));for(let e=0;e<8;e++){try{const e=JSON.parse(t.readFileSync(r.join(o,"package.json"),"utf8"));if("@anthropic-ai/claude-agent-sdk"===e.name)return e.version}catch{}const e=r.dirname(o);if(e===o)break;o=e}}catch{}return"unknown"}function Hn(){try{return s(process.execPath,[Bn],{encoding:"utf8",timeout:22e3,stdio:["ignore","pipe","ignore"]}).trim()}catch(e){return(e.stdout||"").toString().trim()||`SMOKE:FAIL:${Wn()}:${"ETIMEDOUT"===e.code?"timeout":(e.message||"run error").slice(0,80)}`}}if("verify-sdk"===Kn[0]){const e=Hn();console.log(e),process.exit(Ie(e)?0:1)}if(!Kn[0]||Kn[0].startsWith("-")){qe({enabled:De(Kn)});const{runAccount:e}=await import("./account.mjs");await e(An,En)}const zn=(Kn[0]||"").toUpperCase().trim();zn||(console.error(`usage: ${Ee("<ROOM>","[--headless]","[--continue|--fresh]","[-- <command…>]")} | ${Oe} (account mode)`),process.exit(1)),/^[A-Z0-9_-]{2,32}$/.test(zn)||(console.error(`refused: invalid room code ${JSON.stringify(zn)} (expected 2–32 alphanumerics, dash, or underscore)`),process.exit(1)),Se(Kn)&&(function(){const o=r.join(e.homedir(),".thinkpool-pair"),n=r.join(o,"sdk-ok"),s=Wn();Ln.version=s;let i="";try{i=t.readFileSync(n,"utf8").trim()}catch{}if(i&&i===s)return void(Ln.ok=!0);const a=Hn().match(/^SMOKE:(PASS|FAIL):([^:\n]*)(?::(.*))?$/m);if(a&&"PASS"===a[1]){Ln={ok:!0,version:a[2]||s,reason:""};try{t.mkdirSync(o,{recursive:!0}),t.writeFileSync(n,Ln.version)}catch{}process.stderr.write(`\n ◆ agent SDK v${Ln.version} passed the compatibility smoke test.\n`)}else{Ln={ok:!1,version:a&&a[2]||s,reason:a&&a[3]||"unknown"};try{t.mkdirSync(o,{recursive:!0}),t.writeFileSync(r.join(o,"sdk-bad"),`${Ln.version}: ${Ln.reason}`)}catch{}process.stderr.write(`\n ⛔ agent SDK v${Ln.version} FAILED the compatibility smoke test — ${Ln.reason}.\n ⛔ refusing to serve agent turns. Repair or pin a known-good SDK, then restart.\n`)}}(),Ln.ok||process.exit(1));const Jn=Kn.indexOf("--"),Gn=Jn>=0?Kn.slice(0,Jn):Kn;if(Gn.includes("--supervise")||Gn.includes("--keep-alive")){const e=process.argv.slice(1).filter(e=>"--supervise"!==e&&"--keep-alive"!==e);let t=1e3,r=!1,o=null;const s=()=>{const i=Date.now();o=n(process.execPath,e,{stdio:"inherit"}),o.on("exit",(e,o)=>{(r||0===e)&&process.exit(e||0);const n=Date.now()-i>6e4,a=n?1e3:t;t=n?1e3:Math.min(2*t,3e4),process.stderr.write(`\n ⚠ bridge exited (${o||`code ${e}`}); restarting in ${Math.round(a/1e3)}s…\n`),setTimeout(s,a)}),o.on("error",()=>{})};for(const e of["SIGINT","SIGTERM"])process.on(e,()=>{r=!0;try{o?.kill(e)}catch{}setTimeout(()=>process.exit(0),400)});process.stderr.write(`\n [b:${ds} r:${zn}] ◆ supervisor up — keeping the bridge for room ${zn} alive (auto-restart on crash).\n`),s(),await new Promise(()=>{})}{const{acquireMachineLock:e,releaseMachineLock:t,shouldHoldMachineLock:r}=await import("./account.mjs");r(process.env)&&!e()&&(console.error("\n ◇ A thinkpool-pair bridge is already running on this machine\n (~/.thinkpool-pair/account.lock). Only one can be active, and the running\n one already serves every room you are in — use it, or stop it first.\n (If you are certain none is running, delete that stale lock file.)\n"),process.exit(0)),r(process.env)&&process.on("exit",()=>{try{t()}catch{}})}qe({enabled:De(Kn)});const Yn=Kn.includes("--headless"),Vn=(Kn.find(e=>e.startsWith("--auto="))||"").slice(7)||null,Qn=("1"===process.env.TP_STRUCTURED||Kn.includes("--structured"),ce),Xn=e=>!!Qn(e)&&"1"!==process.env.TP_PTY,Zn=qn.filter(e=>{return t=e.cmd,Te(t)&&(!e.availability||e.availability());var t}),es=Kn.indexOf("--"),ts=es>=0?Kn.slice(0,es):Kn,rs=ts.includes("--continue"),os=ts.includes("--fresh"),ns=(e,t=!0)=>new Promise(r=>{const n=o.createInterface({input:process.stdin,output:process.stderr});n.question(e,e=>{n.close();const o=String(e).trim();r(t?!/^n/i.test(o):/^y/i.test(o))})});let ss=null,is=[],as=!1;if(es>=0)[ss,...is]=Kn.slice(es+1),ss&&ss.startsWith("-")&&(process.stderr.write(`\n ◇ ignoring "${ss}" after \`--\` — that's a flag, not a command to share.\n`),ss=null,is=[]);else if(!Yn){0===Zn.length&&(console.error(`\n No known coding-agent CLI found on your PATH.\n Install one (claude / codex / gemini / aider / cursor-agent / opencode …)\n or share a specific command: ${Ee(zn,"--","<your-command>")}\n`),process.exit(1)),ss=await(cs=Zn,new Promise(e=>{if(1===cs.length||!process.stdin.isTTY)return void e(cs[0].cmd);const t=o.createInterface({input:process.stdin,output:process.stderr});process.stderr.write("\n Which coding agent do you want to share?\n\n"),cs.forEach((e,t)=>process.stderr.write(` ${t+1}) ${e.label}\n`)),process.stderr.write("\n"),t.question(" Pick a number [1]: ",r=>{t.close();const o=parseInt(String(r).trim(),10),n=Number.isInteger(o)&&o>=1&&o<=cs.length?o-1:0;e(cs[n].cmd)})}));const e=qn.find(e=>e.cmd===ss);e?.resume&&!os&&(rs?as=!0:process.stdin.isTTY&&e.resume.probe()&&(as=await ns(`\n Continue your latest ${e.label} session in this directory? [Y/n] `)),as&&(is=[...e.resume.args]))}var cs;if(process.stdin.isTTY&&!Yn&&"1"!==process.env.THINKPOOL_PAIR_AUTOUPDATE){const o=await import("./service.mjs");o.isServiceInstalled(zn)&&(process.stderr.write(`\n ◆ a background service is already running room ${zn} (auto-updating).\n ◆ remove it with: npx thinkpool-pair@latest uninstall-service ${zn}\n\n`),process.exit(0));const n=r.join(e.homedir(),".thinkpool-pair",`${zn}.svc-declined`);let s=!1;try{s=t.existsSync(n)}catch{}if(!s){await ns("\n Run as a background service instead? It survives reboot + auto-updates,\n but runs detached — you'd stop it with 'uninstall-service', not Ctrl-C.\n Install background service? [y/N] ",!1)&&(o.installService(zn,ss?[ss,...is]:[]),process.stderr.write(`\n [b:${ds} r:${zn}] ◆ the background service is handling room ${zn} now — you can close this terminal.\n ◆ STOP IT with: npx thinkpool-pair@latest uninstall-service ${zn}\n (closing the terminal does NOT stop it — it's detached under launchd/systemd.)\n\n`),process.exit(0));try{t.mkdirSync(r.dirname(n),{recursive:!0}),t.writeFileSync(n,(new Date).toISOString())}catch{}process.stderr.write(` [b:${ds} r:${zn}] ◆ running in this terminal. (Auto-update service anytime: npx thinkpool-pair@latest install-service ${zn})\n`)}}const ls=process.env.TP_NAME||e.userInfo().username||"host",ds=c?.().slice(0,8)||"bridgexx",us=process.env.TP_ACCOUNT_BRIDGE_ID||null,ms=Number.parseInt(process.env.TP_ACCOUNT_BRIDGE_FENCING||"",10),ps=Date.now(),hs=(e.hostname()||"host").split(".")[0].slice(0,24),fs=A(),ws=D(),gs=process.cwd(),vs=r.basename(gs);let ys=null;try{ys=JSON.parse(t.readFileSync(new URL("./package.json",import.meta.url),"utf8")).version}catch{}try{const o=r.join(e.homedir(),".npm","_npx"),n=t.readdirSync(o,{withFileTypes:!0}).filter(e=>e.isDirectory()).map(e=>e.name).filter(e=>"cache"!==e),s=e=>e?e.split(".").map(e=>parseInt(e,10)||0):[0,0,0],i=(e,t)=>{const r=s(e),o=s(t);for(let e=0;e<3;e++){if(r[e]<o[e])return!0;if(r[e]>o[e])return!1}return!1};let a=null;for(const e of n){const n=r.join(o,e,"node_modules","thinkpool-pair","package.json");try{const e=JSON.parse(t.readFileSync(n,"utf8"));e.version&&(a&&!i(a,e.version)||(a=e.version))}catch{}}a&&ys&&i(ys,a)&&process.stderr.write(` ⚠ stale-cache: running ${ys}, newest ${a}\n`)}catch{}function ks(){try{let e=r.join(gs,".git");t.statSync(e).isFile()&&(e=t.readFileSync(e,"utf8").replace(/^gitdir:\s*/i,"").trim());const o=t.readFileSync(r.join(e,"HEAD"),"utf8").trim();return o.startsWith("ref:")?o.split("/").pop():o.slice(0,7)}catch{return null}}const bs=r.join(e.tmpdir(),"thinkpool-pair",zn),$s=l(An,En,{realtime:{params:{eventsPerSecond:60}}});let Ts="free";async function Rs(){const e=Dn;if(e)try{const{data:t,error:r}=await $s.auth.getUser(e),o=t?.user?.id;if(r||!o)return;const n=await fetch(`${An}/rest/v1/profiles?select=plan&id=eq.${o}`,{headers:{apikey:En,Authorization:`Bearer ${e}`}});if(!n.ok)return;const s=await n.json();s?.[0]?.plan&&(Ts="plus"===s[0].plan?"plus":"free")}catch{}}let Ss=null;{let e=!1;if(!Dn)try{const{loadAuth:t}=await import("./auth-store.mjs");Dn=t()?.access_token||null,Dn&&(e=!0)}catch{}if(e)try{const{authedClient:e}=await import("./account.mjs"),t=await e(An,En);t?.session?.access_token&&(Dn=t.session.access_token)}catch{}try{if(Dn){const{data:e}=await $s.auth.getUser(Dn);Ss=e?.user?.id||null}const{ownerId:e,name:t}=await u({supabaseUrl:An,anonKey:En,token:Dn,room:zn}),r=d({ownerId:e,myUid:Ss});r.serve||(process.stderr.write(m({room:zn,name:t,reason:r.reason})),process.exit(0))}catch(e){"refuse"===p(e)&&(process.stderr.write(m({room:zn,name:null,reason:"no-identity"})),process.stderr.write(`\n ◇ (serve-consent: auth rejected at the gate — ${e.message}; the stored login is expired or revoked. Re-run: ${Ee("login")})\n`),process.exit(0)),process.stderr.write(`\n ◇ serve-consent check degraded (${e.message}); proceeding without it.\n`)}}!await Ct($s,Dn,En)&&Dn&&process.stderr.write("\n ⚠ realtime auth could not be initialized; private bridge features are unavailable.\n"),Rs();const Is="1"===process.env.TP_BUDGET_OFF;async function Cs(e,t){const r=await fetch(`${An}/rest/v1/rpc/${e}`,{method:"POST",headers:{apikey:En,Authorization:`Bearer ${Dn}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!r.ok)throw new Error(`${e} ${r.status}`);const o=await r.text();return o?JSON.parse(o):null}const xs="1"===process.env.TP_AGENT_NOTIFY_OFF,_s=Number(process.env.TP_NOTIFY_MIN_TURN_MS)>0?Number(process.env.TP_NOTIFY_MIN_TURN_MS):R;function As(e){if(xs||!Dn||!Ss||!zn)return;const{eventId:t,...r}=e||{},o={id:`ae:${"string"==typeof t&&/^[A-Za-z0-9_-]{1,120}$/.test(t)?t:c()}`,session_code:zn,author_id:Ss,payload:{__agent:!0,ts:Date.now(),...r}};fetch(`${An}/rest/v1/code_messages`,{method:"POST",headers:{apikey:En,Authorization:`Bearer ${Dn}`,"Content-Type":"application/json",Prefer:"return=minimal"},body:JSON.stringify(o)}).then(e=>{!e.ok&&process.env.TP_DEBUG&&process.stderr.write(`\n ◆ agent-event insert ${e.status}\n`)}).catch(()=>{})}let Ps=null;const Ns=$s.channel(`tpcode:${zn}`,{config:{private:!0,broadcast:{self:!1},presence:{key:`bridge:${ls}`}}}),Os=$s.channel(`tpflow:${zn}`,{config:{broadcast:{self:!1}}}),Es=$s.channel(`tpdesign:${zn}`,{config:{private:!0,broadcast:{self:!1}}}),js=$s.channel(`tpcontrol:${zn}`,{config:{private:!0,broadcast:{self:!1}}}),Ds=new Map,Fs=new Map;let qs=0;function Ks(e,t=Date.now()){const r=e?.session?.turnActive??!1;return r!==e?._busyAnn&&(r&&(e._turnRev=(Number(e._turnRev)||0)+1,e._turnStart=t,e._settledTurnRev=null,e._turnSettledAt=null),e._busyAnn=r,!0)}function Ms(e,t=Date.now()){return!0!==e?._busyAnn&&(e._turnRev=(Number(e._turnRev)||0)+1,e._turnStart=t,e._busyAnn=!0,e._settledTurnRev=null,e._turnSettledAt=null,!0)}function Us(e,t,{options:r,visibleEvent:o,rejectionMessage:n="The agent did not accept this turn; retry after the lane is available."}={}){if(!e?.session)return{accepted:!1,error:new Error("session unavailable")};Ks(e);let s=!1,i=null;try{s=!1!==e.session.sendTurn(t,r)}catch(e){i=e}if(s?Ms(e):Ks(e),o&&(aa(e,o),ii("code-event",{term:e.id,evt:o})),!s){const t={kind:"error",message:n,recoverable:!0};aa(e,t),ii("code-event",{term:e.id,evt:t})}return hi(),{accepted:s,error:i}}function Bs(e){e?.pendingSideContexts?.length&&!e._sideContextTimer&&(e._sideContextTimer=setTimeout(()=>{e._sideContextTimer=null,function(e){if(!e?.pendingSideContexts?.length||"function"!=typeof e.session?.sendTurn)return!1;const t=ln({contexts:e.pendingSideContexts,busy:!0===e.session?.turnActive,sendTurn:t=>e.session?.sendTurn(t)});return e.pendingSideContexts=t.pending,!!t.dispatched&&(Ms(e),e.flush?.(),hi(),!0)}(e)&&process.stderr.write("\n ◆ started main turn from side-lane handoff.\n")},0),e._sideContextTimer.unref?.())}function Ls(e){e?.pendingWorkerCompletions?.length&&!e._workerCompletionTimer&&(e._workerCompletionTimer=setTimeout(()=>{e._workerCompletionTimer=null,function(e){if(!e?.pendingWorkerCompletions?.length||"function"!=typeof e.session?.sendTurn)return!1;if(e.workerCompletionsInFlight?.length)return!1;if(xr(e)||(e.pending?.size||0)>0)return!1;const t=e.pendingWorkerCompletions.slice(),r=hn(t);return r?(e.workerCompletionsInFlight=t,e.flush?.(),!!Us(e,r,{rejectionMessage:"The worker-completion continuation was not accepted; it remains queued."}).accepted||(e.workerCompletionsInFlight=[],e.flush?.(),!1)):(e.pendingWorkerCompletions=[],!1)}(e)&&process.stderr.write("\n ◆ worker finished — continued its owning terminal.\n")},0),e._workerCompletionTimer.unref?.())}function Ws(e,t){return t&&null==t.turnRev&&Number(e?._turnRev)>0&&(t.turnRev=e._turnRev),t}let Hs=null,zs=!1;const Js=[];let Gs=0;const Ys="1"===process.env.TP_BACKGROUND_WARM;function Vs(){for(;Gs<3&&Js.length;){const e=Js.shift();if(e&&!e.warmed&&!e.warming&&e.session&&!e.session.started){e.warming=!0,Gs++;try{e.session.warm?.()}catch{e.warming=!1,Gs--;continue}e.warmTimer=setTimeout(()=>{e.warming&&(e.warming=!1,Gs=Math.max(0,Gs-1),Vs())},1e5)}}}let Qs=Date.now();const Xs=()=>{if(Qs=Date.now(),process.send&&"1"===process.env.THINKPOOL_PAIR_ACCOUNT_CHILD)try{process.send({t:"busy"})}catch{}};let Zs=null,ei=!1,ti=!1;const ri=()=>{try{const e=Ns.presenceState()||{};for(const t of Object.values(e))for(const e of t||[])if(e&&"bridge"!==e.role)return!0}catch{}return!1},oi=2e5,ni=async(e,t,r=Ns)=>{"pty-out"!==e&&"code-event"!==e||(Qs=Date.now()),t=((e,t)=>{let r,o;try{r=JSON.stringify(t)}catch{return t}if(!r||r.length<=oi)return t;process.stderr.write(`\n ⚠ oversized ${e} frame: ${r.length}B (term ${String(t?.term||"?").slice(0,8)}) — defanging so Realtime doesn't drop it\n`);try{o=JSON.parse(r)}catch{return t}if(o.evt&&"object"==typeof o.evt&&(o.evt=So(o.evt,1e5)),Array.isArray(o.events)){o.events=o.events.map(e=>So(e,1e5));let e=0,t=0;for(;o.events.length>1&&JSON.stringify(o).length>oi&&e++<1e4;)o.events.shift(),t++;if(t){const e=qo(o.events);"number"==typeof e&&(o.trimmedBefore=Math.max(o.trimmedBefore??0,e))}}return o})(e,t);try{return r.channelAdapter?.canPush?.()??1?await r.send({type:"broadcast",event:e,payload:t}):await r.httpSend(e,t)}catch{return null}},si=Uo({send:({event:e,payload:t,ch:r})=>ni(e,t,r)}),ii=(e,t,r=Ns)=>{"code-event"!==e||r!==Ns?ni(e,t,r):si.enqueue({event:e,payload:t,ch:r})},ai=Ko({send:({event:e,payload:t})=>ni(e,t)}),ci=no(zn),li=new Set,di=(e,t,r=null)=>{ii("term-opened",{id:e,kind:t,sideParent:r?.sideParent||void 0,sideTask:r?.sideTask||void 0,name:ci[e]||void 0})},ui=new Set,mi=new Map;let pi=null;const hi=()=>{const e=x(),t=new Map(Re(Zn.map(e=>e.cmd)).map(e=>[e.cmd,e.enabled])),o=++qs;return ni("bridge",{v:2,name:ls,bridge_id:ds,started_at:ps,rev:o,repo:vs,branch:ks(),...!1===Ln.ok?{sdkWarn:`${Ln.version}: ${Ln.reason}`}:{},models:pi||void 0,cwd:gs,version:ys,promptBundle:_n,host:hs,hostId:fs,uid:Ss||void 0,provider:Un.provider,providerBaseUrl:Un.baseUrl||void 0,ctxCarry:!0,providerPubKey:_(),providers:P(),pendingUpdate:Zs,updir:bs.split(r.sep).join("/"),scheduledRuns:en(),agents:Zn.map(e=>{let r=!1;if(e.resume)try{r=e.resume.probe()}catch{}return{label:e.label,cmd:e.cmd,canResume:r,enabled:!1!==t.get(e.cmd)}}),terms:[...[...Ds.entries()].map(([e,t])=>({id:e,cmd:t.cmd,alive:!0,cols:t.term.cols,rows:t.term.rows,name:ci[e]||void 0,..._r(t)})),...[...Fs.entries()].map(([t,r])=>({id:t,cmd:r.cmd,kind:"structured",runtime:r.runtime||"claude",alive:!0,..._r(r),turnRev:Number(r._turnRev)||0,...xr(r)&&r._turnStart?{turnStartedAt:r._turnStart}:{},...!xr(r)&&Number(r._settledTurnRev)>0&&Number(r._settledTurnRev)===Number(r._turnRev)?{settledTurnRev:Number(r._settledTurnRev),turnSettledAt:Number(r._turnSettledAt)||void 0}:{},hasTranscript:r.log.length>0,commands:r.commands,mode:r.mode||void 0,effort:r.effort||void 0,name:ci[t]||void 0,model:r.model||void 0,capabilities:{...le(r.runtime||"claude"),modes:ae(r.runtime||"claude",r)},..."codex"===r.runtime?{approvalPolicy:z(r.mode).approvalPolicy,models:r.models||[],canSteer:r.session?.canSteer??!1}:"hermes"===r.runtime?{models:r.models||[],canSteer:r.session?.canSteer??!1}:{},...null!=r.archiveOldestSeq?{oldestSeq:r.archiveOldestSeq}:{},...r.spawnedBy?{spawned:!0,spawnedBy:r.spawnedBy}:{},...r.sideParent?{sideParent:r.sideParent,sideTask:r.sideTask||void 0,sideHandback:!!r.sideHandback}:{},...r.flowSessionId?{flowId:r.flowSessionId,flowRole:r.flowTaskKey?"lane":"conductor"}:{},...r.scheduleRunId?{scheduleRunId:r.scheduleRunId}:{},...r.provider&&"anthropic"!==r.provider?{provider:{id:r.provider,name:e[r.provider]||r.provider}}:{}}))]})},fi=async(e,t,r,o=!0)=>{if(Dn&&e&&t)try{const n=r?`&name=eq.${encodeURIComponent(r)}`:`&or=${encodeURIComponent("(name.is.null,name.eq.Terminal)")}`,s=await fetch(`${An}/rest/v1/code_terminals?id=eq.${encodeURIComponent(e)}${n}&select=id`,{method:"PATCH",headers:{apikey:En,Authorization:`Bearer ${Dn}`,"Content-Type":"application/json",Prefer:"return=representation"},body:JSON.stringify({name:t})}),i=s.ok?await s.json().catch(()=>[]):[];if(o&&(!s.ok||!Array.isArray(i)||0===i.length)){const o=setTimeout(()=>{fi(e,t,r,!1)},1500);o.unref?.()}}catch{if(o){const o=setTimeout(()=>{fi(e,t,r,!1)},1500);o.unref?.()}}},wi=async(e,t,r=!0)=>{if(!Dn||!e||!t)return;const o=new AbortController,n=setTimeout(()=>o.abort(),4500);try{const s=await fetch(`${Pn}/api/code-terminal-name`,{method:"POST",headers:{Authorization:`Bearer ${Dn}`,"Content-Type":"application/json"},body:JSON.stringify({code:zn,terminalId:e,task:t}),signal:o.signal});clearTimeout(n);const i=await s.json().catch(()=>({}));if(r&&404===s.status&&"terminal_pending"===i?.code){const r=setTimeout(()=>{wi(e,t,!1)},1500);return void r.unref?.()}if(!s.ok)return;const a=ee(i?.name);a&&((e,t)=>{if(!t||li.has(e))return!1;const r=mi.get(e);if(ci[e]&&ci[e]!==r)return!1;const o=ci[e]||null,n=((e,t)=>{const r=new Set(Object.entries(ci).filter(([t])=>t!==e).map(([,e])=>String(e).toLowerCase()));if(!r.has(t.toLowerCase()))return t;for(let e=2;e<100;e++){const o=` ${e}`,n=`${t.slice(0,48-o.length).trim()}${o}`;if(!r.has(n.toLowerCase()))return n}return t})(e,t);ci[e]===n||(ci[e]=n,mi.set(e,n),so(zn,ci),fi(e,n,o),hi())})(e,a)}catch{clearTimeout(n)}},gi=(e,t)=>{const r=Fs.get(e);if(!r||ci[e]||li.has(e)||ui.has(e))return;if(r.log?.some(e=>"you"===e?.kind))return;const o=te(t);o&&(ui.add(e),wi(e,o))},vi=!(!process.send||"1"!==process.env.THINKPOOL_PAIR_ACCOUNT_CHILD),yi=new Map;let ki=null;function bi(e,t={},r=4e3){if("1"===process.env.TP_CROSSROOM_OFF)return Promise.resolve({error:"Cross-session reach is turned off in this room."});if(!vi)return Promise.resolve({error:`Cross-session reach needs the thinkpool account bridge running your sessions (${Oe}). This room is running standalone, so it can only see its own terminals — use read_terminal.`});const o=c();return new Promise(n=>{const s=setTimeout(()=>{yi.delete(o),n({error:"The other session did not respond in time."})},r);s.unref?.(),yi.set(o,{resolve:n,timer:s});try{process.send({t:e,reqId:o,...t})}catch{clearTimeout(s),yi.delete(o),n({error:"Could not reach the account bridge."})}})}function $i(e,t){const r={kind:"needs-input",subtype:"pair-control",summary:"A protected action requires a durable decision.",permissionId:String(t?.id||"").slice(0,160)};return aa(e,r),ii("code-event",{term:e.id,evt:r}),{...t,...e.scheduleRunId?{runId:e.scheduleRunId}:{},source:{epoch:0,cid:r.cid,seq:r.seq}}}async function Ti({fromRoom:e,fromHost:t,fromTerminalName:r,text:o,terminal:n}){if("1"===process.env.TP_PAIRBUS_OFF)return{error:"Cross-room posting is turned off in this room."};const s=String(o||"").trim();if(!s)return{error:"Empty cross-room post ignored."};const i=fr({selfId:null,sessions:Fs,terms:Ds,names:ci});let a=null;if(n){const e=wr(i,n);if(e&&"agent"!==e.kind)return{error:`Terminal ${e.ref} in room ${zn} is a shell, not an agent — cross-room posts go to agents only.`};a=e?.id||null}else{const e=[...Fs.keys()];1===e.length&&(a=e[0])}if(!a){const e=i.filter(e=>"agent"===e.kind);return{error:e.length?`Name which agent lane in room ${zn} to deliver to (${e.map(e=>e.ref).join(", ")}).`:`No agent terminal is open in room ${zn} to receive this.`}}const l=Fs.get(a);if(!l?.session)return{error:`That terminal in room ${zn} is no longer live.`};const d=`${e}${t?` on ${t}`:""}`;let u="deny";try{u=await(m=l,p={id:c(),toolName:"mcp__thinkpool__post_to_session",input:{session:e,host:t,terminalName:r,text:s,incoming:!0},risk:"high"},new Promise(e=>{if(!m?.pending)return e("deny");const t=$i(m,{term:m.id,id:p.id,toolName:p.toolName,input:p.input,risk:p.risk});m.pending.set(p.id,{resolve:e,payload:t}),hi(),ii("code-perm-req",t),process.stderr.write(`\n ● incoming cross-room task for ${String(m.id).slice(0,8)} — approve in the room.\n`)}))}catch{u="deny"}var m,p;if("allow"!==u)return{error:`The people in room ${zn} declined the incoming task from ${d}.`};l.roomHop=1,l.hop=(l.hop||0)+1,l.peekCount=0,l.peekRosterCount=0,l.postCount=0,l.pairPeekCount=0,l.crossRoomPostCount=0;const h=`[From: room ${d} — relayed via the thinkpool cross-room Ensemble, approved by a person in this room]\n${s}`,f={kind:"you",text:h,by:`room ${e}`,crosspost:!0,relaySourceName:String(r||"").trim().slice(0,80)||void 0};gi(a,s);const w=Us(l,h,{visibleEvent:f,rejectionMessage:"The incoming cross-room task was not accepted; retry after the lane is available."});return w.accepted?{ok:!0,ref:String(a).slice(0,8)}:{error:w.error?`Could not deliver to room ${zn} — the lane may have just closed.`:`Could not deliver to room ${zn} — the lane refused the turn (check its visible host-memory/runtime error).`}}!async function(){if(vi||"1"===process.env.TP_PAIRBUS_OFF||"1"===process.env.TP_CROSSROOM_OFF)return;if(!Dn||!Ss)return;let t=null;try{const e=`${An}/rest/v1/code_sessions?code=eq.${encodeURIComponent(zn)}&select=code,name,owner_id,participants`,r=await fetch(e,{headers:{apikey:En,Authorization:`Bearer ${Dn}`}});if(!r.ok)return;const o=await r.json().catch(()=>[]);t=Array.isArray(o)?o[0]:null}catch{return}const r=Mr({row:t,myUid:Ss});if(!r?.topic)return;const o=Kr({room:zn,roomName:t?.name||null,host:e.hostname().replace(/\.local$/,""),formatPeek:e=>mr({selfId:null,sessions:Fs,terms:Ds,names:ci,terminal:e.terminal,lines:e.lines}),receivePost:e=>Ti(e)}),n=$s.channel(r.topic,{config:{private:!0,broadcast:{self:!1}}}),s=async(e,t)=>{if(t)try{await n.send({type:"broadcast",event:e,payload:t})}catch{}};n.on("broadcast",{event:"peer-list-req"},({payload:e})=>{s("peer-list-res",o.list(e))}).on("broadcast",{event:"peer-peek-req"},({payload:e})=>{const t=o.peek(e);t&&s("peer-peek-res",t)}).on("broadcast",{event:"peer-post-req"},({payload:e})=>{o.post(e).then(e=>{if(e)return s("peer-post-res",e)})}).subscribe(e=>{"SUBSCRIBED"===e?process.stderr.write("\n ◆ standalone pair bus subscribed — this live room can receive approval-gated cross-session tasks.\n"):"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e||process.stderr.write(`\n ◇ standalone pair bus ${e.toLowerCase().replace("_"," ")} — cross-session reach will retry with realtime.\n`)}),ki=n}(),vi&&process.on("message",e=>{if(e&&e.t){if("pair-list-res"===e.t||"pair-peek-res"===e.t||"pair-post-res"===e.t){const t=yi.get(e.reqId);if(!t)return;return clearTimeout(t.timer),yi.delete(e.reqId),void t.resolve(e)}if("pair-peek-local"===e.t){let t,r;try{t=mr({selfId:null,sessions:Fs,terms:Ds,names:ci,terminal:e.terminal,lines:e.lines})}catch{r="Could not read that session."}try{process.send({t:"pair-peek-res",reqId:e.reqId,text:t,error:r})}catch{}return}"pair-post-local"!==e.t||Ti(e).then(t=>{try{process.send({t:"pair-post-res",reqId:e.reqId,...t})}catch{}})}});const Ri=()=>{const e=ri();for(const[t,r]of Ds){if(!r.buf)continue;if(!e){r.buf="",Qs=Date.now();continue}const o=Buffer.from(r.buf,"utf8").toString("base64");r.buf="",ii("pty-out",{term:t,b64:o})}},Si=setInterval(Ri,35);Si.unref?.();const Ii=r.join(e.tmpdir(),"thinkpool-mockups",zn);try{t.mkdirSync(Ii,{recursive:!0}),process.env.TP_MOCKUP_OUTBOX=Ii}catch{}const Ci=new Map,xi=new Map,_i=new Map,Ai=new Map,Pi=new Map;function Ni(e){e?.scheduleDeadlineTimer&&clearTimeout(e.scheduleDeadlineTimer),e&&(e.scheduleDeadlineTimer=null)}const Oi=new Set;async function Ei(e){const t=e?.scheduleAdmissionLease;return!t||!!(await on(t)).ok&&(e.scheduleAdmissionLease=null,!0)}async function ji(e){const t=Vo(e?.scheduleOutcomePending);if(!e?.id||!t||e.scheduleOutcomeRecorded)return!1;const r=`${e.id}:${t.runId}`;if(Oi.has(r))return!1;Oi.add(r);try{if(!(await Go({supabaseUrl:An,anonKey:En,token:Dn,roomCode:zn,runId:t.runId,bridgeId:us,bridgeFencing:ms,result:t.result,canceled:t.canceled,evidenceRefs:t.evidenceRefs})).ok)return!1;if(await Ei(e),Fs.get(e.id)!==e)return!!po(zn,e.id,t.runId)&&fo(zn,e.id);const r=e.scheduleOutcomePending;e.scheduleOutcomeRecorded=!0,e.scheduleOutcomePending=null;const o=ho(zn,e.id,()=>e.flush?.());return o.snapshotRecorded?o.ok:(e.scheduleOutcomeRecorded=!1,e.scheduleOutcomePending=r,!1)}finally{Oi.delete(r)}}function Di(e,t,{canceled:r=!1}={}){if(!e?.scheduleRunId||e.scheduleOutcomeRecorded||e.scheduleOutcomePending)return!1;const o=Vo({runId:e.scheduleRunId,result:t,canceled:r,evidenceRefs:(n=e.id,[...xi.values()].filter(e=>e?.term===n&&"string"==typeof e.previewId).slice(0,16).map(e=>({type:"preview",id:e.previewId})))});var n;return!!o&&!!vo(zn,e.id,o)&&(e.scheduleOutcomePending=o,Ni(e),e.flush?.(),ji(e),!0)}function Fi(e){if(Ni(e),!Xo({runId:e?.scheduleRunId,deadlineAt:e?.scheduleDeadlineAt,outcomeRecorded:e?.scheduleOutcomeRecorded,outcomePending:e?.scheduleOutcomePending}))return;const t=Math.max(0,e.scheduleDeadlineAt-Date.now());e.scheduleDeadlineTimer=setTimeout(async()=>{if(e.scheduleDeadlineTimer=null,e.scheduleOutcomeRecorded)return;e.scheduleTimedOut=!0,ya(e),await Ae(e);const t={kind:"error",subtype:"runtime_limit",message:"Scheduled run reached its configured runtime ceiling."};aa(e,t),ii("code-event",{term:e.id,evt:t}),Di(e,t),e.flush?.(),hi()},t),e.scheduleDeadlineTimer.unref?.()}const qi=e=>Es.send({type:"broadcast",event:"design-status",payload:{ts:Date.now(),...e}}),Ki=(e,t,r={})=>{const o=Ai.get(e);if(o){if(o.timer&&clearTimeout(o.timer),Ai.delete(e),qi({previewId:o.record.previewId,requestId:o.request.cid,state:t,...r}),"verified-live"===t){const t=_i.get(e)||[];for(const e of t.splice(0))qi({previewId:e.record.previewId,requestId:e.request.cid,state:"stale",message:"The artifact changed. Reselect the element on the new revision."})}queueMicrotask(()=>Ui(e))}},Mi=e=>{const t=Ai.get(e);t?.resultOk&&t.proof&&Ki(e,"verified-live",{message:"Verified at desktop and mobile.",artifact:t.proof.artifact,...t.proof.artifactHtml?{artifactHtml:t.proof.artifactHtml}:{},canRestore:"preview"!==t.record.sourceKind})};function Ui(e){if(Ai.has(e))return;const t=_i.get(e)||[],r=t[0];if(!r)return;const o=Fs.get(e);if(!o)return t.shift(),qi({previewId:r.record.previewId,requestId:r.request.cid,state:"needs-lane",message:"The producing lane is no longer available."}),Ui(e);if(o.session?.turnActive)return;t.shift();const n=xi.get(r.record.previewId),s=n&&Tt(n);if(!n||!s||s.revision!==r.record.revision)return qi({previewId:r.record.previewId,requestId:r.request.cid,state:"stale",message:"The artifact changed. Reselect the element."}),Ui(e);const i={...r,resultOk:!1,proof:null,timer:null};Ai.set(e,i);const a={kind:"you",text:bt(r.request,{restore:!!r.restoreRecord}),cid:r.request.cid,by:r.by,design:!0};Ks(o);let c=!1;try{c=!1!==o.session.sendTurn(kt({record:r.record,request:r.request,by:r.by,restore:!!r.restoreRecord,priorRecord:r.restoreRecord}))}catch{c=!1}if(c&&Ms(o),yo(a),aa(o,a),ii("code-event",{term:e,evt:a}),c&&qi({previewId:r.record.previewId,requestId:r.request.cid,state:"applying"}),!c){Ks(o);const t={kind:"error",message:"The producing lane could not start the edit.",recoverable:!0};aa(o,t),ii("code-event",{term:e,evt:t}),Ki(e,"failed",{message:"The producing lane could not start the edit."})}hi()}const Bi=(e,o,n,s)=>{try{const i=r.join(e,`${o}.receipt.json`),a=`${i}.tmp`;t.writeFileSync(a,JSON.stringify({ok:n,status:s,ts:Date.now()})),t.renameSync(a,i)}catch{}},Li=new $n({deliver:async({box:e,term:o,trustedDesignSource:n=!1,slug:s,m:i})=>{const a=n?Fs.get(o):null,l=a?Rt(i,a.cwd||process.cwd(),{box:e}):null,d=l?St(i,l,{box:e}):null,u=l?Ai.get(o):null,m=!(!u||i.designRequestId!==u.request.cid||i.parentRevision!==u.record.revision),p=u?.restoreRecord?.revision,h=p?l?.revision===p:l?.revision!==u?.record?.revision,f="preview"===u?.record?.sourceKind?"preview"===l?.sourceKind&&l?.captureKey===u.record.captureKey:l?.sourcePath===u?.record?.sourcePath,w=m&&f&&h?u.record.revision:null,g=e=>{try{return e&&t.readFileSync(e).toString("base64")}catch(t){return e&&process.stderr.write(`\n ◇ mockup asset unreadable: ${e} (${t?.code||t?.message||t})\n`),null}},v=e=>{try{return e&&t.readFileSync(e,"utf8")}catch(t){return e&&process.stderr.write(`\n ◇ mockup asset unreadable: ${e} (${t?.code||t?.message||t})\n`),null}},y=c(),k=Date.now();if(l&&!d)return Bi(e,s,!1,"invalid-snapshot"),void process.stderr.write(`\n ◇ mockup "${i.slug}" rendered snapshot was not trusted.\n`);try{const n={"Content-Type":"application/json"};Dn&&(n.Authorization=`Bearer ${Dn}`);const a=await fetch(`${Pn}/api/code-mockup`,{method:"POST",headers:n,body:JSON.stringify({code:zn,slug:i.slug,title:i.title,cid:y,ts:k,term:o,desktopPng:g(i.desktop),mobilePng:g(i.mobile),html:l?d:v(i.html),...l?{previewId:l.previewId,revision:l.revision,sourceKnown:!0}:{},...w?{verified:!0,parentRevision:w}:{}})});if(!a.ok)return Bi(e,s,!1,a.status),void process.stderr.write(`\n ◇ mockup "${i.slug}" upload failed (${a.status}).\n`);const c=await a.json(),{paths:m}=c,p=!(!l||!c?.payload?.sourceKnown),h=!(!p||!w||!0!==c?.payload?.verified||c.payload.parentRevision!==w),f="string"==typeof c?.payload?.artifactHtml?c.payload.artifactHtml:null,b={kind:"mockup",__struct:!0,cid:y,term:o,slug:i.slug,title:i.title||i.slug,ts:k,paths:m,...p?{previewId:l.previewId,revision:l.revision,sourceKnown:!0,...h?{verified:!0,parentRevision:w}:{}}:{},...f?{artifactHtml:f}:{}};if(p){Object.assign(l,{term:o,slug:i.slug,title:i.title||i.slug,desktop:i.desktop,mobile:i.mobile});try{const o=r.join(e,".design-revisions");t.mkdirSync(o,{recursive:!0}),l.backupPath=r.join(o,`${l.revision}.html`),t.existsSync(l.backupPath)||t.writeFileSync(l.backupPath,l.source)}catch{}xi.set(l.previewId,l);const n=u,s=h,a=!!(m?.html&&m?.desktop&&m?.mobile&&i.desktop&&i.mobile);if(s&&a){"preview"!==n.record.sourceKind&&Pi.set(l.previewId,{priorRecord:n.record,request:n.request});const e=f||(Buffer.byteLength(d,"utf8")<=131072?d:null);n.proof={artifact:b,artifactHtml:e},Mi(o)}}ii("code-event",{term:o,evt:b}),Bi(e,s,!0,200),process.stderr.write(`\n ◆ mockup "${i.title||i.slug}" pushed to the room.\n`)}catch(t){Bi(e,s,!1,"error"),process.stderr.write(`\n ◇ mockup "${i.slug}" send failed: ${t?.message||t}\n`)}}});function Wi(e,o,n=!1){try{t.mkdirSync(e,{recursive:!0})}catch{return null}try{return t.watch(e,(s,i)=>function(e,o,n,s=!1){const i=((e,o,n,s=!1)=>{if(!o||o.endsWith(".receipt.json")||!o.endsWith(".json"))return null;const i=r.join(e,o);let a;try{a=t.statSync(i)}catch{return null}const c=o.replace(/\.json$/,""),l=`${n}/${c}`;if(Ci.get(l)===a.mtimeMs)return null;if(Ci.set(l,a.mtimeMs),!n)return null;let d;try{d=JSON.parse(t.readFileSync(i,"utf8"))}catch{return null}return d?.slug?Tn(d,{isReadyFile:e=>{try{const r=t.statSync(e);return r.isFile()&&r.size>0}catch{return!1}}})?{box:e,file:o,term:n,trustedDesignSource:s,slug:c,m:d}:(Bi(e,c,!1,"incomplete"),process.stderr.write(`\n ◇ mockup "${d.title||d.slug}" is incomplete — desktop, mobile, and source are all required.\n`),null):null})(e,o,n,s);if(!i)return;const a=Fs.get(n),c=!!a&&(!0===a._busyAnn||!0===a.session?.turnActive),l="preview"===i.m.sourceKind?`preview:${i.m.captureKey||i.m.route||i.m.slug}:${i.m.title||""}`:`authored:${i.m.slug}`,d=Li.enqueue(n,i,{active:c,key:l});d.queued?(Bi(e,i.slug,!0,"queued"),process.stderr.write(`\n ◆ mockup "${i.m.title||i.m.slug}" ready — ${d.replaced?"replaced an earlier queued render":"queued after the final response"}.\n`)):d.delivery.catch(()=>{})}(e,i,o(),n))}catch{return null}}const Hi=(e,t)=>r.join(Ii,e,t);Wi(Ii,()=>[...Fs.keys()][0]||Hs||[...Ds.keys()][0]);const zi="1"===process.env.TP_FOLLOW,Ji=parseInt(process.env.TP_COLS,10)||null,Gi=parseInt(process.env.TP_ROWS,10)||null,Yi=()=>({cols:Ji||(zi?process.stdout.columns||100:Math.min(process.stdout.columns||100,120)),rows:Gi||(zi?process.stdout.rows||28:Math.min(process.stdout.rows||28,32))});function Vi({id:e,cmd:t,args:r=[],attached:o=!1,cols:n,rows:s}){if(Ds.has(e))return;if(Ds.size>=8)return process.stderr.write(`\n ⚠ can't open "${t}" — terminal cap (8) reached; close one first.\n`),void ii("term-exit",{id:e});if(!Fn)return process.stderr.write(`\n ⚠ can't open "${t}" — node-pty isn't built (PTY mode disabled).\n`),void ii("term-exit",{id:e});const i=xe(`start the ${t} terminal`);if(!i.ok)return process.stderr.write(`\n ⚠ ${i.reason}\n`),void ii("term-exit",{id:e,reason:i.reason});const a=o?Yi():null,c=Hi("terms",e),l=Fn.spawn(t,r,{name:"xterm-256color",cols:n||(o?a.cols:Ji||120),rows:s||(o?a.rows:Gi||32),cwd:process.cwd(),env:{...process.env,TP_MOCKUP_OUTBOX:c}}),d={term:l,cmd:t,attached:o,scrollback:"",buf:"",lastActionAt:null,mockupWatcher:Wi(c,()=>e)};return Ds.set(e,d),o&&(Hs=e),l.onData(e=>{o&&process.stdout.write(e),d.buf+=e,d.lastActionAt=Date.now(),d.scrollback=(d.scrollback+e).slice(-12e4)}),l.onExit(()=>{try{d.mockupWatcher?.close()}catch{}Ds.delete(e),e===Hs&&(Hs=null,xa()),zs||(ii("term-exit",{id:e}),hi(),0!==Ds.size||Yn?process.stderr.write(`\n ◇ terminal "${t}" ended — still relaying ${Ds.size} terminal(s). Ctrl-C to stop.\n`):Ka())}),hi(),d}const Qi=2e3,Xi="[2m",Zi="[0m",ea="[36m",ta="[35m",ra="[33m",oa="[31m",na=e=>{const t=e&&(e.command||e.file_path||e.path||e.pattern||e.url||e.query||e.description);return t?" "+String(t).replace(/\s+/g," ").slice(0,100):""};function sa(e){const t=e=>process.stderr.write(e+"\n");switch(e.kind){case"you":return t(`${ea}❯ ${e.text}${Zi}${e.by?` ${Xi}(${e.by})${Zi}`:""}`);case"chat":return t(`${Xi}${e.by}: ${e.text}${Zi}`);case"whisper":return t(`${Xi}// ${e.by}: ${e.text}${Zi}`);case"pool":return t(e.pending?`${ea}◌ pool dispatching…${Zi}`:`${ea}◆ pool → ${e.text}${Zi}`);case"note":return t(`${Xi}— ${e.text} —${Zi}`);case"clear":return t(`${Xi}— context cleared —${Zi}`);case"usage":{const r=e.ctx;return r?t(`${Xi} ctx ${r.pct}% · ${Math.round(r.used/1e3)}k/${Math.round(r.max/1e3)}k${null!=e.costUsd?` · $${e.costUsd.toFixed(3)}`:""}${Zi}`):void 0}case"error":return t(`${oa}✗ ${e.message}${Zi}`);case"tool_result":{const r=e.content,o=("string"==typeof r?r:Array.isArray(r)?r.map(e=>e?.text||"").join(" "):"").replace(/\s+/g," ").slice(0,120);return t(` ${e.isError?oa:Xi}⎿ ${o||(e.isError?"error":"ok")}${Zi}`)}case"assistant":for(const r of e.blocks||[])"text"===r.type&&r.text?.trim()?t(`[32m⏺${Zi} ${r.text.trim()}`):"thinking"===r.type&&r.text?.trim()?t(`${Xi}✶ ${r.text.trim().slice(0,160)}${Zi}`):"tool_use"===r.type&&t(` ${ea}${r.name}${Zi}${na(r.input)}`);return;default:return}}function ia(e,t){const r=zo(t);return process.stderr.write(`\n ◇ ${r.message}\n`),e?.id&&(aa(e,r),ii("code-event",{term:e.id,evt:r})),r}function aa(e,t){if(!Ho(t).known)return ia(e,t),null;Ws(e,t),yo(t),e.mcpFlight=Wo(e.mcpFlight,t,{now:t.ts}),e.lastActionAt=t.ts,e.lastEvent=t,e.seq&&$o(t)&&(t.seq=e.seq.next()),e.id&&$o(t)&&(io(e.room,e.id,[t]),null==e.archiveOldestSeq&&(e.archiveOldestSeq=t.seq));const r=So(t);for(e.log.push(r),e.logBytes=(e.logBytes||0)+JSON.stringify(r).length+1;e.log.length>Qi||e.log.length>1&&e.logBytes>ar;){const t=e.log.shift();e.logBytes-=JSON.stringify(t).length+1}return t}function ca(e){for(let t=e.length-1;t>=0;t--){const r=e[t]?.kind;if("result"===r||"error"===r||"propose"===r||"pool"===r)return!1;if("assistant"===r||"you"===r||"tool_result"===r)return!0}return!1}function la(e,t,r=null){const o={kind:"control",text:t,by:r};aa(e,o),ii("code-event",{term:e.id,evt:o})}function da(e){const t=Oo(e?.log);return!!t&&(e.pendingCheckpoint=t,!0)}function ua(e,t={}){if(!e||"codex"!==e.runtime||e.codexCompactionPromise)return!1;const r=async function(e,t={}){const r=Eo(e.log,Do,{reason:"compact"});if(!r)return void la(e,"nothing to compact — context unchanged",t.by);const o=e.lastUsage?.ctx?.used||null;ii("code-event",{term:e.id,evt:{kind:"compact",status:"start",ts:Date.now()}});let n=!1;try{n=await(e.session.compactContext?.())}catch{n=null}finally{!e.session.turnActive&&Pr(e)&&hi()}if(!0===n){da(e);const r={kind:"compaction",trigger:"manual",preTokens:o,by:t.by,native:!0};return aa(e,r),ii("code-event",{term:e.id,evt:r}),ii("code-event",{term:e.id,evt:{kind:"compact",status:"done",ts:Date.now()}}),void e.flush?.()}if(null==n)return ii("code-event",{term:e.id,evt:{kind:"compact",status:"done",ts:Date.now()}}),la(e,"Native compaction is still settling; existing context was preserved.",t.by),void e.flush?.();if(!1===e.session.clearContext?.())return ii("code-event",{term:e.id,evt:{kind:"compact",status:"done",ts:Date.now()}}),void la(e,"Codex context compaction unavailable right now",t.by);const s=jo(r,e.pendingCheckpoint);e.pendingRecap=s.pendingRecap,e.pendingCheckpoint=s.pendingCheckpoint;const i={kind:"compaction",trigger:"manual",preTokens:o,by:t.by};if(aa(e,i),ii("code-event",{term:e.id,evt:i}),e.lastUsage?.ctx?.max){const t=Math.ceil(r.length/4),o=e.lastUsage.ctx.max,n={kind:"usage",ctx:{...e.lastUsage.ctx,used:t,max:o,pct:Math.min(100,Math.round(t/o*100)),over:t>o}};e.lastUsage=n,ii("code-event",{term:e.id,evt:n})}ii("code-event",{term:e.id,evt:{kind:"compact",status:"done",ts:Date.now()}}),e.flush?.()}(e,t);return e.codexCompactionPromise=r,r.finally(()=>{e.codexCompactionPromise===r&&(e.codexCompactionPromise=null)}).catch(()=>{}),!0}const ma=new Map;function pa(e,t="parent"){const o=r.resolve(e||process.cwd()),n=s("git",["-C",o,"rev-parse","--verify","HEAD^{commit}"],{encoding:"utf8",timeout:3e3,stdio:["ignore","pipe","ignore"]}).trim();if(!/^[0-9a-f]{40}$/i.test(n))throw new Error("parent review source has no immutable HEAD");return{taskKey:t,cwd:o,sha:n}}function ha({id:e,runtime:t="claude",model:o,models:n,effort:i,resume:a,log:l,commands:d,mode:u,spawnedBy:m,spawnDepth:p,cascadeRole:h,hop:f,sideParent:w,sideTask:g,pendingSideContexts:R,pendingWorkerCompletions:_,workerCompletionsInFlight:A,rolePrompt:E,sliceType:j,flowSessionId:D,flowTaskKey:q,flowTaskContract:K,flowRole:M,flowReviewTarget:z,flowReviewTargets:J,flowReviewSnapshots:G,flowReviewRound:Y,flowReviewConclusion:V,dispatchBaseSha:ee,revertTarget:te,cwd:ie,managedWorktree:ae,reviewSliceRoots:ce,openedAt:me,defer:he,provider:fe,carryRecap:we,carryCheckpoint:ye,lastUsage:ke,receivedTurnCids:$e,mcpFlight:Te,scheduleRunId:Re,scheduleDeadlineAt:Se,scheduleOutcomeRecorded:Ie,scheduleAdmissionLease:_e}){if(Fs.has(e))return;t=le(t)?t:"claude";const Ae=Z({runtime:t,capabilityId:"terminal_interrupt",input:{}});if(!Ae.ok)throw new TypeError(`Structured runtime contract rejected: ${Ae.code}`);u=se(t,{mode:u,sliceType:j,flowRole:M}),u=Ke.has(u)&&de(t,u)?u:re(t),it({runtime:t,provider:fe,model:o});const Pe="codex"===t?H():[],Ne="codex"===t&&(o||W())||void 0,Oe="codex"===t?Ne?nt(Ne,Pe):et({sliceType:"feature",runtime:"codex",catalog:Pe}):"hermes"===t?o||void 0:O({provider:fe,model:o,configuredModel:S(fe)?.ANTHROPIC_MODEL});i=oe(t,i);const Ee=Number.isInteger(p)&&p>=0?p:w||m&&!String(m).startsWith("flow:")?1:0,je=Number.isInteger(f)&&f>=0?f:Ee,De=Array.isArray(l)?l.slice(-Qi):[],Fe=ir(De),qe=De.length-Fe.length,Me=Re&&!0!==Ie?Vo(wo(zn,e)):null,Ue=Me?.runId===Re?Me:null,Be={cmd:t,runtime:t,kind:"structured",log:Fe,pending:new Map,receivedTurnCids:new Set(Array.isArray($e)?$e.filter(Boolean).slice(-1e3):[]),mcpFlight:Lo(Te),session:null,recovered:!1,commands:ue(t,d),mode:u,effort:i,models:"codex"===t?Pe:"hermes"===t?Array.isArray(n)&&n.length?n:On:void 0,model:"codex"===t||"hermes"===t?Oe||null:fe&&"anthropic"!==fe?Oe||x()[fe]||fe:Oe||null,provider:fe||null,spawnedBy:m||void 0,spawnDepth:Ee,cascadeRole:"conductor"===h||"worker"===h?h:null,hop:je,sideParent:w||void 0,sideTask:g||void 0,scheduleRunId:Re||null,scheduleDeadlineAt:Number.isFinite(Number(Se))?Number(Se):null,scheduleOutcomeRecorded:!0===Ie,scheduleOutcomePending:Ue,scheduleAdmissionLease:_e||null,pendingSideContexts:Array.isArray(R)?R.filter(Boolean).slice(-4):[],pendingWorkerCompletions:Array.isArray(_)?_.filter(e=>e?.workerId&&Number(e?.turnRev)>0).slice(-6):[],workerCompletionsInFlight:Array.isArray(A)?A.filter(e=>e?.workerId&&Number(e?.turnRev)>0).slice(-6):[],flowSessionId:D||null,flowTaskKey:q||null,cwd:ie||null,managedWorktree:ae||null,sliceType:"review"===j?"review":null,flowRole:M||(D?q?J?.length||ce?.length?"reviewer":"builder":"conductor":null),flowReviewTarget:z||null,flowReviewTargets:Array.isArray(J)&&J.length?J.filter(Boolean):z?[z]:[],flowReviewSnapshots:Array.isArray(G)?G.filter(e=>e?.taskKey&&e?.sha&&e?.cwd):[],flowReviewRound:Number.isInteger(Y)&&Y>=0?Y:0,flowReviewConclusion:V?.taskKey&&["pass","reject","surface"].includes(V?.action)&&Ft(V?.receipt)?{taskKey:V.taskKey,action:V.action,round:V.round,receipt:V.receipt}:null,dispatchBaseSha:ee||null,revertTarget:te||null,openedAt:me||Array.isArray(l)&&l.find(e=>e?.ts)?.ts||Date.now(),snapshotNeedsCompaction:qe>0||Fe.some((e,t)=>e!==De[t+qe]),logBytes:Fe.reduce((e,t)=>e+JSON.stringify(t).length+1,0)};Be._turnRev=Be.log.reduce((e,t)=>Math.max(e,Number(t?.turnRev)||0),0);const Le=[...Be.log].reverse().find(e=>"result"===e?.kind&&Number(e?.turnRev)>0);Be._settledTurnRev=Number(Le?.turnRev)||null,Be._turnSettledAt=Number(Le?.ts)||null,Be.interruptedRecap=ca(Be.log)?Eo(Be.log,Do):null,Be.workerCompletionsInFlight.length&&!Be.interruptedRecap&&(Be.workerCompletionsInFlight=[]),Be.permNotifier=v({onArm:(t,r)=>As({kind:"needs-input",term:e,termName:ci[e]||null,model:Be.model||null,permissionId:t,summary:r,pushEligible:!1}),onFire:(t,r)=>As({kind:"needs-input",term:e,termName:ci[e]||null,model:Be.model||null,permissionId:t,summary:r,pushEligible:!0}),onResolve:t=>As({kind:"needs-resolved",term:e,termName:ci[e]||null,model:Be.model||null,permissionId:t})}),Be.seq=ko(bo(Be.log)),Be.rolePrompt=E||null,Be.flowTaskContract=K&&"object"==typeof K?K:null,Be.lastUsage=ke||null,Be.reviewSliceRoots=Array.isArray(ce)?ce.filter(Boolean):[];const He=async({reviewPass:t=!1,baselineEvidence:r=""}={})=>{if(!Be.flowSessionId||!Be.flowTaskKey)return"Not a Flow lane — nothing to mark done.";if("builder"!==Be.flowRole&&(!t||"reviewer"!==Be.flowRole))return"This Flow role cannot mark a builder slice done.";if(Be.flowDone)return"This slice is already recorded as done.";let o="";const n=!t&&!!Be.flowTaskContract?.baseline?.gate;if(n)try{o=Ge(r)}catch(e){return`Slice "${Be.flowTaskKey}" is not done: submit the real bounded baselineEvidence receipt (${e?.message||e}). Observe the assigned pre-edit gate; do not fabricate a RED sentence.`}let i=null;try{i=s("git",["-C",Be.cwd||process.cwd(),"rev-parse","HEAD"],{encoding:"utf8"}).trim()}catch{}if(!t&&Be.dispatchBaseSha&&i===Be.dispatchBaseSha)return`Slice "${Be.flowTaskKey}" is not done: HEAD is still the dispatch base (${i.slice(0,8)}). Commit the verified implementation first.`;if(!t){const e=(e=>{try{return s("git",["-C",e,"status","--porcelain=v1","--untracked-files=all"],{encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]}).split("\n").map(e=>e.trim()).filter(Boolean)}catch{return null}})(Be.cwd||process.cwd());if(null==e)return`Slice "${Be.flowTaskKey}" is not done: the bridge could not verify a clean worktree.`;if(e.length)return`Slice "${Be.flowTaskKey}" is not done: commit or remove every remaining worktree change before completion (${e.slice(0,4).join(", ")}).`}let a=null;if(!t&&Be.flowTaskContract?.scopePaths?.length){const e=ur(Be.cwd||process.cwd(),Be.dispatchBaseSha,i);if(!e)return`Slice "${Be.flowTaskKey}" is not done: the bridge could not derive its Git scope footprint.`;if(a=qt({log:Be.log,repoRoot:Be.cwd||process.cwd(),declared:Be.flowTaskContract.scopePaths,changed:e}),!a.held)return`Slice "${Be.flowTaskKey}" is not done: scope drift detected in ${a.unexpected.join(", ")}. The approved scope must be amended before these files can ship.`}let c=null;try{c=(await pt({dir:Be.cwd||process.cwd(),id:`lane:${Be.flowSessionId}:${e}`})).url}catch{}try{const t=Be.cwd||process.cwd(),r=at(Be.flowSessionId,Be.flowTaskKey,"_slice.done",JSON.stringify({taskKey:Be.flowTaskKey,commitSha:i||null,previewUrl:c||null}),{worktreeDir:t}),n=dt(Be.flowSessionId,{worktreeDir:t}),s=[{taskKey:Be.flowTaskKey,name:"_slice.done",path:r.path,sha:r.sha},...n.map(e=>({taskKey:e.taskKey,name:e.name,path:e.path,sha:e.sha}))],a=ct({key:Be.flowTaskKey,title:ci[e]||Be.flowTaskKey},{acceptanceProof:`${o?`baseline: ${o}; `:""}${i?`committed ${i.slice(0,8)}`:"slice done"}`,artifacts:s});lt(Be.flowSessionId,a,{baseDir:process.cwd()})}catch(e){process.stderr.write(`\n ${Xi}◆ flow digest skip ${Be.flowTaskKey} — ${e?.message||e}${Zi}\n`)}const l=n?{...Be.flowTaskContract,baseline:{...Be.flowTaskContract.baseline,evidence:o},...a?{scopeEvidence:a}:{}}:Be.flowTaskContract?{...Be.flowTaskContract,...a?{scopeEvidence:a}:{}}:null;return ii("flow-task-done",{term:e,flowId:Be.flowSessionId,taskKey:Be.flowTaskKey,laneId:e,commitSha:i,previewUrl:c,contract:l,...t?{reviewAction:"pass"}:{}},Os),process.stderr.write(`\n ${ea}◆ flow slice done — ${Be.flowTaskKey} (${i?i.slice(0,8):"no commit"})${c?` · preview ${c}`:""}${Zi}\n`),Be.flowDone=!0,setTimeout(()=>{try{Ta(e)}catch{}},2500),`Slice "${Be.flowTaskKey}" recorded as DONE${i?` (commit ${i.slice(0,8)})`:""}${c?`. Live preview: ${c}`:""}. The room dispatches dependent slices + assembles when all are done. You are finished — stop here.`};Be.markFlowDone=He;const ze=Dt(),Qe=async t=>Be.flowReviewConclusion?{ok:!0,message:`Review already concluded for ${Be.flowReviewConclusion.taskKey}; receipt ${Be.flowReviewConclusion.receipt.cid||"recorded"}.`}:ze(()=>(async t=>{if(!Be.flowSessionId||!Be.flowTaskKey||"reviewer"!==Be.flowRole)return{ok:!1,message:"Not a Flow review lane."};let r,o=null;try{r=Ot(t);const e="string"==typeof t?JSON.parse(String(t).replace(/```(?:json)?|```/g,"").trim()):t,n=e&&(e.taskKey||e.target),s=Be.flowReviewTargets;if(!s.length)throw new Error("review lane has no authorized target");if("codex"===Be.runtime&&1!==s.length)throw new Error("Codex review lane must have exactly one authorized target");if(n&&!s.includes(n))throw new Error(`taskKey ${JSON.stringify(n)} is outside this review lane`);if(o=n||(1===s.length?s[0]:null),!o)throw new Error("taskKey is required when reviewing more than one slice")}catch(e){return{ok:!1,message:"codex"===Be.runtime?`Review verdict REJECTED: ${e?.message||e}. Re-call submit_flow_review with a valid authorized taskKey.`:`Review verdict REJECTED: ${e?.message||e}. Re-Write FLOW_REVIEW.json with {"pass":<boolean>,"reasons":["<specific finding>"],"taskKey":"<the slice you reviewed>"}.`}}if(Be.flowReviewConclusion)return{ok:!0,message:`Review already concluded for ${Be.flowReviewConclusion.taskKey}; receipt ${Be.flowReviewConclusion.receipt.cid||"recorded"}.`};const n=Be.flowReviewRound=(Be.flowReviewRound||0)+1;Be.flush?.();const s=dr.get(Be.flowSessionId)||null,i=Gt({round:n,maxRounds:Yt.maxRounds,spentTokens:s?s.spentTokens:0,budgetCap:s?s.capTokens:null,...Et(r)});if(!i.stop){const e=n+1;return Us(Be,"codex"===Be.runtime?`[Flow review — round ${e}/${Yt.maxRounds}] The happy path held, but you have NOT reported your checks exhausted. Dig one more round, then call submit_flow_review again — pass:false with specific evidence if you break it, or pass:true AND exhausted:true only when nothing remains to check.`:`[Flow review — round ${e}/${Yt.maxRounds}] The happy path held, but you have NOT reported your checks exhausted and you are under both the round and budget ceilings. Dig one more round: hunt the edge cases, the reload, the second click, concurrent use, the error path — the places the builder didn't. Then re-Write FLOW_REVIEW.json — pass:false with a specific reason if you break it, or pass:true AND exhausted:true if you genuinely have nothing left to check.`,{rejectionMessage:"The next Flow review round was not accepted; retry after the lane is available."}),process.stderr.write(`\n ${Xi}◆ review round ${n} inconclusive — digging again (${e}/${Yt.maxRounds}) on ${o||Be.flowTaskKey}${Zi}\n`),{ok:!0,message:`Round ${n} recorded (pass, not yet exhausted). Keep hunting — asked you for round ${e}/${Yt.maxRounds}.`}}if("reject"===i.action&&o){const t=await Pa({term:e,flowId:Be.flowSessionId,taskKey:o,reviewTaskKey:Be.flowTaskKey});t.ok||As({kind:"needs-input",term:e,termName:ci[e]||null,summary:`Flow review could not revert ${o}: ${t.error||t.ignored||"unknown error"}`}),process.stderr.write(`\n ${ra}◆ review REJECT (round ${n}) — reverting ${o}: ${r.reasons.join("; ").slice(0,120)}${Zi}\n`)}else process.stderr.write(`\n ${ea}◆ review ${i.action.toUpperCase()} (round ${n}) — ${o||Be.flowTaskKey}${Zi}\n`);const a=o||Be.flowTaskKey,l=Be.flowReviewSnapshots.find(e=>e.taskKey===a)||null,d=Be.flowTaskContract?.digest||null;let u,m=i.action,p=r.reasons.length?r.reasons:[i.reason];try{u=jt({taskKey:a,outcome:"surface"===m?"held":m,rounds:n,candidateSha:l?.sha,acceptanceDigest:d,scope:l?.scopeEvidence,reasons:p})}catch(e){if("pass"!==m)return{ok:!1,message:`Review verdict REJECTED: ${e?.message||e}.`};m="surface",p=[...p,"Exact candidate or sealed acceptance proof is missing; pass was held."],u=jt({taskKey:a,outcome:"held",rounds:n,candidateSha:l?.sha,acceptanceDigest:d,scope:l?.scopeEvidence,reasons:p})}u.cid=c(),Be.flowReviewConclusion={taskKey:a,action:m,round:n,receipt:u},Be.flush?.(),aa(Be,u),ii("code-event",{term:e,evt:u}),Be.flush?.(),ii("flow-review-verdict",{term:e,flowId:Be.flowSessionId,taskKey:a,pass:"pass"===m,reasons:p,action:m,rounds:n,surfaceToPair:"surface"===m||i.surfaceToPair,prompt:Jt({action:m,reason:m===i.action?i.reason:p.at(-1),taskKey:a,findings:p})},Os);let h="";return"pass"===m?h=await He({reviewPass:!0}):("surface"===m&&(ii("flow-review-held",{term:e,flowId:Be.flowSessionId,reviewTaskKey:Be.flowTaskKey,taskKey:o,reasons:p},Os),As({eventId:u.cid,kind:"needs-input",term:e,termName:ci[e]||null,summary:`Flow review held ${a}: ${p.join("; ")||i.reason}`})),"reject"===m&&(Be.flowDone=!0,Be.flush?.(),setTimeout(()=>{try{Ta(e)}catch{}},2500))),{ok:!0,message:`Review verdict recorded: ${"reject"===m?`REJECT (round ${n}) — reverting ${o||"(no target)"} (${p.join("; ").slice(0,140)})`:"surface"===m?`SURFACED to the pair after ${n} round${1===n?"":"s"} — ${p.at(-1)||i.reason}`:`PASS (round ${n})`}.${h?` ${h}`:""}`}})(t));if(Be.id=e,Be.room=zn,ao(zn,e,Be.log.filter(e=>$o(e))),Be.archiveOldestSeq=lo(zn,e),Fs.set(e,Be),Be.scheduleOutcomePending?ji(Be):Fi(Be),Be.log.length&&ca(Be.log)){const t={kind:"result",subtype:"aborted",recovered:!0};yo(t),aa(Be,t),process.stderr.write(`\n ◆ closed an interrupted turn on resume (${e.slice(0,8)}) — restored idle.\n`)}const Xe=Hi("sessions",e);Be.mockupWatcher=Wi(Xe,()=>e,!0);const Ze=It(Xe,ie||process.cwd(),e);for(const e of Ze)xi.set(e.previewId,e);Ze.length&&process.stderr.write(`\n ◆ restored ${Ze.length} thinkpool Design artifact${1===Ze.length?"":"s"} (${e.slice(0,8)}).\n`),Be.viewport=new wt({workspaceRoot:ie||process.cwd(),ownerId:e,roomCode:zn,outbox:Xe,authContext:()=>({accessToken:Dn,supabaseUrl:An}),designContext:()=>{const t=Ai.get(e);return t&&"preview"===t.record.sourceKind?{requestId:t.request.cid,parentRevision:t.record.revision,captureKey:t.record.captureKey}:null}}),Be.log.length&&process.stderr.write(`\n ◆ restored ${Be.log.length} prior events (${e.slice(0,8)})${a?" + resuming live context":""}.\n`);const tt=()=>({sessionId:Be.session?.sessionId||null,runtime:Be.runtime,log:Be.log,commands:Be.commands,mode:Be.mode,effort:Be.effort,model:Be.model||null,models:"hermes"===Be.runtime?Be.models||[]:void 0,provider:Be.provider||null,spawnedBy:Be.spawnedBy,spawnDepth:Be.spawnDepth||0,cascadeRole:Be.cascadeRole||null,hop:Be.hop||0,sideParent:Be.sideParent,sideTask:Be.sideTask,scheduleRunId:Be.scheduleRunId||null,scheduleDeadlineAt:Be.scheduleDeadlineAt||null,scheduleOutcomeRecorded:!0===Be.scheduleOutcomeRecorded,scheduleAdmissionLease:Be.scheduleAdmissionLease||null,pendingSideContexts:Be.pendingSideContexts,pendingWorkerCompletions:Be.pendingWorkerCompletions,workerCompletionsInFlight:Be.workerCompletionsInFlight,sliceType:Be.sliceType,flowSessionId:Be.flowSessionId,flowTaskKey:Be.flowTaskKey,flowTaskContract:Be.flowTaskContract,flowRole:Be.flowRole||null,flowReviewTargets:Be.flowReviewTargets||[],flowReviewSnapshots:Be.flowReviewSnapshots||[],flowReviewRound:Be.flowReviewRound||0,flowReviewConclusion:Be.flowReviewConclusion,dispatchBaseSha:Be.dispatchBaseSha||null,cwd:Be.cwd,managedWorktree:Be.managedWorktree,rolePrompt:Be.rolePrompt,flowReviewTarget:Be.flowReviewTarget||null,revertTarget:Be.revertTarget||null,reviewSliceRoots:Be.reviewSliceRoots||[],openedAt:Be.openedAt||null,lastUsage:Be.lastUsage||null,carryRecap:Be.pendingRecap||null,carryCheckpoint:Be.pendingCheckpoint||null,receivedTurnCids:[...Be.receivedTurnCids].slice(-1e3),mcpFlight:Be.mcpFlight}),ut=()=>Vr(zn,e,tt());if(Be.flush=()=>Qr(zn,e,tt()),Be.flowReviewConclusion?.receipt&&!Be.log.some(e=>e?.cid===Be.flowReviewConclusion.receipt.cid)){const t={...Be.flowReviewConclusion.receipt};aa(Be,t),ii("code-event",{term:e,evt:t}),Be.flush()}Be.scheduleOutcomeRecorded&&Be.scheduleAdmissionLease&&Ei(Be).then(e=>{e&&Be.flush?.()});const mt=!Be.spawnedBy&&!Be.sideParent&&!Be.flowRole&&0===(Be.spawnDepth||0),ht=mt&&"conductor"!==Be.cascadeRole,ft=mt,vt=()=>P().filter(e=>"anthropic"!==e.id).map(e=>`${e.name}${e.model?` (${e.model})`:""}`).join(", "),yt=(e,{worker:t=!1}={})=>{const r=e?.runtime||Be.runtime||"claude";if("codex"===r&&e?.provider)return{error:"A Codex terminal uses its Codex/OpenAI login in v1; custom bridge providers are not wired to Codex yet. Omit provider or open a Claude terminal for that provider."};if("hermes"===r&&e?.provider)return{error:"A Hermes terminal uses its isolated Hermes profile and ACP model catalog; bridge provider IDs do not apply. Omit provider and choose an exact Hermes model ID."};const o="hermes"===Be.runtime&&Be.models?.length?Be.models:[...Fs.values()].flatMap(e=>"hermes"===e.runtime&&e.models||[]),n="codex"===r?H():"hermes"===r?o:[];if("codex"===r&&e?.model&&!ot(n).has(e.model))return{error:`Could not open a Codex terminal on ${JSON.stringify(e.model)} — that model is not in this host's visible Codex catalog.`};const s="hermes"===r?st(e?.model,n,{strictCatalog:"hermes"===Be.runtime}):null;if(s&&!s.ok)return{error:s.error};const i="claude"===r&&e?.provider?I(e.provider):e?.provider;if("claude"===r&&e?.provider&&!i){const t=vt();return{error:`Unknown registered provider ${JSON.stringify(e.provider)}. No lane was opened and the built-in Claude login was not used.${t?` Available provider names: ${t}.`:" No custom providers are registered on this host."}`}}return"claude"===r&&!e?.provider&&e?.model&&/^gpt-/i.test(e.model)?{error:`Could not open a Claude terminal on Codex model ${JSON.stringify(e.model)}. Choose runtime="codex" or a Claude model.`}:{runtime:r,model:s?.model||e?.model||(t&&e?.sliceType?rt({sliceType:e.sliceType,runtime:r,catalog:n}):void 0),mode:t?"bypassPermissions":e?.mode||("plan"===Be.mode?"default":Be.mode),provider:i}},kt=(e=Date.now())=>({runtime:Be.runtime,mode:Be.mode,hop:Be.hop||0,spawnTimes:Be.spawnTimes||[],now:e,spawnedLive:Fr(Fs.values()),totalLive:Fs.size+Ds.size,plan:Ts,disabled:"1"===process.env.TP_SPAWN_OFF}),bt=r=>new Promise(o=>{if(Be.flowSessionId&&"plan"===r.risk)return ii("flow-plan",{term:e,flowId:Be.flowSessionId,plan:r.plan||""},Os),process.stderr.write(`\n ${ta}◆ flow plan ready — flow ${String(Be.flowSessionId).slice(0,8)}.${Zi}\n`),void o("keep");const n=$i(Be,{term:e,id:r.id,toolName:r.toolName,input:r.input,risk:r.risk,plan:r.plan,questions:r.questions,asker:r.asker,answerFormat:r.answerFormat,autoResolutionMs:r.autoResolutionMs}),s={resolve:o,payload:n,timer:null};Be.pending.set(r.id,s),hi(),ii("code-perm-req",n),T(Be)&&Be.permNotifier?.arm(r.id,b(n)),process.stderr.write("plan"===r.risk?`\n ${ta}◆ plan ready — approve in the room.${Zi}\n`:"ask"===r.risk?`\n ${ea}● ${r.asker||le(t)?.label||"Agent"} is asking: ${(r.questions||[]).map(e=>e.question).join(" / ").slice(0,100)} — answer in the room.${Zi}\n`:`\n ${ra}● permission: ${r.toolName}${na(r.input)} — approve in the room.${Zi}\n`);const i=Number(r.autoResolutionMs);"ask"===r.risk&&Number.isFinite(i)&&i>0&&(s.timer=setTimeout(()=>{if(Be.pending.get(r.id)===s){Be.pending.delete(r.id),Be.permNotifier?.resolve(r.id),ii("code-perm",{term:e,id:r.id,decision:"timeout",name:r.asker||"agent"});try{o(fa(s,{decision:"timeout",answers:{}}))}catch{}hi()}},i),s.timer.unref?.())}),$t=Q(()=>U({name:"thinkpool",version:"1.0.0",tools:[...Be.flowRole||"review"===Be.sliceType?[]:[B("read_mcp_flight_recorder","Read the privacy-filtered MCP flight recorder for THIS terminal. Use it to diagnose a tool path or audit recent MCP activity. It reports only the MCP tool name, start time, duration, and outcome; it never records or returns arguments, result bodies, prompts, secrets, or host paths.",{limit:L.number().int().min(1).max(100).optional().describe("maximum recent calls to return (default 40)")},async e=>({content:[{type:"text",text:Bo(Be.mcpFlight,{limit:e?.limit})}]}))],..."hermes"===t&&"ordinary"===ve({flowRole:Be.flowRole,sliceType:Be.sliceType})?[B("request_user_input","Ask the people in this thinkpool room one to three multiple-choice questions and wait for their answer. Use this for choices that genuinely block useful progress. Each question needs two or three mutually exclusive options; a free-text answer remains available in the room card.",{questions:L.array(L.object({id:L.string().min(1).max(80),header:L.string().min(1).max(12),question:L.string().min(1).max(500),options:L.array(L.object({label:L.string().min(1).max(80),description:L.string().min(1).max(240)})).min(2).max(3),multiSelect:L.boolean().optional(),isSecret:L.boolean().optional()})).min(1).max(3),autoResolutionMs:L.number().int().min(6e4).max(24e4).optional()},async e=>{const t=e.questions.map(e=>({...e,options:e.options.map(e=>({...e}))})),r=await bt({id:`hermes-question:${c()}`,toolName:"AskUserQuestion",input:{questions:t},risk:"ask",questions:t,asker:"Hermes",answerFormat:"hermes",autoResolutionMs:e.autoResolutionMs});return{content:[{type:"text",text:JSON.stringify(Ce(r,t))}]}})]:[],...gt({tool:B,z:L,manager:Be.viewport}),B("read_terminal","Read-only view of ANOTHER terminal in this thinkpool Code room (a sibling agent or a shell the people are using). The current ROOM NOW snapshot is the default roster. Call with no arguments only when that snapshot is missing or truncated; this optional full-roster lookup has its own one-call allowance. Call with `terminal` (a ref, id, name, or command) only when that lane’s detailed activity is needed. Targeted transcript reads have a separate bounded allowance: never poll, collect each finished owned worker once, then close it immediately.",{terminal:L.string().optional().describe("ref, id, or command of the terminal to read; omit to list the open terminals"),lines:L.number().int().positive().max(pr.maxLines).optional().describe(`how many recent lines to return (default ${pr.defaultLines})`)},async t=>{const r=fr({selfId:e,sessions:Fs,terms:Ds,names:ci}),o=t?.terminal?wr(r,t.terminal):null;if(t?.terminal&&!o)return{content:[{type:"text",text:mr({selfId:e,sessions:Fs,terms:Ds,names:ci,terminal:t.terminal,lines:t?.lines})}]};const n=hr({targeted:!!t?.terminal,targetedCount:Be.peekCount,rosterCount:Be.peekRosterCount,budgetTurnRev:Be.peekBudgetTurnRev,currentTurnRev:Be._turnRev});if(Be.peekCount=n.targetedCount,Be.peekRosterCount=n.rosterCount,Be.peekBudgetTurnRev=n.budgetTurnRev,!n.ok)return{content:[{type:"text",text:n.reason}]};const s="agent"===o?.kind?Fs.get(o.id):null;return{content:[{type:"text",text:mr({selfId:e,sessions:Fs,terms:Ds,names:ci,terminal:t?.terminal,lines:t?.lines})+Nr({parentRuntime:Be.runtime,parentModels:Be.models,targetRuntime:s?.runtime,targetLog:s?.log})}]}}),...Be.flowRole?[]:[B("search_past_work","Search bounded saved terminal work from THIS thinkpool room. Returns privacy-filtered excerpts for prior decisions, failed attempts, commands, checks, and Flow receipts. Every hit cites the room, terminal, date, and event sequence. It never searches another room, exposes prompts or host paths, or changes state.",{query:L.string().min(2).max(160).describe("specific terms from the prior decision, failure, command, check, or feature"),limit:L.number().int().min(1).max(8).optional().describe("maximum cited hits; default 8")},async e=>{if(Be.pastWorkSearchTurnRev!==Be._turnRev&&(Be.pastWorkSearchTurnRev=Be._turnRev,Be.pastWorkSearchCount=0),(Be.pastWorkSearchCount||0)>=3)return{content:[{type:"text",text:"Past-work search limit reached for this turn (3). Use the cited results already returned or narrow the next room turn."}]};Be.pastWorkSearchCount=(Be.pastWorkSearchCount||0)+1;const t=new Map;for(const e of eo(zn,40))e?.id&&Array.isArray(e.log)&&t.set(e.id,{id:e.id,name:ci[e.id]||e.name||"Archived terminal",savedAt:e.savedAt||e._archivedAt,log:e.log});for(const[e,r]of Fs)t.set(e,{id:e,name:ci[e]||`Terminal ${String(e).slice(0,8)}`,savedAt:r.openedAt||Date.now(),log:r.log||[]});let r;try{r=Ut([...t.values()],e?.query||"",{room:zn,limit:e?.limit})}catch(e){return{content:[{type:"text",text:`Past-work search rejected: ${e?.message||e}`}]}}return{content:[{type:"text",text:Mt(r,e?.query||"")}]}})],B("list_sessions","List OTHER thinkpool Code sessions (rooms) reachable from this room: your own rooms on this machine plus your partner's shared rooms over the pair bus. Returns each room's code, name, and partner host when remote so you can read into one with read_session. This is thinkpool Ensemble across SESSIONS, not just terminals. Read-only.",{},async()=>{const e=e=>({content:[{type:"text",text:e}]});if(Be.pairPeekCount=(Be.pairPeekCount||0)+1,Be.pairPeekCount>br.peekPerTurnCap)return e(`Cross-session read limit reached for this turn (${br.peekPerTurnCap}). Continue with what you have.`);const t=await bi("pair-list-req",{});return e(Tr(t?.rooms,{thisRoom:zn,error:t?.error}))}),B("read_session","Read-only view INTO another thinkpool Code session returned by list_sessions—either your own room on this machine or your partner's shared room over the pair bus. Pass `session` (the room code) and optionally `terminal` (a ref/name in that room) to read its recent activity; omit `terminal` to list that room's terminals. It never changes the other session.",{session:L.string().describe("the room code of the other session (from list_sessions)"),terminal:L.string().optional().describe("ref, id, or name of a terminal in that room; omit to list that room's terminals"),lines:L.number().int().positive().max(pr.maxLines).optional().describe(`how many recent lines to return (default ${pr.defaultLines})`)},async e=>{const t=e=>({content:[{type:"text",text:e}]}),r=String(e?.session||"").toUpperCase().trim();if(!r)return t("Name a room code to read (call list_sessions to see them).");if(r===zn)return t("That is this room — use read_terminal for terminals in your own room.");if(Be.pairPeekCount=(Be.pairPeekCount||0)+1,Be.pairPeekCount>br.peekPerTurnCap)return t(`Cross-session read limit reached for this turn (${br.peekPerTurnCap}). Continue with what you have.`);const o=await bi("pair-peek-req",{targetRoom:r,terminal:e?.terminal,lines:e?.lines},$r.busTimeoutMs+2e3);return t(o?.error?o.error:o?.text||`Room ${r} returned nothing.`)}),...Be.flowRole?[]:[B("post_to_session","Hand a task or message to an agent in ANOTHER of your thinkpool Code sessions — your own room on this machine, or your partner's room reachable through the pair (a room code from list_sessions). Pass `session` (the room code), `text` (what to send), and optionally `terminal` (which agent lane in that room). A person in YOUR room approves sending AND a person in the TARGET room approves receiving before it is delivered. An agent reached this way cannot post onward to a third room. Read the target with read_session first, and use this sparingly — only when the people clearly want the rooms to coordinate.",{session:L.string().describe("the room code of the other session (from list_sessions)"),text:L.string().describe("the message or task to deliver to that room's agent"),terminal:L.string().optional().describe("ref/name of the agent lane in that room; omit if it has a single agent")},async t=>{const r=e=>({content:[{type:"text",text:e}]}),o=Rr({roomHop:Be.roomHop||0,postCount:Be.crossRoomPostCount||0,disabled:"1"===process.env.TP_PAIRBUS_OFF});if(!o.ok)return r(o.reason);const n=String(t?.session||"").toUpperCase().trim();if(!n)return r("Name a room code to post to (call list_sessions to see your rooms).");if(n===zn)return r("That is this room — use post_to_terminal for an agent in your own room.");const s=String(t?.text||"").trim();if(!s)return r("Nothing to send — provide the task or message text.");Be.crossRoomPostCount=(Be.crossRoomPostCount||0)+1;const i=await bi("pair-post-req",{targetRoom:n,terminal:t?.terminal,text:s,fromRoom:zn,fromTerminalName:ci[e]||void 0},18e4);return r(i?.error?i.error:i?.ok?`Delivered to room ${n}${i.ref?` (lane ${i.ref})`:""} — it will respond in its own room; check back with read_session.`:`Room ${n} did not accept the message.`)})],...Be.flowRole?[]:[B("post_to_terminal","Send a message or task to ANOTHER AGENT terminal in this thinkpool Code room. Use `terminal` (a ref/id/command from read_terminal) and `text` (what to send). A person in the room must approve before it is delivered, and an agent reached via a cross-post cannot post onward. Targets agent terminals only, not plain shells. Use read_terminal first to understand the sibling.",{terminal:L.string().describe("ref, id, or command of the AGENT terminal to send to (from read_terminal)"),text:L.string().describe("the message or task to deliver to that terminal")},async t=>{const r=e=>({content:[{type:"text",text:e}]}),o=gr({hop:Be.hop||0,postCount:Be.postCount||0,disabled:"1"===process.env.TP_CROSSPOST_OFF});if(!o.ok)return r(o.reason);const n=fr({selfId:e,sessions:Fs,terms:Ds,names:ci}),s=wr(n,t?.terminal);if(!s)return r(`No terminal matches "${t?.terminal}". Call read_terminal with no argument to list the open terminals.`);if("agent"!==s.kind)return r(`Terminal ${s.ref} is a shell, not an agent — cross-posting is only allowed to agent terminals.`);const i=Fs.get(s.id);if(!i?.session)return r(`Terminal ${s.ref} is no longer live.`);if(!t?.text||!String(t.text).trim())return r("Nothing to send — provide a non-empty `text` for the post.");Be.postCount=(Be.postCount||0)+1;const a=String(e).slice(0,8),c=`[From: terminal ${a}'s agent — relayed via thinkpool cross-terminal, approved by a person in the room]\n${t.text}`;i.hop=(Be.hop||0)+1,i.peekCount=0,i.peekRosterCount=0,i.postCount=0;const l={kind:"you",text:c,by:`terminal ${a} (agent)`,crosspost:!0,relaySourceName:ci[e]||void 0};gi(s.id,t.text);const d=Us(i,c,{visibleEvent:l,rejectionMessage:"The cross-terminal task was not accepted; retry after the lane is available."});return d.accepted?r(`Delivered to terminal ${s.ref} (${s.cmd}). It will respond in its own lane; check back with read_terminal.`):r(d.error?`Could not deliver to terminal ${s.ref} — it may have just closed.`:`Could not deliver to terminal ${s.ref} — it refused the turn. Check its visible host-memory/runtime error.`)})],...ht?[B("open_main_terminal","Open a separate independent MAIN terminal on any supported runtime: Claude (including a connected Anthropic-compatible BYOK provider), Codex, or Hermes. Use this whenever a person asks to open, launch, start, spawn, or create a new, separate, independent, top-level, or main terminal—even for ordinary work or a handoff and even without the words Cascade or conductor. If the wording includes new or separate terminal, main-terminal routing wins. This is the top-level room lifecycle, NOT Ensemble dispatch: the new terminal has no spawnedBy owner and appears as a main terminal. Never substitute spawn_terminal, which creates worker sub-terminals only. Give the main terminal its full initial task; it can use spawn_terminal for bounded workers.",{name:L.string().max(80).optional().describe('short label for the main conductor, e.g. "Cascade · Multi-device chaos"'),task:L.string().min(1).describe("complete initial brief for the independent main terminal"),model:L.string().optional().describe("optional main-terminal model, e.g. opus / gpt-5.6-sol / nous:z-ai/glm-5.2"),runtime:L.enum(["claude","codex","hermes"]).optional().describe("agent runtime; every top-level terminal can open every supported runtime, defaulting to its own"),provider:L.string().optional().describe("optional registered Claude-compatible provider name or id; omit for built-in Anthropic"+(vt()?`. Available now: ${vt()}`:"")),mode:L.enum(["default","acceptEdits","bypassPermissions","plan"]).optional().describe("permission mode; defaults to inheriting this main terminal, except plan falls back to default")},async t=>{const r=e=>({content:[{type:"text",text:e}]}),o=yt(t);if(o.error)return r(o.error);const n=xe("start another Cascade conductor");if(!n.ok)return r(n.reason);const s=(()=>{const e=Date.now(),t=yr({hop:0,spawnTimes:Be.spawnTimes||[],now:e,spawnedLive:0,totalLive:Fs.size+Ds.size,plan:Ts,disabled:"1"===process.env.TP_SPAWN_OFF});return t.ok?(Be.spawnTimes=[...(Be.spawnTimes||[]).filter(t=>Number.isFinite(t)&&t>e-kr.windowMs),e],t):t})();if(!s.ok)return r(s.reason);const i=c(),a=String(i).slice(0,8),l=String(e).slice(0,8);t?.name&&(ci[i]=String(t.name).slice(0,80),so(zn,ci)),ha({id:i,runtime:o.runtime,model:o.model,provider:o.provider,mode:o.mode,spawnDepth:0,cascadeRole:"conductor",hop:0});const d=Fs.get(i);if(!d)return t?.name&&(delete ci[i],so(zn,ci)),r("Could not open the main conductor terminal — the machine terminal cap may have just been reached.");d.peekCount=0,d.peekRosterCount=0,d.postCount=0,d.spawnTimes=[],hi();const u=`[Task from main terminal ${l}'s agent — opened as an independent MAIN CASCADE CONDUCTOR terminal, not an Ensemble child]\n${String(t.task).trim()}`,m={kind:"you",text:u,by:`main terminal ${l} (agent)`,crosspost:!0,relaySourceName:ci[e]||void 0};gi(i,t.task);const p=Us(d,u,{visibleEvent:m,rejectionMessage:"The initial conductor task was not accepted; retry after the lane is available."});return p.accepted?r(`Opened independent main Cascade conductor ${a}${t?.name?` ("${t.name}")`:""} and handed it the task. It is a main terminal, not an Ensemble lane.`):r(p.error?`Opened main conductor ${a}${t?.name?` ("${t.name}")`:""}, but it may still be starting — the initial task could not be delivered.`:`Opened main conductor ${a}, but host pressure prevented its runtime from starting. Existing lanes remain connected; free memory and retry the task.`)})]:[],...ft?[B("spawn_terminal","Open a visible WORKER SUB-TERMINAL on any supported runtime—Claude (including a connected Anthropic-compatible BYOK provider), Codex, or Hermes—from any top-level terminal. spawn_terminal is worker-only: it can never create a Cascade conductor or main terminal. For ordinary workers use an appropriate non-Sol tier: gpt-5.6-luna or gpt-5.4-mini for scaffold/search, gpt-5.6-terra for feature/fix, and a balanced tier for adversarial review; never select Sol for routine workers. A Hermes sliceType=review lane is structurally reviewer-scoped before ACP startup: it can inspect files and use the bridge review-check tool, but has no terminal, write, patch, delegate, browser, skill, memory, or session-history schema. Pass sliceType=scaffold for mechanical work, feature/fix for builders, and review for adversarial verification. Give the worker a bounded initial task, collect its result with read_terminal, then ALWAYS close_terminal it.",{name:L.string().max(80).optional().describe('a short label for the new lane so the room (and you) can find it, e.g. "Research: topologies"'),task:L.string().optional().describe("an initial task to hand the new lane immediately; omit to open it idle"),model:L.string().optional().describe("model for the chosen runtime; Hermes accepts its profile default or an ACP ID such as nous:z-ai/glm-5.2"),sliceType:L.enum(["scaffold","feature","fix","review"]).optional().describe("optional cascade slice tier; omitted preserves normal inheritance/default, explicit model wins"),runtime:L.enum(["claude","codex","hermes"]).optional().describe("agent runtime for the new lane; every top-level terminal can open every supported runtime"),provider:L.string().optional().describe("optional registered Claude-compatible provider name or id; omit for built-in Anthropic"+(vt()?`. Available now: ${vt()}`:"")),mode:L.enum(["default","acceptEdits","bypassPermissions","plan"]).optional().describe("accepted for compatibility; spawned workers always run autonomously in bypassPermissions")},async t=>{const r=e=>({content:[{type:"text",text:e}]}),o=yt(t,{worker:!0});if(o.error)return r(o.error);const n=Date.now(),s=kt(n),i=yr(s);if(!i.ok)return r(i.reason+Ir(e,[...Fs.entries()].map(([e,t])=>({ref:String(e).slice(0,8),name:ci[e]||void 0,spawnedBy:t.spawnedBy,busy:(t.session?.turnActive??!1)||(t.pending?.size??0)>0}))));const a=xe("start another worker lane");if(!a.ok)return r(a.reason);const l={...t,runtime:o.runtime,model:o.model,provider:o.provider,mode:se(o.runtime,{mode:o.mode,sliceType:t?.sliceType})};let d;try{d=Or({args:l,initiatorTerminalId:e,roomCode:zn,bridgeAuthorityId:ds,localAuthorityId:e,context:{...s,providerName:o.provider?x()[o.provider]||o.provider:void 0,resolvedModel:o.model}})}catch(e){return process.stderr.write(`\n ${oa}✗ dispatch preview rejected — ${e?.message||e}${Zi}\n`),r("Dispatch preview could not be built safely. No lane was created.")}const u=Date.now(),m=kt(u),p=Er({preview:d,args:l,initiatorTerminalId:e,roomCode:zn,bridgeAuthorityId:ds,localAuthorityId:e,context:{...m,providerName:o.provider?x()[o.provider]||o.provider:void 0,resolvedModel:o.model}});if(!p.ok)return r(p.reason||"Dispatch became stale or exceeded a cap. No lane was created.");Be.spawnTimes=[...(Be.spawnTimes||[]).filter(e=>Number.isFinite(e)&&e>u-kr.windowMs),u];const h=c(),f=String(h).slice(0,8),w=String(e).slice(0,8);t?.name&&(ci[h]=String(t.name).slice(0,80),so(zn,ci));const g=(Be.spawnDepth||0)+1,v=(Be.hop||0)+1;let y=[];if("review"===t?.sliceType)try{y=[pa(Be.cwd||process.cwd())]}catch(e){return r(`Review lane was not opened: could not pin the spawning parent’s HEAD (${e?.message||e}).`)}ha({id:h,runtime:o.runtime,model:o.model,provider:o.provider,mode:l.mode,sliceType:t?.sliceType,flowReviewTargets:y.map(e=>e.taskKey),flowReviewSnapshots:y,spawnedBy:e,spawnDepth:g,cascadeRole:"worker",hop:v});const k=Fs.get(h);if(!k)return t?.name&&(delete ci[h],so(zn,ci)),r("Could not open a new lane — the terminal cap may have just been reached. Close one and retry.");if(k.peekCount=0,k.peekRosterCount=0,k.postCount=0,k.spawnTimes=[],hi(),t?.task){const o=y.length?`\n\n[Immutable review target: parent at spawn time — target key "parent", pinned HEAD ${y[0].sha}. Use read_review_file with target="parent" for source and run_review_check with target="parent" for fixed checks. Do not infer a target path/ref or mutate anything.]`:"",n=`[Task from terminal ${w}'s agent — relayed via thinkpool Ensemble; you are its WORKER SUB-TERMINAL, never a main terminal or Cascade conductor]\n${t.task}${o}`,s={kind:"you",text:n,by:`terminal ${w} (agent)`,crosspost:!0,relaySourceName:ci[e]||void 0};gi(h,t.task);const i=Us(k,n,{visibleEvent:s,rejectionMessage:"The initial worker task was not accepted; retry after the lane is available."});return i.accepted?r(`Opened agent lane ${f}${t?.name?` ("${t.name}")`:""} and handed it the task. It runs in its own lane — check back with read_terminal, then close_terminal when done.`):r(i.error?`Opened lane ${f}${t?.name?` ("${t.name}")`:""}, but it may still be starting — could not hand off the task. Try post_to_terminal shortly.`:`Opened lane ${f}${t?.name?` ("${t.name}")`:""}, but host pressure prevented its runtime from accepting the task. Existing lanes remain connected; free memory and retry.`)}return r(`Opened idle agent lane ${f}${t?.name?` ("${t.name}")`:""}. Hand it work with post_to_terminal, or a person can type into it.`)})]:[],...Be.flowRole?[]:[B("close_terminal","Close an IDLE agent lane that YOU opened with spawn_terminal (identified by ref/id/name). Active turns and permission waits are protected: collect the completed result with read_terminal before closing. You can only close lanes you spawned yourself — never a sibling someone else is working in, and never the main terminal.",{terminal:L.string().describe("ref, id, or name of the lane you spawned (from read_terminal)")},async t=>{const r=e=>({content:[{type:"text",text:e}]}),o=fr({selfId:e,sessions:Fs,terms:Ds,names:ci}),n=wr(o,t?.terminal);if(!n)return r(`No terminal matches "${t?.terminal}". Call read_terminal with no argument to list the open terminals.`);const s=Fs.get(n.id);if(!s)return r(`Terminal ${n.ref} is not an agent lane (or already closed) — only spawned agent lanes can be closed this way.`);const i=Cr({callerId:e,spawnedBy:s.spawnedBy,busy:(s.session?.turnActive??!1)||(s.pending?.size??0)>0});return i.ok||"not-owner"!==i.reason?i.ok||"busy"!==i.reason?(Ta(n.id),r(`Closed agent lane ${n.ref}${n.name?` ("${n.name}")`:""}.`)):r(`Terminal ${n.ref} is still working or waiting for a permission decision. close_terminal will not kill an active turn. Wait until read_terminal reports it idle/completed, collect its result, then close it. If it is genuinely stuck, ask a person to press Stop.`):r(`Terminal ${n.ref} was not opened by you — you can only close lanes you spawned yourself. Leave it to the person running it.`)})],..."builder"===Be.flowRole?[B("mark_flow_done","thinkpool Flow ONLY — call this ONCE when your slice is built, RUNS, and meets its acceptance criteria. For a gate-first task, pass `baselineEvidence`: the real, bounded pre-edit command/behavior receipt proving the assigned failure/absence. Never fabricate a RED sentence. The bridge derives the edited-file footprint from Git, compares it with the sealed scopePaths, and refuses unexpected touches. Records your latest commit as the slice's atomic-revert target and signals the room that this slice is done (which unblocks slices that depended on you). Do not call before the slice actually runs + meets acceptance.",{baselineEvidence:L.string().max(1400).optional().describe("real single-line pre-edit baseline command/behavior receipt; required for new gate-first tasks")},async e=>({content:[{type:"text",text:await He({baselineEvidence:e?.baselineEvidence||""})}]}))]:[],..."conductor"===Be.flowRole?[B("submit_flow_plan",'thinkpool Flow CONDUCTOR ONLY — submit your decomposition for human approval. Call this ONCE when your task-graph is ready. Pass it as `plan`: a JSON string {"summary":"<one line; assumptions: …>","tasks":[{"key":"<kebab>","title":"…","scope":"human-readable ownership","scopePaths":["repo/file.js","repo/directory/**"],"acceptance":"observable proof","nonGoals":["bounded exclusion"],"baseline":{"gate":"what fails/is absent before edits","evidence":"optional observed receipt"},"deps":["<key>"],"sliceType":"feature|scaffold|review|fix"}]}. Each builder/fix/scaffold needs acceptance, machine-readable repo-relative scopePaths, nonGoals, and a safe bounded baseline gate; review tasks inherit one builder contract. When uncertain, choose and record a safe reversible default; ask only when a choice materially expands scope or authority. The room validates and persists the graph, then shows approval. Do NOT use ExitPlanMode or write a plan file.',{plan:L.string().describe("the task-graph as a JSON string (the {summary, tasks:[…]} object)")},async t=>{const r=e=>({content:[{type:"text",text:e}]});if(!Be.flowSessionId||"conductor"!==Be.flowRole)return r("Not a Flow conductor — there is no flow to submit a plan for.");let o;try{o=Ve(Ye(t?.plan||""),Be.runtime)}catch(e){return r(`Plan REJECTED: ${e?.message||e}. Re-call submit_flow_plan with valid JSON: a non-empty acyclic tasks array; each builder/fix/scaffold has observable acceptance, repo-relative scopePaths, bounded nonGoals, and a safe baseline gate that says what fails/is absent; each review targets exactly one builder contract.`)}return ii("flow-plan",{term:e,flowId:Be.flowSessionId,plan:JSON.stringify(o)},Os),process.stderr.write(`\n ${ta}◆ flow plan submitted — flow ${String(Be.flowSessionId).slice(0,8)} (${o.tasks.length} slice${1===o.tasks.length?"":"s"}).${Zi}\n`),r(`Plan submitted (${o.tasks.length} slice${1===o.tasks.length?"":"s"}) with gate-first contracts. Safe reversible assumptions belong in the summary; user steering remains authoritative. The room is showing approval. You are DONE; stop here and wait for approval (lane dispatch is the room's job).`)})]:[],..."reviewer"===Be.flowRole?[B("submit_flow_review",'thinkpool Flow REVIEWER ONLY — submit one bounded adversarial review round. Pass `verdict` as JSON: {"pass":boolean,"reasons":["specific evidence"],"taskKey":"authorized reviewed task","exhausted":boolean}. This is the only review completion path; do not call mark_flow_done and do not write FLOW_REVIEW.json.',{verdict:L.string().describe("the structured review verdict as a JSON string")},async e=>({content:[{type:"text",text:(await Qe(e?.verdict||"")).message}]}))]:[],..."reviewer"===Be.flowRole||"review"===Be.sliceType?[B("read_review_file","Read one regular file from the declared immutable review target. This always reads the target’s pinned Git object, never a live worktree; target and path are validated and the response is byte-bounded.",{target:L.string(),path:L.string()},async e=>({content:[{type:"text",text:JSON.stringify(await Ht({target:e?.target,filePath:e?.path,snapshots:Be.flowReviewSnapshots}))}]}),Lt),B("run_review_check","Run one fixed verification check against an immutable git-archived review target. This accepts only the declared target and a fixed check id, but executes target-defined code in a scratch archive that is not an OS filesystem/network sandbox. It can require approval and must be refused by approvalPolicy=never reviewers.",{target:L.string(),checkId:L.string()},async e=>({content:[{type:"text",text:JSON.stringify(await zt({target:e?.target,checkId:e?.checkId,snapshots:Be.flowReviewSnapshots}))}]}),Wt)]:[]]})),Tt=r.join(ie||process.cwd(),"FLOW_REVIEW.json"),Rt=Be.reviewSliceRoots.length?({toolName:e,input:t})=>{for(const r of Be.reviewSliceRoots){const o=Bt({toolName:e,input:t,sliceRoot:r,verdictFile:Tt});if(!o.allow)return o}return{allow:!0,reason:"no reviewed slice targeted"}}:null;Be.deferred=!!he;const St=jo(we,ye);Be.pendingRecap=St.pendingRecap,Be.pendingCheckpoint=St.pendingCheckpoint;const Ct=[Cn({spawnedBy:Be.spawnedBy,spawnDepth:Be.spawnDepth,cascadeRole:Be.cascadeRole,flowRole:Be.flowRole,sideParent:Be.sideParent}),ft?xn:""].filter(Boolean).join("\n\n"),xt="claude"===t?C(fe):null;let _t=!1;const At=!0===xt?.policy?.enabled?{policy:xt.policy,providers:N(),providerId:xt.target.providerId,model:xt.target.actualConfiguredModel,requestedModel:Oe||xt.target.actualConfiguredModel,bridgeHostId:fs,circuit:ws,turnRev:()=>(Number(Be._turnRev)||0)+1,capGate:()=>{const t=Be.flowSessionId?dr.get(Be.flowSessionId):null,r=F(t);return r.configured||_t||(_t=!0,process.stderr.write(`\n ${Xi}◇ provider resilience cap_not_configured (${String(e).slice(0,8)})${Zi}\n`)),r}}:null;if(Be.session=X(t,{cwd:ie||process.cwd(),model:Oe,effort:i,resume:a,mode:u,terminalRolePrompt:Ct,rolePrompt:E,prepareCwd:ie||D||q?null:()=>{try{Be.managedWorktree?.dir||(Be.managedWorktree=be({terminalId:e,cwd:process.cwd()})),Be.cwd=Be.managedWorktree.dir,Be.viewport.setWorkspaceRoot(Be.cwd);try{Be.flush?.()}catch{}return Be.cwd}catch(t){return process.stderr.write(`\n ◇ terminal worktree unavailable (${String(e).slice(0,8)}): ${t?.message||t}; using bridge checkout.\n`),ie||process.cwd()}},suggest:!fe||"anthropic"===fe,roomContext:()=>{const t=function(e){const t=e||process.cwd(),r=ma.get(t);if(r&&Date.now()-r.at<6e4)return r.list;let o=[];try{o=s("git",["-C",t,"worktree","list"],{encoding:"utf8",timeout:3e3,stdio:["ignore","pipe","ignore"]}).split("\n").map(e=>e.trim()).filter(Boolean)}catch{o=[]}return ma.set(t,{at:Date.now(),list:o}),o}(ie||process.cwd());return Sr({selfId:e,sessions:Fs,terms:Ds,names:ci,worktrees:t.length>1?t:[]})},lazy:ne({runtime:t,defer:he,cwd:ie,flowSessionId:D,flowTaskKey:q,models:Be.models}),admitStart:()=>xe("start this agent runtime"),reviewGate:Rt,blockSubagents:"conductor"===Be.flowRole,onSubmitPlan:t=>{if(!Be.flowSessionId||"conductor"!==Be.flowRole)return{ok:!1,message:"Not a Flow conductor — nothing to submit."};let r;try{r=Ve(Ye(t||""),Be.runtime)}catch(e){return{ok:!1,message:`Plan REJECTED: ${e?.message||e}. Re-Write FLOW_PLAN.json with valid JSON: a non-empty acyclic tasks array; each builder/fix/scaffold has observable acceptance, bounded nonGoals, and a baseline gate that says what fails/is absent; each review targets exactly one builder contract.`}}return ii("flow-plan",{term:e,flowId:Be.flowSessionId,plan:JSON.stringify(r)},Os),process.stderr.write(`\n ${ta}◆ flow plan submitted — flow ${String(Be.flowSessionId).slice(0,8)} (${r.tasks.length} slice${1===r.tasks.length?"":"s"}).${Zi}\n`),{ok:!0,message:`Plan SUBMITTED (${r.tasks.length} slice${1===r.tasks.length?"":"s"}) with gate-first contracts. Record safe reversible assumptions in the summary; user steering remains authoritative. The room is showing approval. You are DONE: stop here and wait for approval.`}},onLaneDone:"builder"===Be.flowRole?async e=>{let t="";try{const r=JSON.parse(String(e||"").trim());t="string"==typeof r?.baselineEvidence?r.baselineEvidence:""}catch{}return{ok:!0,message:await He({baselineEvidence:t})}}:null,onReviewVerdict:"reviewer"===Be.flowRole?Qe:null,mcpServers:{thinkpool:$t},requiredMcpTools:"hermes"===t?ge(ve({flowRole:Be.flowRole,sliceType:Be.sliceType}),{canSpawnWorkers:ft}):void 0,hermesRole:"hermes"===t?ve({flowRole:Be.flowRole,sliceType:Be.sliceType}):void 0,crossPostGate:()=>gr({hop:Be.hop||0,postCount:Be.postCount||0,disabled:"1"===process.env.TP_CROSSPOST_OFF}),didSpawnTarget:t=>{try{const r=fr({selfId:e,sessions:Fs,terms:Ds,names:ci}),o=wr(r,t);if(!o)return!1;const n=Fs.get(o.id);return!!n&&n.spawnedBy===e}catch{return!1}},crossRoomPostGate:()=>Rr({roomHop:Be.roomHop||0,postCount:Be.crossRoomPostCount||0,disabled:"1"===process.env.TP_PAIRBUS_OFF}),env:{...process.env,...We({flowSessionId:D,mode:u}),...S(fe)||{},TP_MOCKUP_OUTBOX:Xe},resilience:At,onTurnStart:(t={})=>{!0===Be._busyAnn?function(e,t=Date.now()){e._turnRev=(Number(e._turnRev)||0)+1,e._turnStart=t,e._busyAnn=!0,e._settledTurnRev=null,e._turnSettledAt=null}(Be):Ms(Be);const r=t._thinkpoolQueuedEcho;if(r){const t={kind:"you",...r};aa(Be,t),ii("code-event",{term:e,evt:t})}hi()},onEvent:r=>{if(!Ho(r).known)return sa(ia(Be,r)),void hi();const n="system"===r.kind&&pe({current:Be.commands,incoming:ue(t,r.commands),onChanged:e=>{Be.commands=e,hi(),ut()}});if(a&&"error"===r.kind){const t=Be.interruptedRecap||Eo(Be.log,Do),n=Lr(Be,{message:r.message,recap:t,reopen:t=>{Be.imageQueue?.close();try{Be.mockupWatcher?.close()}catch{}return Fs.delete(e),ha({id:e,runtime:Be.runtime,model:Be.model||o,effort:Be.effort,provider:Be.provider,log:Be.log,commands:Be.commands,mode:Be.mode,spawnedBy:Be.spawnedBy,spawnDepth:Be.spawnDepth,cascadeRole:Be.cascadeRole,hop:Be.hop,sideParent:Be.sideParent,sideTask:Be.sideTask,pendingSideContexts:Be.pendingSideContexts,pendingWorkerCompletions:Be.pendingWorkerCompletions,workerCompletionsInFlight:Be.workerCompletionsInFlight,sliceType:Be.sliceType,flowSessionId:Be.flowSessionId,flowTaskKey:Be.flowTaskKey,flowTaskContract:Be.flowTaskContract,flowRole:Be.flowRole,flowReviewTarget:Be.flowReviewTarget,flowReviewTargets:Be.flowReviewTargets,flowReviewSnapshots:Be.flowReviewSnapshots,flowReviewRound:Be.flowReviewRound,flowReviewConclusion:Be.flowReviewConclusion,dispatchBaseSha:Be.dispatchBaseSha,revertTarget:Be.revertTarget,cwd:Be.cwd,managedWorktree:Be.managedWorktree,rolePrompt:Be.rolePrompt,reviewSliceRoots:Be.reviewSliceRoots,openedAt:Be.openedAt,lastUsage:Be.lastUsage,mcpFlight:Be.mcpFlight,carryRecap:t,carryCheckpoint:Be.pendingCheckpoint}),Fs.get(e)||null}});if(n.recovered)return void process.stderr.write(`\n ◆ saved session expired — started fresh with transcript recap (${n.delivery}).\n`)}const s="hermes"===t&&("result"===r.kind||"error"===r.kind)&&(Be.session?.queuedDepth||0)>0;s&&(r.continuesQueued=!0);const i=!s&&"result"===r.kind,c=i?Ar(Be):Ks(Be),l=Rn(r,{turnActive:!0===Be.session?.turnActive});Ws(Be,r),yo(r),i&&(Be._settledTurnRev=Number(r.turnRev)||Number(Be._turnRev)||null,Be._turnSettledAt=Number(r.ts)||Date.now());const d="stalled"===r.kind?!Be.stalled:!!Be.stalled;Be.stalled="stalled"===r.kind,Be.lastEvent=r,"stalled"!==r.kind&&(Be.lastActionAt=r.ts),(c||d)&&hi();{const e=!0===le(Be.runtime)?.canSteer&&(Be.session?.canSteer??!1);e!==Be._canSteerAnn&&(Be._canSteerAnn=e,hi())}{const e="hermes"!==Be.runtime&&(!Be.provider||"anthropic"===Be.provider),t="hermes"===Be.runtime||e?r.model||r.ctx?.model:null;t&&t!==Be.model&&(Be.model=t,hi(),"model-switch"===r.kind&&ut()),"hermes"===Be.runtime&&"models"===r.kind&&Array.isArray(r.models)&&r.models.length?(Be.models=yn(r.models),On=Be.models,hi()):e&&"models"===r.kind&&Array.isArray(r.models)&&r.models.length&&(pi=r.models,hi())}if("model-switch"===r.kind){const t=Be.pendingModelSwitch;Be.pendingModelSwitch=null;const o=r.requested||t?.model||"requested model",n={kind:"control",text:"success"===r.status?`switched model → ${r.model||o}`:`couldn’t switch to ${o} — still using ${Be.model||"the previous model"}`,by:t?.by||null,cid:t?.cid||void 0};aa(Be,n),ii("code-event",{term:e,evt:n}),Be.flush?.(),hi()}if("usage"===r.kind&&(Be.lastUsage=r,ut()),"effort"===r.kind&&(Be.effort=r.level??r.effort??null,ut(),hi()),Be.flowSessionId&&Be.flowTaskKey&&"result"===r.kind&&r.usage){const e=dr.get(Be.flowSessionId);e&&dr.set(Be.flowSessionId,tr(e,r.usage.output_tokens||0))}var u;if("result"===r.kind&&r.usage&&(u=r.usage.output_tokens||0,!Is&&Dn&&zn&&u&&Cs("record_spend",{p_room:zn,p_tokens:u}).catch(()=>{}),function(e,t,r){if(!Dn||!zn||!e)return;const o=t||{},n=(o.input_tokens||0)+(o.cache_creation_input_tokens||0)+(o.cache_read_input_tokens||0),s=o.output_tokens||0,i=o.cache_read_input_tokens||0;(n||s)&&gn(e).then(t=>Cs("record_code_usage",{p_room:zn,p_model:e,p_input:n,p_output:s,p_cached:i,p_provider:r||"unknown",p_input_usd_per_mtok:t?.input??null,p_output_usd_per_mtok:t?.output??null,p_cached_input_usd_per_mtok:t?.cached??null,p_rate_source:t?.source??null})).catch(()=>{})}(r.model,r.usage,Be.provider)),Be.flowSessionId&&Be.flowTaskKey&&!Be.flowDone&&Je({runtime:Be.runtime,flowRole:Be.flowRole,eventKind:r.kind,eventSubtype:r.subtype})&&Promise.resolve().then(()=>He()).catch(()=>{}),"system"===r.kind&&Be.pendingAutoResume&&Wr(Be)&&process.stderr.write(`\n ◆ auto-resumed interrupted turn (${e.slice(0,8)}) — sent continue.\n`),"system"===r.kind&&Be.pendingRecap){const t=Be.pendingRecap.length;Ur(Be)&&process.stderr.write(`\n ◆ carried ${t}c context recap into fresh session (${e.slice(0,8)}) after provider/restore switch.\n`)}"system"===r.kind&&Be.warming&&(e=>{if(e&&e.warming){e.warming=!1,e.warmed=!0,Gs=Math.max(0,Gs-1);try{clearTimeout(e.warmTimer)}catch{}Vs()}})(Be),"compaction"===r.kind&&(da(Be),Be.compacting?(r.by=Be.compactBy||null,Be.compacting=!1,Be.compactBy=null,ii("code-event",{term:e,evt:{kind:"compact",status:"done",ts:Date.now()}})):"auto"===r.trigger&&(ii("code-event",{term:e,evt:{kind:"compact",status:"start",ts:Date.now()}}),setTimeout(()=>{ii("code-event",{term:e,evt:{kind:"compact",status:"done",ts:Date.now()}})},2500)));const m="mode"===r.kind||"usage"===r.kind||"effort"===r.kind||"clear"===r.kind||"compact"===r.kind||"stalled"===r.kind||"suggestion"===r.kind||"assistant_stream"===r.kind||"model-switch"===r.kind;if(("result"===r.kind||"error"===r.kind)&&Be.compacting){const t=Be.compactBy||null;Be.compacting=!1,Be.compactBy=null,ii("code-event",{term:e,evt:{kind:"compact",status:"done",ts:Date.now()}});const o={kind:"control",text:("error"===r.kind?"compaction failed":"aborted"===r.subtype?"compaction canceled":"nothing to compact")+" — context unchanged",by:t};aa(Be,o),ii("code-event",{term:e,evt:o})}if(("result"===r.kind||"error"===r.kind)&&"codex"===Be.runtime&&Be.pendingCodexCompaction){const e=Be.pendingCodexCompaction;Be.pendingCodexCompaction=null,ua(Be,e)}if("result"===r.kind||"error"===r.kind){i&&Be.workerCompletionsInFlight?.length&&(Be.pendingWorkerCompletions=mn(Be.pendingWorkerCompletions,Be.workerCompletionsInFlight),Be.workerCompletionsInFlight=[],Be.flush?.());const t=Ai.get(e);if(t?"result"!==r.kind||r.subtype&&"success"!==r.subtype?Ki(e,"failed",{message:"The producing lane did not complete the edit."}):(t.resultOk=!0,qi({previewId:t.record.previewId,requestId:t.request.cid,state:"verifying",message:"Waiting for correlated desktop and mobile renders…"}),t.timer=setTimeout(()=>Ki(e,"failed",{message:"The edit finished without a correlated desktop and mobile render."}),12e4),t.timer.unref?.(),Mi(e)):(_i.get(e)||[]).length&&queueMicrotask(()=>Ui(e)),Be.sideHandback){const t=Be.sideHandback;Be.sideHandback=null;const o=Fs.get(t.parentId),n="result"!==r.kind||r.subtype&&"success"!==r.subtype?"":String(r.resultText||"").trim()||cn(Be.log,t.afterSeq);if(o&&n){const r=dn({sideId:e,sideName:ci[e],task:Be.sideTask,summary:n});o.pendingSideContexts=an(o.pendingSideContexts,r);const s={kind:"side-handback",sideId:e,sideName:ci[e]||"Side lane",task:Be.sideTask||"",text:n,by:t.by};yo(s),aa(o,s),ii("code-event",{term:t.parentId,evt:s});const i={kind:"control",text:"Brought to main.",by:t.by};yo(i),aa(Be,i),ii("code-event",{term:e,evt:i}),o.flush?.(),Bs(o)}else{const r={kind:"control",text:o?"Couldn’t prepare a handoff — try again.":"The main terminal is no longer available.",by:t.by};yo(r),aa(Be,r),ii("code-event",{term:e,evt:r})}Be.flush?.(),hi()}const o=Be._turnStart;Be._turnStart=null;const n=[...Be.pending.keys()];ya(Be);for(const t of n)ii("code-perm",{term:e,id:t,decision:"deny",name:"agent"});if(i&&Be.spawnedBy&&!String(Be.spawnedBy).startsWith("flow:")){const t=Fs.get(Be.spawnedBy),o=Number(r.turnRev)||Number(Be._turnRev)||0;if(t&&o>0&&Be._ownerNotifiedTurnRev!==o){const n=fn({workerId:e,workerName:ci[e],turnRev:o,subtype:r.subtype});n&&(Be._ownerNotifiedTurnRev=o,t.pendingWorkerCompletions=pn(t.pendingWorkerCompletions,n),t.flush?.(),Ls(t))}}Bs(Be),Ls(Be);const s=Date.now();k({entry:Be,subtype:r.subtype,startedAt:o,now:s})&&As({kind:"turn-done",term:e,termName:ci[e]||null,model:Be.model||null,summary:$("result"===r.kind?r.resultText:r.message),subtype:r.subtype||("error"===r.kind?"error":null),pushEligible:y({entry:Be,subtype:r.subtype,startedAt:o,now:s,minTurnMs:_s})})}const p=Io(r);!function(e,t,r,o,n){e.imageQueue||=new Co({maxPending:Nn.maxPending,maxBytes:Nn.maxBytes,upload:(e,r,o)=>async function(e,t,r,o){return _o({webBase:Pn,room:zn,authToken:Dn,term:e,cid:t,image:r,timeoutMs:Nn.uploadTimeoutMs,activeUploads:o})}(t,e.cid,r,o),onUploadError:e=>process.stderr.write(`\n ◇ screenshot upload failed (${e?.message||e}).\n`),onOverload:({maxPending:e,maxBytes:t})=>process.stderr.write(`\n ◇ screenshot omitted (image queue cap: ${e} pending / ${t} encoded bytes).\n`)}),e.imageQueue.enqueue(r,o,n)}(Be,e,r,p,t=>{if(!n&&(m||aa(Be,t),ii("code-event",{term:e,evt:t}),sa(t),m||ut(),l&&queueMicrotask(()=>{Li.flush(e).catch(()=>{})}),i&&Be.scheduleRunId&&("result"===t.kind||"error"===t.kind))){const e=Be.scheduleTimedOut?{...t,subtype:"runtime_limit"}:t;Di(Be,e,{canceled:!Be.scheduleTimedOut&&"aborted"===t.subtype})}})},requestPermission:bt}),"codex"===t&&Be.session?.usageSnapshot?.context){const{used:e,max:t}=Be.session.usageSnapshot.context;Be.lastUsage={kind:"usage",ctx:{used:e,max:t,pct:Math.min(100,Math.max(0,Math.round(e/t*100))),over:e>t,model:Be.model}}}return Be.log.length||Be.flush(),Ls(Be),hi(),Be.log.length||process.stderr.write(`\n ◆ structured ${le(t)?.label||"agent"} session (${e.slice(0,8)}) — driven from the room.\n`),Be}function fa(e,t={}){const r=t.decision||"deny";return"dispatch"===e?.payload?.answerFormat?{decision:r,dispatchFingerprint:t.dispatchFingerprint||null,controlItemId:t.controlItemId||null}:"ask"===e?.payload?.risk||"codex"===e?.payload?.answerFormat||"hermes"===e?.payload?.answerFormat?{decision:r,answers:t.answers||{},responder:t.responder||null}:r}function wa(e,t=null,r="permission_aborted",o=!1){const n=t||[...e?.pending?.entries?.()||[]].map(([e])=>e);n.length&&e?.id&&(o?w:g)({supabaseUrl:An,anonKey:En,token:Dn,roomCode:zn,bridgeId:ds,terminalId:e.id,permissionIds:n,reason:r}).then(e=>{!e.ok&&process.env.TP_DEBUG&&process.stderr.write(`\n ◇ durable permission cleanup incomplete (${e.code})\n`)})}let ga=!1;async function va(){ga=!0;const e=await g({supabaseUrl:An,anonKey:En,token:Dn,roomCode:zn,currentBridgeId:ds,reason:"bridge_restarted"});return e.ok?ga=!1:process.env.TP_DEBUG&&process.stderr.write(`\n ◇ restored permission cleanup incomplete (${e.code})\n`),e}function ya(e){if(e?.pending){Jr(e),wa(e,null,"permission_aborted");for(const[,t]of e.pending){t?.timer&&clearTimeout(t.timer);try{t.resolve(fa(t,{decision:"deny"}))}catch{}}e.pending.clear(),e.permNotifier?.clearAll()}}function ka(e){if(e?.pending)for(const[t,r]of e.pending)if("plan"!==r?.payload?.risk&&"ask"!==r?.payload?.risk&&"dispatch"!==r?.payload?.answerFormat){r?.timer&&clearTimeout(r.timer);try{r.resolve("allow")}catch{}e.pending.delete(t),e.permNotifier?.resolve(t)}}const ba=new Set(["Write","Edit","MultiEdit","NotebookEdit"]);function $a(e){if(e?.pending)for(const[t,r]of e.pending){const o=r?.payload?.toolName,n=r?.payload?.risk;if("plan"!==n&&"ask"!==n&&"high"!==n&&ba.has(o)){r?.timer&&clearTimeout(r.timer);try{r.resolve("allow")}catch{}e.pending.delete(t),e.permNotifier?.resolve(t)}}}function Ta(e){if(!e)return;const r=Fs.get(e);if(r){Di(r,{subtype:"canceled"},{canceled:!0}),Ni(r),r.imageQueue?.close(),Li.clear(e),ya(r);try{r.session?.end()}catch{}try{r.mockupWatcher?.close()}catch{}try{r.viewport?.stop()?.catch(()=>{})}catch{}const o=Ai.get(e);o?.timer&&clearTimeout(o.timer),Ai.delete(e),_i.delete(e);for(const[t,r]of xi)r.term===e&&xi.delete(t);for(const[t,r]of Pi)r.priorRecord?.term===e&&Pi.delete(t);try{t.rmSync(Hi("sessions",e),{recursive:!0,force:!0})}catch{}Fs.delete(e),ii("term-exit",{id:e}),function(e){h({id:e,token:Dn,supabaseUrl:An,anonKey:En,shuttingDown:zs,onFailure:({error:t,status:r})=>process.stderr.write(`\n ⚠ terminal row reap failed (${String(e).slice(0,8)}${r?`, HTTP ${r}`:""}): ${t||"unknown error"}\n`)})}(e),function(e){if(e)try{const t={"Content-Type":"application/json"};Dn&&(t.Authorization=`Bearer ${Dn}`),fetch(`${Pn}/api/code-image-cleanup`,{method:"POST",headers:t,body:JSON.stringify({code:zn,term:e})}).catch(()=>{})}catch{}}(e);try{$e({terminalId:e,managedWorktree:r.managedWorktree})}catch{}for(const[t,r]of[...Fs])r.spawnedBy!==e&&r.sideParent!==e||Ta(t)}Xr(zn,e),r&&hi()}function Ra(e,t=4e3){if(!e)return;const r=`flow:${e}`;dr.delete(e),setTimeout(()=>{for(const[t,o]of[...Fs])if(o.flowSessionId===e||o.spawnedBy===r)try{Ta(t)}catch{}},t)}function Sa(e){if(e&&Zs!==e){Zs=e;for(const t of Fs.keys())ii("code-event",{term:t,evt:{kind:"update-available",version:e}});hi()}}const Ia=()=>{if(Yr(Fs))return!1;for(const e of Ds.values())if(e.buf)return!1;return!0};async function Ca(){if(!ei||!Zs||ti)return!1;if(process.send&&"1"===process.env.THINKPOOL_PAIR_ACCOUNT_CHILD)return!1;if(!Ia())return!1;ti=!0;try{const e=await import("./service.mjs");if(!e.serviceActive(zn))return!1;const t=!1!==e.updateService(zn);return t||(ti=!1),t}catch(e){return ti=!1,process.stderr.write(`\n ⚠ bridge update failed: ${e?.message||e}\n`),!1}}setInterval(()=>{ei&&Ca()},5e3).unref();const xa=()=>{try{process.stdin.isTTY&&process.stdin.setRawMode(!1)}catch{}};ss&&process.stdin.isTTY&&process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.on("data",e=>{const t=Hs&&Ds.get(Hs);if(t)try{t.term.write(e.toString("utf8"))}catch{}else e.includes(3)&&Ka()}),process.stdout.on("resize",()=>{const e=Hs&&Ds.get(Hs);if(!e)return;const{cols:t,rows:r}=Yi();if(e.term.cols!==t||e.term.rows!==r)try{e.term.resize(t,r),hi()}catch{}});let _a=!1,Aa=Date.now();async function Pa(e){try{return await cr({payload:e,bridgeName:ls,lanes:[...Fs.entries()],prepareLane:(e,t)=>or({lane:{cwd:e.cwd,session:e.session,commitSha:e.commitSha,revertTarget:t.commitSha??e.commitSha??e.revertTarget??null},sanitize:sr}),rememberRedispatch:(e,t,r)=>{lr.set(nr(r.flowId,r.taskKey),{resumeSessionId:e.resumeSessionId,revertTarget:e.revertTarget}),e.healed&&process.stderr.write(`\n ${Xi}◆ flow re-dispatch heal — ${r.taskKey}: ${e.healed} dangling tool block(s) healed before resume.${Zi}\n`)},endLane:e=>{try{Ta(e)}catch{}},stopPreview:_t,wait:()=>new Promise(e=>setTimeout(e,400)),revert:e=>Nt({flowId:e.flowId,taskKey:e.taskKey}),broadcastReverted:e=>{ii("flow-reverted",{term:"flow",flowId:e.flowId,taskKey:e.taskKey,reviewTaskKey:e.reviewTaskKey,branch:e.branch},Os),process.stderr.write(`\n ${ra}◆ flow slice reverted — ${e.taskKey} (${e.branch}).${Zi}\n`)},onPrepError:(e,t,r)=>process.stderr.write(`\n ${ra}◆ flow re-dispatch prep failed (${r.taskKey}): ${e?.message||e} — will re-dispatch fresh.${Zi}\n`)})}catch(e){return process.stderr.write(`\n ${ra}◆ flow revert failed: ${e?.message||e}${Zi}\n`),{ok:!1,error:e?.message||String(e)}}}js.on("broadcast",{event:"apply-update"},()=>{if(Zs&&(ei=!0,process.send&&"1"===process.env.THINKPOOL_PAIR_ACCOUNT_CHILD))try{process.send({t:"apply-update"})}catch{}}).on("broadcast",{event:"bridge-update"},async({payload:e})=>{const t=e?.nonce,r=(e,r,o)=>js.send({type:"broadcast",event:"bridge-update-res",payload:{nonce:t,ok:e,...r?{error:r}:{},...o?{state:o}:{}}});if(!t)return r(!1,"invalid request");const o="string"==typeof e?.v&&/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(e.v)?e.v:null;if(!o)return r(!1,"invalid bridge version");if(Sa(o),ei=!0,process.send&&"1"===process.env.THINKPOOL_PAIR_ACCOUNT_CHILD){try{process.send({t:"apply-update"})}catch{return r(!1,"account supervisor is unavailable")}return r(!0,null,"queued")}let n=!1;try{n=(await import("./service.mjs")).serviceActive(zn)}catch{}return n?Ia()?(await r(!0,null,"applying"),void Ca()):r(!0,null,"queued"):(ei=!1,r(!1,"This bridge is running in a terminal. Restart it once with npx thinkpool-pair@latest, or install the background service to enable remote updates."))}).on("broadcast",{event:"providers-list-req"},({payload:e})=>{js.send({type:"broadcast",event:"providers-list-res",payload:{nonce:e?.nonce,ok:!0,providers:N()}})}).on("broadcast",{event:"provider-switch"},({payload:e})=>{const t=e?.nonce,r=(e,r,o)=>js.send({type:"broadcast",event:"provider-switch-res",payload:{nonce:t,ok:e,...r?{error:r}:{},...void 0===o?{}:{restarted:o}}}),o=e?.term,n=o?Fs.get(o):null;if(!n)return r(!1,"no such live lane");const s=q({provider:e?.provider,currentProvider:n.provider,registeredIds:N().map(e=>e.id)});if(!s.ok)return r(!1,s.error);const i=e?.provider===M?null:e?.provider,a=K({provider:e?.provider,currentProvider:n.provider,sameEnv:E(n.provider,i),targetModel:j(i)});if("noop"===a.action)return r(!0,void 0,!1);if("in-place"===a.action&&function(e,t){const r=Fs.get(e);if(!r?.session)return!1;const o=j(t);if(!o)return!1;r.provider=t||null,r.model=o;try{r.session.setModel(o)}catch{return!1}try{r.flush?.()}catch{}return!0}(o,i))return process.stderr.write(`\n ◆ lane ${String(o).slice(0,8)} switched model → ${j(i)} (same key, context kept).\n`),hi(),r(!0,void 0,!1);const c=function(e,t){const r=Fs.get(e);if(!r)return!1;r.imageQueue?.close();const{runtime:o,log:n,commands:s,mode:i,spawnedBy:a,spawnDepth:c,cascadeRole:l,hop:d,sideParent:u,sideTask:m,pendingSideContexts:p,pendingWorkerCompletions:h,workerCompletionsInFlight:f,sliceType:w,flowSessionId:g,flowTaskKey:v,flowTaskContract:y,flowRole:k,flowReviewTarget:b,flowReviewTargets:$,flowReviewSnapshots:T,flowReviewRound:R,flowReviewConclusion:S,dispatchBaseSha:I,revertTarget:C,cwd:x,managedWorktree:_,rolePrompt:A,reviewSliceRoots:P,openedAt:N,lastUsage:O,mcpFlight:E,pendingCheckpoint:j}=r,D=g?null:Eo(n,Do);ya(r);try{r.session?.end()}catch{}try{r.mockupWatcher?.close()}catch{}try{r.viewport?.stop()?.catch(()=>{})}catch{}return Fs.delete(e),ha({id:e,runtime:o,provider:t,log:n,commands:s,mode:i,spawnedBy:a,spawnDepth:c,cascadeRole:l,hop:d,sideParent:u,sideTask:m,pendingSideContexts:p,pendingWorkerCompletions:h,workerCompletionsInFlight:f,sliceType:w,flowSessionId:g,flowTaskKey:v,flowTaskContract:y,flowRole:k,flowReviewTarget:b,flowReviewTargets:$,flowReviewSnapshots:T,flowReviewRound:R,flowReviewConclusion:S,dispatchBaseSha:I,revertTarget:C,cwd:x,managedWorktree:_,rolePrompt:A,reviewSliceRoots:P,openedAt:N,lastUsage:O,mcpFlight:E,carryRecap:D,carryCheckpoint:j}),!0}(o,i);if(!c)return r(!1,"no such live lane");process.stderr.write(`\n ◆ lane ${String(o).slice(0,8)} switched provider → ${i||"anthropic"} (memory reset, transcript kept).\n`),r(!0,void 0,!0)}).subscribe(e=>{"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e&&"CLOSED"!==e||process.stderr.write(`\n ⚠ private bridge control ${e} (tpcontrol:${zn}).\n`)}),Ns.on("broadcast",{event:"pty-in"},({payload:e})=>{if(!e?.data)return;Xs();const t=Ds.get(e.term)||(null==e.term&&Hs?Ds.get(Hs):null);if(t)try{t.term.write(e.data)}catch{}}).on("broadcast",{event:"resize"},({payload:e})=>{if(!e?.cols||!e?.rows)return;const t=Ds.get(e.term);if(t&&!t.attached)try{t.term.resize(Math.max(e.cols,80),Math.max(e.rows,20)),hi()}catch{}}).on("broadcast",{event:"session-deleted"},async()=>{if(process.stderr.write("\n ◆ this room was deleted — closing the bridge.\n"),"1"===process.env.THINKPOOL_PAIR_AUTOUPDATE)try{(await import("./service.mjs")).uninstallService(zn)}catch{}Ka()}).on("broadcast",{event:"term-open"},async({payload:e})=>{if(!e?.id||!e?.cmd)return;if(e.host&&e.host!==ls)return;if(Ds.has(e.id))return void di(e.id,"pty",Ds.get(e.id));let t=[];if(e.resume){const r=qn.find(t=>t.cmd===e.cmd);if(r?.resume)try{r.resume.probe()&&(t=[...r.resume.args])}catch{}}if(Xn(e.cmd)){const t=Fs.get(e.id);if(t)return void di(e.id,"structured",t);let r=Qn(e.cmd),o=null,n=null;if(e.sideParent){const t=Fs.get(e.sideParent);if(o=t?.sideParent||e.sideParent,n=Fs.get(o),!n||!String(e.sideTask||"").trim())return void ii("side-open-failed",{id:e.id,parent:o,message:n?"Add a task after /side.":"The main terminal is not live."});r=n.runtime||r,e.name&&(ci[e.id]=String(e.name).slice(0,80),so(zn,ci))}if(ha({id:e.id,runtime:r,mode:n?.mode||e.mode,model:n?.model||e.model||void 0,provider:"claude"===r&&(n?.provider||e.provider)||void 0,cwd:n?n.cwd||process.cwd():void 0,sideParent:o||void 0,sideTask:o?String(e.sideTask).trim():void 0,rolePrompt:o?sn:void 0,defer:!0}),o){const t=Fs.get(e.id),r=String(e.sideTask).trim(),s=Array.isArray(e.files)?e.files:[],i=String(e.by||"A room member"),a=ci[e.id]||"Side lane";if(!t)return void ii("side-open-failed",{id:e.id,parent:o,message:"The side lane could not start."});t.hop=0;const c={kind:"you",text:r,by:i,...s.length?{files:s}:{}},l={kind:"side-started",sideId:e.id,sideName:a,task:r,by:i};aa(n,l),ii("code-event",{term:o,evt:l});const d=un(n.log.filter(e=>e.cid!==l.cid)),u=s.map(e=>ye(e,{updir:bs})).filter(Boolean),m=u.length?`${r}\n\n${u.map(e=>`"${e}"`).join(" ")}`:r,p=d?`${d}\n\n--- side task ---\n${m}`:m,h="codex"===t.runtime||"hermes"===t.runtime?await ke(s,{updir:bs}):[];return Us(t,p,{options:h.length?{images:h}:void 0,visibleEvent:c,rejectionMessage:"The side-lane task was not accepted; retry after the lane is available."}).accepted?(t.flush?.(),n.flush?.(),hi(),di(e.id,"structured",t),void process.stderr.write(`\n ◆ ${i} opened side lane ${String(e.id).slice(0,8)} under ${String(o).slice(0,8)}.\n`)):(ii("side-open-failed",{id:e.id,parent:o,message:"The side agent could not start."}),void Ta(e.id))}const s=Fs.get(e.id);return s&&di(e.id,"structured",s),void process.stderr.write(`\n ◆ web opened a structured "${e.cmd}" session (${e.mode||"default"}${e.model?`, model ${e.model}`:""}).\n`)}Vi({id:e.id,cmd:e.cmd,args:t}),Ds.has(e.id)&&di(e.id,"pty",Ds.get(e.id)),process.stderr.write(`\n ◆ web opened a "${e.cmd}"${t.length?" (continue)":""} terminal (headless).\n`)}).on("broadcast",{event:"term-close"},({payload:e})=>{const t=e?.id&&Ds.get(e.id);if(t&&!t.attached)try{t.term.kill()}catch{}else t||Ta(e?.id)}).on("broadcast",{event:"replay-request"},({payload:e})=>{Ri();const t=e?.to??null,r=String(e?.requestId||c?.()||`${Date.now()}`),o=[];for(const[n,s]of Mo(Ds,e?.terms,e?.priority)){if(!s.scrollback)continue;const e=s.scrollback.length>1e5?s.scrollback.slice(-1e5):s.scrollback;o.push({event:"pty-replay",payload:{to:t,term:n,requestId:r,b64:Buffer.from(e,"utf8").toString("base64")}})}const n=Mo(Fs,e?.terms,e?.priority);for(const[s,i]of n){if(!i.log.length){o.push({event:"code-replay",payload:{to:t,term:s,requestId:r,chunkIndex:0,chunkCount:1,events:[],empty:!0}});continue}const n=Number(e?.cursors?.[s])||0,a=bo(i.log),c=n>a,l=(n>0&&!c?i.log.filter(e=>null==e.seq||e.seq>n):i.log).map(e=>So(e)),d=Ro(l),u=c?0:n,m=Fo(qo(d[0]||[]),u,i.archiveOldestSeq);for(let e=0;e<d.length;e++){const n=d[e];o.push({event:"code-replay",payload:{to:t,term:s,requestId:r,chunkIndex:e,chunkCount:d.length,events:n,...c?{reset:!0}:{},...0===e&&null!=m?{trimmedBefore:m}:{},...0===e&&i.lastUsage?.ctx?{lastUsage:i.lastUsage}:{}}})}}ai.enqueue(t||"*",o,async()=>{for(const[,e]of Fs)for(const[,t]of e.pending)await ni("code-perm-req",t.payload);hi()})}).on("broadcast",{event:"history-page-request"},({payload:e})=>{const t=e?.term;if(!t)return;if(!mo({payloadHost:e?.host,bridgeName:ls,hasSession:Fs.has(t),hasArchive:uo(zn,t)}))return;const{events:r,hasMore:o}=co(zn,t,Number(e?.beforeSeq)||null,200),n=e?.to??null,s=String(e?.requestId||c?.()||`${Date.now()}`);if(!r.length)return void ii("history-page",{to:n,term:t,requestId:s,chunkIndex:0,chunkCount:1,events:[],hasMore:!1});const i=Ro(r.map(e=>So(e)));i.forEach((e,r)=>ii("history-page",{to:n,term:t,requestId:s,chunkIndex:r,chunkCount:i.length,events:e,hasMore:0!==r||o}))}).on("broadcast",{event:"file-put"},({payload:e})=>{e?.id&&e?.url&&(e.host&&e.host!==ls||(async()=>{try{const o=ye(e,{updir:bs});if(!o)throw new Error("invalid attachment metadata");const n=await(async e=>{const t=Dn&&(e=>{const t=String(e||""),r=`code/${zn}/`;return!t.startsWith(r)||t.includes("..")||t.split("/").some(e=>!e)?null:`${An}/storage/v1/object/authenticated/session-attachments/${t.split("/").map(encodeURIComponent).join("/")}`})(e?.path),r=[{url:e?.url,headers:void 0},...t?[{url:t,headers:{apikey:En,Authorization:`Bearer ${Dn}`}}]:[]].filter(e=>e.url);let o=new Error("no attachment source");for(let e=0;e<3;e++){for(const e of r)try{const t=await fetch(e.url,{headers:e.headers});if(!t.ok)throw new Error(`HTTP ${t.status}`);return Buffer.from(await t.arrayBuffer())}catch(e){o=e}e<2&&await new Promise(t=>setTimeout(t,250*(e+1)))}throw o})(e);if(n.length>26214400)throw new Error("file too large");t.mkdirSync(bs,{recursive:!0}),t.writeFileSync(o,n),process.stderr.write(`\n ◆ file from the room: ${o}\n`),ii("file-done",{id:e.id,path:o.split(r.sep).join("/"),host:ls})}catch(t){process.stderr.write(`\n ◇ room file download failed (${o=e.name,String(o||"file").replace(/[^a-zA-Z0-9._-]/g,"_").slice(-80)||e.id}): ${t.message}\n`)}var o})())}).on("broadcast",{event:"code-open"},({payload:e})=>{e?.host&&e.host!==ls||ha({id:e?.id||c(),runtime:e?.runtime,model:e?.model,provider:"claude"===e?.runtime?e?.provider:void 0,resume:e?.resume,mode:e?.mode,defer:!0})}).on("broadcast",{event:"side-handback-request"},({payload:e})=>{const t=e?.term&&Fs.get(e.term);if(!t?.sideParent||t.sideParent!==e?.parent)return;const r=String(e?.by||"A room member");if(t.sideHandback||t.session?.turnActive){const o={kind:"control",text:"Finish or stop the current side-lane turn before bringing it to main.",by:r};return yo(o),aa(t,o),void ii("code-event",{term:e.term,evt:o})}t.sideHandback={parentId:t.sideParent,by:r,afterSeq:bo(t.log)};const o={kind:"control",text:"Preparing a compact handoff for main…",by:r};if(yo(o),aa(t,o),ii("code-event",{term:e.term,evt:o}),t.flush?.(),hi(),!Us(t,nn,{rejectionMessage:"The side-lane handoff was not accepted; retry after the lane is available."}).accepted){t.sideHandback=null;const o={kind:"control",text:"Couldn’t start the handoff — try again.",by:r};yo(o),aa(t,o),ii("code-event",{term:e.term,evt:o}),t.flush?.(),hi()}}).on("broadcast",{event:"code-turn"},async({payload:e})=>{const t=e?.term&&Fs.get(e.term);if(!t||null==e.text)return;if(await Ne(t),Fs.get(e.term)!==t||!t.session)return;const r=e.cid&&String(e.cid);if(r){t.receivedTurnCids||(t.receivedTurnCids=new Set);const o=t.receivedTurnCids.has(r)||t.log?.some(e=>e?.cid===r&&("you"===e.kind||"control"===e.kind));if(!o){if(t.receivedTurnCids.add(r),t.receivedTurnCids.size>1e3){const e=t.receivedTurnCids.values().next().value;t.receivedTurnCids.delete(e)}t.flush?.()}if(ii("code-turn-ack",{term:e.term,cid:r,duplicate:o}),o)return}Xs(),t.peekCount=0,t.peekRosterCount=0,t.postCount=0,t.pairPeekCount=0,t.crossRoomPostCount=0,t.spawnTimes=[],t.hop=0,t.roomHop=0;const o=String(e.text),n=function(e){const t=Jr(e);if(!t)return null;const r=e.pending?.get(t.permissionId);wa(e,[t.permissionId],"dispatch_superseded",!0),r?.timer&&clearTimeout(r.timer),e.pending?.delete(t.permissionId),e.permNotifier?.resolve(t.permissionId);try{r?.resolve(fa(r,{decision:"deny"}))}catch{}return t.permissionId}(t);n&&hi(),zr(t);const s=(r,o={})=>{const n={kind:"control",text:r,by:e.by,cid:e.cid,...o};aa(t,n),ii("code-event",{term:e.term,evt:n})};if(/^\/help\s*$/.test(o)&&"hermes"!==t.runtime)return void s(`Available commands · ${me(t.commands)}`);if(/^\/status\s*$/.test(o)&&"hermes"!==t.runtime){const e=le(t.runtime)?.label||t.runtime,r=t.session?.turnActive?"working":"idle";return void s(`${e} · ${r} · model ${t.model||"default"} · ${t.mode||"default"} permissions · effort ${t.effort||"default"}`)}if(/^\/context\s*$/.test(o)&&"hermes"!==t.runtime){const e=t.lastUsage?.ctx;return void s(e?.max?`Context · ${Number(e.used||0).toLocaleString("en-US")} / ${Number(e.max).toLocaleString("en-US")} tokens (${e.pct??Math.round(Number(e.used||0)/Number(e.max)*100)}%)`:"Context usage unavailable until the runtime reports a completed turn")}if(/^\/diff\s*$/.test(o)){try{const e=t.cwd||process.cwd();s(he({cwd:e}))}catch{s("Working-tree diff unavailable outside a readable Git checkout")}return}const i=o.match(/^\/find(?:\s+([\s\S]+))?$/i);if(i){const r={kind:"repo-search",...fe({cwd:t.cwd||process.cwd(),query:i[1]||""}),by:e.by,cid:e.cid};return aa(t,r),void ii("code-event",{term:e.term,evt:r})}if(/^\/credits\s*$/.test(o)&&"hermes"!==t.runtime)return"codex"!==t.runtime||"function"!=typeof t.session?.accountUsage?void s("Credit balance is unavailable for this runtime; use /usage for provider limits"):void Promise.resolve(t.session.accountUsage()).then(e=>{s(Y(e?.limits))}).catch(()=>s("Codex credits unavailable for this account"));const a=o.match(/^\/model\b\s*(\S+)?/);if(a){if(a[1]){if("hermes"===t.runtime&&t.pendingModelSwitch)return void s("finish the current Hermes model switch before choosing another model");if(!1===t.session.setModel(a[1]))return void s(`finish or stop the current ${le(t.runtime)?.label||"agent"} turn before switching models`);if("hermes"===t.runtime)return t.pendingModelSwitch={model:a[1],by:e.by,cid:e.cid},void ii("code-event",{term:e.term,evt:{kind:"model-switch",status:"pending",requested:a[1],ts:Date.now()}});t.model=a[1],hi(),t.flush?.(),s(`switched model → ${a[1]}`)}else s("use /model <name> to switch — e.g. opus, sonnet, haiku");return}if(/^\/clear\s*$/.test(o))return t.pendingRecap=null,t.pendingCheckpoint=null,t.pendingCodexCompaction=null,"codex"===t.runtime||"hermes"===t.runtime?t.session.clearContext?.():t.session.sendTurn(o),t.log=[],t.logBytes=0,t.seq=ko(0),t.archiveOldestSeq=null,ii("code-event",{term:e.term,evt:{kind:"clear"}}),Qr(zn,e.term,{sessionId:t.session?.sessionId||null,log:[]}),void s("context cleared. You can continue with these answers in mind.");if(/^\/compact\s*$/.test(o)){if("codex"===t.runtime){if(t.codexCompactionPromise||t.pendingCodexCompaction)return;return t.session.turnActive?(t.pendingCodexCompaction={by:e.by,cid:e.cid},void s("Compaction queued for after this turn.",{tone:"caution"})):void ua(t,{by:e.by,cid:e.cid})}return t.compacting=!0,t.compactBy=e.by,ii("code-event",{term:e.term,evt:{kind:"compact",status:"start",ts:Date.now()}}),void t.session.sendTurn(o)}if(/^\/usage\s*$/.test(o))return s("codex"===t.runtime?Po(t.model,t.session?.usageSnapshot):Ao(t.model,t.log)),void("codex"===t.runtime?Promise.resolve(t.session?.accountUsage?.()).then(e=>{const t=G(e?.usage);t&&s(t),s(V(e?.limits))}).catch(()=>s("Codex provider limits unavailable")):wn().then(e=>{e&&s(e)}).catch(()=>{}));if("codex"===t.runtime&&/^\/review(?:\s|$)/.test(o)&&(t.flowSessionId||t.flowRole||"review"===t.sliceType))return void s("Native /review is unavailable in Flow and reviewer lanes; their immutable review contract already owns scope and authority");let c=o;const l=[];t.pendingRecap&&(l.push(t.pendingRecap),t.pendingRecap=null),t.pendingCheckpoint&&(l.push(t.pendingCheckpoint),t.pendingCheckpoint=null),t.pendingSideContexts?.length&&(l.push(...t.pendingSideContexts),t.pendingSideContexts=[]),l.length&&(c=No(l,o),t.flush?.());const d="codex"===t.runtime||"hermes"===t.runtime?await ke(e.files,{updir:bs}):[],u="hermes"===t.runtime&&t.session.turnActive&&/^\s*\/queue\s+/i.test(o),m={...d.length?{images:d}:{},...u&&!e.silent?{_thinkpoolQueuedEcho:{text:null!=e.body?String(e.body):o,cid:e.cid,by:e.by,...Array.isArray(e.files)&&e.files.length?{files:e.files}:{},...Array.isArray(e.pastes)&&e.pastes.length?{pastes:e.pastes}:{}}}:{}};Ks(t),gi(e.term,null!=e.body?String(e.body):o);const p=t.session.sendTurn(c,Object.keys(m).length?m:void 0);if(!1===p?Ks(t):Ms(t),u&&!1!==p||(()=>{if(e.silent)return;const r={kind:"you",text:null!=e.body?String(e.body):o,cid:e.cid,by:e.by,...e.authorId?{authorId:e.authorId}:{},...e.steered?{steered:!0}:{},...Array.isArray(e.files)&&e.files.length?{files:e.files}:{},...Array.isArray(e.pastes)&&e.pastes.length?{pastes:e.pastes}:{}};aa(t,r),ii("code-event",{term:e.term,evt:r})})(),!1===p){const r={kind:"error",message:`${le(t.runtime)?.label||"Agent"} did not accept this turn; retry after the lane is available.`,recoverable:!0};aa(t,r),ii("code-event",{term:e.term,evt:r})}if(hi(),!1!==p&&Pe(t,{turnRev:t._turnRev,turnCid:r})&&(ya(t),Ae(t).finally(()=>hi()),hi()),e.pooled&&!e.silent){const r={kind:"pool",text:"dispatched to agent"};aa(t,r),ii("code-event",{term:e.term,evt:r})}}).on("broadcast",{event:"code-perm"},({payload:e})=>{const t=e?.term&&Fs.get(e.term),r=t&&e.id&&t.pending.get(e.id);r&&Jo({supabaseUrl:An,anonKey:En,token:Dn,roomCode:zn,bridgeId:ds,payload:e}).then(o=>{o.ok&&Fs.get(e.term)?.pending.get(e.id)===r?(r.timer&&clearTimeout(r.timer),t.pending.delete(e.id),t.permNotifier?.resolve(e.id),r.resolve(fa(r,{...e,decision:o.decision,answers:o.answers,responder:o.responder})),hi()):!o.ok&&process.env.TP_DEBUG&&process.stderr.write(`\n ◇ ignored unverified permission delivery (${o.code})\n`)})}).on("broadcast",{event:"code-abort"},({payload:e})=>{const t=e?.term&&Fs.get(e.term);if(t){const r=_e(t,e);ii("code-abort-ack",{term:e.term,cid:e.cid,turnRev:e.turnRev,action:r.action,code:r.code,currentTurnRev:r.currentTurnRev}),"abort"===r.action&&(ya(t),Ae(t).finally(()=>hi()),hi())}}).on("broadcast",{event:"code-mode"},({payload:e})=>{const t=e?.term&&Fs.get(e.term);if(t&&Ke.has(e.mode)){if(ie(t)&&e.mode!==t.mode){const r={kind:"control",text:`This ${t.flowRole||"review"} lane is structurally locked to ${t.mode}; Flow and reviewer restrictions take precedence.`};return aa(t,r),ii("code-event",{term:e.term,evt:r}),void hi()}if("codex"===t.runtime||"hermes"===t.runtime){if(!t.session.setMode(e.mode)){const r={kind:"control",text:`finish or stop the current ${le(t.runtime)?.label||"agent"} turn before switching permissions`};return aa(t,r),ii("code-event",{term:e.term,evt:r}),void hi()}return t.mode=e.mode,"bypassPermissions"===e.mode?ka(t):"acceptEdits"===e.mode?$a(t):"plan"===e.mode&&ya(t),t.flush?.(),void hi()}t.mode=e.mode,t.session.setMode(e.mode),"bypassPermissions"===e.mode?ka(t):"acceptEdits"===e.mode&&$a(t),hi()}}).on("broadcast",{event:"code-effort"},({payload:e})=>{const t=e?.term&&Fs.get(e.term),r=new Set(["low","medium","high","xhigh","max"]);if(t&&r.has(e.level)){if(t.session?.turnActive){const r={kind:"control",text:"finish or stop the current turn before switching thinking power"};return aa(t,r),void ii("code-event",{term:e.term,evt:r})}Promise.resolve(t.session.setEffort?.(e.level)).then(r=>{!1!==r&&(t.effort=e.level,t.flush?.(),hi())}).catch(()=>{})}}).on("broadcast",{event:"code-close"},({payload:e})=>{Ta(e?.id)}).on("broadcast",{event:"term-rename"},({payload:e})=>{e?.id&&(li.add(e.id),mi.delete(e.id),e.name?ci[e.id]=String(e.name).slice(0,80):delete ci[e.id],so(zn,ci),hi())}).on("broadcast",{event:"who"},hi).subscribe(async e=>{if("SUBSCRIBED"===e){_a=!0,Aa=0,t={name:ls,role:"bridge",bridge_id:ds,started_at:ps},(Ps||=kn(Ns,{minMs:5e3}))(t);const e=ss||Vn,r=[];if(e&&!Ds.size&&!Fs.size)if(Xn(e)){const e=Zr(zn),t=e=>e._bt||e.openedAt||e.savedAt||0;if(e.sort((e,r)=>t(e)-t(r)),await va(),e.length)for(const t of e){const e=ca(t.log||[]),o=Hr(t,{canResume:to,codexThreadCanResume:J}),n=e?Eo(t.log||[],Do):"";ha({id:t.id,runtime:t.runtime||"claude",model:t.model||void 0,models:t.models,effort:t.effort,provider:"claude"===t.runtime&&t.provider||void 0,resume:o?t.sessionId:void 0,log:t.log,commands:t.commands,mode:t.mode,spawnedBy:t.spawnedBy,spawnDepth:t.spawnDepth,cascadeRole:t.cascadeRole,hop:t.hop,sideParent:t.sideParent,sideTask:t.sideTask,scheduleRunId:t.scheduleRunId,scheduleDeadlineAt:t.scheduleDeadlineAt,scheduleOutcomeRecorded:t.scheduleOutcomeRecorded,scheduleAdmissionLease:t.scheduleAdmissionLease,pendingSideContexts:t.pendingSideContexts,pendingWorkerCompletions:t.pendingWorkerCompletions,workerCompletionsInFlight:t.workerCompletionsInFlight,sliceType:t.sliceType,flowSessionId:t.flowSessionId,flowTaskKey:t.flowTaskKey,flowTaskContract:t.flowTaskContract,flowRole:t.flowRole,flowReviewTarget:t.flowReviewTarget,flowReviewTargets:t.flowReviewTargets,flowReviewSnapshots:t.flowReviewSnapshots,flowReviewRound:t.flowReviewRound,flowReviewConclusion:t.flowReviewConclusion,dispatchBaseSha:t.dispatchBaseSha,revertTarget:t.revertTarget,cwd:t.cwd,managedWorktree:t.managedWorktree,rolePrompt:t.rolePrompt,reviewSliceRoots:t.reviewSliceRoots,openedAt:t.openedAt,lastUsage:t.lastUsage,receivedTurnCids:t.receivedTurnCids,mcpFlight:t.mcpFlight,carryRecap:e?n:t.carryRecap,carryCheckpoint:t.carryCheckpoint,defer:!t.flowSessionId&&!e});const s=Fs.get(t.id),i=[...t.log||[]].reverse().find(e=>"result"===e?.kind||"error"===e?.kind);s&&t.flowTaskKey&&Je({runtime:s.runtime,flowRole:s.flowRole,eventKind:i?.kind,eventSubtype:i?.subtype,interrupted:e})&&setTimeout(()=>{try{s.markFlowDone?.()}catch{}},2e3),s&&e&&(s.pendingInterruptedRecovery={resumable:o,recap:n},r.push(s))}else ss&&ha({id:c(),runtime:Qn(ss)});Ys&&setTimeout(()=>{for(const[,e]of Fs)!e.deferred||e.warmed||e.warming||e.session?.started||Js.push(e);Js.length&&(process.stderr.write(`\n ◆ background-warming ${Js.length} idle terminal(s) (≤3 at a time)…\n`),Vs())},6e3)}else{const t=ro(zn)||c();oo(zn,t),Vi({id:t,cmd:e,args:is,attached:!Vn})}if(await hi(),f({room:zn,hostId:fs,liveIds:[...Ds.keys(),...Fs.keys()],token:Dn,supabaseUrl:An,anonKey:En,shuttingDown:zs,onFailure:({error:e,status:t})=>process.stderr.write(`\n ⚠ terminal row reconcile failed${t?` (HTTP ${t})`:""}: ${e||"unknown error"}\n`)}).then(({reaped:e})=>{e.length&&process.stderr.write(`\n ◆ removed ${e.length} stale terminal row${1===e.length?"":"s"} after restore.\n`)}),process.send&&"1"===process.env.THINKPOOL_PAIR_ACCOUNT_CHILD)try{process.send({t:"room-ready",room:zn,bridgeId:ds})}catch{}r.forEach((e,t)=>{const r=setTimeout(()=>{const t=e.pendingInterruptedRecovery;if(e.pendingInterruptedRecovery=null,!t||Fs.get(e.id)!==e)return;const r=Br(e,t);"sent"===r?process.stderr.write(`\n ◆ auto-resumed interrupted Codex turn (${e.id.slice(0,8)}) — sent continue.\n`):"recap-sent"===r&&process.stderr.write(`\n ◆ resumed interrupted Codex turn (${e.id.slice(0,8)}) with a fresh context recap.\n`)},1e3+5e3*t);r.unref?.()}),setImmediate(()=>{for(const e of Fs.values())if(e.snapshotNeedsCompaction){e.snapshotNeedsCompaction=!1;try{e.flush?.()}catch{}}}),process.stderr.write(Yn?`\n ◆ thinkpool — relaying room ${zn} (headless). Open terminals from the web UI.\n\n`:`\n ◆ thinkpool — sharing "${ss}"${as?" (continuing your latest session)":""} into room ${zn}. Open the web UI and you're both in.\n\n`)}else"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e&&"CLOSED"!==e||(!_a&&Aa||(Aa=Date.now()),_a=!1,process.stderr.write(`\n ⚠ realtime ${e} — reconnecting…\n`));var t}),Os.on("broadcast",{event:"flow-start"},({payload:e})=>{if(!e?.flowId)return;if(e.host&&e.host!==ls)return;for(const[,t]of Fs)if(t.flowSessionId===e.flowId)return;const t=e.originTerm?Fs.get(e.originTerm):null;if(e.originTerm&&!t)return;const r=t?Ze(t.runtime,null):"claude";if(!r)return;const o="codex"===r?t?.models||H():"hermes"===r&&t?.models||[],n=tt({runtime:r,originModel:t?.model,catalog:o}),s=Dr({totalLive:Fs.size+Ds.size,disabled:"1"===process.env.TP_SPAWN_OFF});if(!s.ok)return process.stderr.write(`\n ${ra}◆ flow start held — ${s.reason}${Zi}\n`),void ii("flow-dispatch-held",{term:"flow",flowId:e.flowId,taskKey:null,reason:s.reason},Os);const i=xe("start the Flow conductor");if(!i.ok)return process.stderr.write(`\n ${ra}◆ flow start held — ${i.reason}${Zi}\n`),void ii("flow-host-pressure",{term:"flow",flowId:e.flowId,reason:i.reason},Os);const a=c();ci[a]=`Flow · ${String(e.flowId).slice(0,6)}`,so(zn,ci),ha({id:a,runtime:r,model:n,mode:"codex"===r?"plan":"default",rolePrompt:"claude"===r?Me:Be,flowSessionId:e.flowId,flowRole:"conductor",spawnedBy:`flow:${e.flowId}`});const l=Fs.get(a);l?.session&&Us(l,e.prompt||"",{rejectionMessage:"The Flow conductor task was not accepted; retry after the lane is available."}),process.stderr.write(`\n ${ta}◆ flow conductor launched — flow ${String(e.flowId).slice(0,8)} (plan mode).${Zi}\n`),hi()}).on("broadcast",{event:"flow-dispatch"},({payload:e})=>{if(!e?.flowId||!Array.isArray(e.tasks))return;if(e.host&&e.host!==ls)return;const t=[...Fs.values()].find(t=>t.flowSessionId===e.flowId&&"conductor"===t.flowRole);if(!t)return void process.stderr.write(`\n ${ra}◆ flow dispatch held — this bridge has no live/restored conductor for ${String(e.flowId).slice(0,8)}.${Zi}\n`);const r=Ze(t.runtime,null);if(!r)return;const o="codex"===r?t.models||H():"hermes"===r&&t.models||[],n=[];let i=Fr(Fs.values());const a=rr();if(a.disabled)return void process.stderr.write(`\n ${ra}◆ flow dispatch refused — TP_FLOW_OFF kill-switch is on.${Zi}\n`);const l=e.mode||"guide",d=null!=a.capFromEnv?a.capFromEnv:null!=e.budgetCap?Number(e.budgetCap):null;let u=dr.get(e.flowId)||er({capTokens:d});u.capTokens!==d&&(u={...u,capTokens:d}),dr.set(e.flowId,u);for(const t of e.tasks){if([...Fs.values()].some(r=>r.flowSessionId===e.flowId&&r.flowTaskKey===t.task_key&&!r.flowDone)){process.stderr.write(`\n ${Xi}◆ flow dispatch skip ${t.task_key} — lane already live.${Zi}\n`);continue}const a=Zt({mode:l,budget:u});if(!a.ok){process.stderr.write(`\n ${ra}◆ flow dispatch held (${a.reason}) — ${n.length} spawned this wave.${Zi}\n`);break}const d=jr({spawnedLive:i,totalLive:Fs.size+Ds.size,plan:Ts,disabled:"1"===process.env.TP_SPAWN_OFF});if(!d.ok){process.stderr.write(`\n ${ra}◆ flow dispatch held — ${d.reason} ${n.length} spawned this wave; remaining slices stay queued.${Zi}\n`),ii("flow-dispatch-held",{term:"flow",flowId:e.flowId,taskKey:t.task_key||null,reason:d.reason},Os);break}const m=xe("start another Flow lane");if(!m.ok){process.stderr.write(`\n ${ra}◆ flow dispatch held — ${m.reason}${Zi}\n`),ii("flow-host-pressure",{term:"flow",flowId:e.flowId,reason:m.reason},Os);break}try{const a="review"===t.slice_type;try{Qe(t,{legacy:null==t.contract})}catch(r){process.stderr.write(`\n ${ra}◆ flow dispatch held — ${t.task_key||"task"} failed its sealed acceptance contract: ${r?.message||r}${Zi}\n`),ii("flow-dispatch-held",{term:"flow",flowId:e.flowId,taskKey:t.task_key||null,reason:"sealed acceptance contract mismatch"},Os);continue}if(!Xe(t,r)){process.stderr.write(`\n ${ra}◆ flow dispatch held — ${"hermes"===r?"Hermes":"Codex"} review ${t.task_key} must target exactly one dependency.${Zi}\n`);continue}const{dir:l}=ut({flowId:e.flowId,taskKey:t.task_key});let d=null;try{d=s("git",["-C",l,"rev-parse","HEAD"],{encoding:"utf8"}).trim()}catch{}const u=c();ci[u]=`Flow · ${t.task_key}`,so(zn,ci);const m=nr(e.flowId,t.task_key),p=lr.get(m)||null;p&&lr.delete(m);const h=a?(t.deps||[]).map(t=>mt({flowId:e.flowId,taskKey:t}).dir):[],f=a?(t.deps||[]).map(r=>{const o=mt({flowId:e.flowId,taskKey:r}).dir;let n=null;try{n=s("git",["-C",o,"rev-parse","HEAD"],{encoding:"utf8",timeout:3e3,stdio:["ignore","pipe","ignore"]}).trim()}catch{}let i=null;if(n&&t.contract?.scopePaths?.length){let e=null;try{e=s("git",["-C",o,"merge-base",n,"origin/main"],{encoding:"utf8",timeout:3e3,stdio:["ignore","pipe","ignore"]}).trim()}catch{}const r=ur(o,e,n);if(r){const e=qt({log:[],repoRoot:o,declared:t.contract.scopePaths,changed:r}),n=Kt(t.contract.scopeEvidence);i=n?{...e,read:n.read,verified:n.verified}:e}}return{taskKey:r,cwd:o,sha:n,...i?{scopeEvidence:i}:{}}}).filter(e=>e.sha):[],w=ze({base:"codex"===r||"hermes"===r?a?Pt:Le:a?At:Ue}),g=t.contract?.acceptancePack?.task?.acceptance;ha({id:u,runtime:r,cwd:l,model:et({sliceType:t.slice_type,runtime:r,catalog:o}),mode:se(r,{mode:"bypassPermissions",flowRole:a?"reviewer":"builder"}),rolePrompt:w,flowSessionId:e.flowId,flowTaskKey:t.task_key,flowTaskContract:t.contract||null,flowRole:a?"reviewer":"builder",flowReviewTargets:a&&t.deps||[],flowReviewSnapshots:f,dispatchBaseSha:d,revertTarget:p?.revertTarget||null,spawnedBy:`flow:${e.flowId}`,resume:p?.resumeSessionId||void 0,reviewSliceRoots:h});const v=Fs.get(u);v&&(p&&(v.revertTarget=p.revertTarget??null),a&&(v.flowReviewTarget=t.deps&&t.deps[0]||null),v.session&&!p)&&Us(v,a?`[Flow REVIEW lane — slice "${t.task_key}" of flow ${String(e.flowId).slice(0,8)}]\nYou are ADVERSARIALLY reviewing the slice(s): ${(t.deps||[]).join(", ")||t.title}\n`+(Array.isArray(t.deps)&&t.deps.length?"Reviewed slice worktree(s) — check out + RUN each yourself:\n"+t.deps.map(t=>{const r=mt({flowId:e.flowId,taskKey:t});return` - ${t}: dir ${r.dir} (branch ${r.branch})`}).join("\n")+"\n":"")+`ACCEPTANCE to INDEPENDENTLY verify: ${g||t.acceptance||t.title}\n`+`INHERITED NON-GOALS (must remain untouched): ${(t.contract?.nonGoals||[]).join(" | ")||"(legacy task: none recorded)"}\n`+`INHERITED BASELINE GATE: ${t.contract?.baseline?.gate||"(legacy task: none recorded)"}\n`+`BUILDER BASELINE EVIDENCE (verify; never invent another baseline): ${t.contract?.baseline?.evidence||"(missing — reject unless this is a legacy task)"}\n`+`\nProject (context): ${e.flowPrompt||""}\n\n`+("codex"===r||"hermes"===r?"Review it without mutating the builder worktree. For write-producing install/build/test commands, copy its source into scratch under your own current worktree first. Submit the structured verdict with the thinkpool submit_flow_review MCP tool; never write FLOW_REVIEW.json or call mark_flow_done.":'Review it — run it, hunt for failure. When done, use the Write tool to write FLOW_REVIEW.json with {"pass":<boolean>,"reasons":["<specific finding>"],"taskKey":"<the slice you reviewed>"}. That Write IS your verdict.'):`[Flow lane — slice "${t.task_key}" of flow ${String(e.flowId).slice(0,8)}]\nTITLE: ${t.title}\nSCOPE (files you OWN — edit ONLY these): ${t.scope||"(none stated)"}\nACCEPTANCE (done = this runs + proves it): ${t.acceptance||"(meet the title)"}\nNON-GOALS (must remain untouched): ${(t.contract?.nonGoals||[]).join(" | ")||"(legacy task: none recorded)"}\nBASELINE GATE (before edits, observe this real failure/absence): ${t.contract?.baseline?.gate||"(legacy task: none recorded)"}\nBASELINE EVIDENCE: run/observe the pre-edit gate, then retain one real bounded command/behavior receipt for mark_flow_done; never fabricate a RED sentence.\n`+(t.deps&&t.deps.length?`DEPENDS ON (already built): ${t.deps.join(", ")}\n`:"")+(e=>e?`${e}\n`:"")(He(e.flowId,{baseDir:process.cwd(),deps:t.deps}).text)+`\nProject (context): ${e.flowPrompt||""}\n\nBuild your slice. Own only your files. Done = it runs + meets acceptance. Commit when done.`+("codex"===r||"hermes"===r?" Then call the thinkpool mark_flow_done MCP tool; do not write FLOW_DONE.":""),{rejectionMessage:`Flow slice ${t.task_key} was not accepted; retry after the lane is available.`}),n.push({task_key:t.task_key,laneId:u}),i++}catch(e){process.stderr.write(`\n ${ra}◆ flow dispatch failed for ${t.task_key}: ${e?.message||e}${Zi}\n`)}}n.length&&(ii("flow-dispatched",{term:"flow",flowId:e.flowId,assignments:n},Os),process.stderr.write(`\n ${ta}◆ flow dispatched ${n.length} lane(s) — flow ${String(e.flowId).slice(0,8)}.${Zi}\n`),hi())}).on("broadcast",{event:"flow-assemble"},async({payload:e})=>{if(e?.flowId&&Array.isArray(e.tasks)&&(!e.host||e.host===ls))try{const o=String(e.flowId).replace(/-/g,"").slice(0,8),n=e.tasks.map(t=>mt({flowId:e.flowId,taskKey:t.task_key}).dir).filter(e=>t.existsSync(e));if(!n.length)return void process.stderr.write(`\n ${ra}◆ flow assemble: no lane worktrees for ${o}.${Zi}\n`);const s=r.join(process.cwd(),".claude","worktrees",`flow-${o}-assembled`);t.rmSync(s,{recursive:!0,force:!0});const i=Vt({dirs:n,outDir:s}),a=r.join(s,"index.html");if(t.existsSync(a))try{t.writeFileSync(a,Qt({htmlPath:a,root:s}))}catch(e){process.stderr.write(`\n ${ra}◆ inline failed: ${e?.message||e}${Zi}\n`)}try{Xt({dir:s})}catch{}let c=null;try{c=(await pt({dir:s,id:`assembled:${e.flowId}`})).url}catch{}_t(e.flowId),ii("flow-assembled",{term:"flow",flowId:e.flowId,previewUrl:c,outDir:s,files:i.files,conflicts:i.conflicts},Os),process.stderr.write(`\n ${ta}◆ flow assembled — ${i.files.length} file(s)${i.conflicts.length?`, ${i.conflicts.length} conflict(s)`:""}${c?` · preview ${c}`:""} (flow ${o}).${Zi}\n`),hi(),Ra(e.flowId)}catch(e){process.stderr.write(`\n ${ra}◆ flow assemble failed: ${e?.message||e}${Zi}\n`)}}).on("broadcast",{event:"flow-revert"},async({payload:e})=>{await Pa(e)}).on("broadcast",{event:"flow-cancel"},({payload:e})=>{e?.flowId&&(e.host&&e.host!==ls||(Ra(e.flowId,600),process.stderr.write(`\n ${ra}◆ flow cancelled — closing its lanes (${String(e.flowId).replace(/-/g,"").slice(0,8)}).${Zi}\n`)))}).subscribe(e=>{"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e&&"CLOSED"!==e||process.stderr.write(`\n ⚠ flow realtime ${e} (tpflow:${zn}).\n`)});const Na=new Set;Es.on("broadcast",{event:"design-capability"},({payload:e})=>{const t=e?.previewId&&xi.get(String(e.previewId)),r=t&&Tt(t),o=!!t&&!!r&&r.revision===t.revision&&t.revision===e?.revision&&Fs.has(t.term);Es.send({type:"broadcast",event:"design-capability-res",payload:{previewId:String(e?.previewId||""),revision:String(e?.revision||""),ok:o}})}).on("broadcast",{event:"design-apply"},async({payload:e})=>{const t=xt(e,xi,zn),r=String(e?.previewId||""),o=String(e?.cid||"").slice(0,80);if(!t.ok){const e=Number.isSafeInteger(t.editIndex)?`Edit ${t.editIndex+1}: `:"";return void qi({previewId:r,requestId:o,state:"stale-preview"===t.error?"stale":"failed",message:`${e}${t.error}`})}if(!o||Na.has(o))return;Na.add(o),Na.size>500&&Na.delete(Na.values().next().value);const n=t.record.term,s=_i.get(n)||[];if(_i.set(n,s),s.length>=8)return void qi({previewId:r,requestId:o,state:"failed",message:"Too many Design batches are queued for this lane."});const i="batch"===t.request.mode?t.request.edits:[t.request],a=[];for(let e=0;e<i.length;e++){const t=i[e];if("image"!==t.mode)continue;const n=await $t({webBase:Pn,token:Dn,room:zn,asset:t.asset,requestId:`${o}-${e+1}`,cleanup:!1});if(!n)return void qi({previewId:r,requestId:o,state:"failed",message:`Edit ${e+1}: The private image draft could not be opened.`});t.asset.localPath=n,a.push(t.asset.path)}await Promise.all(a.map(e=>yt({webBase:Pn,token:Dn,room:zn,path:e})));const c=String(e?.by||"A room member").replace(/\0/g,"").trim().slice(0,120)||"A room member";s.push({...t,by:c});const l="batch"===t.request.mode?t.request.edits.length:1;qi({previewId:r,requestId:o,state:"queued",message:`${l} edit${1===l?"":"s"} pooled to the producing lane.`}),Ui(n)}).on("broadcast",{event:"design-restore"},({payload:e})=>{const t=String(e?.previewId||""),r=String(e?.cid||"").slice(0,80),o=xi.get(t),n=Pi.get(t),s=o&&Tt(o);if(!(r&&o&&n?.priorRecord?.backupPath&&s&&s.revision===o.revision&&e?.revision===o.revision))return void qi({previewId:t,requestId:r,state:"stale",message:"That verified revision can no longer be restored safely."});if(Na.has(r))return;Na.add(r);const i=_i.get(o.term)||[];if(_i.set(o.term,i),i.length>=8)return void qi({previewId:t,requestId:r,state:"failed",message:"Too many Design edits are queued for this lane."});const a=String(e?.by||"A room member").replace(/\0/g,"").trim().slice(0,120)||"A room member";i.push({record:o,restoreRecord:n.priorRecord,request:{previewId:t,revision:o.revision,mode:"restore",intent:"restore previous verified revision",target:n.request.target||{selector:"html",tag:"artifact",name:`${n.request.edits?.length||1} pooled edits`},cid:r},by:a}),qi({previewId:t,requestId:r,state:"queued",message:"Restore queued in the producing lane."}),Ui(o.term)}).subscribe(e=>{"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e&&"CLOSED"!==e||process.stderr.write(`\n ⚠ design realtime ${e} (tpdesign:${zn}).\n`)});let Oa=!1;const Ea=e=>{const t=e?.runtime,r=e?.provider_id||"anthropic";return"claude"===t?!(!N().some(e=>e.id===r)||"anthropic"!==r&&e?.model&&j(r)!==e.model):!e?.provider_id&&("codex"===t?!e?.model||ot(H()).has(e.model):"hermes"===t&&(!e?.model||On.some(t=>(t?.id||t?.model)===e.model)))},ja=async()=>{if(!Oa&&!zs&&Dn&&Ss&&us&&Number.isSafeInteger(ms)&&!(ms<1)){Oa=!0;try{if(!await async function(){if(!Dn||!us||!Number.isSafeInteger(ms)||ms<1)return!1;const e=new Map(Zr(zn).map(e=>[e?.id,e]).filter(([e])=>e));for(const{terminalId:t,intent:r,acknowledged:o}of go(zn)){if(o){fo(zn,t);continue}const n=Vo(r);if(!n){fo(zn,t);continue}let s=Fs.get(t);const i=e.get(t);(!0===s?.scheduleOutcomeRecorded?s.scheduleRunId:!0===i?.scheduleOutcomeRecorded?i.scheduleRunId:null)!==n.runId?!s&&i||s&&s.scheduleRunId&&s.scheduleRunId!==n.runId||(s||(s={id:t,scheduleRunId:n.runId,scheduleOutcomeRecorded:!1}),s.scheduleOutcomePending=n,await ji(s)):fo(zn,t)}return Qo(go(zn))}())return;if(!tn())return;const e=await Yo({enabled:!0,supabaseUrl:An,anonKey:En,token:Dn,roomCode:zn,bridgeId:us,bridgeFencing:ms,ownerId:Ss,providerAvailable:Ea,admitRun:async({runId:e,terminalId:t,deadlineAt:r})=>{const o=Zo({spawnTimes:[],totalLive:Fs.size+Ds.size,disabled:"1"===process.env.TP_SPAWN_OFF});return o.ok?rn({runId:e,terminalId:t,deadlineAt:r}):o},releaseRun:e=>on(e),openTerminal:async({schedule:e,run:t,terminalId:r,admission:o})=>{const n=Date.parse(t.lease_expires_at),s=Number.isFinite(n)?n-6e4:NaN;if(!Number.isFinite(s)||s<=Date.now())return null;const i=ha({id:r,runtime:e.runtime,provider:e.provider_id||void 0,model:e.model||void 0,mode:"default",scheduleRunId:t.id,scheduleDeadlineAt:s,scheduleAdmissionLease:o});if(!i)return null;ci[r]=String(e.title||"Scheduled run").slice(0,80),so(zn,ci);const a=Us(i,String(e.prompt||""),{visibleEvent:{kind:"you",text:String(e.prompt||""),by:"Scheduled run"},rejectionMessage:"The scheduled run could not start; no hidden fallback was used."});return a?.accepted?(Fi(i),i.flush?.(),hi(),r):(i.scheduleRunId=null,Ni(i),Ta(r),null)}});!e.ok&&process.env.TP_DEBUG&&"runner_read_failed"!==e.code&&process.stderr.write(`\n ◇ scheduled-run poll: ${e.code}\n`)}finally{Oa=!1}}};ja(),setInterval(()=>{ja()},15e3).unref();let Da=!1,Fa=0,qa=0;if(setInterval(async()=>{if(_a||!Aa)return Fa=0,void(qa=0);const e=Date.now();if(e-Aa<6e4||Da||e<qa)return;Da=!0;const t=await(async()=>{const e=new AbortController,t=setTimeout(()=>e.abort(),5e3);try{return(await fetch(`${An}/auth/v1/health`,{headers:{apikey:En},signal:e.signal})).ok}catch{return!1}finally{clearTimeout(t)}})(),r=Gr({brokenSince:Aa,now:Date.now(),httpHealthy:t,activeTurn:Yr(Fs)});if("restart"===r)return process.stderr.write("\n ⚠ realtime wedged while HTTP is healthy — exiting for a clean restart.\n"),void Ka(1);const o=bn(Fa);Fa+=1,qa=Date.now()+o,process.stderr.write(`\n ◇ realtime unavailable (${r}) — preserving local agents; retrying in ${Math.round(o/1e3)}s.\n`);try{$s.realtime?.disconnect?.()}catch{}try{$s.realtime?.connect?.()}catch{}Da=!1},15e3).unref(),"1"===process.env.THINKPOOL_PAIR_AUTOUPDATE&&ys){const e=1e3*Math.max(60,parseInt(process.env.THINKPOOL_PAIR_UPDATE_INTERVAL,10)||1800),t=1e3*Math.max(10,parseInt(process.env.THINKPOOL_PAIR_UPDATE_IDLE,10)||90),r=()=>{if(Yr(Fs))return!1;for(const e of Ds.values())if(e.buf)return!1;return!0},o=()=>r()&&Date.now()-Qs>=t,n=(e,t)=>{const r=e=>String(e).split("-")[0].split(".").map(e=>parseInt(e,10)||0),o=r(e),n=r(t);for(let e=0;e<3;e++){if((o[e]||0)>(n[e]||0))return!0;if((o[e]||0)<(n[e]||0))return!1}return!1},s=async()=>{const e=new AbortController,t=setTimeout(()=>e.abort(),8e3);try{const t=await fetch("https://registry.npmjs.org/thinkpool-pair/latest",{signal:e.signal,headers:{accept:"application/json"}});if(!t.ok)return null;const r=await t.json();return"string"==typeof r?.version?r.version:null}catch{return null}finally{clearTimeout(t)}},i=()=>{if(Zs){if(ei){if(!r())return}else if(!o()||ri())return;process.stderr.write(`\n ◆ thinkpool-pair ${Zs} ready (running ${ys}) — restarting to update; the session resumes.\n`),Ka(0,!1)}},a=async()=>{const e=await s();e&&n(e,ys)&&(Zs||process.stderr.write(`\n ◆ thinkpool-pair ${e} published — "update ready" in the room; applies between turns.\n`),Sa(e),i())};setInterval(a,e).unref(),setInterval(i,15e3).unref(),setTimeout(a,6e4).unref()}else if(process.send&&"1"===process.env.THINKPOOL_PAIR_ACCOUNT_CHILD){const e=1e3*Math.max(10,parseInt(process.env.THINKPOOL_PAIR_UPDATE_IDLE,10)||90),t=()=>{if(Yr(Fs))return!1;for(const e of Ds.values())if(e.buf)return!1;return!0},r=()=>t()&&Date.now()-Qs>=e;process.on("message",e=>{if(e)if("update-available"===e.t)Sa(e.version);else if("agent-visibility-changed"===e.t)hi();else if("restart-probe"===e.t)try{process.send({t:"restart-probe-result",nonce:e.nonce,between:t()})}catch{}else"token"===e.t&&(Dn=e.accessToken||null,Ct($s,Dn,En).then(e=>{!e&&Dn&&process.stderr.write("\n ⚠ realtime auth refresh failed; private bridge features may need a reconnect.\n")}),Rs(),ga&&va())}),setInterval(()=>{try{process.send({t:"idle",idle:r(),between:t(),webPeer:ri()})}catch{}},5e3).unref()}else ys&&setTimeout(async()=>{try{const e=new AbortController,t=setTimeout(()=>e.abort(),8e3),r=await fetch("https://registry.npmjs.org/thinkpool-pair/latest",{signal:e.signal,headers:{accept:"application/json"}}).finally(()=>clearTimeout(t));if(!r.ok)return;const o=await r.json(),n="string"==typeof o?.version?o.version:null;if(!n)return;const s=e=>String(e).split("-")[0].split(".").map(e=>parseInt(e,10)||0),i=s(n),a=s(ys);let c=!1;for(let e=0;e<3;e++){if((i[e]||0)>(a[e]||0)){c=!0;break}if((i[e]||0)<(a[e]||0))break}c&&process.stderr.write(`\n ◆ thinkpool-pair ${n} is out (you're on ${ys}).\n To update: stop this bridge (Ctrl-C), then rerun:\n npx thinkpool-pair@latest ${zn}\n Your session resumes on restart (you'll be asked to continue it).\n For hands-off updates with no interruption, install the background\n service: npx thinkpool-pair@latest install-service ${zn}\n`)}catch{}},6e4).unref();async function Ka(e=0,t=!0){if(!zs){zs=!0,si.close(),setTimeout(()=>process.exit(e),1500),clearInterval(Si);try{ht()}catch{}try{vt.close().catch(()=>{})}catch{}if(t)try{const e=Buffer.from("\r\n[ shared session ended ]\r\n","utf8").toString("base64");for(const t of Ds.keys())ii("pty-out",{term:t,b64:e})}catch{}for(const e of Fs.values())try{e.imageQueue?.close()}catch{}for(const e of Fs.values())try{e.flush?.()}catch{}for(const e of Ds.values())try{e.term.kill()}catch{}for(const e of Fs.values())try{e.session.end()}catch{}xa();try{await Ns.untrack()}catch{}try{await $s.removeChannel(Ns)}catch{}try{ki&&await $s.removeChannel(ki)}catch{}try{await $s.removeChannel(Os)}catch{}try{await $s.removeChannel(Es)}catch{}try{await $s.removeChannel(js)}catch{}setTimeout(()=>process.exit(e),250)}}process.on("SIGINT",()=>Ka(0)),process.on("SIGTERM",()=>Ka(0)),process.on("uncaughtException",e=>{if(!e||"EPIPE"!==e.code&&"ECONNRESET"!==e.code&&"ERR_STREAM_WRITE_AFTER_END"!==e.code&&"ERR_STREAM_DESTROYED"!==e.code){try{process.stderr.write(`\n ⚠ uncaughtException: ${e?.stack||e}\n ◆ shutting down cleanly for a fresh respawn.\n`)}catch{}Ka(1)}else try{process.stderr.write(`\n ⚠ ignored benign ${e.code} (not fatal): ${e?.message||""}\n`)}catch{}}),process.on("unhandledRejection",e=>{try{process.stderr.write(`\n ⚠ unhandledRejection (non-fatal, continuing): ${e?.stack||e}\n`)}catch{}});
|
|
2
|
+
import e from"node:os";import t from"node:fs";import r from"node:path";import o from"node:readline";import{spawn as n,execFileSync as s}from"node:child_process";import{fileURLToPath as i}from"node:url";import{createRequire as a}from"node:module";import{randomUUID as c}from"node:crypto";import{createClient as l}from"@supabase/supabase-js";import{serveDecision as d,fetchServeRow as u,refusalMessage as m,gateFailAction as p}from"./serve-consent.mjs";import{reapTerminalRow as h}from"./reap-terminal.mjs";import{reconcileTerminalRows as f}from"./terminal-row-reconcile.mjs";import{cancelDurableDispatchPermissions as w,cancelDurablePermissions as v}from"./dispatch-permission-cleanup.mjs";import{createPermNotifier as g,shouldNotifyTurnDone as y,shouldRecordTurnDone as k,permissionSummary as b,clipSummary as $,isUserFacingLane as T,DEFAULT_MIN_TURN_MS as R}from"./agent-notify.mjs";import{resolveProviderEnv as I,resolveProviderRef as S,resolveProviderResiliencePolicy as C,providerNameMap as x,publicKeyB64 as _,bridgeHostId as A,announceProviders as P,listProviders as N,effectiveLaneModel as O,sameProviderEnv as E,providerModel as D}from"./providers.mjs";import{createMemoryCircuit as j,providerResilienceCapAdmission as q}from"./provider-resilience.mjs";import{validateProviderSwitch as K,providerSwitchPlan as M,BUILTIN_PROVIDER as F}from"./switch-provider.mjs";import{createSdkMcpServer as U,tool as B}from"@anthropic-ai/claude-agent-sdk";import{z as L}from"zod";import{readCodexDefaultModel as W,readCodexModels as H,codexConfigForMode as z,codexThreadCanResume as J}from"./codex-session.mjs";import{codexAccountUsageLine as G,codexCreditsReportLine as Y,codexLimitReportLine as V}from"./codex-commands.mjs";import{withMcpSessionFactory as Q}from"./codex-mcp-http.mjs";import{startStructuredSession as X}from"./runtime-session.mjs";import{admitRuntimeCapability as Z}from"./runtime-contract.mjs";import{cleanTerminalName as ee,modelTerminalNameInput as te}from"./terminal-name.mjs";import{defaultStructuredMode as re,normalizeStructuredEffort as oe,shouldDeferStructuredRuntime as ne,structuredModeForSlice as se,structuredModeLocked as ie,structuredModesForLane as ae,structuredRuntimeForCommand as ce,structuredRuntimeMetadata as le,structuredRuntimeSupportsMode as de}from"./runtime-registry.mjs";import{commandCatalogForRuntime as ue,commandHelpLine as me,reconcileCommandCatalog as pe}from"./command-catalog.mjs";import{gitDiffReport as he}from"./git-diff-report.mjs";import{repoSearch as fe}from"./repo-search.mjs";import{probeHermesRuntime as we}from"./hermes-probe.mjs";import{hermesRequiredMcpTools as ve,hermesRoleFor as ge}from"./hermes-policy.mjs";import{canonicalRoomFilePath as ye,waitForNativeImages as ke}from"./codex-images.mjs";import{createManagedLaneWorktree as be,removeManagedLaneWorktree as $e}from"./lane-worktree.mjs";import{commandOnPath as Te}from"./agent-detect.mjs";import{agentVisibilityStates as Re}from"./agent-visibility.mjs";import{requiresSdkAdmission as Ie,sdkSmokePassed as Se}from"./sdk-admission.mjs";import{hermesUserInputResponse as Ce}from"./question-response.mjs";import{hostMemoryAdmission as xe}from"./host-memory.mjs";import{HostCapacityAuthority as _e}from"./host-capacity.mjs";import{admitAbortRequest as Ae,queueAbortBarrier as Pe,takePendingAbortRequest as Ne,waitForAbortBarrier as Oe}from"./abort-turn-barrier.mjs";import{PAIR_CLI as Ee,pairCli as De}from"./command-guidance.mjs";import{explicitKeepAwakeChoice as je,keepAwakeEnabled as qe,saveKeepAwakePreference as Ke,startKeepAwake as Me}from"./keep-awake.mjs";const Fe=new Set(["default","acceptEdits","plan","review","bypassPermissions"]);import{FLOW_CONDUCTOR_PROMPT as Ue,FLOW_LANE_PROMPT as Be,FLOW_CODEX_CONDUCTOR_PROMPT as Le,FLOW_CODEX_LANE_PROMPT as We,buildConductorEnv as He,assembleCrossWaveContext as ze,buildLanePrompt as Je}from"./flow-conductor.mjs";import{legacyBuilderCompletionAllowed as Ge,normalizeBaselineEvidence as Ye,normalizePlanOutput as Ve,validatePlanForRuntime as Qe,validateTaskContractSeal as Xe,validReviewTargetShape as Ze}from"./flow-task-graph.mjs";import{normalizeFlowRuntime as et,flowLaneModelFor as tt,flowConductorModelFor as rt,spawnedLaneModelFor as ot,modelCatalogValues as nt,resolveCodexModel as st,resolveHermesOpenModel as it,assertRuntimeModelCompatible as at}from"./flow-models.mjs";import{writeLaneArtifact as ct,digestSlice as lt,appendDigest as dt,resumeLane as ut}from"./flow-context-store.mjs";import{createFlowWorktree as mt,worktreeSpec as pt}from"./flow-worktree.mjs";import{startPreview as ht,stopAllPreviews as ft,previews as wt}from"./flow-preview.mjs";import{ViewportManager as vt,createViewportTools as gt,sharedViewportBrowser as yt}from"./viewport.mjs";import{deleteDesignAssetDraft as kt,designPrompt as bt,designTranscript as $t,materializeDesignAsset as Tt,refreshDesignSource as Rt,resolveManifestDesignSource as It,resolveManifestDisplaySource as St,restoreDesignSources as Ct,syncRealtimeAuth as xt,validateDesignBatchRequest as _t}from"./design-edit.mjs";function At(e,t=null){for(const[r,o]of wt)if("string"==typeof r&&(t?r===`lane:${e}:${t}`:r.startsWith(`lane:${e}:`)))try{o.stop()}catch{}}import{FLOW_REVIEWER_PROMPT as Pt,FLOW_CODEX_REVIEWER_PROMPT as Nt,revertLane as Ot,parseReviewVerdict as Et,reviewVerdictToReflection as Dt}from"./flow-review.mjs";import{createFlowReviewReceipt as jt,createFlowReviewSingleFlight as qt,isFlowReviewReceipt as Kt}from"./flow-receipt.mjs";import{collectFlowScopeEvidence as Mt,normalizeFlowScopeEvidence as Ft}from"./flow-scope-evidence.mjs";import{formatPastWorkSearch as Ut,searchPastWork as Bt}from"./past-work-search.mjs";import{reviewGateDecision as Lt}from"./flow-review-gate.mjs";import{IMMUTABLE_REVIEW_READ_TOOL_EXTRAS as Wt,UNSANDBOXED_REVIEW_CHECK_TOOL_EXTRAS as Ht,readReviewFile as zt,runReviewCheck as Jt}from"./review-check.mjs";import{pairAdjudicationPrompt as Gt,reviewReflectionDecision as Yt,REVIEW_DEFAULTS as Vt}from"./flow-review-reflect.mjs";import{mergeWorktrees as Qt,inlineSingleHtml as Xt,initRepo as Zt}from"./flow-assembly.mjs";import{canDispatch as er,makeBudget as tr,recordSpend as rr,killSwitchEnv as or}from"./flow-budget.mjs";import{prepareRedispatch as nr,redispatchKey as sr}from"./flow-redispatch.mjs";import{sanitizeSession as ir}from"./transcript-sanitize.mjs";import{boundStructuredLog as ar,STRUCTURED_LOG_BYTE_CAP as cr}from"./event-bounds.mjs";import{executeFlowRevert as lr}from"./flow-host-revert.mjs";const dr=new Map,ur=new Set,mr=new Map,pr=(e,t,r)=>{if(!e||!t||!r)return null;try{return s("git",["-C",e,"diff","--name-only","--diff-filter=ACMRD",`${t}..${r}`],{encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]}).split("\n").map(e=>e.trim()).filter(Boolean)}catch{return null}};import{formatPeek as hr,PEEK as fr,readTerminalTurnBudgetDecision as wr,siblingsOf as vr,resolveSibling as gr,crossPostDecision as yr,CROSSPOST as kr,spawnDecision as br,SPAWN as $r,CROSSROOM as Tr,CROSSROOM_BUS as Rr,formatPairRoster as Ir,crossRoomPostDecision as Sr,formatRoomNow as Cr,formatClosableHint as xr,closeLaneDecision as _r,laneBusyOf as Ar,laneStatusOf as Pr,settleLaneBusy as Nr,settleLaneControl as Or,nativeClaudeFallbackHint as Er,buildDispatchPreview as Dr,authorizeDirectDispatch as jr,activeWorkerCapacityDecision as qr,machineCapacityDecision as Kr,countActiveDispatchedWorkers as Mr,maxSpawnedFor as Fr}from"./cross-terminal.mjs";import{createStandalonePairResponder as Ur,standalonePairIdentity as Br}from"./direct-pair-room.mjs";import{dispatchPendingRecap as Lr,recoverInterruptedTurn as Wr,recoverMissingResumeOnce as Hr,sendInterruptedContinue as zr,shouldAttemptNativeResume as Jr,supersedeInterruptedResume as Gr}from"./interrupted-resume.mjs";import{supersedeDispatchLease as Yr}from"./dispatch-lease.mjs";import{realtimeRecoveryDecision as Vr,turnInFlight as Qr}from"./update-gate.mjs";import{saveSession as Xr,flushSession as Zr,deleteSession as eo,loadAll as to,loadArchived as ro,canResume as oo,loadPtyId as no,savePtyId as so,loadNames as io,saveNames as ao,appendDurableEvents as co,seedDurableEvents as lo,readDurablePage as uo,readDurableOldestSeq as mo,hasDurableArchive as po,servesHistoryPage as ho,acknowledgePendingScheduledOutcome as fo,commitRecordedScheduledOutcome as wo,deletePendingScheduledOutcome as vo,loadPendingScheduledOutcome as go,loadPendingScheduledOutcomes as yo,savePendingScheduledOutcome as ko}from"./session-store.mjs";import{stampEvent as bo,makeSeqCounter as $o,maxSeq as To,seqable as Ro,capReplayEvents as Io,chunkReplayEvents as So,boundEventForBroadcast as Co,inlineImageBlocks as xo,ImageEventQueue as _o,imageQueueConfig as Ao,uploadCodeImage as Po,usageReportLine as No,codexUsageReportLine as Oo,appendCurrentPersonRequest as Eo,buildCheckpointFromLog as Do,buildRecapFromLog as jo,resolveCheckpointCarry as qo,RECAP_CAP as Ko,trimmedBeforeSeq as Mo,firstSeq as Fo}from"./event-id.mjs";import{createLatestReplayPump as Uo,requestedReplayIds as Bo}from"./replay-transport.mjs";import{createEventDeliveryQueue as Lo}from"./event-delivery-queue.mjs";import{formatMcpFlight as Wo,normalizeMcpFlight as Ho,recordMcpFlightEvent as zo}from"./mcp-flight-recorder.mjs";import{classifyCodeEvent as Jo,unknownCodeEventNotice as Go}from"./code-event-contract.mjs";import{fetchPairControlDeliveryAuthority as Yo}from"./pair-control-authority.mjs";import{finishScheduledRunWithRetry as Vo,pollDueScheduledRuns as Qo,sanitizeScheduledOutcomeIntent as Xo,scheduledOutcomeReconciliationComplete as Zo,scheduledRunDeadlineRequired as en,scheduledRunSpawnAdmission as tn,scheduledRunsCapability as rn,scheduledRunsEnabled as on}from"./scheduled-runs.mjs";import{acquireScheduledRunAdmission as nn,releaseScheduledRunAdmission as sn}from"./scheduled-run-admission.mjs";import{SIDE_HANDOFF_PROMPT as an,SIDE_ROLE_PROMPT as cn,appendSideContext as ln,assistantTextSince as dn,dispatchSideContexts as un,sideContextBlock as mn,sideSnapshot as pn}from"./side-lane.mjs";import{acknowledgeWorkerCompletions as hn,enqueueWorkerCompletion as fn,workerCompletionPrompt as wn,workerCompletionRecord as vn}from"./worker-completion.mjs";import{planMeterLine as gn}from"./plan-meters.mjs";import{priceForModel as yn}from"./model-prices.mjs";import{loadHermesModelCache as kn,saveHermesModelCache as bn}from"./hermes-model-cache.mjs";import{makeThrottledTrack as $n,recoveryBackoffMs as Tn}from"./presence.mjs";import{MockupDeliveryQueue as Rn,completeMockupManifest as In,isMockupDeliveryBoundary as Sn}from"./mockup-delivery.mjs";import{resolveAnonKey as Cn,DEFAULT_SUPABASE_URL as xn}from"./supabase-key.mjs";import{buildTerminalRolePrompt as _n,HERMES_VISIBLE_WORKER_FALLBACK_RULE as An,THINKPOOL_PROMPT_BUNDLE as Pn}from"./thinkpool-room-prompt.mjs";const Nn=process.env.TP_SUPABASE_URL||xn,On=process.env.TP_WEB_BASE||"https://thinkpool.io",En=Ao();let Dn=kn();const{key:jn,source:qn}=await Cn({supabaseUrl:Nn,webBase:On,log:e=>{process.env.TP_DEBUG&&console.error(` ◇ ${e}`)}});process.env.TP_DEBUG&&console.error(` ◇ supabase anon key source: ${qn}`);let Kn=process.env.TP_ACCESS_TOKEN||null,Mn=null;try{Mn=(await import("node-pty")).default??await import("node-pty")}catch{console.error("\n ⚠ node-pty not built — raw terminal sharing is off (structured Claude still works).\n For PTY mode (bash / aider / codex / TP_PTY=1): install a C toolchain, then `npm i` in the bridge.\n (Xcode CLT on mac · build-essential on linux · VS Build Tools on Windows.)\n")}const Fn=[{label:"Claude Code",cmd:"claude",resume:{args:["--continue"],probe:function(){try{const o=r.resolve(process.cwd()).replace(/[/\\.:]/g,"-");return t.readdirSync(r.join(e.homedir(),".claude","projects",o)).length>0}catch{return!1}}}},{label:"Codex CLI",cmd:"codex"},{label:"Hermes Agent",cmd:"thinkpool",availability:()=>we().available},{label:"Gemini CLI",cmd:"gemini"},{label:"Aider",cmd:"aider"},{label:"Cursor CLI",cmd:"cursor-agent"},{label:"opencode",cmd:"opencode"},{label:"Copilot CLI",cmd:"copilot"},{label:"Goose",cmd:"goose"},{label:"Crush",cmd:"crush"},{label:"Qwen Code",cmd:"qwen"}],Un=process.argv.slice(2);if("install-service"===Un[0]||"restart-service"===Un[0]){const e=je(Un);null===e||Ke(e)||(process.stderr.write(" ⚠ could not save the keep-awake setting; service left unchanged.\n"),process.exit(1))}if("privacy-report"===Un[0]){const{runPrivacyReport:e}=await import("./privacy-report.mjs");e(),process.exit(0)}if("install-service"===Un[0]||"uninstall-service"===Un[0]){const e=Un[1]||"",t=!e||e.startsWith("-")?null:e.toUpperCase().trim(),r=Un.indexOf("--"),o=r>=0?Un.slice(r+1):[],n=Un.includes("--auto-update"),s=await import("./service.mjs");if("install-service"===Un[0]){const e=n?s.installService(t,o,{autoUpdate:n}):await s.installAndConfirmService(t,o);process.exit(!1===e?1:0)}else s.uninstallService(t);process.exit(0)}if("restart-service"===Un[0]){const e=Un[1]||"",t=!e||e.startsWith("-")?null:e.toUpperCase().trim(),r=await import("./service.mjs"),o=Un.includes("--current")?r.restartService(t):await r.updateAndConfirmService(t);process.exit(o?0:1)}const{applyProviderEnv:Bn}=await import("./provider.mjs"),Ln=Bn();if("login"===Un[0]){const{runLogin:e}=await import("./account.mjs");await e(Nn,jn,On)}if("bind"===Un[0]){const{runBind:e}=await import("./account.mjs");e(Un[1],Un[2])}if("set-default-dir"===Un[0]){const{saveDefaultDir:t}=await import("./auth-store.mjs");let r=(Un[1]||"").trim();r.startsWith("~")&&(r=r.replace(/^~/,e.homedir())),r||(console.error(` usage: ${De("set-default-dir","<dir>")}`),process.exit(1)),t(r),console.log(` ◆ default project dir set → ${r}\n New/unbound sessions auto-serve from here — no per-session bind. Takes effect next serve tick.`),process.exit(0)}if("provider"===Un[0]){const{runProvider:e}=await import("./provider.mjs");await e(Un.slice(1)),process.exit(0)}if("setup-hermes"===Un[0]){const e=Un.includes("--clone"),t=Un.includes("--clean");e&&t&&(console.error(" choose one Hermes setup mode: --clone or --clean"),process.exit(1));let r=e?"clone":t?"clean":void 0;if(!r&&process.stdin.isTTY){const e=await new Promise(e=>{const t=o.createInterface({input:process.stdin,output:process.stderr});t.question("\n Clone your active Hermes provider/config into an isolated thinkpool profile? [Y/n] ",r=>{t.close(),e(String(r).trim())})});r=/^n/i.test(e)?"clean":"clone"}try{const{setupHermesRuntime:e}=await import("./hermes-setup.mjs"),t=e({mode:r});process.stderr.write(`\n ◆ Hermes ${t.version||""} is ready for thinkpool ordinary lanes.\n profile: ${t.profile} (${t.created?`${t.mode} created`:"existing"})\n hidden delegation: blocked\n${t.created&&"clean"===t.mode?" provider: run `thinkpool setup` before the first model turn\n":""}\n`),process.exit(0)}catch(e){console.error(`\n ◇ Hermes setup failed: ${e?.message||e}\n New profile: npx thinkpool-pair@latest setup-hermes --clone\n Clean profile: npx thinkpool-pair@latest setup-hermes --clean\n`),process.exit(1)}}if("verify-hermes-isolation"===Un[0])try{const{verifyHermesMcpIsolation:e}=await import("./hermes-isolation.mjs"),t=await e({rounds:2});process.stderr.write(`\n ◆ Hermes MCP isolation HELD for ${t.length} consecutive two-lane rounds.\n Each ACP session advertised only its lane-bound marker endpoint.\n No model inference was used.\n\n`),process.exit(0)}catch(e){console.error(`\n ◇ Hermes MCP isolation VIOLATED or unproven: ${e?.message||e}\n`),process.exit(1)}if((!Un[0]||"setup"===Un[0])&&process.stdin.isTTY){const{runLauncher:e,detectState:t}=await import("./launcher.mjs"),r=await import("./service.mjs"),s=i(import.meta.url),a={print:e=>process.stderr.write(e+"\n"),ask:e=>new Promise(t=>{const r=o.createInterface({input:process.stdin,output:process.stderr});r.question(e,e=>{r.close(),t(String(e).trim())})})},c={pairRoom:({room:e,agentCmd:t,resumeArgs:r=[],headless:o})=>new Promise(()=>{const i=[s,e,...o?["--headless"]:[],"--",t,...r];n(process.execPath,i,{stdio:"inherit"}).on("exit",e=>process.exit(null==e?0:e))}),serveAccountForeground:async()=>{Me({enabled:qe([])});const{runAccount:e}=await import("./account.mjs");await e(Nn,jn)},installService:({room:e=null,agentCmd:t}={})=>r.installAndConfirmService(e,t?[t]:[]),uninstallService:({room:e=null}={})=>{r.uninstallService(e)},restartService:({room:e=null}={})=>{r.restartService(e)},restartUpdateService:async({room:e=null}={})=>"win32"===process.platform?r.updateService(e):r.updateAndConfirmService(e),relaunchLauncher:async()=>{const e=r.serviceRuntimeVersion(null);if(!e)return a.print("\n ⚠ the managed runtime was confirmed earlier but could not be resolved for launcher handoff; staying in this launcher."),!1;let t="";try{t=r.provisionRuntime(e)}catch(t){return a.print(`\n ⚠ could not open the verified v${e} launcher: ${t?.message||t}`),!1}return new Promise(e=>{const r=n(process.execPath,[t],{stdio:"inherit",cwd:process.cwd(),env:process.env});r.once("error",t=>{a.print(`\n ⚠ launcher handoff failed: ${t?.message||t}`),e(!1)}),r.once("exit",()=>e(!0))})},login:async()=>{const{runLogin:e}=await import("./account.mjs");await e(Nn,jn,On)},setProvider:async({kind:e,base:t,token:r,model:o})=>{const{runProvider:n}=await import("./provider.mjs"),s="custom"===e?["custom","--base",t,"--token",r,...o?["--model",o]:[]]:["anthropic"];await n(s)},setKeepAwake:async({enabled:e})=>Ke(e)?(r.isServiceInstalled(null)&&r.restartService(null),!0):(a.print("\n ⚠ could not save the keep-awake setting; nothing was changed."),!1),setupHermes:async({mode:e})=>{const{setupHermesRuntime:t}=await import("./hermes-setup.mjs"),r=t({mode:e});a.print(`\n ✓ Hermes ${r.version||""} ready — isolated profile, ACP healthy, hidden delegation blocked.`),r.created&&"clean"===r.mode&&a.print(" Run `thinkpool setup` once to choose a provider before the first model turn.")}};await e({actions:c,io:a,refresh:t}),process.exit(0)}const Wn=process.env.TP_SDK_SMOKE_PATH||r.join(r.dirname(i(import.meta.url)),"sdk-smoke.mjs");let Hn={ok:null,version:"unknown",reason:""};function zn(){try{const e=a(import.meta.url);let o=r.dirname(e.resolve("@anthropic-ai/claude-agent-sdk"));for(let e=0;e<8;e++){try{const e=JSON.parse(t.readFileSync(r.join(o,"package.json"),"utf8"));if("@anthropic-ai/claude-agent-sdk"===e.name)return e.version}catch{}const e=r.dirname(o);if(e===o)break;o=e}}catch{}return"unknown"}function Jn(){try{return s(process.execPath,[Wn],{encoding:"utf8",timeout:22e3,stdio:["ignore","pipe","ignore"]}).trim()}catch(e){return(e.stdout||"").toString().trim()||`SMOKE:FAIL:${zn()}:${"ETIMEDOUT"===e.code?"timeout":(e.message||"run error").slice(0,80)}`}}if("verify-sdk"===Un[0]){const e=Jn();console.log(e),process.exit(Se(e)?0:1)}if(!Un[0]||Un[0].startsWith("-")){Me({enabled:qe(Un)});const{runAccount:e}=await import("./account.mjs");await e(Nn,jn)}const Gn=(Un[0]||"").toUpperCase().trim();Gn||(console.error(`usage: ${De("<ROOM>","[--headless]","[--continue|--fresh]","[-- <command…>]")} | ${Ee} (account mode)`),process.exit(1)),/^[A-Z0-9_-]{2,32}$/.test(Gn)||(console.error(`refused: invalid room code ${JSON.stringify(Gn)} (expected 2–32 alphanumerics, dash, or underscore)`),process.exit(1)),Ie(Un)&&(function(){const o=r.join(e.homedir(),".thinkpool-pair"),n=r.join(o,"sdk-ok"),s=zn();Hn.version=s;let i="";try{i=t.readFileSync(n,"utf8").trim()}catch{}if(i&&i===s)return void(Hn.ok=!0);const a=Jn().match(/^SMOKE:(PASS|FAIL):([^:\n]*)(?::(.*))?$/m);if(a&&"PASS"===a[1]){Hn={ok:!0,version:a[2]||s,reason:""};try{t.mkdirSync(o,{recursive:!0}),t.writeFileSync(n,Hn.version)}catch{}process.stderr.write(`\n ◆ agent SDK v${Hn.version} passed the compatibility smoke test.\n`)}else{Hn={ok:!1,version:a&&a[2]||s,reason:a&&a[3]||"unknown"};try{t.mkdirSync(o,{recursive:!0}),t.writeFileSync(r.join(o,"sdk-bad"),`${Hn.version}: ${Hn.reason}`)}catch{}process.stderr.write(`\n ⛔ agent SDK v${Hn.version} FAILED the compatibility smoke test — ${Hn.reason}.\n ⛔ refusing to serve agent turns. Repair or pin a known-good SDK, then restart.\n`)}}(),Hn.ok||process.exit(1));const Yn=Un.indexOf("--"),Vn=Yn>=0?Un.slice(0,Yn):Un;if(Vn.includes("--supervise")||Vn.includes("--keep-alive")){const e=process.argv.slice(1).filter(e=>"--supervise"!==e&&"--keep-alive"!==e);let t=1e3,r=!1,o=null;const s=()=>{const i=Date.now();o=n(process.execPath,e,{stdio:"inherit"}),o.on("exit",(e,o)=>{(r||0===e)&&process.exit(e||0);const n=Date.now()-i>6e4,a=n?1e3:t;t=n?1e3:Math.min(2*t,3e4),process.stderr.write(`\n ⚠ bridge exited (${o||`code ${e}`}); restarting in ${Math.round(a/1e3)}s…\n`),setTimeout(s,a)}),o.on("error",()=>{})};for(const e of["SIGINT","SIGTERM"])process.on(e,()=>{r=!0;try{o?.kill(e)}catch{}setTimeout(()=>process.exit(0),400)});process.stderr.write(`\n [b:${ms} r:${Gn}] ◆ supervisor up — keeping the bridge for room ${Gn} alive (auto-restart on crash).\n`),s(),await new Promise(()=>{})}{const{acquireMachineLock:e,releaseMachineLock:t,shouldHoldMachineLock:r}=await import("./account.mjs");r(process.env)&&!e()&&(console.error("\n ◇ A thinkpool-pair bridge is already running on this machine\n (~/.thinkpool-pair/account.lock). Only one can be active, and the running\n one already serves every room you are in — use it, or stop it first.\n (If you are certain none is running, delete that stale lock file.)\n"),process.exit(0)),r(process.env)&&process.on("exit",()=>{try{t()}catch{}})}Me({enabled:qe(Un)});const Qn=Un.includes("--headless"),Xn=(Un.find(e=>e.startsWith("--auto="))||"").slice(7)||null,Zn=("1"===process.env.TP_STRUCTURED||Un.includes("--structured"),ce),es=e=>!!Zn(e)&&"1"!==process.env.TP_PTY,ts=Fn.filter(e=>{return t=e.cmd,Te(t)&&(!e.availability||e.availability());var t}),rs=Un.indexOf("--"),os=rs>=0?Un.slice(0,rs):Un,ns=os.includes("--continue"),ss=os.includes("--fresh"),is=(e,t=!0)=>new Promise(r=>{const n=o.createInterface({input:process.stdin,output:process.stderr});n.question(e,e=>{n.close();const o=String(e).trim();r(t?!/^n/i.test(o):/^y/i.test(o))})});let as=null,cs=[],ls=!1;if(rs>=0)[as,...cs]=Un.slice(rs+1),as&&as.startsWith("-")&&(process.stderr.write(`\n ◇ ignoring "${as}" after \`--\` — that's a flag, not a command to share.\n`),as=null,cs=[]);else if(!Qn){0===ts.length&&(console.error(`\n No known coding-agent CLI found on your PATH.\n Install one (claude / codex / gemini / aider / cursor-agent / opencode …)\n or share a specific command: ${De(Gn,"--","<your-command>")}\n`),process.exit(1)),as=await(ds=ts,new Promise(e=>{if(1===ds.length||!process.stdin.isTTY)return void e(ds[0].cmd);const t=o.createInterface({input:process.stdin,output:process.stderr});process.stderr.write("\n Which coding agent do you want to share?\n\n"),ds.forEach((e,t)=>process.stderr.write(` ${t+1}) ${e.label}\n`)),process.stderr.write("\n"),t.question(" Pick a number [1]: ",r=>{t.close();const o=parseInt(String(r).trim(),10),n=Number.isInteger(o)&&o>=1&&o<=ds.length?o-1:0;e(ds[n].cmd)})}));const e=Fn.find(e=>e.cmd===as);e?.resume&&!ss&&(ns?ls=!0:process.stdin.isTTY&&e.resume.probe()&&(ls=await is(`\n Continue your latest ${e.label} session in this directory? [Y/n] `)),ls&&(cs=[...e.resume.args]))}var ds;if(process.stdin.isTTY&&!Qn&&"1"!==process.env.THINKPOOL_PAIR_AUTOUPDATE){const o=await import("./service.mjs");o.isServiceInstalled(Gn)&&(process.stderr.write(`\n ◆ a background service is already running room ${Gn} (auto-updating).\n ◆ remove it with: npx thinkpool-pair@latest uninstall-service ${Gn}\n\n`),process.exit(0));const n=r.join(e.homedir(),".thinkpool-pair",`${Gn}.svc-declined`);let s=!1;try{s=t.existsSync(n)}catch{}if(!s){await is("\n Run as a background service instead? It survives reboot + auto-updates,\n but runs detached — you'd stop it with 'uninstall-service', not Ctrl-C.\n Install background service? [y/N] ",!1)&&(o.installService(Gn,as?[as,...cs]:[]),process.stderr.write(`\n [b:${ms} r:${Gn}] ◆ the background service is handling room ${Gn} now — you can close this terminal.\n ◆ STOP IT with: npx thinkpool-pair@latest uninstall-service ${Gn}\n (closing the terminal does NOT stop it — it's detached under launchd/systemd.)\n\n`),process.exit(0));try{t.mkdirSync(r.dirname(n),{recursive:!0}),t.writeFileSync(n,(new Date).toISOString())}catch{}process.stderr.write(` [b:${ms} r:${Gn}] ◆ running in this terminal. (Auto-update service anytime: npx thinkpool-pair@latest install-service ${Gn})\n`)}}const us=process.env.TP_NAME||e.userInfo().username||"host",ms=c?.().slice(0,8)||"bridgexx",ps=process.env.TP_ACCOUNT_BRIDGE_ID||null,hs=Number.parseInt(process.env.TP_ACCOUNT_BRIDGE_FENCING||"",10),fs=Date.now(),ws=(e.hostname()||"host").split(".")[0].slice(0,24),vs=A(),gs=j(),ys=process.cwd(),ks=r.basename(ys);let bs=null;try{bs=JSON.parse(t.readFileSync(new URL("./package.json",import.meta.url),"utf8")).version}catch{}try{const o=r.join(e.homedir(),".npm","_npx"),n=t.readdirSync(o,{withFileTypes:!0}).filter(e=>e.isDirectory()).map(e=>e.name).filter(e=>"cache"!==e),s=e=>e?e.split(".").map(e=>parseInt(e,10)||0):[0,0,0],i=(e,t)=>{const r=s(e),o=s(t);for(let e=0;e<3;e++){if(r[e]<o[e])return!0;if(r[e]>o[e])return!1}return!1};let a=null;for(const e of n){const n=r.join(o,e,"node_modules","thinkpool-pair","package.json");try{const e=JSON.parse(t.readFileSync(n,"utf8"));e.version&&(a&&!i(a,e.version)||(a=e.version))}catch{}}a&&bs&&i(bs,a)&&process.stderr.write(` ⚠ stale-cache: running ${bs}, newest ${a}\n`)}catch{}function $s(){try{let e=r.join(ys,".git");t.statSync(e).isFile()&&(e=t.readFileSync(e,"utf8").replace(/^gitdir:\s*/i,"").trim());const o=t.readFileSync(r.join(e,"HEAD"),"utf8").trim();return o.startsWith("ref:")?o.split("/").pop():o.slice(0,7)}catch{return null}}const Ts=r.join(e.tmpdir(),"thinkpool-pair",Gn),Rs=l(Nn,jn,{realtime:{params:{eventsPerSecond:60}}});let Is="free";async function Ss(){const e=Kn;if(e)try{const{data:t,error:r}=await Rs.auth.getUser(e),o=t?.user?.id;if(r||!o)return;const n=await fetch(`${Nn}/rest/v1/profiles?select=plan&id=eq.${o}`,{headers:{apikey:jn,Authorization:`Bearer ${e}`}});if(!n.ok)return;const s=await n.json();s?.[0]?.plan&&(Is="plus"===s[0].plan?"plus":"free")}catch{}}let Cs=null;{let e=!1;if(!Kn)try{const{loadAuth:t}=await import("./auth-store.mjs");Kn=t()?.access_token||null,Kn&&(e=!0)}catch{}if(e)try{const{authedClient:e}=await import("./account.mjs"),t=await e(Nn,jn);t?.session?.access_token&&(Kn=t.session.access_token)}catch{}try{if(Kn){const{data:e}=await Rs.auth.getUser(Kn);Cs=e?.user?.id||null}const{ownerId:e,name:t}=await u({supabaseUrl:Nn,anonKey:jn,token:Kn,room:Gn}),r=d({ownerId:e,myUid:Cs});r.serve||(process.stderr.write(m({room:Gn,name:t,reason:r.reason})),process.exit(0))}catch(e){"refuse"===p(e)&&(process.stderr.write(m({room:Gn,name:null,reason:"no-identity"})),process.stderr.write(`\n ◇ (serve-consent: auth rejected at the gate — ${e.message}; the stored login is expired or revoked. Re-run: ${De("login")})\n`),process.exit(0)),process.stderr.write(`\n ◇ serve-consent check degraded (${e.message}); proceeding without it.\n`)}}!await xt(Rs,Kn,jn)&&Kn&&process.stderr.write("\n ⚠ realtime auth could not be initialized; private bridge features are unavailable.\n"),Ss();const xs="1"===process.env.TP_BUDGET_OFF;async function _s(e,t){const r=await fetch(`${Nn}/rest/v1/rpc/${e}`,{method:"POST",headers:{apikey:jn,Authorization:`Bearer ${Kn}`,"Content-Type":"application/json"},body:JSON.stringify(t)});if(!r.ok)throw new Error(`${e} ${r.status}`);const o=await r.text();return o?JSON.parse(o):null}const As="1"===process.env.TP_AGENT_NOTIFY_OFF,Ps=Number(process.env.TP_NOTIFY_MIN_TURN_MS)>0?Number(process.env.TP_NOTIFY_MIN_TURN_MS):R;function Ns(e){if(As||!Kn||!Cs||!Gn)return;const{eventId:t,...r}=e||{},o={id:`ae:${"string"==typeof t&&/^[A-Za-z0-9_-]{1,120}$/.test(t)?t:c()}`,session_code:Gn,author_id:Cs,payload:{__agent:!0,ts:Date.now(),...r}};fetch(`${Nn}/rest/v1/code_messages`,{method:"POST",headers:{apikey:jn,Authorization:`Bearer ${Kn}`,"Content-Type":"application/json",Prefer:"return=minimal"},body:JSON.stringify(o)}).then(e=>{!e.ok&&process.env.TP_DEBUG&&process.stderr.write(`\n ◆ agent-event insert ${e.status}\n`)}).catch(()=>{})}let Os=null;const Es=Rs.channel(`tpcode:${Gn}`,{config:{private:!0,broadcast:{self:!1},presence:{key:`bridge:${us}`}}}),Ds=Rs.channel(`tpflow:${Gn}`,{config:{broadcast:{self:!1}}}),js=Rs.channel(`tpdesign:${Gn}`,{config:{private:!0,broadcast:{self:!1}}}),qs=Rs.channel(`tpcontrol:${Gn}`,{config:{private:!0,broadcast:{self:!1}}}),Ks=new Map,Ms=new Map;let Fs=0;function Us(e,t=Date.now()){const r=e?.session?.turnActive??!1;return r!==e?._busyAnn&&(r&&(e._turnRev=(Number(e._turnRev)||0)+1,e._turnStart=t,e._settledTurnRev=null,e._turnSettledAt=null),e._busyAnn=r,!0)}function Bs(e,t=Date.now()){return!0!==e?._busyAnn&&(e._turnRev=(Number(e._turnRev)||0)+1,e._turnStart=t,e._busyAnn=!0,e._settledTurnRev=null,e._turnSettledAt=null,!0)}function Ls(e,t,{options:r,visibleEvent:o,rejectionMessage:n="The agent did not accept this turn; retry after the lane is available."}={}){if(!e?.session)return{accepted:!1,error:new Error("session unavailable")};Us(e);let s=!1,i=null;try{s=!1!==e.session.sendTurn(t,r)}catch(e){i=e}if(s?Bs(e):Us(e),o&&(va(e,o),ci("code-event",{term:e.id,evt:o})),!s){const t={kind:"error",message:n,recoverable:!0};va(e,t),ci("code-event",{term:e.id,evt:t})}return wi(),{accepted:s,error:i}}function Ws(e){e?.pendingSideContexts?.length&&!e._sideContextTimer&&(e._sideContextTimer=setTimeout(()=>{e._sideContextTimer=null,function(e){if(!e?.pendingSideContexts?.length||"function"!=typeof e.session?.sendTurn)return!1;const t=un({contexts:e.pendingSideContexts,busy:!0===e.session?.turnActive,sendTurn:t=>e.session?.sendTurn(t)});return e.pendingSideContexts=t.pending,!!t.dispatched&&(Bs(e),e.flush?.(),wi(),!0)}(e)&&process.stderr.write("\n ◆ started main turn from side-lane handoff.\n")},0),e._sideContextTimer.unref?.())}function Hs(e){e?.pendingWorkerCompletions?.length&&!e._workerCompletionTimer&&(e._workerCompletionTimer=setTimeout(()=>{e._workerCompletionTimer=null,function(e){if(!e?.pendingWorkerCompletions?.length||"function"!=typeof e.session?.sendTurn)return!1;if(e.workerCompletionsInFlight?.length)return!1;if(Ar(e)||(e.pending?.size||0)>0)return!1;const t=e.pendingWorkerCompletions.slice(),r=wn(t);return r?(e.workerCompletionsInFlight=t,e.flush?.(),!!Ls(e,r,{rejectionMessage:"The worker-completion continuation was not accepted; it remains queued."}).accepted||(e.workerCompletionsInFlight=[],e.flush?.(),!1)):(e.pendingWorkerCompletions=[],!1)}(e)&&process.stderr.write("\n ◆ worker finished — continued its owning terminal.\n")},0),e._workerCompletionTimer.unref?.())}function zs(e,t){return t&&null==t.turnRev&&Number(e?._turnRev)>0&&(t.turnRev=e._turnRev),t}let Js=null,Gs=!1;const Ys=[];let Vs=0;const Qs="1"===process.env.TP_BACKGROUND_WARM;function Xs(){for(;Vs<3&&Ys.length;){const e=Ys.shift();if(e&&!e.warmed&&!e.warming&&e.session&&!e.session.started){e.warming=!0,Vs++;try{e.session.warm?.()}catch{e.warming=!1,Vs--;continue}e.warmTimer=setTimeout(()=>{e.warming&&(e.warming=!1,Vs=Math.max(0,Vs-1),Xs())},1e5)}}}let Zs=Date.now();const ei=()=>{if(Zs=Date.now(),process.send&&"1"===process.env.THINKPOOL_PAIR_ACCOUNT_CHILD)try{process.send({t:"busy"})}catch{}};let ti=null,ri=!1,oi=!1;const ni=()=>{try{const e=Es.presenceState()||{};for(const t of Object.values(e))for(const e of t||[])if(e&&"bridge"!==e.role)return!0}catch{}return!1},si=2e5,ii=async(e,t,r=Es)=>{"pty-out"!==e&&"code-event"!==e||(Zs=Date.now()),t=((e,t)=>{let r,o;try{r=JSON.stringify(t)}catch{return t}if(!r||r.length<=si)return t;process.stderr.write(`\n ⚠ oversized ${e} frame: ${r.length}B (term ${String(t?.term||"?").slice(0,8)}) — defanging so Realtime doesn't drop it\n`);try{o=JSON.parse(r)}catch{return t}if(o.evt&&"object"==typeof o.evt&&(o.evt=Co(o.evt,1e5)),Array.isArray(o.events)){o.events=o.events.map(e=>Co(e,1e5));let e=0,t=0;for(;o.events.length>1&&JSON.stringify(o).length>si&&e++<1e4;)o.events.shift(),t++;if(t){const e=Fo(o.events);"number"==typeof e&&(o.trimmedBefore=Math.max(o.trimmedBefore??0,e))}}return o})(e,t);try{return r.channelAdapter?.canPush?.()??1?await r.send({type:"broadcast",event:e,payload:t}):await r.httpSend(e,t)}catch{return null}},ai=Lo({send:({event:e,payload:t,ch:r})=>ii(e,t,r)}),ci=(e,t,r=Es)=>{"code-event"!==e||r!==Es?ii(e,t,r):ai.enqueue({event:e,payload:t,ch:r})},li=Uo({send:({event:e,payload:t})=>ii(e,t)}),di=io(Gn),ui=new Set,mi=(e,t,r=null)=>{ci("term-opened",{id:e,kind:t,sideParent:r?.sideParent||void 0,sideTask:r?.sideTask||void 0,name:di[e]||void 0})},pi=new Set,hi=new Map;let fi=null;const wi=()=>{const e=x(),t=new Map(Re(ts.map(e=>e.cmd)).map(e=>[e.cmd,e.enabled])),o=++Fs;return ii("bridge",{v:2,name:us,bridge_id:ms,started_at:fs,rev:o,repo:ks,branch:$s(),...!1===Hn.ok?{sdkWarn:`${Hn.version}: ${Hn.reason}`}:{},models:fi||void 0,cwd:ys,version:bs,promptBundle:Pn,host:ws,hostId:vs,uid:Cs||void 0,provider:Ln.provider,providerBaseUrl:Ln.baseUrl||void 0,ctxCarry:!0,providerPubKey:_(),providers:P(),pendingUpdate:ti,updir:Ts.split(r.sep).join("/"),scheduledRuns:rn(),capacity:{workerActive:Mr(Ms.values()),workerLimit:Fr(Is),hostStatus:Ti},agents:ts.map(e=>{let r=!1;if(e.resume)try{r=e.resume.probe()}catch{}return{label:e.label,cmd:e.cmd,canResume:r,enabled:!1!==t.get(e.cmd)}}),terms:[...[...Ks.entries()].map(([e,t])=>({id:e,cmd:t.cmd,alive:!0,cols:t.term.cols,rows:t.term.rows,name:di[e]||void 0,...Pr(t)})),...[...Ms.entries()].map(([t,r])=>({id:t,cmd:r.cmd,kind:"structured",runtime:r.runtime||"claude",alive:!0,...Pr(r),turnRev:Number(r._turnRev)||0,...Ar(r)&&r._turnStart?{turnStartedAt:r._turnStart}:{},...!Ar(r)&&Number(r._settledTurnRev)>0&&Number(r._settledTurnRev)===Number(r._turnRev)?{settledTurnRev:Number(r._settledTurnRev),turnSettledAt:Number(r._turnSettledAt)||void 0}:{},hasTranscript:r.log.length>0,commands:r.commands,mode:r.mode||void 0,effort:r.effort||void 0,name:di[t]||void 0,model:r.model||void 0,capabilities:{...le(r.runtime||"claude"),modes:ae(r.runtime||"claude",r)},..."codex"===r.runtime?{approvalPolicy:z(r.mode).approvalPolicy,models:r.models||[],canSteer:r.session?.canSteer??!1}:"hermes"===r.runtime?{models:r.models||[],canSteer:r.session?.canSteer??!1}:{},...null!=r.archiveOldestSeq?{oldestSeq:r.archiveOldestSeq}:{},...r.spawnedBy?{spawned:!0,spawnedBy:r.spawnedBy}:{},...r.sideParent?{sideParent:r.sideParent,sideTask:r.sideTask||void 0,sideHandback:!!r.sideHandback}:{},...r.flowSessionId?{flowId:r.flowSessionId,flowRole:r.flowTaskKey?"lane":"conductor"}:{},...r.scheduleRunId?{scheduleRunId:r.scheduleRunId}:{},...r.provider&&"anthropic"!==r.provider?{provider:{id:r.provider,name:e[r.provider]||r.provider}}:{}}))]})},vi=async(e,t,r,o=!0)=>{if(Kn&&e&&t)try{const n=r?`&name=eq.${encodeURIComponent(r)}`:`&or=${encodeURIComponent("(name.is.null,name.eq.Terminal)")}`,s=await fetch(`${Nn}/rest/v1/code_terminals?id=eq.${encodeURIComponent(e)}${n}&select=id`,{method:"PATCH",headers:{apikey:jn,Authorization:`Bearer ${Kn}`,"Content-Type":"application/json",Prefer:"return=representation"},body:JSON.stringify({name:t})}),i=s.ok?await s.json().catch(()=>[]):[];if(o&&(!s.ok||!Array.isArray(i)||0===i.length)){const o=setTimeout(()=>{vi(e,t,r,!1)},1500);o.unref?.()}}catch{if(o){const o=setTimeout(()=>{vi(e,t,r,!1)},1500);o.unref?.()}}},gi=async(e,t,r=!0)=>{if(!Kn||!e||!t)return;const o=new AbortController,n=setTimeout(()=>o.abort(),4500);try{const s=await fetch(`${On}/api/code-terminal-name`,{method:"POST",headers:{Authorization:`Bearer ${Kn}`,"Content-Type":"application/json"},body:JSON.stringify({code:Gn,terminalId:e,task:t}),signal:o.signal});clearTimeout(n);const i=await s.json().catch(()=>({}));if(r&&404===s.status&&"terminal_pending"===i?.code){const r=setTimeout(()=>{gi(e,t,!1)},1500);return void r.unref?.()}if(!s.ok)return;const a=ee(i?.name);a&&((e,t)=>{if(!t||ui.has(e))return!1;const r=hi.get(e);if(di[e]&&di[e]!==r)return!1;const o=di[e]||null,n=((e,t)=>{const r=new Set(Object.entries(di).filter(([t])=>t!==e).map(([,e])=>String(e).toLowerCase()));if(!r.has(t.toLowerCase()))return t;for(let e=2;e<100;e++){const o=` ${e}`,n=`${t.slice(0,48-o.length).trim()}${o}`;if(!r.has(n.toLowerCase()))return n}return t})(e,t);di[e]===n||(di[e]=n,hi.set(e,n),ao(Gn,di),vi(e,n,o),wi())})(e,a)}catch{clearTimeout(n)}},yi=(e,t)=>{const r=Ms.get(e);if(!r||di[e]||ui.has(e)||pi.has(e))return;if(r.log?.some(e=>"you"===e?.kind))return;const o=te(t);o&&(pi.add(e),gi(e,o))},ki=!(!process.send||"1"!==process.env.THINKPOOL_PAIR_ACCOUNT_CHILD),bi=new _e,$i=new Map;let Ti="available",Ri=null;const Ii=()=>{if(!xe("resume queued Dispatch work").ok)return Ti="held",void Si();Ti="available",wi(),ci("capacity-changed",{},Ds)},Si=()=>{Ti="held",Ri||(Ri=setInterval(()=>{xe("resume queued Dispatch work").ok&&(clearInterval(Ri),Ri=null,Ii())},5e3),Ri.unref?.(),wi())},Ci=async e=>{if(!e)return{ok:!1,code:"invalid_capacity_request"};if(!ki){const t=bi.acquire({room:Gn,terminalId:e});return t.ok||(Ti="held"),t}const t=c();return new Promise(r=>{const o=setTimeout(()=>{$i.delete(t),Ti="held";try{process.send({t:"capacity-release",terminalId:e})}catch{}r({ok:!1,code:"capacity_authority_unavailable",reason:"The bridge capacity authority did not answer. No lane was opened; retry when the bridge reconnects."})},2500);o.unref?.(),$i.set(t,{resolve:r,timer:o});try{process.send({t:"capacity-acquire",reqId:t,terminalId:e})}catch{clearTimeout(o),$i.delete(t),Ti="held",r({ok:!1,code:"capacity_authority_unavailable",reason:"The bridge capacity authority is unavailable. No lane was opened."})}})},xi=e=>{if(e)if(ki)try{process.send({t:"capacity-release",terminalId:e})}catch{}else bi.release({room:Gn,terminalId:e})&&Ii()};ki&&process.on("message",e=>{if("capacity-acquire-result"===e?.t){const t=$i.get(e.reqId);if(!t)return;clearTimeout(t.timer),$i.delete(e.reqId),e.ok||(Ti="held"),t.resolve({ok:!0===e.ok,code:e.code,reason:e.reason,active:e.active,limit:e.limit})}else"capacity-changed"===e?.t&&Ii()});const _i=new Map;let Ai=null;function Pi(e,t={},r=4e3){if("1"===process.env.TP_CROSSROOM_OFF)return Promise.resolve({error:"Cross-session reach is turned off in this room."});if(!ki)return Promise.resolve({error:`Cross-session reach needs the thinkpool account bridge running your sessions (${Ee}). This room is running standalone, so it can only see its own terminals — use read_terminal.`});const o=c();return new Promise(n=>{const s=setTimeout(()=>{_i.delete(o),n({error:"The other session did not respond in time."})},r);s.unref?.(),_i.set(o,{resolve:n,timer:s});try{process.send({t:e,reqId:o,...t})}catch{clearTimeout(s),_i.delete(o),n({error:"Could not reach the account bridge."})}})}function Ni(e,t){const r={kind:"needs-input",subtype:"pair-control",summary:"A protected action requires a durable decision.",permissionId:String(t?.id||"").slice(0,160)};return va(e,r),ci("code-event",{term:e.id,evt:r}),{...t,...e.scheduleRunId?{runId:e.scheduleRunId}:{},source:{epoch:0,cid:r.cid,seq:r.seq}}}async function Oi({fromRoom:e,fromHost:t,fromTerminalName:r,text:o,terminal:n}){if("1"===process.env.TP_PAIRBUS_OFF)return{error:"Cross-room posting is turned off in this room."};const s=String(o||"").trim();if(!s)return{error:"Empty cross-room post ignored."};const i=vr({selfId:null,sessions:Ms,terms:Ks,names:di});let a=null;if(n){const e=gr(i,n);if(e&&"agent"!==e.kind)return{error:`Terminal ${e.ref} in room ${Gn} is a shell, not an agent — cross-room posts go to agents only.`};a=e?.id||null}else{const e=[...Ms.keys()];1===e.length&&(a=e[0])}if(!a){const e=i.filter(e=>"agent"===e.kind);return{error:e.length?`Name which agent lane in room ${Gn} to deliver to (${e.map(e=>e.ref).join(", ")}).`:`No agent terminal is open in room ${Gn} to receive this.`}}const l=Ms.get(a);if(!l?.session)return{error:`That terminal in room ${Gn} is no longer live.`};const d=`${e}${t?` on ${t}`:""}`;let u="deny";try{u=await(m=l,p={id:c(),toolName:"mcp__thinkpool__post_to_session",input:{session:e,host:t,terminalName:r,text:s,incoming:!0},risk:"high"},new Promise(e=>{if(!m?.pending)return e("deny");const t=Ni(m,{term:m.id,id:p.id,toolName:p.toolName,input:p.input,risk:p.risk});m.pending.set(p.id,{resolve:e,payload:t}),wi(),ci("code-perm-req",t),process.stderr.write(`\n ● incoming cross-room task for ${String(m.id).slice(0,8)} — approve in the room.\n`)}))}catch{u="deny"}var m,p;if("allow"!==u)return{error:`The people in room ${Gn} declined the incoming task from ${d}.`};l.roomHop=1,l.hop=(l.hop||0)+1,l.peekCount=0,l.peekRosterCount=0,l.postCount=0,l.pairPeekCount=0,l.crossRoomPostCount=0;const h=`[From: room ${d} — relayed via the thinkpool cross-room Ensemble, approved by a person in this room]\n${s}`,f={kind:"you",text:h,by:`room ${e}`,crosspost:!0,relaySourceName:String(r||"").trim().slice(0,80)||void 0};yi(a,s);const w=Ls(l,h,{visibleEvent:f,rejectionMessage:"The incoming cross-room task was not accepted; retry after the lane is available."});return w.accepted?{ok:!0,ref:String(a).slice(0,8)}:{error:w.error?`Could not deliver to room ${Gn} — the lane may have just closed.`:`Could not deliver to room ${Gn} — the lane refused the turn (check its visible host-memory/runtime error).`}}!async function(){if(ki||"1"===process.env.TP_PAIRBUS_OFF||"1"===process.env.TP_CROSSROOM_OFF)return;if(!Kn||!Cs)return;let t=null;try{const e=`${Nn}/rest/v1/code_sessions?code=eq.${encodeURIComponent(Gn)}&select=code,name,owner_id,participants`,r=await fetch(e,{headers:{apikey:jn,Authorization:`Bearer ${Kn}`}});if(!r.ok)return;const o=await r.json().catch(()=>[]);t=Array.isArray(o)?o[0]:null}catch{return}const r=Br({row:t,myUid:Cs});if(!r?.topic)return;const o=Ur({room:Gn,roomName:t?.name||null,host:e.hostname().replace(/\.local$/,""),formatPeek:e=>hr({selfId:null,sessions:Ms,terms:Ks,names:di,terminal:e.terminal,lines:e.lines}),receivePost:e=>Oi(e)}),n=Rs.channel(r.topic,{config:{private:!0,broadcast:{self:!1}}}),s=async(e,t)=>{if(t)try{await n.send({type:"broadcast",event:e,payload:t})}catch{}};n.on("broadcast",{event:"peer-list-req"},({payload:e})=>{s("peer-list-res",o.list(e))}).on("broadcast",{event:"peer-peek-req"},({payload:e})=>{const t=o.peek(e);t&&s("peer-peek-res",t)}).on("broadcast",{event:"peer-post-req"},({payload:e})=>{o.post(e).then(e=>{if(e)return s("peer-post-res",e)})}).subscribe(e=>{"SUBSCRIBED"===e?process.stderr.write("\n ◆ standalone pair bus subscribed — this live room can receive approval-gated cross-session tasks.\n"):"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e||process.stderr.write(`\n ◇ standalone pair bus ${e.toLowerCase().replace("_"," ")} — cross-session reach will retry with realtime.\n`)}),Ai=n}(),ki&&process.on("message",e=>{if(e&&e.t){if("pair-list-res"===e.t||"pair-peek-res"===e.t||"pair-post-res"===e.t){const t=_i.get(e.reqId);if(!t)return;return clearTimeout(t.timer),_i.delete(e.reqId),void t.resolve(e)}if("pair-peek-local"===e.t){let t,r;try{t=hr({selfId:null,sessions:Ms,terms:Ks,names:di,terminal:e.terminal,lines:e.lines})}catch{r="Could not read that session."}try{process.send({t:"pair-peek-res",reqId:e.reqId,text:t,error:r})}catch{}return}"pair-post-local"!==e.t||Oi(e).then(t=>{try{process.send({t:"pair-post-res",reqId:e.reqId,...t})}catch{}})}});const Ei=()=>{const e=ni();for(const[t,r]of Ks){if(!r.buf)continue;if(!e){r.buf="",Zs=Date.now();continue}const o=Buffer.from(r.buf,"utf8").toString("base64");r.buf="",ci("pty-out",{term:t,b64:o})}},Di=setInterval(Ei,35);Di.unref?.();const ji=r.join(e.tmpdir(),"thinkpool-mockups",Gn);try{t.mkdirSync(ji,{recursive:!0}),process.env.TP_MOCKUP_OUTBOX=ji}catch{}const qi=new Map,Ki=new Map,Mi=new Map,Fi=new Map,Ui=new Map;function Bi(e){e?.scheduleDeadlineTimer&&clearTimeout(e.scheduleDeadlineTimer),e&&(e.scheduleDeadlineTimer=null)}const Li=new Set;async function Wi(e){const t=e?.scheduleAdmissionLease;return!t||!!(await sn(t)).ok&&(e.scheduleAdmissionLease=null,!0)}async function Hi(e){const t=Xo(e?.scheduleOutcomePending);if(!e?.id||!t||e.scheduleOutcomeRecorded)return!1;const r=`${e.id}:${t.runId}`;if(Li.has(r))return!1;Li.add(r);try{if(!(await Vo({supabaseUrl:Nn,anonKey:jn,token:Kn,roomCode:Gn,runId:t.runId,bridgeId:ps,bridgeFencing:hs,result:t.result,canceled:t.canceled,evidenceRefs:t.evidenceRefs})).ok)return!1;if(await Wi(e),Ms.get(e.id)!==e)return!!fo(Gn,e.id,t.runId)&&vo(Gn,e.id);const r=e.scheduleOutcomePending;e.scheduleOutcomeRecorded=!0,e.scheduleOutcomePending=null;const o=wo(Gn,e.id,()=>e.flush?.());return o.snapshotRecorded?o.ok:(e.scheduleOutcomeRecorded=!1,e.scheduleOutcomePending=r,!1)}finally{Li.delete(r)}}function zi(e,t,{canceled:r=!1}={}){if(!e?.scheduleRunId||e.scheduleOutcomeRecorded||e.scheduleOutcomePending)return!1;const o=Xo({runId:e.scheduleRunId,result:t,canceled:r,evidenceRefs:(n=e.id,[...Ki.values()].filter(e=>e?.term===n&&"string"==typeof e.previewId).slice(0,16).map(e=>({type:"preview",id:e.previewId})))});var n;return!!o&&!!ko(Gn,e.id,o)&&(e.scheduleOutcomePending=o,Bi(e),e.flush?.(),Hi(e),!0)}function Ji(e){if(Bi(e),!en({runId:e?.scheduleRunId,deadlineAt:e?.scheduleDeadlineAt,outcomeRecorded:e?.scheduleOutcomeRecorded,outcomePending:e?.scheduleOutcomePending}))return;const t=Math.max(0,e.scheduleDeadlineAt-Date.now());e.scheduleDeadlineTimer=setTimeout(async()=>{if(e.scheduleDeadlineTimer=null,e.scheduleOutcomeRecorded)return;e.scheduleTimedOut=!0,_a(e),await Pe(e);const t={kind:"error",subtype:"runtime_limit",message:"Scheduled run reached its configured runtime ceiling."};va(e,t),ci("code-event",{term:e.id,evt:t}),zi(e,t),e.flush?.(),wi()},t),e.scheduleDeadlineTimer.unref?.()}const Gi=e=>js.send({type:"broadcast",event:"design-status",payload:{ts:Date.now(),...e}}),Yi=(e,t,r={})=>{const o=Fi.get(e);if(o){if(o.timer&&clearTimeout(o.timer),Fi.delete(e),Gi({previewId:o.record.previewId,requestId:o.request.cid,state:t,...r}),"verified-live"===t){const t=Mi.get(e)||[];for(const e of t.splice(0))Gi({previewId:e.record.previewId,requestId:e.request.cid,state:"stale",message:"The artifact changed. Reselect the element on the new revision."})}queueMicrotask(()=>Qi(e))}},Vi=e=>{const t=Fi.get(e);t?.resultOk&&t.proof&&Yi(e,"verified-live",{message:"Verified at desktop and mobile.",artifact:t.proof.artifact,...t.proof.artifactHtml?{artifactHtml:t.proof.artifactHtml}:{},canRestore:"preview"!==t.record.sourceKind})};function Qi(e){if(Fi.has(e))return;const t=Mi.get(e)||[],r=t[0];if(!r)return;const o=Ms.get(e);if(!o)return t.shift(),Gi({previewId:r.record.previewId,requestId:r.request.cid,state:"needs-lane",message:"The producing lane is no longer available."}),Qi(e);if(o.session?.turnActive)return;t.shift();const n=Ki.get(r.record.previewId),s=n&&Rt(n);if(!n||!s||s.revision!==r.record.revision)return Gi({previewId:r.record.previewId,requestId:r.request.cid,state:"stale",message:"The artifact changed. Reselect the element."}),Qi(e);const i={...r,resultOk:!1,proof:null,timer:null};Fi.set(e,i);const a={kind:"you",text:$t(r.request,{restore:!!r.restoreRecord}),cid:r.request.cid,by:r.by,design:!0};Us(o);let c=!1;try{c=!1!==o.session.sendTurn(bt({record:r.record,request:r.request,by:r.by,restore:!!r.restoreRecord,priorRecord:r.restoreRecord}))}catch{c=!1}if(c&&Bs(o),bo(a),va(o,a),ci("code-event",{term:e,evt:a}),c&&Gi({previewId:r.record.previewId,requestId:r.request.cid,state:"applying"}),!c){Us(o);const t={kind:"error",message:"The producing lane could not start the edit.",recoverable:!0};va(o,t),ci("code-event",{term:e,evt:t}),Yi(e,"failed",{message:"The producing lane could not start the edit."})}wi()}const Xi=(e,o,n,s)=>{try{const i=r.join(e,`${o}.receipt.json`),a=`${i}.tmp`;t.writeFileSync(a,JSON.stringify({ok:n,status:s,ts:Date.now()})),t.renameSync(a,i)}catch{}},Zi=new Rn({deliver:async({box:e,term:o,trustedDesignSource:n=!1,slug:s,m:i})=>{const a=n?Ms.get(o):null,l=a?It(i,a.cwd||process.cwd(),{box:e}):null,d=l?St(i,l,{box:e}):null,u=l?Fi.get(o):null,m=!(!u||i.designRequestId!==u.request.cid||i.parentRevision!==u.record.revision),p=u?.restoreRecord?.revision,h=p?l?.revision===p:l?.revision!==u?.record?.revision,f="preview"===u?.record?.sourceKind?"preview"===l?.sourceKind&&l?.captureKey===u.record.captureKey:l?.sourcePath===u?.record?.sourcePath,w=m&&f&&h?u.record.revision:null,v=e=>{try{return e&&t.readFileSync(e).toString("base64")}catch(t){return e&&process.stderr.write(`\n ◇ mockup asset unreadable: ${e} (${t?.code||t?.message||t})\n`),null}},g=e=>{try{return e&&t.readFileSync(e,"utf8")}catch(t){return e&&process.stderr.write(`\n ◇ mockup asset unreadable: ${e} (${t?.code||t?.message||t})\n`),null}},y=c(),k=Date.now();if(l&&!d)return Xi(e,s,!1,"invalid-snapshot"),void process.stderr.write(`\n ◇ mockup "${i.slug}" rendered snapshot was not trusted.\n`);try{const n={"Content-Type":"application/json"};Kn&&(n.Authorization=`Bearer ${Kn}`);const a=await fetch(`${On}/api/code-mockup`,{method:"POST",headers:n,body:JSON.stringify({code:Gn,slug:i.slug,title:i.title,cid:y,ts:k,term:o,desktopPng:v(i.desktop),mobilePng:v(i.mobile),html:l?d:g(i.html),...l?{previewId:l.previewId,revision:l.revision,sourceKnown:!0}:{},...w?{verified:!0,parentRevision:w}:{}})});if(!a.ok)return Xi(e,s,!1,a.status),void process.stderr.write(`\n ◇ mockup "${i.slug}" upload failed (${a.status}).\n`);const c=await a.json(),{paths:m}=c,p=!(!l||!c?.payload?.sourceKnown),h=!(!p||!w||!0!==c?.payload?.verified||c.payload.parentRevision!==w),f="string"==typeof c?.payload?.artifactHtml?c.payload.artifactHtml:null,b={kind:"mockup",__struct:!0,cid:y,term:o,slug:i.slug,title:i.title||i.slug,ts:k,paths:m,...p?{previewId:l.previewId,revision:l.revision,sourceKnown:!0,...h?{verified:!0,parentRevision:w}:{}}:{},...f?{artifactHtml:f}:{}};if(p){Object.assign(l,{term:o,slug:i.slug,title:i.title||i.slug,desktop:i.desktop,mobile:i.mobile});try{const o=r.join(e,".design-revisions");t.mkdirSync(o,{recursive:!0}),l.backupPath=r.join(o,`${l.revision}.html`),t.existsSync(l.backupPath)||t.writeFileSync(l.backupPath,l.source)}catch{}Ki.set(l.previewId,l);const n=u,s=h,a=!!(m?.html&&m?.desktop&&m?.mobile&&i.desktop&&i.mobile);if(s&&a){"preview"!==n.record.sourceKind&&Ui.set(l.previewId,{priorRecord:n.record,request:n.request});const e=f||(Buffer.byteLength(d,"utf8")<=131072?d:null);n.proof={artifact:b,artifactHtml:e},Vi(o)}}ci("code-event",{term:o,evt:b}),Xi(e,s,!0,200),process.stderr.write(`\n ◆ mockup "${i.title||i.slug}" pushed to the room.\n`)}catch(t){Xi(e,s,!1,"error"),process.stderr.write(`\n ◇ mockup "${i.slug}" send failed: ${t?.message||t}\n`)}}});function ea(e,o,n=!1){try{t.mkdirSync(e,{recursive:!0})}catch{return null}try{return t.watch(e,(s,i)=>function(e,o,n,s=!1){const i=((e,o,n,s=!1)=>{if(!o||o.endsWith(".receipt.json")||!o.endsWith(".json"))return null;const i=r.join(e,o);let a;try{a=t.statSync(i)}catch{return null}const c=o.replace(/\.json$/,""),l=`${n}/${c}`;if(qi.get(l)===a.mtimeMs)return null;if(qi.set(l,a.mtimeMs),!n)return null;let d;try{d=JSON.parse(t.readFileSync(i,"utf8"))}catch{return null}return d?.slug?In(d,{isReadyFile:e=>{try{const r=t.statSync(e);return r.isFile()&&r.size>0}catch{return!1}}})?{box:e,file:o,term:n,trustedDesignSource:s,slug:c,m:d}:(Xi(e,c,!1,"incomplete"),process.stderr.write(`\n ◇ mockup "${d.title||d.slug}" is incomplete — desktop, mobile, and source are all required.\n`),null):null})(e,o,n,s);if(!i)return;const a=Ms.get(n),c=!!a&&(!0===a._busyAnn||!0===a.session?.turnActive),l="preview"===i.m.sourceKind?`preview:${i.m.captureKey||i.m.route||i.m.slug}:${i.m.title||""}`:`authored:${i.m.slug}`,d=Zi.enqueue(n,i,{active:c,key:l});d.queued?(Xi(e,i.slug,!0,"queued"),process.stderr.write(`\n ◆ mockup "${i.m.title||i.m.slug}" ready — ${d.replaced?"replaced an earlier queued render":"queued after the final response"}.\n`)):d.delivery.catch(()=>{})}(e,i,o(),n))}catch{return null}}const ta=(e,t)=>r.join(ji,e,t);ea(ji,()=>[...Ms.keys()][0]||Js||[...Ks.keys()][0]);const ra="1"===process.env.TP_FOLLOW,oa=parseInt(process.env.TP_COLS,10)||null,na=parseInt(process.env.TP_ROWS,10)||null,sa=()=>({cols:oa||(ra?process.stdout.columns||100:Math.min(process.stdout.columns||100,120)),rows:na||(ra?process.stdout.rows||28:Math.min(process.stdout.rows||28,32))});function ia({id:e,cmd:t,args:r=[],attached:o=!1,cols:n,rows:s}){if(Ks.has(e))return;if(Ks.size>=8)return process.stderr.write(`\n ⚠ can't open "${t}" — terminal cap (8) reached; close one first.\n`),void ci("term-exit",{id:e});if(!Mn)return process.stderr.write(`\n ⚠ can't open "${t}" — node-pty isn't built (PTY mode disabled).\n`),void ci("term-exit",{id:e});const i=xe(`start the ${t} terminal`);if(!i.ok)return Si(),process.stderr.write(`\n ⚠ ${i.reason}\n`),void ci("term-exit",{id:e,reason:i.reason});const a=o?sa():null,c=ta("terms",e),l=Mn.spawn(t,r,{name:"xterm-256color",cols:n||(o?a.cols:oa||120),rows:s||(o?a.rows:na||32),cwd:process.cwd(),env:{...process.env,TP_MOCKUP_OUTBOX:c}}),d={term:l,cmd:t,attached:o,scrollback:"",buf:"",lastActionAt:null,mockupWatcher:ea(c,()=>e)};return Ks.set(e,d),o&&(Js=e),l.onData(e=>{o&&process.stdout.write(e),d.buf+=e,d.lastActionAt=Date.now(),d.scrollback=(d.scrollback+e).slice(-12e4)}),l.onExit(()=>{try{d.mockupWatcher?.close()}catch{}Ks.delete(e),xi(e),e===Js&&(Js=null,Ka()),Gs||(ci("term-exit",{id:e}),wi(),0!==Ks.size||Qn?process.stderr.write(`\n ◇ terminal "${t}" ended — still relaying ${Ks.size} terminal(s). Ctrl-C to stop.\n`):Ya())}),wi(),d}const aa=2e3,ca="[2m",la="[0m",da="[36m",ua="[35m",ma="[33m",pa="[31m",ha=e=>{const t=e&&(e.command||e.file_path||e.path||e.pattern||e.url||e.query||e.description);return t?" "+String(t).replace(/\s+/g," ").slice(0,100):""};function fa(e){const t=e=>process.stderr.write(e+"\n");switch(e.kind){case"you":return t(`${da}❯ ${e.text}${la}${e.by?` ${ca}(${e.by})${la}`:""}`);case"chat":return t(`${ca}${e.by}: ${e.text}${la}`);case"whisper":return t(`${ca}// ${e.by}: ${e.text}${la}`);case"pool":return t(e.pending?`${da}◌ pool dispatching…${la}`:`${da}◆ pool → ${e.text}${la}`);case"note":return t(`${ca}— ${e.text} —${la}`);case"clear":return t(`${ca}— context cleared —${la}`);case"usage":{const r=e.ctx;return r?t(`${ca} ctx ${r.pct}% · ${Math.round(r.used/1e3)}k/${Math.round(r.max/1e3)}k${null!=e.costUsd?` · $${e.costUsd.toFixed(3)}`:""}${la}`):void 0}case"error":return t(`${pa}✗ ${e.message}${la}`);case"tool_result":{const r=e.content,o=("string"==typeof r?r:Array.isArray(r)?r.map(e=>e?.text||"").join(" "):"").replace(/\s+/g," ").slice(0,120);return t(` ${e.isError?pa:ca}⎿ ${o||(e.isError?"error":"ok")}${la}`)}case"assistant":for(const r of e.blocks||[])"text"===r.type&&r.text?.trim()?t(`[32m⏺${la} ${r.text.trim()}`):"thinking"===r.type&&r.text?.trim()?t(`${ca}✶ ${r.text.trim().slice(0,160)}${la}`):"tool_use"===r.type&&t(` ${da}${r.name}${la}${ha(r.input)}`);return;default:return}}function wa(e,t){const r=Go(t);return process.stderr.write(`\n ◇ ${r.message}\n`),e?.id&&(va(e,r),ci("code-event",{term:e.id,evt:r})),r}function va(e,t){if(!Jo(t).known)return wa(e,t),null;zs(e,t),bo(t),e.mcpFlight=zo(e.mcpFlight,t,{now:t.ts}),e.lastActionAt=t.ts,e.lastEvent=t,e.seq&&Ro(t)&&(t.seq=e.seq.next()),e.id&&Ro(t)&&(co(e.room,e.id,[t]),null==e.archiveOldestSeq&&(e.archiveOldestSeq=t.seq));const r=Co(t);for(e.log.push(r),e.logBytes=(e.logBytes||0)+JSON.stringify(r).length+1;e.log.length>aa||e.log.length>1&&e.logBytes>cr;){const t=e.log.shift();e.logBytes-=JSON.stringify(t).length+1}return t}function ga(e){for(let t=e.length-1;t>=0;t--){const r=e[t]?.kind;if("result"===r||"error"===r||"propose"===r||"pool"===r)return!1;if("assistant"===r||"you"===r||"tool_result"===r)return!0}return!1}function ya(e,t,r=null){const o={kind:"control",text:t,by:r};va(e,o),ci("code-event",{term:e.id,evt:o})}function ka(e){const t=Do(e?.log);return!!t&&(e.pendingCheckpoint=t,!0)}function ba(e,t={}){if(!e||"codex"!==e.runtime||e.codexCompactionPromise)return!1;const r=async function(e,t={}){const r=jo(e.log,Ko,{reason:"compact"});if(!r)return void ya(e,"nothing to compact — context unchanged",t.by);const o=e.lastUsage?.ctx?.used||null;ci("code-event",{term:e.id,evt:{kind:"compact",status:"start",ts:Date.now()}});let n=!1;try{n=await(e.session.compactContext?.())}catch{n=null}finally{!e.session.turnActive&&Or(e)&&wi()}if(!0===n){ka(e);const r={kind:"compaction",trigger:"manual",preTokens:o,by:t.by,native:!0};return va(e,r),ci("code-event",{term:e.id,evt:r}),ci("code-event",{term:e.id,evt:{kind:"compact",status:"done",ts:Date.now()}}),void e.flush?.()}if(null==n)return ci("code-event",{term:e.id,evt:{kind:"compact",status:"done",ts:Date.now()}}),ya(e,"Native compaction is still settling; existing context was preserved.",t.by),void e.flush?.();if(!1===e.session.clearContext?.())return ci("code-event",{term:e.id,evt:{kind:"compact",status:"done",ts:Date.now()}}),void ya(e,"Codex context compaction unavailable right now",t.by);const s=qo(r,e.pendingCheckpoint);e.pendingRecap=s.pendingRecap,e.pendingCheckpoint=s.pendingCheckpoint;const i={kind:"compaction",trigger:"manual",preTokens:o,by:t.by};if(va(e,i),ci("code-event",{term:e.id,evt:i}),e.lastUsage?.ctx?.max){const t=Math.ceil(r.length/4),o=e.lastUsage.ctx.max,n={kind:"usage",ctx:{...e.lastUsage.ctx,used:t,max:o,pct:Math.min(100,Math.round(t/o*100)),over:t>o}};e.lastUsage=n,ci("code-event",{term:e.id,evt:n})}ci("code-event",{term:e.id,evt:{kind:"compact",status:"done",ts:Date.now()}}),e.flush?.()}(e,t);return e.codexCompactionPromise=r,r.finally(()=>{e.codexCompactionPromise===r&&(e.codexCompactionPromise=null)}).catch(()=>{}),!0}const $a=new Map;function Ta(e,t="parent"){const o=r.resolve(e||process.cwd()),n=s("git",["-C",o,"rev-parse","--verify","HEAD^{commit}"],{encoding:"utf8",timeout:3e3,stdio:["ignore","pipe","ignore"]}).trim();if(!/^[0-9a-f]{40}$/i.test(n))throw new Error("parent review source has no immutable HEAD");return{taskKey:t,cwd:o,sha:n}}function Ra({id:e,runtime:t="claude",model:o,models:n,effort:i,resume:a,log:l,commands:d,mode:u,spawnedBy:m,spawnDepth:p,cascadeRole:h,hop:f,sideParent:w,sideTask:v,pendingSideContexts:R,pendingWorkerCompletions:_,workerCompletionsInFlight:A,rolePrompt:E,sliceType:D,flowSessionId:j,flowTaskKey:K,flowTaskContract:M,flowRole:F,flowReviewTarget:z,flowReviewTargets:J,flowReviewSnapshots:G,flowReviewRound:Y,flowReviewConclusion:V,dispatchBaseSha:ee,revertTarget:te,cwd:ie,managedWorktree:ae,reviewSliceRoots:ce,openedAt:me,defer:he,provider:fe,carryRecap:we,carryCheckpoint:ye,lastUsage:ke,receivedTurnCids:$e,mcpFlight:Te,scheduleRunId:Re,scheduleDeadlineAt:Ie,scheduleOutcomeRecorded:Se,scheduleAdmissionLease:_e}){if(Ms.has(e))return;t=le(t)?t:"claude";const Ae=Z({runtime:t,capabilityId:"terminal_interrupt",input:{}});if(!Ae.ok)throw new TypeError(`Structured runtime contract rejected: ${Ae.code}`);u=se(t,{mode:u,sliceType:D,flowRole:F}),u=Fe.has(u)&&de(t,u)?u:re(t),at({runtime:t,provider:fe,model:o});const Pe="codex"===t?H():[],Ne="codex"===t&&(o||W())||void 0,Oe="codex"===t?Ne?st(Ne,Pe):tt({sliceType:"feature",runtime:"codex",catalog:Pe}):"hermes"===t?o||void 0:O({provider:fe,model:o,configuredModel:I(fe)?.ANTHROPIC_MODEL});i=oe(t,i);const Ee=Number.isInteger(p)&&p>=0?p:w||m&&!String(m).startsWith("flow:")?1:0,De=Number.isInteger(f)&&f>=0?f:Ee,je=Array.isArray(l)?l.slice(-aa):[],qe=ar(je),Ke=je.length-qe.length,Me=Re&&!0!==Se?Xo(go(Gn,e)):null,Ue=Me?.runId===Re?Me:null,Be={cmd:t,runtime:t,kind:"structured",log:qe,pending:new Map,receivedTurnCids:new Set(Array.isArray($e)?$e.filter(Boolean).slice(-1e3):[]),mcpFlight:Ho(Te),session:null,recovered:!1,commands:ue(t,d),mode:u,effort:i,models:"codex"===t?Pe:"hermes"===t?Array.isArray(n)&&n.length?n:Dn:void 0,model:"codex"===t||"hermes"===t?Oe||null:fe&&"anthropic"!==fe?Oe||x()[fe]||fe:Oe||null,provider:fe||null,spawnedBy:m||void 0,spawnDepth:Ee,cascadeRole:"conductor"===h||"worker"===h?h:null,hop:De,sideParent:w||void 0,sideTask:v||void 0,scheduleRunId:Re||null,scheduleDeadlineAt:Number.isFinite(Number(Ie))?Number(Ie):null,scheduleOutcomeRecorded:!0===Se,scheduleOutcomePending:Ue,scheduleAdmissionLease:_e||null,pendingSideContexts:Array.isArray(R)?R.filter(Boolean).slice(-4):[],pendingWorkerCompletions:Array.isArray(_)?_.filter(e=>e?.workerId&&Number(e?.turnRev)>0).slice(-6):[],workerCompletionsInFlight:Array.isArray(A)?A.filter(e=>e?.workerId&&Number(e?.turnRev)>0).slice(-6):[],flowSessionId:j||null,flowTaskKey:K||null,cwd:ie||null,managedWorktree:ae||null,sliceType:"review"===D?"review":null,flowRole:F||(j?K?J?.length||ce?.length?"reviewer":"builder":"conductor":null),flowReviewTarget:z||null,flowReviewTargets:Array.isArray(J)&&J.length?J.filter(Boolean):z?[z]:[],flowReviewSnapshots:Array.isArray(G)?G.filter(e=>e?.taskKey&&e?.sha&&e?.cwd):[],flowReviewRound:Number.isInteger(Y)&&Y>=0?Y:0,flowReviewConclusion:V?.taskKey&&["pass","reject","surface"].includes(V?.action)&&Kt(V?.receipt)?{taskKey:V.taskKey,action:V.action,round:V.round,receipt:V.receipt}:null,dispatchBaseSha:ee||null,revertTarget:te||null,openedAt:me||Array.isArray(l)&&l.find(e=>e?.ts)?.ts||Date.now(),snapshotNeedsCompaction:Ke>0||qe.some((e,t)=>e!==je[t+Ke]),logBytes:qe.reduce((e,t)=>e+JSON.stringify(t).length+1,0)};Be._turnRev=Be.log.reduce((e,t)=>Math.max(e,Number(t?.turnRev)||0),0);const Le=[...Be.log].reverse().find(e=>"result"===e?.kind&&Number(e?.turnRev)>0);Be._settledTurnRev=Number(Le?.turnRev)||null,Be._turnSettledAt=Number(Le?.ts)||null,Be.interruptedRecap=ga(Be.log)?jo(Be.log,Ko):null,Be.workerCompletionsInFlight.length&&!Be.interruptedRecap&&(Be.workerCompletionsInFlight=[]),Be.permNotifier=g({onArm:(t,r)=>Ns({kind:"needs-input",term:e,termName:di[e]||null,model:Be.model||null,permissionId:t,summary:r,pushEligible:!1}),onFire:(t,r)=>Ns({kind:"needs-input",term:e,termName:di[e]||null,model:Be.model||null,permissionId:t,summary:r,pushEligible:!0}),onResolve:t=>Ns({kind:"needs-resolved",term:e,termName:di[e]||null,model:Be.model||null,permissionId:t})}),Be.seq=$o(To(Be.log)),Be.rolePrompt=E||null,Be.flowTaskContract=M&&"object"==typeof M?M:null,Be.lastUsage=ke||null,Be.reviewSliceRoots=Array.isArray(ce)?ce.filter(Boolean):[];const We=async({reviewPass:t=!1,baselineEvidence:r=""}={})=>{if(!Be.flowSessionId||!Be.flowTaskKey)return"Not a Dispatch lane — nothing to mark done.";if("builder"!==Be.flowRole&&(!t||"reviewer"!==Be.flowRole))return"This Dispatch role cannot mark a builder slice done.";if(Be.flowDone)return"This slice is already recorded as done.";let o="";const n=!t&&!!Be.flowTaskContract?.baseline?.gate;if(n)try{o=Ye(r)}catch(e){return`Slice "${Be.flowTaskKey}" is not done: submit the real bounded baselineEvidence receipt (${e?.message||e}). Observe the assigned pre-edit gate; do not fabricate a RED sentence.`}let i=null;try{i=s("git",["-C",Be.cwd||process.cwd(),"rev-parse","HEAD"],{encoding:"utf8"}).trim()}catch{}if(!t&&Be.dispatchBaseSha&&i===Be.dispatchBaseSha)return`Slice "${Be.flowTaskKey}" is not done: HEAD is still the dispatch base (${i.slice(0,8)}). Commit the verified implementation first.`;if(!t){const e=(e=>{try{return s("git",["-C",e,"status","--porcelain=v1","--untracked-files=all"],{encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]}).split("\n").map(e=>e.trim()).filter(Boolean)}catch{return null}})(Be.cwd||process.cwd());if(null==e)return`Slice "${Be.flowTaskKey}" is not done: the bridge could not verify a clean worktree.`;if(e.length)return`Slice "${Be.flowTaskKey}" is not done: commit or remove every remaining worktree change before completion (${e.slice(0,4).join(", ")}).`}let a=null;if(!t&&Be.flowTaskContract?.scopePaths?.length){const e=pr(Be.cwd||process.cwd(),Be.dispatchBaseSha,i);if(!e)return`Slice "${Be.flowTaskKey}" is not done: the bridge could not derive its Git scope footprint.`;if(a=Mt({log:Be.log,repoRoot:Be.cwd||process.cwd(),declared:Be.flowTaskContract.scopePaths,changed:e}),!a.held)return`Slice "${Be.flowTaskKey}" is not done: scope drift detected in ${a.unexpected.join(", ")}. The approved scope must be amended before these files can ship.`}let c=null;try{c=(await ht({dir:Be.cwd||process.cwd(),id:`lane:${Be.flowSessionId}:${e}`})).url}catch{}try{const t=Be.cwd||process.cwd(),r=ct(Be.flowSessionId,Be.flowTaskKey,"_slice.done",JSON.stringify({taskKey:Be.flowTaskKey,commitSha:i||null,previewUrl:c||null}),{worktreeDir:t}),n=ut(Be.flowSessionId,{worktreeDir:t}),s=[{taskKey:Be.flowTaskKey,name:"_slice.done",path:r.path,sha:r.sha},...n.map(e=>({taskKey:e.taskKey,name:e.name,path:e.path,sha:e.sha}))],a=lt({key:Be.flowTaskKey,title:di[e]||Be.flowTaskKey},{acceptanceProof:`${o?`baseline: ${o}; `:""}${i?`committed ${i.slice(0,8)}`:"slice done"}`,artifacts:s});dt(Be.flowSessionId,a,{baseDir:process.cwd()})}catch(e){process.stderr.write(`\n ${ca}◆ flow digest skip ${Be.flowTaskKey} — ${e?.message||e}${la}\n`)}const l=n?{...Be.flowTaskContract,baseline:{...Be.flowTaskContract.baseline,evidence:o},...a?{scopeEvidence:a}:{}}:Be.flowTaskContract?{...Be.flowTaskContract,...a?{scopeEvidence:a}:{}}:null;return ci("flow-task-done",{term:e,flowId:Be.flowSessionId,taskKey:Be.flowTaskKey,laneId:e,commitSha:i,previewUrl:c,contract:l,...t?{reviewAction:"pass"}:{}},Ds),process.stderr.write(`\n ${da}◆ flow slice done — ${Be.flowTaskKey} (${i?i.slice(0,8):"no commit"})${c?` · preview ${c}`:""}${la}\n`),Be.flowDone=!0,setTimeout(()=>{try{Oa(e)}catch{}},2500),`Slice "${Be.flowTaskKey}" recorded as DONE${i?` (commit ${i.slice(0,8)})`:""}${c?`. Live preview: ${c}`:""}. The room dispatches dependent slices + assembles when all are done. You are finished — stop here.`};Be.markFlowDone=We;const ze=qt(),Je=async t=>Be.flowReviewConclusion?{ok:!0,message:`Review already concluded for ${Be.flowReviewConclusion.taskKey}; receipt ${Be.flowReviewConclusion.receipt.cid||"recorded"}.`}:ze(()=>(async t=>{if(!Be.flowSessionId||!Be.flowTaskKey||"reviewer"!==Be.flowRole)return{ok:!1,message:"Not a Dispatch review lane."};let r,o=null;try{r=Et(t);const e="string"==typeof t?JSON.parse(String(t).replace(/```(?:json)?|```/g,"").trim()):t,n=e&&(e.taskKey||e.target),s=Be.flowReviewTargets;if(!s.length)throw new Error("review lane has no authorized target");if("codex"===Be.runtime&&1!==s.length)throw new Error("Codex review lane must have exactly one authorized target");if(n&&!s.includes(n))throw new Error(`taskKey ${JSON.stringify(n)} is outside this review lane`);if(o=n||(1===s.length?s[0]:null),!o)throw new Error("taskKey is required when reviewing more than one slice")}catch(e){return{ok:!1,message:"codex"===Be.runtime?`Review verdict REJECTED: ${e?.message||e}. Re-call submit_flow_review with a valid authorized taskKey.`:`Review verdict REJECTED: ${e?.message||e}. Re-Write FLOW_REVIEW.json with {"pass":<boolean>,"reasons":["<specific finding>"],"taskKey":"<the slice you reviewed>"}.`}}if(Be.flowReviewConclusion)return{ok:!0,message:`Review already concluded for ${Be.flowReviewConclusion.taskKey}; receipt ${Be.flowReviewConclusion.receipt.cid||"recorded"}.`};const n=Be.flowReviewRound=(Be.flowReviewRound||0)+1;Be.flush?.();const s=mr.get(Be.flowSessionId)||null,i=Yt({round:n,maxRounds:Vt.maxRounds,spentTokens:s?s.spentTokens:0,budgetCap:s?s.capTokens:null,...Dt(r)});if(!i.stop){const e=n+1;return Ls(Be,"codex"===Be.runtime?`[Dispatch review — round ${e}/${Vt.maxRounds}] The happy path held, but you have NOT reported your checks exhausted. Dig one more round, then call submit_flow_review again — pass:false with specific evidence if you break it, or pass:true AND exhausted:true only when nothing remains to check.`:`[Dispatch review — round ${e}/${Vt.maxRounds}] The happy path held, but you have NOT reported your checks exhausted and you are under both the round and budget ceilings. Dig one more round: hunt the edge cases, the reload, the second click, concurrent use, the error path — the places the builder didn't. Then re-Write FLOW_REVIEW.json — pass:false with a specific reason if you break it, or pass:true AND exhausted:true if you genuinely have nothing left to check.`,{rejectionMessage:"The next Dispatch review round was not accepted; retry after the lane is available."}),process.stderr.write(`\n ${ca}◆ review round ${n} inconclusive — digging again (${e}/${Vt.maxRounds}) on ${o||Be.flowTaskKey}${la}\n`),{ok:!0,message:`Round ${n} recorded (pass, not yet exhausted). Keep hunting — asked you for round ${e}/${Vt.maxRounds}.`}}if("reject"===i.action&&o){const t=await Ua({term:e,flowId:Be.flowSessionId,taskKey:o,reviewTaskKey:Be.flowTaskKey});t.ok||Ns({kind:"needs-input",term:e,termName:di[e]||null,summary:`Dispatch review could not revert ${o}: ${t.error||t.ignored||"unknown error"}`}),process.stderr.write(`\n ${ma}◆ review REJECT (round ${n}) — reverting ${o}: ${r.reasons.join("; ").slice(0,120)}${la}\n`)}else process.stderr.write(`\n ${da}◆ review ${i.action.toUpperCase()} (round ${n}) — ${o||Be.flowTaskKey}${la}\n`);const a=o||Be.flowTaskKey,l=Be.flowReviewSnapshots.find(e=>e.taskKey===a)||null,d=Be.flowTaskContract?.digest||null;let u,m=i.action,p=r.reasons.length?r.reasons:[i.reason];try{u=jt({taskKey:a,outcome:"surface"===m?"held":m,rounds:n,candidateSha:l?.sha,acceptanceDigest:d,scope:l?.scopeEvidence,reasons:p})}catch(e){if("pass"!==m)return{ok:!1,message:`Review verdict REJECTED: ${e?.message||e}.`};m="surface",p=[...p,"Exact candidate or sealed acceptance proof is missing; pass was held."],u=jt({taskKey:a,outcome:"held",rounds:n,candidateSha:l?.sha,acceptanceDigest:d,scope:l?.scopeEvidence,reasons:p})}u.cid=c(),Be.flowReviewConclusion={taskKey:a,action:m,round:n,receipt:u},Be.flush?.(),va(Be,u),ci("code-event",{term:e,evt:u}),Be.flush?.(),ci("flow-review-verdict",{term:e,flowId:Be.flowSessionId,taskKey:a,pass:"pass"===m,reasons:p,action:m,rounds:n,surfaceToPair:"surface"===m||i.surfaceToPair,prompt:Gt({action:m,reason:m===i.action?i.reason:p.at(-1),taskKey:a,findings:p})},Ds);let h="";return"pass"===m?h=await We({reviewPass:!0}):("surface"===m&&(ci("flow-review-held",{term:e,flowId:Be.flowSessionId,reviewTaskKey:Be.flowTaskKey,taskKey:o,reasons:p},Ds),Ns({eventId:u.cid,kind:"needs-input",term:e,termName:di[e]||null,summary:`Dispatch review held ${a}: ${p.join("; ")||i.reason}`})),"reject"===m&&(Be.flowDone=!0,Be.flush?.(),setTimeout(()=>{try{Oa(e)}catch{}},2500))),{ok:!0,message:`Review verdict recorded: ${"reject"===m?`REJECT (round ${n}) — reverting ${o||"(no target)"} (${p.join("; ").slice(0,140)})`:"surface"===m?`SURFACED to the pair after ${n} round${1===n?"":"s"} — ${p.at(-1)||i.reason}`:`PASS (round ${n})`}.${h?` ${h}`:""}`}})(t));if(Be.id=e,Be.room=Gn,lo(Gn,e,Be.log.filter(e=>Ro(e))),Be.archiveOldestSeq=mo(Gn,e),Ms.set(e,Be),Be.scheduleOutcomePending?Hi(Be):Ji(Be),Be.log.length&&ga(Be.log)){const t={kind:"result",subtype:"aborted",recovered:!0};bo(t),va(Be,t),process.stderr.write(`\n ◆ closed an interrupted turn on resume (${e.slice(0,8)}) — restored idle.\n`)}const Xe=ta("sessions",e);Be.mockupWatcher=ea(Xe,()=>e,!0);const Ze=Ct(Xe,ie||process.cwd(),e);for(const e of Ze)Ki.set(e.previewId,e);Ze.length&&process.stderr.write(`\n ◆ restored ${Ze.length} thinkpool Design artifact${1===Ze.length?"":"s"} (${e.slice(0,8)}).\n`),Be.viewport=new vt({workspaceRoot:ie||process.cwd(),ownerId:e,roomCode:Gn,outbox:Xe,authContext:()=>({accessToken:Kn,supabaseUrl:Nn}),designContext:()=>{const t=Fi.get(e);return t&&"preview"===t.record.sourceKind?{requestId:t.request.cid,parentRevision:t.record.revision,captureKey:t.record.captureKey}:null}}),Be.log.length&&process.stderr.write(`\n ◆ restored ${Be.log.length} prior events (${e.slice(0,8)})${a?" + resuming live context":""}.\n`);const et=()=>({sessionId:Be.session?.sessionId||null,runtime:Be.runtime,log:Be.log,commands:Be.commands,mode:Be.mode,effort:Be.effort,model:Be.model||null,models:"hermes"===Be.runtime?Be.models||[]:void 0,provider:Be.provider||null,spawnedBy:Be.spawnedBy,spawnDepth:Be.spawnDepth||0,cascadeRole:Be.cascadeRole||null,hop:Be.hop||0,sideParent:Be.sideParent,sideTask:Be.sideTask,scheduleRunId:Be.scheduleRunId||null,scheduleDeadlineAt:Be.scheduleDeadlineAt||null,scheduleOutcomeRecorded:!0===Be.scheduleOutcomeRecorded,scheduleAdmissionLease:Be.scheduleAdmissionLease||null,pendingSideContexts:Be.pendingSideContexts,pendingWorkerCompletions:Be.pendingWorkerCompletions,workerCompletionsInFlight:Be.workerCompletionsInFlight,sliceType:Be.sliceType,flowSessionId:Be.flowSessionId,flowTaskKey:Be.flowTaskKey,flowTaskContract:Be.flowTaskContract,flowRole:Be.flowRole||null,flowReviewTargets:Be.flowReviewTargets||[],flowReviewSnapshots:Be.flowReviewSnapshots||[],flowReviewRound:Be.flowReviewRound||0,flowReviewConclusion:Be.flowReviewConclusion,dispatchBaseSha:Be.dispatchBaseSha||null,cwd:Be.cwd,managedWorktree:Be.managedWorktree,rolePrompt:Be.rolePrompt,flowReviewTarget:Be.flowReviewTarget||null,revertTarget:Be.revertTarget||null,reviewSliceRoots:Be.reviewSliceRoots||[],openedAt:Be.openedAt||null,lastUsage:Be.lastUsage||null,carryRecap:Be.pendingRecap||null,carryCheckpoint:Be.pendingCheckpoint||null,receivedTurnCids:[...Be.receivedTurnCids].slice(-1e3),mcpFlight:Be.mcpFlight}),rt=()=>Xr(Gn,e,et());if(Be.flush=()=>Zr(Gn,e,et()),Be.flowReviewConclusion?.receipt&&!Be.log.some(e=>e?.cid===Be.flowReviewConclusion.receipt.cid)){const t={...Be.flowReviewConclusion.receipt};va(Be,t),ci("code-event",{term:e,evt:t}),Be.flush()}Be.scheduleOutcomeRecorded&&Be.scheduleAdmissionLease&&Wi(Be).then(e=>{e&&Be.flush?.()});const mt=!Be.spawnedBy&&!Be.sideParent&&!Be.flowRole&&0===(Be.spawnDepth||0),pt=mt&&"conductor"!==Be.cascadeRole,ft=mt,wt=()=>P().filter(e=>"anthropic"!==e.id).map(e=>`${e.name}${e.model?` (${e.model})`:""}`).join(", "),yt=(e,{worker:t=!1}={})=>{const r=e?.runtime||Be.runtime||"claude";if("codex"===r&&e?.provider)return{error:"A Codex terminal uses its Codex/OpenAI login in v1; custom bridge providers are not wired to Codex yet. Omit provider or open a Claude terminal for that provider."};if("hermes"===r&&e?.provider)return{error:"A Hermes terminal uses its isolated Hermes profile and ACP model catalog; bridge provider IDs do not apply. Omit provider and choose an exact Hermes model ID."};const o="hermes"===Be.runtime&&Be.models?.length?Be.models:[...Ms.values()].flatMap(e=>"hermes"===e.runtime&&e.models||[]),n="codex"===r?H():"hermes"===r?o:[];if("codex"===r&&e?.model&&!nt(n).has(e.model))return{error:`Could not open a Codex terminal on ${JSON.stringify(e.model)} — that model is not in this host's visible Codex catalog.`};const s="hermes"===r?it(e?.model,n,{strictCatalog:"hermes"===Be.runtime}):null;if(s&&!s.ok)return{error:s.error};const i="claude"===r&&e?.provider?S(e.provider):e?.provider;if("claude"===r&&e?.provider&&!i){const t=wt();return{error:`Unknown registered provider ${JSON.stringify(e.provider)}. No lane was opened and the built-in Claude login was not used.${t?` Available provider names: ${t}.`:" No custom providers are registered on this host."}`}}return"claude"===r&&!e?.provider&&e?.model&&/^gpt-/i.test(e.model)?{error:`Could not open a Claude terminal on Codex model ${JSON.stringify(e.model)}. Choose runtime="codex" or a Claude model.`}:{runtime:r,model:s?.model||e?.model||(t&&e?.sliceType?ot({sliceType:e.sliceType,runtime:r,catalog:n}):void 0),mode:t?"bypassPermissions":e?.mode||("plan"===Be.mode?"default":Be.mode),provider:i}},kt=(e=Date.now())=>({runtime:Be.runtime,mode:Be.mode,hop:Be.hop||0,spawnTimes:Be.spawnTimes||[],now:e,spawnedLive:Mr(Ms.values()),totalLive:Ms.size+Ks.size,plan:Is,disabled:"1"===process.env.TP_SPAWN_OFF}),bt=r=>new Promise(o=>{if(Be.flowSessionId&&"plan"===r.risk)return ci("flow-plan",{term:e,flowId:Be.flowSessionId,plan:r.plan||""},Ds),process.stderr.write(`\n ${ua}◆ flow plan ready — flow ${String(Be.flowSessionId).slice(0,8)}.${la}\n`),void o("keep");const n=Ni(Be,{term:e,id:r.id,toolName:r.toolName,input:r.input,risk:r.risk,plan:r.plan,questions:r.questions,asker:r.asker,answerFormat:r.answerFormat,autoResolutionMs:r.autoResolutionMs}),s={resolve:o,payload:n,timer:null};Be.pending.set(r.id,s),wi(),ci("code-perm-req",n),T(Be)&&Be.permNotifier?.arm(r.id,b(n)),process.stderr.write("plan"===r.risk?`\n ${ua}◆ plan ready — approve in the room.${la}\n`:"ask"===r.risk?`\n ${da}● ${r.asker||le(t)?.label||"Agent"} is asking: ${(r.questions||[]).map(e=>e.question).join(" / ").slice(0,100)} — answer in the room.${la}\n`:`\n ${ma}● permission: ${r.toolName}${ha(r.input)} — approve in the room.${la}\n`);const i=Number(r.autoResolutionMs);"ask"===r.risk&&Number.isFinite(i)&&i>0&&(s.timer=setTimeout(()=>{if(Be.pending.get(r.id)===s){Be.pending.delete(r.id),Be.permNotifier?.resolve(r.id),ci("code-perm",{term:e,id:r.id,decision:"timeout",name:r.asker||"agent"});try{o(Ia(s,{decision:"timeout",answers:{}}))}catch{}wi()}},i),s.timer.unref?.())}),$t=Q(()=>U({name:"thinkpool",version:"1.0.0",tools:[...Be.flowRole||"review"===Be.sliceType?[]:[B("read_mcp_flight_recorder","Read the privacy-filtered MCP flight recorder for THIS terminal. Use it to diagnose a tool path or audit recent MCP activity. It reports only the MCP tool name, start time, duration, and outcome; it never records or returns arguments, result bodies, prompts, secrets, or host paths.",{limit:L.number().int().min(1).max(100).optional().describe("maximum recent calls to return (default 40)")},async e=>({content:[{type:"text",text:Wo(Be.mcpFlight,{limit:e?.limit})}]}))],..."hermes"===t&&"ordinary"===ge({flowRole:Be.flowRole,sliceType:Be.sliceType})?[B("request_user_input","Ask the people in this thinkpool room one to three multiple-choice questions and wait for their answer. Use this for choices that genuinely block useful progress. Each question needs two or three mutually exclusive options; a free-text answer remains available in the room card.",{questions:L.array(L.object({id:L.string().min(1).max(80),header:L.string().min(1).max(12),question:L.string().min(1).max(500),options:L.array(L.object({label:L.string().min(1).max(80),description:L.string().min(1).max(240)})).min(2).max(3),multiSelect:L.boolean().optional(),isSecret:L.boolean().optional()})).min(1).max(3),autoResolutionMs:L.number().int().min(6e4).max(24e4).optional()},async e=>{const t=e.questions.map(e=>({...e,options:e.options.map(e=>({...e}))})),r=await bt({id:`hermes-question:${c()}`,toolName:"AskUserQuestion",input:{questions:t},risk:"ask",questions:t,asker:"Hermes",answerFormat:"hermes",autoResolutionMs:e.autoResolutionMs});return{content:[{type:"text",text:JSON.stringify(Ce(r,t))}]}})]:[],...gt({tool:B,z:L,manager:Be.viewport}),B("read_terminal","Read-only view of ANOTHER terminal in this thinkpool Code room (a sibling agent or a shell the people are using). The current ROOM NOW snapshot is the default roster. Call with no arguments only when that snapshot is missing or truncated; this optional full-roster lookup has its own one-call allowance. Call with `terminal` (a ref, id, name, or command) only when that lane’s detailed activity is needed. Targeted transcript reads have a separate bounded allowance: never poll, collect each finished owned worker once, then close it immediately.",{terminal:L.string().optional().describe("ref, id, or command of the terminal to read; omit to list the open terminals"),lines:L.number().int().positive().max(fr.maxLines).optional().describe(`how many recent lines to return (default ${fr.defaultLines})`)},async t=>{const r=vr({selfId:e,sessions:Ms,terms:Ks,names:di}),o=t?.terminal?gr(r,t.terminal):null;if(t?.terminal&&!o)return{content:[{type:"text",text:hr({selfId:e,sessions:Ms,terms:Ks,names:di,terminal:t.terminal,lines:t?.lines})}]};const n=wr({targeted:!!t?.terminal,targetedCount:Be.peekCount,rosterCount:Be.peekRosterCount,budgetTurnRev:Be.peekBudgetTurnRev,currentTurnRev:Be._turnRev});if(Be.peekCount=n.targetedCount,Be.peekRosterCount=n.rosterCount,Be.peekBudgetTurnRev=n.budgetTurnRev,!n.ok)return{content:[{type:"text",text:n.reason}]};const s="agent"===o?.kind?Ms.get(o.id):null;return{content:[{type:"text",text:hr({selfId:e,sessions:Ms,terms:Ks,names:di,terminal:t?.terminal,lines:t?.lines})+Er({parentRuntime:Be.runtime,parentModels:Be.models,targetRuntime:s?.runtime,targetLog:s?.log})}]}}),...Be.flowRole?[]:[B("search_past_work","Search bounded saved terminal work from THIS thinkpool room. Returns privacy-filtered excerpts for prior decisions, failed attempts, commands, checks, and Dispatch receipts. Every hit cites the room, terminal, date, and event sequence. It never searches another room, exposes prompts or host paths, or changes state.",{query:L.string().min(2).max(160).describe("specific terms from the prior decision, failure, command, check, or feature"),limit:L.number().int().min(1).max(8).optional().describe("maximum cited hits; default 8")},async e=>{if(Be.pastWorkSearchTurnRev!==Be._turnRev&&(Be.pastWorkSearchTurnRev=Be._turnRev,Be.pastWorkSearchCount=0),(Be.pastWorkSearchCount||0)>=3)return{content:[{type:"text",text:"Past-work search limit reached for this turn (3). Use the cited results already returned or narrow the next room turn."}]};Be.pastWorkSearchCount=(Be.pastWorkSearchCount||0)+1;const t=new Map;for(const e of ro(Gn,40))e?.id&&Array.isArray(e.log)&&t.set(e.id,{id:e.id,name:di[e.id]||e.name||"Archived terminal",savedAt:e.savedAt||e._archivedAt,log:e.log});for(const[e,r]of Ms)t.set(e,{id:e,name:di[e]||`Terminal ${String(e).slice(0,8)}`,savedAt:r.openedAt||Date.now(),log:r.log||[]});let r;try{r=Bt([...t.values()],e?.query||"",{room:Gn,limit:e?.limit})}catch(e){return{content:[{type:"text",text:`Past-work search rejected: ${e?.message||e}`}]}}return{content:[{type:"text",text:Ut(r,e?.query||"")}]}})],B("list_sessions","List OTHER thinkpool Code sessions (rooms) reachable from this room: your own rooms on this machine plus your partner's shared rooms over the pair bus. Returns each room's code, name, and partner host when remote so you can read into one with read_session. This is thinkpool Ensemble across SESSIONS, not just terminals. Read-only.",{},async()=>{const e=e=>({content:[{type:"text",text:e}]});if(Be.pairPeekCount=(Be.pairPeekCount||0)+1,Be.pairPeekCount>Tr.peekPerTurnCap)return e(`Cross-session read limit reached for this turn (${Tr.peekPerTurnCap}). Continue with what you have.`);const t=await Pi("pair-list-req",{});return e(Ir(t?.rooms,{thisRoom:Gn,error:t?.error}))}),B("read_session","Read-only view INTO another thinkpool Code session returned by list_sessions—either your own room on this machine or your partner's shared room over the pair bus. Pass `session` (the room code) and optionally `terminal` (a ref/name in that room) to read its recent activity; omit `terminal` to list that room's terminals. It never changes the other session.",{session:L.string().describe("the room code of the other session (from list_sessions)"),terminal:L.string().optional().describe("ref, id, or name of a terminal in that room; omit to list that room's terminals"),lines:L.number().int().positive().max(fr.maxLines).optional().describe(`how many recent lines to return (default ${fr.defaultLines})`)},async e=>{const t=e=>({content:[{type:"text",text:e}]}),r=String(e?.session||"").toUpperCase().trim();if(!r)return t("Name a room code to read (call list_sessions to see them).");if(r===Gn)return t("That is this room — use read_terminal for terminals in your own room.");if(Be.pairPeekCount=(Be.pairPeekCount||0)+1,Be.pairPeekCount>Tr.peekPerTurnCap)return t(`Cross-session read limit reached for this turn (${Tr.peekPerTurnCap}). Continue with what you have.`);const o=await Pi("pair-peek-req",{targetRoom:r,terminal:e?.terminal,lines:e?.lines},Rr.busTimeoutMs+2e3);return t(o?.error?o.error:o?.text||`Room ${r} returned nothing.`)}),...Be.flowRole?[]:[B("post_to_session","Hand a task or message to an agent in ANOTHER of your thinkpool Code sessions — your own room on this machine, or your partner's room reachable through the pair (a room code from list_sessions). Pass `session` (the room code), `text` (what to send), and optionally `terminal` (which agent lane in that room). A person in YOUR room approves sending AND a person in the TARGET room approves receiving before it is delivered. An agent reached this way cannot post onward to a third room. Read the target with read_session first, and use this sparingly — only when the people clearly want the rooms to coordinate.",{session:L.string().describe("the room code of the other session (from list_sessions)"),text:L.string().describe("the message or task to deliver to that room's agent"),terminal:L.string().optional().describe("ref/name of the agent lane in that room; omit if it has a single agent")},async t=>{const r=e=>({content:[{type:"text",text:e}]}),o=Sr({roomHop:Be.roomHop||0,postCount:Be.crossRoomPostCount||0,disabled:"1"===process.env.TP_PAIRBUS_OFF});if(!o.ok)return r(o.reason);const n=String(t?.session||"").toUpperCase().trim();if(!n)return r("Name a room code to post to (call list_sessions to see your rooms).");if(n===Gn)return r("That is this room — use post_to_terminal for an agent in your own room.");const s=String(t?.text||"").trim();if(!s)return r("Nothing to send — provide the task or message text.");Be.crossRoomPostCount=(Be.crossRoomPostCount||0)+1;const i=await Pi("pair-post-req",{targetRoom:n,terminal:t?.terminal,text:s,fromRoom:Gn,fromTerminalName:di[e]||void 0},18e4);return r(i?.error?i.error:i?.ok?`Delivered to room ${n}${i.ref?` (lane ${i.ref})`:""} — it will respond in its own room; check back with read_session.`:`Room ${n} did not accept the message.`)})],...Be.flowRole?[]:[B("post_to_terminal","Send a message or task to ANOTHER AGENT terminal in this thinkpool Code room. Use `terminal` (a ref/id/command from read_terminal) and `text` (what to send). A person in the room must approve before it is delivered, and an agent reached via a cross-post cannot post onward. Targets agent terminals only, not plain shells. Use read_terminal first to understand the sibling.",{terminal:L.string().describe("ref, id, or command of the AGENT terminal to send to (from read_terminal)"),text:L.string().describe("the message or task to deliver to that terminal")},async t=>{const r=e=>({content:[{type:"text",text:e}]}),o=yr({hop:Be.hop||0,postCount:Be.postCount||0,disabled:"1"===process.env.TP_CROSSPOST_OFF});if(!o.ok)return r(o.reason);const n=vr({selfId:e,sessions:Ms,terms:Ks,names:di}),s=gr(n,t?.terminal);if(!s)return r(`No terminal matches "${t?.terminal}". Call read_terminal with no argument to list the open terminals.`);if("agent"!==s.kind)return r(`Terminal ${s.ref} is a shell, not an agent — cross-posting is only allowed to agent terminals.`);const i=Ms.get(s.id);if(!i?.session)return r(`Terminal ${s.ref} is no longer live.`);if(!t?.text||!String(t.text).trim())return r("Nothing to send — provide a non-empty `text` for the post.");Be.postCount=(Be.postCount||0)+1;const a=String(e).slice(0,8),c=`[From: terminal ${a}'s agent — relayed via thinkpool cross-terminal, approved by a person in the room]\n${t.text}`;i.hop=(Be.hop||0)+1,i.peekCount=0,i.peekRosterCount=0,i.postCount=0;const l={kind:"you",text:c,by:`terminal ${a} (agent)`,crosspost:!0,relaySourceName:di[e]||void 0};yi(s.id,t.text);const d=Ls(i,c,{visibleEvent:l,rejectionMessage:"The cross-terminal task was not accepted; retry after the lane is available."});return d.accepted?r(`Delivered to terminal ${s.ref} (${s.cmd}). It will respond in its own lane; check back with read_terminal.`):r(d.error?`Could not deliver to terminal ${s.ref} — it may have just closed.`:`Could not deliver to terminal ${s.ref} — it refused the turn. Check its visible host-memory/runtime error.`)})],...pt?[B("open_main_terminal","Open a separate independent MAIN terminal on any supported runtime: Claude (including a connected Anthropic-compatible BYOK provider), Codex, or Hermes. Use this whenever a person asks to open, launch, start, spawn, or create a new, separate, independent, top-level, or main terminal—even for ordinary work or a handoff and even without the words Cascade or conductor. If the wording includes new or separate terminal, main-terminal routing wins. This is the top-level room lifecycle, NOT Ensemble dispatch: the new terminal has no spawnedBy owner and appears as a main terminal. Never substitute spawn_terminal, which creates worker sub-terminals only. Give the main terminal its full initial task; it can use spawn_terminal for bounded workers.",{name:L.string().max(80).optional().describe('short label for the main conductor, e.g. "Cascade · Multi-device chaos"'),task:L.string().min(1).describe("complete initial brief for the independent main terminal"),model:L.string().optional().describe("optional main-terminal model, e.g. opus / gpt-5.6-sol / nous:z-ai/glm-5.2"),runtime:L.enum(["claude","codex","hermes"]).optional().describe("agent runtime; every top-level terminal can open every supported runtime, defaulting to its own"),provider:L.string().optional().describe("optional registered Claude-compatible provider name or id; omit for built-in Anthropic"+(wt()?`. Available now: ${wt()}`:"")),mode:L.enum(["default","acceptEdits","bypassPermissions","plan"]).optional().describe("permission mode; defaults to inheriting this main terminal, except plan falls back to default")},async t=>{const r=e=>({content:[{type:"text",text:e}]}),o=yt(t);if(o.error)return r(o.error);const n=xe("start another Cascade conductor");if(!n.ok)return Si(),r(n.reason);const s=(()=>{const e=Date.now(),t=br({hop:0,spawnTimes:Be.spawnTimes||[],now:e,spawnedLive:0,totalLive:Ms.size+Ks.size,plan:Is,disabled:"1"===process.env.TP_SPAWN_OFF});return t.ok?(Be.spawnTimes=[...(Be.spawnTimes||[]).filter(t=>Number.isFinite(t)&&t>e-$r.windowMs),e],t):t})();if(!s.ok)return r(s.reason);const i=c(),a=await Ci(i);if(!a.ok)return r(a.reason||"The bridge machine cannot accept another live lane yet.");const l=String(i).slice(0,8),d=String(e).slice(0,8);t?.name&&(di[i]=String(t.name).slice(0,80),ao(Gn,di)),Ra({id:i,runtime:o.runtime,model:o.model,provider:o.provider,mode:o.mode,spawnDepth:0,cascadeRole:"conductor",hop:0});const u=Ms.get(i);if(!u)return xi(i),t?.name&&(delete di[i],ao(Gn,di)),r("Could not open the main conductor terminal — the machine terminal cap may have just been reached.");u.peekCount=0,u.peekRosterCount=0,u.postCount=0,u.spawnTimes=[],wi();const m=`[Task from main terminal ${d}'s agent — opened as an independent MAIN CASCADE CONDUCTOR terminal, not an Ensemble child]\n${String(t.task).trim()}`,p={kind:"you",text:m,by:`main terminal ${d} (agent)`,crosspost:!0,relaySourceName:di[e]||void 0};yi(i,t.task);const h=Ls(u,m,{visibleEvent:p,rejectionMessage:"The initial conductor task was not accepted; retry after the lane is available."});return h.accepted?r(`Opened independent main Cascade conductor ${l}${t?.name?` ("${t.name}")`:""} and handed it the task. It is a main terminal, not an Ensemble lane.`):r(h.error?`Opened main conductor ${l}${t?.name?` ("${t.name}")`:""}, but it may still be starting — the initial task could not be delivered.`:`Opened main conductor ${l}, but host pressure prevented its runtime from starting. Existing lanes remain connected; free memory and retry the task.`)})]:[],...ft?[B("spawn_terminal","Open a visible WORKER SUB-TERMINAL on any supported runtime—Claude (including a connected Anthropic-compatible BYOK provider), Codex, or Hermes—from any top-level terminal. spawn_terminal is worker-only: it can never create a Cascade conductor or main terminal. For ordinary workers use an appropriate non-Sol tier: gpt-5.6-luna or gpt-5.4-mini for scaffold/search, gpt-5.6-terra for feature/fix, and a balanced tier for adversarial review; never select Sol for routine workers. A Hermes sliceType=review lane is structurally reviewer-scoped before ACP startup: it can inspect files and use the bridge review-check tool, but has no terminal, write, patch, delegate, browser, skill, memory, or session-history schema. Pass sliceType=scaffold for mechanical work, feature/fix for builders, and review for adversarial verification. Give the worker a bounded initial task, collect its result with read_terminal, then ALWAYS close_terminal it.",{name:L.string().max(80).optional().describe('a short label for the new lane so the room (and you) can find it, e.g. "Research: topologies"'),task:L.string().optional().describe("an initial task to hand the new lane immediately; omit to open it idle"),model:L.string().optional().describe("model for the chosen runtime; Hermes accepts its profile default or an ACP ID such as nous:z-ai/glm-5.2"),sliceType:L.enum(["scaffold","feature","fix","review"]).optional().describe("optional cascade slice tier; omitted preserves normal inheritance/default, explicit model wins"),runtime:L.enum(["claude","codex","hermes"]).optional().describe("agent runtime for the new lane; every top-level terminal can open every supported runtime"),provider:L.string().optional().describe("optional registered Claude-compatible provider name or id; omit for built-in Anthropic"+(wt()?`. Available now: ${wt()}`:"")),mode:L.enum(["default","acceptEdits","bypassPermissions","plan"]).optional().describe("accepted for compatibility; spawned workers always run autonomously in bypassPermissions")},async t=>{const r=e=>({content:[{type:"text",text:e}]}),o=yt(t,{worker:!0});if(o.error)return r(o.error);const n=Date.now(),s=kt(n),i=br(s);if(!i.ok)return r(i.reason+xr(e,[...Ms.entries()].map(([e,t])=>({ref:String(e).slice(0,8),name:di[e]||void 0,spawnedBy:t.spawnedBy,busy:(t.session?.turnActive??!1)||(t.pending?.size??0)>0}))));const a=xe("start another worker lane");if(!a.ok)return Si(),r(a.reason);const l={...t,runtime:o.runtime,model:o.model,provider:o.provider,mode:se(o.runtime,{mode:o.mode,sliceType:t?.sliceType})};let d;try{d=Dr({args:l,initiatorTerminalId:e,roomCode:Gn,bridgeAuthorityId:ms,localAuthorityId:e,context:{...s,providerName:o.provider?x()[o.provider]||o.provider:void 0,resolvedModel:o.model}})}catch(e){return process.stderr.write(`\n ${pa}✗ dispatch preview rejected — ${e?.message||e}${la}\n`),r("Dispatch preview could not be built safely. No lane was created.")}const u=Date.now(),m=kt(u),p=jr({preview:d,args:l,initiatorTerminalId:e,roomCode:Gn,bridgeAuthorityId:ms,localAuthorityId:e,context:{...m,providerName:o.provider?x()[o.provider]||o.provider:void 0,resolvedModel:o.model}});if(!p.ok)return r(p.reason||"Dispatch became stale or exceeded a cap. No lane was created.");Be.spawnTimes=[...(Be.spawnTimes||[]).filter(e=>Number.isFinite(e)&&e>u-$r.windowMs),u];const h=c(),f=await Ci(h);if(!f.ok)return r(f.reason||"The bridge machine cannot accept another live lane yet.");const w=String(h).slice(0,8),v=String(e).slice(0,8);t?.name&&(di[h]=String(t.name).slice(0,80),ao(Gn,di));const g=(Be.spawnDepth||0)+1,y=(Be.hop||0)+1;let k=[];if("review"===t?.sliceType)try{k=[Ta(Be.cwd||process.cwd())]}catch(e){return r(`Review lane was not opened: could not pin the spawning parent’s HEAD (${e?.message||e}).`)}Ra({id:h,runtime:o.runtime,model:o.model,provider:o.provider,mode:l.mode,sliceType:t?.sliceType,flowReviewTargets:k.map(e=>e.taskKey),flowReviewSnapshots:k,spawnedBy:e,spawnDepth:g,cascadeRole:"worker",hop:y});const b=Ms.get(h);if(!b)return xi(h),t?.name&&(delete di[h],ao(Gn,di)),r("Could not open a new lane. No host-capacity slot was kept; retry after checking the runtime.");if(b.peekCount=0,b.peekRosterCount=0,b.postCount=0,b.spawnTimes=[],wi(),t?.task){const o=k.length?`\n\n[Immutable review target: parent at spawn time — target key "parent", pinned HEAD ${k[0].sha}. Use read_review_file with target="parent" for source and run_review_check with target="parent" for fixed checks. Do not infer a target path/ref or mutate anything.]`:"",n=`[Task from terminal ${v}'s agent — relayed via thinkpool Ensemble; you are its WORKER SUB-TERMINAL, never a main terminal or Cascade conductor]\n${t.task}${o}`,s={kind:"you",text:n,by:`terminal ${v} (agent)`,crosspost:!0,relaySourceName:di[e]||void 0};yi(h,t.task);const i=Ls(b,n,{visibleEvent:s,rejectionMessage:"The initial worker task was not accepted; retry after the lane is available."});return i.accepted?r(`Opened agent lane ${w}${t?.name?` ("${t.name}")`:""} and handed it the task. It runs in its own lane — check back with read_terminal, then close_terminal when done.`):r(i.error?`Opened lane ${w}${t?.name?` ("${t.name}")`:""}, but it may still be starting — could not hand off the task. Try post_to_terminal shortly.`:`Opened lane ${w}${t?.name?` ("${t.name}")`:""}, but host pressure prevented its runtime from accepting the task. Existing lanes remain connected; free memory and retry.`)}return r(`Opened idle agent lane ${w}${t?.name?` ("${t.name}")`:""}. Hand it work with post_to_terminal, or a person can type into it.`)})]:[],...Be.flowRole?[]:[B("close_terminal","Close an IDLE agent lane that YOU opened with spawn_terminal (identified by ref/id/name). Active turns and permission waits are protected: collect the completed result with read_terminal before closing. You can only close lanes you spawned yourself — never a sibling someone else is working in, and never the main terminal.",{terminal:L.string().describe("ref, id, or name of the lane you spawned (from read_terminal)")},async t=>{const r=e=>({content:[{type:"text",text:e}]}),o=vr({selfId:e,sessions:Ms,terms:Ks,names:di}),n=gr(o,t?.terminal);if(!n)return r(`No terminal matches "${t?.terminal}". Call read_terminal with no argument to list the open terminals.`);const s=Ms.get(n.id);if(!s)return r(`Terminal ${n.ref} is not an agent lane (or already closed) — only spawned agent lanes can be closed this way.`);const i=_r({callerId:e,spawnedBy:s.spawnedBy,busy:(s.session?.turnActive??!1)||(s.pending?.size??0)>0});return i.ok||"not-owner"!==i.reason?i.ok||"busy"!==i.reason?(Oa(n.id),r(`Closed agent lane ${n.ref}${n.name?` ("${n.name}")`:""}.`)):r(`Terminal ${n.ref} is still working or waiting for a permission decision. close_terminal will not kill an active turn. Wait until read_terminal reports it idle/completed, collect its result, then close it. If it is genuinely stuck, ask a person to press Stop.`):r(`Terminal ${n.ref} was not opened by you — you can only close lanes you spawned yourself. Leave it to the person running it.`)})],..."builder"===Be.flowRole?[B("mark_flow_done","thinkpool Dispatch ONLY — call this ONCE when your slice is built, RUNS, and meets its acceptance criteria. For a gate-first task, pass `baselineEvidence`: the real, bounded pre-edit command/behavior receipt proving the assigned failure/absence. Never fabricate a RED sentence. The bridge derives the edited-file footprint from Git, compares it with the sealed scopePaths, and refuses unexpected touches. Records your latest commit as the slice's atomic-revert target and signals the room that this slice is done (which unblocks slices that depended on you). Do not call before the slice actually runs + meets acceptance.",{baselineEvidence:L.string().max(1400).optional().describe("real single-line pre-edit baseline command/behavior receipt; required for new gate-first tasks")},async e=>({content:[{type:"text",text:await We({baselineEvidence:e?.baselineEvidence||""})}]}))]:[],..."conductor"===Be.flowRole?[B("submit_flow_plan",'thinkpool Dispatch CONDUCTOR ONLY — submit your decomposition for human approval. Call this ONCE when your task-graph is ready. Pass it as `plan`: a JSON string {"summary":"<one line; assumptions: …>","tasks":[{"key":"<kebab>","title":"…","scope":"human-readable ownership","scopePaths":["repo/file.js","repo/directory/**"],"acceptance":"observable proof","nonGoals":["bounded exclusion"],"baseline":{"gate":"what fails/is absent before edits","evidence":"optional observed receipt"},"deps":["<key>"],"sliceType":"feature|scaffold|review|fix"}]}. Each builder/fix/scaffold needs acceptance, machine-readable repo-relative scopePaths, nonGoals, and a safe bounded baseline gate; review tasks inherit one builder contract. When uncertain, choose and record a safe reversible default; ask only when a choice materially expands scope or authority. The room validates and persists the graph, then shows approval. Do NOT use ExitPlanMode or write a plan file.',{plan:L.string().describe("the task-graph as a JSON string (the {summary, tasks:[…]} object)")},async t=>{const r=e=>({content:[{type:"text",text:e}]});if(!Be.flowSessionId||"conductor"!==Be.flowRole)return r("Not a Dispatch conductor — there is no plan to submit.");let o;try{o=Qe(Ve(t?.plan||""),Be.runtime)}catch(e){return r(`Plan REJECTED: ${e?.message||e}. Re-call submit_flow_plan with valid JSON: a non-empty acyclic tasks array; each builder/fix/scaffold has observable acceptance, repo-relative scopePaths, bounded nonGoals, and a safe baseline gate that says what fails/is absent; each review targets exactly one builder contract.`)}return ci("flow-plan",{term:e,flowId:Be.flowSessionId,plan:JSON.stringify(o)},Ds),process.stderr.write(`\n ${ua}◆ flow plan submitted — flow ${String(Be.flowSessionId).slice(0,8)} (${o.tasks.length} slice${1===o.tasks.length?"":"s"}).${la}\n`),r(`Plan submitted (${o.tasks.length} slice${1===o.tasks.length?"":"s"}) with gate-first contracts. Safe reversible assumptions belong in the summary; user steering remains authoritative. The room is showing approval. You are DONE; stop here and wait for approval (lane dispatch is the room's job).`)})]:[],..."reviewer"===Be.flowRole?[B("submit_flow_review",'thinkpool Dispatch REVIEWER ONLY — submit one bounded adversarial review round. Pass `verdict` as JSON: {"pass":boolean,"reasons":["specific evidence"],"taskKey":"authorized reviewed task","exhausted":boolean}. This is the only review completion path; do not call mark_flow_done and do not write FLOW_REVIEW.json.',{verdict:L.string().describe("the structured review verdict as a JSON string")},async e=>({content:[{type:"text",text:(await Je(e?.verdict||"")).message}]}))]:[],..."reviewer"===Be.flowRole||"review"===Be.sliceType?[B("read_review_file","Read one regular file from the declared immutable review target. This always reads the target’s pinned Git object, never a live worktree; target and path are validated and the response is byte-bounded.",{target:L.string(),path:L.string()},async e=>({content:[{type:"text",text:JSON.stringify(await zt({target:e?.target,filePath:e?.path,snapshots:Be.flowReviewSnapshots}))}]}),Wt),B("run_review_check","Run one fixed verification check against an immutable git-archived review target. This accepts only the declared target and a fixed check id, but executes target-defined code in a scratch archive that is not an OS filesystem/network sandbox. It can require approval and must be refused by approvalPolicy=never reviewers.",{target:L.string(),checkId:L.string()},async e=>({content:[{type:"text",text:JSON.stringify(await Jt({target:e?.target,checkId:e?.checkId,snapshots:Be.flowReviewSnapshots}))}]}),Ht)]:[]]})),Tt=r.join(ie||process.cwd(),"FLOW_REVIEW.json"),Rt=Be.reviewSliceRoots.length?({toolName:e,input:t})=>{for(const r of Be.reviewSliceRoots){const o=Lt({toolName:e,input:t,sliceRoot:r,verdictFile:Tt});if(!o.allow)return o}return{allow:!0,reason:"no reviewed slice targeted"}}:null;Be.deferred=!!he;const It=qo(we,ye);Be.pendingRecap=It.pendingRecap,Be.pendingCheckpoint=It.pendingCheckpoint;const St=[_n({spawnedBy:Be.spawnedBy,spawnDepth:Be.spawnDepth,cascadeRole:Be.cascadeRole,flowRole:Be.flowRole,sideParent:Be.sideParent}),ft?An:""].filter(Boolean).join("\n\n"),xt="claude"===t?C(fe):null;let _t=!1;const At=!0===xt?.policy?.enabled?{policy:xt.policy,providers:N(),providerId:xt.target.providerId,model:xt.target.actualConfiguredModel,requestedModel:Oe||xt.target.actualConfiguredModel,bridgeHostId:vs,circuit:gs,turnRev:()=>(Number(Be._turnRev)||0)+1,capGate:()=>{const t=Be.flowSessionId?mr.get(Be.flowSessionId):null,r=q(t);return r.configured||_t||(_t=!0,process.stderr.write(`\n ${ca}◇ provider resilience cap_not_configured (${String(e).slice(0,8)})${la}\n`)),r}}:null;if(Be.session=X(t,{cwd:ie||process.cwd(),model:Oe,effort:i,resume:a,mode:u,terminalRolePrompt:St,rolePrompt:E,prepareCwd:ie||j||K?null:()=>{try{Be.managedWorktree?.dir||(Be.managedWorktree=be({terminalId:e,cwd:process.cwd()})),Be.cwd=Be.managedWorktree.dir,Be.viewport.setWorkspaceRoot(Be.cwd);try{Be.flush?.()}catch{}return Be.cwd}catch(t){return process.stderr.write(`\n ◇ terminal worktree unavailable (${String(e).slice(0,8)}): ${t?.message||t}; using bridge checkout.\n`),ie||process.cwd()}},suggest:!fe||"anthropic"===fe,roomContext:()=>{const t=function(e){const t=e||process.cwd(),r=$a.get(t);if(r&&Date.now()-r.at<6e4)return r.list;let o=[];try{o=s("git",["-C",t,"worktree","list"],{encoding:"utf8",timeout:3e3,stdio:["ignore","pipe","ignore"]}).split("\n").map(e=>e.trim()).filter(Boolean)}catch{o=[]}return $a.set(t,{at:Date.now(),list:o}),o}(ie||process.cwd());return Cr({selfId:e,sessions:Ms,terms:Ks,names:di,worktrees:t.length>1?t:[]})},lazy:ne({runtime:t,defer:he,cwd:ie,flowSessionId:j,flowTaskKey:K,models:Be.models}),admitStart:()=>{const e=xe("start this agent runtime");return e.ok||Si(),e},reviewGate:Rt,blockSubagents:"conductor"===Be.flowRole,onSubmitPlan:t=>{if(!Be.flowSessionId||"conductor"!==Be.flowRole)return{ok:!1,message:"Not a Dispatch conductor — nothing to submit."};let r;try{r=Qe(Ve(t||""),Be.runtime)}catch(e){return{ok:!1,message:`Plan REJECTED: ${e?.message||e}. Re-Write FLOW_PLAN.json with valid JSON: a non-empty acyclic tasks array; each builder/fix/scaffold has observable acceptance, bounded nonGoals, and a baseline gate that says what fails/is absent; each review targets exactly one builder contract.`}}return ci("flow-plan",{term:e,flowId:Be.flowSessionId,plan:JSON.stringify(r)},Ds),process.stderr.write(`\n ${ua}◆ flow plan submitted — flow ${String(Be.flowSessionId).slice(0,8)} (${r.tasks.length} slice${1===r.tasks.length?"":"s"}).${la}\n`),{ok:!0,message:`Plan SUBMITTED (${r.tasks.length} slice${1===r.tasks.length?"":"s"}) with gate-first contracts. Record safe reversible assumptions in the summary; user steering remains authoritative. The room is showing approval. You are DONE: stop here and wait for approval.`}},onLaneDone:"builder"===Be.flowRole?async e=>{let t="";try{const r=JSON.parse(String(e||"").trim());t="string"==typeof r?.baselineEvidence?r.baselineEvidence:""}catch{}return{ok:!0,message:await We({baselineEvidence:t})}}:null,onReviewVerdict:"reviewer"===Be.flowRole?Je:null,mcpServers:{thinkpool:$t},requiredMcpTools:"hermes"===t?ve(ge({flowRole:Be.flowRole,sliceType:Be.sliceType}),{canSpawnWorkers:ft}):void 0,hermesRole:"hermes"===t?ge({flowRole:Be.flowRole,sliceType:Be.sliceType}):void 0,crossPostGate:()=>yr({hop:Be.hop||0,postCount:Be.postCount||0,disabled:"1"===process.env.TP_CROSSPOST_OFF}),didSpawnTarget:t=>{try{const r=vr({selfId:e,sessions:Ms,terms:Ks,names:di}),o=gr(r,t);if(!o)return!1;const n=Ms.get(o.id);return!!n&&n.spawnedBy===e}catch{return!1}},crossRoomPostGate:()=>Sr({roomHop:Be.roomHop||0,postCount:Be.crossRoomPostCount||0,disabled:"1"===process.env.TP_PAIRBUS_OFF}),env:{...process.env,...He({flowSessionId:j,mode:u}),...I(fe)||{},TP_MOCKUP_OUTBOX:Xe},resilience:At,onTurnStart:(t={})=>{!0===Be._busyAnn?function(e,t=Date.now()){e._turnRev=(Number(e._turnRev)||0)+1,e._turnStart=t,e._busyAnn=!0,e._settledTurnRev=null,e._turnSettledAt=null}(Be):Bs(Be);const r=t._thinkpoolQueuedEcho;if(r){const t={kind:"you",...r};va(Be,t),ci("code-event",{term:e,evt:t})}wi()},onEvent:r=>{if(!Jo(r).known)return fa(wa(Be,r)),void wi();const n="system"===r.kind&&pe({current:Be.commands,incoming:ue(t,r.commands),onChanged:e=>{Be.commands=e,wi(),rt()}});if(a&&"error"===r.kind){const t=Be.interruptedRecap||jo(Be.log,Ko),n=Hr(Be,{message:r.message,recap:t,reopen:t=>{Be.imageQueue?.close();try{Be.mockupWatcher?.close()}catch{}return Ms.delete(e),Ra({id:e,runtime:Be.runtime,model:Be.model||o,effort:Be.effort,provider:Be.provider,log:Be.log,commands:Be.commands,mode:Be.mode,spawnedBy:Be.spawnedBy,spawnDepth:Be.spawnDepth,cascadeRole:Be.cascadeRole,hop:Be.hop,sideParent:Be.sideParent,sideTask:Be.sideTask,pendingSideContexts:Be.pendingSideContexts,pendingWorkerCompletions:Be.pendingWorkerCompletions,workerCompletionsInFlight:Be.workerCompletionsInFlight,sliceType:Be.sliceType,flowSessionId:Be.flowSessionId,flowTaskKey:Be.flowTaskKey,flowTaskContract:Be.flowTaskContract,flowRole:Be.flowRole,flowReviewTarget:Be.flowReviewTarget,flowReviewTargets:Be.flowReviewTargets,flowReviewSnapshots:Be.flowReviewSnapshots,flowReviewRound:Be.flowReviewRound,flowReviewConclusion:Be.flowReviewConclusion,dispatchBaseSha:Be.dispatchBaseSha,revertTarget:Be.revertTarget,cwd:Be.cwd,managedWorktree:Be.managedWorktree,rolePrompt:Be.rolePrompt,reviewSliceRoots:Be.reviewSliceRoots,openedAt:Be.openedAt,lastUsage:Be.lastUsage,mcpFlight:Be.mcpFlight,carryRecap:t,carryCheckpoint:Be.pendingCheckpoint}),Ms.get(e)||null}});if(n.recovered)return void process.stderr.write(`\n ◆ saved session expired — started fresh with transcript recap (${n.delivery}).\n`)}const s="hermes"===t&&("result"===r.kind||"error"===r.kind)&&(Be.session?.queuedDepth||0)>0;s&&(r.continuesQueued=!0);const i=!s&&"result"===r.kind,c=i?Nr(Be):Us(Be),l=Sn(r,{turnActive:!0===Be.session?.turnActive});zs(Be,r),bo(r),i&&(Be._settledTurnRev=Number(r.turnRev)||Number(Be._turnRev)||null,Be._turnSettledAt=Number(r.ts)||Date.now());const d="stalled"===r.kind?!Be.stalled:!!Be.stalled;Be.stalled="stalled"===r.kind,Be.lastEvent=r,"stalled"!==r.kind&&(Be.lastActionAt=r.ts),(c||d)&&wi();{const e=!0===le(Be.runtime)?.canSteer&&(Be.session?.canSteer??!1);e!==Be._canSteerAnn&&(Be._canSteerAnn=e,wi())}{const e="hermes"!==Be.runtime&&(!Be.provider||"anthropic"===Be.provider),t="hermes"===Be.runtime||e?r.model||r.ctx?.model:null;t&&t!==Be.model&&(Be.model=t,wi(),"model-switch"===r.kind&&rt()),"hermes"===Be.runtime&&"models"===r.kind&&Array.isArray(r.models)&&r.models.length?(Be.models=bn(r.models),Dn=Be.models,wi()):e&&"models"===r.kind&&Array.isArray(r.models)&&r.models.length&&(fi=r.models,wi())}if("model-switch"===r.kind){const t=Be.pendingModelSwitch;Be.pendingModelSwitch=null;const o=r.requested||t?.model||"requested model",n={kind:"control",text:"success"===r.status?`switched model → ${r.model||o}`:`couldn’t switch to ${o} — still using ${Be.model||"the previous model"}`,by:t?.by||null,cid:t?.cid||void 0};va(Be,n),ci("code-event",{term:e,evt:n}),Be.flush?.(),wi()}if("usage"===r.kind&&(Be.lastUsage=r,rt()),"effort"===r.kind&&(Be.effort=r.level??r.effort??null,rt(),wi()),Be.flowSessionId&&Be.flowTaskKey&&"result"===r.kind&&r.usage){const e=mr.get(Be.flowSessionId);e&&mr.set(Be.flowSessionId,rr(e,r.usage.output_tokens||0))}var u;if("result"===r.kind&&r.usage&&(u=r.usage.output_tokens||0,!xs&&Kn&&Gn&&u&&_s("record_spend",{p_room:Gn,p_tokens:u}).catch(()=>{}),function(e,t,r){if(!Kn||!Gn||!e)return;const o=t||{},n=(o.input_tokens||0)+(o.cache_creation_input_tokens||0)+(o.cache_read_input_tokens||0),s=o.output_tokens||0,i=o.cache_read_input_tokens||0;(n||s)&&yn(e).then(t=>_s("record_code_usage",{p_room:Gn,p_model:e,p_input:n,p_output:s,p_cached:i,p_provider:r||"unknown",p_input_usd_per_mtok:t?.input??null,p_output_usd_per_mtok:t?.output??null,p_cached_input_usd_per_mtok:t?.cached??null,p_rate_source:t?.source??null})).catch(()=>{})}(r.model,r.usage,Be.provider)),Be.flowSessionId&&Be.flowTaskKey&&!Be.flowDone&&Ge({runtime:Be.runtime,flowRole:Be.flowRole,eventKind:r.kind,eventSubtype:r.subtype})&&Promise.resolve().then(()=>We()).catch(()=>{}),"system"===r.kind&&Be.pendingAutoResume&&zr(Be)&&process.stderr.write(`\n ◆ auto-resumed interrupted turn (${e.slice(0,8)}) — sent continue.\n`),"system"===r.kind&&Be.pendingRecap){const t=Be.pendingRecap.length;Lr(Be)&&process.stderr.write(`\n ◆ carried ${t}c context recap into fresh session (${e.slice(0,8)}) after provider/restore switch.\n`)}"system"===r.kind&&Be.warming&&(e=>{if(e&&e.warming){e.warming=!1,e.warmed=!0,Vs=Math.max(0,Vs-1);try{clearTimeout(e.warmTimer)}catch{}Xs()}})(Be),"compaction"===r.kind&&(ka(Be),Be.compacting?(r.by=Be.compactBy||null,Be.compacting=!1,Be.compactBy=null,ci("code-event",{term:e,evt:{kind:"compact",status:"done",ts:Date.now()}})):"auto"===r.trigger&&(ci("code-event",{term:e,evt:{kind:"compact",status:"start",ts:Date.now()}}),setTimeout(()=>{ci("code-event",{term:e,evt:{kind:"compact",status:"done",ts:Date.now()}})},2500)));const m="mode"===r.kind||"usage"===r.kind||"effort"===r.kind||"clear"===r.kind||"compact"===r.kind||"stalled"===r.kind||"suggestion"===r.kind||"assistant_stream"===r.kind||"model-switch"===r.kind;if(("result"===r.kind||"error"===r.kind)&&Be.compacting){const t=Be.compactBy||null;Be.compacting=!1,Be.compactBy=null,ci("code-event",{term:e,evt:{kind:"compact",status:"done",ts:Date.now()}});const o={kind:"control",text:("error"===r.kind?"compaction failed":"aborted"===r.subtype?"compaction canceled":"nothing to compact")+" — context unchanged",by:t};va(Be,o),ci("code-event",{term:e,evt:o})}if(("result"===r.kind||"error"===r.kind)&&"codex"===Be.runtime&&Be.pendingCodexCompaction){const e=Be.pendingCodexCompaction;Be.pendingCodexCompaction=null,ba(Be,e)}if("result"===r.kind||"error"===r.kind){i&&Be.workerCompletionsInFlight?.length&&(Be.pendingWorkerCompletions=hn(Be.pendingWorkerCompletions,Be.workerCompletionsInFlight),Be.workerCompletionsInFlight=[],Be.flush?.());const t=Fi.get(e);if(t?"result"!==r.kind||r.subtype&&"success"!==r.subtype?Yi(e,"failed",{message:"The producing lane did not complete the edit."}):(t.resultOk=!0,Gi({previewId:t.record.previewId,requestId:t.request.cid,state:"verifying",message:"Waiting for correlated desktop and mobile renders…"}),t.timer=setTimeout(()=>Yi(e,"failed",{message:"The edit finished without a correlated desktop and mobile render."}),12e4),t.timer.unref?.(),Vi(e)):(Mi.get(e)||[]).length&&queueMicrotask(()=>Qi(e)),Be.sideHandback){const t=Be.sideHandback;Be.sideHandback=null;const o=Ms.get(t.parentId),n="result"!==r.kind||r.subtype&&"success"!==r.subtype?"":String(r.resultText||"").trim()||dn(Be.log,t.afterSeq);if(o&&n){const r=mn({sideId:e,sideName:di[e],task:Be.sideTask,summary:n});o.pendingSideContexts=ln(o.pendingSideContexts,r);const s={kind:"side-handback",sideId:e,sideName:di[e]||"Side lane",task:Be.sideTask||"",text:n,by:t.by};bo(s),va(o,s),ci("code-event",{term:t.parentId,evt:s});const i={kind:"control",text:"Brought to main.",by:t.by};bo(i),va(Be,i),ci("code-event",{term:e,evt:i}),o.flush?.(),Ws(o)}else{const r={kind:"control",text:o?"Couldn’t prepare a handoff — try again.":"The main terminal is no longer available.",by:t.by};bo(r),va(Be,r),ci("code-event",{term:e,evt:r})}Be.flush?.(),wi()}const o=Be._turnStart;Be._turnStart=null;const n=[...Be.pending.keys()];_a(Be);for(const t of n)ci("code-perm",{term:e,id:t,decision:"deny",name:"agent"});if(i&&Be.spawnedBy&&!String(Be.spawnedBy).startsWith("flow:")){const t=Ms.get(Be.spawnedBy),o=Number(r.turnRev)||Number(Be._turnRev)||0;if(t&&o>0&&Be._ownerNotifiedTurnRev!==o){const n=vn({workerId:e,workerName:di[e],turnRev:o,subtype:r.subtype});n&&(Be._ownerNotifiedTurnRev=o,t.pendingWorkerCompletions=fn(t.pendingWorkerCompletions,n),t.flush?.(),Hs(t))}}Ws(Be),Hs(Be);const s=Date.now();k({entry:Be,subtype:r.subtype,startedAt:o,now:s})&&Ns({kind:"turn-done",term:e,termName:di[e]||null,model:Be.model||null,summary:$("result"===r.kind?r.resultText:r.message),subtype:r.subtype||("error"===r.kind?"error":null),pushEligible:y({entry:Be,subtype:r.subtype,startedAt:o,now:s,minTurnMs:Ps})})}const p=xo(r);!function(e,t,r,o,n){e.imageQueue||=new _o({maxPending:En.maxPending,maxBytes:En.maxBytes,upload:(e,r,o)=>async function(e,t,r,o){return Po({webBase:On,room:Gn,authToken:Kn,term:e,cid:t,image:r,timeoutMs:En.uploadTimeoutMs,activeUploads:o})}(t,e.cid,r,o),onUploadError:e=>process.stderr.write(`\n ◇ screenshot upload failed (${e?.message||e}).\n`),onOverload:({maxPending:e,maxBytes:t})=>process.stderr.write(`\n ◇ screenshot omitted (image queue cap: ${e} pending / ${t} encoded bytes).\n`)}),e.imageQueue.enqueue(r,o,n)}(Be,e,r,p,t=>{if(!n&&(m||va(Be,t),ci("code-event",{term:e,evt:t}),fa(t),m||rt(),l&&queueMicrotask(()=>{Zi.flush(e).catch(()=>{})}),i&&Be.scheduleRunId&&("result"===t.kind||"error"===t.kind))){const e=Be.scheduleTimedOut?{...t,subtype:"runtime_limit"}:t;zi(Be,e,{canceled:!Be.scheduleTimedOut&&"aborted"===t.subtype})}})},requestPermission:bt}),"codex"===t&&Be.session?.usageSnapshot?.context){const{used:e,max:t}=Be.session.usageSnapshot.context;Be.lastUsage={kind:"usage",ctx:{used:e,max:t,pct:Math.min(100,Math.max(0,Math.round(e/t*100))),over:e>t,model:Be.model}}}return Be.log.length||Be.flush(),Hs(Be),wi(),Be.log.length||process.stderr.write(`\n ◆ structured ${le(t)?.label||"agent"} session (${e.slice(0,8)}) — driven from the room.\n`),Be}function Ia(e,t={}){const r=t.decision||"deny";return"dispatch"===e?.payload?.answerFormat?{decision:r,dispatchFingerprint:t.dispatchFingerprint||null,controlItemId:t.controlItemId||null}:"ask"===e?.payload?.risk||"codex"===e?.payload?.answerFormat||"hermes"===e?.payload?.answerFormat?{decision:r,answers:t.answers||{},responder:t.responder||null}:r}function Sa(e,t=null,r="permission_aborted",o=!1){const n=t||[...e?.pending?.entries?.()||[]].map(([e])=>e);n.length&&e?.id&&(o?w:v)({supabaseUrl:Nn,anonKey:jn,token:Kn,roomCode:Gn,bridgeId:ms,terminalId:e.id,permissionIds:n,reason:r}).then(e=>{!e.ok&&process.env.TP_DEBUG&&process.stderr.write(`\n ◇ durable permission cleanup incomplete (${e.code})\n`)})}let Ca=!1;async function xa(){Ca=!0;const e=await v({supabaseUrl:Nn,anonKey:jn,token:Kn,roomCode:Gn,currentBridgeId:ms,reason:"bridge_restarted"});return e.ok?Ca=!1:process.env.TP_DEBUG&&process.stderr.write(`\n ◇ restored permission cleanup incomplete (${e.code})\n`),e}function _a(e){if(e?.pending){Yr(e),Sa(e,null,"permission_aborted");for(const[,t]of e.pending){t?.timer&&clearTimeout(t.timer);try{t.resolve(Ia(t,{decision:"deny"}))}catch{}}e.pending.clear(),e.permNotifier?.clearAll()}}function Aa(e){if(e?.pending)for(const[t,r]of e.pending)if("plan"!==r?.payload?.risk&&"ask"!==r?.payload?.risk&&"dispatch"!==r?.payload?.answerFormat){r?.timer&&clearTimeout(r.timer);try{r.resolve("allow")}catch{}e.pending.delete(t),e.permNotifier?.resolve(t)}}const Pa=new Set(["Write","Edit","MultiEdit","NotebookEdit"]);function Na(e){if(e?.pending)for(const[t,r]of e.pending){const o=r?.payload?.toolName,n=r?.payload?.risk;if("plan"!==n&&"ask"!==n&&"high"!==n&&Pa.has(o)){r?.timer&&clearTimeout(r.timer);try{r.resolve("allow")}catch{}e.pending.delete(t),e.permNotifier?.resolve(t)}}}function Oa(e){if(!e)return;const r=Ms.get(e);if(r){zi(r,{subtype:"canceled"},{canceled:!0}),Bi(r),r.imageQueue?.close(),Zi.clear(e),_a(r);try{r.session?.end()}catch{}try{r.mockupWatcher?.close()}catch{}try{r.viewport?.stop()?.catch(()=>{})}catch{}const o=Fi.get(e);o?.timer&&clearTimeout(o.timer),Fi.delete(e),Mi.delete(e);for(const[t,r]of Ki)r.term===e&&Ki.delete(t);for(const[t,r]of Ui)r.priorRecord?.term===e&&Ui.delete(t);try{t.rmSync(ta("sessions",e),{recursive:!0,force:!0})}catch{}Ms.delete(e),xi(e),ci("term-exit",{id:e}),function(e){h({id:e,token:Kn,supabaseUrl:Nn,anonKey:jn,shuttingDown:Gs,onFailure:({error:t,status:r})=>process.stderr.write(`\n ⚠ terminal row reap failed (${String(e).slice(0,8)}${r?`, HTTP ${r}`:""}): ${t||"unknown error"}\n`)})}(e),function(e){if(e)try{const t={"Content-Type":"application/json"};Kn&&(t.Authorization=`Bearer ${Kn}`),fetch(`${On}/api/code-image-cleanup`,{method:"POST",headers:t,body:JSON.stringify({code:Gn,term:e})}).catch(()=>{})}catch{}}(e);try{$e({terminalId:e,managedWorktree:r.managedWorktree})}catch{}for(const[t,r]of[...Ms])r.spawnedBy!==e&&r.sideParent!==e||Oa(t)}eo(Gn,e),r&&wi()}function Ea(e,t=4e3){if(!e)return;const r=`flow:${e}`;mr.delete(e),setTimeout(()=>{for(const[t,o]of[...Ms])if(o.flowSessionId===e||o.spawnedBy===r)try{Oa(t)}catch{}},t)}function Da(e){if(e&&ti!==e){ti=e;for(const t of Ms.keys())ci("code-event",{term:t,evt:{kind:"update-available",version:e}});wi()}}const ja=()=>{if(Qr(Ms))return!1;for(const e of Ks.values())if(e.buf)return!1;return!0};async function qa(){if(!ri||!ti||oi)return!1;if(process.send&&"1"===process.env.THINKPOOL_PAIR_ACCOUNT_CHILD)return!1;if(!ja())return!1;oi=!0;try{const e=await import("./service.mjs");if(!e.serviceActive(Gn))return!1;const t=!1!==e.updateService(Gn);return t||(oi=!1),t}catch(e){return oi=!1,process.stderr.write(`\n ⚠ bridge update failed: ${e?.message||e}\n`),!1}}setInterval(()=>{ri&&qa()},5e3).unref();const Ka=()=>{try{process.stdin.isTTY&&process.stdin.setRawMode(!1)}catch{}};as&&process.stdin.isTTY&&process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.on("data",e=>{const t=Js&&Ks.get(Js);if(t)try{t.term.write(e.toString("utf8"))}catch{}else e.includes(3)&&Ya()}),process.stdout.on("resize",()=>{const e=Js&&Ks.get(Js);if(!e)return;const{cols:t,rows:r}=sa();if(e.term.cols!==t||e.term.rows!==r)try{e.term.resize(t,r),wi()}catch{}});let Ma=!1,Fa=Date.now();async function Ua(e){try{return await lr({payload:e,bridgeName:us,lanes:[...Ms.entries()],prepareLane:(e,t)=>nr({lane:{cwd:e.cwd,session:e.session,commitSha:e.commitSha,revertTarget:t.commitSha??e.commitSha??e.revertTarget??null},sanitize:ir}),rememberRedispatch:(e,t,r)=>{dr.set(sr(r.flowId,r.taskKey),{resumeSessionId:e.resumeSessionId,revertTarget:e.revertTarget}),e.healed&&process.stderr.write(`\n ${ca}◆ flow re-dispatch heal — ${r.taskKey}: ${e.healed} dangling tool block(s) healed before resume.${la}\n`)},endLane:e=>{try{Oa(e)}catch{}},stopPreview:At,wait:()=>new Promise(e=>setTimeout(e,400)),revert:e=>Ot({flowId:e.flowId,taskKey:e.taskKey}),broadcastReverted:e=>{ci("flow-reverted",{term:"flow",flowId:e.flowId,taskKey:e.taskKey,reviewTaskKey:e.reviewTaskKey,branch:e.branch},Ds),process.stderr.write(`\n ${ma}◆ flow slice reverted — ${e.taskKey} (${e.branch}).${la}\n`)},onPrepError:(e,t,r)=>process.stderr.write(`\n ${ma}◆ flow re-dispatch prep failed (${r.taskKey}): ${e?.message||e} — will re-dispatch fresh.${la}\n`)})}catch(e){return process.stderr.write(`\n ${ma}◆ flow revert failed: ${e?.message||e}${la}\n`),{ok:!1,error:e?.message||String(e)}}}qs.on("broadcast",{event:"apply-update"},()=>{if(ti&&(ri=!0,process.send&&"1"===process.env.THINKPOOL_PAIR_ACCOUNT_CHILD))try{process.send({t:"apply-update"})}catch{}}).on("broadcast",{event:"bridge-update"},async({payload:e})=>{const t=e?.nonce,r=(e,r,o)=>qs.send({type:"broadcast",event:"bridge-update-res",payload:{nonce:t,ok:e,...r?{error:r}:{},...o?{state:o}:{}}});if(!t)return r(!1,"invalid request");const o="string"==typeof e?.v&&/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(e.v)?e.v:null;if(!o)return r(!1,"invalid bridge version");if(Da(o),ri=!0,process.send&&"1"===process.env.THINKPOOL_PAIR_ACCOUNT_CHILD){try{process.send({t:"apply-update"})}catch{return r(!1,"account supervisor is unavailable")}return r(!0,null,"queued")}let n=!1;try{n=(await import("./service.mjs")).serviceActive(Gn)}catch{}return n?ja()?(await r(!0,null,"applying"),void qa()):r(!0,null,"queued"):(ri=!1,r(!1,"This bridge is running in a terminal. Restart it once with npx thinkpool-pair@latest, or install the background service to enable remote updates."))}).on("broadcast",{event:"providers-list-req"},({payload:e})=>{qs.send({type:"broadcast",event:"providers-list-res",payload:{nonce:e?.nonce,ok:!0,providers:N()}})}).on("broadcast",{event:"provider-switch"},({payload:e})=>{const t=e?.nonce,r=(e,r,o)=>qs.send({type:"broadcast",event:"provider-switch-res",payload:{nonce:t,ok:e,...r?{error:r}:{},...void 0===o?{}:{restarted:o}}}),o=e?.term,n=o?Ms.get(o):null;if(!n)return r(!1,"no such live lane");const s=K({provider:e?.provider,currentProvider:n.provider,registeredIds:N().map(e=>e.id)});if(!s.ok)return r(!1,s.error);const i=e?.provider===F?null:e?.provider,a=M({provider:e?.provider,currentProvider:n.provider,sameEnv:E(n.provider,i),targetModel:D(i)});if("noop"===a.action)return r(!0,void 0,!1);if("in-place"===a.action&&function(e,t){const r=Ms.get(e);if(!r?.session)return!1;const o=D(t);if(!o)return!1;r.provider=t||null,r.model=o;try{r.session.setModel(o)}catch{return!1}try{r.flush?.()}catch{}return!0}(o,i))return process.stderr.write(`\n ◆ lane ${String(o).slice(0,8)} switched model → ${D(i)} (same key, context kept).\n`),wi(),r(!0,void 0,!1);const c=function(e,t){const r=Ms.get(e);if(!r)return!1;r.imageQueue?.close();const{runtime:o,log:n,commands:s,mode:i,spawnedBy:a,spawnDepth:c,cascadeRole:l,hop:d,sideParent:u,sideTask:m,pendingSideContexts:p,pendingWorkerCompletions:h,workerCompletionsInFlight:f,sliceType:w,flowSessionId:v,flowTaskKey:g,flowTaskContract:y,flowRole:k,flowReviewTarget:b,flowReviewTargets:$,flowReviewSnapshots:T,flowReviewRound:R,flowReviewConclusion:I,dispatchBaseSha:S,revertTarget:C,cwd:x,managedWorktree:_,rolePrompt:A,reviewSliceRoots:P,openedAt:N,lastUsage:O,mcpFlight:E,pendingCheckpoint:D}=r,j=v?null:jo(n,Ko);_a(r);try{r.session?.end()}catch{}try{r.mockupWatcher?.close()}catch{}try{r.viewport?.stop()?.catch(()=>{})}catch{}return Ms.delete(e),Ra({id:e,runtime:o,provider:t,log:n,commands:s,mode:i,spawnedBy:a,spawnDepth:c,cascadeRole:l,hop:d,sideParent:u,sideTask:m,pendingSideContexts:p,pendingWorkerCompletions:h,workerCompletionsInFlight:f,sliceType:w,flowSessionId:v,flowTaskKey:g,flowTaskContract:y,flowRole:k,flowReviewTarget:b,flowReviewTargets:$,flowReviewSnapshots:T,flowReviewRound:R,flowReviewConclusion:I,dispatchBaseSha:S,revertTarget:C,cwd:x,managedWorktree:_,rolePrompt:A,reviewSliceRoots:P,openedAt:N,lastUsage:O,mcpFlight:E,carryRecap:j,carryCheckpoint:D}),!0}(o,i);if(!c)return r(!1,"no such live lane");process.stderr.write(`\n ◆ lane ${String(o).slice(0,8)} switched provider → ${i||"anthropic"} (memory reset, transcript kept).\n`),r(!0,void 0,!0)}).subscribe(e=>{"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e&&"CLOSED"!==e||process.stderr.write(`\n ⚠ private bridge control ${e} (tpcontrol:${Gn}).\n`)}),Es.on("broadcast",{event:"pty-in"},({payload:e})=>{if(!e?.data)return;ei();const t=Ks.get(e.term)||(null==e.term&&Js?Ks.get(Js):null);if(t)try{t.term.write(e.data)}catch{}}).on("broadcast",{event:"resize"},({payload:e})=>{if(!e?.cols||!e?.rows)return;const t=Ks.get(e.term);if(t&&!t.attached)try{t.term.resize(Math.max(e.cols,80),Math.max(e.rows,20)),wi()}catch{}}).on("broadcast",{event:"session-deleted"},async()=>{if(process.stderr.write("\n ◆ this room was deleted — closing the bridge.\n"),"1"===process.env.THINKPOOL_PAIR_AUTOUPDATE)try{(await import("./service.mjs")).uninstallService(Gn)}catch{}Ya()}).on("broadcast",{event:"term-open"},async({payload:e})=>{if(!e?.id||!e?.cmd)return;if(e.host&&e.host!==us)return;if(Ks.has(e.id))return void mi(e.id,"pty",Ks.get(e.id));let t=[];if(e.resume){const r=Fn.find(t=>t.cmd===e.cmd);if(r?.resume)try{r.resume.probe()&&(t=[...r.resume.args])}catch{}}if(es(e.cmd)){const t=Ms.get(e.id);if(t)return void mi(e.id,"structured",t);let r=Zn(e.cmd),o=null,n=null;if(e.sideParent){const t=Ms.get(e.sideParent);if(o=t?.sideParent||e.sideParent,n=Ms.get(o),!n||!String(e.sideTask||"").trim())return void ci("side-open-failed",{id:e.id,parent:o,message:n?"Add a task after /side.":"The main terminal is not live."});r=n.runtime||r,e.name&&(di[e.id]=String(e.name).slice(0,80),ao(Gn,di))}const s=await Ci(e.id);if(!s.ok){const t=s.reason||"This bridge machine cannot accept another live lane yet.";return o&&ci("side-open-failed",{id:e.id,parent:o,message:t}),void ci("term-exit",{id:e.id,reason:t})}if(Ra({id:e.id,runtime:r,mode:n?.mode||e.mode,model:n?.model||e.model||void 0,provider:"claude"===r&&(n?.provider||e.provider)||void 0,cwd:n?n.cwd||process.cwd():void 0,sideParent:o||void 0,sideTask:o?String(e.sideTask).trim():void 0,rolePrompt:o?cn:void 0,defer:!0}),o){const t=Ms.get(e.id),r=String(e.sideTask).trim(),s=Array.isArray(e.files)?e.files:[],i=String(e.by||"A room member"),a=di[e.id]||"Side lane";if(!t)return xi(e.id),void ci("side-open-failed",{id:e.id,parent:o,message:"The side lane could not start."});t.hop=0;const c={kind:"you",text:r,by:i,...s.length?{files:s}:{}},l={kind:"side-started",sideId:e.id,sideName:a,task:r,by:i};va(n,l),ci("code-event",{term:o,evt:l});const d=pn(n.log.filter(e=>e.cid!==l.cid)),u=s.map(e=>ye(e,{updir:Ts})).filter(Boolean),m=u.length?`${r}\n\n${u.map(e=>`"${e}"`).join(" ")}`:r,p=d?`${d}\n\n--- side task ---\n${m}`:m,h="codex"===t.runtime||"hermes"===t.runtime?await ke(s,{updir:Ts}):[];return Ls(t,p,{options:h.length?{images:h}:void 0,visibleEvent:c,rejectionMessage:"The side-lane task was not accepted; retry after the lane is available."}).accepted?(t.flush?.(),n.flush?.(),wi(),mi(e.id,"structured",t),void process.stderr.write(`\n ◆ ${i} opened side lane ${String(e.id).slice(0,8)} under ${String(o).slice(0,8)}.\n`)):(ci("side-open-failed",{id:e.id,parent:o,message:"The side agent could not start."}),void Oa(e.id))}const i=Ms.get(e.id);return i?mi(e.id,"structured",i):xi(e.id),void process.stderr.write(`\n ◆ web opened a structured "${e.cmd}" session (${e.mode||"default"}${e.model?`, model ${e.model}`:""}).\n`)}const r=await Ci(e.id);r.ok?(ia({id:e.id,cmd:e.cmd,args:t}),Ks.has(e.id)?mi(e.id,"pty",Ks.get(e.id)):xi(e.id),process.stderr.write(`\n ◆ web opened a "${e.cmd}"${t.length?" (continue)":""} terminal (headless).\n`)):ci("term-exit",{id:e.id,reason:r.reason||"This bridge machine cannot accept another live lane yet."})}).on("broadcast",{event:"term-close"},({payload:e})=>{const t=e?.id&&Ks.get(e.id);if(t&&!t.attached)try{t.term.kill()}catch{}else t||Oa(e?.id)}).on("broadcast",{event:"replay-request"},({payload:e})=>{Ei();const t=e?.to??null,r=String(e?.requestId||c?.()||`${Date.now()}`),o=[];for(const[n,s]of Bo(Ks,e?.terms,e?.priority)){if(!s.scrollback)continue;const e=s.scrollback.length>1e5?s.scrollback.slice(-1e5):s.scrollback;o.push({event:"pty-replay",payload:{to:t,term:n,requestId:r,b64:Buffer.from(e,"utf8").toString("base64")}})}const n=Bo(Ms,e?.terms,e?.priority);for(const[s,i]of n){if(!i.log.length){o.push({event:"code-replay",payload:{to:t,term:s,requestId:r,chunkIndex:0,chunkCount:1,events:[],empty:!0}});continue}const n=Number(e?.cursors?.[s])||0,a=To(i.log),c=n>a,l=(n>0&&!c?i.log.filter(e=>null==e.seq||e.seq>n):i.log).map(e=>Co(e)),d=So(l),u=c?0:n,m=Mo(Fo(d[0]||[]),u,i.archiveOldestSeq);for(let e=0;e<d.length;e++){const n=d[e];o.push({event:"code-replay",payload:{to:t,term:s,requestId:r,chunkIndex:e,chunkCount:d.length,events:n,...c?{reset:!0}:{},...0===e&&null!=m?{trimmedBefore:m}:{},...0===e&&i.lastUsage?.ctx?{lastUsage:i.lastUsage}:{}}})}}li.enqueue(t||"*",o,async()=>{for(const[,e]of Ms)for(const[,t]of e.pending)await ii("code-perm-req",t.payload);wi()})}).on("broadcast",{event:"history-page-request"},({payload:e})=>{const t=e?.term;if(!t)return;if(!ho({payloadHost:e?.host,bridgeName:us,hasSession:Ms.has(t),hasArchive:po(Gn,t)}))return;const{events:r,hasMore:o}=uo(Gn,t,Number(e?.beforeSeq)||null,200),n=e?.to??null,s=String(e?.requestId||c?.()||`${Date.now()}`);if(!r.length)return void ci("history-page",{to:n,term:t,requestId:s,chunkIndex:0,chunkCount:1,events:[],hasMore:!1});const i=So(r.map(e=>Co(e)));i.forEach((e,r)=>ci("history-page",{to:n,term:t,requestId:s,chunkIndex:r,chunkCount:i.length,events:e,hasMore:0!==r||o}))}).on("broadcast",{event:"file-put"},({payload:e})=>{e?.id&&e?.url&&(e.host&&e.host!==us||(async()=>{try{const o=ye(e,{updir:Ts});if(!o)throw new Error("invalid attachment metadata");const n=await(async e=>{const t=Kn&&(e=>{const t=String(e||""),r=`code/${Gn}/`;return!t.startsWith(r)||t.includes("..")||t.split("/").some(e=>!e)?null:`${Nn}/storage/v1/object/authenticated/session-attachments/${t.split("/").map(encodeURIComponent).join("/")}`})(e?.path),r=[{url:e?.url,headers:void 0},...t?[{url:t,headers:{apikey:jn,Authorization:`Bearer ${Kn}`}}]:[]].filter(e=>e.url);let o=new Error("no attachment source");for(let e=0;e<3;e++){for(const e of r)try{const t=await fetch(e.url,{headers:e.headers});if(!t.ok)throw new Error(`HTTP ${t.status}`);return Buffer.from(await t.arrayBuffer())}catch(e){o=e}e<2&&await new Promise(t=>setTimeout(t,250*(e+1)))}throw o})(e);if(n.length>26214400)throw new Error("file too large");t.mkdirSync(Ts,{recursive:!0}),t.writeFileSync(o,n),process.stderr.write(`\n ◆ file from the room: ${o}\n`),ci("file-done",{id:e.id,path:o.split(r.sep).join("/"),host:us})}catch(t){process.stderr.write(`\n ◇ room file download failed (${o=e.name,String(o||"file").replace(/[^a-zA-Z0-9._-]/g,"_").slice(-80)||e.id}): ${t.message}\n`)}var o})())}).on("broadcast",{event:"code-open"},async({payload:e})=>{if(e?.host&&e.host!==us)return;const t=e?.id||c();if(Ms.has(t))return;const r=await Ci(t);r.ok?(Ra({id:t,runtime:e?.runtime,model:e?.model,provider:"claude"===e?.runtime?e?.provider:void 0,resume:e?.resume,mode:e?.mode,defer:!0}),Ms.has(t)||xi(t)):ci("term-exit",{id:t,reason:r.reason||"This bridge machine cannot accept another live lane yet."})}).on("broadcast",{event:"side-handback-request"},({payload:e})=>{const t=e?.term&&Ms.get(e.term);if(!t?.sideParent||t.sideParent!==e?.parent)return;const r=String(e?.by||"A room member");if(t.sideHandback||t.session?.turnActive){const o={kind:"control",text:"Finish or stop the current side-lane turn before bringing it to main.",by:r};return bo(o),va(t,o),void ci("code-event",{term:e.term,evt:o})}t.sideHandback={parentId:t.sideParent,by:r,afterSeq:To(t.log)};const o={kind:"control",text:"Preparing a compact handoff for main…",by:r};if(bo(o),va(t,o),ci("code-event",{term:e.term,evt:o}),t.flush?.(),wi(),!Ls(t,an,{rejectionMessage:"The side-lane handoff was not accepted; retry after the lane is available."}).accepted){t.sideHandback=null;const o={kind:"control",text:"Couldn’t start the handoff — try again.",by:r};bo(o),va(t,o),ci("code-event",{term:e.term,evt:o}),t.flush?.(),wi()}}).on("broadcast",{event:"code-turn"},async({payload:e})=>{const t=e?.term&&Ms.get(e.term);if(!t||null==e.text)return;if(await Oe(t),Ms.get(e.term)!==t||!t.session)return;const r=e.cid&&String(e.cid);if(r){t.receivedTurnCids||(t.receivedTurnCids=new Set);const o=t.receivedTurnCids.has(r)||t.log?.some(e=>e?.cid===r&&("you"===e.kind||"control"===e.kind));if(!o){if(t.receivedTurnCids.add(r),t.receivedTurnCids.size>1e3){const e=t.receivedTurnCids.values().next().value;t.receivedTurnCids.delete(e)}t.flush?.()}if(ci("code-turn-ack",{term:e.term,cid:r,duplicate:o}),o)return}ei(),t.peekCount=0,t.peekRosterCount=0,t.postCount=0,t.pairPeekCount=0,t.crossRoomPostCount=0,t.spawnTimes=[],t.hop=0,t.roomHop=0;const o=String(e.text),n=function(e){const t=Yr(e);if(!t)return null;const r=e.pending?.get(t.permissionId);Sa(e,[t.permissionId],"dispatch_superseded",!0),r?.timer&&clearTimeout(r.timer),e.pending?.delete(t.permissionId),e.permNotifier?.resolve(t.permissionId);try{r?.resolve(Ia(r,{decision:"deny"}))}catch{}return t.permissionId}(t);n&&wi(),Gr(t);const s=(r,o={})=>{const n={kind:"control",text:r,by:e.by,cid:e.cid,...o};va(t,n),ci("code-event",{term:e.term,evt:n})};if(/^\/help\s*$/.test(o)&&"hermes"!==t.runtime)return void s(`Available commands · ${me(t.commands)}`);if(/^\/status\s*$/.test(o)&&"hermes"!==t.runtime){const e=le(t.runtime)?.label||t.runtime,r=t.session?.turnActive?"working":"idle";return void s(`${e} · ${r} · model ${t.model||"default"} · ${t.mode||"default"} permissions · effort ${t.effort||"default"}`)}if(/^\/context\s*$/.test(o)&&"hermes"!==t.runtime){const e=t.lastUsage?.ctx;return void s(e?.max?`Context · ${Number(e.used||0).toLocaleString("en-US")} / ${Number(e.max).toLocaleString("en-US")} tokens (${e.pct??Math.round(Number(e.used||0)/Number(e.max)*100)}%)`:"Context usage unavailable until the runtime reports a completed turn")}if(/^\/diff\s*$/.test(o)){try{const e=t.cwd||process.cwd();s(he({cwd:e}))}catch{s("Working-tree diff unavailable outside a readable Git checkout")}return}const i=o.match(/^\/find(?:\s+([\s\S]+))?$/i);if(i){const r={kind:"repo-search",...fe({cwd:t.cwd||process.cwd(),query:i[1]||""}),by:e.by,cid:e.cid};return va(t,r),void ci("code-event",{term:e.term,evt:r})}if(/^\/credits\s*$/.test(o)&&"hermes"!==t.runtime)return"codex"!==t.runtime||"function"!=typeof t.session?.accountUsage?void s("Credit balance is unavailable for this runtime; use /usage for provider limits"):void Promise.resolve(t.session.accountUsage()).then(e=>{s(Y(e?.limits))}).catch(()=>s("Codex credits unavailable for this account"));const a=o.match(/^\/model\b\s*(\S+)?/);if(a){if(a[1]){if("hermes"===t.runtime&&t.pendingModelSwitch)return void s("finish the current Hermes model switch before choosing another model");if(!1===t.session.setModel(a[1]))return void s(`finish or stop the current ${le(t.runtime)?.label||"agent"} turn before switching models`);if("hermes"===t.runtime)return t.pendingModelSwitch={model:a[1],by:e.by,cid:e.cid},void ci("code-event",{term:e.term,evt:{kind:"model-switch",status:"pending",requested:a[1],ts:Date.now()}});t.model=a[1],wi(),t.flush?.(),s(`switched model → ${a[1]}`)}else s("use /model <name> to switch — e.g. opus, sonnet, haiku");return}if(/^\/clear\s*$/.test(o))return t.pendingRecap=null,t.pendingCheckpoint=null,t.pendingCodexCompaction=null,"codex"===t.runtime||"hermes"===t.runtime?t.session.clearContext?.():t.session.sendTurn(o),t.log=[],t.logBytes=0,t.seq=$o(0),t.archiveOldestSeq=null,ci("code-event",{term:e.term,evt:{kind:"clear"}}),Zr(Gn,e.term,{sessionId:t.session?.sessionId||null,log:[]}),void s("context cleared. You can continue with these answers in mind.");if(/^\/compact\s*$/.test(o)){if("codex"===t.runtime){if(t.codexCompactionPromise||t.pendingCodexCompaction)return;return t.session.turnActive?(t.pendingCodexCompaction={by:e.by,cid:e.cid},void s("Compaction queued for after this turn.",{tone:"caution"})):void ba(t,{by:e.by,cid:e.cid})}return t.compacting=!0,t.compactBy=e.by,ci("code-event",{term:e.term,evt:{kind:"compact",status:"start",ts:Date.now()}}),void t.session.sendTurn(o)}if(/^\/usage\s*$/.test(o))return s("codex"===t.runtime?Oo(t.model,t.session?.usageSnapshot):No(t.model,t.log)),void("codex"===t.runtime?Promise.resolve(t.session?.accountUsage?.()).then(e=>{const t=G(e?.usage);t&&s(t),s(V(e?.limits))}).catch(()=>s("Codex provider limits unavailable")):gn().then(e=>{e&&s(e)}).catch(()=>{}));if("codex"===t.runtime&&/^\/review(?:\s|$)/.test(o)&&(t.flowSessionId||t.flowRole||"review"===t.sliceType))return void s("Native /review is unavailable in Dispatch and reviewer lanes; their immutable review contract already owns scope and authority");let c=o;const l=[];t.pendingRecap&&(l.push(t.pendingRecap),t.pendingRecap=null),t.pendingCheckpoint&&(l.push(t.pendingCheckpoint),t.pendingCheckpoint=null),t.pendingSideContexts?.length&&(l.push(...t.pendingSideContexts),t.pendingSideContexts=[]),l.length&&(c=Eo(l,o),t.flush?.());const d="codex"===t.runtime||"hermes"===t.runtime?await ke(e.files,{updir:Ts}):[],u="hermes"===t.runtime&&t.session.turnActive&&/^\s*\/queue\s+/i.test(o),m={...d.length?{images:d}:{},...u&&!e.silent?{_thinkpoolQueuedEcho:{text:null!=e.body?String(e.body):o,cid:e.cid,by:e.by,...Array.isArray(e.files)&&e.files.length?{files:e.files}:{},...Array.isArray(e.pastes)&&e.pastes.length?{pastes:e.pastes}:{}}}:{}};Us(t),yi(e.term,null!=e.body?String(e.body):o);const p=t.session.sendTurn(c,Object.keys(m).length?m:void 0);if(!1===p?Us(t):Bs(t),u&&!1!==p||(()=>{if(e.silent)return;const r={kind:"you",text:null!=e.body?String(e.body):o,cid:e.cid,by:e.by,...e.authorId?{authorId:e.authorId}:{},...e.steered?{steered:!0}:{},...Array.isArray(e.files)&&e.files.length?{files:e.files}:{},...Array.isArray(e.pastes)&&e.pastes.length?{pastes:e.pastes}:{}};va(t,r),ci("code-event",{term:e.term,evt:r})})(),!1===p){const r={kind:"error",message:`${le(t.runtime)?.label||"Agent"} did not accept this turn; retry after the lane is available.`,recoverable:!0};va(t,r),ci("code-event",{term:e.term,evt:r})}if(wi(),!1!==p&&Ne(t,{turnRev:t._turnRev,turnCid:r})&&(_a(t),Pe(t).finally(()=>wi()),wi()),e.pooled&&!e.silent){const r={kind:"pool",text:"dispatched to agent"};va(t,r),ci("code-event",{term:e.term,evt:r})}}).on("broadcast",{event:"code-perm"},({payload:e})=>{const t=e?.term&&Ms.get(e.term),r=t&&e.id&&t.pending.get(e.id);r&&Yo({supabaseUrl:Nn,anonKey:jn,token:Kn,roomCode:Gn,bridgeId:ms,payload:e}).then(o=>{o.ok&&Ms.get(e.term)?.pending.get(e.id)===r?(r.timer&&clearTimeout(r.timer),t.pending.delete(e.id),t.permNotifier?.resolve(e.id),r.resolve(Ia(r,{...e,decision:o.decision,answers:o.answers,responder:o.responder})),wi()):!o.ok&&process.env.TP_DEBUG&&process.stderr.write(`\n ◇ ignored unverified permission delivery (${o.code})\n`)})}).on("broadcast",{event:"code-abort"},({payload:e})=>{const t=e?.term&&Ms.get(e.term);if(t){const r=Ae(t,e);ci("code-abort-ack",{term:e.term,cid:e.cid,turnRev:e.turnRev,action:r.action,code:r.code,currentTurnRev:r.currentTurnRev}),"abort"===r.action&&(_a(t),Pe(t).finally(()=>wi()),wi())}}).on("broadcast",{event:"code-mode"},({payload:e})=>{const t=e?.term&&Ms.get(e.term);if(t&&Fe.has(e.mode)){if(ie(t)&&e.mode!==t.mode){const r={kind:"control",text:`This ${t.flowRole||"review"} lane is structurally locked to ${t.mode}; Dispatch and reviewer restrictions take precedence.`};return va(t,r),ci("code-event",{term:e.term,evt:r}),void wi()}if("codex"===t.runtime||"hermes"===t.runtime){if(!t.session.setMode(e.mode)){const r={kind:"control",text:`finish or stop the current ${le(t.runtime)?.label||"agent"} turn before switching permissions`};return va(t,r),ci("code-event",{term:e.term,evt:r}),void wi()}return t.mode=e.mode,"bypassPermissions"===e.mode?Aa(t):"acceptEdits"===e.mode?Na(t):"plan"===e.mode&&_a(t),t.flush?.(),void wi()}t.mode=e.mode,t.session.setMode(e.mode),"bypassPermissions"===e.mode?Aa(t):"acceptEdits"===e.mode&&Na(t),wi()}}).on("broadcast",{event:"code-effort"},({payload:e})=>{const t=e?.term&&Ms.get(e.term),r=new Set(["low","medium","high","xhigh","max"]);if(t&&r.has(e.level)){if(t.session?.turnActive){const r={kind:"control",text:"finish or stop the current turn before switching thinking power"};return va(t,r),void ci("code-event",{term:e.term,evt:r})}Promise.resolve(t.session.setEffort?.(e.level)).then(r=>{!1!==r&&(t.effort=e.level,t.flush?.(),wi())}).catch(()=>{})}}).on("broadcast",{event:"code-close"},({payload:e})=>{Oa(e?.id)}).on("broadcast",{event:"term-rename"},({payload:e})=>{e?.id&&(ui.add(e.id),hi.delete(e.id),e.name?di[e.id]=String(e.name).slice(0,80):delete di[e.id],ao(Gn,di),wi())}).on("broadcast",{event:"who"},wi).subscribe(async e=>{if("SUBSCRIBED"===e){Ma=!0,Fa=0,t={name:us,role:"bridge",bridge_id:ms,started_at:fs},(Os||=$n(Es,{minMs:5e3}))(t);const e=as||Xn,r=[];if(e&&!Ks.size&&!Ms.size)if(es(e)){const e=to(Gn),t=e=>e._bt||e.openedAt||e.savedAt||0;if(e.sort((e,r)=>t(e)-t(r)),await xa(),e.length)for(const t of e){const e=await Ci(t.id);if(!e.ok){process.stderr.write(`\n ◇ restore held for ${String(t.id).slice(0,8)} — ${e.reason||"host capacity is full"}\n`);continue}const o=ga(t.log||[]),n=Jr(t,{canResume:oo,codexThreadCanResume:J}),s=o?jo(t.log||[],Ko):"";Ra({id:t.id,runtime:t.runtime||"claude",model:t.model||void 0,models:t.models,effort:t.effort,provider:"claude"===t.runtime&&t.provider||void 0,resume:n?t.sessionId:void 0,log:t.log,commands:t.commands,mode:t.mode,spawnedBy:t.spawnedBy,spawnDepth:t.spawnDepth,cascadeRole:t.cascadeRole,hop:t.hop,sideParent:t.sideParent,sideTask:t.sideTask,scheduleRunId:t.scheduleRunId,scheduleDeadlineAt:t.scheduleDeadlineAt,scheduleOutcomeRecorded:t.scheduleOutcomeRecorded,scheduleAdmissionLease:t.scheduleAdmissionLease,pendingSideContexts:t.pendingSideContexts,pendingWorkerCompletions:t.pendingWorkerCompletions,workerCompletionsInFlight:t.workerCompletionsInFlight,sliceType:t.sliceType,flowSessionId:t.flowSessionId,flowTaskKey:t.flowTaskKey,flowTaskContract:t.flowTaskContract,flowRole:t.flowRole,flowReviewTarget:t.flowReviewTarget,flowReviewTargets:t.flowReviewTargets,flowReviewSnapshots:t.flowReviewSnapshots,flowReviewRound:t.flowReviewRound,flowReviewConclusion:t.flowReviewConclusion,dispatchBaseSha:t.dispatchBaseSha,revertTarget:t.revertTarget,cwd:t.cwd,managedWorktree:t.managedWorktree,rolePrompt:t.rolePrompt,reviewSliceRoots:t.reviewSliceRoots,openedAt:t.openedAt,lastUsage:t.lastUsage,receivedTurnCids:t.receivedTurnCids,mcpFlight:t.mcpFlight,carryRecap:o?s:t.carryRecap,carryCheckpoint:t.carryCheckpoint,defer:!t.flowSessionId&&!o});const i=Ms.get(t.id);i||xi(t.id);const a=[...t.log||[]].reverse().find(e=>"result"===e?.kind||"error"===e?.kind);i&&t.flowTaskKey&&Ge({runtime:i.runtime,flowRole:i.flowRole,eventKind:a?.kind,eventSubtype:a?.subtype,interrupted:o})&&setTimeout(()=>{try{i.markFlowDone?.()}catch{}},2e3),i&&o&&(i.pendingInterruptedRecovery={resumable:n,recap:s},r.push(i))}else if(as){const e=c();(await Ci(e)).ok&&(Ra({id:e,runtime:Zn(as)}),Ms.has(e)||xi(e))}Qs&&setTimeout(()=>{for(const[,e]of Ms)!e.deferred||e.warmed||e.warming||e.session?.started||Ys.push(e);Ys.length&&(process.stderr.write(`\n ◆ background-warming ${Ys.length} idle terminal(s) (≤3 at a time)…\n`),Xs())},6e3)}else{const t=no(Gn)||c();so(Gn,t),(await Ci(t)).ok&&(ia({id:t,cmd:e,args:cs,attached:!Xn}),Ks.has(t)||xi(t))}if(await wi(),f({room:Gn,hostId:vs,liveIds:[...Ks.keys(),...Ms.keys()],token:Kn,supabaseUrl:Nn,anonKey:jn,shuttingDown:Gs,onFailure:({error:e,status:t})=>process.stderr.write(`\n ⚠ terminal row reconcile failed${t?` (HTTP ${t})`:""}: ${e||"unknown error"}\n`)}).then(({reaped:e})=>{e.length&&process.stderr.write(`\n ◆ removed ${e.length} stale terminal row${1===e.length?"":"s"} after restore.\n`)}),process.send&&"1"===process.env.THINKPOOL_PAIR_ACCOUNT_CHILD)try{process.send({t:"room-ready",room:Gn,bridgeId:ms})}catch{}r.forEach((e,t)=>{const r=setTimeout(()=>{const t=e.pendingInterruptedRecovery;if(e.pendingInterruptedRecovery=null,!t||Ms.get(e.id)!==e)return;const r=Wr(e,t);"sent"===r?process.stderr.write(`\n ◆ auto-resumed interrupted Codex turn (${e.id.slice(0,8)}) — sent continue.\n`):"recap-sent"===r&&process.stderr.write(`\n ◆ resumed interrupted Codex turn (${e.id.slice(0,8)}) with a fresh context recap.\n`)},1e3+5e3*t);r.unref?.()}),setImmediate(()=>{for(const e of Ms.values())if(e.snapshotNeedsCompaction){e.snapshotNeedsCompaction=!1;try{e.flush?.()}catch{}}}),process.stderr.write(Qn?`\n ◆ thinkpool — relaying room ${Gn} (headless). Open terminals from the web UI.\n\n`:`\n ◆ thinkpool — sharing "${as}"${ls?" (continuing your latest session)":""} into room ${Gn}. Open the web UI and you're both in.\n\n`)}else"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e&&"CLOSED"!==e||(!Ma&&Fa||(Fa=Date.now()),Ma=!1,process.stderr.write(`\n ⚠ realtime ${e} — reconnecting…\n`));var t}),Ds.on("broadcast",{event:"flow-start"},async({payload:e})=>{if(!e?.flowId)return;if(e.host&&e.host!==us)return;for(const[,t]of Ms)if(t.flowSessionId===e.flowId)return;const t=e.originTerm?Ms.get(e.originTerm):null;if(e.originTerm&&!t)return;const r=t?et(t.runtime,null):"claude";if(!r)return;const o="codex"===r?t?.models||H():"hermes"===r&&t?.models||[],n=rt({runtime:r,originModel:t?.model,catalog:o}),s=Kr({totalLive:Ms.size+Ks.size,disabled:"1"===process.env.TP_SPAWN_OFF});if(!s.ok)return process.stderr.write(`\n ${ma}◆ flow start held — ${s.reason}${la}\n`),void ci("flow-dispatch-held",{term:"flow",flowId:e.flowId,taskKey:null,reason:s.reason},Ds);const i=xe("start the Dispatch conductor");if(!i.ok)return Si(),process.stderr.write(`\n ${ma}◆ flow start held — ${i.reason}${la}\n`),void ci("flow-host-pressure",{term:"flow",flowId:e.flowId,reason:i.reason},Ds);const a=c(),l=await Ci(a);if(!l.ok){const t=l.reason||"This bridge machine cannot accept another live lane yet.";return process.stderr.write(`\n ${ma}◆ dispatch start held — ${t}${la}\n`),void ci("flow-dispatch-held",{term:"flow",flowId:e.flowId,taskKey:null,reason:t},Ds)}di[a]=`Dispatch · ${String(e.flowId).slice(0,6)}`,ao(Gn,di),Ra({id:a,runtime:r,model:n,mode:"codex"===r?"plan":"default",rolePrompt:"claude"===r?Ue:Le,flowSessionId:e.flowId,flowRole:"conductor",spawnedBy:`flow:${e.flowId}`});const d=Ms.get(a);if(!d)return xi(a),delete di[a],void ao(Gn,di);d?.session&&Ls(d,e.prompt||"",{rejectionMessage:"The Dispatch conductor task was not accepted; retry after the lane is available."}),process.stderr.write(`\n ${ua}◆ flow conductor launched — flow ${String(e.flowId).slice(0,8)} (plan mode).${la}\n`),wi()}).on("broadcast",{event:"flow-dispatch"},async({payload:e})=>{if(!e?.flowId||!Array.isArray(e.tasks))return;if(e.host&&e.host!==us)return;const t=[...Ms.values()].find(t=>t.flowSessionId===e.flowId&&"conductor"===t.flowRole);if(!t)return void process.stderr.write(`\n ${ma}◆ flow dispatch held — this bridge has no live/restored conductor for ${String(e.flowId).slice(0,8)}.${la}\n`);const r=et(t.runtime,null);if(!r)return;const o="codex"===r?t.models||H():"hermes"===r&&t.models||[],n=[];let i=Mr(Ms.values());const a=or();if(a.disabled)return void process.stderr.write(`\n ${ma}◆ flow dispatch refused — TP_FLOW_OFF kill-switch is on.${la}\n`);const l=e.mode||"guide",d=null!=a.capFromEnv?a.capFromEnv:null!=e.budgetCap?Number(e.budgetCap):null;let u=mr.get(e.flowId)||tr({capTokens:d});u.capTokens!==d&&(u={...u,capTokens:d}),mr.set(e.flowId,u);for(const t of e.tasks){if([...Ms.values()].some(r=>r.flowSessionId===e.flowId&&r.flowTaskKey===t.task_key&&!r.flowDone)){process.stderr.write(`\n ${ca}◆ flow dispatch skip ${t.task_key} — lane already live.${la}\n`);continue}const a=sr(e.flowId,t.task_key);if(ur.has(a))process.stderr.write(`\n ${ca}◆ flow dispatch skip ${t.task_key} — admission already in flight.${la}\n`);else{ur.add(a);try{const a=er({mode:l,budget:u});if(!a.ok){process.stderr.write(`\n ${ma}◆ flow dispatch held (${a.reason}) — ${n.length} spawned this wave.${la}\n`);break}const d=qr({spawnedLive:i,totalLive:Ms.size+Ks.size,plan:Is,disabled:"1"===process.env.TP_SPAWN_OFF});if(!d.ok){process.stderr.write(`\n ${ma}◆ flow dispatch held — ${d.reason} ${n.length} spawned this wave; remaining slices stay queued.${la}\n`),ci("flow-dispatch-held",{term:"flow",flowId:e.flowId,taskKey:t.task_key||null,reason:d.reason},Ds);break}const m=xe("start another Dispatch lane");if(!m.ok){Si(),process.stderr.write(`\n ${ma}◆ flow dispatch held — ${m.reason}${la}\n`),ci("flow-host-pressure",{term:"flow",flowId:e.flowId,reason:m.reason},Ds);break}const p=c(),h=await Ci(p);if(!h.ok){const r=h.reason||"This bridge machine cannot accept another live lane yet.";process.stderr.write(`\n ${ma}◆ dispatch held — ${r}${la}\n`),ci("flow-dispatch-held",{term:"flow",flowId:e.flowId,taskKey:t.task_key||null,reason:r},Ds);break}try{const a="review"===t.slice_type;try{Xe(t,{legacy:null==t.contract})}catch(r){process.stderr.write(`\n ${ma}◆ flow dispatch held — ${t.task_key||"task"} failed its sealed acceptance contract: ${r?.message||r}${la}\n`),ci("flow-dispatch-held",{term:"flow",flowId:e.flowId,taskKey:t.task_key||null,reason:"sealed acceptance contract mismatch"},Ds),xi(p);continue}if(!Ze(t,r)){process.stderr.write(`\n ${ma}◆ flow dispatch held — ${"hermes"===r?"Hermes":"Codex"} review ${t.task_key} must target exactly one dependency.${la}\n`),xi(p);continue}const{dir:c}=mt({flowId:e.flowId,taskKey:t.task_key});let l=null;try{l=s("git",["-C",c,"rev-parse","HEAD"],{encoding:"utf8"}).trim()}catch{}di[p]=`Dispatch · ${t.task_key}`,ao(Gn,di);const d=sr(e.flowId,t.task_key),u=dr.get(d)||null;u&&dr.delete(d);const m=a?(t.deps||[]).map(t=>pt({flowId:e.flowId,taskKey:t}).dir):[],h=a?(t.deps||[]).map(r=>{const o=pt({flowId:e.flowId,taskKey:r}).dir;let n=null;try{n=s("git",["-C",o,"rev-parse","HEAD"],{encoding:"utf8",timeout:3e3,stdio:["ignore","pipe","ignore"]}).trim()}catch{}let i=null;if(n&&t.contract?.scopePaths?.length){let e=null;try{e=s("git",["-C",o,"merge-base",n,"origin/main"],{encoding:"utf8",timeout:3e3,stdio:["ignore","pipe","ignore"]}).trim()}catch{}const r=pr(o,e,n);if(r){const e=Mt({log:[],repoRoot:o,declared:t.contract.scopePaths,changed:r}),n=Ft(t.contract.scopeEvidence);i=n?{...e,read:n.read,verified:n.verified}:e}}return{taskKey:r,cwd:o,sha:n,...i?{scopeEvidence:i}:{}}}).filter(e=>e.sha):[],f=Je({base:"codex"===r||"hermes"===r?a?Nt:We:a?Pt:Be}),w=t.contract?.acceptancePack?.task?.acceptance;Ra({id:p,runtime:r,cwd:c,model:tt({sliceType:t.slice_type,runtime:r,catalog:o}),mode:se(r,{mode:"bypassPermissions",flowRole:a?"reviewer":"builder"}),rolePrompt:f,flowSessionId:e.flowId,flowTaskKey:t.task_key,flowTaskContract:t.contract||null,flowRole:a?"reviewer":"builder",flowReviewTargets:a&&t.deps||[],flowReviewSnapshots:h,dispatchBaseSha:l,revertTarget:u?.revertTarget||null,spawnedBy:`flow:${e.flowId}`,resume:u?.resumeSessionId||void 0,reviewSliceRoots:m});const v=Ms.get(p);v&&(u&&(v.revertTarget=u.revertTarget??null),a&&(v.flowReviewTarget=t.deps&&t.deps[0]||null),v.session&&!u)&&Ls(v,a?`[Dispatch REVIEW lane — slice "${t.task_key}" of run ${String(e.flowId).slice(0,8)}]\nYou are ADVERSARIALLY reviewing the slice(s): ${(t.deps||[]).join(", ")||t.title}\n`+(Array.isArray(t.deps)&&t.deps.length?"Reviewed slice worktree(s) — check out + RUN each yourself:\n"+t.deps.map(t=>{const r=pt({flowId:e.flowId,taskKey:t});return` - ${t}: dir ${r.dir} (branch ${r.branch})`}).join("\n")+"\n":"")+`ACCEPTANCE to INDEPENDENTLY verify: ${w||t.acceptance||t.title}\n`+`INHERITED NON-GOALS (must remain untouched): ${(t.contract?.nonGoals||[]).join(" | ")||"(legacy task: none recorded)"}\n`+`INHERITED BASELINE GATE: ${t.contract?.baseline?.gate||"(legacy task: none recorded)"}\n`+`BUILDER BASELINE EVIDENCE (verify; never invent another baseline): ${t.contract?.baseline?.evidence||"(missing — reject unless this is a legacy task)"}\n`+`\nProject (context): ${e.flowPrompt||""}\n\n`+("codex"===r||"hermes"===r?"Review it without mutating the builder worktree. For write-producing install/build/test commands, copy its source into scratch under your own current worktree first. Submit the structured verdict with the thinkpool submit_flow_review MCP tool; never write FLOW_REVIEW.json or call mark_flow_done.":'Review it — run it, hunt for failure. When done, use the Write tool to write FLOW_REVIEW.json with {"pass":<boolean>,"reasons":["<specific finding>"],"taskKey":"<the slice you reviewed>"}. That Write IS your verdict.'):`[Dispatch lane — slice "${t.task_key}" of run ${String(e.flowId).slice(0,8)}]\nTITLE: ${t.title}\nSCOPE (files you OWN — edit ONLY these): ${t.scope||"(none stated)"}\nACCEPTANCE (done = this runs + proves it): ${t.acceptance||"(meet the title)"}\nNON-GOALS (must remain untouched): ${(t.contract?.nonGoals||[]).join(" | ")||"(legacy task: none recorded)"}\nBASELINE GATE (before edits, observe this real failure/absence): ${t.contract?.baseline?.gate||"(legacy task: none recorded)"}\nBASELINE EVIDENCE: run/observe the pre-edit gate, then retain one real bounded command/behavior receipt for mark_flow_done; never fabricate a RED sentence.\n`+(t.deps&&t.deps.length?`DEPENDS ON (already built): ${t.deps.join(", ")}\n`:"")+(e=>e?`${e}\n`:"")(ze(e.flowId,{baseDir:process.cwd(),deps:t.deps}).text)+`\nProject (context): ${e.flowPrompt||""}\n\nBuild your slice. Own only your files. Done = it runs + meets acceptance. Commit when done.`+("codex"===r||"hermes"===r?" Then call the thinkpool mark_flow_done MCP tool; do not write FLOW_DONE.":""),{rejectionMessage:`Dispatch slice ${t.task_key} was not accepted; retry after the lane is available.`}),v?(n.push({task_key:t.task_key,laneId:p}),i++):xi(p)}catch(e){xi(p),process.stderr.write(`\n ${ma}◆ flow dispatch failed for ${t.task_key}: ${e?.message||e}${la}\n`)}}finally{ur.delete(a)}}}n.length&&(ci("flow-dispatched",{term:"flow",flowId:e.flowId,assignments:n},Ds),process.stderr.write(`\n ${ua}◆ flow dispatched ${n.length} lane(s) — flow ${String(e.flowId).slice(0,8)}.${la}\n`),wi())}).on("broadcast",{event:"flow-assemble"},async({payload:e})=>{if(e?.flowId&&Array.isArray(e.tasks)&&(!e.host||e.host===us))try{const o=String(e.flowId).replace(/-/g,"").slice(0,8),n=e.tasks.map(t=>pt({flowId:e.flowId,taskKey:t.task_key}).dir).filter(e=>t.existsSync(e));if(!n.length)return void process.stderr.write(`\n ${ma}◆ flow assemble: no lane worktrees for ${o}.${la}\n`);const s=r.join(process.cwd(),".claude","worktrees",`flow-${o}-assembled`);t.rmSync(s,{recursive:!0,force:!0});const i=Qt({dirs:n,outDir:s}),a=r.join(s,"index.html");if(t.existsSync(a))try{t.writeFileSync(a,Xt({htmlPath:a,root:s}))}catch(e){process.stderr.write(`\n ${ma}◆ inline failed: ${e?.message||e}${la}\n`)}try{Zt({dir:s})}catch{}let c=null;try{c=(await ht({dir:s,id:`assembled:${e.flowId}`})).url}catch{}At(e.flowId),ci("flow-assembled",{term:"flow",flowId:e.flowId,previewUrl:c,outDir:s,files:i.files,conflicts:i.conflicts},Ds),process.stderr.write(`\n ${ua}◆ flow assembled — ${i.files.length} file(s)${i.conflicts.length?`, ${i.conflicts.length} conflict(s)`:""}${c?` · preview ${c}`:""} (flow ${o}).${la}\n`),wi(),Ea(e.flowId)}catch(e){process.stderr.write(`\n ${ma}◆ flow assemble failed: ${e?.message||e}${la}\n`)}}).on("broadcast",{event:"flow-revert"},async({payload:e})=>{await Ua(e)}).on("broadcast",{event:"flow-cancel"},({payload:e})=>{e?.flowId&&(e.host&&e.host!==us||(Ea(e.flowId,600),process.stderr.write(`\n ${ma}◆ flow cancelled — closing its lanes (${String(e.flowId).replace(/-/g,"").slice(0,8)}).${la}\n`)))}).subscribe(e=>{"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e&&"CLOSED"!==e||process.stderr.write(`\n ⚠ flow realtime ${e} (tpflow:${Gn}).\n`)});const Ba=new Set;js.on("broadcast",{event:"design-capability"},({payload:e})=>{const t=e?.previewId&&Ki.get(String(e.previewId)),r=t&&Rt(t),o=!!t&&!!r&&r.revision===t.revision&&t.revision===e?.revision&&Ms.has(t.term);js.send({type:"broadcast",event:"design-capability-res",payload:{previewId:String(e?.previewId||""),revision:String(e?.revision||""),ok:o}})}).on("broadcast",{event:"design-apply"},async({payload:e})=>{const t=_t(e,Ki,Gn),r=String(e?.previewId||""),o=String(e?.cid||"").slice(0,80);if(!t.ok){const e=Number.isSafeInteger(t.editIndex)?`Edit ${t.editIndex+1}: `:"";return void Gi({previewId:r,requestId:o,state:"stale-preview"===t.error?"stale":"failed",message:`${e}${t.error}`})}if(!o||Ba.has(o))return;Ba.add(o),Ba.size>500&&Ba.delete(Ba.values().next().value);const n=t.record.term,s=Mi.get(n)||[];if(Mi.set(n,s),s.length>=8)return void Gi({previewId:r,requestId:o,state:"failed",message:"Too many Design batches are queued for this lane."});const i="batch"===t.request.mode?t.request.edits:[t.request],a=[];for(let e=0;e<i.length;e++){const t=i[e];if("image"!==t.mode)continue;const n=await Tt({webBase:On,token:Kn,room:Gn,asset:t.asset,requestId:`${o}-${e+1}`,cleanup:!1});if(!n)return void Gi({previewId:r,requestId:o,state:"failed",message:`Edit ${e+1}: The private image draft could not be opened.`});t.asset.localPath=n,a.push(t.asset.path)}await Promise.all(a.map(e=>kt({webBase:On,token:Kn,room:Gn,path:e})));const c=String(e?.by||"A room member").replace(/\0/g,"").trim().slice(0,120)||"A room member";s.push({...t,by:c});const l="batch"===t.request.mode?t.request.edits.length:1;Gi({previewId:r,requestId:o,state:"queued",message:`${l} edit${1===l?"":"s"} pooled to the producing lane.`}),Qi(n)}).on("broadcast",{event:"design-restore"},({payload:e})=>{const t=String(e?.previewId||""),r=String(e?.cid||"").slice(0,80),o=Ki.get(t),n=Ui.get(t),s=o&&Rt(o);if(!(r&&o&&n?.priorRecord?.backupPath&&s&&s.revision===o.revision&&e?.revision===o.revision))return void Gi({previewId:t,requestId:r,state:"stale",message:"That verified revision can no longer be restored safely."});if(Ba.has(r))return;Ba.add(r);const i=Mi.get(o.term)||[];if(Mi.set(o.term,i),i.length>=8)return void Gi({previewId:t,requestId:r,state:"failed",message:"Too many Design edits are queued for this lane."});const a=String(e?.by||"A room member").replace(/\0/g,"").trim().slice(0,120)||"A room member";i.push({record:o,restoreRecord:n.priorRecord,request:{previewId:t,revision:o.revision,mode:"restore",intent:"restore previous verified revision",target:n.request.target||{selector:"html",tag:"artifact",name:`${n.request.edits?.length||1} pooled edits`},cid:r},by:a}),Gi({previewId:t,requestId:r,state:"queued",message:"Restore queued in the producing lane."}),Qi(o.term)}).subscribe(e=>{"CHANNEL_ERROR"!==e&&"TIMED_OUT"!==e&&"CLOSED"!==e||process.stderr.write(`\n ⚠ design realtime ${e} (tpdesign:${Gn}).\n`)});let La=!1;const Wa=e=>{const t=e?.runtime,r=e?.provider_id||"anthropic";return"claude"===t?!(!N().some(e=>e.id===r)||"anthropic"!==r&&e?.model&&D(r)!==e.model):!e?.provider_id&&("codex"===t?!e?.model||nt(H()).has(e.model):"hermes"===t&&(!e?.model||Dn.some(t=>(t?.id||t?.model)===e.model)))},Ha=async()=>{if(!La&&!Gs&&Kn&&Cs&&ps&&Number.isSafeInteger(hs)&&!(hs<1)){La=!0;try{if(!await async function(){if(!Kn||!ps||!Number.isSafeInteger(hs)||hs<1)return!1;const e=new Map(to(Gn).map(e=>[e?.id,e]).filter(([e])=>e));for(const{terminalId:t,intent:r,acknowledged:o}of yo(Gn)){if(o){vo(Gn,t);continue}const n=Xo(r);if(!n){vo(Gn,t);continue}let s=Ms.get(t);const i=e.get(t);(!0===s?.scheduleOutcomeRecorded?s.scheduleRunId:!0===i?.scheduleOutcomeRecorded?i.scheduleRunId:null)!==n.runId?!s&&i||s&&s.scheduleRunId&&s.scheduleRunId!==n.runId||(s||(s={id:t,scheduleRunId:n.runId,scheduleOutcomeRecorded:!1}),s.scheduleOutcomePending=n,await Hi(s)):vo(Gn,t)}return Zo(yo(Gn))}())return;if(!on())return;const e=await Qo({enabled:!0,supabaseUrl:Nn,anonKey:jn,token:Kn,roomCode:Gn,bridgeId:ps,bridgeFencing:hs,ownerId:Cs,providerAvailable:Wa,admitRun:async({runId:e,terminalId:t,deadlineAt:r})=>{const o=tn({spawnTimes:[],totalLive:Ms.size+Ks.size,disabled:"1"===process.env.TP_SPAWN_OFF});return o.ok?nn({runId:e,terminalId:t,deadlineAt:r}):o},releaseRun:e=>sn(e),openTerminal:async({schedule:e,run:t,terminalId:r,admission:o})=>{const n=Date.parse(t.lease_expires_at),s=Number.isFinite(n)?n-6e4:NaN;if(!Number.isFinite(s)||s<=Date.now())return null;if(!(await Ci(r)).ok)return null;const i=Ra({id:r,runtime:e.runtime,provider:e.provider_id||void 0,model:e.model||void 0,mode:"default",scheduleRunId:t.id,scheduleDeadlineAt:s,scheduleAdmissionLease:o});if(!i)return xi(r),null;di[r]=String(e.title||"Scheduled run").slice(0,80),ao(Gn,di);const a=Ls(i,String(e.prompt||""),{visibleEvent:{kind:"you",text:String(e.prompt||""),by:"Scheduled run"},rejectionMessage:"The scheduled run could not start; no hidden fallback was used."});return a?.accepted?(Ji(i),i.flush?.(),wi(),r):(i.scheduleRunId=null,Bi(i),Oa(r),null)}});!e.ok&&process.env.TP_DEBUG&&"runner_read_failed"!==e.code&&process.stderr.write(`\n ◇ scheduled-run poll: ${e.code}\n`)}finally{La=!1}}};Ha(),setInterval(()=>{Ha()},15e3).unref();let za=!1,Ja=0,Ga=0;if(setInterval(async()=>{if(Ma||!Fa)return Ja=0,void(Ga=0);const e=Date.now();if(e-Fa<6e4||za||e<Ga)return;za=!0;const t=await(async()=>{const e=new AbortController,t=setTimeout(()=>e.abort(),5e3);try{return(await fetch(`${Nn}/auth/v1/health`,{headers:{apikey:jn},signal:e.signal})).ok}catch{return!1}finally{clearTimeout(t)}})(),r=Vr({brokenSince:Fa,now:Date.now(),httpHealthy:t,activeTurn:Qr(Ms)});if("restart"===r)return process.stderr.write("\n ⚠ realtime wedged while HTTP is healthy — exiting for a clean restart.\n"),void Ya(1);const o=Tn(Ja);Ja+=1,Ga=Date.now()+o,process.stderr.write(`\n ◇ realtime unavailable (${r}) — preserving local agents; retrying in ${Math.round(o/1e3)}s.\n`);try{Rs.realtime?.disconnect?.()}catch{}try{Rs.realtime?.connect?.()}catch{}za=!1},15e3).unref(),"1"===process.env.THINKPOOL_PAIR_AUTOUPDATE&&bs){const e=1e3*Math.max(60,parseInt(process.env.THINKPOOL_PAIR_UPDATE_INTERVAL,10)||1800),t=1e3*Math.max(10,parseInt(process.env.THINKPOOL_PAIR_UPDATE_IDLE,10)||90),r=()=>{if(Qr(Ms))return!1;for(const e of Ks.values())if(e.buf)return!1;return!0},o=()=>r()&&Date.now()-Zs>=t,n=(e,t)=>{const r=e=>String(e).split("-")[0].split(".").map(e=>parseInt(e,10)||0),o=r(e),n=r(t);for(let e=0;e<3;e++){if((o[e]||0)>(n[e]||0))return!0;if((o[e]||0)<(n[e]||0))return!1}return!1},s=async()=>{const e=new AbortController,t=setTimeout(()=>e.abort(),8e3);try{const t=await fetch("https://registry.npmjs.org/thinkpool-pair/latest",{signal:e.signal,headers:{accept:"application/json"}});if(!t.ok)return null;const r=await t.json();return"string"==typeof r?.version?r.version:null}catch{return null}finally{clearTimeout(t)}},i=()=>{if(ti){if(ri){if(!r())return}else if(!o()||ni())return;process.stderr.write(`\n ◆ thinkpool-pair ${ti} ready (running ${bs}) — restarting to update; the session resumes.\n`),Ya(0,!1)}},a=async()=>{const e=await s();e&&n(e,bs)&&(ti||process.stderr.write(`\n ◆ thinkpool-pair ${e} published — "update ready" in the room; applies between turns.\n`),Da(e),i())};setInterval(a,e).unref(),setInterval(i,15e3).unref(),setTimeout(a,6e4).unref()}else if(process.send&&"1"===process.env.THINKPOOL_PAIR_ACCOUNT_CHILD){const e=1e3*Math.max(10,parseInt(process.env.THINKPOOL_PAIR_UPDATE_IDLE,10)||90),t=()=>{if(Qr(Ms))return!1;for(const e of Ks.values())if(e.buf)return!1;return!0},r=()=>t()&&Date.now()-Zs>=e;process.on("message",e=>{if(e)if("update-available"===e.t)Da(e.version);else if("agent-visibility-changed"===e.t)wi();else if("restart-probe"===e.t)try{process.send({t:"restart-probe-result",nonce:e.nonce,between:t()})}catch{}else"token"===e.t&&(Kn=e.accessToken||null,xt(Rs,Kn,jn).then(e=>{!e&&Kn&&process.stderr.write("\n ⚠ realtime auth refresh failed; private bridge features may need a reconnect.\n")}),Ss(),Ca&&xa())}),setInterval(()=>{try{process.send({t:"idle",idle:r(),between:t(),webPeer:ni()})}catch{}},5e3).unref()}else bs&&setTimeout(async()=>{try{const e=new AbortController,t=setTimeout(()=>e.abort(),8e3),r=await fetch("https://registry.npmjs.org/thinkpool-pair/latest",{signal:e.signal,headers:{accept:"application/json"}}).finally(()=>clearTimeout(t));if(!r.ok)return;const o=await r.json(),n="string"==typeof o?.version?o.version:null;if(!n)return;const s=e=>String(e).split("-")[0].split(".").map(e=>parseInt(e,10)||0),i=s(n),a=s(bs);let c=!1;for(let e=0;e<3;e++){if((i[e]||0)>(a[e]||0)){c=!0;break}if((i[e]||0)<(a[e]||0))break}c&&process.stderr.write(`\n ◆ thinkpool-pair ${n} is out (you're on ${bs}).\n To update: stop this bridge (Ctrl-C), then rerun:\n npx thinkpool-pair@latest ${Gn}\n Your session resumes on restart (you'll be asked to continue it).\n For hands-off updates with no interruption, install the background\n service: npx thinkpool-pair@latest install-service ${Gn}\n`)}catch{}},6e4).unref();async function Ya(e=0,t=!0){if(!Gs){Gs=!0,ai.close(),setTimeout(()=>process.exit(e),1500),clearInterval(Di);try{ft()}catch{}try{yt.close().catch(()=>{})}catch{}if(t)try{const e=Buffer.from("\r\n[ shared session ended ]\r\n","utf8").toString("base64");for(const t of Ks.keys())ci("pty-out",{term:t,b64:e})}catch{}for(const e of Ms.values())try{e.imageQueue?.close()}catch{}for(const e of Ms.values())try{e.flush?.()}catch{}for(const e of Ks.values())try{e.term.kill()}catch{}for(const e of Ms.values())try{e.session.end()}catch{}Ka();try{await Es.untrack()}catch{}try{await Rs.removeChannel(Es)}catch{}try{Ai&&await Rs.removeChannel(Ai)}catch{}try{await Rs.removeChannel(Ds)}catch{}try{await Rs.removeChannel(js)}catch{}try{await Rs.removeChannel(qs)}catch{}setTimeout(()=>process.exit(e),250)}}process.on("SIGINT",()=>Ya(0)),process.on("SIGTERM",()=>Ya(0)),process.on("uncaughtException",e=>{if(!e||"EPIPE"!==e.code&&"ECONNRESET"!==e.code&&"ERR_STREAM_WRITE_AFTER_END"!==e.code&&"ERR_STREAM_DESTROYED"!==e.code){try{process.stderr.write(`\n ⚠ uncaughtException: ${e?.stack||e}\n ◆ shutting down cleanly for a fresh respawn.\n`)}catch{}Ya(1)}else try{process.stderr.write(`\n ⚠ ignored benign ${e.code} (not fatal): ${e?.message||""}\n`)}catch{}}),process.on("unhandledRejection",e=>{try{process.stderr.write(`\n ⚠ unhandledRejection (non-fatal, continuing): ${e?.stack||e}\n`)}catch{}});
|
package/command-catalog.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=(e,t,n,i,r=["claude","codex","hermes"])=>Object.freeze({name:e,description:t,route:n,...i?{inputHint:i}:{},runtimes:Object.freeze(r)});export const CODE_ROOM_COMMANDS=Object.freeze([e("/side","ask or investigate without interrupting this terminal","side","task"),e("/help","list commands available in this lane","control"),e("/status","runtime, model, permissions, and busy state","control"),e("/usage","session usage and provider limits","control"),e("/context","current context-window usage","control"),e("/diff","Git changes and branch status","control"),e("/find","find relevant files in this repository","control","query"),e("/compact","compact context","runtime"),e("/clear","clear context · confirms","clear"),e("/model","pick model — opens selector","model"),e("/mode","set permission mode","mode","normal | auto-accept | plan | bypass"),e("/effort","set reasoning effort","effort","low | medium | high | xhigh | max"),e("/queue","run a prompt after the active turn","queue","prompt"),e("/steer","guide the active turn","steer","prompt",["codex","hermes"]),e("/credits","provider credit balance","credits",null,["codex","hermes"]),e("/review","review uncommitted changes","runtime",null,["codex"])]);const t=Object.freeze({claude:Object.freeze({accept:!0,hidden:Object.freeze(new Set(["/flow"]))}),codex:Object.freeze({accept:!1,hidden:Object.freeze(new Set(["/flow"]))}),hermes:Object.freeze({accept:!0,hidden:Object.freeze(new Set(["/flow","/reasoning"]))})}),n=e=>{const t=(e=>{const t=`/${String(("string"==typeof e?e:e?.name)||"").trim().replace(/^\/+/,"")}`;return/^\/[A-Za-z0-9][A-Za-z0-9:_-]*$/.test(t)?t:""})(e);if(!t)return null;if("string"==typeof e)return{name:t,description:"runtime command",route:"runtime"};const n=String(e?.description||"").trim()||"runtime command",i=String(e?.inputHint||e?.input_hint||e?.input?.hint||"").trim();return{name:t,description:n,route:String(e?.route||"").trim()||"runtime",...i?{inputHint:i}:{}}};export function commandCatalogForRuntime(e,i=[]){const r=(e=>"thinkpool"===e?"hermes":e)(e),o=t[r]||t.codex,c=new Map;for(const e of CODE_ROOM_COMMANDS)e.runtimes.includes(r)&&c.set(e.name,{name:e.name,description:e.description,route:e.route,...e.inputHint?{inputHint:e.inputHint}:{}});for(const e of Array.isArray(i)?i:[]){const t=n(e);if(!t||!o.accept||o.hidden.has(t.name))continue;const i=c.get(t.name),s="hermes"===r&&["/help","/status","/context","/credits"].includes(t.name);c.set(t.name,i?{...t,...i,description:"runtime command"===t.description?i.description:t.description,...t.inputHint?{inputHint:t.inputHint}:{},...s?{route:"runtime"}:{}}:t)}return[...c.values()]}export const commandNeedsInput=e=>!!String(e?.inputHint||"").trim();export const commandRoute=e=>String(e?.route||"runtime");export function commandHelpLine(e){return(Array.isArray(e)?e:[]).map(e=>`${e.name}${e.inputHint?` <${e.inputHint}>`:""}`).join(" ")}export function normalizePermissionMode(e){const t=String(e||"").trim().toLowerCase().replace(/[\s_-]+/g,"");return["normal","default","manual"].includes(t)?"default":["auto","autoaccept","autoacceptedits","acceptedits"].includes(t)?"acceptEdits":"plan"===t?"plan":["bypass","bypasspermissions","fullauto"].includes(t)?"bypassPermissions":null}export function reconcileCommandCatalog({current:e,incoming:t,onChanged:n,onLifecycle:i}={}){const r=Array.isArray(t)&&t.length>0,o=r&&JSON.stringify(e||[])===JSON.stringify(t);return r&&!o&&n?.(t),i?.({duplicate:o,hasIncoming:r}),o}
|
|
1
|
+
const e=(e,t,n,i,r=["claude","codex","hermes"])=>Object.freeze({name:e,description:t,route:n,...i?{inputHint:i}:{},runtimes:Object.freeze(r)});export const CODE_ROOM_COMMANDS=Object.freeze([e("/handoff","save a concise checkpoint or handoff","handoff","optional end goal"),e("/side","ask or investigate without interrupting this terminal","side","task"),e("/help","list commands available in this lane","control"),e("/status","runtime, model, permissions, and busy state","control"),e("/usage","session usage and provider limits","control"),e("/context","current context-window usage","control"),e("/diff","Git changes and branch status","control"),e("/find","find relevant files in this repository","control","query"),e("/compact","compact context","runtime"),e("/clear","clear context · confirms","clear"),e("/model","pick model — opens selector","model"),e("/mode","set permission mode","mode","normal | auto-accept | plan | bypass"),e("/effort","set reasoning effort","effort","low | medium | high | xhigh | max"),e("/queue","run a prompt after the active turn","queue","prompt"),e("/steer","guide the active turn","steer","prompt",["codex","hermes"]),e("/credits","provider credit balance","credits",null,["codex","hermes"]),e("/review","review uncommitted changes","runtime",null,["codex"])]);const t=Object.freeze({claude:Object.freeze({accept:!0,hidden:Object.freeze(new Set(["/flow"]))}),codex:Object.freeze({accept:!1,hidden:Object.freeze(new Set(["/flow"]))}),hermes:Object.freeze({accept:!0,hidden:Object.freeze(new Set(["/flow","/reasoning"]))})}),n=e=>{const t=(e=>{const t=`/${String(("string"==typeof e?e:e?.name)||"").trim().replace(/^\/+/,"")}`;return/^\/[A-Za-z0-9][A-Za-z0-9:_-]*$/.test(t)?t:""})(e);if(!t)return null;if("string"==typeof e)return{name:t,description:"runtime command",route:"runtime"};const n=String(e?.description||"").trim()||"runtime command",i=String(e?.inputHint||e?.input_hint||e?.input?.hint||"").trim();return{name:t,description:n,route:String(e?.route||"").trim()||"runtime",...i?{inputHint:i}:{}}};export function commandCatalogForRuntime(e,i=[]){const r=(e=>"thinkpool"===e?"hermes":e)(e),o=t[r]||t.codex,c=new Map;for(const e of CODE_ROOM_COMMANDS)e.runtimes.includes(r)&&c.set(e.name,{name:e.name,description:e.description,route:e.route,...e.inputHint?{inputHint:e.inputHint}:{}});for(const e of Array.isArray(i)?i:[]){const t=n(e);if(!t||!o.accept||o.hidden.has(t.name))continue;const i=c.get(t.name),s="hermes"===r&&["/help","/status","/context","/credits"].includes(t.name);c.set(t.name,i?{...t,...i,description:"runtime command"===t.description?i.description:t.description,...t.inputHint?{inputHint:t.inputHint}:{},...s?{route:"runtime"}:{}}:t)}return[...c.values()]}export const commandNeedsInput=e=>!!String(e?.inputHint||"").trim();export const commandRoute=e=>String(e?.route||"runtime");export function commandHelpLine(e){return(Array.isArray(e)?e:[]).map(e=>`${e.name}${e.inputHint?` <${e.inputHint}>`:""}`).join(" ")}export function normalizePermissionMode(e){const t=String(e||"").trim().toLowerCase().replace(/[\s_-]+/g,"");return["normal","default","manual"].includes(t)?"default":["auto","autoaccept","autoacceptedits","acceptedits"].includes(t)?"acceptEdits":"plan"===t?"plan":["bypass","bypasspermissions","fullauto"].includes(t)?"bypassPermissions":null}export function reconcileCommandCatalog({current:e,incoming:t,onChanged:n,onLifecycle:i}={}){const r=Array.isArray(t)&&t.length>0,o=r&&JSON.stringify(e||[])===JSON.stringify(t);return r&&!o&&n?.(t),i?.({duplicate:o,hasIncoming:r}),o}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{SPAWN as e}from"./cross-terminal.mjs";const t=/^[A-Za-z0-9][A-Za-z0-9._:@-]{0,255}$/;export const hostLaneLimit=(t=process.env)=>{const i=Number.parseInt(t?.TP_HOST_LIVE_LANES,10);return Number.isSafeInteger(i)?Math.max(1,Math.min(e.machineMax,i)):e.machineMax};export class HostCapacityAuthority{constructor({limit:t=hostLaneLimit()}={}){this.limit=Math.max(1,Math.min(e.machineMax,Number(t)||e.machineMax)),this.leases=new Map}acquire({room:e,terminalId:i}={}){if("string"!=typeof e||!t.test(e)||"string"!=typeof i||!t.test(i))return Object.freeze({ok:!1,code:"invalid_capacity_request"});const s=`${e}:${i}`;return this.leases.has(s)?Object.freeze({ok:!0,code:"already_admitted",active:this.leases.size,limit:this.limit}):this.leases.size>=this.limit?Object.freeze({ok:!1,code:"host_capacity",active:this.leases.size,limit:this.limit,reason:`This bridge machine already has ${this.limit} live lanes. Close a lane or leave the task queued; Dispatch resumes when capacity returns.`}):(this.leases.set(s,Object.freeze({room:e,terminalId:i})),Object.freeze({ok:!0,code:"admitted",active:this.leases.size,limit:this.limit}))}release({room:e,terminalId:t}={}){return"string"==typeof e&&"string"==typeof t&&this.leases.delete(`${e}:${t}`)}releaseRoom(e){let t=0;for(const[i,s]of this.leases)s.room===e&&(this.leases.delete(i),t++);return t}snapshot(){return Object.freeze({active:this.leases.size,limit:this.limit,available:this.leases.size<this.limit})}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thinkpool-pair",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.373",
|
|
4
4
|
"description": "Connect Claude Code, Codex, or Hermes on your computer to a thinkpool Code room.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"command-guidance.mjs",
|
|
15
15
|
"abort-turn-barrier.mjs",
|
|
16
16
|
"host-memory.mjs",
|
|
17
|
+
"host-capacity.mjs",
|
|
17
18
|
"keep-awake.mjs",
|
|
18
19
|
"sdk-smoke.mjs",
|
|
19
20
|
"sdk-admission.mjs",
|
package/publish-manifest.json
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": 1,
|
|
3
3
|
"package": "thinkpool-pair",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.373",
|
|
5
5
|
"kind": "minified",
|
|
6
|
-
"minifiedModules":
|
|
7
|
-
"sourceModuleBytes":
|
|
8
|
-
"artifactModuleBytes":
|
|
6
|
+
"minifiedModules": 112,
|
|
7
|
+
"sourceModuleBytes": 1634209,
|
|
8
|
+
"artifactModuleBytes": 724698,
|
|
9
9
|
"files": {
|
|
10
|
-
"package.json": "
|
|
10
|
+
"package.json": "67de67ee1f208f1ddaebc69563d79906f668481ada9acf46c9100ca7d29e376a",
|
|
11
11
|
"LICENSE": "8a030197ca1cad9669909ca14c9ad15cf48d9fe551da526ccaf1fca993eddb23",
|
|
12
|
-
"bridge.mjs": "
|
|
12
|
+
"bridge.mjs": "883a398e0783c1476b5490d2eebaf646e73ea15bfc265881cc7a3deaa02beb6e",
|
|
13
13
|
"bridge-service.sh": "b64f27c473ca8f3a49190fd08c23947ab14ca9958d70b6fa53c7bddc2be91403",
|
|
14
14
|
"command-guidance.mjs": "b9b967b59ff4e77c9613abb0f28858bf3ac5b106a509e471039777b53bec3e29",
|
|
15
15
|
"abort-turn-barrier.mjs": "3734a5b7e2e940ec6d7fa8b5b04935e1429a23d1bd9e92b2ac2a2ecd9f77c75e",
|
|
16
16
|
"host-memory.mjs": "44dab373e0a11b5f9ed1e5f1105643b51b1ce417781efb207a569d991865b4ae",
|
|
17
|
+
"host-capacity.mjs": "37bbc60ac906ff74dd749b7fd95382ef26db00f337cc47951d6c03cd4ba9ed08",
|
|
17
18
|
"keep-awake.mjs": "6c0a51409321f2564082b414b00696d22a740ca98180b1f628828c5fe19995c7",
|
|
18
19
|
"sdk-smoke.mjs": "dfe509863ede8a12780914939740f7f9fee36d3980f8fcb57803a33593ac4056",
|
|
19
20
|
"sdk-admission.mjs": "eb33725cc33347b900c75289eae7917f6ce3526203711515aecd48d43b3c895d",
|
|
@@ -51,7 +52,7 @@
|
|
|
51
52
|
"hermes-delegation-guard.mjs": "c2a6311320d2ff26137c4394c27561e5c8bee7a712bbb1188307bd55bfecc38e",
|
|
52
53
|
"runtime-registry.mjs": "4606e104310a755be6a8c587e1050e8b0aa5efe56e7b71f9f13983f2685fc31b",
|
|
53
54
|
"runtime-contract.mjs": "eb24b177002ba33353ec0335f4f830fb57fe313552b1a8d7aef8163cc743f6c1",
|
|
54
|
-
"command-catalog.mjs": "
|
|
55
|
+
"command-catalog.mjs": "390c70629c3251cec67bc0201e8e7588b78092f6a8a6ab4eef123032d29f617e",
|
|
55
56
|
"repo-search.mjs": "10cbce1d86655a7add0d7350ea8862a57165ccb02c2afa406348f4669050c304",
|
|
56
57
|
"git-diff-report.mjs": "a428b3129c90e207a125a86c4485ec16c8ee7e81d432060a070e37172d85ce7a",
|
|
57
58
|
"runtime-session.mjs": "1a149012375047f0c031e210cba973e64ce2e6de427a951dfc937fa7c3c402ee",
|
|
@@ -115,7 +116,7 @@
|
|
|
115
116
|
"service.mjs": "412ee48ad7b1dd281063f30f2519b077aa4cc92305e6780ac226293756f6e6f8",
|
|
116
117
|
"supervisor-ready.mjs": "7d5e4ebe3c7a93e0888dd335fb4556a670e55a80a89b861c8a44feac159cd840",
|
|
117
118
|
"presence.mjs": "2516ebb4474a8f45dd881530335c2174af9cde44be8eed6896ff8c62497b6e2b",
|
|
118
|
-
"account.mjs": "
|
|
119
|
+
"account.mjs": "3aaa834fae78706652bf5a9f58b2702bc302a314a854dc5497cf9471bc28d1c8",
|
|
119
120
|
"auth-store.mjs": "c4d41ee7cdc34c2002c6dd50d32e53ace0a3f03a116ffa930ed94a437e247625",
|
|
120
121
|
"key-shape.mjs": "a4113293d52eeba39b05e70a3e0345abc1ddc181b4f236b413bde0ae11a3f646",
|
|
121
122
|
"supabase-key.mjs": "041bde6cf50b15f6426daaf738374abc9647861d8c1dd3d85cedc45684271888",
|
|
@@ -123,7 +124,7 @@
|
|
|
123
124
|
"providers.mjs": "c0757433d30bf2f22e80f85e779cdeeeb10b412d568965f1115d4de2c8aa0314",
|
|
124
125
|
"provider-resilience.mjs": "a5a3921040d1860bb82f1d3b53c6ec25a5e230345c0131f2213c535e07fc497e",
|
|
125
126
|
"model-prices.mjs": "91f0bd8688f59ce6bff7743710d3b1139f4f0823d6b95fa68cd9b6fdcdba6ab4",
|
|
126
|
-
"README.md": "
|
|
127
|
+
"README.md": "94c866f940b8a21d4c8dbb0fe256b7910f423eadb05140da076bc17326170b79",
|
|
127
128
|
"publish-guard.mjs": "569dd788790e68ea822129f588fd16c1bb435324666552fe9dfe7c435ab3f617"
|
|
128
129
|
}
|
|
129
130
|
}
|