cognova 0.1.10 → 0.2.2
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/{BLIw7q7e.js → 4MiwzAAt.js} +2 -2
- package/.output/public/_nuxt/{B8gRcrNP.js → 5ZXA0Ckq.js} +1 -1
- package/.output/public/_nuxt/9IQmsEjr.js +1 -0
- package/.output/public/_nuxt/{DlmPGBGX.js → 9QnH0xQM.js} +1 -1
- package/.output/public/_nuxt/{Qi4Arc25.js → B1X4Bzcy.js} +1 -1
- package/.output/public/_nuxt/{kuWCWJ92.js → B3y_Qqox.js} +1 -1
- package/.output/public/_nuxt/{CJVO4EWp.js → B6S_ob86.js} +1 -1
- package/.output/public/_nuxt/{xdp-pGVh.js → BAIz-dEB.js} +1 -1
- package/.output/public/_nuxt/{DIF41aNz.js → BCtfQCzC.js} +1 -1
- package/.output/public/_nuxt/BIIJhjQO.js +1 -0
- package/.output/public/_nuxt/{QOhiCNXN.js → BIckl6wA.js} +1 -1
- package/.output/public/_nuxt/{CqsT2LL7.js → BJ3o57WW.js} +1 -1
- package/.output/public/_nuxt/BNetzZzF.js +1 -0
- package/.output/public/_nuxt/{C5jkgqcy.js → BOj6t-oo.js} +1 -1
- package/.output/public/_nuxt/BS0ofHJK.js +1 -0
- package/.output/public/_nuxt/{CdKHIoKZ.js → BWhMnjID.js} +1 -1
- package/.output/public/_nuxt/{BUjpjVNI.js → BYjadNrw.js} +1 -1
- package/.output/public/_nuxt/{DLkyutNs.js → BZXMQuYP.js} +1 -1
- package/.output/public/_nuxt/B_3_hrpn.js +1 -0
- package/.output/public/_nuxt/BaBZjmMC.js +1 -0
- package/.output/public/_nuxt/BaMqDm5u.js +1 -0
- package/.output/public/_nuxt/{DwSbu8wg.js → BasgsT_S.js} +1 -1
- package/.output/public/_nuxt/{B4nb4eka.js → BffWCM73.js} +1 -1
- package/.output/public/_nuxt/{BxaDmjPM.js → BhzMoffi.js} +1 -1
- package/.output/public/_nuxt/{DjzaeRs8.js → BjjCvHLT.js} +1 -1
- package/.output/public/_nuxt/{CtJTw_81.js → BlAZO7nq.js} +1 -1
- package/.output/public/_nuxt/{C6nLQFo5.js → BlhFigLL.js} +1 -1
- package/.output/public/_nuxt/{CiJs9fhO.js → Bm9LyG4F.js} +1 -1
- package/.output/public/_nuxt/BoIxv-gM.js +1 -0
- package/.output/public/_nuxt/{C8xYfk_L.js → BqKFIuRj.js} +1 -1
- package/.output/public/_nuxt/Br19oYkq.js +1 -0
- package/.output/public/_nuxt/{htEHZODo.js → BrNqhp1a.js} +3 -3
- package/.output/public/_nuxt/{DFKQfGt8.js → BsEZoHd1.js} +1 -1
- package/.output/public/_nuxt/{CmF_IsFj.js → BxXOsXrM.js} +3 -3
- package/.output/public/_nuxt/{q7M6chAB.js → BzOqrmGa.js} +3 -3
- package/.output/public/_nuxt/{DT_NtxcV.js → C0JKNMDO.js} +1 -1
- package/.output/public/_nuxt/{BOb3QiPL.js → C0kh_F7v.js} +1 -1
- package/.output/public/_nuxt/{D472oOJg.js → C3FxIITy.js} +1 -1
- package/.output/public/_nuxt/{Bh7WRSzZ.js → C4pxqdgg.js} +1 -1
- package/.output/public/_nuxt/{ByWk4RVe.js → C61KgSco.js} +1 -1
- package/.output/public/_nuxt/{TjI_tk0y.js → C69W7k2j.js} +1 -1
- package/.output/public/_nuxt/{uqOLgWHD.js → C6RC3lA1.js} +1 -1
- package/.output/public/_nuxt/{DvA5meSv.js → C6aqGHu1.js} +1 -1
- package/.output/public/_nuxt/{CQM_5Ht0.js → CJUdYEdO.js} +1 -1
- package/.output/public/_nuxt/{BzWvPP8W.js → CKkC3Ptm.js} +1 -1
- package/.output/public/_nuxt/CNnJrDvu.js +1 -0
- package/.output/public/_nuxt/{Bf2SSE6Q.js → CVJQGP1Q.js} +1 -1
- package/.output/public/_nuxt/{0p0wrrYN.js → CVgTJeSq.js} +1 -1
- package/.output/public/_nuxt/CWMUi89H.js +1 -0
- package/.output/public/_nuxt/{DUYrX_jl.js → CYP_MLH8.js} +1 -1
- package/.output/public/_nuxt/{DEDt4pMc.js → C_BdYLzz.js} +1 -1
- package/.output/public/_nuxt/{CU3_Ewk2.js → Cdt3I3Go.js} +1 -1
- package/.output/public/_nuxt/{DX5y-Dpt.js → Cdu2qGgq.js} +1 -1
- package/.output/public/_nuxt/{DQunOghN.js → CeIVm4A3.js} +1 -1
- package/.output/public/_nuxt/CeIu7z4p.js +1 -0
- package/.output/public/_nuxt/{B73gh0JS.js → Ci7UEZQh.js} +1 -1
- package/.output/public/_nuxt/{C7NKjT6R.js → CihWZmJe.js} +2 -2
- package/.output/public/_nuxt/{902fefRh.js → CitkKxhw.js} +1 -1
- package/.output/public/_nuxt/{DH_IrAcJ.js → CmzH6R-N.js} +2 -2
- package/.output/public/_nuxt/{CgPM54k_.js → Cp2MA0cm.js} +1 -1
- package/.output/public/_nuxt/{hfaTbWV_.js → CqU2XbzO.js} +1 -1
- package/.output/public/_nuxt/{CuxiR1jN.js → Cqy_L_ip.js} +1 -1
- package/.output/public/_nuxt/{BFmbqknL.js → Cr8ixbr1.js} +1 -1
- package/.output/public/_nuxt/{BkiRMhMm.js → CsJ9KhQ4.js} +1 -1
- package/.output/public/_nuxt/{Dhvv7eaa.js → CtYFj7k1.js} +1 -1
- package/.output/public/_nuxt/{DG0VCYsy.js → CtchsY6e.js} +1 -1
- package/.output/public/_nuxt/{pqmDf_cQ.js → Cvp7FI3T.js} +1 -1
- package/.output/public/_nuxt/{38G-HXi8.js → CxuZBC8n.js} +5 -5
- package/.output/public/_nuxt/D2689qk4.js +1 -0
- package/.output/public/_nuxt/{Dw5YM8ji.js → D31L7Ks6.js} +1 -1
- package/.output/public/_nuxt/{DYTkcgRd.js → D3RiUGdz.js} +1 -1
- package/.output/public/_nuxt/{Csa19Lyu.js → D3e44mCL.js} +1 -1
- package/.output/public/_nuxt/{DmXY_FiQ.js → D6t3dcTl.js} +1 -1
- package/.output/public/_nuxt/{ChNxcBlH.js → DAQhmSv4.js} +1 -1
- package/.output/public/_nuxt/{BFtDSgo7.js → DB359q8R.js} +1 -1
- package/.output/public/_nuxt/{CrUNulhU.js → DCzfkCGa.js} +1 -1
- package/.output/public/_nuxt/{Cn1H4f01.js → DG-T44jj.js} +1 -1
- package/.output/public/_nuxt/{CAGIVdiL.js → DGX0tzL8.js} +1 -1
- package/.output/public/_nuxt/DHG66LPS.js +1 -0
- package/.output/public/_nuxt/{BV0QyLX9.js → DHKLCQRG.js} +1 -1
- package/.output/public/_nuxt/{DFs-kxzi.js → DIoI0uJm.js} +1 -1
- package/.output/public/_nuxt/{koWn-xAZ.js → DJ5V-y_x.js} +1 -1
- package/.output/public/_nuxt/{HUnwr3r4.js → DJMS2og1.js} +1 -1
- package/.output/public/_nuxt/{CjfarCg3.js → DJjDvbZE.js} +1 -1
- package/.output/public/_nuxt/DK9jxJ0g.js +1 -0
- package/.output/public/_nuxt/{BjN5vE4c.js → DKZxeXDQ.js} +1 -1
- package/.output/public/_nuxt/{CcWl1F-m.js → DLETdGFL.js} +1 -1
- package/.output/public/_nuxt/DOICd-Ld.js +1 -0
- package/.output/public/_nuxt/{bX88p2Mb.js → DPEcH-gi.js} +3 -3
- package/.output/public/_nuxt/{DDqY0xzR.js → DSRrg8JT.js} +1 -1
- package/.output/public/_nuxt/{B67bSHkr.js → DTDgHTuh.js} +2 -2
- package/.output/public/_nuxt/{BYzrgyQu.js → D_3Rq1BS.js} +1 -1
- package/.output/public/_nuxt/{TQO0uTDM.js → Daz4MeL6.js} +1 -1
- package/.output/public/_nuxt/{DxkqpACx.js → Db2v8O7O.js} +1 -1
- package/.output/public/_nuxt/{CHa8PuBL.js → Db8-_gO7.js} +1 -1
- package/.output/public/_nuxt/{BUEnkhcM.js → DfQu3kEw.js} +1 -1
- package/.output/public/_nuxt/{hDpBJf9-.js → DgV-EDJ9.js} +1 -1
- package/.output/public/_nuxt/{D1CNUSvv.js → DnjGH3SQ.js} +1 -1
- package/.output/public/_nuxt/Dp2X5R2m.js +1 -0
- package/.output/public/_nuxt/DqB723Z0.js +1 -0
- package/.output/public/_nuxt/{DcIiuvW-.js → DyRelyfs.js} +1 -1
- package/.output/public/_nuxt/{sgWRawF5.js → Dy_Cq5LQ.js} +1 -1
- package/.output/public/_nuxt/{B4T7pJz5.js → DznawRFW.js} +1 -1
- package/.output/public/_nuxt/EuOqK1A6.js +1 -0
- package/.output/public/_nuxt/{Dn4PGlE2.js → FNC8XZTk.js} +1 -1
- package/.output/public/_nuxt/{ZToTf_46.js → Fukkqjkf.js} +1 -1
- package/.output/public/_nuxt/{D5aulRKh.js → FvlxxmNk.js} +2 -2
- package/.output/public/_nuxt/{C2IkB9Vg.js → IRSbVPIu.js} +1 -1
- package/.output/public/_nuxt/{QESaAMMF.js → JJ3634gV.js} +1 -1
- package/.output/public/_nuxt/{DGUr7xQ7.js → Jez9DHn7.js} +1 -1
- package/.output/public/_nuxt/{DPdR3tu5.js → KKK6HVeG.js} +1 -1
- package/.output/public/_nuxt/{D0bh5qKf.js → Lwdv_RKd.js} +1 -1
- package/.output/public/_nuxt/{BkRZ4-cg.js → Nb2jBtYT.js} +1 -1
- package/.output/public/_nuxt/Q8Ps7oN5.js +1 -0
- package/.output/public/_nuxt/SXTDhzp6.js +1 -0
- package/.output/public/_nuxt/{GC9cY_vb.js → Sg2Lwc46.js} +1 -1
- package/.output/public/_nuxt/{GI6TTFJt.js → YuTZB7sD.js} +1 -1
- package/.output/public/_nuxt/{D2_L0Ze1.js → _CYZi8HN.js} +1 -1
- package/.output/public/_nuxt/_J_7XIn-.js +1 -0
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/a1e9100c-1a4f-4f7e-bb53-9dbe0d07effb.json +1 -0
- package/.output/public/_nuxt/{DZNG1AbU.js → cABRLVee.js} +1 -1
- package/.output/public/_nuxt/eko-0FUm.js +1 -0
- package/.output/public/_nuxt/entry.CGxIBGAf.css +1 -0
- package/.output/public/_nuxt/{BIjt_cIY.js → g20UHUCv.js} +1 -1
- package/.output/public/_nuxt/{HIlTvc-2.js → gBC9k4Qj.js} +1 -1
- package/.output/public/_nuxt/{IQoLFBX8.js → ghuJ76mD.js} +1 -1
- package/.output/public/_nuxt/{BGYWH_3A.js → iBGCpHdw.js} +2 -2
- package/.output/public/_nuxt/{uUGV1V-6.js → inmzPrjz.js} +1 -1
- package/.output/public/_nuxt/{CgHipF8Q.js → m5kGCDpI.js} +1 -1
- package/.output/public/_nuxt/{Bj0OFhNx.js → nIU2F7ia.js} +3 -3
- package/.output/public/_nuxt/{Dcv_tyzb.js → oIX-ZDN6.js} +1 -1
- package/.output/public/_nuxt/{B7NSgclV.js → pcUI-zuY.js} +1 -1
- package/.output/public/_nuxt/{DpF6VoC4.js → sf57orEk.js} +1 -1
- package/.output/public/_nuxt/{DS_mF4Ol.js → wCGVE8_e.js} +1 -1
- package/.output/public/_nuxt/{KAzeBbaL.js → xuzLdW-o.js} +1 -1
- package/.output/public/_nuxt/{ytKsJZlj.js → yNrp2XvX.js} +1 -1
- package/.output/public/_nuxt/{B3mdl0Ae.js → yuf23kh9.js} +1 -1
- package/.output/server/chunks/build/{_uuid_-DAZ5CM0C.mjs → _uuid_-0UgdUhfY.mjs} +6 -5
- package/.output/server/chunks/build/{_uuid_-DAZ5CM0C.mjs.map → _uuid_-0UgdUhfY.mjs.map} +1 -1
- 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/dashboard-YEscLBQN.mjs +1109 -0
- package/.output/server/chunks/build/dashboard-YEscLBQN.mjs.map +1 -0
- package/.output/server/chunks/build/{docs-CFAI1clt.mjs → docs-Dk2JnYq3.mjs} +6 -5
- package/.output/server/chunks/build/{docs-CFAI1clt.mjs.map → docs-Dk2JnYq3.mjs.map} +1 -1
- package/.output/server/chunks/build/server.mjs +3 -3
- package/.output/server/chunks/build/settings-DdkKCJ00.mjs +1 -1
- package/.output/server/chunks/build/styles.mjs +4 -4
- package/.output/server/chunks/build/{CodeEditorFallback-DfYly7f5.mjs → useCopyToClipboard-vi6FYyyZ.mjs} +29 -2
- package/.output/server/chunks/build/useCopyToClipboard-vi6FYyyZ.mjs.map +1 -0
- package/.output/server/chunks/build/useNotificationBus-BG5JNQf1.mjs +1 -1
- package/.output/server/chunks/nitro/nitro.mjs +819 -824
- package/.output/server/chunks/routes/api/dashboard/overview.get.mjs +149 -0
- package/.output/server/chunks/routes/api/dashboard/overview.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/documents/_id/public.get.mjs +1 -1
- package/.output/server/chunks/routes/api/documents/_id/restore.post.mjs +1 -1
- package/.output/server/chunks/routes/api/documents/by-path.post.mjs +1 -1
- package/.output/server/chunks/routes/api/documents/index.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/documents/index.put.mjs +1 -1
- package/.output/server/chunks/routes/api/fs/delete.post.mjs +1 -1
- package/.output/server/chunks/routes/api/fs/list.get.mjs +1 -1
- package/.output/server/chunks/routes/api/fs/mkdir.post.mjs +1 -1
- package/.output/server/chunks/routes/api/fs/move.post.mjs +1 -1
- package/.output/server/chunks/routes/api/fs/read.post.mjs +1 -1
- package/.output/server/chunks/routes/api/fs/rename.post.mjs +1 -1
- package/.output/server/chunks/routes/api/fs/write.post.mjs +1 -1
- package/.output/server/chunks/routes/api/health.get.mjs +1 -1
- package/.output/server/chunks/routes/api/home.get.mjs +1 -1
- package/.output/server/chunks/routes/api/hooks/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/hooks/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/hooks/stats.get.mjs +1 -1
- package/.output/server/chunks/routes/api/index.get3.mjs +1 -1
- package/.output/server/chunks/routes/api/index.get4.mjs +1 -1
- package/.output/server/chunks/routes/api/index.get5.mjs +1 -1
- package/.output/server/chunks/routes/api/index.get6.mjs +1 -1
- package/.output/server/chunks/routes/api/index.get7.mjs +1 -1
- package/.output/server/chunks/routes/api/index.get8.mjs +1 -1
- package/.output/server/chunks/routes/api/index.post2.mjs +1 -1
- package/.output/server/chunks/routes/api/index.post3.mjs +1 -1
- package/.output/server/chunks/routes/api/index.post4.mjs +1 -1
- package/.output/server/chunks/routes/api/index.put.mjs +1 -1
- package/.output/server/chunks/routes/api/memory/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/memory/context.get.mjs +1 -1
- package/.output/server/chunks/routes/api/memory/extract.post.mjs +1 -1
- package/.output/server/chunks/routes/api/memory/search.get.mjs +1 -1
- package/.output/server/chunks/routes/api/memory/store.post.mjs +1 -1
- package/.output/server/chunks/routes/api/projects/index.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/projects/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/projects/index.put.mjs +1 -1
- package/.output/server/chunks/routes/api/secrets/_key_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/secrets/_key_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/secrets/_key_.put.mjs +1 -1
- package/.output/server/chunks/routes/api/tasks/_id/restore.post.mjs +1 -1
- package/.output/server/chunks/routes/api/tasks/index.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/tasks/index.put.mjs +1 -1
- package/.output/server/chunks/routes/api/tasks/tags.get.mjs +1 -1
- package/.output/server/chunks/routes/api/usage/stats.get.mjs +1 -1
- package/.output/server/chunks/routes/renderer.mjs +1 -1
- package/.output/server/package.json +1 -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/app/components/dashboard/RecentChats.vue +93 -0
- package/app/components/dashboard/RecentDocs.vue +108 -0
- package/app/components/dashboard/StatCards.vue +82 -0
- package/app/components/dashboard/UpcomingTasks.vue +119 -0
- package/app/components/dashboard/UsageSummary.vue +94 -0
- package/app/components/editor/DocumentEditor.vue +5 -3
- 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/composables/useCopyToClipboard.ts +37 -0
- package/app/layouts/dashboard.vue +7 -0
- package/app/pages/chat.vue +11 -1
- package/app/pages/dashboard.vue +65 -64
- package/app/pages/skills/[name].vue +198 -0
- package/app/pages/skills/index.vue +157 -0
- package/app/pages/skills/library.vue +209 -0
- package/app/pages/view/[uuid].vue +4 -3
- package/dist/cli/index.js +23 -23
- package/nuxt.config.ts +9 -0
- package/package.json +1 -1
- package/server/api/dashboard/overview.get.ts +133 -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/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/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 +102 -0
- package/.output/public/_nuxt/BAWOIJ__.js +0 -1
- package/.output/public/_nuxt/B_paJhyq.js +0 -1
- package/.output/public/_nuxt/BdYiqlvd.js +0 -1
- package/.output/public/_nuxt/BpiqBbAF.js +0 -1
- package/.output/public/_nuxt/BqDfJ2hd.js +0 -1
- package/.output/public/_nuxt/BxgB0-mq.js +0 -1
- package/.output/public/_nuxt/C1hs5K_e.js +0 -1
- package/.output/public/_nuxt/C4Ncdd9K.js +0 -1
- package/.output/public/_nuxt/CAQ2bGHm.js +0 -1
- package/.output/public/_nuxt/CCpQAJpz.js +0 -1
- package/.output/public/_nuxt/CXXD-owe.js +0 -1
- package/.output/public/_nuxt/CcRijyCZ.js +0 -1
- package/.output/public/_nuxt/CoEfPCKj.js +0 -1
- package/.output/public/_nuxt/D08h2e32.js +0 -1
- package/.output/public/_nuxt/D_t_j6EB.js +0 -1
- package/.output/public/_nuxt/DaZy6Ki2.js +0 -1
- package/.output/public/_nuxt/DdrudNqf.js +0 -1
- package/.output/public/_nuxt/DdtmJxeb.js +0 -1
- package/.output/public/_nuxt/Dgv5fJ6Q.js +0 -1
- package/.output/public/_nuxt/DhIluGHO.js +0 -1
- package/.output/public/_nuxt/DuRk5Dc_.js +0 -1
- package/.output/public/_nuxt/VFwvl1mU.js +0 -1
- package/.output/public/_nuxt/builds/meta/555978fa-172f-4d0d-8238-88f8b610f712.json +0 -1
- package/.output/public/_nuxt/entry.DPbNaeQT.css +0 -1
- package/.output/public/_nuxt/hZV7Z8Ig.js +0 -1
- package/.output/public/_nuxt/lK0inMQ6.js +0 -1
- package/.output/server/chunks/build/CodeEditorFallback-DfYly7f5.mjs.map +0 -1
- package/.output/server/chunks/build/dashboard-DtbGchTa.mjs +0 -277
- package/.output/server/chunks/build/dashboard-DtbGchTa.mjs.map +0 -1
- /package/.output/public/_nuxt/{language-detection.Be_IvFWy.css → useCopyToClipboard.Be_IvFWy.css} +0 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SkillCatalogItem } from '~~/shared/types'
|
|
3
|
+
|
|
4
|
+
definePageMeta({
|
|
5
|
+
layout: 'dashboard',
|
|
6
|
+
middleware: 'auth'
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
const toast = useToast()
|
|
10
|
+
const skills = ref<SkillCatalogItem[]>([])
|
|
11
|
+
const loading = ref(true)
|
|
12
|
+
const installing = ref<string | null>(null)
|
|
13
|
+
const search = ref('')
|
|
14
|
+
const activeTag = ref<string | null>(null)
|
|
15
|
+
|
|
16
|
+
// Collect all unique tags across skills
|
|
17
|
+
const allTags = computed(() => {
|
|
18
|
+
const tagSet = new Set<string>()
|
|
19
|
+
for (const s of skills.value) {
|
|
20
|
+
for (const t of s.tags) tagSet.add(t)
|
|
21
|
+
}
|
|
22
|
+
return [...tagSet].sort()
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const filteredSkills = computed(() => {
|
|
26
|
+
let result = skills.value
|
|
27
|
+
|
|
28
|
+
if (activeTag.value) {
|
|
29
|
+
result = result.filter(s => s.tags.includes(activeTag.value!))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (search.value.trim()) {
|
|
33
|
+
const q = search.value.toLowerCase()
|
|
34
|
+
result = result.filter(s =>
|
|
35
|
+
s.name.toLowerCase().includes(q)
|
|
36
|
+
|| s.description.toLowerCase().includes(q)
|
|
37
|
+
|| s.author.toLowerCase().includes(q)
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return result
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
function toggleTag(tag: string) {
|
|
45
|
+
activeTag.value = activeTag.value === tag ? null : tag
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function loadLibrary() {
|
|
49
|
+
loading.value = true
|
|
50
|
+
try {
|
|
51
|
+
const res = await $fetch<{ data: SkillCatalogItem[] }>('/api/skills/library')
|
|
52
|
+
skills.value = res.data
|
|
53
|
+
} catch {
|
|
54
|
+
toast.add({ title: 'Failed to load skills library', color: 'error' })
|
|
55
|
+
} finally {
|
|
56
|
+
loading.value = false
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function handleInstall(name: string) {
|
|
61
|
+
installing.value = name
|
|
62
|
+
try {
|
|
63
|
+
await $fetch('/api/skills/library/install', {
|
|
64
|
+
method: 'POST',
|
|
65
|
+
body: { name }
|
|
66
|
+
})
|
|
67
|
+
toast.add({ title: `Installed ${name}`, color: 'success' })
|
|
68
|
+
await loadLibrary()
|
|
69
|
+
} catch (e: unknown) {
|
|
70
|
+
const message = e instanceof Error ? e.message : 'Failed to install skill'
|
|
71
|
+
toast.add({ title: message, color: 'error' })
|
|
72
|
+
} finally {
|
|
73
|
+
installing.value = null
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function handleUpdate(name: string) {
|
|
78
|
+
installing.value = name
|
|
79
|
+
try {
|
|
80
|
+
// Remove existing first
|
|
81
|
+
await $fetch(`/api/skills/${name}/files/delete`, {
|
|
82
|
+
method: 'POST',
|
|
83
|
+
body: { path: '.' }
|
|
84
|
+
}).catch(() => {})
|
|
85
|
+
|
|
86
|
+
await $fetch('/api/skills/library/install', {
|
|
87
|
+
method: 'POST',
|
|
88
|
+
body: { name }
|
|
89
|
+
})
|
|
90
|
+
toast.add({ title: `Updated ${name}`, color: 'success' })
|
|
91
|
+
await loadLibrary()
|
|
92
|
+
} catch {
|
|
93
|
+
toast.add({ title: `Failed to update ${name}`, color: 'error' })
|
|
94
|
+
} finally {
|
|
95
|
+
installing.value = null
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
onMounted(() => loadLibrary())
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<template>
|
|
103
|
+
<div class="flex flex-1 min-w-0">
|
|
104
|
+
<UDashboardPanel
|
|
105
|
+
id="skills-library"
|
|
106
|
+
grow
|
|
107
|
+
>
|
|
108
|
+
<template #header>
|
|
109
|
+
<UDashboardNavbar title="Skills Library">
|
|
110
|
+
<template #right>
|
|
111
|
+
<UInput
|
|
112
|
+
v-model="search"
|
|
113
|
+
icon="i-lucide-search"
|
|
114
|
+
placeholder="Search library..."
|
|
115
|
+
size="sm"
|
|
116
|
+
class="w-48"
|
|
117
|
+
/>
|
|
118
|
+
<NuxtLink to="/skills">
|
|
119
|
+
<UButton
|
|
120
|
+
icon="i-lucide-arrow-left"
|
|
121
|
+
variant="ghost"
|
|
122
|
+
color="neutral"
|
|
123
|
+
size="sm"
|
|
124
|
+
>
|
|
125
|
+
My Skills
|
|
126
|
+
</UButton>
|
|
127
|
+
</NuxtLink>
|
|
128
|
+
</template>
|
|
129
|
+
</UDashboardNavbar>
|
|
130
|
+
</template>
|
|
131
|
+
|
|
132
|
+
<template #body>
|
|
133
|
+
<div class="p-4">
|
|
134
|
+
<!-- Tag filter bar -->
|
|
135
|
+
<div
|
|
136
|
+
v-if="allTags.length > 0 && !loading"
|
|
137
|
+
class="flex flex-wrap gap-1.5 mb-4"
|
|
138
|
+
>
|
|
139
|
+
<UButton
|
|
140
|
+
v-for="tag in allTags"
|
|
141
|
+
:key="tag"
|
|
142
|
+
size="xs"
|
|
143
|
+
:variant="activeTag === tag ? 'solid' : 'outline'"
|
|
144
|
+
:color="tag === 'official' ? 'primary' : 'neutral'"
|
|
145
|
+
@click="toggleTag(tag)"
|
|
146
|
+
>
|
|
147
|
+
{{ tag }}
|
|
148
|
+
</UButton>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<!-- Loading -->
|
|
152
|
+
<div
|
|
153
|
+
v-if="loading"
|
|
154
|
+
class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3"
|
|
155
|
+
>
|
|
156
|
+
<div
|
|
157
|
+
v-for="i in 6"
|
|
158
|
+
:key="i"
|
|
159
|
+
class="p-4 rounded-lg border border-default bg-elevated/50"
|
|
160
|
+
>
|
|
161
|
+
<USkeleton class="h-4 w-24 mb-2" />
|
|
162
|
+
<USkeleton class="h-3 w-full mb-1" />
|
|
163
|
+
<USkeleton class="h-3 w-2/3" />
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<!-- Empty -->
|
|
168
|
+
<div
|
|
169
|
+
v-else-if="skills.length === 0"
|
|
170
|
+
class="flex flex-col items-center justify-center py-16 text-dimmed"
|
|
171
|
+
>
|
|
172
|
+
<UIcon
|
|
173
|
+
name="i-lucide-library"
|
|
174
|
+
class="size-12 mb-4"
|
|
175
|
+
/>
|
|
176
|
+
<p class="text-lg font-medium">
|
|
177
|
+
No community skills available
|
|
178
|
+
</p>
|
|
179
|
+
<p class="text-sm mt-1">
|
|
180
|
+
The skills registry is empty or hasn't synced yet.
|
|
181
|
+
</p>
|
|
182
|
+
</div>
|
|
183
|
+
|
|
184
|
+
<!-- No results -->
|
|
185
|
+
<div
|
|
186
|
+
v-else-if="filteredSkills.length === 0"
|
|
187
|
+
class="text-center py-12 text-muted text-sm"
|
|
188
|
+
>
|
|
189
|
+
No skills matching {{ activeTag ? `"${activeTag}"` : '' }} {{ search ? `"${search}"` : '' }}
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
<!-- Grid -->
|
|
193
|
+
<div
|
|
194
|
+
v-else
|
|
195
|
+
class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3"
|
|
196
|
+
>
|
|
197
|
+
<SkillsLibraryCard
|
|
198
|
+
v-for="skill in filteredSkills"
|
|
199
|
+
:key="skill.name"
|
|
200
|
+
:skill="skill"
|
|
201
|
+
@install="handleInstall"
|
|
202
|
+
@update="handleUpdate"
|
|
203
|
+
/>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
</template>
|
|
207
|
+
</UDashboardPanel>
|
|
208
|
+
</div>
|
|
209
|
+
</template>
|
|
@@ -60,18 +60,19 @@ watch(viewSource, v => viewSourceMode.value = v)
|
|
|
60
60
|
|
|
61
61
|
// Copy content to clipboard
|
|
62
62
|
const toast = useToast()
|
|
63
|
+
const { copy } = useCopyToClipboard()
|
|
63
64
|
async function copyContent() {
|
|
64
65
|
const content = data.value?.data?.content
|
|
65
66
|
if (!content) return
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
const ok = await copy(content)
|
|
69
|
+
if (ok) {
|
|
69
70
|
toast.add({
|
|
70
71
|
title: 'Copied to clipboard',
|
|
71
72
|
icon: 'i-lucide-check',
|
|
72
73
|
color: 'success'
|
|
73
74
|
})
|
|
74
|
-
}
|
|
75
|
+
} else {
|
|
75
76
|
toast.add({
|
|
76
77
|
title: 'Failed to copy',
|
|
77
78
|
icon: 'i-lucide-x',
|
package/dist/cli/index.js
CHANGED
|
@@ -154,11 +154,6 @@ var require_src = __commonJS({
|
|
|
154
154
|
}
|
|
155
155
|
});
|
|
156
156
|
|
|
157
|
-
// src/index.ts
|
|
158
|
-
import { readFileSync as readFileSync4 } from "fs";
|
|
159
|
-
import { join as join11, dirname as dirname2 } from "path";
|
|
160
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
161
|
-
|
|
162
157
|
// src/commands/init.ts
|
|
163
158
|
import { execSync as execSync5 } from "child_process";
|
|
164
159
|
import { join as join7 } from "path";
|
|
@@ -1357,6 +1352,14 @@ var __dirname = dirname(__filename);
|
|
|
1357
1352
|
function getPackageDir() {
|
|
1358
1353
|
return join(__dirname, "..", "..");
|
|
1359
1354
|
}
|
|
1355
|
+
function getPackageVersion() {
|
|
1356
|
+
try {
|
|
1357
|
+
const pkg = JSON.parse(readFileSync(join(getPackageDir(), "package.json"), "utf-8"));
|
|
1358
|
+
return pkg.version || "0.0.0";
|
|
1359
|
+
} catch {
|
|
1360
|
+
return "0.0.0";
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1360
1363
|
function getClaudeDir() {
|
|
1361
1364
|
return join(homedir(), ".claude");
|
|
1362
1365
|
}
|
|
@@ -1694,6 +1697,7 @@ You run as a persistent service managed by PM2. Your conversations are streamed
|
|
|
1694
1697
|
| Task Management | \`/task\` | Create, list, update, complete tasks |
|
|
1695
1698
|
| Project Management | \`/project\` | Organize tasks into projects |
|
|
1696
1699
|
| Memory | \`/memory\` | Search past decisions, store insights |
|
|
1700
|
+
| Secrets | \`/secret\` | Store, retrieve, list, delete encrypted API keys and credentials |
|
|
1697
1701
|
| Environment | \`/environment\` | Check system status, troubleshoot issues |
|
|
1698
1702
|
| Skill Creator | \`/skill-creator\` | Create new Claude Code skills |
|
|
1699
1703
|
|
|
@@ -1749,11 +1753,15 @@ Memory is your most important tool. You are stateless between sessions \u2014 wi
|
|
|
1749
1753
|
**Rule: When in doubt, store it.** A redundant memory is harmless. A forgotten one wastes ${p.userName}'s time.
|
|
1750
1754
|
|
|
1751
1755
|
### Secrets & Sensitive Data
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
-
|
|
1755
|
-
-
|
|
1756
|
+
|
|
1757
|
+
**CRITICAL \u2014 Zero tolerance for leaked secrets:**
|
|
1758
|
+
- NEVER store passwords, tokens, API keys, or credentials in memory, notes, conversation, or any file
|
|
1759
|
+
- NEVER write secrets to files \u2014 use \`/secret set KEY\` or the Cognova settings UI instead
|
|
1760
|
+
- NEVER embed API keys, tokens, or credentials in SKILL.md files or Python scripts when creating or modifying skills \u2014 always use \`get_secret()\` from \`_lib/api.py\`
|
|
1761
|
+
- If ${p.userName} shares a credential in chat, warn them and store it via \`/secret set KEY\` immediately
|
|
1762
|
+
- When you need a token for an integration, check with \`/secret list\` and \`/secret get KEY\` before asking ${p.userName}
|
|
1756
1763
|
- Treat any string that looks like a key, token, or password as sensitive \u2014 do not echo it back
|
|
1764
|
+
- When creating skills that need external API keys, declare them in \`metadata.requires-secrets\` frontmatter and use \`get_secret()\` in the script
|
|
1757
1765
|
|
|
1758
1766
|
### Troubleshooting
|
|
1759
1767
|
- Use \`/environment status\` or \`/environment health\` to diagnose issues
|
|
@@ -2205,7 +2213,7 @@ async function init() {
|
|
|
2205
2213
|
s.start("Installing Claude Code configuration");
|
|
2206
2214
|
await installClaudeConfig(config);
|
|
2207
2215
|
s.stop("Claude config installed to ~/.claude/");
|
|
2208
|
-
writeMetadata(resolvedInstallDir, vault.path,
|
|
2216
|
+
writeMetadata(resolvedInstallDir, vault.path, getPackageVersion());
|
|
2209
2217
|
R2.step(import_picocolors5.default.bold("Setup"));
|
|
2210
2218
|
s.start("Installing dependencies");
|
|
2211
2219
|
execSync5("pnpm install", { cwd: resolvedInstallDir, stdio: "pipe" });
|
|
@@ -2387,8 +2395,10 @@ async function update() {
|
|
|
2387
2395
|
process.exit(1);
|
|
2388
2396
|
}
|
|
2389
2397
|
}
|
|
2390
|
-
if (!updateFailed)
|
|
2398
|
+
if (!updateFailed) {
|
|
2399
|
+
writeMetadata(installDir, metadata.vaultPath, latestVersion);
|
|
2391
2400
|
cleanupBackup(backupDir);
|
|
2401
|
+
}
|
|
2392
2402
|
if (updateFailed) {
|
|
2393
2403
|
Le("Update failed. Previous version has been restored. Try again later.");
|
|
2394
2404
|
process.exit(1);
|
|
@@ -2612,18 +2622,8 @@ async function reset() {
|
|
|
2612
2622
|
}
|
|
2613
2623
|
|
|
2614
2624
|
// src/index.ts
|
|
2615
|
-
var __filename2 = fileURLToPath2(import.meta.url);
|
|
2616
|
-
var __dirname2 = dirname2(__filename2);
|
|
2617
|
-
function getVersion() {
|
|
2618
|
-
try {
|
|
2619
|
-
const pkg = JSON.parse(readFileSync4(join11(__dirname2, "..", "..", "package.json"), "utf-8"));
|
|
2620
|
-
return pkg.version || "0.0.0";
|
|
2621
|
-
} catch {
|
|
2622
|
-
return "0.0.0";
|
|
2623
|
-
}
|
|
2624
|
-
}
|
|
2625
2625
|
var HELP_TEXT = `
|
|
2626
|
-
cognova v${
|
|
2626
|
+
cognova v${getPackageVersion()} \u2014 Personal knowledge management with Claude Code
|
|
2627
2627
|
|
|
2628
2628
|
Usage: cognova <command> [options]
|
|
2629
2629
|
|
|
@@ -2720,7 +2720,7 @@ var args = process.argv.slice(2);
|
|
|
2720
2720
|
var command = args.find((a) => !a.startsWith("-"));
|
|
2721
2721
|
var flags = new Set(args.filter((a) => a.startsWith("-")));
|
|
2722
2722
|
if (flags.has("--version") || flags.has("-v")) {
|
|
2723
|
-
console.log(
|
|
2723
|
+
console.log(getPackageVersion());
|
|
2724
2724
|
process.exit(0);
|
|
2725
2725
|
}
|
|
2726
2726
|
if (flags.has("--help") || flags.has("-h")) {
|
package/nuxt.config.ts
CHANGED
|
@@ -10,6 +10,15 @@ export default defineNuxtConfig({
|
|
|
10
10
|
enabled: true
|
|
11
11
|
},
|
|
12
12
|
|
|
13
|
+
app: {
|
|
14
|
+
head: {
|
|
15
|
+
link: [
|
|
16
|
+
{ rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' },
|
|
17
|
+
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
|
|
13
22
|
css: ['~/assets/css/main.css'],
|
|
14
23
|
|
|
15
24
|
mdc: {
|
package/package.json
CHANGED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { eq, isNull, and, inArray, gte, desc, sql, ne } from 'drizzle-orm'
|
|
2
|
+
import { getDb, schema } from '~~/server/db'
|
|
3
|
+
import { requireDb } from '~~/server/utils/db-guard'
|
|
4
|
+
import type { DashboardOverview } from '~~/shared/types'
|
|
5
|
+
|
|
6
|
+
export default defineEventHandler(async (event) => {
|
|
7
|
+
requireDb(event)
|
|
8
|
+
|
|
9
|
+
const db = getDb()
|
|
10
|
+
const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
|
|
11
|
+
|
|
12
|
+
const [taskCounts, upcomingTasks, recentConversations, recentDocuments, usageAgg] = await Promise.all([
|
|
13
|
+
// Task counts: todo + in_progress (not deleted)
|
|
14
|
+
db.select({
|
|
15
|
+
status: schema.tasks.status,
|
|
16
|
+
count: sql<number>`count(*)::int`
|
|
17
|
+
})
|
|
18
|
+
.from(schema.tasks)
|
|
19
|
+
.where(and(
|
|
20
|
+
isNull(schema.tasks.deletedAt),
|
|
21
|
+
inArray(schema.tasks.status, ['todo', 'in_progress'])
|
|
22
|
+
))
|
|
23
|
+
.groupBy(schema.tasks.status),
|
|
24
|
+
|
|
25
|
+
// Top 5 upcoming tasks (not done, not deleted)
|
|
26
|
+
db.select({
|
|
27
|
+
id: schema.tasks.id,
|
|
28
|
+
title: schema.tasks.title,
|
|
29
|
+
status: schema.tasks.status,
|
|
30
|
+
priority: schema.tasks.priority,
|
|
31
|
+
dueDate: schema.tasks.dueDate,
|
|
32
|
+
projectName: schema.projects.name,
|
|
33
|
+
projectColor: schema.projects.color
|
|
34
|
+
})
|
|
35
|
+
.from(schema.tasks)
|
|
36
|
+
.leftJoin(schema.projects, eq(schema.tasks.projectId, schema.projects.id))
|
|
37
|
+
.where(and(
|
|
38
|
+
isNull(schema.tasks.deletedAt),
|
|
39
|
+
ne(schema.tasks.status, 'done')
|
|
40
|
+
))
|
|
41
|
+
.orderBy(
|
|
42
|
+
sql`${schema.tasks.dueDate} ASC NULLS LAST`,
|
|
43
|
+
desc(schema.tasks.priority)
|
|
44
|
+
)
|
|
45
|
+
.limit(5),
|
|
46
|
+
|
|
47
|
+
// Last 3 conversations
|
|
48
|
+
db.select({
|
|
49
|
+
id: schema.conversations.id,
|
|
50
|
+
sessionId: schema.conversations.sessionId,
|
|
51
|
+
title: schema.conversations.title,
|
|
52
|
+
messageCount: schema.conversations.messageCount,
|
|
53
|
+
startedAt: schema.conversations.startedAt
|
|
54
|
+
})
|
|
55
|
+
.from(schema.conversations)
|
|
56
|
+
.orderBy(desc(schema.conversations.startedAt))
|
|
57
|
+
.limit(3),
|
|
58
|
+
|
|
59
|
+
// Last 3 documents (not deleted)
|
|
60
|
+
db.select({
|
|
61
|
+
id: schema.documents.id,
|
|
62
|
+
title: schema.documents.title,
|
|
63
|
+
path: schema.documents.path,
|
|
64
|
+
modifiedAt: schema.documents.modifiedAt,
|
|
65
|
+
projectName: schema.projects.name,
|
|
66
|
+
projectColor: schema.projects.color
|
|
67
|
+
})
|
|
68
|
+
.from(schema.documents)
|
|
69
|
+
.leftJoin(schema.projects, eq(schema.documents.projectId, schema.projects.id))
|
|
70
|
+
.where(isNull(schema.documents.deletedAt))
|
|
71
|
+
.orderBy(desc(schema.documents.modifiedAt))
|
|
72
|
+
.limit(3),
|
|
73
|
+
|
|
74
|
+
// 7-day usage summary
|
|
75
|
+
db.select({
|
|
76
|
+
totalCost: sql<number>`coalesce(sum(${schema.tokenUsage.costUsd}), 0)::real`,
|
|
77
|
+
totalCalls: sql<number>`count(*)::int`,
|
|
78
|
+
totalInputTokens: sql<number>`coalesce(sum(${schema.tokenUsage.inputTokens}), 0)::int`,
|
|
79
|
+
totalOutputTokens: sql<number>`coalesce(sum(${schema.tokenUsage.outputTokens}), 0)::int`
|
|
80
|
+
})
|
|
81
|
+
.from(schema.tokenUsage)
|
|
82
|
+
.where(gte(schema.tokenUsage.createdAt, sevenDaysAgo))
|
|
83
|
+
])
|
|
84
|
+
|
|
85
|
+
// Build task counts
|
|
86
|
+
let todoCount = 0
|
|
87
|
+
let inProgressCount = 0
|
|
88
|
+
for (const row of taskCounts) {
|
|
89
|
+
if (row.status === 'todo') todoCount = row.count
|
|
90
|
+
else if (row.status === 'in_progress') inProgressCount = row.count
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const usageRow = usageAgg[0]
|
|
94
|
+
|
|
95
|
+
const overview: DashboardOverview = {
|
|
96
|
+
tasks: {
|
|
97
|
+
todoCount,
|
|
98
|
+
inProgressCount,
|
|
99
|
+
upcoming: upcomingTasks.map(t => ({
|
|
100
|
+
id: t.id,
|
|
101
|
+
title: t.title,
|
|
102
|
+
status: t.status as DashboardOverview['tasks']['upcoming'][0]['status'],
|
|
103
|
+
priority: t.priority,
|
|
104
|
+
dueDate: t.dueDate?.toISOString() ?? null,
|
|
105
|
+
projectName: t.projectName ?? null,
|
|
106
|
+
projectColor: t.projectColor ?? null
|
|
107
|
+
}))
|
|
108
|
+
},
|
|
109
|
+
conversations: recentConversations.map(c => ({
|
|
110
|
+
id: c.id,
|
|
111
|
+
sessionId: c.sessionId,
|
|
112
|
+
title: c.title ?? null,
|
|
113
|
+
messageCount: c.messageCount,
|
|
114
|
+
startedAt: c.startedAt.toISOString()
|
|
115
|
+
})),
|
|
116
|
+
documents: recentDocuments.map(d => ({
|
|
117
|
+
id: d.id,
|
|
118
|
+
title: d.title,
|
|
119
|
+
path: d.path,
|
|
120
|
+
modifiedAt: d.modifiedAt?.toISOString() ?? null,
|
|
121
|
+
projectName: d.projectName ?? null,
|
|
122
|
+
projectColor: d.projectColor ?? null
|
|
123
|
+
})),
|
|
124
|
+
usage: {
|
|
125
|
+
totalCost7d: usageRow?.totalCost ?? 0,
|
|
126
|
+
totalCalls7d: usageRow?.totalCalls ?? 0,
|
|
127
|
+
totalInputTokens7d: usageRow?.totalInputTokens ?? 0,
|
|
128
|
+
totalOutputTokens7d: usageRow?.totalOutputTokens ?? 0
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { data: overview }
|
|
133
|
+
})
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { mkdir, writeFile, 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, type: 'file' | 'directory' }>(event)
|
|
11
|
+
if (!body?.path)
|
|
12
|
+
throw createError({ statusCode: 400, message: '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
|
+
const targetPath = normalize(join(skillDir, body.path))
|
|
19
|
+
if (!targetPath.startsWith(skillDir))
|
|
20
|
+
throw createError({ statusCode: 403, message: 'Path traversal not allowed' })
|
|
21
|
+
|
|
22
|
+
const existing = await stat(targetPath).catch(() => null)
|
|
23
|
+
if (existing)
|
|
24
|
+
throw createError({ statusCode: 409, message: 'Already exists' })
|
|
25
|
+
|
|
26
|
+
if (body.type === 'directory') {
|
|
27
|
+
await mkdir(targetPath, { recursive: true })
|
|
28
|
+
} else {
|
|
29
|
+
await writeFile(targetPath, '', 'utf-8')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return { data: { path: body.path, type: body.type || 'file' } }
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
async function findSkillDir(name: string): Promise<string | null> {
|
|
36
|
+
const activeDir = join(getSkillsDir(), name)
|
|
37
|
+
const activeStat = await stat(activeDir).catch(() => null)
|
|
38
|
+
if (activeStat?.isDirectory()) return activeDir
|
|
39
|
+
|
|
40
|
+
const inactiveDir = join(getInactiveSkillsDir(), name)
|
|
41
|
+
const inactiveStat = await stat(inactiveDir).catch(() => null)
|
|
42
|
+
if (inactiveStat?.isDirectory()) return inactiveDir
|
|
43
|
+
|
|
44
|
+
return null
|
|
45
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { rm, 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: '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
|
+
const targetPath = normalize(join(skillDir, body.path))
|
|
19
|
+
if (!targetPath.startsWith(skillDir))
|
|
20
|
+
throw createError({ statusCode: 403, message: 'Path traversal not allowed' })
|
|
21
|
+
|
|
22
|
+
// Prevent deleting SKILL.md
|
|
23
|
+
if (body.path === 'SKILL.md')
|
|
24
|
+
throw createError({ statusCode: 403, message: 'Cannot delete SKILL.md' })
|
|
25
|
+
|
|
26
|
+
const targetStat = await stat(targetPath).catch(() => null)
|
|
27
|
+
if (!targetStat)
|
|
28
|
+
throw createError({ statusCode: 404, message: 'File not found' })
|
|
29
|
+
|
|
30
|
+
await rm(targetPath, { recursive: true })
|
|
31
|
+
|
|
32
|
+
return { data: { path: body.path, deleted: true } }
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
async function findSkillDir(name: string): Promise<string | null> {
|
|
36
|
+
const activeDir = join(getSkillsDir(), name)
|
|
37
|
+
const activeStat = await stat(activeDir).catch(() => null)
|
|
38
|
+
if (activeStat?.isDirectory()) return activeDir
|
|
39
|
+
|
|
40
|
+
const inactiveDir = join(getInactiveSkillsDir(), name)
|
|
41
|
+
const inactiveStat = await stat(inactiveDir).catch(() => null)
|
|
42
|
+
if (inactiveStat?.isDirectory()) return inactiveDir
|
|
43
|
+
|
|
44
|
+
return null
|
|
45
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { stat } from 'fs/promises'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import { getSkillsDir, getInactiveSkillsDir, buildSkillFileTree } 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 skillDir = await findSkillDir(name)
|
|
11
|
+
if (!skillDir)
|
|
12
|
+
throw createError({ statusCode: 404, message: `Skill '${name}' not found` })
|
|
13
|
+
|
|
14
|
+
const files = await buildSkillFileTree(skillDir)
|
|
15
|
+
return { data: files }
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
async function findSkillDir(name: string): Promise<string | null> {
|
|
19
|
+
const activeDir = join(getSkillsDir(), name)
|
|
20
|
+
const activeStat = await stat(activeDir).catch(() => null)
|
|
21
|
+
if (activeStat?.isDirectory()) return activeDir
|
|
22
|
+
|
|
23
|
+
const inactiveDir = join(getInactiveSkillsDir(), name)
|
|
24
|
+
const inactiveStat = await stat(inactiveDir).catch(() => null)
|
|
25
|
+
if (inactiveStat?.isDirectory()) return inactiveDir
|
|
26
|
+
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
@@ -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
|
+
}
|