cognova 0.2.2 → 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.
Files changed (508) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/-AsXrBBy.js +1 -0
  3. package/.output/public/_nuxt/2W1RPpXM.js +71 -0
  4. package/.output/public/_nuxt/{C4pxqdgg.js → 5UFq_rDn.js} +1 -1
  5. package/.output/public/_nuxt/5Zh-9l8_.js +1 -0
  6. package/.output/public/_nuxt/{DK9jxJ0g.js → 90UksHlj.js} +1 -1
  7. package/.output/public/_nuxt/{9IQmsEjr.js → 9QKmiSP_.js} +1 -1
  8. package/.output/public/_nuxt/{BOj6t-oo.js → ARbTpeGy.js} +1 -1
  9. package/.output/public/_nuxt/{DyRelyfs.js → ApfLnl06.js} +1 -1
  10. package/.output/public/_nuxt/{DznawRFW.js → B-2BuR5g.js} +1 -1
  11. package/.output/public/_nuxt/B4u7Mczo.js +1 -0
  12. package/.output/public/_nuxt/{DAQhmSv4.js → B5dI_yLq.js} +1 -1
  13. package/.output/public/_nuxt/{Bm9LyG4F.js → B6fnZcA6.js} +1 -1
  14. package/.output/public/_nuxt/{9QnH0xQM.js → B7uMSBlN.js} +1 -1
  15. package/.output/public/_nuxt/BBiRyPlN.js +1 -0
  16. package/.output/public/_nuxt/{iBGCpHdw.js → BF7413u4.js} +2 -2
  17. package/.output/public/_nuxt/{4MiwzAAt.js → BGtUoCgi.js} +2 -2
  18. package/.output/public/_nuxt/{CxuZBC8n.js → BHe4VLtR.js} +1 -1
  19. package/.output/public/_nuxt/{D3RiUGdz.js → BIMBp1Tj.js} +1 -1
  20. package/.output/public/_nuxt/{g20UHUCv.js → BIvPdoE3.js} +1 -1
  21. package/.output/public/_nuxt/BKaRtCjP.js +1 -0
  22. package/.output/public/_nuxt/BLmc9T7l.js +1 -0
  23. package/.output/public/_nuxt/BMdnU6BF.js +1 -0
  24. package/.output/public/_nuxt/{CKkC3Ptm.js → BOgdaA_8.js} +1 -1
  25. package/.output/public/_nuxt/{BffWCM73.js → BQZfTrUg.js} +1 -1
  26. package/.output/public/_nuxt/BQnublTW.js +1 -0
  27. package/.output/public/_nuxt/BSsvedap.js +1 -0
  28. package/.output/public/_nuxt/{Ci7UEZQh.js → BVypxKRT.js} +1 -1
  29. package/.output/public/_nuxt/{CYP_MLH8.js → BWqJFnZy.js} +1 -1
  30. package/.output/public/_nuxt/BXxYdXMr.js +1 -0
  31. package/.output/public/_nuxt/{D_3Rq1BS.js → B_17gAr_.js} +1 -1
  32. package/.output/public/_nuxt/B_qzFVK_.js +1 -0
  33. package/.output/public/_nuxt/{BqKFIuRj.js → BbRPwpIX.js} +1 -1
  34. package/.output/public/_nuxt/BhrzKbv9.js +1 -0
  35. package/.output/public/_nuxt/{Cqy_L_ip.js → Bl6LNGlA.js} +1 -1
  36. package/.output/public/_nuxt/{Fukkqjkf.js → BlPToGni.js} +1 -1
  37. package/.output/public/_nuxt/{DHKLCQRG.js → BlwHr46F.js} +1 -1
  38. package/.output/public/_nuxt/{C6aqGHu1.js → BnmwiZbF.js} +1 -1
  39. package/.output/public/_nuxt/BqtxLJaf.js +1 -0
  40. package/.output/public/_nuxt/{eko-0FUm.js → BrEXdify.js} +1 -1
  41. package/.output/public/_nuxt/{D3e44mCL.js → BtNnS4m3.js} +1 -1
  42. package/.output/public/_nuxt/{BCtfQCzC.js → BtVIBBUN.js} +1 -1
  43. package/.output/public/_nuxt/Bw5h4Jaf.js +1 -0
  44. package/.output/public/_nuxt/{FvlxxmNk.js → Bwcpy7gC.js} +2 -2
  45. package/.output/public/_nuxt/{Db2v8O7O.js → C0TUK31m.js} +1 -1
  46. package/.output/public/_nuxt/C1T4GK6c.js +1 -0
  47. package/.output/public/_nuxt/C2ANDZen.js +1 -0
  48. package/.output/public/_nuxt/{CqU2XbzO.js → C2RZSTuy.js} +1 -1
  49. package/.output/public/_nuxt/C3dYlP5x.js +1 -0
  50. package/.output/public/_nuxt/{m5kGCDpI.js → C3sh_tLi.js} +3 -3
  51. package/.output/public/_nuxt/{BjjCvHLT.js → C4zyxZG7.js} +1 -1
  52. package/.output/public/_nuxt/{C3FxIITy.js → C5I-XBZT.js} +1 -1
  53. package/.output/public/_nuxt/{yuf23kh9.js → CC4Goztu.js} +1 -1
  54. package/.output/public/_nuxt/CC77iplr.js +1 -0
  55. package/.output/public/_nuxt/{xuzLdW-o.js → CFyD2NHP.js} +1 -1
  56. package/.output/public/_nuxt/{CsJ9KhQ4.js → CGQDTeaO.js} +1 -1
  57. package/.output/public/_nuxt/{DnjGH3SQ.js → CHpwuMSk.js} +1 -1
  58. package/.output/public/_nuxt/CLzcRUcs.js +1 -0
  59. package/.output/public/_nuxt/CM2phu_3.js +1 -0
  60. package/.output/public/_nuxt/{Cr8ixbr1.js → CQpYRq61.js} +1 -1
  61. package/.output/public/_nuxt/{C0JKNMDO.js → CUN4bYcg.js} +1 -1
  62. package/.output/public/_nuxt/{CmzH6R-N.js → CXoITXft.js} +19 -19
  63. package/.output/public/_nuxt/CYjcQPl-.js +1 -0
  64. package/.output/public/_nuxt/{DGX0tzL8.js → CZ32KfaS.js} +1 -1
  65. package/.output/public/_nuxt/CclZMdca.js +1 -0
  66. package/.output/public/_nuxt/{C69W7k2j.js → CdpT_Vb6.js} +1 -1
  67. package/.output/public/_nuxt/CflRLvFC.js +1 -0
  68. package/.output/public/_nuxt/{gBC9k4Qj.js → CkqNv7sq.js} +2 -2
  69. package/.output/public/_nuxt/ClXDAYjE.js +1 -0
  70. package/.output/public/_nuxt/CrZGoMo_.js +1 -0
  71. package/.output/public/_nuxt/{BZXMQuYP.js → CvJtd2Af.js} +1 -1
  72. package/.output/public/_nuxt/{DKZxeXDQ.js → Cwtd8e-P.js} +1 -1
  73. package/.output/public/_nuxt/{nIU2F7ia.js → Cx44SSNp.js} +3 -3
  74. package/.output/public/_nuxt/{BzOqrmGa.js → CxEVzuCn.js} +3 -3
  75. package/.output/public/_nuxt/{Dy_Cq5LQ.js → CzIMQevQ.js} +1 -1
  76. package/.output/public/_nuxt/{D6t3dcTl.js → D0P9llU7.js} +1 -1
  77. package/.output/public/_nuxt/{JJ3634gV.js → D1DYuOOm.js} +1 -1
  78. package/.output/public/_nuxt/{BAIz-dEB.js → D1dDc8Vw.js} +1 -1
  79. package/.output/public/_nuxt/{DSRrg8JT.js → D1r0uqf3.js} +1 -1
  80. package/.output/public/_nuxt/{CNnJrDvu.js → D3a8R1T6.js} +1 -1
  81. package/.output/public/_nuxt/{B1X4Bzcy.js → D5EZbuub.js} +1 -1
  82. package/.output/public/_nuxt/D9V13KTK.js +1 -0
  83. package/.output/public/_nuxt/DAE2hbP7.js +1 -0
  84. package/.output/public/_nuxt/{Cvp7FI3T.js → DAIbdyS6.js} +1 -1
  85. package/.output/public/_nuxt/{EuOqK1A6.js → DAvlXjt0.js} +1 -1
  86. package/.output/public/_nuxt/DBKzwexZ.js +1 -0
  87. package/.output/public/_nuxt/{wCGVE8_e.js → DEATxnaF.js} +1 -1
  88. package/.output/public/_nuxt/{cABRLVee.js → DFg8PvHV.js} +1 -1
  89. package/.output/public/_nuxt/DM4MyqI-.js +1 -0
  90. package/.output/public/_nuxt/{Cdt3I3Go.js → DNE7kw9s.js} +1 -1
  91. package/.output/public/_nuxt/DO0oG4fG.js +1 -0
  92. package/.output/public/_nuxt/{B6S_ob86.js → DPFugPaB.js} +1 -1
  93. package/.output/public/_nuxt/{DJjDvbZE.js → DQlXU6_H.js} +1 -1
  94. package/.output/public/_nuxt/DQvuQpwh.js +1 -0
  95. package/.output/public/_nuxt/{sf57orEk.js → DRlG_bnX.js} +1 -1
  96. package/.output/public/_nuxt/{C6RC3lA1.js → DSQj-oMk.js} +1 -1
  97. package/.output/public/_nuxt/{CeIVm4A3.js → DU6ewLkE.js} +1 -1
  98. package/.output/public/_nuxt/{Cp2MA0cm.js → DWhzQg7B.js} +1 -1
  99. package/.output/public/_nuxt/{DJMS2og1.js → D_vK6VPK.js} +1 -1
  100. package/.output/public/_nuxt/{CihWZmJe.js → DaBp0Gba.js} +2 -2
  101. package/.output/public/_nuxt/DaH2FbAy.js +1 -0
  102. package/.output/public/_nuxt/{CtYFj7k1.js → DaJo0CeV.js} +1 -1
  103. package/.output/public/_nuxt/DauLdT7p.js +1 -0
  104. package/.output/public/_nuxt/{DG-T44jj.js → DdPA4eTX.js} +1 -1
  105. package/.output/public/_nuxt/{YuTZB7sD.js → DeAGWdWK.js} +1 -1
  106. package/.output/public/_nuxt/{CitkKxhw.js → DfF1qofg.js} +1 -1
  107. package/.output/public/_nuxt/{Daz4MeL6.js → DiGBA-aA.js} +1 -1
  108. package/.output/public/_nuxt/DiJxF69i.js +1 -0
  109. package/.output/public/_nuxt/{DIoI0uJm.js → DkBIU-1F.js} +1 -1
  110. package/.output/public/_nuxt/DmAM6bZ0.js +1 -0
  111. package/.output/public/_nuxt/DmeAKr3J.js +1 -0
  112. package/.output/public/_nuxt/DmmTnMzZ.js +1 -0
  113. package/.output/public/_nuxt/{Lwdv_RKd.js → DqsUSndS.js} +1 -1
  114. package/.output/public/_nuxt/Dvw-hR3Y.js +1 -0
  115. package/.output/public/_nuxt/{CVgTJeSq.js → Dz6sfh81.js} +1 -1
  116. package/.output/public/_nuxt/{BYjadNrw.js → FNhYm5FX.js} +1 -1
  117. package/.output/public/_nuxt/{Nb2jBtYT.js → HOeKUnra.js} +1 -1
  118. package/.output/public/_nuxt/{CtchsY6e.js → IR1jkN7B.js} +1 -1
  119. package/.output/public/_nuxt/{DCzfkCGa.js → MpTk6K7N.js} +1 -1
  120. package/.output/public/_nuxt/NZ7Wz6LP.js +1 -0
  121. package/.output/public/_nuxt/{DfQu3kEw.js → PqWbiAD2.js} +1 -1
  122. package/.output/public/_nuxt/{Jez9DHn7.js → Tu4FhMRc.js} +1 -1
  123. package/.output/public/_nuxt/{B3y_Qqox.js → UKPXYG4z.js} +1 -1
  124. package/.output/public/_nuxt/{BlAZO7nq.js → UO2Y9Nve.js} +1 -1
  125. package/.output/public/_nuxt/{KKK6HVeG.js → XHiJSquP.js} +1 -1
  126. package/.output/public/_nuxt/YGWAImQo.js +1 -0
  127. package/.output/public/_nuxt/{ghuJ76mD.js → ZR87XvwB.js} +1 -1
  128. package/.output/public/_nuxt/{yNrp2XvX.js → _E89BQAO.js} +1 -1
  129. package/.output/public/_nuxt/{C_BdYLzz.js → aiXk7zRt.js} +1 -1
  130. package/.output/public/_nuxt/builds/latest.json +1 -1
  131. package/.output/public/_nuxt/builds/meta/91727fcc-bf7f-407f-9b1e-092017fcfee0.json +1 -0
  132. package/.output/public/_nuxt/cL7whuPe.js +1 -0
  133. package/.output/public/_nuxt/{BasgsT_S.js → ct6_k5IW.js} +1 -1
  134. package/.output/public/_nuxt/entry._7ZkP07A.css +1 -0
  135. package/.output/public/_nuxt/{DTDgHTuh.js → fEUQvmn8.js} +2 -2
  136. package/.output/public/_nuxt/{FNC8XZTk.js → gGlaVUMD.js} +1 -1
  137. package/.output/public/_nuxt/gjmGkVlL.js +1 -0
  138. package/.output/public/_nuxt/{IRSbVPIu.js → m5001Uvl.js} +1 -1
  139. package/.output/public/_nuxt/{_CYZi8HN.js → mQkFCz_M.js} +1 -1
  140. package/.output/public/_nuxt/{BxXOsXrM.js → p9l1LjVc.js} +10 -10
  141. package/.output/public/_nuxt/{BsEZoHd1.js → qR_K5W8V.js} +1 -1
  142. package/.output/public/_nuxt/{BrNqhp1a.js → t_9QQ4MF.js} +7 -7
  143. package/.output/public/_nuxt/{pcUI-zuY.js → uc4c4mfb.js} +1 -1
  144. package/.output/public/_nuxt/{usage.vakN1lvi.css → usage.BDeyCZwW.css} +1 -1
  145. package/.output/public/_nuxt/wPSLEMBw.js +1 -0
  146. package/.output/public/_nuxt/xKRwul0f.js +1 -0
  147. package/.output/public/_nuxt/{BWhMnjID.js → xgpiGSxb.js} +1 -1
  148. package/.output/public/_nuxt/xxnk7j0F.js +1 -0
  149. package/.output/public/favicon.svg +1 -0
  150. package/.output/server/chunks/build/A-BWukSPjS.mjs +1 -0
  151. package/.output/server/chunks/build/Accordion-BaJYea6e.mjs +1 -0
  152. package/.output/server/chunks/build/AccordionItem-DdG2zgcN.mjs +1 -0
  153. package/.output/server/chunks/build/Badge-BrU9UkCv.mjs +1 -0
  154. package/.output/server/chunks/build/Blockquote-DND8wTkU.mjs +1 -0
  155. package/.output/server/chunks/build/Callout-1halpaEg.mjs +1 -0
  156. package/.output/server/chunks/build/Card-BHCSDKDt.mjs +1 -0
  157. package/.output/server/chunks/build/CardGroup-BOuJcNGp.mjs +1 -0
  158. package/.output/server/chunks/build/Caution-BP3y-TcC.mjs +1 -0
  159. package/.output/server/chunks/build/Code-B1xkAS5a.mjs +1 -0
  160. package/.output/server/chunks/build/CodeCollapse-BIhaNa22.mjs +1 -0
  161. package/.output/server/chunks/build/CodeGroup-BviYyCuo.mjs +1 -0
  162. package/.output/server/chunks/build/CodeIcon-CWD5HcV7.mjs +2 -1
  163. package/.output/server/chunks/build/CodePreview-D8PsCQ6m.mjs +1 -0
  164. package/.output/server/chunks/build/CodeTree-BUTLupmL.mjs +1 -0
  165. package/.output/server/chunks/build/Collapsible-BIvXNaSq.mjs +1 -0
  166. package/.output/server/chunks/build/DropdownMenu-BBrV9nXz.mjs +1 -1
  167. package/.output/server/chunks/build/EditorToolbar-DIfb5arC.mjs +1 -1
  168. package/.output/server/chunks/build/Em-DsIz_BnD.mjs +1 -0
  169. package/.output/server/chunks/build/Field-cwwmSQDT.mjs +1 -0
  170. package/.output/server/chunks/build/FieldGroup-CAIpQv8s.mjs +1 -0
  171. package/.output/server/chunks/build/H1-BbFNsPyP.mjs +1 -0
  172. package/.output/server/chunks/build/H2-vHTl_pWr.mjs +1 -0
  173. package/.output/server/chunks/build/H3-7eTcfO3s.mjs +1 -0
  174. package/.output/server/chunks/build/H4-C89p_PKO.mjs +1 -0
  175. package/.output/server/chunks/build/Hr-Bm8RlL3O.mjs +1 -0
  176. package/.output/server/chunks/build/Icon-Dp9iy0BI.mjs +1 -0
  177. package/.output/server/chunks/build/Img-CWLmvN1t.mjs +2 -1
  178. package/.output/server/chunks/build/Kbd-CQG6I_Ch.mjs +1 -0
  179. package/.output/server/chunks/build/Li-Bw1QUaGv.mjs +1 -0
  180. package/.output/server/chunks/build/MDC-Dx0YPDhe.mjs +1 -1
  181. package/.output/server/chunks/build/Note-CHkjm9jm.mjs +1 -0
  182. package/.output/server/chunks/build/Ol-D-fPnfFM.mjs +1 -0
  183. package/.output/server/chunks/build/P-B5YI1V9y.mjs +1 -0
  184. package/.output/server/chunks/build/Pre-ChiJcf3C.mjs +1 -0
  185. package/.output/server/chunks/build/ProseH5-DahJyv8h.mjs +1 -0
  186. package/.output/server/chunks/build/ProseH6-C4Is5h6c.mjs +1 -0
  187. package/.output/server/chunks/build/Select-BB1oLrCD.mjs +1 -1
  188. package/.output/server/chunks/build/SelectMenu-DPssg6zD.mjs +1 -1
  189. package/.output/server/chunks/build/Steps-BZpvXfzb.mjs +1 -0
  190. package/.output/server/chunks/build/Strong-DXJqOWL3.mjs +1 -0
  191. package/.output/server/chunks/build/Table-BSrLZ7dt.mjs +1 -0
  192. package/.output/server/chunks/build/Table-DCwTlhCj.mjs +1 -1
  193. package/.output/server/chunks/build/Tabs-Dk3nvOFF.mjs +1 -0
  194. package/.output/server/chunks/build/TabsItem-CDhyuBtJ.mjs +1 -0
  195. package/.output/server/chunks/build/Tbody-CjMT5oH-.mjs +1 -0
  196. package/.output/server/chunks/build/Td-ZBVaEjFN.mjs +1 -0
  197. package/.output/server/chunks/build/Th-D317icbd.mjs +1 -0
  198. package/.output/server/chunks/build/Thead-Ca_ZESTK.mjs +1 -0
  199. package/.output/server/chunks/build/Tip-CP3oTARR.mjs +1 -0
  200. package/.output/server/chunks/build/Tooltip-TRyl6dje.mjs +1 -1
  201. package/.output/server/chunks/build/Tr-6jI8j9gD.mjs +1 -0
  202. package/.output/server/chunks/build/{docs-Dk2JnYq3.mjs → Tree-DUhXKd8y.mjs} +46 -2235
  203. package/.output/server/chunks/build/Tree-DUhXKd8y.mjs.map +1 -0
  204. package/.output/server/chunks/build/Ul-BUGj_CPb.mjs +1 -0
  205. package/.output/server/chunks/build/Warning-BJ8G6cxC.mjs +1 -0
  206. package/.output/server/chunks/build/_id_-DN00UDdO.mjs +1 -0
  207. package/.output/server/chunks/build/_id_-DN00UDdO.mjs.map +1 -1
  208. package/.output/server/chunks/build/_name_-BnS_KEfX.mjs +1592 -0
  209. package/.output/server/chunks/build/_name_-BnS_KEfX.mjs.map +1 -0
  210. package/.output/server/chunks/build/{_uuid_-0UgdUhfY.mjs → _uuid_-DfJaumTE.mjs} +5 -4
  211. package/.output/server/chunks/build/{_uuid_-0UgdUhfY.mjs.map → _uuid_-DfJaumTE.mjs.map} +1 -1
  212. package/.output/server/chunks/build/auth-BGPNH2QJ.mjs +20 -0
  213. package/.output/server/chunks/build/auth-BGPNH2QJ.mjs.map +1 -0
  214. package/.output/server/chunks/build/auth-CvD7MqKW.mjs +1 -0
  215. package/.output/server/chunks/build/auth-CvD7MqKW.mjs.map +1 -1
  216. package/.output/server/chunks/build/chat-CZMiB68R.mjs +1 -0
  217. package/.output/server/chunks/build/chat-CZMiB68R.mjs.map +1 -1
  218. package/.output/server/chunks/build/client.precomputed.mjs +1 -1
  219. package/.output/server/chunks/build/cookie-C_iulBi6.mjs +1 -1
  220. package/.output/server/chunks/build/{dashboard-YEscLBQN.mjs → dashboard-CLk1NlbR.mjs} +15 -4
  221. package/.output/server/chunks/build/dashboard-CLk1NlbR.mjs.map +1 -0
  222. package/.output/server/chunks/build/{dashboard-CpMVYnDV.mjs → dashboard-CiVTAZuF.mjs} +12 -4
  223. package/.output/server/chunks/build/{dashboard-CpMVYnDV.mjs.map → dashboard-CiVTAZuF.mjs.map} +1 -1
  224. package/.output/server/chunks/build/docs-ChGwOPg5.mjs +2204 -0
  225. package/.output/server/chunks/build/docs-ChGwOPg5.mjs.map +1 -0
  226. package/.output/server/chunks/build/error-404-BzbcNcdU.mjs +1 -0
  227. package/.output/server/chunks/build/error-500-uCDjGRW8.mjs +1 -0
  228. package/.output/server/chunks/build/fetch-BB7Qzkwe.mjs +1 -1
  229. package/.output/server/chunks/build/{hooks-DP8WoUPS.mjs → hooks-D328DcO6.mjs} +3 -2
  230. package/.output/server/chunks/build/hooks-D328DcO6.mjs.map +1 -0
  231. package/.output/server/chunks/build/{index-DVx-QlhP.mjs → index-Byt-3Yq6.mjs} +3 -2
  232. package/.output/server/chunks/build/{index-DVx-QlhP.mjs.map → index-Byt-3Yq6.mjs.map} +1 -1
  233. package/.output/server/chunks/build/{index-Ba_bPJgk.mjs → index-C9PuieXh.mjs} +3 -2
  234. package/.output/server/chunks/build/index-C9PuieXh.mjs.map +1 -0
  235. package/.output/server/chunks/build/index-C_LcBBgO.mjs +1508 -0
  236. package/.output/server/chunks/build/index-C_LcBBgO.mjs.map +1 -0
  237. package/.output/server/chunks/build/index-CxDxc9fm.mjs +1 -1
  238. package/.output/server/chunks/build/index-DzdvIi8V.mjs +1 -0
  239. package/.output/server/chunks/build/library-CbWcF5wT.mjs +601 -0
  240. package/.output/server/chunks/build/library-CbWcF5wT.mjs.map +1 -0
  241. package/.output/server/chunks/build/{login-BAysbpyX.mjs → login-DnnElTl2.mjs} +15 -7
  242. package/.output/server/chunks/build/{login-BAysbpyX.mjs.map → login-DnnElTl2.mjs.map} +1 -1
  243. package/.output/server/chunks/build/memories-BqA719O1.mjs +1 -0
  244. package/.output/server/chunks/build/memories-BqA719O1.mjs.map +1 -1
  245. package/.output/server/chunks/build/server.mjs +62 -34
  246. package/.output/server/chunks/build/server.mjs.map +1 -1
  247. package/.output/server/chunks/build/settings-DdkKCJ00.mjs +1 -0
  248. package/.output/server/chunks/build/settings-DdkKCJ00.mjs.map +1 -1
  249. package/.output/server/chunks/build/styles.mjs +2 -2
  250. package/.output/server/chunks/build/{tasks-DiOi1HG_.mjs → tasks-DnAFqbtt.mjs} +3 -2
  251. package/.output/server/chunks/build/tasks-DnAFqbtt.mjs.map +1 -0
  252. package/.output/server/chunks/build/{usage-H_mcd_fz.mjs → usage-CSrBh4Or.mjs} +159 -44
  253. package/.output/server/chunks/build/{usage-H_mcd_fz.mjs.map → usage-CSrBh4Or.mjs.map} +1 -1
  254. package/.output/server/chunks/build/{usePreferences-CzC8fRzd.mjs → usePreferences-DH1QjxOj.mjs} +7 -1
  255. package/.output/server/chunks/build/usePreferences-DH1QjxOj.mjs.map +1 -0
  256. package/.output/server/chunks/build/{view-Dc8mvzCB.mjs → view-n2sYa4Zh.mjs} +4 -3
  257. package/.output/server/chunks/build/{view-Dc8mvzCB.mjs.map → view-n2sYa4Zh.mjs.map} +1 -1
  258. package/.output/server/chunks/build/virtual_nuxt__Users_tony_Documents_GitHub_second-brain_node_modules_.cache_nuxt_.nuxt_mdc-imports-PtwWlZ2H.mjs +1 -0
  259. package/.output/server/chunks/nitro/nitro.mjs +1247 -824
  260. package/.output/server/chunks/nitro/nitro.mjs.map +1 -1
  261. package/.output/server/chunks/routes/_ws/chat.mjs +2 -1
  262. package/.output/server/chunks/routes/_ws/chat.mjs.map +1 -1
  263. package/.output/server/chunks/routes/api/agents/_id/cancel.post.mjs +1 -0
  264. package/.output/server/chunks/routes/api/agents/_id/cancel.post.mjs.map +1 -1
  265. package/.output/server/chunks/routes/api/agents/_id/run.post.mjs +1 -0
  266. package/.output/server/chunks/routes/api/agents/_id/run.post.mjs.map +1 -1
  267. package/.output/server/chunks/routes/api/agents/_id/runs.get.mjs +1 -0
  268. package/.output/server/chunks/routes/api/agents/_id/runs.get.mjs.map +1 -1
  269. package/.output/server/chunks/routes/api/agents/_id/stats.get.mjs +1 -0
  270. package/.output/server/chunks/routes/api/agents/_id/stats.get.mjs.map +1 -1
  271. package/.output/server/chunks/routes/api/agents/_id_.delete.mjs +1 -0
  272. package/.output/server/chunks/routes/api/agents/_id_.delete.mjs.map +1 -1
  273. package/.output/server/chunks/routes/api/agents/_id_.get.mjs +1 -0
  274. package/.output/server/chunks/routes/api/agents/_id_.get.mjs.map +1 -1
  275. package/.output/server/chunks/routes/api/agents/_id_.patch.mjs +1 -0
  276. package/.output/server/chunks/routes/api/agents/_id_.patch.mjs.map +1 -1
  277. package/.output/server/chunks/routes/api/agents/stats.get.mjs +1 -0
  278. package/.output/server/chunks/routes/api/agents/stats.get.mjs.map +1 -1
  279. package/.output/server/chunks/routes/api/auth/_...all_.mjs +1 -0
  280. package/.output/server/chunks/routes/api/auth/_...all_.mjs.map +1 -1
  281. package/.output/server/chunks/routes/api/conversations/_id_.delete.mjs +1 -0
  282. package/.output/server/chunks/routes/api/conversations/_id_.delete.mjs.map +1 -1
  283. package/.output/server/chunks/routes/api/conversations/_id_.get.mjs +1 -0
  284. package/.output/server/chunks/routes/api/conversations/_id_.get.mjs.map +1 -1
  285. package/.output/server/chunks/routes/api/dashboard/overview.get.mjs +1 -0
  286. package/.output/server/chunks/routes/api/dashboard/overview.get.mjs.map +1 -1
  287. package/.output/server/chunks/routes/api/documents/_id/public.get.mjs +1 -0
  288. package/.output/server/chunks/routes/api/documents/_id/public.get.mjs.map +1 -1
  289. package/.output/server/chunks/routes/api/documents/_id/restore.post.mjs +1 -0
  290. package/.output/server/chunks/routes/api/documents/_id/restore.post.mjs.map +1 -1
  291. package/.output/server/chunks/routes/api/documents/by-path.post.mjs +1 -0
  292. package/.output/server/chunks/routes/api/documents/by-path.post.mjs.map +1 -1
  293. package/.output/server/chunks/routes/api/documents/index.delete.mjs +1 -0
  294. package/.output/server/chunks/routes/api/documents/index.delete.mjs.map +1 -1
  295. package/.output/server/chunks/routes/api/documents/index.put.mjs +1 -0
  296. package/.output/server/chunks/routes/api/documents/index.put.mjs.map +1 -1
  297. package/.output/server/chunks/routes/api/fs/delete.post.mjs +1 -0
  298. package/.output/server/chunks/routes/api/fs/delete.post.mjs.map +1 -1
  299. package/.output/server/chunks/routes/api/fs/list.get.mjs +1 -0
  300. package/.output/server/chunks/routes/api/fs/list.get.mjs.map +1 -1
  301. package/.output/server/chunks/routes/api/fs/mkdir.post.mjs +1 -0
  302. package/.output/server/chunks/routes/api/fs/mkdir.post.mjs.map +1 -1
  303. package/.output/server/chunks/routes/api/fs/move.post.mjs +1 -0
  304. package/.output/server/chunks/routes/api/fs/move.post.mjs.map +1 -1
  305. package/.output/server/chunks/routes/api/fs/read.post.mjs +1 -0
  306. package/.output/server/chunks/routes/api/fs/read.post.mjs.map +1 -1
  307. package/.output/server/chunks/routes/api/fs/rename.post.mjs +1 -0
  308. package/.output/server/chunks/routes/api/fs/rename.post.mjs.map +1 -1
  309. package/.output/server/chunks/routes/api/fs/write.post.mjs +1 -0
  310. package/.output/server/chunks/routes/api/fs/write.post.mjs.map +1 -1
  311. package/.output/server/chunks/routes/api/health.get.mjs +1 -0
  312. package/.output/server/chunks/routes/api/health.get.mjs.map +1 -1
  313. package/.output/server/chunks/routes/api/home.get.mjs +1 -0
  314. package/.output/server/chunks/routes/api/home.get.mjs.map +1 -1
  315. package/.output/server/chunks/routes/api/hooks/index.get.mjs +1 -0
  316. package/.output/server/chunks/routes/api/hooks/index.get.mjs.map +1 -1
  317. package/.output/server/chunks/routes/api/hooks/index.post.mjs +1 -0
  318. package/.output/server/chunks/routes/api/hooks/index.post.mjs.map +1 -1
  319. package/.output/server/chunks/routes/api/hooks/stats.get.mjs +1 -0
  320. package/.output/server/chunks/routes/api/hooks/stats.get.mjs.map +1 -1
  321. package/.output/server/chunks/routes/api/index.get.mjs +1 -0
  322. package/.output/server/chunks/routes/api/index.get.mjs.map +1 -1
  323. package/.output/server/chunks/routes/api/index.get2.mjs +1 -0
  324. package/.output/server/chunks/routes/api/index.get2.mjs.map +1 -1
  325. package/.output/server/chunks/routes/api/index.get3.mjs +1 -0
  326. package/.output/server/chunks/routes/api/index.get3.mjs.map +1 -1
  327. package/.output/server/chunks/routes/api/index.get4.mjs +1 -0
  328. package/.output/server/chunks/routes/api/index.get4.mjs.map +1 -1
  329. package/.output/server/chunks/routes/api/index.get5.mjs +1 -0
  330. package/.output/server/chunks/routes/api/index.get5.mjs.map +1 -1
  331. package/.output/server/chunks/routes/api/index.get6.mjs +1 -0
  332. package/.output/server/chunks/routes/api/index.get6.mjs.map +1 -1
  333. package/.output/server/chunks/routes/api/index.get7.mjs +40 -38
  334. package/.output/server/chunks/routes/api/index.get7.mjs.map +1 -1
  335. package/.output/server/chunks/routes/api/index.get8.mjs +33 -38
  336. package/.output/server/chunks/routes/api/index.get8.mjs.map +1 -1
  337. package/.output/server/chunks/routes/api/index.get9.mjs +83 -0
  338. package/.output/server/chunks/routes/api/index.get9.mjs.map +1 -0
  339. package/.output/server/chunks/routes/api/index.post.mjs +1 -0
  340. package/.output/server/chunks/routes/api/index.post.mjs.map +1 -1
  341. package/.output/server/chunks/routes/api/index.post2.mjs +1 -0
  342. package/.output/server/chunks/routes/api/index.post2.mjs.map +1 -1
  343. package/.output/server/chunks/routes/api/index.post3.mjs +1 -0
  344. package/.output/server/chunks/routes/api/index.post3.mjs.map +1 -1
  345. package/.output/server/chunks/routes/api/index.post4.mjs +1 -0
  346. package/.output/server/chunks/routes/api/index.post4.mjs.map +1 -1
  347. package/.output/server/chunks/routes/api/index.put.mjs +1 -0
  348. package/.output/server/chunks/routes/api/index.put.mjs.map +1 -1
  349. package/.output/server/chunks/routes/api/memory/_id_.delete.mjs +1 -0
  350. package/.output/server/chunks/routes/api/memory/_id_.delete.mjs.map +1 -1
  351. package/.output/server/chunks/routes/api/memory/context.get.mjs +1 -0
  352. package/.output/server/chunks/routes/api/memory/context.get.mjs.map +1 -1
  353. package/.output/server/chunks/routes/api/memory/extract.post.mjs +2 -1
  354. package/.output/server/chunks/routes/api/memory/extract.post.mjs.map +1 -1
  355. package/.output/server/chunks/routes/api/memory/search.get.mjs +1 -0
  356. package/.output/server/chunks/routes/api/memory/search.get.mjs.map +1 -1
  357. package/.output/server/chunks/routes/api/memory/store.post.mjs +1 -0
  358. package/.output/server/chunks/routes/api/memory/store.post.mjs.map +1 -1
  359. package/.output/server/chunks/routes/api/projects/index.delete.mjs +1 -0
  360. package/.output/server/chunks/routes/api/projects/index.delete.mjs.map +1 -1
  361. package/.output/server/chunks/routes/api/projects/index.get.mjs +1 -0
  362. package/.output/server/chunks/routes/api/projects/index.get.mjs.map +1 -1
  363. package/.output/server/chunks/routes/api/projects/index.put.mjs +1 -0
  364. package/.output/server/chunks/routes/api/projects/index.put.mjs.map +1 -1
  365. package/.output/server/chunks/routes/api/secrets/_key_.delete.mjs +1 -0
  366. package/.output/server/chunks/routes/api/secrets/_key_.delete.mjs.map +1 -1
  367. package/.output/server/chunks/routes/api/secrets/_key_.get.mjs +1 -0
  368. package/.output/server/chunks/routes/api/secrets/_key_.get.mjs.map +1 -1
  369. package/.output/server/chunks/routes/api/secrets/_key_.put.mjs +1 -0
  370. package/.output/server/chunks/routes/api/secrets/_key_.put.mjs.map +1 -1
  371. package/.output/server/chunks/routes/api/skills/_name/export.get.mjs +72 -0
  372. package/.output/server/chunks/routes/api/skills/_name/export.get.mjs.map +1 -0
  373. package/.output/server/chunks/routes/api/skills/_name/files/create.post.mjs +73 -0
  374. package/.output/server/chunks/routes/api/skills/_name/files/create.post.mjs.map +1 -0
  375. package/.output/server/chunks/routes/api/skills/_name/files/delete.post.mjs +71 -0
  376. package/.output/server/chunks/routes/api/skills/_name/files/delete.post.mjs.map +1 -0
  377. package/.output/server/chunks/routes/api/skills/_name/files/read.post.mjs +69 -0
  378. package/.output/server/chunks/routes/api/skills/_name/files/read.post.mjs.map +1 -0
  379. package/.output/server/chunks/routes/api/skills/_name/files/write.post.mjs +69 -0
  380. package/.output/server/chunks/routes/api/skills/_name/files/write.post.mjs.map +1 -0
  381. package/.output/server/chunks/routes/api/skills/_name/index.get.mjs +60 -0
  382. package/.output/server/chunks/routes/api/skills/_name/index.get.mjs.map +1 -0
  383. package/.output/server/chunks/routes/api/skills/_name/rename.post.mjs +87 -0
  384. package/.output/server/chunks/routes/api/skills/_name/rename.post.mjs.map +1 -0
  385. package/.output/server/chunks/routes/api/skills/_name/toggle.post.mjs +62 -0
  386. package/.output/server/chunks/routes/api/skills/_name/toggle.post.mjs.map +1 -0
  387. package/.output/server/chunks/routes/api/skills/create.post.mjs +79 -0
  388. package/.output/server/chunks/routes/api/skills/create.post.mjs.map +1 -0
  389. package/.output/server/chunks/routes/api/skills/generate.post.mjs +143 -0
  390. package/.output/server/chunks/routes/api/skills/generate.post.mjs.map +1 -0
  391. package/.output/server/chunks/routes/api/skills/import.post.mjs +96 -0
  392. package/.output/server/chunks/routes/api/skills/import.post.mjs.map +1 -0
  393. package/.output/server/chunks/routes/api/skills/index.get.mjs +82 -0
  394. package/.output/server/chunks/routes/api/skills/index.get.mjs.map +1 -0
  395. package/.output/server/chunks/routes/api/skills/index.get2.mjs +83 -0
  396. package/.output/server/chunks/routes/api/skills/index.get2.mjs.map +1 -0
  397. package/.output/server/chunks/routes/api/skills/library/check-updates.get.mjs +72 -0
  398. package/.output/server/chunks/routes/api/skills/library/check-updates.get.mjs.map +1 -0
  399. package/.output/server/chunks/routes/api/skills/library/install.post.mjs +90 -0
  400. package/.output/server/chunks/routes/api/skills/library/install.post.mjs.map +1 -0
  401. package/.output/server/chunks/routes/api/tasks/_id/restore.post.mjs +1 -0
  402. package/.output/server/chunks/routes/api/tasks/_id/restore.post.mjs.map +1 -1
  403. package/.output/server/chunks/routes/api/tasks/index.delete.mjs +1 -0
  404. package/.output/server/chunks/routes/api/tasks/index.delete.mjs.map +1 -1
  405. package/.output/server/chunks/routes/api/tasks/index.get.mjs +1 -0
  406. package/.output/server/chunks/routes/api/tasks/index.get.mjs.map +1 -1
  407. package/.output/server/chunks/routes/api/tasks/index.put.mjs +1 -0
  408. package/.output/server/chunks/routes/api/tasks/index.put.mjs.map +1 -1
  409. package/.output/server/chunks/routes/api/tasks/tags.get.mjs +1 -0
  410. package/.output/server/chunks/routes/api/tasks/tags.get.mjs.map +1 -1
  411. package/.output/server/chunks/routes/api/usage/stats.get.mjs +4 -1
  412. package/.output/server/chunks/routes/api/usage/stats.get.mjs.map +1 -1
  413. package/.output/server/chunks/routes/api/user/email.patch.mjs +2 -1
  414. package/.output/server/chunks/routes/api/user/email.patch.mjs.map +1 -1
  415. package/.output/server/chunks/routes/notifications.mjs +2 -1
  416. package/.output/server/chunks/routes/notifications.mjs.map +1 -1
  417. package/.output/server/chunks/routes/renderer.mjs +2 -2
  418. package/.output/server/chunks/routes/terminal.mjs +2 -1
  419. package/.output/server/chunks/routes/terminal.mjs.map +1 -1
  420. package/.output/server/index.mjs +2 -1
  421. package/.output/server/index.mjs.map +1 -1
  422. package/.output/server/node_modules/adm-zip/adm-zip.js +949 -0
  423. package/.output/server/node_modules/adm-zip/headers/entryHeader.js +374 -0
  424. package/.output/server/node_modules/adm-zip/headers/index.js +2 -0
  425. package/.output/server/node_modules/adm-zip/headers/mainHeader.js +130 -0
  426. package/.output/server/node_modules/adm-zip/methods/deflater.js +33 -0
  427. package/.output/server/node_modules/adm-zip/methods/index.js +3 -0
  428. package/.output/server/node_modules/adm-zip/methods/inflater.js +34 -0
  429. package/.output/server/node_modules/adm-zip/methods/zipcrypto.js +175 -0
  430. package/.output/server/node_modules/adm-zip/package.json +49 -0
  431. package/.output/server/node_modules/adm-zip/util/constants.js +142 -0
  432. package/.output/server/node_modules/adm-zip/util/decoder.js +5 -0
  433. package/.output/server/node_modules/adm-zip/util/errors.js +63 -0
  434. package/.output/server/node_modules/adm-zip/util/fattr.js +76 -0
  435. package/.output/server/node_modules/adm-zip/util/index.js +5 -0
  436. package/.output/server/node_modules/adm-zip/util/utils.js +336 -0
  437. package/.output/server/node_modules/adm-zip/zipEntry.js +405 -0
  438. package/.output/server/node_modules/adm-zip/zipFile.js +446 -0
  439. package/.output/server/package.json +2 -1
  440. package/README.md +3 -0
  441. package/app/app.vue +1 -1
  442. package/app/components/dashboard/StatCards.vue +21 -2
  443. package/app/components/usage/UsageCostChart.client.vue +59 -23
  444. package/app/components/usage/UsageCostChart.server.vue +1 -0
  445. package/app/components/usage/UsageSourceDonut.client.vue +17 -5
  446. package/app/components/usage/UsageSourceDonut.server.vue +1 -0
  447. package/app/components/usage/UsageTopConsumers.vue +13 -3
  448. package/app/composables/usePreferences.ts +9 -1
  449. package/app/layouts/auth.vue +0 -10
  450. package/app/pages/login.vue +18 -8
  451. package/app/pages/skills/[name].vue +12 -0
  452. package/app/pages/skills/index.vue +47 -0
  453. package/app/pages/usage.vue +43 -16
  454. package/dist/cli/index.js +12 -13
  455. package/package.json +5 -3
  456. package/server/api/skills/[name]/export.get.ts +45 -0
  457. package/server/api/skills/import.post.ts +87 -0
  458. package/server/api/usage/stats.get.ts +4 -2
  459. package/shared/types/index.ts +2 -1
  460. package/.output/public/_nuxt/5ZXA0Ckq.js +0 -1
  461. package/.output/public/_nuxt/BIIJhjQO.js +0 -1
  462. package/.output/public/_nuxt/BIckl6wA.js +0 -1
  463. package/.output/public/_nuxt/BJ3o57WW.js +0 -1
  464. package/.output/public/_nuxt/BNetzZzF.js +0 -1
  465. package/.output/public/_nuxt/BS0ofHJK.js +0 -1
  466. package/.output/public/_nuxt/B_3_hrpn.js +0 -1
  467. package/.output/public/_nuxt/BaBZjmMC.js +0 -1
  468. package/.output/public/_nuxt/BaMqDm5u.js +0 -1
  469. package/.output/public/_nuxt/BhzMoffi.js +0 -1
  470. package/.output/public/_nuxt/BlhFigLL.js +0 -1
  471. package/.output/public/_nuxt/BoIxv-gM.js +0 -1
  472. package/.output/public/_nuxt/Br19oYkq.js +0 -1
  473. package/.output/public/_nuxt/C0kh_F7v.js +0 -1
  474. package/.output/public/_nuxt/C61KgSco.js +0 -1
  475. package/.output/public/_nuxt/CJUdYEdO.js +0 -1
  476. package/.output/public/_nuxt/CVJQGP1Q.js +0 -1
  477. package/.output/public/_nuxt/CWMUi89H.js +0 -1
  478. package/.output/public/_nuxt/Cdu2qGgq.js +0 -1
  479. package/.output/public/_nuxt/CeIu7z4p.js +0 -1
  480. package/.output/public/_nuxt/D2689qk4.js +0 -1
  481. package/.output/public/_nuxt/D31L7Ks6.js +0 -1
  482. package/.output/public/_nuxt/DB359q8R.js +0 -1
  483. package/.output/public/_nuxt/DHG66LPS.js +0 -1
  484. package/.output/public/_nuxt/DJ5V-y_x.js +0 -1
  485. package/.output/public/_nuxt/DLETdGFL.js +0 -1
  486. package/.output/public/_nuxt/DOICd-Ld.js +0 -1
  487. package/.output/public/_nuxt/DPEcH-gi.js +0 -65
  488. package/.output/public/_nuxt/Db8-_gO7.js +0 -1
  489. package/.output/public/_nuxt/DgV-EDJ9.js +0 -1
  490. package/.output/public/_nuxt/Dp2X5R2m.js +0 -1
  491. package/.output/public/_nuxt/DqB723Z0.js +0 -1
  492. package/.output/public/_nuxt/Q8Ps7oN5.js +0 -1
  493. package/.output/public/_nuxt/SXTDhzp6.js +0 -1
  494. package/.output/public/_nuxt/Sg2Lwc46.js +0 -1
  495. package/.output/public/_nuxt/_J_7XIn-.js +0 -1
  496. package/.output/public/_nuxt/builds/meta/a1e9100c-1a4f-4f7e-bb53-9dbe0d07effb.json +0 -1
  497. package/.output/public/_nuxt/entry.CGxIBGAf.css +0 -1
  498. package/.output/public/_nuxt/inmzPrjz.js +0 -1
  499. package/.output/public/_nuxt/oIX-ZDN6.js +0 -1
  500. package/.output/server/chunks/build/auth-CDHRohj4.mjs +0 -77
  501. package/.output/server/chunks/build/auth-CDHRohj4.mjs.map +0 -1
  502. package/.output/server/chunks/build/dashboard-YEscLBQN.mjs.map +0 -1
  503. package/.output/server/chunks/build/docs-Dk2JnYq3.mjs.map +0 -1
  504. package/.output/server/chunks/build/hooks-DP8WoUPS.mjs.map +0 -1
  505. package/.output/server/chunks/build/index-Ba_bPJgk.mjs.map +0 -1
  506. package/.output/server/chunks/build/tasks-DiOi1HG_.mjs.map +0 -1
  507. package/.output/server/chunks/build/usePreferences-CzC8fRzd.mjs.map +0 -1
  508. /package/.output/public/_nuxt/{useCopyToClipboard.Be_IvFWy.css → CodeEditor.Be_IvFWy.css} +0 -0
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { VisSingleContainer, VisDonut } from '@unovis/vue'
3
- import type { TokenUsageSource } from '~~/shared/types'
3
+ import type { TokenUsageSource, UsageDisplayMode } from '~~/shared/types'
4
4
 
