argus-code 0.4.1__tar.gz → 0.4.2__tar.gz

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 (184) hide show
  1. {argus_code-0.4.1 → argus_code-0.4.2}/PKG-INFO +1 -1
  2. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/pages/session.astro +99 -19
  3. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/scripts/api.ts +18 -0
  4. argus_code-0.4.1/dashboard-dist/_astro/charts.CQF9QNgP.js → argus_code-0.4.2/dashboard-dist/_astro/charts.36uaSAWt.js +1 -1
  5. argus_code-0.4.2/dashboard-dist/_astro/format.BexCUztC.js +1 -0
  6. argus_code-0.4.1/dashboard-dist/_astro/index.astro_astro_type_script_index_0_lang.cnW_pvh0.js → argus_code-0.4.2/dashboard-dist/_astro/index.astro_astro_type_script_index_0_lang.BF0nZzma.js +1 -1
  7. argus_code-0.4.1/dashboard-dist/_astro/index.astro_astro_type_script_index_0_lang.UFVBMlig.js → argus_code-0.4.2/dashboard-dist/_astro/index.astro_astro_type_script_index_0_lang.D-QKQJAF.js +1 -1
  8. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard-dist/_astro/installCanvasRenderer.XK5yP7fW.js +18 -18
  9. argus_code-0.4.1/dashboard-dist/_astro/models.astro_astro_type_script_index_0_lang.DsSR6D_a.js → argus_code-0.4.2/dashboard-dist/_astro/models.astro_astro_type_script_index_0_lang.0Aczy7Vm.js +1 -1
  10. argus_code-0.4.1/dashboard-dist/_astro/prompts.astro_astro_type_script_index_0_lang.C0Mv7sTw.js → argus_code-0.4.2/dashboard-dist/_astro/prompts.astro_astro_type_script_index_0_lang.B1i5N4zM.js +1 -1
  11. argus_code-0.4.2/dashboard-dist/_astro/session.astro_astro_type_script_index_0_lang.SRsknMTL.js +126 -0
  12. argus_code-0.4.1/dashboard-dist/_astro/settings.astro_astro_type_script_index_0_lang.Cs7bzN_0.js → argus_code-0.4.2/dashboard-dist/_astro/settings.astro_astro_type_script_index_0_lang.BLXx3usF.js +1 -1
  13. argus_code-0.4.1/dashboard-dist/_astro/tools.astro_astro_type_script_index_0_lang.DTzvpY-G.js → argus_code-0.4.2/dashboard-dist/_astro/tools.astro_astro_type_script_index_0_lang.OvyHH6MH.js +1 -1
  14. argus_code-0.4.1/dashboard-dist/_astro/trends.astro_astro_type_script_index_0_lang.5olZlQfw.js → argus_code-0.4.2/dashboard-dist/_astro/trends.astro_astro_type_script_index_0_lang.CBtUcxGK.js +1 -1
  15. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard-dist/index.html +1 -1
  16. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard-dist/models/index.html +1 -1
  17. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard-dist/prompts/index.html +1 -1
  18. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard-dist/session/index.html +2 -2
  19. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard-dist/sessions/index.html +1 -1
  20. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard-dist/settings/index.html +1 -1
  21. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard-dist/tools/index.html +1 -1
  22. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard-dist/trends/index.html +1 -1
  23. {argus_code-0.4.1 → argus_code-0.4.2}/pyproject.toml +1 -1
  24. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/__init__.py +1 -1
  25. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/server/api.py +19 -11
  26. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/server/app.py +17 -1
  27. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/store/repository.py +68 -0
  28. {argus_code-0.4.1 → argus_code-0.4.2}/tests/server/test_api.py +42 -0
  29. {argus_code-0.4.1 → argus_code-0.4.2}/tests/server/test_server.py +40 -0
  30. {argus_code-0.4.1 → argus_code-0.4.2}/tests/store/test_repository.py +48 -0
  31. {argus_code-0.4.1 → argus_code-0.4.2}/uv.lock +1 -1
  32. argus_code-0.4.1/dashboard-dist/_astro/format.CgLh3UFa.js +0 -1
  33. argus_code-0.4.1/dashboard-dist/_astro/session.astro_astro_type_script_index_0_lang.IkwnKMSS.js +0 -114
  34. {argus_code-0.4.1 → argus_code-0.4.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  35. {argus_code-0.4.1 → argus_code-0.4.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  36. {argus_code-0.4.1 → argus_code-0.4.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  37. {argus_code-0.4.1 → argus_code-0.4.2}/.github/pull_request_template.md +0 -0
  38. {argus_code-0.4.1 → argus_code-0.4.2}/.gitignore +0 -0
  39. {argus_code-0.4.1 → argus_code-0.4.2}/.npmrc +0 -0
  40. {argus_code-0.4.1 → argus_code-0.4.2}/ARCHITECTURE.md +0 -0
  41. {argus_code-0.4.1 → argus_code-0.4.2}/CONTRIBUTING.md +0 -0
  42. {argus_code-0.4.1 → argus_code-0.4.2}/LICENSE +0 -0
  43. {argus_code-0.4.1 → argus_code-0.4.2}/NOTICE +0 -0
  44. {argus_code-0.4.1 → argus_code-0.4.2}/PRD.md +0 -0
  45. {argus_code-0.4.1 → argus_code-0.4.2}/README.md +0 -0
  46. {argus_code-0.4.1 → argus_code-0.4.2}/SECURITY.md +0 -0
  47. {argus_code-0.4.1 → argus_code-0.4.2}/TESTING.md +0 -0
  48. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/.astro/content-assets.mjs +0 -0
  49. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/.astro/content-modules.mjs +0 -0
  50. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/.astro/content.d.ts +0 -0
  51. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/.astro/types.d.ts +0 -0
  52. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/astro.config.mjs +0 -0
  53. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/package-lock.json +0 -0
  54. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/package.json +0 -0
  55. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/public/styles/global.css +0 -0
  56. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/layouts/Default.astro +0 -0
  57. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/pages/index.astro +0 -0
  58. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/pages/models.astro +0 -0
  59. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/pages/prompts.astro +0 -0
  60. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/pages/sessions/index.astro +0 -0
  61. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/pages/settings.astro +0 -0
  62. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/pages/tools.astro +0 -0
  63. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/pages/trends.astro +0 -0
  64. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/scripts/alerts.ts +0 -0
  65. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/scripts/charts.ts +0 -0
  66. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/scripts/format.ts +0 -0
  67. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/src/styles/global.css +0 -0
  68. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard/tsconfig.json +0 -0
  69. {argus_code-0.4.1 → argus_code-0.4.2}/dashboard-dist/styles/global.css +0 -0
  70. {argus_code-0.4.1 → argus_code-0.4.2}/pricing/2026-05-02.json +0 -0
  71. {argus_code-0.4.1 → argus_code-0.4.2}/pricing/2026-06-12.json +0 -0
  72. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/adapters/__init__.py +0 -0
  73. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/adapters/base.py +0 -0
  74. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/adapters/claude_code/__init__.py +0 -0
  75. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/adapters/claude_code/adapter.py +0 -0
  76. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/adapters/claude_code/discover.py +0 -0
  77. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/adapters/claude_code/extract_tool_calls.py +0 -0
  78. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/adapters/claude_code/extract_transcript.py +0 -0
  79. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/adapters/claude_code/extract_turns.py +0 -0
  80. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/adapters/claude_code/history_jsonl.py +0 -0
  81. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/adapters/claude_code/ingest_file.py +0 -0
  82. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/adapters/claude_code/model.py +0 -0
  83. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/adapters/claude_code/schemas.py +0 -0
  84. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/adapters/registry.py +0 -0
  85. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/cli.py +0 -0
  86. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/collector/__init__.py +0 -0
  87. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/collector/aggregate.py +0 -0
  88. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/collector/first_run.py +0 -0
  89. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/collector/pipeline.py +0 -0
  90. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/collector/rollup_subagents.py +0 -0
  91. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/collector/scheduler.py +0 -0
  92. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/collector/search_backfill.py +0 -0
  93. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/collector/watcher.py +0 -0
  94. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/core/__init__.py +0 -0
  95. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/core/runtime.py +0 -0
  96. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/daemon/__init__.py +0 -0
  97. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/daemon/logging.py +0 -0
  98. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/daemon/pidfile.py +0 -0
  99. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/daemon/process.py +0 -0
  100. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/daemon/service.py +0 -0
  101. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/detectors/__init__.py +0 -0
  102. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/detectors/base.py +0 -0
  103. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/detectors/registry.py +0 -0
  104. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/detectors/tool_error_rate_spike.py +0 -0
  105. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/pricing/__init__.py +0 -0
  106. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/pricing/compute.py +0 -0
  107. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/pricing/load.py +0 -0
  108. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/pricing/refresh.py +0 -0
  109. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/pricing/types.py +0 -0
  110. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/scaffold/__init__.py +0 -0
  111. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/scaffold/scaffolder.py +0 -0
  112. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/scaffold/snapshot.py +0 -0
  113. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/scaffold/storage.py +0 -0
  114. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/schema/__init__.py +0 -0
  115. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/schema/types.py +0 -0
  116. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/server/__init__.py +0 -0
  117. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/store/__init__.py +0 -0
  118. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/store/db.py +0 -0
  119. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/store/migrations/__init__.py +0 -0
  120. {argus_code-0.4.1 → argus_code-0.4.2}/python/argus/store/migrations/inline.py +0 -0
  121. {argus_code-0.4.1 → argus_code-0.4.2}/templates/default/.claude/agents/code-reviewer.md +0 -0
  122. {argus_code-0.4.1 → argus_code-0.4.2}/templates/default/.claude/agents/security-auditor.md +0 -0
  123. {argus_code-0.4.1 → argus_code-0.4.2}/templates/default/.claude/commands/commit.md +0 -0
  124. {argus_code-0.4.1 → argus_code-0.4.2}/templates/default/.claude/commands/deploy.md +0 -0
  125. {argus_code-0.4.1 → argus_code-0.4.2}/templates/default/.claude/commands/fix-issue.md +0 -0
  126. {argus_code-0.4.1 → argus_code-0.4.2}/templates/default/.claude/commands/pr.md +0 -0
  127. {argus_code-0.4.1 → argus_code-0.4.2}/templates/default/.claude/commands/review.md +0 -0
  128. {argus_code-0.4.1 → argus_code-0.4.2}/templates/default/.claude/rules/api-conventions.md +0 -0
  129. {argus_code-0.4.1 → argus_code-0.4.2}/templates/default/.claude/rules/code-style.md +0 -0
  130. {argus_code-0.4.1 → argus_code-0.4.2}/templates/default/.claude/rules/testing.md +0 -0
  131. {argus_code-0.4.1 → argus_code-0.4.2}/templates/default/.claude/settings.json +0 -0
  132. {argus_code-0.4.1 → argus_code-0.4.2}/templates/default/.claude/skills/example/SKILL.md +0 -0
  133. {argus_code-0.4.1 → argus_code-0.4.2}/templates/default/CLAUDE.md +0 -0
  134. {argus_code-0.4.1 → argus_code-0.4.2}/tests/__init__.py +0 -0
  135. {argus_code-0.4.1 → argus_code-0.4.2}/tests/adapters/__init__.py +0 -0
  136. {argus_code-0.4.1 → argus_code-0.4.2}/tests/adapters/claude_code/__init__.py +0 -0
  137. {argus_code-0.4.1 → argus_code-0.4.2}/tests/adapters/claude_code/test_adapter.py +0 -0
  138. {argus_code-0.4.1 → argus_code-0.4.2}/tests/adapters/claude_code/test_discover.py +0 -0
  139. {argus_code-0.4.1 → argus_code-0.4.2}/tests/adapters/claude_code/test_extract_tool_calls.py +0 -0
  140. {argus_code-0.4.1 → argus_code-0.4.2}/tests/adapters/claude_code/test_extract_transcript.py +0 -0
  141. {argus_code-0.4.1 → argus_code-0.4.2}/tests/adapters/claude_code/test_extract_turns.py +0 -0
  142. {argus_code-0.4.1 → argus_code-0.4.2}/tests/adapters/claude_code/test_history_jsonl.py +0 -0
  143. {argus_code-0.4.1 → argus_code-0.4.2}/tests/adapters/claude_code/test_ingest_file.py +0 -0
  144. {argus_code-0.4.1 → argus_code-0.4.2}/tests/adapters/claude_code/test_integration.py +0 -0
  145. {argus_code-0.4.1 → argus_code-0.4.2}/tests/adapters/claude_code/test_model.py +0 -0
  146. {argus_code-0.4.1 → argus_code-0.4.2}/tests/adapters/claude_code/test_schemas.py +0 -0
  147. {argus_code-0.4.1 → argus_code-0.4.2}/tests/adapters/test_registry.py +0 -0
  148. {argus_code-0.4.1 → argus_code-0.4.2}/tests/collector/__init__.py +0 -0
  149. {argus_code-0.4.1 → argus_code-0.4.2}/tests/collector/test_aggregate.py +0 -0
  150. {argus_code-0.4.1 → argus_code-0.4.2}/tests/collector/test_first_run.py +0 -0
  151. {argus_code-0.4.1 → argus_code-0.4.2}/tests/collector/test_pipeline.py +0 -0
  152. {argus_code-0.4.1 → argus_code-0.4.2}/tests/collector/test_rollup_subagents.py +0 -0
  153. {argus_code-0.4.1 → argus_code-0.4.2}/tests/collector/test_scheduler.py +0 -0
  154. {argus_code-0.4.1 → argus_code-0.4.2}/tests/collector/test_watcher.py +0 -0
  155. {argus_code-0.4.1 → argus_code-0.4.2}/tests/conftest.py +0 -0
  156. {argus_code-0.4.1 → argus_code-0.4.2}/tests/core/__init__.py +0 -0
  157. {argus_code-0.4.1 → argus_code-0.4.2}/tests/core/test_runtime.py +0 -0
  158. {argus_code-0.4.1 → argus_code-0.4.2}/tests/daemon/__init__.py +0 -0
  159. {argus_code-0.4.1 → argus_code-0.4.2}/tests/daemon/test_logs.py +0 -0
  160. {argus_code-0.4.1 → argus_code-0.4.2}/tests/daemon/test_pidfile.py +0 -0
  161. {argus_code-0.4.1 → argus_code-0.4.2}/tests/daemon/test_process.py +0 -0
  162. {argus_code-0.4.1 → argus_code-0.4.2}/tests/daemon/test_service.py +0 -0
  163. {argus_code-0.4.1 → argus_code-0.4.2}/tests/daemon/test_yield.py +0 -0
  164. {argus_code-0.4.1 → argus_code-0.4.2}/tests/detectors/__init__.py +0 -0
  165. {argus_code-0.4.1 → argus_code-0.4.2}/tests/detectors/test_registry.py +0 -0
  166. {argus_code-0.4.1 → argus_code-0.4.2}/tests/detectors/test_tool_error_rate_spike.py +0 -0
  167. {argus_code-0.4.1 → argus_code-0.4.2}/tests/pricing/__init__.py +0 -0
  168. {argus_code-0.4.1 → argus_code-0.4.2}/tests/pricing/test_compute.py +0 -0
  169. {argus_code-0.4.1 → argus_code-0.4.2}/tests/pricing/test_load.py +0 -0
  170. {argus_code-0.4.1 → argus_code-0.4.2}/tests/pricing/test_refresh.py +0 -0
  171. {argus_code-0.4.1 → argus_code-0.4.2}/tests/scaffold/__init__.py +0 -0
  172. {argus_code-0.4.1 → argus_code-0.4.2}/tests/scaffold/test_bundled_template.py +0 -0
  173. {argus_code-0.4.1 → argus_code-0.4.2}/tests/scaffold/test_cli_claude.py +0 -0
  174. {argus_code-0.4.1 → argus_code-0.4.2}/tests/scaffold/test_scaffolder.py +0 -0
  175. {argus_code-0.4.1 → argus_code-0.4.2}/tests/scaffold/test_snapshot.py +0 -0
  176. {argus_code-0.4.1 → argus_code-0.4.2}/tests/scaffold/test_storage.py +0 -0
  177. {argus_code-0.4.1 → argus_code-0.4.2}/tests/schema/__init__.py +0 -0
  178. {argus_code-0.4.1 → argus_code-0.4.2}/tests/schema/test_types.py +0 -0
  179. {argus_code-0.4.1 → argus_code-0.4.2}/tests/server/__init__.py +0 -0
  180. {argus_code-0.4.1 → argus_code-0.4.2}/tests/server/test_api_search.py +0 -0
  181. {argus_code-0.4.1 → argus_code-0.4.2}/tests/server/test_week_of.py +0 -0
  182. {argus_code-0.4.1 → argus_code-0.4.2}/tests/store/__init__.py +0 -0
  183. {argus_code-0.4.1 → argus_code-0.4.2}/tests/store/test_db.py +0 -0
  184. {argus_code-0.4.1 → argus_code-0.4.2}/tests/test_e2e.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: argus-code
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: Local-first dashboard for Claude Code cost, token, tool-usage, and full-text search analytics
5
5
  Project-URL: Homepage, https://github.com/KrishBhimani/argus-code
6
6
  Project-URL: Repository, https://github.com/KrishBhimani/argus-code.git
@@ -6,6 +6,7 @@ import Default from '../layouts/Default.astro';
6
6
  <div class="sd-tabs">
7
7
  <button id="tab-btn-overview" class="sd-tab active" type="button">Overview</button>
8
8
  <button id="tab-btn-timeline" class="sd-tab" type="button">Timeline</button>
9
+ <button id="tab-btn-subagents" class="sd-tab" type="button" style="display:none;">Sub-agents</button>
9
10
  </div>
10
11
  <div id="content">
11
12
  <div class="card"><div class="skel" style="width:60%;height:1.5em;"></div></div>
@@ -13,6 +14,7 @@ import Default from '../layouts/Default.astro';
13
14
  <div id="timeline-content" style="display:none;">
14
15
  <div class="card"><div class="skel" style="width:60%;height:1.5em;"></div></div>
15
16
  </div>
17
+ <div id="subagents-content" style="display:none;"></div>
16
18
  <button id="to-top" type="button" title="Back to top">↑</button>
17
19
 
18
20
  <!--
@@ -116,10 +118,28 @@ import Default from '../layouts/Default.astro';
116
118
  display: none; box-shadow: 0 4px 12px rgba(0,0,0,0.4);
117
119
  }
118
120
  #to-top:hover { color: var(--text-0); border-color: var(--accent, #f0883e); }
121
+ .sa-wrap { display: grid; grid-template-columns: 38% 62%; gap: 1rem; align-items: start; }
122
+ .sa-list { display: flex; flex-direction: column; gap: 2px; }
123
+ .sa-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.45rem 0.55rem; border-radius: 7px; cursor: pointer; font-size: 0.84rem; }
124
+ .sa-row:hover { background: var(--bg-2); }
125
+ .sa-row.sel { background: var(--bg-2); box-shadow: inset 0 0 0 1px var(--border); }
126
+ .sa-dot { font-weight: 700; }
127
+ .sa-dot.ok { color: var(--good); }
128
+ .sa-dot.error { color: #f85149; }
129
+ .sa-meta { margin-left: auto; color: var(--text-2); font-size: 0.76rem; white-space: nowrap; }
130
+ .sa-detail { padding: 1rem; }
131
+ .sa-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; margin-bottom: 0.8rem; }
132
+ .sa-stats > div { background: var(--bg-2); border-radius: 8px; padding: 0.5rem 0.6rem; }
133
+ .sa-stats span { display: block; color: var(--text-2); font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.03em; }
134
+ .sa-stats b { font-size: 1rem; }
135
+ .sa-task { background: var(--bg-2); border-radius: 7px; padding: 0.6rem 0.7rem; font-size: 0.85rem; margin-bottom: 0.4rem; line-height: 1.4; word-break: break-word; }
136
+ .sa-tool { display: flex; justify-content: space-between; font-size: 0.82rem; padding: 0.25rem 0.4rem; border-radius: 5px; color: var(--text-1); }
137
+ .sa-tool.bad { background: rgba(248,81,73,0.1); color: #f85149; }
138
+ .sa-open { display: inline-block; margin-top: 0.8rem; color: var(--accent, #f0883e); font-size: 0.85rem; }
119
139
  </style>
120
140
 
121
141
  <script>
122
- import { api, type Turn, type TimelineTurn } from '../scripts/api';
142
+ import { api, type Turn, type TimelineTurn, type SubagentSummary } from '../scripts/api';
123
143
  import { turnTokensBar } from '../scripts/charts';
124
144
  import { usd, tok, num, dur, escapeHtml } from '../scripts/format';
125
145
 
@@ -172,6 +192,12 @@ import Default from '../layouts/Default.astro';
172
192
  const reportedDelta = s.agent_reported_cost_usd != null
173
193
  ? `<span style="color:var(--text-2);font-size:0.8rem;"> (agent reported: ${usd(s.agent_reported_cost_usd)})</span>` : '';
174
194
 
195
+ if (subAgents?.length) {
196
+ const subBtn = document.getElementById('tab-btn-subagents')!;
197
+ subBtn.textContent = `Sub-agents (${subAgents.length})`;
198
+ subBtn.style.display = '';
199
+ }
200
+
175
201
  root.innerHTML = `
176
202
  <div class="grid-cards" style="margin-bottom:1.2rem;">
177
203
  <div class="card kpi"><span class="kpi-label">Tokens</span><span class="kpi-value tokens">${tok(totalTokens)}</span><span class="kpi-sub">${num(totalTokens)} total${subAgents?.length ? ` · incl. ${subAgents.length} sub-agent${subAgents.length === 1 ? '' : 's'}` : ''}</span></div>
@@ -199,14 +225,6 @@ import Default from '../layouts/Default.astro';
199
225
  </table>
200
226
  </div>
201
227
 
202
- ${subAgents?.length ? `
203
- <div class="card" style="margin-bottom:1rem;">
204
- <h3>Sub-agents (${subAgents.length})</h3>
205
- <ul style="margin:0;padding-left:1.2rem;color:var(--text-1);font-size:0.88rem;">
206
- ${subAgents.map(id => `<li><a href="/session?id=${encodeURIComponent(id)}" class="mono">${escapeHtml(id)}</a></li>`).join('')}
207
- </ul>
208
- </div>` : ''}
209
-
210
228
  <div class="card" style="margin-bottom:1rem;">
211
229
  <div style="display:flex;gap:0.6rem;align-items:center;flex-wrap:wrap;">
212
230
  <h3 style="margin:0;flex-shrink:0;">Search this session</h3>
@@ -303,23 +321,26 @@ import Default from '../layouts/Default.astro';
303
321
  // ─── Tabs ───────────────────────────────────────────────────────
304
322
  const overviewPane = document.getElementById('content')!;
305
323
  const timelinePane = document.getElementById('timeline-content')!;
324
+ const subagentsPane = document.getElementById('subagents-content')!;
306
325
  const btnOverview = document.getElementById('tab-btn-overview')!;
307
326
  const btnTimeline = document.getElementById('tab-btn-timeline')!;
327
+ const btnSubagents = document.getElementById('tab-btn-subagents')!;
308
328
  let timelineLoaded = false;
329
+ let subagentsLoaded = false;
309
330
 
310
- function showTab(tab: 'overview' | 'timeline') {
311
- const onOverview = tab === 'overview';
312
- overviewPane.style.display = onOverview ? '' : 'none';
313
- timelinePane.style.display = onOverview ? 'none' : '';
314
- btnOverview.classList.toggle('active', onOverview);
315
- btnTimeline.classList.toggle('active', !onOverview);
316
- if (!onOverview && !timelineLoaded) {
317
- timelineLoaded = true;
318
- loadTimeline();
319
- }
331
+ function showTab(tab: 'overview' | 'timeline' | 'subagents') {
332
+ overviewPane.style.display = tab === 'overview' ? '' : 'none';
333
+ timelinePane.style.display = tab === 'timeline' ? '' : 'none';
334
+ subagentsPane.style.display = tab === 'subagents' ? '' : 'none';
335
+ btnOverview.classList.toggle('active', tab === 'overview');
336
+ btnTimeline.classList.toggle('active', tab === 'timeline');
337
+ btnSubagents.classList.toggle('active', tab === 'subagents');
338
+ if (tab === 'timeline' && !timelineLoaded) { timelineLoaded = true; loadTimeline(); }
339
+ if (tab === 'subagents' && !subagentsLoaded) { subagentsLoaded = true; renderSubagents(); }
320
340
  }
321
341
  btnOverview.addEventListener('click', () => showTab('overview'));
322
342
  btnTimeline.addEventListener('click', () => showTab('timeline'));
343
+ btnSubagents.addEventListener('click', () => showTab('subagents'));
323
344
 
324
345
  // ─── Timeline tab ───────────────────────────────────────────────
325
346
  // "Burn" = tokens this turn actually generated/consumed at full rate.
@@ -463,6 +484,65 @@ import Default from '../layouts/Default.astro';
463
484
  });
464
485
  }
465
486
 
487
+ // ─── Sub-agents tab ─────────────────────────────────────────────
488
+ function saDetail(sa: SubagentSummary): string {
489
+ const tools = sa.tools.length
490
+ ? sa.tools.map(t => `<div class="sa-tool${t.errors ? ' bad' : ''}"><span>${escapeHtml(t.name)}</span><span>×${t.count}${t.errors ? ` · ${t.errors} failed` : ''}</span></div>`).join('')
491
+ : '<p class="sd-no-tools">No tool calls recorded.</p>';
492
+ return `
493
+ <div class="sa-stats">
494
+ <div><span>Turns</span><b>${num(sa.turns)}</b></div>
495
+ <div><span>Tool calls</span><b>${num(sa.tool_calls)}</b></div>
496
+ <div><span>Tokens</span><b>${tok(sa.total_tokens)}</b></div>
497
+ <div><span>Cost (est.)</span><b>~${usd(sa.cost_usd)}</b></div>
498
+ <div><span>Duration</span><b>${dur(sa.duration_sec)}</b></div>
499
+ <div><span>Errors</span><b>${num(sa.errors)}</b></div>
500
+ </div>
501
+ <div class="sa-task"><b>Task given →</b> ${sa.task_given ? escapeHtml(sa.task_given) : '<span class="sd-no-tools">not available (transcript not indexed)</span>'}</div>
502
+ <h4 style="margin:0.6rem 0 0.3rem;">Tools used</h4>${tools}
503
+ <a class="sa-open" href="/session?id=${encodeURIComponent(sa.id)}">Open full timeline for this sub-agent →</a>`;
504
+ }
505
+
506
+ async function renderSubagents() {
507
+ subagentsPane.innerHTML = '<p class="empty">Loading sub-agents…</p>';
508
+ let subs: SubagentSummary[] = [];
509
+ try {
510
+ subs = (await api.subagents(id!)).subagents;
511
+ } catch {
512
+ subagentsPane.innerHTML = '<p class="empty">Sub-agents unavailable.</p>';
513
+ return;
514
+ }
515
+ if (!subs.length) {
516
+ subagentsPane.innerHTML = '<p class="empty">No sub-agents.</p>';
517
+ return;
518
+ }
519
+ const rows = subs.map((sa, i) => {
520
+ const dotTitle = sa.status === 'error'
521
+ ? `${sa.errors} failed tool call${sa.errors === 1 ? '' : 's'}`
522
+ : 'no failed tool calls';
523
+ const dot = sa.status === 'error' ? `✗ ${num(sa.errors)}` : '✓';
524
+ return `
525
+ <div class="sa-row${i === 0 ? ' sel' : ''}" data-i="${i}">
526
+ <span class="sa-dot ${sa.status}" title="${dotTitle}">${dot}</span>
527
+ <code class="mono">${escapeHtml(sa.model)}</code>
528
+ <span class="sa-meta">${num(sa.tool_calls)} tools · ${tok(sa.total_tokens)}</span>
529
+ </div>`;
530
+ }).join('');
531
+ subagentsPane.innerHTML = `
532
+ <div class="sa-wrap">
533
+ <div class="sa-list">${rows}</div>
534
+ <div class="card sa-detail" id="sa-detail">${saDetail(subs[0])}</div>
535
+ </div>`;
536
+ const detail = document.getElementById('sa-detail')!;
537
+ subagentsPane.querySelectorAll<HTMLElement>('.sa-row').forEach(rowEl => {
538
+ rowEl.addEventListener('click', () => {
539
+ subagentsPane.querySelectorAll('.sa-row').forEach(e => e.classList.remove('sel'));
540
+ rowEl.classList.add('sel');
541
+ detail.innerHTML = saDetail(subs[Number(rowEl.dataset.i)]);
542
+ });
543
+ });
544
+ }
545
+
466
546
  // ─── Back-to-top ──────────────────────────────────────────────────
467
547
  const toTop = document.getElementById('to-top')!;
468
548
  let toTopVisible = false;
@@ -73,6 +73,21 @@ export interface ToolsOverview {
73
73
  subagents: { type: string; calls: number; errors: number }[];
74
74
  }
75
75
 
76
+ export interface SubagentSummary {
77
+ id: string;
78
+ model: string;
79
+ status: 'ok' | 'error';
80
+ turns: number;
81
+ tool_calls: number;
82
+ errors: number;
83
+ tokens: { fresh_input: number; output: number; cache_read: number; cache_write: number };
84
+ total_tokens: number;
85
+ cost_usd: number;
86
+ duration_sec: number | null;
87
+ task_given: string | null;
88
+ tools: { name: string; count: number; errors: number }[];
89
+ }
90
+
76
91
  export interface PromptHit {
77
92
  id: number;
78
93
  timestamp_ms: number;
@@ -105,6 +120,9 @@ export const api = {
105
120
  sessionToolOutput: (id: string, toolUseId: string) =>
106
121
  fetch(`/api/sessions/${encodeURIComponent(id)}/tool-output/${encodeURIComponent(toolUseId)}`)
107
122
  .then(r => r.ok ? r.json() as Promise<{ search_enabled: boolean; found: boolean; text: string | null }> : null),
123
+ subagents: (id: string) =>
124
+ fetch(`/api/sessions/${encodeURIComponent(id)}/subagents`)
125
+ .then(r => r.json() as Promise<{ subagents: SubagentSummary[] }>),
108
126
  overview: (window: string) => fetch('/api/overview?window=' + window).then(r => r.json() as Promise<Overview>),
109
127
  trends: (granularity: string, groupBy: string) => fetch(`/api/trends?granularity=${granularity}&groupBy=${groupBy}`).then(r => r.json() as Promise<{ points: { bucket: string; groups: Record<string, { cost: number; tokens: number; sessions: number }> }[] }>),
110
128
  pricing: () => fetch('/api/pricing').then(r => r.json() as Promise<{ version: string }>),