@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,405 @@
1
+ """Persistent error recovery queue for failed operations.
2
+
3
+ Operations that fail (LLM calls, message sends, sync failures) are
4
+ enqueued here and retried with exponential backoff up to MAX_RETRIES times.
5
+ The queue is persisted to ~/.skcapstone/error_queue.json.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import logging
12
+ import uuid
13
+ from datetime import datetime, timezone
14
+ from enum import Enum
15
+ from pathlib import Path
16
+ from typing import Any, Callable, Optional
17
+
18
+ logger = logging.getLogger("skcapstone.error_queue")
19
+
20
+ DEFAULT_QUEUE_PATH = Path("~/.skcapstone/error_queue.json")
21
+ MAX_RETRIES = 3
22
+ # Exponential backoff: delay = BASE_BACKOFF_SECONDS * 2^attempt (seconds)
23
+ BASE_BACKOFF_SECONDS = 60
24
+
25
+
26
+ class ErrorStatus(str, Enum):
27
+ """Life-cycle status of a queued error entry."""
28
+
29
+ PENDING = "pending" # Waiting for next retry attempt
30
+ RETRYING = "retrying" # Retry in progress (transient; set during retry)
31
+ EXHAUSTED = "exhausted" # Max retries reached
32
+ RESOLVED = "resolved" # Successfully retried and recovered
33
+
34
+
35
+ class ErrorEntry:
36
+ """One failed operation stored in the error queue.
37
+
38
+ Attributes:
39
+ entry_id: Unique identifier (UUID4 hex).
40
+ operation_type: Logical type label, e.g. "llm_call", "message_send".
41
+ payload: Arbitrary serialisable data needed to replay the operation.
42
+ error_message: Human-readable description of the original failure.
43
+ created_at: ISO-8601 UTC timestamp when the entry was created.
44
+ retry_count: Number of retries attempted so far.
45
+ next_retry_at: ISO-8601 UTC timestamp after which the next retry is due.
46
+ status: Current :class:`ErrorStatus`.
47
+ """
48
+
49
+ def __init__(
50
+ self,
51
+ operation_type: str,
52
+ payload: dict[str, Any],
53
+ error_message: str,
54
+ entry_id: Optional[str] = None,
55
+ created_at: Optional[str] = None,
56
+ retry_count: int = 0,
57
+ next_retry_at: Optional[str] = None,
58
+ status: str = ErrorStatus.PENDING,
59
+ ) -> None:
60
+ self.entry_id: str = entry_id or uuid.uuid4().hex
61
+ self.operation_type: str = operation_type
62
+ self.payload: dict[str, Any] = payload
63
+ self.error_message: str = error_message
64
+ self.created_at: str = created_at or _now_iso()
65
+ self.retry_count: int = retry_count
66
+ self.next_retry_at: Optional[str] = next_retry_at
67
+ # Always store the bare string value, not the enum repr.
68
+ self.status: str = status.value if isinstance(status, ErrorStatus) else str(status)
69
+
70
+ # ------------------------------------------------------------------
71
+ # Serialisation helpers
72
+ # ------------------------------------------------------------------
73
+
74
+ def to_dict(self) -> dict[str, Any]:
75
+ """Serialise to a plain dict (JSON-safe).
76
+
77
+ Returns:
78
+ Dict representation of the entry.
79
+ """
80
+ return {
81
+ "entry_id": self.entry_id,
82
+ "operation_type": self.operation_type,
83
+ "payload": self.payload,
84
+ "error_message": self.error_message,
85
+ "created_at": self.created_at,
86
+ "retry_count": self.retry_count,
87
+ "next_retry_at": self.next_retry_at,
88
+ "status": self.status,
89
+ }
90
+
91
+ @classmethod
92
+ def from_dict(cls, data: dict[str, Any]) -> "ErrorEntry":
93
+ """Deserialise from a plain dict.
94
+
95
+ Args:
96
+ data: Dict previously produced by :meth:`to_dict`.
97
+
98
+ Returns:
99
+ Reconstructed :class:`ErrorEntry`.
100
+ """
101
+ return cls(
102
+ entry_id=data["entry_id"],
103
+ operation_type=data["operation_type"],
104
+ payload=data.get("payload", {}),
105
+ error_message=data.get("error_message", ""),
106
+ created_at=data.get("created_at"),
107
+ retry_count=data.get("retry_count", 0),
108
+ next_retry_at=data.get("next_retry_at"),
109
+ status=data.get("status", ErrorStatus.PENDING),
110
+ )
111
+
112
+ def __repr__(self) -> str:
113
+ return (
114
+ f"<ErrorEntry id={self.entry_id[:8]} op={self.operation_type} "
115
+ f"retries={self.retry_count} status={self.status}>"
116
+ )
117
+
118
+
119
+ class ErrorQueue:
120
+ """Persistent queue for failed operations with exponential-backoff retry.
121
+
122
+ The queue is stored as a JSON array in *path* (default
123
+ ``~/.skcapstone/error_queue.json``). All mutating methods persist
124
+ immediately so the queue survives process restarts.
125
+
126
+ Args:
127
+ path: Path to the JSON file. Expanded with :meth:`Path.expanduser`.
128
+ max_retries: Maximum number of retry attempts before an entry is
129
+ marked :attr:`ErrorStatus.EXHAUSTED`.
130
+ base_backoff: Base delay in seconds for exponential backoff.
131
+
132
+ Example::
133
+
134
+ queue = ErrorQueue()
135
+ queue.enqueue("llm_call", {"prompt": "..."}, "timeout")
136
+ due = queue.due_entries()
137
+ for entry in due:
138
+ queue.retry(entry.entry_id, handler=my_llm_handler)
139
+ """
140
+
141
+ def __init__(
142
+ self,
143
+ path: Optional[Path] = None,
144
+ max_retries: int = MAX_RETRIES,
145
+ base_backoff: int = BASE_BACKOFF_SECONDS,
146
+ ) -> None:
147
+ self._path: Path = (path or DEFAULT_QUEUE_PATH).expanduser()
148
+ self._max_retries = max_retries
149
+ self._base_backoff = base_backoff
150
+
151
+ # ------------------------------------------------------------------
152
+ # Persistence
153
+ # ------------------------------------------------------------------
154
+
155
+ def _load(self) -> list[ErrorEntry]:
156
+ """Load all entries from disk.
157
+
158
+ Returns:
159
+ List of :class:`ErrorEntry` objects.
160
+ """
161
+ if not self._path.exists():
162
+ return []
163
+ try:
164
+ data = json.loads(self._path.read_text(encoding="utf-8"))
165
+ return [ErrorEntry.from_dict(d) for d in data]
166
+ except (json.JSONDecodeError, KeyError) as exc:
167
+ logger.warning("error_queue: corrupt queue file (%s); starting fresh", exc)
168
+ return []
169
+
170
+ def _save(self, entries: list[ErrorEntry]) -> None:
171
+ """Persist *entries* to disk atomically.
172
+
173
+ Args:
174
+ entries: Current list of queue entries to write.
175
+ """
176
+ self._path.parent.mkdir(parents=True, exist_ok=True)
177
+ tmp = self._path.with_suffix(".json.tmp")
178
+ tmp.write_text(
179
+ json.dumps([e.to_dict() for e in entries], indent=2),
180
+ encoding="utf-8",
181
+ )
182
+ tmp.replace(self._path)
183
+
184
+ # ------------------------------------------------------------------
185
+ # Public API
186
+ # ------------------------------------------------------------------
187
+
188
+ def enqueue(
189
+ self,
190
+ operation_type: str,
191
+ payload: dict[str, Any],
192
+ error_message: str,
193
+ ) -> ErrorEntry:
194
+ """Add a new failed operation to the queue.
195
+
196
+ Args:
197
+ operation_type: Short label for the operation (e.g. ``"llm_call"``).
198
+ payload: Data needed to re-run the operation.
199
+ error_message: Human-readable description of the failure.
200
+
201
+ Returns:
202
+ The newly created :class:`ErrorEntry`.
203
+ """
204
+ entries = self._load()
205
+ entry = ErrorEntry(
206
+ operation_type=operation_type,
207
+ payload=payload,
208
+ error_message=error_message,
209
+ )
210
+ entry.next_retry_at = _backoff_ts(0, self._base_backoff)
211
+ entries.append(entry)
212
+ self._save(entries)
213
+ logger.info("error_queue: enqueued %s [%s]", entry.entry_id[:8], operation_type)
214
+ return entry
215
+
216
+ def list_entries(
217
+ self,
218
+ status: Optional[str] = None,
219
+ include_resolved: bool = False,
220
+ ) -> list[ErrorEntry]:
221
+ """Return all (or filtered) queue entries.
222
+
223
+ Args:
224
+ status: If given, only return entries with this status string.
225
+ include_resolved: If ``True``, include resolved entries.
226
+
227
+ Returns:
228
+ Filtered list of :class:`ErrorEntry`, newest first.
229
+ """
230
+ entries = self._load()
231
+ if not include_resolved:
232
+ entries = [e for e in entries if e.status != ErrorStatus.RESOLVED]
233
+ if status:
234
+ entries = [e for e in entries if e.status == status]
235
+ return sorted(entries, key=lambda e: e.created_at, reverse=True)
236
+
237
+ def due_entries(self) -> list[ErrorEntry]:
238
+ """Return entries that are due for a retry attempt right now.
239
+
240
+ Returns:
241
+ List of :class:`ErrorEntry` objects whose ``next_retry_at`` is
242
+ in the past and whose status is :attr:`ErrorStatus.PENDING`.
243
+ """
244
+ now = _now_iso()
245
+ return [
246
+ e
247
+ for e in self._load()
248
+ if e.status == ErrorStatus.PENDING
249
+ and e.next_retry_at is not None
250
+ and e.next_retry_at <= now
251
+ ]
252
+
253
+ def retry(
254
+ self,
255
+ entry_id: str,
256
+ handler: Optional[Callable[[ErrorEntry], bool]] = None,
257
+ ) -> bool:
258
+ """Attempt to retry a single queued entry.
259
+
260
+ The *handler* callable receives the :class:`ErrorEntry` and returns
261
+ ``True`` on success, ``False`` on failure. When no handler is
262
+ provided the entry is simply promoted (useful for manual resolution).
263
+
264
+ Args:
265
+ entry_id: The ``entry_id`` of the entry to retry.
266
+ handler: Optional callable ``(ErrorEntry) -> bool``.
267
+
268
+ Returns:
269
+ ``True`` if the retry succeeded (entry marked resolved),
270
+ ``False`` otherwise.
271
+ """
272
+ entries = self._load()
273
+ target = next((e for e in entries if e.entry_id == entry_id), None)
274
+ if target is None:
275
+ logger.warning("error_queue: retry — entry %s not found", entry_id)
276
+ return False
277
+
278
+ if target.status == ErrorStatus.EXHAUSTED:
279
+ logger.info("error_queue: entry %s is exhausted; skipping", entry_id[:8])
280
+ return False
281
+
282
+ target.status = ErrorStatus.RETRYING
283
+ self._save(entries)
284
+
285
+ success = handler(target) if handler else False
286
+
287
+ if success:
288
+ target.status = ErrorStatus.RESOLVED
289
+ logger.info("error_queue: entry %s resolved", entry_id[:8])
290
+ else:
291
+ target.retry_count += 1
292
+ if target.retry_count >= self._max_retries:
293
+ target.status = ErrorStatus.EXHAUSTED
294
+ target.next_retry_at = None
295
+ logger.warning(
296
+ "error_queue: entry %s exhausted after %d retries",
297
+ entry_id[:8],
298
+ target.retry_count,
299
+ )
300
+ else:
301
+ target.status = ErrorStatus.PENDING
302
+ target.next_retry_at = _backoff_ts(target.retry_count, self._base_backoff)
303
+ logger.info(
304
+ "error_queue: entry %s rescheduled (attempt %d/%d)",
305
+ entry_id[:8],
306
+ target.retry_count,
307
+ self._max_retries,
308
+ )
309
+
310
+ self._save(entries)
311
+ return success
312
+
313
+ def retry_all_due(
314
+ self,
315
+ handler: Optional[Callable[[ErrorEntry], bool]] = None,
316
+ ) -> dict[str, bool]:
317
+ """Retry all entries that are currently due.
318
+
319
+ Args:
320
+ handler: Optional callable ``(ErrorEntry) -> bool``.
321
+
322
+ Returns:
323
+ Dict mapping ``entry_id`` to success bool.
324
+ """
325
+ due = self.due_entries()
326
+ results: dict[str, bool] = {}
327
+ for entry in due:
328
+ results[entry.entry_id] = self.retry(entry.entry_id, handler=handler)
329
+ return results
330
+
331
+ def remove(self, entry_id: str) -> bool:
332
+ """Permanently remove a single entry from the queue.
333
+
334
+ Args:
335
+ entry_id: The ``entry_id`` to remove.
336
+
337
+ Returns:
338
+ ``True`` if the entry was found and removed, ``False`` otherwise.
339
+ """
340
+ entries = self._load()
341
+ before = len(entries)
342
+ entries = [e for e in entries if e.entry_id != entry_id]
343
+ if len(entries) == before:
344
+ return False
345
+ self._save(entries)
346
+ return True
347
+
348
+ def clear_all(self, status: Optional[str] = None) -> int:
349
+ """Remove all entries (or all entries with a given status).
350
+
351
+ Args:
352
+ status: If given, only remove entries with this status string.
353
+
354
+ Returns:
355
+ Number of entries removed.
356
+ """
357
+ entries = self._load()
358
+ if status:
359
+ kept = [e for e in entries if e.status != status]
360
+ else:
361
+ kept = []
362
+ removed = len(entries) - len(kept)
363
+ self._save(kept)
364
+ return removed
365
+
366
+ def stats(self) -> dict[str, int]:
367
+ """Return a count summary grouped by status.
368
+
369
+ Returns:
370
+ Dict mapping status string to count.
371
+ """
372
+ entries = self._load()
373
+ counts: dict[str, int] = {s.value: 0 for s in ErrorStatus}
374
+ for e in entries:
375
+ counts[e.status] = counts.get(e.status, 0) + 1
376
+ counts["total"] = len(entries)
377
+ return counts
378
+
379
+
380
+ # ---------------------------------------------------------------------------
381
+ # Internal helpers
382
+ # ---------------------------------------------------------------------------
383
+
384
+ def _now_iso() -> str:
385
+ """Return current UTC time as ISO-8601 string."""
386
+ return datetime.now(timezone.utc).isoformat()
387
+
388
+
389
+ def _backoff_ts(attempt: int, base: int) -> str:
390
+ """Compute next-retry timestamp using exponential backoff.
391
+
392
+ delay = base * 2^attempt (seconds)
393
+
394
+ Args:
395
+ attempt: Zero-based attempt index.
396
+ base: Base delay in seconds.
397
+
398
+ Returns:
399
+ ISO-8601 UTC timestamp string.
400
+ """
401
+ import math
402
+ from datetime import timedelta
403
+
404
+ delay = base * (2 ** attempt)
405
+ return (datetime.now(timezone.utc) + timedelta(seconds=delay)).isoformat()