@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,482 @@
1
+ """
2
+ Unit tests for skcapstone SyncEngine.
3
+
4
+ Covers orchestration of push/pull across backends, config/state
5
+ persistence, backend filtering, and the init_sync factory.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ from pathlib import Path
12
+ from unittest.mock import MagicMock, patch
13
+
14
+ import pytest
15
+ import yaml
16
+
17
+
18
+ # ---------------------------------------------------------------------------
19
+ # Fixtures
20
+ # ---------------------------------------------------------------------------
21
+
22
+
23
+ @pytest.fixture
24
+ def agent_home(tmp_path: Path) -> Path:
25
+ home = tmp_path / ".skcapstone"
26
+ home.mkdir()
27
+ for d in ("identity", "memory", "trust", "config", "skills"):
28
+ (home / d).mkdir()
29
+
30
+ (home / "identity" / "identity.json").write_text(
31
+ json.dumps({
32
+ "name": "EngineTestAgent",
33
+ "fingerprint": "FFFF1111AAAA2222BBBB3333CCCC4444DDDD5555",
34
+ })
35
+ )
36
+ (home / "trust" / "trust.json").write_text(
37
+ json.dumps({"depth": 3.0, "trust_level": 0.7})
38
+ )
39
+ (home / "config" / "config.yaml").write_text("agent_name: EngineTestAgent\n")
40
+ (home / "manifest.json").write_text(
41
+ json.dumps({"name": "EngineTestAgent", "version": "0.1.0", "connectors": []})
42
+ )
43
+ for layer in ("short-term", "mid-term", "long-term"):
44
+ (home / "memory" / layer).mkdir(parents=True)
45
+ (home / "memory" / "long-term" / "mem.json").write_text(
46
+ json.dumps({"content": "remember this"})
47
+ )
48
+ return home
49
+
50
+
51
+ @pytest.fixture
52
+ def engine(agent_home: Path):
53
+ from skcapstone.sync.engine import SyncEngine
54
+
55
+ e = SyncEngine(agent_home)
56
+ e.config.encrypt = False
57
+ return e
58
+
59
+
60
+ @pytest.fixture
61
+ def local_backend_config(tmp_path: Path):
62
+ from skcapstone.sync.models import SyncBackendConfig, SyncBackendType
63
+
64
+ backup = tmp_path / "local-bkp"
65
+ backup.mkdir()
66
+ return SyncBackendConfig(
67
+ backend_type=SyncBackendType.LOCAL,
68
+ local_path=backup,
69
+ )
70
+
71
+
72
+ # ---------------------------------------------------------------------------
73
+ # Initialisation
74
+ # ---------------------------------------------------------------------------
75
+
76
+
77
+ class TestSyncEngineInit:
78
+ def test_default_config_is_empty(self, engine):
79
+ """Fresh engine has no backends configured."""
80
+ assert engine.config.backends == []
81
+
82
+ def test_state_starts_at_zero(self, engine):
83
+ """Fresh engine state has zero push/pull counts."""
84
+ assert engine.state.push_count == 0
85
+ assert engine.state.pull_count == 0
86
+ assert engine.state.last_push is None
87
+ assert engine.state.last_pull is None
88
+
89
+ def test_creates_sync_directory(self, agent_home: Path):
90
+ """Engine constructor creates agent_home/sync/."""
91
+ from skcapstone.sync.engine import SyncEngine
92
+
93
+ SyncEngine(agent_home)
94
+ assert (agent_home / "sync").is_dir()
95
+
96
+ def test_loads_existing_config(self, agent_home: Path):
97
+ """Engine reads backends from an existing config.yaml."""
98
+ from skcapstone.sync.models import SyncBackendConfig, SyncBackendType
99
+
100
+ config_data = {
101
+ "backends": [{"backend_type": "syncthing", "enabled": True}],
102
+ "encrypt": False,
103
+ "auto_push": True,
104
+ "auto_pull": True,
105
+ }
106
+ (agent_home / "sync").mkdir(exist_ok=True)
107
+ (agent_home / "sync" / "config.yaml").write_text(
108
+ yaml.dump(config_data, default_flow_style=False)
109
+ )
110
+
111
+ from skcapstone.sync.engine import SyncEngine
112
+
113
+ eng = SyncEngine(agent_home)
114
+ assert len(eng.config.backends) == 1
115
+ assert eng.config.backends[0].backend_type == SyncBackendType.SYNCTHING
116
+
117
+ def test_loads_existing_state(self, agent_home: Path):
118
+ """Engine reads push/pull counts from an existing state.json."""
119
+ (agent_home / "sync").mkdir(exist_ok=True)
120
+ (agent_home / "sync" / "state.json").write_text(
121
+ json.dumps({"push_count": 5, "pull_count": 3})
122
+ )
123
+
124
+ from skcapstone.sync.engine import SyncEngine
125
+
126
+ eng = SyncEngine(agent_home)
127
+ assert eng.state.push_count == 5
128
+ assert eng.state.pull_count == 3
129
+
130
+ def test_corrupt_config_falls_back_to_defaults(self, agent_home: Path):
131
+ """Corrupt config.yaml results in default SyncConfig."""
132
+ (agent_home / "sync").mkdir(exist_ok=True)
133
+ (agent_home / "sync" / "config.yaml").write_text("{{{NOT YAML")
134
+
135
+ from skcapstone.sync.engine import SyncEngine
136
+
137
+ eng = SyncEngine(agent_home)
138
+ assert eng.config.backends == []
139
+
140
+ def test_corrupt_state_falls_back_to_defaults(self, agent_home: Path):
141
+ """Corrupt state.json results in default SyncState."""
142
+ (agent_home / "sync").mkdir(exist_ok=True)
143
+ (agent_home / "sync" / "state.json").write_text("NOT JSON")
144
+
145
+ from skcapstone.sync.engine import SyncEngine
146
+
147
+ eng = SyncEngine(agent_home)
148
+ assert eng.state.push_count == 0
149
+
150
+
151
+ # ---------------------------------------------------------------------------
152
+ # add_backend / save_config
153
+ # ---------------------------------------------------------------------------
154
+
155
+
156
+ class TestAddBackend:
157
+ def test_add_backend_appends(self, engine, local_backend_config):
158
+ engine.add_backend(local_backend_config)
159
+ assert len(engine.config.backends) == 1
160
+
161
+ def test_add_backend_replaces_same_type(self, engine, tmp_path: Path):
162
+ """Adding a backend of the same type replaces the existing one."""
163
+ from skcapstone.sync.models import SyncBackendConfig, SyncBackendType
164
+
165
+ first = SyncBackendConfig(
166
+ backend_type=SyncBackendType.LOCAL,
167
+ local_path=tmp_path / "first",
168
+ )
169
+ (tmp_path / "first").mkdir()
170
+ second = SyncBackendConfig(
171
+ backend_type=SyncBackendType.LOCAL,
172
+ local_path=tmp_path / "second",
173
+ )
174
+ (tmp_path / "second").mkdir()
175
+
176
+ engine.add_backend(first)
177
+ engine.add_backend(second)
178
+ # Only one LOCAL backend should remain
179
+ local_backends = [
180
+ b for b in engine.config.backends
181
+ if b.backend_type.value == "local"
182
+ ]
183
+ assert len(local_backends) == 1
184
+ assert local_backends[0].local_path == tmp_path / "second"
185
+
186
+ def test_add_backend_persists_to_disk(self, engine, local_backend_config, agent_home: Path):
187
+ engine.add_backend(local_backend_config)
188
+ config_file = agent_home / "sync" / "config.yaml"
189
+ assert config_file.exists()
190
+ data = yaml.safe_load(config_file.read_text())
191
+ assert len(data["backends"]) == 1
192
+
193
+ def test_config_reloaded_by_new_engine(self, agent_home: Path, local_backend_config):
194
+ from skcapstone.sync.engine import SyncEngine
195
+
196
+ eng1 = SyncEngine(agent_home)
197
+ eng1.config.encrypt = False
198
+ eng1.add_backend(local_backend_config)
199
+
200
+ eng2 = SyncEngine(agent_home)
201
+ assert len(eng2.config.backends) == 1
202
+
203
+
204
+ # ---------------------------------------------------------------------------
205
+ # push
206
+ # ---------------------------------------------------------------------------
207
+
208
+
209
+ class TestSyncEnginePush:
210
+ def test_push_local_backend_succeeds(self, engine, local_backend_config):
211
+ engine.add_backend(local_backend_config)
212
+ results = engine.push()
213
+ assert results.get("local") is True
214
+
215
+ def test_push_increments_push_count(self, engine, local_backend_config):
216
+ engine.add_backend(local_backend_config)
217
+ engine.push()
218
+ assert engine.state.push_count == 1
219
+
220
+ def test_push_sets_last_push_backend(self, engine, local_backend_config):
221
+ engine.add_backend(local_backend_config)
222
+ engine.push()
223
+ assert engine.state.last_push_backend == "local"
224
+
225
+ def test_push_sets_last_push_timestamp(self, engine, local_backend_config):
226
+ engine.add_backend(local_backend_config)
227
+ engine.push()
228
+ assert engine.state.last_push is not None
229
+
230
+ def test_push_persists_state(self, engine, agent_home: Path, local_backend_config):
231
+ engine.add_backend(local_backend_config)
232
+ engine.push()
233
+ state_file = agent_home / "sync" / "state.json"
234
+ assert state_file.exists()
235
+ data = json.loads(state_file.read_text())
236
+ assert data["push_count"] == 1
237
+
238
+ def test_push_skips_disabled_backend(self, engine, tmp_path: Path):
239
+ """Backends with enabled=False should be skipped."""
240
+ from skcapstone.sync.models import SyncBackendConfig, SyncBackendType
241
+
242
+ backup = tmp_path / "disabled-bkp"
243
+ backup.mkdir()
244
+ disabled = SyncBackendConfig(
245
+ backend_type=SyncBackendType.LOCAL,
246
+ local_path=backup,
247
+ enabled=False,
248
+ )
249
+ engine.add_backend(disabled)
250
+ results = engine.push()
251
+ assert "local" not in results
252
+
253
+ def test_push_skips_unavailable_backend(self, engine, agent_home: Path):
254
+ """Unavailable backends are reported as False in results."""
255
+ from skcapstone.sync.models import SyncBackendConfig, SyncBackendType
256
+
257
+ config = SyncBackendConfig(backend_type=SyncBackendType.SYNCTHING)
258
+ engine.add_backend(config)
259
+
260
+ with patch("shutil.which", return_value=None):
261
+ results = engine.push()
262
+
263
+ assert results.get("syncthing") is False
264
+
265
+ def test_push_with_backend_filter(self, engine, tmp_path: Path):
266
+ """backend_filter should push only to the named backend."""
267
+ from skcapstone.sync.models import SyncBackendConfig, SyncBackendType
268
+
269
+ backup = tmp_path / "bkp"
270
+ backup.mkdir()
271
+ engine.add_backend(SyncBackendConfig(backend_type=SyncBackendType.SYNCTHING))
272
+ engine.add_backend(SyncBackendConfig(
273
+ backend_type=SyncBackendType.LOCAL, local_path=backup
274
+ ))
275
+
276
+ with patch("shutil.which", return_value=None):
277
+ results = engine.push(backend_filter="local")
278
+
279
+ assert "local" in results
280
+ assert "syncthing" not in results
281
+
282
+ def test_push_no_backends_returns_empty(self, engine):
283
+ results = engine.push()
284
+ assert results == {}
285
+
286
+ def test_push_multiple_backends_all_succeed(self, engine, tmp_path: Path):
287
+ from skcapstone.sync.models import SyncBackendConfig, SyncBackendType
288
+
289
+ for i in range(2):
290
+ d = tmp_path / f"bkp{i}"
291
+ d.mkdir()
292
+ engine.add_backend(SyncBackendConfig(
293
+ backend_type=SyncBackendType.LOCAL, local_path=d
294
+ ))
295
+ # Second add_backend replaces first (same type), so only 1 local backend
296
+ results = engine.push()
297
+ assert "local" in results
298
+
299
+
300
+ # ---------------------------------------------------------------------------
301
+ # pull
302
+ # ---------------------------------------------------------------------------
303
+
304
+
305
+ class TestSyncEnginePull:
306
+ def _push_to_local(self, engine, local_backend_config):
307
+ engine.add_backend(local_backend_config)
308
+ engine.push()
309
+
310
+ def test_pull_returns_none_with_no_backends(self, engine):
311
+ assert engine.pull() is None
312
+
313
+ def test_pull_restores_state(self, engine, local_backend_config, tmp_path: Path):
314
+ from skcapstone.sync.engine import SyncEngine
315
+
316
+ self._push_to_local(engine, local_backend_config)
317
+
318
+ restore_home = tmp_path / "restore"
319
+ restore_home.mkdir()
320
+ engine2 = SyncEngine(restore_home)
321
+ engine2.config.encrypt = False
322
+ engine2.add_backend(local_backend_config)
323
+ result = engine2.pull()
324
+ assert result is not None
325
+
326
+ def test_pull_increments_pull_count(self, engine, local_backend_config, tmp_path: Path):
327
+ from skcapstone.sync.engine import SyncEngine
328
+
329
+ self._push_to_local(engine, local_backend_config)
330
+
331
+ restore = tmp_path / "restore"
332
+ restore.mkdir()
333
+ engine2 = SyncEngine(restore)
334
+ engine2.config.encrypt = False
335
+ engine2.add_backend(local_backend_config)
336
+ engine2.pull()
337
+ assert engine2.state.pull_count == 1
338
+
339
+ def test_pull_sets_last_pull_backend(self, engine, local_backend_config, tmp_path: Path):
340
+ from skcapstone.sync.engine import SyncEngine
341
+
342
+ self._push_to_local(engine, local_backend_config)
343
+
344
+ restore = tmp_path / "restore"
345
+ restore.mkdir()
346
+ engine2 = SyncEngine(restore)
347
+ engine2.config.encrypt = False
348
+ engine2.add_backend(local_backend_config)
349
+ engine2.pull()
350
+ assert engine2.state.last_pull_backend == "local"
351
+
352
+ def test_pull_dry_run_does_not_extract(self, engine, local_backend_config, tmp_path: Path):
353
+ """dry_run=True downloads the vault but doesn't call unpack."""
354
+ from skcapstone.sync.engine import SyncEngine
355
+
356
+ self._push_to_local(engine, local_backend_config)
357
+
358
+ restore = tmp_path / "restore"
359
+ restore.mkdir()
360
+ engine2 = SyncEngine(restore)
361
+ engine2.config.encrypt = False
362
+ engine2.add_backend(local_backend_config)
363
+
364
+ with patch.object(engine2.vault, "unpack") as mock_unpack:
365
+ result = engine2.pull(dry_run=True)
366
+
367
+ assert result is not None
368
+ mock_unpack.assert_not_called()
369
+
370
+ def test_pull_skips_disabled_backend(self, engine, tmp_path: Path):
371
+ from skcapstone.sync.models import SyncBackendConfig, SyncBackendType
372
+
373
+ backup = tmp_path / "bkp"
374
+ backup.mkdir()
375
+ disabled = SyncBackendConfig(
376
+ backend_type=SyncBackendType.LOCAL,
377
+ local_path=backup,
378
+ enabled=False,
379
+ )
380
+ engine.add_backend(disabled)
381
+ result = engine.pull()
382
+ assert result is None
383
+
384
+ def test_pull_with_backend_filter(self, engine, local_backend_config, tmp_path: Path):
385
+ from skcapstone.sync.engine import SyncEngine
386
+ from skcapstone.sync.models import SyncBackendConfig, SyncBackendType
387
+
388
+ self._push_to_local(engine, local_backend_config)
389
+
390
+ restore = tmp_path / "restore"
391
+ restore.mkdir()
392
+ engine2 = SyncEngine(restore)
393
+ engine2.config.encrypt = False
394
+ engine2.add_backend(local_backend_config)
395
+ # Also add syncthing (unavailable) - filter should pull from local only
396
+ engine2.add_backend(SyncBackendConfig(backend_type=SyncBackendType.SYNCTHING))
397
+
398
+ with patch("shutil.which", side_effect=lambda x: None if x == "syncthing" else "/usr/bin/git"):
399
+ result = engine2.pull(backend_filter="local")
400
+ assert result is not None
401
+
402
+ def test_pull_skips_unavailable_backend_tries_next(self, engine, local_backend_config, tmp_path: Path):
403
+ """Pull skips unavailable backends and tries the next one."""
404
+ from skcapstone.sync.engine import SyncEngine
405
+ from skcapstone.sync.models import SyncBackendConfig, SyncBackendType
406
+
407
+ self._push_to_local(engine, local_backend_config)
408
+
409
+ restore = tmp_path / "restore"
410
+ restore.mkdir()
411
+ engine2 = SyncEngine(restore)
412
+ engine2.config.encrypt = False
413
+ # Add syncthing first (unavailable), then local
414
+ engine2.config.backends = [
415
+ SyncBackendConfig(backend_type=SyncBackendType.SYNCTHING),
416
+ local_backend_config,
417
+ ]
418
+
419
+ with patch("shutil.which", side_effect=lambda x: None if x == "syncthing" else "/bin/true"):
420
+ result = engine2.pull()
421
+ # Local backend should succeed
422
+ assert result is not None
423
+
424
+
425
+ # ---------------------------------------------------------------------------
426
+ # status
427
+ # ---------------------------------------------------------------------------
428
+
429
+
430
+ class TestSyncEngineStatus:
431
+ def test_status_keys(self, engine):
432
+ info = engine.status()
433
+ assert "state" in info
434
+ assert "backends" in info
435
+ assert "vaults" in info
436
+ assert "encrypt" in info
437
+ assert "auto_push" in info
438
+
439
+ def test_status_reports_backend_availability(self, engine):
440
+ from skcapstone.sync.models import SyncBackendConfig, SyncBackendType
441
+
442
+ engine.add_backend(SyncBackendConfig(backend_type=SyncBackendType.SYNCTHING))
443
+ with patch("shutil.which", return_value=None):
444
+ info = engine.status()
445
+ assert info["backends"][0]["available"] is False
446
+
447
+ def test_status_vault_count(self, engine, local_backend_config):
448
+ engine.add_backend(local_backend_config)
449
+ engine.push()
450
+ info = engine.status()
451
+ assert info["vaults"] >= 1
452
+
453
+
454
+ # ---------------------------------------------------------------------------
455
+ # init_sync factory
456
+ # ---------------------------------------------------------------------------
457
+
458
+
459
+ class TestInitSync:
460
+ def test_init_sync_returns_engine(self, agent_home: Path):
461
+ from skcapstone.sync.engine import SyncEngine, init_sync
462
+ from skcapstone.sync.models import SyncBackendType
463
+
464
+ eng = init_sync(agent_home, SyncBackendType.SYNCTHING)
465
+ assert isinstance(eng, SyncEngine)
466
+
467
+ def test_init_sync_adds_backend(self, agent_home: Path):
468
+ from skcapstone.sync.engine import init_sync
469
+ from skcapstone.sync.models import SyncBackendType
470
+
471
+ eng = init_sync(agent_home, SyncBackendType.SYNCTHING)
472
+ assert len(eng.config.backends) == 1
473
+ assert eng.config.backends[0].backend_type == SyncBackendType.SYNCTHING
474
+
475
+ def test_init_sync_with_local_backend(self, agent_home: Path, tmp_path: Path):
476
+ from skcapstone.sync.engine import init_sync
477
+ from skcapstone.sync.models import SyncBackendType
478
+
479
+ backup = tmp_path / "bkp"
480
+ backup.mkdir()
481
+ eng = init_sync(agent_home, SyncBackendType.LOCAL, local_path=backup)
482
+ assert eng.config.backends[0].backend_type == SyncBackendType.LOCAL