@agent-deck/backend 1.5.2 → 1.6.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.
@@ -377,7 +377,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${t.do
377
377
  "Authorization": "Bearer YOUR_TOKEN_HERE",
378
378
  "X-API-Key": "YOUR_API_KEY_HERE"
379
379
  }`,value:g,onChange:E=>{v(E.target.value),w&&k(null)},onBlur:()=>{g.trim()&&H()},rows:6,className:"bg-white/10 border-white/20 text-white placeholder-gray-400 resize-none font-mono text-xs","data-testid":"textarea-headers"}),w&&c.jsxs("p",{className:"text-red-400 text-xs mt-1 flex items-center gap-1",children:[c.jsx(Pr,{className:"w-3 h-3 shrink-0"}),w]}),c.jsx("div",{className:"text-xs text-gray-400 mt-1",children:c.jsx("p",{children:"Enter headers as JSON. Keys are header names, values are header values."})})]})]})]}),f&&c.jsxs("div",{className:"text-red-400 text-sm mt-2",children:[c.jsx(Pr,{className:"w-4 h-4 mr-1"}),f]}),h&&c.jsxs("div",{className:"text-red-400 text-sm mt-2",children:[c.jsx(Pr,{className:"w-4 h-4 mr-1"}),'A service with the name "',h,'" already exists. You can register it anyway, but it might overwrite the existing one.']}),c.jsxs("div",{className:"flex space-x-3 pt-4",children:[c.jsx(ne,{type:"button",variant:"secondary",className:"flex-1 border text-white",style:{background:"#ad095e",borderColor:"#ad095e"},onClick:Z,"data-testid":"button-cancel",children:"Cancel"}),!(e==="mcp"&&r==="local")&&c.jsxs(ne,{type:"button",variant:"ghost",className:`flex-1 border-2 hover:opacity-90 ${Jr}`,style:Yr(wn),disabled:z.isPending||S(),"data-testid":"button-register",onClick:D,children:[c.jsx(ai,{className:"w-4 h-4 mr-2"}),z.isPending?"Registering...":"Register Service"]})]})]})})}async function oP(e){return(await(await _e("POST","/api/export",{scope:e.scope??"collection",...e.deckId?{deckId:e.deckId}:{}})).json()).data}async function n3(e){return(await(await _e("POST","/api/import",e)).json()).data}function sP(e,t){const n=new Blob([`${JSON.stringify(e,null,2)}
