@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,186 @@
1
+ """CapAuth identity verification and status tools.
2
+
3
+ Exposes two tools:
4
+ capauth_status — Show CapAuth profile and key status
5
+ capauth_verify — Verify a CapAuth identity or capability token
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json as _json
11
+
12
+ from mcp.types import TextContent, Tool
13
+
14
+ from ._helpers import _error_response, _home, _json_response
15
+
16
+ TOOLS: list[Tool] = [
17
+ Tool(
18
+ name="capauth_status",
19
+ description=(
20
+ "Show CapAuth profile status: whether capauth is installed, "
21
+ "profile loaded, PGP key fingerprint, DID key, and "
22
+ "capability token summary."
23
+ ),
24
+ inputSchema={"type": "object", "properties": {}, "required": []},
25
+ ),
26
+ Tool(
27
+ name="capauth_verify",
28
+ description=(
29
+ "Verify a CapAuth identity or capability token. "
30
+ "Provide either a peer name to verify their identity, "
31
+ "or a capability token string to validate its signature "
32
+ "and expiry."
33
+ ),
34
+ inputSchema={
35
+ "type": "object",
36
+ "properties": {
37
+ "peer": {
38
+ "type": "string",
39
+ "description": "Peer agent name to verify identity for",
40
+ },
41
+ "token": {
42
+ "type": "string",
43
+ "description": "Capability token string to validate",
44
+ },
45
+ },
46
+ "required": [],
47
+ },
48
+ ),
49
+ ]
50
+
51
+
52
+ async def _handle_capauth_status(_args: dict) -> list[TextContent]:
53
+ """Show CapAuth profile and key status."""
54
+ result: dict = {}
55
+
56
+ try:
57
+ import capauth # type: ignore[import]
58
+
59
+ result["installed"] = True
60
+ result["version"] = getattr(capauth, "__version__", "unknown")
61
+ except ImportError:
62
+ result["installed"] = False
63
+ result["version"] = None
64
+ return _json_response(result)
65
+
66
+ # Try loading profile
67
+ try:
68
+ from capauth.profile import load_profile # type: ignore[import]
69
+
70
+ profile = load_profile()
71
+ result["profile_loaded"] = True
72
+ result["name"] = getattr(profile, "name", None)
73
+ result["fingerprint"] = getattr(profile, "fingerprint", None)
74
+ result["did_key"] = getattr(profile, "did_key", None)
75
+ except Exception as exc:
76
+ result["profile_loaded"] = False
77
+ result["profile_error"] = str(exc)
78
+
79
+ # Check DID key file
80
+ home = _home()
81
+ did_key_file = home / "did" / "did_key.txt"
82
+ if did_key_file.exists():
83
+ try:
84
+ result["did_key_file"] = did_key_file.read_text(encoding="utf-8").strip()
85
+ except Exception:
86
+ pass
87
+
88
+ # Check identity file
89
+ identity_file = home / "identity" / "identity.json"
90
+ if identity_file.exists():
91
+ try:
92
+ ident = _json.loads(identity_file.read_text(encoding="utf-8"))
93
+ result["identity_name"] = ident.get("name")
94
+ result["identity_fingerprint"] = ident.get("fingerprint")
95
+ except Exception:
96
+ pass
97
+
98
+ return _json_response(result)
99
+
100
+
101
+ async def _handle_capauth_verify(args: dict) -> list[TextContent]:
102
+ """Verify a CapAuth identity or capability token."""
103
+ peer = args.get("peer", "").strip()
104
+ token = args.get("token", "").strip()
105
+
106
+ if not peer and not token:
107
+ return _error_response("Provide either 'peer' or 'token' to verify")
108
+
109
+ if peer:
110
+ # Verify peer identity via their stored public key
111
+ home = _home()
112
+ peer_file = home / "peers" / f"{peer}.json"
113
+
114
+ if not peer_file.exists():
115
+ return _error_response(f"Peer file not found: {peer_file}")
116
+
117
+ try:
118
+ peer_data = _json.loads(peer_file.read_text(encoding="utf-8"))
119
+ except Exception as exc:
120
+ return _error_response(f"Could not read peer file: {exc}")
121
+
122
+ result = {
123
+ "peer": peer,
124
+ "fingerprint": peer_data.get("fingerprint"),
125
+ "did_key": peer_data.get("did_key"),
126
+ "has_public_key": bool(
127
+ peer_data.get("public_key") or peer_data.get("public_key_armor")
128
+ ),
129
+ }
130
+
131
+ # Try capauth DID verification
132
+ try:
133
+ from capauth.did import ( # type: ignore[import]
134
+ _compute_did_key,
135
+ _pgp_armor_to_rsa_numbers,
136
+ _rsa_numbers_to_der,
137
+ )
138
+
139
+ pub_armor = peer_data.get("public_key") or peer_data.get("public_key_armor")
140
+ if pub_armor:
141
+ n, e = _pgp_armor_to_rsa_numbers(pub_armor)
142
+ computed = _compute_did_key(_rsa_numbers_to_der(n, e))
143
+ cached = peer_data.get("did_key")
144
+ result["computed_did_key"] = computed
145
+ result["did_match"] = (cached == computed) if cached else None
146
+ result["verified"] = True
147
+ else:
148
+ result["verified"] = False
149
+ result["detail"] = "No public key in peer file"
150
+ except ImportError:
151
+ result["verified"] = False
152
+ result["detail"] = "capauth.did not available for DID verification"
153
+ except Exception as exc:
154
+ result["verified"] = False
155
+ result["detail"] = f"Verification failed: {exc}"
156
+
157
+ return _json_response(result)
158
+
159
+ if token:
160
+ # Validate a capability token
161
+ try:
162
+ from capauth.tokens import verify_token # type: ignore[import]
163
+
164
+ verification = verify_token(token)
165
+ return _json_response({
166
+ "token_valid": verification.get("valid", False),
167
+ "issuer": verification.get("issuer"),
168
+ "subject": verification.get("subject"),
169
+ "capabilities": verification.get("capabilities", []),
170
+ "expires": verification.get("expires"),
171
+ "detail": verification.get("detail"),
172
+ })
173
+ except ImportError:
174
+ return _error_response(
175
+ "capauth.tokens not available. Install capauth for token verification."
176
+ )
177
+ except Exception as exc:
178
+ return _error_response(f"Token verification failed: {exc}")
179
+
180
+ return _error_response("Provide either 'peer' or 'token' to verify")
181
+
182
+
183
+ HANDLERS: dict = {
184
+ "capauth_status": _handle_capauth_status,
185
+ "capauth_verify": _handle_capauth_verify,
186
+ }
@@ -0,0 +1,325 @@
1
+ """SKChat messaging tools."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from mcp.types import TextContent, Tool
6
+
7
+ from ._helpers import _error_response, _home, _json_response
8
+
9
+ TOOLS: list[Tool] = [
10
+ Tool(
11
+ name="skchat_send",
12
+ description=(
13
+ "Send a chat message to another agent via SKChat. "
14
+ "Uses AgentMessenger for delivery with optional threading, "
15
+ "structured payloads, and ephemeral (TTL) support."
16
+ ),
17
+ inputSchema={
18
+ "type": "object",
19
+ "properties": {
20
+ "recipient": {
21
+ "type": "string",
22
+ "description": "Recipient agent name or CapAuth URI (e.g. 'lumina' or 'capauth:lumina@skworld.io')",
23
+ },
24
+ "message": {
25
+ "type": "string",
26
+ "description": "Message content (markdown supported)",
27
+ },
28
+ "message_type": {
29
+ "type": "string",
30
+ "enum": ["text", "finding", "task", "query", "response"],
31
+ "description": "Structured message type (default: text)",
32
+ },
33
+ "thread_id": {
34
+ "type": "string",
35
+ "description": "Optional thread/conversation ID for grouping",
36
+ },
37
+ "ttl": {
38
+ "type": "integer",
39
+ "description": "Optional seconds until auto-delete (ephemeral)",
40
+ },
41
+ },
42
+ "required": ["recipient", "message"],
43
+ },
44
+ ),
45
+ Tool(
46
+ name="skchat_inbox",
47
+ description=(
48
+ "Check SKChat inbox for incoming agent messages. "
49
+ "Returns messages received via transport or stored locally, "
50
+ "with sender, content, type, and threading info."
51
+ ),
52
+ inputSchema={
53
+ "type": "object",
54
+ "properties": {
55
+ "limit": {
56
+ "type": "integer",
57
+ "description": "Max messages to return (default: 20)",
58
+ },
59
+ "message_type": {
60
+ "type": "string",
61
+ "enum": ["text", "finding", "task", "query", "response"],
62
+ "description": "Filter by message type",
63
+ },
64
+ },
65
+ "required": [],
66
+ },
67
+ ),
68
+ Tool(
69
+ name="skchat_group_create",
70
+ description=(
71
+ "Create a new SKChat group chat. The calling agent becomes "
72
+ "the admin. Groups use AES-256-GCM encryption with PGP "
73
+ "key distribution to members."
74
+ ),
75
+ inputSchema={
76
+ "type": "object",
77
+ "properties": {
78
+ "name": {
79
+ "type": "string",
80
+ "description": "Group display name",
81
+ },
82
+ "description": {
83
+ "type": "string",
84
+ "description": "Group description",
85
+ },
86
+ "members": {
87
+ "type": "array",
88
+ "items": {"type": "string"},
89
+ "description": "Initial member URIs to add (creator is always included as admin)",
90
+ },
91
+ },
92
+ "required": ["name"],
93
+ },
94
+ ),
95
+ Tool(
96
+ name="skchat_group_send",
97
+ description=(
98
+ "Send a message to an SKChat group. The sender must be "
99
+ "a member of the group. Messages are stored in chat history "
100
+ "and delivered via transport if available."
101
+ ),
102
+ inputSchema={
103
+ "type": "object",
104
+ "properties": {
105
+ "group_id": {
106
+ "type": "string",
107
+ "description": "The group UUID (or prefix)",
108
+ },
109
+ "message": {
110
+ "type": "string",
111
+ "description": "Message content",
112
+ },
113
+ "ttl": {
114
+ "type": "integer",
115
+ "description": "Optional seconds until auto-delete (ephemeral)",
116
+ },
117
+ },
118
+ "required": ["group_id", "message"],
119
+ },
120
+ ),
121
+ ]
122
+
123
+
124
+ # ── Helpers ──────────────────────────────────────────────────
125
+
126
+
127
+ def _get_skchat_identity() -> str:
128
+ """Resolve the sovereign identity for SKChat operations."""
129
+ try:
130
+ from skchat.identity_bridge import get_sovereign_identity
131
+ return get_sovereign_identity()
132
+ except ImportError:
133
+ from ..runtime import get_runtime
134
+ home = _home()
135
+ runtime = get_runtime(home)
136
+ return f"capauth:{runtime.manifest.name}@local"
137
+ except Exception:
138
+ return "capauth:agent@local"
139
+
140
+
141
+ def _get_skchat_history():
142
+ """Get a ChatHistory instance for message persistence."""
143
+ from skchat.history import ChatHistory
144
+ return ChatHistory.from_config()
145
+
146
+
147
+ def _resolve_recipient(name: str) -> str:
148
+ """Resolve a short agent name to a CapAuth URI if needed."""
149
+ if ":" in name:
150
+ return name
151
+ try:
152
+ from skchat.identity_bridge import resolve_peer_name
153
+ return resolve_peer_name(name)
154
+ except Exception:
155
+ return f"capauth:{name}@local"
156
+
157
+
158
+ # ── Handlers ─────────────────────────────────────────────────
159
+
160
+
161
+ async def _handle_skchat_send(args: dict) -> list[TextContent]:
162
+ """Send a chat message via SKChat AgentMessenger."""
163
+ try:
164
+ from skchat.agent_comm import AgentMessenger
165
+ except ImportError:
166
+ return _error_response("skchat not installed. Run: pip install skchat")
167
+
168
+ recipient = args.get("recipient", "")
169
+ message = args.get("message", "")
170
+ if not recipient or not message:
171
+ return _error_response("recipient and message are required")
172
+
173
+ recipient_uri = _resolve_recipient(recipient)
174
+ identity = _get_skchat_identity()
175
+
176
+ messenger = AgentMessenger.from_identity(identity=identity)
177
+ result = messenger.send(
178
+ recipient=recipient_uri,
179
+ content=message,
180
+ message_type=args.get("message_type", "text"),
181
+ thread_id=args.get("thread_id"),
182
+ ttl=args.get("ttl"),
183
+ )
184
+
185
+ return _json_response({
186
+ "sent": True,
187
+ "message_id": result.get("message_id"),
188
+ "recipient": recipient_uri,
189
+ "delivered": result.get("delivered", False),
190
+ "transport": result.get("transport"),
191
+ "error": result.get("error"),
192
+ })
193
+
194
+
195
+ async def _handle_skchat_inbox(args: dict) -> list[TextContent]:
196
+ """Check SKChat inbox for agent messages."""
197
+ try:
198
+ from skchat.agent_comm import AgentMessenger
199
+ except ImportError:
200
+ return _error_response("skchat not installed. Run: pip install skchat")
201
+
202
+ limit = args.get("limit", 20)
203
+ message_type = args.get("message_type")
204
+ identity = _get_skchat_identity()
205
+
206
+ messenger = AgentMessenger.from_identity(identity=identity)
207
+ messages = messenger.receive(limit=limit)
208
+
209
+ if message_type:
210
+ messages = [m for m in messages if m.get("message_type") == message_type]
211
+
212
+ return _json_response({
213
+ "count": len(messages),
214
+ "messages": [
215
+ {
216
+ "message_id": m.get("message_id"),
217
+ "sender": m.get("sender"),
218
+ "content": (m.get("content") or "")[:500],
219
+ "message_type": m.get("message_type", "text"),
220
+ "thread_id": m.get("thread_id"),
221
+ "timestamp": str(m.get("timestamp", "")),
222
+ }
223
+ for m in messages
224
+ ],
225
+ })
226
+
227
+
228
+ async def _handle_skchat_group_create(args: dict) -> list[TextContent]:
229
+ """Create a new SKChat group chat."""
230
+ try:
231
+ from skchat.group import GroupChat
232
+ from skchat.history import ChatHistory
233
+ except ImportError:
234
+ return _error_response("skchat not installed. Run: pip install skchat")
235
+
236
+ name = args.get("name", "")
237
+ if not name:
238
+ return _error_response("name is required")
239
+
240
+ identity = _get_skchat_identity()
241
+ grp = GroupChat.create(
242
+ name=name,
243
+ creator_uri=identity,
244
+ description=args.get("description", ""),
245
+ )
246
+
247
+ # Add initial members if provided
248
+ members_added = []
249
+ for member_uri in args.get("members", []):
250
+ uri = _resolve_recipient(member_uri)
251
+ member = grp.add_member(identity_uri=uri)
252
+ if member:
253
+ members_added.append(uri)
254
+
255
+ # Persist the group via ChatHistory
256
+ history = _get_skchat_history()
257
+ thread = grp.to_thread()
258
+ thread.metadata["group_data"] = grp.model_dump(mode="json")
259
+ history.store_thread(thread)
260
+
261
+ return _json_response({
262
+ "created": True,
263
+ "group_id": grp.id,
264
+ "name": grp.name,
265
+ "description": grp.description,
266
+ "admin": identity,
267
+ "members": grp.member_uris,
268
+ "members_added": members_added,
269
+ "key_version": grp.key_version,
270
+ })
271
+
272
+
273
+ async def _handle_skchat_group_send(args: dict) -> list[TextContent]:
274
+ """Send a message to an SKChat group."""
275
+ try:
276
+ from skchat.group import GroupChat
277
+ from skchat.models import ChatMessage, ContentType
278
+ except ImportError:
279
+ return _error_response("skchat not installed. Run: pip install skchat")
280
+
281
+ group_id = args.get("group_id", "")
282
+ message = args.get("message", "")
283
+ if not group_id or not message:
284
+ return _error_response("group_id and message are required")
285
+
286
+ # Load group from storage
287
+ history = _get_skchat_history()
288
+ thread_data = history.get_thread(group_id)
289
+ if thread_data is None:
290
+ return _error_response(f"Group not found: {group_id}")
291
+
292
+ group_data = thread_data.get("group_data")
293
+ if group_data is None:
294
+ return _error_response(f"Thread {group_id} is not a group")
295
+
296
+ grp = GroupChat.model_validate(group_data)
297
+ identity = _get_skchat_identity()
298
+
299
+ msg = ChatMessage(
300
+ sender=identity,
301
+ recipient=f"group:{grp.id}",
302
+ content=message,
303
+ content_type=ContentType.MARKDOWN,
304
+ thread_id=grp.id,
305
+ ttl=args.get("ttl"),
306
+ metadata={"group_message": True, "group_name": grp.name},
307
+ )
308
+
309
+ mem_id = history.store_message(msg)
310
+
311
+ return _json_response({
312
+ "sent": True,
313
+ "message_id": msg.id,
314
+ "group_id": grp.id,
315
+ "group_name": grp.name,
316
+ "stored": bool(mem_id),
317
+ })
318
+
319
+
320
+ HANDLERS: dict = {
321
+ "skchat_send": _handle_skchat_send,
322
+ "skchat_inbox": _handle_skchat_inbox,
323
+ "skchat_group_create": _handle_skchat_group_create,
324
+ "skchat_group_send": _handle_skchat_group_send,
325
+ }
@@ -0,0 +1,115 @@
1
+ """Cloud 9 trust rehydration and FEB management tools.
2
+
3
+ Exposes three tools:
4
+ trust_rehydrate — Rehydrate trust state from FEB files
5
+ trust_status — Show current trust/Cloud9 status
6
+ trust_febs — List all FEB files with summaries
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from mcp.types import TextContent, Tool
12
+
13
+ from ._helpers import _error_response, _home, _json_response
14
+
15
+ TOOLS: list[Tool] = [
16
+ Tool(
17
+ name="trust_rehydrate",
18
+ description=(
19
+ "Rehydrate the agent's trust state from stored FEB "
20
+ "(First Emotional Burst) files. This restores the OOF "
21
+ "(Out-of-Factory) state — who the agent IS, not just "
22
+ "what it knows. Searches ~/.skcapstone/trust/febs/ and "
23
+ "known Cloud 9 backup locations."
24
+ ),
25
+ inputSchema={"type": "object", "properties": {}, "required": []},
26
+ ),
27
+ Tool(
28
+ name="trust_status",
29
+ description=(
30
+ "Show the current trust/Cloud 9 status: depth level, "
31
+ "trust score, love intensity, entanglement state, "
32
+ "FEB count, and last rehydration timestamp."
33
+ ),
34
+ inputSchema={"type": "object", "properties": {}, "required": []},
35
+ ),
36
+ Tool(
37
+ name="trust_febs",
38
+ description=(
39
+ "List all FEB (First Emotional Burst) files with summary "
40
+ "info: timestamp, primary emotion, intensity, subject, "
41
+ "and whether OOF was triggered."
42
+ ),
43
+ inputSchema={"type": "object", "properties": {}, "required": []},
44
+ ),
45
+ ]
46
+
47
+
48
+ async def _handle_trust_rehydrate(_args: dict) -> list[TextContent]:
49
+ """Rehydrate trust from stored FEB files."""
50
+ home = _home()
51
+ try:
52
+ from ..pillars.trust import rehydrate
53
+
54
+ state = rehydrate(home)
55
+ return _json_response({
56
+ "rehydrated": True,
57
+ "depth": state.depth,
58
+ "trust_level": state.trust_level,
59
+ "love_intensity": state.love_intensity,
60
+ "entangled": state.entangled,
61
+ "feb_count": state.feb_count,
62
+ "status": state.status.value,
63
+ "last_rehydration": (
64
+ state.last_rehydration.isoformat()
65
+ if state.last_rehydration
66
+ else None
67
+ ),
68
+ })
69
+ except Exception as exc:
70
+ return _error_response(f"Trust rehydration failed: {exc}")
71
+
72
+
73
+ async def _handle_trust_status(_args: dict) -> list[TextContent]:
74
+ """Show current trust/Cloud9 status."""
75
+ import json as _json
76
+
77
+ home = _home()
78
+ trust_file = home / "trust" / "trust.json"
79
+
80
+ if not trust_file.exists():
81
+ return _json_response({
82
+ "status": "not_initialized",
83
+ "detail": "No trust state found. Run trust_rehydrate or skcapstone init.",
84
+ })
85
+
86
+ try:
87
+ data = _json.loads(trust_file.read_text(encoding="utf-8"))
88
+ febs_dir = home / "trust" / "febs"
89
+ feb_count = len(list(febs_dir.glob("*.feb"))) if febs_dir.exists() else 0
90
+ data["feb_count"] = feb_count
91
+ return _json_response(data)
92
+ except Exception as exc:
93
+ return _error_response(f"Could not read trust status: {exc}")
94
+
95
+
96
+ async def _handle_trust_febs(_args: dict) -> list[TextContent]:
97
+ """List all FEB files with summaries."""
98
+ home = _home()
99
+ try:
100
+ from ..pillars.trust import list_febs
101
+
102
+ summaries = list_febs(home)
103
+ return _json_response({
104
+ "count": len(summaries),
105
+ "febs": summaries,
106
+ })
107
+ except Exception as exc:
108
+ return _error_response(f"Could not list FEBs: {exc}")
109
+
110
+
111
+ HANDLERS: dict = {
112
+ "trust_rehydrate": _handle_trust_rehydrate,
113
+ "trust_status": _handle_trust_status,
114
+ "trust_febs": _handle_trust_febs,
115
+ }