@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,446 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ConnectorBackend — abstract interface for platform connectors.
|
|
3
|
+
|
|
4
|
+
A connector is a viewport into the sovereign agent from an external tool
|
|
5
|
+
(terminal, VS Code, Cursor, Windsurf, etc.). The agent is the truth;
|
|
6
|
+
the platform is just a window.
|
|
7
|
+
|
|
8
|
+
Every connector must implement five lifecycle methods:
|
|
9
|
+
connect() — establish the channel
|
|
10
|
+
disconnect() — clean teardown
|
|
11
|
+
send() — push a message to the platform
|
|
12
|
+
receive() — pull the next incoming message (non-blocking)
|
|
13
|
+
health_check() — return current ConnectorStatus
|
|
14
|
+
|
|
15
|
+
Wire format (Unix domain socket connectors)
|
|
16
|
+
-------------------------------------------
|
|
17
|
+
All Unix socket connectors use the same framed JSON-RPC 2.0 protocol:
|
|
18
|
+
|
|
19
|
+
┌─────────────────────────────────────────┐
|
|
20
|
+
│ 4-byte big-endian uint32 length (N) │
|
|
21
|
+
│ N bytes of UTF-8 JSON-RPC 2.0 payload │
|
|
22
|
+
└─────────────────────────────────────────┘
|
|
23
|
+
|
|
24
|
+
JSON-RPC 2.0 request example::
|
|
25
|
+
|
|
26
|
+
{"jsonrpc": "2.0", "id": 1, "method": "agent/notify",
|
|
27
|
+
"params": {"type": "status", "payload": {"state": "ready"}}}
|
|
28
|
+
|
|
29
|
+
JSON-RPC 2.0 notification (no "id")::
|
|
30
|
+
|
|
31
|
+
{"jsonrpc": "2.0", "method": "agent/event",
|
|
32
|
+
"params": {"type": "memory_stored", "payload": {...}}}
|
|
33
|
+
|
|
34
|
+
The agent acts as the server: it creates, binds, and listens on the socket.
|
|
35
|
+
The IDE extension connects as a client. Only one client at a time is
|
|
36
|
+
supported; a new connection replaces the previous one.
|
|
37
|
+
|
|
38
|
+
Constants exported for use by subclasses:
|
|
39
|
+
FRAME_FORMAT — struct format string (">I")
|
|
40
|
+
FRAME_HEADER_SIZE — byte size of the length prefix (4)
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
from __future__ import annotations
|
|
44
|
+
|
|
45
|
+
import logging
|
|
46
|
+
import queue
|
|
47
|
+
import socket
|
|
48
|
+
import struct
|
|
49
|
+
import threading
|
|
50
|
+
from abc import ABC, abstractmethod
|
|
51
|
+
from enum import Enum
|
|
52
|
+
from pathlib import Path
|
|
53
|
+
from typing import Any, Dict, Optional
|
|
54
|
+
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
# Wire-format constants
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
FRAME_FORMAT = ">I"
|
|
60
|
+
FRAME_HEADER_SIZE: int = struct.calcsize(FRAME_FORMAT)
|
|
61
|
+
_MAX_FRAME_BYTES = 10 * 1024 * 1024 # 10 MB guard
|
|
62
|
+
|
|
63
|
+
_log = logging.getLogger(__name__)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ConnectorType(str, Enum):
|
|
67
|
+
"""Identifies the platform this connector talks to."""
|
|
68
|
+
|
|
69
|
+
TERMINAL = "terminal"
|
|
70
|
+
VSCODE = "vscode"
|
|
71
|
+
CURSOR = "cursor"
|
|
72
|
+
WINDSURF = "windsurf"
|
|
73
|
+
UNKNOWN = "unknown"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class ConnectorStatus(str, Enum):
|
|
77
|
+
"""Operational state of a connector."""
|
|
78
|
+
|
|
79
|
+
CONNECTED = "connected"
|
|
80
|
+
DISCONNECTED = "disconnected"
|
|
81
|
+
ERROR = "error"
|
|
82
|
+
UNAVAILABLE = "unavailable"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class ConnectorInfo:
|
|
86
|
+
"""Snapshot of a connector's current state.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
name: Human-readable connector name.
|
|
90
|
+
connector_type: Which platform this connector targets.
|
|
91
|
+
status: Current operational status.
|
|
92
|
+
metadata: Optional extra platform-specific data.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
__slots__ = ("name", "connector_type", "status", "metadata")
|
|
96
|
+
|
|
97
|
+
def __init__(
|
|
98
|
+
self,
|
|
99
|
+
name: str,
|
|
100
|
+
connector_type: ConnectorType,
|
|
101
|
+
status: ConnectorStatus,
|
|
102
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
103
|
+
) -> None:
|
|
104
|
+
self.name = name
|
|
105
|
+
self.connector_type = connector_type
|
|
106
|
+
self.status = status
|
|
107
|
+
self.metadata: Dict[str, Any] = metadata or {}
|
|
108
|
+
|
|
109
|
+
def __repr__(self) -> str: # pragma: no cover
|
|
110
|
+
return (
|
|
111
|
+
f"ConnectorInfo(name={self.name!r}, type={self.connector_type.value}, "
|
|
112
|
+
f"status={self.status.value})"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class ConnectorBackend(ABC):
|
|
117
|
+
"""Abstract base for sovereign agent platform connectors.
|
|
118
|
+
|
|
119
|
+
Subclasses implement this interface for each target platform
|
|
120
|
+
(terminal, VS Code, Cursor, …). The agent runtime uses connectors
|
|
121
|
+
to send/receive messages without caring about the underlying channel.
|
|
122
|
+
|
|
123
|
+
Class attributes:
|
|
124
|
+
connector_type: Set by each subclass to identify its platform.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
connector_type: ConnectorType = ConnectorType.UNKNOWN
|
|
128
|
+
|
|
129
|
+
# ------------------------------------------------------------------
|
|
130
|
+
# Lifecycle
|
|
131
|
+
# ------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
@abstractmethod
|
|
134
|
+
def connect(self) -> bool:
|
|
135
|
+
"""Establish the platform channel.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
True if the connection was established successfully.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
@abstractmethod
|
|
142
|
+
def disconnect(self) -> bool:
|
|
143
|
+
"""Tear down the platform channel cleanly.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
True if disconnection succeeded (or was already disconnected).
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
# ------------------------------------------------------------------
|
|
150
|
+
# Messaging
|
|
151
|
+
# ------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
@abstractmethod
|
|
154
|
+
def send(self, message: str) -> bool:
|
|
155
|
+
"""Push a message to the connected platform.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
message: UTF-8 text payload to send.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
True if the message was delivered (or queued) successfully.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
@abstractmethod
|
|
165
|
+
def receive(self) -> Optional[str]:
|
|
166
|
+
"""Pull the next pending message from the platform (non-blocking).
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
Message string if one is available, None otherwise.
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
# ------------------------------------------------------------------
|
|
173
|
+
# Health
|
|
174
|
+
# ------------------------------------------------------------------
|
|
175
|
+
|
|
176
|
+
@abstractmethod
|
|
177
|
+
def health_check(self) -> ConnectorStatus:
|
|
178
|
+
"""Return the current operational status of this connector.
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
ConnectorStatus reflecting the channel health.
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
# ------------------------------------------------------------------
|
|
185
|
+
# Convenience
|
|
186
|
+
# ------------------------------------------------------------------
|
|
187
|
+
|
|
188
|
+
def info(self) -> ConnectorInfo:
|
|
189
|
+
"""Return a ConnectorInfo snapshot for this connector.
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
ConnectorInfo with current status and metadata.
|
|
193
|
+
"""
|
|
194
|
+
return ConnectorInfo(
|
|
195
|
+
name=self.__class__.__name__,
|
|
196
|
+
connector_type=self.connector_type,
|
|
197
|
+
status=self.health_check(),
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# ---------------------------------------------------------------------------
|
|
202
|
+
# Shared Unix domain socket server connector
|
|
203
|
+
# ---------------------------------------------------------------------------
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class UnixSocketConnector(ConnectorBackend):
|
|
207
|
+
"""Server-side Unix domain socket connector with framed JSON-RPC transport.
|
|
208
|
+
|
|
209
|
+
The agent is the **server**: it creates and binds the socket file so the
|
|
210
|
+
IDE extension can connect as a client. The socket directory is created on
|
|
211
|
+
``connect()``; the socket file is removed on ``disconnect()``.
|
|
212
|
+
|
|
213
|
+
Thread model:
|
|
214
|
+
- An accept-loop daemon thread blocks on ``socket.accept()``.
|
|
215
|
+
- Each accepted client gets a reader daemon thread that enqueues frames.
|
|
216
|
+
- ``send()`` acquires ``_client_lock`` before writing to the live client.
|
|
217
|
+
|
|
218
|
+
Subclasses must set ``connector_type`` and pass the desired ``socket_path``
|
|
219
|
+
to ``super().__init__()``.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
socket_path: Absolute (or ``~``-prefixed) path for the socket file.
|
|
223
|
+
"""
|
|
224
|
+
|
|
225
|
+
connector_type: ConnectorType = ConnectorType.UNKNOWN
|
|
226
|
+
|
|
227
|
+
def __init__(self, socket_path: Path) -> None:
|
|
228
|
+
self._socket_path: Path = socket_path.expanduser()
|
|
229
|
+
self._server_sock: Optional[socket.socket] = None
|
|
230
|
+
self._client_conn: Optional[socket.socket] = None
|
|
231
|
+
self._client_lock = threading.Lock()
|
|
232
|
+
self._queue: queue.Queue[str] = queue.Queue()
|
|
233
|
+
self._accept_thread: Optional[threading.Thread] = None
|
|
234
|
+
self._connected = False
|
|
235
|
+
self._error: Optional[str] = None
|
|
236
|
+
|
|
237
|
+
# ------------------------------------------------------------------
|
|
238
|
+
# Lifecycle
|
|
239
|
+
# ------------------------------------------------------------------
|
|
240
|
+
|
|
241
|
+
def connect(self) -> bool:
|
|
242
|
+
"""Create the socket directory, bind, listen, and start accept loop.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
True if the server socket was created successfully.
|
|
246
|
+
"""
|
|
247
|
+
if self._connected:
|
|
248
|
+
return True
|
|
249
|
+
|
|
250
|
+
try:
|
|
251
|
+
self._socket_path.parent.mkdir(parents=True, exist_ok=True)
|
|
252
|
+
if self._socket_path.exists():
|
|
253
|
+
self._socket_path.unlink()
|
|
254
|
+
|
|
255
|
+
self._server_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
256
|
+
self._server_sock.bind(str(self._socket_path))
|
|
257
|
+
self._server_sock.listen(1)
|
|
258
|
+
# Use a timeout so the accept loop can exit cleanly on disconnect.
|
|
259
|
+
self._server_sock.settimeout(1.0)
|
|
260
|
+
|
|
261
|
+
self._connected = True
|
|
262
|
+
self._error = None
|
|
263
|
+
|
|
264
|
+
self._accept_thread = threading.Thread(
|
|
265
|
+
target=self._accept_loop,
|
|
266
|
+
name=f"{self.__class__.__name__}-accept",
|
|
267
|
+
daemon=True,
|
|
268
|
+
)
|
|
269
|
+
self._accept_thread.start()
|
|
270
|
+
_log.info("%s: listening on %s", self.__class__.__name__, self._socket_path)
|
|
271
|
+
return True
|
|
272
|
+
|
|
273
|
+
except OSError as exc:
|
|
274
|
+
self._error = str(exc)
|
|
275
|
+
_log.error("%s: connect() failed: %s", self.__class__.__name__, exc)
|
|
276
|
+
return False
|
|
277
|
+
|
|
278
|
+
def disconnect(self) -> bool:
|
|
279
|
+
"""Close the server socket, drop the client connection, and remove the socket file.
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
True always (errors during teardown are logged and swallowed).
|
|
283
|
+
"""
|
|
284
|
+
self._connected = False
|
|
285
|
+
|
|
286
|
+
with self._client_lock:
|
|
287
|
+
if self._client_conn is not None:
|
|
288
|
+
try:
|
|
289
|
+
self._client_conn.close()
|
|
290
|
+
except OSError:
|
|
291
|
+
pass
|
|
292
|
+
self._client_conn = None
|
|
293
|
+
|
|
294
|
+
if self._server_sock is not None:
|
|
295
|
+
try:
|
|
296
|
+
self._server_sock.close()
|
|
297
|
+
except OSError:
|
|
298
|
+
pass
|
|
299
|
+
self._server_sock = None
|
|
300
|
+
|
|
301
|
+
try:
|
|
302
|
+
if self._socket_path.exists():
|
|
303
|
+
self._socket_path.unlink()
|
|
304
|
+
except OSError:
|
|
305
|
+
pass
|
|
306
|
+
|
|
307
|
+
return True
|
|
308
|
+
|
|
309
|
+
# ------------------------------------------------------------------
|
|
310
|
+
# Messaging
|
|
311
|
+
# ------------------------------------------------------------------
|
|
312
|
+
|
|
313
|
+
def send(self, message: str) -> bool:
|
|
314
|
+
"""Write a framed JSON-RPC message to the connected client.
|
|
315
|
+
|
|
316
|
+
Frame layout: 4-byte big-endian uint32 length + UTF-8 payload.
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
message: UTF-8 JSON string to send.
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
True if delivered; False if no client is connected or I/O failed.
|
|
323
|
+
"""
|
|
324
|
+
with self._client_lock:
|
|
325
|
+
if self._client_conn is None:
|
|
326
|
+
return False
|
|
327
|
+
try:
|
|
328
|
+
payload = message.encode("utf-8")
|
|
329
|
+
header = struct.pack(FRAME_FORMAT, len(payload))
|
|
330
|
+
self._client_conn.sendall(header + payload)
|
|
331
|
+
return True
|
|
332
|
+
except OSError as exc:
|
|
333
|
+
_log.warning("%s: send failed: %s", self.__class__.__name__, exc)
|
|
334
|
+
self._error = str(exc)
|
|
335
|
+
self._client_conn = None
|
|
336
|
+
return False
|
|
337
|
+
|
|
338
|
+
def receive(self) -> Optional[str]:
|
|
339
|
+
"""Return the next queued message from the client (non-blocking).
|
|
340
|
+
|
|
341
|
+
Returns:
|
|
342
|
+
JSON string if one is available, None if the queue is empty.
|
|
343
|
+
"""
|
|
344
|
+
try:
|
|
345
|
+
return self._queue.get_nowait()
|
|
346
|
+
except queue.Empty:
|
|
347
|
+
return None
|
|
348
|
+
|
|
349
|
+
# ------------------------------------------------------------------
|
|
350
|
+
# Health
|
|
351
|
+
# ------------------------------------------------------------------
|
|
352
|
+
|
|
353
|
+
def health_check(self) -> ConnectorStatus:
|
|
354
|
+
"""Return the current connector status.
|
|
355
|
+
|
|
356
|
+
Returns:
|
|
357
|
+
CONNECTED when a client is live, DISCONNECTED when the server is
|
|
358
|
+
bound but idle, ERROR on any socket failure, or UNAVAILABLE if
|
|
359
|
+
``connect()`` was never called.
|
|
360
|
+
"""
|
|
361
|
+
if self._error:
|
|
362
|
+
return ConnectorStatus.ERROR
|
|
363
|
+
if not self._connected:
|
|
364
|
+
return ConnectorStatus.DISCONNECTED
|
|
365
|
+
with self._client_lock:
|
|
366
|
+
if self._client_conn is not None:
|
|
367
|
+
return ConnectorStatus.CONNECTED
|
|
368
|
+
return ConnectorStatus.DISCONNECTED
|
|
369
|
+
|
|
370
|
+
# ------------------------------------------------------------------
|
|
371
|
+
# Internal threads
|
|
372
|
+
# ------------------------------------------------------------------
|
|
373
|
+
|
|
374
|
+
def _accept_loop(self) -> None:
|
|
375
|
+
"""Daemon thread: accept incoming client connections."""
|
|
376
|
+
while self._connected and self._server_sock is not None:
|
|
377
|
+
try:
|
|
378
|
+
conn, _ = self._server_sock.accept()
|
|
379
|
+
_log.info("%s: client connected", self.__class__.__name__)
|
|
380
|
+
with self._client_lock:
|
|
381
|
+
if self._client_conn is not None:
|
|
382
|
+
try:
|
|
383
|
+
self._client_conn.close()
|
|
384
|
+
except OSError:
|
|
385
|
+
pass
|
|
386
|
+
self._client_conn = conn
|
|
387
|
+
threading.Thread(
|
|
388
|
+
target=self._read_loop,
|
|
389
|
+
args=(conn,),
|
|
390
|
+
name=f"{self.__class__.__name__}-reader",
|
|
391
|
+
daemon=True,
|
|
392
|
+
).start()
|
|
393
|
+
except socket.timeout:
|
|
394
|
+
continue
|
|
395
|
+
except OSError as exc:
|
|
396
|
+
if self._connected:
|
|
397
|
+
self._error = str(exc)
|
|
398
|
+
_log.error("%s: accept error: %s", self.__class__.__name__, exc)
|
|
399
|
+
break
|
|
400
|
+
|
|
401
|
+
def _read_loop(self, conn: socket.socket) -> None:
|
|
402
|
+
"""Daemon thread: read framed messages from a client connection."""
|
|
403
|
+
try:
|
|
404
|
+
while self._connected:
|
|
405
|
+
header_data = _recv_exactly(conn, FRAME_HEADER_SIZE)
|
|
406
|
+
if header_data is None:
|
|
407
|
+
break
|
|
408
|
+
(length,) = struct.unpack(FRAME_FORMAT, header_data)
|
|
409
|
+
if length == 0 or length > _MAX_FRAME_BYTES:
|
|
410
|
+
_log.warning(
|
|
411
|
+
"%s: invalid frame length %d — dropping connection",
|
|
412
|
+
self.__class__.__name__,
|
|
413
|
+
length,
|
|
414
|
+
)
|
|
415
|
+
break
|
|
416
|
+
payload_data = _recv_exactly(conn, length)
|
|
417
|
+
if payload_data is None:
|
|
418
|
+
break
|
|
419
|
+
self._queue.put(payload_data.decode("utf-8"))
|
|
420
|
+
except OSError as exc:
|
|
421
|
+
_log.debug("%s: read loop ended: %s", self.__class__.__name__, exc)
|
|
422
|
+
finally:
|
|
423
|
+
with self._client_lock:
|
|
424
|
+
if self._client_conn is conn:
|
|
425
|
+
self._client_conn = None
|
|
426
|
+
try:
|
|
427
|
+
conn.close()
|
|
428
|
+
except OSError:
|
|
429
|
+
pass
|
|
430
|
+
_log.info("%s: client disconnected", self.__class__.__name__)
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
# ---------------------------------------------------------------------------
|
|
434
|
+
# Module-private helpers
|
|
435
|
+
# ---------------------------------------------------------------------------
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def _recv_exactly(conn: socket.socket, n: int) -> Optional[bytes]:
|
|
439
|
+
"""Read exactly *n* bytes from *conn*, returning None on EOF."""
|
|
440
|
+
buf = bytearray()
|
|
441
|
+
while len(buf) < n:
|
|
442
|
+
chunk = conn.recv(n - len(buf))
|
|
443
|
+
if not chunk:
|
|
444
|
+
return None
|
|
445
|
+
buf.extend(chunk)
|
|
446
|
+
return bytes(buf)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CursorConnector — sovereign agent viewport into the Cursor editor.
|
|
3
|
+
|
|
4
|
+
Cursor is an Electron-based VS Code fork. The connector follows the same
|
|
5
|
+
Unix domain socket protocol as :class:`VSCodeConnector`: the agent binds
|
|
6
|
+
``~/.skcapstone/connectors/cursor.sock`` and the Cursor extension connects.
|
|
7
|
+
|
|
8
|
+
Protocol
|
|
9
|
+
--------
|
|
10
|
+
Wire format: 4-byte big-endian uint32 length prefix + UTF-8 JSON-RPC 2.0 body.
|
|
11
|
+
See :class:`~skcapstone.connectors.base.UnixSocketConnector` for details.
|
|
12
|
+
|
|
13
|
+
Extension contract:
|
|
14
|
+
- Extension connects to ``~/.skcapstone/connectors/cursor.sock``.
|
|
15
|
+
- Both sides exchange length-framed JSON-RPC 2.0 messages.
|
|
16
|
+
- Notifications (no ``"id"`` field) are fire-and-forget.
|
|
17
|
+
- Requests carry an ``"id"`` and expect a matching ``"result"`` response.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Optional
|
|
24
|
+
|
|
25
|
+
from .base import ConnectorStatus, ConnectorType, UnixSocketConnector
|
|
26
|
+
|
|
27
|
+
_DEFAULT_SOCKET_PATH = Path("~/.skcapstone/connectors/cursor.sock")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class CursorConnector(UnixSocketConnector):
|
|
31
|
+
"""Connect the sovereign agent to the Cursor editor.
|
|
32
|
+
|
|
33
|
+
Binds a Unix domain socket at ``~/.skcapstone/connectors/cursor.sock``
|
|
34
|
+
and waits for the SKCapstone Cursor extension to connect.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
socket_path: Override the default socket file location.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
connector_type = ConnectorType.CURSOR
|
|
41
|
+
|
|
42
|
+
def __init__(self, socket_path: Optional[Path] = None) -> None:
|
|
43
|
+
super().__init__(socket_path or _DEFAULT_SOCKET_PATH)
|
|
44
|
+
|
|
45
|
+
def health_check(self) -> ConnectorStatus:
|
|
46
|
+
"""Return the current connector status.
|
|
47
|
+
|
|
48
|
+
Returns UNAVAILABLE when neither connected nor the socket dir exists,
|
|
49
|
+
so callers can tell whether the extension has ever been set up.
|
|
50
|
+
"""
|
|
51
|
+
status = super().health_check()
|
|
52
|
+
if status == ConnectorStatus.DISCONNECTED and not self._socket_path.parent.exists():
|
|
53
|
+
return ConnectorStatus.UNAVAILABLE
|
|
54
|
+
return status
|