@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,156 @@
|
|
|
1
|
+
"""Config commands: validate."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
|
|
11
|
+
from ._common import AGENT_HOME, console
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def register_config_commands(main: click.Group) -> None:
|
|
15
|
+
"""Register the ``config`` command group on the main CLI."""
|
|
16
|
+
|
|
17
|
+
@main.group()
|
|
18
|
+
def config():
|
|
19
|
+
"""Config management — validate and inspect agent configuration."""
|
|
20
|
+
|
|
21
|
+
@config.command("validate")
|
|
22
|
+
@click.option(
|
|
23
|
+
"--home", default=AGENT_HOME, type=click.Path(),
|
|
24
|
+
help="Agent home directory.",
|
|
25
|
+
)
|
|
26
|
+
@click.option("--json-out", is_flag=True, help="Output as machine-readable JSON.")
|
|
27
|
+
@click.option(
|
|
28
|
+
"--strict", is_flag=True,
|
|
29
|
+
help="Treat warnings as errors (non-zero exit when warnings present).",
|
|
30
|
+
)
|
|
31
|
+
def validate(home: str, json_out: bool, strict: bool) -> None:
|
|
32
|
+
"""Validate all agent config files.
|
|
33
|
+
|
|
34
|
+
Checks consciousness.yaml, model_profiles.yaml, identity.json,
|
|
35
|
+
and soul blueprints. Reports schema errors with line numbers.
|
|
36
|
+
|
|
37
|
+
Exits 0 when all configs are valid (warnings do not cause failure
|
|
38
|
+
unless --strict is set). Exits 1 when any errors are found or
|
|
39
|
+
--strict is set and warnings are present.
|
|
40
|
+
"""
|
|
41
|
+
from ..config_validator import validate_all
|
|
42
|
+
|
|
43
|
+
home_path = Path(home).expanduser()
|
|
44
|
+
report = validate_all(home_path)
|
|
45
|
+
|
|
46
|
+
if json_out:
|
|
47
|
+
_json_output(report, strict)
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
_rich_output(report, strict)
|
|
51
|
+
|
|
52
|
+
has_errors = report.total_errors > 0 or (strict and report.total_warnings > 0)
|
|
53
|
+
if has_errors:
|
|
54
|
+
sys.exit(1)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
# Output helpers
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _json_output(report: object, strict: bool) -> None: # type: ignore[type-arg]
|
|
63
|
+
"""Emit machine-readable JSON to stdout."""
|
|
64
|
+
from ..config_validator import ConfigValidationReport
|
|
65
|
+
|
|
66
|
+
r: ConfigValidationReport = report # type: ignore[assignment]
|
|
67
|
+
data = {
|
|
68
|
+
"valid": r.is_valid and not (strict and r.total_warnings > 0),
|
|
69
|
+
"total_errors": r.total_errors,
|
|
70
|
+
"total_warnings": r.total_warnings,
|
|
71
|
+
"files": [
|
|
72
|
+
{
|
|
73
|
+
"name": fr.config_name,
|
|
74
|
+
"path": str(fr.file_path),
|
|
75
|
+
"found": fr.found,
|
|
76
|
+
"valid": fr.is_valid,
|
|
77
|
+
"issues": [
|
|
78
|
+
{
|
|
79
|
+
"severity": i.severity,
|
|
80
|
+
"message": i.message,
|
|
81
|
+
"field": i.field,
|
|
82
|
+
"line": i.line,
|
|
83
|
+
}
|
|
84
|
+
for i in fr.issues
|
|
85
|
+
],
|
|
86
|
+
}
|
|
87
|
+
for fr in r.results
|
|
88
|
+
],
|
|
89
|
+
}
|
|
90
|
+
click.echo(json.dumps(data, indent=2))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _rich_output(report: object, strict: bool) -> None: # type: ignore[type-arg]
|
|
94
|
+
"""Emit formatted Rich output to the terminal."""
|
|
95
|
+
from ..config_validator import ConfigValidationReport
|
|
96
|
+
from rich.panel import Panel
|
|
97
|
+
|
|
98
|
+
r: ConfigValidationReport = report # type: ignore[assignment]
|
|
99
|
+
|
|
100
|
+
console.print()
|
|
101
|
+
console.print(Panel(
|
|
102
|
+
"[bold]Config Validation[/]",
|
|
103
|
+
border_style="cyan",
|
|
104
|
+
padding=(0, 2),
|
|
105
|
+
))
|
|
106
|
+
console.print()
|
|
107
|
+
|
|
108
|
+
for fr in r.results:
|
|
109
|
+
if not fr.found:
|
|
110
|
+
icon, status = "[yellow]~[/]", "[yellow]NOT FOUND[/]"
|
|
111
|
+
elif fr.errors:
|
|
112
|
+
n = len(fr.errors)
|
|
113
|
+
icon = "[red]✗[/]"
|
|
114
|
+
status = f"[red]FAIL {n} error{'s' if n != 1 else ''}[/]"
|
|
115
|
+
elif fr.warnings:
|
|
116
|
+
n = len(fr.warnings)
|
|
117
|
+
icon = "[yellow]~[/]"
|
|
118
|
+
status = f"[yellow]OK {n} warning{'s' if n != 1 else ''}[/]"
|
|
119
|
+
else:
|
|
120
|
+
icon, status = "[green]✓[/]", "[green]OK[/]"
|
|
121
|
+
|
|
122
|
+
console.print(f" {icon} [bold]{fr.config_name}[/] {status}")
|
|
123
|
+
console.print(f" [dim]{fr.file_path}[/]")
|
|
124
|
+
|
|
125
|
+
for issue in fr.issues:
|
|
126
|
+
color = "red" if issue.severity == "error" else "yellow"
|
|
127
|
+
loc = f" line {issue.line}" if issue.line else ""
|
|
128
|
+
fld = f" [{issue.field}]" if issue.field else ""
|
|
129
|
+
console.print(
|
|
130
|
+
f" [{color}]{issue.severity.upper()}[/]"
|
|
131
|
+
f"[dim]{fld}{loc}[/] {issue.message}"
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
console.print()
|
|
135
|
+
|
|
136
|
+
# Summary line
|
|
137
|
+
errors = r.total_errors
|
|
138
|
+
warnings = r.total_warnings
|
|
139
|
+
if errors == 0 and warnings == 0:
|
|
140
|
+
console.print(" [bold green]✓ All configs valid.[/]")
|
|
141
|
+
elif errors == 0:
|
|
142
|
+
detail = f"{warnings} warning{'s' if warnings != 1 else ''}"
|
|
143
|
+
console.print(
|
|
144
|
+
f" [bold yellow]~ {detail}.[/] Configs are functional."
|
|
145
|
+
)
|
|
146
|
+
else:
|
|
147
|
+
err_detail = f"{errors} error{'s' if errors != 1 else ''}"
|
|
148
|
+
warn_detail = (
|
|
149
|
+
f", {warnings} warning{'s' if warnings != 1 else ''}"
|
|
150
|
+
if warnings else ""
|
|
151
|
+
)
|
|
152
|
+
console.print(
|
|
153
|
+
f" [bold red]✗ {err_detail}{warn_detail}[/] — fix before running the agent."
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
console.print()
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
"""Consciousness commands: status, config, test, backends, profiles."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
|
|
11
|
+
from ._common import AGENT_HOME, console
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def register_consciousness_commands(main: click.Group) -> None:
|
|
15
|
+
"""Register the consciousness command group."""
|
|
16
|
+
|
|
17
|
+
@main.group()
|
|
18
|
+
def consciousness():
|
|
19
|
+
"""Consciousness loop — autonomous message processing.
|
|
20
|
+
|
|
21
|
+
Manages the LLM-powered consciousness loop that lets agents
|
|
22
|
+
respond to messages autonomously, route to the right model,
|
|
23
|
+
and self-heal when things break.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
@consciousness.command("status")
|
|
27
|
+
@click.option("--port", default=7777, help="Daemon API port.")
|
|
28
|
+
@click.option("--json-out", is_flag=True, help="Output as JSON.")
|
|
29
|
+
def consciousness_status(port: int, json_out: bool):
|
|
30
|
+
"""Show consciousness loop status from the running daemon."""
|
|
31
|
+
import urllib.request
|
|
32
|
+
import urllib.error
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
url = f"http://127.0.0.1:{port}/consciousness"
|
|
36
|
+
with urllib.request.urlopen(url, timeout=3) as resp:
|
|
37
|
+
data = json.loads(resp.read())
|
|
38
|
+
except (urllib.error.URLError, OSError):
|
|
39
|
+
if json_out:
|
|
40
|
+
click.echo(json.dumps({"error": "Daemon not reachable"}))
|
|
41
|
+
else:
|
|
42
|
+
console.print("[yellow]Daemon is not running or unreachable.[/]")
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
if json_out:
|
|
46
|
+
click.echo(json.dumps(data, indent=2))
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
from rich.panel import Panel
|
|
50
|
+
from rich.table import Table
|
|
51
|
+
|
|
52
|
+
enabled = data.get("enabled", False)
|
|
53
|
+
color = "green" if enabled else "yellow"
|
|
54
|
+
|
|
55
|
+
inbox_watcher = data.get("inbox_watcher", "unknown")
|
|
56
|
+
|
|
57
|
+
console.print()
|
|
58
|
+
console.print(
|
|
59
|
+
Panel(
|
|
60
|
+
f"Enabled: [bold {color}]{enabled}[/]\n"
|
|
61
|
+
f"Messages processed: [bold]{data.get('messages_processed', 0)}[/]\n"
|
|
62
|
+
f"Responses sent: [bold]{data.get('responses_sent', 0)}[/]\n"
|
|
63
|
+
f"Errors: [bold]{data.get('errors', 0)}[/]\n"
|
|
64
|
+
f"Inotify active: {data.get('inotify_active', False)}\n"
|
|
65
|
+
f"Inbox watcher mode: [dim]{inbox_watcher}[/]\n"
|
|
66
|
+
f"Last activity: {data.get('last_activity') or '[dim]never[/]'}",
|
|
67
|
+
title=f"[{color}]Consciousness Loop[/]",
|
|
68
|
+
border_style=color,
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
backends = data.get("backends", {})
|
|
73
|
+
if backends:
|
|
74
|
+
table = Table(title="LLM Backends")
|
|
75
|
+
table.add_column("Backend", style="bold")
|
|
76
|
+
table.add_column("Status")
|
|
77
|
+
for name, available in sorted(backends.items()):
|
|
78
|
+
status_str = "[green]available[/]" if available else "[red]unavailable[/]"
|
|
79
|
+
table.add_row(name, status_str)
|
|
80
|
+
console.print(table)
|
|
81
|
+
|
|
82
|
+
console.print()
|
|
83
|
+
|
|
84
|
+
@consciousness.command("config")
|
|
85
|
+
@click.option("--init", "do_init", is_flag=True, help="Write default config YAML.")
|
|
86
|
+
@click.option("--show", "do_show", is_flag=True, help="Show current config.")
|
|
87
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path())
|
|
88
|
+
def consciousness_config(do_init: bool, do_show: bool, home: str):
|
|
89
|
+
"""Manage consciousness configuration."""
|
|
90
|
+
home_path = Path(home).expanduser()
|
|
91
|
+
|
|
92
|
+
if do_init:
|
|
93
|
+
from ..consciousness_config import write_default_config
|
|
94
|
+
path = write_default_config(home_path)
|
|
95
|
+
console.print(f"\n [green]Config written to[/] {path}\n")
|
|
96
|
+
return
|
|
97
|
+
|
|
98
|
+
if do_show:
|
|
99
|
+
from ..consciousness_config import load_consciousness_config
|
|
100
|
+
config = load_consciousness_config(home_path)
|
|
101
|
+
console.print()
|
|
102
|
+
for key, value in config.model_dump().items():
|
|
103
|
+
console.print(f" [bold]{key}[/]: {value}")
|
|
104
|
+
console.print()
|
|
105
|
+
return
|
|
106
|
+
|
|
107
|
+
# Default: show help
|
|
108
|
+
click.echo(click.get_current_context().get_help())
|
|
109
|
+
|
|
110
|
+
@consciousness.command("test")
|
|
111
|
+
@click.argument("message")
|
|
112
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path())
|
|
113
|
+
def consciousness_test(message: str, home: str):
|
|
114
|
+
"""Test the LLM pipeline end-to-end with a message.
|
|
115
|
+
|
|
116
|
+
Builds the full agent system prompt, routes via the model
|
|
117
|
+
router, and returns the LLM response.
|
|
118
|
+
"""
|
|
119
|
+
home_path = Path(home).expanduser()
|
|
120
|
+
|
|
121
|
+
from ..consciousness_config import load_consciousness_config
|
|
122
|
+
from ..consciousness_loop import (
|
|
123
|
+
ConsciousnessConfig,
|
|
124
|
+
LLMBridge,
|
|
125
|
+
SystemPromptBuilder,
|
|
126
|
+
_classify_message,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
console.print("\n [cyan]Testing consciousness pipeline...[/]")
|
|
130
|
+
|
|
131
|
+
config = load_consciousness_config(home_path)
|
|
132
|
+
bridge = LLMBridge(config)
|
|
133
|
+
builder = SystemPromptBuilder(home_path, config.max_context_tokens)
|
|
134
|
+
|
|
135
|
+
# Classify
|
|
136
|
+
signal = _classify_message(message)
|
|
137
|
+
console.print(f" Signal: tags={signal.tags}, tokens~{signal.estimated_tokens}")
|
|
138
|
+
|
|
139
|
+
# Build system prompt
|
|
140
|
+
system_prompt = builder.build()
|
|
141
|
+
console.print(f" System prompt: {len(system_prompt)} chars")
|
|
142
|
+
|
|
143
|
+
# Generate
|
|
144
|
+
console.print(" [dim]Generating response...[/]")
|
|
145
|
+
try:
|
|
146
|
+
response = bridge.generate(system_prompt, message, signal)
|
|
147
|
+
console.print(f"\n [green]Response ({len(response)} chars):[/]\n")
|
|
148
|
+
console.print(f" {response}\n")
|
|
149
|
+
except Exception as exc:
|
|
150
|
+
console.print(f"\n [red]Error:[/] {exc}\n")
|
|
151
|
+
sys.exit(1)
|
|
152
|
+
|
|
153
|
+
@consciousness.command("backends")
|
|
154
|
+
@click.option("--json-out", is_flag=True, help="Output as JSON.")
|
|
155
|
+
def consciousness_backends(json_out: bool):
|
|
156
|
+
"""Show which LLM backends are reachable."""
|
|
157
|
+
from ..consciousness_loop import ConsciousnessConfig, LLMBridge
|
|
158
|
+
|
|
159
|
+
config = ConsciousnessConfig()
|
|
160
|
+
bridge = LLMBridge(config)
|
|
161
|
+
health = bridge.health_check()
|
|
162
|
+
|
|
163
|
+
if json_out:
|
|
164
|
+
click.echo(json.dumps(health, indent=2))
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
from rich.table import Table
|
|
168
|
+
|
|
169
|
+
console.print()
|
|
170
|
+
table = Table(title="LLM Backend Availability")
|
|
171
|
+
table.add_column("Backend", style="bold")
|
|
172
|
+
table.add_column("Status")
|
|
173
|
+
table.add_column("Source")
|
|
174
|
+
|
|
175
|
+
backend_sources = {
|
|
176
|
+
"ollama": "localhost:11434 or OLLAMA_HOST",
|
|
177
|
+
"anthropic": "ANTHROPIC_API_KEY",
|
|
178
|
+
"openai": "OPENAI_API_KEY",
|
|
179
|
+
"grok": "XAI_API_KEY",
|
|
180
|
+
"kimi": "MOONSHOT_API_KEY",
|
|
181
|
+
"nvidia": "NVIDIA_API_KEY",
|
|
182
|
+
"passthrough": "always available (echo mode)",
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
for name, available in sorted(health.items()):
|
|
186
|
+
status_str = "[green]AVAILABLE[/]" if available else "[red]UNAVAILABLE[/]"
|
|
187
|
+
source = backend_sources.get(name, "")
|
|
188
|
+
table.add_row(name, status_str, source)
|
|
189
|
+
|
|
190
|
+
console.print(table)
|
|
191
|
+
|
|
192
|
+
try:
|
|
193
|
+
import watchdog # noqa: F401
|
|
194
|
+
inotify_line = "[green]inotify: active (watchdog installed)[/]"
|
|
195
|
+
except ImportError:
|
|
196
|
+
inotify_line = "[yellow]inotify: degraded (polling only, install watchdog)[/]"
|
|
197
|
+
console.print(f" {inotify_line}")
|
|
198
|
+
console.print()
|
|
199
|
+
|
|
200
|
+
@consciousness.command("quality")
|
|
201
|
+
@click.option("--home", default=AGENT_HOME, type=click.Path(), help="Agent home directory.")
|
|
202
|
+
@click.option("--json-out", is_flag=True, help="Output as JSON.")
|
|
203
|
+
@click.option("--port", default=7777, help="Daemon API port (tries live daemon first).")
|
|
204
|
+
def consciousness_quality(home: str, json_out: bool, port: int):
|
|
205
|
+
"""Show average response quality scores for today.
|
|
206
|
+
|
|
207
|
+
Reads quality metrics from today's daily metrics file.
|
|
208
|
+
Dimensions: length appropriateness, coherence, latency, overall.
|
|
209
|
+
"""
|
|
210
|
+
import urllib.request
|
|
211
|
+
import urllib.error
|
|
212
|
+
from datetime import datetime, timezone
|
|
213
|
+
from pathlib import Path
|
|
214
|
+
|
|
215
|
+
quality: dict = {}
|
|
216
|
+
|
|
217
|
+
# Try live daemon first — it may have unsaved in-memory data
|
|
218
|
+
try:
|
|
219
|
+
url = f"http://127.0.0.1:{port}/consciousness"
|
|
220
|
+
with urllib.request.urlopen(url, timeout=2) as resp:
|
|
221
|
+
data = json.loads(resp.read())
|
|
222
|
+
if "quality_avg" in data:
|
|
223
|
+
quality = data["quality_avg"]
|
|
224
|
+
except Exception:
|
|
225
|
+
pass # Daemon unreachable — fall through to file
|
|
226
|
+
|
|
227
|
+
# Fall back to daily metrics file
|
|
228
|
+
if not quality:
|
|
229
|
+
home_path = Path(home).expanduser()
|
|
230
|
+
date_str = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
231
|
+
daily = home_path / "metrics" / "daily" / f"{date_str}.json"
|
|
232
|
+
if daily.exists():
|
|
233
|
+
try:
|
|
234
|
+
file_data = json.loads(daily.read_text(encoding="utf-8"))
|
|
235
|
+
quality = file_data.get("quality_avg", {})
|
|
236
|
+
except Exception:
|
|
237
|
+
pass
|
|
238
|
+
|
|
239
|
+
if not quality or quality.get("count", 0) == 0:
|
|
240
|
+
if json_out:
|
|
241
|
+
click.echo(json.dumps({"count": 0, "message": "No quality data for today"}))
|
|
242
|
+
else:
|
|
243
|
+
console.print("\n [yellow]No quality metrics recorded today.[/]\n")
|
|
244
|
+
return
|
|
245
|
+
|
|
246
|
+
if json_out:
|
|
247
|
+
click.echo(json.dumps(quality, indent=2))
|
|
248
|
+
return
|
|
249
|
+
|
|
250
|
+
from rich.panel import Panel
|
|
251
|
+
from rich.table import Table
|
|
252
|
+
|
|
253
|
+
count = quality.get("count", 0)
|
|
254
|
+
overall = quality.get("overall", 0.0)
|
|
255
|
+
color = "green" if overall >= 0.7 else ("yellow" if overall >= 0.4 else "red")
|
|
256
|
+
|
|
257
|
+
def _bar(score: float) -> str:
|
|
258
|
+
filled = int(round(score * 10))
|
|
259
|
+
return "█" * filled + "░" * (10 - filled)
|
|
260
|
+
|
|
261
|
+
table = Table(title=f"Response Quality — {count} response(s) today", show_header=True)
|
|
262
|
+
table.add_column("Dimension", style="bold")
|
|
263
|
+
table.add_column("Score", justify="right")
|
|
264
|
+
table.add_column("Bar")
|
|
265
|
+
table.add_column("Description", style="dim")
|
|
266
|
+
|
|
267
|
+
dims = [
|
|
268
|
+
("Length", quality.get("length", 0.0), "Response is appropriate length for question"),
|
|
269
|
+
("Coherence", quality.get("coherence", 0.0), "Keywords from question appear in response"),
|
|
270
|
+
("Latency", quality.get("latency", 0.0), "Response generated quickly"),
|
|
271
|
+
("Overall", overall, "Weighted average (coherence 40%, length 30%, latency 30%)"),
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
for name, score, desc in dims:
|
|
275
|
+
s_color = "green" if score >= 0.7 else ("yellow" if score >= 0.4 else "red")
|
|
276
|
+
table.add_row(
|
|
277
|
+
name,
|
|
278
|
+
f"[{s_color}]{score:.3f}[/]",
|
|
279
|
+
f"[{s_color}]{_bar(score)}[/]",
|
|
280
|
+
desc,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
console.print()
|
|
284
|
+
console.print(table)
|
|
285
|
+
console.print(
|
|
286
|
+
Panel(
|
|
287
|
+
f"Overall quality: [{color}]{overall:.3f}[/] ({count} responses today)",
|
|
288
|
+
border_style=color,
|
|
289
|
+
)
|
|
290
|
+
)
|
|
291
|
+
console.print()
|
|
292
|
+
|
|
293
|
+
@consciousness.command("profiles")
|
|
294
|
+
@click.option("--show", "do_show", is_flag=True, help="List all profiles.")
|
|
295
|
+
@click.option("--stale", "do_stale", is_flag=True, help="Show profiles older than 90 days.")
|
|
296
|
+
@click.option("--update", "do_update", is_flag=True, help="Re-apply bundled defaults.")
|
|
297
|
+
@click.option("--export", "do_export", is_flag=True, help="Export profiles as YAML.")
|
|
298
|
+
def consciousness_profiles(do_show: bool, do_stale: bool, do_update: bool, do_export: bool):
|
|
299
|
+
"""Manage model prompt profiles."""
|
|
300
|
+
from ..prompt_adapter import PromptAdapter, _BUNDLED_PROFILES
|
|
301
|
+
|
|
302
|
+
adapter = PromptAdapter()
|
|
303
|
+
|
|
304
|
+
if do_export:
|
|
305
|
+
import yaml
|
|
306
|
+
profiles_data = [p.model_dump() for p in adapter.profiles]
|
|
307
|
+
click.echo(yaml.dump({"profiles": profiles_data}, default_flow_style=False))
|
|
308
|
+
return
|
|
309
|
+
|
|
310
|
+
if do_update:
|
|
311
|
+
adapter.reload_profiles()
|
|
312
|
+
console.print(f"\n [green]Reloaded {len(adapter.profiles)} profiles from bundled defaults.[/]\n")
|
|
313
|
+
return
|
|
314
|
+
|
|
315
|
+
if do_stale:
|
|
316
|
+
from datetime import datetime, timezone
|
|
317
|
+
now = datetime.now(timezone.utc)
|
|
318
|
+
stale = []
|
|
319
|
+
for p in adapter.profiles:
|
|
320
|
+
if not p.last_updated:
|
|
321
|
+
stale.append((p.family, "never"))
|
|
322
|
+
continue
|
|
323
|
+
try:
|
|
324
|
+
updated = datetime.fromisoformat(p.last_updated)
|
|
325
|
+
if hasattr(updated, "tzinfo") and updated.tzinfo is None:
|
|
326
|
+
updated = updated.replace(tzinfo=timezone.utc)
|
|
327
|
+
age = (now - updated).days
|
|
328
|
+
if age > 90:
|
|
329
|
+
stale.append((p.family, f"{age}d ago"))
|
|
330
|
+
except (ValueError, TypeError):
|
|
331
|
+
stale.append((p.family, "invalid date"))
|
|
332
|
+
|
|
333
|
+
if stale:
|
|
334
|
+
console.print("\n [yellow]Stale profiles (>90 days):[/]")
|
|
335
|
+
for family, age in stale:
|
|
336
|
+
console.print(f" {family}: {age}")
|
|
337
|
+
else:
|
|
338
|
+
console.print("\n [green]All profiles are fresh.[/]")
|
|
339
|
+
console.print()
|
|
340
|
+
return
|
|
341
|
+
|
|
342
|
+
# Default: --show
|
|
343
|
+
from rich.table import Table
|
|
344
|
+
table = Table(title="Model Profiles")
|
|
345
|
+
table.add_column("Family", style="bold")
|
|
346
|
+
table.add_column("Pattern")
|
|
347
|
+
table.add_column("System Mode")
|
|
348
|
+
table.add_column("Format")
|
|
349
|
+
table.add_column("Thinking")
|
|
350
|
+
table.add_column("Updated")
|
|
351
|
+
|
|
352
|
+
for p in adapter.profiles:
|
|
353
|
+
thinking = p.thinking_mode if p.thinking_enabled else "-"
|
|
354
|
+
table.add_row(
|
|
355
|
+
p.family,
|
|
356
|
+
p.model_pattern,
|
|
357
|
+
p.system_prompt_mode,
|
|
358
|
+
p.structure_format,
|
|
359
|
+
thinking,
|
|
360
|
+
p.last_updated or "[dim]never[/]",
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
console.print()
|
|
364
|
+
console.print(table)
|
|
365
|
+
console.print()
|
|
366
|
+
|
|
367
|
+
@consciousness.command("fallbacks")
|
|
368
|
+
@click.option("--limit", default=20, show_default=True, help="Number of recent events to show.")
|
|
369
|
+
@click.option("--json-out", is_flag=True, help="Output as JSON.")
|
|
370
|
+
@click.option("--clear", "do_clear", is_flag=True, help="Clear all stored fallback events.")
|
|
371
|
+
def consciousness_fallbacks(limit: int, json_out: bool, do_clear: bool):
|
|
372
|
+
"""Show LLM fallback history — when and why the agent degraded.
|
|
373
|
+
|
|
374
|
+
Each entry records the primary model that failed, the backend that
|
|
375
|
+
was tried next, whether the fallback succeeded, and the reason.
|
|
376
|
+
Events are stored in ~/.skcapstone/fallbacks.json.
|
|
377
|
+
"""
|
|
378
|
+
from ..fallback_tracker import FallbackTracker
|
|
379
|
+
|
|
380
|
+
tracker = FallbackTracker()
|
|
381
|
+
|
|
382
|
+
if do_clear:
|
|
383
|
+
count = tracker.clear()
|
|
384
|
+
console.print(f"\n [green]Cleared {count} fallback event(s).[/]\n")
|
|
385
|
+
return
|
|
386
|
+
|
|
387
|
+
events = tracker.load_events(limit=limit)
|
|
388
|
+
|
|
389
|
+
if json_out:
|
|
390
|
+
click.echo(
|
|
391
|
+
json.dumps([e.model_dump() for e in events], indent=2)
|
|
392
|
+
)
|
|
393
|
+
return
|
|
394
|
+
|
|
395
|
+
if not events:
|
|
396
|
+
console.print(
|
|
397
|
+
f"\n [dim]No fallback events recorded yet.[/]\n"
|
|
398
|
+
f" Events are written to: {tracker.path}\n"
|
|
399
|
+
)
|
|
400
|
+
return
|
|
401
|
+
|
|
402
|
+
from rich.table import Table
|
|
403
|
+
|
|
404
|
+
table = Table(title=f"LLM Fallback History (last {len(events)})", show_lines=True)
|
|
405
|
+
table.add_column("Time", style="dim", no_wrap=True)
|
|
406
|
+
table.add_column("Primary", style="bold")
|
|
407
|
+
table.add_column("→ Fallback")
|
|
408
|
+
table.add_column("OK?", justify="center")
|
|
409
|
+
table.add_column("Reason")
|
|
410
|
+
|
|
411
|
+
for evt in events:
|
|
412
|
+
ts = evt.timestamp[:19].replace("T", " ") # YYYY-MM-DD HH:MM:SS
|
|
413
|
+
ok_str = "[green]✓[/]" if evt.success else "[red]✗[/]"
|
|
414
|
+
primary = f"{evt.primary_model}\n[dim]{evt.primary_backend}[/]"
|
|
415
|
+
fallback = f"{evt.fallback_model}\n[dim]{evt.fallback_backend}[/]"
|
|
416
|
+
table.add_row(ts, primary, fallback, ok_str, evt.reason)
|
|
417
|
+
|
|
418
|
+
console.print()
|
|
419
|
+
console.print(table)
|
|
420
|
+
console.print(f" [dim]Source: {tracker.path}[/]")
|
|
421
|
+
console.print()
|