ideawave 0.0.48 → 0.0.49

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.
Files changed (2) hide show
  1. package/dist/index.mjs +2 -2
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -15,7 +15,7 @@ ${Q}`:null].filter(Boolean).join(`
15
15
 
16
16
  `));return l($)}function T1($,X){if(!X)return $;if(!$)return X;if($===X||$.endsWith(X))return $;if(X.startsWith($))return X;return e(`${$}
17
17
 
18
- ${X}`)}function D$($){if(!Array.isArray($))return null;let X=$.flatMap((Z)=>{if(!Z||typeof Z!=="object")return[];let J=Z;if(typeof J.path!=="string"||!J.path.trim())return[];let Q=typeof J.line==="number"?`:${J.line}`:"";return[`${J.path}${Q}`]});return X.length>0?X.slice(0,5):null}function f1($){let{ctx:X,appendText:Z,appendToolActivity:J}=$,Q=$.flushIntervalMs??OX,j="",Y="",G=0,z=null,K={},H=new Map,B=(P)=>{if(H.set(P.toolCallId,P),!J)return;J({boardId:X.boardId,cardId:X.cardId,runId:X.runId,entry:P}).catch((W)=>{console.warn("[streamAdapter] appendToolActivity failed",W)})},U=(P)=>{let W=`${X.runId}:thought`,C=H.get(W);if(!C||C.status!=="running")return;B({...C,status:"completed",completedAt:C.completedAt??P})},M=(P)=>{for(let W of H.values()){if(W.status!=="running"||W.rawTitle.toLowerCase()!=="toolsearch")continue;B({...W,status:"completed",completedAt:W.completedAt??P})}},N=(P)=>{for(let W of Array.from(H.values())){if(W.status!=="running")continue;if(W.kind==="thought"||W.rawTitle==="agent_thought")continue;B({...W,status:"completed",completedAt:W.completedAt??P})}},F="",V=0,D=null,x=null,k=(P)=>{if(P===F)return;F=P,V=Date.now(),Z({boardId:X.boardId,cardId:X.cardId,runId:X.runId,text:P}).catch((W)=>{console.warn("[streamAdapter] appendText failed",W)})},A=()=>{if(D!==null)clearTimeout(D),D=null;if(x!==null){let P=x;x=null,k(P)}},_=(P)=>{let W=Date.now()-V;if(W>=Q&&D===null){k(P);return}if(x=P,D===null){let C=Math.max(0,Q-W);D=setTimeout(()=>{D=null,A()},C)}};return{onSessionUpdate:async(P)=>{let W=P.update;switch(K[W.sessionUpdate]=(K[W.sessionUpdate]??0)+1,W.sessionUpdate){case"agent_message_chunk":{let C=new Date().toISOString();if(U(C),W.content.type==="text")j+=W.content.text,_(j);else{let T=`agent_message_chunk:${W.content.type}`;K[T]=(K[T]??0)+1}return}case"agent_thought_chunk":{if(W.content.type!=="text")return;Y+=W.content.text;let C=new Date().toISOString(),T=`${X.runId}:thought`,f=H.get(T);B({toolCallId:T,rawTitle:"agent_thought",title:"Thought",kind:"thought",status:"running",startedAt:f?.startedAt??C,completedAt:null,contentPreview:e(Y.trim())});return}case"user_message_chunk":return;case"tool_call":{G+=1;let C=A1(W.title),T=z$(W.status),f=new Date().toISOString();U(f),M(f),B({toolCallId:W.toolCallId,rawTitle:C,title:H$(C,W.rawInput),kind:G$(W.kind),status:T,startedAt:f,completedAt:T==="running"?null:f,inputPreview:l(W.rawInput),outputPreview:U$(W.rawOutput),contentPreview:y0(W.content),locations:D$(W.locations)});return}case"tool_call_update":{let C=H.get(W.toolCallId);if(!C){let p=A1(W.title),B0=z$(W.status),X0=new Date().toISOString();B({toolCallId:W.toolCallId,rawTitle:p,title:H$(p,W.rawInput),kind:G$(W.kind),status:B0,startedAt:X0,completedAt:B0==="running"?null:X0,inputPreview:l(W.rawInput),outputPreview:U$(W.rawOutput),contentPreview:y0(W.content),locations:D$(W.locations)});return}let T=W.status===void 0||W.status===null?C.status:z$(W.status),f=typeof W.title==="string"&&W.title.trim().length>0?W.title:C.rawTitle,L=typeof W.title==="string"&&W.title.trim().length>0,R=T==="running"?C.completedAt:C.completedAt??new Date().toISOString(),E=W.content===void 0?C.contentPreview:T1(C.contentPreview,y0(W.content)),I=W.rawOutput===void 0?C.outputPreview:T1(C.outputPreview,U$(W.rawOutput));B({...C,rawTitle:f,title:L?H$(f,W.rawInput):C.title,kind:W.kind===void 0?C.kind:G$(W.kind),status:T,completedAt:R,inputPreview:W.rawInput===void 0?C.inputPreview:l(W.rawInput),outputPreview:I,contentPreview:E,locations:W.locations===void 0?C.locations:D$(W.locations)});return}case"plan":z=W.entries;return;case"available_commands_update":return;case"current_mode_update":return;default:return}},getFinalText:()=>j,getToolCallCount:()=>G,getLatestPlan:()=>z,getUpdateTypeCounts:()=>({...K}),flush:(P)=>{let W=new Date().toISOString();if(U(W),P?.completeOpenToolCalls)N(W);A()}}}var U0=1,R1=-32000;function E1($){if($.awaitingInput)return!1;return $.nowMs-$.lastUpdateMs>$.windowMs}function v1($){if(!$||typeof $!=="object")return!1;return $.code===R1}var TX=300000,fX=5000;function I1(){return{name:"ideawave-cli",title:"IdeaWave CLI",version:"0.0.48".trim()?"0.0.48":"dev"}}function h1($){if($===U0)return;throw new O(`Unsupported ACP protocol version ${$}; expected ${U0}`)}function S1($){return AX.toWeb($)}function m1($){return wX.toWeb($)}function M$($){return $!==null&&typeof $==="object"}function RX($){if(!Array.isArray($))return[];let X=[];for(let Z of $){if(!M$(Z))continue;if(typeof Z.group==="string"&&Array.isArray(Z.options)){let J=typeof Z.name==="string"?Z.name:Z.group;for(let Q of Z.options){if(!M$(Q))continue;if(typeof Q.value!=="string"||typeof Q.name!=="string")continue;X.push({value:Q.value,name:Q.name,description:typeof Q.description==="string"?Q.description:null,group:Z.group,groupName:J})}continue}if(typeof Z.value!=="string"||typeof Z.name!=="string")continue;X.push({value:Z.value,name:Z.name,description:typeof Z.description==="string"?Z.description:null,group:null,groupName:null})}return X}function EX($){if(!M$($))return null;if(typeof $.id!=="string"||typeof $.name!=="string")return null;let X=typeof $.category==="string"?$.category:null,Z=typeof $.description==="string"?$.description:null;if($.type==="select"){let J=typeof $.currentValue==="string"?$.currentValue:null;return{id:$.id,name:$.name,category:X,description:Z,type:"select",currentValue:J,options:RX($.options)}}if($.type==="boolean"){let J=typeof $.currentValue==="boolean"?$.currentValue:typeof $.value==="boolean"?$.value:null;return{id:$.id,name:$.name,category:X,description:Z,type:"boolean",currentValue:J,options:[]}}return null}function N$($){let X=($.configOptions??[]).map(EX).filter((G)=>G!==null),Z=X.find((G)=>G.type==="select"&&G.category==="model")??X.find((G)=>G.type==="select"&&G.id==="model")??null,J=Z?.options.map((G)=>({id:G.value,name:G.name,description:G.description??null})),Q=yX($.models),j=J&&J.length>0?J:Q&&Q.length>0?Q:null,Y=(typeof Z?.currentValue==="string"?Z.currentValue:null)??bX($.models)??null;return{models:j,currentModelId:Y,configOptions:X,modelConfigId:Z?.id??null}}function yX($){if(!$||!Array.isArray($.availableModels))return null;let X=[];for(let Z of $.availableModels){if(typeof Z.modelId!=="string")continue;X.push({id:Z.modelId,name:typeof Z.name==="string"?Z.name:null,description:typeof Z.description==="string"?Z.description:null})}return X.length>0?X:null}function bX($){return typeof $?.currentModelId==="string"?$.currentModelId:null}function vX($,X){let Z=[];if($.trim())Z.push({type:"text",text:$});for(let J of X)if(J.content.trim())Z.push({type:"text",text:J.content});return Z}function IX($){if(typeof $.value==="boolean")return{sessionId:$.sessionId,configId:$.configId,type:"boolean",value:$.value};return{sessionId:$.sessionId,configId:$.configId,value:$.value}}function hX($,X){let Z=N$({configOptions:X.configOptions});return{models:Z.models??$.models,currentModelId:Z.currentModelId??$.currentModelId,configOptions:Z.configOptions,modelConfigId:Z.modelConfigId??$.modelConfigId}}function g1($,X){if($==="default")return null;if(!X||X.length===0)return $;let Z=X.find((K)=>K.id===$);if(Z)return Z.id;let J=$.toLowerCase(),Q=J.includes("opus")?"opus":J.includes("sonnet")?"sonnet":J.includes("haiku")?"haiku":null;if(!Q)return $;let j=(K)=>`${K.id} ${K.name??""} ${K.description??""}`.toLowerCase(),Y=X.filter((K)=>j(K).includes(Q));if(Y.length===0)return $;let z=(J.includes("1m")?Y.find((K)=>j(K).includes("1m")):void 0)??Y[0];return z?z.id:$}async function v0($){try{let X=await $.conn.setSessionConfigOption(IX({sessionId:$.sessionId,configId:$.configId,value:$.value}));return hX($.metadata,X)}catch(X){return console.warn(`[acp] setSessionConfigOption(${$.label}) failed; using agent default.`,X instanceof Error?X.message:X),$.metadata}}async function q$($){let X=W$($.spawn),Z=[],J=0,Q=4096;X.stderr.on("data",(L)=>{Z.push(L),J+=L.length;while(J>Q*2&&Z.length>1){let R=Z.shift();if(R)J-=R.length}});let j=()=>{let L=Buffer.concat(Z).toString("utf8");return L.length>Q?L.slice(-Q):L},Y=_1($.spawn.cwd),G={current:null},z={at:Date.now()},K=m1(X.stdin),H=S1(X.stdout),B=b1(K,H),M=new y1((L)=>({requestPermission:async(R)=>{let E=R.options,I=E?.find((p)=>p.kind==="allow_once")??E?.find((p)=>p.kind==="allow_always");if(I)return{outcome:{outcome:"selected",optionId:I.optionId}};return{outcome:{outcome:"cancelled"}}},sessionUpdate:async(R)=>{z.at=Date.now();let E=G.current;if(E)await E.onSessionUpdate(R)},readTextFile:Y.readTextFile}),B),N=()=>X.kill();if($.signal)$.signal.addEventListener("abort",N);let F=()=>{if($.signal)$.signal.removeEventListener("abort",N)},V=async(L,R)=>{if(F(),X.kill(),v1(L))throw new J0(L.message??"Authentication required",R);if(L instanceof Error&&L.message==="ACP connection closed"){if($.signal?.aborted)throw new O("ACP session cancelled: abort signal received");let E=await Promise.race([X.processCrashed,X.waitForExit,new Promise((I)=>setTimeout(()=>I({stderr:""}),500))]);throw new O(`Runtime process exited before completion: ${E.stderr?.trim()??""}`)}throw L},D;try{D=await M.initialize({protocolVersion:U0,clientCapabilities:Y$,clientInfo:I1()})}catch(L){throw await V(L,[]),Error("unreachable")}try{h1(D.protocolVersion)}catch(L){throw F(),X.kill(),L}let x=D.authMethods?.map((L)=>L.id)??[],k;try{k=await M.newSession({cwd:$.spawn.cwd,mcpServers:$.mcpServers??[]})}catch(L){throw await V(L,x),Error("unreachable")}let A=k.sessionId,_=N$(k),P=$.modelId??null,W=P?g1(P,_.models):null;if(W&&W!==_.currentModelId)if(_.modelConfigId)_=await v0({conn:M,sessionId:A,configId:_.modelConfigId,value:W,metadata:_,label:`${_.modelConfigId}=${W}`});else console.warn(`[acp] runtime did not advertise a model config option for ${W}; using agent default.`);for(let[L,R]of Object.entries($.configValues??{}).sort(([E],[I])=>E.localeCompare(I))){if(L===_.modelConfigId)continue;if(!_.configOptions.some((E)=>E.id===L))continue;_=await v0({conn:M,sessionId:A,configId:L,value:R,metadata:_,label:`${L}=${String(R)}`})}F();let C=!1,T=async()=>{if(C)return;C=!0,X.kill(),await Promise.race([X.waitForExit,new Promise((L)=>setTimeout(L,2000))])},f=!1;return X.processCrashed.then(()=>{f=!0}),{sessionId:A,availableModels:_.models,currentModelId:_.currentModelId,availableConfigOptions:_.configOptions,isAlive:()=>!C&&!f,dispose:T,prompt:(L)=>SX({proc:X,conn:M,sessionId:A,activeAdapter:G,lastUpdate:z,collectStderrTail:j},L)}}async function SX($,X){let{proc:Z,conn:J,sessionId:Q,activeAdapter:j,lastUpdate:Y}=$,G={boardId:X.boardId,cardId:X.cardId,runId:X.runId},z=f1({ctx:G,appendText:X.appendText,appendToolActivity:X.appendToolActivity});j.current=z,Y.at=Date.now();let K=!1,H=null,B=()=>Z.kill();X.signal.addEventListener("abort",B);try{let U=async()=>{let V=X.heartbeatMs??TX,D=Math.min(fX,Math.max(50,Math.floor(V/2)));H=setInterval(()=>{let k=X.isAwaitingInput?.()??!1;if(k){Y.at=Date.now();return}if(E1({nowMs:Date.now(),lastUpdateMs:Y.at,windowMs:V,awaitingInput:k}))K=!0,J.cancel({sessionId:Q}).catch(()=>{return}),Z.kill()},D);let x=vX(X.prompt.systemPrompt,X.prompt.messages);await J.prompt({sessionId:Q,prompt:x}),z.flush({completeOpenToolCalls:!0})},M=Z.waitForExit.then((V)=>({kind:"exited",exit:V})),N=U().then(()=>({kind:"ok"})).catch(async(V)=>{if(V instanceof Error&&V.message==="ACP connection closed")return{kind:"crashed",exit:await Promise.race([Z.processCrashed,Z.waitForExit])};throw V}),F;try{F=await Promise.race([N,Z.processCrashed.then((V)=>({kind:"crashed",exit:V})),M])}catch(V){if(K)throw new d;throw V}if(K)throw new d;if(F.kind==="crashed")throw new O(`Runtime process exited before completion: ${F.exit.stderr.trim()}`);if(F.kind==="exited"){if(X.signal.aborted)throw new O("ACP session cancelled: abort signal received");if(K)throw new d;throw new O(`Runtime process exited unexpectedly: ${F.exit.stderr.trim()}`)}return{modelReported:"unknown",finalText:z.getFinalText(),toolCallsExecuted:z.getToolCallCount(),stderrTail:$.collectStderrTail(),updateTypeCounts:z.getUpdateTypeCounts()}}finally{if(H!==null)clearInterval(H);X.signal.removeEventListener("abort",B),z.flush({completeOpenToolCalls:!0}),j.current=null}}var mX=30000;async function c1($){let X=W$($.spawn),Z=m1(X.stdin),J=S1(X.stdout),Q=b1(Z,J),Y=new y1((K)=>({requestPermission:async()=>({outcome:{outcome:"cancelled"}}),sessionUpdate:async()=>{return},readTextFile:async()=>({content:""})}),Q),G=()=>X.kill();if($.signal)$.signal.addEventListener("abort",G);let z=null;try{let K=(async()=>{let B=await Y.initialize({protocolVersion:U0,clientCapabilities:Y$,clientInfo:I1()});h1(B.protocolVersion);let U=B.authMethods?.map((k)=>k.id)??[],M;try{M=await Y.newSession({cwd:$.spawn.cwd,mcpServers:[]})}catch(k){if(v1(k))throw new J0(k.message??"Authentication required",U);throw k}let N=N$(M),F=$.modelId??null,V=F?g1(F,N.models):null;if(V&&V!==N.currentModelId)if(N.modelConfigId)N=await v0({conn:Y,sessionId:M.sessionId,configId:N.modelConfigId,value:V,metadata:N,label:`${N.modelConfigId}=${V}`});else console.warn(`[acp] runtime did not advertise a model config option for ${V}; discovering agent default models.`);for(let[k,A]of Object.entries($.configValues??{}).sort(([_],[P])=>_.localeCompare(P))){if(k===N.modelConfigId)continue;if(!N.configOptions.some((_)=>_.id===k))continue;N=await v0({conn:Y,sessionId:M.sessionId,configId:k,value:A,metadata:N,label:`${k}=${String(A)}`})}let D=N.models??[],x=N.currentModelId;return Y.cancel({sessionId:M.sessionId}).catch(()=>{return}),{models:D,configOptions:N.configOptions,currentModelId:x}})(),H=new Promise((B,U)=>{z=setTimeout(()=>{U(new d)},mX)});return await Promise.race([K,H])}catch(K){if(K instanceof Error&&K.message==="ACP connection closed"){if($.signal?.aborted)throw new O("ACP model discovery cancelled: abort signal received");throw new O("Runtime process exited during model discovery.")}throw K}finally{if(z)clearTimeout(z);if($.signal)$.signal.removeEventListener("abort",G);X.kill()}}var y=new Map,u=null;function I0($){$.then((X)=>X.dispose()).catch(()=>{return})}function gX(){if(u!==null)return;u=setInterval(()=>{let $=Date.now();for(let[X,Z]of y){if(Z.inUse)continue;if($-Z.lastUsed<600000)continue;y.delete(X),I0(Z.sessionPromise)}if(y.size===0&&u!==null)clearInterval(u),u=null},60000),u.unref?.()}function cX(){if(y.size<200)return;let $=null,X=1/0;for(let[J,Q]of y){if(Q.inUse)continue;if(Q.lastUsed>=X)continue;$=J,X=Q.lastUsed}if(!$)return;let Z=y.get($);if(!Z)return;y.delete($),I0(Z.sessionPromise)}function B$($,X,Z){return`${$}:${X}:${Z}`}async function x$($){let X=y.get($.key);if(X)if(X.fingerprint===$.fingerprint){X.inUse=!0,X.lastUsed=Date.now();try{let J=await X.sessionPromise;if(J.isAlive())return J}catch{}y.delete($.key)}else y.delete($.key),I0(X.sessionPromise);let Z=$.open();cX(),y.set($.key,{key:$.key,fingerprint:$.fingerprint,sessionPromise:Z,lastUsed:Date.now(),inUse:!0}),gX();try{return await Z}catch(J){throw y.delete($.key),J}}function F$($,X=!1){let Z=y.get($);if(!Z)return;if(X){y.delete($),I0(Z.sessionPromise);return}Z.inUse=!1,Z.lastUsed=Date.now()}async function lX(){let $=Array.from(y.values());if(y.clear(),u!==null)clearInterval(u),u=null;await Promise.all($.map((X)=>X.sessionPromise.then((Z)=>Z.dispose()).catch(()=>{return})))}function C$($){let X=Object.entries($.configValues??{}),Z=X.length>0?JSON.stringify(Object.fromEntries(X.sort(([J],[Q])=>J.localeCompare(Q)))):"";return[$.adapterId,$.configId??"",$.modelId??"",Z,$.mcpUrl??"",$.runFolder??"",$.toolSurface??"full"].join(" ")}var l1=!1;function uX(){if(l1)return;l1=!0;let $=()=>{lX()};process.once("beforeExit",$),process.once("SIGTERM",$),process.once("SIGINT",$)}uX();import pX from"node:fs/promises";import h0 from"node:os";async function u1($){let X={version:1,globalDefaultConfigId:null,runtimes:[],boardOverrides:{},cardOverrides:{}},Z;try{Z=await pX.readFile($,"utf-8")}catch(J){if(J.code==="ENOENT")return structuredClone(X);throw J}return F0.parse(JSON.parse(Z))}function P$($,X,Z){return{...$.defaultConfigValues??{},...X?.configValues??{},...Z?.configValues??{}}}async function i($){let X=$.configPath?await u1($.configPath):await h(),Z=$.cardId?X.cardOverrides[$.cardId]:void 0;if(Z?.runtimeConfigId){let Q=X.runtimes.find((j)=>j.id===Z.runtimeConfigId);if(Q)return{entry:Q,adapter:c(Q),runFolder:Z.runFolder??Q.runFolder??h0.homedir(),modelId:Z.modelId??Q.defaultModelId??null,configValues:P$(Q,void 0,Z)}}let J=X.boardOverrides[$.boardId];if(J?.runtimeConfigId){let Q=X.runtimes.find((j)=>j.id===J.runtimeConfigId);if(Q)return{entry:Q,adapter:c(Q),runFolder:J.runFolder??Q.runFolder??h0.homedir(),modelId:J.modelId??Q.defaultModelId??null,configValues:P$(Q,J)}}if(X.globalDefaultConfigId){let Q=X.runtimes.find((j)=>j.id===X.globalDefaultConfigId);if(Q)return{entry:Q,adapter:c(Q),runFolder:Z?.runFolder??J?.runFolder??Q.runFolder??h0.homedir(),modelId:Z?.modelId??J?.modelId??Q.defaultModelId??null,configValues:P$(Q,J,Z)}}throw new t}async function p1($,X={}){let J=(X.configPath?await u1(X.configPath):await h()).runtimes.find((Q)=>Q.id===$);if(!J)return null;return{entry:J,adapter:c(J),runFolder:J.runFolder??h0.homedir(),modelId:X.modelId??J.defaultModelId??null,configValues:{...J.defaultConfigValues??{},...X.configValues??{}}}}var d1=new Map;function L$($,X){if(!$)return;d1.set($,X)}function a1($){if(!$)return!1;return d1.get($)??!1}var $0=new Map,k$=new Set;function O$($){$0.get($)?.controller.abort()}function i1($){for(let[X,Z]of $0){if(Z.frontendSessionId!==$)continue;Z.controller.abort(),$0.delete(X)}}function n1(){for(let $ of $0.values())$.controller.abort();$0.clear()}function o1($,X){if(X?.aborted)return!0;return $ instanceof Error&&/abort signal received|session cancelled/i.test($.message)}function s1($,X,Z,J){if((!X.availableModels||X.availableModels.length===0)&&X.availableConfigOptions.length===0)return;g((Q)=>{let j=Q.runtimes.find((Y)=>Y.id===$);if(j){if(X.availableModels&&X.availableModels.length>0)j.discoveredModels=T0({adapterId:Z,models:X.availableModels,currentModelId:X.currentModelId??J});if(X.availableConfigOptions.length>0)j.discoveredConfigOptions=X.availableConfigOptions}}).catch(()=>{return})}function dX($,X){return`${$}
18
+ ${X}`)}function D$($){if(!Array.isArray($))return null;let X=$.flatMap((Z)=>{if(!Z||typeof Z!=="object")return[];let J=Z;if(typeof J.path!=="string"||!J.path.trim())return[];let Q=typeof J.line==="number"?`:${J.line}`:"";return[`${J.path}${Q}`]});return X.length>0?X.slice(0,5):null}function f1($){let{ctx:X,appendText:Z,appendToolActivity:J}=$,Q=$.flushIntervalMs??OX,j="",Y="",G=0,z=null,K={},H=new Map,B=(P)=>{if(H.set(P.toolCallId,P),!J)return;J({boardId:X.boardId,cardId:X.cardId,runId:X.runId,entry:P}).catch((W)=>{console.warn("[streamAdapter] appendToolActivity failed",W)})},U=(P)=>{let W=`${X.runId}:thought`,C=H.get(W);if(!C||C.status!=="running")return;B({...C,status:"completed",completedAt:C.completedAt??P})},M=(P)=>{for(let W of H.values()){if(W.status!=="running"||W.rawTitle.toLowerCase()!=="toolsearch")continue;B({...W,status:"completed",completedAt:W.completedAt??P})}},N=(P)=>{for(let W of Array.from(H.values())){if(W.status!=="running")continue;if(W.kind==="thought"||W.rawTitle==="agent_thought")continue;B({...W,status:"completed",completedAt:W.completedAt??P})}},F="",V=0,D=null,x=null,k=(P)=>{if(P===F)return;F=P,V=Date.now(),Z({boardId:X.boardId,cardId:X.cardId,runId:X.runId,text:P}).catch((W)=>{console.warn("[streamAdapter] appendText failed",W)})},A=()=>{if(D!==null)clearTimeout(D),D=null;if(x!==null){let P=x;x=null,k(P)}},_=(P)=>{let W=Date.now()-V;if(W>=Q&&D===null){k(P);return}if(x=P,D===null){let C=Math.max(0,Q-W);D=setTimeout(()=>{D=null,A()},C)}};return{onSessionUpdate:async(P)=>{let W=P.update;switch(K[W.sessionUpdate]=(K[W.sessionUpdate]??0)+1,W.sessionUpdate){case"agent_message_chunk":{let C=new Date().toISOString();if(U(C),W.content.type==="text")j+=W.content.text,_(j);else{let T=`agent_message_chunk:${W.content.type}`;K[T]=(K[T]??0)+1}return}case"agent_thought_chunk":{if(W.content.type!=="text")return;Y+=W.content.text;let C=new Date().toISOString(),T=`${X.runId}:thought`,f=H.get(T);B({toolCallId:T,rawTitle:"agent_thought",title:"Thought",kind:"thought",status:"running",startedAt:f?.startedAt??C,completedAt:null,contentPreview:e(Y.trim())});return}case"user_message_chunk":return;case"tool_call":{G+=1;let C=A1(W.title),T=z$(W.status),f=new Date().toISOString();U(f),M(f),B({toolCallId:W.toolCallId,rawTitle:C,title:H$(C,W.rawInput),kind:G$(W.kind),status:T,startedAt:f,completedAt:T==="running"?null:f,inputPreview:l(W.rawInput),outputPreview:U$(W.rawOutput),contentPreview:y0(W.content),locations:D$(W.locations)});return}case"tool_call_update":{let C=H.get(W.toolCallId);if(!C){let p=A1(W.title),B0=z$(W.status),X0=new Date().toISOString();B({toolCallId:W.toolCallId,rawTitle:p,title:H$(p,W.rawInput),kind:G$(W.kind),status:B0,startedAt:X0,completedAt:B0==="running"?null:X0,inputPreview:l(W.rawInput),outputPreview:U$(W.rawOutput),contentPreview:y0(W.content),locations:D$(W.locations)});return}let T=W.status===void 0||W.status===null?C.status:z$(W.status),f=typeof W.title==="string"&&W.title.trim().length>0?W.title:C.rawTitle,L=typeof W.title==="string"&&W.title.trim().length>0,R=T==="running"?C.completedAt:C.completedAt??new Date().toISOString(),E=W.content===void 0?C.contentPreview:T1(C.contentPreview,y0(W.content)),I=W.rawOutput===void 0?C.outputPreview:T1(C.outputPreview,U$(W.rawOutput));B({...C,rawTitle:f,title:L?H$(f,W.rawInput):C.title,kind:W.kind===void 0?C.kind:G$(W.kind),status:T,completedAt:R,inputPreview:W.rawInput===void 0?C.inputPreview:l(W.rawInput),outputPreview:I,contentPreview:E,locations:W.locations===void 0?C.locations:D$(W.locations)});return}case"plan":z=W.entries;return;case"available_commands_update":return;case"current_mode_update":return;default:return}},getFinalText:()=>j,getToolCallCount:()=>G,getLatestPlan:()=>z,getUpdateTypeCounts:()=>({...K}),flush:(P)=>{let W=new Date().toISOString();if(U(W),P?.completeOpenToolCalls)N(W);A()}}}var U0=1,R1=-32000;function E1($){if($.awaitingInput)return!1;return $.nowMs-$.lastUpdateMs>$.windowMs}function v1($){if(!$||typeof $!=="object")return!1;return $.code===R1}var TX=300000,fX=5000;function I1(){return{name:"ideawave-cli",title:"IdeaWave CLI",version:"0.0.49".trim()?"0.0.49":"dev"}}function h1($){if($===U0)return;throw new O(`Unsupported ACP protocol version ${$}; expected ${U0}`)}function S1($){return AX.toWeb($)}function m1($){return wX.toWeb($)}function M$($){return $!==null&&typeof $==="object"}function RX($){if(!Array.isArray($))return[];let X=[];for(let Z of $){if(!M$(Z))continue;if(typeof Z.group==="string"&&Array.isArray(Z.options)){let J=typeof Z.name==="string"?Z.name:Z.group;for(let Q of Z.options){if(!M$(Q))continue;if(typeof Q.value!=="string"||typeof Q.name!=="string")continue;X.push({value:Q.value,name:Q.name,description:typeof Q.description==="string"?Q.description:null,group:Z.group,groupName:J})}continue}if(typeof Z.value!=="string"||typeof Z.name!=="string")continue;X.push({value:Z.value,name:Z.name,description:typeof Z.description==="string"?Z.description:null,group:null,groupName:null})}return X}function EX($){if(!M$($))return null;if(typeof $.id!=="string"||typeof $.name!=="string")return null;let X=typeof $.category==="string"?$.category:null,Z=typeof $.description==="string"?$.description:null;if($.type==="select"){let J=typeof $.currentValue==="string"?$.currentValue:null;return{id:$.id,name:$.name,category:X,description:Z,type:"select",currentValue:J,options:RX($.options)}}if($.type==="boolean"){let J=typeof $.currentValue==="boolean"?$.currentValue:typeof $.value==="boolean"?$.value:null;return{id:$.id,name:$.name,category:X,description:Z,type:"boolean",currentValue:J,options:[]}}return null}function N$($){let X=($.configOptions??[]).map(EX).filter((G)=>G!==null),Z=X.find((G)=>G.type==="select"&&G.category==="model")??X.find((G)=>G.type==="select"&&G.id==="model")??null,J=Z?.options.map((G)=>({id:G.value,name:G.name,description:G.description??null})),Q=yX($.models),j=J&&J.length>0?J:Q&&Q.length>0?Q:null,Y=(typeof Z?.currentValue==="string"?Z.currentValue:null)??bX($.models)??null;return{models:j,currentModelId:Y,configOptions:X,modelConfigId:Z?.id??null}}function yX($){if(!$||!Array.isArray($.availableModels))return null;let X=[];for(let Z of $.availableModels){if(typeof Z.modelId!=="string")continue;X.push({id:Z.modelId,name:typeof Z.name==="string"?Z.name:null,description:typeof Z.description==="string"?Z.description:null})}return X.length>0?X:null}function bX($){return typeof $?.currentModelId==="string"?$.currentModelId:null}function vX($,X){let Z=[];if($.trim())Z.push({type:"text",text:$});for(let J of X)if(J.content.trim())Z.push({type:"text",text:J.content});return Z}function IX($){if(typeof $.value==="boolean")return{sessionId:$.sessionId,configId:$.configId,type:"boolean",value:$.value};return{sessionId:$.sessionId,configId:$.configId,value:$.value}}function hX($,X){let Z=N$({configOptions:X.configOptions});return{models:Z.models??$.models,currentModelId:Z.currentModelId??$.currentModelId,configOptions:Z.configOptions,modelConfigId:Z.modelConfigId??$.modelConfigId}}function g1($,X){if($==="default")return null;if(!X||X.length===0)return $;let Z=X.find((K)=>K.id===$);if(Z)return Z.id;let J=$.toLowerCase(),Q=J.includes("opus")?"opus":J.includes("sonnet")?"sonnet":J.includes("haiku")?"haiku":null;if(!Q)return $;let j=(K)=>`${K.id} ${K.name??""} ${K.description??""}`.toLowerCase(),Y=X.filter((K)=>j(K).includes(Q));if(Y.length===0)return $;let z=(J.includes("1m")?Y.find((K)=>j(K).includes("1m")):void 0)??Y[0];return z?z.id:$}async function v0($){try{let X=await $.conn.setSessionConfigOption(IX({sessionId:$.sessionId,configId:$.configId,value:$.value}));return hX($.metadata,X)}catch(X){return console.warn(`[acp] setSessionConfigOption(${$.label}) failed; using agent default.`,X instanceof Error?X.message:X),$.metadata}}async function q$($){let X=W$($.spawn),Z=[],J=0,Q=4096;X.stderr.on("data",(L)=>{Z.push(L),J+=L.length;while(J>Q*2&&Z.length>1){let R=Z.shift();if(R)J-=R.length}});let j=()=>{let L=Buffer.concat(Z).toString("utf8");return L.length>Q?L.slice(-Q):L},Y=_1($.spawn.cwd),G={current:null},z={at:Date.now()},K=m1(X.stdin),H=S1(X.stdout),B=b1(K,H),M=new y1((L)=>({requestPermission:async(R)=>{let E=R.options,I=E?.find((p)=>p.kind==="allow_once")??E?.find((p)=>p.kind==="allow_always");if(I)return{outcome:{outcome:"selected",optionId:I.optionId}};return{outcome:{outcome:"cancelled"}}},sessionUpdate:async(R)=>{z.at=Date.now();let E=G.current;if(E)await E.onSessionUpdate(R)},readTextFile:Y.readTextFile}),B),N=()=>X.kill();if($.signal)$.signal.addEventListener("abort",N);let F=()=>{if($.signal)$.signal.removeEventListener("abort",N)},V=async(L,R)=>{if(F(),X.kill(),v1(L))throw new J0(L.message??"Authentication required",R);if(L instanceof Error&&L.message==="ACP connection closed"){if($.signal?.aborted)throw new O("ACP session cancelled: abort signal received");let E=await Promise.race([X.processCrashed,X.waitForExit,new Promise((I)=>setTimeout(()=>I({stderr:""}),500))]);throw new O(`Runtime process exited before completion: ${E.stderr?.trim()??""}`)}throw L},D;try{D=await M.initialize({protocolVersion:U0,clientCapabilities:Y$,clientInfo:I1()})}catch(L){throw await V(L,[]),Error("unreachable")}try{h1(D.protocolVersion)}catch(L){throw F(),X.kill(),L}let x=D.authMethods?.map((L)=>L.id)??[],k;try{k=await M.newSession({cwd:$.spawn.cwd,mcpServers:$.mcpServers??[]})}catch(L){throw await V(L,x),Error("unreachable")}let A=k.sessionId,_=N$(k),P=$.modelId??null,W=P?g1(P,_.models):null;if(W&&W!==_.currentModelId)if(_.modelConfigId)_=await v0({conn:M,sessionId:A,configId:_.modelConfigId,value:W,metadata:_,label:`${_.modelConfigId}=${W}`});else console.warn(`[acp] runtime did not advertise a model config option for ${W}; using agent default.`);for(let[L,R]of Object.entries($.configValues??{}).sort(([E],[I])=>E.localeCompare(I))){if(L===_.modelConfigId)continue;if(!_.configOptions.some((E)=>E.id===L))continue;_=await v0({conn:M,sessionId:A,configId:L,value:R,metadata:_,label:`${L}=${String(R)}`})}F();let C=!1,T=async()=>{if(C)return;C=!0,X.kill(),await Promise.race([X.waitForExit,new Promise((L)=>setTimeout(L,2000))])},f=!1;return X.processCrashed.then(()=>{f=!0}),{sessionId:A,availableModels:_.models,currentModelId:_.currentModelId,availableConfigOptions:_.configOptions,isAlive:()=>!C&&!f,dispose:T,prompt:(L)=>SX({proc:X,conn:M,sessionId:A,activeAdapter:G,lastUpdate:z,collectStderrTail:j},L)}}async function SX($,X){let{proc:Z,conn:J,sessionId:Q,activeAdapter:j,lastUpdate:Y}=$,G={boardId:X.boardId,cardId:X.cardId,runId:X.runId},z=f1({ctx:G,appendText:X.appendText,appendToolActivity:X.appendToolActivity});j.current=z,Y.at=Date.now();let K=!1,H=null,B=()=>Z.kill();X.signal.addEventListener("abort",B);try{let U=async()=>{let V=X.heartbeatMs??TX,D=Math.min(fX,Math.max(50,Math.floor(V/2)));H=setInterval(()=>{let k=X.isAwaitingInput?.()??!1;if(k){Y.at=Date.now();return}if(E1({nowMs:Date.now(),lastUpdateMs:Y.at,windowMs:V,awaitingInput:k}))K=!0,J.cancel({sessionId:Q}).catch(()=>{return}),Z.kill()},D);let x=vX(X.prompt.systemPrompt,X.prompt.messages);await J.prompt({sessionId:Q,prompt:x}),z.flush({completeOpenToolCalls:!0})},M=Z.waitForExit.then((V)=>({kind:"exited",exit:V})),N=U().then(()=>({kind:"ok"})).catch(async(V)=>{if(V instanceof Error&&V.message==="ACP connection closed")return{kind:"crashed",exit:await Promise.race([Z.processCrashed,Z.waitForExit])};throw V}),F;try{F=await Promise.race([N,Z.processCrashed.then((V)=>({kind:"crashed",exit:V})),M])}catch(V){if(K)throw new d;throw V}if(K)throw new d;if(F.kind==="crashed")throw new O(`Runtime process exited before completion: ${F.exit.stderr.trim()}`);if(F.kind==="exited"){if(X.signal.aborted)throw new O("ACP session cancelled: abort signal received");if(K)throw new d;throw new O(`Runtime process exited unexpectedly: ${F.exit.stderr.trim()}`)}return{modelReported:"unknown",finalText:z.getFinalText(),toolCallsExecuted:z.getToolCallCount(),stderrTail:$.collectStderrTail(),updateTypeCounts:z.getUpdateTypeCounts()}}finally{if(H!==null)clearInterval(H);X.signal.removeEventListener("abort",B),z.flush({completeOpenToolCalls:!0}),j.current=null}}var mX=30000;async function c1($){let X=W$($.spawn),Z=m1(X.stdin),J=S1(X.stdout),Q=b1(Z,J),Y=new y1((K)=>({requestPermission:async()=>({outcome:{outcome:"cancelled"}}),sessionUpdate:async()=>{return},readTextFile:async()=>({content:""})}),Q),G=()=>X.kill();if($.signal)$.signal.addEventListener("abort",G);let z=null;try{let K=(async()=>{let B=await Y.initialize({protocolVersion:U0,clientCapabilities:Y$,clientInfo:I1()});h1(B.protocolVersion);let U=B.authMethods?.map((k)=>k.id)??[],M;try{M=await Y.newSession({cwd:$.spawn.cwd,mcpServers:[]})}catch(k){if(v1(k))throw new J0(k.message??"Authentication required",U);throw k}let N=N$(M),F=$.modelId??null,V=F?g1(F,N.models):null;if(V&&V!==N.currentModelId)if(N.modelConfigId)N=await v0({conn:Y,sessionId:M.sessionId,configId:N.modelConfigId,value:V,metadata:N,label:`${N.modelConfigId}=${V}`});else console.warn(`[acp] runtime did not advertise a model config option for ${V}; discovering agent default models.`);for(let[k,A]of Object.entries($.configValues??{}).sort(([_],[P])=>_.localeCompare(P))){if(k===N.modelConfigId)continue;if(!N.configOptions.some((_)=>_.id===k))continue;N=await v0({conn:Y,sessionId:M.sessionId,configId:k,value:A,metadata:N,label:`${k}=${String(A)}`})}let D=N.models??[],x=N.currentModelId;return Y.cancel({sessionId:M.sessionId}).catch(()=>{return}),{models:D,configOptions:N.configOptions,currentModelId:x}})(),H=new Promise((B,U)=>{z=setTimeout(()=>{U(new d)},mX)});return await Promise.race([K,H])}catch(K){if(K instanceof Error&&K.message==="ACP connection closed"){if($.signal?.aborted)throw new O("ACP model discovery cancelled: abort signal received");throw new O("Runtime process exited during model discovery.")}throw K}finally{if(z)clearTimeout(z);if($.signal)$.signal.removeEventListener("abort",G);X.kill()}}var y=new Map,u=null;function I0($){$.then((X)=>X.dispose()).catch(()=>{return})}function gX(){if(u!==null)return;u=setInterval(()=>{let $=Date.now();for(let[X,Z]of y){if(Z.inUse)continue;if($-Z.lastUsed<600000)continue;y.delete(X),I0(Z.sessionPromise)}if(y.size===0&&u!==null)clearInterval(u),u=null},60000),u.unref?.()}function cX(){if(y.size<200)return;let $=null,X=1/0;for(let[J,Q]of y){if(Q.inUse)continue;if(Q.lastUsed>=X)continue;$=J,X=Q.lastUsed}if(!$)return;let Z=y.get($);if(!Z)return;y.delete($),I0(Z.sessionPromise)}function B$($,X,Z){return`${$}:${X}:${Z}`}async function x$($){let X=y.get($.key);if(X)if(X.fingerprint===$.fingerprint){X.inUse=!0,X.lastUsed=Date.now();try{let J=await X.sessionPromise;if(J.isAlive())return J}catch{}y.delete($.key)}else y.delete($.key),I0(X.sessionPromise);let Z=$.open();cX(),y.set($.key,{key:$.key,fingerprint:$.fingerprint,sessionPromise:Z,lastUsed:Date.now(),inUse:!0}),gX();try{return await Z}catch(J){throw y.delete($.key),J}}function F$($,X=!1){let Z=y.get($);if(!Z)return;if(X){y.delete($),I0(Z.sessionPromise);return}Z.inUse=!1,Z.lastUsed=Date.now()}async function lX(){let $=Array.from(y.values());if(y.clear(),u!==null)clearInterval(u),u=null;await Promise.all($.map((X)=>X.sessionPromise.then((Z)=>Z.dispose()).catch(()=>{return})))}function C$($){let X=Object.entries($.configValues??{}),Z=X.length>0?JSON.stringify(Object.fromEntries(X.sort(([J],[Q])=>J.localeCompare(Q)))):"";return[$.adapterId,$.configId??"",$.modelId??"",Z,$.mcpUrl??"",$.runFolder??"",$.toolSurface??"full"].join(" ")}var l1=!1;function uX(){if(l1)return;l1=!0;let $=()=>{lX()};process.once("beforeExit",$),process.once("SIGTERM",$),process.once("SIGINT",$)}uX();import pX from"node:fs/promises";import h0 from"node:os";async function u1($){let X={version:1,globalDefaultConfigId:null,runtimes:[],boardOverrides:{},cardOverrides:{}},Z;try{Z=await pX.readFile($,"utf-8")}catch(J){if(J.code==="ENOENT")return structuredClone(X);throw J}return F0.parse(JSON.parse(Z))}function P$($,X,Z){return{...$.defaultConfigValues??{},...X?.configValues??{},...Z?.configValues??{}}}async function i($){let X=$.configPath?await u1($.configPath):await h(),Z=$.cardId?X.cardOverrides[$.cardId]:void 0;if(Z?.runtimeConfigId){let Q=X.runtimes.find((j)=>j.id===Z.runtimeConfigId);if(Q)return{entry:Q,adapter:c(Q),runFolder:Z.runFolder??Q.runFolder??h0.homedir(),modelId:Z.modelId??Q.defaultModelId??null,configValues:P$(Q,void 0,Z)}}let J=X.boardOverrides[$.boardId];if(J?.runtimeConfigId){let Q=X.runtimes.find((j)=>j.id===J.runtimeConfigId);if(Q)return{entry:Q,adapter:c(Q),runFolder:J.runFolder??Q.runFolder??h0.homedir(),modelId:J.modelId??Q.defaultModelId??null,configValues:P$(Q,J)}}if(X.globalDefaultConfigId){let Q=X.runtimes.find((j)=>j.id===X.globalDefaultConfigId);if(Q)return{entry:Q,adapter:c(Q),runFolder:Z?.runFolder??J?.runFolder??Q.runFolder??h0.homedir(),modelId:Z?.modelId??J?.modelId??Q.defaultModelId??null,configValues:P$(Q,J,Z)}}throw new t}async function p1($,X={}){let J=(X.configPath?await u1(X.configPath):await h()).runtimes.find((Q)=>Q.id===$);if(!J)return null;return{entry:J,adapter:c(J),runFolder:J.runFolder??h0.homedir(),modelId:X.modelId??J.defaultModelId??null,configValues:{...J.defaultConfigValues??{},...X.configValues??{}}}}var d1=new Map;function L$($,X){if(!$)return;d1.set($,X)}function a1($){if(!$)return!1;return d1.get($)??!1}var $0=new Map,k$=new Set;function O$($){$0.get($)?.controller.abort()}function i1($){for(let[X,Z]of $0){if(Z.frontendSessionId!==$)continue;Z.controller.abort(),$0.delete(X)}}function n1(){for(let $ of $0.values())$.controller.abort();$0.clear()}function o1($,X){if(X?.aborted)return!0;return $ instanceof Error&&/abort signal received|session cancelled/i.test($.message)}function s1($,X,Z,J){if((!X.availableModels||X.availableModels.length===0)&&X.availableConfigOptions.length===0)return;g((Q)=>{let j=Q.runtimes.find((Y)=>Y.id===$);if(j){if(X.availableModels&&X.availableModels.length>0)j.discoveredModels=T0({adapterId:Z,models:X.availableModels,currentModelId:X.currentModelId??J});if(X.availableConfigOptions.length>0)j.discoveredConfigOptions=X.availableConfigOptions}}).catch(()=>{return})}function dX($,X){return`${$}
19
19
 
