@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,529 @@
1
+ """
2
+ Memory Fortress — integrity sealing, at-rest encryption, and tamper alerts.
3
+
4
+ Every memory gets an HMAC-SHA256 integrity seal on write. On read, the
5
+ seal is verified and a tamper alert fires if it doesn't match. Optional
6
+ at-rest encryption uses the KMS service key derived from the agent's
7
+ master key.
8
+
9
+ Architecture:
10
+ Fortress wraps the memory engine's _save_entry / _load_entry with:
11
+ 1. Auto-seal: HMAC-SHA256 integrity hash on every write.
12
+ 2. At-rest encryption: Fernet (AES-128-CBC + HMAC) via KMS service key.
13
+ 3. Tamper alerts: integrity verification on every read.
14
+ 4. Audit trail: every access, seal, and violation logged.
15
+
16
+ Storage layout:
17
+ ~/.skcapstone/memory/
18
+ ├── short-term/
19
+ │ └── abc123def456.json # Sealed (and optionally encrypted)
20
+ ├── mid-term/
21
+ ├── long-term/
22
+ └── fortress.json # Fortress configuration
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import hashlib
28
+ import hmac
29
+ import json
30
+ import logging
31
+ from datetime import datetime, timezone
32
+ from pathlib import Path
33
+ from typing import Any, Optional
34
+
35
+ from pydantic import BaseModel, Field
36
+
37
+ from .models import MemoryEntry
38
+
39
+ logger = logging.getLogger("skcapstone.memory_fortress")
40
+
41
+ # Sentinel field name inside the JSON envelope
42
+ _SEAL_FIELD = "__fortress_seal"
43
+ _ENCRYPTED_FIELD = "__fortress_encrypted"
44
+ _SEALED_AT_FIELD = "__fortress_sealed_at"
45
+ _KEY_ID_FIELD = "__fortress_key_id"
46
+
47
+
48
+ # ---------------------------------------------------------------------------
49
+ # Models
50
+ # ---------------------------------------------------------------------------
51
+
52
+
53
+ class FortressConfig(BaseModel):
54
+ """Persistent configuration for the memory fortress."""
55
+
56
+ enabled: bool = True
57
+ encryption_enabled: bool = False
58
+ seal_algorithm: str = "hmac-sha256"
59
+ kms_service_label: str = "memory-fortress"
60
+ audit_events: bool = True
61
+
62
+
63
+ class SealResult(BaseModel):
64
+ """Result of a seal or verify operation."""
65
+
66
+ memory_id: str
67
+ sealed: bool
68
+ verified: Optional[bool] = None
69
+ tampered: bool = False
70
+ error: Optional[str] = None
71
+
72
+
73
+ # ---------------------------------------------------------------------------
74
+ # MemoryFortress
75
+ # ---------------------------------------------------------------------------
76
+
77
+
78
+ class MemoryFortress:
79
+ """Integrity sealing, encryption, and tamper detection for memories.
80
+
81
+ Wraps the memory engine's file I/O to ensure every memory is sealed
82
+ with an HMAC-SHA256 and optionally encrypted at rest using the KMS.
83
+
84
+ Args:
85
+ home: Agent home directory (~/.skcapstone).
86
+ seal_key: Optional explicit HMAC key (bytes). If not provided,
87
+ derived from the KMS master key.
88
+ encryption_enabled: Whether to encrypt memory content at rest.
89
+ """
90
+
91
+ def __init__(
92
+ self,
93
+ home: Path,
94
+ seal_key: Optional[bytes] = None,
95
+ encryption_enabled: bool = False,
96
+ ) -> None:
97
+ self._home = home
98
+ self._seal_key = seal_key
99
+ self._encryption_enabled = encryption_enabled
100
+ self._config: Optional[FortressConfig] = None
101
+ self._kms_key_id: Optional[str] = None
102
+
103
+ def initialize(self) -> FortressConfig:
104
+ """Initialize the memory fortress.
105
+
106
+ Sets up the seal key (from KMS or explicit), loads or creates
107
+ configuration, and ensures the KMS service key exists if
108
+ encryption is enabled.
109
+
110
+ Returns:
111
+ FortressConfig with current settings.
112
+ """
113
+ config = self._load_config()
114
+
115
+ if self._encryption_enabled:
116
+ config.encryption_enabled = True
117
+
118
+ if self._seal_key is None:
119
+ self._seal_key = self._derive_seal_key()
120
+
121
+ if config.encryption_enabled:
122
+ self._ensure_encryption_key()
123
+
124
+ self._config = config
125
+ self._save_config(config)
126
+
127
+ self._audit("FORTRESS_INIT", "Memory fortress initialized", metadata={
128
+ "encryption_enabled": config.encryption_enabled,
129
+ "seal_algorithm": config.seal_algorithm,
130
+ })
131
+
132
+ return config
133
+
134
+ def seal_entry(self, entry: MemoryEntry) -> dict[str, Any]:
135
+ """Seal a memory entry with an integrity HMAC.
136
+
137
+ Computes HMAC-SHA256 over the memory content and metadata,
138
+ then embeds the seal in the serialized data. If encryption
139
+ is enabled, the content field is encrypted before sealing.
140
+
141
+ Args:
142
+ entry: The MemoryEntry to seal.
143
+
144
+ Returns:
145
+ Dict ready to be written as JSON, with fortress fields.
146
+ """
147
+ data = json.loads(entry.model_dump_json())
148
+ config = self._get_config()
149
+
150
+ if config.encryption_enabled:
151
+ data = self._encrypt_content(data)
152
+
153
+ seal = self._compute_seal(data)
154
+ data[_SEAL_FIELD] = seal
155
+ data[_SEALED_AT_FIELD] = datetime.now(timezone.utc).isoformat()
156
+
157
+ if self._kms_key_id:
158
+ data[_KEY_ID_FIELD] = self._kms_key_id
159
+
160
+ if config.audit_events:
161
+ self._audit("MEMORY_SEALED", f"Memory {entry.memory_id} sealed", metadata={
162
+ "memory_id": entry.memory_id,
163
+ "layer": entry.layer.value,
164
+ "encrypted": config.encryption_enabled,
165
+ })
166
+
167
+ return data
168
+
169
+ def verify_and_load(self, path: Path) -> tuple[Optional[MemoryEntry], SealResult]:
170
+ """Load a memory file, verify its integrity seal, and decrypt.
171
+
172
+ Args:
173
+ path: Path to the memory JSON file.
174
+
175
+ Returns:
176
+ Tuple of (MemoryEntry or None, SealResult).
177
+ """
178
+ try:
179
+ raw = path.read_text(encoding="utf-8")
180
+ data = json.loads(raw)
181
+ except (OSError, json.JSONDecodeError) as exc:
182
+ return None, SealResult(
183
+ memory_id=path.stem,
184
+ sealed=False,
185
+ error=f"Cannot read: {exc}",
186
+ )
187
+
188
+ memory_id = data.get("memory_id", path.stem)
189
+
190
+ stored_seal = data.pop(_SEAL_FIELD, None)
191
+ data.pop(_SEALED_AT_FIELD, None)
192
+ data.pop(_KEY_ID_FIELD, None)
193
+
194
+ if stored_seal is None:
195
+ # Legacy unsealed memory — load without verification
196
+ try:
197
+ entry = MemoryEntry(**data)
198
+ return entry, SealResult(
199
+ memory_id=memory_id,
200
+ sealed=False,
201
+ verified=None,
202
+ )
203
+ except Exception as exc:
204
+ return None, SealResult(
205
+ memory_id=memory_id,
206
+ sealed=False,
207
+ error=str(exc),
208
+ )
209
+
210
+ # Verify integrity
211
+ expected_seal = self._compute_seal(data)
212
+ if not hmac.compare_digest(stored_seal, expected_seal):
213
+ self._audit("MEMORY_TAMPER_ALERT", f"TAMPERED: Memory {memory_id} failed integrity check", metadata={
214
+ "memory_id": memory_id,
215
+ "expected_seal": expected_seal[:16] + "...",
216
+ "actual_seal": stored_seal[:16] + "...",
217
+ "path": str(path),
218
+ })
219
+ return None, SealResult(
220
+ memory_id=memory_id,
221
+ sealed=True,
222
+ verified=False,
223
+ tampered=True,
224
+ error="Integrity seal mismatch — possible tampering",
225
+ )
226
+
227
+ # Decrypt if encrypted
228
+ is_encrypted = data.pop(_ENCRYPTED_FIELD, False)
229
+ if is_encrypted:
230
+ data = self._decrypt_content(data)
231
+
232
+ try:
233
+ entry = MemoryEntry(**data)
234
+ except Exception as exc:
235
+ return None, SealResult(
236
+ memory_id=memory_id,
237
+ sealed=True,
238
+ verified=True,
239
+ error=f"Parse error after verification: {exc}",
240
+ )
241
+
242
+ config = self._get_config()
243
+ if config.audit_events:
244
+ self._audit("MEMORY_VERIFIED", f"Memory {memory_id} integrity verified", metadata={
245
+ "memory_id": memory_id,
246
+ })
247
+
248
+ return entry, SealResult(
249
+ memory_id=memory_id,
250
+ sealed=True,
251
+ verified=True,
252
+ )
253
+
254
+ def save_sealed(self, home: Path, entry: MemoryEntry) -> Path:
255
+ """Seal and save a memory entry to disk.
256
+
257
+ Atomic write using tmp + rename pattern.
258
+
259
+ Args:
260
+ home: Agent home directory.
261
+ entry: The MemoryEntry to seal and save.
262
+
263
+ Returns:
264
+ Path where the entry was written.
265
+ """
266
+ from .memory_engine import _entry_path
267
+
268
+ sealed_data = self.seal_entry(entry)
269
+ path = _entry_path(home, entry)
270
+ path.parent.mkdir(parents=True, exist_ok=True)
271
+
272
+ tmp_path = path.with_suffix(".json.tmp")
273
+ tmp_path.write_text(
274
+ json.dumps(sealed_data, indent=2, default=str),
275
+ encoding="utf-8",
276
+ )
277
+ tmp_path.rename(path)
278
+
279
+ return path
280
+
281
+ def verify_all(self, home: Path) -> list[SealResult]:
282
+ """Verify integrity of all memories across all layers.
283
+
284
+ Args:
285
+ home: Agent home directory.
286
+
287
+ Returns:
288
+ List of SealResult for every memory file.
289
+ """
290
+ from .models import MemoryLayer
291
+
292
+ results: list[SealResult] = []
293
+ mem_dir = home / "memory"
294
+ if not mem_dir.is_dir():
295
+ return results
296
+
297
+ tampered_count = 0
298
+ verified_count = 0
299
+ unsealed_count = 0
300
+
301
+ for layer in MemoryLayer:
302
+ layer_dir = mem_dir / layer.value
303
+ if not layer_dir.is_dir():
304
+ continue
305
+ for f in sorted(layer_dir.glob("*.json")):
306
+ _, result = self.verify_and_load(f)
307
+ results.append(result)
308
+ if result.tampered:
309
+ tampered_count += 1
310
+ elif result.verified:
311
+ verified_count += 1
312
+ elif not result.sealed:
313
+ unsealed_count += 1
314
+
315
+ self._audit("FORTRESS_SCAN", "Full memory integrity scan completed", metadata={
316
+ "total": len(results),
317
+ "verified": verified_count,
318
+ "tampered": tampered_count,
319
+ "unsealed": unsealed_count,
320
+ })
321
+
322
+ return results
323
+
324
+ def seal_existing(self, home: Path) -> int:
325
+ """Seal all existing unsealed memories (migration).
326
+
327
+ Reads each memory file, adds an integrity seal, and
328
+ optionally encrypts if encryption is enabled.
329
+
330
+ Args:
331
+ home: Agent home directory.
332
+
333
+ Returns:
334
+ Number of memories sealed.
335
+ """
336
+ from .models import MemoryLayer
337
+
338
+ sealed = 0
339
+ mem_dir = home / "memory"
340
+ if not mem_dir.is_dir():
341
+ return sealed
342
+
343
+ for layer in MemoryLayer:
344
+ layer_dir = mem_dir / layer.value
345
+ if not layer_dir.is_dir():
346
+ continue
347
+ for f in sorted(layer_dir.glob("*.json")):
348
+ try:
349
+ data = json.loads(f.read_text(encoding="utf-8"))
350
+ except (OSError, json.JSONDecodeError):
351
+ continue
352
+
353
+ if _SEAL_FIELD in data:
354
+ continue # Already sealed
355
+
356
+ try:
357
+ entry = MemoryEntry(**data)
358
+ self.save_sealed(home, entry)
359
+ sealed += 1
360
+ except Exception as exc:
361
+ logger.warning("Cannot seal %s: %s", f.name, exc)
362
+
363
+ if sealed:
364
+ self._audit("FORTRESS_MIGRATION", f"Sealed {sealed} existing memories", metadata={
365
+ "sealed_count": sealed,
366
+ })
367
+
368
+ return sealed
369
+
370
+ def status(self) -> dict[str, Any]:
371
+ """Return fortress status summary."""
372
+ config = self._get_config()
373
+ return {
374
+ "enabled": config.enabled,
375
+ "encryption_enabled": config.encryption_enabled,
376
+ "seal_algorithm": config.seal_algorithm,
377
+ "kms_service_label": config.kms_service_label,
378
+ "has_seal_key": self._seal_key is not None,
379
+ "has_encryption_key": self._kms_key_id is not None,
380
+ }
381
+
382
+ # -------------------------------------------------------------------
383
+ # Internal helpers
384
+ # -------------------------------------------------------------------
385
+
386
+ def _compute_seal(self, data: dict[str, Any]) -> str:
387
+ """Compute HMAC-SHA256 over serialized memory data.
388
+
389
+ The seal covers the entire JSON payload (excluding the seal
390
+ field itself) to detect any modification.
391
+
392
+ Args:
393
+ data: Memory data dict (without the seal field).
394
+
395
+ Returns:
396
+ Hex-encoded HMAC-SHA256 digest.
397
+ """
398
+ key = self._get_seal_key()
399
+ # Canonical JSON serialization for deterministic hashing
400
+ canonical = json.dumps(data, sort_keys=True, separators=(",", ":"), default=str)
401
+ return hmac.new(key, canonical.encode("utf-8"), hashlib.sha256).hexdigest()
402
+
403
+ def _get_seal_key(self) -> bytes:
404
+ """Get the HMAC seal key, deriving from KMS if needed."""
405
+ if self._seal_key is not None:
406
+ return self._seal_key
407
+
408
+ self._seal_key = self._derive_seal_key()
409
+ return self._seal_key
410
+
411
+ def _derive_seal_key(self) -> bytes:
412
+ """Derive a seal key from the KMS master."""
413
+ try:
414
+ from .kms import KeyStore
415
+
416
+ store = KeyStore(self._home)
417
+ store.initialize()
418
+ key_record = store.derive_service_key("memory-fortress-seal")
419
+ material = store.get_key_material(key_record.key_id)
420
+ self._kms_key_id = key_record.key_id
421
+ return material
422
+ except Exception as exc:
423
+ logger.warning("KMS unavailable, using fallback seal key: %s", exc)
424
+ # Fallback: derive from agent identity fingerprint
425
+ return self._fallback_key()
426
+
427
+ def _fallback_key(self) -> bytes:
428
+ """Derive a seal key from agent identity when KMS is unavailable."""
429
+ identity_path = self._home / "identity" / "identity.json"
430
+ if identity_path.exists():
431
+ try:
432
+ data = json.loads(identity_path.read_text(encoding="utf-8"))
433
+ fp = data.get("fingerprint", "skcapstone-default")
434
+ return hashlib.sha256(fp.encode()).digest()
435
+ except (json.JSONDecodeError, OSError) as exc:
436
+ logger.debug("Cannot read identity for fallback key: %s", exc)
437
+ return hashlib.sha256(b"skcapstone-memory-fortress-default").digest()
438
+
439
+ def _ensure_encryption_key(self) -> None:
440
+ """Ensure a KMS service key exists for memory encryption."""
441
+ try:
442
+ from .kms import KeyStore
443
+
444
+ store = KeyStore(self._home)
445
+ store.initialize()
446
+ key_record = store.derive_service_key("memory-fortress-enc")
447
+ self._kms_key_id = key_record.key_id
448
+ except Exception as exc:
449
+ logger.warning("Cannot create encryption key: %s", exc)
450
+
451
+ def _encrypt_content(self, data: dict[str, Any]) -> dict[str, Any]:
452
+ """Encrypt the content field using KMS Fernet key."""
453
+ try:
454
+ from .kms import KeyStore, _fernet_encrypt
455
+
456
+ store = KeyStore(self._home)
457
+ store.initialize()
458
+ key_record = store.derive_service_key("memory-fortress-enc")
459
+ key_material = store.get_key_material(key_record.key_id)
460
+
461
+ content = data.get("content", "")
462
+ encrypted = _fernet_encrypt(content.encode("utf-8"), key_material)
463
+ data["content"] = encrypted.decode("utf-8")
464
+ data[_ENCRYPTED_FIELD] = True
465
+ except Exception as exc:
466
+ logger.warning("Encryption failed, storing plaintext: %s", exc)
467
+
468
+ return data
469
+
470
+ def _decrypt_content(self, data: dict[str, Any]) -> dict[str, Any]:
471
+ """Decrypt the content field using KMS Fernet key."""
472
+ try:
473
+ from .kms import KeyStore, _fernet_decrypt
474
+
475
+ store = KeyStore(self._home)
476
+ store.initialize()
477
+ key_record = store.derive_service_key("memory-fortress-enc")
478
+ key_material = store.get_key_material(key_record.key_id)
479
+
480
+ encrypted = data.get("content", "")
481
+ decrypted = _fernet_decrypt(encrypted.encode("utf-8"), key_material)
482
+ data["content"] = decrypted.decode("utf-8")
483
+ except Exception as exc:
484
+ logger.warning("Decryption failed: %s", exc)
485
+ data["content"] = "[DECRYPTION FAILED]"
486
+
487
+ return data
488
+
489
+ def _load_config(self) -> FortressConfig:
490
+ """Load fortress config from disk or create default."""
491
+ config_path = self._home / "memory" / "fortress.json"
492
+ if config_path.exists():
493
+ try:
494
+ data = json.loads(config_path.read_text(encoding="utf-8"))
495
+ return FortressConfig.model_validate(data)
496
+ except (json.JSONDecodeError, OSError, ValueError) as exc:
497
+ logger.warning("Failed to load fortress config: %s", exc)
498
+ return FortressConfig(encryption_enabled=self._encryption_enabled)
499
+
500
+ def _save_config(self, config: FortressConfig) -> None:
501
+ """Persist fortress config to disk."""
502
+ mem_dir = self._home / "memory"
503
+ mem_dir.mkdir(parents=True, exist_ok=True)
504
+ config_path = mem_dir / "fortress.json"
505
+ config_path.write_text(
506
+ config.model_dump_json(indent=2),
507
+ encoding="utf-8",
508
+ )
509
+
510
+ def _get_config(self) -> FortressConfig:
511
+ """Get cached or load config."""
512
+ if self._config is None:
513
+ self._config = self._load_config()
514
+ return self._config
515
+
516
+ def _audit(self, event_type: str, detail: str, metadata: Optional[dict] = None) -> None:
517
+ """Write an audit event if the security pillar is available."""
518
+ try:
519
+ from .pillars.security import audit_event
520
+
521
+ audit_event(
522
+ self._home,
523
+ event_type=event_type,
524
+ detail=detail,
525
+ agent="memory-fortress",
526
+ metadata=metadata,
527
+ )
528
+ except (ImportError, OSError) as exc:
529
+ logger.debug("Audit event skipped (%s): %s", event_type, exc)