@promptowl/contextnest-community 1.26.0 → 1.27.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/API.md +34 -1
- package/CONFIGURATION.md +32 -1
- package/dist/{chunk-TRSGPS27.js → chunk-H3W72HN3.js} +28 -0
- package/dist/{chunk-DGPTJXIV.js → chunk-MB52DWWP.js} +4 -4
- package/dist/{chunk-IEAWRHMV.js → chunk-NFFUZF2B.js} +23 -2
- package/dist/{chunk-PICUHQEM.js → chunk-O3JEI33N.js} +2 -2
- package/dist/{chunk-SWA5M5XX.js → chunk-QMQDWRHN.js} +128 -22
- package/dist/{chunk-I5EDEZBQ.js → chunk-RXCVXG34.js} +1 -1
- package/dist/{chunk-2QOJE7A5.js → chunk-SE5U4J4T.js} +4 -4
- package/dist/{chunk-RPGFHESR.js → chunk-VHEMGQ3I.js} +1 -1
- package/dist/{chunk-M6PGYMBD.js → chunk-VRLAP4HB.js} +33 -15
- package/dist/{engine-QNMFDIBV.js → engine-HLYQLP5T.js} +3 -3
- package/dist/{external-edit-service-4MEGPT4D.js → external-edit-service-3DFQ4EZZ.js} +4 -4
- package/dist/{grants-service-24GLUBY4.js → grants-service-WICV4Y2J.js} +2 -2
- package/dist/index.js +804 -304
- package/dist/{invited-user-AM6A3WGO.js → invited-user-XEBX6BM4.js} +3 -3
- package/dist/{review-service-2EWN7WWO.js → review-service-GB43UQVH.js} +7 -7
- package/dist/{stewardship-service-TDZUC2Q6.js → stewardship-service-KDBPWRZI.js} +4 -4
- package/dist/{version-service-C3JTZLJH.js → version-service-JYHFPSYP.js} +8 -4
- package/dist/web3/assets/{ActivityTracePage-DzwWIjjx.js → ActivityTracePage-CkRoyIc-.js} +1 -1
- package/dist/web3/assets/AgentDocsPage-BTRXmliv.js +1 -0
- package/dist/web3/assets/CollaboratorManager-CqJIkvs-.js +1 -0
- package/dist/web3/assets/CollaboratorsTab-JcO1P-qm.js +1 -0
- package/dist/web3/assets/DocumentEditor-D1GLeeEP.js +36 -0
- package/dist/web3/assets/DocumentsTab-BAgSxTX1.js +6 -0
- package/dist/web3/assets/ExternalEditsTab-DuuTXZap.js +1 -0
- package/dist/web3/assets/{MarkdownEditor-CKh4WSn-.js → MarkdownEditor-BELFww9q.js} +116 -126
- package/dist/web3/assets/{NestPageHeader-Cizo8nUi.js → NestPageHeader-Bbje2ncY.js} +1 -1
- package/dist/web3/assets/NestView-D4OMXPQ7.js +73 -0
- package/dist/web3/assets/OverviewTab-FIDGjR3Q.js +6 -0
- package/dist/web3/assets/{PersonCombobox-BKI7dff4.js → PersonCombobox-D52m_jhc.js} +1 -1
- package/dist/web3/assets/{ReviewActions-CS8JXgXF.js → ReviewActions-DYqBcWlv.js} +2 -2
- package/dist/web3/assets/ReviewTab-DoxfygOb.js +1 -0
- package/dist/web3/assets/StewardsTab-CFsYjbEn.js +1 -0
- package/dist/web3/assets/{SubmitForReviewModal-Biq3m79i.js → SubmitForReviewModal-AW2OLNAE.js} +1 -1
- package/dist/web3/assets/{alert-dialog-BvF3NFr7.js → alert-dialog-p-fBLSWx.js} +2 -2
- package/dist/web3/assets/{arrow-left-CWIsv-sG.js → arrow-left-CiErCCTG.js} +1 -1
- package/dist/web3/assets/{backlinks-Cqcn7n1J.js → backlinks-DaVSYvhV.js} +2 -2
- package/dist/web3/assets/{boxes-ClbgQqG2.js → boxes-VWrCCMzW.js} +1 -1
- package/dist/web3/assets/{chevron-left-CK_ZPFm9.js → chevron-left-CsD8gZwL.js} +1 -1
- package/dist/web3/assets/{circle-check-Bw_aTXiH.js → circle-check-BBCXd9LI.js} +1 -1
- package/dist/web3/assets/{circle-x-DkIG68H7.js → circle-x-C9LsnORQ.js} +1 -1
- package/dist/web3/assets/{code-xml-BlR7EN6l.js → code-xml-BaoV7HiQ.js} +1 -1
- package/dist/web3/assets/{corner-down-right-DSVxK3tf.js → corner-down-right-DgiTXrtw.js} +1 -1
- package/dist/web3/assets/{count-skeleton-DToLM74B.js → count-skeleton-CnEE4uF-.js} +1 -1
- package/dist/web3/assets/{earth-BXhVPvCR.js → earth-BmMbVt9k.js} +1 -1
- package/dist/web3/assets/{file-exclamation-point-BevGZgtj.js → file-exclamation-point-qJeca9-A.js} +1 -1
- package/dist/web3/assets/{folder-input-m8UBV4fA.js → folder-input-D7R93LJ6.js} +1 -1
- package/dist/web3/assets/index-DNmWTxN7.css +1 -0
- package/dist/web3/assets/index-DvuUIUP6.js +451 -0
- package/dist/web3/assets/{page-DzKwP5Ds.js → page-BJQuaTRW.js} +2 -2
- package/dist/web3/assets/{page-B6pkc9cd.js → page-Bb8xGOPQ.js} +2 -2
- package/dist/web3/assets/{page-Deq6IKiN.js → page-BtM-qDzr.js} +2 -2
- package/dist/web3/assets/{page-DPY01SOj.js → page-Bxd0EG25.js} +1 -1
- package/dist/web3/assets/page-C3QCO6IR.js +1 -0
- package/dist/web3/assets/{page-CptuAPJc.js → page-CfoR0khy.js} +2 -2
- package/dist/web3/assets/page-D7Zr5tAI.js +1 -0
- package/dist/web3/assets/{page-Dwbp4Seu.js → page-DATSlHCW.js} +2 -2
- package/dist/web3/assets/page-DTjPQizZ.js +45 -0
- package/dist/web3/assets/{page-Bgy9Ng9p.js → page-DspptlWr.js} +1 -1
- package/dist/web3/assets/{page-Dh57L0RG.js → page-I6vAFJOj.js} +4 -4
- package/dist/web3/assets/page-QxI4Ud2s.js +9 -0
- package/dist/web3/assets/{page-BJrFCKXB.js → page-YcNNg-dX.js} +1 -1
- package/dist/web3/assets/page-kM7eO5Kj.js +1 -0
- package/dist/web3/assets/{page-title-DVq4qvMR.js → page-title-Dn5jANiU.js} +1 -1
- package/dist/web3/assets/{play-CXhS6Pgq.js → play-B2k_Ix-L.js} +1 -1
- package/dist/web3/assets/{send-DdfwnIrj.js → send-DPNxv3As.js} +1 -1
- package/dist/web3/assets/{settings-DKX0Q4gO.js → settings-DZjq-OQA.js} +1 -1
- package/dist/web3/assets/{share-2-CxmXRt58.js → share-2-C-OnE2ru.js} +1 -1
- package/dist/web3/assets/{tag-DeYC_mRv.js → tag-CwJl7FdI.js} +1 -1
- package/dist/web3/assets/{trash-2-B0HyPTnI.js → trash-2-aljmIff4.js} +1 -1
- package/dist/web3/assets/{user-plus-Ckm_Isyc.js → user-plus-DPerZexX.js} +1 -1
- package/dist/web3/assets/{zap-D2ifcnYb.js → zap-CHZtiN7P.js} +1 -1
- package/dist/web3/index.html +2 -2
- package/package.json +6 -2
- package/dist/web3/assets/AgentDocsPage-ixP2UdAE.js +0 -1
- package/dist/web3/assets/CollaboratorManager-C9VAXZ0h.js +0 -1
- package/dist/web3/assets/CollaboratorsTab-tq4ZTexH.js +0 -1
- package/dist/web3/assets/DocumentEditor-C2CP2fiE.js +0 -36
- package/dist/web3/assets/DocumentsTab-Mh7KxUoB.js +0 -6
- package/dist/web3/assets/ExternalEditsTab-B_CWKXZ_.js +0 -1
- package/dist/web3/assets/NestView-EW-sraEb.js +0 -73
- package/dist/web3/assets/OverviewTab-CjidsMX_.js +0 -6
- package/dist/web3/assets/ReviewTab-CwVrXzw5.js +0 -1
- package/dist/web3/assets/StewardsTab-C-iP6gnh.js +0 -1
- package/dist/web3/assets/index-BOVYgMvj.js +0 -29
- package/dist/web3/assets/index-DVnaYqj9.css +0 -1
- package/dist/web3/assets/index-WYDmEOfO.js +0 -404
- package/dist/web3/assets/page-C2zoxumw.js +0 -1
- package/dist/web3/assets/page-CJWO06dN.js +0 -1
- package/dist/web3/assets/page-Dea2SblF.js +0 -9
- package/dist/web3/assets/page-Dfjg8p7Z.js +0 -1
- package/dist/web3/assets/page-YxjrE5b5.js +0 -45
- package/dist/web3/assets/x-mNtADYHc.js +0 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as gt,r,j as e,
|
|
1
|
+
import{c as gt,r,j as e,V as Bt,W as Kt,Y as Be,Z as Ke,bd as ft,be as vt,bf as Ue,bg as jt,bh as qt,bi as Je,I as te,B as S,R as st,L as J,bj as Qe,bk as Ie,bl as bt,bm as yt,e as se,bn as Ut,b4 as oe,bo as Xt,bp as Gt,bq as mt,br as Jt,S as Yt,bs as Zt,bt as Nt,bu as Qt,bv as wt,bw as It,bx as es,by as ts,bz as ss,bA as ns,aa as as,F as rs,bB as kt,bC as os,bD as _t,f as ls,aI as is,al as St,am as Ct,an as Et,ao as Tt,ap as et,bE as qe,X as $t,bF as cs,bG as ds,aT as us,au as ms,b8 as xs}from"./index-DvuUIUP6.js";import{A as Ye,W as At,T as hs,O as ps}from"./MarkdownEditor-BELFww9q.js";import{F as gs,N as We}from"./NestView-D4OMXPQ7.js";import{N as fs}from"./NestPageHeader-Bbje2ncY.js";import{P as Pt}from"./play-B2k_Ix-L.js";import{T as ze}from"./trash-2-aljmIff4.js";import{Z as Rt,F as vs}from"./zap-CHZtiN7P.js";import{C as nt}from"./corner-down-right-DgiTXrtw.js";import{A as js}from"./arrow-left-CiErCCTG.js";import"./chevron-left-CsD8gZwL.js";import"./alert-dialog-p-fBLSWx.js";import"./count-skeleton-CnEE4uF-.js";import"./folder-input-D7R93LJ6.js";import"./PersonCombobox-D52m_jhc.js";import"./tag-CwJl7FdI.js";import"./user-plus-DPerZexX.js";import"./ReviewActions-DYqBcWlv.js";import"./circle-check-BBCXd9LI.js";import"./circle-x-C9LsnORQ.js";import"./settings-DZjq-OQA.js";/**
|
|
2
2
|
* @license lucide-react v0.577.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -8,9 +8,9 @@ import{c as gt,r,j as e,S as Kt,V as Bt,W as Ke,X as Be,b7 as ft,b8 as vt,b9 as
|
|
|
8
8
|
*
|
|
9
9
|
* This source code is licensed under the ISC license.
|
|
10
10
|
* See the LICENSE file in the root directory of this source tree.
|
|
11
|
-
*/const Ns=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 6v6h4",key:"135r8i"}]],ws=gt("clock-3",Ns),ks=6,xt=46;function _s(s,m){const g=m?`${s} · ${m}`:s,b=g.length>xt?`${g.slice(0,xt-1).trimEnd()}…`:g;return{full:g,short:b,width:b.length*ks+8}}const tt=s=>s==="succeeded"?"default":s==="failed"||s==="cancelled"?"destructive":s==="queued"?"outline":"secondary",Ss=.85,Cs=6;function ht(s){return`${.75+Math.min(s,Cs)*Ss}rem`}const Ae=s=>qe(s)?"queued":s.status,Mt="Created — waiting for a runner to claim it",Es=s=>s==="read"?e.jsx(us,{className:"h-3.5 w-3.5"}):s==="branch"?e.jsx(Pt,{className:"h-3.5 w-3.5"}):s==="write"?e.jsx(ms,{className:"h-3.5 w-3.5"}):s==="notify"?e.jsx(ys,{className:"h-3.5 w-3.5"}):e.jsx("span",{className:"h-3.5 w-3.5"}),Ee=s=>ls(s)||s;function Ts({nestId:s,nestName:m,onBack:g}){const[b,C]=r.useState("canvas");return e.jsxs("div",{children:[e.jsx(fs,{nestName:m,onBack:g}),e.jsxs(Kt,{value:b,onValueChange:C,children:[e.jsxs(Bt,{children:[e.jsx(Ke,{value:"canvas",children:"Canvas"}),e.jsx(Ke,{value:"table",children:"Table"}),e.jsx(Ke,{value:"run",children:"Run"}),e.jsx(Ke,{value:"activity",children:"Activity"})]}),e.jsx(Be,{value:"canvas",className:"mt-4",children:e.jsx(Fs,{nestId:s})}),e.jsx(Be,{value:"table",className:"mt-4",children:e.jsx(As,{nestId:s})}),e.jsx(Be,{value:"run",className:"mt-4",children:e.jsx(Os,{nestId:s})}),e.jsxs(Be,{value:"activity",className:"mt-4 space-y-6",children:[e.jsx(Vs,{nestId:s}),e.jsx(Ds,{nestId:s}),e.jsx(Bs,{nestId:s}),e.jsx(Hs,{nestId:s})]})]})]})}function Ce({type:s}){return s==="agent"?e.jsx(as,{className:"h-3.5 w-3.5 text-violet-500 shrink-0"}):s==="skill"?e.jsx(Pt,{className:"h-3.5 w-3.5 text-blue-500 shrink-0"}):s==="artifact"?e.jsx(gs,{className:"h-3.5 w-3.5 text-amber-500 shrink-0"}):s==="tool"?e.jsx($t,{className:"h-3.5 w-3.5 text-teal-500 shrink-0"}):s==="table"?e.jsx(hs,{className:"h-3.5 w-3.5 text-cyan-500 shrink-0"}):s==="pdf"?e.jsx(vs,{className:"h-3.5 w-3.5 text-rose-500 shrink-0"}):e.jsx(rs,{className:"h-3.5 w-3.5 text-slate-400 shrink-0"})}function $s({edge:s}){if(!s.condition_mode||!s.condition)return e.jsx("span",{className:"rounded-full bg-muted px-2 py-0.5 text-[10px] text-muted-foreground",children:"always"});if(s.condition_mode==="nl")return e.jsxs("span",{className:"rounded-full bg-amber-500/10 text-amber-700 dark:text-amber-300 px-2 py-0.5 text-[10px] italic max-w-[260px] truncate inline-block align-middle",title:`AI judges: "${s.condition}"`,children:["if “",String(s.condition),"”"]});let m="";try{const g=typeof s.condition=="string"?JSON.parse(s.condition):s.condition;m=g&&g.term?`${g.term} ${g.op??""} ${g.value??""}`:JSON.stringify(g)}catch{m=String(s.condition)}return e.jsx("span",{className:"rounded-full bg-blue-500/10 text-blue-700 dark:text-blue-300 px-2 py-0.5 text-[10px] font-mono max-w-[260px] truncate inline-block align-middle",title:`Deterministic check: ${m}`,children:m})}function As({nestId:s}){var ke;const[m,g]=r.useState([]),[b,C]=r.useState([]),[y,j]=r.useState(!0),[k,d]=r.useState(null),[h,E]=r.useState([]),[N,w]=r.useState(""),[x,O]=r.useState(""),[c,L]=r.useState(""),[T,B]=r.useState(""),[D,q]=r.useState(""),[Y,X]=r.useState(""),[i,$]=r.useState(">"),[W,he]=r.useState(""),[ne,de]=r.useState(!1),[be,pe]=r.useState(!1),U=r.useCallback(async()=>{var n;j(!0);try{const[v,P,z]=await Promise.all([ft(s),vt(s),Xe(s).then(R=>R.nodes).catch(()=>[])]);g(v),C(P),E(z),!c&&P.length&&L(((n=P.find(R=>R.is_flow))==null?void 0:n.name)??P[0].name),d(null)}catch(v){d(v instanceof Error?v.message:"Failed to load edges")}finally{j(!1)}},[s,c]);r.useEffect(()=>{U()},[U]);const le=async()=>{if(!N.trim()||!x.trim()||!c)return;const n=m.find(v=>v.from_node===N.trim()&&v.to_node===x.trim()&&v.type.name===c);if(n){d(`${H(n.from_node)} → ${H(n.to_node)} is already connected with "${c}".`);return}de(!0);try{const v=T==="structured"?{term:Y.trim(),op:i,value:isNaN(Number(W))?W.trim():Number(W)}:T==="nl"?D.trim():null;await kt(s,{from_node:N.trim(),to_node:x.trim(),type:c,condition_mode:T||null,condition:T?v:null}),O(""),q(""),X(""),he(""),B(""),await U()}catch(v){d(v instanceof Error?v.message:"Failed to add edge")}finally{de(!1)}},ye=n=>{w(n),pe(!0)},Ne=async n=>{try{await _t(s,n),g(v=>v.filter(P=>P.id!==n))}catch(v){d(v instanceof Error?v.message:"Failed to delete edge")}},we=new Map(h.map(n=>[n.id,n])),H=n=>{var v;return((v=we.get(n))==null?void 0:v.title)||n.replace(/^nodes\//,"")},ae=n=>{var v;return(v=we.get(n))==null?void 0:v.type},re=m.filter(n=>n.type.is_flow),G=m.filter(n=>!n.type.is_flow),Te=(ke=b.find(n=>n.is_flow))==null?void 0:ke.name,Z=new Map;for(const n of re)Z.has(n.from_node)||Z.set(n.from_node,[]),Z.get(n.from_node).push(n);const $e=new Set(re.map(n=>n.to_node)),Q=[...Z.keys()].filter(n=>!$e.has(n)).sort(),I=[...h].sort((n,v)=>{const P=z=>z.type==="agent"?0:z.type==="skill"?1:2;return P(n)-P(v)||String(n.title||n.id).localeCompare(String(v.title||v.id))}),ue=(n,v,P)=>{const z=[];for(const R of Z.get(n)??[])z.push(e.jsxs("div",{className:"flex items-center gap-2 py-1 rounded px-1 -mx-1 hover:bg-muted/40 group",style:{marginLeft:`${v*1.5}rem`},children:[e.jsx(nt,{className:"h-3.5 w-3.5 text-muted-foreground/50 shrink-0"}),e.jsx($s,{edge:R}),e.jsx(Ye,{className:"h-3 w-3 text-muted-foreground/50 shrink-0"}),e.jsx(Ce,{type:ae(R.to_node)}),e.jsx("span",{className:"text-sm truncate",title:R.to_node,children:H(R.to_node)}),R.type.name!==Te&&e.jsxs("span",{className:"text-[10px] text-muted-foreground shrink-0",children:["(",R.type.name,")"]}),e.jsx("div",{className:"flex-1"}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6 opacity-0 group-hover:opacity-100 text-muted-foreground",onClick:()=>ye(R.to_node),title:"Add a step after this document",children:e.jsx(oe,{className:"h-3.5 w-3.5"})}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6 opacity-0 group-hover:opacity-100 text-muted-foreground hover:text-destructive",onClick:()=>void Ne(R.id),title:"Remove this step",children:e.jsx(ze,{className:"h-3.5 w-3.5"})})]},R.id)),P.has(R.to_node)||(P.add(R.to_node),z.push(...ue(R.to_node,v+1,P)));return z},ie=e.jsxs("div",{className:"rounded-lg border bg-muted/20 p-3",id:"wf-composer",children:[e.jsx("div",{className:"text-xs font-medium mb-2",children:"Connect two documents"}),e.jsxs("div",{className:"flex items-center flex-wrap gap-2",children:[e.jsxs("select",{value:N,onChange:n=>w(n.target.value),className:"h-8 rounded-md border bg-background px-2 text-sm max-w-[220px]","data-testid":"wf-compose-from",children:[e.jsx("option",{value:"",children:"When this runs…"}),I.map(n=>e.jsxs("option",{value:n.id,children:[n.type==="agent"?"🤖 ":n.type==="skill"?"⚡ ":"",n.title||n.id]},n.id))]}),e.jsx(Ye,{className:"h-4 w-4 text-muted-foreground shrink-0"}),e.jsx("div",{className:"flex items-center rounded-md border h-8 text-xs overflow-hidden",children:[["","always"],["nl","if…"],["structured","metric"]].map(([n,v],P)=>e.jsx("button",{type:"button",className:`px-2.5 h-full ${P>0?"border-l":""} ${T===n?"bg-primary text-primary-foreground":"hover:bg-muted"}`,onClick:()=>B(n),children:v},n))}),T==="nl"&&e.jsx(te,{value:D,onChange:n=>q(n.target.value),placeholder:'e.g. "lost on price, not product"',className:"h-8 text-sm italic w-60",title:"An AI judges this plain-English rule against the run's context"}),T==="structured"&&e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(te,{value:Y,onChange:n=>X(n.target.value),placeholder:"CAC",className:"h-8 text-sm w-24 font-mono",title:"A term from your governed definitions"}),e.jsx("select",{value:i,onChange:n=>$(n.target.value),className:"h-8 rounded-md border bg-background px-1.5 text-sm font-mono",children:[">","<",">=","<=","=","!="].map(n=>e.jsx("option",{value:n,children:n},n))}),e.jsx(te,{value:W,onChange:n=>he(n.target.value),placeholder:"500",className:"h-8 text-sm w-20 font-mono"})]}),e.jsx(Ye,{className:"h-4 w-4 text-muted-foreground shrink-0"}),e.jsxs("select",{value:x,onChange:n=>O(n.target.value),className:"h-8 rounded-md border bg-background px-2 text-sm max-w-[220px]","data-testid":"wf-compose-to",children:[e.jsx("option",{value:"",children:"…continue to"}),I.map(n=>e.jsxs("option",{value:n.id,children:[n.type==="agent"?"🤖 ":n.type==="skill"?"⚡ ":"",n.title||n.id]},n.id))]}),e.jsxs(S,{size:"sm",className:"h-8",disabled:ne||!N||!x||T==="nl"&&!D.trim()||T==="structured"&&!Y.trim(),onClick:()=>void le(),children:[ne?e.jsx(J,{className:"h-3.5 w-3.5 animate-spin"}):e.jsx(oe,{className:"h-3.5 w-3.5 mr-1"}),"Add step"]}),e.jsx("select",{value:c,onChange:n=>L(n.target.value),className:"h-8 rounded-md border bg-background px-1.5 text-xs text-muted-foreground ml-auto",title:"Edge type — flow types (▶) are walked by the runner; others are reference links",children:b.map(n=>e.jsxs("option",{value:n.name,children:[n.is_flow?"▶ ":"",n.name]},n.id))})]})]});return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"Each card is a flow the runner can walk, starting from its top node."}),e.jsx("div",{className:"flex-1"}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>void U(),children:[e.jsx(st,{className:"h-3.5 w-3.5 mr-1"})," Refresh"]})]}),k&&e.jsx("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive whitespace-pre-line",children:k}),y?e.jsx("div",{className:"py-8 text-center text-muted-foreground",children:e.jsx(J,{className:"h-4 w-4 animate-spin inline"})}):Q.length===0?e.jsxs("div",{className:"rounded-lg border border-dashed p-6 text-center",children:[e.jsx("p",{className:"text-sm font-medium mb-1",children:"No flows yet"}),e.jsxs("p",{className:"text-xs text-muted-foreground max-w-md mx-auto",children:["A flow is a chain of steps: an ",e.jsx("b",{children:"agent"})," runs, and each connection says what happens next — always, when an AI judges a rule true, or when a metric crosses a threshold. Connect your first two documents below."]})]}):Q.map(n=>e.jsxs("div",{className:"rounded-lg border p-3",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(Ce,{type:ae(n)}),e.jsx("span",{className:"font-medium text-sm truncate",title:n,children:H(n)}),e.jsx(se,{variant:"secondary",className:"text-[10px]",children:ae(n)==="agent"?"agent · start":"start"}),e.jsx("div",{className:"flex-1"}),e.jsxs(S,{variant:"ghost",size:"sm",className:"h-7 text-xs text-muted-foreground",onClick:()=>ye(n),children:[e.jsx(oe,{className:"h-3.5 w-3.5 mr-1"})," Step"]})]}),ue(n,0,new Set([n]))]},n)),be||Q.length===0||G.length+re.length===0?ie:e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>pe(!0),children:[e.jsx(oe,{className:"h-3.5 w-3.5 mr-1"})," Connect documents"]}),G.length>0&&e.jsxs("details",{className:"rounded-lg border px-3 py-2",children:[e.jsxs("summary",{className:"cursor-pointer text-xs font-medium text-muted-foreground select-none",children:["Reference links (",G.length,") — ontology edges the runner doesn't walk"]}),e.jsx("div",{className:"mt-2 space-y-1",children:G.map(n=>e.jsxs("div",{className:"flex items-center gap-2 text-sm group",children:[e.jsx(Ce,{type:ae(n.from_node)}),e.jsx("span",{className:"truncate",title:n.from_node,children:H(n.from_node)}),e.jsx("span",{className:"rounded-full px-2 py-0.5 text-[10px] text-muted-foreground border",style:{borderColor:n.type.color??void 0},children:n.type.name}),e.jsx(Ce,{type:ae(n.to_node)}),e.jsx("span",{className:"truncate",title:n.to_node,children:H(n.to_node)}),e.jsx("div",{className:"flex-1"}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6 opacity-0 group-hover:opacity-100 text-muted-foreground hover:text-destructive",onClick:()=>void Ne(n.id),title:"Delete link",children:e.jsx(ze,{className:"h-3.5 w-3.5"})})]},n.id))})]}),e.jsxs("p",{className:"text-[11px] text-muted-foreground",children:[e.jsx("b",{children:"always"})," = the step fires whenever the previous one runs ·"," ",e.jsx("b",{children:"if…"})," = an AI judges a plain-English rule against the run's context · ",e.jsx("b",{children:"metric"})," = a deterministic check like"," ",e.jsx("code",{children:"CAC > 500"}),", resolved from your governed terms."]})]})}const Ps=8,Rs=16;function pt({value:s,onValueChange:m,runnables:g,placeholder:b,testId:C,disabledReason:y}){return e.jsxs(St,{value:s||void 0,onValueChange:m,children:[e.jsx(Ct,{className:"h-9 w-full","data-testid":C,disabled:!g.length,children:e.jsx(Et,{placeholder:g.length?b:"No runnable agents yet"})}),e.jsx(Tt,{children:g.map(j=>{const k=(y==null?void 0:y(j.id))??null;return e.jsx(et,{value:j.id,disabled:!!k,children:e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx(We,{type:j.type,className:"h-3.5 w-3.5"}),j.title||j.id,k&&e.jsxs("span",{className:"text-[10px] text-muted-foreground",children:["— ",k]})]})},j.id)})})]})}function Ms({value:s,onValueChange:m,runs:g,runLabel:b,runType:C,blockedReason:y}){const j="__none__",k=g.filter(d=>d.status==="running");return e.jsxs(St,{value:s||j,onValueChange:d=>m(d===j?"":d),children:[e.jsx(Ct,{className:"h-auto min-h-9 w-full","data-testid":"run-parent-lookup",children:e.jsx(Et,{})}),e.jsxs(Tt,{children:[e.jsx(et,{value:j,children:"— None (top-level run)"}),k.map(d=>{const h=y(d),E=d.depth??0;return e.jsx(et,{value:d.id,disabled:!!h,children:e.jsxs("span",{className:"flex flex-col gap-0.5 py-0.5",children:[e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx(We,{type:C(d.agent_node),className:"h-3.5 w-3.5"}),e.jsx("span",{className:"font-medium",children:b(d.agent_node)}),e.jsx("span",{className:"font-mono text-[11px] text-muted-foreground",children:d.id.replace(/^run_/,"").slice(0,8)}),h&&e.jsx(se,{variant:"outline",className:"text-[10px]",children:h})]}),e.jsxs("span",{className:"text-[11px] text-muted-foreground",children:["depth ",E," → ",E+1," · ",Ee(d.started_at)]})]})},d.id)})]})]})}function Os({nestId:s}){const{subagentRunsEnabled:m,subagentMaxDepth:g,subagentMaxChildren:b}=Yt(),C=g||Ps,y=b||Rs,[j,k]=r.useState([]),[d,h]=r.useState(null),[E,N]=r.useState(!0),[w,x]=r.useState(null),[O,c]=r.useState(""),[L,T]=r.useState(!1),[B,D]=r.useState(""),[q,Y]=r.useState(""),[X,i]=r.useState(""),[$,W]=r.useState(""),[he,ne]=r.useState(""),[de,be]=r.useState(!1),[pe,U]=r.useState(null),[le,ye]=r.useState(null),[Ne,we]=r.useState([]),H=r.useCallback(async()=>{N(!0);try{const[a,p]=await Promise.all([Zt(s,void 0,500),Xe(s).then(F=>F.nodes).catch(()=>[])]);k(a),we(p),x(null)}catch(a){x(a instanceof Error?a.message:"Failed to load runs")}finally{N(!1)}},[s]),ae=Ne.filter(a=>a.type==="agent"||a.type==="skill");r.useEffect(()=>{H()},[H]);const re=async a=>{try{h(await ds(a))}catch(p){x(p instanceof Error?p.message:"Failed to load run")}},G=async a=>{ye(a);try{await cs(a),await H(),(d==null?void 0:d.id)===a&&await re(a)}catch(p){x(p instanceof Error?p.message:"Failed to cancel run")}finally{ye(null)}},Te=a=>{const p=a.trim();if(p)try{const F=JSON.parse(p);return typeof F=="object"&&F!==null?F:{input:F}}catch{return{input:p}}},Z=async()=>{if(O.trim()){T(!0);try{await Qe(s,O.trim(),Te(B),q||void 0),c(""),D(""),Y(""),await H()}catch(a){x(a instanceof Error?a.message:"Failed to trigger run")}finally{T(!1)}}},$e=async a=>{if($.trim()){be(!0),U(null);try{await Qe(s,$.trim(),Te(he),a),i(""),W(""),ne(""),await H()}catch(p){U(p instanceof Error?p.message:"Failed to spawn sub-agent")}finally{be(!1)}}},Q=new Map(Ne.map(a=>[a.id,a])),I=a=>{var p;return((p=Q.get(a))==null?void 0:p.title)||a.replace(/^nodes\//,"")},ue=a=>{var p;return(p=Q.get(a))==null?void 0:p.type},ie=new Map,ke=new Set(j.map(a=>a.id)),n=[];for(const a of j)a.parent_run_id&&ke.has(a.parent_run_id)?(ie.has(a.parent_run_id)||ie.set(a.parent_run_id,[]),ie.get(a.parent_run_id).push(a)):n.push(a);const v=new Map(j.map(a=>[a.id,a])),P=a=>{var p;return((p=ie.get(a))==null?void 0:p.length)??0},z=a=>{const p=new Set;let F=a;for(let me=0;F&&me<=C+1;me++){const fe=v.get(F);if(!fe)break;p.add(fe.agent_node),F=fe.parent_run_id??null}return p},R=(a,p)=>(a.depth??0)>=C?"at max depth":P(a.id)>=y?`${y}/${y} full`:p&&z(a.id).has(p)?"would loop":null,Fe=q?v.get(q)??null:null,ge=Fe?R(Fe,O):null,Pe=(a,p)=>{var fe;const F=ie.get(a.id)??[],me=p?ht(p):void 0;return e.jsxs("div",{children:[e.jsxs("div",{role:"button",tabIndex:0,onClick:()=>void re(a.id),onKeyDown:V=>{(V.key==="Enter"||V.key===" ")&&re(a.id)},className:`group w-full overflow-hidden cursor-pointer px-3 py-2 hover:bg-muted/40 ${(d==null?void 0:d.id)===a.id?"bg-muted/60":""}`,style:{paddingLeft:me},children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[p>0&&e.jsx(nt,{className:"h-3 w-3 text-muted-foreground/50 shrink-0","aria-label":`Sub-agent at depth ${a.depth??p}`,children:e.jsx("title",{children:`Sub-agent at depth ${a.depth??p}`})}),e.jsx(We,{type:ue(a.agent_node),className:"h-3.5 w-3.5"}),e.jsx("span",{className:"font-mono text-xs truncate min-w-[6rem]",title:a.id,children:a.id.length>12?`${a.id.slice(0,12)}…`:a.id}),e.jsx(se,{variant:tt(Ae(a)),className:"text-[10px]",title:qe(a)?Mt:void 0,children:Ae(a)}),a.status==="running"&&(()=>{const V=[];return m&&(a.depth??0)<C&&P(a.id)<y&&V.push({label:X===a.id?"Close sub-agent form":"Spawn sub-agent",icon:oe,testId:"run-action-spawn",onSelect:()=>{i(X===a.id?"":a.id),W(""),ne(""),U(null)}}),V.push({label:le===a.id?"Cancelling…":"Cancel run",icon:le===a.id?J:Rt,iconClassName:le===a.id?"animate-spin":void 0,destructive:!0,disabled:le===a.id,separatorBefore:!0,testId:"run-action-cancel",onSelect:()=>void G(a.id)}),e.jsx("div",{className:"ml-auto shrink-0",children:e.jsx(ps,{actions:V,className:"h-6 w-6 text-muted-foreground",triggerTitle:"Run actions",testId:"run-actions"})})})()]}),e.jsxs("div",{className:"text-[11px] text-muted-foreground truncate",children:[I(a.agent_node)," · ",Ee(a.started_at),F.length>0&&` · ${F.length} child${F.length===1?"":"ren"}`]}),a.status==="failed"&&((fe=a.trace)==null?void 0:fe.error)&&e.jsx("div",{className:"text-[11px] text-destructive truncate mt-0.5",title:String(a.trace.error),children:String(a.trace.error).replace(/^\d+ /,"").slice(0,110)})]}),m&&X===a.id&&e.jsxs("div",{className:"border-t bg-muted/20 px-3 py-2.5 space-y-2",style:{paddingLeft:ht(p+1)},children:[e.jsxs("div",{className:"text-[11px] font-medium text-muted-foreground",children:["New sub-agent under"," ",e.jsx("span",{className:"font-mono",children:a.id.slice(0,12)})," —"," ",I(a.agent_node)," · depth ",a.depth??p," → child depth"," ",(a.depth??p)+1]}),e.jsx(pt,{value:$,onValueChange:W,runnables:ae,placeholder:"Choose an agent…",testId:"spawn-agent-lookup",disabledReason:V=>z(a.id).has(V)?"already in this chain":null}),e.jsx("textarea",{value:he,onChange:V=>ne(V.target.value),placeholder:"Inputs (optional) — plain text or JSON",className:"w-full rounded-md border bg-background px-2 py-1.5 text-xs font-mono min-h-[44px]"}),pe&&e.jsx("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-2.5 py-1.5 text-[11px] text-destructive",children:pe}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(S,{size:"sm",className:"h-7",disabled:de||!$.trim(),onClick:()=>void $e(a.id),children:[de?e.jsx(J,{className:"h-3.5 w-3.5 mr-1 animate-spin"}):e.jsx(oe,{className:"h-3.5 w-3.5 mr-1"}),"Create sub-agent"]}),e.jsx(S,{variant:"ghost",size:"sm",className:"h-7",onClick:()=>{i(""),U(null)},children:"Cancel"})]})]}),F.map(V=>Pe(V,p+1))]},a.id)};return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-sm font-semibold",children:"Trigger a run"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Creates a run record + bundle (inputs ride along). The server never executes — a runner (the contextnest-runner) walks the bundle and posts each step back into the trace below."})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[11px] font-medium text-muted-foreground mb-1",children:"Agent / skill node"}),e.jsx(pt,{value:O,onValueChange:c,runnables:ae,placeholder:"Choose an agent to run…",testId:"run-agent-lookup"})]}),m&&e.jsxs("div",{children:[e.jsx("label",{className:"block text-[11px] font-medium text-muted-foreground mb-1",children:"Parent run (optional — spawn as a sub-agent)"}),e.jsx(Ms,{value:q,onValueChange:Y,runs:j,runLabel:I,runType:ue,blockedReason:a=>R(a,O)}),ge&&e.jsxs("p",{className:"text-[11px] text-destructive mt-1",children:["This parent can't be used (",ge,") — pick another or change the agent."]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[11px] font-medium text-muted-foreground mb-1",children:"Inputs (optional — plain text or JSON)"}),e.jsx("textarea",{value:B,onChange:a=>D(a.target.value),placeholder:'e.g. {"account":"Foley"}',className:"w-full rounded-md border bg-background px-2 py-1.5 text-xs font-mono min-h-[64px]"})]}),w&&e.jsx("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:w}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(S,{disabled:L||!O.trim()||!!ge,onClick:()=>void Z(),title:"Create a run (a runner executes it)",children:[L?e.jsx(J,{className:"h-3.5 w-3.5 mr-1.5 animate-spin"}):e.jsx(At,{className:"h-3.5 w-3.5 mr-1.5"}),"Create run"]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>void H(),children:[e.jsx(st,{className:"h-3.5 w-3.5 mr-1"})," Refresh"]})]}),e.jsxs("details",{className:"rounded-md border bg-muted/30 px-3 py-2 text-[11px]",children:[e.jsx("summary",{className:"cursor-pointer font-medium",children:"How do I run one? (the runner is a separate process)"}),e.jsxs("div",{className:"mt-2 space-y-1.5 text-muted-foreground",children:[e.jsxs("p",{children:["The ",e.jsx("b",{children:"trigger"})," button just records a run. The"," ",e.jsx("b",{children:"runner"})," is a small stateless container that actually walks it and calls the LLM. Point it at this nest:"]}),e.jsx("pre",{className:"overflow-x-auto rounded bg-background border p-2 font-mono text-[10.5px] leading-relaxed",children:`docker run -d --name cn-runner --network host \\
|
|
11
|
+
*/const Ns=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 6v6h4",key:"135r8i"}]],ws=gt("clock-3",Ns),ks=6,xt=46;function _s(s,m){const g=m?`${s} · ${m}`:s,b=g.length>xt?`${g.slice(0,xt-1).trimEnd()}…`:g;return{full:g,short:b,width:b.length*ks+8}}const tt=s=>s==="succeeded"?"default":s==="failed"||s==="cancelled"?"destructive":s==="queued"?"outline":"secondary",Ss=.85,Cs=6;function ht(s){return`${.75+Math.min(s,Cs)*Ss}rem`}const Ae=s=>qe(s)?"queued":s.status,Mt="Created — waiting for a runner to claim it",Es=s=>s==="read"?e.jsx(us,{className:"h-3.5 w-3.5"}):s==="branch"?e.jsx(Rt,{className:"h-3.5 w-3.5"}):s==="write"?e.jsx(ms,{className:"h-3.5 w-3.5"}):s==="notify"?e.jsx(ys,{className:"h-3.5 w-3.5"}):e.jsx("span",{className:"h-3.5 w-3.5"}),Ee=s=>ls(s)||s;function Ts({nestId:s,nestName:m,onBack:g}){const[b,C]=r.useState("canvas");return e.jsxs("div",{children:[e.jsx(fs,{nestName:m,onBack:g}),e.jsxs(Bt,{value:b,onValueChange:C,children:[e.jsxs(Kt,{children:[e.jsx(Be,{value:"canvas",children:"Canvas"}),e.jsx(Be,{value:"table",children:"Table"}),e.jsx(Be,{value:"run",children:"Run"}),e.jsx(Be,{value:"activity",children:"Activity"})]}),e.jsx(Ke,{value:"canvas",className:"mt-4",children:e.jsx(Fs,{nestId:s})}),e.jsx(Ke,{value:"table",className:"mt-4",children:e.jsx(As,{nestId:s})}),e.jsx(Ke,{value:"run",className:"mt-4",children:e.jsx(Os,{nestId:s})}),e.jsxs(Ke,{value:"activity",className:"mt-4 space-y-6",children:[e.jsx(Vs,{nestId:s}),e.jsx(Ds,{nestId:s}),e.jsx(Ks,{nestId:s}),e.jsx(Hs,{nestId:s})]})]})]})}function Ce({type:s}){return s==="agent"?e.jsx(as,{className:"h-3.5 w-3.5 text-violet-500 shrink-0"}):s==="skill"?e.jsx(Rt,{className:"h-3.5 w-3.5 text-blue-500 shrink-0"}):s==="artifact"?e.jsx(gs,{className:"h-3.5 w-3.5 text-amber-500 shrink-0"}):s==="tool"?e.jsx(At,{className:"h-3.5 w-3.5 text-teal-500 shrink-0"}):s==="table"?e.jsx(hs,{className:"h-3.5 w-3.5 text-cyan-500 shrink-0"}):s==="pdf"?e.jsx(vs,{className:"h-3.5 w-3.5 text-rose-500 shrink-0"}):e.jsx(rs,{className:"h-3.5 w-3.5 text-slate-400 shrink-0"})}function $s({edge:s}){if(!s.condition_mode||!s.condition)return e.jsx("span",{className:"rounded-full bg-muted px-2 py-0.5 text-[10px] text-muted-foreground",children:"always"});if(s.condition_mode==="nl")return e.jsxs("span",{className:"rounded-full bg-amber-500/10 text-amber-700 dark:text-amber-300 px-2 py-0.5 text-[10px] italic max-w-[260px] truncate inline-block align-middle",title:`AI judges: "${s.condition}"`,children:["if “",String(s.condition),"”"]});let m="";try{const g=typeof s.condition=="string"?JSON.parse(s.condition):s.condition;m=g&&g.term?`${g.term} ${g.op??""} ${g.value??""}`:JSON.stringify(g)}catch{m=String(s.condition)}return e.jsx("span",{className:"rounded-full bg-blue-500/10 text-blue-700 dark:text-blue-300 px-2 py-0.5 text-[10px] font-mono max-w-[260px] truncate inline-block align-middle",title:`Deterministic check: ${m}`,children:m})}function As({nestId:s}){var ke;const[m,g]=r.useState([]),[b,C]=r.useState([]),[y,j]=r.useState(!0),[k,d]=r.useState(null),[h,E]=r.useState([]),[N,w]=r.useState(""),[x,O]=r.useState(""),[c,L]=r.useState(""),[T,K]=r.useState(""),[D,q]=r.useState(""),[Y,U]=r.useState(""),[i,$]=r.useState(">"),[W,he]=r.useState(""),[ne,de]=r.useState(!1),[be,pe]=r.useState(!1),X=r.useCallback(async()=>{var n;j(!0);try{const[v,P,z]=await Promise.all([ft(s),vt(s),Ue(s).then(R=>R.nodes).catch(()=>[])]);g(v),C(P),E(z),!c&&P.length&&L(((n=P.find(R=>R.is_flow))==null?void 0:n.name)??P[0].name),d(null)}catch(v){d(v instanceof Error?v.message:"Failed to load edges")}finally{j(!1)}},[s,c]);r.useEffect(()=>{X()},[X]);const le=async()=>{if(!N.trim()||!x.trim()||!c)return;const n=m.find(v=>v.from_node===N.trim()&&v.to_node===x.trim()&&v.type.name===c);if(n){d(`${H(n.from_node)} → ${H(n.to_node)} is already connected with "${c}".`);return}de(!0);try{const v=T==="structured"?{term:Y.trim(),op:i,value:isNaN(Number(W))?W.trim():Number(W)}:T==="nl"?D.trim():null;await kt(s,{from_node:N.trim(),to_node:x.trim(),type:c,condition_mode:T||null,condition:T?v:null}),O(""),q(""),U(""),he(""),K(""),await X()}catch(v){d(v instanceof Error?v.message:"Failed to add edge")}finally{de(!1)}},ye=n=>{w(n),pe(!0)},Ne=async n=>{try{await _t(s,n),g(v=>v.filter(P=>P.id!==n))}catch(v){d(v instanceof Error?v.message:"Failed to delete edge")}},we=new Map(h.map(n=>[n.id,n])),H=n=>{var v;return((v=we.get(n))==null?void 0:v.title)||n.replace(/^nodes\//,"")},ae=n=>{var v;return(v=we.get(n))==null?void 0:v.type},re=m.filter(n=>n.type.is_flow),G=m.filter(n=>!n.type.is_flow),Te=(ke=b.find(n=>n.is_flow))==null?void 0:ke.name,Z=new Map;for(const n of re)Z.has(n.from_node)||Z.set(n.from_node,[]),Z.get(n.from_node).push(n);const $e=new Set(re.map(n=>n.to_node)),Q=[...Z.keys()].filter(n=>!$e.has(n)).sort(),I=[...h].sort((n,v)=>{const P=z=>z.type==="agent"?0:z.type==="skill"?1:2;return P(n)-P(v)||String(n.title||n.id).localeCompare(String(v.title||v.id))}),ue=(n,v,P)=>{const z=[];for(const R of Z.get(n)??[])z.push(e.jsxs("div",{className:"flex items-center gap-2 py-1 rounded px-1 -mx-1 hover:bg-muted/40 group",style:{marginLeft:`${v*1.5}rem`},children:[e.jsx(nt,{className:"h-3.5 w-3.5 text-muted-foreground/50 shrink-0"}),e.jsx($s,{edge:R}),e.jsx(Ye,{className:"h-3 w-3 text-muted-foreground/50 shrink-0"}),e.jsx(Ce,{type:ae(R.to_node)}),e.jsx("span",{className:"text-sm truncate",title:R.to_node,children:H(R.to_node)}),R.type.name!==Te&&e.jsxs("span",{className:"text-[10px] text-muted-foreground shrink-0",children:["(",R.type.name,")"]}),e.jsx("div",{className:"flex-1"}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6 opacity-0 group-hover:opacity-100 text-muted-foreground",onClick:()=>ye(R.to_node),title:"Add a step after this document",children:e.jsx(oe,{className:"h-3.5 w-3.5"})}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6 opacity-0 group-hover:opacity-100 text-muted-foreground hover:text-destructive",onClick:()=>void Ne(R.id),title:"Remove this step",children:e.jsx(ze,{className:"h-3.5 w-3.5"})})]},R.id)),P.has(R.to_node)||(P.add(R.to_node),z.push(...ue(R.to_node,v+1,P)));return z},ie=e.jsxs("div",{className:"rounded-lg border bg-muted/20 p-3",id:"wf-composer",children:[e.jsx("div",{className:"text-xs font-medium mb-2",children:"Connect two documents"}),e.jsxs("div",{className:"flex items-center flex-wrap gap-2",children:[e.jsxs("select",{value:N,onChange:n=>w(n.target.value),className:"h-8 rounded-md border bg-background px-2 text-sm max-w-[220px]","data-testid":"wf-compose-from",children:[e.jsx("option",{value:"",children:"When this runs…"}),I.map(n=>e.jsxs("option",{value:n.id,children:[n.type==="agent"?"🤖 ":n.type==="skill"?"⚡ ":"",n.title||n.id]},n.id))]}),e.jsx(Ye,{className:"h-4 w-4 text-muted-foreground shrink-0"}),e.jsx("div",{className:"flex items-center rounded-md border h-8 text-xs overflow-hidden",children:[["","always"],["nl","if…"],["structured","metric"]].map(([n,v],P)=>e.jsx("button",{type:"button",className:`px-2.5 h-full ${P>0?"border-l":""} ${T===n?"bg-primary text-primary-foreground":"hover:bg-muted"}`,onClick:()=>K(n),children:v},n))}),T==="nl"&&e.jsx(te,{value:D,onChange:n=>q(n.target.value),placeholder:'e.g. "lost on price, not product"',className:"h-8 text-sm italic w-60",title:"An AI judges this plain-English rule against the run's context"}),T==="structured"&&e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(te,{value:Y,onChange:n=>U(n.target.value),placeholder:"CAC",className:"h-8 text-sm w-24 font-mono",title:"A term from your governed definitions"}),e.jsx("select",{value:i,onChange:n=>$(n.target.value),className:"h-8 rounded-md border bg-background px-1.5 text-sm font-mono",children:[">","<",">=","<=","=","!="].map(n=>e.jsx("option",{value:n,children:n},n))}),e.jsx(te,{value:W,onChange:n=>he(n.target.value),placeholder:"500",className:"h-8 text-sm w-20 font-mono"})]}),e.jsx(Ye,{className:"h-4 w-4 text-muted-foreground shrink-0"}),e.jsxs("select",{value:x,onChange:n=>O(n.target.value),className:"h-8 rounded-md border bg-background px-2 text-sm max-w-[220px]","data-testid":"wf-compose-to",children:[e.jsx("option",{value:"",children:"…continue to"}),I.map(n=>e.jsxs("option",{value:n.id,children:[n.type==="agent"?"🤖 ":n.type==="skill"?"⚡ ":"",n.title||n.id]},n.id))]}),e.jsxs(S,{size:"sm",className:"h-8",disabled:ne||!N||!x||T==="nl"&&!D.trim()||T==="structured"&&!Y.trim(),onClick:()=>void le(),children:[ne?e.jsx(J,{className:"h-3.5 w-3.5 animate-spin"}):e.jsx(oe,{className:"h-3.5 w-3.5 mr-1"}),"Add step"]}),e.jsx("select",{value:c,onChange:n=>L(n.target.value),className:"h-8 rounded-md border bg-background px-1.5 text-xs text-muted-foreground ml-auto",title:"Edge type — flow types (▶) are walked by the runner; others are reference links",children:b.map(n=>e.jsxs("option",{value:n.name,children:[n.is_flow?"▶ ":"",n.name]},n.id))})]})]});return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"Each card is a flow the runner can walk, starting from its top node."}),e.jsx("div",{className:"flex-1"}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>void X(),children:[e.jsx(st,{className:"h-3.5 w-3.5 mr-1"})," Refresh"]})]}),k&&e.jsx("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive whitespace-pre-line",children:k}),y?e.jsx("div",{className:"py-8 text-center text-muted-foreground",children:e.jsx(J,{className:"h-4 w-4 animate-spin inline"})}):Q.length===0?e.jsxs("div",{className:"rounded-lg border border-dashed p-6 text-center",children:[e.jsx("p",{className:"text-sm font-medium mb-1",children:"No flows yet"}),e.jsxs("p",{className:"text-xs text-muted-foreground max-w-md mx-auto",children:["A flow is a chain of steps: an ",e.jsx("b",{children:"agent"})," runs, and each connection says what happens next — always, when an AI judges a rule true, or when a metric crosses a threshold. Connect your first two documents below."]})]}):Q.map(n=>e.jsxs("div",{className:"rounded-lg border p-3",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(Ce,{type:ae(n)}),e.jsx("span",{className:"font-medium text-sm truncate",title:n,children:H(n)}),e.jsx(se,{variant:"secondary",className:"text-[10px]",children:ae(n)==="agent"?"agent · start":"start"}),e.jsx("div",{className:"flex-1"}),e.jsxs(S,{variant:"ghost",size:"sm",className:"h-7 text-xs text-muted-foreground",onClick:()=>ye(n),children:[e.jsx(oe,{className:"h-3.5 w-3.5 mr-1"})," Step"]})]}),ue(n,0,new Set([n]))]},n)),be||Q.length===0||G.length+re.length===0?ie:e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>pe(!0),children:[e.jsx(oe,{className:"h-3.5 w-3.5 mr-1"})," Connect documents"]}),G.length>0&&e.jsxs("details",{className:"rounded-lg border px-3 py-2",children:[e.jsxs("summary",{className:"cursor-pointer text-xs font-medium text-muted-foreground select-none",children:["Reference links (",G.length,") — ontology edges the runner doesn't walk"]}),e.jsx("div",{className:"mt-2 space-y-1",children:G.map(n=>e.jsxs("div",{className:"flex items-center gap-2 text-sm group",children:[e.jsx(Ce,{type:ae(n.from_node)}),e.jsx("span",{className:"truncate",title:n.from_node,children:H(n.from_node)}),e.jsx("span",{className:"rounded-full px-2 py-0.5 text-[10px] text-muted-foreground border",style:{borderColor:n.type.color??void 0},children:n.type.name}),e.jsx(Ce,{type:ae(n.to_node)}),e.jsx("span",{className:"truncate",title:n.to_node,children:H(n.to_node)}),e.jsx("div",{className:"flex-1"}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6 opacity-0 group-hover:opacity-100 text-muted-foreground hover:text-destructive",onClick:()=>void Ne(n.id),title:"Delete link",children:e.jsx(ze,{className:"h-3.5 w-3.5"})})]},n.id))})]}),e.jsxs("p",{className:"text-[11px] text-muted-foreground",children:[e.jsx("b",{children:"always"})," = the step fires whenever the previous one runs ·"," ",e.jsx("b",{children:"if…"})," = an AI judges a plain-English rule against the run's context · ",e.jsx("b",{children:"metric"})," = a deterministic check like"," ",e.jsx("code",{children:"CAC > 500"}),", resolved from your governed terms."]})]})}const Ps=8,Rs=16;function pt({value:s,onValueChange:m,runnables:g,placeholder:b,testId:C,disabledReason:y}){return e.jsxs(St,{value:s||void 0,onValueChange:m,children:[e.jsx(Ct,{className:"h-9 w-full","data-testid":C,disabled:!g.length,children:e.jsx(Et,{placeholder:g.length?b:"No runnable agents yet"})}),e.jsx(Tt,{children:g.map(j=>{const k=(y==null?void 0:y(j.id))??null;return e.jsx(et,{value:j.id,disabled:!!k,children:e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx(We,{type:j.type,className:"h-3.5 w-3.5"}),j.title||j.id,k&&e.jsxs("span",{className:"text-[10px] text-muted-foreground",children:["— ",k]})]})},j.id)})})]})}function Ms({value:s,onValueChange:m,runs:g,runLabel:b,runType:C,blockedReason:y}){const j="__none__",k=g.filter(d=>d.status==="running");return e.jsxs(St,{value:s||j,onValueChange:d=>m(d===j?"":d),children:[e.jsx(Ct,{className:"h-auto min-h-9 w-full","data-testid":"run-parent-lookup",children:e.jsx(Et,{})}),e.jsxs(Tt,{children:[e.jsx(et,{value:j,children:"— None (top-level run)"}),k.map(d=>{const h=y(d),E=d.depth??0;return e.jsx(et,{value:d.id,disabled:!!h,children:e.jsxs("span",{className:"flex flex-col gap-0.5 py-0.5",children:[e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx(We,{type:C(d.agent_node),className:"h-3.5 w-3.5"}),e.jsx("span",{className:"font-medium",children:b(d.agent_node)}),e.jsx("span",{className:"font-mono text-[11px] text-muted-foreground",children:d.id.replace(/^run_/,"").slice(0,8)}),h&&e.jsx(se,{variant:"outline",className:"text-[10px]",children:h})]}),e.jsxs("span",{className:"text-[11px] text-muted-foreground",children:["depth ",E," → ",E+1," · ",Ee(d.started_at)]})]})},d.id)})]})]})}function Os({nestId:s}){const{subagentRunsEnabled:m,subagentMaxDepth:g,subagentMaxChildren:b}=Yt(),C=g||Ps,y=b||Rs,[j,k]=r.useState([]),[d,h]=r.useState(null),[E,N]=r.useState(!0),[w,x]=r.useState(null),[O,c]=r.useState(""),[L,T]=r.useState(!1),[K,D]=r.useState(""),[q,Y]=r.useState(""),[U,i]=r.useState(""),[$,W]=r.useState(""),[he,ne]=r.useState(""),[de,be]=r.useState(!1),[pe,X]=r.useState(null),[le,ye]=r.useState(null),[Ne,we]=r.useState([]),H=r.useCallback(async()=>{N(!0);try{const[a,p]=await Promise.all([Zt(s,void 0,500),Ue(s).then(F=>F.nodes).catch(()=>[])]);k(a),we(p),x(null)}catch(a){x(a instanceof Error?a.message:"Failed to load runs")}finally{N(!1)}},[s]),ae=Ne.filter(a=>a.type==="agent"||a.type==="skill");r.useEffect(()=>{H()},[H]);const re=async a=>{try{h(await ds(a))}catch(p){x(p instanceof Error?p.message:"Failed to load run")}},G=async a=>{ye(a);try{await cs(a),await H(),(d==null?void 0:d.id)===a&&await re(a)}catch(p){x(p instanceof Error?p.message:"Failed to cancel run")}finally{ye(null)}},Te=a=>{const p=a.trim();if(p)try{const F=JSON.parse(p);return typeof F=="object"&&F!==null?F:{input:F}}catch{return{input:p}}},Z=async()=>{if(O.trim()){T(!0);try{await Qe(s,O.trim(),Te(K),q||void 0),c(""),D(""),Y(""),await H()}catch(a){x(a instanceof Error?a.message:"Failed to trigger run")}finally{T(!1)}}},$e=async a=>{if($.trim()){be(!0),X(null);try{await Qe(s,$.trim(),Te(he),a),i(""),W(""),ne(""),await H()}catch(p){X(p instanceof Error?p.message:"Failed to spawn sub-agent")}finally{be(!1)}}},Q=new Map(Ne.map(a=>[a.id,a])),I=a=>{var p;return((p=Q.get(a))==null?void 0:p.title)||a.replace(/^nodes\//,"")},ue=a=>{var p;return(p=Q.get(a))==null?void 0:p.type},ie=new Map,ke=new Set(j.map(a=>a.id)),n=[];for(const a of j)a.parent_run_id&&ke.has(a.parent_run_id)?(ie.has(a.parent_run_id)||ie.set(a.parent_run_id,[]),ie.get(a.parent_run_id).push(a)):n.push(a);const v=new Map(j.map(a=>[a.id,a])),P=a=>{var p;return((p=ie.get(a))==null?void 0:p.length)??0},z=a=>{const p=new Set;let F=a;for(let me=0;F&&me<=C+1;me++){const fe=v.get(F);if(!fe)break;p.add(fe.agent_node),F=fe.parent_run_id??null}return p},R=(a,p)=>(a.depth??0)>=C?"at max depth":P(a.id)>=y?`${y}/${y} full`:p&&z(a.id).has(p)?"would loop":null,Fe=q?v.get(q)??null:null,ge=Fe?R(Fe,O):null,Pe=(a,p)=>{var fe;const F=ie.get(a.id)??[],me=p?ht(p):void 0;return e.jsxs("div",{children:[e.jsxs("div",{role:"button",tabIndex:0,onClick:()=>void re(a.id),onKeyDown:V=>{(V.key==="Enter"||V.key===" ")&&re(a.id)},className:`group w-full overflow-hidden cursor-pointer px-3 py-2 hover:bg-muted/40 ${(d==null?void 0:d.id)===a.id?"bg-muted/60":""}`,style:{paddingLeft:me},children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[p>0&&e.jsx(nt,{className:"h-3 w-3 text-muted-foreground/50 shrink-0","aria-label":`Sub-agent at depth ${a.depth??p}`,children:e.jsx("title",{children:`Sub-agent at depth ${a.depth??p}`})}),e.jsx(We,{type:ue(a.agent_node),className:"h-3.5 w-3.5"}),e.jsx("span",{className:"font-mono text-xs truncate min-w-[6rem]",title:a.id,children:a.id.length>12?`${a.id.slice(0,12)}…`:a.id}),e.jsx(se,{variant:tt(Ae(a)),className:"text-[10px]",title:qe(a)?Mt:void 0,children:Ae(a)}),a.status==="running"&&(()=>{const V=[];return m&&(a.depth??0)<C&&P(a.id)<y&&V.push({label:U===a.id?"Close sub-agent form":"Spawn sub-agent",icon:oe,testId:"run-action-spawn",onSelect:()=>{i(U===a.id?"":a.id),W(""),ne(""),X(null)}}),V.push({label:le===a.id?"Cancelling…":"Cancel run",icon:le===a.id?J:$t,iconClassName:le===a.id?"animate-spin":void 0,destructive:!0,disabled:le===a.id,separatorBefore:!0,testId:"run-action-cancel",onSelect:()=>void G(a.id)}),e.jsx("div",{className:"ml-auto shrink-0",children:e.jsx(ps,{actions:V,className:"h-6 w-6 text-muted-foreground",triggerTitle:"Run actions",testId:"run-actions"})})})()]}),e.jsxs("div",{className:"text-[11px] text-muted-foreground truncate",children:[I(a.agent_node)," · ",Ee(a.started_at),F.length>0&&` · ${F.length} child${F.length===1?"":"ren"}`]}),a.status==="failed"&&((fe=a.trace)==null?void 0:fe.error)&&e.jsx("div",{className:"text-[11px] text-destructive truncate mt-0.5",title:String(a.trace.error),children:String(a.trace.error).replace(/^\d+ /,"").slice(0,110)})]}),m&&U===a.id&&e.jsxs("div",{className:"border-t bg-muted/20 px-3 py-2.5 space-y-2",style:{paddingLeft:ht(p+1)},children:[e.jsxs("div",{className:"text-[11px] font-medium text-muted-foreground",children:["New sub-agent under"," ",e.jsx("span",{className:"font-mono",children:a.id.slice(0,12)})," —"," ",I(a.agent_node)," · depth ",a.depth??p," → child depth"," ",(a.depth??p)+1]}),e.jsx(pt,{value:$,onValueChange:W,runnables:ae,placeholder:"Choose an agent…",testId:"spawn-agent-lookup",disabledReason:V=>z(a.id).has(V)?"already in this chain":null}),e.jsx("textarea",{value:he,onChange:V=>ne(V.target.value),placeholder:"Inputs (optional) — plain text or JSON",className:"w-full rounded-md border bg-background px-2 py-1.5 text-xs font-mono min-h-[44px]"}),pe&&e.jsx("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-2.5 py-1.5 text-[11px] text-destructive",children:pe}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(S,{size:"sm",className:"h-7",disabled:de||!$.trim(),onClick:()=>void $e(a.id),children:[de?e.jsx(J,{className:"h-3.5 w-3.5 mr-1 animate-spin"}):e.jsx(oe,{className:"h-3.5 w-3.5 mr-1"}),"Create sub-agent"]}),e.jsx(S,{variant:"ghost",size:"sm",className:"h-7",onClick:()=>{i(""),X(null)},children:"Cancel"})]})]}),F.map(V=>Pe(V,p+1))]},a.id)};return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-sm font-semibold",children:"Trigger a run"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Creates a run record + bundle (inputs ride along). The server never executes — a runner (the contextnest-runner) walks the bundle and posts each step back into the trace below."})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[11px] font-medium text-muted-foreground mb-1",children:"Agent / skill node"}),e.jsx(pt,{value:O,onValueChange:c,runnables:ae,placeholder:"Choose an agent to run…",testId:"run-agent-lookup"})]}),m&&e.jsxs("div",{children:[e.jsx("label",{className:"block text-[11px] font-medium text-muted-foreground mb-1",children:"Parent run (optional — spawn as a sub-agent)"}),e.jsx(Ms,{value:q,onValueChange:Y,runs:j,runLabel:I,runType:ue,blockedReason:a=>R(a,O)}),ge&&e.jsxs("p",{className:"text-[11px] text-destructive mt-1",children:["This parent can't be used (",ge,") — pick another or change the agent."]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[11px] font-medium text-muted-foreground mb-1",children:"Inputs (optional — plain text or JSON)"}),e.jsx("textarea",{value:K,onChange:a=>D(a.target.value),placeholder:'e.g. {"account":"Foley"}',className:"w-full rounded-md border bg-background px-2 py-1.5 text-xs font-mono min-h-[64px]"})]}),w&&e.jsx("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:w}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(S,{disabled:L||!O.trim()||!!ge,onClick:()=>void Z(),title:"Create a run (a runner executes it)",children:[L?e.jsx(J,{className:"h-3.5 w-3.5 mr-1.5 animate-spin"}):e.jsx(Pt,{className:"h-3.5 w-3.5 mr-1.5"}),"Create run"]}),e.jsxs(S,{variant:"outline",size:"sm",onClick:()=>void H(),children:[e.jsx(st,{className:"h-3.5 w-3.5 mr-1"})," Refresh"]})]}),e.jsxs("details",{className:"rounded-md border bg-muted/30 px-3 py-2 text-[11px]",children:[e.jsx("summary",{className:"cursor-pointer font-medium",children:"How do I run one? (the runner is a separate process)"}),e.jsxs("div",{className:"mt-2 space-y-1.5 text-muted-foreground",children:[e.jsxs("p",{children:["The ",e.jsx("b",{children:"trigger"})," button just records a run. The"," ",e.jsx("b",{children:"runner"})," is a small stateless container that actually walks it and calls the LLM. Point it at this nest:"]}),e.jsx("pre",{className:"overflow-x-auto rounded bg-background border p-2 font-mono text-[10.5px] leading-relaxed",children:`docker run -d --name cn-runner --network host \\
|
|
12
12
|
-e CONTEXTNEST_SERVER=http://localhost:4040 \\
|
|
13
13
|
-e CONTEXTNEST_NEST=${s} \\
|
|
14
14
|
-e CONTEXTNEST_KEY=cnst_localdev \\
|
|
15
|
-
contextnest-runner:local poll`}),e.jsxs("p",{children:[e.jsx("b",{children:"poll"})," claims every run this server creates (Schedule tab, Run buttons) and executes it — one standing container per nest. No Anthropic key flag needed: set"," ",e.jsx("code",{children:"ANTHROPIC_API_KEY"})," in Activity → Tool environment and the runner picks it up from the run bundle. Steps stream back into the trace below — refresh to watch."]})]})]})]}),e.jsxs("div",{className:`grid gap-4 items-start ${d?"lg:grid-cols-[minmax(0,24rem)_minmax(0,1fr)]":"grid-cols-1"}`,children:[e.jsx("div",{className:"rounded-lg border divide-y min-w-0",children:E?e.jsx("div",{className:"px-3 py-6 text-center text-muted-foreground",children:e.jsx(J,{className:"h-4 w-4 animate-spin inline"})}):j.length===0?e.jsx("div",{className:"px-3 py-6 text-center text-xs text-muted-foreground",children:"No runs yet. Trigger an agent above."}):n.map(a=>Pe(a,0))}),d&&e.jsx("div",{className:"rounded-lg border p-4 min-w-0 lg:sticky lg:top-20",children:e.jsx(Ls,{run:d,children:j.filter(a=>a.parent_run_id===d.id),parent:d.parent_run_id?j.find(a=>a.id===d.parent_run_id)??null:null,label:I,typeOf:ue,onOpen:a=>void re(a),onCancel:a=>void G(a),cancelling:le===d.id})})]})]})}function Ls({run:s,children:m=[],parent:g=null,label:b=d=>d,typeOf:C=()=>{},onOpen:y,onCancel:j,cancelling:k=!1}){var d;return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[e.jsx(We,{type:C(s.agent_node),className:"h-4 w-4"}),e.jsx("span",{className:"font-mono text-sm",children:s.id}),e.jsx(se,{variant:tt(Ae(s)),title:qe(s)?Mt:void 0,children:Ae(s)}),(s.depth??0)>0&&e.jsxs(se,{variant:"outline",className:"text-[10px]",children:["sub-agent · depth ",s.depth]}),s.status==="running"&&j&&e.jsxs(S,{variant:"outline",size:"sm",className:"ml-auto h-7",disabled:k,onClick:()=>j(s.id),title:"Cancel this run",children:[k?e.jsx(J,{className:"h-3.5 w-3.5 mr-1 animate-spin"}):e.jsx(Rt,{className:"h-3.5 w-3.5 mr-1"}),"Cancel run"]})]}),e.jsxs("div",{className:"text-xs text-muted-foreground mb-4",children:["agent ",b(s.agent_node)," · started ",Ee(s.started_at),s.finished_at?` · finished ${Ee(s.finished_at)}`:""," · triggered by ",s.triggered_by]}),g&&e.jsxs("button",{type:"button",onClick:()=>y==null?void 0:y(g.id),className:"mb-3 inline-flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground",title:"Open the run that spawned this one",children:[e.jsx(js,{className:"h-3 w-3"})," Spawned by ",b(g.agent_node)," ",e.jsxs("span",{className:"font-mono",children:["(",g.id.slice(0,8),")"]})]}),m.length>0&&e.jsxs("div",{className:"mb-4 rounded-md border bg-muted/20 p-2.5",children:[e.jsxs("div",{className:"text-[10px] uppercase tracking-wide text-muted-foreground mb-1.5",children:["Sub-agents spawned (",m.length,")"]}),e.jsx("div",{className:"space-y-1",children:m.map(h=>e.jsxs("button",{type:"button",onClick:()=>y==null?void 0:y(h.id),className:"flex w-full items-center gap-2 rounded px-1.5 py-1 text-left text-xs hover:bg-muted/50",children:[e.jsx(nt,{className:"h-3 w-3 text-muted-foreground/50 shrink-0"}),e.jsx(We,{type:C(h.agent_node),className:"h-3.5 w-3.5"}),e.jsx("span",{className:"truncate",children:b(h.agent_node)}),e.jsx(se,{variant:tt(Ae(h)),className:"text-[10px] shrink-0",children:Ae(h)}),e.jsx("span",{className:"ml-auto font-mono text-[10px] text-muted-foreground shrink-0",children:h.id.slice(0,8)})]},h.id))})]}),((d=s.trace)==null?void 0:d.error)&&e.jsx("div",{className:"mb-3 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive font-mono break-all",children:s.trace.error}),e.jsx("div",{className:"space-y-0",children:s.steps.length===0?e.jsx("div",{className:"text-xs text-muted-foreground",children:qe(s)?"No steps yet — queued, waiting for a runner to claim it. Start a runner (see “How do I run one?” above) or cancel the run.":"No steps recorded."}):s.steps.map(h=>e.jsxs("div",{className:"grid grid-cols-[24px_1fr] gap-3 py-2 border-b border-dashed last:border-0",children:[e.jsx("div",{className:"text-muted-foreground pt-0.5",children:Es(h.action)}),e.jsxs("div",{children:[e.jsxs("div",{className:"text-xs",children:[e.jsxs("span",{className:"text-muted-foreground",children:[Ee(h.at)," ·"," "]}),e.jsx("span",{className:"font-medium",children:h.action}),h.node_id&&e.jsxs("span",{className:"font-mono text-muted-foreground",children:[" ",h.node_id]})]}),h.detail&&e.jsx("div",{className:"text-[11px] text-muted-foreground font-mono mt-0.5 break-all",children:typeof h.detail=="string"?h.detail:JSON.stringify(h.detail)})]})]},h.seq))})]})}const _e=168,je=56,Ws=260,zs=100,Se=30,Ze=70;function Fs({nestId:s}){const[m,g]=r.useState([]),[b,C]=r.useState([]),[y,j]=r.useState([]),[k,d]=r.useState(!0),[h,E]=r.useState(null),[N,w]=r.useState(null),[x,O]=r.useState(null),[c,L]=r.useState(null),[T,B]=r.useState(""),[D,q]=r.useState(""),[Y,X]=r.useState(""),[i,$]=r.useState(""),[W,he]=r.useState(">"),[ne,de]=r.useState(""),[be,pe]=r.useState(!1),[U,le]=r.useState(""),[ye,Ne]=r.useState([]),[we,H]=r.useState(60),[ae,re]=r.useState(""),[G,Te]=r.useState(1),[Z,$e]=r.useState(""),[Q,I]=r.useState(null),[ue,ie]=r.useState(!1),[ke,n]=r.useState(""),[v,P]=r.useState([]),[z,R]=r.useState(""),[Fe,ge]=r.useState([]),[Pe,a]=r.useState("slack"),[p,F]=r.useState({}),[me,fe]=r.useState(null),[V,at]=r.useState(0);r.useEffect(()=>{if(!me)return;const t=new ResizeObserver(o=>{var f;const u=((f=o[0])==null?void 0:f.contentRect.width)??0;u&&at(u)});return t.observe(me),at(me.clientWidth),()=>t.disconnect()},[me]);const xe=r.useCallback(async()=>{d(!0);try{const[t,o,u,f]=await Promise.all([ft(s),vt(s),Xe(s).then(_=>_.nodes).catch(()=>[]),jt(s).catch(()=>[])]);g(t),C(o),j(u),Ne(f),E(null)}catch(t){E(t instanceof Error?t.message:"Failed to load canvas")}finally{d(!1)}},[s]);r.useEffect(()=>{if(!x)return;let t=!1;return qt(s,x).then(o=>!t&&P(o.map(u=>u.user_email))).catch(()=>!t&&P([])),Je(s,x).then(o=>!t&&ge(o)).catch(()=>!t&&ge([])),()=>{t=!0}},[s,x]);const De=(t,o)=>{is(o).then(u=>{u&&($e(t),setTimeout(()=>$e(""),1500))})};r.useEffect(()=>{xe()},[xe]);const rt=new Map(y.map(t=>[t.id,t])),K=t=>{var o;return((o=rt.get(t))==null?void 0:o.title)||t.replace(/^nodes\//,"")},Re=t=>{var o;return(o=rt.get(t))==null?void 0:o.type},ot=m.filter(t=>t.type.is_flow),ee=new Map;{const t=new Set;for(const A of m)t.add(A.from_node),t.add(A.to_node);const o=new Map,u=new Set(ot.map(A=>A.to_node)),f=[...t].filter(A=>!u.has(A)).sort();for(const A of f)o.set(A,0);for(let A=0;A<t.size;A++){let l=!1;for(const M of ot){const ce=(o.get(M.from_node)??0)+1;ce>(o.get(M.to_node)??0)&&(o.set(M.to_node,ce),l=!0)}if(!l)break}const _=new Map;for(const A of[...t].sort((l,M)=>String(K(l)).localeCompare(K(M)))){const l=o.get(A)??0;_.has(l)||_.set(l,[]),_.get(l).push(A)}for(const[A,l]of _)l.forEach((M,ce)=>{ee.set(M,{id:M,x:Se+A*Ws,y:Ze+ce*zs})})}const Ot=Se*2+(Math.max(0,...[...ee.values()].map(t=>t.x))+_e+60),lt=Math.max(300,Ze+(Math.max(-Ze+40,...[...ee.values()].map(t=>t.y))+je+40)),He=ke.trim().toLowerCase(),Me=y.map(t=>t.id).filter(t=>!ee.has(t)).filter(t=>!He||K(t).toLowerCase().includes(He)||t.toLowerCase().includes(He)).sort((t,o)=>{const u=f=>Re(f)==="agent"?0:Re(f)==="skill"?1:2;return u(t)-u(o)||K(t).localeCompare(K(o))}),Oe=lt+46,it=Math.max(Ot,V>0?Math.floor(V):920),Ue=Math.max(1,Math.floor((it-Se*2)/(_e+46)));Me.forEach((t,o)=>{ee.set(t,{id:t,x:Se+o%Ue*(_e+46),y:Oe+Math.floor(o/Ue)*(je+28)})});const ct=it,Lt=Me.length?Oe+Math.ceil(Me.length/Ue)*(je+28)+30:lt+20,ve=(t,o)=>{const u=ee.get(t);return u?{x:o==="out"?u.x+_e:u.x,y:u.y+je/2}:{x:0,y:0}},Wt=(t,o,u=0)=>{const f=ve(t,"out"),_=ve(o,"in"),A=Math.max(40,(_.x-f.x)/2),l=u*4/3;return`M${f.x},${f.y} C${f.x+A},${f.y+l} ${_.x-A},${_.y+l} ${_.x},${_.y}`},Ge=new Map;{const t=new Map;for(const o of m){const u=`${o.from_node}\0${o.to_node}`,f=t.get(u)??[];f.push(o),t.set(u,f)}for(const o of t.values())o.length<2||o.forEach((u,f)=>Ge.set(u.id,(f-(o.length-1)/2)*34))}const dt=t=>t.type.color||(t.type.is_flow?"#34a853":"#94a3b8"),zt=m.filter(t=>ee.has(t.from_node)&&ee.has(t.to_node)).map(t=>{let o="";if(t.condition_mode==="nl"&&t.condition)o=`“${t.condition}”`;else if(t.condition_mode==="structured"&&t.condition)try{const _=typeof t.condition=="string"?JSON.parse(t.condition):t.condition;o=_!=null&&_.term?`${_.term} ${_.op??""} ${_.value??""}`:""}catch{}const u=ve(t.from_node,"out"),f=ve(t.to_node,"in");return{edge:t,x:(u.x+f.x)/2,y:(u.y+f.y)/2+(Ge.get(t.id)??0)-je/2-6,..._s(t.type.name,o)}}),Ve=t=>{if(O(null),I(null),w(t.id),B(t.type.name),q(t.condition_mode||""),t.condition_mode==="nl")X(String(t.condition??""));else if(t.condition_mode==="structured"&&t.condition)try{const o=typeof t.condition=="string"?JSON.parse(t.condition):t.condition;$(String(o.term??"")),he(String(o.op??">")),de(String(o.value??""))}catch{$(""),de("")}},Ft=async()=>{if(!N)return;const t=m.find(u=>u.id===N),o=t&&m.find(u=>u.id!==N&&u.from_node===t.from_node&&u.to_node===t.to_node&&u.type.name===T);if(o){E(`${K(o.from_node)} → ${K(o.to_node)} is already connected with "${T}".`);return}pe(!0);try{await os(s,N,{type:T,condition_mode:D||null,condition:D==="nl"?Y.trim():D==="structured"?{term:i.trim(),op:W,value:isNaN(Number(ne))?ne.trim():Number(ne)}:null}),await xe()}catch(u){E(u instanceof Error?u.message:"Failed to save edge")}finally{pe(!1)}},Dt=async t=>{try{await _t(s,t),w(null),await xe()}catch(o){E(o instanceof Error?o.message:"Failed to delete edge")}},ut=async(t,o)=>{var _,A;if(t===o)return;const u=((_=b.find(l=>l.is_flow))==null?void 0:_.name)??((A=b[0])==null?void 0:A.name);if(!u)return;const f=m.find(l=>l.from_node===t&&l.to_node===o&&l.type.name===u);if(f){E(`${K(t)} → ${K(o)} is already connected with "${u}".`),Ve(f);return}try{const l=await kt(s,{from_node:t,to_node:o,type:u,condition_mode:null,condition:null});await xe(),Ve(l)}catch(l){E(l instanceof Error?l.message:"Failed to connect")}},Ht=t=>{const o=t.currentTarget.closest("svg").getBoundingClientRect();return{x:t.clientX-o.left,y:t.clientY-o.top}},Le=m.find(t=>t.id===N)??null,Vt=[...new Set(m.map(dt))];return e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-[minmax(0,1fr)_300px] gap-4",children:[e.jsxs("div",{className:"rounded-lg border overflow-hidden bg-background",children:[e.jsxs("div",{className:"flex items-center gap-2 px-3 py-2 border-b text-xs text-muted-foreground",children:[e.jsxs("span",{className:"hidden md:inline",children:["Drag from a card's ",e.jsx("b",{children:"right port"})," onto another card to connect. Click a wire or card to edit it."]}),e.jsx("div",{className:"flex-1"}),e.jsx(te,{value:ke,onChange:t=>n(t.target.value),placeholder:"Find a document to wire in…",className:"h-7 w-56 text-xs","data-testid":"canvas-shelf-search"}),e.jsx(S,{variant:"outline",size:"sm",className:"h-7",onClick:()=>void xe(),children:e.jsx(st,{className:"h-3.5 w-3.5"})})]}),h&&e.jsx("div",{className:"mx-3 mt-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive whitespace-pre-line",children:h}),k?e.jsx("div",{className:"py-16 text-center text-muted-foreground",children:e.jsx(J,{className:"h-4 w-4 animate-spin inline"})}):ee.size===0?e.jsx("div",{className:"py-16 text-center text-sm text-muted-foreground",children:"No documents in this nest yet — create one from the Documents tab and it appears here, ready to wire up."}):e.jsx("div",{className:"overflow-auto max-h-[70vh]",ref:fe,children:e.jsxs("svg",{width:ct,height:Lt,ref:t=>{},style:{background:"radial-gradient(circle, hsl(var(--muted-foreground) / 0.18) 1px, transparent 1px)",backgroundSize:"20px 20px"},onMouseMove:t=>{if(!c)return;const o=t.currentTarget.getBoundingClientRect();L({...c,x:t.clientX-o.left,y:t.clientY-o.top})},onMouseUp:()=>L(null),onClick:()=>{w(null),O(null)},children:[e.jsx("defs",{children:Vt.map(t=>e.jsx("marker",{id:`ah-${t.replace(/[^a-z0-9]/gi,"")}`,markerWidth:"9",markerHeight:"9",refX:"7",refY:"3",orient:"auto",children:e.jsx("path",{d:"M0,0 L7,3 L0,6 z",fill:t})},t))}),m.map(t=>{if(!ee.has(t.from_node)||!ee.has(t.to_node))return null;const o=Ge.get(t.id)??0,u=Wt(t.from_node,t.to_node,o),f=dt(t);return e.jsxs("g",{children:[e.jsx("path",{d:u,fill:"none",stroke:f,strokeWidth:N===t.id?3:2,strokeDasharray:t.type.is_flow?void 0:"4 4",markerEnd:`url(#ah-${f.replace(/[^a-z0-9]/gi,"")})`,opacity:N&&N!==t.id?.45:1}),e.jsx("path",{d:u,fill:"none",stroke:"transparent",strokeWidth:14,style:{cursor:"pointer"},onClick:_=>{_.stopPropagation(),Ve(t)}})]},t.id)}),c&&e.jsx("path",{d:`M${ve(c.from,"out").x},${ve(c.from,"out").y} C${ve(c.from,"out").x+60},${ve(c.from,"out").y} ${c.x-60},${c.y} ${c.x},${c.y}`,fill:"none",stroke:"hsl(var(--primary))",strokeWidth:2,strokeDasharray:"5 4"}),Me.length>0&&e.jsxs("g",{children:[e.jsx("line",{x1:Se,y1:Oe-26,x2:ct-Se,y2:Oe-26,stroke:"hsl(var(--border))",strokeDasharray:"3 3"}),e.jsxs("text",{x:Se,y:Oe-32,style:{font:"10px sans-serif",fill:"hsl(var(--muted-foreground))"},children:["NOT WIRED IN YET (",Me.length,He?" matching":"",") — drag a right port onto any card to connect"]})]}),[...ee.values()].map(t=>{const o=Re(t.id),u=x===t.id;return e.jsxs("g",{children:[e.jsx("foreignObject",{x:t.x,y:t.y,width:_e,height:je+6,children:e.jsxs("div",{className:`rounded-lg border-2 bg-background px-2.5 py-1.5 shadow-sm cursor-pointer select-none ${u?"border-primary ring-2 ring-primary/20":"border-border"}`,style:{width:_e,height:je},onClick:f=>{f.stopPropagation(),w(null),I(null),O(t.id)},onMouseUp:()=>{c&&c.from!==t.id&&(ut(c.from,t.id),L(null))},title:t.id,children:[e.jsxs("div",{className:"flex items-center gap-1 text-[10px] uppercase tracking-wide text-muted-foreground",children:[e.jsx(Ce,{type:o}),o??"document"]}),e.jsx("div",{className:"text-xs font-semibold truncate mt-0.5",children:K(t.id)})]})}),e.jsx("circle",{cx:t.x+_e,cy:t.y+je/2,r:6,fill:"hsl(var(--background))",stroke:"hsl(var(--primary))",strokeWidth:1.5,style:{cursor:"crosshair"},onMouseDown:f=>{f.stopPropagation(),f.preventDefault();const _=Ht(f);L({from:t.id,x:_.x,y:_.y})}})]},t.id)}),zt.map(t=>e.jsxs("g",{style:{cursor:"pointer"},onClick:o=>{o.stopPropagation(),Ve(t.edge)},children:[e.jsx("title",{children:t.full}),e.jsx("rect",{x:t.x-t.width/2,y:t.y-9,width:t.width,height:13,rx:3,fill:"hsl(var(--background))",opacity:.92}),e.jsx("text",{x:t.x,y:t.y,textAnchor:"middle",style:{font:"10px ui-monospace, monospace",fill:"hsl(var(--muted-foreground))"},children:t.short})]},`label-${t.edge.id}`))]})})]}),e.jsx("div",{className:"rounded-lg border p-4 h-fit",children:Le?e.jsxs("div",{children:[e.jsxs("h3",{className:"text-sm font-semibold",children:["Edge · ",Le.type.name]}),e.jsxs("p",{className:"text-xs text-muted-foreground mb-3",children:[K(Le.from_node)," → ",K(Le.to_node)]}),e.jsx("label",{className:"block text-[10px] uppercase tracking-wide text-muted-foreground mb-1",children:"Type"}),e.jsx("select",{value:T,onChange:t=>B(t.target.value),className:"w-full h-8 rounded-md border bg-background px-2 text-sm mb-3",children:b.map(t=>e.jsxs("option",{value:t.name,children:[t.is_flow?"▶ ":"",t.name]},t.id))}),e.jsx("label",{className:"block text-[10px] uppercase tracking-wide text-muted-foreground mb-1",children:"Fires"}),e.jsx("div",{className:"flex items-center rounded-md border h-8 text-xs overflow-hidden w-fit mb-2",children:[["","always"],["nl","if…"],["structured","metric"]].map(([t,o],u)=>e.jsx("button",{type:"button",className:`px-2.5 h-full ${u>0?"border-l":""} ${D===t?"bg-primary text-primary-foreground":"hover:bg-muted"}`,onClick:()=>q(t),children:o},t))}),D==="nl"&&e.jsx(te,{value:Y,onChange:t=>X(t.target.value),placeholder:'e.g. "lost on price, not product"',className:"h-8 text-sm italic mb-2"}),D==="structured"&&e.jsxs("div",{className:"grid grid-cols-[1fr_58px_1fr] gap-1.5 mb-2",children:[e.jsx(te,{value:i,onChange:t=>$(t.target.value),placeholder:"CAC",className:"h-8 text-sm font-mono"}),e.jsx("select",{value:W,onChange:t=>he(t.target.value),className:"h-8 rounded-md border bg-background px-1 text-sm font-mono",children:[">","<",">=","<=","=","!="].map(t=>e.jsx("option",{value:t,children:t},t))}),e.jsx(te,{value:ne,onChange:t=>de(t.target.value),placeholder:"500",className:"h-8 text-sm font-mono"})]}),e.jsxs("div",{className:"flex gap-2 mt-4",children:[e.jsx(S,{size:"sm",className:"flex-1",disabled:be,onClick:()=>void Ft(),children:be?e.jsx(J,{className:"h-3.5 w-3.5 animate-spin"}):"Save"}),e.jsx(S,{size:"sm",variant:"outline",className:"text-destructive",onClick:()=>void Dt(Le.id),children:"Delete"})]})]}):x?(()=>{const t=["agent","skill"].includes(Re(x)??""),o=ye.find(l=>l.agent_node===x),u=window.location.origin,f=`[[${K(x)}]]`,_=`curl -s -X POST ${u}/nests/${s}/context -H 'Content-Type: application/json' -d '{"selector":"${f}","hops":${G},"max_tokens":4000}'`,A=`curl -s -X PATCH ${u}/nests/${s}/nodes/${x} -H 'Content-Type: application/json' -d '{"append":"<your update>","changeNote":"via ctx"}'`;return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ce,{type:Re(x)}),e.jsx("h3",{className:"text-sm font-semibold truncate",children:K(x)})]}),e.jsx("p",{className:"text-xs text-muted-foreground font-mono truncate",children:x})]}),t&&e.jsxs("div",{className:"space-y-2",children:[e.jsxs(S,{size:"sm",className:"w-full",onClick:async()=>{try{await Qe(s,x),re("Run created — a polling runner will pick it up"),setTimeout(()=>re(""),3e3)}catch(l){E(l instanceof Error?l.message:"Trigger failed")}},children:[e.jsx(At,{className:"h-3.5 w-3.5 mr-1.5"})," Run now"]}),ae&&e.jsx("p",{className:"text-[11px] text-emerald-600",children:ae}),e.jsx("label",{className:"block text-[10px] uppercase tracking-wide text-muted-foreground",children:"Schedule"}),o?e.jsxs("div",{className:"rounded-md border px-2.5 py-2 text-xs space-y-1.5",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("span",{children:["every"," ",e.jsx("b",{children:o.every_minutes>=60?`${o.every_minutes/60}h`:`${o.every_minutes}m`}),o.enabled?"":" · paused"]}),e.jsx("div",{className:"flex-1"}),e.jsx("button",{type:"button",className:"text-primary hover:underline",onClick:async()=>{await Ie(s,o.id,{enabled:!o.enabled}),await xe()},children:o.enabled?"Pause":"Resume"}),e.jsx("button",{type:"button",className:"text-destructive hover:underline",onClick:async()=>{await bt(s,o.id),await xe()},children:"Remove"})]}),o.enabled&&o.next_due_at&&e.jsxs("div",{className:"text-muted-foreground",children:["next fire ~",Ee(o.next_due_at)]})]}):e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsxs("select",{value:we,onChange:l=>H(Number(l.target.value)),className:"h-8 rounded-md border bg-background px-2 text-sm flex-1",children:[e.jsx("option",{value:15,children:"every 15 minutes"}),e.jsx("option",{value:60,children:"every hour"}),e.jsx("option",{value:360,children:"every 6 hours"}),e.jsx("option",{value:1440,children:"every day"})]}),e.jsx(S,{size:"sm",className:"h-8",onClick:async()=>{try{await yt(s,{agent_node:x,every_minutes:we}),await xe()}catch(l){E(l instanceof Error?l.message:"Schedule failed")}},children:"Schedule"})]})]}),t&&e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("label",{className:"block text-[10px] uppercase tracking-wide text-muted-foreground",children:"Triggers — call this agent from outside"}),Fe.map(l=>e.jsxs("div",{className:"rounded-md border px-2 py-1.5 text-[11px] space-y-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(se,{variant:"secondary",className:"text-[10px]",children:l.preset}),e.jsxs("span",{className:"text-muted-foreground",children:["fired ",l.fire_count,"×"]}),e.jsx("div",{className:"flex-1"}),e.jsx("button",{type:"button",className:"text-destructive hover:underline",onClick:async()=>{await Xt(s,l.id),ge(await Je(s,x))},children:"Remove"})]}),l.url??p[l.id]?e.jsx("button",{type:"button",className:"w-full text-left font-mono break-all rounded bg-muted/40 px-1.5 py-1 hover:border-primary border border-transparent",title:"Copy the trigger URL — paste into a Slack slash command / Events API, Teams outgoing webhook, or any system that can POST",onClick:()=>De(`hook-${l.id}`,l.url??p[l.id]),children:Z===`hook-${l.id}`?"✓ copied":l.url??p[l.id]}):e.jsx("p",{className:"text-muted-foreground px-1.5",children:"URL was shown at creation only (like an API key). Remove + re-add to mint a fresh one."})]},l.id)),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsxs("select",{value:Pe,onChange:l=>a(l.target.value),className:"h-7 rounded-md border bg-background px-1.5 text-xs flex-1",children:[e.jsx("option",{value:"slack",children:"Slack (slash command / @mention)"}),e.jsx("option",{value:"teams",children:"Teams (outgoing webhook)"}),e.jsx("option",{value:"webhook",children:"Webhook (any system)"})]}),e.jsx(S,{size:"sm",variant:"outline",className:"h-7 px-2",onClick:async()=>{const l=await Ut(s,x,Pe);if(l.url){const M=`${l.id.slice(0,7)}…${l.id.slice(-4)}`;F(ce=>({...ce,[M]:l.url}))}ge(await Je(s,x))},children:e.jsx(oe,{className:"h-3.5 w-3.5"})})]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Each trigger is a secret URL that queues a run — message text becomes the run's inputs. Add SLACK_SIGNING_SECRET to the Tool environment to verify Slack requests."})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("label",{className:"block text-[10px] uppercase tracking-wide text-muted-foreground",children:"Notify on output"}),v.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1",children:v.map(l=>e.jsxs("span",{className:"inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[11px]",children:[l,e.jsx("button",{type:"button",className:"text-muted-foreground hover:text-destructive",title:"Stop notifying",onClick:async()=>{const M=await Gt(s,x,l);P(M.map(ce=>ce.user_email))},children:"✕"})]},l))}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(te,{value:z,onChange:l=>R(l.target.value),placeholder:"person@team.com",className:"h-7 text-xs flex-1",onKeyDown:async l=>{if(l.key==="Enter"&&z.includes("@")){const M=await mt(s,x,z.trim());P(M.map(ce=>ce.user_email)),R("")}}}),e.jsx(S,{size:"sm",variant:"outline",className:"h-7 px-2",disabled:!z.includes("@"),onClick:async()=>{const l=await mt(s,x,z.trim());P(l.map(M=>M.user_email)),R("")},children:e.jsx(oe,{className:"h-3.5 w-3.5"})})]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Tagged people get an inbox notification when this node's output lands for review. (Slack/webhook delivery comes later — same table.)"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] uppercase tracking-wide text-muted-foreground mb-1",children:"Add a step after this"}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsxs("select",{value:U,onChange:l=>le(l.target.value),className:"h-8 rounded-md border bg-background px-2 text-sm flex-1 min-w-0",children:[e.jsx("option",{value:"",children:"Choose a document…"}),y.filter(l=>l.id!==x).map(l=>e.jsx("option",{value:l.id,children:l.title||l.id},l.id))]}),e.jsx(S,{size:"sm",className:"h-8",disabled:!U,onClick:()=>{ut(x,U),le("")},children:e.jsx(oe,{className:"h-3.5 w-3.5"})})]}),e.jsx("p",{className:"text-[11px] text-muted-foreground mt-1.5",children:"Or drag from the node's right port straight onto another card."})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("label",{className:"text-[10px] uppercase tracking-wide text-muted-foreground",children:"Use from CLI / agent"}),e.jsx("div",{className:"flex-1"}),e.jsx("select",{value:G,onChange:l=>Te(Number(l.target.value)),className:"h-6 rounded border bg-background px-1 text-[11px]",title:"How many hops of linked context to pull with it",children:[0,1,2,3].map(l=>e.jsxs("option",{value:l,children:[l," hop",l===1?"":"s"]},l))})]}),e.jsx("button",{type:"button",className:"w-full text-left rounded-md border bg-muted/40 px-2 py-1.5 text-[10.5px] font-mono break-all hover:border-primary",onClick:()=>De("sel",f),title:"Copy the selector",children:Z==="sel"?"✓ copied":f}),e.jsx("button",{type:"button",className:"w-full text-left rounded-md border bg-muted/40 px-2 py-1.5 text-[10.5px] font-mono break-all hover:border-primary",onClick:()=>De("read",_),title:"Copy — deterministic read: this node + linked context",children:Z==="read"?"✓ copied":`read → ${_.slice(0,64)}…`}),e.jsx("button",{type:"button",className:"w-full text-left rounded-md border bg-muted/40 px-2 py-1.5 text-[10.5px] font-mono break-all hover:border-primary",onClick:()=>De("write",A),title:"Copy — governed write: append to this node (lands as a new version / review request)",children:Z==="write"?"✓ copied":`write → ${A.slice(0,64)}…`}),e.jsx(S,{variant:"outline",size:"sm",className:"w-full h-7 text-xs",disabled:ue,onClick:async()=>{var l;ie(!0);try{const M=await Jt(s,f,G);I({text:M.context||"(empty context)",nodes:((l=M.trace)==null?void 0:l.nodes_traversed)??M.nodes_traversed??0})}catch(M){E(M instanceof Error?M.message:"Preview failed")}finally{ie(!1)}},children:ue?e.jsx(J,{className:"h-3.5 w-3.5 animate-spin"}):e.jsxs(e.Fragment,{children:["Test: preview what it reads (",G," hop",G===1?"":"s",")"]})}),Q&&e.jsxs("div",{className:"rounded-md border bg-muted/30 p-2",children:[e.jsxs("div",{className:"flex items-center text-[10px] text-muted-foreground mb-1",children:[e.jsxs("span",{children:[Q.nodes," node",Q.nodes===1?"":"s"," assembled — exactly what a run reads"]}),e.jsx("button",{type:"button",className:"ml-auto hover:text-foreground",onClick:()=>I(null),children:"✕"})]}),e.jsxs("pre",{className:"max-h-56 overflow-auto whitespace-pre-wrap text-[10.5px] leading-relaxed",children:[Q.text.slice(0,4e3),Q.text.length>4e3?`
|
|
16
|
-
…(truncated)`:""]})]})]})]})})():e.jsxs("div",{className:"text-sm text-muted-foreground",children:[e.jsx("p",{className:"font-medium text-foreground mb-1",children:"Nothing selected"}),e.jsxs("p",{className:"text-xs",children:["Click a ",e.jsx("b",{children:"wire"})," to change its type or condition, click a"," ",e.jsx("b",{children:"card"})," to add a next step, or drag from a card's right port onto another card to connect them."]})]})})]})}function Ds({nestId:s}){const[m,g]=r.useState([]),[b,C]=r.useState([]),[y,j]=r.useState(!0),[k,d]=r.useState(null),[h,E]=r.useState(""),[N,w]=r.useState(60),[x,O]=r.useState(""),[c,L]=r.useState(!1),T=r.useCallback(async()=>{j(!0);try{const[i,$]=await Promise.all([jt(s),Xe(s).then(W=>W.nodes).catch(()=>[])]);g(i),C($),d(null)}catch(i){d(i instanceof Error?i.message:"Failed to load schedules")}finally{j(!1)}},[s]);r.useEffect(()=>{T()},[T]);const B=i=>{var $;return(($=b.find(W=>W.id===i))==null?void 0:$.title)||i.replace(/^nodes\//,"")},D=i=>{var $;return($=b.find(W=>W.id===i))==null?void 0:$.type},q=b.filter(i=>i.type==="agent"||i.type==="skill"),Y=q.filter(i=>!m.some($=>$.agent_node===i.id)),X=i=>i>=1440?`${i/1440}d`:i>=60?`${i/60}h`:`${i}m`;return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("p",{className:"text-sm text-muted-foreground",children:["A schedule decides ",e.jsx("b",{children:"when a run starts"})," and its stop-after bound decides ",e.jsx("b",{children:"when it's done"}),". What happens ",e.jsx("em",{children:"inside"})," a run — which step fires, on what condition — lives on the wires in the Canvas (click a wire to set always / if… / metric). Scheduled output still lands as a review request; scheduling doesn't skip governance."]}),k&&e.jsx("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:k}),y?e.jsx("div",{className:"py-8 text-center text-muted-foreground",children:e.jsx(J,{className:"h-4 w-4 animate-spin inline"})}):m.length===0?e.jsxs("div",{className:"rounded-lg border border-dashed p-6 text-center",children:[e.jsx(ws,{className:"h-6 w-6 text-muted-foreground/50 mx-auto mb-2"}),e.jsx("p",{className:"text-sm font-medium mb-1",children:"Nothing on the clock yet"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:q.length?"Pick an agent below — every interval, the server files a run for it.":"This nest has no runnable agents yet. Create one from Documents → New → type Agent (its body is the instructions), then schedule it here."})]}):e.jsx("div",{className:"rounded-lg border divide-y",children:m.map(i=>e.jsxs("div",{className:"px-3 py-2.5 flex items-center gap-2 text-sm",children:[e.jsx(Ce,{type:D(i.agent_node)}),e.jsx("span",{className:"truncate font-medium",title:i.agent_node,children:B(i.agent_node)}),e.jsxs(se,{variant:"secondary",className:"text-[10px] shrink-0",children:["every ",X(i.every_minutes)]}),i.max_runs!==null&&e.jsxs(se,{variant:"outline",className:"text-[10px] shrink-0",title:"Stops automatically after this many runs",children:[i.runs_created,"/",i.max_runs," runs"]}),i.enabled?i.next_due_at&&e.jsxs("span",{className:"text-[11px] text-muted-foreground shrink-0",children:["next ~",Ee(i.next_due_at)]}):i.max_runs!==null&&i.runs_created>=i.max_runs?e.jsx(se,{className:"text-[10px] shrink-0 bg-emerald-600",children:"done"}):e.jsx(se,{variant:"outline",className:"text-[10px] shrink-0",children:"paused"}),e.jsx("div",{className:"flex-1"}),e.jsxs("select",{value:i.every_minutes,onChange:async $=>{await Ie(s,i.id,{every_minutes:Number($.target.value)}),await T()},className:"h-7 rounded-md border bg-background px-1.5 text-xs shrink-0",title:"Change the interval",children:[[15,60,360,1440].map($=>e.jsx("option",{value:$,children:X($)},$)),![15,60,360,1440].includes(i.every_minutes)&&e.jsx("option",{value:i.every_minutes,children:X(i.every_minutes)})]}),e.jsx(S,{variant:"outline",size:"sm",className:"h-7 text-xs shrink-0",onClick:async()=>{await Ie(s,i.id,{enabled:!i.enabled}),await T()},children:i.enabled?"Pause":"Resume"}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-7 w-7 text-muted-foreground hover:text-destructive shrink-0",onClick:async()=>{await bt(s,i.id),await T()},title:"Remove schedule",children:e.jsx(ze,{className:"h-3.5 w-3.5"})})]},i.id))}),e.jsxs("div",{className:"rounded-lg border bg-muted/20 p-3",children:[e.jsx("div",{className:"text-xs font-medium mb-2",children:"Put an agent on the clock"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("select",{value:h,onChange:i=>E(i.target.value),className:"h-8 rounded-md border bg-background px-2 text-sm flex-1 min-w-0","data-testid":"schedule-agent-lookup",children:[e.jsx("option",{value:"",children:Y.length?"Choose an agent…":"Every runnable agent is scheduled"}),Y.map(i=>e.jsxs("option",{value:i.id,children:[i.type==="agent"?"🤖 ":"⚡ ",i.title||i.id]},i.id))]}),e.jsxs("select",{value:N,onChange:i=>w(Number(i.target.value)),className:"h-8 rounded-md border bg-background px-2 text-sm",children:[e.jsx("option",{value:15,children:"every 15 minutes"}),e.jsx("option",{value:60,children:"every hour"}),e.jsx("option",{value:360,children:"every 6 hours"}),e.jsx("option",{value:1440,children:"every day"})]}),e.jsxs("select",{value:x,onChange:i=>O(i.target.value===""?"":Number(i.target.value)),className:"h-8 rounded-md border bg-background px-2 text-sm",title:"The stop condition: pause automatically after this many runs",children:[e.jsx("option",{value:"",children:"until stopped"}),e.jsx("option",{value:1,children:"once"}),e.jsx("option",{value:5,children:"stop after 5"}),e.jsx("option",{value:10,children:"stop after 10"}),e.jsx("option",{value:25,children:"stop after 25"})]}),e.jsxs(S,{size:"sm",className:"h-8",disabled:c||!h,onClick:async()=>{L(!0);try{await yt(s,{agent_node:h,every_minutes:N,max_runs:x===""?null:x}),E(""),await T()}catch(i){d(i instanceof Error?i.message:"Schedule failed")}finally{L(!1)}},children:[e.jsx(oe,{className:"h-3.5 w-3.5 mr-1"})," Schedule"]})]})]})]})}function Hs({nestId:s}){const[m,g]=r.useState([]),[b,C]=r.useState(null),[y,j]=r.useState(""),[k,d]=r.useState(""),[h,E]=r.useState(!1),N=r.useCallback(async()=>{try{g(await Nt(s)),C(null)}catch(w){C(w instanceof Error?w.message:"Failed to load env")}},[s]);return r.useEffect(()=>{N()},[N]),e.jsxs("details",{className:"rounded-lg border px-4 py-3",children:[e.jsxs("summary",{className:"cursor-pointer select-none text-sm font-medium flex items-center gap-2",children:[e.jsx($t,{className:"h-4 w-4 text-teal-500 inline"})," Tool environment (",m.length," key",m.length===1?"":"s",")"]}),e.jsxs("div",{className:"mt-3 space-y-3",children:[e.jsxs("p",{className:"text-[11px] text-muted-foreground",children:["Credentials for ",e.jsx("b",{children:"tool"})," nodes. Values are write-only here and travel to the runner inside the run bundle. Stored alongside nest content, not encrypted — treat this box like the nest itself."]}),b&&e.jsx("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:b}),m.length>0&&e.jsx("div",{className:"rounded-md border divide-y",children:m.map(w=>e.jsxs("div",{className:"px-3 py-1.5 flex items-center gap-2 text-xs",children:[e.jsx("span",{className:"font-mono font-medium",children:w.key}),e.jsx("span",{className:"font-mono text-muted-foreground",children:w.value_masked}),e.jsx("div",{className:"flex-1"}),e.jsx("span",{className:"text-muted-foreground",children:w.updated_by}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6 text-muted-foreground hover:text-destructive",title:"Delete key",onClick:async()=>{await ns(s,w.key),await N()},children:e.jsx(ze,{className:"h-3.5 w-3.5"})})]},w.key))}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(te,{value:y,onChange:w=>j(w.target.value.toUpperCase()),placeholder:"SLACK_TOKEN",className:"h-8 text-xs font-mono w-44"}),e.jsx(te,{value:k,onChange:w=>d(w.target.value),placeholder:"value (write-only)",type:"password",className:"h-8 text-xs font-mono flex-1"}),e.jsx(S,{size:"sm",className:"h-8",disabled:h||!/^[A-Z][A-Z0-9_]*$/.test(y)||!k,onClick:async()=>{E(!0);try{await wt(s,y,k),j(""),d(""),await N()}catch(w){C(w instanceof Error?w.message:"Save failed")}finally{E(!1)}},children:h?e.jsx(J,{className:"h-3.5 w-3.5 animate-spin"}):"Set"})]})]})]})}function Vs({nestId:s}){const[m,g]=r.useState(null),[b,C]=r.useState(""),[y,j]=r.useState(!1),[k,d]=r.useState(null),[h,E]=r.useState(!1);return r.useEffect(()=>{let N=!1;return Promise.all([Nt(s).catch(()=>null),Qt().catch(()=>null)]).then(([w,x])=>{if(!N){if(x!=null&&x.runner_key_configured)return g(!0);if(!w)return g(null);g(w.some(O=>O.key==="ANTHROPIC_API_KEY"))}}),()=>{N=!0}},[s]),m!==!1?h?e.jsx("div",{className:"rounded-lg border border-emerald-400/50 bg-emerald-500/5 px-4 py-3 text-sm",children:"✓ Key stored (masked from here on). Runners pick it up from the run bundle — start one in poll mode and your queued runs execute."}):null:e.jsxs("div",{className:"rounded-lg border border-amber-400/60 bg-amber-500/5 px-4 py-3",children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"🔑 Add your Anthropic API key to execute runs"}),e.jsx("p",{className:"text-xs text-muted-foreground mb-2",children:"Runs are created here, but a runner needs a key to call the model. Paste it once — it's stored write-only for this nest (masked everywhere, delivered to runners inside the run bundle). Get one at console.anthropic.com → Settings → API keys."}),k&&e.jsx("p",{className:"text-xs text-destructive mb-2",children:k}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(te,{type:"password",value:b,onChange:N=>C(N.target.value),placeholder:"sk-ant-…",className:"h-8 text-sm font-mono flex-1","data-testid":"runner-key-input"}),e.jsx(S,{size:"sm",className:"h-8",disabled:y||!b.trim().startsWith("sk-"),onClick:async()=>{j(!0);try{await wt(s,"ANTHROPIC_API_KEY",b.trim()),C(""),g(!0),E(!0)}catch(N){d(N instanceof Error?N.message:"Save failed")}finally{j(!1)}},children:y?e.jsx(J,{className:"h-3.5 w-3.5 animate-spin"}):"Save key"})]})]})}const Ks=[["review_requested","review requested"],["review_approved","approved"],["review_rejected","rejected"],["run_failed","run failed"],["mention","mentioned"]];function Bs({nestId:s}){const[m,g]=r.useState([]),[b,C]=r.useState(null),[y,j]=r.useState("slack"),[k,d]=r.useState(""),[h,E]=r.useState(["*"]),[N,w]=r.useState(!1),x=r.useCallback(async()=>{try{g(await It(s)),C(null)}catch(c){C(c instanceof Error?c.message:"Failed to load connectors")}},[s]);r.useEffect(()=>{x()},[x]);const O=c=>{E(L=>{if(c==="*")return["*"];const T=L.filter(B=>B!=="*"&&B!==c);return L.includes(c)?T.length?T:["*"]:[...T,c]})};return e.jsxs("details",{className:"rounded-lg border px-4 py-3",open:m.length>0,children:[e.jsxs("summary",{className:"cursor-pointer select-none text-sm font-medium",children:["📤 Connectors (",m.length,") — send events to Slack / Teams / webhooks"]}),e.jsxs("div",{className:"mt-3 space-y-3",children:[e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Governance + run events post to each matching channel. Fire-and-forget — a channel outage never blocks a review. The server-wide Slack webhook (super-admin Settings) always fires too."}),b&&e.jsx("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:b}),m.length>0&&e.jsx("div",{className:"rounded-md border divide-y",children:m.map(c=>e.jsxs("div",{className:"px-3 py-2 flex items-center gap-2 text-xs",children:[e.jsx(se,{variant:"secondary",className:"text-[10px] shrink-0",children:c.channel}),e.jsx("span",{className:"font-mono truncate",children:c.url}),e.jsx("span",{className:"text-muted-foreground shrink-0",children:c.events.includes("*")?"all events":c.events.join(", ")}),e.jsx("div",{className:"flex-1"}),e.jsx(S,{variant:"outline",size:"sm",className:"h-6 text-[11px] px-2 shrink-0",onClick:async()=>{await es(s,c.id,{enabled:!c.enabled}),await x()},children:c.enabled?"Pause":"Resume"}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6 text-muted-foreground hover:text-destructive shrink-0",onClick:async()=>{await ts(s,c.id),await x()},title:"Delete connector",children:e.jsx(ze,{className:"h-3.5 w-3.5"})})]},c.id))}),e.jsxs("div",{className:"space-y-2 rounded-md border bg-muted/20 p-2.5",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsxs("select",{value:y,onChange:c=>j(c.target.value),className:"h-8 rounded-md border bg-background px-1.5 text-xs",children:[e.jsx("option",{value:"slack",children:"Slack"}),e.jsx("option",{value:"teams",children:"Teams"}),e.jsx("option",{value:"webhook",children:"Webhook (raw JSON)"})]}),e.jsx(te,{value:k,onChange:c=>d(c.target.value),placeholder:"https://hooks.slack.com/… or env:SLACK_WEBHOOK",className:"h-8 text-xs font-mono flex-1"}),e.jsx(S,{size:"sm",className:"h-8",disabled:N||!(k.startsWith("https://")||k.startsWith("env:")),onClick:async()=>{w(!0);try{await ss(s,{channel:y,url:k.trim(),events:h}),d(""),E(["*"]),await x()}catch(c){C(c instanceof Error?c.message:"Create failed")}finally{w(!1)}},children:e.jsx(oe,{className:"h-3.5 w-3.5"})})]}),e.jsxs("div",{className:"flex items-center flex-wrap gap-1 text-[11px]",children:[e.jsx("button",{type:"button",className:`rounded-full border px-2 py-0.5 ${h.includes("*")?"bg-primary text-primary-foreground border-primary":"hover:bg-muted"}`,onClick:()=>O("*"),children:"all events"}),Ks.map(([c,L])=>e.jsx("button",{type:"button",className:`rounded-full border px-2 py-0.5 ${h.includes(c)?"bg-primary text-primary-foreground border-primary":"hover:bg-muted"}`,onClick:()=>O(c),children:L},c))]})]})]})]})}function hn(){const s=xs();return e.jsx(Ts,{nestId:s.nestId,nestName:s.nestName,onBack:s.leaveNest})}export{hn as default};
|
|
15
|
+
contextnest-runner:local poll`}),e.jsxs("p",{children:[e.jsx("b",{children:"poll"})," claims every run this server creates (Schedule tab, Run buttons) and executes it — one standing container per nest. No Anthropic key flag needed: set"," ",e.jsx("code",{children:"ANTHROPIC_API_KEY"})," in Activity → Tool environment and the runner picks it up from the run bundle. Steps stream back into the trace below — refresh to watch."]})]})]})]}),e.jsxs("div",{className:`grid gap-4 items-start ${d?"lg:grid-cols-[minmax(0,24rem)_minmax(0,1fr)]":"grid-cols-1"}`,children:[e.jsx("div",{className:"rounded-lg border divide-y min-w-0",children:E?e.jsx("div",{className:"px-3 py-6 text-center text-muted-foreground",children:e.jsx(J,{className:"h-4 w-4 animate-spin inline"})}):j.length===0?e.jsx("div",{className:"px-3 py-6 text-center text-xs text-muted-foreground",children:"No runs yet. Trigger an agent above."}):n.map(a=>Pe(a,0))}),d&&e.jsx("div",{className:"rounded-lg border p-4 min-w-0 lg:sticky lg:top-20",children:e.jsx(Ls,{run:d,children:j.filter(a=>a.parent_run_id===d.id),parent:d.parent_run_id?j.find(a=>a.id===d.parent_run_id)??null:null,label:I,typeOf:ue,onOpen:a=>void re(a),onCancel:a=>void G(a),cancelling:le===d.id})})]})]})}function Ls({run:s,children:m=[],parent:g=null,label:b=d=>d,typeOf:C=()=>{},onOpen:y,onCancel:j,cancelling:k=!1}){var d;return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[e.jsx(We,{type:C(s.agent_node),className:"h-4 w-4"}),e.jsx("span",{className:"font-mono text-sm",children:s.id}),e.jsx(se,{variant:tt(Ae(s)),title:qe(s)?Mt:void 0,children:Ae(s)}),(s.depth??0)>0&&e.jsxs(se,{variant:"outline",className:"text-[10px]",children:["sub-agent · depth ",s.depth]}),s.status==="running"&&j&&e.jsxs(S,{variant:"outline",size:"sm",className:"ml-auto h-7",disabled:k,onClick:()=>j(s.id),title:"Cancel this run",children:[k?e.jsx(J,{className:"h-3.5 w-3.5 mr-1 animate-spin"}):e.jsx($t,{className:"h-3.5 w-3.5 mr-1"}),"Cancel run"]})]}),e.jsxs("div",{className:"text-xs text-muted-foreground mb-4",children:["agent ",b(s.agent_node)," · started ",Ee(s.started_at),s.finished_at?` · finished ${Ee(s.finished_at)}`:""," · triggered by ",s.triggered_by]}),g&&e.jsxs("button",{type:"button",onClick:()=>y==null?void 0:y(g.id),className:"mb-3 inline-flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground",title:"Open the run that spawned this one",children:[e.jsx(js,{className:"h-3 w-3"})," Spawned by ",b(g.agent_node)," ",e.jsxs("span",{className:"font-mono",children:["(",g.id.slice(0,8),")"]})]}),m.length>0&&e.jsxs("div",{className:"mb-4 rounded-md border bg-muted/20 p-2.5",children:[e.jsxs("div",{className:"text-[10px] uppercase tracking-wide text-muted-foreground mb-1.5",children:["Sub-agents spawned (",m.length,")"]}),e.jsx("div",{className:"space-y-1",children:m.map(h=>e.jsxs("button",{type:"button",onClick:()=>y==null?void 0:y(h.id),className:"flex w-full items-center gap-2 rounded px-1.5 py-1 text-left text-xs hover:bg-muted/50",children:[e.jsx(nt,{className:"h-3 w-3 text-muted-foreground/50 shrink-0"}),e.jsx(We,{type:C(h.agent_node),className:"h-3.5 w-3.5"}),e.jsx("span",{className:"truncate",children:b(h.agent_node)}),e.jsx(se,{variant:tt(Ae(h)),className:"text-[10px] shrink-0",children:Ae(h)}),e.jsx("span",{className:"ml-auto font-mono text-[10px] text-muted-foreground shrink-0",children:h.id.slice(0,8)})]},h.id))})]}),((d=s.trace)==null?void 0:d.error)&&e.jsx("div",{className:"mb-3 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive font-mono break-all",children:s.trace.error}),e.jsx("div",{className:"space-y-0",children:s.steps.length===0?e.jsx("div",{className:"text-xs text-muted-foreground",children:qe(s)?"No steps yet — queued, waiting for a runner to claim it. Start a runner (see “How do I run one?” above) or cancel the run.":"No steps recorded."}):s.steps.map(h=>e.jsxs("div",{className:"grid grid-cols-[24px_1fr] gap-3 py-2 border-b border-dashed last:border-0",children:[e.jsx("div",{className:"text-muted-foreground pt-0.5",children:Es(h.action)}),e.jsxs("div",{children:[e.jsxs("div",{className:"text-xs",children:[e.jsxs("span",{className:"text-muted-foreground",children:[Ee(h.at)," ·"," "]}),e.jsx("span",{className:"font-medium",children:h.action}),h.node_id&&e.jsxs("span",{className:"font-mono text-muted-foreground",children:[" ",h.node_id]})]}),h.detail&&e.jsx("div",{className:"text-[11px] text-muted-foreground font-mono mt-0.5 break-all",children:typeof h.detail=="string"?h.detail:JSON.stringify(h.detail)})]})]},h.seq))})]})}const _e=168,je=56,Ws=260,zs=100,Se=30,Ze=70;function Fs({nestId:s}){const[m,g]=r.useState([]),[b,C]=r.useState([]),[y,j]=r.useState([]),[k,d]=r.useState(!0),[h,E]=r.useState(null),[N,w]=r.useState(null),[x,O]=r.useState(null),[c,L]=r.useState(null),[T,K]=r.useState(""),[D,q]=r.useState(""),[Y,U]=r.useState(""),[i,$]=r.useState(""),[W,he]=r.useState(">"),[ne,de]=r.useState(""),[be,pe]=r.useState(!1),[X,le]=r.useState(""),[ye,Ne]=r.useState([]),[we,H]=r.useState(60),[ae,re]=r.useState(""),[G,Te]=r.useState(1),[Z,$e]=r.useState(""),[Q,I]=r.useState(null),[ue,ie]=r.useState(!1),[ke,n]=r.useState(""),[v,P]=r.useState([]),[z,R]=r.useState(""),[Fe,ge]=r.useState([]),[Pe,a]=r.useState("slack"),[p,F]=r.useState({}),[me,fe]=r.useState(null),[V,at]=r.useState(0);r.useEffect(()=>{if(!me)return;const t=new ResizeObserver(o=>{var f;const u=((f=o[0])==null?void 0:f.contentRect.width)??0;u&&at(u)});return t.observe(me),at(me.clientWidth),()=>t.disconnect()},[me]);const xe=r.useCallback(async()=>{d(!0);try{const[t,o,u,f]=await Promise.all([ft(s),vt(s),Ue(s).then(_=>_.nodes).catch(()=>[]),jt(s).catch(()=>[])]);g(t),C(o),j(u),Ne(f),E(null)}catch(t){E(t instanceof Error?t.message:"Failed to load canvas")}finally{d(!1)}},[s]);r.useEffect(()=>{if(!x)return;let t=!1;return qt(s,x).then(o=>!t&&P(o.map(u=>u.user_email))).catch(()=>!t&&P([])),Je(s,x).then(o=>!t&&ge(o)).catch(()=>!t&&ge([])),()=>{t=!0}},[s,x]);const De=(t,o)=>{is(o).then(u=>{u&&($e(t),setTimeout(()=>$e(""),1500))})};r.useEffect(()=>{xe()},[xe]);const rt=new Map(y.map(t=>[t.id,t])),B=t=>{var o;return((o=rt.get(t))==null?void 0:o.title)||t.replace(/^nodes\//,"")},Re=t=>{var o;return(o=rt.get(t))==null?void 0:o.type},ot=m.filter(t=>t.type.is_flow),ee=new Map;{const t=new Set;for(const A of m)t.add(A.from_node),t.add(A.to_node);const o=new Map,u=new Set(ot.map(A=>A.to_node)),f=[...t].filter(A=>!u.has(A)).sort();for(const A of f)o.set(A,0);for(let A=0;A<t.size;A++){let l=!1;for(const M of ot){const ce=(o.get(M.from_node)??0)+1;ce>(o.get(M.to_node)??0)&&(o.set(M.to_node,ce),l=!0)}if(!l)break}const _=new Map;for(const A of[...t].sort((l,M)=>String(B(l)).localeCompare(B(M)))){const l=o.get(A)??0;_.has(l)||_.set(l,[]),_.get(l).push(A)}for(const[A,l]of _)l.forEach((M,ce)=>{ee.set(M,{id:M,x:Se+A*Ws,y:Ze+ce*zs})})}const Ot=Se*2+(Math.max(0,...[...ee.values()].map(t=>t.x))+_e+60),lt=Math.max(300,Ze+(Math.max(-Ze+40,...[...ee.values()].map(t=>t.y))+je+40)),He=ke.trim().toLowerCase(),Me=y.map(t=>t.id).filter(t=>!ee.has(t)).filter(t=>!He||B(t).toLowerCase().includes(He)||t.toLowerCase().includes(He)).sort((t,o)=>{const u=f=>Re(f)==="agent"?0:Re(f)==="skill"?1:2;return u(t)-u(o)||B(t).localeCompare(B(o))}),Oe=lt+46,it=Math.max(Ot,V>0?Math.floor(V):920),Xe=Math.max(1,Math.floor((it-Se*2)/(_e+46)));Me.forEach((t,o)=>{ee.set(t,{id:t,x:Se+o%Xe*(_e+46),y:Oe+Math.floor(o/Xe)*(je+28)})});const ct=it,Lt=Me.length?Oe+Math.ceil(Me.length/Xe)*(je+28)+30:lt+20,ve=(t,o)=>{const u=ee.get(t);return u?{x:o==="out"?u.x+_e:u.x,y:u.y+je/2}:{x:0,y:0}},Wt=(t,o,u=0)=>{const f=ve(t,"out"),_=ve(o,"in"),A=Math.max(40,(_.x-f.x)/2),l=u*4/3;return`M${f.x},${f.y} C${f.x+A},${f.y+l} ${_.x-A},${_.y+l} ${_.x},${_.y}`},Ge=new Map;{const t=new Map;for(const o of m){const u=`${o.from_node}\0${o.to_node}`,f=t.get(u)??[];f.push(o),t.set(u,f)}for(const o of t.values())o.length<2||o.forEach((u,f)=>Ge.set(u.id,(f-(o.length-1)/2)*34))}const dt=t=>t.type.color||(t.type.is_flow?"#34a853":"#94a3b8"),zt=m.filter(t=>ee.has(t.from_node)&&ee.has(t.to_node)).map(t=>{let o="";if(t.condition_mode==="nl"&&t.condition)o=`“${t.condition}”`;else if(t.condition_mode==="structured"&&t.condition)try{const _=typeof t.condition=="string"?JSON.parse(t.condition):t.condition;o=_!=null&&_.term?`${_.term} ${_.op??""} ${_.value??""}`:""}catch{}const u=ve(t.from_node,"out"),f=ve(t.to_node,"in");return{edge:t,x:(u.x+f.x)/2,y:(u.y+f.y)/2+(Ge.get(t.id)??0)-je/2-6,..._s(t.type.name,o)}}),Ve=t=>{if(O(null),I(null),w(t.id),K(t.type.name),q(t.condition_mode||""),t.condition_mode==="nl")U(String(t.condition??""));else if(t.condition_mode==="structured"&&t.condition)try{const o=typeof t.condition=="string"?JSON.parse(t.condition):t.condition;$(String(o.term??"")),he(String(o.op??">")),de(String(o.value??""))}catch{$(""),de("")}},Ft=async()=>{if(!N)return;const t=m.find(u=>u.id===N),o=t&&m.find(u=>u.id!==N&&u.from_node===t.from_node&&u.to_node===t.to_node&&u.type.name===T);if(o){E(`${B(o.from_node)} → ${B(o.to_node)} is already connected with "${T}".`);return}pe(!0);try{await os(s,N,{type:T,condition_mode:D||null,condition:D==="nl"?Y.trim():D==="structured"?{term:i.trim(),op:W,value:isNaN(Number(ne))?ne.trim():Number(ne)}:null}),await xe()}catch(u){E(u instanceof Error?u.message:"Failed to save edge")}finally{pe(!1)}},Dt=async t=>{try{await _t(s,t),w(null),await xe()}catch(o){E(o instanceof Error?o.message:"Failed to delete edge")}},ut=async(t,o)=>{var _,A;if(t===o)return;const u=((_=b.find(l=>l.is_flow))==null?void 0:_.name)??((A=b[0])==null?void 0:A.name);if(!u)return;const f=m.find(l=>l.from_node===t&&l.to_node===o&&l.type.name===u);if(f){E(`${B(t)} → ${B(o)} is already connected with "${u}".`),Ve(f);return}try{const l=await kt(s,{from_node:t,to_node:o,type:u,condition_mode:null,condition:null});await xe(),Ve(l)}catch(l){E(l instanceof Error?l.message:"Failed to connect")}},Ht=t=>{const o=t.currentTarget.closest("svg").getBoundingClientRect();return{x:t.clientX-o.left,y:t.clientY-o.top}},Le=m.find(t=>t.id===N)??null,Vt=[...new Set(m.map(dt))];return e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-[minmax(0,1fr)_300px] gap-4",children:[e.jsxs("div",{className:"rounded-lg border overflow-hidden bg-background",children:[e.jsxs("div",{className:"flex items-center gap-2 px-3 py-2 border-b text-xs text-muted-foreground",children:[e.jsxs("span",{className:"hidden md:inline",children:["Drag from a card's ",e.jsx("b",{children:"right port"})," onto another card to connect. Click a wire or card to edit it."]}),e.jsx("div",{className:"flex-1"}),e.jsx(te,{value:ke,onChange:t=>n(t.target.value),placeholder:"Find a document to wire in…",className:"h-7 w-56 text-xs","data-testid":"canvas-shelf-search"}),e.jsx(S,{variant:"outline",size:"sm",className:"h-7",onClick:()=>void xe(),children:e.jsx(st,{className:"h-3.5 w-3.5"})})]}),h&&e.jsx("div",{className:"mx-3 mt-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive whitespace-pre-line",children:h}),k?e.jsx("div",{className:"py-16 text-center text-muted-foreground",children:e.jsx(J,{className:"h-4 w-4 animate-spin inline"})}):ee.size===0?e.jsx("div",{className:"py-16 text-center text-sm text-muted-foreground",children:"No documents in this nest yet — create one from the Documents tab and it appears here, ready to wire up."}):e.jsx("div",{className:"overflow-auto max-h-[70vh]",ref:fe,children:e.jsxs("svg",{width:ct,height:Lt,ref:t=>{},style:{background:"radial-gradient(circle, hsl(var(--muted-foreground) / 0.18) 1px, transparent 1px)",backgroundSize:"20px 20px"},onMouseMove:t=>{if(!c)return;const o=t.currentTarget.getBoundingClientRect();L({...c,x:t.clientX-o.left,y:t.clientY-o.top})},onMouseUp:()=>L(null),onClick:()=>{w(null),O(null)},children:[e.jsx("defs",{children:Vt.map(t=>e.jsx("marker",{id:`ah-${t.replace(/[^a-z0-9]/gi,"")}`,markerWidth:"9",markerHeight:"9",refX:"7",refY:"3",orient:"auto",children:e.jsx("path",{d:"M0,0 L7,3 L0,6 z",fill:t})},t))}),m.map(t=>{if(!ee.has(t.from_node)||!ee.has(t.to_node))return null;const o=Ge.get(t.id)??0,u=Wt(t.from_node,t.to_node,o),f=dt(t);return e.jsxs("g",{children:[e.jsx("path",{d:u,fill:"none",stroke:f,strokeWidth:N===t.id?3:2,strokeDasharray:t.type.is_flow?void 0:"4 4",markerEnd:`url(#ah-${f.replace(/[^a-z0-9]/gi,"")})`,opacity:N&&N!==t.id?.45:1}),e.jsx("path",{d:u,fill:"none",stroke:"transparent",strokeWidth:14,style:{cursor:"pointer"},onClick:_=>{_.stopPropagation(),Ve(t)}})]},t.id)}),c&&e.jsx("path",{d:`M${ve(c.from,"out").x},${ve(c.from,"out").y} C${ve(c.from,"out").x+60},${ve(c.from,"out").y} ${c.x-60},${c.y} ${c.x},${c.y}`,fill:"none",stroke:"hsl(var(--primary))",strokeWidth:2,strokeDasharray:"5 4"}),Me.length>0&&e.jsxs("g",{children:[e.jsx("line",{x1:Se,y1:Oe-26,x2:ct-Se,y2:Oe-26,stroke:"hsl(var(--border))",strokeDasharray:"3 3"}),e.jsxs("text",{x:Se,y:Oe-32,style:{font:"10px sans-serif",fill:"hsl(var(--muted-foreground))"},children:["NOT WIRED IN YET (",Me.length,He?" matching":"",") — drag a right port onto any card to connect"]})]}),[...ee.values()].map(t=>{const o=Re(t.id),u=x===t.id;return e.jsxs("g",{children:[e.jsx("foreignObject",{x:t.x,y:t.y,width:_e,height:je+6,children:e.jsxs("div",{className:`rounded-lg border-2 bg-background px-2.5 py-1.5 shadow-sm cursor-pointer select-none ${u?"border-primary ring-2 ring-primary/20":"border-border"}`,style:{width:_e,height:je},onClick:f=>{f.stopPropagation(),w(null),I(null),O(t.id)},onMouseUp:()=>{c&&c.from!==t.id&&(ut(c.from,t.id),L(null))},title:t.id,children:[e.jsxs("div",{className:"flex items-center gap-1 text-[10px] uppercase tracking-wide text-muted-foreground",children:[e.jsx(Ce,{type:o}),o??"document"]}),e.jsx("div",{className:"text-xs font-semibold truncate mt-0.5",children:B(t.id)})]})}),e.jsx("circle",{cx:t.x+_e,cy:t.y+je/2,r:6,fill:"hsl(var(--background))",stroke:"hsl(var(--primary))",strokeWidth:1.5,style:{cursor:"crosshair"},onMouseDown:f=>{f.stopPropagation(),f.preventDefault();const _=Ht(f);L({from:t.id,x:_.x,y:_.y})}})]},t.id)}),zt.map(t=>e.jsxs("g",{style:{cursor:"pointer"},onClick:o=>{o.stopPropagation(),Ve(t.edge)},children:[e.jsx("title",{children:t.full}),e.jsx("rect",{x:t.x-t.width/2,y:t.y-9,width:t.width,height:13,rx:3,fill:"hsl(var(--background))",opacity:.92}),e.jsx("text",{x:t.x,y:t.y,textAnchor:"middle",style:{font:"10px ui-monospace, monospace",fill:"hsl(var(--muted-foreground))"},children:t.short})]},`label-${t.edge.id}`))]})})]}),e.jsx("div",{className:"rounded-lg border p-4 h-fit",children:Le?e.jsxs("div",{children:[e.jsxs("h3",{className:"text-sm font-semibold",children:["Edge · ",Le.type.name]}),e.jsxs("p",{className:"text-xs text-muted-foreground mb-3",children:[B(Le.from_node)," → ",B(Le.to_node)]}),e.jsx("label",{className:"block text-[10px] uppercase tracking-wide text-muted-foreground mb-1",children:"Type"}),e.jsx("select",{value:T,onChange:t=>K(t.target.value),className:"w-full h-8 rounded-md border bg-background px-2 text-sm mb-3",children:b.map(t=>e.jsxs("option",{value:t.name,children:[t.is_flow?"▶ ":"",t.name]},t.id))}),e.jsx("label",{className:"block text-[10px] uppercase tracking-wide text-muted-foreground mb-1",children:"Fires"}),e.jsx("div",{className:"flex items-center rounded-md border h-8 text-xs overflow-hidden w-fit mb-2",children:[["","always"],["nl","if…"],["structured","metric"]].map(([t,o],u)=>e.jsx("button",{type:"button",className:`px-2.5 h-full ${u>0?"border-l":""} ${D===t?"bg-primary text-primary-foreground":"hover:bg-muted"}`,onClick:()=>q(t),children:o},t))}),D==="nl"&&e.jsx(te,{value:Y,onChange:t=>U(t.target.value),placeholder:'e.g. "lost on price, not product"',className:"h-8 text-sm italic mb-2"}),D==="structured"&&e.jsxs("div",{className:"grid grid-cols-[1fr_58px_1fr] gap-1.5 mb-2",children:[e.jsx(te,{value:i,onChange:t=>$(t.target.value),placeholder:"CAC",className:"h-8 text-sm font-mono"}),e.jsx("select",{value:W,onChange:t=>he(t.target.value),className:"h-8 rounded-md border bg-background px-1 text-sm font-mono",children:[">","<",">=","<=","=","!="].map(t=>e.jsx("option",{value:t,children:t},t))}),e.jsx(te,{value:ne,onChange:t=>de(t.target.value),placeholder:"500",className:"h-8 text-sm font-mono"})]}),e.jsxs("div",{className:"flex gap-2 mt-4",children:[e.jsx(S,{size:"sm",className:"flex-1",disabled:be,onClick:()=>void Ft(),children:be?e.jsx(J,{className:"h-3.5 w-3.5 animate-spin"}):"Save"}),e.jsx(S,{size:"sm",variant:"outline",className:"text-destructive",onClick:()=>void Dt(Le.id),children:"Delete"})]})]}):x?(()=>{const t=["agent","skill"].includes(Re(x)??""),o=ye.find(l=>l.agent_node===x),u=window.location.origin,f=`[[${B(x)}]]`,_=`curl -s -X POST ${u}/nests/${s}/context -H 'Content-Type: application/json' -d '{"selector":"${f}","hops":${G},"max_tokens":4000}'`,A=`curl -s -X PATCH ${u}/nests/${s}/nodes/${x} -H 'Content-Type: application/json' -d '{"append":"<your update>","changeNote":"via ctx"}'`;return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Ce,{type:Re(x)}),e.jsx("h3",{className:"text-sm font-semibold truncate",children:B(x)})]}),e.jsx("p",{className:"text-xs text-muted-foreground font-mono truncate",children:x})]}),t&&e.jsxs("div",{className:"space-y-2",children:[e.jsxs(S,{size:"sm",className:"w-full",onClick:async()=>{try{await Qe(s,x),re("Run created — a polling runner will pick it up"),setTimeout(()=>re(""),3e3)}catch(l){E(l instanceof Error?l.message:"Trigger failed")}},children:[e.jsx(Pt,{className:"h-3.5 w-3.5 mr-1.5"})," Run now"]}),ae&&e.jsx("p",{className:"text-[11px] text-emerald-600",children:ae}),e.jsx("label",{className:"block text-[10px] uppercase tracking-wide text-muted-foreground",children:"Schedule"}),o?e.jsxs("div",{className:"rounded-md border px-2.5 py-2 text-xs space-y-1.5",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("span",{children:["every"," ",e.jsx("b",{children:o.every_minutes>=60?`${o.every_minutes/60}h`:`${o.every_minutes}m`}),o.enabled?"":" · paused"]}),e.jsx("div",{className:"flex-1"}),e.jsx("button",{type:"button",className:"text-primary hover:underline",onClick:async()=>{await Ie(s,o.id,{enabled:!o.enabled}),await xe()},children:o.enabled?"Pause":"Resume"}),e.jsx("button",{type:"button",className:"text-destructive hover:underline",onClick:async()=>{await bt(s,o.id),await xe()},children:"Remove"})]}),o.enabled&&o.next_due_at&&e.jsxs("div",{className:"text-muted-foreground",children:["next fire ~",Ee(o.next_due_at)]})]}):e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsxs("select",{value:we,onChange:l=>H(Number(l.target.value)),className:"h-8 rounded-md border bg-background px-2 text-sm flex-1",children:[e.jsx("option",{value:15,children:"every 15 minutes"}),e.jsx("option",{value:60,children:"every hour"}),e.jsx("option",{value:360,children:"every 6 hours"}),e.jsx("option",{value:1440,children:"every day"})]}),e.jsx(S,{size:"sm",className:"h-8",onClick:async()=>{try{await yt(s,{agent_node:x,every_minutes:we}),await xe()}catch(l){E(l instanceof Error?l.message:"Schedule failed")}},children:"Schedule"})]})]}),t&&e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("label",{className:"block text-[10px] uppercase tracking-wide text-muted-foreground",children:"Triggers — call this agent from outside"}),Fe.map(l=>e.jsxs("div",{className:"rounded-md border px-2 py-1.5 text-[11px] space-y-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(se,{variant:"secondary",className:"text-[10px]",children:l.preset}),e.jsxs("span",{className:"text-muted-foreground",children:["fired ",l.fire_count,"×"]}),e.jsx("div",{className:"flex-1"}),e.jsx("button",{type:"button",className:"text-destructive hover:underline",onClick:async()=>{await Ut(s,l.id),ge(await Je(s,x))},children:"Remove"})]}),l.url??p[l.id]?e.jsx("button",{type:"button",className:"w-full text-left font-mono break-all rounded bg-muted/40 px-1.5 py-1 hover:border-primary border border-transparent",title:"Copy the trigger URL — paste into a Slack slash command / Events API, Teams outgoing webhook, or any system that can POST",onClick:()=>De(`hook-${l.id}`,l.url??p[l.id]),children:Z===`hook-${l.id}`?"✓ copied":l.url??p[l.id]}):e.jsx("p",{className:"text-muted-foreground px-1.5",children:"URL was shown at creation only (like an API key). Remove + re-add to mint a fresh one."})]},l.id)),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsxs("select",{value:Pe,onChange:l=>a(l.target.value),className:"h-7 rounded-md border bg-background px-1.5 text-xs flex-1",children:[e.jsx("option",{value:"slack",children:"Slack (slash command / @mention)"}),e.jsx("option",{value:"teams",children:"Teams (outgoing webhook)"}),e.jsx("option",{value:"webhook",children:"Webhook (any system)"})]}),e.jsx(S,{size:"sm",variant:"outline",className:"h-7 px-2",onClick:async()=>{const l=await Xt(s,x,Pe);if(l.url){const M=`${l.id.slice(0,7)}…${l.id.slice(-4)}`;F(ce=>({...ce,[M]:l.url}))}ge(await Je(s,x))},children:e.jsx(oe,{className:"h-3.5 w-3.5"})})]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Each trigger is a secret URL that queues a run — message text becomes the run's inputs. Add SLACK_SIGNING_SECRET to the Tool environment to verify Slack requests."})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("label",{className:"block text-[10px] uppercase tracking-wide text-muted-foreground",children:"Notify on output"}),v.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1",children:v.map(l=>e.jsxs("span",{className:"inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[11px]",children:[l,e.jsx("button",{type:"button",className:"text-muted-foreground hover:text-destructive",title:"Stop notifying",onClick:async()=>{const M=await Gt(s,x,l);P(M.map(ce=>ce.user_email))},children:"✕"})]},l))}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(te,{value:z,onChange:l=>R(l.target.value),placeholder:"person@team.com",className:"h-7 text-xs flex-1",onKeyDown:async l=>{if(l.key==="Enter"&&z.includes("@")){const M=await mt(s,x,z.trim());P(M.map(ce=>ce.user_email)),R("")}}}),e.jsx(S,{size:"sm",variant:"outline",className:"h-7 px-2",disabled:!z.includes("@"),onClick:async()=>{const l=await mt(s,x,z.trim());P(l.map(M=>M.user_email)),R("")},children:e.jsx(oe,{className:"h-3.5 w-3.5"})})]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Tagged people get an inbox notification when this node's output lands for review. (Slack/webhook delivery comes later — same table.)"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[10px] uppercase tracking-wide text-muted-foreground mb-1",children:"Add a step after this"}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsxs("select",{value:X,onChange:l=>le(l.target.value),className:"h-8 rounded-md border bg-background px-2 text-sm flex-1 min-w-0",children:[e.jsx("option",{value:"",children:"Choose a document…"}),y.filter(l=>l.id!==x).map(l=>e.jsx("option",{value:l.id,children:l.title||l.id},l.id))]}),e.jsx(S,{size:"sm",className:"h-8",disabled:!X,onClick:()=>{ut(x,X),le("")},children:e.jsx(oe,{className:"h-3.5 w-3.5"})})]}),e.jsx("p",{className:"text-[11px] text-muted-foreground mt-1.5",children:"Or drag from the node's right port straight onto another card."})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("label",{className:"text-[10px] uppercase tracking-wide text-muted-foreground",children:"Use from CLI / agent"}),e.jsx("div",{className:"flex-1"}),e.jsx("select",{value:G,onChange:l=>Te(Number(l.target.value)),className:"h-6 rounded border bg-background px-1 text-[11px]",title:"How many hops of linked context to pull with it",children:[0,1,2,3].map(l=>e.jsxs("option",{value:l,children:[l," hop",l===1?"":"s"]},l))})]}),e.jsx("button",{type:"button",className:"w-full text-left rounded-md border bg-muted/40 px-2 py-1.5 text-[10.5px] font-mono break-all hover:border-primary",onClick:()=>De("sel",f),title:"Copy the selector",children:Z==="sel"?"✓ copied":f}),e.jsx("button",{type:"button",className:"w-full text-left rounded-md border bg-muted/40 px-2 py-1.5 text-[10.5px] font-mono break-all hover:border-primary",onClick:()=>De("read",_),title:"Copy — deterministic read: this node + linked context",children:Z==="read"?"✓ copied":`read → ${_.slice(0,64)}…`}),e.jsx("button",{type:"button",className:"w-full text-left rounded-md border bg-muted/40 px-2 py-1.5 text-[10.5px] font-mono break-all hover:border-primary",onClick:()=>De("write",A),title:"Copy — governed write: append to this node (lands as a new version / review request)",children:Z==="write"?"✓ copied":`write → ${A.slice(0,64)}…`}),e.jsx(S,{variant:"outline",size:"sm",className:"w-full h-7 text-xs",disabled:ue,onClick:async()=>{var l;ie(!0);try{const M=await Jt(s,f,G);I({text:M.context||"(empty context)",nodes:((l=M.trace)==null?void 0:l.nodes_traversed)??M.nodes_traversed??0})}catch(M){E(M instanceof Error?M.message:"Preview failed")}finally{ie(!1)}},children:ue?e.jsx(J,{className:"h-3.5 w-3.5 animate-spin"}):e.jsxs(e.Fragment,{children:["Test: preview what it reads (",G," hop",G===1?"":"s",")"]})}),Q&&e.jsxs("div",{className:"rounded-md border bg-muted/30 p-2",children:[e.jsxs("div",{className:"flex items-center text-[10px] text-muted-foreground mb-1",children:[e.jsxs("span",{children:[Q.nodes," node",Q.nodes===1?"":"s"," assembled — exactly what a run reads"]}),e.jsx("button",{type:"button",className:"ml-auto hover:text-foreground",onClick:()=>I(null),children:"✕"})]}),e.jsxs("pre",{className:"max-h-56 overflow-auto whitespace-pre-wrap text-[10.5px] leading-relaxed",children:[Q.text.slice(0,4e3),Q.text.length>4e3?`
|
|
16
|
+
…(truncated)`:""]})]})]})]})})():e.jsxs("div",{className:"text-sm text-muted-foreground",children:[e.jsx("p",{className:"font-medium text-foreground mb-1",children:"Nothing selected"}),e.jsxs("p",{className:"text-xs",children:["Click a ",e.jsx("b",{children:"wire"})," to change its type or condition, click a"," ",e.jsx("b",{children:"card"})," to add a next step, or drag from a card's right port onto another card to connect them."]})]})})]})}function Ds({nestId:s}){const[m,g]=r.useState([]),[b,C]=r.useState([]),[y,j]=r.useState(!0),[k,d]=r.useState(null),[h,E]=r.useState(""),[N,w]=r.useState(60),[x,O]=r.useState(""),[c,L]=r.useState(!1),T=r.useCallback(async()=>{j(!0);try{const[i,$]=await Promise.all([jt(s),Ue(s).then(W=>W.nodes).catch(()=>[])]);g(i),C($),d(null)}catch(i){d(i instanceof Error?i.message:"Failed to load schedules")}finally{j(!1)}},[s]);r.useEffect(()=>{T()},[T]);const K=i=>{var $;return(($=b.find(W=>W.id===i))==null?void 0:$.title)||i.replace(/^nodes\//,"")},D=i=>{var $;return($=b.find(W=>W.id===i))==null?void 0:$.type},q=b.filter(i=>i.type==="agent"||i.type==="skill"),Y=q.filter(i=>!m.some($=>$.agent_node===i.id)),U=i=>i>=1440?`${i/1440}d`:i>=60?`${i/60}h`:`${i}m`;return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("p",{className:"text-sm text-muted-foreground",children:["A schedule decides ",e.jsx("b",{children:"when a run starts"})," and its stop-after bound decides ",e.jsx("b",{children:"when it's done"}),". What happens ",e.jsx("em",{children:"inside"})," a run — which step fires, on what condition — lives on the wires in the Canvas (click a wire to set always / if… / metric). Scheduled output still lands as a review request; scheduling doesn't skip governance."]}),k&&e.jsx("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:k}),y?e.jsx("div",{className:"py-8 text-center text-muted-foreground",children:e.jsx(J,{className:"h-4 w-4 animate-spin inline"})}):m.length===0?e.jsxs("div",{className:"rounded-lg border border-dashed p-6 text-center",children:[e.jsx(ws,{className:"h-6 w-6 text-muted-foreground/50 mx-auto mb-2"}),e.jsx("p",{className:"text-sm font-medium mb-1",children:"Nothing on the clock yet"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:q.length?"Pick an agent below — every interval, the server files a run for it.":"This nest has no runnable agents yet. Create one from Documents → New → type Agent (its body is the instructions), then schedule it here."})]}):e.jsx("div",{className:"rounded-lg border divide-y",children:m.map(i=>e.jsxs("div",{className:"px-3 py-2.5 flex items-center gap-2 text-sm",children:[e.jsx(Ce,{type:D(i.agent_node)}),e.jsx("span",{className:"truncate font-medium",title:i.agent_node,children:K(i.agent_node)}),e.jsxs(se,{variant:"secondary",className:"text-[10px] shrink-0",children:["every ",U(i.every_minutes)]}),i.max_runs!==null&&e.jsxs(se,{variant:"outline",className:"text-[10px] shrink-0",title:"Stops automatically after this many runs",children:[i.runs_created,"/",i.max_runs," runs"]}),i.enabled?i.next_due_at&&e.jsxs("span",{className:"text-[11px] text-muted-foreground shrink-0",children:["next ~",Ee(i.next_due_at)]}):i.max_runs!==null&&i.runs_created>=i.max_runs?e.jsx(se,{className:"text-[10px] shrink-0 bg-emerald-600",children:"done"}):e.jsx(se,{variant:"outline",className:"text-[10px] shrink-0",children:"paused"}),e.jsx("div",{className:"flex-1"}),e.jsxs("select",{value:i.every_minutes,onChange:async $=>{await Ie(s,i.id,{every_minutes:Number($.target.value)}),await T()},className:"h-7 rounded-md border bg-background px-1.5 text-xs shrink-0",title:"Change the interval",children:[[15,60,360,1440].map($=>e.jsx("option",{value:$,children:U($)},$)),![15,60,360,1440].includes(i.every_minutes)&&e.jsx("option",{value:i.every_minutes,children:U(i.every_minutes)})]}),e.jsx(S,{variant:"outline",size:"sm",className:"h-7 text-xs shrink-0",onClick:async()=>{await Ie(s,i.id,{enabled:!i.enabled}),await T()},children:i.enabled?"Pause":"Resume"}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-7 w-7 text-muted-foreground hover:text-destructive shrink-0",onClick:async()=>{await bt(s,i.id),await T()},title:"Remove schedule",children:e.jsx(ze,{className:"h-3.5 w-3.5"})})]},i.id))}),e.jsxs("div",{className:"rounded-lg border bg-muted/20 p-3",children:[e.jsx("div",{className:"text-xs font-medium mb-2",children:"Put an agent on the clock"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("select",{value:h,onChange:i=>E(i.target.value),className:"h-8 rounded-md border bg-background px-2 text-sm flex-1 min-w-0","data-testid":"schedule-agent-lookup",children:[e.jsx("option",{value:"",children:Y.length?"Choose an agent…":"Every runnable agent is scheduled"}),Y.map(i=>e.jsxs("option",{value:i.id,children:[i.type==="agent"?"🤖 ":"⚡ ",i.title||i.id]},i.id))]}),e.jsxs("select",{value:N,onChange:i=>w(Number(i.target.value)),className:"h-8 rounded-md border bg-background px-2 text-sm",children:[e.jsx("option",{value:15,children:"every 15 minutes"}),e.jsx("option",{value:60,children:"every hour"}),e.jsx("option",{value:360,children:"every 6 hours"}),e.jsx("option",{value:1440,children:"every day"})]}),e.jsxs("select",{value:x,onChange:i=>O(i.target.value===""?"":Number(i.target.value)),className:"h-8 rounded-md border bg-background px-2 text-sm",title:"The stop condition: pause automatically after this many runs",children:[e.jsx("option",{value:"",children:"until stopped"}),e.jsx("option",{value:1,children:"once"}),e.jsx("option",{value:5,children:"stop after 5"}),e.jsx("option",{value:10,children:"stop after 10"}),e.jsx("option",{value:25,children:"stop after 25"})]}),e.jsxs(S,{size:"sm",className:"h-8",disabled:c||!h,onClick:async()=>{L(!0);try{await yt(s,{agent_node:h,every_minutes:N,max_runs:x===""?null:x}),E(""),await T()}catch(i){d(i instanceof Error?i.message:"Schedule failed")}finally{L(!1)}},children:[e.jsx(oe,{className:"h-3.5 w-3.5 mr-1"})," Schedule"]})]})]})]})}function Hs({nestId:s}){const[m,g]=r.useState([]),[b,C]=r.useState(null),[y,j]=r.useState(""),[k,d]=r.useState(""),[h,E]=r.useState(!1),N=r.useCallback(async()=>{try{g(await Nt(s)),C(null)}catch(w){C(w instanceof Error?w.message:"Failed to load env")}},[s]);return r.useEffect(()=>{N()},[N]),e.jsxs("details",{className:"rounded-lg border px-4 py-3",children:[e.jsxs("summary",{className:"cursor-pointer select-none text-sm font-medium flex items-center gap-2",children:[e.jsx(At,{className:"h-4 w-4 text-teal-500 inline"})," Tool environment (",m.length," key",m.length===1?"":"s",")"]}),e.jsxs("div",{className:"mt-3 space-y-3",children:[e.jsxs("p",{className:"text-[11px] text-muted-foreground",children:["Credentials for ",e.jsx("b",{children:"tool"})," nodes. Values are write-only here and travel to the runner inside the run bundle. Stored alongside nest content, not encrypted — treat this box like the nest itself."]}),b&&e.jsx("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:b}),m.length>0&&e.jsx("div",{className:"rounded-md border divide-y",children:m.map(w=>e.jsxs("div",{className:"px-3 py-1.5 flex items-center gap-2 text-xs",children:[e.jsx("span",{className:"font-mono font-medium",children:w.key}),e.jsx("span",{className:"font-mono text-muted-foreground",children:w.value_masked}),e.jsx("div",{className:"flex-1"}),e.jsx("span",{className:"text-muted-foreground",children:w.updated_by}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6 text-muted-foreground hover:text-destructive",title:"Delete key",onClick:async()=>{await ns(s,w.key),await N()},children:e.jsx(ze,{className:"h-3.5 w-3.5"})})]},w.key))}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(te,{value:y,onChange:w=>j(w.target.value.toUpperCase()),placeholder:"SLACK_TOKEN",className:"h-8 text-xs font-mono w-44"}),e.jsx(te,{value:k,onChange:w=>d(w.target.value),placeholder:"value (write-only)",type:"password",className:"h-8 text-xs font-mono flex-1"}),e.jsx(S,{size:"sm",className:"h-8",disabled:h||!/^[A-Z][A-Z0-9_]*$/.test(y)||!k,onClick:async()=>{E(!0);try{await wt(s,y,k),j(""),d(""),await N()}catch(w){C(w instanceof Error?w.message:"Save failed")}finally{E(!1)}},children:h?e.jsx(J,{className:"h-3.5 w-3.5 animate-spin"}):"Set"})]})]})]})}function Vs({nestId:s}){const[m,g]=r.useState(null),[b,C]=r.useState(""),[y,j]=r.useState(!1),[k,d]=r.useState(null),[h,E]=r.useState(!1);return r.useEffect(()=>{let N=!1;return Promise.all([Nt(s).catch(()=>null),Qt().catch(()=>null)]).then(([w,x])=>{if(!N){if(x!=null&&x.runner_key_configured)return g(!0);if(!w)return g(null);g(w.some(O=>O.key==="ANTHROPIC_API_KEY"))}}),()=>{N=!0}},[s]),m!==!1?h?e.jsx("div",{className:"rounded-lg border border-emerald-400/50 bg-emerald-500/5 px-4 py-3 text-sm",children:"✓ Key stored (masked from here on). Runners pick it up from the run bundle — start one in poll mode and your queued runs execute."}):null:e.jsxs("div",{className:"rounded-lg border border-amber-400/60 bg-amber-500/5 px-4 py-3",children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"🔑 Add your Anthropic API key to execute runs"}),e.jsx("p",{className:"text-xs text-muted-foreground mb-2",children:"Runs are created here, but a runner needs a key to call the model. Paste it once — it's stored write-only for this nest (masked everywhere, delivered to runners inside the run bundle). Get one at console.anthropic.com → Settings → API keys."}),k&&e.jsx("p",{className:"text-xs text-destructive mb-2",children:k}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(te,{type:"password",value:b,onChange:N=>C(N.target.value),placeholder:"sk-ant-…",className:"h-8 text-sm font-mono flex-1","data-testid":"runner-key-input"}),e.jsx(S,{size:"sm",className:"h-8",disabled:y||!b.trim().startsWith("sk-"),onClick:async()=>{j(!0);try{await wt(s,"ANTHROPIC_API_KEY",b.trim()),C(""),g(!0),E(!0)}catch(N){d(N instanceof Error?N.message:"Save failed")}finally{j(!1)}},children:y?e.jsx(J,{className:"h-3.5 w-3.5 animate-spin"}):"Save key"})]})]})}const Bs=[["review_requested","review requested"],["review_approved","approved"],["review_rejected","rejected"],["run_failed","run failed"],["mention","mentioned"]];function Ks({nestId:s}){const[m,g]=r.useState([]),[b,C]=r.useState(null),[y,j]=r.useState("slack"),[k,d]=r.useState(""),[h,E]=r.useState(["*"]),[N,w]=r.useState(!1),x=r.useCallback(async()=>{try{g(await It(s)),C(null)}catch(c){C(c instanceof Error?c.message:"Failed to load connectors")}},[s]);r.useEffect(()=>{x()},[x]);const O=c=>{E(L=>{if(c==="*")return["*"];const T=L.filter(K=>K!=="*"&&K!==c);return L.includes(c)?T.length?T:["*"]:[...T,c]})};return e.jsxs("details",{className:"rounded-lg border px-4 py-3",open:m.length>0,children:[e.jsxs("summary",{className:"cursor-pointer select-none text-sm font-medium",children:["📤 Connectors (",m.length,") — send events to Slack / Teams / webhooks"]}),e.jsxs("div",{className:"mt-3 space-y-3",children:[e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Governance + run events post to each matching channel. Fire-and-forget — a channel outage never blocks a review. The server-wide Slack webhook (super-admin Settings) always fires too."}),b&&e.jsx("div",{className:"rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:b}),m.length>0&&e.jsx("div",{className:"rounded-md border divide-y",children:m.map(c=>e.jsxs("div",{className:"px-3 py-2 flex items-center gap-2 text-xs",children:[e.jsx(se,{variant:"secondary",className:"text-[10px] shrink-0",children:c.channel}),e.jsx("span",{className:"font-mono truncate",children:c.url}),e.jsx("span",{className:"text-muted-foreground shrink-0",children:c.events.includes("*")?"all events":c.events.join(", ")}),e.jsx("div",{className:"flex-1"}),e.jsx(S,{variant:"outline",size:"sm",className:"h-6 text-[11px] px-2 shrink-0",onClick:async()=>{await es(s,c.id,{enabled:!c.enabled}),await x()},children:c.enabled?"Pause":"Resume"}),e.jsx(S,{variant:"ghost",size:"icon",className:"h-6 w-6 text-muted-foreground hover:text-destructive shrink-0",onClick:async()=>{await ts(s,c.id),await x()},title:"Delete connector",children:e.jsx(ze,{className:"h-3.5 w-3.5"})})]},c.id))}),e.jsxs("div",{className:"space-y-2 rounded-md border bg-muted/20 p-2.5",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsxs("select",{value:y,onChange:c=>j(c.target.value),className:"h-8 rounded-md border bg-background px-1.5 text-xs",children:[e.jsx("option",{value:"slack",children:"Slack"}),e.jsx("option",{value:"teams",children:"Teams"}),e.jsx("option",{value:"webhook",children:"Webhook (raw JSON)"})]}),e.jsx(te,{value:k,onChange:c=>d(c.target.value),placeholder:"https://hooks.slack.com/… or env:SLACK_WEBHOOK",className:"h-8 text-xs font-mono flex-1"}),e.jsx(S,{size:"sm",className:"h-8",disabled:N||!(k.startsWith("https://")||k.startsWith("env:")),onClick:async()=>{w(!0);try{await ss(s,{channel:y,url:k.trim(),events:h}),d(""),E(["*"]),await x()}catch(c){C(c instanceof Error?c.message:"Create failed")}finally{w(!1)}},children:e.jsx(oe,{className:"h-3.5 w-3.5"})})]}),e.jsxs("div",{className:"flex items-center flex-wrap gap-1 text-[11px]",children:[e.jsx("button",{type:"button",className:`rounded-full border px-2 py-0.5 ${h.includes("*")?"bg-primary text-primary-foreground border-primary":"hover:bg-muted"}`,onClick:()=>O("*"),children:"all events"}),Bs.map(([c,L])=>e.jsx("button",{type:"button",className:`rounded-full border px-2 py-0.5 ${h.includes(c)?"bg-primary text-primary-foreground border-primary":"hover:bg-muted"}`,onClick:()=>O(c),children:L},c))]})]})]})]})}function mn(){const s=xs();return e.jsx(Ts,{nestId:s.nestId,nestName:s.nestName,onBack:s.leaveNest})}export{mn as default};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{r as l,j as e,c6 as h,c7 as m,c9 as u,c8 as p,B as b,aD as se,aI as te,ca as x,h as We,e as Te,aW as qe,aX as Ke,S as Oe,u as Pe,e1 as Ve,e2 as Ye,l as ne,i as z,bK as X,L as I,V as Qe,W as Je,Y as Xe,Z as E,$ as j,N as M,b4 as ve,U as Ze,d3 as es,C as ss,dp as ts,au as ns,D as je,G as be,H as ke,J as we,K as Ne,I as $,M as Ce,d4 as as,E as rs,e3 as Se,e4 as is,e5 as os,e6 as ls}from"./index-DvuUIUP6.js";import{P as cs}from"./page-title-Dn5jANiU.js";import{E as ds}from"./earth-BmMbVt9k.js";import{T as hs}from"./trash-2-aljmIff4.js";function Ie(n){return`${n.replace(/["'`\\$;|&<>(){}\s]/g,"").replace(/\/+$/,"")}/mcp`}function A(...n){return n.filter(i=>i!==null).join(`
|
|
2
|
+
`)}const q="<your ContextNest API key>",L="CONTEXTNEST_API_KEY";function ms(n,i,t,y){return[`**Not connectable yet.** ${t}`,"",n.openMode?`This server needs no credential at all, but ${i} still wants an OAuth client to authorize against, and this server runs no authorization server to offer it. There is no header field to fall back to either.`:`This server authenticates with API keys and does not run an OAuth authorization server, so ${i} has nothing to complete its consent flow against. There is no header field to fall back to.`,"",`The endpoint it would point at is \`${y}\`, so nothing here changes once an authorization server ships.`,"","Until then, the workable routes are:","","- Use one of the other harnesses in this panel.","- Or drive the nest through the REST API directly."].join(`
|
|
3
|
+
`)}const K=[{id:"claude-desktop",name:"Claude (claude.ai and Claude Desktop)",kind:"chat",where:"Customize → Connectors → Add custom connector",open:"https://claude.ai/customize/connectors",docs:"https://claude.com/docs/connectors/custom/remote-mcp",support:"header",body:(n,i)=>A("1. Open **Customize → Connectors** and click **Add custom connector**. On Team and Enterprise plans an Owner adds it once under **Organization settings → Connectors → Add → Custom → Web**; members then find it under **Customize → Connectors** and click **Connect**.",`2. Set the MCP server URL to \`${i}\`.`,n.openMode?"3. For **Authentication**, choose **No sign-in** — this server needs no credential.":`3. For **Authentication**, choose **No sign-in**, then open **Request headers**, pick the \`authorization\` header and enter \`Bearer ${q}\` as its value. Enter the value only — Claude adds the header name itself and sends the value exactly as typed, so the \`Bearer \` prefix and its trailing space have to be there.`,"4. Click **Add**. Authentication settings can't be changed afterwards; changing them means removing the connector and adding it again.",n.openMode?null:"",n.openMode?null:"> **Request headers are in beta, and the credential is organization-wide.** If the dialog has no **Request headers** section, your organization doesn't have access yet. Everyone on the connector shares the one credential, so on this surface they all reach this server as the key's owner and see that person's nests. Per-user visibility here needs OAuth, which this server doesn't run yet — for per-user nests today, use one of the command-line harnesses.","","> The MCP client runs on Anthropic's servers, not the user's machine, so this URL must resolve on the public internet and present a valid TLS certificate. A `localhost` or internal-DNS address will not work here.")},{id:"chatgpt",name:"ChatGPT",kind:"chat",where:"Settings → Security and login → Developer mode",docs:"https://developers.openai.com/plugins/deploy/connect-chatgpt",support:"header",body:(n,i)=>A("1. Open **Settings → Security and login** and turn on **Developer mode**.","2. Go to the **Plugins** page and click the **+** button.","3. Give it a name and description you'll recognise in the tools menu later.",`4. Under **Connection**, paste the MCP server URL \`${i}\` — including the \`/mcp\` path.`,"5. Create the connection, then add it from the **tools menu** in a new conversation.","","Developer mode is available on Plus, Pro, Business, Enterprise and Edu — not on the free tier. Public HTTPS is required.",n.openMode?null:"",n.openMode?null:"> **This surface may not connect yet.** The connection step takes a URL and discovers the server's own authentication; OpenAI documents no field for a fixed API key or `Authorization` header. If the connection fails asking you to sign in, this server has no OAuth authorization server to offer it — use one of the command-line harnesses instead.","","> ChatGPT renamed this surface in July 2026. Older guides point at **Settings → Connectors → Advanced**, which no longer exists.")},{id:"grok",name:"Grok",kind:"chat",where:"grok.com/connectors → New Connector → Custom",open:"https://grok.com/connectors",docs:"https://docs.x.ai/grok/connectors",support:"header",body:(n,i)=>A("1. Go to **grok.com/connectors** and choose **New Connector → Custom**.",`2. Enter the MCP server URL \`${i}\`.`,n.openMode?"3. Leave authentication empty.":`3. Complete any authentication the form asks for, supplying \`Bearer ${q}\` where it wants a credential.`,"4. Grok discovers the exposed tools and offers them alongside its built-in connectors.","","The server must be reachable over the public internet; Grok has no tunnel of its own.",n.openMode?null:"",n.openMode?null:"> xAI documents the connector form but not which credentials it accepts, so the authentication step isn't verified here. If it only offers OAuth, this server has none to offer yet — use a command-line harness instead.")},{id:"perplexity",name:"Perplexity",kind:"chat",where:"All settings → Connectors (perplexity.ai/account/connectors)",open:"https://www.perplexity.ai/account/connectors",docs:"https://www.perplexity.ai/help-center/en/articles/13915507-adding-custom-remote-connectors",support:"oauth-only",body:(n,i)=>ms(n,"Perplexity","Under **All settings → Connectors**, Perplexity's custom-connector form asks for an OAuth client ID under **Advanced**, over Streamable HTTP, on a Pro, Max or Enterprise plan.",i)},{id:"claude-code",name:"Claude Code",kind:"cli",where:"one command in any terminal",docs:"https://code.claude.com/docs/en/mcp-quickstart",support:"header",body:(n,i)=>A("```bash",n.openMode?`claude mcp add --transport http contextnest ${i}`:`claude mcp add --transport http contextnest ${i} \\
|
|
4
|
+
--header "Authorization: Bearer $${L}"`,"```","",n.openMode?"By default this registers at `local` scope — only you, only this project. Add `--scope user` for every project, or `--scope project` to write `.mcp.json` in the repo; that file is safe to commit.":`By default this registers at \`local\` scope — only you, only this project. Add \`--scope user\` for every project, or \`--scope project\` to write \`.mcp.json\` in the repo — that file is safe to commit because it can reference \`\${${L}}\` rather than the value.`,"","A session started before the server was added must be restarted; a fresh session picks it up automatically.")},{id:"codex",name:"OpenAI Codex CLI",kind:"cli",where:"codex mcp add, or ~/.codex/config.toml",docs:"https://learn.chatgpt.com/docs/extend/mcp?surface=cli",support:"header",body:(n,i)=>A("```bash",n.openMode?`codex mcp add contextnest --url ${i}`:`codex mcp add contextnest --url ${i} --bearer-token-env-var ${L}`,"```","","Or write it into `~/.codex/config.toml` directly:","","```toml","[mcp_servers.contextnest]",`url = "${i}"`,n.openMode?null:`bearer_token_env_var = "${L}"`,"```","",n.openMode?null:"Codex reads the token from the environment and sends it as an `Authorization: Bearer` header, so the value never lands in the config file.")},{id:"hermes",name:"Hermes (Nous Research)",kind:"cli",where:"~/.hermes/config.yaml",docs:"https://hermes-agent.nousresearch.com/docs/reference/mcp-config-reference",support:"header",body:(n,i)=>A("```yaml","mcp_servers:"," contextnest:",` url: "${i}"`,n.openMode?null:" headers:",n.openMode?null:` Authorization: "Bearer \${env:${L}}"`," enabled: true","```","",n.openMode?null:`Values support \`\${env:VAR}\` interpolation against \`~/.hermes/.env\`, so put the key in that file as \`${L}\` and keep it out of the YAML.`,n.openMode?null:"",'A `url` entry speaks Streamable HTTP — set `transport: "sse"` only if you need the older one.')},{id:"gemini-cli",name:"Gemini CLI",kind:"cli",where:"~/.gemini/settings.json",docs:"https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md",support:"header",body:(n,i)=>A("```json","{",' "mcpServers": {',' "contextnest": {',` "httpUrl": "${i}"${n.openMode?"":","}`,n.openMode?null:` "headers": { "Authorization": "Bearer ${q}" }`," }"," }","}","```","","Gemini CLI picks the transport from the property name: `httpUrl` is Streamable HTTP, `url` would be SSE, `command` would be stdio. Use `httpUrl` here.")},{id:"cursor",name:"Cursor",kind:"editor",where:"~/.cursor/mcp.json (or .cursor/mcp.json in a project)",docs:"https://cursor.com/docs/mcp",support:"header",body:(n,i)=>A("```json","{",' "mcpServers": {',' "contextnest": {',` "url": "${i}"${n.openMode?"":","}`,n.openMode?null:` "headers": { "Authorization": "Bearer ${q}" }`," }"," }","}","```","","Cursor expands variables inside `url` and `headers`, so the key can come from the environment rather than the file.")}],Ae=K[0];function us(n){return K.find(i=>i.id===n)}function Ee(n,i){const t=[n.open?`[Open the settings page](${n.open})`:null,`[${n.name} docs](${n.docs})`].filter(y=>y!==null).join(" · ");return`${n.body(i,Ie(i.serverUrl))}
|
|
5
|
+
|
|
6
|
+
${t}`}const ps=[{kind:"chat",heading:"# Chat"},{kind:"cli",heading:"# Command line"},{kind:"editor",heading:"# Editors"}];function xs(n){const t=[`**Connect once.** All of these point at the same endpoint — \`${Ie(n.serverUrl)}\` — and that one connection reads across every nest the caller can see: the public ones, plus whatever private nests they have been given access to. There is no per-nest setup, and nothing to redo when someone is added to another nest.`,"","What comes back is decided by who the caller authenticates as, not by which tool they are running.","",n.openMode?"This deployment runs in open mode, so no credential is involved and every caller is the same anonymous user.":["Two things to get right about the credential:","","- **Use a user-level key, not a nest-scoped one.** A key scoped to a single nest narrows this endpoint back down to that nest, which looks exactly like the connect-once promise being broken. Mint a user-level key in the Connect dialog.","- **Each person uses their own key.** A key shared across a team makes all of them the same user to this server, so they would all see the key owner's nests instead of their own."].join(`
|
|
7
|
+
`),""];for(const{kind:y,heading:_}of ps){const d=K.filter(g=>g.kind===y);if(d.length!==0){t.push(_,"");for(const g of d)t.push(`## ${g.name}`,"",`*${g.where}*`,"",Ee(g,n),"")}}return t.join(`
|
|
8
|
+
`).trimEnd()+`
|
|
9
|
+
`}const gs={chat:"Chat",cli:"Command line",editor:"Editors"},ys=["chat","cli","editor"];function _s({publicBaseUrl:n,openMode:i}){const[t,y]=l.useState(Ae.id),_=n.trim(),d=_||window.location.origin,g=l.useMemo(()=>({serverUrl:d,openMode:i}),[d,i]),v=us(t)??Ae,T=l.useMemo(()=>Ee(v,g),[v,g]);return e.jsxs(h,{children:[e.jsx(m,{children:e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx(u,{className:"text-base",children:"Connecting agents"}),e.jsxs(p,{children:["Setup steps for each AI tool your people are likely to use. Every one of them connects ",e.jsx("strong",{children:"once"}),", to the same server-level MCP endpoint, and that single connection reads across every nest the caller can see — the public ones plus whatever private nests they have access to. There is no per-nest setup, and nothing to redo when someone is added to another nest."]})]}),e.jsxs(b,{size:"sm",variant:"outline",onClick:()=>te(xs(g),"All connection instructions copied"),children:[e.jsx(se,{className:"h-4 w-4 mr-1.5"}),"Copy all"]})]})}),e.jsxs(x,{className:"space-y-4",children:[!_&&e.jsxs("div",{role:"alert",className:"flex gap-2 rounded-md border border-amber-500/50 bg-amber-500/10 px-3 py-2 text-xs",children:[e.jsx(We,{className:"h-4 w-4 shrink-0 mt-0.5 text-amber-600"}),e.jsxs("span",{children:["No public base URL is set, so these steps use"," ",e.jsx("code",{children:d})," — the address of"," ",e.jsx("em",{children:"this browser's"})," connection. Most of these tools run the MCP client on the vendor's servers, not the user's machine, so a private or proxied address will fail for them. Set the public base URL on the ",e.jsx("strong",{children:"General"})," tab."]})]}),!i&&e.jsxs("div",{className:"space-y-1 text-xs text-muted-foreground",children:[e.jsxs("p",{children:[e.jsx("strong",{children:"Use a user-level key, not a nest-scoped one."})," A key scoped to a single nest narrows this endpoint back down to that nest, which looks exactly like the connect-once promise being broken."]}),e.jsxs("p",{children:[e.jsx("strong",{children:"Each person uses their own key."})," A key shared across a team makes all of them the same user to this server, so they would all see the key owner's nests instead of their own."]})]}),ys.map(k=>{const f=K.filter(N=>N.kind===k);return f.length===0?null:e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("div",{className:"text-xs font-medium text-muted-foreground",children:gs[k]}),e.jsx("div",{className:"flex flex-wrap gap-1.5",children:f.map(N=>e.jsxs(b,{size:"sm",variant:N.id===t?"default":"outline","aria-pressed":N.id===t,onClick:()=>y(N.id),children:[N.name,N.support==="oauth-only"&&e.jsx(Te,{variant:"secondary",className:"ml-1.5",children:"OAuth"})]},N.id))})]},k)}),e.jsxs("div",{className:"rounded-lg border border-border bg-muted/30 p-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-4 mb-2",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium",children:v.name}),e.jsx("div",{className:"text-xs text-muted-foreground",children:v.where})]}),e.jsxs(b,{size:"sm",variant:"ghost",onClick:()=>te(T,`${v.name} steps copied`),children:[e.jsx(se,{className:"h-4 w-4 mr-1.5"}),"Copy"]})]}),e.jsx("article",{className:"prose prose-sm dark:prose-invert max-w-none",children:e.jsx(qe,{remarkPlugins:[Ke],components:{a:({...k})=>e.jsx("a",{...k,target:"_blank",rel:"noopener noreferrer"})},children:T})})]})]})]})}const fs=[{value:"open",label:"Everyone",hint:"Anyone can sign in with PromptOwl."},{value:"admin-only",label:"Admins only",hint:"Only the server admin can use PromptOwl sign-in."},{value:"disabled",label:"Off",hint:"Hide PromptOwl sign-in."}],vs=[{value:"open",label:"Everyone",hint:"Anyone can sign in and create their own account."},{value:"invite-only",label:"Invite only",hint:"Invited users sign in and set a password; no self sign-up."},{value:"disabled",label:"Off",hint:"No email & password sign-in — PromptOwl only."}],Z=[{id:"general",label:"General",keys:["promptowl_sign_in_gate","manual_sign_in","public_base_url","logo_url","anthropic_api_key","anthropic_base_url","hootie_enabled","hootie_model","nest_creation","people_suggest_all_users","shared_deployment"]},{id:"sso",label:"Single sign-on",keys:["oidc_enabled","oidc_issuer","oidc_client_id","oidc_client_secret","oidc_allowed_domains","oidc_auto_provision","oidc_department_tagging","sso_token_exchange_enabled","mcp_signing_secret","mcp_token_ttl_seconds","ms_token_exchange_enabled","ms_client_id","ms_tenant_id","google_token_exchange_enabled","google_client_id"]},{id:"notifications",label:"Notifications",keys:["slack_webhook_url","msteams_webhook_url","email_provider","smtp_url","ses_region","ses_access_key_id","ses_secret_access_key","notify_email_from","notify_email_to"]},{id:"community-sites",label:"Community sites",keys:[]},{id:"agents",label:"Connecting agents",keys:[]},{id:"advanced",label:"Advanced",keys:["telemetry_enabled","posthog_key","posthog_host","max_body_bytes","trace_retention_days","type_artifact_enabled","type_table_enabled","workflow_plane_enabled","promptowl_teams_enabled","subagent_runs_enabled","subagent_max_depth","subagent_max_children"]}],V=n=>({autoComplete:n==="password"?"new-password":"off","data-1p-ignore":!0,"data-lpignore":"true","data-form-type":"other"});function c({id:n,value:i,placeholder:t,onChange:y,type:_="text",error:d}){const g=_==="password",[v,T]=l.useState(!1);return e.jsxs("div",{className:"flex-1",children:[e.jsxs("div",{className:"relative",children:[e.jsx($,{id:n,value:i,type:g&&v?"text":_,placeholder:t,onChange:k=>y(k.target.value),"aria-invalid":!!d,className:`flex-1 ${g?"pr-9":""} ${d?"border-destructive focus-visible:ring-destructive":""}`,...V(_)}),g&&e.jsx("button",{type:"button",tabIndex:-1,onClick:()=>T(k=>!k),className:"absolute inset-y-0 right-0 flex items-center px-2.5 text-muted-foreground hover:text-foreground",title:v?"Hide":"Show","aria-label":v?"Hide value":"Show value",children:v?e.jsx(as,{className:"h-4 w-4"}):e.jsx(rs,{className:"h-4 w-4"})})]}),d&&e.jsx("p",{className:"mt-1 text-xs text-destructive",children:d})]})}function js({bytes:n,onChange:i}){const[t,y]=l.useState(String(Math.round(n/1048576)));return l.useEffect(()=>y(String(Math.round(n/(1024*1024)))),[n]),e.jsxs("div",{className:"flex items-center gap-2 max-w-xs",children:[e.jsx($,{type:"number",value:t,onChange:_=>{y(_.target.value);const d=Number(_.target.value);Number.isFinite(d)&&d>0&&i(Math.floor(d*1024*1024))},...V("number")}),e.jsx("span",{className:"text-sm text-muted-foreground shrink-0",children:"MB"})]})}function ee({value:n,onChange:i,min:t,max:y}){const[_,d]=l.useState(String(n));return l.useEffect(()=>d(String(n)),[n]),e.jsx($,{type:"number",min:t,max:y,value:_,className:"max-w-[7rem]",onChange:g=>{d(g.target.value);const v=Number(g.target.value);Number.isInteger(v)&&i(v)},...V("number")})}function bs({settings:n,onUpdate:i}){var ye,_e;const[t,y]=l.useState(n),[_,d]=l.useState(!1),g=Pe(),{authMode:v}=Oe(),[T,k]=l.useState(null),[f,N]=l.useState({}),[Me,ae]=l.useState("general"),[re,ie]=l.useState(!1);l.useEffect(()=>{n&&y(n)},[n]);const[Y,Le]=l.useState(null),[oe,le]=l.useState(null),F=async()=>{try{await g.invalidateQueries({queryKey:ne.communitySites().queryKey});const s=await g.fetchQuery(ne.communitySites());Le(s.community_sites),le(null)}catch(s){le(s.message)}};l.useEffect(()=>{F()},[]);const[C,D]=l.useState(null),[S,O]=l.useState({name:"",url:"",secret:"",is_active:!0}),[ce,de]=l.useState(!1),[he,H]=l.useState(null),[P,B]=l.useState(null),[me,ue]=l.useState(!1),$e=()=>{O({name:"",url:"",secret:"",is_active:!0}),H(null),D({mode:"add"})},De=s=>{O({name:s.name,url:s.url,secret:"",is_active:s.is_active}),H(null),D({mode:"edit",site:s})},Re=async()=>{if(C){de(!0),H(null);try{if(C.mode==="add")await is({name:S.name.trim(),url:S.url.trim(),secret:S.secret.trim(),is_active:S.is_active});else{const s={name:S.name.trim(),url:S.url.trim(),is_active:S.is_active};S.secret.trim()&&(s.secret=S.secret.trim()),await Se(C.site.id,s)}D(null),await F()}catch(s){H(s.message)}finally{de(!1)}}},Ue=async s=>{try{await Se(s.id,{is_active:!s.is_active}),await F()}catch(r){z.error(r.message)}},ze=async()=>{if(P){ue(!0);try{await os(P.id),B(null),await F()}catch(s){z.error(s.message)}finally{ue(!1)}}},a=s=>{y(r=>r&&{...r,...s}),k(null),N({})},R=l.useMemo(()=>{if(!t||!n)return[];const s=n;return Object.keys(t).filter(r=>{if(r==="anthropic_api_key"||r==="oidc_client_secret"||r==="mcp_signing_secret"||r==="ses_secret_access_key"){const o=t[r];return typeof o=="string"&&o.trim()!==""||o===null}return(t[r]??"")!==(s[r]??"")})},[t,n]),G=R.length>0,Fe=s=>s.some(r=>R.includes(r)),He=async()=>{var r;if(!t||!G)return;const s={};for(const o of R)s[o]=t[o];d(!0),k(null),N({});try{await i(s)}catch(o){k((o==null?void 0:o.message)||"Failed to save settings");const w=((r=o==null?void 0:o.body)==null?void 0:r.fieldErrors)??{};N(w);const U=Object.keys(w),W=Q=>U.some(J=>Q.keys.includes(J)),fe=U.length?Z.find(W):Z.find(Q=>Q.keys.some(J=>R.includes(J)));fe&&ae(fe.id)}finally{d(!1)}},Be=()=>{n&&y(n),k(null),N({})},[pe,xe]=l.useState(null),Ge=async s=>{xe(s);try{await ls(s),z.success(`Test ${s==="slack"?"Slack":"Teams"} notification sent — check the channel.`)}catch(r){z.error((r==null?void 0:r.message)||"Test notification failed.")}finally{xe(null)}},ge=(s,r)=>e.jsxs("div",{className:"mt-3 flex items-center gap-2",children:[e.jsxs(b,{type:"button",variant:"outline",size:"sm",disabled:pe===s||!(n!=null&&n[r]),onClick:()=>Ge(s),children:[pe===s&&e.jsx(I,{className:"h-3.5 w-3.5 mr-1.5 animate-spin"}),"Send test"]}),R.includes(r)&&e.jsx("span",{className:"text-xs text-muted-foreground",children:"Save first — the test uses the saved URL."})]});return e.jsxs("div",{children:[e.jsx(cs,{icon:X,title:"Server settings",description:"Server-wide options. Changes apply on Save and persist across restarts.",className:"mb-6",actions:n&&e.jsxs(e.Fragment,{children:[G&&e.jsx("span",{className:"text-xs text-muted-foreground mr-1",children:"Unsaved changes"}),e.jsx(b,{variant:"ghost",size:"sm",onClick:Be,disabled:!G||_,children:"Discard"}),e.jsxs(b,{size:"sm",onClick:He,disabled:!G||_,children:[_&&e.jsx(I,{className:"h-4 w-4 mr-1.5 animate-spin"}),"Save changes"]})]})}),T&&e.jsxs("div",{role:"alert",className:"mb-4 rounded-md border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive",children:[e.jsx("div",{className:"font-medium",children:"Couldn't save settings"}),e.jsx("div",{className:"mt-0.5 text-destructive/90",children:T})]}),t?e.jsxs(Qe,{value:Me,onValueChange:ae,children:[e.jsx(Je,{children:Z.map(s=>e.jsxs(Xe,{value:s.id,className:"gap-1.5",children:[s.label,Fe(s.keys)&&e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-primary","aria-label":"unsaved changes"})]},s.id))}),e.jsxs(E,{value:"general",className:"space-y-4",children:[e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsxs(u,{className:"flex items-center gap-2 text-base",children:[e.jsx(X,{className:"h-4 w-4 text-muted-foreground"}),"PromptOwl sign-in"]}),e.jsx(p,{children:"Who can sign in to this server using their PromptOwl account."})]}),e.jsx(x,{children:e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-2",children:fs.map(s=>{const r=t.promptowl_sign_in_gate===s.value,o=s.value==="disabled"&&t.manual_sign_in==="disabled";return e.jsxs("button",{type:"button",disabled:o,onClick:()=>!r&&!o&&a({promptowl_sign_in_gate:s.value}),className:`text-left rounded-lg border p-3 transition-colors ${r?"border-primary bg-primary/5 ring-1 ring-primary":o?"opacity-50 cursor-not-allowed":"hover:bg-muted/50"}`,"aria-pressed":r,children:[e.jsx("div",{className:"text-sm font-medium",children:s.label}),e.jsx("div",{className:"text-xs text-muted-foreground mt-0.5",children:s.hint})]},s.value)})})})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsxs(u,{className:"flex items-center gap-2 text-base",children:[e.jsx(X,{className:"h-4 w-4 text-muted-foreground"}),"Manual sign-in"]}),e.jsx(p,{children:"Email & password sign-in. Independent of PromptOwl — you can't turn this fully off while PromptOwl sign-in is also off."})]}),e.jsx(x,{children:e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-2",children:vs.map(s=>{const r=t.manual_sign_in===s.value,o=s.value==="disabled"&&t.promptowl_sign_in_gate==="disabled";return e.jsxs("button",{type:"button",disabled:o,onClick:()=>!r&&!o&&a({manual_sign_in:s.value}),className:`text-left rounded-lg border p-3 transition-colors ${r?"border-primary bg-primary/5 ring-1 ring-primary":o?"opacity-50 cursor-not-allowed":"hover:bg-muted/50"}`,"aria-pressed":r,children:[e.jsx("div",{className:"text-sm font-medium",children:s.label}),e.jsx("div",{className:"text-xs text-muted-foreground mt-0.5",children:s.hint})]},s.value)})})})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Public base URL"}),e.jsx(p,{children:"This server's public address — used for share links and SSO redirects. Leave empty if unsure."})]}),e.jsx(x,{children:e.jsx(c,{error:f.public_base_url,value:t.public_base_url??"",placeholder:"https://nest.yourcompany.com",onChange:s=>a({public_base_url:s})})})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Logo"}),e.jsx(p,{children:"URL of the logo shown in the header. Leave empty for the default."})]}),e.jsx(x,{children:e.jsx(c,{value:t.logo_url??"",placeholder:"https://example.com/logo.svg",onChange:s=>a({logo_url:s})})})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Anthropic API key"}),e.jsx(p,{children:"The server-wide model key. Runners pick it up automatically (every nest, unless a nest overrides it in its Tool environment). No key, no LLM calls. Checked against the provider when you save, so a bad key is refused here rather than failing later. Stored server-side; shown masked."})]}),e.jsxs(x,{children:[e.jsx("div",{className:"text-xs text-muted-foreground mb-2",children:t.anthropic_api_key===null?"Will be cleared when you save.":n!=null&&n.anthropic_api_key_masked?`Current: ${n.anthropic_api_key_masked}`:"Not set — runs can't execute until a key exists here or in a nest's Tool environment."}),e.jsx(c,{error:f.anthropic_api_key,type:"password",value:typeof t.anthropic_api_key=="string"?t.anthropic_api_key:"",placeholder:"sk-ant-… (paste to set or replace)",onChange:s=>a({anthropic_api_key:s})}),(n==null?void 0:n.anthropic_api_key_masked)&&t.anthropic_api_key!==null&&e.jsx("button",{type:"button",className:"mt-2 text-xs text-destructive hover:underline",onClick:()=>a({anthropic_api_key:null}),children:"Clear key"}),t.anthropic_api_key===null&&e.jsx("button",{type:"button",className:"mt-2 text-xs text-muted-foreground hover:underline",onClick:()=>a({anthropic_api_key:void 0}),children:"Keep current key"})]})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Hootie"}),e.jsx(p,{children:"The assistant in the corner of every page. It answers from what the person asking can read in the nest, cites the documents it used, and lets them @tag a colleague — which posts the exchange as a comment and notifies them. Uses the Anthropic API key above; without one the panel says so."})]}),e.jsxs(x,{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm",children:["Hootie in the nest — ",t.hootie_enabled?"On":"Off"]}),e.jsx(j,{checked:t.hootie_enabled,onCheckedChange:s=>a({hootie_enabled:s})})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(M,{htmlFor:"hootie-model",children:"Model"}),e.jsx(c,{error:f.hootie_model,id:"hootie-model",value:t.hootie_model??"",placeholder:"claude-opus-5",onChange:s=>a({hootie_model:s})}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["The model Hootie answers with. Through a gateway this is the gateway's name for it (",e.jsx("code",{children:"ollama/llama3.2"}),","," ",e.jsx("code",{children:"gpt-5"}),", …)."]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(M,{htmlFor:"anthropic-base-url",children:"Model gateway URL"}),e.jsx(c,{id:"anthropic-base-url",value:t.anthropic_base_url??"",placeholder:"http://gateway:4000 — empty calls Anthropic directly",onChange:s=>a({anthropic_base_url:s})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Route every model call — Hootie and agent runs — through a LiteLLM or PromptOwl gateway with the key above as its virtual key: budgets, spend logs, and any model the gateway fronts. Empty means Anthropic directly."})]})]})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsxs(u,{className:"flex items-center gap-2 text-base",children:[e.jsx(ve,{className:"h-4 w-4 text-muted-foreground"}),"Nest creation"]}),e.jsx(p,{children:"Who can create and import nests on this server."})]}),e.jsx(x,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"pr-4",children:[e.jsx("div",{className:"text-sm font-medium",children:"Let everyone create nests"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-0.5",children:"Off, only server admins can create or import nests, and everyone else works in the nests shared with them. On, any signed-in user can create their own."})]}),e.jsx(j,{checked:t.nest_creation==="everyone",onCheckedChange:s=>a({nest_creation:s?"everyone":"admins"})})]})})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsxs(u,{className:"flex items-center gap-2 text-base",children:[e.jsx(Ze,{className:"h-4 w-4 text-muted-foreground"}),"People directory"]}),e.jsx(p,{children:'What the "add a person" fields suggest when inviting someone to a nest, a team, or a stewardship role.'})]}),e.jsxs(x,{children:[e.jsxs("div",{className:"flex items-start justify-between gap-4 pb-4",children:[e.jsxs("div",{className:"pr-4",children:[e.jsx("div",{className:"text-sm font-medium",children:"Suggest everyone on this server"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-0.5",children:"When enabled, the pickers suggest every registered account on this server."}),e.jsxs("ul",{className:"text-xs text-muted-foreground mt-1.5 space-y-0.5",children:[e.jsxs("li",{children:[e.jsx("b",{className:"text-foreground/80",children:"Off:"})," only people the inviter already shares a nest or team with."]}),e.jsxs("li",{children:[e.jsx("b",{className:"text-foreground/80",children:"On:"})," every registered account — right when this server is one organisation, wrong when it hosts several, because it shows users each other's email addresses."]}),e.jsxs("li",{children:[e.jsx("b",{className:"text-foreground/80",children:"In either state:"})," anyone can still be invited by typing their email address."]})]})]}),e.jsx(j,{checked:t.people_suggest_all_users,onCheckedChange:s=>a({people_suggest_all_users:s})})]}),e.jsxs("div",{className:"flex items-start justify-between gap-4 pt-4 border-t",children:[e.jsxs("div",{className:"pr-4",children:[e.jsx("div",{className:"text-sm font-medium",children:"This server hosts several organizations"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-0.5",children:"A nest's Organization tier is readable by every account on this server."}),e.jsxs("ul",{className:"text-xs text-muted-foreground mt-1.5 space-y-0.5",children:[e.jsxs("li",{children:[e.jsx("b",{className:"text-foreground/80",children:"Off:"})," the server is one company and the Organization tier applies in one click."]}),e.jsxs("li",{children:[e.jsx("b",{className:"text-foreground/80",children:"On:"})," for the PromptOwl-hosted service, or any install shared by unrelated customers — opening a nest to Organization asks for the same acknowledgement as Public. Enforced by the server, not only the UI, and the visibility picker explains who the tier really reaches."]})]})]}),e.jsx(j,{checked:t.shared_deployment,onCheckedChange:s=>a({shared_deployment:s}),"data-testid":"settings-shared-deployment"})]})]})]})]}),e.jsxs(E,{value:"sso",className:"space-y-4",children:[e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsxs(u,{className:"flex items-center gap-2 text-base",children:[e.jsx(es,{className:"h-4 w-4 text-muted-foreground"}),"Single sign-on (OIDC)"]}),e.jsx(p,{children:"Let teammates sign in with your identity provider — Microsoft Entra ID, Google, or any OpenID Connect issuer. Fill in the issuer and app credentials below, then turn it on."})]}),e.jsxs(x,{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm",children:[t.oidc_enabled?"On":"Off",!t.oidc_enabled&&!(t.oidc_issuer&&t.oidc_client_id)&&e.jsxs("span",{className:"text-muted-foreground",children:[" ","· configure the issuer and app credentials first"]})]}),e.jsx(j,{checked:t.oidc_enabled,onCheckedChange:s=>a({oidc_enabled:s})})]}),(()=>{var o,w;const s=t.oidc_client_secret===null?!1:typeof t.oidc_client_secret=="string"&&t.oidc_client_secret.trim()!==""?!0:!!(n!=null&&n.oidc_client_secret_set),r=t.oidc_enabled&&!!((o=t.oidc_issuer)!=null&&o.trim())&&!!((w=t.oidc_client_id)!=null&&w.trim())&&s;return!t.oidc_enabled||r?null:e.jsx("div",{role:"alert",className:"rounded-md border border-amber-500/50 bg-amber-500/10 px-3 py-2 text-xs text-amber-700 dark:text-amber-400",children:"Enabled but not configured — the SSO sign-in button stays hidden until the issuer, client ID, and client secret are all set."})})(),(()=>{var o;const s=((o=t.oidc_issuer)==null?void 0:o.trim())??"",r=/^https:\/\/login\.microsoftonline\.com\/[^/]+\/v2\.0$/.test(s)?"entra":s==="https://accounts.google.com"?"google":null;return e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"Issuer URL"}),e.jsxs("div",{className:"flex gap-2 mb-2",role:"group","aria-label":"Identity provider preset",children:[e.jsx(b,{type:"button",variant:r==="entra"?"default":"outline",size:"sm","aria-pressed":r==="entra",onClick:()=>{const w=window.prompt("Microsoft Entra tenant ID (Directory ID) — find it on your app registration's Overview page:");w&&w.trim()&&a({oidc_issuer:`https://login.microsoftonline.com/${w.trim()}/v2.0`})},children:"Microsoft Entra ID"}),e.jsx(b,{type:"button",variant:r==="google"?"default":"outline",size:"sm","aria-pressed":r==="google",onClick:()=>a({oidc_issuer:"https://accounts.google.com"}),children:"Google"}),r===null&&s!==""&&e.jsx("span",{className:"self-center text-xs text-muted-foreground",children:"Custom issuer"})]}),e.jsx(c,{error:f.oidc_issuer,value:t.oidc_issuer??"",placeholder:"https://login.microsoftonline.com/{tenant}/v2.0",onChange:w=>a({oidc_issuer:w})}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"https:// only. Must serve /.well-known/openid-configuration."})]})})(),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"Client ID"}),e.jsx(c,{value:t.oidc_client_id??"",placeholder:"Application (client) ID from your IdP app registration",onChange:s=>a({oidc_client_id:s})})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"Client secret"}),e.jsx("div",{className:"text-xs text-muted-foreground mb-2",children:t.oidc_client_secret===null?"Will be cleared when you save.":n!=null&&n.oidc_client_secret_set?"A client secret is set. Paste a new one to replace it.":"Not set."}),e.jsx(c,{error:f.oidc_client_secret,type:"password",value:typeof t.oidc_client_secret=="string"?t.oidc_client_secret:"",placeholder:"Paste to set or replace",onChange:s=>a({oidc_client_secret:s})}),(n==null?void 0:n.oidc_client_secret_set)&&t.oidc_client_secret!==null&&e.jsx("button",{type:"button",className:"mt-2 text-xs text-destructive hover:underline",onClick:()=>a({oidc_client_secret:null}),children:"Clear secret"}),t.oidc_client_secret===null&&e.jsx("button",{type:"button",className:"mt-2 text-xs text-muted-foreground hover:underline",onClick:()=>a({oidc_client_secret:void 0}),children:"Keep current secret"})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"Redirect URI"}),(()=>{const r=`${(t.public_base_url||window.location.origin).replace(/\/$/,"")}/auth/oidc/callback`;return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("code",{className:"flex-1 bg-muted/40 border rounded px-2 py-1.5 text-xs font-mono break-all",children:r}),e.jsxs(b,{type:"button",variant:"outline",size:"sm",onClick:async()=>{await te(r)&&(ie(!0),setTimeout(()=>ie(!1),1500))},children:[re?e.jsx(ss,{className:"h-3.5 w-3.5"}):e.jsx(se,{className:"h-3.5 w-3.5"}),e.jsx("span",{className:"ml-1.5",children:re?"Copied":"Copy"})]})]})})(),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"Register this exact URI in your IdP's app registration (Entra: Authentication → Web redirect URIs; Google: Authorized redirect URIs)."})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"Allowed email domains"}),e.jsx(c,{error:f.oidc_allowed_domains,value:t.oidc_allowed_domains??"",placeholder:"acme.com, contractors.acme.com — empty allows any",onChange:s=>a({oidc_allowed_domains:s})}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"Only accounts whose email domain is listed may sign in. Leave empty to allow any domain your IdP asserts."})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium",children:"Auto-provision new users"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-0.5",children:"Create an account on first SSO sign-in. Turn off to allow only users you've already invited."})]}),e.jsx(j,{checked:t.oidc_auto_provision,onCheckedChange:s=>a({oidc_auto_provision:s})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium",children:"Department auto-tagging"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-0.5",children:"Tag new documents with the creator's directory department (requires the department claim from your IdP)."})]}),e.jsx(j,{checked:t.oidc_department_tagging,onCheckedChange:s=>a({oidc_department_tagging:s})})]}),t.oidc_enabled&&t.oidc_auto_provision&&!((ye=t.oidc_allowed_domains)!=null&&ye.trim())&&e.jsx("div",{role:"alert",className:"rounded-md border border-amber-500/50 bg-amber-500/10 px-3 py-2 text-xs text-amber-700 dark:text-amber-400",children:"Anyone your issuer can authenticate will get an account on first sign-in — with a consumer or multi-tenant issuer (e.g. Google), that's any account on the internet, and it applies even when manual sign-in is invite-only. Set allowed email domains above, or turn auto-provision off."})]})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{children:"Agent SSO — token exchange"}),e.jsx(p,{children:"Let an external agent, acting for a user your IdP already authenticated (Microsoft Entra / Google), exchange that IdP's ID token for a short-lived MCP bearer — no second login. Uses the domain allowlist and auto-provision settings above."})]}),e.jsxs(x,{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-sm",children:t.sso_token_exchange_enabled?"On":"Off"}),e.jsx(j,{checked:t.sso_token_exchange_enabled,onCheckedChange:s=>a({sso_token_exchange_enabled:s})})]}),(t.ms_token_exchange_enabled||t.google_token_exchange_enabled)&&t.oidc_auto_provision&&!((_e=t.oidc_allowed_domains)!=null&&_e.trim())&&e.jsx("div",{role:"alert",className:"rounded-md border border-destructive/50 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:"Blocked: with auto-provision on and no allowed email domains, anyone with an account at that provider could sign themselves up and mint a token. Set allowed email domains above, or turn auto-provision off."}),(()=>{var w,U,W;const s=t.mcp_signing_secret===null?!1:typeof t.mcp_signing_secret=="string"&&t.mcp_signing_secret.trim()!==""?!0:!!(n!=null&&n.mcp_signing_secret_set),r=t.ms_token_exchange_enabled&&!!((w=t.ms_client_id)!=null&&w.trim())&&!!((U=t.ms_tenant_id)!=null&&U.trim()),o=t.google_token_exchange_enabled&&!!((W=t.google_client_id)!=null&&W.trim());return!t.sso_token_exchange_enabled||s&&(r||o)?null:e.jsx("div",{role:"alert",className:"rounded-md border border-amber-500/50 bg-amber-500/10 px-3 py-2 text-xs text-amber-700 dark:text-amber-400",children:"Enabled but not ready — the endpoint needs a signing secret and at least one provider turned on with its client ID filled in (plus the tenant ID for Microsoft)."})})(),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"MCP signing secret"}),e.jsx("div",{className:"text-xs text-muted-foreground mb-2",children:t.mcp_signing_secret===null?"Will be cleared when you save.":n!=null&&n.mcp_signing_secret_set?"A signing secret is set. Paste a new one to replace it.":"Not set. Use a long random string — this signs the MCP tokens the exchange mints."}),e.jsx(c,{error:f.mcp_signing_secret,type:"password",value:typeof t.mcp_signing_secret=="string"?t.mcp_signing_secret:"",placeholder:"Paste to set or replace (16+ characters)",onChange:s=>a({mcp_signing_secret:s})}),(n==null?void 0:n.mcp_signing_secret_set)&&t.mcp_signing_secret!==null&&e.jsx("button",{type:"button",className:"mt-2 text-xs text-destructive hover:underline",onClick:()=>a({mcp_signing_secret:null}),children:"Clear secret"}),t.mcp_signing_secret===null&&e.jsx("button",{type:"button",className:"mt-2 text-xs text-muted-foreground hover:underline",onClick:()=>a({mcp_signing_secret:void 0}),children:"Keep current secret"})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"Token lifetime (seconds)"}),e.jsx(c,{error:f.mcp_token_ttl_seconds,type:"number",value:String(t.mcp_token_ttl_seconds??300),placeholder:"300",onChange:s=>a({mcp_token_ttl_seconds:s.trim()===""?300:Number(s)})}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"30–3600. Short by design — a minted token expires quickly."})]}),e.jsxs("div",{className:"border-t pt-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-sm font-medium",children:"Microsoft Entra"}),e.jsx(j,{checked:t.ms_token_exchange_enabled,onCheckedChange:s=>a({ms_token_exchange_enabled:s})})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"Client (application) ID"}),e.jsx(c,{value:t.ms_client_id??"",placeholder:"Entra app (client) ID — the token audience",onChange:s=>a({ms_client_id:s})})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"Tenant ID"}),e.jsx(c,{value:t.ms_tenant_id??"",placeholder:"Directory (tenant) ID — builds the issuer",onChange:s=>a({ms_tenant_id:s})})]})]}),e.jsxs("div",{className:"border-t pt-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-sm font-medium",children:"Google"}),e.jsx(j,{checked:t.google_token_exchange_enabled,onCheckedChange:s=>a({google_token_exchange_enabled:s})})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"OAuth client ID"}),e.jsx(c,{value:t.google_client_id??"",placeholder:"Google OAuth client ID — the token audience",onChange:s=>a({google_client_id:s})})]})]}),e.jsxs("div",{className:"rounded-md border bg-muted/30 px-3 py-2 text-xs text-muted-foreground",children:["Your agent calls"," ",e.jsx("code",{className:"text-[11px]",children:"POST /auth/token-exchange"})," ","with the IdP ID token and receives a short-lived MCP bearer for"," ",e.jsx("code",{className:"text-[11px]",children:"/mcp"})," and"," ",e.jsx("code",{className:"text-[11px]",children:"/index"}),". The token is verified by signature, issuer, audience (the client id above) and expiry. Security-critical — keep it off until reviewed. For a public IdP like Google, set the allowed email domains above so only your organization can exchange."]})]})]})]}),e.jsxs(E,{value:"notifications",className:"space-y-4",children:[e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Slack notifications"}),e.jsx(p,{children:"Post governance events (review requested, approved, rejected, nest shared) to a Slack channel via an incoming-webhook URL. Leave empty to turn the connector off. The URL contains a secret — treat it like a password."})]}),e.jsxs(x,{children:[e.jsx(c,{error:f.slack_webhook_url,type:"password",value:t.slack_webhook_url??"",placeholder:"https://hooks.slack.com/services/…",onChange:s=>a({slack_webhook_url:s})}),ge("slack","slack_webhook_url")]})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Microsoft Teams notifications"}),e.jsx(p,{children:'Post the same governance events to a Microsoft Teams channel as Adaptive Cards via an incoming-webhook URL (create one in Teams with the Workflows app: "Post to a channel when a webhook request is received"). Leave empty to turn the connector off. The URL contains a secret — treat it like a password.'})]}),e.jsxs(x,{children:[e.jsx(c,{error:f.msteams_webhook_url,type:"password",value:t.msteams_webhook_url??"",placeholder:"https://….logic.azure.com/workflows/…",onChange:s=>a({msteams_webhook_url:s})}),ge("teams","msteams_webhook_url")]})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Email notifications"}),e.jsx(p,{children:"Invites, shares and governance events by email. Send through SMTP, or through AWS SES when this server can't use SMTP. Set a From address and one or more team recipients (comma-separated). Leave the SMTP URL or AWS region empty to turn email off."})]}),e.jsxs(x,{className:"space-y-3",children:[e.jsx("div",{role:"radiogroup",className:"flex gap-4 text-sm",children:[["smtp","SMTP"],["ses","AWS SES"]].map(([s,r])=>e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer",children:[e.jsx("input",{type:"radio",name:"email_provider",checked:(t.email_provider??"smtp")===s,onChange:()=>a({email_provider:s})}),r]},s))}),(t.email_provider??"smtp")==="smtp"?e.jsx(c,{error:f.smtp_url,type:"password",value:t.smtp_url??"",placeholder:"smtps://user:pass@smtp.example.com:465",onChange:s=>a({smtp_url:s})}):e.jsxs(e.Fragment,{children:[e.jsx(c,{error:f.ses_region,value:t.ses_region??"",placeholder:"AWS region — us-east-1",onChange:s=>a({ses_region:s})}),e.jsx(c,{value:t.ses_access_key_id??"",placeholder:"Access key ID — leave empty to use the server's IAM role",onChange:s=>a({ses_access_key_id:s})}),e.jsx(c,{error:f.ses_secret_access_key,type:"password",value:typeof t.ses_secret_access_key=="string"?t.ses_secret_access_key:"",placeholder:t.ses_secret_access_key===null?"Secret access key — will be cleared when you save":n!=null&&n.ses_secret_access_key_set?"Secret access key is set — paste to replace":"Secret access key — leave empty to use the server's IAM role",onChange:s=>a({ses_secret_access_key:s})}),(n==null?void 0:n.ses_secret_access_key_set)&&t.ses_secret_access_key!==null&&e.jsx("button",{type:"button",className:"text-xs text-destructive hover:underline",onClick:()=>a({ses_secret_access_key:null,ses_access_key_id:""}),children:"Clear keys"})]}),e.jsx(c,{error:f.notify_email_from,value:t.notify_email_from??"",placeholder:"From — nest@yourcompany.com",onChange:s=>a({notify_email_from:s})}),e.jsx(c,{error:f.notify_email_to,value:t.notify_email_to??"",placeholder:"To — team@yourcompany.com, ops@yourcompany.com",onChange:s=>a({notify_email_to:s})})]})]})]}),e.jsxs(E,{value:"advanced",className:"space-y-4",children:[e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Usage telemetry"}),e.jsx(p,{children:"Send anonymous usage counts to PromptOwl. Turn off to keep all usage data on this server."})]}),e.jsx(x,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-sm",children:t.telemetry_enabled?"On":"Off"}),e.jsx(j,{checked:t.telemetry_enabled,onCheckedChange:s=>a({telemetry_enabled:s})})]})})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Product analytics"}),e.jsx(p,{children:"Send usage events to your own PostHog project. Leave the key empty to keep analytics off. Also off whenever usage telemetry above is off."})]}),e.jsxs(x,{className:"space-y-3",children:[e.jsx(c,{error:f.posthog_key,value:t.posthog_key??"",placeholder:"Project API key — phc_...",onChange:s=>a({posthog_key:s})}),e.jsx(c,{error:f.posthog_host,value:t.posthog_host??"",placeholder:"Host — https://us.i.posthog.com",onChange:s=>a({posthog_host:s})})]})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Max upload size"}),e.jsx(p,{children:"Largest request/file accepted, in megabytes. Raise this if big HTML artifacts (decks, dashboards) get rejected."})]}),e.jsx(x,{children:e.jsx(js,{bytes:t.max_body_bytes,onChange:s=>a({max_body_bytes:s})})})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Activity trace retention"}),e.jsx(p,{children:"How many days of activity-trace rows (API requests and MCP tool calls) to keep. Older rows are pruned opportunistically. Set 0 to keep activity forever."})]}),e.jsxs(x,{children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ee,{value:t.trace_retention_days,min:0,max:3650,onChange:s=>a({trace_retention_days:s})}),e.jsx("span",{className:"text-sm text-muted-foreground shrink-0",children:"days"})]}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"0–3650 — 0 disables pruning entirely."})]})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Content types"}),e.jsx(p,{children:"Which node types can be created on this server. Turning one off hides it from the editor and refuses new creations — existing nodes of that type stay readable and versioned. Runnable types (agent, skill, tool) are governed by the workflow plane below."})]}),e.jsxs(x,{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm",children:["Artifacts (hosted HTML) —"," ",t.type_artifact_enabled?"On":"Off"]}),e.jsx(j,{checked:t.type_artifact_enabled,onCheckedChange:s=>a({type_artifact_enabled:s})})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm",children:["Tables (CSV fact stores) —"," ",t.type_table_enabled?"On":"Off"]}),e.jsx(j,{checked:t.type_table_enabled,onCheckedChange:s=>a({type_table_enabled:s})})]})]})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsxs(u,{className:"text-base",children:["Workflow plane ",e.jsx(ts,{className:"ml-1 align-middle"})]}),e.jsx(p,{children:"Typed edges, an edge-type registry, and governed runs — the automation layer. Optional; off by default. Turning it on adds API surface and UI views but changes nothing until someone creates an edge."})]}),e.jsx(x,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-sm",children:t.workflow_plane_enabled?"On":"Off"}),e.jsx(j,{checked:t.workflow_plane_enabled,onCheckedChange:s=>a({workflow_plane_enabled:s,...s?{}:{subagent_runs_enabled:!1}})})]})})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Import teams from PromptOwl"}),e.jsx(p,{children:"Lets users who signed in with PromptOwl pull their PromptOwl teams in as local teams. Off by default. When off, the PromptOwl Teams panel is hidden and the import API is unavailable."})]}),e.jsx(x,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-sm",children:t.promptowl_teams_enabled?"On":"Off"}),e.jsx(j,{checked:t.promptowl_teams_enabled,onCheckedChange:s=>a({promptowl_teams_enabled:s})})]})})]}),e.jsxs(h,{children:[e.jsxs(m,{children:[e.jsx(u,{className:"text-base",children:"Sub-agent runs (recursion)"}),e.jsx(p,{children:"Lets a run spawn nested sub-agent runs (a call tree). Bounded by depth, fan-out and re-entrancy caps so the tree stays finite. This opens a recursion surface — enable it only after reviewing the caps for your deployment. Requires the workflow plane."})]}),e.jsxs(x,{children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-sm",children:[t.subagent_runs_enabled?"On":"Off",!t.workflow_plane_enabled&&e.jsxs("span",{className:"text-muted-foreground",children:[" ","· enable the workflow plane first"]})]}),e.jsx(j,{checked:t.subagent_runs_enabled,disabled:!t.workflow_plane_enabled,onCheckedChange:s=>a({subagent_runs_enabled:s})})]}),t.subagent_runs_enabled&&e.jsxs("div",{className:"mt-4 grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"Max depth"}),e.jsx(ee,{value:t.subagent_max_depth,min:1,max:32,onChange:s=>a({subagent_max_depth:s})}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"1–32 — how deep the sub-agent call tree may nest."})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium mb-1",children:"Max sub-agents per run"}),e.jsx(ee,{value:t.subagent_max_children,min:1,max:128,onChange:s=>a({subagent_max_children:s})}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"1–128 — fan-out a single run may spawn."})]})]})]})]})]}),e.jsx(E,{value:"community-sites",className:"space-y-4",children:e.jsxs(h,{children:[e.jsx(m,{children:e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{children:[e.jsxs(u,{className:"flex items-center gap-2 text-base",children:[e.jsx(ds,{className:"h-4 w-4 text-muted-foreground"}),"Official community sites"]}),e.jsx(p,{children:"Sites trusted for one-click SSO auto-login. A visitor arriving with a ticket signed by one of these sites' secrets is signed in automatically — the ticket's audience is also checked against this server's own base URL, so a ticket minted for a different deployment can't be replayed here."})]}),e.jsxs(b,{size:"sm",onClick:$e,children:[e.jsx(ve,{className:"h-4 w-4 mr-1.5"}),"Add site"]})]})}),e.jsxs(x,{children:[oe&&e.jsx("div",{role:"alert",className:"mb-4 rounded-md border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive",children:oe}),Y?Y.length===0?e.jsx("p",{className:"text-sm text-muted-foreground py-6",children:"No community sites configured yet. Add one to enable SSO auto-login from it."}):e.jsx("div",{className:"divide-y",children:Y.map(s=>e.jsxs("div",{className:"flex items-center justify-between gap-3 py-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"font-medium text-sm truncate",children:s.name}),e.jsx(Te,{variant:"outline",className:s.is_active?"border-emerald-200 bg-emerald-50 text-emerald-700":"border-muted-foreground/20 text-muted-foreground",children:s.is_active?"Enabled":"Disabled"})]}),e.jsxs("div",{className:"text-xs text-muted-foreground truncate",children:[s.url," · secret ",s.secret_set?"set":"not set"]})]}),e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[e.jsx(j,{checked:s.is_active,onCheckedChange:()=>Ue(s),"aria-label":`Enable ${s.name}`,title:"Enabled sites can sign visitors in with an SSO ticket. This is the admin switch, not a reachability check."}),e.jsx(b,{variant:"outline",size:"sm",onClick:()=>De(s),title:"Edit this community site",children:e.jsx(ns,{className:"h-4 w-4"})}),e.jsx(b,{variant:"outline",size:"sm",className:"text-destructive hover:text-destructive hover:bg-destructive/10",onClick:()=>B(s),title:"Remove this community site",children:e.jsx(hs,{className:"h-4 w-4"})})]})]},s.id))}):e.jsxs("div",{className:"flex items-center gap-2 text-sm text-muted-foreground py-6",children:[e.jsx(I,{className:"h-4 w-4 animate-spin"})," Loading community sites…"]})]})]})}),e.jsx(E,{value:"agents",className:"space-y-4",children:e.jsx(_s,{publicBaseUrl:t.public_base_url,openMode:v==="open"})})]}):e.jsxs("div",{className:"flex items-center gap-2 text-sm text-muted-foreground py-10",children:[e.jsx(I,{className:"h-4 w-4 animate-spin"})," Loading settings…"]}),e.jsx(je,{open:!!C,onOpenChange:s=>!s&&D(null),children:e.jsxs(be,{children:[e.jsxs(ke,{children:[e.jsx(we,{children:(C==null?void 0:C.mode)==="edit"?"Edit community site":"Add community site"}),e.jsx(Ne,{children:"The secret is write-only — leave it blank when editing to keep the current one."})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx(M,{htmlFor:"site-name",children:"Name"}),e.jsx($,{id:"site-name",value:S.name,onChange:s=>O(r=>({...r,name:s.target.value})),placeholder:"Main community site"})]}),e.jsxs("div",{children:[e.jsx(M,{htmlFor:"site-url",children:"Site URL"}),e.jsx($,{id:"site-url",value:S.url,onChange:s=>O(r=>({...r,url:s.target.value})),placeholder:"https://community.example.com"})]}),e.jsxs("div",{children:[e.jsx(M,{htmlFor:"site-secret",children:"Secret key"}),e.jsx($,{id:"site-secret",type:"password",value:S.secret,onChange:s=>O(r=>({...r,secret:s.target.value})),placeholder:(C==null?void 0:C.mode)==="edit"?"Leave blank to keep the current secret":"Shared secret (16+ characters)",...V("password")})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(M,{htmlFor:"site-active",children:"Auto-login enabled"}),e.jsx(j,{id:"site-active",checked:S.is_active,onCheckedChange:s=>O(r=>({...r,is_active:s}))})]}),he&&e.jsx("div",{role:"alert",className:"text-sm text-destructive",children:he})]}),e.jsxs(Ce,{children:[e.jsx(b,{variant:"outline",onClick:()=>D(null),children:"Cancel"}),e.jsxs(b,{onClick:Re,disabled:ce,children:[ce&&e.jsx(I,{className:"h-4 w-4 mr-1.5 animate-spin"}),(C==null?void 0:C.mode)==="edit"?"Save changes":"Add site"]})]})]})}),e.jsx(je,{open:!!P,onOpenChange:s=>!s&&B(null),children:e.jsxs(be,{children:[e.jsxs(ke,{children:[e.jsxs(we,{children:["Remove ",P==null?void 0:P.name,"?"]}),e.jsx(Ne,{children:"Visitors arriving from this site will no longer be auto-signed-in. This can't be undone from here — you'll need to re-add the site and its secret to restore it."})]}),e.jsxs(Ce,{children:[e.jsx(b,{variant:"outline",onClick:()=>B(null),children:"Cancel"}),e.jsxs(b,{variant:"destructive",onClick:ze,disabled:me,children:[me&&e.jsx(I,{className:"h-4 w-4 mr-1.5 animate-spin"}),"Remove"]})]})]})})]})}function Ss(){const{isAdmin:n,refreshHealth:i}=Oe(),t=Pe(),[y,_]=l.useState(null);l.useEffect(()=>{n&&Ve().then(_).catch(()=>{})},[n]);const d=l.useCallback(async g=>{try{const v=await Ye(g);_(v.settings),await i(),await t.invalidateQueries({queryKey:ne.health().queryKey}),z.success("Settings saved")}catch(v){throw v}},[i,t]);return e.jsx(bs,{settings:y,onUpdate:d})}export{Ss as default};
|