@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,449 @@
1
+ """Tests for CloudProvider — Hetzner adapter and provider_type property.
2
+
3
+ Focuses on HetznerAdapter (full lifecycle) and CloudProvider.provider_type
4
+ which are not covered in test_cloud_providers.py. All Hetzner API calls
5
+ are mocked via requests — no real cloud account required.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import Any, Dict
11
+ from unittest.mock import MagicMock, patch
12
+
13
+ import pytest
14
+
15
+ from skcapstone.blueprints.schema import AgentRole, AgentSpec, ModelTier, ProviderType, ResourceSpec
16
+ from skcapstone.providers.cloud import (
17
+ CloudProvider,
18
+ HetznerAdapter,
19
+ _build_cloud_init,
20
+ _memory_to_hetzner_type,
21
+ )
22
+ from skcapstone.team_engine import AgentStatus
23
+
24
+
25
+ # ---------------------------------------------------------------------------
26
+ # Helpers
27
+ # ---------------------------------------------------------------------------
28
+
29
+
30
+ def _make_spec(
31
+ role: str = "worker",
32
+ model: str = "fast",
33
+ memory: str = "4g",
34
+ cores: int = 2,
35
+ skills: list | None = None,
36
+ ) -> AgentSpec:
37
+ return AgentSpec(
38
+ role=AgentRole(role),
39
+ model=ModelTier(model),
40
+ resources=ResourceSpec(memory=memory, cores=cores),
41
+ skills=skills or [],
42
+ env={},
43
+ )
44
+
45
+
46
+ # ---------------------------------------------------------------------------
47
+ # _memory_to_hetzner_type
48
+ # ---------------------------------------------------------------------------
49
+
50
+
51
+ class TestMemoryToHetznerType:
52
+ def test_small_instance_cx22(self):
53
+ assert _memory_to_hetzner_type("2g", 2) == "cx22"
54
+
55
+ def test_cx22_for_4g_2c(self):
56
+ assert _memory_to_hetzner_type("4g", 2) == "cx22"
57
+
58
+ def test_cx32_for_8g_4c(self):
59
+ assert _memory_to_hetzner_type("8g", 4) == "cx32"
60
+
61
+ def test_cx42_for_16g(self):
62
+ assert _memory_to_hetzner_type("16g", 8) == "cx42"
63
+
64
+ def test_cx52_for_large(self):
65
+ assert _memory_to_hetzner_type("64g", 32) == "cx52"
66
+
67
+ def test_megabytes_converted(self):
68
+ assert _memory_to_hetzner_type("512m", 1) == "cx22"
69
+
70
+
71
+ # ---------------------------------------------------------------------------
72
+ # HetznerAdapter._api_call
73
+ # ---------------------------------------------------------------------------
74
+
75
+
76
+ class TestHetznerApiCall:
77
+ @pytest.fixture()
78
+ def adapter(self):
79
+ return HetznerAdapter(api_token="test-token-abc")
80
+
81
+ def _mock_response(self, status_code: int, data: Any) -> MagicMock:
82
+ resp = MagicMock()
83
+ resp.status_code = status_code
84
+ resp.json.return_value = data
85
+ resp.text = str(data)
86
+ return resp
87
+
88
+ def test_successful_get_returns_json(self, adapter):
89
+ mock_resp = self._mock_response(200, {"servers": []})
90
+ with patch("requests.request", return_value=mock_resp):
91
+ result = adapter._api_call("GET", "/servers")
92
+ assert result == {"servers": []}
93
+
94
+ def test_raises_on_4xx(self, adapter):
95
+ mock_resp = self._mock_response(404, {"error": "not found"})
96
+ with patch("requests.request", return_value=mock_resp):
97
+ with pytest.raises(RuntimeError, match="Hetzner API"):
98
+ adapter._api_call("GET", "/servers/999")
99
+
100
+ def test_raises_on_5xx(self, adapter):
101
+ mock_resp = self._mock_response(500, "internal server error")
102
+ with patch("requests.request", return_value=mock_resp):
103
+ with pytest.raises(RuntimeError):
104
+ adapter._api_call("DELETE", "/servers/1")
105
+
106
+ def test_raises_without_token(self):
107
+ adapter = HetznerAdapter(api_token="")
108
+ with patch("requests.request"):
109
+ with pytest.raises(RuntimeError, match="HETZNER_API_TOKEN"):
110
+ adapter._api_call("GET", "/servers")
111
+
112
+ def test_raises_without_requests_sdk(self, adapter):
113
+ with patch.dict("sys.modules", {"requests": None}):
114
+ with pytest.raises((RuntimeError, ImportError)):
115
+ adapter._api_call("GET", "/servers")
116
+
117
+ def test_authorization_header_bearer(self, adapter):
118
+ mock_resp = self._mock_response(200, {})
119
+ with patch("requests.request", return_value=mock_resp) as mock_req:
120
+ adapter._api_call("GET", "/servers")
121
+ headers = mock_req.call_args[1]["headers"]
122
+ assert "Bearer test-token-abc" in headers["Authorization"]
123
+
124
+
125
+ # ---------------------------------------------------------------------------
126
+ # HetznerAdapter.provision
127
+ # ---------------------------------------------------------------------------
128
+
129
+
130
+ class TestHetznerAdapterProvision:
131
+ @pytest.fixture()
132
+ def adapter(self):
133
+ return HetznerAdapter(api_token="tok")
134
+
135
+ def test_provision_returns_server_id_and_host(self, adapter):
136
+ mock_resp = MagicMock()
137
+ mock_resp.status_code = 201
138
+ mock_resp.json.return_value = {
139
+ "server": {
140
+ "id": 12345,
141
+ "public_net": {"ipv4": {"ip": "1.2.3.4"}},
142
+ }
143
+ }
144
+ with patch("requests.request", return_value=mock_resp):
145
+ result = adapter.provision("agent-hz", _make_spec(), "my-team")
146
+ assert result["server_id"] == 12345
147
+ assert result["host"] == "1.2.3.4"
148
+ assert result["container_id"] == "12345"
149
+
150
+ def test_provision_applies_correct_server_type(self, adapter):
151
+ mock_resp = MagicMock()
152
+ mock_resp.status_code = 201
153
+ mock_resp.json.return_value = {"server": {"id": 100, "public_net": {"ipv4": {"ip": ""}}}}
154
+ with patch("requests.request", return_value=mock_resp) as mock_req:
155
+ adapter.provision("agent-hz", _make_spec(memory="8g", cores=4), "team")
156
+ post_data = mock_req.call_args[1]["json"]
157
+ assert post_data["server_type"] == "cx32"
158
+
159
+ def test_provision_includes_cloud_init(self, adapter):
160
+ mock_resp = MagicMock()
161
+ mock_resp.status_code = 201
162
+ mock_resp.json.return_value = {"server": {"id": 101, "public_net": {"ipv4": {"ip": ""}}}}
163
+ with patch("requests.request", return_value=mock_resp) as mock_req:
164
+ adapter.provision("agent-hz", _make_spec(), "team")
165
+ post_data = mock_req.call_args[1]["json"]
166
+ assert "user_data" in post_data
167
+ assert "#cloud-config" in post_data["user_data"]
168
+
169
+ def test_provision_sets_labels(self, adapter):
170
+ mock_resp = MagicMock()
171
+ mock_resp.status_code = 201
172
+ mock_resp.json.return_value = {"server": {"id": 102, "public_net": {"ipv4": {"ip": ""}}}}
173
+ with patch("requests.request", return_value=mock_resp) as mock_req:
174
+ adapter.provision("my-agent", _make_spec(role="coder"), "ops-team")
175
+ post_data = mock_req.call_args[1]["json"]
176
+ labels = post_data.get("labels", {})
177
+ assert labels.get("managed-by") == "skcapstone"
178
+ assert labels.get("role") == "coder"
179
+
180
+ def test_provision_normalizes_server_name(self, adapter):
181
+ mock_resp = MagicMock()
182
+ mock_resp.status_code = 201
183
+ mock_resp.json.return_value = {"server": {"id": 103, "public_net": {"ipv4": {"ip": ""}}}}
184
+ with patch("requests.request", return_value=mock_resp) as mock_req:
185
+ adapter.provision("agent_underscore", _make_spec(), "team")
186
+ post_data = mock_req.call_args[1]["json"]
187
+ assert "_" not in post_data["name"]
188
+
189
+ def test_provision_handles_missing_ip(self, adapter):
190
+ mock_resp = MagicMock()
191
+ mock_resp.status_code = 201
192
+ mock_resp.json.return_value = {"server": {"id": 104, "public_net": {}}}
193
+ with patch("requests.request", return_value=mock_resp):
194
+ result = adapter.provision("agent-hz", _make_spec(), "team")
195
+ assert result["host"] == ""
196
+ assert result["server_id"] == 104
197
+
198
+
199
+ # ---------------------------------------------------------------------------
200
+ # HetznerAdapter.configure
201
+ # ---------------------------------------------------------------------------
202
+
203
+
204
+ class TestHetznerAdapterConfigure:
205
+ def test_configure_returns_true(self):
206
+ adapter = HetznerAdapter(api_token="tok")
207
+ assert adapter.configure("a", _make_spec(), {}) is True
208
+
209
+
210
+ # ---------------------------------------------------------------------------
211
+ # HetznerAdapter.start
212
+ # ---------------------------------------------------------------------------
213
+
214
+
215
+ class TestHetznerAdapterStart:
216
+ @pytest.fixture()
217
+ def adapter(self):
218
+ return HetznerAdapter(api_token="tok")
219
+
220
+ def test_start_calls_poweron(self, adapter):
221
+ mock_resp = MagicMock()
222
+ mock_resp.status_code = 201
223
+ mock_resp.json.return_value = {}
224
+ with patch("requests.request", return_value=mock_resp) as mock_req:
225
+ result = adapter.start("a", {"server_id": 100})
226
+ assert result is True
227
+ url = mock_req.call_args[0][1]
228
+ assert "poweron" in url
229
+
230
+ def test_start_returns_false_without_server_id(self, adapter):
231
+ assert adapter.start("a", {}) is False
232
+
233
+ def test_start_returns_false_on_api_error(self, adapter):
234
+ mock_resp = MagicMock()
235
+ mock_resp.status_code = 404
236
+ mock_resp.text = "not found"
237
+ mock_resp.json.return_value = {}
238
+ with patch("requests.request", return_value=mock_resp):
239
+ result = adapter.start("a", {"server_id": 100})
240
+ assert result is False
241
+
242
+
243
+ # ---------------------------------------------------------------------------
244
+ # HetznerAdapter.stop
245
+ # ---------------------------------------------------------------------------
246
+
247
+
248
+ class TestHetznerAdapterStop:
249
+ @pytest.fixture()
250
+ def adapter(self):
251
+ return HetznerAdapter(api_token="tok")
252
+
253
+ def test_stop_calls_poweroff(self, adapter):
254
+ mock_resp = MagicMock()
255
+ mock_resp.status_code = 201
256
+ mock_resp.json.return_value = {}
257
+ with patch("requests.request", return_value=mock_resp) as mock_req:
258
+ result = adapter.stop("a", {"server_id": 100})
259
+ assert result is True
260
+ url = mock_req.call_args[0][1]
261
+ assert "poweroff" in url
262
+
263
+ def test_stop_returns_false_without_server_id(self, adapter):
264
+ assert adapter.stop("a", {}) is False
265
+
266
+ def test_stop_returns_false_on_api_error(self, adapter):
267
+ mock_resp = MagicMock()
268
+ mock_resp.status_code = 500
269
+ mock_resp.text = "error"
270
+ mock_resp.json.return_value = {}
271
+ with patch("requests.request", return_value=mock_resp):
272
+ result = adapter.stop("a", {"server_id": 100})
273
+ assert result is False
274
+
275
+
276
+ # ---------------------------------------------------------------------------
277
+ # HetznerAdapter.destroy
278
+ # ---------------------------------------------------------------------------
279
+
280
+
281
+ class TestHetznerAdapterDestroy:
282
+ @pytest.fixture()
283
+ def adapter(self):
284
+ return HetznerAdapter(api_token="tok")
285
+
286
+ def test_destroy_calls_delete(self, adapter):
287
+ mock_resp = MagicMock()
288
+ mock_resp.status_code = 204
289
+ mock_resp.json.return_value = {}
290
+ with patch("requests.request", return_value=mock_resp) as mock_req:
291
+ result = adapter.destroy("a", {"server_id": 100})
292
+ assert result is True
293
+ method, url = mock_req.call_args[0]
294
+ assert method == "DELETE"
295
+ assert "100" in url
296
+
297
+ def test_destroy_returns_false_without_server_id(self, adapter):
298
+ assert adapter.destroy("a", {}) is False
299
+
300
+ def test_destroy_returns_false_on_error(self, adapter):
301
+ mock_resp = MagicMock()
302
+ mock_resp.status_code = 403
303
+ mock_resp.text = "forbidden"
304
+ mock_resp.json.return_value = {}
305
+ with patch("requests.request", return_value=mock_resp):
306
+ result = adapter.destroy("a", {"server_id": 100})
307
+ assert result is False
308
+
309
+
310
+ # ---------------------------------------------------------------------------
311
+ # HetznerAdapter.health_check
312
+ # ---------------------------------------------------------------------------
313
+
314
+
315
+ class TestHetznerAdapterHealthCheck:
316
+ @pytest.fixture()
317
+ def adapter(self):
318
+ return HetznerAdapter(api_token="tok")
319
+
320
+ def test_health_running(self, adapter):
321
+ mock_resp = MagicMock()
322
+ mock_resp.status_code = 200
323
+ mock_resp.json.return_value = {"server": {"status": "running"}}
324
+ with patch("requests.request", return_value=mock_resp):
325
+ status = adapter.health_check("a", {"server_id": 100})
326
+ assert status == AgentStatus.RUNNING
327
+
328
+ def test_health_off(self, adapter):
329
+ mock_resp = MagicMock()
330
+ mock_resp.status_code = 200
331
+ mock_resp.json.return_value = {"server": {"status": "off"}}
332
+ with patch("requests.request", return_value=mock_resp):
333
+ status = adapter.health_check("a", {"server_id": 100})
334
+ assert status == AgentStatus.STOPPED
335
+
336
+ def test_health_deleting(self, adapter):
337
+ mock_resp = MagicMock()
338
+ mock_resp.status_code = 200
339
+ mock_resp.json.return_value = {"server": {"status": "deleting"}}
340
+ with patch("requests.request", return_value=mock_resp):
341
+ status = adapter.health_check("a", {"server_id": 100})
342
+ assert status == AgentStatus.STOPPED
343
+
344
+ def test_health_initializing_is_degraded(self, adapter):
345
+ mock_resp = MagicMock()
346
+ mock_resp.status_code = 200
347
+ mock_resp.json.return_value = {"server": {"status": "initializing"}}
348
+ with patch("requests.request", return_value=mock_resp):
349
+ status = adapter.health_check("a", {"server_id": 100})
350
+ assert status == AgentStatus.DEGRADED
351
+
352
+ def test_health_no_server_id_returns_stopped(self, adapter):
353
+ assert adapter.health_check("a", {}) == AgentStatus.STOPPED
354
+
355
+ def test_health_api_error_returns_failed(self, adapter):
356
+ mock_resp = MagicMock()
357
+ mock_resp.status_code = 500
358
+ mock_resp.text = "server error"
359
+ mock_resp.json.return_value = {}
360
+ with patch("requests.request", return_value=mock_resp):
361
+ status = adapter.health_check("a", {"server_id": 100})
362
+ assert status == AgentStatus.FAILED
363
+
364
+
365
+ # ---------------------------------------------------------------------------
366
+ # CloudProvider.provider_type property
367
+ # ---------------------------------------------------------------------------
368
+
369
+
370
+ class TestCloudProviderProviderType:
371
+ def test_hetzner_provider_type(self):
372
+ provider = CloudProvider(cloud="hetzner")
373
+ assert provider.provider_type == ProviderType.HETZNER
374
+
375
+ def test_aws_provider_type(self):
376
+ provider = CloudProvider(cloud="aws")
377
+ assert provider.provider_type == ProviderType.AWS
378
+
379
+ def test_gcp_provider_type(self):
380
+ provider = CloudProvider(cloud="gcp")
381
+ assert provider.provider_type == ProviderType.GCP
382
+
383
+
384
+ # ---------------------------------------------------------------------------
385
+ # CloudProvider delegation to Hetzner
386
+ # ---------------------------------------------------------------------------
387
+
388
+
389
+ class TestCloudProviderHetznerDelegation:
390
+ @pytest.fixture()
391
+ def provider(self):
392
+ return CloudProvider(cloud="hetzner", config={"api_token": "tok"})
393
+
394
+ def test_provision_delegates_to_hetzner(self, provider):
395
+ mock_result = {"server_id": 1, "host": "1.2.3.4", "container_id": "1"}
396
+ with patch.object(provider._adapter, "provision", return_value=mock_result):
397
+ result = provider.provision("a", _make_spec(), "t")
398
+ assert result == mock_result
399
+
400
+ def test_configure_delegates_to_hetzner(self, provider):
401
+ with patch.object(provider._adapter, "configure", return_value=True):
402
+ ok = provider.configure("a", _make_spec(), {})
403
+ assert ok is True
404
+
405
+ def test_start_delegates_to_hetzner(self, provider):
406
+ with patch.object(provider._adapter, "start", return_value=True):
407
+ ok = provider.start("a", {"server_id": 1})
408
+ assert ok is True
409
+
410
+ def test_stop_delegates_to_hetzner(self, provider):
411
+ with patch.object(provider._adapter, "stop", return_value=True):
412
+ ok = provider.stop("a", {"server_id": 1})
413
+ assert ok is True
414
+
415
+ def test_destroy_delegates_to_hetzner(self, provider):
416
+ with patch.object(provider._adapter, "destroy", return_value=True):
417
+ ok = provider.destroy("a", {"server_id": 1})
418
+ assert ok is True
419
+
420
+ def test_health_check_delegates_to_hetzner(self, provider):
421
+ with patch.object(
422
+ provider._adapter, "health_check", return_value=AgentStatus.RUNNING
423
+ ):
424
+ status = provider.health_check("a", {"server_id": 1})
425
+ assert status == AgentStatus.RUNNING
426
+
427
+
428
+ # ---------------------------------------------------------------------------
429
+ # _build_cloud_init — Hetzner-specific tailscale authkey
430
+ # ---------------------------------------------------------------------------
431
+
432
+
433
+ class TestBuildCloudInitTailscale:
434
+ def test_tailscale_join_included_when_authkey_set(self):
435
+ spec = _make_spec()
436
+ ci = _build_cloud_init("agent", spec, tailscale_authkey="ts-key-abc")
437
+ assert "ts-key-abc" in ci
438
+ assert "tailscale up" in ci
439
+
440
+ def test_tailscale_join_omitted_when_no_authkey(self):
441
+ spec = _make_spec()
442
+ ci = _build_cloud_init("agent", spec, tailscale_authkey="")
443
+ assert "tailscale up" not in ci or "--authkey" not in ci
444
+
445
+ def test_tailscale_authkey_from_env(self, monkeypatch):
446
+ monkeypatch.setenv("TAILSCALE_AUTHKEY", "env-ts-key")
447
+ spec = _make_spec()
448
+ ci = _build_cloud_init("agent", spec)
449
+ assert "env-ts-key" in ci