opencami 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (346) hide show
  1. package/README.md +20 -3
  2. package/dist/client/analytics-dashboard.html +509 -0
  3. package/dist/client/analytics.json +598 -0
  4. package/dist/client/assets/_sessionKey-xUqdePGW.js +97 -0
  5. package/dist/client/assets/agents-BiadNAEz.js +2 -0
  6. package/dist/client/assets/agents-screen-C5TPJbry.js +1 -0
  7. package/dist/client/assets/button-seqh98ae.js +1 -0
  8. package/dist/client/assets/{connect-BRasuRbB.js → connect-DlVsi-ya.js} +2 -2
  9. package/dist/client/assets/file-explorer-screen-B0hwrjdF.js +1 -0
  10. package/dist/client/assets/files-dkr2U72N.js +2 -0
  11. package/dist/client/assets/index-CwoJpeG1.js +153 -0
  12. package/dist/client/assets/{index-DHGnKfAU.js → index-D1Et4XlM.js} +1 -1
  13. package/dist/client/assets/keyboard-shortcuts-dialog-zdnAmDiH.js +1 -0
  14. package/dist/client/assets/{main-BAHT5yqU.js → main-DOBfHXDF.js} +12 -12
  15. package/dist/client/assets/opencami-logo-Bxp_4d3X.js +1 -0
  16. package/dist/client/assets/react-DD8SkMJn.js +1 -0
  17. package/dist/client/assets/search-dialog-Ck1AQreu.js +1 -0
  18. package/dist/client/assets/session-export-dialog-Bh3zH4nZ.js +1 -0
  19. package/dist/client/assets/settings-dialog-CvUsgnnZ.js +1 -0
  20. package/dist/client/assets/styles-DogPvrGY.css +1 -0
  21. package/dist/client/assets/switch-BoGcWcnr.js +1 -0
  22. package/dist/client/assets/use-file-explorer-state-B5JLNsSa.js +12 -0
  23. package/dist/client/assets/useButton-csSB2uQJ.js +9 -0
  24. package/dist/client/manifest.json +8 -2
  25. package/dist/server/assets/{_sessionKey-qlAPF_Ft.js → _sessionKey-DQwkBUS7.js} +981 -229
  26. package/dist/server/assets/_tanstack-start-manifest_v-cW8K1Mnv.js +4 -0
  27. package/dist/server/assets/agents-Dz_i76VW.js +11 -0
  28. package/dist/server/assets/agents-screen-CqQPJndp.js +587 -0
  29. package/dist/server/assets/{connect-BWI_6rCm.js → connect-CIDOw12K.js} +34 -2
  30. package/dist/server/assets/{file-explorer-screen-DJXPEG_J.js → file-explorer-screen-BzvgvV8m.js} +7 -58
  31. package/dist/server/assets/{files-CONoVTGD.js → files-BxvRDIWU.js} +1 -1
  32. package/dist/server/assets/{index-Bp8QskbI.js → index-BwD7ufHE.js} +4 -3
  33. package/dist/server/assets/{index-COu2idHm.js → index-CmbNTqa2.js} +105 -14
  34. package/dist/server/assets/{keyboard-shortcuts-dialog-D5hqVX2v.js → keyboard-shortcuts-dialog-7OEtXUlW.js} +2 -2
  35. package/dist/server/assets/opencami-logo-C-43FL3R.js +24 -0
  36. package/dist/server/assets/{router-DbxyvprK.js → router-5qObg5aX.js} +368 -74
  37. package/dist/server/assets/{search-dialog-JY8C3mqa.js → search-dialog-BE2ZBkj0.js} +44 -12
  38. package/dist/server/assets/{session-export-dialog-D87uafPD.js → session-export-dialog-DRVbC8Q-.js} +2 -2
  39. package/dist/server/assets/{settings-dialog-CBj7njLM.js → settings-dialog-BBQcU55J.js} +204 -41
  40. package/dist/server/assets/switch-DnX0MjGS.js +28 -0
  41. package/dist/server/assets/tooltip-gbV6rEVv.js +60 -0
  42. package/dist/server/assets/{menu-D6n4DB0U.js → use-file-explorer-state-DMHdtb7D.js} +56 -57
  43. package/dist/server/server.js +2 -2
  44. package/package.json +1 -1
  45. package/dist/client/assets/_sessionKey-B-MBYHgD.js +0 -95
  46. package/dist/client/assets/abap-BdImnpbu.js +0 -1
  47. package/dist/client/assets/actionscript-3-CfeIJUat.js +0 -1
  48. package/dist/client/assets/ada-bCR0ucgS.js +0 -1
  49. package/dist/client/assets/andromeeda-C-Jbm3Hp.js +0 -1
  50. package/dist/client/assets/angular-html-CU67Zn6k.js +0 -1
  51. package/dist/client/assets/angular-ts-BwZT4LLn.js +0 -1
  52. package/dist/client/assets/apache-Pmp26Uib.js +0 -1
  53. package/dist/client/assets/apex-D8_7TLub.js +0 -1
  54. package/dist/client/assets/apl-dKokRX4l.js +0 -1
  55. package/dist/client/assets/applescript-Co6uUVPk.js +0 -1
  56. package/dist/client/assets/ara-BRHolxvo.js +0 -1
  57. package/dist/client/assets/asciidoc-Dv7Oe6Be.js +0 -1
  58. package/dist/client/assets/asm-D_Q5rh1f.js +0 -1
  59. package/dist/client/assets/astro-CbQHKStN.js +0 -1
  60. package/dist/client/assets/aurora-x-D-2ljcwZ.js +0 -1
  61. package/dist/client/assets/awk-DMzUqQB5.js +0 -1
  62. package/dist/client/assets/ayu-dark-CmMr59Fi.js +0 -1
  63. package/dist/client/assets/ballerina-BFfxhgS-.js +0 -1
  64. package/dist/client/assets/bat-BkioyH1T.js +0 -1
  65. package/dist/client/assets/beancount-k_qm7-4y.js +0 -1
  66. package/dist/client/assets/berry-uYugtg8r.js +0 -1
  67. package/dist/client/assets/bibtex-CHM0blh-.js +0 -1
  68. package/dist/client/assets/bicep-Bmn6On1c.js +0 -1
  69. package/dist/client/assets/blade-D4QpJJKB.js +0 -1
  70. package/dist/client/assets/bsl-BO_Y6i37.js +0 -1
  71. package/dist/client/assets/button-D_9OBT_f.js +0 -1
  72. package/dist/client/assets/c-BIGW1oBm.js +0 -1
  73. package/dist/client/assets/c3-VCDPK7BO.js +0 -1
  74. package/dist/client/assets/cadence-Bv_4Rxtq.js +0 -1
  75. package/dist/client/assets/cairo-KRGpt6FW.js +0 -1
  76. package/dist/client/assets/catppuccin-frappe-DFWUc33u.js +0 -1
  77. package/dist/client/assets/catppuccin-latte-C9dUb6Cb.js +0 -1
  78. package/dist/client/assets/catppuccin-macchiato-DQyhUUbL.js +0 -1
  79. package/dist/client/assets/catppuccin-mocha-D87Tk5Gz.js +0 -1
  80. package/dist/client/assets/clarity-D53aC0YG.js +0 -1
  81. package/dist/client/assets/clojure-P80f7IUj.js +0 -1
  82. package/dist/client/assets/cmake-D1j8_8rp.js +0 -1
  83. package/dist/client/assets/cobol-nwyudZeR.js +0 -1
  84. package/dist/client/assets/codeowners-Bp6g37R7.js +0 -1
  85. package/dist/client/assets/codeql-DsOJ9woJ.js +0 -1
  86. package/dist/client/assets/coffee-Ch7k5sss.js +0 -1
  87. package/dist/client/assets/common-lisp-Cg-RD9OK.js +0 -1
  88. package/dist/client/assets/coq-DkFqJrB1.js +0 -1
  89. package/dist/client/assets/cpp-CofmeUqb.js +0 -1
  90. package/dist/client/assets/crystal-tKQVLTB8.js +0 -1
  91. package/dist/client/assets/csharp-K5feNrxe.js +0 -1
  92. package/dist/client/assets/css-DPfMkruS.js +0 -1
  93. package/dist/client/assets/csv-fuZLfV_i.js +0 -1
  94. package/dist/client/assets/cue-D82EKSYY.js +0 -1
  95. package/dist/client/assets/cypher-COkxafJQ.js +0 -1
  96. package/dist/client/assets/d-85-TOEBH.js +0 -1
  97. package/dist/client/assets/dark-plus-C3mMm8J8.js +0 -1
  98. package/dist/client/assets/dart-CF10PKvl.js +0 -1
  99. package/dist/client/assets/dax-CEL-wOlO.js +0 -1
  100. package/dist/client/assets/desktop-BmXAJ9_W.js +0 -1
  101. package/dist/client/assets/diff-D97Zzqfu.js +0 -1
  102. package/dist/client/assets/docker-BcOcwvcX.js +0 -1
  103. package/dist/client/assets/dotenv-Da5cRb03.js +0 -1
  104. package/dist/client/assets/dracula-BzJJZx-M.js +0 -1
  105. package/dist/client/assets/dracula-soft-BXkSAIEj.js +0 -1
  106. package/dist/client/assets/dream-maker-BtqSS_iP.js +0 -1
  107. package/dist/client/assets/edge-BkV0erSs.js +0 -1
  108. package/dist/client/assets/elixir-CDX3lj18.js +0 -1
  109. package/dist/client/assets/elm-DbKCFpqz.js +0 -1
  110. package/dist/client/assets/emacs-lisp-C9XAeP06.js +0 -1
  111. package/dist/client/assets/erb-BOJIQeun.js +0 -1
  112. package/dist/client/assets/erlang-DsQrWhSR.js +0 -1
  113. package/dist/client/assets/everforest-dark-BgDCqdQA.js +0 -1
  114. package/dist/client/assets/everforest-light-C8M2exoo.js +0 -1
  115. package/dist/client/assets/fennel-BYunw83y.js +0 -1
  116. package/dist/client/assets/file-explorer-screen-Daf4rIq9.js +0 -1
  117. package/dist/client/assets/files-ByeIMLfw.js +0 -2
  118. package/dist/client/assets/fish-BvzEVeQv.js +0 -1
  119. package/dist/client/assets/fluent-C4IJs8-o.js +0 -1
  120. package/dist/client/assets/fortran-fixed-form-CkoXwp7k.js +0 -1
  121. package/dist/client/assets/fortran-free-form-BxgE0vQu.js +0 -1
  122. package/dist/client/assets/fsharp-CXgrBDvD.js +0 -1
  123. package/dist/client/assets/gdresource-B7Tvp0Sc.js +0 -1
  124. package/dist/client/assets/gdscript-DTMYz4Jt.js +0 -1
  125. package/dist/client/assets/gdshader-DkwncUOv.js +0 -1
  126. package/dist/client/assets/genie-D0YGMca9.js +0 -1
  127. package/dist/client/assets/gherkin-DyxjwDmM.js +0 -1
  128. package/dist/client/assets/git-commit-F4YmCXRG.js +0 -1
  129. package/dist/client/assets/git-rebase-r7XF79zn.js +0 -1
  130. package/dist/client/assets/github-dark-DHJKELXO.js +0 -1
  131. package/dist/client/assets/github-dark-default-Cuk6v7N8.js +0 -1
  132. package/dist/client/assets/github-dark-dimmed-DH5Ifo-i.js +0 -1
  133. package/dist/client/assets/github-dark-high-contrast-E3gJ1_iC.js +0 -1
  134. package/dist/client/assets/github-light-DAi9KRSo.js +0 -1
  135. package/dist/client/assets/github-light-default-D7oLnXFd.js +0 -1
  136. package/dist/client/assets/github-light-high-contrast-BfjtVDDH.js +0 -1
  137. package/dist/client/assets/gleam-BspZqrRM.js +0 -1
  138. package/dist/client/assets/glimmer-js-Rg0-pVw9.js +0 -1
  139. package/dist/client/assets/glimmer-ts-U6CK756n.js +0 -1
  140. package/dist/client/assets/glsl-DplSGwfg.js +0 -1
  141. package/dist/client/assets/gn-n2N0HUVH.js +0 -1
  142. package/dist/client/assets/gnuplot-DdkO51Og.js +0 -1
  143. package/dist/client/assets/go-Dn2_MT6a.js +0 -1
  144. package/dist/client/assets/graphql-ChdNCCLP.js +0 -1
  145. package/dist/client/assets/groovy-gcz8RCvz.js +0 -1
  146. package/dist/client/assets/gruvbox-dark-hard-CFHQjOhq.js +0 -1
  147. package/dist/client/assets/gruvbox-dark-medium-GsRaNv29.js +0 -1
  148. package/dist/client/assets/gruvbox-dark-soft-CVdnzihN.js +0 -1
  149. package/dist/client/assets/gruvbox-light-hard-CH1njM8p.js +0 -1
  150. package/dist/client/assets/gruvbox-light-medium-DRw_LuNl.js +0 -1
  151. package/dist/client/assets/gruvbox-light-soft-hJgmCMqR.js +0 -1
  152. package/dist/client/assets/hack-CaT9iCJl.js +0 -1
  153. package/dist/client/assets/haml-B8DHNrY2.js +0 -1
  154. package/dist/client/assets/handlebars-BL8al0AC.js +0 -1
  155. package/dist/client/assets/haskell-Df6bDoY_.js +0 -1
  156. package/dist/client/assets/haxe-CzTSHFRz.js +0 -1
  157. package/dist/client/assets/hcl-BWvSN4gD.js +0 -1
  158. package/dist/client/assets/hjson-D5-asLiD.js +0 -1
  159. package/dist/client/assets/hlsl-D3lLCCz7.js +0 -1
  160. package/dist/client/assets/houston-DnULxvSX.js +0 -1
  161. package/dist/client/assets/html-GMplVEZG.js +0 -1
  162. package/dist/client/assets/html-derivative-BFtXZ54Q.js +0 -1
  163. package/dist/client/assets/http-jrhK8wxY.js +0 -1
  164. package/dist/client/assets/hurl-irOxFIW8.js +0 -1
  165. package/dist/client/assets/hxml-Bvhsp5Yf.js +0 -1
  166. package/dist/client/assets/hy-DFXneXwc.js +0 -1
  167. package/dist/client/assets/imba-DGztddWO.js +0 -1
  168. package/dist/client/assets/index-ByUDBI-n.js +0 -14
  169. package/dist/client/assets/ini-BEwlwnbL.js +0 -1
  170. package/dist/client/assets/java-CylS5w8V.js +0 -1
  171. package/dist/client/assets/javascript-wDzz0qaB.js +0 -1
  172. package/dist/client/assets/jinja-4LBKfQ-Z.js +0 -1
  173. package/dist/client/assets/jison-wvAkD_A8.js +0 -1
  174. package/dist/client/assets/json-Cp-IABpG.js +0 -1
  175. package/dist/client/assets/json5-C9tS-k6U.js +0 -1
  176. package/dist/client/assets/jsonc-Des-eS-w.js +0 -1
  177. package/dist/client/assets/jsonl-DcaNXYhu.js +0 -1
  178. package/dist/client/assets/jsonnet-DFQXde-d.js +0 -1
  179. package/dist/client/assets/jssm-C2t-YnRu.js +0 -1
  180. package/dist/client/assets/jsx-g9-lgVsj.js +0 -1
  181. package/dist/client/assets/julia-CxzCAyBv.js +0 -1
  182. package/dist/client/assets/kanagawa-dragon-CkXjmgJE.js +0 -1
  183. package/dist/client/assets/kanagawa-lotus-CfQXZHmo.js +0 -1
  184. package/dist/client/assets/kanagawa-wave-DWedfzmr.js +0 -1
  185. package/dist/client/assets/kdl-DV7GczEv.js +0 -1
  186. package/dist/client/assets/keyboard-shortcuts-dialog-agsWJ36q.js +0 -1
  187. package/dist/client/assets/kotlin-BdnUsdx6.js +0 -1
  188. package/dist/client/assets/kusto-DZf3V79B.js +0 -1
  189. package/dist/client/assets/laserwave-DUszq2jm.js +0 -1
  190. package/dist/client/assets/latex-B4uzh10-.js +0 -1
  191. package/dist/client/assets/lean-BZvkOJ9d.js +0 -1
  192. package/dist/client/assets/less-B1dDrJ26.js +0 -1
  193. package/dist/client/assets/light-plus-B7mTdjB0.js +0 -1
  194. package/dist/client/assets/liquid-DYVedYrR.js +0 -1
  195. package/dist/client/assets/llvm-BtvRca6l.js +0 -1
  196. package/dist/client/assets/log-2UxHyX5q.js +0 -1
  197. package/dist/client/assets/logo-BtOb2qkB.js +0 -1
  198. package/dist/client/assets/lua-BbnMAYS6.js +0 -1
  199. package/dist/client/assets/luau-C-HG3fhB.js +0 -1
  200. package/dist/client/assets/make-CHLpvVh8.js +0 -1
  201. package/dist/client/assets/markdown-Cvjx9yec.js +0 -1
  202. package/dist/client/assets/marko-DZsq8hO1.js +0 -1
  203. package/dist/client/assets/material-theme-D5KoaKCx.js +0 -1
  204. package/dist/client/assets/material-theme-darker-BfHTSMKl.js +0 -1
  205. package/dist/client/assets/material-theme-lighter-B0m2ddpp.js +0 -1
  206. package/dist/client/assets/material-theme-ocean-CyktbL80.js +0 -1
  207. package/dist/client/assets/material-theme-palenight-Csfq5Kiy.js +0 -1
  208. package/dist/client/assets/matlab-D7o27uSR.js +0 -1
  209. package/dist/client/assets/mdc-DUICxH0z.js +0 -1
  210. package/dist/client/assets/mdx-Cmh6b_Ma.js +0 -1
  211. package/dist/client/assets/menu-BhVaz8Ly.js +0 -20
  212. package/dist/client/assets/mermaid-mWjccvbQ.js +0 -1
  213. package/dist/client/assets/min-dark-CafNBF8u.js +0 -1
  214. package/dist/client/assets/min-light-CTRr51gU.js +0 -1
  215. package/dist/client/assets/mipsasm-CKIfxQSi.js +0 -1
  216. package/dist/client/assets/mojo-B93PlW-d.js +0 -1
  217. package/dist/client/assets/monokai-D4h5O-jR.js +0 -1
  218. package/dist/client/assets/moonbit-Ba13S78F.js +0 -1
  219. package/dist/client/assets/move-Bu9oaDYs.js +0 -1
  220. package/dist/client/assets/narrat-DRg8JJMk.js +0 -1
  221. package/dist/client/assets/nextflow-BrzmwbiE.js +0 -1
  222. package/dist/client/assets/nginx-DknmC5AR.js +0 -1
  223. package/dist/client/assets/night-owl-C39BiMTA.js +0 -1
  224. package/dist/client/assets/nim-CVrawwO9.js +0 -1
  225. package/dist/client/assets/nix-CwoSXNpI.js +0 -1
  226. package/dist/client/assets/nord-Ddv68eIx.js +0 -1
  227. package/dist/client/assets/nushell-C-sUppwS.js +0 -1
  228. package/dist/client/assets/objective-c-DXmwc3jG.js +0 -1
  229. package/dist/client/assets/objective-cpp-CLxacb5B.js +0 -1
  230. package/dist/client/assets/ocaml-C0hk2d4L.js +0 -1
  231. package/dist/client/assets/one-dark-pro-DVMEJ2y_.js +0 -1
  232. package/dist/client/assets/one-light-PoHY5YXO.js +0 -1
  233. package/dist/client/assets/openscad-C4EeE6gA.js +0 -1
  234. package/dist/client/assets/pascal-D93ZcfNL.js +0 -1
  235. package/dist/client/assets/perl-C0TMdlhV.js +0 -1
  236. package/dist/client/assets/php-CDn_0X-4.js +0 -1
  237. package/dist/client/assets/pkl-u5AG7uiY.js +0 -1
  238. package/dist/client/assets/plastic-3e1v2bzS.js +0 -1
  239. package/dist/client/assets/plsql-ChMvpjG-.js +0 -1
  240. package/dist/client/assets/po-BTJTHyun.js +0 -1
  241. package/dist/client/assets/poimandres-CS3Unz2-.js +0 -1
  242. package/dist/client/assets/polar-C0HS_06l.js +0 -1
  243. package/dist/client/assets/postcss-CXtECtnM.js +0 -1
  244. package/dist/client/assets/powerquery-CEu0bR-o.js +0 -1
  245. package/dist/client/assets/powershell-Dpen1YoG.js +0 -1
  246. package/dist/client/assets/prisma-Dd19v3D-.js +0 -1
  247. package/dist/client/assets/prolog-CbFg5uaA.js +0 -1
  248. package/dist/client/assets/proto-C7zT0LnQ.js +0 -1
  249. package/dist/client/assets/pug-CGlum2m_.js +0 -1
  250. package/dist/client/assets/puppet-BMWR74SV.js +0 -1
  251. package/dist/client/assets/purescript-CklMAg4u.js +0 -1
  252. package/dist/client/assets/python-B6aJPvgy.js +0 -1
  253. package/dist/client/assets/qml-3beO22l8.js +0 -1
  254. package/dist/client/assets/qmldir-C8lEn-DE.js +0 -1
  255. package/dist/client/assets/qss-IeuSbFQv.js +0 -1
  256. package/dist/client/assets/r-Dspwwk_N.js +0 -1
  257. package/dist/client/assets/racket-BqYA7rlc.js +0 -1
  258. package/dist/client/assets/raku-DXvB9xmW.js +0 -1
  259. package/dist/client/assets/razor-C1TweQQi.js +0 -1
  260. package/dist/client/assets/red-bN70gL4F.js +0 -1
  261. package/dist/client/assets/reg-C-SQnVFl.js +0 -1
  262. package/dist/client/assets/regexp-CDVJQ6XC.js +0 -1
  263. package/dist/client/assets/rel-C3B-1QV4.js +0 -1
  264. package/dist/client/assets/riscv-BM1_JUlF.js +0 -1
  265. package/dist/client/assets/rose-pine-dawn-DHQR4-dF.js +0 -1
  266. package/dist/client/assets/rose-pine-moon-D4_iv3hh.js +0 -1
  267. package/dist/client/assets/rose-pine-qdsjHGoJ.js +0 -1
  268. package/dist/client/assets/rosmsg-BJDFO7_C.js +0 -1
  269. package/dist/client/assets/rst-B0xPkSld.js +0 -1
  270. package/dist/client/assets/ruby-BvKwtOVI.js +0 -1
  271. package/dist/client/assets/rust-B1yitclQ.js +0 -1
  272. package/dist/client/assets/sas-cz2c8ADy.js +0 -1
  273. package/dist/client/assets/sass-Cj5Yp3dK.js +0 -1
  274. package/dist/client/assets/scala-C151Ov-r.js +0 -1
  275. package/dist/client/assets/scheme-C98Dy4si.js +0 -1
  276. package/dist/client/assets/scss-OYdSNvt2.js +0 -1
  277. package/dist/client/assets/sdbl-DVxCFoDh.js +0 -1
  278. package/dist/client/assets/search-dialog-CHwnOyPS.js +0 -1
  279. package/dist/client/assets/session-export-dialog-uOlDUzgX.js +0 -1
  280. package/dist/client/assets/settings-dialog-D0aYDkAM.js +0 -1
  281. package/dist/client/assets/shaderlab-Dg9Lc6iA.js +0 -1
  282. package/dist/client/assets/shellscript-Yzrsuije.js +0 -1
  283. package/dist/client/assets/shellsession-BADoaaVG.js +0 -1
  284. package/dist/client/assets/slack-dark-BthQWCQV.js +0 -1
  285. package/dist/client/assets/slack-ochin-DqwNpetd.js +0 -1
  286. package/dist/client/assets/smalltalk-BERRCDM3.js +0 -1
  287. package/dist/client/assets/snazzy-light-Bw305WKR.js +0 -1
  288. package/dist/client/assets/solarized-dark-DXbdFlpD.js +0 -1
  289. package/dist/client/assets/solarized-light-L9t79GZl.js +0 -1
  290. package/dist/client/assets/solidity-rGO070M0.js +0 -1
  291. package/dist/client/assets/soy-Brmx7dQM.js +0 -1
  292. package/dist/client/assets/sparql-rVzFXLq3.js +0 -1
  293. package/dist/client/assets/splunk-BtCnVYZw.js +0 -1
  294. package/dist/client/assets/sql-BLtJtn59.js +0 -1
  295. package/dist/client/assets/ssh-config-_ykCGR6B.js +0 -1
  296. package/dist/client/assets/stata-BH5u7GGu.js +0 -1
  297. package/dist/client/assets/styles-7aVSlb6l.css +0 -1
  298. package/dist/client/assets/stylus-BEDo0Tqx.js +0 -1
  299. package/dist/client/assets/svelte-zxCyuUbr.js +0 -1
  300. package/dist/client/assets/swift-Dg5xB15N.js +0 -1
  301. package/dist/client/assets/synthwave-84-CbfX1IO0.js +0 -1
  302. package/dist/client/assets/system-verilog-CnnmHF94.js +0 -1
  303. package/dist/client/assets/systemd-4A_iFExJ.js +0 -1
  304. package/dist/client/assets/talonscript-CkByrt1z.js +0 -1
  305. package/dist/client/assets/tasl-QIJgUcNo.js +0 -1
  306. package/dist/client/assets/tcl-dwOrl1Do.js +0 -1
  307. package/dist/client/assets/templ-W15q3VgB.js +0 -1
  308. package/dist/client/assets/terraform-BETggiCN.js +0 -1
  309. package/dist/client/assets/tex-CvyZ59Mk.js +0 -1
  310. package/dist/client/assets/tokyo-night-hegEt444.js +0 -1
  311. package/dist/client/assets/toml-vGWfd6FD.js +0 -1
  312. package/dist/client/assets/ts-tags-zn1MmPIZ.js +0 -1
  313. package/dist/client/assets/tsv-B_m7g4N7.js +0 -1
  314. package/dist/client/assets/tsx-COt5Ahok.js +0 -1
  315. package/dist/client/assets/turtle-BsS91CYL.js +0 -1
  316. package/dist/client/assets/twig-CO9l9SDP.js +0 -1
  317. package/dist/client/assets/typescript-BPQ3VLAy.js +0 -1
  318. package/dist/client/assets/typespec-BGHnOYBU.js +0 -1
  319. package/dist/client/assets/typst-DHCkPAjA.js +0 -1
  320. package/dist/client/assets/v-BcVCzyr7.js +0 -1
  321. package/dist/client/assets/vala-CsfeWuGM.js +0 -1
  322. package/dist/client/assets/vb-D17OF-Vu.js +0 -1
  323. package/dist/client/assets/verilog-BQ8w6xss.js +0 -1
  324. package/dist/client/assets/vesper-DU1UobuO.js +0 -1
  325. package/dist/client/assets/vhdl-CeAyd5Ju.js +0 -1
  326. package/dist/client/assets/viml-CJc9bBzg.js +0 -1
  327. package/dist/client/assets/vitesse-black-Bkuqu6BP.js +0 -1
  328. package/dist/client/assets/vitesse-dark-D0r3Knsf.js +0 -1
  329. package/dist/client/assets/vitesse-light-CVO1_9PV.js +0 -1
  330. package/dist/client/assets/vue-DN_0RTcg.js +0 -1
  331. package/dist/client/assets/vue-html-AaS7Mt5G.js +0 -1
  332. package/dist/client/assets/vue-vine-CQOfvN7w.js +0 -1
  333. package/dist/client/assets/vyper-CDx5xZoG.js +0 -1
  334. package/dist/client/assets/wasm-CG6Dc4jp.js +0 -1
  335. package/dist/client/assets/wasm-MzD3tlZU.js +0 -1
  336. package/dist/client/assets/wenyan-BV7otONQ.js +0 -1
  337. package/dist/client/assets/wgsl-Dx-B1_4e.js +0 -1
  338. package/dist/client/assets/wikitext-BhOHFoWU.js +0 -1
  339. package/dist/client/assets/wit-5i3qLPDT.js +0 -1
  340. package/dist/client/assets/wolfram-lXgVvXCa.js +0 -1
  341. package/dist/client/assets/xml-sdJ4AIDG.js +0 -1
  342. package/dist/client/assets/xsl-CtQFsRM5.js +0 -1
  343. package/dist/client/assets/yaml-Buea-lGh.js +0 -1
  344. package/dist/client/assets/zenscript-DVFEvuxE.js +0 -1
  345. package/dist/client/assets/zig-VOosw3JB.js +0 -1
  346. package/dist/server/assets/_tanstack-start-manifest_v-El8F-kd-.js +0 -4
