cognova 0.2.0 → 0.2.3
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/.output/nitro.json +1 -1
- package/.output/public/_nuxt/-AsXrBBy.js +1 -0
- package/.output/public/_nuxt/2W1RPpXM.js +71 -0
- package/.output/public/_nuxt/{C4pxqdgg.js → 5UFq_rDn.js} +1 -1
- package/.output/public/_nuxt/5Zh-9l8_.js +1 -0
- package/.output/public/_nuxt/{DK9jxJ0g.js → 90UksHlj.js} +1 -1
- package/.output/public/_nuxt/{9IQmsEjr.js → 9QKmiSP_.js} +1 -1
- package/.output/public/_nuxt/{BOj6t-oo.js → ARbTpeGy.js} +1 -1
- package/.output/public/_nuxt/{DyRelyfs.js → ApfLnl06.js} +1 -1
- package/.output/public/_nuxt/{DznawRFW.js → B-2BuR5g.js} +1 -1
- package/.output/public/_nuxt/B4u7Mczo.js +1 -0
- package/.output/public/_nuxt/{DAQhmSv4.js → B5dI_yLq.js} +1 -1
- package/.output/public/_nuxt/{Bm9LyG4F.js → B6fnZcA6.js} +1 -1
- package/.output/public/_nuxt/{9QnH0xQM.js → B7uMSBlN.js} +1 -1
- package/.output/public/_nuxt/BBiRyPlN.js +1 -0
- package/.output/public/_nuxt/{iBGCpHdw.js → BF7413u4.js} +2 -2
- package/.output/public/_nuxt/{4MiwzAAt.js → BGtUoCgi.js} +2 -2
- package/.output/public/_nuxt/{CxuZBC8n.js → BHe4VLtR.js} +1 -1
- package/.output/public/_nuxt/{D3RiUGdz.js → BIMBp1Tj.js} +1 -1
- package/.output/public/_nuxt/{g20UHUCv.js → BIvPdoE3.js} +1 -1
- package/.output/public/_nuxt/BKaRtCjP.js +1 -0
- package/.output/public/_nuxt/BLmc9T7l.js +1 -0
- package/.output/public/_nuxt/BMdnU6BF.js +1 -0
- package/.output/public/_nuxt/{CKkC3Ptm.js → BOgdaA_8.js} +1 -1
- package/.output/public/_nuxt/{BffWCM73.js → BQZfTrUg.js} +1 -1
- package/.output/public/_nuxt/BQnublTW.js +1 -0
- package/.output/public/_nuxt/BSsvedap.js +1 -0
- package/.output/public/_nuxt/{Ci7UEZQh.js → BVypxKRT.js} +1 -1
- package/.output/public/_nuxt/{CYP_MLH8.js → BWqJFnZy.js} +1 -1
- package/.output/public/_nuxt/BXxYdXMr.js +1 -0
- package/.output/public/_nuxt/{D_3Rq1BS.js → B_17gAr_.js} +1 -1
- package/.output/public/_nuxt/B_qzFVK_.js +1 -0
- package/.output/public/_nuxt/{BqKFIuRj.js → BbRPwpIX.js} +1 -1
- package/.output/public/_nuxt/BhrzKbv9.js +1 -0
- package/.output/public/_nuxt/{Cqy_L_ip.js → Bl6LNGlA.js} +1 -1
- package/.output/public/_nuxt/{Fukkqjkf.js → BlPToGni.js} +1 -1
- package/.output/public/_nuxt/{DHKLCQRG.js → BlwHr46F.js} +1 -1
- package/.output/public/_nuxt/{C6aqGHu1.js → BnmwiZbF.js} +1 -1
- package/.output/public/_nuxt/BqtxLJaf.js +1 -0
- package/.output/public/_nuxt/{eko-0FUm.js → BrEXdify.js} +1 -1
- package/.output/public/_nuxt/{D3e44mCL.js → BtNnS4m3.js} +1 -1
- package/.output/public/_nuxt/{BCtfQCzC.js → BtVIBBUN.js} +1 -1
- package/.output/public/_nuxt/Bw5h4Jaf.js +1 -0
- package/.output/public/_nuxt/{FvlxxmNk.js → Bwcpy7gC.js} +2 -2
- package/.output/public/_nuxt/{Db2v8O7O.js → C0TUK31m.js} +1 -1
- package/.output/public/_nuxt/C1T4GK6c.js +1 -0
- package/.output/public/_nuxt/C2ANDZen.js +1 -0
- package/.output/public/_nuxt/{CqU2XbzO.js → C2RZSTuy.js} +1 -1
- package/.output/public/_nuxt/C3dYlP5x.js +1 -0
- package/.output/public/_nuxt/{m5kGCDpI.js → C3sh_tLi.js} +3 -3
- package/.output/public/_nuxt/{BjjCvHLT.js → C4zyxZG7.js} +1 -1
- package/.output/public/_nuxt/{C3FxIITy.js → C5I-XBZT.js} +1 -1
- package/.output/public/_nuxt/{yuf23kh9.js → CC4Goztu.js} +1 -1
- package/.output/public/_nuxt/CC77iplr.js +1 -0
- package/.output/public/_nuxt/{xuzLdW-o.js → CFyD2NHP.js} +1 -1
- package/.output/public/_nuxt/{CsJ9KhQ4.js → CGQDTeaO.js} +1 -1
- package/.output/public/_nuxt/{DnjGH3SQ.js → CHpwuMSk.js} +1 -1
- package/.output/public/_nuxt/CLzcRUcs.js +1 -0
- package/.output/public/_nuxt/CM2phu_3.js +1 -0
- package/.output/public/_nuxt/{Cr8ixbr1.js → CQpYRq61.js} +1 -1
- package/.output/public/_nuxt/{C0JKNMDO.js → CUN4bYcg.js} +1 -1
- package/.output/public/_nuxt/{CmzH6R-N.js → CXoITXft.js} +19 -19
- package/.output/public/_nuxt/CYjcQPl-.js +1 -0
- package/.output/public/_nuxt/{DGX0tzL8.js → CZ32KfaS.js} +1 -1
- package/.output/public/_nuxt/CclZMdca.js +1 -0
- package/.output/public/_nuxt/{C69W7k2j.js → CdpT_Vb6.js} +1 -1
- package/.output/public/_nuxt/CflRLvFC.js +1 -0
- package/.output/public/_nuxt/{gBC9k4Qj.js → CkqNv7sq.js} +2 -2
- package/.output/public/_nuxt/ClXDAYjE.js +1 -0
- package/.output/public/_nuxt/CrZGoMo_.js +1 -0
- package/.output/public/_nuxt/{BZXMQuYP.js → CvJtd2Af.js} +1 -1
- package/.output/public/_nuxt/{DKZxeXDQ.js → Cwtd8e-P.js} +1 -1
- package/.output/public/_nuxt/{nIU2F7ia.js → Cx44SSNp.js} +3 -3
- package/.output/public/_nuxt/{BzOqrmGa.js → CxEVzuCn.js} +3 -3
- package/.output/public/_nuxt/{Dy_Cq5LQ.js → CzIMQevQ.js} +1 -1
- package/.output/public/_nuxt/{D6t3dcTl.js → D0P9llU7.js} +1 -1
- package/.output/public/_nuxt/{JJ3634gV.js → D1DYuOOm.js} +1 -1
- package/.output/public/_nuxt/{BAIz-dEB.js → D1dDc8Vw.js} +1 -1
- package/.output/public/_nuxt/{DSRrg8JT.js → D1r0uqf3.js} +1 -1
- package/.output/public/_nuxt/{CNnJrDvu.js → D3a8R1T6.js} +1 -1
- package/.output/public/_nuxt/{B1X4Bzcy.js → D5EZbuub.js} +1 -1
- package/.output/public/_nuxt/D9V13KTK.js +1 -0
- package/.output/public/_nuxt/DAE2hbP7.js +1 -0
- package/.output/public/_nuxt/{Cvp7FI3T.js → DAIbdyS6.js} +1 -1
- package/.output/public/_nuxt/{EuOqK1A6.js → DAvlXjt0.js} +1 -1
- package/.output/public/_nuxt/DBKzwexZ.js +1 -0
- package/.output/public/_nuxt/{wCGVE8_e.js → DEATxnaF.js} +1 -1
- package/.output/public/_nuxt/{cABRLVee.js → DFg8PvHV.js} +1 -1
- package/.output/public/_nuxt/DM4MyqI-.js +1 -0
- package/.output/public/_nuxt/{Cdt3I3Go.js → DNE7kw9s.js} +1 -1
- package/.output/public/_nuxt/DO0oG4fG.js +1 -0
- package/.output/public/_nuxt/{B6S_ob86.js → DPFugPaB.js} +1 -1
- package/.output/public/_nuxt/{DJjDvbZE.js → DQlXU6_H.js} +1 -1
- package/.output/public/_nuxt/DQvuQpwh.js +1 -0
- package/.output/public/_nuxt/{sf57orEk.js → DRlG_bnX.js} +1 -1
- package/.output/public/_nuxt/{C6RC3lA1.js → DSQj-oMk.js} +1 -1
- package/.output/public/_nuxt/{CeIVm4A3.js → DU6ewLkE.js} +1 -1
- package/.output/public/_nuxt/{Cp2MA0cm.js → DWhzQg7B.js} +1 -1
- package/.output/public/_nuxt/{DJMS2og1.js → D_vK6VPK.js} +1 -1
- package/.output/public/_nuxt/{CihWZmJe.js → DaBp0Gba.js} +2 -2
- package/.output/public/_nuxt/DaH2FbAy.js +1 -0
- package/.output/public/_nuxt/{CtYFj7k1.js → DaJo0CeV.js} +1 -1
- package/.output/public/_nuxt/DauLdT7p.js +1 -0
- package/.output/public/_nuxt/{DG-T44jj.js → DdPA4eTX.js} +1 -1
- package/.output/public/_nuxt/{YuTZB7sD.js → DeAGWdWK.js} +1 -1
- package/.output/public/_nuxt/{CitkKxhw.js → DfF1qofg.js} +1 -1
- package/.output/public/_nuxt/{Daz4MeL6.js → DiGBA-aA.js} +1 -1
- package/.output/public/_nuxt/DiJxF69i.js +1 -0
- package/.output/public/_nuxt/{DIoI0uJm.js → DkBIU-1F.js} +1 -1
- package/.output/public/_nuxt/DmAM6bZ0.js +1 -0
- package/.output/public/_nuxt/DmeAKr3J.js +1 -0
- package/.output/public/_nuxt/DmmTnMzZ.js +1 -0
- package/.output/public/_nuxt/{Lwdv_RKd.js → DqsUSndS.js} +1 -1
- package/.output/public/_nuxt/Dvw-hR3Y.js +1 -0
- package/.output/public/_nuxt/{CVgTJeSq.js → Dz6sfh81.js} +1 -1
- package/.output/public/_nuxt/{BYjadNrw.js → FNhYm5FX.js} +1 -1
- package/.output/public/_nuxt/{Nb2jBtYT.js → HOeKUnra.js} +1 -1
- package/.output/public/_nuxt/{CtchsY6e.js → IR1jkN7B.js} +1 -1
- package/.output/public/_nuxt/{DCzfkCGa.js → MpTk6K7N.js} +1 -1
- package/.output/public/_nuxt/NZ7Wz6LP.js +1 -0
- package/.output/public/_nuxt/{DfQu3kEw.js → PqWbiAD2.js} +1 -1
- package/.output/public/_nuxt/{Jez9DHn7.js → Tu4FhMRc.js} +1 -1
- package/.output/public/_nuxt/{B3y_Qqox.js → UKPXYG4z.js} +1 -1
- package/.output/public/_nuxt/{BlAZO7nq.js → UO2Y9Nve.js} +1 -1
- package/.output/public/_nuxt/{KKK6HVeG.js → XHiJSquP.js} +1 -1
- package/.output/public/_nuxt/YGWAImQo.js +1 -0
- package/.output/public/_nuxt/{ghuJ76mD.js → ZR87XvwB.js} +1 -1
- package/.output/public/_nuxt/{yNrp2XvX.js → _E89BQAO.js} +1 -1
- package/.output/public/_nuxt/{C_BdYLzz.js → aiXk7zRt.js} +1 -1
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/91727fcc-bf7f-407f-9b1e-092017fcfee0.json +1 -0
- package/.output/public/_nuxt/cL7whuPe.js +1 -0
- package/.output/public/_nuxt/{BasgsT_S.js → ct6_k5IW.js} +1 -1
- package/.output/public/_nuxt/entry._7ZkP07A.css +1 -0
- package/.output/public/_nuxt/{DTDgHTuh.js → fEUQvmn8.js} +2 -2
- package/.output/public/_nuxt/{FNC8XZTk.js → gGlaVUMD.js} +1 -1
- package/.output/public/_nuxt/gjmGkVlL.js +1 -0
- package/.output/public/_nuxt/{IRSbVPIu.js → m5001Uvl.js} +1 -1
- package/.output/public/_nuxt/{_CYZi8HN.js → mQkFCz_M.js} +1 -1
- package/.output/public/_nuxt/{BxXOsXrM.js → p9l1LjVc.js} +10 -10
- package/.output/public/_nuxt/{BsEZoHd1.js → qR_K5W8V.js} +1 -1
- package/.output/public/_nuxt/{BrNqhp1a.js → t_9QQ4MF.js} +7 -7
- package/.output/public/_nuxt/{pcUI-zuY.js → uc4c4mfb.js} +1 -1
- package/.output/public/_nuxt/{usage.vakN1lvi.css → usage.BDeyCZwW.css} +1 -1
- package/.output/public/_nuxt/wPSLEMBw.js +1 -0
- package/.output/public/_nuxt/xKRwul0f.js +1 -0
- package/.output/public/_nuxt/{BWhMnjID.js → xgpiGSxb.js} +1 -1
- package/.output/public/_nuxt/xxnk7j0F.js +1 -0
- package/.output/public/favicon.svg +1 -0
- package/.output/server/chunks/build/A-BWukSPjS.mjs +1 -0
- package/.output/server/chunks/build/Accordion-BaJYea6e.mjs +1 -0
- package/.output/server/chunks/build/AccordionItem-DdG2zgcN.mjs +1 -0
- package/.output/server/chunks/build/Badge-BrU9UkCv.mjs +1 -0
- package/.output/server/chunks/build/Blockquote-DND8wTkU.mjs +1 -0
- package/.output/server/chunks/build/Callout-1halpaEg.mjs +1 -0
- package/.output/server/chunks/build/Card-BHCSDKDt.mjs +1 -0
- package/.output/server/chunks/build/CardGroup-BOuJcNGp.mjs +1 -0
- package/.output/server/chunks/build/Caution-BP3y-TcC.mjs +1 -0
- package/.output/server/chunks/build/Code-B1xkAS5a.mjs +1 -0
- package/.output/server/chunks/build/CodeCollapse-BIhaNa22.mjs +1 -0
- package/.output/server/chunks/build/CodeGroup-BviYyCuo.mjs +1 -0
- package/.output/server/chunks/build/CodeIcon-CWD5HcV7.mjs +2 -1
- package/.output/server/chunks/build/CodePreview-D8PsCQ6m.mjs +1 -0
- package/.output/server/chunks/build/CodeTree-BUTLupmL.mjs +1 -0
- package/.output/server/chunks/build/Collapsible-BIvXNaSq.mjs +1 -0
- package/.output/server/chunks/build/DropdownMenu-BBrV9nXz.mjs +1 -1
- package/.output/server/chunks/build/EditorToolbar-DIfb5arC.mjs +1 -1
- package/.output/server/chunks/build/Em-DsIz_BnD.mjs +1 -0
- package/.output/server/chunks/build/Field-cwwmSQDT.mjs +1 -0
- package/.output/server/chunks/build/FieldGroup-CAIpQv8s.mjs +1 -0
- package/.output/server/chunks/build/H1-BbFNsPyP.mjs +1 -0
- package/.output/server/chunks/build/H2-vHTl_pWr.mjs +1 -0
- package/.output/server/chunks/build/H3-7eTcfO3s.mjs +1 -0
- package/.output/server/chunks/build/H4-C89p_PKO.mjs +1 -0
- package/.output/server/chunks/build/Hr-Bm8RlL3O.mjs +1 -0
- package/.output/server/chunks/build/Icon-Dp9iy0BI.mjs +1 -0
- package/.output/server/chunks/build/Img-CWLmvN1t.mjs +2 -1
- package/.output/server/chunks/build/Kbd-CQG6I_Ch.mjs +1 -0
- package/.output/server/chunks/build/Li-Bw1QUaGv.mjs +1 -0
- package/.output/server/chunks/build/MDC-Dx0YPDhe.mjs +1 -1
- package/.output/server/chunks/build/Note-CHkjm9jm.mjs +1 -0
- package/.output/server/chunks/build/Ol-D-fPnfFM.mjs +1 -0
- package/.output/server/chunks/build/P-B5YI1V9y.mjs +1 -0
- package/.output/server/chunks/build/Pre-ChiJcf3C.mjs +1 -0
- package/.output/server/chunks/build/ProseH5-DahJyv8h.mjs +1 -0
- package/.output/server/chunks/build/ProseH6-C4Is5h6c.mjs +1 -0
- package/.output/server/chunks/build/Select-BB1oLrCD.mjs +1 -1
- package/.output/server/chunks/build/SelectMenu-DPssg6zD.mjs +1 -1
- package/.output/server/chunks/build/Steps-BZpvXfzb.mjs +1 -0
- package/.output/server/chunks/build/Strong-DXJqOWL3.mjs +1 -0
- package/.output/server/chunks/build/Table-BSrLZ7dt.mjs +1 -0
- package/.output/server/chunks/build/Table-DCwTlhCj.mjs +1 -1
- package/.output/server/chunks/build/Tabs-Dk3nvOFF.mjs +1 -0
- package/.output/server/chunks/build/TabsItem-CDhyuBtJ.mjs +1 -0
- package/.output/server/chunks/build/Tbody-CjMT5oH-.mjs +1 -0
- package/.output/server/chunks/build/Td-ZBVaEjFN.mjs +1 -0
- package/.output/server/chunks/build/Th-D317icbd.mjs +1 -0
- package/.output/server/chunks/build/Thead-Ca_ZESTK.mjs +1 -0
- package/.output/server/chunks/build/Tip-CP3oTARR.mjs +1 -0
- package/.output/server/chunks/build/Tooltip-TRyl6dje.mjs +1 -1
- package/.output/server/chunks/build/Tr-6jI8j9gD.mjs +1 -0
- package/.output/server/chunks/build/{docs-Dk2JnYq3.mjs → Tree-DUhXKd8y.mjs} +46 -2235
- package/.output/server/chunks/build/Tree-DUhXKd8y.mjs.map +1 -0
- package/.output/server/chunks/build/Ul-BUGj_CPb.mjs +1 -0
- package/.output/server/chunks/build/Warning-BJ8G6cxC.mjs +1 -0
- package/.output/server/chunks/build/_id_-DN00UDdO.mjs +1 -0
- package/.output/server/chunks/build/_id_-DN00UDdO.mjs.map +1 -1
- package/.output/server/chunks/build/_name_-BnS_KEfX.mjs +1592 -0
- package/.output/server/chunks/build/_name_-BnS_KEfX.mjs.map +1 -0
- package/.output/server/chunks/build/{_uuid_-0UgdUhfY.mjs → _uuid_-DfJaumTE.mjs} +5 -4
- package/.output/server/chunks/build/{_uuid_-0UgdUhfY.mjs.map → _uuid_-DfJaumTE.mjs.map} +1 -1
- package/.output/server/chunks/build/auth-BGPNH2QJ.mjs +20 -0
- package/.output/server/chunks/build/auth-BGPNH2QJ.mjs.map +1 -0
- package/.output/server/chunks/build/auth-CvD7MqKW.mjs +1 -0
- package/.output/server/chunks/build/auth-CvD7MqKW.mjs.map +1 -1
- package/.output/server/chunks/build/chat-CZMiB68R.mjs +1 -0
- package/.output/server/chunks/build/chat-CZMiB68R.mjs.map +1 -1
- package/.output/server/chunks/build/client.precomputed.mjs +1 -1
- package/.output/server/chunks/build/cookie-C_iulBi6.mjs +1 -1
- package/.output/server/chunks/build/{dashboard-YEscLBQN.mjs → dashboard-CLk1NlbR.mjs} +15 -4
- package/.output/server/chunks/build/dashboard-CLk1NlbR.mjs.map +1 -0
- package/.output/server/chunks/build/{dashboard-CpMVYnDV.mjs → dashboard-CiVTAZuF.mjs} +12 -4
- package/.output/server/chunks/build/{dashboard-CpMVYnDV.mjs.map → dashboard-CiVTAZuF.mjs.map} +1 -1
- package/.output/server/chunks/build/docs-ChGwOPg5.mjs +2204 -0
- package/.output/server/chunks/build/docs-ChGwOPg5.mjs.map +1 -0
- package/.output/server/chunks/build/error-404-BzbcNcdU.mjs +1 -0
- package/.output/server/chunks/build/error-500-uCDjGRW8.mjs +1 -0
- package/.output/server/chunks/build/fetch-BB7Qzkwe.mjs +1 -1
- package/.output/server/chunks/build/{hooks-DP8WoUPS.mjs → hooks-D328DcO6.mjs} +3 -2
- package/.output/server/chunks/build/hooks-D328DcO6.mjs.map +1 -0
- package/.output/server/chunks/build/{index-DVx-QlhP.mjs → index-Byt-3Yq6.mjs} +3 -2
- package/.output/server/chunks/build/{index-DVx-QlhP.mjs.map → index-Byt-3Yq6.mjs.map} +1 -1
- package/.output/server/chunks/build/{index-Ba_bPJgk.mjs → index-C9PuieXh.mjs} +3 -2
- package/.output/server/chunks/build/index-C9PuieXh.mjs.map +1 -0
- package/.output/server/chunks/build/index-C_LcBBgO.mjs +1508 -0
- package/.output/server/chunks/build/index-C_LcBBgO.mjs.map +1 -0
- package/.output/server/chunks/build/index-CxDxc9fm.mjs +1 -1
- package/.output/server/chunks/build/index-DzdvIi8V.mjs +1 -0
- package/.output/server/chunks/build/library-CbWcF5wT.mjs +601 -0
- package/.output/server/chunks/build/library-CbWcF5wT.mjs.map +1 -0
- package/.output/server/chunks/build/{login-BAysbpyX.mjs → login-DnnElTl2.mjs} +15 -7
- package/.output/server/chunks/build/{login-BAysbpyX.mjs.map → login-DnnElTl2.mjs.map} +1 -1
- package/.output/server/chunks/build/memories-BqA719O1.mjs +1 -0
- package/.output/server/chunks/build/memories-BqA719O1.mjs.map +1 -1
- package/.output/server/chunks/build/server.mjs +62 -34
- package/.output/server/chunks/build/server.mjs.map +1 -1
- package/.output/server/chunks/build/settings-DdkKCJ00.mjs +1 -0
- package/.output/server/chunks/build/settings-DdkKCJ00.mjs.map +1 -1
- package/.output/server/chunks/build/styles.mjs +2 -2
- package/.output/server/chunks/build/{tasks-DiOi1HG_.mjs → tasks-DnAFqbtt.mjs} +3 -2
- package/.output/server/chunks/build/tasks-DnAFqbtt.mjs.map +1 -0
- package/.output/server/chunks/build/{usage-H_mcd_fz.mjs → usage-CSrBh4Or.mjs} +159 -44
- package/.output/server/chunks/build/{usage-H_mcd_fz.mjs.map → usage-CSrBh4Or.mjs.map} +1 -1
- package/.output/server/chunks/build/{usePreferences-CzC8fRzd.mjs → usePreferences-DH1QjxOj.mjs} +7 -1
- package/.output/server/chunks/build/usePreferences-DH1QjxOj.mjs.map +1 -0
- package/.output/server/chunks/build/{view-Dc8mvzCB.mjs → view-n2sYa4Zh.mjs} +4 -3
- package/.output/server/chunks/build/{view-Dc8mvzCB.mjs.map → view-n2sYa4Zh.mjs.map} +1 -1
- package/.output/server/chunks/build/virtual_nuxt__Users_tony_Documents_GitHub_second-brain_node_modules_.cache_nuxt_.nuxt_mdc-imports-PtwWlZ2H.mjs +1 -0
- package/.output/server/chunks/nitro/nitro.mjs +1247 -824
- package/.output/server/chunks/nitro/nitro.mjs.map +1 -1
- package/.output/server/chunks/routes/_ws/chat.mjs +2 -1
- package/.output/server/chunks/routes/_ws/chat.mjs.map +1 -1
- package/.output/server/chunks/routes/api/agents/_id/cancel.post.mjs +1 -0
- package/.output/server/chunks/routes/api/agents/_id/cancel.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/agents/_id/run.post.mjs +1 -0
- package/.output/server/chunks/routes/api/agents/_id/run.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/agents/_id/runs.get.mjs +1 -0
- package/.output/server/chunks/routes/api/agents/_id/runs.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/agents/_id/stats.get.mjs +1 -0
- package/.output/server/chunks/routes/api/agents/_id/stats.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/agents/_id_.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/agents/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/agents/_id_.get.mjs +1 -0
- package/.output/server/chunks/routes/api/agents/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/agents/_id_.patch.mjs +1 -0
- package/.output/server/chunks/routes/api/agents/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/agents/stats.get.mjs +1 -0
- package/.output/server/chunks/routes/api/agents/stats.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/auth/_...all_.mjs +1 -0
- package/.output/server/chunks/routes/api/auth/_...all_.mjs.map +1 -1
- package/.output/server/chunks/routes/api/conversations/_id_.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/conversations/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/conversations/_id_.get.mjs +1 -0
- package/.output/server/chunks/routes/api/conversations/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/dashboard/overview.get.mjs +1 -0
- package/.output/server/chunks/routes/api/dashboard/overview.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/documents/_id/public.get.mjs +1 -0
- package/.output/server/chunks/routes/api/documents/_id/public.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/documents/_id/restore.post.mjs +1 -0
- package/.output/server/chunks/routes/api/documents/_id/restore.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/documents/by-path.post.mjs +1 -0
- package/.output/server/chunks/routes/api/documents/by-path.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/documents/index.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/documents/index.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/documents/index.put.mjs +1 -0
- package/.output/server/chunks/routes/api/documents/index.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/fs/delete.post.mjs +1 -0
- package/.output/server/chunks/routes/api/fs/delete.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/fs/list.get.mjs +1 -0
- package/.output/server/chunks/routes/api/fs/list.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/fs/mkdir.post.mjs +1 -0
- package/.output/server/chunks/routes/api/fs/mkdir.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/fs/move.post.mjs +1 -0
- package/.output/server/chunks/routes/api/fs/move.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/fs/read.post.mjs +1 -0
- package/.output/server/chunks/routes/api/fs/read.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/fs/rename.post.mjs +1 -0
- package/.output/server/chunks/routes/api/fs/rename.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/fs/write.post.mjs +1 -0
- package/.output/server/chunks/routes/api/fs/write.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/health.get.mjs +1 -0
- package/.output/server/chunks/routes/api/health.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/home.get.mjs +1 -0
- package/.output/server/chunks/routes/api/home.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/hooks/index.get.mjs +1 -0
- package/.output/server/chunks/routes/api/hooks/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/hooks/index.post.mjs +1 -0
- package/.output/server/chunks/routes/api/hooks/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/hooks/stats.get.mjs +1 -0
- package/.output/server/chunks/routes/api/hooks/stats.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get.mjs +1 -0
- package/.output/server/chunks/routes/api/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get2.mjs +1 -0
- package/.output/server/chunks/routes/api/index.get2.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get3.mjs +1 -0
- package/.output/server/chunks/routes/api/index.get3.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get4.mjs +1 -0
- package/.output/server/chunks/routes/api/index.get4.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get5.mjs +1 -0
- package/.output/server/chunks/routes/api/index.get5.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get6.mjs +1 -0
- package/.output/server/chunks/routes/api/index.get6.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get7.mjs +40 -38
- package/.output/server/chunks/routes/api/index.get7.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get8.mjs +33 -38
- package/.output/server/chunks/routes/api/index.get8.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get9.mjs +83 -0
- package/.output/server/chunks/routes/api/index.get9.mjs.map +1 -0
- package/.output/server/chunks/routes/api/index.post.mjs +1 -0
- package/.output/server/chunks/routes/api/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.post2.mjs +1 -0
- package/.output/server/chunks/routes/api/index.post2.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.post3.mjs +1 -0
- package/.output/server/chunks/routes/api/index.post3.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.post4.mjs +1 -0
- package/.output/server/chunks/routes/api/index.post4.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.put.mjs +1 -0
- package/.output/server/chunks/routes/api/index.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/memory/_id_.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/memory/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/memory/context.get.mjs +1 -0
- package/.output/server/chunks/routes/api/memory/context.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/memory/extract.post.mjs +2 -1
- package/.output/server/chunks/routes/api/memory/extract.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/memory/search.get.mjs +1 -0
- package/.output/server/chunks/routes/api/memory/search.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/memory/store.post.mjs +1 -0
- package/.output/server/chunks/routes/api/memory/store.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/index.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/index.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/index.get.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/projects/index.put.mjs +1 -0
- package/.output/server/chunks/routes/api/projects/index.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/secrets/_key_.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/secrets/_key_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/secrets/_key_.get.mjs +1 -0
- package/.output/server/chunks/routes/api/secrets/_key_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/secrets/_key_.put.mjs +1 -0
- package/.output/server/chunks/routes/api/secrets/_key_.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/skills/_name/export.get.mjs +72 -0
- package/.output/server/chunks/routes/api/skills/_name/export.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/_name/files/create.post.mjs +73 -0
- package/.output/server/chunks/routes/api/skills/_name/files/create.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/_name/files/delete.post.mjs +71 -0
- package/.output/server/chunks/routes/api/skills/_name/files/delete.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/_name/files/read.post.mjs +69 -0
- package/.output/server/chunks/routes/api/skills/_name/files/read.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/_name/files/write.post.mjs +69 -0
- package/.output/server/chunks/routes/api/skills/_name/files/write.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/_name/index.get.mjs +60 -0
- package/.output/server/chunks/routes/api/skills/_name/index.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/_name/rename.post.mjs +87 -0
- package/.output/server/chunks/routes/api/skills/_name/rename.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/_name/toggle.post.mjs +62 -0
- package/.output/server/chunks/routes/api/skills/_name/toggle.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/create.post.mjs +79 -0
- package/.output/server/chunks/routes/api/skills/create.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/generate.post.mjs +143 -0
- package/.output/server/chunks/routes/api/skills/generate.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/import.post.mjs +96 -0
- package/.output/server/chunks/routes/api/skills/import.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/index.get.mjs +82 -0
- package/.output/server/chunks/routes/api/skills/index.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/index.get2.mjs +83 -0
- package/.output/server/chunks/routes/api/skills/index.get2.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/library/check-updates.get.mjs +72 -0
- package/.output/server/chunks/routes/api/skills/library/check-updates.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/skills/library/install.post.mjs +90 -0
- package/.output/server/chunks/routes/api/skills/library/install.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/tasks/_id/restore.post.mjs +1 -0
- package/.output/server/chunks/routes/api/tasks/_id/restore.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/tasks/index.delete.mjs +1 -0
- package/.output/server/chunks/routes/api/tasks/index.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/tasks/index.get.mjs +1 -0
- package/.output/server/chunks/routes/api/tasks/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/tasks/index.put.mjs +1 -0
- package/.output/server/chunks/routes/api/tasks/index.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/tasks/tags.get.mjs +1 -0
- package/.output/server/chunks/routes/api/tasks/tags.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/usage/stats.get.mjs +4 -1
- package/.output/server/chunks/routes/api/usage/stats.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/user/email.patch.mjs +2 -1
- package/.output/server/chunks/routes/api/user/email.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/notifications.mjs +2 -1
- package/.output/server/chunks/routes/notifications.mjs.map +1 -1
- package/.output/server/chunks/routes/renderer.mjs +2 -2
- package/.output/server/chunks/routes/terminal.mjs +2 -1
- package/.output/server/chunks/routes/terminal.mjs.map +1 -1
- package/.output/server/index.mjs +2 -1
- package/.output/server/index.mjs.map +1 -1
- package/.output/server/node_modules/adm-zip/adm-zip.js +949 -0
- package/.output/server/node_modules/adm-zip/headers/entryHeader.js +374 -0
- package/.output/server/node_modules/adm-zip/headers/index.js +2 -0
- package/.output/server/node_modules/adm-zip/headers/mainHeader.js +130 -0
- package/.output/server/node_modules/adm-zip/methods/deflater.js +33 -0
- package/.output/server/node_modules/adm-zip/methods/index.js +3 -0
- package/.output/server/node_modules/adm-zip/methods/inflater.js +34 -0
- package/.output/server/node_modules/adm-zip/methods/zipcrypto.js +175 -0
- package/.output/server/node_modules/adm-zip/package.json +49 -0
- package/.output/server/node_modules/adm-zip/util/constants.js +142 -0
- package/.output/server/node_modules/adm-zip/util/decoder.js +5 -0
- package/.output/server/node_modules/adm-zip/util/errors.js +63 -0
- package/.output/server/node_modules/adm-zip/util/fattr.js +76 -0
- package/.output/server/node_modules/adm-zip/util/index.js +5 -0
- package/.output/server/node_modules/adm-zip/util/utils.js +336 -0
- package/.output/server/node_modules/adm-zip/zipEntry.js +405 -0
- package/.output/server/node_modules/adm-zip/zipFile.js +446 -0
- package/.output/server/package.json +2 -1
- package/Claude/CLAUDE.md +9 -4
- package/Claude/skills/environment/SKILL.md +6 -0
- package/Claude/skills/memory/SKILL.md +6 -0
- package/Claude/skills/project/SKILL.md +6 -0
- package/Claude/skills/secret/SKILL.md +85 -0
- package/Claude/skills/secret/secret.py +146 -0
- package/Claude/skills/skill-creator/SKILL.md +30 -0
- package/Claude/skills/task/SKILL.md +6 -0
- package/README.md +3 -0
- package/app/app.vue +1 -1
- package/app/components/dashboard/StatCards.vue +21 -2
- package/app/components/skills/Card.vue +82 -0
- package/app/components/skills/CreateModal.vue +156 -0
- package/app/components/skills/Editor.vue +135 -0
- package/app/components/skills/FileTree.vue +336 -0
- package/app/components/skills/LibraryCard.vue +122 -0
- package/app/components/skills/RenameModal.vue +84 -0
- package/app/components/usage/UsageCostChart.client.vue +59 -23
- package/app/components/usage/UsageCostChart.server.vue +1 -0
- package/app/components/usage/UsageSourceDonut.client.vue +17 -5
- package/app/components/usage/UsageSourceDonut.server.vue +1 -0
- package/app/components/usage/UsageTopConsumers.vue +13 -3
- package/app/composables/usePreferences.ts +9 -1
- package/app/layouts/auth.vue +0 -10
- package/app/layouts/dashboard.vue +7 -0
- package/app/pages/login.vue +18 -8
- package/app/pages/skills/[name].vue +210 -0
- package/app/pages/skills/index.vue +204 -0
- package/app/pages/skills/library.vue +209 -0
- package/app/pages/usage.vue +43 -16
- package/dist/cli/index.js +35 -36
- package/nuxt.config.ts +9 -0
- package/package.json +5 -3
- package/server/api/skills/[name]/export.get.ts +45 -0
- package/server/api/skills/[name]/files/create.post.ts +45 -0
- package/server/api/skills/[name]/files/delete.post.ts +45 -0
- package/server/api/skills/[name]/files/index.get.ts +28 -0
- package/server/api/skills/[name]/files/read.post.ts +41 -0
- package/server/api/skills/[name]/files/write.post.ts +42 -0
- package/server/api/skills/[name]/index.get.ts +54 -0
- package/server/api/skills/[name]/rename.post.ts +64 -0
- package/server/api/skills/[name]/toggle.post.ts +32 -0
- package/server/api/skills/create.post.ts +51 -0
- package/server/api/skills/generate.post.ts +126 -0
- package/server/api/skills/import.post.ts +87 -0
- package/server/api/skills/index.get.ts +57 -0
- package/server/api/skills/library/check-updates.get.ts +46 -0
- package/server/api/skills/library/index.get.ts +56 -0
- package/server/api/skills/library/install.post.ts +73 -0
- package/server/api/usage/stats.get.ts +4 -2
- package/server/db/schema.ts +17 -0
- package/server/drizzle/migrations/0012_good_deadpool.sql +12 -0
- package/server/drizzle/migrations/0013_swift_snowbird.sql +1 -0
- package/server/drizzle/migrations/meta/0012_snapshot.json +1713 -0
- package/server/drizzle/migrations/meta/0013_snapshot.json +1720 -0
- package/server/drizzle/migrations/meta/_journal.json +14 -0
- package/server/middleware/auth.ts +0 -1
- package/server/plugins/05.skills-catalog.ts +105 -0
- package/server/utils/skills-path.ts +197 -0
- package/shared/types/index.ts +65 -1
- package/.output/public/_nuxt/5ZXA0Ckq.js +0 -1
- package/.output/public/_nuxt/BIIJhjQO.js +0 -1
- package/.output/public/_nuxt/BIckl6wA.js +0 -1
- package/.output/public/_nuxt/BJ3o57WW.js +0 -1
- package/.output/public/_nuxt/BNetzZzF.js +0 -1
- package/.output/public/_nuxt/BS0ofHJK.js +0 -1
- package/.output/public/_nuxt/B_3_hrpn.js +0 -1
- package/.output/public/_nuxt/BaBZjmMC.js +0 -1
- package/.output/public/_nuxt/BaMqDm5u.js +0 -1
- package/.output/public/_nuxt/BhzMoffi.js +0 -1
- package/.output/public/_nuxt/BlhFigLL.js +0 -1
- package/.output/public/_nuxt/BoIxv-gM.js +0 -1
- package/.output/public/_nuxt/Br19oYkq.js +0 -1
- package/.output/public/_nuxt/C0kh_F7v.js +0 -1
- package/.output/public/_nuxt/C61KgSco.js +0 -1
- package/.output/public/_nuxt/CJUdYEdO.js +0 -1
- package/.output/public/_nuxt/CVJQGP1Q.js +0 -1
- package/.output/public/_nuxt/CWMUi89H.js +0 -1
- package/.output/public/_nuxt/Cdu2qGgq.js +0 -1
- package/.output/public/_nuxt/CeIu7z4p.js +0 -1
- package/.output/public/_nuxt/D2689qk4.js +0 -1
- package/.output/public/_nuxt/D31L7Ks6.js +0 -1
- package/.output/public/_nuxt/DB359q8R.js +0 -1
- package/.output/public/_nuxt/DHG66LPS.js +0 -1
- package/.output/public/_nuxt/DJ5V-y_x.js +0 -1
- package/.output/public/_nuxt/DLETdGFL.js +0 -1
- package/.output/public/_nuxt/DOICd-Ld.js +0 -1
- package/.output/public/_nuxt/DPEcH-gi.js +0 -65
- package/.output/public/_nuxt/Db8-_gO7.js +0 -1
- package/.output/public/_nuxt/DgV-EDJ9.js +0 -1
- package/.output/public/_nuxt/Dp2X5R2m.js +0 -1
- package/.output/public/_nuxt/DqB723Z0.js +0 -1
- package/.output/public/_nuxt/Q8Ps7oN5.js +0 -1
- package/.output/public/_nuxt/SXTDhzp6.js +0 -1
- package/.output/public/_nuxt/Sg2Lwc46.js +0 -1
- package/.output/public/_nuxt/_J_7XIn-.js +0 -1
- package/.output/public/_nuxt/builds/meta/a1e9100c-1a4f-4f7e-bb53-9dbe0d07effb.json +0 -1
- package/.output/public/_nuxt/entry.CGxIBGAf.css +0 -1
- package/.output/public/_nuxt/inmzPrjz.js +0 -1
- package/.output/public/_nuxt/oIX-ZDN6.js +0 -1
- package/.output/server/chunks/build/auth-CDHRohj4.mjs +0 -77
- package/.output/server/chunks/build/auth-CDHRohj4.mjs.map +0 -1
- package/.output/server/chunks/build/dashboard-YEscLBQN.mjs.map +0 -1
- package/.output/server/chunks/build/docs-Dk2JnYq3.mjs.map +0 -1
- package/.output/server/chunks/build/hooks-DP8WoUPS.mjs.map +0 -1
- package/.output/server/chunks/build/index-Ba_bPJgk.mjs.map +0 -1
- package/.output/server/chunks/build/tasks-DiOi1HG_.mjs.map +0 -1
- package/.output/server/chunks/build/usePreferences-CzC8fRzd.mjs.map +0 -1
- /package/.output/public/_nuxt/{useCopyToClipboard.Be_IvFWy.css → CodeEditor.Be_IvFWy.css} +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { readFile, stat } from 'fs/promises'
|
|
2
|
+
import { join, normalize } from 'path'
|
|
3
|
+
import { getSkillsDir, getInactiveSkillsDir } from '~~/server/utils/skills-path'
|
|
4
|
+
|
|
5
|
+
export default defineEventHandler(async (event) => {
|
|
6
|
+
const name = getRouterParam(event, 'name')
|
|
7
|
+
if (!name)
|
|
8
|
+
throw createError({ statusCode: 400, message: 'Skill name required' })
|
|
9
|
+
|
|
10
|
+
const body = await readBody<{ path: string }>(event)
|
|
11
|
+
if (!body?.path)
|
|
12
|
+
throw createError({ statusCode: 400, message: 'File path is required' })
|
|
13
|
+
|
|
14
|
+
const skillDir = await findSkillDir(name)
|
|
15
|
+
if (!skillDir)
|
|
16
|
+
throw createError({ statusCode: 404, message: `Skill '${name}' not found` })
|
|
17
|
+
|
|
18
|
+
// Prevent path traversal
|
|
19
|
+
const filePath = normalize(join(skillDir, body.path))
|
|
20
|
+
if (!filePath.startsWith(skillDir))
|
|
21
|
+
throw createError({ statusCode: 403, message: 'Path traversal not allowed' })
|
|
22
|
+
|
|
23
|
+
const fileStat = await stat(filePath).catch(() => null)
|
|
24
|
+
if (!fileStat?.isFile())
|
|
25
|
+
throw createError({ statusCode: 404, message: 'File not found' })
|
|
26
|
+
|
|
27
|
+
const content = await readFile(filePath, 'utf-8')
|
|
28
|
+
return { data: { path: body.path, content } }
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
async function findSkillDir(name: string): Promise<string | null> {
|
|
32
|
+
const activeDir = join(getSkillsDir(), name)
|
|
33
|
+
const activeStat = await stat(activeDir).catch(() => null)
|
|
34
|
+
if (activeStat?.isDirectory()) return activeDir
|
|
35
|
+
|
|
36
|
+
const inactiveDir = join(getInactiveSkillsDir(), name)
|
|
37
|
+
const inactiveStat = await stat(inactiveDir).catch(() => null)
|
|
38
|
+
if (inactiveStat?.isDirectory()) return inactiveDir
|
|
39
|
+
|
|
40
|
+
return null
|
|
41
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { writeFile, mkdir, stat } from 'fs/promises'
|
|
2
|
+
import { join, normalize, dirname } from 'path'
|
|
3
|
+
import { getSkillsDir, getInactiveSkillsDir } from '~~/server/utils/skills-path'
|
|
4
|
+
|
|
5
|
+
export default defineEventHandler(async (event) => {
|
|
6
|
+
const name = getRouterParam(event, 'name')
|
|
7
|
+
if (!name)
|
|
8
|
+
throw createError({ statusCode: 400, message: 'Skill name required' })
|
|
9
|
+
|
|
10
|
+
const body = await readBody<{ path: string, content: string }>(event)
|
|
11
|
+
if (!body?.path)
|
|
12
|
+
throw createError({ statusCode: 400, message: 'File path is required' })
|
|
13
|
+
if (typeof body.content !== 'string')
|
|
14
|
+
throw createError({ statusCode: 400, message: 'Content is required' })
|
|
15
|
+
|
|
16
|
+
const skillDir = await findSkillDir(name)
|
|
17
|
+
if (!skillDir)
|
|
18
|
+
throw createError({ statusCode: 404, message: `Skill '${name}' not found` })
|
|
19
|
+
|
|
20
|
+
// Prevent path traversal
|
|
21
|
+
const filePath = normalize(join(skillDir, body.path))
|
|
22
|
+
if (!filePath.startsWith(skillDir))
|
|
23
|
+
throw createError({ statusCode: 403, message: 'Path traversal not allowed' })
|
|
24
|
+
|
|
25
|
+
// Ensure parent directory exists
|
|
26
|
+
await mkdir(dirname(filePath), { recursive: true })
|
|
27
|
+
await writeFile(filePath, body.content, 'utf-8')
|
|
28
|
+
|
|
29
|
+
return { data: { path: body.path, saved: true } }
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
async function findSkillDir(name: string): Promise<string | null> {
|
|
33
|
+
const activeDir = join(getSkillsDir(), name)
|
|
34
|
+
const activeStat = await stat(activeDir).catch(() => null)
|
|
35
|
+
if (activeStat?.isDirectory()) return activeDir
|
|
36
|
+
|
|
37
|
+
const inactiveDir = join(getInactiveSkillsDir(), name)
|
|
38
|
+
const inactiveStat = await stat(inactiveDir).catch(() => null)
|
|
39
|
+
if (inactiveStat?.isDirectory()) return inactiveDir
|
|
40
|
+
|
|
41
|
+
return null
|
|
42
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { readFile, stat } from 'fs/promises'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import { getSkillsDir, getInactiveSkillsDir, parseSkillFrontmatter, buildSkillFileTree, isCoreSkill } from '~~/server/utils/skills-path'
|
|
4
|
+
import type { SkillDetail } from '~~/shared/types'
|
|
5
|
+
|
|
6
|
+
export default defineEventHandler(async (event) => {
|
|
7
|
+
const name = getRouterParam(event, 'name')
|
|
8
|
+
if (!name)
|
|
9
|
+
throw createError({ statusCode: 400, message: 'Skill name required' })
|
|
10
|
+
|
|
11
|
+
// Check active first, then inactive
|
|
12
|
+
const activeDir = join(getSkillsDir(), name)
|
|
13
|
+
const inactiveDir = join(getInactiveSkillsDir(), name)
|
|
14
|
+
|
|
15
|
+
let skillDir = ''
|
|
16
|
+
let active = false
|
|
17
|
+
|
|
18
|
+
const activeStat = await stat(activeDir).catch(() => null)
|
|
19
|
+
if (activeStat?.isDirectory()) {
|
|
20
|
+
skillDir = activeDir
|
|
21
|
+
active = true
|
|
22
|
+
} else {
|
|
23
|
+
const inactiveStat = await stat(inactiveDir).catch(() => null)
|
|
24
|
+
if (inactiveStat?.isDirectory()) {
|
|
25
|
+
skillDir = inactiveDir
|
|
26
|
+
active = false
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!skillDir)
|
|
31
|
+
throw createError({ statusCode: 404, message: `Skill '${name}' not found` })
|
|
32
|
+
|
|
33
|
+
const skillMdPath = join(skillDir, 'SKILL.md')
|
|
34
|
+
const content = await readFile(skillMdPath, 'utf-8').catch(() => '')
|
|
35
|
+
const meta = parseSkillFrontmatter(content)
|
|
36
|
+
const files = await buildSkillFileTree(skillDir)
|
|
37
|
+
|
|
38
|
+
const detail: SkillDetail = {
|
|
39
|
+
name: meta.name || name,
|
|
40
|
+
description: meta.description || '',
|
|
41
|
+
version: meta.version || '',
|
|
42
|
+
author: meta.author || '',
|
|
43
|
+
active,
|
|
44
|
+
core: isCoreSkill(name),
|
|
45
|
+
allowedTools: meta.allowedTools,
|
|
46
|
+
requiresSecrets: meta.requiresSecrets,
|
|
47
|
+
installedFrom: meta.installedFrom || '',
|
|
48
|
+
fileCount: files.filter(f => f.type === 'file').length,
|
|
49
|
+
meta,
|
|
50
|
+
files
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { data: detail }
|
|
54
|
+
})
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { stat, rename, readFile, writeFile } from 'fs/promises'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import { getSkillsDir, getInactiveSkillsDir, isCoreSkill, validateSkillName } from '~~/server/utils/skills-path'
|
|
4
|
+
|
|
5
|
+
export default defineEventHandler(async (event) => {
|
|
6
|
+
const name = getRouterParam(event, 'name')
|
|
7
|
+
if (!name)
|
|
8
|
+
throw createError({ statusCode: 400, message: 'Skill name required' })
|
|
9
|
+
|
|
10
|
+
if (isCoreSkill(name))
|
|
11
|
+
throw createError({ statusCode: 403, message: `'${name}' is a core skill and cannot be renamed` })
|
|
12
|
+
|
|
13
|
+
const body = await readBody<{ newName: string }>(event)
|
|
14
|
+
if (!body?.newName)
|
|
15
|
+
throw createError({ statusCode: 400, message: 'newName is required' })
|
|
16
|
+
|
|
17
|
+
const nameError = validateSkillName(body.newName)
|
|
18
|
+
if (nameError)
|
|
19
|
+
throw createError({ statusCode: 400, message: nameError })
|
|
20
|
+
|
|
21
|
+
// Find where the skill currently lives
|
|
22
|
+
const activeDir = join(getSkillsDir(), name)
|
|
23
|
+
const inactiveDir = join(getInactiveSkillsDir(), name)
|
|
24
|
+
|
|
25
|
+
let currentDir = ''
|
|
26
|
+
let baseDir = ''
|
|
27
|
+
|
|
28
|
+
const activeStat = await stat(activeDir).catch(() => null)
|
|
29
|
+
if (activeStat?.isDirectory()) {
|
|
30
|
+
currentDir = activeDir
|
|
31
|
+
baseDir = getSkillsDir()
|
|
32
|
+
} else {
|
|
33
|
+
const inactiveStat = await stat(inactiveDir).catch(() => null)
|
|
34
|
+
if (inactiveStat?.isDirectory()) {
|
|
35
|
+
currentDir = inactiveDir
|
|
36
|
+
baseDir = getInactiveSkillsDir()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!currentDir)
|
|
41
|
+
throw createError({ statusCode: 404, message: `Skill '${name}' not found` })
|
|
42
|
+
|
|
43
|
+
const newDir = join(baseDir, body.newName)
|
|
44
|
+
const newDirStat = await stat(newDir).catch(() => null)
|
|
45
|
+
if (newDirStat)
|
|
46
|
+
throw createError({ statusCode: 409, message: `Skill '${body.newName}' already exists` })
|
|
47
|
+
|
|
48
|
+
// Rename directory
|
|
49
|
+
await rename(currentDir, newDir)
|
|
50
|
+
|
|
51
|
+
// Update name in SKILL.md frontmatter if it exists
|
|
52
|
+
const skillMdPath = join(newDir, 'SKILL.md')
|
|
53
|
+
const content = await readFile(skillMdPath, 'utf-8').catch(() => '')
|
|
54
|
+
if (content) {
|
|
55
|
+
const updated = content.replace(
|
|
56
|
+
/^(name:\s*).+$/m,
|
|
57
|
+
`$1${body.newName}`
|
|
58
|
+
)
|
|
59
|
+
if (updated !== content)
|
|
60
|
+
await writeFile(skillMdPath, updated, 'utf-8')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return { data: { name: body.newName } }
|
|
64
|
+
})
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { stat, mkdir, rename } from 'fs/promises'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import { getSkillsDir, getInactiveSkillsDir, isCoreSkill } from '~~/server/utils/skills-path'
|
|
4
|
+
|
|
5
|
+
export default defineEventHandler(async (event) => {
|
|
6
|
+
const name = getRouterParam(event, 'name')
|
|
7
|
+
if (!name)
|
|
8
|
+
throw createError({ statusCode: 400, message: 'Skill name required' })
|
|
9
|
+
|
|
10
|
+
if (isCoreSkill(name))
|
|
11
|
+
throw createError({ statusCode: 403, message: `'${name}' is a core skill and cannot be disabled` })
|
|
12
|
+
|
|
13
|
+
const activeDir = join(getSkillsDir(), name)
|
|
14
|
+
const inactiveDir = join(getInactiveSkillsDir(), name)
|
|
15
|
+
|
|
16
|
+
const activeStat = await stat(activeDir).catch(() => null)
|
|
17
|
+
if (activeStat?.isDirectory()) {
|
|
18
|
+
// Move active -> inactive
|
|
19
|
+
await mkdir(getInactiveSkillsDir(), { recursive: true })
|
|
20
|
+
await rename(activeDir, inactiveDir)
|
|
21
|
+
return { data: { name, active: false } }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const inactiveStat = await stat(inactiveDir).catch(() => null)
|
|
25
|
+
if (inactiveStat?.isDirectory()) {
|
|
26
|
+
// Move inactive -> active
|
|
27
|
+
await rename(inactiveDir, activeDir)
|
|
28
|
+
return { data: { name, active: true } }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
throw createError({ statusCode: 404, message: `Skill '${name}' not found` })
|
|
32
|
+
})
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { mkdir, writeFile, stat } from 'fs/promises'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import { getSkillsDir, validateSkillName } from '~~/server/utils/skills-path'
|
|
4
|
+
|
|
5
|
+
export default defineEventHandler(async (event) => {
|
|
6
|
+
const body = await readBody<{ name: string, description?: string }>(event)
|
|
7
|
+
if (!body?.name)
|
|
8
|
+
throw createError({ statusCode: 400, message: 'Skill name is required' })
|
|
9
|
+
|
|
10
|
+
const nameError = validateSkillName(body.name)
|
|
11
|
+
if (nameError)
|
|
12
|
+
throw createError({ statusCode: 400, message: nameError })
|
|
13
|
+
|
|
14
|
+
const skillDir = join(getSkillsDir(), body.name)
|
|
15
|
+
|
|
16
|
+
// Check if already exists
|
|
17
|
+
const existing = await stat(skillDir).catch(() => null)
|
|
18
|
+
if (existing)
|
|
19
|
+
throw createError({ statusCode: 409, message: `Skill '${body.name}' already exists` })
|
|
20
|
+
|
|
21
|
+
await mkdir(skillDir, { recursive: true })
|
|
22
|
+
|
|
23
|
+
const description = body.description || `Description for ${body.name}`
|
|
24
|
+
|
|
25
|
+
const skillMd = `---
|
|
26
|
+
name: ${body.name}
|
|
27
|
+
description: ${description}
|
|
28
|
+
allowed-tools: Bash, Read
|
|
29
|
+
metadata:
|
|
30
|
+
version: "1.0.0"
|
|
31
|
+
requires-secrets: []
|
|
32
|
+
author: ""
|
|
33
|
+
repository: ""
|
|
34
|
+
installed-from: ""
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
# ${body.name}
|
|
38
|
+
|
|
39
|
+
${description}
|
|
40
|
+
|
|
41
|
+
## Commands
|
|
42
|
+
|
|
43
|
+
\`\`\`bash
|
|
44
|
+
python3 ~/.claude/skills/${body.name}/${body.name}.py <command>
|
|
45
|
+
\`\`\`
|
|
46
|
+
`
|
|
47
|
+
|
|
48
|
+
await writeFile(join(skillDir, 'SKILL.md'), skillMd, 'utf-8')
|
|
49
|
+
|
|
50
|
+
return { data: { name: body.name, path: skillDir } }
|
|
51
|
+
})
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { mkdir, readdir, rm, stat } from 'fs/promises'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import { query } from '@anthropic-ai/claude-agent-sdk'
|
|
4
|
+
import { getInactiveSkillsDir, validateSkillName } from '~~/server/utils/skills-path'
|
|
5
|
+
import { logTokenUsage } from '~~/server/utils/log-token-usage'
|
|
6
|
+
|
|
7
|
+
export default defineEventHandler(async (event) => {
|
|
8
|
+
const body = await readBody<{ name: string, description: string }>(event)
|
|
9
|
+
if (!body?.name || !body?.description)
|
|
10
|
+
throw createError({ statusCode: 400, message: 'name and description are required' })
|
|
11
|
+
|
|
12
|
+
const nameError = validateSkillName(body.name)
|
|
13
|
+
if (nameError)
|
|
14
|
+
throw createError({ statusCode: 400, message: nameError })
|
|
15
|
+
|
|
16
|
+
// Create in inactive-skills so user can review before enabling
|
|
17
|
+
const skillDir = join(getInactiveSkillsDir(), body.name)
|
|
18
|
+
|
|
19
|
+
const existing = await stat(skillDir).catch(() => null)
|
|
20
|
+
if (existing)
|
|
21
|
+
throw createError({ statusCode: 409, message: `Skill '${body.name}' already exists` })
|
|
22
|
+
|
|
23
|
+
await mkdir(skillDir, { recursive: true })
|
|
24
|
+
|
|
25
|
+
const appendInstructions = `You are creating a Claude Code skill called "${body.name}".
|
|
26
|
+
Description: ${body.description}
|
|
27
|
+
|
|
28
|
+
Use the Write tool to create files in the current directory. You MUST create:
|
|
29
|
+
1. SKILL.md with proper frontmatter (name, description, allowed-tools, metadata with version/requires-secrets/author)
|
|
30
|
+
2. A Python script if the skill needs to call APIs or run logic
|
|
31
|
+
|
|
32
|
+
CRITICAL RULES:
|
|
33
|
+
- Use the Write tool to create each file
|
|
34
|
+
- NEVER hardcode API keys, tokens, or secrets. Use get_secret() from the shared library.
|
|
35
|
+
- If the skill needs external API keys, list them in metadata.requires-secrets
|
|
36
|
+
- Import the shared client: sys.path.insert(0, str(Path(__file__).parent.parent)); from _lib.api import get, post, get_secret
|
|
37
|
+
- Use argparse for CLI interface
|
|
38
|
+
- Follow existing skill patterns (task.py, memory.py, etc.)
|
|
39
|
+
|
|
40
|
+
SKILL.md frontmatter format:
|
|
41
|
+
---
|
|
42
|
+
name: ${body.name}
|
|
43
|
+
description: ${body.description}
|
|
44
|
+
allowed-tools: Bash, Read
|
|
45
|
+
metadata:
|
|
46
|
+
version: "1.0.0"
|
|
47
|
+
requires-secrets: []
|
|
48
|
+
author: ""
|
|
49
|
+
repository: ""
|
|
50
|
+
installed-from: ""
|
|
51
|
+
---`
|
|
52
|
+
|
|
53
|
+
const startTime = Date.now()
|
|
54
|
+
let totalInput = 0
|
|
55
|
+
let totalOutput = 0
|
|
56
|
+
let totalCost = 0
|
|
57
|
+
let turns = 0
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const conversation = query({
|
|
61
|
+
prompt: `Create the "${body.name}" skill: ${body.description}`,
|
|
62
|
+
options: {
|
|
63
|
+
systemPrompt: {
|
|
64
|
+
type: 'preset',
|
|
65
|
+
preset: 'claude_code',
|
|
66
|
+
append: appendInstructions
|
|
67
|
+
},
|
|
68
|
+
cwd: skillDir,
|
|
69
|
+
settingSources: ['user'],
|
|
70
|
+
permissionMode: 'bypassPermissions',
|
|
71
|
+
allowDangerouslySkipPermissions: true,
|
|
72
|
+
maxTurns: 30
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
for await (const event of conversation) {
|
|
77
|
+
if (event.type === 'result') {
|
|
78
|
+
// Cast to access usage fields the SDK provides but aren't in the TS types
|
|
79
|
+
const msg = event as unknown as {
|
|
80
|
+
total_cost_usd: number
|
|
81
|
+
num_turns: number
|
|
82
|
+
usage: { input_tokens: number, output_tokens: number }
|
|
83
|
+
}
|
|
84
|
+
totalInput = msg.usage?.input_tokens || 0
|
|
85
|
+
totalOutput = msg.usage?.output_tokens || 0
|
|
86
|
+
totalCost = msg.total_cost_usd || 0
|
|
87
|
+
turns = msg.num_turns || 0
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch (e) {
|
|
91
|
+
console.error('[skills/generate] SDK error:', e)
|
|
92
|
+
// Clean up empty directory on failure
|
|
93
|
+
await rm(skillDir, { recursive: true }).catch(() => {})
|
|
94
|
+
throw createError({ statusCode: 500, message: 'Skill generation failed' })
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Verify files were actually created
|
|
98
|
+
const files = await readdir(skillDir).catch(() => [])
|
|
99
|
+
if (files.length === 0) {
|
|
100
|
+
await rm(skillDir, { recursive: true }).catch(() => {})
|
|
101
|
+
throw createError({ statusCode: 500, message: 'Skill generation produced no files' })
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const durationMs = Date.now() - startTime
|
|
105
|
+
|
|
106
|
+
// Log token usage
|
|
107
|
+
await logTokenUsage({
|
|
108
|
+
source: 'agent',
|
|
109
|
+
sourceName: 'Skill Generator',
|
|
110
|
+
inputTokens: totalInput,
|
|
111
|
+
outputTokens: totalOutput,
|
|
112
|
+
costUsd: totalCost,
|
|
113
|
+
durationMs,
|
|
114
|
+
numTurns: turns
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
data: {
|
|
119
|
+
name: body.name,
|
|
120
|
+
path: skillDir,
|
|
121
|
+
active: false,
|
|
122
|
+
costUsd: totalCost,
|
|
123
|
+
durationMs
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
})
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { stat, mkdir, writeFile } from 'fs/promises'
|
|
2
|
+
import { join, normalize } from 'path'
|
|
3
|
+
import AdmZip from 'adm-zip'
|
|
4
|
+
import { getSkillsDir, getInactiveSkillsDir, validateSkillName } from '~~/server/utils/skills-path'
|
|
5
|
+
|
|
6
|
+
export default defineEventHandler(async (event) => {
|
|
7
|
+
const form = await readMultipartFormData(event)
|
|
8
|
+
if (!form)
|
|
9
|
+
throw createError({ statusCode: 400, message: 'Multipart form data required' })
|
|
10
|
+
|
|
11
|
+
const fileField = form.find(f => f.name === 'file')
|
|
12
|
+
if (!fileField?.data)
|
|
13
|
+
throw createError({ statusCode: 400, message: 'No file uploaded' })
|
|
14
|
+
|
|
15
|
+
const zip = new AdmZip(Buffer.from(fileField.data))
|
|
16
|
+
const entries = zip.getEntries()
|
|
17
|
+
|
|
18
|
+
if (entries.length === 0)
|
|
19
|
+
throw createError({ statusCode: 400, message: 'Zip file is empty' })
|
|
20
|
+
|
|
21
|
+
// Determine skill name from root folder or filename
|
|
22
|
+
const firstEntry = entries[0].entryName
|
|
23
|
+
const rootFolder = firstEntry.includes('/') ? firstEntry.split('/')[0] : null
|
|
24
|
+
const fileName = fileField.filename?.replace(/\.zip$/i, '') || ''
|
|
25
|
+
const skillName = rootFolder || fileName
|
|
26
|
+
|
|
27
|
+
if (!skillName)
|
|
28
|
+
throw createError({ statusCode: 400, message: 'Could not determine skill name from zip' })
|
|
29
|
+
|
|
30
|
+
const nameError = validateSkillName(skillName)
|
|
31
|
+
if (nameError)
|
|
32
|
+
throw createError({ statusCode: 400, message: `Invalid skill name: ${nameError}` })
|
|
33
|
+
|
|
34
|
+
// Check skill doesn't already exist
|
|
35
|
+
const activeDir = join(getSkillsDir(), skillName)
|
|
36
|
+
const inactiveDir = join(getInactiveSkillsDir(), skillName)
|
|
37
|
+
|
|
38
|
+
const activeExists = await stat(activeDir).catch(() => null)
|
|
39
|
+
const inactiveExists = await stat(inactiveDir).catch(() => null)
|
|
40
|
+
|
|
41
|
+
if (activeExists || inactiveExists)
|
|
42
|
+
throw createError({ statusCode: 409, message: `Skill '${skillName}' already exists` })
|
|
43
|
+
|
|
44
|
+
// Validate zip contains SKILL.md
|
|
45
|
+
const hasSkillMd = entries.some((e) => {
|
|
46
|
+
const parts = e.entryName.split('/')
|
|
47
|
+
// SKILL.md at root or inside one-level folder
|
|
48
|
+
return parts[parts.length - 1] === 'SKILL.md'
|
|
49
|
+
|| (parts.length === 2 && parts[1] === 'SKILL.md')
|
|
50
|
+
})
|
|
51
|
+
if (!hasSkillMd)
|
|
52
|
+
throw createError({ statusCode: 400, message: 'Zip must contain a SKILL.md file' })
|
|
53
|
+
|
|
54
|
+
// Extract to skills dir with path traversal protection
|
|
55
|
+
const targetDir = activeDir
|
|
56
|
+
await mkdir(targetDir, { recursive: true })
|
|
57
|
+
|
|
58
|
+
let fileCount = 0
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
if (entry.isDirectory) continue
|
|
61
|
+
|
|
62
|
+
// Strip root folder prefix if present
|
|
63
|
+
let relativePath = entry.entryName
|
|
64
|
+
if (rootFolder && relativePath.startsWith(rootFolder + '/'))
|
|
65
|
+
relativePath = relativePath.slice(rootFolder.length + 1)
|
|
66
|
+
|
|
67
|
+
if (!relativePath) continue
|
|
68
|
+
|
|
69
|
+
// Skip __pycache__ and .pyc files
|
|
70
|
+
if (relativePath.includes('__pycache__') || relativePath.endsWith('.pyc'))
|
|
71
|
+
continue
|
|
72
|
+
|
|
73
|
+
// Path traversal check
|
|
74
|
+
const fullPath = normalize(join(targetDir, relativePath))
|
|
75
|
+
if (!fullPath.startsWith(targetDir))
|
|
76
|
+
throw createError({ statusCode: 400, message: 'Path traversal detected in zip entry' })
|
|
77
|
+
|
|
78
|
+
// Ensure parent directory exists
|
|
79
|
+
const parentDir = join(fullPath, '..')
|
|
80
|
+
await mkdir(parentDir, { recursive: true })
|
|
81
|
+
|
|
82
|
+
await writeFile(fullPath, entry.getData())
|
|
83
|
+
fileCount++
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return { data: { name: skillName, fileCount } }
|
|
87
|
+
})
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { readdir, readFile, stat } from 'fs/promises'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import { getSkillsDir, getInactiveSkillsDir, parseSkillFrontmatter, isCoreSkill } from '~~/server/utils/skills-path'
|
|
4
|
+
import type { SkillListItem } from '~~/shared/types'
|
|
5
|
+
|
|
6
|
+
export default defineEventHandler(async () => {
|
|
7
|
+
const skills: SkillListItem[] = []
|
|
8
|
+
|
|
9
|
+
// Scan active skills
|
|
10
|
+
await scanDir(getSkillsDir(), true, skills)
|
|
11
|
+
|
|
12
|
+
// Scan inactive skills
|
|
13
|
+
await scanDir(getInactiveSkillsDir(), false, skills)
|
|
14
|
+
|
|
15
|
+
// Sort: core first, then alphabetical
|
|
16
|
+
skills.sort((a, b) => {
|
|
17
|
+
if (a.core !== b.core) return a.core ? -1 : 1
|
|
18
|
+
return a.name.localeCompare(b.name)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
return { data: skills }
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
async function scanDir(dir: string, active: boolean, skills: SkillListItem[]): Promise<void> {
|
|
25
|
+
const entries = await readdir(dir).catch(() => [])
|
|
26
|
+
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
// Skip _lib and hidden dirs
|
|
29
|
+
if (entry.startsWith('_') || entry.startsWith('.'))
|
|
30
|
+
continue
|
|
31
|
+
|
|
32
|
+
const skillDir = join(dir, entry)
|
|
33
|
+
const stats = await stat(skillDir).catch(() => null)
|
|
34
|
+
if (!stats?.isDirectory()) continue
|
|
35
|
+
|
|
36
|
+
const skillMdPath = join(skillDir, 'SKILL.md')
|
|
37
|
+
const content = await readFile(skillMdPath, 'utf-8').catch(() => '')
|
|
38
|
+
const meta = parseSkillFrontmatter(content)
|
|
39
|
+
|
|
40
|
+
// Count files (excluding __pycache__)
|
|
41
|
+
const files = await readdir(skillDir).catch(() => [])
|
|
42
|
+
const fileCount = files.filter(f => f !== '__pycache__' && !f.endsWith('.pyc')).length
|
|
43
|
+
|
|
44
|
+
skills.push({
|
|
45
|
+
name: meta.name || entry,
|
|
46
|
+
description: meta.description || '',
|
|
47
|
+
version: meta.version || '',
|
|
48
|
+
author: meta.author || '',
|
|
49
|
+
active,
|
|
50
|
+
core: isCoreSkill(entry),
|
|
51
|
+
allowedTools: meta.allowedTools,
|
|
52
|
+
requiresSecrets: meta.requiresSecrets,
|
|
53
|
+
installedFrom: meta.installedFrom || '',
|
|
54
|
+
fileCount
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { readFile, readdir, stat } from 'fs/promises'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import { getDb } from '~~/server/db'
|
|
4
|
+
import { getSkillsDir, getInactiveSkillsDir, parseSkillFrontmatter } from '~~/server/utils/skills-path'
|
|
5
|
+
|
|
6
|
+
export default defineEventHandler(async () => {
|
|
7
|
+
const db = getDb()
|
|
8
|
+
const catalogItems = await db.query.skillsCatalog.findMany()
|
|
9
|
+
|
|
10
|
+
if (catalogItems.length === 0)
|
|
11
|
+
return { data: { updates: [] } }
|
|
12
|
+
|
|
13
|
+
const catalogByName = new Map(catalogItems.map(c => [c.name, c]))
|
|
14
|
+
const updates: { name: string, installed: string, latest: string }[] = []
|
|
15
|
+
|
|
16
|
+
// Scan both active and inactive skill dirs
|
|
17
|
+
for (const dir of [getSkillsDir(), getInactiveSkillsDir()]) {
|
|
18
|
+
const dirStat = await stat(dir).catch(() => null)
|
|
19
|
+
if (!dirStat) continue
|
|
20
|
+
|
|
21
|
+
const entries = await readdir(dir, { withFileTypes: true })
|
|
22
|
+
for (const entry of entries) {
|
|
23
|
+
if (!entry.isDirectory()) continue
|
|
24
|
+
|
|
25
|
+
const skillMdPath = join(dir, entry.name, 'SKILL.md')
|
|
26
|
+
const content = await readFile(skillMdPath, 'utf-8').catch(() => '')
|
|
27
|
+
if (!content) continue
|
|
28
|
+
|
|
29
|
+
const meta = parseSkillFrontmatter(content)
|
|
30
|
+
if (!meta.installedFrom) continue
|
|
31
|
+
|
|
32
|
+
const catalogEntry = catalogByName.get(entry.name)
|
|
33
|
+
if (!catalogEntry) continue
|
|
34
|
+
|
|
35
|
+
if (meta.version && meta.version !== catalogEntry.version) {
|
|
36
|
+
updates.push({
|
|
37
|
+
name: entry.name,
|
|
38
|
+
installed: meta.version,
|
|
39
|
+
latest: catalogEntry.version
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return { data: { updates } }
|
|
46
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { readFile, stat } from 'fs/promises'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import { getDb } from '~~/server/db'
|
|
4
|
+
import { getSkillsDir, getInactiveSkillsDir, parseSkillFrontmatter } from '~~/server/utils/skills-path'
|
|
5
|
+
|
|
6
|
+
export default defineEventHandler(async () => {
|
|
7
|
+
const db = getDb()
|
|
8
|
+
const catalogItems = await db.query.skillsCatalog.findMany()
|
|
9
|
+
|
|
10
|
+
// Check which skills are already installed
|
|
11
|
+
const skillsDir = getSkillsDir()
|
|
12
|
+
const inactiveDir = getInactiveSkillsDir()
|
|
13
|
+
|
|
14
|
+
const items = await Promise.all(catalogItems.map(async (item) => {
|
|
15
|
+
const activePath = join(skillsDir, item.name, 'SKILL.md')
|
|
16
|
+
const inactivePath = join(inactiveDir, item.name, 'SKILL.md')
|
|
17
|
+
|
|
18
|
+
let installed = false
|
|
19
|
+
let installedVersion: string | undefined
|
|
20
|
+
|
|
21
|
+
// Check active skills
|
|
22
|
+
const activeStat = await stat(activePath).catch(() => null)
|
|
23
|
+
if (activeStat) {
|
|
24
|
+
installed = true
|
|
25
|
+
const content = await readFile(activePath, 'utf-8').catch(() => '')
|
|
26
|
+
const meta = parseSkillFrontmatter(content)
|
|
27
|
+
installedVersion = meta.version
|
|
28
|
+
} else {
|
|
29
|
+
// Check inactive skills
|
|
30
|
+
const inactiveStat = await stat(inactivePath).catch(() => null)
|
|
31
|
+
if (inactiveStat) {
|
|
32
|
+
installed = true
|
|
33
|
+
const content = await readFile(inactivePath, 'utf-8').catch(() => '')
|
|
34
|
+
const meta = parseSkillFrontmatter(content)
|
|
35
|
+
installedVersion = meta.version
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
id: item.id,
|
|
41
|
+
name: item.name,
|
|
42
|
+
description: item.description,
|
|
43
|
+
version: item.version,
|
|
44
|
+
author: item.author,
|
|
45
|
+
tags: item.tags || [],
|
|
46
|
+
requiresSecrets: item.requiresSecrets || [],
|
|
47
|
+
files: item.files || [],
|
|
48
|
+
updatedAt: item.updatedAt.toISOString(),
|
|
49
|
+
installed,
|
|
50
|
+
installedVersion,
|
|
51
|
+
hasUpdate: installed && installedVersion ? installedVersion !== item.version : false
|
|
52
|
+
}
|
|
53
|
+
}))
|
|
54
|
+
|
|
55
|
+
return { data: items }
|
|
56
|
+
})
|