@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,552 @@
|
|
|
1
|
+
"""Upgrade / update command — smart sovereign package management.
|
|
2
|
+
|
|
3
|
+
Checks installed sovereign packages, upgrades all that are present,
|
|
4
|
+
and interactively prompts about optional pillar components that are
|
|
5
|
+
not yet installed.
|
|
6
|
+
|
|
7
|
+
Commands:
|
|
8
|
+
skcapstone upgrade — full upgrade of installed sovereign packages
|
|
9
|
+
skcapstone update — alias for upgrade (friendlier name)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import subprocess
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
import click
|
|
20
|
+
|
|
21
|
+
from ._common import AGENT_HOME, console
|
|
22
|
+
|
|
23
|
+
# ── Package definitions ───────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
# Core packages: always upgraded when installed; always offered for install.
|
|
26
|
+
CORE_PACKAGES: list[str] = [
|
|
27
|
+
"skmemory", # persistent memory layer
|
|
28
|
+
"capauth", # sovereign identity + PGP auth
|
|
29
|
+
"skcapstone", # main agent framework
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
# Optional pillar packages: upgraded only when already installed.
|
|
33
|
+
# If NOT installed, the user is prompted whether they want to add them.
|
|
34
|
+
OPTIONAL_PACKAGES: list[str] = [
|
|
35
|
+
"skcomm", # P2P transport layer
|
|
36
|
+
"skchat", # agent messaging daemon
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
# All sovereign packages in dependency order
|
|
40
|
+
SOVEREIGN_PACKAGES: list[str] = CORE_PACKAGES + OPTIONAL_PACKAGES
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# ── Version helpers ───────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _get_installed_version(package: str) -> Optional[str]:
|
|
47
|
+
"""Return the installed version string for a package, or None if not installed.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
package: PyPI package name.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Version string like '1.2.3', or None.
|
|
54
|
+
"""
|
|
55
|
+
try:
|
|
56
|
+
result = subprocess.run(
|
|
57
|
+
[sys.executable, "-m", "pip", "show", package],
|
|
58
|
+
capture_output=True,
|
|
59
|
+
text=True,
|
|
60
|
+
timeout=10,
|
|
61
|
+
)
|
|
62
|
+
for line in result.stdout.splitlines():
|
|
63
|
+
if line.startswith("Version:"):
|
|
64
|
+
return line.split(":", 1)[1].strip()
|
|
65
|
+
except Exception:
|
|
66
|
+
pass
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _get_latest_version(package: str) -> Optional[str]:
|
|
71
|
+
"""Fetch the latest available version from PyPI.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
package: PyPI package name.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Latest version string, or None if unreachable.
|
|
78
|
+
"""
|
|
79
|
+
try:
|
|
80
|
+
result = subprocess.run(
|
|
81
|
+
[sys.executable, "-m", "pip", "index", "versions", package],
|
|
82
|
+
capture_output=True,
|
|
83
|
+
text=True,
|
|
84
|
+
timeout=15,
|
|
85
|
+
)
|
|
86
|
+
# Output: "AVAILABLE VERSIONS: 0.3.0, 0.2.1, ..."
|
|
87
|
+
for line in result.stdout.splitlines():
|
|
88
|
+
if "AVAILABLE VERSIONS" in line.upper() or package in line.lower():
|
|
89
|
+
parts = line.split(":")
|
|
90
|
+
if len(parts) > 1:
|
|
91
|
+
versions = [v.strip() for v in parts[-1].split(",")]
|
|
92
|
+
if versions:
|
|
93
|
+
return versions[0]
|
|
94
|
+
except Exception:
|
|
95
|
+
pass
|
|
96
|
+
return None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _pip_install(package: str, upgrade: bool = True, force_reinstall: bool = False) -> tuple[bool, str]:
|
|
100
|
+
"""Run pip install [--upgrade] [--force-reinstall] for a package.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
package: PyPI package name.
|
|
104
|
+
upgrade: If True, pass --upgrade flag.
|
|
105
|
+
force_reinstall: If True, pass --force-reinstall (overwrites current install).
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Tuple of (success, output_or_error).
|
|
109
|
+
"""
|
|
110
|
+
cmd = [sys.executable, "-m", "pip", "install"]
|
|
111
|
+
if force_reinstall:
|
|
112
|
+
cmd.append("--force-reinstall")
|
|
113
|
+
elif upgrade:
|
|
114
|
+
cmd.append("--upgrade")
|
|
115
|
+
cmd.append(package)
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
result = subprocess.run(
|
|
119
|
+
cmd,
|
|
120
|
+
capture_output=True,
|
|
121
|
+
text=True,
|
|
122
|
+
timeout=120,
|
|
123
|
+
)
|
|
124
|
+
if result.returncode == 0:
|
|
125
|
+
return True, result.stdout
|
|
126
|
+
return False, result.stderr or result.stdout
|
|
127
|
+
except subprocess.TimeoutExpired:
|
|
128
|
+
return False, "pip install timed out after 120s"
|
|
129
|
+
except Exception as exc:
|
|
130
|
+
return False, str(exc)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _restart_daemon(home: Path) -> None:
|
|
134
|
+
"""Restart the skcapstone daemon after an upgrade.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
home: Agent home directory.
|
|
138
|
+
"""
|
|
139
|
+
console.print()
|
|
140
|
+
console.print("[bold]Restarting daemon...[/]")
|
|
141
|
+
try:
|
|
142
|
+
result = subprocess.run(
|
|
143
|
+
["skcapstone", "daemon", "restart", "--home", str(home)],
|
|
144
|
+
capture_output=True,
|
|
145
|
+
text=True,
|
|
146
|
+
timeout=30,
|
|
147
|
+
)
|
|
148
|
+
if result.returncode == 0:
|
|
149
|
+
console.print(" Daemon: [green]restarted[/]")
|
|
150
|
+
else:
|
|
151
|
+
err = result.stderr.strip() or result.stdout.strip()
|
|
152
|
+
console.print(f" Daemon: [yellow]restart failed[/] — {err}")
|
|
153
|
+
except FileNotFoundError:
|
|
154
|
+
console.print(" Daemon: [yellow]skcapstone not in PATH[/]")
|
|
155
|
+
except subprocess.TimeoutExpired:
|
|
156
|
+
console.print(" Daemon: [yellow]restart timed out[/]")
|
|
157
|
+
except Exception as exc:
|
|
158
|
+
console.print(f" Daemon: [yellow]restart error[/] — {exc}")
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
# ── Package descriptions ──────────────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
_PKG_DESCRIPTIONS: dict[str, str] = {
|
|
164
|
+
"skmemory": "persistent memory layer (required by skcapstone)",
|
|
165
|
+
"capauth": "sovereign PGP identity + authentication",
|
|
166
|
+
"skcapstone": "main sovereign agent framework",
|
|
167
|
+
"skcomm": "P2P transport layer for agent messaging",
|
|
168
|
+
"skchat": "agent messaging daemon + MCP server",
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _describe(pkg: str) -> str:
|
|
173
|
+
return _PKG_DESCRIPTIONS.get(pkg, pkg)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# ── Core upgrade logic ────────────────────────────────────────────────────────
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _run_upgrade(
|
|
180
|
+
pkg_list: list[str],
|
|
181
|
+
home_path: Path,
|
|
182
|
+
restart: bool,
|
|
183
|
+
yes: bool,
|
|
184
|
+
force_reinstall: bool = False,
|
|
185
|
+
) -> bool:
|
|
186
|
+
"""Perform the upgrade, print results, return True if all succeeded.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
pkg_list: Packages to upgrade/install.
|
|
190
|
+
home_path: Agent home directory.
|
|
191
|
+
restart: Whether to restart daemon after success.
|
|
192
|
+
yes: Whether to skip interactive prompts.
|
|
193
|
+
force_reinstall: Whether to force-reinstall regardless of current version.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
True if all upgrades succeeded.
|
|
197
|
+
"""
|
|
198
|
+
if not pkg_list:
|
|
199
|
+
console.print(" [dim]No packages selected.[/]")
|
|
200
|
+
return True
|
|
201
|
+
|
|
202
|
+
if force_reinstall:
|
|
203
|
+
console.print(" [yellow]Force-reinstall mode:[/] all packages will be overwritten.\n")
|
|
204
|
+
|
|
205
|
+
# Snapshot versions before
|
|
206
|
+
before: dict[str, Optional[str]] = {pkg: _get_installed_version(pkg) for pkg in pkg_list}
|
|
207
|
+
|
|
208
|
+
# Run upgrades
|
|
209
|
+
results: dict[str, tuple[bool, Optional[str], Optional[str]]] = {}
|
|
210
|
+
any_failed = False
|
|
211
|
+
|
|
212
|
+
for pkg in pkg_list:
|
|
213
|
+
already_installed = before.get(pkg) is not None
|
|
214
|
+
if force_reinstall:
|
|
215
|
+
action = "Reinstalling"
|
|
216
|
+
elif already_installed:
|
|
217
|
+
action = "Upgrading"
|
|
218
|
+
else:
|
|
219
|
+
action = "Installing"
|
|
220
|
+
console.print(f" {action} [cyan]{pkg}[/]...", end=" ")
|
|
221
|
+
ok, _output = _pip_install(pkg, upgrade=True, force_reinstall=force_reinstall)
|
|
222
|
+
after_ver = _get_installed_version(pkg)
|
|
223
|
+
results[pkg] = (ok, before.get(pkg), after_ver)
|
|
224
|
+
if ok:
|
|
225
|
+
console.print("[green]ok[/]")
|
|
226
|
+
else:
|
|
227
|
+
console.print("[red]FAILED[/]")
|
|
228
|
+
any_failed = True
|
|
229
|
+
|
|
230
|
+
# Version diff table
|
|
231
|
+
from rich.table import Table
|
|
232
|
+
|
|
233
|
+
console.print()
|
|
234
|
+
table = Table(
|
|
235
|
+
show_header=True,
|
|
236
|
+
header_style="bold",
|
|
237
|
+
box=None,
|
|
238
|
+
padding=(0, 2),
|
|
239
|
+
)
|
|
240
|
+
table.add_column("Package", style="cyan")
|
|
241
|
+
table.add_column("Description", style="dim")
|
|
242
|
+
table.add_column("Before", style="dim")
|
|
243
|
+
table.add_column("")
|
|
244
|
+
table.add_column("After")
|
|
245
|
+
table.add_column("Status")
|
|
246
|
+
|
|
247
|
+
for pkg in pkg_list:
|
|
248
|
+
ok, v_before, v_after = results[pkg]
|
|
249
|
+
before_str = v_before or "[dim]—[/]"
|
|
250
|
+
after_str = v_after or "[dim]unknown[/]"
|
|
251
|
+
|
|
252
|
+
if not ok:
|
|
253
|
+
status_str = "[red]FAILED[/]"
|
|
254
|
+
arrow = "[red]✗[/]"
|
|
255
|
+
elif v_before is None:
|
|
256
|
+
status_str = "[green]installed[/]"
|
|
257
|
+
arrow = "[green]NEW[/]"
|
|
258
|
+
elif v_before == v_after:
|
|
259
|
+
status_str = "[dim]up to date[/]"
|
|
260
|
+
arrow = "[dim]=[/]"
|
|
261
|
+
else:
|
|
262
|
+
status_str = "[green]upgraded[/]"
|
|
263
|
+
arrow = "[green]→[/]"
|
|
264
|
+
|
|
265
|
+
table.add_row(pkg, _describe(pkg), before_str, arrow, after_str, status_str)
|
|
266
|
+
|
|
267
|
+
console.print(table)
|
|
268
|
+
|
|
269
|
+
# Restart if requested and all succeeded
|
|
270
|
+
if restart:
|
|
271
|
+
if any_failed:
|
|
272
|
+
console.print()
|
|
273
|
+
console.print("[yellow]Warning:[/] some packages failed — skipping daemon restart.")
|
|
274
|
+
else:
|
|
275
|
+
_restart_daemon(home_path)
|
|
276
|
+
|
|
277
|
+
# Summary
|
|
278
|
+
console.print()
|
|
279
|
+
upgraded = [p for p in pkg_list if results[p][0] and results[p][1] != results[p][2]]
|
|
280
|
+
up_to_date = [p for p in pkg_list if results[p][0] and results[p][1] == results[p][2]]
|
|
281
|
+
failed = [p for p in pkg_list if not results[p][0]]
|
|
282
|
+
|
|
283
|
+
parts: list[str] = []
|
|
284
|
+
if upgraded:
|
|
285
|
+
parts.append(f"[green]{len(upgraded)} upgraded[/]")
|
|
286
|
+
if up_to_date:
|
|
287
|
+
parts.append(f"[dim]{len(up_to_date)} up to date[/]")
|
|
288
|
+
if failed:
|
|
289
|
+
parts.append(f"[red]{len(failed)} failed[/]")
|
|
290
|
+
|
|
291
|
+
console.print(" " + " ".join(parts))
|
|
292
|
+
|
|
293
|
+
# Auto-register skills and MCP servers after successful upgrade
|
|
294
|
+
if not any_failed:
|
|
295
|
+
_run_auto_register()
|
|
296
|
+
|
|
297
|
+
return not any_failed
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def _run_auto_register() -> None:
|
|
301
|
+
"""Run auto-registration of SK* skills and MCP servers.
|
|
302
|
+
|
|
303
|
+
This is called as a final step after upgrading packages, ensuring
|
|
304
|
+
all SKILL.md symlinks and MCP server entries are in place.
|
|
305
|
+
"""
|
|
306
|
+
console.print()
|
|
307
|
+
console.print("[bold]Registering skills & MCP servers...[/]")
|
|
308
|
+
try:
|
|
309
|
+
from skcapstone.register import register_all
|
|
310
|
+
|
|
311
|
+
results = register_all()
|
|
312
|
+
registered = 0
|
|
313
|
+
for _name, pkg_result in results.get("packages", {}).items():
|
|
314
|
+
skill = pkg_result.get("skill", {})
|
|
315
|
+
if skill.get("action") == "created":
|
|
316
|
+
registered += 1
|
|
317
|
+
mcp = pkg_result.get("mcp", {})
|
|
318
|
+
for _env, action in (mcp if isinstance(mcp, dict) else {}).items():
|
|
319
|
+
if action == "created":
|
|
320
|
+
registered += 1
|
|
321
|
+
|
|
322
|
+
if registered > 0:
|
|
323
|
+
console.print(f" [green]{registered} registration(s) applied[/]")
|
|
324
|
+
else:
|
|
325
|
+
console.print(" [dim]All registrations up to date[/]")
|
|
326
|
+
except Exception as exc:
|
|
327
|
+
console.print(f" [yellow]Registration skipped[/] — {exc}")
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
# ── Click commands ────────────────────────────────────────────────────────────
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def register_upgrade_commands(main: click.Group) -> None:
|
|
334
|
+
"""Register upgrade and update commands on the main CLI group."""
|
|
335
|
+
|
|
336
|
+
@main.command()
|
|
337
|
+
@click.option(
|
|
338
|
+
"--home",
|
|
339
|
+
default=AGENT_HOME,
|
|
340
|
+
help="Agent home directory.",
|
|
341
|
+
type=click.Path(),
|
|
342
|
+
)
|
|
343
|
+
@click.option(
|
|
344
|
+
"--restart",
|
|
345
|
+
is_flag=True,
|
|
346
|
+
default=False,
|
|
347
|
+
help="Restart the daemon after a successful upgrade.",
|
|
348
|
+
)
|
|
349
|
+
@click.option(
|
|
350
|
+
"--packages",
|
|
351
|
+
default=None,
|
|
352
|
+
help=(
|
|
353
|
+
"Comma-separated list of packages to upgrade. "
|
|
354
|
+
"Default: all installed sovereign packages."
|
|
355
|
+
),
|
|
356
|
+
)
|
|
357
|
+
@click.option(
|
|
358
|
+
"--yes", "-y",
|
|
359
|
+
is_flag=True,
|
|
360
|
+
default=False,
|
|
361
|
+
help="Skip interactive prompts — do not install optional packages that are missing.",
|
|
362
|
+
)
|
|
363
|
+
@click.option(
|
|
364
|
+
"--all", "install_all",
|
|
365
|
+
is_flag=True,
|
|
366
|
+
default=False,
|
|
367
|
+
help="Install all optional packages without prompting.",
|
|
368
|
+
)
|
|
369
|
+
@click.option(
|
|
370
|
+
"--force-reinstall",
|
|
371
|
+
is_flag=True,
|
|
372
|
+
default=False,
|
|
373
|
+
help=(
|
|
374
|
+
"Force-reinstall ALL components, overwriting whatever is currently installed. "
|
|
375
|
+
"Use this to fix broken installs or downgrade to a clean state."
|
|
376
|
+
),
|
|
377
|
+
)
|
|
378
|
+
def upgrade(
|
|
379
|
+
home: str,
|
|
380
|
+
restart: bool,
|
|
381
|
+
packages: Optional[str],
|
|
382
|
+
yes: bool,
|
|
383
|
+
install_all: bool,
|
|
384
|
+
force_reinstall: bool,
|
|
385
|
+
) -> None:
|
|
386
|
+
"""Upgrade sovereign packages to their latest versions.
|
|
387
|
+
|
|
388
|
+
Upgrades all currently installed sovereign packages (skcapstone,
|
|
389
|
+
skmemory, capauth) and any optional pillars already present.
|
|
390
|
+
|
|
391
|
+
For optional packages that are NOT installed (skcomm, skchat),
|
|
392
|
+
you will be prompted whether you want to add them — unless
|
|
393
|
+
--yes (skip) or --all (install all) is passed.
|
|
394
|
+
|
|
395
|
+
Use --force-reinstall to overwrite everything regardless of current
|
|
396
|
+
version — useful for fixing broken installs.
|
|
397
|
+
|
|
398
|
+
Examples:
|
|
399
|
+
|
|
400
|
+
skcapstone upgrade # smart upgrade + prompts
|
|
401
|
+
skcapstone upgrade --yes # upgrade only what's installed
|
|
402
|
+
skcapstone upgrade --all # upgrade + install all pillars
|
|
403
|
+
skcapstone upgrade --force-reinstall # overwrite ALL components
|
|
404
|
+
skcapstone upgrade --force-reinstall --all # reinstall everything
|
|
405
|
+
skcapstone upgrade --packages skcomm,skchat
|
|
406
|
+
skcapstone upgrade --restart # restart daemon after upgrade
|
|
407
|
+
"""
|
|
408
|
+
home_path = Path(home).expanduser()
|
|
409
|
+
|
|
410
|
+
console.print()
|
|
411
|
+
console.print("[bold cyan]SKCapstone Upgrade[/]")
|
|
412
|
+
console.print()
|
|
413
|
+
|
|
414
|
+
# ── Force reinstall: use all sovereign packages ────────────────────────
|
|
415
|
+
if force_reinstall:
|
|
416
|
+
pkg_list = (
|
|
417
|
+
[p.strip() for p in packages.split(",") if p.strip()]
|
|
418
|
+
if packages
|
|
419
|
+
else (SOVEREIGN_PACKAGES if install_all else CORE_PACKAGES + [
|
|
420
|
+
pkg for pkg in OPTIONAL_PACKAGES
|
|
421
|
+
if install_all or _get_installed_version(pkg) is not None
|
|
422
|
+
])
|
|
423
|
+
)
|
|
424
|
+
console.print(
|
|
425
|
+
f" [yellow bold]Force reinstall[/]: {', '.join(pkg_list)}"
|
|
426
|
+
)
|
|
427
|
+
console.print()
|
|
428
|
+
ok = _run_upgrade(pkg_list, home_path, restart, yes, force_reinstall=True)
|
|
429
|
+
if not ok:
|
|
430
|
+
raise SystemExit(1)
|
|
431
|
+
return
|
|
432
|
+
|
|
433
|
+
# ── Explicit package list ──────────────────────────────────────────────
|
|
434
|
+
if packages:
|
|
435
|
+
pkg_list = [p.strip() for p in packages.split(",") if p.strip()]
|
|
436
|
+
console.print(f" Packages: {', '.join(pkg_list)}")
|
|
437
|
+
console.print()
|
|
438
|
+
ok = _run_upgrade(pkg_list, home_path, restart, yes)
|
|
439
|
+
if not ok:
|
|
440
|
+
raise SystemExit(1)
|
|
441
|
+
return
|
|
442
|
+
|
|
443
|
+
# ── Smart mode: scan installed packages ───────────────────────────────
|
|
444
|
+
installed: list[str] = []
|
|
445
|
+
not_installed: list[str] = []
|
|
446
|
+
|
|
447
|
+
for pkg in SOVEREIGN_PACKAGES:
|
|
448
|
+
ver = _get_installed_version(pkg)
|
|
449
|
+
if ver:
|
|
450
|
+
installed.append(pkg)
|
|
451
|
+
else:
|
|
452
|
+
not_installed.append(pkg)
|
|
453
|
+
|
|
454
|
+
console.print(" [bold]Installed pillar packages:[/]")
|
|
455
|
+
for pkg in installed:
|
|
456
|
+
ver = _get_installed_version(pkg)
|
|
457
|
+
console.print(f" [green]●[/] [cyan]{pkg}[/] {ver} [dim]{_describe(pkg)}[/]")
|
|
458
|
+
|
|
459
|
+
if not_installed:
|
|
460
|
+
console.print()
|
|
461
|
+
console.print(" [bold]Not installed:[/]")
|
|
462
|
+
for pkg in not_installed:
|
|
463
|
+
console.print(f" [dim]○[/] [dim]{pkg}[/] [dim]{_describe(pkg)}[/]")
|
|
464
|
+
|
|
465
|
+
console.print()
|
|
466
|
+
|
|
467
|
+
# ── Prompt for optional packages ──────────────────────────────────────
|
|
468
|
+
to_install_extra: list[str] = []
|
|
469
|
+
|
|
470
|
+
if install_all:
|
|
471
|
+
to_install_extra = not_installed
|
|
472
|
+
if to_install_extra:
|
|
473
|
+
console.print(
|
|
474
|
+
f" [cyan]--all[/]: will also install: {', '.join(to_install_extra)}"
|
|
475
|
+
)
|
|
476
|
+
console.print()
|
|
477
|
+
elif not yes and not_installed:
|
|
478
|
+
console.print(" [bold]Optional components available:[/]")
|
|
479
|
+
for pkg in not_installed:
|
|
480
|
+
answer = click.confirm(
|
|
481
|
+
f" Install [cyan]{pkg}[/] ({_describe(pkg)})?",
|
|
482
|
+
default=False,
|
|
483
|
+
)
|
|
484
|
+
if answer:
|
|
485
|
+
to_install_extra.append(pkg)
|
|
486
|
+
if to_install_extra:
|
|
487
|
+
console.print()
|
|
488
|
+
|
|
489
|
+
# Combine: upgrade installed + install newly selected extras
|
|
490
|
+
final_list = installed + to_install_extra
|
|
491
|
+
|
|
492
|
+
if not final_list:
|
|
493
|
+
console.print(" [dim]Nothing to do.[/]")
|
|
494
|
+
return
|
|
495
|
+
|
|
496
|
+
console.print(f" Upgrading: [cyan]{', '.join(final_list)}[/]")
|
|
497
|
+
console.print()
|
|
498
|
+
|
|
499
|
+
ok = _run_upgrade(final_list, home_path, restart, yes)
|
|
500
|
+
if not ok:
|
|
501
|
+
raise SystemExit(1)
|
|
502
|
+
|
|
503
|
+
# ── `update` alias ────────────────────────────────────────────────────────
|
|
504
|
+
|
|
505
|
+
@main.command(
|
|
506
|
+
name="update",
|
|
507
|
+
context_settings={"ignore_unknown_options": False},
|
|
508
|
+
)
|
|
509
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path())
|
|
510
|
+
@click.option("--restart", is_flag=True, default=False)
|
|
511
|
+
@click.option("--packages", default=None)
|
|
512
|
+
@click.option("--yes", "-y", is_flag=True, default=False)
|
|
513
|
+
@click.option("--all", "install_all", is_flag=True, default=False)
|
|
514
|
+
@click.option(
|
|
515
|
+
"--force-reinstall",
|
|
516
|
+
is_flag=True,
|
|
517
|
+
default=False,
|
|
518
|
+
help="Force-reinstall ALL components, overwriting current installs.",
|
|
519
|
+
)
|
|
520
|
+
@click.pass_context
|
|
521
|
+
def update(
|
|
522
|
+
ctx: click.Context,
|
|
523
|
+
home: str,
|
|
524
|
+
restart: bool,
|
|
525
|
+
packages: Optional[str],
|
|
526
|
+
yes: bool,
|
|
527
|
+
install_all: bool,
|
|
528
|
+
force_reinstall: bool,
|
|
529
|
+
) -> None:
|
|
530
|
+
"""Alias for 'upgrade' — update all sovereign packages.
|
|
531
|
+
|
|
532
|
+
Checks installed pillar programs and upgrades them to the latest
|
|
533
|
+
available versions. Prompts about optional components (skcomm,
|
|
534
|
+
skchat) that are not yet installed.
|
|
535
|
+
|
|
536
|
+
Examples:
|
|
537
|
+
|
|
538
|
+
skcapstone update # smart update + prompts
|
|
539
|
+
skcapstone update --yes # update only what's installed
|
|
540
|
+
skcapstone update --all # update + install all pillars
|
|
541
|
+
skcapstone update --force-reinstall # overwrite ALL components
|
|
542
|
+
skcapstone update --restart # restart daemon after update
|
|
543
|
+
"""
|
|
544
|
+
ctx.invoke(
|
|
545
|
+
upgrade,
|
|
546
|
+
home=home,
|
|
547
|
+
restart=restart,
|
|
548
|
+
packages=packages,
|
|
549
|
+
yes=yes,
|
|
550
|
+
install_all=install_all,
|
|
551
|
+
force_reinstall=force_reinstall,
|
|
552
|
+
)
|