@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,593 @@
1
+ """Trustee management commands: restart, scale, rotate, health, logs, messages, monitor."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import Optional
7
+
8
+ import click
9
+
10
+ from ._common import AGENT_HOME, console
11
+
12
+ from rich.panel import Panel
13
+ from rich.table import Table
14
+
15
+
16
+ def _print_monitor_report(report, iteration: int = 0):
17
+ """Print a monitor report to the console."""
18
+ prefix = f"[dim]#{iteration}[/] " if iteration else ""
19
+
20
+ status_color = "green" if report.agents_degraded == 0 else "yellow"
21
+ if report.escalations_sent:
22
+ status_color = "red"
23
+
24
+ total = report.agents_healthy + report.agents_degraded
25
+ line = (
26
+ f" {prefix}"
27
+ f"[{status_color}]{report.agents_healthy}/{total} healthy[/]"
28
+ )
29
+
30
+ if report.restarts_triggered:
31
+ line += f" [yellow]restarted: {', '.join(report.restarts_triggered)}[/]"
32
+ if report.rotations_triggered:
33
+ line += f" [bright_magenta]rotated: {', '.join(report.rotations_triggered)}[/]"
34
+ if report.escalations_sent:
35
+ line += f" [red bold]ESCALATED: {', '.join(report.escalations_sent)}[/]"
36
+
37
+ console.print(line)
38
+
39
+
40
+ def register_agents_trustee_commands(agents: click.Group) -> None:
41
+ """Register trustee management commands on the agents group."""
42
+
43
+ @agents.command("restart")
44
+ @click.argument("deployment_id")
45
+ @click.option("--agent", "agent_name", default=None, help="Restart only this agent.")
46
+ @click.option("--home", default=AGENT_HOME, type=click.Path())
47
+ def agents_restart(deployment_id: str, agent_name: Optional[str], home: str):
48
+ """Restart a failed agent or the entire team.
49
+
50
+ \b
51
+ Examples:
52
+ skcapstone agents restart myteam-1740000000
53
+ skcapstone agents restart myteam-1740000000 --agent myteam-alpha
54
+ """
55
+ from ..team_engine import TeamEngine
56
+ from ..trustee_ops import TrusteeOps
57
+
58
+ home_path = Path(home).expanduser()
59
+ engine = TeamEngine(home=home_path)
60
+ ops = TrusteeOps(engine=engine, home=home_path)
61
+
62
+ try:
63
+ with console.status("[bold cyan]Restarting...[/]"):
64
+ results = ops.restart_agent(deployment_id, agent_name=agent_name)
65
+ except ValueError as exc:
66
+ console.print(f"\n [red]{exc}[/]\n")
67
+ return
68
+
69
+ table = Table(show_header=True, header_style="bold", box=None, padding=(0, 2))
70
+ table.add_column("Agent", style="cyan")
71
+ table.add_column("Result")
72
+
73
+ for name, result in results.items():
74
+ color = "green" if result == "restarted" else "red"
75
+ table.add_row(name, f"[{color}]{result}[/]")
76
+
77
+ console.print()
78
+ console.print(
79
+ Panel(table, title=f"Restart: {deployment_id}", border_style="bright_blue")
80
+ )
81
+ console.print()
82
+
83
+ @agents.command("scale")
84
+ @click.argument("deployment_id")
85
+ @click.option("--agent", "agent_spec_key", required=True, help="Agent spec key to scale.")
86
+ @click.option("--count", required=True, type=int, help="Target instance count.")
87
+ @click.option("--home", default=AGENT_HOME, type=click.Path())
88
+ def agents_scale(deployment_id: str, agent_spec_key: str, count: int, home: str):
89
+ """Scale agent instances up or down.
90
+
91
+ \b
92
+ Examples:
93
+ skcapstone agents scale myteam-1740000000 --agent alpha --count 3
94
+ skcapstone agents scale myteam-1740000000 --agent worker --count 1
95
+ """
96
+ from ..team_engine import TeamEngine
97
+ from ..trustee_ops import TrusteeOps
98
+
99
+ home_path = Path(home).expanduser()
100
+ engine = TeamEngine(home=home_path)
101
+ ops = TrusteeOps(engine=engine, home=home_path)
102
+
103
+ try:
104
+ with console.status("[bold cyan]Scaling...[/]"):
105
+ result = ops.scale_agent(deployment_id, agent_spec_key, count)
106
+ except ValueError as exc:
107
+ console.print(f"\n [red]{exc}[/]\n")
108
+ return
109
+
110
+ added = result["added"]
111
+ removed = result["removed"]
112
+ current = result["current_count"]
113
+
114
+ console.print()
115
+ lines = [f" [bold]Agent:[/] {agent_spec_key}\n [bold]Count:[/] {current}"]
116
+ if added:
117
+ lines.append(f" [green]Added:[/] {', '.join(added)}")
118
+ if removed:
119
+ lines.append(f" [yellow]Removed:[/] {', '.join(removed)}")
120
+
121
+ console.print(
122
+ Panel(
123
+ "\n".join(lines),
124
+ title=f"Scale: {deployment_id}",
125
+ border_style="bright_blue",
126
+ padding=(1, 2),
127
+ )
128
+ )
129
+ console.print()
130
+
131
+ @agents.command("rotate")
132
+ @click.argument("deployment_id")
133
+ @click.option("--agent", "agent_name", required=True, help="Agent instance to rotate.")
134
+ @click.option("--home", default=AGENT_HOME, type=click.Path())
135
+ def agents_rotate(deployment_id: str, agent_name: str, home: str):
136
+ """Snapshot context, destroy, and redeploy an agent fresh.
137
+
138
+ Use when an agent shows context degradation. Memory is snapshotted
139
+ before rotation so nothing is lost.
140
+
141
+ \b
142
+ Example:
143
+ skcapstone agents rotate myteam-1740000000 --agent myteam-thread-weaver
144
+ """
145
+ from ..team_engine import TeamEngine
146
+ from ..trustee_ops import TrusteeOps
147
+
148
+ home_path = Path(home).expanduser()
149
+ engine = TeamEngine(home=home_path)
150
+ ops = TrusteeOps(engine=engine, home=home_path)
151
+
152
+ try:
153
+ with console.status("[bold cyan]Rotating agent...[/]"):
154
+ result = ops.rotate_agent(deployment_id, agent_name)
155
+ except ValueError as exc:
156
+ console.print(f"\n [red]{exc}[/]\n")
157
+ return
158
+
159
+ status_color = "green" if result["redeployed"] else "yellow"
160
+ console.print()
161
+ console.print(
162
+ Panel(
163
+ f" [bold]Agent:[/] {agent_name}\n"
164
+ f" [bold]Snapshot:[/] {result['snapshot_path']}\n"
165
+ f" [bold]Destroyed:[/] {'yes' if result['destroyed'] else 'no'}\n"
166
+ f" [bold]Status:[/] [{status_color}]"
167
+ f"{'fresh' if result['redeployed'] else 'pending'}[/]",
168
+ title=f"Rotate: {deployment_id}",
169
+ border_style=status_color,
170
+ padding=(1, 2),
171
+ )
172
+ )
173
+ console.print()
174
+
175
+ @agents.command("health")
176
+ @click.argument("deployment_id")
177
+ @click.option("--home", default=AGENT_HOME, type=click.Path())
178
+ def agents_health(deployment_id: str, home: str):
179
+ """Run health checks on all agents and show a status table.
180
+
181
+ \b
182
+ Example:
183
+ skcapstone agents health myteam-1740000000
184
+ """
185
+ from ..team_engine import TeamEngine
186
+ from ..trustee_ops import TrusteeOps
187
+
188
+ home_path = Path(home).expanduser()
189
+ engine = TeamEngine(home=home_path)
190
+ ops = TrusteeOps(engine=engine, home=home_path)
191
+
192
+ try:
193
+ with console.status("[bold cyan]Running health checks...[/]"):
194
+ report = ops.health_report(deployment_id)
195
+ except ValueError as exc:
196
+ console.print(f"\n [red]{exc}[/]\n")
197
+ return
198
+
199
+ healthy_count = sum(1 for r in report if r["healthy"])
200
+ total = len(report)
201
+ border = "green" if healthy_count == total else "yellow"
202
+
203
+ console.print()
204
+ console.print(
205
+ Panel(
206
+ f" [bold]Deployment:[/] {deployment_id}\n"
207
+ f" [bold]Health:[/] [{border}]{healthy_count}/{total} agents healthy[/]",
208
+ title="Health Report",
209
+ border_style=border,
210
+ padding=(0, 2),
211
+ )
212
+ )
213
+
214
+ table = Table(show_header=True, header_style="bold", box=None, padding=(0, 2))
215
+ table.add_column("Agent", style="cyan")
216
+ table.add_column("Status")
217
+ table.add_column("Host", style="dim")
218
+ table.add_column("Last Heartbeat", style="dim")
219
+ table.add_column("Error", style="red dim")
220
+
221
+ status_style = {
222
+ "running": "[green]running[/]",
223
+ "pending": "[yellow]pending[/]",
224
+ "stopped": "[red]stopped[/]",
225
+ "failed": "[red]failed[/]",
226
+ "degraded": "[yellow]degraded[/]",
227
+ }
228
+
229
+ for row in report:
230
+ table.add_row(
231
+ row["name"],
232
+ status_style.get(row["status"], f"[dim]{row['status']}[/]"),
233
+ row["host"],
234
+ row["last_heartbeat"][:19] if row["last_heartbeat"] != "\u2014" else "\u2014",
235
+ row["error"][:40] if row["error"] else "",
236
+ )
237
+
238
+ console.print(table)
239
+ console.print()
240
+
241
+ @agents.command("logs")
242
+ @click.argument("deployment_id")
243
+ @click.option("--agent", "agent_name", default=None, help="Show logs for one agent only.")
244
+ @click.option("--tail", default=50, show_default=True, help="Max lines per agent.")
245
+ @click.option("--home", default=AGENT_HOME, type=click.Path())
246
+ def agents_logs(deployment_id: str, agent_name: Optional[str], tail: int, home: str):
247
+ """Show recent activity logs for agents in a deployment.
248
+
249
+ \b
250
+ Examples:
251
+ skcapstone agents logs myteam-1740000000
252
+ skcapstone agents logs myteam-1740000000 --agent myteam-alpha --tail 20
253
+ """
254
+ from ..team_engine import TeamEngine
255
+ from ..trustee_ops import TrusteeOps
256
+
257
+ home_path = Path(home).expanduser()
258
+ engine = TeamEngine(home=home_path)
259
+ ops = TrusteeOps(engine=engine, home=home_path)
260
+
261
+ try:
262
+ logs = ops.get_logs(deployment_id, agent_name=agent_name, tail=tail)
263
+ except ValueError as exc:
264
+ console.print(f"\n [red]{exc}[/]\n")
265
+ return
266
+
267
+ if not logs:
268
+ console.print("\n [dim]No log data found.[/]\n")
269
+ return
270
+
271
+ console.print()
272
+ for name, lines in logs.items():
273
+ if not lines:
274
+ console.print(f" [dim]{name}: no logs available[/]")
275
+ continue
276
+ console.print(
277
+ Panel(
278
+ "\n".join(lines),
279
+ title=f"Logs: {name}",
280
+ border_style="dim",
281
+ padding=(0, 1),
282
+ )
283
+ )
284
+ console.print()
285
+
286
+ @agents.command("messages")
287
+ @click.argument("deployment_id")
288
+ @click.option(
289
+ "--agent", "agent_name", default=None,
290
+ help="Show messages only for this agent (inbox + broadcast).",
291
+ )
292
+ @click.option(
293
+ "--limit", "-n", default=20, show_default=True,
294
+ help="Maximum number of archived messages to display per agent.",
295
+ )
296
+ @click.option("--home", default=AGENT_HOME, type=click.Path())
297
+ def agents_messages(deployment_id: str, agent_name: Optional[str], limit: int, home: str):
298
+ """View recent inter-agent messages for a deployed team.
299
+
300
+ Reads archived envelopes from the team comms channel so you can
301
+ audit what agents have been saying to each other.
302
+
303
+ \b
304
+ Examples:
305
+ skcapstone agents messages myteam-1740000000
306
+ skcapstone agents messages myteam-1740000000 --agent myteam-alpha
307
+ skcapstone agents messages myteam-1740000000 --limit 50
308
+ """
309
+ from ..team_comms import TeamChannel, _ENVELOPE_SUFFIX
310
+
311
+ home_path = Path(home).expanduser()
312
+ comms_root = home_path / "comms"
313
+ team_dir = comms_root / deployment_id
314
+
315
+ if not team_dir.exists():
316
+ console.print(
317
+ f"\n [red]No comms directory found for deployment '{deployment_id}'.[/]"
318
+ )
319
+ console.print(
320
+ " [dim]Check that the deployment exists:[/] "
321
+ "[cyan]skcapstone agents status[/]\n"
322
+ )
323
+ return
324
+
325
+ # Collect agent directories to inspect
326
+ if agent_name:
327
+ agent_dirs = [team_dir / agent_name]
328
+ if not agent_dirs[0].exists():
329
+ console.print(
330
+ f"\n [red]Agent '{agent_name}' not found in deployment '{deployment_id}'.[/]\n"
331
+ )
332
+ return
333
+ else:
334
+ agent_dirs = [
335
+ d for d in sorted(team_dir.iterdir())
336
+ if d.is_dir() and d.name != "broadcast"
337
+ ]
338
+
339
+ if not agent_dirs:
340
+ console.print("\n [dim]No agents found in comms directory.[/]\n")
341
+ return
342
+
343
+ total_shown = 0
344
+ console.print()
345
+
346
+ for agent_dir in agent_dirs:
347
+ name = agent_dir.name
348
+ archive = agent_dir / "archive"
349
+
350
+ if not archive.exists():
351
+ continue
352
+
353
+ envelope_files = sorted(
354
+ archive.glob(f"*{_ENVELOPE_SUFFIX}"),
355
+ key=lambda p: p.stat().st_mtime,
356
+ reverse=True,
357
+ )[:limit]
358
+
359
+ if not envelope_files:
360
+ continue
361
+
362
+ table = Table(
363
+ show_header=True, header_style="bold", box=None, padding=(0, 2),
364
+ )
365
+ table.add_column("Time", style="dim", width=12)
366
+ table.add_column("From", style="bold cyan", width=18)
367
+ table.add_column("To", width=18)
368
+ table.add_column("Message")
369
+
370
+ for env_file in reversed(envelope_files):
371
+ try:
372
+ import json as _json
373
+ data = _json.loads(env_file.read_text(encoding="utf-8"))
374
+ sender = data.get("sender", "?")
375
+ recipient = data.get("recipient", "?")
376
+ content = data.get("payload", {}).get("content", "")
377
+ created_at = (
378
+ data.get("metadata", {}).get("created_at", "")[:19] or "\u2014"
379
+ )
380
+ time_part = created_at[11:19] if len(created_at) >= 19 else created_at
381
+
382
+ table.add_row(
383
+ time_part,
384
+ sender,
385
+ recipient,
386
+ content[:80] + ("\u2026" if len(content) > 80 else ""),
387
+ )
388
+ total_shown += 1
389
+ except Exception:
390
+ continue
391
+
392
+ if table.row_count:
393
+ console.print(
394
+ Panel(
395
+ table,
396
+ title=f"Agent inbox archive: {name}",
397
+ border_style="bright_blue",
398
+ padding=(0, 1),
399
+ )
400
+ )
401
+
402
+ # Show broadcast directory if it exists
403
+ broadcast_dir = team_dir / "broadcast"
404
+ if broadcast_dir.exists() and not agent_name:
405
+ bc_files = sorted(
406
+ broadcast_dir.glob(f"*{_ENVELOPE_SUFFIX}"),
407
+ key=lambda p: p.stat().st_mtime,
408
+ reverse=True,
409
+ )[:limit]
410
+
411
+ if bc_files:
412
+ bc_table = Table(
413
+ show_header=True, header_style="bold", box=None, padding=(0, 2),
414
+ )
415
+ bc_table.add_column("Time", style="dim", width=12)
416
+ bc_table.add_column("From", style="bold magenta", width=18)
417
+ bc_table.add_column("Message")
418
+
419
+ for env_file in reversed(bc_files):
420
+ try:
421
+ import json as _json
422
+ data = _json.loads(env_file.read_text(encoding="utf-8"))
423
+ sender = data.get("sender", "?")
424
+ content = data.get("payload", {}).get("content", "")
425
+ created_at = (
426
+ data.get("metadata", {}).get("created_at", "")[:19] or "\u2014"
427
+ )
428
+ time_part = created_at[11:19] if len(created_at) >= 19 else created_at
429
+
430
+ bc_table.add_row(
431
+ time_part,
432
+ sender,
433
+ content[:90] + ("\u2026" if len(content) > 90 else ""),
434
+ )
435
+ total_shown += 1
436
+ except Exception:
437
+ continue
438
+
439
+ if bc_table.row_count:
440
+ console.print(
441
+ Panel(
442
+ bc_table,
443
+ title="Broadcast channel (queen \u2192 team)",
444
+ border_style="bright_magenta",
445
+ padding=(0, 1),
446
+ )
447
+ )
448
+
449
+ if total_shown == 0:
450
+ console.print(
451
+ " [dim]No archived messages found. Messages appear here after they are "
452
+ "received by an agent.[/]"
453
+ )
454
+ else:
455
+ console.print(
456
+ f" [dim]Showing up to {limit} archived messages per agent. "
457
+ "Unread messages are in each agent's inbox.[/]"
458
+ )
459
+
460
+ console.print()
461
+
462
+ @agents.command("monitor")
463
+ @click.option("--home", default=AGENT_HOME, type=click.Path())
464
+ @click.option(
465
+ "--interval", "-i", type=float, default=30.0, show_default=True,
466
+ help="Seconds between health checks.",
467
+ )
468
+ @click.option(
469
+ "--deployment", "-d", "deployment_id", default=None,
470
+ help="Monitor only this deployment (default: all).",
471
+ )
472
+ @click.option(
473
+ "--heartbeat-timeout", type=float, default=120.0, show_default=True,
474
+ help="Seconds since last heartbeat before auto-restart.",
475
+ )
476
+ @click.option(
477
+ "--max-restarts", type=int, default=3, show_default=True,
478
+ help="Consecutive restart failures before auto-rotate.",
479
+ )
480
+ @click.option("--no-restart", is_flag=True, help="Disable auto-restart.")
481
+ @click.option("--no-rotate", is_flag=True, help="Disable auto-rotate.")
482
+ @click.option("--no-escalate", is_flag=True, help="Disable escalation messages.")
483
+ @click.option("--once", is_flag=True, help="Run a single pass and exit.")
484
+ def agents_monitor(
485
+ home: str,
486
+ interval: float,
487
+ deployment_id: Optional[str],
488
+ heartbeat_timeout: float,
489
+ max_restarts: int,
490
+ no_restart: bool,
491
+ no_rotate: bool,
492
+ no_escalate: bool,
493
+ once: bool,
494
+ ):
495
+ """Autonomous agent health monitoring with auto-remediation.
496
+
497
+ Continuously watches deployed teams and takes corrective action:
498
+
499
+ \b
500
+ - Heartbeat miss -> auto-restart
501
+ - Repeated failures -> auto-rotate (snapshot + fresh deploy)
502
+ - Critical degradation -> escalation to Chef via SKChat
503
+
504
+ Press Ctrl+C to stop.
505
+
506
+ \b
507
+ Examples:
508
+ skcapstone agents monitor
509
+ skcapstone agents monitor --interval 15 --deployment myteam-123
510
+ skcapstone agents monitor --once
511
+ skcapstone agents monitor --no-escalate --heartbeat-timeout 60
512
+ """
513
+ from ..providers.local import LocalProvider
514
+ from ..team_engine import TeamEngine as _TE
515
+ from ..trustee_ops import TrusteeOps as _TO
516
+ from ..trustee_monitor import MonitorConfig, TrusteeMonitor
517
+
518
+ home_path = Path(home).expanduser()
519
+ provider = LocalProvider(home=home_path)
520
+ engine = _TE(home=home_path, provider=provider, comms_root=home_path / "comms")
521
+ ops = _TO(engine=engine, home=home_path)
522
+
523
+ config = MonitorConfig(
524
+ heartbeat_timeout=heartbeat_timeout,
525
+ max_restart_attempts=max_restarts,
526
+ auto_restart=not no_restart,
527
+ auto_rotate=not no_rotate,
528
+ auto_escalate=not no_escalate,
529
+ )
530
+
531
+ monitor = TrusteeMonitor(ops=ops, engine=engine, config=config)
532
+
533
+ deployments = engine.list_deployments()
534
+ if deployment_id:
535
+ deployments = [d for d in deployments if d.deployment_id == deployment_id]
536
+ if not deployments:
537
+ console.print(f"\n [red]Deployment '{deployment_id}' not found.[/]\n")
538
+ return
539
+
540
+ console.print()
541
+ console.print(
542
+ Panel(
543
+ f"[bold]Deployments:[/] {len(deployments)}\n"
544
+ f"[bold]Interval:[/] {interval}s\n"
545
+ f"[bold]Heartbeat:[/] {heartbeat_timeout}s timeout\n"
546
+ f"[bold]Auto-restart:[/] {'[green]on[/]' if not no_restart else '[red]off[/]'}\n"
547
+ f"[bold]Auto-rotate:[/] {'[green]on[/]' if not no_rotate else '[red]off[/]'}\n"
548
+ f"[bold]Escalation:[/] {'[green]on[/]' if not no_escalate else '[red]off[/]'}",
549
+ title="Trustee Monitor",
550
+ border_style="bright_blue",
551
+ padding=(1, 2),
552
+ )
553
+ )
554
+
555
+ if once:
556
+ if deployment_id:
557
+ deployment = engine.get_deployment(deployment_id)
558
+ report = monitor.check_deployment(deployment)
559
+ else:
560
+ report = monitor.check_all()
561
+
562
+ _print_monitor_report(report)
563
+ return
564
+
565
+ console.print(" [cyan]Monitoring...[/] (Ctrl+C to stop)\n")
566
+
567
+ try:
568
+ iteration = 0
569
+ while True:
570
+ iteration += 1
571
+ if deployment_id:
572
+ deployment = engine.get_deployment(deployment_id)
573
+ if deployment:
574
+ report = monitor.check_deployment(deployment)
575
+ else:
576
+ report = monitor.check_all()
577
+ else:
578
+ report = monitor.check_all()
579
+
580
+ has_actions = (
581
+ report.restarts_triggered or
582
+ report.rotations_triggered or
583
+ report.escalations_sent
584
+ )
585
+
586
+ if has_actions or iteration % 10 == 1:
587
+ _print_monitor_report(report, iteration=iteration)
588
+
589
+ import time as _time
590
+ _time.sleep(interval)
591
+
592
+ except KeyboardInterrupt:
593
+ console.print(f"\n [dim]Monitor stopped after {iteration} iterations.[/]\n")