@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,439 @@
1
+ """
2
+ Cron-like scheduler for recurring agent background tasks.
3
+
4
+ Runs a single daemon thread that wakes up every TICK_INTERVAL seconds,
5
+ checks which tasks are due, and fires their callbacks.
6
+
7
+ Built-in recurring tasks:
8
+ - heartbeat_pulse — every 30 seconds
9
+ - backend_reprobe — every 5 minutes
10
+ - memory_promotion_sweep — every hour
11
+ - profile_freshness_check — every 24 hours
12
+
13
+ Usage:
14
+ scheduler = build_scheduler(home, stop_event, consciousness_loop, beacon)
15
+ thread = scheduler.start() # returns the daemon thread
16
+ print(scheduler.status()) # list[dict] of task state
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import logging
22
+ import threading
23
+ from dataclasses import dataclass, field
24
+ from datetime import datetime, timedelta, timezone
25
+ from pathlib import Path
26
+ from typing import Callable, Optional
27
+
28
+ logger = logging.getLogger("skcapstone.scheduled_tasks")
29
+
30
+
31
+ # ---------------------------------------------------------------------------
32
+ # Core data structures
33
+ # ---------------------------------------------------------------------------
34
+
35
+
36
+ @dataclass
37
+ class ScheduledTask:
38
+ """A recurring task entry managed by TaskScheduler.
39
+
40
+ Attributes:
41
+ name: Unique task name.
42
+ interval_seconds: How often (in seconds) the task should run.
43
+ callback: Zero-argument callable invoked on each run.
44
+ last_run: UTC timestamp of the most recent execution (or None if never run).
45
+ last_error: String representation of the last exception, if any.
46
+ run_count: Total number of successful (non-raising) executions.
47
+ error_count: Total number of executions that raised an exception.
48
+ """
49
+
50
+ name: str
51
+ interval_seconds: float
52
+ callback: Callable[[], None]
53
+ last_run: Optional[datetime] = None
54
+ last_error: Optional[str] = None
55
+ run_count: int = 0
56
+ error_count: int = 0
57
+
58
+ def is_due(self, now: Optional[datetime] = None) -> bool:
59
+ """Return True if the task interval has elapsed since last_run.
60
+
61
+ A task with no prior run is always considered due.
62
+
63
+ Args:
64
+ now: Reference time for the check (defaults to UTC now).
65
+ """
66
+ if self.last_run is None:
67
+ return True
68
+ reference = now or datetime.now(timezone.utc)
69
+ elapsed = (reference - self.last_run).total_seconds()
70
+ return elapsed >= self.interval_seconds
71
+
72
+ def run(self) -> None:
73
+ """Execute the callback, recording outcome regardless of success.
74
+
75
+ On success: increments run_count, clears last_error.
76
+ On failure: increments error_count, stores exception string in last_error.
77
+ In both cases last_run is updated so the interval resets.
78
+ """
79
+ try:
80
+ self.callback()
81
+ self.run_count += 1
82
+ self.last_error = None
83
+ logger.debug("Scheduled task '%s' completed (run #%d)", self.name, self.run_count)
84
+ except Exception as exc:
85
+ self.error_count += 1
86
+ self.last_error = str(exc)
87
+ logger.error("Scheduled task '%s' failed: %s", self.name, exc)
88
+ finally:
89
+ self.last_run = datetime.now(timezone.utc)
90
+
91
+
92
+ # ---------------------------------------------------------------------------
93
+ # Scheduler
94
+ # ---------------------------------------------------------------------------
95
+
96
+
97
+ class TaskScheduler:
98
+ """Cron-like scheduler that fires registered tasks on configurable intervals.
99
+
100
+ Runs one daemon thread (``daemon-scheduler``) that wakes up every
101
+ ``TICK_INTERVAL`` seconds, checks which tasks are due, and calls their
102
+ callbacks inline (serially, in registration order).
103
+
104
+ Args:
105
+ home: Agent home directory.
106
+ stop_event: Daemon stop event; scheduler thread exits when set.
107
+ tick_interval: How often (seconds) the scheduler loop wakes to check tasks.
108
+ """
109
+
110
+ TICK_INTERVAL: float = 5.0
111
+
112
+ def __init__(
113
+ self,
114
+ home: Path,
115
+ stop_event: threading.Event,
116
+ tick_interval: float = TICK_INTERVAL,
117
+ ) -> None:
118
+ self._home = home
119
+ self._stop_event = stop_event
120
+ self._tick_interval = tick_interval
121
+ self._tasks: list[ScheduledTask] = []
122
+ self._lock = threading.Lock()
123
+ self._thread: Optional[threading.Thread] = None
124
+
125
+ # ------------------------------------------------------------------
126
+ # Public API
127
+ # ------------------------------------------------------------------
128
+
129
+ def register(
130
+ self,
131
+ name: str,
132
+ interval_seconds: float,
133
+ callback: Callable[[], None],
134
+ ) -> ScheduledTask:
135
+ """Register a recurring task.
136
+
137
+ Args:
138
+ name: Unique task name (used in logs and status output).
139
+ interval_seconds: Minimum seconds between executions.
140
+ callback: Zero-argument callable to invoke.
141
+
142
+ Returns:
143
+ The created ScheduledTask (caller may inspect it at runtime).
144
+ """
145
+ task = ScheduledTask(name=name, interval_seconds=interval_seconds, callback=callback)
146
+ with self._lock:
147
+ self._tasks.append(task)
148
+ logger.debug("Registered scheduled task '%s' every %.0fs", name, interval_seconds)
149
+ return task
150
+
151
+ def start(self) -> threading.Thread:
152
+ """Start the scheduler background thread.
153
+
154
+ Returns:
155
+ The started daemon thread (for lifecycle management by caller).
156
+ """
157
+ self._thread = threading.Thread(
158
+ target=self._run,
159
+ name="daemon-scheduler",
160
+ daemon=True,
161
+ )
162
+ self._thread.start()
163
+ logger.info(
164
+ "Task scheduler started — %d task(s), tick=%.0fs",
165
+ len(self._tasks),
166
+ self._tick_interval,
167
+ )
168
+ return self._thread
169
+
170
+ def status(self) -> list[dict]:
171
+ """Return serializable status for all registered tasks.
172
+
173
+ Returns:
174
+ List of dicts with: name, interval_seconds, last_run (ISO or None),
175
+ last_error, run_count, error_count.
176
+ """
177
+ with self._lock:
178
+ return [
179
+ {
180
+ "name": t.name,
181
+ "interval_seconds": t.interval_seconds,
182
+ "last_run": t.last_run.isoformat() if t.last_run else None,
183
+ "last_error": t.last_error,
184
+ "run_count": t.run_count,
185
+ "error_count": t.error_count,
186
+ }
187
+ for t in self._tasks
188
+ ]
189
+
190
+ # ------------------------------------------------------------------
191
+ # Internal
192
+ # ------------------------------------------------------------------
193
+
194
+ def _run(self) -> None:
195
+ """Main scheduler loop — ticks every TICK_INTERVAL seconds."""
196
+ while not self._stop_event.is_set():
197
+ now = datetime.now(timezone.utc)
198
+ with self._lock:
199
+ tasks_snapshot = list(self._tasks)
200
+
201
+ for task in tasks_snapshot:
202
+ if task.is_due(now):
203
+ task.run()
204
+
205
+ self._stop_event.wait(timeout=self._tick_interval)
206
+
207
+
208
+ # ---------------------------------------------------------------------------
209
+ # Built-in task factories
210
+ # ---------------------------------------------------------------------------
211
+
212
+
213
+ def make_memory_promotion_task(home: Path) -> Callable[[], None]:
214
+ """Return a callback that runs an hourly memory promotion sweep.
215
+
216
+ Instantiates PromotionEngine lazily (so import errors are deferred until
217
+ first run, matching the graceful-import pattern used elsewhere in the daemon).
218
+
219
+ Args:
220
+ home: Agent home directory containing the ``memory/`` subtree.
221
+ """
222
+
223
+ def _run() -> None:
224
+ from .memory_promoter import PromotionEngine
225
+
226
+ engine = PromotionEngine(home)
227
+ result = engine.sweep()
228
+ if result.promoted:
229
+ logger.info(
230
+ "Memory promotion sweep: %d promoted of %d scanned",
231
+ len(result.promoted),
232
+ result.scanned,
233
+ )
234
+ else:
235
+ logger.debug(
236
+ "Memory promotion sweep: %d scanned, 0 promoted",
237
+ result.scanned,
238
+ )
239
+
240
+ return _run
241
+
242
+
243
+ def make_backend_reprobe_task(consciousness_loop: object) -> Callable[[], None]:
244
+ """Return a callback that re-probes LLM backend availability every 5 min.
245
+
246
+ Reaches into ``consciousness_loop._bridge._probe_available_backends()``.
247
+ Silently no-ops if any of those attributes are missing, keeping the
248
+ scheduler stable when the consciousness loop is unavailable.
249
+
250
+ Args:
251
+ consciousness_loop: ConsciousnessLoop instance (or None).
252
+ """
253
+
254
+ def _run() -> None:
255
+ if consciousness_loop is None:
256
+ return
257
+ bridge = getattr(consciousness_loop, "_bridge", None)
258
+ if bridge is None:
259
+ return
260
+ probe_fn = getattr(bridge, "_probe_available_backends", None)
261
+ if callable(probe_fn):
262
+ probe_fn()
263
+ available = getattr(bridge, "_available", {})
264
+ enabled = [k for k, v in available.items() if v]
265
+ logger.debug("Backend re-probe: available=%s", enabled)
266
+
267
+ return _run
268
+
269
+
270
+ def make_heartbeat_task(
271
+ beacon: object,
272
+ consciousness_active_fn: Callable[[], bool],
273
+ ) -> Callable[[], None]:
274
+ """Return a callback that emits a heartbeat pulse every 30 seconds.
275
+
276
+ Args:
277
+ beacon: HeartbeatBeacon instance (or None).
278
+ consciousness_active_fn: Zero-arg callable returning bool — whether
279
+ the consciousness loop is currently active.
280
+ """
281
+
282
+ def _run() -> None:
283
+ if beacon is None:
284
+ return
285
+ active = consciousness_active_fn()
286
+ beacon.pulse(consciousness_active=active)
287
+ logger.debug("Heartbeat pulse sent (consciousness_active=%s)", active)
288
+
289
+ return _run
290
+
291
+
292
+ def make_profile_freshness_task(home: Path, max_age_days: int = 7) -> Callable[[], None]:
293
+ """Return a callback that checks agent profile freshness daily.
294
+
295
+ Inspects:
296
+ - ``identity/identity.json``
297
+ - ``data/model_profiles/*.json`` (if present)
298
+
299
+ Logs a WARNING for any file older than *max_age_days* days, otherwise
300
+ logs at DEBUG level so the daemon stays quiet on healthy systems.
301
+
302
+ Args:
303
+ home: Agent home directory.
304
+ max_age_days: Files older than this trigger a warning (default 7).
305
+ """
306
+
307
+ def _run() -> None:
308
+ now = datetime.now(timezone.utc)
309
+ warnings: list[str] = []
310
+
311
+ # Identity manifest
312
+ identity_file = home / "identity" / "identity.json"
313
+ if identity_file.exists():
314
+ mtime = datetime.fromtimestamp(identity_file.stat().st_mtime, tz=timezone.utc)
315
+ age_days = (now - mtime).days
316
+ if age_days > max_age_days:
317
+ warnings.append(
318
+ f"identity.json is {age_days}d old — consider re-running 'skcapstone init'"
319
+ )
320
+
321
+ # Model profile files
322
+ profiles_dir = home / "data" / "model_profiles"
323
+ if profiles_dir.exists():
324
+ for profile in sorted(profiles_dir.glob("*.json")):
325
+ mtime = datetime.fromtimestamp(profile.stat().st_mtime, tz=timezone.utc)
326
+ age_days = (now - mtime).days
327
+ if age_days > max_age_days:
328
+ warnings.append(
329
+ f"model profile '{profile.stem}' is {age_days}d old"
330
+ )
331
+
332
+ if warnings:
333
+ for msg in warnings:
334
+ logger.warning("Profile freshness: %s", msg)
335
+ else:
336
+ logger.debug("Profile freshness check passed — all profiles current")
337
+
338
+ return _run
339
+
340
+
341
+ # ---------------------------------------------------------------------------
342
+ # Convenience builder
343
+ # ---------------------------------------------------------------------------
344
+
345
+
346
+ def build_scheduler(
347
+ home: Path,
348
+ stop_event: threading.Event,
349
+ consciousness_loop: object = None,
350
+ beacon: object = None,
351
+ sync_watcher: object = None,
352
+ ) -> TaskScheduler:
353
+ """Build and register all standard scheduled tasks.
354
+
355
+ Tasks registered (in priority order — shortest interval first):
356
+
357
+ +--------------------------+------------+
358
+ | Task | Interval |
359
+ +==========================+============+
360
+ | heartbeat_pulse | 30 s |
361
+ +--------------------------+------------+
362
+ | sync_inbox_scan | 30 s |
363
+ +--------------------------+------------+
364
+ | backend_reprobe | 5 min |
365
+ +--------------------------+------------+
366
+ | service_health_check | 5 min |
367
+ +--------------------------+------------+
368
+ | memory_promotion_sweep | 1 hour |
369
+ +--------------------------+------------+
370
+ | profile_freshness_check | 24 hours |
371
+ +--------------------------+------------+
372
+
373
+ Args:
374
+ home: Agent home directory.
375
+ stop_event: Daemon stop event — scheduler thread exits when set.
376
+ consciousness_loop: Optional ConsciousnessLoop for backend re-probe.
377
+ beacon: Optional HeartbeatBeacon for heartbeat pulse.
378
+ sync_watcher: Optional SyncWatcher for inbox polling fallback.
379
+
380
+ Returns:
381
+ Configured TaskScheduler (call ``.start()`` to begin).
382
+ """
383
+ scheduler = TaskScheduler(home, stop_event)
384
+
385
+ def _consciousness_active() -> bool:
386
+ if consciousness_loop is None:
387
+ return False
388
+ cfg = getattr(consciousness_loop, "_config", None)
389
+ return bool(cfg and getattr(cfg, "enabled", False))
390
+
391
+ scheduler.register(
392
+ name="heartbeat_pulse",
393
+ interval_seconds=30,
394
+ callback=make_heartbeat_task(beacon, _consciousness_active),
395
+ )
396
+
397
+ # Sync inbox polling (fallback for when inotify misses events)
398
+ try:
399
+ from .sync_watcher import make_sync_inbox_scan_task
400
+
401
+ scheduler.register(
402
+ name="sync_inbox_scan",
403
+ interval_seconds=30,
404
+ callback=make_sync_inbox_scan_task(sync_watcher),
405
+ )
406
+ except ImportError:
407
+ logger.debug("sync_watcher not available — sync_inbox_scan task skipped")
408
+
409
+ scheduler.register(
410
+ name="backend_reprobe",
411
+ interval_seconds=300, # 5 minutes
412
+ callback=make_backend_reprobe_task(consciousness_loop),
413
+ )
414
+
415
+ scheduler.register(
416
+ name="memory_promotion_sweep",
417
+ interval_seconds=3600, # 1 hour
418
+ callback=make_memory_promotion_task(home),
419
+ )
420
+
421
+ scheduler.register(
422
+ name="profile_freshness_check",
423
+ interval_seconds=86400, # 24 hours
424
+ callback=make_profile_freshness_task(home),
425
+ )
426
+
427
+ # Service health check — pings Qdrant, FalkorDB, Syncthing, daemons
428
+ try:
429
+ from .service_health import make_service_health_task
430
+
431
+ scheduler.register(
432
+ name="service_health_check",
433
+ interval_seconds=300, # 5 minutes
434
+ callback=make_service_health_task(),
435
+ )
436
+ except ImportError:
437
+ logger.debug("service_health not available — service_health_check task skipped")
438
+
439
+ return scheduler