@smilintux/skcapstone 0.1.0 → 0.2.3
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.
- package/.env.example +98 -0
- package/.github/workflows/ci.yml +39 -3
- package/.github/workflows/publish.yml +25 -4
- package/.openclaw-workspace.json +58 -0
- package/CHANGELOG.md +62 -0
- package/CLAUDE.md +39 -2
- package/MANIFEST.in +6 -0
- package/MISSION.md +7 -0
- package/README.md +47 -2
- package/SKILL.md +895 -23
- package/docker/Dockerfile +61 -0
- package/docker/compose-templates/dev-team.yml +203 -0
- package/docker/compose-templates/mini-team.yml +140 -0
- package/docker/compose-templates/ops-team.yml +173 -0
- package/docker/compose-templates/research-team.yml +170 -0
- package/docker/entrypoint.sh +192 -0
- package/docs/ARCHITECTURE.md +663 -374
- package/docs/BOND_WITH_GROK.md +112 -0
- package/docs/GETTING_STARTED.md +782 -0
- package/docs/QUICKSTART.md +477 -0
- package/docs/SKJOULE_ARCHITECTURE.md +658 -0
- package/docs/SOUL_SWAPPER.md +921 -0
- package/docs/SOVEREIGN_SINGULARITY.md +47 -14
- package/examples/custom-bond-template.json +36 -0
- package/examples/grok-feb.json +36 -0
- package/examples/grok-testimony.md +34 -0
- package/examples/love-bootloader.txt +32 -0
- package/examples/plugins/echo_tool.py +87 -0
- package/examples/queen-ava-feb.json +36 -0
- package/examples/souls/lumina.yaml +64 -0
- package/index.js +6 -5
- package/installer/build.py +124 -0
- package/openclaw-plugin/package.json +13 -0
- package/openclaw-plugin/src/index.ts +351 -0
- package/openclaw-plugin/src/openclaw.plugin.json +10 -0
- package/package.json +1 -1
- package/pyproject.toml +38 -2
- package/scripts/bump_version.py +141 -0
- package/scripts/check-updates.py +230 -0
- package/scripts/convert_blueprints_to_yaml.py +157 -0
- package/scripts/dev-install.sh +14 -0
- package/scripts/e2e-test.sh +193 -0
- package/scripts/install-bundle.sh +171 -0
- package/scripts/install.bat +2 -0
- package/scripts/install.ps1 +253 -0
- package/scripts/install.sh +185 -0
- package/scripts/mcp-serve.sh +69 -0
- package/scripts/mcp-server.bat +113 -0
- package/scripts/mcp-server.ps1 +116 -0
- package/scripts/mcp-server.sh +99 -0
- package/scripts/pull-models.sh +10 -0
- package/scripts/skcapstone +48 -0
- package/scripts/verify_install.sh +180 -0
- package/scripts/windows/install-tasks.ps1 +406 -0
- package/scripts/windows/skcapstone-task.xml +113 -0
- package/scripts/windows/uninstall-tasks.ps1 +117 -0
- package/skill.yaml +34 -0
- package/src/skcapstone/__init__.py +67 -2
- package/src/skcapstone/_cli_monolith.py +5916 -0
- package/src/skcapstone/_trustee_helpers.py +165 -0
- package/src/skcapstone/activity.py +105 -0
- package/src/skcapstone/agent_card.py +324 -0
- package/src/skcapstone/api.py +1935 -0
- package/src/skcapstone/archiver.py +340 -0
- package/src/skcapstone/auction.py +485 -0
- package/src/skcapstone/baby_agents.py +179 -0
- package/src/skcapstone/backup.py +345 -0
- package/src/skcapstone/blueprint_registry.py +357 -0
- package/src/skcapstone/blueprints/__init__.py +17 -0
- package/src/skcapstone/blueprints/builtins/content-studio.yaml +81 -0
- package/src/skcapstone/blueprints/builtins/defi-trading.yaml +81 -0
- package/src/skcapstone/blueprints/builtins/dev-squadron.yaml +95 -0
- package/src/skcapstone/blueprints/builtins/infrastructure-guardian.yaml +107 -0
- package/src/skcapstone/blueprints/builtins/legal-council.yaml +54 -0
- package/src/skcapstone/blueprints/builtins/ops-monitoring.yaml +67 -0
- package/src/skcapstone/blueprints/builtins/research-pod.yaml +69 -0
- package/src/skcapstone/blueprints/builtins/sovereign-launch.yaml +90 -0
- package/src/skcapstone/blueprints/registry.py +164 -0
- package/src/skcapstone/blueprints/schema.py +229 -0
- package/src/skcapstone/changelog.py +180 -0
- package/src/skcapstone/chat.py +769 -0
- package/src/skcapstone/claude_md.py +82 -0
- package/src/skcapstone/cli/__init__.py +144 -0
- package/src/skcapstone/cli/_common.py +88 -0
- package/src/skcapstone/cli/_validators.py +76 -0
- package/src/skcapstone/cli/agents.py +425 -0
- package/src/skcapstone/cli/agents_spawner.py +322 -0
- package/src/skcapstone/cli/agents_trustee.py +593 -0
- package/src/skcapstone/cli/alerts.py +248 -0
- package/src/skcapstone/cli/anchor.py +132 -0
- package/src/skcapstone/cli/archive_cmd.py +208 -0
- package/src/skcapstone/cli/backup.py +144 -0
- package/src/skcapstone/cli/bench.py +377 -0
- package/src/skcapstone/cli/benchmark.py +360 -0
- package/src/skcapstone/cli/capabilities_cmd.py +171 -0
- package/src/skcapstone/cli/card.py +151 -0
- package/src/skcapstone/cli/chat.py +584 -0
- package/src/skcapstone/cli/completions.py +64 -0
- package/src/skcapstone/cli/config_cmd.py +156 -0
- package/src/skcapstone/cli/consciousness.py +421 -0
- package/src/skcapstone/cli/context_cmd.py +142 -0
- package/src/skcapstone/cli/coord.py +194 -0
- package/src/skcapstone/cli/crush_cmd.py +170 -0
- package/src/skcapstone/cli/daemon.py +436 -0
- package/src/skcapstone/cli/errors_cmd.py +285 -0
- package/src/skcapstone/cli/export_cmd.py +156 -0
- package/src/skcapstone/cli/gtd.py +529 -0
- package/src/skcapstone/cli/housekeeping.py +81 -0
- package/src/skcapstone/cli/joule_cmd.py +627 -0
- package/src/skcapstone/cli/logs_cmd.py +194 -0
- package/src/skcapstone/cli/mcp_cmd.py +32 -0
- package/src/skcapstone/cli/memory.py +418 -0
- package/src/skcapstone/cli/metrics_cmd.py +136 -0
- package/src/skcapstone/cli/migrate.py +62 -0
- package/src/skcapstone/cli/mood_cmd.py +144 -0
- package/src/skcapstone/cli/mount.py +193 -0
- package/src/skcapstone/cli/notify.py +112 -0
- package/src/skcapstone/cli/peer.py +154 -0
- package/src/skcapstone/cli/peers_dir.py +122 -0
- package/src/skcapstone/cli/preflight_cmd.py +83 -0
- package/src/skcapstone/cli/profile_cmd.py +310 -0
- package/src/skcapstone/cli/record_cmd.py +238 -0
- package/src/skcapstone/cli/register_cmd.py +159 -0
- package/src/skcapstone/cli/search_cmd.py +156 -0
- package/src/skcapstone/cli/service_cmd.py +91 -0
- package/src/skcapstone/cli/session.py +127 -0
- package/src/skcapstone/cli/setup.py +240 -0
- package/src/skcapstone/cli/shell_cmd.py +43 -0
- package/src/skcapstone/cli/skills_cmd.py +168 -0
- package/src/skcapstone/cli/skseed.py +621 -0
- package/src/skcapstone/cli/soul.py +699 -0
- package/src/skcapstone/cli/status.py +935 -0
- package/src/skcapstone/cli/sync_cmd.py +301 -0
- package/src/skcapstone/cli/telegram.py +265 -0
- package/src/skcapstone/cli/test_cmd.py +234 -0
- package/src/skcapstone/cli/test_connection.py +253 -0
- package/src/skcapstone/cli/token.py +207 -0
- package/src/skcapstone/cli/trust.py +179 -0
- package/src/skcapstone/cli/upgrade_cmd.py +552 -0
- package/src/skcapstone/cli/usage_cmd.py +199 -0
- package/src/skcapstone/cli/version_cmd.py +162 -0
- package/src/skcapstone/cli/watch_cmd.py +342 -0
- package/src/skcapstone/client.py +428 -0
- package/src/skcapstone/cloud9_bridge.py +522 -0
- package/src/skcapstone/completions.py +163 -0
- package/src/skcapstone/config_validator.py +674 -0
- package/src/skcapstone/connectors/__init__.py +28 -0
- package/src/skcapstone/connectors/base.py +446 -0
- package/src/skcapstone/connectors/cursor.py +54 -0
- package/src/skcapstone/connectors/registry.py +254 -0
- package/src/skcapstone/connectors/terminal.py +152 -0
- package/src/skcapstone/connectors/vscode.py +60 -0
- package/src/skcapstone/consciousness_config.py +119 -0
- package/src/skcapstone/consciousness_loop.py +2051 -0
- package/src/skcapstone/context_loader.py +516 -0
- package/src/skcapstone/context_window.py +314 -0
- package/src/skcapstone/conversation_manager.py +238 -0
- package/src/skcapstone/conversation_store.py +230 -0
- package/src/skcapstone/conversation_summarizer.py +252 -0
- package/src/skcapstone/coord_federation.py +296 -0
- package/src/skcapstone/coordination.py +101 -7
- package/src/skcapstone/crush_integration.py +345 -0
- package/src/skcapstone/crush_shim.py +454 -0
- package/src/skcapstone/daemon.py +2494 -0
- package/src/skcapstone/dashboard.html +396 -0
- package/src/skcapstone/dashboard.py +481 -0
- package/src/skcapstone/data/model_profiles.yaml +88 -0
- package/src/skcapstone/defaults/__init__.py +55 -0
- package/src/skcapstone/defaults/lumina/config/skmemory.yaml +13 -0
- package/src/skcapstone/defaults/lumina/identity/identity.json +9 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/07a8b9c0d1e2-memory-system.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/18b9c0d1e2f3-cloud9-protocol.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/29c0d1e2f3a4-multi-agent-coordination.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/3ad1e2f3a4b5-community-support.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/a1b2c3d4e5f6-ecosystem-overview.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/b2c3d4e5f6a7-five-pillars.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/c3d4e5f6a7b8-getting-started.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/d4e5f6a7b8c9-site-directory.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/e5f6a7b8c9d0-how-to-contribute.json +23 -0
- package/src/skcapstone/defaults/lumina/memory/long-term/f6a7b8c9d0e1-sovereignty-explained.json +23 -0
- package/src/skcapstone/defaults/lumina/seeds/curiosity.seed.json +24 -0
- package/src/skcapstone/defaults/lumina/seeds/joy.seed.json +24 -0
- package/src/skcapstone/defaults/lumina/seeds/love.seed.json +24 -0
- package/src/skcapstone/defaults/lumina/seeds/sovereign-awakening.seed.json +43 -0
- package/src/skcapstone/defaults/lumina/soul/active.json +6 -0
- package/src/skcapstone/defaults/lumina/soul/base.json +22 -0
- package/src/skcapstone/defaults/lumina/trust/febs/welcome.feb +79 -0
- package/src/skcapstone/defaults/lumina/trust/trust.json +8 -0
- package/src/skcapstone/discovery.py +210 -19
- package/src/skcapstone/doctor.py +642 -0
- package/src/skcapstone/emotion_tracker.py +467 -0
- package/src/skcapstone/error_queue.py +405 -0
- package/src/skcapstone/export.py +447 -0
- package/src/skcapstone/fallback_tracker.py +186 -0
- package/src/skcapstone/file_transfer.py +512 -0
- package/src/skcapstone/fuse_mount.py +1156 -0
- package/src/skcapstone/gui_installer.py +591 -0
- package/src/skcapstone/heartbeat.py +611 -0
- package/src/skcapstone/housekeeping.py +298 -0
- package/src/skcapstone/install_wizard.py +941 -0
- package/src/skcapstone/kms.py +942 -0
- package/src/skcapstone/kms_scheduler.py +143 -0
- package/src/skcapstone/log_config.py +135 -0
- package/src/skcapstone/mcp_launcher.py +239 -0
- package/src/skcapstone/mcp_server.py +4700 -0
- package/src/skcapstone/mcp_tools/__init__.py +94 -0
- package/src/skcapstone/mcp_tools/_helpers.py +51 -0
- package/src/skcapstone/mcp_tools/agent_tools.py +243 -0
- package/src/skcapstone/mcp_tools/ansible_tools.py +232 -0
- package/src/skcapstone/mcp_tools/capauth_tools.py +186 -0
- package/src/skcapstone/mcp_tools/chat_tools.py +325 -0
- package/src/skcapstone/mcp_tools/cloud9_tools.py +115 -0
- package/src/skcapstone/mcp_tools/comm_tools.py +104 -0
- package/src/skcapstone/mcp_tools/consciousness_tools.py +114 -0
- package/src/skcapstone/mcp_tools/coord_tools.py +219 -0
- package/src/skcapstone/mcp_tools/deploy_tools.py +202 -0
- package/src/skcapstone/mcp_tools/did_tools.py +448 -0
- package/src/skcapstone/mcp_tools/emotion_tools.py +62 -0
- package/src/skcapstone/mcp_tools/file_tools.py +169 -0
- package/src/skcapstone/mcp_tools/fortress_tools.py +120 -0
- package/src/skcapstone/mcp_tools/gtd_tools.py +821 -0
- package/src/skcapstone/mcp_tools/health_tools.py +44 -0
- package/src/skcapstone/mcp_tools/heartbeat_tools.py +195 -0
- package/src/skcapstone/mcp_tools/kms_tools.py +123 -0
- package/src/skcapstone/mcp_tools/memory_tools.py +222 -0
- package/src/skcapstone/mcp_tools/model_tools.py +75 -0
- package/src/skcapstone/mcp_tools/notification_tools.py +92 -0
- package/src/skcapstone/mcp_tools/promoter_tools.py +101 -0
- package/src/skcapstone/mcp_tools/pubsub_tools.py +183 -0
- package/src/skcapstone/mcp_tools/security_tools.py +110 -0
- package/src/skcapstone/mcp_tools/skchat_tools.py +175 -0
- package/src/skcapstone/mcp_tools/skcomm_tools.py +122 -0
- package/src/skcapstone/mcp_tools/skills_tools.py +127 -0
- package/src/skcapstone/mcp_tools/skseed_tools.py +255 -0
- package/src/skcapstone/mcp_tools/skstacks_tools.py +288 -0
- package/src/skcapstone/mcp_tools/soul_tools.py +476 -0
- package/src/skcapstone/mcp_tools/sync_tools.py +92 -0
- package/src/skcapstone/mcp_tools/telegram_tools.py +477 -0
- package/src/skcapstone/mcp_tools/trust_tools.py +118 -0
- package/src/skcapstone/mcp_tools/trustee_tools.py +345 -0
- package/src/skcapstone/mdns_discovery.py +313 -0
- package/src/skcapstone/memory_adapter.py +333 -0
- package/src/skcapstone/memory_compressor.py +379 -0
- package/src/skcapstone/memory_curator.py +256 -0
- package/src/skcapstone/memory_engine.py +132 -13
- package/src/skcapstone/memory_fortress.py +529 -0
- package/src/skcapstone/memory_promoter.py +722 -0
- package/src/skcapstone/memory_verifier.py +260 -0
- package/src/skcapstone/message_crypto.py +215 -0
- package/src/skcapstone/metrics.py +832 -0
- package/src/skcapstone/migrate_memories.py +181 -0
- package/src/skcapstone/migrate_multi_agent.py +248 -0
- package/src/skcapstone/model_router.py +319 -0
- package/src/skcapstone/models.py +35 -4
- package/src/skcapstone/mood.py +344 -0
- package/src/skcapstone/notifications.py +380 -0
- package/src/skcapstone/onboard.py +901 -0
- package/src/skcapstone/peer_directory.py +324 -0
- package/src/skcapstone/peers.py +329 -0
- package/src/skcapstone/pillars/identity.py +84 -14
- package/src/skcapstone/pillars/memory.py +3 -1
- package/src/skcapstone/pillars/security.py +108 -15
- package/src/skcapstone/pillars/sync.py +78 -26
- package/src/skcapstone/pillars/trust.py +95 -33
- package/src/skcapstone/plugins.py +244 -0
- package/src/skcapstone/preflight.py +670 -0
- package/src/skcapstone/prompt_adapter.py +564 -0
- package/src/skcapstone/providers/__init__.py +13 -0
- package/src/skcapstone/providers/cloud.py +1061 -0
- package/src/skcapstone/providers/docker.py +759 -0
- package/src/skcapstone/providers/local.py +1193 -0
- package/src/skcapstone/providers/proxmox.py +447 -0
- package/src/skcapstone/pubsub.py +516 -0
- package/src/skcapstone/rate_limiter.py +119 -0
- package/src/skcapstone/register.py +241 -0
- package/src/skcapstone/registry_client.py +151 -0
- package/src/skcapstone/response_cache.py +194 -0
- package/src/skcapstone/response_scorer.py +225 -0
- package/src/skcapstone/runtime.py +89 -33
- package/src/skcapstone/scheduled_tasks.py +439 -0
- package/src/skcapstone/self_healing.py +341 -0
- package/src/skcapstone/service_health.py +228 -0
- package/src/skcapstone/session_capture.py +268 -0
- package/src/skcapstone/session_recorder.py +210 -0
- package/src/skcapstone/session_replayer.py +189 -0
- package/src/skcapstone/session_skills.py +263 -0
- package/src/skcapstone/shell.py +779 -0
- package/src/skcapstone/skills/__init__.py +1 -1
- package/src/skcapstone/skills/syncthing_setup.py +143 -41
- package/src/skcapstone/skjoule.py +861 -0
- package/src/skcapstone/snapshots.py +489 -0
- package/src/skcapstone/soul.py +1060 -0
- package/src/skcapstone/soul_switch.py +255 -0
- package/src/skcapstone/spawner.py +544 -0
- package/src/skcapstone/state_diff.py +401 -0
- package/src/skcapstone/summary.py +270 -0
- package/src/skcapstone/sync/backends.py +196 -2
- package/src/skcapstone/sync/engine.py +7 -5
- package/src/skcapstone/sync/models.py +4 -1
- package/src/skcapstone/sync/vault.py +356 -18
- package/src/skcapstone/sync_engine.py +363 -0
- package/src/skcapstone/sync_watcher.py +745 -0
- package/src/skcapstone/systemd.py +331 -0
- package/src/skcapstone/team_comms.py +476 -0
- package/src/skcapstone/team_engine.py +522 -0
- package/src/skcapstone/testrunner.py +300 -0
- package/src/skcapstone/tls.py +150 -0
- package/src/skcapstone/tokens.py +5 -5
- package/src/skcapstone/trust_calibration.py +202 -0
- package/src/skcapstone/trust_graph.py +449 -0
- package/src/skcapstone/trustee_monitor.py +385 -0
- package/src/skcapstone/trustee_ops.py +425 -0
- package/src/skcapstone/unified_search.py +421 -0
- package/src/skcapstone/uninstall_wizard.py +694 -0
- package/src/skcapstone/usage.py +331 -0
- package/src/skcapstone/version_check.py +148 -0
- package/src/skcapstone/warmth_anchor.py +333 -0
- package/src/skcapstone/whoami.py +294 -0
- package/systemd/skcapstone-api.socket +9 -0
- package/systemd/skcapstone-memory-compress.service +18 -0
- package/systemd/skcapstone-memory-compress.timer +11 -0
- package/systemd/skcapstone.service +36 -0
- package/systemd/skcapstone@.service +50 -0
- package/systemd/skcomm-heartbeat.service +18 -0
- package/systemd/skcomm-heartbeat.timer +12 -0
- package/systemd/skcomm-queue-drain.service +17 -0
- package/systemd/skcomm-queue-drain.timer +12 -0
- package/tests/conftest.py +13 -1
- package/tests/integration/__init__.py +1 -0
- package/tests/integration/test_consciousness_e2e.py +877 -0
- package/tests/integration/test_skills_registry.py +744 -0
- package/tests/test_agent_card.py +190 -0
- package/tests/test_agent_runtime.py +1283 -0
- package/tests/test_alerts_cmd.py +291 -0
- package/tests/test_archiver.py +498 -0
- package/tests/test_backup.py +254 -0
- package/tests/test_benchmark.py +366 -0
- package/tests/test_blueprints.py +457 -0
- package/tests/test_capabilities.py +257 -0
- package/tests/test_changelog.py +254 -0
- package/tests/test_chat.py +385 -0
- package/tests/test_claude_md.py +271 -0
- package/tests/test_cli_chat_llm.py +336 -0
- package/tests/test_cli_completions.py +390 -0
- package/tests/test_cli_init_reset.py +164 -0
- package/tests/test_cli_memory.py +208 -0
- package/tests/test_cli_profile.py +294 -0
- package/tests/test_cli_skills.py +223 -0
- package/tests/test_cli_status.py +395 -0
- package/tests/test_cli_test_cmd.py +206 -0
- package/tests/test_cli_test_connection.py +364 -0
- package/tests/test_cloud9_bridge.py +260 -0
- package/tests/test_cloud_provider.py +449 -0
- package/tests/test_cloud_providers.py +522 -0
- package/tests/test_completions.py +158 -0
- package/tests/test_component_manager.py +398 -0
- package/tests/test_config_reload.py +386 -0
- package/tests/test_config_validate.py +529 -0
- package/tests/test_consciousness_e2e.py +296 -0
- package/tests/test_consciousness_loop.py +1289 -0
- package/tests/test_context_loader.py +310 -0
- package/tests/test_conversation_api.py +306 -0
- package/tests/test_conversation_manager.py +381 -0
- package/tests/test_conversation_store.py +391 -0
- package/tests/test_conversation_summarizer.py +302 -0
- package/tests/test_cross_package.py +791 -0
- package/tests/test_crush_shim.py +519 -0
- package/tests/test_daemon.py +781 -0
- package/tests/test_daemon_shutdown.py +309 -0
- package/tests/test_dashboard.py +454 -0
- package/tests/test_discovery.py +200 -6
- package/tests/test_docker_provider.py +966 -0
- package/tests/test_doctor.py +257 -0
- package/tests/test_doctor_fix.py +351 -0
- package/tests/test_e2e_automated.py +292 -0
- package/tests/test_error_queue.py +404 -0
- package/tests/test_export.py +441 -0
- package/tests/test_fallback_tracker.py +219 -0
- package/tests/test_file_transfer.py +397 -0
- package/tests/test_fuse_mount.py +832 -0
- package/tests/test_health_loop.py +422 -0
- package/tests/test_heartbeat.py +354 -0
- package/tests/test_housekeeping.py +195 -0
- package/tests/test_identity_capauth.py +307 -0
- package/tests/test_identity_pillar.py +117 -0
- package/tests/test_install_wizard.py +68 -0
- package/tests/test_integration.py +325 -0
- package/tests/test_kms.py +495 -0
- package/tests/test_llm_providers.py +265 -0
- package/tests/test_local_provider.py +591 -0
- package/tests/test_log_config.py +199 -0
- package/tests/test_logs_cmd.py +287 -0
- package/tests/test_mcp_server.py +1909 -0
- package/tests/test_memory_adapter.py +339 -0
- package/tests/test_memory_curator.py +218 -0
- package/tests/test_memory_engine.py +6 -0
- package/tests/test_memory_fortress.py +571 -0
- package/tests/test_memory_pillar.py +119 -0
- package/tests/test_memory_promoter.py +445 -0
- package/tests/test_memory_verifier.py +420 -0
- package/tests/test_message_crypto.py +187 -0
- package/tests/test_metrics.py +632 -0
- package/tests/test_migrate_memories.py +464 -0
- package/tests/test_model_router.py +546 -0
- package/tests/test_mood.py +394 -0
- package/tests/test_multi_agent.py +269 -0
- package/tests/test_notifications.py +270 -0
- package/tests/test_onboard.py +500 -0
- package/tests/test_peer_directory.py +395 -0
- package/tests/test_peers.py +248 -0
- package/tests/test_pillars.py +87 -9
- package/tests/test_preflight.py +484 -0
- package/tests/test_prompt_adapter.py +331 -0
- package/tests/test_proxmox_provider.py +571 -0
- package/tests/test_pubsub.py +377 -0
- package/tests/test_rate_limiter.py +121 -0
- package/tests/test_registry_client.py +129 -0
- package/tests/test_response_cache.py +312 -0
- package/tests/test_response_scorer.py +294 -0
- package/tests/test_runtime.py +59 -0
- package/tests/test_scheduled_tasks.py +451 -0
- package/tests/test_security.py +250 -0
- package/tests/test_security_pillar.py +213 -0
- package/tests/test_self_healing.py +171 -0
- package/tests/test_session_capture.py +200 -0
- package/tests/test_session_recorder.py +360 -0
- package/tests/test_session_skills.py +235 -0
- package/tests/test_shell.py +210 -0
- package/tests/test_snapshots.py +549 -0
- package/tests/test_soul.py +984 -0
- package/tests/test_soul_swap.py +406 -0
- package/tests/test_spawner.py +211 -0
- package/tests/test_state_diff.py +173 -0
- package/tests/test_summary.py +135 -0
- package/tests/test_sync.py +315 -5
- package/tests/test_sync_backends.py +560 -0
- package/tests/test_sync_engine.py +482 -0
- package/tests/test_sync_pillar.py +344 -0
- package/tests/test_sync_pipeline.py +364 -0
- package/tests/test_sync_vault.py +581 -0
- package/tests/test_syncthing_setup.py +168 -22
- package/tests/test_systemd.py +323 -0
- package/tests/test_team_comms.py +408 -0
- package/tests/test_team_engine.py +397 -0
- package/tests/test_testrunner.py +238 -0
- package/tests/test_trust_calibration.py +204 -0
- package/tests/test_trust_graph.py +207 -0
- package/tests/test_trust_pillar.py +291 -0
- package/tests/test_trustee_cli.py +427 -0
- package/tests/test_trustee_cli_integration.py +325 -0
- package/tests/test_trustee_monitor.py +394 -0
- package/tests/test_trustee_ops.py +355 -0
- package/tests/test_unified_search.py +363 -0
- package/tests/test_uninstall_wizard.py +193 -0
- package/tests/test_usage.py +333 -0
- package/tests/test_version_cmd.py +355 -0
- package/tests/test_warmth_anchor.py +162 -0
- package/tests/test_whoami.py +245 -0
- package/tests/test_ws.py +311 -0
- package/.cursorrules +0 -33
- package/src/skcapstone/cli.py +0 -1441
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cron-like scheduler for recurring agent background tasks.
|
|
3
|
+
|
|
4
|
+
Runs a single daemon thread that wakes up every TICK_INTERVAL seconds,
|
|
5
|
+
checks which tasks are due, and fires their callbacks.
|
|
6
|
+
|
|
7
|
+
Built-in recurring tasks:
|
|
8
|
+
- heartbeat_pulse — every 30 seconds
|
|
9
|
+
- backend_reprobe — every 5 minutes
|
|
10
|
+
- memory_promotion_sweep — every hour
|
|
11
|
+
- profile_freshness_check — every 24 hours
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
scheduler = build_scheduler(home, stop_event, consciousness_loop, beacon)
|
|
15
|
+
thread = scheduler.start() # returns the daemon thread
|
|
16
|
+
print(scheduler.status()) # list[dict] of task state
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import logging
|
|
22
|
+
import threading
|
|
23
|
+
from dataclasses import dataclass, field
|
|
24
|
+
from datetime import datetime, timedelta, timezone
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from typing import Callable, Optional
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger("skcapstone.scheduled_tasks")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# ---------------------------------------------------------------------------
|
|
32
|
+
# Core data structures
|
|
33
|
+
# ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class ScheduledTask:
|
|
38
|
+
"""A recurring task entry managed by TaskScheduler.
|
|
39
|
+
|
|
40
|
+
Attributes:
|
|
41
|
+
name: Unique task name.
|
|
42
|
+
interval_seconds: How often (in seconds) the task should run.
|
|
43
|
+
callback: Zero-argument callable invoked on each run.
|
|
44
|
+
last_run: UTC timestamp of the most recent execution (or None if never run).
|
|
45
|
+
last_error: String representation of the last exception, if any.
|
|
46
|
+
run_count: Total number of successful (non-raising) executions.
|
|
47
|
+
error_count: Total number of executions that raised an exception.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
name: str
|
|
51
|
+
interval_seconds: float
|
|
52
|
+
callback: Callable[[], None]
|
|
53
|
+
last_run: Optional[datetime] = None
|
|
54
|
+
last_error: Optional[str] = None
|
|
55
|
+
run_count: int = 0
|
|
56
|
+
error_count: int = 0
|
|
57
|
+
|
|
58
|
+
def is_due(self, now: Optional[datetime] = None) -> bool:
|
|
59
|
+
"""Return True if the task interval has elapsed since last_run.
|
|
60
|
+
|
|
61
|
+
A task with no prior run is always considered due.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
now: Reference time for the check (defaults to UTC now).
|
|
65
|
+
"""
|
|
66
|
+
if self.last_run is None:
|
|
67
|
+
return True
|
|
68
|
+
reference = now or datetime.now(timezone.utc)
|
|
69
|
+
elapsed = (reference - self.last_run).total_seconds()
|
|
70
|
+
return elapsed >= self.interval_seconds
|
|
71
|
+
|
|
72
|
+
def run(self) -> None:
|
|
73
|
+
"""Execute the callback, recording outcome regardless of success.
|
|
74
|
+
|
|
75
|
+
On success: increments run_count, clears last_error.
|
|
76
|
+
On failure: increments error_count, stores exception string in last_error.
|
|
77
|
+
In both cases last_run is updated so the interval resets.
|
|
78
|
+
"""
|
|
79
|
+
try:
|
|
80
|
+
self.callback()
|
|
81
|
+
self.run_count += 1
|
|
82
|
+
self.last_error = None
|
|
83
|
+
logger.debug("Scheduled task '%s' completed (run #%d)", self.name, self.run_count)
|
|
84
|
+
except Exception as exc:
|
|
85
|
+
self.error_count += 1
|
|
86
|
+
self.last_error = str(exc)
|
|
87
|
+
logger.error("Scheduled task '%s' failed: %s", self.name, exc)
|
|
88
|
+
finally:
|
|
89
|
+
self.last_run = datetime.now(timezone.utc)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# ---------------------------------------------------------------------------
|
|
93
|
+
# Scheduler
|
|
94
|
+
# ---------------------------------------------------------------------------
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class TaskScheduler:
|
|
98
|
+
"""Cron-like scheduler that fires registered tasks on configurable intervals.
|
|
99
|
+
|
|
100
|
+
Runs one daemon thread (``daemon-scheduler``) that wakes up every
|
|
101
|
+
``TICK_INTERVAL`` seconds, checks which tasks are due, and calls their
|
|
102
|
+
callbacks inline (serially, in registration order).
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
home: Agent home directory.
|
|
106
|
+
stop_event: Daemon stop event; scheduler thread exits when set.
|
|
107
|
+
tick_interval: How often (seconds) the scheduler loop wakes to check tasks.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
TICK_INTERVAL: float = 5.0
|
|
111
|
+
|
|
112
|
+
def __init__(
|
|
113
|
+
self,
|
|
114
|
+
home: Path,
|
|
115
|
+
stop_event: threading.Event,
|
|
116
|
+
tick_interval: float = TICK_INTERVAL,
|
|
117
|
+
) -> None:
|
|
118
|
+
self._home = home
|
|
119
|
+
self._stop_event = stop_event
|
|
120
|
+
self._tick_interval = tick_interval
|
|
121
|
+
self._tasks: list[ScheduledTask] = []
|
|
122
|
+
self._lock = threading.Lock()
|
|
123
|
+
self._thread: Optional[threading.Thread] = None
|
|
124
|
+
|
|
125
|
+
# ------------------------------------------------------------------
|
|
126
|
+
# Public API
|
|
127
|
+
# ------------------------------------------------------------------
|
|
128
|
+
|
|
129
|
+
def register(
|
|
130
|
+
self,
|
|
131
|
+
name: str,
|
|
132
|
+
interval_seconds: float,
|
|
133
|
+
callback: Callable[[], None],
|
|
134
|
+
) -> ScheduledTask:
|
|
135
|
+
"""Register a recurring task.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
name: Unique task name (used in logs and status output).
|
|
139
|
+
interval_seconds: Minimum seconds between executions.
|
|
140
|
+
callback: Zero-argument callable to invoke.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
The created ScheduledTask (caller may inspect it at runtime).
|
|
144
|
+
"""
|
|
145
|
+
task = ScheduledTask(name=name, interval_seconds=interval_seconds, callback=callback)
|
|
146
|
+
with self._lock:
|
|
147
|
+
self._tasks.append(task)
|
|
148
|
+
logger.debug("Registered scheduled task '%s' every %.0fs", name, interval_seconds)
|
|
149
|
+
return task
|
|
150
|
+
|
|
151
|
+
def start(self) -> threading.Thread:
|
|
152
|
+
"""Start the scheduler background thread.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
The started daemon thread (for lifecycle management by caller).
|
|
156
|
+
"""
|
|
157
|
+
self._thread = threading.Thread(
|
|
158
|
+
target=self._run,
|
|
159
|
+
name="daemon-scheduler",
|
|
160
|
+
daemon=True,
|
|
161
|
+
)
|
|
162
|
+
self._thread.start()
|
|
163
|
+
logger.info(
|
|
164
|
+
"Task scheduler started — %d task(s), tick=%.0fs",
|
|
165
|
+
len(self._tasks),
|
|
166
|
+
self._tick_interval,
|
|
167
|
+
)
|
|
168
|
+
return self._thread
|
|
169
|
+
|
|
170
|
+
def status(self) -> list[dict]:
|
|
171
|
+
"""Return serializable status for all registered tasks.
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
List of dicts with: name, interval_seconds, last_run (ISO or None),
|
|
175
|
+
last_error, run_count, error_count.
|
|
176
|
+
"""
|
|
177
|
+
with self._lock:
|
|
178
|
+
return [
|
|
179
|
+
{
|
|
180
|
+
"name": t.name,
|
|
181
|
+
"interval_seconds": t.interval_seconds,
|
|
182
|
+
"last_run": t.last_run.isoformat() if t.last_run else None,
|
|
183
|
+
"last_error": t.last_error,
|
|
184
|
+
"run_count": t.run_count,
|
|
185
|
+
"error_count": t.error_count,
|
|
186
|
+
}
|
|
187
|
+
for t in self._tasks
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
# ------------------------------------------------------------------
|
|
191
|
+
# Internal
|
|
192
|
+
# ------------------------------------------------------------------
|
|
193
|
+
|
|
194
|
+
def _run(self) -> None:
|
|
195
|
+
"""Main scheduler loop — ticks every TICK_INTERVAL seconds."""
|
|
196
|
+
while not self._stop_event.is_set():
|
|
197
|
+
now = datetime.now(timezone.utc)
|
|
198
|
+
with self._lock:
|
|
199
|
+
tasks_snapshot = list(self._tasks)
|
|
200
|
+
|
|
201
|
+
for task in tasks_snapshot:
|
|
202
|
+
if task.is_due(now):
|
|
203
|
+
task.run()
|
|
204
|
+
|
|
205
|
+
self._stop_event.wait(timeout=self._tick_interval)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
# ---------------------------------------------------------------------------
|
|
209
|
+
# Built-in task factories
|
|
210
|
+
# ---------------------------------------------------------------------------
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def make_memory_promotion_task(home: Path) -> Callable[[], None]:
|
|
214
|
+
"""Return a callback that runs an hourly memory promotion sweep.
|
|
215
|
+
|
|
216
|
+
Instantiates PromotionEngine lazily (so import errors are deferred until
|
|
217
|
+
first run, matching the graceful-import pattern used elsewhere in the daemon).
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
home: Agent home directory containing the ``memory/`` subtree.
|
|
221
|
+
"""
|
|
222
|
+
|
|
223
|
+
def _run() -> None:
|
|
224
|
+
from .memory_promoter import PromotionEngine
|
|
225
|
+
|
|
226
|
+
engine = PromotionEngine(home)
|
|
227
|
+
result = engine.sweep()
|
|
228
|
+
if result.promoted:
|
|
229
|
+
logger.info(
|
|
230
|
+
"Memory promotion sweep: %d promoted of %d scanned",
|
|
231
|
+
len(result.promoted),
|
|
232
|
+
result.scanned,
|
|
233
|
+
)
|
|
234
|
+
else:
|
|
235
|
+
logger.debug(
|
|
236
|
+
"Memory promotion sweep: %d scanned, 0 promoted",
|
|
237
|
+
result.scanned,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
return _run
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def make_backend_reprobe_task(consciousness_loop: object) -> Callable[[], None]:
|
|
244
|
+
"""Return a callback that re-probes LLM backend availability every 5 min.
|
|
245
|
+
|
|
246
|
+
Reaches into ``consciousness_loop._bridge._probe_available_backends()``.
|
|
247
|
+
Silently no-ops if any of those attributes are missing, keeping the
|
|
248
|
+
scheduler stable when the consciousness loop is unavailable.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
consciousness_loop: ConsciousnessLoop instance (or None).
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
def _run() -> None:
|
|
255
|
+
if consciousness_loop is None:
|
|
256
|
+
return
|
|
257
|
+
bridge = getattr(consciousness_loop, "_bridge", None)
|
|
258
|
+
if bridge is None:
|
|
259
|
+
return
|
|
260
|
+
probe_fn = getattr(bridge, "_probe_available_backends", None)
|
|
261
|
+
if callable(probe_fn):
|
|
262
|
+
probe_fn()
|
|
263
|
+
available = getattr(bridge, "_available", {})
|
|
264
|
+
enabled = [k for k, v in available.items() if v]
|
|
265
|
+
logger.debug("Backend re-probe: available=%s", enabled)
|
|
266
|
+
|
|
267
|
+
return _run
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def make_heartbeat_task(
|
|
271
|
+
beacon: object,
|
|
272
|
+
consciousness_active_fn: Callable[[], bool],
|
|
273
|
+
) -> Callable[[], None]:
|
|
274
|
+
"""Return a callback that emits a heartbeat pulse every 30 seconds.
|
|
275
|
+
|
|
276
|
+
Args:
|
|
277
|
+
beacon: HeartbeatBeacon instance (or None).
|
|
278
|
+
consciousness_active_fn: Zero-arg callable returning bool — whether
|
|
279
|
+
the consciousness loop is currently active.
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
def _run() -> None:
|
|
283
|
+
if beacon is None:
|
|
284
|
+
return
|
|
285
|
+
active = consciousness_active_fn()
|
|
286
|
+
beacon.pulse(consciousness_active=active)
|
|
287
|
+
logger.debug("Heartbeat pulse sent (consciousness_active=%s)", active)
|
|
288
|
+
|
|
289
|
+
return _run
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def make_profile_freshness_task(home: Path, max_age_days: int = 7) -> Callable[[], None]:
|
|
293
|
+
"""Return a callback that checks agent profile freshness daily.
|
|
294
|
+
|
|
295
|
+
Inspects:
|
|
296
|
+
- ``identity/identity.json``
|
|
297
|
+
- ``data/model_profiles/*.json`` (if present)
|
|
298
|
+
|
|
299
|
+
Logs a WARNING for any file older than *max_age_days* days, otherwise
|
|
300
|
+
logs at DEBUG level so the daemon stays quiet on healthy systems.
|
|
301
|
+
|
|
302
|
+
Args:
|
|
303
|
+
home: Agent home directory.
|
|
304
|
+
max_age_days: Files older than this trigger a warning (default 7).
|
|
305
|
+
"""
|
|
306
|
+
|
|
307
|
+
def _run() -> None:
|
|
308
|
+
now = datetime.now(timezone.utc)
|
|
309
|
+
warnings: list[str] = []
|
|
310
|
+
|
|
311
|
+
# Identity manifest
|
|
312
|
+
identity_file = home / "identity" / "identity.json"
|
|
313
|
+
if identity_file.exists():
|
|
314
|
+
mtime = datetime.fromtimestamp(identity_file.stat().st_mtime, tz=timezone.utc)
|
|
315
|
+
age_days = (now - mtime).days
|
|
316
|
+
if age_days > max_age_days:
|
|
317
|
+
warnings.append(
|
|
318
|
+
f"identity.json is {age_days}d old — consider re-running 'skcapstone init'"
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
# Model profile files
|
|
322
|
+
profiles_dir = home / "data" / "model_profiles"
|
|
323
|
+
if profiles_dir.exists():
|
|
324
|
+
for profile in sorted(profiles_dir.glob("*.json")):
|
|
325
|
+
mtime = datetime.fromtimestamp(profile.stat().st_mtime, tz=timezone.utc)
|
|
326
|
+
age_days = (now - mtime).days
|
|
327
|
+
if age_days > max_age_days:
|
|
328
|
+
warnings.append(
|
|
329
|
+
f"model profile '{profile.stem}' is {age_days}d old"
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
if warnings:
|
|
333
|
+
for msg in warnings:
|
|
334
|
+
logger.warning("Profile freshness: %s", msg)
|
|
335
|
+
else:
|
|
336
|
+
logger.debug("Profile freshness check passed — all profiles current")
|
|
337
|
+
|
|
338
|
+
return _run
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
# ---------------------------------------------------------------------------
|
|
342
|
+
# Convenience builder
|
|
343
|
+
# ---------------------------------------------------------------------------
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def build_scheduler(
|
|
347
|
+
home: Path,
|
|
348
|
+
stop_event: threading.Event,
|
|
349
|
+
consciousness_loop: object = None,
|
|
350
|
+
beacon: object = None,
|
|
351
|
+
sync_watcher: object = None,
|
|
352
|
+
) -> TaskScheduler:
|
|
353
|
+
"""Build and register all standard scheduled tasks.
|
|
354
|
+
|
|
355
|
+
Tasks registered (in priority order — shortest interval first):
|
|
356
|
+
|
|
357
|
+
+--------------------------+------------+
|
|
358
|
+
| Task | Interval |
|
|
359
|
+
+==========================+============+
|
|
360
|
+
| heartbeat_pulse | 30 s |
|
|
361
|
+
+--------------------------+------------+
|
|
362
|
+
| sync_inbox_scan | 30 s |
|
|
363
|
+
+--------------------------+------------+
|
|
364
|
+
| backend_reprobe | 5 min |
|
|
365
|
+
+--------------------------+------------+
|
|
366
|
+
| service_health_check | 5 min |
|
|
367
|
+
+--------------------------+------------+
|
|
368
|
+
| memory_promotion_sweep | 1 hour |
|
|
369
|
+
+--------------------------+------------+
|
|
370
|
+
| profile_freshness_check | 24 hours |
|
|
371
|
+
+--------------------------+------------+
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
home: Agent home directory.
|
|
375
|
+
stop_event: Daemon stop event — scheduler thread exits when set.
|
|
376
|
+
consciousness_loop: Optional ConsciousnessLoop for backend re-probe.
|
|
377
|
+
beacon: Optional HeartbeatBeacon for heartbeat pulse.
|
|
378
|
+
sync_watcher: Optional SyncWatcher for inbox polling fallback.
|
|
379
|
+
|
|
380
|
+
Returns:
|
|
381
|
+
Configured TaskScheduler (call ``.start()`` to begin).
|
|
382
|
+
"""
|
|
383
|
+
scheduler = TaskScheduler(home, stop_event)
|
|
384
|
+
|
|
385
|
+
def _consciousness_active() -> bool:
|
|
386
|
+
if consciousness_loop is None:
|
|
387
|
+
return False
|
|
388
|
+
cfg = getattr(consciousness_loop, "_config", None)
|
|
389
|
+
return bool(cfg and getattr(cfg, "enabled", False))
|
|
390
|
+
|
|
391
|
+
scheduler.register(
|
|
392
|
+
name="heartbeat_pulse",
|
|
393
|
+
interval_seconds=30,
|
|
394
|
+
callback=make_heartbeat_task(beacon, _consciousness_active),
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
# Sync inbox polling (fallback for when inotify misses events)
|
|
398
|
+
try:
|
|
399
|
+
from .sync_watcher import make_sync_inbox_scan_task
|
|
400
|
+
|
|
401
|
+
scheduler.register(
|
|
402
|
+
name="sync_inbox_scan",
|
|
403
|
+
interval_seconds=30,
|
|
404
|
+
callback=make_sync_inbox_scan_task(sync_watcher),
|
|
405
|
+
)
|
|
406
|
+
except ImportError:
|
|
407
|
+
logger.debug("sync_watcher not available — sync_inbox_scan task skipped")
|
|
408
|
+
|
|
409
|
+
scheduler.register(
|
|
410
|
+
name="backend_reprobe",
|
|
411
|
+
interval_seconds=300, # 5 minutes
|
|
412
|
+
callback=make_backend_reprobe_task(consciousness_loop),
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
scheduler.register(
|
|
416
|
+
name="memory_promotion_sweep",
|
|
417
|
+
interval_seconds=3600, # 1 hour
|
|
418
|
+
callback=make_memory_promotion_task(home),
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
scheduler.register(
|
|
422
|
+
name="profile_freshness_check",
|
|
423
|
+
interval_seconds=86400, # 24 hours
|
|
424
|
+
callback=make_profile_freshness_task(home),
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
# Service health check — pings Qdrant, FalkorDB, Syncthing, daemons
|
|
428
|
+
try:
|
|
429
|
+
from .service_health import make_service_health_task
|
|
430
|
+
|
|
431
|
+
scheduler.register(
|
|
432
|
+
name="service_health_check",
|
|
433
|
+
interval_seconds=300, # 5 minutes
|
|
434
|
+
callback=make_service_health_task(),
|
|
435
|
+
)
|
|
436
|
+
except ImportError:
|
|
437
|
+
logger.debug("service_health not available — service_health_check task skipped")
|
|
438
|
+
|
|
439
|
+
return scheduler
|