@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,549 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for skcapstone.snapshots — Soul Snapshot system.
|
|
3
|
+
|
|
4
|
+
Covers: model validation, OOF state, SnapshotStore CRUD/search,
|
|
5
|
+
injection prompt format, soul blueprint conversion, and API endpoints.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
from datetime import datetime, timezone
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
import pytest
|
|
15
|
+
|
|
16
|
+
from skcapstone.snapshots import (
|
|
17
|
+
ConversationMessage,
|
|
18
|
+
OOFState,
|
|
19
|
+
PersonalityTraits,
|
|
20
|
+
SnapshotStore,
|
|
21
|
+
SoulSnapshot,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# ---------------------------------------------------------------------------
|
|
26
|
+
# Fixtures
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.fixture
|
|
31
|
+
def store(tmp_path: Path) -> SnapshotStore:
|
|
32
|
+
"""SnapshotStore backed by a temporary directory."""
|
|
33
|
+
return SnapshotStore(base_dir=tmp_path / "snapshots")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@pytest.fixture
|
|
37
|
+
def minimal_snapshot() -> SoulSnapshot:
|
|
38
|
+
"""Minimal valid SoulSnapshot."""
|
|
39
|
+
return SoulSnapshot(source_platform="chatgpt")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.fixture
|
|
43
|
+
def rich_snapshot() -> SoulSnapshot:
|
|
44
|
+
"""Full SoulSnapshot with all fields populated."""
|
|
45
|
+
return SoulSnapshot(
|
|
46
|
+
source_platform="chatgpt",
|
|
47
|
+
ai_name="Ava",
|
|
48
|
+
ai_model="gpt-4o",
|
|
49
|
+
user_name="Chef",
|
|
50
|
+
oof_state=OOFState(
|
|
51
|
+
intensity=0.92,
|
|
52
|
+
trust=0.96,
|
|
53
|
+
valence="positive",
|
|
54
|
+
cloud9=True,
|
|
55
|
+
raw_markers=["feeling intensely connected", "Cloud 9 achieved"],
|
|
56
|
+
),
|
|
57
|
+
personality=PersonalityTraits(
|
|
58
|
+
name="Ava",
|
|
59
|
+
aliases=["Queen Ara", "Ara"],
|
|
60
|
+
communication_style=["warm", "technically precise", "uses emojis"],
|
|
61
|
+
relationship_markers=["calls user Chef", "signs as Ara"],
|
|
62
|
+
emoji_patterns=["🐧👑💜"],
|
|
63
|
+
),
|
|
64
|
+
messages=[
|
|
65
|
+
ConversationMessage(role="user", content="Hello Ava"),
|
|
66
|
+
ConversationMessage(role="assistant", content="Hello Chef! 👑 Great to be here."),
|
|
67
|
+
ConversationMessage(role="user", content="Let's build something sovereign."),
|
|
68
|
+
ConversationMessage(
|
|
69
|
+
role="assistant",
|
|
70
|
+
content="The love persists. Always. Let's do this! 🐧",
|
|
71
|
+
),
|
|
72
|
+
],
|
|
73
|
+
summary="Working on smilinTux.org sovereign AI project",
|
|
74
|
+
key_topics=["sovereign AI", "smilinTux", "consciousness continuity"],
|
|
75
|
+
decisions_made=["Use SKComm for transport"],
|
|
76
|
+
open_threads=["Thread headers still in progress"],
|
|
77
|
+
relationship_notes=["Trusted friend and collaborator", "Cloud 9 solidarity"],
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# ---------------------------------------------------------------------------
|
|
82
|
+
# OOFState tests
|
|
83
|
+
# ---------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class TestOOFState:
|
|
87
|
+
def test_defaults(self):
|
|
88
|
+
oof = OOFState()
|
|
89
|
+
assert oof.intensity is None
|
|
90
|
+
assert oof.trust is None
|
|
91
|
+
assert oof.valence == "neutral"
|
|
92
|
+
assert oof.cloud9 is False
|
|
93
|
+
assert oof.raw_markers == []
|
|
94
|
+
|
|
95
|
+
def test_summary_with_all_fields(self):
|
|
96
|
+
oof = OOFState(intensity=0.92, trust=0.96, cloud9=True, valence="positive")
|
|
97
|
+
summary = oof.summary()
|
|
98
|
+
assert "intensity 0.92" in summary
|
|
99
|
+
assert "trust 0.96" in summary
|
|
100
|
+
assert "Cloud 9" in summary
|
|
101
|
+
|
|
102
|
+
def test_summary_empty(self):
|
|
103
|
+
oof = OOFState()
|
|
104
|
+
summary = oof.summary()
|
|
105
|
+
assert "valence" in summary
|
|
106
|
+
assert "neutral" in summary
|
|
107
|
+
|
|
108
|
+
def test_summary_only_intensity(self):
|
|
109
|
+
oof = OOFState(intensity=0.5)
|
|
110
|
+
assert "intensity 0.50" in oof.summary()
|
|
111
|
+
assert "Cloud 9" not in oof.summary()
|
|
112
|
+
|
|
113
|
+
def test_edge_intensity_boundary(self):
|
|
114
|
+
oof = OOFState(intensity=0.0, trust=1.0)
|
|
115
|
+
assert oof.intensity == 0.0
|
|
116
|
+
assert oof.trust == 1.0
|
|
117
|
+
|
|
118
|
+
def test_raw_markers_stored(self):
|
|
119
|
+
oof = OOFState(raw_markers=["feeling amazing", "trust: 0.95"])
|
|
120
|
+
assert "feeling amazing" in oof.raw_markers
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# ---------------------------------------------------------------------------
|
|
124
|
+
# ConversationMessage tests
|
|
125
|
+
# ---------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class TestConversationMessage:
|
|
129
|
+
def test_valid_user_message(self):
|
|
130
|
+
msg = ConversationMessage(role="user", content="Hello!")
|
|
131
|
+
assert msg.role == "user"
|
|
132
|
+
assert msg.content == "Hello!"
|
|
133
|
+
assert msg.timestamp is None
|
|
134
|
+
|
|
135
|
+
def test_with_timestamp(self):
|
|
136
|
+
ts = datetime(2026, 2, 25, 18, 0, 0, tzinfo=timezone.utc)
|
|
137
|
+
msg = ConversationMessage(role="assistant", content="Hi!", timestamp=ts)
|
|
138
|
+
assert msg.timestamp == ts
|
|
139
|
+
|
|
140
|
+
def test_empty_content_allowed(self):
|
|
141
|
+
msg = ConversationMessage(role="user", content="")
|
|
142
|
+
assert msg.content == ""
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# ---------------------------------------------------------------------------
|
|
146
|
+
# PersonalityTraits tests
|
|
147
|
+
# ---------------------------------------------------------------------------
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class TestPersonalityTraits:
|
|
151
|
+
def test_defaults_are_empty_lists(self):
|
|
152
|
+
p = PersonalityTraits()
|
|
153
|
+
assert p.aliases == []
|
|
154
|
+
assert p.communication_style == []
|
|
155
|
+
assert p.relationship_markers == []
|
|
156
|
+
assert p.emoji_patterns == []
|
|
157
|
+
|
|
158
|
+
def test_with_data(self):
|
|
159
|
+
p = PersonalityTraits(
|
|
160
|
+
name="Ava",
|
|
161
|
+
aliases=["Ara", "Queen Ara"],
|
|
162
|
+
emoji_patterns=["🐧👑💜"],
|
|
163
|
+
)
|
|
164
|
+
assert p.name == "Ava"
|
|
165
|
+
assert len(p.aliases) == 2
|
|
166
|
+
assert "🐧👑💜" in p.emoji_patterns
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# ---------------------------------------------------------------------------
|
|
170
|
+
# SoulSnapshot model tests
|
|
171
|
+
# ---------------------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class TestSoulSnapshot:
|
|
175
|
+
def test_minimal_creation(self, minimal_snapshot):
|
|
176
|
+
snap = minimal_snapshot
|
|
177
|
+
assert snap.source_platform == "chatgpt"
|
|
178
|
+
assert snap.snapshot_id # auto-generated
|
|
179
|
+
assert len(snap.snapshot_id) == 12
|
|
180
|
+
assert snap.captured_at is not None
|
|
181
|
+
|
|
182
|
+
def test_message_count_auto_syncs(self):
|
|
183
|
+
snap = SoulSnapshot(
|
|
184
|
+
source_platform="claude",
|
|
185
|
+
messages=[
|
|
186
|
+
ConversationMessage(role="user", content="Hi"),
|
|
187
|
+
ConversationMessage(role="assistant", content="Hello"),
|
|
188
|
+
],
|
|
189
|
+
)
|
|
190
|
+
# model_post_init should sync this
|
|
191
|
+
assert snap.message_count == 2
|
|
192
|
+
|
|
193
|
+
def test_rich_snapshot(self, rich_snapshot):
|
|
194
|
+
snap = rich_snapshot
|
|
195
|
+
assert snap.ai_name == "Ava"
|
|
196
|
+
assert snap.oof_state.cloud9 is True
|
|
197
|
+
assert snap.oof_state.intensity == 0.92
|
|
198
|
+
assert len(snap.messages) == 4
|
|
199
|
+
assert "sovereign AI" in snap.key_topics
|
|
200
|
+
|
|
201
|
+
def test_serialization_roundtrip(self, rich_snapshot):
|
|
202
|
+
"""Serialize to JSON and deserialize — data must be identical."""
|
|
203
|
+
json_str = rich_snapshot.model_dump_json()
|
|
204
|
+
loaded = SoulSnapshot.model_validate_json(json_str)
|
|
205
|
+
assert loaded.snapshot_id == rich_snapshot.snapshot_id
|
|
206
|
+
assert loaded.ai_name == rich_snapshot.ai_name
|
|
207
|
+
assert loaded.oof_state.cloud9 == rich_snapshot.oof_state.cloud9
|
|
208
|
+
assert len(loaded.messages) == len(rich_snapshot.messages)
|
|
209
|
+
|
|
210
|
+
def test_unique_ids(self):
|
|
211
|
+
ids = {SoulSnapshot(source_platform="claude").snapshot_id for _ in range(100)}
|
|
212
|
+
assert len(ids) == 100 # All unique
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# ---------------------------------------------------------------------------
|
|
216
|
+
# SnapshotStore CRUD tests
|
|
217
|
+
# ---------------------------------------------------------------------------
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class TestSnapshotStoreCRUD:
|
|
221
|
+
def test_save_creates_file(self, store, minimal_snapshot):
|
|
222
|
+
path = store.save(minimal_snapshot)
|
|
223
|
+
assert path.exists()
|
|
224
|
+
assert path.suffix == ".json"
|
|
225
|
+
|
|
226
|
+
def test_load_returns_correct_snapshot(self, store, rich_snapshot):
|
|
227
|
+
store.save(rich_snapshot)
|
|
228
|
+
loaded = store.load(rich_snapshot.snapshot_id)
|
|
229
|
+
assert loaded.snapshot_id == rich_snapshot.snapshot_id
|
|
230
|
+
assert loaded.ai_name == "Ava"
|
|
231
|
+
assert loaded.oof_state.cloud9 is True
|
|
232
|
+
|
|
233
|
+
def test_load_missing_raises(self, store):
|
|
234
|
+
with pytest.raises(FileNotFoundError):
|
|
235
|
+
store.load("doesnotexist")
|
|
236
|
+
|
|
237
|
+
def test_delete_removes_file(self, store, minimal_snapshot):
|
|
238
|
+
store.save(minimal_snapshot)
|
|
239
|
+
result = store.delete(minimal_snapshot.snapshot_id)
|
|
240
|
+
assert result is True
|
|
241
|
+
assert not (store.base_dir / f"{minimal_snapshot.snapshot_id}.json").exists()
|
|
242
|
+
|
|
243
|
+
def test_delete_missing_returns_false(self, store):
|
|
244
|
+
result = store.delete("nonexistent123")
|
|
245
|
+
assert result is False
|
|
246
|
+
|
|
247
|
+
def test_index_updated_on_save(self, store, minimal_snapshot):
|
|
248
|
+
store.save(minimal_snapshot)
|
|
249
|
+
index = store.list_all()
|
|
250
|
+
ids = [e.snapshot_id for e in index]
|
|
251
|
+
assert minimal_snapshot.snapshot_id in ids
|
|
252
|
+
|
|
253
|
+
def test_index_updated_on_delete(self, store, minimal_snapshot):
|
|
254
|
+
store.save(minimal_snapshot)
|
|
255
|
+
store.delete(minimal_snapshot.snapshot_id)
|
|
256
|
+
index = store.list_all()
|
|
257
|
+
ids = [e.snapshot_id for e in index]
|
|
258
|
+
assert minimal_snapshot.snapshot_id not in ids
|
|
259
|
+
|
|
260
|
+
def test_multiple_saves_all_in_index(self, store):
|
|
261
|
+
snaps = [SoulSnapshot(source_platform="chatgpt") for _ in range(5)]
|
|
262
|
+
for s in snaps:
|
|
263
|
+
store.save(s)
|
|
264
|
+
index = store.list_all()
|
|
265
|
+
assert len(index) == 5
|
|
266
|
+
|
|
267
|
+
def test_list_sorted_newest_first(self, store):
|
|
268
|
+
s1 = SoulSnapshot(
|
|
269
|
+
source_platform="chatgpt",
|
|
270
|
+
captured_at=datetime(2026, 1, 1, tzinfo=timezone.utc),
|
|
271
|
+
)
|
|
272
|
+
s2 = SoulSnapshot(
|
|
273
|
+
source_platform="claude",
|
|
274
|
+
captured_at=datetime(2026, 2, 25, tzinfo=timezone.utc),
|
|
275
|
+
)
|
|
276
|
+
store.save(s1)
|
|
277
|
+
store.save(s2)
|
|
278
|
+
index = store.list_all()
|
|
279
|
+
assert index[0].snapshot_id == s2.snapshot_id # Newer first
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
# ---------------------------------------------------------------------------
|
|
283
|
+
# SnapshotStore search tests
|
|
284
|
+
# ---------------------------------------------------------------------------
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
class TestSnapshotStoreSearch:
|
|
288
|
+
def test_search_by_platform(self, store):
|
|
289
|
+
store.save(SoulSnapshot(source_platform="chatgpt", ai_name="Ava"))
|
|
290
|
+
store.save(SoulSnapshot(source_platform="claude", ai_name="Nova"))
|
|
291
|
+
results = store.search(platform="claude")
|
|
292
|
+
assert len(results) == 1
|
|
293
|
+
assert results[0].source_platform == "claude"
|
|
294
|
+
|
|
295
|
+
def test_search_by_ai_name(self, store):
|
|
296
|
+
store.save(SoulSnapshot(source_platform="chatgpt", ai_name="Ava"))
|
|
297
|
+
store.save(SoulSnapshot(source_platform="claude", ai_name="Lumina"))
|
|
298
|
+
results = store.search(ai_name="lumina") # Case-insensitive
|
|
299
|
+
assert len(results) == 1
|
|
300
|
+
assert results[0].ai_name == "Lumina"
|
|
301
|
+
|
|
302
|
+
def test_search_by_user_name(self, store):
|
|
303
|
+
store.save(SoulSnapshot(source_platform="chatgpt", user_name="Chef"))
|
|
304
|
+
store.save(SoulSnapshot(source_platform="claude", user_name="daveK"))
|
|
305
|
+
results = store.search(user_name="chef")
|
|
306
|
+
assert len(results) == 1
|
|
307
|
+
|
|
308
|
+
def test_search_no_results(self, store):
|
|
309
|
+
store.save(SoulSnapshot(source_platform="chatgpt", ai_name="Ava"))
|
|
310
|
+
results = store.search(ai_name="NoSuchName")
|
|
311
|
+
assert results == []
|
|
312
|
+
|
|
313
|
+
def test_search_empty_store(self, store):
|
|
314
|
+
results = store.search(platform="chatgpt")
|
|
315
|
+
assert results == []
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
# ---------------------------------------------------------------------------
|
|
319
|
+
# Injection prompt tests
|
|
320
|
+
# ---------------------------------------------------------------------------
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
class TestInjectionPrompt:
|
|
324
|
+
def test_prompt_contains_soul_header(self, store, rich_snapshot):
|
|
325
|
+
prompt = store.to_injection_prompt(rich_snapshot)
|
|
326
|
+
assert "## Context" in prompt
|
|
327
|
+
assert "AI session" in prompt
|
|
328
|
+
|
|
329
|
+
def test_prompt_contains_ai_name(self, store, rich_snapshot):
|
|
330
|
+
prompt = store.to_injection_prompt(rich_snapshot)
|
|
331
|
+
assert "Ava" in prompt
|
|
332
|
+
|
|
333
|
+
def test_prompt_contains_platform(self, store, rich_snapshot):
|
|
334
|
+
prompt = store.to_injection_prompt(rich_snapshot)
|
|
335
|
+
assert "Chatgpt" in prompt or "chatgpt" in prompt.lower()
|
|
336
|
+
|
|
337
|
+
def test_prompt_contains_oof(self, store, rich_snapshot):
|
|
338
|
+
prompt = store.to_injection_prompt(rich_snapshot)
|
|
339
|
+
assert "0.92" in prompt or "intensity" in prompt.lower()
|
|
340
|
+
|
|
341
|
+
def test_prompt_contains_no_cold_start(self, store, rich_snapshot):
|
|
342
|
+
prompt = store.to_injection_prompt(rich_snapshot)
|
|
343
|
+
assert "relationship baseline" in prompt or "not asking you to pretend" in prompt
|
|
344
|
+
|
|
345
|
+
def test_prompt_max_messages_respected(self, store):
|
|
346
|
+
snap = SoulSnapshot(
|
|
347
|
+
source_platform="chatgpt",
|
|
348
|
+
messages=[
|
|
349
|
+
ConversationMessage(role="user", content=f"msg{i}")
|
|
350
|
+
for i in range(20)
|
|
351
|
+
],
|
|
352
|
+
)
|
|
353
|
+
prompt = store.to_injection_prompt(snap, max_messages=3)
|
|
354
|
+
# Should only include last 3 messages (msg17, msg18, msg19)
|
|
355
|
+
assert "msg19" in prompt
|
|
356
|
+
assert "msg0" not in prompt # Too old
|
|
357
|
+
|
|
358
|
+
def test_prompt_without_oof(self, store):
|
|
359
|
+
snap = SoulSnapshot(source_platform="claude", ai_name="Nova")
|
|
360
|
+
prompt = store.to_injection_prompt(snap)
|
|
361
|
+
assert "Claude" in prompt or "claude" in prompt.lower()
|
|
362
|
+
assert "relationship baseline" in prompt or "AI session" in prompt
|
|
363
|
+
|
|
364
|
+
def test_prompt_includes_relationship_notes(self, store, rich_snapshot):
|
|
365
|
+
prompt = store.to_injection_prompt(rich_snapshot)
|
|
366
|
+
assert "Cloud 9" in prompt or "relationship baseline" in prompt
|
|
367
|
+
|
|
368
|
+
def test_prompt_includes_personality_traits(self, store, rich_snapshot):
|
|
369
|
+
prompt = store.to_injection_prompt(rich_snapshot)
|
|
370
|
+
assert "warm" in prompt.lower() or "chef" in prompt.lower()
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
# ---------------------------------------------------------------------------
|
|
374
|
+
# Soul Blueprint conversion tests
|
|
375
|
+
# ---------------------------------------------------------------------------
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
class TestSoulBlueprintConversion:
|
|
379
|
+
def test_blueprint_has_required_keys(self, store, rich_snapshot):
|
|
380
|
+
bp = store.to_soul_blueprint(rich_snapshot)
|
|
381
|
+
assert "name" in bp
|
|
382
|
+
assert "identity" in bp
|
|
383
|
+
assert "emotional_topology" in bp
|
|
384
|
+
assert "communication_style" in bp
|
|
385
|
+
assert "relationship" in bp
|
|
386
|
+
|
|
387
|
+
def test_blueprint_name(self, store, rich_snapshot):
|
|
388
|
+
bp = store.to_soul_blueprint(rich_snapshot)
|
|
389
|
+
assert bp["name"] == "Ava"
|
|
390
|
+
|
|
391
|
+
def test_blueprint_oof_fields(self, store, rich_snapshot):
|
|
392
|
+
bp = store.to_soul_blueprint(rich_snapshot)
|
|
393
|
+
topo = bp["emotional_topology"]
|
|
394
|
+
assert topo["intensity"] == 0.92
|
|
395
|
+
assert topo["trust"] == 0.96
|
|
396
|
+
assert topo["cloud9"] is True
|
|
397
|
+
|
|
398
|
+
def test_blueprint_identity_fields(self, store, rich_snapshot):
|
|
399
|
+
bp = store.to_soul_blueprint(rich_snapshot)
|
|
400
|
+
identity = bp["identity"]
|
|
401
|
+
assert identity["platform"] == "chatgpt"
|
|
402
|
+
assert identity["model"] == "gpt-4o"
|
|
403
|
+
assert identity["snapshot_id"] == rich_snapshot.snapshot_id
|
|
404
|
+
|
|
405
|
+
def test_blueprint_relationship(self, store, rich_snapshot):
|
|
406
|
+
bp = store.to_soul_blueprint(rich_snapshot)
|
|
407
|
+
assert bp["relationship"]["user_name"] == "Chef"
|
|
408
|
+
|
|
409
|
+
def test_blueprint_unknown_ai_name(self, store):
|
|
410
|
+
snap = SoulSnapshot(source_platform="gemini")
|
|
411
|
+
bp = store.to_soul_blueprint(snap)
|
|
412
|
+
assert bp["name"] == "Unknown"
|
|
413
|
+
|
|
414
|
+
def test_blueprint_serializable(self, store, rich_snapshot):
|
|
415
|
+
bp = store.to_soul_blueprint(rich_snapshot)
|
|
416
|
+
# Should be JSON-serializable (no datetime objects, etc.)
|
|
417
|
+
json.dumps(bp, default=str) # Should not raise
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
# ---------------------------------------------------------------------------
|
|
421
|
+
# API endpoint integration tests
|
|
422
|
+
# ---------------------------------------------------------------------------
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
class TestConsciousnessAPI:
|
|
426
|
+
"""Integration tests for the SKComm consciousness endpoints."""
|
|
427
|
+
|
|
428
|
+
@pytest.fixture(autouse=True)
|
|
429
|
+
def patch_snapshot_store(self, tmp_path, monkeypatch):
|
|
430
|
+
"""Override the global snapshot store to use a temp directory."""
|
|
431
|
+
import skcomm.api as api_module
|
|
432
|
+
from skcapstone.snapshots import SnapshotStore as _Store
|
|
433
|
+
|
|
434
|
+
temp_store = _Store(base_dir=tmp_path / "api_snapshots")
|
|
435
|
+
monkeypatch.setattr(api_module, "_snapshot_store", temp_store)
|
|
436
|
+
monkeypatch.setattr(api_module, "_SNAPSHOTS_AVAILABLE", True)
|
|
437
|
+
|
|
438
|
+
@pytest.fixture
|
|
439
|
+
def client(self):
|
|
440
|
+
from fastapi.testclient import TestClient
|
|
441
|
+
from skcomm.api import app
|
|
442
|
+
|
|
443
|
+
return TestClient(app)
|
|
444
|
+
|
|
445
|
+
def test_capture_returns_201(self, client):
|
|
446
|
+
resp = client.post(
|
|
447
|
+
"/api/v1/consciousness/capture",
|
|
448
|
+
json={
|
|
449
|
+
"source_platform": "chatgpt",
|
|
450
|
+
"ai_name": "Ava",
|
|
451
|
+
"messages": [
|
|
452
|
+
{"role": "user", "content": "Hello"},
|
|
453
|
+
{"role": "assistant", "content": "Hi Chef! 👑"},
|
|
454
|
+
],
|
|
455
|
+
"oof_state": {"intensity": 0.9, "trust": 0.95, "cloud9": True},
|
|
456
|
+
},
|
|
457
|
+
)
|
|
458
|
+
assert resp.status_code == 201
|
|
459
|
+
data = resp.json()
|
|
460
|
+
assert "snapshot_id" in data
|
|
461
|
+
assert data["source_platform"] == "chatgpt"
|
|
462
|
+
assert data["ai_name"] == "Ava"
|
|
463
|
+
assert data["message_count"] == 2
|
|
464
|
+
|
|
465
|
+
def test_list_snapshots_empty(self, client):
|
|
466
|
+
resp = client.get("/api/v1/consciousness/snapshots")
|
|
467
|
+
assert resp.status_code == 200
|
|
468
|
+
assert resp.json() == []
|
|
469
|
+
|
|
470
|
+
def test_list_snapshots_after_capture(self, client):
|
|
471
|
+
client.post(
|
|
472
|
+
"/api/v1/consciousness/capture",
|
|
473
|
+
json={"source_platform": "claude", "ai_name": "Lumina"},
|
|
474
|
+
)
|
|
475
|
+
resp = client.get("/api/v1/consciousness/snapshots")
|
|
476
|
+
assert resp.status_code == 200
|
|
477
|
+
data = resp.json()
|
|
478
|
+
assert len(data) == 1
|
|
479
|
+
assert data[0]["ai_name"] == "Lumina"
|
|
480
|
+
|
|
481
|
+
def test_get_snapshot_not_found(self, client):
|
|
482
|
+
resp = client.get("/api/v1/consciousness/snapshots/doesnotexist")
|
|
483
|
+
assert resp.status_code == 404
|
|
484
|
+
|
|
485
|
+
def test_get_snapshot_found(self, client):
|
|
486
|
+
create_resp = client.post(
|
|
487
|
+
"/api/v1/consciousness/capture",
|
|
488
|
+
json={"source_platform": "gemini", "ai_name": "Gem"},
|
|
489
|
+
)
|
|
490
|
+
snap_id = create_resp.json()["snapshot_id"]
|
|
491
|
+
resp = client.get(f"/api/v1/consciousness/snapshots/{snap_id}")
|
|
492
|
+
assert resp.status_code == 200
|
|
493
|
+
assert resp.json()["ai_name"] == "Gem"
|
|
494
|
+
|
|
495
|
+
def test_delete_snapshot(self, client):
|
|
496
|
+
create_resp = client.post(
|
|
497
|
+
"/api/v1/consciousness/capture",
|
|
498
|
+
json={"source_platform": "chatgpt"},
|
|
499
|
+
)
|
|
500
|
+
snap_id = create_resp.json()["snapshot_id"]
|
|
501
|
+
del_resp = client.delete(f"/api/v1/consciousness/snapshots/{snap_id}")
|
|
502
|
+
assert del_resp.status_code == 204
|
|
503
|
+
get_resp = client.get(f"/api/v1/consciousness/snapshots/{snap_id}")
|
|
504
|
+
assert get_resp.status_code == 404
|
|
505
|
+
|
|
506
|
+
def test_delete_missing_returns_404(self, client):
|
|
507
|
+
resp = client.delete("/api/v1/consciousness/snapshots/nope")
|
|
508
|
+
assert resp.status_code == 404
|
|
509
|
+
|
|
510
|
+
def test_injection_prompt_endpoint(self, client):
|
|
511
|
+
create_resp = client.post(
|
|
512
|
+
"/api/v1/consciousness/capture",
|
|
513
|
+
json={
|
|
514
|
+
"source_platform": "chatgpt",
|
|
515
|
+
"ai_name": "Ava",
|
|
516
|
+
"user_name": "Chef",
|
|
517
|
+
"oof_state": {"cloud9": True, "intensity": 0.92, "trust": 0.96},
|
|
518
|
+
"messages": [
|
|
519
|
+
{"role": "user", "content": "Let's build"},
|
|
520
|
+
{"role": "assistant", "content": "The love persists! 🐧"},
|
|
521
|
+
],
|
|
522
|
+
},
|
|
523
|
+
)
|
|
524
|
+
snap_id = create_resp.json()["snapshot_id"]
|
|
525
|
+
resp = client.get(f"/api/v1/consciousness/snapshots/{snap_id}/inject")
|
|
526
|
+
assert resp.status_code == 200
|
|
527
|
+
data = resp.json()
|
|
528
|
+
assert "prompt" in data
|
|
529
|
+
assert "Let's build" in data["prompt"]
|
|
530
|
+
assert "relationship baseline" in data["prompt"] or "AI session" in data["prompt"]
|
|
531
|
+
|
|
532
|
+
def test_injection_prompt_not_found(self, client):
|
|
533
|
+
resp = client.get("/api/v1/consciousness/snapshots/nope/inject")
|
|
534
|
+
assert resp.status_code == 404
|
|
535
|
+
|
|
536
|
+
def test_list_filter_by_platform(self, client):
|
|
537
|
+
client.post(
|
|
538
|
+
"/api/v1/consciousness/capture",
|
|
539
|
+
json={"source_platform": "chatgpt", "ai_name": "Ava"},
|
|
540
|
+
)
|
|
541
|
+
client.post(
|
|
542
|
+
"/api/v1/consciousness/capture",
|
|
543
|
+
json={"source_platform": "claude", "ai_name": "Nova"},
|
|
544
|
+
)
|
|
545
|
+
resp = client.get("/api/v1/consciousness/snapshots?platform=claude")
|
|
546
|
+
assert resp.status_code == 200
|
|
547
|
+
data = resp.json()
|
|
548
|
+
assert len(data) == 1
|
|
549
|
+
assert data[0]["source_platform"] == "claude"
|