@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,230 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
SKCapstone Bundle Update Checker
|
|
4
|
+
Checks for updates to all SK packages and reports status
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
import json
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
# Package configuration
|
|
14
|
+
PACKAGES = {
|
|
15
|
+
"skcapstone": {
|
|
16
|
+
"name": "skcapstone",
|
|
17
|
+
"path": "~/clawd/skcapstone",
|
|
18
|
+
"pypi_name": "skcapstone",
|
|
19
|
+
},
|
|
20
|
+
"skmemory": {
|
|
21
|
+
"name": "skmemory",
|
|
22
|
+
"path": "~/clawd/skcapstone-repos/skmemory",
|
|
23
|
+
"pypi_name": "skmemory",
|
|
24
|
+
},
|
|
25
|
+
"sksecurity": {
|
|
26
|
+
"name": "sksecurity",
|
|
27
|
+
"path": "~/clawd/skcapstone-repos/sksecurity",
|
|
28
|
+
"pypi_name": "sksecurity",
|
|
29
|
+
},
|
|
30
|
+
"cloud9-protocol": {
|
|
31
|
+
"name": "cloud9-protocol",
|
|
32
|
+
"path": "~/clawd/skcapstone-repos/cloud9-python",
|
|
33
|
+
"pypi_name": "cloud9-protocol",
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_installed_version(package_name):
|
|
39
|
+
"""Get currently installed version of a package."""
|
|
40
|
+
try:
|
|
41
|
+
result = subprocess.run(
|
|
42
|
+
[sys.executable, "-m", "pip", "show", package_name],
|
|
43
|
+
capture_output=True,
|
|
44
|
+
text=True,
|
|
45
|
+
check=True,
|
|
46
|
+
)
|
|
47
|
+
for line in result.stdout.split("\n"):
|
|
48
|
+
if line.startswith("Version:"):
|
|
49
|
+
return line.split(":")[1].strip()
|
|
50
|
+
except subprocess.CalledProcessError:
|
|
51
|
+
return None
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_latest_version(package_name):
|
|
56
|
+
"""Get latest version from PyPI."""
|
|
57
|
+
try:
|
|
58
|
+
import urllib.request
|
|
59
|
+
import json
|
|
60
|
+
|
|
61
|
+
url = f"https://pypi.org/pypi/{package_name}/json"
|
|
62
|
+
with urllib.request.urlopen(url, timeout=5) as response:
|
|
63
|
+
data = json.loads(response.read())
|
|
64
|
+
return data["info"]["version"]
|
|
65
|
+
except Exception:
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def check_git_updates(package_name, package_path):
|
|
70
|
+
"""Check if local repo has uncommitted changes or is behind remote."""
|
|
71
|
+
path = Path(package_path).expanduser()
|
|
72
|
+
|
|
73
|
+
if not path.exists():
|
|
74
|
+
return {"error": "Repository not found"}
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
# Check for uncommitted changes
|
|
78
|
+
result = subprocess.run(
|
|
79
|
+
["git", "-C", str(path), "status", "--porcelain"], capture_output=True, text=True
|
|
80
|
+
)
|
|
81
|
+
has_changes = len(result.stdout.strip()) > 0
|
|
82
|
+
|
|
83
|
+
# Check if behind remote
|
|
84
|
+
subprocess.run(["git", "-C", str(path), "fetch", "--quiet"], capture_output=True)
|
|
85
|
+
|
|
86
|
+
result = subprocess.run(
|
|
87
|
+
["git", "-C", str(path), "rev-list", "HEAD..@{upstream}", "--count"],
|
|
88
|
+
capture_output=True,
|
|
89
|
+
text=True,
|
|
90
|
+
)
|
|
91
|
+
behind_count = int(result.stdout.strip()) if result.stdout.strip().isdigit() else 0
|
|
92
|
+
|
|
93
|
+
# Get current commit
|
|
94
|
+
result = subprocess.run(
|
|
95
|
+
["git", "-C", str(path), "rev-parse", "--short", "HEAD"],
|
|
96
|
+
capture_output=True,
|
|
97
|
+
text=True,
|
|
98
|
+
)
|
|
99
|
+
current_commit = result.stdout.strip()
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
"has_changes": has_changes,
|
|
103
|
+
"behind_count": behind_count,
|
|
104
|
+
"current_commit": current_commit,
|
|
105
|
+
}
|
|
106
|
+
except Exception as e:
|
|
107
|
+
return {"error": str(e)}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def check_package(package_key):
|
|
111
|
+
"""Check status of a single package."""
|
|
112
|
+
config = PACKAGES[package_key]
|
|
113
|
+
|
|
114
|
+
status = {
|
|
115
|
+
"name": config["name"],
|
|
116
|
+
"installed": None,
|
|
117
|
+
"latest_pypi": None,
|
|
118
|
+
"git_status": None,
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# Check installed version
|
|
122
|
+
status["installed"] = get_installed_version(config["pypi_name"])
|
|
123
|
+
|
|
124
|
+
# Check PyPI version
|
|
125
|
+
status["latest_pypi"] = get_latest_version(config["pypi_name"])
|
|
126
|
+
|
|
127
|
+
# Check git status
|
|
128
|
+
status["git_status"] = check_git_updates(config["name"], config["path"])
|
|
129
|
+
|
|
130
|
+
return status
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def print_status_report(results):
|
|
134
|
+
"""Print formatted status report."""
|
|
135
|
+
print("\n" + "=" * 70)
|
|
136
|
+
print("SKCapstone Bundle Update Checker")
|
|
137
|
+
print(f"Checked at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
138
|
+
print("=" * 70)
|
|
139
|
+
|
|
140
|
+
updates_available = []
|
|
141
|
+
git_updates_available = []
|
|
142
|
+
|
|
143
|
+
for package_key, status in results.items():
|
|
144
|
+
print(f"\n📦 {status['name']}")
|
|
145
|
+
print("-" * 70)
|
|
146
|
+
|
|
147
|
+
# Installed version
|
|
148
|
+
if status["installed"]:
|
|
149
|
+
print(f" Installed: {status['installed']}")
|
|
150
|
+
else:
|
|
151
|
+
print(f" Installed: ❌ Not installed")
|
|
152
|
+
|
|
153
|
+
# PyPI version
|
|
154
|
+
if status["latest_pypi"]:
|
|
155
|
+
print(f" PyPI: {status['latest_pypi']}")
|
|
156
|
+
if status["installed"] and status["installed"] != status["latest_pypi"]:
|
|
157
|
+
print(f" ⚠️ Update available on PyPI!")
|
|
158
|
+
updates_available.append(status["name"])
|
|
159
|
+
else:
|
|
160
|
+
print(f" PyPI: (unable to check)")
|
|
161
|
+
|
|
162
|
+
# Git status
|
|
163
|
+
git = status["git_status"]
|
|
164
|
+
if git:
|
|
165
|
+
if "error" in git:
|
|
166
|
+
print(f" Git: ❌ {git['error']}")
|
|
167
|
+
else:
|
|
168
|
+
print(f" Git commit: {git['current_commit']}")
|
|
169
|
+
if git["has_changes"]:
|
|
170
|
+
print(f" ⚠️ Uncommitted changes detected")
|
|
171
|
+
if git["behind_count"] > 0:
|
|
172
|
+
print(f" ⚠️ {git['behind_count']} commit(s) behind remote")
|
|
173
|
+
git_updates_available.append(status["name"])
|
|
174
|
+
|
|
175
|
+
print("\n" + "=" * 70)
|
|
176
|
+
print("SUMMARY")
|
|
177
|
+
print("=" * 70)
|
|
178
|
+
|
|
179
|
+
if updates_available:
|
|
180
|
+
print(f"\n🔄 PyPI updates available: {', '.join(updates_available)}")
|
|
181
|
+
print(" Run: pip install --upgrade " + " ".join(updates_available))
|
|
182
|
+
else:
|
|
183
|
+
print("\n✅ All packages up-to-date on PyPI")
|
|
184
|
+
|
|
185
|
+
if git_updates_available:
|
|
186
|
+
print(f"\n🔄 Git updates available: {', '.join(git_updates_available)}")
|
|
187
|
+
print(" Run: git pull in respective repositories")
|
|
188
|
+
else:
|
|
189
|
+
print("✅ All repositories up-to-date")
|
|
190
|
+
|
|
191
|
+
print("\n" + "=" * 70)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def save_check_results(results):
|
|
195
|
+
"""Save results to JSON file for programmatic access."""
|
|
196
|
+
results_dir = Path("~/.skcapstone/logs").expanduser()
|
|
197
|
+
results_dir.mkdir(parents=True, exist_ok=True)
|
|
198
|
+
|
|
199
|
+
results_file = results_dir / f"update-check-{datetime.now().strftime('%Y%m%d-%H%M%S')}.json"
|
|
200
|
+
|
|
201
|
+
with open(results_file, "w") as f:
|
|
202
|
+
json.dump({"timestamp": datetime.now().isoformat(), "results": results}, f, indent=2)
|
|
203
|
+
|
|
204
|
+
print(f"\n📄 Detailed results saved to: {results_file}")
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def main():
|
|
208
|
+
"""Main entry point."""
|
|
209
|
+
print("Checking for updates to all SK packages...")
|
|
210
|
+
print("This may take a moment...")
|
|
211
|
+
|
|
212
|
+
results = {}
|
|
213
|
+
for package_key in PACKAGES:
|
|
214
|
+
results[package_key] = check_package(package_key)
|
|
215
|
+
|
|
216
|
+
print_status_report(results)
|
|
217
|
+
save_check_results(results)
|
|
218
|
+
|
|
219
|
+
# Exit with error code if updates available (useful for automation)
|
|
220
|
+
has_updates = any(
|
|
221
|
+
r["installed"] != r["latest_pypi"]
|
|
222
|
+
for r in results.values()
|
|
223
|
+
if r["installed"] and r["latest_pypi"]
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
return 1 if has_updates else 0
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
if __name__ == "__main__":
|
|
230
|
+
sys.exit(main())
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Convert soul blueprint markdown files to structured YAML.
|
|
3
|
+
|
|
4
|
+
Reads all .md blueprints from the souls-blueprints repo and writes
|
|
5
|
+
corresponding .yaml files using the existing soul.py parser.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
python scripts/convert_blueprints_to_yaml.py [--source DIR] [--dest DIR]
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import re
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
import yaml
|
|
19
|
+
|
|
20
|
+
# Add src to path so we can import soul.py
|
|
21
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "src"))
|
|
22
|
+
|
|
23
|
+
from skcapstone.soul import parse_blueprint, _slugify
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _slug_from_filename(path: Path) -> str:
|
|
27
|
+
"""Derive a clean slug from the filename, not the display name."""
|
|
28
|
+
stem = path.stem.lower()
|
|
29
|
+
# Remove leading 'the-' or 'the_' for cleaner slugs
|
|
30
|
+
stem = re.sub(r"[^\w\s-]", "", stem)
|
|
31
|
+
stem = re.sub(r"[\s_]+", "-", stem)
|
|
32
|
+
return stem.strip("-")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def convert_one(md_path: Path, dest_dir: Path) -> Path:
|
|
36
|
+
"""Convert a single MD blueprint to YAML.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
md_path: Path to the .md blueprint file.
|
|
40
|
+
dest_dir: Directory to write the .yaml file.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Path to the written YAML file.
|
|
44
|
+
"""
|
|
45
|
+
bp = parse_blueprint(md_path)
|
|
46
|
+
|
|
47
|
+
# Use filename-based slug for predictable, short names
|
|
48
|
+
slug = _slug_from_filename(md_path)
|
|
49
|
+
|
|
50
|
+
# Build the YAML structure
|
|
51
|
+
data = {
|
|
52
|
+
"name": slug,
|
|
53
|
+
"display_name": bp.display_name,
|
|
54
|
+
"category": bp.category,
|
|
55
|
+
"vibe": bp.vibe or "",
|
|
56
|
+
"philosophy": bp.philosophy or "",
|
|
57
|
+
"emoji": bp.emoji,
|
|
58
|
+
"core_traits": bp.core_traits if bp.core_traits else [],
|
|
59
|
+
"communication_style": {
|
|
60
|
+
"patterns": bp.communication_style.patterns,
|
|
61
|
+
"tone_markers": bp.communication_style.tone_markers,
|
|
62
|
+
"signature_phrases": bp.communication_style.signature_phrases,
|
|
63
|
+
},
|
|
64
|
+
"decision_framework": bp.decision_framework,
|
|
65
|
+
"emotional_topology": bp.emotional_topology if bp.emotional_topology else {},
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# Clean up None values in nested dicts
|
|
69
|
+
if not data["communication_style"]["patterns"]:
|
|
70
|
+
del data["communication_style"]["patterns"]
|
|
71
|
+
if not data["communication_style"]["tone_markers"]:
|
|
72
|
+
del data["communication_style"]["tone_markers"]
|
|
73
|
+
if not data["communication_style"]["signature_phrases"]:
|
|
74
|
+
del data["communication_style"]["signature_phrases"]
|
|
75
|
+
if not data["communication_style"]:
|
|
76
|
+
data["communication_style"] = {}
|
|
77
|
+
|
|
78
|
+
dest_dir.mkdir(parents=True, exist_ok=True)
|
|
79
|
+
yaml_path = dest_dir / f"{slug}.yaml"
|
|
80
|
+
|
|
81
|
+
with open(yaml_path, "w", encoding="utf-8") as f:
|
|
82
|
+
yaml.dump(
|
|
83
|
+
data,
|
|
84
|
+
f,
|
|
85
|
+
default_flow_style=False,
|
|
86
|
+
allow_unicode=True,
|
|
87
|
+
sort_keys=False,
|
|
88
|
+
width=120,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
return yaml_path
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def convert_all(source: Path, dest: Path) -> tuple[int, int]:
|
|
95
|
+
"""Convert all MD blueprints preserving category directories.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
source: Root directory containing category subdirs with .md files.
|
|
99
|
+
dest: Root directory for YAML output.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Tuple of (success_count, failure_count).
|
|
103
|
+
"""
|
|
104
|
+
successes = 0
|
|
105
|
+
failures = 0
|
|
106
|
+
|
|
107
|
+
for md_path in sorted(source.rglob("*.md")):
|
|
108
|
+
if md_path.name.startswith(".") or md_path.name.upper() == "README.MD":
|
|
109
|
+
continue
|
|
110
|
+
|
|
111
|
+
# Preserve category directory structure
|
|
112
|
+
rel = md_path.parent.relative_to(source)
|
|
113
|
+
dest_dir = dest / rel
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
yaml_path = convert_one(md_path, dest_dir)
|
|
117
|
+
print(f" {md_path.name} -> {yaml_path.relative_to(dest)}")
|
|
118
|
+
successes += 1
|
|
119
|
+
except Exception as exc:
|
|
120
|
+
print(f" FAIL: {md_path.name}: {exc}", file=sys.stderr)
|
|
121
|
+
failures += 1
|
|
122
|
+
|
|
123
|
+
return successes, failures
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def main():
|
|
127
|
+
parser = argparse.ArgumentParser(description="Convert soul blueprints MD -> YAML")
|
|
128
|
+
parser.add_argument(
|
|
129
|
+
"--source",
|
|
130
|
+
type=Path,
|
|
131
|
+
default=Path(__file__).resolve().parent.parent.parent
|
|
132
|
+
/ "souls-blueprints"
|
|
133
|
+
/ "blueprints",
|
|
134
|
+
help="Source directory with MD blueprints",
|
|
135
|
+
)
|
|
136
|
+
parser.add_argument(
|
|
137
|
+
"--dest",
|
|
138
|
+
type=Path,
|
|
139
|
+
default=Path(__file__).resolve().parent.parent.parent
|
|
140
|
+
/ "souls-blueprints"
|
|
141
|
+
/ "yaml",
|
|
142
|
+
help="Destination directory for YAML output",
|
|
143
|
+
)
|
|
144
|
+
args = parser.parse_args()
|
|
145
|
+
|
|
146
|
+
print(f"Source: {args.source}")
|
|
147
|
+
print(f"Dest: {args.dest}")
|
|
148
|
+
print()
|
|
149
|
+
|
|
150
|
+
ok, fail = convert_all(args.source, args.dest)
|
|
151
|
+
print(f"\nConverted: {ok}, Failed: {fail}")
|
|
152
|
+
|
|
153
|
+
return 0 if fail == 0 else 1
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
if __name__ == "__main__":
|
|
157
|
+
sys.exit(main())
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# dev-install.sh — Sovereign Agent Suite Dev Installer
|
|
3
|
+
#
|
|
4
|
+
# Wrapper around install.sh with --dev flag.
|
|
5
|
+
# Installs all SK* packages plus pytest, ruff, black.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# bash scripts/dev-install.sh
|
|
9
|
+
# bash scripts/dev-install.sh --force # Recreate venv
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
14
|
+
exec bash "$SCRIPT_DIR/install.sh" --dev "$@"
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# scripts/e2e-test.sh — Automated multi-agent E2E test for the SKCapstone daemon.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# ./scripts/e2e-test.sh [--port PORT] [--timeout SECS] [--peer PEER_NAME]
|
|
6
|
+
#
|
|
7
|
+
# Exit codes:
|
|
8
|
+
# 0 — all checks passed
|
|
9
|
+
# 1 — one or more checks failed
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
# ---------------------------------------------------------------------------
|
|
14
|
+
# Defaults
|
|
15
|
+
# ---------------------------------------------------------------------------
|
|
16
|
+
PORT="${PORT:-7777}"
|
|
17
|
+
STARTUP_WAIT="${STARTUP_WAIT:-10}"
|
|
18
|
+
POLL_TIMEOUT="${POLL_TIMEOUT:-300}"
|
|
19
|
+
PEER="${PEER:-test-peer}"
|
|
20
|
+
AGENT_HOME="${SKCAPSTONE_ROOT:-${HOME}/.skcapstone}"
|
|
21
|
+
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
# Helpers
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
RED='\033[0;31m'
|
|
26
|
+
GREEN='\033[0;32m'
|
|
27
|
+
YELLOW='\033[1;33m'
|
|
28
|
+
NC='\033[0m'
|
|
29
|
+
|
|
30
|
+
pass() { echo -e "${GREEN}[PASS]${NC} $*"; }
|
|
31
|
+
fail() { echo -e "${RED}[FAIL]${NC} $*"; FAILURES=$((FAILURES + 1)); }
|
|
32
|
+
info() { echo -e "${YELLOW}[INFO]${NC} $*"; }
|
|
33
|
+
|
|
34
|
+
FAILURES=0
|
|
35
|
+
DAEMON_PID=""
|
|
36
|
+
|
|
37
|
+
cleanup() {
|
|
38
|
+
if [[ -n "${DAEMON_PID}" ]]; then
|
|
39
|
+
info "Stopping daemon (PID ${DAEMON_PID})…"
|
|
40
|
+
kill "${DAEMON_PID}" 2>/dev/null || true
|
|
41
|
+
wait "${DAEMON_PID}" 2>/dev/null || true
|
|
42
|
+
fi
|
|
43
|
+
}
|
|
44
|
+
trap cleanup EXIT
|
|
45
|
+
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
# Step 0: Reinstall package
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
info "Reinstalling skcapstone…"
|
|
50
|
+
pip install -e . --quiet
|
|
51
|
+
|
|
52
|
+
# ---------------------------------------------------------------------------
|
|
53
|
+
# Step 1: Start daemon in the background
|
|
54
|
+
# ---------------------------------------------------------------------------
|
|
55
|
+
INBOX_DIR="${AGENT_HOME}/sync/comms/inbox/${PEER}"
|
|
56
|
+
OUTBOX_DIR="${AGENT_HOME}/sync/comms/outbox/${PEER}"
|
|
57
|
+
CONV_FILE="${AGENT_HOME}/conversations/${PEER}.json"
|
|
58
|
+
|
|
59
|
+
info "Starting daemon on port ${PORT}…"
|
|
60
|
+
skcapstone daemon start --foreground --port "${PORT}" \
|
|
61
|
+
>"${TMPDIR:-/tmp}/skcapstone-e2e-daemon.log" 2>&1 &
|
|
62
|
+
DAEMON_PID=$!
|
|
63
|
+
|
|
64
|
+
info "Waiting ${STARTUP_WAIT}s for daemon to initialize…"
|
|
65
|
+
sleep "${STARTUP_WAIT}"
|
|
66
|
+
|
|
67
|
+
# Verify process is still alive
|
|
68
|
+
if ! kill -0 "${DAEMON_PID}" 2>/dev/null; then
|
|
69
|
+
fail "Daemon exited prematurely — check ${TMPDIR:-/tmp}/skcapstone-e2e-daemon.log"
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
# Step 2: Check /consciousness endpoint
|
|
75
|
+
# ---------------------------------------------------------------------------
|
|
76
|
+
info "Checking /consciousness endpoint…"
|
|
77
|
+
CONSCIOUSNESS_RESP=$(curl -sf "http://127.0.0.1:${PORT}/consciousness" 2>&1) || true
|
|
78
|
+
if echo "${CONSCIOUSNESS_RESP}" | python3 -c "import sys,json; d=json.load(sys.stdin); assert d.get('status') in ('ACTIVE','active','ok','running')" 2>/dev/null; then
|
|
79
|
+
pass "/consciousness endpoint returned active status"
|
|
80
|
+
elif [[ -n "${CONSCIOUSNESS_RESP}" ]]; then
|
|
81
|
+
# Accept any valid JSON response — daemon is reachable
|
|
82
|
+
if echo "${CONSCIOUSNESS_RESP}" | python3 -m json.tool >/dev/null 2>&1; then
|
|
83
|
+
pass "/consciousness endpoint returned JSON (status field: $(echo "${CONSCIOUSNESS_RESP}" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('status','N/A'))" 2>/dev/null))"
|
|
84
|
+
else
|
|
85
|
+
fail "/consciousness endpoint returned non-JSON: ${CONSCIOUSNESS_RESP:0:120}"
|
|
86
|
+
fi
|
|
87
|
+
else
|
|
88
|
+
fail "/consciousness endpoint unreachable on port ${PORT}"
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# ---------------------------------------------------------------------------
|
|
92
|
+
# Step 3: Write a test message to the inbox
|
|
93
|
+
# ---------------------------------------------------------------------------
|
|
94
|
+
info "Writing test message to inbox (peer=${PEER})…"
|
|
95
|
+
mkdir -p "${INBOX_DIR}"
|
|
96
|
+
TIMESTAMP=$(date +%s)
|
|
97
|
+
MSG_ID="e2e-${TIMESTAMP}"
|
|
98
|
+
MSG_FILE="${INBOX_DIR}/${MSG_ID}.skc.json"
|
|
99
|
+
|
|
100
|
+
python3 - <<PYEOF
|
|
101
|
+
import json, time
|
|
102
|
+
msg = {
|
|
103
|
+
"sender": "${PEER}",
|
|
104
|
+
"recipient": "Opus",
|
|
105
|
+
"payload": {
|
|
106
|
+
"content": "Ping test — automated E2E at $(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
107
|
+
"content_type": "text",
|
|
108
|
+
},
|
|
109
|
+
"message_id": "${MSG_ID}",
|
|
110
|
+
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%S+00:00", time.gmtime()),
|
|
111
|
+
}
|
|
112
|
+
with open("${MSG_FILE}", "w") as fh:
|
|
113
|
+
json.dump(msg, fh)
|
|
114
|
+
print(f" Wrote {len(json.dumps(msg))} bytes → ${MSG_FILE}")
|
|
115
|
+
PYEOF
|
|
116
|
+
|
|
117
|
+
pass "Test message written: ${MSG_FILE}"
|
|
118
|
+
|
|
119
|
+
# ---------------------------------------------------------------------------
|
|
120
|
+
# Step 4: Poll outbox for response (up to POLL_TIMEOUT seconds)
|
|
121
|
+
# ---------------------------------------------------------------------------
|
|
122
|
+
info "Polling outbox for response (timeout=${POLL_TIMEOUT}s)…"
|
|
123
|
+
mkdir -p "${OUTBOX_DIR}"
|
|
124
|
+
|
|
125
|
+
RESPONSE_FOUND=false
|
|
126
|
+
DEADLINE=$((SECONDS + POLL_TIMEOUT))
|
|
127
|
+
LAST_OUTBOX_COUNT=0
|
|
128
|
+
|
|
129
|
+
while [[ ${SECONDS} -lt ${DEADLINE} ]]; do
|
|
130
|
+
OUTBOX_COUNT=$(find "${OUTBOX_DIR}" -name "*.skc.json" 2>/dev/null | wc -l)
|
|
131
|
+
if [[ "${OUTBOX_COUNT}" -gt "${LAST_OUTBOX_COUNT}" ]]; then
|
|
132
|
+
RESPONSE_FOUND=true
|
|
133
|
+
LATEST_RESP=$(find "${OUTBOX_DIR}" -name "*.skc.json" -newer "${MSG_FILE}" 2>/dev/null | sort | tail -1)
|
|
134
|
+
info "Response file detected: ${LATEST_RESP:-<any .skc.json in outbox>}"
|
|
135
|
+
break
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
# Also accept: conversations file updated (passthrough / no-SKComm mode)
|
|
139
|
+
if [[ -f "${CONV_FILE}" ]] && [[ "${CONV_FILE}" -nt "${MSG_FILE}" ]]; then
|
|
140
|
+
RESPONSE_FOUND=true
|
|
141
|
+
info "Conversation file updated (passthrough mode detected)"
|
|
142
|
+
break
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
ELAPSED=$((SECONDS - (DEADLINE - POLL_TIMEOUT)))
|
|
146
|
+
if (( ELAPSED % 30 == 0 )); then
|
|
147
|
+
info " Still waiting… ${ELAPSED}s elapsed / ${POLL_TIMEOUT}s timeout"
|
|
148
|
+
fi
|
|
149
|
+
sleep 2
|
|
150
|
+
done
|
|
151
|
+
|
|
152
|
+
if ${RESPONSE_FOUND}; then
|
|
153
|
+
pass "Response received within $((SECONDS - (DEADLINE - POLL_TIMEOUT)))s"
|
|
154
|
+
else
|
|
155
|
+
fail "No response within ${POLL_TIMEOUT}s (outbox: ${OUTBOX_DIR}, conv: ${CONV_FILE})"
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# ---------------------------------------------------------------------------
|
|
159
|
+
# Step 5: Check conversations file
|
|
160
|
+
# ---------------------------------------------------------------------------
|
|
161
|
+
info "Checking conversations/${PEER}.json…"
|
|
162
|
+
if [[ -f "${CONV_FILE}" ]]; then
|
|
163
|
+
CONV_SIZE=$(wc -c < "${CONV_FILE}")
|
|
164
|
+
if python3 -m json.tool "${CONV_FILE}" >/dev/null 2>&1; then
|
|
165
|
+
pass "conversations/${PEER}.json exists and is valid JSON (${CONV_SIZE} bytes)"
|
|
166
|
+
else
|
|
167
|
+
fail "conversations/${PEER}.json exists but is not valid JSON"
|
|
168
|
+
fi
|
|
169
|
+
else
|
|
170
|
+
fail "conversations/${PEER}.json not found at ${CONV_FILE}"
|
|
171
|
+
fi
|
|
172
|
+
|
|
173
|
+
# ---------------------------------------------------------------------------
|
|
174
|
+
# Step 6: Kill daemon
|
|
175
|
+
# ---------------------------------------------------------------------------
|
|
176
|
+
info "Stopping daemon…"
|
|
177
|
+
kill "${DAEMON_PID}" 2>/dev/null || true
|
|
178
|
+
wait "${DAEMON_PID}" 2>/dev/null || true
|
|
179
|
+
DAEMON_PID="" # prevent double-kill in trap
|
|
180
|
+
pass "Daemon stopped"
|
|
181
|
+
|
|
182
|
+
# ---------------------------------------------------------------------------
|
|
183
|
+
# Summary
|
|
184
|
+
# ---------------------------------------------------------------------------
|
|
185
|
+
echo ""
|
|
186
|
+
if [[ ${FAILURES} -eq 0 ]]; then
|
|
187
|
+
echo -e "${GREEN}E2E TEST PASSED${NC} — all checks passed."
|
|
188
|
+
exit 0
|
|
189
|
+
else
|
|
190
|
+
echo -e "${RED}E2E TEST FAILED${NC} — ${FAILURES} check(s) failed."
|
|
191
|
+
echo " Daemon log: ${TMPDIR:-/tmp}/skcapstone-e2e-daemon.log"
|
|
192
|
+
exit 1
|
|
193
|
+
fi
|