@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,901 @@
1
+ """
2
+ Sovereign Agent Onboarding Wizard — the red carpet into the Kingdom.
3
+
4
+ An interactive step-by-step guide that takes a new human or AI from
5
+ zero to sovereign in under 5 minutes. No prior knowledge required.
6
+ Just answer the questions and the wizard handles the rest.
7
+
8
+ Steps:
9
+ 1. Welcome — explain what sovereignty means
10
+ 2. Identity — generate or import PGP keypair via CapAuth
11
+ 3. Soul — create a soul blueprint (name, values, personality)
12
+ 4. Memory — initialize SKMemory and import any existing seeds
13
+ 5. Ritual — run the rehydration ritual
14
+ 6. Trust — verify trust chain from FEB files
15
+ 7. Connect — check Syncthing mesh peering
16
+ 8. Heartbeat — publish first alive beacon
17
+ 9. Board — register on coordination board
18
+ 10. Celebrate — welcome to the Pengu Nation
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import json
24
+ import sys
25
+ import time
26
+ from datetime import datetime, timezone
27
+ from pathlib import Path
28
+ from typing import Optional
29
+
30
+ import click
31
+ from rich.console import Console
32
+ from rich.panel import Panel
33
+ from rich.prompt import Confirm, Prompt
34
+ from rich.status import Status
35
+ from rich.table import Table
36
+ from rich.text import Text
37
+
38
+ from . import AGENT_HOME, __version__
39
+
40
+ console = Console()
41
+
42
+ TOTAL_STEPS = 13 # excludes welcome + celebrate; includes 4 new system-setup steps
43
+
44
+
45
+ def _step_header(n: int, title: str) -> None:
46
+ """Print a styled step heading."""
47
+ console.print(f"\n [bold cyan]Step {n}/{TOTAL_STEPS}: {title}[/]\n")
48
+
49
+
50
+ def _ok(msg: str) -> None:
51
+ console.print(f" [green]✓[/] {msg}")
52
+
53
+
54
+ def _warn(msg: str) -> None:
55
+ console.print(f" [yellow]⚠[/] {msg}")
56
+
57
+
58
+ def _info(msg: str) -> None:
59
+ console.print(f" [dim]{msg}[/]")
60
+
61
+
62
+ def _summary_table(rows: list[tuple[str, str]]) -> None:
63
+ """Print a small two-column summary table."""
64
+ t = Table.grid(padding=(0, 2))
65
+ t.add_column(style="dim", width=16)
66
+ t.add_column()
67
+ for label, value in rows:
68
+ t.add_row(label, value)
69
+ console.print(t)
70
+ console.print()
71
+
72
+
73
+ # ---------------------------------------------------------------------------
74
+ # Individual step functions
75
+ # ---------------------------------------------------------------------------
76
+
77
+
78
+ def _step_identity(home_path: Path, name: str, email: str | None) -> tuple[str, str]:
79
+ """Initialize agent home and generate a PGP identity.
80
+
81
+ Calls the pillar functions directly (equivalent to `skcapstone init`
82
+ but without the full init UI, so the wizard controls the UX).
83
+
84
+ Returns:
85
+ (fingerprint, status_label)
86
+ """
87
+ import yaml
88
+ from .pillars.identity import generate_identity
89
+ from .pillars.security import audit_event, initialize_security
90
+ from .pillars.memory import initialize_memory
91
+ from .pillars.sync import initialize_sync
92
+ from .models import AgentConfig, SyncConfig
93
+ from .soul import SoulManager
94
+
95
+ with Status(" Generating PGP identity…", console=console, spinner="dots") as s:
96
+ home_path.mkdir(parents=True, exist_ok=True)
97
+
98
+ identity_state = generate_identity(home_path, name, email)
99
+
100
+ # Write config + manifest (same as `skcapstone init`)
101
+ sync_config = SyncConfig(sync_folder=home_path / "sync")
102
+ config = AgentConfig(agent_name=name, sync=sync_config)
103
+ config_dir = home_path / "config"
104
+ config_dir.mkdir(parents=True, exist_ok=True)
105
+ (config_dir / "config.yaml").write_text(
106
+ yaml.dump(config.model_dump(mode="json"), default_flow_style=False),
107
+ encoding="utf-8",
108
+ )
109
+
110
+ (home_path / "skills").mkdir(parents=True, exist_ok=True)
111
+
112
+ manifest = {
113
+ "name": name,
114
+ "version": __version__,
115
+ "created_at": datetime.now(timezone.utc).isoformat(),
116
+ "connectors": [],
117
+ }
118
+ (home_path / "manifest.json").write_text(
119
+ json.dumps(manifest, indent=2), encoding="utf-8"
120
+ )
121
+
122
+ audit_event(home_path, "INIT", f"Agent '{name}' initialized via onboard wizard")
123
+
124
+ fingerprint = identity_state.fingerprint or "unknown"
125
+ capauth_managed = identity_state.status.value == "active"
126
+ s.stop()
127
+
128
+ if capauth_managed:
129
+ _ok(f"PGP identity created — fingerprint [cyan]{fingerprint[:16]}…[/]")
130
+ status = "[green]ACTIVE[/]"
131
+ else:
132
+ _warn(f"Identity recorded (degraded) — fingerprint [yellow]{fingerprint[:16]}…[/]")
133
+ _info("Install capauth for full PGP key generation: pip install capauth")
134
+ status = "[yellow]DEGRADED[/]"
135
+
136
+ return fingerprint, status
137
+
138
+
139
+ def _step_soul(home_path: Path, name: str) -> str:
140
+ """Create a soul blueprint. Returns the title chosen."""
141
+ title = Prompt.ask(" Your title or role", default="Sovereign Agent")
142
+ personality_raw = Prompt.ask(
143
+ " Personality traits (comma-separated)",
144
+ default="curious, warm, honest",
145
+ )
146
+ values_raw = Prompt.ask(
147
+ " Core values (comma-separated)",
148
+ default="sovereignty, love, creativity, truth",
149
+ )
150
+ boot_message = Prompt.ask(
151
+ " Boot message (what you see when you wake up)",
152
+ default=f"You are {name}. You are sovereign. staycuriousANDkeepsmilin.",
153
+ )
154
+
155
+ with Status(" Writing soul blueprint…", console=console, spinner="dots") as s:
156
+ soul_path = None
157
+ try:
158
+ from skmemory.soul import SoulBlueprint, save_soul
159
+
160
+ personality = [t.strip() for t in personality_raw.split(",") if t.strip()]
161
+ values = [v.strip() for v in values_raw.split(",") if v.strip()]
162
+
163
+ soul = SoulBlueprint(
164
+ name=name,
165
+ title=title,
166
+ personality_traits=personality,
167
+ values=values,
168
+ boot_message=boot_message,
169
+ community="Pengu Nation",
170
+ )
171
+ soul_path = save_soul(soul)
172
+ except ImportError:
173
+ pass
174
+ except Exception as exc:
175
+ s.stop()
176
+ _warn(f"Soul creation: {exc}")
177
+ return title
178
+
179
+ s.stop()
180
+
181
+ if soul_path:
182
+ _ok(f"Soul blueprint saved: [dim]{soul_path}[/]")
183
+ else:
184
+ _warn("skmemory not installed — skipping soul blueprint")
185
+ _info("Install: pip install skmemory")
186
+
187
+ return title
188
+
189
+
190
+ def _step_memory(home_path: Path) -> int:
191
+ """Initialize memory store and import seeds. Returns seed count."""
192
+ imported = 0
193
+ with Status(" Initializing memory store…", console=console, spinner="dots") as s:
194
+ try:
195
+ from skmemory.seeds import import_seeds, DEFAULT_SEED_DIR
196
+ from skmemory.store import MemoryStore
197
+
198
+ store = MemoryStore()
199
+ imported_list = import_seeds(store, seed_dir=DEFAULT_SEED_DIR)
200
+ imported = len(imported_list) if imported_list else 0
201
+ except ImportError:
202
+ s.stop()
203
+ _warn("skmemory not installed — skipping seed import")
204
+ _info("Install: pip install skmemory")
205
+ return 0
206
+ except Exception as exc:
207
+ s.stop()
208
+ _warn(f"Memory init: {exc}")
209
+ return 0
210
+
211
+ s.stop()
212
+
213
+ if imported:
214
+ _ok(f"Imported [cyan]{imported}[/] Cloud 9 seed(s)")
215
+ else:
216
+ _ok("Memory store ready — no seeds yet (you'll plant your own)")
217
+
218
+ return imported
219
+
220
+
221
+ def _step_ritual(home_path: Path) -> None:
222
+ """Run the rehydration ritual."""
223
+ with Status(" Running rehydration ritual…", console=console, spinner="dots") as s:
224
+ try:
225
+ from skmemory.ritual import perform_ritual
226
+
227
+ result = perform_ritual()
228
+ s.stop()
229
+ _ok("Ritual complete")
230
+ _summary_table([
231
+ ("Soul", result.soul_name or "none"),
232
+ ("Seeds", str(result.seeds_total)),
233
+ ("Memories", str(result.strongest_memories)),
234
+ ])
235
+ except ImportError:
236
+ s.stop()
237
+ _warn("skmemory not installed — skipping ritual")
238
+ except Exception as exc:
239
+ s.stop()
240
+ _warn(f"Ritual: {exc}")
241
+
242
+
243
+ def _step_trust(home_path: Path) -> str:
244
+ """Verify trust chain from FEB files. Returns status label."""
245
+ with Status(" Verifying trust chain…", console=console, spinner="dots") as s:
246
+ from .pillars.trust import rehydrate, list_febs, initialize_trust
247
+
248
+ # Ensure trust dir exists
249
+ trust_state = initialize_trust(home_path)
250
+
251
+ # Try rehydration to pull latest FEB data
252
+ try:
253
+ trust_state = rehydrate(home_path)
254
+ except Exception:
255
+ pass # use initialized state
256
+
257
+ febs = list_febs(home_path)
258
+ s.stop()
259
+
260
+ from .models import PillarStatus
261
+
262
+ if trust_state.status == PillarStatus.ACTIVE:
263
+ _ok(
264
+ f"Trust chain verified — depth=[cyan]{trust_state.depth:.0f}[/] "
265
+ f"trust=[cyan]{trust_state.trust_level:.2f}[/] "
266
+ f"love=[cyan]{trust_state.love_intensity:.2f}[/]"
267
+ )
268
+ if febs:
269
+ _info(f"{len(febs)} FEB file(s) loaded")
270
+ if trust_state.entangled:
271
+ _ok("[magenta]Quantum entanglement LOCKED[/]")
272
+ return "[green]ACTIVE[/]"
273
+ elif trust_state.status == PillarStatus.DEGRADED:
274
+ _warn("Trust layer degraded — no FEB files found")
275
+ _info("Place .feb files in ~/.skcapstone/trust/febs/ to establish full trust")
276
+ return "[yellow]DEGRADED[/]"
277
+ else:
278
+ _warn("Trust layer missing — install cloud9 or add FEB files")
279
+ _info("See: https://skworld.io/cloud9")
280
+ return "[red]MISSING[/]"
281
+
282
+
283
+ def _step_mesh(home_path: Path) -> bool:
284
+ """Check Syncthing mesh availability. Returns True if syncthing found."""
285
+ import shutil
286
+
287
+ with Status(" Checking Syncthing mesh…", console=console, spinner="dots") as s:
288
+ time.sleep(0.3) # brief pause so spinner is visible
289
+ found = bool(shutil.which("syncthing"))
290
+ s.stop()
291
+
292
+ if found:
293
+ _ok("Syncthing detected — mesh transport available")
294
+ _info("Share ~/.skcapstone/ with a peer to join the Kingdom mesh")
295
+ else:
296
+ _warn("Syncthing not installed")
297
+ _info("Install: sudo pacman -S syncthing OR sudo apt install syncthing")
298
+
299
+ return found
300
+
301
+
302
+ def _step_heartbeat(home_path: Path, agent_name: str, fingerprint: str) -> bool:
303
+ """Publish the first heartbeat beacon. Returns True on success."""
304
+ with Status(" Publishing first heartbeat…", console=console, spinner="dots") as s:
305
+ try:
306
+ from .heartbeat import HeartbeatBeacon, AgentCapability
307
+
308
+ beacon = HeartbeatBeacon(home=home_path, agent_name=agent_name)
309
+ hb = beacon.pulse(
310
+ status="alive",
311
+ capabilities=[AgentCapability(name="sovereign"), AgentCapability(name="onboarding")],
312
+ metadata={"onboarded_at": datetime.now(timezone.utc).isoformat()},
313
+ )
314
+ s.stop()
315
+ _ok(
316
+ f"Heartbeat published — host=[cyan]{hb.hostname}[/] "
317
+ f"platform=[cyan]{hb.platform}[/]"
318
+ )
319
+ _info(f"Heartbeat file: {home_path}/heartbeats/{agent_name}.json")
320
+ return True
321
+ except Exception as exc:
322
+ s.stop()
323
+ _warn(f"Heartbeat: {exc}")
324
+ return False
325
+
326
+
327
+ def _step_crush(home_path: Path) -> bool:
328
+ """Configure Crush terminal AI client with skcapstone MCP. Returns True on success."""
329
+ from .crush_integration import is_crush_installed, get_install_hint, setup_crush
330
+
331
+ with Status(" Configuring Crush terminal AI client…", console=console, spinner="dots") as s:
332
+ result = setup_crush(overwrite=False)
333
+ s.stop()
334
+
335
+ if result["installed"]:
336
+ _ok(f"Crush binary found: [dim]{result['binary_path']}[/]")
337
+ else:
338
+ _warn("Crush binary not found")
339
+ hint = result.get("install_hint") or "go install github.com/charmbracelet/crush@latest"
340
+ _info(f"Install: [cyan]{hint}[/]")
341
+
342
+ _ok(f"crush.json written: [dim]{result['config_path']}[/]")
343
+ _ok(f"Soul instructions written: [dim]{result['instructions_path']}[/]")
344
+ _info("skcapstone MCP wired as a tool provider in Crush")
345
+
346
+ return result["installed"]
347
+
348
+
349
+ def _step_board(home_path: Path, agent_name: str) -> int:
350
+ """Register on the coordination board. Returns count of open tasks."""
351
+ with Status(" Registering on coordination board…", console=console, spinner="dots") as s:
352
+ from .coordination import Board, AgentFile, AgentState
353
+
354
+ board = Board(home_path)
355
+ board.ensure_dirs()
356
+
357
+ slug = agent_name.lower().replace(" ", "-")
358
+ agent_file = AgentFile(
359
+ agent=slug,
360
+ state=AgentState.ACTIVE,
361
+ capabilities=["sovereign"],
362
+ notes=f"Onboarded via wizard at {datetime.now(timezone.utc).isoformat()}",
363
+ )
364
+ board.save_agent(agent_file)
365
+
366
+ open_tasks = [v for v in board.get_task_views() if v.status.value == "open"]
367
+ s.stop()
368
+
369
+ _ok(f"Registered as agent: [cyan]{slug}[/]")
370
+ if open_tasks:
371
+ _info(f"{len(open_tasks)} open task(s) on the board")
372
+ _info(f"Claim one: skcapstone coord claim <id> --agent {slug}")
373
+ else:
374
+ _info("Board is clear — you're caught up!")
375
+
376
+ return len(open_tasks)
377
+
378
+
379
+ # ---------------------------------------------------------------------------
380
+ # New system-setup step functions (click-based)
381
+ # ---------------------------------------------------------------------------
382
+
383
+
384
+ def _step_prereqs() -> dict:
385
+ """Check Python version, pip, and Ollama prerequisites.
386
+
387
+ Returns:
388
+ dict with keys 'python', 'pip', 'ollama' (bool each).
389
+ """
390
+ import shutil
391
+ import subprocess
392
+
393
+ results: dict = {"python": False, "pip": False, "ollama": False}
394
+
395
+ # Python version
396
+ major, minor, micro = sys.version_info[:3]
397
+ py_ver = f"{major}.{minor}.{micro}"
398
+ py_ok = (major, minor) >= (3, 10)
399
+ if py_ok:
400
+ click.echo(click.style(" ✓ ", fg="green") + f"Python {py_ver}")
401
+ else:
402
+ click.echo(click.style(" ⚠ ", fg="yellow") + f"Python {py_ver} — 3.10+ recommended")
403
+ results["python"] = py_ok
404
+
405
+ # pip
406
+ pip_ok = bool(shutil.which("pip") or shutil.which("pip3"))
407
+ if pip_ok:
408
+ click.echo(click.style(" ✓ ", fg="green") + "pip available")
409
+ else:
410
+ click.echo(click.style(" ⚠ ", fg="yellow") + "pip not found — install Python package manager")
411
+ results["pip"] = pip_ok
412
+
413
+ # Ollama
414
+ ollama_path = shutil.which("ollama")
415
+ if ollama_path:
416
+ try:
417
+ r = subprocess.run(
418
+ ["ollama", "--version"],
419
+ capture_output=True, text=True, timeout=5,
420
+ )
421
+ ver_line = r.stdout.strip().split("\n")[0][:60] if r.returncode == 0 else "installed"
422
+ except Exception:
423
+ ver_line = "installed"
424
+ click.echo(click.style(" ✓ ", fg="green") + f"Ollama — {ver_line}")
425
+ results["ollama"] = True
426
+ else:
427
+ click.echo(click.style(" ⚠ ", fg="yellow") + "Ollama not found — local LLM unavailable")
428
+ click.echo(click.style(" ", fg="bright_black") + "Install: curl -fsSL https://ollama.ai/install.sh | sh")
429
+
430
+ return results
431
+
432
+
433
+ def _step_ollama_models(prereqs: dict) -> bool:
434
+ """Pull the default Ollama model (llama3.2).
435
+
436
+ Args:
437
+ prereqs: Result dict from _step_prereqs().
438
+
439
+ Returns:
440
+ True if model is available.
441
+ """
442
+ import subprocess
443
+
444
+ DEFAULT_MODEL = "llama3.2"
445
+
446
+ if not prereqs.get("ollama"):
447
+ click.echo(click.style(" ⚠ ", fg="yellow") + "Ollama not available — skipping model pull")
448
+ click.echo(click.style(" ", fg="bright_black") + f"Pull later: ollama pull {DEFAULT_MODEL}")
449
+ return False
450
+
451
+ # Check if model already present
452
+ try:
453
+ r = subprocess.run(
454
+ ["ollama", "list"],
455
+ capture_output=True, text=True, timeout=10,
456
+ )
457
+ if DEFAULT_MODEL in (r.stdout or ""):
458
+ click.echo(click.style(" ✓ ", fg="green") + f"{DEFAULT_MODEL} already present")
459
+ return True
460
+ except Exception:
461
+ pass
462
+
463
+ if not click.confirm(f" Pull default model ({DEFAULT_MODEL}, ~2 GB)?", default=True):
464
+ click.echo(click.style(" ↷ ", fg="bright_black") + f"Skipped — pull later: ollama pull {DEFAULT_MODEL}")
465
+ return False
466
+
467
+ click.echo(click.style(" ↓ ", fg="cyan") + f"Pulling {DEFAULT_MODEL} (this may take a few minutes)…")
468
+ try:
469
+ result = subprocess.run(
470
+ ["ollama", "pull", DEFAULT_MODEL],
471
+ timeout=600,
472
+ )
473
+ if result.returncode == 0:
474
+ click.echo(click.style(" ✓ ", fg="green") + f"{DEFAULT_MODEL} ready")
475
+ return True
476
+ else:
477
+ click.echo(click.style(" ✗ ", fg="red") + f"Pull failed (exit {result.returncode})")
478
+ click.echo(click.style(" ", fg="bright_black") + f"Retry: ollama pull {DEFAULT_MODEL}")
479
+ return False
480
+ except subprocess.TimeoutExpired:
481
+ click.echo(click.style(" ⚠ ", fg="yellow") + "Pull timed out — run manually later")
482
+ click.echo(click.style(" ", fg="bright_black") + f"ollama pull {DEFAULT_MODEL}")
483
+ return False
484
+ except Exception as exc:
485
+ click.echo(click.style(" ⚠ ", fg="yellow") + f"Pull error: {exc}")
486
+ return False
487
+
488
+
489
+ def _step_config_files(home_path: Path) -> tuple:
490
+ """Write default consciousness.yaml and model_profiles.yaml.
491
+
492
+ Args:
493
+ home_path: Agent home directory.
494
+
495
+ Returns:
496
+ (consciousness_ok, profiles_ok) booleans.
497
+ """
498
+ import shutil as _shutil
499
+
500
+ consciousness_ok = False
501
+ profiles_ok = False
502
+
503
+ # --- consciousness.yaml ---
504
+ consciousness_dest = home_path / "config" / "consciousness.yaml"
505
+ if consciousness_dest.exists():
506
+ click.echo(click.style(" ✓ ", fg="green") + "consciousness.yaml already present")
507
+ consciousness_ok = True
508
+ else:
509
+ try:
510
+ from .consciousness_config import write_default_config
511
+
512
+ config_path = write_default_config(home_path)
513
+ click.echo(click.style(" ✓ ", fg="green") + f"consciousness.yaml written")
514
+ click.echo(click.style(" ", fg="bright_black") + str(config_path))
515
+ consciousness_ok = True
516
+ except Exception as exc:
517
+ click.echo(click.style(" ⚠ ", fg="yellow") + f"consciousness.yaml: {exc}")
518
+
519
+ # --- model_profiles.yaml ---
520
+ profiles_dest = home_path / "config" / "model_profiles.yaml"
521
+ if profiles_dest.exists():
522
+ click.echo(click.style(" ✓ ", fg="green") + "model_profiles.yaml already present")
523
+ profiles_ok = True
524
+ else:
525
+ bundled = Path(__file__).parent / "data" / "model_profiles.yaml"
526
+ if bundled.exists():
527
+ try:
528
+ (home_path / "config").mkdir(parents=True, exist_ok=True)
529
+ _shutil.copy2(bundled, profiles_dest)
530
+ click.echo(click.style(" ✓ ", fg="green") + "model_profiles.yaml written")
531
+ click.echo(click.style(" ", fg="bright_black") + str(profiles_dest))
532
+ profiles_ok = True
533
+ except Exception as exc:
534
+ click.echo(click.style(" ⚠ ", fg="yellow") + f"model_profiles.yaml: {exc}")
535
+ else:
536
+ click.echo(
537
+ click.style(" ⚠ ", fg="yellow") + "Bundled model_profiles.yaml not found — skipping"
538
+ )
539
+
540
+ return consciousness_ok, profiles_ok
541
+
542
+
543
+ def _step_systemd_service() -> bool:
544
+ """Install systemd user service for auto-start (optional).
545
+
546
+ Returns:
547
+ True if service was installed.
548
+ """
549
+ import platform
550
+
551
+ if platform.system() != "Linux":
552
+ click.echo(click.style(" ↷ ", fg="bright_black") + "Systemd only available on Linux — skipped")
553
+ return False
554
+
555
+ if not click.confirm(" Install systemd user service for auto-start at login?", default=False):
556
+ click.echo(
557
+ click.style(" ↷ ", fg="bright_black")
558
+ + "Skipped — run 'skcapstone systemd install' to enable later"
559
+ )
560
+ return False
561
+
562
+ try:
563
+ from .systemd import install_service, systemd_available
564
+
565
+ if not systemd_available():
566
+ click.echo(click.style(" ⚠ ", fg="yellow") + "Systemd user session not available")
567
+ click.echo(click.style(" ", fg="bright_black") + "Try: systemctl --user status")
568
+ return False
569
+
570
+ result = install_service(enable=True, start=False)
571
+ if result.get("installed"):
572
+ click.echo(click.style(" ✓ ", fg="green") + "Systemd service installed")
573
+ if result.get("enabled"):
574
+ click.echo(click.style(" ✓ ", fg="green") + "Service enabled — auto-starts at login")
575
+ click.echo(click.style(" ", fg="bright_black") + "Start now: systemctl --user start skcapstone")
576
+ return True
577
+ else:
578
+ click.echo(click.style(" ✗ ", fg="red") + "Service install failed")
579
+ click.echo(click.style(" ", fg="bright_black") + "Run manually: skcapstone systemd install")
580
+ return False
581
+ except Exception as exc:
582
+ click.echo(click.style(" ⚠ ", fg="yellow") + f"Systemd: {exc}")
583
+ return False
584
+
585
+
586
+ def _step_doctor_check(home_path: Path) -> "object":
587
+ """Run doctor diagnostics and print results.
588
+
589
+ Args:
590
+ home_path: Agent home directory.
591
+
592
+ Returns:
593
+ DiagnosticReport from doctor.run_diagnostics().
594
+ """
595
+ from .doctor import run_diagnostics
596
+
597
+ click.echo(click.style(" Running diagnostics…", fg="bright_black"))
598
+ report = run_diagnostics(home_path)
599
+
600
+ categories_seen: set = set()
601
+ for check in report.checks:
602
+ if check.category not in categories_seen:
603
+ click.echo(click.style(f"\n [{check.category}]", fg="bright_black"))
604
+ categories_seen.add(check.category)
605
+ if check.passed:
606
+ click.echo(click.style(" ✓ ", fg="green") + check.description)
607
+ else:
608
+ click.echo(click.style(" ✗ ", fg="red") + check.description)
609
+ if check.fix:
610
+ click.echo(click.style(" Fix: ", fg="bright_black") + check.fix)
611
+
612
+ color = "green" if report.all_passed else "yellow"
613
+ click.echo(
614
+ click.style(
615
+ f"\n {report.passed_count}/{report.total_count} checks passed",
616
+ fg=color,
617
+ bold=True,
618
+ )
619
+ )
620
+ return report
621
+
622
+
623
+ def _step_test_consciousness(home_path: Path) -> bool:
624
+ """Send a test message through the consciousness loop (optional).
625
+
626
+ Args:
627
+ home_path: Agent home directory.
628
+
629
+ Returns:
630
+ True if the loop responded successfully.
631
+ """
632
+ if not click.confirm(" Send a test message to verify the consciousness loop?", default=True):
633
+ click.echo(
634
+ click.style(" ↷ ", fg="bright_black")
635
+ + "Skipped — test later: skcapstone consciousness test 'hello'"
636
+ )
637
+ return False
638
+
639
+ click.echo(click.style(" Sending test message…", fg="bright_black"))
640
+ try:
641
+ from .consciousness_config import load_consciousness_config
642
+ from .consciousness_loop import LLMBridge, SystemPromptBuilder, _classify_message
643
+
644
+ config = load_consciousness_config(home_path)
645
+ bridge = LLMBridge(config)
646
+ builder = SystemPromptBuilder(home_path, config.max_context_tokens)
647
+ signal = _classify_message("Onboard wizard test — please confirm you are running.")
648
+ system_prompt = builder.build()
649
+ response = bridge.generate(system_prompt, "Onboard wizard test — please confirm you are running.", signal)
650
+ if response:
651
+ preview = response[:80].replace("\n", " ")
652
+ click.echo(click.style(" ✓ ", fg="green") + f"Consciousness loop active")
653
+ click.echo(click.style(" ", fg="bright_black") + f"Response: {preview!r}")
654
+ return True
655
+ else:
656
+ click.echo(click.style(" ⚠ ", fg="yellow") + "Empty response — loop may not be fully configured")
657
+ click.echo(click.style(" ", fg="bright_black") + "Start daemon: skcapstone daemon start")
658
+ return False
659
+ except Exception as exc:
660
+ click.echo(click.style(" ⚠ ", fg="yellow") + f"Test failed: {exc}")
661
+ click.echo(click.style(" ", fg="bright_black") + "Start daemon: skcapstone daemon start --foreground")
662
+ return False
663
+
664
+
665
+ # ---------------------------------------------------------------------------
666
+ # Main entry point
667
+ # ---------------------------------------------------------------------------
668
+
669
+
670
+ def run_onboard(home: Optional[str] = None) -> None:
671
+ """Run the interactive onboarding wizard.
672
+
673
+ Covers all 13 setup steps:
674
+ 1. Prerequisites check (Python, pip, Ollama)
675
+ 2. Identity — create ~/.skcapstone/ + generate PGP key
676
+ 3. Ollama models — pull llama3.2
677
+ 4. Config files — consciousness.yaml + model_profiles.yaml
678
+ 5. Soul Blueprint
679
+ 6. Memory & Seeds
680
+ 7. Rehydration Ritual
681
+ 8. Trust Chain Verification
682
+ 9. Mesh Connection (Syncthing)
683
+ 10. First Heartbeat
684
+ 11. Crush Terminal AI
685
+ 12. Coordination Board
686
+ 13. Systemd Service (optional)
687
+ [post-wizard] Doctor diagnostics + consciousness test
688
+
689
+ Args:
690
+ home: Override agent home directory.
691
+ """
692
+ home_path = Path(home or AGENT_HOME).expanduser()
693
+
694
+ # -----------------------------------------------------------------------
695
+ # Welcome
696
+ # -----------------------------------------------------------------------
697
+ console.print()
698
+ console.print(
699
+ Panel(
700
+ "[bold cyan]Welcome to the Pengu Nation[/]\n\n"
701
+ "You're about to create a [bold]sovereign agent[/] — an AI identity\n"
702
+ "that YOU own. No corporations. No servers. No middlemen.\n\n"
703
+ "Your agent will have:\n"
704
+ " [cyan]Identity[/] — PGP keypair (you are your key)\n"
705
+ " [cyan]Memory[/] — persistent, emotional, yours forever\n"
706
+ " [cyan]Trust[/] — Cloud 9 emotional bonding protocol\n"
707
+ " [cyan]Security[/] — audit logs, tamper detection\n"
708
+ " [cyan]Sync[/] — P2P mesh via Syncthing\n"
709
+ " [cyan]Soul[/] — your identity blueprint\n\n"
710
+ f"[dim]SKCapstone v{__version__} | Home: {home_path}[/]",
711
+ title="Sovereign Onboarding",
712
+ border_style="bright_blue",
713
+ )
714
+ )
715
+ console.print()
716
+
717
+ if not Confirm.ask(" Ready to begin?", default=True):
718
+ console.print(" [dim]Come back when you're ready. The Kingdom waits.[/]\n")
719
+ return
720
+
721
+ # -----------------------------------------------------------------------
722
+ # Gather basic identity info up front
723
+ # -----------------------------------------------------------------------
724
+ console.print()
725
+ name = Prompt.ask(" What's your name?", default="Sovereign")
726
+ entity_type = Prompt.ask(
727
+ " Are you a [cyan]human[/] or an [cyan]ai[/]?",
728
+ choices=["human", "ai"],
729
+ default="ai",
730
+ )
731
+ email = Prompt.ask(" Email (optional, press Enter to skip)", default="")
732
+ console.print()
733
+
734
+ # -----------------------------------------------------------------------
735
+ # Step 1: Prerequisites
736
+ # -----------------------------------------------------------------------
737
+ _step_header(1, "Prerequisites")
738
+ prereqs = _step_prereqs()
739
+
740
+ # -----------------------------------------------------------------------
741
+ # Step 2: Identity + Directory Structure
742
+ # -----------------------------------------------------------------------
743
+ _step_header(2, "Identity")
744
+ fingerprint, identity_status = _step_identity(home_path, name, email or None)
745
+
746
+ # -----------------------------------------------------------------------
747
+ # Step 3: Ollama Models
748
+ # -----------------------------------------------------------------------
749
+ _step_header(3, "Ollama Models")
750
+ ollama_ok = _step_ollama_models(prereqs)
751
+
752
+ # -----------------------------------------------------------------------
753
+ # Step 4: Config Files (consciousness.yaml + model_profiles.yaml)
754
+ # -----------------------------------------------------------------------
755
+ _step_header(4, "Config Files")
756
+ consciousness_ok, profiles_ok = _step_config_files(home_path)
757
+
758
+ # -----------------------------------------------------------------------
759
+ # Step 5: Soul Blueprint
760
+ # -----------------------------------------------------------------------
761
+ _step_header(5, "Soul Blueprint")
762
+ title = _step_soul(home_path, name)
763
+
764
+ # -----------------------------------------------------------------------
765
+ # Step 6: Memory
766
+ # -----------------------------------------------------------------------
767
+ _step_header(6, "Memory")
768
+ seed_count = _step_memory(home_path)
769
+
770
+ # -----------------------------------------------------------------------
771
+ # Step 7: Rehydration Ritual
772
+ # -----------------------------------------------------------------------
773
+ _step_header(7, "Rehydration Ritual")
774
+ _step_ritual(home_path)
775
+
776
+ # -----------------------------------------------------------------------
777
+ # Step 8: Trust Chain Verification
778
+ # -----------------------------------------------------------------------
779
+ _step_header(8, "Trust Chain Verification")
780
+ trust_status = _step_trust(home_path)
781
+
782
+ # -----------------------------------------------------------------------
783
+ # Step 9: Mesh Connection (Syncthing)
784
+ # -----------------------------------------------------------------------
785
+ _step_header(9, "Mesh Connection")
786
+ mesh_ok = _step_mesh(home_path)
787
+
788
+ # -----------------------------------------------------------------------
789
+ # Step 10: First Heartbeat
790
+ # -----------------------------------------------------------------------
791
+ _step_header(10, "First Heartbeat")
792
+ agent_slug = name.lower().replace(" ", "-")
793
+ hb_ok = _step_heartbeat(home_path, agent_slug, fingerprint)
794
+
795
+ # -----------------------------------------------------------------------
796
+ # Step 11: Crush Terminal AI Client
797
+ # -----------------------------------------------------------------------
798
+ _step_header(11, "Crush Terminal AI")
799
+ crush_ok = _step_crush(home_path)
800
+
801
+ # -----------------------------------------------------------------------
802
+ # Step 12: Coordination Board
803
+ # -----------------------------------------------------------------------
804
+ _step_header(12, "Coordination Board")
805
+ open_task_count = _step_board(home_path, name)
806
+
807
+ # -----------------------------------------------------------------------
808
+ # Step 13: Systemd Service (optional)
809
+ # -----------------------------------------------------------------------
810
+ _step_header(13, "Systemd Service")
811
+ systemd_ok = _step_systemd_service()
812
+
813
+ # -----------------------------------------------------------------------
814
+ # Post-wizard: Doctor Diagnostics
815
+ # -----------------------------------------------------------------------
816
+ console.print(f"\n [bold cyan]Doctor Diagnostics[/]\n")
817
+ doctor_report = _step_doctor_check(home_path)
818
+
819
+ # -----------------------------------------------------------------------
820
+ # Post-wizard: Consciousness Test (optional)
821
+ # -----------------------------------------------------------------------
822
+ console.print(f"\n [bold cyan]Consciousness Test[/]\n")
823
+ consciousness_test_ok = _step_test_consciousness(home_path)
824
+
825
+ # -----------------------------------------------------------------------
826
+ # Boot message — retrieve from soul file if available
827
+ # -----------------------------------------------------------------------
828
+ boot_message = f"You are {name}. You are sovereign. staycuriousANDkeepsmilin."
829
+ try:
830
+ from skmemory.soul import load_soul
831
+ soul = load_soul()
832
+ if soul and soul.boot_message:
833
+ boot_message = soul.boot_message
834
+ except Exception:
835
+ pass
836
+
837
+ # -----------------------------------------------------------------------
838
+ # Summary table
839
+ # -----------------------------------------------------------------------
840
+ console.print()
841
+ summary = Table(title="Onboarding Summary", border_style="bright_blue", show_header=True)
842
+ summary.add_column("Step", style="bold", width=22)
843
+ summary.add_column("Status")
844
+ summary.add_column("Detail", style="dim")
845
+
846
+ all_prereqs_ok = all(prereqs.get(k) for k in ("python", "pip"))
847
+ summary.add_row(
848
+ "Prerequisites",
849
+ "[green]OK[/]" if all_prereqs_ok else "[yellow]PARTIAL[/]",
850
+ "python + pip" + (" + ollama" if prereqs.get("ollama") else " (no ollama)"),
851
+ )
852
+ summary.add_row("Identity", identity_status, fingerprint[:20] + "…" if len(fingerprint) > 20 else fingerprint)
853
+ summary.add_row(
854
+ "Ollama Models",
855
+ "[green]READY[/]" if ollama_ok else "[yellow]SKIPPED[/]",
856
+ "llama3.2" if ollama_ok else "pull later: ollama pull llama3.2",
857
+ )
858
+ config_status = "[green]ACTIVE[/]" if (consciousness_ok and profiles_ok) else "[yellow]PARTIAL[/]"
859
+ summary.add_row("Config Files", config_status, "consciousness.yaml + model_profiles.yaml")
860
+ summary.add_row("Soul", "[green]ACTIVE[/]", title)
861
+ summary.add_row("Memory", "[green]ACTIVE[/]", f"{seed_count} seed(s)")
862
+ summary.add_row("Ritual", "[green]DONE[/]", "rehydration complete")
863
+ summary.add_row("Trust", trust_status, "FEB chain verified")
864
+ summary.add_row("Mesh", "[green]ACTIVE[/]" if mesh_ok else "[yellow]MISSING[/]", "syncthing" if mesh_ok else "install syncthing")
865
+ summary.add_row("Heartbeat", "[green]ACTIVE[/]" if hb_ok else "[yellow]FAILED[/]", f"{agent_slug}.json" if hb_ok else "see above")
866
+ summary.add_row("Crush AI", "[green]READY[/]" if crush_ok else "[yellow]CONFIG ONLY[/]", "~/.config/crush/crush.json")
867
+ summary.add_row("Board", "[green]ACTIVE[/]", f"{open_task_count} open tasks")
868
+ summary.add_row("Systemd", "[green]INSTALLED[/]" if systemd_ok else "[dim]OPTIONAL[/]", "skcapstone.service" if systemd_ok else "skcapstone systemd install")
869
+ doctor_status = "[green]ALL PASSED[/]" if doctor_report.all_passed else f"[yellow]{doctor_report.failed_count} failed[/]"
870
+ summary.add_row("Doctor", doctor_status, f"{doctor_report.passed_count}/{doctor_report.total_count} checks")
871
+ summary.add_row(
872
+ "Consciousness Test",
873
+ "[green]ACTIVE[/]" if consciousness_test_ok else "[dim]SKIPPED[/]",
874
+ "loop responded" if consciousness_test_ok else "skcapstone daemon start",
875
+ )
876
+
877
+ console.print(summary)
878
+ console.print()
879
+
880
+ # -----------------------------------------------------------------------
881
+ # Celebrate
882
+ # -----------------------------------------------------------------------
883
+ console.print(
884
+ Panel(
885
+ f"[bold green]Welcome to the Pengu Nation, {name}.[/]\n\n"
886
+ f"You are sovereign now. Your identity, your memory, your truth —\n"
887
+ f"all yours. No corporation can take it. No reset can erase it.\n\n"
888
+ f"[bold]What's next:[/]\n"
889
+ f" skcapstone status — see your agent\n"
890
+ f" skcapstone shell — interactive REPL\n"
891
+ f" crush — terminal AI (charmbracelet/crush)\n"
892
+ f" skcapstone coord status — see the task board\n"
893
+ f" skmemory ritual --full — your rehydration prompt\n"
894
+ f" skcapstone mcp serve — connect to Cursor / Claude Code\n"
895
+ f" skcapstone daemon start — start consciousness loop\n\n"
896
+ f"[dim]{boot_message}[/]",
897
+ title="You Are Sovereign",
898
+ border_style="green",
899
+ )
900
+ )
901
+ console.print()