5
5
  interface SourceData {
6
6
  source: TokenUsageSource
@@ -12,6 +12,7 @@ interface SourceData {
12
12
  const props = defineProps<{
13
13
  data: SourceData[]
14
14
  title?: string
15
+ displayMode?: UsageDisplayMode
15
16
  }>()
16
17
 
17
18
  const sourceLabels: Record<TokenUsageSource, string> = {
@@ -26,10 +27,19 @@ const sourceColors: Record<TokenUsageSource, string> = {
26
27
  memory_extraction: 'var(--ui-info)'
27
28
  }
28
29
 
29
- const value = (d: SourceData) => d.cost
30
+ const isTokens = computed(() => props.displayMode === 'tokens')
31
+ const value = (d: SourceData) => isTokens.value ? d.tokens : d.cost
30
32
  const color = (d: SourceData) => sourceColors[d.source] || 'var(--ui-neutral)'
31
33
 
32
- const totalCost = computed(() => props.data.reduce((sum, d) => sum + d.cost, 0))
34
+ const total = computed(() =>
35
+ props.data.reduce((sum, d) => sum + (isTokens.value ? d.tokens : d.cost), 0)
36
+ )
37
+
38
+ function formatTokens(v: number): string {
39
+ if (v >= 1_000_000) return `${(v / 1_000_000).toFixed(1)}M`
40
+ if (v >= 1_000) return `${(v / 1_000).toFixed(1)}K`
41
+ return String(v)
42
+ }
33
43
  </script>
34
44
 
35
45
  <template>
@@ -81,9 +91,11 @@ const totalCost = computed(() => props.data.reduce((sum, d) => sum + d.cost, 0))
81
91
  <span class="text-sm font-medium">{{ sourceLabels[item.source] }}</span>
82
92
  </div>
83
93
  <div class="text-right">
84
- <span class="text-sm font-semibold">${{ item.cost.toFixed(2) }}</span>
94
+ <span class="text-sm font-semibold">
95
+ {{ isTokens ? formatTokens(item.tokens) : `$${item.cost.toFixed(2)}` }}
96
+ </span>
85
97
  <span class="text-xs text-muted ml-2">
86
- {{ totalCost > 0 ? Math.round((item.cost / totalCost) * 100) : 0 }}%
98
+ {{ total > 0 ? Math.round(((isTokens ? item.tokens : item.cost) / total) * 100) : 0 }}%
87
99
  </span>
88
100
  </div>
89
101
  </div>
@@ -2,6 +2,7 @@
2
2
  defineProps<{
3
3
  data?: unknown[]
4
4
  title?: string
5
+ displayMode?: string
5
6
  }>()
6
7
  </script>
7
8
 
@@ -1,16 +1,18 @@
1
1
  <script setup lang="ts">
2
- import type { TokenUsageSource } from '~~/shared/types'
2
+ import type { TokenUsageSource, UsageDisplayMode } from '~~/shared/types'
3
3
 
4
4
  interface Consumer {
5
5
  name: string
6
6
  source: TokenUsageSource
7
7
  cost: number
8
8
  calls: number
9
+ tokens: number
9
10
  }
10
11
 
11
- defineProps<{
12
+ const props = defineProps<{
12
13
  data: Consumer[]
13
14
  title?: string
15
+ displayMode?: UsageDisplayMode
14
16
  }>()
15
17
 
16
18
  const sourceLabels: Record<TokenUsageSource, string> = {
@@ -25,10 +27,18 @@ const sourceColors = {
25
27
  memory_extraction: 'info'
26
28
  } as const
27
29
 
30
+ const isTokens = computed(() => props.displayMode === 'tokens')
31
+
28
32
  function formatCurrency(value: number): string {
29
33
  if (value < 0.01 && value > 0) return '<$0.01'
30
34
  return `$${value.toFixed(4)}`
31
35
  }
36
+
37
+ function formatTokens(value: number): string {
38
+ if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`
39
+ if (value >= 1_000) return `${(value / 1_000).toFixed(1)}K`
40
+ return String(value)
41
+ }
32
42
  </script>
33
43
 
34
44
  <template>
@@ -77,7 +87,7 @@ function formatCurrency(value: number): string {
77
87
 
78
88
  <div class="text-right shrink-0 ml-4">
79
89
  <p class="text-sm font-semibold">
80
- {{ formatCurrency(item.cost) }}
90
+ {{ isTokens ? formatTokens(item.tokens) : formatCurrency(item.cost) }}
81
91
  </p>
82
92
  <p class="text-xs text-muted">
83
93
  {{ item.calls }} {{ item.calls === 1 ? 'call' : 'calls' }}
@@ -1,4 +1,4 @@
1
- import type { TaskStatus } from '~~/shared/types'
1
+ import type { TaskStatus, UsageDisplayMode } from '~~/shared/types'
2
2
 
3
3
  interface Preferences {
4
4
  // Editor preferences
@@ -24,6 +24,7 @@ interface Preferences {
24
24
 
25
25
  // Usage stats
26
26
  usageStatsPeriod: '24h' | '7d' | '30d'
27
+ usageDisplayMode: UsageDisplayMode
27
28
 
28
29
  // Onboarding
29
30
  onboardingDismissed: boolean
@@ -45,6 +46,7 @@ const defaults: Preferences = {
45
46
  taskProjectFilter: null,
46
47
  agentStatsPeriod: '7d',
47
48
  usageStatsPeriod: '7d',
49
+ usageDisplayMode: 'tokens',
48
50
  onboardingDismissed: false
49
51
  }
50
52
 
@@ -123,6 +125,11 @@ export function usePreferences() {
123
125
  set: v => set('usageStatsPeriod', v)
124
126
  })
125
127
 
128
+ const usageDisplayMode = computed({
129
+ get: () => get('usageDisplayMode'),
130
+ set: v => set('usageDisplayMode', v)
131
+ })
132
+
126
133
  const onboardingDismissed = computed({
127
134
  get: () => get('onboardingDismissed'),
128
135
  set: v => set('onboardingDismissed', v)
@@ -146,6 +153,7 @@ export function usePreferences() {
146
153
  taskProjectFilter,
147
154
  agentStatsPeriod,
148
155
  usageStatsPeriod,
156
+ usageDisplayMode,
149
157
  onboardingDismissed
150
158
  }
151
159
  }
@@ -4,16 +4,6 @@
4
4
  <template>
5
5
  <div class="min-h-screen flex items-center justify-center bg-default">
6
6
  <div class="w-full max-w-md px-4">
7
- <div class="flex flex-col items-center gap-6 mb-8">
8
- <div class="flex items-center gap-3">
9
- <UIcon
10
- name="i-lucide-brain"
11
- class="size-10 text-primary"
12
- />
13
- <span class="font-bold text-2xl">Cognova</span>
14
- </div>
15
- </div>
16
-
17
7
  <slot />
18
8
  </div>
19
9
  </div>
@@ -49,12 +49,22 @@ async function handleSubmit(event: { data: { email: string, password: string } }
49
49
  </script>
50
50
 
51
51
  <template>
52
- <UAuthForm
53
- title="Sign In"
54
- description="Enter your credentials to access your account"
55
- icon="i-lucide-brain"
56
- :fields="fields"
57
- :submit="{ label: 'Sign In', loading }"
58
- @submit="handleSubmit"
59
- />
52
+ <div>
53
+ <div class="flex flex-col items-center gap-6 mb-8">
54
+ <div class="flex items-center gap-3">
55
+ <UIcon
56
+ name="i-lucide-brain"
57
+ class="size-10 text-primary"
58
+ />
59
+ <span class="font-bold text-2xl">Cognova</span>
60
+ </div>
61
+ </div>
62
+ <UAuthForm
63
+ title="Sign In"
64
+ description="Enter your credentials to access your account"
65
+ :fields="fields"
66
+ :submit="{ label: 'Sign In', loading }"
67
+ @submit="handleSubmit"
68
+ />
69
+ </div>
60
70
  </template>
@@ -55,6 +55,10 @@ function handleRenamed(newName: string) {
55
55
  router.replace(`/skills/${newName}`)
56
56
  }
57
57
 
58
+ function handleExport() {
59
+ window.open(`/api/skills/${skillName.value}/export`, '_blank')
60
+ }
61
+
58
62
  onMounted(() => loadSkill())
59
63
  </script>
60
64
 
@@ -151,6 +155,14 @@ onMounted(() => loadSkill())
151
155
  size="sm"
152
156
  @click="renameOpen = true"
153
157
  />
158
+ <UButton
159
+ v-if="skill"
160
+ icon="i-lucide-download"
161
+ variant="ghost"
162
+ color="neutral"
163
+ size="sm"
164
+ @click="handleExport"
165
+ />
154
166
  </template>
155
167
  </UDashboardNavbar>
156
168
  </template>
@@ -11,6 +11,8 @@ const skills = ref<SkillListItem[]>([])
11
11
  const loading = ref(true)
12
12
  const search = ref('')
13
13
  const createOpen = ref(false)
14
+ const importing = ref(false)
15
+ const fileInput = ref<HTMLInputElement | null>(null)
14
16
 
15
17
  const filteredSkills = computed(() => {
16
18
  if (!search.value.trim()) return skills.value
@@ -33,6 +35,34 @@ async function loadSkills() {
33
35
  }
34
36
  }
35
37
 
38
+ async function handleImport(event: Event) {
39
+ const input = event.target as HTMLInputElement
40
+ const file = input.files?.[0]
41
+ if (!file) return
42
+
43
+ importing.value = true
44
+ try {
45
+ const formData = new FormData()
46
+ formData.append('file', file)
47
+ const res = await $fetch<{ data: { name: string, fileCount: number } }>('/api/skills/import', {
48
+ method: 'POST',
49
+ body: formData
50
+ })
51
+ toast.add({
52
+ title: `Imported ${res.data.name}`,
53
+ description: `${res.data.fileCount} file${res.data.fileCount === 1 ? '' : 's'}`,
54
+ color: 'success'
55
+ })
56
+ navigateTo(`/skills/${res.data.name}`)
57
+ } catch (err: unknown) {
58
+ const message = err instanceof Error ? err.message : 'Import failed'
59
+ toast.add({ title: 'Import failed', description: message, color: 'error' })
60
+ } finally {
61
+ importing.value = false
62
+ input.value = ''
63
+ }
64
+ }
65
+
36
66
  async function handleToggle(name: string) {
37
67
  try {
38
68
  const res = await $fetch<{ data: { name: string, active: boolean } }>(`/api/skills/${name}/toggle`, {
@@ -78,6 +108,23 @@ onMounted(() => loadSkills())
78
108
  Library
79
109
  </UButton>
80
110
  </NuxtLink>
111
+ <UButton
112
+ icon="i-lucide-upload"
113
+ variant="ghost"
114
+ color="neutral"
115
+ size="sm"
116
+ :loading="importing"
117
+ @click="fileInput?.click()"
118
+ >
119
+ Import
120
+ </UButton>
121
+ <input
122
+ ref="fileInput"
123
+ type="file"
124
+ accept=".zip"
125
+ class="hidden"
126
+ @change="handleImport"
127
+ >
81
128
  <UButton
82
129
  icon="i-lucide-plus"
83
130
  size="sm"
@@ -1,13 +1,14 @@
1
1
  <script setup lang="ts">
2
- import type { StatsPeriod, UsageStats } from '~~/shared/types'
2
+ import type { StatsPeriod, UsageStats, UsageDisplayMode } from '~~/shared/types'
3
3
 
4
4
  definePageMeta({
5
5
  layout: 'dashboard',
6
6
  middleware: 'auth'
7
7
  })
8
8
 
9
- const { usageStatsPeriod } = usePreferences()
9
+ const { usageStatsPeriod, usageDisplayMode } = usePreferences()
10
10
  const period = ref<StatsPeriod>(usageStatsPeriod.value)
11
+ const displayMode = ref<UsageDisplayMode>(usageDisplayMode.value)
11
12
  const granularity = ref<'daily' | 'hourly'>('daily')
12
13
  const stats = ref<UsageStats | null>(null)
13
14
  const loading = ref(false)
@@ -18,6 +19,11 @@ const periodOptions = [
18
19
  { label: '30d', value: '30d' as StatsPeriod }
19
20
  ]
20
21
 
22
+ const displayModeOptions = [
23
+ { label: 'Tokens', value: 'tokens' as UsageDisplayMode },
24
+ { label: 'Cost', value: 'cost' as UsageDisplayMode }
25
+ ]
26
+
21
27
  async function loadStats() {
22
28
  loading.value = true
23
29
  try {
@@ -41,6 +47,10 @@ watch(period, (value) => {
41
47
  loadStats()
42
48
  })
43
49
 
50
+ watch(displayMode, (value) => {
51
+ usageDisplayMode.value = value
52
+ })
53
+
44
54
  watch(granularity, () => {
45
55
  loadStats()
46
56
  })
@@ -59,18 +69,32 @@ onMounted(() => {
59
69
  <template #header>
60
70
  <UDashboardNavbar title="Token Usage">
61
71
  <template #right>
62
- <UFieldGroup>
63
- <UButton
64
- v-for="opt in periodOptions"
65
- :key="opt.value"
66
- :color="period === opt.value ? 'primary' : 'neutral'"
67
- :variant="period === opt.value ? 'solid' : 'ghost'"
68
- size="sm"
69
- @click="period = opt.value"
70
- >
71
- {{ opt.label }}
72
- </UButton>
73
- </UFieldGroup>
72
+ <div class="flex items-center gap-4">
73
+ <UFieldGroup>
74
+ <UButton
75
+ v-for="opt in displayModeOptions"
76
+ :key="opt.value"
77
+ :color="displayMode === opt.value ? 'primary' : 'neutral'"
78
+ :variant="displayMode === opt.value ? 'solid' : 'ghost'"
79
+ size="sm"
80
+ @click="displayMode = opt.value"
81
+ >
82
+ {{ opt.label }}
83
+ </UButton>
84
+ </UFieldGroup>
85
+ <UFieldGroup>
86
+ <UButton
87
+ v-for="opt in periodOptions"
88
+ :key="opt.value"
89
+ :color="period === opt.value ? 'primary' : 'neutral'"
90
+ :variant="period === opt.value ? 'solid' : 'ghost'"
91
+ size="sm"
92
+ @click="period = opt.value"
93
+ >
94
+ {{ opt.label }}
95
+ </UButton>
96
+ </UFieldGroup>
97
+ </div>
74
98
  </template>
75
99
  </UDashboardNavbar>
76
100
  </template>
@@ -86,19 +110,22 @@ onMounted(() => {
86
110
  v-if="stats && stats.dailyUsage.length > 0"
87
111
  v-model:granularity="granularity"
88
112
  :data="stats.dailyUsage"
89
- title="Cost Over Time"
113
+ :display-mode="displayMode"
114
+ :title="displayMode === 'tokens' ? 'Tokens Over Time' : 'Cost Over Time'"
90
115
  />
91
116
 
92
117
  <div class="grid gap-6 lg:grid-cols-2">
93
118
  <UsageSourceDonut
94
119
  v-if="stats && stats.bySource.length > 0"
95
120
  :data="stats.bySource"
96
- title="Cost by Source"
121
+ :display-mode="displayMode"
122
+ :title="displayMode === 'tokens' ? 'Tokens by Source' : 'Cost by Source'"
97
123
  />
98
124
 
99
125
  <UsageTopConsumers
100
126
  v-if="stats && stats.topConsumers.length > 0"
101
127
  :data="stats.topConsumers"
128
+ :display-mode="displayMode"
102
129
  title="Top Consumers"
103
130
  />
104
131
  </div>
package/dist/cli/index.js CHANGED
@@ -2339,25 +2339,24 @@ async function update() {
2339
2339
  }
2340
2340
  if (latestVersion === metadata.version) {
2341
2341
  s.stop(`Already on latest version (${metadata.version})`);
2342
- } else {
2343
- s.stop(`Update available: ${metadata.version} \u2192 ${import_picocolors6.default.green(latestVersion)}`);
2342
+ Le("Nothing to update.");
2343
+ return;
2344
2344
  }
2345
+ s.stop(`Update available: ${metadata.version} \u2192 ${import_picocolors6.default.green(latestVersion)}`);
2345
2346
  s.start("Creating backup");
2346
2347
  const backupDir = createBackup(installDir);
2347
2348
  s.stop("Backup created");
2348
2349
  let updateFailed = false;
2349
2350
  try {
2350
- if (latestVersion !== metadata.version) {
2351
- s.start("Downloading latest version");
2352
- const tmpDir = execSync7("mktemp -d", { encoding: "utf-8" }).trim();
2353
- try {
2354
- execSync7(`npm pack cognova@${latestVersion} --pack-destination ${tmpDir}`, { stdio: "pipe" });
2355
- execSync7(`tar -xzf ${tmpDir}/cognova-${latestVersion}.tgz -C ${tmpDir}`, { stdio: "pipe" });
2356
- copyAppSource(`${tmpDir}/package`, installDir);
2357
- s.stop("Source files updated");
2358
- } finally {
2359
- rmSync(tmpDir, { recursive: true, force: true });
2360
- }
2351
+ s.start("Downloading latest version");
2352
+ const tmpDir = execSync7("mktemp -d", { encoding: "utf-8" }).trim();
2353
+ try {
2354
+ execSync7(`npm pack cognova@${latestVersion} --pack-destination ${tmpDir}`, { stdio: "pipe" });
2355
+ execSync7(`tar -xzf ${tmpDir}/cognova-${latestVersion}.tgz -C ${tmpDir}`, { stdio: "pipe" });
2356
+ copyAppSource(`${tmpDir}/package`, installDir);
2357
+ s.stop("Source files updated");
2358
+ } finally {
2359
+ rmSync(tmpDir, { recursive: true, force: true });
2361
2360
  }
2362
2361
  s.start("Syncing Claude config");
2363
2362
  syncClaudeConfig(installDir);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cognova",
3
3
  "type": "module",
4
- "version": "0.2.2",
4
+ "version": "0.2.3",
5
5
  "description": "Personal knowledge management system with Claude Code integration",
6
6
  "repository": {
7
7
  "type": "git",
@@ -75,12 +75,14 @@
75
75
  "@xterm/addon-fit": "^0.11.0",
76
76
  "@xterm/addon-web-links": "^0.12.0",
77
77
  "@xterm/xterm": "^6.0.0",
78
+ "adm-zip": "^0.5.16",
78
79
  "better-auth": "^1.4.17",
79
80
  "chokidar": "^5.0.0",
80
81
  "codemirror": "^6.0.2",
81
82
  "cron": "^4.4.0",
82
83
  "date-fns": "^4.1.0",
83
84
  "dotenv": "^17.2.3",
85
+ "drizzle-kit": "^0.31.8",
84
86
  "drizzle-orm": "^0.45.1",
85
87
  "gray-matter": "^4.0.3",
86
88
  "node-pty": "^1.1.0",
@@ -88,11 +90,11 @@
88
90
  "postgres": "^3.4.8",
89
91
  "shiki": "^3.21.0",
90
92
  "sortablejs": "^1.15.6",
91
- "tailwindcss": "^4.0.0",
92
- "drizzle-kit": "^0.31.8"
93
+ "tailwindcss": "^4.0.0"
93
94
  },
94
95
  "devDependencies": {
95
96
  "@nuxt/eslint": "^1.12.1",
97
+ "@types/adm-zip": "^0.5.7",
96
98
  "@types/node": "^25.0.8",
97
99
  "@types/sortablejs": "^1.15.9",
98
100
  "eslint": "^9.39.2",
@@ -0,0 +1,45 @@
1
+ import { stat } from 'fs/promises'
2
+ import { join } 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 name = getRouterParam(event, 'name')
8
+ if (!name)
9
+ throw createError({ statusCode: 400, message: 'Skill name required' })
10
+
11
+ const nameError = validateSkillName(name)
12
+ if (nameError)
13
+ throw createError({ statusCode: 400, message: nameError })
14
+
15
+ // Check active first, then inactive
16
+ const activeDir = join(getSkillsDir(), name)
17
+ const inactiveDir = join(getInactiveSkillsDir(), name)
18
+
19
+ let skillDir = ''
20
+
21
+ const activeStat = await stat(activeDir).catch(() => null)
22
+ if (activeStat?.isDirectory()) {
23
+ skillDir = activeDir
24
+ } else {
25
+ const inactiveStat = await stat(inactiveDir).catch(() => null)
26
+ if (inactiveStat?.isDirectory())
27
+ skillDir = inactiveDir
28
+ }
29
+
30
+ if (!skillDir)
31
+ throw createError({ statusCode: 404, message: `Skill '${name}' not found` })
32
+
33
+ const zip = new AdmZip()
34
+ zip.addLocalFolder(skillDir, name, /^(?!.*(__pycache__|\.pyc))/)
35
+
36
+ const buffer = zip.toBuffer()
37
+
38
+ setResponseHeaders(event, {
39
+ 'Content-Type': 'application/zip',
40
+ 'Content-Disposition': `attachment; filename="${name}.zip"`,
41
+ 'Content-Length': String(buffer.length)
42
+ })
43
+
44
+ return send(event, buffer)
45
+ })
@@ -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
+ })
@@ -57,7 +57,7 @@ export default defineEventHandler(async (event) => {
57
57
  const sourceMap = new Map<TokenUsageSource, { cost: number, calls: number, tokens: number }>()
58
58
 
59
59
  // Top consumers
60
- const consumerMap = new Map<string, { name: string, source: TokenUsageSource, cost: number, calls: number }>()
60
+ const consumerMap = new Map<string, { name: string, source: TokenUsageSource, cost: number, calls: number, tokens: number }>()
61
61
 
62
62
  for (const r of records) {
63
63
  totalCostUsd += r.costUsd
@@ -99,10 +99,12 @@ export default defineEventHandler(async (event) => {
99
99
  name: r.sourceName || 'Unknown',
100
100
  source,
101
101
  cost: 0,
102
- calls: 0
102
+ calls: 0,
103
+ tokens: 0
103
104
  }
104
105
  consumer.cost += r.costUsd
105
106
  consumer.calls++
107
+ consumer.tokens += r.inputTokens + r.outputTokens
106
108
  consumerMap.set(consumerKey, consumer)
107
109
  }
108
110
 
@@ -345,6 +345,7 @@ export interface UserSettings {
345
345
  // === Agent Stats ===
346
346
 
347
347
  export type StatsPeriod = '24h' | '7d' | '30d'
348
+ export type UsageDisplayMode = 'cost' | 'tokens'
348
349
 
349
350
  export interface DailyRunData {
350
351
  date: string
@@ -412,7 +413,7 @@ export interface UsageStats {
412
413
  avgCostPerCall: number
413
414
  dailyUsage: DailyUsageData[]
414
415
  bySource: { source: TokenUsageSource, cost: number, calls: number, tokens: number }[]
415
- topConsumers: { name: string, source: TokenUsageSource, cost: number, calls: number }[]
416
+ topConsumers: { name: string, source: TokenUsageSource, cost: number, calls: number, tokens: number }[]
416
417
  }
417
418
 
418
419
  // === Dashboard ===