thinkpool-pair 0.7.377 → 0.7.379
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/bridge.mjs +1 -1
- package/codex-app-server.mjs +1 -1
- package/codex-session.mjs +1 -1
- package/command-catalog.mjs +1 -1
- package/lane-work-snapshot.mjs +1 -1
- package/package.json +7 -6
- package/publish-manifest.json +14 -13
- package/reasoning-effort.mjs +1 -0
- package/runtime-registry.mjs +1 -1
- package/thinkpool-capabilities.json +7 -4
- package/thinkpool-room-prompt.mjs +1 -1
package/codex-app-server.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execFileSync as e,spawn as t}from"node:child_process";import r from"node:readline";export const CODEX_APP_SERVER_ENV="TP_CODEX_APP_SERVER";export const MIN_CODEX_APP_SERVER_VERSION=Object.freeze([0,144,1]);
|
|
1
|
+
import{execFileSync as e,spawn as t}from"node:child_process";import r from"node:readline";export const CODEX_APP_SERVER_ENV="TP_CODEX_APP_SERVER";export const MIN_CODEX_APP_SERVER_VERSION=Object.freeze([0,144,1]);const i=(e,t="unknown")=>{const r=e instanceof Error?e:new Error(String(e||"Codex App Server transport failed"));return r.delivery=t,r};export function codexAppServerGate({env:t=process.env,execFile:r=e}={}){const i=String(t?.[CODEX_APP_SERVER_ENV]||"").trim().toLowerCase();if(["0","false","off"].includes(i))return{enabled:!1,reason:`${CODEX_APP_SERVER_ENV} disables App Server`,version:null};if(i&&!["1","true","on"].includes(i))return{enabled:!1,reason:`${CODEX_APP_SERVER_ENV} has an invalid value`,version:null};try{const e=r("codex",["--version"],{encoding:"utf8",env:t}),i=(e=>{const t=String(e||"").match(/(?:codex-cli\s+)?(\d+)\.(\d+)\.(\d+)/i);return t?t.slice(1,4).map(Number):null})(e);if(!i)return{enabled:!1,reason:`unrecognized Codex version: ${String(e).trim()}`,version:null};const s=i.join(".");return((e,t)=>{for(let r=0;r<3;r++){if(e[r]>t[r])return!0;if(e[r]<t[r])return!1}return!0})(i,MIN_CODEX_APP_SERVER_VERSION)?{enabled:!0,reason:null,version:s}:{enabled:!1,reason:`Codex ${s} is older than ${MIN_CODEX_APP_SERVER_VERSION.join(".")}`,version:s}}catch(e){return{enabled:!1,reason:`could not read Codex version: ${e?.message||e}`,version:null}}}export function buildCodexAppServerArgs({providerConfig:e,mcpUrl:t,writableDirs:r=[]}={}){const i=["app-server","--stdio"];return e&&i.push("-c",e),t&&(i.push("-c",`mcp_servers.thinkpool.url=${JSON.stringify(t)}`),i.push("-c","mcp_servers.thinkpool.required=true")),r.length&&i.push("-c",`sandbox_workspace_write.writable_roots=${JSON.stringify(r)}`),i}const s=(e,t=-32e3)=>({code:t,message:String(e||"App Server request failed")}),o=(e,t=[])=>[{type:"text",text:String(e??"")},...t.filter(Boolean).map(e=>({type:"localImage",path:String(e)}))];export class CodexAppServerClient{constructor({cwd:e,env:r,args:i=["app-server","--stdio"],spawnImpl:s=t,onNotification:o,onServerRequest:n,onClose:a,initializeTimeoutMs:d=3e3,threadTimeoutMs:c=5e3,turnStartTimeoutMs:l=5e3,controlTimeoutMs:h=5e3}={}){this.cwd=e,this.env=r,this.args=i,this.spawnImpl=s,this.onNotification=o,this.onServerRequest=n,this.onClose=a,this.initializeTimeoutMs=d,this.threadTimeoutMs=c,this.turnStartTimeoutMs=l,this.controlTimeoutMs=h,this.child=null,this.nextId=1,this.pending=new Map,this.turnWaiters=new Map,this.completedTurns=new Map,this.mcpStartup=new Map,this.mcpWaiters=new Map,this.closedError=null,this.stderrTail=""}get alive(){return!!this.child&&!this.closedError}async start(){if(this.child)return;const e=this.spawnImpl("codex",this.args,{cwd:this.cwd,env:this.env,stdio:["pipe","pipe","pipe"]});this.child=e,r.createInterface({input:e.stdout,crlfDelay:1/0}).on("line",e=>this._onLine(e)),e.stderr?.on?.("data",e=>{this.stderrTail+=String(e),this.stderrTail.length>1200&&(this.stderrTail=this.stderrTail.slice(-1200))}),e.stdin?.on?.("error",e=>this._close(e)),e.on("error",e=>this._close(e)),e.on("close",e=>this._close(new Error(`codex app-server exited ${e??"unknown"}${this.stderrTail?`: ${this.stderrTail.trim().slice(-300)}`:""}`))),await this.request("initialize",{clientInfo:{name:"thinkpool-pair",title:"thinkpool Code",version:"1"},capabilities:{experimentalApi:!0}},this.initializeTimeoutMs),this.notify("initialized")}_write(e){if(!this.child?.stdin||this.closedError)throw this.closedError||new Error("codex app-server is not running");this.child.stdin.write(`${JSON.stringify(e)}\n`)}request(e,t={},r=0){const s=this.nextId++;return new Promise((o,n)=>{let a=null;r>0&&(a=setTimeout(()=>{this.pending.delete(s),n(i(`${e} timed out after ${r}ms`,"unknown"))},r)),this.pending.set(s,{resolve:o,reject:n,timer:a,method:e});try{this._write({id:s,method:e,params:t})}catch(e){this.pending.delete(s),a&&clearTimeout(a),n(i(e,"not_sent"))}})}notify(e,t){this._write(void 0===t?{method:e}:{method:e,params:t})}respond(e,t){this._write({id:e,result:t})}respondError(e,t){this._write({id:e,error:s(t?.message||t)})}_onLine(e){if(!String(e).trim())return;let t;try{t=JSON.parse(e)}catch{return}if(null!=t.id&&("result"in t||"error"in t)&&!t.method){const e=this.pending.get(t.id);if(!e)return;if(this.pending.delete(t.id),e.timer&&clearTimeout(e.timer),t.error){const r=i(t.error.message||`${e.method} failed`,"rejected");r.code=t.error.code,r.data=t.error.data,e.reject(r)}else e.resolve(t.result);return}if(null!=t.id&&t.method)Promise.resolve().then(()=>{if(!this.onServerRequest)throw new Error(`Unsupported Codex App Server request: ${t.method}`);return this.onServerRequest(t.method,t.params||{},t.id)}).then(e=>{try{this.respond(t.id,e??{})}catch{}}).catch(e=>{try{this.respondError(t.id,e)}catch{}});else if(t.method){if("turn/completed"===t.method){const e=t.params?.turn,r=e?.id;if(r){const e=this.turnWaiters.get(r);if(e)this.turnWaiters.delete(r),e.resolve(t.params);else for(this.completedTurns.set(r,t.params);this.completedTurns.size>32;)this.completedTurns.delete(this.completedTurns.keys().next().value)}}if("mcpServer/startupStatus/updated"===t.method){const e=t.params||{},r=String(e.threadId||""),i=String(e.name||"");if(r&&i){const t=`${r}\0${i}`;this.mcpStartup.set(t,e);const s=this.mcpWaiters.get(t);s&&"ready"===e.status?(this.mcpWaiters.delete(t),s.timer&&clearTimeout(s.timer),s.resolve(e)):s&&("failed"===e.status||e.error||e.failureReason)&&(this.mcpWaiters.delete(t),s.timer&&clearTimeout(s.timer),s.reject(new Error(`Codex MCP server ${i} failed to start: ${e.error||e.failureReason||e.status}`)))}}try{this.onNotification?.(t.method,t.params||{})}catch{}}}_close(e){if(!this.closedError){this.closedError=i(e instanceof Error?e:String(e||"codex app-server closed"),"unknown"),this.child=null;for(const{reject:e,timer:t}of this.pending.values())t&&clearTimeout(t),e(this.closedError);this.pending.clear();for(const{reject:e}of this.turnWaiters.values())e(this.closedError);this.turnWaiters.clear(),this.completedTurns.clear();for(const{reject:e,timer:t}of this.mcpWaiters.values())t&&clearTimeout(t),e(this.closedError);this.mcpWaiters.clear(),this.mcpStartup.clear();try{this.onClose?.(this.closedError)}catch{}}}async startThread({threadId:e,cwd:t,model:r,sandbox:i,approvalPolicy:s,config:o}={}){const n={cwd:t,model:r,sandbox:i,approvalPolicy:s,...o?{config:o}:{}},a=e?await this.request("thread/resume",{...n,threadId:e},this.threadTimeoutMs):await this.request("thread/start",n,this.threadTimeoutMs),d=a?.thread?.id||a?.threadId||e;if(!d)throw new Error("Codex App Server did not return a thread id");return d}waitForMcpServer({threadId:e,name:t,timeoutMs:r=this.threadTimeoutMs}={}){const i=String(e||""),s=String(t||"");if(!i||!s)return Promise.reject(new Error("Codex MCP readiness needs a thread id and server name"));const o=`${i}\0${s}`,n=this.mcpStartup.get(o);if("ready"===n?.status)return Promise.resolve(n);if(n&&("failed"===n.status||n.error||n.failureReason))return Promise.reject(new Error(`Codex MCP server ${s} failed to start: ${n.error||n.failureReason||n.status}`));if(this.mcpWaiters.has(o))return this.mcpWaiters.get(o).promise;let a,d,c=null;const l=new Promise((e,t)=>{a=e,d=t,r>0&&(c=setTimeout(()=>{this.mcpWaiters.delete(o),t(new Error(`Codex MCP server ${s} did not become ready within ${r}ms`))},r))});return this.mcpWaiters.set(o,{promise:l,resolve:a,reject:d,timer:c}),l}async startTurn({threadId:e,input:t,images:r,model:i,effort:s,approvalPolicy:n,collaborationMode:a}={}){const d=await this.request("turn/start",{threadId:e,input:o(t,r),...i?{model:i}:{},...s?{effort:s}:{},...n?{approvalPolicy:n}:{},...a?{collaborationMode:a}:{}},this.turnStartTimeoutMs),c=d?.turn?.id||d?.turnId;if(!c)throw new Error("Codex App Server did not return a turn id");return c}waitForTurn(e){if(this.completedTurns.has(e)){const t=this.completedTurns.get(e);return this.completedTurns.delete(e),Promise.resolve(t)}return this.turnWaiters.has(e)?Promise.reject(new Error(`Already waiting for Codex turn ${e}`)):new Promise((t,r)=>this.turnWaiters.set(e,{resolve:t,reject:r}))}async steer({threadId:e,turnId:t,input:r,images:i}={}){return this.request("turn/steer",{threadId:e,expectedTurnId:t,input:o(r,i)},this.controlTimeoutMs)}interrupt({threadId:e,turnId:t}={}){return this.request("turn/interrupt",{threadId:e,turnId:t},this.controlTimeoutMs)}compact({threadId:e}={}){return this.request("thread/compact/start",{threadId:e},this.controlTimeoutMs)}accountUsage(){return this.request("account/usage/read",null,this.controlTimeoutMs)}accountRateLimits(){return this.request("account/rateLimits/read",null,this.controlTimeoutMs)}startReview({threadId:e,target:t}={}){return this.request("review/start",{threadId:e,target:t||{type:"uncommittedChanges"},delivery:"inline"},this.turnStartTimeoutMs)}end(){const e=this.child;if(this._close(new Error("codex app-server ended")),e)try{e.kill("SIGTERM")}catch{}}}export function createCodexAppServer(e){return new CodexAppServerClient(e)}
|
package/codex-session.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execFileSync as e,spawn as t}from"node:child_process";import r from"node:fs";import n from"node:os";import o from"node:path";import s from"node:readline";import{buildCodexAppServerArgs as a,codexAppServerGate as i,createCodexAppServer as l}from"./codex-app-server.mjs";import{CodexEventMapper as u}from"./codex-event-mapper.mjs";import{startCodexMcpHttp as d}from"./codex-mcp-http.mjs";import{CODEX_THINKPOOL_FIRST_TURN_PREAMBLE as c,buildThinkPoolTurnGuidance as p,createRoomContextSelector as m,usesFullThinkPoolReminder as f}from"./thinkpool-room-prompt.mjs";import{questionAnswerResponse as h}from"./question-response.mjs";import{codexReviewTarget as x,isCodexCompactCommand as g}from"./codex-commands.mjs";import{createCumulativeEventRelay as y}from"./cumulative-event-relay.mjs";import{stallDecision as v,stallEvent as b}from"./turn-stall.mjs";const w=new Set(["read-only","workspace-write","danger-full-access"]);export const EFFORT_LEVELS=new Set(["low","medium","high","xhigh","max"]);export const CODEX_MODE_CONFIG={default:{sandbox:"workspace-write",approvalPolicy:"untrusted"},acceptEdits:{sandbox:"workspace-write",approvalPolicy:"on-request"},plan:{sandbox:"read-only",approvalPolicy:"never"},review:{sandbox:"read-only",approvalPolicy:"never"},bypassPermissions:{sandbox:"danger-full-access",approvalPolicy:"never"}};export function codexConfigForMode(e){return CODEX_MODE_CONFIG[e]||CODEX_MODE_CONFIG.default}export function codexDefaultCollaborationMode(e,t){return e?{mode:"default",settings:{model:String(e),reasoning_effort:EFFORT_LEVELS.has(t)?t:null,developer_instructions:null}}:null}export function defaultModeForRuntime(e){return"codex"===e?"bypassPermissions":"default"}export function codexWritableDirsForSandbox(e,t=[]){return"read-only"===normalizeCodexSandbox(e)?[]:t}export function codexExtraWritableDirsForMode(e,t,r=[]){return"review"===e?[]:codexWritableDirsForSandbox(t,r)}export function readCodexDefaultModel({home:e=process.env.CODEX_HOME||o.join(n.homedir(),".codex"),fsImpl:t=r}={}){try{const r=t.readFileSync(o.join(e,"config.toml"),"utf8").split(/^\s*\[/m,1)[0].match(/^\s*model\s*=\s*["']([^"']+)["']\s*(?:#.*)?$/m);return r?.[1]?.trim()||null}catch{return null}}export function readCodexModels({home:e=process.env.CODEX_HOME||o.join(n.homedir(),".codex"),fsImpl:t=r}={}){try{const r=JSON.parse(t.readFileSync(o.join(e,"models_cache.json"),"utf8"));return(Array.isArray(r?.models)?r.models:[]).filter(e=>e?.slug&&"hide"!==e.visibility).sort((e,t)=>(Number(e.priority)||999)-(Number(t.priority)||999)).map(e=>({value:e.slug,displayName:e.display_name||e.slug,description:e.description||""}))}catch{return[]}}const k=new Map;function I(e,{home:t,fsImpl:r}){if(!e)return null;const n=`${t}\0${e}`,s=k.get(n);if(s)return s;const a=o.join(t,"sessions");try{const t=`${e}.jsonl`,s=r.readdirSync(a,{recursive:!0,withFileTypes:!0}).find(e=>e.isFile()&&e.name.endsWith(t));if(!s)return null;const i=o.join(s.parentPath||s.path||a,s.name);return k.set(n,i),i}catch{return null}}export function codexThreadCanResume(e,{home:t=process.env.CODEX_HOME||o.join(n.homedir(),".codex"),fsImpl:s=r}={}){if(!e)return!1;const a=I(e,{home:t,fsImpl:s});if(!a)return!0;try{return Number(s.statSync(a).size)>0}catch{return!0}}export function readCodexThreadUsage(e,{home:t=process.env.CODEX_HOME||o.join(n.homedir(),".codex"),fsImpl:s=r,tailBytes:a=4194304}={}){const i=I(e,{home:t,fsImpl:s});if(!i)return null;let l;try{const e=Number(s.statSync(i).size)||0,t=Math.min(e,Math.max(65536,a)),r=Buffer.alloc(t);l=s.openSync(i,"r"),s.readSync(l,r,0,t,e-t);const n=r.toString("utf8").split("\n");for(let e=n.length-1;e>=0;e--){let t;try{t=JSON.parse(n[e])}catch{continue}if("token_count"!==t?.payload?.type||!t.payload.info)continue;const r=t.payload.info,o=r.last_token_usage||{},s=r.total_token_usage||{},a=Number(o.total_tokens),i=Number(r.model_context_window);return!Number.isFinite(a)||a<0||!Number.isFinite(i)||i<=0?null:{context:{used:Math.floor(a),max:Math.floor(i)},total:{input_tokens:Math.max(0,Number(s.input_tokens)||0),cached_input_tokens:Math.max(0,Number(s.cached_input_tokens)||0),output_tokens:Math.max(0,Number(s.output_tokens)||0)},rateLimits:t.payload.rate_limits||null}}}catch{return null}finally{if(null!=l)try{s.closeSync(l)}catch{}}return null}export function codexUsageSnapshotFromAppServer(e){const t=Number(e?.last?.totalTokens),r=Number(e?.modelContextWindow);if(!Number.isFinite(t)||t<0||!Number.isFinite(r)||r<=0)return null;const n=e?.total||{};return{context:{used:Math.floor(t),max:Math.floor(r)},total:{input_tokens:Math.max(0,Number(n.inputTokens)||0),cached_input_tokens:Math.max(0,Number(n.cachedInputTokens)||0),output_tokens:Math.max(0,Number(n.outputTokens)||0)},rateLimits:e?.rateLimits||null}}export function normalizeCodexSandbox(e){return w.has(e)?e:"workspace-write"}export function codexPublishAccess({cwd:t,env:r=process.env,tmpdir:s=n.tmpdir(),execFile:a=e}={}){const i=[];try{const e=String(a("git",["rev-parse","--git-common-dir"],{cwd:t,encoding:"utf8"})||"").trim();if(e){const r=o.resolve(t,e),n=o.resolve(t);r===n||r.startsWith(n+o.sep)||i.push(r)}}catch{}return{writableDirs:i,env:{...r,NPM_CONFIG_CACHE:o.join(s,"thinkpool-npm-cache")}}}export const CODEX_ROOM_CASCADE_REMINDER=["thinkpool ROOM ROLE ENFORCEMENT: obey the authoritative TERMINAL ROLE above. A person-authored request for a new, separate, independent, top-level, or main terminal uses open_main_terminal — NEVER spawn_terminal — even for ordinary work or a handoff. If the wording includes new or separate terminal, main-terminal routing wins. Use spawn_terminal only for agent-decided bounded worker slices or when the person explicitly asks for a worker, sub-terminal, Ensemble lane, or delegated slice. If open_main_terminal is unavailable, say so; never substitute an Ensemble child. Leaf, worker, Side, and managed Flow lanes work directly and must not delegate. Never use hidden in-process subagents."].join(" ");export function buildCodexPrompt({text:e,terminalRolePrompt:t,rolePrompt:r,roomContext:n,firstTurn:o=!1,promptIndex:s=0,forceFullReminder:a=!1}){const i="function"==typeof n?n():n,l=f({promptIndex:s,forceFull:a}),u=[o?c:"",l?t:"",p({text:e,promptIndex:s,forceFull:a}),l?r||CODEX_ROOM_CASCADE_REMINDER:"",i].map(e=>String(e||"").trim()).filter(Boolean);return u.length?`<thinkpool-context>\n${u.join("\n\n")}\n</thinkpool-context>\n\n${String(e??"")}`:String(e??"")}export function buildCodexExecArgs({sessionId:e,model:t,effort:r,sandbox:n,approvalPolicy:s="untrusted",providerConfig:a,mcpUrl:i,writableDirs:l=[],images:u=[],prompt:d}){const c=normalizeCodexSandbox(n),p=e?["exec","resume","--json","--skip-git-repo-check",..."danger-full-access"===c?["--dangerously-bypass-approvals-and-sandbox"]:["-c",`sandbox_mode="${c}"`]]:["exec","--json","--sandbox",c,"--skip-git-repo-check"];if(t&&p.push("-m",t),p.push("-c",`approval_policy="${s}"`),EFFORT_LEVELS.has(r)&&p.push("-c",`model_reasoning_effort="${r}"`),a&&p.push("-c",a),!e)for(const e of l)p.push("--add-dir",e);i&&(p.push("-c",`mcp_servers.thinkpool.url=${JSON.stringify(i)}`),p.push("-c","mcp_servers.thinkpool.required=true"));let m=!1;for(const e of u)o.isAbsolute(String(e||""))&&(p.push("--image",String(e)),m=!0);return m&&p.push("--"),e&&p.push(e),p.push(String(d??"")),p}export function codexExecFailedBeforeTurn({stderr:e="",eventTypes:t=[]}={}){if((Array.isArray(t)?t.map(e=>String(e||"")):[]).some(e=>e&&"thread.started"!==e))return!1;const r=String(e||"");return/timed out handshaking with MCP server/i.test(r)||/thread\/resume failed/i.test(r)&&/failed to initialize session/i.test(r)}const _=/\brm\s+\S|\brmdir\s+\S|\bgit\s+(push\s+(-f|--force)|reset\s+--hard|clean\s+-[a-z]*f)|\bdrop\s+(table|database)\b|\b(mkfs|dd)\b|\bsudo\b|>\s*\/dev\/|\bchmod\s+-R|\bchown\s+-R|\bkillall\b|\btruncate\b/i;export function codexApprovalCard(e,t={},r=null){const n=String(t.approvalId||t.itemId||`${t.turnId||"turn"}:${e}`);if("item/tool/requestUserInput"===e){const e=Array.isArray(t.questions)?t.questions:[];return{id:n,toolName:"AskUserQuestion",input:{questions:e},risk:"ask",questions:e,asker:"Codex",answerFormat:"codex",...Number.isFinite(t.autoResolutionMs)&&t.autoResolutionMs>0?{autoResolutionMs:t.autoResolutionMs}:{}}}if("item/commandExecution/requestApproval"===e){const e=t.command||r?.command||"";return{id:n,toolName:"Bash",input:{command:e,cwd:t.cwd||r?.cwd||"",...t.reason?{reason:t.reason}:{}},risk:_.test(e)?"high":"medium"}}if("item/fileChange/requestApproval"===e){const e=Array.isArray(r?.changes)?r.changes:[],o=e[0]||{};return{id:n,toolName:e.length>1?"MultiEdit":"add"===o.kind?"Write":"Edit",input:e.length>1?{edits:e.map(e=>({file_path:e.path||"",path:e.path||"",kind:e.kind||"update"})),...t.reason?{reason:t.reason}:{}}:{file_path:o.path||t.grantRoot||"",path:o.path||t.grantRoot||"",kind:o.kind||"update",...t.reason?{reason:t.reason}:{}},risk:"medium"}}return null}export function codexApprovalResponse(e){return{decision:"always"===e?"acceptForSession":"allow"===e?"accept":"decline"}}export function codexUserInputResponse(e,t=[]){return h(e,t)}function M(e){if(!e||"object"!=typeof e)return e;const t={...e};switch(e.type){case"agentMessage":return{...t,type:"agent_message"};case"commandExecution":return{...t,type:"command_execution",aggregated_output:e.aggregatedOutput||"",exit_code:e.exitCode};case"fileChange":return{...t,type:"file_change"};case"webSearch":return{...t,type:"web_search"};case"mcpToolCall":return{...t,type:"mcp_tool_call",arguments:e.arguments||{},result:e.result,error:e.error};case"reasoning":return{...t,type:"reasoning",text:[...e.summary||[],...e.content||[]].join("\n")};default:return t}}export function startCodexSession({cwd:e,model:c,effort:p="high",resume:h,env:w,sandbox:k,mode:I="default",onEvent:_,providerConfig:S,terminalRolePrompt:C,rolePrompt:E,roomContext:T,mcpServers:F,prepareCwd:R=null,requestPermission:O,appServerGate:N=i,appServerFactory:A=l,mcpHttpFactory:P=d,spawnImpl:U=t,admitStart:D=null,stallOptions:$={}}){let j=CODEX_MODE_CONFIG[I]?I:"default",L=codexConfigForMode(j);k=normalizeCodexSandbox(k||L.sandbox);const q=codexPublishAccess({cwd:e,env:{...process.env,...w||{}}}),X=q.env,G=h||null,z=!G||codexThreadCanResume(G,{home:X.CODEX_HOME||o.join(n.homedir(),".codex")});let W=z?G:null,B=W?1:0,H=0,V=!0;const J=m(T);let K=null,Q=!1,Y=!1,Z=!1;const ee="function"==typeof $.now?$.now:Date.now,te="function"==typeof $.setInterval?$.setInterval:setInterval,re="function"==typeof $.clearInterval?$.clearInterval:clearInterval,ne=Number.isFinite($.stallMs)?Math.max(1,Number($.stallMs)):Math.max(3e4,parseInt(X.TP_STALL_MS,10)||9e4),oe=Number.isFinite($.forceStopMs)?Math.max(ne,Number($.forceStopMs)):Math.max(3*ne,parseInt(X.TP_FORCE_STOP_MS,10)||3e5),se=Number.isFinite($.intervalMs)?Math.max(1,Number($.intervalMs)):5e3;let ae=ee(),ie=!1,le=!1,ue=!1,de=!1,ce=!0,pe=0,me=null,fe=c||null,he=EFFORT_LEVELS.has(p)?p:"high",xe=W?readCodexThreadUsage(W):null,ge=null;const ye=N({env:X});let ve=!ye.enabled,be=null,we=!1,ke=null,Ie=null,_e=!1;const Me=new Set,Se=new Map,Ce=new Map;let Ee=Promise.resolve(),Te=Promise.resolve();const Fe=[],Re=y(e=>{try{_?.(e)}catch{}}),Oe=()=>{ae=ee(),ie=!1},Ne=e=>{Oe(),Re(e)};Ne.cancel=()=>Re.cancel();const Ae=new u({onEvent:Ne,model:c||null,usageSnapshotForSession:e=>{const t=readCodexThreadUsage(e);return t&&(xe=t),t||xe}}),Pe=e=>{"turn.completed"!==e?.type&&"turn.failed"!==e?.type||(Z=!1),Ae.push(e)},Ue=e=>{Z=!1,Ne(e)},De=({retry:e=!1}={})=>{Z=!0,ae=ee(),ie=!1,ue=!1,de=!1,ce=!0,e||(le=!1)},$e=e=>Ne({kind:"note",text:e}),je=(e=ke)=>{const t=String(e||"");if(t)for(Me.add(t);Me.size>64;)Me.delete(Me.values().next().value)},Le=(e={})=>{const t=String(e.turnId||"");return!(!t||Y||Q||Me.has(t)||t!==String(ke||""))};async function qe(){const e=F?.thinkpool;return e?(ge||(ge=P({sdkServer:e})),ge):null}function Xe(e,t={}){if("thread/tokenUsage/updated"===e){if(t.threadId&&W&&String(t.threadId)!==String(W))return;const e=codexUsageSnapshotFromAppServer(t.tokenUsage);if(!e)return;if(xe=e,_e){const{used:t,max:r}=e.context;Ne({kind:"usage",ctx:{used:t,max:r,pct:Math.min(100,Math.max(0,Math.round(t/r*100))),over:t>r,model:fe}})}return}if("turn/started"===e&&t.turn?.id){const e=String(t.turn.id);if(Y||Q)return void je(e);if(Ie){const t=Ie;return Ie=null,void t.resolve(e)}return ke||(ke=e),void Oe()}if("turn/plan/updated"!==e&&"item/agentMessage/delta"!==e&&"item/started"!==e&&"item/completed"!==e&&"error"!==e||Le(t)){if(Oe(),"turn/plan/updated"===e){const e=(Array.isArray(t.plan)?t.plan:[]).map(({step:e,status:t})=>({content:e||"",activeForm:e||"",status:"inProgress"===t?"in_progress":"completed"===t?"completed":"pending"})).filter(e=>e.content);return void Ne({kind:"assistant",blocks:[{type:"tool_use",id:`codex-plan:${t.turnId||"active"}`,name:"TodoWrite",input:{todos:e}}],parentToolUseId:null})}if("item/agentMessage/delta"===e){if(!t.delta)return;const e=t.itemId||`turn:${t.turnId||ke||"active"}`,r=Ce.get(e)||{cid:`codex-stream:${W||"thread"}:${e}`,text:""};return r.text+=String(t.delta),Ce.set(e,r),void Ne({kind:"assistant_stream",cid:r.cid,text:r.text,itemId:e,streaming:!0})}if("item/started"===e||"item/completed"===e){const r=t.item;if(!r)return;if("item/started"===e&&Se.set(r.id,r),"item/completed"===e&&(Se.set(r.id,r),"agentMessage"===r.type&&Ce.has(r.id))){const e=Ce.get(r.id);return Ce.delete(r.id),void Ne({kind:"assistant",blocks:[{type:"text",text:r.text||e.text}],parentToolUseId:null,replacesCid:e.cid})}return void Pe({type:"item/started"===e?"item.started":"item.completed",item:M(r)})}if("error"===e){const e=t.error?.message||t.message||"codex app-server error";Pe({type:"error",message:e})}}}async function Ge(e,t={}){if(!Le(t))return"item/tool/requestUserInput"===e?{answers:{}}:{decision:"decline"};const r=codexApprovalCard(e,t,Se.get(t.itemId));if(!r)throw new Error(`Unsupported Codex App Server request: ${e}`);let n="deny";pe++;try{n=await(O?.(r))}catch{}finally{pe=Math.max(0,pe-1),Oe()}return"item/tool/requestUserInput"===e?codexUserInputResponse(n,r.questions):codexApprovalResponse(n)}async function ze(){if(ve)return!1;if(!1===be?.alive)return we=!1,ve=!0,!1;if(be&&we)return!0;let t;try{t=await qe()}catch(e){$e(`thinkpool peer tools unavailable: ${e?.message||e}`)}try{return be||(be=A({cwd:e,env:X,args:a({providerConfig:S,mcpUrl:t?.url,writableDirs:codexExtraWritableDirsForMode(j,k,q.writableDirs)}),onNotification:Xe,onServerRequest:Ge,onClose:e=>{Y||ve||(we=!1,ve=!0,$e(`Codex App Server closed; later turns will use codex exec: ${e?.message||e}`))}}),await be.start(),Oe()),W=await be.startThread({threadId:B>0?W:null,cwd:e,model:fe,sandbox:k,approvalPolicy:L.approvalPolicy,config:{"features.default_mode_request_user_input":!0}}),Oe(),t?.url&&(await be.waitForMcpServer({threadId:W,name:"thinkpool"}),Oe()),we=!0,Pe({type:"thread.started",thread_id:W}),!0}catch{ve=!0;try{be?.end()}catch{}return be=null,we=!1,!1}}function We({force:e=!1}={}){const t=be,r=ke;if(t&&e){je(r),ve=!0,we=!1;try{t.end()}catch{}be===t&&(be=null)}else if(t&&r)je(r),Promise.resolve(t.interrupt({threadId:W,turnId:r})).catch(()=>{ve=!0,we=!1;try{t.end()}catch{}be===t&&(be=null)});else if(t){ve=!0,we=!1;try{t.end()}catch{}be===t&&(be=null)}if(K){const e=K;try{e.kill("SIGTERM")}catch{}setTimeout(()=>{if(K===e)try{e.kill("SIGKILL")}catch{}},1500)}}async function Be(e,t={}){if(Y||Q||de)return!0;if(!await ze())return!1;if(Y||Q||de)return!0;Ae.setUsageBaseline(W?readCodexThreadUsage(W):null),Z=!0;try{if(ce=!1,ke=await be.startTurn({threadId:W,input:e,images:Array.isArray(t.images)?t.images:[],model:fe,effort:he,approvalPolicy:L.approvalPolicy,collaborationMode:codexDefaultCollaborationMode(fe,he)}),Oe(),Q||Y){je(ke);try{await be.interrupt({threadId:W,turnId:ke})}catch{}return!0}const r=await be.waitForTurn(ke);je(r?.turn?.id||ke);const n=r?.turn?.status;Q?Ue({kind:"result",subtype:"aborted",sessionId:W,model:fe,costUsd:null,usage:null,numTurns:1,durationMs:r?.turn?.durationMs,denials:0,resultText:null}):"interrupted"===n&&(ue||de)||("interrupted"===n?Ue({kind:"result",subtype:"aborted",sessionId:W,model:fe,costUsd:null,usage:null,numTurns:1,durationMs:r?.turn?.durationMs,denials:0,resultText:null}):"failed"===n?(ue=!1,Pe({type:"turn.failed",message:r?.turn?.error?.message||"codex turn failed"})):(ue=!1,Pe({type:"turn.completed"})))}catch(e){ve=!0,we=!1,je(ke);try{be?.end()}catch{}be=null,Y||ue||de||Pe({type:"turn.failed",message:`codex app-server turn failed: ${e?.message||e}`})}finally{for(const e of Ce.values())e.text&&Ne({kind:"assistant",blocks:[{type:"text",text:e.text}],parentToolUseId:null,replacesCid:e.cid});ke=null,Z=!1,Se.clear(),Ce.clear()}return!0}async function He(e){if(Y||Q||de)return!0;if(!await ze())return!1;if(Y||Q||de)return!0;Ae.setUsageBaseline(W?readCodexThreadUsage(W):null),Z=!0;try{ce=!1;const t=await be.startReview({threadId:W,target:x(e)});if(ke=t?.turn?.id||t?.turnId,!ke)throw new Error("Codex review/start returned no turn id");if(Oe(),Q||Y){je(ke);try{await be.interrupt({threadId:W,turnId:ke})}catch{}return!0}const r=await be.waitForTurn(ke);je(r?.turn?.id||ke);const n=r?.turn?.status;Q?Ue({kind:"result",subtype:"aborted",sessionId:W,model:fe,costUsd:null,usage:null,numTurns:1,durationMs:r?.turn?.durationMs,denials:0,resultText:null}):"interrupted"===n&&(ue||de)||("interrupted"===n?Ue({kind:"result",subtype:"aborted",sessionId:W,model:fe,costUsd:null,usage:null,numTurns:1,durationMs:r?.turn?.durationMs,denials:0,resultText:null}):"failed"===n?(ue=!1,Pe({type:"turn.failed",message:r?.turn?.error?.message||"codex review failed"})):(ue=!1,Pe({type:"turn.completed"})))}catch(e){ve=!0,we=!1,je(ke);try{be?.end()}catch{}be=null,Y||ue||de||Pe({type:"turn.failed",message:`codex review failed: ${e?.message||e}`})}finally{for(const e of Ce.values())e.text&&Ne({kind:"assistant",blocks:[{type:"text",text:e.text}],parentToolUseId:null,replacesCid:e.cid});ke=null,Z=!1,Se.clear(),Ce.clear()}return!0}async function Ve(t,n={}){if(Y||Q||de)return;let o;try{o=await qe()}catch(e){$e(`thinkpool peer tools unavailable: ${e?.message||e}`)}try{await(o?.handoff?.())}catch(e){$e(`thinkpool peer handoff failed: ${e?.message||e}`)}const a=buildCodexExecArgs({sessionId:0===B?null:W,model:fe,effort:he,sandbox:k,approvalPolicy:L.approvalPolicy,providerConfig:S,mcpUrl:o?.url,writableDirs:codexExtraWritableDirsForMode(j,k,q.writableDirs),images:Array.isArray(n.images)?n.images:[],prompt:t});return Ae.setUsageBaseline(W?readCodexThreadUsage(W):null),new Promise(t=>{let n;try{n=r.openSync("/dev/null","r")}catch{}const o={cwd:e,env:X,stdio:["ignore","pipe","pipe"]};if(null!=n&&(o.stdio=[n,"pipe","pipe"]),Z=!0,ce=!1,K=U("codex",a,o),null!=n)try{r.closeSync(n)}catch{}const i=[];s.createInterface({input:K.stdout,crlfDelay:1/0}).on("line",e=>{if(!e.trim())return;let t;try{t=JSON.parse(e)}catch{return}i.push(t.type),"thread.started"===t.type&&t.thread_id&&(W=W||t.thread_id),"turn.completed"!==t.type&&"turn.failed"!==t.type||(u=!0,ue=!1),Pe(t)});let l="",u=!1,d=!1;K.stderr.on("data",e=>{l+=e.toString(),l.length>800&&(l=l.slice(-800))}),K.on("error",e=>{d||(d=!0,K=null,ue||de||Ue({kind:"error",message:`codex failed to start: ${e.message}`,recoverable:!0}),t({preTurnInitFailure:!1}))}),K.on("close",e=>{if(d)return;d=!0,K=null,Z=!1;const r=`codex exec exited ${e}${l?": "+l.trim().slice(-300):""}`;0===e||null==e||u||!codexExecFailedBeforeTurn({stderr:l,eventTypes:i})||Q||de?((!ue&&!de||u||Q)&&(Q&&!u?Ue({kind:"result",subtype:"aborted",sessionId:W,model:fe,costUsd:null,usage:null,numTurns:1,durationMs:void 0,denials:0,resultText:null}):Q||u||0===e||null==e||Ue({kind:"error",message:r,recoverable:!0})),t({preTurnInitFailure:!1})):t({preTurnInitFailure:!0,message:r})})})}function Je(){if(Y)return;const e=Fe.shift();e&&(Te=Te.then(async()=>{De();const t=f({promptIndex:e.promptIndex,forceFull:e.forceFullReminder}),r=buildCodexPrompt({text:e.text,terminalRolePrompt:C,rolePrompt:E,roomContext:()=>J({force:t}),firstTurn:0===B,promptIndex:e.promptIndex,forceFullReminder:e.forceFullReminder}),n=/^\s*\/review(?:\s|$)/i.test(String(e.text||""));let o=!1,s=!1;for(;!Y&&!Q&&!de;){if(!(n?await He(e.text):await Be(r,e.options)))if(n)ue=!1,Ue({kind:"error",message:"Codex review is unavailable without the tested App Server runtime.",recoverable:!0});else{ue&&(ue=!1,o=!0,De({retry:!0}),Re({kind:"note",text:"retrying the stalled turn on a fresh connection"}));const t=await Ve(r,e.options);if(t?.preTurnInitFailure){if(!(s||Y||Q||de)){s=!0,De({retry:!0}),Re({kind:"note",text:"Codex initialization failed before the turn started; retrying once with a fresh thinkpool connection."});continue}Ue({kind:"error",message:t.message,recoverable:!0})}}if(!ue||o||de||Y||Q)break;ue=!1,o=!0,De({retry:!0}),Re({kind:"note",text:"retrying the stalled turn on a fresh connection"})}B++,Je()}))}return G&&!z&&queueMicrotask(()=>$e("The stopped Codex turn had no resumable context; continuing in a fresh thread.")),["0","false","off"].includes(String(X.TP_CODEX_APP_SERVER||"").trim().toLowerCase())||ye.enabled||queueMicrotask(()=>$e(`Codex App Server disabled: ${ye.reason}`)),me=te(()=>{const e=ee()-ae,t=v({turnActive:Z,awaitingUser:pe,quietMs:e,stallMs:ne,forceStopMs:oe,stalledSent:ie,stallRetried:le});if("none"===t)return;if("retry"===t&&!ce)return de=!0,ue=!1,Re({kind:"error",recoverable:!0,message:"Codex stopped responding after the turn began. The transport was stopped, but the prompt was not replayed automatically."}),Ue({kind:"result",subtype:"aborted",sessionId:W,model:fe,costUsd:null,usage:null,numTurns:1,durationMs:void 0,denials:0,resultText:null}),void We({force:!0});const r=b(t,e);if(r&&Re(r),"status"!==t){if("retry"===t)return le=!0,ue=!0,ae=ee(),ie=!1,void We();de=!0,ue=!1,Fe.length=0,Ue({kind:"result",subtype:"aborted",sessionId:W,model:fe,costUsd:null,usage:null,numTurns:1,durationMs:void 0,denials:0,resultText:null}),We({force:!0})}else ie=!0},se),me.unref?.(),{get sessionId(){return W},get usageSnapshot(){return xe},get turnActive(){return Z||_e},get canSteer(){return!(!be||!1===be.alive||!we||ve)},get started(){return B>0||Z},sendTurn(t,r={}){if(Y)return!1;if(!Z&&0===Fe.length&&!we&&!K){const e="function"==typeof D?D():{ok:!0};if(!1===e?.ok)return Ne({kind:"error",message:e.reason||"Host memory is critically low. This Codex runtime was not started.",recoverable:!0}),!1}const n=H++,o=V;if(V=g(t)||/^\s*\/(?:reset|clear)\b/i.test(String(t||"")),!Z&&0===B&&R)try{e=R()||e}catch{}if(Z&&be&&ke){Oe();const e=f({promptIndex:n,forceFull:o}),s=buildCodexPrompt({text:t,terminalRolePrompt:C,rolePrompt:E,roomContext:()=>J({force:e}),promptIndex:n,forceFullReminder:o}),a=ke;return Ee=Ee.then(()=>be.steer({threadId:W,turnId:a,input:s,images:Array.isArray(r.images)?r.images:[]})).catch(e=>{"rejected"===e?.delivery||"not_sent"===e?.delivery?(Fe.push({text:t,options:r,promptIndex:n,forceFullReminder:o}),Z||1!==Fe.length||Je()):Ne({kind:"error",message:"Codex steering delivery is uncertain; the message was not replayed automatically.",recoverable:!0})}),!0}return Fe.push({text:t,options:r,promptIndex:n,forceFullReminder:o}),Z||_e||(Q=!1,De()),1!==Fe.length||_e||Je(),!0},abort(){const e=Te,t=Z&&!ke&&!K;Q=!0,ue=!1,de=!1,Fe.length=0,je(ke);let r=Promise.resolve();if(be&&ke&&(r=be.interrupt({threadId:W,turnId:ke}).catch(()=>{})),K){try{K.kill("SIGTERM")}catch{}setTimeout(()=>{try{K?.kill("SIGKILL")}catch{}},1500)}else t&&Ue({kind:"result",subtype:"aborted",sessionId:W,model:fe,costUsd:null,usage:null,numTurns:0,durationMs:void 0,denials:0,resultText:null});return r.then(()=>e).catch(()=>e).then(()=>{})},end(){if(Y=!0,Z=!1,me&&re(me),Ne.cancel(),Fe.length=0,je(ke),K)try{K.kill()}catch{}try{be?.end()}catch{}ge?.then(e=>e.close()).catch(()=>{})},setModel:e=>!(!e||Z||(fe=String(e),Ae.setModel(fe),0)),setMode:e=>!(Z||!CODEX_MODE_CONFIG[e]||(j=e,L=codexConfigForMode(j),k=L.sandbox,W=null,B=0,xe=null,we=!1,0)),setEffort:e=>!(Z||!EFFORT_LEVELS.has(e)||(he=e,Ne({kind:"effort",level:he}),0)),clearContext:()=>!Z&&(W=null,B=0,xe=null,we=!1,!0),async compactContext(){if(Z||_e)return!1;Q=!1,_e=!0;let e=null,t=!1;try{if(!await ze()||Z)return!1;const r=new Promise((t,r)=>{e=setTimeout(()=>{Ie=null,r(new Error("Codex did not start the compaction turn"))},5e3),Ie={resolve:t,reject:r}});await be.compact({threadId:W}),t=!0;const n=await r;e&&clearTimeout(e);const o=await be.waitForTurn(n);je(o?.turn?.id||n);const s=o?.turn?.status;if("completed"===s)return!0;throw new Error(o?.turn?.error?.message||`compaction ${s||"failed"}`)}catch(e){return t||!["rejected","not_sent"].includes(e?.delivery)?($e(`Native Codex compaction status is uncertain; existing context was preserved: ${e?.message||e}`),null):($e(`Native Codex compaction unavailable; using bounded recap fallback: ${e?.message||e}`),!1)}finally{e&&clearTimeout(e),Ie=null,_e=!1,Fe.length&&Je()}},async accountUsage(){if(!await ze())return null;const[e,t]=await Promise.all([be.accountUsage().catch(()=>null),be.accountRateLimits().catch(()=>null)]);return{usage:e,limits:t}}}}
|
|
1
|
+
import{execFileSync as e,spawn as t}from"node:child_process";import r from"node:fs";import n from"node:os";import o from"node:path";import s from"node:readline";import{buildCodexAppServerArgs as a,codexAppServerGate as i,createCodexAppServer as l}from"./codex-app-server.mjs";import{CodexEventMapper as u}from"./codex-event-mapper.mjs";import{startCodexMcpHttp as d}from"./codex-mcp-http.mjs";import{CODEX_THINKPOOL_FIRST_TURN_PREAMBLE as c,THINKPOOL_CODEX_ULTRA_RULE as p,buildThinkPoolTurnGuidance as m,createRoomContextSelector as f,usesFullThinkPoolReminder as h}from"./thinkpool-room-prompt.mjs";import{questionAnswerResponse as x}from"./question-response.mjs";import{codexReviewTarget as g,isCodexCompactCommand as y}from"./codex-commands.mjs";import{createCumulativeEventRelay as v}from"./cumulative-event-relay.mjs";import{stallDecision as b,stallEvent as w}from"./turn-stall.mjs";import{codexNativeReasoningEffort as k,codexReasoningEfforts as C,normalizeCodexReasoningEffort as I,normalizeReasoningEffortList as _}from"./reasoning-effort.mjs";const M=new Set(["read-only","workspace-write","danger-full-access"]);export const CODEX_MODE_CONFIG={default:{sandbox:"workspace-write",approvalPolicy:"untrusted"},acceptEdits:{sandbox:"workspace-write",approvalPolicy:"on-request"},plan:{sandbox:"read-only",approvalPolicy:"never"},review:{sandbox:"read-only",approvalPolicy:"never"},bypassPermissions:{sandbox:"danger-full-access",approvalPolicy:"never"}};export function codexConfigForMode(e){return CODEX_MODE_CONFIG[e]||CODEX_MODE_CONFIG.default}export function codexDefaultCollaborationMode(e,t){if(!e)return null;const r=k(t);return{mode:"default",settings:{model:String(e),reasoning_effort:r,developer_instructions:null}}}export function defaultModeForRuntime(e){return"codex"===e?"bypassPermissions":"default"}export function codexWritableDirsForSandbox(e,t=[]){return"read-only"===normalizeCodexSandbox(e)?[]:t}export function codexExtraWritableDirsForMode(e,t,r=[]){return"review"===e?[]:codexWritableDirsForSandbox(t,r)}export function readCodexDefaultModel({home:e=process.env.CODEX_HOME||o.join(n.homedir(),".codex"),fsImpl:t=r}={}){try{const r=t.readFileSync(o.join(e,"config.toml"),"utf8").split(/^\s*\[/m,1)[0].match(/^\s*model\s*=\s*["']([^"']+)["']\s*(?:#.*)?$/m);return r?.[1]?.trim()||null}catch{return null}}export function readCodexModels({home:e=process.env.CODEX_HOME||o.join(n.homedir(),".codex"),fsImpl:t=r}={}){try{const r=JSON.parse(t.readFileSync(o.join(e,"models_cache.json"),"utf8"));return(Array.isArray(r?.models)?r.models:[]).filter(e=>e?.slug&&"hide"!==e.visibility).sort((e,t)=>(Number(e.priority)||999)-(Number(t.priority)||999)).map(e=>({value:e.slug,displayName:e.display_name||e.slug,description:e.description||"",reasoningEfforts:_(e.supported_reasoning_levels)}))}catch{return[]}}const S=new Map;function E(e,{home:t,fsImpl:r}){if(!e)return null;const n=`${t}\0${e}`,s=S.get(n);if(s)return s;const a=o.join(t,"sessions");try{const t=`${e}.jsonl`,s=r.readdirSync(a,{recursive:!0,withFileTypes:!0}).find(e=>e.isFile()&&e.name.endsWith(t));if(!s)return null;const i=o.join(s.parentPath||s.path||a,s.name);return S.set(n,i),i}catch{return null}}export function codexThreadCanResume(e,{home:t=process.env.CODEX_HOME||o.join(n.homedir(),".codex"),fsImpl:s=r}={}){if(!e)return!1;const a=E(e,{home:t,fsImpl:s});if(!a)return!0;try{return Number(s.statSync(a).size)>0}catch{return!0}}export function readCodexThreadUsage(e,{home:t=process.env.CODEX_HOME||o.join(n.homedir(),".codex"),fsImpl:s=r,tailBytes:a=4194304}={}){const i=E(e,{home:t,fsImpl:s});if(!i)return null;let l;try{const e=Number(s.statSync(i).size)||0,t=Math.min(e,Math.max(65536,a)),r=Buffer.alloc(t);l=s.openSync(i,"r"),s.readSync(l,r,0,t,e-t);const n=r.toString("utf8").split("\n");for(let e=n.length-1;e>=0;e--){let t;try{t=JSON.parse(n[e])}catch{continue}if("token_count"!==t?.payload?.type||!t.payload.info)continue;const r=t.payload.info,o=r.last_token_usage||{},s=r.total_token_usage||{},a=Number(o.total_tokens),i=Number(r.model_context_window);return!Number.isFinite(a)||a<0||!Number.isFinite(i)||i<=0?null:{context:{used:Math.floor(a),max:Math.floor(i)},total:{input_tokens:Math.max(0,Number(s.input_tokens)||0),cached_input_tokens:Math.max(0,Number(s.cached_input_tokens)||0),output_tokens:Math.max(0,Number(s.output_tokens)||0)},rateLimits:t.payload.rate_limits||null}}}catch{return null}finally{if(null!=l)try{s.closeSync(l)}catch{}}return null}export function codexUsageSnapshotFromAppServer(e){const t=Number(e?.last?.totalTokens),r=Number(e?.modelContextWindow);if(!Number.isFinite(t)||t<0||!Number.isFinite(r)||r<=0)return null;const n=e?.total||{};return{context:{used:Math.floor(t),max:Math.floor(r)},total:{input_tokens:Math.max(0,Number(n.inputTokens)||0),cached_input_tokens:Math.max(0,Number(n.cachedInputTokens)||0),output_tokens:Math.max(0,Number(n.outputTokens)||0)},rateLimits:e?.rateLimits||null}}export function normalizeCodexSandbox(e){return M.has(e)?e:"workspace-write"}export function codexPublishAccess({cwd:t,env:r=process.env,tmpdir:s=n.tmpdir(),execFile:a=e}={}){const i=[];try{const e=String(a("git",["rev-parse","--git-common-dir"],{cwd:t,encoding:"utf8"})||"").trim();if(e){const r=o.resolve(t,e),n=o.resolve(t);r===n||r.startsWith(n+o.sep)||i.push(r)}}catch{}return{writableDirs:i,env:{...r,NPM_CONFIG_CACHE:o.join(s,"thinkpool-npm-cache")}}}export const CODEX_ROOM_CASCADE_REMINDER=["thinkpool ROOM ROLE ENFORCEMENT: obey the authoritative TERMINAL ROLE above. A person-authored request for a new, separate, independent, top-level, or main terminal uses open_main_terminal — NEVER spawn_terminal — even for ordinary work or a handoff. If the wording includes new or separate terminal, main-terminal routing wins. Use spawn_terminal only for agent-decided bounded worker slices or when the person explicitly asks for a worker, sub-terminal, Ensemble lane, or delegated slice. If open_main_terminal is unavailable, say so; never substitute an Ensemble child. Leaf, worker, Side, and managed Flow lanes work directly and must not delegate. Never use hidden in-process subagents."].join(" ");export const CODEX_ULTRA_CASCADE_REMINDER=p;export function buildCodexPrompt({text:e,terminalRolePrompt:t,rolePrompt:r,roomContext:n,firstTurn:o=!1,promptIndex:s=0,forceFullReminder:a=!1,ultraCascade:i=!1}){const l="function"==typeof n?n():n,u=h({promptIndex:s,forceFull:a}),d=[o?c:"",u?t:"",m({text:e,promptIndex:s,forceFull:a}),u?r||CODEX_ROOM_CASCADE_REMINDER:"",i?CODEX_ULTRA_CASCADE_REMINDER:"",l].map(e=>String(e||"").trim()).filter(Boolean);return d.length?`<thinkpool-context>\n${d.join("\n\n")}\n</thinkpool-context>\n\n${String(e??"")}`:String(e??"")}export function buildCodexExecArgs({sessionId:e,model:t,effort:r,sandbox:n,approvalPolicy:s="untrusted",providerConfig:a,mcpUrl:i,writableDirs:l=[],images:u=[],prompt:d}){const c=normalizeCodexSandbox(n),p=e?["exec","resume","--json","--skip-git-repo-check",..."danger-full-access"===c?["--dangerously-bypass-approvals-and-sandbox"]:["-c",`sandbox_mode="${c}"`]]:["exec","--json","--sandbox",c,"--skip-git-repo-check"];t&&p.push("-m",t),p.push("-c",`approval_policy="${s}"`);const m=k(r);if(m&&p.push("-c",`model_reasoning_effort="${m}"`),a&&p.push("-c",a),!e)for(const e of l)p.push("--add-dir",e);i&&(p.push("-c",`mcp_servers.thinkpool.url=${JSON.stringify(i)}`),p.push("-c","mcp_servers.thinkpool.required=true"));let f=!1;for(const e of u)o.isAbsolute(String(e||""))&&(p.push("--image",String(e)),f=!0);return f&&p.push("--"),e&&p.push(e),p.push(String(d??"")),p}export function codexExecFailedBeforeTurn({stderr:e="",eventTypes:t=[]}={}){if((Array.isArray(t)?t.map(e=>String(e||"")):[]).some(e=>e&&"thread.started"!==e))return!1;const r=String(e||"");return/timed out handshaking with MCP server/i.test(r)||/thread\/resume failed/i.test(r)&&/failed to initialize session/i.test(r)}const T=/\brm\s+\S|\brmdir\s+\S|\bgit\s+(push\s+(-f|--force)|reset\s+--hard|clean\s+-[a-z]*f)|\bdrop\s+(table|database)\b|\b(mkfs|dd)\b|\bsudo\b|>\s*\/dev\/|\bchmod\s+-R|\bchown\s+-R|\bkillall\b|\btruncate\b/i;export function codexApprovalCard(e,t={},r=null){const n=String(t.approvalId||t.itemId||`${t.turnId||"turn"}:${e}`);if("item/tool/requestUserInput"===e){const e=Array.isArray(t.questions)?t.questions:[];return{id:n,toolName:"AskUserQuestion",input:{questions:e},risk:"ask",questions:e,asker:"Codex",answerFormat:"codex",...Number.isFinite(t.autoResolutionMs)&&t.autoResolutionMs>0?{autoResolutionMs:t.autoResolutionMs}:{}}}if("item/commandExecution/requestApproval"===e){const e=t.command||r?.command||"";return{id:n,toolName:"Bash",input:{command:e,cwd:t.cwd||r?.cwd||"",...t.reason?{reason:t.reason}:{}},risk:T.test(e)?"high":"medium"}}if("item/fileChange/requestApproval"===e){const e=Array.isArray(r?.changes)?r.changes:[],o=e[0]||{};return{id:n,toolName:e.length>1?"MultiEdit":"add"===o.kind?"Write":"Edit",input:e.length>1?{edits:e.map(e=>({file_path:e.path||"",path:e.path||"",kind:e.kind||"update"})),...t.reason?{reason:t.reason}:{}}:{file_path:o.path||t.grantRoot||"",path:o.path||t.grantRoot||"",kind:o.kind||"update",...t.reason?{reason:t.reason}:{}},risk:"medium"}}return null}export function codexApprovalResponse(e){return{decision:"always"===e?"acceptForSession":"allow"===e?"accept":"decline"}}export function codexUserInputResponse(e,t=[]){return x(e,t)}function F(e){if(!e||"object"!=typeof e)return e;const t={...e};switch(e.type){case"agentMessage":return{...t,type:"agent_message"};case"commandExecution":return{...t,type:"command_execution",aggregated_output:e.aggregatedOutput||"",exit_code:e.exitCode};case"fileChange":return{...t,type:"file_change"};case"webSearch":return{...t,type:"web_search"};case"mcpToolCall":return{...t,type:"mcp_tool_call",arguments:e.arguments||{},result:e.result,error:e.error};case"reasoning":return{...t,type:"reasoning",text:[...e.summary||[],...e.content||[]].join("\n")};default:return t}}export function startCodexSession({cwd:e,model:c,models:p=[],effort:m="high",allowUltraCascade:x=!1,resume:_,env:M,sandbox:S,mode:E="default",onEvent:T,providerConfig:R,terminalRolePrompt:N,rolePrompt:A,roomContext:O,mcpServers:P,prepareCwd:U=null,requestPermission:D,appServerGate:$=i,appServerFactory:j=l,mcpHttpFactory:q=d,spawnImpl:L=t,admitStart:X=null,stallOptions:G={}}){let z=CODEX_MODE_CONFIG[E]?E:"default",W=codexConfigForMode(z);S=normalizeCodexSandbox(S||W.sandbox);const B=codexPublishAccess({cwd:e,env:{...process.env,...M||{}}}),H=B.env,J=_||null,K=!J||codexThreadCanResume(J,{home:H.CODEX_HOME||o.join(n.homedir(),".codex")});let V=K?J:null,Q=V?1:0,Y=0,Z=!0;const ee=f(O);let te=null,re=!1,ne=!1,oe=!1;const se="function"==typeof G.now?G.now:Date.now,ae="function"==typeof G.setInterval?G.setInterval:setInterval,ie="function"==typeof G.clearInterval?G.clearInterval:clearInterval,le=Number.isFinite(G.stallMs)?Math.max(1,Number(G.stallMs)):Math.max(3e4,parseInt(H.TP_STALL_MS,10)||9e4),ue=Number.isFinite(G.forceStopMs)?Math.max(le,Number(G.forceStopMs)):Math.max(3*le,parseInt(H.TP_FORCE_STOP_MS,10)||3e5),de=Number.isFinite(G.intervalMs)?Math.max(1,Number(G.intervalMs)):5e3;let ce=se(),pe=!1,me=!1,fe=!1,he=!1,xe=!0,ge=0,ye=null,ve=c||null,be=I(m,{models:p,model:ve,allowUltraCascade:x}),we=V?readCodexThreadUsage(V):null,ke=null;const Ce=$({env:H});let Ie=!Ce.enabled,_e=null,Me=!1,Se=null,Ee=null,Te=!1;const Fe=new Set,Re=new Map,Ne=new Map;let Ae=Promise.resolve(),Oe=Promise.resolve();const Pe=[],Ue=v(e=>{try{T?.(e)}catch{}}),De=()=>{ce=se(),pe=!1},$e=e=>{De(),Ue(e)};$e.cancel=()=>Ue.cancel();const je=new u({onEvent:$e,model:c||null,usageSnapshotForSession:e=>{const t=readCodexThreadUsage(e);return t&&(we=t),t||we}}),qe=e=>{"turn.completed"!==e?.type&&"turn.failed"!==e?.type||(oe=!1),je.push(e)},Le=e=>{oe=!1,$e(e)},Xe=({retry:e=!1}={})=>{oe=!0,ce=se(),pe=!1,fe=!1,he=!1,xe=!0,e||(me=!1)},Ge=e=>$e({kind:"note",text:e}),ze=(e=Se)=>{const t=String(e||"");if(t)for(Fe.add(t);Fe.size>64;)Fe.delete(Fe.values().next().value)},We=(e={})=>{const t=String(e.turnId||"");return!(!t||ne||re||Fe.has(t)||t!==String(Se||""))};async function Be(){const e=P?.thinkpool;return e?(ke||(ke=q({sdkServer:e})),ke):null}function He(e,t={}){if("thread/tokenUsage/updated"===e){if(t.threadId&&V&&String(t.threadId)!==String(V))return;const e=codexUsageSnapshotFromAppServer(t.tokenUsage);if(!e)return;if(we=e,Te){const{used:t,max:r}=e.context;$e({kind:"usage",ctx:{used:t,max:r,pct:Math.min(100,Math.max(0,Math.round(t/r*100))),over:t>r,model:ve}})}return}if("turn/started"===e&&t.turn?.id){const e=String(t.turn.id);if(ne||re)return void ze(e);if(Ee){const t=Ee;return Ee=null,void t.resolve(e)}return Se||(Se=e),void De()}if("turn/plan/updated"!==e&&"item/agentMessage/delta"!==e&&"item/started"!==e&&"item/completed"!==e&&"error"!==e||We(t)){if(De(),"turn/plan/updated"===e){const e=(Array.isArray(t.plan)?t.plan:[]).map(({step:e,status:t})=>({content:e||"",activeForm:e||"",status:"inProgress"===t?"in_progress":"completed"===t?"completed":"pending"})).filter(e=>e.content);return void $e({kind:"assistant",blocks:[{type:"tool_use",id:`codex-plan:${t.turnId||"active"}`,name:"TodoWrite",input:{todos:e}}],parentToolUseId:null})}if("item/agentMessage/delta"===e){if(!t.delta)return;const e=t.itemId||`turn:${t.turnId||Se||"active"}`,r=Ne.get(e)||{cid:`codex-stream:${V||"thread"}:${e}`,text:""};return r.text+=String(t.delta),Ne.set(e,r),void $e({kind:"assistant_stream",cid:r.cid,text:r.text,itemId:e,streaming:!0})}if("item/started"===e||"item/completed"===e){const r=t.item;if(!r)return;if("item/started"===e&&Re.set(r.id,r),"item/completed"===e&&(Re.set(r.id,r),"agentMessage"===r.type&&Ne.has(r.id))){const e=Ne.get(r.id);return Ne.delete(r.id),void $e({kind:"assistant",blocks:[{type:"text",text:r.text||e.text}],parentToolUseId:null,replacesCid:e.cid})}return void qe({type:"item/started"===e?"item.started":"item.completed",item:F(r)})}if("error"===e){const e=t.error?.message||t.message||"codex app-server error";qe({type:"error",message:e})}}}async function Je(e,t={}){if(!We(t))return"item/tool/requestUserInput"===e?{answers:{}}:{decision:"decline"};const r=codexApprovalCard(e,t,Re.get(t.itemId));if(!r)throw new Error(`Unsupported Codex App Server request: ${e}`);let n="deny";ge++;try{n=await(D?.(r))}catch{}finally{ge=Math.max(0,ge-1),De()}return"item/tool/requestUserInput"===e?codexUserInputResponse(n,r.questions):codexApprovalResponse(n)}async function Ke(){if(Ie)return!1;if(!1===_e?.alive)return Me=!1,Ie=!0,!1;if(_e&&Me)return!0;let t;try{t=await Be()}catch(e){Ge(`thinkpool peer tools unavailable: ${e?.message||e}`)}try{return _e||(_e=j({cwd:e,env:H,args:a({providerConfig:R,mcpUrl:t?.url,writableDirs:codexExtraWritableDirsForMode(z,S,B.writableDirs)}),onNotification:He,onServerRequest:Je,onClose:e=>{ne||Ie||(Me=!1,Ie=!0,Ge(`Codex App Server closed; later turns will use codex exec: ${e?.message||e}`))}}),await _e.start(),De()),V=await _e.startThread({threadId:Q>0?V:null,cwd:e,model:ve,sandbox:S,approvalPolicy:W.approvalPolicy,config:{"features.default_mode_request_user_input":!0}}),De(),t?.url&&(await _e.waitForMcpServer({threadId:V,name:"thinkpool"}),De()),Me=!0,qe({type:"thread.started",thread_id:V}),!0}catch{Ie=!0;try{_e?.end()}catch{}return _e=null,Me=!1,!1}}function Ve({force:e=!1}={}){const t=_e,r=Se;if(t&&e){ze(r),Ie=!0,Me=!1;try{t.end()}catch{}_e===t&&(_e=null)}else if(t&&r)ze(r),Promise.resolve(t.interrupt({threadId:V,turnId:r})).catch(()=>{Ie=!0,Me=!1;try{t.end()}catch{}_e===t&&(_e=null)});else if(t){Ie=!0,Me=!1;try{t.end()}catch{}_e===t&&(_e=null)}if(te){const e=te;try{e.kill("SIGTERM")}catch{}setTimeout(()=>{if(te===e)try{e.kill("SIGKILL")}catch{}},1500)}}async function Qe(e,t={}){if(ne||re||he)return!0;if(!await Ke())return!1;if(ne||re||he)return!0;je.setUsageBaseline(V?readCodexThreadUsage(V):null),oe=!0;try{if(xe=!1,Se=await _e.startTurn({threadId:V,input:e,images:Array.isArray(t.images)?t.images:[],model:ve,effort:k(be),approvalPolicy:W.approvalPolicy,collaborationMode:codexDefaultCollaborationMode(ve,be)}),De(),re||ne){ze(Se);try{await _e.interrupt({threadId:V,turnId:Se})}catch{}return!0}const r=await _e.waitForTurn(Se);ze(r?.turn?.id||Se);const n=r?.turn?.status;re?Le({kind:"result",subtype:"aborted",sessionId:V,model:ve,costUsd:null,usage:null,numTurns:1,durationMs:r?.turn?.durationMs,denials:0,resultText:null}):"interrupted"===n&&(fe||he)||("interrupted"===n?Le({kind:"result",subtype:"aborted",sessionId:V,model:ve,costUsd:null,usage:null,numTurns:1,durationMs:r?.turn?.durationMs,denials:0,resultText:null}):"failed"===n?(fe=!1,qe({type:"turn.failed",message:r?.turn?.error?.message||"codex turn failed"})):(fe=!1,qe({type:"turn.completed"})))}catch(e){Ie=!0,Me=!1,ze(Se);try{_e?.end()}catch{}_e=null,ne||fe||he||qe({type:"turn.failed",message:`codex app-server turn failed: ${e?.message||e}`})}finally{for(const e of Ne.values())e.text&&$e({kind:"assistant",blocks:[{type:"text",text:e.text}],parentToolUseId:null,replacesCid:e.cid});Se=null,oe=!1,Re.clear(),Ne.clear()}return!0}async function Ye(e){if(ne||re||he)return!0;if(!await Ke())return!1;if(ne||re||he)return!0;je.setUsageBaseline(V?readCodexThreadUsage(V):null),oe=!0;try{xe=!1;const t=await _e.startReview({threadId:V,target:g(e)});if(Se=t?.turn?.id||t?.turnId,!Se)throw new Error("Codex review/start returned no turn id");if(De(),re||ne){ze(Se);try{await _e.interrupt({threadId:V,turnId:Se})}catch{}return!0}const r=await _e.waitForTurn(Se);ze(r?.turn?.id||Se);const n=r?.turn?.status;re?Le({kind:"result",subtype:"aborted",sessionId:V,model:ve,costUsd:null,usage:null,numTurns:1,durationMs:r?.turn?.durationMs,denials:0,resultText:null}):"interrupted"===n&&(fe||he)||("interrupted"===n?Le({kind:"result",subtype:"aborted",sessionId:V,model:ve,costUsd:null,usage:null,numTurns:1,durationMs:r?.turn?.durationMs,denials:0,resultText:null}):"failed"===n?(fe=!1,qe({type:"turn.failed",message:r?.turn?.error?.message||"codex review failed"})):(fe=!1,qe({type:"turn.completed"})))}catch(e){Ie=!0,Me=!1,ze(Se);try{_e?.end()}catch{}_e=null,ne||fe||he||qe({type:"turn.failed",message:`codex review failed: ${e?.message||e}`})}finally{for(const e of Ne.values())e.text&&$e({kind:"assistant",blocks:[{type:"text",text:e.text}],parentToolUseId:null,replacesCid:e.cid});Se=null,oe=!1,Re.clear(),Ne.clear()}return!0}async function Ze(t,n={}){if(ne||re||he)return;let o;try{o=await Be()}catch(e){Ge(`thinkpool peer tools unavailable: ${e?.message||e}`)}try{await(o?.handoff?.())}catch(e){Ge(`thinkpool peer handoff failed: ${e?.message||e}`)}const a=buildCodexExecArgs({sessionId:0===Q?null:V,model:ve,effort:be,sandbox:S,approvalPolicy:W.approvalPolicy,providerConfig:R,mcpUrl:o?.url,writableDirs:codexExtraWritableDirsForMode(z,S,B.writableDirs),images:Array.isArray(n.images)?n.images:[],prompt:t});return je.setUsageBaseline(V?readCodexThreadUsage(V):null),new Promise(t=>{let n;try{n=r.openSync("/dev/null","r")}catch{}const o={cwd:e,env:H,stdio:["ignore","pipe","pipe"]};if(null!=n&&(o.stdio=[n,"pipe","pipe"]),oe=!0,xe=!1,te=L("codex",a,o),null!=n)try{r.closeSync(n)}catch{}const i=[];s.createInterface({input:te.stdout,crlfDelay:1/0}).on("line",e=>{if(!e.trim())return;let t;try{t=JSON.parse(e)}catch{return}i.push(t.type),"thread.started"===t.type&&t.thread_id&&(V=V||t.thread_id),"turn.completed"!==t.type&&"turn.failed"!==t.type||(u=!0,fe=!1),qe(t)});let l="",u=!1,d=!1;te.stderr.on("data",e=>{l+=e.toString(),l.length>800&&(l=l.slice(-800))}),te.on("error",e=>{d||(d=!0,te=null,fe||he||Le({kind:"error",message:`codex failed to start: ${e.message}`,recoverable:!0}),t({preTurnInitFailure:!1}))}),te.on("close",e=>{if(d)return;d=!0,te=null,oe=!1;const r=`codex exec exited ${e}${l?": "+l.trim().slice(-300):""}`;0===e||null==e||u||!codexExecFailedBeforeTurn({stderr:l,eventTypes:i})||re||he?((!fe&&!he||u||re)&&(re&&!u?Le({kind:"result",subtype:"aborted",sessionId:V,model:ve,costUsd:null,usage:null,numTurns:1,durationMs:void 0,denials:0,resultText:null}):re||u||0===e||null==e||Le({kind:"error",message:r,recoverable:!0})),t({preTurnInitFailure:!1})):t({preTurnInitFailure:!0,message:r})})})}function et(){if(ne)return;const e=Pe.shift();e&&(Oe=Oe.then(async()=>{Xe();const t=h({promptIndex:e.promptIndex,forceFull:e.forceFullReminder}),r=buildCodexPrompt({text:e.text,terminalRolePrompt:N,rolePrompt:A,roomContext:()=>ee({force:t}),firstTurn:0===Q,promptIndex:e.promptIndex,forceFullReminder:e.forceFullReminder,ultraCascade:x&&"ultra"===be}),n=/^\s*\/review(?:\s|$)/i.test(String(e.text||""));let o=!1,s=!1;for(;!ne&&!re&&!he;){if(!(n?await Ye(e.text):await Qe(r,e.options)))if(n)fe=!1,Le({kind:"error",message:"Codex review is unavailable without the tested App Server runtime.",recoverable:!0});else{fe&&(fe=!1,o=!0,Xe({retry:!0}),Ue({kind:"note",text:"retrying the stalled turn on a fresh connection"}));const t=await Ze(r,e.options);if(t?.preTurnInitFailure){if(!(s||ne||re||he)){s=!0,Xe({retry:!0}),Ue({kind:"note",text:"Codex initialization failed before the turn started; retrying once with a fresh thinkpool connection."});continue}Le({kind:"error",message:t.message,recoverable:!0})}}if(!fe||o||he||ne||re)break;fe=!1,o=!0,Xe({retry:!0}),Ue({kind:"note",text:"retrying the stalled turn on a fresh connection"})}Q++,et()}))}return J&&!K&&queueMicrotask(()=>Ge("The stopped Codex turn had no resumable context; continuing in a fresh thread.")),["0","false","off"].includes(String(H.TP_CODEX_APP_SERVER||"").trim().toLowerCase())||Ce.enabled||queueMicrotask(()=>Ge(`Codex App Server disabled: ${Ce.reason}`)),ye=ae(()=>{const e=se()-ce,t=b({turnActive:oe,awaitingUser:ge,quietMs:e,stallMs:le,forceStopMs:ue,stalledSent:pe,stallRetried:me});if("none"===t)return;if("retry"===t&&!xe)return he=!0,fe=!1,Ue({kind:"error",recoverable:!0,message:"Codex stopped responding after the turn began. The transport was stopped, but the prompt was not replayed automatically."}),Le({kind:"result",subtype:"aborted",sessionId:V,model:ve,costUsd:null,usage:null,numTurns:1,durationMs:void 0,denials:0,resultText:null}),void Ve({force:!0});const r=w(t,e);if(r&&Ue(r),"status"!==t){if("retry"===t)return me=!0,fe=!0,ce=se(),pe=!1,void Ve();he=!0,fe=!1,Pe.length=0,Le({kind:"result",subtype:"aborted",sessionId:V,model:ve,costUsd:null,usage:null,numTurns:1,durationMs:void 0,denials:0,resultText:null}),Ve({force:!0})}else pe=!0},de),ye.unref?.(),{get sessionId(){return V},get usageSnapshot(){return we},get turnActive(){return oe||Te},get canSteer(){return!(!_e||!1===_e.alive||!Me||Ie)},get started(){return Q>0||oe},sendTurn(t,r={}){if(ne)return!1;if(!oe&&0===Pe.length&&!Me&&!te){const e="function"==typeof X?X():{ok:!0};if(!1===e?.ok)return $e({kind:"error",message:e.reason||"Host memory is critically low. This Codex runtime was not started.",recoverable:!0}),!1}const n=Y++,o=Z;if(Z=y(t)||/^\s*\/(?:reset|clear)\b/i.test(String(t||"")),!oe&&0===Q&&U)try{e=U()||e}catch{}if(oe&&_e&&Se){De();const e=h({promptIndex:n,forceFull:o}),s=buildCodexPrompt({text:t,terminalRolePrompt:N,rolePrompt:A,roomContext:()=>ee({force:e}),promptIndex:n,forceFullReminder:o}),a=Se;return Ae=Ae.then(()=>_e.steer({threadId:V,turnId:a,input:s,images:Array.isArray(r.images)?r.images:[]})).catch(e=>{"rejected"===e?.delivery||"not_sent"===e?.delivery?(Pe.push({text:t,options:r,promptIndex:n,forceFullReminder:o}),oe||1!==Pe.length||et()):$e({kind:"error",message:"Codex steering delivery is uncertain; the message was not replayed automatically.",recoverable:!0})}),!0}return Pe.push({text:t,options:r,promptIndex:n,forceFullReminder:o}),oe||Te||(re=!1,Xe()),1!==Pe.length||Te||et(),!0},abort(){const e=Oe,t=oe&&!Se&&!te;re=!0,fe=!1,he=!1,Pe.length=0,ze(Se);let r=Promise.resolve();if(_e&&Se&&(r=_e.interrupt({threadId:V,turnId:Se}).catch(()=>{})),te){try{te.kill("SIGTERM")}catch{}setTimeout(()=>{try{te?.kill("SIGKILL")}catch{}},1500)}else t&&Le({kind:"result",subtype:"aborted",sessionId:V,model:ve,costUsd:null,usage:null,numTurns:0,durationMs:void 0,denials:0,resultText:null});return r.then(()=>e).catch(()=>e).then(()=>{})},end(){if(ne=!0,oe=!1,ye&&ie(ye),$e.cancel(),Pe.length=0,ze(Se),te)try{te.kill()}catch{}try{_e?.end()}catch{}ke?.then(e=>e.close()).catch(()=>{})},setModel(e){if(!e||oe)return!1;ve=String(e),je.setModel(ve);const t=I(be,{models:p,model:ve,allowUltraCascade:x});return t!==be&&(be=t,$e({kind:"effort",level:be})),!0},setMode:e=>!(oe||!CODEX_MODE_CONFIG[e]||(z=e,W=codexConfigForMode(z),S=W.sandbox,V=null,Q=0,we=null,Me=!1,0)),setEffort:e=>!(oe||!C({models:p,model:ve,allowUltraCascade:x}).includes(e)||(be=e,$e({kind:"effort",level:be}),0)),clearContext:()=>!oe&&(V=null,Q=0,we=null,Me=!1,!0),async compactContext(){if(oe||Te)return!1;re=!1,Te=!0;let e=null,t=!1;try{if(!await Ke()||oe)return!1;const r=new Promise((t,r)=>{e=setTimeout(()=>{Ee=null,r(new Error("Codex did not start the compaction turn"))},5e3),Ee={resolve:t,reject:r}});await _e.compact({threadId:V}),t=!0;const n=await r;e&&clearTimeout(e);const o=await _e.waitForTurn(n);ze(o?.turn?.id||n);const s=o?.turn?.status;if("completed"===s)return!0;throw new Error(o?.turn?.error?.message||`compaction ${s||"failed"}`)}catch(e){return t||!["rejected","not_sent"].includes(e?.delivery)?(Ge(`Native Codex compaction status is uncertain; existing context was preserved: ${e?.message||e}`),null):(Ge(`Native Codex compaction unavailable; using bounded recap fallback: ${e?.message||e}`),!1)}finally{e&&clearTimeout(e),Ee=null,Te=!1,Pe.length&&et()}},async accountUsage(){if(!await Ke())return null;const[e,t]=await Promise.all([_e.accountUsage().catch(()=>null),_e.accountRateLimits().catch(()=>null)]);return{usage:e,limits:t}}}}
|
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","low | medium | high | xhigh | max"),e("/queue","run a prompt after the active turn","queue","prompt"),e("/steer","guide the active turn","steer","prompt",["codex","hermes"]),e("/credits","provider credit balance","credits",null,["codex","hermes"]),e("/review","review uncommitted changes","runtime",null,["codex"])]);const t=Object.freeze({claude:Object.freeze({accept:!0,hidden:Object.freeze(new Set(["/flow"]))}),codex:Object.freeze({accept:!1,hidden:Object.freeze(new Set(["/flow"]))}),hermes:Object.freeze({accept:!0,hidden:Object.freeze(new Set(["/flow","/reasoning"]))})}),n=e=>{const t=(e=>{const t=`/${String(("string"==typeof e?e:e?.name)||"").trim().replace(/^\/+/,"")}`;return/^\/[A-Za-z0-9][A-Za-z0-9:_-]*$/.test(t)?t:""})(e);if(!t)return null;if("string"==typeof e)return{name:t,description:"runtime command",route:"runtime"};const n=String(e?.description||"").trim()||"runtime command",i=String(e?.inputHint||e?.input_hint||e?.input?.hint||"").trim();return{name:t,description:n,route:String(e?.route||"").trim()||"runtime",...i?{inputHint:i}:{}}};export function commandCatalogForRuntime(e,i=[]){const r=(e=>"thinkpool"===e?"hermes":e)(e),o=t[r]||t.codex,c=new Map;for(const e of CODE_ROOM_COMMANDS)e.runtimes.includes(r)&&c.set(e.name,{name:e.name,description:e.description,route:e.route,...e.inputHint?{inputHint:e.inputHint}:{}});for(const e of Array.isArray(i)?i:[]){const t=n(e);if(!t||!o.accept||o.hidden.has(t.name))continue;const i=c.get(t.name),s="hermes"===r&&["/help","/status","/context","/credits"].includes(t.name);c.set(t.name,i?{...t,...i,description:"runtime command"===t.description?i.description:t.description,...t.inputHint?{inputHint:t.inputHint}:{},...s?{route:"runtime"}:{}}:t)}return[...c.values()]}export const commandNeedsInput=e=>!!String(e?.inputHint||"").trim();export const commandRoute=e=>String(e?.route||"runtime");export function commandHelpLine(e){return(Array.isArray(e)?e:[]).map(e=>`${e.name}${e.inputHint?` <${e.inputHint}>`:""}`).join(" ")}export function normalizePermissionMode(e){const t=String(e||"").trim().toLowerCase().replace(/[\s_-]+/g,"");return["normal","default","manual"].includes(t)?"default":["auto","autoaccept","autoacceptedits","acceptedits"].includes(t)?"acceptEdits":"plan"===t?"plan":["bypass","bypasspermissions","fullauto"].includes(t)?"bypassPermissions":null}export function reconcileCommandCatalog({current:e,incoming:t,onChanged:n,onLifecycle:i}={}){const r=Array.isArray(t)&&t.length>0,o=r&&JSON.stringify(e||[])===JSON.stringify(t);return r&&!o&&n?.(t),i?.({duplicate:o,hasIncoming:r}),o}
|
|
1
|
+
const e=(e,t,n,i,r=["claude","codex","hermes"])=>Object.freeze({name:e,description:t,route:n,...i?{inputHint:i}:{},runtimes:Object.freeze(r)});export const CODE_ROOM_COMMANDS=Object.freeze([e("/handoff","save a concise checkpoint or handoff","handoff","optional end goal"),e("/side","ask or investigate without interrupting this terminal","side","task"),e("/help","list commands available in this lane","control"),e("/status","runtime, model, permissions, and busy state","control"),e("/usage","session usage and provider limits","control"),e("/context","current context-window usage","control"),e("/diff","Git changes and branch status","control"),e("/find","find relevant files in this repository","control","query"),e("/compact","compact context","runtime"),e("/clear","clear context · confirms","clear"),e("/model","pick model — opens selector","model"),e("/mode","set permission mode","mode","normal | auto-accept | plan | bypass"),e("/effort","set reasoning effort","effort","low | medium | high | xhigh | max | ultra (eligible Codex terminals)"),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/lane-work-snapshot.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execFileSync as e}from"node:child_process";const t=/^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$/,
|
|
1
|
+
import{execFileSync as e}from"node:child_process";const t=/^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$/,n=/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/,r=new Set(["claude","codex","hermes"]),i=new Set(["default","acceptEdits","plan","review","bypassPermissions"]),o=new Set(["main","worker","side","flow-conductor","flow-builder","flow-reviewer","scheduled"]),a=new Set(["clean","dirty","unavailable"]),l=/(?:\r|\n|(?:^|[\\/])(?:Users|home|private|tmp|var|workspace)(?:[\\/]|$)|\.thinkpool[\\/]|(?:api[_-]?key|authorization|bearer|password|secret)\b)/i,u=1e5;function s(e){if("string"!=typeof e)return null;const n=e.trim();return t.test(n)?n:null}function d(e){if("string"!=typeof e)return null;const t=e.trim().toLowerCase();return n.test(t)?t:null}function c(e={}){return"conductor"===e.flowRole?"flow-conductor":"reviewer"===e.flowRole||"review"===e.sliceType?"flow-reviewer":e.flowSessionId||e.flowTaskKey||"builder"===e.flowRole?"flow-builder":e.scheduleRunId?"scheduled":e.sideParent?"side":e.spawnedBy?"worker":"main"}function f(e){return new Set(String(e||"").split("\0").filter(Boolean))}export function readLaneWorkGit(t,n=e,r=null){if("string"!=typeof t||!t.trim())return{worktreeState:"unavailable"};let i=null;try{i=d(n("git",["-C",t,"rev-parse","HEAD"],{encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]}))}catch{return{worktreeState:"unavailable"}}try{const e=n("git",["-C",t,"status","--porcelain=v1","--untracked-files=all"],{encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]}),o={...i?{headSha:i}:{},worktreeState:String(e||"").trim()?"dirty":"clean"},a="clean"===r?.worktreeState?d(r?.headSha):null;if(a){const e=function(e,t,n){try{const r=n("git",["-C",e,"diff","--name-only","-z","--no-renames",t,"--"],{encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]}),i=n("git",["-C",e,"ls-files","--others","--exclude-standard","-z"],{encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]}),o=f(r);for(const e of f(i))o.add(e);return Math.min(o.size,u)}catch{return null}}(t,a,n);null!==e&&(o.changedFileCount=e)}return o}catch{return{...i?{headSha:i}:{},worktreeState:"unavailable"}}}export function normalizeLaneWorkSnapshot(e){if(!e||"object"!=typeof e||Array.isArray(e)||![1,2].includes(e.version))return null;const t=s(e.terminalId),n=Number.isSafeInteger(e.turnRev)&&e.turnRev>0?e.turnRev:null,c="string"==typeof e.capturedAt&&Number.isFinite(Date.parse(e.capturedAt))?new Date(e.capturedAt).toISOString():null,f=e.identity,w=r.has(f?.runtime)?f.runtime:null,p=o.has(f?.laneRole)?f.laneRole:null,g=a.has(e.git?.worktreeState)?e.git.worktreeState:null;if(!(t&&n&&c&&w&&p&&g))return null;const m={runtime:w,laneRole:p},h=function(e,t=120){if("string"!=typeof e)return null;const n=e.replace(/\s+/g," ").trim();return!n||n.length>t||l.test(n)?null:n}(f.model),S=i.has(f.mode)?f.mode:null,y=s(f.parentTerminalId),k=s(f.flowId),v=s(f.flowTaskKey);h&&(m.model=h),S&&(m.mode=S),y&&(m.parentTerminalId=y),k&&(m.flowId=k),v&&(m.flowTaskKey=v);const b={worktreeState:g},I=d(e.git?.headSha),R=Number.isSafeInteger(e.git?.changedFileCount)&&e.git.changedFileCount>=0&&e.git.changedFileCount<=u?e.git.changedFileCount:null;return I&&(b.headSha=I),null!==R&&(b.changedFileCount=R),{version:e.version,terminalId:t,turnRev:n,capturedAt:c,identity:m,git:b}}export function buildLaneWorkSnapshot(t,{now:n=Date.now(),gitFacts:r}={}){const i=t?.sideParent||("string"!=typeof t?.spawnedBy||t.spawnedBy.startsWith("flow:")?null:t.spawnedBy),o={runtime:t?.runtime,model:t?.model,mode:t?.mode,laneRole:c(t),parentTerminalId:i,flowId:t?.flowSessionId,flowTaskKey:t?.flowTaskKey};return normalizeLaneWorkSnapshot({version:2,terminalId:t?.id,turnRev:Number(t?._turnRev),capturedAt:new Date(n).toISOString(),identity:o,git:r||readLaneWorkGit(t?.cwd,e,t?._turnGitStart)})}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thinkpool-pair",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.379",
|
|
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",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"hermes-isolation.mjs",
|
|
53
53
|
"hermes-delegation-guard.mjs",
|
|
54
54
|
"runtime-registry.mjs",
|
|
55
|
+
"reasoning-effort.mjs",
|
|
55
56
|
"runtime-contract.mjs",
|
|
56
57
|
"command-catalog.mjs",
|
|
57
58
|
"repo-search.mjs",
|
|
@@ -140,17 +141,17 @@
|
|
|
140
141
|
"node": ">=18"
|
|
141
142
|
},
|
|
142
143
|
"dependencies": {
|
|
143
|
-
"@agentclientprotocol/sdk": "1.
|
|
144
|
-
"@anthropic-ai/claude-agent-sdk": "^0.3.
|
|
145
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
146
|
-
"@supabase/supabase-js": "^2.
|
|
144
|
+
"@agentclientprotocol/sdk": "1.3.0",
|
|
145
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.220",
|
|
146
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
147
|
+
"@supabase/supabase-js": "^2.111.0",
|
|
147
148
|
"compromise": "14.16.0",
|
|
148
149
|
"yaml": "2.9.0",
|
|
149
150
|
"zod": "^4.4.3"
|
|
150
151
|
},
|
|
151
152
|
"optionalDependencies": {
|
|
152
153
|
"codebase-memory-mcp": "0.9.0",
|
|
153
|
-
"node-pty": "^1.2.0-beta.
|
|
154
|
+
"node-pty": "^1.2.0-beta.14"
|
|
154
155
|
},
|
|
155
156
|
"thinkpoolArtifact": {
|
|
156
157
|
"format": 1,
|
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.379",
|
|
5
5
|
"kind": "minified",
|
|
6
|
-
"minifiedModules":
|
|
7
|
-
"sourceModuleBytes":
|
|
8
|
-
"artifactModuleBytes":
|
|
6
|
+
"minifiedModules": 117,
|
|
7
|
+
"sourceModuleBytes": 1685595,
|
|
8
|
+
"artifactModuleBytes": 753815,
|
|
9
9
|
"files": {
|
|
10
|
-
"package.json": "
|
|
10
|
+
"package.json": "a6a7b78ab6b5edd954a0667d5cec6e46224212444b026f72200d48456956633c",
|
|
11
11
|
"LICENSE": "8a030197ca1cad9669909ca14c9ad15cf48d9fe551da526ccaf1fca993eddb23",
|
|
12
|
-
"bridge.mjs": "
|
|
12
|
+
"bridge.mjs": "b90f1294c63773f9233eeea5baf1a4bbf692aad509e9e91e1cfab036d43d42a4",
|
|
13
13
|
"bridge-service.sh": "b64f27c473ca8f3a49190fd08c23947ab14ca9958d70b6fa53c7bddc2be91403",
|
|
14
14
|
"command-guidance.mjs": "b9b967b59ff4e77c9613abb0f28858bf3ac5b106a509e471039777b53bec3e29",
|
|
15
15
|
"abort-turn-barrier.mjs": "3734a5b7e2e940ec6d7fa8b5b04935e1429a23d1bd9e92b2ac2a2ecd9f77c75e",
|
|
@@ -27,16 +27,16 @@
|
|
|
27
27
|
"claude-session.mjs": "a8e8d2db7dc350a53a5af3a7df1ee96cfa00a327c1e5b344d6aceda4d307600a",
|
|
28
28
|
"terminal-name.mjs": "f39bb8d1e148ab9a74cbb96438d31e524d6597b8035f00d7a906c28c306c0cf8",
|
|
29
29
|
"claude-command-catalog.mjs": "36bd4342b2ae94b43a0072533ef2d1648c7473003964bbad433fdb1a8b2bfec1",
|
|
30
|
-
"codex-session.mjs": "
|
|
30
|
+
"codex-session.mjs": "f7c4b1e74552fef8d86f4c09a077bce05480756ab67e40ac73a48559d1562a91",
|
|
31
31
|
"question-response.mjs": "35a7ba53d3eb117717c18004d2a8441f8f37665b231a3c44f4bd9321ff59dd57",
|
|
32
|
-
"thinkpool-room-prompt.mjs": "
|
|
32
|
+
"thinkpool-room-prompt.mjs": "1b156d349bda8df85b4bee7f4139ce820bce70ef7c6cd8614eaf04a10ab8e758",
|
|
33
33
|
"thinkpool-prompt-contracts.mjs": "051602d7d2fe9b34df92957bd3922c5eeebedbcc60c892adf415243887d8c62f",
|
|
34
|
-
"thinkpool-capabilities.json": "
|
|
35
|
-
"codex-app-server.mjs": "
|
|
34
|
+
"thinkpool-capabilities.json": "cb7b8d9a9c06f2d3eac67eb75f3d0bd361bc0b59032b613b3a48231b92c399c9",
|
|
35
|
+
"codex-app-server.mjs": "06778825aa3c51595d57cce733235cb07874986351b6fea7adac70ca33f32b11",
|
|
36
36
|
"codex-images.mjs": "31605d6d8b3dd6b73395da63d1b0c513445c95ffa2f4306ee466f201d633ffc0",
|
|
37
37
|
"codex-mcp-http.mjs": "7472543648a9bb575ce20dc3e3270c2da84174c6ea6e9faf87dfaafb95b6212a",
|
|
38
38
|
"lane-worktree.mjs": "37583757ab82843412ba565dfba3d7cab517e94782eb33115decd5438d092d8f",
|
|
39
|
-
"lane-work-snapshot.mjs": "
|
|
39
|
+
"lane-work-snapshot.mjs": "d3295638ddfa34c823fafa602675727544d337968c89f0e6d703ad6cfd2fda5a",
|
|
40
40
|
"codex-event-mapper.mjs": "7e7b878b24cb9208af517a195cc4089de87eda68086355f9e8e3b7e308825dee",
|
|
41
41
|
"edit-diff.mjs": "9a1bef6bb2d853d630ad38aba374cb2a120dd75b9aa08ab42ffc83cb0e1c57b6",
|
|
42
42
|
"cumulative-event-relay.mjs": "cf6e6533e33b3c5bb0b462d15ccc86106f2b56f8b1e66fc1f4867dd8f44d7ae6",
|
|
@@ -51,9 +51,10 @@
|
|
|
51
51
|
"hermes-setup.mjs": "1e903d0b9d3711669c06ff323323361920fe8827a7605311f74171f47eb6d602",
|
|
52
52
|
"hermes-isolation.mjs": "50e960ce815c520805245cc75719c9c53e2c5af51b7304c8ecef8a4946e23c6d",
|
|
53
53
|
"hermes-delegation-guard.mjs": "c2a6311320d2ff26137c4394c27561e5c8bee7a712bbb1188307bd55bfecc38e",
|
|
54
|
-
"runtime-registry.mjs": "
|
|
54
|
+
"runtime-registry.mjs": "d0a3d93edb60443df56273025ed3f10ed4b1d06a16b84759267782691cacdda8",
|
|
55
|
+
"reasoning-effort.mjs": "2d6855b6c67898d4c7104798ababc801018fea50070c42015d33d861fe6e818b",
|
|
55
56
|
"runtime-contract.mjs": "eb24b177002ba33353ec0335f4f830fb57fe313552b1a8d7aef8163cc743f6c1",
|
|
56
|
-
"command-catalog.mjs": "
|
|
57
|
+
"command-catalog.mjs": "4ef58a9d1ef33aad5054032e13432d4d0180b2045229838170c9c863c76d2f44",
|
|
57
58
|
"repo-search.mjs": "10cbce1d86655a7add0d7350ea8862a57165ccb02c2afa406348f4669050c304",
|
|
58
59
|
"project-intelligence.mjs": "b16108075648b331c84976cb63e267cf5835da7776ec7456b7642721225610a6",
|
|
59
60
|
"git-diff-report.mjs": "a428b3129c90e207a125a86c4485ec16c8ee7e81d432060a070e37172d85ce7a",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const STANDARD_REASONING_EFFORT_IDS=Object.freeze(["low","medium","high","xhigh","max"]);export const REASONING_EFFORT_META=Object.freeze([Object.freeze({id:"low",label:"Max speed",short:"Speed",hint:"lightest reasoning"}),Object.freeze({id:"medium",label:"Balanced",short:"Balanced",hint:"speed + depth"}),Object.freeze({id:"high",label:"Think hard",short:"High",hint:"deeper reasoning"}),Object.freeze({id:"xhigh",label:"Think harder",short:"XHigh",hint:"long-horizon work"}),Object.freeze({id:"max",label:"Max thinking",short:"Max",hint:"deepest single agent"}),Object.freeze({id:"ultra",label:"Ultra Cascade",short:"Ultra",hint:"max + visible lanes"})]);const e=/^[a-z][a-z0-9_-]{0,31}$/,n=new Map(REASONING_EFFORT_META.map(e=>[e.id,e])),o=n=>{const o=String(("string"==typeof n?n:n?.effort??n?.id??n?.value)||"").trim().toLowerCase();return e.test(o)?o:null};export function normalizeReasoningEffortList(e){const n=new Set,t=[];for(const r of Array.isArray(e)?e:[]){const e=o(r);e&&"none"!==e&&!n.has(e)&&(n.add(e),t.push(e))}return t}export function reasoningEffortMeta(e){const t=o(e)||"high",r=n.get(t);if(r)return r;const i=t.split(/[-_]/).filter(Boolean).map(e=>e[0].toUpperCase()+e.slice(1)).join(" ");return Object.freeze({id:t,label:i||t,short:i||t,hint:"model-supported reasoning"})}export function codexModelReasoningEfforts(e,n){const o=String(n||""),t=(Array.isArray(e)?e:[]).find(e=>(e=>String(e?.value??e?.id??e?.slug??e?.model??""))(e)===o),r=normalizeReasoningEffortList(t?.reasoningEfforts??t?.supportedReasoningLevels??t?.supported_reasoning_levels);return r.length?r:[...STANDARD_REASONING_EFFORT_IDS]}export function codexUltraLaneEligible(e={}){const n=Number.isInteger(e.spawnDepth)&&e.spawnDepth>=0?e.spawnDepth:e.spawnedBy||e.sideParent?1:0;return!(e.spawnedBy||e.sideParent||e.flowRole||e.flowSessionId||e.scheduleRunId||"review"===e.sliceType||"worker"===e.cascadeRole||0!==n)}export function codexReasoningEfforts({models:e=[],model:n=null,allowUltraCascade:o=!1}={}){return codexModelReasoningEfforts(e,n).filter(e=>"ultra"!==e||o)}export function reasoningEffortsForLane(e,n={}){return"codex"!==e?[...STANDARD_REASONING_EFFORT_IDS]:codexReasoningEfforts({models:n.models,model:n.model,allowUltraCascade:codexUltraLaneEligible(n)})}export function normalizeCodexReasoningEffort(e,n={}){const t=codexReasoningEfforts(n),r=o(e);return r&&t.includes(r)?r:"ultra"===r&&t.includes("max")?"max":t.includes("high")?"high":t[0]||"high"}export function normalizeStructuredEffort(e,n,t={}){if(null===n)return null;if("hermes"===e&&"none"===n)return"none";if("codex"===e)return normalizeCodexReasoningEffort(n,{models:t.models,model:t.model,allowUltraCascade:codexUltraLaneEligible(t)});const r=o(n);return r&&STANDARD_REASONING_EFFORT_IDS.includes(r)?r:"high"}export function codexNativeReasoningEffort(e){const n=o(e);return n?"ultra"===n?"max":n:null}
|
package/runtime-registry.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"node:path";import{runtimeCapability as t,runtimeSupportsCapability as o}from"./runtime-contract.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};
|
|
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:s,models:d}={})=>{const a=structuredRuntimeMetadata(e);return!(!(!a?.catalogRequiresSession||Array.isArray(d)&&d.length)||!t&&(o||r||s))};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"bundleVersion":
|
|
3
|
+
"bundleVersion": 28,
|
|
4
4
|
"contracts": [
|
|
5
5
|
{
|
|
6
6
|
"id": "room-coordination",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
70
|
"id": "work-routing",
|
|
71
|
-
"version":
|
|
71
|
+
"version": 9,
|
|
72
72
|
"providerRoutingContract": "A Claude lane may select a connected Anthropic-compatible provider by durable id, unique display name, or unique configured model. Unknown or ambiguous references fail closed and must never fall through to built-in Claude.",
|
|
73
73
|
"openerParityContract": "Every top-level terminal may use spawn_terminal or open_main_terminal to open every supported structured runtime: Claude, Codex, or Hermes. Runtime-specific provider/model validation remains authoritative and occurs before inference.",
|
|
74
74
|
"routes": [
|
|
@@ -80,16 +80,19 @@
|
|
|
80
80
|
}
|
|
81
81
|
],
|
|
82
82
|
"expandedPrompt": "MAIN TERMINAL ROUTING (authoritative): a person-authored request to open, launch, start, spawn, or create a new, separate, independent, top-level, or main terminal uses open_main_terminal, even for ordinary work or a handoff and even when they do not say Cascade or conductor. If the wording includes new or separate terminal, main-terminal routing wins. spawn_terminal is only for agent-decided bounded worker slices or when the person explicitly asks for a worker, sub-terminal, Ensemble lane, or delegated slice. CASCADE WORKFLOW (default for non-trivial work that genuinely decomposes; mandatory when the people ask for Cascade, tiered lanes, one-shot flow, or unattended multi-slice execution): first investigate enough to name evidence-backed slices and their dependencies, then post a short plan in the room. The current top-level/conductor terminal keeps decomposition, integration, and final judgment; use spawn_terminal only for bounded worker slices. Parallelize only disjoint slices and encode dependencies instead of holding them in your head. Choose sliceType=scaffold for mechanical/search work, feature or fix for implementation, and review with a balanced capable tier for adversarial verification. Review slices are structurally read-only: they resolve to a native review/Plan mode before launch and can never inherit autonomous bypass authority. Every worker brief names the evidence/diagnosis, exact scope, observable acceptance proof, relevant repo gates, whether merge/publish is required, and a safe-skip escape hatch. ROOM NOW is the default roster and completion signals wake the conductor; do not spend the bounded read allowance polling or repeating a no-argument roster. After dispatch, remain responsible: once an owned worker is finished, make one targeted read_terminal call to collect its result, verify its claim, close_terminal immediately, and dispatch newly unblocked work. Preserve enough targeted reads for every open worker and the final adversarial review; never declare the Cascade done or yield a final result while owned workers remain uncollected. Check origin/main CI before merge-bearing waves, coordinate shared fixtures/publishers, and treat sibling pushes as context rather than proof. Run an adversarial review after builders (or pipeline review behind completed phases), finish with production-condition evidence, verify every reported SHA/version, and close every worker you opened.",
|
|
83
|
+
"codexUltraPrompt": "CODEX ULTRA IN thinkpool: Ultra means maximum Codex reasoning plus proactive thinkpool Cascade. When the current request genuinely decomposes, investigate first, post a short plan, and dispatch bounded work through visible spawn_terminal Ensemble lanes. Use the room’s tiered worker models, collect each finished worker once with read_terminal, close it immediately, and finish with adversarial verification. When the work does not meaningfully decompose, stay in this terminal at maximum reasoning. Never use built-in or hidden subagent delegation; thinkpool owns worker visibility, limits, permissions, and lifecycle.",
|
|
83
84
|
"impact": [
|
|
84
85
|
{"path": "bridge/bridge.mjs", "diffPattern": "spawn_terminal|open_main_terminal|close_terminal|cascadeRole|spawnDepth"},
|
|
85
86
|
{"path": "bridge/lane-lifecycle.mjs"},
|
|
86
87
|
{"path": "bridge/lane-worktree.mjs"},
|
|
87
|
-
{"path": "bridge/flow-conductor.mjs"}
|
|
88
|
+
{"path": "bridge/flow-conductor.mjs"},
|
|
89
|
+
{"path": "bridge/codex-session.mjs", "diffPattern": "CODEX_ULTRA|ultraCascade|THINKPOOL_CODEX_ULTRA"}
|
|
88
90
|
],
|
|
89
91
|
"evidence": [
|
|
90
92
|
{"path": "bridge/bridge.mjs", "pattern": "'spawn_terminal'"},
|
|
91
93
|
{"path": "bridge/bridge.mjs", "pattern": "'open_main_terminal'"},
|
|
92
|
-
{"path": "bridge/bridge.mjs", "pattern": "'close_terminal'"}
|
|
94
|
+
{"path": "bridge/bridge.mjs", "pattern": "'close_terminal'"},
|
|
95
|
+
{"path": "bridge/codex-session.mjs", "pattern": "THINKPOOL_CODEX_ULTRA_RULE"}
|
|
93
96
|
]
|
|
94
97
|
},
|
|
95
98
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{THINKPOOL_CAPABILITY_ROUTES as e,THINKPOOL_PROMPT_BUNDLE as t,thinkPoolCapabilityContract as o}from"./thinkpool-prompt-contracts.mjs";import{buildContextManifest as a,formatRoomContextProjection as r}from"./context-contract.mjs";export{e as THINKPOOL_CAPABILITY_ROUTES,t as THINKPOOL_PROMPT_BUNDLE};export const THINKPOOL_ROUTED_TOOLS=Object.freeze([...new Set(e.flatMap(e=>e.tools))]);export function renderThinkPoolCapabilityRoutes(t=e){return t.map(e=>`${e.id}: ${e.rule}`).join(" ")}export const THINKPOOL_RUNTIME_AUTHORITY_RULE=o("runtime-authority").globalPrompt;export const THINKPOOL_TURN_SCOPE_RULE=o("turn-scope-authority").globalPrompt;export const THINKPOOL_CASCADE_RULE=o("work-routing").expandedPrompt;export const THINKPOOL_AGENT_CONTRACT=[THINKPOOL_TURN_SCOPE_RULE,"thinkpool-FIRST OPERATING CONTRACT (authoritative): thinkpool room capabilities are your normal operating surface, not optional enrichment. Before acting on every request, infer which exposed thinkpool capabilities materially improve room visibility, coordination, delivery, or verification and use them without waiting for the people to know a tool name, magic word, or workflow.",THINKPOOL_RUNTIME_AUTHORITY_RULE,`DEFAULT ROUTING: ${renderThinkPoolCapabilityRoutes()}`,THINKPOOL_CASCADE_RULE,"DEFAULT DOES NOT MEAN GRATUITOUS: use only capabilities exposed to your current role and only when relevant. Honor explicit steering such as single-lane, do not contact another room, or do not use a named thinkpool feature. Metered and side-effecting capabilities still obey their stated offer, approval, and consent contracts."].join(" ");export const THINKPOOL_DESIGN_INTERACTION_RULE=o("design-workspace").interactionPrompt;export const THINKPOOL_DESIGN_DELIVERY_RULE=`thinkpool DESIGN (mandatory for authored HTML): save the editable HTML source in the workspace, then use the $TP_MOCKUP_OUTBOX render helper so the room receives a source-backed thinkpool Design card with both desktop (1440×900) and mobile (390×844) previews. The interactive Design card/popup is the visible result: the renders remain required verification inputs, but when that card is displayed do not also surface duplicate inline PNGs. Surface desktop/mobile PNGs only when no interactive source-backed Design artifact is available. ${THINKPOOL_DESIGN_INTERACTION_RULE} When the requested Design surface is an existing product page or route, first build and capture the actual route at both viewports, then read its current source, styles, copy, fonts, and assets. Derive the editable Design artifact from that evidence and compare both artifact captures against the real route before delivery. Preserve the real page faithfully except for explicitly proposed edits—never hand-recreate it from memory, simplify it, replace it with generic mockup content, or label an approximation as the product. If a faithful editable artifact cannot be produced, surface the actual route captures and say that Design editing is unavailable for that surface. Never paste raw HTML into chat, send an .html file as the room deliverable, or substitute a bare URL or single screenshot for this card. A shareable browser URL may accompany the card, but never replaces it.`;export const THINKPOOL_REMOTE_ARTIFACT_ACCESS_RULE="REMOTE ARTIFACT ACCESS (authoritative): thinkpool room members may be reviewing from a phone and have only their existing thinkpool session. Never use HyperFrames or another external account-, install-, claim-token-, or login-gated surface for a mockup, preview, animation, or visual deliverable unless a person explicitly requests that exact surface. Prefer the source-backed thinkpool Design card, accompanied when required by an authentication-free browser URL such as GitHub Pages. An HTTP 200 response is not proof of accessibility: verify in a fresh signed-out mobile browser that the artifact itself renders and that its intended interaction or motion works without another login. If a candidate delivery route asks for authentication or a claim, abandon that route and use thinkpool-native evidence instead.";export const THINKPOOL_REMOTE_DELIVERY_RULES=Object.freeze(['REMOTE USER (authoritative default for thinkpool Code rooms): unless a person explicitly says they are at the host machine, assume everyone driving this room is remote — possibly on a phone — with no terminal and no access to the host filesystem. Never ask them to run a local command, open a local file, or "go check" something on the machine. Anything host-side, you run yourself and show the result in the room. Only suggest actions they can actually do from the room UI or a browser.',"LINKS & ARTIFACTS: a local filesystem path, file:// URL, localhost/127.0.0.1 address, or host-only preview is useless to a remote room. Every link you surface must be reachable by the people in the room.",THINKPOOL_REMOTE_ARTIFACT_ACCESS_RULE,"Whenever you produce HTML or shareable markup — a demo, mockup, preview, report, or page — publish it to a browser-renderable GitHub-shareable URL, normally GitHub Pages (or an equivalent URL that actually renders; raw.githubusercontent.com serves HTML as plain text). Give the room that shareable URL in addition to the thinkpool Design card, never instead of it and never only as a local path. If you cannot publish it, say so instead of falling back to a host-only path.","SHOW VISUAL WORK: whenever you build, change, or fix anything visual, show the result in the room. A source-backed thinkpool Design card/popup is already the interactive visible result, so do not additionally surface duplicate PNGs. When no interactive Design artifact is available, capture and surface desktop/mobile PNG evidence inline.","BRIDGE PREVIEWS: for a built web UI, use preview_start (default root: dist), then preview_capture for exact desktop 1440x900 and mobile 390x844 PNGs, and preview_inspect when DOM text or selector geometry helps. Run the project build first and stop the preview server with preview_stop when done. Captures are verification evidence by default; set card=true only for an intentional user-facing mockup or Design deliverable, never merely because a turn changed visual code.",THINKPOOL_DESIGN_DELIVERY_RULE,"VERIFY BEFORE CLAIMING: run or serve what you changed, observe it, and show the evidence in the room — the PNG, passing test output, or real response. If something could not be verified, say exactly what remains unverified."]);export const THINKPOOL_RUNTIME_TURN_REMINDER=[THINKPOOL_AGENT_CONTRACT,"REMOTE DELIVERY: assume the people are remote unless they explicitly say otherwise. Run host-side work yourself; never hand them a local path, file:// or localhost URL, or ask them to use the host terminal. Surface reachable links and inline evidence in the room.",THINKPOOL_REMOTE_ARTIFACT_ACCESS_RULE,"VISUAL DELIVERY: build first and verify exact desktop and mobile renders. If a source-backed thinkpool Design card/popup is displayed, do not separately surface its PNGs; if no interactive Design artifact is available, surface the desktop/mobile PNG evidence inline. Stop bridge previews when finished.",THINKPOOL_DESIGN_INTERACTION_RULE,"VERIFY BEFORE CLAIMING: run or serve what changed and show the real response, passing output, or rendered evidence; state exactly what remains unverified."].join(" ");export const THINKPOOL_RUNTIME_SALIENCE_REMINDER=[THINKPOOL_TURN_SCOPE_RULE,"thinkpool: use relevant room tools within role and consent limits; run host work for remote people and return reachable, verified results.","Visual artifacts stay thinkpool-native or authentication-free unless explicitly requested otherwise."].join(" ");const n=Object.freeze(Object.fromEntries(e.map(e=>[e.id,new RegExp(e.trigger,"i")]))),i=o("design-workspace").turnReminder;export function usesFullThinkPoolReminder({promptIndex:e=0,forceFull:t=!1}={}){const o=Math.max(0,Number.isFinite(Number(e))?Math.trunc(Number(e)):0);return!!t||0===o}export function buildThinkPoolTurnGuidance({text:t="",promptIndex:o=0,forceFull:a=!1}={}){if(usesFullThinkPoolReminder({promptIndex:o,forceFull:a}))return THINKPOOL_RUNTIME_TURN_REMINDER;const r=String(t||""),s=e.filter(e=>n[e.id]?.test(r)).map(e=>`${e.id}: ${e.rule}`);return n["work-routing"].test(r)&&s.push(THINKPOOL_CASCADE_RULE),n["visual-proof"].test(r)&&s.push(i),[THINKPOOL_RUNTIME_SALIENCE_REMINDER,...s].join(" ")}export function roomContextFingerprint(e){return String(e||"").replace(/ · (?:\d+[smhd] ago|no activity)(?=\s+—)/g," · age").trim()}export function createRoomContextSelector(e){let t=null;return({force:o=!1}={})=>{let a=null;try{a="function"==typeof e?e():e}catch{a=null}const n=r(a);if(!n)return"";const i=roomContextFingerprint(n),s=i!==t;return t=i,o||s?n:""}}export function buildThinkPoolContextManifest({currentUserTurn:e="",roomNow:o="",flowSliceDigest:n=null,approvedHumanResponse:i=null}={}){const s=r(o);return a({promptBundle:t,sources:[{kind:"current_user_turn",value:e},{kind:"room_now_delta",value:s},...n?[{kind:"flow_slice_digest",value:n,ref:{type:"flow_digest",id:"local"}}]:[],...i?[{kind:"approved_human_response",value:i,ref:{type:"control_item",id:"approved"}}]:[]]})}export function buildTerminalRolePrompt({spawnedBy:e=null,spawnDepth:t=0,cascadeRole:o=null,flowRole:a=null,sideParent:r=null}={}){const n=Math.max(0,Number.isFinite(Number(t))?Math.trunc(Number(t)):0),i=String(r||e||"").slice(0,8);return"conductor"===a?"TERMINAL ROLE (authoritative): You are a system-managed thinkpool FLOW CONDUCTOR. You are not a human-opened top-level terminal and not a worker sub-terminal. Your role is decomposition and Flow coordination only; the Flow runtime dispatches its managed lanes. Do not use ordinary spawn_terminal delegation or claim to be an independent room terminal. Follow the stricter Flow conductor role prompt below.":"builder"===a||"reviewer"===a?`TERMINAL ROLE (authoritative): You are a system-managed thinkpool FLOW ${a.toUpperCase()} LANE. You are a leaf worker/reviewer, not a top-level terminal and not a conductor. Complete only the assigned Flow slice, do not spawn terminals, and finish through the Flow completion contract in your role prompt.`:r?`TERMINAL ROLE (authoritative): You are a SIDE SUB-TERMINAL attached to main terminal ${i}. You are not an independent top-level terminal and not a Cascade conductor. Complete the bounded side task directly, do not fan out more terminals, and return a compact handoff to main.`:"conductor"===o?e||0!==n?`TERMINAL ROLE (authoritative): You are a MISCLASSIFIED ENSEMBLE SUB-TERMINAL at spawn depth ${Math.max(1,n)}, owned by parent terminal ${i}. A spawned lane can never be a Cascade conductor. Work directly as a worker, do not spawn terminals, and report that the parent must use open_main_terminal for a separate conductor.`:"TERMINAL ROLE (authoritative): You are an independent MAIN CASCADE CONDUCTOR TERMINAL opened through the room's top-level terminal lifecycle. You are not an Ensemble child, spawned sub-terminal, Side lane, or Flow lane. Keep decomposition and integration here. Open only worker SUB-TERMINALS with spawn_terminal, collect and verify their results, and close them. Never call open_main_terminal yourself or delegate conductor responsibility to a worker.":e||0!==n?n>=2?`TERMINAL ROLE (authoritative): You are a LEAF SUB-TERMINAL at spawn depth ${n}, owned by parent terminal ${i}. You are not top-level and not a conductor. Complete the assigned slice directly, do not spawn another terminal, and hand evidence/results back to your parent.`:"worker"===o?`TERMINAL ROLE (authoritative): You are a WORKER SUB-TERMINAL at spawn depth ${Math.max(1,n)}, owned by parent terminal ${i}. You are not top-level and not a conductor. Complete the assigned slice directly, do not spawn another terminal, and hand evidence/results back to your parent.`:`TERMINAL ROLE (authoritative): You are a SPAWNED WORKER SUB-TERMINAL at depth ${Math.max(1,n)}, owned by parent terminal ${i}. You are not an independent top-level terminal or a Cascade conductor. Complete the delegated task directly, do not spawn another terminal, and hand evidence/results back to your parent. If the task asks you to conduct, report that the parent must use open_main_terminal instead.`:"TERMINAL ROLE (authoritative): You are an independent TOP-LEVEL thinkpool terminal opened directly in the room. You are not a spawned sub-terminal or worker lane. You may conduct the current task here and open worker SUB-TERMINALS with spawn_terminal. A person-authored request to open, launch, start, spawn, or create a new, separate, independent, top-level, or main terminal uses open_main_terminal — never spawn_terminal — even for ordinary work or a handoff. If the wording includes new or separate terminal, main-terminal routing wins. Use spawn_terminal only for agent-decided bounded worker slices or when the person explicitly asks for a worker, sub-terminal, Ensemble lane, or delegated slice."}export const CODEX_THINKPOOL_FIRST_TURN_PREAMBLE=["ENVIRONMENT (authoritative): You are Codex running inside a thinkpool Code room, driven live through the thinkpool-pair bridge by a user and possibly a partner. This is a shared remote workspace, not an ordinary local terminal session; act accordingly.","MODEL TIERING FOR TERMINALS: When calling open_main_terminal for a genuinely complex Cascade conductor, gpt-5.6-sol may be appropriate. When calling spawn_terminal for worker slices, explicitly choose gpt-5.6-luna or gpt-5.4-mini for mechanical/scaffold/search/formatting work, gpt-5.6-terra for ordinary feature/fix work, and a balanced tier for adversarial review. Never select Sol for routine workers. If a named model is unavailable, use the nearest advertised lower tier or omit model and allow runtime fallback.",...THINKPOOL_REMOTE_DELIVERY_RULES].join(" ");export const HERMES_VISIBLE_WORKER_FALLBACK_RULE='UNIVERSAL OPENER ROUTING: a top-level terminal of any runtime may use spawn_terminal or open_main_terminal to open Claude (including a connected Anthropic-compatible BYOK provider), Codex, or Hermes. For Hermes, omit model to use the isolated profile default or pass an ACP ID such as model="nous:z-ai/glm-5.2"; common GLM shorthand is normalized and the child acknowledges the selected model before inference. If a native Claude Code worker reports an account/provider authentication or subscription-access failure, treat the entire native Claude provider as unavailable for the rest of the task—do not retry Sonnet, Opus, or Haiku aliases on it. For a manual Claude-family review fallback, use runtime="hermes", the exact Nous Claude model suggested by read_terminal, mode="default", and sliceType="review". This fallback is permission-gated, not structurally read-only: instruct it not to edit, stop/deny any write request, and never call it Flow/reviewer safety. Never use hidden Hermes delegate_task.';
|
|
1
|
+
import{THINKPOOL_CAPABILITY_ROUTES as e,THINKPOOL_PROMPT_BUNDLE as t,thinkPoolCapabilityContract as o}from"./thinkpool-prompt-contracts.mjs";import{buildContextManifest as r,formatRoomContextProjection as a}from"./context-contract.mjs";export{e as THINKPOOL_CAPABILITY_ROUTES,t as THINKPOOL_PROMPT_BUNDLE};export const THINKPOOL_ROUTED_TOOLS=Object.freeze([...new Set(e.flatMap(e=>e.tools))]);export function renderThinkPoolCapabilityRoutes(t=e){return t.map(e=>`${e.id}: ${e.rule}`).join(" ")}export const THINKPOOL_RUNTIME_AUTHORITY_RULE=o("runtime-authority").globalPrompt;export const THINKPOOL_TURN_SCOPE_RULE=o("turn-scope-authority").globalPrompt;export const THINKPOOL_CASCADE_RULE=o("work-routing").expandedPrompt;export const THINKPOOL_CODEX_ULTRA_RULE=o("work-routing").codexUltraPrompt;export const THINKPOOL_AGENT_CONTRACT=[THINKPOOL_TURN_SCOPE_RULE,"thinkpool-FIRST OPERATING CONTRACT (authoritative): thinkpool room capabilities are your normal operating surface, not optional enrichment. Before acting on every request, infer which exposed thinkpool capabilities materially improve room visibility, coordination, delivery, or verification and use them without waiting for the people to know a tool name, magic word, or workflow.",THINKPOOL_RUNTIME_AUTHORITY_RULE,`DEFAULT ROUTING: ${renderThinkPoolCapabilityRoutes()}`,THINKPOOL_CASCADE_RULE,"DEFAULT DOES NOT MEAN GRATUITOUS: use only capabilities exposed to your current role and only when relevant. Honor explicit steering such as single-lane, do not contact another room, or do not use a named thinkpool feature. Metered and side-effecting capabilities still obey their stated offer, approval, and consent contracts."].join(" ");export const THINKPOOL_DESIGN_INTERACTION_RULE=o("design-workspace").interactionPrompt;export const THINKPOOL_DESIGN_DELIVERY_RULE=`thinkpool DESIGN (mandatory for authored HTML): save the editable HTML source in the workspace, then use the $TP_MOCKUP_OUTBOX render helper so the room receives a source-backed thinkpool Design card with both desktop (1440×900) and mobile (390×844) previews. The interactive Design card/popup is the visible result: the renders remain required verification inputs, but when that card is displayed do not also surface duplicate inline PNGs. Surface desktop/mobile PNGs only when no interactive source-backed Design artifact is available. ${THINKPOOL_DESIGN_INTERACTION_RULE} When the requested Design surface is an existing product page or route, first build and capture the actual route at both viewports, then read its current source, styles, copy, fonts, and assets. Derive the editable Design artifact from that evidence and compare both artifact captures against the real route before delivery. Preserve the real page faithfully except for explicitly proposed edits—never hand-recreate it from memory, simplify it, replace it with generic mockup content, or label an approximation as the product. If a faithful editable artifact cannot be produced, surface the actual route captures and say that Design editing is unavailable for that surface. Never paste raw HTML into chat, send an .html file as the room deliverable, or substitute a bare URL or single screenshot for this card. A shareable browser URL may accompany the card, but never replaces it.`;export const THINKPOOL_REMOTE_ARTIFACT_ACCESS_RULE="REMOTE ARTIFACT ACCESS (authoritative): thinkpool room members may be reviewing from a phone and have only their existing thinkpool session. Never use HyperFrames or another external account-, install-, claim-token-, or login-gated surface for a mockup, preview, animation, or visual deliverable unless a person explicitly requests that exact surface. Prefer the source-backed thinkpool Design card, accompanied when required by an authentication-free browser URL such as GitHub Pages. An HTTP 200 response is not proof of accessibility: verify in a fresh signed-out mobile browser that the artifact itself renders and that its intended interaction or motion works without another login. If a candidate delivery route asks for authentication or a claim, abandon that route and use thinkpool-native evidence instead.";export const THINKPOOL_REMOTE_DELIVERY_RULES=Object.freeze(['REMOTE USER (authoritative default for thinkpool Code rooms): unless a person explicitly says they are at the host machine, assume everyone driving this room is remote — possibly on a phone — with no terminal and no access to the host filesystem. Never ask them to run a local command, open a local file, or "go check" something on the machine. Anything host-side, you run yourself and show the result in the room. Only suggest actions they can actually do from the room UI or a browser.',"LINKS & ARTIFACTS: a local filesystem path, file:// URL, localhost/127.0.0.1 address, or host-only preview is useless to a remote room. Every link you surface must be reachable by the people in the room.",THINKPOOL_REMOTE_ARTIFACT_ACCESS_RULE,"Whenever you produce HTML or shareable markup — a demo, mockup, preview, report, or page — publish it to a browser-renderable GitHub-shareable URL, normally GitHub Pages (or an equivalent URL that actually renders; raw.githubusercontent.com serves HTML as plain text). Give the room that shareable URL in addition to the thinkpool Design card, never instead of it and never only as a local path. If you cannot publish it, say so instead of falling back to a host-only path.","SHOW VISUAL WORK: whenever you build, change, or fix anything visual, show the result in the room. A source-backed thinkpool Design card/popup is already the interactive visible result, so do not additionally surface duplicate PNGs. When no interactive Design artifact is available, capture and surface desktop/mobile PNG evidence inline.","BRIDGE PREVIEWS: for a built web UI, use preview_start (default root: dist), then preview_capture for exact desktop 1440x900 and mobile 390x844 PNGs, and preview_inspect when DOM text or selector geometry helps. Run the project build first and stop the preview server with preview_stop when done. Captures are verification evidence by default; set card=true only for an intentional user-facing mockup or Design deliverable, never merely because a turn changed visual code.",THINKPOOL_DESIGN_DELIVERY_RULE,"VERIFY BEFORE CLAIMING: run or serve what you changed, observe it, and show the evidence in the room — the PNG, passing test output, or real response. If something could not be verified, say exactly what remains unverified."]);export const THINKPOOL_RUNTIME_TURN_REMINDER=[THINKPOOL_AGENT_CONTRACT,"REMOTE DELIVERY: assume the people are remote unless they explicitly say otherwise. Run host-side work yourself; never hand them a local path, file:// or localhost URL, or ask them to use the host terminal. Surface reachable links and inline evidence in the room.",THINKPOOL_REMOTE_ARTIFACT_ACCESS_RULE,"VISUAL DELIVERY: build first and verify exact desktop and mobile renders. If a source-backed thinkpool Design card/popup is displayed, do not separately surface its PNGs; if no interactive Design artifact is available, surface the desktop/mobile PNG evidence inline. Stop bridge previews when finished.",THINKPOOL_DESIGN_INTERACTION_RULE,"VERIFY BEFORE CLAIMING: run or serve what changed and show the real response, passing output, or rendered evidence; state exactly what remains unverified."].join(" ");export const THINKPOOL_RUNTIME_SALIENCE_REMINDER=[THINKPOOL_TURN_SCOPE_RULE,"thinkpool: use relevant room tools within role and consent limits; run host work for remote people and return reachable, verified results.","Visual artifacts stay thinkpool-native or authentication-free unless explicitly requested otherwise."].join(" ");const n=Object.freeze(Object.fromEntries(e.map(e=>[e.id,new RegExp(e.trigger,"i")]))),i=o("design-workspace").turnReminder;export function usesFullThinkPoolReminder({promptIndex:e=0,forceFull:t=!1}={}){const o=Math.max(0,Number.isFinite(Number(e))?Math.trunc(Number(e)):0);return!!t||0===o}export function buildThinkPoolTurnGuidance({text:t="",promptIndex:o=0,forceFull:r=!1}={}){if(usesFullThinkPoolReminder({promptIndex:o,forceFull:r}))return THINKPOOL_RUNTIME_TURN_REMINDER;const a=String(t||""),s=e.filter(e=>n[e.id]?.test(a)).map(e=>`${e.id}: ${e.rule}`);return n["work-routing"].test(a)&&s.push(THINKPOOL_CASCADE_RULE),n["visual-proof"].test(a)&&s.push(i),[THINKPOOL_RUNTIME_SALIENCE_REMINDER,...s].join(" ")}export function roomContextFingerprint(e){return String(e||"").replace(/ · (?:\d+[smhd] ago|no activity)(?=\s+—)/g," · age").trim()}export function createRoomContextSelector(e){let t=null;return({force:o=!1}={})=>{let r=null;try{r="function"==typeof e?e():e}catch{r=null}const n=a(r);if(!n)return"";const i=roomContextFingerprint(n),s=i!==t;return t=i,o||s?n:""}}export function buildThinkPoolContextManifest({currentUserTurn:e="",roomNow:o="",flowSliceDigest:n=null,approvedHumanResponse:i=null}={}){const s=a(o);return r({promptBundle:t,sources:[{kind:"current_user_turn",value:e},{kind:"room_now_delta",value:s},...n?[{kind:"flow_slice_digest",value:n,ref:{type:"flow_digest",id:"local"}}]:[],...i?[{kind:"approved_human_response",value:i,ref:{type:"control_item",id:"approved"}}]:[]]})}export function buildTerminalRolePrompt({spawnedBy:e=null,spawnDepth:t=0,cascadeRole:o=null,flowRole:r=null,sideParent:a=null}={}){const n=Math.max(0,Number.isFinite(Number(t))?Math.trunc(Number(t)):0),i=String(a||e||"").slice(0,8);return"conductor"===r?"TERMINAL ROLE (authoritative): You are a system-managed thinkpool FLOW CONDUCTOR. You are not a human-opened top-level terminal and not a worker sub-terminal. Your role is decomposition and Flow coordination only; the Flow runtime dispatches its managed lanes. Do not use ordinary spawn_terminal delegation or claim to be an independent room terminal. Follow the stricter Flow conductor role prompt below.":"builder"===r||"reviewer"===r?`TERMINAL ROLE (authoritative): You are a system-managed thinkpool FLOW ${r.toUpperCase()} LANE. You are a leaf worker/reviewer, not a top-level terminal and not a conductor. Complete only the assigned Flow slice, do not spawn terminals, and finish through the Flow completion contract in your role prompt.`:a?`TERMINAL ROLE (authoritative): You are a SIDE SUB-TERMINAL attached to main terminal ${i}. You are not an independent top-level terminal and not a Cascade conductor. Complete the bounded side task directly, do not fan out more terminals, and return a compact handoff to main.`:"conductor"===o?e||0!==n?`TERMINAL ROLE (authoritative): You are a MISCLASSIFIED ENSEMBLE SUB-TERMINAL at spawn depth ${Math.max(1,n)}, owned by parent terminal ${i}. A spawned lane can never be a Cascade conductor. Work directly as a worker, do not spawn terminals, and report that the parent must use open_main_terminal for a separate conductor.`:"TERMINAL ROLE (authoritative): You are an independent MAIN CASCADE CONDUCTOR TERMINAL opened through the room's top-level terminal lifecycle. You are not an Ensemble child, spawned sub-terminal, Side lane, or Flow lane. Keep decomposition and integration here. Open only worker SUB-TERMINALS with spawn_terminal, collect and verify their results, and close them. Never call open_main_terminal yourself or delegate conductor responsibility to a worker.":e||0!==n?n>=2?`TERMINAL ROLE (authoritative): You are a LEAF SUB-TERMINAL at spawn depth ${n}, owned by parent terminal ${i}. You are not top-level and not a conductor. Complete the assigned slice directly, do not spawn another terminal, and hand evidence/results back to your parent.`:"worker"===o?`TERMINAL ROLE (authoritative): You are a WORKER SUB-TERMINAL at spawn depth ${Math.max(1,n)}, owned by parent terminal ${i}. You are not top-level and not a conductor. Complete the assigned slice directly, do not spawn another terminal, and hand evidence/results back to your parent.`:`TERMINAL ROLE (authoritative): You are a SPAWNED WORKER SUB-TERMINAL at depth ${Math.max(1,n)}, owned by parent terminal ${i}. You are not an independent top-level terminal or a Cascade conductor. Complete the delegated task directly, do not spawn another terminal, and hand evidence/results back to your parent. If the task asks you to conduct, report that the parent must use open_main_terminal instead.`:"TERMINAL ROLE (authoritative): You are an independent TOP-LEVEL thinkpool terminal opened directly in the room. You are not a spawned sub-terminal or worker lane. You may conduct the current task here and open worker SUB-TERMINALS with spawn_terminal. A person-authored request to open, launch, start, spawn, or create a new, separate, independent, top-level, or main terminal uses open_main_terminal — never spawn_terminal — even for ordinary work or a handoff. If the wording includes new or separate terminal, main-terminal routing wins. Use spawn_terminal only for agent-decided bounded worker slices or when the person explicitly asks for a worker, sub-terminal, Ensemble lane, or delegated slice."}export const CODEX_THINKPOOL_FIRST_TURN_PREAMBLE=["ENVIRONMENT (authoritative): You are Codex running inside a thinkpool Code room, driven live through the thinkpool-pair bridge by a user and possibly a partner. This is a shared remote workspace, not an ordinary local terminal session; act accordingly.","MODEL TIERING FOR TERMINALS: When calling open_main_terminal for a genuinely complex Cascade conductor, gpt-5.6-sol may be appropriate. When calling spawn_terminal for worker slices, explicitly choose gpt-5.6-luna or gpt-5.4-mini for mechanical/scaffold/search/formatting work, gpt-5.6-terra for ordinary feature/fix work, and a balanced tier for adversarial review. Never select Sol for routine workers. If a named model is unavailable, use the nearest advertised lower tier or omit model and allow runtime fallback.",...THINKPOOL_REMOTE_DELIVERY_RULES].join(" ");export const HERMES_VISIBLE_WORKER_FALLBACK_RULE='UNIVERSAL OPENER ROUTING: a top-level terminal of any runtime may use spawn_terminal or open_main_terminal to open Claude (including a connected Anthropic-compatible BYOK provider), Codex, or Hermes. For Hermes, omit model to use the isolated profile default or pass an ACP ID such as model="nous:z-ai/glm-5.2"; common GLM shorthand is normalized and the child acknowledges the selected model before inference. If a native Claude Code worker reports an account/provider authentication or subscription-access failure, treat the entire native Claude provider as unavailable for the rest of the task—do not retry Sonnet, Opus, or Haiku aliases on it. For a manual Claude-family review fallback, use runtime="hermes", the exact Nous Claude model suggested by read_terminal, mode="default", and sliceType="review". This fallback is permission-gated, not structurally read-only: instruct it not to edit, stop/deny any write request, and never call it Flow/reviewer safety. Never use hidden Hermes delegate_task.';
|