380
- `],{type:"application/json"}),r=URL.createObjectURL(n),o=document.createElement("a");o.href=r,o.download=t,o.click(),URL.revokeObjectURL(r)}function r3(e){return e.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,48)||"deck"}function bk(e){const{services:t,playbooks:n,decks:r}=e.counts;return`Decks +${r.created} / skipped ${r.reused}. Services +${t.created} / skipped ${t.reused}. Playbooks +${n.created} / skipped ${n.reused}.`}function o3({decks:e,editingDeckId:t,onSelectDeck:n,isLoading:r}){const[o,s]=b.useState(!1),[i,a]=b.useState(""),l=Zt(),{toast:u}=Ht(),{data:d}=ut({queryKey:["/api/scope/bindings"],refetchInterval:3e3}),f=b.useMemo(()=>mF((d==null?void 0:d.data)??[]),[d]),p=dt({mutationFn:async k=>_e("POST","/api/decks",{name:k,isActive:!1}),onSuccess:async(k,C)=>{var _;const j=await k.json();l.invalidateQueries({queryKey:["/api/decks"]}),(_=j.data)!=null&&_.id&&n(j.data.id),u({title:"Deck created",description:`${C} has been created successfully.`}),s(!1),a("")},onError:k=>{u({title:"Failed to create deck",description:k.message,variant:"destructive"})}}),h=dt({mutationFn:async k=>{const C=await oP({scope:"deck",deckId:k.id});return sP(C,`${r3(k.name)}.agent-deck.json`),C},onSuccess:(k,C)=>{u({title:"Deck exported",description:`${C.name}: ${k.services.length} services, ${k.playbooks.length} playbooks`})},onError:k=>{u({title:"Export failed",description:k.message,variant:"destructive"})}}),y=(k,C)=>{k.stopPropagation(),h.mutate(C)},m=dt({mutationFn:async k=>_e("DELETE",`/api/decks/${k}`,{}),onSuccess:()=>{l.invalidateQueries({queryKey:["/api/decks"]}),u({title:"Deck deleted",description:"Your deck has been deleted successfully."})},onError:k=>{k.message.includes("Cannot delete the last deck")?u({title:"Cannot delete deck",description:"You cannot delete the last deck. Please create another deck first.",variant:"destructive"}):u({title:"Failed to delete deck",description:k.message,variant:"destructive"})}}),x=async(k,C)=>{k.stopPropagation();try{await navigator.clipboard.writeText(C.id),u({title:"Copied deck id",description:"Use with bind_workspace({ workspaceRoot, deckId }) in your agent."})}catch(j){u({title:"Failed to copy deck id",description:j instanceof Error?j.message:"Unknown error",variant:"destructive"})}},g=(k,C)=>{k.stopPropagation(),window.confirm("Are you sure you want to delete this deck? This action cannot be undone.")&&m.mutate(C)},v=k=>{k.preventDefault();const C=i.trim();C&&p.mutate(C)},w=k=>{var C,j,_;return(((C=k.services)==null?void 0:C.length)??0)+(((j=k.credentials)==null?void 0:j.length)??0)+(((_=k.playbooks)==null?void 0:_.length)??0)};return r?c.jsx("div",{className:"bg-black/40 backdrop-blur-md rounded-2xl border border-white/10 p-6 shadow-2xl",children:c.jsxs("div",{className:"animate-pulse space-y-4",children:[c.jsx("div",{className:"h-6 bg-white/10 rounded"}),c.jsx("div",{className:"space-y-3",children:Array.from({length:3}).map((k,C)=>c.jsx("div",{className:"h-16 bg-white/5 rounded-lg"},C))})]})}):c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"h-full flex flex-col","data-testid":"deck-management-panel",children:[c.jsxs("h2",{className:"text-lg font-bold mb-3 flex items-center",children:[c.jsx(kf,{className:"w-4 h-4 mr-2",style:{color:"#92E4DD"}}),c.jsx("span",{style:{color:"#92E4DD"},children:"My Decks"})]}),c.jsx("div",{className:"mb-3",children:c.jsxs(ne,{onClick:()=>s(!0),className:"w-full border text-sm py-2",style:{background:"#C4B643",borderColor:"#C4B643",color:"black"},"data-testid":"create-deck-button",children:[c.jsx(ai,{className:"w-3 h-3 mr-2"}),"Add Deck"]})}),c.jsx("div",{className:"flex-1 overflow-y-auto",children:c.jsx("div",{className:"space-y-2",children:e.map(k=>{const C=k.id===t,j=w(k),_=f.get(k.id)??0,I=gF(j,_);return c.jsxs("div",{className:`p-2 rounded-lg border cursor-pointer transition-all relative group ${C?"bg-gradient-to-r from-yellow-500/20 to-yellow-600/20 border-2 border-yellow-500/40 hover:border-yellow-400/60":"bg-white/5 border border-white/10 hover:border-white/20"}`,onClick:()=>n(k.id),"data-testid":`deck-item-${k.id}`,children:[c.jsxs("div",{className:"absolute top-1 right-1 flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity duration-200",children:[c.jsx(ne,{size:"sm",variant:"secondary",className:"h-5 w-5 p-0",onClick:P=>y(P,k),title:"Export this deck","data-testid":`export-deck-${k.id}`,children:c.jsx(XE,{className:"w-2 h-2"})}),c.jsx(ne,{size:"sm",variant:"secondary",className:"h-5 w-5 p-0",onClick:P=>x(P,k),title:"Copy deck id for bind_workspace",children:c.jsx(Xv,{className:"w-2 h-2"})}),c.jsx(ne,{size:"sm",variant:"destructive",className:"h-5 w-5 p-0 bg-red-500/80 hover:bg-red-500 border-red-400",onClick:P=>g(P,k.id),title:"Delete deck",children:c.jsx(su,{className:"w-2 h-2"})})]}),c.jsxs("div",{children:[c.jsx("h3",{className:`font-semibold text-sm pr-16 ${C?"text-yellow-300":"text-white"}`,children:k.name}),c.jsx("p",{className:"text-xs text-gray-400 select-none pointer-events-none",children:I})]})]},k.id)})})})]}),c.jsx(Fs,{open:o,onOpenChange:s,children:c.jsxs(Fo,{className:"sm:max-w-md border-border bg-[#161612] text-[#E8F6F4]",children:[c.jsx(Uo,{children:c.jsxs(qo,{className:"flex items-center text-xl font-bold",children:[c.jsx(kf,{className:"mr-2 h-5 w-5",style:{color:"#92E4DD"}}),"Create New Deck"]})}),c.jsxs("form",{onSubmit:v,className:"space-y-4","data-testid":"form-create-deck",children:[c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"deckName",children:"Deck Name"}),c.jsx(Xe,{id:"deckName",placeholder:"e.g., Hiring stack",value:i,onChange:k=>a(k.target.value),className:"border-white/15 bg-[#0F0F0C] text-[#E8F6F4] placeholder:text-[#A8C4C0]/60",required:!0,"data-testid":"input-deck-name"})]}),c.jsxs("div",{className:"flex gap-3 pt-2",children:[c.jsx(ne,{type:"button",variant:"outline",className:"flex-1 rounded-full border-white/20 text-[#E8F6F4] hover:bg-white/10",onClick:()=>s(!1),"data-testid":"button-cancel-create",children:"Cancel"}),c.jsx(ne,{type:"submit",className:"flex-1 rounded-full border px-6 text-sm font-semibold hover:opacity-90",style:{background:"#C4B643",borderColor:"#C4B643",color:"black"},disabled:p.isPending,"data-testid":"button-submit-create",children:p.isPending?"Creating…":"Create Deck"})]})]})]})})]})}function s3({open:e,onOpenChange:t}){const[n,r]=b.useState(""),[o,s]=b.useState(""),i=Zt(),{toast:a}=Ht(),l=dt({mutationFn:async()=>_e("POST","/api/credentials",{label:n.trim(),value:o}),onSuccess:()=>{i.invalidateQueries({queryKey:["/api/credentials/vault"]}),i.invalidateQueries({queryKey:["/api/decks"]}),a({title:"API key saved",description:`${n.trim()} is stored securely. Your agent can use it from the active deck.`}),t(!1),r(""),s("")},onError:d=>{a({title:"Could not save API key",description:d.message,variant:"destructive"})}}),u=n.trim().length>0&&o.trim().length>0;return c.jsx(Fs,{open:e,onOpenChange:t,children:c.jsxs(Fo,{className:"sm:max-w-md border-border bg-[#161612] text-[#E8F6F4]",children:[c.jsxs(Uo,{children:[c.jsx(qo,{className:"text-[#E8F6F4]",children:"Register API key"}),c.jsx(Li,{className:"text-[#A8C4C0]",children:"Name the service and paste the key. Agent Deck handles the rest — stored in your vault, never shown again."})]}),c.jsxs("div",{className:"space-y-4",children:[c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"credential-name",className:"text-[#CFEAE6]",children:"Service name"}),c.jsx(Xe,{id:"credential-name",placeholder:"OpenAI, Linear, Slack…",value:n,onChange:d=>r(d.target.value),className:"border-white/15 bg-[#0F0F0C] text-[#E8F6F4] placeholder:text-[#6B8581]"})]}),c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"credential-value",className:"text-[#CFEAE6]",children:"API key"}),c.jsx(Xe,{id:"credential-value",type:"password",placeholder:"Paste key from the service dashboard",value:o,onChange:d=>s(d.target.value),className:"border-white/15 bg-[#0F0F0C] text-[#E8F6F4] placeholder:text-[#6B8581]"})]}),c.jsx(ne,{variant:"ghost",className:`w-full border-2 hover:opacity-90 ${Jr}`,style:Yr(In),onClick:()=>l.mutate(),disabled:!u||l.isPending,children:"Save to vault"})]})]})})}function i3({open:e,onOpenChange:t}){const[n,r]=b.useState(""),[o,s]=b.useState(""),[i,a]=b.useState(""),[l,u]=b.useState(""),[d,f]=b.useState(""),[p,h]=b.useState([]),[y,m]=b.useState([]),x=Zt(),{toast:g}=Ht(),{data:v}=ut({queryKey:["/api/credentials/vault"],enabled:e}),{data:w}=ut({queryKey:["/api/services"],enabled:e}),k=(v==null?void 0:v.data)??[],C=(w==null?void 0:w.data)??[],j=dt({mutationFn:async()=>_e("POST","/api/playbooks",{title:n.trim(),body:o,triggers:i.split(",").map(P=>P.trim()).filter(Boolean),dependsOnCredentialIds:p,dependsOnServiceIds:y,exec:l.trim()||void 0,skill:d.trim()||void 0,autoDetectDependencies:!0}),onSuccess:()=>{x.invalidateQueries({queryKey:["/api/playbooks/vault"]}),g({title:"Playbook saved",description:`${n.trim()} is in your collection.`}),t(!1),r(""),s(""),a(""),u(""),f(""),h([]),m([])},onError:P=>{g({title:"Could not save playbook",description:P.message,variant:"destructive"})}}),_=(P,$,T)=>{T(P.includes($)?P.filter(A=>A!==$):[...P,$])},I=n.trim().length>0&&o.trim().length>0;return c.jsx(Fs,{open:e,onOpenChange:t,children:c.jsxs(Fo,{className:"sm:max-w-2xl max-h-[90vh] overflow-y-auto border-border bg-[#161612] text-[#E8F6F4]",children:[c.jsxs(Uo,{children:[c.jsx(qo,{children:"Register Playbook"}),c.jsxs(Li,{className:"text-[#A8C4C0]",children:["Prefer"," ",c.jsx("span",{className:"font-mono text-xs",children:"register_playbook"})," /"," ",c.jsx("span",{className:"font-mono text-xs",children:"update_playbook"})," from your AI agent. This form also auto-detects API key and MCP dependencies from the content on save."]})]}),c.jsxs("div",{className:"space-y-4",children:[c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"playbook-title",children:"Title"}),c.jsx(Xe,{id:"playbook-title",placeholder:"Hiring inbox, Ashby API guide…",value:n,onChange:P=>r(P.target.value),className:"border-white/15 bg-[#0F0F0C] text-[#E8F6F4]"})]}),c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"playbook-triggers",children:"Triggers (comma-separated)"}),c.jsx(Xe,{id:"playbook-triggers",placeholder:"check inbox, review applicants",value:i,onChange:P=>a(P.target.value),className:"border-white/15 bg-[#0F0F0C] text-[#E8F6F4]"})]}),c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"playbook-body",children:"Instructions (markdown)"}),c.jsx(_o,{id:"playbook-body",rows:8,placeholder:`# Steps
380
+ `],{type:"application/json"}),r=URL.createObjectURL(n),o=document.createElement("a");o.href=r,o.download=t,o.click(),URL.revokeObjectURL(r)}function r3(e){return e.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,48)||"deck"}function bk(e){const{services:t,playbooks:n,decks:r}=e.counts;return`Decks +${r.created} / skipped ${r.reused}. Services +${t.created} / skipped ${t.reused}. Playbooks +${n.created} / skipped ${n.reused}.`}function o3({decks:e,editingDeckId:t,onSelectDeck:n,isLoading:r}){const[o,s]=b.useState(!1),[i,a]=b.useState(""),l=Zt(),{toast:u}=Ht(),{data:d}=ut({queryKey:["/api/scope/bindings"],refetchInterval:3e3}),f=b.useMemo(()=>mF((d==null?void 0:d.data)??[]),[d]),p=dt({mutationFn:async k=>_e("POST","/api/decks",{name:k,isActive:!1}),onSuccess:async(k,C)=>{var _;const j=await k.json();l.invalidateQueries({queryKey:["/api/decks"]}),(_=j.data)!=null&&_.id&&n(j.data.id),u({title:"Deck created",description:`${C} has been created successfully.`}),s(!1),a("")},onError:k=>{u({title:"Failed to create deck",description:k.message,variant:"destructive"})}}),h=dt({mutationFn:async k=>{const C=await oP({scope:"deck",deckId:k.id});return sP(C,`${r3(k.name)}.agent-deck.json`),C},onSuccess:(k,C)=>{u({title:"Deck exported",description:`${C.name}: ${k.services.length} services, ${k.playbooks.length} playbooks`})},onError:k=>{u({title:"Export failed",description:k.message,variant:"destructive"})}}),y=(k,C)=>{k.stopPropagation(),h.mutate(C)},m=dt({mutationFn:async k=>_e("DELETE",`/api/decks/${k}`,{}),onSuccess:()=>{l.invalidateQueries({queryKey:["/api/decks"]}),u({title:"Deck deleted",description:"Your deck has been deleted successfully."})},onError:k=>{k.message.includes("Cannot delete the last deck")?u({title:"Cannot delete deck",description:"You cannot delete the last deck. Please create another deck first.",variant:"destructive"}):u({title:"Failed to delete deck",description:k.message,variant:"destructive"})}}),x=async(k,C)=>{k.stopPropagation();try{await navigator.clipboard.writeText(C.id),u({title:"Copied deck id",description:"Use with bind_workspace({ workspaceRoot, deckId }) in your agent."})}catch(j){u({title:"Failed to copy deck id",description:j instanceof Error?j.message:"Unknown error",variant:"destructive"})}},g=(k,C)=>{k.stopPropagation(),window.confirm("Are you sure you want to delete this deck? This action cannot be undone.")&&m.mutate(C)},v=k=>{k.preventDefault();const C=i.trim();C&&p.mutate(C)},w=k=>{var C,j,_;return(((C=k.services)==null?void 0:C.length)??0)+(((j=k.credentials)==null?void 0:j.length)??0)+(((_=k.playbooks)==null?void 0:_.length)??0)};return r?c.jsx("div",{className:"bg-black/40 backdrop-blur-md rounded-2xl border border-white/10 p-6 shadow-2xl",children:c.jsxs("div",{className:"animate-pulse space-y-4",children:[c.jsx("div",{className:"h-6 bg-white/10 rounded"}),c.jsx("div",{className:"space-y-3",children:Array.from({length:3}).map((k,C)=>c.jsx("div",{className:"h-16 bg-white/5 rounded-lg"},C))})]})}):c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"h-full flex flex-col","data-testid":"deck-management-panel",children:[c.jsxs("h2",{className:"text-lg font-bold mb-3 flex items-center",children:[c.jsx(kf,{className:"w-4 h-4 mr-2",style:{color:"#92E4DD"}}),c.jsx("span",{style:{color:"#92E4DD"},children:"My Decks"})]}),c.jsx("div",{className:"mb-3",children:c.jsxs(ne,{onClick:()=>s(!0),className:"w-full border text-sm py-2",style:{background:"#C4B643",borderColor:"#C4B643",color:"black"},"data-testid":"create-deck-button",children:[c.jsx(ai,{className:"w-3 h-3 mr-2"}),"Add Deck"]})}),c.jsx("div",{className:"flex-1 overflow-y-auto",children:c.jsx("div",{className:"space-y-2",children:e.map(k=>{const C=k.id===t,j=w(k),_=f.get(k.id)??0,I=gF(j,_);return c.jsxs("div",{className:`p-2 rounded-lg border cursor-pointer transition-all relative group ${C?"bg-gradient-to-r from-yellow-500/20 to-yellow-600/20 border-2 border-yellow-500/40 hover:border-yellow-400/60":"bg-white/5 border border-white/10 hover:border-white/20"}`,onClick:()=>n(k.id),"data-testid":`deck-item-${k.id}`,children:[c.jsxs("div",{className:"absolute top-1 right-1 flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity duration-200",children:[c.jsx(ne,{size:"sm",variant:"secondary",className:"h-5 w-5 p-0",onClick:P=>y(P,k),title:"Export this deck","data-testid":`export-deck-${k.id}`,children:c.jsx(XE,{className:"w-2 h-2"})}),c.jsx(ne,{size:"sm",variant:"secondary",className:"h-5 w-5 p-0",onClick:P=>x(P,k),title:"Copy deck id for bind_workspace",children:c.jsx(Xv,{className:"w-2 h-2"})}),c.jsx(ne,{size:"sm",variant:"destructive",className:"h-5 w-5 p-0 bg-red-500/80 hover:bg-red-500 border-red-400",onClick:P=>g(P,k.id),title:"Delete deck",children:c.jsx(su,{className:"w-2 h-2"})})]}),c.jsxs("div",{children:[c.jsx("h3",{className:`font-semibold text-sm pr-16 ${C?"text-yellow-300":"text-white"}`,children:k.name}),c.jsx("p",{className:"text-xs text-gray-400 select-none pointer-events-none",children:I})]})]},k.id)})})})]}),c.jsx(Fs,{open:o,onOpenChange:s,children:c.jsxs(Fo,{className:"sm:max-w-md border-border bg-[#161612] text-[#E8F6F4]",children:[c.jsx(Uo,{children:c.jsxs(qo,{className:"flex items-center text-xl font-bold",children:[c.jsx(kf,{className:"mr-2 h-5 w-5",style:{color:"#92E4DD"}}),"Create New Deck"]})}),c.jsxs("form",{onSubmit:v,className:"space-y-4","data-testid":"form-create-deck",children:[c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"deckName",children:"Deck Name"}),c.jsx(Xe,{id:"deckName",placeholder:"e.g., Hiring stack",value:i,onChange:k=>a(k.target.value),className:"border-white/15 bg-[#0F0F0C] text-[#E8F6F4] placeholder:text-[#A8C4C0]/60",required:!0,"data-testid":"input-deck-name"})]}),c.jsxs("div",{className:"flex gap-3 pt-2",children:[c.jsx(ne,{type:"button",variant:"outline",className:"flex-1 rounded-full border-white/20 text-[#E8F6F4] hover:bg-white/10",onClick:()=>s(!1),"data-testid":"button-cancel-create",children:"Cancel"}),c.jsx(ne,{type:"submit",className:"flex-1 rounded-full border px-6 text-sm font-semibold hover:opacity-90",style:{background:"#C4B643",borderColor:"#C4B643",color:"black"},disabled:p.isPending,"data-testid":"button-submit-create",children:p.isPending?"Creating…":"Create Deck"})]})]})]})})]})}function s3({open:e,onOpenChange:t}){const[n,r]=b.useState(""),[o,s]=b.useState(""),i=Zt(),{toast:a}=Ht(),l=dt({mutationFn:async()=>_e("POST","/api/credentials",{label:n.trim(),value:o}),onSuccess:()=>{i.invalidateQueries({queryKey:["/api/credentials/vault"]}),i.invalidateQueries({queryKey:["/api/decks"]}),a({title:"API key saved",description:`${n.trim()} is stored securely. Your agent can use it from the active deck.`}),t(!1),r(""),s("")},onError:d=>{a({title:"Could not save API key",description:d.message,variant:"destructive"})}}),u=n.trim().length>0&&o.trim().length>0;return c.jsx(Fs,{open:e,onOpenChange:t,children:c.jsxs(Fo,{className:"sm:max-w-md border-border bg-[#161612] text-[#E8F6F4]",children:[c.jsxs(Uo,{children:[c.jsx(qo,{className:"text-[#E8F6F4]",children:"Register API key"}),c.jsx(Li,{className:"text-[#A8C4C0]",children:"Name the service and paste the key. Agent Deck handles the rest — stored in your vault, never shown again."})]}),c.jsxs("div",{className:"space-y-4",children:[c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"credential-name",className:"text-[#CFEAE6]",children:"Service name"}),c.jsx(Xe,{id:"credential-name",placeholder:"OpenAI, Linear, Slack…",value:n,onChange:d=>r(d.target.value),className:"border-white/15 bg-[#0F0F0C] text-[#E8F6F4] placeholder:text-[#6B8581]"})]}),c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"credential-value",className:"text-[#CFEAE6]",children:"API key"}),c.jsx(Xe,{id:"credential-value",type:"password",placeholder:"Paste key from the service dashboard",value:o,onChange:d=>s(d.target.value),className:"border-white/15 bg-[#0F0F0C] text-[#E8F6F4] placeholder:text-[#6B8581]"})]}),c.jsx(ne,{variant:"ghost",className:`w-full border-2 hover:opacity-90 ${Jr}`,style:Yr(In),onClick:()=>l.mutate(),disabled:!u||l.isPending,children:"Save to vault"})]})]})})}function i3({open:e,onOpenChange:t}){const[n,r]=b.useState(""),[o,s]=b.useState(""),[i,a]=b.useState(""),[l,u]=b.useState(""),[d,f]=b.useState(""),[p,h]=b.useState([]),[y,m]=b.useState([]),x=Zt(),{toast:g}=Ht(),{data:v}=ut({queryKey:["/api/credentials/vault"],enabled:e}),{data:w}=ut({queryKey:["/api/services"],enabled:e}),k=(v==null?void 0:v.data)??[],C=(w==null?void 0:w.data)??[],j=dt({mutationFn:async()=>_e("POST","/api/playbooks",{title:n.trim(),body:o,triggers:i.split(",").map(P=>P.trim()).filter(Boolean),dependsOnCredentialIds:p,dependsOnServiceIds:y,exec:l.trim()||void 0,skill:d.trim()||void 0,autoDetectDependencies:!0}),onSuccess:()=>{x.invalidateQueries({queryKey:["/api/playbooks/vault"]}),g({title:"Playbook saved",description:`${n.trim()} is in your collection.`}),t(!1),r(""),s(""),a(""),u(""),f(""),h([]),m([])},onError:P=>{g({title:"Could not save playbook",description:P.message,variant:"destructive"})}}),_=(P,$,T)=>{T(P.includes($)?P.filter(A=>A!==$):[...P,$])},I=n.trim().length>0&&o.trim().length>0;return c.jsx(Fs,{open:e,onOpenChange:t,children:c.jsxs(Fo,{className:"sm:max-w-2xl max-h-[90vh] overflow-y-auto border-border bg-[#161612] text-[#E8F6F4]",children:[c.jsxs(Uo,{children:[c.jsx(qo,{children:"Register Playbook"}),c.jsxs(Li,{className:"text-[#A8C4C0]",children:["Prefer"," ",c.jsx("span",{className:"font-mono text-xs",children:"register_playbook"})," /"," ",c.jsx("span",{className:"font-mono text-xs",children:"update_playbook"})," from your AI agent. This form also auto-detects API key and MCP dependencies from the content on save."]})]}),c.jsxs("div",{className:"space-y-4",children:[c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"playbook-title",children:"Title"}),c.jsx(Xe,{id:"playbook-title",placeholder:"Hiring inbox, Ashby API guide…",value:n,onChange:P=>r(P.target.value),className:"border-white/15 bg-[#0F0F0C] text-[#E8F6F4]"})]}),c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"playbook-triggers",children:"Triggers (comma-separated, max 16)"}),c.jsx(Xe,{id:"playbook-triggers",placeholder:"check inbox, review applicants",value:i,onChange:P=>a(P.target.value),className:"border-white/15 bg-[#0F0F0C] text-[#E8F6F4]"})]}),c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"playbook-body",children:"Instructions (markdown)"}),c.jsx(_o,{id:"playbook-body",rows:8,placeholder:`# Steps
381
381
  1. …
