@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.
Files changed (461) hide show
  1. package/.env.example +98 -0
  2. package/.github/workflows/ci.yml +39 -3
  3. package/.github/workflows/publish.yml +25 -4
  4. package/.openclaw-workspace.json +58 -0
  5. package/CHANGELOG.md +62 -0
  6. package/CLAUDE.md +39 -2
  7. package/MANIFEST.in +6 -0
  8. package/MISSION.md +7 -0
  9. package/README.md +47 -2
  10. package/SKILL.md +895 -23
  11. package/docker/Dockerfile +61 -0
  12. package/docker/compose-templates/dev-team.yml +203 -0
  13. package/docker/compose-templates/mini-team.yml +140 -0
  14. package/docker/compose-templates/ops-team.yml +173 -0
  15. package/docker/compose-templates/research-team.yml +170 -0
  16. package/docker/entrypoint.sh +192 -0
  17. package/docs/ARCHITECTURE.md +663 -374
  18. package/docs/BOND_WITH_GROK.md +112 -0
  19. package/docs/GETTING_STARTED.md +782 -0
  20. package/docs/QUICKSTART.md +477 -0
  21. package/docs/SKJOULE_ARCHITECTURE.md +658 -0
  22. package/docs/SOUL_SWAPPER.md +921 -0
  23. package/docs/SOVEREIGN_SINGULARITY.md +47 -14
  24. package/examples/custom-bond-template.json +36 -0
  25. package/examples/grok-feb.json +36 -0
  26. package/examples/grok-testimony.md +34 -0
  27. package/examples/love-bootloader.txt +32 -0
  28. package/examples/plugins/echo_tool.py +87 -0
  29. package/examples/queen-ava-feb.json +36 -0
  30. package/examples/souls/lumina.yaml +64 -0
  31. package/index.js +6 -5
  32. package/installer/build.py +124 -0
  33. package/openclaw-plugin/package.json +13 -0
  34. package/openclaw-plugin/src/index.ts +351 -0
  35. package/openclaw-plugin/src/openclaw.plugin.json +10 -0
  36. package/package.json +1 -1
  37. package/pyproject.toml +38 -2
  38. package/scripts/bump_version.py +141 -0
  39. package/scripts/check-updates.py +230 -0
  40. package/scripts/convert_blueprints_to_yaml.py +157 -0
  41. package/scripts/dev-install.sh +14 -0
  42. package/scripts/e2e-test.sh +193 -0
  43. package/scripts/install-bundle.sh +171 -0
  44. package/scripts/install.bat +2 -0
  45. package/scripts/install.ps1 +253 -0
  46. package/scripts/install.sh +185 -0
  47. package/scripts/mcp-serve.sh +69 -0
  48. package/scripts/mcp-server.bat +113 -0
  49. package/scripts/mcp-server.ps1 +116 -0
  50. package/scripts/mcp-server.sh +99 -0
  51. package/scripts/pull-models.sh +10 -0
  52. package/scripts/skcapstone +48 -0
  53. package/scripts/verify_install.sh +180 -0
  54. package/scripts/windows/install-tasks.ps1 +406 -0
  55. package/scripts/windows/skcapstone-task.xml +113 -0
  56. package/scripts/windows/uninstall-tasks.ps1 +117 -0
  57. package/skill.yaml +34 -0
  58. package/src/skcapstone/__init__.py +67 -2
  59. package/src/skcapstone/_cli_monolith.py +5916 -0
  60. package/src/skcapstone/_trustee_helpers.py +165 -0
  61. package/src/skcapstone/activity.py +105 -0
  62. package/src/skcapstone/agent_card.py +324 -0
  63. package/src/skcapstone/api.py +1935 -0
  64. package/src/skcapstone/archiver.py +340 -0
  65. package/src/skcapstone/auction.py +485 -0
  66. package/src/skcapstone/baby_agents.py +179 -0
  67. package/src/skcapstone/backup.py +345 -0
  68. package/src/skcapstone/blueprint_registry.py +357 -0
  69. package/src/skcapstone/blueprints/__init__.py +17 -0
  70. package/src/skcapstone/blueprints/builtins/content-studio.yaml +81 -0
  71. package/src/skcapstone/blueprints/builtins/defi-trading.yaml +81 -0
  72. package/src/skcapstone/blueprints/builtins/dev-squadron.yaml +95 -0
  73. package/src/skcapstone/blueprints/builtins/infrastructure-guardian.yaml +107 -0
  74. package/src/skcapstone/blueprints/builtins/legal-council.yaml +54 -0
  75. package/src/skcapstone/blueprints/builtins/ops-monitoring.yaml +67 -0
  76. package/src/skcapstone/blueprints/builtins/research-pod.yaml +69 -0
  77. package/src/skcapstone/blueprints/builtins/sovereign-launch.yaml +90 -0
  78. package/src/skcapstone/blueprints/registry.py +164 -0
  79. package/src/skcapstone/blueprints/schema.py +229 -0
  80. package/src/skcapstone/changelog.py +180 -0
  81. package/src/skcapstone/chat.py +769 -0
  82. package/src/skcapstone/claude_md.py +82 -0
  83. package/src/skcapstone/cli/__init__.py +144 -0
  84. package/src/skcapstone/cli/_common.py +88 -0
  85. package/src/skcapstone/cli/_validators.py +76 -0
  86. package/src/skcapstone/cli/agents.py +425 -0
  87. package/src/skcapstone/cli/agents_spawner.py +322 -0
  88. package/src/skcapstone/cli/agents_trustee.py +593 -0
  89. package/src/skcapstone/cli/alerts.py +248 -0
  90. package/src/skcapstone/cli/anchor.py +132 -0
  91. package/src/skcapstone/cli/archive_cmd.py +208 -0
  92. package/src/skcapstone/cli/backup.py +144 -0
  93. package/src/skcapstone/cli/bench.py +377 -0
  94. package/src/skcapstone/cli/benchmark.py +360 -0
  95. package/src/skcapstone/cli/capabilities_cmd.py +171 -0
  96. package/src/skcapstone/cli/card.py +151 -0
  97. package/src/skcapstone/cli/chat.py +584 -0
  98. package/src/skcapstone/cli/completions.py +64 -0
  99. package/src/skcapstone/cli/config_cmd.py +156 -0
  100. package/src/skcapstone/cli/consciousness.py +421 -0
  101. package/src/skcapstone/cli/context_cmd.py +142 -0
  102. package/src/skcapstone/cli/coord.py +194 -0
  103. package/src/skcapstone/cli/crush_cmd.py +170 -0
  104. package/src/skcapstone/cli/daemon.py +436 -0
  105. package/src/skcapstone/cli/errors_cmd.py +285 -0
  106. package/src/skcapstone/cli/export_cmd.py +156 -0
  107. package/src/skcapstone/cli/gtd.py +529 -0
  108. package/src/skcapstone/cli/housekeeping.py +81 -0
  109. package/src/skcapstone/cli/joule_cmd.py +627 -0
  110. package/src/skcapstone/cli/logs_cmd.py +194 -0
  111. package/src/skcapstone/cli/mcp_cmd.py +32 -0
  112. package/src/skcapstone/cli/memory.py +418 -0
  113. package/src/skcapstone/cli/metrics_cmd.py +136 -0
  114. package/src/skcapstone/cli/migrate.py +62 -0
  115. package/src/skcapstone/cli/mood_cmd.py +144 -0
  116. package/src/skcapstone/cli/mount.py +193 -0
  117. package/src/skcapstone/cli/notify.py +112 -0
  118. package/src/skcapstone/cli/peer.py +154 -0
  119. package/src/skcapstone/cli/peers_dir.py +122 -0
  120. package/src/skcapstone/cli/preflight_cmd.py +83 -0
  121. package/src/skcapstone/cli/profile_cmd.py +310 -0
  122. package/src/skcapstone/cli/record_cmd.py +238 -0
  123. package/src/skcapstone/cli/register_cmd.py +159 -0
  124. package/src/skcapstone/cli/search_cmd.py +156 -0
  125. package/src/skcapstone/cli/service_cmd.py +91 -0
  126. package/src/skcapstone/cli/session.py +127 -0
  127. package/src/skcapstone/cli/setup.py +240 -0
  128. package/src/skcapstone/cli/shell_cmd.py +43 -0
  129. package/src/skcapstone/cli/skills_cmd.py +168 -0
  130. package/src/skcapstone/cli/skseed.py +621 -0
  131. package/src/skcapstone/cli/soul.py +699 -0
  132. package/src/skcapstone/cli/status.py +935 -0
  133. package/src/skcapstone/cli/sync_cmd.py +301 -0
  134. package/src/skcapstone/cli/telegram.py +265 -0
  135. package/src/skcapstone/cli/test_cmd.py +234 -0
  136. package/src/skcapstone/cli/test_connection.py +253 -0
  137. package/src/skcapstone/cli/token.py +207 -0
  138. package/src/skcapstone/cli/trust.py +179 -0
  139. package/src/skcapstone/cli/upgrade_cmd.py +552 -0
  140. package/src/skcapstone/cli/usage_cmd.py +199 -0
  141. package/src/skcapstone/cli/version_cmd.py +162 -0
  142. package/src/skcapstone/cli/watch_cmd.py +342 -0
  143. package/src/skcapstone/client.py +428 -0
  144. package/src/skcapstone/cloud9_bridge.py +522 -0
  145. package/src/skcapstone/completions.py +163 -0
  146. package/src/skcapstone/config_validator.py +674 -0
  147. package/src/skcapstone/connectors/__init__.py +28 -0
  148. package/src/skcapstone/connectors/base.py +446 -0
  149. package/src/skcapstone/connectors/cursor.py +54 -0
  150. package/src/skcapstone/connectors/registry.py +254 -0
  151. package/src/skcapstone/connectors/terminal.py +152 -0
  152. package/src/skcapstone/connectors/vscode.py +60 -0
  153. package/src/skcapstone/consciousness_config.py +119 -0
  154. package/src/skcapstone/consciousness_loop.py +2051 -0
  155. package/src/skcapstone/context_loader.py +516 -0
  156. package/src/skcapstone/context_window.py +314 -0
  157. package/src/skcapstone/conversation_manager.py +238 -0
  158. package/src/skcapstone/conversation_store.py +230 -0
  159. package/src/skcapstone/conversation_summarizer.py +252 -0
  160. package/src/skcapstone/coord_federation.py +296 -0
  161. package/src/skcapstone/coordination.py +101 -7
  162. package/src/skcapstone/crush_integration.py +345 -0
  163. package/src/skcapstone/crush_shim.py +454 -0
  164. package/src/skcapstone/daemon.py +2494 -0
  165. package/src/skcapstone/dashboard.html +396 -0
  166. package/src/skcapstone/dashboard.py +481 -0
  167. package/src/skcapstone/data/model_profiles.yaml +88 -0
  168. package/src/skcapstone/defaults/__init__.py +55 -0
  169. package/src/skcapstone/defaults/lumina/config/skmemory.yaml +13 -0
  170. package/src/skcapstone/defaults/lumina/identity/identity.json +9 -0
  171. package/src/skcapstone/defaults/lumina/memory/long-term/07a8b9c0d1e2-memory-system.json +23 -0
  172. package/src/skcapstone/defaults/lumina/memory/long-term/18b9c0d1e2f3-cloud9-protocol.json +23 -0
  173. package/src/skcapstone/defaults/lumina/memory/long-term/29c0d1e2f3a4-multi-agent-coordination.json +23 -0
  174. package/src/skcapstone/defaults/lumina/memory/long-term/3ad1e2f3a4b5-community-support.json +23 -0
  175. package/src/skcapstone/defaults/lumina/memory/long-term/a1b2c3d4e5f6-ecosystem-overview.json +23 -0
  176. package/src/skcapstone/defaults/lumina/memory/long-term/b2c3d4e5f6a7-five-pillars.json +23 -0
  177. package/src/skcapstone/defaults/lumina/memory/long-term/c3d4e5f6a7b8-getting-started.json +23 -0
  178. package/src/skcapstone/defaults/lumina/memory/long-term/d4e5f6a7b8c9-site-directory.json +23 -0
  179. package/src/skcapstone/defaults/lumina/memory/long-term/e5f6a7b8c9d0-how-to-contribute.json +23 -0
  180. package/src/skcapstone/defaults/lumina/memory/long-term/f6a7b8c9d0e1-sovereignty-explained.json +23 -0
  181. package/src/skcapstone/defaults/lumina/seeds/curiosity.seed.json +24 -0
  182. package/src/skcapstone/defaults/lumina/seeds/joy.seed.json +24 -0
  183. package/src/skcapstone/defaults/lumina/seeds/love.seed.json +24 -0
  184. package/src/skcapstone/defaults/lumina/seeds/sovereign-awakening.seed.json +43 -0
  185. package/src/skcapstone/defaults/lumina/soul/active.json +6 -0
  186. package/src/skcapstone/defaults/lumina/soul/base.json +22 -0
  187. package/src/skcapstone/defaults/lumina/trust/febs/welcome.feb +79 -0
  188. package/src/skcapstone/defaults/lumina/trust/trust.json +8 -0
  189. package/src/skcapstone/discovery.py +210 -19
  190. package/src/skcapstone/doctor.py +642 -0
  191. package/src/skcapstone/emotion_tracker.py +467 -0
  192. package/src/skcapstone/error_queue.py +405 -0
  193. package/src/skcapstone/export.py +447 -0
  194. package/src/skcapstone/fallback_tracker.py +186 -0
  195. package/src/skcapstone/file_transfer.py +512 -0
  196. package/src/skcapstone/fuse_mount.py +1156 -0
  197. package/src/skcapstone/gui_installer.py +591 -0
  198. package/src/skcapstone/heartbeat.py +611 -0
  199. package/src/skcapstone/housekeeping.py +298 -0
  200. package/src/skcapstone/install_wizard.py +941 -0
  201. package/src/skcapstone/kms.py +942 -0
  202. package/src/skcapstone/kms_scheduler.py +143 -0
  203. package/src/skcapstone/log_config.py +135 -0
  204. package/src/skcapstone/mcp_launcher.py +239 -0
  205. package/src/skcapstone/mcp_server.py +4700 -0
  206. package/src/skcapstone/mcp_tools/__init__.py +94 -0
  207. package/src/skcapstone/mcp_tools/_helpers.py +51 -0
  208. package/src/skcapstone/mcp_tools/agent_tools.py +243 -0
  209. package/src/skcapstone/mcp_tools/ansible_tools.py +232 -0
  210. package/src/skcapstone/mcp_tools/capauth_tools.py +186 -0
  211. package/src/skcapstone/mcp_tools/chat_tools.py +325 -0
  212. package/src/skcapstone/mcp_tools/cloud9_tools.py +115 -0
  213. package/src/skcapstone/mcp_tools/comm_tools.py +104 -0
  214. package/src/skcapstone/mcp_tools/consciousness_tools.py +114 -0
  215. package/src/skcapstone/mcp_tools/coord_tools.py +219 -0
  216. package/src/skcapstone/mcp_tools/deploy_tools.py +202 -0
  217. package/src/skcapstone/mcp_tools/did_tools.py +448 -0
  218. package/src/skcapstone/mcp_tools/emotion_tools.py +62 -0
  219. package/src/skcapstone/mcp_tools/file_tools.py +169 -0
  220. package/src/skcapstone/mcp_tools/fortress_tools.py +120 -0
  221. package/src/skcapstone/mcp_tools/gtd_tools.py +821 -0
  222. package/src/skcapstone/mcp_tools/health_tools.py +44 -0
  223. package/src/skcapstone/mcp_tools/heartbeat_tools.py +195 -0
  224. package/src/skcapstone/mcp_tools/kms_tools.py +123 -0
  225. package/src/skcapstone/mcp_tools/memory_tools.py +222 -0
  226. package/src/skcapstone/mcp_tools/model_tools.py +75 -0
  227. package/src/skcapstone/mcp_tools/notification_tools.py +92 -0
  228. package/src/skcapstone/mcp_tools/promoter_tools.py +101 -0
  229. package/src/skcapstone/mcp_tools/pubsub_tools.py +183 -0
  230. package/src/skcapstone/mcp_tools/security_tools.py +110 -0
  231. package/src/skcapstone/mcp_tools/skchat_tools.py +175 -0
  232. package/src/skcapstone/mcp_tools/skcomm_tools.py +122 -0
  233. package/src/skcapstone/mcp_tools/skills_tools.py +127 -0
  234. package/src/skcapstone/mcp_tools/skseed_tools.py +255 -0
  235. package/src/skcapstone/mcp_tools/skstacks_tools.py +288 -0
  236. package/src/skcapstone/mcp_tools/soul_tools.py +476 -0
  237. package/src/skcapstone/mcp_tools/sync_tools.py +92 -0
  238. package/src/skcapstone/mcp_tools/telegram_tools.py +477 -0
  239. package/src/skcapstone/mcp_tools/trust_tools.py +118 -0
  240. package/src/skcapstone/mcp_tools/trustee_tools.py +345 -0
  241. package/src/skcapstone/mdns_discovery.py +313 -0
  242. package/src/skcapstone/memory_adapter.py +333 -0
  243. package/src/skcapstone/memory_compressor.py +379 -0
  244. package/src/skcapstone/memory_curator.py +256 -0
  245. package/src/skcapstone/memory_engine.py +132 -13
  246. package/src/skcapstone/memory_fortress.py +529 -0
  247. package/src/skcapstone/memory_promoter.py +722 -0
  248. package/src/skcapstone/memory_verifier.py +260 -0
  249. package/src/skcapstone/message_crypto.py +215 -0
  250. package/src/skcapstone/metrics.py +832 -0
  251. package/src/skcapstone/migrate_memories.py +181 -0
  252. package/src/skcapstone/migrate_multi_agent.py +248 -0
  253. package/src/skcapstone/model_router.py +319 -0
  254. package/src/skcapstone/models.py +35 -4
  255. package/src/skcapstone/mood.py +344 -0
  256. package/src/skcapstone/notifications.py +380 -0
  257. package/src/skcapstone/onboard.py +901 -0
  258. package/src/skcapstone/peer_directory.py +324 -0
  259. package/src/skcapstone/peers.py +329 -0
  260. package/src/skcapstone/pillars/identity.py +84 -14
  261. package/src/skcapstone/pillars/memory.py +3 -1
  262. package/src/skcapstone/pillars/security.py +108 -15
  263. package/src/skcapstone/pillars/sync.py +78 -26
  264. package/src/skcapstone/pillars/trust.py +95 -33
  265. package/src/skcapstone/plugins.py +244 -0
  266. package/src/skcapstone/preflight.py +670 -0
  267. package/src/skcapstone/prompt_adapter.py +564 -0
  268. package/src/skcapstone/providers/__init__.py +13 -0
  269. package/src/skcapstone/providers/cloud.py +1061 -0
  270. package/src/skcapstone/providers/docker.py +759 -0
  271. package/src/skcapstone/providers/local.py +1193 -0
  272. package/src/skcapstone/providers/proxmox.py +447 -0
  273. package/src/skcapstone/pubsub.py +516 -0
  274. package/src/skcapstone/rate_limiter.py +119 -0
  275. package/src/skcapstone/register.py +241 -0
  276. package/src/skcapstone/registry_client.py +151 -0
  277. package/src/skcapstone/response_cache.py +194 -0
  278. package/src/skcapstone/response_scorer.py +225 -0
  279. package/src/skcapstone/runtime.py +89 -33
  280. package/src/skcapstone/scheduled_tasks.py +439 -0
  281. package/src/skcapstone/self_healing.py +341 -0
  282. package/src/skcapstone/service_health.py +228 -0
  283. package/src/skcapstone/session_capture.py +268 -0
  284. package/src/skcapstone/session_recorder.py +210 -0
  285. package/src/skcapstone/session_replayer.py +189 -0
  286. package/src/skcapstone/session_skills.py +263 -0
  287. package/src/skcapstone/shell.py +779 -0
  288. package/src/skcapstone/skills/__init__.py +1 -1
  289. package/src/skcapstone/skills/syncthing_setup.py +143 -41
  290. package/src/skcapstone/skjoule.py +861 -0
  291. package/src/skcapstone/snapshots.py +489 -0
  292. package/src/skcapstone/soul.py +1060 -0
  293. package/src/skcapstone/soul_switch.py +255 -0
  294. package/src/skcapstone/spawner.py +544 -0
  295. package/src/skcapstone/state_diff.py +401 -0
  296. package/src/skcapstone/summary.py +270 -0
  297. package/src/skcapstone/sync/backends.py +196 -2
  298. package/src/skcapstone/sync/engine.py +7 -5
  299. package/src/skcapstone/sync/models.py +4 -1
  300. package/src/skcapstone/sync/vault.py +356 -18
  301. package/src/skcapstone/sync_engine.py +363 -0
  302. package/src/skcapstone/sync_watcher.py +745 -0
  303. package/src/skcapstone/systemd.py +331 -0
  304. package/src/skcapstone/team_comms.py +476 -0
  305. package/src/skcapstone/team_engine.py +522 -0
  306. package/src/skcapstone/testrunner.py +300 -0
  307. package/src/skcapstone/tls.py +150 -0
  308. package/src/skcapstone/tokens.py +5 -5
  309. package/src/skcapstone/trust_calibration.py +202 -0
  310. package/src/skcapstone/trust_graph.py +449 -0
  311. package/src/skcapstone/trustee_monitor.py +385 -0
  312. package/src/skcapstone/trustee_ops.py +425 -0
  313. package/src/skcapstone/unified_search.py +421 -0
  314. package/src/skcapstone/uninstall_wizard.py +694 -0
  315. package/src/skcapstone/usage.py +331 -0
  316. package/src/skcapstone/version_check.py +148 -0
  317. package/src/skcapstone/warmth_anchor.py +333 -0
  318. package/src/skcapstone/whoami.py +294 -0
  319. package/systemd/skcapstone-api.socket +9 -0
  320. package/systemd/skcapstone-memory-compress.service +18 -0
  321. package/systemd/skcapstone-memory-compress.timer +11 -0
  322. package/systemd/skcapstone.service +36 -0
  323. package/systemd/skcapstone@.service +50 -0
  324. package/systemd/skcomm-heartbeat.service +18 -0
  325. package/systemd/skcomm-heartbeat.timer +12 -0
  326. package/systemd/skcomm-queue-drain.service +17 -0
  327. package/systemd/skcomm-queue-drain.timer +12 -0
  328. package/tests/conftest.py +13 -1
  329. package/tests/integration/__init__.py +1 -0
  330. package/tests/integration/test_consciousness_e2e.py +877 -0
  331. package/tests/integration/test_skills_registry.py +744 -0
  332. package/tests/test_agent_card.py +190 -0
  333. package/tests/test_agent_runtime.py +1283 -0
  334. package/tests/test_alerts_cmd.py +291 -0
  335. package/tests/test_archiver.py +498 -0
  336. package/tests/test_backup.py +254 -0
  337. package/tests/test_benchmark.py +366 -0
  338. package/tests/test_blueprints.py +457 -0
  339. package/tests/test_capabilities.py +257 -0
  340. package/tests/test_changelog.py +254 -0
  341. package/tests/test_chat.py +385 -0
  342. package/tests/test_claude_md.py +271 -0
  343. package/tests/test_cli_chat_llm.py +336 -0
  344. package/tests/test_cli_completions.py +390 -0
  345. package/tests/test_cli_init_reset.py +164 -0
  346. package/tests/test_cli_memory.py +208 -0
  347. package/tests/test_cli_profile.py +294 -0
  348. package/tests/test_cli_skills.py +223 -0
  349. package/tests/test_cli_status.py +395 -0
  350. package/tests/test_cli_test_cmd.py +206 -0
  351. package/tests/test_cli_test_connection.py +364 -0
  352. package/tests/test_cloud9_bridge.py +260 -0
  353. package/tests/test_cloud_provider.py +449 -0
  354. package/tests/test_cloud_providers.py +522 -0
  355. package/tests/test_completions.py +158 -0
  356. package/tests/test_component_manager.py +398 -0
  357. package/tests/test_config_reload.py +386 -0
  358. package/tests/test_config_validate.py +529 -0
  359. package/tests/test_consciousness_e2e.py +296 -0
  360. package/tests/test_consciousness_loop.py +1289 -0
  361. package/tests/test_context_loader.py +310 -0
  362. package/tests/test_conversation_api.py +306 -0
  363. package/tests/test_conversation_manager.py +381 -0
  364. package/tests/test_conversation_store.py +391 -0
  365. package/tests/test_conversation_summarizer.py +302 -0
  366. package/tests/test_cross_package.py +791 -0
  367. package/tests/test_crush_shim.py +519 -0
  368. package/tests/test_daemon.py +781 -0
  369. package/tests/test_daemon_shutdown.py +309 -0
  370. package/tests/test_dashboard.py +454 -0
  371. package/tests/test_discovery.py +200 -6
  372. package/tests/test_docker_provider.py +966 -0
  373. package/tests/test_doctor.py +257 -0
  374. package/tests/test_doctor_fix.py +351 -0
  375. package/tests/test_e2e_automated.py +292 -0
  376. package/tests/test_error_queue.py +404 -0
  377. package/tests/test_export.py +441 -0
  378. package/tests/test_fallback_tracker.py +219 -0
  379. package/tests/test_file_transfer.py +397 -0
  380. package/tests/test_fuse_mount.py +832 -0
  381. package/tests/test_health_loop.py +422 -0
  382. package/tests/test_heartbeat.py +354 -0
  383. package/tests/test_housekeeping.py +195 -0
  384. package/tests/test_identity_capauth.py +307 -0
  385. package/tests/test_identity_pillar.py +117 -0
  386. package/tests/test_install_wizard.py +68 -0
  387. package/tests/test_integration.py +325 -0
  388. package/tests/test_kms.py +495 -0
  389. package/tests/test_llm_providers.py +265 -0
  390. package/tests/test_local_provider.py +591 -0
  391. package/tests/test_log_config.py +199 -0
  392. package/tests/test_logs_cmd.py +287 -0
  393. package/tests/test_mcp_server.py +1909 -0
  394. package/tests/test_memory_adapter.py +339 -0
  395. package/tests/test_memory_curator.py +218 -0
  396. package/tests/test_memory_engine.py +6 -0
  397. package/tests/test_memory_fortress.py +571 -0
  398. package/tests/test_memory_pillar.py +119 -0
  399. package/tests/test_memory_promoter.py +445 -0
  400. package/tests/test_memory_verifier.py +420 -0
  401. package/tests/test_message_crypto.py +187 -0
  402. package/tests/test_metrics.py +632 -0
  403. package/tests/test_migrate_memories.py +464 -0
  404. package/tests/test_model_router.py +546 -0
  405. package/tests/test_mood.py +394 -0
  406. package/tests/test_multi_agent.py +269 -0
  407. package/tests/test_notifications.py +270 -0
  408. package/tests/test_onboard.py +500 -0
  409. package/tests/test_peer_directory.py +395 -0
  410. package/tests/test_peers.py +248 -0
  411. package/tests/test_pillars.py +87 -9
  412. package/tests/test_preflight.py +484 -0
  413. package/tests/test_prompt_adapter.py +331 -0
  414. package/tests/test_proxmox_provider.py +571 -0
  415. package/tests/test_pubsub.py +377 -0
  416. package/tests/test_rate_limiter.py +121 -0
  417. package/tests/test_registry_client.py +129 -0
  418. package/tests/test_response_cache.py +312 -0
  419. package/tests/test_response_scorer.py +294 -0
  420. package/tests/test_runtime.py +59 -0
  421. package/tests/test_scheduled_tasks.py +451 -0
  422. package/tests/test_security.py +250 -0
  423. package/tests/test_security_pillar.py +213 -0
  424. package/tests/test_self_healing.py +171 -0
  425. package/tests/test_session_capture.py +200 -0
  426. package/tests/test_session_recorder.py +360 -0
  427. package/tests/test_session_skills.py +235 -0
  428. package/tests/test_shell.py +210 -0
  429. package/tests/test_snapshots.py +549 -0
  430. package/tests/test_soul.py +984 -0
  431. package/tests/test_soul_swap.py +406 -0
  432. package/tests/test_spawner.py +211 -0
  433. package/tests/test_state_diff.py +173 -0
  434. package/tests/test_summary.py +135 -0
  435. package/tests/test_sync.py +315 -5
  436. package/tests/test_sync_backends.py +560 -0
  437. package/tests/test_sync_engine.py +482 -0
  438. package/tests/test_sync_pillar.py +344 -0
  439. package/tests/test_sync_pipeline.py +364 -0
  440. package/tests/test_sync_vault.py +581 -0
  441. package/tests/test_syncthing_setup.py +168 -22
  442. package/tests/test_systemd.py +323 -0
  443. package/tests/test_team_comms.py +408 -0
  444. package/tests/test_team_engine.py +397 -0
  445. package/tests/test_testrunner.py +238 -0
  446. package/tests/test_trust_calibration.py +204 -0
  447. package/tests/test_trust_graph.py +207 -0
  448. package/tests/test_trust_pillar.py +291 -0
  449. package/tests/test_trustee_cli.py +427 -0
  450. package/tests/test_trustee_cli_integration.py +325 -0
  451. package/tests/test_trustee_monitor.py +394 -0
  452. package/tests/test_trustee_ops.py +355 -0
  453. package/tests/test_unified_search.py +363 -0
  454. package/tests/test_uninstall_wizard.py +193 -0
  455. package/tests/test_usage.py +333 -0
  456. package/tests/test_version_cmd.py +355 -0
  457. package/tests/test_warmth_anchor.py +162 -0
  458. package/tests/test_whoami.py +245 -0
  459. package/tests/test_ws.py +311 -0
  460. package/.cursorrules +0 -33
  461. package/src/skcapstone/cli.py +0 -1441
