clawmetry 0.12.415__tar.gz → 0.12.417__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.
- {clawmetry-0.12.415/clawmetry.egg-info → clawmetry-0.12.417}/PKG-INFO +1 -1
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/js/app.js +54 -1
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/sync.py +35 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/subagents.html +5 -1
- {clawmetry-0.12.415 → clawmetry-0.12.417/clawmetry.egg-info}/PKG-INFO +1 -1
- {clawmetry-0.12.415 → clawmetry-0.12.417}/dashboard.py +1 -1
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/sessions.py +24 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/update_check.py +41 -3
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_auto_update.py +52 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/ARCHITECTURE.md +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/CHANGELOG.md +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/CLAUDE.md +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/LICENSE +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/MANIFEST.in +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/README.md +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/__init__.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/__main__.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/_gate.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/adapters/__init__.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/adapters/base.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/adapters/nemo.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/adapters/openclaw.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/adapters/registry.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/alert_evaluator.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/approvals.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/audit.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/blueprints/__init__.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/cli.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/config.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/connector_health.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/dives_prompt.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/dives_sql_safety.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/entitlements.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/error_patterns.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/error_signal.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/eval_regression_replay.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/eval_runner.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/eval_suite_runner.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/extensions.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/gateway_tap.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/insights.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/interceptor.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/latency_tracker.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/license.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/local_server.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/otel_exporter.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/otel_push.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/outcome_classifier.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/providers/__init__.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/providers/base.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/providers/local.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/providers/turso.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/providers_pricing.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/proxy.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/py.typed +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/redaction.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/relay.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/resources/add-nemoclaw-clawmetry-preset.sh +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/risk.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/siem.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/css/dashboard.css +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/img/logo.svg +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/js/alerts.js +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/js/auth-bootstrap.js +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/js/dives.js +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/js/gw-setup.js +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/js/i18n.js +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/js/nav-dropdown.js +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/_glossary.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/_meta.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/ar.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/bn.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/de.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/el.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/en.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/es-419.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/es.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/fa.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/fil.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/fr.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/gu.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/he.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/hi.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/id.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/it.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/ja.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/kn.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/ko.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/ml.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/mr.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/nl.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/pa.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/pl.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/pt-BR.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/pt-PT.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/ru.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/sv.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/ta.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/te.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/th.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/tr.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/uk.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/ur.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/vi.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/zh-CN.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/locales/zh-TW.json +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/v2/dist/assets/index-Dtt_uBk_.js +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/v2/dist/assets/index-NbINX9rU.css +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/v2/dist/index.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/telemetry.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/README.md +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/partials/banners.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/partials/budget-modal.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/partials/cloud-modal.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/partials/overlays.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/partials/paywall_modal.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/alerts.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/approvals.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/brain.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/clusters.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/context-economics.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/context.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/crons.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/dives.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/flow.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/history.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/logs.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/memory.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/models.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/nemoclaw.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/notifications.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/overview.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/policy.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/security.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/selfevolve.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/skills.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/swimlane.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/tool-catalog.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/tracing.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/transcripts.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/turn-anatomy.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/usage.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/templates/tabs/version-impact.html +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/tests/__init__.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/tests/e2e/__init__.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/tests/e2e/test_cloud_sync_resilience.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/tests/integration/__init__.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/tests/integration/test_fast_paths_cross_process.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/token_confidence.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/track.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/v2/__init__.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/v2/routes.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/waste_flags.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry.egg-info/SOURCES.txt +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry.egg-info/dependency_links.txt +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry.egg-info/entry_points.txt +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry.egg-info/requires.txt +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry.egg-info/top_level.txt +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/helpers/__init__.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/helpers/gateway.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/helpers/hardware.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/helpers/logs.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/helpers/openapi.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/helpers/pricing.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/helpers/streams.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/helpers/system.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/__init__.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/_dedupe.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/advisor.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/agents.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/alerts.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/assets.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/audit.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/autonomy.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/bootstrap.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/brain.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/channels.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/components.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/context_economics.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/crons.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/dives.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/entitlement.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/evals.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/fleet_history.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/health.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/heartbeat.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/hitl.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/infra.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/insights.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/local_query.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/meta.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/nemoclaw.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/otel_export.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/overview.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/plugins.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/policy.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/reasoning.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/review.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/runtime_ingest.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/scheduler.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/selfconfig.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/selfevolve.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/skills.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/sla.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/tool_catalog.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/tracing.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/turn_anatomy.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/usage.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/routes/workspaces.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/setup.cfg +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/setup.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/__init__.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/_moat_perf_fixture.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/conftest.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/eval_ci_mock_agent.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_adapter_gating.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_adapter_registry_override.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_adapters.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_adaptive_heartbeat.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_advertised_runtimes_match_catalogue.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_advisor_auth_resolution.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_aesgcm_swallow_fix.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_alert_evaluator_unit.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_alert_rules_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_alerts_evaluator_duckdb.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_anon_auth_fail_ping.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_api.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_appjs_units.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_approvals_duckdb_watcher.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_approvals_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_audit.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_auth_detected_token.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_automation_analysis_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_autonomy_v3_shape.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_backfill_family_cost.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_blueprint_uniqueness.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_bootstrap_capture.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_brain_cache_push.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_brain_cache_push_channel_events.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_brain_clusters_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_brain_history_v3_event_detail.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_brain_llm_call_timeline.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_brain_local_fastpath.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_brain_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_brain_no_log_keyword_noise.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_brain_sse_reconnect.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_budget_cap.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_cache_trends.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_channel_bluebubbles_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_channel_config_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_channel_event_chokepoint.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_channel_signal_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_channel_telegram_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_channel_tui_duckdb_fastpath.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_channel_whatsapp_duckdb_fastpath.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_channels_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_circular_import.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_class_bug_parent_sid_drain.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_claude_sessions_privacy_boundary.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_claudecode.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_claudecode_loads_plugins.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_cli.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_cli_banner.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_component_gateway_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_component_tool_model_completed.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_component_tool_timeout.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_connector_health.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_context_anatomy_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_context_window_model_aware.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_cost_optimizer_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_cron_health.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_cron_runs_duckdb_ingest.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_cron_runs_events_only.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_crons_cache_push.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_crons_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_crons_runs_endpoint.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_daemon_error_event_pipeline.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_daemon_health_endpoint.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_dashboard_perf_hotfix.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_decoding_config_extract.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_delegation_tree_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_dives_prompt.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_dives_sql_safety.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_duckdb_coverage_batch_2026_05_13.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_duckdb_coverage_phase2_2026_05_13.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_duckdb_coverage_phase3_2026_05_13.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_duckdb_coverage_phase4_channels_2026_05_13.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_duckdb_coverage_phase5_channels_2026_05_13.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_duckdb_fastpath_v3_invariants.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_duckdb_relay_integration.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_e2e.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_e2e_browserstack.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_e2e_cross_repo_handoff.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_e2e_nightly_workflow.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_e2e_oss_all_tabs.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_e2e_oss_golden_path.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_e2e_real_openclaw_pipeline.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_e2e_telegram_brain_ingest.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_entitlement_api.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_entitlements.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_entitlements_catalogue.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_error_patterns.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_error_triage.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_eval_regression_replay.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_eval_runner.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_eval_suite_runner.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_evaluate_alerts_integration.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_event_id_unification_and_dedup.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_event_metrics_extraction.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_events_only_computation.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_extensions.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_fallbacks_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_family_runtime_ingest.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_first_heartbeat_onboarding.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_flow_events_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_flow_runs_endpoint.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_flow_sse_reconnect.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_forward_progress.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_gateway_health.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_gateway_health_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_gateway_metric_history.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_gateway_tap.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_gateway_tap_opt_in_banner.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_gateway_token_fallback.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_gateway_ws_handshake_client_id.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_hallucination_risk.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_health_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_heartbeat_agent_install_piggyback.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_heartbeat_dispatch.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_heartbeat_envelope.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_heartbeat_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_heartbeat_loop_detector.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_heartbeat_relay_e2e.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_i18n_catalog.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_i18n_no_raw_codes.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_insights.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_install_script_linux_restart.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_install_script_no_duplicate_daemon.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_integrity_hash_chain.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_interceptor.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_issue_1127_ux_dead_ends.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_latency_tracker.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_license.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_license_api.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_local_max_bytes_auto_vacuum.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_local_query_api.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_local_query_dispatch_edge_cases.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_local_server_proxy.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_local_store_concurrent_flush_1590.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_local_store_default_on.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_local_store_missing_writers.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_local_store_multi_agent.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_local_store_rename.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_local_store_sync_integration.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_log_sse_reconnect.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_loop_signals_integration.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_memory_cache_push.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_memory_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_memory_rag.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_bug_class_v3_event_shape_gate.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_cloud_robustness.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_cloud_roundtrip_e2e.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_cloud_sync_e2e.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_component_tool_e2e.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_cross_repo_version_skew.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_daemon_crash_recovery.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_event_shape_manifest_guard.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_live_openclaw_e2e.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_perf_benchmark.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_real_e2e.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_regression_1129.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_send_message_e2e.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_moat_tier1_daemon_proxy_sweep.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_model_transitions_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_multi_workspace_discovery.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_nemo_adapter.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_nemo_adapter_pro_gate.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_nemoclaw_events_metrics.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_nemoclaw_governance.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_nemoclaw_runtime_adapter.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_no_agent_detected_state.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_no_direct_get_store_in_routes.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_oauth_detection.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_openclaw_claude_session_ingest.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_openclaw_detection_real.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_openclaw_list_events.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_openclaw_sessions_followup.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_oss_routes_source_canary.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_oss_stubs_after_pro_move.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_otel_export.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_otlp_metrics_edge_cases.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_outcome_classifier.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_overview_autonomy_score.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_overview_heartbeat.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_overview_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_pending_query_dispatch.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_per_agent_budget.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_phase2_stubs.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_phase3_stubs.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_phase4_adapter_move.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_phase_2_to_5_live_e2e.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_plugins_invocations_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_providers_pricing.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_proxy.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_proxy_budget_abort.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_proxy_loads_plugins.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_query_sessions_message_count.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_rate_limits_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_read_cloud_token_fallback.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_real_openclaw_binary_e2e.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_reasoning_v3_shape.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_redaction.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_relay.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_reliability.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_retention_prune.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_review_queue.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_route_gates.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_routes_runtimes.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_run_compare.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_run_daemon_uniqueness.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_runtime_detection_snapshot.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_runtime_filter_no_leak.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_runtime_switcher_gating.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_schema_migration_failure_integrity.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_security_threat_heuristics.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_selfconfig_session_attribution.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_session_cost_intel.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_session_export.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_session_export_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_session_insight.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_session_tools_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_sessions_by_type_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_sessions_clusters_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_sessions_local_fastpath.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_sessions_retention_cap.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_sigterm_ring_flush.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_skills_fidelity_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_skills_fidelity_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_skills_multi_dir_discovery.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_spans_e2e.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_spans_ingest.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_spans_otlp_edge_cases.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_status_live.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_subagent_attribution_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_subagents_events_only.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_subagents_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_subscribe_queue_bounded.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_sync_cloud_plan_cache.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_sync_daemon_crash_recovery.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_sync_loads_plugins.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_sync_main_block_at_eof.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_sync_progress_sticky.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_sync_reliability.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_sync_skip_sidecar_jsonls.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_sync_trial_gating.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_system_snapshot_dlq.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_task_runs_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_telegram_gatewaylog_parser.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_telegram_ingest.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_telemetry.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_tier1_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_tier_pro_paywall_no_flash.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_token_attribution_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_token_confidence.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_token_spike_rules.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_token_velocity_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_tool_alternatives.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_tool_catalog_provenance_and_calls.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_tool_modal_fastpath_2026_05_13.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_tracing_accuracy.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_track.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_track_source.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_transcript_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_transcript_openclaw_shapes.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_transcripts_list_detail_count_parity.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_trial_copy_consistency.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_update_banner_live_version.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_uptime_portable.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_usage_cache_trends_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_usage_forecast_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_usage_local_store.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_usage_per_session.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_v3_schema_parser.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_verify_integrity_cli_proxy.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_version_impact.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_version_impact_local_store_v3.py +0 -0
- {clawmetry-0.12.415 → clawmetry-0.12.417}/tests/test_workspace_switcher_copy.py +0 -0
|
@@ -1178,7 +1178,7 @@ function switchTab(name) {
|
|
|
1178
1178
|
if (name === 'models') loadModelAttribution();
|
|
1179
1179
|
if (name === 'nemoclaw') { loadNemoClaw(); _startNcApprovalsAutoRefresh(); }
|
|
1180
1180
|
if (name !== 'nemoclaw') _stopNcApprovalsAutoRefresh();
|
|
1181
|
-
if (name === 'subagents') { loadRunLedger(); loadSubagents(); if (!_subagentsTimer) _subagentsTimer = visibilitySetInterval(function(){ loadRunLedger(); loadSubagents(); }, 5000); }
|
|
1181
|
+
if (name === 'subagents') { loadOrchestration(); loadRunLedger(); loadSubagents(); if (!_subagentsTimer) _subagentsTimer = visibilitySetInterval(function(){ loadOrchestration(); loadRunLedger(); loadSubagents(); }, 5000); }
|
|
1182
1182
|
if (name !== 'subagents' && _subagentsTimer) { clearInterval(_subagentsTimer); _subagentsTimer = null; }
|
|
1183
1183
|
if (name === 'swimlane') { loadSwimlane(); if (!_swimlaneTimer) _swimlaneTimer = visibilitySetInterval(loadSwimlane, 3000); }
|
|
1184
1184
|
if (name !== 'swimlane' && _swimlaneTimer) { clearInterval(_swimlaneTimer); _swimlaneTimer = null; }
|
|
@@ -13383,6 +13383,59 @@ function _saToggle(sid) {
|
|
|
13383
13383
|
loadSubagents();
|
|
13384
13384
|
}
|
|
13385
13385
|
|
|
13386
|
+
async function loadOrchestration() {
|
|
13387
|
+
var el = document.getElementById('orchestration-board');
|
|
13388
|
+
if (!el) return;
|
|
13389
|
+
try {
|
|
13390
|
+
var data = await fetch('/api/orchestration').then(function(r) { return r.json(); });
|
|
13391
|
+
var agents = data.agents || [];
|
|
13392
|
+
var summary = data.summary || {};
|
|
13393
|
+
if (agents.length === 0) { el.innerHTML = ''; return; }
|
|
13394
|
+
var statusColors = {
|
|
13395
|
+
active: '#16a34a', running: '#16a34a', idle: '#d97706',
|
|
13396
|
+
stale: '#6b7280', failed: '#ef4444', paused: '#7c3aed', completed: '#3b82f6'
|
|
13397
|
+
};
|
|
13398
|
+
var html = '<div style="border:1px solid var(--border-primary);border-radius:10px;overflow:hidden;margin-bottom:4px;">';
|
|
13399
|
+
html += '<div style="display:flex;align-items:center;gap:16px;padding:8px 14px;background:var(--bg-secondary);border-bottom:1px solid var(--border-primary);font-size:12px;flex-wrap:wrap;">';
|
|
13400
|
+
html += '<span style="font-weight:700;color:var(--text-primary);font-size:13px;">🤖 Orchestration</span>';
|
|
13401
|
+
html += '<span style="color:var(--text-muted);"><strong style="color:var(--text-primary);">' + (summary.total || 0) + '</strong> agents</span>';
|
|
13402
|
+
if (summary.active) html += '<span style="color:#16a34a;"><strong>' + summary.active + '</strong> active</span>';
|
|
13403
|
+
if (summary.total_cost_usd) {
|
|
13404
|
+
html += '<span style="color:var(--text-muted);">$<strong style="color:var(--text-primary);">' + summary.total_cost_usd.toFixed(4) + '</strong> total cost</span>';
|
|
13405
|
+
}
|
|
13406
|
+
html += '</div>';
|
|
13407
|
+
html += '<div style="display:flex;flex-wrap:wrap;gap:8px;padding:10px;">';
|
|
13408
|
+
agents.forEach(function(a) {
|
|
13409
|
+
var color = statusColors[a.status] || '#6b7280';
|
|
13410
|
+
var glow = (a.status === 'active' || a.status === 'running') ? 'box-shadow:0 0 0 1px ' + color + '40;' : '';
|
|
13411
|
+
var costStr = (a.costUsd > 0) ? '$' + a.costUsd.toFixed(4) : '';
|
|
13412
|
+
var tokens = a.totalTokens >= 1000 ? (a.totalTokens / 1000).toFixed(1) + 'K tok' : (a.totalTokens > 0 ? a.totalTokens + ' tok' : '');
|
|
13413
|
+
var depthBadge = (a.depth > 1) ? '<span style="font-size:9px;background:var(--bg-secondary);border:1px solid var(--border-primary);border-radius:3px;padding:0 4px;color:var(--text-muted);margin-left:4px;">d' + a.depth + '</span>' : '';
|
|
13414
|
+
html += '<div style="flex:0 0 auto;min-width:155px;max-width:215px;border:1px solid var(--border-primary);border-radius:8px;padding:8px 10px;background:var(--bg-card);' + glow + '">';
|
|
13415
|
+
html += '<div style="display:flex;align-items:center;gap:5px;margin-bottom:4px;">';
|
|
13416
|
+
html += '<span style="width:8px;height:8px;border-radius:50%;background:' + color + ';display:inline-block;flex-shrink:0;"></span>';
|
|
13417
|
+
html += '<span style="font-size:12px;font-weight:600;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;" title="' + escHtml(a.displayName) + '">' + escHtml(a.displayName) + '</span>';
|
|
13418
|
+
html += depthBadge;
|
|
13419
|
+
html += '</div>';
|
|
13420
|
+
if (a.model && a.model !== 'unknown') {
|
|
13421
|
+
html += '<div style="font-size:10px;color:var(--text-muted);margin-bottom:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">' + escHtml(a.model) + '</div>';
|
|
13422
|
+
}
|
|
13423
|
+
if (costStr || tokens) {
|
|
13424
|
+
html += '<div style="display:flex;gap:8px;font-size:10px;color:var(--text-faint);">';
|
|
13425
|
+
if (costStr) html += '<span style="color:#16a34a;">' + escHtml(costStr) + '</span>';
|
|
13426
|
+
if (tokens) html += '<span>' + escHtml(tokens) + '</span>';
|
|
13427
|
+
html += '</div>';
|
|
13428
|
+
}
|
|
13429
|
+
html += '</div>';
|
|
13430
|
+
});
|
|
13431
|
+
html += '</div></div>';
|
|
13432
|
+
el.innerHTML = html;
|
|
13433
|
+
} catch(e) {
|
|
13434
|
+
var board = document.getElementById('orchestration-board');
|
|
13435
|
+
if (board) board.innerHTML = '';
|
|
13436
|
+
}
|
|
13437
|
+
}
|
|
13438
|
+
|
|
13386
13439
|
async function controlAgent(key, action) {
|
|
13387
13440
|
if (action === 'stop') {
|
|
13388
13441
|
if (!confirm('Stop agent ' + key + '? This will attempt to terminate it via the gateway and cannot be undone.')) return;
|
|
@@ -1032,6 +1032,39 @@ _HEARTBEAT_PLAN_TO_TIER = {
|
|
|
1032
1032
|
}
|
|
1033
1033
|
|
|
1034
1034
|
|
|
1035
|
+
def _sync_auto_update_with_plan(tier: str | None) -> None:
|
|
1036
|
+
"""Entitled accounts (Trial / Starter / Pro / Enterprise) keep the node
|
|
1037
|
+
current automatically: enable the opt-in ``auto_update`` flag so the
|
|
1038
|
+
daemon's update-check worker installs new releases (riding the 48h
|
|
1039
|
+
staleness rail). This is what makes "I'm on Pro, the node should just stay
|
|
1040
|
+
current" real without a manual ``pip install -U``.
|
|
1041
|
+
|
|
1042
|
+
Safety: respects an explicit opt-out (``CLAWMETRY_AUTO_UPDATE`` in
|
|
1043
|
+
0/false/no/off), only ever ENABLES (never auto-disables, so a user's manual
|
|
1044
|
+
choice survives a downgrade), and no-ops for free / inactive plans. Best
|
|
1045
|
+
effort — never raises."""
|
|
1046
|
+
try:
|
|
1047
|
+
if not tier or tier == "cloud_free":
|
|
1048
|
+
return
|
|
1049
|
+
_ov = os.environ.get("CLAWMETRY_AUTO_UPDATE", "").strip().lower()
|
|
1050
|
+
if _ov in ("0", "false", "no", "off"):
|
|
1051
|
+
return
|
|
1052
|
+
from routes.update_check import (
|
|
1053
|
+
_get_update_check_config as _gucc,
|
|
1054
|
+
_set_update_check_config as _succ,
|
|
1055
|
+
)
|
|
1056
|
+
cfg = _gucc() or {}
|
|
1057
|
+
if not cfg.get("auto_update"):
|
|
1058
|
+
_succ({"auto_update": True})
|
|
1059
|
+
log.info(
|
|
1060
|
+
"auto-update enabled for entitled plan (%s) — this node will keep "
|
|
1061
|
+
"itself current (48h stability window). Opt out any time with "
|
|
1062
|
+
"CLAWMETRY_AUTO_UPDATE=0.", tier,
|
|
1063
|
+
)
|
|
1064
|
+
except Exception as exc:
|
|
1065
|
+
log.debug("auto-update plan sync skipped: %s", exc)
|
|
1066
|
+
|
|
1067
|
+
|
|
1035
1068
|
def _persist_cloud_plan_to_disk(plan: str | None, trial_days_left=None) -> None:
|
|
1036
1069
|
"""Mirror the heartbeat plan into ``~/.clawmetry/cloud_plan.json`` so the
|
|
1037
1070
|
dashboard process (which runs ``clawmetry.entitlements.get_entitlement``)
|
|
@@ -1043,6 +1076,8 @@ def _persist_cloud_plan_to_disk(plan: str | None, trial_days_left=None) -> None:
|
|
|
1043
1076
|
is removed instead of written, so the resolver falls back to OSS-free
|
|
1044
1077
|
rather than granting a dead plan."""
|
|
1045
1078
|
tier = _HEARTBEAT_PLAN_TO_TIER.get(str(plan or "").strip().lower())
|
|
1079
|
+
# Entitled plan → keep this node current automatically (opt-out + 48h rail).
|
|
1080
|
+
_sync_auto_update_with_plan(tier)
|
|
1046
1081
|
try:
|
|
1047
1082
|
if tier is None:
|
|
1048
1083
|
if os.path.isfile(_CLOUD_PLAN_CACHE_PATH):
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
<div class="page" id="page-subagents">
|
|
2
2
|
<div class="refresh-bar">
|
|
3
3
|
<h2 style="font-size:16px;font-weight:700;color:var(--text-primary);margin:0;flex:1;" data-i18n="app.sub_agents_queue_lanes">🤖 Sub-Agents & Queue Lanes</h2>
|
|
4
|
-
<button class="refresh-btn" onclick="loadRunLedger();loadSubagents()" data-i18n="app.refresh">↻ Refresh</button>
|
|
4
|
+
<button class="refresh-btn" onclick="loadOrchestration();loadRunLedger();loadSubagents()" data-i18n="app.refresh">↻ Refresh</button>
|
|
5
5
|
</div>
|
|
6
|
+
<!-- Orchestration status board: one card per agent with status badge, cost,
|
|
7
|
+
model tag. Populated by loadOrchestration() from /api/orchestration.
|
|
8
|
+
Hidden automatically when no agents exist. -->
|
|
9
|
+
<div id="orchestration-board" style="margin-bottom:12px;"></div>
|
|
6
10
|
<!-- OpenClaw run-ledger lane monitor (cli / cron / subagent) + recent runs.
|
|
7
11
|
Populated by loadRunLedger() from /api/run-ledger. `runtime` is the
|
|
8
12
|
OpenClaw queue lane, so this is the live queue/concurrency view. -->
|
|
@@ -160,7 +160,7 @@ except ImportError:
|
|
|
160
160
|
metrics_service_pb2 = None
|
|
161
161
|
trace_service_pb2 = None
|
|
162
162
|
|
|
163
|
-
__version__ = "0.12.
|
|
163
|
+
__version__ = "0.12.417"
|
|
164
164
|
|
|
165
165
|
# Extensions (Phase 2): import the plugin host now, but defer the actual
|
|
166
166
|
# load_plugins() call until after the Flask app is created below so we can
|
|
@@ -2027,6 +2027,7 @@ def _try_local_store_subagents(_rows=None):
|
|
|
2027
2027
|
"depth": int(extra.get("depth") or 1),
|
|
2028
2028
|
"parent": r.get("parent_session_id") or extra.get("spawnedBy"),
|
|
2029
2029
|
"totalTokens": token_count,
|
|
2030
|
+
"costUsd": round(float(r.get("cost_usd") or 0.0), 4),
|
|
2030
2031
|
"runtime": runtime,
|
|
2031
2032
|
"runtimeMs": runtime_ms,
|
|
2032
2033
|
"startedAt": spawned_at_ms or updated_at_ms,
|
|
@@ -2417,6 +2418,29 @@ def _check_integrity(subagents):
|
|
|
2417
2418
|
return violations
|
|
2418
2419
|
|
|
2419
2420
|
|
|
2421
|
+
@bp_sessions.route("/api/orchestration")
|
|
2422
|
+
def api_orchestration():
|
|
2423
|
+
"""Compact orchestration status board — agent cards with cost and model tags.
|
|
2424
|
+
|
|
2425
|
+
Wraps the subagents DuckDB fast-path (same source as /api/subagents) and
|
|
2426
|
+
adds a per-agent ``costUsd`` field for the status-board panel rendered
|
|
2427
|
+
above the subagent tree. Returns an empty board when the local store is
|
|
2428
|
+
unavailable so the existing tree view still works via its own fallback.
|
|
2429
|
+
"""
|
|
2430
|
+
fast = _try_local_store_subagents()
|
|
2431
|
+
agents = (fast or {}).get("subagents", [])
|
|
2432
|
+
counts = (fast or {}).get("counts", {})
|
|
2433
|
+
total_cost_usd = round(sum(a.get("costUsd", 0.0) for a in agents), 4)
|
|
2434
|
+
return jsonify({
|
|
2435
|
+
"agents": agents,
|
|
2436
|
+
"summary": {
|
|
2437
|
+
"total": counts.get("total", 0),
|
|
2438
|
+
"active": counts.get("active", 0),
|
|
2439
|
+
"total_cost_usd": total_cost_usd,
|
|
2440
|
+
},
|
|
2441
|
+
})
|
|
2442
|
+
|
|
2443
|
+
|
|
2420
2444
|
@bp_sessions.route("/api/subagents/integrity")
|
|
2421
2445
|
def api_subagents_integrity():
|
|
2422
2446
|
"""Validate subagent state-machine: orphans, cycles, duplicate completions.
|
|
@@ -223,12 +223,34 @@ def _check_for_update():
|
|
|
223
223
|
|
|
224
224
|
_record_update_check(current, latest, update_available, CHANGELOG_URL)
|
|
225
225
|
|
|
226
|
+
# Age (hours) of the latest release, for the auto-update staleness rail.
|
|
227
|
+
# NEVER blocks the banner — only the silent upgrade waits for the release
|
|
228
|
+
# to have survived a stability window before installing it unattended.
|
|
229
|
+
_age_h = None
|
|
230
|
+
try:
|
|
231
|
+
_files = (data.get("releases", {}) or {}).get(latest) or []
|
|
232
|
+
_times = [
|
|
233
|
+
f.get("upload_time_iso_8601") or f.get("upload_time")
|
|
234
|
+
for f in _files
|
|
235
|
+
if f.get("upload_time_iso_8601") or f.get("upload_time")
|
|
236
|
+
]
|
|
237
|
+
if _times:
|
|
238
|
+
from datetime import datetime as _dt, timezone as _tz
|
|
239
|
+
_t0 = min(
|
|
240
|
+
_dt.fromisoformat(str(t).replace("Z", "+00:00")) for t in _times
|
|
241
|
+
)
|
|
242
|
+
if _t0.tzinfo is None:
|
|
243
|
+
_t0 = _t0.replace(tzinfo=_tz.utc)
|
|
244
|
+
_age_h = (_dt.now(_tz.utc) - _t0).total_seconds() / 3600.0
|
|
245
|
+
except Exception:
|
|
246
|
+
_age_h = None
|
|
247
|
+
|
|
226
248
|
# Auto-update: if the user opted in, install the newer release now (no
|
|
227
249
|
# click). Runs in the always-on dashboard server process, so it works
|
|
228
250
|
# with no browser open. Guarded so a pending restart isn't re-triggered.
|
|
229
251
|
if update_available:
|
|
230
252
|
try:
|
|
231
|
-
_maybe_auto_update(current, latest)
|
|
253
|
+
_maybe_auto_update(current, latest, _age_h)
|
|
232
254
|
except Exception as exc:
|
|
233
255
|
log.warning("auto-update trigger failed: %s", exc)
|
|
234
256
|
|
|
@@ -246,14 +268,30 @@ def _check_for_update():
|
|
|
246
268
|
_auto_update_in_progress = False
|
|
247
269
|
|
|
248
270
|
|
|
249
|
-
def _maybe_auto_update(current, latest):
|
|
250
|
-
"""Install a newer release automatically when ``auto_update`` is enabled.
|
|
271
|
+
def _maybe_auto_update(current, latest, age_hours=None):
|
|
272
|
+
"""Install a newer release automatically when ``auto_update`` is enabled.
|
|
273
|
+
|
|
274
|
+
Staleness rail: unattended upgrades wait until the release has been on PyPI
|
|
275
|
+
for at least ``CLAWMETRY_AUTOUPDATE_MIN_AGE_HOURS`` (default 48h), so a node
|
|
276
|
+
never auto-installs a brand-new (possibly broken) release the instant it
|
|
277
|
+
publishes. The update banner is unaffected — only the silent upgrade waits.
|
|
278
|
+
``age_hours=None`` (age unknown) does not block, preserving prior behaviour.
|
|
279
|
+
"""
|
|
251
280
|
global _auto_update_in_progress
|
|
252
281
|
if _auto_update_in_progress:
|
|
253
282
|
return
|
|
254
283
|
cfg = _get_update_check_config()
|
|
255
284
|
if not cfg.get("auto_update"):
|
|
256
285
|
return
|
|
286
|
+
try:
|
|
287
|
+
import os as _os
|
|
288
|
+
_min_age = float(_os.environ.get("CLAWMETRY_AUTOUPDATE_MIN_AGE_HOURS", "48") or 48)
|
|
289
|
+
except Exception:
|
|
290
|
+
_min_age = 48.0
|
|
291
|
+
if age_hours is not None and age_hours < _min_age:
|
|
292
|
+
log.info("auto-update: holding v%s (released %.1fh ago < %.0fh stability "
|
|
293
|
+
"window) — will install once it ages in", latest, age_hours, _min_age)
|
|
294
|
+
return
|
|
257
295
|
_auto_update_in_progress = True
|
|
258
296
|
log.info("auto-update: opted in — upgrading clawmetry v%s -> v%s", current, latest)
|
|
259
297
|
try:
|
|
@@ -70,3 +70,55 @@ def test_auto_update_in_allowed_config_keys(monkeypatch):
|
|
|
70
70
|
with app.test_request_context(json={"auto_update": True, "bogus": "x"}):
|
|
71
71
|
uc.api_update_check_config_post()
|
|
72
72
|
assert captured == {"auto_update": True}, "auto_update must pass the allow-list, bogus keys filtered"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_auto_update_holds_fresh_release(monkeypatch):
|
|
76
|
+
uc = _uc()
|
|
77
|
+
calls = []
|
|
78
|
+
_mock_self_update(monkeypatch, calls)
|
|
79
|
+
monkeypatch.setattr(uc, "_get_update_check_config", lambda: {"auto_update": True})
|
|
80
|
+
monkeypatch.setenv("CLAWMETRY_AUTOUPDATE_MIN_AGE_HOURS", "48")
|
|
81
|
+
# 2h-old release → held (too fresh)
|
|
82
|
+
uc._maybe_auto_update("0.12.1", "0.12.2", age_hours=2.0)
|
|
83
|
+
assert calls == [], "must hold a release younger than the stability window"
|
|
84
|
+
# 72h-old release → installs
|
|
85
|
+
uc._maybe_auto_update("0.12.1", "0.12.2", age_hours=72.0)
|
|
86
|
+
assert calls == ["auto"], "must install once the release has aged in"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_auto_update_unknown_age_does_not_block(monkeypatch):
|
|
90
|
+
uc = _uc()
|
|
91
|
+
calls = []
|
|
92
|
+
_mock_self_update(monkeypatch, calls)
|
|
93
|
+
monkeypatch.setattr(uc, "_get_update_check_config", lambda: {"auto_update": True})
|
|
94
|
+
uc._maybe_auto_update("0.12.1", "0.12.2", age_hours=None)
|
|
95
|
+
assert calls == ["auto"], "unknown age must not block (back-compat)"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_entitled_plan_enables_auto_update(monkeypatch):
|
|
99
|
+
import clawmetry.sync as S
|
|
100
|
+
import routes.update_check as uc
|
|
101
|
+
state = {"auto_update": False}
|
|
102
|
+
monkeypatch.setattr(uc, "_get_update_check_config", lambda: dict(state))
|
|
103
|
+
monkeypatch.setattr(uc, "_set_update_check_config", lambda upd: state.update(upd))
|
|
104
|
+
monkeypatch.delenv("CLAWMETRY_AUTO_UPDATE", raising=False)
|
|
105
|
+
# free / inactive → unchanged
|
|
106
|
+
S._sync_auto_update_with_plan("cloud_free"); assert state["auto_update"] is False
|
|
107
|
+
S._sync_auto_update_with_plan(None); assert state["auto_update"] is False
|
|
108
|
+
# entitled → enabled
|
|
109
|
+
S._sync_auto_update_with_plan("trial"); assert state["auto_update"] is True
|
|
110
|
+
S._sync_auto_update_with_plan("cloud_pro"); assert state["auto_update"] is True
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_entitled_plan_respects_optout_and_never_disables(monkeypatch):
|
|
114
|
+
import clawmetry.sync as S
|
|
115
|
+
import routes.update_check as uc
|
|
116
|
+
state = {"auto_update": False}
|
|
117
|
+
monkeypatch.setattr(uc, "_get_update_check_config", lambda: dict(state))
|
|
118
|
+
monkeypatch.setattr(uc, "_set_update_check_config", lambda upd: state.update(upd))
|
|
119
|
+
monkeypatch.setenv("CLAWMETRY_AUTO_UPDATE", "0")
|
|
120
|
+
S._sync_auto_update_with_plan("cloud_pro"); assert state["auto_update"] is False # opt-out
|
|
121
|
+
# never auto-DISABLES a user's manual choice on downgrade
|
|
122
|
+
monkeypatch.delenv("CLAWMETRY_AUTO_UPDATE", raising=False)
|
|
123
|
+
state["auto_update"] = True
|
|
124
|
+
S._sync_auto_update_with_plan("cloud_free"); assert state["auto_update"] is True
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/resources/add-nemoclaw-clawmetry-preset.sh
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clawmetry-0.12.415 → clawmetry-0.12.417}/clawmetry/static/v2/dist/assets/index-NbINX9rU.css
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|