20
20
  Runtime run folder:
21
21
  - Effective run folder: ${X}
@@ -25,4 +25,4 @@ Runtime run folder:
25
25
  Connection: close\r
26
26
  Content-Length: ${Buffer.byteLength(Z)}\r
27
27
  \r
28
- ${Z}`),$.destroy()}function WZ($,X){return new Promise((Z,J)=>{let Q=(Y)=>{$.off("listening",j),J(Y)},j=()=>{$.off("error",Q);let Y=$.address();if(!Y||typeof Y==="string"){J(Error("Failed to read CLI bridge server address"));return}Z(Y.port)};$.once("error",Q),$.once("listening",j),$.listen(X,"127.0.0.1")})}function j6($){return new Promise((X,Z)=>{$.close((J)=>{if(J)Z(J);else X()})})}async function W6($,X=A$()){let Z=new Map,J=new Map,Q=$.maxMessageSize??tX,j=!1,Y=(U)=>{let M=J.get(U);if(M)clearTimeout(M);J.delete(U)},G=(U)=>{J.delete(U);let{activeRunIds:M}=$.registry.disconnect(U);$.onDisconnect(U,M)},z=(U,M)=>{let N={type:"cli_status",connected:!0,runtime:$.runtime,mcpReady:$.mcpReady(),error:M};if(U){let F=Z.get(U);if(F)K0(F,N);return}for(let F of Z.values())K0(F,N)},K=(U,M)=>{let N=M.sessionId.trim(),F=M.userId.trim();if(!N||!F){K0(U,{type:"cli_status",connected:!1,runtime:$.runtime,mcpReady:$.mcpReady(),error:"Missing frontend session or user id"}),U.close();return}Y(N);let V=Z.get(N);if(V&&V!==U)V.close();U.data.frontendSessionId=N,Z.set(N,U),$.registry.register({frontendSessionId:N,userId:F,tools:M.tools,send:(D)=>K0(U,D)}),z(N),$.onToolMetadata?.(N)},H=(U,M)=>{let N=$.registry.getUserId(U);if(!N)return;switch(M.type){case"bridge_ping":{let F=Z.get(U);if(F)K0(F,{type:"bridge_pong"});break}case"tool_metadata":$.registry.setMetadata(U,M.tools),$.onToolMetadata?.(U);break;case"tool_result":$.registry.handleToolResult(U,M);break;case"run_turn":$.registry.markRunActive(U,M.run.runId,M.run.cardId),$.onRunTurn(U,{...M.run,frontendSessionId:U,userId:N});break;case"cancel_run":if($.registry.ownsRun(U,M.runId))$.onCancelRun(U,M.runId);break;case"runtime_rpc":$.onRuntimeRpc(U,M);break;case"warmup_run":$.onWarmupRun(U,{...M,frontendSessionId:U},N);break;default:break}},B=(U,M)=>{let N=J6(U.headers.origin),F=Z6(N),V={Vary:"Origin"};if(F&&N)V["Access-Control-Allow-Origin"]=N,V["Access-Control-Allow-Private-Network"]="true";if(U.method==="OPTIONS"){M.writeHead(204,{...V,"Access-Control-Allow-Methods":"GET, OPTIONS","Access-Control-Allow-Headers":"*","Access-Control-Max-Age":"600"}),M.end();return}if(U.method!=="GET"){M.writeHead(405,V),M.end();return}M.writeHead(200,{...V,"content-type":"application/json","cache-control":"no-store"}),M.end(JSON.stringify({ideawave:!0,runtime:$.runtime,mcpReady:$.mcpReady()}))};for(let U of X){let M=oX((V,D)=>{if(new URL(V.url??"/","http://127.0.0.1").pathname===e1){B(V,D);return}D.writeHead(404,{"content-type":"text/plain"}),D.end("IdeaWave CLI bridge")}),N=new sX({noServer:!0,maxPayload:Q}),F=(V)=>{if(V.idleTimer)clearTimeout(V.idleTimer);V.idleTimer=setTimeout(()=>{V.close()},rX),V.idleTimer.unref?.()};N.on("connection",(V)=>{let D=V;D.data={id:nX(),frontendSessionId:null},D.idleTimer=null,F(D),D.on("ping",()=>F(D)),D.on("pong",()=>F(D)),D.on("error",()=>{if(D.idleTimer)clearTimeout(D.idleTimer);D.close()}),D.on("message",(x)=>{F(D);let k=YZ(x);if(Q>0&&k.length>Q)return;let A=S0(k);if(!A)return;let _=D.data.frontendSessionId;if(!_){if(A.type==="bridge_probe")K0(D,{type:"bridge_probe_ack",protocolVersion:A.protocolVersion});else if(A.type==="frontend_hello")K(D,A);return}H(_,A)}),D.on("close",()=>{if(D.idleTimer)clearTimeout(D.idleTimer);let x=D.data.frontendSessionId;if(!x)return;if(Z.get(x)!==D)return;if(Z.delete(x),Y(x),j)return;J.set(x,setTimeout(()=>G(x),eX))})}),M.on("upgrade",(V,D,x)=>{if(new URL(V.url??"/","http://127.0.0.1").pathname!==_$){Q6(D,404,"Not Found");return}if(!Z6(J6(V.headers.origin))){Q6(D,403,"Forbidden");return}N.handleUpgrade(V,D,x,(A)=>{N.emit("connection",A,V)})});try{let V=await WZ(M,U);return{url:`ws://127.0.0.1:${V}${_$}`,port:V,sendStatus:z,close:async()=>{j=!0;for(let D of J.values())clearTimeout(D);J.clear();for(let D of N.clients){let x=D;if(x.idleTimer)clearTimeout(x.idleTimer);x.close()}N.close(),await j6(M).catch(()=>{return})}}}catch(V){if(N.close(),await j6(M).catch(()=>{return}),V?.code==="EADDRINUSE")continue;throw V}}throw Error(`No free IdeaWave CLI bridge port found in ${X[0]}-${X.at(-1)}`)}import{Server as PZ}from"@modelcontextprotocol/sdk/server/index.js";import{CallToolRequestSchema as LZ,ListToolsRequestSchema as kZ}from"@modelcontextprotocol/sdk/types.js";import{randomUUID as zZ}from"node:crypto";import{createServer as GZ}from"node:http";import{StreamableHTTPServerTransport as HZ}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as H6}from"@modelcontextprotocol/sdk/types.js";var V6=new Set(["127.0.0.1","localhost","[::1]","::1"]);function VZ($){let X=$.trim();if(X.length===0)return null;if(X.startsWith("[")){let j=X.indexOf("]");if(j===-1)return null;let Y=X.slice(0,j+1),G=X.slice(j+1);if(G.length===0)return{host:Y,port:null};if(!G.startsWith(":"))return null;let z=Number(G.slice(1));if(!Number.isInteger(z)||z<=0||z>65535)return null;return{host:Y,port:z}}let Z=X.lastIndexOf(":");if(Z===-1)return{host:X,port:null};let J=X.slice(Z+1),Q=Number(J);if(!Number.isInteger(Q)||Q<=0||Q>65535)return{host:X,port:null};return{host:X.slice(0,Z),port:Q}}function z6($){return V6.has($)||V6.has($.toLowerCase())}function G6($,X){let Z=$.headers.host;if(typeof Z!=="string")return{ok:!1,status:403,reason:"missing-host"};let J=VZ(Z);if(!J)return{ok:!1,status:403,reason:"bad-host"};if(!z6(J.host))return{ok:!1,status:403,reason:"non-loopback-host"};if(J.port!==null&&J.port!==X)return{ok:!1,status:403,reason:"host-port-mismatch"};let Q=$.headers.origin;if(typeof Q==="string"&&Q.length>0){if(Q!=="null"){let j;try{j=new URL(Q)}catch{return{ok:!1,status:403,reason:"bad-origin"}}if(!z6(j.hostname))return{ok:!1,status:403,reason:"non-loopback-origin"}}}return{ok:!0}}var U6="/mcp",UZ=43274,M6=16777216,DZ=1800000,MZ=300000,D6=200,NZ=-32700,n=-32600,T$=-32603;function m($,X,Z,J,Q){$.statusCode=X,$.setHeader("content-type","application/json"),$.end(JSON.stringify({jsonrpc:"2.0",error:{code:Z,message:J,...Q?{data:Q}:{}},id:null}))}class f$ extends Error{constructor(){super("expected application/json");this.name="BadContentTypeError"}}class R$ extends Error{constructor(){super(`body exceeds ${M6} bytes`);this.name="BodyTooLargeError"}}async function qZ($){if($.method&&$.method!=="POST")return;let X=$.headers["content-type"];if(typeof X==="string"&&X.trim().length>0){if(!X.toLowerCase().includes("application/json"))throw new f$}let Z=0,J=[];for await(let j of $){let Y=typeof j==="string"?Buffer.from(j):j;if(Z+=Y.byteLength,Z>M6)throw new R$;J.push(Y)}if(J.length===0)return;let Q=Buffer.concat(J).toString("utf8");if(Q.length===0)return;return JSON.parse(Q)}function BZ($){if(Array.isArray($))return $.some(H6);return H6($)}function xZ($){if(typeof $==="number")return $;let X=process.env.IDEAWAVE_MCP_PORT;if(X&&X.trim().length>0){let Z=Number(X);if(Number.isInteger(Z)&&Z>=0&&Z<65536)return Z}return UZ}async function FZ($,X){let Z=(Q)=>new Promise((j,Y)=>{let G=(K)=>{$.off("listening",z),Y(K)},z=()=>{$.off("error",G),j()};$.once("error",G),$.once("listening",z),$.listen(Q,"127.0.0.1")});try{await Z(X)}catch(Q){if(Q.code!=="EADDRINUSE"||X===0)throw Q;console.warn(`[mcp] port ${X} in use, falling back to an OS-assigned port; external CLIs will need to re-paste the install command from Settings → External agents`),await Z(0)}let J=$.address();if(J==null||typeof J==="string")throw Error("[mcp] failed to read bound address");return J.port}function CZ($,X){if(X&&typeof X==="object"&&!Array.isArray(X)){let J=X.params;if(J&&typeof J==="object"&&!Array.isArray(J)){let Q=J.clientInfo;if(Q&&typeof Q==="object"&&!Array.isArray(Q)){let j=Q.name;if(typeof j==="string"&&j.trim().length>0)return j.trim()}}}let Z=$.headers["user-agent"];if(typeof Z==="string"&&Z.trim().length>0)return Z.trim();return null}async function N6($){let X=new Map,Z=0;function J(K){let H=X.get(K);if(H)H.lastActivity=Date.now()}async function Q(K,H){X.delete(K),await H.transport.close().catch(()=>{return})}async function j(){let K=null,H=1/0;for(let[B,U]of X)if(U.lastActivity<H)H=U.lastActivity,K=B;if(K!==null){let B=X.get(K);if(B)console.warn(`[mcp] session cap of ${D6} reached; evicting ${K}`),await Q(K,B)}}let Y=setInterval(()=>{let K=Date.now()-DZ;for(let[H,B]of X)if(B.lastActivity<K)console.log(`[mcp] sweeping idle session ${H}`),Q(H,B)},MZ);Y.unref?.();let G=GZ((K,H)=>{(async()=>{let B;try{B=new URL(K.url??"/","http://127.0.0.1").pathname}catch{m(H,400,n,"bad-url");return}if(B!==U6){m(H,404,n,"not-found");return}let U=K.method??"POST";if(U!=="POST"&&U!=="GET"&&U!=="DELETE"){H.setHeader("Allow","GET, POST, DELETE"),m(H,405,n,"method-not-allowed");return}let M=G6(K,Z);if(!M.ok){m(H,M.status,n,"forbidden",{reason:M.reason});return}let N=K.headers["mcp-session-id"],F=typeof N==="string"?N:void 0;if(U==="GET"||U==="DELETE"){if(!F||!X.has(F)){m(H,400,n,"no-session",{hint:"Open a POST initialize first to receive an Mcp-Session-Id."});return}let x=X.get(F).transport;J(F);try{await x.handleRequest(K,H)}catch(k){if(console.error("[mcp] transport.handleRequest (GET/DELETE) threw",k),!H.headersSent)m(H,500,T$,"internal")}return}let V;try{V=await qZ(K)}catch(x){if(x instanceof f$){m(H,415,n,"expected-application-json");return}if(x instanceof R$){m(H,413,n,"body-too-large");return}m(H,400,NZ,"invalid-json");return}let D;if(F&&X.has(F))D=X.get(F).transport,J(F);else if(!F&&V!==void 0&&BZ(V)){let x=K.headers["x-ideawave-user-id"],k=typeof x==="string"&&x.trim().length>0?x.trim():null,A=K.headers["x-ideawave-frontend-session-id"],_=typeof A==="string"&&A.trim().length>0?A.trim():null,P=K.headers["x-ideawave-tool-surface"],W=typeof P==="string"&&P.trim()==="read"?"read":"full",C=K.headers["x-ideawave-images-supported"],T=typeof C==="string"&&C.trim()==="1",f=K.headers["x-ideawave-card-id"],L=typeof f==="string"&&f.trim().length>0?f.trim():null,R=K.headers["x-ideawave-board-id"],E=typeof R==="string"&&R.trim().length>0?R.trim():null,I=K.headers["x-ideawave-run-folder"],p=typeof I==="string"&&I.trim().length>0?I.trim():null,B0=CZ(K,V);if(X.size>=D6)await j();let X0=null,s=new HZ({sessionIdGenerator:()=>zZ(),onsessioninitialized:(Z0)=>{X0=Z0,X.set(Z0,{transport:s,lastActivity:Date.now()})},onsessionclosed:(Z0)=>{X.delete(Z0)}});s.onclose=()=>{if(s.sessionId)X.delete(s.sessionId)};try{await $.buildServer({userId:k,frontendSessionId:_,boardId:E,toolSurface:W,imagesSupported:T,cardId:L,runFolder:p,clientHint:B0}).connect(s)}catch(Z0){if(console.error("[mcp] buildServer/connect failed",Z0),X0)X.delete(X0);await s.close().catch(()=>{return}),m(H,500,T$,"server-init-failed");return}D=s}else{m(H,400,n,"no-session",{hint:"Non-initialize requests must include a valid Mcp-Session-Id header obtained from a prior initialize."});return}try{await D.handleRequest(K,H,V)}catch(x){if(console.error("[mcp] transport.handleRequest threw",x),!H.headersSent)m(H,500,T$,"internal")}})().catch((B)=>{console.error("[mcp] unhandled request handler error:",B)})});return Z=await FZ(G,xZ($.port)),{url:`http://127.0.0.1:${Z}${U6}`,port:Z,close:async()=>{clearInterval(Y);for(let K of X.values())await K.transport.close().catch(()=>{return});X.clear(),await new Promise((K)=>G.close(()=>K()))}}}var OZ={name:"ideawave-board",version:"1.0.0"},g0="list_run_folder",c0="read_run_folder_file",x6=new Set(["list_boards","get_board","list_nodes","list_edges","inspect_node","list_context_sources","read_context_card","read_context_file","read_context_image","list_context_folder","get_board_wiki","search_board","get_card_messages","list_agent_cards","inspect_neighbors",g0,c0]),F6=new Set(["inspect_diagram"]),_Z=[{name:g0,description:"List visible files and folders under the selected runtime run folder. Hidden/config folders are omitted.",inputSchema:{type:"object",properties:{path:{type:"string",description:"Optional relative path inside the selected run folder. Defaults to the run-folder root."}},additionalProperties:!1}},{name:c0,description:"Read a text file inside the selected runtime run folder. Hidden/config paths and outside-folder paths are denied.",inputSchema:{type:"object",properties:{path:{type:"string",description:"Relative path to a text file inside the selected run folder."}},required:["path"],additionalProperties:!1}}];function E$($){return{content:[{type:"text",text:$}]}}function AZ($){return E$(JSON.stringify($,null,2))}function q6($){return{...E$($),isError:!0}}function wZ($,X,Z="full",J=!1){return $.getMetadata(X).filter((Q)=>{let j=E0(Q.name);if(Z==="read"&&!x6.has(j))return!1;if(!J&&F6.has(j))return!1;return!0}).map((Q)=>({name:Q.name,description:Q.description,inputSchema:Q.inputSchema}))}function TZ($,X,Z={}){let J=wZ($,X,Z.toolSurface??"full",Z.imagesSupported??!1);return Z.includeRunFolderTools?[...J,..._Z]:J}function B6($,X){if(!$||typeof $!=="object"||Array.isArray($))return null;let Z=$[X];return typeof Z==="string"?Z:null}async function fZ($,X,Z){if(Z&&Z.trim().length>0)return Z.trim();if(!$||!X)throw Error("Run-folder tools require an active IdeaWave board and card.");return(await i({boardId:$,cardId:X})).runFolder}async function RZ($){let X=await fZ($.boardId,$.cardId,$.runFolder);if($.name===g0){let Z=B6($.args,"path")??"",J=await O1(X,Z);return AZ(J)}if($.name===c0){let Z=B6($.args,"path");if(!Z)return q6("read_run_folder_file requires a path.");return E$(await R0(X,Z))}return q6(`Unknown local tool "${$.name}"`)}function EZ($,X,Z,J,Q,j="full",Y=!1){let G=new PZ(OZ,{capabilities:{tools:{}}}),z=async()=>{if(Y)return!0;if(a1(J))return!0;if(Z&&J)try{return(await i({boardId:Z,cardId:J})).adapter.supportsImages===!0}catch{return!1}return!1};return G.setRequestHandler(kZ,async()=>({tools:TZ($,X,{includeRunFolderTools:Boolean(Q||Z&&J),toolSurface:j,imagesSupported:await z()})})),G.setRequestHandler(LZ,async(K)=>{let{name:H,arguments:B}=K.params,U=E0(H);try{if(U===g0||U===c0)return await RZ({name:U,args:B,boardId:Z,cardId:J,runFolder:Q});if(j==="read"&&!x6.has(U))throw Error(`Tool "${H}" is not available in read-only mode`);if(F6.has(U)&&!await z())throw Error(`Tool "${H}" requires a runtime that supports image input`);let M=await $.callTool(X,U,B??{},void 0,J??void 0);if(M&&typeof M==="object"&&Array.isArray(M.content))return M;return{content:[{type:"text",text:typeof M==="string"?M:JSON.stringify(M)}]}}catch(M){return{content:[{type:"text",text:M instanceof Error?M.message:"Tool call failed"}],isError:!0}}}),G}function C6($,X){return N6({buildServer:(Z)=>EZ($,Z.frontendSessionId,Z.boardId,Z.cardId,Z.runFolder,Z.toolSurface,Z.imagesSupported),port:X})}import l0 from"node:fs/promises";import y$ from"node:os";import u0 from"node:path";function P6(){return`cfg_${crypto.randomUUID().replace(/-/g,"").slice(0,16)}`}async function yZ(){let[$,X]=await Promise.all([h(),F1()]),Z=$.globalDefaultConfigId?$.runtimes.find((J)=>J.id===$.globalDefaultConfigId)??null:null;return{runtimes:$.runtimes,globalDefaultConfigId:$.globalDefaultConfigId,globalDefaultEffective:Z?{runFolder:Z.runFolder??y$.homedir(),modelId:Z.defaultModelId??null,configValues:Z.defaultConfigValues??{}}:null,knownAdapters:j0().map((J)=>({id:J.id,displayName:J.displayName})),readiness:X}}async function bZ($){try{let X=await i({boardId:$.boardId,cardId:$.cardId});return{resolved:{configId:X.entry.id,adapterId:X.entry.kind==="registered"?X.entry.adapterId:null,displayName:X.entry.displayName,runFolder:X.runFolder,modelId:X.modelId,configValues:X.configValues}}}catch(X){if(X instanceof t)return{resolved:null};throw X}}async function vZ($){return g((X)=>{let Z=X.runtimes.find((j)=>j.kind==="registered"&&j.adapterId===$.adapterId);if(Z)return Z;let J=j0().find((j)=>j.id===$.adapterId);if(!J)throw Error(`Unknown adapterId: ${$.adapterId}`);let Q={id:P6(),kind:"registered",adapterId:$.adapterId,displayName:J.displayName,runFolder:null,defaultModelId:null,defaultConfigValues:{},discoveredModels:[],discoveredConfigOptions:[],discoveredAt:null};return X.runtimes.push(Q),Q})}async function IZ($){return g((X)=>{let Z={id:P6(),kind:"custom",displayName:$.displayName,command:$.command,args:$.args,env:$.env,runFolder:$.runFolder,defaultModelId:null,defaultConfigValues:{},discoveredModels:[],discoveredConfigOptions:[],discoveredAt:null};return X.runtimes.push(Z),Z})}async function hZ($){await g((X)=>{if(X.runtimes=X.runtimes.filter((Z)=>Z.id!==$.runtimeConfigId),X.globalDefaultConfigId===$.runtimeConfigId)X.globalDefaultConfigId=null;for(let Z of Object.keys(X.boardOverrides))if(X.boardOverrides[Z].runtimeConfigId===$.runtimeConfigId)delete X.boardOverrides[Z];for(let Z of Object.keys(X.cardOverrides))if(X.cardOverrides[Z].runtimeConfigId===$.runtimeConfigId)delete X.cardOverrides[Z]})}async function SZ($){await g((X)=>{let Z=X.runtimes.find((J)=>J.id===$.runtimeConfigId);if(!Z)throw Error(`Runtime config not found: ${$.runtimeConfigId}`);if(X.globalDefaultConfigId=$.runtimeConfigId,$.runFolder!==void 0)Z.runFolder=$.runFolder;if($.modelId!==void 0)Z.defaultModelId=$.modelId;if($.configValues!==void 0)Z.defaultConfigValues=$.configValues})}async function mZ($){$.boardId,await g((X)=>{if($.runtimeConfigId===null){delete X.cardOverrides[$.cardId];return}if(!X.runtimes.some((Q)=>Q.id===$.runtimeConfigId))throw Error(`Runtime config not found: ${$.runtimeConfigId}`);let J=X.cardOverrides[$.cardId];X.cardOverrides[$.cardId]={runtimeConfigId:$.runtimeConfigId,runFolder:$.runFolder!==void 0?$.runFolder:J?.runFolder??null,modelId:$.modelId!==void 0?$.modelId:J?.modelId??null,configValues:$.configValues!==void 0?$.configValues:J?.configValues??{}}})}async function gZ($){let Z=(await h()).runtimes.find((Y)=>Y.id===$.runtimeConfigId);if(!Z)throw Error(`Runtime config not found: ${$.runtimeConfigId}`);let J=c(Z),Q=await J.resolveSpawnConfig(Z),j=Z.runFolder??y$.homedir();try{let Y=await c1({spawn:{...Q,cwd:j},modelId:$.modelId??Z.defaultModelId??null,configValues:$.configValues??Z.defaultConfigValues??{}}),G=T0({adapterId:J.id,models:Y.models,currentModelId:Y.currentModelId}),z=new Date().toISOString();return await g((K)=>{let H=K.runtimes.find((B)=>B.id===$.runtimeConfigId);if(H)H.discoveredModels=G,H.discoveredConfigOptions=Y.configOptions,H.discoveredAt=z}),{ok:!0,models:G,configOptions:Y.configOptions,currentModelId:Y.currentModelId}}catch(Y){if(Y instanceof J0)throw Error(`${Y.message}${J.authHint?` ${J.authHint}`:""}`);if(Y instanceof O||Y instanceof d)throw Error(Y.message);throw Y}}async function cZ($){let X=y$.homedir(),Z=$.path?.trim()?$.path.trim():X,J=u0.resolve(Z),Q=!0;try{if(!(await l0.stat(J)).isDirectory())J=u0.dirname(J)}catch{Q=!1,J=X}let j=[];try{j=(await l0.readdir(J,{withFileTypes:!0})).filter((z)=>z.isDirectory()&&!z.name.startsWith(".")).map((z)=>({name:z.name,path:u0.join(J,z.name)})).sort((z,K)=>z.name.localeCompare(K.name))}catch{j=[]}let Y=u0.dirname(J);return{path:J,parent:Y===J?null:Y,home:X,exists:Q,entries:j}}var L6={list:yZ,getEffectiveForCard:bZ,registerRegistered:vZ,registerCustom:IZ,unregister:hZ,setUserDefault:SZ,setCardOverride:mZ,refreshModels:gZ,browseFolder:cZ};var lZ=[{id:"claude-code",displayName:"Claude Code"},{id:"codex",displayName:"Codex"},{id:"copilot",displayName:"Copilot"},{id:"opencode",displayName:"OpenCode"}];function uZ(){return`cfg_${crypto.randomUUID().replace(/-/g,"").slice(0,16)}`}async function k6(){try{let $=await h();if($.globalDefaultConfigId){if($.runtimes.some((Z)=>Z.id===$.globalDefaultConfigId))return $.globalDefaultConfigId}for(let X of lZ){if((await C1(X.id))?.status!=="ready")continue;let J=null;if(await g((Q)=>{if(Q.globalDefaultConfigId){if(Q.runtimes.some((G)=>G.id===Q.globalDefaultConfigId)){J=Q.globalDefaultConfigId;return}}let j=Q.runtimes.find((Y)=>Y.kind==="registered"&&Y.adapterId===X.id);if(!j){let Y={id:uZ(),kind:"registered",adapterId:X.id,displayName:X.displayName,runFolder:null,defaultModelId:null,defaultConfigValues:{},discoveredModels:[],discoveredConfigOptions:[],discoveredAt:null};Q.runtimes.push(Y),j=Y}Q.globalDefaultConfigId=j.id,J=j.id}),J)return console.log(`[ideawave-cli] using agent runtime: ${X.displayName}`),J}return console.warn("[ideawave-cli] no agent runtime detected on PATH (tried claude, codex, gh copilot, opencode). Install one to run agents."),null}catch($){return console.warn("[ideawave-cli] runtime auto-seed failed",$),null}}function pZ(){if(typeof crypto<"u"&&"randomUUID"in crypto)return`call_${crypto.randomUUID()}`;return`call_${Date.now()}_${Math.random().toString(16).slice(2)}`}class b${sessions=new Map;createCallId;toolCallTimeoutMs;constructor($={}){this.createCallId=$.createCallId??pZ,this.toolCallTimeoutMs=$.toolCallTimeoutMs??120000}register($){let X=this.sessions.get($.frontendSessionId);if(X){if(X.userId!==$.userId)this.rejectPending(X,"frontend session user changed"),X.activeRunIds.clear();this.sessions.set($.frontendSessionId,{frontendSessionId:$.frontendSessionId,userId:$.userId,tools:$.tools,send:$.send,pendingToolCalls:X.pendingToolCalls,activeRunIds:X.activeRunIds,activeRunCardIds:X.activeRunCardIds});return}this.sessions.set($.frontendSessionId,{frontendSessionId:$.frontendSessionId,userId:$.userId,tools:$.tools,send:$.send,pendingToolCalls:new Map,activeRunIds:new Set,activeRunCardIds:new Map})}disconnect($,X="frontend session disconnected"){let Z=this.sessions.get($);if(!Z)return{activeRunIds:[]};return this.sessions.delete($),this.rejectPending(Z,X),{activeRunIds:Array.from(Z.activeRunIds)}}sessionCount(){return this.sessions.size}has($){return this.sessions.has($)}getUserId($){return this.sessions.get($)?.userId??null}setMetadata($,X){let Z=this.sessions.get($);if(Z)Z.tools=X}getMetadata($){if(!$)return[];return this.sessions.get($)?.tools??[]}sendToSession($,X){let Z=this.sessions.get($);if(!Z)return!1;return Z.send(X),!0}callTool($,X,Z,J,Q){if(!$)return Promise.reject(Error("MCP tool call is missing a frontend session id"));let j=this.sessions.get($);if(!j)return Promise.reject(Error(`Frontend session ${$} is not connected`));let Y=this.createCallId();return new Promise((G,z)=>{let K=setTimeout(()=>{j.pendingToolCalls.delete(Y),z(Error(`Tool "${X}" timed out waiting for the frontend`))},this.toolCallTimeoutMs),H=J??(Q?this.getActiveRunIdForCard(j,Q):this.getSoleActiveRunId(j)),B=Q??(H?j.activeRunCardIds.get(H):void 0);j.pendingToolCalls.set(Y,{resolve:G,reject:z,timer:K}),j.send({type:"tool_call",callId:Y,name:X,args:Z,...H?{runId:H}:{},...B?{cardId:B}:{}})})}handleToolResult($,X){let Z=this.sessions.get($);if(!Z)return;let J=Z.pendingToolCalls.get(X.callId);if(!J)return;if(Z.pendingToolCalls.delete(X.callId),clearTimeout(J.timer),X.ok)J.resolve(X.result);else J.reject(Error(X.error??"Tool execution failed"))}markRunActive($,X,Z){let J=this.sessions.get($);if(!J)return;if(J.activeRunIds.add(X),Z)J.activeRunCardIds.set(X,Z)}markRunSettled($,X){let Z=this.sessions.get($);if(!Z)return;Z.activeRunIds.delete(X),Z.activeRunCardIds.delete(X)}ownsRun($,X){return this.sessions.get($)?.activeRunIds.has(X)??!1}rejectPending($,X){for(let Z of $.pendingToolCalls.values())clearTimeout(Z.timer),Z.reject(Error(X));$.pendingToolCalls.clear()}getSoleActiveRunId($){return $.activeRunIds.size===1?$.activeRunIds.values().next().value:void 0}getActiveRunIdForCard($,X){let Z=[...$.activeRunCardIds.entries()].filter(([J,Q])=>$.activeRunIds.has(J)&&Q===X).map(([J])=>J);return Z.length===1?Z[0]:void 0}}function dZ(){return"0.0.48".trim()?"0.0.48":"dev"}var aZ=process.argv.slice(2),_6=[];for(let $ of aZ){if($==="--dev"){process.env[w$]="1";continue}_6.push($)}var o=_6[0];if(o==="--help"||o==="-h"||o==="help")console.log("ideawave — host the local bridge for a running ideawave.app session."),console.log(""),console.log("Usage:"),console.log(" ideawave Serve the browser bridge and MCP forwarder."),console.log(" ideawave --version Print the CLI version."),process.exit(0);if(o==="--version"||o==="-v"||o==="version")console.log(dZ()),process.exit(0);if(o)console.error(`Unknown command: ${o}`),console.error("Run `ideawave --help` for usage."),process.exit(1);var M0=new b$,Y0=null;function N0($,X){M0.sendToSession($,X)}async function iZ($,X){try{let Z=L6[X.method],J=await Z(X.params);N0($,{type:"runtime_rpc_result",requestId:X.requestId,ok:!0,result:J})}catch(Z){N0($,{type:"runtime_rpc_result",requestId:X.requestId,ok:!1,error:Z instanceof Error?Z.message:String(Z)})}}var q0=!1,D0=null;async function v$(){if(q0)return;if(D0)return D0;return D0=(async()=>{try{let $=await C6(M0);m$({...$,requestedPort:$.port}),console.log(`[ideawave-cli] MCP endpoint for the agent: ${$.url}`);try{await X1({onStatusChange:(X)=>{if(P1(),Y0?.sendStatus(),X.status==="failed")console.warn(`[ideawave-cli] ACP bridge setup failed for ${X.packageName}: ${X.error??"unknown error"}`)}})}catch(X){console.warn("[ideawave-cli] ACP bridge setup skipped:",X instanceof Error?X.message:String(X))}await k6(),q0=!0,console.log("[ideawave-cli] ready — agent runs will drive the board."),Y0?.sendStatus()}catch($){console.error("[ideawave-cli] failed to start agent host:",$),Y0?.sendStatus(void 0,$ instanceof Error?$.message:String($))}finally{D0=null}})(),D0}if(process.env.APP_ENV!=="development"){let $=await Y6();if($)console.error(`[ideawave-cli] An IdeaWave CLI is already running at ${$}.`),console.error("[ideawave-cli] Only one CLI per machine is supported — it already serves every browser tab. Exiting."),process.exit(0)}Y0=await W6({registry:M0,runtime:null,mcpReady:()=>q0,onToolMetadata:($)=>{console.log(`[ideawave-cli] session ${$} advertised ${M0.getMetadata($).length} tools`),v$()},onRunTurn:($,X)=>{console.log(`[ideawave-cli] running agent turn for card ${X.cardId} (session ${$})`),(async()=>{if(await v$(),!q0){N0($,{type:"run_settled",runId:X.runId,cardId:X.cardId,result:{assistantContent:"",model:null,latencyMs:0,errorText:"IdeaWave CLI agent host is not ready",partialText:null}});return}await t1(X,(Z)=>N0($,Z))})().catch(()=>{return}).finally(()=>M0.markRunSettled($,X.runId))},onCancelRun:($,X)=>{O$(X)},onRuntimeRpc:($,X)=>{iZ($,X)},onWarmupRun:($,X,Z)=>{(async()=>{if(await v$(),!q0)return{status:"retryable",error:"agent host is not ready"};return r1({cardId:X.cardId,boardId:X.boardId,userId:Z,frontendSessionId:$})})().then((J)=>{if(!X.warmupId)return;N0($,{type:"warmup_result",warmupId:X.warmupId,cardId:X.cardId,...J})})},onDisconnect:($,X)=>{i1($);for(let Z of X)O$(Z);console.log(`[ideawave-cli] browser session ${$} disconnected`)}});console.log(`[ideawave-cli] browser bridge listening on ${Y0.url}`);console.log("[ideawave-cli] waiting for ideawave.app browser sessions…");var O6=!1;for(let $ of["SIGINT","SIGTERM"])process.once($,()=>{if(O6)return;O6=!0,n1(),(async()=>{await Y0?.close().catch(()=>{return}),process.exit(0)})()});
28
+ ${Z}`),$.destroy()}function WZ($,X){return new Promise((Z,J)=>{let Q=(Y)=>{$.off("listening",j),J(Y)},j=()=>{$.off("error",Q);let Y=$.address();if(!Y||typeof Y==="string"){J(Error("Failed to read CLI bridge server address"));return}Z(Y.port)};$.once("error",Q),$.once("listening",j),$.listen(X,"127.0.0.1")})}function j6($){return new Promise((X,Z)=>{$.close((J)=>{if(J)Z(J);else X()})})}async function W6($,X=A$()){let Z=new Map,J=new Map,Q=$.maxMessageSize??tX,j=!1,Y=(U)=>{let M=J.get(U);if(M)clearTimeout(M);J.delete(U)},G=(U)=>{J.delete(U);let{activeRunIds:M}=$.registry.disconnect(U);$.onDisconnect(U,M)},z=(U,M)=>{let N={type:"cli_status",connected:!0,runtime:$.runtime,mcpReady:$.mcpReady(),error:M};if(U){let F=Z.get(U);if(F)K0(F,N);return}for(let F of Z.values())K0(F,N)},K=(U,M)=>{let N=M.sessionId.trim(),F=M.userId.trim();if(!N||!F){K0(U,{type:"cli_status",connected:!1,runtime:$.runtime,mcpReady:$.mcpReady(),error:"Missing frontend session or user id"}),U.close();return}Y(N);let V=Z.get(N);if(V&&V!==U)V.close();U.data.frontendSessionId=N,Z.set(N,U),$.registry.register({frontendSessionId:N,userId:F,tools:M.tools,send:(D)=>K0(U,D)}),z(N),$.onToolMetadata?.(N)},H=(U,M)=>{let N=$.registry.getUserId(U);if(!N)return;switch(M.type){case"bridge_ping":{let F=Z.get(U);if(F)K0(F,{type:"bridge_pong"});break}case"tool_metadata":$.registry.setMetadata(U,M.tools),$.onToolMetadata?.(U);break;case"tool_result":$.registry.handleToolResult(U,M);break;case"run_turn":$.registry.markRunActive(U,M.run.runId,M.run.cardId),$.onRunTurn(U,{...M.run,frontendSessionId:U,userId:N});break;case"cancel_run":if($.registry.ownsRun(U,M.runId))$.onCancelRun(U,M.runId);break;case"runtime_rpc":$.onRuntimeRpc(U,M);break;case"warmup_run":$.onWarmupRun(U,{...M,frontendSessionId:U},N);break;default:break}},B=(U,M)=>{let N=J6(U.headers.origin),F=Z6(N),V={Vary:"Origin"};if(F&&N)V["Access-Control-Allow-Origin"]=N,V["Access-Control-Allow-Private-Network"]="true";if(U.method==="OPTIONS"){M.writeHead(204,{...V,"Access-Control-Allow-Methods":"GET, OPTIONS","Access-Control-Allow-Headers":"*","Access-Control-Max-Age":"600"}),M.end();return}if(U.method!=="GET"){M.writeHead(405,V),M.end();return}M.writeHead(200,{...V,"content-type":"application/json","cache-control":"no-store"}),M.end(JSON.stringify({ideawave:!0,runtime:$.runtime,mcpReady:$.mcpReady()}))};for(let U of X){let M=oX((V,D)=>{if(new URL(V.url??"/","http://127.0.0.1").pathname===e1){B(V,D);return}D.writeHead(404,{"content-type":"text/plain"}),D.end("IdeaWave CLI bridge")}),N=new sX({noServer:!0,maxPayload:Q}),F=(V)=>{if(V.idleTimer)clearTimeout(V.idleTimer);V.idleTimer=setTimeout(()=>{V.close()},rX),V.idleTimer.unref?.()};N.on("connection",(V)=>{let D=V;D.data={id:nX(),frontendSessionId:null},D.idleTimer=null,F(D),D.on("ping",()=>F(D)),D.on("pong",()=>F(D)),D.on("error",()=>{if(D.idleTimer)clearTimeout(D.idleTimer);D.close()}),D.on("message",(x)=>{F(D);let k=YZ(x);if(Q>0&&k.length>Q)return;let A=S0(k);if(!A)return;let _=D.data.frontendSessionId;if(!_){if(A.type==="bridge_probe")K0(D,{type:"bridge_probe_ack",protocolVersion:A.protocolVersion});else if(A.type==="frontend_hello")K(D,A);return}H(_,A)}),D.on("close",()=>{if(D.idleTimer)clearTimeout(D.idleTimer);let x=D.data.frontendSessionId;if(!x)return;if(Z.get(x)!==D)return;if(Z.delete(x),Y(x),j)return;J.set(x,setTimeout(()=>G(x),eX))})}),M.on("upgrade",(V,D,x)=>{if(new URL(V.url??"/","http://127.0.0.1").pathname!==_$){Q6(D,404,"Not Found");return}if(!Z6(J6(V.headers.origin))){Q6(D,403,"Forbidden");return}N.handleUpgrade(V,D,x,(A)=>{N.emit("connection",A,V)})});try{let V=await WZ(M,U);return{url:`ws://127.0.0.1:${V}${_$}`,port:V,sendStatus:z,close:async()=>{j=!0;for(let D of J.values())clearTimeout(D);J.clear();for(let D of N.clients){let x=D;if(x.idleTimer)clearTimeout(x.idleTimer);x.close()}N.close(),await j6(M).catch(()=>{return})}}}catch(V){if(N.close(),await j6(M).catch(()=>{return}),V?.code==="EADDRINUSE")continue;throw V}}throw Error(`No free IdeaWave CLI bridge port found in ${X[0]}-${X.at(-1)}`)}import{Server as PZ}from"@modelcontextprotocol/sdk/server/index.js";import{CallToolRequestSchema as LZ,ListToolsRequestSchema as kZ}from"@modelcontextprotocol/sdk/types.js";import{randomUUID as zZ}from"node:crypto";import{createServer as GZ}from"node:http";import{StreamableHTTPServerTransport as HZ}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as H6}from"@modelcontextprotocol/sdk/types.js";var V6=new Set(["127.0.0.1","localhost","[::1]","::1"]);function VZ($){let X=$.trim();if(X.length===0)return null;if(X.startsWith("[")){let j=X.indexOf("]");if(j===-1)return null;let Y=X.slice(0,j+1),G=X.slice(j+1);if(G.length===0)return{host:Y,port:null};if(!G.startsWith(":"))return null;let z=Number(G.slice(1));if(!Number.isInteger(z)||z<=0||z>65535)return null;return{host:Y,port:z}}let Z=X.lastIndexOf(":");if(Z===-1)return{host:X,port:null};let J=X.slice(Z+1),Q=Number(J);if(!Number.isInteger(Q)||Q<=0||Q>65535)return{host:X,port:null};return{host:X.slice(0,Z),port:Q}}function z6($){return V6.has($)||V6.has($.toLowerCase())}function G6($,X){let Z=$.headers.host;if(typeof Z!=="string")return{ok:!1,status:403,reason:"missing-host"};let J=VZ(Z);if(!J)return{ok:!1,status:403,reason:"bad-host"};if(!z6(J.host))return{ok:!1,status:403,reason:"non-loopback-host"};if(J.port!==null&&J.port!==X)return{ok:!1,status:403,reason:"host-port-mismatch"};let Q=$.headers.origin;if(typeof Q==="string"&&Q.length>0){if(Q!=="null"){let j;try{j=new URL(Q)}catch{return{ok:!1,status:403,reason:"bad-origin"}}if(!z6(j.hostname))return{ok:!1,status:403,reason:"non-loopback-origin"}}}return{ok:!0}}var U6="/mcp",UZ=43274,M6=16777216,DZ=1800000,MZ=300000,D6=200,NZ=-32700,n=-32600,T$=-32603;function m($,X,Z,J,Q){$.statusCode=X,$.setHeader("content-type","application/json"),$.end(JSON.stringify({jsonrpc:"2.0",error:{code:Z,message:J,...Q?{data:Q}:{}},id:null}))}class f$ extends Error{constructor(){super("expected application/json");this.name="BadContentTypeError"}}class R$ extends Error{constructor(){super(`body exceeds ${M6} bytes`);this.name="BodyTooLargeError"}}async function qZ($){if($.method&&$.method!=="POST")return;let X=$.headers["content-type"];if(typeof X==="string"&&X.trim().length>0){if(!X.toLowerCase().includes("application/json"))throw new f$}let Z=0,J=[];for await(let j of $){let Y=typeof j==="string"?Buffer.from(j):j;if(Z+=Y.byteLength,Z>M6)throw new R$;J.push(Y)}if(J.length===0)return;let Q=Buffer.concat(J).toString("utf8");if(Q.length===0)return;return JSON.parse(Q)}function BZ($){if(Array.isArray($))return $.some(H6);return H6($)}function xZ($){if(typeof $==="number")return $;let X=process.env.IDEAWAVE_MCP_PORT;if(X&&X.trim().length>0){let Z=Number(X);if(Number.isInteger(Z)&&Z>=0&&Z<65536)return Z}return UZ}async function FZ($,X){let Z=(Q)=>new Promise((j,Y)=>{let G=(K)=>{$.off("listening",z),Y(K)},z=()=>{$.off("error",G),j()};$.once("error",G),$.once("listening",z),$.listen(Q,"127.0.0.1")});try{await Z(X)}catch(Q){if(Q.code!=="EADDRINUSE"||X===0)throw Q;console.warn(`[mcp] port ${X} in use, falling back to an OS-assigned port; external CLIs will need to re-paste the install command from Settings → External agents`),await Z(0)}let J=$.address();if(J==null||typeof J==="string")throw Error("[mcp] failed to read bound address");return J.port}function CZ($,X){if(X&&typeof X==="object"&&!Array.isArray(X)){let J=X.params;if(J&&typeof J==="object"&&!Array.isArray(J)){let Q=J.clientInfo;if(Q&&typeof Q==="object"&&!Array.isArray(Q)){let j=Q.name;if(typeof j==="string"&&j.trim().length>0)return j.trim()}}}let Z=$.headers["user-agent"];if(typeof Z==="string"&&Z.trim().length>0)return Z.trim();return null}async function N6($){let X=new Map,Z=0;function J(K){let H=X.get(K);if(H)H.lastActivity=Date.now()}async function Q(K,H){X.delete(K),await H.transport.close().catch(()=>{return})}async function j(){let K=null,H=1/0;for(let[B,U]of X)if(U.lastActivity<H)H=U.lastActivity,K=B;if(K!==null){let B=X.get(K);if(B)console.warn(`[mcp] session cap of ${D6} reached; evicting ${K}`),await Q(K,B)}}let Y=setInterval(()=>{let K=Date.now()-DZ;for(let[H,B]of X)if(B.lastActivity<K)console.log(`[mcp] sweeping idle session ${H}`),Q(H,B)},MZ);Y.unref?.();let G=GZ((K,H)=>{(async()=>{let B;try{B=new URL(K.url??"/","http://127.0.0.1").pathname}catch{m(H,400,n,"bad-url");return}if(B!==U6){m(H,404,n,"not-found");return}let U=K.method??"POST";if(U!=="POST"&&U!=="GET"&&U!=="DELETE"){H.setHeader("Allow","GET, POST, DELETE"),m(H,405,n,"method-not-allowed");return}let M=G6(K,Z);if(!M.ok){m(H,M.status,n,"forbidden",{reason:M.reason});return}let N=K.headers["mcp-session-id"],F=typeof N==="string"?N:void 0;if(U==="GET"||U==="DELETE"){if(!F||!X.has(F)){m(H,400,n,"no-session",{hint:"Open a POST initialize first to receive an Mcp-Session-Id."});return}let x=X.get(F).transport;J(F);try{await x.handleRequest(K,H)}catch(k){if(console.error("[mcp] transport.handleRequest (GET/DELETE) threw",k),!H.headersSent)m(H,500,T$,"internal")}return}let V;try{V=await qZ(K)}catch(x){if(x instanceof f$){m(H,415,n,"expected-application-json");return}if(x instanceof R$){m(H,413,n,"body-too-large");return}m(H,400,NZ,"invalid-json");return}let D;if(F&&X.has(F))D=X.get(F).transport,J(F);else if(!F&&V!==void 0&&BZ(V)){let x=K.headers["x-ideawave-user-id"],k=typeof x==="string"&&x.trim().length>0?x.trim():null,A=K.headers["x-ideawave-frontend-session-id"],_=typeof A==="string"&&A.trim().length>0?A.trim():null,P=K.headers["x-ideawave-tool-surface"],W=typeof P==="string"&&P.trim()==="read"?"read":"full",C=K.headers["x-ideawave-images-supported"],T=typeof C==="string"&&C.trim()==="1",f=K.headers["x-ideawave-card-id"],L=typeof f==="string"&&f.trim().length>0?f.trim():null,R=K.headers["x-ideawave-board-id"],E=typeof R==="string"&&R.trim().length>0?R.trim():null,I=K.headers["x-ideawave-run-folder"],p=typeof I==="string"&&I.trim().length>0?I.trim():null,B0=CZ(K,V);if(X.size>=D6)await j();let X0=null,s=new HZ({sessionIdGenerator:()=>zZ(),onsessioninitialized:(Z0)=>{X0=Z0,X.set(Z0,{transport:s,lastActivity:Date.now()})},onsessionclosed:(Z0)=>{X.delete(Z0)}});s.onclose=()=>{if(s.sessionId)X.delete(s.sessionId)};try{await $.buildServer({userId:k,frontendSessionId:_,boardId:E,toolSurface:W,imagesSupported:T,cardId:L,runFolder:p,clientHint:B0}).connect(s)}catch(Z0){if(console.error("[mcp] buildServer/connect failed",Z0),X0)X.delete(X0);await s.close().catch(()=>{return}),m(H,500,T$,"server-init-failed");return}D=s}else{m(H,400,n,"no-session",{hint:"Non-initialize requests must include a valid Mcp-Session-Id header obtained from a prior initialize."});return}try{await D.handleRequest(K,H,V)}catch(x){if(console.error("[mcp] transport.handleRequest threw",x),!H.headersSent)m(H,500,T$,"internal")}})().catch((B)=>{console.error("[mcp] unhandled request handler error:",B)})});return Z=await FZ(G,xZ($.port)),{url:`http://127.0.0.1:${Z}${U6}`,port:Z,close:async()=>{clearInterval(Y);for(let K of X.values())await K.transport.close().catch(()=>{return});X.clear(),await new Promise((K)=>G.close(()=>K()))}}}var OZ={name:"ideawave-board",version:"1.0.0"},g0="list_run_folder",c0="read_run_folder_file",x6=new Set(["list_boards","get_board","list_nodes","list_edges","inspect_node","list_context_sources","read_context_card","read_context_file","read_context_image","list_context_folder","get_board_wiki","search_board","get_card_messages","list_agent_cards","inspect_neighbors",g0,c0]),F6=new Set(["inspect_diagram"]),_Z=[{name:g0,description:"List visible files and folders under the selected runtime run folder. Hidden/config folders are omitted.",inputSchema:{type:"object",properties:{path:{type:"string",description:"Optional relative path inside the selected run folder. Defaults to the run-folder root."}},additionalProperties:!1}},{name:c0,description:"Read a text file inside the selected runtime run folder. Hidden/config paths and outside-folder paths are denied.",inputSchema:{type:"object",properties:{path:{type:"string",description:"Relative path to a text file inside the selected run folder."}},required:["path"],additionalProperties:!1}}];function E$($){return{content:[{type:"text",text:$}]}}function AZ($){return E$(JSON.stringify($,null,2))}function q6($){return{...E$($),isError:!0}}function wZ($,X,Z="full",J=!1){return $.getMetadata(X).filter((Q)=>{let j=E0(Q.name);if(Z==="read"&&!x6.has(j))return!1;if(!J&&F6.has(j))return!1;return!0}).map((Q)=>({name:Q.name,description:Q.description,inputSchema:Q.inputSchema}))}function TZ($,X,Z={}){let J=wZ($,X,Z.toolSurface??"full",Z.imagesSupported??!1);return Z.includeRunFolderTools?[...J,..._Z]:J}function B6($,X){if(!$||typeof $!=="object"||Array.isArray($))return null;let Z=$[X];return typeof Z==="string"?Z:null}async function fZ($,X,Z){if(Z&&Z.trim().length>0)return Z.trim();if(!$||!X)throw Error("Run-folder tools require an active IdeaWave board and card.");return(await i({boardId:$,cardId:X})).runFolder}async function RZ($){let X=await fZ($.boardId,$.cardId,$.runFolder);if($.name===g0){let Z=B6($.args,"path")??"",J=await O1(X,Z);return AZ(J)}if($.name===c0){let Z=B6($.args,"path");if(!Z)return q6("read_run_folder_file requires a path.");return E$(await R0(X,Z))}return q6(`Unknown local tool "${$.name}"`)}function EZ($,X,Z,J,Q,j="full",Y=!1){let G=new PZ(OZ,{capabilities:{tools:{}}}),z=async()=>{if(Y)return!0;if(a1(J))return!0;if(Z&&J)try{return(await i({boardId:Z,cardId:J})).adapter.supportsImages===!0}catch{return!1}return!1};return G.setRequestHandler(kZ,async()=>({tools:TZ($,X,{includeRunFolderTools:Boolean(Q||Z&&J),toolSurface:j,imagesSupported:await z()})})),G.setRequestHandler(LZ,async(K)=>{let{name:H,arguments:B}=K.params,U=E0(H);try{if(U===g0||U===c0)return await RZ({name:U,args:B,boardId:Z,cardId:J,runFolder:Q});if(j==="read"&&!x6.has(U))throw Error(`Tool "${H}" is not available in read-only mode`);if(F6.has(U)&&!await z())throw Error(`Tool "${H}" requires a runtime that supports image input`);let M=await $.callTool(X,U,B??{},void 0,J??void 0);if(M&&typeof M==="object"&&Array.isArray(M.content))return M;return{content:[{type:"text",text:typeof M==="string"?M:JSON.stringify(M)}]}}catch(M){return{content:[{type:"text",text:M instanceof Error?M.message:"Tool call failed"}],isError:!0}}}),G}function C6($,X){return N6({buildServer:(Z)=>EZ($,Z.frontendSessionId,Z.boardId,Z.cardId,Z.runFolder,Z.toolSurface,Z.imagesSupported),port:X})}import l0 from"node:fs/promises";import y$ from"node:os";import u0 from"node:path";function P6(){return`cfg_${crypto.randomUUID().replace(/-/g,"").slice(0,16)}`}async function yZ(){let[$,X]=await Promise.all([h(),F1()]),Z=$.globalDefaultConfigId?$.runtimes.find((J)=>J.id===$.globalDefaultConfigId)??null:null;return{runtimes:$.runtimes,globalDefaultConfigId:$.globalDefaultConfigId,globalDefaultEffective:Z?{runFolder:Z.runFolder??y$.homedir(),modelId:Z.defaultModelId??null,configValues:Z.defaultConfigValues??{}}:null,knownAdapters:j0().map((J)=>({id:J.id,displayName:J.displayName})),readiness:X}}async function bZ($){try{let X=await i({boardId:$.boardId,cardId:$.cardId});return{resolved:{configId:X.entry.id,adapterId:X.entry.kind==="registered"?X.entry.adapterId:null,displayName:X.entry.displayName,runFolder:X.runFolder,modelId:X.modelId,configValues:X.configValues}}}catch(X){if(X instanceof t)return{resolved:null};throw X}}async function vZ($){return g((X)=>{let Z=X.runtimes.find((j)=>j.kind==="registered"&&j.adapterId===$.adapterId);if(Z)return Z;let J=j0().find((j)=>j.id===$.adapterId);if(!J)throw Error(`Unknown adapterId: ${$.adapterId}`);let Q={id:P6(),kind:"registered",adapterId:$.adapterId,displayName:J.displayName,runFolder:null,defaultModelId:null,defaultConfigValues:{},discoveredModels:[],discoveredConfigOptions:[],discoveredAt:null};return X.runtimes.push(Q),Q})}async function IZ($){return g((X)=>{let Z={id:P6(),kind:"custom",displayName:$.displayName,command:$.command,args:$.args,env:$.env,runFolder:$.runFolder,defaultModelId:null,defaultConfigValues:{},discoveredModels:[],discoveredConfigOptions:[],discoveredAt:null};return X.runtimes.push(Z),Z})}async function hZ($){await g((X)=>{if(X.runtimes=X.runtimes.filter((Z)=>Z.id!==$.runtimeConfigId),X.globalDefaultConfigId===$.runtimeConfigId)X.globalDefaultConfigId=null;for(let Z of Object.keys(X.boardOverrides))if(X.boardOverrides[Z].runtimeConfigId===$.runtimeConfigId)delete X.boardOverrides[Z];for(let Z of Object.keys(X.cardOverrides))if(X.cardOverrides[Z].runtimeConfigId===$.runtimeConfigId)delete X.cardOverrides[Z]})}async function SZ($){await g((X)=>{let Z=X.runtimes.find((J)=>J.id===$.runtimeConfigId);if(!Z)throw Error(`Runtime config not found: ${$.runtimeConfigId}`);if(X.globalDefaultConfigId=$.runtimeConfigId,$.runFolder!==void 0)Z.runFolder=$.runFolder;if($.modelId!==void 0)Z.defaultModelId=$.modelId;if($.configValues!==void 0)Z.defaultConfigValues=$.configValues})}async function mZ($){$.boardId,await g((X)=>{if($.runtimeConfigId===null){delete X.cardOverrides[$.cardId];return}if(!X.runtimes.some((Q)=>Q.id===$.runtimeConfigId))throw Error(`Runtime config not found: ${$.runtimeConfigId}`);let J=X.cardOverrides[$.cardId];X.cardOverrides[$.cardId]={runtimeConfigId:$.runtimeConfigId,runFolder:$.runFolder!==void 0?$.runFolder:J?.runFolder??null,modelId:$.modelId!==void 0?$.modelId:J?.modelId??null,configValues:$.configValues!==void 0?$.configValues:J?.configValues??{}}})}async function gZ($){let Z=(await h()).runtimes.find((Y)=>Y.id===$.runtimeConfigId);if(!Z)throw Error(`Runtime config not found: ${$.runtimeConfigId}`);let J=c(Z),Q=await J.resolveSpawnConfig(Z),j=Z.runFolder??y$.homedir();try{let Y=await c1({spawn:{...Q,cwd:j},modelId:$.modelId??Z.defaultModelId??null,configValues:$.configValues??Z.defaultConfigValues??{}}),G=T0({adapterId:J.id,models:Y.models,currentModelId:Y.currentModelId}),z=new Date().toISOString();return await g((K)=>{let H=K.runtimes.find((B)=>B.id===$.runtimeConfigId);if(H)H.discoveredModels=G,H.discoveredConfigOptions=Y.configOptions,H.discoveredAt=z}),{ok:!0,models:G,configOptions:Y.configOptions,currentModelId:Y.currentModelId}}catch(Y){if(Y instanceof J0)throw Error(`${Y.message}${J.authHint?` ${J.authHint}`:""}`);if(Y instanceof O||Y instanceof d)throw Error(Y.message);throw Y}}async function cZ($){let X=y$.homedir(),Z=$.path?.trim()?$.path.trim():X,J=u0.resolve(Z),Q=!0;try{if(!(await l0.stat(J)).isDirectory())J=u0.dirname(J)}catch{Q=!1,J=X}let j=[];try{j=(await l0.readdir(J,{withFileTypes:!0})).filter((z)=>z.isDirectory()&&!z.name.startsWith(".")).map((z)=>({name:z.name,path:u0.join(J,z.name)})).sort((z,K)=>z.name.localeCompare(K.name))}catch{j=[]}let Y=u0.dirname(J);return{path:J,parent:Y===J?null:Y,home:X,exists:Q,entries:j}}var L6={list:yZ,getEffectiveForCard:bZ,registerRegistered:vZ,registerCustom:IZ,unregister:hZ,setUserDefault:SZ,setCardOverride:mZ,refreshModels:gZ,browseFolder:cZ};var lZ=[{id:"claude-code",displayName:"Claude Code"},{id:"codex",displayName:"Codex"},{id:"copilot",displayName:"Copilot"},{id:"opencode",displayName:"OpenCode"}];function uZ(){return`cfg_${crypto.randomUUID().replace(/-/g,"").slice(0,16)}`}async function k6(){try{let $=await h();if($.globalDefaultConfigId){if($.runtimes.some((Z)=>Z.id===$.globalDefaultConfigId))return $.globalDefaultConfigId}for(let X of lZ){if((await C1(X.id))?.status!=="ready")continue;let J=null;if(await g((Q)=>{if(Q.globalDefaultConfigId){if(Q.runtimes.some((G)=>G.id===Q.globalDefaultConfigId)){J=Q.globalDefaultConfigId;return}}let j=Q.runtimes.find((Y)=>Y.kind==="registered"&&Y.adapterId===X.id);if(!j){let Y={id:uZ(),kind:"registered",adapterId:X.id,displayName:X.displayName,runFolder:null,defaultModelId:null,defaultConfigValues:{},discoveredModels:[],discoveredConfigOptions:[],discoveredAt:null};Q.runtimes.push(Y),j=Y}Q.globalDefaultConfigId=j.id,J=j.id}),J)return console.log(`[ideawave-cli] using agent runtime: ${X.displayName}`),J}return console.warn("[ideawave-cli] no agent runtime detected on PATH (tried claude, codex, gh copilot, opencode). Install one to run agents."),null}catch($){return console.warn("[ideawave-cli] runtime auto-seed failed",$),null}}function pZ(){if(typeof crypto<"u"&&"randomUUID"in crypto)return`call_${crypto.randomUUID()}`;return`call_${Date.now()}_${Math.random().toString(16).slice(2)}`}class b${sessions=new Map;createCallId;toolCallTimeoutMs;constructor($={}){this.createCallId=$.createCallId??pZ,this.toolCallTimeoutMs=$.toolCallTimeoutMs??120000}register($){let X=this.sessions.get($.frontendSessionId);if(X){if(X.userId!==$.userId)this.rejectPending(X,"frontend session user changed"),X.activeRunIds.clear();this.sessions.set($.frontendSessionId,{frontendSessionId:$.frontendSessionId,userId:$.userId,tools:$.tools,send:$.send,pendingToolCalls:X.pendingToolCalls,activeRunIds:X.activeRunIds,activeRunCardIds:X.activeRunCardIds});return}this.sessions.set($.frontendSessionId,{frontendSessionId:$.frontendSessionId,userId:$.userId,tools:$.tools,send:$.send,pendingToolCalls:new Map,activeRunIds:new Set,activeRunCardIds:new Map})}disconnect($,X="frontend session disconnected"){let Z=this.sessions.get($);if(!Z)return{activeRunIds:[]};return this.sessions.delete($),this.rejectPending(Z,X),{activeRunIds:Array.from(Z.activeRunIds)}}sessionCount(){return this.sessions.size}has($){return this.sessions.has($)}getUserId($){return this.sessions.get($)?.userId??null}setMetadata($,X){let Z=this.sessions.get($);if(Z)Z.tools=X}getMetadata($){if(!$)return[];return this.sessions.get($)?.tools??[]}sendToSession($,X){let Z=this.sessions.get($);if(!Z)return!1;return Z.send(X),!0}callTool($,X,Z,J,Q){if(!$)return Promise.reject(Error("MCP tool call is missing a frontend session id"));let j=this.sessions.get($);if(!j)return Promise.reject(Error(`Frontend session ${$} is not connected`));let Y=this.createCallId();return new Promise((G,z)=>{let K=setTimeout(()=>{j.pendingToolCalls.delete(Y),z(Error(`Tool "${X}" timed out waiting for the frontend`))},this.toolCallTimeoutMs),H=J??(Q?this.getActiveRunIdForCard(j,Q):this.getSoleActiveRunId(j)),B=Q??(H?j.activeRunCardIds.get(H):void 0);j.pendingToolCalls.set(Y,{resolve:G,reject:z,timer:K}),j.send({type:"tool_call",callId:Y,name:X,args:Z,...H?{runId:H}:{},...B?{cardId:B}:{}})})}handleToolResult($,X){let Z=this.sessions.get($);if(!Z)return;let J=Z.pendingToolCalls.get(X.callId);if(!J)return;if(Z.pendingToolCalls.delete(X.callId),clearTimeout(J.timer),X.ok)J.resolve(X.result);else J.reject(Error(X.error??"Tool execution failed"))}markRunActive($,X,Z){let J=this.sessions.get($);if(!J)return;if(J.activeRunIds.add(X),Z)J.activeRunCardIds.set(X,Z)}markRunSettled($,X){let Z=this.sessions.get($);if(!Z)return;Z.activeRunIds.delete(X),Z.activeRunCardIds.delete(X)}ownsRun($,X){return this.sessions.get($)?.activeRunIds.has(X)??!1}rejectPending($,X){for(let Z of $.pendingToolCalls.values())clearTimeout(Z.timer),Z.reject(Error(X));$.pendingToolCalls.clear()}getSoleActiveRunId($){return $.activeRunIds.size===1?$.activeRunIds.values().next().value:void 0}getActiveRunIdForCard($,X){let Z=[...$.activeRunCardIds.entries()].filter(([J,Q])=>$.activeRunIds.has(J)&&Q===X).map(([J])=>J);return Z.length===1?Z[0]:void 0}}function dZ(){return"0.0.49".trim()?"0.0.49":"dev"}var aZ=process.argv.slice(2),_6=[];for(let $ of aZ){if($==="--dev"){process.env[w$]="1";continue}_6.push($)}var o=_6[0];if(o==="--help"||o==="-h"||o==="help")console.log("ideawave — host the local bridge for a running ideawave.app session."),console.log(""),console.log("Usage:"),console.log(" ideawave Serve the browser bridge and MCP forwarder."),console.log(" ideawave --version Print the CLI version."),process.exit(0);if(o==="--version"||o==="-v"||o==="version")console.log(dZ()),process.exit(0);if(o)console.error(`Unknown command: ${o}`),console.error("Run `ideawave --help` for usage."),process.exit(1);var M0=new b$,Y0=null;function N0($,X){M0.sendToSession($,X)}async function iZ($,X){try{let Z=L6[X.method],J=await Z(X.params);N0($,{type:"runtime_rpc_result",requestId:X.requestId,ok:!0,result:J})}catch(Z){N0($,{type:"runtime_rpc_result",requestId:X.requestId,ok:!1,error:Z instanceof Error?Z.message:String(Z)})}}var q0=!1,D0=null;async function v$(){if(q0)return;if(D0)return D0;return D0=(async()=>{try{let $=await C6(M0);m$({...$,requestedPort:$.port}),console.log(`[ideawave-cli] MCP endpoint for the agent: ${$.url}`);try{await X1({onStatusChange:(X)=>{if(P1(),Y0?.sendStatus(),X.status==="failed")console.warn(`[ideawave-cli] ACP bridge setup failed for ${X.packageName}: ${X.error??"unknown error"}`)}})}catch(X){console.warn("[ideawave-cli] ACP bridge setup skipped:",X instanceof Error?X.message:String(X))}await k6(),q0=!0,console.log("[ideawave-cli] ready — agent runs will drive the board."),Y0?.sendStatus()}catch($){console.error("[ideawave-cli] failed to start agent host:",$),Y0?.sendStatus(void 0,$ instanceof Error?$.message:String($))}finally{D0=null}})(),D0}if(process.env.APP_ENV!=="development"){let $=await Y6();if($)console.error(`[ideawave-cli] An IdeaWave CLI is already running at ${$}.`),console.error("[ideawave-cli] Only one CLI per machine is supported — it already serves every browser tab. Exiting."),process.exit(0)}Y0=await W6({registry:M0,runtime:null,mcpReady:()=>q0,onToolMetadata:($)=>{console.log(`[ideawave-cli] session ${$} advertised ${M0.getMetadata($).length} tools`),v$()},onRunTurn:($,X)=>{console.log(`[ideawave-cli] running agent turn for card ${X.cardId} (session ${$})`),(async()=>{if(await v$(),!q0){N0($,{type:"run_settled",runId:X.runId,cardId:X.cardId,result:{assistantContent:"",model:null,latencyMs:0,errorText:"IdeaWave CLI agent host is not ready",partialText:null}});return}await t1(X,(Z)=>N0($,Z))})().catch(()=>{return}).finally(()=>M0.markRunSettled($,X.runId))},onCancelRun:($,X)=>{O$(X)},onRuntimeRpc:($,X)=>{iZ($,X)},onWarmupRun:($,X,Z)=>{(async()=>{if(await v$(),!q0)return{status:"retryable",error:"agent host is not ready"};return r1({cardId:X.cardId,boardId:X.boardId,userId:Z,frontendSessionId:$})})().then((J)=>{if(!X.warmupId)return;N0($,{type:"warmup_result",warmupId:X.warmupId,cardId:X.cardId,...J})})},onDisconnect:($,X)=>{i1($);for(let Z of X)O$(Z);console.log(`[ideawave-cli] browser session ${$} disconnected`)}});console.log(`[ideawave-cli] browser bridge listening on ${Y0.url}`);console.log("[ideawave-cli] waiting for ideawave.app browser sessions…");var O6=!1;for(let $ of["SIGINT","SIGTERM"])process.once($,()=>{if(O6)return;O6=!0,n1(),(async()=>{await Y0?.close().catch(()=>{return}),process.exit(0)})()});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ideawave",
3
- "version": "0.0.48",
3
+ "version": "0.0.49",
4
4
  "description": "IdeaWave CLI",
5
5
  "type": "module",
6
6
  "bin": {