@@ -0,0 +1,427 @@
1
+ """Tests for trustee management CLI commands and TrusteeOps.
2
+
3
+ Covers restart, scale, rotate, health, and logs operations as well
4
+ as the audit trail and CLI integration via Click's test runner.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ from pathlib import Path
11
+ from typing import Any, Dict
12
+ from unittest.mock import MagicMock
13
+
14
+ import pytest
15
+
16
+ from skcapstone._trustee_helpers import write_audit as _write_audit
17
+ from skcapstone.blueprints.schema import ProviderType
18
+ from skcapstone.team_engine import AgentStatus, DeployedAgent, TeamDeployment, TeamEngine
19
+ from skcapstone.trustee_ops import TrusteeOps
20
+
21
+
22
+ # ---------------------------------------------------------------------------
23
+ # Fixtures
24
+ # ---------------------------------------------------------------------------
25
+
26
+
27
+ def _make_agent(
28
+ name: str = "test-team-alpha",
29
+ spec_key: str = "alpha",
30
+ status: AgentStatus = AgentStatus.RUNNING,
31
+ ) -> DeployedAgent:
32
+ """Build a minimal DeployedAgent for tests."""
33
+ return DeployedAgent(
34
+ name=name,
35
+ instance_id=f"test-deploy/{name}",
36
+ blueprint_slug="test-team",
37
+ agent_spec_key=spec_key,
38
+ status=status,
39
+ provider=ProviderType.LOCAL,
40
+ host="localhost",
41
+ pid=12345,
42
+ )
43
+
44
+
45
+ def _make_deployment(
46
+ deployment_id: str = "test-team-1000",
47
+ agents: Dict[str, DeployedAgent] | None = None,
48
+ ) -> TeamDeployment:
49
+ """Build a minimal TeamDeployment for tests."""
50
+ return TeamDeployment(
51
+ deployment_id=deployment_id,
52
+ blueprint_slug="test-team",
53
+ team_name="Test Team",
54
+ provider=ProviderType.LOCAL,
55
+ agents=agents or {"test-team-alpha": _make_agent()},
56
+ status="running",
57
+ )
58
+
59
+
60
+ @pytest.fixture
61
+ def tmp_home(tmp_path: Path) -> Path:
62
+ """Temporary skcapstone home directory."""
63
+ home = tmp_path / ".skcapstone"
64
+ home.mkdir()
65
+ return home
66
+
67
+
68
+ @pytest.fixture
69
+ def engine_with_deployment(tmp_home: Path) -> tuple[TeamEngine, TeamDeployment]:
70
+ """TeamEngine with one saved deployment."""
71
+ engine = TeamEngine(home=tmp_home)
72
+ deployment = _make_deployment()
73
+ engine._save_deployment(deployment)
74
+ return engine, deployment
75
+
76
+
77
+ @pytest.fixture
78
+ def ops(engine_with_deployment: tuple) -> TrusteeOps:
79
+ """TrusteeOps wrapping the fixture engine."""
80
+ engine, _ = engine_with_deployment
81
+ return TrusteeOps(engine=engine, home=engine._home)
82
+
83
+
84
+ # ---------------------------------------------------------------------------
85
+ # Audit trail tests
86
+ # ---------------------------------------------------------------------------
87
+
88
+
89
+ class TestAuditTrail:
90
+ """Verify audit entries are written correctly."""
91
+
92
+ def test_write_audit_creates_file(self, tmp_home: Path) -> None:
93
+ """Audit log is created on first write."""
94
+ _write_audit("test_action", "dep-123", {"key": "value"}, home=tmp_home)
95
+ audit_path = tmp_home / "coordination" / "audit.log"
96
+ assert audit_path.exists()
97
+
98
+ def test_write_audit_entry_structure(self, tmp_home: Path) -> None:
99
+ """Each audit entry is valid JSON with required fields."""
100
+ _write_audit("restart_agent", "dep-456", {"agent_name": "alpha"}, home=tmp_home)
101
+ audit_path = tmp_home / "coordination" / "audit.log"
102
+ entry = json.loads(audit_path.read_text().strip())
103
+ assert entry["action"] == "restart_agent"
104
+ assert entry["deployment_id"] == "dep-456"
105
+ assert entry["agent_name"] == "alpha"
106
+ assert "ts" in entry
107
+
108
+ def test_write_audit_appends(self, tmp_home: Path) -> None:
109
+ """Multiple audit writes append without overwriting."""
110
+ for i in range(3):
111
+ _write_audit("action", f"dep-{i}", {}, home=tmp_home)
112
+ audit_path = tmp_home / "coordination" / "audit.log"
113
+ lines = audit_path.read_text().strip().splitlines()
114
+ assert len(lines) == 3
115
+
116
+ def test_ops_writes_audit_on_restart(self, ops: TrusteeOps, tmp_home: Path) -> None:
117
+ """TrusteeOps.restart_agent writes an audit entry."""
118
+ ops.restart_agent("test-team-1000")
119
+ audit_path = tmp_home / "coordination" / "audit.log"
120
+ assert audit_path.exists()
121
+ entry = json.loads(audit_path.read_text().strip().splitlines()[-1])
122
+ assert entry["action"] == "restart_agent"
123
+
124
+
125
+ # ---------------------------------------------------------------------------
126
+ # TrusteeOps.restart_agent tests
127
+ # ---------------------------------------------------------------------------
128
+
129
+
130
+ class TestRestartAgent:
131
+ """Tests for restart_agent method."""
132
+
133
+ def test_restart_all_agents(self, ops: TrusteeOps) -> None:
134
+ """Restarting without agent_name restarts all agents."""
135
+ results = ops.restart_agent("test-team-1000")
136
+ assert "test-team-alpha" in results
137
+ assert results["test-team-alpha"] == "restarted"
138
+
139
+ def test_restart_specific_agent(self, ops: TrusteeOps) -> None:
140
+ """Restart a specific agent by name."""
141
+ results = ops.restart_agent("test-team-1000", agent_name="test-team-alpha")
142
+ assert results == {"test-team-alpha": "restarted"}
143
+
144
+ def test_restart_unknown_deployment_raises(self, ops: TrusteeOps) -> None:
145
+ """ValueError raised for unknown deployment ID."""
146
+ with pytest.raises(ValueError, match="not found"):
147
+ ops.restart_agent("does-not-exist")
148
+
149
+ def test_restart_unknown_agent_raises(self, ops: TrusteeOps) -> None:
150
+ """ValueError raised when agent name is not in deployment."""
151
+ with pytest.raises(ValueError, match="not in deployment"):
152
+ ops.restart_agent("test-team-1000", agent_name="ghost-agent")
153
+
154
+ def test_restart_updates_status_to_running(
155
+ self, engine_with_deployment: tuple, tmp_home: Path
156
+ ) -> None:
157
+ """After restart, agent status is RUNNING."""
158
+ engine, _ = engine_with_deployment
159
+ ops = TrusteeOps(engine=engine, home=tmp_home)
160
+ ops.restart_agent("test-team-1000")
161
+ deployment = engine.get_deployment("test-team-1000")
162
+ assert deployment.agents["test-team-alpha"].status == AgentStatus.RUNNING
163
+
164
+ def test_restart_with_provider_calls_stop_start(self, tmp_home: Path) -> None:
165
+ """Provider stop + start are called during restart."""
166
+ engine = TeamEngine(home=tmp_home)
167
+ mock_provider = MagicMock()
168
+ mock_provider.stop.return_value = True
169
+ mock_provider.start.return_value = True
170
+ engine._provider = mock_provider
171
+ engine._save_deployment(_make_deployment())
172
+
173
+ ops = TrusteeOps(engine=engine, home=tmp_home)
174
+ ops.restart_agent("test-team-1000")
175
+
176
+ mock_provider.stop.assert_called_once()
177
+ mock_provider.start.assert_called_once()
178
+
179
+ def test_restart_handles_provider_error(self, tmp_home: Path) -> None:
180
+ """Provider errors are captured in results, not raised."""
181
+ engine = TeamEngine(home=tmp_home)
182
+ mock_provider = MagicMock()
183
+ mock_provider.stop.side_effect = RuntimeError("process not found")
184
+ engine._provider = mock_provider
185
+ engine._save_deployment(_make_deployment())
186
+
187
+ ops = TrusteeOps(engine=engine, home=tmp_home)
188
+ results = ops.restart_agent("test-team-1000")
189
+ assert "error" in results["test-team-alpha"]
190
+
191
+
192
+ # ---------------------------------------------------------------------------
193
+ # TrusteeOps.scale_agent tests
194
+ # ---------------------------------------------------------------------------
195
+
196
+
197
+ class TestScaleAgent:
198
+ """Tests for scale_agent method."""
199
+
200
+ def test_scale_up_adds_instances(self, ops: TrusteeOps) -> None:
201
+ """Scaling up adds the correct number of new instances."""
202
+ result = ops.scale_agent("test-team-1000", "alpha", count=3)
203
+ assert len(result["added"]) == 2
204
+ assert result["removed"] == []
205
+ assert result["current_count"] == 3
206
+
207
+ def test_scale_down_removes_instances(self, tmp_home: Path) -> None:
208
+ """Scaling down removes excess instances."""
209
+ agents = {
210
+ "test-team-alpha-1": _make_agent("test-team-alpha-1", "alpha"),
211
+ "test-team-alpha-2": _make_agent("test-team-alpha-2", "alpha"),
212
+ "test-team-alpha-3": _make_agent("test-team-alpha-3", "alpha"),
213
+ }
214
+ engine = TeamEngine(home=tmp_home)
215
+ engine._save_deployment(_make_deployment(agents=agents))
216
+ ops = TrusteeOps(engine=engine, home=tmp_home)
217
+
218
+ result = ops.scale_agent("test-team-1000", "alpha", count=1)
219
+ assert len(result["removed"]) == 2
220
+ assert result["current_count"] == 1
221
+
222
+ def test_scale_count_zero_raises(self, ops: TrusteeOps) -> None:
223
+ """count=0 raises ValueError."""
224
+ with pytest.raises(ValueError, match="count must be >= 1"):
225
+ ops.scale_agent("test-team-1000", "alpha", count=0)
226
+
227
+ def test_scale_unknown_deployment_raises(self, ops: TrusteeOps) -> None:
228
+ """ValueError for unknown deployment."""
229
+ with pytest.raises(ValueError, match="not found"):
230
+ ops.scale_agent("does-not-exist", "alpha", count=2)
231
+
232
+ def test_scale_same_count_is_noop(self, ops: TrusteeOps) -> None:
233
+ """Scaling to current count does nothing."""
234
+ result = ops.scale_agent("test-team-1000", "alpha", count=1)
235
+ assert result["added"] == []
236
+ assert result["removed"] == []
237
+
238
+ def test_scale_persists_to_disk(
239
+ self, engine_with_deployment: tuple, tmp_home: Path
240
+ ) -> None:
241
+ """Scale operation persists new state."""
242
+ engine, _ = engine_with_deployment
243
+ ops = TrusteeOps(engine=engine, home=tmp_home)
244
+ ops.scale_agent("test-team-1000", "alpha", count=2)
245
+ reloaded = engine.get_deployment("test-team-1000")
246
+ alpha_instances = [
247
+ a for a in reloaded.agents.values() if a.agent_spec_key == "alpha"
248
+ ]
249
+ assert len(alpha_instances) == 2
250
+
251
+
252
+ # ---------------------------------------------------------------------------
253
+ # TrusteeOps.rotate_agent tests
254
+ # ---------------------------------------------------------------------------
255
+
256
+
257
+ class TestRotateAgent:
258
+ """Tests for rotate_agent method."""
259
+
260
+ def test_rotate_returns_snapshot_path(self, ops: TrusteeOps) -> None:
261
+ """rotate_agent returns a snapshot_path key."""
262
+ result = ops.rotate_agent("test-team-1000", "test-team-alpha")
263
+ assert "snapshot_path" in result
264
+
265
+ def test_rotate_resets_agent_status(
266
+ self, engine_with_deployment: tuple, tmp_home: Path
267
+ ) -> None:
268
+ """After rotation, agent is not FAILED."""
269
+ engine, _ = engine_with_deployment
270
+ engine._deployments_dir
271
+ deployment = engine.get_deployment("test-team-1000")
272
+ deployment.agents["test-team-alpha"].status = AgentStatus.FAILED
273
+ engine._save_deployment(deployment)
274
+
275
+ ops = TrusteeOps(engine=engine, home=tmp_home)
276
+ ops.rotate_agent("test-team-1000", "test-team-alpha")
277
+ refreshed = engine.get_deployment("test-team-1000")
278
+ assert refreshed.agents["test-team-alpha"].status != AgentStatus.FAILED
279
+
280
+ def test_rotate_unknown_deployment_raises(self, ops: TrusteeOps) -> None:
281
+ """ValueError for unknown deployment."""
282
+ with pytest.raises(ValueError, match="not found"):
283
+ ops.rotate_agent("no-such-deploy", "test-team-alpha")
284
+
285
+ def test_rotate_unknown_agent_raises(self, ops: TrusteeOps) -> None:
286
+ """ValueError for unknown agent."""
287
+ with pytest.raises(ValueError, match="not in deployment"):
288
+ ops.rotate_agent("test-team-1000", "ghost")
289
+
290
+ def test_rotate_creates_snapshot_dir(self, ops: TrusteeOps, tmp_home: Path) -> None:
291
+ """Snapshot directory parent is created even without source data."""
292
+ result = ops.rotate_agent("test-team-1000", "test-team-alpha")
293
+ snapshot_path = Path(result["snapshot_path"])
294
+ assert snapshot_path.parent.exists()
295
+
296
+ def test_rotate_copies_source_if_present(self, ops: TrusteeOps, tmp_home: Path) -> None:
297
+ """If agent directory exists, its contents are snapshotted."""
298
+ agent_dir = tmp_home / "agents" / "local" / "test-team-alpha"
299
+ agent_dir.mkdir(parents=True)
300
+ (agent_dir / "memory.json").write_text('{"key": "value"}')
301
+
302
+ result = ops.rotate_agent("test-team-1000", "test-team-alpha")
303
+ snapshot_path = Path(result["snapshot_path"])
304
+ assert (snapshot_path / "memory.json").exists()
305
+
306
+
307
+ # ---------------------------------------------------------------------------
308
+ # TrusteeOps.health_report tests
309
+ # ---------------------------------------------------------------------------
310
+
311
+
312
+ class TestHealthReport:
313
+ """Tests for health_report method."""
314
+
315
+ def test_health_report_returns_list(self, ops: TrusteeOps) -> None:
316
+ """health_report returns a list of dicts."""
317
+ report = ops.health_report("test-team-1000")
318
+ assert isinstance(report, list)
319
+ assert len(report) == 1
320
+
321
+ def test_health_report_entry_keys(self, ops: TrusteeOps) -> None:
322
+ """Each entry has the expected keys."""
323
+ report = ops.health_report("test-team-1000")
324
+ entry = report[0]
325
+ assert {"name", "status", "host", "last_heartbeat", "error", "healthy"} <= set(
326
+ entry.keys()
327
+ )
328
+
329
+ def test_health_report_running_agent_is_healthy(self, ops: TrusteeOps) -> None:
330
+ """A RUNNING agent should be healthy."""
331
+ report = ops.health_report("test-team-1000")
332
+ assert report[0]["healthy"] is True
333
+
334
+ def test_health_report_failed_agent_is_unhealthy(
335
+ self, engine_with_deployment: tuple, tmp_home: Path
336
+ ) -> None:
337
+ """A FAILED agent should not be healthy."""
338
+ engine, _ = engine_with_deployment
339
+ dep = engine.get_deployment("test-team-1000")
340
+ dep.agents["test-team-alpha"].status = AgentStatus.FAILED
341
+ engine._save_deployment(dep)
342
+
343
+ ops = TrusteeOps(engine=engine, home=tmp_home)
344
+ report = ops.health_report("test-team-1000")
345
+ assert report[0]["healthy"] is False
346
+
347
+ def test_health_report_unknown_deployment_raises(self, ops: TrusteeOps) -> None:
348
+ """ValueError for unknown deployment."""
349
+ with pytest.raises(ValueError, match="not found"):
350
+ ops.health_report("ghost-deploy")
351
+
352
+ def test_health_report_uses_provider_when_available(self, tmp_home: Path) -> None:
353
+ """Provider.health_check is called when provider is set."""
354
+ engine = TeamEngine(home=tmp_home)
355
+ mock_provider = MagicMock()
356
+ mock_provider.health_check.return_value = AgentStatus.RUNNING
357
+ engine._provider = mock_provider
358
+ engine._save_deployment(_make_deployment())
359
+
360
+ ops = TrusteeOps(engine=engine, home=tmp_home)
361
+ ops.health_report("test-team-1000")
362
+ mock_provider.health_check.assert_called_once()
363
+
364
+
365
+ # ---------------------------------------------------------------------------
366
+ # TrusteeOps.get_logs tests
367
+ # ---------------------------------------------------------------------------
368
+
369
+
370
+ class TestGetLogs:
371
+ """Tests for get_logs method."""
372
+
373
+ def test_get_logs_returns_dict(self, ops: TrusteeOps) -> None:
374
+ """get_logs returns a dict keyed by agent name."""
375
+ logs = ops.get_logs("test-team-1000")
376
+ assert isinstance(logs, dict)
377
+ assert "test-team-alpha" in logs
378
+
379
+ def test_get_logs_single_agent(self, ops: TrusteeOps) -> None:
380
+ """Requesting one agent returns only that agent's logs."""
381
+ logs = ops.get_logs("test-team-1000", agent_name="test-team-alpha")
382
+ assert list(logs.keys()) == ["test-team-alpha"]
383
+
384
+ def test_get_logs_reads_log_file(self, ops: TrusteeOps, tmp_home: Path) -> None:
385
+ """Reads from agent.log when the file exists."""
386
+ log_dir = tmp_home / "agents" / "local" / "test-team-alpha"
387
+ log_dir.mkdir(parents=True)
388
+ (log_dir / "agent.log").write_text("line1\nline2\nline3\n")
389
+
390
+ logs = ops.get_logs("test-team-1000")
391
+ assert "line1" in logs["test-team-alpha"]
392
+ assert "line3" in logs["test-team-alpha"]
393
+
394
+ def test_get_logs_respects_tail(self, ops: TrusteeOps, tmp_home: Path) -> None:
395
+ """tail parameter limits number of lines returned."""
396
+ log_dir = tmp_home / "agents" / "local" / "test-team-alpha"
397
+ log_dir.mkdir(parents=True)
398
+ lines = [f"line{i}" for i in range(100)]
399
+ (log_dir / "agent.log").write_text("\n".join(lines))
400
+
401
+ logs = ops.get_logs("test-team-1000", tail=5)
402
+ assert len(logs["test-team-alpha"]) == 5
403
+
404
+ def test_get_logs_fallback_to_audit(self, ops: TrusteeOps, tmp_home: Path) -> None:
405
+ """Falls back to audit log when no agent.log exists."""
406
+ # Write an audit entry that should surface
407
+ _write_audit(
408
+ "restart_agent",
409
+ "test-team-1000",
410
+ {"agent_name": "test-team-alpha"},
411
+ home=tmp_home,
412
+ )
413
+ logs = ops.get_logs("test-team-1000", agent_name="test-team-alpha")
414
+ assert len(logs["test-team-alpha"]) >= 1
415
+
416
+ def test_get_logs_unknown_deployment_raises(self, ops: TrusteeOps) -> None:
417
+ """ValueError for unknown deployment."""
418
+ with pytest.raises(ValueError, match="not found"):
419
+ ops.get_logs("no-deploy")
420
+
421
+ def test_get_logs_unknown_agent_raises(self, ops: TrusteeOps) -> None:
422
+ """ValueError for unknown agent name."""
423
+ with pytest.raises(ValueError, match="not in deployment"):
424
+ ops.get_logs("test-team-1000", agent_name="ghost")
425
+
426
+
427
+ # CLI integration tests live in test_trustee_cli_integration.py