argus-code 0.5.0__tar.gz → 0.5.1__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 (337) hide show
  1. {argus_code-0.5.0 → argus_code-0.5.1}/PKG-INFO +1 -1
  2. {argus_code-0.5.0 → argus_code-0.5.1}/pyproject.toml +1 -1
  3. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/AGENTS.md +10 -0
  4. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/__init__.py +1 -1
  5. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/core/runtime.py +40 -5
  6. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/daemon/service.py +10 -2
  7. argus_code-0.5.1/tests/daemon/test_no_claude_dir.py +162 -0
  8. {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/test_service.py +13 -1
  9. {argus_code-0.5.0 → argus_code-0.5.1}/uv.lock +983 -983
  10. {argus_code-0.5.0 → argus_code-0.5.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  11. {argus_code-0.5.0 → argus_code-0.5.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  12. {argus_code-0.5.0 → argus_code-0.5.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  13. {argus_code-0.5.0 → argus_code-0.5.1}/.github/pull_request_template.md +0 -0
  14. {argus_code-0.5.0 → argus_code-0.5.1}/.github/workflows/test.yml +0 -0
  15. {argus_code-0.5.0 → argus_code-0.5.1}/.gitignore +0 -0
  16. {argus_code-0.5.0 → argus_code-0.5.1}/.npmrc +0 -0
  17. {argus_code-0.5.0 → argus_code-0.5.1}/AGENTS.md +0 -0
  18. {argus_code-0.5.0 → argus_code-0.5.1}/ARCHITECTURE.md +0 -0
  19. {argus_code-0.5.0 → argus_code-0.5.1}/CLAUDE.md +0 -0
  20. {argus_code-0.5.0 → argus_code-0.5.1}/CONTRIBUTING.md +0 -0
  21. {argus_code-0.5.0 → argus_code-0.5.1}/LICENSE +0 -0
  22. {argus_code-0.5.0 → argus_code-0.5.1}/NOTICE +0 -0
  23. {argus_code-0.5.0 → argus_code-0.5.1}/PRD.md +0 -0
  24. {argus_code-0.5.0 → argus_code-0.5.1}/README.md +0 -0
  25. {argus_code-0.5.0 → argus_code-0.5.1}/SECURITY.md +0 -0
  26. {argus_code-0.5.0 → argus_code-0.5.1}/TESTING.md +0 -0
  27. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/.astro/content-assets.mjs +0 -0
  28. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/.astro/content-modules.mjs +0 -0
  29. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/.astro/content.d.ts +0 -0
  30. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/.astro/types.d.ts +0 -0
  31. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/AGENTS.md +0 -0
  32. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/e2e/smoke.spec.ts +0 -0
  33. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/index.html +0 -0
  34. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/package-lock.json +0 -0
  35. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/package.json +0 -0
  36. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/playwright.config.ts +0 -0
  37. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/scripts/size.mjs +0 -0
  38. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/App.test.tsx +0 -0
  39. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/queryClient.ts +0 -0
  40. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/router.tsx +0 -0
  41. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/shell/CommandPalette.test.tsx +0 -0
  42. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/shell/CommandPalette.tsx +0 -0
  43. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/shell/Shell.tsx +0 -0
  44. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/shell/Sidebar.test.tsx +0 -0
  45. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/shell/Sidebar.tsx +0 -0
  46. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/shell/TopBar.tsx +0 -0
  47. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/AlertStrip.tsx +0 -0
  48. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/AreaLine.test.tsx +0 -0
  49. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/AreaLine.tsx +0 -0
  50. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Bars.test.tsx +0 -0
  51. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Bars.tsx +0 -0
  52. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/CalendarHeatmap.test.tsx +0 -0
  53. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/CalendarHeatmap.tsx +0 -0
  54. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/ChartTable.tsx +0 -0
  55. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/GridHeatmap.tsx +0 -0
  56. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Legend.tsx +0 -0
  57. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Meter.test.tsx +0 -0
  58. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Meter.tsx +0 -0
  59. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Minimap.test.tsx +0 -0
  60. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Minimap.tsx +0 -0
  61. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/MultiLine.tsx +0 -0
  62. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/README.md +0 -0
  63. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Scatter.tsx +0 -0
  64. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Sparkline.tsx +0 -0
  65. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/StackedColumns.tsx +0 -0
  66. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/UPlotChart.tsx +0 -0
  67. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/ramp.ts +0 -0
  68. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/uplotTheme.ts +0 -0
  69. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Button.tsx +0 -0
  70. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Chip.tsx +0 -0
  71. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/CopyId.tsx +0 -0
  72. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/DataTable.tsx +0 -0
  73. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/EmptyState.tsx +0 -0
  74. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/ErrorPanel.tsx +0 -0
  75. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Icon.tsx +0 -0
  76. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Kbd.tsx +0 -0
  77. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Panel.tsx +0 -0
  78. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Pill.test.tsx +0 -0
  79. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Pill.tsx +0 -0
  80. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Seg.test.tsx +0 -0
  81. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Seg.tsx +0 -0
  82. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Skeleton.tsx +0 -0
  83. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Tile.test.tsx +0 -0
  84. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Tile.tsx +0 -0
  85. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/alerts/AlertsPage.tsx +0 -0
  86. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/budgets/BudgetsPage.tsx +0 -0
  87. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/models/ModelsPage.tsx +0 -0
  88. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/overview/AttentionStrip.tsx +0 -0
  89. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/overview/OverviewPage.tsx +0 -0
  90. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/overview/TopSessions.tsx +0 -0
  91. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/overview/useOverviewModel.test.ts +0 -0
  92. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/overview/useOverviewModel.ts +0 -0
  93. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/search/SearchPage.tsx +0 -0
  94. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/search/cleanSnippet.test.ts +0 -0
  95. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/search/cleanSnippet.ts +0 -0
  96. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/session/OverviewTab.tsx +0 -0
  97. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/session/SessionPage.tsx +0 -0
  98. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/session/SubagentsTab.tsx +0 -0
  99. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/session/TimelineTab.tsx +0 -0
  100. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/session/model.test.ts +0 -0
  101. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/session/model.ts +0 -0
  102. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/sessions/AnalysisStrip.tsx +0 -0
  103. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/sessions/SessionsPage.tsx +0 -0
  104. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/sessions/SessionsTable.tsx +0 -0
  105. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/sessions/filters.test.ts +0 -0
  106. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/sessions/filters.ts +0 -0
  107. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/settings/SettingsPage.tsx +0 -0
  108. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/tools/ToolsPage.tsx +0 -0
  109. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/tools/toolsOverTime.test.ts +0 -0
  110. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/tools/toolsOverTime.ts +0 -0
  111. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/trends/TrendsPage.tsx +0 -0
  112. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/composition.test.ts +0 -0
  113. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/composition.ts +0 -0
  114. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/cumulative.test.ts +0 -0
  115. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/cumulative.ts +0 -0
  116. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/deltas.test.ts +0 -0
  117. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/deltas.ts +0 -0
  118. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/hourWeekday.test.ts +0 -0
  119. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/hourWeekday.ts +0 -0
  120. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/rollups.test.ts +0 -0
  121. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/rollups.ts +0 -0
  122. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/series.test.ts +0 -0
  123. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/series.ts +0 -0
  124. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/testutil.ts +0 -0
  125. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/trendsMetrics.test.ts +0 -0
  126. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/trendsMetrics.ts +0 -0
  127. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/windows.test.ts +0 -0
  128. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/windows.ts +0 -0
  129. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/__fixtures__/alerts.json +0 -0
  130. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/__fixtures__/overview.json +0 -0
  131. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/__fixtures__/sessions.json +0 -0
  132. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/__fixtures__/timeline.json +0 -0
  133. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/__fixtures__/tools-overview.json +0 -0
  134. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/__fixtures__/trends.json +0 -0
  135. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/client.test.ts +0 -0
  136. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/client.ts +0 -0
  137. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/hooks.ts +0 -0
  138. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/schemas.ts +0 -0
  139. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/format/format.test.ts +0 -0
  140. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/format/format.ts +0 -0
  141. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/main.tsx +0 -0
  142. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routeTree.gen.ts +0 -0
  143. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/__root.tsx +0 -0
  144. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/alerts.tsx +0 -0
  145. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/budgets.tsx +0 -0
  146. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/index.tsx +0 -0
  147. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/models.tsx +0 -0
  148. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/prompts.tsx +0 -0
  149. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/search.tsx +0 -0
  150. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/session.tsx +0 -0
  151. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/sessions.$id.tsx +0 -0
  152. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/sessions.index.tsx +0 -0
  153. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/settings.tsx +0 -0
  154. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/tools.tsx +0 -0
  155. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/trends.tsx +0 -0
  156. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/styles.css +0 -0
  157. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/tsconfig.json +0 -0
  158. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/vite.config.ts +0 -0
  159. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/vitest.config.ts +0 -0
  160. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/vitest.setup.ts +0 -0
  161. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/AlertsPage-Cs8_bu24.js +0 -0
  162. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/AreaLine-VUt7zZPY.js +0 -0
  163. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/AttentionStrip-uulCqq7B.js +0 -0
  164. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/Bars-gdNIlXNl.js +0 -0
  165. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/BudgetsPage-DNk4EMLO.js +0 -0
  166. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/Button-BqHL1YGs.js +0 -0
  167. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ChartTable-C2SF4hxC.js +0 -0
  168. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/Chip-CSAZEvs5.js +0 -0
  169. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ErrorPanel-YJvBzoti.js +0 -0
  170. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ModelsPage-CC5HgXSC.js +0 -0
  171. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/MultiLine-DaOioHM_.js +0 -0
  172. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/OverviewPage-DtYtpPeA.js +0 -0
  173. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/Panel-C0lmkoau.js +0 -0
  174. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/Pill-BaEMC6Uo.js +0 -0
  175. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/SearchPage-DENLda5C.js +0 -0
  176. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/SessionPage-h4KU-Iel.js +0 -0
  177. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/SessionsPage-BQOKS0MJ.js +0 -0
  178. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/SettingsPage-JyOusfCm.js +0 -0
  179. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/StackedColumns-D_Ewnsrg.js +0 -0
  180. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/Tile-kzNeIivi.js +0 -0
  181. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/TimelineTab-D86rkM-N.js +0 -0
  182. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ToolsPage-DAKkhNxC.js +0 -0
  183. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/TrendsPage-tRubbqz4.js +0 -0
  184. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/cumulative-C3-3HW0n.js +0 -0
  185. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  186. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  187. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
  188. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  189. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  190. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  191. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  192. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  193. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  194. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  195. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/index-CiLtq5Ja.js +0 -0
  196. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/index-DwJcAbKT.css +0 -0
  197. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/rollups-C1zMwbci.js +0 -0
  198. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/series-BjP-80tt.js +0 -0
  199. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/uplotTheme-D1GxaB_c.css +0 -0
  200. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/uplotTheme-dVdt58Jw.js +0 -0
  201. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/windows-7ctt19Z4.js +0 -0
  202. {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/index.html +0 -0
  203. {argus_code-0.5.0 → argus_code-0.5.1}/pricing/2026-05-02.json +0 -0
  204. {argus_code-0.5.0 → argus_code-0.5.1}/pricing/2026-06-12.json +0 -0
  205. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/AGENTS.md +0 -0
  206. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/__init__.py +0 -0
  207. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/base.py +0 -0
  208. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/__init__.py +0 -0
  209. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/adapter.py +0 -0
  210. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/discover.py +0 -0
  211. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/extract_tool_calls.py +0 -0
  212. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/extract_transcript.py +0 -0
  213. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/extract_turns.py +0 -0
  214. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/history_jsonl.py +0 -0
  215. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/ingest_file.py +0 -0
  216. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/model.py +0 -0
  217. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/schemas.py +0 -0
  218. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/registry.py +0 -0
  219. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/cli.py +0 -0
  220. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/AGENTS.md +0 -0
  221. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/__init__.py +0 -0
  222. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/aggregate.py +0 -0
  223. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/first_run.py +0 -0
  224. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/pipeline.py +0 -0
  225. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/rollup_subagents.py +0 -0
  226. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/scheduler.py +0 -0
  227. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/search_backfill.py +0 -0
  228. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/watcher.py +0 -0
  229. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/core/__init__.py +0 -0
  230. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/daemon/__init__.py +0 -0
  231. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/daemon/logging.py +0 -0
  232. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/daemon/pidfile.py +0 -0
  233. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/daemon/process.py +0 -0
  234. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/detectors/__init__.py +0 -0
  235. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/detectors/base.py +0 -0
  236. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/detectors/registry.py +0 -0
  237. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/detectors/tool_error_rate_spike.py +0 -0
  238. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/pricing/__init__.py +0 -0
  239. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/pricing/compute.py +0 -0
  240. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/pricing/load.py +0 -0
  241. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/pricing/refresh.py +0 -0
  242. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/pricing/types.py +0 -0
  243. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/scaffold/__init__.py +0 -0
  244. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/scaffold/scaffolder.py +0 -0
  245. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/scaffold/snapshot.py +0 -0
  246. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/scaffold/storage.py +0 -0
  247. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/schema/__init__.py +0 -0
  248. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/schema/types.py +0 -0
  249. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/server/AGENTS.md +0 -0
  250. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/server/__init__.py +0 -0
  251. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/server/api.py +0 -0
  252. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/server/app.py +0 -0
  253. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/store/AGENTS.md +0 -0
  254. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/store/__init__.py +0 -0
  255. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/store/db.py +0 -0
  256. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/store/migrations/__init__.py +0 -0
  257. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/store/migrations/inline.py +0 -0
  258. {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/store/repository.py +0 -0
  259. {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/agents/code-reviewer.md +0 -0
  260. {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/agents/security-auditor.md +0 -0
  261. {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/commands/commit.md +0 -0
  262. {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/commands/deploy.md +0 -0
  263. {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/commands/fix-issue.md +0 -0
  264. {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/commands/pr.md +0 -0
  265. {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/commands/review.md +0 -0
  266. {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/rules/api-conventions.md +0 -0
  267. {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/rules/code-style.md +0 -0
  268. {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/rules/testing.md +0 -0
  269. {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/settings.json +0 -0
  270. {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/skills/example/SKILL.md +0 -0
  271. {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/CLAUDE.md +0 -0
  272. {argus_code-0.5.0 → argus_code-0.5.1}/tests/AGENTS.md +0 -0
  273. {argus_code-0.5.0 → argus_code-0.5.1}/tests/__init__.py +0 -0
  274. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/__init__.py +0 -0
  275. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/__init__.py +0 -0
  276. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_adapter.py +0 -0
  277. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_discover.py +0 -0
  278. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_extract_tool_calls.py +0 -0
  279. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_extract_transcript.py +0 -0
  280. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_extract_turns.py +0 -0
  281. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_history_jsonl.py +0 -0
  282. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_ingest_file.py +0 -0
  283. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_integration.py +0 -0
  284. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_model.py +0 -0
  285. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_path_containment.py +0 -0
  286. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_schemas.py +0 -0
  287. {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/test_registry.py +0 -0
  288. {argus_code-0.5.0 → argus_code-0.5.1}/tests/cli/__init__.py +0 -0
  289. {argus_code-0.5.0 → argus_code-0.5.1}/tests/cli/test_indexing_cli.py +0 -0
  290. {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/__init__.py +0 -0
  291. {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_aggregate.py +0 -0
  292. {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_first_run.py +0 -0
  293. {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_first_run_shutdown.py +0 -0
  294. {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_pipeline.py +0 -0
  295. {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_rollup_subagents.py +0 -0
  296. {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_scheduler.py +0 -0
  297. {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_watcher.py +0 -0
  298. {argus_code-0.5.0 → argus_code-0.5.1}/tests/conftest.py +0 -0
  299. {argus_code-0.5.0 → argus_code-0.5.1}/tests/core/__init__.py +0 -0
  300. {argus_code-0.5.0 → argus_code-0.5.1}/tests/core/test_runtime.py +0 -0
  301. {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/__init__.py +0 -0
  302. {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/test_logs.py +0 -0
  303. {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/test_pidfile.py +0 -0
  304. {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/test_process.py +0 -0
  305. {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/test_spawn_safe_path.py +0 -0
  306. {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/test_yield.py +0 -0
  307. {argus_code-0.5.0 → argus_code-0.5.1}/tests/dashboard/__init__.py +0 -0
  308. {argus_code-0.5.0 → argus_code-0.5.1}/tests/dashboard/test_no_raw_html.py +0 -0
  309. {argus_code-0.5.0 → argus_code-0.5.1}/tests/detectors/__init__.py +0 -0
  310. {argus_code-0.5.0 → argus_code-0.5.1}/tests/detectors/test_registry.py +0 -0
  311. {argus_code-0.5.0 → argus_code-0.5.1}/tests/detectors/test_tool_error_rate_spike.py +0 -0
  312. {argus_code-0.5.0 → argus_code-0.5.1}/tests/pricing/__init__.py +0 -0
  313. {argus_code-0.5.0 → argus_code-0.5.1}/tests/pricing/test_compute.py +0 -0
  314. {argus_code-0.5.0 → argus_code-0.5.1}/tests/pricing/test_load.py +0 -0
  315. {argus_code-0.5.0 → argus_code-0.5.1}/tests/pricing/test_refresh.py +0 -0
  316. {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/__init__.py +0 -0
  317. {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_bundled_template.py +0 -0
  318. {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_cli_claude.py +0 -0
  319. {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_scaffold_containment.py +0 -0
  320. {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_scaffolder.py +0 -0
  321. {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_snapshot.py +0 -0
  322. {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_snapshot_secrets.py +0 -0
  323. {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_storage.py +0 -0
  324. {argus_code-0.5.0 → argus_code-0.5.1}/tests/schema/__init__.py +0 -0
  325. {argus_code-0.5.0 → argus_code-0.5.1}/tests/schema/test_types.py +0 -0
  326. {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/__init__.py +0 -0
  327. {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_api.py +0 -0
  328. {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_api_search.py +0 -0
  329. {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_param_bounds.py +0 -0
  330. {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_read_cache.py +0 -0
  331. {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_server.py +0 -0
  332. {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_spa_fallback.py +0 -0
  333. {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_week_of.py +0 -0
  334. {argus_code-0.5.0 → argus_code-0.5.1}/tests/store/__init__.py +0 -0
  335. {argus_code-0.5.0 → argus_code-0.5.1}/tests/store/test_db.py +0 -0
  336. {argus_code-0.5.0 → argus_code-0.5.1}/tests/store/test_repository.py +0 -0
  337. {argus_code-0.5.0 → argus_code-0.5.1}/tests/test_e2e.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: argus-code
3
- Version: 0.5.0
3
+ Version: 0.5.1
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "argus-code"
3
- version = "0.5.0"
3
+ version = "0.5.1"
4
4
  description = "Local-first dashboard for Claude Code cost, token, tool-usage, and full-text search analytics"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -29,6 +29,16 @@ Delegated subtrees (see their own AGENTS.md): `store/`, `collector/`, `adapters/
29
29
  user-facing command, keep the old name as a `hidden=True` alias and nudge to the
30
30
  new one (precedent: `search` → `indexing`). Update help strings, the daemon
31
31
  read-only API hint, and dashboard copy together.
32
+ - **A missing `~/.claude` is fatal for `argus start` but not for `argusd`.**
33
+ `CoreRuntime.start(require_adapters=True)` (the foreground default) raises
34
+ `NoAdaptersError` — immediate, readable feedback. The daemon
35
+ (`daemon/service.py`) passes `require_adapters=False`, comes up idle with the
36
+ DB open, and polls `CoreRuntime.try_activate()` every `adapter_poll_sec`
37
+ (30 s) so ingest starts by itself once the directory appears (issue #11).
38
+ `try_activate()` is idempotent and returns `True` only on the idle→running
39
+ transition, so callers can log it once. Keep `_FakeRuntime` in
40
+ `tests/daemon/test_service.py` signature-compatible with `CoreRuntime` — it
41
+ asserts the daemon requests the tolerant mode.
32
42
  - **Privacy stays intact:** no network calls or telemetry beyond opt-in
33
43
  `argus pricing refresh`. Don't add outbound calls.
34
44
 
@@ -1,3 +1,3 @@
1
1
  """Argus — local-first analytics for Claude Code and other coding agents."""
2
2
 
3
- __version__ = "0.5.0"
3
+ __version__ = "0.5.1"
@@ -58,18 +58,53 @@ class CoreRuntime:
58
58
  self._watcher = None
59
59
  self._scheduler = None
60
60
 
61
- def start(self) -> None:
61
+ def start(self, *, require_adapters: bool = True) -> None:
62
+ """Open the DB and begin ingesting.
63
+
64
+ ``require_adapters=False`` is for long-running services (argusd): a
65
+ missing ``~/.claude`` is a "not yet" rather than an error, so we come up
66
+ idle and let :meth:`try_activate` pick things up when the directory
67
+ appears. The foreground ``argus start`` keeps the default, because
68
+ failing immediately with a clear message is better feedback there.
69
+ """
62
70
  self._db = open_db(self._data_dir / "argus.db", read_only=self.read_only)
63
71
  self.repo = Repository(self._db)
72
+ self.pricing_table = load_pricing_table()
64
73
 
65
74
  self.adapters = available_adapters()
66
75
  if not self.adapters:
67
- raise NoAdaptersError(
68
- "No adapter data found. Argus expects ~/.claude/ (Claude Code) "
69
- "to be present at minimum."
76
+ if require_adapters:
77
+ raise NoAdaptersError(
78
+ "No adapter data found. Argus expects ~/.claude/ (Claude Code) "
79
+ "to be present at minimum."
80
+ )
81
+ logger.warning(
82
+ "No agent data found (~/.claude/ is missing). Staying up and "
83
+ "watching for it — ingest starts automatically once it appears."
70
84
  )
85
+ return
86
+
87
+ self._activate()
88
+
89
+ def try_activate(self) -> bool:
90
+ """Start ingesting if adapters have appeared since startup.
91
+
92
+ Returns True only on the transition from "nothing to do" to "running",
93
+ so callers can log it once. Cheap and idempotent — safe to poll.
94
+ """
95
+ if self.adapters or self.repo is None or self.read_only:
96
+ return False
97
+ found = available_adapters()
98
+ if not found:
99
+ return False
100
+ self.adapters = found
101
+ self._activate()
102
+ return True
103
+
104
+ def _activate(self) -> None:
105
+ """Kick off first-pass ingest, the watcher, and the detector scheduler."""
106
+ assert self.repo is not None and self.pricing_table is not None
71
107
  logger.info("Detected adapters: %s", ", ".join(a.agent for a in self.adapters))
72
- self.pricing_table = load_pricing_table()
73
108
 
74
109
  if self.read_only:
75
110
  logger.info("argusd active — dashboard read-only (no ingest/scheduler).")
@@ -33,6 +33,7 @@ def run_foreground(
33
33
  *,
34
34
  stop_event: threading.Event | None = None,
35
35
  install_signals: bool = True,
36
+ adapter_poll_sec: float = 30.0,
36
37
  ) -> None:
37
38
  data_dir = Path(data_dir)
38
39
  stop_event = stop_event or threading.Event()
@@ -61,9 +62,16 @@ def run_foreground(
61
62
  pidfile.write(data_dir, me)
62
63
  runtime = CoreRuntime(data_dir, read_only=False)
63
64
  try:
64
- runtime.start()
65
+ # A missing ~/.claude must not kill the service. On a fresh machine, or
66
+ # one where Claude Code simply hasn't been launched yet, argusd comes up
67
+ # idle and waits for the directory instead of exiting (issue #11).
68
+ runtime.start(require_adapters=False)
65
69
  logger.info("argusd started (PID %d).", me)
66
- stop_event.wait()
70
+ # Wake periodically so ingest can begin by itself once ~/.claude shows
71
+ # up; try_activate() is a no-op once we're running.
72
+ while not stop_event.wait(adapter_poll_sec):
73
+ if runtime.try_activate():
74
+ logger.info("Agent data appeared — ingest started.")
67
75
  finally:
68
76
  runtime.stop()
69
77
  pidfile.remove(data_dir)
@@ -0,0 +1,162 @@
1
+ """argusd must survive a missing ``~/.claude`` — issue #11.
2
+
3
+ ``CoreRuntime.start()`` raises ``NoAdaptersError`` when no adapter reports
4
+ ``is_present()``, and ``ClaudeCodeAdapter.is_present()`` is just "does
5
+ ``~/.claude`` exist". In ``service.run_foreground`` that exception propagates
6
+ straight out of ``runtime.start()``, so the ``finally`` tears down and removes
7
+ the pidfile and the process exits — on a fresh machine, or one where Claude
8
+ Code simply hasn't been launched yet, the daemon refuses to stay up.
9
+
10
+ A long-running service should tolerate the directory being absent and start
11
+ working once it appears. The *foreground* ``argus start`` raising immediately is
12
+ useful feedback and is deliberately kept.
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import sqlite3
17
+ import threading
18
+ from pathlib import Path
19
+
20
+ import pytest
21
+
22
+ from argus.adapters.claude_code import adapter as cc_adapter
23
+ from argus.core.runtime import CoreRuntime, NoAdaptersError
24
+ from argus.daemon import service
25
+
26
+
27
+ @pytest.fixture
28
+ def fake_home(tmp_path: Path, monkeypatch):
29
+ """Point the Claude Code adapter at a home that has no .claude/ yet."""
30
+ home = tmp_path / "home"
31
+ home.mkdir()
32
+ monkeypatch.setattr(cc_adapter, "_default_root", lambda: home / ".claude")
33
+ return home
34
+
35
+
36
+ def test_foreground_start_still_raises(fake_home, tmp_path: Path):
37
+ """`argus start` keeps its immediate, friendly failure — that's useful."""
38
+ rt = CoreRuntime(tmp_path / "data")
39
+ try:
40
+ with pytest.raises(NoAdaptersError):
41
+ rt.start()
42
+ finally:
43
+ rt.stop()
44
+
45
+
46
+ def test_daemon_start_does_not_raise_when_claude_is_missing(fake_home, tmp_path: Path):
47
+ rt = CoreRuntime(tmp_path / "data")
48
+ try:
49
+ rt.start(require_adapters=False) # must not raise
50
+ assert rt.adapters == []
51
+ assert rt.repo is not None, "the DB should still be open and usable"
52
+ finally:
53
+ rt.stop()
54
+
55
+
56
+ def test_daemon_activates_once_claude_appears(fake_home, tmp_path: Path):
57
+ """The whole point: come up idle, then start working by itself."""
58
+ rt = CoreRuntime(tmp_path / "data")
59
+ try:
60
+ rt.start(require_adapters=False)
61
+ assert rt.try_activate() is False, "nothing to activate yet"
62
+
63
+ proj = fake_home / ".claude" / "projects" / "p"
64
+ proj.mkdir(parents=True)
65
+ (proj / "s1.jsonl").write_text(
66
+ '{"type":"user","message":{"role":"user","content":"hi"}}\n',
67
+ encoding="utf-8",
68
+ )
69
+
70
+ assert rt.try_activate() is True, "should pick up the new ~/.claude"
71
+ assert [a.agent for a in rt.adapters] == ["claude_code"]
72
+ # Idempotent: a second call must not start a second watcher/scheduler.
73
+ assert rt.try_activate() is False
74
+ finally:
75
+ rt.stop()
76
+
77
+
78
+ def test_run_foreground_stays_alive_without_claude(fake_home, tmp_path: Path):
79
+ """The daemon process must not exit; it must sit waiting for work."""
80
+ data_dir = tmp_path / "data"
81
+ stop = threading.Event()
82
+ error: list[BaseException] = []
83
+
84
+ def run() -> None:
85
+ try:
86
+ service.run_foreground(
87
+ data_dir, stop_event=stop, install_signals=False, adapter_poll_sec=0.05
88
+ )
89
+ except BaseException as e: # noqa: BLE001
90
+ error.append(e)
91
+
92
+ t = threading.Thread(target=run, daemon=True)
93
+ t.start()
94
+ try:
95
+ # Give it long enough to have crashed if it were going to.
96
+ t.join(2.0)
97
+ assert t.is_alive(), f"daemon exited instead of waiting; error={error}"
98
+ assert not error, f"daemon raised: {error}"
99
+ finally:
100
+ stop.set()
101
+ t.join(10)
102
+ assert not error, f"daemon raised on shutdown: {error}"
103
+
104
+
105
+ def test_run_foreground_picks_up_claude_created_while_running(
106
+ fake_home, tmp_path: Path
107
+ ):
108
+ data_dir = tmp_path / "data"
109
+ stop = threading.Event()
110
+ error: list[BaseException] = []
111
+
112
+ def run() -> None:
113
+ try:
114
+ service.run_foreground(
115
+ data_dir, stop_event=stop, install_signals=False, adapter_poll_sec=0.05
116
+ )
117
+ except BaseException as e: # noqa: BLE001
118
+ error.append(e)
119
+
120
+ t = threading.Thread(target=run, daemon=True)
121
+ t.start()
122
+ try:
123
+ # Must be an *assistant* line: the pipeline deliberately creates no
124
+ # session row for a file with no turns, so a user-only line would
125
+ # ingest fine and still leave list_sessions() empty.
126
+ import json
127
+
128
+ from tests.conftest import assistant_line
129
+
130
+ proj = fake_home / ".claude" / "projects" / "p"
131
+ proj.mkdir(parents=True)
132
+ (proj / "s1.jsonl").write_text(
133
+ json.dumps(assistant_line("m1", 1)) + "\n", encoding="utf-8"
134
+ )
135
+ # Assert on the observable effect — data actually ingested — rather
136
+ # than on the daemon's internals.
137
+ from argus.store.db import open_db
138
+ from argus.store.repository import Repository
139
+
140
+ found = False
141
+ for _ in range(200):
142
+ # "The file exists" is not "the schema is ready" — SQLite creates
143
+ # the file the moment it is opened, before migrations run, so a
144
+ # fast probe queries a table-less DB. Treat every not-yet state
145
+ # (missing file, missing table, locked) as "keep waiting" rather
146
+ # than as a failure; the assert below is what decides the outcome.
147
+ try:
148
+ probe = open_db(data_dir / "argus.db", read_only=True)
149
+ try:
150
+ found = bool(Repository(probe).list_sessions(limit=5))
151
+ finally:
152
+ probe.close()
153
+ except (sqlite3.OperationalError, sqlite3.DatabaseError, OSError):
154
+ pass
155
+ if found:
156
+ break
157
+ threading.Event().wait(0.05)
158
+ assert found, "daemon never ingested the newly created ~/.claude"
159
+ finally:
160
+ stop.set()
161
+ t.join(10)
162
+ assert not error, f"daemon raised: {error}"
@@ -10,12 +10,22 @@ from argus.daemon import pidfile, service
10
10
 
11
11
 
12
12
  class _FakeRuntime:
13
+ """Stand-in for CoreRuntime — keep this signature-compatible with the real
14
+ one, or these tests pass while the daemon is broken."""
15
+
13
16
  def __init__(self, *a, **k):
14
17
  self.started = False
15
18
  self.stopped = False
19
+ self.require_adapters = None
20
+ self.activate_calls = 0
16
21
 
17
- def start(self):
22
+ def start(self, *, require_adapters: bool = True):
18
23
  self.started = True
24
+ self.require_adapters = require_adapters
25
+
26
+ def try_activate(self) -> bool:
27
+ self.activate_calls += 1
28
+ return False
19
29
 
20
30
  def stop(self):
21
31
  self.stopped = True
@@ -41,6 +51,8 @@ def test_run_foreground_writes_pid_runs_and_cleans_up(tmp_path, monkeypatch):
41
51
  time.sleep(0.01)
42
52
  assert pidfile.read(tmp_path) is not None
43
53
  assert fake.started is True
54
+ # The daemon must tolerate a missing ~/.claude rather than exiting (issue #11).
55
+ assert fake.require_adapters is False
44
56
 
45
57
  stop.set()
46
58
  t.join(timeout=3)