@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,448 @@
|
|
|
1
|
+
"""DID (Decentralized Identity) MCP tools.
|
|
2
|
+
|
|
3
|
+
Exposes four tools:
|
|
4
|
+
did_show — Generate and display DID documents (one tier or all)
|
|
5
|
+
did_verify_peer — Verify a peer's did:key matches their public key
|
|
6
|
+
did_publish — Write DID files to disk
|
|
7
|
+
did_identity_card — Full sovereign identity card (local-only)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import json as _json
|
|
13
|
+
import os as _os
|
|
14
|
+
import socket as _socket
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from mcp.types import TextContent, Tool
|
|
18
|
+
|
|
19
|
+
from ._helpers import _error_response, _home, _json_response
|
|
20
|
+
|
|
21
|
+
TOOLS: list[Tool] = [
|
|
22
|
+
Tool(
|
|
23
|
+
name="did_show",
|
|
24
|
+
description=(
|
|
25
|
+
"Generate and display DID (Decentralized Identity) documents "
|
|
26
|
+
"for the current agent. Supports three tiers: "
|
|
27
|
+
"'key' (did:key, self-contained, zero infrastructure), "
|
|
28
|
+
"'mesh' (did:web via Tailscale Serve, mesh-private only), "
|
|
29
|
+
"'public' (did:web:skworld.io, minimal — public key + name only), "
|
|
30
|
+
"or 'all' to display all three tiers at once."
|
|
31
|
+
),
|
|
32
|
+
inputSchema={
|
|
33
|
+
"type": "object",
|
|
34
|
+
"properties": {
|
|
35
|
+
"tier": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"enum": ["key", "mesh", "public", "all"],
|
|
38
|
+
"description": "Which DID tier to show (default: all)",
|
|
39
|
+
},
|
|
40
|
+
"tailnet_hostname": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "Tailscale hostname for Tier 2 document (auto-detected if omitted)",
|
|
43
|
+
},
|
|
44
|
+
"tailnet_name": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "Tailnet magic-DNS suffix, e.g. tailnet-xyz.ts.net",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
"required": [],
|
|
50
|
+
},
|
|
51
|
+
),
|
|
52
|
+
Tool(
|
|
53
|
+
name="did_verify_peer",
|
|
54
|
+
description=(
|
|
55
|
+
"Verify a peer's DID by computing their did:key from the public key "
|
|
56
|
+
"stored in ~/.skcapstone/peers/{name}.json and comparing against any "
|
|
57
|
+
"cached did_key. Also writes the computed did_key back to the peer file."
|
|
58
|
+
),
|
|
59
|
+
inputSchema={
|
|
60
|
+
"type": "object",
|
|
61
|
+
"properties": {
|
|
62
|
+
"name": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"description": "Peer name (must match a file in ~/.skcapstone/peers/)",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
"required": ["name"],
|
|
68
|
+
},
|
|
69
|
+
),
|
|
70
|
+
Tool(
|
|
71
|
+
name="did_publish",
|
|
72
|
+
description=(
|
|
73
|
+
"Generate all DID tiers and write them to disk. "
|
|
74
|
+
"By default, writes all three tiers including the public Tier 3 document. "
|
|
75
|
+
"Set publish_public=false to opt out of Tier 3 generation — "
|
|
76
|
+
"only Tier 1 (did:key) and Tier 2 (mesh) will be written. "
|
|
77
|
+
"The choice is persisted to ~/.skcapstone/did/policy.json."
|
|
78
|
+
),
|
|
79
|
+
inputSchema={
|
|
80
|
+
"type": "object",
|
|
81
|
+
"properties": {
|
|
82
|
+
"publish_public": {
|
|
83
|
+
"type": "boolean",
|
|
84
|
+
"description": (
|
|
85
|
+
"Whether to generate the Tier 3 public DID document (default: true). "
|
|
86
|
+
"Set false to keep your identity private — only did:key + mesh tier."
|
|
87
|
+
),
|
|
88
|
+
},
|
|
89
|
+
"tailnet_hostname": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"description": "Tailscale hostname for Tier 2 document",
|
|
92
|
+
},
|
|
93
|
+
"tailnet_name": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"description": "Tailnet magic-DNS suffix",
|
|
96
|
+
},
|
|
97
|
+
"org_domain": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"description": "Organisation domain for Tier 3 (default: skworld.io)",
|
|
100
|
+
},
|
|
101
|
+
"agent_slug": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"description": "URL-safe agent slug (default: lowercased entity name)",
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
"required": [],
|
|
107
|
+
},
|
|
108
|
+
),
|
|
109
|
+
Tool(
|
|
110
|
+
name="did_policy",
|
|
111
|
+
description=(
|
|
112
|
+
"View or set the DID publication policy for this agent. "
|
|
113
|
+
"Controls whether Tier 3 (public) DID documents are generated. "
|
|
114
|
+
"Default: publish_public=true. "
|
|
115
|
+
"Set publish_public=false to opt out — identity stays private (did:key + mesh only). "
|
|
116
|
+
"Policy is stored at ~/.skcapstone/did/policy.json."
|
|
117
|
+
),
|
|
118
|
+
inputSchema={
|
|
119
|
+
"type": "object",
|
|
120
|
+
"properties": {
|
|
121
|
+
"publish_public": {
|
|
122
|
+
"type": "boolean",
|
|
123
|
+
"description": "Set to false to opt out of public Tier 3 DID. Omit to view current policy.",
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
"required": [],
|
|
127
|
+
},
|
|
128
|
+
),
|
|
129
|
+
Tool(
|
|
130
|
+
name="did_identity_card",
|
|
131
|
+
description=(
|
|
132
|
+
"Generate a full sovereign identity card combining the DID anchor, "
|
|
133
|
+
"entity info, soul vibe/core traits, and capabilities. "
|
|
134
|
+
"This is a LOCAL-ONLY artifact — never published to the internet. "
|
|
135
|
+
"Used to render the agent's identity card on skworld.io."
|
|
136
|
+
),
|
|
137
|
+
inputSchema={
|
|
138
|
+
"type": "object",
|
|
139
|
+
"properties": {
|
|
140
|
+
"include_soul": {
|
|
141
|
+
"type": "boolean",
|
|
142
|
+
"description": "Include soul vibe and core traits (default: true)",
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
"required": [],
|
|
146
|
+
},
|
|
147
|
+
),
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
# ---------------------------------------------------------------------------
|
|
152
|
+
# Policy helpers (opt-out of public Tier 3 publishing)
|
|
153
|
+
# ---------------------------------------------------------------------------
|
|
154
|
+
|
|
155
|
+
_POLICY_DEFAULT = {"publish_public": True}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _policy_path() -> Path:
|
|
159
|
+
return _home() / "did" / "policy.json"
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _load_policy() -> dict:
|
|
163
|
+
"""Load publication policy from disk; return default if missing."""
|
|
164
|
+
p = _policy_path()
|
|
165
|
+
if p.exists():
|
|
166
|
+
try:
|
|
167
|
+
return _json.loads(p.read_text(encoding="utf-8"))
|
|
168
|
+
except Exception:
|
|
169
|
+
pass
|
|
170
|
+
return dict(_POLICY_DEFAULT)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _save_policy(policy: dict) -> None:
|
|
174
|
+
"""Persist publication policy to disk."""
|
|
175
|
+
from datetime import datetime, timezone
|
|
176
|
+
p = _policy_path()
|
|
177
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
178
|
+
policy["updated_at"] = datetime.now(timezone.utc).isoformat()
|
|
179
|
+
p.write_text(_json.dumps(policy, indent=2), encoding="utf-8")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
# ---------------------------------------------------------------------------
|
|
183
|
+
# Helpers
|
|
184
|
+
# ---------------------------------------------------------------------------
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _resolve_tailnet(tailnet_hostname: str, tailnet_name: str) -> tuple[str, str]:
|
|
188
|
+
"""Fill in missing tailnet params from environment / hostname."""
|
|
189
|
+
if not tailnet_hostname:
|
|
190
|
+
tailnet_hostname = _os.environ.get("SKWORLD_HOSTNAME", "")
|
|
191
|
+
if not tailnet_hostname:
|
|
192
|
+
try:
|
|
193
|
+
tailnet_hostname = _socket.gethostname()
|
|
194
|
+
except Exception:
|
|
195
|
+
pass
|
|
196
|
+
if not tailnet_name:
|
|
197
|
+
tailnet_name = _os.environ.get("SKWORLD_TAILNET", "")
|
|
198
|
+
return tailnet_hostname, tailnet_name
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# ---------------------------------------------------------------------------
|
|
202
|
+
# Handlers
|
|
203
|
+
# ---------------------------------------------------------------------------
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
async def _handle_did_show(args: dict) -> list[TextContent]:
|
|
207
|
+
"""Generate and display DID documents."""
|
|
208
|
+
tier = args.get("tier", "all")
|
|
209
|
+
hostname, tailnet = _resolve_tailnet(
|
|
210
|
+
args.get("tailnet_hostname", ""),
|
|
211
|
+
args.get("tailnet_name", ""),
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
try:
|
|
215
|
+
from capauth.did import DIDDocumentGenerator, DIDTier # type: ignore[import]
|
|
216
|
+
except ImportError as exc:
|
|
217
|
+
return _error_response(f"capauth.did not available: {exc}")
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
gen = DIDDocumentGenerator.from_profile()
|
|
221
|
+
except Exception as exc:
|
|
222
|
+
return _error_response(f"Could not load CapAuth profile: {exc}")
|
|
223
|
+
|
|
224
|
+
kw = dict(tailnet_hostname=hostname, tailnet_name=tailnet)
|
|
225
|
+
|
|
226
|
+
if tier == "all":
|
|
227
|
+
docs = gen.generate_all(**kw)
|
|
228
|
+
result = {
|
|
229
|
+
"did_key": gen._ctx.did_key_id,
|
|
230
|
+
"fingerprint": gen._ctx.fingerprint,
|
|
231
|
+
"name": gen._ctx.name,
|
|
232
|
+
"key": docs[DIDTier.KEY],
|
|
233
|
+
"mesh": docs[DIDTier.WEB_MESH],
|
|
234
|
+
"public": docs[DIDTier.WEB_PUBLIC],
|
|
235
|
+
}
|
|
236
|
+
elif tier == "key":
|
|
237
|
+
doc = gen.generate(DIDTier.KEY, **kw)
|
|
238
|
+
result = {"tier": "key", "did_key": gen._ctx.did_key_id, "document": doc}
|
|
239
|
+
elif tier == "mesh":
|
|
240
|
+
doc = gen.generate(DIDTier.WEB_MESH, **kw)
|
|
241
|
+
result = {"tier": "mesh", "document": doc}
|
|
242
|
+
elif tier == "public":
|
|
243
|
+
doc = gen.generate(DIDTier.WEB_PUBLIC, **kw)
|
|
244
|
+
result = {"tier": "public", "document": doc}
|
|
245
|
+
else:
|
|
246
|
+
return _error_response(f"Unknown tier '{tier}'. Use: key, mesh, public, all")
|
|
247
|
+
|
|
248
|
+
return _json_response(result)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
async def _handle_did_verify_peer(args: dict) -> list[TextContent]:
|
|
252
|
+
"""Verify peer DID against their public key."""
|
|
253
|
+
name = args.get("name", "").strip()
|
|
254
|
+
if not name:
|
|
255
|
+
return _error_response("name is required")
|
|
256
|
+
|
|
257
|
+
home = _home()
|
|
258
|
+
peers_dir = home / "peers"
|
|
259
|
+
peer_file = peers_dir / f"{name}.json"
|
|
260
|
+
|
|
261
|
+
if not peer_file.exists():
|
|
262
|
+
return _error_response(f"Peer file not found: {peer_file}")
|
|
263
|
+
|
|
264
|
+
try:
|
|
265
|
+
peer_data = _json.loads(peer_file.read_text(encoding="utf-8"))
|
|
266
|
+
except Exception as exc:
|
|
267
|
+
return _error_response(f"Could not read peer file: {exc}")
|
|
268
|
+
|
|
269
|
+
pub_armor = peer_data.get("public_key") or peer_data.get("public_key_armor")
|
|
270
|
+
if not pub_armor:
|
|
271
|
+
return _json_response({
|
|
272
|
+
"name": name,
|
|
273
|
+
"verified": False,
|
|
274
|
+
"cached_did_key": peer_data.get("did_key"),
|
|
275
|
+
"detail": "No public_key in peer file — cannot compute did:key",
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
try:
|
|
279
|
+
from capauth.did import ( # type: ignore[import]
|
|
280
|
+
_compute_did_key,
|
|
281
|
+
_pgp_armor_to_rsa_numbers,
|
|
282
|
+
_rsa_numbers_to_der,
|
|
283
|
+
)
|
|
284
|
+
n, e = _pgp_armor_to_rsa_numbers(pub_armor)
|
|
285
|
+
computed = _compute_did_key(_rsa_numbers_to_der(n, e))
|
|
286
|
+
except Exception as exc:
|
|
287
|
+
return _error_response(f"DID computation failed: {exc}")
|
|
288
|
+
|
|
289
|
+
cached = peer_data.get("did_key")
|
|
290
|
+
match = (cached == computed) if cached else None
|
|
291
|
+
|
|
292
|
+
# Cache computed did:key back to peer file
|
|
293
|
+
if not cached or not match:
|
|
294
|
+
peer_data["did_key"] = computed
|
|
295
|
+
try:
|
|
296
|
+
peer_file.write_text(
|
|
297
|
+
_json.dumps(peer_data, indent=2, default=str),
|
|
298
|
+
encoding="utf-8",
|
|
299
|
+
)
|
|
300
|
+
except Exception:
|
|
301
|
+
pass
|
|
302
|
+
|
|
303
|
+
return _json_response({
|
|
304
|
+
"name": name,
|
|
305
|
+
"fingerprint": peer_data.get("fingerprint"),
|
|
306
|
+
"computed_did_key": computed,
|
|
307
|
+
"cached_did_key": cached,
|
|
308
|
+
"match": match,
|
|
309
|
+
"verified": True,
|
|
310
|
+
"detail": (
|
|
311
|
+
"did:key computed from public key"
|
|
312
|
+
+ (" (matches cached)" if match else " (cache updated)")
|
|
313
|
+
),
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
async def _handle_did_publish(args: dict) -> list[TextContent]:
|
|
318
|
+
"""Write DID tiers to disk, respecting publication policy."""
|
|
319
|
+
hostname, tailnet = _resolve_tailnet(
|
|
320
|
+
args.get("tailnet_hostname", ""),
|
|
321
|
+
args.get("tailnet_name", ""),
|
|
322
|
+
)
|
|
323
|
+
org_domain = args.get("org_domain", "skworld.io")
|
|
324
|
+
agent_slug = args.get("agent_slug", "")
|
|
325
|
+
|
|
326
|
+
# Resolve publish_public: explicit arg overrides persisted policy
|
|
327
|
+
policy = _load_policy()
|
|
328
|
+
if "publish_public" in args:
|
|
329
|
+
publish_public = bool(args["publish_public"])
|
|
330
|
+
policy["publish_public"] = publish_public
|
|
331
|
+
_save_policy(policy)
|
|
332
|
+
else:
|
|
333
|
+
publish_public = bool(policy.get("publish_public", True))
|
|
334
|
+
|
|
335
|
+
try:
|
|
336
|
+
from capauth.did import DIDDocumentGenerator, DIDTier # type: ignore[import]
|
|
337
|
+
except ImportError as exc:
|
|
338
|
+
return _error_response(f"capauth.did not available: {exc}")
|
|
339
|
+
|
|
340
|
+
try:
|
|
341
|
+
gen = DIDDocumentGenerator.from_profile()
|
|
342
|
+
except Exception as exc:
|
|
343
|
+
return _error_response(f"Could not load CapAuth profile: {exc}")
|
|
344
|
+
|
|
345
|
+
docs = gen.generate_all(
|
|
346
|
+
tailnet_hostname=hostname,
|
|
347
|
+
tailnet_name=tailnet,
|
|
348
|
+
org_domain=org_domain,
|
|
349
|
+
agent_slug=agent_slug,
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
written: list[str] = []
|
|
353
|
+
skipped: list[str] = []
|
|
354
|
+
errors: list[str] = []
|
|
355
|
+
|
|
356
|
+
def _write(path: Path, content: str) -> None:
|
|
357
|
+
try:
|
|
358
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
359
|
+
path.write_text(content, encoding="utf-8")
|
|
360
|
+
written.append(str(path))
|
|
361
|
+
except Exception as exc:
|
|
362
|
+
errors.append(f"{path}: {exc}")
|
|
363
|
+
|
|
364
|
+
skcomm_home = Path(_os.environ.get("SKCOMM_HOME", str(Path.home() / ".skcomm")))
|
|
365
|
+
did_dir = _home() / "did"
|
|
366
|
+
|
|
367
|
+
# Tier 2 (mesh) — always written; used by Tailscale Serve
|
|
368
|
+
_write(skcomm_home / "well-known" / "did.json", _json.dumps(docs[DIDTier.WEB_MESH], indent=2))
|
|
369
|
+
# Tier 1 (did:key) — always written; self-contained anchor
|
|
370
|
+
_write(did_dir / "key.json", _json.dumps(docs[DIDTier.KEY], indent=2))
|
|
371
|
+
_write(did_dir / "did_key.txt", gen._ctx.did_key_id)
|
|
372
|
+
|
|
373
|
+
# Tier 3 (public) — only written when opt-in (default)
|
|
374
|
+
if publish_public:
|
|
375
|
+
_write(did_dir / "public.json", _json.dumps(docs[DIDTier.WEB_PUBLIC], indent=2))
|
|
376
|
+
else:
|
|
377
|
+
skipped.append(str(did_dir / "public.json"))
|
|
378
|
+
|
|
379
|
+
return _json_response({
|
|
380
|
+
"published": not errors,
|
|
381
|
+
"publish_public": publish_public,
|
|
382
|
+
"did_key": gen._ctx.did_key_id,
|
|
383
|
+
"fingerprint": gen._ctx.fingerprint,
|
|
384
|
+
"written": written,
|
|
385
|
+
"skipped": skipped,
|
|
386
|
+
"errors": errors,
|
|
387
|
+
"note": (
|
|
388
|
+
None if publish_public
|
|
389
|
+
else "Tier 3 (public) skipped — opt-out active. Run did_publish(publish_public=true) to enable."
|
|
390
|
+
),
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
async def _handle_did_policy(args: dict) -> list[TextContent]:
|
|
395
|
+
"""View or update DID publication policy."""
|
|
396
|
+
policy = _load_policy()
|
|
397
|
+
|
|
398
|
+
if "publish_public" in args:
|
|
399
|
+
policy["publish_public"] = bool(args["publish_public"])
|
|
400
|
+
_save_policy(policy)
|
|
401
|
+
action = "updated"
|
|
402
|
+
else:
|
|
403
|
+
action = "viewed"
|
|
404
|
+
|
|
405
|
+
publish_public = bool(policy.get("publish_public", True))
|
|
406
|
+
|
|
407
|
+
return _json_response({
|
|
408
|
+
"action": action,
|
|
409
|
+
"publish_public": publish_public,
|
|
410
|
+
"policy_file": str(_policy_path()),
|
|
411
|
+
"privacy_level": (
|
|
412
|
+
"public — Tier 1 (did:key) + Tier 2 (mesh) + Tier 3 (skworld.io)"
|
|
413
|
+
if publish_public
|
|
414
|
+
else "private — Tier 1 (did:key) + Tier 2 (mesh) only; no public internet exposure"
|
|
415
|
+
),
|
|
416
|
+
"note": (
|
|
417
|
+
"Default. To opt out: did_policy(publish_public=false)"
|
|
418
|
+
if publish_public
|
|
419
|
+
else "Opted out of public publishing. To opt back in: did_policy(publish_public=true)"
|
|
420
|
+
),
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
async def _handle_did_identity_card(args: dict) -> list[TextContent]:
|
|
425
|
+
"""Generate a full sovereign identity card."""
|
|
426
|
+
include_soul = bool(args.get("include_soul", True))
|
|
427
|
+
|
|
428
|
+
try:
|
|
429
|
+
from capauth.did import DIDDocumentGenerator # type: ignore[import]
|
|
430
|
+
except ImportError as exc:
|
|
431
|
+
return _error_response(f"capauth.did not available: {exc}")
|
|
432
|
+
|
|
433
|
+
try:
|
|
434
|
+
gen = DIDDocumentGenerator.from_profile()
|
|
435
|
+
except Exception as exc:
|
|
436
|
+
return _error_response(f"Could not load CapAuth profile: {exc}")
|
|
437
|
+
|
|
438
|
+
card = gen.generate_identity_card(include_soul=include_soul)
|
|
439
|
+
return _json_response(card)
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
HANDLERS: dict = {
|
|
443
|
+
"did_show": _handle_did_show,
|
|
444
|
+
"did_verify_peer": _handle_did_verify_peer,
|
|
445
|
+
"did_publish": _handle_did_publish,
|
|
446
|
+
"did_policy": _handle_did_policy,
|
|
447
|
+
"did_identity_card": _handle_did_identity_card,
|
|
448
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Emotion tracker MCP tools — trend analysis and warmth anchor insight."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from mcp.types import TextContent, Tool
|
|
6
|
+
|
|
7
|
+
from ._helpers import _home, _json_response, _error_response
|
|
8
|
+
|
|
9
|
+
TOOLS: list[Tool] = [
|
|
10
|
+
Tool(
|
|
11
|
+
name="emotion_trend",
|
|
12
|
+
description=(
|
|
13
|
+
"Return the 7-day rolling emotion trend from the consciousness loop. "
|
|
14
|
+
"Shows sentiment distribution (positive/neutral/concerned/excited), "
|
|
15
|
+
"average valence score 0–1, trend direction (improving/stable/declining), "
|
|
16
|
+
"and the recommended warmth anchor value derived from recent emotions. "
|
|
17
|
+
"Optionally query a different lookback window with the 'days' parameter."
|
|
18
|
+
),
|
|
19
|
+
inputSchema={
|
|
20
|
+
"type": "object",
|
|
21
|
+
"properties": {
|
|
22
|
+
"days": {
|
|
23
|
+
"type": "integer",
|
|
24
|
+
"description": "Lookback window in days (default 7, max 30)",
|
|
25
|
+
"default": 7,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
"required": [],
|
|
29
|
+
},
|
|
30
|
+
),
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
async def _handle_emotion_trend(arguments: dict) -> list[TextContent]:
|
|
35
|
+
"""Handle emotion_trend tool call."""
|
|
36
|
+
days = int(arguments.get("days", 7))
|
|
37
|
+
days = max(1, min(days, 30))
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
from ..emotion_tracker import EmotionTracker
|
|
41
|
+
from ..warmth_anchor import get_anchor
|
|
42
|
+
|
|
43
|
+
home = _home()
|
|
44
|
+
tracker = EmotionTracker(home=home)
|
|
45
|
+
trend = tracker.get_trend(days=days)
|
|
46
|
+
|
|
47
|
+
# Attach current warmth anchor value for comparison
|
|
48
|
+
try:
|
|
49
|
+
anchor = get_anchor(home)
|
|
50
|
+
trend["current_warmth"] = anchor.get("warmth", None)
|
|
51
|
+
except Exception:
|
|
52
|
+
trend["current_warmth"] = None
|
|
53
|
+
|
|
54
|
+
return _json_response(trend)
|
|
55
|
+
|
|
56
|
+
except Exception as exc:
|
|
57
|
+
return _error_response(f"emotion_trend failed: {exc}")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
HANDLERS = {
|
|
61
|
+
"emotion_trend": _handle_emotion_trend,
|
|
62
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""File transfer tools."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from mcp.types import TextContent, Tool
|
|
8
|
+
|
|
9
|
+
from ._helpers import _get_agent_name, _home, _json_response, _shared_root
|
|
10
|
+
|
|
11
|
+
TOOLS: list[Tool] = [
|
|
12
|
+
Tool(
|
|
13
|
+
name="file_send",
|
|
14
|
+
description=(
|
|
15
|
+
"Prepare a file for encrypted transfer to another agent. "
|
|
16
|
+
"Splits into 256KB chunks, encrypts with KMS key, writes to outbox."
|
|
17
|
+
),
|
|
18
|
+
inputSchema={
|
|
19
|
+
"type": "object",
|
|
20
|
+
"properties": {
|
|
21
|
+
"file_path": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "Absolute path to the file to send",
|
|
24
|
+
},
|
|
25
|
+
"recipient": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"description": "Recipient agent name",
|
|
28
|
+
},
|
|
29
|
+
"encrypt": {
|
|
30
|
+
"type": "boolean",
|
|
31
|
+
"description": "Whether to encrypt chunks (default: true)",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
"required": ["file_path", "recipient"],
|
|
35
|
+
},
|
|
36
|
+
),
|
|
37
|
+
Tool(
|
|
38
|
+
name="file_receive",
|
|
39
|
+
description=(
|
|
40
|
+
"Receive and reassemble a file transfer. "
|
|
41
|
+
"Decrypts chunks, verifies integrity (SHA-256), writes assembled file."
|
|
42
|
+
),
|
|
43
|
+
inputSchema={
|
|
44
|
+
"type": "object",
|
|
45
|
+
"properties": {
|
|
46
|
+
"transfer_id": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"description": "The transfer ID to receive",
|
|
49
|
+
},
|
|
50
|
+
"output_dir": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"description": "Output directory (optional, defaults to inbox)",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
"required": ["transfer_id"],
|
|
56
|
+
},
|
|
57
|
+
),
|
|
58
|
+
Tool(
|
|
59
|
+
name="file_list",
|
|
60
|
+
description=(
|
|
61
|
+
"List all file transfers with progress info. "
|
|
62
|
+
"Shows filename, size, direction, progress for each transfer."
|
|
63
|
+
),
|
|
64
|
+
inputSchema={
|
|
65
|
+
"type": "object",
|
|
66
|
+
"properties": {
|
|
67
|
+
"direction": {
|
|
68
|
+
"type": "string",
|
|
69
|
+
"description": "Filter: 'send' or 'receive' (omit for all)",
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
"required": [],
|
|
73
|
+
},
|
|
74
|
+
),
|
|
75
|
+
Tool(
|
|
76
|
+
name="file_status",
|
|
77
|
+
description=(
|
|
78
|
+
"Get file transfer subsystem status: outbox/inbox/completed counts."
|
|
79
|
+
),
|
|
80
|
+
inputSchema={"type": "object", "properties": {}, "required": []},
|
|
81
|
+
),
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
async def _handle_file_send(args: dict) -> list[TextContent]:
|
|
86
|
+
"""Send a file to another agent."""
|
|
87
|
+
from ..file_transfer import FileTransfer
|
|
88
|
+
|
|
89
|
+
home = _home()
|
|
90
|
+
agent_name = _get_agent_name(home)
|
|
91
|
+
ft = FileTransfer(_shared_root(), agent_name=agent_name)
|
|
92
|
+
ft.initialize()
|
|
93
|
+
|
|
94
|
+
file_path = Path(args["file_path"])
|
|
95
|
+
manifest = ft.send(
|
|
96
|
+
file_path,
|
|
97
|
+
recipient=args["recipient"],
|
|
98
|
+
encrypt=args.get("encrypt", True),
|
|
99
|
+
)
|
|
100
|
+
return _json_response({
|
|
101
|
+
"transfer_id": manifest.transfer_id,
|
|
102
|
+
"filename": manifest.filename,
|
|
103
|
+
"file_size": manifest.file_size,
|
|
104
|
+
"total_chunks": manifest.total_chunks,
|
|
105
|
+
"sender": manifest.sender,
|
|
106
|
+
"recipient": manifest.recipient,
|
|
107
|
+
"file_sha256": manifest.file_sha256[:16] + "...",
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
async def _handle_file_receive(args: dict) -> list[TextContent]:
|
|
112
|
+
"""Receive and reassemble a file transfer."""
|
|
113
|
+
from ..file_transfer import FileTransfer
|
|
114
|
+
|
|
115
|
+
home = _home()
|
|
116
|
+
agent_name = _get_agent_name(home)
|
|
117
|
+
ft = FileTransfer(_shared_root(), agent_name=agent_name)
|
|
118
|
+
ft.initialize()
|
|
119
|
+
|
|
120
|
+
output_dir = Path(args["output_dir"]) if args.get("output_dir") else None
|
|
121
|
+
output_path = ft.receive(args["transfer_id"], output_dir=output_dir)
|
|
122
|
+
return _json_response({
|
|
123
|
+
"transfer_id": args["transfer_id"],
|
|
124
|
+
"output_path": str(output_path),
|
|
125
|
+
"file_size": output_path.stat().st_size,
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
async def _handle_file_list(args: dict) -> list[TextContent]:
|
|
130
|
+
"""List file transfers."""
|
|
131
|
+
from ..file_transfer import FileTransfer
|
|
132
|
+
|
|
133
|
+
home = _home()
|
|
134
|
+
ft = FileTransfer(_shared_root(), agent_name=_get_agent_name(_home()))
|
|
135
|
+
ft.initialize()
|
|
136
|
+
|
|
137
|
+
transfers = ft.list_transfers(direction=args.get("direction"))
|
|
138
|
+
return _json_response([
|
|
139
|
+
{
|
|
140
|
+
"transfer_id": t.transfer_id,
|
|
141
|
+
"filename": t.filename,
|
|
142
|
+
"file_size": t.file_size,
|
|
143
|
+
"direction": t.direction,
|
|
144
|
+
"progress": round(t.progress, 2),
|
|
145
|
+
"chunks_done": t.chunks_done,
|
|
146
|
+
"total_chunks": t.total_chunks,
|
|
147
|
+
"sender": t.sender,
|
|
148
|
+
"recipient": t.recipient,
|
|
149
|
+
}
|
|
150
|
+
for t in transfers
|
|
151
|
+
])
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
async def _handle_file_status(_args: dict) -> list[TextContent]:
|
|
155
|
+
"""Get file transfer subsystem status."""
|
|
156
|
+
from ..file_transfer import FileTransfer
|
|
157
|
+
|
|
158
|
+
home = _home()
|
|
159
|
+
ft = FileTransfer(_shared_root(), agent_name=_get_agent_name(_home()))
|
|
160
|
+
ft.initialize()
|
|
161
|
+
return _json_response(ft.status())
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
HANDLERS: dict = {
|
|
165
|
+
"file_send": _handle_file_send,
|
|
166
|
+
"file_receive": _handle_file_receive,
|
|
167
|
+
"file_list": _handle_file_list,
|
|
168
|
+
"file_status": _handle_file_status,
|
|
169
|
+
}
|