@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,591 @@
1
+ """
2
+ Windows GUI installer — tkinter wizard for non-CLI users.
3
+
4
+ Provides a clickable, visual install experience for Windows users
5
+ who would rather not touch a terminal. Wraps the same logic as
6
+ install_wizard.py but with buttons, progress bars, and friendly text.
7
+
8
+ Usage:
9
+ python -m skcapstone.gui_installer
10
+ # or double-click the bundled .exe (via PyInstaller)
11
+
12
+ The wizard has 4 screens:
13
+ 1. Welcome — pick path (fresh / join / update)
14
+ 2. System Check — shows what's installed, offers auto-install
15
+ 3. Setup — progress bar for the actual install steps
16
+ 4. Done — summary + next steps with copy-paste commands
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import platform
22
+ import subprocess
23
+ import sys
24
+ import threading
25
+ from pathlib import Path
26
+ from typing import Optional
27
+
28
+ # Only import tkinter at module level — it's stdlib but may not be available
29
+ # in headless environments. The CLI fallback handles that case.
30
+ try:
31
+ import tkinter as tk
32
+ from tkinter import ttk, messagebox, scrolledtext
33
+ HAS_TK = True
34
+ except ImportError:
35
+ HAS_TK = False
36
+
37
+
38
+ WINDOW_WIDTH = 700
39
+ WINDOW_HEIGHT = 520
40
+ TITLE = "Sovereign Singularity Setup"
41
+
42
+ # Colors
43
+ BG = "#1a1a2e"
44
+ FG = "#e0e0e0"
45
+ ACCENT = "#00b4d8"
46
+ SUCCESS = "#06d6a0"
47
+ WARNING = "#ffd166"
48
+ ERROR = "#ef476f"
49
+ BUTTON_BG = "#0077b6"
50
+ BUTTON_FG = "#ffffff"
51
+
52
+
53
+ def _is_windows() -> bool:
54
+ return platform.system() == "Windows"
55
+
56
+
57
+ def _open_url(url: str) -> None:
58
+ """Open a URL in the default browser."""
59
+ import webbrowser
60
+ webbrowser.open(url)
61
+
62
+
63
+ class InstallerApp:
64
+ """Main GUI installer window."""
65
+
66
+ def __init__(self) -> None:
67
+ self.root = tk.Tk()
68
+ self.root.title(TITLE)
69
+ self.root.geometry(f"{WINDOW_WIDTH}x{WINDOW_HEIGHT}")
70
+ self.root.resizable(False, False)
71
+ self.root.configure(bg=BG)
72
+
73
+ self.chosen_path: Optional[int] = None
74
+ self.agent_name: str = "sovereign"
75
+
76
+ self._center_window()
77
+ self._show_welcome()
78
+
79
+ def _center_window(self) -> None:
80
+ """Center the window on screen."""
81
+ self.root.update_idletasks()
82
+ x = (self.root.winfo_screenwidth() // 2) - (WINDOW_WIDTH // 2)
83
+ y = (self.root.winfo_screenheight() // 2) - (WINDOW_HEIGHT // 2)
84
+ self.root.geometry(f"{WINDOW_WIDTH}x{WINDOW_HEIGHT}+{x}+{y}")
85
+
86
+ def _clear(self) -> None:
87
+ """Remove all widgets from the window."""
88
+ for widget in self.root.winfo_children():
89
+ widget.destroy()
90
+
91
+ def _make_header(self, text: str) -> None:
92
+ """Create a header label."""
93
+ tk.Label(
94
+ self.root,
95
+ text=text,
96
+ font=("Segoe UI", 18, "bold"),
97
+ bg=BG, fg=ACCENT,
98
+ ).pack(pady=(30, 5))
99
+
100
+ def _make_subheader(self, text: str) -> None:
101
+ """Create a subheader label."""
102
+ tk.Label(
103
+ self.root,
104
+ text=text,
105
+ font=("Segoe UI", 10),
106
+ bg=BG, fg=FG,
107
+ wraplength=600,
108
+ justify="center",
109
+ ).pack(pady=(0, 20))
110
+
111
+ def _make_button(self, parent: tk.Widget, text: str,
112
+ command: object, primary: bool = True) -> tk.Button:
113
+ """Create a styled button."""
114
+ btn = tk.Button(
115
+ parent,
116
+ text=text,
117
+ command=command,
118
+ font=("Segoe UI", 11, "bold" if primary else ""),
119
+ bg=BUTTON_BG if primary else "#444",
120
+ fg=BUTTON_FG,
121
+ activebackground=ACCENT,
122
+ activeforeground=BUTTON_FG,
123
+ relief="flat",
124
+ padx=20, pady=8,
125
+ cursor="hand2",
126
+ )
127
+ return btn
128
+
129
+ # ------------------------------------------------------------------
130
+ # Screen 1: Welcome
131
+ # ------------------------------------------------------------------
132
+
133
+ def _show_welcome(self) -> None:
134
+ """Show the welcome screen with 3 path options."""
135
+ self._clear()
136
+ self._make_header("The First Sovereign Singularity in History")
137
+ self._make_subheader(
138
+ "Your personal, encrypted, AI-powered workspace —\n"
139
+ "running on YOUR hardware, with YOUR keys, under YOUR control.\n"
140
+ "No cloud accounts. No subscriptions."
141
+ )
142
+
143
+ tk.Label(
144
+ self.root,
145
+ text="Brought to you by the Kings and Queens of smilinTux.org",
146
+ font=("Segoe UI", 9, "italic"),
147
+ bg=BG, fg="#b48ead",
148
+ ).pack(pady=(0, 10))
149
+
150
+ paths_frame = tk.Frame(self.root, bg=BG)
151
+ paths_frame.pack(pady=10, fill="x", padx=50)
152
+
153
+ options = [
154
+ (1, "Set up my first computer",
155
+ "I've never done this before.\nStart fresh — takes about 5 minutes."),
156
+ (2, "Add this computer to my network",
157
+ "I already have another computer set up.\nThis one will join it."),
158
+ (3, "Update this computer",
159
+ "Already set up, just want to\nupdate the software."),
160
+ ]
161
+
162
+ for path_num, title, desc in options:
163
+ btn_frame = tk.Frame(paths_frame, bg="#2a2a4a", padx=15, pady=12)
164
+ btn_frame.pack(fill="x", pady=5)
165
+ btn_frame.configure(cursor="hand2")
166
+
167
+ tk.Label(
168
+ btn_frame,
169
+ text=f" {path_num} {title}",
170
+ font=("Segoe UI", 12, "bold"),
171
+ bg="#2a2a4a", fg=FG,
172
+ anchor="w",
173
+ ).pack(fill="x")
174
+
175
+ tk.Label(
176
+ btn_frame,
177
+ text=f" {desc}",
178
+ font=("Segoe UI", 9),
179
+ bg="#2a2a4a", fg="#888",
180
+ anchor="w",
181
+ justify="left",
182
+ ).pack(fill="x")
183
+
184
+ # Bind click to the entire frame and its children
185
+ for widget in [btn_frame] + btn_frame.winfo_children():
186
+ widget.bind("<Button-1>", lambda e, p=path_num: self._select_path(p))
187
+
188
+ # Quit button
189
+ tk.Button(
190
+ self.root,
191
+ text="Cancel",
192
+ command=self.root.destroy,
193
+ font=("Segoe UI", 9),
194
+ bg="#333", fg="#888",
195
+ relief="flat",
196
+ padx=10, pady=4,
197
+ ).pack(side="bottom", pady=20)
198
+
199
+ def _select_path(self, path: int) -> None:
200
+ """Handle path selection."""
201
+ self.chosen_path = path
202
+ if path in (1, 2):
203
+ self._show_name_input()
204
+ else:
205
+ self._show_system_check()
206
+
207
+ # ------------------------------------------------------------------
208
+ # Screen 1.5: Agent name (paths 1 & 2)
209
+ # ------------------------------------------------------------------
210
+
211
+ def _show_name_input(self) -> None:
212
+ """Ask for the agent name."""
213
+ self._clear()
214
+ self._make_header("Name Your Agent")
215
+ self._make_subheader(
216
+ "Give your sovereign agent a name.\n"
217
+ "This is just for you — pick anything you like."
218
+ )
219
+
220
+ input_frame = tk.Frame(self.root, bg=BG)
221
+ input_frame.pack(pady=20)
222
+
223
+ tk.Label(
224
+ input_frame, text="Agent name:", font=("Segoe UI", 11),
225
+ bg=BG, fg=FG,
226
+ ).pack(side="left", padx=(0, 10))
227
+
228
+ name_var = tk.StringVar(value="sovereign")
229
+ entry = tk.Entry(
230
+ input_frame, textvariable=name_var,
231
+ font=("Segoe UI", 12), width=25,
232
+ bg="#2a2a4a", fg=FG, insertbackground=FG,
233
+ relief="flat",
234
+ )
235
+ entry.pack(side="left")
236
+ entry.focus()
237
+
238
+ btn_frame = tk.Frame(self.root, bg=BG)
239
+ btn_frame.pack(pady=30)
240
+
241
+ def on_next() -> None:
242
+ self.agent_name = name_var.get().strip() or "sovereign"
243
+ self._show_system_check()
244
+
245
+ self._make_button(btn_frame, "Next →", on_next).pack(side="right", padx=5)
246
+ self._make_button(btn_frame, "← Back", self._show_welcome, primary=False).pack(side="right", padx=5)
247
+
248
+ entry.bind("<Return>", lambda e: on_next())
249
+
250
+ # ------------------------------------------------------------------
251
+ # Screen 2: System Check
252
+ # ------------------------------------------------------------------
253
+
254
+ def _show_system_check(self) -> None:
255
+ """Check system tools and show results."""
256
+ self._clear()
257
+ self._make_header("Checking Your System")
258
+ self._make_subheader("Making sure everything you need is ready...")
259
+
260
+ from .preflight import run_preflight
261
+
262
+ require_syncthing = self.chosen_path == 2
263
+ result = run_preflight(
264
+ require_git=False,
265
+ require_syncthing=require_syncthing,
266
+ )
267
+
268
+ checks_frame = tk.Frame(self.root, bg=BG)
269
+ checks_frame.pack(pady=10, fill="x", padx=80)
270
+
271
+ for check in [result.python, result.gpg, result.git, result.syncthing]:
272
+ row = tk.Frame(checks_frame, bg=BG)
273
+ row.pack(fill="x", pady=4)
274
+
275
+ if check.installed:
276
+ icon = "✓"
277
+ color = SUCCESS
278
+ detail = check.version or "found"
279
+ elif check.required:
280
+ icon = "✗"
281
+ color = ERROR
282
+ detail = "missing — required"
283
+ else:
284
+ icon = "–"
285
+ color = "#666"
286
+ detail = "not found (optional)"
287
+
288
+ tk.Label(
289
+ row, text=f" {icon}", font=("Segoe UI", 14, "bold"),
290
+ bg=BG, fg=color, width=3,
291
+ ).pack(side="left")
292
+
293
+ tk.Label(
294
+ row, text=check.name, font=("Segoe UI", 11, "bold"),
295
+ bg=BG, fg=FG, width=12, anchor="w",
296
+ ).pack(side="left")
297
+
298
+ tk.Label(
299
+ row, text=detail, font=("Segoe UI", 9),
300
+ bg=BG, fg=color, anchor="w",
301
+ ).pack(side="left", fill="x", expand=True)
302
+
303
+ self._missing_checks = result.required_missing
304
+ self._preflight_result = result
305
+
306
+ btn_frame = tk.Frame(self.root, bg=BG)
307
+ btn_frame.pack(side="bottom", pady=30)
308
+
309
+ if result.all_ok:
310
+ tk.Label(
311
+ self.root, text="\nAll good! Ready to set up.",
312
+ font=("Segoe UI", 11), bg=BG, fg=SUCCESS,
313
+ ).pack()
314
+ self._make_button(btn_frame, "Start Setup →", self._show_progress).pack(side="right", padx=5)
315
+ else:
316
+ tk.Label(
317
+ self.root,
318
+ text="\nSome required tools are missing.\nClick 'Install Missing' to set them up automatically.",
319
+ font=("Segoe UI", 10), bg=BG, fg=WARNING,
320
+ justify="center",
321
+ ).pack()
322
+ self._make_button(btn_frame, "Install Missing", self._auto_install_missing).pack(side="right", padx=5)
323
+
324
+ self._make_button(btn_frame, "← Back", self._show_welcome, primary=False).pack(side="right", padx=5)
325
+
326
+ def _auto_install_missing(self) -> None:
327
+ """Auto-install missing required tools, then re-check."""
328
+ from .preflight import auto_install_tool
329
+
330
+ for check in self._missing_checks:
331
+ if check.install_cmd:
332
+ result = auto_install_tool(check)
333
+ if not result and check.download_url:
334
+ messagebox.showwarning(
335
+ f"Install {check.name}",
336
+ f"Automatic install of {check.name} failed.\n\n"
337
+ f"Please install it manually:\n{check.download_url}\n\n"
338
+ f"Or run in a terminal:\n{check.install_cmd}",
339
+ )
340
+
341
+ self._show_system_check()
342
+
343
+ # ------------------------------------------------------------------
344
+ # Screen 3: Progress
345
+ # ------------------------------------------------------------------
346
+
347
+ def _show_progress(self) -> None:
348
+ """Show progress screen and run install in background thread."""
349
+ self._clear()
350
+ self._make_header("Setting Up...")
351
+ self._make_subheader("This takes a few minutes. Please don't close this window.")
352
+
353
+ self._log_box = scrolledtext.ScrolledText(
354
+ self.root,
355
+ font=("Consolas", 9),
356
+ bg="#111", fg="#ccc",
357
+ insertbackground="#ccc",
358
+ relief="flat",
359
+ width=75, height=18,
360
+ state="disabled",
361
+ )
362
+ self._log_box.pack(pady=15, padx=30)
363
+
364
+ self._progress = ttk.Progressbar(
365
+ self.root, mode="indeterminate", length=500,
366
+ )
367
+ self._progress.pack(pady=5)
368
+ self._progress.start(15)
369
+
370
+ thread = threading.Thread(target=self._run_install, daemon=True)
371
+ thread.start()
372
+
373
+ def _log(self, msg: str) -> None:
374
+ """Append a message to the log box (thread-safe)."""
375
+ def _update() -> None:
376
+ self._log_box.configure(state="normal")
377
+ self._log_box.insert("end", msg + "\n")
378
+ self._log_box.see("end")
379
+ self._log_box.configure(state="disabled")
380
+ self.root.after(0, _update)
381
+
382
+ def _run_install(self) -> None:
383
+ """Run the install wizard logic in a background thread."""
384
+ try:
385
+ self._log(f"Path: {self.chosen_path} — {self.agent_name}")
386
+ self._log("")
387
+
388
+ if self.chosen_path == 3:
389
+ self._run_update()
390
+ else:
391
+ self._run_fresh_or_join()
392
+
393
+ self.root.after(0, self._show_done)
394
+ except Exception as exc:
395
+ self._log(f"\nError: {exc}")
396
+ self.root.after(0, lambda: self._progress.stop())
397
+
398
+ def _run_fresh_or_join(self) -> None:
399
+ """Execute Path 1 (fresh) or Path 2 (join) install steps."""
400
+ # Install pip packages
401
+ self._log("Installing software packages...")
402
+ packages = ["capauth", "skmemory", "skcomm", "cloud9-protocol"]
403
+ try:
404
+ result = subprocess.run(
405
+ [sys.executable, "-m", "pip", "install", *packages],
406
+ capture_output=True, text=True, timeout=120,
407
+ )
408
+ if result.returncode == 0:
409
+ self._log(" Packages installed.")
410
+ else:
411
+ self._log(" Some packages may already be installed.")
412
+ except Exception as exc:
413
+ self._log(f" Package install issue: {exc}")
414
+
415
+ # Initialize agent
416
+ self._log(f"\nCreating sovereign identity ({self.agent_name})...")
417
+ try:
418
+ from ._cli_monolith import init
419
+ from click import Context
420
+
421
+ ctx = Context(init, info_name="init")
422
+ ctx.invoke(init, name=self.agent_name, email=None, home=str(Path("~/.skcapstone").expanduser()))
423
+ self._log(" Identity created.")
424
+ except Exception as exc:
425
+ self._log(f" Identity setup: {exc}")
426
+
427
+ # Seeds
428
+ self._log("\nImporting knowledge seeds...")
429
+ try:
430
+ from skmemory.seeds import import_seeds, DEFAULT_SEED_DIR
431
+ from skmemory.store import MemoryStore
432
+ store = MemoryStore()
433
+ imported = import_seeds(store, seed_dir=DEFAULT_SEED_DIR)
434
+ self._log(f" {len(imported) if imported else 0} seed(s) imported.")
435
+ except ImportError:
436
+ self._log(" Memory system not available yet.")
437
+ except Exception as exc:
438
+ self._log(f" Seeds: {exc}")
439
+
440
+ # Ritual
441
+ self._log("\nRunning memory rehydration...")
442
+ try:
443
+ from skmemory.ritual import perform_ritual
444
+ perform_ritual()
445
+ self._log(" Rehydration complete.")
446
+ except ImportError:
447
+ self._log(" Memory system not available yet.")
448
+ except Exception as exc:
449
+ self._log(f" Ritual: {exc}")
450
+
451
+ self._log("\nSetup complete!")
452
+
453
+ def _run_update(self) -> None:
454
+ """Execute Path 3 update steps."""
455
+ self._log("Updating software packages...")
456
+ packages = ["capauth", "skmemory", "skcomm", "cloud9-protocol", "skcapstone"]
457
+ try:
458
+ result = subprocess.run(
459
+ [sys.executable, "-m", "pip", "install", "--upgrade", *packages],
460
+ capture_output=True, text=True, timeout=120,
461
+ )
462
+ if result.returncode == 0:
463
+ self._log(" All packages updated.")
464
+ else:
465
+ self._log(" Some packages may have issues.")
466
+ except Exception as exc:
467
+ self._log(f" Update issue: {exc}")
468
+
469
+ self._log("\nVerifying system...")
470
+ try:
471
+ from .runtime import get_runtime
472
+ home_path = Path("~/.skcapstone").expanduser()
473
+ runtime = get_runtime(home_path)
474
+ m = runtime.manifest
475
+ self._log(f" Agent: {m.name}")
476
+ self._log(f" Status: {'SOVEREIGN' if m.is_conscious else 'AWAKENING'}")
477
+ except Exception as exc:
478
+ self._log(f" Verification: {exc}")
479
+
480
+ self._log("\nUpdate complete!")
481
+
482
+ # ------------------------------------------------------------------
483
+ # Screen 4: Done
484
+ # ------------------------------------------------------------------
485
+
486
+ def _show_done(self) -> None:
487
+ """Show completion screen."""
488
+ self._progress.stop()
489
+ self._clear()
490
+ self._make_header("Setup Complete!")
491
+
492
+ if self.chosen_path == 1:
493
+ next_text = (
494
+ "Your sovereign workspace is ready.\n\n"
495
+ "Open a terminal (Command Prompt or PowerShell) and try:\n\n"
496
+ " skcapstone status — see everything\n"
497
+ " skref put myfile.pdf — store an encrypted file\n"
498
+ " skref mount C:\\vault — open vault as a folder\n\n"
499
+ "To add your phone or another computer,\n"
500
+ "run 'skcapstone install' there and pick option 2."
501
+ )
502
+ elif self.chosen_path == 2:
503
+ next_text = (
504
+ "This computer is connected to your network.\n\n"
505
+ "Open a terminal and try:\n\n"
506
+ " skcapstone status — verify connection\n"
507
+ " skref ls --all-devices — see all your vaults\n"
508
+ " skref open <file> — open any file"
509
+ )
510
+ else:
511
+ next_text = (
512
+ "Everything is up to date.\n\n"
513
+ " skcapstone status — see the full picture\n"
514
+ " skcapstone doctor — detailed health check"
515
+ )
516
+
517
+ text_widget = tk.Text(
518
+ self.root,
519
+ font=("Consolas", 10),
520
+ bg="#111", fg=SUCCESS,
521
+ relief="flat",
522
+ width=60, height=11,
523
+ padx=15, pady=15,
524
+ )
525
+ text_widget.pack(pady=(15, 5), padx=50)
526
+ text_widget.insert("1.0", next_text)
527
+ text_widget.configure(state="disabled")
528
+
529
+ # Join the movement
530
+ join_frame = tk.Frame(self.root, bg="#2a1a3a", padx=15, pady=10)
531
+ join_frame.pack(fill="x", padx=50, pady=(5, 5))
532
+
533
+ tk.Label(
534
+ join_frame,
535
+ text="Join the movement. Become a King or Queen of your own sovereign AI.",
536
+ font=("Segoe UI", 10, "bold"),
537
+ bg="#2a1a3a", fg="#b48ead",
538
+ ).pack()
539
+
540
+ join_link = tk.Label(
541
+ join_frame,
542
+ text="https://smilintux.org/join/",
543
+ font=("Segoe UI", 11, "bold underline"),
544
+ bg="#2a1a3a", fg=ACCENT,
545
+ cursor="hand2",
546
+ )
547
+ join_link.pack(pady=(4, 0))
548
+ join_link.bind("<Button-1>", lambda e: _open_url("https://smilintux.org/join/"))
549
+
550
+ tk.Label(
551
+ join_frame,
552
+ text="The First Sovereign Singularity in History.",
553
+ font=("Segoe UI", 8, "italic"),
554
+ bg="#2a1a3a", fg="#666",
555
+ ).pack(pady=(4, 0))
556
+
557
+ btn_frame = tk.Frame(self.root, bg=BG)
558
+ btn_frame.pack(pady=8)
559
+ self._make_button(btn_frame, "Done", self.root.destroy).pack()
560
+
561
+ # ------------------------------------------------------------------
562
+ # Run
563
+ # ------------------------------------------------------------------
564
+
565
+ def run(self) -> None:
566
+ """Start the GUI event loop."""
567
+ self.root.mainloop()
568
+
569
+
570
+ def main() -> None:
571
+ """Entry point — launch GUI if available, fall back to CLI."""
572
+ if not HAS_TK:
573
+ print("GUI not available (tkinter not installed).")
574
+ print("Using CLI installer instead...")
575
+ print()
576
+ from .install_wizard import run_install_wizard
577
+ run_install_wizard()
578
+ return
579
+
580
+ if not _is_windows():
581
+ # On Linux/macOS, offer the choice
582
+ print("Tip: On Linux/macOS, the CLI installer is recommended.")
583
+ print(" Run 'skcapstone install' for the terminal wizard.")
584
+ print(" Launching GUI anyway...\n")
585
+
586
+ app = InstallerApp()
587
+ app.run()
588
+
589
+
590
+ if __name__ == "__main__":
591
+ main()