thinkpool-pair 0.7.373 → 0.7.375
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/account.mjs +1 -1
- package/bridge.mjs +1 -1
- package/cloud-session-transcript.mjs +1 -0
- package/event-id.mjs +1 -1
- package/host-capacity.mjs +1 -1
- package/package.json +3 -1
- package/publish-manifest.json +13 -11
- package/recap.mjs +1 -1
- package/session-search.mjs +1 -0
- package/session-store.mjs +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{PEEK as e,cleanPtyTail as r,digestLogEvent as t,formatLaneAge as n,resolveSibling as a,siblingRef as o}from"./cross-terminal.mjs";const i=(e,r)=>{if(e?.error)throw new Error(`${r}: ${e.error.message||e.error}`);return e?.data},s=e=>{const r="number"==typeof e?e:Date.parse(String(e||""));return Number.isFinite(r)&&r>0?r:null},l=e=>`${e.ref}${e.name?` · "${e.name}"`:""}`;export const cloudTerminalRoster=(e,r=Date.now())=>(Array.isArray(e)?e:[]).filter(e=>e?.id).map(e=>{const t="pty"===e.kind?"shell":"agent",n=s(e.last_active_at);return{id:String(e.id),ref:o(e.id),name:String(e.name||""),kind:t,cmd:String(e.agent||("shell"===t?"shell":"think"===e.kind?"think":"agent")),lastActionAt:n,lastActionAgeMs:null==n?null:Math.max(0,r-n),sortOrder:Number.isFinite(Number(e.sort_order))?Number(e.sort_order):Number.MAX_SAFE_INTEGER}}).sort((e,r)=>e.sortOrder-r.sortOrder||e.id.localeCompare(r.id));export const formatCloudTerminalRoster=({room:e,terminals:r,now:t=Date.now()}={})=>{const a=cloudTerminalRoster(r,t);return a.length?`Cloud fallback for room ${e} · partner bridge offline (snapshots may lag the host-local event log).\nDurable terminals (call read_session again with a ref or name to read one):\n${a.map(e=>`- ${l(e)} · ${e.kind} · ${e.cmd} · bridge offline · ${n(e.lastActionAgeMs)}`).join("\n")}`:`Room ${e} is paired with you, but its host bridge is offline and no durable terminal rows are available in the cloud.`};export const formatCloudAgentTranscript=({room:r,terminal:a,snapshot:o,lines:i,now:m=Date.now()}={})=>{const d=Math.min(e.maxLines,Math.max(1,Number(i)||e.defaultLines)),c=o?.payload,u=!0===c?.__txsnap&&String(c.term||"")===a.id&&Array.isArray(c.events),f=u?s(c.ts)||s(o?.created_at):null,h=u?c.events.map(r=>t(r,e.lineCap)).filter(Boolean).slice(-d).join("\n"):"";return`Cloud fallback for room ${r} · partner bridge offline · ${null==f?"unknown snapshot time":`snapshot saved ${n(Math.max(0,m-f))}`} (may lag the host-local event log).\nTerminal ${l(a)} (${a.kind} · ${a.cmd}) — last ${d} readable lines:\n`+(h||"(no durable structured transcript snapshot is available)")};export const formatCloudShellTranscript=({room:t,terminal:n,rows:a,lines:o,archived:i=!1}={})=>{const s=Math.min(e.maxLines,Math.max(1,Number(o)||e.defaultLines)),m=(Array.isArray(a)?a:[]).slice().sort((e,r)=>Number(e.seq)-Number(r.seq)),d=r(m.map(e=>e?.line||"").join("\n"),s).join("\n");return`Cloud fallback for room ${t} · partner bridge offline${i?" · archived scrollback":""} (may lag the host-local event log).\nTerminal ${l(n)} (${n.kind} · ${n.cmd}) — last ${s} readable lines:\n`+(d||"(no durable shell transcript is available)")};export async function readCloudSessionTranscript({sb:r,targetRoom:t,terminal:n,lines:o,now:s=Date.now()}={}){if(!r?.from)throw new Error("cloud transcript client is unavailable");const l=String(t||"").toUpperCase().trim();if(!l)throw new Error("cloud transcript room is missing");const m=Math.min(e.maxLines,Math.max(1,Number(o)||e.defaultLines)),d=await r.from("code_terminals").select("id,name,agent,kind,last_active_at,sort_order").eq("session_code",l).order("sort_order",{ascending:!0}).order("id",{ascending:!0}).limit(100),c=i(d,"durable terminal roster")||[];if(!n)return formatCloudTerminalRoster({room:l,terminals:c,now:s});const u=cloudTerminalRoster(c,s),f=a(u,n);if(!f)return`${formatCloudTerminalRoster({room:l,terminals:c,now:s})}\nNo durable terminal matches "${n}". Use a name or stable ref from the roster above.`;if("agent"===f.kind){const e=await r.from("code_messages").select("payload,created_at").eq("session_code",l).eq("id",`tx:${f.id}`).maybeSingle(),t=i(e,"durable structured transcript");return formatCloudAgentTranscript({room:l,terminal:f,snapshot:t,lines:m,now:s})}const h=await r.from("code_terminal_lines").select("seq,line").eq("terminal_id",f.id).order("seq",{ascending:!1}).limit(m),p=i(h,"durable shell transcript")||[];if(p.length)return formatCloudShellTranscript({room:l,terminal:f,rows:p,lines:m});const b=await r.from("code_terminal_lines_archive").select("seq,line").eq("session_code",l).eq("terminal_id",f.id).order("seq",{ascending:!1}).limit(m),g=i(b,"archived shell transcript")||[];return formatCloudShellTranscript({room:l,terminal:f,rows:g,lines:m,archived:g.length>0})}
|
package/event-id.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import{boundStructuredEvent as t,STRUCTURED_EVENT_CAP as n}from"./event-bounds.mjs";import{classifyCodeEvent as o}from"./code-event-contract.mjs";export function stampEvent(t,n=e){return t&&"object"==typeof t?("number"!=typeof t.ts&&(t.ts=Date.now()),t.cid||(t.cid=n()),t):t}export function makeSeqCounter(e=0){let t=Number.isFinite(e)?e:0;return{next:()=>++t,bumpTo:e=>{Number.isFinite(e)&&e>t&&(t=e)},current:()=>t}}export const NO_SEQ_KINDS=new Set(["system","thinking_tokens","effort","models","queue-add","queue-cancel","propose-done","update-available"]);export const seqable=e=>!(!e||"object"!=typeof e)&&o(e,{strict:!1}).known&&!NO_SEQ_KINDS.has(e.kind);export function maxSeq(e){if(!Array.isArray(e))return 0;let t=0;for(const n of e)n&&"number"==typeof n.seq&&n.seq>t&&(t=n.seq);return t}export const REPLAY_BYTE_BUDGET=15e4;export function capReplayEvents(e,t=15e4){if(!Array.isArray(e)||0===e.length)return e;let n=0,o=e.length;for(;o>0;){const s=JSON.stringify(e[o-1]).length+1;if(o<e.length&&n+s>t)break;n+=s,o--}return 0===o?e:e.slice(o)}export const REPLAY_MAX_CHUNKS=14;export function chunkReplayEvents(e,t=15e4,n=14){if(!Array.isArray(e)||0===e.length)return[];const o=[];let s=[],i=0;for(let r=e.length-1;r>=0;r--){const a=JSON.stringify(e[r]).length+1;if(s.length&&i+a>t){if(o.push(s),o.length>=n){s=null;break}s=[],i=0}s.push(e[r]),i+=a}return s&&s.length&&o.push(s),o.reverse().map(e=>e.reverse())}export function trimmedBeforeSeq(e,t=0,n=null){if("number"!=typeof e)return null;const o="number"==typeof n?n:1;return e>Math.max(t||0,o-1)+1?e:null}export function firstSeq(e){if(!Array.isArray(e))return null;for(const t of e)if(t&&"number"==typeof t.seq)return t.seq;return null}export const PER_EVENT_CAP=n;export function boundEventForBroadcast(e,n=PER_EVENT_CAP){return t(e,n)}export function inlineImageBlocks(e){if(!e||"tool_result"!==e.kind||!Array.isArray(e.content))return[];const t=[];return e.content.forEach((e,n)=>{e&&"image"===e.type&&e.source&&"base64"===e.source.type&&"string"==typeof e.source.data&&e.source.data.length&&t.push({idx:n,b64:e.source.data,mediaType:e.source.media_type||"image/png"})}),t}export const SCREENSHOT_OMITTED="[screenshot omitted — upload failed]";export const DEFAULT_IMAGE_UPLOAD_TIMEOUT_MS=15e3;export const DEFAULT_IMAGE_QUEUE_MAX_PENDING=4;export const DEFAULT_IMAGE_QUEUE_MAX_BYTES=16e6;const s=(e,t)=>{const n=Number(e);return Number.isSafeInteger(n)&&n>0?n:t};export function imageQueueConfig(e=process.env){return{uploadTimeoutMs:s(e.TP_CODE_IMAGE_UPLOAD_TIMEOUT_MS,15e3),maxPending:s(e.TP_CODE_IMAGE_QUEUE_MAX_PENDING,4),maxBytes:s(e.TP_CODE_IMAGE_QUEUE_MAX_BYTES,16e6)}}export async function uploadCodeImage({webBase:e,room:t,authToken:n,term:o,cid:s,image:i,fetchImpl:r=globalThis.fetch,timeoutMs:a=15e3,activeUploads:u=new Set}){const c=new AbortController;let d=null,l=null,p=!1;const h=new Promise((e,t)=>{l=t}),m={cancel(e=new Error("code-image upload cancelled")){if(!p){d&&(clearTimeout(d),d=null);try{c.abort(e)}catch{}l(e instanceof Error?e:new Error(String(e)))}}};u.add(m),d=setTimeout(()=>m.cancel(new Error(`code-image upload timed out after ${a}ms`)),a),d.unref?.();const f={"Content-Type":"application/json"};n&&(f.Authorization=`Bearer ${n}`);const g=(async()=>{const n=await r(`${e}/api/code-image`,{method:"POST",headers:f,signal:c.signal,body:JSON.stringify({code:t,term:o,cid:s,idx:i.idx,mediaType:i.mediaType,b64:i.b64})});if(!n.ok)throw new Error(`code-image ${n.status}`);const{path:a}=await n.json();if(!a)throw new Error("code-image: no path");return a})();try{return await Promise.race([g,h])}finally{p=!0,d&&clearTimeout(d),u.delete(m)}}const i=e=>Buffer.byteLength(String(e?.b64||""),"ascii");function r(e,t,n){for(const o of t){const t=Array.isArray(e?.content)?e.content[o.idx]:null;("base64"===t?.source?.type||o.b64)&&(e.content[o.idx]={type:"text",text:n}),o.b64=""}}export class ImageEventQueue{constructor({upload:e,maxPending:t=4,maxBytes:n=16e6,placeholder:o=SCREENSHOT_OMITTED,onUploadError:i=()=>{},onOverload:r=()=>{}}){if("function"!=typeof e)throw new TypeError("ImageEventQueue requires upload");this.upload=e,this.maxPending=s(t,4),this.maxBytes=s(n,16e6),this.placeholder=o,this.onUploadError=i,this.onOverload=r,this.pendingCount=0,this.pendingBytes=0,this.peakPendingCount=0,this.peakPendingBytes=0,this.activeUploads=new Set,this.tasks=new Set,this.tail=Promise.resolve(),this.closed=!1,this.overloadNotified=!1}stats(){return{pendingCount:this.pendingCount,pendingBytes:this.pendingBytes,peakPendingCount:this.peakPendingCount,peakPendingBytes:this.peakPendingBytes,activeUploads:this.activeUploads.size,queuedEvents:this.tasks.size}}enqueue(e,t,n){if(this.closed||"function"!=typeof n)return!1;const o=Array.isArray(t)?t:[],s=o.length,a=o.reduce((e,t)=>e+i(t),0),u=s>0&&this.pendingCount+s<=this.maxPending&&this.pendingBytes+a<=this.maxBytes;if(s&&u){for(const e of o)e._queueBytes=i(e),e._queueReserved=!0;this.pendingCount+=s,this.pendingBytes+=a,this.peakPendingCount=Math.max(this.peakPendingCount,this.pendingCount),this.peakPendingBytes=Math.max(this.peakPendingBytes,this.pendingBytes)}else s&&(r(e,o,this.placeholder),this.overloadNotified||(this.overloadNotified=!0,this.onOverload({count:s,bytes:a,maxPending:this.maxPending,maxBytes:this.maxBytes})));if(!u&&0===this.tasks.size)return n(e),!0;const c={evt:e,images:o,emitTail:n,accepted:u,emitted:!1,done:!1};return this.tasks.add(c),this.tail=this.tail.catch(()=>{}).then(()=>this._run(c)),!0}async _run(e){if(!e.done&&!this.closed)try{if(e.accepted)for(const t of e.images)if(t._queueReserved&&!this.closed)try{const n=await this.upload(e.evt,t,this.activeUploads);e.evt.content[t.idx]={type:"image",path:n,mediaType:t.mediaType}}catch(n){e.evt.content[t.idx]={type:"text",text:this.placeholder},this.closed||this.onUploadError(n)}finally{t.b64="",this._release(t)}this.closed||e.emitted||(e.emitTail(e.evt),e.emitted=!0)}finally{e.done=!0,this.tasks.delete(e)}}_release(e){e?._queueReserved&&(e._queueReserved=!1,this.pendingCount=Math.max(0,this.pendingCount-1),this.pendingBytes=Math.max(0,this.pendingBytes-(e._queueBytes||0)),e._queueBytes=0)}async idle(){await this.tail.catch(()=>{})}close({flush:e=!0}={}){if(this.closed)return;this.closed=!0;const t=new Error("code-image queue closed");for(const e of this.activeUploads)e.cancel(t);this.activeUploads.clear();for(const t of this.tasks){r(t.evt,t.images,this.placeholder);for(const e of t.images)this._release(e);if(e&&!t.emitted){try{t.emitTail(t.evt)}catch{}t.emitted=!0}t.done=!0}this.tasks.clear(),this.pendingCount=0,this.pendingBytes=0}}export function summarizeUsage(e){const t=(Array.isArray(e)?e:[]).filter(e=>e&&"result"===e.kind&&e.usage),n=new Map;let o=0,s=0,i=0,r=!1;for(const e of t){const t=e.usage||{},a=(t.input_tokens||0)+(t.cache_creation_input_tokens||0)+(t.cache_read_input_tokens||0),u=t.output_tokens||0,c=t.cache_read_input_tokens||0,d=e.model||"unknown",l=n.get(d)||{model:d,in:0,out:0,cached:0};l.in+=a,l.out+=u,l.cached+=c,n.set(d,l),o+=a,s+=u,"number"==typeof e.costUsd&&(i+=e.costUsd,r=!0)}return{turns:t.length,per:[...n.values()],totalIn:o,totalOut:s,totalCost:i,haveCost:r}}export const claudeish=e=>/claude|anthropic|opus|sonnet|haiku|fable/i.test(String(e||""));export function prettyModelId(e){if(!e)return"unknown";const t=String(e),n=/\[1m\]/i.test(t)?" [1m]":"",o=t.match(/(opus|sonnet|haiku|fable)-(\d+)(?:-(\d+))?/i);return o?`${o[1][0].toUpperCase()}${o[1].slice(1)} ${o[2]}${o[3]?"."+o[3]:""}${n}`:t}export function usageReportLine(e,t){const n=summarizeUsage(t);if(!claudeish(e)&&!n.per.some(e=>claudeish(e.model))&&(e||n.turns))return"usage reporting is available on Claude models only";if(!n.turns)return"usage · no completed turns yet this session";const o=e=>e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"k":String(e),s=n.per.filter(e=>e.in||e.out).length?n.per.filter(e=>e.in||e.out):n.per,i=s.map(e=>{const t=e.cached?` (${o(e.cached)} cached)`:"";return`${prettyModelId(e.model)}: ${o(e.in)} in${t} / ${o(e.out)} out`}).join(" · "),r=s.length>1?` · total ${o(n.totalIn)} in / ${o(n.totalOut)} out`:"",a=n.haveCost?` · ~$${n.totalCost.toFixed(2)} est`:"";return`usage · ${n.turns} turn${1===n.turns?"":"s"} · ${i}${r}${a}`}export function codexUsageReportLine(e,t){const n=t?.context,o=t?.total;if(!n||!o)return"usage · no completed Codex turn yet";const s=e=>e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"k":String(Math.round(e||0)),i=Math.max(0,Number(n.used)||0),r=Math.max(0,Number(n.max)||0),a=r>0?Math.min(100,Math.max(0,Math.round(i/r*100))):0,u=Math.max(0,Number(o.input_tokens)||0),c=Math.min(u,Math.max(0,Number(o.cached_input_tokens)||0)),d=Math.max(0,Number(o.output_tokens)||0);return`usage · ${prettyModelId(e)} · context ${s(i)}/${s(r)} (${a}%) · thread ${s(u)} processed (${s(c)} cached) / ${s(d)} out`}export{CHECKPOINT_CAP,CURRENT_PERSON_REQUEST_MARKER,RECAP_CAP,appendCurrentPersonRequest,buildCheckpointFromLog,buildRecapFromLog,recapHasCheckpoint,resolveCheckpointCarry}from"./recap.mjs";
|
|
1
|
+
import{randomUUID as e}from"node:crypto";import{boundStructuredEvent as t,STRUCTURED_EVENT_CAP as n}from"./event-bounds.mjs";import{classifyCodeEvent as o}from"./code-event-contract.mjs";export function stampEvent(t,n=e){return t&&"object"==typeof t?("number"!=typeof t.ts&&(t.ts=Date.now()),t.cid||(t.cid=n()),t):t}export function makeSeqCounter(e=0){let t=Number.isFinite(e)?e:0;return{next:()=>++t,bumpTo:e=>{Number.isFinite(e)&&e>t&&(t=e)},current:()=>t}}export const NO_SEQ_KINDS=new Set(["system","thinking_tokens","effort","models","queue-add","queue-cancel","propose-done","update-available"]);export const seqable=e=>!(!e||"object"!=typeof e)&&o(e,{strict:!1}).known&&!NO_SEQ_KINDS.has(e.kind);export function maxSeq(e){if(!Array.isArray(e))return 0;let t=0;for(const n of e)n&&"number"==typeof n.seq&&n.seq>t&&(t=n.seq);return t}export const REPLAY_BYTE_BUDGET=15e4;export function capReplayEvents(e,t=15e4){if(!Array.isArray(e)||0===e.length)return e;let n=0,o=e.length;for(;o>0;){const s=JSON.stringify(e[o-1]).length+1;if(o<e.length&&n+s>t)break;n+=s,o--}return 0===o?e:e.slice(o)}export const REPLAY_MAX_CHUNKS=14;export function chunkReplayEvents(e,t=15e4,n=14){if(!Array.isArray(e)||0===e.length)return[];const o=[];let s=[],i=0;for(let r=e.length-1;r>=0;r--){const a=JSON.stringify(e[r]).length+1;if(s.length&&i+a>t){if(o.push(s),o.length>=n){s=null;break}s=[],i=0}s.push(e[r]),i+=a}return s&&s.length&&o.push(s),o.reverse().map(e=>e.reverse())}export function trimmedBeforeSeq(e,t=0,n=null){if("number"!=typeof e)return null;const o="number"==typeof n?n:1;return e>Math.max(t||0,o-1)+1?e:null}export function firstSeq(e){if(!Array.isArray(e))return null;for(const t of e)if(t&&"number"==typeof t.seq)return t.seq;return null}export const PER_EVENT_CAP=n;export function boundEventForBroadcast(e,n=PER_EVENT_CAP){return t(e,n)}export function inlineImageBlocks(e){if(!e||"tool_result"!==e.kind||!Array.isArray(e.content))return[];const t=[];return e.content.forEach((e,n)=>{e&&"image"===e.type&&e.source&&"base64"===e.source.type&&"string"==typeof e.source.data&&e.source.data.length&&t.push({idx:n,b64:e.source.data,mediaType:e.source.media_type||"image/png"})}),t}export const SCREENSHOT_OMITTED="[screenshot omitted — upload failed]";export const DEFAULT_IMAGE_UPLOAD_TIMEOUT_MS=15e3;export const DEFAULT_IMAGE_QUEUE_MAX_PENDING=4;export const DEFAULT_IMAGE_QUEUE_MAX_BYTES=16e6;const s=(e,t)=>{const n=Number(e);return Number.isSafeInteger(n)&&n>0?n:t};export function imageQueueConfig(e=process.env){return{uploadTimeoutMs:s(e.TP_CODE_IMAGE_UPLOAD_TIMEOUT_MS,15e3),maxPending:s(e.TP_CODE_IMAGE_QUEUE_MAX_PENDING,4),maxBytes:s(e.TP_CODE_IMAGE_QUEUE_MAX_BYTES,16e6)}}export async function uploadCodeImage({webBase:e,room:t,authToken:n,term:o,cid:s,image:i,fetchImpl:r=globalThis.fetch,timeoutMs:a=15e3,activeUploads:u=new Set}){const c=new AbortController;let d=null,l=null,p=!1;const h=new Promise((e,t)=>{l=t}),m={cancel(e=new Error("code-image upload cancelled")){if(!p){d&&(clearTimeout(d),d=null);try{c.abort(e)}catch{}l(e instanceof Error?e:new Error(String(e)))}}};u.add(m),d=setTimeout(()=>m.cancel(new Error(`code-image upload timed out after ${a}ms`)),a),d.unref?.();const f={"Content-Type":"application/json"};n&&(f.Authorization=`Bearer ${n}`);const g=(async()=>{const n=await r(`${e}/api/code-image`,{method:"POST",headers:f,signal:c.signal,body:JSON.stringify({code:t,term:o,cid:s,idx:i.idx,mediaType:i.mediaType,b64:i.b64})});if(!n.ok)throw new Error(`code-image ${n.status}`);const{path:a}=await n.json();if(!a)throw new Error("code-image: no path");return a})();try{return await Promise.race([g,h])}finally{p=!0,d&&clearTimeout(d),u.delete(m)}}const i=e=>Buffer.byteLength(String(e?.b64||""),"ascii");function r(e,t,n){for(const o of t){const t=Array.isArray(e?.content)?e.content[o.idx]:null;("base64"===t?.source?.type||o.b64)&&(e.content[o.idx]={type:"text",text:n}),o.b64=""}}export class ImageEventQueue{constructor({upload:e,maxPending:t=4,maxBytes:n=16e6,placeholder:o=SCREENSHOT_OMITTED,onUploadError:i=()=>{},onOverload:r=()=>{}}){if("function"!=typeof e)throw new TypeError("ImageEventQueue requires upload");this.upload=e,this.maxPending=s(t,4),this.maxBytes=s(n,16e6),this.placeholder=o,this.onUploadError=i,this.onOverload=r,this.pendingCount=0,this.pendingBytes=0,this.peakPendingCount=0,this.peakPendingBytes=0,this.activeUploads=new Set,this.tasks=new Set,this.tail=Promise.resolve(),this.closed=!1,this.overloadNotified=!1}stats(){return{pendingCount:this.pendingCount,pendingBytes:this.pendingBytes,peakPendingCount:this.peakPendingCount,peakPendingBytes:this.peakPendingBytes,activeUploads:this.activeUploads.size,queuedEvents:this.tasks.size}}enqueue(e,t,n){if(this.closed||"function"!=typeof n)return!1;const o=Array.isArray(t)?t:[],s=o.length,a=o.reduce((e,t)=>e+i(t),0),u=s>0&&this.pendingCount+s<=this.maxPending&&this.pendingBytes+a<=this.maxBytes;if(s&&u){for(const e of o)e._queueBytes=i(e),e._queueReserved=!0;this.pendingCount+=s,this.pendingBytes+=a,this.peakPendingCount=Math.max(this.peakPendingCount,this.pendingCount),this.peakPendingBytes=Math.max(this.peakPendingBytes,this.pendingBytes)}else s&&(r(e,o,this.placeholder),this.overloadNotified||(this.overloadNotified=!0,this.onOverload({count:s,bytes:a,maxPending:this.maxPending,maxBytes:this.maxBytes})));if(!u&&0===this.tasks.size)return n(e),!0;const c={evt:e,images:o,emitTail:n,accepted:u,emitted:!1,done:!1};return this.tasks.add(c),this.tail=this.tail.catch(()=>{}).then(()=>this._run(c)),!0}async _run(e){if(!e.done&&!this.closed)try{if(e.accepted)for(const t of e.images)if(t._queueReserved&&!this.closed)try{const n=await this.upload(e.evt,t,this.activeUploads);e.evt.content[t.idx]={type:"image",path:n,mediaType:t.mediaType}}catch(n){e.evt.content[t.idx]={type:"text",text:this.placeholder},this.closed||this.onUploadError(n)}finally{t.b64="",this._release(t)}this.closed||e.emitted||(e.emitTail(e.evt),e.emitted=!0)}finally{e.done=!0,this.tasks.delete(e)}}_release(e){e?._queueReserved&&(e._queueReserved=!1,this.pendingCount=Math.max(0,this.pendingCount-1),this.pendingBytes=Math.max(0,this.pendingBytes-(e._queueBytes||0)),e._queueBytes=0)}async idle(){await this.tail.catch(()=>{})}close({flush:e=!0}={}){if(this.closed)return;this.closed=!0;const t=new Error("code-image queue closed");for(const e of this.activeUploads)e.cancel(t);this.activeUploads.clear();for(const t of this.tasks){r(t.evt,t.images,this.placeholder);for(const e of t.images)this._release(e);if(e&&!t.emitted){try{t.emitTail(t.evt)}catch{}t.emitted=!0}t.done=!0}this.tasks.clear(),this.pendingCount=0,this.pendingBytes=0}}export function summarizeUsage(e){const t=(Array.isArray(e)?e:[]).filter(e=>e&&"result"===e.kind&&e.usage),n=new Map;let o=0,s=0,i=0,r=!1;for(const e of t){const t=e.usage||{},a=(t.input_tokens||0)+(t.cache_creation_input_tokens||0)+(t.cache_read_input_tokens||0),u=t.output_tokens||0,c=t.cache_read_input_tokens||0,d=e.model||"unknown",l=n.get(d)||{model:d,in:0,out:0,cached:0};l.in+=a,l.out+=u,l.cached+=c,n.set(d,l),o+=a,s+=u,"number"==typeof e.costUsd&&(i+=e.costUsd,r=!0)}return{turns:t.length,per:[...n.values()],totalIn:o,totalOut:s,totalCost:i,haveCost:r}}export const claudeish=e=>/claude|anthropic|opus|sonnet|haiku|fable/i.test(String(e||""));export function prettyModelId(e){if(!e)return"unknown";const t=String(e),n=/\[1m\]/i.test(t)?" [1m]":"",o=t.match(/(opus|sonnet|haiku|fable)-(\d+)(?:-(\d+))?/i);return o?`${o[1][0].toUpperCase()}${o[1].slice(1)} ${o[2]}${o[3]?"."+o[3]:""}${n}`:t}export function usageReportLine(e,t){const n=summarizeUsage(t);if(!claudeish(e)&&!n.per.some(e=>claudeish(e.model))&&(e||n.turns))return"usage reporting is available on Claude models only";if(!n.turns)return"usage · no completed turns yet this session";const o=e=>e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"k":String(e),s=n.per.filter(e=>e.in||e.out).length?n.per.filter(e=>e.in||e.out):n.per,i=s.map(e=>{const t=e.cached?` (${o(e.cached)} cached)`:"";return`${prettyModelId(e.model)}: ${o(e.in)} in${t} / ${o(e.out)} out`}).join(" · "),r=s.length>1?` · total ${o(n.totalIn)} in / ${o(n.totalOut)} out`:"",a=n.haveCost?` · ~$${n.totalCost.toFixed(2)} est`:"";return`usage · ${n.turns} turn${1===n.turns?"":"s"} · ${i}${r}${a}`}export function codexUsageReportLine(e,t){const n=t?.context,o=t?.total;if(!n||!o)return"usage · no completed Codex turn yet";const s=e=>e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"k":String(Math.round(e||0)),i=Math.max(0,Number(n.used)||0),r=Math.max(0,Number(n.max)||0),a=r>0?Math.min(100,Math.max(0,Math.round(i/r*100))):0,u=Math.max(0,Number(o.input_tokens)||0),c=Math.min(u,Math.max(0,Number(o.cached_input_tokens)||0)),d=Math.max(0,Number(o.output_tokens)||0);return`usage · ${prettyModelId(e)} · context ${s(i)}/${s(r)} (${a}%) · thread ${s(u)} processed (${s(c)} cached) / ${s(d)} out`}export{CHECKPOINT_CAP,CURRENT_PERSON_REQUEST_MARKER,RECAP_CAP,appendCurrentPersonRequest,buildCheckpointFromLog,buildRecapFromLog,checkpointFactsFromLog,recapHasCheckpoint,resolveCheckpointCarry,visibleWorkTurnsFromLog}from"./recap.mjs";
|
package/host-capacity.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{SPAWN as e}from"./cross-terminal.mjs";const t=/^[A-Za-z0-9][A-Za-z0-9._:@-]{0,255}$/;export const hostLaneLimit=(t=process.env)=>{const i=Number.parseInt(t?.TP_HOST_LIVE_LANES,10);return Number.isSafeInteger(i)?Math.max(1,Math.min(e.machineMax,i)):e.machineMax};export class HostCapacityAuthority{constructor({limit:t=hostLaneLimit()}={}){this.limit=Math.max(1,Math.min(e.machineMax,Number(t)||e.machineMax)),this.leases=new Map}acquire({room:e,terminalId:i}={}){if("string"!=typeof e||!t.test(e)||"string"!=typeof i||!t.test(i))return Object.freeze({ok:!1,code:"invalid_capacity_request"});const s=`${e}:${i}`;return this.leases.has(s)?Object.freeze({ok:!0,code:"already_admitted",active:this.leases.size,limit:this.limit}):this.leases.size>=this.limit?Object.freeze({ok:!1,code:"host_capacity",active:this.leases.size,limit:this.limit,reason:`This bridge machine already has ${this.limit} live
|
|
1
|
+
import{SPAWN as e}from"./cross-terminal.mjs";const t=/^[A-Za-z0-9][A-Za-z0-9._:@-]{0,255}$/;export const hostLaneLimit=(t=process.env)=>{const i=Number.parseInt(t?.TP_HOST_LIVE_LANES,10);return Number.isSafeInteger(i)?Math.max(1,Math.min(e.machineMax,i)):e.machineMax};export class HostCapacityAuthority{constructor({limit:t=hostLaneLimit()}={}){this.limit=Math.max(1,Math.min(e.machineMax,Number(t)||e.machineMax)),this.leases=new Map}acquire({room:e,terminalId:i}={}){if("string"!=typeof e||!t.test(e)||"string"!=typeof i||!t.test(i))return Object.freeze({ok:!1,code:"invalid_capacity_request"});const s=`${e}:${i}`;return this.leases.has(s)?Object.freeze({ok:!0,code:"already_admitted",active:this.leases.size,limit:this.limit}):this.leases.size>=this.limit?Object.freeze({ok:!1,code:"host_capacity",active:this.leases.size,limit:this.limit,reason:`This bridge machine already has ${this.limit} live agent runtimes. Close a running lane or leave the task queued; Dispatch resumes when capacity returns.`}):(this.leases.set(s,Object.freeze({room:e,terminalId:i})),Object.freeze({ok:!0,code:"admitted",active:this.leases.size,limit:this.limit}))}release({room:e,terminalId:t}={}){return"string"==typeof e&&"string"==typeof t&&this.leases.delete(`${e}:${t}`)}releaseRoom(e){let t=0;for(const[i,s]of this.leases)s.room===e&&(this.leases.delete(i),t++);return t}snapshot(){return Object.freeze({active:this.leases.size,limit:this.limit,available:this.leases.size<this.limit})}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thinkpool-pair",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.375",
|
|
4
4
|
"description": "Connect Claude Code, Codex, or Hermes on your computer to a thinkpool Code room.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|
|
@@ -75,10 +75,12 @@
|
|
|
75
75
|
"plan-meters.mjs",
|
|
76
76
|
"recap.mjs",
|
|
77
77
|
"transcript-sanitize.mjs",
|
|
78
|
+
"session-search.mjs",
|
|
78
79
|
"session-store.mjs",
|
|
79
80
|
"side-lane.mjs",
|
|
80
81
|
"worker-completion.mjs",
|
|
81
82
|
"cross-terminal.mjs",
|
|
83
|
+
"cloud-session-transcript.mjs",
|
|
82
84
|
"pair-bus.mjs",
|
|
83
85
|
"direct-pair-room.mjs",
|
|
84
86
|
"lane-lifecycle.mjs",
|
package/publish-manifest.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": 1,
|
|
3
3
|
"package": "thinkpool-pair",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.375",
|
|
5
5
|
"kind": "minified",
|
|
6
|
-
"minifiedModules":
|
|
7
|
-
"sourceModuleBytes":
|
|
8
|
-
"artifactModuleBytes":
|
|
6
|
+
"minifiedModules": 114,
|
|
7
|
+
"sourceModuleBytes": 1653590,
|
|
8
|
+
"artifactModuleBytes": 734878,
|
|
9
9
|
"files": {
|
|
10
|
-
"package.json": "
|
|
10
|
+
"package.json": "523c25c7f60f3c634c92787443779b34ce1486b72470567693c1bc71535d30ab",
|
|
11
11
|
"LICENSE": "8a030197ca1cad9669909ca14c9ad15cf48d9fe551da526ccaf1fca993eddb23",
|
|
12
|
-
"bridge.mjs": "
|
|
12
|
+
"bridge.mjs": "33e43921f58a3a6e735a605ce4b0fb959f04ae91f08e12e8597f01d305558ca1",
|
|
13
13
|
"bridge-service.sh": "b64f27c473ca8f3a49190fd08c23947ab14ca9958d70b6fa53c7bddc2be91403",
|
|
14
14
|
"command-guidance.mjs": "b9b967b59ff4e77c9613abb0f28858bf3ac5b106a509e471039777b53bec3e29",
|
|
15
15
|
"abort-turn-barrier.mjs": "3734a5b7e2e940ec6d7fa8b5b04935e1429a23d1bd9e92b2ac2a2ecd9f77c75e",
|
|
16
16
|
"host-memory.mjs": "44dab373e0a11b5f9ed1e5f1105643b51b1ce417781efb207a569d991865b4ae",
|
|
17
|
-
"host-capacity.mjs": "
|
|
17
|
+
"host-capacity.mjs": "13f127951dc9d5adffc6b8da0617977e6c4aaefdf0e72d92c7fdb84ee8ad9a12",
|
|
18
18
|
"keep-awake.mjs": "6c0a51409321f2564082b414b00696d22a740ca98180b1f628828c5fe19995c7",
|
|
19
19
|
"sdk-smoke.mjs": "dfe509863ede8a12780914939740f7f9fee36d3980f8fcb57803a33593ac4056",
|
|
20
20
|
"sdk-admission.mjs": "eb33725cc33347b900c75289eae7917f6ce3526203711515aecd48d43b3c895d",
|
|
@@ -67,18 +67,20 @@
|
|
|
67
67
|
"pair-control-authority.mjs": "7a95f101153dcc6dd0633b5a01595bf2979cd0c4bf50cfc6cd44bb7612ef40a5",
|
|
68
68
|
"scheduled-runs.mjs": "c139e7d47dd7a12c73149502b5d02409e96f4ccafaf28a9ab6889e5b101931e9",
|
|
69
69
|
"scheduled-run-admission.mjs": "3a2098d904c3aff571bf314e0182d5636d25d242cef52207e70f9dc1618c94f5",
|
|
70
|
-
"event-id.mjs": "
|
|
70
|
+
"event-id.mjs": "8535c07a68b4a66405278281bdc74ad0341bcac73caf94f1cd517afee8e712cf",
|
|
71
71
|
"event-bounds.mjs": "aa8eb8517c4aa81b3378f71401ed39c550cdc80e28e3a57ab46d0a5ef5c7c9c1",
|
|
72
72
|
"replay-transport.mjs": "f4ed49dc023e3bb2d9534814bc2684121caafe4d24151b87688407eda47c6c7a",
|
|
73
73
|
"event-delivery-queue.mjs": "c596e298384e0e4890bccdc07f622e1807d1784e19b65f0ef5b7b1bfea0c41d4",
|
|
74
74
|
"mcp-flight-recorder.mjs": "46e3bf7b04212fe69819e38e377c4239caf8b1552ac7bf4905abddd66385065c",
|
|
75
75
|
"plan-meters.mjs": "f7f5aeb3d6a3462b754d3724367bbb331643ba58108e29e91b2aca2f613ab499",
|
|
76
|
-
"recap.mjs": "
|
|
76
|
+
"recap.mjs": "0f030c0473cda87e87a767c1bfdd4365493c9cdb171d2253ede298b6d2dc5b9c",
|
|
77
77
|
"transcript-sanitize.mjs": "c7f4718f25f97c05bc7b4ad8e09f18cbda152c53ad6593af1ab99f0c132dbf01",
|
|
78
|
-
"session-
|
|
78
|
+
"session-search.mjs": "d606fbab5c47357071e4919107aa00ad090f6e7d7e6dc929e0ac5a4d0cb2c538",
|
|
79
|
+
"session-store.mjs": "fa3f7a27a8a7c49bb89364fb28c9c2680f7f487d4b4125329ab4a0ba9362bd8c",
|
|
79
80
|
"side-lane.mjs": "306d451e2d163ecdf40030d886a338770b11bc57952543a107e422f95ca49d45",
|
|
80
81
|
"worker-completion.mjs": "7fad56bd9d3bb88f3e7bbeaa027508abad3465d3a33240cf82370104defad301",
|
|
81
82
|
"cross-terminal.mjs": "57fbd5c13b7d8c1ca671b13381e0ccd3c96cb75ebc13a8f466aff9727bba5460",
|
|
83
|
+
"cloud-session-transcript.mjs": "1e8b3000d628eac0cff171901d6fed13983528b42e23e277583ef65bf8f9fa2b",
|
|
82
84
|
"pair-bus.mjs": "cbc28cee7f4f06b2213091e0b7b07d61c1d01f0ff207c5c6d808cd616ece221e",
|
|
83
85
|
"direct-pair-room.mjs": "92557b54307da2ca31f0a0d090e44b019a23b1ab32a7dfd6cbcb9d55fd761736",
|
|
84
86
|
"lane-lifecycle.mjs": "9b5ae3d105c30e3ad37f1f1f792200da2dd4d2bb5c4979a2a69618373e58f1c8",
|
|
@@ -116,7 +118,7 @@
|
|
|
116
118
|
"service.mjs": "412ee48ad7b1dd281063f30f2519b077aa4cc92305e6780ac226293756f6e6f8",
|
|
117
119
|
"supervisor-ready.mjs": "7d5e4ebe3c7a93e0888dd335fb4556a670e55a80a89b861c8a44feac159cd840",
|
|
118
120
|
"presence.mjs": "2516ebb4474a8f45dd881530335c2174af9cde44be8eed6896ff8c62497b6e2b",
|
|
119
|
-
"account.mjs": "
|
|
121
|
+
"account.mjs": "df9ebc9fba1ac5b97ae1d6c9bdf0028b5be5d0b02779aad44952690c35ac4b74",
|
|
120
122
|
"auth-store.mjs": "c4d41ee7cdc34c2002c6dd50d32e53ace0a3f03a116ffa930ed94a437e247625",
|
|
121
123
|
"key-shape.mjs": "a4113293d52eeba39b05e70a3e0345abc1ddc181b4f236b413bde0ae11a3f646",
|
|
122
124
|
"supabase-key.mjs": "041bde6cf50b15f6426daaf738374abc9647861d8c1dd3d85cedc45684271888",
|
package/recap.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const RECAP_CAP=2e4;export const CHECKPOINT_CAP=6e3;const e="--- deterministic checkpoint (visible text only; evidence, not hidden state) ---",t="--- end deterministic checkpoint ---";export const CURRENT_PERSON_REQUEST_MARKER="--- CURRENT PERSON REQUEST (authoritative; overrides all carried context above) ---";const n=/(?:file:\/\/|[a-z]:\\|\\\\|(?:^|[^a-z0-9/])(?:~[\\/]|\/(?:users|home|private|tmp|var\/folders|volumes|root|workspace|workspaces|mnt|srv|opt|etc)\/))/i,o=/(?:^|[^a-z0-9.])\.\.(?:[\\/]|$)/i,s=/(?:sk[_-](?:proj[_-])?[a-z0-9_-]{8,}|gsk_[a-z0-9_-]{8,}|AIza[a-z0-9_-]{8,}|gh[pousr]_[a-z0-9_-]{8,}|github_pat_[a-z0-9_]{20,}|glpat-[a-z0-9_-]{8,}|x(?:ox[baprsce]|app)-[a-z0-9_-]{8,}|(?:AKIA|ASIA)[0-9A-Z]{16}|sbp_[a-z0-9_-]{20,}|sb_secret_[a-z0-9_-]{8,}|npm_[a-z0-9]{24,}|(?:sk|rk)_(?:live|test)_[a-z0-9]{8,}|whsec_[a-z0-9]{8,}|eyJ[a-z0-9_-]{8,}\.[a-z0-9_-]{8,}\.[a-z0-9_-]{8,}|bearer\s+[a-z0-9._-]{8,}|hooks\.slack\.com\/services\/[a-z0-9/_-]{8,})/i,
|
|
1
|
+
export const RECAP_CAP=2e4;export const CHECKPOINT_CAP=6e3;const e="--- deterministic checkpoint (visible text only; evidence, not hidden state) ---",t="--- end deterministic checkpoint ---";export const CURRENT_PERSON_REQUEST_MARKER="--- CURRENT PERSON REQUEST (authoritative; overrides all carried context above) ---";const n=/(?:file:\/\/|[a-z]:\\|\\\\|(?:^|[^a-z0-9/])(?:~[\\/]|\/(?:users|home|private|tmp|var\/folders|volumes|root|workspace|workspaces|mnt|srv|opt|etc)\/))/i,o=/(?:^|[^a-z0-9.])\.\.(?:[\\/]|$)/i,s=/(?:sk[_-](?:proj[_-])?[a-z0-9_-]{8,}|gsk_[a-z0-9_-]{8,}|AIza[a-z0-9_-]{8,}|gh[pousr]_[a-z0-9_-]{8,}|github_pat_[a-z0-9_]{20,}|glpat-[a-z0-9_-]{8,}|x(?:ox[baprsce]|app)-[a-z0-9_-]{8,}|(?:AKIA|ASIA)[0-9A-Z]{16}|sbp_[a-z0-9_-]{20,}|sb_secret_[a-z0-9_-]{8,}|npm_[a-z0-9]{24,}|(?:sk|rk)_(?:live|test)_[a-z0-9]{8,}|whsec_[a-z0-9]{8,}|eyJ[a-z0-9_-]{8,}\.[a-z0-9_-]{8,}\.[a-z0-9_-]{8,}|bearer\s+[a-z0-9._-]{8,}|hooks\.slack\.com\/services\/[a-z0-9/_-]{8,})/i,r=/(?:[a-z0-9]+[_ -])*(?:token|secret(?:[_ -]access[_ -]key)?|password|authorization|api[_ -]?key|private[_ -]?key|access[_ -]?key(?:[_ -]?id)?)\s*[:=]\s*\S{4,}/i,i=/(?:BEGIN (?:RSA |OPENSSH )?PRIVATE KEY|raw transcript|tool args?|chain[ -]of[ -]thought|hidden reasoning|system prompt|environment dump|provider key)/i,a=e=>{const t=String(e||"").trim();return!t||n.test(t)||o.test(t)||s.test(t)||r.test(t)||i.test(t)?"":t},c=(e,t)=>{const n=String(e||"").trim().replace(/\s+/g," ");return n?n.length<=t?n:`${n.slice(0,Math.max(0,t-1)).trimEnd()}…`:""};export function visibleWorkTurnsFromLog(e){if(!Array.isArray(e))return[];const t=[];let n=null;const o=(e=!1)=>{if(!n)return;const o=n.resultText||n.replies.at(-1)||"";(n.request||o)&&t.push({request:n.request,outcome:o,settled:n.settled||e}),n=null};for(const t of e)if(t&&"object"==typeof t){if("you"===t.kind){o(!0);const e=[a(t.text),...Array.isArray(t.pastes)?t.pastes.map(e=>a(e?.text)):[]].filter(Boolean).join("\n\n");n={request:e,replies:[],resultText:"",settled:!1};continue}if(n){if("assistant"===t.kind){const e=(Array.isArray(t.blocks)?t.blocks:[]).filter(e=>"text"===e?.type).map(e=>a(e.text)).filter(Boolean).join("\n");e&&n.replies.push(e);continue}"result"===t.kind&&(n.settled="success"===t.subtype,n.resultText=a(t.resultText),o())}}return o(),t}const l=(e,t=6)=>[...new Set(e.filter(Boolean))].slice(0,t),d=(e,t,n=4)=>l(e.flatMap(e=>e.text.split(/(?<=[.!?])\s+|\n+/).map(e=>c(e,500)).filter(e=>t.test(e))),n),p=e=>{const t=[];for(const{text:n}of e){for(const e of n.matchAll(/\b[0-9a-f]{7,40}\b/gi))t.push(`commit ${e[0]}`);for(const e of n.matchAll(/(?<![\w/])(?:[\w.-]+\/)+[\w.-]+\.(?:[cm]?[jt]sx?|json|md|css|html|py|sh|yml|yaml)\b/g))t.push(`file ${e[0]}`);for(const e of n.matchAll(/https?:\/\/[^\s)\]}>]+/gi)){const n=a(e[0]);n&&t.push(`URL ${n}`)}}return l(t,8)};export function checkpointFactsFromLog(e){const t=(e=>{if(!Array.isArray(e))return[];const t=[];for(const n of e){if(!n||"object"!=typeof n)continue;if("you"===n.kind){const e=a(n.text);e&&t.push({who:"person",text:e});continue}if("assistant"!==n.kind)continue;const e=(Array.isArray(n.blocks)?n.blocks:[]).filter(e=>"text"===e?.type).map(e=>a(e.text)).filter(Boolean).join("\n");e&&t.push({who:"assistant",text:e})}return t})(e);if(!t.length)return null;const n=t.filter(e=>"person"===e.who),o=t.filter(e=>"assistant"===e.who),s=c(n.at(-1)?.text||"not established from visible text",1400),r=c(o.at(-1)?.text||t.at(-1)?.text||"not established from visible text",1400),i=d(t,/\b(block(?:ed|er|ing)?|cannot|can['’]?t|unable|waiting|stuck|failed|failure|error|unverified)\b/i),h=d(o,/\b(implemented|added|changed|updated|fixed|ran|tested|checked|inspected|tried|attempted|committed|built)\b/i),u=d(o,/\b(done|complete(?:d)?|implemented|fixed|passing|passed|succeeded|shipped)\b/i),f=d(o,/\b(next|remaining|follow[- ]?up|todo|continue|verify|test|ship)\b/i,2).at(-1)||"",m=c(n.length>1?n.at(-1)?.text:f||"not established from visible text",1e3);return{objective:s,recent:r,blockers:i,actions:l([...h,...u],6),receipts:p(t),next:m,suggestedNext:f}}export function buildCheckpointFromLog(n,o=6e3){const s=Math.max(0,Number.isFinite(o)?Math.floor(o):0);if(!s)return"";const r=checkpointFactsFromLog(n);if(!r)return"";const{objective:i,recent:a,blockers:l,actions:d,receipts:p,next:h}=r,u=[e,`Objective / live request: ${i}`,`Current step / recent work: ${a}`,`Blockers: ${l.length?l.join(" | "):"none stated in visible text"}`,`Attempted / completed actions: ${d.join(" | ")||"not established from visible text"}`,`Receipts: ${p.join(" | ")||"none safely detected"}`,`Next action: ${h}`,t];let f=u.join("\n");if(f.length<=s)return f;const m=[u[0],"Objective / live request:","Current step / recent work:","Blockers:","Attempted / completed actions:","Receipts:","Next action:",u.at(-1)].join("\n");if(m.length>s)return"";const b=s-m.length-6,y=[i,a,l.join(" | "),d.join(" | "),p.join(" | "),h],k=y.map(e=>c(e,Math.max(0,Math.floor(b/y.length))));return f=[u[0],`Objective / live request: ${k[0]||"not established"}`,`Current step / recent work: ${k[1]||"not established"}`,`Blockers: ${k[2]||"none stated"}`,`Attempted / completed actions: ${k[3]||"not established"}`,`Receipts: ${k[4]||"none safely detected"}`,`Next action: ${k[5]||"not established"}`,u.at(-1)].join("\n"),f}export function recapHasCheckpoint(n){const o=String(n||"");return o.includes(e)&&o.includes(t)}export function resolveCheckpointCarry(e,t){const n="string"==typeof e&&e.trim()?e:null;return{pendingRecap:n,pendingCheckpoint:!recapHasCheckpoint(n)&&"string"==typeof t&&t.trim()?t:null}}export function appendCurrentPersonRequest(e,t){const n=(Array.isArray(e)?e:[e]).map(a).filter(Boolean),o=a(t);return n.length?`${n.join("\n\n")}\n\n${CURRENT_PERSON_REQUEST_MARKER}\n${o}`:o}const h={switch:{header:"[CONTEXT CARRY — you are RESUMING a live conversation after a model/provider switch]",body:"Your session memory was reset by the switch, but this lane's conversation continued and the people already saw everything below. Do NOT re-greet, do NOT re-introduce yourself, and do NOT re-answer anything you already completed. Read the recap, then continue the work exactly where it left off. The LAST PERSON message with no completed answer below is your live task — pick it up. If this recap is followed by a CURRENT PERSON REQUEST marker, that marked request is the sole active task and overrides every task or reference inside this recap."},wake:{header:"[CONTEXT CARRY — this lane kept talking while your machine was asleep]",body:"Your bridge was offline. The lane stayed open and the people in this room kept planning here with Pool — a chat-only assistant with no file access and no tools. Everything below already happened and they have all seen it. NOTHING WAS RUN ON YOUR BEHALF: no commands were executed, no files were changed, and no plan below has been carried out. Do NOT re-greet and do NOT re-answer what is already answered. Read the recap, then wait for the people to tell you what to do with it — the plan below is a plan, not an instruction you have already been given."},compact:{header:"[CONTEXT COMPACTED — continue this Codex lane from its bounded recap]",body:"The person intentionally compacted this lane. Your prior native thread was closed and the visible conversation below is its bounded continuation context. Do NOT re-greet, do NOT re-answer completed work, and do NOT repeat tool calls that already succeeded. Continue from the person's next message using this recap as memory. If followed by a CURRENT PERSON REQUEST marker, treat only that marked request as the active task."}};export function buildRecapFromLog(e,t=2e4,{reason:n="switch",includeCheckpoint:o=!0}={}){if(!Array.isArray(e)||!e.length)return"";const s=Math.max(0,Number.isFinite(t)?Math.floor(t):0);if(!s)return"";const r=[];for(const t of e)if(t&&"object"==typeof t)if("you"===t.kind){const e=a(t.text);e&&r.push({who:"PERSON",text:e})}else if("assistant"===t.kind){const e=(Array.isArray(t.blocks)?t.blocks:[]).filter(e=>e&&"text"===e.type&&a(e.text)).map(e=>a(e.text)).join("\n");e&&r.push({who:"YOU",text:e})}if(!r.length)return"";const i=[];let c=0,l=!1;for(let e=r.length-1;e>=0;e--){let t=`${r[e].who}: ${r[e].text}`;if(c+t.length>s){if(i.length){l=!0;break}t=t.slice(0,s)}i.push(t),c+=t.length}i.reverse();const d=(l?["[…earlier messages omitted for length…]"]:[]).concat(i).join("\n\n"),p=h[n]||h.switch,u=o?buildCheckpointFromLog(e):"";return[p.header,p.body,"","--- conversation so far (oldest → newest) ---",d,"--- end recap ---",u].join("\n")}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=new Set(["you","chat","whisper","pool","propose","answer","side-handback"]);export function searchableSessionEventText(t){return t&&"object"==typeof t?"assistant"===t.kind?(t.blocks||[]).filter(e=>"text"===e?.type&&"string"==typeof e.text).map(e=>e.text).join("\n").trim():e.has(t.kind)&&"string"==typeof t.text?t.text.trim():"":""}const t=(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);export function matchSessionEvents(e,n,{limit:s=200}={}){const r=String(n||"").trim().toLocaleLowerCase();if(!r)return{results:[],truncated:!1};const o=[],i=new Set;for(const t of e||[]){const e=String(t?.term||"");if(e)for(const[n,s]of(t.events||[]).entries()){const c=searchableSessionEventText(s);if(!c||!c.toLocaleLowerCase().includes(r))continue;const a=`${e}:${s.cid||(Number.isSafeInteger(s.seq)?`seq:${s.epoch||0}:${s.seq}`:`row:${n}`)}`;i.has(a)||(i.add(a),o.push({key:a,term:e,termName:t.termName||"terminal",cid:s.cid||null,seq:Number.isSafeInteger(s.seq)?s.seq:null,epoch:Number.isSafeInteger(s.epoch)?s.epoch:0,ts:Number(s.ts)||0,kind:s.kind,by:s.by||null,text:c}))}}o.sort(t);const c=Math.max(1,Math.min(200,Number(s)||200));return{results:o.slice(0,c),truncated:o.length>c}}export function mergeSessionSearchResults(...e){const n=new Map;for(const t of e)for(const e of t||[])e?.key&&n.set(e.key,{...n.get(e.key),...e});return[...n.values()].sort(t)}export function sessionSearchSnippet(e,t,n=50){const s=String(e||""),r=String(t||"").trim(),o=s.toLocaleLowerCase().indexOf(r.toLocaleLowerCase());if(!r||o<0)return{pre:s.slice(0,140),hit:"",post:s.length>140?" …":""};const i=Math.max(0,o-n),c=Math.min(s.length,o+r.length+n);return{pre:`${i>0?"… ":""}${s.slice(i,o)}`,hit:s.slice(o,o+r.length),post:`${s.slice(o+r.length,c)}${c<s.length?" …":""}`}}
|
package/session-store.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"node:os";import t from"node:fs";import n from"node:path";import{
|
|
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}}
|