382
382
  2. …`,value:o,onChange:P=>s(P.target.value),className:"border-white/15 bg-[#0F0F0C] text-[#E8F6F4] font-mono text-sm"})]}),c.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{children:"Extra API key deps (optional)"}),c.jsx("p",{className:"text-xs text-gray-500",children:"Merged with auto-detected refs from content."}),c.jsx("div",{className:"max-h-28 overflow-y-auto rounded border border-white/10 p-2 space-y-1",children:k.length===0?c.jsx("p",{className:"text-xs text-gray-500",children:"No API keys registered yet."}):k.map(P=>c.jsxs("label",{className:"flex items-center gap-2 text-xs cursor-pointer",children:[c.jsx("input",{type:"checkbox",checked:p.includes(P.id),onChange:()=>_(p,P.id,h)}),P.label]},P.id))})]}),c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{children:"Extra MCP deps (optional)"}),c.jsx("p",{className:"text-xs text-gray-500",children:"Merged with auto-detected refs from content."}),c.jsx("div",{className:"max-h-28 overflow-y-auto rounded border border-white/10 p-2 space-y-1",children:C.length===0?c.jsx("p",{className:"text-xs text-gray-500",children:"No MCP services registered yet."}):C.map(P=>c.jsxs("label",{className:"flex items-center gap-2 text-xs cursor-pointer",children:[c.jsx("input",{type:"checkbox",checked:y.includes(P.id),onChange:()=>_(y,P.id,m)}),P.name]},P.id))})]})]}),c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"playbook-exec",children:"Suggested exec (optional)"}),c.jsx(Xe,{id:"playbook-exec",placeholder:"agent-deck exec --connections … -- uv run …",value:l,onChange:P=>u(P.target.value),className:"border-white/15 bg-[#0F0F0C] text-[#E8F6F4] font-mono text-xs"})]}),c.jsxs("div",{className:"space-y-2",children:[c.jsx(Be,{htmlFor:"playbook-skill",children:"Skill path hint (optional)"}),c.jsx(Xe,{id:"playbook-skill",placeholder:".cursor/skills/…/SKILL.md",value:d,onChange:P=>f(P.target.value),className:"border-white/15 bg-[#0F0F0C] text-[#E8F6F4] font-mono text-xs"})]}),c.jsx(ne,{variant:"ghost",className:`w-full border-2 hover:opacity-90 ${Jr}`,style:Yr(Sr),onClick:()=>j.mutate(),disabled:!I||j.isPending,children:"Save to collection"})]})]})})}async function cu(e){const t=await e.json();if(!t.success)throw new Error(t.error??"Request failed");return t.data}function kk(e){return e.length===0?null:e.length<=3?e.join(", "):`${e.slice(0,3).join(", ")} and ${e.length-3} more`}async function Gg(e){const t=e?`?status=${encodeURIComponent(e)}`:"",n=await _e("GET",`/api/playbook-patches${t}`);return cu(n)}async function a3(e){const t=await _e("GET",`/api/playbook-patches/${e}/preview`);return cu(t)}async function l3(e){const t=await _e("POST",`/api/playbook-patches/${e}/accept`);return cu(t)}async function c3(e,t){const n=await _e("POST",`/api/playbook-patches/${e}/reject`,{reason:t});return cu(n)}async function u3(e){const t=await _e("GET",`/api/playbooks/${e}/events/count`);return cu(t)}async function _0(e){const t=await e.json();if(!t.success)throw new Error(t.error??"Request failed");return t.data}async function iP(e){const t=new URLSearchParams({available:"1"});e&&t.set("playbookId",e);const n=await _e("GET",`/api/feedback-signals/count?${t.toString()}`);return(await _0(n)).open}async function d3(e){const t=new URLSearchParams;e!=null&&e.status&&t.set("status",e.status),e!=null&&e.playbookId&&t.set("playbookId",e.playbookId),e!=null&&e.deckId&&t.set("deckId",e.deckId),(e==null?void 0:e.excludeInProposal)!==void 0&&t.set("excludeInProposal",e.excludeInProposal?"true":"false");const n=t.toString()?`?${t.toString()}`:"",r=await _e("GET",`/api/feedback-signals${n}`);return _0(r)}async function f3(e){const t=await _e("POST","/api/feedback-signals/discard",{signalIds:e});return _0(t)}function h3(e){return!!e.linkedPatchId&&e.status==="open"}function Ad(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n")}"`}function p3(e){return e==null||e===""?"null":Ad(e)}function m3(e){return`Propose playbook updates from these Agent Deck feedback signals (copied from the Feedback table).
383
383
 
@@ -8,7 +8,7 @@
8
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
10
  <link href="https://fonts.googleapis.com/css2?family=Architects+Daughter&family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&family=Fira+Code:wght@300..700&family=Geist+Mono:wght@100..900&family=Geist:wght@100..900&family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=IBM+Plex+Sans:ital,wght@0,100..700;1,100..700&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&family=Lora:ital,wght@0,400..700;1,400..700&family=Merriweather:ital,opsz,wght@0,18..144,300..900;1,18..144,300..900&family=Montserrat:ital,wght@0,100..900;1,100..900&family=Open+Sans:ital,wght@0,300..800;1,300..800&family=Outfit:wght@100..900&family=Oxanium:wght@200..800&family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Plus+Jakarta+Sans:ital,wght@0,200..800;1,200..800&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto:ital,wght@0,100..900;1,100..900&family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&family=Space+Grotesk:wght@300..700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
11
- <script type="module" crossorigin src="/assets/index-C4c6WJOq.js"></script>
11
+ <script type="module" crossorigin src="/assets/index-BQv_d6hd.js"></script>
12
12
  <link rel="stylesheet" crossorigin href="/assets/index-DI74jZFZ.css">
13
13
  </head>
14
14
  <body>