@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,364 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for the full Syncthing ↔ consciousness loop comms pipeline.
|
|
3
|
+
|
|
4
|
+
Pipeline under test:
|
|
5
|
+
{shared_root}/sync/comms/inbox/{peer}/*.skc.json ← Syncthing writes here
|
|
6
|
+
→ inotify detects file (ConsciousnessLoop._run_inotify)
|
|
7
|
+
→ ConsciousnessLoop.process_envelope()
|
|
8
|
+
→ skcomm.send(sender, response)
|
|
9
|
+
→ {shared_root}/sync/comms/outbox/{peer}/*.skc.json ← Syncthing syncs this out
|
|
10
|
+
|
|
11
|
+
Three test classes:
|
|
12
|
+
TestInboxToOutboxFlow — mock LLM, drop inbox file, verify skcomm.send called
|
|
13
|
+
TestOutboxEnvelopeFormat — verify envelope spec compliance and path layout
|
|
14
|
+
TestSyncStatusInHealth — verify health snapshot includes sync_pipeline key
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import json
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from unittest.mock import MagicMock, patch
|
|
22
|
+
|
|
23
|
+
import pytest
|
|
24
|
+
|
|
25
|
+
from skcapstone.sync_engine import (
|
|
26
|
+
ENVELOPE_SUFFIX,
|
|
27
|
+
get_inbox_dir,
|
|
28
|
+
get_outbox_dir,
|
|
29
|
+
get_sync_pipeline_status,
|
|
30
|
+
verify_pipeline_paths,
|
|
31
|
+
write_outbox_envelope,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# ---------------------------------------------------------------------------
|
|
36
|
+
# Fixtures
|
|
37
|
+
# ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@pytest.fixture
|
|
41
|
+
def shared_root(tmp_path: Path) -> Path:
|
|
42
|
+
"""Minimal shared-root with comms inbox/outbox directories pre-created."""
|
|
43
|
+
root = tmp_path / ".skcapstone"
|
|
44
|
+
root.mkdir()
|
|
45
|
+
(root / "sync" / "comms" / "inbox").mkdir(parents=True)
|
|
46
|
+
(root / "sync" / "comms" / "outbox").mkdir(parents=True)
|
|
47
|
+
return root
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@pytest.fixture
|
|
51
|
+
def agent_home(shared_root: Path) -> Path:
|
|
52
|
+
"""Single-agent mode: home == shared_root. Provides identity.json."""
|
|
53
|
+
home = shared_root
|
|
54
|
+
for d in ("identity", "memory", "trust", "config", "conversations"):
|
|
55
|
+
(home / d).mkdir(exist_ok=True)
|
|
56
|
+
(home / "identity" / "identity.json").write_text(
|
|
57
|
+
json.dumps({"name": "TestAgent", "fingerprint": "AABB1122CCDD3344"}),
|
|
58
|
+
encoding="utf-8",
|
|
59
|
+
)
|
|
60
|
+
return home
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@pytest.fixture
|
|
64
|
+
def mock_skcomm() -> MagicMock:
|
|
65
|
+
skcomm = MagicMock()
|
|
66
|
+
skcomm.send.return_value = None
|
|
67
|
+
skcomm.receive.return_value = []
|
|
68
|
+
return skcomm
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# ---------------------------------------------------------------------------
|
|
72
|
+
# TestInboxToOutboxFlow
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class TestInboxToOutboxFlow:
|
|
77
|
+
"""Drop a file in the inbox and verify the consciousness loop responds."""
|
|
78
|
+
|
|
79
|
+
def _make_loop(self, agent_home: Path, shared_root: Path, mock_skcomm):
|
|
80
|
+
"""Return a ConsciousnessLoop with a mocked LLM bridge."""
|
|
81
|
+
from skcapstone.consciousness_loop import ConsciousnessConfig, ConsciousnessLoop
|
|
82
|
+
|
|
83
|
+
config = ConsciousnessConfig(
|
|
84
|
+
enabled=True,
|
|
85
|
+
use_inotify=False, # manual trigger in tests
|
|
86
|
+
auto_ack=False,
|
|
87
|
+
auto_memory=False,
|
|
88
|
+
desktop_notifications=False,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
with patch("skcapstone.consciousness_loop.LLMBridge") as MockBridge:
|
|
92
|
+
bridge = MagicMock()
|
|
93
|
+
bridge.generate.return_value = "Hello back from TestAgent"
|
|
94
|
+
bridge.available_backends = {"passthrough": True}
|
|
95
|
+
MockBridge.return_value = bridge
|
|
96
|
+
|
|
97
|
+
loop = ConsciousnessLoop(
|
|
98
|
+
config,
|
|
99
|
+
home=agent_home,
|
|
100
|
+
shared_root=shared_root,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
loop.set_skcomm(mock_skcomm)
|
|
104
|
+
return loop
|
|
105
|
+
|
|
106
|
+
def test_inbox_to_outbox_flow(
|
|
107
|
+
self, shared_root: Path, agent_home: Path, mock_skcomm: MagicMock
|
|
108
|
+
):
|
|
109
|
+
"""File dropped in inbox triggers process_envelope and skcomm.send."""
|
|
110
|
+
loop = self._make_loop(agent_home, shared_root, mock_skcomm)
|
|
111
|
+
|
|
112
|
+
peer = "alice"
|
|
113
|
+
inbox_peer = get_inbox_dir(shared_root) / peer
|
|
114
|
+
inbox_peer.mkdir(parents=True, exist_ok=True)
|
|
115
|
+
|
|
116
|
+
envelope = {
|
|
117
|
+
"envelope_id": "test-msg-001",
|
|
118
|
+
"sender": peer,
|
|
119
|
+
"recipient": "testagent",
|
|
120
|
+
"timestamp": "2026-03-01T00:00:00Z",
|
|
121
|
+
"payload": {
|
|
122
|
+
"content": "Hey TestAgent, what is happening?",
|
|
123
|
+
"content_type": "text",
|
|
124
|
+
},
|
|
125
|
+
}
|
|
126
|
+
inbox_file = inbox_peer / f"test-msg-001{ENVELOPE_SUFFIX}"
|
|
127
|
+
inbox_file.write_text(json.dumps(envelope), encoding="utf-8")
|
|
128
|
+
|
|
129
|
+
# Simulate inotify trigger
|
|
130
|
+
loop._on_inbox_file(inbox_file)
|
|
131
|
+
loop._executor.shutdown(wait=True)
|
|
132
|
+
|
|
133
|
+
assert mock_skcomm.send.called, "skcomm.send() must be called with the LLM response"
|
|
134
|
+
recipient_arg = mock_skcomm.send.call_args[0][0]
|
|
135
|
+
assert recipient_arg == peer, "Response must be addressed to the original sender"
|
|
136
|
+
|
|
137
|
+
def test_skipped_when_sender_missing(
|
|
138
|
+
self, shared_root: Path, agent_home: Path, mock_skcomm: MagicMock
|
|
139
|
+
):
|
|
140
|
+
"""Envelopes without a sender field are silently dropped."""
|
|
141
|
+
loop = self._make_loop(agent_home, shared_root, mock_skcomm)
|
|
142
|
+
|
|
143
|
+
inbox_peer = get_inbox_dir(shared_root) / "ghost"
|
|
144
|
+
inbox_peer.mkdir(parents=True, exist_ok=True)
|
|
145
|
+
no_sender = {"payload": {"content": "ghost message", "content_type": "text"}}
|
|
146
|
+
inbox_file = inbox_peer / f"no-sender{ENVELOPE_SUFFIX}"
|
|
147
|
+
inbox_file.write_text(json.dumps(no_sender), encoding="utf-8")
|
|
148
|
+
|
|
149
|
+
loop._on_inbox_file(inbox_file)
|
|
150
|
+
loop._executor.shutdown(wait=True)
|
|
151
|
+
|
|
152
|
+
mock_skcomm.send.assert_not_called()
|
|
153
|
+
|
|
154
|
+
def test_duplicate_envelope_not_reprocessed(
|
|
155
|
+
self, shared_root: Path, agent_home: Path, mock_skcomm: MagicMock
|
|
156
|
+
):
|
|
157
|
+
"""The same envelope_id is never processed twice."""
|
|
158
|
+
loop = self._make_loop(agent_home, shared_root, mock_skcomm)
|
|
159
|
+
|
|
160
|
+
peer = "bob"
|
|
161
|
+
inbox_peer = get_inbox_dir(shared_root) / peer
|
|
162
|
+
inbox_peer.mkdir(parents=True, exist_ok=True)
|
|
163
|
+
|
|
164
|
+
envelope = {
|
|
165
|
+
"envelope_id": "dup-001",
|
|
166
|
+
"sender": peer,
|
|
167
|
+
"recipient": "testagent",
|
|
168
|
+
"payload": {"content": "duplicate test", "content_type": "text"},
|
|
169
|
+
}
|
|
170
|
+
inbox_file = inbox_peer / f"dup-001{ENVELOPE_SUFFIX}"
|
|
171
|
+
inbox_file.write_text(json.dumps(envelope), encoding="utf-8")
|
|
172
|
+
|
|
173
|
+
# First call
|
|
174
|
+
loop._on_inbox_file(inbox_file)
|
|
175
|
+
loop._executor.shutdown(wait=True)
|
|
176
|
+
first_count = mock_skcomm.send.call_count
|
|
177
|
+
|
|
178
|
+
# Recreate the loop's executor for a second submission attempt
|
|
179
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
180
|
+
loop._executor = ThreadPoolExecutor(max_workers=1, thread_name_prefix="consciousness")
|
|
181
|
+
|
|
182
|
+
# Second call with the same file (same envelope_id)
|
|
183
|
+
loop._on_inbox_file(inbox_file)
|
|
184
|
+
loop._executor.shutdown(wait=True)
|
|
185
|
+
|
|
186
|
+
# Exactly the same number of sends — second call was deduped
|
|
187
|
+
assert mock_skcomm.send.call_count == first_count
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
# ---------------------------------------------------------------------------
|
|
191
|
+
# TestOutboxEnvelopeFormat
|
|
192
|
+
# ---------------------------------------------------------------------------
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class TestOutboxEnvelopeFormat:
|
|
196
|
+
"""Verify that outbox envelopes comply with the SKComm envelope spec."""
|
|
197
|
+
|
|
198
|
+
def test_required_fields_preserved(self, shared_root: Path):
|
|
199
|
+
"""write_outbox_envelope writes all envelope fields to the .skc.json."""
|
|
200
|
+
envelope = {
|
|
201
|
+
"envelope_id": "out-001",
|
|
202
|
+
"sender": "opus",
|
|
203
|
+
"recipient": "alice",
|
|
204
|
+
"timestamp": "2026-03-01T00:00:00Z",
|
|
205
|
+
"payload": {
|
|
206
|
+
"content": "Response from Opus",
|
|
207
|
+
"content_type": "text",
|
|
208
|
+
},
|
|
209
|
+
}
|
|
210
|
+
written = write_outbox_envelope(shared_root, "alice", envelope)
|
|
211
|
+
|
|
212
|
+
assert written.exists()
|
|
213
|
+
data = json.loads(written.read_text(encoding="utf-8"))
|
|
214
|
+
assert data["envelope_id"] == "out-001"
|
|
215
|
+
assert data["sender"] == "opus"
|
|
216
|
+
assert data["recipient"] == "alice"
|
|
217
|
+
assert data["payload"]["content"] == "Response from Opus"
|
|
218
|
+
assert data["payload"]["content_type"] == "text"
|
|
219
|
+
|
|
220
|
+
def test_file_placed_in_outbox_subdirectory(self, shared_root: Path):
|
|
221
|
+
"""Envelope file lives under outbox/{recipient}/."""
|
|
222
|
+
envelope = {"envelope_id": "dir-test", "payload": {"content": "hi", "content_type": "text"}}
|
|
223
|
+
written = write_outbox_envelope(shared_root, "bob", envelope)
|
|
224
|
+
|
|
225
|
+
expected_parent = get_outbox_dir(shared_root) / "bob"
|
|
226
|
+
assert written.parent == expected_parent
|
|
227
|
+
|
|
228
|
+
def test_file_has_skc_json_suffix(self, shared_root: Path):
|
|
229
|
+
"""Written file ends with .skc.json."""
|
|
230
|
+
envelope = {"envelope_id": "suffix-test", "payload": {"content": "x", "content_type": "text"}}
|
|
231
|
+
written = write_outbox_envelope(shared_root, "carol", envelope)
|
|
232
|
+
assert written.name.endswith(ENVELOPE_SUFFIX)
|
|
233
|
+
|
|
234
|
+
def test_atomic_write_leaves_no_tmp_files(self, shared_root: Path):
|
|
235
|
+
"""No .tmp files remain after write_outbox_envelope."""
|
|
236
|
+
envelope = {
|
|
237
|
+
"envelope_id": "atomic-001",
|
|
238
|
+
"payload": {"content": "atomic test", "content_type": "text"},
|
|
239
|
+
}
|
|
240
|
+
written = write_outbox_envelope(shared_root, "dave", envelope)
|
|
241
|
+
tmp_files = list(written.parent.glob("*.tmp"))
|
|
242
|
+
assert tmp_files == []
|
|
243
|
+
|
|
244
|
+
def test_path_traversal_in_recipient_neutralized(self, shared_root: Path):
|
|
245
|
+
"""Path-traversal characters in recipient are stripped."""
|
|
246
|
+
envelope = {
|
|
247
|
+
"envelope_id": "safe-001",
|
|
248
|
+
"payload": {"content": "test", "content_type": "text"},
|
|
249
|
+
}
|
|
250
|
+
written = write_outbox_envelope(shared_root, "../../../etc/passwd", envelope)
|
|
251
|
+
# Must stay inside shared_root
|
|
252
|
+
assert shared_root in written.parents
|
|
253
|
+
|
|
254
|
+
def test_outbox_pipeline_status_reflects_written_file(self, shared_root: Path):
|
|
255
|
+
"""get_sync_pipeline_status counts the newly written outbox file."""
|
|
256
|
+
envelope = {
|
|
257
|
+
"envelope_id": "count-001",
|
|
258
|
+
"payload": {"content": "counting", "content_type": "text"},
|
|
259
|
+
}
|
|
260
|
+
write_outbox_envelope(shared_root, "eve", envelope)
|
|
261
|
+
status = get_sync_pipeline_status(shared_root)
|
|
262
|
+
assert status["outbox_files"] >= 1
|
|
263
|
+
assert "eve" in status["outbox_peers"]
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
# ---------------------------------------------------------------------------
|
|
267
|
+
# TestSyncStatusInHealth
|
|
268
|
+
# ---------------------------------------------------------------------------
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class TestSyncStatusInHealth:
|
|
272
|
+
"""Verify that the daemon health snapshot includes sync pipeline status."""
|
|
273
|
+
|
|
274
|
+
def test_get_sync_pipeline_status_keys(self, shared_root: Path):
|
|
275
|
+
"""get_sync_pipeline_status returns all required keys."""
|
|
276
|
+
status = get_sync_pipeline_status(shared_root)
|
|
277
|
+
required = {
|
|
278
|
+
"inbox_files",
|
|
279
|
+
"outbox_files",
|
|
280
|
+
"inbox_peers",
|
|
281
|
+
"outbox_peers",
|
|
282
|
+
"inbox_path",
|
|
283
|
+
"outbox_path",
|
|
284
|
+
"inbox_exists",
|
|
285
|
+
"outbox_exists",
|
|
286
|
+
"checked_at",
|
|
287
|
+
}
|
|
288
|
+
assert required.issubset(status.keys())
|
|
289
|
+
|
|
290
|
+
def test_get_sync_pipeline_status_counts_inbox_file(self, shared_root: Path):
|
|
291
|
+
"""Status correctly counts a file dropped in the inbox."""
|
|
292
|
+
peer = "frank"
|
|
293
|
+
inbox_dir = get_inbox_dir(shared_root) / peer
|
|
294
|
+
inbox_dir.mkdir(parents=True, exist_ok=True)
|
|
295
|
+
(inbox_dir / f"msg-001{ENVELOPE_SUFFIX}").write_text(
|
|
296
|
+
json.dumps({"payload": {"content": "hi"}}), encoding="utf-8"
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
status = get_sync_pipeline_status(shared_root)
|
|
300
|
+
assert status["inbox_files"] >= 1
|
|
301
|
+
assert peer in status["inbox_peers"]
|
|
302
|
+
|
|
303
|
+
def test_verify_pipeline_paths_ok_when_dirs_exist(self, shared_root: Path):
|
|
304
|
+
"""verify_pipeline_paths reports no issues when dirs are present."""
|
|
305
|
+
result = verify_pipeline_paths(shared_root)
|
|
306
|
+
assert result["inbox_ok"] is True
|
|
307
|
+
assert result["outbox_ok"] is True
|
|
308
|
+
assert result["issues"] == []
|
|
309
|
+
|
|
310
|
+
def test_verify_pipeline_paths_reports_missing_inbox(self, tmp_path: Path):
|
|
311
|
+
"""verify_pipeline_paths reports missing inbox dir."""
|
|
312
|
+
empty_root = tmp_path / "empty"
|
|
313
|
+
empty_root.mkdir()
|
|
314
|
+
result = verify_pipeline_paths(empty_root)
|
|
315
|
+
assert result["inbox_ok"] is False
|
|
316
|
+
assert any("Inbox" in issue for issue in result["issues"])
|
|
317
|
+
|
|
318
|
+
def test_verify_pipeline_paths_reports_missing_outbox(self, tmp_path: Path):
|
|
319
|
+
"""verify_pipeline_paths reports missing outbox dir."""
|
|
320
|
+
root = tmp_path / "partial"
|
|
321
|
+
root.mkdir()
|
|
322
|
+
# create only inbox
|
|
323
|
+
(root / "sync" / "comms" / "inbox").mkdir(parents=True)
|
|
324
|
+
result = verify_pipeline_paths(root)
|
|
325
|
+
assert result["outbox_ok"] is False
|
|
326
|
+
assert any("Outbox" in issue for issue in result["issues"])
|
|
327
|
+
|
|
328
|
+
def test_daemon_state_snapshot_includes_sync_pipeline(self):
|
|
329
|
+
"""DaemonState.snapshot() includes sync_pipeline after record_sync_pipeline."""
|
|
330
|
+
from skcapstone.daemon import DaemonState
|
|
331
|
+
|
|
332
|
+
state = DaemonState()
|
|
333
|
+
state.record_sync_pipeline({"inbox_files": 3, "outbox_files": 1})
|
|
334
|
+
snap = state.snapshot()
|
|
335
|
+
|
|
336
|
+
assert "sync_pipeline" in snap
|
|
337
|
+
assert snap["sync_pipeline"]["inbox_files"] == 3
|
|
338
|
+
assert snap["sync_pipeline"]["outbox_files"] == 1
|
|
339
|
+
|
|
340
|
+
def test_daemon_state_sync_pipeline_starts_empty(self):
|
|
341
|
+
"""DaemonState starts with an empty sync_pipeline dict."""
|
|
342
|
+
from skcapstone.daemon import DaemonState
|
|
343
|
+
|
|
344
|
+
state = DaemonState()
|
|
345
|
+
snap = state.snapshot()
|
|
346
|
+
assert "sync_pipeline" in snap
|
|
347
|
+
assert snap["sync_pipeline"] == {}
|
|
348
|
+
|
|
349
|
+
def test_verify_pipeline_detects_transport_misalignment(self, shared_root: Path):
|
|
350
|
+
"""verify_pipeline_paths flags a SyncthingTransport with a wrong comms_root."""
|
|
351
|
+
# Build a mock SKComm with a Syncthing transport pointing to the wrong path
|
|
352
|
+
wrong_transport = MagicMock()
|
|
353
|
+
wrong_transport.name = "syncthing"
|
|
354
|
+
wrong_transport._root = Path("/tmp/wrong/path")
|
|
355
|
+
|
|
356
|
+
mock_router = MagicMock()
|
|
357
|
+
mock_router.transports = [wrong_transport]
|
|
358
|
+
|
|
359
|
+
mock_skcomm = MagicMock()
|
|
360
|
+
mock_skcomm.router = mock_router
|
|
361
|
+
|
|
362
|
+
result = verify_pipeline_paths(shared_root, skcomm=mock_skcomm)
|
|
363
|
+
assert result["transport_aligned"] is False
|
|
364
|
+
assert any("mismatch" in issue.lower() for issue in result["issues"])
|