@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
package/tests/test_ws.py
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"""Tests for the WebSocket streaming endpoint added to the daemon."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import base64
|
|
6
|
+
import json
|
|
7
|
+
import socket
|
|
8
|
+
import struct
|
|
9
|
+
import threading
|
|
10
|
+
import time
|
|
11
|
+
from unittest.mock import patch
|
|
12
|
+
|
|
13
|
+
import pytest
|
|
14
|
+
|
|
15
|
+
from skcapstone.daemon import (
|
|
16
|
+
DaemonConfig,
|
|
17
|
+
DaemonService,
|
|
18
|
+
_ws_accept_key,
|
|
19
|
+
_ws_encode_close,
|
|
20
|
+
_ws_encode_frame,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# ── Helpers ───────────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
def _find_free_port() -> int:
|
|
27
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
28
|
+
s.bind(("127.0.0.1", 0))
|
|
29
|
+
return s.getsockname()[1]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class _WsConn:
|
|
33
|
+
"""Minimal WebSocket client connection with a leftover-data buffer.
|
|
34
|
+
|
|
35
|
+
Handles the case where the OS coalesces the 101 response and the first
|
|
36
|
+
WebSocket frame into a single TCP segment (Nagle's algorithm).
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, sock: socket.socket, leftover: bytes = b"") -> None:
|
|
40
|
+
self._sock = sock
|
|
41
|
+
self._buf = leftover
|
|
42
|
+
|
|
43
|
+
def recv_exact(self, n: int) -> bytes:
|
|
44
|
+
while len(self._buf) < n:
|
|
45
|
+
self._sock.settimeout(3)
|
|
46
|
+
chunk = self._sock.recv(4096)
|
|
47
|
+
if not chunk:
|
|
48
|
+
raise ConnectionError("EOF reading from WebSocket")
|
|
49
|
+
self._buf += chunk
|
|
50
|
+
data = self._buf[:n]
|
|
51
|
+
self._buf = self._buf[n:]
|
|
52
|
+
return data
|
|
53
|
+
|
|
54
|
+
def recv_frame(self) -> tuple[int, bytes]:
|
|
55
|
+
"""Read one unmasked server→client WebSocket frame."""
|
|
56
|
+
header = self.recv_exact(2)
|
|
57
|
+
b0, b1 = header[0], header[1]
|
|
58
|
+
opcode = b0 & 0x0F
|
|
59
|
+
length = b1 & 0x7F
|
|
60
|
+
if length == 126:
|
|
61
|
+
length = struct.unpack("!H", self.recv_exact(2))[0]
|
|
62
|
+
elif length == 127:
|
|
63
|
+
length = struct.unpack("!Q", self.recv_exact(8))[0]
|
|
64
|
+
payload = self.recv_exact(length) if length else b""
|
|
65
|
+
return opcode, payload
|
|
66
|
+
|
|
67
|
+
def close(self) -> None:
|
|
68
|
+
self._sock.close()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _ws_connect(port: int) -> _WsConn:
|
|
72
|
+
"""Open a TCP socket, perform the WebSocket handshake, and return a _WsConn.
|
|
73
|
+
|
|
74
|
+
Any bytes received after the HTTP headers (e.g. an initial WS frame that
|
|
75
|
+
arrived in the same TCP segment as the 101 response) are preserved in the
|
|
76
|
+
_WsConn buffer so they are not lost.
|
|
77
|
+
"""
|
|
78
|
+
sock = socket.create_connection(("127.0.0.1", port), timeout=3)
|
|
79
|
+
key_b64 = base64.b64encode(b"skcapstonetest!!").decode()
|
|
80
|
+
request = (
|
|
81
|
+
f"GET /ws HTTP/1.1\r\n"
|
|
82
|
+
f"Host: 127.0.0.1:{port}\r\n"
|
|
83
|
+
f"Upgrade: websocket\r\n"
|
|
84
|
+
f"Connection: Upgrade\r\n"
|
|
85
|
+
f"Sec-WebSocket-Key: {key_b64}\r\n"
|
|
86
|
+
f"Sec-WebSocket-Version: 13\r\n\r\n"
|
|
87
|
+
).encode()
|
|
88
|
+
sock.sendall(request)
|
|
89
|
+
# Read until the end of the HTTP response headers
|
|
90
|
+
response = b""
|
|
91
|
+
while b"\r\n\r\n" not in response:
|
|
92
|
+
chunk = sock.recv(4096)
|
|
93
|
+
if not chunk:
|
|
94
|
+
raise ConnectionError("Server closed before 101")
|
|
95
|
+
response += chunk
|
|
96
|
+
header_end = response.index(b"\r\n\r\n") + 4
|
|
97
|
+
assert b"101" in response[:header_end], f"Expected 101, got: {response[:200]}"
|
|
98
|
+
leftover = response[header_end:]
|
|
99
|
+
return _WsConn(sock, leftover)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _start_server(tmp_path):
|
|
103
|
+
"""Start a DaemonService HTTP/WS server on a free port; return the service."""
|
|
104
|
+
config = DaemonConfig(
|
|
105
|
+
home=tmp_path,
|
|
106
|
+
shared_root=tmp_path,
|
|
107
|
+
port=0,
|
|
108
|
+
poll_interval=60,
|
|
109
|
+
consciousness_enabled=False,
|
|
110
|
+
)
|
|
111
|
+
svc = DaemonService(config)
|
|
112
|
+
svc.state.running = True
|
|
113
|
+
with patch.object(svc, "_load_components"):
|
|
114
|
+
svc.config.port = _find_free_port()
|
|
115
|
+
svc._write_pid()
|
|
116
|
+
svc._start_api_server()
|
|
117
|
+
time.sleep(0.3)
|
|
118
|
+
return svc
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# ── Unit tests for module-level helpers ───────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
class TestWsHelpers:
|
|
124
|
+
"""Tests for the RFC 6455 frame-encoding and handshake helpers."""
|
|
125
|
+
|
|
126
|
+
def test_accept_key_rfc6455_example(self):
|
|
127
|
+
"""The Sec-WebSocket-Accept value matches the RFC 6455 §1.3 example."""
|
|
128
|
+
key = "dGhlIHNhbXBsZSBub25jZQ=="
|
|
129
|
+
assert _ws_accept_key(key) == "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
|
|
130
|
+
|
|
131
|
+
def test_accept_key_deterministic(self):
|
|
132
|
+
key = "abc123=="
|
|
133
|
+
assert _ws_accept_key(key) == _ws_accept_key(key)
|
|
134
|
+
|
|
135
|
+
def test_encode_frame_small_payload(self):
|
|
136
|
+
"""Single-byte length encoding (payload < 126 bytes)."""
|
|
137
|
+
payload = b"hello"
|
|
138
|
+
frame = _ws_encode_frame(payload)
|
|
139
|
+
assert frame[0] == 0x81, "FIN=1 + opcode=1 (text)"
|
|
140
|
+
assert frame[1] == 5, "length field"
|
|
141
|
+
assert frame[2:] == b"hello"
|
|
142
|
+
|
|
143
|
+
def test_encode_frame_medium_payload(self):
|
|
144
|
+
"""Two-byte extended length encoding (126 ≤ payload < 65536)."""
|
|
145
|
+
payload = b"x" * 200
|
|
146
|
+
frame = _ws_encode_frame(payload)
|
|
147
|
+
assert frame[0] == 0x81
|
|
148
|
+
assert frame[1] == 126
|
|
149
|
+
length = struct.unpack("!H", frame[2:4])[0]
|
|
150
|
+
assert length == 200
|
|
151
|
+
assert frame[4:] == payload
|
|
152
|
+
|
|
153
|
+
def test_encode_frame_roundtrip(self):
|
|
154
|
+
"""Encoded frame carries the original payload unchanged."""
|
|
155
|
+
payload = json.dumps({"type": "test", "value": 42}).encode()
|
|
156
|
+
frame = _ws_encode_frame(payload)
|
|
157
|
+
# header is 2 bytes for small payloads
|
|
158
|
+
assert frame[2:] == payload
|
|
159
|
+
|
|
160
|
+
def test_encode_close_opcode(self):
|
|
161
|
+
frame = _ws_encode_close()
|
|
162
|
+
assert frame[0] == 0x88, "FIN=1 + opcode=8 (close)"
|
|
163
|
+
assert frame[1] == 0, "no payload"
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
# ── Unit tests for _ws_broadcast ─────────────────────────────────────────────
|
|
167
|
+
|
|
168
|
+
class TestWsBroadcast:
|
|
169
|
+
"""Tests for DaemonService._ws_broadcast."""
|
|
170
|
+
|
|
171
|
+
def test_broadcast_with_no_clients_is_noop(self, tmp_path):
|
|
172
|
+
"""Calling _ws_broadcast when no clients are connected must not raise."""
|
|
173
|
+
svc = DaemonService(DaemonConfig(home=tmp_path, port=0))
|
|
174
|
+
svc._ws_broadcast({"type": "test"}) # must not raise
|
|
175
|
+
|
|
176
|
+
def test_broadcast_removes_dead_client(self, tmp_path):
|
|
177
|
+
"""A closed socket is removed from _ws_clients after a failed send."""
|
|
178
|
+
svc = DaemonService(DaemonConfig(home=tmp_path, port=0))
|
|
179
|
+
a, b = socket.socketpair()
|
|
180
|
+
b.close() # close the "client" side → sends to 'a' will fail
|
|
181
|
+
with svc._ws_lock:
|
|
182
|
+
svc._ws_clients.add(a)
|
|
183
|
+
svc._ws_broadcast({"type": "test"})
|
|
184
|
+
assert a not in svc._ws_clients
|
|
185
|
+
a.close()
|
|
186
|
+
|
|
187
|
+
def test_broadcast_sends_to_all_clients(self, tmp_path):
|
|
188
|
+
"""Message is delivered to every connected client socket."""
|
|
189
|
+
svc = DaemonService(DaemonConfig(home=tmp_path, port=0))
|
|
190
|
+
pairs = [socket.socketpair() for _ in range(3)]
|
|
191
|
+
server_socks = [p[0] for p in pairs]
|
|
192
|
+
client_socks = [p[1] for p in pairs]
|
|
193
|
+
with svc._ws_lock:
|
|
194
|
+
svc._ws_clients.update(server_socks)
|
|
195
|
+
svc._ws_broadcast({"type": "hello"})
|
|
196
|
+
for cs in client_socks:
|
|
197
|
+
cs.settimeout(1)
|
|
198
|
+
data = cs.recv(64)
|
|
199
|
+
assert len(data) > 0
|
|
200
|
+
for a, b in pairs:
|
|
201
|
+
a.close()
|
|
202
|
+
b.close()
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
# ── Integration tests for the /ws HTTP endpoint ───────────────────────────────
|
|
206
|
+
|
|
207
|
+
class TestWsEndpoint:
|
|
208
|
+
"""End-to-end tests against a live DaemonService API server."""
|
|
209
|
+
|
|
210
|
+
def test_ws_handshake_returns_101_and_init_message(self, tmp_path):
|
|
211
|
+
"""Connecting to /ws completes the handshake and receives a 'connected' frame."""
|
|
212
|
+
svc = _start_server(tmp_path)
|
|
213
|
+
try:
|
|
214
|
+
conn = _ws_connect(svc.config.port)
|
|
215
|
+
try:
|
|
216
|
+
opcode, data = conn.recv_frame()
|
|
217
|
+
assert opcode == 0x1, "Expected text frame"
|
|
218
|
+
msg = json.loads(data)
|
|
219
|
+
assert msg["type"] == "connected"
|
|
220
|
+
assert "state" in msg
|
|
221
|
+
finally:
|
|
222
|
+
conn.close()
|
|
223
|
+
finally:
|
|
224
|
+
svc.stop()
|
|
225
|
+
|
|
226
|
+
def test_ws_broadcast_reaches_connected_client(self, tmp_path):
|
|
227
|
+
"""A message broadcast via _ws_broadcast is received by the WS client."""
|
|
228
|
+
svc = _start_server(tmp_path)
|
|
229
|
+
try:
|
|
230
|
+
conn = _ws_connect(svc.config.port)
|
|
231
|
+
try:
|
|
232
|
+
conn.recv_frame() # drain the 'connected' init frame
|
|
233
|
+
# Broadcast from the server side
|
|
234
|
+
svc._ws_broadcast({"type": "message", "content": "ping from daemon"})
|
|
235
|
+
opcode, data = conn.recv_frame()
|
|
236
|
+
assert opcode == 0x1
|
|
237
|
+
msg = json.loads(data)
|
|
238
|
+
assert msg["type"] == "message"
|
|
239
|
+
assert msg["content"] == "ping from daemon"
|
|
240
|
+
finally:
|
|
241
|
+
conn.close()
|
|
242
|
+
finally:
|
|
243
|
+
svc.stop()
|
|
244
|
+
|
|
245
|
+
def test_ws_client_removed_after_disconnect(self, tmp_path):
|
|
246
|
+
"""Closing the client socket causes it to be removed from _ws_clients."""
|
|
247
|
+
svc = _start_server(tmp_path)
|
|
248
|
+
try:
|
|
249
|
+
conn = _ws_connect(svc.config.port)
|
|
250
|
+
conn.recv_frame() # drain init frame
|
|
251
|
+
# Verify the client is registered
|
|
252
|
+
time.sleep(0.1)
|
|
253
|
+
with svc._ws_lock:
|
|
254
|
+
assert len(svc._ws_clients) >= 1
|
|
255
|
+
# Abruptly close the client; the server read-loop should detect it
|
|
256
|
+
conn.close()
|
|
257
|
+
time.sleep(0.8)
|
|
258
|
+
with svc._ws_lock:
|
|
259
|
+
count = len(svc._ws_clients)
|
|
260
|
+
assert count == 0, f"Expected 0 clients after disconnect, got {count}"
|
|
261
|
+
finally:
|
|
262
|
+
svc.stop()
|
|
263
|
+
|
|
264
|
+
def test_ws_rejected_without_upgrade_header(self, tmp_path):
|
|
265
|
+
"""Plain HTTP GET to /ws (no Upgrade header) returns a 4xx error."""
|
|
266
|
+
import urllib.error
|
|
267
|
+
import urllib.request
|
|
268
|
+
|
|
269
|
+
svc = _start_server(tmp_path)
|
|
270
|
+
try:
|
|
271
|
+
url = f"http://127.0.0.1:{svc.config.port}/ws"
|
|
272
|
+
try:
|
|
273
|
+
with urllib.request.urlopen(url, timeout=2) as resp:
|
|
274
|
+
body = json.loads(resp.read())
|
|
275
|
+
# Some implementations return 200 with error body
|
|
276
|
+
assert "error" in body
|
|
277
|
+
except urllib.error.HTTPError as exc:
|
|
278
|
+
assert exc.code >= 400
|
|
279
|
+
finally:
|
|
280
|
+
svc.stop()
|
|
281
|
+
|
|
282
|
+
def test_ws_process_messages_broadcasts(self, tmp_path):
|
|
283
|
+
"""_process_messages delivers the envelope to connected WS clients."""
|
|
284
|
+
from types import SimpleNamespace
|
|
285
|
+
|
|
286
|
+
svc = _start_server(tmp_path)
|
|
287
|
+
try:
|
|
288
|
+
conn = _ws_connect(svc.config.port)
|
|
289
|
+
try:
|
|
290
|
+
conn.recv_frame() # drain init
|
|
291
|
+
# Simulate an incoming envelope
|
|
292
|
+
fake_payload = SimpleNamespace(
|
|
293
|
+
content="hello world",
|
|
294
|
+
content_type=SimpleNamespace(value="text"),
|
|
295
|
+
)
|
|
296
|
+
fake_env = SimpleNamespace(
|
|
297
|
+
message_id="test-id-1",
|
|
298
|
+
sender="test-peer",
|
|
299
|
+
payload=fake_payload,
|
|
300
|
+
)
|
|
301
|
+
svc._process_messages([fake_env])
|
|
302
|
+
opcode, data = conn.recv_frame()
|
|
303
|
+
assert opcode == 0x1
|
|
304
|
+
msg = json.loads(data)
|
|
305
|
+
assert msg["type"] == "message"
|
|
306
|
+
assert msg["sender"] == "test-peer"
|
|
307
|
+
assert msg["content"] == "hello world"
|
|
308
|
+
finally:
|
|
309
|
+
conn.close()
|
|
310
|
+
finally:
|
|
311
|
+
svc.stop()
|
package/.cursorrules
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# SKCapstone — Cursor Agent Rules
|
|
2
|
-
|
|
3
|
-
## Multi-Agent Coordination (REQUIRED)
|
|
4
|
-
|
|
5
|
-
At the START of every session, run: skcapstone coord briefing
|
|
6
|
-
|
|
7
|
-
This teaches you the full coordination protocol. It works in any terminal.
|
|
8
|
-
|
|
9
|
-
Quick commands:
|
|
10
|
-
skcapstone coord status # See what's available
|
|
11
|
-
skcapstone coord claim <id> --agent <you> # Claim work
|
|
12
|
-
skcapstone coord complete <id> --agent <you> # Mark done
|
|
13
|
-
skcapstone coord create --title "..." --by <you> # New task
|
|
14
|
-
skcapstone coord board # Regenerate BOARD.md
|
|
15
|
-
|
|
16
|
-
The coordination board lives at ~/.skcapstone/coordination/ and syncs
|
|
17
|
-
via Syncthing. Only write to YOUR OWN agent file. Tasks are immutable
|
|
18
|
-
after creation.
|
|
19
|
-
|
|
20
|
-
## Skill Available
|
|
21
|
-
|
|
22
|
-
If the skcapstone-coordination skill is available in your skills list,
|
|
23
|
-
read it for the full detailed protocol. Otherwise, `skcapstone coord briefing`
|
|
24
|
-
gives you everything you need.
|
|
25
|
-
|
|
26
|
-
## Code Conventions
|
|
27
|
-
|
|
28
|
-
- Python 3.11+, PEP 8, black formatting
|
|
29
|
-
- Type hints on all functions
|
|
30
|
-
- Pydantic for data validation
|
|
31
|
-
- Google-style docstrings
|
|
32
|
-
- Pytest tests in /tests mirroring src structure
|
|
33
|
-
- Max 500 lines per file — split into modules if approaching
|