package/README.md CHANGED
@@ -27,22 +27,33 @@ That's it. Opens your browser to the chat interface.
27
27
 
28
28
  | Flag | Description | Default |
29
29
  |------|-------------|---------|
30
- | `--port` | Port to serve on | `3001` |
30
+ | `--port` | Port to serve on | `3000` |
31
31
  | `--gateway` | OpenClaw gateway URL | `ws://127.0.0.1:18789` |
32
32
  | `--host` | Bind address | `localhost` |
33
33
  | `--no-open` | Don't open browser | — |
34
34
 
35
+ ### Docker
36
+
37
+ ```bash
38
+ docker build -t opencami .
39
+ docker run -p 3000:3000 opencami
40
+ ```
41
+
35
42
  ## Features
36
43
 
37
44
  ⚡ **Real-time streaming** — persistent WebSocket + SSE, token-by-token\
38
45
  🔍 **Conversation search** — current session (⌘F) and global (⌘⇧F)\
39
- 🔊 **Voice playback** — ElevenLabs → OpenAI → Edge TTS fallback chain\
46
+ 🔊 **Voice playback (TTS)** — ElevenLabs → OpenAI → Edge TTS fallback chain\
47
+ 🎤 **Voice input (STT)** — ElevenLabs Scribe → OpenAI Whisper → Browser Web Speech API\
48
+ 🔧 **TTS/STT provider selection** — choose provider and voice in Settings\
40
49
  📂 **File explorer** — 30+ file types, built-in editor, path jailing\
