thinkpool-pair 0.7.366 → 0.7.367

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/launcher.mjs CHANGED
@@ -1 +1 @@
1
- import e from"node:os";import n from"node:fs";import t from"node:path";import{execSync as r}from"node:child_process";import{detectProvider as i,fetchModels as o,ANTHROPIC_COMPATIBLE as a,gatewayHint as s}from"./byok-detect.mjs";import{probeHermesRuntime as l}from"./hermes-probe.mjs";import{darwinServiceRunning as c,serviceRuntimeVersion as d}from"./service.mjs";import{loadKeepAwakePreference as p}from"./keep-awake.mjs";const u=e.homedir(),m=t.join(u,".thinkpool-pair"),h=(()=>{try{return JSON.parse(n.readFileSync(new URL("./package.json",import.meta.url),"utf8")).version}catch{return null}})();export const KNOWN_AGENTS=[{label:"Claude Code",cmd:"claude",resume:["--continue"]},{label:"Codex",cmd:"codex"},{label:"Hermes",cmd:"thinkpool"}];function k(e){const r="win32"===process.platform?(process.env.PATHEXT||".EXE;.CMD;.BAT;.COM").split(";"):[""];for(const i of(process.env.PATH||"").split(t.delimiter))if(i)for(const o of r)try{if(n.existsSync(t.join(i,e+o)))return!0}catch{}return!1}function f(e){try{return JSON.parse(n.readFileSync(e,"utf8"))}catch{return null}}export function detectState(){const e=f(t.join(m,"auth.json")),i=f(t.join(m,"provider.json")),o=!!i?.provider&&"anthropic"!==i.provider,a=k("hermes"),s=k("thinkpool")&&l().available,v=function(e){const i=e?`io.thinkpool.pair.${e.toLowerCase()}`:"io.thinkpool.pair.account";try{if("darwin"===process.platform){const e=r(`launchctl print gui/$(id -u)/${i}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return c(e)}return"linux"===process.platform?(r(`systemctl --user is-active --quiet ${i}.service`),!0):n.existsSync(function(e){const n=e?`io.thinkpool.pair.${e.toLowerCase()}`:"io.thinkpool.pair.account";if("darwin"===process.platform)return t.join(u,"Library","LaunchAgents",`${n}.plist`);if("linux"===process.platform)return t.join(u,".config","systemd","user",`${n}.service`);const r=t.join(process.env.APPDATA||t.join(u,"AppData","Roaming"),"Microsoft","Windows","Start Menu","Programs","Startup");return t.join(r,`thinkpool-pair-${e||"account"}.cmd`)}(e))}catch{return!1}}(null),g=!!e?.reconnect_required;return{loggedIn:!!e?.refresh_token&&!g,reconnectRequired:g,email:e?.email||e?.user?.email||null,provider:o?`Custom (${i.baseUrl||"endpoint"})`:"Anthropic (default)",providerModel:o&&i.model||null,agents:KNOWN_AGENTS.filter(e=>k(e.cmd)&&("thinkpool"!==e.cmd||s)),hermesInstalled:a,hermesReady:s,accountSvc:v,keepAwake:p(),serviceVersion:v?d(null):null,platform:process.platform,cwd:process.cwd(),version:h}}const v=e=>`${e}`,g=e=>`${e}`,y=e=>`${e}`,w=e=>`${e}`,b=e=>`${e}`;export async function runLauncher({actions:e,io:n,state:t=detectState(),refresh:r=null}){const l=e=>({...e,agents:Array.isArray(e?.agents)?e.agents:[],loggedIn:!!e?.loggedIn,reconnectRequired:!!e?.reconnectRequired,accountSvc:!!e?.accountSvc,keepAwake:!0===e?.keepAwake,serviceVersion:"string"==typeof e?.serviceVersion&&e.serviceVersion?e.serviceVersion:null,platform:e?.platform||process.platform,provider:e?.provider||"Anthropic (default)",cwd:e?.cwd||process.cwd(),version:e?.version||h});t=l(t);const c=()=>{r&&(t=l(r()))},d=async(e,t,r=1)=>{t.forEach((e,t)=>n.print(` ${y(String(t+1))}) ${e.label}${e.hint?" "+v(e.hint):""}`));const i=await n.ask(`\n ${e} ${v(`[${r}]`)} ${y("▸")} `),o=parseInt(i,10);return Number.isInteger(o)&&o>=1&&o<=t.length?o-1:r-1},p=async(e,t=!0)=>{const r=(await n.ask(` ${e} ${v(t?"[Y/n]":"[y/N]")} ${y("▸")} `)).toLowerCase();return r?"y"===r[0]:t},u=()=>{n.print(""),n.print(" "+v("┌ ")+g("thinkpool-pair")+v(" "+"─".repeat(40))),n.print(` ${v("│ launcher ")} ${t.version?`v${t.version}`:"version unavailable"}`),n.print(` ${v("│ account ")} ${t.reconnectRequired?b("reconnect required"):t.loggedIn?w((t.email||"linked")+" ✓"):b("not linked")}`),n.print(` ${v("│ agents ")} ${t.agents.length?t.agents.map(e=>e.label).join(", "):b("none ready: install Claude Code, Codex, or Hermes")}`),n.print(` ${v("│ directory")} ${v(t.cwd)}`);const e=t.accountSvc?"win32"===t.platform?w("startup entry installed"):w("running"+(t.serviceVersion?` v${t.serviceVersion}`:" (version unavailable)")):"not installed";n.print(` ${v("│ bridge ")} ${e}`),n.print(` ${v("│ keep awake")} ${t.keepAwake?w("on")+v(", display may still dim"):"off"}`),n.print(" "+v("└"+"─".repeat(54))+"\n")},m=async()=>!!t.loggedIn||(n.print("\n "+b(t.reconnectRequired?"This bridge lost its Thinkpool account link.":"You are not linked to a ThinkPool account yet.")),await p(" Link this device now?",!0)&&(await e.login(),c()),!!t.loggedIn||(n.print(" "+b("login needed to serve your sessions — back to menu")),!1)),k=async()=>!!t.agents.length||(n.print("\n "+b("No coding agent is ready on this computer")),n.print(" Thinkpool connects an agent already installed on this machine. It does not"),n.print(" include one. Install and configure at least one of:"),n.print(`\n ${y("Claude Code")} command: claude`),n.print(` ${y("Codex")} command: codex`),n.print(` ${y("Hermes")} command: hermes, then set up its Thinkpool profile here`),n.print("\n "+g("BYOK does not replace the agent. It only gives an installed agent")),n.print(" credentials for a model provider."),n.print("\n Install one, then reopen this launcher."),!1),f=async()=>{const r=t.provider+(t.providerModel?`, model ${t.providerModel}`:"");n.print("\n "+v("Provider settings supply model credentials. Claude Code, Codex, or Hermes must still be installed locally."));const l=await d("\n provider",[{label:"Anthropic (default)",hint:"regular Claude login"},{label:"Paste a key, pick a model",hint:"auto-detects the provider · OpenRouter = any model"},{label:"Custom endpoint",hint:"enter a base url + token by hand"},{label:"← Back",hint:`current: ${r}`}],4);if(3===l)return;if(0===l)return await e.setProvider({kind:"anthropic"}),c(),void n.print("\n "+w("✓ back on regular Claude."));if(1===l){const t=(await n.ask(`\n Paste your API key ${v("(blank to cancel)")} ${y("▸")} `)).trim();if(!t)return void n.print(" "+b("cancelled — provider unchanged"));const r=i(t);if(!r.compatible)return void n.print("\n "+b(s(r.name)));const l=a[r.id];n.print(`\n ${w("✓ detected "+l.name)} ${v("— fetching models…")}`);const p=await o({modelsUrl:l.models,key:t,auth:l.auth});let u;if(0===p.length)u=(await n.ask(` Couldn't list models. Model id ${v("(blank = endpoint default)")} ${y("▸")} `)).trim()||void 0;else if(p.length<=40){const e=await d("\n model",p.map(e=>({label:e})),1);u=p[e]}else for(n.print(` ${v(p.length+" models available, e.g. "+p.slice(0,3).join(", ")+"…")}`);;){const e=(await n.ask(` Type a model id or part of it ${v("(blank to cancel)")} ${y("▸")} `)).trim();if(!e)return void n.print(" "+b("cancelled — provider unchanged"));const t=p.filter(n=>n.toLowerCase().includes(e.toLowerCase()));if(0!==t.length){if(1===t.length){u=t[0];break}if(t.length<=40){const e=await d("\n pick",t.map(e=>({label:e})),1);u=t[e];break}n.print(` ${b(t.length+" matches — narrow it down")}`)}else n.print(" "+b("no match — try again"))}return await e.setProvider({kind:"custom",base:l.base,token:t,model:u}),c(),void n.print(`\n ${w("✓ provider set.")}\n ${l.name}\n model: ${u||"(endpoint default)"}`)}const p=(await n.ask(`\n Base url ${v("(blank to cancel · SDK appends /v1/messages)")} ${y("▸")} `)).trim();if(!p)return void n.print(" "+b("cancelled — provider unchanged"));const u=(await n.ask(` API token ${v("(blank to cancel)")} ${y("▸")} `)).trim();if(!u)return void n.print(" "+b("cancelled — provider unchanged"));const m=(await n.ask(` Model ${v("(blank = endpoint default · e.g. glm-4.6)")} ${y("▸")} `)).trim();await e.setProvider({kind:"custom",base:p,token:u,model:m||void 0}),c(),n.print(`\n ${w("✓ provider set to custom.")}\n base url: ${t.provider}\n model: ${t.providerModel||"(endpoint default)"}`)},$=async()=>{for(;;){const r=[{key:"provider",label:"Provider",hint:`current: ${t.provider}`},{key:"account",label:"Account",hint:t.reconnectRequired?"reconnect required":t.loggedIn?`linked: ${t.email||"yes"}`:"not linked"},{key:"awake",label:"Keep computer awake",hint:(t.keepAwake?"ON":"off")+" · the screen can still dim, lock, and turn off"}];t.hermesInstalled&&r.push({key:"hermes",label:t.hermesReady?"Hermes profile":"Set up Hermes",hint:t.hermesReady?"isolated profile ready":"set up isolated profile + delegation guard"}),r.push({key:"back",label:"Back to main menu",hint:""});const i=r[await d("\n change",r,r.length)];if("back"===i.key)return;if("provider"===i.key)await f();else{if("account"===i.key)return await e.login(),void c();if("awake"===i.key)if(t.keepAwake){if(!1===await e.setKeepAwake({enabled:!1}))continue;t={...t,keepAwake:!1},c(),n.print("\n "+w("✓ keep-awake is off. The computer may sleep normally."))}else if(n.print("\n "+b("Important: keep-awake changes this computer’s power behavior")),n.print(" While the bridge runs, Thinkpool will prevent the computer itself from"),n.print(" automatically sleeping. This can use substantially more battery and may"),n.print(" also block suspend requests on some Linux systems."),n.print("\n "+w("It does NOT keep the screen on. Display dimming, screen locking, and")),n.print(" display sleep continue to work normally. Closing a laptop lid may still"),n.print(" sleep it, depending on the operating system and power settings."),await p("\n Enable keep-awake while the Thinkpool bridge runs?",!1)){if(!1===await e.setKeepAwake({enabled:!0}))continue;t={...t,keepAwake:!0},c(),n.print("\n "+w("✓ keep-awake is on. Your screen is still free to dim and turn off."))}else n.print("\n "+b("unchanged: keep-awake remains off."));else if("hermes"===i.key){const n=await d("\n Hermes profile",[{label:"Clone active profile",hint:"copies provider/config explicitly; fresh ThinkPool session history"},{label:"Create clean profile",hint:"no copied credentials or bundled skills; configure provider afterward"},{label:"Back",hint:""}],3);2!==n&&(await e.setupHermes({mode:0===n?"clone":"clean"}),c())}}}};for(;;){u(),n.print(" "+g("What do you want to do?")+"\n");const r=t.accountSvc?["win32"===t.platform?{key:"restart",label:"Update startup entry",hint:"installs the latest version; relaunch the bridge window to apply"}:{key:"restart",label:"Restart & update bridge",hint:"install the latest published version; sessions resume"},{key:"uninstall",label:"Remove background service",hint:"stop serving your sessions on this device"}]:[{key:"serve",label:"Serve all my sessions",hint:"runs here, Ctrl-C stops it"},{key:"service",label:"Always-on background service",hint:"recommended — survives reboot, restarts on crash"}];r.push({key:"settings",label:"Settings",hint:`provider · account · keep-awake ${t.keepAwake?"ON":"off"}${t.hermesInstalled?" · Hermes profile":""}`}),r.push({key:"quit",label:"Quit",hint:""});const i=r[await d("choose",r)];if("quit"===i.key)return;if("serve"===i.key)await k()&&await m()&&await e.serveAccountForeground();else if("service"===i.key){if(await k()&&await m()){if(!0===await e.installService({room:null})&&(!e.relaunchLauncher||await e.relaunchLauncher()))return;c()}}else if("restart"===i.key){if(!0===await e.restartUpdateService({room:null})&&(!e.relaunchLauncher||await e.relaunchLauncher()))return;c()}else"uninstall"===i.key?(await e.uninstallService({room:null}),c()):"settings"===i.key&&await $();await n.ask("\n "+v("press Enter to return to the menu…"))}}
1
+ import e from"node:os";import n from"node:fs";import t from"node:path";import{execSync as r}from"node:child_process";import{detectProvider as i,fetchModels as o,ANTHROPIC_COMPATIBLE as a,gatewayHint as s}from"./byok-detect.mjs";import{probeHermesRuntime as l}from"./hermes-probe.mjs";import{darwinServiceRunning as c,serviceRuntimeVersion as p}from"./service.mjs";import{loadKeepAwakePreference as d}from"./keep-awake.mjs";const u=e.homedir(),m=t.join(u,".thinkpool-pair"),h=(()=>{try{return JSON.parse(n.readFileSync(new URL("./package.json",import.meta.url),"utf8")).version}catch{return null}})();export const KNOWN_AGENTS=[{label:"Claude Code",cmd:"claude",resume:["--continue"]},{label:"Codex",cmd:"codex"},{label:"Hermes",cmd:"thinkpool"}];function k(e){const r="win32"===process.platform?(process.env.PATHEXT||".EXE;.CMD;.BAT;.COM").split(";"):[""];for(const i of(process.env.PATH||"").split(t.delimiter))if(i)for(const o of r)try{if(n.existsSync(t.join(i,e+o)))return!0}catch{}return!1}function f(e){try{return JSON.parse(n.readFileSync(e,"utf8"))}catch{return null}}export function detectState(){const e=f(t.join(m,"auth.json")),i=f(t.join(m,"provider.json")),o=!!i?.provider&&"anthropic"!==i.provider,a=k("hermes"),s=k("thinkpool")&&l().available,v=function(e){const i=e?`io.thinkpool.pair.${e.toLowerCase()}`:"io.thinkpool.pair.account";try{if("darwin"===process.platform){const e=r(`launchctl print gui/$(id -u)/${i}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return c(e)}return"linux"===process.platform?(r(`systemctl --user is-active --quiet ${i}.service`),!0):n.existsSync(function(e){const n=e?`io.thinkpool.pair.${e.toLowerCase()}`:"io.thinkpool.pair.account";if("darwin"===process.platform)return t.join(u,"Library","LaunchAgents",`${n}.plist`);if("linux"===process.platform)return t.join(u,".config","systemd","user",`${n}.service`);const r=t.join(process.env.APPDATA||t.join(u,"AppData","Roaming"),"Microsoft","Windows","Start Menu","Programs","Startup");return t.join(r,`thinkpool-pair-${e||"account"}.cmd`)}(e))}catch{return!1}}(null),g=!!e?.reconnect_required;return{loggedIn:!!e?.refresh_token&&!g,reconnectRequired:g,email:e?.email||e?.user?.email||null,provider:o?`Custom (${i.baseUrl||"endpoint"})`:"Anthropic (default)",providerModel:o&&i.model||null,agents:KNOWN_AGENTS.filter(e=>k(e.cmd)&&("thinkpool"!==e.cmd||s)),hermesInstalled:a,hermesReady:s,accountSvc:v,keepAwake:d(),serviceVersion:v?p(null):null,platform:process.platform,cwd:process.cwd(),version:h}}const v=e=>`${e}`,g=e=>`${e}`,y=e=>`${e}`,w=e=>`${e}`,b=e=>`${e}`;export async function runLauncher({actions:e,io:n,state:t=detectState(),refresh:r=null}){const l=e=>({...e,agents:Array.isArray(e?.agents)?e.agents:[],loggedIn:!!e?.loggedIn,reconnectRequired:!!e?.reconnectRequired,accountSvc:!!e?.accountSvc,keepAwake:!0===e?.keepAwake,serviceVersion:"string"==typeof e?.serviceVersion&&e.serviceVersion?e.serviceVersion:null,platform:e?.platform||process.platform,provider:e?.provider||"Anthropic (default)",cwd:e?.cwd||process.cwd(),version:e?.version||h});t=l(t);const c=()=>{r&&(t=l(r()))},p=async(e,t,r=1)=>{t.forEach((e,t)=>n.print(` ${y(String(t+1))}) ${e.label}${e.hint?" "+v(e.hint):""}`));const i=await n.ask(`\n ${e} ${v(`[${r}]`)} ${y("▸")} `),o=parseInt(i,10);return Number.isInteger(o)&&o>=1&&o<=t.length?o-1:r-1},d=async(e,t=!0)=>{const r=(await n.ask(` ${e} ${v(t?"[Y/n]":"[y/N]")} ${y("▸")} `)).toLowerCase();return r?"y"===r[0]:t},u=()=>{n.print(""),n.print(" "+v("┌ ")+g("thinkpool-pair")+v(" "+"─".repeat(40))),n.print(` ${v("│ launcher ")} ${t.version?`v${t.version}`:"version unavailable"}`),n.print(` ${v("│ account ")} ${t.reconnectRequired?b("reconnect required"):t.loggedIn?w((t.email||"linked")+" ✓"):b("not linked")}`),n.print(` ${v("│ agents ")} ${t.agents.length?t.agents.map(e=>e.label).join(", "):b("none ready: install Claude Code, Codex, or Hermes")}`),n.print(` ${v("│ directory")} ${v(t.cwd)}`);const e=t.accountSvc?"win32"===t.platform?w("startup entry installed"):w("running"+(t.serviceVersion?` v${t.serviceVersion}`:" (version unavailable)")):"not installed";n.print(` ${v("│ bridge ")} ${e}`),n.print(` ${v("│ keep awake")} ${t.keepAwake?w("on")+v(", display may still dim"):"off"}`),n.print(" "+v("└"+"─".repeat(54))+"\n")},m=async()=>!!t.loggedIn||(n.print("\n "+b(t.reconnectRequired?"This bridge lost its thinkpool account link.":"You are not linked to a thinkpool account yet.")),await d(" Link this device now?",!0)&&(await e.login(),c()),!!t.loggedIn||(n.print(" "+b("login needed to serve your sessions — back to menu")),!1)),k=async()=>!!t.agents.length||(n.print("\n "+b("No coding agent is ready on this computer")),n.print(" thinkpool connects an agent already installed on this machine. It does not"),n.print(" include one. Install and configure at least one of:"),n.print(`\n ${y("Claude Code")} command: claude`),n.print(` ${y("Codex")} command: codex`),n.print(` ${y("Hermes")} command: hermes, then set up its thinkpool profile here`),n.print("\n "+g("BYOK does not replace the agent. It only gives an installed agent")),n.print(" credentials for a model provider."),n.print("\n Install one, then reopen this launcher."),!1),f=async()=>{const r=t.provider+(t.providerModel?`, model ${t.providerModel}`:"");n.print("\n "+v("Provider settings supply model credentials. Claude Code, Codex, or Hermes must still be installed locally."));const l=await p("\n provider",[{label:"Anthropic (default)",hint:"regular Claude login"},{label:"Paste a key, pick a model",hint:"auto-detects the provider · OpenRouter = any model"},{label:"Custom endpoint",hint:"enter a base url + token by hand"},{label:"← Back",hint:`current: ${r}`}],4);if(3===l)return;if(0===l)return await e.setProvider({kind:"anthropic"}),c(),void n.print("\n "+w("✓ back on regular Claude."));if(1===l){const t=(await n.ask(`\n Paste your API key ${v("(blank to cancel)")} ${y("▸")} `)).trim();if(!t)return void n.print(" "+b("cancelled — provider unchanged"));const r=i(t);if(!r.compatible)return void n.print("\n "+b(s(r.name)));const l=a[r.id];n.print(`\n ${w("✓ detected "+l.name)} ${v("— fetching models…")}`);const d=await o({modelsUrl:l.models,key:t,auth:l.auth});let u;if(0===d.length)u=(await n.ask(` Couldn't list models. Model id ${v("(blank = endpoint default)")} ${y("▸")} `)).trim()||void 0;else if(d.length<=40){const e=await p("\n model",d.map(e=>({label:e})),1);u=d[e]}else for(n.print(` ${v(d.length+" models available, e.g. "+d.slice(0,3).join(", ")+"…")}`);;){const e=(await n.ask(` Type a model id or part of it ${v("(blank to cancel)")} ${y("▸")} `)).trim();if(!e)return void n.print(" "+b("cancelled — provider unchanged"));const t=d.filter(n=>n.toLowerCase().includes(e.toLowerCase()));if(0!==t.length){if(1===t.length){u=t[0];break}if(t.length<=40){const e=await p("\n pick",t.map(e=>({label:e})),1);u=t[e];break}n.print(` ${b(t.length+" matches — narrow it down")}`)}else n.print(" "+b("no match — try again"))}return await e.setProvider({kind:"custom",base:l.base,token:t,model:u}),c(),void n.print(`\n ${w("✓ provider set.")}\n ${l.name}\n model: ${u||"(endpoint default)"}`)}const d=(await n.ask(`\n Base url ${v("(blank to cancel · SDK appends /v1/messages)")} ${y("▸")} `)).trim();if(!d)return void n.print(" "+b("cancelled — provider unchanged"));const u=(await n.ask(` API token ${v("(blank to cancel)")} ${y("▸")} `)).trim();if(!u)return void n.print(" "+b("cancelled — provider unchanged"));const m=(await n.ask(` Model ${v("(blank = endpoint default · e.g. glm-4.6)")} ${y("▸")} `)).trim();await e.setProvider({kind:"custom",base:d,token:u,model:m||void 0}),c(),n.print(`\n ${w("✓ provider set to custom.")}\n base url: ${t.provider}\n model: ${t.providerModel||"(endpoint default)"}`)},$=async()=>{for(;;){const r=[{key:"provider",label:"Provider",hint:`current: ${t.provider}`},{key:"account",label:"Account",hint:t.reconnectRequired?"reconnect required":t.loggedIn?`linked: ${t.email||"yes"}`:"not linked"},{key:"awake",label:"Keep computer awake",hint:(t.keepAwake?"ON":"off")+" · the screen can still dim, lock, and turn off"}];t.hermesInstalled&&r.push({key:"hermes",label:t.hermesReady?"Hermes profile":"Set up Hermes",hint:t.hermesReady?"isolated profile ready":"set up isolated profile + delegation guard"}),r.push({key:"back",label:"Back to main menu",hint:""});const i=r[await p("\n change",r,r.length)];if("back"===i.key)return;if("provider"===i.key)await f();else{if("account"===i.key)return await e.login(),void c();if("awake"===i.key)if(t.keepAwake){if(!1===await e.setKeepAwake({enabled:!1}))continue;t={...t,keepAwake:!1},c(),n.print("\n "+w("✓ keep-awake is off. The computer may sleep normally."))}else if(n.print("\n "+b("Important: keep-awake changes this computer’s power behavior")),n.print(" While the bridge runs, thinkpool will prevent the computer itself from"),n.print(" automatically sleeping. This can use substantially more battery and may"),n.print(" also block suspend requests on some Linux systems."),n.print("\n "+w("It does NOT keep the screen on. Display dimming, screen locking, and")),n.print(" display sleep continue to work normally. Closing a laptop lid may still"),n.print(" sleep it, depending on the operating system and power settings."),await d("\n Enable keep-awake while the thinkpool bridge runs?",!1)){if(!1===await e.setKeepAwake({enabled:!0}))continue;t={...t,keepAwake:!0},c(),n.print("\n "+w("✓ keep-awake is on. Your screen is still free to dim and turn off."))}else n.print("\n "+b("unchanged: keep-awake remains off."));else if("hermes"===i.key){const n=await p("\n Hermes profile",[{label:"Clone active profile",hint:"copies provider/config explicitly; fresh thinkpool session history"},{label:"Create clean profile",hint:"no copied credentials or bundled skills; configure provider afterward"},{label:"Back",hint:""}],3);2!==n&&(await e.setupHermes({mode:0===n?"clone":"clean"}),c())}}}};for(;;){u(),n.print(" "+g("What do you want to do?")+"\n");const r=t.accountSvc?["win32"===t.platform?{key:"restart",label:"Update startup entry",hint:"installs the latest version; relaunch the bridge window to apply"}:{key:"restart",label:"Restart & update bridge",hint:"install the latest published version; sessions resume"},{key:"uninstall",label:"Remove background service",hint:"stop serving your sessions on this device"}]:[{key:"serve",label:"Serve all my sessions",hint:"runs here, Ctrl-C stops it"},{key:"service",label:"Always-on background service",hint:"recommended — survives reboot, restarts on crash"}];r.push({key:"settings",label:"Settings",hint:`provider · account · keep-awake ${t.keepAwake?"ON":"off"}${t.hermesInstalled?" · Hermes profile":""}`}),r.push({key:"quit",label:"Quit",hint:""});const i=r[await p("choose",r)];if("quit"===i.key)return;if("serve"===i.key)await k()&&await m()&&await e.serveAccountForeground();else if("service"===i.key){if(await k()&&await m()){if(!0===await e.installService({room:null})&&(!e.relaunchLauncher||await e.relaunchLauncher()))return;c()}}else if("restart"===i.key){if(!0===await e.restartUpdateService({room:null})&&(!e.relaunchLauncher||await e.relaunchLauncher()))return;c()}else"uninstall"===i.key?(await e.uninstallService({room:null}),c()):"settings"===i.key&&await $();await n.ask("\n "+v("press Enter to return to the menu…"))}}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.7.366",
4
- "description": "Connect Claude Code, Codex, or Hermes on your computer to a Thinkpool Code room.",
3
+ "version": "0.7.367",
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",
7
7
  "bin": {
@@ -1 +1 @@
1
- import e from"node:fs";import o from"node:os";import t from"node:path";const r=e=>{try{return new URL(e).host}catch{return null}},n=(o,t)=>{try{return JSON.parse(e.readFileSync(o,"utf8"))}catch{return t}},i=(e,o)=>{const r=t.resolve(String(e||""));return r===o?"~":r.startsWith(`${o}${t.sep}`)?`~${r.slice(o.length)}`:r};export function buildPrivacyReport({home:a=o.homedir(),cwd:s=process.cwd(),env:d=process.env,exists:c=e.existsSync,read:p=n}={}){const l=t.join(a,".thinkpool-pair"),u=p(t.join(l,"dirs.json"),{})||{},m=p(t.join(l,"served.json"),{})||{},h=p(t.join(l,"providers.json"),[])||[],y=p(t.join(l,"provider.json"),null);let g="";try{g=e.readFileSync(t.join(l,"default-dir"),"utf8").trim()}catch{}const j=new Set([s,g,...Object.values(u),...Object.values(m)].filter(Boolean).map(e=>i(e,a))),v=new Set([...h.map(e=>r(e?.baseUrl)),r(y?.baseUrl)].filter(Boolean)),b=r(d.TP_SUPABASE_URL||"https://daytvtakmlixpfbbqzjd.supabase.co"),f=r(d.TP_WEB_BASE||"https://thinkpool.io"),k=[["Saved login","auth.json",c(t.join(l,"auth.json")),"refresh token and account identity"],["Provider registry","providers.json",c(t.join(l,"providers.json")),"provider endpoint, model, and API key"],["Bridge keypair","bridge-key.json",c(t.join(l,"bridge-key.json")),"private key used to open browser-sealed provider keys"],["Agent picker visibility","agent-visibility.json",c(t.join(l,"agent-visibility.json")),"which installed runtimes are hidden from terminal pickers"],["Room directories","dirs.json / served.json",c(t.join(l,"dirs.json"))||c(t.join(l,"served.json")),"room-to-project directory mappings"],["Bridge logs","update.log and service logs",c(t.join(l,"update.log")),"update and background-service diagnostics"]];return{generatedAt:(new Date).toISOString(),configDir:i(l,a),projectDirs:[...j].sort(),localRecords:k,outbound:[[f,"Thinkpool configuration, linking, version checks, and product APIs"],[b,"authentication, room database, storage, and realtime transport"],["registry.npmjs.org","package installation and updates initiated with npm or npx"],...[...v].sort().map(e=>[e,"AI provider selected on this bridge"])].filter(([e])=>e),remote:[["Thinkpool cloud receives","account/profile data; room membership and metadata; room chat; cleaned terminal output; terminal and room events; attachments; operational request metadata"],["Thinkpool cloud does not receive as a repository","a crawled copy of the project directory or repository file tree"],["Readable provider key","stored locally by the bridge; Thinkpool relays only a browser-sealed envelope"],["AI prompts and code context","sent by the local coding agent to the selected AI provider; content depends on that runtime and the task"]],limits:["Coding-agent runtimes and commands can contact domains beyond the bridge list above.","Thinkpool room transcripts are readable by Thinkpool infrastructure today; they are not end-to-end encrypted.","This report describes configured access. It is not a packet capture or a guarantee that a third-party agent obeys the same boundary."]}}export function formatPrivacyReport(e){return[""," THINKPOOL PRIVACY REPORT",` generated ${e.generatedAt}`,""," LOCAL ACCESS",` Bridge configuration: ${e.configDir}`,...e.projectDirs.map(e=>` Project directory: ${e}`),""," LOCAL RECORDS",...e.localRecords.map(([e,o,t,r])=>{return` ${e}: ${n=t,n?"present":"not present"} (${o})\n contains: ${r}`;var n}),""," OUTBOUND DOMAINS",...e.outbound.map(([e,o])=>` ${e}\n ${o}`),""," REMOTE DATA",...e.remote.map(([e,o])=>` ${e}:\n ${o}`),""," IMPORTANT LIMITS",...e.limits.map(e=>` - ${e}`),""," Full data map: https://thinkpool.io/data",""].join("\n")}export function runPrivacyReport(e){const o=buildPrivacyReport(e);return process.stdout.write(formatPrivacyReport(o)),o}
1
+ import e from"node:fs";import t from"node:os";import o from"node:path";const r=e=>{try{return new URL(e).host}catch{return null}},n=(t,o)=>{try{return JSON.parse(e.readFileSync(t,"utf8"))}catch{return o}},i=(e,t)=>{const r=o.resolve(String(e||""));return r===t?"~":r.startsWith(`${t}${o.sep}`)?`~${r.slice(t.length)}`:r};export function buildPrivacyReport({home:a=t.homedir(),cwd:s=process.cwd(),env:d=process.env,exists:c=e.existsSync,read:p=n}={}){const l=o.join(a,".thinkpool-pair"),u=p(o.join(l,"dirs.json"),{})||{},m=p(o.join(l,"served.json"),{})||{},h=p(o.join(l,"providers.json"),[])||[],y=p(o.join(l,"provider.json"),null);let g="";try{g=e.readFileSync(o.join(l,"default-dir"),"utf8").trim()}catch{}const j=new Set([s,g,...Object.values(u),...Object.values(m)].filter(Boolean).map(e=>i(e,a))),v=new Set([...h.map(e=>r(e?.baseUrl)),r(y?.baseUrl)].filter(Boolean)),b=r(d.TP_SUPABASE_URL||"https://daytvtakmlixpfbbqzjd.supabase.co"),f=r(d.TP_WEB_BASE||"https://thinkpool.io"),k=[["Saved login","auth.json",c(o.join(l,"auth.json")),"refresh token and account identity"],["Provider registry","providers.json",c(o.join(l,"providers.json")),"provider endpoint, model, and API key"],["Bridge keypair","bridge-key.json",c(o.join(l,"bridge-key.json")),"private key used to open browser-sealed provider keys"],["Agent picker visibility","agent-visibility.json",c(o.join(l,"agent-visibility.json")),"which installed runtimes are hidden from terminal pickers"],["Room directories","dirs.json / served.json",c(o.join(l,"dirs.json"))||c(o.join(l,"served.json")),"room-to-project directory mappings"],["Bridge logs","update.log and service logs",c(o.join(l,"update.log")),"update and background-service diagnostics"]];return{generatedAt:(new Date).toISOString(),configDir:i(l,a),projectDirs:[...j].sort(),localRecords:k,outbound:[[f,"thinkpool configuration, linking, version checks, and product APIs"],[b,"authentication, room database, storage, and realtime transport"],["registry.npmjs.org","package installation and updates initiated with npm or npx"],...[...v].sort().map(e=>[e,"AI provider selected on this bridge"])].filter(([e])=>e),remote:[["thinkpool cloud receives","account/profile data; room membership and metadata; room chat; cleaned terminal output; terminal and room events; attachments; operational request metadata"],["thinkpool cloud does not receive as a repository","a crawled copy of the project directory or repository file tree"],["Readable provider key","stored locally by the bridge; thinkpool relays only a browser-sealed envelope"],["AI prompts and code context","sent by the local coding agent to the selected AI provider; content depends on that runtime and the task"]],limits:["Coding-agent runtimes and commands can contact domains beyond the bridge list above.","thinkpool room transcripts are readable by thinkpool infrastructure today; they are not end-to-end encrypted.","This report describes configured access. It is not a packet capture or a guarantee that a third-party agent obeys the same boundary."]}}export function formatPrivacyReport(e){return[""," thinkpool PRIVACY REPORT",` generated ${e.generatedAt}`,""," LOCAL ACCESS",` Bridge configuration: ${e.configDir}`,...e.projectDirs.map(e=>` Project directory: ${e}`),""," LOCAL RECORDS",...e.localRecords.map(([e,t,o,r])=>{return` ${e}: ${n=o,n?"present":"not present"} (${t})\n contains: ${r}`;var n}),""," OUTBOUND DOMAINS",...e.outbound.map(([e,t])=>` ${e}\n ${t}`),""," REMOTE DATA",...e.remote.map(([e,t])=>` ${e}:\n ${t}`),""," IMPORTANT LIMITS",...e.limits.map(e=>` - ${e}`),""," Full data map: https://thinkpool.io/data",""].join("\n")}export function runPrivacyReport(e){const t=buildPrivacyReport(e);return process.stdout.write(formatPrivacyReport(t)),t}
@@ -1,37 +1,37 @@
1
1
  {
2
2
  "format": 1,
3
3
  "package": "thinkpool-pair",
4
- "version": "0.7.366",
4
+ "version": "0.7.367",
5
5
  "kind": "minified",
6
6
  "minifiedModules": 111,
7
7
  "sourceModuleBytes": 1620861,
8
8
  "artifactModuleBytes": 719348,
9
9
  "files": {
10
- "package.json": "0229a6f617212531ad287ab4bfc00aecca97f8296a812dafcc666fd560dad051",
11
- "LICENSE": "95f1ba638272b3c5f26c36b45bbd8a951b545a091e2c9710fb47f2d68a83a001",
12
- "bridge.mjs": "9cddacbf7a91fddd8a7bc57ea2f6f9ce1ec442a21bafd948202fd09b188b00b1",
10
+ "package.json": "5a338ed260210301ebc15e734101e2853e173699d3d493e23554b74388a1d457",
11
+ "LICENSE": "8a030197ca1cad9669909ca14c9ad15cf48d9fe551da526ccaf1fca993eddb23",
12
+ "bridge.mjs": "62d87e3820d509d39ff6cb3288979d855f0c1b64745f7acf7b284cd606500b09",
13
13
  "bridge-service.sh": "b64f27c473ca8f3a49190fd08c23947ab14ca9958d70b6fa53c7bddc2be91403",
14
14
  "command-guidance.mjs": "b9b967b59ff4e77c9613abb0f28858bf3ac5b106a509e471039777b53bec3e29",
15
15
  "abort-turn-barrier.mjs": "3734a5b7e2e940ec6d7fa8b5b04935e1429a23d1bd9e92b2ac2a2ecd9f77c75e",
16
- "host-memory.mjs": "0fab9118b1a53e6939dd047140a5e181d3fc98f5f8faa2b49b1ee04fd148f650",
17
- "keep-awake.mjs": "af39f17c0279ddacffbbe52443231184d30fc4a5a579692898689b80e8189d67",
16
+ "host-memory.mjs": "44dab373e0a11b5f9ed1e5f1105643b51b1ce417781efb207a569d991865b4ae",
17
+ "keep-awake.mjs": "6c0a51409321f2564082b414b00696d22a740ca98180b1f628828c5fe19995c7",
18
18
  "sdk-smoke.mjs": "dfe509863ede8a12780914939740f7f9fee36d3980f8fcb57803a33593ac4056",
19
19
  "sdk-admission.mjs": "eb33725cc33347b900c75289eae7917f6ce3526203711515aecd48d43b3c895d",
20
- "launcher.mjs": "1723ab61347bd160479da520a5a18f99c8af1dc5a18fbd3f6ca03b97b16ce8e4",
21
- "privacy-report.mjs": "2299c607b9872d8d3f563ad14ba3a7b75ea1fb5292e7b6ef756d62f26f2362ec",
20
+ "launcher.mjs": "d10ea30ec940094b8ae7881c296d18f348f16d013a89c1ea725cacc273e2d376",
21
+ "privacy-report.mjs": "b444610be6de8b3bcf0086d585594286ef000dad1e075df87013003a315bf211",
22
22
  "agent-visibility.mjs": "624448728a596fea3a2f01fc686db78716cff20429b8ddbfaa4fb7eb05027870",
23
- "byok-detect.mjs": "61befb5e53427b558cb911d35ad69fab2458de93dc34f650b7c56ca75d387bc9",
23
+ "byok-detect.mjs": "f31f2ca426737581a97c391b3cecfc75f0207cfa31f51c6bf4a9148309c9625d",
24
24
  "context-contract.mjs": "ffebb435dc5d75c289329bf16ab909df9d634a2b508154c250c6b25906a02a91",
25
25
  "context-windows.mjs": "80af664f84d7e95ef2b0a2a3131090ac4ccd522709448ac9a0d96c378bbec0f7",
26
- "claude-session.mjs": "d0b25010078ed642ee7f1149b3f171ba9ff165eaa6ad864f060410682d7e94f8",
27
- "terminal-name.mjs": "3e114c771abdf42d4ba43d280d01a0d212267f122e3d6d793e3f4e52d052e66a",
26
+ "claude-session.mjs": "a8e8d2db7dc350a53a5af3a7df1ee96cfa00a327c1e5b344d6aceda4d307600a",
27
+ "terminal-name.mjs": "f39bb8d1e148ab9a74cbb96438d31e524d6597b8035f00d7a906c28c306c0cf8",
28
28
  "claude-command-catalog.mjs": "36bd4342b2ae94b43a0072533ef2d1648c7473003964bbad433fdb1a8b2bfec1",
29
- "codex-session.mjs": "dc4029720e1787e334fc8c81672514c9f830201bef489564eb39f4720e6c3f73",
29
+ "codex-session.mjs": "54a6b23978e1e726f181d990a9ef4933067aa3a88a32fcbf3343be2dd1489120",
30
30
  "question-response.mjs": "35a7ba53d3eb117717c18004d2a8441f8f37665b231a3c44f4bd9321ff59dd57",
31
- "thinkpool-room-prompt.mjs": "d9abf116d457043833a8afdb7755a2d03426362f1858053f8615ebf46ed10e34",
32
- "thinkpool-prompt-contracts.mjs": "8e47f2b7928dc99b85596f85b8ca1c26e9ee99b985405989e64cb9752ce67e9c",
33
- "thinkpool-capabilities.json": "d0c138387d3cc48f5567480457d10659fd2b20a9445693183ae0f6958a4956bd",
34
- "codex-app-server.mjs": "f9c2bad1eaf79420d87e12c256bc645ab48083c0b89d252e4968fd176f4bdfc3",
31
+ "thinkpool-room-prompt.mjs": "bba3e5b9776ef95475aa3a7d242ab59881f3908a086d0fe4d75a3945316a5505",
32
+ "thinkpool-prompt-contracts.mjs": "051602d7d2fe9b34df92957bd3922c5eeebedbcc60c892adf415243887d8c62f",
33
+ "thinkpool-capabilities.json": "9e7407c59b5e2465201a63cb33ad56373c7e8e5fe9a678d92ed41869f4f7f90e",
34
+ "codex-app-server.mjs": "f4a3125c3ca4c43795d711705da14b05f064c08bf024bed16f706d8cf624de3e",
35
35
  "codex-images.mjs": "31605d6d8b3dd6b73395da63d1b0c513445c95ffa2f4306ee466f201d633ffc0",
36
36
  "codex-mcp-http.mjs": "7472543648a9bb575ce20dc3e3270c2da84174c6ea6e9faf87dfaafb95b6212a",
37
37
  "lane-worktree.mjs": "37583757ab82843412ba565dfba3d7cab517e94782eb33115decd5438d092d8f",
@@ -40,15 +40,15 @@
40
40
  "cumulative-event-relay.mjs": "cf6e6533e33b3c5bb0b462d15ccc86106f2b56f8b1e66fc1f4867dd8f44d7ae6",
41
41
  "codex-commands.mjs": "cae3f617ac42e1316d8980ef97e4255227fe5df5e8e9b556630a3bfb83bb7c2b",
42
42
  "acp-client.mjs": "9e7919ff79825883820019ff7a0ca578f120853ed61c7caab21a8ffc3a67ffc9",
43
- "hermes-session.mjs": "18cb3fc87338724abb75de2a7ebd8e53fa2902f995dca1f93d2f26b08f3cd331",
43
+ "hermes-session.mjs": "07cebfff03ba757a53117b868475bf6339b9bbe9f3c46f77ddad932220482d0b",
44
44
  "hermes-model-cache.mjs": "aee23efdebe1aa5e10053f291a9153981fe9b45065c293c9519ca73477251e72",
45
- "hermes-policy.mjs": "c0e59a65555c7ac25fdaacf6d72c9e8153803f9115eaaeb5ff802560f3a64cbc",
46
- "hermes-acp-bootstrap.py": "7c3c8114b1da3ea28320eaec9f9851b42d2359d76488e8dbf484871187c68850",
45
+ "hermes-policy.mjs": "8799ccd3851987b261cdcf18087b6a2ca95ba20367262a88a173494518dbe840",
46
+ "hermes-acp-bootstrap.py": "905604833e928c406a6cf4e20dd3c4745fa79108cfc2f48d8d32d0de918e6a29",
47
47
  "hermes-event-mapper.mjs": "7c714e15d06d970c4d602e755461bacf8f4d4136a8afc03406e8b3207ff84cdc",
48
- "hermes-probe.mjs": "935a80f2633afc4fb65d2610f662d650addde6b4086aaeac8bcbcf7932c26819",
49
- "hermes-setup.mjs": "3198a2a21282f4694c9ef3bc46e97fa4f467b721c525db0af584d50f34dd570c",
50
- "hermes-isolation.mjs": "ea9594480a8f470dc66bdcd1907b00c016f52398d9c39c8547cab95e5fb44f86",
51
- "hermes-delegation-guard.mjs": "4e6dd8d0cddefaddb30f83769acda72242c9b7242671f23ca2cb0c242dace178",
48
+ "hermes-probe.mjs": "b128dfaf3c7302d3d5372a16c0148a6de591768a9b7d1c306f0ae1d0a42198f7",
49
+ "hermes-setup.mjs": "1e903d0b9d3711669c06ff323323361920fe8827a7605311f74171f47eb6d602",
50
+ "hermes-isolation.mjs": "50e960ce815c520805245cc75719c9c53e2c5af51b7304c8ecef8a4946e23c6d",
51
+ "hermes-delegation-guard.mjs": "c2a6311320d2ff26137c4394c27561e5c8bee7a712bbb1188307bd55bfecc38e",
52
52
  "runtime-registry.mjs": "4606e104310a755be6a8c587e1050e8b0aa5efe56e7b71f9f13983f2685fc31b",
53
53
  "runtime-contract.mjs": "eb24b177002ba33353ec0335f4f830fb57fe313552b1a8d7aef8163cc743f6c1",
54
54
  "command-catalog.mjs": "8bdeba1dda874c68f4fa273cb03e6c634dfa22ffae88dec582398220ed2be8bf",
@@ -59,7 +59,7 @@
59
59
  "update-gate.mjs": "f223a82e72a2a33b48b8321b508e0965f9c705b5722a80a3c199ebd5cf2fcdcf",
60
60
  "agent-notify.mjs": "5950ba8928edb6e8d6091a0fdc8fb62cb21fcb79d864504e3b56e012a6f8339a",
61
61
  "agent-detect.mjs": "f38ede090e9caa8f7cde0febc41d9dc2c4301e1cd6017a07517b96364ebafb8c",
62
- "code-event-contract.mjs": "0a092608d85442064ed6b56cd28ea7b28d2cd49f37e8ea6bc5dc3adeb43be833",
62
+ "code-event-contract.mjs": "fc8672a77a7aadcee3817dea686b55d23e4a4160cab6623df1886cd5161d41e6",
63
63
  "evidence-compact.mjs": "f8175315f17b46a42f7b396f081374ff3d39ead94c18d64fccfa5fd02b6679f0",
64
64
  "evidence-citations.mjs": "865032925532c0f7a4b3f0ed484c85fa53237a7f46d79640714cd483b493b98d",
65
65
  "error-recovery.mjs": "0ace80add28fa72b49a3f3a716f247e3ef9816671c09749b3863867700beae32",
@@ -75,9 +75,9 @@
75
75
  "recap.mjs": "b2eee701ab8646007670514b08103e7b56b90eaa7d119e765b563a8ede87f85f",
76
76
  "transcript-sanitize.mjs": "c7f4718f25f97c05bc7b4ad8e09f18cbda152c53ad6593af1ab99f0c132dbf01",
77
77
  "session-store.mjs": "adeb5d7fe8b18b10e5c795877f797696bbb4f2f222916710173ada32bd433c1e",
78
- "side-lane.mjs": "e70871b0c3d0ef0037ffc85dcdda888984dc907e88a2506620cad0c3f76921bf",
79
- "worker-completion.mjs": "c456b78eed9847a31003937baa23f259e28b11209674402a462e20c59712a66c",
80
- "cross-terminal.mjs": "e1404c47bcd437cd32d5ed7766e1cab2a2e8a9d19e39f677bbc41afcc514edd1",
78
+ "side-lane.mjs": "306d451e2d163ecdf40030d886a338770b11bc57952543a107e422f95ca49d45",
79
+ "worker-completion.mjs": "7fad56bd9d3bb88f3e7bbeaa027508abad3465d3a33240cf82370104defad301",
80
+ "cross-terminal.mjs": "8dd07a9cde6f07f43a9d0c5be981bd61f9057558de2d30f3ee3981fb46fafc3f",
81
81
  "pair-bus.mjs": "cbc28cee7f4f06b2213091e0b7b07d61c1d01f0ff207c5c6d808cd616ece221e",
82
82
  "direct-pair-room.mjs": "92557b54307da2ca31f0a0d090e44b019a23b1ab32a7dfd6cbcb9d55fd761736",
83
83
  "lane-lifecycle.mjs": "9b5ae3d105c30e3ad37f1f1f792200da2dd4d2bb5c4979a2a69618373e58f1c8",
@@ -85,24 +85,24 @@
85
85
  "interrupted-resume.mjs": "df46a5fa07fad734dc3a56643aa44e24121e4afdd8206cc5e123102dad87f901",
86
86
  "dispatch-lease.mjs": "6e951cad5fb02999ac27e1cf03d9f932b079b2184853b8c6f9b5a8d579fcbbdd",
87
87
  "dispatch-permission-cleanup.mjs": "e9793c6f1aab616ad6cf0bf78cd68630428b511f1fdc5c66bb12c68a9932fe26",
88
- "flow-conductor.mjs": "a2b034a690e57869b3606cf61ae9029da422ed892032be7614bb76488a47da25",
88
+ "flow-conductor.mjs": "79e3f04fddc4ffa83dbda047a1e9bf01d73450079e9d63905a04f831261db543",
89
89
  "flow-worktree.mjs": "d9579a9b2eb8eff46c0708b2e3f546f5a6a3cded1ff726ab334cac9a48544e90",
90
90
  "flow-task-graph.mjs": "52f555219c6c940c5d33c6c429d132ab2ded46f9ac6d5207bd5ad972067493bf",
91
- "flow-models.mjs": "5796e23b8287d6b54bfe9dddfc30c9ef73d715dc322f54c73f2a30a523210021",
91
+ "flow-models.mjs": "735192dd2a67a1c790c77aa8e34b4e42817bef27da72853bad10941c65fccb86",
92
92
  "flow-host-revert.mjs": "a6da239fc54723c74ed51fc03ae3203458b92d2a2e33c26576a9e62cd1031fea",
93
93
  "flow-preview.mjs": "b4f1fb6aeed49623c0264ef47d02ec0b244c055ba4386f5ba4c1ffdcd02824c5",
94
94
  "mockup-delivery.mjs": "fa112408a186d856b343157381188dc18502aba6cf7ef365459f6c5a074e9cd6",
95
95
  "viewport.mjs": "80cb9b6e9275499397239a8b4288c0b49791886696a46917ac798acb75267ee5",
96
- "design-edit.mjs": "eeafab61056512338a18ed3f2e0339c9315f2fbf0d58456ffe9be08d77dd42b3",
96
+ "design-edit.mjs": "8e34351dcad2bea3e3ee1b0e57bdd28aeb047ac2e2b3f30c0d86dc1fd3575561",
97
97
  "design-source-contract.mjs": "18bcd024b317293e445c433fc9c59f9eb85e8fb3fa4de824b82604bbae4687b8",
98
- "flow-review.mjs": "3d53a8a385dd1360d23c994847a7a3186e93df4a455c8dded1cffeeedbbac378",
98
+ "flow-review.mjs": "9d64fb9e95cd685559df20f1fc778de10c9e02fb0e662ae37699e26c632d0a40",
99
99
  "flow-receipt.mjs": "9fc2804b0a6940d605449818d69f46f19fa2d83dbe6ba29caeaaf0b6694e86aa",
100
100
  "flow-scope-evidence.mjs": "37983eeee599380d47ef7dacc5d22349ce45dea712442e822c896f9cec9450fc",
101
101
  "past-work-search.mjs": "766f4e669364bd9c3c3667135c502719dbbaf550bf074bda4394ab106f33f415",
102
102
  "review-check.mjs": "e16c45fcbbe731b67c5aa1796daffc711e4a5734dbedda282a5e01db0602722e",
103
103
  "flow-review-gate.mjs": "0ef351065269bf2cc6112707064024cf2b916890a80fb94404ebca3a7905754b",
104
104
  "flow-review-reflect.mjs": "61b39e32ad21501b76c1d9267dd5cdf35017afe7e1333b305e72392bc0304628",
105
- "flow-assembly.mjs": "3535203e1ad75fb326db5212c2f013ab6c0049e31bc0ba59813c7d0ef1956d03",
105
+ "flow-assembly.mjs": "5241097f9084d77fdb72f34b41681e03d063c513d126907f5cbb9becb7972e2c",
106
106
  "flow-budget.mjs": "d406ecbdd5d4acc08c60c641d7ad12553675cf4bbf35a9600bc96300c1af3404",
107
107
  "flow-context-store.mjs": "949c20aeac1984d265f0445547a7d248565e61270cf9fed509047a1dd2c44f02",
108
108
  "flow-redispatch.mjs": "4fa3bf3dd9461fa1c447d12b5db5a0f1befb3427abaed1ee1cec86134ad3eb95",
@@ -112,10 +112,10 @@
112
112
  "reap-terminal.mjs": "76d6ed14316d26d0d8b246d54cfdbde1f246badee91524b4caca8151f1440ccd",
113
113
  "terminal-row-reconcile.mjs": "b6f4022f03d908445f404ca1f8479c780ed645bf855428a2726ac2db682ab4ed",
114
114
  "switch-provider.mjs": "9805d59df49e1272ffd5ef7e3d2260f6e93c76d32265b78e461287ef500f5b71",
115
- "service.mjs": "4d649a995d8fee138d9714dcfd41fdcfee5b5148e6b2b0328dd31a797cc134fc",
115
+ "service.mjs": "412ee48ad7b1dd281063f30f2519b077aa4cc92305e6780ac226293756f6e6f8",
116
116
  "supervisor-ready.mjs": "7d5e4ebe3c7a93e0888dd335fb4556a670e55a80a89b861c8a44feac159cd840",
117
117
  "presence.mjs": "2516ebb4474a8f45dd881530335c2174af9cde44be8eed6896ff8c62497b6e2b",
118
- "account.mjs": "a8bc640fe66b179777597477899ec4eb82460f602d637ca477ab76eb682eb233",
118
+ "account.mjs": "55a6df0bfd25ced5c800211c6b305879859bc3421d8ecade87aa647332678506",
119
119
  "auth-store.mjs": "c4d41ee7cdc34c2002c6dd50d32e53ace0a3f03a116ffa930ed94a437e247625",
120
120
  "key-shape.mjs": "a4113293d52eeba39b05e70a3e0345abc1ddc181b4f236b413bde0ae11a3f646",
121
121
  "supabase-key.mjs": "041bde6cf50b15f6426daaf738374abc9647861d8c1dd3d85cedc45684271888",
@@ -123,7 +123,7 @@
123
123
  "providers.mjs": "c0757433d30bf2f22e80f85e779cdeeeb10b412d568965f1115d4de2c8aa0314",
124
124
  "provider-resilience.mjs": "a5a3921040d1860bb82f1d3b53c6ec25a5e230345c0131f2213c535e07fc497e",
125
125
  "model-prices.mjs": "91f0bd8688f59ce6bff7743710d3b1139f4f0823d6b95fa68cd9b6fdcdba6ab4",
126
- "README.md": "b801ce3677409cd8f99dacef2f5a9d69487db6d3146d41381c70b82f5d04eed4",
126
+ "README.md": "203720616675733bc3032b7399b2e057763ec593dba4beabd1a2042f824400fb",
127
127
  "publish-guard.mjs": "569dd788790e68ea822129f588fd16c1bb435324666552fe9dfe7c435ab3f617"
128
128
  }
129
129
  }
package/service.mjs CHANGED
@@ -1 +1 @@
1
- import e from"node:os";import t from"node:fs";import r from"node:path";import{execSync as n}from"node:child_process";import{hostMemoryAdmission as i}from"./host-memory.mjs";import{readSupervisorReady as o,supervisorReadyMatches as s}from"./supervisor-ready.mjs";import{pairCli as a}from"./command-guidance.mjs";import{loadKeepAwakePreference as l}from"./keep-awake.mjs";import{scheduledRunsEnabled as c}from"./scheduled-runs.mjs";const d=/^[A-Za-z0-9]{2,16}$/,p=e=>{if(e&&!d.test(e))throw new Error(`invalid room code: ${JSON.stringify(e)} (expected 2–16 alphanumerics)`);return e?`io.thinkpool.pair.${e.toLowerCase()}`:"io.thinkpool.pair.account"},u=e=>e||"account",f=e=>String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;"),$=e=>`'${String(e).replace(/'/g,"'\\''")}'`;export function sanitizeServicePath(e,t=process.platform){const r="win32"===t?";":":";return String(e||"").split(r).filter(e=>e&&!e.includes("/.npm/_npx/")).join(r)}export function darwinServiceRunning(e){const t=String(e||"");return/(^|\n)[ \t]*state = running[ \t]*($|\n)/.test(t)&&/(^|\n)[ \t]*pid = \d+[ \t]*($|\n)/.test(t)}const h=e=>`rm -rf ${$(r.join(e,"_npx"))}/* 2>/dev/null`,m=(()=>{try{return JSON.parse(t.readFileSync(new URL("./package.json",import.meta.url),"utf8")).version}catch{return"latest"}})();function g(e){try{const n=JSON.parse(t.readFileSync(r.join(r.dirname(e),"package.json"),"utf8"));return"string"==typeof n?.version?n.version:null}catch{return null}}export function provisionRuntime(o,{exec:s=n,root:a=r.join(e.homedir(),".thinkpool-pair","runtimes"),admit:l=i}={}){if(!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(String(o)))throw new Error(`invalid runtime version: ${o}`);const c=r.join(a,String(o)),d=r.join(c,"node_modules","thinkpool-pair","bridge.mjs");if(t.existsSync(d)&&g(d)===String(o))return d;const p=l("stage a bridge runtime update");if(!p?.ok)throw new Error(p?.reason||"host memory is critically low");const u=`${c}.install-${process.pid}-${Date.now()}`;t.rmSync(u,{recursive:!0,force:!0}),t.mkdirSync(u,{recursive:!0});const f=`https://registry.npmjs.org/thinkpool-pair/-/thinkpool-pair-${o}.tgz`,h=r.join(u,"node_modules","thinkpool-pair","bridge.mjs");try{s(`${$(function(e=process.platform){const n=r.dirname(process.execPath),i=r.join(n,"win32"===e?"npm.cmd":"npm");try{return t.accessSync(i),i}catch{return"win32"===e?"npm.cmd":"npm"}}())} install --prefix ${$(u)} ${$(f)} --prefer-online --no-audit --no-fund`,{stdio:"inherit",shell:"/bin/bash"});const e=g(h);if(!t.existsSync(h)||e!==String(o))throw new Error(`runtime verification failed: requested ${o}, installed ${e||"no valid package"}`);t.rmSync(c,{recursive:!0,force:!0}),t.renameSync(u,c)}catch(e){throw t.rmSync(u,{recursive:!0,force:!0}),e}return d}export function buildArtifact(n,{room:i=null,cmdArgs:o=[],autoUpdate:s=!1,version:a=m,staleProof:l=!1,runtimeEntry:d=null,scheduledRuns:g=c()}={}){const v=function(e){const n=r.dirname(process.execPath),i=r.join(n,"win32"===e?"npx.cmd":"npx");try{return t.accessSync(i),i}catch{return"win32"===e?"npx.cmd":"npx"}}(n),y=i?process.cwd():e.homedir(),k=u(i),b=r.join(e.homedir(),".thinkpool-pair"),w=r.join(b,`${k}.log`),S=sanitizeServicePath(process.env.PATH||"",n),_=r.join(e.homedir(),".thinkpool-pair","npm-cache"),x=o.length?["--",...o]:[],A=i?`bridge (${i})`:"account bridge",P=s?"thinkpool-pair@latest":`thinkpool-pair@${a}`,j=s||l?["--prefer-online"]:[],E=i?["-y",...j,P,i]:["-y",...j,P],F=!0===g?{darwin:"<key>TP_SCHEDULED_RUNS_ENABLED</key><string>1</string>",linux:"Environment=TP_SCHEDULED_RUNS_ENABLED=1\n",win32:'set "TP_SCHEDULED_RUNS_ENABLED=1"\r\n'}:{darwin:"",linux:"",win32:""};if("darwin"===n){const t=d?[process.execPath,d,...i?[i]:[],...x]:l?["/bin/bash","-lc",`${h(_)}; export NPM_CONFIG_CACHE=${$(_)}; exec ${[v,...E,...x].map($).join(" ")}`]:[v,...E,...x];return{file:r.join(e.homedir(),"Library","LaunchAgents",`${p(i)}.plist`),content:`<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0"><dict>\n <key>Label</key><string>${p(i)}</string>\n <key>ProgramArguments</key><array>${t.map(e=>`<string>${f(e)}</string>`).join("")}</array>\n <key>RunAtLoad</key><true/>\n \x3c!-- KeepAlive only on UNSUCCESSFUL exit. A bridge that exits 0 has intentionally\n stood down — told to stop, or another bridge already owns this machine's\n singleton lock — and must NOT be relaunched, or launchd thrashes it every\n few seconds forever (the 2026-06-28 account-bridge restart loop). A crash\n or an update-restart exits non-zero and IS relaunched. Mirrors the bridge's\n own exit-code contract (stop()=0, restart-requested=non-zero). --\x3e\n <key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>\n <key>WorkingDirectory</key><string>${f(y)}</string>\n <key>StandardOutPath</key><string>${f(w)}</string>\n <key>StandardErrorPath</key><string>${f(w)}</string>\n <key>EnvironmentVariables</key><dict><key>PATH</key><string>${f(S)}</string>${d?"":`<key>NPM_CONFIG_CACHE</key><string>${f(_)}</string>`}${s?"<key>THINKPOOL_PAIR_AUTOUPDATE</key><string>1</string>":""}${F.darwin}</dict>\n</dict></plist>\n`,logDir:b,post:[],expectedRuntime:d||P,note:"Loaded as a LaunchAgent — starts at login, restarts on crash."}}if("linux"===n){const t=d?[process.execPath,d,...i?[i]:[],...x]:[v,...E,...x];return{file:r.join(e.homedir(),".config","systemd","user",`${p(i)}.service`),content:`[Unit]\nDescription=ThinkPool Code ${A}\nAfter=network-online.target\n\n[Service]\nExecStart=${d?t.map(e=>`'${e.replace(/'/g,"'\\''")}'`).join(" "):l?`/bin/bash -lc "${h(_)}; export NPM_CONFIG_CACHE=${$(_)}; exec ${[v,...E,...x].join(" ")}"`:t.map(e=>`'${e.replace(/'/g,"'\\''")}'`).join(" ")}\nRestart=always\nRestartSec=2\n# Don't relaunch a clean stand-down. exit 0 = the bridge intentionally stopped —\n# told to stop, or another bridge already holds this machine's singleton lock —\n# so restarting it just thrashes every RestartSec forever (the 2026-06-28\n# account-bridge restart loop). Crashes + update-restarts exit non-zero and are\n# still restarted. Matches the bridge's exit-code contract (stop()=0, restart=non-zero).\nRestartPreventExitStatus=0\nWorkingDirectory=${y}\nEnvironment=PATH=${S}\n${d?"":`Environment=NPM_CONFIG_CACHE=${_}\n`}${s?"Environment=THINKPOOL_PAIR_AUTOUPDATE=1\n":""}${F.linux}StandardOutput=append:${w}\nStandardError=append:${w}\n\n[Install]\nWantedBy=default.target\n`,logDir:b,post:["systemctl --user daemon-reload",`systemctl --user enable ${p(i)}.service`,`systemctl --user restart ${p(i)}.service`],expectedRuntime:d||P,note:"Enabled as a systemd --user service. Run `loginctl enable-linger $USER` once to keep it running after logout."}}if("win32"===n){const t=r.join(process.env.APPDATA||r.join(e.homedir(),"AppData","Roaming"),"Microsoft","Windows","Start Menu","Programs","Startup"),n=r.join(t,`thinkpool-pair-${k}.cmd`),o=d?[process.execPath,d,...i?[i,"--supervise"]:[],...x].map(e=>`"${e}"`).join(" "):i?["npx","-y",...j,P,i,"--supervise",...x].join(" "):["npx","-y",...j,P].join(" ");return{file:n,content:`@echo off\r\ntitle thinkpool-pair ${k}\r\n${d?"":`set "NPM_CONFIG_CACHE=${_}"\r\n`}${F.win32}${o}\r\n`,logDir:b,post:[],note:"Installed to the Startup folder — runs at login"+(i?" with --supervise (auto-restart on crash).":" (account mode).")+" Start it now without rebooting by double-clicking the .cmd, or run it from a terminal."}}throw new Error(`unsupported platform: ${n}`)}export function parseRunningPairVersions(e){const t=String(e).match(/(?:thinkpool-pair@|runtimes[\\/])(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/g)||[];return new Set(t.map(e=>e.match(/\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?/)?.[0]).filter(Boolean))}export function serviceRuntimeSnapshot(e,{platform:t=process.platform,exec:r=n}={}){const i=e=>{const t=parseRunningPairVersions(e);return 1===t.size?[...t][0]:null},o=p(e);try{if("darwin"===t){const e=r(`launchctl print gui/$(id -u)/${o}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"],shell:"/bin/bash"}),t=String(e).match(/(^|\n)[ \t]*pid = (\d+)[ \t]*($|\n)/)?.[2];return darwinServiceRunning(e)?{version:i(e),pid:t||null}:null}if("linux"===t){const e=r(`systemctl --user show ${o}.service --property=ActiveState --property=MainPID --property=ExecStart`,{encoding:"utf8",stdio:["ignore","pipe","ignore"]}),t=String(e).match(/^MainPID=([1-9]\d*)$/m)?.[1];return/^ActiveState=active$/m.test(String(e))&&t?{version:i(e),pid:t}:null}}catch{}return null}export function serviceRuntimeVersion(e,t){return serviceRuntimeSnapshot(e,t)?.version||null}export function buildDarwinReloadHandoff({targetLabel:t,targetFile:n,stagedFile:i,expectedRuntime:o,version:s,nonce:a=`${process.pid}-${Date.now()}`}){if(!/^io\.thinkpool\.pair\.[A-Za-z0-9_.-]+$/.test(String(t)))throw new Error(`invalid service label: ${t}`);if(!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(String(s)))throw new Error(`invalid runtime version: ${s}`);const l=`io.thinkpool.pair.update.${String(a).replace(/[^A-Za-z0-9-]/g,"")||String(process.pid)}`,c=r.join(e.homedir(),"Library","LaunchAgents",`${l}.plist`),d=`${i}.previous`,u=r.join(e.homedir(),".thinkpool-pair","update-status.json"),h=r.join(e.homedir(),".thinkpool-pair","update.log"),m=r.join(e.homedir(),".thinkpool-pair","account-ready.json"),g=t===p(null),v=["set -u",'dom="gui/$(id -u)"',`target=${$(t)}`,`helper=${$(l)}`,`target_file=${$(n)}`,`staged_file=${$(i)}`,`backup_file=${$(d)}`,`helper_file=${$(c)}`,`expected=${$(o)}`,`version=${$(s)}`,`status=${$(u)}`,`ready=${$(m)}`,"requires_ready="+(g?"1":"0"),'tmp="$status.tmp.$$"',"ok=0",'live_pid=""',"stable=0","had_previous=0",'if [ -f "$target_file" ]; then cp "$target_file" "$backup_file" && had_previous=1; fi','launchctl bootout "$dom/$target" 2>/dev/null || true','for i in $(seq 1 40); do launchctl print "$dom/$target" >/dev/null 2>&1 || break; sleep 0.2; done','if [ "$requires_ready" = 1 ]; then rm -f "$ready"; fi','cp "$staged_file" "$target_file"','launchctl enable "$dom/$target" 2>/dev/null || true','for i in $(seq 1 30); do launchctl bootstrap "$dom" "$target_file" 2>/dev/null && break; sleep 0.3; done','printf "update_handoff_start target=%s version=%s timeout_s=90\\n" "$target" "$version"','for i in $(seq 1 180); do snapshot="$(launchctl print "$dom/$target" 2>/dev/null || true)"; pid="$(printf "%s\\n" "$snapshot" | sed -n "s/^[[:space:]]*pid = \\([0-9][0-9]*\\)[[:space:]]*$/\\1/p" | head -1)"; ready_ok=1; if [ "$requires_ready" = 1 ]; then ready_ok=0; [ -f "$ready" ] && grep -F "\\"pid\\":$pid" "$ready" >/dev/null 2>&1 && grep -F "\\"version\\":\\"$version\\"" "$ready" >/dev/null 2>&1 && ready_ok=1; fi; if [ -n "$pid" ] && [ "$ready_ok" = 1 ] && printf "%s\\n" "$snapshot" | grep -F -- "$expected" >/dev/null && printf "%s\\n" "$snapshot" | grep -F "state = running" >/dev/null; then if [ "$pid" = "$live_pid" ]; then stable=$((stable+1)); else live_pid="$pid"; stable=1; fi; if [ "$stable" -ge 5 ]; then ok=1; break; fi; else live_pid=""; stable=0; fi; sleep 0.5; done','if [ "$ok" != 1 ]; then ready_state=missing; [ -f "$ready" ] && ready_state=present; printf "update_handoff_verify_timeout target=%s version=%s last_pid=%s ready=%s\\n" "$target" "$version" "$live_pid" "$ready_state"; fi',`if [ "$ok" = 1 ]; then printf '%s\\n' '${JSON.stringify({ok:!0,version:String(s),target:String(t)})}' > "$tmp"; else rollback=0; if [ "$had_previous" = 1 ]; then launchctl bootout "$dom/$target" 2>/dev/null || true; for i in $(seq 1 40); do launchctl print "$dom/$target" >/dev/null 2>&1 || break; sleep 0.2; done; if [ "$requires_ready" = 1 ]; then rm -f "$ready"; fi; cp "$backup_file" "$target_file"; launchctl enable "$dom/$target" 2>/dev/null || true; bootstrapped=0; for i in $(seq 1 30); do if launchctl bootstrap "$dom" "$target_file" 2>/dev/null; then bootstrapped=1; break; fi; sleep 0.3; done; if [ "$bootstrapped" = 1 ]; then rollback_pid=""; rollback_stable=0; for i in $(seq 1 180); do snapshot="$(launchctl print "$dom/$target" 2>/dev/null || true)"; pid="$(printf "%s\\n" "$snapshot" | sed -n "s/^[[:space:]]*pid = \\([0-9][0-9]*\\)[[:space:]]*$/\\1/p" | head -1)"; ready_ok=1; if [ "$requires_ready" = 1 ]; then ready_ok=0; [ -f "$ready" ] && grep -F "\\"pid\\":$pid" "$ready" >/dev/null 2>&1 && ready_ok=1; fi; if [ -n "$pid" ] && [ "$ready_ok" = 1 ] && printf "%s\\n" "$snapshot" | grep -F "state = running" >/dev/null; then if [ "$pid" = "$rollback_pid" ]; then rollback_stable=$((rollback_stable+1)); else rollback_pid="$pid"; rollback_stable=1; fi; if [ "$rollback_stable" -ge 5 ]; then rollback=1; break; fi; else rollback_pid=""; rollback_stable=0; fi; sleep 0.5; done; fi; else launchctl bootout "$dom/$target" 2>/dev/null || true; rm -f "$target_file"; fi; if [ "$rollback" = 1 ]; then printf '%s\\n' '${JSON.stringify({ok:!1,version:String(s),target:String(t),error:"new runtime not confirmed within 90s; previous service restored and ready",rolledBack:!0})}' > "$tmp"; else printf '%s\\n' '${JSON.stringify({ok:!1,version:String(s),target:String(t),error:"new runtime not confirmed within 90s and ready rollback failed",rolledBack:!1})}' > "$tmp"; fi; fi`,'printf "update_handoff_complete target=%s version=%s ok=%s\\n" "$target" "$version" "$ok"','mv "$tmp" "$status"','rm -f "$staged_file" "$backup_file" "$helper_file"','launchctl bootout "$dom/$helper" >/dev/null 2>&1 || true','exit "$((1-ok))"'].join("; ");return{helperLabel:l,helperFile:c,backupFile:d,statusFile:u,logFile:h,script:v,content:`<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0"><dict>\n <key>Label</key><string>${f(l)}</string>\n <key>ProgramArguments</key><array><string>/bin/bash</string><string>-lc</string><string>${f(v)}</string></array>\n <key>RunAtLoad</key><true/>\n <key>StandardOutPath</key><string>${f(h)}</string>\n <key>StandardErrorPath</key><string>${f(h)}</string>\n</dict></plist>\n`}}export function buildLinuxReloadHandoff({targetLabel:t,targetFile:n,stagedFile:i,expectedRuntime:o,version:s,nonce:a=`${process.pid}-${Date.now()}`}){if(!/^io\.thinkpool\.pair\.[A-Za-z0-9_.-]+$/.test(String(t)))throw new Error(`invalid service label: ${t}`);if(!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(String(s)))throw new Error(`invalid runtime version: ${s}`);const l=`io.thinkpool.pair.update.${String(a).replace(/[^A-Za-z0-9-]/g,"")||String(process.pid)}`,c=`${i}.previous`,d=r.join(e.homedir(),".thinkpool-pair","update-status.json"),u=r.join(e.homedir(),".thinkpool-pair","update.log"),f=r.join(e.homedir(),".thinkpool-pair","account-ready.json"),h=t===p(null);return{helperLabel:l,backupFile:c,statusFile:d,logFile:u,script:["set -u",`target=${$(t)}`,'unit="$target.service"',`target_file=${$(n)}`,`staged_file=${$(i)}`,`backup_file=${$(c)}`,`expected=${$(o)}`,`version=${$(s)}`,`status=${$(d)}`,`ready=${$(f)}`,"requires_ready="+(h?"1":"0"),'tmp="$status.tmp.$$"',"ok=0","had_previous=0",'if [ -f "$target_file" ]; then cp "$target_file" "$backup_file" && had_previous=1; fi','systemctl --user stop "$unit" 2>/dev/null || true','if [ "$requires_ready" = 1 ]; then rm -f "$ready"; fi','cp "$staged_file" "$target_file"',"systemctl --user daemon-reload",'systemctl --user enable "$unit" >/dev/null 2>&1 || true','systemctl --user restart "$unit" >/dev/null 2>&1 || true','live_pid=""',"stable=0",'printf "update_handoff_start target=%s version=%s timeout_s=90\\n" "$target" "$version"','for i in $(seq 1 180); do snapshot="$(systemctl --user show "$unit" --property=ActiveState --property=MainPID --property=ExecStart 2>/dev/null || true)"; pid="$(printf "%s\\n" "$snapshot" | sed -n "s/^MainPID=\\([1-9][0-9]*\\)$/\\1/p" | head -1)"; ready_ok=1; if [ "$requires_ready" = 1 ]; then ready_ok=0; [ -f "$ready" ] && grep -F "\\"pid\\":$pid" "$ready" >/dev/null 2>&1 && grep -F "\\"version\\":\\"$version\\"" "$ready" >/dev/null 2>&1 && ready_ok=1; fi; if [ -n "$pid" ] && [ "$ready_ok" = 1 ] && printf "%s\\n" "$snapshot" | grep -F "ActiveState=active" >/dev/null && printf "%s\\n" "$snapshot" | grep -F -- "$expected" >/dev/null; then if [ "$pid" = "$live_pid" ]; then stable=$((stable+1)); else live_pid="$pid"; stable=1; fi; if [ "$stable" -ge 5 ]; then ok=1; break; fi; else live_pid=""; stable=0; fi; sleep 0.5; done','if [ "$ok" != 1 ]; then ready_state=missing; [ -f "$ready" ] && ready_state=present; printf "update_handoff_verify_timeout target=%s version=%s last_pid=%s ready=%s\\n" "$target" "$version" "$live_pid" "$ready_state"; fi',`if [ "$ok" = 1 ]; then printf '%s\\n' '${JSON.stringify({ok:!0,version:String(s),target:String(t)})}' > "$tmp"; else rollback=0; if [ "$had_previous" = 1 ]; then systemctl --user stop "$unit" 2>/dev/null || true; if [ "$requires_ready" = 1 ]; then rm -f "$ready"; fi; cp "$backup_file" "$target_file"; systemctl --user daemon-reload; systemctl --user enable "$unit" >/dev/null 2>&1 || true; systemctl --user restart "$unit" >/dev/null 2>&1 || true; rollback_pid=""; rollback_stable=0; for i in $(seq 1 180); do snapshot="$(systemctl --user show "$unit" --property=ActiveState --property=MainPID 2>/dev/null || true)"; pid="$(printf "%s\\n" "$snapshot" | sed -n "s/^MainPID=\\([1-9][0-9]*\\)$/\\1/p" | head -1)"; ready_ok=1; if [ "$requires_ready" = 1 ]; then ready_ok=0; [ -f "$ready" ] && grep -F "\\"pid\\":$pid" "$ready" >/dev/null 2>&1 && ready_ok=1; fi; if [ -n "$pid" ] && [ "$ready_ok" = 1 ] && printf "%s\\n" "$snapshot" | grep -F "ActiveState=active" >/dev/null; then if [ "$pid" = "$rollback_pid" ]; then rollback_stable=$((rollback_stable+1)); else rollback_pid="$pid"; rollback_stable=1; fi; if [ "$rollback_stable" -ge 5 ]; then rollback=1; break; fi; else rollback_pid=""; rollback_stable=0; fi; sleep 0.5; done; else systemctl --user stop "$unit" 2>/dev/null || true; rm -f "$target_file"; systemctl --user daemon-reload; fi; if [ "$rollback" = 1 ]; then printf '%s\\n' '${JSON.stringify({ok:!1,version:String(s),target:String(t),error:"new runtime not confirmed within 90s; previous service restored and ready",rolledBack:!0})}' > "$tmp"; else printf '%s\\n' '${JSON.stringify({ok:!1,version:String(s),target:String(t),error:"new runtime not confirmed within 90s and ready rollback failed",rolledBack:!1})}' > "$tmp"; fi; fi`,'printf "update_handoff_complete target=%s version=%s ok=%s\\n" "$target" "$version" "$ok"','mv "$tmp" "$status"','rm -f "$staged_file" "$backup_file"','exit "$((1-ok))"'].join("; ")}}const v=()=>r.join(e.homedir(),".thinkpool-pair","account.lock"),y=e=>{try{return process.kill(e,0),!0}catch(e){return"EPERM"===e?.code}};export async function retireUnmanagedBridgeLock({lockFile:e=v(),readLock:r=()=>t.readFileSync(e,"utf8"),removeLock:i=()=>t.rmSync(e,{force:!0}),commandForPid:o=e=>String(n(`ps -p ${e} -o command=`,{encoding:"utf8",stdio:["ignore","pipe","ignore"]})),alive:s=y,signal:a=(e,t)=>process.kill(e,t),sleep:l=e=>new Promise(t=>setTimeout(t,e)),waitMs:c=2500,pollMs:d=100,stderr:p=process.stderr}={}){let u=0;try{u=parseInt(String(r()).trim(),10)||0}catch{return!0}const f=()=>{if(s(u))return!1;try{(parseInt(String(r()).trim(),10)||0)===u&&i()}catch{}return!0};if(!u||u===process.pid||f())return!0;let $="";try{$=o(u)}catch{return f()}if(!/(?:node_modules[\\/]thinkpool-pair|\.npm[\\/]_npx|\.thinkpool-pair[\\/]runtimes)[\\/][^\n]*bridge\.mjs(?:\s|$)/.test($))return p.write(` ⚠ account.lock belongs to PID ${u}, but it is not a verified thinkpool-pair bridge; refusing to signal an unrelated process.\n`),!1;p.write(` ◆ stopping previous thinkpool-pair bridge (PID ${u}) before installing the background service…\n`);try{a(u,"SIGTERM")}catch{if(f())return!0}const h=Math.max(1,Math.ceil(Math.max(0,Number(c)||0)/Math.max(1,Number(d)||1)));for(let e=0;e<h;e++){if(f())return!0;await l(Math.max(1,Number(d)||1))}try{a(u,"SIGKILL")}catch{}for(let e=0;e<5;e++){if(f())return!0;await l(Math.max(1,Number(d)||1))}return p.write(` ⚠ previous thinkpool-pair bridge PID ${u} did not stop; background install aborted to avoid two competing bridges.\n`),!1}function k(e){const t=r.basename(e).match(/^(io\.thinkpool\.pair\.[A-Za-z0-9_.-]+)\.(?:plist|service)$/);if(!t)throw new Error(`cannot derive service label from ${e}`);return t[1]}export function existingServiceLabels(i=process.platform,{fsMod:o=t}={}){const s=new Set;try{if("darwin"===i){try{const e=n("launchctl print gui/$(id -u) 2>/dev/null | grep -oE 'io\\.thinkpool\\.pair\\.[A-Za-z0-9_]+' | sort -u",{encoding:"utf8",shell:"/bin/bash"});for(const t of e.split("\n")){const e=t.trim();e&&s.add(e)}}catch{}try{const t=r.join(e.homedir(),"Library","LaunchAgents");for(const e of o.readdirSync(t)){const t=e.match(/^(io\.thinkpool\.pair\.[A-Za-z0-9_]+)\.plist$/);t&&s.add(t[1])}}catch{}}else if("linux"===i){try{const e=n("systemctl --user list-unit-files 'io.thinkpool.pair.*' --no-legend 2>/dev/null | awk '{print $1}'",{encoding:"utf8",shell:"/bin/bash"});for(const t of e.split("\n")){const e=t.trim().replace(/\.service$/,"");e&&s.add(e)}}catch{}try{const t=r.join(e.homedir(),".config","systemd","user");for(const e of o.readdirSync(t)){const t=e.match(/^(io\.thinkpool\.pair\.[A-Za-z0-9_]+)\.service$/);t&&s.add(t[1])}}catch{}}}catch{}return[...s]}export function sweepExistingServices(i,o=process.platform){for(const s of existingServiceLabels(o))if(s!==i)try{if("darwin"===o){n(`launchctl bootout gui/$(id -u)/${s} 2>/dev/null || true`,{stdio:"ignore",shell:"/bin/bash"});try{t.rmSync(r.join(e.homedir(),"Library","LaunchAgents",`${s}.plist`),{force:!0})}catch{}}else"linux"===o&&n(`systemctl --user disable --now ${s}.service 2>/dev/null || true`,{stdio:"ignore",shell:"/bin/bash"});process.stderr.write(` ◆ swept stale service ${s}\n`)}catch{}if("win32"!==o)try{n("pkill -9 -f 'thinkpool-pair/bridge.mjs [A-Z0-9]' 2>/dev/null || true",{stdio:"ignore",shell:"/bin/bash"})}catch{}}export function installService(e,i=[],{autoUpdate:o=!1,version:s=m,staleProof:c=!0}={}){let d=null;if(!o)try{d=provisionRuntime(s)}catch(e){return process.stderr.write(` ⚠ runtime install failed; service left unchanged: ${e.message}\n`),!1}const f=buildArtifact(process.platform,{room:e,cmdArgs:i,autoUpdate:o,version:s,staleProof:c,runtimeEntry:d});try{sweepExistingServices(p(e),process.platform)}catch{}if(t.mkdirSync(f.logDir,{recursive:!0}),t.mkdirSync(r.dirname(f.file),{recursive:!0}),"darwin"===process.platform){if(process.stderr.write(`\n ◆ staged replacement for ${f.file}\n`),!function(e,i){const o=r.join(e.logDir,`service-update-${process.pid}-${Date.now()}.plist`),s=buildDarwinReloadHandoff({targetLabel:k(e.file),targetFile:e.file,stagedFile:o,expectedRuntime:e.expectedRuntime,version:i});t.mkdirSync(r.dirname(s.helperFile),{recursive:!0}),t.mkdirSync(r.dirname(s.statusFile),{recursive:!0}),t.rmSync(s.statusFile,{force:!0}),t.writeFileSync(o,e.content),t.writeFileSync(s.helperFile,s.content);try{return n(`launchctl bootstrap gui/$(id -u) ${$(s.helperFile)}`,{stdio:"inherit",shell:"/bin/bash"}),process.stderr.write(` ◆ update handoff armed outside the bridge process tree — completion is recorded in ${s.statusFile}.\n`),!0}catch(e){return t.rmSync(o,{force:!0}),t.rmSync(s.helperFile,{force:!0}),process.stderr.write(` ⚠ could not arm the launchd update handoff; existing service left running: ${e.message}\n`),!1}}(f,s))return!1}else if("linux"===process.platform){if(process.stderr.write(`\n ◆ staged replacement for ${f.file}\n`),!function(e,i){const o=r.join(e.logDir,`service-update-${process.pid}-${Date.now()}.service`),s=buildLinuxReloadHandoff({targetLabel:k(e.file),targetFile:e.file,stagedFile:o,expectedRuntime:e.expectedRuntime,version:i});t.mkdirSync(r.dirname(s.statusFile),{recursive:!0}),t.rmSync(s.statusFile,{force:!0}),t.writeFileSync(o,e.content);try{return n(`systemd-run --user --unit=${$(s.helperLabel)} --collect --property=StandardOutput=append:${$(s.logFile)} --property=StandardError=append:${$(s.logFile)} /bin/bash -lc ${$(s.script)}`,{stdio:"inherit",shell:"/bin/bash"}),process.stderr.write(` ◆ update handoff armed outside the bridge service cgroup — completion is recorded in ${s.statusFile}.\n`),!0}catch(e){return t.rmSync(o,{force:!0}),process.stderr.write(` ⚠ could not arm the systemd update handoff; existing service left running: ${e.message}\n`),!1}}(f,s))return!1}else{t.writeFileSync(f.file,f.content),process.stderr.write(`\n ◆ wrote ${f.file}\n`);for(const e of f.post)try{n(e,{stdio:"inherit"})}catch(t){return process.stderr.write(` ⚠ "${e}" failed; service update NOT confirmed: ${t.message}\n`),!1}}const h=Math.max(10,parseInt(process.env.THINKPOOL_PAIR_UPDATE_IDLE,10)||90),g=o?"win32"===process.platform?"auto-update ON: a new thinkpool-pair@latest applies on the next login/restart (Windows has no in-process self-update).":`auto-update ON: checks npm ~every 30 min and restarts to apply a new @latest once sessions are idle (≥${h}s quiet; they resume in place).`:`PINNED to ${s} (stable local runtime; restarts do not depend on npx or the network). To update: use "Restart & update the bridge" (or run ${a("install-service",e||void 0)}). Pass --auto-update to track @latest instead.`,v=e?` ${e}`:"",y=e?`room ${e}`:"your account (auto-serves every session)",b=l()?" ◆ Keep-awake on: system sleep is inhibited while the bridge runs (higher battery use); the display may still dim, lock, and turn off.\n":"";return process.stderr.write(` ◆ ${y}\n ◆ ${"darwin"===process.platform?"Launchd is completing and verifying the reload independently.":f.note}\n ◆ Prerequisite: Claude Code, Codex, or Hermes must be installed on this machine. BYOK supplies model credentials; it does not install an agent.\n${b} ◆ ${g}\n ◆ logs: ${r.join(f.logDir,`${u(e)}.log`)}\n ◆ remove with: ${a("uninstall-service")}${v}\n\n`),!0}export async function installAndConfirmService(i,a=[],{platform:l=process.platform,version:c=m,staleProof:d=!0,install:u=installService,exec:f=n,snapshot:$=serviceRuntimeSnapshot,prepareAccountHandoff:h=retireUnmanagedBridgeLock,readReady:g=()=>o(),readStatus:v=()=>{try{return JSON.parse(t.readFileSync(r.join(e.homedir(),".thinkpool-pair","update-status.json"),"utf8"))}catch{return null}},now:y=Date.now,sleep:k=e=>new Promise(t=>setTimeout(t,e)),timeoutMs:b=2e5,pollMs:w=250,stderr:S=process.stderr}={}){const _=$(i,{platform:l,exec:f});if(!i&&"win32"!==l&&!_&&!await h())return S.write(" ⚠ background install aborted: the previous bridge could not be handed off safely.\n"),!1;const x=y();if(!1===u(i,a,{version:c,staleProof:d}))return!1;const A=()=>{const e=$(i,{platform:l,exec:f}),t=!!i||"win32"===l||s(g(),e,c,{notBefore:x});return!(e?.version!==c||!t||(S.write(` ✓ bridge install confirmed — running v${c}.\n`),0))};if("win32"===l)return!0;const P=y()+Math.max(0,Number(b)||0),j=p(i);for(;;){const e=v();if(e&&"object"==typeof e&&e.target===j&&e.version===c){if(!1===e.ok)return S.write(` ⚠ install v${c} was not confirmed: ${e.error||"the launchd handoff failed"}.\n`),!1;if(!0===e.ok&&A())return!0}if(y()>=P)return S.write(` ⚠ install v${c} timed out waiting for supervisor readiness; no connected account bridge was proven.\n`),!1;await k(Math.max(1,Number(w)||1))}}export function restartService(e){const t=process.platform;if(!isServiceInstalled(e))return process.stderr.write(" ⚠ no background service installed to restart — install one first.\n"),!1;const r=p(e);try{if("darwin"===t)n(`launchctl kickstart -k gui/$(id -u)/${r}`,{stdio:"inherit"});else{if("linux"!==t)return process.stderr.write(" ⚠ Windows has no managed daemon — close the running thinkpool-pair window and re-launch the Startup .cmd (or reboot) to restart.\n"),!1;n(`systemctl --user restart ${r}.service`,{stdio:"inherit"})}return process.stderr.write(` ◆ restarted ${r} — any active session resumes in place.\n`),!0}catch(e){return process.stderr.write(` ⚠ restart failed: ${e.message}\n`),!1}}function b(e=n){let t="";try{t=String(e("npm view thinkpool-pair version",{encoding:"utf8",stdio:["ignore","pipe","ignore"]})).trim()}catch{}return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(t)?t:null}export function stageServiceUpdate(e,{exec:t=n,active:r=isServiceInstalled,provision:i=provisionRuntime}={}){if(!r(e))return process.stderr.write(" ⚠ no background service installed to update — install one first.\n"),null;const o=b(t);if(!o)return process.stderr.write(" ⚠ couldn't reach npm or resolve the published version — bridge left unchanged; NO update or restart was applied.\n"),null;process.stderr.write(`\n ◆ preparing bridge v${o} in the background; active sessions keep running…\n`);try{return i(o),o}catch(e){return process.stderr.write(` ⚠ couldn't stage bridge v${o}: ${e?.message||e}\n`),null}}export function applyStagedServiceUpdate(e,t,{install:r=installService,active:n=isServiceInstalled}={}){return!(!n(e)||!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(String(t||"")))&&(process.stderr.write(`\n ◆ updating the background service to v${t} and restarting…\n`),!1!==r(e,[],{version:t,staleProof:!0}))}export function updateService(e,{exec:t=n,install:r=installService,active:i=isServiceInstalled}={}){if(!i(e))return process.stderr.write(" ⚠ no background service installed to update — install one first.\n"),!1;const o=b(t);return o?(process.stderr.write(`\n ◆ updating the background service to v${o} and restarting…\n`),!1!==r(e,[],{version:o,staleProof:!0})):(process.stderr.write(" ⚠ couldn't reach npm or resolve the published version — bridge left unchanged; NO update or restart was applied.\n"),!1)}export async function updateAndConfirmService(i,{platform:a=process.platform,exec:l=n,update:c=updateService,install:d=installService,active:u=isServiceInstalled,snapshot:f=serviceRuntimeSnapshot,readReady:$=()=>o(),readStatus:h=()=>{try{return JSON.parse(t.readFileSync(r.join(e.homedir(),".thinkpool-pair","update-status.json"),"utf8"))}catch{return null}},now:m=Date.now,sleep:g=e=>new Promise(t=>setTimeout(t,e)),timeoutMs:v=2e5,pollMs:y=250,stderr:k=process.stderr}={}){const b=f(i,{platform:a,exec:l}),w=m();let S=null;if(!1===c(i,{exec:(...e)=>{const t=l(...e),r=String(t).trim();return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(r)&&(S=r),t},install:d,active:u})||!S)return k.write(" ⚠ update was not confirmed: staging the published runtime failed; the existing service was left unchanged.\n"),!1;const _=()=>{const e=f(i,{platform:a,exec:l}),t=!!b&&b.version!==S,r=!!b?.pid&&!!e?.pid&&b.pid!==e.pid,n=!!i||"win32"===a||s($(),e,S,{notBefore:w});return e?.version===S&&(t||r)&&n?(k.write(` ✓ bridge restart confirmed — running v${S}.\n`),{ok:!0,live:e}):{ok:!1,live:e}},x=({live:e}={})=>{e?.version&&e.version!==S?k.write(` ⚠ update v${S} was not confirmed: live service is still v${e.version}.\n`):e?.version===S?k.write(` ⚠ update v${S} was not confirmed: the service process did not restart.\n`):k.write(` ⚠ update v${S} was not confirmed: the service manager cannot prove the new runtime is running.\n`)};if("win32"===a)return!0;const A=m()+Math.max(0,Number(v)||0),P=p(i);let j=null;for(;;){const e=h();if(e&&"object"==typeof e&&e.target===P){if(!1===e.ok&&e.version===S)return k.write(` ⚠ update v${S} was not confirmed: ${e.error||"the launchd handoff failed"}.\n`),!1;if(!0===e.ok&&e.version===S&&(j=_(),j.ok))return!0}if(m()>=A)return j?x(j):k.write(` ⚠ update v${S} timed out waiting for launchd confirmation; the service may have rolled back.\n`),!1;await g(Math.max(1,Number(y)||1))}}export function serviceActive(e,{platform:t=process.platform,exec:r=n}={}){const i=t,o=p(e);try{return"darwin"===i?darwinServiceRunning(r(`launchctl print gui/$(id -u)/${o}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"]})):"linux"===i&&(r(`systemctl --user is-active --quiet ${o}.service`),!0)}catch{return!1}}export function isServiceInstalled(e){if("win32"===process.platform)try{return t.existsSync(buildArtifact("win32",{room:e}).file)}catch{return!1}return serviceActive(e)}export function uninstallService(e){const r=process.platform;let i;try{i=buildArtifact(r,{room:e})}catch(e){return void process.stderr.write(` ⚠ ${e.message}\n`)}if("darwin"===r)try{n(`launchctl bootout gui/$(id -u)/${p(e)} 2>/dev/null`)}catch{}if("linux"===r)try{n(`systemctl --user disable --now ${p(e)}.service 2>/dev/null`)}catch{}try{t.rmSync(i.file,{force:!0}),process.stderr.write(` ◆ removed ${i.file}\n`)}catch(e){process.stderr.write(` ⚠ ${e.message}\n`)}}
1
+ import e from"node:os";import t from"node:fs";import r from"node:path";import{execSync as n}from"node:child_process";import{hostMemoryAdmission as i}from"./host-memory.mjs";import{readSupervisorReady as o,supervisorReadyMatches as s}from"./supervisor-ready.mjs";import{pairCli as a}from"./command-guidance.mjs";import{loadKeepAwakePreference as l}from"./keep-awake.mjs";import{scheduledRunsEnabled as c}from"./scheduled-runs.mjs";const d=/^[A-Za-z0-9]{2,16}$/,p=e=>{if(e&&!d.test(e))throw new Error(`invalid room code: ${JSON.stringify(e)} (expected 2–16 alphanumerics)`);return e?`io.thinkpool.pair.${e.toLowerCase()}`:"io.thinkpool.pair.account"},u=e=>e||"account",f=e=>String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;"),$=e=>`'${String(e).replace(/'/g,"'\\''")}'`;export function sanitizeServicePath(e,t=process.platform){const r="win32"===t?";":":";return String(e||"").split(r).filter(e=>e&&!e.includes("/.npm/_npx/")).join(r)}export function darwinServiceRunning(e){const t=String(e||"");return/(^|\n)[ \t]*state = running[ \t]*($|\n)/.test(t)&&/(^|\n)[ \t]*pid = \d+[ \t]*($|\n)/.test(t)}const h=e=>`rm -rf ${$(r.join(e,"_npx"))}/* 2>/dev/null`,m=(()=>{try{return JSON.parse(t.readFileSync(new URL("./package.json",import.meta.url),"utf8")).version}catch{return"latest"}})();function g(e){try{const n=JSON.parse(t.readFileSync(r.join(r.dirname(e),"package.json"),"utf8"));return"string"==typeof n?.version?n.version:null}catch{return null}}export function provisionRuntime(o,{exec:s=n,root:a=r.join(e.homedir(),".thinkpool-pair","runtimes"),admit:l=i}={}){if(!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(String(o)))throw new Error(`invalid runtime version: ${o}`);const c=r.join(a,String(o)),d=r.join(c,"node_modules","thinkpool-pair","bridge.mjs");if(t.existsSync(d)&&g(d)===String(o))return d;const p=l("stage a bridge runtime update");if(!p?.ok)throw new Error(p?.reason||"host memory is critically low");const u=`${c}.install-${process.pid}-${Date.now()}`;t.rmSync(u,{recursive:!0,force:!0}),t.mkdirSync(u,{recursive:!0});const f=`https://registry.npmjs.org/thinkpool-pair/-/thinkpool-pair-${o}.tgz`,h=r.join(u,"node_modules","thinkpool-pair","bridge.mjs");try{s(`${$(function(e=process.platform){const n=r.dirname(process.execPath),i=r.join(n,"win32"===e?"npm.cmd":"npm");try{return t.accessSync(i),i}catch{return"win32"===e?"npm.cmd":"npm"}}())} install --prefix ${$(u)} ${$(f)} --prefer-online --no-audit --no-fund`,{stdio:"inherit",shell:"/bin/bash"});const e=g(h);if(!t.existsSync(h)||e!==String(o))throw new Error(`runtime verification failed: requested ${o}, installed ${e||"no valid package"}`);t.rmSync(c,{recursive:!0,force:!0}),t.renameSync(u,c)}catch(e){throw t.rmSync(u,{recursive:!0,force:!0}),e}return d}export function buildArtifact(n,{room:i=null,cmdArgs:o=[],autoUpdate:s=!1,version:a=m,staleProof:l=!1,runtimeEntry:d=null,scheduledRuns:g=c()}={}){const v=function(e){const n=r.dirname(process.execPath),i=r.join(n,"win32"===e?"npx.cmd":"npx");try{return t.accessSync(i),i}catch{return"win32"===e?"npx.cmd":"npx"}}(n),y=i?process.cwd():e.homedir(),k=u(i),b=r.join(e.homedir(),".thinkpool-pair"),w=r.join(b,`${k}.log`),S=sanitizeServicePath(process.env.PATH||"",n),_=r.join(e.homedir(),".thinkpool-pair","npm-cache"),x=o.length?["--",...o]:[],A=i?`bridge (${i})`:"account bridge",P=s?"thinkpool-pair@latest":`thinkpool-pair@${a}`,j=s||l?["--prefer-online"]:[],E=i?["-y",...j,P,i]:["-y",...j,P],F=!0===g?{darwin:"<key>TP_SCHEDULED_RUNS_ENABLED</key><string>1</string>",linux:"Environment=TP_SCHEDULED_RUNS_ENABLED=1\n",win32:'set "TP_SCHEDULED_RUNS_ENABLED=1"\r\n'}:{darwin:"",linux:"",win32:""};if("darwin"===n){const t=d?[process.execPath,d,...i?[i]:[],...x]:l?["/bin/bash","-lc",`${h(_)}; export NPM_CONFIG_CACHE=${$(_)}; exec ${[v,...E,...x].map($).join(" ")}`]:[v,...E,...x];return{file:r.join(e.homedir(),"Library","LaunchAgents",`${p(i)}.plist`),content:`<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0"><dict>\n <key>Label</key><string>${p(i)}</string>\n <key>ProgramArguments</key><array>${t.map(e=>`<string>${f(e)}</string>`).join("")}</array>\n <key>RunAtLoad</key><true/>\n \x3c!-- KeepAlive only on UNSUCCESSFUL exit. A bridge that exits 0 has intentionally\n stood down — told to stop, or another bridge already owns this machine's\n singleton lock — and must NOT be relaunched, or launchd thrashes it every\n few seconds forever (the 2026-06-28 account-bridge restart loop). A crash\n or an update-restart exits non-zero and IS relaunched. Mirrors the bridge's\n own exit-code contract (stop()=0, restart-requested=non-zero). --\x3e\n <key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>\n <key>WorkingDirectory</key><string>${f(y)}</string>\n <key>StandardOutPath</key><string>${f(w)}</string>\n <key>StandardErrorPath</key><string>${f(w)}</string>\n <key>EnvironmentVariables</key><dict><key>PATH</key><string>${f(S)}</string>${d?"":`<key>NPM_CONFIG_CACHE</key><string>${f(_)}</string>`}${s?"<key>THINKPOOL_PAIR_AUTOUPDATE</key><string>1</string>":""}${F.darwin}</dict>\n</dict></plist>\n`,logDir:b,post:[],expectedRuntime:d||P,note:"Loaded as a LaunchAgent — starts at login, restarts on crash."}}if("linux"===n){const t=d?[process.execPath,d,...i?[i]:[],...x]:[v,...E,...x];return{file:r.join(e.homedir(),".config","systemd","user",`${p(i)}.service`),content:`[Unit]\nDescription=thinkpool Code ${A}\nAfter=network-online.target\n\n[Service]\nExecStart=${d?t.map(e=>`'${e.replace(/'/g,"'\\''")}'`).join(" "):l?`/bin/bash -lc "${h(_)}; export NPM_CONFIG_CACHE=${$(_)}; exec ${[v,...E,...x].join(" ")}"`:t.map(e=>`'${e.replace(/'/g,"'\\''")}'`).join(" ")}\nRestart=always\nRestartSec=2\n# Don't relaunch a clean stand-down. exit 0 = the bridge intentionally stopped —\n# told to stop, or another bridge already holds this machine's singleton lock —\n# so restarting it just thrashes every RestartSec forever (the 2026-06-28\n# account-bridge restart loop). Crashes + update-restarts exit non-zero and are\n# still restarted. Matches the bridge's exit-code contract (stop()=0, restart=non-zero).\nRestartPreventExitStatus=0\nWorkingDirectory=${y}\nEnvironment=PATH=${S}\n${d?"":`Environment=NPM_CONFIG_CACHE=${_}\n`}${s?"Environment=THINKPOOL_PAIR_AUTOUPDATE=1\n":""}${F.linux}StandardOutput=append:${w}\nStandardError=append:${w}\n\n[Install]\nWantedBy=default.target\n`,logDir:b,post:["systemctl --user daemon-reload",`systemctl --user enable ${p(i)}.service`,`systemctl --user restart ${p(i)}.service`],expectedRuntime:d||P,note:"Enabled as a systemd --user service. Run `loginctl enable-linger $USER` once to keep it running after logout."}}if("win32"===n){const t=r.join(process.env.APPDATA||r.join(e.homedir(),"AppData","Roaming"),"Microsoft","Windows","Start Menu","Programs","Startup"),n=r.join(t,`thinkpool-pair-${k}.cmd`),o=d?[process.execPath,d,...i?[i,"--supervise"]:[],...x].map(e=>`"${e}"`).join(" "):i?["npx","-y",...j,P,i,"--supervise",...x].join(" "):["npx","-y",...j,P].join(" ");return{file:n,content:`@echo off\r\ntitle thinkpool-pair ${k}\r\n${d?"":`set "NPM_CONFIG_CACHE=${_}"\r\n`}${F.win32}${o}\r\n`,logDir:b,post:[],note:"Installed to the Startup folder — runs at login"+(i?" with --supervise (auto-restart on crash).":" (account mode).")+" Start it now without rebooting by double-clicking the .cmd, or run it from a terminal."}}throw new Error(`unsupported platform: ${n}`)}export function parseRunningPairVersions(e){const t=String(e).match(/(?:thinkpool-pair@|runtimes[\\/])(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/g)||[];return new Set(t.map(e=>e.match(/\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?/)?.[0]).filter(Boolean))}export function serviceRuntimeSnapshot(e,{platform:t=process.platform,exec:r=n}={}){const i=e=>{const t=parseRunningPairVersions(e);return 1===t.size?[...t][0]:null},o=p(e);try{if("darwin"===t){const e=r(`launchctl print gui/$(id -u)/${o}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"],shell:"/bin/bash"}),t=String(e).match(/(^|\n)[ \t]*pid = (\d+)[ \t]*($|\n)/)?.[2];return darwinServiceRunning(e)?{version:i(e),pid:t||null}:null}if("linux"===t){const e=r(`systemctl --user show ${o}.service --property=ActiveState --property=MainPID --property=ExecStart`,{encoding:"utf8",stdio:["ignore","pipe","ignore"]}),t=String(e).match(/^MainPID=([1-9]\d*)$/m)?.[1];return/^ActiveState=active$/m.test(String(e))&&t?{version:i(e),pid:t}:null}}catch{}return null}export function serviceRuntimeVersion(e,t){return serviceRuntimeSnapshot(e,t)?.version||null}export function buildDarwinReloadHandoff({targetLabel:t,targetFile:n,stagedFile:i,expectedRuntime:o,version:s,nonce:a=`${process.pid}-${Date.now()}`}){if(!/^io\.thinkpool\.pair\.[A-Za-z0-9_.-]+$/.test(String(t)))throw new Error(`invalid service label: ${t}`);if(!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(String(s)))throw new Error(`invalid runtime version: ${s}`);const l=`io.thinkpool.pair.update.${String(a).replace(/[^A-Za-z0-9-]/g,"")||String(process.pid)}`,c=r.join(e.homedir(),"Library","LaunchAgents",`${l}.plist`),d=`${i}.previous`,u=r.join(e.homedir(),".thinkpool-pair","update-status.json"),h=r.join(e.homedir(),".thinkpool-pair","update.log"),m=r.join(e.homedir(),".thinkpool-pair","account-ready.json"),g=t===p(null),v=["set -u",'dom="gui/$(id -u)"',`target=${$(t)}`,`helper=${$(l)}`,`target_file=${$(n)}`,`staged_file=${$(i)}`,`backup_file=${$(d)}`,`helper_file=${$(c)}`,`expected=${$(o)}`,`version=${$(s)}`,`status=${$(u)}`,`ready=${$(m)}`,"requires_ready="+(g?"1":"0"),'tmp="$status.tmp.$$"',"ok=0",'live_pid=""',"stable=0","had_previous=0",'if [ -f "$target_file" ]; then cp "$target_file" "$backup_file" && had_previous=1; fi','launchctl bootout "$dom/$target" 2>/dev/null || true','for i in $(seq 1 40); do launchctl print "$dom/$target" >/dev/null 2>&1 || break; sleep 0.2; done','if [ "$requires_ready" = 1 ]; then rm -f "$ready"; fi','cp "$staged_file" "$target_file"','launchctl enable "$dom/$target" 2>/dev/null || true','for i in $(seq 1 30); do launchctl bootstrap "$dom" "$target_file" 2>/dev/null && break; sleep 0.3; done','printf "update_handoff_start target=%s version=%s timeout_s=90\\n" "$target" "$version"','for i in $(seq 1 180); do snapshot="$(launchctl print "$dom/$target" 2>/dev/null || true)"; pid="$(printf "%s\\n" "$snapshot" | sed -n "s/^[[:space:]]*pid = \\([0-9][0-9]*\\)[[:space:]]*$/\\1/p" | head -1)"; ready_ok=1; if [ "$requires_ready" = 1 ]; then ready_ok=0; [ -f "$ready" ] && grep -F "\\"pid\\":$pid" "$ready" >/dev/null 2>&1 && grep -F "\\"version\\":\\"$version\\"" "$ready" >/dev/null 2>&1 && ready_ok=1; fi; if [ -n "$pid" ] && [ "$ready_ok" = 1 ] && printf "%s\\n" "$snapshot" | grep -F -- "$expected" >/dev/null && printf "%s\\n" "$snapshot" | grep -F "state = running" >/dev/null; then if [ "$pid" = "$live_pid" ]; then stable=$((stable+1)); else live_pid="$pid"; stable=1; fi; if [ "$stable" -ge 5 ]; then ok=1; break; fi; else live_pid=""; stable=0; fi; sleep 0.5; done','if [ "$ok" != 1 ]; then ready_state=missing; [ -f "$ready" ] && ready_state=present; printf "update_handoff_verify_timeout target=%s version=%s last_pid=%s ready=%s\\n" "$target" "$version" "$live_pid" "$ready_state"; fi',`if [ "$ok" = 1 ]; then printf '%s\\n' '${JSON.stringify({ok:!0,version:String(s),target:String(t)})}' > "$tmp"; else rollback=0; if [ "$had_previous" = 1 ]; then launchctl bootout "$dom/$target" 2>/dev/null || true; for i in $(seq 1 40); do launchctl print "$dom/$target" >/dev/null 2>&1 || break; sleep 0.2; done; if [ "$requires_ready" = 1 ]; then rm -f "$ready"; fi; cp "$backup_file" "$target_file"; launchctl enable "$dom/$target" 2>/dev/null || true; bootstrapped=0; for i in $(seq 1 30); do if launchctl bootstrap "$dom" "$target_file" 2>/dev/null; then bootstrapped=1; break; fi; sleep 0.3; done; if [ "$bootstrapped" = 1 ]; then rollback_pid=""; rollback_stable=0; for i in $(seq 1 180); do snapshot="$(launchctl print "$dom/$target" 2>/dev/null || true)"; pid="$(printf "%s\\n" "$snapshot" | sed -n "s/^[[:space:]]*pid = \\([0-9][0-9]*\\)[[:space:]]*$/\\1/p" | head -1)"; ready_ok=1; if [ "$requires_ready" = 1 ]; then ready_ok=0; [ -f "$ready" ] && grep -F "\\"pid\\":$pid" "$ready" >/dev/null 2>&1 && ready_ok=1; fi; if [ -n "$pid" ] && [ "$ready_ok" = 1 ] && printf "%s\\n" "$snapshot" | grep -F "state = running" >/dev/null; then if [ "$pid" = "$rollback_pid" ]; then rollback_stable=$((rollback_stable+1)); else rollback_pid="$pid"; rollback_stable=1; fi; if [ "$rollback_stable" -ge 5 ]; then rollback=1; break; fi; else rollback_pid=""; rollback_stable=0; fi; sleep 0.5; done; fi; else launchctl bootout "$dom/$target" 2>/dev/null || true; rm -f "$target_file"; fi; if [ "$rollback" = 1 ]; then printf '%s\\n' '${JSON.stringify({ok:!1,version:String(s),target:String(t),error:"new runtime not confirmed within 90s; previous service restored and ready",rolledBack:!0})}' > "$tmp"; else printf '%s\\n' '${JSON.stringify({ok:!1,version:String(s),target:String(t),error:"new runtime not confirmed within 90s and ready rollback failed",rolledBack:!1})}' > "$tmp"; fi; fi`,'printf "update_handoff_complete target=%s version=%s ok=%s\\n" "$target" "$version" "$ok"','mv "$tmp" "$status"','rm -f "$staged_file" "$backup_file" "$helper_file"','launchctl bootout "$dom/$helper" >/dev/null 2>&1 || true','exit "$((1-ok))"'].join("; ");return{helperLabel:l,helperFile:c,backupFile:d,statusFile:u,logFile:h,script:v,content:`<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0"><dict>\n <key>Label</key><string>${f(l)}</string>\n <key>ProgramArguments</key><array><string>/bin/bash</string><string>-lc</string><string>${f(v)}</string></array>\n <key>RunAtLoad</key><true/>\n <key>StandardOutPath</key><string>${f(h)}</string>\n <key>StandardErrorPath</key><string>${f(h)}</string>\n</dict></plist>\n`}}export function buildLinuxReloadHandoff({targetLabel:t,targetFile:n,stagedFile:i,expectedRuntime:o,version:s,nonce:a=`${process.pid}-${Date.now()}`}){if(!/^io\.thinkpool\.pair\.[A-Za-z0-9_.-]+$/.test(String(t)))throw new Error(`invalid service label: ${t}`);if(!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(String(s)))throw new Error(`invalid runtime version: ${s}`);const l=`io.thinkpool.pair.update.${String(a).replace(/[^A-Za-z0-9-]/g,"")||String(process.pid)}`,c=`${i}.previous`,d=r.join(e.homedir(),".thinkpool-pair","update-status.json"),u=r.join(e.homedir(),".thinkpool-pair","update.log"),f=r.join(e.homedir(),".thinkpool-pair","account-ready.json"),h=t===p(null);return{helperLabel:l,backupFile:c,statusFile:d,logFile:u,script:["set -u",`target=${$(t)}`,'unit="$target.service"',`target_file=${$(n)}`,`staged_file=${$(i)}`,`backup_file=${$(c)}`,`expected=${$(o)}`,`version=${$(s)}`,`status=${$(d)}`,`ready=${$(f)}`,"requires_ready="+(h?"1":"0"),'tmp="$status.tmp.$$"',"ok=0","had_previous=0",'if [ -f "$target_file" ]; then cp "$target_file" "$backup_file" && had_previous=1; fi','systemctl --user stop "$unit" 2>/dev/null || true','if [ "$requires_ready" = 1 ]; then rm -f "$ready"; fi','cp "$staged_file" "$target_file"',"systemctl --user daemon-reload",'systemctl --user enable "$unit" >/dev/null 2>&1 || true','systemctl --user restart "$unit" >/dev/null 2>&1 || true','live_pid=""',"stable=0",'printf "update_handoff_start target=%s version=%s timeout_s=90\\n" "$target" "$version"','for i in $(seq 1 180); do snapshot="$(systemctl --user show "$unit" --property=ActiveState --property=MainPID --property=ExecStart 2>/dev/null || true)"; pid="$(printf "%s\\n" "$snapshot" | sed -n "s/^MainPID=\\([1-9][0-9]*\\)$/\\1/p" | head -1)"; ready_ok=1; if [ "$requires_ready" = 1 ]; then ready_ok=0; [ -f "$ready" ] && grep -F "\\"pid\\":$pid" "$ready" >/dev/null 2>&1 && grep -F "\\"version\\":\\"$version\\"" "$ready" >/dev/null 2>&1 && ready_ok=1; fi; if [ -n "$pid" ] && [ "$ready_ok" = 1 ] && printf "%s\\n" "$snapshot" | grep -F "ActiveState=active" >/dev/null && printf "%s\\n" "$snapshot" | grep -F -- "$expected" >/dev/null; then if [ "$pid" = "$live_pid" ]; then stable=$((stable+1)); else live_pid="$pid"; stable=1; fi; if [ "$stable" -ge 5 ]; then ok=1; break; fi; else live_pid=""; stable=0; fi; sleep 0.5; done','if [ "$ok" != 1 ]; then ready_state=missing; [ -f "$ready" ] && ready_state=present; printf "update_handoff_verify_timeout target=%s version=%s last_pid=%s ready=%s\\n" "$target" "$version" "$live_pid" "$ready_state"; fi',`if [ "$ok" = 1 ]; then printf '%s\\n' '${JSON.stringify({ok:!0,version:String(s),target:String(t)})}' > "$tmp"; else rollback=0; if [ "$had_previous" = 1 ]; then systemctl --user stop "$unit" 2>/dev/null || true; if [ "$requires_ready" = 1 ]; then rm -f "$ready"; fi; cp "$backup_file" "$target_file"; systemctl --user daemon-reload; systemctl --user enable "$unit" >/dev/null 2>&1 || true; systemctl --user restart "$unit" >/dev/null 2>&1 || true; rollback_pid=""; rollback_stable=0; for i in $(seq 1 180); do snapshot="$(systemctl --user show "$unit" --property=ActiveState --property=MainPID 2>/dev/null || true)"; pid="$(printf "%s\\n" "$snapshot" | sed -n "s/^MainPID=\\([1-9][0-9]*\\)$/\\1/p" | head -1)"; ready_ok=1; if [ "$requires_ready" = 1 ]; then ready_ok=0; [ -f "$ready" ] && grep -F "\\"pid\\":$pid" "$ready" >/dev/null 2>&1 && ready_ok=1; fi; if [ -n "$pid" ] && [ "$ready_ok" = 1 ] && printf "%s\\n" "$snapshot" | grep -F "ActiveState=active" >/dev/null; then if [ "$pid" = "$rollback_pid" ]; then rollback_stable=$((rollback_stable+1)); else rollback_pid="$pid"; rollback_stable=1; fi; if [ "$rollback_stable" -ge 5 ]; then rollback=1; break; fi; else rollback_pid=""; rollback_stable=0; fi; sleep 0.5; done; else systemctl --user stop "$unit" 2>/dev/null || true; rm -f "$target_file"; systemctl --user daemon-reload; fi; if [ "$rollback" = 1 ]; then printf '%s\\n' '${JSON.stringify({ok:!1,version:String(s),target:String(t),error:"new runtime not confirmed within 90s; previous service restored and ready",rolledBack:!0})}' > "$tmp"; else printf '%s\\n' '${JSON.stringify({ok:!1,version:String(s),target:String(t),error:"new runtime not confirmed within 90s and ready rollback failed",rolledBack:!1})}' > "$tmp"; fi; fi`,'printf "update_handoff_complete target=%s version=%s ok=%s\\n" "$target" "$version" "$ok"','mv "$tmp" "$status"','rm -f "$staged_file" "$backup_file"','exit "$((1-ok))"'].join("; ")}}const v=()=>r.join(e.homedir(),".thinkpool-pair","account.lock"),y=e=>{try{return process.kill(e,0),!0}catch(e){return"EPERM"===e?.code}};export async function retireUnmanagedBridgeLock({lockFile:e=v(),readLock:r=()=>t.readFileSync(e,"utf8"),removeLock:i=()=>t.rmSync(e,{force:!0}),commandForPid:o=e=>String(n(`ps -p ${e} -o command=`,{encoding:"utf8",stdio:["ignore","pipe","ignore"]})),alive:s=y,signal:a=(e,t)=>process.kill(e,t),sleep:l=e=>new Promise(t=>setTimeout(t,e)),waitMs:c=2500,pollMs:d=100,stderr:p=process.stderr}={}){let u=0;try{u=parseInt(String(r()).trim(),10)||0}catch{return!0}const f=()=>{if(s(u))return!1;try{(parseInt(String(r()).trim(),10)||0)===u&&i()}catch{}return!0};if(!u||u===process.pid||f())return!0;let $="";try{$=o(u)}catch{return f()}if(!/(?:node_modules[\\/]thinkpool-pair|\.npm[\\/]_npx|\.thinkpool-pair[\\/]runtimes)[\\/][^\n]*bridge\.mjs(?:\s|$)/.test($))return p.write(` ⚠ account.lock belongs to PID ${u}, but it is not a verified thinkpool-pair bridge; refusing to signal an unrelated process.\n`),!1;p.write(` ◆ stopping previous thinkpool-pair bridge (PID ${u}) before installing the background service…\n`);try{a(u,"SIGTERM")}catch{if(f())return!0}const h=Math.max(1,Math.ceil(Math.max(0,Number(c)||0)/Math.max(1,Number(d)||1)));for(let e=0;e<h;e++){if(f())return!0;await l(Math.max(1,Number(d)||1))}try{a(u,"SIGKILL")}catch{}for(let e=0;e<5;e++){if(f())return!0;await l(Math.max(1,Number(d)||1))}return p.write(` ⚠ previous thinkpool-pair bridge PID ${u} did not stop; background install aborted to avoid two competing bridges.\n`),!1}function k(e){const t=r.basename(e).match(/^(io\.thinkpool\.pair\.[A-Za-z0-9_.-]+)\.(?:plist|service)$/);if(!t)throw new Error(`cannot derive service label from ${e}`);return t[1]}export function existingServiceLabels(i=process.platform,{fsMod:o=t}={}){const s=new Set;try{if("darwin"===i){try{const e=n("launchctl print gui/$(id -u) 2>/dev/null | grep -oE 'io\\.thinkpool\\.pair\\.[A-Za-z0-9_]+' | sort -u",{encoding:"utf8",shell:"/bin/bash"});for(const t of e.split("\n")){const e=t.trim();e&&s.add(e)}}catch{}try{const t=r.join(e.homedir(),"Library","LaunchAgents");for(const e of o.readdirSync(t)){const t=e.match(/^(io\.thinkpool\.pair\.[A-Za-z0-9_]+)\.plist$/);t&&s.add(t[1])}}catch{}}else if("linux"===i){try{const e=n("systemctl --user list-unit-files 'io.thinkpool.pair.*' --no-legend 2>/dev/null | awk '{print $1}'",{encoding:"utf8",shell:"/bin/bash"});for(const t of e.split("\n")){const e=t.trim().replace(/\.service$/,"");e&&s.add(e)}}catch{}try{const t=r.join(e.homedir(),".config","systemd","user");for(const e of o.readdirSync(t)){const t=e.match(/^(io\.thinkpool\.pair\.[A-Za-z0-9_]+)\.service$/);t&&s.add(t[1])}}catch{}}}catch{}return[...s]}export function sweepExistingServices(i,o=process.platform){for(const s of existingServiceLabels(o))if(s!==i)try{if("darwin"===o){n(`launchctl bootout gui/$(id -u)/${s} 2>/dev/null || true`,{stdio:"ignore",shell:"/bin/bash"});try{t.rmSync(r.join(e.homedir(),"Library","LaunchAgents",`${s}.plist`),{force:!0})}catch{}}else"linux"===o&&n(`systemctl --user disable --now ${s}.service 2>/dev/null || true`,{stdio:"ignore",shell:"/bin/bash"});process.stderr.write(` ◆ swept stale service ${s}\n`)}catch{}if("win32"!==o)try{n("pkill -9 -f 'thinkpool-pair/bridge.mjs [A-Z0-9]' 2>/dev/null || true",{stdio:"ignore",shell:"/bin/bash"})}catch{}}export function installService(e,i=[],{autoUpdate:o=!1,version:s=m,staleProof:c=!0}={}){let d=null;if(!o)try{d=provisionRuntime(s)}catch(e){return process.stderr.write(` ⚠ runtime install failed; service left unchanged: ${e.message}\n`),!1}const f=buildArtifact(process.platform,{room:e,cmdArgs:i,autoUpdate:o,version:s,staleProof:c,runtimeEntry:d});try{sweepExistingServices(p(e),process.platform)}catch{}if(t.mkdirSync(f.logDir,{recursive:!0}),t.mkdirSync(r.dirname(f.file),{recursive:!0}),"darwin"===process.platform){if(process.stderr.write(`\n ◆ staged replacement for ${f.file}\n`),!function(e,i){const o=r.join(e.logDir,`service-update-${process.pid}-${Date.now()}.plist`),s=buildDarwinReloadHandoff({targetLabel:k(e.file),targetFile:e.file,stagedFile:o,expectedRuntime:e.expectedRuntime,version:i});t.mkdirSync(r.dirname(s.helperFile),{recursive:!0}),t.mkdirSync(r.dirname(s.statusFile),{recursive:!0}),t.rmSync(s.statusFile,{force:!0}),t.writeFileSync(o,e.content),t.writeFileSync(s.helperFile,s.content);try{return n(`launchctl bootstrap gui/$(id -u) ${$(s.helperFile)}`,{stdio:"inherit",shell:"/bin/bash"}),process.stderr.write(` ◆ update handoff armed outside the bridge process tree — completion is recorded in ${s.statusFile}.\n`),!0}catch(e){return t.rmSync(o,{force:!0}),t.rmSync(s.helperFile,{force:!0}),process.stderr.write(` ⚠ could not arm the launchd update handoff; existing service left running: ${e.message}\n`),!1}}(f,s))return!1}else if("linux"===process.platform){if(process.stderr.write(`\n ◆ staged replacement for ${f.file}\n`),!function(e,i){const o=r.join(e.logDir,`service-update-${process.pid}-${Date.now()}.service`),s=buildLinuxReloadHandoff({targetLabel:k(e.file),targetFile:e.file,stagedFile:o,expectedRuntime:e.expectedRuntime,version:i});t.mkdirSync(r.dirname(s.statusFile),{recursive:!0}),t.rmSync(s.statusFile,{force:!0}),t.writeFileSync(o,e.content);try{return n(`systemd-run --user --unit=${$(s.helperLabel)} --collect --property=StandardOutput=append:${$(s.logFile)} --property=StandardError=append:${$(s.logFile)} /bin/bash -lc ${$(s.script)}`,{stdio:"inherit",shell:"/bin/bash"}),process.stderr.write(` ◆ update handoff armed outside the bridge service cgroup — completion is recorded in ${s.statusFile}.\n`),!0}catch(e){return t.rmSync(o,{force:!0}),process.stderr.write(` ⚠ could not arm the systemd update handoff; existing service left running: ${e.message}\n`),!1}}(f,s))return!1}else{t.writeFileSync(f.file,f.content),process.stderr.write(`\n ◆ wrote ${f.file}\n`);for(const e of f.post)try{n(e,{stdio:"inherit"})}catch(t){return process.stderr.write(` ⚠ "${e}" failed; service update NOT confirmed: ${t.message}\n`),!1}}const h=Math.max(10,parseInt(process.env.THINKPOOL_PAIR_UPDATE_IDLE,10)||90),g=o?"win32"===process.platform?"auto-update ON: a new thinkpool-pair@latest applies on the next login/restart (Windows has no in-process self-update).":`auto-update ON: checks npm ~every 30 min and restarts to apply a new @latest once sessions are idle (≥${h}s quiet; they resume in place).`:`PINNED to ${s} (stable local runtime; restarts do not depend on npx or the network). To update: use "Restart & update the bridge" (or run ${a("install-service",e||void 0)}). Pass --auto-update to track @latest instead.`,v=e?` ${e}`:"",y=e?`room ${e}`:"your account (auto-serves every session)",b=l()?" ◆ Keep-awake on: system sleep is inhibited while the bridge runs (higher battery use); the display may still dim, lock, and turn off.\n":"";return process.stderr.write(` ◆ ${y}\n ◆ ${"darwin"===process.platform?"Launchd is completing and verifying the reload independently.":f.note}\n ◆ Prerequisite: Claude Code, Codex, or Hermes must be installed on this machine. BYOK supplies model credentials; it does not install an agent.\n${b} ◆ ${g}\n ◆ logs: ${r.join(f.logDir,`${u(e)}.log`)}\n ◆ remove with: ${a("uninstall-service")}${v}\n\n`),!0}export async function installAndConfirmService(i,a=[],{platform:l=process.platform,version:c=m,staleProof:d=!0,install:u=installService,exec:f=n,snapshot:$=serviceRuntimeSnapshot,prepareAccountHandoff:h=retireUnmanagedBridgeLock,readReady:g=()=>o(),readStatus:v=()=>{try{return JSON.parse(t.readFileSync(r.join(e.homedir(),".thinkpool-pair","update-status.json"),"utf8"))}catch{return null}},now:y=Date.now,sleep:k=e=>new Promise(t=>setTimeout(t,e)),timeoutMs:b=2e5,pollMs:w=250,stderr:S=process.stderr}={}){const _=$(i,{platform:l,exec:f});if(!i&&"win32"!==l&&!_&&!await h())return S.write(" ⚠ background install aborted: the previous bridge could not be handed off safely.\n"),!1;const x=y();if(!1===u(i,a,{version:c,staleProof:d}))return!1;const A=()=>{const e=$(i,{platform:l,exec:f}),t=!!i||"win32"===l||s(g(),e,c,{notBefore:x});return!(e?.version!==c||!t||(S.write(` ✓ bridge install confirmed — running v${c}.\n`),0))};if("win32"===l)return!0;const P=y()+Math.max(0,Number(b)||0),j=p(i);for(;;){const e=v();if(e&&"object"==typeof e&&e.target===j&&e.version===c){if(!1===e.ok)return S.write(` ⚠ install v${c} was not confirmed: ${e.error||"the launchd handoff failed"}.\n`),!1;if(!0===e.ok&&A())return!0}if(y()>=P)return S.write(` ⚠ install v${c} timed out waiting for supervisor readiness; no connected account bridge was proven.\n`),!1;await k(Math.max(1,Number(w)||1))}}export function restartService(e){const t=process.platform;if(!isServiceInstalled(e))return process.stderr.write(" ⚠ no background service installed to restart — install one first.\n"),!1;const r=p(e);try{if("darwin"===t)n(`launchctl kickstart -k gui/$(id -u)/${r}`,{stdio:"inherit"});else{if("linux"!==t)return process.stderr.write(" ⚠ Windows has no managed daemon — close the running thinkpool-pair window and re-launch the Startup .cmd (or reboot) to restart.\n"),!1;n(`systemctl --user restart ${r}.service`,{stdio:"inherit"})}return process.stderr.write(` ◆ restarted ${r} — any active session resumes in place.\n`),!0}catch(e){return process.stderr.write(` ⚠ restart failed: ${e.message}\n`),!1}}function b(e=n){let t="";try{t=String(e("npm view thinkpool-pair version",{encoding:"utf8",stdio:["ignore","pipe","ignore"]})).trim()}catch{}return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(t)?t:null}export function stageServiceUpdate(e,{exec:t=n,active:r=isServiceInstalled,provision:i=provisionRuntime}={}){if(!r(e))return process.stderr.write(" ⚠ no background service installed to update — install one first.\n"),null;const o=b(t);if(!o)return process.stderr.write(" ⚠ couldn't reach npm or resolve the published version — bridge left unchanged; NO update or restart was applied.\n"),null;process.stderr.write(`\n ◆ preparing bridge v${o} in the background; active sessions keep running…\n`);try{return i(o),o}catch(e){return process.stderr.write(` ⚠ couldn't stage bridge v${o}: ${e?.message||e}\n`),null}}export function applyStagedServiceUpdate(e,t,{install:r=installService,active:n=isServiceInstalled}={}){return!(!n(e)||!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(String(t||"")))&&(process.stderr.write(`\n ◆ updating the background service to v${t} and restarting…\n`),!1!==r(e,[],{version:t,staleProof:!0}))}export function updateService(e,{exec:t=n,install:r=installService,active:i=isServiceInstalled}={}){if(!i(e))return process.stderr.write(" ⚠ no background service installed to update — install one first.\n"),!1;const o=b(t);return o?(process.stderr.write(`\n ◆ updating the background service to v${o} and restarting…\n`),!1!==r(e,[],{version:o,staleProof:!0})):(process.stderr.write(" ⚠ couldn't reach npm or resolve the published version — bridge left unchanged; NO update or restart was applied.\n"),!1)}export async function updateAndConfirmService(i,{platform:a=process.platform,exec:l=n,update:c=updateService,install:d=installService,active:u=isServiceInstalled,snapshot:f=serviceRuntimeSnapshot,readReady:$=()=>o(),readStatus:h=()=>{try{return JSON.parse(t.readFileSync(r.join(e.homedir(),".thinkpool-pair","update-status.json"),"utf8"))}catch{return null}},now:m=Date.now,sleep:g=e=>new Promise(t=>setTimeout(t,e)),timeoutMs:v=2e5,pollMs:y=250,stderr:k=process.stderr}={}){const b=f(i,{platform:a,exec:l}),w=m();let S=null;if(!1===c(i,{exec:(...e)=>{const t=l(...e),r=String(t).trim();return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(r)&&(S=r),t},install:d,active:u})||!S)return k.write(" ⚠ update was not confirmed: staging the published runtime failed; the existing service was left unchanged.\n"),!1;const _=()=>{const e=f(i,{platform:a,exec:l}),t=!!b&&b.version!==S,r=!!b?.pid&&!!e?.pid&&b.pid!==e.pid,n=!!i||"win32"===a||s($(),e,S,{notBefore:w});return e?.version===S&&(t||r)&&n?(k.write(` ✓ bridge restart confirmed — running v${S}.\n`),{ok:!0,live:e}):{ok:!1,live:e}},x=({live:e}={})=>{e?.version&&e.version!==S?k.write(` ⚠ update v${S} was not confirmed: live service is still v${e.version}.\n`):e?.version===S?k.write(` ⚠ update v${S} was not confirmed: the service process did not restart.\n`):k.write(` ⚠ update v${S} was not confirmed: the service manager cannot prove the new runtime is running.\n`)};if("win32"===a)return!0;const A=m()+Math.max(0,Number(v)||0),P=p(i);let j=null;for(;;){const e=h();if(e&&"object"==typeof e&&e.target===P){if(!1===e.ok&&e.version===S)return k.write(` ⚠ update v${S} was not confirmed: ${e.error||"the launchd handoff failed"}.\n`),!1;if(!0===e.ok&&e.version===S&&(j=_(),j.ok))return!0}if(m()>=A)return j?x(j):k.write(` ⚠ update v${S} timed out waiting for launchd confirmation; the service may have rolled back.\n`),!1;await g(Math.max(1,Number(y)||1))}}export function serviceActive(e,{platform:t=process.platform,exec:r=n}={}){const i=t,o=p(e);try{return"darwin"===i?darwinServiceRunning(r(`launchctl print gui/$(id -u)/${o}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"]})):"linux"===i&&(r(`systemctl --user is-active --quiet ${o}.service`),!0)}catch{return!1}}export function isServiceInstalled(e){if("win32"===process.platform)try{return t.existsSync(buildArtifact("win32",{room:e}).file)}catch{return!1}return serviceActive(e)}export function uninstallService(e){const r=process.platform;let i;try{i=buildArtifact(r,{room:e})}catch(e){return void process.stderr.write(` ⚠ ${e.message}\n`)}if("darwin"===r)try{n(`launchctl bootout gui/$(id -u)/${p(e)} 2>/dev/null`)}catch{}if("linux"===r)try{n(`systemctl --user disable --now ${p(e)}.service 2>/dev/null`)}catch{}try{t.rmSync(i.file,{force:!0}),process.stderr.write(` ◆ removed ${i.file}\n`)}catch(e){process.stderr.write(` ⚠ ${e.message}\n`)}}
package/side-lane.mjs CHANGED
@@ -1 +1 @@
1
- import{buildRecapFromLog as e}from"./recap.mjs";export const SIDE_RECAP_CAP=12e3;export const SIDE_ROLE_PROMPT="You are a ThinkPool side lane attached to a main terminal.\nFocus first on reading, searching, comparing, and answering the side task. You are a full agent and share the main terminal's working directory, so coordinate through ThinkPool Peer before changing files that another lane may be editing. Do not make edits unless a person explicitly asks for them in this side lane. Keep the investigation self-contained; the main terminal receives nothing until a person chooses Bring to main.";export const SIDE_HANDOFF_PROMPT="Prepare a compact handoff for the main terminal now.\nReturn only the handoff. Include: conclusion, strongest evidence, files changed or artifacts produced, and any unresolved question or recommended next action. Do not continue the investigation and do not address the reader conversationally.";export const SIDE_MAIN_TURN_PROMPT="A room member chose Bring to main.\nRead the side-lane handoff below, incorporate the relevant findings into the main lane's current work, and respond now. If the handoff recommends a next step that is already authorized and in scope, take it; otherwise explain the concrete impact on the current work.";export function sideSnapshot(n){return e(Array.isArray(n)?n:[],12e3,{includeCheckpoint:!1})}export function assistantTextSince(e,n=0){const t=[];for(const r of Array.isArray(e)?e:[])if("assistant"===r?.kind&&!(Number.isFinite(n)&&Number.isFinite(r.seq)&&r.seq<=n))for(const e of Array.isArray(r.blocks)?r.blocks:[])"text"===e?.type&&String(e.text||"").trim()&&t.push(String(e.text).trim());return t.join("\n\n").trim()}export function sideContextBlock({sideId:e,sideName:n,task:t,summary:r}){const i=String(n||"Side lane").trim(),o=String(e||"").slice(0,8);return[`--- side-lane handoff: ${i}${o?` (${o})`:""} ---`,t?`Task: ${String(t).trim()}`:"",String(r||"").trim(),"--- end side-lane handoff ---"].filter(Boolean).join("\n")}export function appendSideContext(e,n,t=4){return n?[...Array.isArray(e)?e:[],n].slice(-t):Array.isArray(e)?e.slice(-t):[]}export function sideMainTurnPrompt(e){const n=(Array.isArray(e)?e:[]).filter(Boolean);return n.length?`${SIDE_MAIN_TURN_PROMPT}\n\n${n.join("\n\n")}`:""}export function dispatchSideContexts({contexts:e,busy:n,sendTurn:t}){const r=(Array.isArray(e)?e:[]).filter(Boolean).slice(-4);if(!r.length||n||"function"!=typeof t)return{dispatched:!1,pending:r};const i=sideMainTurnPrompt(r);try{if(!1===t(i))return{dispatched:!1,pending:r}}catch{return{dispatched:!1,pending:r}}return{dispatched:!0,pending:[]}}
1
+ import{buildRecapFromLog as e}from"./recap.mjs";export const SIDE_RECAP_CAP=12e3;export const SIDE_ROLE_PROMPT="You are a thinkpool side lane attached to a main terminal.\nFocus first on reading, searching, comparing, and answering the side task. You are a full agent and share the main terminal's working directory, so coordinate through thinkpool Peer before changing files that another lane may be editing. Do not make edits unless a person explicitly asks for them in this side lane. Keep the investigation self-contained; the main terminal receives nothing until a person chooses Bring to main.";export const SIDE_HANDOFF_PROMPT="Prepare a compact handoff for the main terminal now.\nReturn only the handoff. Include: conclusion, strongest evidence, files changed or artifacts produced, and any unresolved question or recommended next action. Do not continue the investigation and do not address the reader conversationally.";export const SIDE_MAIN_TURN_PROMPT="A room member chose Bring to main.\nRead the side-lane handoff below, incorporate the relevant findings into the main lane's current work, and respond now. If the handoff recommends a next step that is already authorized and in scope, take it; otherwise explain the concrete impact on the current work.";export function sideSnapshot(n){return e(Array.isArray(n)?n:[],12e3,{includeCheckpoint:!1})}export function assistantTextSince(e,n=0){const t=[];for(const r of Array.isArray(e)?e:[])if("assistant"===r?.kind&&!(Number.isFinite(n)&&Number.isFinite(r.seq)&&r.seq<=n))for(const e of Array.isArray(r.blocks)?r.blocks:[])"text"===e?.type&&String(e.text||"").trim()&&t.push(String(e.text).trim());return t.join("\n\n").trim()}export function sideContextBlock({sideId:e,sideName:n,task:t,summary:r}){const i=String(n||"Side lane").trim(),o=String(e||"").slice(0,8);return[`--- side-lane handoff: ${i}${o?` (${o})`:""} ---`,t?`Task: ${String(t).trim()}`:"",String(r||"").trim(),"--- end side-lane handoff ---"].filter(Boolean).join("\n")}export function appendSideContext(e,n,t=4){return n?[...Array.isArray(e)?e:[],n].slice(-t):Array.isArray(e)?e.slice(-t):[]}export function sideMainTurnPrompt(e){const n=(Array.isArray(e)?e:[]).filter(Boolean);return n.length?`${SIDE_MAIN_TURN_PROMPT}\n\n${n.join("\n\n")}`:""}export function dispatchSideContexts({contexts:e,busy:n,sendTurn:t}){const r=(Array.isArray(e)?e:[]).filter(Boolean).slice(-4);if(!r.length||n||"function"!=typeof t)return{dispatched:!1,pending:r};const i=sideMainTurnPrompt(r);try{if(!1===t(i))return{dispatched:!1,pending:r}}catch{return{dispatched:!1,pending:r}}return{dispatched:!0,pending:[]}}
package/terminal-name.mjs CHANGED
@@ -1 +1 @@
1
- import{nativeClaudeProviderAccessFailed as e}from"./cross-terminal.mjs";import t from"compromise/two";const i=new Set(["a","an","and","are","at","be","can","could","for","from","how","i","in","is","it","just","like","maybe","me","my","of","on","or","our","please","something","that","the","this","to","we","with","would","you","do","much","better","really","need","want","your","their","its","also","all","away","before","cause","does","dont","don't","fully","has","have","now","occasionally","return","second","so","sometimes","still","than","then","there","what","when","where","which","who","whenever","why","working"]),s=/^(?:new )?(?:agent |coding )?(?:terminal|task|lane|session|work)$/i,n=/^(?:#{1,6}\s*)?(?:task|goal|objective|request|mission|assignment|problem(?: to solve)?|what to do)(?:\s*:\s*(.*)|\s*)$/i,r=/^(?:#{1,6}\s+|(?:context|background|constraints?|inputs?|outputs?|acceptance|success criteria|steps?|assumptions?|open questions?|notes?|references?|environment)\s*:)/i,o=/^(?:context|background|for reference|here(?:'s| is)|note|current(?:ly)?|example|environment|room now|constraints?|acceptance|success criteria)\b/i,a=/^(?:because|cause|since|so that|this is because)\b/i,l=/^(?:users? can still|keep|must|never|should|without)\b/i,c=/^(?:after|before|by|during|for|from|in|instead(?: of)?|on|through|until|with|without)\b/i,m=/\b(?:broken|buggy|crash(?:es|ed|ing)?|duplicate|error|fail(?:s|ed|ing|ure)?|flash(?:es|ed|ing)?|missing|no animation|not working|out of (?:scrollable )?view|stuck|wrong)\b/i,u=/^(?:please\s+)?(?:can|could|would|will)\s+(?:we|you)\b|^(?:please\s+)?(?:how about|let's|let us|we need to|i want you to)\b/i,p=/(?<![\p{L}\p{N}])(?:sk-(?:proj-)?[a-z0-9_-]{8,}|gsk_[a-z0-9_-]{8,}|xox[baprs]-[a-z0-9_-]{8,}|gh[pousr]_[a-z0-9_-]{8,}|glpat-[a-z0-9_-]{8,}|npm_[a-z0-9]{24,}|(?:sk|rk)_(?:live|test)_[a-z0-9]{8,}|whsec_[a-z0-9]{8,}|AIza[a-z0-9_-]{8,}|AKIA[A-Z0-9]{12,}|bearer\s+[a-z0-9._-]{8,}|eyJ[a-z0-9_-]{8,}\.[a-z0-9_-]{8,}\.[a-z0-9_-]{8,})(?![\p{L}\p{N}])/giu,d=/^---\s*(?:the person's next message|current person request(?:\s*\([^\n]*\))?|side task)\s*---\s*$/gim,g=/^(?:#{1,6}\s*)?CURRENT PERSON REQUEST(?:\s*\([^\n]*\))?\s*:?\s*/gim,b=new Set(["how","what","when","where","which","who","whom","whose","why"]),h=new Set(["avoid","choose","include","need","use","want"]),f=new Set(["avoid","choose","include","use"]),w=e=>new Set([e?.text,e?.normal,e?.machine,e?.implicit].map(e=>String(e||"").trim().toLowerCase()).filter(Boolean)),v=(e,i=null)=>{const s=String(e||"").trim(),n=i||t(s).json({terms:!0}).flatMap(e=>e.terms||[]),r=n.filter(e=>String(e?.text||"").trim()).map(e=>({text:e.text,concepts:w(e),tags:new Set(e.tags||[])})),o=r.some(e=>[...e.concepts].some(e=>b.has(e))),a=r.some(e=>e.tags.has("QuestionWord")),l=n.some(e=>Array.isArray(e?.tags)&&e.tags.includes("Negative")),c=n.some(e=>[...w(e)].some(e=>h.has(e)));return{text:s,visible:r,informationRequest:o&&(a||/\?\s*$/.test(s)),negativePreference:l&&c}},x=Object.freeze([{title:"Fix",score:100,re:/\b(?:fix|fixes|fixed|fixing|repair|repairs|repaired|repairing)\b/i},{title:"Harden",score:98,re:/\b(?:harden|hardens|hardened|hardening)\b/i},{title:"Snap",score:96,re:/\b(?:snap|snaps|snapped|snapping)\b/i},{title:"Improve",score:94,re:/\b(?:improve|improves|improved|improving|optimi[sz](?:e|es|ed|ing)|\bbetter\b)\b/i},{title:"Rework",score:93,re:/\b(?:rework|reworks|reworked|reworking)\b/i},{title:"Implement",score:92,re:/\b(?:implement|implements|implemented|implementing)\b/i},{title:"Build",score:90,re:/\b(?:build|builds|built|building|create|creates|created|creating)\b/i},{title:"Add",score:88,re:/\b(?:add|adds|added|adding|wire|wires|wired|wiring)\b/i},{title:"Replace",score:87,re:/\b(?:replace|replaces|replaced|replacing|migrate|migrates|migrated|migrating)\b/i},{title:"Rename",score:86,re:/\b(?:rename|renames|renamed|renaming)\b/i},{title:"Name",score:85,re:/\b(?:name|names|named|naming)\b/i},{title:"Refactor",score:84,re:/\b(?:refactor|refactors|refactored|refactoring|simplify|simplifies|simplified|simplifying)\b/i},{title:"Remove",score:83,re:/\b(?:remove|removes|removed|removing)\b/i},{title:"Update",score:82,re:/\b(?:update|updates|updated|updating|change|changes|changed|changing)\b/i},{title:"Debug",score:76,re:/\b(?:debug|debugs|debugged|debugging|diagnose|diagnoses|diagnosed|diagnosing|trace|traces|traced|tracing)\b/i},{title:"Audit",score:70,re:/\b(?:audit|audits|audited|auditing|check|checks|checked|checking|investigate|investigates|investigated|investigating|review|reviews|reviewed|reviewing|test|tests|tested|testing|verify|verifies|verified|verifying)\b/i}]),k=e=>{const t=String(e||"");let i=null;for(const e of x){const s=t.match(e.re);if(!s)continue;const n={...e,index:s.index,match:s[0]};(!i||n.score>i.score||n.score===i.score&&n.index<i.index)&&(i=n)}return i},S=e=>String(e||"").replace(p," "),y=e=>{p.lastIndex=0;const t=p.test(String(e||""));return p.lastIndex=0,t},_=e=>(e.replace(/[?#].*$/,"").replace(/[),.;:]+$/,"").split(/[\\/]/).filter(Boolean).at(-1)||"").replace(/\.(?:[cm]?[jt]sx?|tsx?|json|md|html?|css|scss|py|rb|rs|go|java|kt|swift|sh|ya?ml|toml)$/i,"").replace(/[-_.]+/g," "),$=e=>String(e||"").replace(/\bhttps?:\/\/[^\s<>"'`]+/gi," ").replace(/(^|[\s("'`])((?:\.{0,2}\/)[^\s<>"'`]+)/g,(e,t,i)=>`${t}${_(i)}`).replace(/\b[A-Za-z]:\\[^\s<>"'`]+/g,e=>_(e)).replace(/\b(?:[\p{L}\p{N}_.-]+\/)+[\p{L}\p{N}_.-]+\.(?:[cm]?[jt]sx?|tsx?|json|md|html?|css|scss|py|rb|rs|go|java|kt|swift|sh|ya?ml|toml)\b/giu,e=>_(e)),j=e=>{let t=S(String(e||"").slice(0,24e3));const i=[...t.matchAll(d)].at(-1);return i&&(t=t.slice(i.index+i[0].length)),t.replace(/<(?:thinkpool-context|system-reminder|environment_context|recommended_plugins)\b[^>]*>[\s\S]*?<\/(?:thinkpool-context|system-reminder|environment_context|recommended_plugins)>/gi," ").replace(/^\s*\[[^\]\n]{1,300}\]\s*/g,"").replace(/```[^\n]*\n[\s\S]*?(?:```|$)/g," ").replace(/\r/g,"").trim()},z=e=>{const t=e.split("\n"),i=[];for(let e=0;e<t.length;e++){const s=t[e].trim().match(n);if(!s)continue;const o=[];s[1]?.trim()&&o.push(s[1].trim());for(let i=e+1;i<t.length&&o.join(" ").length<1200;i++){const e=t[i].trim();if(r.test(e)||n.test(e))break;e&&o.push(e.replace(/^[-*]\s*/,""))}const a=o.join(" ").trim();a&&i.push(a)}return i.at(-1)||null};export function extractTerminalTask(e){const i=j(e);return i&&(z(i)||(e=>{const i=String(e||"").replace(/,\s*(?:but|however)\s+/gi,"\n").split(/\n+|;\s*/).flatMap(e=>{const i=e.trim();if(!i)return[];const s=t(i).json({terms:!0});return s.length?s.map(e=>v(e.text,e.terms||[])):[v(i)]}).filter(e=>e.text);let s=null;for(const e of i){const t=e.text.replace(/^[-*#>\d.)\s]+/,"").trim();if(!t||/^(?:https?:\/\/|\/|[A-Za-z]:\\)/.test(t))continue;const i=t===e.text?e:v(t),n=k(t);let r=n?.score||0;u.test(t)&&(r+=18),i.informationRequest&&(r+=36),m.test(t)&&(r+=/\b(?:crash|fail|flash|stuck|wrong)\w*\b/i.test(t)?36:26),i.visible.length>=3&&i.visible.length<=24?r+=10:i.visible.length>40&&(r-=14),o.test(t)&&(r-=30),a.test(t)&&(r-=34),l.test(t)&&(r-=45),i.negativePreference&&(r-=70),n||u.test(t)||i.informationRequest||!c.test(t)||(r-=24),(!s||r>s.score)&&(s={clause:t,score:r})}return s?.clause||i[0]?.text||null})(i)||i).slice(0,1600).trim()||null}export function cleanTerminalName(t){const i=String(t||"");if(y(i))return null;let n=i.trim().split(/\r?\n/,1)[0].replace(/^\s*(?:[-*#>]+|title\s*:?)\s*/i,"").replace(/^["'`]+|["'`]+$/g,"").replace(/[^\p{L}\p{N}+#&.' -]+/gu," ").replace(/\s+/g," ").replace(/[.,;:!?]+$/u,"").trim();if(!n||s.test(n)||e(n))return null;if(/^(?:error|failed|sorry|unable|i (?:cannot|can't)|rate limit|request failed)\b/i.test(n))return null;n.length>48&&(n=n.slice(0,48).replace(/\s+\S*$/,"").trim());const r=n.split(/\s+/).filter(Boolean),o=1===r.length&&/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u.test(n);return r.length<2&&!o||r.length>3?null:n||null}const N=e=>{const t=e.toLowerCase();return"thinkpool"===t||"thinkpool.io"===t?"ThinkPool":"serverside"===t?"Server-Side":/^(?:api|ci|css|db|html|llm|mcp|npm|sdk|ui|ux)$/i.test(e)?t.toUpperCase():/^[A-Z\d+#.-]{2,}$/.test(e)||/\d/.test(e)?e:e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()},A=(e,t=[])=>{const s=String(e||"").match(/[\p{L}\p{N}][\p{L}\p{N}+#.'-]*/gu)||[],n=new Set,r=[];for(let e of s){const s=e.toLowerCase();if(i.has(s)||/^https?$/i.test(e))continue;if(t.some(t=>t.test(e)))continue;"flashes"!==s&&"flashing"!==s||(e="flash"),"failing"!==s&&"failed"!==s&&"fails"!==s||(e="failure");const o=e.toLowerCase().replace(/(?:s|ed|ing)$/i,"");o&&!n.has(o)&&(n.add(o),r.push(e))}return r};export function fallbackTerminalName(e){return(e=>{let t=String(e||"").replace(/^\s*(?:hey|hi|okay|ok|so)\b[,:!]?\s*/i,"").replace(/^\s*(?:return to (?:working on )?|can|could|would|will)\s+(?:we\s+|you\s+)?/i,"").replace(/^\s*(?:how about|i (?:do not|don't) know|i guess|i want you to|we need to|your task is to|let(?:'s| us))\s+/i,"").trim();if(!t)return null;const i=v(t);if(i.negativePreference){const e=A((e=>{let t=-1;for(let i=0;i<e.visible.length;i++)[...e.visible[i].concepts].some(e=>f.has(e))&&(t=i);return t<0&&(t=e.visible.findIndex(e=>[...e.concepts].some(e=>"need"===e||"want"===e))),t>=0?e.visible.slice(t+1).map(e=>e.text).join(" "):e.text})(i)).slice(0,2);return e.length?cleanTerminalName(["Avoid",...e.map(N)].join(" ")):null}const s=i.informationRequest;s&&(t=(e=>{const t=e.visible.findIndex(e=>[...e.concepts].some(e=>b.has(e)));return t>=0?e.visible.slice(t+1).map(e=>e.text).join(" "):e.text})(i).trim());const n=t;t=t.replace(/\s*,?\s+(?:so (?:that|you|we|it)\b|because\b|cause\b|if you know what i mean\b)[\s\S]*$/i,"").replace(/\s+for\s+(?:a|an|one|\d+)\s+(?:moment|second|minute|hour)s?\b[\s\S]*$/i,"").trim();const r=m.test(t),o=k(t);let a=r?"Fix":o?.title;if(!a&&/\bclos(?:e|es|ed|ing)\b/i.test(t)&&(a="Close"),!a&&/\bopen(?:s|ed|ing)?\b/i.test(t)&&(a="Open"),/\bautomatic(?:ally)?\b[\s\S]{0,24}\bnam(?:e|ing)\b/i.test(n)&&/\bterminals?\b/i.test(n)){if(/\bcontext\b[\s\S]{0,24}\broom\b|\broom\b[\s\S]{0,24}\bcontext\b/i.test(n))return"Contextual Terminal Names";a="Auto-Name"}if("Snap"===a&&/\bterminal row\b/i.test(n)&&/\bview\b/i.test(n))return"Snap Terminal Row";if("Snap"===a&&/\bclicked terminal\b/i.test(n)&&/\bview\b/i.test(n))return"Snap Clicked Terminal";let l=[],c=t;if(o){const e=t.slice(0,o.index);c=t.slice(o.index+o.match.length);const i=k(e);i?.score<=76&&(l=A(e.slice(i.index+i.match.length),[i.re]).slice(0,3)),c=c.split(/\s*,?\s+(?:and|then)\s+(?:(?:also)\s+)?(?=(?:add|build|create|implement|remove|replace|update|wire)\b)/i,1)[0],c=c.replace(/\b(?:and|then)\s+(?:audit|check|debug|investigate|review|test|verify)\b/gi," ")}const u=o?[o.re]:[];let p=A(c,u);if(p.length||(p=A(t,u)),s){const e=p.findIndex(e=>/^available$/i.test(e));e>0&&(p=[p[e],...p.slice(0,e),...p.slice(e+1)])}const d=[...l,...p].filter((e,t,i)=>i.findIndex(t=>t.toLowerCase()===e.toLowerCase())===t).slice(0,a?2:3);return d.length?cleanTerminalName([a,...d.map(N)].filter(Boolean).join(" ")):null})($(S(extractTerminalTask(e)||"")).replace(/[`*_>#()[\]{}]/g," ").slice(0,1600))}export function modelTerminalNameInput(e){const t=$(S((e=>{let t=j(e);if(!t)return null;const i=[...t.matchAll(g)].at(-1);return i&&(t=t.slice(i.index+i[0].length)),(z(t)||t).trim()||null})(e)||"")).replace(/[`*_>#()[\]{}]/g," ").replace(/\s+/g," ").trim();return!t||y(t)?null:((e,t=1600)=>{let i="",s=0;for(const n of String(e||"")){const e=Buffer.byteLength(n,"utf8");if(s+e>t)break;i+=n,s+=e}return i.trim()})(t)}
1
+ import{nativeClaudeProviderAccessFailed as e}from"./cross-terminal.mjs";import t from"compromise/two";const i=new Set(["a","an","and","are","at","be","can","could","for","from","how","i","in","is","it","just","like","maybe","me","my","of","on","or","our","please","something","that","the","this","to","we","with","would","you","do","much","better","really","need","want","your","their","its","also","all","away","before","cause","does","dont","don't","fully","has","have","now","occasionally","return","second","so","sometimes","still","than","then","there","what","when","where","which","who","whenever","why","working"]),s=/^(?:new )?(?:agent |coding )?(?:terminal|task|lane|session|work)$/i,n=/^(?:#{1,6}\s*)?(?:task|goal|objective|request|mission|assignment|problem(?: to solve)?|what to do)(?:\s*:\s*(.*)|\s*)$/i,r=/^(?:#{1,6}\s+|(?:context|background|constraints?|inputs?|outputs?|acceptance|success criteria|steps?|assumptions?|open questions?|notes?|references?|environment)\s*:)/i,o=/^(?:context|background|for reference|here(?:'s| is)|note|current(?:ly)?|example|environment|room now|constraints?|acceptance|success criteria)\b/i,a=/^(?:because|cause|since|so that|this is because)\b/i,l=/^(?:users? can still|keep|must|never|should|without)\b/i,c=/^(?:after|before|by|during|for|from|in|instead(?: of)?|on|through|until|with|without)\b/i,m=/\b(?:broken|buggy|crash(?:es|ed|ing)?|duplicate|error|fail(?:s|ed|ing|ure)?|flash(?:es|ed|ing)?|missing|no animation|not working|out of (?:scrollable )?view|stuck|wrong)\b/i,u=/^(?:please\s+)?(?:can|could|would|will)\s+(?:we|you)\b|^(?:please\s+)?(?:how about|let's|let us|we need to|i want you to)\b/i,p=/(?<![\p{L}\p{N}])(?:sk-(?:proj-)?[a-z0-9_-]{8,}|gsk_[a-z0-9_-]{8,}|xox[baprs]-[a-z0-9_-]{8,}|gh[pousr]_[a-z0-9_-]{8,}|glpat-[a-z0-9_-]{8,}|npm_[a-z0-9]{24,}|(?:sk|rk)_(?:live|test)_[a-z0-9]{8,}|whsec_[a-z0-9]{8,}|AIza[a-z0-9_-]{8,}|AKIA[A-Z0-9]{12,}|bearer\s+[a-z0-9._-]{8,}|eyJ[a-z0-9_-]{8,}\.[a-z0-9_-]{8,}\.[a-z0-9_-]{8,})(?![\p{L}\p{N}])/giu,d=/^---\s*(?:the person's next message|current person request(?:\s*\([^\n]*\))?|side task)\s*---\s*$/gim,g=/^(?:#{1,6}\s*)?CURRENT PERSON REQUEST(?:\s*\([^\n]*\))?\s*:?\s*/gim,b=new Set(["how","what","when","where","which","who","whom","whose","why"]),h=new Set(["avoid","choose","include","need","use","want"]),f=new Set(["avoid","choose","include","use"]),w=e=>new Set([e?.text,e?.normal,e?.machine,e?.implicit].map(e=>String(e||"").trim().toLowerCase()).filter(Boolean)),v=(e,i=null)=>{const s=String(e||"").trim(),n=i||t(s).json({terms:!0}).flatMap(e=>e.terms||[]),r=n.filter(e=>String(e?.text||"").trim()).map(e=>({text:e.text,concepts:w(e),tags:new Set(e.tags||[])})),o=r.some(e=>[...e.concepts].some(e=>b.has(e))),a=r.some(e=>e.tags.has("QuestionWord")),l=n.some(e=>Array.isArray(e?.tags)&&e.tags.includes("Negative")),c=n.some(e=>[...w(e)].some(e=>h.has(e)));return{text:s,visible:r,informationRequest:o&&(a||/\?\s*$/.test(s)),negativePreference:l&&c}},x=Object.freeze([{title:"Fix",score:100,re:/\b(?:fix|fixes|fixed|fixing|repair|repairs|repaired|repairing)\b/i},{title:"Harden",score:98,re:/\b(?:harden|hardens|hardened|hardening)\b/i},{title:"Snap",score:96,re:/\b(?:snap|snaps|snapped|snapping)\b/i},{title:"Improve",score:94,re:/\b(?:improve|improves|improved|improving|optimi[sz](?:e|es|ed|ing)|\bbetter\b)\b/i},{title:"Rework",score:93,re:/\b(?:rework|reworks|reworked|reworking)\b/i},{title:"Implement",score:92,re:/\b(?:implement|implements|implemented|implementing)\b/i},{title:"Build",score:90,re:/\b(?:build|builds|built|building|create|creates|created|creating)\b/i},{title:"Add",score:88,re:/\b(?:add|adds|added|adding|wire|wires|wired|wiring)\b/i},{title:"Replace",score:87,re:/\b(?:replace|replaces|replaced|replacing|migrate|migrates|migrated|migrating)\b/i},{title:"Rename",score:86,re:/\b(?:rename|renames|renamed|renaming)\b/i},{title:"Name",score:85,re:/\b(?:name|names|named|naming)\b/i},{title:"Refactor",score:84,re:/\b(?:refactor|refactors|refactored|refactoring|simplify|simplifies|simplified|simplifying)\b/i},{title:"Remove",score:83,re:/\b(?:remove|removes|removed|removing)\b/i},{title:"Update",score:82,re:/\b(?:update|updates|updated|updating|change|changes|changed|changing)\b/i},{title:"Debug",score:76,re:/\b(?:debug|debugs|debugged|debugging|diagnose|diagnoses|diagnosed|diagnosing|trace|traces|traced|tracing)\b/i},{title:"Audit",score:70,re:/\b(?:audit|audits|audited|auditing|check|checks|checked|checking|investigate|investigates|investigated|investigating|review|reviews|reviewed|reviewing|test|tests|tested|testing|verify|verifies|verified|verifying)\b/i}]),k=e=>{const t=String(e||"");let i=null;for(const e of x){const s=t.match(e.re);if(!s)continue;const n={...e,index:s.index,match:s[0]};(!i||n.score>i.score||n.score===i.score&&n.index<i.index)&&(i=n)}return i},S=e=>String(e||"").replace(p," "),y=e=>{p.lastIndex=0;const t=p.test(String(e||""));return p.lastIndex=0,t},_=e=>(e.replace(/[?#].*$/,"").replace(/[),.;:]+$/,"").split(/[\\/]/).filter(Boolean).at(-1)||"").replace(/\.(?:[cm]?[jt]sx?|tsx?|json|md|html?|css|scss|py|rb|rs|go|java|kt|swift|sh|ya?ml|toml)$/i,"").replace(/[-_.]+/g," "),$=e=>String(e||"").replace(/\bhttps?:\/\/[^\s<>"'`]+/gi," ").replace(/(^|[\s("'`])((?:\.{0,2}\/)[^\s<>"'`]+)/g,(e,t,i)=>`${t}${_(i)}`).replace(/\b[A-Za-z]:\\[^\s<>"'`]+/g,e=>_(e)).replace(/\b(?:[\p{L}\p{N}_.-]+\/)+[\p{L}\p{N}_.-]+\.(?:[cm]?[jt]sx?|tsx?|json|md|html?|css|scss|py|rb|rs|go|java|kt|swift|sh|ya?ml|toml)\b/giu,e=>_(e)),j=e=>{let t=S(String(e||"").slice(0,24e3));const i=[...t.matchAll(d)].at(-1);return i&&(t=t.slice(i.index+i[0].length)),t.replace(/<(?:thinkpool-context|system-reminder|environment_context|recommended_plugins)\b[^>]*>[\s\S]*?<\/(?:thinkpool-context|system-reminder|environment_context|recommended_plugins)>/gi," ").replace(/^\s*\[[^\]\n]{1,300}\]\s*/g,"").replace(/```[^\n]*\n[\s\S]*?(?:```|$)/g," ").replace(/\r/g,"").trim()},z=e=>{const t=e.split("\n"),i=[];for(let e=0;e<t.length;e++){const s=t[e].trim().match(n);if(!s)continue;const o=[];s[1]?.trim()&&o.push(s[1].trim());for(let i=e+1;i<t.length&&o.join(" ").length<1200;i++){const e=t[i].trim();if(r.test(e)||n.test(e))break;e&&o.push(e.replace(/^[-*]\s*/,""))}const a=o.join(" ").trim();a&&i.push(a)}return i.at(-1)||null};export function extractTerminalTask(e){const i=j(e);return i&&(z(i)||(e=>{const i=String(e||"").replace(/,\s*(?:but|however)\s+/gi,"\n").split(/\n+|;\s*/).flatMap(e=>{const i=e.trim();if(!i)return[];const s=t(i).json({terms:!0});return s.length?s.map(e=>v(e.text,e.terms||[])):[v(i)]}).filter(e=>e.text);let s=null;for(const e of i){const t=e.text.replace(/^[-*#>\d.)\s]+/,"").trim();if(!t||/^(?:https?:\/\/|\/|[A-Za-z]:\\)/.test(t))continue;const i=t===e.text?e:v(t),n=k(t);let r=n?.score||0;u.test(t)&&(r+=18),i.informationRequest&&(r+=36),m.test(t)&&(r+=/\b(?:crash|fail|flash|stuck|wrong)\w*\b/i.test(t)?36:26),i.visible.length>=3&&i.visible.length<=24?r+=10:i.visible.length>40&&(r-=14),o.test(t)&&(r-=30),a.test(t)&&(r-=34),l.test(t)&&(r-=45),i.negativePreference&&(r-=70),n||u.test(t)||i.informationRequest||!c.test(t)||(r-=24),(!s||r>s.score)&&(s={clause:t,score:r})}return s?.clause||i[0]?.text||null})(i)||i).slice(0,1600).trim()||null}export function cleanTerminalName(t){const i=String(t||"");if(y(i))return null;let n=i.trim().split(/\r?\n/,1)[0].replace(/^\s*(?:[-*#>]+|title\s*:?)\s*/i,"").replace(/^["'`]+|["'`]+$/g,"").replace(/[^\p{L}\p{N}+#&.' -]+/gu," ").replace(/\s+/g," ").replace(/[.,;:!?]+$/u,"").trim();if(!n||s.test(n)||e(n))return null;if(/^(?:error|failed|sorry|unable|i (?:cannot|can't)|rate limit|request failed)\b/i.test(n))return null;n.length>48&&(n=n.slice(0,48).replace(/\s+\S*$/,"").trim());const r=n.split(/\s+/).filter(Boolean),o=1===r.length&&/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u.test(n);return r.length<2&&!o||r.length>3?null:n||null}const N=e=>{const t=e.toLowerCase();return"thinkpool"===t||"thinkpool.io"===t?"thinkpool":"serverside"===t?"Server-Side":/^(?:api|ci|css|db|html|llm|mcp|npm|sdk|ui|ux)$/i.test(e)?t.toUpperCase():/^[A-Z\d+#.-]{2,}$/.test(e)||/\d/.test(e)?e:e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()},A=(e,t=[])=>{const s=String(e||"").match(/[\p{L}\p{N}][\p{L}\p{N}+#.'-]*/gu)||[],n=new Set,r=[];for(let e of s){const s=e.toLowerCase();if(i.has(s)||/^https?$/i.test(e))continue;if(t.some(t=>t.test(e)))continue;"flashes"!==s&&"flashing"!==s||(e="flash"),"failing"!==s&&"failed"!==s&&"fails"!==s||(e="failure");const o=e.toLowerCase().replace(/(?:s|ed|ing)$/i,"");o&&!n.has(o)&&(n.add(o),r.push(e))}return r};export function fallbackTerminalName(e){return(e=>{let t=String(e||"").replace(/^\s*(?:hey|hi|okay|ok|so)\b[,:!]?\s*/i,"").replace(/^\s*(?:return to (?:working on )?|can|could|would|will)\s+(?:we\s+|you\s+)?/i,"").replace(/^\s*(?:how about|i (?:do not|don't) know|i guess|i want you to|we need to|your task is to|let(?:'s| us))\s+/i,"").trim();if(!t)return null;const i=v(t);if(i.negativePreference){const e=A((e=>{let t=-1;for(let i=0;i<e.visible.length;i++)[...e.visible[i].concepts].some(e=>f.has(e))&&(t=i);return t<0&&(t=e.visible.findIndex(e=>[...e.concepts].some(e=>"need"===e||"want"===e))),t>=0?e.visible.slice(t+1).map(e=>e.text).join(" "):e.text})(i)).slice(0,2);return e.length?cleanTerminalName(["Avoid",...e.map(N)].join(" ")):null}const s=i.informationRequest;s&&(t=(e=>{const t=e.visible.findIndex(e=>[...e.concepts].some(e=>b.has(e)));return t>=0?e.visible.slice(t+1).map(e=>e.text).join(" "):e.text})(i).trim());const n=t;t=t.replace(/\s*,?\s+(?:so (?:that|you|we|it)\b|because\b|cause\b|if you know what i mean\b)[\s\S]*$/i,"").replace(/\s+for\s+(?:a|an|one|\d+)\s+(?:moment|second|minute|hour)s?\b[\s\S]*$/i,"").trim();const r=m.test(t),o=k(t);let a=r?"Fix":o?.title;if(!a&&/\bclos(?:e|es|ed|ing)\b/i.test(t)&&(a="Close"),!a&&/\bopen(?:s|ed|ing)?\b/i.test(t)&&(a="Open"),/\bautomatic(?:ally)?\b[\s\S]{0,24}\bnam(?:e|ing)\b/i.test(n)&&/\bterminals?\b/i.test(n)){if(/\bcontext\b[\s\S]{0,24}\broom\b|\broom\b[\s\S]{0,24}\bcontext\b/i.test(n))return"Contextual Terminal Names";a="Auto-Name"}if("Snap"===a&&/\bterminal row\b/i.test(n)&&/\bview\b/i.test(n))return"Snap Terminal Row";if("Snap"===a&&/\bclicked terminal\b/i.test(n)&&/\bview\b/i.test(n))return"Snap Clicked Terminal";let l=[],c=t;if(o){const e=t.slice(0,o.index);c=t.slice(o.index+o.match.length);const i=k(e);i?.score<=76&&(l=A(e.slice(i.index+i.match.length),[i.re]).slice(0,3)),c=c.split(/\s*,?\s+(?:and|then)\s+(?:(?:also)\s+)?(?=(?:add|build|create|implement|remove|replace|update|wire)\b)/i,1)[0],c=c.replace(/\b(?:and|then)\s+(?:audit|check|debug|investigate|review|test|verify)\b/gi," ")}const u=o?[o.re]:[];let p=A(c,u);if(p.length||(p=A(t,u)),s){const e=p.findIndex(e=>/^available$/i.test(e));e>0&&(p=[p[e],...p.slice(0,e),...p.slice(e+1)])}const d=[...l,...p].filter((e,t,i)=>i.findIndex(t=>t.toLowerCase()===e.toLowerCase())===t).slice(0,a?2:3);return d.length?cleanTerminalName([a,...d.map(N)].filter(Boolean).join(" ")):null})($(S(extractTerminalTask(e)||"")).replace(/[`*_>#()[\]{}]/g," ").slice(0,1600))}export function modelTerminalNameInput(e){const t=$(S((e=>{let t=j(e);if(!t)return null;const i=[...t.matchAll(g)].at(-1);return i&&(t=t.slice(i.index+i[0].length)),(z(t)||t).trim()||null})(e)||"")).replace(/[`*_>#()[\]{}]/g," ").replace(/\s+/g," ").trim();return!t||y(t)?null:((e,t=1600)=>{let i="",s=0;for(const n of String(e||"")){const e=Buffer.byteLength(n,"utf8");if(s+e>t)break;i+=n,s+=e}return i.trim()})(t)}