@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,544 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Sub-agent Spawner — spin up task-specific agents on correct nodes.
|
|
3
|
+
|
|
4
|
+
Unlike the TeamEngine which deploys full teams from blueprints, the
|
|
5
|
+
spawner creates lightweight single-purpose agents for specific tasks.
|
|
6
|
+
It auto-selects the right model tier and role based on the task
|
|
7
|
+
description, then provisions via the appropriate provider.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
spawner = SubAgentSpawner(home=Path("~/.skcapstone"))
|
|
11
|
+
result = spawner.spawn(
|
|
12
|
+
task="Write unit tests for the capauth login flow",
|
|
13
|
+
provider=ProviderType.LOCAL,
|
|
14
|
+
)
|
|
15
|
+
# result.agent_name, result.deployment_id, result.status
|
|
16
|
+
|
|
17
|
+
The spawner integrates with the coordination board to optionally
|
|
18
|
+
claim tasks for spawned agents and with the trustee audit log for
|
|
19
|
+
transparency.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import logging
|
|
25
|
+
import time
|
|
26
|
+
from datetime import datetime, timezone
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
from typing import Any, Dict, List, Optional
|
|
29
|
+
|
|
30
|
+
from pydantic import BaseModel, Field
|
|
31
|
+
|
|
32
|
+
from .blueprints.schema import (
|
|
33
|
+
AgentRole,
|
|
34
|
+
AgentSpec,
|
|
35
|
+
BlueprintManifest,
|
|
36
|
+
CoordinationConfig,
|
|
37
|
+
ModelTier,
|
|
38
|
+
NetworkConfig,
|
|
39
|
+
ProviderType,
|
|
40
|
+
ResourceSpec,
|
|
41
|
+
StorageConfig,
|
|
42
|
+
VMType,
|
|
43
|
+
)
|
|
44
|
+
from .team_engine import AgentStatus, DeployedAgent, ProviderBackend, TeamEngine
|
|
45
|
+
|
|
46
|
+
logger = logging.getLogger(__name__)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
# Task classification
|
|
51
|
+
# ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
# Keywords mapped to (role, model_tier) tuples for auto-detection
|
|
54
|
+
_TASK_ROLE_MAP: Dict[str, tuple[AgentRole, ModelTier]] = {
|
|
55
|
+
"test": (AgentRole.CODER, ModelTier.CODE),
|
|
56
|
+
"unit test": (AgentRole.CODER, ModelTier.CODE),
|
|
57
|
+
"debug": (AgentRole.CODER, ModelTier.CODE),
|
|
58
|
+
"fix bug": (AgentRole.CODER, ModelTier.CODE),
|
|
59
|
+
"implement": (AgentRole.CODER, ModelTier.CODE),
|
|
60
|
+
"refactor": (AgentRole.CODER, ModelTier.CODE),
|
|
61
|
+
"code review": (AgentRole.REVIEWER, ModelTier.REASON),
|
|
62
|
+
"review": (AgentRole.REVIEWER, ModelTier.REASON),
|
|
63
|
+
"architecture": (AgentRole.REVIEWER, ModelTier.REASON),
|
|
64
|
+
"design": (AgentRole.REVIEWER, ModelTier.REASON),
|
|
65
|
+
"plan": (AgentRole.REVIEWER, ModelTier.REASON),
|
|
66
|
+
"research": (AgentRole.RESEARCHER, ModelTier.REASON),
|
|
67
|
+
"analyze": (AgentRole.RESEARCHER, ModelTier.REASON),
|
|
68
|
+
"investigate": (AgentRole.RESEARCHER, ModelTier.REASON),
|
|
69
|
+
"explore": (AgentRole.RESEARCHER, ModelTier.FAST),
|
|
70
|
+
"document": (AgentRole.DOCUMENTARIAN, ModelTier.FAST),
|
|
71
|
+
"write docs": (AgentRole.DOCUMENTARIAN, ModelTier.FAST),
|
|
72
|
+
"readme": (AgentRole.DOCUMENTARIAN, ModelTier.FAST),
|
|
73
|
+
"changelog": (AgentRole.DOCUMENTARIAN, ModelTier.FAST),
|
|
74
|
+
"security audit": (AgentRole.SECURITY, ModelTier.REASON),
|
|
75
|
+
"vulnerability": (AgentRole.SECURITY, ModelTier.REASON),
|
|
76
|
+
"scan": (AgentRole.SECURITY, ModelTier.FAST),
|
|
77
|
+
"deploy": (AgentRole.OPS, ModelTier.FAST),
|
|
78
|
+
"monitor": (AgentRole.OPS, ModelTier.FAST),
|
|
79
|
+
"backup": (AgentRole.OPS, ModelTier.FAST),
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def classify_task(description: str) -> tuple[AgentRole, ModelTier]:
|
|
84
|
+
"""Determine the best agent role and model tier for a task description.
|
|
85
|
+
|
|
86
|
+
Scans the description for known keywords and returns the most specific
|
|
87
|
+
match. Falls back to (WORKER, FAST) if nothing matches.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
description: Free-text task description.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Tuple of (AgentRole, ModelTier).
|
|
94
|
+
"""
|
|
95
|
+
desc_lower = description.lower()
|
|
96
|
+
|
|
97
|
+
# Try multi-word patterns first (more specific)
|
|
98
|
+
for pattern in sorted(_TASK_ROLE_MAP.keys(), key=len, reverse=True):
|
|
99
|
+
if pattern in desc_lower:
|
|
100
|
+
return _TASK_ROLE_MAP[pattern]
|
|
101
|
+
|
|
102
|
+
return (AgentRole.WORKER, ModelTier.FAST)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# ---------------------------------------------------------------------------
|
|
106
|
+
# Node selection
|
|
107
|
+
# ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
class NodeInfo(BaseModel):
|
|
110
|
+
"""Describes an available deployment target node."""
|
|
111
|
+
|
|
112
|
+
name: str
|
|
113
|
+
provider: ProviderType
|
|
114
|
+
host: str = "localhost"
|
|
115
|
+
capacity: float = Field(default=1.0, ge=0.0, le=1.0)
|
|
116
|
+
tags: List[str] = Field(default_factory=list)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def select_node(
|
|
120
|
+
nodes: List[NodeInfo],
|
|
121
|
+
role: AgentRole,
|
|
122
|
+
model: ModelTier,
|
|
123
|
+
preferred_provider: Optional[ProviderType] = None,
|
|
124
|
+
) -> NodeInfo:
|
|
125
|
+
"""Select the best node for a given agent role and model.
|
|
126
|
+
|
|
127
|
+
Selection criteria:
|
|
128
|
+
1. Preferred provider match
|
|
129
|
+
2. Highest available capacity
|
|
130
|
+
3. Tag affinity (e.g. "gpu" nodes for reason-tier models)
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
nodes: Available deployment nodes.
|
|
134
|
+
role: The agent's role.
|
|
135
|
+
model: The model tier required.
|
|
136
|
+
preferred_provider: If set, prefer nodes of this provider type.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
The selected NodeInfo.
|
|
140
|
+
"""
|
|
141
|
+
if not nodes:
|
|
142
|
+
return NodeInfo(name="local", provider=ProviderType.LOCAL)
|
|
143
|
+
|
|
144
|
+
scored: List[tuple[float, NodeInfo]] = []
|
|
145
|
+
for node in nodes:
|
|
146
|
+
score = node.capacity
|
|
147
|
+
|
|
148
|
+
if preferred_provider and node.provider == preferred_provider:
|
|
149
|
+
score += 2.0
|
|
150
|
+
|
|
151
|
+
if model in (ModelTier.REASON, ModelTier.NUANCE) and "gpu" in node.tags:
|
|
152
|
+
score += 1.0
|
|
153
|
+
|
|
154
|
+
if model == ModelTier.LOCAL and node.provider == ProviderType.LOCAL:
|
|
155
|
+
score += 1.5
|
|
156
|
+
|
|
157
|
+
scored.append((score, node))
|
|
158
|
+
|
|
159
|
+
scored.sort(key=lambda x: x[0], reverse=True)
|
|
160
|
+
return scored[0][1]
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# ---------------------------------------------------------------------------
|
|
164
|
+
# Spawn result
|
|
165
|
+
# ---------------------------------------------------------------------------
|
|
166
|
+
|
|
167
|
+
class SpawnResult(BaseModel):
|
|
168
|
+
"""Result of spawning a sub-agent."""
|
|
169
|
+
|
|
170
|
+
agent_name: str
|
|
171
|
+
deployment_id: str
|
|
172
|
+
status: AgentStatus
|
|
173
|
+
provider: ProviderType
|
|
174
|
+
host: str = "localhost"
|
|
175
|
+
pid: Optional[int] = None
|
|
176
|
+
role: AgentRole = AgentRole.WORKER
|
|
177
|
+
model: ModelTier = ModelTier.FAST
|
|
178
|
+
task_description: str = ""
|
|
179
|
+
coord_task_id: Optional[str] = None
|
|
180
|
+
spawned_at: str = Field(
|
|
181
|
+
default_factory=lambda: datetime.now(timezone.utc).isoformat()
|
|
182
|
+
)
|
|
183
|
+
error: Optional[str] = None
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# ---------------------------------------------------------------------------
|
|
187
|
+
# Sub-agent spawner
|
|
188
|
+
# ---------------------------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
class SubAgentSpawner:
|
|
191
|
+
"""Lightweight spawner for task-specific sub-agents.
|
|
192
|
+
|
|
193
|
+
Wraps TeamEngine to create single-agent deployments for specific tasks
|
|
194
|
+
without requiring a full blueprint. Integrates with the coordination
|
|
195
|
+
board and trustee audit trail.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
home: Agent home directory.
|
|
199
|
+
provider: Provider backend (defaults to LocalProvider if None).
|
|
200
|
+
nodes: Available deployment nodes for smart routing.
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
def __init__(
|
|
204
|
+
self,
|
|
205
|
+
home: Optional[Path] = None,
|
|
206
|
+
provider: Optional[ProviderBackend] = None,
|
|
207
|
+
nodes: Optional[List[NodeInfo]] = None,
|
|
208
|
+
) -> None:
|
|
209
|
+
self._home = (home or Path("~/.skcapstone")).expanduser()
|
|
210
|
+
self._provider = provider
|
|
211
|
+
self._nodes = nodes or []
|
|
212
|
+
self._engine = TeamEngine(
|
|
213
|
+
home=self._home,
|
|
214
|
+
provider=self._provider,
|
|
215
|
+
comms_root=self._home / "comms",
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
def _build_mini_blueprint(
|
|
219
|
+
self,
|
|
220
|
+
task: str,
|
|
221
|
+
role: AgentRole,
|
|
222
|
+
model: ModelTier,
|
|
223
|
+
skills: Optional[List[str]] = None,
|
|
224
|
+
soul_blueprint: Optional[str] = None,
|
|
225
|
+
) -> BlueprintManifest:
|
|
226
|
+
"""Create a minimal single-agent blueprint for a task.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
task: Task description (used for naming).
|
|
230
|
+
role: Agent role.
|
|
231
|
+
model: Model tier.
|
|
232
|
+
skills: Optional skill list.
|
|
233
|
+
soul_blueprint: Optional soul blueprint path.
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
A BlueprintManifest with one agent.
|
|
237
|
+
"""
|
|
238
|
+
slug = f"spawn-{role.value}-{int(time.time())}"
|
|
239
|
+
agent_key = f"{role.value}-agent"
|
|
240
|
+
|
|
241
|
+
spec = AgentSpec(
|
|
242
|
+
role=role,
|
|
243
|
+
model=model,
|
|
244
|
+
skills=skills or [],
|
|
245
|
+
soul_blueprint=soul_blueprint,
|
|
246
|
+
description=task[:200],
|
|
247
|
+
count=1,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
return BlueprintManifest(
|
|
251
|
+
name=f"Spawned {role.value} for: {task[:80]}",
|
|
252
|
+
slug=slug,
|
|
253
|
+
version="0.1.0",
|
|
254
|
+
description=task,
|
|
255
|
+
icon=_role_icon(role),
|
|
256
|
+
author="sub-agent-spawner",
|
|
257
|
+
agents={agent_key: spec},
|
|
258
|
+
default_provider=ProviderType.LOCAL,
|
|
259
|
+
network=NetworkConfig(
|
|
260
|
+
mesh_vpn="tailscale",
|
|
261
|
+
discovery="skref_registry",
|
|
262
|
+
),
|
|
263
|
+
storage=StorageConfig(
|
|
264
|
+
memory_backend="filesystem",
|
|
265
|
+
memory_sync=False,
|
|
266
|
+
),
|
|
267
|
+
coordination=CoordinationConfig(
|
|
268
|
+
pattern="peer-to-peer",
|
|
269
|
+
heartbeat="5m",
|
|
270
|
+
),
|
|
271
|
+
tags=["spawned", "sub-agent", role.value],
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
def spawn(
|
|
275
|
+
self,
|
|
276
|
+
task: str,
|
|
277
|
+
provider: Optional[ProviderType] = None,
|
|
278
|
+
role: Optional[AgentRole] = None,
|
|
279
|
+
model: Optional[ModelTier] = None,
|
|
280
|
+
skills: Optional[List[str]] = None,
|
|
281
|
+
soul_blueprint: Optional[str] = None,
|
|
282
|
+
coord_task_id: Optional[str] = None,
|
|
283
|
+
agent_name: Optional[str] = None,
|
|
284
|
+
) -> SpawnResult:
|
|
285
|
+
"""Spawn a task-specific sub-agent.
|
|
286
|
+
|
|
287
|
+
Auto-classifies the task to determine role and model tier if not
|
|
288
|
+
explicitly provided. Selects the best node, builds a mini blueprint,
|
|
289
|
+
and deploys via TeamEngine.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
task: Free-text task description.
|
|
293
|
+
provider: Force a specific provider type.
|
|
294
|
+
role: Override auto-detected agent role.
|
|
295
|
+
model: Override auto-detected model tier.
|
|
296
|
+
skills: Skills to load into the agent.
|
|
297
|
+
soul_blueprint: Path to a soul blueprint YAML.
|
|
298
|
+
coord_task_id: Optional coordination board task to claim.
|
|
299
|
+
agent_name: Optional custom agent name.
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
SpawnResult with deployment details.
|
|
303
|
+
"""
|
|
304
|
+
# Auto-classify if not specified
|
|
305
|
+
detected_role, detected_model = classify_task(task)
|
|
306
|
+
final_role = role or detected_role
|
|
307
|
+
final_model = model or detected_model
|
|
308
|
+
|
|
309
|
+
# Select node
|
|
310
|
+
node = select_node(
|
|
311
|
+
self._nodes, final_role, final_model,
|
|
312
|
+
preferred_provider=provider,
|
|
313
|
+
)
|
|
314
|
+
target_provider = provider or node.provider
|
|
315
|
+
|
|
316
|
+
logger.info(
|
|
317
|
+
"Spawning %s agent (model=%s) on %s for: %s",
|
|
318
|
+
final_role.value, final_model.value, node.name, task[:80],
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
# Build mini blueprint
|
|
322
|
+
blueprint = self._build_mini_blueprint(
|
|
323
|
+
task, final_role, final_model, skills, soul_blueprint,
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
# Deploy
|
|
327
|
+
try:
|
|
328
|
+
deployment = self._engine.deploy(
|
|
329
|
+
blueprint,
|
|
330
|
+
name=agent_name,
|
|
331
|
+
provider_override=target_provider,
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
# Get the single deployed agent
|
|
335
|
+
agents = list(deployment.agents.values())
|
|
336
|
+
agent = agents[0] if agents else None
|
|
337
|
+
|
|
338
|
+
if not agent:
|
|
339
|
+
return SpawnResult(
|
|
340
|
+
agent_name=agent_name or "unknown",
|
|
341
|
+
deployment_id=deployment.deployment_id,
|
|
342
|
+
status=AgentStatus.FAILED,
|
|
343
|
+
provider=target_provider,
|
|
344
|
+
role=final_role,
|
|
345
|
+
model=final_model,
|
|
346
|
+
task_description=task,
|
|
347
|
+
error="No agent was created in deployment.",
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
# Claim coordination task if provided
|
|
351
|
+
if coord_task_id:
|
|
352
|
+
self._claim_coord_task(coord_task_id, agent.name)
|
|
353
|
+
|
|
354
|
+
# Audit the spawn
|
|
355
|
+
self._audit_spawn(agent, task, deployment.deployment_id)
|
|
356
|
+
|
|
357
|
+
return SpawnResult(
|
|
358
|
+
agent_name=agent.name,
|
|
359
|
+
deployment_id=deployment.deployment_id,
|
|
360
|
+
status=agent.status,
|
|
361
|
+
provider=target_provider,
|
|
362
|
+
host=agent.host or "localhost",
|
|
363
|
+
pid=agent.pid,
|
|
364
|
+
role=final_role,
|
|
365
|
+
model=final_model,
|
|
366
|
+
task_description=task,
|
|
367
|
+
coord_task_id=coord_task_id,
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
except Exception as exc:
|
|
371
|
+
logger.error("Spawn failed: %s", exc)
|
|
372
|
+
return SpawnResult(
|
|
373
|
+
agent_name=agent_name or f"spawn-{final_role.value}-failed",
|
|
374
|
+
deployment_id="",
|
|
375
|
+
status=AgentStatus.FAILED,
|
|
376
|
+
provider=target_provider,
|
|
377
|
+
role=final_role,
|
|
378
|
+
model=final_model,
|
|
379
|
+
task_description=task,
|
|
380
|
+
error=str(exc),
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
def spawn_baby(
|
|
384
|
+
self,
|
|
385
|
+
name: str,
|
|
386
|
+
provider: Optional[ProviderType] = None,
|
|
387
|
+
) -> SpawnResult:
|
|
388
|
+
"""Spawn a pre-defined baby agent by name.
|
|
389
|
+
|
|
390
|
+
Baby agents are the 12 lightweight daemons of the SK* ecosystem
|
|
391
|
+
(e.g., memory-curator, trust-guardian, health-monitor). Each has
|
|
392
|
+
a pre-configured role, model tier, skills, and default task.
|
|
393
|
+
|
|
394
|
+
Args:
|
|
395
|
+
name: Baby agent name (e.g., 'memory-curator').
|
|
396
|
+
provider: Override the default provider.
|
|
397
|
+
|
|
398
|
+
Returns:
|
|
399
|
+
SpawnResult with deployment details.
|
|
400
|
+
|
|
401
|
+
Raises:
|
|
402
|
+
ValueError: If the baby agent name is not recognized.
|
|
403
|
+
"""
|
|
404
|
+
from .baby_agents import get_baby_agent
|
|
405
|
+
|
|
406
|
+
baby = get_baby_agent(name)
|
|
407
|
+
if baby is None:
|
|
408
|
+
from .baby_agents import BABY_AGENTS
|
|
409
|
+
available = ", ".join(sorted(BABY_AGENTS.keys()))
|
|
410
|
+
raise ValueError(
|
|
411
|
+
f"Unknown baby agent '{name}'. "
|
|
412
|
+
f"Available: {available}"
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
logger.info("Spawning baby agent: %s", baby.name)
|
|
416
|
+
return self.spawn(
|
|
417
|
+
task=baby.task,
|
|
418
|
+
provider=provider,
|
|
419
|
+
role=baby.role,
|
|
420
|
+
model=baby.model,
|
|
421
|
+
skills=baby.skills,
|
|
422
|
+
agent_name=baby.name,
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
def spawn_batch(
|
|
426
|
+
self,
|
|
427
|
+
tasks: List[Dict[str, Any]],
|
|
428
|
+
provider: Optional[ProviderType] = None,
|
|
429
|
+
) -> List[SpawnResult]:
|
|
430
|
+
"""Spawn multiple sub-agents for a batch of tasks.
|
|
431
|
+
|
|
432
|
+
Args:
|
|
433
|
+
tasks: List of dicts with at least a "task" key. Optional keys:
|
|
434
|
+
"role", "model", "skills", "coord_task_id".
|
|
435
|
+
provider: Default provider for all spawns.
|
|
436
|
+
|
|
437
|
+
Returns:
|
|
438
|
+
List of SpawnResult, one per task.
|
|
439
|
+
"""
|
|
440
|
+
results = []
|
|
441
|
+
for task_spec in tasks:
|
|
442
|
+
result = self.spawn(
|
|
443
|
+
task=task_spec["task"],
|
|
444
|
+
provider=provider or task_spec.get("provider"),
|
|
445
|
+
role=task_spec.get("role"),
|
|
446
|
+
model=task_spec.get("model"),
|
|
447
|
+
skills=task_spec.get("skills"),
|
|
448
|
+
coord_task_id=task_spec.get("coord_task_id"),
|
|
449
|
+
)
|
|
450
|
+
results.append(result)
|
|
451
|
+
return results
|
|
452
|
+
|
|
453
|
+
def list_spawned(self) -> List[SpawnResult]:
|
|
454
|
+
"""List all currently spawned sub-agents.
|
|
455
|
+
|
|
456
|
+
Returns:
|
|
457
|
+
List of SpawnResult for active spawned deployments.
|
|
458
|
+
"""
|
|
459
|
+
results = []
|
|
460
|
+
for dep in self._engine.list_deployments():
|
|
461
|
+
if "spawned" not in dep.blueprint_slug.split("-")[0:1]:
|
|
462
|
+
# Only show spawn-prefixed deployments
|
|
463
|
+
if not dep.blueprint_slug.startswith("spawn-"):
|
|
464
|
+
continue
|
|
465
|
+
|
|
466
|
+
for agent in dep.agents.values():
|
|
467
|
+
results.append(SpawnResult(
|
|
468
|
+
agent_name=agent.name,
|
|
469
|
+
deployment_id=dep.deployment_id,
|
|
470
|
+
status=agent.status,
|
|
471
|
+
provider=dep.provider,
|
|
472
|
+
host=agent.host or "localhost",
|
|
473
|
+
pid=agent.pid,
|
|
474
|
+
task_description=dep.team_name or "",
|
|
475
|
+
spawned_at=agent.started_at or dep.created_at,
|
|
476
|
+
))
|
|
477
|
+
return results
|
|
478
|
+
|
|
479
|
+
def kill(self, deployment_id: str) -> bool:
|
|
480
|
+
"""Destroy a spawned sub-agent by deployment ID.
|
|
481
|
+
|
|
482
|
+
Args:
|
|
483
|
+
deployment_id: The deployment to destroy.
|
|
484
|
+
|
|
485
|
+
Returns:
|
|
486
|
+
True if successfully destroyed.
|
|
487
|
+
"""
|
|
488
|
+
return self._engine.destroy_deployment(deployment_id)
|
|
489
|
+
|
|
490
|
+
# ------------------------------------------------------------------
|
|
491
|
+
# Internal helpers
|
|
492
|
+
# ------------------------------------------------------------------
|
|
493
|
+
|
|
494
|
+
def _claim_coord_task(self, task_id: str, agent_name: str) -> None:
|
|
495
|
+
"""Claim a coordination board task for the spawned agent."""
|
|
496
|
+
try:
|
|
497
|
+
from .coordination import Board
|
|
498
|
+
board = Board(home=self._home)
|
|
499
|
+
board.claim_task(agent_name, task_id)
|
|
500
|
+
logger.info("Claimed coord task %s for %s", task_id, agent_name)
|
|
501
|
+
except Exception as exc:
|
|
502
|
+
logger.warning("Could not claim coord task %s: %s", task_id, exc)
|
|
503
|
+
|
|
504
|
+
def _audit_spawn(
|
|
505
|
+
self,
|
|
506
|
+
agent: DeployedAgent,
|
|
507
|
+
task: str,
|
|
508
|
+
deployment_id: str,
|
|
509
|
+
) -> None:
|
|
510
|
+
"""Write an audit entry for the spawn."""
|
|
511
|
+
try:
|
|
512
|
+
from ._trustee_helpers import write_audit
|
|
513
|
+
write_audit(
|
|
514
|
+
"spawn_agent",
|
|
515
|
+
deployment_id,
|
|
516
|
+
{
|
|
517
|
+
"agent_name": agent.name,
|
|
518
|
+
"task": task[:200],
|
|
519
|
+
"status": agent.status.value,
|
|
520
|
+
"provider": agent.provider.value,
|
|
521
|
+
},
|
|
522
|
+
home=self._home,
|
|
523
|
+
)
|
|
524
|
+
except Exception as exc:
|
|
525
|
+
logger.warning("Audit write failed: %s", exc)
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
# ---------------------------------------------------------------------------
|
|
529
|
+
# Utilities
|
|
530
|
+
# ---------------------------------------------------------------------------
|
|
531
|
+
|
|
532
|
+
def _role_icon(role: AgentRole) -> str:
|
|
533
|
+
"""Map agent role to an emoji icon."""
|
|
534
|
+
return {
|
|
535
|
+
AgentRole.MANAGER: "👑",
|
|
536
|
+
AgentRole.WORKER: "⚙️",
|
|
537
|
+
AgentRole.RESEARCHER: "🔬",
|
|
538
|
+
AgentRole.CODER: "💻",
|
|
539
|
+
AgentRole.REVIEWER: "🔍",
|
|
540
|
+
AgentRole.DOCUMENTARIAN: "📝",
|
|
541
|
+
AgentRole.SECURITY: "🛡️",
|
|
542
|
+
AgentRole.OPS: "🔧",
|
|
543
|
+
AgentRole.CUSTOM: "🎯",
|
|
544
|
+
}.get(role, "🤖")
|