thinkpool-pair 0.7.438 → 0.7.439

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/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 s,supervisorReadyMatches as o}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;"),m=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 ${m(r.join(e,"_npx"))}/* 2>/dev/null`,$=(()=>{try{return JSON.parse(t.readFileSync(new URL("./package.json",import.meta.url),"utf8")).version}catch{return"latest"}})(),g=/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/,v=/^(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)\.install-(\d+)-(\d+)$/,y=36e5;function b(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}}function k(e,t=process.kill){if(!Number.isSafeInteger(e)||e<1)return!1;try{return t(e,0),!0}catch(e){return"ESRCH"!==e?.code}}export function runtimeDiskDecision(e,{env:t=process.env}={}){if("1"===t.TP_RUNTIME_DISK_GUARD_OFF)return{ok:!0,source:"disabled",availableBytes:e};const r=Number(t.TP_RUNTIME_DISK_MIN_MIB),n=1024*Math.max(512,Number.isFinite(r)?r:4096)*1024;return Number.isFinite(e)?{ok:e>=n,source:"statfs",availableBytes:e,minimumBytes:n}:{ok:!0,source:"unavailable",availableBytes:null,minimumBytes:n}}export function hostRuntimeDiskAdmission(e,r,{statfs:n=t.statfsSync,env:i=process.env}={}){try{const t=n(e),s=runtimeDiskDecision(Number(t.bavail)*Number(t.bsize),{env:i});if(s.ok)return s;const o=Math.max(0,s.availableBytes/1073741824).toFixed(1),a=(s.minimumBytes/1073741824).toFixed(1);return{...s,reason:`Host disk space is critically low (${o} GiB available; ${a} GiB required). thinkpool did not ${r}.`}}catch{return{ok:!0,source:"unavailable",availableBytes:null}}}export function runtimeRetentionPlan(e,{protectedVersions:n=[],retainRecent:i=2,now:s=Date.now(),signal:o=process.kill}={}){let a;try{a=t.readdirSync(e)}catch(e){if("ENOENT"===e?.code)return[];throw e}const l=new Set([...n].filter(e=>g.test(String(e)))),c=[],d=[];for(const n of a){const i=r.join(e,n);let a;try{a=t.lstatSync(i)}catch{continue}if(!a.isDirectory()||a.isSymbolicLink())continue;if(g.test(n)){b(r.join(i,"node_modules","thinkpool-pair","bridge.mjs"))===n?c.push({name:n,mtimeMs:a.mtimeMs}):s-a.mtimeMs>=y&&!l.has(n)&&d.push(n);continue}const p=n.match(v);!p||s-a.mtimeMs<y||k(Number(p[2]),o)||d.push(n)}c.sort((e,t)=>t.mtimeMs-e.mtimeMs||t.name.localeCompare(e.name));for(const e of c.slice(0,Math.max(0,Number(i)||0)))l.add(e.name);return[...c.filter(e=>!l.has(e.name)).map(e=>e.name),...d].sort()}export function pruneProvisionedRuntimes(e,n={}){const i=[];for(const s of runtimeRetentionPlan(e,n)){const n=r.join(e,s),o=t.lstatSync(n);o.isDirectory()&&!o.isSymbolicLink()&&r.dirname(t.realpathSync(n))===t.realpathSync(e)&&(t.rmSync(n,{recursive:!0,force:!1}),i.push(s))}return i}export function provisionRuntime(s,{exec:o=n,root:a=r.join(e.homedir(),".thinkpool-pair","runtimes"),admit:l=i,disk:c=hostRuntimeDiskAdmission,protectedVersions:d=[]}={}){if(!g.test(String(s)))throw new Error(`invalid runtime version: ${s}`);t.mkdirSync(a,{recursive:!0});const p=function(e,{now:n=Date.now,signal:i=process.kill}={}){const s=r.join(e,".provision.lock"),o=`${process.pid}-${n()}-${Math.random().toString(16).slice(2)}`,a=()=>{const e=t.openSync(s,"wx",384);try{t.writeFileSync(e,JSON.stringify({pid:process.pid,createdAt:n(),token:o}))}catch(r){t.closeSync(e);try{t.unlinkSync(s)}catch{}throw r}return e};let l;try{l=a()}catch(e){if("EEXIST"!==e?.code)throw e;let r=!1;try{const e=JSON.parse(t.readFileSync(s,"utf8")),o=Number.isFinite(Number(e.createdAt))?Number(e.createdAt):t.lstatSync(s).mtimeMs;r=n()-o>=y&&!k(Number(e.pid),i)}catch{try{r=n()-t.lstatSync(s).mtimeMs>=y}catch{r=!1}}if(!r)throw new Error("another bridge runtime update is already in progress");t.unlinkSync(s),l=a()}return()=>{try{t.closeSync(l)}catch{}try{JSON.parse(t.readFileSync(s,"utf8")).token===o&&t.unlinkSync(s)}catch{}}}(a);try{const e=pruneProvisionedRuntimes(a,{protectedVersions:[...d,$,String(s)]});e.length&&process.stderr.write(` ◆ removed ${e.length} obsolete bridge runtime${1===e.length?"":"s"}\n`);const n=r.join(a,String(s)),i=r.join(n,"node_modules","thinkpool-pair","bridge.mjs");if(t.existsSync(i)&&b(i)===String(s))return i;const p=c(a,"stage a bridge runtime update");if(!p?.ok)throw new Error(p?.reason||"host disk space is critically low");const u=l("stage a bridge runtime update");if(!u?.ok)throw new Error(u?.reason||"host memory is critically low");const f=`${n}.install-${process.pid}-${Date.now()}`;t.rmSync(f,{recursive:!0,force:!0}),t.mkdirSync(f,{recursive:!0});const h=`https://registry.npmjs.org/thinkpool-pair/-/thinkpool-pair-${s}.tgz`,g=r.join(f,"node_modules","thinkpool-pair","bridge.mjs");try{o(`${m(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 ${m(f)} ${m(h)} --prefer-online --no-audit --no-fund`,{stdio:"inherit",shell:"/bin/bash"});const e=b(g);if(!t.existsSync(g)||e!==String(s))throw new Error(`runtime verification failed: requested ${s}, installed ${e||"no valid package"}`);t.rmSync(n,{recursive:!0,force:!0}),t.renameSync(f,n)}catch(e){throw t.rmSync(f,{recursive:!0,force:!0}),e}return i}finally{p()}}export function buildArtifact(n,{room:i=null,cmdArgs:s=[],autoUpdate:o=!1,version:a=$,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(),b=u(i),k=r.join(e.homedir(),".thinkpool-pair"),S=r.join(k,`${b}.log`),w=sanitizeServicePath(process.env.PATH||"",n),_=r.join(e.homedir(),".thinkpool-pair","npm-cache"),x=s.length?["--",...s]:[],E=i?`bridge (${i})`:"account bridge",A=o?"thinkpool-pair@latest":`thinkpool-pair@${a}`,P=o||l?["--prefer-online"]:[],D=i?["-y",...P,A,i]:["-y",...P,A],N=!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=${m(_)}; exec ${[v,...D,...x].map(m).join(" ")}`]:[v,...D,...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(S)}</string>\n <key>StandardErrorPath</key><string>${f(S)}</string>\n <key>EnvironmentVariables</key><dict><key>PATH</key><string>${f(w)}</string>${d?"":`<key>NPM_CONFIG_CACHE</key><string>${f(_)}</string>`}${o?"<key>THINKPOOL_PAIR_AUTOUPDATE</key><string>1</string>":""}${N.darwin}</dict>\n</dict></plist>\n`,logDir:k,post:[],expectedRuntime:d||A,note:"Loaded as a LaunchAgent — starts at login, restarts on crash."}}if("linux"===n){const t=d?[process.execPath,d,...i?[i]:[],...x]:[v,...D,...x];return{file:r.join(e.homedir(),".config","systemd","user",`${p(i)}.service`),content:`[Unit]\nDescription=thinkpool Code ${E}\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=${m(_)}; exec ${[v,...D,...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=${w}\n${d?"":`Environment=NPM_CONFIG_CACHE=${_}\n`}${o?"Environment=THINKPOOL_PAIR_AUTOUPDATE=1\n":""}${N.linux}StandardOutput=append:${S}\nStandardError=append:${S}\n\n[Install]\nWantedBy=default.target\n`,logDir:k,post:["systemctl --user daemon-reload",`systemctl --user enable ${p(i)}.service`,`systemctl --user restart ${p(i)}.service`],expectedRuntime:d||A,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-${b}.cmd`),s=d?[process.execPath,d,...i?[i,"--supervise"]:[],...x].map(e=>`"${e}"`).join(" "):i?["npx","-y",...P,A,i,"--supervise",...x].join(" "):["npx","-y",...P,A].join(" ");return{file:n,content:`@echo off\r\ntitle thinkpool-pair ${b}\r\n${d?"":`set "NPM_CONFIG_CACHE=${_}"\r\n`}${N.win32}${s}\r\n`,logDir:k,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 artifactScheduledRunsEnabled(e,t){const r=String(t||"");return"darwin"===e?/<key>\s*TP_SCHEDULED_RUNS_ENABLED\s*<\/key>\s*<string>\s*1\s*<\/string>/.test(r):"linux"===e?/^Environment=TP_SCHEDULED_RUNS_ENABLED=1\r?$/m.test(r):"win32"===e&&/^set "TP_SCHEDULED_RUNS_ENABLED=1"\r?$/m.test(r)}export function installedScheduledRunsEnabled(e,{platform:r=process.platform,readFile:n=e=>t.readFileSync(e,"utf8")}={}){try{return artifactScheduledRunsEnabled(r,n(buildArtifact(r,{room:e,scheduledRuns:!1}).file))}catch{return!1}}export function installedServiceRuntimeVersion(e,{platform:r=process.platform,readFile:n=e=>t.readFileSync(e,"utf8")}={}){try{const t=parseRunningPairVersions(n(buildArtifact(r,{room:e}).file));return 1===t.size?[...t][0]:null}catch{return null}}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},s=p(e);try{if("darwin"===t){const e=r(`launchctl print gui/$(id -u)/${s}`,{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 ${s}.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:s,version:o,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(o)))throw new Error(`invalid runtime version: ${o}`);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"),$=r.join(e.homedir(),".thinkpool-pair","account-ready.json"),g=t===p(null),v=["set -u",'dom="gui/$(id -u)"',`target=${m(t)}`,`helper=${m(l)}`,`target_file=${m(n)}`,`staged_file=${m(i)}`,`backup_file=${m(d)}`,`helper_file=${m(c)}`,`expected=${m(s)}`,`version=${m(o)}`,`status=${m(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(o),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(o),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(o),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:s,version:o,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(o)))throw new Error(`invalid runtime version: ${o}`);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=${m(t)}`,'unit="$target.service"',`target_file=${m(n)}`,`staged_file=${m(i)}`,`backup_file=${m(c)}`,`expected=${m(s)}`,`version=${m(o)}`,`status=${m(d)}`,`ready=${m(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(o),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(o),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(o),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 S=()=>r.join(e.homedir(),".thinkpool-pair","account.lock"),w=e=>{try{return process.kill(e,0),!0}catch(e){return"EPERM"===e?.code}};export async function retireUnmanagedBridgeLock({lockFile:e=S(),readLock:r=()=>t.readFileSync(e,"utf8"),removeLock:i=()=>t.rmSync(e,{force:!0}),commandForPid:s=e=>String(n(`ps -p ${e} -o command=`,{encoding:"utf8",stdio:["ignore","pipe","ignore"]})),alive:o=w,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(o(u))return!1;try{(parseInt(String(r()).trim(),10)||0)===u&&i()}catch{}return!0};if(!u||u===process.pid||f())return!0;let m="";try{m=s(u)}catch{return f()}if(!/(?:node_modules[\\/]thinkpool-pair|\.npm[\\/]_npx|\.thinkpool-pair[\\/]runtimes)[\\/][^\n]*bridge\.mjs(?:\s|$)/.test(m))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 _(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:s=t}={}){const o=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&&o.add(e)}}catch{}try{const t=r.join(e.homedir(),"Library","LaunchAgents");for(const e of s.readdirSync(t)){const t=e.match(/^(io\.thinkpool\.pair\.[A-Za-z0-9_]+)\.plist$/);t&&o.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&&o.add(e)}}catch{}try{const t=r.join(e.homedir(),".config","systemd","user");for(const e of s.readdirSync(t)){const t=e.match(/^(io\.thinkpool\.pair\.[A-Za-z0-9_]+)\.service$/);t&&o.add(t[1])}}catch{}}}catch{}return[...o]}export function sweepExistingServices(i,s=process.platform){for(const o of existingServiceLabels(s))if(o!==i)try{if("darwin"===s){n(`launchctl bootout gui/$(id -u)/${o} 2>/dev/null || true`,{stdio:"ignore",shell:"/bin/bash"});try{t.rmSync(r.join(e.homedir(),"Library","LaunchAgents",`${o}.plist`),{force:!0})}catch{}}else"linux"===s&&n(`systemctl --user disable --now ${o}.service 2>/dev/null || true`,{stdio:"ignore",shell:"/bin/bash"});process.stderr.write(` ◆ swept stale service ${o}\n`)}catch{}if("win32"!==s)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:s=!1,version:o=$,staleProof:d=!0}={}){let f=null;if(!s){const t=installedServiceRuntimeVersion(e),r=serviceRuntimeVersion(e);try{f=provisionRuntime(o,{protectedVersions:[t,r]})}catch(e){return process.stderr.write(` ⚠ runtime install failed; service left unchanged: ${e.message}\n`),!1}}const h=c()||installedScheduledRunsEnabled(e),g=buildArtifact(process.platform,{room:e,cmdArgs:i,autoUpdate:s,version:o,staleProof:d,runtimeEntry:f,scheduledRuns:h});try{sweepExistingServices(p(e),process.platform)}catch{}if(t.mkdirSync(g.logDir,{recursive:!0}),t.mkdirSync(r.dirname(g.file),{recursive:!0}),"darwin"===process.platform){if(process.stderr.write(`\n ◆ staged replacement for ${g.file}\n`),!function(e,i){const s=r.join(e.logDir,`service-update-${process.pid}-${Date.now()}.plist`),o=buildDarwinReloadHandoff({targetLabel:_(e.file),targetFile:e.file,stagedFile:s,expectedRuntime:e.expectedRuntime,version:i});t.mkdirSync(r.dirname(o.helperFile),{recursive:!0}),t.mkdirSync(r.dirname(o.statusFile),{recursive:!0}),t.rmSync(o.statusFile,{force:!0}),t.writeFileSync(s,e.content),t.writeFileSync(o.helperFile,o.content);try{return n(`launchctl bootstrap gui/$(id -u) ${m(o.helperFile)}`,{stdio:"inherit",shell:"/bin/bash"}),process.stderr.write(` ◆ update handoff armed outside the bridge process tree — completion is recorded in ${o.statusFile}.\n`),!0}catch(e){return t.rmSync(s,{force:!0}),t.rmSync(o.helperFile,{force:!0}),process.stderr.write(` ⚠ could not arm the launchd update handoff; existing service left running: ${e.message}\n`),!1}}(g,o))return!1}else if("linux"===process.platform){if(process.stderr.write(`\n ◆ staged replacement for ${g.file}\n`),!function(e,i){const s=r.join(e.logDir,`service-update-${process.pid}-${Date.now()}.service`),o=buildLinuxReloadHandoff({targetLabel:_(e.file),targetFile:e.file,stagedFile:s,expectedRuntime:e.expectedRuntime,version:i});t.mkdirSync(r.dirname(o.statusFile),{recursive:!0}),t.rmSync(o.statusFile,{force:!0}),t.writeFileSync(s,e.content);try{return n(`systemd-run --user --unit=${m(o.helperLabel)} --collect --property=StandardOutput=append:${m(o.logFile)} --property=StandardError=append:${m(o.logFile)} /bin/bash -lc ${m(o.script)}`,{stdio:"inherit",shell:"/bin/bash"}),process.stderr.write(` ◆ update handoff armed outside the bridge service cgroup — completion is recorded in ${o.statusFile}.\n`),!0}catch(e){return t.rmSync(s,{force:!0}),process.stderr.write(` ⚠ could not arm the systemd update handoff; existing service left running: ${e.message}\n`),!1}}(g,o))return!1}else{t.writeFileSync(g.file,g.content),process.stderr.write(`\n ◆ wrote ${g.file}\n`);for(const e of g.post)try{n(e,{stdio:"inherit"})}catch(t){return process.stderr.write(` ⚠ "${e}" failed; service update NOT confirmed: ${t.message}\n`),!1}}const v=Math.max(10,parseInt(process.env.THINKPOOL_PAIR_UPDATE_IDLE,10)||90),y=s?"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 (≥${v}s quiet; they resume in place).`:`PINNED to ${o} (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.`,b=e?` ${e}`:"",k=e?`room ${e}`:"your account (auto-serves every session)",S=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(` ◆ ${k}\n ◆ ${"darwin"===process.platform?"Launchd is completing and verifying the reload independently.":g.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${S} ◆ ${y}\n ◆ logs: ${r.join(g.logDir,`${u(e)}.log`)}\n ◆ remove with: ${a("uninstall-service")}${b}\n\n`),!0}export async function installAndConfirmService(i,a=[],{platform:l=process.platform,version:c=$,staleProof:d=!0,install:u=installService,exec:f=n,snapshot:m=serviceRuntimeSnapshot,prepareAccountHandoff:h=retireUnmanagedBridgeLock,readReady:g=()=>s(),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:b=e=>new Promise(t=>setTimeout(t,e)),timeoutMs:k=2e5,pollMs:S=250,stderr:w=process.stderr}={}){const _=m(i,{platform:l,exec:f});if(!i&&"win32"!==l&&!_&&!await h())return w.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 E=()=>{const e=m(i,{platform:l,exec:f}),t=!!i||"win32"===l||o(g(),e,c,{notBefore:x});return!(e?.version!==c||!t||(w.write(` ✓ bridge install confirmed — running v${c}.\n`),0))};if("win32"===l)return!0;const A=y()+Math.max(0,Number(k)||0),P=p(i);for(;;){const e=v();if(e&&"object"==typeof e&&e.target===P&&e.version===c){if(!1===e.ok)return w.write(` ⚠ install v${c} was not confirmed: ${e.error||"the launchd handoff failed"}.\n`),!1;if(!0===e.ok&&E())return!0}if(y()>=A)return w.write(` ⚠ install v${c} timed out waiting for supervisor readiness; no connected account bridge was proven.\n`),!1;await b(Math.max(1,Number(S)||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 x(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 s=x(t);if(!s)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${s} in the background; active sessions keep running…\n`);try{return i(s),s}catch(e){return process.stderr.write(` ⚠ couldn't stage bridge v${s}: ${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 s=x(t);return s?(process.stderr.write(`\n ◆ updating the background service to v${s} and restarting…\n`),!1!==r(e,[],{version:s,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:m=()=>s(),readStatus:h=()=>{try{return JSON.parse(t.readFileSync(r.join(e.homedir(),".thinkpool-pair","update-status.json"),"utf8"))}catch{return null}},now:$=Date.now,sleep:g=e=>new Promise(t=>setTimeout(t,e)),timeoutMs:v=2e5,pollMs:y=250,stderr:b=process.stderr}={}){const k=f(i,{platform:a,exec:l}),S=$();let w=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)&&(w=r),t},install:d,active:u})||!w)return b.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=!!k&&k.version!==w,r=!!k?.pid&&!!e?.pid&&k.pid!==e.pid,n=!!i||"win32"===a||o(m(),e,w,{notBefore:S});return e?.version===w&&(t||r)&&n?(b.write(` ✓ bridge restart confirmed — running v${w}.\n`),{ok:!0,live:e}):{ok:!1,live:e}},x=({live:e}={})=>{e?.version&&e.version!==w?b.write(` ⚠ update v${w} was not confirmed: live service is still v${e.version}.\n`):e?.version===w?b.write(` ⚠ update v${w} was not confirmed: the service process did not restart.\n`):b.write(` ⚠ update v${w} was not confirmed: the service manager cannot prove the new runtime is running.\n`)};if("win32"===a)return!0;const E=$()+Math.max(0,Number(v)||0),A=p(i);let P=null;for(;;){const e=h();if(e&&"object"==typeof e&&e.target===A){if(!1===e.ok&&e.version===w)return b.write(` ⚠ update v${w} was not confirmed: ${e.error||"the launchd handoff failed"}.\n`),!1;if(!0===e.ok&&e.version===w&&(P=_(),P.ok))return!0}if($()>=E)return P?x(P):b.write(` ⚠ update v${w} 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,s=p(e);try{return"darwin"===i?darwinServiceRunning(r(`launchctl print gui/$(id -u)/${s}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"]})):"linux"===i&&(r(`systemctl --user is-active --quiet ${s}.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 d}from"./scheduled-runs.mjs";const c=/^[A-Za-z0-9]{2,16}$/,p=e=>{if(e&&!c.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 d=r.join(a,String(o)),c=r.join(d,"node_modules","thinkpool-pair","bridge.mjs");if(t.existsSync(c)&&g(c)===String(o))return c;const p=l("stage a bridge runtime update");if(!p?.ok)throw new Error(p?.reason||"host memory is critically low");const u=`${d}.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(d,{recursive:!0,force:!0}),t.renameSync(u,d)}catch(e){throw t.rmSync(u,{recursive:!0,force:!0}),e}return c}export function buildArtifact(n,{room:i=null,cmdArgs:o=[],autoUpdate:s=!1,version:a=m,staleProof:l=!1,runtimeEntry:c=null,scheduledRuns:g=d()}={}){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",E=s?"thinkpool-pair@latest":`thinkpool-pair@${a}`,P=s||l?["--prefer-online"]:[],j=i?["-y",...P,E,i]:["-y",...P,E],D=!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=c?[process.execPath,c,...i?[i]:[],...x]:l?["/bin/bash","-lc",`${h(_)}; export NPM_CONFIG_CACHE=${$(_)}; exec ${[v,...j,...x].map($).join(" ")}`]:[v,...j,...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>${c?"":`<key>NPM_CONFIG_CACHE</key><string>${f(_)}</string>`}${s?"<key>THINKPOOL_PAIR_AUTOUPDATE</key><string>1</string>":""}${D.darwin}</dict>\n</dict></plist>\n`,logDir:b,post:[],expectedRuntime:c||E,note:"Loaded as a LaunchAgent — starts at login, restarts on crash."}}if("linux"===n){const t=c?[process.execPath,c,...i?[i]:[],...x]:[v,...j,...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=${c?t.map(e=>`'${e.replace(/'/g,"'\\''")}'`).join(" "):l?`/bin/bash -lc "${h(_)}; export NPM_CONFIG_CACHE=${$(_)}; exec ${[v,...j,...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${c?"":`Environment=NPM_CONFIG_CACHE=${_}\n`}${s?"Environment=THINKPOOL_PAIR_AUTOUPDATE=1\n":""}${D.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:c||E,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=c?[process.execPath,c,...i?[i,"--supervise"]:[],...x].map(e=>`"${e}"`).join(" "):i?["npx","-y",...P,E,i,"--supervise",...x].join(" "):["npx","-y",...P,E].join(" ");return{file:n,content:`@echo off\r\ntitle thinkpool-pair ${k}\r\n${c?"":`set "NPM_CONFIG_CACHE=${_}"\r\n`}${D.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 artifactScheduledRunsEnabled(e,t){const r=String(t||"");return"darwin"===e?/<key>\s*TP_SCHEDULED_RUNS_ENABLED\s*<\/key>\s*<string>\s*1\s*<\/string>/.test(r):"linux"===e?/^Environment=TP_SCHEDULED_RUNS_ENABLED=1\r?$/m.test(r):"win32"===e&&/^set "TP_SCHEDULED_RUNS_ENABLED=1"\r?$/m.test(r)}export function installedScheduledRunsEnabled(e,{platform:r=process.platform,readFile:n=e=>t.readFileSync(e,"utf8")}={}){try{return artifactScheduledRunsEnabled(r,n(buildArtifact(r,{room:e,scheduledRuns:!1}).file))}catch{return!1}}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)}`,d=r.join(e.homedir(),"Library","LaunchAgents",`${l}.plist`),c=`${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=${$(c)}`,`helper_file=${$(d)}`,`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:d,backupFile:c,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)}`,d=`${i}.previous`,c=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:d,statusFile:c,logFile:u,script:["set -u",`target=${$(t)}`,'unit="$target.service"',`target_file=${$(n)}`,`staged_file=${$(i)}`,`backup_file=${$(d)}`,`expected=${$(o)}`,`version=${$(s)}`,`status=${$(c)}`,`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:d=2500,pollMs:c=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(d)||0)/Math.max(1,Number(c)||1)));for(let e=0;e<h;e++){if(f())return!0;await l(Math.max(1,Number(c)||1))}try{a(u,"SIGKILL")}catch{}for(let e=0;e<5;e++){if(f())return!0;await l(Math.max(1,Number(c)||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 f=null;if(!o)try{f=provisionRuntime(s)}catch(e){return process.stderr.write(` ⚠ runtime install failed; service left unchanged: ${e.message}\n`),!1}const h=d()||installedScheduledRunsEnabled(e),g=buildArtifact(process.platform,{room:e,cmdArgs:i,autoUpdate:o,version:s,staleProof:c,runtimeEntry:f,scheduledRuns:h});try{sweepExistingServices(p(e),process.platform)}catch{}if(t.mkdirSync(g.logDir,{recursive:!0}),t.mkdirSync(r.dirname(g.file),{recursive:!0}),"darwin"===process.platform){if(process.stderr.write(`\n ◆ staged replacement for ${g.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}}(g,s))return!1}else if("linux"===process.platform){if(process.stderr.write(`\n ◆ staged replacement for ${g.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}}(g,s))return!1}else{t.writeFileSync(g.file,g.content),process.stderr.write(`\n ◆ wrote ${g.file}\n`);for(const e of g.post)try{n(e,{stdio:"inherit"})}catch(t){return process.stderr.write(` ⚠ "${e}" failed; service update NOT confirmed: ${t.message}\n`),!1}}const v=Math.max(10,parseInt(process.env.THINKPOOL_PAIR_UPDATE_IDLE,10)||90),y=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 (≥${v}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.`,b=e?` ${e}`:"",w=e?`room ${e}`:"your account (auto-serves every session)",S=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(` ◆ ${w}\n ◆ ${"darwin"===process.platform?"Launchd is completing and verifying the reload independently.":g.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${S} ◆ ${y}\n ◆ logs: ${r.join(g.logDir,`${u(e)}.log`)}\n ◆ remove with: ${a("uninstall-service")}${b}\n\n`),!0}export async function installAndConfirmService(i,a=[],{platform:l=process.platform,version:d=m,staleProof:c=!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:d,staleProof:c}))return!1;const A=()=>{const e=$(i,{platform:l,exec:f}),t=!!i||"win32"===l||s(g(),e,d,{notBefore:x});return!(e?.version!==d||!t||(S.write(` ✓ bridge install confirmed — running v${d}.\n`),0))};if("win32"===l)return!0;const E=y()+Math.max(0,Number(b)||0),P=p(i);for(;;){const e=v();if(e&&"object"==typeof e&&e.target===P&&e.version===d){if(!1===e.ok)return S.write(` ⚠ install v${d} was not confirmed: ${e.error||"the launchd handoff failed"}.\n`),!1;if(!0===e.ok&&A())return!0}if(y()>=E)return S.write(` ⚠ install v${d} 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:d=updateService,install:c=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===d(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:c,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),E=p(i);let P=null;for(;;){const e=h();if(e&&"object"==typeof e&&e.target===E){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&&(P=_(),P.ok))return!0}if(m()>=A)return P?x(P):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/session-store.mjs CHANGED
@@ -1 +1 @@
1
- import e from"node:os";import t from"node:fs";import n from"node:path";import{searchableSessionEventText as r}from"./session-search.mjs";import{SPAWN as s}from"./cross-terminal.mjs";import{boundStructuredLog as o}from"./event-bounds.mjs";const i=t=>{const r=n.resolve(process.env.TP_PAIR_ROOT||n.join(e.homedir(),".thinkpool-pair")),s=n.resolve(r,t||"default");if(s!==r&&!s.startsWith(r+n.sep))throw new Error(`refused: room path escapes sandbox: ${JSON.stringify(t)}`);return s},a=e=>n.join(i(e),".archive");export const LIVE_SESSION_MAX=s.machineMax;function c(e){t.mkdirSync(i(e),{recursive:!0})}let l=0,u=null;function f(e,r){const s=n.join(n.dirname(e),`.${n.basename(e)}.tmp.${process.pid}.${Date.now()}.${l++}`);let o=null;try{o=t.openSync(s,"wx",384);const n=Buffer.from(r);for(let r=0;r<n.length;){const s=t.writeSync(o,n,r,n.length-r);if(s<=0)throw new Error(`short write while committing ${e}`);r+=s}return t.fsyncSync(o),t.closeSync(o),o=null,u?.({file:e,tmp:s}),t.renameSync(s,e),!0}catch(e){try{null!=o&&t.closeSync(o)}catch{}try{t.rmSync(s,{force:!0})}catch{}throw e}}export function setAtomicCommitHookForTest(e){u="function"==typeof e?e:null}function d(e,t,n){console.error(`[thinkpool-pair session-store] ${e} failed for ${t}: ${n?.message||n}`)}function m(e,r){try{t.mkdirSync(a(e),{recursive:!0});const s=n.basename(r),o=n.join(a(e),`${s}.${Date.now()}`);return t.renameSync(r,o),!0}catch(e){return d("archive session snapshot",r,e),!1}}function y(e){try{return t.readdirSync(i(e)).filter(e=>e.endsWith(".json")&&!e.endsWith(".events.index.json")).map(r=>{const s=n.join(i(e),r);try{const e=JSON.parse(t.readFileSync(s,"utf8"));try{const n=t.statSync(s);e._bt=n.birthtimeMs||n.mtimeMs||0}catch{e._bt=0}return e}catch(e){return d("parse session snapshot",s,e),null}}).filter(Boolean)}catch{return[]}}const h=(e,t)=>n.join(i(e),`${t}.events.jsonl`),p=(e,t)=>n.join(i(e),`${t}.events.index.json`),S=1048576,g=8388608,b=262144,v=131072,x=new Map;function N(e,n,r,s){try{const o=p(e,n);let i=null;try{i=JSON.parse(t.readFileSync(o,"utf8"))}catch{}if(0!==s&&(!i||3!==i.v||i.size!==s))return;let a=s,c=Number.isFinite(i?.lastSeq)?i.lastSeq:null,l=Number.isFinite(i?.epochStart)?i.epochStart:s,u=Number.isFinite(i?.oldestSeq)?i.oldestSeq:null,d=Array.isArray(i?.points)?i.points.filter(e=>Number.isFinite(e?.seq)&&Number.isFinite(e?.offset)):[];for(const e of r){const t=Buffer.byteLength(JSON.stringify(e))+1,n=e?.seq;if("number"==typeof n){null!=c&&n<=c?(l=a,u=n,d=[]):null==u&&(u=n);const e=d.at(-1);(!e||n-e.seq>=64||a-e.offset>=v)&&d.push({seq:n,offset:a}),c=n}a+=t}const m=t.statSync(h(e,n));if(m.size!==a)return;f(o,JSON.stringify({v:3,size:a,epochStart:l,oldestSeq:u,lastSeq:c,points:d,dev:m.dev,ino:m.ino,mtimeMs:m.mtimeMs,ctimeMs:m.ctimeMs}))}catch{}}export function appendDurableEvents(e,n,r){if(e&&n&&Array.isArray(r)&&r.length)try{c(e);const s=h(e,n),o=t.existsSync(s)?t.statSync(s).size:0;t.appendFileSync(s,r.map(e=>JSON.stringify(e)).join("\n")+"\n"),N(e,n,r,o)}catch{}}export function seedDurableEvents(e,n,r){if(e&&n&&Array.isArray(r)&&r.length)try{c(e);const s=h(e,n);if(t.existsSync(s))return;t.writeFileSync(s,r.map(e=>JSON.stringify(e)).join("\n")+"\n"),N(e,n,r,0)}catch{}}export function hasDurableArchive(e,n){try{return!!e&&!!n&&t.existsSync(h(e,n))}catch{return!1}}export function servesHistoryPage({payloadHost:e,bridgeName:t,hasSession:n,hasArchive:r}){return!(e&&e!==t||!n&&!r)}function O(e,n){try{const r=h(e,n),s=JSON.parse(t.readFileSync(p(e,n),"utf8")),o=t.statSync(r);return 3!==s?.v||s.size!==o.size||s.dev!==o.dev||s.ino!==o.ino||s.mtimeMs!==o.mtimeMs||s.ctimeMs!==o.ctimeMs||!Number.isFinite(s.epochStart)||s.epochStart<0||s.epochStart>o.size||!Array.isArray(s.points)?null:s}catch{return null}}const w=e=>`${e.dev}:${e.ino}:${e.size}:${e.mtimeMs}:${e.ctimeMs}`;function A(e,t,n,r){let s=t,o=n;if(e.discarding){const t=s.indexOf(10);if(t<0)return;s=s.subarray(t+1),o+=t+1,e.discarding=!1}e.carry.length&&(s=Buffer.concat([e.carry,s]),o=e.carryOffset,e.carry=Buffer.alloc(0));let i=0;for(;;){const e=s.indexOf(10,i);if(e<0)break;const t=s.subarray(i,e);t.length<=b&&r(t,o+i),i=e+1}const a=s.subarray(i);a.length>b?(e.carry=Buffer.alloc(0),e.discarding=!0):(e.carry=Buffer.from(a),e.carryOffset=o+i)}function q(e,n){let r;try{r=t.statSync(h(e,n))}catch{return}const s=w(r),o=`${e}\0${n}`,i=x.get(o);if(i?.signature===s&&(i.active||i.attempts>=2))return;const a=i?.signature===s?i.attempts+1:1;x.set(o,{signature:s,attempts:a,active:!0}),j().then(async()=>{const r=await async function(e,n,r){const s=h(e,n);let o;try{const i=await t.promises.stat(s);if(w(i)!==r)return;o=await t.promises.open(s,"r");const a={carry:Buffer.alloc(0),carryOffset:0,discarding:!1};let c=0,l=0,u=null,d=null,m=[];const y=(e,t)=>{let n;try{n=JSON.parse(e.toString("utf8"))}catch{return}if("number"!=typeof n?.seq)return;null!=d&&n.seq<=d?(l=t,u=n.seq,m=[]):null==u&&(u=n.seq);const r=m.at(-1);(!r||n.seq-r.seq>=64||t-r.offset>=v)&&m.push({seq:n.seq,offset:t}),d=n.seq};for(;c<i.size;){const e=Math.min(65536,i.size-c),t=Buffer.allocUnsafe(e),{bytesRead:n}=await o.read(t,0,e,c);if(!n)break;A(a,t.subarray(0,n),c,y),c+=n,await j()}!a.discarding&&a.carry.length&&y(a.carry,a.carryOffset);const h=await t.promises.stat(s);if(w(h)!==r)return;return f(p(e,n),JSON.stringify({v:3,size:h.size,epochStart:l,oldestSeq:u,lastSeq:d,points:m,dev:h.dev,ino:h.ino,mtimeMs:h.mtimeMs,ctimeMs:h.ctimeMs})),!0}catch{}finally{try{await(o?.close())}catch{}}}(e,n,s),i=x.get(o);i?.signature===s&&(r?x.delete(o):x.set(o,{...i,active:!1}))})}function M(e,t,n=!1){if(n){const t=e.lastIndexOf(10);return t<0?{carry:Buffer.alloc(0),lines:[],discarding:!0}:M(e.subarray(0,t+1),Buffer.alloc(0))}const r=t.length?Buffer.concat([e,t]):e,s=r.indexOf(10);if(s<0)return r.length>b?{carry:Buffer.alloc(0),lines:[],discarding:!0}:{carry:Buffer.from(r),lines:[],discarding:!1};const o=Buffer.from(r.subarray(0,s)),i=[];let a=s+1;for(;;){const e=r.indexOf(10,a);if(e<0)break;i.push(r.subarray(a,e)),a=e+1}return i.push(r.subarray(a)),{carry:o.length>b?Buffer.alloc(0):o,lines:i,discarding:o.length>b}}export function readDurableOldestSeq(e,n){try{const r=O(e,n);return r?r.oldestSeq??null:(t.existsSync(h(e,n))&&q(e,n),null)}catch{return null}}export function readDurablePage(e,n,r,s=200){try{const o=O(e,n);return t.existsSync(h(e,n))?(o||q(e,n),function(e,n,r,s,o){const i=(e=>Math.max(1,Math.min(200,Number(e)||200)))(s),a=h(e,n),c=t.statSync(a).size,l=o?.epochStart||0,u=null==r?null:o?.points.find(e=>e.seq>r);let f=u?.offset??c,d=Buffer.alloc(0),m=!1,y=0,p=0,g=[],v=null,x=!1,N=!1;const O=t.openSync(a,"r");try{for(;f>l&&y<S&&p<5e3&&g.length<=i;){const e=Math.max(l,f-Math.min(65536,S-y)),n=Buffer.alloc(f-e);t.readSync(O,n,0,n.length,e),y+=n.length;const s=M(n,d,m);d=s.carry,m=s.discarding;for(let e=s.lines.length-1;e>=0;e--){const t=s.lines[e];if(t.length){try{if(t.length>b){N=!0;continue}const e=JSON.parse(t.toString("utf8"));if(p++,"number"==typeof e?.seq){if(null!=v&&e.seq>=v){x=!0;break}v=e.seq}(null==r||null==e?.seq||e.seq<r)&&g.push(e)}catch{}if(g.length>i)break}}if(x||g.length>i)break;f=e}if(f===l&&m&&(N=!0),f===l&&d.length&&!x&&g.length<=i)try{if(d.length>b)N=!0;else{const e=JSON.parse(d.toString("utf8"));p++,"number"==typeof e?.seq&&null!=v&&e.seq>=v?x=!0:(null==r||null==e?.seq||e.seq<r)&&g.push(e)}}catch{}}finally{t.closeSync(O)}f>l&&(y>=S||p>=5e3)&&(N=!0);const w=N||g.length>i||!x&&f>l;return{events:g.slice(0,i).reverse(),hasMore:w,...N?{partial:!0,bytesRead:y,eventsRead:p}:{}}}(e,n,r,s,o)):{events:[],hasMore:!1}}catch{return{events:[],hasMore:!1}}}const k=(e,t)=>(Number(e.ts)||0)-(Number(t.ts)||0)||String(e.termName||"").localeCompare(String(t.termName||""))||(Number(e.seq)||0)-(Number(t.seq)||0),j=()=>new Promise(e=>setImmediate(e));export async function searchDurableSessionEventsAsync(e,n,s,o={}){const i=String(s||"").trim().toLocaleLowerCase();if(!i)return{results:[],truncated:!1,partial:!1,bytesRead:0,eventsRead:0};const a=Math.max(1,Math.min(200,Number(o.limit)||200)),c=Math.max(16384,Math.min(g,Number(o.maxBytes)||g)),l=Math.max(1,Math.min(5e4,Number(o.maxEvents)||5e4)),u=Math.max(1,Math.min(5e3,Number(o.deadlineMs)||100)),f=Date.now()+u,d={bytes:0,events:0,partial:!1,truncated:!1},m=[],y=new Set;let p=2;const S=(e,t,n)=>{const s=r(e);if(!s||!s.toLocaleLowerCase().includes(i))return;const o=e.cid||(Number.isSafeInteger(e.seq)?`seq:${e.epoch||0}:${e.seq}`:`row:${n}`),c=`${t.term}:${o}`;if(y.has(c))return;y.add(c);const l=s.toLocaleLowerCase().indexOf(i),u=s.slice(Math.max(0,l-240),Math.min(s.length,l+i.length+560)),f={key:c,term:t.term,termName:t.termName||"terminal",cid:e.cid||null,seq:Number.isSafeInteger(e.seq)?e.seq:null,epoch:Number.isSafeInteger(e.epoch)?e.epoch:0,ts:Number(e.ts)||0,kind:e.kind,by:e.by||null,text:u},h=Buffer.byteLength(JSON.stringify(f))+1;if(p+h>12e4)return d.truncated=!0,void(d.partial=!0);p+=h,m.push(f),m.sort(k),m.length>a&&(p-=Buffer.byteLength(JSON.stringify(m.pop()))+1,d.truncated=!0)};try{for(const r of n||[]){const n=String(r?.term||"");if(!n||d.partial)continue;const s={term:n,termName:r.termName||"terminal"},o=h(e,n);let i;try{i=await t.promises.stat(o)}catch{continue}const a=O(e,n);a||q(e,n);const u=a?.epochStart||0;let m,y=i.size,p=Buffer.alloc(0),g=!1,v=null,x=!1,N=0;try{for(m=await t.promises.open(o,"r");y>u&&!x;){if(d.bytes>=c||d.events>=l||Date.now()>=f){d.partial=!0;break}const e=Math.min(16384,y-u,c-d.bytes);if(e<=0){d.partial=!0;break}const t=y-e,n=Buffer.allocUnsafe(e),{bytesRead:r}=await m.read(n,0,e,t);d.bytes+=r;const o=M(n.subarray(0,r),p,g);p=o.carry,g=o.discarding;for(let e=o.lines.length-1;e>=0;e--){const t=o.lines[e];if(!t.length)continue;if(t.length>b){d.partial=!0;continue}let n;try{n=JSON.parse(t.toString("utf8"))}catch{continue}if(d.events++,N++,"number"==typeof n?.seq){if(null!=v&&n.seq>=v){x=!0;break}v=n.seq}if(S(n,s,N),d.events>=l){d.partial=!0;break}}y=t,await j()}if(g&&(d.partial=!0),!d.partial&&!x&&y===u&&p.length)if(p.length>b)d.partial=!0;else try{const e=JSON.parse(p.toString("utf8"));d.events++,N++,"number"==typeof e?.seq&&null!=v&&e.seq>=v?x=!0:S(e,s,N)}catch{}}finally{await(m?.close())}!x&&y>u&&(d.partial=!0)}}catch{d.partial=!0}return d.partial&&(d.truncated=!0),{results:m,truncated:d.truncated,partial:d.partial,bytesRead:d.bytes,eventsRead:d.events,deadlineMs:u}}export function searchDurableSessionEvents(){return{results:[],truncated:!0,partial:!0,bytesRead:0,eventsRead:0}}const $=new Map;function I(e,r,s){const a=n.join(i(e),`${r}.json`);try{c(e);const l=Array.isArray(s?.log)?o(s.log):s?.log;return f(a,JSON.stringify({...s,...l?{log:l}:{},id:r,savedAt:Date.now()})),function(e){try{const r=loadNames(e),s=e=>{try{return JSON.parse(t.readFileSync(e,"utf8")).id}catch{return null}};t.readdirSync(i(e)).filter(e=>e.endsWith(".json")).map(r=>{const s=n.join(i(e),r);let o=0;try{o=JSON.parse(t.readFileSync(s,"utf8")).savedAt||0}catch{}return{p:s,f:r,m:o}}).sort((e,t)=>t.m-e.m).filter(e=>{const t=s(e.p);return!t||!r[t]}).slice(LIVE_SESSION_MAX).forEach(t=>m(e,t.p))}catch(t){d("prune live session snapshots",i(e),t)}}(e),!0}catch(e){return d("write session snapshot",a,e),!1}}export function saveSession(e,t,n){clearTimeout($.get(t)),$.set(t,setTimeout(()=>I(e,t,n),1500))}export function flushSession(e,t,n){return clearTimeout($.get(t)),I(e,t,n)}export function deleteSession(e,r){clearTimeout($.get(r)),$.delete(r);const s=n.join(i(e),`${r}.json`);try{return!t.existsSync(s)||m(e,s)}catch(e){return d("archive closed session snapshot",s,e),!1}}const J=e=>n.join(i(e),".scheduled-outcomes"),B=e=>"string"==typeof e&&/^[A-Za-z0-9][A-Za-z0-9._:@-]{0,159}$/.test(e),F=e=>"string"==typeof e&&/^[A-Za-z0-9][A-Za-z0-9._:@-]{0,159}$/.test(e),z=e=>{try{const n=JSON.parse(t.readFileSync(J(e),"utf8"));return n&&"object"==typeof n&&!Array.isArray(n)?n:{}}catch{return{}}},R=e=>{if(!e||"object"!=typeof e||Array.isArray(e))return null;if(1===e.v&&"acknowledged"===e.state){const t=e.intent;return t&&"object"==typeof t&&!Array.isArray(t)&&F(t.runId)&&e.runId===t.runId?{intent:t,acknowledged:!0}:null}return F(e.runId)?{intent:e,acknowledged:!1}:null};export function savePendingScheduledOutcome(e,t,n){if(!B(t)||!n||"object"!=typeof n||Array.isArray(n)||!F(n.runId))return!1;try{c(e);const r=z(e);return r[t]=n,f(J(e),JSON.stringify(r)),!0}catch(t){return d("write scheduled outcome outbox",J(e),t),!1}}export function loadPendingScheduledOutcomes(e){return Object.entries(z(e)).map(([e,t])=>({terminalId:e,record:R(t)})).filter(({terminalId:e,record:t})=>B(e)&&t).map(({terminalId:e,record:t})=>({terminalId:e,intent:t.intent,...t.acknowledged?{acknowledged:!0}:{}})).slice(0,LIVE_SESSION_MAX)}export function loadPendingScheduledOutcome(e,t){return B(t)&&R(z(e)[t])?.intent||null}export function acknowledgePendingScheduledOutcome(e,t,n){if(!B(t)||!F(n))return!1;try{const r=z(e),s=R(r[t]);return!(!s||s.intent.runId!==n||(s.acknowledged||(r[t]={v:1,state:"acknowledged",runId:n,intent:s.intent},f(J(e),JSON.stringify(r))),0))}catch(t){return d("acknowledge scheduled outcome outbox",J(e),t),!1}}export function deletePendingScheduledOutcome(e,n){if(!B(n))return!1;try{const r=z(e);return!(n in r)||(delete r[n],Object.keys(r).length?f(J(e),JSON.stringify(r)):t.rmSync(J(e),{force:!0}),!0)}catch(t){return d("delete scheduled outcome outbox",J(e),t),!1}}export function commitRecordedScheduledOutcome(e,t,r){let s=!1;try{s="function"==typeof r&&!0===r()}catch(r){d("record scheduled outcome in session snapshot",n.join(i(e),`${t}.json`),r)}if(!s)return{ok:!1,snapshotRecorded:!1,outboxAcknowledged:!1,outboxDeleted:!1};const o=loadPendingScheduledOutcome(e,t);if(!acknowledgePendingScheduledOutcome(e,t,o?.runId))return{ok:!1,snapshotRecorded:!0,outboxAcknowledged:!1,outboxDeleted:!1};const a=deletePendingScheduledOutcome(e,t);return{ok:a,snapshotRecorded:!0,outboxAcknowledged:!0,outboxDeleted:a}}export function loadLatest(e){return y(e).sort((e,t)=>(t.savedAt||0)-(e.savedAt||0))[0]||null}export function canResume(e){return!!(e&&e.sessionId&&e.savedAt&&Date.now()-e.savedAt<432e5)}export function loadAll(e){return y(e).sort((e,t)=>(e.savedAt||0)-(t.savedAt||0))}export function loadArchived(e,r=40){try{return t.readdirSync(a(e)).map(r=>{const s=n.join(a(e),r);try{const e=t.statSync(s);if(!e.isFile())return null;const n=JSON.parse(t.readFileSync(s,"utf8"));return n&&Array.isArray(n.log)?{...n,_archivedAt:e.mtimeMs||0}:null}catch{return null}}).filter(Boolean).sort((e,t)=>(t._archivedAt||t.savedAt||0)-(e._archivedAt||e.savedAt||0)).slice(0,Math.max(1,Math.min(100,Number(r)||40)))}catch{return[]}}const D=e=>n.join(i(e),".pty-id");export function loadPtyId(e){try{return t.readFileSync(D(e),"utf8").trim()||null}catch{return null}}export function savePtyId(e,t){const n=D(e);try{return c(e),f(n,String(t)),!0}catch(e){return d("write PTY id",n,e),!1}}const E=e=>n.join(i(e),".names");export function loadNames(e){const n=E(e);try{return JSON.parse(t.readFileSync(n,"utf8"))||{}}catch(e){return"ENOENT"!==e?.code&&d("parse terminal names",n,e),{}}}export function saveNames(e,t){const n=E(e);try{return c(e),f(n,JSON.stringify(t||{})),!0}catch(e){return d("write terminal names",n,e),!1}}
1
+ import e from"node:os";import t from"node:fs";import n from"node:path";import{matchSessionEvents as r}from"./session-search.mjs";import{SPAWN as o}from"./cross-terminal.mjs";import{boundStructuredLog as c}from"./event-bounds.mjs";const s=t=>{const r=n.resolve(process.env.TP_PAIR_ROOT||n.join(e.homedir(),".thinkpool-pair")),o=n.resolve(r,t||"default");if(o!==r&&!o.startsWith(r+n.sep))throw new Error(`refused: room path escapes sandbox: ${JSON.stringify(t)}`);return o},i=e=>n.join(s(e),".archive");export const LIVE_SESSION_MAX=o.machineMax;function a(e){t.mkdirSync(s(e),{recursive:!0})}let u=0,l=null;function d(e,r){const o=n.join(n.dirname(e),`.${n.basename(e)}.tmp.${process.pid}.${Date.now()}.${u++}`);let c=null;try{c=t.openSync(o,"wx",384);const n=Buffer.from(r);for(let r=0;r<n.length;){const o=t.writeSync(c,n,r,n.length-r);if(o<=0)throw new Error(`short write while committing ${e}`);r+=o}return t.fsyncSync(c),t.closeSync(c),c=null,l?.({file:e,tmp:o}),t.renameSync(o,e),!0}catch(e){try{null!=c&&t.closeSync(c)}catch{}try{t.rmSync(o,{force:!0})}catch{}throw e}}export function setAtomicCommitHookForTest(e){l="function"==typeof e?e:null}function f(e,t,n){console.error(`[thinkpool-pair session-store] ${e} failed for ${t}: ${n?.message||n}`)}function m(e,r){try{t.mkdirSync(i(e),{recursive:!0});const o=n.basename(r),c=n.join(i(e),`${o}.${Date.now()}`);return t.renameSync(r,c),!0}catch(e){return f("archive session snapshot",r,e),!1}}function h(e){try{return t.readdirSync(s(e)).filter(e=>e.endsWith(".json")).map(r=>{const o=n.join(s(e),r);try{const e=JSON.parse(t.readFileSync(o,"utf8"));try{const n=t.statSync(o);e._bt=n.birthtimeMs||n.mtimeMs||0}catch{e._bt=0}return e}catch(e){return f("parse session snapshot",o,e),null}}).filter(Boolean)}catch{return[]}}const y=(e,t)=>n.join(s(e),`${t}.events.jsonl`);export function appendDurableEvents(e,n,r){if(e&&n&&Array.isArray(r)&&r.length)try{a(e),t.appendFileSync(y(e,n),r.map(e=>JSON.stringify(e)).join("\n")+"\n")}catch{}}export function seedDurableEvents(e,n,r){if(e&&n&&Array.isArray(r)&&r.length)try{a(e);const o=y(e,n);if(t.existsSync(o))return;t.writeFileSync(o,r.map(e=>JSON.stringify(e)).join("\n")+"\n")}catch{}}export function hasDurableArchive(e,n){try{return!!e&&!!n&&t.existsSync(y(e,n))}catch{return!1}}export function servesHistoryPage({payloadHost:e,bridgeName:t,hasSession:n,hasArchive:r}){return!(e&&e!==t||!n&&!r)}function p(e){let t=0,n=-1/0;for(let r=0;r<e.length;r++){const o=e[r]?.seq;"number"==typeof o&&(o<=n?(t=r,n=o):n=o)}return t}function S(e,n){const r=y(e,n);if(!t.existsSync(r))return null;const o=[];for(const e of t.readFileSync(r,"utf8").split("\n"))if(e)try{o.push(JSON.parse(e))}catch{}return o}export function readDurableOldestSeq(e,t){try{const n=S(e,t);if(!n)return null;for(let e=p(n);e<n.length;e++)if(n[e]&&null!=n[e].seq)return n[e].seq;return null}catch{return null}}export function readDurablePage(e,t,n,r=200){try{const o=S(e,t);if(!o)return{events:[],hasMore:!1};const c=p(o);let s=o.length;if(null!=n){const e=o.findIndex((e,t)=>t>=c&&e&&null!=e.seq&&e.seq>=n);e>=0&&(s=e)}const i=Math.max(c,s-r);return{events:o.slice(i,Math.max(i,s)),hasMore:i>c}}catch{return{events:[],hasMore:!1}}}export function searchDurableSessionEvents(e,t,n,{limit:o=200}={}){try{const c=[];for(const n of t||[]){const t=String(n?.term||"");if(!t)continue;const r=S(e,t);r&&c.push({term:t,termName:n.termName||"terminal",events:r.slice(p(r))})}return r(c,n,{limit:o})}catch{return{results:[],truncated:!1}}}const g=new Map;function x(e,r,o){const i=n.join(s(e),`${r}.json`);try{a(e);const u=Array.isArray(o?.log)?c(o.log):o?.log;return d(i,JSON.stringify({...o,...u?{log:u}:{},id:r,savedAt:Date.now()})),function(e){try{const r=loadNames(e),o=e=>{try{return JSON.parse(t.readFileSync(e,"utf8")).id}catch{return null}};t.readdirSync(s(e)).filter(e=>e.endsWith(".json")).map(r=>{const o=n.join(s(e),r);let c=0;try{c=JSON.parse(t.readFileSync(o,"utf8")).savedAt||0}catch{}return{p:o,f:r,m:c}}).sort((e,t)=>t.m-e.m).filter(e=>{const t=o(e.p);return!t||!r[t]}).slice(LIVE_SESSION_MAX).forEach(t=>m(e,t.p))}catch(t){f("prune live session snapshots",s(e),t)}}(e),!0}catch(e){return f("write session snapshot",i,e),!1}}export function saveSession(e,t,n){clearTimeout(g.get(t)),g.set(t,setTimeout(()=>x(e,t,n),1500))}export function flushSession(e,t,n){return clearTimeout(g.get(t)),x(e,t,n)}export function deleteSession(e,r){clearTimeout(g.get(r)),g.delete(r);const o=n.join(s(e),`${r}.json`);try{return!t.existsSync(o)||m(e,o)}catch(e){return f("archive closed session snapshot",o,e),!1}}const A=e=>n.join(s(e),".scheduled-outcomes"),v=e=>"string"==typeof e&&/^[A-Za-z0-9][A-Za-z0-9._:@-]{0,159}$/.test(e),O=e=>"string"==typeof e&&/^[A-Za-z0-9][A-Za-z0-9._:@-]{0,159}$/.test(e),w=e=>{try{const n=JSON.parse(t.readFileSync(A(e),"utf8"));return n&&"object"==typeof n&&!Array.isArray(n)?n:{}}catch{return{}}},b=e=>{if(!e||"object"!=typeof e||Array.isArray(e))return null;if(1===e.v&&"acknowledged"===e.state){const t=e.intent;return t&&"object"==typeof t&&!Array.isArray(t)&&O(t.runId)&&e.runId===t.runId?{intent:t,acknowledged:!0}:null}return O(e.runId)?{intent:e,acknowledged:!1}:null};export function savePendingScheduledOutcome(e,t,n){if(!v(t)||!n||"object"!=typeof n||Array.isArray(n)||!O(n.runId))return!1;try{a(e);const r=w(e);return r[t]=n,d(A(e),JSON.stringify(r)),!0}catch(t){return f("write scheduled outcome outbox",A(e),t),!1}}export function loadPendingScheduledOutcomes(e){return Object.entries(w(e)).map(([e,t])=>({terminalId:e,record:b(t)})).filter(({terminalId:e,record:t})=>v(e)&&t).map(({terminalId:e,record:t})=>({terminalId:e,intent:t.intent,...t.acknowledged?{acknowledged:!0}:{}})).slice(0,LIVE_SESSION_MAX)}export function loadPendingScheduledOutcome(e,t){return v(t)&&b(w(e)[t])?.intent||null}export function acknowledgePendingScheduledOutcome(e,t,n){if(!v(t)||!O(n))return!1;try{const r=w(e),o=b(r[t]);return!(!o||o.intent.runId!==n||(o.acknowledged||(r[t]={v:1,state:"acknowledged",runId:n,intent:o.intent},d(A(e),JSON.stringify(r))),0))}catch(t){return f("acknowledge scheduled outcome outbox",A(e),t),!1}}export function deletePendingScheduledOutcome(e,n){if(!v(n))return!1;try{const r=w(e);return!(n in r)||(delete r[n],Object.keys(r).length?d(A(e),JSON.stringify(r)):t.rmSync(A(e),{force:!0}),!0)}catch(t){return f("delete scheduled outcome outbox",A(e),t),!1}}export function commitRecordedScheduledOutcome(e,t,r){let o=!1;try{o="function"==typeof r&&!0===r()}catch(r){f("record scheduled outcome in session snapshot",n.join(s(e),`${t}.json`),r)}if(!o)return{ok:!1,snapshotRecorded:!1,outboxAcknowledged:!1,outboxDeleted:!1};const c=loadPendingScheduledOutcome(e,t);if(!acknowledgePendingScheduledOutcome(e,t,c?.runId))return{ok:!1,snapshotRecorded:!0,outboxAcknowledged:!1,outboxDeleted:!1};const i=deletePendingScheduledOutcome(e,t);return{ok:i,snapshotRecorded:!0,outboxAcknowledged:!0,outboxDeleted:i}}export function loadLatest(e){return h(e).sort((e,t)=>(t.savedAt||0)-(e.savedAt||0))[0]||null}export function canResume(e){return!!(e&&e.sessionId&&e.savedAt&&Date.now()-e.savedAt<432e5)}export function loadAll(e){return h(e).sort((e,t)=>(e.savedAt||0)-(t.savedAt||0))}export function loadArchived(e,r=40){try{return t.readdirSync(i(e)).map(r=>{const o=n.join(i(e),r);try{const e=t.statSync(o);if(!e.isFile())return null;const n=JSON.parse(t.readFileSync(o,"utf8"));return n&&Array.isArray(n.log)?{...n,_archivedAt:e.mtimeMs||0}:null}catch{return null}}).filter(Boolean).sort((e,t)=>(t._archivedAt||t.savedAt||0)-(e._archivedAt||e.savedAt||0)).slice(0,Math.max(1,Math.min(100,Number(r)||40)))}catch{return[]}}const j=e=>n.join(s(e),".pty-id");export function loadPtyId(e){try{return t.readFileSync(j(e),"utf8").trim()||null}catch{return null}}export function savePtyId(e,t){const n=j(e);try{return a(e),d(n,String(t)),!0}catch(e){return f("write PTY id",n,e),!1}}const N=e=>n.join(s(e),".names");export function loadNames(e){const n=N(e);try{return JSON.parse(t.readFileSync(n,"utf8"))||{}}catch(e){return"ENOENT"!==e?.code&&f("parse terminal names",n,e),{}}}export function saveNames(e,t){const n=N(e);try{return a(e),d(n,JSON.stringify(t||{})),!0}catch(e){return f("write terminal names",n,e),!1}}
@@ -1 +0,0 @@
1
- import{claimTurnReceipt as e}from"./turn-receipt.mjs";const t=4194304,n=new Set(["received","prepared","dispatching","dispatched","completed","recovery_required"]),r=e=>Buffer.byteLength(JSON.stringify(e)),o=()=>new Error("Command journal capacity is full; pending commands must be resolved first.");export function restoreCommandJournal(e){const a=(Array.isArray(e)?e:[]).filter(e=>e&&"string"==typeof e.cid&&n.has(e.state));if(a.length>128||a.reduce((e,t)=>e+r(t.payload),0)>t)throw o();return a}export function recordCommand(e,n){const a="string"==typeof n?.cid?n.cid:"";if(!a)return null;const i=e.commandJournal||(e.commandJournal=[]),d=i.find(e=>e.cid===a);if(d)return d;const s=JSON.stringify(n),c=Buffer.byteLength(s);if(c>1048576)throw new Error("Command is too large to persist safely.");let m=i.reduce((e,t)=>e+r(t.payload),0);for(;i.length>=128||m+c>t;){const e=i.findIndex(e=>"completed"===e.state);if(e<0)throw o();m-=r(i[e].payload),i.splice(e,1)}const u={cid:a,state:"received",payload:JSON.parse(s),createdAt:Date.now(),updatedAt:Date.now()};return i.push(u),u}export function transitionCommand(e,t,r){if(!n.has(r))throw new TypeError(`invalid command journal state: ${r}`);const o=e?.commandJournal?.find(e=>e.cid===t);return o?("completed"===o.state&&"dispatched"===r||(o.state=r,o.updatedAt=Date.now()),o):null}export function acceptDurableCommand(t,n){if(t.receivedTurnCids?.has(n.cid))return{duplicate:!0,claimed:!1};const r=[...t.commandJournal||[]],o=new Set(t.receivedTurnCids||[]);try{recordCommand(t,n);const r=e(t,n.cid);if(!0!==t.flush?.())throw new Error("Command persistence failed; no receipt was issued.");return r}catch(e){throw t.commandJournal=r,t.receivedTurnCids=o,e}}export function beginCommandDispatch(e,t){if(!t)return;const n=e.commandJournal?.find(e=>e.cid===t);if(!n)throw new Error("Command has no durable receipt.");const r=n.state;if(transitionCommand(e,t,"dispatching"),!0!==e.flush?.())throw n.state=r,new Error("Command dispatch persistence failed; agent was not called.");const o=e._dispatchingCommandCids||(e._dispatchingCommandCids=[]);o.includes(t)||o.push(t)}export function takeCommandResult(e){return e._dispatchingCommandCids?.shift()||null}export function completeCommand(e,t){if(!t)return!1;const n=e.commandJournal?.find(e=>e.cid===t);if(!n)return!1;const r=n.state;return transitionCommand(e,t,"completed"),!0!==e.flush?.()?(n.state=r,!1):(e._dispatchingCommandCids&&(e._dispatchingCommandCids=e._dispatchingCommandCids.filter(e=>e!==t)),!0)}export function recoverableCommands(e){const t=[];for(const n of e?.commandJournal||[])"received"===n.state||"prepared"===n.state?t.push({...n,recovery:"safe_redelivery"}):"completed"!==n.state&&(n.state="recovery_required",n.updatedAt=Date.now(),t.push({...n,recovery:"dispatch_uncertain"}));return t}
@@ -1 +0,0 @@
1
- import{z as t}from"zod";export const MCP_SCHEMA_FIXTURES={array:()=>t.array(t.string()).min(1),boolean:()=>t.boolean(),enum:()=>t.enum(["once","interval","daily"]),literal:()=>t.literal(15),number:()=>t.number().int().min(1).max(100),object:()=>t.object({name:t.string().min(1).max(80)}),string:()=>t.string().min(1).max(80).uuid().describe("fixture string"),union:()=>t.union([t.literal(15),t.literal(30),t.literal(60)]),unknown:()=>t.unknown()};export const MCP_SCHEMA_SENTINEL=()=>t.object({items:t.array(t.object({}).catchall(t.unknown())).optional()}).strict();export function fixtureToolRegistrations(){return Object.entries(MCP_SCHEMA_FIXTURES).map(([e,n])=>({name:`fixture_${e}`,description:`tools/list gate fixture for z.${e}`,inputSchema:t.object({v:n().optional()}),outputSchema:t.object({v:n()})}))}export function sentinelToolRegistration(){return{name:"sentinel_record_shape",description:"2026-09-04 incident shape: arbitrary-key object map (was z.record)",inputSchema:t.object({operation:MCP_SCHEMA_FIXTURES.enum()}),outputSchema:t.object({items:t.array(t.object({}).catchall(t.unknown())).optional()}).strict()}}
@@ -1 +0,0 @@
1
- export const makeRoutedRealtimeFrame=(e,t,a)=>({event:e,payload:t,channel:a});export const realtimeWireBytes=({event:e,payload:t})=>{try{return Buffer.byteLength(JSON.stringify({event:e,payload:t}))}catch{return 1/0}};export async function sendAbortableReplayFrame(e,{event:t,payload:a},{signal:o,fetchImpl:n=fetch}={}){const r=new URL(e.broadcastEndpointURL),c={apikey:e.socket.apiKey||"","Content-Type":"application/json"};e.socket.accessTokenValue&&(c.Authorization=`Bearer ${e.socket.accessTokenValue}`);const s=await n(r,{method:"POST",headers:c,body:JSON.stringify({messages:[{topic:e.subTopic,event:t,payload:a,private:e.private}]}),signal:o});try{await(s.body?.cancel())}catch{}return s.ok?"ok":"error"}
@@ -1 +0,0 @@
1
- export function createTurnAdmissionQueue({maxPending:e=128}={}){const t=new WeakMap;return(n,r)=>{if(!n||"function"!=typeof r)return Promise.resolve();let o=t.get(n);if(o||(o={tail:Promise.resolve(),count:0},t.set(n,o)),o.count>=e)return Promise.reject(new Error("Too many pending turns; wait for this lane to finish preparing."));o.count++;const i=o.tail.then(r),u=()=>{o.count--,o.count||t.get(n)!==o||t.delete(n)};return o.tail=i.then(u,u),i}}