@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,445 @@
1
+ """Tests for Memory Auto-Promotion Engine."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from datetime import datetime, timedelta, timezone
7
+ from pathlib import Path
8
+
9
+ import pytest
10
+
11
+ from skcapstone.memory_promoter import (
12
+ PromotionEngine,
13
+ PromotionThresholds,
14
+ SweepResult,
15
+ )
16
+ from skcapstone.models import MemoryEntry, MemoryLayer
17
+
18
+
19
+ @pytest.fixture
20
+ def home(tmp_path: Path) -> Path:
21
+ """Create a minimal agent home for promoter tests."""
22
+ mem_dir = tmp_path / "memory"
23
+ mem_dir.mkdir()
24
+ for layer in ("short-term", "mid-term", "long-term"):
25
+ (mem_dir / layer).mkdir()
26
+ return tmp_path
27
+
28
+
29
+ @pytest.fixture
30
+ def engine(home: Path) -> PromotionEngine:
31
+ """Create a PromotionEngine with default thresholds."""
32
+ return PromotionEngine(home)
33
+
34
+
35
+ def _write_memory(
36
+ home: Path,
37
+ memory_id: str,
38
+ content: str = "Test memory",
39
+ layer: MemoryLayer = MemoryLayer.SHORT_TERM,
40
+ importance: float = 0.5,
41
+ access_count: int = 0,
42
+ tags: list[str] | None = None,
43
+ age_hours: float = 0,
44
+ ) -> MemoryEntry:
45
+ """Helper to create a memory file on disk."""
46
+ created_at = datetime.now(timezone.utc) - timedelta(hours=age_hours)
47
+ entry = MemoryEntry(
48
+ memory_id=memory_id,
49
+ content=content,
50
+ tags=tags or [],
51
+ source="test",
52
+ layer=layer,
53
+ importance=importance,
54
+ access_count=access_count,
55
+ created_at=created_at,
56
+ )
57
+ path = home / "memory" / layer.value / f"{memory_id}.json"
58
+ path.write_text(entry.model_dump_json(indent=2), encoding="utf-8")
59
+ return entry
60
+
61
+
62
+ # ---------------------------------------------------------------------------
63
+ # Scoring
64
+ # ---------------------------------------------------------------------------
65
+
66
+
67
+ class TestScoring:
68
+ """Tests for the scoring system."""
69
+
70
+ def test_high_importance_scores_high(self, engine: PromotionEngine, home: Path) -> None:
71
+ """High importance memories score higher."""
72
+ entry = _write_memory(home, "imp-high", importance=0.95, age_hours=48)
73
+ candidate = engine.score(entry)
74
+ assert candidate.signals["importance"] == 0.95
75
+
76
+ def test_low_importance_scores_low(self, engine: PromotionEngine, home: Path) -> None:
77
+ """Low importance memories score lower."""
78
+ entry = _write_memory(home, "imp-low", importance=0.1, age_hours=48)
79
+ candidate = engine.score(entry)
80
+ assert candidate.signals["importance"] == 0.1
81
+
82
+ def test_emotional_tags_boost_score(self, engine: PromotionEngine, home: Path) -> None:
83
+ """Emotional tags increase the emotion signal."""
84
+ entry = _write_memory(
85
+ home, "emo",
86
+ tags=["love", "trust", "cloud9"],
87
+ age_hours=48,
88
+ )
89
+ candidate = engine.score(entry)
90
+ assert candidate.signals["emotion"] == 1.0
91
+
92
+ def test_no_emotional_content(self, engine: PromotionEngine, home: Path) -> None:
93
+ """No emotional tags or content yields zero emotion score."""
94
+ entry = _write_memory(home, "noemo", tags=["debug", "test"], age_hours=48)
95
+ candidate = engine.score(entry)
96
+ assert candidate.signals["emotion"] == 0.0
97
+
98
+ def test_high_access_frequency(self, engine: PromotionEngine, home: Path) -> None:
99
+ """Frequently accessed memories score high on access."""
100
+ entry = _write_memory(home, "freq", access_count=10, age_hours=1)
101
+ candidate = engine.score(entry)
102
+ assert candidate.signals["access"] == 1.0
103
+
104
+ def test_no_access(self, engine: PromotionEngine, home: Path) -> None:
105
+ """Never-accessed memories score zero on access."""
106
+ entry = _write_memory(home, "noaccess", access_count=0, age_hours=48)
107
+ candidate = engine.score(entry)
108
+ assert candidate.signals["access"] == 0.0
109
+
110
+ def test_age_maturity_short_term(self, engine: PromotionEngine, home: Path) -> None:
111
+ """Short-term memories older than 24h start scoring on age."""
112
+ young = _write_memory(home, "young", importance=0.8, age_hours=12)
113
+ old = _write_memory(home, "old", importance=0.8, age_hours=48)
114
+ young_c = engine.score(young)
115
+ old_c = engine.score(old)
116
+ assert old_c.signals["age"] > young_c.signals["age"]
117
+
118
+ def test_tag_richness(self, engine: PromotionEngine, home: Path) -> None:
119
+ """Well-tagged memories score higher on tags."""
120
+ rich = _write_memory(
121
+ home, "rich",
122
+ tags=["a", "b", "c", "d", "e"],
123
+ age_hours=48,
124
+ )
125
+ poor = _write_memory(home, "poor", tags=[], age_hours=48)
126
+ rich_c = engine.score(rich)
127
+ poor_c = engine.score(poor)
128
+ assert rich_c.signals["tags"] == 1.0
129
+ assert poor_c.signals["tags"] == 0.0
130
+
131
+ def test_score_clamped_to_unit(self, engine: PromotionEngine, home: Path) -> None:
132
+ """Score is always between 0 and 1."""
133
+ entry = _write_memory(
134
+ home, "extreme",
135
+ importance=1.0,
136
+ access_count=100,
137
+ tags=["love", "trust", "cloud9", "milestone", "breakthrough"],
138
+ age_hours=200,
139
+ )
140
+ candidate = engine.score(entry)
141
+ assert 0.0 <= candidate.score <= 1.0
142
+
143
+ def test_target_layer_short_to_mid(self, engine: PromotionEngine, home: Path) -> None:
144
+ """Short-term memories target mid-term."""
145
+ entry = _write_memory(home, "s2m", layer=MemoryLayer.SHORT_TERM)
146
+ candidate = engine.score(entry)
147
+ assert candidate.target_layer == "mid-term"
148
+
149
+ def test_target_layer_mid_to_long(self, engine: PromotionEngine, home: Path) -> None:
150
+ """Mid-term memories target long-term."""
151
+ entry = _write_memory(home, "m2l", layer=MemoryLayer.MID_TERM)
152
+ candidate = engine.score(entry)
153
+ assert candidate.target_layer == "long-term"
154
+
155
+
156
+ # ---------------------------------------------------------------------------
157
+ # Sweep
158
+ # ---------------------------------------------------------------------------
159
+
160
+
161
+ class TestSweep:
162
+ """Tests for the promotion sweep."""
163
+
164
+ def test_sweep_empty(self, engine: PromotionEngine, home: Path) -> None:
165
+ """Sweep on empty memory returns empty result."""
166
+ result = engine.sweep()
167
+ assert result.scanned == 0
168
+ assert result.promoted == []
169
+
170
+ def test_sweep_promotes_qualifying(self, home: Path) -> None:
171
+ """Qualifying memories are promoted."""
172
+ # Low thresholds so our test memory qualifies
173
+ engine = PromotionEngine(
174
+ home,
175
+ thresholds=PromotionThresholds(short_to_mid=0.3),
176
+ )
177
+ _write_memory(
178
+ home, "promote-me",
179
+ importance=0.9,
180
+ access_count=5,
181
+ tags=["milestone", "love"],
182
+ age_hours=48,
183
+ )
184
+
185
+ result = engine.sweep()
186
+ assert len(result.promoted) >= 1
187
+ assert result.promoted[0].memory_id == "promote-me"
188
+
189
+ # File should have moved
190
+ assert not (home / "memory" / "short-term" / "promote-me.json").exists()
191
+ assert (home / "memory" / "mid-term" / "promote-me.json").exists()
192
+
193
+ def test_sweep_skips_unqualified(self, home: Path) -> None:
194
+ """Low-scoring memories are not promoted."""
195
+ engine = PromotionEngine(
196
+ home,
197
+ thresholds=PromotionThresholds(short_to_mid=0.9),
198
+ )
199
+ _write_memory(home, "skip-me", importance=0.1, age_hours=1)
200
+
201
+ result = engine.sweep()
202
+ assert len(result.promoted) == 0
203
+ assert result.skipped == 1
204
+
205
+ def test_sweep_dry_run(self, home: Path) -> None:
206
+ """Dry run doesn't move files."""
207
+ engine = PromotionEngine(
208
+ home,
209
+ thresholds=PromotionThresholds(short_to_mid=0.1),
210
+ )
211
+ _write_memory(
212
+ home, "dry-run",
213
+ importance=0.9,
214
+ access_count=10,
215
+ age_hours=48,
216
+ )
217
+
218
+ result = engine.sweep(dry_run=True)
219
+ assert result.dry_run is True
220
+ # File should still be in short-term
221
+ assert (home / "memory" / "short-term" / "dry-run.json").exists()
222
+
223
+ def test_sweep_respects_limit(self, home: Path) -> None:
224
+ """Limit caps the number of promotions."""
225
+ engine = PromotionEngine(
226
+ home,
227
+ thresholds=PromotionThresholds(short_to_mid=0.1),
228
+ )
229
+ for i in range(5):
230
+ _write_memory(
231
+ home, f"limit{i:02d}",
232
+ importance=0.9,
233
+ access_count=10,
234
+ age_hours=48,
235
+ )
236
+
237
+ result = engine.sweep(limit=2)
238
+ assert len(result.promoted) == 2
239
+
240
+ def test_sweep_single_layer(self, home: Path) -> None:
241
+ """Sweep restricted to a single layer."""
242
+ engine = PromotionEngine(
243
+ home,
244
+ thresholds=PromotionThresholds(short_to_mid=0.1, mid_to_long=0.1),
245
+ )
246
+ _write_memory(
247
+ home, "short1",
248
+ importance=0.9, access_count=10, age_hours=48,
249
+ layer=MemoryLayer.SHORT_TERM,
250
+ )
251
+ _write_memory(
252
+ home, "mid1",
253
+ importance=0.9, access_count=10, age_hours=200,
254
+ layer=MemoryLayer.MID_TERM,
255
+ )
256
+
257
+ result = engine.sweep(layer=MemoryLayer.SHORT_TERM)
258
+ promoted_ids = [c.memory_id for c in result.promoted]
259
+ assert "short1" in promoted_ids
260
+ assert "mid1" not in promoted_ids
261
+
262
+ def test_sweep_records_layer_counts(self, home: Path) -> None:
263
+ """Sweep result includes layer counts after sweep."""
264
+ engine = PromotionEngine(home)
265
+ _write_memory(home, "count1")
266
+ _write_memory(home, "count2")
267
+ result = engine.sweep()
268
+ assert "short-term" in result.by_layer
269
+
270
+ def test_long_term_not_swept(self, home: Path) -> None:
271
+ """Long-term memories are never swept for promotion."""
272
+ engine = PromotionEngine(
273
+ home,
274
+ thresholds=PromotionThresholds(mid_to_long=0.0),
275
+ )
276
+ _write_memory(
277
+ home, "longterm",
278
+ layer=MemoryLayer.LONG_TERM,
279
+ importance=1.0,
280
+ access_count=100,
281
+ age_hours=1000,
282
+ )
283
+ result = engine.sweep()
284
+ assert result.scanned == 0 # Long-term not scanned
285
+
286
+
287
+ # ---------------------------------------------------------------------------
288
+ # Mid-term to long-term
289
+ # ---------------------------------------------------------------------------
290
+
291
+
292
+ class TestMidToLong:
293
+ """Tests for mid-term to long-term promotion."""
294
+
295
+ def test_mid_to_long_promotion(self, home: Path) -> None:
296
+ """Mid-term memories can be promoted to long-term."""
297
+ engine = PromotionEngine(
298
+ home,
299
+ thresholds=PromotionThresholds(mid_to_long=0.3),
300
+ )
301
+ _write_memory(
302
+ home, "m2l-promo",
303
+ layer=MemoryLayer.MID_TERM,
304
+ importance=0.9,
305
+ access_count=15,
306
+ tags=["milestone", "architecture"],
307
+ age_hours=200,
308
+ )
309
+
310
+ result = engine.sweep()
311
+ assert len(result.promoted) >= 1
312
+ assert (home / "memory" / "long-term" / "m2l-promo.json").exists()
313
+
314
+ def test_mid_needs_higher_threshold(self, home: Path) -> None:
315
+ """Mid-term promotion requires a higher score than short-term."""
316
+ thresholds = PromotionThresholds()
317
+ assert thresholds.mid_to_long > thresholds.short_to_mid
318
+
319
+
320
+ # ---------------------------------------------------------------------------
321
+ # History
322
+ # ---------------------------------------------------------------------------
323
+
324
+
325
+ class TestHistory:
326
+ """Tests for promotion history logging."""
327
+
328
+ def test_sweep_records_history(self, engine: PromotionEngine, home: Path) -> None:
329
+ """Sweep writes to promotion-log.json."""
330
+ engine.sweep()
331
+ log_path = home / "memory" / "promotion-log.json"
332
+ assert log_path.exists()
333
+
334
+ def test_history_contains_sweep_data(self, engine: PromotionEngine, home: Path) -> None:
335
+ """History entries contain sweep metadata."""
336
+ _write_memory(home, "hist1")
337
+ engine.sweep()
338
+
339
+ history = engine.get_history()
340
+ assert len(history) >= 1
341
+ entry = history[-1]
342
+ assert "timestamp" in entry
343
+ assert "scanned" in entry
344
+ assert "promoted" in entry
345
+
346
+ def test_history_accumulates(self, engine: PromotionEngine, home: Path) -> None:
347
+ """Multiple sweeps accumulate in history."""
348
+ engine.sweep()
349
+ engine.sweep()
350
+ engine.sweep()
351
+
352
+ history = engine.get_history()
353
+ assert len(history) >= 3
354
+
355
+ def test_get_history_empty(self, engine: PromotionEngine) -> None:
356
+ """Get history on fresh instance returns empty."""
357
+ assert engine.get_history() == []
358
+
359
+ def test_get_history_limit(self, engine: PromotionEngine, home: Path) -> None:
360
+ """History respects limit parameter."""
361
+ for _ in range(5):
362
+ engine.sweep()
363
+
364
+ history = engine.get_history(limit=2)
365
+ assert len(history) == 2
366
+
367
+
368
+ # ---------------------------------------------------------------------------
369
+ # Custom Thresholds
370
+ # ---------------------------------------------------------------------------
371
+
372
+
373
+ class TestCustomThresholds:
374
+ """Tests for configurable thresholds."""
375
+
376
+ def test_strict_thresholds_reject_all(self, home: Path) -> None:
377
+ """Very high thresholds reject everything."""
378
+ engine = PromotionEngine(
379
+ home,
380
+ thresholds=PromotionThresholds(short_to_mid=1.0, mid_to_long=1.0),
381
+ )
382
+ _write_memory(home, "strict", importance=0.5, age_hours=48)
383
+ result = engine.sweep()
384
+ assert len(result.promoted) == 0
385
+
386
+ def test_lenient_thresholds_promote_all(self, home: Path) -> None:
387
+ """Very low thresholds promote everything."""
388
+ engine = PromotionEngine(
389
+ home,
390
+ thresholds=PromotionThresholds(short_to_mid=0.0),
391
+ )
392
+ _write_memory(home, "lenient1", age_hours=48)
393
+ _write_memory(home, "lenient2", age_hours=48)
394
+ result = engine.sweep()
395
+ assert len(result.promoted) == 2
396
+
397
+ def test_custom_weights(self, home: Path) -> None:
398
+ """Custom signal weights affect scoring."""
399
+ # Weight importance heavily
400
+ engine = PromotionEngine(
401
+ home,
402
+ thresholds=PromotionThresholds(
403
+ importance_weight=1.0,
404
+ access_weight=0.0,
405
+ emotion_weight=0.0,
406
+ age_weight=0.0,
407
+ tag_weight=0.0,
408
+ short_to_mid=0.8,
409
+ ),
410
+ )
411
+ _write_memory(home, "high-imp", importance=0.9, age_hours=48)
412
+ _write_memory(home, "low-imp", importance=0.3, age_hours=48)
413
+
414
+ result = engine.sweep()
415
+ promoted_ids = [c.memory_id for c in result.promoted]
416
+ assert "high-imp" in promoted_ids
417
+ assert "low-imp" not in promoted_ids
418
+
419
+
420
+ # ---------------------------------------------------------------------------
421
+ # Model tests
422
+ # ---------------------------------------------------------------------------
423
+
424
+
425
+ class TestModels:
426
+ """Tests for promotion models."""
427
+
428
+ def test_thresholds_defaults(self) -> None:
429
+ """PromotionThresholds has sensible defaults."""
430
+ t = PromotionThresholds()
431
+ assert t.short_to_mid < t.mid_to_long
432
+ assert sum([
433
+ t.access_weight,
434
+ t.importance_weight,
435
+ t.emotion_weight,
436
+ t.age_weight,
437
+ t.tag_weight,
438
+ ]) == pytest.approx(1.0)
439
+
440
+ def test_sweep_result_defaults(self) -> None:
441
+ """SweepResult has sensible defaults."""
442
+ r = SweepResult()
443
+ assert r.scanned == 0
444
+ assert r.promoted == []
445
+ assert r.dry_run is False