@smilintux/skcapstone 0.1.0 → 0.2.4
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 +880 -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 +191 -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 +398 -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 +357 -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 +264 -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,142 @@
|
|
|
1
|
+
"""Context loader commands: show, generate."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
from ._common import AGENT_HOME, console
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def register_context_commands(main: click.Group) -> None:
|
|
13
|
+
"""Register the context command group."""
|
|
14
|
+
|
|
15
|
+
@main.group()
|
|
16
|
+
def context():
|
|
17
|
+
"""Universal AI agent context loader.
|
|
18
|
+
|
|
19
|
+
Outputs agent identity, pillar status, board state, and recent
|
|
20
|
+
memories in formats consumable by any AI tool. Tool-agnostic:
|
|
21
|
+
works with Claude Code, Cursor, Windsurf, Aider, or any terminal.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
@context.command("show")
|
|
25
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path())
|
|
26
|
+
@click.option(
|
|
27
|
+
"--format",
|
|
28
|
+
"fmt",
|
|
29
|
+
type=click.Choice(["text", "json", "claude-md", "cursor-rules"]),
|
|
30
|
+
default="text",
|
|
31
|
+
help="Output format (default: text).",
|
|
32
|
+
)
|
|
33
|
+
@click.option("--memories", "-n", default=10, help="Max recent memories to include.")
|
|
34
|
+
def context_show(home: str, fmt: str, memories: int):
|
|
35
|
+
"""Show the agent's full context.
|
|
36
|
+
|
|
37
|
+
Pipe into any AI tool or redirect to a file:
|
|
38
|
+
|
|
39
|
+
skcapstone context show # terminal
|
|
40
|
+
skcapstone context show --format json # machine-readable
|
|
41
|
+
skcapstone context show --format claude-md # for Claude Code
|
|
42
|
+
skcapstone context show | claude # pipe to Claude Code CLI
|
|
43
|
+
|
|
44
|
+
Examples:
|
|
45
|
+
skcapstone context show --format claude-md > CLAUDE.md
|
|
46
|
+
skcapstone context show --format cursor-rules > .cursor/rules/agent.mdc
|
|
47
|
+
"""
|
|
48
|
+
home_path = Path(home).expanduser()
|
|
49
|
+
if fmt == "claude-md":
|
|
50
|
+
from ..claude_md import generate_claude_md
|
|
51
|
+
click.echo(generate_claude_md(home_path, memory_limit=memories))
|
|
52
|
+
else:
|
|
53
|
+
from ..context_loader import FORMATTERS, gather_context
|
|
54
|
+
ctx = gather_context(home_path, memory_limit=memories)
|
|
55
|
+
click.echo(FORMATTERS[fmt](ctx))
|
|
56
|
+
|
|
57
|
+
@context.command("generate")
|
|
58
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path())
|
|
59
|
+
@click.option("--memories", "-n", default=10, help="Max recent memories to include.")
|
|
60
|
+
@click.option(
|
|
61
|
+
"--target",
|
|
62
|
+
type=click.Choice(["claude-md", "cursor-rules", "both"]),
|
|
63
|
+
default="both",
|
|
64
|
+
help="Which config file(s) to generate.",
|
|
65
|
+
)
|
|
66
|
+
def context_generate(home: str, memories: int, target: str):
|
|
67
|
+
"""Auto-generate AI tool config files from agent context.
|
|
68
|
+
|
|
69
|
+
Writes CLAUDE.md (for Claude Code CLI) and/or
|
|
70
|
+
.cursor/rules/agent.mdc (for Cursor) in the current directory.
|
|
71
|
+
|
|
72
|
+
Examples:
|
|
73
|
+
skcapstone context generate # both files
|
|
74
|
+
skcapstone context generate --target claude-md # CLAUDE.md only
|
|
75
|
+
"""
|
|
76
|
+
from ..context_loader import FORMATTERS, gather_context
|
|
77
|
+
|
|
78
|
+
home_path = Path(home).expanduser()
|
|
79
|
+
ctx = gather_context(home_path, memory_limit=memories)
|
|
80
|
+
|
|
81
|
+
cwd = Path.cwd()
|
|
82
|
+
|
|
83
|
+
if target in ("claude-md", "both"):
|
|
84
|
+
claude_path = cwd / "CLAUDE.md"
|
|
85
|
+
claude_path.write_text(FORMATTERS["claude-md"](ctx), encoding="utf-8")
|
|
86
|
+
console.print(f" [green]Written:[/] {claude_path}")
|
|
87
|
+
|
|
88
|
+
if target in ("cursor-rules", "both"):
|
|
89
|
+
rules_dir = cwd / ".cursor" / "rules"
|
|
90
|
+
rules_dir.mkdir(parents=True, exist_ok=True)
|
|
91
|
+
rules_path = rules_dir / "agent.mdc"
|
|
92
|
+
rules_path.write_text(FORMATTERS["cursor-rules"](ctx), encoding="utf-8")
|
|
93
|
+
console.print(f" [green]Written:[/] {rules_path}")
|
|
94
|
+
|
|
95
|
+
console.print()
|
|
96
|
+
|
|
97
|
+
@main.command("refresh-context")
|
|
98
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path())
|
|
99
|
+
@click.option("--memories", "-n", default=10, help="Max recent memories to embed.")
|
|
100
|
+
@click.option(
|
|
101
|
+
"--dest",
|
|
102
|
+
default=None,
|
|
103
|
+
type=click.Path(),
|
|
104
|
+
help="Destination path for CLAUDE.md (default: repo root or cwd).",
|
|
105
|
+
)
|
|
106
|
+
@click.option("--backup", is_flag=True, default=False, help="Rename existing CLAUDE.md to .bak before writing.")
|
|
107
|
+
def refresh_context(home: str, memories: int, dest: str | None, backup: bool):
|
|
108
|
+
"""Regenerate CLAUDE.md from current agent state.
|
|
109
|
+
|
|
110
|
+
Writes CLAUDE.md to the git repository root (or cwd if not in a
|
|
111
|
+
git repository). Useful as a pre-commit hook or alias.
|
|
112
|
+
|
|
113
|
+
Examples:
|
|
114
|
+
skcapstone refresh-context
|
|
115
|
+
skcapstone refresh-context --dest /path/to/project/CLAUDE.md
|
|
116
|
+
skcapstone refresh-context --backup
|
|
117
|
+
"""
|
|
118
|
+
import subprocess
|
|
119
|
+
|
|
120
|
+
from ..claude_md import write_claude_md
|
|
121
|
+
|
|
122
|
+
home_path = Path(home).expanduser()
|
|
123
|
+
|
|
124
|
+
if dest:
|
|
125
|
+
target = Path(dest).expanduser().resolve()
|
|
126
|
+
if target.is_dir():
|
|
127
|
+
target = target / "CLAUDE.md"
|
|
128
|
+
else:
|
|
129
|
+
# Walk up from cwd to find git root; fall back to cwd.
|
|
130
|
+
try:
|
|
131
|
+
result = subprocess.run(
|
|
132
|
+
["git", "rev-parse", "--show-toplevel"],
|
|
133
|
+
capture_output=True,
|
|
134
|
+
text=True,
|
|
135
|
+
check=True,
|
|
136
|
+
)
|
|
137
|
+
target = Path(result.stdout.strip()) / "CLAUDE.md"
|
|
138
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
139
|
+
target = Path.cwd() / "CLAUDE.md"
|
|
140
|
+
|
|
141
|
+
write_claude_md(home_path, target, memory_limit=memories, backup=backup)
|
|
142
|
+
console.print(f" [green]Written:[/] {target}")
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""Coordination board commands: status, create, claim, complete, board, changelog, briefing."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
|
|
10
|
+
from ._common import AGENT_HOME, console
|
|
11
|
+
from ._validators import validate_agent_name, validate_task_id
|
|
12
|
+
|
|
13
|
+
from rich.panel import Panel
|
|
14
|
+
from rich.table import Table
|
|
15
|
+
from rich.text import Text
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def register_coord_commands(main: click.Group) -> None:
|
|
19
|
+
"""Register the coord command group."""
|
|
20
|
+
|
|
21
|
+
@main.group()
|
|
22
|
+
def coord():
|
|
23
|
+
"""Multi-agent coordination board.
|
|
24
|
+
|
|
25
|
+
Create tasks, claim work, and track progress across
|
|
26
|
+
agents. All data lives in ~/.skcapstone/coordination/
|
|
27
|
+
and syncs via Syncthing. Conflict-free by design.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
@coord.command("status")
|
|
31
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path())
|
|
32
|
+
def coord_status(home):
|
|
33
|
+
"""Show the coordination board overview."""
|
|
34
|
+
from ..coordination import Board
|
|
35
|
+
|
|
36
|
+
home_path = Path(home).expanduser()
|
|
37
|
+
board = Board(home_path)
|
|
38
|
+
views = board.get_task_views()
|
|
39
|
+
agents = board.load_agents()
|
|
40
|
+
|
|
41
|
+
if not views and not agents:
|
|
42
|
+
console.print("\n [dim]Board is empty. Create tasks with:[/]")
|
|
43
|
+
console.print(" [cyan]skcapstone coord create --title 'My Task'[/]\n")
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
open_count = sum(1 for v in views if v.status.value == "open")
|
|
47
|
+
progress_count = sum(1 for v in views if v.status.value == "in_progress")
|
|
48
|
+
claimed_count = sum(1 for v in views if v.status.value == "claimed")
|
|
49
|
+
done_count = sum(1 for v in views if v.status.value == "done")
|
|
50
|
+
|
|
51
|
+
console.print()
|
|
52
|
+
console.print(Panel(
|
|
53
|
+
f"[bold]Tasks:[/] {len(views)} total "
|
|
54
|
+
f"[green]{open_count} open[/] "
|
|
55
|
+
f"[cyan]{claimed_count} claimed[/] "
|
|
56
|
+
f"[yellow]{progress_count} in progress[/] "
|
|
57
|
+
f"[dim]{done_count} done[/]",
|
|
58
|
+
title="Coordination Board", border_style="bright_blue",
|
|
59
|
+
))
|
|
60
|
+
|
|
61
|
+
table = Table(show_header=True, header_style="bold", box=None, padding=(0, 2))
|
|
62
|
+
table.add_column("ID", style="cyan", max_width=10)
|
|
63
|
+
table.add_column("Title", style="bold")
|
|
64
|
+
table.add_column("Priority")
|
|
65
|
+
table.add_column("Status")
|
|
66
|
+
table.add_column("Assignee", style="dim")
|
|
67
|
+
table.add_column("Tags", style="dim")
|
|
68
|
+
|
|
69
|
+
priority_colors = {"critical": "bold red", "high": "red", "medium": "yellow", "low": "dim"}
|
|
70
|
+
status_colors = {"open": "green", "claimed": "cyan", "in_progress": "yellow", "done": "dim", "blocked": "red"}
|
|
71
|
+
|
|
72
|
+
for v in views:
|
|
73
|
+
if v.status.value == "done":
|
|
74
|
+
continue
|
|
75
|
+
t = v.task
|
|
76
|
+
p_style = priority_colors.get(t.priority.value, "dim")
|
|
77
|
+
s_style = status_colors.get(v.status.value, "dim")
|
|
78
|
+
table.add_row(t.id, t.title, Text(t.priority.value.upper(), style=p_style),
|
|
79
|
+
Text(v.status.value.upper(), style=s_style), v.claimed_by or "", ", ".join(t.tags))
|
|
80
|
+
|
|
81
|
+
console.print(table)
|
|
82
|
+
|
|
83
|
+
if agents:
|
|
84
|
+
console.print()
|
|
85
|
+
for ag in agents:
|
|
86
|
+
icon = {"active": "[green]ACTIVE[/]", "idle": "[yellow]IDLE[/]"}.get(ag.state.value, "[dim]OFFLINE[/]")
|
|
87
|
+
current = f" -> [cyan]{ag.current_task}[/]" if ag.current_task else ""
|
|
88
|
+
console.print(f" {icon} [bold]{ag.agent}[/]{current}")
|
|
89
|
+
console.print()
|
|
90
|
+
|
|
91
|
+
@coord.command("create")
|
|
92
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path())
|
|
93
|
+
@click.option("--title", required=True, help="Task title.")
|
|
94
|
+
@click.option("--desc", default="", help="Task description.")
|
|
95
|
+
@click.option("--priority", type=click.Choice(["critical", "high", "medium", "low"]), default="medium")
|
|
96
|
+
@click.option("--tag", multiple=True, help="Tags (repeatable).")
|
|
97
|
+
@click.option("--by", default="human", help="Creator name.")
|
|
98
|
+
@click.option("--criteria", multiple=True, help="Acceptance criteria (repeatable).")
|
|
99
|
+
@click.option("--dep", multiple=True, help="Dependency task IDs (repeatable).")
|
|
100
|
+
def coord_create(home, title, desc, priority, tag, by, criteria, dep):
|
|
101
|
+
"""Create a new task on the board."""
|
|
102
|
+
from ..coordination import Board, Task, TaskPriority
|
|
103
|
+
|
|
104
|
+
validate_agent_name(by)
|
|
105
|
+
for d in dep:
|
|
106
|
+
validate_task_id(d)
|
|
107
|
+
|
|
108
|
+
home_path = Path(home).expanduser()
|
|
109
|
+
board = Board(home_path)
|
|
110
|
+
task = Task(title=title, description=desc, priority=TaskPriority(priority),
|
|
111
|
+
tags=list(tag), created_by=by, acceptance_criteria=list(criteria), dependencies=list(dep))
|
|
112
|
+
path = board.create_task(task)
|
|
113
|
+
console.print(f"\n [green]Created:[/] [{task.id}] {task.title}")
|
|
114
|
+
console.print(f" [dim]{path}[/]\n")
|
|
115
|
+
|
|
116
|
+
@coord.command("claim")
|
|
117
|
+
@click.argument("task_id")
|
|
118
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path())
|
|
119
|
+
@click.option("--agent", required=True, help="Agent name claiming the task.")
|
|
120
|
+
def coord_claim(task_id, home, agent):
|
|
121
|
+
"""Claim a task for an agent."""
|
|
122
|
+
from ..coordination import Board
|
|
123
|
+
|
|
124
|
+
validate_task_id(task_id)
|
|
125
|
+
validate_agent_name(agent)
|
|
126
|
+
|
|
127
|
+
home_path = Path(home).expanduser()
|
|
128
|
+
board = Board(home_path)
|
|
129
|
+
try:
|
|
130
|
+
ag = board.claim_task(agent, task_id)
|
|
131
|
+
console.print(f"\n [green]Claimed:[/] [{task_id}] by [bold]{ag.agent}[/]\n")
|
|
132
|
+
except ValueError as e:
|
|
133
|
+
console.print(f"\n [red]Error:[/] {e}\n")
|
|
134
|
+
sys.exit(1)
|
|
135
|
+
|
|
136
|
+
@coord.command("complete")
|
|
137
|
+
@click.argument("task_id")
|
|
138
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path())
|
|
139
|
+
@click.option("--agent", required=True, help="Agent name completing the task.")
|
|
140
|
+
def coord_complete(task_id, home, agent):
|
|
141
|
+
"""Mark a task as completed."""
|
|
142
|
+
from ..coordination import Board
|
|
143
|
+
|
|
144
|
+
validate_task_id(task_id)
|
|
145
|
+
validate_agent_name(agent)
|
|
146
|
+
|
|
147
|
+
home_path = Path(home).expanduser()
|
|
148
|
+
board = Board(home_path)
|
|
149
|
+
ag = board.complete_task(agent, task_id)
|
|
150
|
+
# board.complete_task() automatically mints Joules via _mint_joules_for_task
|
|
151
|
+
console.print(f"\n [green]Completed:[/] [{task_id}] by [bold]{ag.agent}[/]\n")
|
|
152
|
+
|
|
153
|
+
@coord.command("board")
|
|
154
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path())
|
|
155
|
+
def coord_board(home):
|
|
156
|
+
"""Generate and display the BOARD.md overview."""
|
|
157
|
+
from ..coordination import Board
|
|
158
|
+
|
|
159
|
+
home_path = Path(home).expanduser()
|
|
160
|
+
board = Board(home_path)
|
|
161
|
+
path = board.write_board_md()
|
|
162
|
+
md = board.generate_board_md()
|
|
163
|
+
console.print(md)
|
|
164
|
+
console.print(f"\n [dim]Written to {path}[/]\n")
|
|
165
|
+
|
|
166
|
+
@coord.command("changelog")
|
|
167
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path())
|
|
168
|
+
@click.option("--output", "-o", default=None, type=click.Path(), help="Output file path.")
|
|
169
|
+
def coord_changelog(home, output):
|
|
170
|
+
"""Generate CHANGELOG.md from completed board tasks."""
|
|
171
|
+
from ..changelog import generate_changelog, write_changelog
|
|
172
|
+
|
|
173
|
+
home_path = Path(home).expanduser()
|
|
174
|
+
out_path = Path(output) if output else None
|
|
175
|
+
path = write_changelog(home_path, out_path)
|
|
176
|
+
|
|
177
|
+
content = generate_changelog(home_path)
|
|
178
|
+
console.print(content[:3000])
|
|
179
|
+
if len(content) > 3000:
|
|
180
|
+
console.print(f"\n [dim]... ({len(content)} chars total)[/]")
|
|
181
|
+
console.print(f"\n [green]Written to {path}[/]\n")
|
|
182
|
+
|
|
183
|
+
@coord.command("briefing")
|
|
184
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path())
|
|
185
|
+
@click.option("--format", "fmt", type=click.Choice(["text", "json"]), default="text")
|
|
186
|
+
def coord_briefing(home, fmt):
|
|
187
|
+
"""Print the full coordination protocol for any AI agent."""
|
|
188
|
+
from ..coordination import get_briefing_text, get_briefing_json
|
|
189
|
+
|
|
190
|
+
home_path = Path(home).expanduser()
|
|
191
|
+
if fmt == "json":
|
|
192
|
+
click.echo(get_briefing_json(home_path))
|
|
193
|
+
else:
|
|
194
|
+
click.echo(get_briefing_text(home_path))
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""Crush (charmbracelet/crush) integration commands.
|
|
2
|
+
|
|
3
|
+
Subcommands:
|
|
4
|
+
skcapstone crush setup — install config + soul instructions
|
|
5
|
+
skcapstone crush config — print the generated crush.json
|
|
6
|
+
skcapstone crush status — show installation status
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
|
|
13
|
+
import click
|
|
14
|
+
from rich.console import Console
|
|
15
|
+
from rich.panel import Panel
|
|
16
|
+
from rich.table import Table
|
|
17
|
+
|
|
18
|
+
console = Console()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def register_crush_commands(main: click.Group) -> None:
|
|
22
|
+
"""Register the crush command group."""
|
|
23
|
+
|
|
24
|
+
@main.group()
|
|
25
|
+
def crush():
|
|
26
|
+
"""Crush terminal AI client integration.
|
|
27
|
+
|
|
28
|
+
Wire the charmbracelet/crush TUI to skcapstone MCP and
|
|
29
|
+
load your soul blueprint as its system instructions.
|
|
30
|
+
|
|
31
|
+
https://github.com/charmbracelet/crush
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
@crush.command("setup")
|
|
35
|
+
@click.option(
|
|
36
|
+
"--overwrite",
|
|
37
|
+
is_flag=True,
|
|
38
|
+
default=False,
|
|
39
|
+
help="Overwrite existing crush config files.",
|
|
40
|
+
)
|
|
41
|
+
def crush_setup(overwrite: bool) -> None:
|
|
42
|
+
"""Set up Crush: write crush.json + instructions.md.
|
|
43
|
+
|
|
44
|
+
Writes:
|
|
45
|
+
~/.config/crush/crush.json — MCP wiring + permissions
|
|
46
|
+
~/.config/crush/instructions.md — soul blueprint as system prompt
|
|
47
|
+
"""
|
|
48
|
+
from ..crush_integration import setup_crush
|
|
49
|
+
|
|
50
|
+
console.print()
|
|
51
|
+
with console.status(" Configuring Crush…", spinner="dots"):
|
|
52
|
+
result = setup_crush(overwrite=overwrite)
|
|
53
|
+
|
|
54
|
+
t = Table.grid(padding=(0, 2))
|
|
55
|
+
t.add_column(style="dim", width=20)
|
|
56
|
+
t.add_column()
|
|
57
|
+
|
|
58
|
+
if result["installed"]:
|
|
59
|
+
t.add_row("Binary", f"[green]{result['binary_path']}[/]")
|
|
60
|
+
else:
|
|
61
|
+
t.add_row("Binary", "[yellow]not found[/]")
|
|
62
|
+
if result.get("install_hint"):
|
|
63
|
+
t.add_row("Install with", f"[cyan]{result['install_hint']}[/]")
|
|
64
|
+
|
|
65
|
+
t.add_row("Config", f"[dim]{result['config_path']}[/]")
|
|
66
|
+
t.add_row("Instructions", f"[dim]{result['instructions_path']}[/]")
|
|
67
|
+
|
|
68
|
+
console.print(
|
|
69
|
+
Panel(
|
|
70
|
+
t,
|
|
71
|
+
title="[bold]Crush Setup Complete[/]",
|
|
72
|
+
border_style="bright_blue",
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
console.print()
|
|
77
|
+
console.print(
|
|
78
|
+
" [dim]Run crush in your project directory to start coding with your sovereign agent.[/]"
|
|
79
|
+
)
|
|
80
|
+
if not result["installed"]:
|
|
81
|
+
console.print()
|
|
82
|
+
hint = result.get("install_hint", "go install github.com/charmbracelet/crush@latest")
|
|
83
|
+
console.print(f" [bold]Install crush:[/] [cyan]{hint}[/]")
|
|
84
|
+
console.print()
|
|
85
|
+
|
|
86
|
+
@crush.command("config")
|
|
87
|
+
@click.option(
|
|
88
|
+
"--json-only",
|
|
89
|
+
"json_only",
|
|
90
|
+
is_flag=True,
|
|
91
|
+
default=False,
|
|
92
|
+
help="Print raw JSON without formatting.",
|
|
93
|
+
)
|
|
94
|
+
def crush_config(json_only: bool) -> None:
|
|
95
|
+
"""Print the crush.json config that will be written."""
|
|
96
|
+
from ..crush_integration import generate_crush_config
|
|
97
|
+
|
|
98
|
+
config = generate_crush_config()
|
|
99
|
+
if json_only:
|
|
100
|
+
click.echo(json.dumps(config, indent=2))
|
|
101
|
+
else:
|
|
102
|
+
console.print()
|
|
103
|
+
console.print_json(json.dumps(config, indent=2))
|
|
104
|
+
console.print()
|
|
105
|
+
console.print(
|
|
106
|
+
f" [dim]Write this to [cyan]~/.config/crush/crush.json[/] "
|
|
107
|
+
f"with: skcapstone crush setup[/]"
|
|
108
|
+
)
|
|
109
|
+
console.print()
|
|
110
|
+
|
|
111
|
+
@crush.command("status")
|
|
112
|
+
def crush_status() -> None:
|
|
113
|
+
"""Show Crush installation and config status."""
|
|
114
|
+
from ..crush_integration import (
|
|
115
|
+
find_crush_binary,
|
|
116
|
+
get_install_hint,
|
|
117
|
+
is_crush_installed,
|
|
118
|
+
)
|
|
119
|
+
from pathlib import Path
|
|
120
|
+
|
|
121
|
+
crush_config_dir = Path("~/.config/crush").expanduser()
|
|
122
|
+
crush_json = crush_config_dir / "crush.json"
|
|
123
|
+
instructions_md = crush_config_dir / "instructions.md"
|
|
124
|
+
|
|
125
|
+
console.print()
|
|
126
|
+
t = Table(
|
|
127
|
+
title="Crush Status",
|
|
128
|
+
border_style="bright_blue",
|
|
129
|
+
show_header=True,
|
|
130
|
+
)
|
|
131
|
+
t.add_column("Item", style="bold", width=22)
|
|
132
|
+
t.add_column("Status")
|
|
133
|
+
t.add_column("Detail", style="dim")
|
|
134
|
+
|
|
135
|
+
# Binary
|
|
136
|
+
binary = find_crush_binary()
|
|
137
|
+
if binary:
|
|
138
|
+
t.add_row("Binary", "[green]FOUND[/]", str(binary))
|
|
139
|
+
else:
|
|
140
|
+
hint = get_install_hint()
|
|
141
|
+
t.add_row("Binary", "[yellow]MISSING[/]", hint)
|
|
142
|
+
|
|
143
|
+
# crush.json
|
|
144
|
+
if crush_json.exists():
|
|
145
|
+
try:
|
|
146
|
+
data = json.loads(crush_json.read_text(encoding="utf-8"))
|
|
147
|
+
mcp_count = len(data.get("mcp", {}))
|
|
148
|
+
t.add_row(
|
|
149
|
+
"crush.json",
|
|
150
|
+
"[green]OK[/]",
|
|
151
|
+
f"{mcp_count} MCP server(s) — {str(crush_json)}",
|
|
152
|
+
)
|
|
153
|
+
except Exception:
|
|
154
|
+
t.add_row("crush.json", "[red]CORRUPT[/]", str(crush_json))
|
|
155
|
+
else:
|
|
156
|
+
t.add_row("crush.json", "[yellow]MISSING[/]", "run: skcapstone crush setup")
|
|
157
|
+
|
|
158
|
+
# instructions.md
|
|
159
|
+
if instructions_md.exists():
|
|
160
|
+
size = instructions_md.stat().st_size
|
|
161
|
+
t.add_row("instructions.md", "[green]OK[/]", f"{size} bytes — {str(instructions_md)}")
|
|
162
|
+
else:
|
|
163
|
+
t.add_row(
|
|
164
|
+
"instructions.md",
|
|
165
|
+
"[yellow]MISSING[/]",
|
|
166
|
+
"run: skcapstone crush setup",
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
console.print(t)
|
|
170
|
+
console.print()
|