@agenthippo-ai/agenthippo 0.1.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 (480) hide show
  1. package/LICENSE +21 -0
  2. package/bin/agenthippo.js +2 -0
  3. package/out/agentpack/github.js +547 -0
  4. package/out/agentpack/index.js +66 -0
  5. package/out/agentpack/install.js +297 -0
  6. package/out/agentpack/manager.js +441 -0
  7. package/out/agentpack/manifest.js +135 -0
  8. package/out/agentpack/paths.js +475 -0
  9. package/out/agentpack/publish.js +248 -0
  10. package/out/agentpack/stores.js +554 -0
  11. package/out/agentpack/types.js +5 -0
  12. package/out/analytics/dashboard/artifactManager.js +439 -0
  13. package/out/analytics/dashboard/fleetDisplayUtils.js +159 -0
  14. package/out/analytics/dashboard/fleetOrchestrator.js +142 -0
  15. package/out/analytics/dashboard/fleetRegistry.js +79 -0
  16. package/out/analytics/dashboard/fleetRowDefaults.js +87 -0
  17. package/out/analytics/dashboard/fleetScriptAdapter.js +146 -0
  18. package/out/analytics/dashboard/fleetStatusUtils.js +30 -0
  19. package/out/analytics/dashboard/fleetTitleUtils.js +68 -0
  20. package/out/analytics/dashboard/fleetTypes.js +29 -0
  21. package/out/analytics/dashboard/index.js +17 -0
  22. package/out/analytics/dashboard/indexingService.js +422 -0
  23. package/out/analytics/dashboard/localFleetAdapter.js +222 -0
  24. package/out/analytics/dashboard/performanceMonitor.js +76 -0
  25. package/out/analytics/dashboard/processManager.js +209 -0
  26. package/out/analytics/dashboard/provider.js +3885 -0
  27. package/out/analytics/dashboard/queryRunner.js +994 -0
  28. package/out/analytics/dashboard/refreshPolicy.js +16 -0
  29. package/out/analytics/dashboard/scheduledFleetFingerprint.js +22 -0
  30. package/out/analytics/dashboard/scheduledFleetStorage.js +241 -0
  31. package/out/analytics/dashboard/scheduledFleetUtils.js +22 -0
  32. package/out/analytics/dashboard/sessionEventFleetStats.js +118 -0
  33. package/out/analytics/dashboard/sessionJsonlFleet.js +204 -0
  34. package/out/analytics/dashboard/teamViewDiscovery.js +106 -0
  35. package/out/analytics/dashboard/viewsConfigMerge.js +221 -0
  36. package/out/analytics/dashboard/webview/analytics-panel.html +155 -0
  37. package/out/analytics/dashboard/webview/codicon.ttf +0 -0
  38. package/out/analytics/dashboard/webview/index.html +78 -0
  39. package/out/analytics/dashboard/webview/panel.js +2295 -0
  40. package/out/analytics/dashboard/webview/runtime-bridge.js +82 -0
  41. package/out/analytics/dashboard/webview/styles.css +1009 -0
  42. package/out/analytics/lifecycle.js +43 -0
  43. package/out/analytics/service.js +1279 -0
  44. package/out/analytics/sessionEvents.js +231 -0
  45. package/out/auth/bootstrapApply.js +72 -0
  46. package/out/auth/brokerClient.js +126 -0
  47. package/out/auth/callbackUri.js +59 -0
  48. package/out/auth/callbackUriParse.js +59 -0
  49. package/out/auth/githubStoreGate.js +70 -0
  50. package/out/auth/loopbackAuthServer.js +165 -0
  51. package/out/auth/pkce.js +9 -0
  52. package/out/auth/provider.js +239 -0
  53. package/out/auth/sessionStore.js +193 -0
  54. package/out/auth/signInFlow.js +182 -0
  55. package/out/auth/types.js +12 -0
  56. package/out/auth-broker/config.js +62 -0
  57. package/out/auth-broker/jwt.js +105 -0
  58. package/out/auth-broker/pkce.js +57 -0
  59. package/out/auth-broker/server.js +539 -0
  60. package/out/auth-broker/store.js +273 -0
  61. package/out/base-prompts/gateway/openclaw-starter.json5 +144 -0
  62. package/out/base-prompts/gateway/slack-socket-mode-minimal.manifest.json +44 -0
  63. package/out/base-prompts/mcp-servers/.mcp.json +13 -0
  64. package/out/base-prompts/mcp-servers/langfuse-analytics/README.md +142 -0
  65. package/out/base-prompts/mcp-servers/langfuse-analytics/mcp.json +13 -0
  66. package/out/base-prompts/mcp-servers/langfuse-analytics/package-lock.json +1192 -0
  67. package/out/base-prompts/mcp-servers/langfuse-analytics/package.json +23 -0
  68. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/run-with-env.sh +12 -0
  69. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/sdk-test.js +102 -0
  70. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/simple-test.js +137 -0
  71. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/test-client.js +118 -0
  72. package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/test-server.js +209 -0
  73. package/out/base-prompts/mcp-servers/langfuse-analytics/src/client.ts +431 -0
  74. package/out/base-prompts/mcp-servers/langfuse-analytics/src/index.ts +270 -0
  75. package/out/base-prompts/mcp-servers/langfuse-analytics/tsconfig.json +18 -0
  76. package/out/base-prompts/rules/AGENTS.md +204 -0
  77. package/out/base-prompts/skills/agent-browser/SKILL.md +102 -0
  78. package/out/base-prompts/skills/agent-builder/SKILL.md +73 -0
  79. package/out/base-prompts/skills/agent-builder/references/agent-pack.md +63 -0
  80. package/out/base-prompts/skills/agent-builder/references/crewai.md +66 -0
  81. package/out/base-prompts/skills/agent-builder/references/langchain.md +60 -0
  82. package/out/base-prompts/skills/agent-builder/references/raw-sdk.md +73 -0
  83. package/out/base-prompts/skills/agent-engine-creator/SKILL.md +586 -0
  84. package/out/base-prompts/skills/agent-engine-installer/SKILL.md +106 -0
  85. package/out/base-prompts/skills/agent-engine-installer/scripts/install-engine.mjs +259 -0
  86. package/out/base-prompts/skills/agent-engine-installer/scripts/install-engine.ps1 +189 -0
  87. package/out/base-prompts/skills/agenthippo-cli/SKILL.md +69 -0
  88. package/out/base-prompts/skills/agenthippo-cli/scripts/install.sh +63 -0
  89. package/out/base-prompts/skills/agentpack-creator/SKILL.md +375 -0
  90. package/out/base-prompts/skills/agentpack-creator/references/agent-templates.md +261 -0
  91. package/out/base-prompts/skills/agentpack-creator/references/agents-md-guide.md +195 -0
  92. package/out/base-prompts/skills/agentpack-creator/scripts/init_pack.py +391 -0
  93. package/out/base-prompts/skills/agentpack-creator/scripts/init_pack_test.py +294 -0
  94. package/out/base-prompts/skills/agentpack-testbench/SKILL.md +135 -0
  95. package/out/base-prompts/skills/algorithmic-art/LICENSE.txt +202 -0
  96. package/out/base-prompts/skills/algorithmic-art/SKILL.md +405 -0
  97. package/out/base-prompts/skills/algorithmic-art/templates/generator_template.js +223 -0
  98. package/out/base-prompts/skills/algorithmic-art/templates/viewer.html +599 -0
  99. package/out/base-prompts/skills/debug-agent/SKILL.md +83 -0
  100. package/out/base-prompts/skills/desktop-automation/SKILL.md +166 -0
  101. package/out/base-prompts/skills/desktop-automation/references/agenthippo-ui-recipes.md +441 -0
  102. package/out/base-prompts/skills/desktop-automation/scripts/windows-desktop-uia.psm1 +280 -0
  103. package/out/base-prompts/skills/docx/LICENSE.txt +30 -0
  104. package/out/base-prompts/skills/docx/SKILL.md +197 -0
  105. package/out/base-prompts/skills/docx/docx-js.md +350 -0
  106. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  107. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  108. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  109. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  110. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  111. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  112. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  113. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  114. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  115. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  116. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  117. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  118. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  119. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  120. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  121. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  122. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  123. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  124. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  125. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  126. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  127. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  128. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  129. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  130. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  131. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  132. package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  133. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  134. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  135. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  136. package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  137. package/out/base-prompts/skills/docx/ooxml/schemas/mce/mc.xsd +75 -0
  138. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  139. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  140. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  141. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  142. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  143. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  144. package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  145. package/out/base-prompts/skills/docx/ooxml/scripts/pack.py +159 -0
  146. package/out/base-prompts/skills/docx/ooxml/scripts/unpack.py +29 -0
  147. package/out/base-prompts/skills/docx/ooxml/scripts/validate.py +69 -0
  148. package/out/base-prompts/skills/docx/ooxml/scripts/validation/__init__.py +15 -0
  149. package/out/base-prompts/skills/docx/ooxml/scripts/validation/base.py +951 -0
  150. package/out/base-prompts/skills/docx/ooxml/scripts/validation/docx.py +274 -0
  151. package/out/base-prompts/skills/docx/ooxml/scripts/validation/pptx.py +315 -0
  152. package/out/base-prompts/skills/docx/ooxml/scripts/validation/redlining.py +279 -0
  153. package/out/base-prompts/skills/docx/ooxml.md +610 -0
  154. package/out/base-prompts/skills/docx/scripts/__init__.py +1 -0
  155. package/out/base-prompts/skills/docx/scripts/document.py +1276 -0
  156. package/out/base-prompts/skills/docx/scripts/templates/comments.xml +3 -0
  157. package/out/base-prompts/skills/docx/scripts/templates/commentsExtended.xml +3 -0
  158. package/out/base-prompts/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
  159. package/out/base-prompts/skills/docx/scripts/templates/commentsIds.xml +3 -0
  160. package/out/base-prompts/skills/docx/scripts/templates/people.xml +3 -0
  161. package/out/base-prompts/skills/docx/scripts/utilities.py +374 -0
  162. package/out/base-prompts/skills/gateway-outbound/SKILL.md +136 -0
  163. package/out/base-prompts/skills/mcp-builder/LICENSE.txt +202 -0
  164. package/out/base-prompts/skills/mcp-builder/SKILL.md +328 -0
  165. package/out/base-prompts/skills/mcp-builder/reference/evaluation.md +602 -0
  166. package/out/base-prompts/skills/mcp-builder/reference/mcp_best_practices.md +249 -0
  167. package/out/base-prompts/skills/mcp-builder/reference/node_mcp_server.md +970 -0
  168. package/out/base-prompts/skills/mcp-builder/reference/python_mcp_server.md +719 -0
  169. package/out/base-prompts/skills/mcp-builder/scripts/connections.py +151 -0
  170. package/out/base-prompts/skills/mcp-builder/scripts/evaluation.py +373 -0
  171. package/out/base-prompts/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  172. package/out/base-prompts/skills/mcp-builder/scripts/requirements.txt +2 -0
  173. package/out/base-prompts/skills/openclaw/SKILL.md +406 -0
  174. package/out/base-prompts/skills/openclaw/scripts/run-smoke.sh +61 -0
  175. package/out/base-prompts/skills/pdf/LICENSE.txt +30 -0
  176. package/out/base-prompts/skills/pdf/SKILL.md +294 -0
  177. package/out/base-prompts/skills/pdf/forms.md +205 -0
  178. package/out/base-prompts/skills/pdf/reference.md +612 -0
  179. package/out/base-prompts/skills/pdf/scripts/check_bounding_boxes.py +70 -0
  180. package/out/base-prompts/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
  181. package/out/base-prompts/skills/pdf/scripts/check_fillable_fields.py +12 -0
  182. package/out/base-prompts/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
  183. package/out/base-prompts/skills/pdf/scripts/create_validation_image.py +41 -0
  184. package/out/base-prompts/skills/pdf/scripts/extract_form_field_info.py +152 -0
  185. package/out/base-prompts/skills/pdf/scripts/fill_fillable_fields.py +114 -0
  186. package/out/base-prompts/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
  187. package/out/base-prompts/skills/pptx/LICENSE.txt +30 -0
  188. package/out/base-prompts/skills/pptx/SKILL.md +484 -0
  189. package/out/base-prompts/skills/pptx/html2pptx.md +625 -0
  190. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  191. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  192. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  193. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  194. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  195. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  196. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  197. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  198. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  199. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  200. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  201. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  202. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  203. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  204. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  205. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  206. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  207. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  208. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  209. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  210. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  211. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  212. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  213. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  214. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  215. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  216. package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  217. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  218. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  219. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  220. package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  221. package/out/base-prompts/skills/pptx/ooxml/schemas/mce/mc.xsd +75 -0
  222. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  223. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  224. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  225. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  226. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  227. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  228. package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  229. package/out/base-prompts/skills/pptx/ooxml/scripts/pack.py +159 -0
  230. package/out/base-prompts/skills/pptx/ooxml/scripts/unpack.py +29 -0
  231. package/out/base-prompts/skills/pptx/ooxml/scripts/validate.py +69 -0
  232. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/__init__.py +15 -0
  233. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/base.py +951 -0
  234. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/docx.py +274 -0
  235. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/pptx.py +315 -0
  236. package/out/base-prompts/skills/pptx/ooxml/scripts/validation/redlining.py +279 -0
  237. package/out/base-prompts/skills/pptx/ooxml.md +427 -0
  238. package/out/base-prompts/skills/pptx/scripts/html2pptx.js +984 -0
  239. package/out/base-prompts/skills/pptx/scripts/inventory.py +1020 -0
  240. package/out/base-prompts/skills/pptx/scripts/rearrange.py +231 -0
  241. package/out/base-prompts/skills/pptx/scripts/replace.py +385 -0
  242. package/out/base-prompts/skills/pptx/scripts/thumbnail.py +450 -0
  243. package/out/base-prompts/skills/prompt-lab/SKILL.md +149 -0
  244. package/out/base-prompts/skills/prompt-lab/scripts/query-analytics.sh +2551 -0
  245. package/out/base-prompts/skills/skill-creator/LICENSE.txt +202 -0
  246. package/out/base-prompts/skills/skill-creator/SKILL.md +371 -0
  247. package/out/base-prompts/skills/skill-creator/references/output-patterns.md +82 -0
  248. package/out/base-prompts/skills/skill-creator/references/workflows.md +28 -0
  249. package/out/base-prompts/skills/skill-creator/scripts/init_skill.py +303 -0
  250. package/out/base-prompts/skills/skill-creator/scripts/package_skill.py +110 -0
  251. package/out/base-prompts/skills/skill-creator/scripts/quick_validate.py +95 -0
  252. package/out/base-prompts/skills/skill-installer/SKILL.md +251 -0
  253. package/out/base-prompts/skills/skill-installer/references/store-api.md +219 -0
  254. package/out/base-prompts/skills/spotlight-dashboard/SKILL.md +83 -0
  255. package/out/base-prompts/skills/spotlight-insights/SKILL.md +101 -0
  256. package/out/base-prompts/skills/spotlight-optimize/SKILL.md +93 -0
  257. package/out/base-prompts/skills/spotlight-optimize/scripts/query-analytics.sh +2551 -0
  258. package/out/base-prompts/skills/spotlight-query/SKILL.md +314 -0
  259. package/out/base-prompts/skills/spotlight-query/references/otel-schema.md +163 -0
  260. package/out/base-prompts/skills/spotlight-query/scripts/query-analytics.sh +2551 -0
  261. package/out/base-prompts/skills/spotlight-query/scripts/query-analytics.test.sh +744 -0
  262. package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/sessions/sess-test-1.jsonl +14 -0
  263. package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/traces/.duckdb-index.json +7 -0
  264. package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/traces/sample.jsonl +5 -0
  265. package/out/base-prompts/skills/spotlight-report/SKILL.md +86 -0
  266. package/out/base-prompts/skills/spotlight-visualize/SKILL.md +92 -0
  267. package/out/base-prompts/skills/spotlight-visualize/scripts/query-analytics.sh +2551 -0
  268. package/out/base-prompts/skills/xlsx/LICENSE.txt +30 -0
  269. package/out/base-prompts/skills/xlsx/SKILL.md +289 -0
  270. package/out/base-prompts/skills/xlsx/recalc.py +178 -0
  271. package/out/branding.js +23 -0
  272. package/out/cli/commands/anywhere.js +66 -0
  273. package/out/cli/commands/ask.js +243 -0
  274. package/out/cli/commands/auth-broker.js +24 -0
  275. package/out/cli/commands/auth.js +219 -0
  276. package/out/cli/commands/chat.js +354 -0
  277. package/out/cli/commands/deploy.js +223 -0
  278. package/out/cli/commands/gateway.js +160 -0
  279. package/out/cli/commands/pack.js +220 -0
  280. package/out/cli/commands/probe-custom-engine.js +82 -0
  281. package/out/cli/commands/serve.js +583 -0
  282. package/out/cli/commands/store.js +919 -0
  283. package/out/cli/credential-context.js +113 -0
  284. package/out/cli/deploy-init.js +2087 -0
  285. package/out/cli/deps.js +238 -0
  286. package/out/cli/index.js +390 -0
  287. package/out/cli/pack-loader.js +376 -0
  288. package/out/cli/run-custom-engine-runner.js +318 -0
  289. package/out/cli/runtime.js +409 -0
  290. package/out/cli/serve-hardening.js +325 -0
  291. package/out/cli/state-sync.js +135 -0
  292. package/out/cli/utils.js +220 -0
  293. package/out/cli/vscode-shim.js +86 -0
  294. package/out/engines/base.js +159 -0
  295. package/out/engines/claude.js +1215 -0
  296. package/out/engines/codex.js +759 -0
  297. package/out/engines/custom.js +632 -0
  298. package/out/engines/customEngineIpc.js +95 -0
  299. package/out/engines/customEngineRunnerEmbed.js +107 -0
  300. package/out/engines/customRegistry.js +274 -0
  301. package/out/engines/embeddedCustomEngineRunner.generated.js +9 -0
  302. package/out/engines/engineApiKey.js +138 -0
  303. package/out/engines/factory.js +45 -0
  304. package/out/engines/install.js +372 -0
  305. package/out/engines/persistentEngineWorker.js +320 -0
  306. package/out/engines/publish.js +341 -0
  307. package/out/engines/types.js +17 -0
  308. package/out/examples/run-headless-repl.js +291 -0
  309. package/out/examples/run-headless.js +187 -0
  310. package/out/extension.js +4472 -0
  311. package/out/gateway/bridge.js +805 -0
  312. package/out/gateway/cli-agent-id.js +36 -0
  313. package/out/gateway/client.js +303 -0
  314. package/out/gateway/client.test.js +395 -0
  315. package/out/gateway/gateway-scope-errors.js +14 -0
  316. package/out/gateway/gatewayBackup.js +76 -0
  317. package/out/gateway/gatewayRouteIndex.js +371 -0
  318. package/out/gateway/gatewaySessionStore.js +243 -0
  319. package/out/gateway/index.js +31 -0
  320. package/out/gateway/lifecycle.js +3056 -0
  321. package/out/gateway/openclaw-channel-routing.js +317 -0
  322. package/out/gateway/outboundHandles.js +373 -0
  323. package/out/gateway/outboundPaths.js +72 -0
  324. package/out/gateway/outboundSend.js +254 -0
  325. package/out/gateway/protocol.js +48 -0
  326. package/out/gateway/resetMappings.js +52 -0
  327. package/out/gateway/service.js +1244 -0
  328. package/out/gateway/sessionRouting.js +77 -0
  329. package/out/headless/index.js +505 -0
  330. package/out/headless/sync.js +473 -0
  331. package/out/mcp/publish.js +143 -0
  332. package/out/mcp.js +597 -0
  333. package/out/permissions.js +108 -0
  334. package/out/permissions.mapping.yaml +68 -0
  335. package/out/registry/index.js +332 -0
  336. package/out/remote/handleRemoteChat.js +122 -0
  337. package/out/remote/remotePackStatusBar.js +103 -0
  338. package/out/remote/serveClient.js +216 -0
  339. package/out/remoteSkills.js +191 -0
  340. package/out/runtime/index.js +32 -0
  341. package/out/runtime/interfaces/config-provider.js +32 -0
  342. package/out/runtime/interfaces/edit-tracker.js +22 -0
  343. package/out/runtime/interfaces/index.js +29 -0
  344. package/out/runtime/interfaces/logger.js +40 -0
  345. package/out/runtime/interfaces/permission-handler.js +66 -0
  346. package/out/runtime/interfaces/session-store.js +342 -0
  347. package/out/runtime/vscode/index.js +20 -0
  348. package/out/runtime/vscode/vscode-config-provider.js +77 -0
  349. package/out/runtime/vscode/vscode-edit-tracker.js +120 -0
  350. package/out/runtime/vscode/vscode-logger.js +30 -0
  351. package/out/runtime/vscode/vscode-permission-handler.js +72 -0
  352. package/out/runtime/vscode/vscode-session-store.js +22 -0
  353. package/out/scripts/agentide-litellm.ps1 +501 -0
  354. package/out/scripts/agentide-litellm.sh +700 -0
  355. package/out/scripts/agentide_litellm_hooks_v1.py +604 -0
  356. package/out/scripts/analytics/agent-fleet-widget.js +954 -0
  357. package/out/scripts/analytics/agentide-litellm-otel.config.yaml +160 -0
  358. package/out/scripts/analytics/default-seed-scripts.json +12 -0
  359. package/out/scripts/analytics/duckdbLocator.js +29 -0
  360. package/out/scripts/analytics/fleet-local-adapter.js +246 -0
  361. package/out/scripts/analytics/fleet-workflow.sh +263 -0
  362. package/out/scripts/analytics/generate-default-charts.py +685 -0
  363. package/out/scripts/analytics/hotspot-analysis-widget.js +909 -0
  364. package/out/scripts/analytics/index-traces.py +1394 -0
  365. package/out/scripts/analytics/install-analytics.sh +286 -0
  366. package/out/scripts/analytics/live-fleet-4-collector.cjs +315 -0
  367. package/out/scripts/analytics/live-fleet-4-daemon.mjs +134 -0
  368. package/out/scripts/analytics/live-fleet-4-widget.cjs +433 -0
  369. package/out/scripts/analytics/otel-collector.yaml +55 -0
  370. package/out/scripts/analytics/query-analytics.ps1 +396 -0
  371. package/out/scripts/analytics/query-analytics.sh +2551 -0
  372. package/out/scripts/analytics/session-comparison-widget.js +1468 -0
  373. package/out/scripts/analytics/session-timeline-widget.js +2137 -0
  374. package/out/scripts/analytics/setup-analytics.ps1 +432 -0
  375. package/out/scripts/analytics/setup-analytics.sh +854 -0
  376. package/out/scripts/analytics/start-analytics.ps1 +169 -0
  377. package/out/scripts/analytics/start-analytics.sh +323 -0
  378. package/out/scripts/analytics/token-cost-flamegraph-widget.js +954 -0
  379. package/out/scripts/analytics/token-cost-trend-widget.js +1062 -0
  380. package/out/scripts/analytics/workflows-collector.cjs +315 -0
  381. package/out/scripts/analytics/workflows-daemon.mjs +186 -0
  382. package/out/scripts/analytics/workflows-widget.cjs +433 -0
  383. package/out/scripts/analytics/wow-model-widget.js +191 -0
  384. package/out/scripts/gateway/Dockerfile.serve +45 -0
  385. package/out/scripts/gateway/docker-serve.sh +248 -0
  386. package/out/scripts/gateway/setup-gateway-server.ps1 +953 -0
  387. package/out/scripts/gateway/setup-gateway-server.sh +935 -0
  388. package/out/scripts/gateway/setup-gateway.ps1 +1813 -0
  389. package/out/scripts/gateway/setup-gateway.sh +1541 -0
  390. package/out/scripts/setup-cli.ps1 +86 -0
  391. package/out/scripts/setup-cli.sh +117 -0
  392. package/out/scripts/tools-manifest.json +83 -0
  393. package/out/scripts/vendor-tools.mjs +234 -0
  394. package/out/session.js +272 -0
  395. package/out/shared/agentEngines.js +170 -0
  396. package/out/shared/index.js +109 -0
  397. package/out/shared/models.js +235 -0
  398. package/out/shared/providers.js +202 -0
  399. package/out/skills/publish.js +178 -0
  400. package/out/spotlight/install.js +339 -0
  401. package/out/spotlight/publish.js +544 -0
  402. package/out/spotlight/yaml.js +31 -0
  403. package/out/store/github/setup.js +235 -0
  404. package/out/store/github/templates/build-index.ts +339 -0
  405. package/out/store/github/templates/build-index.yml +97 -0
  406. package/out/store/github/templates/package.json +11 -0
  407. package/out/store/index.js +755 -0
  408. package/out/store/oramaIndex.js +884 -0
  409. package/out/store/shared.js +241 -0
  410. package/out/sync.js +1827 -0
  411. package/out/terminalLogger.js +358 -0
  412. package/out/test/agentEnvFile.test.js +97 -0
  413. package/out/test/agentYaml.test.js +373 -0
  414. package/out/test/agentpack.test.js +639 -0
  415. package/out/test/analytics-lifecycle.test.js +174 -0
  416. package/out/test/analytics.test.js +524 -0
  417. package/out/test/auth-bootstrapApply.test.js +102 -0
  418. package/out/test/auth-broker.test.js +434 -0
  419. package/out/test/auth-callback.test.js +62 -0
  420. package/out/test/branding.test.js +229 -0
  421. package/out/test/cli-agent-id.test.js +55 -0
  422. package/out/test/credential-context.test.js +105 -0
  423. package/out/test/customEngineInstall.test.js +100 -0
  424. package/out/test/customRegistry.test.js +122 -0
  425. package/out/test/deploy-init.test.js +532 -0
  426. package/out/test/deps-auto-install.test.js +81 -0
  427. package/out/test/engine-integration.test.js +297 -0
  428. package/out/test/enginePaths.test.js +195 -0
  429. package/out/test/enginePublish.test.js +82 -0
  430. package/out/test/fleetDisplayUtils.test.js +96 -0
  431. package/out/test/gateway-client.test.js +381 -0
  432. package/out/test/gateway-lifecycle.test.js +608 -0
  433. package/out/test/gateway-outbound.test.js +531 -0
  434. package/out/test/gateway-reset-mappings.test.js +221 -0
  435. package/out/test/gateway-route-index.test.js +235 -0
  436. package/out/test/gateway-session-routing.test.js +47 -0
  437. package/out/test/gateway-session-store.test.js +216 -0
  438. package/out/test/github.test.js +232 -0
  439. package/out/test/headless-sync.test.js +279 -0
  440. package/out/test/helpers/manifest-fixtures.js +27 -0
  441. package/out/test/mcp-obo.test.js +82 -0
  442. package/out/test/mcp.test.js +307 -0
  443. package/out/test/openclaw-channel-routing.test.js +191 -0
  444. package/out/test/pathSafety.test.js +63 -0
  445. package/out/test/permissions.test.js +175 -0
  446. package/out/test/persistent-engine-worker.test.js +220 -0
  447. package/out/test/refreshPolicy.test.js +60 -0
  448. package/out/test/registry.test.js +351 -0
  449. package/out/test/runtime.test.js +349 -0
  450. package/out/test/scheduledFleetStorage.test.js +72 -0
  451. package/out/test/serve-hardening.test.js +192 -0
  452. package/out/test/serveClient.test.js +173 -0
  453. package/out/test/sessionJsonlFleet.test.js +78 -0
  454. package/out/test/shared.test.js +173 -0
  455. package/out/test/skills-mcp.test.js +299 -0
  456. package/out/test/spotlightPublish.test.js +299 -0
  457. package/out/test/spotlightYaml.test.js +58 -0
  458. package/out/test/state-sync-peer.test.js +74 -0
  459. package/out/test/store.test.js +331 -0
  460. package/out/test/stores.test.js +504 -0
  461. package/out/test/sync-switch.test.js +251 -0
  462. package/out/test/teamViewDiscovery.test.js +90 -0
  463. package/out/test/toolPath.test.js +120 -0
  464. package/out/test/utils.test.js +308 -0
  465. package/out/test/viewsConfigMerge.test.js +180 -0
  466. package/out/test/windows-command-line.test.js +75 -0
  467. package/out/utils/agentEnvFile.js +131 -0
  468. package/out/utils/binary.js +175 -0
  469. package/out/utils/index.js +37 -0
  470. package/out/utils/network.js +74 -0
  471. package/out/utils/pathSafety.js +60 -0
  472. package/out/utils/paths.js +116 -0
  473. package/out/utils/pid.js +180 -0
  474. package/out/utils/pythonRunner.js +258 -0
  475. package/out/utils/resolveNodeBinary.js +168 -0
  476. package/out/utils/toolPath.js +83 -0
  477. package/out/utils/windowsCommandLine.js +29 -0
  478. package/out/utils.js +915 -0
  479. package/out/workspaceFolders.js +59 -0
  480. package/package.json +41 -0
