ideawave 0.0.17 → 0.0.18
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/dist/index.mjs +5 -4
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{readFileSync as
|
|
3
|
-
`),I0(`${Xf()}.tmp`,Xf())}function C$(f){return kf.find(($)=>$.packageName===f)??null}function L(f,$,g){return{adapterId:f.adapterId,packageName:f.packageName,version:f.version,status:$,...g?{error:g}:{}}}function g$(f,$){return $?.packageName===f.packageName&&$.version===f.version}function X$(f){try{return Date.now()-A0(f).mtimeMs>T0}catch{return!1}}function E0(f){let $=Uf(f);if(!M$($))return!1;if(X$($))return l$($,{force:!0}),!1;return!0}function i0(f){let $=Uf(f);if(Z$(a.dirname($),{recursive:!0}),X$($))l$($,{force:!0});try{let g=_0($,"wx");return O0(g),!0}catch{return!1}}function h0(f){v0(Uf(f))}function wf(f){let $=x$().bridges?.[f.adapterId];if(g$(f,$)&&$.status==="ready")return L(f,"ready");if(Yf.has(f.adapterId)||E0(f))return L(f,"installing");if(g$(f,$)&&$.status==="failed")return L(f,"failed",$.error);return L(f,"missing")}function a0(f){let $=wf(f);if($.status==="ready"||$.status==="installing")return $;if(!i0(f))return L(f,"installing");let g=L(f,"installing");Bf(f,g);let M=()=>{},Z=new Promise((j)=>{M=j});Yf.set(f.adapterId,Z);let l=!1,x=(j)=>{if(l)return;l=!0;try{h0(f)}catch{}Bf(f,j),Yf.delete(f.adapterId),M(j)},X;try{X=m0(cf(),["-y",Nf(f),...f.warmupArgs],{stdio:"ignore",windowsHide:!0})}catch(j){let F=L(f,"failed",j instanceof Error?j.message:String(j));return x(F),F}return X.on("error",(j)=>{x(L(f,"failed",j.message))}),X.on("close",(j)=>{if(j===0){x(L(f,"ready"));return}x(L(f,"failed",`npx warmup exited ${j??"null"}`))}),X.unref(),g}function p(f){let $=C$(f);return $?wf($):null}async function F$(){let f=[];for(let $ of kf){if(!await c($.runtimeBinary)){f.push(L($,"not_needed"));continue}f.push(a0($))}return f.filter(($)=>$.status!=="not_needed")}function Ff(f){let $=C$(f);if(!$)return null;if(wf($).status!=="ready")return null;return{command:cf(),args:["-y",Nf($)],env:{}}}function Hf(f,$){if(f.command!==cf())return!1;let g=kf.find((M)=>f.args.includes(Nf(M)));if(!g)return!1;return Bf(g,L(g,"failed",$)),!0}import{Readable as o0,Writable as t0}from"node:stream";import{ClientSideConnection as W$,ndJsonStream as K$}from"@agentclientprotocol/sdk";import jf from"node:fs/promises";import I from"node:path";var Rf={fs:{readTextFile:!0,writeTextFile:!1},terminal:!1};class j$ extends Error{constructor(f){super(f);this.name="PathTraversalError"}}async function d0(f,$){let g=await jf.realpath(f),M=I.resolve(g,$),Z;try{Z=await jf.realpath(M)}catch(x){if(x.code!=="ENOENT")throw x;let X=I.dirname(M),j=[I.basename(M)];while(X!==g&&X!==I.dirname(X))try{X=await jf.realpath(X);break}catch(F){if(F.code!=="ENOENT")throw F;j.unshift(I.basename(X)),X=I.dirname(X)}Z=I.join(X,...j)}let l=I.relative(g,Z);if(l.startsWith("..")||I.isAbsolute(l)||l==="..")throw new j$(`Path "${$}" resolves outside the run folder`);return Z}function D$(f){return{readTextFile:async($)=>{let g=await d0(f,$.path);return{content:await jf.readFile(g,"utf-8")}}}}import{spawn as S0}from"node:child_process";function qf(f){let $=S0(f.command,f.args,{cwd:f.cwd,env:f.env,stdio:["pipe","pipe","pipe"]});if(!$.stdin||!$.stdout||!$.stderr)throw Error("Failed to allocate stdio streams for ACP subprocess");let{stdin:g,stdout:M,stderr:Z}=$,l=4096,x=[],X=0;Z.on("data",(Q)=>{x.push(Q),X+=Q.length;while(X>l*2&&x.length>1){let K=x.shift();if(K)X-=K.length}});let j=()=>{let Q=Buffer.concat(x).toString("utf8");return Q.length>l?Q.slice(-l):Q},F=!1,C=new Promise((Q)=>{$.on("exit",(K,G)=>{Q({code:K,signal:G,stderr:j()})})}),J=new Promise((Q)=>{$.on("exit",(K,G)=>{if(!F)Q({code:K,signal:G,stderr:j()})})});return{stdin:g,stdout:M,stderr:Z,kill:(Q="SIGTERM")=>{if(F)return;F=!0;try{$.kill(Q)}catch{}},waitForExit:C,processCrashed:J}}function Pf(f){if(f==="completed")return"completed";if(f==="failed")return"failed";return"running"}var n0={delete_node:"Delete card",delete_nodes:"Delete cards",create_code_card:"Create code card",update_code_card:"Update code card",create_note_card:"Create note",update_note_card:"Update note",create_edge:"Create connection",update_edge:"Update connection",delete_edge:"Delete connection",create_flowchart:"Create flowchart",create_agent_card:"Spawn sub-agent",spawn_child_agents:"Spawn sub-agents",list_nodes:"Read board",list_edges:"Read connections",read_file:"Read file"};function Lf(f){let $=n0[f];if($)return $;let g=f.replaceAll(/[_-]+/g," ").trim().split(/\s+/);if(g.length>1&&g[0].toLowerCase()==="mcp")g.shift();if(g.length===0)return f;return g.map((M,Z)=>Z===0?M.charAt(0).toUpperCase()+M.slice(1):M).join(" ")}var p0=33;function J$(f){let{ctx:$,appendText:g,appendToolActivity:M}=f,Z=f.flushIntervalMs??p0,l="",x=0,X=null,j={},F=new Map,C=(W)=>{if(F.set(W.toolCallId,W),!M)return;M({boardId:$.boardId,cardId:$.cardId,runId:$.runId,entry:W}).catch((V)=>{console.warn("[streamAdapter] appendToolActivity failed",V)})},J="",Q=0,K=null,G=null,D=(W)=>{if(W===J)return;J=W,Q=Date.now(),g({boardId:$.boardId,cardId:$.cardId,runId:$.runId,text:W}).catch((V)=>{console.warn("[streamAdapter] appendText failed",V)})},k=()=>{if(K!==null)clearTimeout(K),K=null;if(G!==null){let W=G;G=null,D(W)}},N=(W)=>{let V=Date.now()-Q;if(V>=Z&&K===null){D(W);return}if(G=W,K===null){let U=Math.max(0,Z-V);K=setTimeout(()=>{K=null,k()},U)}};return{onSessionUpdate:async(W)=>{let V=W.update;switch(j[V.sessionUpdate]=(j[V.sessionUpdate]??0)+1,V.sessionUpdate){case"agent_message_chunk":{if(V.content.type==="text")l+=V.content.text,N(l);else{let U=`agent_message_chunk:${V.content.type}`;j[U]=(j[U]??0)+1}return}case"agent_thought_chunk":return;case"user_message_chunk":return;case"tool_call":{x+=1;let U=typeof V.title==="string"&&V.title.length>0?V.title:"tool",P=Pf(V.status),R=new Date().toISOString();C({toolCallId:V.toolCallId,rawTitle:U,title:Lf(U),kind:typeof V.kind==="string"?V.kind:null,status:P,startedAt:R,completedAt:P==="running"?null:R});return}case"tool_call_update":{let U=F.get(V.toolCallId);if(!U){let S=typeof V.title==="string"&&V.title.length>0?V.title:"tool",y=Pf(V.status),Y=new Date().toISOString();C({toolCallId:V.toolCallId,rawTitle:S,title:Lf(S),kind:typeof V.kind==="string"?V.kind:null,status:y,startedAt:Y,completedAt:y==="running"?null:Y});return}let P=V.status===void 0||V.status===null?U.status:Pf(V.status),R=typeof V.title==="string"&&V.title.length>0?V.title:U.rawTitle,E=P==="running"?U.completedAt:U.completedAt??new Date().toISOString();C({...U,rawTitle:R,title:Lf(R),kind:typeof V.kind==="string"?V.kind:U.kind,status:P,completedAt:E});return}case"plan":X=V.entries;return;case"available_commands_update":return;case"current_mode_update":return;default:return}},getFinalText:()=>l,getToolCallCount:()=>x,getLatestPlan:()=>X,getUpdateTypeCounts:()=>({...j}),flush:k}}var s=1,Q$=-32000;function V$(f){if(f.awaitingInput)return!1;return f.nowMs-f.lastUpdateMs>f.windowMs}function G$(f){if(!f||typeof f!=="object")return!1;return f.code===Q$}var s0=300000,r0=90000,e0=5000;function Y$(){return{name:"ideawave-cli",title:"IdeaWave CLI",version:"0.0.17".trim()?"0.0.17":"dev"}}function B$(f){if(f===s)return;throw new z(`Unsupported ACP protocol version ${f}; expected ${s}`)}function k$(f){return o0.toWeb(f)}function z$(f){return t0.toWeb(f)}function U$(f){let $=f.configOptions?.find((M)=>M.type==="select"&&(M.category==="model"||M.id==="model"));if($&&Array.isArray($.options)){let M=[];for(let Z of $.options)if(Z&&typeof Z==="object"&&"group"in Z){let l=Z.options;if(Array.isArray(l)){for(let x of l)if(x&&typeof x.value==="string"&&typeof x.name==="string")M.push({id:x.value,name:x.name,description:typeof x.description==="string"?x.description:null})}}else if(Z&&typeof Z.value==="string"&&typeof Z.name==="string")M.push({id:Z.value,name:Z.name,description:typeof Z.description==="string"?Z.description:null});if(M.length>0)return M}let g=f.models?.availableModels?.map((M)=>({id:M.modelId,name:M.name??null,description:M.description??null}));return g&&g.length>0?g:null}function fg(f,$){let g=[];if(f.trim())g.push({type:"text",text:f});for(let M of $)if(M.content.trim())g.push({type:"text",text:M.content});return g}async function mf(f){let $=qf(f.spawn),g=[],M=0,Z=4096;$.stderr.on("data",(Y)=>{g.push(Y),M+=Y.length;while(M>Z*2&&g.length>1){let H=g.shift();if(H)M-=H.length}});let l=()=>{let Y=Buffer.concat(g).toString("utf8");return Y.length>Z?Y.slice(-Z):Y},x=D$(f.spawn.cwd),X={current:null},j={at:Date.now()},F=z$($.stdin),C=k$($.stdout),J=K$(F,C),K=new W$((Y)=>({requestPermission:async(H)=>{let b=H.options?.find((xf)=>xf.kind==="allow_once"||xf.kind==="allow_always");if(b)return{outcome:{outcome:"selected",optionId:b.optionId}};return{outcome:{outcome:"cancelled"}}},sessionUpdate:async(H)=>{j.at=Date.now();let b=X.current;if(b)await b.onSessionUpdate(H)},readTextFile:x.readTextFile}),J),G=()=>$.kill();if(f.signal)f.signal.addEventListener("abort",G);let D=()=>{if(f.signal)f.signal.removeEventListener("abort",G)},k=async(Y,H)=>{if(D(),$.kill(),G$(Y))throw new n(Y.message??"Authentication required",H);if(Y instanceof Error&&Y.message==="ACP connection closed"){if(f.signal?.aborted)throw new z("ACP session cancelled: abort signal received");let b=await Promise.race([$.processCrashed,$.waitForExit,new Promise((xf)=>setTimeout(()=>xf({stderr:""}),500))]);throw new z(`Runtime process exited before completion: ${b.stderr?.trim()??""}`)}throw Y},N;try{N=await K.initialize({protocolVersion:s,clientCapabilities:Rf,clientInfo:Y$()})}catch(Y){throw await k(Y,[]),Error("unreachable")}try{B$(N.protocolVersion)}catch(Y){throw D(),$.kill(),Y}let W=N.authMethods?.map((Y)=>Y.id)??[],V;try{V=await K.newSession({cwd:f.spawn.cwd,mcpServers:f.mcpServers??[]})}catch(Y){throw await k(Y,W),Error("unreachable")}let U=V.sessionId,P=U$(V),R=f.modelId??V.models?.currentModelId??null;if(R)try{await K.unstable_setSessionModel({sessionId:U,modelId:R})}catch(Y){console.warn(`[acp] setSessionModel(${R}) failed; using agent default.`,Y instanceof Error?Y.message:Y)}D();let E=!1,S=async()=>{if(E)return;E=!0,$.kill(),await Promise.race([$.waitForExit,new Promise((Y)=>setTimeout(Y,2000))])},y=!1;return $.processCrashed.then(()=>{y=!0}),{sessionId:U,availableModels:P,isAlive:()=>!E&&!y,dispose:S,prompt:(Y)=>$g({proc:$,conn:K,sessionId:U,activeAdapter:X,lastUpdate:j,collectStderrTail:l},Y)}}async function $g(f,$){let{proc:g,conn:M,sessionId:Z,activeAdapter:l,lastUpdate:x}=f,X={boardId:$.boardId,cardId:$.cardId,runId:$.runId},j=J$({ctx:X,appendText:$.appendText,appendToolActivity:$.appendToolActivity});l.current=j,x.at=Date.now();let F=!1,C=null,J=null,Q=()=>g.kill();$.signal.addEventListener("abort",Q);let K=$.timeoutMs??s0;try{let G=async()=>{let W=$.heartbeatMs??r0,V=Math.min(e0,Math.max(50,Math.floor(W/2)));J=setInterval(()=>{let P=$.isAwaitingInput?.()??!1;if(P){x.at=Date.now();return}if(V$({nowMs:Date.now(),lastUpdateMs:x.at,windowMs:W,awaitingInput:P}))F=!0,M.cancel({sessionId:Z}).catch(()=>{return}),g.kill()},V);let U=fg($.prompt.systemPrompt,$.prompt.messages);await M.prompt({sessionId:Z,prompt:U}),j.flush()},D=g.waitForExit.then((W)=>({kind:"exited",exit:W})),k=G().then(()=>({kind:"ok"})).catch(async(W)=>{if(W instanceof Error&&W.message==="ACP connection closed")return{kind:"crashed",exit:await Promise.race([g.processCrashed,g.waitForExit])};throw W}),N=await Promise.race([k,g.processCrashed.then((W)=>({kind:"crashed",exit:W})),D,new Promise((W,V)=>{let U=()=>{C=setTimeout(()=>{if($.isAwaitingInput?.()){U();return}V({kind:"timeout"})},K)};U()}).catch((W)=>W)]);if(N.kind==="crashed")throw new z(`Runtime process exited before completion: ${N.exit.stderr.trim()}`);if(N.kind==="exited"){if($.signal.aborted)throw new z("ACP session cancelled: abort signal received");if(F)throw new h;throw new z(`Runtime process exited unexpectedly: ${N.exit.stderr.trim()}`)}if(N.kind==="timeout"||F)throw new h;return{modelReported:"unknown",finalText:j.getFinalText(),toolCallsExecuted:j.getToolCallCount(),stderrTail:f.collectStderrTail(),updateTypeCounts:j.getUpdateTypeCounts()}}finally{if(C!==null)clearTimeout(C);if(J!==null)clearInterval(J);$.signal.removeEventListener("abort",Q),j.flush(),l.current=null}}var gg=30000;async function c$(f){let $=qf(f.spawn),g=z$($.stdin),M=k$($.stdout),Z=K$(g,M),x=new W$((F)=>({requestPermission:async()=>({outcome:{outcome:"cancelled"}}),sessionUpdate:async()=>{return},readTextFile:async()=>({content:""})}),Z),X=()=>$.kill();if(f.signal)f.signal.addEventListener("abort",X);let j=null;try{let F=(async()=>{let J=await x.initialize({protocolVersion:s,clientCapabilities:Rf,clientInfo:Y$()});B$(J.protocolVersion);let Q=J.authMethods?.map((k)=>k.id)??[],K;try{K=await x.newSession({cwd:f.spawn.cwd,mcpServers:[]})}catch(k){if(G$(k))throw new n(k.message??"Authentication required",Q);throw k}let G=U$(K)??[],D=K.models?.currentModelId??null;return x.cancel({sessionId:K.sessionId}).catch(()=>{return}),{models:G,currentModelId:D}})(),C=new Promise((J,Q)=>{j=setTimeout(()=>{Q(new h)},gg)});return await Promise.race([F,C])}catch(F){if(F instanceof Error&&F.message==="ACP connection closed")throw new z("Runtime process exited during model discovery.");throw F}finally{if(j)clearTimeout(j);if(f.signal)f.signal.removeEventListener("abort",X);$.kill()}}var w=new Map,A=null;function Df(f){f.then(($)=>$.dispose()).catch(()=>{return})}function Mg(){if(A!==null)return;A=setInterval(()=>{let f=Date.now();for(let[$,g]of w){if(g.inUse)continue;if(f-g.lastUsed<600000)continue;w.delete($),Df(g.sessionPromise)}if(w.size===0&&A!==null)clearInterval(A),A=null},60000),A.unref?.()}function Zg(){if(w.size<200)return;let f=null,$=1/0;for(let[M,Z]of w){if(Z.inUse)continue;if(Z.lastUsed>=$)continue;f=M,$=Z.lastUsed}if(!f)return;let g=w.get(f);if(!g)return;w.delete(f),Df(g.sessionPromise)}function Of(f,$,g){return`${f}:${$}:${g}`}async function _f(f){let $=w.get(f.key);if($)if($.fingerprint===f.fingerprint){$.inUse=!0,$.lastUsed=Date.now();try{let M=await $.sessionPromise;if(M.isAlive())return M}catch{}w.delete(f.key)}else w.delete(f.key),Df($.sessionPromise);let g=f.open();Zg(),w.set(f.key,{key:f.key,fingerprint:f.fingerprint,sessionPromise:g,lastUsed:Date.now(),inUse:!0}),Mg();try{return await g}catch(M){throw w.delete(f.key),M}}function yf(f,$=!1){let g=w.get(f);if(!g)return;if($){w.delete(f),Df(g.sessionPromise);return}g.inUse=!1,g.lastUsed=Date.now()}async function lg(){let f=Array.from(w.values());if(w.clear(),A!==null)clearInterval(A),A=null;await Promise.all(f.map(($)=>$.sessionPromise.then((g)=>g.dispose()).catch(()=>{return})))}function If(f){return[f.adapterId,f.configId??"",f.modelId??"",f.mcpUrl??""].join(" ")}var N$=!1;function xg(){if(N$)return;N$=!0;let f=()=>{lg()};process.once("beforeExit",f),process.once("SIGTERM",f),process.once("SIGINT",f)}xg();import r from"node:fs/promises";import jg from"node:path";import{z as B}from"zod";var w$=B.object({id:B.string(),name:B.string().nullable().default(null),description:B.string().nullable().default(null)}),Cg=B.discriminatedUnion("kind",[B.object({id:B.string(),kind:B.literal("registered"),adapterId:B.enum(["claude-code","opencode","codex","copilot"]),displayName:B.string(),runFolder:B.string().nullable(),defaultModelId:B.string().nullable().default(null),discoveredModels:B.array(w$).default([]),discoveredAt:B.string().nullable().default(null)}),B.object({id:B.string(),kind:B.literal("custom"),displayName:B.string(),command:B.string(),args:B.array(B.string()),env:B.record(B.string(),B.string()),runFolder:B.string().nullable(),defaultModelId:B.string().nullable().default(null),discoveredModels:B.array(w$).default([]),discoveredAt:B.string().nullable().default(null)})]),H$=B.object({runtimeConfigId:B.string(),runFolder:B.string().nullable(),modelId:B.string().nullable().default(null)}),Jf=B.object({version:B.literal(1),globalDefaultConfigId:B.string().nullable(),runtimes:B.array(Cg),boardOverrides:B.record(B.string(),H$).default({}),cardOverrides:B.record(B.string(),H$).default({})});import Xg from"node:os";import Qf from"node:path";function Fg(){let f=Xg.homedir();switch(process.platform){case"win32":return process.env.APPDATA??Qf.join(f,"AppData","Roaming");case"darwin":return Qf.join(f,"Library","Application Support");default:return process.env.XDG_CONFIG_HOME??Qf.join(f,".config")}}function Vf(){let f=process.env.IDEAWAVE_RUNTIME_CONFIG_PATH;if(f)return f;return Qf.join(Fg(),"ideawave","runtimes.json")}var Dg={version:1,globalDefaultConfigId:null,runtimes:[],boardOverrides:{},cardOverrides:{}},R$=new Map;function Jg(f){return R$.get(f)??Promise.resolve()}function Qg(f,$){R$.set(f,$)}async function O(f){let $=f??Vf(),g;try{g=await r.readFile($,"utf-8")}catch(Z){if(Z.code==="ENOENT")return structuredClone(Dg);throw Z}return Jf.parse(JSON.parse(g))}async function _(f,$){let g=$??Vf(),M=Jg(g).then(async()=>{let Z=await O(g),l=structuredClone(Z),x=await f(l);return await Vg(l,g),x});return Qg(g,M.catch(()=>{return})),M}async function Vg(f,$){let g=$??Vf(),M=jg.dirname(g);await r.mkdir(M,{recursive:!0});let Z=`${g}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`,l=JSON.stringify(f,null,2);await r.writeFile(Z,l,"utf-8");try{await r.rename(Z,g)}catch(x){throw await r.unlink(Z).catch(()=>{return}),x}}import Gg from"node:fs/promises";import bf from"node:os";var q$="claude",Af="@agentclientprotocol/claude-agent-acp",P$=["claude-agent-acp","claude-code-acp"],L$="Install Claude Code from https://github.com/anthropics/claude-code",m$={id:"claude-code",displayName:"Claude Code",kind:"registered",resolveSpawnConfig:async()=>{if(!await c(q$))throw new z(`Claude Code CLI not found. ${L$}`);let $=Ff(Af);if($)return{command:$.command,args:$.args,env:q($.env)};let g=p(Af),M=g?.status==="installing";for(let l of P$){let x=await c(l);if(x&&!M&&g?.status!=="failed")return{command:x,args:[],env:q()}}let Z=g?.status==="failed"?`Claude Code ACP bridge install failed. ${g.error??"Restart IdeaWave CLI so it can warm the pinned bridge again."}`:"Claude Code ACP bridge is not ready. Keep IdeaWave CLI running and retry in a moment.";throw new z(Z)},checkReadiness:async()=>{if(!await c(q$))return{status:"not_installed",detail:L$};let $=p(Af);if($?.status==="ready")return{status:"ready"};if($?.status==="installing")return{status:"not_running",detail:"Installing Claude Code ACP bridge..."};if($?.status==="failed")return{status:"not_running",detail:$.error??"Claude Code ACP bridge install failed. Restart IdeaWave CLI so it can warm the pinned bridge again."};for(let g of P$)if(await c(g))return{status:"ready"};return{status:"not_running",detail:"Installing Claude Code ACP bridge..."}},authHint:"Run `claude login` (or set ANTHROPIC_API_KEY)."};var O$="codex",vf="@zed-industries/codex-acp",_$="codex-acp",y$="Install Codex CLI from https://developers.openai.com/codex/cli",I$={id:"codex",displayName:"Codex",kind:"registered",resolveSpawnConfig:async()=>{if(!await c(O$))throw new z(`Codex CLI not found. ${y$}`);let $=Ff(vf);if($)return{command:$.command,args:$.args,env:q($.env)};let g=p(vf),M=g?.status==="installing",Z=await c(_$);if(Z&&!M&&g?.status!=="failed")return{command:Z,args:[],env:q()};let l=g?.status==="failed"?`Codex ACP bridge install failed. ${g.error??"Restart IdeaWave CLI so it can warm the pinned bridge again."}`:"Codex ACP bridge is not ready. Keep IdeaWave CLI running and retry in a moment.";throw new z(l)},checkReadiness:async()=>{if(!await c(O$))return{status:"not_installed",detail:y$};let $=p(vf);if($?.status==="ready")return{status:"ready"};if($?.status==="installing")return{status:"not_running",detail:"Installing Codex ACP bridge..."};if($?.status==="failed")return{status:"not_running",detail:$.error??"Codex ACP bridge install failed. Restart IdeaWave CLI so it can warm the pinned bridge again."};if(await c(_$))return{status:"ready"};return{status:"not_running",detail:"Installing Codex ACP bridge..."}},authHint:"Run `codex login` (or set OPENAI_API_KEY)."};var A$="copilot",v$="copilot-acp",b$="npm i -g @github/copilot",T$={id:"copilot",displayName:"GitHub Copilot",kind:"registered",resolveSpawnConfig:async()=>{let f=await c(A$);if(f)return{command:f,args:["--acp"],env:q()};let $=await c(v$);if($)return{command:$,args:[],env:q()};throw new z(`Copilot not installed. Run: ${b$}`)},checkReadiness:async()=>{if(await c(A$))return{status:"ready"};if(await c(v$))return{status:"ready"};return{status:"not_installed",detail:b$}},authHint:"Run `gh auth login` (or `copilot login`)."};import Wg from"node:fs/promises";function Kg(f){return f.startsWith("/")||/^[a-zA-Z]:[\\/]/.test(f)}async function u$(f){if(Kg(f))try{return await Wg.access(f),!0}catch{return!1}return await c(f)!==null}var E$={id:"custom",displayName:"Custom ACP",kind:"custom",resolveSpawnConfig:async(f)=>{if(f.kind!=="custom")throw new z("customAdapter received non-custom entry");if(!await u$(f.command))throw new z(`custom: command "${f.command}" not found`);return{command:f.command,args:f.args,env:q(f.env)}},checkReadiness:async(f)=>{if(f.kind!=="custom")return{status:"unknown"};return await u$(f.command)?{status:"ready"}:{status:"not_installed"}}};var i$="opencode",h$="Install OpenCode from https://opencode.ai",a$={id:"opencode",displayName:"OpenCode",kind:"registered",resolveSpawnConfig:async()=>{let f=await c(i$);if(!f)throw new z(`OpenCode not installed. ${h$}`);return{command:f,args:["acp"],env:q()}},checkReadiness:async()=>{if(!await c(i$))return{status:"not_installed",detail:h$};return{status:"ready"}},authHint:"Run `opencode auth login <provider>` (or set the provider's API-key env var)."};var d$={"claude-code":m$,opencode:a$,codex:I$,copilot:T$};function v(f){if(f.kind==="custom")return E$;let $=d$[f.adapterId];if(!$)throw Error(`Unknown registered adapter: ${f.adapterId}`);return $}function o(){return Object.values(d$)}async function Yg(f){let $={version:1,globalDefaultConfigId:null,runtimes:[],boardOverrides:{},cardOverrides:{}},g;try{g=await Gg.readFile(f,"utf-8")}catch(M){if(M.code==="ENOENT")return structuredClone($);throw M}return Jf.parse(JSON.parse(g))}async function e(f){let $=f.configPath?await Yg(f.configPath):await O(),g=f.cardId?$.cardOverrides[f.cardId]:void 0;if(g?.runtimeConfigId){let Z=$.runtimes.find((l)=>l.id===g.runtimeConfigId);if(Z)return{entry:Z,adapter:v(Z),runFolder:g.runFolder??Z.runFolder??bf.homedir(),modelId:g.modelId??Z.defaultModelId??null}}let M=$.boardOverrides[f.boardId];if(M?.runtimeConfigId){let Z=$.runtimes.find((l)=>l.id===M.runtimeConfigId);if(Z)return{entry:Z,adapter:v(Z),runFolder:M.runFolder??Z.runFolder??bf.homedir(),modelId:M.modelId??Z.defaultModelId??null}}if($.globalDefaultConfigId){let Z=$.runtimes.find((l)=>l.id===$.globalDefaultConfigId);if(Z)return{entry:Z,adapter:v(Z),runFolder:g?.runFolder??M?.runFolder??Z.runFolder??bf.homedir(),modelId:g?.modelId??M?.modelId??Z.defaultModelId??null}}throw new i}var d=new Map,Tf=new Set;function uf(f){d.get(f)?.controller.abort()}function S$(f){for(let[$,g]of d){if(g.frontendSessionId!==f)continue;g.controller.abort(),d.delete($)}}function n$(){for(let f of d.values())f.controller.abort();d.clear()}function p$(f,$){if(!$.availableModels||$.availableModels.length===0)return;_((g)=>{let M=g.runtimes.find((Z)=>Z.id===f);if(M)M.discoveredModels=$.availableModels??[]}).catch(()=>{return})}async function o$(f,$){let g=Date.now(),M=new AbortController;d.set(f.runId,{controller:M,frontendSessionId:f.frontendSessionId}),Tf.add(f.cardId);let Z=Of(f.userId,f.frontendSessionId,f.cardId),l=!1,x=null;try{let X=await e({boardId:f.boardId,cardId:f.cardId}),j=await X.adapter.resolveSpawnConfig(X.entry);x=j;let F=Kf({userId:f.userId,frontendSessionId:f.frontendSessionId,cardId:f.cardId}),C=F?[F]:[],J=f.modelHint??X.modelId,Q=If({adapterId:X.adapter.id,configId:X.entry.id,modelId:J,mcpUrl:F?.url??null}),K=await _f({key:Z,fingerprint:Q,open:()=>mf({spawn:{...j,cwd:X.runFolder},mcpServers:C,modelId:J,signal:M.signal})});p$(X.entry.id,K);let G;try{G=await K.prompt({runId:f.runId,boardId:f.boardId,cardId:f.cardId,prompt:{systemPrompt:f.systemPrompt,messages:f.promptMessages.map((D)=>({role:D.role,content:D.content}))},signal:M.signal,appendText:async({text:D})=>{$({type:"partial_text",runId:f.runId,cardId:f.cardId,text:D})},appendToolActivity:async({entry:D})=>{$({type:"tool_activity",runId:f.runId,cardId:f.cardId,activity:D})}})}catch(D){if(!K.isAlive()||D instanceof z)l=!0;throw D}$({type:"run_settled",runId:f.runId,cardId:f.cardId,result:{assistantContent:G.finalText,model:G.modelReported??null,latencyMs:Date.now()-g,errorText:null,partialText:null}})}catch(X){let j=X instanceof Error?X.message:"Agent run failed";if(X instanceof z&&x)Hf(x,j);console.error(`[ideawave-cli] run ${f.runId} failed:`,j),$({type:"run_settled",runId:f.runId,cardId:f.cardId,result:{assistantContent:"",model:null,latencyMs:Date.now()-g,errorText:j,partialText:null}})}finally{yf(Z,l),d.delete(f.runId),Tf.delete(f.cardId)}}async function t$(f){if(Tf.has(f.cardId))return{status:"skipped"};let $=Of(f.userId,f.frontendSessionId,f.cardId),g=null;try{let M=await e({boardId:f.boardId,cardId:f.cardId}),Z=await M.adapter.resolveSpawnConfig(M.entry);g=Z;let l=Kf({userId:f.userId,frontendSessionId:f.frontendSessionId,cardId:f.cardId}),x=l?[l]:[],X=If({adapterId:M.adapter.id,configId:M.entry.id,modelId:M.modelId,mcpUrl:l?.url??null}),j=new AbortController,F=await _f({key:$,fingerprint:X,open:()=>mf({spawn:{...Z,cwd:M.runFolder},mcpServers:x,modelId:M.modelId,signal:j.signal})});return p$(M.entry.id,F),yf($,!1),console.log(`[ideawave-cli] warmed runtime for card ${f.cardId}`),{status:"ready"}}catch(M){if(M instanceof i)return{status:"skipped"};let Z=M instanceof Error?M.message:String(M);if(M instanceof z&&g)Hf(g,Z);if(M instanceof z&&/(not ready|installing|warming|retry in a moment)/i.test(Z))return{status:"retryable",error:Z};return console.warn(`[ideawave-cli] warmup failed for card ${f.cardId}:`,Z),{status:"failed",error:Z}}}import{randomUUID as kg}from"node:crypto";import{createServer as zg}from"node:http";import{WebSocket as Ug,WebSocketServer as cg}from"ws";var Ef="/cli-bridge";function s$(f=43275,$=43284){let g=[];for(let M=f;M<=$;M+=1)g.push(M);return g}var Bg=new Set(["hello","frontend_hello","cli_status","browser_status","bridge_probe","bridge_probe_ack","bridge_ping","tool_metadata","run_turn","cancel_run","tool_result","request_tool_metadata","tool_call","partial_text","tool_activity","run_settled","runtime_rpc","runtime_rpc_result","warmup_run","warmup_result"]);function r$(f){try{let $=JSON.parse(f);if($&&typeof $==="object"&&typeof $.type==="string"&&Bg.has($.type))return $}catch{}return null}function e$(f){return JSON.stringify(f)}var f0=10485760,Ng=30000,wg=15000;function Hg(f){if(!f)return!1;let $;try{$=new URL(f)}catch{return!1}if($.origin==="https://ideawave.app"||$.origin==="https://ideawave-app-production.up.railway.app")return!0;if($.protocol!=="http:"&&$.protocol!=="https:")return!1;return $.hostname==="localhost"||$.hostname==="127.0.0.1"||$.hostname==="::1"}function ff(f,$){if(f.readyState!==Ug.OPEN)return;try{f.send(e$($))}catch{}}function Rg(f){if(typeof f==="string")return f;if(Buffer.isBuffer(f))return f.toString("utf8");if(Array.isArray(f))return Buffer.concat(f).toString("utf8");return Buffer.from(f).toString("utf8")}function qg(f){if(typeof f==="string")return f;if(Array.isArray(f))return f[0]??null;return null}function $0(f,$,g){f.write(`HTTP/1.1 ${$} ${g}\r
|
|
2
|
+
import{readFileSync as O1}from"node:fs";import{homedir as _1}from"node:os";import{join as j0}from"node:path";function w1(){let $=_1();switch(process.platform){case"win32":return process.env.APPDATA??j0($,"AppData","Roaming");case"darwin":return j0($,"Library","Application Support");default:return process.env.XDG_CONFIG_HOME??j0($,".config")}}function $$(){let $=process.env.IDEAWAVE_MCP_JSON_PATH;if($&&$.trim().length>0)return $;return j0(w1(),"ideawave","mcp.json")}var X$=null;function M$($){X$=$}var R1=86400000;function A1(){let $;try{$=O1($$(),"utf8")}catch{return null}let Z;try{Z=JSON.parse($)}catch{return null}if(typeof Z.url!=="string")return null;if(typeof Z.startedAt==="string"){let X=Date.parse(Z.startedAt);if(!Number.isNaN(X)){if(Date.now()-X>R1)return null}}if(typeof Z.pid==="number"&&Z.pid>0)try{process.kill(Z.pid,0)}catch(X){if(X?.code!=="EPERM")return null}return{url:Z.url}}function Z$($,Z={}){let X=[];if(Z.userId&&Z.userId.trim().length>0)X.push({name:"X-Ideawave-User-Id",value:Z.userId.trim()});if(Z.frontendSessionId&&Z.frontendSessionId.trim().length>0)X.push({name:"X-Ideawave-Frontend-Session-Id",value:Z.frontendSessionId.trim()});if(Z.cardId&&Z.cardId.trim().length>0)X.push({name:"X-Ideawave-Card-Id",value:Z.cardId.trim()});return{type:"http",name:"ideawave-board",url:$,headers:X}}function N0($={}){let Z=X$;if(Z)return Z$(Z.url,$);let X=A1();if(!X)return null;return Z$(X.url,$)}import{spawn as E1}from"node:child_process";import{closeSync as l1,existsSync as V$,mkdirSync as x$,openSync as I1,readFileSync as c1,renameSync as m1,rmSync as G$,statSync as h1,unlinkSync as S1,writeFileSync as u1}from"node:fs";import Q$ from"node:os";import a from"node:path";import{execFile as g1}from"node:child_process";import{promisify as y1}from"node:util";import{execFile as T1}from"node:child_process";import{promisify as b1}from"node:util";var v1=b1(T1),H0=new Map,W$=5000;async function J$($,Z=v1){let X=H0.get($);if(X&&X.expiresAt>Date.now())return X.value;let M=process.platform==="win32"?"where":"which";try{let{stdout:W}=await Z(M,[$],{timeout:2000}),J=W.split(/\r?\n/).find((x)=>x.trim().length>0),Q=J?J.trim():null;return H0.set($,{value:Q,expiresAt:Date.now()+W$}),Q}catch{return H0.set($,{value:null,expiresAt:Date.now()+W$}),null}}class s extends Error{code;constructor($,Z){super($);this.name="AcpError",this.code=Z}}class S extends s{constructor($="No ACP runtime configured"){super($,"RUNTIME_NOT_CONFIGURED");this.name="RuntimeNotConfiguredError"}}class q extends s{constructor($){super($,"RUNTIME_UNREACHABLE");this.name="RuntimeUnreachableError"}}class d extends s{authMethods;constructor($,Z){super($,"AUTH_REQUIRED");this.name="AuthRequiredError",this.authMethods=Z}}class u extends s{constructor($="ACP session timed out"){super($,"SESSION_TIMEOUT");this.name="SessionTimeoutError"}}var A3=y1(g1);function P($,...Z){return J$($,...Z)}function O($){let Z={};for(let[X,M]of Object.entries(process.env))if(typeof M==="string")Z[X]=M;return{...Z,...$??{}}}var P0=[{adapterId:"claude-code",runtimeBinary:"claude",packageName:"@agentclientprotocol/claude-agent-acp",version:"0.39.0",warmupArgs:["--cli","--help"]},{adapterId:"codex",runtimeBinary:"codex",packageName:"@zed-industries/codex-acp",version:"0.15.0",warmupArgs:["--help"]}],a1=1800000,q0=new Map;function f0(){if(process.env.IDEAWAVE_ACP_BRIDGE_CACHE_DIR)return process.env.IDEAWAVE_ACP_BRIDGE_CACHE_DIR;if(process.platform==="win32"){let $=process.env.LOCALAPPDATA??a.join(Q$.homedir(),"AppData","Local");return a.join($,"ideawave","acp-bridges")}return a.join(process.env.XDG_CACHE_HOME??a.join(Q$.homedir(),".cache"),"ideawave","acp-bridges")}function i1($){return $.replace(/^@/,"").replace(/[/\\]/g,"-")}function V0(){return a.join(f0(),"install-state.json")}function _0($){return a.join(f0(),`${i1($.packageName)}@${$.version}.install.lock`)}function w0(){return process.platform==="win32"?"npx.cmd":"npx"}function O0($){return`${$.packageName}@${$.version}`}function K$(){let $=V0();if(!V$($))return{};try{return JSON.parse(c1($,"utf8"))}catch{return{}}}function C0($,Z){let X=f0();x$(X,{recursive:!0});let M=K$();M.bridges={...M.bridges??{},[$.adapterId]:Z},u1(`${V0()}.tmp`,`${JSON.stringify(M,null,2)}
|
|
3
|
+
`),m1(`${V0()}.tmp`,V0())}function Y$($){return P0.find((Z)=>Z.packageName===$)??null}function A($,Z,X){return{adapterId:$.adapterId,packageName:$.packageName,version:$.version,status:Z,...X?{error:X}:{}}}function j$($,Z){return Z?.packageName===$.packageName&&Z.version===$.version}function D$($){try{return Date.now()-h1($).mtimeMs>a1}catch{return!1}}function p1($){let Z=_0($);if(!V$(Z))return!1;if(D$(Z))return G$(Z,{force:!0}),!1;return!0}function d1($){let Z=_0($);if(x$(a.dirname(Z),{recursive:!0}),D$(Z))G$(Z,{force:!0});try{let X=I1(Z,"wx");return l1(X),!0}catch{return!1}}function n1($){S1(_0($))}function R0($){let Z=K$().bridges?.[$.adapterId];if(j$($,Z)&&Z.status==="ready")return A($,"ready");if(q0.has($.adapterId)||p1($))return A($,"installing");if(j$($,Z)&&Z.status==="failed")return A($,"failed",Z.error);return A($,"missing")}function o1($){let Z=R0($);if(Z.status==="ready"||Z.status==="installing")return Z;if(!d1($))return A($,"installing");let X=A($,"installing");C0($,X);let M=()=>{},W=new Promise((G)=>{M=G});q0.set($.adapterId,W);let J=!1,Q=(G)=>{if(J)return;J=!0;try{n1($)}catch{}C0($,G),q0.delete($.adapterId),M(G)},x;try{x=E1(w0(),["-y",O0($),...$.warmupArgs],{stdio:"ignore",windowsHide:!0})}catch(G){let K=A($,"failed",G instanceof Error?G.message:String(G));return Q(K),K}return x.on("error",(G)=>{Q(A($,"failed",G.message))}),x.on("close",(G)=>{if(G===0){Q(A($,"ready"));return}Q(A($,"failed",`npx warmup exited ${G??"null"}`))}),x.unref(),X}function n($){let Z=Y$($);return Z?R0(Z):null}async function F$(){let $=[];for(let Z of P0){if(!await P(Z.runtimeBinary)){$.push(A(Z,"not_needed"));continue}$.push(o1(Z))}return $.filter((Z)=>Z.status!=="not_needed")}function x0($){let Z=Y$($);if(!Z)return null;if(R0(Z).status!=="ready")return null;return{command:w0(),args:["-y",O0(Z)],env:{}}}function A0($,Z){if($.command!==w0())return!1;let X=P0.find((M)=>$.args.includes(O0(M)));if(!X)return!1;return C0(X,A(X,"failed",Z)),!0}import{Readable as $2,Writable as Z2}from"node:stream";import{ClientSideConnection as N$,ndJsonStream as H$}from"@agentclientprotocol/sdk";import G0 from"node:fs/promises";import y from"node:path";var T0={fs:{readTextFile:!0,writeTextFile:!1},terminal:!1};class B$ extends Error{constructor($){super($);this.name="PathTraversalError"}}async function t1($,Z){let X=await G0.realpath($),M=y.resolve(X,Z),W;try{W=await G0.realpath(M)}catch(Q){if(Q.code!=="ENOENT")throw Q;let x=y.dirname(M),G=[y.basename(M)];while(x!==X&&x!==y.dirname(x))try{x=await G0.realpath(x);break}catch(K){if(K.code!=="ENOENT")throw K;G.unshift(y.basename(x)),x=y.dirname(x)}W=y.join(x,...G)}let J=y.relative(X,W);if(J.startsWith("..")||y.isAbsolute(J)||J==="..")throw new B$(`Path "${Z}" resolves outside the run folder`);return W}function k$($){return{readTextFile:async(Z)=>{let X=await t1($,Z.path);return{content:await G0.readFile(X,"utf-8")}}}}import{spawn as s1}from"node:child_process";function b0($){let Z=s1($.command,$.args,{cwd:$.cwd,env:$.env,stdio:["pipe","pipe","pipe"]});if(!Z.stdin||!Z.stdout||!Z.stderr)throw Error("Failed to allocate stdio streams for ACP subprocess");let{stdin:X,stdout:M,stderr:W}=Z,J=4096,Q=[],x=0;W.on("data",(D)=>{Q.push(D),x+=D.length;while(x>J*2&&Q.length>1){let H=Q.shift();if(H)x-=H.length}});let G=()=>{let D=Buffer.concat(Q).toString("utf8");return D.length>J?D.slice(-J):D},K=!1,j=!1,Y,z,U=new Promise((D)=>{Y=D}),F=new Promise((D)=>{z=D}),V=(D)=>{if(j)return;if(j=!0,Y(D),!K)z(D)};return Z.on("exit",(D,H)=>{V({code:D,signal:H,stderr:G()})}),Z.on("error",(D)=>{let H=G(),B=D?.message??String(D);V({code:null,signal:null,stderr:H?`${B}
|
|
4
|
+
${H}`:B})}),{stdin:X,stdout:M,stderr:W,kill:(D="SIGTERM")=>{if(K)return;K=!0;try{Z.kill(D)}catch{}},waitForExit:U,processCrashed:F}}function v0($){if($==="completed")return"completed";if($==="failed")return"failed";return"running"}var r1={delete_node:"Delete card",delete_nodes:"Delete cards",create_code_card:"Create code card",update_code_card:"Update code card",create_note_card:"Create note",update_note_card:"Update note",create_edge:"Create connection",update_edge:"Update connection",delete_edge:"Delete connection",create_flowchart:"Create flowchart",create_agent_card:"Spawn sub-agent",spawn_child_agents:"Spawn sub-agents",list_nodes:"Read board",list_edges:"Read connections",read_file:"Read file"};function g0($){let Z=r1[$];if(Z)return Z;let X=$.replaceAll(/[_-]+/g," ").trim().split(/\s+/);if(X.length>1&&X[0].toLowerCase()==="mcp")X.shift();if(X.length===0)return $;return X.map((M,W)=>W===0?M.charAt(0).toUpperCase()+M.slice(1):M).join(" ")}var e1=33;function z$($){let{ctx:Z,appendText:X,appendToolActivity:M}=$,W=$.flushIntervalMs??e1,J="",Q=0,x=null,G={},K=new Map,j=(B)=>{if(K.set(B.toolCallId,B),!M)return;M({boardId:Z.boardId,cardId:Z.cardId,runId:Z.runId,entry:B}).catch((k)=>{console.warn("[streamAdapter] appendToolActivity failed",k)})},Y="",z=0,U=null,F=null,V=(B)=>{if(B===Y)return;Y=B,z=Date.now(),X({boardId:Z.boardId,cardId:Z.cardId,runId:Z.runId,text:B}).catch((k)=>{console.warn("[streamAdapter] appendText failed",k)})},D=()=>{if(U!==null)clearTimeout(U),U=null;if(F!==null){let B=F;F=null,V(B)}},H=(B)=>{let k=Date.now()-z;if(k>=W&&U===null){V(B);return}if(F=B,U===null){let C=Math.max(0,W-k);U=setTimeout(()=>{U=null,D()},C)}};return{onSessionUpdate:async(B)=>{let k=B.update;switch(G[k.sessionUpdate]=(G[k.sessionUpdate]??0)+1,k.sessionUpdate){case"agent_message_chunk":{if(k.content.type==="text")J+=k.content.text,H(J);else{let C=`agent_message_chunk:${k.content.type}`;G[C]=(G[C]??0)+1}return}case"agent_thought_chunk":return;case"user_message_chunk":return;case"tool_call":{Q+=1;let C=typeof k.title==="string"&&k.title.length>0?k.title:"tool",R=v0(k.status),w=new Date().toISOString();j({toolCallId:k.toolCallId,rawTitle:C,title:g0(C),kind:typeof k.kind==="string"?k.kind:null,status:R,startedAt:w,completedAt:R==="running"?null:w});return}case"tool_call_update":{let C=K.get(k.toolCallId);if(!C){let p=typeof k.title==="string"&&k.title.length>0?k.title:"tool",g=v0(k.status),L=new Date().toISOString();j({toolCallId:k.toolCallId,rawTitle:p,title:g0(p),kind:typeof k.kind==="string"?k.kind:null,status:g,startedAt:L,completedAt:g==="running"?null:L});return}let R=k.status===void 0||k.status===null?C.status:v0(k.status),w=typeof k.title==="string"&&k.title.length>0?k.title:C.rawTitle,h=R==="running"?C.completedAt:C.completedAt??new Date().toISOString();j({...C,rawTitle:w,title:g0(w),kind:typeof k.kind==="string"?k.kind:C.kind,status:R,completedAt:h});return}case"plan":x=k.entries;return;case"available_commands_update":return;case"current_mode_update":return;default:return}},getFinalText:()=>J,getToolCallCount:()=>Q,getLatestPlan:()=>x,getUpdateTypeCounts:()=>({...G}),flush:D}}var r=1,U$=-32000;function L$($){if($.awaitingInput)return!1;return $.nowMs-$.lastUpdateMs>$.windowMs}function q$($){if(!$||typeof $!=="object")return!1;return $.code===U$}var X2=300000,M2=90000,W2=5000;function C$(){return{name:"ideawave-cli",title:"IdeaWave CLI",version:"0.0.18".trim()?"0.0.18":"dev"}}function P$($){if($===r)return;throw new q(`Unsupported ACP protocol version ${$}; expected ${r}`)}function f$($){return $2.toWeb($)}function _$($){return Z2.toWeb($)}function w$($){let Z=$.configOptions?.find((M)=>M.type==="select"&&(M.category==="model"||M.id==="model"));if(Z&&Array.isArray(Z.options)){let M=[];for(let W of Z.options)if(W&&typeof W==="object"&&"group"in W){let J=W.options;if(Array.isArray(J)){for(let Q of J)if(Q&&typeof Q.value==="string"&&typeof Q.name==="string")M.push({id:Q.value,name:Q.name,description:typeof Q.description==="string"?Q.description:null})}}else if(W&&typeof W.value==="string"&&typeof W.name==="string")M.push({id:W.value,name:W.name,description:typeof W.description==="string"?W.description:null});if(M.length>0)return M}let X=$.models?.availableModels?.map((M)=>({id:M.modelId,name:M.name??null,description:M.description??null}));return X&&X.length>0?X:null}function J2($,Z){let X=[];if($.trim())X.push({type:"text",text:$});for(let M of Z)if(M.content.trim())X.push({type:"text",text:M.content});return X}async function y0($){let Z=b0($.spawn),X=[],M=0,W=4096;Z.stderr.on("data",(L)=>{X.push(L),M+=L.length;while(M>W*2&&X.length>1){let _=X.shift();if(_)M-=_.length}});let J=()=>{let L=Buffer.concat(X).toString("utf8");return L.length>W?L.slice(-W):L},Q=k$($.spawn.cwd),x={current:null},G={at:Date.now()},K=_$(Z.stdin),j=f$(Z.stdout),Y=H$(K,j),U=new N$((L)=>({requestPermission:async(_)=>{let I=_.options?.find((Q0)=>Q0.kind==="allow_once"||Q0.kind==="allow_always");if(I)return{outcome:{outcome:"selected",optionId:I.optionId}};return{outcome:{outcome:"cancelled"}}},sessionUpdate:async(_)=>{G.at=Date.now();let I=x.current;if(I)await I.onSessionUpdate(_)},readTextFile:Q.readTextFile}),Y),F=()=>Z.kill();if($.signal)$.signal.addEventListener("abort",F);let V=()=>{if($.signal)$.signal.removeEventListener("abort",F)},D=async(L,_)=>{if(V(),Z.kill(),q$(L))throw new d(L.message??"Authentication required",_);if(L instanceof Error&&L.message==="ACP connection closed"){if($.signal?.aborted)throw new q("ACP session cancelled: abort signal received");let I=await Promise.race([Z.processCrashed,Z.waitForExit,new Promise((Q0)=>setTimeout(()=>Q0({stderr:""}),500))]);throw new q(`Runtime process exited before completion: ${I.stderr?.trim()??""}`)}throw L},H;try{H=await U.initialize({protocolVersion:r,clientCapabilities:T0,clientInfo:C$()})}catch(L){throw await D(L,[]),Error("unreachable")}try{P$(H.protocolVersion)}catch(L){throw V(),Z.kill(),L}let B=H.authMethods?.map((L)=>L.id)??[],k;try{k=await U.newSession({cwd:$.spawn.cwd,mcpServers:$.mcpServers??[]})}catch(L){throw await D(L,B),Error("unreachable")}let C=k.sessionId,R=w$(k),w=$.modelId??k.models?.currentModelId??null;if(w)try{await U.unstable_setSessionModel({sessionId:C,modelId:w})}catch(L){console.warn(`[acp] setSessionModel(${w}) failed; using agent default.`,L instanceof Error?L.message:L)}V();let h=!1,p=async()=>{if(h)return;h=!0,Z.kill(),await Promise.race([Z.waitForExit,new Promise((L)=>setTimeout(L,2000))])},g=!1;return Z.processCrashed.then(()=>{g=!0}),{sessionId:C,availableModels:R,isAlive:()=>!h&&!g,dispose:p,prompt:(L)=>Q2({proc:Z,conn:U,sessionId:C,activeAdapter:x,lastUpdate:G,collectStderrTail:J},L)}}async function Q2($,Z){let{proc:X,conn:M,sessionId:W,activeAdapter:J,lastUpdate:Q}=$,x={boardId:Z.boardId,cardId:Z.cardId,runId:Z.runId},G=z$({ctx:x,appendText:Z.appendText,appendToolActivity:Z.appendToolActivity});J.current=G,Q.at=Date.now();let K=!1,j=null,Y=null,z=()=>X.kill();Z.signal.addEventListener("abort",z);let U=Z.timeoutMs??X2;try{let F=async()=>{let B=Z.heartbeatMs??M2,k=Math.min(W2,Math.max(50,Math.floor(B/2)));Y=setInterval(()=>{let R=Z.isAwaitingInput?.()??!1;if(R){Q.at=Date.now();return}if(L$({nowMs:Date.now(),lastUpdateMs:Q.at,windowMs:B,awaitingInput:R}))K=!0,M.cancel({sessionId:W}).catch(()=>{return}),X.kill()},k);let C=J2(Z.prompt.systemPrompt,Z.prompt.messages);await M.prompt({sessionId:W,prompt:C}),G.flush()},V=X.waitForExit.then((B)=>({kind:"exited",exit:B})),D=F().then(()=>({kind:"ok"})).catch(async(B)=>{if(B instanceof Error&&B.message==="ACP connection closed")return{kind:"crashed",exit:await Promise.race([X.processCrashed,X.waitForExit])};throw B}),H=await Promise.race([D,X.processCrashed.then((B)=>({kind:"crashed",exit:B})),V,new Promise((B,k)=>{let C=()=>{j=setTimeout(()=>{if(Z.isAwaitingInput?.()){C();return}k({kind:"timeout"})},U)};C()}).catch((B)=>B)]);if(H.kind==="crashed")throw new q(`Runtime process exited before completion: ${H.exit.stderr.trim()}`);if(H.kind==="exited"){if(Z.signal.aborted)throw new q("ACP session cancelled: abort signal received");if(K)throw new u;throw new q(`Runtime process exited unexpectedly: ${H.exit.stderr.trim()}`)}if(H.kind==="timeout"||K)throw new u;return{modelReported:"unknown",finalText:G.getFinalText(),toolCallsExecuted:G.getToolCallCount(),stderrTail:$.collectStderrTail(),updateTypeCounts:G.getUpdateTypeCounts()}}finally{if(j!==null)clearTimeout(j);if(Y!==null)clearInterval(Y);Z.signal.removeEventListener("abort",z),G.flush(),J.current=null}}var j2=30000;async function O$($){let Z=b0($.spawn),X=_$(Z.stdin),M=f$(Z.stdout),W=H$(X,M),Q=new N$((K)=>({requestPermission:async()=>({outcome:{outcome:"cancelled"}}),sessionUpdate:async()=>{return},readTextFile:async()=>({content:""})}),W),x=()=>Z.kill();if($.signal)$.signal.addEventListener("abort",x);let G=null;try{let K=(async()=>{let Y=await Q.initialize({protocolVersion:r,clientCapabilities:T0,clientInfo:C$()});P$(Y.protocolVersion);let z=Y.authMethods?.map((D)=>D.id)??[],U;try{U=await Q.newSession({cwd:$.spawn.cwd,mcpServers:[]})}catch(D){if(q$(D))throw new d(D.message??"Authentication required",z);throw D}let F=w$(U)??[],V=U.models?.currentModelId??null;return Q.cancel({sessionId:U.sessionId}).catch(()=>{return}),{models:F,currentModelId:V}})(),j=new Promise((Y,z)=>{G=setTimeout(()=>{z(new u)},j2)});return await Promise.race([K,j])}catch(K){if(K instanceof Error&&K.message==="ACP connection closed")throw new q("Runtime process exited during model discovery.");throw K}finally{if(G)clearTimeout(G);if($.signal)$.signal.removeEventListener("abort",x);Z.kill()}}var f=new Map,E=null;function K0($){$.then((Z)=>Z.dispose()).catch(()=>{return})}function V2(){if(E!==null)return;E=setInterval(()=>{let $=Date.now();for(let[Z,X]of f){if(X.inUse)continue;if($-X.lastUsed<600000)continue;f.delete(Z),K0(X.sessionPromise)}if(f.size===0&&E!==null)clearInterval(E),E=null},60000),E.unref?.()}function x2(){if(f.size<200)return;let $=null,Z=1/0;for(let[M,W]of f){if(W.inUse)continue;if(W.lastUsed>=Z)continue;$=M,Z=W.lastUsed}if(!$)return;let X=f.get($);if(!X)return;f.delete($),K0(X.sessionPromise)}function E0($,Z,X){return`${$}:${Z}:${X}`}async function l0($){let Z=f.get($.key);if(Z)if(Z.fingerprint===$.fingerprint){Z.inUse=!0,Z.lastUsed=Date.now();try{let M=await Z.sessionPromise;if(M.isAlive())return M}catch{}f.delete($.key)}else f.delete($.key),K0(Z.sessionPromise);let X=$.open();x2(),f.set($.key,{key:$.key,fingerprint:$.fingerprint,sessionPromise:X,lastUsed:Date.now(),inUse:!0}),V2();try{return await X}catch(M){throw f.delete($.key),M}}function I0($,Z=!1){let X=f.get($);if(!X)return;if(Z){f.delete($),K0(X.sessionPromise);return}X.inUse=!1,X.lastUsed=Date.now()}async function G2(){let $=Array.from(f.values());if(f.clear(),E!==null)clearInterval(E),E=null;await Promise.all($.map((Z)=>Z.sessionPromise.then((X)=>X.dispose()).catch(()=>{return})))}function c0($){return[$.adapterId,$.configId??"",$.modelId??"",$.mcpUrl??""].join(" ")}var R$=!1;function K2(){if(R$)return;R$=!0;let $=()=>{G2()};process.once("beforeExit",$),process.once("SIGTERM",$),process.once("SIGINT",$)}K2();import e from"node:fs/promises";import B2 from"node:path";import{z as N}from"zod";var A$=N.object({id:N.string(),name:N.string().nullable().default(null),description:N.string().nullable().default(null)}),Y2=N.discriminatedUnion("kind",[N.object({id:N.string(),kind:N.literal("registered"),adapterId:N.enum(["claude-code","opencode","codex","copilot"]),displayName:N.string(),runFolder:N.string().nullable(),defaultModelId:N.string().nullable().default(null),discoveredModels:N.array(A$).default([]),discoveredAt:N.string().nullable().default(null)}),N.object({id:N.string(),kind:N.literal("custom"),displayName:N.string(),command:N.string(),args:N.array(N.string()),env:N.record(N.string(),N.string()),runFolder:N.string().nullable(),defaultModelId:N.string().nullable().default(null),discoveredModels:N.array(A$).default([]),discoveredAt:N.string().nullable().default(null)})]),T$=N.object({runtimeConfigId:N.string(),runFolder:N.string().nullable(),modelId:N.string().nullable().default(null)}),Y0=N.object({version:N.literal(1),globalDefaultConfigId:N.string().nullable(),runtimes:N.array(Y2),boardOverrides:N.record(N.string(),T$).default({}),cardOverrides:N.record(N.string(),T$).default({})});import D2 from"node:os";import D0 from"node:path";function F2(){let $=D2.homedir();switch(process.platform){case"win32":return process.env.APPDATA??D0.join($,"AppData","Roaming");case"darwin":return D0.join($,"Library","Application Support");default:return process.env.XDG_CONFIG_HOME??D0.join($,".config")}}function F0(){let $=process.env.IDEAWAVE_RUNTIME_CONFIG_PATH;if($)return $;return D0.join(F2(),"ideawave","runtimes.json")}var k2={version:1,globalDefaultConfigId:null,runtimes:[],boardOverrides:{},cardOverrides:{}},b$=new Map;function z2($){return b$.get($)??Promise.resolve()}function U2($,Z){b$.set($,Z)}async function b($){let Z=$??F0(),X;try{X=await e.readFile(Z,"utf-8")}catch(W){if(W.code==="ENOENT")return structuredClone(k2);throw W}return Y0.parse(JSON.parse(X))}async function v($,Z){let X=Z??F0(),M=z2(X).then(async()=>{let W=await b(X),J=structuredClone(W),Q=await $(J);return await L2(J,X),Q});return U2(X,M.catch(()=>{return})),M}async function L2($,Z){let X=Z??F0(),M=B2.dirname(X);await e.mkdir(M,{recursive:!0});let W=`${X}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`,J=JSON.stringify($,null,2);await e.writeFile(W,J,"utf-8");try{await e.rename(W,X)}catch(Q){throw await e.unlink(W).catch(()=>{return}),Q}}import q2 from"node:fs/promises";import S0 from"node:os";var v$="claude",m0="@agentclientprotocol/claude-agent-acp",g$=["claude-agent-acp","claude-code-acp"],y$="Install Claude Code from https://github.com/anthropics/claude-code",E$={id:"claude-code",displayName:"Claude Code",kind:"registered",resolveSpawnConfig:async()=>{if(!await P(v$))throw new q(`Claude Code CLI not found. ${y$}`);let Z=x0(m0);if(Z)return{command:Z.command,args:Z.args,env:O(Z.env)};let X=n(m0),M=X?.status==="installing";for(let J of g$){let Q=await P(J);if(Q&&!M&&X?.status!=="failed")return{command:Q,args:[],env:O()}}let W=X?.status==="failed"?`Claude Code ACP bridge install failed. ${X.error??"Restart IdeaWave CLI so it can warm the pinned bridge again."}`:"Claude Code ACP bridge is not ready. Keep IdeaWave CLI running and retry in a moment.";throw new q(W)},checkReadiness:async()=>{if(!await P(v$))return{status:"not_installed",detail:y$};let Z=n(m0);if(Z?.status==="ready")return{status:"ready"};if(Z?.status==="installing")return{status:"not_running",detail:"Installing Claude Code ACP bridge..."};if(Z?.status==="failed")return{status:"not_running",detail:Z.error??"Claude Code ACP bridge install failed. Restart IdeaWave CLI so it can warm the pinned bridge again."};for(let X of g$)if(await P(X))return{status:"ready"};return{status:"not_running",detail:"Installing Claude Code ACP bridge..."}},authHint:"Run `claude login` (or set ANTHROPIC_API_KEY)."};var l$="codex",h0="@zed-industries/codex-acp",I$="codex-acp",c$="Install Codex CLI from https://developers.openai.com/codex/cli",m$={id:"codex",displayName:"Codex",kind:"registered",resolveSpawnConfig:async()=>{if(!await P(l$))throw new q(`Codex CLI not found. ${c$}`);let Z=x0(h0);if(Z)return{command:Z.command,args:Z.args,env:O(Z.env)};let X=n(h0),M=X?.status==="installing",W=await P(I$);if(W&&!M&&X?.status!=="failed")return{command:W,args:[],env:O()};let J=X?.status==="failed"?`Codex ACP bridge install failed. ${X.error??"Restart IdeaWave CLI so it can warm the pinned bridge again."}`:"Codex ACP bridge is not ready. Keep IdeaWave CLI running and retry in a moment.";throw new q(J)},checkReadiness:async()=>{if(!await P(l$))return{status:"not_installed",detail:c$};let Z=n(h0);if(Z?.status==="ready")return{status:"ready"};if(Z?.status==="installing")return{status:"not_running",detail:"Installing Codex ACP bridge..."};if(Z?.status==="failed")return{status:"not_running",detail:Z.error??"Codex ACP bridge install failed. Restart IdeaWave CLI so it can warm the pinned bridge again."};if(await P(I$))return{status:"ready"};return{status:"not_running",detail:"Installing Codex ACP bridge..."}},authHint:"Run `codex login` (or set OPENAI_API_KEY)."};var h$="copilot",S$="copilot-acp",u$="npm i -g @github/copilot",a$={id:"copilot",displayName:"GitHub Copilot",kind:"registered",resolveSpawnConfig:async()=>{let $=await P(h$);if($)return{command:$,args:["--acp"],env:O()};let Z=await P(S$);if(Z)return{command:Z,args:[],env:O()};throw new q(`Copilot not installed. Run: ${u$}`)},checkReadiness:async()=>{if(await P(h$))return{status:"ready"};if(await P(S$))return{status:"ready"};return{status:"not_installed",detail:u$}},authHint:"Run `gh auth login` (or `copilot login`)."};import N2 from"node:fs/promises";function H2($){return $.startsWith("/")||/^[a-zA-Z]:[\\/]/.test($)}async function i$($){if(H2($))try{return await N2.access($),!0}catch{return!1}return await P($)!==null}var p$={id:"custom",displayName:"Custom ACP",kind:"custom",resolveSpawnConfig:async($)=>{if($.kind!=="custom")throw new q("customAdapter received non-custom entry");if(!await i$($.command))throw new q(`custom: command "${$.command}" not found`);return{command:$.command,args:$.args,env:O($.env)}},checkReadiness:async($)=>{if($.kind!=="custom")return{status:"unknown"};return await i$($.command)?{status:"ready"}:{status:"not_installed"}}};var d$="opencode",n$="Install OpenCode from https://opencode.ai",o$={id:"opencode",displayName:"OpenCode",kind:"registered",resolveSpawnConfig:async()=>{let $=await P(d$);if(!$)throw new q(`OpenCode not installed. ${n$}`);return{command:$,args:["acp"],env:O()}},checkReadiness:async()=>{if(!await P(d$))return{status:"not_installed",detail:n$};return{status:"ready"}},authHint:"Run `opencode auth login <provider>` (or set the provider's API-key env var)."};var t$={"claude-code":E$,opencode:o$,codex:m$,copilot:a$};function l($){if($.kind==="custom")return p$;let Z=t$[$.adapterId];if(!Z)throw Error(`Unknown registered adapter: ${$.adapterId}`);return Z}function o(){return Object.values(t$)}async function C2($){let Z={version:1,globalDefaultConfigId:null,runtimes:[],boardOverrides:{},cardOverrides:{}},X;try{X=await q2.readFile($,"utf-8")}catch(M){if(M.code==="ENOENT")return structuredClone(Z);throw M}return Y0.parse(JSON.parse(X))}async function $0($){let Z=$.configPath?await C2($.configPath):await b(),X=$.cardId?Z.cardOverrides[$.cardId]:void 0;if(X?.runtimeConfigId){let W=Z.runtimes.find((J)=>J.id===X.runtimeConfigId);if(W)return{entry:W,adapter:l(W),runFolder:X.runFolder??W.runFolder??S0.homedir(),modelId:X.modelId??W.defaultModelId??null}}let M=Z.boardOverrides[$.boardId];if(M?.runtimeConfigId){let W=Z.runtimes.find((J)=>J.id===M.runtimeConfigId);if(W)return{entry:W,adapter:l(W),runFolder:M.runFolder??W.runFolder??S0.homedir(),modelId:M.modelId??W.defaultModelId??null}}if(Z.globalDefaultConfigId){let W=Z.runtimes.find((J)=>J.id===Z.globalDefaultConfigId);if(W)return{entry:W,adapter:l(W),runFolder:X?.runFolder??M?.runFolder??W.runFolder??S0.homedir(),modelId:X?.modelId??M?.modelId??W.defaultModelId??null}}throw new S}var i=new Map,u0=new Set;function a0($){i.get($)?.controller.abort()}function s$($){for(let[Z,X]of i){if(X.frontendSessionId!==$)continue;X.controller.abort(),i.delete(Z)}}function r$(){for(let $ of i.values())$.controller.abort();i.clear()}function e$($,Z){if(!Z.availableModels||Z.availableModels.length===0)return;v((X)=>{let M=X.runtimes.find((W)=>W.id===$);if(M)M.discoveredModels=Z.availableModels??[]}).catch(()=>{return})}async function $1($,Z){let X=Date.now(),M=new AbortController;i.set($.runId,{controller:M,frontendSessionId:$.frontendSessionId}),u0.add($.cardId);let W=E0($.userId,$.frontendSessionId,$.cardId),J=!1,Q=null;try{let x=await $0({boardId:$.boardId,cardId:$.cardId}),G=await x.adapter.resolveSpawnConfig(x.entry);Q=G;let K=N0({userId:$.userId,frontendSessionId:$.frontendSessionId,cardId:$.cardId}),j=K?[K]:[],Y=$.modelHint??x.modelId,z=c0({adapterId:x.adapter.id,configId:x.entry.id,modelId:Y,mcpUrl:K?.url??null}),U=await l0({key:W,fingerprint:z,open:()=>y0({spawn:{...G,cwd:x.runFolder},mcpServers:j,modelId:Y,signal:M.signal})});e$(x.entry.id,U);let F;try{F=await U.prompt({runId:$.runId,boardId:$.boardId,cardId:$.cardId,prompt:{systemPrompt:$.systemPrompt,messages:$.promptMessages.map((V)=>({role:V.role,content:V.content}))},signal:M.signal,appendText:async({text:V})=>{Z({type:"partial_text",runId:$.runId,cardId:$.cardId,text:V})},appendToolActivity:async({entry:V})=>{Z({type:"tool_activity",runId:$.runId,cardId:$.cardId,activity:V})}})}catch(V){if(!U.isAlive()||V instanceof q)J=!0;throw V}Z({type:"run_settled",runId:$.runId,cardId:$.cardId,result:{assistantContent:F.finalText,model:F.modelReported??null,latencyMs:Date.now()-X,errorText:null,partialText:null}})}catch(x){let G=x instanceof Error?x.message:"Agent run failed";if(x instanceof q&&Q)A0(Q,G);console.error(`[ideawave-cli] run ${$.runId} failed:`,G),Z({type:"run_settled",runId:$.runId,cardId:$.cardId,result:{assistantContent:"",model:null,latencyMs:Date.now()-X,errorText:G,partialText:null}})}finally{I0(W,J),i.delete($.runId),u0.delete($.cardId)}}async function Z1($){if(u0.has($.cardId))return{status:"skipped"};let Z=E0($.userId,$.frontendSessionId,$.cardId),X=null;try{let M=await $0({boardId:$.boardId,cardId:$.cardId}),W=await M.adapter.resolveSpawnConfig(M.entry);X=W;let J=N0({userId:$.userId,frontendSessionId:$.frontendSessionId,cardId:$.cardId}),Q=J?[J]:[],x=c0({adapterId:M.adapter.id,configId:M.entry.id,modelId:M.modelId,mcpUrl:J?.url??null}),G=new AbortController,K=await l0({key:Z,fingerprint:x,open:()=>y0({spawn:{...W,cwd:M.runFolder},mcpServers:Q,modelId:M.modelId,signal:G.signal})});return e$(M.entry.id,K),I0(Z,!1),console.log(`[ideawave-cli] warmed runtime for card ${$.cardId}`),{status:"ready"}}catch(M){if(M instanceof S)return{status:"skipped"};let W=M instanceof Error?M.message:String(M);if(M instanceof q&&X)A0(X,W);if(M instanceof q&&/(not ready|installing|warming|retry in a moment)/i.test(W))return{status:"retryable",error:W};return console.warn(`[ideawave-cli] warmup failed for card ${$.cardId}:`,W),{status:"failed",error:W}}}import{randomUUID as _2}from"node:crypto";import{createServer as w2}from"node:http";import{WebSocket as j1,WebSocketServer as O2}from"ws";var i0="/cli-bridge";function p0($=43275,Z=43284){let X=[];for(let M=$;M<=Z;M+=1)X.push(M);return X}function X1($=p0(),Z="127.0.0.1",X="/cli-bridge"){return $.map((M)=>`ws://${Z}:${M}${X}`)}var P2=new Set(["hello","frontend_hello","cli_status","browser_status","bridge_probe","bridge_probe_ack","bridge_ping","bridge_pong","tool_metadata","run_turn","cancel_run","tool_result","request_tool_metadata","tool_call","partial_text","tool_activity","run_settled","runtime_rpc","runtime_rpc_result","warmup_run","warmup_result"]);function B0($){try{let Z=JSON.parse($);if(Z&&typeof Z==="object"&&typeof Z.type==="string"&&P2.has(Z.type))return Z}catch{}return null}function k0($){return JSON.stringify($)}var f2=800;function M1({candidates:$,createWebSocket:Z,timeoutMs:X=f2,setTimeoutFn:M=setTimeout,clearTimeoutFn:W=clearTimeout}){return new Promise((J,Q)=>{let x=0,G=!1,K=null,j=null,Y=(F,V)=>{if(F.removeEventListener("open",V.open),F.removeEventListener("message",V.message),F.removeEventListener("error",V.error),F.removeEventListener("close",V.close),j!==null)W(j),j=null},z=(F,V)=>{if(G)return;Y(F,V);try{F.close()}catch{}K=null,U()},U=()=>{if(G)return;let F=$[x];if(x+=1,!F){G=!0,Q(Error("No IdeaWave CLI bridge is reachable"));return}let V;try{V=Z(F)}catch{U();return}K=V;let D={open:()=>{if(G||K!==V)return;V.send(k0({type:"bridge_probe",protocolVersion:1}))},message:(H)=>{if(G||K!==V)return;if(B0(String(H?.data??""))?.type!=="bridge_probe_ack")return;G=!0,Y(V,D),J({url:F,socket:V})},error:()=>z(V,D),close:()=>z(V,D)};V.addEventListener("open",D.open),V.addEventListener("message",D.message),V.addEventListener("error",D.error),V.addEventListener("close",D.close),j=M(()=>z(V,D),X)};U()})}var W1=10485760,R2=30000,A2=15000,T2="http://127.0.0.1";async function V1($=X1(),Z=(X)=>new j1(X,{headers:{origin:T2}})){try{let{url:X,socket:M}=await M1({candidates:$,createWebSocket:Z});try{M.close()}catch{}return X}catch{return null}}function b2($){if(!$)return!1;let Z;try{Z=new URL($)}catch{return!1}if(Z.origin==="https://ideawave.app"||Z.origin==="https://ideawave-app-production.up.railway.app")return!0;if(Z.protocol!=="http:"&&Z.protocol!=="https:")return!1;return Z.hostname==="localhost"||Z.hostname==="127.0.0.1"||Z.hostname==="::1"}function t($,Z){if($.readyState!==j1.OPEN)return;try{$.send(k0(Z))}catch{}}function v2($){if(typeof $==="string")return $;if(Buffer.isBuffer($))return $.toString("utf8");if(Array.isArray($))return Buffer.concat($).toString("utf8");return Buffer.from($).toString("utf8")}function g2($){if(typeof $==="string")return $;if(Array.isArray($))return $[0]??null;return null}function J1($,Z,X){$.write(`HTTP/1.1 ${Z} ${X}\r
|
|
4
5
|
Connection: close\r
|
|
5
|
-
Content-Length: ${Buffer.byteLength(
|
|
6
|
+
Content-Length: ${Buffer.byteLength(X)}\r
|
|
6
7
|
\r
|
|
7
|
-
${g}`),f.destroy()}function Pg(f,$){return new Promise((g,M)=>{let Z=(x)=>{f.off("listening",l),M(x)},l=()=>{f.off("error",Z);let x=f.address();if(!x||typeof x==="string"){M(Error("Failed to read CLI bridge server address"));return}g(x.port)};f.once("error",Z),f.once("listening",l),f.listen($,"127.0.0.1")})}function g0(f){return new Promise(($,g)=>{f.close((M)=>{if(M)g(M);else $()})})}async function M0(f,$=s$()){let g=new Map,M=new Map,Z=!1,l=(C)=>{let J=M.get(C);if(J)clearTimeout(J);M.delete(C)},x=(C)=>{M.delete(C);let{activeRunIds:J}=f.registry.disconnect(C);f.onDisconnect(C,J)},X=(C,J)=>{let Q={type:"cli_status",connected:!0,runtime:f.runtime,mcpReady:f.mcpReady(),error:J};if(C){let K=g.get(C);if(K)ff(K,Q);return}for(let K of g.values())ff(K,Q)},j=(C,J)=>{let Q=J.sessionId.trim(),K=J.userId.trim();if(!Q||!K){ff(C,{type:"cli_status",connected:!1,runtime:f.runtime,mcpReady:f.mcpReady(),error:"Missing frontend session or user id"}),C.close();return}l(Q);let G=g.get(Q);if(G&&G!==C)G.close();C.data.frontendSessionId=Q,g.set(Q,C),f.registry.register({frontendSessionId:Q,userId:K,tools:J.tools,send:(D)=>ff(C,D)}),X(Q),f.onToolMetadata?.(Q)},F=(C,J)=>{let Q=f.registry.getUserId(C);if(!Q)return;switch(J.type){case"bridge_ping":break;case"tool_metadata":f.registry.setMetadata(C,J.tools),f.onToolMetadata?.(C);break;case"tool_result":f.registry.handleToolResult(C,J);break;case"run_turn":f.registry.markRunActive(C,J.run.runId,J.run.cardId),f.onRunTurn(C,{...J.run,frontendSessionId:C,userId:Q});break;case"cancel_run":if(f.registry.ownsRun(C,J.runId))f.onCancelRun(C,J.runId);break;case"runtime_rpc":f.onRuntimeRpc(C,J);break;case"warmup_run":f.onWarmupRun(C,{...J,frontendSessionId:C},Q);break;default:break}};for(let C of $){let J=zg((G,D)=>{D.writeHead(404,{"content-type":"text/plain"}),D.end("IdeaWave CLI bridge")}),Q=new cg({noServer:!0,maxPayload:f0}),K=(G)=>{if(G.idleTimer)clearTimeout(G.idleTimer);G.idleTimer=setTimeout(()=>{G.close()},Ng),G.idleTimer.unref?.()};Q.on("connection",(G)=>{let D=G;D.data={id:kg(),frontendSessionId:null},D.idleTimer=null,K(D),D.on("ping",()=>K(D)),D.on("pong",()=>K(D)),D.on("message",(k)=>{K(D);let N=Rg(k);if(N.length>f0)return;let W=r$(N);if(!W)return;let V=D.data.frontendSessionId;if(!V){if(W.type==="bridge_probe")ff(D,{type:"bridge_probe_ack",protocolVersion:W.protocolVersion});else if(W.type==="frontend_hello")j(D,W);return}F(V,W)}),D.on("close",()=>{if(D.idleTimer)clearTimeout(D.idleTimer);let k=D.data.frontendSessionId;if(!k)return;if(g.get(k)!==D)return;if(g.delete(k),l(k),Z)return;M.set(k,setTimeout(()=>x(k),wg))})}),J.on("upgrade",(G,D,k)=>{if(new URL(G.url??"/","http://127.0.0.1").pathname!==Ef){$0(D,404,"Not Found");return}if(!Hg(qg(G.headers.origin))){$0(D,403,"Forbidden");return}Q.handleUpgrade(G,D,k,(W)=>{Q.emit("connection",W,G)})});try{let G=await Pg(J,C);return{url:`ws://127.0.0.1:${G}${Ef}`,port:G,sendStatus:X,close:async()=>{Z=!0;for(let D of M.values())clearTimeout(D);M.clear();for(let D of Q.clients){let k=D;if(k.idleTimer)clearTimeout(k.idleTimer);k.close()}Q.close(),await g0(J).catch(()=>{return})}}}catch(G){if(Q.close(),await g0(J).catch(()=>{return}),G?.code==="EADDRINUSE")continue;throw G}}throw Error(`No free IdeaWave CLI bridge port found in ${$[0]}-${$.at(-1)}`)}import{Server as hg}from"@modelcontextprotocol/sdk/server/index.js";import{CallToolRequestSchema as ag,ListToolsRequestSchema as dg}from"@modelcontextprotocol/sdk/types.js";import{randomUUID as mg}from"node:crypto";import{createServer as Og}from"node:http";import{StreamableHTTPServerTransport as _g}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as C0}from"@modelcontextprotocol/sdk/types.js";var Z0=new Set(["127.0.0.1","localhost","[::1]","::1"]);function Lg(f){let $=f.trim();if($.length===0)return null;if($.startsWith("[")){let l=$.indexOf("]");if(l===-1)return null;let x=$.slice(0,l+1),X=$.slice(l+1);if(X.length===0)return{host:x,port:null};if(!X.startsWith(":"))return null;let j=Number(X.slice(1));if(!Number.isInteger(j)||j<=0||j>65535)return null;return{host:x,port:j}}let g=$.lastIndexOf(":");if(g===-1)return{host:$,port:null};let M=$.slice(g+1),Z=Number(M);if(!Number.isInteger(Z)||Z<=0||Z>65535)return{host:$,port:null};return{host:$.slice(0,g),port:Z}}function l0(f){return Z0.has(f)||Z0.has(f.toLowerCase())}function x0(f,$){let g=f.headers.host;if(typeof g!=="string")return{ok:!1,status:403,reason:"missing-host"};let M=Lg(g);if(!M)return{ok:!1,status:403,reason:"bad-host"};if(!l0(M.host))return{ok:!1,status:403,reason:"non-loopback-host"};if(M.port!==null&&M.port!==$)return{ok:!1,status:403,reason:"host-port-mismatch"};let Z=f.headers.origin;if(typeof Z==="string"&&Z.length>0){if(Z!=="null"){let l;try{l=new URL(Z)}catch{return{ok:!1,status:403,reason:"bad-origin"}}if(!l0(l.hostname))return{ok:!1,status:403,reason:"non-loopback-origin"}}}return{ok:!0}}var X0="/mcp",yg=43274,j0=16777216,Ig=1800000,Ag=300000,F0=200,vg=-32700,T=-32600,hf=-32603;function m(f,$,g,M,Z){f.statusCode=$,f.setHeader("content-type","application/json"),f.end(JSON.stringify({jsonrpc:"2.0",error:{code:g,message:M,...Z?{data:Z}:{}},id:null}))}class af extends Error{constructor(){super("expected application/json");this.name="BadContentTypeError"}}class df extends Error{constructor(){super(`body exceeds ${j0} bytes`);this.name="BodyTooLargeError"}}async function bg(f){if(f.method&&f.method!=="POST")return;let $=f.headers["content-type"];if(typeof $==="string"&&$.trim().length>0){if(!$.toLowerCase().includes("application/json"))throw new af}let g=0,M=[];for await(let l of f){let x=typeof l==="string"?Buffer.from(l):l;if(g+=x.byteLength,g>j0)throw new df;M.push(x)}if(M.length===0)return;let Z=Buffer.concat(M).toString("utf8");if(Z.length===0)return;return JSON.parse(Z)}function Tg(f){if(Array.isArray(f))return f.some(C0);return C0(f)}function ug(f){if(typeof f==="number")return f;let $=process.env.IDEAWAVE_MCP_PORT;if($&&$.trim().length>0){let g=Number($);if(Number.isInteger(g)&&g>=0&&g<65536)return g}return yg}async function Eg(f,$){let g=(Z)=>new Promise((l,x)=>{let X=(F)=>{f.off("listening",j),x(F)},j=()=>{f.off("error",X),l()};f.once("error",X),f.once("listening",j),f.listen(Z,"127.0.0.1")});try{await g($)}catch(Z){if(Z.code!=="EADDRINUSE"||$===0)throw Z;console.warn(`[mcp] port ${$} in use, falling back to an OS-assigned port; external CLIs will need to re-paste the install command from Settings → External agents`),await g(0)}let M=f.address();if(M==null||typeof M==="string")throw Error("[mcp] failed to read bound address");return M.port}function ig(f,$){if($&&typeof $==="object"&&!Array.isArray($)){let M=$.params;if(M&&typeof M==="object"&&!Array.isArray(M)){let Z=M.clientInfo;if(Z&&typeof Z==="object"&&!Array.isArray(Z)){let l=Z.name;if(typeof l==="string"&&l.trim().length>0)return l.trim()}}}let g=f.headers["user-agent"];if(typeof g==="string"&&g.trim().length>0)return g.trim();return null}async function D0(f){let $=new Map,g=0;function M(F){let C=$.get(F);if(C)C.lastActivity=Date.now()}async function Z(F,C){$.delete(F),await C.transport.close().catch(()=>{return})}async function l(){let F=null,C=1/0;for(let[J,Q]of $)if(Q.lastActivity<C)C=Q.lastActivity,F=J;if(F!==null){let J=$.get(F);if(J)console.warn(`[mcp] session cap of ${F0} reached; evicting ${F}`),await Z(F,J)}}let x=setInterval(()=>{let F=Date.now()-Ig;for(let[C,J]of $)if(J.lastActivity<F)console.log(`[mcp] sweeping idle session ${C}`),Z(C,J)},Ag);x.unref?.();let X=Og((F,C)=>{(async()=>{let J;try{J=new URL(F.url??"/","http://127.0.0.1").pathname}catch{m(C,400,T,"bad-url");return}if(J!==X0){m(C,404,T,"not-found");return}let Q=F.method??"POST";if(Q!=="POST"&&Q!=="GET"&&Q!=="DELETE"){C.setHeader("Allow","GET, POST, DELETE"),m(C,405,T,"method-not-allowed");return}let K=x0(F,g);if(!K.ok){m(C,K.status,T,"forbidden",{reason:K.reason});return}let G=F.headers["mcp-session-id"],D=typeof G==="string"?G:void 0;if(Q==="GET"||Q==="DELETE"){if(!D||!$.has(D)){m(C,400,T,"no-session",{hint:"Open a POST initialize first to receive an Mcp-Session-Id."});return}let W=$.get(D).transport;M(D);try{await W.handleRequest(F,C)}catch(V){if(console.error("[mcp] transport.handleRequest (GET/DELETE) threw",V),!C.headersSent)m(C,500,hf,"internal")}return}let k;try{k=await bg(F)}catch(W){if(W instanceof af){m(C,415,T,"expected-application-json");return}if(W instanceof df){m(C,413,T,"body-too-large");return}m(C,400,vg,"invalid-json");return}let N;if(D&&$.has(D))N=$.get(D).transport,M(D);else if(!D&&k!==void 0&&Tg(k)){let W=F.headers["x-ideawave-user-id"],V=typeof W==="string"&&W.trim().length>0?W.trim():null,U=F.headers["x-ideawave-frontend-session-id"],P=typeof U==="string"&&U.trim().length>0?U.trim():null,R=F.headers["x-ideawave-card-id"],E=typeof R==="string"&&R.trim().length>0?R.trim():null,S=ig(F,k);if($.size>=F0)await l();let y=null,Y=new _g({sessionIdGenerator:()=>mg(),onsessioninitialized:(H)=>{y=H,$.set(H,{transport:Y,lastActivity:Date.now()})},onsessionclosed:(H)=>{$.delete(H)}});Y.onclose=()=>{if(Y.sessionId)$.delete(Y.sessionId)};try{await f.buildServer({userId:V,frontendSessionId:P,cardId:E,clientHint:S}).connect(Y)}catch(H){if(console.error("[mcp] buildServer/connect failed",H),y)$.delete(y);await Y.close().catch(()=>{return}),m(C,500,hf,"server-init-failed");return}N=Y}else{m(C,400,T,"no-session",{hint:"Non-initialize requests must include a valid Mcp-Session-Id header obtained from a prior initialize."});return}try{await N.handleRequest(F,C,k)}catch(W){if(console.error("[mcp] transport.handleRequest threw",W),!C.headersSent)m(C,500,hf,"internal")}})().catch((J)=>{console.error("[mcp] unhandled request handler error:",J)})});return g=await Eg(X,ug(f.port)),{url:`http://127.0.0.1:${g}${X0}`,port:g,close:async()=>{clearInterval(x);for(let F of $.values())await F.transport.close().catch(()=>{return});$.clear(),await new Promise((F)=>X.close(()=>F()))}}}var Sg={name:"ideawave-board",version:"1.0.0"};function ng(f,$){return f.getMetadata($).map((g)=>({name:g.name,description:g.description,inputSchema:g.inputSchema}))}function pg(f,$,g){let M=new hg(Sg,{capabilities:{tools:{}}});return M.setRequestHandler(dg,async()=>({tools:ng(f,$)})),M.setRequestHandler(ag,async(Z)=>{let{name:l,arguments:x}=Z.params;try{let X=await f.callTool($,l,x??{},void 0,g??void 0);if(X&&typeof X==="object"&&Array.isArray(X.content))return X;return{content:[{type:"text",text:typeof X==="string"?X:JSON.stringify(X)}]}}catch(X){return{content:[{type:"text",text:X instanceof Error?X.message:"Tool call failed"}],isError:!0}}}),M}function J0(f,$){return D0({buildServer:(g)=>pg(f,g.frontendSessionId,g.cardId),port:$})}import K0 from"node:os";var Q0=new Map,Sf=new Map,og=30000;function Wf(f,$){let g=Q0.get(f);if(g&&g.expiresAt>Date.now())return Promise.resolve(g.value);let M=Sf.get(f);if(M)return M;let Z=$().then((l)=>{return Q0.set(f,{value:l,expiresAt:Date.now()+og}),l}).finally(()=>{Sf.delete(f)});return Sf.set(f,Z),Z}async function V0(f){let $=await Promise.all(o().map((l)=>Wf(l.id,async()=>({adapterId:l.id,...await l.checkReadiness({id:"__probe__",kind:"registered",adapterId:l.id,displayName:l.displayName,runFolder:null,defaultModelId:null,discoveredModels:[],discoveredAt:null})})))),M=(await O(f)).runtimes.filter((l)=>l.kind==="custom"),Z=await Promise.all(M.map((l)=>Wf(`custom:${l.id}`,async()=>({adapterId:l.id,...await v(l).checkReadiness(l)}))));return[...$,...Z]}async function W0(f,$){let g=o().find((l)=>l.id===f);if(g)return Wf(g.id,async()=>({adapterId:g.id,...await g.checkReadiness({id:"__probe__",kind:"registered",adapterId:g.id,displayName:g.displayName,runFolder:null,defaultModelId:null,discoveredModels:[],discoveredAt:null})}));let Z=(await O($)).runtimes.find((l)=>l.id===f);if(!Z||Z.kind!=="custom")return null;return Wf(`custom:${Z.id}`,async()=>({adapterId:Z.id,...await v(Z).checkReadiness(Z)}))}function G0(){return`cfg_${crypto.randomUUID().replace(/-/g,"").slice(0,16)}`}async function tg(){let[f,$]=await Promise.all([O(),V0()]),g=f.globalDefaultConfigId?f.runtimes.find((M)=>M.id===f.globalDefaultConfigId)??null:null;return{runtimes:f.runtimes,globalDefaultConfigId:f.globalDefaultConfigId,globalDefaultEffective:g?{runFolder:g.runFolder??K0.homedir(),modelId:g.defaultModelId??null}:null,knownAdapters:o().map((M)=>({id:M.id,displayName:M.displayName})),readiness:$}}async function sg(f){try{let $=await e({boardId:f.boardId,cardId:f.cardId});return{resolved:{configId:$.entry.id,adapterId:$.entry.kind==="registered"?$.entry.adapterId:null,displayName:$.entry.displayName,runFolder:$.runFolder,modelId:$.modelId}}}catch($){if($ instanceof i)return{resolved:null};throw $}}async function rg(f){return _(($)=>{let g=$.runtimes.find((l)=>l.kind==="registered"&&l.adapterId===f.adapterId);if(g)return g;let M=o().find((l)=>l.id===f.adapterId);if(!M)throw Error(`Unknown adapterId: ${f.adapterId}`);let Z={id:G0(),kind:"registered",adapterId:f.adapterId,displayName:M.displayName,runFolder:null,defaultModelId:null,discoveredModels:[],discoveredAt:null};return $.runtimes.push(Z),Z})}async function eg(f){return _(($)=>{let g={id:G0(),kind:"custom",displayName:f.displayName,command:f.command,args:f.args,env:f.env,runFolder:f.runFolder,defaultModelId:null,discoveredModels:[],discoveredAt:null};return $.runtimes.push(g),g})}async function f1(f){await _(($)=>{if($.runtimes=$.runtimes.filter((g)=>g.id!==f.runtimeConfigId),$.globalDefaultConfigId===f.runtimeConfigId)$.globalDefaultConfigId=null;for(let g of Object.keys($.boardOverrides))if($.boardOverrides[g].runtimeConfigId===f.runtimeConfigId)delete $.boardOverrides[g];for(let g of Object.keys($.cardOverrides))if($.cardOverrides[g].runtimeConfigId===f.runtimeConfigId)delete $.cardOverrides[g]})}async function $1(f){await _(($)=>{let g=$.runtimes.find((M)=>M.id===f.runtimeConfigId);if(!g)throw Error(`Runtime config not found: ${f.runtimeConfigId}`);if($.globalDefaultConfigId=f.runtimeConfigId,f.runFolder!==void 0)g.runFolder=f.runFolder;if(f.modelId!==void 0)g.defaultModelId=f.modelId})}async function g1(f){f.boardId,await _(($)=>{if(f.runtimeConfigId===null){delete $.cardOverrides[f.cardId];return}if(!$.runtimes.some((Z)=>Z.id===f.runtimeConfigId))throw Error(`Runtime config not found: ${f.runtimeConfigId}`);let M=$.cardOverrides[f.cardId];$.cardOverrides[f.cardId]={runtimeConfigId:f.runtimeConfigId,runFolder:f.runFolder!==void 0?f.runFolder:M?.runFolder??null,modelId:f.modelId!==void 0?f.modelId:M?.modelId??null}})}async function M1(f){let g=(await O()).runtimes.find((x)=>x.id===f.runtimeConfigId);if(!g)throw Error(`Runtime config not found: ${f.runtimeConfigId}`);let M=v(g),Z=await M.resolveSpawnConfig(g),l=g.runFolder??K0.homedir();try{let x=await c$({spawn:{...Z,cwd:l}}),X=new Date().toISOString();return await _((j)=>{let F=j.runtimes.find((C)=>C.id===f.runtimeConfigId);if(F)F.discoveredModels=x.models,F.discoveredAt=X}),{ok:!0,models:x.models,currentModelId:x.currentModelId}}catch(x){if(x instanceof n)throw Error(`${x.message}${M.authHint?` ${M.authHint}`:""}`);if(x instanceof z||x instanceof h)throw Error(x.message);throw x}}var Y0={list:tg,getEffectiveForCard:sg,registerRegistered:rg,registerCustom:eg,unregister:f1,setUserDefault:$1,setCardOverride:g1,refreshModels:M1};var Z1=[{id:"claude-code",displayName:"Claude Code"},{id:"codex",displayName:"Codex"},{id:"copilot",displayName:"Copilot"},{id:"opencode",displayName:"OpenCode"}];function l1(){return`cfg_${crypto.randomUUID().replace(/-/g,"").slice(0,16)}`}async function B0(){try{let f=await O();if(f.globalDefaultConfigId){if(f.runtimes.some((g)=>g.id===f.globalDefaultConfigId))return f.globalDefaultConfigId}for(let $ of Z1){if((await W0($.id))?.status!=="ready")continue;let M=null;if(await _((Z)=>{if(Z.globalDefaultConfigId){if(Z.runtimes.some((X)=>X.id===Z.globalDefaultConfigId)){M=Z.globalDefaultConfigId;return}}let l=Z.runtimes.find((x)=>x.kind==="registered"&&x.adapterId===$.id);if(!l){let x={id:l1(),kind:"registered",adapterId:$.id,displayName:$.displayName,runFolder:null,defaultModelId:null,discoveredModels:[],discoveredAt:null};Z.runtimes.push(x),l=x}Z.globalDefaultConfigId=l.id,M=l.id}),M)return console.log(`[ideawave-cli] using agent runtime: ${$.displayName}`),M}return console.warn("[ideawave-cli] no agent runtime detected on PATH (tried claude, codex, gh copilot, opencode). Install one to run agents."),null}catch(f){return console.warn("[ideawave-cli] runtime auto-seed failed",f),null}}function x1(){if(typeof crypto<"u"&&"randomUUID"in crypto)return`call_${crypto.randomUUID()}`;return`call_${Date.now()}_${Math.random().toString(16).slice(2)}`}class nf{sessions=new Map;createCallId;toolCallTimeoutMs;constructor(f={}){this.createCallId=f.createCallId??x1,this.toolCallTimeoutMs=f.toolCallTimeoutMs??120000}register(f){let $=this.sessions.get(f.frontendSessionId);if($){if($.userId!==f.userId)this.rejectPending($,"frontend session user changed"),$.activeRunIds.clear();this.sessions.set(f.frontendSessionId,{frontendSessionId:f.frontendSessionId,userId:f.userId,tools:f.tools,send:f.send,pendingToolCalls:$.pendingToolCalls,activeRunIds:$.activeRunIds,activeRunCardIds:$.activeRunCardIds});return}this.sessions.set(f.frontendSessionId,{frontendSessionId:f.frontendSessionId,userId:f.userId,tools:f.tools,send:f.send,pendingToolCalls:new Map,activeRunIds:new Set,activeRunCardIds:new Map})}disconnect(f,$="frontend session disconnected"){let g=this.sessions.get(f);if(!g)return{activeRunIds:[]};return this.sessions.delete(f),this.rejectPending(g,$),{activeRunIds:Array.from(g.activeRunIds)}}sessionCount(){return this.sessions.size}has(f){return this.sessions.has(f)}getUserId(f){return this.sessions.get(f)?.userId??null}setMetadata(f,$){let g=this.sessions.get(f);if(g)g.tools=$}getMetadata(f){if(!f)return[];return this.sessions.get(f)?.tools??[]}sendToSession(f,$){let g=this.sessions.get(f);if(!g)return!1;return g.send($),!0}callTool(f,$,g,M,Z){if(!f)return Promise.reject(Error("MCP tool call is missing a frontend session id"));let l=this.sessions.get(f);if(!l)return Promise.reject(Error(`Frontend session ${f} is not connected`));let x=this.createCallId();return new Promise((X,j)=>{let F=setTimeout(()=>{l.pendingToolCalls.delete(x),j(Error(`Tool "${$}" timed out waiting for the frontend`))},this.toolCallTimeoutMs),C=M??(Z?this.getActiveRunIdForCard(l,Z):this.getSoleActiveRunId(l)),J=Z??(C?l.activeRunCardIds.get(C):void 0);l.pendingToolCalls.set(x,{resolve:X,reject:j,timer:F}),l.send({type:"tool_call",callId:x,name:$,args:g,...C?{runId:C}:{},...J?{cardId:J}:{}})})}handleToolResult(f,$){let g=this.sessions.get(f);if(!g)return;let M=g.pendingToolCalls.get($.callId);if(!M)return;if(g.pendingToolCalls.delete($.callId),clearTimeout(M.timer),$.ok)M.resolve($.result);else M.reject(Error($.error??"Tool execution failed"))}markRunActive(f,$,g){let M=this.sessions.get(f);if(!M)return;if(M.activeRunIds.add($),g)M.activeRunCardIds.set($,g)}markRunSettled(f,$){let g=this.sessions.get(f);if(!g)return;g.activeRunIds.delete($),g.activeRunCardIds.delete($)}ownsRun(f,$){return this.sessions.get(f)?.activeRunIds.has($)??!1}rejectPending(f,$){for(let g of f.pendingToolCalls.values())clearTimeout(g.timer),g.reject(Error($));f.pendingToolCalls.clear()}getSoleActiveRunId(f){return f.activeRunIds.size===1?f.activeRunIds.values().next().value:void 0}getActiveRunIdForCard(f,$){let g=[...f.activeRunCardIds.entries()].filter(([M,Z])=>f.activeRunIds.has(M)&&Z===$).map(([M])=>M);return g.length===1?g[0]:void 0}}function C1(){return"0.0.17".trim()?"0.0.17":"dev"}var u=process.argv[2];if(u==="--help"||u==="-h"||u==="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(u==="--version"||u==="-v"||u==="version")console.log(C1()),process.exit(0);if(u)console.error(`Unknown command: ${u}`),console.error("Run `ideawave --help` for usage."),process.exit(1);var gf=new nf,lf=null;function Mf(f,$){gf.sendToSession(f,$)}async function X1(f,$){try{let g=Y0[$.method],M=await g($.params);Mf(f,{type:"runtime_rpc_result",requestId:$.requestId,ok:!0,result:M})}catch(g){Mf(f,{type:"runtime_rpc_result",requestId:$.requestId,ok:!1,error:g instanceof Error?g.message:String(g)})}}var Zf=!1,$f=null;async function pf(){if(Zf)return;if($f)return $f;return $f=(async()=>{try{let f=await J0(gf);rf({...f,requestedPort:f.port}),console.log(`[ideawave-cli] MCP endpoint for the agent: ${f.url}`);try{let $=await F$();for(let g of $)if(g.status==="failed")console.warn(`[ideawave-cli] ACP bridge setup failed for ${g.packageName}: ${g.error??"unknown error"}`)}catch($){console.warn("[ideawave-cli] ACP bridge setup skipped:",$ instanceof Error?$.message:String($))}await B0(),Zf=!0,console.log("[ideawave-cli] ready — agent runs will drive the board."),lf?.sendStatus()}catch(f){console.error("[ideawave-cli] failed to start agent host:",f),lf?.sendStatus(void 0,f instanceof Error?f.message:String(f))}finally{$f=null}})(),$f}lf=await M0({registry:gf,runtime:null,mcpReady:()=>Zf,onToolMetadata:(f)=>{console.log(`[ideawave-cli] session ${f} advertised ${gf.getMetadata(f).length} tools`),pf()},onRunTurn:(f,$)=>{console.log(`[ideawave-cli] running agent turn for card ${$.cardId} (session ${f})`),(async()=>{if(await pf(),!Zf){Mf(f,{type:"run_settled",runId:$.runId,cardId:$.cardId,result:{assistantContent:"",model:null,latencyMs:0,errorText:"IdeaWave CLI agent host is not ready",partialText:null}});return}await o$($,(g)=>Mf(f,g))})().catch(()=>{return}).finally(()=>gf.markRunSettled(f,$.runId))},onCancelRun:(f,$)=>{uf($)},onRuntimeRpc:(f,$)=>{X1(f,$)},onWarmupRun:(f,$,g)=>{(async()=>{if(await pf(),!Zf)return{status:"retryable",error:"agent host is not ready"};return t$({cardId:$.cardId,boardId:$.boardId,userId:g,frontendSessionId:f})})().then((M)=>{if(!$.warmupId)return;Mf(f,{type:"warmup_result",warmupId:$.warmupId,cardId:$.cardId,...M})})},onDisconnect:(f,$)=>{S$(f);for(let g of $)uf(g);console.log(`[ideawave-cli] browser session ${f} disconnected`)}});console.log(`[ideawave-cli] browser bridge listening on ${lf.url}`);console.log("[ideawave-cli] waiting for ideawave.app browser sessions…");var k0=!1;for(let f of["SIGINT","SIGTERM"])process.once(f,()=>{if(k0)return;k0=!0,n$(),(async()=>{await lf?.close().catch(()=>{return}),process.exit(0)})()});
|
|
8
|
+
${X}`),$.destroy()}function y2($,Z){return new Promise((X,M)=>{let W=(Q)=>{$.off("listening",J),M(Q)},J=()=>{$.off("error",W);let Q=$.address();if(!Q||typeof Q==="string"){M(Error("Failed to read CLI bridge server address"));return}X(Q.port)};$.once("error",W),$.once("listening",J),$.listen(Z,"127.0.0.1")})}function Q1($){return new Promise((Z,X)=>{$.close((M)=>{if(M)X(M);else Z()})})}async function x1($,Z=p0()){let X=new Map,M=new Map,W=!1,J=(j)=>{let Y=M.get(j);if(Y)clearTimeout(Y);M.delete(j)},Q=(j)=>{M.delete(j);let{activeRunIds:Y}=$.registry.disconnect(j);$.onDisconnect(j,Y)},x=(j,Y)=>{let z={type:"cli_status",connected:!0,runtime:$.runtime,mcpReady:$.mcpReady(),error:Y};if(j){let U=X.get(j);if(U)t(U,z);return}for(let U of X.values())t(U,z)},G=(j,Y)=>{let z=Y.sessionId.trim(),U=Y.userId.trim();if(!z||!U){t(j,{type:"cli_status",connected:!1,runtime:$.runtime,mcpReady:$.mcpReady(),error:"Missing frontend session or user id"}),j.close();return}J(z);let F=X.get(z);if(F&&F!==j)F.close();j.data.frontendSessionId=z,X.set(z,j),$.registry.register({frontendSessionId:z,userId:U,tools:Y.tools,send:(V)=>t(j,V)}),x(z),$.onToolMetadata?.(z)},K=(j,Y)=>{let z=$.registry.getUserId(j);if(!z)return;switch(Y.type){case"bridge_ping":{let U=X.get(j);if(U)t(U,{type:"bridge_pong"});break}case"tool_metadata":$.registry.setMetadata(j,Y.tools),$.onToolMetadata?.(j);break;case"tool_result":$.registry.handleToolResult(j,Y);break;case"run_turn":$.registry.markRunActive(j,Y.run.runId,Y.run.cardId),$.onRunTurn(j,{...Y.run,frontendSessionId:j,userId:z});break;case"cancel_run":if($.registry.ownsRun(j,Y.runId))$.onCancelRun(j,Y.runId);break;case"runtime_rpc":$.onRuntimeRpc(j,Y);break;case"warmup_run":$.onWarmupRun(j,{...Y,frontendSessionId:j},z);break;default:break}};for(let j of Z){let Y=w2((F,V)=>{V.writeHead(404,{"content-type":"text/plain"}),V.end("IdeaWave CLI bridge")}),z=new O2({noServer:!0,maxPayload:W1}),U=(F)=>{if(F.idleTimer)clearTimeout(F.idleTimer);F.idleTimer=setTimeout(()=>{F.close()},R2),F.idleTimer.unref?.()};z.on("connection",(F)=>{let V=F;V.data={id:_2(),frontendSessionId:null},V.idleTimer=null,U(V),V.on("ping",()=>U(V)),V.on("pong",()=>U(V)),V.on("message",(D)=>{U(V);let H=v2(D);if(H.length>W1)return;let B=B0(H);if(!B)return;let k=V.data.frontendSessionId;if(!k){if(B.type==="bridge_probe")t(V,{type:"bridge_probe_ack",protocolVersion:B.protocolVersion});else if(B.type==="frontend_hello")G(V,B);return}K(k,B)}),V.on("close",()=>{if(V.idleTimer)clearTimeout(V.idleTimer);let D=V.data.frontendSessionId;if(!D)return;if(X.get(D)!==V)return;if(X.delete(D),J(D),W)return;M.set(D,setTimeout(()=>Q(D),A2))})}),Y.on("upgrade",(F,V,D)=>{if(new URL(F.url??"/","http://127.0.0.1").pathname!==i0){J1(V,404,"Not Found");return}if(!b2(g2(F.headers.origin))){J1(V,403,"Forbidden");return}z.handleUpgrade(F,V,D,(B)=>{z.emit("connection",B,F)})});try{let F=await y2(Y,j);return{url:`ws://127.0.0.1:${F}${i0}`,port:F,sendStatus:x,close:async()=>{W=!0;for(let V of M.values())clearTimeout(V);M.clear();for(let V of z.clients){let D=V;if(D.idleTimer)clearTimeout(D.idleTimer);D.close()}z.close(),await Q1(Y).catch(()=>{return})}}}catch(F){if(z.close(),await Q1(Y).catch(()=>{return}),F?.code==="EADDRINUSE")continue;throw F}}throw Error(`No free IdeaWave CLI bridge port found in ${Z[0]}-${Z.at(-1)}`)}import{Server as o2}from"@modelcontextprotocol/sdk/server/index.js";import{CallToolRequestSchema as t2,ListToolsRequestSchema as s2}from"@modelcontextprotocol/sdk/types.js";import{randomUUID as l2}from"node:crypto";import{createServer as I2}from"node:http";import{StreamableHTTPServerTransport as c2}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as D1}from"@modelcontextprotocol/sdk/types.js";var G1=new Set(["127.0.0.1","localhost","[::1]","::1"]);function E2($){let Z=$.trim();if(Z.length===0)return null;if(Z.startsWith("[")){let J=Z.indexOf("]");if(J===-1)return null;let Q=Z.slice(0,J+1),x=Z.slice(J+1);if(x.length===0)return{host:Q,port:null};if(!x.startsWith(":"))return null;let G=Number(x.slice(1));if(!Number.isInteger(G)||G<=0||G>65535)return null;return{host:Q,port:G}}let X=Z.lastIndexOf(":");if(X===-1)return{host:Z,port:null};let M=Z.slice(X+1),W=Number(M);if(!Number.isInteger(W)||W<=0||W>65535)return{host:Z,port:null};return{host:Z.slice(0,X),port:W}}function K1($){return G1.has($)||G1.has($.toLowerCase())}function Y1($,Z){let X=$.headers.host;if(typeof X!=="string")return{ok:!1,status:403,reason:"missing-host"};let M=E2(X);if(!M)return{ok:!1,status:403,reason:"bad-host"};if(!K1(M.host))return{ok:!1,status:403,reason:"non-loopback-host"};if(M.port!==null&&M.port!==Z)return{ok:!1,status:403,reason:"host-port-mismatch"};let W=$.headers.origin;if(typeof W==="string"&&W.length>0){if(W!=="null"){let J;try{J=new URL(W)}catch{return{ok:!1,status:403,reason:"bad-origin"}}if(!K1(J.hostname))return{ok:!1,status:403,reason:"non-loopback-origin"}}}return{ok:!0}}var F1="/mcp",m2=43274,k1=16777216,h2=1800000,S2=300000,B1=200,u2=-32700,c=-32600,d0=-32603;function T($,Z,X,M,W){$.statusCode=Z,$.setHeader("content-type","application/json"),$.end(JSON.stringify({jsonrpc:"2.0",error:{code:X,message:M,...W?{data:W}:{}},id:null}))}class n0 extends Error{constructor(){super("expected application/json");this.name="BadContentTypeError"}}class o0 extends Error{constructor(){super(`body exceeds ${k1} bytes`);this.name="BodyTooLargeError"}}async function a2($){if($.method&&$.method!=="POST")return;let Z=$.headers["content-type"];if(typeof Z==="string"&&Z.trim().length>0){if(!Z.toLowerCase().includes("application/json"))throw new n0}let X=0,M=[];for await(let J of $){let Q=typeof J==="string"?Buffer.from(J):J;if(X+=Q.byteLength,X>k1)throw new o0;M.push(Q)}if(M.length===0)return;let W=Buffer.concat(M).toString("utf8");if(W.length===0)return;return JSON.parse(W)}function i2($){if(Array.isArray($))return $.some(D1);return D1($)}function p2($){if(typeof $==="number")return $;let Z=process.env.IDEAWAVE_MCP_PORT;if(Z&&Z.trim().length>0){let X=Number(Z);if(Number.isInteger(X)&&X>=0&&X<65536)return X}return m2}async function d2($,Z){let X=(W)=>new Promise((J,Q)=>{let x=(K)=>{$.off("listening",G),Q(K)},G=()=>{$.off("error",x),J()};$.once("error",x),$.once("listening",G),$.listen(W,"127.0.0.1")});try{await X(Z)}catch(W){if(W.code!=="EADDRINUSE"||Z===0)throw W;console.warn(`[mcp] port ${Z} in use, falling back to an OS-assigned port; external CLIs will need to re-paste the install command from Settings → External agents`),await X(0)}let M=$.address();if(M==null||typeof M==="string")throw Error("[mcp] failed to read bound address");return M.port}function n2($,Z){if(Z&&typeof Z==="object"&&!Array.isArray(Z)){let M=Z.params;if(M&&typeof M==="object"&&!Array.isArray(M)){let W=M.clientInfo;if(W&&typeof W==="object"&&!Array.isArray(W)){let J=W.name;if(typeof J==="string"&&J.trim().length>0)return J.trim()}}}let X=$.headers["user-agent"];if(typeof X==="string"&&X.trim().length>0)return X.trim();return null}async function z1($){let Z=new Map,X=0;function M(K){let j=Z.get(K);if(j)j.lastActivity=Date.now()}async function W(K,j){Z.delete(K),await j.transport.close().catch(()=>{return})}async function J(){let K=null,j=1/0;for(let[Y,z]of Z)if(z.lastActivity<j)j=z.lastActivity,K=Y;if(K!==null){let Y=Z.get(K);if(Y)console.warn(`[mcp] session cap of ${B1} reached; evicting ${K}`),await W(K,Y)}}let Q=setInterval(()=>{let K=Date.now()-h2;for(let[j,Y]of Z)if(Y.lastActivity<K)console.log(`[mcp] sweeping idle session ${j}`),W(j,Y)},S2);Q.unref?.();let x=I2((K,j)=>{(async()=>{let Y;try{Y=new URL(K.url??"/","http://127.0.0.1").pathname}catch{T(j,400,c,"bad-url");return}if(Y!==F1){T(j,404,c,"not-found");return}let z=K.method??"POST";if(z!=="POST"&&z!=="GET"&&z!=="DELETE"){j.setHeader("Allow","GET, POST, DELETE"),T(j,405,c,"method-not-allowed");return}let U=Y1(K,X);if(!U.ok){T(j,U.status,c,"forbidden",{reason:U.reason});return}let F=K.headers["mcp-session-id"],V=typeof F==="string"?F:void 0;if(z==="GET"||z==="DELETE"){if(!V||!Z.has(V)){T(j,400,c,"no-session",{hint:"Open a POST initialize first to receive an Mcp-Session-Id."});return}let B=Z.get(V).transport;M(V);try{await B.handleRequest(K,j)}catch(k){if(console.error("[mcp] transport.handleRequest (GET/DELETE) threw",k),!j.headersSent)T(j,500,d0,"internal")}return}let D;try{D=await a2(K)}catch(B){if(B instanceof n0){T(j,415,c,"expected-application-json");return}if(B instanceof o0){T(j,413,c,"body-too-large");return}T(j,400,u2,"invalid-json");return}let H;if(V&&Z.has(V))H=Z.get(V).transport,M(V);else if(!V&&D!==void 0&&i2(D)){let B=K.headers["x-ideawave-user-id"],k=typeof B==="string"&&B.trim().length>0?B.trim():null,C=K.headers["x-ideawave-frontend-session-id"],R=typeof C==="string"&&C.trim().length>0?C.trim():null,w=K.headers["x-ideawave-card-id"],h=typeof w==="string"&&w.trim().length>0?w.trim():null,p=n2(K,D);if(Z.size>=B1)await J();let g=null,L=new c2({sessionIdGenerator:()=>l2(),onsessioninitialized:(_)=>{g=_,Z.set(_,{transport:L,lastActivity:Date.now()})},onsessionclosed:(_)=>{Z.delete(_)}});L.onclose=()=>{if(L.sessionId)Z.delete(L.sessionId)};try{await $.buildServer({userId:k,frontendSessionId:R,cardId:h,clientHint:p}).connect(L)}catch(_){if(console.error("[mcp] buildServer/connect failed",_),g)Z.delete(g);await L.close().catch(()=>{return}),T(j,500,d0,"server-init-failed");return}H=L}else{T(j,400,c,"no-session",{hint:"Non-initialize requests must include a valid Mcp-Session-Id header obtained from a prior initialize."});return}try{await H.handleRequest(K,j,D)}catch(B){if(console.error("[mcp] transport.handleRequest threw",B),!j.headersSent)T(j,500,d0,"internal")}})().catch((Y)=>{console.error("[mcp] unhandled request handler error:",Y)})});return X=await d2(x,p2($.port)),{url:`http://127.0.0.1:${X}${F1}`,port:X,close:async()=>{clearInterval(Q);for(let K of Z.values())await K.transport.close().catch(()=>{return});Z.clear(),await new Promise((K)=>x.close(()=>K()))}}}var r2={name:"ideawave-board",version:"1.0.0"};function e2($,Z){return $.getMetadata(Z).map((X)=>({name:X.name,description:X.description,inputSchema:X.inputSchema}))}function $3($,Z,X){let M=new o2(r2,{capabilities:{tools:{}}});return M.setRequestHandler(s2,async()=>({tools:e2($,Z)})),M.setRequestHandler(t2,async(W)=>{let{name:J,arguments:Q}=W.params;try{let x=await $.callTool(Z,J,Q??{},void 0,X??void 0);if(x&&typeof x==="object"&&Array.isArray(x.content))return x;return{content:[{type:"text",text:typeof x==="string"?x:JSON.stringify(x)}]}}catch(x){return{content:[{type:"text",text:x instanceof Error?x.message:"Tool call failed"}],isError:!0}}}),M}function U1($,Z){return z1({buildServer:(X)=>$3($,X.frontendSessionId,X.cardId),port:Z})}import U0 from"node:fs/promises";import s0 from"node:os";import L0 from"node:path";var L1=new Map,t0=new Map,Z3=30000;function z0($,Z){let X=L1.get($);if(X&&X.expiresAt>Date.now())return Promise.resolve(X.value);let M=t0.get($);if(M)return M;let W=Z().then((J)=>{return L1.set($,{value:J,expiresAt:Date.now()+Z3}),J}).finally(()=>{t0.delete($)});return t0.set($,W),W}async function N1($){let Z=await Promise.all(o().map((J)=>z0(J.id,async()=>({adapterId:J.id,...await J.checkReadiness({id:"__probe__",kind:"registered",adapterId:J.id,displayName:J.displayName,runFolder:null,defaultModelId:null,discoveredModels:[],discoveredAt:null})})))),M=(await b($)).runtimes.filter((J)=>J.kind==="custom"),W=await Promise.all(M.map((J)=>z0(`custom:${J.id}`,async()=>({adapterId:J.id,...await l(J).checkReadiness(J)}))));return[...Z,...W]}async function H1($,Z){let X=o().find((J)=>J.id===$);if(X)return z0(X.id,async()=>({adapterId:X.id,...await X.checkReadiness({id:"__probe__",kind:"registered",adapterId:X.id,displayName:X.displayName,runFolder:null,defaultModelId:null,discoveredModels:[],discoveredAt:null})}));let W=(await b(Z)).runtimes.find((J)=>J.id===$);if(!W||W.kind!=="custom")return null;return z0(`custom:${W.id}`,async()=>({adapterId:W.id,...await l(W).checkReadiness(W)}))}function q1(){return`cfg_${crypto.randomUUID().replace(/-/g,"").slice(0,16)}`}async function X3(){let[$,Z]=await Promise.all([b(),N1()]),X=$.globalDefaultConfigId?$.runtimes.find((M)=>M.id===$.globalDefaultConfigId)??null:null;return{runtimes:$.runtimes,globalDefaultConfigId:$.globalDefaultConfigId,globalDefaultEffective:X?{runFolder:X.runFolder??s0.homedir(),modelId:X.defaultModelId??null}:null,knownAdapters:o().map((M)=>({id:M.id,displayName:M.displayName})),readiness:Z}}async function M3($){try{let Z=await $0({boardId:$.boardId,cardId:$.cardId});return{resolved:{configId:Z.entry.id,adapterId:Z.entry.kind==="registered"?Z.entry.adapterId:null,displayName:Z.entry.displayName,runFolder:Z.runFolder,modelId:Z.modelId}}}catch(Z){if(Z instanceof S)return{resolved:null};throw Z}}async function W3($){return v((Z)=>{let X=Z.runtimes.find((J)=>J.kind==="registered"&&J.adapterId===$.adapterId);if(X)return X;let M=o().find((J)=>J.id===$.adapterId);if(!M)throw Error(`Unknown adapterId: ${$.adapterId}`);let W={id:q1(),kind:"registered",adapterId:$.adapterId,displayName:M.displayName,runFolder:null,defaultModelId:null,discoveredModels:[],discoveredAt:null};return Z.runtimes.push(W),W})}async function J3($){return v((Z)=>{let X={id:q1(),kind:"custom",displayName:$.displayName,command:$.command,args:$.args,env:$.env,runFolder:$.runFolder,defaultModelId:null,discoveredModels:[],discoveredAt:null};return Z.runtimes.push(X),X})}async function Q3($){await v((Z)=>{if(Z.runtimes=Z.runtimes.filter((X)=>X.id!==$.runtimeConfigId),Z.globalDefaultConfigId===$.runtimeConfigId)Z.globalDefaultConfigId=null;for(let X of Object.keys(Z.boardOverrides))if(Z.boardOverrides[X].runtimeConfigId===$.runtimeConfigId)delete Z.boardOverrides[X];for(let X of Object.keys(Z.cardOverrides))if(Z.cardOverrides[X].runtimeConfigId===$.runtimeConfigId)delete Z.cardOverrides[X]})}async function j3($){await v((Z)=>{let X=Z.runtimes.find((M)=>M.id===$.runtimeConfigId);if(!X)throw Error(`Runtime config not found: ${$.runtimeConfigId}`);if(Z.globalDefaultConfigId=$.runtimeConfigId,$.runFolder!==void 0)X.runFolder=$.runFolder;if($.modelId!==void 0)X.defaultModelId=$.modelId})}async function V3($){$.boardId,await v((Z)=>{if($.runtimeConfigId===null){delete Z.cardOverrides[$.cardId];return}if(!Z.runtimes.some((W)=>W.id===$.runtimeConfigId))throw Error(`Runtime config not found: ${$.runtimeConfigId}`);let M=Z.cardOverrides[$.cardId];Z.cardOverrides[$.cardId]={runtimeConfigId:$.runtimeConfigId,runFolder:$.runFolder!==void 0?$.runFolder:M?.runFolder??null,modelId:$.modelId!==void 0?$.modelId:M?.modelId??null}})}async function x3($){let X=(await b()).runtimes.find((Q)=>Q.id===$.runtimeConfigId);if(!X)throw Error(`Runtime config not found: ${$.runtimeConfigId}`);let M=l(X),W=await M.resolveSpawnConfig(X),J=X.runFolder??s0.homedir();try{let Q=await O$({spawn:{...W,cwd:J}}),x=new Date().toISOString();return await v((G)=>{let K=G.runtimes.find((j)=>j.id===$.runtimeConfigId);if(K)K.discoveredModels=Q.models,K.discoveredAt=x}),{ok:!0,models:Q.models,currentModelId:Q.currentModelId}}catch(Q){if(Q instanceof d)throw Error(`${Q.message}${M.authHint?` ${M.authHint}`:""}`);if(Q instanceof q||Q instanceof u)throw Error(Q.message);throw Q}}async function G3($){let Z=s0.homedir(),X=$.path?.trim()?$.path.trim():Z,M=L0.resolve(X),W=!0;try{if(!(await U0.stat(M)).isDirectory())M=L0.dirname(M)}catch{W=!1,M=Z}let J=[];try{J=(await U0.readdir(M,{withFileTypes:!0})).filter((G)=>G.isDirectory()&&!G.name.startsWith(".")).map((G)=>({name:G.name,path:L0.join(M,G.name)})).sort((G,K)=>G.name.localeCompare(K.name))}catch{J=[]}let Q=L0.dirname(M);return{path:M,parent:Q===M?null:Q,home:Z,exists:W,entries:J}}var C1={list:X3,getEffectiveForCard:M3,registerRegistered:W3,registerCustom:J3,unregister:Q3,setUserDefault:j3,setCardOverride:V3,refreshModels:x3,browseFolder:G3};var K3=[{id:"claude-code",displayName:"Claude Code"},{id:"codex",displayName:"Codex"},{id:"copilot",displayName:"Copilot"},{id:"opencode",displayName:"OpenCode"}];function Y3(){return`cfg_${crypto.randomUUID().replace(/-/g,"").slice(0,16)}`}async function P1(){try{let $=await b();if($.globalDefaultConfigId){if($.runtimes.some((X)=>X.id===$.globalDefaultConfigId))return $.globalDefaultConfigId}for(let Z of K3){if((await H1(Z.id))?.status!=="ready")continue;let M=null;if(await v((W)=>{if(W.globalDefaultConfigId){if(W.runtimes.some((x)=>x.id===W.globalDefaultConfigId)){M=W.globalDefaultConfigId;return}}let J=W.runtimes.find((Q)=>Q.kind==="registered"&&Q.adapterId===Z.id);if(!J){let Q={id:Y3(),kind:"registered",adapterId:Z.id,displayName:Z.displayName,runFolder:null,defaultModelId:null,discoveredModels:[],discoveredAt:null};W.runtimes.push(Q),J=Q}W.globalDefaultConfigId=J.id,M=J.id}),M)return console.log(`[ideawave-cli] using agent runtime: ${Z.displayName}`),M}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 D3(){if(typeof crypto<"u"&&"randomUUID"in crypto)return`call_${crypto.randomUUID()}`;return`call_${Date.now()}_${Math.random().toString(16).slice(2)}`}class r0{sessions=new Map;createCallId;toolCallTimeoutMs;constructor($={}){this.createCallId=$.createCallId??D3,this.toolCallTimeoutMs=$.toolCallTimeoutMs??120000}register($){let Z=this.sessions.get($.frontendSessionId);if(Z){if(Z.userId!==$.userId)this.rejectPending(Z,"frontend session user changed"),Z.activeRunIds.clear();this.sessions.set($.frontendSessionId,{frontendSessionId:$.frontendSessionId,userId:$.userId,tools:$.tools,send:$.send,pendingToolCalls:Z.pendingToolCalls,activeRunIds:Z.activeRunIds,activeRunCardIds:Z.activeRunCardIds});return}this.sessions.set($.frontendSessionId,{frontendSessionId:$.frontendSessionId,userId:$.userId,tools:$.tools,send:$.send,pendingToolCalls:new Map,activeRunIds:new Set,activeRunCardIds:new Map})}disconnect($,Z="frontend session disconnected"){let X=this.sessions.get($);if(!X)return{activeRunIds:[]};return this.sessions.delete($),this.rejectPending(X,Z),{activeRunIds:Array.from(X.activeRunIds)}}sessionCount(){return this.sessions.size}has($){return this.sessions.has($)}getUserId($){return this.sessions.get($)?.userId??null}setMetadata($,Z){let X=this.sessions.get($);if(X)X.tools=Z}getMetadata($){if(!$)return[];return this.sessions.get($)?.tools??[]}sendToSession($,Z){let X=this.sessions.get($);if(!X)return!1;return X.send(Z),!0}callTool($,Z,X,M,W){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 Q=this.createCallId();return new Promise((x,G)=>{let K=setTimeout(()=>{J.pendingToolCalls.delete(Q),G(Error(`Tool "${Z}" timed out waiting for the frontend`))},this.toolCallTimeoutMs),j=M??(W?this.getActiveRunIdForCard(J,W):this.getSoleActiveRunId(J)),Y=W??(j?J.activeRunCardIds.get(j):void 0);J.pendingToolCalls.set(Q,{resolve:x,reject:G,timer:K}),J.send({type:"tool_call",callId:Q,name:Z,args:X,...j?{runId:j}:{},...Y?{cardId:Y}:{}})})}handleToolResult($,Z){let X=this.sessions.get($);if(!X)return;let M=X.pendingToolCalls.get(Z.callId);if(!M)return;if(X.pendingToolCalls.delete(Z.callId),clearTimeout(M.timer),Z.ok)M.resolve(Z.result);else M.reject(Error(Z.error??"Tool execution failed"))}markRunActive($,Z,X){let M=this.sessions.get($);if(!M)return;if(M.activeRunIds.add(Z),X)M.activeRunCardIds.set(Z,X)}markRunSettled($,Z){let X=this.sessions.get($);if(!X)return;X.activeRunIds.delete(Z),X.activeRunCardIds.delete(Z)}ownsRun($,Z){return this.sessions.get($)?.activeRunIds.has(Z)??!1}rejectPending($,Z){for(let X of $.pendingToolCalls.values())clearTimeout(X.timer),X.reject(Error(Z));$.pendingToolCalls.clear()}getSoleActiveRunId($){return $.activeRunIds.size===1?$.activeRunIds.values().next().value:void 0}getActiveRunIdForCard($,Z){let X=[...$.activeRunCardIds.entries()].filter(([M,W])=>$.activeRunIds.has(M)&&W===Z).map(([M])=>M);return X.length===1?X[0]:void 0}}function F3(){return"0.0.18".trim()?"0.0.18":"dev"}var m=process.argv[2];if(m==="--help"||m==="-h"||m==="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(m==="--version"||m==="-v"||m==="version")console.log(F3()),process.exit(0);if(m)console.error(`Unknown command: ${m}`),console.error("Run `ideawave --help` for usage."),process.exit(1);var X0=new r0,J0=null;function M0($,Z){X0.sendToSession($,Z)}async function B3($,Z){try{let X=C1[Z.method],M=await X(Z.params);M0($,{type:"runtime_rpc_result",requestId:Z.requestId,ok:!0,result:M})}catch(X){M0($,{type:"runtime_rpc_result",requestId:Z.requestId,ok:!1,error:X instanceof Error?X.message:String(X)})}}var W0=!1,Z0=null;async function e0(){if(W0)return;if(Z0)return Z0;return Z0=(async()=>{try{let $=await U1(X0);M$({...$,requestedPort:$.port}),console.log(`[ideawave-cli] MCP endpoint for the agent: ${$.url}`);try{let Z=await F$();for(let X of Z)if(X.status==="failed")console.warn(`[ideawave-cli] ACP bridge setup failed for ${X.packageName}: ${X.error??"unknown error"}`)}catch(Z){console.warn("[ideawave-cli] ACP bridge setup skipped:",Z instanceof Error?Z.message:String(Z))}await P1(),W0=!0,console.log("[ideawave-cli] ready — agent runs will drive the board."),J0?.sendStatus()}catch($){console.error("[ideawave-cli] failed to start agent host:",$),J0?.sendStatus(void 0,$ instanceof Error?$.message:String($))}finally{Z0=null}})(),Z0}if(process.env.APP_ENV!=="development"){let $=await V1();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)}J0=await x1({registry:X0,runtime:null,mcpReady:()=>W0,onToolMetadata:($)=>{console.log(`[ideawave-cli] session ${$} advertised ${X0.getMetadata($).length} tools`),e0()},onRunTurn:($,Z)=>{console.log(`[ideawave-cli] running agent turn for card ${Z.cardId} (session ${$})`),(async()=>{if(await e0(),!W0){M0($,{type:"run_settled",runId:Z.runId,cardId:Z.cardId,result:{assistantContent:"",model:null,latencyMs:0,errorText:"IdeaWave CLI agent host is not ready",partialText:null}});return}await $1(Z,(X)=>M0($,X))})().catch(()=>{return}).finally(()=>X0.markRunSettled($,Z.runId))},onCancelRun:($,Z)=>{a0(Z)},onRuntimeRpc:($,Z)=>{B3($,Z)},onWarmupRun:($,Z,X)=>{(async()=>{if(await e0(),!W0)return{status:"retryable",error:"agent host is not ready"};return Z1({cardId:Z.cardId,boardId:Z.boardId,userId:X,frontendSessionId:$})})().then((M)=>{if(!Z.warmupId)return;M0($,{type:"warmup_result",warmupId:Z.warmupId,cardId:Z.cardId,...M})})},onDisconnect:($,Z)=>{s$($);for(let X of Z)a0(X);console.log(`[ideawave-cli] browser session ${$} disconnected`)}});console.log(`[ideawave-cli] browser bridge listening on ${J0.url}`);console.log("[ideawave-cli] waiting for ideawave.app browser sessions…");var f1=!1;for(let $ of["SIGINT","SIGTERM"])process.once($,()=>{if(f1)return;f1=!0,r$(),(async()=>{await J0?.close().catch(()=>{return}),process.exit(0)})()});
|