@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
@@ -32,7 +32,6 @@ logger = logging.getLogger("skcapstone.trust")
32
32
  FEB_SEARCH_PATHS = [
33
33
  Path("~/.cloud9/feb-backups"),
34
34
  Path("~/.cloud9/febs"),
35
- Path("~/.openclaw/feb"),
36
35
  Path("~/clawd/cloud9/feb-backups"),
37
36
  Path("~/clawd/skills/cloud9/feb-backups"),
38
37
  Path("~/Nextcloud/p/smilintux-org/cloud9/feb-backups"),
@@ -86,7 +85,7 @@ def initialize_trust(home: Path) -> TrustState:
86
85
  "feb_search_paths": [str(p) for p in FEB_SEARCH_PATHS],
87
86
  "how_to_fix": "Place .feb files in ~/.skcapstone/trust/febs/ or install cloud9",
88
87
  }
89
- (trust_dir / "trust.json").write_text(json.dumps(trust_config, indent=2))
88
+ (trust_dir / "trust.json").write_text(json.dumps(trust_config, indent=2), encoding="utf-8")
90
89
  return TrustState(status=PillarStatus.MISSING)
91
90
 
92
91
 
@@ -171,19 +170,23 @@ def list_febs(home: Path) -> list[dict]:
171
170
 
172
171
  summaries = []
173
172
  for f in sorted(febs_dir.glob("*.feb")):
173
+ data = _read_feb_safe(f)
174
+ if data is None:
175
+ continue
174
176
  try:
175
- data = json.loads(f.read_text())
176
- payload = data.get("emotional_payload", data.get("cooked_state", {}))
177
+ payload = data.get("emotional_payload", data.get("emotional", data.get("cooked_state", {})))
177
178
  cooked = payload.get("cooked_state", payload)
179
+ emotion = cooked.get("primary_emotion", cooked.get("primary", "unknown"))
180
+ meta = data.get("metadata", {})
178
181
  summaries.append({
179
182
  "file": f.name,
180
- "timestamp": data.get("timestamp", data.get("metadata", {}).get("created_at", "unknown")),
181
- "emotion": cooked.get("primary_emotion", "unknown"),
183
+ "timestamp": data.get("timestamp", meta.get("created_at", "unknown")),
184
+ "emotion": emotion,
182
185
  "intensity": cooked.get("intensity", 0),
183
- "subject": payload.get("subject", "unknown"),
184
- "oof_triggered": data.get("metadata", {}).get("oof_triggered", False),
186
+ "subject": payload.get("subject", data.get("relationship_state", {}).get("ai_name", "unknown")),
187
+ "oof_triggered": meta.get("oof_triggered", False),
185
188
  })
186
- except (json.JSONDecodeError, Exception) as exc:
189
+ except Exception as exc:
187
190
  logger.warning("Could not parse FEB %s: %s", f.name, exc)
188
191
 
189
192
  return summaries
@@ -204,12 +207,11 @@ def export_febs_for_seed(home: Path) -> list[dict]:
204
207
 
205
208
  exported = []
206
209
  for f in febs_dir.glob("*.feb"):
207
- try:
208
- data = json.loads(f.read_text())
209
- data["_source_file"] = f.name
210
- exported.append(data)
211
- except (json.JSONDecodeError, Exception):
212
- pass
210
+ data = _read_feb_safe(f)
211
+ if data is None:
212
+ continue
213
+ data["_source_file"] = f.name
214
+ exported.append(data)
213
215
 
214
216
  return exported
215
217
 
@@ -239,7 +241,7 @@ def import_febs_from_seed(home: Path, seed_febs: list[dict]) -> int:
239
241
  if filename in existing:
240
242
  continue
241
243
 
242
- (febs_dir / filename).write_text(json.dumps(feb_data, indent=2))
244
+ (febs_dir / filename).write_text(json.dumps(feb_data, indent=2), encoding="utf-8")
243
245
  imported += 1
244
246
 
245
247
  if imported:
@@ -250,6 +252,44 @@ def import_febs_from_seed(home: Path, seed_febs: list[dict]) -> int:
250
252
 