41
50
  🎭 **Persona picker** — 20 personas, integrated with the personas skill\
51
+ 🤖 **Agent manager** — sidebar panel for managing agents\
42
52
  🎨 **Model selector** — switch models on the fly\
43
53
  🏷️ **Smart titles** — LLM-generated session titles\
44
54
  💡 **Smart follow-ups** — contextual suggestions after each response\
45
55
  🖼️ **Image attachments** — with compression for the 512KB WS limit\
56
+ 🔎 **Search sources badge** — expandable badge with favicons for search results\
46
57
  📁 **Session folders** — grouped by kind (chats, subagents, cron, other)\
47
58
  📌 **Pin sessions** — pinned always on top\
48
59
  📥 **Export** — Markdown, JSON, or plain text\
@@ -62,13 +73,17 @@ cp .env.example .env.local
62
73
  npm run dev
63
74
  ```
64
75
 
76
+ Then open the URL printed by Vite in your terminal.
77
+
78
+ > Dev port notes: this repo's `npm run dev` script uses port `3002`. If you run Vite directly with the config default, it targets `3003` and auto-falls back to the next free port.
79
+
65
80
  ## Documentation
66
81
 
67
82
  - [Features](docs/features.md)
68
83
  - [Architecture](docs/architecture.md)
69
84
  - [Deployment](docs/deployment.md)
70
85
  - [Contributing](docs/contributing.md)
71
- - [Changelog](docs/changelog.md)
86
+ - [Changelog](CHANGELOG.md)
72
87
 
73
88
  ## Credits
74
89
 
@@ -76,6 +91,8 @@ Built on top of [WebClaw](https://github.com/ibelick/webclaw) by [@ibelick](http
76
91
 
77
92
  File Explorer by [@balin-ar](https://github.com/balin-ar) ([PR #2](https://github.com/ibelick/webclaw/pull/2)).
78
93
 
94
+ Dockerfile by [@deblanco](https://github.com/deblanco) ([PR #7](https://github.com/ibelick/webclaw/pull/7)).
95
+
79
96
  Powered by [OpenClaw](https://github.com/openclaw/openclaw).
80
97
 
81
98
  ## Links
@@ -0,0 +1,509 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>OpenCami Analytics 🦎</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;700&family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet">
8
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
9
+ <style>
10
+ :root {
11
+ --bg-primary: #0a0a0f;
12
+ --bg-card: #12121a;
13
+ --bg-card-hover: #181824;
14
+ --bg-row-hover: #1a1a28;
15
+ --border: #1e1e2e;
16
+ --text-primary: #e8e8ed;
17
+ --text-secondary: #6b6b7b;
18
+ --text-muted: #3a3a4a;
19
+ --accent-cyan: #00e5ff;
20
+ --accent-amber: #ffab00;
21
+ --accent-emerald: #00e676;
22
+ --accent-rose: #ff5272;
23
+ --accent-violet: #b388ff;
24
+ --accent-blue: #40c4ff;
25
+ --accent-orange: #ff9100;
26
+ --font-sans: 'Outfit', sans-serif;
27
+ --font-mono: 'JetBrains Mono', monospace;
28
+ }
29
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
30
+ body {
31
+ background: var(--bg-primary);
32
+ color: var(--text-primary);
33
+ font-family: var(--font-sans);
34
+ line-height: 1.5;
35
+ min-height: 100vh;
36
+ overflow-x: hidden;
37
+ }
38
+ .container { max-width: 1480px; margin: 0 auto; padding: 1.5rem; }
39
+
40
+ .header {
41
+ display: flex; justify-content: space-between; align-items: baseline;
42
+ margin-bottom: 2rem; padding-bottom: 1rem;
43
+ border-bottom: 1px solid var(--border);
44
+ }
45
+ .header h1 { font-size: 1.5rem; font-weight: 600; letter-spacing: -0.02em; }
46
+ .header h1 span { color: var(--accent-cyan); }
47
+ .header .meta { text-align: right; }
48
+ .header .updated { font-family: var(--font-mono); font-size: 0.7rem; color: var(--text-secondary); }
49
+ .header .date-range { font-size: 0.8rem; color: var(--text-secondary); margin-top: 0.15rem; }
50
+
51
+ /* Hero Stats - 5 cards */
52
+ .hero-stats {
53
+ display: grid; grid-template-columns: repeat(5, 1fr); gap: 0.75rem;
54
+ margin-bottom: 1.5rem;
55
+ }
56
+ .stat-card {
57
+ background: var(--bg-card); border: 1px solid var(--border);
58
+ border-radius: 10px; padding: 1.2rem 1rem;
59
+ position: relative; overflow: hidden;
60
+ opacity: 0; transform: translateY(12px);
61
+ animation: cardIn 0.4s ease forwards;
62
+ }
63
+ .stat-card::before {
64
+ content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
65
+ }
66
+ .stat-card:nth-child(1)::before { background: var(--accent-cyan); }
67
+ .stat-card:nth-child(2)::before { background: var(--accent-amber); }
68
+ .stat-card:nth-child(3)::before { background: var(--accent-emerald); }
69
+ .stat-card:nth-child(4)::before { background: var(--accent-rose); }
70
+ .stat-card:nth-child(5)::before { background: var(--accent-violet); }
71
+ .stat-card:nth-child(1) { animation-delay: 0s; }
72
+ .stat-card:nth-child(2) { animation-delay: 0.05s; }
73
+ .stat-card:nth-child(3) { animation-delay: 0.1s; }
74
+ .stat-card:nth-child(4) { animation-delay: 0.15s; }
75
+ .stat-card:nth-child(5) { animation-delay: 0.2s; }
76
+ .stat-card .label {
77
+ font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.1em;
78
+ color: var(--text-secondary); margin-bottom: 0.4rem; font-weight: 500;
79
+ }
80
+ .stat-card .value {
81
+ font-family: var(--font-mono); font-size: 1.8rem; font-weight: 700;
82
+ letter-spacing: -0.03em;
83
+ }
84
+ .stat-card:nth-child(1) .value { color: var(--accent-cyan); }
85
+ .stat-card:nth-child(2) .value { color: var(--accent-amber); }
86
+ .stat-card:nth-child(3) .value { color: var(--accent-emerald); }
87
+ .stat-card:nth-child(4) .value { color: var(--accent-rose); }
88
+ .stat-card:nth-child(5) .value { color: var(--accent-violet); }
89
+
90
+ /* Dashboard grid */
91
+ .dashboard-grid {
92
+ display: grid;
93
+ grid-template-columns: 1fr 1fr;
94
+ gap: 0.75rem;
95
+ }
96
+ .card {
97
+ background: var(--bg-card); border: 1px solid var(--border);
98
+ border-radius: 10px; padding: 1.25rem;
99
+ opacity: 0; transform: translateY(12px);
100
+ animation: cardIn 0.4s ease forwards;
101
+ }
102
+ .card.wide { grid-column: 1 / -1; }
103
+ .card h2 {
104
+ font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.12em;
105
+ color: var(--text-secondary); margin-bottom: 1rem; font-weight: 500;
106
+ display: flex; align-items: center; gap: 0.5rem;
107
+ }
108
+ .card h2 .badge {
109
+ font-family: var(--font-mono); font-size: 0.6rem; background: rgba(0,229,255,0.1);
110
+ color: var(--accent-cyan); padding: 0.15rem 0.5rem; border-radius: 4px;
111
+ text-transform: none; letter-spacing: 0;
112
+ }
113
+ .card canvas { max-height: 260px; }
114
+
115
+ /* Model table */
116
+ .model-table { width: 100%; border-collapse: collapse; font-size: 0.78rem; }
117
+ .model-table th {
118
+ text-align: left; font-size: 0.6rem; text-transform: uppercase;
119
+ letter-spacing: 0.08em; color: var(--text-muted); font-weight: 500;
120
+ padding: 0.5rem 0.6rem; border-bottom: 1px solid var(--border);
121
+ }
122
+ .model-table th.right, .model-table td.right { text-align: right; }
123
+ .model-table td {
124
+ padding: 0.55rem 0.6rem; border-bottom: 1px solid rgba(30,30,46,0.5);
125
+ font-family: var(--font-mono); font-size: 0.72rem;
126
+ }
127
+ .model-table tr:hover td { background: var(--bg-row-hover); }
128
+ .model-table .model-name { color: var(--accent-cyan); font-weight: 500; }
129
+ .model-table .provider-badge {
130
+ font-size: 0.58rem; padding: 0.12rem 0.4rem; border-radius: 3px;
131
+ font-family: var(--font-sans); font-weight: 500; display: inline-block;
132
+ }
133
+ .provider-anthropic { background: rgba(179,136,255,0.15); color: var(--accent-violet); }
134
+ .provider-openai-codex { background: rgba(0,230,118,0.12); color: var(--accent-emerald); }
135
+ .provider-openrouter { background: rgba(255,145,0,0.12); color: var(--accent-orange); }
136
+ .provider-synthetic, .provider-synthetic-openai { background: rgba(64,196,255,0.12); color: var(--accent-blue); }
137
+ .provider-openclaw { background: rgba(255,82,114,0.12); color: var(--accent-rose); }
138
+ .provider-unknown { background: rgba(58,58,74,0.3); color: var(--text-secondary); }
139
+ .model-table .bar-cell { width: 30%; }
140
+ .model-table .bar-bg {
141
+ height: 6px; background: rgba(255,255,255,0.04); border-radius: 3px;
142
+ overflow: hidden; position: relative;
143
+ }
144
+ .model-table .bar-fill {
145
+ height: 100%; border-radius: 3px; transition: width 0.8s ease;
146
+ }
147
+ .token-dim { color: var(--text-secondary); }
148
+
149
+ /* Provider cards */
150
+ .providers-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0.6rem; }
151
+ .provider-card {
152
+ background: var(--bg-primary); border: 1px solid var(--border);
153
+ border-radius: 8px; padding: 0.9rem;
154
+ }
155
+ .provider-card .prov-name {
156
+ font-family: var(--font-mono); font-size: 0.8rem; font-weight: 500;
157
+ margin-bottom: 0.4rem;
158
+ }
159
+ .provider-card .prov-stat {
160
+ font-size: 0.65rem; color: var(--text-secondary); line-height: 1.9;
161
+ }
162
+ .provider-card .prov-stat strong {
163
+ font-family: var(--font-mono); color: var(--text-primary); font-weight: 400;
164
+ }
165
+
166
+ /* Agent cards */
167
+ .agents-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 0.6rem; }
168
+ .agent-item {
169
+ background: var(--bg-primary); border: 1px solid var(--border);
170
+ border-radius: 8px; padding: 0.9rem;
171
+ }
172
+ .agent-item .agent-name {
173
+ font-family: var(--font-mono); font-size: 0.8rem; font-weight: 500;
174
+ color: var(--accent-cyan); margin-bottom: 0.35rem;
175
+ }
176
+ .agent-item .agent-stat {
177
+ font-size: 0.65rem; color: var(--text-secondary); line-height: 1.9;
178
+ }
179
+ .agent-item .agent-stat strong {
180
+ font-family: var(--font-mono); color: var(--text-primary); font-weight: 400;
181
+ }
182
+
183
+ .footer {
184
+ text-align: center; padding: 1.5rem 0 0.5rem;
185
+ font-size: 0.7rem; color: var(--text-muted);
186
+ font-family: var(--font-mono);
187
+ }
188
+
189
+ @keyframes cardIn { to { opacity: 1; transform: translateY(0); } }
190
+
191
+ @media (max-width: 900px) {
192
+ .hero-stats { grid-template-columns: repeat(3, 1fr); }
193
+ .dashboard-grid { grid-template-columns: 1fr; }
194
+ .stat-card .value { font-size: 1.4rem; }
195
+ .header { flex-direction: column; gap: 0.5rem; }
196
+ }
197
+ @media (max-width: 600px) {
198
+ .hero-stats { grid-template-columns: repeat(2, 1fr); }
199
+ .model-table { font-size: 0.65rem; }
200
+ }
201
+ </style>
202
+ </head>
203
+ <body>
204
+ <div class="container">
205
+ <div class="header">
206
+ <div>
207
+ <h1><span>OpenCami</span> Analytics 🦎</h1>
208
+ <div class="date-range" id="dateRange"></div>
209
+ </div>
210
+ <div class="meta">
211
+ <div class="updated" id="updatedAt"></div>
212
+ </div>
213
+ </div>
214
+
215
+ <div class="hero-stats">
216
+ <div class="stat-card"><div class="label">Total Tokens</div><div class="value" id="totalTokens">—</div></div>
217
+ <div class="stat-card"><div class="label">Messages</div><div class="value" id="totalMessages">—</div></div>
218
+ <div class="stat-card"><div class="label">Sessions</div><div class="value" id="totalSessions">—</div></div>
219
+ <div class="stat-card"><div class="label">Models</div><div class="value" id="totalModels">—</div></div>
220
+ <div class="stat-card"><div class="label">Agents</div><div class="value" id="totalAgents">—</div></div>
221
+ </div>
222
+
223
+ <div class="dashboard-grid">
224
+ <!-- Daily tokens -->
225
+ <div class="card wide" style="animation-delay:0.25s">
226
+ <h2>Daily Token Usage</h2>
227
+ <canvas id="dailyChart"></canvas>
228
+ </div>
229
+
230
+ <!-- By Model - THE BIG ONE -->
231
+ <div class="card wide" style="animation-delay:0.3s">
232
+ <h2>Token Usage by Model <span class="badge" id="modelCount"></span></h2>
233
+ <div style="overflow-x:auto">
234
+ <table class="model-table" id="modelTable">
235
+ <thead>
236
+ <tr>
237
+ <th>Model</th>
238
+ <th>Provider</th>
239
+ <th class="right">Total Tokens</th>
240
+ <th class="right">Messages</th>
241
+ <th class="right">Tokens/Msg</th>
242
+ <th class="bar-cell">Share</th>
243
+ </tr>
244
+ </thead>
245
+ <tbody id="modelBody"></tbody>
246
+ </table>
247
+ </div>
248
+ </div>
249
+
250
+ <!-- By Provider -->
251
+ <div class="card" style="animation-delay:0.35s">
252
+ <h2>By Provider</h2>
253
+ <div class="providers-grid" id="providersGrid"></div>
254
+ </div>
255
+
256
+ <!-- Token Breakdown -->
257
+ <div class="card" style="animation-delay:0.38s">
258
+ <h2>Token Breakdown</h2>
259
+ <canvas id="tokenBreakdownChart"></canvas>
260
+ </div>
261
+
262
+ <!-- Activity by Hour -->
263
+ <div class="card" style="animation-delay:0.42s">
264
+ <h2>Activity by Hour <span class="badge">UTC</span></h2>
265
+ <canvas id="hourChart"></canvas>
266
+ </div>
267
+
268
+ <!-- Top Tools -->
269
+ <div class="card" style="animation-delay:0.45s">
270
+ <h2>Top Tools <span class="badge" id="toolCount"></span></h2>
271
+ <canvas id="toolsChart"></canvas>
272
+ </div>
273
+
274
+ <!-- Agents -->
275
+ <div class="card wide" style="animation-delay:0.5s">
276
+ <h2>By Agent</h2>
277
+ <div class="agents-grid" id="agentsGrid"></div>
278
+ </div>
279
+ </div>
280
+
281
+ <div class="footer">🦎 OpenCami Analytics — tokens only, no dollars</div>
282
+ </div>
283
+
284
+ <script>
285
+ const SAMPLE = {
286
+ generatedAt: "2026-02-09T09:00:00Z",
287
+ daily: Array.from({length:25},(_,i)=>{
288
+ const d=new Date(2026,0,16+i);
289
+ return {date:d.toISOString().slice(0,10),totalTokens:Math.round(15e6+Math.random()*85e6),sessions:Math.round(3+Math.random()*20),messages:Math.round(300+Math.random()*2000)};
290
+ }),
291
+ byModel:[
292
+ {model:"claude-opus-4-5",provider:"anthropic",totalTokens:1406133099,messages:14400},
293
+ {model:"claude-sonnet-4-5",provider:"anthropic",totalTokens:426049002,messages:5858},
294
+ {model:"claude-opus-4-6",provider:"anthropic",totalTokens:424354704,messages:3950},
295
+ {model:"gpt-5.2",provider:"openai-codex",totalTokens:71158180,messages:1162},
296
+ {model:"claude-haiku-4-5",provider:"anthropic",totalTokens:36245539,messages:1036},
297
+ ],
298
+ byAgent:[
299
+ {agent:"main",totalTokens:2407067242,sessions:734,messages:37580},
300
+ {agent:"codex",totalTokens:16342194,sessions:3,messages:251},
301
+ ],
302
+ byHour: Array.from({length:24},(_,h)=>({hour:h,messages:Math.round(100+Math.random()*2900)})),
303
+ topTools:[{tool:"exec",count:9826},{tool:"read",count:2357},{tool:"process",count:1910},{tool:"bash",count:1572},{tool:"edit",count:1203}],
304
+ totals:{tokens:2439095843,sessions:760,messages:38564,dateRange:"2026-01-16 to 2026-02-09"}
305
+ };
306
+
307
+ Chart.defaults.color = '#6b6b7b';
308
+ Chart.defaults.font.family = "'JetBrains Mono', monospace";
309
+ Chart.defaults.font.size = 10;
310
+ Chart.defaults.plugins.legend.display = false;
311
+ Chart.defaults.scale.grid = { color: 'rgba(255,255,255,0.04)', drawBorder: false };
312
+
313
+ function fmtNum(n) {
314
+ if (n >= 1e9) return (n/1e9).toFixed(1) + 'B';
315
+ if (n >= 1e6) return (n/1e6).toFixed(1) + 'M';
316
+ if (n >= 1e3) return (n/1e3).toFixed(1) + 'K';
317
+ return n.toString();
318
+ }
319
+
320
+ function fmtNumPrecise(n) {
321
+ if (n >= 1e9) return (n/1e9).toFixed(2) + 'B';
322
+ if (n >= 1e6) return (n/1e6).toFixed(1) + 'M';
323
+ if (n >= 1e3) return (n/1e3).toFixed(1) + 'K';
324
+ return n.toLocaleString();
325
+ }
326
+
327
+ function fmtComma(n) { return Math.round(n).toLocaleString(); }
328
+
329
+ const providerColors = {
330
+ anthropic: '#b388ff',
331
+ 'openai-codex': '#00e676',
332
+ openrouter: '#ff9100',
333
+ synthetic: '#40c4ff',
334
+ 'synthetic-openai': '#40c4ff',
335
+ openclaw: '#ff5272',
336
+ unknown: '#3a3a4a'
337
+ };
338
+
339
+ const modelBarColors = ['#00e5ff','#b388ff','#ffab00','#00e676','#ff5272','#40c4ff','#ff9100','#e040fb','#69f0ae','#ffd740','#ff6e40','#448aff'];
340
+
341
+ function render(data) {
342
+ document.getElementById('updatedAt').textContent = 'Updated ' + new Date(data.generatedAt).toLocaleString();
343
+ document.getElementById('dateRange').textContent = data.totals.dateRange;
344
+
345
+ // Hero stats
346
+ const realModels = data.byModel.filter(m => m.model !== 'unknown' && m.model !== 'delivery-mirror');
347
+ document.getElementById('totalTokens').textContent = fmtNum(data.totals.tokens);
348
+ document.getElementById('totalMessages').textContent = fmtNum(data.totals.messages);
349
+ document.getElementById('totalSessions').textContent = fmtComma(data.totals.sessions);
350
+ document.getElementById('totalModels').textContent = realModels.length;
351
+ document.getElementById('totalAgents').textContent = data.byAgent.length;
352
+
353
+ // Daily tokens chart
354
+ new Chart(document.getElementById('dailyChart'), {
355
+ type: 'line',
356
+ data: {
357
+ labels: data.daily.map(d => d.date.slice(5)),
358
+ datasets: [{
359
+ data: data.daily.map(d => d.totalTokens),
360
+ borderColor: '#00e5ff',
361
+ backgroundColor: 'rgba(0,229,255,0.06)',
362
+ fill: true, tension: 0.3, pointRadius: 2.5, pointHoverRadius: 6,
363
+ borderWidth: 2, pointBackgroundColor: '#00e5ff'
364
+ }]
365
+ },
366
+ options: {
367
+ scales: {
368
+ y: { ticks: { callback: v => fmtNum(v) } }
369
+ },
370
+ plugins: {
371
+ tooltip: {
372
+ callbacks: {
373
+ label: c => fmtComma(c.raw) + ' tokens',
374
+ title: t => t[0].label
375
+ }
376
+ }
377
+ }
378
+ }
379
+ });
380
+
381
+ // Model table
382
+ const models = [...data.byModel]
383
+ .filter(m => m.totalTokens > 0 || (m.messages > 0 && m.model !== 'unknown'))
384
+ .sort((a, b) => b.totalTokens - a.totalTokens);
385
+ const maxTokens = models[0]?.totalTokens || 1;
386
+ const tbody = document.getElementById('modelBody');
387
+ document.getElementById('modelCount').textContent = models.length + ' models';
388
+
389
+ models.forEach((m, i) => {
390
+ const pct = (m.totalTokens / maxTokens * 100).toFixed(1);
391
+ const tpm = m.messages > 0 ? Math.round(m.totalTokens / m.messages) : 0;
392
+ const provClass = 'provider-' + (m.provider || 'unknown').replace(/[^a-z-]/g, '');
393
+ const color = modelBarColors[i % modelBarColors.length];
394
+ const tr = document.createElement('tr');
395
+ tr.innerHTML = `
396
+ <td class="model-name">${m.model}</td>
397
+ <td><span class="provider-badge ${provClass}">${m.provider}</span></td>
398
+ <td class="right">${fmtNumPrecise(m.totalTokens)}</td>
399
+ <td class="right">${fmtComma(m.messages)}</td>
400
+ <td class="right"><span class="token-dim">${fmtNum(tpm)}</span></td>
401
+ <td class="bar-cell"><div class="bar-bg"><div class="bar-fill" style="width:${pct}%;background:${color}"></div></div></td>
402
+ `;
403
+ tbody.appendChild(tr);
404
+ });
405
+
406
+ // By Provider - aggregate
407
+ const provMap = {};
408
+ data.byModel.forEach(m => {
409
+ const p = m.provider || 'unknown';
410
+ if (!provMap[p]) provMap[p] = { tokens: 0, messages: 0, models: [] };
411
+ provMap[p].tokens += m.totalTokens;
412
+ provMap[p].messages += m.messages;
413
+ if (m.model !== 'unknown' && m.model !== 'delivery-mirror') provMap[p].models.push(m.model);
414
+ });
415
+ const providers = Object.entries(provMap).sort((a, b) => b[1].tokens - a[1].tokens);
416
+ const provGrid = document.getElementById('providersGrid');
417
+ providers.forEach(([name, p]) => {
418
+ const color = providerColors[name] || '#6b6b7b';
419
+ provGrid.innerHTML += `<div class="provider-card">
420
+ <div class="prov-name" style="color:${color}">${name}</div>
421
+ <div class="prov-stat">Tokens <strong>${fmtNumPrecise(p.tokens)}</strong></div>
422
+ <div class="prov-stat">Messages <strong>${fmtComma(p.messages)}</strong></div>
423
+ <div class="prov-stat">Models <strong>${p.models.length}</strong></div>
424
+ </div>`;
425
+ });
426
+
427
+ // Token Breakdown donut - use overall split estimate from model data
428
+ // Since we don't have per-token-type data, show total tokens distribution by model category
429
+ // Actually let's do a by-provider donut
430
+ new Chart(document.getElementById('tokenBreakdownChart'), {
431
+ type: 'doughnut',
432
+ data: {
433
+ labels: providers.map(([n]) => n),
434
+ datasets: [{
435
+ data: providers.map(([, p]) => p.tokens),
436
+ backgroundColor: providers.map(([n]) => providerColors[n] || '#3a3a4a'),
437
+ borderWidth: 0,
438
+ spacing: 2
439
+ }]
440
+ },
441
+ options: {
442
+ cutout: '65%',
443
+ plugins: {
444
+ legend: { display: true, position: 'right', labels: { font: { size: 10 }, padding: 8, boxWidth: 12 } },
445
+ tooltip: { callbacks: { label: c => c.label + ': ' + fmtNumPrecise(c.raw) + ' tokens' } }
446
+ }
447
+ }
448
+ });
449
+
450
+ // Activity by hour
451
+ const maxH = Math.max(...data.byHour.map(x => x.messages));
452
+ new Chart(document.getElementById('hourChart'), {
453
+ type: 'bar',
454
+ data: {
455
+ labels: data.byHour.map(h => h.hour.toString().padStart(2, '0')),
456
+ datasets: [{
457
+ data: data.byHour.map(h => h.messages),
458
+ backgroundColor: data.byHour.map(h => {
459
+ const t = h.messages / maxH;
460
+ return `rgba(0,229,255,${0.12 + t * 0.88})`;
461
+ }),
462
+ borderRadius: 3, barThickness: 14
463
+ }]
464
+ },
465
+ options: {
466
+ scales: {
467
+ x: { ticks: { maxRotation: 0 } },
468
+ y: { ticks: { callback: v => fmtNum(v) } }
469
+ },
470
+ plugins: { tooltip: { callbacks: { label: c => fmtComma(c.raw) + ' messages' } } }
471
+ }
472
+ });
473
+
474
+ // Tools
475
+ const tools = data.topTools.slice(0, 15);
476
+ document.getElementById('toolCount').textContent = data.topTools.length + ' tools';
477
+ new Chart(document.getElementById('toolsChart'), {
478
+ type: 'bar',
479
+ data: {
480
+ labels: tools.map(t => t.tool),
481
+ datasets: [{
482
+ data: tools.map(t => t.count),
483
+ backgroundColor: 'rgba(255,171,0,0.65)',
484
+ borderRadius: 3, barThickness: 14
485
+ }]
486
+ },
487
+ options: {
488
+ indexAxis: 'y',
489
+ plugins: { tooltip: { callbacks: { label: c => fmtComma(c.raw) + ' calls' } } }
490
+ }
491
+ });
492
+
493
+ // Agents
494
+ const agents = [...data.byAgent].sort((a, b) => b.totalTokens - a.totalTokens);
495
+ const agGrid = document.getElementById('agentsGrid');
496
+ agents.forEach(a => {
497
+ agGrid.innerHTML += `<div class="agent-item">
498
+ <div class="agent-name">${a.agent}</div>
499
+ <div class="agent-stat">Tokens <strong>${fmtNumPrecise(a.totalTokens)}</strong></div>
500
+ <div class="agent-stat">Messages <strong>${fmtComma(a.messages)}</strong></div>
501
+ <div class="agent-stat">Sessions <strong>${a.sessions}</strong></div>
502
+ </div>`;
503
+ });
504
+ }
505
+
506
+ fetch('analytics.json').then(r => r.json()).then(render).catch(() => render(SAMPLE));
507
+ </script>
508
+ </body>
509
+ </html>