@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,164 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Blueprint Registry — discovers, validates, and loads team blueprints.
|
|
3
|
+
|
|
4
|
+
Searches three locations in priority order:
|
|
5
|
+
1. User blueprints: ~/.skcapstone/blueprints/teams/
|
|
6
|
+
2. Vault blueprints: ~/.skcapstone/vaults/blueprints/teams/ (synced via skref)
|
|
7
|
+
3. Built-in blueprints: shipped with the skcapstone package
|
|
8
|
+
|
|
9
|
+
This follows the filesystem-context skill pattern: use the filesystem
|
|
10
|
+
as the source of truth, keep it simple, add sophistication later.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import logging
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Dict, List, Optional
|
|
18
|
+
|
|
19
|
+
import yaml
|
|
20
|
+
|
|
21
|
+
from .schema import BlueprintManifest
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
# Built-in blueprints ship alongside this module
|
|
26
|
+
_BUILTIN_DIR = Path(__file__).parent / "builtins"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class BlueprintRegistry:
|
|
30
|
+
"""Discovers and manages agent team blueprints.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
home: Agent home directory (default ~/.skcapstone).
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, home: Optional[Path] = None) -> None:
|
|
37
|
+
self._home = (home or Path("~/.skcapstone")).expanduser()
|
|
38
|
+
self._cache: Dict[str, BlueprintManifest] = {}
|
|
39
|
+
|
|
40
|
+
# ------------------------------------------------------------------
|
|
41
|
+
# Discovery paths
|
|
42
|
+
# ------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def _search_paths(self) -> List[Path]:
|
|
46
|
+
"""Return blueprint directories in priority order."""
|
|
47
|
+
return [
|
|
48
|
+
self._home / "blueprints" / "teams",
|
|
49
|
+
self._home / "vaults" / "blueprints" / "teams",
|
|
50
|
+
_BUILTIN_DIR,
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
# ------------------------------------------------------------------
|
|
54
|
+
# Public API
|
|
55
|
+
# ------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
def scan(self) -> Dict[str, BlueprintManifest]:
|
|
58
|
+
"""Scan all search paths and return discovered blueprints.
|
|
59
|
+
|
|
60
|
+
Later paths lose to earlier paths when slugs collide (user
|
|
61
|
+
overrides take priority over built-ins).
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Dict mapping slug to validated BlueprintManifest.
|
|
65
|
+
"""
|
|
66
|
+
found: Dict[str, BlueprintManifest] = {}
|
|
67
|
+
|
|
68
|
+
# Reverse so built-ins load first, then get overridden
|
|
69
|
+
for search_dir in reversed(self._search_paths):
|
|
70
|
+
if not search_dir.is_dir():
|
|
71
|
+
continue
|
|
72
|
+
for yaml_file in sorted(search_dir.glob("*.yaml")):
|
|
73
|
+
try:
|
|
74
|
+
bp = self._load_file(yaml_file)
|
|
75
|
+
found[bp.slug] = bp
|
|
76
|
+
except Exception as exc:
|
|
77
|
+
logger.warning("Skipping %s: %s", yaml_file, exc)
|
|
78
|
+
|
|
79
|
+
for yml_file in sorted(search_dir.glob("*.yml")):
|
|
80
|
+
try:
|
|
81
|
+
bp = self._load_file(yml_file)
|
|
82
|
+
found[bp.slug] = bp
|
|
83
|
+
except Exception as exc:
|
|
84
|
+
logger.warning("Skipping %s: %s", yml_file, exc)
|
|
85
|
+
|
|
86
|
+
self._cache = found
|
|
87
|
+
return found
|
|
88
|
+
|
|
89
|
+
def list_blueprints(self) -> List[BlueprintManifest]:
|
|
90
|
+
"""Return all discovered blueprints as a sorted list.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
List of BlueprintManifest objects sorted by name.
|
|
94
|
+
"""
|
|
95
|
+
if not self._cache:
|
|
96
|
+
self.scan()
|
|
97
|
+
return sorted(self._cache.values(), key=lambda b: b.name)
|
|
98
|
+
|
|
99
|
+
def get(self, slug: str) -> Optional[BlueprintManifest]:
|
|
100
|
+
"""Get a specific blueprint by slug.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
slug: The blueprint identifier.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
BlueprintManifest or None if not found.
|
|
107
|
+
"""
|
|
108
|
+
if not self._cache:
|
|
109
|
+
self.scan()
|
|
110
|
+
return self._cache.get(slug)
|
|
111
|
+
|
|
112
|
+
def save_blueprint(
|
|
113
|
+
self,
|
|
114
|
+
blueprint: BlueprintManifest,
|
|
115
|
+
location: str = "user",
|
|
116
|
+
) -> Path:
|
|
117
|
+
"""Save a blueprint to the user or vault directory.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
blueprint: The validated blueprint to save.
|
|
121
|
+
location: 'user' for ~/.skcapstone/blueprints/teams/,
|
|
122
|
+
'vault' for ~/.skcapstone/vaults/blueprints/teams/.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
Path to the written file.
|
|
126
|
+
"""
|
|
127
|
+
if location == "vault":
|
|
128
|
+
target_dir = self._home / "vaults" / "blueprints" / "teams"
|
|
129
|
+
else:
|
|
130
|
+
target_dir = self._home / "blueprints" / "teams"
|
|
131
|
+
|
|
132
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
133
|
+
target_file = target_dir / f"{blueprint.slug}.yaml"
|
|
134
|
+
|
|
135
|
+
data = blueprint.model_dump(mode="json", exclude_none=True)
|
|
136
|
+
target_file.write_text(
|
|
137
|
+
yaml.dump(data, default_flow_style=False, sort_keys=False),
|
|
138
|
+
encoding="utf-8",
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
self._cache[blueprint.slug] = blueprint
|
|
142
|
+
return target_file
|
|
143
|
+
|
|
144
|
+
# ------------------------------------------------------------------
|
|
145
|
+
# Internal
|
|
146
|
+
# ------------------------------------------------------------------
|
|
147
|
+
|
|
148
|
+
@staticmethod
|
|
149
|
+
def _load_file(path: Path) -> BlueprintManifest:
|
|
150
|
+
"""Parse and validate a single blueprint YAML file.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
path: Path to the YAML file.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Validated BlueprintManifest.
|
|
157
|
+
|
|
158
|
+
Raises:
|
|
159
|
+
ValueError: If the YAML is invalid or fails validation.
|
|
160
|
+
"""
|
|
161
|
+
raw = yaml.safe_load(path.read_text(encoding="utf-8"))
|
|
162
|
+
if not isinstance(raw, dict):
|
|
163
|
+
raise ValueError(f"Expected a YAML mapping, got {type(raw).__name__}")
|
|
164
|
+
return BlueprintManifest(**raw)
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pydantic models for Agent Team Blueprint definitions.
|
|
3
|
+
|
|
4
|
+
A BlueprintManifest defines a complete deployable team of AI agents,
|
|
5
|
+
including their roles, models, resource requirements, networking,
|
|
6
|
+
memory, and coordination settings. Provider-agnostic by design —
|
|
7
|
+
the same blueprint deploys to local processes, Proxmox LXCs,
|
|
8
|
+
Hetzner, AWS, GCP, or any future provider.
|
|
9
|
+
|
|
10
|
+
Architecture references:
|
|
11
|
+
- Context isolation per agent (multi-agent-patterns best practice)
|
|
12
|
+
- Tiered model strategy (fast/code/reason/nuance)
|
|
13
|
+
- Memory-systems: file-system -> vector -> graph progression
|
|
14
|
+
- Hosted-agents: pre-built images, warm pools, snapshot/restore
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from enum import Enum
|
|
20
|
+
from typing import Any, Dict, List, Optional
|
|
21
|
+
|
|
22
|
+
from pydantic import BaseModel, Field, field_validator
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# ---------------------------------------------------------------------------
|
|
26
|
+
# Enums
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
class ModelTier(str, Enum):
|
|
30
|
+
"""Model selection tiers aligned with agent framework best practices."""
|
|
31
|
+
|
|
32
|
+
FAST = "fast"
|
|
33
|
+
CODE = "code"
|
|
34
|
+
REASON = "reason"
|
|
35
|
+
NUANCE = "nuance"
|
|
36
|
+
LOCAL = "local"
|
|
37
|
+
CUSTOM = "custom"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ProviderType(str, Enum):
|
|
41
|
+
"""Infrastructure providers for agent deployment."""
|
|
42
|
+
|
|
43
|
+
LOCAL = "local"
|
|
44
|
+
PROXMOX = "proxmox"
|
|
45
|
+
HETZNER = "hetzner"
|
|
46
|
+
AWS = "aws"
|
|
47
|
+
GCP = "gcp"
|
|
48
|
+
DOCKER = "docker"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class VMType(str, Enum):
|
|
52
|
+
"""VM/container type for cloud/proxmox deployments."""
|
|
53
|
+
|
|
54
|
+
LXC = "lxc"
|
|
55
|
+
VM = "vm"
|
|
56
|
+
CONTAINER = "container"
|
|
57
|
+
PROCESS = "process"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class AgentRole(str, Enum):
|
|
61
|
+
"""Standard agent roles within a team."""
|
|
62
|
+
|
|
63
|
+
MANAGER = "manager"
|
|
64
|
+
WORKER = "worker"
|
|
65
|
+
RESEARCHER = "researcher"
|
|
66
|
+
CODER = "coder"
|
|
67
|
+
REVIEWER = "reviewer"
|
|
68
|
+
DOCUMENTARIAN = "documentarian"
|
|
69
|
+
SECURITY = "security"
|
|
70
|
+
OPS = "ops"
|
|
71
|
+
CUSTOM = "custom"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# ---------------------------------------------------------------------------
|
|
75
|
+
# Sub-models
|
|
76
|
+
# ---------------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
class ResourceSpec(BaseModel):
|
|
79
|
+
"""Compute resources allocated to an agent."""
|
|
80
|
+
|
|
81
|
+
memory: str = Field(default="2g", description="RAM allocation (e.g. '2g', '512m')")
|
|
82
|
+
cores: int = Field(default=1, ge=1, le=128, description="CPU cores")
|
|
83
|
+
disk: str = Field(default="10g", description="Disk allocation")
|
|
84
|
+
gpu: Optional[str] = Field(default=None, description="GPU type if needed")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class AgentSpec(BaseModel):
|
|
88
|
+
"""Specification for a single agent within a team blueprint.
|
|
89
|
+
|
|
90
|
+
Each agent gets its own context window (context isolation principle),
|
|
91
|
+
its own model tier, its own soul blueprint, and a defined skill set.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
role: AgentRole = Field(default=AgentRole.WORKER, description="Functional role")
|
|
95
|
+
model: ModelTier = Field(default=ModelTier.FAST, description="Model tier")
|
|
96
|
+
model_name: Optional[str] = Field(
|
|
97
|
+
default=None,
|
|
98
|
+
description="Specific model override (e.g. 'kimi-k2.5', 'minimax-m2.1')",
|
|
99
|
+
)
|
|
100
|
+
vm_type: VMType = Field(default=VMType.PROCESS, description="Execution environment")
|
|
101
|
+
resources: ResourceSpec = Field(default_factory=ResourceSpec)
|
|
102
|
+
soul_blueprint: Optional[str] = Field(
|
|
103
|
+
default=None,
|
|
104
|
+
description="Path to soul blueprint YAML (e.g. 'souls/sentinel.yaml')",
|
|
105
|
+
)
|
|
106
|
+
skills: List[str] = Field(default_factory=list, description="Skill names")
|
|
107
|
+
depends_on: List[str] = Field(
|
|
108
|
+
default_factory=list,
|
|
109
|
+
description="Other agents this one depends on being ready first",
|
|
110
|
+
)
|
|
111
|
+
env: Dict[str, str] = Field(
|
|
112
|
+
default_factory=dict,
|
|
113
|
+
description="Extra environment variables for this agent",
|
|
114
|
+
)
|
|
115
|
+
description: Optional[str] = Field(default=None, description="What this agent does")
|
|
116
|
+
count: int = Field(
|
|
117
|
+
default=1, ge=1, le=50,
|
|
118
|
+
description="Number of instances of this agent to spawn",
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class NetworkConfig(BaseModel):
|
|
123
|
+
"""Networking configuration for the team."""
|
|
124
|
+
|
|
125
|
+
mesh_vpn: str = Field(default="tailscale", description="VPN mesh provider")
|
|
126
|
+
discovery: str = Field(
|
|
127
|
+
default="skref_registry",
|
|
128
|
+
description="How agents discover each other",
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class StorageConfig(BaseModel):
|
|
133
|
+
"""Storage and memory configuration for the team."""
|
|
134
|
+
|
|
135
|
+
skref_vault: Optional[str] = Field(
|
|
136
|
+
default=None,
|
|
137
|
+
description="Shared vault name for the team",
|
|
138
|
+
)
|
|
139
|
+
# Supported backends: "filesystem" (default, no deps) and "skvector" (via skmemory).
|
|
140
|
+
# "mem0" and "zep" are not yet implemented — no adapter classes exist.
|
|
141
|
+
memory_backend: str = Field(
|
|
142
|
+
default="filesystem",
|
|
143
|
+
description="Memory backend: filesystem, skvector",
|
|
144
|
+
)
|
|
145
|
+
memory_sync: bool = Field(
|
|
146
|
+
default=True,
|
|
147
|
+
description="Auto-sync agent memories to shared storage",
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class CoordinationConfig(BaseModel):
|
|
152
|
+
"""How the team coordinates internally."""
|
|
153
|
+
|
|
154
|
+
queen: Optional[str] = Field(
|
|
155
|
+
default=None,
|
|
156
|
+
description="Managing agent (e.g. 'lumina')",
|
|
157
|
+
)
|
|
158
|
+
pattern: str = Field(
|
|
159
|
+
default="supervisor",
|
|
160
|
+
description="Architecture: supervisor, peer-to-peer, hierarchical",
|
|
161
|
+
)
|
|
162
|
+
heartbeat: str = Field(default="30m", description="Health check interval")
|
|
163
|
+
escalation: Optional[str] = Field(
|
|
164
|
+
default=None,
|
|
165
|
+
description="Who to escalate critical issues to",
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# ---------------------------------------------------------------------------
|
|
170
|
+
# Top-level Blueprint
|
|
171
|
+
# ---------------------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
class BlueprintManifest(BaseModel):
|
|
174
|
+
"""Complete definition of a deployable agent team.
|
|
175
|
+
|
|
176
|
+
This is the YAML schema that users select from the blueprint store.
|
|
177
|
+
It contains everything needed to spin up a coordinated team of AI
|
|
178
|
+
agents on any supported infrastructure provider.
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
name: str = Field(description="Human-readable team name")
|
|
182
|
+
slug: str = Field(description="URL/filesystem-safe identifier")
|
|
183
|
+
version: str = Field(default="1.0.0")
|
|
184
|
+
description: str = Field(description="What this team does")
|
|
185
|
+
icon: str = Field(default="🤖", description="Display emoji")
|
|
186
|
+
author: str = Field(default="smilinTux")
|
|
187
|
+
|
|
188
|
+
agents: Dict[str, AgentSpec] = Field(
|
|
189
|
+
description="Named agents in this team (key = agent name)",
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
default_provider: ProviderType = Field(
|
|
193
|
+
default=ProviderType.LOCAL,
|
|
194
|
+
description="Default infrastructure provider",
|
|
195
|
+
)
|
|
196
|
+
network: NetworkConfig = Field(default_factory=NetworkConfig)
|
|
197
|
+
storage: StorageConfig = Field(default_factory=StorageConfig)
|
|
198
|
+
coordination: CoordinationConfig = Field(default_factory=CoordinationConfig)
|
|
199
|
+
|
|
200
|
+
tags: List[str] = Field(default_factory=list)
|
|
201
|
+
estimated_cost: Optional[str] = Field(
|
|
202
|
+
default=None,
|
|
203
|
+
description="Estimated monthly cost (e.g. '$12/mo compute')",
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
@field_validator("slug")
|
|
207
|
+
@classmethod
|
|
208
|
+
def slug_must_be_clean(cls, v: str) -> str:
|
|
209
|
+
"""Ensure slug is filesystem/URL safe."""
|
|
210
|
+
import re
|
|
211
|
+
if not re.match(r"^[a-z0-9][a-z0-9\-]*[a-z0-9]$", v):
|
|
212
|
+
raise ValueError(
|
|
213
|
+
f"slug must be lowercase alphanumeric with hyphens: got '{v}'"
|
|
214
|
+
)
|
|
215
|
+
return v
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def agent_count(self) -> int:
|
|
219
|
+
"""Total number of agent instances in this blueprint."""
|
|
220
|
+
return sum(spec.count for spec in self.agents.values())
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def model_summary(self) -> str:
|
|
224
|
+
"""Comma-separated list of model tiers used."""
|
|
225
|
+
tiers = sorted({
|
|
226
|
+
spec.model_name or spec.model.value
|
|
227
|
+
for spec in self.agents.values()
|
|
228
|
+
})
|
|
229
|
+
return ", ".join(tiers)
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Changelog Generator — auto-document the Kingdom's progress.
|
|
3
|
+
|
|
4
|
+
Reads the coordination board's completed tasks and generates
|
|
5
|
+
a structured CHANGELOG.md grouped by date and category. Every
|
|
6
|
+
completed task becomes a line item in the project's history.
|
|
7
|
+
|
|
8
|
+
The board IS the changelog. No separate tracking needed.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import re
|
|
15
|
+
from collections import defaultdict
|
|
16
|
+
from datetime import datetime, timezone
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Optional
|
|
19
|
+
|
|
20
|
+
from .coordination import Board, TaskStatus
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
TAG_CATEGORIES = {
|
|
24
|
+
"feature": ["skcapstone", "skchat", "skcomm", "skmemory", "capauth", "cloud9", "skworld"],
|
|
25
|
+
"security": ["security", "encryption", "capauth", "integrity", "quantum-resistant", "pgp"],
|
|
26
|
+
"infrastructure": ["ci", "docker", "systemd", "daemon", "syncthing", "pypi", "packaging"],
|
|
27
|
+
"documentation": ["documentation", "docs", "readme", "quickstart", "api"],
|
|
28
|
+
"testing": ["testing", "integration", "e2e", "pytest"],
|
|
29
|
+
"ux": ["cli", "repl", "dashboard", "interactive", "rich"],
|
|
30
|
+
"p2p": ["p2p", "nostr", "mesh", "discovery", "transport"],
|
|
31
|
+
"emotional": ["cloud9", "soul", "trust", "feb", "emotional", "seeds", "anchor"],
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _categorize(tags: list[str]) -> str:
|
|
36
|
+
"""Determine the changelog category from task tags.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
tags: Task tags list.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Category string (e.g., 'feature', 'security', 'infrastructure').
|
|
43
|
+
"""
|
|
44
|
+
tag_set = set(t.lower() for t in tags)
|
|
45
|
+
best_category = "other"
|
|
46
|
+
best_score = 0
|
|
47
|
+
|
|
48
|
+
for category, keywords in TAG_CATEGORIES.items():
|
|
49
|
+
score = len(tag_set.intersection(keywords))
|
|
50
|
+
if score > best_score:
|
|
51
|
+
best_score = score
|
|
52
|
+
best_category = category
|
|
53
|
+
|
|
54
|
+
return best_category
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _parse_date(iso_str: str) -> str:
|
|
58
|
+
"""Extract YYYY-MM-DD from an ISO timestamp.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
iso_str: ISO 8601 datetime string.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Date string like '2026-02-24'.
|
|
65
|
+
"""
|
|
66
|
+
try:
|
|
67
|
+
match = re.match(r"(\d{4}-\d{2}-\d{2})", iso_str)
|
|
68
|
+
if match:
|
|
69
|
+
return match.group(1)
|
|
70
|
+
except (TypeError, ValueError):
|
|
71
|
+
pass
|
|
72
|
+
return datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def generate_changelog(
|
|
76
|
+
home: Path,
|
|
77
|
+
title: str = "SKCapstone Changelog",
|
|
78
|
+
include_agents: bool = True,
|
|
79
|
+
) -> str:
|
|
80
|
+
"""Generate a CHANGELOG.md from completed board tasks.
|
|
81
|
+
|
|
82
|
+
Groups tasks by date and category, with agent attribution.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
home: Path to ~/.skcapstone.
|
|
86
|
+
title: Changelog title.
|
|
87
|
+
include_agents: Whether to show who completed each task.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Markdown string for the changelog.
|
|
91
|
+
"""
|
|
92
|
+
board = Board(home)
|
|
93
|
+
views = board.get_task_views()
|
|
94
|
+
agents = board.load_agents()
|
|
95
|
+
|
|
96
|
+
completed = [v for v in views if v.status == TaskStatus.DONE]
|
|
97
|
+
|
|
98
|
+
completed_by_agent: dict[str, list[str]] = defaultdict(list)
|
|
99
|
+
for a in agents:
|
|
100
|
+
for tid in a.completed_tasks:
|
|
101
|
+
completed_by_agent[tid].append(a.agent)
|
|
102
|
+
|
|
103
|
+
by_date: dict[str, list[dict]] = defaultdict(list)
|
|
104
|
+
for v in completed:
|
|
105
|
+
t = v.task
|
|
106
|
+
date = _parse_date(t.created_at)
|
|
107
|
+
category = _categorize(t.tags)
|
|
108
|
+
who = completed_by_agent.get(t.id, [v.claimed_by] if v.claimed_by else ["unknown"])
|
|
109
|
+
|
|
110
|
+
by_date[date].append({
|
|
111
|
+
"id": t.id,
|
|
112
|
+
"title": t.title,
|
|
113
|
+
"category": category,
|
|
114
|
+
"tags": t.tags,
|
|
115
|
+
"agents": who,
|
|
116
|
+
"priority": t.priority.value,
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
lines = [
|
|
120
|
+
f"# {title}",
|
|
121
|
+
"",
|
|
122
|
+
f"*Auto-generated from the coordination board — {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}*",
|
|
123
|
+
"",
|
|
124
|
+
f"**Total completed: {len(completed)}** across {len(set(a.agent for a in agents))} agents",
|
|
125
|
+
"",
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
category_icons = {
|
|
129
|
+
"feature": "NEW",
|
|
130
|
+
"security": "SEC",
|
|
131
|
+
"infrastructure": "OPS",
|
|
132
|
+
"documentation": "DOC",
|
|
133
|
+
"testing": "TST",
|
|
134
|
+
"ux": "UX",
|
|
135
|
+
"p2p": "P2P",
|
|
136
|
+
"emotional": "SOUL",
|
|
137
|
+
"other": "---",
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
for date in sorted(by_date.keys(), reverse=True):
|
|
141
|
+
tasks = by_date[date]
|
|
142
|
+
lines.append(f"## {date}")
|
|
143
|
+
lines.append("")
|
|
144
|
+
|
|
145
|
+
by_cat: dict[str, list[dict]] = defaultdict(list)
|
|
146
|
+
for task in tasks:
|
|
147
|
+
by_cat[task["category"]].append(task)
|
|
148
|
+
|
|
149
|
+
for cat in ["feature", "security", "p2p", "emotional", "ux", "infrastructure", "testing", "documentation", "other"]:
|
|
150
|
+
if cat not in by_cat:
|
|
151
|
+
continue
|
|
152
|
+
icon = category_icons.get(cat, "---")
|
|
153
|
+
lines.append(f"### [{icon}] {cat.title()}")
|
|
154
|
+
lines.append("")
|
|
155
|
+
for task in by_cat[cat]:
|
|
156
|
+
agent_str = f" (@{', @'.join(task['agents'])})" if include_agents and task["agents"] else ""
|
|
157
|
+
lines.append(f"- **{task['title']}**{agent_str}")
|
|
158
|
+
lines.append("")
|
|
159
|
+
|
|
160
|
+
lines.append("---")
|
|
161
|
+
lines.append("")
|
|
162
|
+
lines.append("*Built by the Pengu Nation — staycuriousANDkeepsmilin*")
|
|
163
|
+
|
|
164
|
+
return "\n".join(lines)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def write_changelog(home: Path, output: Optional[Path] = None) -> Path:
|
|
168
|
+
"""Generate and write CHANGELOG.md.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
home: Path to ~/.skcapstone.
|
|
172
|
+
output: Output file path. Defaults to project root CHANGELOG.md.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Path to the written file.
|
|
176
|
+
"""
|
|
177
|
+
content = generate_changelog(home)
|
|
178
|
+
out_path = output or Path.cwd() / "CHANGELOG.md"
|
|
179
|
+
out_path.write_text(content, encoding="utf-8")
|
|
180
|
+
return out_path
|