251
253
  # --- Internal helpers ---
252
254
 
255
+ # OpenPGP binary packet header bytes (RFC 4880 §4.2)
256
+ _GPG_HEADER_BYTES = {0x8C, 0x85, 0x99, 0xC0, 0xC2, 0xC8, 0xCB}
257
+
258
+
259
+ def _read_feb_safe(path: Path) -> Optional[dict]:
260
+ """Read a FEB file safely, skipping GPG-encrypted binaries.
261
+
262
+ On Windows the default codec is cp1252, which chokes on binary .feb
263
+ files that are GPG-encrypted. We detect the OpenPGP packet header
264
+ and skip those files rather than crashing.
265
+
266
+ Args:
267
+ path: Path to the .feb file.
268
+
269
+ Returns:
270
+ Parsed FEB dict, or None if the file is binary/unreadable.
271
+ """
272
+ try:
273
+ raw = path.read_bytes()
274
+ except OSError as exc:
275
+ logger.warning("Cannot read FEB %s: %s", path.name, exc)
276
+ return None
277
+
278
+ # Detect GPG-encrypted binary by OpenPGP packet header
279
+ if raw and raw[0] in _GPG_HEADER_BYTES:
280
+ logger.debug(
281
+ "Skipping GPG-encrypted FEB (binary): %s — "
282
+ "import the peer's public key and run 'skcapstone sync pull' to decrypt",
283
+ path.name,
284
+ )
285
+ return None
286
+
287
+ try:
288
+ return json.loads(raw.decode("utf-8"))
289
+ except (UnicodeDecodeError, json.JSONDecodeError) as exc:
290
+ logger.warning("Cannot parse FEB %s: %s", path.name, exc)
291
+ return None
292
+
253
293
 
254
294
  def _discover_and_import_febs(home: Path) -> int:
255
295
  """Search known locations for FEB files and copy to agent home.
@@ -277,40 +317,62 @@ def _discover_and_import_febs(home: Path) -> int:
277
317
 
278
318
 
279
319
  def _derive_trust_from_febs(home: Path, feb_files: list[Path]) -> TrustState:
280
- """Derive trust state from FEB files, using the peak values."""
281
- peak_depth = 0.0
282
- peak_trust = 0.0
283
- peak_love = 0.0
320
+ """Derive trust state from FEB files using calibration thresholds."""
321
+ from ..trust_calibration import load_calibration
322
+
323
+ cal = load_calibration(home)
324
+ depths: list[float] = []
325
+ trusts: list[float] = []
326
+ loves: list[float] = []
284
327
  entangled = False
285
328
 
286
329
  for f in feb_files:
287
330
  try:
288
- data = json.loads(f.read_text())
331
+ data = _read_feb_safe(f)
332
+ if data is None:
333
+ continue
289
334
 
290
335
  rel = data.get("relationship_state", {})
291
- depth = float(rel.get("depth_level", 0))
336
+ depth = float(rel.get("depth_level", rel.get("depth", 0)))
292
337
  trust = float(rel.get("trust_level", 0))
293
- if trust > 1.0:
338
+ if trust > cal.normalization_cap:
294
339
  trust = trust / 10.0
295
340
 
296
- payload = data.get("emotional_payload", {})
341
+ payload = data.get("emotional_payload", data.get("emotional", {}))
297
342
  cooked = payload.get("cooked_state", payload)
298
343
  love = float(cooked.get("intensity", 0))
299
- if love > 1.0:
344
+ if love > cal.normalization_cap:
300
345
  love = love / 10.0
301
346
 
302
- entangled = entangled or (rel.get("quantum_entanglement") == "LOCKED")
347
+ is_locked = rel.get("quantum_entanglement") == "LOCKED"
348
+ is_entangled_flag = rel.get("entangled", False) or data.get("quantum", {}).get("entanglement_fidelity", 0) > 0.8
349
+ meets_threshold = depth >= cal.entanglement_depth and trust >= cal.entanglement_trust
350
+ entangled = entangled or is_locked or is_entangled_flag or meets_threshold
303
351
 
304
- peak_depth = max(peak_depth, depth)
305
- peak_trust = max(peak_trust, trust)
306
- peak_love = max(peak_love, love)
352
+ depths.append(depth)
353
+ trusts.append(trust)
354
+ loves.append(love)
307
355
  except (json.JSONDecodeError, ValueError, Exception) as exc:
308
356
  logger.warning("Could not parse FEB %s: %s", f.name, exc)
309
357
 
358
+ if cal.peak_strategy == "average" and depths:
359
+ final_depth = sum(depths) / len(depths)
360
+ final_trust = sum(trusts) / len(trusts)
361
+ final_love = sum(loves) / len(loves)
362
+ elif cal.peak_strategy == "weighted" and depths:
363
+ total_weight = sum(range(1, len(depths) + 1))
364
+ final_depth = sum(d * (i + 1) for i, d in enumerate(depths)) / total_weight
365
+ final_trust = sum(t * (i + 1) for i, t in enumerate(trusts)) / total_weight
366
+ final_love = sum(l * (i + 1) for i, l in enumerate(loves)) / total_weight
367
+ else:
368
+ final_depth = max(depths) if depths else 0.0
369
+ final_trust = max(trusts) if trusts else 0.0
370
+ final_love = max(loves) if loves else 0.0
371
+
310
372
  state = TrustState(
311
- depth=peak_depth,
312
- trust_level=peak_trust,
313
- love_intensity=peak_love,
373
+ depth=final_depth,
374
+ trust_level=final_trust,
375
+ love_intensity=final_love,
314
376
  entangled=entangled,
315
377
  last_rehydration=datetime.now(timezone.utc),
316
378
  feb_count=len(feb_files),
@@ -332,4 +394,4 @@ def _write_trust_json(trust_dir: Path, state: TrustState) -> None:
332
394
  "feb_count": state.feb_count,
333
395
  "last_rehydration": state.last_rehydration.isoformat() if state.last_rehydration else None,
334
396
  }
335
- (trust_dir / "trust.json").write_text(json.dumps(data, indent=2))
397
+ (trust_dir / "trust.json").write_text(json.dumps(data, indent=2), encoding="utf-8")
@@ -0,0 +1,244 @@
1
+ """SKCapstone plugin loader.
2
+
3
+ Plugins live in ``~/.skcapstone/plugins/*.py`` and are loaded at daemon and
4
+ MCP server startup. Each plugin module must expose a ``register`` function::
5
+
6
+ def register(mcp_server, app) -> None:
7
+ ...
8
+
9
+ ``mcp_server`` is the :class:`mcp.server.Server` instance when called from
10
+ the MCP server process, or ``None`` when called from the daemon process.
11
+
12
+ ``app`` is the FastAPI :class:`~fastapi.FastAPI` instance when the docs
13
+ server is running, or ``None`` otherwise.
14
+
15
+ Plugins that add MCP tools call :func:`register_tool` inside ``register``::
16
+
17
+ from skcapstone.plugins import register_tool
18
+ from mcp.types import Tool, TextContent
19
+
20
+ async def _handler(arguments: dict) -> list[TextContent]:
21
+ return [TextContent(type="text", text="pong")]
22
+
23
+ def register(mcp_server, app):
24
+ register_tool(
25
+ Tool(
26
+ name="ping",
27
+ description="Respond with pong.",
28
+ inputSchema={"type": "object", "properties": {}},
29
+ ),
30
+ _handler,
31
+ )
32
+
33
+ The ``_registry`` singleton is process-local — the daemon and the MCP server
34
+ each maintain independent state. Hot-reload is triggered by sending SIGHUP to
35
+ the daemon PID and causes a fresh scan of ``~/.skcapstone/plugins/``.
36
+
37
+ Files whose names start with ``_`` are skipped (use them for shared helpers).
38
+ """
39
+
40
+ from __future__ import annotations
41
+
42
+ import importlib.util
43
+ import logging
44
+ import sys
45
+ import types
46
+ from pathlib import Path
47
+ from typing import Any, Callable, Coroutine
48
+
49
+ logger = logging.getLogger("skcapstone.plugins")
50
+
51
+ PLUGIN_DIR_NAME = "plugins"
52
+
53
+
54
+ class PluginRegistry:
55
+ """Process-local registry of dynamically loaded plugin tools and handlers.
56
+
57
+ Each process (daemon, MCP server) owns an independent instance via the
58
+ module-level ``_registry`` singleton.
59
+ """
60
+
61
+ def __init__(self) -> None:
62
+ # Use plain list/dict so we don't force-import mcp at module load time.
63
+ self._tools: list = []
64
+ self._handlers: dict[str, Callable[..., Coroutine[Any, Any, Any]]] = {}
65
+ # Canonical resolved path → loaded module, for hot-reload eviction.
66
+ self._loaded: dict[str, types.ModuleType] = {}
67
+
68
+ # ------------------------------------------------------------------
69
+ # Registration — called by plugins via register_tool()
70
+ # ------------------------------------------------------------------
71
+
72
+ def register_tool(
73
+ self,
74
+ tool: Any,
75
+ handler: Callable[..., Coroutine[Any, Any, Any]],
76
+ ) -> None:
77
+ """Add an MCP tool + async handler to the registry.
78
+
79
+ Idempotent: re-registering the same tool name replaces the old entry.
80
+ """
81
+ self._tools = [t for t in self._tools if t.name != tool.name]
82
+ self._tools.append(tool)
83
+ self._handlers[tool.name] = handler
84
+ logger.debug("Plugin registered tool: %s", tool.name)
85
+
86
+ # ------------------------------------------------------------------
87
+ # Query — called by mcp_server.py at list/dispatch time
88
+ # ------------------------------------------------------------------
89
+
90
+ def get_tools(self) -> list:
91
+ """Return a snapshot of all plugin-registered Tool definitions."""
92
+ return list(self._tools)
93
+
94
+ def get_handlers(self) -> dict[str, Callable[..., Coroutine[Any, Any, Any]]]:
95
+ """Return a snapshot of all plugin-registered handler callables."""
96
+ return dict(self._handlers)
97
+
98
+ # ------------------------------------------------------------------
99
+ # Internal loading helpers
100
+ # ------------------------------------------------------------------
101
+
102
+ def _load_one(self, plugin_path: Path, mcp_server: Any, app: Any) -> bool:
103
+ """Load a single plugin file and invoke its ``register()`` function.
104
+
105
+ Returns ``True`` on success, ``False`` on any error.
106
+ """
107
+ module_name = f"skcapstone._plugin_{plugin_path.stem}"
108
+ # Evict any cached version so hot-reload always re-executes the file.
109
+ sys.modules.pop(module_name, None)
110
+ try:
111
+ spec = importlib.util.spec_from_file_location(module_name, plugin_path)
112
+ if spec is None or spec.loader is None:
113
+ logger.warning("Plugin %s: cannot create module spec", plugin_path.name)
114
+ return False
115
+
116
+ mod = importlib.util.module_from_spec(spec)
117
+ sys.modules[module_name] = mod
118
+ spec.loader.exec_module(mod) # type: ignore[union-attr]
119
+
120
+ if not hasattr(mod, "register"):
121
+ logger.warning(
122
+ "Plugin %s: no register() function — skipping", plugin_path.name
123
+ )
124
+ sys.modules.pop(module_name, None)
125
+ return False
126
+
127
+ mod.register(mcp_server, app)
128
+ self._loaded[str(plugin_path.resolve())] = mod
129
+ logger.info("Plugin loaded: %s", plugin_path.name)
130
+ return True
131
+
132
+ except Exception as exc:
133
+ logger.error(
134
+ "Plugin %s failed to load: %s", plugin_path.name, exc, exc_info=True
135
+ )
136
+ sys.modules.pop(module_name, None)
137
+ return False
138
+
139
+ # ------------------------------------------------------------------
140
+ # Public loading API
141
+ # ------------------------------------------------------------------
142
+
143
+ def scan_and_load(self, plugin_dir: Path, mcp_server: Any, app: Any) -> int:
144
+ """Scan *plugin_dir* for ``*.py`` files and load each as a plugin.
145
+
146
+ Files whose names start with ``_`` are skipped (private helpers).
147
+ Returns the number of successfully loaded plugins.
148
+ """
149
+ if not plugin_dir.exists():
150
+ logger.debug("Plugin directory not found: %s", plugin_dir)
151
+ return 0
152
+
153
+ count = 0
154
+ for plugin_path in sorted(plugin_dir.glob("*.py")):
155
+ if plugin_path.name.startswith("_"):
156
+ continue
157
+ if self._load_one(plugin_path, mcp_server, app):
158
+ count += 1
159
+
160
+ if count:
161
+ logger.info("Loaded %d plugin(s) from %s", count, plugin_dir)
162
+ else:
163
+ logger.debug("No plugins found in %s", plugin_dir)
164
+ return count
165
+
166
+ def clear(self) -> None:
167
+ """Unload all plugins and reset the registry."""
168
+ for mod in self._loaded.values():
169
+ sys.modules.pop(getattr(mod, "__name__", ""), None)
170
+ self._tools.clear()
171
+ self._handlers.clear()
172
+ self._loaded.clear()
173
+ logger.debug("Plugin registry cleared")
174
+
175
+ def reload(self, plugin_dir: Path, mcp_server: Any, app: Any) -> int:
176
+ """Clear and reload all plugins from *plugin_dir*.
177
+
178
+ Called on SIGHUP for hot-reload. Returns the number of plugins loaded.
179
+ """
180
+ logger.info("Plugin hot-reload — clearing %d plugin(s)", len(self._loaded))
181
+ self.clear()
182
+ return self.scan_and_load(plugin_dir, mcp_server, app)
183
+
184
+
185
+ # Module-level singleton — each process (daemon / MCP server) has its own copy.
186
+ _registry = PluginRegistry()
187
+
188
+
189
+ # ------------------------------------------------------------------
190
+ # Public convenience API used by plugins and the MCP server
191
+ # ------------------------------------------------------------------
192
+
193
+
194
+ def register_tool(
195
+ tool: Any,
196
+ handler: Callable[..., Coroutine[Any, Any, Any]],
197
+ ) -> None:
198
+ """Register an MCP tool from within a plugin's ``register()`` function.
199
+
200
+ Example::
201
+
202
+ from skcapstone.plugins import register_tool
203
+ from mcp.types import Tool, TextContent
204
+
205
+ async def _handler(arguments: dict) -> list[TextContent]:
206
+ return [TextContent(type="text", text="ok")]
207
+
208
+ def register(mcp_server, app):
209
+ register_tool(
210
+ Tool(
211
+ name="my_tool",
212
+ description="Does something useful.",
213
+ inputSchema={"type": "object", "properties": {}},
214
+ ),
215
+ _handler,
216
+ )
217
+ """
218
+ _registry.register_tool(tool, handler)
219
+
220
+
221
+ def load_plugins(home: Path, mcp_server: Any, app: Any) -> int:
222
+ """Scan ``{home}/plugins/*.py`` and load each plugin.
223
+
224
+ Returns the count of successfully loaded plugins.
225
+ """
226
+ return _registry.scan_and_load(home / PLUGIN_DIR_NAME, mcp_server, app)
227
+
228
+
229
+ def reload_plugins(home: Path, mcp_server: Any, app: Any) -> int:
230
+ """Clear and reload all plugins from ``{home}/plugins/*.py``.
231
+
232
+ Intended to be called from the SIGHUP handler for live hot-reload.
233
+ """
234
+ return _registry.reload(home / PLUGIN_DIR_NAME, mcp_server, app)
235
+
236
+
237
+ def get_plugin_tools() -> list:
238
+ """Return all MCP Tool definitions registered by plugins."""
239
+ return _registry.get_tools()
240
+
241
+
242
+ def get_plugin_handlers() -> dict[str, Callable[..., Coroutine[Any, Any, Any]]]:
243
+ """Return all handler callables registered by plugins."""
244
+ return _registry.get_handlers()