@coreplane/switchboard 1.237.0 → 1.239.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/deploy/cloudflare-resident/worker.ts +40 -12
- package/dist/assets/deploy/cloudflare-sandbox/Dockerfile +8 -1
- package/dist/assets/deploy/cloudflare-sandbox/worker.ts +337 -44
- package/dist/assets/deploy/cloudflare-sandbox/wrangler.template.jsonc +19 -0
- package/dist/assets/deploy/secrets.manifest.json +3 -3
- package/dist/assets/package-lock.json +3 -3
- package/dist/assets/package.json +1 -1
- package/dist/assets/source.json +3 -3
- package/dist/assets/src/agents/registry.ts +82 -0
- package/dist/assets/src/execution/seedPlan.ts +267 -0
- package/dist/assets/src/execution/snapshotRetention.ts +62 -0
- package/dist/assets/src/mcp/registry.ts +9 -1
- package/dist/assets/web/dist/.vite/manifest.json +27 -27
- package/dist/assets/web/dist/assets/{ResidentDetailPage-Dc23v_8v.js → ResidentDetailPage-CrfCd8fx.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentsIndexPage-TR5D1TRR.js → ResidentsIndexPage-BdW0k2h3.js} +1 -1
- package/dist/assets/web/dist/assets/{RunFoldRow-mkUj7WEN.js → RunFoldRow-CbTd9SiS.js} +1 -1
- package/dist/assets/web/dist/assets/{RunRoutePage-CQI17__g.js → RunRoutePage-br0H-8Pz.js} +3 -3
- package/dist/assets/web/dist/assets/{RunsIndexPage-yIP4PlKP.js → RunsIndexPage-Bnzb15zH.js} +1 -1
- package/dist/assets/web/dist/assets/{ScheduledPage-CdCVyNbh.js → ScheduledPage-NLhjzHAz.js} +1 -1
- package/dist/assets/web/dist/assets/SettingsPage-D-i0uVw-.js +1 -0
- package/dist/assets/web/dist/assets/{StatusDot-DmNHX6am.js → StatusDot-DkXALvKf.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-qVnJTgSt.js → Tooltip-DtLIyi5P.js} +1 -1
- package/dist/assets/web/dist/assets/{UnitRoutePage-BcTeH7m2.js → UnitRoutePage-DGXukEAH.js} +1 -1
- package/dist/assets/web/dist/assets/{dist-TAGawIfM.js → dist-DtA7JiH5.js} +1 -1
- package/dist/assets/web/dist/assets/main-CFHF2RvQ.css +1 -0
- package/dist/assets/web/dist/assets/{main-mUd_TJjH.js → main-Dht0in4v.js} +2 -2
- package/dist/cli.js +452 -51
- package/package.json +1 -1
- package/dist/assets/web/dist/assets/SettingsPage-DuA8JpLU.js +0 -1
- package/dist/assets/web/dist/assets/main-csihqEj5.css +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coreplane/switchboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.239.0",
|
|
4
4
|
"description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://openswitchboard.dev",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{i as e,n as t,t as n}from"./AppShell-MYHNxJks.js";import{Bt as r,Lr as i,Vt as a,Wt as o,Xt as s,_n as c,a as l,ci as u,cn as d,gn as f,ir as p,ln as m,oi as h,on as g,r as _,sn as v,un as y,ur as b,vi as x,wi as S,xi as C,yn as w,zr as T}from"./seed-DeKSHrt2.js";async function E(e,t,n){try{let r=await e(`/api/${t}`,{method:`POST`,credentials:`same-origin`,headers:{"content-type":`application/json`},body:JSON.stringify(n)}),i=await r.json().catch(()=>null);return r.ok?{ok:!0,value:i}:{ok:!1,failure:{error:typeof i?.error==`string`?i.error:`HTTP ${r.status}`,message:typeof i?.message==`string`?i.message:`HTTP ${r.status}`}}}catch(e){return{ok:!1,failure:{error:`network`,message:e instanceof Error?e.message:String(e)}}}}async function D(e,t,n){let r=new URLSearchParams;for(let[e,t]of Object.entries(n))t!==void 0&&t!==``&&r.set(e,t);let i=r.size>0?`?${r.toString()}`:``;try{let n=await e(`/api/${t}${i}`,{credentials:`same-origin`}),r=await n.json().catch(()=>null);return n.ok?{ok:!0,value:r}:{ok:!1,failure:{error:typeof r?.error==`string`?r.error:`HTTP ${n.status}`,message:typeof r?.message==`string`?r.message:`HTTP ${n.status}`}}}catch(e){return{ok:!1,failure:{error:`network`,message:e instanceof Error?e.message:String(e)}}}}var O=`min-w-0 rounded border border-accented bg-default px-2 py-1 text-sm text-highlighted placeholder:text-dimmed disabled:opacity-60`,k=`rounded border border-accented bg-default px-2 py-1 font-mono text-xs text-toned disabled:opacity-60`,A={class:`grid gap-4`},j={class:`grid gap-3 lg:grid-cols-[minmax(16rem,22rem)_1fr]`},M={class:`grid content-start gap-3`},N={class:`overflow-hidden rounded-lg border border-default bg-elevated`},P={key:0,class:`unavailable px-4 py-3 text-sm text-warn`},F={key:1,class:`empty px-4 py-3 text-sm text-muted`},I={key:2,class:`index text-sm`},L=[`data-channel`],R=[`href`,`aria-current`],z={class:`font-mono text-xs font-medium text-highlighted`},B={class:`text-xs text-muted`},V={key:0,class:`placeholder rounded-lg border border-dashed border-default px-5 py-8 text-center text-sm text-muted`},H={key:1,class:`refused rounded-lg border border-warn/30 bg-warn/10 px-5 py-4 text-sm`},U={class:`font-mono text-xs`},W={key:2,class:`scope grid gap-4`},G={class:`flex flex-wrap items-baseline justify-between gap-2`},K={class:`font-mono text-sm font-medium text-highlighted`},q={class:`effective text-xs text-muted`},ee={key:0,class:`restricted text-xs text-muted`},te={class:`grid gap-3 sm:grid-cols-[9rem_1fr]`},ne=[`disabled`],re={value:``},ie=[`value`,`disabled`],ae=[`disabled`],oe={class:`grid gap-1.5`},se={class:`text-muted`},ce=[`onUpdate:modelValue`,`name`,`placeholder`,`disabled`],le=[`disabled`],ue=[`value`],de={class:`grid gap-1.5`},fe={class:`text-muted`},pe=[`onUpdate:modelValue`,`name`,`disabled`],me=[`value`],he={class:`grid gap-3 sm:grid-cols-[9rem_1fr]`},ge=[`disabled`],_e=[`disabled`],ve=[`value`],ye={class:`flex flex-wrap gap-x-4 gap-y-1`},be=[`name`,`checked`,`disabled`,`onChange`],xe={class:`flex flex-wrap items-center gap-3`},Se=[`disabled`],Ce={class:`flex flex-wrap items-center gap-3`},we={class:`text-xs text-dimmed tabular-nums`},J=w({__name:`ChannelsPanel`,props:{channels:{},vocabulary:{},fetch:{type:Function}},setup(e){let n=e,d=(e,t)=>(n.fetch??((e,t)=>globalThis.fetch(e,t)))(e,t),_=g(()=>n.channels.selected??null),w=g(()=>_.value?.scope?.channel??null),D=u(``);function J(){let e=D.value.trim();e&&t.navigate(`/settings/channels/${encodeURIComponent(e)}`)}let Y=h({agent:w.value?.agent??``,model:w.value?.model??``,models:Object.fromEntries(n.vocabulary.agents.map(e=>[e,w.value?.models?.[e]??``])),effort:w.value?.effort??``,efforts:Object.fromEntries(n.vocabulary.agents.map(e=>[e,w.value?.efforts?.[e]??``])),maxMinutes:w.value?.boundary?.maxMinutes?.toString()??``,maxIdentity:w.value?.boundary?.maxIdentity??``,machines:new Set(w.value?.boundary?.machines??[]),instructions:w.value?.instructions??``}),X=u(!1),Z=u(null),Q=g(()=>_.value?.canWrite===!0);function Te(e,t){t?Y.machines.add(e):Y.machines.delete(e)}function Ee(){let e={};Y.agent&&(e.agent=Y.agent),Y.model.trim()&&(e.model=Y.model.trim());let t=Object.fromEntries(Object.entries(Y.models).filter(([,e])=>e.trim()));Object.keys(t).length&&(e.models=t),Y.effort&&(e.effort=Y.effort);let n=Object.fromEntries(Object.entries(Y.efforts).filter(([,e])=>e));Object.keys(n).length&&(e.efforts=n);let r={};return Y.maxMinutes.trim()&&(r.maxMinutes=Number(Y.maxMinutes)),Y.maxIdentity&&(r.maxIdentity=Y.maxIdentity),Y.machines.size&&(r.machines=[...Y.machines].join(`,`)),Object.keys(r).length&&(e.boundary=r),e}async function $(e,n,r){if(!_.value)return;X.value=!0,Z.value=null;let i=await E(d,e,{scope:`channel`,channel:_.value.channelId,...n});if(X.value=!1,!i.ok){Z.value={kind:`error`,text:i.failure.message};return}Z.value={kind:`ok`,text:r},t.reload()}let De=()=>$(`config.set`,Ee(),`Saved.`),Oe=()=>$(`config.instructions`,{text:Y.instructions.trim()},`Instructions saved.`),ke=()=>$(`config.instructions`,{text:``},`Instructions cleared.`);async function Ae(){_.value&&t.confirm(`Drop every runtime override of ${_.value.channelId}? Static config.yaml values show through again.`)&&await $(`config.clear`,{},`Cleared.`)}let je={config:`config.yaml`,runtime:`runtime`,both:`config.yaml + runtime`};return(t,n)=>{let u=l;return p(),y(`section`,A,[n[31]||=v(`p`,{class:`text-sm text-muted`},[f(` A channel's scope sets which agent, model and effort its runs get, caps every run there, and adds advisory instructions. It layers over the installation defaults; a person's own settings (`),v(`code`,null,`config set me`),f(` in chat) layer over it. `)],-1),v(`div`,j,[v(`aside`,M,[v(`div`,N,[n[7]||=v(`h2`,{class:`border-b border-muted px-4 py-2 font-mono text-[0.6875rem] font-medium uppercase tracking-widest text-dimmed`},` Configured channels `,-1),e.channels.unavailable?(p(),y(`p`,P,S(e.channels.unavailable),1)):e.channels.index.length===0?(p(),y(`p`,F,` No channel carries a scope yet. `)):(p(),y(`ul`,I,[(p(!0),y(s,null,b(e.channels.index,e=>(p(),y(`li`,{key:e.channelId,class:`border-b border-muted last:border-0`,"data-channel":e.channelId},[v(`a`,{class:`grid gap-0.5 px-4 py-2 no-underline hover:bg-(--ui-bg-muted)`,href:`/settings/channels/${encodeURIComponent(e.channelId)}`,"aria-current":_.value?.channelId===e.channelId?`page`:void 0},[v(`span`,z,S(e.channelId),1),v(`span`,B,S(e.settings.join(`, `))+` · `+S(je[e.source]),1)],8,R)],8,L))),128))]))]),v(`form`,{class:`flex items-center gap-2`,onSubmit:o(J,[`prevent`])},[T(v(`input`,{id:`channel-open`,"onUpdate:modelValue":n[0]||=e=>D.value=e,class:C([x(O),`flex-1 font-mono text-xs`]),placeholder:`slack:C0123… — a channel with no scope yet`,"aria-label":`channel id to open`},null,2),[[a,D.value]]),c(u,{type:`submit`,size:`xs`,color:`neutral`,variant:`outline`},{default:i(()=>[...n[8]||=[f(`Open`,-1)]]),_:1})],32)]),_.value?_.value.refused?(p(),y(`div`,H,[v(`span`,U,S(_.value.channelId),1),f(` · `+S(_.value.refused),1)])):w.value&&_.value.scope?(p(),y(`div`,W,[v(`div`,G,[v(`h2`,K,S(_.value.channelId),1),v(`p`,q,[n[10]||=f(` Runs here get agent `,-1),v(`code`,null,S(_.value.scope.effective.agent),1),n[11]||=f(`, model `,-1),v(`code`,null,S(_.value.scope.effective.model),1),_.value.scope.effective.effort?(p(),y(s,{key:0},[n[9]||=f(`, effort `,-1),v(`code`,null,S(_.value.scope.effective.effort),1)],64)):m(``,!0)])]),Q.value?m(``,!0):(p(),y(`p`,ee,` Read-only: channel config changes need the channel-config right. `+S(_.value.scope.adminsHint),1)),v(`form`,{class:`agent-form grid gap-3 rounded-lg border border-default bg-elevated px-5 py-4`,onSubmit:o(De,[`prevent`])},[n[26]||=v(`h3`,{class:`font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Agent, model, effort`,-1),v(`div`,te,[n[14]||=v(`label`,{class:`text-sm text-muted`,for:`ch-agent`},`Agent`,-1),T(v(`select`,{id:`ch-agent`,"onUpdate:modelValue":n[1]||=e=>Y.agent=e,class:C(x(k)),disabled:!Q.value},[v(`option`,re,`— the default (`+S(_.value.scope.defaults.agent)+`), or the router —`,1),(p(!0),y(s,null,b(e.vocabulary.agents,e=>(p(),y(`option`,{key:e,value:e,disabled:_.value.scope.restrictedAgents.includes(e)},S(e)+S(_.value.scope.restrictedAgents.includes(e)?` (restricted)`:``),9,ie))),128))],10,ne),[[r,Y.agent]]),n[15]||=v(`label`,{class:`text-sm text-muted`,for:`ch-model`},`Model, any agent`,-1),T(v(`input`,{id:`ch-model`,"onUpdate:modelValue":n[2]||=e=>Y.model=e,class:C([x(O),`font-mono text-xs`]),placeholder:`provider/model — forces every run's model`,disabled:!Q.value},null,10,ae),[[a,Y.model]]),n[16]||=v(`span`,{class:`text-sm text-muted`},`Model per agent`,-1),v(`div`,oe,[(p(!0),y(s,null,b(e.vocabulary.agents,e=>(p(),y(`label`,{key:e,class:`grid grid-cols-[6rem_1fr] items-center gap-2 font-mono text-xs`},[v(`span`,se,S(e),1),T(v(`input`,{"onUpdate:modelValue":t=>Y.models[e]=t,name:`models.${e}`,class:C([x(O),`font-mono text-xs`]),placeholder:_.value.scope.defaults.models[e]??`default`,disabled:!Q.value},null,10,ce),[[a,Y.models[e]]])]))),128))]),n[17]||=v(`label`,{class:`text-sm text-muted`,for:`ch-effort`},`Effort, any agent`,-1),T(v(`select`,{id:`ch-effort`,"onUpdate:modelValue":n[3]||=e=>Y.effort=e,class:C(x(k)),disabled:!Q.value},[n[12]||=v(`option`,{value:``},`— unset —`,-1),(p(!0),y(s,null,b(e.vocabulary.efforts,e=>(p(),y(`option`,{key:e,value:e},S(e),9,ue))),128))],10,le),[[r,Y.effort]]),n[18]||=v(`span`,{class:`text-sm text-muted`},`Effort per agent`,-1),v(`div`,de,[(p(!0),y(s,null,b(e.vocabulary.agents,t=>(p(),y(`label`,{key:t,class:`grid grid-cols-[6rem_1fr] items-center gap-2 font-mono text-xs`},[v(`span`,fe,S(t),1),T(v(`select`,{"onUpdate:modelValue":e=>Y.efforts[t]=e,name:`efforts.${t}`,class:C(x(k)),disabled:!Q.value},[n[13]||=v(`option`,{value:``},`— unset —`,-1),(p(!0),y(s,null,b(e.vocabulary.efforts,e=>(p(),y(`option`,{key:e,value:e},S(e),9,me))),128))],10,pe),[[r,Y.efforts[t]]])]))),128))])]),n[27]||=v(`h3`,{class:`mt-2 font-mono text-xs font-medium uppercase tracking-wider text-muted`},` Boundary · caps every run here, never grants `,-1),v(`div`,he,[n[20]||=v(`label`,{class:`text-sm text-muted`,for:`ch-minutes`},`Max minutes`,-1),T(v(`input`,{id:`ch-minutes`,"onUpdate:modelValue":n[4]||=e=>Y.maxMinutes=e,class:C([x(O),`w-28 font-mono text-xs tabular-nums`]),type:`number`,min:`2`,placeholder:`uncapped`,disabled:!Q.value},null,10,ge),[[a,Y.maxMinutes]]),n[21]||=v(`label`,{class:`text-sm text-muted`,for:`ch-identity`},`Max identity`,-1),T(v(`select`,{id:`ch-identity`,"onUpdate:modelValue":n[5]||=e=>Y.maxIdentity=e,class:C(x(k)),disabled:!Q.value},[n[19]||=v(`option`,{value:``},`— uncapped —`,-1),(p(!0),y(s,null,b(e.vocabulary.identities,e=>(p(),y(`option`,{key:e,value:e},S(e),9,ve))),128))],10,_e),[[r,Y.maxIdentity]]),n[22]||=v(`span`,{class:`text-sm text-muted`},`Machines`,-1),v(`div`,ye,[(p(!0),y(s,null,b(e.vocabulary.machines,e=>(p(),y(`label`,{key:e,class:`inline-flex items-center gap-1.5 font-mono text-xs`},[v(`input`,{type:`checkbox`,name:`machine-${e}`,checked:Y.machines.has(e),disabled:!Q.value,onChange:t=>Te(e,t.target.checked)},null,40,be),f(` `+S(e),1)]))),128))])]),v(`div`,xe,[c(u,{type:`submit`,size:`sm`,color:`neutral`,disabled:!Q.value||X.value},{default:i(()=>[...n[23]||=[f(`Save`,-1)]]),_:1},8,[`disabled`]),c(u,{size:`sm`,color:`error`,variant:`ghost`,disabled:!Q.value||X.value,onClick:Ae},{default:i(()=>[...n[24]||=[f(`Clear every override`,-1)]]),_:1},8,[`disabled`]),n[25]||=v(`span`,{class:`text-xs text-dimmed`},`Save sets the filled fields and leaves the rest as they are.`,-1)])],32),v(`form`,{class:`instructions-form grid gap-3 rounded-lg border border-default bg-elevated px-5 py-4`,onSubmit:o(Oe,[`prevent`])},[n[30]||=v(`h3`,{class:`font-mono text-xs font-medium uppercase tracking-wider text-muted`},` Custom instructions · advisory, on every run here `,-1),T(v(`textarea`,{id:`ch-instructions`,"onUpdate:modelValue":n[6]||=e=>Y.instructions=e,class:C([x(O),`min-h-28 w-full`]),maxlength:`2000`,placeholder:`Always reply in bullet points.`,disabled:!Q.value},null,10,Se),[[a,Y.instructions]]),v(`div`,Ce,[c(u,{type:`submit`,size:`sm`,color:`neutral`,disabled:!Q.value||X.value},{default:i(()=>[...n[28]||=[f(`Save instructions`,-1)]]),_:1},8,[`disabled`]),c(u,{size:`sm`,color:`neutral`,variant:`ghost`,disabled:!Q.value||X.value,onClick:ke},{default:i(()=>[...n[29]||=[f(`Clear instructions`,-1)]]),_:1},8,[`disabled`]),v(`span`,we,S(Y.instructions.length)+` / 2000`,1)])],32),Z.value?(p(),y(`p`,{key:1,class:C([`notice rounded-md px-3 py-2 text-sm`,Z.value.kind===`error`?`border border-err/30 bg-err/10`:`border border-ok/30 bg-ok/10`])},S(Z.value.text),3)):m(``,!0)])):m(``,!0):(p(),y(`div`,V,` Pick a channel to see and change its scope. `))])])}}}),Y={class:`grid gap-4`},X={class:`overflow-x-auto rounded-lg border border-default bg-elevated`},Z={class:`settings w-full min-w-[42rem] border-collapse text-[0.8125rem]`},Q={class:`border-t border-muted bg-muted/40`},Te={colspan:`4`,class:`px-4 py-1.5 text-left font-mono text-xs font-medium text-toned`},Ee=[`data-key`],$={class:`px-4 py-2 font-mono text-xs text-highlighted`},De={class:`px-4 py-2 font-mono text-xs tabular-nums`},Oe={class:`value`},ke={key:0,class:`ml-1.5 rounded bg-accented px-1.5 py-0.5 text-[0.625rem] text-muted`},Ae={class:`px-4 py-2 text-muted`},je={class:`px-4 py-2 text-xs text-dimmed`},Me={class:`capabilities grid gap-1.5 rounded-lg border border-default bg-elevated px-4 py-3 text-sm`},Ne=[`data-capability`,`data-on`],Pe={class:`w-40 font-mono text-xs text-highlighted`},Fe={class:`text-xs text-muted`},Ie=w({__name:`InstallationPanel`,props:{installation:{}},setup(e){let t=e,n=g(()=>{let e=[];for(let n of t.installation.settings){let t=n.key.split(`.`)[0],r=e[e.length-1];r&&r.block===t?r.rows.push(n):e.push({block:t,rows:[n]})}return e}),r={runtime:"config.yaml default · a channel overrides it at run time (Channels tab, `config set channel`)",config:"config.yaml · `deploy config`, then a restart"},i=e=>typeof e==`string`?e:e?`on`:`off`;return(t,a)=>(p(),y(`section`,Y,[a[1]||=v(`p`,{class:`text-sm text-muted`},[f(` The behaviour knobs of this installation's `),v(`code`,null,`config.yaml`),f(`, with the value in force. A running process keeps the config it started with: a change here is `),v(`code`,null,`deploy config`),f(` and a restart. The `),v(`code`,null,`defaults.*`),f(` rows are what a channel overrides on the Channels tab. `)],-1),v(`div`,X,[v(`table`,Z,[a[0]||=v(`thead`,null,[v(`tr`,{class:`text-left font-mono text-[0.6875rem] uppercase tracking-widest text-dimmed`},[v(`th`,{class:`px-4 py-2.5 font-medium`},`Key`),v(`th`,{class:`px-4 py-2.5 font-medium`},`Value`),v(`th`,{class:`px-4 py-2.5 font-medium`},`What it does`),v(`th`,{class:`px-4 py-2.5 font-medium`},`Changes in`)])],-1),(p(!0),y(s,null,b(n.value,e=>(p(),y(`tbody`,{key:e.block},[v(`tr`,Q,[v(`th`,Te,S(e.block),1)]),(p(!0),y(s,null,b(e.rows,e=>(p(),y(`tr`,{key:e.key,class:`setting border-t border-muted align-top`,"data-key":e.key},[v(`td`,$,S(e.key),1),v(`td`,De,[v(`span`,Oe,S(e.value),1),e.isDefault?(p(),y(`span`,ke,`default`)):m(``,!0)]),v(`td`,Ae,S(e.note),1),v(`td`,je,S(r[e.how]),1)],8,Ee))),128))]))),128))])]),a[2]||=v(`h2`,{class:`mt-2 font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Capabilities`,-1),a[3]||=v(`p`,{class:`-mt-3 text-sm text-muted`},[f(` What is on in this process. Each one is a `),v(`code`,null,`config.yaml`),f(` block plus what its environment needs; the commands, dashboard section and Worker of a capability appear together when it is on. `)],-1),v(`ul`,Me,[(p(!0),y(s,null,b(e.installation.capabilities,e=>(p(),y(`li`,{key:e.key,class:`capability flex flex-wrap items-baseline gap-x-3 gap-y-0.5 border-b border-muted py-1.5 last:border-0`,"data-capability":e.key,"data-on":String(e.on)},[v(`span`,Pe,S(e.key),1),v(`span`,{class:C([`state rounded px-1.5 py-0.5 font-mono text-[0.6875rem]`,e.on===!1?`bg-accented text-dimmed`:`bg-ok/15 text-ok`])},S(i(e.on)),3),v(`span`,Fe,S(e.how),1)],8,Ne))),128))])]))}}),Le={class:`grid gap-4`},Re={class:`text-sm text-muted`},ze={key:0,class:`unavailable rounded-md border border-warn/30 bg-warn/10 px-3 py-2 text-sm`},Be={key:1,class:`overflow-x-auto rounded-lg border border-default bg-elevated`},Ve={class:`servers w-full min-w-[46rem] border-collapse text-[0.8125rem]`},He={key:0},Ue=[`data-name`,`data-scope`],We={class:`px-4 py-2 font-mono text-xs font-medium text-highlighted`},Ge={key:0,class:`ml-1 text-[0.625rem] font-normal text-dimmed`},Ke={class:`px-4 py-2 font-mono text-xs`},qe=[`title`],Je={class:`px-4 py-2 font-mono text-xs`},Ye={class:`px-4 py-2 font-mono text-xs`},Xe={class:`px-4 py-2 text-xs`},Ze={key:0,class:`probe mt-1 text-dimmed`},Qe={class:`px-4 py-1.5 text-right whitespace-nowrap`},$e={class:`grid gap-3 sm:grid-cols-[8rem_1fr]`},et=[`disabled`],tt=[`disabled`],nt=[`disabled`],rt=[`disabled`],it=[`disabled`],at={class:`flex flex-wrap gap-x-4 gap-y-1 text-sm`},ot=[`name`,`checked`,`disabled`,`onChange`],st=[`disabled`],ct={class:`flex flex-wrap items-center gap-3`},lt={key:0,class:`restricted text-xs text-muted`},ut=[`href`],dt=w({__name:`McpServersPanel`,props:{mcps:{},vocabulary:{},viewer:{},asUser:{},fetch:{type:Function}},setup(e){let n=e,_=(e,t)=>(n.fetch??((e,t)=>globalThis.fetch(e,t)))(e,t),w=[`general`,`research`],A=g(()=>n.asUser!==void 0),j=h({name:``,url:``,scope:n.mcps.channel?`channel`:n.asUser?`me`:`org`,agents:new Set(w),auth:``}),M=u(n.mcps.channel??``),N=u(!1),P=u(null),F=h({}),I=g(()=>j.scope===`org`?n.mcps.canWrite.org:j.scope===`channel`?n.mcps.canWrite.channel:A.value),L=e=>e.scope===`org`?n.mcps.canWrite.org:e.scope===`channel`?n.mcps.canWrite.channel:n.asUser!==void 0&&e.scopeKey===`user:${n.asUser.id}`,R=e=>e.addedBy===n.viewer||n.asUser!==void 0&&e.addedBy===n.asUser.id,z={connected:`connected`,awaiting_credential:`awaiting credential`,static:`pinned in config.yaml`};function B(){let e=M.value.trim();t.navigate(e?`/settings/mcps?channel=${encodeURIComponent(e)}`:`/settings/mcps`)}function V(e,t){t?j.agents.add(e):j.agents.delete(e)}function H(e){return e===`channel`?{scope:`channel`,channel:n.mcps.channel}:{scope:e}}let U=e=>e.scope===`user`?`me`:e.scope;async function W(){N.value=!0,P.value=null;let e=await E(_,`mcp.add`,{name:j.name.trim(),url:j.url.trim(),...H(j.scope),agents:[...j.agents].join(`,`),...j.auth?{auth:j.auth}:{}});if(N.value=!1,!e.ok){P.value={kind:`error`,text:e.failure.message};return}let n=e.value;P.value=n.connectUrl?{kind:`ok`,text:`Added ${n.server?.name??j.name}. Open the one-time link to connect it (it expires in 10 minutes; only you can complete it).`,connectUrl:n.connectUrl}:{kind:`ok`,text:`Added ${n.server?.name??j.name}.`},n.connectUrl||t.reload()}async function G(e){N.value=!0,P.value=null;let t=await E(_,`mcp.connect`,{name:e.name,...H(U(e))});if(N.value=!1,!t.ok){P.value={kind:`error`,text:t.failure.message};return}let n=t.value;P.value={kind:`ok`,text:`A fresh one-time link for ${e.name} (10 minutes; only you can complete it).`,...n.connectUrl?{connectUrl:n.connectUrl}:{}}}async function K(e){if(!t.confirm(`Remove ${e.name} from the ${e.scope} tier and forget its stored credential?`))return;N.value=!0,P.value=null;let n=await E(_,`mcp.remove`,{name:e.name,...H(U(e))});if(N.value=!1,!n.ok){P.value={kind:`error`,text:n.failure.message};return}t.reload()}async function q(e){F[e.name]=`probing…`;let t=await D(_,`mcp.show`,{name:e.name,scope:e.scope===`user`?`me`:e.scope,channel:e.scope===`channel`?n.mcps.channel:void 0});if(!t.ok){F[e.name]=t.failure.message;return}let{probe:r}=t.value;F[e.name]=r?.tools?`${r.tools.length} tool${r.tools.length===1?``:`s`}: ${r.tools.map(e=>e.name).join(`, `)}`:r?.error??`no tools listed`}return(t,n)=>{let u=l;return p(),y(`section`,Le,[v(`p`,Re,[n[9]||=f(` External MCP servers a run's tools may call, by tier: `,-1),n[10]||=v(`strong`,null,`org`,-1),n[11]||=f(` reaches every run and is the only tier that may name the coding, review or ship agents; `,-1),n[12]||=v(`strong`,null,`channel`,-1),n[13]||=f(` reaches that channel's runs; `,-1),e.asUser?(p(),y(s,{key:0},[n[5]||=v(`strong`,null,`me`,-1),f(` reaches the runs you ask for as `+S(e.asUser.name??e.asUser.id)+`.`,1)],64)):(p(),y(s,{key:1},[n[6]||=f(`personal servers are added in chat (`,-1),n[7]||=v(`code`,null,`mcp add`,-1),n[8]||=f(`), where your runs are requested as you.`,-1)],64))]),v(`form`,{class:`flex flex-wrap items-center gap-2 text-sm`,onSubmit:o(B,[`prevent`])},[n[15]||=v(`label`,{class:`text-muted`,for:`mcp-channel`},`Channel tier`,-1),T(v(`input`,{id:`mcp-channel`,"onUpdate:modelValue":n[0]||=e=>M.value=e,class:C([x(O),`font-mono text-xs`]),placeholder:`slack:C0123… (blank: org and your own)`,"aria-label":`channel whose MCP servers to list`},null,2),[[a,M.value]]),c(u,{type:`submit`,size:`xs`,color:`neutral`,variant:`outline`},{default:i(()=>[...n[14]||=[f(`Open`,-1)]]),_:1})],32),e.mcps.unavailable?(p(),y(`p`,ze,S(e.mcps.unavailable),1)):(p(),y(`div`,Be,[v(`table`,Ve,[n[20]||=v(`thead`,null,[v(`tr`,{class:`text-left font-mono text-[0.6875rem] uppercase tracking-widest text-dimmed`},[v(`th`,{class:`px-4 py-2.5 font-medium`},`Name`),v(`th`,{class:`px-4 py-2.5 font-medium`},`Tier`),v(`th`,{class:`px-4 py-2.5 font-medium`},`URL`),v(`th`,{class:`px-4 py-2.5 font-medium`},`Agents`),v(`th`,{class:`px-4 py-2.5 font-medium`},`Auth`),v(`th`,{class:`px-4 py-2.5 font-medium`},`State`),v(`th`,{class:`px-4 py-2.5 font-medium`},[v(`span`,{class:`sr-only`},`Actions`)])])],-1),v(`tbody`,null,[e.mcps.servers.length===0?(p(),y(`tr`,He,[...n[16]||=[v(`td`,{colspan:`7`,class:`empty px-4 py-6 text-center text-muted`},` No MCP server reaches runs here yet. Add one below. `,-1)]])):m(``,!0),(p(!0),y(s,null,b(e.mcps.servers,e=>(p(),y(`tr`,{key:`${e.scopeKey}/${e.name}`,class:`server border-t border-muted align-top`,"data-name":e.name,"data-scope":e.scope},[v(`td`,We,[f(S(e.name)+` `,1),R(e)?(p(),y(`span`,Ge,`· added by you`)):m(``,!0)]),v(`td`,Ke,S(e.scope),1),v(`td`,{class:`max-w-[18rem] truncate px-4 py-2 font-mono text-xs text-muted`,title:e.url},S(e.url),9,qe),v(`td`,Je,S(e.agents.join(`, `)),1),v(`td`,Ye,S(e.auth),1),v(`td`,Xe,[v(`span`,{class:C([`state rounded px-1.5 py-0.5 font-mono text-[0.6875rem]`,e.state===`connected`?`bg-ok/15 text-ok`:e.state===`awaiting_credential`?`bg-warn/15 text-warn`:`bg-accented text-muted`])},S(z[e.state]),3),F[e.name]?(p(),y(`div`,Ze,S(F[e.name]),1)):m(``,!0)]),v(`td`,Qe,[c(u,{size:`xs`,color:`neutral`,variant:`ghost`,disabled:N.value,onClick:t=>q(e)},{default:i(()=>[...n[17]||=[f(`Probe`,-1)]]),_:1},8,[`disabled`,`onClick`]),e.source===`runtime`&&e.auth!==`none`?(p(),d(u,{key:0,size:`xs`,color:`neutral`,variant:`ghost`,disabled:N.value||!L(e),onClick:t=>G(e)},{default:i(()=>[...n[18]||=[f(`Connect`,-1)]]),_:1},8,[`disabled`,`onClick`])):m(``,!0),e.source===`runtime`?(p(),d(u,{key:1,size:`xs`,color:`error`,variant:`ghost`,disabled:N.value||!L(e),onClick:t=>K(e)},{default:i(()=>[...n[19]||=[f(`Remove`,-1)]]),_:1},8,[`disabled`,`onClick`])):m(``,!0)])],8,Ue))),128))])])])),e.mcps.unavailable?m(``,!0):(p(),y(`form`,{key:2,class:`add grid gap-3 rounded-lg border border-default bg-elevated px-5 py-4`,onSubmit:o(W,[`prevent`])},[n[29]||=v(`h2`,{class:`font-mono text-xs font-medium uppercase tracking-wider text-muted`},`Add a server`,-1),v(`div`,$e,[n[23]||=v(`label`,{class:`text-sm text-muted`,for:`mcp-name`},`Name`,-1),T(v(`input`,{id:`mcp-name`,"onUpdate:modelValue":n[1]||=e=>j.name=e,class:C([x(O),`font-mono text-xs`]),required:``,pattern:`[a-z0-9][a-z0-9-]{0,31}`,placeholder:`notion — becomes the tool prefix mcp__notion__`,disabled:!I.value},null,10,et),[[a,j.name]]),n[24]||=v(`label`,{class:`text-sm text-muted`,for:`mcp-url`},`URL`,-1),T(v(`input`,{id:`mcp-url`,"onUpdate:modelValue":n[2]||=e=>j.url=e,class:C([x(O),`font-mono text-xs`]),type:`url`,required:``,placeholder:`https://mcp.example.com/mcp — Streamable HTTP`,disabled:!I.value},null,10,tt),[[a,j.url]]),n[25]||=v(`label`,{class:`text-sm text-muted`,for:`mcp-scope`},`Tier`,-1),T(v(`select`,{id:`mcp-scope`,"onUpdate:modelValue":n[3]||=e=>j.scope=e,class:C(x(k)),disabled:!I.value&&!e.mcps.canWrite.org&&!e.mcps.canWrite.channel&&!A.value},[v(`option`,{value:`me`,disabled:!A.value},` me — `+S(e.asUser?`your own runs, as ${e.asUser.name??e.asUser.id}`:`your session is not linked to a Slack user`),9,rt),n[21]||=v(`option`,{value:`org`},`org — every run; may name coding, review, ship`,-1),v(`option`,{value:`channel`,disabled:!e.mcps.channel},` channel — `+S(e.mcps.channel??`open a channel above first`),9,it)],10,nt),[[r,j.scope]]),n[26]||=v(`span`,{class:`text-sm text-muted`},`Agents`,-1),v(`div`,at,[(p(!0),y(s,null,b(e.vocabulary.agents,e=>(p(),y(`label`,{key:e,class:`inline-flex items-center gap-1.5 font-mono text-xs`},[v(`input`,{type:`checkbox`,name:`agent-${e}`,checked:j.agents.has(e),disabled:!I.value||j.scope===`channel`&&!w.includes(e),onChange:t=>V(e,t.target.checked)},null,40,ot),f(` `+S(e),1)]))),128))]),n[27]||=v(`label`,{class:`text-sm text-muted`,for:`mcp-auth`},`Auth`,-1),T(v(`select`,{id:`mcp-auth`,"onUpdate:modelValue":n[4]||=e=>j.auth=e,class:C(x(k)),disabled:!I.value},[...n[22]||=[v(`option`,{value:``},`detect from the server`,-1),v(`option`,{value:`oauth`},`oauth — sign in on a one-time link`,-1),v(`option`,{value:`bearer`},`bearer — paste a token on a one-time link`,-1),v(`option`,{value:`none`},`none`,-1)]],10,st),[[r,j.auth]])]),v(`div`,ct,[c(u,{type:`submit`,size:`sm`,color:`neutral`,disabled:!I.value||N.value},{default:i(()=>[...n[28]||=[f(`Add`,-1)]]),_:1},8,[`disabled`]),I.value?m(``,!0):(p(),y(`span`,lt,S(j.scope===`org`?`Org-wide servers are managed by admins (repo-management rights).`:j.scope===`channel`?`This channel's servers need channel-config rights.`:"Personal servers need a session linked to your Slack user; add yours in chat with `mcp add`."),1))]),P.value?(p(),y(`p`,{key:0,class:C([`notice rounded-md px-3 py-2 text-sm`,P.value.kind===`error`?`border border-err/30 bg-err/10`:`border border-ok/30 bg-ok/10`])},[f(S(P.value.text)+` `,1),P.value.connectUrl?(p(),y(`a`,{key:0,class:`connect ml-1 font-mono text-xs underline`,href:P.value.connectUrl},S(P.value.connectUrl),9,ut)):m(``,!0)],2)):m(``,!0)],32))])}}}),ft=[{id:`mcps`,href:`/settings/mcps`,label:`MCPs`,on:e=>e.mcp},{id:`channels`,href:`/settings/channels`,label:`Channels`},{id:`installation`,href:`/settings/installation`,label:`Installation`}];function pt(e,t){return ft.filter(n=>n.id===t||n.on===void 0||e!==null&&n.on(e))}var mt={class:`tabs mb-3.5 flex gap-5 border-b border-muted px-2 text-[0.8rem]`,"aria-label":`Settings sections`},ht=[`href`,`aria-current`],gt=w({__name:`SettingsTabs`,props:{current:{}},setup(t){let n=t,r=e(),i=g(()=>pt(r,n.current));return(e,n)=>(p(),y(`nav`,mt,[(p(!0),y(s,null,b(i.value,e=>(p(),y(`a`,{key:e.id,href:e.href,"aria-current":e.id===t.current?`page`:void 0,class:`-mb-px border-b border-transparent pb-2 pt-1.5 text-muted no-underline hover:text-highlighted aria-[current=page]:border-(--ui-text-highlighted) aria-[current=page]:font-medium aria-[current=page]:text-highlighted`},S(e.label),9,ht))),128))]))}}),_t=w({__name:`SettingsPage`,setup(e){let t=_(`settings`),r=g(()=>t?.tab??`channels`);return(e,a)=>x(t)?(p(),d(n,{key:0,title:`Settings`,nav:`settings`},{default:i(()=>[c(gt,{current:r.value},null,8,[`current`]),r.value===`mcps`&&x(t).mcps?(p(),d(dt,{key:0,mcps:x(t).mcps,vocabulary:x(t).vocabulary,viewer:x(t).viewer,"as-user":x(t).asUser},null,8,[`mcps`,`vocabulary`,`viewer`,`as-user`])):r.value===`channels`&&x(t).channels?(p(),d(J,{key:1,channels:x(t).channels,vocabulary:x(t).vocabulary},null,8,[`channels`,`vocabulary`])):r.value===`installation`&&x(t).installation?(p(),d(Ie,{key:2,installation:x(t).installation},null,8,[`installation`])):m(``,!0)]),_:1})):(p(),d(n,{key:1,title:`Settings`,nav:`settings`},{default:i(()=>[...a[0]||=[v(`p`,{class:`empty py-8 text-center text-sm text-muted`},` Settings are unavailable: the page was served without its data. `,-1)]]),_:1}))}});export{_t as default};
|