@@ -0,0 +1,1062 @@
1
+ #!/usr/bin/env node
2
+ /* Copyright (c) AgentHippo.ai. All rights reserved. */
3
+ /* eslint-disable no-console */
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ const MAX_TRACE_FILES = 36;
8
+ const MAX_ROWS = 45_000;
9
+ const MOVING_AVG_WINDOW = 6;
10
+ const MAX_SPIKES = 10;
11
+
12
+ const TOKEN_KEYS_IN = [
13
+ 'gen_ai.usage.input_tokens',
14
+ 'llm.usage.prompt_tokens',
15
+ 'llm.token_count.prompt',
16
+ ];
17
+ const TOKEN_KEYS_OUT = [
18
+ 'gen_ai.usage.output_tokens',
19
+ 'llm.usage.completion_tokens',
20
+ 'llm.token_count.completion',
21
+ ];
22
+ const COST_KEYS = [
23
+ 'gen_ai.cost.total_cost',
24
+ 'llm.cost.total_cost',
25
+ 'cost',
26
+ ];
27
+ const MODEL_KEYS = [
28
+ 'gen_ai.request.model',
29
+ 'gen_ai.response.model',
30
+ 'model',
31
+ ];
32
+
33
+ function isOutputDisabled(filename) {
34
+ const raw = String(process.env.AGENTIDE_DISABLED_CHARTS || '').trim();
35
+ if (!raw) {
36
+ return false;
37
+ }
38
+ const disabled = new Set(
39
+ raw
40
+ .split(',')
41
+ .map((entry) => path.basename(entry.trim()).toLowerCase())
42
+ .filter(Boolean),
43
+ );
44
+ return disabled.has(path.basename(filename).toLowerCase());
45
+ }
46
+
47
+ function listTraceFiles(tracesDir) {
48
+ let entries = [];
49
+ try {
50
+ entries = fs.readdirSync(tracesDir, { withFileTypes: true });
51
+ } catch {
52
+ return [];
53
+ }
54
+
55
+ return entries
56
+ .filter((entry) => entry.isFile() && entry.name.endsWith('.jsonl'))
57
+ .map((entry) => path.join(tracesDir, entry.name))
58
+ .map((filePath) => ({
59
+ filePath,
60
+ mtime: fs.statSync(filePath).mtimeMs,
61
+ }))
62
+ .sort((a, b) => b.mtime - a.mtime)
63
+ .slice(0, MAX_TRACE_FILES)
64
+ .map((row) => row.filePath);
65
+ }
66
+
67
+ function toNumber(value) {
68
+ if (typeof value === 'number' && Number.isFinite(value)) {
69
+ return value;
70
+ }
71
+ if (typeof value === 'string') {
72
+ const parsed = Number(value);
73
+ if (Number.isFinite(parsed)) {
74
+ return parsed;
75
+ }
76
+ }
77
+ return 0;
78
+ }
79
+
80
+ function parseAttributeValue(value) {
81
+ if (!value || typeof value !== 'object') {
82
+ return null;
83
+ }
84
+ if (typeof value.stringValue === 'string') {
85
+ return value.stringValue;
86
+ }
87
+ if (value.intValue !== undefined) {
88
+ return toNumber(value.intValue);
89
+ }
90
+ if (value.doubleValue !== undefined) {
91
+ return toNumber(value.doubleValue);
92
+ }
93
+ if (typeof value.boolValue === 'boolean') {
94
+ return value.boolValue ? 1 : 0;
95
+ }
96
+ return null;
97
+ }
98
+
99
+ function attrsToMap(attributes) {
100
+ const out = Object.create(null);
101
+ if (!Array.isArray(attributes)) {
102
+ return out;
103
+ }
104
+ for (const item of attributes) {
105
+ if (!item || typeof item !== 'object') {
106
+ continue;
107
+ }
108
+ const key = String(item.key || '').trim();
109
+ if (!key) {
110
+ continue;
111
+ }
112
+ out[key] = parseAttributeValue(item.value);
113
+ }
114
+ return out;
115
+ }
116
+
117
+ function firstNumber(attrs, keys) {
118
+ for (const key of keys) {
119
+ const value = toNumber(attrs[key]);
120
+ if (value > 0) {
121
+ return value;
122
+ }
123
+ }
124
+ return 0;
125
+ }
126
+
127
+ function firstString(attrs, keys) {
128
+ for (const key of keys) {
129
+ const value = attrs[key];
130
+ if (typeof value === 'string' && value.trim()) {
131
+ return value.trim();
132
+ }
133
+ }
134
+ return '';
135
+ }
136
+
137
+ function extractFromRegex(raw, pattern) {
138
+ const text = typeof raw === 'string' ? raw : '';
139
+ if (!text) {
140
+ return '';
141
+ }
142
+ const match = text.match(pattern);
143
+ return match ? String(match[1] || '').trim() : '';
144
+ }
145
+
146
+ function extractAgentId(attrs) {
147
+ const explicit = firstString(attrs, [
148
+ 'agent_id',
149
+ 'gen_ai.agent.id',
150
+ 'metadata.agent_id',
151
+ ]);
152
+ if (explicit) {
153
+ return explicit;
154
+ }
155
+
156
+ const headers = firstString(attrs, ['metadata.requester_custom_headers']);
157
+ const metadata = firstString(attrs, ['metadata.requester_metadata']);
158
+ return (
159
+ extractFromRegex(headers, /x-litellm-metadata-agent-id'?:\s*'([^']+)'/i) ||
160
+ extractFromRegex(metadata, /agent_id'?:\s*'([^']+)'/i) ||
161
+ ''
162
+ );
163
+ }
164
+
165
+ function extractSessionId(attrs) {
166
+ const headers = firstString(attrs, ['metadata.requester_custom_headers']);
167
+ const metadata = firstString(attrs, ['metadata.requester_metadata']);
168
+ return (
169
+ extractFromRegex(headers, /x-litellm-metadata-session-id'?:\s*'([^']+)'/i) ||
170
+ extractFromRegex(metadata, /session_id'?:\s*'([^']+)'/i) ||
171
+ ''
172
+ );
173
+ }
174
+
175
+ function chooseBucketSizeMs(rangeMs) {
176
+ const hour = 60 * 60 * 1000;
177
+ const day = 24 * hour;
178
+ if (rangeMs <= 36 * hour) {
179
+ return 15 * 60 * 1000;
180
+ }
181
+ if (rangeMs <= 14 * day) {
182
+ return hour;
183
+ }
184
+ if (rangeMs <= 90 * day) {
185
+ return 6 * hour;
186
+ }
187
+ return day;
188
+ }
189
+
190
+ function bucketLabel(ms, stepMs) {
191
+ const date = new Date(ms);
192
+ const hour = 60 * 60 * 1000;
193
+ const day = 24 * hour;
194
+ if (stepMs < day) {
195
+ return date.toLocaleString();
196
+ }
197
+ return date.toLocaleDateString();
198
+ }
199
+
200
+ function movingAverage(values, windowSize) {
201
+ const out = [];
202
+ let rollingSum = 0;
203
+ for (let i = 0; i < values.length; i++) {
204
+ rollingSum += values[i];
205
+ if (i >= windowSize) {
206
+ rollingSum -= values[i - windowSize];
207
+ }
208
+ const width = Math.min(windowSize, i + 1);
209
+ out.push(width > 0 ? rollingSum / width : 0);
210
+ }
211
+ return out;
212
+ }
213
+
214
+ function median(values) {
215
+ if (!values.length) {
216
+ return 0;
217
+ }
218
+ const sorted = [...values].sort((a, b) => a - b);
219
+ const half = Math.floor(sorted.length / 2);
220
+ if (sorted.length % 2 === 0) {
221
+ return (sorted[half - 1] + sorted[half]) / 2;
222
+ }
223
+ return sorted[half];
224
+ }
225
+
226
+ function loadRows(tracesDir, agentFilterId) {
227
+ const files = listTraceFiles(tracesDir);
228
+ const rows = [];
229
+ let tracesSeen = 0;
230
+ const traceSeenSet = new Set();
231
+
232
+ for (const filePath of files) {
233
+ if (rows.length >= MAX_ROWS) {
234
+ break;
235
+ }
236
+ let raw = '';
237
+ try {
238
+ raw = fs.readFileSync(filePath, 'utf8');
239
+ } catch {
240
+ continue;
241
+ }
242
+
243
+ for (const line of raw.split(/\r?\n/)) {
244
+ if (rows.length >= MAX_ROWS) {
245
+ break;
246
+ }
247
+ const trimmed = String(line || '').trim();
248
+ if (!trimmed) {
249
+ continue;
250
+ }
251
+ let parsed;
252
+ try {
253
+ parsed = JSON.parse(trimmed);
254
+ } catch {
255
+ continue;
256
+ }
257
+
258
+ const resourceSpans = Array.isArray(parsed?.resourceSpans) ? parsed.resourceSpans : [];
259
+ for (const resourceSpan of resourceSpans) {
260
+ const scopeSpans = Array.isArray(resourceSpan?.scopeSpans) ? resourceSpan.scopeSpans : [];
261
+ for (const scopeSpan of scopeSpans) {
262
+ const spans = Array.isArray(scopeSpan?.spans) ? scopeSpan.spans : [];
263
+ for (const span of spans) {
264
+ if (!span || typeof span !== 'object') {
265
+ continue;
266
+ }
267
+ const attrs = attrsToMap(span.attributes);
268
+ const inputTokens = firstNumber(attrs, TOKEN_KEYS_IN);
269
+ const outputTokens = firstNumber(attrs, TOKEN_KEYS_OUT);
270
+ const cost = firstNumber(attrs, COST_KEYS);
271
+ if (inputTokens <= 0 && outputTokens <= 0 && cost <= 0) {
272
+ continue;
273
+ }
274
+
275
+ const agentId = extractAgentId(attrs);
276
+ if (agentFilterId && agentId && agentId !== agentFilterId) {
277
+ continue;
278
+ }
279
+ if (agentFilterId && !agentId) {
280
+ continue;
281
+ }
282
+
283
+ const timestampMs = Math.round(toNumber(span.startTimeUnixNano) / 1_000_000);
284
+ if (!Number.isFinite(timestampMs) || timestampMs <= 0) {
285
+ continue;
286
+ }
287
+
288
+ const traceId = String(span.traceId || '').trim();
289
+ if (traceId && !traceSeenSet.has(traceId)) {
290
+ traceSeenSet.add(traceId);
291
+ tracesSeen += 1;
292
+ }
293
+
294
+ rows.push({
295
+ timestampMs,
296
+ traceId,
297
+ spanName: String(span.name || '(span)').trim() || '(span)',
298
+ model: firstString(attrs, MODEL_KEYS) || 'unknown',
299
+ agentId: agentId || 'unknown',
300
+ sessionId: extractSessionId(attrs) || '',
301
+ inputTokens,
302
+ outputTokens,
303
+ totalTokens: inputTokens + outputTokens,
304
+ cost,
305
+ });
306
+ }
307
+ }
308
+ }
309
+ }
310
+ }
311
+
312
+ rows.sort((a, b) => a.timestampMs - b.timestampMs);
313
+ return {
314
+ rows,
315
+ traceCount: tracesSeen,
316
+ fileCount: files.length,
317
+ };
318
+ }
319
+
320
+ function aggregateRows(rows) {
321
+ if (!rows.length) {
322
+ return null;
323
+ }
324
+ const minTs = rows[0].timestampMs;
325
+ const maxTs = rows[rows.length - 1].timestampMs;
326
+ const rangeMs = Math.max(1, maxTs - minTs);
327
+ const bucketSizeMs = chooseBucketSizeMs(rangeMs);
328
+ const start = Math.floor(minTs / bucketSizeMs) * bucketSizeMs;
329
+ const end = Math.ceil(maxTs / bucketSizeMs) * bucketSizeMs;
330
+
331
+ /** @type {Map<number, any>} */
332
+ const byBucket = new Map();
333
+ for (let t = start; t <= end; t += bucketSizeMs) {
334
+ byBucket.set(t, {
335
+ bucketStartMs: t,
336
+ inputTokens: 0,
337
+ outputTokens: 0,
338
+ totalTokens: 0,
339
+ cost: 0,
340
+ requests: 0,
341
+ traceIds: new Set(),
342
+ modelCounts: new Map(),
343
+ sessionCounts: new Map(),
344
+ });
345
+ }
346
+
347
+ for (const row of rows) {
348
+ const bucketStartMs = Math.floor(row.timestampMs / bucketSizeMs) * bucketSizeMs;
349
+ const bucket = byBucket.get(bucketStartMs);
350
+ if (!bucket) {
351
+ continue;
352
+ }
353
+ bucket.inputTokens += row.inputTokens;
354
+ bucket.outputTokens += row.outputTokens;
355
+ bucket.totalTokens += row.totalTokens;
356
+ bucket.cost += row.cost;
357
+ bucket.requests += 1;
358
+ if (row.traceId) {
359
+ bucket.traceIds.add(row.traceId);
360
+ }
361
+ bucket.modelCounts.set(row.model, (bucket.modelCounts.get(row.model) || 0) + row.totalTokens);
362
+ if (row.sessionId) {
363
+ bucket.sessionCounts.set(row.sessionId, (bucket.sessionCounts.get(row.sessionId) || 0) + row.totalTokens);
364
+ }
365
+ }
366
+
367
+ const buckets = [...byBucket.values()]
368
+ .sort((a, b) => a.bucketStartMs - b.bucketStartMs)
369
+ .map((bucket) => {
370
+ const topModel = [...bucket.modelCounts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] || 'unknown';
371
+ const topSession = [...bucket.sessionCounts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] || '';
372
+ return {
373
+ bucketStartMs: bucket.bucketStartMs,
374
+ label: bucketLabel(bucket.bucketStartMs, bucketSizeMs),
375
+ inputTokens: Math.round(bucket.inputTokens),
376
+ outputTokens: Math.round(bucket.outputTokens),
377
+ totalTokens: Math.round(bucket.totalTokens),
378
+ cost: Number(bucket.cost.toFixed(6)),
379
+ requests: Math.round(bucket.requests),
380
+ traceCount: bucket.traceIds.size,
381
+ topModel,
382
+ topSession,
383
+ };
384
+ });
385
+
386
+ const tokenSeries = buckets.map((bucket) => bucket.totalTokens);
387
+ const costSeries = buckets.map((bucket) => bucket.cost);
388
+ const tokenMa = movingAverage(tokenSeries, MOVING_AVG_WINDOW);
389
+ const costMa = movingAverage(costSeries, MOVING_AVG_WINDOW);
390
+ let cumulativeCost = 0;
391
+
392
+ for (let i = 0; i < buckets.length; i++) {
393
+ cumulativeCost += buckets[i].cost;
394
+ buckets[i].cumulativeCost = Number(cumulativeCost.toFixed(6));
395
+ buckets[i].tokenMovingAvg = Math.round(tokenMa[i]);
396
+ buckets[i].costMovingAvg = Number(costMa[i].toFixed(6));
397
+ if (i > 0) {
398
+ const previous = buckets[i - 1];
399
+ buckets[i].tokenDelta = buckets[i].totalTokens - previous.totalTokens;
400
+ buckets[i].costDelta = Number((buckets[i].cost - previous.cost).toFixed(6));
401
+ } else {
402
+ buckets[i].tokenDelta = 0;
403
+ buckets[i].costDelta = 0;
404
+ }
405
+ }
406
+
407
+ const nonZeroTokens = tokenSeries.filter((value) => value > 0);
408
+ const nonZeroCosts = costSeries.filter((value) => value > 0);
409
+ const tokenMedian = median(nonZeroTokens);
410
+ const costMedian = median(nonZeroCosts);
411
+ const tokenSpikeThreshold = tokenMedian > 0 ? tokenMedian * 2.2 : 0;
412
+ const costSpikeThreshold = costMedian > 0 ? costMedian * 2.2 : 0;
413
+
414
+ const spikes = buckets
415
+ .map((bucket, index) => {
416
+ const tokenSpike = tokenSpikeThreshold > 0 && bucket.totalTokens >= tokenSpikeThreshold;
417
+ const costSpike = costSpikeThreshold > 0 && bucket.cost >= costSpikeThreshold;
418
+ if (!tokenSpike && !costSpike) {
419
+ return null;
420
+ }
421
+ const score = (bucket.totalTokens / Math.max(1, tokenMedian)) + (bucket.cost / Math.max(0.000001, costMedian));
422
+ return {
423
+ index,
424
+ label: bucket.label,
425
+ bucketStartMs: bucket.bucketStartMs,
426
+ totalTokens: bucket.totalTokens,
427
+ cost: bucket.cost,
428
+ requests: bucket.requests,
429
+ topModel: bucket.topModel,
430
+ topSession: bucket.topSession,
431
+ tokenSpike,
432
+ costSpike,
433
+ score,
434
+ };
435
+ })
436
+ .filter(Boolean)
437
+ .sort((a, b) => b.score - a.score)
438
+ .slice(0, MAX_SPIKES);
439
+
440
+ const totalInputTokens = buckets.reduce((sum, bucket) => sum + bucket.inputTokens, 0);
441
+ const totalOutputTokens = buckets.reduce((sum, bucket) => sum + bucket.outputTokens, 0);
442
+ const totalCost = Number(buckets.reduce((sum, bucket) => sum + bucket.cost, 0).toFixed(6));
443
+ const totalRequests = buckets.reduce((sum, bucket) => sum + bucket.requests, 0);
444
+
445
+ return {
446
+ buckets,
447
+ bucketSizeMs,
448
+ tokenMedian,
449
+ costMedian,
450
+ tokenSpikeThreshold,
451
+ costSpikeThreshold,
452
+ spikes,
453
+ totals: {
454
+ inputTokens: totalInputTokens,
455
+ outputTokens: totalOutputTokens,
456
+ totalTokens: totalInputTokens + totalOutputTokens,
457
+ totalCost,
458
+ totalRequests,
459
+ },
460
+ };
461
+ }
462
+
463
+ function buildFallbackHtml(message) {
464
+ return `<!doctype html><html><head><meta charset="utf-8"><title>Token + Cost Trend</title></head><body style="font-family:ui-sans-serif,system-ui;background:#0f111a;color:#e5e7eb;margin:0;padding:20px;"><h2 style="margin:0 0 8px;">Token + Cost Trend</h2><p style="opacity:.85;">${message}</p></body></html>`;
465
+ }
466
+
467
+ function buildHtml(payload) {
468
+ const safeJson = JSON.stringify(payload)
469
+ .replace(/</g, '\\u003c')
470
+ .replace(/>/g, '\\u003e')
471
+ .replace(/&/g, '\\u0026')
472
+ .replace(/\u2028/g, '\\u2028')
473
+ .replace(/\u2029/g, '\\u2029');
474
+
475
+ return `<!doctype html>
476
+ <html>
477
+ <head>
478
+ <meta charset="utf-8" />
479
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
480
+ <title>Token + Cost Trend</title>
481
+ <style>
482
+ :root {
483
+ color-scheme: dark;
484
+ --bg: #0b1220;
485
+ --panel: #101a2f;
486
+ --soft: #16243c;
487
+ --border: #253a59;
488
+ --text: #e2e8f0;
489
+ --muted: #9ab0cf;
490
+ --token: #38bdf8;
491
+ --cost: #f59e0b;
492
+ --ma: #a78bfa;
493
+ --spike: #ef4444;
494
+ }
495
+ * { box-sizing: border-box; }
496
+ body {
497
+ margin: 0;
498
+ background: var(--bg);
499
+ color: var(--text);
500
+ font: 13px/1.45 ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
501
+ }
502
+ .root {
503
+ display: grid;
504
+ grid-template-columns: minmax(620px, 1fr) minmax(280px, 360px);
505
+ gap: 10px;
506
+ min-height: 96vh;
507
+ padding: 12px;
508
+ }
509
+ .card {
510
+ border: 1px solid var(--border);
511
+ background: var(--panel);
512
+ border-radius: 12px;
513
+ overflow: hidden;
514
+ }
515
+ .head {
516
+ padding: 10px 12px;
517
+ border-bottom: 1px solid var(--border);
518
+ display: flex;
519
+ align-items: center;
520
+ justify-content: space-between;
521
+ gap: 10px;
522
+ flex-wrap: wrap;
523
+ }
524
+ .title { font-size: 14px; font-weight: 700; }
525
+ .meta { color: var(--muted); font-size: 11px; margin-top: 2px; }
526
+ .pill {
527
+ border: 1px solid #2d5f8f;
528
+ color: #bfdbfe;
529
+ background: #112845;
530
+ border-radius: 999px;
531
+ padding: 2px 8px;
532
+ font-size: 11px;
533
+ white-space: nowrap;
534
+ }
535
+ .plot-wrap {
536
+ padding: 8px;
537
+ height: min(76vh, 840px);
538
+ overflow: auto;
539
+ background: #091224;
540
+ }
541
+ svg {
542
+ width: 100%;
543
+ min-height: 420px;
544
+ border-radius: 10px;
545
+ border: 1px solid #1f3151;
546
+ background: #071121;
547
+ display: block;
548
+ }
549
+ .legend {
550
+ display: flex;
551
+ gap: 10px;
552
+ align-items: center;
553
+ flex-wrap: wrap;
554
+ padding: 8px 12px;
555
+ border-top: 1px solid var(--border);
556
+ color: var(--muted);
557
+ font-size: 11px;
558
+ }
559
+ .sw {
560
+ display: inline-block;
561
+ width: 11px;
562
+ height: 11px;
563
+ border-radius: 2px;
564
+ margin-right: 5px;
565
+ vertical-align: -1px;
566
+ }
567
+ .side {
568
+ display: grid;
569
+ grid-template-rows: auto auto 1fr auto;
570
+ min-height: 0;
571
+ }
572
+ .block {
573
+ padding: 10px 12px;
574
+ border-bottom: 1px solid var(--border);
575
+ }
576
+ .block:last-child { border-bottom: none; }
577
+ .stats {
578
+ display: grid;
579
+ grid-template-columns: 1fr 1fr;
580
+ gap: 6px;
581
+ }
582
+ .stat {
583
+ border: 1px solid var(--border);
584
+ border-radius: 8px;
585
+ background: var(--soft);
586
+ padding: 6px;
587
+ min-width: 0;
588
+ }
589
+ .k {
590
+ color: var(--muted);
591
+ text-transform: uppercase;
592
+ letter-spacing: .4px;
593
+ font-size: 10px;
594
+ }
595
+ .v {
596
+ margin-top: 2px;
597
+ font-weight: 700;
598
+ font-size: 13px;
599
+ white-space: nowrap;
600
+ overflow: hidden;
601
+ text-overflow: ellipsis;
602
+ }
603
+ .row {
604
+ margin-top: 8px;
605
+ color: var(--muted);
606
+ font-size: 12px;
607
+ word-break: break-word;
608
+ }
609
+ .spikes {
610
+ list-style: none;
611
+ margin: 0;
612
+ padding: 0;
613
+ display: grid;
614
+ gap: 7px;
615
+ max-height: 34vh;
616
+ overflow: auto;
617
+ }
618
+ .spikes li {
619
+ border: 1px solid #2a3f60;
620
+ border-radius: 8px;
621
+ background: #11203a;
622
+ padding: 7px;
623
+ font-size: 11px;
624
+ line-height: 1.35;
625
+ color: #dbeafe;
626
+ cursor: pointer;
627
+ }
628
+ .spikes li:hover {
629
+ border-color: #3b82f6;
630
+ }
631
+ .tag {
632
+ display: inline-block;
633
+ border: 1px solid #7f1d1d;
634
+ background: #450a0a;
635
+ color: #fca5a5;
636
+ border-radius: 999px;
637
+ font-size: 10px;
638
+ padding: 1px 6px;
639
+ margin-right: 5px;
640
+ margin-top: 3px;
641
+ }
642
+ button {
643
+ border: 1px solid #315685;
644
+ background: #122642;
645
+ color: #dbeafe;
646
+ border-radius: 8px;
647
+ padding: 7px 10px;
648
+ font-size: 12px;
649
+ cursor: pointer;
650
+ }
651
+ button:hover { border-color: #60a5fa; }
652
+ button:disabled { opacity: .55; cursor: not-allowed; }
653
+ @media (max-width: 1080px) {
654
+ .root { grid-template-columns: 1fr; }
655
+ .plot-wrap { height: min(56vh, 560px); }
656
+ .spikes { max-height: 24vh; }
657
+ }
658
+ </style>
659
+ </head>
660
+ <body>
661
+ <div class="root">
662
+ <section class="card">
663
+ <div class="head">
664
+ <div>
665
+ <div class="title">Token + Cost Growth Over Time</div>
666
+ <div class="meta" id="chart-meta"></div>
667
+ </div>
668
+ <span class="pill">Interactive SVG</span>
669
+ </div>
670
+ <div class="plot-wrap">
671
+ <svg id="trend-svg" role="img" aria-label="Token and cost trend over time"></svg>
672
+ </div>
673
+ <div class="legend">
674
+ <span><span class="sw" style="background:var(--token)"></span>Tokens</span>
675
+ <span><span class="sw" style="background:var(--cost)"></span>Cost</span>
676
+ <span><span class="sw" style="background:var(--ma)"></span>Moving Avg</span>
677
+ <span><span class="sw" style="background:var(--spike)"></span>Spike</span>
678
+ </div>
679
+ </section>
680
+
681
+ <aside class="card side">
682
+ <div class="block">
683
+ <div class="title">Selected Bucket</div>
684
+ <div class="row" id="selected-label">Click any point on the chart.</div>
685
+ <div class="stats" id="selected-stats"></div>
686
+ </div>
687
+ <div class="block">
688
+ <button id="ask-ai-btn" type="button" disabled>Ask AI about this growth point</button>
689
+ </div>
690
+ <div class="block">
691
+ <div class="title">Detected Spikes</div>
692
+ <ul id="spike-list" class="spikes"></ul>
693
+ </div>
694
+ <div class="block">
695
+ <div class="meta">Tip: click spike rows to jump highlight in chart.</div>
696
+ </div>
697
+ </aside>
698
+ </div>
699
+
700
+ <script>
701
+ const payload = ${safeJson};
702
+ const buckets = Array.isArray(payload.buckets) ? payload.buckets : [];
703
+ const spikes = Array.isArray(payload.spikes) ? payload.spikes : [];
704
+
705
+ const svg = document.getElementById('trend-svg');
706
+ const chartMetaEl = document.getElementById('chart-meta');
707
+ const selectedLabelEl = document.getElementById('selected-label');
708
+ const selectedStatsEl = document.getElementById('selected-stats');
709
+ const spikeListEl = document.getElementById('spike-list');
710
+ const askAiBtn = document.getElementById('ask-ai-btn');
711
+
712
+ const num = (value) => Number(value || 0);
713
+ const fmtNum = (value) => num(value).toLocaleString();
714
+ const fmtMoney = (value) => '$' + num(value).toFixed(5);
715
+ const esc = (value) => String(value ?? '')
716
+ .replaceAll('&', '&amp;')
717
+ .replaceAll('<', '&lt;')
718
+ .replaceAll('>', '&gt;')
719
+ .replaceAll('"', '&quot;')
720
+ .replaceAll("'", '&#39;');
721
+
722
+ const state = {
723
+ selectedIndex: buckets.length > 0 ? buckets.length - 1 : -1,
724
+ };
725
+
726
+ function renderMeta() {
727
+ chartMetaEl.textContent =
728
+ buckets.length + ' buckets (' + payload.bucketLabel + ') | ' +
729
+ fmtNum(payload.totals.totalTokens) + ' tokens | ' +
730
+ fmtMoney(payload.totals.totalCost) + ' total cost';
731
+ }
732
+
733
+ function setSelected(index) {
734
+ if (index < 0 || index >= buckets.length) {
735
+ state.selectedIndex = -1;
736
+ selectedLabelEl.textContent = 'Click any point on the chart.';
737
+ selectedStatsEl.innerHTML = '';
738
+ askAiBtn.disabled = true;
739
+ return;
740
+ }
741
+ state.selectedIndex = index;
742
+ const bucket = buckets[index];
743
+ selectedLabelEl.textContent = bucket.label;
744
+ selectedStatsEl.innerHTML = [
745
+ '<div class="stat"><div class="k">Tokens</div><div class="v">' + esc(fmtNum(bucket.totalTokens)) + '</div></div>',
746
+ '<div class="stat"><div class="k">Cost</div><div class="v">' + esc(fmtMoney(bucket.cost)) + '</div></div>',
747
+ '<div class="stat"><div class="k">Delta Tokens</div><div class="v">' + esc((bucket.tokenDelta > 0 ? '+' : '') + fmtNum(bucket.tokenDelta)) + '</div></div>',
748
+ '<div class="stat"><div class="k">Delta Cost</div><div class="v">' + esc((bucket.costDelta > 0 ? '+' : '') + fmtMoney(bucket.costDelta)) + '</div></div>',
749
+ '<div class="stat"><div class="k">Requests</div><div class="v">' + esc(fmtNum(bucket.requests)) + '</div></div>',
750
+ '<div class="stat"><div class="k">Top Model</div><div class="v">' + esc(bucket.topModel || 'unknown') + '</div></div>',
751
+ ].join('');
752
+ askAiBtn.disabled = false;
753
+ renderChart();
754
+ }
755
+
756
+ function drawPath(points) {
757
+ if (!points.length) return '';
758
+ let d = 'M ' + points[0].x + ' ' + points[0].y;
759
+ for (let i = 1; i < points.length; i++) {
760
+ d += ' L ' + points[i].x + ' ' + points[i].y;
761
+ }
762
+ return d;
763
+ }
764
+
765
+ function renderChart() {
766
+ const width = Math.max(720, svg.clientWidth || 940);
767
+ const height = Math.max(420, svg.clientHeight || 520);
768
+ const margin = { top: 22, right: 62, bottom: 50, left: 72 };
769
+ const innerWidth = Math.max(220, width - margin.left - margin.right);
770
+ const innerHeight = Math.max(180, height - margin.top - margin.bottom);
771
+
772
+ svg.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
773
+ svg.innerHTML = '';
774
+ if (!buckets.length) {
775
+ return;
776
+ }
777
+
778
+ const maxTokens = Math.max(1, ...buckets.map((bucket) => num(bucket.totalTokens)), ...buckets.map((bucket) => num(bucket.tokenMovingAvg)));
779
+ const maxCost = Math.max(0.000001, ...buckets.map((bucket) => num(bucket.cost)), ...buckets.map((bucket) => num(bucket.costMovingAvg)));
780
+
781
+ const sx = (index) => margin.left + (index / Math.max(1, buckets.length - 1)) * innerWidth;
782
+ const syTokens = (value) => margin.top + innerHeight - (num(value) / maxTokens) * innerHeight;
783
+ const syCost = (value) => margin.top + innerHeight - (num(value) / maxCost) * innerHeight;
784
+
785
+ const make = (name) => document.createElementNS('http://www.w3.org/2000/svg', name);
786
+
787
+ const bg = make('rect');
788
+ bg.setAttribute('x', String(margin.left));
789
+ bg.setAttribute('y', String(margin.top));
790
+ bg.setAttribute('width', String(innerWidth));
791
+ bg.setAttribute('height', String(innerHeight));
792
+ bg.setAttribute('fill', '#081224');
793
+ bg.setAttribute('stroke', '#223452');
794
+ svg.appendChild(bg);
795
+
796
+ const xAxis = make('line');
797
+ xAxis.setAttribute('x1', String(margin.left));
798
+ xAxis.setAttribute('y1', String(margin.top + innerHeight));
799
+ xAxis.setAttribute('x2', String(margin.left + innerWidth));
800
+ xAxis.setAttribute('y2', String(margin.top + innerHeight));
801
+ xAxis.setAttribute('stroke', '#3a4f72');
802
+ svg.appendChild(xAxis);
803
+
804
+ const yAxisLeft = make('line');
805
+ yAxisLeft.setAttribute('x1', String(margin.left));
806
+ yAxisLeft.setAttribute('y1', String(margin.top));
807
+ yAxisLeft.setAttribute('x2', String(margin.left));
808
+ yAxisLeft.setAttribute('y2', String(margin.top + innerHeight));
809
+ yAxisLeft.setAttribute('stroke', '#3a4f72');
810
+ svg.appendChild(yAxisLeft);
811
+
812
+ const yAxisRight = make('line');
813
+ yAxisRight.setAttribute('x1', String(margin.left + innerWidth));
814
+ yAxisRight.setAttribute('y1', String(margin.top));
815
+ yAxisRight.setAttribute('x2', String(margin.left + innerWidth));
816
+ yAxisRight.setAttribute('y2', String(margin.top + innerHeight));
817
+ yAxisRight.setAttribute('stroke', '#3a4f72');
818
+ svg.appendChild(yAxisRight);
819
+
820
+ const tokenPoints = buckets.map((bucket, index) => ({ x: sx(index), y: syTokens(bucket.totalTokens) }));
821
+ const tokenMaPoints = buckets.map((bucket, index) => ({ x: sx(index), y: syTokens(bucket.tokenMovingAvg) }));
822
+ const costPoints = buckets.map((bucket, index) => ({ x: sx(index), y: syCost(bucket.cost) }));
823
+ const costMaPoints = buckets.map((bucket, index) => ({ x: sx(index), y: syCost(bucket.costMovingAvg) }));
824
+
825
+ const tokenPath = make('path');
826
+ tokenPath.setAttribute('d', drawPath(tokenPoints));
827
+ tokenPath.setAttribute('fill', 'none');
828
+ tokenPath.setAttribute('stroke', 'var(--token)');
829
+ tokenPath.setAttribute('stroke-width', '2');
830
+ svg.appendChild(tokenPath);
831
+
832
+ const costPath = make('path');
833
+ costPath.setAttribute('d', drawPath(costPoints));
834
+ costPath.setAttribute('fill', 'none');
835
+ costPath.setAttribute('stroke', 'var(--cost)');
836
+ costPath.setAttribute('stroke-width', '2');
837
+ svg.appendChild(costPath);
838
+
839
+ const maPath = make('path');
840
+ maPath.setAttribute('d', drawPath(tokenMaPoints));
841
+ maPath.setAttribute('fill', 'none');
842
+ maPath.setAttribute('stroke', 'var(--ma)');
843
+ maPath.setAttribute('stroke-width', '1.8');
844
+ maPath.setAttribute('stroke-dasharray', '5 4');
845
+ svg.appendChild(maPath);
846
+
847
+ const maCostPath = make('path');
848
+ maCostPath.setAttribute('d', drawPath(costMaPoints));
849
+ maCostPath.setAttribute('fill', 'none');
850
+ maCostPath.setAttribute('stroke', '#fcd34d');
851
+ maCostPath.setAttribute('stroke-width', '1.4');
852
+ maCostPath.setAttribute('stroke-dasharray', '3 4');
853
+ svg.appendChild(maCostPath);
854
+
855
+ for (let i = 0; i < buckets.length; i++) {
856
+ const bucket = buckets[i];
857
+ const x = sx(i);
858
+ const active = i === state.selectedIndex;
859
+ const spike = spikes.some((row) => row.index === i);
860
+
861
+ const hit = make('rect');
862
+ hit.setAttribute('x', String(x - 5));
863
+ hit.setAttribute('y', String(margin.top));
864
+ hit.setAttribute('width', '10');
865
+ hit.setAttribute('height', String(innerHeight));
866
+ hit.setAttribute('fill', 'transparent');
867
+ hit.style.cursor = 'pointer';
868
+ hit.addEventListener('click', () => setSelected(i));
869
+ svg.appendChild(hit);
870
+
871
+ const tokenDot = make('circle');
872
+ tokenDot.setAttribute('cx', String(x));
873
+ tokenDot.setAttribute('cy', String(syTokens(bucket.totalTokens)));
874
+ tokenDot.setAttribute('r', active ? '4' : '2.8');
875
+ tokenDot.setAttribute('fill', 'var(--token)');
876
+ if (active) {
877
+ tokenDot.setAttribute('stroke', '#ffffff');
878
+ tokenDot.setAttribute('stroke-width', '1.2');
879
+ }
880
+ const title = make('title');
881
+ title.textContent = bucket.label + '\\nTokens: ' + fmtNum(bucket.totalTokens) + '\\nCost: ' + fmtMoney(bucket.cost);
882
+ tokenDot.appendChild(title);
883
+ svg.appendChild(tokenDot);
884
+
885
+ const costDot = make('circle');
886
+ costDot.setAttribute('cx', String(x));
887
+ costDot.setAttribute('cy', String(syCost(bucket.cost)));
888
+ costDot.setAttribute('r', active ? '3.8' : '2.6');
889
+ costDot.setAttribute('fill', 'var(--cost)');
890
+ svg.appendChild(costDot);
891
+
892
+ if (spike) {
893
+ const marker = make('line');
894
+ marker.setAttribute('x1', String(x));
895
+ marker.setAttribute('y1', String(margin.top));
896
+ marker.setAttribute('x2', String(x));
897
+ marker.setAttribute('y2', String(margin.top + innerHeight));
898
+ marker.setAttribute('stroke', 'var(--spike)');
899
+ marker.setAttribute('stroke-opacity', active ? '0.7' : '0.35');
900
+ marker.setAttribute('stroke-dasharray', '2 4');
901
+ svg.appendChild(marker);
902
+ }
903
+ }
904
+
905
+ const leftLabel = make('text');
906
+ leftLabel.setAttribute('x', '16');
907
+ leftLabel.setAttribute('y', String(margin.top + innerHeight / 2));
908
+ leftLabel.setAttribute('transform', 'rotate(-90 16 ' + (margin.top + innerHeight / 2) + ')');
909
+ leftLabel.setAttribute('text-anchor', 'middle');
910
+ leftLabel.setAttribute('fill', '#9fb1cc');
911
+ leftLabel.setAttribute('font-size', '11');
912
+ leftLabel.textContent = 'Tokens';
913
+ svg.appendChild(leftLabel);
914
+
915
+ const rightLabel = make('text');
916
+ rightLabel.setAttribute('x', String(width - 14));
917
+ rightLabel.setAttribute('y', String(margin.top + innerHeight / 2));
918
+ rightLabel.setAttribute('transform', 'rotate(90 ' + (width - 14) + ' ' + (margin.top + innerHeight / 2) + ')');
919
+ rightLabel.setAttribute('text-anchor', 'middle');
920
+ rightLabel.setAttribute('fill', '#9fb1cc');
921
+ rightLabel.setAttribute('font-size', '11');
922
+ rightLabel.textContent = 'Cost';
923
+ svg.appendChild(rightLabel);
924
+
925
+ const xLabel = make('text');
926
+ xLabel.setAttribute('x', String(margin.left + innerWidth / 2));
927
+ xLabel.setAttribute('y', String(height - 14));
928
+ xLabel.setAttribute('text-anchor', 'middle');
929
+ xLabel.setAttribute('fill', '#9fb1cc');
930
+ xLabel.setAttribute('font-size', '11');
931
+ xLabel.textContent = 'Time';
932
+ svg.appendChild(xLabel);
933
+ }
934
+
935
+ function renderSpikeList() {
936
+ if (!spikes.length) {
937
+ spikeListEl.innerHTML = '<li>No major spikes detected for current window.</li>';
938
+ return;
939
+ }
940
+ spikeListEl.innerHTML = spikes.map((spike) => {
941
+ const tags = [
942
+ spike.tokenSpike ? '<span class="tag">TOKEN SPIKE</span>' : '',
943
+ spike.costSpike ? '<span class="tag">COST SPIKE</span>' : '',
944
+ ].join('');
945
+ return '<li data-index="' + spike.index + '">' +
946
+ '<div>' + esc(spike.label) + '</div>' +
947
+ '<div>tokens ' + esc(fmtNum(spike.totalTokens)) + ' | cost ' + esc(fmtMoney(spike.cost)) + '</div>' +
948
+ '<div>requests ' + esc(fmtNum(spike.requests)) + ' | model ' + esc(spike.topModel || 'unknown') + '</div>' +
949
+ tags +
950
+ '</li>';
951
+ }).join('');
952
+
953
+ spikeListEl.querySelectorAll('li[data-index]').forEach((item) => {
954
+ item.addEventListener('click', () => {
955
+ const index = Number(item.getAttribute('data-index') || '-1');
956
+ if (Number.isFinite(index) && index >= 0) {
957
+ setSelected(index);
958
+ }
959
+ });
960
+ });
961
+ }
962
+
963
+ askAiBtn.addEventListener('click', () => {
964
+ if (state.selectedIndex < 0 || state.selectedIndex >= buckets.length) {
965
+ return;
966
+ }
967
+ const bucket = buckets[state.selectedIndex];
968
+ const prompt = [
969
+ 'Investigate token/cost growth point:',
970
+ '- Bucket: ' + bucket.label,
971
+ '- Tokens: ' + fmtNum(bucket.totalTokens),
972
+ '- Cost: ' + fmtMoney(bucket.cost),
973
+ '- Token delta vs previous: ' + (bucket.tokenDelta > 0 ? '+' : '') + fmtNum(bucket.tokenDelta),
974
+ '- Cost delta vs previous: ' + (bucket.costDelta > 0 ? '+' : '') + fmtMoney(bucket.costDelta),
975
+ '- Requests: ' + fmtNum(bucket.requests),
976
+ '- Top model: ' + (bucket.topModel || 'unknown'),
977
+ '- Top session: ' + (bucket.topSession || '(none)'),
978
+ '',
979
+ 'Context:',
980
+ '- Bucket size: ' + payload.bucketLabel,
981
+ '- Median tokens per bucket: ' + fmtNum(payload.tokenMedian),
982
+ '- Median cost per bucket: ' + fmtMoney(payload.costMedian),
983
+ '',
984
+ 'Please identify likely causes for this growth and propose concrete code-level optimizations to reduce token/cost while preserving output quality.',
985
+ ].join('\\n');
986
+ window.parent.postMessage({
987
+ source: 'agentide-wow-widget',
988
+ type: 'openChatWithPrompt',
989
+ prompt,
990
+ }, '*');
991
+ askAiBtn.textContent = 'Prompt sent';
992
+ setTimeout(() => {
993
+ askAiBtn.textContent = 'Ask AI about this growth point';
994
+ }, 1300);
995
+ });
996
+
997
+ renderMeta();
998
+ renderSpikeList();
999
+ setSelected(state.selectedIndex);
1000
+ renderChart();
1001
+ window.addEventListener('resize', () => renderChart());
1002
+ </script>
1003
+ </body>
1004
+ </html>`;
1005
+ }
1006
+
1007
+ function main() {
1008
+ const home = process.env.HOME || '';
1009
+ const tracesDir = process.env.AGENTIDE_TRACES_DIR || path.join(home, '.agent-hippo', 'analytics', 'traces');
1010
+ const chartDir = process.env.AGENTIDE_CHART_DIR || path.join(home, '.agent-hippo', 'analytics', 'views', 'global', '__all', '__all', 'charts');
1011
+ const outputPath = path.join(chartDir, 'token-cost-trend-widget.html');
1012
+ const agentFilterId = String(process.env.AGENTIDE_ANALYTICS_AGENT_ID || '').trim();
1013
+
1014
+ fs.mkdirSync(chartDir, { recursive: true });
1015
+ if (isOutputDisabled('token-cost-trend-widget.html')) {
1016
+ try {
1017
+ fs.unlinkSync(outputPath);
1018
+ } catch {
1019
+ // ignore missing file
1020
+ }
1021
+ return;
1022
+ }
1023
+
1024
+ const { rows, traceCount, fileCount } = loadRows(tracesDir, agentFilterId);
1025
+ if (!rows.length) {
1026
+ const reason = agentFilterId
1027
+ ? `No token/cost trace rows found for agent "${agentFilterId}".`
1028
+ : 'No token/cost trace rows found yet.';
1029
+ fs.writeFileSync(outputPath, buildFallbackHtml(reason), 'utf8');
1030
+ return;
1031
+ }
1032
+
1033
+ const aggregated = aggregateRows(rows);
1034
+ if (!aggregated || !aggregated.buckets.length) {
1035
+ fs.writeFileSync(outputPath, buildFallbackHtml('Trace rows were found, but no time buckets could be generated.'), 'utf8');
1036
+ return;
1037
+ }
1038
+
1039
+ const payload = {
1040
+ version: 1,
1041
+ generatedAt: new Date().toISOString(),
1042
+ agentFilterId: agentFilterId || null,
1043
+ rowCount: rows.length,
1044
+ traceCount,
1045
+ fileCount,
1046
+ bucketSizeMs: aggregated.bucketSizeMs,
1047
+ bucketLabel: aggregated.bucketSizeMs >= 24 * 60 * 60 * 1000
1048
+ ? `${Math.round(aggregated.bucketSizeMs / (24 * 60 * 60 * 1000))} day`
1049
+ : `${Math.round(aggregated.bucketSizeMs / (60 * 60 * 1000))} hour`,
1050
+ totals: aggregated.totals,
1051
+ tokenMedian: Math.round(aggregated.tokenMedian),
1052
+ costMedian: Number(aggregated.costMedian.toFixed(6)),
1053
+ tokenSpikeThreshold: Math.round(aggregated.tokenSpikeThreshold),
1054
+ costSpikeThreshold: Number(aggregated.costSpikeThreshold.toFixed(6)),
1055
+ spikes: aggregated.spikes,
1056
+ buckets: aggregated.buckets,
1057
+ };
1058
+
1059
+ fs.writeFileSync(outputPath, buildHtml(payload), 'utf8');
1060
+ }
1061
+
1062
+ main();