@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,380 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Desktop notification support for the sovereign agent.
|
|
3
|
+
|
|
4
|
+
Sends desktop notifications for incoming messages via:
|
|
5
|
+
- gi.repository.Notify (Linux / libnotify, with GLib action callbacks)
|
|
6
|
+
- notify-send (Linux / libnotify, subprocess fallback)
|
|
7
|
+
- osascript (macOS)
|
|
8
|
+
|
|
9
|
+
Gracefully no-ops if neither tool is available.
|
|
10
|
+
Enforces a 5-second debounce so rapid messages don't flood the desktop.
|
|
11
|
+
|
|
12
|
+
Click actions (Linux gi.Notify only):
|
|
13
|
+
- open-dashboard: xdg-open the skcapstone dashboard URL (default localhost:7778)
|
|
14
|
+
- open-skchat: open skchat watch in a terminal session
|
|
15
|
+
Click events are stored in skcapstone memory (layer: short-term).
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import datetime
|
|
21
|
+
import logging
|
|
22
|
+
import platform
|
|
23
|
+
import subprocess
|
|
24
|
+
import threading
|
|
25
|
+
import time
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
from typing import Optional
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger("skcapstone.notifications")
|
|
30
|
+
|
|
31
|
+
# Default dashboard URL (skcapstone dashboard default port)
|
|
32
|
+
_DEFAULT_DASHBOARD_URL = "http://localhost:7778"
|
|
33
|
+
|
|
34
|
+
# Terminal emulators tried in order when opening skchat watch
|
|
35
|
+
_TERMINAL_CMDS: list[list[str]] = [
|
|
36
|
+
["konsole", "--new-tab", "-e"],
|
|
37
|
+
["gnome-terminal", "--"],
|
|
38
|
+
["xfce4-terminal", "-x"],
|
|
39
|
+
["alacritty", "-e"],
|
|
40
|
+
["kitty"],
|
|
41
|
+
["xterm", "-e"],
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _store_notification_memory(title: str, body: str, urgency: str) -> None:
|
|
46
|
+
"""Persist a short-term memory entry for every dispatched notification."""
|
|
47
|
+
try:
|
|
48
|
+
from . import AGENT_HOME
|
|
49
|
+
from .memory_engine import store as mem_store
|
|
50
|
+
from .models import MemoryLayer
|
|
51
|
+
|
|
52
|
+
home = Path(AGENT_HOME).expanduser()
|
|
53
|
+
if not home.exists():
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
ts = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
57
|
+
content = f"[{ts}] Notification sent — title={title!r} body={body!r} urgency={urgency}"
|
|
58
|
+
mem_store(
|
|
59
|
+
home=home,
|
|
60
|
+
content=content,
|
|
61
|
+
tags=["notification"],
|
|
62
|
+
source="notifications",
|
|
63
|
+
importance=0.3,
|
|
64
|
+
layer=MemoryLayer.SHORT_TERM,
|
|
65
|
+
)
|
|
66
|
+
except Exception as exc:
|
|
67
|
+
logger.debug("Failed to store notification memory: %s", exc)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _store_click_event(action: str, detail: str) -> None:
|
|
71
|
+
"""Persist a short-term memory entry for a notification click action."""
|
|
72
|
+
try:
|
|
73
|
+
from . import AGENT_HOME
|
|
74
|
+
from .memory_engine import store as mem_store
|
|
75
|
+
from .models import MemoryLayer
|
|
76
|
+
|
|
77
|
+
home = Path(AGENT_HOME).expanduser()
|
|
78
|
+
if not home.exists():
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
ts = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
82
|
+
content = (
|
|
83
|
+
f"[{ts}] Notification click — action={action!r} detail={detail!r}"
|
|
84
|
+
)
|
|
85
|
+
mem_store(
|
|
86
|
+
home=home,
|
|
87
|
+
content=content,
|
|
88
|
+
tags=["notification", "click-event"],
|
|
89
|
+
source="notifications",
|
|
90
|
+
importance=0.3,
|
|
91
|
+
layer=MemoryLayer.SHORT_TERM,
|
|
92
|
+
)
|
|
93
|
+
logger.debug("Stored notification click event: %s → %s", action, detail)
|
|
94
|
+
except Exception as exc:
|
|
95
|
+
logger.debug("Failed to store click event in memory: %s", exc)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _open_skchat_terminal() -> None:
|
|
99
|
+
"""Open ``skchat watch`` in a terminal emulator (best-effort)."""
|
|
100
|
+
skchat_cmd = ["skchat", "watch"]
|
|
101
|
+
for term_prefix in _TERMINAL_CMDS:
|
|
102
|
+
cmd = term_prefix + skchat_cmd
|
|
103
|
+
try:
|
|
104
|
+
subprocess.Popen(
|
|
105
|
+
cmd,
|
|
106
|
+
stdout=subprocess.DEVNULL,
|
|
107
|
+
stderr=subprocess.DEVNULL,
|
|
108
|
+
)
|
|
109
|
+
logger.debug("Opened skchat terminal with: %s", cmd)
|
|
110
|
+
return
|
|
111
|
+
except FileNotFoundError:
|
|
112
|
+
continue
|
|
113
|
+
except Exception as exc:
|
|
114
|
+
logger.debug("Terminal launch error (%s): %s", cmd[0], exc)
|
|
115
|
+
continue
|
|
116
|
+
logger.debug("No terminal emulator found; cannot open skchat session")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# Urgency map for notify-send
|
|
120
|
+
_NOTIFY_SEND_URGENCY = {
|
|
121
|
+
"low": "low",
|
|
122
|
+
"normal": "normal",
|
|
123
|
+
"critical": "critical",
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class NotificationManager:
|
|
128
|
+
"""Send desktop notifications with debounce protection.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
debounce_seconds: Minimum seconds between notifications (default 5).
|
|
132
|
+
dashboard_url: URL opened by the "Open Dashboard" action button.
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
def __init__(
|
|
136
|
+
self,
|
|
137
|
+
debounce_seconds: float = 5.0,
|
|
138
|
+
dashboard_url: str = _DEFAULT_DASHBOARD_URL,
|
|
139
|
+
) -> None:
|
|
140
|
+
self._debounce_seconds = debounce_seconds
|
|
141
|
+
self._dashboard_url = dashboard_url
|
|
142
|
+
self._last_sent: float = 0.0
|
|
143
|
+
self._system = platform.system() # "Linux", "Darwin", "Windows"
|
|
144
|
+
# GLib main-loop plumbing (created lazily, shared across notifications)
|
|
145
|
+
self._glib_loop: object | None = None
|
|
146
|
+
self._glib_thread: threading.Thread | None = None
|
|
147
|
+
|
|
148
|
+
# ------------------------------------------------------------------
|
|
149
|
+
# Public API
|
|
150
|
+
# ------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
def notify(
|
|
153
|
+
self,
|
|
154
|
+
title: str,
|
|
155
|
+
body: str,
|
|
156
|
+
urgency: str = "normal",
|
|
157
|
+
) -> bool:
|
|
158
|
+
"""Send a desktop notification.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
title: Notification title.
|
|
162
|
+
body: Notification body text.
|
|
163
|
+
urgency: "low", "normal", or "critical".
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
True if the notification was dispatched, False if debounced
|
|
167
|
+
or no notification system is available.
|
|
168
|
+
"""
|
|
169
|
+
now = time.monotonic()
|
|
170
|
+
if now - self._last_sent < self._debounce_seconds:
|
|
171
|
+
logger.debug(
|
|
172
|
+
"Notification debounced (%.1fs since last send)",
|
|
173
|
+
now - self._last_sent,
|
|
174
|
+
)
|
|
175
|
+
return False
|
|
176
|
+
|
|
177
|
+
dispatched = False
|
|
178
|
+
if self._system == "Linux":
|
|
179
|
+
dispatched = self._notify_linux_gi(title, body, urgency)
|
|
180
|
+
if not dispatched:
|
|
181
|
+
dispatched = self._notify_linux(title, body, urgency)
|
|
182
|
+
elif self._system == "Darwin":
|
|
183
|
+
dispatched = self._notify_macos(title, body)
|
|
184
|
+
else:
|
|
185
|
+
logger.debug("Desktop notifications not supported on %s", self._system)
|
|
186
|
+
return False
|
|
187
|
+
|
|
188
|
+
if dispatched:
|
|
189
|
+
self._last_sent = time.monotonic()
|
|
190
|
+
_store_notification_memory(title, body, urgency)
|
|
191
|
+
return dispatched
|
|
192
|
+
|
|
193
|
+
# ------------------------------------------------------------------
|
|
194
|
+
# GLib main loop (needed for gi.Notify action callbacks)
|
|
195
|
+
# ------------------------------------------------------------------
|
|
196
|
+
|
|
197
|
+
def _ensure_glib_loop(self) -> None:
|
|
198
|
+
"""Start a GLib main loop in a daemon thread (idempotent)."""
|
|
199
|
+
if (
|
|
200
|
+
self._glib_loop is not None
|
|
201
|
+
and self._glib_thread is not None
|
|
202
|
+
and self._glib_thread.is_alive()
|
|
203
|
+
):
|
|
204
|
+
return
|
|
205
|
+
try:
|
|
206
|
+
from gi.repository import GLib # type: ignore[import-untyped]
|
|
207
|
+
|
|
208
|
+
loop = GLib.MainLoop()
|
|
209
|
+
self._glib_loop = loop
|
|
210
|
+
|
|
211
|
+
def _run() -> None:
|
|
212
|
+
loop.run()
|
|
213
|
+
|
|
214
|
+
t = threading.Thread(
|
|
215
|
+
target=_run,
|
|
216
|
+
daemon=True,
|
|
217
|
+
name="skcapstone-glib-loop",
|
|
218
|
+
)
|
|
219
|
+
t.start()
|
|
220
|
+
self._glib_thread = t
|
|
221
|
+
logger.debug("GLib main loop started in daemon thread")
|
|
222
|
+
except Exception as exc:
|
|
223
|
+
logger.debug("Could not start GLib main loop: %s", exc)
|
|
224
|
+
|
|
225
|
+
# ------------------------------------------------------------------
|
|
226
|
+
# Platform implementations
|
|
227
|
+
# ------------------------------------------------------------------
|
|
228
|
+
|
|
229
|
+
def _notify_linux_gi(self, title: str, body: str, urgency: str) -> bool:
|
|
230
|
+
"""Send via gi.repository.Notify with GLib action callbacks.
|
|
231
|
+
|
|
232
|
+
Adds two action buttons:
|
|
233
|
+
- "Open Dashboard" → xdg-open dashboard URL + stores click event
|
|
234
|
+
- "Open SKChat" → open skchat watch in terminal + stores click event
|
|
235
|
+
|
|
236
|
+
Falls back gracefully (returns False) if gi is not importable.
|
|
237
|
+
"""
|
|
238
|
+
try:
|
|
239
|
+
import gi # type: ignore[import-untyped]
|
|
240
|
+
|
|
241
|
+
gi.require_version("Notify", "0.7")
|
|
242
|
+
from gi.repository import Notify # type: ignore[import-untyped]
|
|
243
|
+
except (ImportError, ValueError) as exc:
|
|
244
|
+
logger.debug("gi.repository.Notify unavailable: %s", exc)
|
|
245
|
+
return False
|
|
246
|
+
|
|
247
|
+
try:
|
|
248
|
+
if not Notify.is_initted():
|
|
249
|
+
Notify.init("skcapstone")
|
|
250
|
+
|
|
251
|
+
_urgency_map = {
|
|
252
|
+
"low": Notify.Urgency.LOW,
|
|
253
|
+
"normal": Notify.Urgency.NORMAL,
|
|
254
|
+
"critical": Notify.Urgency.CRITICAL,
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
n = Notify.Notification.new(title, body, "dialog-information")
|
|
258
|
+
n.set_urgency(_urgency_map.get(urgency, Notify.Urgency.NORMAL))
|
|
259
|
+
|
|
260
|
+
dashboard_url = self._dashboard_url
|
|
261
|
+
|
|
262
|
+
def _on_open_dashboard(
|
|
263
|
+
notification: object, action: str, user_data: object
|
|
264
|
+
) -> None:
|
|
265
|
+
logger.debug("Notification action invoked: open-dashboard")
|
|
266
|
+
_store_click_event("open-dashboard", dashboard_url)
|
|
267
|
+
try:
|
|
268
|
+
subprocess.Popen(
|
|
269
|
+
["xdg-open", dashboard_url],
|
|
270
|
+
stdout=subprocess.DEVNULL,
|
|
271
|
+
stderr=subprocess.DEVNULL,
|
|
272
|
+
)
|
|
273
|
+
except Exception as exc:
|
|
274
|
+
logger.debug("xdg-open failed: %s", exc)
|
|
275
|
+
|
|
276
|
+
def _on_open_skchat(
|
|
277
|
+
notification: object, action: str, user_data: object
|
|
278
|
+
) -> None:
|
|
279
|
+
logger.debug("Notification action invoked: open-skchat")
|
|
280
|
+
_store_click_event("open-skchat", "skchat watch")
|
|
281
|
+
_open_skchat_terminal()
|
|
282
|
+
|
|
283
|
+
n.add_action(
|
|
284
|
+
"open-dashboard",
|
|
285
|
+
"Open Dashboard",
|
|
286
|
+
_on_open_dashboard,
|
|
287
|
+
None,
|
|
288
|
+
)
|
|
289
|
+
n.add_action(
|
|
290
|
+
"open-skchat",
|
|
291
|
+
"Open SKChat",
|
|
292
|
+
_on_open_skchat,
|
|
293
|
+
None,
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
# GLib main loop must be running to deliver action callbacks
|
|
297
|
+
self._ensure_glib_loop()
|
|
298
|
+
|
|
299
|
+
n.show()
|
|
300
|
+
logger.debug("gi.Notify dispatched: %r / %r", title, body)
|
|
301
|
+
return True
|
|
302
|
+
|
|
303
|
+
except Exception as exc:
|
|
304
|
+
logger.debug("gi.Notify error: %s", exc)
|
|
305
|
+
return False
|
|
306
|
+
|
|
307
|
+
def _notify_linux(self, title: str, body: str, urgency: str) -> bool:
|
|
308
|
+
"""Send via notify-send (libnotify subprocess fallback)."""
|
|
309
|
+
urgency_arg = _NOTIFY_SEND_URGENCY.get(urgency, "normal")
|
|
310
|
+
try:
|
|
311
|
+
subprocess.run(
|
|
312
|
+
["notify-send", "--urgency", urgency_arg, title, body],
|
|
313
|
+
check=True,
|
|
314
|
+
capture_output=True,
|
|
315
|
+
timeout=5,
|
|
316
|
+
)
|
|
317
|
+
logger.debug("notify-send dispatched: %r / %r", title, body)
|
|
318
|
+
return True
|
|
319
|
+
except FileNotFoundError:
|
|
320
|
+
logger.debug("notify-send not found — desktop notifications unavailable")
|
|
321
|
+
return False
|
|
322
|
+
except subprocess.CalledProcessError as exc:
|
|
323
|
+
logger.debug("notify-send failed (rc=%d): %s", exc.returncode, exc.stderr)
|
|
324
|
+
return False
|
|
325
|
+
except subprocess.TimeoutExpired:
|
|
326
|
+
logger.debug("notify-send timed out")
|
|
327
|
+
return False
|
|
328
|
+
except Exception as exc:
|
|
329
|
+
logger.debug("notify-send unexpected error: %s", exc)
|
|
330
|
+
return False
|
|
331
|
+
|
|
332
|
+
def _notify_macos(self, title: str, body: str) -> bool:
|
|
333
|
+
"""Send via osascript (macOS Notification Center)."""
|
|
334
|
+
# Escape single quotes to prevent injection through osascript
|
|
335
|
+
safe_title = title.replace("\\", "\\\\").replace('"', '\\"')
|
|
336
|
+
safe_body = body.replace("\\", "\\\\").replace('"', '\\"')
|
|
337
|
+
script = (
|
|
338
|
+
f'display notification "{safe_body}" with title "{safe_title}"'
|
|
339
|
+
)
|
|
340
|
+
try:
|
|
341
|
+
subprocess.run(
|
|
342
|
+
["osascript", "-e", script],
|
|
343
|
+
check=True,
|
|
344
|
+
capture_output=True,
|
|
345
|
+
timeout=5,
|
|
346
|
+
)
|
|
347
|
+
logger.debug("osascript dispatched: %r / %r", title, body)
|
|
348
|
+
return True
|
|
349
|
+
except FileNotFoundError:
|
|
350
|
+
logger.debug("osascript not found — desktop notifications unavailable")
|
|
351
|
+
return False
|
|
352
|
+
except subprocess.CalledProcessError as exc:
|
|
353
|
+
logger.debug("osascript failed (rc=%d): %s", exc.returncode, exc.stderr)
|
|
354
|
+
return False
|
|
355
|
+
except subprocess.TimeoutExpired:
|
|
356
|
+
logger.debug("osascript timed out")
|
|
357
|
+
return False
|
|
358
|
+
except Exception as exc:
|
|
359
|
+
logger.debug("osascript unexpected error: %s", exc)
|
|
360
|
+
return False
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
# ---------------------------------------------------------------------------
|
|
364
|
+
# Module-level singleton (lazy, shared across the process)
|
|
365
|
+
# ---------------------------------------------------------------------------
|
|
366
|
+
|
|
367
|
+
_manager: Optional[NotificationManager] = None
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def get_manager() -> NotificationManager:
|
|
371
|
+
"""Return the module-level NotificationManager singleton."""
|
|
372
|
+
global _manager
|
|
373
|
+
if _manager is None:
|
|
374
|
+
_manager = NotificationManager()
|
|
375
|
+
return _manager
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def notify(title: str, body: str, urgency: str = "normal") -> bool:
|
|
379
|
+
"""Convenience wrapper — send a notification via the singleton manager."""
|
|
380
|
+
return get_manager().notify(title, body, urgency)
|