thinkpool-pair 0.7.398 → 0.7.400
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/acp-event-mapper.mjs +1 -0
- package/acp-runtime-adapter.mjs +1 -0
- package/agent-visibility.mjs +1 -1
- package/branch-checkpoint.mjs +1 -0
- package/bridge.mjs +1 -1
- package/command-catalog.mjs +1 -1
- package/event-id.mjs +1 -1
- package/lane-worktree.mjs +1 -1
- package/launcher.mjs +1 -1
- package/opencode-policy.mjs +1 -0
- package/opencode-probe.mjs +1 -0
- package/opencode-session.mjs +1 -0
- package/package.json +11 -1
- package/permission-rules.mjs +1 -0
- package/public-proof.mjs +1 -0
- package/publish-manifest.json +25 -15
- package/recap.mjs +1 -1
- package/runtime-adapter.mjs +1 -0
- package/runtime-compatibility-profile.mjs +1 -0
- package/runtime-contract.mjs +1 -1
- package/runtime-registry.mjs +1 -1
- package/runtime-session.mjs +1 -1
package/command-catalog.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=(e,t,n,i,r=["claude","codex","hermes"])=>Object.freeze({name:e,description:t,route:n,...i?{inputHint:i}:{},runtimes:Object.freeze(r)});export const CODE_ROOM_COMMANDS=Object.freeze([e("/handoff","save a concise checkpoint or handoff","handoff","optional end goal"),e("/side","ask or investigate without interrupting this terminal","side","task"),e("/help","list commands available in this lane","control"),e("/status","runtime, model, permissions, and busy state","control"),e("/usage","session usage and provider limits","control"),e("/context","current context-window usage","control"),e("/diff","Git changes and branch status","control"),e("/find","find relevant files in this repository","control","query"),e("/compact","compact context","runtime"),e("/clear","clear context · confirms","clear"),e("/model","pick model — opens selector","model"),e("/mode","set permission mode","mode","normal | auto-accept | plan | bypass"),e("/effort","set reasoning effort","effort","none | minimal | low | medium | high | xhigh | max | ultra"),e("/queue","run a prompt after the active turn","queue","prompt"),e("/steer","guide the active turn","steer","prompt",["codex","hermes"]),e("/credits","provider credit balance","credits",null,["codex","hermes"]),e("/review","review uncommitted changes","runtime",null,["codex"])]);const t=Object.freeze({claude:Object.freeze({accept:!0,hidden:Object.freeze(new Set(["/flow"]))}),codex:Object.freeze({accept:!1,hidden:Object.freeze(new Set(["/flow"]))}),hermes:Object.freeze({accept:!0,hidden:Object.freeze(new Set(["/flow","/reasoning"]))})}),n=e=>{const t=(e=>{const t=`/${String(("string"==typeof e?e:e?.name)||"").trim().replace(/^\/+/,"")}`;return/^\/[A-Za-z0-9][A-Za-z0-9:_-]*$/.test(t)?t:""})(e);if(!t)return null;if("string"==typeof e)return{name:t,description:"runtime command",route:"runtime"};const n=String(e?.description||"").trim()||"runtime command",i=String(e?.inputHint||e?.input_hint||e?.input?.hint||"").trim();return{name:t,description:n,route:String(e?.route||"").trim()||"runtime",...i?{inputHint:i}:{}}};export function commandCatalogForRuntime(e,i=[]){const r=(e=>"thinkpool"===e?"hermes":e)(e),o=t[r]||t.codex,c=new Map;for(const e of CODE_ROOM_COMMANDS)e.runtimes.includes(r)&&c.set(e.name,{name:e.name,description:e.description,route:e.route,...e.inputHint?{inputHint:e.inputHint}:{}});for(const e of Array.isArray(i)?i:[]){const t=n(e);if(!t||!o.accept||o.hidden.has(t.name))continue;const i=c.get(t.name),s="hermes"===r&&["/help","/status","/context","/credits"].includes(t.name);c.set(t.name,i?{...t,...i,description:"runtime command"===t.description?i.description:t.description,...t.inputHint?{inputHint:t.inputHint}:{},...s?{route:"runtime"}:{}}:t)}return[...c.values()]}export const commandNeedsInput=e=>!!String(e?.inputHint||"").trim();export const commandRoute=e=>String(e?.route||"runtime");export function commandHelpLine(e){return(Array.isArray(e)?e:[]).map(e=>`${e.name}${e.inputHint?` <${e.inputHint}>`:""}`).join(" ")}export function normalizePermissionMode(e){const t=String(e||"").trim().toLowerCase().replace(/[\s_-]+/g,"");return["normal","default","manual"].includes(t)?"default":["auto","autoaccept","autoacceptedits","acceptedits"].includes(t)?"acceptEdits":"plan"===t?"plan":["bypass","bypasspermissions","fullauto"].includes(t)?"bypassPermissions":null}export function reconcileCommandCatalog({current:e,incoming:t,onChanged:n,onLifecycle:i}={}){const r=Array.isArray(t)&&t.length>0,o=r&&JSON.stringify(e||[])===JSON.stringify(t);return r&&!o&&n?.(t),i?.({duplicate:o,hasIncoming:r}),o}
|
|
1
|
+
const e=(e,t,n,i,r=["claude","codex","hermes","opencode"])=>Object.freeze({name:e,description:t,route:n,...i?{inputHint:i}:{},runtimes:Object.freeze(r)});export const CODE_ROOM_COMMANDS=Object.freeze([e("/handoff","save a concise checkpoint or handoff","handoff","optional end goal"),e("/side","ask or investigate without interrupting this terminal","side","task"),e("/help","list commands available in this lane","control"),e("/status","runtime, model, permissions, and busy state","control"),e("/usage","session usage and provider limits","control"),e("/context","current context-window usage","control"),e("/diff","Git changes and branch status","control"),e("/find","find relevant files in this repository","control","query"),e("/compact","compact context","runtime"),e("/clear","clear context · confirms","clear"),e("/model","pick model — opens selector","model"),e("/mode","set permission mode","mode","normal | auto-accept | plan | bypass"),e("/effort","set reasoning effort","effort","none | minimal | low | medium | high | xhigh | max | ultra"),e("/queue","run a prompt after the active turn","queue","prompt"),e("/steer","guide the active turn","steer","prompt",["codex","hermes"]),e("/credits","provider credit balance","credits",null,["codex","hermes"]),e("/review","review uncommitted changes","runtime",null,["codex"])]);const t=Object.freeze({claude:Object.freeze({accept:!0,hidden:Object.freeze(new Set(["/flow"]))}),codex:Object.freeze({accept:!1,hidden:Object.freeze(new Set(["/flow"]))}),hermes:Object.freeze({accept:!0,hidden:Object.freeze(new Set(["/flow","/reasoning"]))})}),n=e=>{const t=(e=>{const t=`/${String(("string"==typeof e?e:e?.name)||"").trim().replace(/^\/+/,"")}`;return/^\/[A-Za-z0-9][A-Za-z0-9:_-]*$/.test(t)?t:""})(e);if(!t)return null;if("string"==typeof e)return{name:t,description:"runtime command",route:"runtime"};const n=String(e?.description||"").trim()||"runtime command",i=String(e?.inputHint||e?.input_hint||e?.input?.hint||"").trim();return{name:t,description:n,route:String(e?.route||"").trim()||"runtime",...i?{inputHint:i}:{}}};export function commandCatalogForRuntime(e,i=[]){const r=(e=>"thinkpool"===e?"hermes":e)(e),o=t[r]||t.codex,c=new Map;for(const e of CODE_ROOM_COMMANDS)e.runtimes.includes(r)&&c.set(e.name,{name:e.name,description:e.description,route:e.route,...e.inputHint?{inputHint:e.inputHint}:{}});for(const e of Array.isArray(i)?i:[]){const t=n(e);if(!t||!o.accept||o.hidden.has(t.name))continue;const i=c.get(t.name),s="hermes"===r&&["/help","/status","/context","/credits"].includes(t.name);c.set(t.name,i?{...t,...i,description:"runtime command"===t.description?i.description:t.description,...t.inputHint?{inputHint:t.inputHint}:{},...s?{route:"runtime"}:{}}:t)}return[...c.values()]}export const commandNeedsInput=e=>!!String(e?.inputHint||"").trim();export const commandRoute=e=>String(e?.route||"runtime");export function commandHelpLine(e){return(Array.isArray(e)?e:[]).map(e=>`${e.name}${e.inputHint?` <${e.inputHint}>`:""}`).join(" ")}export function normalizePermissionMode(e){const t=String(e||"").trim().toLowerCase().replace(/[\s_-]+/g,"");return["normal","default","manual"].includes(t)?"default":["auto","autoaccept","autoacceptedits","acceptedits"].includes(t)?"acceptEdits":"plan"===t?"plan":["bypass","bypasspermissions","fullauto"].includes(t)?"bypassPermissions":null}export function reconcileCommandCatalog({current:e,incoming:t,onChanged:n,onLifecycle:i}={}){const r=Array.isArray(t)&&t.length>0,o=r&&JSON.stringify(e||[])===JSON.stringify(t);return r&&!o&&n?.(t),i?.({duplicate:o,hasIncoming:r}),o}
|
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=[],
|
|
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=[],r=0;for(let i=e.length-1;i>=0;i--){const a=JSON.stringify(e[i]).length+1;if(s.length&&r+a>t){if(o.push(s),o.length>=n){s=null;break}s=[],r=0}s.push(e[i]),r+=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:r,fetchImpl:i=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 i(`${e}/api/code-image`,{method:"POST",headers:f,signal:c.signal,body:JSON.stringify({code:t,term:o,cid:s,idx:r.idx,mediaType:r.mediaType,b64:r.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 r=e=>Buffer.byteLength(String(e?.b64||""),"ascii");function i(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:r=()=>{},onOverload:i=()=>{}}){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=r,this.onOverload=i,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+r(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=r(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&&(i(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){i(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,r=0,i=!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&&(r+=e.costUsd,i=!0)}return{turns:t.length,per:[...n.values()],totalIn:o,totalOut:s,totalCost:r,haveCost:i}}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,r=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(" · "),i=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"} · ${r}${i}${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)),r=Math.max(0,Number(n.used)||0),i=Math.max(0,Number(n.max)||0),a=i>0?Math.min(100,Math.max(0,Math.round(r/i*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(r)}/${s(i)} (${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,resolveIdleRestoreCarry,visibleWorkTurnsFromLog}from"./recap.mjs";
|
package/lane-worktree.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execFileSync as r}from"node:child_process";import e from"node:path";import t from"node:fs";const o=[".env.local",".env.development.local"];export function linkLocalEnvIntoWorktree({root:r,dir:n,fsImpl:i=t}={}){const a=[];for(const t of o){const o=e.join(r,t),
|
|
1
|
+
import{execFileSync as r}from"node:child_process";import e from"node:path";import t from"node:fs";const o=[".env.local",".env.development.local"];export function linkLocalEnvIntoWorktree({root:r,dir:n,fsImpl:i=t}={}){const a=[];for(const t of o){const o=e.join(r,t),s=e.join(n,t);try{if(!i.existsSync?.(o)||i.existsSync?.(s))continue;i.symlinkSync?.(o,s),a.push(t)}catch{}}return a}export function createManagedLaneWorktree({terminalId:r,cwd:o=process.cwd(),baseSha:i=null,git:a=n,fsImpl:s=t}={}){const c=String(r||""),l=c.replace(/[^a-zA-Z0-9]/g,"").slice(0,8);if(!l)throw new Error("terminal id required for managed worktree");const m=String(a(["rev-parse","--show-toplevel"],o)||"").trim();if(!m)throw new Error("not a git repository");const d=e.join(m,".thinkpool","worktrees",`terminal-${l}`),p=`thinkpool/terminal/${l}`,h=null==i?function({root:r,git:e}){for(const t of["origin/HEAD","origin/main","origin/master","main","master","HEAD"])try{if(String(e(["rev-parse","--verify","--quiet",t],r)||"").trim())return t}catch{}return"HEAD"}({root:m,git:a}):function({root:r,baseSha:e,git:t}){const o=String(e||"").trim().toLowerCase();if(!/^[a-f0-9]{40}$/.test(o))throw new Error("exact base SHA required for checkpoint branch");let n="";try{n=String(t(["rev-parse","--verify",`${o}^{commit}`],r)||"").trim().toLowerCase()}catch{}if(n!==o)throw new Error("checkpoint base SHA is unavailable in this repository");return o}({root:m,baseSha:i,git:a});return s.mkdirSync(e.dirname(d),{recursive:!0}),a(["worktree","add","-b",p,d,h],m),linkLocalEnvIntoWorktree({root:m,dir:d,fsImpl:s}),{terminalId:c,root:m,dir:d,branch:p,...null==i?{}:{baseSha:h}}}export function removeManagedLaneWorktree({terminalId:r,managedWorktree:t,git:o=n}={}){const i=String(r||""),a=t&&"object"==typeof t?t:null;if(!i||!a||a.terminalId!==i)return{removed:!1,reason:"not managed by this terminal"};const s=e.resolve(String(a.root||"")),c=e.resolve(String(a.dir||"")),l=String(a.branch||""),m=e.join(s,".thinkpool","worktrees"),d=i.replace(/[^a-zA-Z0-9]/g,"").slice(0,8);if(!s||c===m||!c.startsWith(m+e.sep))return{removed:!1,reason:"path outside managed worktrees"};if(!d||!e.basename(c).includes(d)||!l.startsWith(`thinkpool/terminal/${d}`))return{removed:!1,reason:"ownership marker mismatch"};try{o(["worktree","remove",c,"--force"],s)}catch{}try{o(["branch","-D",l],s)}catch{}return{removed:!0,dir:c,branch:l}}function n(e,t){return r("git",e,{cwd:t,stdio:["ignore","pipe","pipe"],encoding:"utf8"})}
|
package/launcher.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"node:os";import n from"node:fs";import t from"node:path";import{execSync as r}from"node:child_process";import{detectProvider as i,fetchModels as o,ANTHROPIC_COMPATIBLE as a,gatewayHint as s}from"./byok-detect.mjs";import{probeHermesRuntime as l}from"./hermes-probe.mjs";import{darwinServiceRunning as c,serviceRuntimeVersion as p}from"./service.mjs";import{loadKeepAwakePreference as d}from"./keep-awake.mjs";const u=e.homedir(),m=t.join(u,".thinkpool-pair"),h=(()=>{try{return JSON.parse(n.readFileSync(new URL("./package.json",import.meta.url),"utf8")).version}catch{return null}})();export const KNOWN_AGENTS=[{label:"Claude Code",cmd:"claude",resume:["--continue"]},{label:"Codex",cmd:"codex"},{label:"Hermes",cmd:"thinkpool"}];function k(e){const r="win32"===process.platform?(process.env.PATHEXT||".EXE;.CMD;.BAT;.COM").split(";"):[""];for(const i of(process.env.PATH||"").split(t.delimiter))if(i)for(const o of r)try{if(n.existsSync(t.join(i,e+o)))return!0}catch{}return!1}function f(e){try{return JSON.parse(n.readFileSync(e,"utf8"))}catch{return null}}export function detectState(){const e=f(t.join(m,"auth.json")),i=f(t.join(m,"provider.json")),o=!!i?.provider&&"anthropic"!==i.provider,a=k("hermes"),s=k("thinkpool")&&l().available,v=function(e){const i=e?`io.thinkpool.pair.${e.toLowerCase()}`:"io.thinkpool.pair.account";try{if("darwin"===process.platform){const e=r(`launchctl print gui/$(id -u)/${i}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return c(e)}return"linux"===process.platform?(r(`systemctl --user is-active --quiet ${i}.service`),!0):n.existsSync(function(e){const n=e?`io.thinkpool.pair.${e.toLowerCase()}`:"io.thinkpool.pair.account";if("darwin"===process.platform)return t.join(u,"Library","LaunchAgents",`${n}.plist`);if("linux"===process.platform)return t.join(u,".config","systemd","user",`${n}.service`);const r=t.join(process.env.APPDATA||t.join(u,"AppData","Roaming"),"Microsoft","Windows","Start Menu","Programs","Startup");return t.join(r,`thinkpool-pair-${e||"account"}.cmd`)}(e))}catch{return!1}}(null),g=!!e?.reconnect_required;return{loggedIn:!!e?.refresh_token&&!g,reconnectRequired:g,email:e?.email||e?.user?.email||null,provider:o?`Custom (${i.baseUrl||"endpoint"})`:"Anthropic (default)",providerModel:o&&i.model||null,agents:KNOWN_AGENTS.filter(e=>k(e.cmd)&&("thinkpool"!==e.cmd||s)),hermesInstalled:a,hermesReady:s,accountSvc:v,keepAwake:d(),serviceVersion:v?p(null):null,platform:process.platform,cwd:process.cwd(),version:h}}const v=e=>`[2m${e}[0m`,g=e=>`[1m${e}[0m`,y=e=>`[36m${e}[0m`,w=e=>`[32m${e}[0m`,b=e=>`[33m${e}[0m`;export async function runLauncher({actions:e,io:n,state:t=detectState(),refresh:r=null}){const l=e=>({...e,agents:Array.isArray(e?.agents)?e.agents:[],loggedIn:!!e?.loggedIn,reconnectRequired:!!e?.reconnectRequired,accountSvc:!!e?.accountSvc,keepAwake:!0===e?.keepAwake,serviceVersion:"string"==typeof e?.serviceVersion&&e.serviceVersion?e.serviceVersion:null,platform:e?.platform||process.platform,provider:e?.provider||"Anthropic (default)",cwd:e?.cwd||process.cwd(),version:e?.version||h});t=l(t);const c=()=>{r&&(t=l(r()))},p=async(e,t,r=1)=>{t.forEach((e,t)=>n.print(` ${y(String(t+1))}) ${e.label}${e.hint?" "+v(e.hint):""}`));const i=await n.ask(`\n ${e} ${v(`[${r}]`)} ${y("▸")} `),o=parseInt(i,10);return Number.isInteger(o)&&o>=1&&o<=t.length?o-1:r-1},d=async(e,t=!0)=>{const r=(await n.ask(` ${e} ${v(t?"[Y/n]":"[y/N]")} ${y("▸")} `)).toLowerCase();return r?"y"===r[0]:t},u=()=>{n.print(""),n.print(" "+v("┌ ")+g("thinkpool-pair")+v(" "+"─".repeat(40))),n.print(` ${v("│ launcher ")} ${t.version?`v${t.version}`:"version unavailable"}`),n.print(` ${v("│ account ")} ${t.reconnectRequired?b("reconnect required"):t.loggedIn?w((t.email||"linked")+" ✓"):b("not linked")}`),n.print(` ${v("│ agents ")} ${t.agents.length?t.agents.map(e=>e.label).join(", "):b("none ready: install Claude Code, Codex, or Hermes")}`),n.print(` ${v("│ directory")} ${v(t.cwd)}`);const e=t.accountSvc?"win32"===t.platform?w("startup entry installed"):w("running"+(t.serviceVersion?` v${t.serviceVersion}`:" (version unavailable)")):"not installed";n.print(` ${v("│ bridge ")} ${e}`),n.print(` ${v("│ keep awake")} ${t.keepAwake?w("on")+v(", display may still dim"):"off"}`),n.print(" "+v("└"+"─".repeat(54))+"\n")},m=async()=>!!t.loggedIn||(n.print("\n "+b(t.reconnectRequired?"This bridge lost its thinkpool account link.":"You are not linked to a thinkpool account yet.")),await d(" Link this device now?",!0)&&(await e.login(),c()),!!t.loggedIn||(n.print(" "+b("login needed to serve your sessions — back to menu")),!1)),k=async()=>!!t.agents.length||(n.print("\n "+b("No coding agent is ready on this computer")),n.print(" thinkpool connects an agent already installed on this machine. It does not"),n.print(" include one. Install and configure at least one of:"),n.print(`\n ${y("Claude Code")} command: claude`),n.print(` ${y("Codex")} command: codex`),n.print(` ${y("Hermes")} command: hermes, then set up its thinkpool profile here`),n.print("\n "+g("BYOK does not replace the agent. It only gives an installed agent")),n.print(" credentials for a model provider."),n.print("\n Install one, then reopen this launcher."),!1),f=async()=>{const r=t.provider+(t.providerModel?`, model ${t.providerModel}`:"");n.print("\n "+v("Provider settings supply model credentials. Claude Code, Codex, or Hermes must still be installed locally."));const l=await p("\n provider",[{label:"Anthropic (default)",hint:"regular Claude login"},{label:"Paste a key, pick a model",hint:"auto-detects the provider · OpenRouter = any model"},{label:"Custom endpoint",hint:"enter a base url + token by hand"},{label:"← Back",hint:`current: ${r}`}],4);if(3===l)return;if(0===l)return await e.setProvider({kind:"anthropic"}),c(),void n.print("\n "+w("✓ back on regular Claude."));if(1===l){const t=(await n.ask(`\n Paste your API key ${v("(blank to cancel)")} ${y("▸")} `)).trim();if(!t)return void n.print(" "+b("cancelled — provider unchanged"));const r=i(t);if(!r.compatible)return void n.print("\n "+b(s(r.name)));const l=a[r.id];n.print(`\n ${w("✓ detected "+l.name)} ${v("— fetching models…")}`);const d=await o({modelsUrl:l.models,key:t,auth:l.auth});let u;if(0===d.length)u=(await n.ask(` Couldn't list models. Model id ${v("(blank = endpoint default)")} ${y("▸")} `)).trim()||void 0;else if(d.length<=40){const e=await p("\n model",d.map(e=>({label:e})),1);u=d[e]}else for(n.print(` ${v(d.length+" models available, e.g. "+d.slice(0,3).join(", ")+"…")}`);;){const e=(await n.ask(` Type a model id or part of it ${v("(blank to cancel)")} ${y("▸")} `)).trim();if(!e)return void n.print(" "+b("cancelled — provider unchanged"));const t=d.filter(n=>n.toLowerCase().includes(e.toLowerCase()));if(0!==t.length){if(1===t.length){u=t[0];break}if(t.length<=40){const e=await p("\n pick",t.map(e=>({label:e})),1);u=t[e];break}n.print(` ${b(t.length+" matches — narrow it down")}`)}else n.print(" "+b("no match — try again"))}return await e.setProvider({kind:"custom",base:l.base,token:t,model:u}),c(),void n.print(`\n ${w("✓ provider set.")}\n ${l.name}\n model: ${u||"(endpoint default)"}`)}const d=(await n.ask(`\n Base url ${v("(blank to cancel · SDK appends /v1/messages)")} ${y("▸")} `)).trim();if(!d)return void n.print(" "+b("cancelled — provider unchanged"));const u=(await n.ask(` API token ${v("(blank to cancel)")} ${y("▸")} `)).trim();if(!u)return void n.print(" "+b("cancelled — provider unchanged"));const m=(await n.ask(` Model ${v("(blank = endpoint default · e.g. glm-4.6)")} ${y("▸")} `)).trim();await e.setProvider({kind:"custom",base:d,token:u,model:m||void 0}),c(),n.print(`\n ${w("✓ provider set to custom.")}\n base url: ${t.provider}\n model: ${t.providerModel||"(endpoint default)"}`)},$=async()=>{for(;;){const r=[{key:"provider",label:"Provider",hint:`current: ${t.provider}`},{key:"account",label:"Account",hint:t.reconnectRequired?"reconnect required":t.loggedIn?`linked: ${t.email||"yes"}`:"not linked"},{key:"awake",label:"Keep computer awake",hint:(t.keepAwake?"ON":"off")+" · the screen can still dim, lock, and turn off"}];t.hermesInstalled&&r.push({key:"hermes",label:t.hermesReady?"Hermes profile":"Set up Hermes",hint:t.hermesReady?"isolated profile ready":"set up isolated profile + delegation guard"}),r.push({key:"back",label:"Back to main menu",hint:""});const i=r[await p("\n change",r,r.length)];if("back"===i.key)return;if("provider"===i.key)await f();else{if("account"===i.key)return await e.login(),void c();if("awake"===i.key)if(t.keepAwake){if(!1===await e.setKeepAwake({enabled:!1}))continue;t={...t,keepAwake:!1},c(),n.print("\n "+w("✓ keep-awake is off. The computer may sleep normally."))}else if(n.print("\n "+b("Important: keep-awake changes this computer’s power behavior")),n.print(" While the bridge runs, thinkpool will prevent the computer itself from"),n.print(" automatically sleeping. This can use substantially more battery and may"),n.print(" also block suspend requests on some Linux systems."),n.print("\n "+w("It does NOT keep the screen on. Display dimming, screen locking, and")),n.print(" display sleep continue to work normally. Closing a laptop lid may still"),n.print(" sleep it, depending on the operating system and power settings."),await d("\n Enable keep-awake while the thinkpool bridge runs?",!1)){if(!1===await e.setKeepAwake({enabled:!0}))continue;t={...t,keepAwake:!0},c(),n.print("\n "+w("✓ keep-awake is on. Your screen is still free to dim and turn off."))}else n.print("\n "+b("unchanged: keep-awake remains off."));else if("hermes"===i.key){const n=await p("\n Hermes profile",[{label:"Clone active profile",hint:"copies provider/config explicitly; fresh thinkpool session history"},{label:"Create clean profile",hint:"no copied credentials or bundled skills; configure provider afterward"},{label:"Back",hint:""}],3);2!==n&&(await e.setupHermes({mode:0===n?"clone":"clean"}),c())}}}};for(;;){u(),n.print(" "+g("What do you want to do?")+"\n");const r=t.accountSvc?["win32"===t.platform?{key:"restart",label:"Update startup entry",hint:"installs the latest version; relaunch the bridge window to apply"}:{key:"restart",label:"Restart & update bridge",hint:"install the latest published version; sessions resume"},{key:"uninstall",label:"Remove background service",hint:"stop serving your sessions on this device"}]:[{key:"serve",label:"Serve all my sessions",hint:"runs here, Ctrl-C stops it"},{key:"service",label:"Always-on background service",hint:"recommended — survives reboot, restarts on crash"}];r.push({key:"settings",label:"Settings",hint:`provider · account · keep-awake ${t.keepAwake?"ON":"off"}${t.hermesInstalled?" · Hermes profile":""}`}),r.push({key:"quit",label:"Quit",hint:""});const i=r[await p("choose",r)];if("quit"===i.key)return;if("serve"===i.key)await k()&&await m()&&await e.serveAccountForeground();else if("service"===i.key){if(await k()&&await m()){if(!0===await e.installService({room:null})&&(!e.relaunchLauncher||await e.relaunchLauncher()))return;c()}}else if("restart"===i.key){if(!0===await e.restartUpdateService({room:null})&&(!e.relaunchLauncher||await e.relaunchLauncher()))return;c()}else"uninstall"===i.key?(await e.uninstallService({room:null}),c()):"settings"===i.key&&await $();await n.ask("\n "+v("press Enter to return to the menu…"))}}
|
|
1
|
+
import e from"node:os";import n from"node:fs";import t from"node:path";import{execSync as r}from"node:child_process";import{detectProvider as o,fetchModels as i,ANTHROPIC_COMPATIBLE as a,gatewayHint as s}from"./byok-detect.mjs";import{probeHermesRuntime as l}from"./hermes-probe.mjs";import{probeOpenCodeRuntime as c}from"./opencode-probe.mjs";import{darwinServiceRunning as p,serviceRuntimeVersion as d}from"./service.mjs";import{loadKeepAwakePreference as u}from"./keep-awake.mjs";const m=e.homedir(),h=t.join(m,".thinkpool-pair"),k=(()=>{try{return JSON.parse(n.readFileSync(new URL("./package.json",import.meta.url),"utf8")).version}catch{return null}})();export const KNOWN_AGENTS=[{label:"Claude Code",cmd:"claude",resume:["--continue"]},{label:"Codex",cmd:"codex"},{label:"Hermes",cmd:"thinkpool"},{label:"OpenCode",cmd:"opencode"}];function f(e){const r="win32"===process.platform?(process.env.PATHEXT||".EXE;.CMD;.BAT;.COM").split(";"):[""];for(const o of(process.env.PATH||"").split(t.delimiter))if(o)for(const i of r)try{if(n.existsSync(t.join(o,e+i)))return!0}catch{}return!1}function v(e){try{return JSON.parse(n.readFileSync(e,"utf8"))}catch{return null}}export function detectState(){const e=v(t.join(h,"auth.json")),o=v(t.join(h,"provider.json")),i=!!o?.provider&&"anthropic"!==o.provider,a=f("hermes"),s=f("thinkpool")&&l().available,g=f("opencode")&&c().available,y=function(e){const o=e?`io.thinkpool.pair.${e.toLowerCase()}`:"io.thinkpool.pair.account";try{if("darwin"===process.platform){const e=r(`launchctl print gui/$(id -u)/${o}`,{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return p(e)}return"linux"===process.platform?(r(`systemctl --user is-active --quiet ${o}.service`),!0):n.existsSync(function(e){const n=e?`io.thinkpool.pair.${e.toLowerCase()}`:"io.thinkpool.pair.account";if("darwin"===process.platform)return t.join(m,"Library","LaunchAgents",`${n}.plist`);if("linux"===process.platform)return t.join(m,".config","systemd","user",`${n}.service`);const r=t.join(process.env.APPDATA||t.join(m,"AppData","Roaming"),"Microsoft","Windows","Start Menu","Programs","Startup");return t.join(r,`thinkpool-pair-${e||"account"}.cmd`)}(e))}catch{return!1}}(null),w=!!e?.reconnect_required;return{loggedIn:!!e?.refresh_token&&!w,reconnectRequired:w,email:e?.email||e?.user?.email||null,provider:i?`Custom (${o.baseUrl||"endpoint"})`:"Anthropic (default)",providerModel:i&&o.model||null,agents:KNOWN_AGENTS.filter(e=>f(e.cmd)&&("thinkpool"!==e.cmd||s)&&("opencode"!==e.cmd||g)),hermesInstalled:a,hermesReady:s,opencodeReady:g,accountSvc:y,keepAwake:u(),serviceVersion:y?d(null):null,platform:process.platform,cwd:process.cwd(),version:k}}const g=e=>`[2m${e}[0m`,y=e=>`[1m${e}[0m`,w=e=>`[36m${e}[0m`,b=e=>`[32m${e}[0m`,$=e=>`[33m${e}[0m`;export async function runLauncher({actions:e,io:n,state:t=detectState(),refresh:r=null}){const l=e=>({...e,agents:Array.isArray(e?.agents)?e.agents:[],loggedIn:!!e?.loggedIn,reconnectRequired:!!e?.reconnectRequired,accountSvc:!!e?.accountSvc,keepAwake:!0===e?.keepAwake,serviceVersion:"string"==typeof e?.serviceVersion&&e.serviceVersion?e.serviceVersion:null,platform:e?.platform||process.platform,provider:e?.provider||"Anthropic (default)",cwd:e?.cwd||process.cwd(),version:e?.version||k});t=l(t);const c=()=>{r&&(t=l(r()))},p=async(e,t,r=1)=>{t.forEach((e,t)=>n.print(` ${w(String(t+1))}) ${e.label}${e.hint?" "+g(e.hint):""}`));const o=await n.ask(`\n ${e} ${g(`[${r}]`)} ${w("▸")} `),i=parseInt(o,10);return Number.isInteger(i)&&i>=1&&i<=t.length?i-1:r-1},d=async(e,t=!0)=>{const r=(await n.ask(` ${e} ${g(t?"[Y/n]":"[y/N]")} ${w("▸")} `)).toLowerCase();return r?"y"===r[0]:t},u=()=>{n.print(""),n.print(" "+g("┌ ")+y("thinkpool-pair")+g(" "+"─".repeat(40))),n.print(` ${g("│ launcher ")} ${t.version?`v${t.version}`:"version unavailable"}`),n.print(` ${g("│ account ")} ${t.reconnectRequired?$("reconnect required"):t.loggedIn?b((t.email||"linked")+" ✓"):$("not linked")}`),n.print(` ${g("│ agents ")} ${t.agents.length?t.agents.map(e=>e.label).join(", "):$("none ready: install Claude Code, Codex, or Hermes")}`),n.print(` ${g("│ directory")} ${g(t.cwd)}`);const e=t.accountSvc?"win32"===t.platform?b("startup entry installed"):b("running"+(t.serviceVersion?` v${t.serviceVersion}`:" (version unavailable)")):"not installed";n.print(` ${g("│ bridge ")} ${e}`),n.print(` ${g("│ keep awake")} ${t.keepAwake?b("on")+g(", display may still dim"):"off"}`),n.print(" "+g("└"+"─".repeat(54))+"\n")},m=async()=>!!t.loggedIn||(n.print("\n "+$(t.reconnectRequired?"This bridge lost its thinkpool account link.":"You are not linked to a thinkpool account yet.")),await d(" Link this device now?",!0)&&(await e.login(),c()),!!t.loggedIn||(n.print(" "+$("login needed to serve your sessions — back to menu")),!1)),h=async()=>!!t.agents.length||(n.print("\n "+$("No coding agent is ready on this computer")),n.print(" thinkpool connects an agent already installed on this machine. It does not"),n.print(" include one. Install and configure at least one of:"),n.print(`\n ${w("Claude Code")} command: claude`),n.print(` ${w("Codex")} command: codex`),n.print(` ${w("Hermes")} command: hermes, then set up its thinkpool profile here`),n.print("\n "+y("BYOK does not replace the agent. It only gives an installed agent")),n.print(" credentials for a model provider."),n.print("\n Install one, then reopen this launcher."),!1),f=async()=>{const r=t.provider+(t.providerModel?`, model ${t.providerModel}`:"");n.print("\n "+g("Provider settings supply model credentials. Claude Code, Codex, or Hermes must still be installed locally."));const l=await p("\n provider",[{label:"Anthropic (default)",hint:"regular Claude login"},{label:"Paste a key, pick a model",hint:"auto-detects the provider · OpenRouter = any model"},{label:"Custom endpoint",hint:"enter a base url + token by hand"},{label:"← Back",hint:`current: ${r}`}],4);if(3===l)return;if(0===l)return await e.setProvider({kind:"anthropic"}),c(),void n.print("\n "+b("✓ back on regular Claude."));if(1===l){const t=(await n.ask(`\n Paste your API key ${g("(blank to cancel)")} ${w("▸")} `)).trim();if(!t)return void n.print(" "+$("cancelled — provider unchanged"));const r=o(t);if(!r.compatible)return void n.print("\n "+$(s(r.name)));const l=a[r.id];n.print(`\n ${b("✓ detected "+l.name)} ${g("— fetching models…")}`);const d=await i({modelsUrl:l.models,key:t,auth:l.auth});let u;if(0===d.length)u=(await n.ask(` Couldn't list models. Model id ${g("(blank = endpoint default)")} ${w("▸")} `)).trim()||void 0;else if(d.length<=40){const e=await p("\n model",d.map(e=>({label:e})),1);u=d[e]}else for(n.print(` ${g(d.length+" models available, e.g. "+d.slice(0,3).join(", ")+"…")}`);;){const e=(await n.ask(` Type a model id or part of it ${g("(blank to cancel)")} ${w("▸")} `)).trim();if(!e)return void n.print(" "+$("cancelled — provider unchanged"));const t=d.filter(n=>n.toLowerCase().includes(e.toLowerCase()));if(0!==t.length){if(1===t.length){u=t[0];break}if(t.length<=40){const e=await p("\n pick",t.map(e=>({label:e})),1);u=t[e];break}n.print(` ${$(t.length+" matches — narrow it down")}`)}else n.print(" "+$("no match — try again"))}return await e.setProvider({kind:"custom",base:l.base,token:t,model:u}),c(),void n.print(`\n ${b("✓ provider set.")}\n ${l.name}\n model: ${u||"(endpoint default)"}`)}const d=(await n.ask(`\n Base url ${g("(blank to cancel · SDK appends /v1/messages)")} ${w("▸")} `)).trim();if(!d)return void n.print(" "+$("cancelled — provider unchanged"));const u=(await n.ask(` API token ${g("(blank to cancel)")} ${w("▸")} `)).trim();if(!u)return void n.print(" "+$("cancelled — provider unchanged"));const m=(await n.ask(` Model ${g("(blank = endpoint default · e.g. glm-4.6)")} ${w("▸")} `)).trim();await e.setProvider({kind:"custom",base:d,token:u,model:m||void 0}),c(),n.print(`\n ${b("✓ provider set to custom.")}\n base url: ${t.provider}\n model: ${t.providerModel||"(endpoint default)"}`)},v=async()=>{for(;;){const r=[{key:"provider",label:"Provider",hint:`current: ${t.provider}`},{key:"account",label:"Account",hint:t.reconnectRequired?"reconnect required":t.loggedIn?`linked: ${t.email||"yes"}`:"not linked"},{key:"awake",label:"Keep computer awake",hint:(t.keepAwake?"ON":"off")+" · the screen can still dim, lock, and turn off"}];t.hermesInstalled&&r.push({key:"hermes",label:t.hermesReady?"Hermes profile":"Set up Hermes",hint:t.hermesReady?"isolated profile ready":"set up isolated profile + delegation guard"}),r.push({key:"back",label:"Back to main menu",hint:""});const o=r[await p("\n change",r,r.length)];if("back"===o.key)return;if("provider"===o.key)await f();else{if("account"===o.key)return await e.login(),void c();if("awake"===o.key)if(t.keepAwake){if(!1===await e.setKeepAwake({enabled:!1}))continue;t={...t,keepAwake:!1},c(),n.print("\n "+b("✓ keep-awake is off. The computer may sleep normally."))}else if(n.print("\n "+$("Important: keep-awake changes this computer’s power behavior")),n.print(" While the bridge runs, thinkpool will prevent the computer itself from"),n.print(" automatically sleeping. This can use substantially more battery and may"),n.print(" also block suspend requests on some Linux systems."),n.print("\n "+b("It does NOT keep the screen on. Display dimming, screen locking, and")),n.print(" display sleep continue to work normally. Closing a laptop lid may still"),n.print(" sleep it, depending on the operating system and power settings."),await d("\n Enable keep-awake while the thinkpool bridge runs?",!1)){if(!1===await e.setKeepAwake({enabled:!0}))continue;t={...t,keepAwake:!0},c(),n.print("\n "+b("✓ keep-awake is on. Your screen is still free to dim and turn off."))}else n.print("\n "+$("unchanged: keep-awake remains off."));else if("hermes"===o.key){const n=await p("\n Hermes profile",[{label:"Clone active profile",hint:"copies provider/config explicitly; fresh thinkpool session history"},{label:"Create clean profile",hint:"no copied credentials or bundled skills; configure provider afterward"},{label:"Back",hint:""}],3);2!==n&&(await e.setupHermes({mode:0===n?"clone":"clean"}),c())}}}};for(;;){u(),n.print(" "+y("What do you want to do?")+"\n");const r=t.accountSvc?["win32"===t.platform?{key:"restart",label:"Update startup entry",hint:"installs the latest version; relaunch the bridge window to apply"}:{key:"restart",label:"Restart & update bridge",hint:"install the latest published version; sessions resume"},{key:"uninstall",label:"Remove background service",hint:"stop serving your sessions on this device"}]:[{key:"serve",label:"Serve all my sessions",hint:"runs here, Ctrl-C stops it"},{key:"service",label:"Always-on background service",hint:"recommended — survives reboot, restarts on crash"}];r.push({key:"settings",label:"Settings",hint:`provider · account · keep-awake ${t.keepAwake?"ON":"off"}${t.hermesInstalled?" · Hermes profile":""}`}),r.push({key:"quit",label:"Quit",hint:""});const o=r[await p("choose",r)];if("quit"===o.key)return;if("serve"===o.key)await h()&&await m()&&await e.serveAccountForeground();else if("service"===o.key){if(await h()&&await m()){if(!0===await e.installService({room:null})&&(!e.relaunchLauncher||await e.relaunchLauncher()))return;c()}}else if("restart"===o.key){if(!0===await e.restartUpdateService({room:null})&&(!e.relaunchLauncher||await e.relaunchLauncher()))return;c()}else"uninstall"===o.key?(await e.uninstallService({room:null}),c()):"settings"===o.key&&await v();await n.ask("\n "+g("press Enter to return to the menu…"))}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=/(?:TOKEN|SECRET|PASSWORD|PRIVATE_KEY|API_KEY|ACCESS_KEY|CREDENTIAL|AUTHORIZATION)/i;export const OPENCODE_SUPPORTED_SLICE_TYPES=Object.freeze(["scaffold","feature","fix"]);export const opencodeChildEnv=(o={})=>Object.fromEntries(Object.entries(o).filter(([o])=>!e.test(o)));export function opencodeRoleAdmission({flowRole:e=null,sliceType:o=null}={}){return e?Object.freeze({ok:!1,code:"flow_roles_unsupported"}):"review"===o||"plan"===o?Object.freeze({ok:!1,code:"structural_role_unsupported"}):o&&!OPENCODE_SUPPORTED_SLICE_TYPES.includes(o)?Object.freeze({ok:!1,code:"slice_type_unsupported"}):Object.freeze({ok:!0,role:o||"ordinary"})}export function opencodePermissionOutcome(e,o=[]){if("allow"!==e)return{outcome:"cancelled"};const t=o.find(e=>"allow_once"===e?.kind&&"allow_once"===e?.optionId);return t?{outcome:"selected",optionId:t.optionId}:{outcome:"cancelled"}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{execFileSync as e}from"node:child_process";const n=e=>String(e||"").replace(/[\r\n]+/g," ").trim();export function probeOpenCodeRuntime({command:o="opencode",execFile:a=e,env:r=process.env}={}){try{const e=a(o,["--version"],{encoding:"utf8",env:r,timeout:1e4,stdio:["ignore","pipe","pipe"]}),i=n(e).match(/\b(\d+\.\d+\.\d+(?:[-+][\w.-]+)?)\b/)?.[1]||null;return i?{available:!0,version:i,command:o,package:"opencode-ai",acpProtocol:1}:{available:!1,version:null,reason:"OpenCode did not report an exact semantic version"}}catch(e){return{available:!1,version:null,command:o,package:"opencode-ai",reason:n(e?.stderr||e?.message||e)||"opencode is not installed"}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"node:path";import o from"node:fs";import{randomUUID as n}from"node:crypto";import{createAcpRuntimeAdapter as t,startAcpAdapterClient as s}from"./acp-runtime-adapter.mjs";import{AcpEventMapper as r}from"./acp-event-mapper.mjs";import{opencodeChildEnv as i,opencodePermissionOutcome as a,opencodeRoleAdmission as l}from"./opencode-policy.mjs";import{probeOpenCodeRuntime as c}from"./opencode-probe.mjs";import{createCompatibilityProfile as p,projectCompatibilityProfile as d}from"./runtime-compatibility-profile.mjs";export const OPENCODE_COMMAND="opencode";export const OPENCODE_ACP_PROTOCOL_VERSION=1;const m=t({runtime:"opencode",command:"opencode",capabilities:{streaming:!0,permission_request:!0,cancellation:!0,resume:!0,new_session:!0,model_catalog:!1,mode_catalog:!1,images:!0}}),u=n=>{const t=e.extname(n).toLowerCase();return{type:"image",mimeType:".png"===t?"image/png":".webp"===t?"image/webp":".gif"===t?"image/gif":"image/jpeg",data:o.readFileSync(n).toString("base64")}};export function startOpenCodeSession({cwd:o,model:f,resume:g,env:w=process.env,onEvent:C,requestPermission:h,command:y="opencode",args:v=["acp"],clientFactory:b=null,flowRole:O=null,sliceType:I=null,lazy:E=!1,platform:S=process.platform}={}){const k=l({flowRole:O,sliceType:I});if(!k.ok)throw new Error(`OpenCode runtime selection rejected: ${k.code}`);let A=g||null,q=null,P=null,$=!1,_=!1,x=!1,R=!1,T=f||null,j="",N=null,V=null;const M=e=>{try{C?.(e)}catch{}},D=async()=>{if(_)throw new Error("OpenCode session is closed");if(x)throw new Error("OpenCode ACP process crashed; retry starts a fresh process");if(!q?.alive||!P)return N||(N=(async()=>{if("opencode"===y&&!b){const e=c({command:y,env:i(w)});if(!e.available)throw new Error(`OpenCode runtime unavailable: ${e.reason}`)}const n="opencode"===y?m:t({...m,runtime:"opencode",command:y,args:v});q=b?b({command:y,args:v,cwd:o,env:i(w),onNotification:z,onRequest:F,onStderr:L,onClose:U}):s(n,{cwd:o,env:i(w),onNotification:z,onRequest:F,onStderr:L,onClose:U}),q.start();const a=await q.request("initialize",{protocolVersion:1,clientCapabilities:{fs:{readTextFile:!1,writeTextFile:!1},terminal:!1},clientInfo:{name:"thinkpool-pair",title:"thinkpool Code",version:"1"}},15e3);if(1!==a?.protocolVersion)throw new Error(`Unsupported OpenCode ACP protocol ${a?.protocolVersion??"unknown"}`);const l={cwd:e.resolve(o||process.cwd()),mcpServers:[]},u=A?await q.request("session/resume",{...l,sessionId:A},3e4):await q.request("session/new",l,3e4);if(A||=u?.sessionId||null,!A)throw new Error("OpenCode ACP did not return a session id");T||=u?.models?.currentModelId||null,P=new r({onEvent:M,sessionId:A,model:T,runtime:"opencode"}),P.startSession({sessionId:A,models:u?.models,modes:u?.modes,commands:[]}),V=p({runtime:"opencode",runtimeVersion:a?.agentInfo?.version||null,modelId:T,role:k.role,platform:S,observedAt:(new Date).toISOString().slice(0,10),checks:["acp_initialize","session_lifecycle"],capabilities:{streaming:!0,cancellation:!0,resume:null!=a?.agentCapabilities?.sessionCapabilities?.resume,images:!0===a?.agentCapabilities?.promptCapabilities?.image},available:!0}),M({kind:"capabilities",runtime:"opencode",protocol:"acp",protocolVersion:a.protocolVersion,capabilities:a.agentCapabilities||{},models:[],provider:"OpenCode local configuration (unverified)",profile:d(V),flow:!1}),$=!0})().catch(e=>{throw x=!0,q?.end(),M({kind:"error",message:`OpenCode ACP startup failed: ${e?.message||e}${j?`: ${j.slice(-240)}`:""}`,recoverable:!0}),e}).finally(()=>{N=null}),N)};async function F(e,o,n){if("session/request_permission"!==e)throw Object.assign(new Error(`Unsupported ACP client method: ${e}`),{code:-32601});let t="deny";try{t=await(h?.({id:`opencode-perm:${n}`,toolName:String(o?.toolCall?.title||"OpenCode tool"),input:o?.toolCall?.rawInput||{},risk:"high"}))}catch{}return{outcome:a(t,o?.options||[])}}function z(e,o){"session/update"===e&&P?.push(o)}function L(e){j=(j+String(e)).slice(-2e3)}function U(e){_||x||(x=!0,R=!1,M({kind:"error",message:`OpenCode ACP closed unexpectedly: ${e?.message||e}`,recoverable:!0}))}return E||queueMicrotask(()=>{D().catch(()=>{})}),{get sessionId(){return A},get turnActive(){return R},get started(){return $},get canSteer(){return!1},get profile(){return V},sendTurn(e,o={}){if(_||R)return!1;R=!0;const t=[{type:"text",text:String(e)}];for(const e of Array.isArray(o.images)?o.images:[])try{t.push(u(e))}catch{}return D().then(()=>q.request("session/prompt",{sessionId:A,prompt:t,messageId:n()},0)).then(e=>P.finishTurn({stopReason:e?.stopReason,usage:e?.usage})).catch(e=>M({kind:"error",message:`OpenCode turn failed: ${e?.message||e}`,recoverable:!0})).finally(()=>{R=!1}),!0},async abort(){R&&q?.alive&&A&&(R=!1,await q.notify("session/cancel",{sessionId:A}).catch(e=>{x=!0,q?.end(),M({kind:"error",message:`OpenCode cancellation delivery failed: ${e?.message||e}`,recoverable:!0})}),P?.finishTurn({stopReason:"cancelled"}))},setModel:()=>!1,setMode:()=>!1,clearContext:()=>!1,warm(){D().catch(()=>{})},end(){_=!0,R=!1,A&&q?.alive?q.request("session/close",{sessionId:A},1500).catch(()=>{}).finally(()=>q?.end()):q?.end()}}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thinkpool-pair",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.400",
|
|
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",
|
|
@@ -37,12 +37,22 @@
|
|
|
37
37
|
"codex-mcp-http.mjs",
|
|
38
38
|
"lane-worktree.mjs",
|
|
39
39
|
"lane-work-snapshot.mjs",
|
|
40
|
+
"branch-checkpoint.mjs",
|
|
41
|
+
"permission-rules.mjs",
|
|
42
|
+
"public-proof.mjs",
|
|
40
43
|
"codex-event-mapper.mjs",
|
|
41
44
|
"edit-diff.mjs",
|
|
42
45
|
"cumulative-event-relay.mjs",
|
|
43
46
|
"codex-commands.mjs",
|
|
44
47
|
"acp-client.mjs",
|
|
48
|
+
"acp-event-mapper.mjs",
|
|
49
|
+
"acp-runtime-adapter.mjs",
|
|
45
50
|
"hermes-session.mjs",
|
|
51
|
+
"opencode-session.mjs",
|
|
52
|
+
"opencode-policy.mjs",
|
|
53
|
+
"opencode-probe.mjs",
|
|
54
|
+
"runtime-adapter.mjs",
|
|
55
|
+
"runtime-compatibility-profile.mjs",
|
|
46
56
|
"hermes-model-cache.mjs",
|
|
47
57
|
"hermes-policy.mjs",
|
|
48
58
|
"hermes-acp-bootstrap.py",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=/^(?!.*\.\.)[A-Za-z0-9][A-Za-z0-9_.:/-]{0,119}$/,r=/^[A-Z0-9-]{3,12}$/,o=new Set(["medium","network"]);export function codePermissionRuleSignature(r,t){const s="string"==typeof r?r.trim():"";return e.test(s)&&o.has(t)?`${s}:${t}`:null}export function activePermissionRuleAllows(e,{toolName:r,risk:o}={}){const t=codePermissionRuleSignature(r,o);return!(!t||!Array.isArray(e))&&e.some(e=>!e?.revoked_at&&codePermissionRuleSignature(e?.tool_name,e?.risk)===t)}export async function fetchCodePermissionRules({supabaseUrl:e,anonKey:o,token:t,roomCode:s,fetcher:i=globalThis.fetch,timeoutMs:n=1200}={}){const a="string"==typeof s?s.toUpperCase().trim():"";if(!("function"==typeof i&&"string"==typeof e&&e&&"string"==typeof o&&o&&"string"==typeof t&&t&&r.test(a)))return Object.freeze({ok:!1,code:"permission_rules_unavailable",rules:Object.freeze([])});const l=new AbortController,u=setTimeout(()=>l.abort(),n);u.unref?.();try{const r=await i(`${e.replace(/\/$/,"")}/rest/v1/rpc/list_code_permission_rules`,{method:"POST",headers:{apikey:o,Authorization:`Bearer ${t}`,"Content-Type":"application/json"},body:JSON.stringify({p_session_code:a,p_include_revoked:!1}),signal:l.signal});if(!r?.ok)return Object.freeze({ok:!1,code:"permission_rules_unavailable",rules:Object.freeze([])});const s=await r.json();if(!Array.isArray(s))return Object.freeze({ok:!1,code:"permission_rules_invalid",rules:Object.freeze([])});const n=s.filter(e=>!e?.revoked_at&&codePermissionRuleSignature(e?.tool_name,e?.risk));return Object.freeze({ok:!0,code:"permission_rules_loaded",rules:Object.freeze(n)})}catch{return Object.freeze({ok:!1,code:"permission_rules_unavailable",rules:Object.freeze([])})}finally{clearTimeout(u)}}export async function allowsCodePermissionRule(e={}){if(!codePermissionRuleSignature(e.toolName,e.risk))return!1;const r=await fetchCodePermissionRules(e);return r.ok&&activePermissionRuleAllows(r.rules,e)}
|
package/public-proof.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createFlowReviewReceipt as e}from"./flow-receipt.mjs";const r=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;export async function registerPublicProof({webBase:t,token:o,room:i,sourceCid:a,sourceTerminalId:n,receipt:s,fetcher:c=fetch,timeoutMs:l=1800}={}){if(!(t&&o&&i&&r.test(a||"")&&r.test(n||"")))return{ok:!1,reason:"unavailable"};let u;try{u=e(s)}catch{return{ok:!1,reason:"invalid-receipt"}}if("pass"!==u.outcome||!u.verified||!u.scope?.held)return{ok:!1,reason:"ineligible"};const f=new AbortController,p=setTimeout(()=>f.abort(),l);try{const e=await c(`${t.replace(/\/$/,"")}/api/proof-receipt`,{method:"POST",headers:{Authorization:`Bearer ${o}`,"Content-Type":"application/json"},body:JSON.stringify({action:"register",code:i,sourceCid:a,sourceTerminalId:n,receipt:u}),signal:f.signal});return e.ok?{ok:!0}:{ok:!1,reason:`http-${e.status}`}}catch(e){return{ok:!1,reason:"AbortError"===e?.name?"timeout":"network"}}finally{clearTimeout(p)}}
|
package/publish-manifest.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": 1,
|
|
3
3
|
"package": "thinkpool-pair",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.400",
|
|
5
5
|
"kind": "minified",
|
|
6
|
-
"minifiedModules":
|
|
7
|
-
"sourceModuleBytes":
|
|
8
|
-
"artifactModuleBytes":
|
|
6
|
+
"minifiedModules": 133,
|
|
7
|
+
"sourceModuleBytes": 1811976,
|
|
8
|
+
"artifactModuleBytes": 827663,
|
|
9
9
|
"files": {
|
|
10
|
-
"package.json": "
|
|
10
|
+
"package.json": "a9aef48fb7dd3d7064f69759a4c34076c6aca7fa86f5abecc25030eece66dfb4",
|
|
11
11
|
"LICENSE": "8a030197ca1cad9669909ca14c9ad15cf48d9fe551da526ccaf1fca993eddb23",
|
|
12
|
-
"bridge.mjs": "
|
|
12
|
+
"bridge.mjs": "e34e3424c02c8ce09b68754b9d492663e629f36ca9baafd38e98c3acaeebbc66",
|
|
13
13
|
"bridge-service.sh": "b64f27c473ca8f3a49190fd08c23947ab14ca9958d70b6fa53c7bddc2be91403",
|
|
14
14
|
"command-guidance.mjs": "b9b967b59ff4e77c9613abb0f28858bf3ac5b106a509e471039777b53bec3e29",
|
|
15
15
|
"abort-turn-barrier.mjs": "3734a5b7e2e940ec6d7fa8b5b04935e1429a23d1bd9e92b2ac2a2ecd9f77c75e",
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
"keep-awake.mjs": "6c0a51409321f2564082b414b00696d22a740ca98180b1f628828c5fe19995c7",
|
|
19
19
|
"sdk-smoke.mjs": "dfe509863ede8a12780914939740f7f9fee36d3980f8fcb57803a33593ac4056",
|
|
20
20
|
"sdk-admission.mjs": "eb33725cc33347b900c75289eae7917f6ce3526203711515aecd48d43b3c895d",
|
|
21
|
-
"launcher.mjs": "
|
|
21
|
+
"launcher.mjs": "a63c63492be0e97b41aae9c0ae24045903207a768c2cb86f8d7a9297d2741f1b",
|
|
22
22
|
"privacy-report.mjs": "b444610be6de8b3bcf0086d585594286ef000dad1e075df87013003a315bf211",
|
|
23
|
-
"agent-visibility.mjs": "
|
|
23
|
+
"agent-visibility.mjs": "6afed5ce9120c4aaa7582d3cfb30c0658186a936ad1f87b1b01dfd20e988f839",
|
|
24
24
|
"byok-detect.mjs": "f31f2ca426737581a97c391b3cecfc75f0207cfa31f51c6bf4a9148309c9625d",
|
|
25
25
|
"context-contract.mjs": "ffebb435dc5d75c289329bf16ab909df9d634a2b508154c250c6b25906a02a91",
|
|
26
26
|
"context-windows.mjs": "80af664f84d7e95ef2b0a2a3131090ac4ccd522709448ac9a0d96c378bbec0f7",
|
|
@@ -35,14 +35,24 @@
|
|
|
35
35
|
"codex-app-server.mjs": "d50e30ba6cb2a383c90d89186bc7a13f4caf900c977dd501572468986009470e",
|
|
36
36
|
"codex-images.mjs": "31605d6d8b3dd6b73395da63d1b0c513445c95ffa2f4306ee466f201d633ffc0",
|
|
37
37
|
"codex-mcp-http.mjs": "7472543648a9bb575ce20dc3e3270c2da84174c6ea6e9faf87dfaafb95b6212a",
|
|
38
|
-
"lane-worktree.mjs": "
|
|
38
|
+
"lane-worktree.mjs": "20a4327b501d3771c8e41e0908926d50c477db9d76c41d5243204d72d20417e8",
|
|
39
39
|
"lane-work-snapshot.mjs": "ba40233059ea86ba2e08d0b61763427baa9602eb6edf6c445a6b22fd15af212c",
|
|
40
|
+
"branch-checkpoint.mjs": "6301c39df24b0343aacb05c13aad4a37dcce1c1acee3ffdf7465fc51db6acaa2",
|
|
41
|
+
"permission-rules.mjs": "552a9e33dc85ea2dbbe168d6335fcee4f11ef7c0a5b47fd8d9c5b74d24c149ef",
|
|
42
|
+
"public-proof.mjs": "00e010d629e0bb2ab859167037e65b6c90986a23cb7df0fb5f2c898972c34581",
|
|
40
43
|
"codex-event-mapper.mjs": "a7c423806b5e80957733c21d756078740773ae7230305ed00dba72cecb3a558a",
|
|
41
44
|
"edit-diff.mjs": "258c64416b4e60b1f8243546f1cc25e1b27457f0edeaa0e6c837a3e888f49ba2",
|
|
42
45
|
"cumulative-event-relay.mjs": "cf6e6533e33b3c5bb0b462d15ccc86106f2b56f8b1e66fc1f4867dd8f44d7ae6",
|
|
43
46
|
"codex-commands.mjs": "cae3f617ac42e1316d8980ef97e4255227fe5df5e8e9b556630a3bfb83bb7c2b",
|
|
44
47
|
"acp-client.mjs": "9e7919ff79825883820019ff7a0ca578f120853ed61c7caab21a8ffc3a67ffc9",
|
|
48
|
+
"acp-event-mapper.mjs": "bcef2d7b5b940a4ee1dc5053e2283ac962dd0567c7fd87f8fb6e16b083be5847",
|
|
49
|
+
"acp-runtime-adapter.mjs": "b0e65df88a2e5f64ad3bcb123843daca5ae30e32ac33aceee31ca4f4c167f38b",
|
|
45
50
|
"hermes-session.mjs": "b3d521ea59297edb58ecfcc0daad3c0df88d96131cadc455fa36fc1cca954210",
|
|
51
|
+
"opencode-session.mjs": "0828568fe8ad2110fb75363b501b69730627889aa8191fc460513f80c72ba337",
|
|
52
|
+
"opencode-policy.mjs": "3c76d26162a26a6ea15d4f123155be5ca0ee10efe2cc1bc74659750ccc62d277",
|
|
53
|
+
"opencode-probe.mjs": "08aa692d27873ece9aec2907641ae8e6d0f776f6f0e9e0dafb865fd890ce3bfd",
|
|
54
|
+
"runtime-adapter.mjs": "0500660893b12b202848b1a0da9b00ab86f6be425aa4820eb680d10537a95cba",
|
|
55
|
+
"runtime-compatibility-profile.mjs": "137730baf95d315723872e8df80e66305bccb909e3c6cb81ae753ea9adadac84",
|
|
46
56
|
"hermes-model-cache.mjs": "aee23efdebe1aa5e10053f291a9153981fe9b45065c293c9519ca73477251e72",
|
|
47
57
|
"hermes-policy.mjs": "df6dd384ab130b3626045816b6ac4c1d2aecde37fb7b7a4be0c1bffc375fd8ff",
|
|
48
58
|
"hermes-acp-bootstrap.py": "9453b48d1ec0057a1d1754fc828acb949ad3f69c687fd055dc3856823d26c19b",
|
|
@@ -53,15 +63,15 @@
|
|
|
53
63
|
"hermes-delegation-guard.mjs": "f737d05fb93591848fa3839fd5df2c019779bda828d42ab785cd57213665f922",
|
|
54
64
|
"catastrophic-command-guard.mjs": "65158e59266e4be1e2a72479fb9b2c7e7a4ec7902a8b764d3b26017cd0cdbfd5",
|
|
55
65
|
"codex-catastrophic-command-hook.mjs": "5bf1eb5dd837b77044846af0cb8936a81edbc435e454217ddb15981f3626f7dc",
|
|
56
|
-
"runtime-registry.mjs": "
|
|
66
|
+
"runtime-registry.mjs": "278ff20fe803dba5990f275ef4f2f26730a2e17d0886700d76cb5b37c6e3163e",
|
|
57
67
|
"runtime-skill-parity.mjs": "933535bc7b70d7843cf7bf8eb83f306693045ccf7154ad781b6d42be75442f1c",
|
|
58
68
|
"reasoning-effort.mjs": "3a514997656bbcd41ff1aefe9d5e59c5920a90e6bfcc928016d95987db2ceaa3",
|
|
59
|
-
"runtime-contract.mjs": "
|
|
60
|
-
"command-catalog.mjs": "
|
|
69
|
+
"runtime-contract.mjs": "410e55770d4b1ee72af5adc5c7706fb021c28126f728f270a1aad711d4ad3460",
|
|
70
|
+
"command-catalog.mjs": "42a61109ce791bcdb4ca793ad343402fe3c7bbad44cbe8f1f135bc67207aa00e",
|
|
61
71
|
"repo-search.mjs": "10cbce1d86655a7add0d7350ea8862a57165ccb02c2afa406348f4669050c304",
|
|
62
72
|
"project-intelligence.mjs": "b16108075648b331c84976cb63e267cf5835da7776ec7456b7642721225610a6",
|
|
63
73
|
"git-diff-report.mjs": "a428b3129c90e207a125a86c4485ec16c8ee7e81d432060a070e37172d85ce7a",
|
|
64
|
-
"runtime-session.mjs": "
|
|
74
|
+
"runtime-session.mjs": "ff97a7a65aba31d176d1afc8d0dc9d11a217415c8b0b7660a5b33c17756576c4",
|
|
65
75
|
"turn-stall.mjs": "88c712d45974e492bfcfdbd93baa371bb8be1ddb754dacb18fae20da4dd672db",
|
|
66
76
|
"update-gate.mjs": "4627870d1edae64cd4c569277dff702e4be7dd691a0a29bca6d2449d30e64d4b",
|
|
67
77
|
"agent-notify.mjs": "5950ba8928edb6e8d6091a0fdc8fb62cb21fcb79d864504e3b56e012a6f8339a",
|
|
@@ -73,13 +83,13 @@
|
|
|
73
83
|
"pair-control-authority.mjs": "7a95f101153dcc6dd0633b5a01595bf2979cd0c4bf50cfc6cd44bb7612ef40a5",
|
|
74
84
|
"scheduled-runs.mjs": "c139e7d47dd7a12c73149502b5d02409e96f4ccafaf28a9ab6889e5b101931e9",
|
|
75
85
|
"scheduled-run-admission.mjs": "3a2098d904c3aff571bf314e0182d5636d25d242cef52207e70f9dc1618c94f5",
|
|
76
|
-
"event-id.mjs": "
|
|
86
|
+
"event-id.mjs": "09c75e7fc8da282fc00651add58e5d2f82d3020e0c4dddb9921250cf9a6fa8c0",
|
|
77
87
|
"event-bounds.mjs": "aa8eb8517c4aa81b3378f71401ed39c550cdc80e28e3a57ab46d0a5ef5c7c9c1",
|
|
78
88
|
"replay-transport.mjs": "f4ed49dc023e3bb2d9534814bc2684121caafe4d24151b87688407eda47c6c7a",
|
|
79
89
|
"event-delivery-queue.mjs": "c596e298384e0e4890bccdc07f622e1807d1784e19b65f0ef5b7b1bfea0c41d4",
|
|
80
90
|
"mcp-flight-recorder.mjs": "30bf77f4d567f0449856d6da09f7a0a9c8d7e12c5dcaf200dc9e511a331425be",
|
|
81
91
|
"plan-meters.mjs": "f7f5aeb3d6a3462b754d3724367bbb331643ba58108e29e91b2aca2f613ab499",
|
|
82
|
-
"recap.mjs": "
|
|
92
|
+
"recap.mjs": "17bbc73916381cb70758f2605567a21b1c4290c31f94213ab05b23e28d05a3fd",
|
|
83
93
|
"transcript-sanitize.mjs": "c7f4718f25f97c05bc7b4ad8e09f18cbda152c53ad6593af1ab99f0c132dbf01",
|
|
84
94
|
"session-search.mjs": "d606fbab5c47357071e4919107aa00ad090f6e7d7e6dc929e0ac5a4d0cb2c538",
|
|
85
95
|
"session-store.mjs": "fa3f7a27a8a7c49bb89364fb28c9c2680f7f487d4b4125329ab4a0ba9362bd8c",
|
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,
|
|
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,r=/(?: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,s=/(?:[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)||r.test(t)||s.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),p=(e,t,n=4)=>l(e.flatMap(e=>e.text.split(/(?<=[.!?])\s+|\n+/).map(e=>c(e,500)).filter(e=>t.test(e))),n),d=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),r=c(n.at(-1)?.text||"not established from visible text",1400),s=c(o.at(-1)?.text||t.at(-1)?.text||"not established from visible text",1400),i=p(t,/\b(block(?:ed|er|ing)?|cannot|can['’]?t|unable|waiting|stuck|failed|failure|error|unverified)\b/i),h=p(o,/\b(implemented|added|changed|updated|fixed|ran|tested|checked|inspected|tried|attempted|committed|built)\b/i),u=p(o,/\b(done|complete(?:d)?|implemented|fixed|passing|passed|succeeded|shipped)\b/i),f=p(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:r,recent:s,blockers:i,actions:l([...h,...u],6),receipts:d(t),next:m,suggestedNext:f}}export function buildCheckpointFromLog(n,o=6e3){const r=Math.max(0,Number.isFinite(o)?Math.floor(o):0);if(!r)return"";const s=checkpointFactsFromLog(n);if(!s)return"";const{objective:i,recent:a,blockers:l,actions:p,receipts:d,next:h}=s,u=[e,`Objective / live request: ${i}`,`Current step / recent work: ${a}`,`Blockers: ${l.length?l.join(" | "):"none stated in visible text"}`,`Attempted / completed actions: ${p.join(" | ")||"not established from visible text"}`,`Receipts: ${d.join(" | ")||"none safely detected"}`,`Next action: ${h}`,t];let f=u.join("\n");if(f.length<=r)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>r)return"";const b=r-m.length-6,y=[i,a,l.join(" | "),p.join(" | "),d.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 r=Math.max(0,Number.isFinite(t)?Math.floor(t):0);if(!r)return"";const s=[];for(const t of e)if(t&&"object"==typeof t)if("you"===t.kind){const e=a(t.text);e&&s.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&&s.push({who:"YOU",text:e})}if(!s.length)return"";const i=[];let c=0,l=!1;for(let e=s.length-1;e>=0;e--){let t=`${s[e].who}: ${s[e].text}`;if(c+t.length>r){if(i.length){l=!0;break}t=t.slice(0,r)}i.push(t),c+=t.length}i.reverse();const p=(l?["[…earlier messages omitted for length…]"]:[]).concat(i).join("\n\n"),d=h[n]||h.switch,u=o?buildCheckpointFromLog(e):"";return[d.header,d.body,"","--- conversation so far (oldest → newest) ---",p,"--- end recap ---",u].join("\n")}export function resolveIdleRestoreCarry({carryRecap:e,resumable:t=!1,interrupted:n=!1,flowSessionId:o=null,log:r}={},s=2e4){return("string"==typeof e&&e.trim()?e:null)||(t||n||o?null:buildRecapFromLog(r,s)||null)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const RUNTIME_ADAPTER_VERSION=1;const e=new Set(["start","new_session","resume","prompt","cancel","close","crash"]),r=new Set(["streaming","permission_request","cancellation","resume","new_session","model_catalog","mode_catalog","images"]),t=e=>e&&"object"==typeof e&&!Array.isArray(e);export function adapterFailureReceipt({runtime:e,check:r,code:t,detail:i=""}={}){return Object.freeze({version:1,runtime:String(e||""),check:String(r||""),ok:!1,code:String(t||"failed"),detail:String(i||"").slice(0,500)})}export function validateRuntimeAdapter(i){return t(i)&&1===i.version?/^[a-z][a-z0-9-]{1,63}$/.test(String(i.runtime||""))?t(i.subprocess)&&"string"==typeof i.subprocess.command&&Array.isArray(i.subprocess.args)?!Array.isArray(i.lifecycle)||i.lifecycle.some(r=>!e.has(r))?adapterFailureReceipt({runtime:i.runtime,check:"lifecycle",code:"invalid_lifecycle"}):!t(i.capabilities)||Object.entries(i.capabilities).some(([e,t])=>!r.has(e)||"boolean"!=typeof t)?adapterFailureReceipt({runtime:i.runtime,check:"capabilities",code:"invalid_capability_schema"}):Object.freeze({version:1,runtime:i.runtime,ok:!0,checks:["adapter_schema","subprocess_boundary","lifecycle","capabilities"]}):adapterFailureReceipt({runtime:i.runtime,check:"subprocess_boundary",code:"invalid_subprocess_boundary"}):adapterFailureReceipt({runtime:i?.runtime,check:"adapter_schema",code:"invalid_runtime_id"}):adapterFailureReceipt({runtime:i?.runtime,check:"adapter_schema",code:"unsupported_adapter_version"})}export function runRuntimeAdapterConformance(e,r={}){const t=validateRuntimeAdapter(e);if(!t.ok)return t;const i=Array.isArray(r.checks)?r.checks.filter(e=>/^[a-z][a-z0-9_-]{1,80}$/.test(e)):[],a=Array.isArray(r.failures)?r.failures.filter(Boolean).map(String).slice(0,16):[];return i.length?a.length?adapterFailureReceipt({runtime:e.runtime,check:"conformance",code:"observed_check_failed",detail:a.join("; ")}):Object.freeze({version:1,runtime:e.runtime,ok:!0,checks:[...new Set([...t.checks,...i])],observedAt:"string"==typeof r.observedAt?r.observedAt:null}):adapterFailureReceipt({runtime:e.runtime,check:"conformance",code:"no_observed_checks"})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=(e,i=160)=>"string"==typeof e&&e.length>0&&e.length<=i;export function createCompatibilityProfile({runtime:i,runtimeVersion:l,modelId:t=null,role:r,platform:n,observedAt:o,checks:a=[],capabilities:c={},available:s=!0}={}){const u=(b=a,Array.isArray(b)?[...new Set(b.filter(e=>/^[a-z][a-z0-9_-]{1,80}$/.test(e)))]:[]);var b;const d=e(i)&&e(l)&&e(r)&&e(n)&&e(o,32),f=!0===s&&d&&u.includes("acp_initialize")&&u.includes("session_lifecycle");return Object.freeze({version:1,runtime:i||null,runtimeVersion:l||null,modelId:t||null,role:r||null,platform:n||null,observedAt:o||null,checks:Object.freeze(u),capabilities:Object.freeze({...c}),available:!0===s,verified:f})}export function projectCompatibilityProfile(e){const i=e&&"object"==typeof e&&1===e.version;return Object.freeze({runtime:i?e.runtime:null,modelId:i?e.modelId:null,verified:i&&!0===e.verified,available:i&&!0===e.available,capabilities:i?e.capabilities:{},observedAt:i?e.observedAt:null})}
|
package/runtime-contract.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=Object.freeze(["claude","codex","hermes"]),t=Object.freeze({claude:"native",codex:"native",hermes:"native"}),r=/(?:\/home\/|\/users\/|\/private\/|\/tmp\/|[a-z]:\\|\\\\|(?:^|[\\/])\.\.(?:[\\/]|$))/i,
|
|
1
|
+
const e=Object.freeze(["claude","codex","hermes","opencode"]),t=Object.freeze({claude:"native",codex:"native",hermes:"native"}),r=Object.freeze({...t,opencode:"native"}),i=Object.freeze({...t,opencode:"native"}),n=Object.freeze({claude:"native",codex:"native",hermes:"native"}),a=/(?:\/home\/|\/users\/|\/private\/|\/tmp\/|[a-z]:\\|\\\\|(?:^|[\\/])\.\.(?:[\\/]|$))/i,o=/(secret|token|password|authorization|api.?key|private.?key)/i,c=/(?:sk-[a-z0-9_-]{8,}|gsk_[a-z0-9_-]{8,}|AIza[a-z0-9_-]{8,}|gh[pousr]_[a-z0-9]{20,}|github_pat_[a-z0-9_]{20,}|xox[baprs]-[a-z0-9-]{10,}|AKIA[0-9A-Z]{16}|sbp_[a-z0-9]{20,}|eyJ[a-z0-9_-]{16,}\.[a-z0-9_-]{16,}\.[a-z0-9_-]{8,}|bearer\s+[a-z0-9._-]{8,})/i,p=/(?:raw transcript|tool args?|chain[ -]of[ -]thought|hidden reasoning|system prompt|environment dump|provider key|BEGIN (?:RSA |OPENSSH )?PRIVATE KEY)/i,s=(e=[],t={})=>Object.freeze({type:"object",additionalProperties:!1,required:Object.freeze(e),properties:Object.freeze(t)}),u=(e=500)=>Object.freeze({type:"string",minLength:1,maxLength:e}),m=(e=500)=>Object.freeze({type:"string",maxLength:e}),d=Object.freeze({type:"boolean"}),l=Object.freeze({type:"string",minLength:1,maxLength:160,pattern:"^[A-Za-z0-9][A-Za-z0-9._:@-]*$"}),b=s(["label","description"],{label:u(80),description:u(240)}),y=s(["id","header","question","options"],{id:Object.freeze({type:"string",minLength:1,maxLength:80,pattern:"^[A-Za-z0-9][A-Za-z0-9_-]*$"}),header:u(12),question:u(500),options:Object.freeze({type:"array",minItems:2,maxItems:3,items:b}),multiSelect:d}),f=s(["type","id"],{type:l,id:l});export const RUNTIME_CAPABILITY_VERSION=1;export const RUNTIME_CAPABILITIES=Object.freeze([Object.freeze({id:"request_user_input",version:1,runtimeSupport:t,inputSchema:s(["questions"],{questions:Object.freeze({type:"array",minItems:1,maxItems:3,items:y}),autoResolutionMs:Object.freeze({type:"integer",minimum:6e4,maximum:24e4})}),output:"accepted | deferred | rejected | failed",authority:"pair-control",persistence:"durable-safe-ref",continuation:"resumable",secretFreeRoomPayload:!0}),Object.freeze({id:"request_permission",version:1,runtimeSupport:r,inputSchema:s(["action"],{action:u(160),reason:m(280)}),output:"accepted | deferred | rejected | failed",authority:"pair-control",persistence:"durable-safe-ref",continuation:"resumable",secretFreeRoomPayload:!0}),Object.freeze({id:"submit_flow_plan",version:1,runtimeSupport:n,inputSchema:s(["plan"],{plan:u(32768)}),output:"accepted | rejected | failed",authority:"pair-control",persistence:"durable-safe-ref",continuation:"resumable",secretFreeRoomPayload:!0}),Object.freeze({id:"mark_flow_done",version:1,runtimeSupport:n,inputSchema:s([],{evidenceRef:f}),output:"accepted | rejected | failed",authority:"bridge",persistence:"durable-safe-ref",continuation:"none",secretFreeRoomPayload:!0}),Object.freeze({id:"submit_flow_review",version:1,runtimeSupport:n,inputSchema:s(["verdict"],{verdict:u(16384)}),output:"accepted | rejected | failed",authority:"bridge",persistence:"durable-safe-ref",continuation:"none",secretFreeRoomPayload:!0}),Object.freeze({id:"terminal_interrupt",version:1,runtimeSupport:r,inputSchema:s([],{reason:m(280)}),output:"accepted | rejected | failed",authority:"bridge",persistence:"ephemeral",continuation:"none",secretFreeRoomPayload:!0}),Object.freeze({id:"lane_continuation",version:1,runtimeSupport:i,inputSchema:s(["state"],{state:Object.freeze({type:"string",enum:Object.freeze(["waiting_for_human","resumable","canceled","terminal"])}),resumeKind:Object.freeze({type:"string",enum:Object.freeze(["human_response","approval","redispatch","reconnect"])})}),output:"accepted | deferred | rejected | failed",authority:"bridge",persistence:"durable-safe-ref",continuation:"resumable",secretFreeRoomPayload:!0})]);const h=new Map(RUNTIME_CAPABILITIES.map(e=>[e.id,e]));export const runtimeCapability=e=>h.get(e)||null;export const runtimeSupportsCapability=(t,r)=>e.includes(t)&&"native"===runtimeCapability(r)?.runtimeSupport?.[t];export function isSecretFreeRoomPayload(e,t=8192){if(null==e||(e=>{try{return(new TextEncoder).encode(JSON.stringify(e)).length}catch{return 1/0}})(e)>t)return!1;const r=e=>"string"==typeof e?e.length<=2048&&!a.test(e)&&!c.test(e)&&!p.test(e):null==e||"number"==typeof e||"boolean"==typeof e||(Array.isArray(e)?e.length<=64&&e.every(r):"object"==typeof e&&Object.entries(e).every(([e,t])=>!o.test(e)&&r(t)));return r(e)}function j(e,t){return!t||("object"===t.type?!(!e||"object"!=typeof e||Array.isArray(e))&&(!1!==t.additionalProperties||!Object.keys(e).some(e=>!Object.hasOwn(t.properties||{},e)))&&!(t.required||[]).some(t=>!Object.hasOwn(e,t))&&Object.entries(t.properties||{}).every(([t,r])=>!Object.hasOwn(e,t)||j(e[t],r)):"array"===t.type?Array.isArray(e)&&e.length>=(t.minItems||0)&&e.length<=(t.maxItems??1/0)&&(!t.items||e.every(e=>j(e,t.items))):"string"===t.type?"string"==typeof e&&e.length>=(t.minLength||0)&&e.length<=(t.maxLength??1/0)&&(!t.enum||t.enum.includes(e))&&(!t.pattern||new RegExp(t.pattern).test(e)):"integer"===t.type?Number.isSafeInteger(e)&&e>=(t.minimum??-1/0)&&e<=(t.maximum??1/0):"boolean"===t.type&&"boolean"==typeof e)}export function validateRuntimeCapabilityInput(e,t){const r=runtimeCapability(e);return!!r&&j(t,r.inputSchema)}export function admitRuntimeCapability({runtime:t,capabilityId:r,input:i={},roomPayload:n=null}={}){const a=runtimeCapability(r);return a?e.includes(t)&&"native"===a.runtimeSupport[t]?validateRuntimeCapabilityInput(r,i)?a.secretFreeRoomPayload&&null!=n&&!isSecretFreeRoomPayload(n)?Object.freeze({ok:!1,code:"unsafe_room_payload"}):Object.freeze({ok:!0,code:"admitted",capability:a}):Object.freeze({ok:!1,code:"invalid_capability_input"}):Object.freeze({ok:!1,code:"runtime_capability_mismatch"}):Object.freeze({ok:!1,code:"unregistered_capability"})}export function assertRuntimeCapability(e){const t=admitRuntimeCapability(e);if(!t.ok)throw new TypeError(`Runtime capability rejected: ${t.code}`);return t.capability}
|
package/runtime-registry.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"node:path";import{runtimeCapability as t,runtimeSupportsCapability as o}from"./runtime-contract.mjs";export{normalizeStructuredEffort,reasoningEffortsForLane}from"./reasoning-effort.mjs";const r=Object.freeze({claude:Object.freeze({id:"claude",command:"claude",label:"Claude Code",protocol:"agent-sdk",structured:!0,flow:!0,canSteer:!1,images:!0,nativeModelCatalog:!1,effortControl:!0,defaultMode:"default",modes:Object.freeze(["default","acceptEdits","plan","bypassPermissions"])}),codex:Object.freeze({id:"codex",command:"codex",label:"Codex",protocol:"codex-app-server",structured:!0,flow:!0,canSteer:!0,images:!0,nativeModelCatalog:!0,effortControl:!0,defaultMode:"bypassPermissions",modes:Object.freeze(["default","acceptEdits","plan","bypassPermissions","review"])}),hermes:Object.freeze({id:"hermes",command:"thinkpool",label:"Hermes Agent",protocol:"acp",structured:!0,flow:!0,canSteer:!0,images:!0,nativeModelCatalog:!0,catalogRequiresSession:!0,effortControl:!0,defaultMode:"default",modes:Object.freeze(["default","acceptEdits","plan","bypassPermissions"]),beta:!0})});export const STRUCTURED_RUNTIME_IDS=Object.freeze(Object.keys(r));export const structuredRuntimeMetadata=e=>r[e]||null;export const structuredRuntimeForCommand=t=>{const o=e.basename(String(t||"")).toLowerCase();return Object.values(r).find(e=>e.command===o)?.id||null};export const defaultStructuredMode=e=>structuredRuntimeMetadata(e)?.defaultMode||"default";export const structuredRuntimeSupportsMode=(e,t)=>!0===structuredRuntimeMetadata(e)?.modes?.includes(t);export const structuredRuntimeSupportsFlow=e=>!0===structuredRuntimeMetadata(e)?.flow;export const structuredRuntimeCapability=(e,r)=>o(e,r)?t(r):null;export const structuredModeLocked=({flowRole:e,sliceType:t}={})=>"conductor"===e||"reviewer"===e||"review"===t;export const structuredModeForSlice=(e,t={})=>"reviewer"!==t.flowRole&&"review"!==t.sliceType?t.mode:structuredRuntimeSupportsMode(e,"review")?"review":structuredRuntimeSupportsMode(e,"plan")?"plan":t.mode;export const structuredModesForLane=(e,t={})=>{const o=structuredRuntimeMetadata(e)?.modes||[];return structuredModeLocked(t)&&o.includes(t.mode)?[t.mode]:o};export const shouldDeferStructuredRuntime=({runtime:e,defer:t,cwd:o,flowSessionId:r,flowTaskKey:
|
|
1
|
+
import e from"node:path";import{runtimeCapability as t,runtimeSupportsCapability as o}from"./runtime-contract.mjs";export{normalizeStructuredEffort,reasoningEffortsForLane}from"./reasoning-effort.mjs";const r=Object.freeze({claude:Object.freeze({id:"claude",command:"claude",label:"Claude Code",protocol:"agent-sdk",structured:!0,flow:!0,canSteer:!1,images:!0,nativeModelCatalog:!1,effortControl:!0,defaultMode:"default",modes:Object.freeze(["default","acceptEdits","plan","bypassPermissions"])}),codex:Object.freeze({id:"codex",command:"codex",label:"Codex",protocol:"codex-app-server",structured:!0,flow:!0,canSteer:!0,images:!0,nativeModelCatalog:!0,effortControl:!0,defaultMode:"bypassPermissions",modes:Object.freeze(["default","acceptEdits","plan","bypassPermissions","review"])}),hermes:Object.freeze({id:"hermes",command:"thinkpool",label:"Hermes Agent",protocol:"acp",structured:!0,flow:!0,canSteer:!0,images:!0,nativeModelCatalog:!0,catalogRequiresSession:!0,effortControl:!0,defaultMode:"default",modes:Object.freeze(["default","acceptEdits","plan","bypassPermissions"]),beta:!0}),opencode:Object.freeze({id:"opencode",command:"opencode",label:"OpenCode",protocol:"acp",structured:!0,flow:!1,canSteer:!1,images:!0,nativeModelCatalog:!1,catalogRequiresSession:!1,effortControl:!1,defaultMode:"default",modes:Object.freeze(["default"]),ordinaryOnly:!0})});export const STRUCTURED_RUNTIME_IDS=Object.freeze(Object.keys(r));export const structuredRuntimeMetadata=e=>r[e]||null;export const structuredRuntimeForCommand=t=>{const o=e.basename(String(t||"")).toLowerCase();return Object.values(r).find(e=>e.command===o)?.id||null};export const defaultStructuredMode=e=>structuredRuntimeMetadata(e)?.defaultMode||"default";export const structuredRuntimeSupportsMode=(e,t)=>!0===structuredRuntimeMetadata(e)?.modes?.includes(t);export const structuredRuntimeSupportsFlow=e=>!0===structuredRuntimeMetadata(e)?.flow;export const structuredRuntimeRoleSupported=(e,t={})=>{const o=structuredRuntimeMetadata(e);return!!o&&(!o.ordinaryOnly||!t.flowRole&&"review"!==t.sliceType&&"plan"!==t.sliceType)};export const structuredRuntimeCapability=(e,r)=>o(e,r)?t(r):null;export const structuredModeLocked=({flowRole:e,sliceType:t}={})=>"conductor"===e||"reviewer"===e||"review"===t;export const structuredModeForSlice=(e,t={})=>structuredRuntimeRoleSupported(e,t)?"reviewer"!==t.flowRole&&"review"!==t.sliceType?t.mode:structuredRuntimeSupportsMode(e,"review")?"review":structuredRuntimeSupportsMode(e,"plan")?"plan":t.mode:null;export const structuredModesForLane=(e,t={})=>{const o=structuredRuntimeMetadata(e)?.modes||[];return structuredModeLocked(t)&&o.includes(t.mode)?[t.mode]:o};export const shouldDeferStructuredRuntime=({runtime:e,defer:t,cwd:o,flowSessionId:r,flowTaskKey:d,models:s}={})=>{const a=structuredRuntimeMetadata(e);return!(!(!a?.catalogRequiresSession||Array.isArray(s)&&s.length)||!t&&(o||r||d))};
|
package/runtime-session.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{startClaudeSession as
|
|
1
|
+
import{startClaudeSession as e}from"./claude-session.mjs";import{startCodexSession as r}from"./codex-session.mjs";import{startHermesSession as o}from"./hermes-session.mjs";import{startOpenCodeSession as t}from"./opencode-session.mjs";import{assertRuntimeCapability as s}from"./runtime-contract.mjs";const n=Object.freeze({claude:e,codex:r,hermes:o,opencode:t});export function startStructuredSession(e,r){const o=n[e];if(!o)throw new Error(`Unsupported structured runtime: ${e}`);if("opencode"===e&&(r?.flowRole||"review"===r?.sliceType||"plan"===r?.sliceType))throw new Error("OpenCode runtime selection rejected: structural_role_unsupported");return s({runtime:e,capabilityId:"terminal_interrupt",input:{}}),o(r)}
|