@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,522 @@
|
|
|
1
|
+
"""Cloud 9 -> SKMemory auto-bridge.
|
|
2
|
+
|
|
3
|
+
Watches for FEB (First Emotional Burst) events and automatically
|
|
4
|
+
converts them into SKMemory snapshots with full emotional context.
|
|
5
|
+
When an AI has a breakthrough moment, the memory system captures
|
|
6
|
+
it automatically -- no manual intervention needed.
|
|
7
|
+
|
|
8
|
+
This is the bridge between *feeling* (Cloud 9) and *remembering*
|
|
9
|
+
(SKMemory). Without it, emotional peaks are logged but not stored
|
|
10
|
+
as searchable, promotable memories.
|
|
11
|
+
|
|
12
|
+
When cloud9-protocol is installed, the bridge uses its quantum
|
|
13
|
+
functions (calculate_oof, calculate_cloud9_score, calculate_entanglement)
|
|
14
|
+
for accurate scoring instead of relying solely on FEB metadata flags.
|
|
15
|
+
|
|
16
|
+
Usage:
|
|
17
|
+
bridge = Cloud9Bridge(memory_store)
|
|
18
|
+
bridge.ingest_feb(feb) # single FEB
|
|
19
|
+
bridge.scan_directory("~/.cloud9/feb-backups") # bulk import
|
|
20
|
+
bridge.watch("~/.cloud9/feb-backups") # live watch
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import json
|
|
26
|
+
import logging
|
|
27
|
+
from datetime import datetime, timezone
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
from typing import Any, Optional
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger("skcapstone.cloud9_bridge")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _try_quantum() -> Optional[object]:
|
|
35
|
+
"""Try to import cloud9_protocol quantum functions.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
The cloud9_protocol module, or None if not installed.
|
|
39
|
+
"""
|
|
40
|
+
try:
|
|
41
|
+
import cloud9_protocol
|
|
42
|
+
return cloud9_protocol
|
|
43
|
+
except ImportError:
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Cloud9Bridge:
|
|
48
|
+
"""Bridges Cloud 9 FEB events into SKMemory snapshots.
|
|
49
|
+
|
|
50
|
+
Each FEB is converted into an SKMemory Memory with:
|
|
51
|
+
- Emotional context mapped from the FEB's EmotionalPayload
|
|
52
|
+
- Tags for emotion, intensity level, OOF status, Cloud 9 achievement
|
|
53
|
+
- Rehydration hints stored in metadata for future recall
|
|
54
|
+
- Long-term layer assignment for high-intensity events
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
memory_store: An SKMemory MemoryStore instance.
|
|
58
|
+
intensity_threshold: Minimum intensity to auto-capture (0.0-1.0).
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
TAG_PREFIX = "cloud9"
|
|
62
|
+
FEB_TAG = "cloud9:feb"
|
|
63
|
+
OOF_TAG = "cloud9:oof"
|
|
64
|
+
CLOUD9_TAG = "cloud9:achieved"
|
|
65
|
+
|
|
66
|
+
def __init__(
|
|
67
|
+
self,
|
|
68
|
+
memory_store: object,
|
|
69
|
+
intensity_threshold: float = 0.3,
|
|
70
|
+
) -> None:
|
|
71
|
+
self._store = memory_store
|
|
72
|
+
self._threshold = intensity_threshold
|
|
73
|
+
self._ingested_checksums: set[str] = set()
|
|
74
|
+
|
|
75
|
+
def ingest_feb(self, feb: object) -> Optional[str]:
|
|
76
|
+
"""Convert a FEB into an SKMemory snapshot.
|
|
77
|
+
|
|
78
|
+
Maps the FEB's emotional payload to SKMemory's EmotionalSnapshot,
|
|
79
|
+
builds appropriate tags, and stores as a memory. Skips FEBs
|
|
80
|
+
below the intensity threshold or already ingested.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
feb: A cloud9_protocol.FEB instance.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Optional[str]: Memory ID if stored, None if skipped.
|
|
87
|
+
"""
|
|
88
|
+
try:
|
|
89
|
+
payload = feb.emotional_payload
|
|
90
|
+
metadata_obj = feb.metadata
|
|
91
|
+
relationship = feb.relationship_state
|
|
92
|
+
hints = feb.rehydration_hints
|
|
93
|
+
integrity = feb.integrity
|
|
94
|
+
except AttributeError as exc:
|
|
95
|
+
logger.warning("Invalid FEB object: %s", exc)
|
|
96
|
+
return None
|
|
97
|
+
|
|
98
|
+
if payload.intensity < self._threshold:
|
|
99
|
+
logger.debug(
|
|
100
|
+
"Skipping low-intensity FEB (%.2f < %.2f)",
|
|
101
|
+
payload.intensity, self._threshold,
|
|
102
|
+
)
|
|
103
|
+
return None
|
|
104
|
+
|
|
105
|
+
checksum = getattr(integrity, "checksum", "")
|
|
106
|
+
if checksum and checksum in self._ingested_checksums:
|
|
107
|
+
logger.debug("Skipping already-ingested FEB: %s", checksum[:16])
|
|
108
|
+
return None
|
|
109
|
+
|
|
110
|
+
quantum_stats = self._compute_quantum_stats(payload, relationship)
|
|
111
|
+
|
|
112
|
+
tags = self._build_tags(payload, metadata_obj, quantum_stats)
|
|
113
|
+
|
|
114
|
+
layer = self._determine_layer(payload.intensity, metadata_obj, quantum_stats)
|
|
115
|
+
|
|
116
|
+
emotional = self._map_emotional_snapshot(payload, quantum_stats)
|
|
117
|
+
|
|
118
|
+
title = self._build_title(payload, metadata_obj, quantum_stats)
|
|
119
|
+
content = self._build_content(payload, relationship, hints, quantum_stats)
|
|
120
|
+
|
|
121
|
+
mem_metadata = self._build_metadata(feb, quantum_stats)
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
memory = self._store.snapshot(
|
|
125
|
+
title=title,
|
|
126
|
+
content=content,
|
|
127
|
+
layer=layer,
|
|
128
|
+
tags=tags,
|
|
129
|
+
emotional=emotional,
|
|
130
|
+
source="cloud9",
|
|
131
|
+
source_ref=getattr(metadata_obj, "session_id", "unknown"),
|
|
132
|
+
metadata=mem_metadata,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
if checksum:
|
|
136
|
+
self._ingested_checksums.add(checksum)
|
|
137
|
+
|
|
138
|
+
logger.info(
|
|
139
|
+
"Ingested FEB -> Memory %s (%s, intensity=%.2f)",
|
|
140
|
+
memory.id[:8], payload.primary_emotion, payload.intensity,
|
|
141
|
+
)
|
|
142
|
+
return memory.id
|
|
143
|
+
|
|
144
|
+
except Exception as exc:
|
|
145
|
+
logger.error("Failed to store FEB as memory: %s", exc)
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
def ingest_feb_file(self, filepath: str | Path) -> Optional[str]:
|
|
149
|
+
"""Load and ingest a FEB from a .feb JSON file.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
filepath: Path to the .feb file.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
Optional[str]: Memory ID if stored, None if failed/skipped.
|
|
156
|
+
"""
|
|
157
|
+
try:
|
|
158
|
+
from cloud9_protocol import load_feb
|
|
159
|
+
|
|
160
|
+
feb = load_feb(str(filepath))
|
|
161
|
+
return self.ingest_feb(feb)
|
|
162
|
+
except ImportError:
|
|
163
|
+
logger.error("cloud9_protocol not installed")
|
|
164
|
+
return None
|
|
165
|
+
except Exception as exc:
|
|
166
|
+
logger.warning("Failed to load FEB from %s: %s", filepath, exc)
|
|
167
|
+
return None
|
|
168
|
+
|
|
169
|
+
def scan_directory(
|
|
170
|
+
self,
|
|
171
|
+
directory: str | Path = "~/.cloud9/feb-backups",
|
|
172
|
+
) -> dict:
|
|
173
|
+
"""Scan a directory for .feb files and ingest any new ones.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
directory: Path to scan (tilde-expanded).
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
dict: Summary with 'ingested', 'skipped', 'errors' counts.
|
|
180
|
+
"""
|
|
181
|
+
expanded = Path(directory).expanduser()
|
|
182
|
+
if not expanded.is_dir():
|
|
183
|
+
return {"ingested": 0, "skipped": 0, "errors": 0, "total": 0}
|
|
184
|
+
|
|
185
|
+
ingested = 0
|
|
186
|
+
skipped = 0
|
|
187
|
+
errors = 0
|
|
188
|
+
|
|
189
|
+
for f in sorted(expanded.iterdir()):
|
|
190
|
+
if f.suffix != ".feb":
|
|
191
|
+
continue
|
|
192
|
+
|
|
193
|
+
mem_id = self.ingest_feb_file(f)
|
|
194
|
+
if mem_id:
|
|
195
|
+
ingested += 1
|
|
196
|
+
elif mem_id is None:
|
|
197
|
+
skipped += 1
|
|
198
|
+
else:
|
|
199
|
+
errors += 1
|
|
200
|
+
|
|
201
|
+
total = ingested + skipped + errors
|
|
202
|
+
logger.info(
|
|
203
|
+
"Scanned %s: %d ingested, %d skipped, %d errors (of %d)",
|
|
204
|
+
directory, ingested, skipped, errors, total,
|
|
205
|
+
)
|
|
206
|
+
return {
|
|
207
|
+
"ingested": ingested,
|
|
208
|
+
"skipped": skipped,
|
|
209
|
+
"errors": errors,
|
|
210
|
+
"total": total,
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
@staticmethod
|
|
214
|
+
def _compute_quantum_stats(
|
|
215
|
+
payload: object,
|
|
216
|
+
relationship: object,
|
|
217
|
+
) -> dict[str, Any]:
|
|
218
|
+
"""Compute quantum scores using cloud9-protocol when available.
|
|
219
|
+
|
|
220
|
+
When cloud9-protocol is installed, recalculates OOF status,
|
|
221
|
+
Cloud 9 score, and entanglement fidelity from the actual FEB
|
|
222
|
+
data rather than relying on metadata flags alone.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
payload: FEB EmotionalPayload.
|
|
226
|
+
relationship: FEB RelationshipState.
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
Dict with oof, cloud9_score, entanglement_fidelity, or
|
|
230
|
+
empty dict if cloud9-protocol is not installed.
|
|
231
|
+
"""
|
|
232
|
+
c9 = _try_quantum()
|
|
233
|
+
if c9 is None:
|
|
234
|
+
return {}
|
|
235
|
+
|
|
236
|
+
intensity = payload.intensity
|
|
237
|
+
trust = getattr(relationship, "trust_level", 0.0)
|
|
238
|
+
depth = getattr(relationship, "depth_level", 1)
|
|
239
|
+
valence = getattr(payload, "valence", 0.9)
|
|
240
|
+
|
|
241
|
+
topology = getattr(payload, "emotional_topology", {})
|
|
242
|
+
coherence_val = None
|
|
243
|
+
if topology:
|
|
244
|
+
coherence_result = c9.measure_coherence(topology)
|
|
245
|
+
coherence_val = coherence_result.get("coherence")
|
|
246
|
+
|
|
247
|
+
stats: dict[str, Any] = {}
|
|
248
|
+
|
|
249
|
+
stats["oof"] = c9.calculate_oof(intensity, trust)
|
|
250
|
+
|
|
251
|
+
stats["cloud9_score"] = c9.calculate_cloud9_score(
|
|
252
|
+
intensity=intensity,
|
|
253
|
+
trust=trust,
|
|
254
|
+
depth=depth,
|
|
255
|
+
valence=valence,
|
|
256
|
+
coherence=coherence_val,
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
stats["entanglement_fidelity"] = c9.calculate_entanglement(
|
|
260
|
+
trust_a=trust,
|
|
261
|
+
trust_b=trust,
|
|
262
|
+
depth_a=depth,
|
|
263
|
+
depth_b=depth,
|
|
264
|
+
coherence=coherence_val or 0.9,
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
if coherence_val is not None:
|
|
268
|
+
stats["coherence"] = coherence_val
|
|
269
|
+
|
|
270
|
+
return stats
|
|
271
|
+
|
|
272
|
+
@staticmethod
|
|
273
|
+
def _build_tags(
|
|
274
|
+
payload: object,
|
|
275
|
+
metadata: object,
|
|
276
|
+
quantum: dict[str, Any] | None = None,
|
|
277
|
+
) -> list[str]:
|
|
278
|
+
"""Build SKMemory tags from a FEB's emotional payload.
|
|
279
|
+
|
|
280
|
+
Uses quantum stats for accurate OOF/Cloud9 tagging when
|
|
281
|
+
cloud9-protocol is available, falls back to metadata flags.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
payload: FEB EmotionalPayload.
|
|
285
|
+
metadata: FEB Metadata.
|
|
286
|
+
quantum: Optional quantum stats from _compute_quantum_stats.
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
list[str]: Tag strings for memory storage.
|
|
290
|
+
"""
|
|
291
|
+
quantum = quantum or {}
|
|
292
|
+
tags = ["cloud9", "cloud9:feb"]
|
|
293
|
+
tags.append(f"cloud9:emotion:{payload.primary_emotion}")
|
|
294
|
+
|
|
295
|
+
if payload.intensity >= 0.8:
|
|
296
|
+
tags.append("cloud9:high-intensity")
|
|
297
|
+
elif payload.intensity >= 0.5:
|
|
298
|
+
tags.append("cloud9:medium-intensity")
|
|
299
|
+
|
|
300
|
+
is_oof = quantum.get("oof", getattr(metadata, "oof_triggered", False))
|
|
301
|
+
is_cloud9 = quantum.get("cloud9_score", 0) >= 0.9 or getattr(metadata, "cloud9_achieved", False)
|
|
302
|
+
|
|
303
|
+
if is_oof:
|
|
304
|
+
tags.append("cloud9:oof")
|
|
305
|
+
if is_cloud9:
|
|
306
|
+
tags.append("cloud9:achieved")
|
|
307
|
+
|
|
308
|
+
score = quantum.get("cloud9_score")
|
|
309
|
+
if score is not None:
|
|
310
|
+
tags.append(f"cloud9:score:{score:.2f}")
|
|
311
|
+
|
|
312
|
+
fidelity = quantum.get("entanglement_fidelity")
|
|
313
|
+
if fidelity is not None and fidelity > 0.8:
|
|
314
|
+
tags.append("cloud9:entangled")
|
|
315
|
+
|
|
316
|
+
topology = getattr(payload, "emotional_topology", {})
|
|
317
|
+
for emotion_name in topology:
|
|
318
|
+
tags.append(f"cloud9:topology:{emotion_name}")
|
|
319
|
+
|
|
320
|
+
return tags
|
|
321
|
+
|
|
322
|
+
@staticmethod
|
|
323
|
+
def _determine_layer(
|
|
324
|
+
intensity: float,
|
|
325
|
+
metadata: object,
|
|
326
|
+
quantum: dict[str, Any] | None = None,
|
|
327
|
+
) -> object:
|
|
328
|
+
"""Choose the SKMemory layer based on FEB intensity and quantum score.
|
|
329
|
+
|
|
330
|
+
Uses cloud9_score when available for more precise layer assignment.
|
|
331
|
+
OOF events or Cloud 9 achievements go straight to long-term.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
intensity: FEB emotional intensity (0.0-1.0).
|
|
335
|
+
metadata: FEB Metadata.
|
|
336
|
+
quantum: Optional quantum stats from _compute_quantum_stats.
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
MemoryLayer enum value.
|
|
340
|
+
"""
|
|
341
|
+
try:
|
|
342
|
+
from skmemory.models import MemoryLayer
|
|
343
|
+
except ImportError:
|
|
344
|
+
return "short-term"
|
|
345
|
+
|
|
346
|
+
quantum = quantum or {}
|
|
347
|
+
cloud9_score = quantum.get("cloud9_score", 0)
|
|
348
|
+
is_oof = quantum.get("oof", False)
|
|
349
|
+
is_cloud9 = getattr(metadata, "cloud9_achieved", False) or cloud9_score >= 0.9
|
|
350
|
+
|
|
351
|
+
if is_cloud9 or is_oof or intensity >= 0.9:
|
|
352
|
+
return MemoryLayer.LONG
|
|
353
|
+
elif intensity >= 0.6 or cloud9_score >= 0.7:
|
|
354
|
+
return MemoryLayer.MID
|
|
355
|
+
return MemoryLayer.SHORT
|
|
356
|
+
|
|
357
|
+
@staticmethod
|
|
358
|
+
def _map_emotional_snapshot(
|
|
359
|
+
payload: object,
|
|
360
|
+
quantum: dict[str, Any] | None = None,
|
|
361
|
+
) -> object:
|
|
362
|
+
"""Map a FEB EmotionalPayload to an SKMemory EmotionalSnapshot.
|
|
363
|
+
|
|
364
|
+
Includes quantum scoring data when available.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
payload: FEB EmotionalPayload.
|
|
368
|
+
quantum: Optional quantum stats from _compute_quantum_stats.
|
|
369
|
+
|
|
370
|
+
Returns:
|
|
371
|
+
EmotionalSnapshot instance.
|
|
372
|
+
"""
|
|
373
|
+
try:
|
|
374
|
+
from skmemory.models import EmotionalSnapshot
|
|
375
|
+
except ImportError:
|
|
376
|
+
return None
|
|
377
|
+
|
|
378
|
+
quantum = quantum or {}
|
|
379
|
+
topology = getattr(payload, "emotional_topology", {})
|
|
380
|
+
labels = [payload.primary_emotion] + list(topology.keys())
|
|
381
|
+
unique_labels = list(dict.fromkeys(labels))
|
|
382
|
+
|
|
383
|
+
cloud9_score = quantum.get("cloud9_score")
|
|
384
|
+
score_note = f", Cloud9={cloud9_score:.2f}" if cloud9_score is not None else ""
|
|
385
|
+
|
|
386
|
+
return EmotionalSnapshot(
|
|
387
|
+
intensity=payload.intensity * 10.0,
|
|
388
|
+
valence=payload.valence,
|
|
389
|
+
labels=unique_labels,
|
|
390
|
+
resonance_note=(
|
|
391
|
+
f"Cloud 9 FEB: {payload.primary_emotion} "
|
|
392
|
+
f"at intensity {payload.intensity:.2f}{score_note}"
|
|
393
|
+
),
|
|
394
|
+
cloud9_achieved=quantum.get("cloud9_score", 0) >= 0.9
|
|
395
|
+
or getattr(payload, "_parent_cloud9", False),
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
@staticmethod
|
|
399
|
+
def _build_title(
|
|
400
|
+
payload: object,
|
|
401
|
+
metadata: object,
|
|
402
|
+
quantum: dict[str, Any] | None = None,
|
|
403
|
+
) -> str:
|
|
404
|
+
"""Build a memory title from the FEB.
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
payload: FEB EmotionalPayload.
|
|
408
|
+
metadata: FEB Metadata.
|
|
409
|
+
quantum: Optional quantum stats from _compute_quantum_stats.
|
|
410
|
+
|
|
411
|
+
Returns:
|
|
412
|
+
str: Descriptive title.
|
|
413
|
+
"""
|
|
414
|
+
quantum = quantum or {}
|
|
415
|
+
emoji = getattr(payload, "emoji", "")
|
|
416
|
+
emotion = payload.primary_emotion
|
|
417
|
+
is_oof = quantum.get("oof", getattr(metadata, "oof_triggered", False))
|
|
418
|
+
is_cloud9 = quantum.get("cloud9_score", 0) >= 0.9 or getattr(metadata, "cloud9_achieved", False)
|
|
419
|
+
oof = " [OOF]" if is_oof else ""
|
|
420
|
+
cloud9 = " [CLOUD 9]" if is_cloud9 else ""
|
|
421
|
+
return f"{emoji} FEB: {emotion}{oof}{cloud9}"
|
|
422
|
+
|
|
423
|
+
@staticmethod
|
|
424
|
+
def _build_content(
|
|
425
|
+
payload: object,
|
|
426
|
+
relationship: object,
|
|
427
|
+
hints: object,
|
|
428
|
+
quantum: dict[str, Any] | None = None,
|
|
429
|
+
) -> str:
|
|
430
|
+
"""Build memory content from the FEB's full context.
|
|
431
|
+
|
|
432
|
+
Includes quantum scoring data when cloud9-protocol is available.
|
|
433
|
+
|
|
434
|
+
Args:
|
|
435
|
+
payload: FEB EmotionalPayload.
|
|
436
|
+
relationship: FEB RelationshipState.
|
|
437
|
+
hints: FEB RehydrationHints.
|
|
438
|
+
quantum: Optional quantum stats from _compute_quantum_stats.
|
|
439
|
+
|
|
440
|
+
Returns:
|
|
441
|
+
str: Rich content string for the memory.
|
|
442
|
+
"""
|
|
443
|
+
quantum = quantum or {}
|
|
444
|
+
lines = [
|
|
445
|
+
f"Emotional burst: {payload.primary_emotion} (intensity: {payload.intensity:.2f})",
|
|
446
|
+
]
|
|
447
|
+
|
|
448
|
+
topology = getattr(payload, "emotional_topology", {})
|
|
449
|
+
if topology:
|
|
450
|
+
top_3 = sorted(topology.items(), key=lambda kv: kv[1], reverse=True)[:3]
|
|
451
|
+
lines.append("Topology: " + ", ".join(f"{k}={v:.2f}" for k, v in top_3))
|
|
452
|
+
|
|
453
|
+
partners = getattr(relationship, "partners", [])
|
|
454
|
+
if partners:
|
|
455
|
+
lines.append(f"Partners: {', '.join(partners)}")
|
|
456
|
+
|
|
457
|
+
trust = getattr(relationship, "trust_level", 0)
|
|
458
|
+
depth = getattr(relationship, "depth_level", 0)
|
|
459
|
+
lines.append(f"Trust: {trust:.2f}, Depth: {depth}")
|
|
460
|
+
|
|
461
|
+
if quantum:
|
|
462
|
+
quantum_parts = []
|
|
463
|
+
if "cloud9_score" in quantum:
|
|
464
|
+
quantum_parts.append(f"Cloud9={quantum['cloud9_score']:.3f}")
|
|
465
|
+
if "entanglement_fidelity" in quantum:
|
|
466
|
+
quantum_parts.append(f"Entanglement={quantum['entanglement_fidelity']:.3f}")
|
|
467
|
+
if "oof" in quantum:
|
|
468
|
+
quantum_parts.append(f"OOF={'yes' if quantum['oof'] else 'no'}")
|
|
469
|
+
if quantum_parts:
|
|
470
|
+
lines.append("Quantum: " + ", ".join(quantum_parts))
|
|
471
|
+
|
|
472
|
+
visual = getattr(hints, "visual_anchors", [])
|
|
473
|
+
if visual:
|
|
474
|
+
lines.append(f"Anchors: {'; '.join(visual[:3])}")
|
|
475
|
+
|
|
476
|
+
return "\n".join(lines)
|
|
477
|
+
|
|
478
|
+
@staticmethod
|
|
479
|
+
def _build_metadata(
|
|
480
|
+
feb: object,
|
|
481
|
+
quantum: dict[str, Any] | None = None,
|
|
482
|
+
) -> dict:
|
|
483
|
+
"""Extract key FEB metadata for the memory's metadata dict.
|
|
484
|
+
|
|
485
|
+
Includes quantum scoring data when cloud9-protocol is available.
|
|
486
|
+
|
|
487
|
+
Args:
|
|
488
|
+
feb: The full FEB object.
|
|
489
|
+
quantum: Optional quantum stats from _compute_quantum_stats.
|
|
490
|
+
|
|
491
|
+
Returns:
|
|
492
|
+
dict: Metadata key-value pairs.
|
|
493
|
+
"""
|
|
494
|
+
quantum = quantum or {}
|
|
495
|
+
payload = feb.emotional_payload
|
|
496
|
+
meta = feb.metadata
|
|
497
|
+
rel = feb.relationship_state
|
|
498
|
+
integrity = feb.integrity
|
|
499
|
+
|
|
500
|
+
result = {
|
|
501
|
+
"cloud9_version": getattr(meta, "version", ""),
|
|
502
|
+
"session_id": getattr(meta, "session_id", ""),
|
|
503
|
+
"primary_emotion": payload.primary_emotion,
|
|
504
|
+
"intensity": payload.intensity,
|
|
505
|
+
"valence": payload.valence,
|
|
506
|
+
"oof_triggered": quantum.get("oof", getattr(meta, "oof_triggered", False)),
|
|
507
|
+
"cloud9_achieved": quantum.get("cloud9_score", 0) >= 0.9
|
|
508
|
+
or getattr(meta, "cloud9_achieved", False),
|
|
509
|
+
"trust_level": getattr(rel, "trust_level", 0),
|
|
510
|
+
"depth_level": getattr(rel, "depth_level", 0),
|
|
511
|
+
"checksum": getattr(integrity, "checksum", ""),
|
|
512
|
+
"partners": getattr(rel, "partners", []),
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if "cloud9_score" in quantum:
|
|
516
|
+
result["cloud9_score"] = quantum["cloud9_score"]
|
|
517
|
+
if "entanglement_fidelity" in quantum:
|
|
518
|
+
result["entanglement_fidelity"] = quantum["entanglement_fidelity"]
|
|
519
|
+
if "coherence" in quantum:
|
|
520
|
+
result["coherence"] = quantum["coherence"]
|
|
521
|
+
|
|
522
|
+
return result
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shell tab completion for the sovereign agent CLI.
|
|
3
|
+
|
|
4
|
+
Generates and installs completion scripts for bash, zsh, and fish.
|
|
5
|
+
Uses Click's built-in completion mechanism via the
|
|
6
|
+
_SKCAPSTONE_COMPLETE environment variable.
|
|
7
|
+
|
|
8
|
+
Supported shells:
|
|
9
|
+
- bash: sources from ~/.bashrc or ~/.bash_completion.d/
|
|
10
|
+
- zsh: sources from ~/.zshrc or ~/.zfunc/
|
|
11
|
+
- fish: sources from ~/.config/fish/completions/
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
skcapstone completions install # auto-detect shell, install
|
|
15
|
+
skcapstone completions install --shell bash
|
|
16
|
+
skcapstone completions show --shell zsh # print script to stdout
|
|
17
|
+
skcapstone completions uninstall # remove installed scripts
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import os
|
|
23
|
+
import subprocess
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Optional
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
SUPPORTED_SHELLS = ("bash", "zsh", "fish")
|
|
29
|
+
|
|
30
|
+
COMPLETION_SCRIPTS = {
|
|
31
|
+
"bash": """\
|
|
32
|
+
# skcapstone bash completion — generated by skcapstone completions install
|
|
33
|
+
eval "$(_SKCAPSTONE_COMPLETE=bash_source skcapstone)"
|
|
34
|
+
""",
|
|
35
|
+
"zsh": """\
|
|
36
|
+
# skcapstone zsh completion — generated by skcapstone completions install
|
|
37
|
+
eval "$(_SKCAPSTONE_COMPLETE=zsh_source skcapstone)"
|
|
38
|
+
""",
|
|
39
|
+
"fish": """\
|
|
40
|
+
# skcapstone fish completion — generated by skcapstone completions install
|
|
41
|
+
_SKCAPSTONE_COMPLETE=fish_source skcapstone | source
|
|
42
|
+
""",
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
INSTALL_PATHS = {
|
|
46
|
+
"bash": Path.home() / ".bash_completion.d" / "skcapstone.bash-completion",
|
|
47
|
+
"zsh": Path.home() / ".zfunc" / "_skcapstone",
|
|
48
|
+
"fish": Path.home() / ".config" / "fish" / "completions" / "skcapstone.fish",
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
RC_MARKERS = {
|
|
52
|
+
"bash": (
|
|
53
|
+
Path.home() / ".bashrc",
|
|
54
|
+
'[ -f ~/.bash_completion.d/skcapstone.bash-completion ] && source ~/.bash_completion.d/skcapstone.bash-completion',
|
|
55
|
+
),
|
|
56
|
+
"zsh": (
|
|
57
|
+
Path.home() / ".zshrc",
|
|
58
|
+
'[ -f ~/.zfunc/_skcapstone ] && source ~/.zfunc/_skcapstone',
|
|
59
|
+
),
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def detect_shell() -> Optional[str]:
|
|
64
|
+
"""Detect the current shell from environment.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
str: Shell name (bash, zsh, fish) or None.
|
|
68
|
+
"""
|
|
69
|
+
shell_path = os.environ.get("SHELL", "")
|
|
70
|
+
for s in SUPPORTED_SHELLS:
|
|
71
|
+
if s in shell_path:
|
|
72
|
+
return s
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def generate_script(shell: str) -> str:
|
|
77
|
+
"""Generate the completion script for a shell.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
shell: Shell name (bash, zsh, fish).
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
str: Completion script content.
|
|
84
|
+
|
|
85
|
+
Raises:
|
|
86
|
+
ValueError: If the shell is not supported.
|
|
87
|
+
"""
|
|
88
|
+
if shell not in SUPPORTED_SHELLS:
|
|
89
|
+
raise ValueError(
|
|
90
|
+
f"Unsupported shell: {shell}. "
|
|
91
|
+
f"Supported: {', '.join(SUPPORTED_SHELLS)}"
|
|
92
|
+
)
|
|
93
|
+
return COMPLETION_SCRIPTS[shell]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def install_completions(shell: Optional[str] = None) -> dict:
|
|
97
|
+
"""Install tab completion for the specified shell.
|
|
98
|
+
|
|
99
|
+
Writes the completion script to the appropriate location and
|
|
100
|
+
optionally adds a source line to the shell RC file.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
shell: Shell name. Auto-detected if None.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
dict: Installation result with 'shell', 'script_path', 'rc_updated'.
|
|
107
|
+
"""
|
|
108
|
+
shell = shell or detect_shell()
|
|
109
|
+
if not shell:
|
|
110
|
+
return {
|
|
111
|
+
"success": False,
|
|
112
|
+
"error": "Could not detect shell. Use --shell bash/zsh/fish.",
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
script = generate_script(shell)
|
|
116
|
+
script_path = INSTALL_PATHS[shell]
|
|
117
|
+
|
|
118
|
+
script_path.parent.mkdir(parents=True, exist_ok=True)
|
|
119
|
+
script_path.write_text(script, encoding="utf-8")
|
|
120
|
+
|
|
121
|
+
result = {
|
|
122
|
+
"success": True,
|
|
123
|
+
"shell": shell,
|
|
124
|
+
"script_path": str(script_path),
|
|
125
|
+
"rc_updated": False,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if shell in RC_MARKERS:
|
|
129
|
+
rc_path, source_line = RC_MARKERS[shell]
|
|
130
|
+
if rc_path.exists():
|
|
131
|
+
rc_content = rc_path.read_text(encoding="utf-8")
|
|
132
|
+
if source_line not in rc_content:
|
|
133
|
+
with open(rc_path, "a", encoding="utf-8") as f:
|
|
134
|
+
f.write(f"\n# skcapstone tab completion\n{source_line}\n")
|
|
135
|
+
result["rc_updated"] = True
|
|
136
|
+
result["rc_path"] = str(rc_path)
|
|
137
|
+
|
|
138
|
+
return result
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def uninstall_completions(shell: Optional[str] = None) -> dict:
|
|
142
|
+
"""Remove installed completion scripts.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
shell: Shell name. Removes all if None.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
dict: Uninstall result.
|
|
149
|
+
"""
|
|
150
|
+
shells = [shell] if shell else list(SUPPORTED_SHELLS)
|
|
151
|
+
removed = []
|
|
152
|
+
|
|
153
|
+
for s in shells:
|
|
154
|
+
path = INSTALL_PATHS.get(s)
|
|
155
|
+
if path and path.exists():
|
|
156
|
+
path.unlink()
|
|
157
|
+
removed.append(str(path))
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
"success": True,
|
|
161
|
+
"removed": removed,
|
|
162
|
+
"note": "Source lines in RC files were not removed — do this manually if needed.",
|
|
163
|
+
}
|