diff --git a/ui/dist/bundle.js b/ui/dist/bundle.js index 61e0e86..f453bc6 100644 --- a/ui/dist/bundle.js +++ b/ui/dist/bundle.js @@ -1,4 +1,4 @@ -class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatuses:{},circuitBreakers:[],clients:[],clientFilterCategory:"all",clientSearchQuery:"",secrets:[],clientsCollapsed:!1,capabilities:[],capabilitiesHiddenByPolicy:0,resources:[],resourcesHiddenByPolicy:0,prompts:[],promptsHiddenByPolicy:0,catalogEvents:[],tasks:[],selectedTaskId:null,taskFilterStatus:"all",approvals:[],auditEvents:[],auditTotal:0,auditFilters:{search:"",status:"all",eventType:"all",serverId:"all",limit:25,offset:0},auditSelectedEvent:null,auditStats:null,auditVerification:null,selectedCapabilityId:null,selectedResourceId:null,selectedPromptId:null,playgroundMode:"tools",playgroundArgs:{},isExecuting:!1,playgroundAsyncTask:!1,activeRequestId:null,isBatchModalOpen:!1,batchSteps:[{id:"step_1",capability_id:"",argsJson:"{}",continue_on_error:!1},{id:"step_2",capability_id:"",argsJson:"{}",continue_on_error:!0}],activeTab:"overview",activeProfile:null,eventLogs:[],executionResult:null,resourceReadResult:null,promptGetResult:null,metrics:{totalCatalogRequests:0,totalEtagHits:0,totalToolCalls:0,totalToolDurationUs:0}};listeners=[];getState(){return this.state}setState(e){this.state={...this.state,...e},this.listeners.forEach((t)=>t(this.state))}subscribe(e){return this.listeners.push(e),()=>{this.listeners=this.listeners.filter((t)=>t!==e)}}addEventLog(e,t,a,o){let r=[{time:new Date().toLocaleTimeString(),method:e,target:t,status:a,latency:o},...this.state.eventLogs].slice(0,50);this.setState({eventLogs:r})}}var c=new ae;class ne{baseUrl;constructor(e=""){this.baseUrl=e}async getConfig(){return(await fetch(`${this.baseUrl}/v1/config`)).json()}async listCapabilities(e){let t={};if(e)t["X-Warmplane-Profile"]=e;return(await fetch(`${this.baseUrl}/v1/capabilities`,{headers:t})).json()}async listResources(e){let t={};if(e)t["X-Warmplane-Profile"]=e;return(await fetch(`${this.baseUrl}/v1/resources`,{headers:t})).json()}async readResource(e,t){let a=performance.now(),o={"Content-Type":"application/json"};if(t)o["X-Warmplane-Profile"]=t;let n=await fetch(`${this.baseUrl}/v1/resources/read`,{method:"POST",headers:o,body:JSON.stringify(e)}),r=performance.now()-a,s=await n.json();return{status:n.status,durationMs:r,data:s}}async listPrompts(e){let t={};if(e)t["X-Warmplane-Profile"]=e;return(await fetch(`${this.baseUrl}/v1/prompts`,{headers:t})).json()}async getPrompt(e,t){let a=performance.now(),o={"Content-Type":"application/json"};if(t)o["X-Warmplane-Profile"]=t;let n=await fetch(`${this.baseUrl}/v1/prompts/get`,{method:"POST",headers:o,body:JSON.stringify(e)}),r=performance.now()-a,s=await n.json();return{status:n.status,durationMs:r,data:s}}async getCatalogEvents(e){let t=e?`?after=${encodeURIComponent(e)}`:"";return(await fetch(`${this.baseUrl}/v1/catalog/events${t}`)).json()}async callCapability(e,t){let a=performance.now(),o={"Content-Type":"application/json"};if(t)o["X-Warmplane-Profile"]=t;let n=await fetch(`${this.baseUrl}/v1/tools/call`,{method:"POST",headers:o,body:JSON.stringify(e)}),r=performance.now()-a,s=await n.json();return{status:n.status,durationMs:r,data:s}}async batchCallCapabilities(e,t){let a=performance.now(),o={"Content-Type":"application/json"};if(t)o["X-Warmplane-Profile"]=t;let n=await fetch(`${this.baseUrl}/v1/tools/batch_call`,{method:"POST",headers:o,body:JSON.stringify({steps:e})}),r=performance.now()-a,s=await n.json();return{status:n.status,durationMs:r,data:s}}async cancelOperation(e){return(await fetch(`${this.baseUrl}/v1/operations/${encodeURIComponent(e)}/cancel`,{method:"POST"})).json()}async completeArgument(e){return(await fetch(`${this.baseUrl}/v1/completion/complete`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})).json()}async upsertServer(e,t){return(await fetch(`${this.baseUrl}/v1/config/servers`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,server:t})})).json()}async deleteServer(e){return(await fetch(`${this.baseUrl}/v1/config/servers/${encodeURIComponent(e)}`,{method:"DELETE"})).json()}async restartServer(e){return(await fetch(`${this.baseUrl}/v1/config/servers/${encodeURIComponent(e)}/restart`,{method:"POST"})).json()}async upsertProfile(e,t,a,o){return(await fetch(`${this.baseUrl}/v1/config/profiles`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,servers:t,description:a,policy:o})})).json()}async deleteProfile(e){return(await fetch(`${this.baseUrl}/v1/config/profiles/${encodeURIComponent(e)}`,{method:"DELETE"})).json()}async getEcosystemSources(){return(await fetch(`${this.baseUrl}/v1/config/ecosystem`)).json()}async importConfig(e,t=!1){return(await fetch(`${this.baseUrl}/v1/config/import`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({source_path:e,overwrite:t})})).json()}async savePolicy(e){let t={allow:e.allow||[],deny:e.deny||[],redactKeys:e.redact_keys||e.redactKeys||[],requireApproval:e.require_approval||e.requireApproval||[],approvalTimeoutSecs:e.approvalTimeoutSecs||e.approval_timeout_secs||300,webhook:e.webhook};return(await fetch(`${this.baseUrl}/v1/config/policy`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).json()}async listTasks(){return(await fetch(`${this.baseUrl}/v1/tasks`)).json()}async getTask(e){return(await fetch(`${this.baseUrl}/v1/tasks/${encodeURIComponent(e)}`)).json()}async updateTask(e,t){return(await fetch(`${this.baseUrl}/v1/tasks/${encodeURIComponent(e)}/update`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({inputResponses:t})})).json()}async cancelTask(e,t){return(await fetch(`${this.baseUrl}/v1/tasks/${encodeURIComponent(e)}/cancel`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({reason:t})})).json()}async listApprovals(){return(await fetch(`${this.baseUrl}/v1/approvals`)).json()}async approveTicket(e,t,a){return(await fetch(`${this.baseUrl}/v1/approvals/${encodeURIComponent(e)}/approve`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({operator:t,modified_args:a})})).json()}async rejectTicket(e,t,a){return(await fetch(`${this.baseUrl}/v1/approvals/${encodeURIComponent(e)}/reject`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({operator:t,reason:a})})).json()}async updateAlias(e,t,a,o,n,r){return(await fetch(`${this.baseUrl}/v1/config/alias`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({kind:e,alias:t,target:a,summary:o,description:n,passthrough:r})})).json()}async reloadConfig(){return(await fetch(`${this.baseUrl}/v1/config/reload`,{method:"POST"})).json()}async listAuditEvents(e){let t=new URLSearchParams;if(e?.actor_id)t.set("actor_id",e.actor_id);if(e?.server_id&&e.server_id!=="all")t.set("server_id",e.server_id);if(e?.capability_id)t.set("capability_id",e.capability_id);if(e?.event_type&&e.event_type!=="all")t.set("event_type",e.event_type);if(e?.status&&e.status!=="all")t.set("status",e.status);if(e?.trace_id)t.set("trace_id",e.trace_id);if(e?.request_id)t.set("request_id",e.request_id);if(e?.search)t.set("search",e.search);if(e?.limit)t.set("limit",String(e.limit));if(e?.offset!==void 0)t.set("offset",String(e.offset));let a=t.toString();return(await fetch(`${this.baseUrl}/v1/audit/events${a?`?${a}`:""}`)).json()}getAuditExportUrl(e,t="csv"){let a=new URLSearchParams;if(a.set("format",t),e?.actor_id)a.set("actor_id",e.actor_id);if(e?.server_id&&e.server_id!=="all")a.set("server_id",e.server_id);if(e?.capability_id)a.set("capability_id",e.capability_id);if(e?.event_type&&e.event_type!=="all")a.set("event_type",e.event_type);if(e?.status&&e.status!=="all")a.set("status",e.status);if(e?.trace_id)a.set("trace_id",e.trace_id);if(e?.request_id)a.set("request_id",e.request_id);if(e?.search)a.set("search",e.search);return`${this.baseUrl}/v1/audit/export?${a.toString()}`}async verifyAuditChain(){return(await fetch(`${this.baseUrl}/v1/audit/verify`)).json()}async getAuditStats(){return(await fetch(`${this.baseUrl}/v1/audit/stats`)).json()}async getClients(){return(await fetch(`${this.baseUrl}/v1/clients`)).json()}async attachClient(e,t,a="stdio",o){return(await fetch(`${this.baseUrl}/v1/clients/${encodeURIComponent(e)}/attach`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({profile:t||void 0,transport:a,http_url:o||void 0})})).json()}async detachClient(e){return(await fetch(`${this.baseUrl}/v1/clients/${encodeURIComponent(e)}/detach`,{method:"POST",headers:{"Content-Type":"application/json"}})).json()}async testWebhook(e,t){return(await fetch(`${this.baseUrl}/v1/webhooks/test`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:e||void 0,format:t||void 0})})).json()}async getSecrets(){return(await fetch(`${this.baseUrl}/v1/secrets`)).json()}async saveSecret(e,t,a){return(await fetch(`${this.baseUrl}/v1/secrets`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:e,value:t,service:a})})).json()}async deleteSecret(e){return(await fetch(`${this.baseUrl}/v1/secrets/${encodeURIComponent(e)}`,{method:"DELETE"})).json()}}var h=new ne;function oe(){let e=c.getState(),t=e.config.mcpServers||{},a=Object.keys(t),o=a.length,n="";if(a.length===0)n=` +function i(e){if(e===null||e===void 0)return"";return String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}class G{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatuses:{},circuitBreakers:[],clients:[],clientFilterCategory:"all",clientSearchQuery:"",secrets:[],clientsCollapsed:!1,capabilities:[],capabilitiesHiddenByPolicy:0,resources:[],resourcesHiddenByPolicy:0,prompts:[],promptsHiddenByPolicy:0,catalogEvents:[],tasks:[],selectedTaskId:null,taskFilterStatus:"all",approvals:[],auditEvents:[],auditTotal:0,auditFilters:{search:"",status:"all",eventType:"all",serverId:"all",limit:25,offset:0},auditSelectedEvent:null,auditStats:null,auditVerification:null,selectedCapabilityId:null,selectedResourceId:null,selectedPromptId:null,playgroundMode:"tools",playgroundArgs:{},isExecuting:!1,playgroundAsyncTask:!1,activeRequestId:null,isBatchModalOpen:!1,batchSteps:[{id:"step_1",capability_id:"",argsJson:"{}",continue_on_error:!1},{id:"step_2",capability_id:"",argsJson:"{}",continue_on_error:!0}],activeTab:"overview",activeProfile:null,eventLogs:[],executionResult:null,resourceReadResult:null,promptGetResult:null,metrics:{totalCatalogRequests:0,totalEtagHits:0,totalToolCalls:0,totalToolDurationUs:0}};listeners=[];getState(){return this.state}setState(e){this.state={...this.state,...e},this.listeners.forEach((t)=>t(this.state))}subscribe(e){return this.listeners.push(e),()=>{this.listeners=this.listeners.filter((t)=>t!==e)}}addEventLog(e,t,a,n){let r=[{time:new Date().toLocaleTimeString(),method:e,target:t,status:a,latency:n},...this.state.eventLogs].slice(0,50);this.setState({eventLogs:r})}}var p=new G;class Q{baseUrl;constructor(e=""){this.baseUrl=e}async getConfig(){return(await fetch(`${this.baseUrl}/v1/config`)).json()}async listCapabilities(e){let t={};if(e)t["X-Warmplane-Profile"]=e;return(await fetch(`${this.baseUrl}/v1/capabilities`,{headers:t})).json()}async listResources(e){let t={};if(e)t["X-Warmplane-Profile"]=e;return(await fetch(`${this.baseUrl}/v1/resources`,{headers:t})).json()}async readResource(e,t){let a=performance.now(),n={"Content-Type":"application/json"};if(t)n["X-Warmplane-Profile"]=t;let o=await fetch(`${this.baseUrl}/v1/resources/read`,{method:"POST",headers:n,body:JSON.stringify(e)}),r=performance.now()-a,s=await o.json();return{status:o.status,durationMs:r,data:s}}async listPrompts(e){let t={};if(e)t["X-Warmplane-Profile"]=e;return(await fetch(`${this.baseUrl}/v1/prompts`,{headers:t})).json()}async getPrompt(e,t){let a=performance.now(),n={"Content-Type":"application/json"};if(t)n["X-Warmplane-Profile"]=t;let o=await fetch(`${this.baseUrl}/v1/prompts/get`,{method:"POST",headers:n,body:JSON.stringify(e)}),r=performance.now()-a,s=await o.json();return{status:o.status,durationMs:r,data:s}}async getCatalogEvents(e){let t=e?`?after=${encodeURIComponent(e)}`:"";return(await fetch(`${this.baseUrl}/v1/catalog/events${t}`)).json()}async callCapability(e,t){let a=performance.now(),n={"Content-Type":"application/json"};if(t)n["X-Warmplane-Profile"]=t;let o=await fetch(`${this.baseUrl}/v1/tools/call`,{method:"POST",headers:n,body:JSON.stringify(e)}),r=performance.now()-a,s=await o.json();return{status:o.status,durationMs:r,data:s}}async batchCallCapabilities(e,t){let a=performance.now(),n={"Content-Type":"application/json"};if(t)n["X-Warmplane-Profile"]=t;let o=await fetch(`${this.baseUrl}/v1/tools/batch_call`,{method:"POST",headers:n,body:JSON.stringify({steps:e})}),r=performance.now()-a,s=await o.json();return{status:o.status,durationMs:r,data:s}}async cancelOperation(e){return(await fetch(`${this.baseUrl}/v1/operations/${encodeURIComponent(e)}/cancel`,{method:"POST"})).json()}async completeArgument(e){return(await fetch(`${this.baseUrl}/v1/completion/complete`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})).json()}async upsertServer(e,t){return(await fetch(`${this.baseUrl}/v1/config/servers`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,server:t})})).json()}async deleteServer(e){return(await fetch(`${this.baseUrl}/v1/config/servers/${encodeURIComponent(e)}`,{method:"DELETE"})).json()}async restartServer(e){return(await fetch(`${this.baseUrl}/v1/config/servers/${encodeURIComponent(e)}/restart`,{method:"POST"})).json()}async upsertProfile(e,t,a,n){return(await fetch(`${this.baseUrl}/v1/config/profiles`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,servers:t,description:a,policy:n})})).json()}async deleteProfile(e){return(await fetch(`${this.baseUrl}/v1/config/profiles/${encodeURIComponent(e)}`,{method:"DELETE"})).json()}async getEcosystemSources(){return(await fetch(`${this.baseUrl}/v1/config/ecosystem`)).json()}async importConfig(e,t=!1){return(await fetch(`${this.baseUrl}/v1/config/import`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({source_path:e,overwrite:t})})).json()}async savePolicy(e){let t={allow:e.allow||[],deny:e.deny||[],redactKeys:e.redact_keys||e.redactKeys||[],requireApproval:e.require_approval||e.requireApproval||[],approvalTimeoutSecs:e.approvalTimeoutSecs||e.approval_timeout_secs||300,webhook:e.webhook};return(await fetch(`${this.baseUrl}/v1/config/policy`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})).json()}async listTasks(){return(await fetch(`${this.baseUrl}/v1/tasks`)).json()}async getTask(e){return(await fetch(`${this.baseUrl}/v1/tasks/${encodeURIComponent(e)}`)).json()}async updateTask(e,t){return(await fetch(`${this.baseUrl}/v1/tasks/${encodeURIComponent(e)}/update`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({inputResponses:t})})).json()}async cancelTask(e,t){return(await fetch(`${this.baseUrl}/v1/tasks/${encodeURIComponent(e)}/cancel`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({reason:t})})).json()}async listApprovals(){return(await fetch(`${this.baseUrl}/v1/approvals`)).json()}async approveTicket(e,t,a){return(await fetch(`${this.baseUrl}/v1/approvals/${encodeURIComponent(e)}/approve`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({operator:t,modified_args:a})})).json()}async rejectTicket(e,t,a){return(await fetch(`${this.baseUrl}/v1/approvals/${encodeURIComponent(e)}/reject`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({operator:t,reason:a})})).json()}async updateAlias(e,t,a,n,o,r){return(await fetch(`${this.baseUrl}/v1/config/alias`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({kind:e,alias:t,target:a,summary:n,description:o,passthrough:r})})).json()}async reloadConfig(){return(await fetch(`${this.baseUrl}/v1/config/reload`,{method:"POST"})).json()}async listAuditEvents(e){let t=new URLSearchParams;if(e?.actor_id)t.set("actor_id",e.actor_id);if(e?.server_id&&e.server_id!=="all")t.set("server_id",e.server_id);if(e?.capability_id)t.set("capability_id",e.capability_id);if(e?.event_type&&e.event_type!=="all")t.set("event_type",e.event_type);if(e?.status&&e.status!=="all")t.set("status",e.status);if(e?.trace_id)t.set("trace_id",e.trace_id);if(e?.request_id)t.set("request_id",e.request_id);if(e?.search)t.set("search",e.search);if(e?.limit)t.set("limit",String(e.limit));if(e?.offset!==void 0)t.set("offset",String(e.offset));let a=t.toString();return(await fetch(`${this.baseUrl}/v1/audit/events${a?`?${a}`:""}`)).json()}getAuditExportUrl(e,t="csv"){let a=new URLSearchParams;if(a.set("format",t),e?.actor_id)a.set("actor_id",e.actor_id);if(e?.server_id&&e.server_id!=="all")a.set("server_id",e.server_id);if(e?.capability_id)a.set("capability_id",e.capability_id);if(e?.event_type&&e.event_type!=="all")a.set("event_type",e.event_type);if(e?.status&&e.status!=="all")a.set("status",e.status);if(e?.trace_id)a.set("trace_id",e.trace_id);if(e?.request_id)a.set("request_id",e.request_id);if(e?.search)a.set("search",e.search);return`${this.baseUrl}/v1/audit/export?${a.toString()}`}async verifyAuditChain(){return(await fetch(`${this.baseUrl}/v1/audit/verify`)).json()}async getAuditStats(){return(await fetch(`${this.baseUrl}/v1/audit/stats`)).json()}async getClients(){return(await fetch(`${this.baseUrl}/v1/clients`)).json()}async attachClient(e,t,a="stdio",n){return(await fetch(`${this.baseUrl}/v1/clients/${encodeURIComponent(e)}/attach`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({profile:t||void 0,transport:a,http_url:n||void 0})})).json()}async detachClient(e){return(await fetch(`${this.baseUrl}/v1/clients/${encodeURIComponent(e)}/detach`,{method:"POST",headers:{"Content-Type":"application/json"}})).json()}async testWebhook(e,t){return(await fetch(`${this.baseUrl}/v1/webhooks/test`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:e||void 0,format:t||void 0})})).json()}async getSecrets(){return(await fetch(`${this.baseUrl}/v1/secrets`)).json()}async saveSecret(e,t,a){return(await fetch(`${this.baseUrl}/v1/secrets`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:e,value:t,service:a})})).json()}async deleteSecret(e){return(await fetch(`${this.baseUrl}/v1/secrets/${encodeURIComponent(e)}`,{method:"DELETE"})).json()}}var h=new Q;function Y(){let e=p.getState(),t=e.config.mcpServers||{},a=Object.keys(t),n=a.length,o="";if(a.length===0)o=`
No Upstream MCP Servers Connected
Initialize connections by adding a server or syncing existing IDE configurations.
@@ -8,21 +8,21 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- `;else n=a.map((E)=>{let O=t[E],W=O.command?"stdio":"http / sse",K=O.command?`${O.command} ${(O.args||[]).join(" ")}`:O.url,F=e.serverStatuses[E]||{status:"connected",protocol_version:"2026-07-28"},G=F.status==="degraded",re=F.status==="error"||F.status==="disconnected",Z=G?"var(--amber-400)":re?"var(--red-400)":"var(--green-400)";return` + `;else o=a.map((S)=>{let P=t[S],q=P.command?"stdio":"http / sse",H=P.command?`${P.command} ${(P.args||[]).join(" ")}`:P.url,z=e.serverStatuses[S]||{status:"connected",protocol_version:"2026-07-28"},F=z.status==="degraded",V=z.status==="error"||z.status==="disconnected",U=F?"var(--amber-400)":V?"var(--red-400)":"var(--green-400)";return`
- - ${M(E)} + + ${i(S)} - ${W} + ${q}
-
- ${M(K||"")} +
+ ${i(H||"")}
- Status: ${M(F.status)} - Protocol: ${F.protocol_version} + Status: ${i(z.status)} + Protocol: ${z.protocol_version}
`}).join("");let r=e.eventLogs.length===0?` @@ -33,62 +33,62 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu CONNECTED 0.0ms
- `:e.eventLogs.map((E)=>` + `:e.eventLogs.map((S)=>`
- ${M(E.time)} - ${M(E.method)} - ${M(E.target)} - ${M(E.status)} - ${M(E.latency)} + ${i(S.time)} + ${i(S.method)} + ${i(S.target)} + ${i(S.status)} + ${i(S.latency)}
- `).join(""),s=e.metrics,i=s.totalCatalogRequests,l=s.totalEtagHits,u=i>0?`${(l/i*100).toFixed(1)}%`:"0.0%",p=i>0?`${l} of ${i} requests served via HTTP 304`:"Waiting for client requests",g=s.totalToolCalls,m=g>0?`${(s.totalToolDurationUs/g/1000).toFixed(1)}ms`:"0.0ms",d=g>0?`${g} tool executions processed`:"Local worker task queues warm",y=Object.keys(e.config.capabilityAliases||{}).length+Object.keys(e.config.resourceAliases||{}).length+Object.keys(e.config.promptAliases||{}).length,b=y>0?`${y*18}B / call`:"0B",v=y>0?`${y} active facade aliases pruning prompt size`:"Configure aliases in Studio to reduce prompt size",x=e.tasks||[],A=x.filter((E)=>E.status==="input_required").length,R=x.filter((E)=>E.status==="working"||E.status==="input_required").length,T=e.clients||[],S=T.filter((E)=>E.is_attached).length,w=T.filter((E)=>E.config_exists&&!E.is_attached).length,z=e.clientsCollapsed,L=S>0?`⚡ ${S} Connected`:w>0?`○ ${w} Ready to Connect`:'No Apps Detected',N=Object.keys(e.config.profiles||{}),D=e.activeProfile,q=e.clientFilterCategory||"all",U=(e.clientSearchQuery||"").toLowerCase().trim(),V=T.filter((E)=>{if(U){let O=E.name.toLowerCase().includes(U),W=E.id.toLowerCase().includes(U),K=E.category.toLowerCase().includes(U);if(!O&&!W&&!K)return!1}if(q==="connected")return E.is_attached;if(q==="ready")return E.config_exists||E.app_installed;if(q==="ides")return E.category.toLowerCase().includes("ide")||E.category.toLowerCase().includes("extension");if(q==="agents")return E.category.toLowerCase().includes("agent")||E.category.toLowerCase().includes("cli")||E.category.toLowerCase().includes("platform");return!0}),te=V.length===0?'
No AI clients match current filter.
':V.map((E)=>{let{is_attached:O,config_exists:W,app_installed:K}=E,F="rgba(255, 255, 255, 0.2)",G="Not Found";if(O){F="var(--green-400)";let J=E.attached_transport==="http"?"HTTP":"stdio";G=E.attached_profile?`Connected · ${J} (${E.attached_profile})`:`Connected · ${J} (All Tools)`}else if(W)F="var(--amber-300)",G="Ready to Attach";else if(K)F="var(--cyan-400)",G="Installed";let re=N.map((J)=>` - - `).join(""),Z=O?``:W||K?` + `).join(""),s=e.metrics,l=s.totalCatalogRequests,d=s.totalEtagHits,g=l>0?`${(d/l*100).toFixed(1)}%`:"0.0%",u=l>0?`${d} of ${l} requests served via HTTP 304`:"Waiting for client requests",m=s.totalToolCalls,v=m>0?`${(s.totalToolDurationUs/m/1000).toFixed(1)}ms`:"0.0ms",c=m>0?`${m} tool executions processed`:"Local worker task queues warm",y=Object.keys(e.config.capabilityAliases||{}).length+Object.keys(e.config.resourceAliases||{}).length+Object.keys(e.config.promptAliases||{}).length,b=y>0?`${y*18}B / call`:"0B",f=y>0?`${y} active facade aliases pruning prompt size`:"Configure aliases in Studio to reduce prompt size",x=e.tasks||[],T=x.filter((S)=>S.status==="input_required").length,I=x.filter((S)=>S.status==="working"||S.status==="input_required").length,E=e.clients||[],k=E.filter((S)=>S.is_attached).length,w=E.filter((S)=>S.config_exists&&!S.is_attached).length,C=e.clientsCollapsed,A=k>0?`⚡ ${k} Connected`:w>0?`○ ${w} Ready to Connect`:'No Apps Detected',L=Object.keys(e.config.profiles||{}),M=e.activeProfile,R=e.clientFilterCategory||"all",B=(e.clientSearchQuery||"").toLowerCase().trim(),O=E.filter((S)=>{if(B){let P=S.name.toLowerCase().includes(B),q=S.id.toLowerCase().includes(B),H=S.category.toLowerCase().includes(B);if(!P&&!q&&!H)return!1}if(R==="connected")return S.is_attached;if(R==="ready")return S.config_exists||S.app_installed;if(R==="ides")return S.category.toLowerCase().includes("ide")||S.category.toLowerCase().includes("extension");if(R==="agents")return S.category.toLowerCase().includes("agent")||S.category.toLowerCase().includes("cli")||S.category.toLowerCase().includes("platform");return!0}),J=O.length===0?'
No AI clients match current filter.
':O.map((S)=>{let{is_attached:P,config_exists:q,app_installed:H}=S,z="rgba(255, 255, 255, 0.2)",F="Not Found";if(P){z="var(--green-400)";let j=S.attached_transport==="http"?"HTTP":"stdio";F=S.attached_profile?`Connected · ${j} (${S.attached_profile})`:`Connected · ${j} (All Tools)`}else if(q)z="var(--amber-300)",F="Ready to Attach";else if(H)z="var(--cyan-400)",F="Installed";let V=L.map((j)=>` + + `).join(""),U=P?``:q||H?`
- ${N.length>0?` - + + ${V} `:""} - +
`:"";return`
- +
-
${M(E.name)}
-
${M(G)}
+
${i(S.name)}
+
${i(F)}
- ${Z} + ${U}
- `}).join(""),se=[{id:"all",label:"All"},{id:"ready",label:"Ready / Installed"},{id:"connected",label:"Connected"},{id:"ides",label:"IDEs"},{id:"agents",label:"Agents & CLIs"}].map((E)=>``).join(""),B=` + `}).join(""),W=[{id:"all",label:"All"},{id:"ready",label:"Ready / Installed"},{id:"connected",label:"Connected"},{id:"ides",label:"IDEs"},{id:"agents",label:"Agents & CLIs"}].map((S)=>``).join(""),_=`
⚡ 1-Click AI Client Integrations - ${L} + ${A}
- ${z?"▼ Show":"▲ Hide"} + ${C?"▼ Show":"▲ Hide"}
- ${!z?` + ${!C?`
- ${se} + ${W}
- +
- ${te} + ${J}
`:""} @@ -98,34 +98,34 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
Token Savings Rate
${b}
-
${v}
+
${f}
ETag Cache Hit Rate
-
${u}
-
${p}
+
${g}
+
${u}
Tasks & HITL State
-
${A>0?`${A} Action Req`:`${R} Active`}
-
${A>0?"Awaiting Human-in-the-Loop decision":`${x.length} total registered tasks`}
+
${T>0?`${T} Action Req`:`${I} Active`}
+
${T>0?"Awaiting Human-in-the-Loop decision":`${x.length} total registered tasks`}
Connected Upstreams
-
${o} Active
-
${o>0?"Persistent worker task channels":"No active upstream servers"}
+
${n} Active
+
${n>0?"Persistent worker task channels":"No active upstream servers"}
- ${B} + ${_}
Connected Upstream Servers
- +
- ${n} + ${o}
@@ -143,9 +143,9 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu ${r}
- `}function M(e){return String(e||"").replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}var X=[{id:"github",name:"GitHub",category:"devtools",description:"Explore repositories, issues, pull requests, branches, and commit histories.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-github"],envFields:[{key:"GITHUB_PERSONAL_ACCESS_TOKEN",label:"GitHub Personal Access Token",placeholder:"ghp_...",required:!0,description:"Classic or fine-grained token with repo scope."}]},{id:"git",name:"Git (Local)",category:"devtools",description:"Read local Git repository status, diffs, log histories, and commit changes.",badge:"Official / uvx",command:"uvx",defaultArgs:["--with","mcp<2","mcp-server-git","--repository","."],argsPlaceholder:"--with mcp<2 mcp-server-git --repository /path/to/repo",envFields:[]},{id:"filesystem",name:"Filesystem",category:"devtools",description:"Secure, sandboxed access to local files and directories for AI workflows.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-filesystem","."],argsPlaceholder:"-y @modelcontextprotocol/server-filesystem /allowed/dir1 /allowed/dir2",envFields:[]},{id:"memory",name:"Memory Graph",category:"devtools",description:"Persistent knowledge-graph based memory for multi-turn agent learning.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-memory"],envFields:[]},{id:"chrome-devtools",name:"Chrome DevTools",category:"devtools",description:"Inspect live DOM, execute scripts, read console logs, and capture network traces in Chrome.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-puppeteer"],envFields:[]},{id:"sentry",name:"Sentry",category:"devtools",description:"Query production error events, stack traces, and issue frequencies directly from Sentry.",badge:"uvx / Telemetry",command:"uvx",defaultArgs:["--with","mcp<2","--with","httpx","mcp-server-sentry","--auth-token","sntrys_token"],argsPlaceholder:"--with mcp<2 --with httpx mcp-server-sentry --auth-token YOUR_SENTRY_TOKEN",envFields:[{key:"SENTRY_AUTH_TOKEN",label:"Sentry Auth Token",placeholder:"sntrys_...",required:!0}]},{id:"playwright",name:"Playwright Browser",category:"browser",description:"Headless / headed browser automation for scraping, form filling, and UI interaction.",badge:"Popular #1 / npx",command:"npx",defaultArgs:["-y","@executeautomation/playwright-mcp-server"],envFields:[]},{id:"puppeteer",name:"Puppeteer",category:"browser",description:"Official browser automation server for web page scraping and screenshot capture.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-puppeteer"],envFields:[]},{id:"brave-search",name:"Brave Search",category:"browser",description:"Real-time privacy-preserving web search and local point-of-interest query engine.",badge:"Official / Search",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-brave-search"],envFields:[{key:"BRAVE_API_KEY",label:"Brave Search API Key",placeholder:"BSA...",required:!0}]},{id:"tavily",name:"Tavily Search",category:"browser",description:"AI-optimized web search engine structured specifically for LLM context injection.",badge:"Community / Stdio",command:"npx",defaultArgs:["-y","tavily-mcp"],envFields:[{key:"TAVILY_API_KEY",label:"Tavily API Key",placeholder:"tvly-...",required:!0}]},{id:"fetch",name:"Fetch / Web Markdown",category:"browser",description:"Download web pages, strip clutter, and convert raw HTML to clean markdown text.",badge:"Official / uvx",command:"uvx",defaultArgs:["mcp-server-fetch"],envFields:[]},{id:"postgres",name:"PostgreSQL",category:"database",description:"Read schemas, inspect tables, and execute SQL queries against PostgreSQL databases.",badge:"Official / Database",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-postgres","postgresql://user:pass@localhost:5432/mydb"],argsPlaceholder:"-y @modelcontextprotocol/server-postgres postgresql://user:pass@localhost:5432/dbname",envFields:[]},{id:"sqlite",name:"SQLite",category:"database",description:"Local embedded SQLite query runner and schema inspector.",badge:"Official / uvx",command:"uvx",defaultArgs:["--with","mcp<2","mcp-server-sqlite","--db-path","./app.db"],argsPlaceholder:"--with mcp<2 mcp-server-sqlite --db-path /path/to/database.sqlite",envFields:[]},{id:"supabase",name:"Supabase",category:"database",description:"Query database tables, manage auth policies, and inspect storage in Supabase.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@supabase/mcp-server-supabase@latest"],envFields:[{key:"SUPABASE_ACCESS_TOKEN",label:"Supabase Personal Access Token",placeholder:"sbp_...",required:!0},{key:"SUPABASE_PROJECT_REF",label:"Supabase Project Reference ID",placeholder:"abcdefghijklmnop",required:!1}]},{id:"redis",name:"Redis",category:"database",description:"Inspect cached keys, hash sets, lists, TTLs, and pub/sub channels in Redis.",badge:"Official / Key-Value",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-redis","redis://localhost:6379"],argsPlaceholder:"-y @modelcontextprotocol/server-redis redis://localhost:6379",envFields:[]},{id:"s3",name:"AWS S3 / Cloud Storage",category:"database",description:"Browse S3 buckets, fetch object metadata, and download files from cloud storage.",badge:"Community / Stdio",command:"npx",defaultArgs:["-y","@geunoh/s3-mcp-server"],argsPlaceholder:"-y @geunoh/s3-mcp-server",envFields:[{key:"AWS_ACCESS_KEY_ID",label:"AWS Access Key ID",placeholder:"AKIA...",required:!0},{key:"AWS_SECRET_ACCESS_KEY",label:"AWS Secret Access Key",placeholder:"...",required:!0},{key:"AWS_REGION",label:"AWS Region",placeholder:"us-east-1",required:!1}]},{id:"linear",name:"Linear",category:"productivity",description:"Search, create, and triage Linear issues, cycles, teams, and project roadmaps.",badge:"Productivity / Stdio",command:"npx",defaultArgs:["-y","mcp-linear"],envFields:[{key:"LINEAR_API_KEY",label:"Linear API Key",placeholder:"lin_api_...",required:!0}]},{id:"slack",name:"Slack",category:"productivity",description:"Read channels, post messages, inspect threads, and search team discussions.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-slack"],envFields:[{key:"SLACK_BOT_TOKEN",label:"Slack Bot User Token",placeholder:"xoxb-...",required:!0},{key:"SLACK_TEAM_ID",label:"Slack Team ID",placeholder:"T01234567",required:!0}]},{id:"notion",name:"Notion",category:"productivity",description:"Search Notion workspace pages, read nested blocks, and query database entries.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@notionhq/notion-mcp-server"],envFields:[{key:"NOTION_TOKEN",label:"Notion Internal Integration Token",placeholder:"secret_...",required:!0}]},{id:"jira",name:"Jira / Atlassian",category:"productivity",description:"Manage Jira issues, search JQL, read sprint statuses, and inspect boards.",badge:"uvx / Atlassian",command:"uvx",defaultArgs:["--with","mcp<2","mcp-server-jira","--jira-base-url","https://your-domain.atlassian.net"],argsPlaceholder:"--with mcp<2 mcp-server-jira --jira-base-url https://org.atlassian.net",envFields:[{key:"JIRA_TOKEN",label:"Atlassian API Token",placeholder:"ATATT3...",required:!0}]},{id:"google-drive",name:"Google Drive",category:"productivity",description:"Search, list, and read documents, spreadsheets, and drive files.",badge:"Community / Stdio",command:"npx",defaultArgs:["-y","@piotr-agier/google-drive-mcp"],envFields:[{key:"GOOGLE_APPLICATION_CREDENTIALS",label:"Google Credentials JSON Path",placeholder:"/path/to/credentials.json",required:!0}]},{id:"docker",name:"Docker",category:"cloud",description:"Inspect running containers, tail container logs, list images, and manage compose services.",badge:"uvx / DevOps",command:"uvx",defaultArgs:["mcp-server-docker"],envFields:[]},{id:"kubernetes",name:"Kubernetes (K8s)",category:"cloud",description:"Query cluster pods, services, deployment status, and inspect Kubernetes logs.",badge:"Popular / Stdio",command:"npx",defaultArgs:["-y","@strowk/mcp-k8s"],envFields:[{key:"KUBECONFIG",label:"Kubeconfig File Path (Optional)",placeholder:"~/.kube/config",required:!1}]},{id:"cloudflare",name:"Cloudflare",category:"cloud",description:"Manage Cloudflare Workers, KV namespaces, D1 databases, Vectorize indexes, and DNS.",badge:"Official / Cloudflare",command:"npx",defaultArgs:["-y","@cloudflare/mcp-server-cloudflare","run","dummy_account_id"],argsPlaceholder:"-y @cloudflare/mcp-server-cloudflare run YOUR_ACCOUNT_ID",envFields:[{key:"CLOUDFLARE_API_TOKEN",label:"Cloudflare API Token",placeholder:"...",required:!0},{key:"CLOUDFLARE_ACCOUNT_ID",label:"Cloudflare Account ID",placeholder:"...",required:!0}]},{id:"terraform",name:"Terraform",category:"cloud",description:"Inspect Terraform state files, resource dependency graphs, and plan previews.",badge:"Community / IaC",command:"npx",defaultArgs:["-y","@mseep/terraform-mcp-server"],envFields:[]}];function Q(e,t,a){let o=X.find((r)=>r.id.toLowerCase()===e.toLowerCase());if(o)return o;let n=`${t||""} ${(a||[]).join(" ")}`.toLowerCase();return X.find((r)=>{let s=`${r.command} ${r.defaultArgs.join(" ")}`.toLowerCase();if(n.includes(r.id.toLowerCase()))return!0;if(r.command&&n.includes(r.command.toLowerCase())&&r.defaultArgs.some((i)=>n.includes(i.toLowerCase())))return!0;return!1})}function ie(){let e=c.getState(),t=e.config.mcpServers||{},a=Object.keys(t),o=e.activeProfile,n=o?e.config.profiles?.[o]:void 0,r=!!n,s=n?.servers||[],i="";if(a.length===0)i=` + `}var D=[{id:"github",name:"GitHub",category:"devtools",description:"Explore repositories, issues, pull requests, branches, and commit histories.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-github"],envFields:[{key:"GITHUB_PERSONAL_ACCESS_TOKEN",label:"GitHub Personal Access Token",placeholder:"ghp_...",required:!0,description:"Classic or fine-grained token with repo scope."}]},{id:"git",name:"Git (Local)",category:"devtools",description:"Read local Git repository status, diffs, log histories, and commit changes.",badge:"Official / uvx",command:"uvx",defaultArgs:["--with","mcp<2","mcp-server-git","--repository","."],argsPlaceholder:"--with mcp<2 mcp-server-git --repository /path/to/repo",envFields:[]},{id:"filesystem",name:"Filesystem",category:"devtools",description:"Secure, sandboxed access to local files and directories for AI workflows.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-filesystem","."],argsPlaceholder:"-y @modelcontextprotocol/server-filesystem /allowed/dir1 /allowed/dir2",envFields:[]},{id:"memory",name:"Memory Graph",category:"devtools",description:"Persistent knowledge-graph based memory for multi-turn agent learning.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-memory"],envFields:[]},{id:"chrome-devtools",name:"Chrome DevTools",category:"devtools",description:"Inspect live DOM, execute scripts, read console logs, and capture network traces in Chrome.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-puppeteer"],envFields:[]},{id:"sentry",name:"Sentry",category:"devtools",description:"Query production error events, stack traces, and issue frequencies directly from Sentry.",badge:"uvx / Telemetry",command:"uvx",defaultArgs:["--with","mcp<2","--with","httpx","mcp-server-sentry","--auth-token","sntrys_token"],argsPlaceholder:"--with mcp<2 --with httpx mcp-server-sentry --auth-token YOUR_SENTRY_TOKEN",envFields:[{key:"SENTRY_AUTH_TOKEN",label:"Sentry Auth Token",placeholder:"sntrys_...",required:!0}]},{id:"playwright",name:"Playwright Browser",category:"browser",description:"Headless / headed browser automation for scraping, form filling, and UI interaction.",badge:"Popular #1 / npx",command:"npx",defaultArgs:["-y","@executeautomation/playwright-mcp-server"],envFields:[]},{id:"puppeteer",name:"Puppeteer",category:"browser",description:"Official browser automation server for web page scraping and screenshot capture.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-puppeteer"],envFields:[]},{id:"brave-search",name:"Brave Search",category:"browser",description:"Real-time privacy-preserving web search and local point-of-interest query engine.",badge:"Official / Search",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-brave-search"],envFields:[{key:"BRAVE_API_KEY",label:"Brave Search API Key",placeholder:"BSA...",required:!0}]},{id:"tavily",name:"Tavily Search",category:"browser",description:"AI-optimized web search engine structured specifically for LLM context injection.",badge:"Community / Stdio",command:"npx",defaultArgs:["-y","tavily-mcp"],envFields:[{key:"TAVILY_API_KEY",label:"Tavily API Key",placeholder:"tvly-...",required:!0}]},{id:"fetch",name:"Fetch / Web Markdown",category:"browser",description:"Download web pages, strip clutter, and convert raw HTML to clean markdown text.",badge:"Official / uvx",command:"uvx",defaultArgs:["mcp-server-fetch"],envFields:[]},{id:"postgres",name:"PostgreSQL",category:"database",description:"Read schemas, inspect tables, and execute SQL queries against PostgreSQL databases.",badge:"Official / Database",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-postgres","postgresql://user:pass@localhost:5432/mydb"],argsPlaceholder:"-y @modelcontextprotocol/server-postgres postgresql://user:pass@localhost:5432/dbname",envFields:[]},{id:"sqlite",name:"SQLite",category:"database",description:"Local embedded SQLite query runner and schema inspector.",badge:"Official / uvx",command:"uvx",defaultArgs:["--with","mcp<2","mcp-server-sqlite","--db-path","./app.db"],argsPlaceholder:"--with mcp<2 mcp-server-sqlite --db-path /path/to/database.sqlite",envFields:[]},{id:"supabase",name:"Supabase",category:"database",description:"Query database tables, manage auth policies, and inspect storage in Supabase.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@supabase/mcp-server-supabase@latest"],envFields:[{key:"SUPABASE_ACCESS_TOKEN",label:"Supabase Personal Access Token",placeholder:"sbp_...",required:!0},{key:"SUPABASE_PROJECT_REF",label:"Supabase Project Reference ID",placeholder:"abcdefghijklmnop",required:!1}]},{id:"redis",name:"Redis",category:"database",description:"Inspect cached keys, hash sets, lists, TTLs, and pub/sub channels in Redis.",badge:"Official / Key-Value",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-redis","redis://localhost:6379"],argsPlaceholder:"-y @modelcontextprotocol/server-redis redis://localhost:6379",envFields:[]},{id:"s3",name:"AWS S3 / Cloud Storage",category:"database",description:"Browse S3 buckets, fetch object metadata, and download files from cloud storage.",badge:"Community / Stdio",command:"npx",defaultArgs:["-y","@geunoh/s3-mcp-server"],argsPlaceholder:"-y @geunoh/s3-mcp-server",envFields:[{key:"AWS_ACCESS_KEY_ID",label:"AWS Access Key ID",placeholder:"AKIA...",required:!0},{key:"AWS_SECRET_ACCESS_KEY",label:"AWS Secret Access Key",placeholder:"...",required:!0},{key:"AWS_REGION",label:"AWS Region",placeholder:"us-east-1",required:!1}]},{id:"linear",name:"Linear",category:"productivity",description:"Search, create, and triage Linear issues, cycles, teams, and project roadmaps.",badge:"Productivity / Stdio",command:"npx",defaultArgs:["-y","mcp-linear"],envFields:[{key:"LINEAR_API_KEY",label:"Linear API Key",placeholder:"lin_api_...",required:!0}]},{id:"slack",name:"Slack",category:"productivity",description:"Read channels, post messages, inspect threads, and search team discussions.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@modelcontextprotocol/server-slack"],envFields:[{key:"SLACK_BOT_TOKEN",label:"Slack Bot User Token",placeholder:"xoxb-...",required:!0},{key:"SLACK_TEAM_ID",label:"Slack Team ID",placeholder:"T01234567",required:!0}]},{id:"notion",name:"Notion",category:"productivity",description:"Search Notion workspace pages, read nested blocks, and query database entries.",badge:"Official / Stdio",command:"npx",defaultArgs:["-y","@notionhq/notion-mcp-server"],envFields:[{key:"NOTION_TOKEN",label:"Notion Internal Integration Token",placeholder:"secret_...",required:!0}]},{id:"jira",name:"Jira / Atlassian",category:"productivity",description:"Manage Jira issues, search JQL, read sprint statuses, and inspect boards.",badge:"uvx / Atlassian",command:"uvx",defaultArgs:["--with","mcp<2","mcp-server-jira","--jira-base-url","https://your-domain.atlassian.net"],argsPlaceholder:"--with mcp<2 mcp-server-jira --jira-base-url https://org.atlassian.net",envFields:[{key:"JIRA_TOKEN",label:"Atlassian API Token",placeholder:"ATATT3...",required:!0}]},{id:"google-drive",name:"Google Drive",category:"productivity",description:"Search, list, and read documents, spreadsheets, and drive files.",badge:"Community / Stdio",command:"npx",defaultArgs:["-y","@piotr-agier/google-drive-mcp"],envFields:[{key:"GOOGLE_APPLICATION_CREDENTIALS",label:"Google Credentials JSON Path",placeholder:"/path/to/credentials.json",required:!0}]},{id:"docker",name:"Docker",category:"cloud",description:"Inspect running containers, tail container logs, list images, and manage compose services.",badge:"uvx / DevOps",command:"uvx",defaultArgs:["mcp-server-docker"],envFields:[]},{id:"kubernetes",name:"Kubernetes (K8s)",category:"cloud",description:"Query cluster pods, services, deployment status, and inspect Kubernetes logs.",badge:"Popular / Stdio",command:"npx",defaultArgs:["-y","@strowk/mcp-k8s"],envFields:[{key:"KUBECONFIG",label:"Kubeconfig File Path (Optional)",placeholder:"~/.kube/config",required:!1}]},{id:"cloudflare",name:"Cloudflare",category:"cloud",description:"Manage Cloudflare Workers, KV namespaces, D1 databases, Vectorize indexes, and DNS.",badge:"Official / Cloudflare",command:"npx",defaultArgs:["-y","@cloudflare/mcp-server-cloudflare","run","dummy_account_id"],argsPlaceholder:"-y @cloudflare/mcp-server-cloudflare run YOUR_ACCOUNT_ID",envFields:[{key:"CLOUDFLARE_API_TOKEN",label:"Cloudflare API Token",placeholder:"...",required:!0},{key:"CLOUDFLARE_ACCOUNT_ID",label:"Cloudflare Account ID",placeholder:"...",required:!0}]},{id:"terraform",name:"Terraform",category:"cloud",description:"Inspect Terraform state files, resource dependency graphs, and plan previews.",badge:"Community / IaC",command:"npx",defaultArgs:["-y","@mseep/terraform-mcp-server"],envFields:[]}];function N(e,t,a){let n=D.find((r)=>r.id.toLowerCase()===e.toLowerCase());if(n)return n;let o=`${t||""} ${(a||[]).join(" ")}`.toLowerCase();return D.find((r)=>{let s=`${r.command} ${r.defaultArgs.join(" ")}`.toLowerCase();if(o.includes(r.id.toLowerCase()))return!0;if(r.command&&o.includes(r.command.toLowerCase())&&r.defaultArgs.some((l)=>o.includes(l.toLowerCase())))return!0;return!1})}function X(){let e=p.getState(),t=e.config.mcpServers||{},a=Object.keys(t),n=e.activeProfile,o=n?e.config.profiles?.[n]:void 0,r=!!o,s=o?.servers||[],l="";if(a.length===0)l=`
-
No Servers Configured in ${I(e.configPath)}
+
No Servers Configured in ${i(e.configPath)}

Warmplane bridges local tools and remote MCP servers into one unified facade. Add your first server or import existing configs from Claude Desktop or Cursor.

@@ -155,56 +155,56 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- `;else i=a.map((u)=>{let p=t[u],g=p.command?"stdio":"http / sse",m=p.command?`${p.command} ${(p.args||[]).join(" ")}`:p.url,d=e.serverStatuses[u]||{status:"connected",protocol_version:"2026-07-28"},y=!r||s.includes(u),b=Q(u,p.command,p.args),v=Object.keys(p.env||{}),x=(b?.envFields||[]).filter((B)=>B.required&&!v.includes(B.key)),A=p.env?Object.entries(p.env).map(([B,E])=>{if(E.startsWith("keychain://"))return`\uD83D\uDD12 ${I(B)} (Keychain)`;if(E.startsWith("op://"))return`\uD83D\uDD12 ${I(B)} (1Password)`;if(E.startsWith("env://"))return`\uD83D\uDD12 ${I(B)} (Env)`;return`${I(B)}=***`}):[];for(let B of x)A.push(`⚠️ Missing ${I(B.key)}`);let R=A.length>0?A.join(" "):"None",T=(e.circuitBreakers||[]).find((B)=>B.server_id===u),S='Circuit: CLOSED';if(T){if(T.state==="open")S=`Circuit: OPEN (${T.consecutive_failures} failures)`;else if(T.state==="half_open")S=`Circuit: HALF-OPEN (${T.consecutive_successes} probe)`}let w=p.resilience||e.config.resilience,z=w?`FT: ${w.failureThreshold||3} · Cooldown: ${(w.cooldownMs||30000)/1000}s · AutoRestart: ${w.autoRestart!==!1?"ON":"OFF"}`:"Default Resilience",L=x.length>0,N=d.status==="degraded"||L,D=d.status==="error"||d.status==="disconnected",q=L?"var(--amber-400)":N?"var(--amber-400)":D?"var(--red-400)":"var(--green-400)",U=L?`Status: ${I(d.status)} (Missing Keys)`:`Status: ${I(d.status)}`,V=(N||D)&&(d.error||L)?` + `;else l=a.map((g)=>{let u=t[g],m=u.command?"stdio":"http / sse",v=u.command?`${u.command} ${(u.args||[]).join(" ")}`:u.url,c=e.serverStatuses[g]||{status:"connected",protocol_version:"2026-07-28"},y=!r||s.includes(g),b=N(g,u.command,u.args),f=Object.keys(u.env||{}),x=(b?.envFields||[]).filter((_)=>_.required&&!f.includes(_.key)),T=u.env?Object.entries(u.env).map(([_,S])=>{if(S.startsWith("keychain://"))return`\uD83D\uDD12 ${i(_)} (Keychain)`;if(S.startsWith("op://"))return`\uD83D\uDD12 ${i(_)} (1Password)`;if(S.startsWith("env://"))return`\uD83D\uDD12 ${i(_)} (Env)`;return`${i(_)}=***`}):[];for(let _ of x)T.push(`⚠️ Missing ${i(_.key)}`);let I=T.length>0?T.join(" "):"None",E=(e.circuitBreakers||[]).find((_)=>_.server_id===g),k='Circuit: CLOSED';if(E){if(E.state==="open")k=`Circuit: OPEN (${E.consecutive_failures} failures)`;else if(E.state==="half_open")k=`Circuit: HALF-OPEN (${E.consecutive_successes} probe)`}let w=u.resilience||e.config.resilience,C=w?`FT: ${w.failureThreshold||3} · Cooldown: ${(w.cooldownMs||30000)/1000}s · AutoRestart: ${w.autoRestart!==!1?"ON":"OFF"}`:"Default Resilience",A=x.length>0,L=c.status==="degraded"||A,M=c.status==="error"||c.status==="disconnected",R=A?"var(--amber-400)":L?"var(--amber-400)":M?"var(--red-400)":"var(--green-400)",B=A?`Status: ${i(c.status)} (Missing Keys)`:`Status: ${i(c.status)}`,O=(L||M)&&(c.error||A)?`
- ⚠️ Diagnostics: ${I(d.error||`Missing required environment variable(s): ${x.map((B)=>B.key).join(", ")}`)} + ⚠️ Diagnostics: ${i(c.error||`Missing required environment variable(s): ${x.map((_)=>_.key).join(", ")}`)}
- +
- `:"",te=r?y?` + `:"",J=r?y?` ✔ IN CONSTELLATION - + `:` - \uD83D\uDEAB EXCLUDED FROM PROFILE: ${I(o)} - + \uD83D\uDEAB EXCLUDED FROM PROFILE: ${i(n)} + `:"";return` -
+
- - ${I(u)} - ${g} - ${U} - Protocol: ${d.protocol_version} - ${S} - ${te} + + ${i(g)} + ${m} + ${B} + Protocol: ${c.protocol_version} + ${k} + ${J}
- ${p.command?"Command: ":"URL: "}${I(m||"")} + ${u.command?"Command: ":"URL: "}${i(v||"")}
- \uD83D\uDEE1️ ${I(z)} - ${p.env&&Object.keys(p.env).length>0?`Env: ${R}`:""} + \uD83D\uDEE1️ ${i(C)} + ${u.env&&Object.keys(u.env).length>0?`Env: ${I}`:""}
- - - - + + + +
- ${V} + ${O}
- `}).join("");let l=r?` + `}).join("");let d=r?`
\uD83C\uDF0C
- Active Profile Constellation: ${I(o)} + Active Profile Constellation: ${i(n)} ${s.length} of ${a.length} servers included
@@ -221,52 +221,52 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
Configured MCP Upstream Servers
-
Active configuration file: ${I(e.configPath)}
+
Active configuration file: ${i(e.configPath)}
- ${l} + ${d} - ${i} + ${l} - ${ye()} - `}function ye(){let e=c.getState(),t=e.clients||[],a=Object.keys(e.config.profiles||{}),o=e.clientsCollapsed,n=e.clientFilterCategory||"all",r=(e.clientSearchQuery||"").toLowerCase().trim();if(t.length===0)return"";let s=t.filter((d)=>d.is_attached).length,i=t.filter((d)=>d.config_exists&&!d.is_attached).length,l=t.filter((d)=>d.category.toLowerCase().includes("ide")||d.category.toLowerCase().includes("extension")).length,u=t.filter((d)=>d.category.toLowerCase().includes("agent")||d.category.toLowerCase().includes("cli")||d.category.toLowerCase().includes("platform")).length,p=t.filter((d)=>{if(r){let y=d.name.toLowerCase().includes(r),b=d.id.toLowerCase().includes(r),v=d.category.toLowerCase().includes(r),x=d.config_path.toLowerCase().includes(r);if(!y&&!b&&!v&&!x)return!1}if(n==="connected")return d.is_attached;if(n==="ready")return d.config_exists||d.app_installed;if(n==="ides")return d.category.toLowerCase().includes("ide")||d.category.toLowerCase().includes("extension");if(n==="agents")return d.category.toLowerCase().includes("agent")||d.category.toLowerCase().includes("cli")||d.category.toLowerCase().includes("platform");return!0}),g=[{id:"all",label:`All Ecosystems (${t.length})`},{id:"ready",label:`Ready / Installed (${i+s})`},{id:"connected",label:`⚡ Connected (${s})`},{id:"ides",label:`IDEs & Editors (${l})`},{id:"agents",label:`Agents & CLIs (${u})`}].map((d)=>` - - `).join(""),m=p.length===0?`
No AI clients match the filter "${I(r||n)}".
`:p.map((d)=>{let{is_attached:y,config_exists:b,app_installed:v}=d,x='Not Found';if(y){let S=d.attached_profile?` · ${d.attached_profile}`:"";x=`⚡ Connected · ${d.attached_transport==="http"?"HTTP":"stdio"}${I(S)}`}else if(b)x='○ Ready';else if(v)x='○ Installed';let A=e.activeProfile,R=a.map((S)=>` - - `).join(""),T=y?``:``;return` + `).join(""),v=u.length===0?`
No AI clients match the filter "${i(r||o)}".
`:u.map((c)=>{let{is_attached:y,config_exists:b,app_installed:f}=c,x='Not Found';if(y){let k=c.attached_profile?` · ${c.attached_profile}`:"";x=`⚡ Connected · ${c.attached_transport==="http"?"HTTP":"stdio"}${i(k)}`}else if(b)x='○ Ready';else if(f)x='○ Installed';let T=e.activeProfile,I=a.map((k)=>` + + `).join(""),E=y?``:``;return`
- ${I(d.name)} + ${i(c.name)}
-
${I(d.category)}
+
${i(c.category)}
${x}
-
- ${I(d.config_path)} +
+ ${i(c.config_path)}
${a.length>0&&!y?` - - ${R} + ${I} - `:`${d.other_servers_count>0?`${d.other_servers_count} other tools`:"Single facade"}`} + `:`${c.other_servers_count>0?`${c.other_servers_count} other tools`:"Single facade"}`}
- ${T} + ${E}
`}).join("");return` @@ -283,18 +283,18 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${o?"▼ Show":"▲ Hide"} + ${n?"▼ Show":"▲ Hide"}
- ${!o?` + ${!n?`
- ${g} + ${m}
- +
@@ -306,12 +306,12 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu Constellation Scope Action
- ${m} + ${v}
`:""}
- `}function I(e){return String(e||"").replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function le(){let e=c.getState(),t=e.playgroundMode||"tools",a=e.capabilities||[],o=e.resources||[],n=e.prompts||[],r=e.capabilitiesHiddenByPolicy||0,s=e.resourcesHiddenByPolicy||0,i=e.promptsHiddenByPolicy||0,l=e.activeProfile,p=!!(l?e.config.profiles?.[l]:void 0),g=` + `}function Z(){let e=p.getState(),t=e.playgroundMode||"tools",a=e.capabilities||[],n=e.resources||[],o=e.prompts||[],r=e.capabilitiesHiddenByPolicy||0,s=e.resourcesHiddenByPolicy||0,l=e.promptsHiddenByPolicy||0,d=e.activeProfile,u=!!(d?e.config.profiles?.[d]:void 0),m=`
${t==="tools"&&r>0?`
- \uD83D\uDEE1️ ${r} tool${r>1?"s":""} filtered ${p?`(Profile: ${k(l)})`:"by policy"} + \uD83D\uDEE1️ ${r} tool${r>1?"s":""} filtered ${u?`(Profile: ${i(d)})`:"by policy"} View Policy - ${p?`Server Hub`:""} + ${u?`Server Hub`:""}
`:t==="resources"&&s>0?`
- \uD83D\uDEE1️ ${s} resource${s>1?"s":""} filtered ${p?`(Profile: ${k(l)})`:"by policy"} + \uD83D\uDEE1️ ${s} resource${s>1?"s":""} filtered ${u?`(Profile: ${i(d)})`:"by policy"} View Policy - ${p?`Server Hub`:""} + ${u?`Server Hub`:""}
- `:t==="prompts"&&i>0?` + `:t==="prompts"&&l>0?`
- \uD83D\uDEE1️ ${i} prompt${i>1?"s":""} filtered ${p?`(Profile: ${k(l)})`:"by policy"} + \uD83D\uDEE1️ ${l} prompt${l>1?"s":""} filtered ${u?`(Profile: ${i(d)})`:"by policy"} View Policy - ${p?`Server Hub`:""} + ${u?`Server Hub`:""}
`:`
@@ -367,43 +367,43 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
`;if(t==="resources")return` - ${g} - ${xe(e)} + ${m} + ${ce(e)} `;if(t==="prompts")return` - ${g} - ${he(e)} + ${m} + ${pe(e)} `;return` - ${g} - ${be(e)} - ${e.isBatchModalOpen?we(e):""} - `}function ee(e,t=!1){if(!e||!e.properties)return{};let a=e.properties||{},o=Array.isArray(e.required)?e.required:[],n={};for(let[r,s]of Object.entries(a)){let i=o.includes(r);if(t&&!i)continue;if(s.default!==void 0)n[r]=s.default;else if(Array.isArray(s.enum)&&s.enum.length>0)n[r]=s.enum[0];else if(s.examples&&Array.isArray(s.examples)&&s.examples.length>0)n[r]=s.examples[0];else if(s.example!==void 0)n[r]=s.example;else switch(s.type||"string"){case"string":n[r]=i?`sample_${r}`:"";break;case"number":case"integer":n[r]=0;break;case"boolean":n[r]=!0;break;case"array":n[r]=[];break;case"object":n[r]={};break;default:n[r]=`sample_${r}`}}return n}function be(e){let t=e.capabilities||[],a=e.selectedCapabilityId||(t.length>0?t[0].id:null),o=t.find((b)=>b.id===a),n=e.isExecutingCapability,r=e.capabilitiesHiddenByPolicy||0,s=e.activeProfile,i=!!(s&&e.config.profiles?.[s]),l="";if(t.length===0)l=` + ${m} + ${de(e)} + ${e.isBatchModalOpen?ue(e):""} + `}function K(e,t=!1){if(!e||!e.properties)return{};let a=e.properties||{},n=Array.isArray(e.required)?e.required:[],o={};for(let[r,s]of Object.entries(a)){let l=n.includes(r);if(t&&!l)continue;if(s.default!==void 0)o[r]=s.default;else if(Array.isArray(s.enum)&&s.enum.length>0)o[r]=s.enum[0];else if(s.examples&&Array.isArray(s.examples)&&s.examples.length>0)o[r]=s.examples[0];else if(s.example!==void 0)o[r]=s.example;else switch(s.type||"string"){case"string":o[r]=l?`sample_${r}`:"";break;case"number":case"integer":o[r]=0;break;case"boolean":o[r]=!0;break;case"array":o[r]=[];break;case"object":o[r]={};break;default:o[r]=`sample_${r}`}}return o}function de(e){let t=e.capabilities||[],a=e.selectedCapabilityId||(t.length>0?t[0].id:null),n=t.find((b)=>b.id===a),o=e.isExecutingCapability,r=e.capabilitiesHiddenByPolicy||0,s=e.activeProfile,l=!!(s&&e.config.profiles?.[s]),d="";if(t.length===0)d=`
No tools or capabilities discovered from connected servers.
- `;else l=t.map((b)=>` -
+ `;else d=t.map((b)=>` +
- ${k(b.id)} - ${k(b.mode||"read")} + ${i(b.id)} + ${i(b.mode||"read")}
-
server: ${k(b.server||"local")}
+
server: ${i(b.server||"local")}
- `).join("");let u=o?.input_schema,p=u?.properties||{},g=Array.isArray(u?.required)?u.required:[],m=Object.entries(p),d="";if(m.length>0)d=` + `).join("");let g=n?.input_schema,u=g?.properties||{},m=Array.isArray(g?.required)?g.required:[],v=Object.entries(u),c="";if(v.length>0)c=`
Fields: - ${m.map(([b,v])=>{let x=g.includes(b),A=v.type||(v.enum?"enum":"any"),R=x?"rgba(239, 68, 68, 0.15)":"rgba(148, 163, 184, 0.1)",T=x?"var(--red-400)":"var(--text-muted)",S=x?"rgba(239, 68, 68, 0.3)":"var(--border)",w=v.description?` - ${v.description}`:"";return` + ${v.map(([b,f])=>{let x=m.includes(b),T=f.type||(f.enum?"enum":"any"),I=x?"rgba(239, 68, 68, 0.15)":"rgba(148, 163, 184, 0.1)",E=x?"var(--red-400)":"var(--text-muted)",k=x?"rgba(239, 68, 68, 0.3)":"var(--border)",w=f.description?` - ${f.description}`:"";return` `}).join("")}
- `;let y="{}";if(a&&e.playgroundArgs&&e.playgroundArgs[a]!==void 0)y=e.playgroundArgs[a];else{let b=ee(u,!1);y=JSON.stringify(b,null,2)}return` + `;let y="{}";if(a&&e.playgroundArgs&&e.playgroundArgs[a]!==void 0)y=e.playgroundArgs[a];else{let b=K(g,!1);y=JSON.stringify(b,null,2)}return`
@@ -411,14 +411,14 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${l} + ${d}
${r>0?`
- \uD83D\uDEE1️ ${r} tool${r>1?"s":""} filtered ${i?`(${k(s)})`:""} + \uD83D\uDEE1️ ${r} tool${r>1?"s":""} filtered ${l?`(${i(s)})`:""}
Policy - ${i?`Servers`:""} + ${l?`Servers`:""}
`:""} @@ -429,15 +429,15 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${k(o?o.id:"No Capability Selected")} + ${i(n?n.id:"No Capability Selected")}
- ${k(o?o.summary||o.description:"Connect servers to inspect and execute tools")} + ${i(n?n.summary||n.description:"Connect servers to inspect and execute tools")}
- ${n?` + ${o?`
@@ -449,7 +449,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
`:` - @@ -464,7 +464,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${g.length>0?` + ${m.length>0?` `:""} @@ -472,9 +472,9 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${d} + ${c} - +
@@ -515,13 +515,13 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${o&&o.input_schema?` + ${n&&n.input_schema?`
- ${m.length} field${m.length===1?"":"s"} (${g.length} required) + ${v.length} field${v.length===1?"":"s"} (${m.length} required)
-
${k(JSON.stringify(o.input_schema,null,2))}
+
${i(JSON.stringify(n.input_schema,null,2))}
`:""}
@@ -542,9 +542,9 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${k(e.executionResult.data?.task?.status||e.executionResult.data?.status||"TASK_CREATED").toUpperCase()} + ${i(e.executionResult.data?.task?.status||e.executionResult.data?.status||"TASK_CREATED").toUpperCase()} - ${k(e.executionResult.data?.task?.taskId||e.executionResult.data?.taskId||"")} + ${i(e.executionResult.data?.task?.taskId||e.executionResult.data?.taskId||"")}
Execution suspended for Human-in-the-Loop approval or async resolution. @@ -556,25 +556,25 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
`:""} -
${e.executionResult?k(JSON.stringify(e.executionResult.data,null,2)):"// Response envelope output will be formatted here"}
+
${e.executionResult?i(JSON.stringify(e.executionResult.data,null,2)):"// Response envelope output will be formatted here"}
- `}function xe(e){let t=e.resources||[],a=e.resourcesHiddenByPolicy||0,o=e.selectedResourceId||(t.length>0?t[0].id:null),n=t.find((i)=>i.id===o),r=e.resourceReadResult,s="";if(t.length===0)s=` + `}function ce(e){let t=e.resources||[],a=e.resourcesHiddenByPolicy||0,n=e.selectedResourceId||(t.length>0?t[0].id:null),o=t.find((l)=>l.id===n),r=e.resourceReadResult,s="";if(t.length===0)s=`
No resources exposed by connected MCP servers.
- `;else s=t.map((i)=>{let l=i.id===o?"active":"",u=i.uri?i.uri.split(":")[0]:"res";return` -
+ `;else s=t.map((l)=>{let d=l.id===n?"active":"",g=l.uri?l.uri.split(":")[0]:"res";return` +
- ${k(i.name||i.id)} - ${k(u)} + ${i(l.name||l.id)} + ${i(g)}
-
${k(i.uri)}
+
${i(l.uri)}
- server: ${k(i.server||"local")} - ${k(i.mime_type||"text/plain")} + server: ${i(l.server||"local")} + ${i(l.mime_type||"text/plain")}
`}).join("");return` @@ -600,13 +600,13 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${k(n?n.name||n.id:"No Resource Selected")} + ${i(o?o.name||o.id:"No Resource Selected")}
- ${k(n?n.uri:"Select a resource from the list to read live content")} + ${i(o?o.uri:"Select a resource from the list to read live content")}
- @@ -615,16 +615,16 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${n?` + ${o?`
Resource Metadata
-
Server: ${k(n.server)}
-
MIME Type: ${k(n.mime_type||"text/plain")}
+
Server: ${i(o.server)}
+
MIME Type: ${i(o.mime_type||"text/plain")}
- ${n.description?` + ${o.description?`
- ${k(n.description)} + ${i(o.description)}
`:""}
@@ -659,34 +659,34 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu ${r?`HTTP ${r.status} · ${r.durationMs.toFixed(1)}ms`:"READY"}
-
${r?k(JSON.stringify(r.data,null,2)):'// Click "Read Resource Content" to inspect live payload'}
+
${r?i(JSON.stringify(r.data,null,2)):'// Click "Read Resource Content" to inspect live payload'}
- `}function he(e){let t=e.prompts||[],a=e.promptsHiddenByPolicy||0,o=e.selectedPromptId||(t.length>0?t[0].id:null),n=t.find((l)=>l.id===o),r=e.promptGetResult,s="";if(t.length===0)s=` + `}function pe(e){let t=e.prompts||[],a=e.promptsHiddenByPolicy||0,n=e.selectedPromptId||(t.length>0?t[0].id:null),o=t.find((d)=>d.id===n),r=e.promptGetResult,s="";if(t.length===0)s=`
No prompt templates registered by connected MCP servers.
- `;else s=t.map((l)=>{let u=l.id===o?"active":"",p=l.arguments?l.arguments.length:0;return` -
+ `;else s=t.map((d)=>{let g=d.id===n?"active":"",u=d.arguments?d.arguments.length:0;return` +
- ${k(l.name||l.id)} - ${p} args + ${i(d.name||d.id)} + ${u} args
-
${k(l.description||l.title||"Prompt template")}
-
server: ${k(l.server||"local")}
+
${i(d.description||d.title||"Prompt template")}
+
server: ${i(d.server||"local")}
- `}).join("");let i="";if(n&&n.arguments&&n.arguments.length>0)i=n.arguments.map((l)=>` + `}).join("");let l="";if(o&&o.arguments&&o.arguments.length>0)l=o.arguments.map((d)=>`
- - ${l.required?'REQUIRED':'optional'} + + ${d.required?'REQUIRED':'optional'}
- ${l.description?`
${k(l.description)}
`:""} - + ${d.description?`
${i(d.description)}
`:""} +
- `).join("");else if(n)i=` + `).join("");else if(o)l=`
This prompt template does not require any input arguments.
@@ -713,13 +713,13 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${k(n?n.name||n.id:"No Prompt Selected")} + ${i(o?o.name||o.id:"No Prompt Selected")}
- ${k(n?n.description||n.title||"Bind variables and render messages":"Select a prompt from the list to test")} + ${i(o?o.description||o.title||"Bind variables and render messages":"Select a prompt from the list to test")}
- @@ -731,7 +731,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
Template Arguments
- ${i} + ${l}
@@ -742,12 +742,12 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu ${r?`HTTP ${r.status} · ${r.durationMs.toFixed(1)}ms`:"READY"}
-
${r?k(JSON.stringify(r.data,null,2)):'// Click "Render Prompt Messages" to view resolved system/user messages'}
+
${r?i(JSON.stringify(r.data,null,2)):'// Click "Render Prompt Messages" to view resolved system/user messages'}
- `}function we(e){let t=e.capabilities||[],a=e.batchSteps||[];return` + `}function ue(e){let t=e.capabilities||[],a=e.batchSteps||[];return`
@@ -763,16 +763,16 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${a.map((n,r)=>{let s=t.find((d)=>d.id===n.capability_id),i=s?.input_schema,l=i?.properties||{},u=Array.isArray(i?.required)?i.required:[],p=Object.entries(l),g=t.map((d)=>` - - `).join(""),m="";if(p.length>0)m=` + `).join(""),v="";if(u.length>0)v=`
Parameters: - ${p.map(([d,y])=>{let b=u.includes(d),v=y.type||(y.enum?"enum":"any");return` - - ${k(d)} (${v}${b?" *":""}) + ${u.map(([c,y])=>{let b=g.includes(c),f=y.type||(y.enum?"enum":"any");return` + + ${i(c)} (${f}${b?" *":""}) `}).join("")}
@@ -781,7 +781,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
STEP ${r+1} - id: ${k(n.id)} + id: ${i(o.id)}
- ${m} + ${v}
@@ -826,7 +826,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu rows="3" style="font-size: 11px; font-family: var(--ff-mono);" oninput="window.app.updateBatchStepArgs(${r}, this.value)" - >${k(n.argsJson)} + >${i(o.argsJson)}
`}).join("")} @@ -852,7 +852,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- `}function k(e){return String(e||"").replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function de(e){let t=e.tasks||[],a=e.taskFilterStatus||"all",o=t.filter((d)=>d.status==="input_required"),n=t.filter((d)=>d.status==="working"),r=t.filter((d)=>d.status==="completed"),s=t.filter((d)=>d.status==="cancelled"),i=t.filter((d)=>d.status==="failed"),l=a==="all"?t:t.filter((d)=>d.status===a),u=e.config.policy?.require_approval||e.config.policy?.requireApproval||[],p=o.length===0?` + `}function ee(e){let t=e.tasks||[],a=e.taskFilterStatus||"all",n=t.filter((c)=>c.status==="input_required"),o=t.filter((c)=>c.status==="working"),r=t.filter((c)=>c.status==="completed"),s=t.filter((c)=>c.status==="cancelled"),l=t.filter((c)=>c.status==="failed"),d=a==="all"?t:t.filter((c)=>c.status===a),g=e.config.policy?.require_approval||e.config.policy?.requireApproval||[],u=n.length===0?`
✓ @@ -862,7 +862,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu Tool calls requiring Human-in-the-Loop approval or returning asynchronous input_required tasks will suspend here for operator inspection, parameter editing, and response submission.
- `:o.map((d)=>{let y=d.inputRequests||{},b=Object.keys(y),v=b.length>0,x=Math.floor(Date.now()/1000),A=d.expiresAtEpochSecs?Math.max(0,d.expiresAtEpochSecs-x):d.ttlMs?Math.max(0,Math.floor(d.ttlMs/1000)):d.ttlSeconds||300,R=d.createdAtEpochSecs?new Date(d.createdAtEpochSecs*1000).toLocaleTimeString():d.createdAt?new Date(d.createdAt).toLocaleTimeString():"—";return` + `:n.map((c)=>{let y=c.inputRequests||{},b=Object.keys(y),f=b.length>0,x=Math.floor(Date.now()/1000),T=c.expiresAtEpochSecs?Math.max(0,c.expiresAtEpochSecs-x):c.ttlMs?Math.max(0,Math.floor(c.ttlMs/1000)):c.ttlSeconds||300,I=c.createdAtEpochSecs?new Date(c.createdAtEpochSecs*1000).toLocaleTimeString():c.createdAt?new Date(c.createdAt).toLocaleTimeString():"—";return`
@@ -870,143 +870,143 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu INPUT REQUIRED - ${C(d.taskId)} + ${i(c.taskId)}
- ${C(d.capabilityId||"Tool Execution")} + ${i(c.capabilityId||"Tool Execution")} - ${d.serverId?`via ${C(d.serverId)}`:""} + ${c.serverId?`via ${i(c.serverId)}`:""}
-
Created: ${R}
-
TTL Remaining: ${A}s
+
Created: ${I}
+
TTL Remaining: ${T}s
- ${d.context?` + ${c.context?`
- ${d.context.actor_id?`
Actor: ${C(d.context.actor_id)}
`:""} - ${d.context.operation_id?`
Operation: ${C(d.context.operation_id)}
`:""} - ${d.context.grant_id?`
Grant: ${C(d.context.grant_id)}
`:""} + ${c.context.actor_id?`
Actor: ${i(c.context.actor_id)}
`:""} + ${c.context.operation_id?`
Operation: ${i(c.context.operation_id)}
`:""} + ${c.context.grant_id?`
Grant: ${i(c.context.grant_id)}
`:""}
`:""}
- ${v?"Required Input Responses (MRTR / HITL)":"Input Responses Payload (JSON)"} + ${f?"Required Input Responses (MRTR / HITL)":"Input Responses Payload (JSON)"}
- ${v?` + ${f?`
- ${b.map((T)=>{let S=y[T]||{},w=typeof S==="string"?S:S.prompt||S.description||S.title||T,z=S.type||"text",L=S.default!==void 0?JSON.stringify(S.default):S.value!==void 0?JSON.stringify(S.value):S.sanitized_args?JSON.stringify(S.sanitized_args,null,2):"";if(z==="approval_review")return` + ${b.map((E)=>{let k=y[E]||{},w=typeof k==="string"?k:k.prompt||k.description||k.title||E,C=k.type||"text",A=k.default!==void 0?JSON.stringify(k.default):k.value!==void 0?JSON.stringify(k.value):k.sanitized_args?JSON.stringify(k.sanitized_args,null,2):"";if(C==="approval_review")return`
- + APPROVAL GATED
-
${C(w)}
+
${i(w)}
-
- +
`;return`
- - ${C(z)} + + ${i(C)}
-
${C(w)}
- ${z==="confirmation"||z==="boolean"?` - - `:S.sanitized_args||z==="object"||z==="json"?` - + `:k.sanitized_args||C==="object"||C==="json"?` + `:` - + `}
`}).join("")}
`:` - + `}
- +
- -
- `}).join(""),g=u.length===0?` + `}).join(""),m=g.length===0?`
No explicit require_approval rules active. Gated execution rules convert matching tool calls into tasks in real-time.
- `:u.map((d)=>` + `:g.map((c)=>`
- \uD83D\uDEE1️ ${C(d)} + \uD83D\uDEE1️ ${i(c)} GATED
- `).join(""),m=l.length===0?` + `).join(""),v=d.length===0?` - No tasks found matching filter "${C(a)}". + No tasks found matching filter "${i(a)}". - `:l.map((d)=>{let y=d.status==="completed"?"background: rgba(52, 211, 153, 0.12); color: var(--green-400); border-color: rgba(52, 211, 153, 0.3);":d.status==="working"?"background: rgba(56, 189, 248, 0.15); color: var(--cyan-400); border-color: rgba(56, 189, 248, 0.4);":d.status==="input_required"?"background: rgba(245, 158, 11, 0.2); color: var(--amber-300); border-color: rgba(245, 158, 11, 0.5);":d.status==="cancelled"?"background: rgba(148, 163, 184, 0.15); color: var(--text-muted); border-color: rgba(148, 163, 184, 0.3);":"background: rgba(248, 113, 113, 0.12); color: var(--red-400); border-color: rgba(248, 113, 113, 0.3);",b=d.progress!==void 0?Math.round(d.progress*100):d.status==="completed"?100:d.status==="working"?50:0,v=d.createdAtEpochSecs?new Date(d.createdAtEpochSecs*1000).toLocaleTimeString():d.createdAt?new Date(d.createdAt).toLocaleTimeString():"—";return` + `:d.map((c)=>{let y=c.status==="completed"?"background: rgba(52, 211, 153, 0.12); color: var(--green-400); border-color: rgba(52, 211, 153, 0.3);":c.status==="working"?"background: rgba(56, 189, 248, 0.15); color: var(--cyan-400); border-color: rgba(56, 189, 248, 0.4);":c.status==="input_required"?"background: rgba(245, 158, 11, 0.2); color: var(--amber-300); border-color: rgba(245, 158, 11, 0.5);":c.status==="cancelled"?"background: rgba(148, 163, 184, 0.15); color: var(--text-muted); border-color: rgba(148, 163, 184, 0.3);":"background: rgba(248, 113, 113, 0.12); color: var(--red-400); border-color: rgba(248, 113, 113, 0.3);",b=c.progress!==void 0?Math.round(c.progress*100):c.status==="completed"?100:c.status==="working"?50:0,f=c.createdAtEpochSecs?new Date(c.createdAtEpochSecs*1000).toLocaleTimeString():c.createdAt?new Date(c.createdAt).toLocaleTimeString():"—";return` - ${d.status.toUpperCase()} + ${c.status.toUpperCase()} - ${C(d.capabilityId||"Tool Execution")} + ${i(c.capabilityId||"Tool Execution")} - ${C(d.taskId)} + ${i(c.taskId)}
-
+
${b}%
- ${v} + ${f}
- - ${d.status==="input_required"||d.status==="working"?` - + + ${c.status==="input_required"||c.status==="working"?` + `:""}
@@ -1015,8 +1015,8 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- 0?"rgba(245, 158, 11, 0.4)":"rgba(52, 211, 153, 0.4)"}; background: ${o.length>0?"rgba(245, 158, 11, 0.1)":"rgba(52, 211, 153, 0.1)"};"> - ${o.length} ACTION REQUIRED + 0?"rgba(245, 158, 11, 0.4)":"rgba(52, 211, 153, 0.4)"}; background: ${n.length>0?"rgba(245, 158, 11, 0.1)":"rgba(52, 211, 153, 0.1)"};"> + ${n.length} ACTION REQUIRED SEP-2663 Tasks Extension (io.modelcontextprotocol/tasks) and Unified Human-in-the-Loop execution control. @@ -1034,12 +1034,12 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
Input Required (HITL)
-
${o.length}
+
${n.length}
Awaiting operator decision or response
Working / In-Flight
-
${n.length}
+
${o.length}
Asynchronous active executions
@@ -1049,7 +1049,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
Cancelled / Failed
-
${s.length+i.length}
+
${s.length+l.length}
Terminated or errored
@@ -1059,10 +1059,10 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ⚡ Awaiting Operator Action (${o.length}) + ⚡ Awaiting Operator Action (${n.length})
- ${p} + ${u}
@@ -1073,7 +1073,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${g} + ${m}
@@ -1089,7 +1089,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- \uD83D\uDCDC Task Registry (${l.length}) + \uD83D\uDCDC Task Registry (${d.length})
Filter Status: @@ -1117,26 +1117,26 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu - ${m} + ${v}
- `}function C(e){return String(e||"").replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function ce(){let e=c.getState(),t=e.auditEvents||[],a=e.auditStats||{total_events:0,by_status:{success:0,failed:0,denied:0,intercepted:0}},o=e.auditVerification,n=e.auditFilters,r=e.auditTotal??t.length,s=e.auditSelectedEvent,i=Object.keys(e.config?.mcpServers||{}),l=n.limit||25,u=n.offset||0,p=Math.floor(u/l)+1,g=Math.max(1,Math.ceil(r/l)),m=r===0?0:u+1,d=Math.min(u+l,r),y=h.getAuditExportUrl({actor_id:n.search?void 0:void 0,server_id:n.serverId!=="all"?n.serverId:void 0,event_type:n.eventType!=="all"?n.eventType:void 0,status:n.status!=="all"?n.status:void 0,search:n.search.trim()?n.search.trim():void 0},"csv"),b=h.getAuditExportUrl({server_id:n.serverId!=="all"?n.serverId:void 0,event_type:n.eventType!=="all"?n.eventType:void 0,status:n.status!=="all"?n.status:void 0,search:n.search.trim()?n.search.trim():void 0},"jsonl"),v=o?o.is_valid?` + `}function te(){let e=p.getState(),t=e.auditEvents||[],a=e.auditStats||{total_events:0,by_status:{success:0,failed:0,denied:0,intercepted:0}},n=e.auditVerification,o=e.auditFilters,r=e.auditTotal??t.length,s=e.auditSelectedEvent,l=Object.keys(e.config?.mcpServers||{}),d=o.limit||25,g=o.offset||0,u=Math.floor(g/d)+1,m=Math.max(1,Math.ceil(r/d)),v=r===0?0:g+1,c=Math.min(g+d,r),y=h.getAuditExportUrl({actor_id:o.search?void 0:void 0,server_id:o.serverId!=="all"?o.serverId:void 0,event_type:o.eventType!=="all"?o.eventType:void 0,status:o.status!=="all"?o.status:void 0,search:o.search.trim()?o.search.trim():void 0},"csv"),b=h.getAuditExportUrl({server_id:o.serverId!=="all"?o.serverId:void 0,event_type:o.eventType!=="all"?o.eventType:void 0,status:o.status!=="all"?o.status:void 0,search:o.search.trim()?o.search.trim():void 0},"jsonl"),f=n?n.is_valid?`
\uD83D\uDEE1️ - Chain Verified: 100% Tamper Free (${o.total_records} events) + Chain Verified: 100% Tamper Free (${n.total_records} events)
`:`
⚠️ - TAMPER DETECTED at Record #${o.corrupted_at_index} + TAMPER DETECTED at Record #${n.corrupted_at_index}
`:` - `,x=i.map((w)=>``).join(""),A=` + `,x=l.map((w)=>``).join(""),T=`
@@ -1147,7 +1147,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu class="form-input" style="width: 100%; padding-left: 28px; font-size: 12px; height: 32px;" placeholder="Search trace, actor, capability, hash, error..." - value="${_(n.search)}" + value="${i(o.search)}" oninput="window.app.handleAuditSearchInput(this.value)" /> \uD83D\uDD0D @@ -1160,12 +1160,12 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu style="width: 100%; font-size: 12px; height: 32px;" onchange="window.app.handleAuditStatusFilter(this.value)" > - - - - - - + + + + + +
@@ -1176,16 +1176,16 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu style="width: 100%; font-size: 12px; height: 32px;" onchange="window.app.handleAuditEventTypeFilter(this.value)" > - - - - - - - - - - + + + + + + + + + +
@@ -1196,7 +1196,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu style="width: 100%; font-size: 12px; height: 32px;" onchange="window.app.handleAuditServerFilter(this.value)" > - + ${x}
@@ -1214,10 +1214,10 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- `,R=` + `,I=`
- Showing ${m}–${d} of ${r} events + Showing ${v}–${c} of ${r} events | Page Size:
@@ -1236,7 +1236,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu - Page ${p} of ${g} + Page ${u} of ${m}
- `,T="";if(t.length===0)T=` + `,E="";if(t.length===0)E=`
\uD83D\uDD0D
No Matching Audit Events
No audit records match your currently selected filters. Try broadening your search or resetting filters.
- `;else T=t.map((w)=>{let z=new Date(Math.floor(w.timestamp_ns/1e6)).toLocaleString(),L='SUCCESS';if(w.status==="denied")L='DENIED';else if(w.status==="intercepted")L='HITL INTERCEPT';else if(w.status==="failed")L='FAILED';else if(w.status==="cancelled")L='CANCELLED';let N=w.sanitized_args?JSON.stringify(w.sanitized_args):"-",D=w.actor_id||w.operator_id||"anonymous",q=w.server_id||"system",U=w.capability_id||w.event_type,V=w.execution_latency_us?`${(w.execution_latency_us/1000).toFixed(1)}ms`:"-";return` + `;else E=t.map((w)=>{let C=new Date(Math.floor(w.timestamp_ns/1e6)).toLocaleString(),A='SUCCESS';if(w.status==="denied")A='DENIED';else if(w.status==="intercepted")A='HITL INTERCEPT';else if(w.status==="failed")A='FAILED';else if(w.status==="cancelled")A='CANCELLED';let L=w.sanitized_args?JSON.stringify(w.sanitized_args):"-",M=w.actor_id||w.operator_id||"anonymous",R=w.server_id||"system",B=w.capability_id||w.event_type,O=w.execution_latency_us?`${(w.execution_latency_us/1000).toFixed(1)}ms`:"-";return`
- ${_(w.id)} - ${L} - ${_(U)} + ${i(w.id)} + ${A} + ${i(B)}
-
${_(z)}
+
${i(C)}
-
Actor: ${_(D)}
-
Server: ${_(q)}
-
Trace: ${_(w.trace_id)}
-
Latency: ${V}
+
Actor: ${i(M)}
+
Server: ${i(R)}
+
Trace: ${i(w.trace_id)}
+
Latency: ${O}
- Args: ${_(N)} + Args: ${i(L)}
-
prev_hash: ${_(w.prev_hash.slice(0,16))}...
-
hash: ${_(w.hash.slice(0,16))}...
+
prev_hash: ${i(w.prev_hash.slice(0,16))}...
+
hash: ${i(w.hash.slice(0,16))}...
- `}).join("");let S="";if(s){let w=new Date(Math.floor(s.timestamp_ns/1e6)).toISOString();S=` + `}).join("");let k="";if(s){let w=new Date(Math.floor(s.timestamp_ns/1e6)).toISOString();k=`
\uD83D\uDD12 -

Audit Event Details (${_(s.id)})

+

Audit Event Details (${i(s.id)})

@@ -1331,36 +1331,36 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
-
Timestamp: ${_(w)}
-
Status: ${_(s.status.toUpperCase())}
-
Event Type: ${_(s.event_type)}
-
Server: ${_(s.server_id||"system")}
-
Capability: ${_(s.capability_id||"-")}
-
Actor / Operator: ${_(s.actor_id||s.operator_id||"anonymous")}
-
Trace ID: ${_(s.trace_id)}
-
Request ID: ${_(s.request_id||"-")}
-
Client IP: ${_(s.client_ip||"-")}
+
Timestamp: ${i(w)}
+
Status: ${i(s.status.toUpperCase())}
+
Event Type: ${i(s.event_type)}
+
Server: ${i(s.server_id||"system")}
+
Capability: ${i(s.capability_id||"-")}
+
Actor / Operator: ${i(s.actor_id||s.operator_id||"anonymous")}
+
Trace ID: ${i(s.trace_id)}
+
Request ID: ${i(s.request_id||"-")}
+
Client IP: ${i(s.client_ip||"-")}
Latency: ${s.execution_latency_us?`${(s.execution_latency_us/1000).toFixed(2)} ms`:"-"}
${s.error_message?`
-
Error (${_(s.error_code||"ERROR")}):
-
${_(s.error_message)}
+
Error (${i(s.error_code||"ERROR")}):
+
${i(s.error_message)}
`:""}
Sanitized Arguments
-
${_(JSON.stringify(s.sanitized_args||{},null,2))}
+
${i(JSON.stringify(s.sanitized_args||{},null,2))}
${s.sanitized_response?`
Sanitized Response
-
${_(JSON.stringify(s.sanitized_response,null,2))}
+
${i(JSON.stringify(s.sanitized_response,null,2))}
`:""} @@ -1369,11 +1369,11 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
Tamper-Evidence Cryptographic Hashes
Previous Chain Hash (prev_hash): -
${_(s.prev_hash)}
+
${i(s.prev_hash)}
Record Hash Signature (hash): -
${_(s.hash)}
+
${i(s.hash)}
@@ -1391,7 +1391,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu Cryptographically tamper-evident, append-only execution log for SOC2 & ISO 27001 compliance.
- ${v} + ${f} \uD83D\uDCE5 Export CSV \uD83D\uDCE5 Export JSONL @@ -1419,7 +1419,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${A} + ${T}
@@ -1429,49 +1429,49 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${T} + ${E}
- ${r>0?R:""} + ${r>0?I:""} - ${S} - `}function _(e){if(!e)return"";return String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function pe(){let e=c.getState(),t=e.activeProfile,a=t?e.config.profiles?.[t]:void 0,o=!!a,n=e.config.policy||{},r=a?.policy,s=o?r||{}:n,i=s.allow||[],l=s.deny||[],u=s.redact_keys||s.redactKeys||[],p=s.require_approval||s.requireApproval||[],g=i.length===0?` -
${o?"No profile allow list (inherits global rules)":"No allow list (all non-denied operations permitted)"}
- `:i.map((S,w)=>` + ${k} + `}function re(){let e=p.getState(),t=e.activeProfile,a=t?e.config.profiles?.[t]:void 0,n=!!a,o=e.config.policy||{},r=a?.policy,s=n?r||{}:o,l=s.allow||[],d=s.deny||[],g=s.redact_keys||s.redactKeys||[],u=s.require_approval||s.requireApproval||[],m=l.length===0?` +
${n?"No profile allow list (inherits global rules)":"No allow list (all non-denied operations permitted)"}
+ `:l.map((k,w)=>`
- ✔ ${j(S)} + ✔ ${i(k)}
- `).join(""),m=l.length===0?` -
${o?"No profile deny rules configured":"No deny rules configured"}
- `:l.map((S,w)=>` + `).join(""),v=d.length===0?` +
${n?"No profile deny rules configured":"No deny rules configured"}
+ `:d.map((k,w)=>`
- ✖ ${j(S)} + ✖ ${i(k)}
- `).join(""),d=p.length===0?` -
${o?"No profile human-in-the-loop triggers configured":"No human-in-the-loop approval rules configured"}
- `:p.map((S,w)=>` + `).join(""),c=u.length===0?` +
${n?"No profile human-in-the-loop triggers configured":"No human-in-the-loop approval rules configured"}
+ `:u.map((k,w)=>`
- \uD83D\uDEE1️ ${j(S)} + \uD83D\uDEE1️ ${i(k)}
- `).join(""),y=u.length===0?` -
${o?"No profile key redaction patterns configured":"No key redaction patterns configured"}
- `:u.map((S,w)=>` + `).join(""),y=g.length===0?` +
${n?"No profile key redaction patterns configured":"No key redaction patterns configured"}
+ `:g.map((k,w)=>` - ${j(S)} + ${i(k)} ✕ - `).join(""),b=o?` + `).join(""),b=n?`
\uD83D\uDEE1️
- Viewing & Editing Policy for Profile Constellation: ${j(t)} + Viewing & Editing Policy for Profile Constellation: ${i(t)}
Rules defined here apply specifically when requests target this profile. Deny and HITL rules are strictly additive with global rules. @@ -1484,11 +1484,11 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
Global security policy rules governing wildcard access control, human-in-the-loop triggers, and sensitive key masking. (Select an active profile in the top bar to edit per-profile rules).
- `,v=Object.keys(e.config.mcpServers||{}),x=a?.servers||[],A=o?v.filter((S)=>!x.includes(S)):[],R=o?` + `,f=Object.keys(e.config.mcpServers||{}),x=a?.servers||[],T=n?f.filter((k)=>!x.includes(k)):[],I=n?`
- Constellation Server Boundaries (Profile: ${j(t)}) - ${x.length} of ${v.length} servers active + Constellation Server Boundaries (Profile: ${i(t)}) + ${x.length} of ${f.length} servers active
@@ -1496,9 +1496,9 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu ✔ Included Servers (${x.length})
- ${x.length>0?x.map((S)=>` + ${x.length>0?x.map((k)=>` - ${j(S)} + ${i(k)} `).join(""):'No servers included'}
@@ -1506,28 +1506,28 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- \uD83D\uDEAB Excluded Servers (${A.length}) · Implicitly Denied + \uD83D\uDEAB Excluded Servers (${T.length}) · Implicitly Denied
- ${A.length>0?A.map((S)=>` + ${T.length>0?T.map((k)=>` - ${j(S)} - + ${i(k)} + `).join(""):'All servers included in constellation'}
- `:"",T=o&&A.length>0?` + `:"",E=n&&T.length>0?`
- Implicit Boundary Denials (${A.length}) + Implicit Boundary Denials (${T.length})
- ${A.map((S)=>` + ${T.map((k)=>`
- ✖ ${j(S)}.* + ✖ ${i(k)}.* server excluded
`).join("")} @@ -1536,7 +1536,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu `:"";return` ${b} - ${R} + ${I}
@@ -1545,7 +1545,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu Allow List Patterns
- ${g} + ${m}
@@ -1559,8 +1559,8 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu Deny List Patterns (Strict Precedence)
- ${m} - ${T} + ${v} + ${E}
@@ -1574,7 +1574,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu Human-in-the-Loop Triggers
- ${d} + ${c}
@@ -1610,7 +1610,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- +
@@ -1623,7 +1623,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- +
@@ -1633,7 +1633,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- ${typeof s.webhook==="object"&&s.webhook?.url?`Active Target: ${j(s.webhook.url)}`:"No webhook configured"} + ${typeof s.webhook==="object"&&s.webhook?.url?`Active Target: ${i(s.webhook.url)}`:"No webhook configured"}
@@ -1652,47 +1652,47 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
- `}function j(e){return String(e||"").replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function ue(){let e=c.getState(),t=e.config,a=Object.entries(t.capabilityAliases||{}),o=Object.entries(t.resourceAliases||{}),n=Object.entries(t.promptAliases||{}),r="";if(a.length===0&&o.length===0&&n.length===0)r=` + `}function se(){let e=p.getState(),t=e.config,a=Object.entries(t.capabilityAliases||{}),n=Object.entries(t.resourceAliases||{}),o=Object.entries(t.promptAliases||{}),r="";if(a.length===0&&n.length===0&&o.length===0)r=`
- No facade aliases configured in ${P(e.configPath)}. Add short names or custom descriptions to prune token payload sizes. + No facade aliases configured in ${i(e.configPath)}. Add short names or custom descriptions to prune token payload sizes.
- `;else{for(let[s,i]of a){let l=typeof i==="string"?i:i.target,u=typeof i==="object"&&i.summary?i.summary:"",p=typeof i==="object"&&!!i.passthrough,g=p?'⚡ passthrough':"",m=u?`
\uD83D\uDCAC ${P(u)}
`:"";r+=` -
+ `;else{for(let[s,l]of a){let d=typeof l==="string"?l:l.target,g=typeof l==="object"&&l.summary?l.summary:"",u=typeof l==="object"&&!!l.passthrough,m=u?'⚡ passthrough':"",v=g?`
\uD83D\uDCAC ${i(g)}
`:"";r+=` +
Tool
- ${P(s)} - ${g} + ${i(s)} + ${m}
- ${P(l)} - ${m} + ${i(d)} + ${v}
- +
- `}for(let[s,i]of o){let l=typeof i==="string"?i:i.target,u=typeof i==="object"&&i.summary?i.summary:"",p=u?`
\uD83D\uDCAC ${P(u)}
`:"";r+=` -
+ `}for(let[s,l]of n){let d=typeof l==="string"?l:l.target,g=typeof l==="object"&&l.summary?l.summary:"",u=g?`
\uD83D\uDCAC ${i(g)}
`:"";r+=` +
Resource - ${P(s)} + ${i(s)}
- ${P(l)} - ${p} + ${i(d)} + ${u}
- +
- `}for(let[s,i]of n){let l=typeof i==="string"?i:i.target,u=typeof i==="object"&&i.summary?i.summary:"",p=u?`
\uD83D\uDCAC ${P(u)}
`:"";r+=` -
+ `}for(let[s,l]of o){let d=typeof l==="string"?l:l.target,g=typeof l==="object"&&l.summary?l.summary:"",u=g?`
\uD83D\uDCAC ${i(g)}
`:"";r+=` +
Prompt - ${P(s)} + ${i(s)}
- ${P(l)} - ${p} + ${i(d)} + ${u}
- +
`}}return` @@ -1739,7 +1739,7 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
${r}
- `}function P(e){return String(e||"").replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function ge(){let e=c.getState(),t=e.config,a=t.profiles||{},o=Object.entries(a),n=t.mcpServers||{},r=e.activeProfile,s="";if(o.length===0)s=` + `}function ae(){let e=p.getState(),t=e.config,a=t.profiles||{},n=Object.entries(a),o=t.mcpServers||{},r=e.activeProfile,s="";if(n.length===0)s=`
No Profiles Configured

@@ -1747,50 +1747,50 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu

- `;else s=o.map(([i,l])=>{let u=r===i,p=l.servers.map((x)=>`${Y(x)}`).join(" "),g=(e.capabilities||[]).filter((x)=>l.servers.includes(x.server)).length,m=!!l.policy,d=l.policy?.allow?.length||0,y=l.policy?.deny?.length||0,b=(l.policy?.require_approval||l.policy?.requireApproval||[]).length,v=(l.policy?.redact_keys||l.policy?.redactKeys||[]).length;return` -
+ `;else s=n.map(([l,d])=>{let g=r===l,u=d.servers.map((x)=>`${i(x)}`).join(" "),m=(e.capabilities||[]).filter((x)=>d.servers.includes(x.server)).length,v=!!d.policy,c=d.policy?.allow?.length||0,y=d.policy?.deny?.length||0,b=(d.policy?.require_approval||d.policy?.requireApproval||[]).length,f=(d.policy?.redact_keys||d.policy?.redactKeys||[]).length;return` +
- ${Y(i)} - ${u?'ACTIVE IN UI':""} - ${l.servers.length} server${l.servers.length===1?"":"s"} - ${g} capabilities - ${m?'CUSTOM POLICY':""} + ${i(l)} + ${g?'ACTIVE IN UI':""} + ${d.servers.length} server${d.servers.length===1?"":"s"} + ${m} capabilities + ${v?'CUSTOM POLICY':""}
- ${Y(l.description||"No description provided")} + ${i(d.description||"No description provided")}
-
+
Servers: - ${p||'None'} + ${u||'None'}
- ${m?` + ${v?`
Policy Overlay: - ${d>0?`Allow: ${d}`:""} + ${c>0?`Allow: ${c}`:""} ${y>0?`Deny: ${y}`:""} ${b>0?`HITL: ${b}`:""} - ${v>0?`Redact: ${v}`:""} - ${d===0&&y===0&&b===0&&v===0?'Configured':""} + ${f>0?`Redact: ${f}`:""} + ${c===0&&y===0&&b===0&&f===0?'Configured':""}
`:""}
- ${u?` + ${g?` `:` - `} - -
@@ -1818,26 +1818,26 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
${s} - `}function Y(e){return String(e||"").replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}function me(){let e=c.getState(),t=e.secrets||[],a=e.config.mcpServers||{},o=[];for(let[p,g]of Object.entries(a)){let m=Q(p,g.command,g.args);if(m){let d=Object.keys(g.env||{});for(let y of m.envFields)if(y.required&&!d.includes(y.key))o.push({server:p,key:y.key,uri:"(Not Configured)",is_vault:!1,exists:!1,backend:"Required Variable",display:`Required by ${m.name} template (${y.label})`,is_unconfigured_requirement:!0})}}let n=[...t,...o],r=n.length,s=n.filter((p)=>p.is_vault&&p.exists!==!1).length,i=n.filter((p)=>p.exists===!1).length,l=n.filter((p)=>!p.is_vault&&p.exists!==!1).length,u=n.length===0?` + `}function oe(){let e=p.getState(),t=e.secrets||[],a=e.config.mcpServers||{},n=[];for(let[u,m]of Object.entries(a)){let v=N(u,m.command,m.args);if(v){let c=Object.keys(m.env||{});for(let y of v.envFields)if(y.required&&!c.includes(y.key))n.push({server:u,key:y.key,uri:"(Not Configured)",is_vault:!1,exists:!1,backend:"Required Variable",display:`Required by ${v.name} template (${y.label})`,is_unconfigured_requirement:!0})}}let o=[...t,...n],r=o.length,s=o.filter((u)=>u.is_vault&&u.exists!==!1).length,l=o.filter((u)=>u.exists===!1).length,d=o.filter((u)=>!u.is_vault&&u.exists!==!1).length,g=o.length===0?`
No environment variables or secrets configured in active servers.
- `:n.map((p)=>{let g='Plaintext (Unsecured)',m=p.exists===!1;if(p.is_unconfigured_requirement)g='⚠️ Not Configured (Required)';else if(m)g=`⚠️ Missing from ${H(p.backend)}`;else if(p.is_vault)g=`\uD83D\uDD12 ${H(p.backend)}`;return` + `:o.map((u)=>{let m='Plaintext (Unsecured)',v=u.exists===!1;if(u.is_unconfigured_requirement)m='⚠️ Not Configured (Required)';else if(v)m=`⚠️ Missing from ${i(u.backend)}`;else if(u.is_vault)m=`\uD83D\uDD12 ${i(u.backend)}`;return`
- ${H(p.server)} - ${H(p.key)} - ${H(p.display)} -
${g}
+ ${i(u.server)} + ${i(u.key)} + ${i(u.display)} +
${m}
- ${p.is_unconfigured_requirement?` - - `:m?` - - - `:!p.is_vault?` - + ${u.is_unconfigured_requirement?` + + `:v?` + + + `:!u.is_vault?` + `:` - + `}
@@ -1860,8 +1860,8 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu
Missing or Unsecured
-
${i+l}
-
${i>0?`${i} missing required key(s)`:l>0?"Recommend migrating to Keychain":"All credentials protected"}
+
${l+d}
+
${l>0?`${l} missing required key(s)`:d>0?"Recommend migrating to Keychain":"All credentials protected"}
@@ -1888,39 +1888,39 @@ class ae{state={configPath:"mcp_servers.json",config:{mcpServers:{}},serverStatu ACTION
- ${u} + ${g}
- `}function H(e){return String(e||"").replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}class ve{activeTemplateCategory="all";activeTemplateFilter="";selectedTemplate=null;pendingClientId=null;async init(){let e=window.location.port?`:${window.location.port}`:"",t=document.getElementById("daemon-port-label");if(t)t.textContent=`Daemon ${e}`;await this.refreshData(),this.initSSE(),this.render(),c.subscribe(()=>{this.render()})}auditSearchTimeout=null;async refreshData(){try{let e=c.getState(),t=e.auditFilters,a=e.activeProfile||void 0,[o,n,r,s,i,l,u,p,g,m,d]=await Promise.all([h.getConfig(),h.listCapabilities(a),h.listResources(a),h.listPrompts(a),h.getCatalogEvents(),h.listApprovals(),h.listTasks(),h.listAuditEvents({server_id:t.serverId!=="all"?t.serverId:void 0,event_type:t.eventType!=="all"?t.eventType:void 0,status:t.status!=="all"?t.status:void 0,search:t.search.trim()?t.search.trim():void 0,limit:t.limit,offset:t.offset}),h.getAuditStats(),h.getClients().catch(()=>({ok:!1,clients:[]})),h.getSecrets().catch(()=>({ok:!1,secrets:[],keychain_service:"warmplane"}))]);if(m&&m.ok&&Array.isArray(m.clients))c.setState({clients:m.clients});if(d&&d.ok&&Array.isArray(d.secrets))c.setState({secrets:d.secrets});if(o.ok)c.setState({configPath:o.config_path,config:o.config,serverStatuses:o.server_statuses||{},circuitBreakers:o.circuit_breakers||[],metrics:{totalCatalogRequests:o.metrics?.total_catalog_requests||0,totalEtagHits:o.metrics?.total_etag_hits||0,totalToolCalls:o.metrics?.total_tool_calls||0,totalToolDurationUs:o.metrics?.total_tool_duration_us||0}});if(n&&Array.isArray(n.capabilities)){let y=c.getState().selectedCapabilityId,v=n.capabilities.some((x)=>x.id===y)?y:n.capabilities.length>0?n.capabilities[0].id:null;c.setState({capabilities:n.capabilities,capabilitiesHiddenByPolicy:n.hidden_by_policy||0,selectedCapabilityId:v})}if(r&&Array.isArray(r.resources)){let y=c.getState().selectedResourceId,v=r.resources.some((x)=>x.uri===y||x.id===y)?y:r.resources.length>0?r.resources[0].uri||r.resources[0].id||null:null;c.setState({resources:r.resources,resourcesHiddenByPolicy:r.hidden_by_policy||0,selectedResourceId:v})}if(s&&Array.isArray(s.prompts)){let y=c.getState().selectedPromptId,v=s.prompts.some((x)=>x.name===y||x.id===y)?y:s.prompts.length>0?s.prompts[0].name||s.prompts[0].id||null:null;c.setState({prompts:s.prompts,promptsHiddenByPolicy:s.hidden_by_policy||0,selectedPromptId:v})}if(i&&Array.isArray(i.events))c.setState({catalogEvents:i.events});if(l&&Array.isArray(l.approvals))c.setState({approvals:l.approvals});if(u&&Array.isArray(u.tasks))c.setState({tasks:u.tasks});if(p&&Array.isArray(p.events))c.setState({auditEvents:p.events,auditTotal:p.total??p.events.length});if(g&&g.ok)c.setState({auditStats:g})}catch(e){console.error("Failed to fetch daemon state:",e)}}async refreshAuditEvents(){try{let t=c.getState().auditFilters,[a,o]=await Promise.all([h.listAuditEvents({server_id:t.serverId!=="all"?t.serverId:void 0,event_type:t.eventType!=="all"?t.eventType:void 0,status:t.status!=="all"?t.status:void 0,search:t.search.trim()?t.search.trim():void 0,limit:t.limit,offset:t.offset}),h.getAuditStats()]);if(a&&Array.isArray(a.events))c.setState({auditEvents:a.events,auditTotal:a.total??a.events.length});if(o&&o.ok)c.setState({auditStats:o})}catch(e){console.error("Failed to refresh audit events:",e)}}handleAuditSearchInput(e){let a={...c.getState().auditFilters,search:e,offset:0};c.setState({auditFilters:a}),clearTimeout(this.auditSearchTimeout),this.auditSearchTimeout=setTimeout(()=>{this.refreshAuditEvents()},250)}handleAuditStatusFilter(e){let t=c.getState();c.setState({auditFilters:{...t.auditFilters,status:e,offset:0}}),this.refreshAuditEvents()}handleAuditEventTypeFilter(e){let t=c.getState();c.setState({auditFilters:{...t.auditFilters,eventType:e,offset:0}}),this.refreshAuditEvents()}handleAuditServerFilter(e){let t=c.getState();c.setState({auditFilters:{...t.auditFilters,serverId:e,offset:0}}),this.refreshAuditEvents()}handleAuditPageSize(e){let t=parseInt(e,10)||25,a=c.getState();c.setState({auditFilters:{...a.auditFilters,limit:t,offset:0}}),this.refreshAuditEvents()}clearAuditFilters(){let e=c.getState();c.setState({auditFilters:{search:"",status:"all",eventType:"all",serverId:"all",limit:e.auditFilters.limit||25,offset:0}}),this.refreshAuditEvents()}auditPrevPage(){let e=c.getState(),{limit:t,offset:a}=e.auditFilters,o=Math.max(0,a-t);if(o!==a)c.setState({auditFilters:{...e.auditFilters,offset:o}}),this.refreshAuditEvents()}auditNextPage(){let e=c.getState(),{limit:t,offset:a}=e.auditFilters,o=e.auditTotal;if(a+to.id===e)||null;c.setState({auditSelectedEvent:a})}async verifyAuditChain(){try{let e=await h.verifyAuditChain();if(e&&e.report)c.setState({auditVerification:e.report})}catch(e){console.error("Failed to verify audit chain:",e)}}async refreshApprovals(){try{let e=await h.listApprovals();if(e&&Array.isArray(e.approvals))c.setState({approvals:e.approvals})}catch(e){console.error("Failed to refresh approvals:",e)}}initSSE(){try{let e=new EventSource("/v1/resources/updates");e.onmessage=(t)=>{c.addEventLog("SSE","/v1/resources/updates","UPDATED","0.1ms"),this.refreshData()}}catch(e){console.warn("SSE connection unavailable")}}switchTab(e){c.setState({activeTab:e}),this.refreshData()}render(){let e=c.getState(),t=document.getElementById("app-main");if(!t)return;let a=(e.tasks||[]).filter((l)=>l.status==="input_required").length,o=(e.approvals||[]).filter((l)=>l.status==="pending").length,n=Math.max(a,o),r=document.getElementById("nav-approvals-badge");if(r)r.textContent=n>0?`${n}`:"",r.style.display=n>0?"inline-block":"none";document.querySelectorAll(".nav-item").forEach((l)=>{let u=l.getAttribute("data-tab");if(u===e.activeTab||e.activeTab==="tasks"&&u==="approvals"||e.activeTab==="approvals"&&u==="tasks")l.classList.add("active");else l.classList.remove("active")});let s=document.getElementById("top-title"),i={overview:"Overview Cockpit",servers:"Server Hub & Connections",playground:"MCP Capability Playground",tasks:"SEP-2663 Tasks & HITL Review",approvals:"SEP-2663 Tasks & HITL Review",audit:"WORM Audit & Compliance Ledger",policy:"Security Governance & Redaction",secrets:"Native OS Keychain & Secrets Vault",aliases:"Facade & Alias Studio",profiles:"Server Constellation Profiles"};if(s)s.textContent=i[e.activeTab]||"Control Deck";switch(this.renderTopProfileSelector(),e.activeTab){case"overview":t.innerHTML=oe();break;case"servers":t.innerHTML=ie();break;case"playground":t.innerHTML=le();break;case"tasks":case"approvals":t.innerHTML=de(e);break;case"audit":t.innerHTML=ce();break;case"policy":t.innerHTML=pe();break;case"secrets":t.innerHTML=me();break;case"aliases":t.innerHTML=ue();break;case"profiles":t.innerHTML=ge();break}}toggleClientsCollapse(){let e=c.getState().clientsCollapsed;c.setState({clientsCollapsed:!e}),this.render()}async saveNewVaultSecret(){let e=document.getElementById("vault-new-key"),t=document.getElementById("vault-new-val"),a=document.getElementById("vault-new-service"),o=e?.value.trim(),n=t?.value.trim(),r=a?.value.trim()||"warmplane";if(!o||!n){alert("Key and secret value are required");return}try{let s=await h.saveSecret(o,n,r);if(s.ok){if(alert(`Secret '${o}' saved securely into OS Keychain! -Reference: ${s.uri}`),e)e.value="";if(t)t.value="";await this.refreshData()}else alert(`Failed to save secret: ${s.error}`)}catch(s){alert(`Error saving secret: ${s.message}`)}}async deleteVaultSecret(e,t){let a=t?`Are you sure you want to remove secret '${e}' from OS Keychain and server '${t}'?`:`Are you sure you want to remove secret '${e}' from OS Keychain?`;if(!confirm(a))return;try{let o=await h.deleteSecret(e);if(o.ok||o.error?.includes("not found")){if(t){let s=(c.getState().config.mcpServers||{})[t];if(s&&s.env&&s.env[e]){let i={...s.env};delete i[e];let l={...s,env:i};await h.upsertServer(t,l)}}await this.refreshData()}else alert(`Failed to delete secret: ${o.error}`)}catch(o){alert(`Error deleting secret: ${o.message}`)}}async removeSecretFromConfig(e,t){if(!confirm(`Remove environment variable '${t}' from '${e}' configuration?`))return;try{let n=(c.getState().config.mcpServers||{})[e];if(n&&n.env&&n.env[t]){let r={...n.env};delete r[t];let s={...n,env:r},i=await h.upsertServer(e,s);if(i.ok)await this.refreshData();else alert(`Failed to update server config: ${i.error}`)}}catch(a){alert(`Error removing secret from config: ${a.message}`)}}async quickVaultEnv(e,t){let a=prompt(`Enter secret value to store in OS Keychain for ${e}.${t}:`);if(!a)return;try{let o=await h.saveSecret(t,a,"warmplane");if(!o.ok){alert(`Failed to save to Keychain: ${o.error}`);return}let s=(c.getState().config.mcpServers||{})[e];if(s){let i={...s.env||{},[t]:`keychain://warmplane/${t}`},l={...s,env:i},u=await h.upsertServer(e,l);if(u.ok)await this.refreshData(),alert(`Successfully configured ${e}.${t} in OS Keychain!`);else alert(`Failed to update server config: ${u.error}`)}}catch(o){alert(`Error during migration: ${o.message}`)}}async refreshTasks(){try{let e=await h.listTasks();if(e&&Array.isArray(e.tasks))c.setState({tasks:e.tasks})}catch(e){console.error("Failed to refresh tasks:",e)}}filterTasksByStatus(e){c.setState({taskFilterStatus:e})}togglePlaygroundAsyncTask(e){c.setState({playgroundAsyncTask:e})}async submitTaskInputResponses(e){let a=c.getState().tasks.find((r)=>r.taskId===e)?.inputRequests||{},o=Object.keys(a),n={};if(o.length>0)for(let r of o){let s=a[r];if(s&&s.type==="approval_review"){let i=document.getElementById(`task-input-${e}-${r}-decision`),l=document.getElementById(`task-input-${e}-${r}`),u=i?i.value==="true":!0,p=void 0;if(l&&l.value.trim())try{p=JSON.parse(l.value.trim())}catch{alert("Invalid JSON in parameters editor");return}n[r]={approved:u,modified_args:p,reason:u?void 0:"Operator rejected execution via Tasks review"}}else{let i=document.getElementById(`task-input-${e}-${r}`);if(i){let l=i.value.trim();try{n[r]=JSON.parse(l)}catch{n[r]=l}}}}else{let r=document.getElementById(`task-raw-input-${e}`);if(r&&r.value.trim())try{Object.assign(n,JSON.parse(r.value.trim()))}catch{alert("Invalid JSON in raw input responses");return}}try{let r=await h.updateTask(e,n);if(r.ok)await this.refreshTasks();else alert(`Task update failed: ${r.error?.message||r.error||"Unknown error"}`)}catch(r){alert(`Error updating task: ${r.message}`)}}async promptCancelTask(e){let t=prompt("Reason for cancelling task:");if(t===null)return;try{let a=await h.cancelTask(e,t||void 0);if(a.ok)await this.refreshTasks();else alert(`Task cancellation failed: ${a.error?.message||a.error||"Unknown error"}`)}catch(a){alert(`Error cancelling task: ${a.message}`)}}async openTaskInspectorModal(e){this.closeModals();let t=document.getElementById("modal-task-inspector");if(!t)return;let a=document.getElementById("modal-task-title"),o=document.getElementById("modal-task-body"),n=document.getElementById("modal-task-footer");if(a)a.textContent=`Task Inspector: ${e}`;if(o)o.innerHTML=` + `}class ne{activeTemplateCategory="all";activeTemplateFilter="";selectedTemplate=null;pendingClientId=null;async init(){let e=window.location.port?`:${window.location.port}`:"",t=document.getElementById("daemon-port-label");if(t)t.textContent=`Daemon ${e}`;await this.refreshData(),this.initSSE(),this.render(),p.subscribe(()=>{this.render()})}auditSearchTimeout=null;async refreshData(){try{let e=p.getState(),t=e.auditFilters,a=e.activeProfile||void 0,[n,o,r,s,l,d,g,u,m,v,c]=await Promise.all([h.getConfig(),h.listCapabilities(a),h.listResources(a),h.listPrompts(a),h.getCatalogEvents(),h.listApprovals(),h.listTasks(),h.listAuditEvents({server_id:t.serverId!=="all"?t.serverId:void 0,event_type:t.eventType!=="all"?t.eventType:void 0,status:t.status!=="all"?t.status:void 0,search:t.search.trim()?t.search.trim():void 0,limit:t.limit,offset:t.offset}),h.getAuditStats(),h.getClients().catch(()=>({ok:!1,clients:[]})),h.getSecrets().catch(()=>({ok:!1,secrets:[],keychain_service:"warmplane"}))]);if(v&&v.ok&&Array.isArray(v.clients))p.setState({clients:v.clients});if(c&&c.ok&&Array.isArray(c.secrets))p.setState({secrets:c.secrets});if(n.ok)p.setState({configPath:n.config_path,config:n.config,serverStatuses:n.server_statuses||{},circuitBreakers:n.circuit_breakers||[],metrics:{totalCatalogRequests:n.metrics?.total_catalog_requests||0,totalEtagHits:n.metrics?.total_etag_hits||0,totalToolCalls:n.metrics?.total_tool_calls||0,totalToolDurationUs:n.metrics?.total_tool_duration_us||0}});if(o&&Array.isArray(o.capabilities)){let y=p.getState().selectedCapabilityId,f=o.capabilities.some((x)=>x.id===y)?y:o.capabilities.length>0?o.capabilities[0].id:null;p.setState({capabilities:o.capabilities,capabilitiesHiddenByPolicy:o.hidden_by_policy||0,selectedCapabilityId:f})}if(r&&Array.isArray(r.resources)){let y=p.getState().selectedResourceId,f=r.resources.some((x)=>x.uri===y||x.id===y)?y:r.resources.length>0?r.resources[0].uri||r.resources[0].id||null:null;p.setState({resources:r.resources,resourcesHiddenByPolicy:r.hidden_by_policy||0,selectedResourceId:f})}if(s&&Array.isArray(s.prompts)){let y=p.getState().selectedPromptId,f=s.prompts.some((x)=>x.name===y||x.id===y)?y:s.prompts.length>0?s.prompts[0].name||s.prompts[0].id||null:null;p.setState({prompts:s.prompts,promptsHiddenByPolicy:s.hidden_by_policy||0,selectedPromptId:f})}if(l&&Array.isArray(l.events))p.setState({catalogEvents:l.events});if(d&&Array.isArray(d.approvals))p.setState({approvals:d.approvals});if(g&&Array.isArray(g.tasks))p.setState({tasks:g.tasks});if(u&&Array.isArray(u.events))p.setState({auditEvents:u.events,auditTotal:u.total??u.events.length});if(m&&m.ok)p.setState({auditStats:m})}catch(e){console.error("Failed to fetch daemon state:",e)}}async refreshAuditEvents(){try{let t=p.getState().auditFilters,[a,n]=await Promise.all([h.listAuditEvents({server_id:t.serverId!=="all"?t.serverId:void 0,event_type:t.eventType!=="all"?t.eventType:void 0,status:t.status!=="all"?t.status:void 0,search:t.search.trim()?t.search.trim():void 0,limit:t.limit,offset:t.offset}),h.getAuditStats()]);if(a&&Array.isArray(a.events))p.setState({auditEvents:a.events,auditTotal:a.total??a.events.length});if(n&&n.ok)p.setState({auditStats:n})}catch(e){console.error("Failed to refresh audit events:",e)}}handleAuditSearchInput(e){let a={...p.getState().auditFilters,search:e,offset:0};p.setState({auditFilters:a}),clearTimeout(this.auditSearchTimeout),this.auditSearchTimeout=setTimeout(()=>{this.refreshAuditEvents()},250)}handleAuditStatusFilter(e){let t=p.getState();p.setState({auditFilters:{...t.auditFilters,status:e,offset:0}}),this.refreshAuditEvents()}handleAuditEventTypeFilter(e){let t=p.getState();p.setState({auditFilters:{...t.auditFilters,eventType:e,offset:0}}),this.refreshAuditEvents()}handleAuditServerFilter(e){let t=p.getState();p.setState({auditFilters:{...t.auditFilters,serverId:e,offset:0}}),this.refreshAuditEvents()}handleAuditPageSize(e){let t=parseInt(e,10)||25,a=p.getState();p.setState({auditFilters:{...a.auditFilters,limit:t,offset:0}}),this.refreshAuditEvents()}clearAuditFilters(){let e=p.getState();p.setState({auditFilters:{search:"",status:"all",eventType:"all",serverId:"all",limit:e.auditFilters.limit||25,offset:0}}),this.refreshAuditEvents()}auditPrevPage(){let e=p.getState(),{limit:t,offset:a}=e.auditFilters,n=Math.max(0,a-t);if(n!==a)p.setState({auditFilters:{...e.auditFilters,offset:n}}),this.refreshAuditEvents()}auditNextPage(){let e=p.getState(),{limit:t,offset:a}=e.auditFilters,n=e.auditTotal;if(a+tn.id===e)||null;p.setState({auditSelectedEvent:a})}async verifyAuditChain(){try{let e=await h.verifyAuditChain();if(e&&e.report)p.setState({auditVerification:e.report})}catch(e){console.error("Failed to verify audit chain:",e)}}async refreshApprovals(){try{let e=await h.listApprovals();if(e&&Array.isArray(e.approvals))p.setState({approvals:e.approvals})}catch(e){console.error("Failed to refresh approvals:",e)}}initSSE(){try{let e=new EventSource("/v1/resources/updates");e.onmessage=(t)=>{p.addEventLog("SSE","/v1/resources/updates","UPDATED","0.1ms"),this.refreshData()}}catch(e){console.warn("SSE connection unavailable")}}switchTab(e){p.setState({activeTab:e}),this.refreshData()}render(){let e=p.getState(),t=document.getElementById("app-main");if(!t)return;let a=(e.tasks||[]).filter((d)=>d.status==="input_required").length,n=(e.approvals||[]).filter((d)=>d.status==="pending").length,o=Math.max(a,n),r=document.getElementById("nav-approvals-badge");if(r)r.textContent=o>0?`${o}`:"",r.style.display=o>0?"inline-block":"none";document.querySelectorAll(".nav-item").forEach((d)=>{let g=d.getAttribute("data-tab");if(g===e.activeTab||e.activeTab==="tasks"&&g==="approvals"||e.activeTab==="approvals"&&g==="tasks")d.classList.add("active");else d.classList.remove("active")});let s=document.getElementById("top-title"),l={overview:"Overview Cockpit",servers:"Server Hub & Connections",playground:"MCP Capability Playground",tasks:"SEP-2663 Tasks & HITL Review",approvals:"SEP-2663 Tasks & HITL Review",audit:"WORM Audit & Compliance Ledger",policy:"Security Governance & Redaction",secrets:"Native OS Keychain & Secrets Vault",aliases:"Facade & Alias Studio",profiles:"Server Constellation Profiles"};if(s)s.textContent=l[e.activeTab]||"Control Deck";switch(this.renderTopProfileSelector(),e.activeTab){case"overview":t.innerHTML=Y();break;case"servers":t.innerHTML=X();break;case"playground":t.innerHTML=Z();break;case"tasks":case"approvals":t.innerHTML=ee(e);break;case"audit":t.innerHTML=te();break;case"policy":t.innerHTML=re();break;case"secrets":t.innerHTML=oe();break;case"aliases":t.innerHTML=se();break;case"profiles":t.innerHTML=ae();break}}toggleClientsCollapse(){let e=p.getState().clientsCollapsed;p.setState({clientsCollapsed:!e}),this.render()}async saveNewVaultSecret(){let e=document.getElementById("vault-new-key"),t=document.getElementById("vault-new-val"),a=document.getElementById("vault-new-service"),n=e?.value.trim(),o=t?.value.trim(),r=a?.value.trim()||"warmplane";if(!n||!o){alert("Key and secret value are required");return}try{let s=await h.saveSecret(n,o,r);if(s.ok){if(alert(`Secret '${n}' saved securely into OS Keychain! +Reference: ${s.uri}`),e)e.value="";if(t)t.value="";await this.refreshData()}else alert(`Failed to save secret: ${s.error}`)}catch(s){alert(`Error saving secret: ${s.message}`)}}async deleteVaultSecret(e,t){let a=t?`Are you sure you want to remove secret '${e}' from OS Keychain and server '${t}'?`:`Are you sure you want to remove secret '${e}' from OS Keychain?`;if(!confirm(a))return;try{let n=await h.deleteSecret(e);if(n.ok||n.error?.includes("not found")){if(t){let s=(p.getState().config.mcpServers||{})[t];if(s&&s.env&&s.env[e]){let l={...s.env};delete l[e];let d={...s,env:l};await h.upsertServer(t,d)}}await this.refreshData()}else alert(`Failed to delete secret: ${n.error}`)}catch(n){alert(`Error deleting secret: ${n.message}`)}}async removeSecretFromConfig(e,t){if(!confirm(`Remove environment variable '${t}' from '${e}' configuration?`))return;try{let o=(p.getState().config.mcpServers||{})[e];if(o&&o.env&&o.env[t]){let r={...o.env};delete r[t];let s={...o,env:r},l=await h.upsertServer(e,s);if(l.ok)await this.refreshData();else alert(`Failed to update server config: ${l.error}`)}}catch(a){alert(`Error removing secret from config: ${a.message}`)}}async quickVaultEnv(e,t){let a=prompt(`Enter secret value to store in OS Keychain for ${e}.${t}:`);if(!a)return;try{let n=await h.saveSecret(t,a,"warmplane");if(!n.ok){alert(`Failed to save to Keychain: ${n.error}`);return}let s=(p.getState().config.mcpServers||{})[e];if(s){let l={...s.env||{},[t]:`keychain://warmplane/${t}`},d={...s,env:l},g=await h.upsertServer(e,d);if(g.ok)await this.refreshData(),alert(`Successfully configured ${e}.${t} in OS Keychain!`);else alert(`Failed to update server config: ${g.error}`)}}catch(n){alert(`Error during migration: ${n.message}`)}}async refreshTasks(){try{let e=await h.listTasks();if(e&&Array.isArray(e.tasks))p.setState({tasks:e.tasks})}catch(e){console.error("Failed to refresh tasks:",e)}}filterTasksByStatus(e){p.setState({taskFilterStatus:e})}togglePlaygroundAsyncTask(e){p.setState({playgroundAsyncTask:e})}async submitTaskInputResponses(e){let a=p.getState().tasks.find((r)=>r.taskId===e)?.inputRequests||{},n=Object.keys(a),o={};if(n.length>0)for(let r of n){let s=a[r];if(s&&s.type==="approval_review"){let l=document.getElementById(`task-input-${e}-${r}-decision`),d=document.getElementById(`task-input-${e}-${r}`),g=l?l.value==="true":!0,u=void 0;if(d&&d.value.trim())try{u=JSON.parse(d.value.trim())}catch{alert("Invalid JSON in parameters editor");return}o[r]={approved:g,modified_args:u,reason:g?void 0:"Operator rejected execution via Tasks review"}}else{let l=document.getElementById(`task-input-${e}-${r}`);if(l){let d=l.value.trim();try{o[r]=JSON.parse(d)}catch{o[r]=d}}}}else{let r=document.getElementById(`task-raw-input-${e}`);if(r&&r.value.trim())try{Object.assign(o,JSON.parse(r.value.trim()))}catch{alert("Invalid JSON in raw input responses");return}}try{let r=await h.updateTask(e,o);if(r.ok)await this.refreshTasks();else alert(`Task update failed: ${r.error?.message||r.error||"Unknown error"}`)}catch(r){alert(`Error updating task: ${r.message}`)}}async promptCancelTask(e){let t=prompt("Reason for cancelling task:");if(t===null)return;try{let a=await h.cancelTask(e,t||void 0);if(a.ok)await this.refreshTasks();else alert(`Task cancellation failed: ${a.error?.message||a.error||"Unknown error"}`)}catch(a){alert(`Error cancelling task: ${a.message}`)}}async openTaskInspectorModal(e){this.closeModals();let t=document.getElementById("modal-task-inspector");if(!t)return;let a=document.getElementById("modal-task-title"),n=document.getElementById("modal-task-body"),o=document.getElementById("modal-task-footer");if(a)a.textContent=`Task Inspector: ${e}`;if(n)n.innerHTML=`
⏳ Fetching task execution record...
- `;t.classList.add("active");try{let r=await h.getTask(e);if(!r.ok||!r.task){if(o)o.innerHTML=` + `;t.classList.add("active");try{let r=await h.getTask(e);if(!r.ok||!r.task){if(n)n.innerHTML=`
Failed to load task snapshot
-
${f(r.error?.message||"Task not found in runtime registry")}
+
${i(r.error?.message||"Task not found in runtime registry")}
- `;return}let s=r.task,i=s.progress!==void 0?Math.round(s.progress*100):s.status==="completed"?100:s.status==="working"?50:0,l=Math.floor(Date.now()/1000),u=s.expiresAtEpochSecs?Math.max(0,s.expiresAtEpochSecs-l):s.ttlSeconds||300,p=s.status==="completed"||s.status==="cancelled"||s.status==="failed",g=s.status==="completed"?"var(--green-400)":s.status==="working"?"var(--cyan-400)":s.status==="input_required"?"var(--amber-300)":s.status==="cancelled"?"var(--text-muted)":"var(--red-400)",m=s.status==="completed"?"rgba(52, 211, 153, 0.15)":s.status==="working"?"rgba(56, 189, 248, 0.15)":s.status==="input_required"?"rgba(245, 158, 11, 0.18)":s.status==="cancelled"?"rgba(148, 163, 184, 0.15)":"rgba(248, 113, 113, 0.15)",d=!!s.error,y=s.result!==void 0&&s.result!==null,b=s.inputRequests&&Object.keys(s.inputRequests).length>0;if(o)o.innerHTML=` + `;return}let s=r.task,l=s.progress!==void 0?Math.round(s.progress*100):s.status==="completed"?100:s.status==="working"?50:0,d=Math.floor(Date.now()/1000),g=s.expiresAtEpochSecs?Math.max(0,s.expiresAtEpochSecs-d):s.ttlSeconds||300,u=s.status==="completed"||s.status==="cancelled"||s.status==="failed",m=s.status==="completed"?"var(--green-400)":s.status==="working"?"var(--cyan-400)":s.status==="input_required"?"var(--amber-300)":s.status==="cancelled"?"var(--text-muted)":"var(--red-400)",v=s.status==="completed"?"rgba(52, 211, 153, 0.15)":s.status==="working"?"rgba(56, 189, 248, 0.15)":s.status==="input_required"?"rgba(245, 158, 11, 0.18)":s.status==="cancelled"?"rgba(148, 163, 184, 0.15)":"rgba(248, 113, 113, 0.15)",c=!!s.error,y=s.result!==void 0&&s.result!==null,b=s.inputRequests&&Object.keys(s.inputRequests).length>0;if(n)n.innerHTML=`
- - ${f(s.status.toUpperCase())} + + ${i(s.status.toUpperCase())} - ${f(s.capabilityId||"Tool Execution")} + ${i(s.capabilityId||"Tool Execution")} - ${s.serverId?`via ${f(s.serverId)}`:""} + ${s.serverId?`via ${i(s.serverId)}`:""}
- Task ID: ${f(s.taskId)} + Task ID: ${i(s.taskId)}
Created: ${s.createdAtEpochSecs?new Date(s.createdAtEpochSecs*1000).toLocaleString():s.createdAt?new Date(s.createdAt).toLocaleString():"—"}
- ${!p?`
TTL: ${u}s remaining
`:""} + ${!u?`
TTL: ${g}s remaining
`:""}
@@ -1928,29 +1928,29 @@ Reference: ${s.uri}`),e)e.value="";if(t)t.value="";await this.refreshData()}else
Execution Progress - ${i}% ${s.total?`(step ${Math.round((s.progress||0)*s.total)} of ${s.total})`:""} + ${l}% ${s.total?`(step ${Math.round((s.progress||0)*s.total)} of ${s.total})`:""}
-
+
${s.context?`
- ${s.context.actor_id?`
Actor: ${f(s.context.actor_id)}
`:""} - ${s.context.operation_id?`
Operation: ${f(s.context.operation_id)}
`:""} - ${s.context.grant_id?`
Grant: ${f(s.context.grant_id)}
`:""} + ${s.context.actor_id?`
Actor: ${i(s.context.actor_id)}
`:""} + ${s.context.operation_id?`
Operation: ${i(s.context.operation_id)}
`:""} + ${s.context.grant_id?`
Grant: ${i(s.context.grant_id)}
`:""}
`:""} - ${d?` + ${c?`
⚠️ Failure / Cancellation Trace
-
${f(typeof s.error==="string"?s.error:JSON.stringify(s.error,null,2))}
+
${i(typeof s.error==="string"?s.error:JSON.stringify(s.error,null,2))}
`:""} @@ -1960,7 +1960,7 @@ Reference: ${s.uri}`),e)e.value="";if(t)t.value="";await this.refreshData()}else
⚡ Pending Input Requests (MRTR / HITL)
-
${f(JSON.stringify(s.inputRequests,null,2))}
+
${i(JSON.stringify(s.inputRequests,null,2))}
`:""} @@ -1969,103 +1969,103 @@ Reference: ${s.uri}`),e)e.value="";if(t)t.value="";await this.refreshData()}else
${y?"\uD83D\uDCE6 Output Result Payload":"State Details"}
-
${f(y?JSON.stringify(s.result,null,2):s.status==="working"?"Task execution is currently in-flight in background worker pool.":"No output payload recorded.")}
+
${i(y?JSON.stringify(s.result,null,2):s.status==="working"?"Task execution is currently in-flight in background worker pool.":"No output payload recorded.")}
- `;if(n)n.innerHTML=` + `;if(o)o.innerHTML=`
- ${!p?` - `:` - Task is terminal (${f(s.status)}) + Task is terminal (${i(s.status)}) `}
-
- `}catch(r){if(o)o.innerHTML=` + `}catch(r){if(n)n.innerHTML=`
- Failed to inspect task: ${f(r.message)} + Failed to inspect task: ${i(r.message)}
- `}}async submitApproval(e){let t=document.getElementById(`appr-operator-${e}`),a=document.getElementById(`appr-args-${e}`),o=t?.value.trim()||"security-operator",n=void 0;if(a&&a.value.trim())try{n=JSON.parse(a.value.trim())}catch{alert("Invalid JSON in arguments editor");return}let r=await h.approveTicket(e,o,n);if(r.ok)await this.refreshApprovals(),await this.refreshTasks();else alert(`Approval failed: ${r.error||"Unknown error"}`)}async promptReject(e){let t=prompt("Reason for rejection (will be returned to the calling agent):");if(t===null)return;let o=document.getElementById(`appr-operator-${e}`)?.value.trim()||"security-operator",n=await h.rejectTicket(e,o,t);if(n.ok)await this.refreshApprovals(),await this.refreshTasks();else alert(`Rejection failed: ${n.error||"Unknown error"}`)}setPlaygroundMode(e){c.setState({playgroundMode:e})}selectCapability(e){c.setState({selectedCapabilityId:e});let t=c.getState().capabilities.find((o)=>o.id===e),a=document.getElementById("pg-args-input");if(t){let o=ee(t.input_schema,!1),n=JSON.stringify(o,null,2);if(a)a.value=n;let r={...c.getState().playgroundArgs||{}};r[e]=n,c.getState().playgroundArgs=r}}selectResource(e){c.setState({selectedResourceId:e})}selectPrompt(e){c.setState({selectedPromptId:e})}filterResources(e){let t=e.toLowerCase().trim(),o=(c.getState().resources||[]).filter((r)=>r.id.toLowerCase().includes(t)||r.name&&r.name.toLowerCase().includes(t)||r.uri&&r.uri.toLowerCase().includes(t)||r.server&&r.server.toLowerCase().includes(t)),n=document.getElementById("pg-res-list");if(n)if(o.length===0)n.innerHTML=` + `}}async submitApproval(e){let t=document.getElementById(`appr-operator-${e}`),a=document.getElementById(`appr-args-${e}`),n=t?.value.trim()||"security-operator",o=void 0;if(a&&a.value.trim())try{o=JSON.parse(a.value.trim())}catch{alert("Invalid JSON in arguments editor");return}let r=await h.approveTicket(e,n,o);if(r.ok)await this.refreshApprovals(),await this.refreshTasks();else alert(`Approval failed: ${r.error||"Unknown error"}`)}async promptReject(e){let t=prompt("Reason for rejection (will be returned to the calling agent):");if(t===null)return;let n=document.getElementById(`appr-operator-${e}`)?.value.trim()||"security-operator",o=await h.rejectTicket(e,n,t);if(o.ok)await this.refreshApprovals(),await this.refreshTasks();else alert(`Rejection failed: ${o.error||"Unknown error"}`)}setPlaygroundMode(e){p.setState({playgroundMode:e})}selectCapability(e){p.setState({selectedCapabilityId:e});let t=p.getState().capabilities.find((n)=>n.id===e),a=document.getElementById("pg-args-input");if(t){let n=K(t.input_schema,!1),o=JSON.stringify(n,null,2);if(a)a.value=o;let r={...p.getState().playgroundArgs||{}};r[e]=o,p.getState().playgroundArgs=r}}selectResource(e){p.setState({selectedResourceId:e})}selectPrompt(e){p.setState({selectedPromptId:e})}filterResources(e){let t=e.toLowerCase().trim(),n=(p.getState().resources||[]).filter((r)=>r.id.toLowerCase().includes(t)||r.name&&r.name.toLowerCase().includes(t)||r.uri&&r.uri.toLowerCase().includes(t)||r.server&&r.server.toLowerCase().includes(t)),o=document.getElementById("pg-res-list");if(o)if(n.length===0)o.innerHTML=`
- No resources match "${f(e)}" + No resources match "${i(e)}"
- `;else n.innerHTML=o.map((r)=>{let s=r.id===c.getState().selectedResourceId?"active":"",i=r.uri?r.uri.split(":")[0]:"res";return` -
+ `;else o.innerHTML=n.map((r)=>{let s=r.id===p.getState().selectedResourceId?"active":"",l=r.uri?r.uri.split(":")[0]:"res";return` +
- ${f(r.name||r.id)} - ${f(i)} + ${i(r.name||r.id)} + ${i(l)}
-
${f(r.uri)}
+
${i(r.uri)}
- server: ${f(r.server||"local")} - ${f(r.mime_type||"text/plain")} + server: ${i(r.server||"local")} + ${i(r.mime_type||"text/plain")}
- `}).join("")}filterPrompts(e){let t=e.toLowerCase().trim(),o=(c.getState().prompts||[]).filter((r)=>r.id.toLowerCase().includes(t)||r.name&&r.name.toLowerCase().includes(t)||r.description&&r.description.toLowerCase().includes(t)||r.server&&r.server.toLowerCase().includes(t)),n=document.getElementById("pg-prompt-list");if(n)if(o.length===0)n.innerHTML=` + `}).join("")}filterPrompts(e){let t=e.toLowerCase().trim(),n=(p.getState().prompts||[]).filter((r)=>r.id.toLowerCase().includes(t)||r.name&&r.name.toLowerCase().includes(t)||r.description&&r.description.toLowerCase().includes(t)||r.server&&r.server.toLowerCase().includes(t)),o=document.getElementById("pg-prompt-list");if(o)if(n.length===0)o.innerHTML=`
- No prompts match "${f(e)}" + No prompts match "${i(e)}"
- `;else n.innerHTML=o.map((r)=>{let s=r.id===c.getState().selectedPromptId?"active":"",i=r.arguments?r.arguments.length:0;return` -
+ `;else o.innerHTML=n.map((r)=>{let s=r.id===p.getState().selectedPromptId?"active":"",l=r.arguments?r.arguments.length:0;return` +
- ${f(r.name||r.id)} - ${i} args + ${i(r.name||r.id)} + ${l} args
-
${f(r.description||r.title||"Prompt template")}
-
server: ${f(r.server||"local")}
+
${i(r.description||r.title||"Prompt template")}
+
server: ${i(r.server||"local")}
- `}).join("")}updatePlaygroundArgs(e){let t=c.getState(),a=t.selectedCapabilityId||(t.capabilities[0]?t.capabilities[0].id:null);if(!a)return;let o={...t.playgroundArgs||{}};o[a]=e,t.playgroundArgs=o}fillPlaygroundSampleArgs(e=!1){let t=c.getState(),a=t.selectedCapabilityId||(t.capabilities[0]?t.capabilities[0].id:null),o=t.capabilities.find((i)=>i.id===a),n=document.getElementById("pg-args-input");if(!n)return;if(!o||!o.input_schema){if(n.value="{}",a){let i={...t.playgroundArgs||{}};i[a]="{}",t.playgroundArgs=i}return}let r=ee(o.input_schema,e),s=JSON.stringify(r,null,2);if(n.value=s,a){let i={...t.playgroundArgs||{}};i[a]=s,t.playgroundArgs=i}}formatPlaygroundArgs(){let e=c.getState(),t=e.selectedCapabilityId||(e.capabilities[0]?e.capabilities[0].id:null),a=document.getElementById("pg-args-input");if(a)try{let o=JSON.parse(a.value||"{}"),n=JSON.stringify(o,null,2);if(a.value=n,t){let r={...e.playgroundArgs||{}};r[t]=n,e.playgroundArgs=r}}catch(o){alert(`Cannot format JSON: ${o.message}`)}}insertPlaygroundArgKey(e,t,a){let o=c.getState(),n=o.selectedCapabilityId||(o.capabilities[0]?o.capabilities[0].id:null),r=document.getElementById("pg-args-input");if(r){let s={};try{s=JSON.parse(r.value||"{}")}catch{s={}}if(s[e]===void 0)if(a!==null&&a!==void 0)s[e]=a;else switch(t){case"string":s[e]=`sample_${e}`;break;case"number":case"integer":s[e]=0;break;case"boolean":s[e]=!0;break;case"array":s[e]=[];break;case"object":s[e]={};break;default:s[e]=`sample_${e}`}let i=JSON.stringify(s,null,2);if(r.value=i,n){let l={...o.playgroundArgs||{}};l[n]=i,o.playgroundArgs=l}}}fillBatchStepSampleArgs(e){let t=c.getState(),a=[...t.batchSteps||[]],o=a[e];if(!o||!o.capability_id)return;let n=t.capabilities.find((l)=>l.id===o.capability_id);if(!n||!n.input_schema)return;let r=n.input_schema.properties||{},s={};for(let[l,u]of Object.entries(r))if(u.default!==void 0)s[l]=u.default;else if(Array.isArray(u.enum)&&u.enum.length>0)s[l]=u.enum[0];else switch(u.type||"string"){case"string":s[l]=`sample_${l}`;break;case"number":case"integer":s[l]=0;break;case"boolean":s[l]=!0;break;case"array":s[l]=[];break;case"object":s[l]={};break;default:s[l]=`sample_${l}`}let i=JSON.stringify(s,null,2);a[e]={...a[e],argsJson:i},c.setState({batchSteps:a})}filterCapabilities(e){let t=e.toLowerCase().trim(),o=c.getState().capabilities.filter((r)=>r.id.toLowerCase().includes(t)||r.summary&&r.summary.toLowerCase().includes(t)||r.server&&r.server.toLowerCase().includes(t)),n=document.getElementById("pg-cap-list");if(n)if(o.length===0)n.innerHTML=` + `}).join("")}updatePlaygroundArgs(e){let t=p.getState(),a=t.selectedCapabilityId||(t.capabilities[0]?t.capabilities[0].id:null);if(!a)return;let n={...t.playgroundArgs||{}};n[a]=e,t.playgroundArgs=n}fillPlaygroundSampleArgs(e=!1){let t=p.getState(),a=t.selectedCapabilityId||(t.capabilities[0]?t.capabilities[0].id:null),n=t.capabilities.find((l)=>l.id===a),o=document.getElementById("pg-args-input");if(!o)return;if(!n||!n.input_schema){if(o.value="{}",a){let l={...t.playgroundArgs||{}};l[a]="{}",t.playgroundArgs=l}return}let r=K(n.input_schema,e),s=JSON.stringify(r,null,2);if(o.value=s,a){let l={...t.playgroundArgs||{}};l[a]=s,t.playgroundArgs=l}}formatPlaygroundArgs(){let e=p.getState(),t=e.selectedCapabilityId||(e.capabilities[0]?e.capabilities[0].id:null),a=document.getElementById("pg-args-input");if(a)try{let n=JSON.parse(a.value||"{}"),o=JSON.stringify(n,null,2);if(a.value=o,t){let r={...e.playgroundArgs||{}};r[t]=o,e.playgroundArgs=r}}catch(n){alert(`Cannot format JSON: ${n.message}`)}}insertPlaygroundArgKey(e,t,a){let n=p.getState(),o=n.selectedCapabilityId||(n.capabilities[0]?n.capabilities[0].id:null),r=document.getElementById("pg-args-input");if(r){let s={};try{s=JSON.parse(r.value||"{}")}catch{s={}}if(s[e]===void 0)if(a!==null&&a!==void 0)s[e]=a;else switch(t){case"string":s[e]=`sample_${e}`;break;case"number":case"integer":s[e]=0;break;case"boolean":s[e]=!0;break;case"array":s[e]=[];break;case"object":s[e]={};break;default:s[e]=`sample_${e}`}let l=JSON.stringify(s,null,2);if(r.value=l,o){let d={...n.playgroundArgs||{}};d[o]=l,n.playgroundArgs=d}}}fillBatchStepSampleArgs(e){let t=p.getState(),a=[...t.batchSteps||[]],n=a[e];if(!n||!n.capability_id)return;let o=t.capabilities.find((d)=>d.id===n.capability_id);if(!o||!o.input_schema)return;let r=o.input_schema.properties||{},s={};for(let[d,g]of Object.entries(r))if(g.default!==void 0)s[d]=g.default;else if(Array.isArray(g.enum)&&g.enum.length>0)s[d]=g.enum[0];else switch(g.type||"string"){case"string":s[d]=`sample_${d}`;break;case"number":case"integer":s[d]=0;break;case"boolean":s[d]=!0;break;case"array":s[d]=[];break;case"object":s[d]={};break;default:s[d]=`sample_${d}`}let l=JSON.stringify(s,null,2);a[e]={...a[e],argsJson:l},p.setState({batchSteps:a})}filterCapabilities(e){let t=e.toLowerCase().trim(),n=p.getState().capabilities.filter((r)=>r.id.toLowerCase().includes(t)||r.summary&&r.summary.toLowerCase().includes(t)||r.server&&r.server.toLowerCase().includes(t)),o=document.getElementById("pg-cap-list");if(o)if(n.length===0)o.innerHTML=`
- No capabilities match "${f(e)}" + No capabilities match "${i(e)}"
- `;else n.innerHTML=o.map((r)=>` -
+ `;else o.innerHTML=n.map((r)=>` +
- ${f(r.id)} - ${f(r.mode||"read")} + ${i(r.id)} + ${i(r.mode||"read")}
-
server: ${f(r.server||"local")}
+
server: ${i(r.server||"local")}
- `).join("")}async executePlaygroundTool(){let e=c.getState(),t=e.selectedCapabilityId||(e.capabilities[0]?e.capabilities[0].id:null);if(!t)return;let a=document.getElementById("pg-args-input")?.value||"{}",o=document.getElementById("pg-context-input")?.value||void 0,n=document.getElementById("pg-jsonpath-input")?.value.trim()||void 0,r=document.getElementById("pg-limit-lines-input")?.value.trim()||void 0,s=document.getElementById("pg-truncate-bytes-input")?.value.trim()||void 0,i={};try{i=JSON.parse(a)}catch{alert("Invalid arguments JSON object");return}if(n)i._jsonpath=n;if(r&&!isNaN(Number(r)))i._limit_lines=Number(r);if(s&&!isNaN(Number(s)))i._truncate_bytes=Number(s);let l=`op-${Date.now()}`;c.setState({isExecuting:!0,activeRequestId:l});let u=e.activeProfile||void 0,p=e.playgroundAsyncTask||!1;try{let g=await h.callCapability({capability_id:t,args:i,request_id:l,async_task:p?!0:void 0,context:{operation_id:o||l}},u);if(c.setState({isExecuting:!1,activeRequestId:null,executionResult:{status:g.status,durationMs:g.durationMs,data:g.data}}),g.status===202||g.data?.resultType==="task")this.refreshTasks();c.addEventLog("POST",`/v1/tools/call → ${t}`,g.status===200?"200 OK":`HTTP ${g.status}`,`${g.durationMs.toFixed(1)}ms`),h.getConfig().then((m)=>{if(m.ok&&m.circuit_breakers)c.setState({circuitBreakers:m.circuit_breakers})})}catch(g){c.setState({isExecuting:!1,activeRequestId:null,executionResult:{status:500,durationMs:0,data:{error:g.toString()}}})}}async cancelActiveOperation(){let t=c.getState().activeRequestId;if(t)try{await h.cancelOperation(t)}catch(a){console.warn("Failed to send cancel signal:",a)}c.setState({isExecuting:!1,activeRequestId:null,executionResult:{status:499,durationMs:0,data:{ok:!1,error:{code:"CANCELLED",message:"Operation cancelled by operator"}}}})}openBatchModal(){let e=c.getState(),t=e.batchSteps;if(!t||t.length===0)t=[{id:"step_1",capability_id:e.selectedCapabilityId||(e.capabilities[0]?e.capabilities[0].id:""),argsJson:"{}",continue_on_error:!1},{id:"step_2",capability_id:"",argsJson:"{}",continue_on_error:!0}],c.setState({batchSteps:t});c.setState({isBatchModalOpen:!0})}closeBatchModal(){c.setState({isBatchModalOpen:!1})}addBatchStep(){let t=[...c.getState().batchSteps||[]],a=t.length+1;t.push({id:`step_${a}`,capability_id:"",argsJson:"{}",continue_on_error:!1}),c.setState({batchSteps:t})}removeBatchStep(e){let a=[...c.getState().batchSteps||[]];if(a.length<=1){alert("Pipeline must contain at least one execution step.");return}a.splice(e,1);let o=a.map((n,r)=>({...n,id:`step_${r+1}`}));c.setState({batchSteps:o})}updateBatchStepCapability(e,t){let o=[...c.getState().batchSteps||[]];if(o[e])o[e]={...o[e],capability_id:t},c.setState({batchSteps:o})}updateBatchStepContinueOnError(e,t){let o=[...c.getState().batchSteps||[]];if(o[e])o[e]={...o[e],continue_on_error:t},c.setState({batchSteps:o})}updateBatchStepArgs(e,t){let a=c.getState(),o=[...a.batchSteps||[]];if(o[e])o[e]={...o[e],argsJson:t},a.batchSteps[e].argsJson=t}appendBatchVariable(e,t){let o=[...c.getState().batchSteps||[]],n=document.getElementById(`batch-step-args-${e}`);if(n){let r=n.value,s=n.selectionStart||r.length,i=n.selectionEnd||r.length,l=r.substring(0,s)+t+r.substring(i);if(n.value=l,o[e])o[e]={...o[e],argsJson:l},c.setState({batchSteps:o})}}async executeBatchPipeline(){let e=c.getState(),t=e.batchSteps||[],a=[];for(let n=0;n{let s=r,i=s.getAttribute("data-arg-name");if(i&&s.value.trim())o[i]=s.value.trim()});let n=e.activeProfile||void 0;try{let r=await h.getPrompt({prompt_id:t,arguments:o},n);c.setState({promptGetResult:{status:r.status,durationMs:r.durationMs,data:r.data}}),c.addEventLog("POST",`/v1/prompts/get → ${t}`,r.status===200?"200 OK":`HTTP ${r.status}`,`${r.durationMs.toFixed(1)}ms`)}catch(r){c.setState({promptGetResult:{status:500,durationMs:0,data:{error:r.toString()}}})}}toggleBatchPlayground(){let e=document.getElementById("pg-args-input");if(!e)return;let t=[{id:"step_1",capability_id:"sqlite.read_query",args:{query:"SELECT * FROM users LIMIT 2"}},{id:"step_2",capability_id:"github.issues.search",args:{query:"label:bug"},continue_on_error:!0}];e.value=JSON.stringify(t,null,2)}async submitPolicyRule(e){let t=e==="allow"?"policy-new-allow":e==="deny"?"policy-new-deny":e==="redact"?"policy-new-redact":"policy-new-requireApproval",a=document.getElementById(t);if(!a)return;let o=a.value.trim();if(!o)return;await this.addPolicyRule(e,o),a.value=""}async addPolicyRule(e,t){let a=(t||"").trim();if(!a)return;let o=c.getState(),n=o.activeProfile,r=n?o.config.profiles?.[n]:void 0;if(r&&n){let s=r.policy||{},i=[...s.allow||[]],l=[...s.deny||[]],u=[...s.redact_keys||s.redactKeys||[]],p=[...s.require_approval||s.requireApproval||[]];if(e==="allow"&&!i.includes(a))i.push(a);if(e==="deny"&&!l.includes(a))l.push(a);if(e==="redact"&&!u.includes(a))u.push(a);if(e==="requireApproval"&&!p.includes(a))p.push(a);let g={...s,allow:i,deny:l,redactKeys:u,requireApproval:p},m=await h.upsertProfile(n,r.servers,r.description,g);if(!m.ok)alert(`Failed to save profile policy rule: ${m.error||"Unknown error"}`)}else{let s=o.config.policy||{},i=[...s.allow||[]],l=[...s.deny||[]],u=[...s.redact_keys||s.redactKeys||[]],p=[...s.require_approval||s.requireApproval||[]];if(e==="allow"&&!i.includes(a))i.push(a);if(e==="deny"&&!l.includes(a))l.push(a);if(e==="redact"&&!u.includes(a))u.push(a);if(e==="requireApproval"&&!p.includes(a))p.push(a);let g=await h.savePolicy({...s,allow:i,deny:l,redact_keys:u,redactKeys:u,require_approval:p,requireApproval:p});if(!g.ok)alert(`Failed to save policy rule: ${g.error||"Unknown error"}`)}await this.refreshData()}async removePolicyRule(e,t){let a=c.getState(),o=a.activeProfile,n=o?a.config.profiles?.[o]:void 0;if(n&&o){let r=n.policy||{},s=[...r.allow||[]],i=[...r.deny||[]],l=[...r.redact_keys||r.redactKeys||[]],u=[...r.require_approval||r.requireApproval||[]];if(e==="allow")s.splice(t,1);if(e==="deny")i.splice(t,1);if(e==="redact")l.splice(t,1);if(e==="requireApproval")u.splice(t,1);let p={...r,allow:s,deny:i,redactKeys:l,requireApproval:u},g=await h.upsertProfile(o,n.servers,n.description,p);if(!g.ok)alert(`Failed to update profile policy: ${g.error||"Unknown error"}`)}else{let r=a.config.policy||{},s=[...r.allow||[]],i=[...r.deny||[]],l=[...r.redact_keys||r.redactKeys||[]],u=[...r.require_approval||r.requireApproval||[]];if(e==="allow")s.splice(t,1);if(e==="deny")i.splice(t,1);if(e==="redact")l.splice(t,1);if(e==="requireApproval")u.splice(t,1);let p=await h.savePolicy({...r,allow:s,deny:i,redact_keys:l,redactKeys:l,require_approval:u,requireApproval:u});if(!p.ok)alert(`Failed to update policy: ${p.error||"Unknown error"}`)}await this.refreshData()}async saveWebhookConfig(){let e=document.getElementById("policy-webhook-url"),t=document.getElementById("policy-webhook-format"),a=document.getElementById("policy-webhook-secret"),o=e?e.value.trim():"",n=t?t.value:"generic",r=a?a.value.trim():"",i=c.getState().config.policy||{},l=o?{url:o,format:n,secret:r&&!r.startsWith("WARMPLANE_")&&!r.includes("_")?r:void 0,secret_env:r&&(r.startsWith("WARMPLANE_")||r.includes("_"))?r:void 0,events:["approval.requested","circuit_breaker.tripped","policy.violation"]}:void 0,u=await h.savePolicy({...i,webhook:l});if(u.ok)alert("Webhook settings saved successfully");else alert(`Failed to save webhook settings: ${u.error||"Unknown error"}`);await this.refreshData()}async testWebhook(){let e=document.getElementById("policy-webhook-url"),t=document.getElementById("policy-webhook-format"),a=e?e.value.trim():void 0,o=t?t.value:void 0,n=c.getState(),r=typeof n.config.policy?.webhook==="object"?n.config.policy.webhook?.url:void 0;if(a&&a!==r)await this.saveWebhookConfig();let s=document.getElementById("policy-webhook-status");if(s)s.textContent="Sending test event...",s.style.color="var(--cyan-400)";try{let i=await h.testWebhook(a,o);if(i.ok){if(alert(`Test webhook sent successfully! (${i.message})`),s)s.textContent=`✔ Test sent (HTTP ${i.status_code||200})`,s.style.color="var(--green-400)"}else if(alert(`Test webhook failed: ${i.error||"Unknown error"}`),s)s.textContent=`✖ Failed: ${i.error}`,s.style.color="var(--red-400)"}catch(i){alert(`Error sending test webhook: ${i.message}`)}}testPolicySandbox(e){let t=document.getElementById("policy-test-verdict");if(!t)return;let a=e.trim();if(!a){t.textContent="ENTER ID",t.style.color="var(--text-dim)";return}let o=c.getState(),n=o.activeProfile,r=n?o.config.profiles?.[n]:void 0,s=o.config.policy||{},i=r?.policy,l=s.deny||[],u=i?.deny||[],p=Array.from(new Set([...l,...u])),g=s.require_approval||s.requireApproval||[],m=i?.require_approval||i?.requireApproval||[],d=Array.from(new Set([...g,...m])),y=i&&i.allow&&i.allow.length>0?i.allow:s.allow||[],b=(v,x)=>{if(v==="*")return!0;if(v.endsWith("*"))return x.startsWith(v.slice(0,-1));return v===x};if(p.some((v)=>b(v,a))){t.textContent="DENIED (Strict Block)",t.style.color="var(--red-400)";return}if(y.length>0&&!y.some((v)=>b(v,a))){t.textContent="DENIED (Not in Allow List)",t.style.color="var(--red-400)";return}if(d.some((v)=>b(v,a))){t.textContent="REQUIRE APPROVAL (HITL Gate)",t.style.color="var(--amber-400)";return}t.textContent="ALLOWED",t.style.color="var(--green-400)"}async deleteServer(e){let t=c.getState().activeProfile,a=t?`Permanently delete server '${e}' globally from warmplane configuration? (This will also unbind it from profile '${t}')`:`Are you sure you want to permanently remove server '${e}' from configuration?`;if(!confirm(a))return;try{let o=await h.deleteServer(e);if(o.ok)await this.refreshData();else alert(`Failed to remove server '${e}': ${o.error||"Unknown error"}`)}catch(o){alert(`Error removing server '${e}': ${o.message}`)}}async restartServer(e){try{let t=await h.restartServer(e);if(t.ok)await this.refreshData();else alert(`Failed to restart server '${e}': ${t.error||"Unknown error"}`)}catch(t){alert(`Error restarting server '${e}': ${t.message}`)}}openServerDiagnosticsModal(e){this.closeModals();let t=c.getState(),a=t.config.mcpServers?.[e],o=t.serverStatuses?.[e],n=(t.circuitBreakers||[]).find((l)=>l.server_id===e),r=document.getElementById("modal-server-diagnostics");if(!r)return;let s=document.getElementById("modal-diag-title"),i=document.getElementById("modal-diag-body");if(s)s.textContent=`Live Diagnostics: ${e}`;if(i){let l=o?.status==="degraded",u=l?"var(--amber-400)":o?.status==="connected"?"var(--green-400)":"var(--red-400)",p=o?.error||"No active crash or error reported. Server is healthy.",g=Q(e,a?.command,a?.args),m=a?.env||{},d=Object.keys(m),b=(g?.envFields||[]).filter((x)=>x.required).filter((x)=>!d.includes(x.key)),v="";if(g||d.length>0){let x=(g?.envFields||[]).map((T)=>{let w=m[T.key]!==void 0,z='Configured';if(!w&&T.required)z='Required / Missing';else if(!w)z='Optional / Not Set';return` + `).join("")}async executePlaygroundTool(){let e=p.getState(),t=e.selectedCapabilityId||(e.capabilities[0]?e.capabilities[0].id:null);if(!t)return;let a=document.getElementById("pg-args-input")?.value||"{}",n=document.getElementById("pg-context-input")?.value||void 0,o=document.getElementById("pg-jsonpath-input")?.value.trim()||void 0,r=document.getElementById("pg-limit-lines-input")?.value.trim()||void 0,s=document.getElementById("pg-truncate-bytes-input")?.value.trim()||void 0,l={};try{l=JSON.parse(a)}catch{alert("Invalid arguments JSON object");return}if(o)l._jsonpath=o;if(r&&!isNaN(Number(r)))l._limit_lines=Number(r);if(s&&!isNaN(Number(s)))l._truncate_bytes=Number(s);let d=`op-${Date.now()}`;p.setState({isExecuting:!0,activeRequestId:d});let g=e.activeProfile||void 0,u=e.playgroundAsyncTask||!1;try{let m=await h.callCapability({capability_id:t,args:l,request_id:d,async_task:u?!0:void 0,context:{operation_id:n||d}},g);if(p.setState({isExecuting:!1,activeRequestId:null,executionResult:{status:m.status,durationMs:m.durationMs,data:m.data}}),m.status===202||m.data?.resultType==="task")this.refreshTasks();p.addEventLog("POST",`/v1/tools/call → ${t}`,m.status===200?"200 OK":`HTTP ${m.status}`,`${m.durationMs.toFixed(1)}ms`),h.getConfig().then((v)=>{if(v.ok&&v.circuit_breakers)p.setState({circuitBreakers:v.circuit_breakers})})}catch(m){p.setState({isExecuting:!1,activeRequestId:null,executionResult:{status:500,durationMs:0,data:{error:m.toString()}}})}}async cancelActiveOperation(){let t=p.getState().activeRequestId;if(t)try{await h.cancelOperation(t)}catch(a){console.warn("Failed to send cancel signal:",a)}p.setState({isExecuting:!1,activeRequestId:null,executionResult:{status:499,durationMs:0,data:{ok:!1,error:{code:"CANCELLED",message:"Operation cancelled by operator"}}}})}openBatchModal(){let e=p.getState(),t=e.batchSteps;if(!t||t.length===0)t=[{id:"step_1",capability_id:e.selectedCapabilityId||(e.capabilities[0]?e.capabilities[0].id:""),argsJson:"{}",continue_on_error:!1},{id:"step_2",capability_id:"",argsJson:"{}",continue_on_error:!0}],p.setState({batchSteps:t});p.setState({isBatchModalOpen:!0})}closeBatchModal(){p.setState({isBatchModalOpen:!1})}addBatchStep(){let t=[...p.getState().batchSteps||[]],a=t.length+1;t.push({id:`step_${a}`,capability_id:"",argsJson:"{}",continue_on_error:!1}),p.setState({batchSteps:t})}removeBatchStep(e){let a=[...p.getState().batchSteps||[]];if(a.length<=1){alert("Pipeline must contain at least one execution step.");return}a.splice(e,1);let n=a.map((o,r)=>({...o,id:`step_${r+1}`}));p.setState({batchSteps:n})}updateBatchStepCapability(e,t){let n=[...p.getState().batchSteps||[]];if(n[e])n[e]={...n[e],capability_id:t},p.setState({batchSteps:n})}updateBatchStepContinueOnError(e,t){let n=[...p.getState().batchSteps||[]];if(n[e])n[e]={...n[e],continue_on_error:t},p.setState({batchSteps:n})}updateBatchStepArgs(e,t){let a=p.getState(),n=[...a.batchSteps||[]];if(n[e])n[e]={...n[e],argsJson:t},a.batchSteps[e].argsJson=t}appendBatchVariable(e,t){let n=[...p.getState().batchSteps||[]],o=document.getElementById(`batch-step-args-${e}`);if(o){let r=o.value,s=o.selectionStart||r.length,l=o.selectionEnd||r.length,d=r.substring(0,s)+t+r.substring(l);if(o.value=d,n[e])n[e]={...n[e],argsJson:d},p.setState({batchSteps:n})}}async executeBatchPipeline(){let e=p.getState(),t=e.batchSteps||[],a=[];for(let o=0;o{let s=r,l=s.getAttribute("data-arg-name");if(l&&s.value.trim())n[l]=s.value.trim()});let o=e.activeProfile||void 0;try{let r=await h.getPrompt({prompt_id:t,arguments:n},o);p.setState({promptGetResult:{status:r.status,durationMs:r.durationMs,data:r.data}}),p.addEventLog("POST",`/v1/prompts/get → ${t}`,r.status===200?"200 OK":`HTTP ${r.status}`,`${r.durationMs.toFixed(1)}ms`)}catch(r){p.setState({promptGetResult:{status:500,durationMs:0,data:{error:r.toString()}}})}}toggleBatchPlayground(){let e=document.getElementById("pg-args-input");if(!e)return;let t=[{id:"step_1",capability_id:"sqlite.read_query",args:{query:"SELECT * FROM users LIMIT 2"}},{id:"step_2",capability_id:"github.issues.search",args:{query:"label:bug"},continue_on_error:!0}];e.value=JSON.stringify(t,null,2)}async submitPolicyRule(e){let t=e==="allow"?"policy-new-allow":e==="deny"?"policy-new-deny":e==="redact"?"policy-new-redact":"policy-new-requireApproval",a=document.getElementById(t);if(!a)return;let n=a.value.trim();if(!n)return;await this.addPolicyRule(e,n),a.value=""}async addPolicyRule(e,t){let a=(t||"").trim();if(!a)return;let n=p.getState(),o=n.activeProfile,r=o?n.config.profiles?.[o]:void 0;if(r&&o){let s=r.policy||{},l=[...s.allow||[]],d=[...s.deny||[]],g=[...s.redact_keys||s.redactKeys||[]],u=[...s.require_approval||s.requireApproval||[]];if(e==="allow"&&!l.includes(a))l.push(a);if(e==="deny"&&!d.includes(a))d.push(a);if(e==="redact"&&!g.includes(a))g.push(a);if(e==="requireApproval"&&!u.includes(a))u.push(a);let m={...s,allow:l,deny:d,redactKeys:g,requireApproval:u},v=await h.upsertProfile(o,r.servers,r.description,m);if(!v.ok)alert(`Failed to save profile policy rule: ${v.error||"Unknown error"}`)}else{let s=n.config.policy||{},l=[...s.allow||[]],d=[...s.deny||[]],g=[...s.redact_keys||s.redactKeys||[]],u=[...s.require_approval||s.requireApproval||[]];if(e==="allow"&&!l.includes(a))l.push(a);if(e==="deny"&&!d.includes(a))d.push(a);if(e==="redact"&&!g.includes(a))g.push(a);if(e==="requireApproval"&&!u.includes(a))u.push(a);let m=await h.savePolicy({...s,allow:l,deny:d,redact_keys:g,redactKeys:g,require_approval:u,requireApproval:u});if(!m.ok)alert(`Failed to save policy rule: ${m.error||"Unknown error"}`)}await this.refreshData()}async removePolicyRule(e,t){let a=p.getState(),n=a.activeProfile,o=n?a.config.profiles?.[n]:void 0;if(o&&n){let r=o.policy||{},s=[...r.allow||[]],l=[...r.deny||[]],d=[...r.redact_keys||r.redactKeys||[]],g=[...r.require_approval||r.requireApproval||[]];if(e==="allow")s.splice(t,1);if(e==="deny")l.splice(t,1);if(e==="redact")d.splice(t,1);if(e==="requireApproval")g.splice(t,1);let u={...r,allow:s,deny:l,redactKeys:d,requireApproval:g},m=await h.upsertProfile(n,o.servers,o.description,u);if(!m.ok)alert(`Failed to update profile policy: ${m.error||"Unknown error"}`)}else{let r=a.config.policy||{},s=[...r.allow||[]],l=[...r.deny||[]],d=[...r.redact_keys||r.redactKeys||[]],g=[...r.require_approval||r.requireApproval||[]];if(e==="allow")s.splice(t,1);if(e==="deny")l.splice(t,1);if(e==="redact")d.splice(t,1);if(e==="requireApproval")g.splice(t,1);let u=await h.savePolicy({...r,allow:s,deny:l,redact_keys:d,redactKeys:d,require_approval:g,requireApproval:g});if(!u.ok)alert(`Failed to update policy: ${u.error||"Unknown error"}`)}await this.refreshData()}async saveWebhookConfig(){let e=document.getElementById("policy-webhook-url"),t=document.getElementById("policy-webhook-format"),a=document.getElementById("policy-webhook-secret"),n=e?e.value.trim():"",o=t?t.value:"generic",r=a?a.value.trim():"",l=p.getState().config.policy||{},d=n?{url:n,format:o,secret:r&&!r.startsWith("WARMPLANE_")&&!r.includes("_")?r:void 0,secret_env:r&&(r.startsWith("WARMPLANE_")||r.includes("_"))?r:void 0,events:["approval.requested","circuit_breaker.tripped","policy.violation"]}:void 0,g=await h.savePolicy({...l,webhook:d});if(g.ok)alert("Webhook settings saved successfully");else alert(`Failed to save webhook settings: ${g.error||"Unknown error"}`);await this.refreshData()}async testWebhook(){let e=document.getElementById("policy-webhook-url"),t=document.getElementById("policy-webhook-format"),a=e?e.value.trim():void 0,n=t?t.value:void 0,o=p.getState(),r=typeof o.config.policy?.webhook==="object"?o.config.policy.webhook?.url:void 0;if(a&&a!==r)await this.saveWebhookConfig();let s=document.getElementById("policy-webhook-status");if(s)s.textContent="Sending test event...",s.style.color="var(--cyan-400)";try{let l=await h.testWebhook(a,n);if(l.ok){if(alert(`Test webhook sent successfully! (${l.message})`),s)s.textContent=`✔ Test sent (HTTP ${l.status_code||200})`,s.style.color="var(--green-400)"}else if(alert(`Test webhook failed: ${l.error||"Unknown error"}`),s)s.textContent=`✖ Failed: ${l.error}`,s.style.color="var(--red-400)"}catch(l){alert(`Error sending test webhook: ${l.message}`)}}testPolicySandbox(e){let t=document.getElementById("policy-test-verdict");if(!t)return;let a=e.trim();if(!a){t.textContent="ENTER ID",t.style.color="var(--text-dim)";return}let n=p.getState(),o=n.activeProfile,r=o?n.config.profiles?.[o]:void 0,s=n.config.policy||{},l=r?.policy,d=s.deny||[],g=l?.deny||[],u=Array.from(new Set([...d,...g])),m=s.require_approval||s.requireApproval||[],v=l?.require_approval||l?.requireApproval||[],c=Array.from(new Set([...m,...v])),y=l&&l.allow&&l.allow.length>0?l.allow:s.allow||[],b=(f,x)=>{if(f==="*")return!0;if(f.endsWith("*"))return x.startsWith(f.slice(0,-1));return f===x};if(u.some((f)=>b(f,a))){t.textContent="DENIED (Strict Block)",t.style.color="var(--red-400)";return}if(y.length>0&&!y.some((f)=>b(f,a))){t.textContent="DENIED (Not in Allow List)",t.style.color="var(--red-400)";return}if(c.some((f)=>b(f,a))){t.textContent="REQUIRE APPROVAL (HITL Gate)",t.style.color="var(--amber-400)";return}t.textContent="ALLOWED",t.style.color="var(--green-400)"}async deleteServer(e){let t=p.getState().activeProfile,a=t?`Permanently delete server '${e}' globally from warmplane configuration? (This will also unbind it from profile '${t}')`:`Are you sure you want to permanently remove server '${e}' from configuration?`;if(!confirm(a))return;try{let n=await h.deleteServer(e);if(n.ok)await this.refreshData();else alert(`Failed to remove server '${e}': ${n.error||"Unknown error"}`)}catch(n){alert(`Error removing server '${e}': ${n.message}`)}}async restartServer(e){try{let t=await h.restartServer(e);if(t.ok)await this.refreshData();else alert(`Failed to restart server '${e}': ${t.error||"Unknown error"}`)}catch(t){alert(`Error restarting server '${e}': ${t.message}`)}}openServerDiagnosticsModal(e){this.closeModals();let t=p.getState(),a=t.config.mcpServers?.[e],n=t.serverStatuses?.[e],o=(t.circuitBreakers||[]).find((d)=>d.server_id===e),r=document.getElementById("modal-server-diagnostics");if(!r)return;let s=document.getElementById("modal-diag-title"),l=document.getElementById("modal-diag-body");if(s)s.textContent=`Live Diagnostics: ${e}`;if(l){let d=n?.status==="degraded",g=d?"var(--amber-400)":n?.status==="connected"?"var(--green-400)":"var(--red-400)",u=n?.error||"No active crash or error reported. Server is healthy.",m=N(e,a?.command,a?.args),v=a?.env||{},c=Object.keys(v),b=(m?.envFields||[]).filter((x)=>x.required).filter((x)=>!c.includes(x.key)),f="";if(m||c.length>0){let x=(m?.envFields||[]).map((E)=>{let w=v[E.key]!==void 0,C='Configured';if(!w&&E.required)C='Required / Missing';else if(!w)C='Optional / Not Set';return`
- ${f(T.key)} - ${T.label?`(${f(T.label)})`:""} + ${i(E.key)} + ${E.label?`(${i(E.label)})`:""}
- ${z} + ${C} ${!w?` - + `:""}
- `}).join(""),A=(g?.envFields||[]).map((T)=>T.key),R=Object.entries(m).filter(([T])=>!A.includes(T)).map(([T,S])=>` + `}).join(""),T=(m?.envFields||[]).map((E)=>E.key),I=Object.entries(v).filter(([E])=>!T.includes(E)).map(([E,k])=>`
- ${f(T)} + ${i(E)} Custom Configured
- `).join("");v=` + `).join("");f=`
\uD83D\uDD11 Environment Variables & Secrets ${b.length>0?`⚠️ ${b.length} required key(s) missing`:""}
${x} - ${R} + ${I}
- `}i.innerHTML=` + `}l.innerHTML=`
- - Current Status: ${f(o?.status||"unknown")} - Protocol: ${f(o?.protocol_version||"2026-07-28")} + + Current Status: ${i(n?.status||"unknown")} + Protocol: ${i(n?.protocol_version||"2026-07-28")} ${b.length>0?'⚠️ Missing Required Keys':""}
@@ -2073,16 +2073,16 @@ Reference: ${s.uri}`),e)e.value="";if(t)t.value="";await this.refreshData()}else
⚠️ Diagnostic Details / Failure Root Cause
-
${f(p)}
+
${i(u)}
- ${v} + ${f}
Circuit Breaker State
- ${n?`${n.state.toUpperCase()} (${n.consecutive_failures} failures)`:"CLOSED (Healthy)"} + ${o?`${o.state.toUpperCase()} (${o.consecutive_failures} failures)`:"CLOSED (Healthy)"}
@@ -2096,71 +2096,71 @@ Reference: ${s.uri}`),e)e.value="";if(t)t.value="";await this.refreshData()}else
Configured Execution Target
- ${a?.command?`${f(a.command)} ${f((a.args||[]).join(" "))}`:f(a?.url||"")} + ${a?.command?`${i(a.command)} ${i((a.args||[]).join(" "))}`:i(a?.url||"")}
- +
- `}r.classList.add("active")}openAddServerModal(){this.closeModals();let e=document.getElementById("modal-srv-title"),t=document.getElementById("modal-srv-template-banner"),a=document.getElementById("modal-srv-name"),o=document.getElementById("modal-srv-transport"),n=document.getElementById("modal-srv-command"),r=document.getElementById("modal-srv-url"),s=document.getElementById("modal-srv-ft"),i=document.getElementById("modal-srv-cd"),l=document.getElementById("modal-srv-autorestart"),u=document.getElementById("modal-srv-maxrestarts");if(e)e.textContent="Add Upstream MCP Server";if(t)t.style.display="flex";if(a)a.value="",a.disabled=!1;if(o)o.value="stdio";if(n)n.value="";if(r)r.value="";let p=document.getElementById("modal-group-cmd"),g=document.getElementById("modal-group-url");if(p)p.style.display="block";if(g)g.style.display="none";if(s)s.value="3";if(i)i.value="30000";if(l)l.value="true";if(u)u.value="5";let m=document.getElementById("modal-add-server");if(m)m.classList.add("active")}openEditServerModal(e){this.closeModals();let t=c.getState(),a=t.config.mcpServers?.[e];if(!a){alert(`Server '${e}' not found in configuration.`);return}let o=document.getElementById("modal-srv-title"),n=document.getElementById("modal-srv-template-banner"),r=document.getElementById("modal-srv-name"),s=document.getElementById("modal-srv-transport"),i=document.getElementById("modal-srv-command"),l=document.getElementById("modal-srv-url"),u=document.getElementById("modal-srv-ft"),p=document.getElementById("modal-srv-cd"),g=document.getElementById("modal-srv-autorestart"),m=document.getElementById("modal-srv-maxrestarts");if(o)o.textContent=`Edit Server '${e}'`;if(n)n.style.display="none";if(r)r.value=e,r.disabled=!0;let d=!!a.command;if(s)s.value=d?"stdio":"http";let y=document.getElementById("modal-group-cmd"),b=document.getElementById("modal-group-url");if(y)y.style.display=d?"block":"none";if(b)b.style.display=d?"none":"block";if(i)i.value=d?`${a.command} ${(a.args||[]).join(" ")}`.trim():"";if(l)l.value=a.url||"";let v=a.resilience||t.config.resilience;if(u)u.value=String(v?.failureThreshold??3);if(p)p.value=String(v?.cooldownMs??30000);if(g)g.value=v?.autoRestart===!1?"false":"true";if(m)m.value=String(v?.maxRestarts??5);let x=document.getElementById("modal-add-server");if(x)x.classList.add("active")}async submitAddServer(){let e=document.getElementById("modal-srv-name"),t=e?.value.trim(),a=document.getElementById("modal-srv-transport")?.value;if(!t){alert("Server name is required");return}if(e&&!e.disabled){if((c.getState().config.mcpServers||{})[t]){if(!confirm(`Server '${t}' already exists in configuration. Do you want to overwrite it?`))return}}let o={};if(a==="stdio"){let p=(document.getElementById("modal-srv-command")?.value.trim()).split(/\s+/).filter(Boolean);if(p.length===0){alert("Command is required");return}o.command=p[0],o.args=p.slice(1)}else{let u=document.getElementById("modal-srv-url")?.value.trim();if(!u){alert("URL is required");return}o.url=u}let n=document.getElementById("modal-srv-ft")?.value.trim(),r=document.getElementById("modal-srv-cd")?.value.trim(),s=document.getElementById("modal-srv-autorestart")?.value,i=document.getElementById("modal-srv-maxrestarts")?.value.trim();if(n||r||s||i)o.resilience={failureThreshold:n?Number(n):3,cooldownMs:r?Number(r):30000,autoRestart:s!=="false",maxRestarts:i?Number(i):5};let l=await h.upsertServer(t,o);if(l.ok)this.closeModals(),await this.refreshData();else alert(`Failed to save server: ${l.error}`)}openTemplateCatalog(){this.closeModals();let e=document.getElementById("modal-templates");if(e)e.classList.add("active");this.renderTemplateGrid()}setTemplateCategory(e){this.activeTemplateCategory=e,document.querySelectorAll(".tmpl-cat-btn").forEach((t)=>{if(t.getAttribute("data-category")===e)t.classList.add("active"),t.style.background="var(--surface-elevated)",t.style.color="var(--amber-400)";else t.classList.remove("active"),t.style.background="var(--surface-card)",t.style.color="var(--text-main)"}),this.renderTemplateGrid()}filterTemplates(e){this.activeTemplateFilter=e.toLowerCase().trim(),this.renderTemplateGrid()}renderTemplateGrid(){let e=document.getElementById("tmpl-grid");if(!e)return;let t=X.filter((n)=>{let r=this.activeTemplateCategory==="all"||n.category===this.activeTemplateCategory,s=!this.activeTemplateFilter||n.name.toLowerCase().includes(this.activeTemplateFilter)||n.id.toLowerCase().includes(this.activeTemplateFilter)||n.description.toLowerCase().includes(this.activeTemplateFilter)||n.command.toLowerCase().includes(this.activeTemplateFilter)||n.envFields.some((i)=>i.key.toLowerCase().includes(this.activeTemplateFilter));return r&&s});if(t.length===0){e.innerHTML=` + `}r.classList.add("active")}openAddServerModal(){this.closeModals();let e=document.getElementById("modal-srv-title"),t=document.getElementById("modal-srv-template-banner"),a=document.getElementById("modal-srv-name"),n=document.getElementById("modal-srv-transport"),o=document.getElementById("modal-srv-command"),r=document.getElementById("modal-srv-url"),s=document.getElementById("modal-srv-ft"),l=document.getElementById("modal-srv-cd"),d=document.getElementById("modal-srv-autorestart"),g=document.getElementById("modal-srv-maxrestarts");if(e)e.textContent="Add Upstream MCP Server";if(t)t.style.display="flex";if(a)a.value="",a.disabled=!1;if(n)n.value="stdio";if(o)o.value="";if(r)r.value="";let u=document.getElementById("modal-group-cmd"),m=document.getElementById("modal-group-url");if(u)u.style.display="block";if(m)m.style.display="none";if(s)s.value="3";if(l)l.value="30000";if(d)d.value="true";if(g)g.value="5";let v=document.getElementById("modal-add-server");if(v)v.classList.add("active")}openEditServerModal(e){this.closeModals();let t=p.getState(),a=t.config.mcpServers?.[e];if(!a){alert(`Server '${e}' not found in configuration.`);return}let n=document.getElementById("modal-srv-title"),o=document.getElementById("modal-srv-template-banner"),r=document.getElementById("modal-srv-name"),s=document.getElementById("modal-srv-transport"),l=document.getElementById("modal-srv-command"),d=document.getElementById("modal-srv-url"),g=document.getElementById("modal-srv-ft"),u=document.getElementById("modal-srv-cd"),m=document.getElementById("modal-srv-autorestart"),v=document.getElementById("modal-srv-maxrestarts");if(n)n.textContent=`Edit Server '${e}'`;if(o)o.style.display="none";if(r)r.value=e,r.disabled=!0;let c=!!a.command;if(s)s.value=c?"stdio":"http";let y=document.getElementById("modal-group-cmd"),b=document.getElementById("modal-group-url");if(y)y.style.display=c?"block":"none";if(b)b.style.display=c?"none":"block";if(l)l.value=c?`${a.command} ${(a.args||[]).join(" ")}`.trim():"";if(d)d.value=a.url||"";let f=a.resilience||t.config.resilience;if(g)g.value=String(f?.failureThreshold??3);if(u)u.value=String(f?.cooldownMs??30000);if(m)m.value=f?.autoRestart===!1?"false":"true";if(v)v.value=String(f?.maxRestarts??5);let x=document.getElementById("modal-add-server");if(x)x.classList.add("active")}async submitAddServer(){let e=document.getElementById("modal-srv-name"),t=e?.value.trim(),a=document.getElementById("modal-srv-transport")?.value;if(!t){alert("Server name is required");return}if(e&&!e.disabled){if((p.getState().config.mcpServers||{})[t]){if(!confirm(`Server '${t}' already exists in configuration. Do you want to overwrite it?`))return}}let n={};if(a==="stdio"){let u=(document.getElementById("modal-srv-command")?.value.trim()).split(/\s+/).filter(Boolean);if(u.length===0){alert("Command is required");return}n.command=u[0],n.args=u.slice(1)}else{let g=document.getElementById("modal-srv-url")?.value.trim();if(!g){alert("URL is required");return}n.url=g}let o=document.getElementById("modal-srv-ft")?.value.trim(),r=document.getElementById("modal-srv-cd")?.value.trim(),s=document.getElementById("modal-srv-autorestart")?.value,l=document.getElementById("modal-srv-maxrestarts")?.value.trim();if(o||r||s||l)n.resilience={failureThreshold:o?Number(o):3,cooldownMs:r?Number(r):30000,autoRestart:s!=="false",maxRestarts:l?Number(l):5};let d=await h.upsertServer(t,n);if(d.ok)this.closeModals(),await this.refreshData();else alert(`Failed to save server: ${d.error}`)}openTemplateCatalog(){this.closeModals();let e=document.getElementById("modal-templates");if(e)e.classList.add("active");this.renderTemplateGrid()}setTemplateCategory(e){this.activeTemplateCategory=e,document.querySelectorAll(".tmpl-cat-btn").forEach((t)=>{if(t.getAttribute("data-category")===e)t.classList.add("active"),t.style.background="var(--surface-elevated)",t.style.color="var(--amber-400)";else t.classList.remove("active"),t.style.background="var(--surface-card)",t.style.color="var(--text-main)"}),this.renderTemplateGrid()}filterTemplates(e){this.activeTemplateFilter=e.toLowerCase().trim(),this.renderTemplateGrid()}renderTemplateGrid(){let e=document.getElementById("tmpl-grid");if(!e)return;let t=D.filter((o)=>{let r=this.activeTemplateCategory==="all"||o.category===this.activeTemplateCategory,s=!this.activeTemplateFilter||o.name.toLowerCase().includes(this.activeTemplateFilter)||o.id.toLowerCase().includes(this.activeTemplateFilter)||o.description.toLowerCase().includes(this.activeTemplateFilter)||o.command.toLowerCase().includes(this.activeTemplateFilter)||o.envFields.some((l)=>l.key.toLowerCase().includes(this.activeTemplateFilter));return r&&s});if(t.length===0){e.innerHTML=`
No matching MCP server templates found.
- `;return}let o=c.getState().config.mcpServers||{};e.innerHTML=t.map((n)=>{let r=!!o[n.id],s=`${n.command} ${n.defaultArgs.join(" ")}`;return` + `;return}let n=p.getState().config.mcpServers||{};e.innerHTML=t.map((o)=>{let r=!!n[o.id],s=`${o.command} ${o.defaultArgs.join(" ")}`;return`
- ${f(n.name)} - ${f(n.badge)} + ${i(o.name)} + ${i(o.badge)}
${r?'CONNECTED':""}
- ${f(n.description)} + ${i(o.description)}
- ${f(s)} + ${i(s)}
- ${n.envFields.length>0?` + ${o.envFields.length>0?`
⚡ Needs: - ${n.envFields.map((i)=>f(i.key)).join(", ")} + ${o.envFields.map((l)=>i(l.key)).join(", ")}
`:""}
-
- `}).join("")}selectTemplate(e){let t=X.find((l)=>l.id===e);if(!t)return;this.selectedTemplate=t,this.closeModals();let a=document.getElementById("modal-configure-template");if(a)a.classList.add("active");let o=document.getElementById("cfg-tmpl-title"),n=document.getElementById("cfg-tmpl-desc"),r=document.getElementById("cfg-tmpl-form");if(o)o.textContent=`Configure ${t.name} Server`;if(n)n.textContent=t.description;let s=c.getState().config.mcpServers||{},i=t.id;if(s[i]){let l=2;while(s[`${t.id}-${l}`])l++;i=`${t.id}-${l}`}if(r){let l="";if(t.envFields.length>0)l=` + `}).join("")}selectTemplate(e){let t=D.find((d)=>d.id===e);if(!t)return;this.selectedTemplate=t,this.closeModals();let a=document.getElementById("modal-configure-template");if(a)a.classList.add("active");let n=document.getElementById("cfg-tmpl-title"),o=document.getElementById("cfg-tmpl-desc"),r=document.getElementById("cfg-tmpl-form");if(n)n.textContent=`Configure ${t.name} Server`;if(o)o.textContent=t.description;let s=p.getState().config.mcpServers||{},l=t.id;if(s[l]){let d=2;while(s[`${t.id}-${d}`])d++;l=`${t.id}-${d}`}if(r){let d="";if(t.envFields.length>0)d=`
Environment Variables & API Keys
- ${t.envFields.map((u)=>` + ${t.envFields.map((g)=>`
- - - ${u.description?`
${f(u.description)}
`:""} + + + ${g.description?`
${i(g.description)}
`:""}
`).join("")} `;r.innerHTML=`
- +
Must be unique across all configured servers.
- -
Executable: ${f(t.command)}
+ +
Executable: ${i(t.command)}
- ${l} + ${d}
\uD83D\uDEE1️ Fault Tolerance & Process Supervision (Optional) @@ -2187,37 +2187,37 @@ Reference: ${s.uri}`),e)e.value="";if(t)t.value="";await this.refreshData()}else
- `}}async submitTemplateServer(){if(!this.selectedTemplate)return;let e=this.selectedTemplate,t=document.getElementById("cfg-srv-id")?.value.trim(),a=document.getElementById("cfg-srv-args")?.value.trim();if(!t){alert("Server identifier is required");return}if((c.getState().config.mcpServers||{})[t]){if(!confirm(`Server '${t}' already exists. Do you want to overwrite its configuration?`))return}let r=a?a.split(/\s+/).filter(Boolean):[],s={},i=document.querySelectorAll(".tmpl-env-input");for(let y of Array.from(i)){let b=y.getAttribute("data-key"),v=y.value.trim(),x=e.envFields.find((A)=>A.key===b);if(x?.required&&!v){alert(`Required field '${x.label}' is missing.`);return}if(b&&v)s[b]=v}let l={command:e.command,args:r};if(Object.keys(s).length>0)l.env=s;let u=document.getElementById("cfg-srv-ft")?.value.trim(),p=document.getElementById("cfg-srv-cd")?.value.trim(),g=document.getElementById("cfg-srv-autorestart")?.value,m=document.getElementById("cfg-srv-maxrestarts")?.value.trim();if(u||p||g||m)l.resilience={failureThreshold:u?Number(u):3,cooldownMs:p?Number(p):30000,autoRestart:g!=="false",maxRestarts:m?Number(m):5};let d=await h.upsertServer(t,l);if(d.ok)this.closeModals(),await this.refreshData();else alert(`Failed to save server: ${d.error}`)}async openImportModal(){this.closeModals();let e=document.getElementById("modal-import");if(e)e.classList.add("active");let t=document.getElementById("modal-eco-list");if(!t)return;t.innerHTML='
Scanning IDE configs...
';try{let a=await h.getEcosystemSources();if(a.sources&&a.sources.length>0)t.innerHTML=a.sources.map((o)=>` + `}}async submitTemplateServer(){if(!this.selectedTemplate)return;let e=this.selectedTemplate,t=document.getElementById("cfg-srv-id")?.value.trim(),a=document.getElementById("cfg-srv-args")?.value.trim();if(!t){alert("Server identifier is required");return}if((p.getState().config.mcpServers||{})[t]){if(!confirm(`Server '${t}' already exists. Do you want to overwrite its configuration?`))return}let r=a?a.split(/\s+/).filter(Boolean):[],s={},l=document.querySelectorAll(".tmpl-env-input");for(let y of Array.from(l)){let b=y.getAttribute("data-key"),f=y.value.trim(),x=e.envFields.find((T)=>T.key===b);if(x?.required&&!f){alert(`Required field '${x.label}' is missing.`);return}if(b&&f)s[b]=f}let d={command:e.command,args:r};if(Object.keys(s).length>0)d.env=s;let g=document.getElementById("cfg-srv-ft")?.value.trim(),u=document.getElementById("cfg-srv-cd")?.value.trim(),m=document.getElementById("cfg-srv-autorestart")?.value,v=document.getElementById("cfg-srv-maxrestarts")?.value.trim();if(g||u||m||v)d.resilience={failureThreshold:g?Number(g):3,cooldownMs:u?Number(u):30000,autoRestart:m!=="false",maxRestarts:v?Number(v):5};let c=await h.upsertServer(t,d);if(c.ok)this.closeModals(),await this.refreshData();else alert(`Failed to save server: ${c.error}`)}async openImportModal(){this.closeModals();let e=document.getElementById("modal-import");if(e)e.classList.add("active");let t=document.getElementById("modal-eco-list");if(!t)return;t.innerHTML='
Scanning IDE configs...
';try{let a=await h.getEcosystemSources();if(a.sources&&a.sources.length>0)t.innerHTML=a.sources.map((n)=>` - `).join("");else t.innerHTML='
No external MCP configuration files found on this system.
'}catch{t.innerHTML='
Failed to scan ecosystem sources.
'}}async submitImport(){let e=document.querySelectorAll(".eco-checkbox:checked");if(e.length===0){alert("No sources selected");return}for(let t of Array.from(e))await h.importConfig(t.value,!1);this.closeModals(),await this.refreshData()}async refreshClients(){try{let e=await h.getClients();if(e.ok&&Array.isArray(e.clients))c.setState({clients:e.clients})}catch(e){console.error("Failed to scan clients:",e)}}setClientCategoryFilter(e){c.setState({clientFilterCategory:e})}setClientSearchQuery(e){c.setState({clientSearchQuery:e})}async attachClient(e,t){let a=t;if(!a){let o=document.getElementById(`client-prof-${e}`)||document.getElementById(`overview-client-prof-${e}`);if(o)a=o.value||void 0;else a=c.getState().activeProfile||void 0}this.openClientAttachModal(e,a)}openClientAttachModal(e,t){this.closeModals(),this.pendingClientId=e;let a=c.getState().config,o=a.mcpHttpServer,n=o?`http://${o.bind==="0.0.0.0"||o.bind==="::"?"127.0.0.1":o.bind||"127.0.0.1"}:${o.port||9191}/mcp`:"",r=document.getElementById("modal-client-title"),s=document.getElementById("modal-client-transport"),i=document.getElementById("modal-client-url"),l=document.getElementById("modal-client-profile"),u=document.getElementById("modal-client-profile-wrap");if(r)r.textContent=`Connect ${e}`;if(s)s.value="stdio";if(i)i.value=n;if(l){let p=Object.keys(a.profiles||{});if(l.innerHTML=`${p.map((g)=>``).join("")}`,l.value=t||"",u)u.style.display=p.length>0?"block":"none"}this.updateClientTransportForm(),document.getElementById("modal-client-attach")?.classList.add("active")}updateClientTransportForm(){let t=(document.getElementById("modal-client-transport")?.value||"stdio")==="http",a=document.getElementById("modal-client-http-group"),o=document.getElementById("modal-client-http-status"),n=!!c.getState().config.mcpHttpServer;if(a)a.style.display=t?"block":"none";if(o)o.textContent=n?"Uses the daemon Streamable HTTP endpoint. The daemon must already be running.":"HTTP is unavailable until mcpHttpServer is configured and the daemon is restarted.",o.style.color=n?"var(--text-dim)":"var(--amber-300)"}async submitClientAttach(){let e=this.pendingClientId;if(!e)return;let t=document.getElementById("modal-client-transport")?.value||"stdio",a=document.getElementById("modal-client-profile")?.value||void 0,o=document.getElementById("modal-client-url")?.value.trim()||void 0;if(t==="http"&&!c.getState().config.mcpHttpServer&&!o){alert("Configure mcpHttpServer and restart the daemon, or provide an explicit HTTP endpoint.");return}if(t==="http"&&!o){alert("Enter an HTTP endpoint URL.");return}let n=await h.attachClient(e,a,t,o);if(!n.ok)alert(`Failed to attach client: ${n.error||n.message||"Unknown error"}`);else this.pendingClientId=null,this.closeModals(),await this.refreshData()}async detachClient(e){if(!confirm("Disconnect Warmplane from this client?"))return;let t=await h.detachClient(e);if(!t.ok)alert(`Failed to detach client: ${t.error||t.message||"Unknown error"}`);else await this.refreshData()}handleAliasTargetInput(e){let t=document.getElementById("alias-suggestions-dropdown");if(!t)return;let a=(e||"").trim().toLowerCase();if(a.length<2){t.style.display="none";return}let n=c.getState().capabilities.filter((r)=>r.id.toLowerCase().includes(a)||r.summary&&r.summary.toLowerCase().includes(a)||r.description&&r.description.toLowerCase().includes(a)||r.server&&r.server.toLowerCase().includes(a)).slice(0,8);if(n.length===0){t.style.display="none";return}t.innerHTML=n.map((r)=>` + `).join("");else t.innerHTML='
No external MCP configuration files found on this system.
'}catch{t.innerHTML='
Failed to scan ecosystem sources.
'}}async submitImport(){let e=document.querySelectorAll(".eco-checkbox:checked");if(e.length===0){alert("No sources selected");return}for(let t of Array.from(e))await h.importConfig(t.value,!1);this.closeModals(),await this.refreshData()}async refreshClients(){try{let e=await h.getClients();if(e.ok&&Array.isArray(e.clients))p.setState({clients:e.clients})}catch(e){console.error("Failed to scan clients:",e)}}setClientCategoryFilter(e){p.setState({clientFilterCategory:e})}setClientSearchQuery(e){p.setState({clientSearchQuery:e})}async attachClient(e,t){let a=t;if(!a){let n=document.getElementById(`client-prof-${e}`)||document.getElementById(`overview-client-prof-${e}`);if(n)a=n.value||void 0;else a=p.getState().activeProfile||void 0}this.openClientAttachModal(e,a)}openClientAttachModal(e,t){this.closeModals(),this.pendingClientId=e;let a=p.getState().config,n=a.mcpHttpServer,o=n?`http://${n.bind==="0.0.0.0"||n.bind==="::"?"127.0.0.1":n.bind||"127.0.0.1"}:${n.port||9191}/mcp`:"",r=document.getElementById("modal-client-title"),s=document.getElementById("modal-client-transport"),l=document.getElementById("modal-client-url"),d=document.getElementById("modal-client-profile"),g=document.getElementById("modal-client-profile-wrap");if(r)r.textContent=`Connect ${e}`;if(s)s.value="stdio";if(l)l.value=o;if(d){let u=Object.keys(a.profiles||{});if(d.innerHTML=`${u.map((m)=>``).join("")}`,d.value=t||"",g)g.style.display=u.length>0?"block":"none"}this.updateClientTransportForm(),document.getElementById("modal-client-attach")?.classList.add("active")}updateClientTransportForm(){let t=(document.getElementById("modal-client-transport")?.value||"stdio")==="http",a=document.getElementById("modal-client-http-group"),n=document.getElementById("modal-client-http-status"),o=!!p.getState().config.mcpHttpServer;if(a)a.style.display=t?"block":"none";if(n)n.textContent=o?"Uses the daemon Streamable HTTP endpoint. The daemon must already be running.":"HTTP is unavailable until mcpHttpServer is configured and the daemon is restarted.",n.style.color=o?"var(--text-dim)":"var(--amber-300)"}async submitClientAttach(){let e=this.pendingClientId;if(!e)return;let t=document.getElementById("modal-client-transport")?.value||"stdio",a=document.getElementById("modal-client-profile")?.value||void 0,n=document.getElementById("modal-client-url")?.value.trim()||void 0;if(t==="http"&&!p.getState().config.mcpHttpServer&&!n){alert("Configure mcpHttpServer and restart the daemon, or provide an explicit HTTP endpoint.");return}if(t==="http"&&!n){alert("Enter an HTTP endpoint URL.");return}let o=await h.attachClient(e,a,t,n);if(!o.ok)alert(`Failed to attach client: ${o.error||o.message||"Unknown error"}`);else this.pendingClientId=null,this.closeModals(),await this.refreshData()}async detachClient(e){if(!confirm("Disconnect Warmplane from this client?"))return;let t=await h.detachClient(e);if(!t.ok)alert(`Failed to detach client: ${t.error||t.message||"Unknown error"}`);else await this.refreshData()}handleAliasTargetInput(e){let t=document.getElementById("alias-suggestions-dropdown");if(!t)return;let a=(e||"").trim().toLowerCase();if(a.length<2){t.style.display="none";return}let o=p.getState().capabilities.filter((r)=>r.id.toLowerCase().includes(a)||r.summary&&r.summary.toLowerCase().includes(a)||r.description&&r.description.toLowerCase().includes(a)||r.server&&r.server.toLowerCase().includes(a)).slice(0,8);if(o.length===0){t.style.display="none";return}t.innerHTML=o.map((r)=>`
+ onmousedown="window.app.selectAliasSuggestion('${i(r.id)}')">
-
${f(r.id)}
-
${f(r.summary||r.description||"")}
+
${i(r.id)}
+
${i(r.summary||r.description||"")}
- ${f(r.server||"local")} + ${i(r.server||"local")}
- `).join(""),t.style.display="block"}selectAliasSuggestion(e){let t=document.getElementById("alias-target");if(t)t.value=e;this.hideAliasDropdown()}hideAliasDropdown(){let e=document.getElementById("alias-suggestions-dropdown");if(e)e.style.display="none"}startEditAlias(e,t,a,o="",n=!1){let r=document.getElementById("alias-kind"),s=document.getElementById("alias-name"),i=document.getElementById("alias-target"),l=document.getElementById("alias-summary"),u=document.getElementById("alias-passthrough"),p=document.getElementById("alias-passthrough-container"),g=document.getElementById("alias-form-title"),m=document.getElementById("alias-save-btn"),d=document.getElementById("alias-cancel-btn");if(r)r.value=e;if(s)s.value=t;if(i)i.value=a;if(l)l.value=o;if(u)u.checked=n;if(p)p.style.display=e==="tool"?"flex":"none";if(g)g.innerHTML=`✏️ EDIT ALIAS: ${t}`;if(m)m.textContent="✓ Update";if(d)d.style.display="inline-block";s?.focus(),s?.scrollIntoView({behavior:"smooth",block:"nearest"})}resetAliasForm(){let e=document.getElementById("alias-kind"),t=document.getElementById("alias-name"),a=document.getElementById("alias-target"),o=document.getElementById("alias-summary"),n=document.getElementById("alias-passthrough"),r=document.getElementById("alias-passthrough-container"),s=document.getElementById("alias-form-title"),i=document.getElementById("alias-save-btn"),l=document.getElementById("alias-cancel-btn");if(e)e.value="tool";if(t)t.value="";if(a)a.value="";if(o)o.value="";if(n)n.checked=!1;if(r)r.style.display="flex";if(s)s.textContent="Create New Alias";if(i)i.textContent="+ Save";if(l)l.style.display="none"}async createAlias(){let e=document.getElementById("alias-kind")?.value,t=document.getElementById("alias-name")?.value.trim(),a=document.getElementById("alias-target")?.value.trim(),o=document.getElementById("alias-summary")?.value.trim()||void 0,n=document.getElementById("alias-passthrough")?.checked||!1;if(!t||!a){alert("Please provide both alias name and canonical target");return}if(e==="tool"&&n&&!/^[a-zA-Z0-9_-]{1,64}$/.test(t)){let r=t.replace(/[^a-zA-Z0-9_-]/g,"_").substring(0,64);if(!confirm(`MCP tool names must match ^[a-zA-Z0-9_-]{1,64}$. + `).join(""),t.style.display="block"}selectAliasSuggestion(e){let t=document.getElementById("alias-target");if(t)t.value=e;this.hideAliasDropdown()}hideAliasDropdown(){let e=document.getElementById("alias-suggestions-dropdown");if(e)e.style.display="none"}startEditAlias(e,t,a,n="",o=!1){let r=document.getElementById("alias-kind"),s=document.getElementById("alias-name"),l=document.getElementById("alias-target"),d=document.getElementById("alias-summary"),g=document.getElementById("alias-passthrough"),u=document.getElementById("alias-passthrough-container"),m=document.getElementById("alias-form-title"),v=document.getElementById("alias-save-btn"),c=document.getElementById("alias-cancel-btn");if(r)r.value=e;if(s)s.value=t;if(l)l.value=a;if(d)d.value=n;if(g)g.checked=o;if(u)u.style.display=e==="tool"?"flex":"none";if(m)m.innerHTML=`✏️ EDIT ALIAS: ${t}`;if(v)v.textContent="✓ Update";if(c)c.style.display="inline-block";s?.focus(),s?.scrollIntoView({behavior:"smooth",block:"nearest"})}resetAliasForm(){let e=document.getElementById("alias-kind"),t=document.getElementById("alias-name"),a=document.getElementById("alias-target"),n=document.getElementById("alias-summary"),o=document.getElementById("alias-passthrough"),r=document.getElementById("alias-passthrough-container"),s=document.getElementById("alias-form-title"),l=document.getElementById("alias-save-btn"),d=document.getElementById("alias-cancel-btn");if(e)e.value="tool";if(t)t.value="";if(a)a.value="";if(n)n.value="";if(o)o.checked=!1;if(r)r.style.display="flex";if(s)s.textContent="Create New Alias";if(l)l.textContent="+ Save";if(d)d.style.display="none"}async createAlias(){let e=document.getElementById("alias-kind")?.value,t=document.getElementById("alias-name")?.value.trim(),a=document.getElementById("alias-target")?.value.trim(),n=document.getElementById("alias-summary")?.value.trim()||void 0,o=document.getElementById("alias-passthrough")?.checked||!1;if(!t||!a){alert("Please provide both alias name and canonical target");return}if(e==="tool"&&o&&!/^[a-zA-Z0-9_-]{1,64}$/.test(t)){let r=t.replace(/[^a-zA-Z0-9_-]/g,"_").substring(0,64);if(!confirm(`MCP tool names must match ^[a-zA-Z0-9_-]{1,64}$. '${t}' will be exported to MCP clients as '${r}'. -Do you want to proceed?`))return}await h.updateAlias(e,t,a,o,void 0,n),this.resetAliasForm(),await this.refreshData()}async deleteAlias(e,t){await h.updateAlias(e,t,void 0),this.resetAliasForm(),await this.refreshData()}async reloadFromDisk(){try{let e=await h.reloadConfig();if(e.ok){let t="Hot-reload completed successfully!";if(e.mounted&&e.mounted.length>0)t+=` +Do you want to proceed?`))return}await h.updateAlias(e,t,a,n,void 0,o),this.resetAliasForm(),await this.refreshData()}async deleteAlias(e,t){await h.updateAlias(e,t,void 0),this.resetAliasForm(),await this.refreshData()}async reloadFromDisk(){try{let e=await h.reloadConfig();if(e.ok){let t="Hot-reload completed successfully!";if(e.mounted&&e.mounted.length>0)t+=` Mounted: ${e.mounted.join(", ")}`;if(e.unmounted&&e.unmounted.length>0)t+=` Unmounted: ${e.unmounted.join(", ")}`;if(e.warnings&&e.warnings.length>0)t+=` Warnings: ${e.warnings.join(` -`)}`;alert(t)}else alert(`Hot-reload failed: ${e.error||"Unknown error"}`)}catch(e){alert(`Error reaching daemon: ${e.message}`)}await this.refreshData()}renderTopProfileSelector(){let e=document.getElementById("top-profile-selector");if(!e)return;let t=c.getState(),a=t.config.profiles||{},o=Object.keys(a),n=t.activeProfile,r='';for(let s of o){let i=n===s?"selected":"";r+=``}e.innerHTML=r}async setActiveProfile(e){c.setState({activeProfile:e||null}),await this.refreshData()}openAddProfileModal(){let e=document.getElementById("modal-prof-title");if(e)e.textContent="Create Server Constellation Profile";let t=document.getElementById("modal-prof-name"),a=document.getElementById("modal-prof-desc"),o=document.getElementById("modal-prof-mode");if(t)t.value="",t.disabled=!1;if(a)a.value="";if(o)o.value="create";let n=document.getElementById("modal-prof-allow"),r=document.getElementById("modal-prof-deny"),s=document.getElementById("modal-prof-hitl"),i=document.getElementById("modal-prof-redact");if(n)n.value="";if(r)r.value="";if(s)s.value="";if(i)i.value="";this.renderProfileServerCheckboxes([]);let l=document.getElementById("modal-add-profile");if(l)l.classList.add("active")}openEditProfileModal(e){let a=c.getState().config.profiles?.[e];if(!a)return;let o=document.getElementById("modal-prof-title");if(o)o.textContent=`Edit Profile: ${e}`;let n=document.getElementById("modal-prof-name"),r=document.getElementById("modal-prof-desc"),s=document.getElementById("modal-prof-mode");if(n)n.value=e,n.disabled=!0;if(r)r.value=a.description||"";if(s)s.value="edit";let i=document.getElementById("modal-prof-allow"),l=document.getElementById("modal-prof-deny"),u=document.getElementById("modal-prof-hitl"),p=document.getElementById("modal-prof-redact"),g=a.policy;if(i)i.value=(g?.allow||[]).join(", ");if(l)l.value=(g?.deny||[]).join(", ");if(u)u.value=(g?.require_approval||g?.requireApproval||[]).join(", ");if(p)p.value=(g?.redact_keys||g?.redactKeys||[]).join(", ");this.renderProfileServerCheckboxes(a.servers||[]);let m=document.getElementById("modal-add-profile");if(m)m.classList.add("active")}renderProfileServerCheckboxes(e){let t=document.getElementById("modal-prof-servers-list");if(!t)return;let a=c.getState(),o=Object.keys(a.config.mcpServers||{});if(o.length===0){t.innerHTML='
No MCP servers configured yet. Add servers first.
';return}t.innerHTML=o.map((n)=>{let r=e.includes(n)?"checked":"";return` +`)}`;alert(t)}else alert(`Hot-reload failed: ${e.error||"Unknown error"}`)}catch(e){alert(`Error reaching daemon: ${e.message}`)}await this.refreshData()}renderTopProfileSelector(){let e=document.getElementById("top-profile-selector");if(!e)return;let t=p.getState(),a=t.config.profiles||{},n=Object.keys(a),o=t.activeProfile,r='';for(let s of n){let l=o===s?"selected":"";r+=``}e.innerHTML=r}async setActiveProfile(e){p.setState({activeProfile:e||null}),await this.refreshData()}openAddProfileModal(){let e=document.getElementById("modal-prof-title");if(e)e.textContent="Create Server Constellation Profile";let t=document.getElementById("modal-prof-name"),a=document.getElementById("modal-prof-desc"),n=document.getElementById("modal-prof-mode");if(t)t.value="",t.disabled=!1;if(a)a.value="";if(n)n.value="create";let o=document.getElementById("modal-prof-allow"),r=document.getElementById("modal-prof-deny"),s=document.getElementById("modal-prof-hitl"),l=document.getElementById("modal-prof-redact");if(o)o.value="";if(r)r.value="";if(s)s.value="";if(l)l.value="";this.renderProfileServerCheckboxes([]);let d=document.getElementById("modal-add-profile");if(d)d.classList.add("active")}openEditProfileModal(e){let a=p.getState().config.profiles?.[e];if(!a)return;let n=document.getElementById("modal-prof-title");if(n)n.textContent=`Edit Profile: ${e}`;let o=document.getElementById("modal-prof-name"),r=document.getElementById("modal-prof-desc"),s=document.getElementById("modal-prof-mode");if(o)o.value=e,o.disabled=!0;if(r)r.value=a.description||"";if(s)s.value="edit";let l=document.getElementById("modal-prof-allow"),d=document.getElementById("modal-prof-deny"),g=document.getElementById("modal-prof-hitl"),u=document.getElementById("modal-prof-redact"),m=a.policy;if(l)l.value=(m?.allow||[]).join(", ");if(d)d.value=(m?.deny||[]).join(", ");if(g)g.value=(m?.require_approval||m?.requireApproval||[]).join(", ");if(u)u.value=(m?.redact_keys||m?.redactKeys||[]).join(", ");this.renderProfileServerCheckboxes(a.servers||[]);let v=document.getElementById("modal-add-profile");if(v)v.classList.add("active")}renderProfileServerCheckboxes(e){let t=document.getElementById("modal-prof-servers-list");if(!t)return;let a=p.getState(),n=Object.keys(a.config.mcpServers||{});if(n.length===0){t.innerHTML='
No MCP servers configured yet. Add servers first.
';return}t.innerHTML=n.map((o)=>{let r=e.includes(o)?"checked":"";return` - `}).join("")}async saveProfile(){let e=document.getElementById("modal-prof-name"),t=document.getElementById("modal-prof-desc"),a=e?.value.trim(),o=t?.value.trim();if(!a){alert("Please enter a profile name");return}let n=document.querySelectorAll(".prof-server-checkbox:checked"),r=[];if(n.forEach((v)=>{r.push(v.value)}),r.length===0){alert("Please select at least one server to include in this constellation");return}let s=(v)=>{if(!v)return[];return v.split(",").map((x)=>x.trim()).filter((x)=>x.length>0)},i=document.getElementById("modal-prof-allow"),l=document.getElementById("modal-prof-deny"),u=document.getElementById("modal-prof-hitl"),p=document.getElementById("modal-prof-redact"),g=s(i?.value),m=s(l?.value),d=s(u?.value),y=s(p?.value),b=void 0;if(g.length>0||m.length>0||d.length>0||y.length>0)b={allow:g,deny:m,requireApproval:d,redactKeys:y};try{let v=await h.upsertProfile(a,r,o||void 0,b);if(v.ok)this.closeModals(),await this.refreshData();else alert(`Failed to save profile: ${v.error||"Unknown error"}`)}catch(v){alert(`Error saving profile: ${v.message}`)}}async deleteProfile(e){if(!confirm(`Are you sure you want to delete profile '${e}'?`))return;try{let t=await h.deleteProfile(e);if(t.ok){if(c.getState().activeProfile===e)c.setState({activeProfile:null});await this.refreshData()}else alert(`Failed to delete profile: ${t.error||"Unknown error"}`)}catch(t){alert(`Error deleting profile: ${t.message}`)}}async toggleServerInProfile(e,t,a){let n=c.getState().config.profiles?.[e];if(!n)return;let r=[...n.servers||[]];if(a){if(!r.includes(t))r.push(t)}else if(r=r.filter((s)=>s!==t),r.length===0){alert("A profile must contain at least one server. To remove the profile, delete it in the Profiles tab.");return}try{let s=await h.upsertProfile(e,r,n.description,n.policy);if(s.ok)await this.refreshData();else alert(`Failed to update profile constellation: ${s.error||"Unknown error"}`)}catch(s){alert(`Error updating profile constellation: ${s.message}`)}}closeModals(){document.querySelectorAll(".modal-backdrop").forEach((e)=>e.classList.remove("active"))}}function f(e){return String(e||"").replace(/&/g,"&").replace(//g,">").replace(/"/g,""")}var fe=new ve;window.app=fe;window.addEventListener("DOMContentLoaded",()=>fe.init()); + `}).join("")}async saveProfile(){let e=document.getElementById("modal-prof-name"),t=document.getElementById("modal-prof-desc"),a=e?.value.trim(),n=t?.value.trim();if(!a){alert("Please enter a profile name");return}let o=document.querySelectorAll(".prof-server-checkbox:checked"),r=[];if(o.forEach((f)=>{r.push(f.value)}),r.length===0){alert("Please select at least one server to include in this constellation");return}let s=(f)=>{if(!f)return[];return f.split(",").map((x)=>x.trim()).filter((x)=>x.length>0)},l=document.getElementById("modal-prof-allow"),d=document.getElementById("modal-prof-deny"),g=document.getElementById("modal-prof-hitl"),u=document.getElementById("modal-prof-redact"),m=s(l?.value),v=s(d?.value),c=s(g?.value),y=s(u?.value),b=void 0;if(m.length>0||v.length>0||c.length>0||y.length>0)b={allow:m,deny:v,requireApproval:c,redactKeys:y};try{let f=await h.upsertProfile(a,r,n||void 0,b);if(f.ok)this.closeModals(),await this.refreshData();else alert(`Failed to save profile: ${f.error||"Unknown error"}`)}catch(f){alert(`Error saving profile: ${f.message}`)}}async deleteProfile(e){if(!confirm(`Are you sure you want to delete profile '${e}'?`))return;try{let t=await h.deleteProfile(e);if(t.ok){if(p.getState().activeProfile===e)p.setState({activeProfile:null});await this.refreshData()}else alert(`Failed to delete profile: ${t.error||"Unknown error"}`)}catch(t){alert(`Error deleting profile: ${t.message}`)}}async toggleServerInProfile(e,t,a){let o=p.getState().config.profiles?.[e];if(!o)return;let r=[...o.servers||[]];if(a){if(!r.includes(t))r.push(t)}else if(r=r.filter((s)=>s!==t),r.length===0){alert("A profile must contain at least one server. To remove the profile, delete it in the Profiles tab.");return}try{let s=await h.upsertProfile(e,r,o.description,o.policy);if(s.ok)await this.refreshData();else alert(`Failed to update profile constellation: ${s.error||"Unknown error"}`)}catch(s){alert(`Error updating profile constellation: ${s.message}`)}}closeModals(){document.querySelectorAll(".modal-backdrop").forEach((e)=>e.classList.remove("active"))}}var ie=new ne;window.app=ie;window.addEventListener("DOMContentLoaded",()=>ie.init()); diff --git a/ui/dist/index.html b/ui/dist/index.html index c894494..969a4e7 100644 --- a/ui/dist/index.html +++ b/ui/dist/index.html @@ -822,7 +822,7 @@
diff --git a/ui/src/components/aliases.ts b/ui/src/components/aliases.ts index 75f2849..3f66275 100644 --- a/ui/src/components/aliases.ts +++ b/ui/src/components/aliases.ts @@ -1,3 +1,4 @@ +import { escapeHtml } from '../escape'; import { store } from '../state'; import { api } from '../api'; @@ -128,7 +129,3 @@ export function renderAliases(): string {
`; } - -function escapeHtml(str: string): string { - return String(str || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); -} diff --git a/ui/src/components/approvals.ts b/ui/src/components/approvals.ts index 93e6011..eb56deb 100644 --- a/ui/src/components/approvals.ts +++ b/ui/src/components/approvals.ts @@ -1,3 +1,4 @@ +import { escapeHtml } from '../escape'; import { AppState } from '../state'; export function renderApprovals(state: AppState): string { @@ -213,8 +214,4 @@ export function renderApprovals(state: AppState): string { `; } -function escapeHtml(str: string): string { - return String(str || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); -} - diff --git a/ui/src/components/audit.ts b/ui/src/components/audit.ts index a0fd7c2..b2c32de 100644 --- a/ui/src/components/audit.ts +++ b/ui/src/components/audit.ts @@ -1,3 +1,4 @@ +import { escapeHtml } from '../escape'; import { store } from '../state'; import { api, AuditEventItem } from '../api'; @@ -408,13 +409,3 @@ export function renderAudit(): string { `; } -function escapeHtml(str: string): string { - if (!str) return ''; - return String(str) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); -} - diff --git a/ui/src/components/overview.ts b/ui/src/components/overview.ts index 9a68590..e7b6b7e 100644 --- a/ui/src/components/overview.ts +++ b/ui/src/components/overview.ts @@ -1,3 +1,4 @@ +import { escapeHtml } from '../escape'; import { store } from '../state'; export function renderOverview(): string { @@ -278,7 +279,3 @@ export function renderOverview(): string {
`; } - -function escapeHtml(str: string): string { - return String(str || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); -} diff --git a/ui/src/components/playground.ts b/ui/src/components/playground.ts index f0b35cc..44b2e82 100644 --- a/ui/src/components/playground.ts +++ b/ui/src/components/playground.ts @@ -1,3 +1,4 @@ +import { escapeHtml } from '../escape'; import { store } from '../state'; import { api } from '../api'; @@ -747,12 +748,4 @@ function renderBatchModal(state: any): string { `; } -function escapeHtml(str: string): string { - return String(str || '') - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); -} - diff --git a/ui/src/components/policy.ts b/ui/src/components/policy.ts index e2d7b31..a34bb4c 100644 --- a/ui/src/components/policy.ts +++ b/ui/src/components/policy.ts @@ -1,3 +1,4 @@ +import { escapeHtml } from '../escape'; import { store } from '../state'; import { api } from '../api'; @@ -253,7 +254,3 @@ export function renderPolicy(): string { `; } - -function escapeHtml(str: string): string { - return String(str || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); -} diff --git a/ui/src/components/profiles.ts b/ui/src/components/profiles.ts index 8e6a119..48a2e6f 100644 --- a/ui/src/components/profiles.ts +++ b/ui/src/components/profiles.ts @@ -1,3 +1,4 @@ +import { escapeHtml } from '../escape'; import { store } from '../state'; import { api } from '../api'; @@ -118,7 +119,3 @@ export function renderProfiles(): string { ${profilesListHtml} `; } - -function escapeHtml(str: string): string { - return String(str || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); -} diff --git a/ui/src/components/secrets.ts b/ui/src/components/secrets.ts index dfdac34..c7e5740 100644 --- a/ui/src/components/secrets.ts +++ b/ui/src/components/secrets.ts @@ -1,3 +1,4 @@ +import { escapeHtml } from '../escape'; import { store } from '../state'; import { api } from '../api'; import { findTemplateForServer } from '../templates'; @@ -136,7 +137,3 @@ export function renderSecrets(): string { `; } - -function escapeHtml(str: string): string { - return String(str || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); -} diff --git a/ui/src/components/servers.ts b/ui/src/components/servers.ts index 68c0008..8d4467e 100644 --- a/ui/src/components/servers.ts +++ b/ui/src/components/servers.ts @@ -1,3 +1,4 @@ +import { escapeHtml } from '../escape'; import { store } from '../state'; import { api } from '../api'; import { findTemplateForServer } from '../templates'; @@ -332,7 +333,3 @@ function renderClientIntegrations(): string { `; } - -function escapeHtml(str: string): string { - return String(str || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); -} diff --git a/ui/src/components/tasks.ts b/ui/src/components/tasks.ts index fb959d0..d77eb99 100644 --- a/ui/src/components/tasks.ts +++ b/ui/src/components/tasks.ts @@ -1,3 +1,4 @@ +import { escapeHtml } from '../escape'; import { AppState } from '../state'; import { TaskItem } from '../api'; @@ -337,7 +338,3 @@ export function renderTasks(state: AppState): string { `; } - -function escapeHtml(str: string): string { - return String(str || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); -} diff --git a/ui/src/escape.ts b/ui/src/escape.ts new file mode 100644 index 0000000..f96c93e --- /dev/null +++ b/ui/src/escape.ts @@ -0,0 +1,21 @@ +// Escapes a value for safe interpolation into HTML text or an attribute. + +/** + * Escapes a value for safe interpolation into HTML text or an attribute. + * + * Also escapes the single quote, so the value is safe inside the single-quoted + * JavaScript string literals used by inline `on*` handlers. + * + * @param value Any value. Non-strings are coerced; nullish values become an + * empty string. + * @returns The escaped string. + */ +export function escapeHtml(value: unknown): string { + if (value === null || value === undefined) return ''; + return String(value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); +} \ No newline at end of file diff --git a/ui/src/main.ts b/ui/src/main.ts index bad613c..076a5b2 100644 --- a/ui/src/main.ts +++ b/ui/src/main.ts @@ -1,3 +1,4 @@ +import { escapeHtml } from './escape'; import { store } from './state'; import { api } from './api'; import { renderOverview } from './components/overview'; @@ -2777,10 +2778,6 @@ class WarmplaneApp { } } -function escapeHtml(str: string): string { - return String(str || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); -} - const app = new WarmplaneApp(); (window as any).app = app; window.addEventListener('DOMContentLoaded', () => app.init());