@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,199 @@
1
+ """Tests for skcapstone.log_config — structured JSON logging."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import logging
7
+ import logging.handlers
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ import pytest
12
+
13
+ import skcapstone.log_config as log_config_module
14
+ from skcapstone.log_config import JsonFormatter, configure_logging
15
+
16
+
17
+ # ---------------------------------------------------------------------------
18
+ # Fixtures
19
+ # ---------------------------------------------------------------------------
20
+
21
+
22
+ @pytest.fixture(autouse=True)
23
+ def _reset_log_config(monkeypatch):
24
+ """Reset the _CONFIGURED flag and remove rotating file handlers before/after each test."""
25
+ monkeypatch.setattr(log_config_module, "_CONFIGURED", False)
26
+ root = logging.getLogger()
27
+ # Remove any RotatingFileHandlers left by previous tests before this test runs.
28
+ for h in list(root.handlers):
29
+ if isinstance(h, logging.handlers.RotatingFileHandler):
30
+ root.removeHandler(h)
31
+ try:
32
+ h.close()
33
+ except Exception:
34
+ pass
35
+ handlers_before = list(root.handlers)
36
+ yield
37
+ # Tear down any handlers added during the test.
38
+ for h in list(root.handlers):
39
+ if h not in handlers_before:
40
+ root.removeHandler(h)
41
+ try:
42
+ h.close()
43
+ except Exception:
44
+ pass
45
+ monkeypatch.setattr(log_config_module, "_CONFIGURED", False)
46
+
47
+
48
+ # ---------------------------------------------------------------------------
49
+ # JsonFormatter tests
50
+ # ---------------------------------------------------------------------------
51
+
52
+
53
+ class TestJsonFormatter:
54
+ def test_outputs_valid_json(self):
55
+ formatter = JsonFormatter()
56
+ record = logging.LogRecord(
57
+ name="test.logger",
58
+ level=logging.INFO,
59
+ pathname="",
60
+ lineno=0,
61
+ msg="hello world",
62
+ args=(),
63
+ exc_info=None,
64
+ )
65
+ output = formatter.format(record)
66
+ data = json.loads(output) # must not raise
67
+ assert isinstance(data, dict)
68
+
69
+ def test_required_fields_present(self):
70
+ formatter = JsonFormatter()
71
+ record = logging.LogRecord(
72
+ name="skcapstone.daemon",
73
+ level=logging.WARNING,
74
+ pathname="",
75
+ lineno=0,
76
+ msg="something %s",
77
+ args=("bad",),
78
+ exc_info=None,
79
+ )
80
+ data = json.loads(formatter.format(record))
81
+ assert data["level"] == "WARNING"
82
+ assert data["logger"] == "skcapstone.daemon"
83
+ assert data["msg"] == "something bad"
84
+ assert "ts" in data
85
+ # ts should be a parseable ISO-8601 string
86
+ from datetime import datetime
87
+ datetime.fromisoformat(data["ts"]) # raises if malformed
88
+
89
+ def test_exception_info_included(self):
90
+ formatter = JsonFormatter()
91
+ try:
92
+ raise RuntimeError("boom")
93
+ except RuntimeError:
94
+ exc_info = sys.exc_info()
95
+
96
+ record = logging.LogRecord(
97
+ name="test",
98
+ level=logging.ERROR,
99
+ pathname="",
100
+ lineno=0,
101
+ msg="an error",
102
+ args=(),
103
+ exc_info=exc_info,
104
+ )
105
+ data = json.loads(formatter.format(record))
106
+ assert "exc" in data
107
+ assert "RuntimeError" in data["exc"]
108
+ assert "boom" in data["exc"]
109
+
110
+ def test_extra_fields_forwarded(self):
111
+ formatter = JsonFormatter()
112
+ record = logging.LogRecord(
113
+ name="test",
114
+ level=logging.DEBUG,
115
+ pathname="",
116
+ lineno=0,
117
+ msg="extra test",
118
+ args=(),
119
+ exc_info=None,
120
+ )
121
+ record.request_id = "abc-123"
122
+ data = json.loads(formatter.format(record))
123
+ assert data.get("request_id") == "abc-123"
124
+
125
+
126
+ # ---------------------------------------------------------------------------
127
+ # configure_logging tests
128
+ # ---------------------------------------------------------------------------
129
+
130
+
131
+ class TestConfigureLogging:
132
+ def test_creates_rotating_file_handler(self, tmp_path):
133
+ log_file = tmp_path / "logs" / "daemon.log"
134
+ configure_logging(log_file)
135
+ root = logging.getLogger()
136
+ rotating = [
137
+ h for h in root.handlers if isinstance(h, logging.handlers.RotatingFileHandler)
138
+ ]
139
+ assert len(rotating) == 1
140
+ h = rotating[0]
141
+ assert h.maxBytes == 10 * 1024 * 1024
142
+ assert h.backupCount == 5
143
+
144
+ def test_file_handler_uses_json_formatter(self, tmp_path):
145
+ log_file = tmp_path / "daemon.log"
146
+ configure_logging(log_file)
147
+ root = logging.getLogger()
148
+ rotating = [
149
+ h for h in root.handlers if isinstance(h, logging.handlers.RotatingFileHandler)
150
+ ]
151
+ assert len(rotating) == 1
152
+ assert isinstance(rotating[0].formatter, JsonFormatter)
153
+
154
+ def test_creates_console_handler_at_info(self, tmp_path):
155
+ log_file = tmp_path / "daemon.log"
156
+ configure_logging(log_file)
157
+ root = logging.getLogger()
158
+ stream_handlers = [
159
+ h
160
+ for h in root.handlers
161
+ if isinstance(h, logging.StreamHandler)
162
+ and not isinstance(h, logging.handlers.RotatingFileHandler)
163
+ ]
164
+ assert len(stream_handlers) >= 1
165
+ assert any(h.level == logging.INFO for h in stream_handlers)
166
+
167
+ def test_creates_log_parent_directory(self, tmp_path):
168
+ log_file = tmp_path / "nested" / "deep" / "daemon.log"
169
+ assert not log_file.parent.exists()
170
+ configure_logging(log_file)
171
+ assert log_file.parent.exists()
172
+
173
+ def test_idempotent_no_duplicate_handlers(self, tmp_path):
174
+ log_file = tmp_path / "daemon.log"
175
+ configure_logging(log_file)
176
+ root = logging.getLogger()
177
+ count_after_first = len(root.handlers)
178
+ # Second call must be a no-op (_CONFIGURED is now True).
179
+ configure_logging(log_file)
180
+ assert len(root.handlers) == count_after_first
181
+
182
+ def test_file_handler_log_level_is_debug_by_default(self, tmp_path):
183
+ log_file = tmp_path / "daemon.log"
184
+ configure_logging(log_file)
185
+ root = logging.getLogger()
186
+ rotating = [
187
+ h for h in root.handlers if isinstance(h, logging.handlers.RotatingFileHandler)
188
+ ]
189
+ assert rotating[0].level == logging.DEBUG
190
+
191
+ def test_custom_max_bytes_and_backup_count(self, tmp_path):
192
+ log_file = tmp_path / "daemon.log"
193
+ configure_logging(log_file, max_bytes=5 * 1024 * 1024, backup_count=3)
194
+ root = logging.getLogger()
195
+ rotating = [
196
+ h for h in root.handlers if isinstance(h, logging.handlers.RotatingFileHandler)
197
+ ]
198
+ assert rotating[0].maxBytes == 5 * 1024 * 1024
199
+ assert rotating[0].backupCount == 3
@@ -0,0 +1,287 @@
1
+ """Tests for ``skcapstone logs`` command.
2
+
3
+ Covers:
4
+ - help text exposes all options
5
+ - graceful handling of missing log file
6
+ - --lines N limits output to N recent lines
7
+ - --level filters by minimum log level
8
+ - --peer filters lines containing a peer name substring
9
+ - --follow outputs existing lines before entering the tail loop
10
+ - --follow combined with --level filter
11
+ - helper: _parse_level
12
+ - helper: _matches_filters
13
+ - helper: _tail
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from pathlib import Path
19
+ from unittest.mock import patch
20
+
21
+ import pytest
22
+ from click.testing import CliRunner
23
+
24
+ from skcapstone.cli import main
25
+ from skcapstone.cli.logs_cmd import _matches_filters, _parse_level, _tail
26
+
27
+ runner = CliRunner()
28
+
29
+ # ---------------------------------------------------------------------------
30
+ # Shared fixture
31
+ # ---------------------------------------------------------------------------
32
+
33
+ SAMPLE_LOG = (
34
+ "2026-01-01 00:00:01,000 [skcapstone.daemon] DEBUG: debug message\n"
35
+ "2026-01-01 00:00:02,000 [skcapstone.daemon] INFO: started up\n"
36
+ "2026-01-01 00:00:03,000 [skcapstone.sync] WARNING: peer opus slow\n"
37
+ "2026-01-01 00:00:04,000 [skcapstone.daemon] ERROR: transport failed\n"
38
+ "2026-01-01 00:00:05,000 [skcapstone.daemon] INFO: heartbeat ok\n"
39
+ )
40
+
41
+
42
+ @pytest.fixture
43
+ def log_home(tmp_path: Path) -> Path:
44
+ """Agent home with a pre-populated daemon.log."""
45
+ log_dir = tmp_path / "logs"
46
+ log_dir.mkdir(parents=True)
47
+ (log_dir / "daemon.log").write_text(SAMPLE_LOG)
48
+ return tmp_path
49
+
50
+
51
+ # ---------------------------------------------------------------------------
52
+ # Unit tests — _parse_level
53
+ # ---------------------------------------------------------------------------
54
+
55
+ class TestParseLevel:
56
+ def test_info(self):
57
+ assert _parse_level("2026-01-01 [skcapstone.daemon] INFO: hello") == "INFO"
58
+
59
+ def test_error(self):
60
+ assert _parse_level("2026-01-01 [transport] ERROR: connection refused") == "ERROR"
61
+
62
+ def test_warning(self):
63
+ assert _parse_level("... [x] WARNING: slow") == "WARNING"
64
+
65
+ def test_debug(self):
66
+ assert _parse_level("2026-01-01 [y] DEBUG: verbose") == "DEBUG"
67
+
68
+ def test_critical(self):
69
+ assert _parse_level("2026-01-01 [z] CRITICAL: crash") == "CRITICAL"
70
+
71
+ def test_unparseable_returns_none(self):
72
+ assert _parse_level("not a structured log line") is None
73
+
74
+ def test_empty_string(self):
75
+ assert _parse_level("") is None
76
+
77
+
78
+ # ---------------------------------------------------------------------------
79
+ # Unit tests — _matches_filters
80
+ # ---------------------------------------------------------------------------
81
+
82
+ class TestMatchesFilters:
83
+ def test_no_filters_accepts_all(self):
84
+ assert _matches_filters("any line whatsoever", None, None) is True
85
+
86
+ def test_level_min_warning_accepts_error(self):
87
+ line = "2026-01-01 [x] ERROR: something bad"
88
+ assert _matches_filters(line, "WARNING", None) is True
89
+
90
+ def test_level_min_error_rejects_warning(self):
91
+ line = "2026-01-01 [x] WARNING: minor issue"
92
+ assert _matches_filters(line, "ERROR", None) is False
93
+
94
+ def test_level_min_error_rejects_info(self):
95
+ line = "2026-01-01 [x] INFO: routine"
96
+ assert _matches_filters(line, "ERROR", None) is False
97
+
98
+ def test_level_exact_match(self):
99
+ line = "2026-01-01 [x] INFO: hello"
100
+ assert _matches_filters(line, "INFO", None) is True
101
+
102
+ def test_level_unparseable_excluded(self):
103
+ assert _matches_filters("plain text", "INFO", None) is False
104
+
105
+ def test_peer_match(self):
106
+ line = "2026-01-01 [x] INFO: message from opus"
107
+ assert _matches_filters(line, None, "opus") is True
108
+
109
+ def test_peer_case_insensitive(self):
110
+ line = "2026-01-01 [x] INFO: message from OPUS"
111
+ assert _matches_filters(line, None, "opus") is True
112
+
113
+ def test_peer_no_match(self):
114
+ line = "2026-01-01 [x] INFO: message from jarvis"
115
+ assert _matches_filters(line, None, "opus") is False
116
+
117
+ def test_combined_both_pass(self):
118
+ line = "2026-01-01 [x] ERROR: opus transport failed"
119
+ assert _matches_filters(line, "WARNING", "opus") is True
120
+
121
+ def test_combined_level_fails(self):
122
+ line = "2026-01-01 [x] DEBUG: opus verbose"
123
+ assert _matches_filters(line, "WARNING", "opus") is False
124
+
125
+ def test_combined_peer_fails(self):
126
+ line = "2026-01-01 [x] ERROR: jarvis transport failed"
127
+ assert _matches_filters(line, "WARNING", "opus") is False
128
+
129
+
130
+ # ---------------------------------------------------------------------------
131
+ # Unit tests — _tail
132
+ # ---------------------------------------------------------------------------
133
+
134
+ class TestTail:
135
+ def test_returns_last_n_lines(self, tmp_path):
136
+ f = tmp_path / "test.log"
137
+ f.write_text("\n".join(f"line{i}" for i in range(20)) + "\n")
138
+ lines = _tail(f, 5)
139
+ assert len(lines) == 5
140
+ assert "line19" in lines[-1]
141
+
142
+ def test_fewer_lines_than_n(self, tmp_path):
143
+ f = tmp_path / "test.log"
144
+ f.write_text("a\nb\nc\n")
145
+ lines = _tail(f, 100)
146
+ assert len(lines) == 3
147
+
148
+ def test_single_line(self, tmp_path):
149
+ f = tmp_path / "test.log"
150
+ f.write_text("only one line\n")
151
+ lines = _tail(f, 10)
152
+ assert len(lines) == 1
153
+ assert "only one line" in lines[0]
154
+
155
+
156
+ # ---------------------------------------------------------------------------
157
+ # CLI integration tests
158
+ # ---------------------------------------------------------------------------
159
+
160
+ class TestLogsCLI:
161
+ def test_help_shows_all_options(self):
162
+ """``logs --help`` exposes every documented option."""
163
+ result = runner.invoke(main, ["logs", "--help"])
164
+ assert result.exit_code == 0
165
+ assert "--follow" in result.output
166
+ assert "--lines" in result.output
167
+ assert "--level" in result.output
168
+ assert "--peer" in result.output
169
+
170
+ def test_missing_log_file_friendly_message(self, tmp_path):
171
+ """Missing daemon.log prints a helpful message and exits 0."""
172
+ result = runner.invoke(main, ["logs", "--home", str(tmp_path)])
173
+ assert result.exit_code == 0
174
+ assert "not found" in result.output.lower() or "log file" in result.output.lower()
175
+
176
+ def test_lines_limits_output(self, log_home):
177
+ """``-n 2`` returns only the 2 most recent lines."""
178
+ result = runner.invoke(main, ["logs", "--home", str(log_home), "-n", "2"])
179
+ assert result.exit_code == 0
180
+ # Last 2 lines of fixture
181
+ assert "heartbeat ok" in result.output
182
+ assert "transport failed" in result.output
183
+ # 3rd-to-last must not appear
184
+ assert "peer opus slow" not in result.output
185
+
186
+ def test_level_filter_hides_lower_levels(self, log_home):
187
+ """``--level WARNING`` hides DEBUG and INFO lines."""
188
+ result = runner.invoke(
189
+ main, ["logs", "--home", str(log_home), "--level", "WARNING"]
190
+ )
191
+ assert result.exit_code == 0
192
+ assert "debug message" not in result.output
193
+ assert "started up" not in result.output
194
+ assert "heartbeat ok" not in result.output
195
+ assert "peer opus slow" in result.output # WARNING
196
+ assert "transport failed" in result.output # ERROR
197
+
198
+ def test_level_filter_case_insensitive(self, log_home):
199
+ """``--level warning`` (lowercase) works identically."""
200
+ result = runner.invoke(
201
+ main, ["logs", "--home", str(log_home), "--level", "warning"]
202
+ )
203
+ assert result.exit_code == 0
204
+ assert "peer opus slow" in result.output
205
+ assert "debug message" not in result.output
206
+
207
+ def test_peer_filter_only_matching_lines(self, log_home):
208
+ """``--peer opus`` shows only lines containing 'opus'."""
209
+ result = runner.invoke(
210
+ main, ["logs", "--home", str(log_home), "--peer", "opus"]
211
+ )
212
+ assert result.exit_code == 0
213
+ assert "peer opus slow" in result.output
214
+ # Lines without 'opus' must be absent
215
+ assert "heartbeat ok" not in result.output
216
+ assert "transport failed" not in result.output
217
+ assert "debug message" not in result.output
218
+
219
+ def test_no_matching_lines_message(self, log_home):
220
+ """Filtering that matches nothing prints a 'no matching' notice."""
221
+ result = runner.invoke(
222
+ main, ["logs", "--home", str(log_home), "--peer", "zz_no_such_peer_zz"]
223
+ )
224
+ assert result.exit_code == 0
225
+ assert "no matching" in result.output.lower()
226
+
227
+ def test_follow_shows_initial_lines(self, log_home):
228
+ """``--follow`` outputs the last N historical lines before entering the loop."""
229
+
230
+ def fake_sleep(_n: float) -> None:
231
+ raise KeyboardInterrupt()
232
+
233
+ with patch("skcapstone.cli.logs_cmd.time.sleep", fake_sleep):
234
+ result = runner.invoke(
235
+ main, ["logs", "--home", str(log_home), "--follow", "-n", "3"]
236
+ )
237
+
238
+ assert result.exit_code == 0
239
+ # Last 3 lines of fixture
240
+ assert "heartbeat ok" in result.output
241
+ assert "transport failed" in result.output
242
+ assert "peer opus slow" in result.output
243
+ # First 2 lines must NOT appear (only last 3 requested)
244
+ assert "debug message" not in result.output
245
+ assert "started up" not in result.output
246
+
247
+ def test_follow_with_level_filter(self, log_home):
248
+ """``--follow --level ERROR`` only streams lines at ERROR or above."""
249
+
250
+ def fake_sleep(_n: float) -> None:
251
+ raise KeyboardInterrupt()
252
+
253
+ with patch("skcapstone.cli.logs_cmd.time.sleep", fake_sleep):
254
+ result = runner.invoke(
255
+ main,
256
+ ["logs", "--home", str(log_home), "--follow", "--level", "ERROR"],
257
+ )
258
+
259
+ assert result.exit_code == 0
260
+ assert "transport failed" in result.output
261
+ assert "debug message" not in result.output
262
+ assert "started up" not in result.output
263
+ assert "peer opus slow" not in result.output # WARNING < ERROR
264
+
265
+ def test_follow_streams_new_content(self, log_home):
266
+ """``--follow`` reads content appended after the initial seek."""
267
+ log_file = log_home / "logs" / "daemon.log"
268
+
269
+ call_count = 0
270
+
271
+ def fake_sleep(_n: float) -> None:
272
+ nonlocal call_count
273
+ call_count += 1
274
+ if call_count == 1:
275
+ # Append a new line on first poll
276
+ with open(log_file, "a") as fh:
277
+ fh.write("2026-01-01 00:01:00,000 [skcapstone.daemon] INFO: new entry\n")
278
+ else:
279
+ raise KeyboardInterrupt()
280
+
281
+ with patch("skcapstone.cli.logs_cmd.time.sleep", fake_sleep):
282
+ result = runner.invoke(
283
+ main, ["logs", "--home", str(log_home), "--follow"]
284
+ )
285
+
286
+ assert result.exit_code == 0
287
+ assert "new entry" in result.output