@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,398 @@
|
|
|
1
|
+
"""Tests for ComponentHealth and ComponentManager in skcapstone.daemon."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import threading
|
|
6
|
+
import time
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
from skcapstone.daemon import ComponentHealth, ComponentManager
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
# ComponentHealth unit tests
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestComponentHealth:
|
|
20
|
+
"""Tests for the ComponentHealth state machine."""
|
|
21
|
+
|
|
22
|
+
def test_initial_state(self):
|
|
23
|
+
"""New component starts in pending state with no timestamps."""
|
|
24
|
+
comp = ComponentHealth("poll")
|
|
25
|
+
assert comp.status == "pending"
|
|
26
|
+
assert comp.started_at is None
|
|
27
|
+
assert comp.last_heartbeat is None
|
|
28
|
+
assert comp.restart_count == 0
|
|
29
|
+
assert comp.last_error is None
|
|
30
|
+
|
|
31
|
+
def test_mark_started_sets_alive(self):
|
|
32
|
+
"""mark_started() transitions to alive and records timestamps."""
|
|
33
|
+
comp = ComponentHealth("poll")
|
|
34
|
+
comp.mark_started()
|
|
35
|
+
assert comp.status == "alive"
|
|
36
|
+
assert comp.started_at is not None
|
|
37
|
+
assert comp.last_heartbeat is not None
|
|
38
|
+
|
|
39
|
+
def test_pulse_updates_heartbeat(self):
|
|
40
|
+
"""pulse() updates last_heartbeat without changing started_at."""
|
|
41
|
+
comp = ComponentHealth("poll")
|
|
42
|
+
comp.mark_started()
|
|
43
|
+
before = comp.last_heartbeat
|
|
44
|
+
time.sleep(0.01)
|
|
45
|
+
comp.pulse()
|
|
46
|
+
assert comp.last_heartbeat > before
|
|
47
|
+
assert comp.started_at == comp.started_at # unchanged
|
|
48
|
+
|
|
49
|
+
def test_pulse_from_non_alive_transitions_to_alive(self):
|
|
50
|
+
"""pulse() on a dead component recovers it to alive."""
|
|
51
|
+
comp = ComponentHealth("poll")
|
|
52
|
+
comp.mark_dead("oops")
|
|
53
|
+
assert comp.status == "dead"
|
|
54
|
+
comp.pulse()
|
|
55
|
+
assert comp.status == "alive"
|
|
56
|
+
|
|
57
|
+
def test_mark_dead_records_error(self):
|
|
58
|
+
"""mark_dead() stores error message and sets status to dead."""
|
|
59
|
+
comp = ComponentHealth("poll")
|
|
60
|
+
comp.mark_started()
|
|
61
|
+
comp.mark_dead("connection refused")
|
|
62
|
+
assert comp.status == "dead"
|
|
63
|
+
assert comp.last_error == "connection refused"
|
|
64
|
+
|
|
65
|
+
def test_mark_dead_no_error(self):
|
|
66
|
+
"""mark_dead() with no error leaves last_error as None."""
|
|
67
|
+
comp = ComponentHealth("poll")
|
|
68
|
+
comp.mark_dead()
|
|
69
|
+
assert comp.status == "dead"
|
|
70
|
+
assert comp.last_error is None
|
|
71
|
+
|
|
72
|
+
def test_mark_restarting_increments_counter(self):
|
|
73
|
+
"""mark_restarting() increments restart_count each time."""
|
|
74
|
+
comp = ComponentHealth("poll")
|
|
75
|
+
comp.mark_restarting()
|
|
76
|
+
assert comp.status == "restarting"
|
|
77
|
+
assert comp.restart_count == 1
|
|
78
|
+
comp.mark_restarting()
|
|
79
|
+
assert comp.restart_count == 2
|
|
80
|
+
|
|
81
|
+
def test_mark_disabled(self):
|
|
82
|
+
"""mark_disabled() sets status to disabled."""
|
|
83
|
+
comp = ComponentHealth("poll")
|
|
84
|
+
comp.mark_disabled()
|
|
85
|
+
assert comp.status == "disabled"
|
|
86
|
+
|
|
87
|
+
def test_mark_alive_sets_timestamps(self):
|
|
88
|
+
"""mark_alive() sets started_at and last_heartbeat."""
|
|
89
|
+
comp = ComponentHealth("poll")
|
|
90
|
+
comp.mark_alive()
|
|
91
|
+
assert comp.status == "alive"
|
|
92
|
+
assert comp.started_at is not None
|
|
93
|
+
assert comp.last_heartbeat is not None
|
|
94
|
+
|
|
95
|
+
def test_snapshot_fields(self):
|
|
96
|
+
"""snapshot() returns all required fields."""
|
|
97
|
+
comp = ComponentHealth("health", auto_restart=True, heartbeat_timeout=60)
|
|
98
|
+
comp.mark_started()
|
|
99
|
+
snap = comp.snapshot()
|
|
100
|
+
assert snap["name"] == "health"
|
|
101
|
+
assert snap["status"] == "alive"
|
|
102
|
+
assert snap["auto_restart"] is True
|
|
103
|
+
assert snap["restart_count"] == 0
|
|
104
|
+
assert snap["last_error"] is None
|
|
105
|
+
assert snap["started_at"] is not None
|
|
106
|
+
assert snap["last_heartbeat"] is not None
|
|
107
|
+
assert snap["heartbeat_age_seconds"] is not None
|
|
108
|
+
assert snap["heartbeat_age_seconds"] >= 0
|
|
109
|
+
|
|
110
|
+
def test_snapshot_heartbeat_age_none_when_never_pulsed(self):
|
|
111
|
+
"""snapshot() returns heartbeat_age_seconds=None before any pulse."""
|
|
112
|
+
comp = ComponentHealth("poll")
|
|
113
|
+
snap = comp.snapshot()
|
|
114
|
+
assert snap["heartbeat_age_seconds"] is None
|
|
115
|
+
|
|
116
|
+
def test_thread_safe_concurrent_pulses(self):
|
|
117
|
+
"""Multiple threads pulsing simultaneously should not corrupt state."""
|
|
118
|
+
comp = ComponentHealth("poll")
|
|
119
|
+
comp.mark_started()
|
|
120
|
+
errors = []
|
|
121
|
+
|
|
122
|
+
def do_pulses():
|
|
123
|
+
try:
|
|
124
|
+
for _ in range(100):
|
|
125
|
+
comp.pulse()
|
|
126
|
+
except Exception as exc:
|
|
127
|
+
errors.append(exc)
|
|
128
|
+
|
|
129
|
+
threads = [threading.Thread(target=do_pulses) for _ in range(5)]
|
|
130
|
+
for t in threads:
|
|
131
|
+
t.start()
|
|
132
|
+
for t in threads:
|
|
133
|
+
t.join()
|
|
134
|
+
|
|
135
|
+
assert errors == []
|
|
136
|
+
assert comp.status == "alive"
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# ---------------------------------------------------------------------------
|
|
140
|
+
# ComponentManager unit tests
|
|
141
|
+
# ---------------------------------------------------------------------------
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class TestComponentManager:
|
|
145
|
+
"""Tests for ComponentManager registration, heartbeats, and snapshots."""
|
|
146
|
+
|
|
147
|
+
def _stop(self) -> threading.Event:
|
|
148
|
+
ev = threading.Event()
|
|
149
|
+
ev.set() # pre-set so loops exit immediately
|
|
150
|
+
return ev
|
|
151
|
+
|
|
152
|
+
def test_register_creates_component(self):
|
|
153
|
+
"""register() creates a ComponentHealth entry."""
|
|
154
|
+
mgr = ComponentManager(self._stop())
|
|
155
|
+
mgr.register("poll", lambda: None)
|
|
156
|
+
snap = mgr.snapshot()
|
|
157
|
+
assert "poll" in snap
|
|
158
|
+
|
|
159
|
+
def test_register_disabled(self):
|
|
160
|
+
"""register(..., disabled=True) creates a disabled component."""
|
|
161
|
+
mgr = ComponentManager(self._stop())
|
|
162
|
+
mgr.register("healing", lambda: None, disabled=True)
|
|
163
|
+
snap = mgr.snapshot()
|
|
164
|
+
assert snap["healing"]["status"] == "disabled"
|
|
165
|
+
|
|
166
|
+
def test_register_passive_alive(self):
|
|
167
|
+
"""register_passive() creates a passive alive component."""
|
|
168
|
+
mgr = ComponentManager(self._stop())
|
|
169
|
+
mgr.register_passive("consciousness", status="alive")
|
|
170
|
+
snap = mgr.snapshot()
|
|
171
|
+
assert snap["consciousness"]["status"] == "alive"
|
|
172
|
+
assert snap["consciousness"]["auto_restart"] is False
|
|
173
|
+
|
|
174
|
+
def test_register_passive_disabled(self):
|
|
175
|
+
"""register_passive(..., status='disabled') creates a disabled entry."""
|
|
176
|
+
mgr = ComponentManager(self._stop())
|
|
177
|
+
mgr.register_passive("scheduler", status="disabled")
|
|
178
|
+
snap = mgr.snapshot()
|
|
179
|
+
assert snap["scheduler"]["status"] == "disabled"
|
|
180
|
+
|
|
181
|
+
def test_heartbeat_updates_timestamp(self):
|
|
182
|
+
"""heartbeat() updates last_heartbeat for a registered component."""
|
|
183
|
+
mgr = ComponentManager(self._stop())
|
|
184
|
+
mgr.register("poll", lambda: None)
|
|
185
|
+
# Manually mark started so heartbeat_age is tracked
|
|
186
|
+
with mgr._lock:
|
|
187
|
+
comp = mgr._health["poll"]
|
|
188
|
+
comp.mark_started()
|
|
189
|
+
before = comp.last_heartbeat
|
|
190
|
+
|
|
191
|
+
time.sleep(0.02)
|
|
192
|
+
mgr.heartbeat("poll")
|
|
193
|
+
|
|
194
|
+
assert comp.last_heartbeat > before
|
|
195
|
+
|
|
196
|
+
def test_heartbeat_unknown_name_no_error(self):
|
|
197
|
+
"""heartbeat() on an unknown name should not raise."""
|
|
198
|
+
mgr = ComponentManager(self._stop())
|
|
199
|
+
mgr.heartbeat("nonexistent") # must not raise
|
|
200
|
+
|
|
201
|
+
def test_mark_dead_sets_status(self):
|
|
202
|
+
"""mark_dead() transitions component to dead status."""
|
|
203
|
+
mgr = ComponentManager(self._stop())
|
|
204
|
+
mgr.register("poll", lambda: None)
|
|
205
|
+
with mgr._lock:
|
|
206
|
+
comp = mgr._health["poll"]
|
|
207
|
+
comp.mark_started()
|
|
208
|
+
mgr.mark_dead("poll", "test error")
|
|
209
|
+
assert comp.status == "dead"
|
|
210
|
+
assert comp.last_error == "test error"
|
|
211
|
+
|
|
212
|
+
def test_mark_alive_on_passive(self):
|
|
213
|
+
"""mark_alive() on a passive component sets it alive."""
|
|
214
|
+
mgr = ComponentManager(self._stop())
|
|
215
|
+
mgr.register_passive("consciousness", status="disabled")
|
|
216
|
+
mgr.mark_alive("consciousness")
|
|
217
|
+
snap = mgr.snapshot()
|
|
218
|
+
assert snap["consciousness"]["status"] == "alive"
|
|
219
|
+
|
|
220
|
+
def test_mark_disabled_on_passive(self):
|
|
221
|
+
"""mark_disabled() on a passive component sets it disabled."""
|
|
222
|
+
mgr = ComponentManager(self._stop())
|
|
223
|
+
mgr.register_passive("scheduler", status="alive")
|
|
224
|
+
mgr.mark_disabled("scheduler")
|
|
225
|
+
snap = mgr.snapshot()
|
|
226
|
+
assert snap["scheduler"]["status"] == "disabled"
|
|
227
|
+
|
|
228
|
+
def test_snapshot_returns_all_components(self):
|
|
229
|
+
"""snapshot() includes every registered component."""
|
|
230
|
+
mgr = ComponentManager(self._stop())
|
|
231
|
+
mgr.register("poll", lambda: None)
|
|
232
|
+
mgr.register("health", lambda: None)
|
|
233
|
+
mgr.register_passive("consciousness", status="alive")
|
|
234
|
+
snap = mgr.snapshot()
|
|
235
|
+
assert set(snap.keys()) == {"poll", "health", "consciousness"}
|
|
236
|
+
|
|
237
|
+
def test_snapshot_is_serializable(self):
|
|
238
|
+
"""snapshot() values must be JSON-serializable primitives."""
|
|
239
|
+
import json
|
|
240
|
+
|
|
241
|
+
mgr = ComponentManager(self._stop())
|
|
242
|
+
mgr.register("poll", lambda: None)
|
|
243
|
+
mgr.register_passive("consciousness", status="alive")
|
|
244
|
+
snap = mgr.snapshot()
|
|
245
|
+
# Should not raise
|
|
246
|
+
encoded = json.dumps(snap)
|
|
247
|
+
decoded = json.loads(encoded)
|
|
248
|
+
assert "poll" in decoded
|
|
249
|
+
assert "consciousness" in decoded
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
# ---------------------------------------------------------------------------
|
|
253
|
+
# Auto-restart tests via _check_components()
|
|
254
|
+
# ---------------------------------------------------------------------------
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class TestComponentManagerAutoRestart:
|
|
258
|
+
"""Tests for watchdog auto-restart logic via _check_components()."""
|
|
259
|
+
|
|
260
|
+
def _make_mgr(self) -> ComponentManager:
|
|
261
|
+
stop = threading.Event()
|
|
262
|
+
return ComponentManager(stop)
|
|
263
|
+
|
|
264
|
+
def test_dead_component_is_restarted(self):
|
|
265
|
+
"""_check_components() restarts a dead auto-restart component."""
|
|
266
|
+
call_log: list[str] = []
|
|
267
|
+
|
|
268
|
+
def loop():
|
|
269
|
+
call_log.append("called")
|
|
270
|
+
# Exit immediately (simulates a restarted loop that exits)
|
|
271
|
+
|
|
272
|
+
mgr = self._make_mgr()
|
|
273
|
+
mgr.register("poll", loop)
|
|
274
|
+
|
|
275
|
+
# Mark it as already-started, then immediately dead
|
|
276
|
+
with mgr._lock:
|
|
277
|
+
comp = mgr._health["poll"]
|
|
278
|
+
comp.mark_started()
|
|
279
|
+
comp.mark_dead("test crash")
|
|
280
|
+
|
|
281
|
+
# Run the watchdog check once
|
|
282
|
+
mgr._check_components()
|
|
283
|
+
|
|
284
|
+
# A new thread was launched — give it a moment to run
|
|
285
|
+
time.sleep(0.1)
|
|
286
|
+
assert len(call_log) >= 1
|
|
287
|
+
assert comp.restart_count == 1
|
|
288
|
+
|
|
289
|
+
def test_max_restarts_not_exceeded(self):
|
|
290
|
+
"""Components exceeding MAX_RESTARTS are not restarted again."""
|
|
291
|
+
call_log: list[str] = []
|
|
292
|
+
|
|
293
|
+
def loop():
|
|
294
|
+
call_log.append("called")
|
|
295
|
+
|
|
296
|
+
mgr = self._make_mgr()
|
|
297
|
+
mgr.register("poll", loop)
|
|
298
|
+
|
|
299
|
+
with mgr._lock:
|
|
300
|
+
comp = mgr._health["poll"]
|
|
301
|
+
comp.mark_started()
|
|
302
|
+
|
|
303
|
+
# Exhaust restart budget
|
|
304
|
+
comp.restart_count = ComponentManager.MAX_RESTARTS
|
|
305
|
+
comp.mark_dead("too many times")
|
|
306
|
+
|
|
307
|
+
before = len(call_log)
|
|
308
|
+
mgr._check_components()
|
|
309
|
+
time.sleep(0.05)
|
|
310
|
+
|
|
311
|
+
assert len(call_log) == before # no new call
|
|
312
|
+
|
|
313
|
+
def test_disabled_component_not_restarted(self):
|
|
314
|
+
"""Disabled components are never restarted by the watchdog."""
|
|
315
|
+
call_log: list[str] = []
|
|
316
|
+
|
|
317
|
+
def loop():
|
|
318
|
+
call_log.append("called")
|
|
319
|
+
|
|
320
|
+
mgr = self._make_mgr()
|
|
321
|
+
mgr.register("healing", loop, disabled=True)
|
|
322
|
+
|
|
323
|
+
mgr._check_components()
|
|
324
|
+
time.sleep(0.05)
|
|
325
|
+
assert call_log == []
|
|
326
|
+
|
|
327
|
+
def test_passive_component_not_restarted(self):
|
|
328
|
+
"""Passive (non-auto-restart) components are never restarted."""
|
|
329
|
+
call_log: list[str] = []
|
|
330
|
+
|
|
331
|
+
def loop():
|
|
332
|
+
call_log.append("called")
|
|
333
|
+
|
|
334
|
+
mgr = self._make_mgr()
|
|
335
|
+
# Register passive, then forcibly mark dead to test watchdog ignores it
|
|
336
|
+
mgr.register_passive("consciousness", status="alive")
|
|
337
|
+
with mgr._lock:
|
|
338
|
+
comp = mgr._health["consciousness"]
|
|
339
|
+
comp.mark_dead("test")
|
|
340
|
+
|
|
341
|
+
mgr._check_components()
|
|
342
|
+
time.sleep(0.05)
|
|
343
|
+
assert call_log == []
|
|
344
|
+
|
|
345
|
+
def test_heartbeat_timeout_triggers_restart(self):
|
|
346
|
+
"""Component with stale heartbeat is detected and restarted."""
|
|
347
|
+
from datetime import timedelta
|
|
348
|
+
|
|
349
|
+
call_log: list[str] = []
|
|
350
|
+
|
|
351
|
+
def loop():
|
|
352
|
+
call_log.append("called")
|
|
353
|
+
|
|
354
|
+
mgr = self._make_mgr()
|
|
355
|
+
mgr.register("poll", loop, heartbeat_timeout=1)
|
|
356
|
+
|
|
357
|
+
with mgr._lock:
|
|
358
|
+
comp = mgr._health["poll"]
|
|
359
|
+
comp.mark_started()
|
|
360
|
+
|
|
361
|
+
# Backdate last_heartbeat past the timeout
|
|
362
|
+
comp.last_heartbeat = datetime.now(timezone.utc) - timedelta(seconds=10)
|
|
363
|
+
comp.status = "alive"
|
|
364
|
+
|
|
365
|
+
mgr._check_components()
|
|
366
|
+
time.sleep(0.1)
|
|
367
|
+
|
|
368
|
+
assert comp.restart_count >= 1
|
|
369
|
+
|
|
370
|
+
def test_alive_thread_not_restarted(self):
|
|
371
|
+
"""Component whose thread is still alive is not unnecessarily restarted."""
|
|
372
|
+
stop = threading.Event()
|
|
373
|
+
mgr = ComponentManager(stop)
|
|
374
|
+
|
|
375
|
+
started = threading.Event()
|
|
376
|
+
|
|
377
|
+
def loop():
|
|
378
|
+
started.set()
|
|
379
|
+
stop.wait() # block until stop
|
|
380
|
+
|
|
381
|
+
mgr.register("poll", loop)
|
|
382
|
+
threads = mgr.start_all()
|
|
383
|
+
started.wait(timeout=2)
|
|
384
|
+
|
|
385
|
+
# Give heartbeat a moment to fire
|
|
386
|
+
time.sleep(0.05)
|
|
387
|
+
mgr.heartbeat("poll")
|
|
388
|
+
|
|
389
|
+
with mgr._lock:
|
|
390
|
+
comp = mgr._health["poll"]
|
|
391
|
+
original_restarts = comp.restart_count
|
|
392
|
+
|
|
393
|
+
mgr._check_components() # should NOT restart
|
|
394
|
+
assert comp.restart_count == original_restarts
|
|
395
|
+
|
|
396
|
+
stop.set()
|
|
397
|
+
for t in threads:
|
|
398
|
+
t.join(timeout=1)
|