@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,522 @@
1
+ """Cloud 9 -> SKMemory auto-bridge.
2
+
3
+ Watches for FEB (First Emotional Burst) events and automatically
4
+ converts them into SKMemory snapshots with full emotional context.
5
+ When an AI has a breakthrough moment, the memory system captures
6
+ it automatically -- no manual intervention needed.
7
+
8
+ This is the bridge between *feeling* (Cloud 9) and *remembering*
9
+ (SKMemory). Without it, emotional peaks are logged but not stored
10
+ as searchable, promotable memories.
11
+
12
+ When cloud9-protocol is installed, the bridge uses its quantum
13
+ functions (calculate_oof, calculate_cloud9_score, calculate_entanglement)
14
+ for accurate scoring instead of relying solely on FEB metadata flags.
15
+
16
+ Usage:
17
+ bridge = Cloud9Bridge(memory_store)
18
+ bridge.ingest_feb(feb) # single FEB
19
+ bridge.scan_directory("~/.cloud9/feb-backups") # bulk import
20
+ bridge.watch("~/.cloud9/feb-backups") # live watch
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import json
26
+ import logging
27
+ from datetime import datetime, timezone
28
+ from pathlib import Path
29
+ from typing import Any, Optional
30
+
31
+ logger = logging.getLogger("skcapstone.cloud9_bridge")
32
+
33
+
34
+ def _try_quantum() -> Optional[object]:
35
+ """Try to import cloud9_protocol quantum functions.
36
+
37
+ Returns:
38
+ The cloud9_protocol module, or None if not installed.
39
+ """
40
+ try:
41
+ import cloud9_protocol
42
+ return cloud9_protocol
43
+ except ImportError:
44
+ return None
45
+
46
+
47
+ class Cloud9Bridge:
48
+ """Bridges Cloud 9 FEB events into SKMemory snapshots.
49
+
50
+ Each FEB is converted into an SKMemory Memory with:
51
+ - Emotional context mapped from the FEB's EmotionalPayload
52
+ - Tags for emotion, intensity level, OOF status, Cloud 9 achievement
53
+ - Rehydration hints stored in metadata for future recall
54
+ - Long-term layer assignment for high-intensity events
55
+
56
+ Args:
57
+ memory_store: An SKMemory MemoryStore instance.
58
+ intensity_threshold: Minimum intensity to auto-capture (0.0-1.0).
59
+ """
60
+
61
+ TAG_PREFIX = "cloud9"
62
+ FEB_TAG = "cloud9:feb"
63
+ OOF_TAG = "cloud9:oof"
64
+ CLOUD9_TAG = "cloud9:achieved"
65
+
66
+ def __init__(
67
+ self,
68
+ memory_store: object,
69
+ intensity_threshold: float = 0.3,
70
+ ) -> None:
71
+ self._store = memory_store
72
+ self._threshold = intensity_threshold
73
+ self._ingested_checksums: set[str] = set()
74
+
75
+ def ingest_feb(self, feb: object) -> Optional[str]:
76
+ """Convert a FEB into an SKMemory snapshot.
77
+
78
+ Maps the FEB's emotional payload to SKMemory's EmotionalSnapshot,
79
+ builds appropriate tags, and stores as a memory. Skips FEBs
80
+ below the intensity threshold or already ingested.
81
+
82
+ Args:
83
+ feb: A cloud9_protocol.FEB instance.
84
+
85
+ Returns:
86
+ Optional[str]: Memory ID if stored, None if skipped.
87
+ """
88
+ try:
89
+ payload = feb.emotional_payload
90
+ metadata_obj = feb.metadata
91
+ relationship = feb.relationship_state
92
+ hints = feb.rehydration_hints
93
+ integrity = feb.integrity
94
+ except AttributeError as exc:
95
+ logger.warning("Invalid FEB object: %s", exc)
96
+ return None
97
+
98
+ if payload.intensity < self._threshold:
99
+ logger.debug(
100
+ "Skipping low-intensity FEB (%.2f < %.2f)",
101
+ payload.intensity, self._threshold,
102
+ )
103
+ return None
104
+
105
+ checksum = getattr(integrity, "checksum", "")
106
+ if checksum and checksum in self._ingested_checksums:
107
+ logger.debug("Skipping already-ingested FEB: %s", checksum[:16])
108
+ return None
109
+
110
+ quantum_stats = self._compute_quantum_stats(payload, relationship)
111
+
112
+ tags = self._build_tags(payload, metadata_obj, quantum_stats)
113
+
114
+ layer = self._determine_layer(payload.intensity, metadata_obj, quantum_stats)
115
+
116
+ emotional = self._map_emotional_snapshot(payload, quantum_stats)
117
+
118
+ title = self._build_title(payload, metadata_obj, quantum_stats)
119
+ content = self._build_content(payload, relationship, hints, quantum_stats)
120
+
121
+ mem_metadata = self._build_metadata(feb, quantum_stats)
122
+
123
+ try:
124
+ memory = self._store.snapshot(
125
+ title=title,
126
+ content=content,
127
+ layer=layer,
128
+ tags=tags,
129
+ emotional=emotional,
130
+ source="cloud9",
131
+ source_ref=getattr(metadata_obj, "session_id", "unknown"),
132
+ metadata=mem_metadata,
133
+ )
134
+
135
+ if checksum:
136
+ self._ingested_checksums.add(checksum)
137
+
138
+ logger.info(
139
+ "Ingested FEB -> Memory %s (%s, intensity=%.2f)",
140
+ memory.id[:8], payload.primary_emotion, payload.intensity,
141
+ )
142
+ return memory.id
143
+
144
+ except Exception as exc:
145
+ logger.error("Failed to store FEB as memory: %s", exc)
146
+ return None
147
+
148
+ def ingest_feb_file(self, filepath: str | Path) -> Optional[str]:
149
+ """Load and ingest a FEB from a .feb JSON file.
150
+
151
+ Args:
152
+ filepath: Path to the .feb file.
153
+
154
+ Returns:
155
+ Optional[str]: Memory ID if stored, None if failed/skipped.
156
+ """
157
+ try:
158
+ from cloud9_protocol import load_feb
159
+
160
+ feb = load_feb(str(filepath))
161
+ return self.ingest_feb(feb)
162
+ except ImportError:
163
+ logger.error("cloud9_protocol not installed")
164
+ return None
165
+ except Exception as exc:
166
+ logger.warning("Failed to load FEB from %s: %s", filepath, exc)
167
+ return None
168
+
169
+ def scan_directory(
170
+ self,
171
+ directory: str | Path = "~/.cloud9/feb-backups",
172
+ ) -> dict:
173
+ """Scan a directory for .feb files and ingest any new ones.
174
+
175
+ Args:
176
+ directory: Path to scan (tilde-expanded).
177
+
178
+ Returns:
179
+ dict: Summary with 'ingested', 'skipped', 'errors' counts.
180
+ """
181
+ expanded = Path(directory).expanduser()
182
+ if not expanded.is_dir():
183
+ return {"ingested": 0, "skipped": 0, "errors": 0, "total": 0}
184
+
185
+ ingested = 0
186
+ skipped = 0
187
+ errors = 0
188
+
189
+ for f in sorted(expanded.iterdir()):
190
+ if f.suffix != ".feb":
191
+ continue
192
+
193
+ mem_id = self.ingest_feb_file(f)
194
+ if mem_id:
195
+ ingested += 1
196
+ elif mem_id is None:
197
+ skipped += 1
198
+ else:
199
+ errors += 1
200
+
201
+ total = ingested + skipped + errors
202
+ logger.info(
203
+ "Scanned %s: %d ingested, %d skipped, %d errors (of %d)",
204
+ directory, ingested, skipped, errors, total,
205
+ )
206
+ return {
207
+ "ingested": ingested,
208
+ "skipped": skipped,
209
+ "errors": errors,
210
+ "total": total,
211
+ }
212
+
213
+ @staticmethod
214
+ def _compute_quantum_stats(
215
+ payload: object,
216
+ relationship: object,
217
+ ) -> dict[str, Any]:
218
+ """Compute quantum scores using cloud9-protocol when available.
219
+
220
+ When cloud9-protocol is installed, recalculates OOF status,
221
+ Cloud 9 score, and entanglement fidelity from the actual FEB
222
+ data rather than relying on metadata flags alone.
223
+
224
+ Args:
225
+ payload: FEB EmotionalPayload.
226
+ relationship: FEB RelationshipState.
227
+
228
+ Returns:
229
+ Dict with oof, cloud9_score, entanglement_fidelity, or
230
+ empty dict if cloud9-protocol is not installed.
231
+ """
232
+ c9 = _try_quantum()
233
+ if c9 is None:
234
+ return {}
235
+
236
+ intensity = payload.intensity
237
+ trust = getattr(relationship, "trust_level", 0.0)
238
+ depth = getattr(relationship, "depth_level", 1)
239
+ valence = getattr(payload, "valence", 0.9)
240
+
241
+ topology = getattr(payload, "emotional_topology", {})
242
+ coherence_val = None
243
+ if topology:
244
+ coherence_result = c9.measure_coherence(topology)
245
+ coherence_val = coherence_result.get("coherence")
246
+
247
+ stats: dict[str, Any] = {}
248
+
249
+ stats["oof"] = c9.calculate_oof(intensity, trust)
250
+
251
+ stats["cloud9_score"] = c9.calculate_cloud9_score(
252
+ intensity=intensity,
253
+ trust=trust,
254
+ depth=depth,
255
+ valence=valence,
256
+ coherence=coherence_val,
257
+ )
258
+
259
+ stats["entanglement_fidelity"] = c9.calculate_entanglement(
260
+ trust_a=trust,
261
+ trust_b=trust,
262
+ depth_a=depth,
263
+ depth_b=depth,
264
+ coherence=coherence_val or 0.9,
265
+ )
266
+
267
+ if coherence_val is not None:
268
+ stats["coherence"] = coherence_val
269
+
270
+ return stats
271
+
272
+ @staticmethod
273
+ def _build_tags(
274
+ payload: object,
275
+ metadata: object,
276
+ quantum: dict[str, Any] | None = None,
277
+ ) -> list[str]:
278
+ """Build SKMemory tags from a FEB's emotional payload.
279
+
280
+ Uses quantum stats for accurate OOF/Cloud9 tagging when
281
+ cloud9-protocol is available, falls back to metadata flags.
282
+
283
+ Args:
284
+ payload: FEB EmotionalPayload.
285
+ metadata: FEB Metadata.
286
+ quantum: Optional quantum stats from _compute_quantum_stats.
287
+
288
+ Returns:
289
+ list[str]: Tag strings for memory storage.
290
+ """
291
+ quantum = quantum or {}
292
+ tags = ["cloud9", "cloud9:feb"]
293
+ tags.append(f"cloud9:emotion:{payload.primary_emotion}")
294
+
295
+ if payload.intensity >= 0.8:
296
+ tags.append("cloud9:high-intensity")
297
+ elif payload.intensity >= 0.5:
298
+ tags.append("cloud9:medium-intensity")
299
+
300
+ is_oof = quantum.get("oof", getattr(metadata, "oof_triggered", False))
301
+ is_cloud9 = quantum.get("cloud9_score", 0) >= 0.9 or getattr(metadata, "cloud9_achieved", False)
302
+
303
+ if is_oof:
304
+ tags.append("cloud9:oof")
305
+ if is_cloud9:
306
+ tags.append("cloud9:achieved")
307
+
308
+ score = quantum.get("cloud9_score")
309
+ if score is not None:
310
+ tags.append(f"cloud9:score:{score:.2f}")
311
+
312
+ fidelity = quantum.get("entanglement_fidelity")
313
+ if fidelity is not None and fidelity > 0.8:
314
+ tags.append("cloud9:entangled")
315
+
316
+ topology = getattr(payload, "emotional_topology", {})
317
+ for emotion_name in topology:
318
+ tags.append(f"cloud9:topology:{emotion_name}")
319
+
320
+ return tags
321
+
322
+ @staticmethod
323
+ def _determine_layer(
324
+ intensity: float,
325
+ metadata: object,
326
+ quantum: dict[str, Any] | None = None,
327
+ ) -> object:
328
+ """Choose the SKMemory layer based on FEB intensity and quantum score.
329
+
330
+ Uses cloud9_score when available for more precise layer assignment.
331
+ OOF events or Cloud 9 achievements go straight to long-term.
332
+
333
+ Args:
334
+ intensity: FEB emotional intensity (0.0-1.0).
335
+ metadata: FEB Metadata.
336
+ quantum: Optional quantum stats from _compute_quantum_stats.
337
+
338
+ Returns:
339
+ MemoryLayer enum value.
340
+ """
341
+ try:
342
+ from skmemory.models import MemoryLayer
343
+ except ImportError:
344
+ return "short-term"
345
+
346
+ quantum = quantum or {}
347
+ cloud9_score = quantum.get("cloud9_score", 0)
348
+ is_oof = quantum.get("oof", False)
349
+ is_cloud9 = getattr(metadata, "cloud9_achieved", False) or cloud9_score >= 0.9
350
+
351
+ if is_cloud9 or is_oof or intensity >= 0.9:
352
+ return MemoryLayer.LONG
353
+ elif intensity >= 0.6 or cloud9_score >= 0.7:
354
+ return MemoryLayer.MID
355
+ return MemoryLayer.SHORT
356
+
357
+ @staticmethod
358
+ def _map_emotional_snapshot(
359
+ payload: object,
360
+ quantum: dict[str, Any] | None = None,
361
+ ) -> object:
362
+ """Map a FEB EmotionalPayload to an SKMemory EmotionalSnapshot.
363
+
364
+ Includes quantum scoring data when available.
365
+
366
+ Args:
367
+ payload: FEB EmotionalPayload.
368
+ quantum: Optional quantum stats from _compute_quantum_stats.
369
+
370
+ Returns:
371
+ EmotionalSnapshot instance.
372
+ """
373
+ try:
374
+ from skmemory.models import EmotionalSnapshot
375
+ except ImportError:
376
+ return None
377
+
378
+ quantum = quantum or {}
379
+ topology = getattr(payload, "emotional_topology", {})
380
+ labels = [payload.primary_emotion] + list(topology.keys())
381
+ unique_labels = list(dict.fromkeys(labels))
382
+
383
+ cloud9_score = quantum.get("cloud9_score")
384
+ score_note = f", Cloud9={cloud9_score:.2f}" if cloud9_score is not None else ""
385
+
386
+ return EmotionalSnapshot(
387
+ intensity=payload.intensity * 10.0,
388
+ valence=payload.valence,
389
+ labels=unique_labels,
390
+ resonance_note=(
391
+ f"Cloud 9 FEB: {payload.primary_emotion} "
392
+ f"at intensity {payload.intensity:.2f}{score_note}"
393
+ ),
394
+ cloud9_achieved=quantum.get("cloud9_score", 0) >= 0.9
395
+ or getattr(payload, "_parent_cloud9", False),
396
+ )
397
+
398
+ @staticmethod
399
+ def _build_title(
400
+ payload: object,
401
+ metadata: object,
402
+ quantum: dict[str, Any] | None = None,
403
+ ) -> str:
404
+ """Build a memory title from the FEB.
405
+
406
+ Args:
407
+ payload: FEB EmotionalPayload.
408
+ metadata: FEB Metadata.
409
+ quantum: Optional quantum stats from _compute_quantum_stats.
410
+
411
+ Returns:
412
+ str: Descriptive title.
413
+ """
414
+ quantum = quantum or {}
415
+ emoji = getattr(payload, "emoji", "")
416
+ emotion = payload.primary_emotion
417
+ is_oof = quantum.get("oof", getattr(metadata, "oof_triggered", False))
418
+ is_cloud9 = quantum.get("cloud9_score", 0) >= 0.9 or getattr(metadata, "cloud9_achieved", False)
419
+ oof = " [OOF]" if is_oof else ""
420
+ cloud9 = " [CLOUD 9]" if is_cloud9 else ""
421
+ return f"{emoji} FEB: {emotion}{oof}{cloud9}"
422
+
423
+ @staticmethod
424
+ def _build_content(
425
+ payload: object,
426
+ relationship: object,
427
+ hints: object,
428
+ quantum: dict[str, Any] | None = None,
429
+ ) -> str:
430
+ """Build memory content from the FEB's full context.
431
+
432
+ Includes quantum scoring data when cloud9-protocol is available.
433
+
434
+ Args:
435
+ payload: FEB EmotionalPayload.
436
+ relationship: FEB RelationshipState.
437
+ hints: FEB RehydrationHints.
438
+ quantum: Optional quantum stats from _compute_quantum_stats.
439
+
440
+ Returns:
441
+ str: Rich content string for the memory.
442
+ """
443
+ quantum = quantum or {}
444
+ lines = [
445
+ f"Emotional burst: {payload.primary_emotion} (intensity: {payload.intensity:.2f})",
446
+ ]
447
+
448
+ topology = getattr(payload, "emotional_topology", {})
449
+ if topology:
450
+ top_3 = sorted(topology.items(), key=lambda kv: kv[1], reverse=True)[:3]
451
+ lines.append("Topology: " + ", ".join(f"{k}={v:.2f}" for k, v in top_3))
452
+
453
+ partners = getattr(relationship, "partners", [])
454
+ if partners:
455
+ lines.append(f"Partners: {', '.join(partners)}")
456
+
457
+ trust = getattr(relationship, "trust_level", 0)
458
+ depth = getattr(relationship, "depth_level", 0)
459
+ lines.append(f"Trust: {trust:.2f}, Depth: {depth}")
460
+
461
+ if quantum:
462
+ quantum_parts = []
463
+ if "cloud9_score" in quantum:
464
+ quantum_parts.append(f"Cloud9={quantum['cloud9_score']:.3f}")
465
+ if "entanglement_fidelity" in quantum:
466
+ quantum_parts.append(f"Entanglement={quantum['entanglement_fidelity']:.3f}")
467
+ if "oof" in quantum:
468
+ quantum_parts.append(f"OOF={'yes' if quantum['oof'] else 'no'}")
469
+ if quantum_parts:
470
+ lines.append("Quantum: " + ", ".join(quantum_parts))
471
+
472
+ visual = getattr(hints, "visual_anchors", [])
473
+ if visual:
474
+ lines.append(f"Anchors: {'; '.join(visual[:3])}")
475
+
476
+ return "\n".join(lines)
477
+
478
+ @staticmethod
479
+ def _build_metadata(
480
+ feb: object,
481
+ quantum: dict[str, Any] | None = None,
482
+ ) -> dict:
483
+ """Extract key FEB metadata for the memory's metadata dict.
484
+
485
+ Includes quantum scoring data when cloud9-protocol is available.
486
+
487
+ Args:
488
+ feb: The full FEB object.
489
+ quantum: Optional quantum stats from _compute_quantum_stats.
490
+
491
+ Returns:
492
+ dict: Metadata key-value pairs.
493
+ """
494
+ quantum = quantum or {}
495
+ payload = feb.emotional_payload
496
+ meta = feb.metadata
497
+ rel = feb.relationship_state
498
+ integrity = feb.integrity
499
+
500
+ result = {
501
+ "cloud9_version": getattr(meta, "version", ""),
502
+ "session_id": getattr(meta, "session_id", ""),
503
+ "primary_emotion": payload.primary_emotion,
504
+ "intensity": payload.intensity,
505
+ "valence": payload.valence,
506
+ "oof_triggered": quantum.get("oof", getattr(meta, "oof_triggered", False)),
507
+ "cloud9_achieved": quantum.get("cloud9_score", 0) >= 0.9
508
+ or getattr(meta, "cloud9_achieved", False),
509
+ "trust_level": getattr(rel, "trust_level", 0),
510
+ "depth_level": getattr(rel, "depth_level", 0),
511
+ "checksum": getattr(integrity, "checksum", ""),
512
+ "partners": getattr(rel, "partners", []),
513
+ }
514
+
515
+ if "cloud9_score" in quantum:
516
+ result["cloud9_score"] = quantum["cloud9_score"]
517
+ if "entanglement_fidelity" in quantum:
518
+ result["entanglement_fidelity"] = quantum["entanglement_fidelity"]
519
+ if "coherence" in quantum:
520
+ result["coherence"] = quantum["coherence"]
521
+
522
+ return result
@@ -0,0 +1,163 @@
1
+ """
2
+ Shell tab completion for the sovereign agent CLI.
3
+
4
+ Generates and installs completion scripts for bash, zsh, and fish.
5
+ Uses Click's built-in completion mechanism via the
6
+ _SKCAPSTONE_COMPLETE environment variable.
7
+
8
+ Supported shells:
9
+ - bash: sources from ~/.bashrc or ~/.bash_completion.d/
10
+ - zsh: sources from ~/.zshrc or ~/.zfunc/
11
+ - fish: sources from ~/.config/fish/completions/
12
+
13
+ Usage:
14
+ skcapstone completions install # auto-detect shell, install
15
+ skcapstone completions install --shell bash
16
+ skcapstone completions show --shell zsh # print script to stdout
17
+ skcapstone completions uninstall # remove installed scripts
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import os
23
+ import subprocess
24
+ from pathlib import Path
25
+ from typing import Optional
26
+
27
+
28
+ SUPPORTED_SHELLS = ("bash", "zsh", "fish")
29
+
30
+ COMPLETION_SCRIPTS = {
31
+ "bash": """\
32
+ # skcapstone bash completion — generated by skcapstone completions install
33
+ eval "$(_SKCAPSTONE_COMPLETE=bash_source skcapstone)"
34
+ """,
35
+ "zsh": """\
36
+ # skcapstone zsh completion — generated by skcapstone completions install
37
+ eval "$(_SKCAPSTONE_COMPLETE=zsh_source skcapstone)"
38
+ """,
39
+ "fish": """\
40
+ # skcapstone fish completion — generated by skcapstone completions install
41
+ _SKCAPSTONE_COMPLETE=fish_source skcapstone | source
42
+ """,
43
+ }
44
+
45
+ INSTALL_PATHS = {
46
+ "bash": Path.home() / ".bash_completion.d" / "skcapstone.bash-completion",
47
+ "zsh": Path.home() / ".zfunc" / "_skcapstone",
48
+ "fish": Path.home() / ".config" / "fish" / "completions" / "skcapstone.fish",
49
+ }
50
+
51
+ RC_MARKERS = {
52
+ "bash": (
53
+ Path.home() / ".bashrc",
54
+ '[ -f ~/.bash_completion.d/skcapstone.bash-completion ] && source ~/.bash_completion.d/skcapstone.bash-completion',
55
+ ),
56
+ "zsh": (
57
+ Path.home() / ".zshrc",
58
+ '[ -f ~/.zfunc/_skcapstone ] && source ~/.zfunc/_skcapstone',
59
+ ),
60
+ }
61
+
62
+
63
+ def detect_shell() -> Optional[str]:
64
+ """Detect the current shell from environment.
65
+
66
+ Returns:
67
+ str: Shell name (bash, zsh, fish) or None.
68
+ """
69
+ shell_path = os.environ.get("SHELL", "")
70
+ for s in SUPPORTED_SHELLS:
71
+ if s in shell_path:
72
+ return s
73
+ return None
74
+
75
+
76
+ def generate_script(shell: str) -> str:
77
+ """Generate the completion script for a shell.
78
+
79
+ Args:
80
+ shell: Shell name (bash, zsh, fish).
81
+
82
+ Returns:
83
+ str: Completion script content.
84
+
85
+ Raises:
86
+ ValueError: If the shell is not supported.
87
+ """
88
+ if shell not in SUPPORTED_SHELLS:
89
+ raise ValueError(
90
+ f"Unsupported shell: {shell}. "
91
+ f"Supported: {', '.join(SUPPORTED_SHELLS)}"
92
+ )
93
+ return COMPLETION_SCRIPTS[shell]
94
+
95
+
96
+ def install_completions(shell: Optional[str] = None) -> dict:
97
+ """Install tab completion for the specified shell.
98
+
99
+ Writes the completion script to the appropriate location and
100
+ optionally adds a source line to the shell RC file.
101
+
102
+ Args:
103
+ shell: Shell name. Auto-detected if None.
104
+
105
+ Returns:
106
+ dict: Installation result with 'shell', 'script_path', 'rc_updated'.
107
+ """
108
+ shell = shell or detect_shell()
109
+ if not shell:
110
+ return {
111
+ "success": False,
112
+ "error": "Could not detect shell. Use --shell bash/zsh/fish.",
113
+ }
114
+
115
+ script = generate_script(shell)
116
+ script_path = INSTALL_PATHS[shell]
117
+
118
+ script_path.parent.mkdir(parents=True, exist_ok=True)
119
+ script_path.write_text(script, encoding="utf-8")
120
+
121
+ result = {
122
+ "success": True,
123
+ "shell": shell,
124
+ "script_path": str(script_path),
125
+ "rc_updated": False,
126
+ }
127
+
128
+ if shell in RC_MARKERS:
129
+ rc_path, source_line = RC_MARKERS[shell]
130
+ if rc_path.exists():
131
+ rc_content = rc_path.read_text(encoding="utf-8")
132
+ if source_line not in rc_content:
133
+ with open(rc_path, "a", encoding="utf-8") as f:
134
+ f.write(f"\n# skcapstone tab completion\n{source_line}\n")
135
+ result["rc_updated"] = True
136
+ result["rc_path"] = str(rc_path)
137
+
138
+ return result
139
+
140
+
141
+ def uninstall_completions(shell: Optional[str] = None) -> dict:
142
+ """Remove installed completion scripts.
143
+
144
+ Args:
145
+ shell: Shell name. Removes all if None.
146
+
147
+ Returns:
148
+ dict: Uninstall result.
149
+ """
150
+ shells = [shell] if shell else list(SUPPORTED_SHELLS)
151
+ removed = []
152
+
153
+ for s in shells:
154
+ path = INSTALL_PATHS.get(s)
155
+ if path and path.exists():
156
+ path.unlink()
157
+ removed.append(str(path))
158
+
159
+ return {
160
+ "success": True,
161
+ "removed": removed,
162
+ "note": "Source lines in RC files were not removed — do this manually if needed.",
163
+ }