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.
- {argus_code-0.5.0 → argus_code-0.5.1}/PKG-INFO +1 -1
- {argus_code-0.5.0 → argus_code-0.5.1}/pyproject.toml +1 -1
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/AGENTS.md +10 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/__init__.py +1 -1
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/core/runtime.py +40 -5
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/daemon/service.py +10 -2
- argus_code-0.5.1/tests/daemon/test_no_claude_dir.py +162 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/test_service.py +13 -1
- {argus_code-0.5.0 → argus_code-0.5.1}/uv.lock +983 -983
- {argus_code-0.5.0 → argus_code-0.5.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/.github/pull_request_template.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/.github/workflows/test.yml +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/.gitignore +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/.npmrc +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/AGENTS.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/ARCHITECTURE.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/CLAUDE.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/CONTRIBUTING.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/LICENSE +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/NOTICE +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/PRD.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/README.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/SECURITY.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/TESTING.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/.astro/content-assets.mjs +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/.astro/content-modules.mjs +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/.astro/content.d.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/.astro/types.d.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/AGENTS.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/e2e/smoke.spec.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/index.html +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/package-lock.json +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/package.json +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/playwright.config.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/scripts/size.mjs +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/App.test.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/queryClient.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/router.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/shell/CommandPalette.test.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/shell/CommandPalette.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/shell/Shell.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/shell/Sidebar.test.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/shell/Sidebar.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/app/shell/TopBar.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/AlertStrip.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/AreaLine.test.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/AreaLine.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Bars.test.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Bars.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/CalendarHeatmap.test.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/CalendarHeatmap.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/ChartTable.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/GridHeatmap.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Legend.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Meter.test.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Meter.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Minimap.test.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Minimap.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/MultiLine.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/README.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Scatter.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/Sparkline.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/StackedColumns.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/UPlotChart.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/ramp.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/charts/uplotTheme.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Button.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Chip.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/CopyId.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/DataTable.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/EmptyState.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/ErrorPanel.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Icon.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Kbd.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Panel.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Pill.test.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Pill.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Seg.test.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Seg.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Skeleton.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Tile.test.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/components/ui/Tile.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/alerts/AlertsPage.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/budgets/BudgetsPage.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/models/ModelsPage.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/overview/AttentionStrip.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/overview/OverviewPage.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/overview/TopSessions.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/overview/useOverviewModel.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/overview/useOverviewModel.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/search/SearchPage.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/search/cleanSnippet.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/search/cleanSnippet.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/session/OverviewTab.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/session/SessionPage.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/session/SubagentsTab.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/session/TimelineTab.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/session/model.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/session/model.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/sessions/AnalysisStrip.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/sessions/SessionsPage.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/sessions/SessionsTable.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/sessions/filters.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/sessions/filters.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/settings/SettingsPage.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/tools/ToolsPage.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/tools/toolsOverTime.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/tools/toolsOverTime.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/features/trends/TrendsPage.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/composition.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/composition.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/cumulative.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/cumulative.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/deltas.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/deltas.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/hourWeekday.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/hourWeekday.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/rollups.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/rollups.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/series.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/series.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/testutil.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/trendsMetrics.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/trendsMetrics.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/windows.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/analysis/windows.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/__fixtures__/alerts.json +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/__fixtures__/overview.json +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/__fixtures__/sessions.json +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/__fixtures__/timeline.json +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/__fixtures__/tools-overview.json +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/__fixtures__/trends.json +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/client.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/client.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/hooks.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/api/schemas.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/format/format.test.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/lib/format/format.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/main.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routeTree.gen.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/__root.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/alerts.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/budgets.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/index.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/models.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/prompts.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/search.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/session.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/sessions.$id.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/sessions.index.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/settings.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/tools.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/routes/trends.tsx +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/src/styles.css +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/tsconfig.json +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/vite.config.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/vitest.config.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard/vitest.setup.ts +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/AlertsPage-Cs8_bu24.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/AreaLine-VUt7zZPY.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/AttentionStrip-uulCqq7B.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/Bars-gdNIlXNl.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/BudgetsPage-DNk4EMLO.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/Button-BqHL1YGs.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ChartTable-C2SF4hxC.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/Chip-CSAZEvs5.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ErrorPanel-YJvBzoti.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ModelsPage-CC5HgXSC.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/MultiLine-DaOioHM_.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/OverviewPage-DtYtpPeA.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/Panel-C0lmkoau.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/Pill-BaEMC6Uo.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/SearchPage-DENLda5C.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/SessionPage-h4KU-Iel.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/SessionsPage-BQOKS0MJ.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/SettingsPage-JyOusfCm.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/StackedColumns-D_Ewnsrg.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/Tile-kzNeIivi.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/TimelineTab-D86rkM-N.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ToolsPage-DAKkhNxC.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/TrendsPage-tRubbqz4.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/cumulative-C3-3HW0n.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/index-CiLtq5Ja.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/index-DwJcAbKT.css +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/rollups-C1zMwbci.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/series-BjP-80tt.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/uplotTheme-D1GxaB_c.css +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/uplotTheme-dVdt58Jw.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/assets/windows-7ctt19Z4.js +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/dashboard-dist/index.html +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/pricing/2026-05-02.json +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/pricing/2026-06-12.json +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/AGENTS.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/base.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/adapter.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/discover.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/extract_tool_calls.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/extract_transcript.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/extract_turns.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/history_jsonl.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/ingest_file.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/model.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/claude_code/schemas.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/adapters/registry.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/cli.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/AGENTS.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/aggregate.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/first_run.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/pipeline.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/rollup_subagents.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/scheduler.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/search_backfill.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/collector/watcher.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/core/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/daemon/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/daemon/logging.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/daemon/pidfile.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/daemon/process.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/detectors/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/detectors/base.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/detectors/registry.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/detectors/tool_error_rate_spike.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/pricing/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/pricing/compute.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/pricing/load.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/pricing/refresh.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/pricing/types.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/scaffold/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/scaffold/scaffolder.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/scaffold/snapshot.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/scaffold/storage.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/schema/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/schema/types.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/server/AGENTS.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/server/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/server/api.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/server/app.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/store/AGENTS.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/store/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/store/db.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/store/migrations/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/store/migrations/inline.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/python/argus/store/repository.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/agents/code-reviewer.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/agents/security-auditor.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/commands/commit.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/commands/deploy.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/commands/fix-issue.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/commands/pr.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/commands/review.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/rules/api-conventions.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/rules/code-style.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/rules/testing.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/settings.json +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/.claude/skills/example/SKILL.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/templates/default/CLAUDE.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/AGENTS.md +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_adapter.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_discover.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_extract_tool_calls.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_extract_transcript.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_extract_turns.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_history_jsonl.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_ingest_file.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_integration.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_model.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_path_containment.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/claude_code/test_schemas.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/adapters/test_registry.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/cli/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/cli/test_indexing_cli.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_aggregate.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_first_run.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_first_run_shutdown.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_pipeline.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_rollup_subagents.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_scheduler.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/collector/test_watcher.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/conftest.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/core/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/core/test_runtime.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/test_logs.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/test_pidfile.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/test_process.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/test_spawn_safe_path.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/daemon/test_yield.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/dashboard/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/dashboard/test_no_raw_html.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/detectors/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/detectors/test_registry.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/detectors/test_tool_error_rate_spike.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/pricing/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/pricing/test_compute.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/pricing/test_load.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/pricing/test_refresh.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_bundled_template.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_cli_claude.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_scaffold_containment.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_scaffolder.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_snapshot.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_snapshot_secrets.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/scaffold/test_storage.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/schema/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/schema/test_types.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_api.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_api_search.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_param_bounds.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_read_cache.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_server.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_spa_fallback.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/server/test_week_of.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/store/__init__.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/store/test_db.py +0 -0
- {argus_code-0.5.0 → argus_code-0.5.1}/tests/store/test_repository.py +0 -0
- {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.
|
|
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
|
|
@@ -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
|
|
|
@@ -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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)
|