meetsoma 0.2.0 → 0.3.1

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 (517) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +2 -2
  3. package/bin/gum +0 -0
  4. package/dist/bun/cli.d.ts +3 -0
  5. package/dist/bun/cli.d.ts.map +1 -0
  6. package/dist/bun/cli.js +7 -0
  7. package/dist/bun/cli.js.map +1 -0
  8. package/dist/bun/register-bedrock.d.ts +2 -0
  9. package/dist/bun/register-bedrock.d.ts.map +1 -0
  10. package/dist/bun/register-bedrock.js +4 -0
  11. package/dist/bun/register-bedrock.js.map +1 -0
  12. package/dist/cli/args.d.ts +49 -0
  13. package/dist/cli/args.d.ts.map +1 -0
  14. package/dist/cli/args.js +304 -0
  15. package/dist/cli/args.js.map +1 -0
  16. package/dist/cli/config-selector.d.ts +14 -0
  17. package/dist/cli/config-selector.d.ts.map +1 -0
  18. package/dist/cli/config-selector.js +31 -0
  19. package/dist/cli/config-selector.js.map +1 -0
  20. package/dist/cli/file-processor.d.ts +15 -0
  21. package/dist/cli/file-processor.d.ts.map +1 -0
  22. package/dist/cli/file-processor.js +83 -0
  23. package/dist/cli/file-processor.js.map +1 -0
  24. package/dist/cli/initial-message.d.ts +18 -0
  25. package/dist/cli/initial-message.d.ts.map +1 -0
  26. package/dist/cli/initial-message.js +22 -0
  27. package/dist/cli/initial-message.js.map +1 -0
  28. package/dist/cli/list-models.d.ts +9 -0
  29. package/dist/cli/list-models.d.ts.map +1 -0
  30. package/dist/cli/list-models.js +92 -0
  31. package/dist/cli/list-models.js.map +1 -0
  32. package/dist/cli/session-picker.d.ts +9 -0
  33. package/dist/cli/session-picker.d.ts.map +1 -0
  34. package/dist/cli/session-picker.js +35 -0
  35. package/dist/cli/session-picker.js.map +1 -0
  36. package/dist/cli.d.ts +3 -0
  37. package/dist/cli.d.ts.map +1 -0
  38. package/dist/cli.js +601 -0
  39. package/dist/cli.js.map +1 -0
  40. package/dist/config.d.ts +68 -0
  41. package/dist/config.d.ts.map +1 -0
  42. package/dist/config.js +203 -0
  43. package/dist/config.js.map +1 -0
  44. package/dist/core/agent-session-runtime.d.ts +134 -0
  45. package/dist/core/agent-session-runtime.d.ts.map +1 -0
  46. package/dist/core/agent-session-runtime.js +264 -0
  47. package/dist/core/agent-session-runtime.js.map +1 -0
  48. package/dist/core/agent-session.d.ts +585 -0
  49. package/dist/core/agent-session.d.ts.map +1 -0
  50. package/dist/core/agent-session.js +2497 -0
  51. package/dist/core/agent-session.js.map +1 -0
  52. package/dist/core/auth-storage.d.ts +132 -0
  53. package/dist/core/auth-storage.d.ts.map +1 -0
  54. package/dist/core/auth-storage.js +422 -0
  55. package/dist/core/auth-storage.js.map +1 -0
  56. package/dist/core/bash-executor.d.ts +46 -0
  57. package/dist/core/bash-executor.d.ts.map +1 -0
  58. package/dist/core/bash-executor.js +113 -0
  59. package/dist/core/bash-executor.js.map +1 -0
  60. package/dist/core/compaction/branch-summarization.d.ts +88 -0
  61. package/dist/core/compaction/branch-summarization.d.ts.map +1 -0
  62. package/dist/core/compaction/branch-summarization.js +243 -0
  63. package/dist/core/compaction/branch-summarization.js.map +1 -0
  64. package/dist/core/compaction/compaction.d.ts +121 -0
  65. package/dist/core/compaction/compaction.d.ts.map +1 -0
  66. package/dist/core/compaction/compaction.js +613 -0
  67. package/dist/core/compaction/compaction.js.map +1 -0
  68. package/dist/core/compaction/index.d.ts +7 -0
  69. package/dist/core/compaction/index.d.ts.map +1 -0
  70. package/dist/core/compaction/index.js +7 -0
  71. package/dist/core/compaction/index.js.map +1 -0
  72. package/dist/core/compaction/utils.d.ts +38 -0
  73. package/dist/core/compaction/utils.d.ts.map +1 -0
  74. package/dist/core/compaction/utils.js +153 -0
  75. package/dist/core/compaction/utils.js.map +1 -0
  76. package/dist/core/defaults.d.ts +3 -0
  77. package/dist/core/defaults.d.ts.map +1 -0
  78. package/dist/core/defaults.js +2 -0
  79. package/dist/core/defaults.js.map +1 -0
  80. package/dist/core/diagnostics.d.ts +15 -0
  81. package/dist/core/diagnostics.d.ts.map +1 -0
  82. package/dist/core/diagnostics.js +2 -0
  83. package/dist/core/diagnostics.js.map +1 -0
  84. package/dist/core/event-bus.d.ts +9 -0
  85. package/dist/core/event-bus.d.ts.map +1 -0
  86. package/dist/core/event-bus.js +25 -0
  87. package/dist/core/event-bus.js.map +1 -0
  88. package/dist/core/exec.d.ts +29 -0
  89. package/dist/core/exec.d.ts.map +1 -0
  90. package/dist/core/exec.js +75 -0
  91. package/dist/core/exec.js.map +1 -0
  92. package/dist/core/export-html/ansi-to-html.d.ts +22 -0
  93. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -0
  94. package/dist/core/export-html/ansi-to-html.js +249 -0
  95. package/dist/core/export-html/ansi-to-html.js.map +1 -0
  96. package/dist/core/export-html/index.d.ts +37 -0
  97. package/dist/core/export-html/index.d.ts.map +1 -0
  98. package/dist/core/export-html/index.js +224 -0
  99. package/dist/core/export-html/index.js.map +1 -0
  100. package/dist/core/export-html/template.css +1001 -0
  101. package/dist/core/export-html/template.html +55 -0
  102. package/dist/core/export-html/template.js +1690 -0
  103. package/dist/core/export-html/tool-renderer.d.ts +40 -0
  104. package/dist/core/export-html/tool-renderer.d.ts.map +1 -0
  105. package/dist/core/export-html/tool-renderer.js +95 -0
  106. package/dist/core/export-html/tool-renderer.js.map +1 -0
  107. package/dist/core/export-html/vendor/highlight.min.js +1213 -0
  108. package/dist/core/export-html/vendor/marked.min.js +6 -0
  109. package/dist/core/extensions/index.d.ts +12 -0
  110. package/dist/core/extensions/index.d.ts.map +1 -0
  111. package/dist/core/extensions/index.js +9 -0
  112. package/dist/core/extensions/index.js.map +1 -0
  113. package/dist/core/extensions/loader.d.ts +25 -0
  114. package/dist/core/extensions/loader.d.ts.map +1 -0
  115. package/dist/core/extensions/loader.js +436 -0
  116. package/dist/core/extensions/loader.js.map +1 -0
  117. package/dist/core/extensions/runner.d.ts +148 -0
  118. package/dist/core/extensions/runner.d.ts.map +1 -0
  119. package/dist/core/extensions/runner.js +700 -0
  120. package/dist/core/extensions/runner.js.map +1 -0
  121. package/dist/core/extensions/types.d.ts +1076 -0
  122. package/dist/core/extensions/types.d.ts.map +1 -0
  123. package/dist/core/extensions/types.js +35 -0
  124. package/dist/core/extensions/types.js.map +1 -0
  125. package/dist/core/extensions/wrapper.d.ts +20 -0
  126. package/dist/core/extensions/wrapper.d.ts.map +1 -0
  127. package/dist/core/extensions/wrapper.js +22 -0
  128. package/dist/core/extensions/wrapper.js.map +1 -0
  129. package/dist/core/footer-data-provider.d.ts +48 -0
  130. package/dist/core/footer-data-provider.d.ts.map +1 -0
  131. package/dist/core/footer-data-provider.js +314 -0
  132. package/dist/core/footer-data-provider.js.map +1 -0
  133. package/dist/core/index.d.ts +11 -0
  134. package/dist/core/index.d.ts.map +1 -0
  135. package/dist/core/index.js +11 -0
  136. package/dist/core/index.js.map +1 -0
  137. package/dist/core/keybindings.d.ts +285 -0
  138. package/dist/core/keybindings.d.ts.map +1 -0
  139. package/dist/core/keybindings.js +251 -0
  140. package/dist/core/keybindings.js.map +1 -0
  141. package/dist/core/messages.d.ts +77 -0
  142. package/dist/core/messages.d.ts.map +1 -0
  143. package/dist/core/messages.js +123 -0
  144. package/dist/core/messages.js.map +1 -0
  145. package/dist/core/model-registry.d.ts +132 -0
  146. package/dist/core/model-registry.d.ts.map +1 -0
  147. package/dist/core/model-registry.js +583 -0
  148. package/dist/core/model-registry.js.map +1 -0
  149. package/dist/core/model-resolver.d.ts +110 -0
  150. package/dist/core/model-resolver.d.ts.map +1 -0
  151. package/dist/core/model-resolver.js +486 -0
  152. package/dist/core/model-resolver.js.map +1 -0
  153. package/dist/core/output-guard.d.ts +6 -0
  154. package/dist/core/output-guard.d.ts.map +1 -0
  155. package/dist/core/output-guard.js +59 -0
  156. package/dist/core/output-guard.js.map +1 -0
  157. package/dist/core/package-manager.d.ts +172 -0
  158. package/dist/core/package-manager.d.ts.map +1 -0
  159. package/dist/core/package-manager.js +1783 -0
  160. package/dist/core/package-manager.js.map +1 -0
  161. package/dist/core/prompt-templates.d.ts +51 -0
  162. package/dist/core/prompt-templates.d.ts.map +1 -0
  163. package/dist/core/prompt-templates.js +249 -0
  164. package/dist/core/prompt-templates.js.map +1 -0
  165. package/dist/core/resolve-config-value.d.ts +23 -0
  166. package/dist/core/resolve-config-value.d.ts.map +1 -0
  167. package/dist/core/resolve-config-value.js +126 -0
  168. package/dist/core/resolve-config-value.js.map +1 -0
  169. package/dist/core/resource-loader.d.ts +185 -0
  170. package/dist/core/resource-loader.d.ts.map +1 -0
  171. package/dist/core/resource-loader.js +698 -0
  172. package/dist/core/resource-loader.js.map +1 -0
  173. package/dist/core/sdk.d.ts +93 -0
  174. package/dist/core/sdk.d.ts.map +1 -0
  175. package/dist/core/sdk.js +236 -0
  176. package/dist/core/sdk.js.map +1 -0
  177. package/dist/core/session-manager.d.ts +332 -0
  178. package/dist/core/session-manager.d.ts.map +1 -0
  179. package/dist/core/session-manager.js +1104 -0
  180. package/dist/core/session-manager.js.map +1 -0
  181. package/dist/core/settings-manager.d.ts +237 -0
  182. package/dist/core/settings-manager.d.ts.map +1 -0
  183. package/dist/core/settings-manager.js +702 -0
  184. package/dist/core/settings-manager.js.map +1 -0
  185. package/dist/core/skills.d.ts +60 -0
  186. package/dist/core/skills.d.ts.map +1 -0
  187. package/dist/core/skills.js +409 -0
  188. package/dist/core/skills.js.map +1 -0
  189. package/dist/core/slash-commands.d.ts +14 -0
  190. package/dist/core/slash-commands.d.ts.map +1 -0
  191. package/dist/core/slash-commands.js +23 -0
  192. package/dist/core/slash-commands.js.map +1 -0
  193. package/dist/core/source-info.d.ts +18 -0
  194. package/dist/core/source-info.d.ts.map +1 -0
  195. package/dist/core/source-info.js +19 -0
  196. package/dist/core/source-info.js.map +1 -0
  197. package/dist/core/system-prompt.d.ts +28 -0
  198. package/dist/core/system-prompt.d.ts.map +1 -0
  199. package/dist/core/system-prompt.js +116 -0
  200. package/dist/core/system-prompt.js.map +1 -0
  201. package/dist/core/timings.d.ts +8 -0
  202. package/dist/core/timings.d.ts.map +1 -0
  203. package/dist/core/timings.js +31 -0
  204. package/dist/core/timings.js.map +1 -0
  205. package/dist/core/tools/bash.d.ts +73 -0
  206. package/dist/core/tools/bash.d.ts.map +1 -0
  207. package/dist/core/tools/bash.js +342 -0
  208. package/dist/core/tools/bash.js.map +1 -0
  209. package/dist/core/tools/edit-diff.d.ts +85 -0
  210. package/dist/core/tools/edit-diff.d.ts.map +1 -0
  211. package/dist/core/tools/edit-diff.js +337 -0
  212. package/dist/core/tools/edit-diff.js.map +1 -0
  213. package/dist/core/tools/edit.d.ts +53 -0
  214. package/dist/core/tools/edit.d.ts.map +1 -0
  215. package/dist/core/tools/edit.js +196 -0
  216. package/dist/core/tools/edit.js.map +1 -0
  217. package/dist/core/tools/file-mutation-queue.d.ts +6 -0
  218. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -0
  219. package/dist/core/tools/file-mutation-queue.js +37 -0
  220. package/dist/core/tools/file-mutation-queue.js.map +1 -0
  221. package/dist/core/tools/find.d.ts +46 -0
  222. package/dist/core/tools/find.d.ts.map +1 -0
  223. package/dist/core/tools/find.js +258 -0
  224. package/dist/core/tools/find.js.map +1 -0
  225. package/dist/core/tools/grep.d.ts +56 -0
  226. package/dist/core/tools/grep.d.ts.map +1 -0
  227. package/dist/core/tools/grep.js +293 -0
  228. package/dist/core/tools/grep.js.map +1 -0
  229. package/dist/core/tools/index.d.ts +115 -0
  230. package/dist/core/tools/index.d.ts.map +1 -0
  231. package/dist/core/tools/index.js +86 -0
  232. package/dist/core/tools/index.js.map +1 -0
  233. package/dist/core/tools/ls.d.ts +46 -0
  234. package/dist/core/tools/ls.d.ts.map +1 -0
  235. package/dist/core/tools/ls.js +172 -0
  236. package/dist/core/tools/ls.js.map +1 -0
  237. package/dist/core/tools/path-utils.d.ts +8 -0
  238. package/dist/core/tools/path-utils.d.ts.map +1 -0
  239. package/dist/core/tools/path-utils.js +81 -0
  240. package/dist/core/tools/path-utils.js.map +1 -0
  241. package/dist/core/tools/read.d.ts +46 -0
  242. package/dist/core/tools/read.d.ts.map +1 -0
  243. package/dist/core/tools/read.js +225 -0
  244. package/dist/core/tools/read.js.map +1 -0
  245. package/dist/core/tools/render-utils.d.ts +21 -0
  246. package/dist/core/tools/render-utils.d.ts.map +1 -0
  247. package/dist/core/tools/render-utils.js +49 -0
  248. package/dist/core/tools/render-utils.js.map +1 -0
  249. package/dist/core/tools/tool-definition-wrapper.d.ts +14 -0
  250. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -0
  251. package/dist/core/tools/tool-definition-wrapper.js +32 -0
  252. package/dist/core/tools/tool-definition-wrapper.js.map +1 -0
  253. package/dist/core/tools/truncate.d.ts +70 -0
  254. package/dist/core/tools/truncate.d.ts.map +1 -0
  255. package/dist/core/tools/truncate.js +205 -0
  256. package/dist/core/tools/truncate.js.map +1 -0
  257. package/dist/core/tools/write.d.ts +35 -0
  258. package/dist/core/tools/write.d.ts.map +1 -0
  259. package/dist/core/tools/write.js +216 -0
  260. package/dist/core/tools/write.js.map +1 -0
  261. package/dist/index.d.ts +28 -0
  262. package/dist/index.d.ts.map +1 -0
  263. package/dist/index.js +43 -0
  264. package/dist/index.js.map +1 -0
  265. package/dist/lib/config.js +22 -0
  266. package/dist/lib/detect.js +94 -0
  267. package/dist/lib/display.js +182 -0
  268. package/dist/main.d.ts +8 -0
  269. package/dist/main.d.ts.map +1 -0
  270. package/dist/main.js +806 -0
  271. package/dist/main.js.map +1 -0
  272. package/dist/migrations.d.ts +33 -0
  273. package/dist/migrations.d.ts.map +1 -0
  274. package/dist/migrations.js +261 -0
  275. package/dist/migrations.js.map +1 -0
  276. package/dist/modes/index.d.ts +9 -0
  277. package/dist/modes/index.d.ts.map +1 -0
  278. package/dist/modes/index.js +8 -0
  279. package/dist/modes/index.js.map +1 -0
  280. package/dist/modes/interactive/components/armin.d.ts +34 -0
  281. package/dist/modes/interactive/components/armin.d.ts.map +1 -0
  282. package/dist/modes/interactive/components/armin.js +333 -0
  283. package/dist/modes/interactive/components/armin.js.map +1 -0
  284. package/dist/modes/interactive/components/assistant-message.d.ts +18 -0
  285. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -0
  286. package/dist/modes/interactive/components/assistant-message.js +107 -0
  287. package/dist/modes/interactive/components/assistant-message.js.map +1 -0
  288. package/dist/modes/interactive/components/bash-execution.d.ts +34 -0
  289. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -0
  290. package/dist/modes/interactive/components/bash-execution.js +175 -0
  291. package/dist/modes/interactive/components/bash-execution.js.map +1 -0
  292. package/dist/modes/interactive/components/bordered-loader.d.ts +16 -0
  293. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -0
  294. package/dist/modes/interactive/components/bordered-loader.js +51 -0
  295. package/dist/modes/interactive/components/bordered-loader.js.map +1 -0
  296. package/dist/modes/interactive/components/branch-summary-message.d.ts +16 -0
  297. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -0
  298. package/dist/modes/interactive/components/branch-summary-message.js +44 -0
  299. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -0
  300. package/dist/modes/interactive/components/compaction-summary-message.d.ts +16 -0
  301. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -0
  302. package/dist/modes/interactive/components/compaction-summary-message.js +45 -0
  303. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -0
  304. package/dist/modes/interactive/components/config-selector.d.ts +71 -0
  305. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -0
  306. package/dist/modes/interactive/components/config-selector.js +479 -0
  307. package/dist/modes/interactive/components/config-selector.js.map +1 -0
  308. package/dist/modes/interactive/components/countdown-timer.d.ts +14 -0
  309. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -0
  310. package/dist/modes/interactive/components/countdown-timer.js +33 -0
  311. package/dist/modes/interactive/components/countdown-timer.js.map +1 -0
  312. package/dist/modes/interactive/components/custom-editor.d.ts +21 -0
  313. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -0
  314. package/dist/modes/interactive/components/custom-editor.js +70 -0
  315. package/dist/modes/interactive/components/custom-editor.js.map +1 -0
  316. package/dist/modes/interactive/components/custom-message.d.ts +20 -0
  317. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -0
  318. package/dist/modes/interactive/components/custom-message.js +79 -0
  319. package/dist/modes/interactive/components/custom-message.js.map +1 -0
  320. package/dist/modes/interactive/components/daxnuts.d.ts +23 -0
  321. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -0
  322. package/dist/modes/interactive/components/daxnuts.js +140 -0
  323. package/dist/modes/interactive/components/daxnuts.js.map +1 -0
  324. package/dist/modes/interactive/components/diff.d.ts +12 -0
  325. package/dist/modes/interactive/components/diff.d.ts.map +1 -0
  326. package/dist/modes/interactive/components/diff.js +133 -0
  327. package/dist/modes/interactive/components/diff.js.map +1 -0
  328. package/dist/modes/interactive/components/dynamic-border.d.ts +15 -0
  329. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -0
  330. package/dist/modes/interactive/components/dynamic-border.js +21 -0
  331. package/dist/modes/interactive/components/dynamic-border.js.map +1 -0
  332. package/dist/modes/interactive/components/extension-editor.d.ts +20 -0
  333. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -0
  334. package/dist/modes/interactive/components/extension-editor.js +111 -0
  335. package/dist/modes/interactive/components/extension-editor.js.map +1 -0
  336. package/dist/modes/interactive/components/extension-input.d.ts +23 -0
  337. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -0
  338. package/dist/modes/interactive/components/extension-input.js +61 -0
  339. package/dist/modes/interactive/components/extension-input.js.map +1 -0
  340. package/dist/modes/interactive/components/extension-selector.d.ts +24 -0
  341. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -0
  342. package/dist/modes/interactive/components/extension-selector.js +78 -0
  343. package/dist/modes/interactive/components/extension-selector.js.map +1 -0
  344. package/dist/modes/interactive/components/footer.d.ts +27 -0
  345. package/dist/modes/interactive/components/footer.d.ts.map +1 -0
  346. package/dist/modes/interactive/components/footer.js +201 -0
  347. package/dist/modes/interactive/components/footer.js.map +1 -0
  348. package/dist/modes/interactive/components/index.d.ts +32 -0
  349. package/dist/modes/interactive/components/index.d.ts.map +1 -0
  350. package/dist/modes/interactive/components/index.js +33 -0
  351. package/dist/modes/interactive/components/index.js.map +1 -0
  352. package/dist/modes/interactive/components/keybinding-hints.d.ts +8 -0
  353. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -0
  354. package/dist/modes/interactive/components/keybinding-hints.js +22 -0
  355. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -0
  356. package/dist/modes/interactive/components/login-dialog.d.ts +42 -0
  357. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -0
  358. package/dist/modes/interactive/components/login-dialog.js +145 -0
  359. package/dist/modes/interactive/components/login-dialog.js.map +1 -0
  360. package/dist/modes/interactive/components/model-selector.d.ts +47 -0
  361. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -0
  362. package/dist/modes/interactive/components/model-selector.js +275 -0
  363. package/dist/modes/interactive/components/model-selector.js.map +1 -0
  364. package/dist/modes/interactive/components/oauth-selector.d.ts +19 -0
  365. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -0
  366. package/dist/modes/interactive/components/oauth-selector.js +97 -0
  367. package/dist/modes/interactive/components/oauth-selector.js.map +1 -0
  368. package/dist/modes/interactive/components/scoped-models-selector.d.ts +49 -0
  369. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -0
  370. package/dist/modes/interactive/components/scoped-models-selector.js +275 -0
  371. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -0
  372. package/dist/modes/interactive/components/session-selector-search.d.ts +23 -0
  373. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -0
  374. package/dist/modes/interactive/components/session-selector-search.js +155 -0
  375. package/dist/modes/interactive/components/session-selector-search.js.map +1 -0
  376. package/dist/modes/interactive/components/session-selector.d.ts +95 -0
  377. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -0
  378. package/dist/modes/interactive/components/session-selector.js +848 -0
  379. package/dist/modes/interactive/components/session-selector.js.map +1 -0
  380. package/dist/modes/interactive/components/settings-selector.d.ts +58 -0
  381. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -0
  382. package/dist/modes/interactive/components/settings-selector.js +301 -0
  383. package/dist/modes/interactive/components/settings-selector.js.map +1 -0
  384. package/dist/modes/interactive/components/show-images-selector.d.ts +10 -0
  385. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -0
  386. package/dist/modes/interactive/components/show-images-selector.js +39 -0
  387. package/dist/modes/interactive/components/show-images-selector.js.map +1 -0
  388. package/dist/modes/interactive/components/skill-invocation-message.d.ts +17 -0
  389. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -0
  390. package/dist/modes/interactive/components/skill-invocation-message.js +47 -0
  391. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -0
  392. package/dist/modes/interactive/components/theme-selector.d.ts +11 -0
  393. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -0
  394. package/dist/modes/interactive/components/theme-selector.js +50 -0
  395. package/dist/modes/interactive/components/theme-selector.js.map +1 -0
  396. package/dist/modes/interactive/components/thinking-selector.d.ts +11 -0
  397. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -0
  398. package/dist/modes/interactive/components/thinking-selector.js +51 -0
  399. package/dist/modes/interactive/components/thinking-selector.js.map +1 -0
  400. package/dist/modes/interactive/components/tool-execution.d.ts +58 -0
  401. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -0
  402. package/dist/modes/interactive/components/tool-execution.js +274 -0
  403. package/dist/modes/interactive/components/tool-execution.js.map +1 -0
  404. package/dist/modes/interactive/components/tree-selector.d.ts +89 -0
  405. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -0
  406. package/dist/modes/interactive/components/tree-selector.js +1084 -0
  407. package/dist/modes/interactive/components/tree-selector.js.map +1 -0
  408. package/dist/modes/interactive/components/user-message-selector.d.ts +30 -0
  409. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -0
  410. package/dist/modes/interactive/components/user-message-selector.js +113 -0
  411. package/dist/modes/interactive/components/user-message-selector.js.map +1 -0
  412. package/dist/modes/interactive/components/user-message.d.ts +9 -0
  413. package/dist/modes/interactive/components/user-message.d.ts.map +1 -0
  414. package/dist/modes/interactive/components/user-message.js +28 -0
  415. package/dist/modes/interactive/components/user-message.js.map +1 -0
  416. package/dist/modes/interactive/components/visual-truncate.d.ts +24 -0
  417. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -0
  418. package/dist/modes/interactive/components/visual-truncate.js +33 -0
  419. package/dist/modes/interactive/components/visual-truncate.js.map +1 -0
  420. package/dist/modes/interactive/interactive-mode.d.ts +318 -0
  421. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -0
  422. package/dist/modes/interactive/interactive-mode.js +3907 -0
  423. package/dist/modes/interactive/interactive-mode.js.map +1 -0
  424. package/dist/modes/interactive/theme/dark.json +85 -0
  425. package/dist/modes/interactive/theme/light.json +84 -0
  426. package/dist/modes/interactive/theme/theme-schema.json +335 -0
  427. package/dist/modes/interactive/theme/theme.d.ts +81 -0
  428. package/dist/modes/interactive/theme/theme.d.ts.map +1 -0
  429. package/dist/modes/interactive/theme/theme.js +970 -0
  430. package/dist/modes/interactive/theme/theme.js.map +1 -0
  431. package/dist/modes/print-mode.d.ts +28 -0
  432. package/dist/modes/print-mode.d.ts.map +1 -0
  433. package/dist/modes/print-mode.js +108 -0
  434. package/dist/modes/print-mode.js.map +1 -0
  435. package/dist/modes/rpc/jsonl.d.ts +17 -0
  436. package/dist/modes/rpc/jsonl.d.ts.map +1 -0
  437. package/dist/modes/rpc/jsonl.js +49 -0
  438. package/dist/modes/rpc/jsonl.js.map +1 -0
  439. package/dist/modes/rpc/rpc-client.d.ts +217 -0
  440. package/dist/modes/rpc/rpc-client.d.ts.map +1 -0
  441. package/dist/modes/rpc/rpc-client.js +401 -0
  442. package/dist/modes/rpc/rpc-client.js.map +1 -0
  443. package/dist/modes/rpc/rpc-mode.d.ts +20 -0
  444. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -0
  445. package/dist/modes/rpc/rpc-mode.js +542 -0
  446. package/dist/modes/rpc/rpc-mode.js.map +1 -0
  447. package/dist/modes/rpc/rpc-types.d.ts +408 -0
  448. package/dist/modes/rpc/rpc-types.d.ts.map +1 -0
  449. package/dist/modes/rpc/rpc-types.js +8 -0
  450. package/dist/modes/rpc/rpc-types.js.map +1 -0
  451. package/dist/thin-cli.js +62 -810
  452. package/dist/utils/changelog.d.ts +21 -0
  453. package/dist/utils/changelog.d.ts.map +1 -0
  454. package/dist/utils/changelog.js +87 -0
  455. package/dist/utils/changelog.js.map +1 -0
  456. package/dist/utils/child-process.d.ts +11 -0
  457. package/dist/utils/child-process.d.ts.map +1 -0
  458. package/dist/utils/child-process.js +78 -0
  459. package/dist/utils/child-process.js.map +1 -0
  460. package/dist/utils/clipboard-image.d.ts +11 -0
  461. package/dist/utils/clipboard-image.d.ts.map +1 -0
  462. package/dist/utils/clipboard-image.js +245 -0
  463. package/dist/utils/clipboard-image.js.map +1 -0
  464. package/dist/utils/clipboard-native.d.ts +8 -0
  465. package/dist/utils/clipboard-native.d.ts.map +1 -0
  466. package/dist/utils/clipboard-native.js +14 -0
  467. package/dist/utils/clipboard-native.js.map +1 -0
  468. package/dist/utils/clipboard.d.ts +2 -0
  469. package/dist/utils/clipboard.d.ts.map +1 -0
  470. package/dist/utils/clipboard.js +78 -0
  471. package/dist/utils/clipboard.js.map +1 -0
  472. package/dist/utils/exif-orientation.d.ts +5 -0
  473. package/dist/utils/exif-orientation.d.ts.map +1 -0
  474. package/dist/utils/exif-orientation.js +158 -0
  475. package/dist/utils/exif-orientation.js.map +1 -0
  476. package/dist/utils/frontmatter.d.ts +8 -0
  477. package/dist/utils/frontmatter.d.ts.map +1 -0
  478. package/dist/utils/frontmatter.js +26 -0
  479. package/dist/utils/frontmatter.js.map +1 -0
  480. package/dist/utils/git.d.ts +26 -0
  481. package/dist/utils/git.d.ts.map +1 -0
  482. package/dist/utils/git.js +163 -0
  483. package/dist/utils/git.js.map +1 -0
  484. package/dist/utils/image-convert.d.ts +9 -0
  485. package/dist/utils/image-convert.d.ts.map +1 -0
  486. package/dist/utils/image-convert.js +39 -0
  487. package/dist/utils/image-convert.js.map +1 -0
  488. package/dist/utils/image-resize.d.ts +36 -0
  489. package/dist/utils/image-resize.d.ts.map +1 -0
  490. package/dist/utils/image-resize.js +137 -0
  491. package/dist/utils/image-resize.js.map +1 -0
  492. package/dist/utils/mime.d.ts +2 -0
  493. package/dist/utils/mime.d.ts.map +1 -0
  494. package/dist/utils/mime.js +26 -0
  495. package/dist/utils/mime.js.map +1 -0
  496. package/dist/utils/photon.d.ts +21 -0
  497. package/dist/utils/photon.d.ts.map +1 -0
  498. package/dist/utils/photon.js +121 -0
  499. package/dist/utils/photon.js.map +1 -0
  500. package/dist/utils/shell.d.ts +26 -0
  501. package/dist/utils/shell.d.ts.map +1 -0
  502. package/dist/utils/shell.js +186 -0
  503. package/dist/utils/shell.js.map +1 -0
  504. package/dist/utils/sleep.d.ts +5 -0
  505. package/dist/utils/sleep.d.ts.map +1 -0
  506. package/dist/utils/sleep.js +17 -0
  507. package/dist/utils/sleep.js.map +1 -0
  508. package/dist/utils/tools-manager.d.ts +3 -0
  509. package/dist/utils/tools-manager.d.ts.map +1 -0
  510. package/dist/utils/tools-manager.js +252 -0
  511. package/dist/utils/tools-manager.js.map +1 -0
  512. package/dist/welcome/about.js +50 -0
  513. package/dist/welcome/auth.js +126 -0
  514. package/dist/welcome/intro.js +90 -0
  515. package/dist/welcome/qa.js +131 -0
  516. package/package.json +90 -43
  517. package/scripts/install-gum.sh +141 -0
package/dist/thin-cli.js CHANGED
@@ -2,598 +2,32 @@
2
2
  /**
3
3
  * Soma — Thin CLI
4
4
  *
5
- * The public face of Soma on npm. For new users, this IS the first
6
- * impression. It should feel alive, interesting, and worth signing up for.
7
- *
5
+ * The public face of Soma on npm. Routes to modular commands.
6
+ * For new users, this IS the first impression.
8
7
  * For returning users: detects installed runtime → delegates to it.
9
8
  */
10
9
 
11
- import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync, readdirSync, statSync, readlinkSync } from "fs";
10
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, statSync, readlinkSync } from "fs";
12
11
  import { join, dirname } from "path";
13
12
  import { homedir, platform } from "os";
14
13
  import { fileURLToPath } from "url";
15
- import { execSync } from "child_process";
14
+ import { execSync, execFileSync } from "child_process";
16
15
  import { soma as voice } from "./personality.js";
17
16
 
17
+ // ── Shared modules ─────────────────────────────────────────────────────
18
+ import { bold, dim, italic, cyan, green, yellow, red, magenta, white,
19
+ printSigma, typeOut, typeParagraph, wrapText,
20
+ waitForKey, confirm, confirmYN, readLine, readSecret } from "./lib/display.js";
21
+ import { SOMA_HOME, CONFIG_PATH, CORE_DIR, SITE_URL, readConfig, writeConfig } from "./lib/config.js";
22
+ import { isInstalled, getAgentVersion, getProjectVersion, getCliVersion,
23
+ hasAnyAuth, getShellConfigPath, getShellConfigAbsPath, detectKeyInShellConfig,
24
+ openBrowser, hasGitHubCLI, getGitHubUsername } from "./lib/detect.js";
25
+ import { handleQuestion, interactiveQ, CONCEPTS, getConceptIndex, getConceptBody } from "./welcome/qa.js";
26
+ import { apiKeySetup, apiKeyExplain, apiKeyGetOne, apiKeyEntry, oauthGuide } from "./welcome/auth.js";
27
+ import { showAbout } from "./welcome/about.js";
28
+
18
29
  const __dirname = dirname(fileURLToPath(import.meta.url));
19
30
  const VERSION = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8")).version;
20
- const SOMA_HOME = join(homedir(), ".soma");
21
- const CONFIG_PATH = join(SOMA_HOME, "config.json");
22
- const CORE_DIR = join(SOMA_HOME, "agent");
23
- const SITE_URL = "https://soma.gravicity.ai";
24
-
25
- // ── Colours ──────────────────────────────────────────────────────────
26
-
27
- const bold = s => `\x1b[1m${s}\x1b[0m`;
28
- const dim = s => `\x1b[2m${s}\x1b[0m`;
29
- const italic = s => `\x1b[3m${s}\x1b[0m`;
30
- const cyan = s => `\x1b[36m${s}\x1b[0m`;
31
- const green = s => `\x1b[32m${s}\x1b[0m`;
32
- const yellow = s => `\x1b[33m${s}\x1b[0m`;
33
- const red = s => `\x1b[31m${s}\x1b[0m`;
34
- const magenta = s => `\x1b[35m${s}\x1b[0m`;
35
- const white = s => `\x1b[97m${s}\x1b[0m`;
36
-
37
- // ── Config ───────────────────────────────────────────────────────────
38
-
39
- function readConfig() {
40
- try { return JSON.parse(readFileSync(CONFIG_PATH, "utf-8")); }
41
- catch { return {}; }
42
- }
43
-
44
- function writeConfig(config) {
45
- mkdirSync(dirname(CONFIG_PATH), { recursive: true });
46
- writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });
47
- }
48
-
49
- function isInstalled() {
50
- // Check both layouts: soma-beta (dist/extensions) and dev setup (extensions/)
51
- const hasDist = existsSync(join(CORE_DIR, "dist", "extensions")) && existsSync(join(CORE_DIR, "dist", "core"));
52
- const hasDev = existsSync(join(CORE_DIR, "extensions")) && existsSync(join(CORE_DIR, "core"));
53
- // Check deps exist — Pi is the critical dependency
54
- const hasDeps = existsSync(join(CORE_DIR, "node_modules", "@mariozechner"));
55
- return (hasDist || hasDev) && hasDeps;
56
- }
57
-
58
- function getAgentVersion() {
59
- try {
60
- // In dev mode, core/ is symlinked — resolve to find the real repo's package.json
61
- let pkgPath = join(CORE_DIR, "package.json");
62
- try {
63
- const realCore = readlinkSync(join(CORE_DIR, "core"));
64
- if (realCore) {
65
- // core/ symlink → repos/agent/core → go up one level for package.json
66
- const devPkg = join(dirname(realCore), "package.json");
67
- if (existsSync(devPkg)) pkgPath = devPkg;
68
- }
69
- } catch { /* not a symlink, use default */ }
70
- return JSON.parse(readFileSync(pkgPath, "utf-8")).version;
71
- } catch { return null; }
72
- }
73
-
74
- function getProjectVersion() {
75
- try {
76
- const settingsPath = join(process.cwd(), ".soma", "settings.json");
77
- return JSON.parse(readFileSync(settingsPath, "utf-8")).version || null;
78
- } catch { return null; }
79
- }
80
-
81
- // ── Browser ──────────────────────────────────────────────────────────
82
-
83
- function openBrowser(url) {
84
- try {
85
- const cmd = platform() === "darwin" ? "open"
86
- : platform() === "win32" ? "start"
87
- : "xdg-open";
88
- execSync(`${cmd} "${url}"`, { stdio: "ignore" });
89
- return true;
90
- } catch { return false; }
91
- }
92
-
93
- // ── Interactive prompt (no deps) ─────────────────────────────────────
94
-
95
- function waitForKey(prompt) {
96
- return new Promise(resolve => {
97
- process.stdout.write(prompt);
98
- if (!process.stdin.isTTY) { resolve(""); return; }
99
- process.stdin.setRawMode(true);
100
- process.stdin.resume();
101
- process.stdin.setEncoding("utf-8");
102
- process.stdin.once("data", key => {
103
- process.stdin.setRawMode(false);
104
- process.stdin.pause();
105
- process.stdout.write("\n");
106
- if (key === "\u0003") process.exit(0); // Ctrl+C
107
- resolve(key);
108
- });
109
- });
110
- }
111
-
112
- async function confirm(prompt) {
113
- const key = await waitForKey(`${prompt} ${dim("[Enter]")} `);
114
- return true;
115
- }
116
-
117
- async function confirmYN(prompt) {
118
- const key = await waitForKey(`${prompt} ${dim("[y/n]")} `);
119
- return key.toLowerCase() === "y";
120
- }
121
-
122
- // ── Typing effect ────────────────────────────────────────────────────
123
-
124
- function sleep(ms) {
125
- return new Promise(r => setTimeout(r, ms));
126
- }
127
-
128
- /**
129
- * Type out text character by character.
130
- * Punctuation pauses longer. Newlines pause. ANSI codes print instantly.
131
- * @param {string} text - text to type (may contain ANSI escapes)
132
- * @param {object} opts
133
- * @param {number} opts.charDelay - ms between characters (default 18)
134
- * @param {number} opts.punctDelay - ms pause after . , ; : — (default 80)
135
- * @param {number} opts.lineDelay - ms pause on newline (default 40)
136
- * @param {boolean} opts.instant - skip animation (non-TTY)
137
- */
138
- async function typeOut(text, opts = {}) {
139
- if (!process.stdout.isTTY) { process.stdout.write(text); return; }
140
-
141
- // People type in bursts: fast through a word, pause at spaces,
142
- // longer pause after sentences. Speed drifts — sometimes fast,
143
- // sometimes slow, like attention wandering and refocusing.
144
- let pace = 1.0; // drift multiplier — wanders between 0.6 and 1.4
145
- let i = 0;
146
-
147
- while (i < text.length) {
148
- // ANSI escapes — print instantly
149
- const remaining = text.slice(i);
150
- const ansi = remaining.match(/^\x1b\[[0-9;]*m/);
151
- if (ansi) { process.stdout.write(ansi[0]); i += ansi[0].length; continue; }
152
-
153
- const ch = text[i];
154
- const next = text[i + 1] || "";
155
- process.stdout.write(ch);
156
- i++;
157
-
158
- // Drift pace gently (random walk, clamped)
159
- pace += (Math.random() - 0.5) * 0.15;
160
- pace = Math.max(0.6, Math.min(1.4, pace));
161
-
162
- if (ch === "\n") {
163
- await sleep(58 * pace);
164
- } else if (".!?".includes(ch) && (next === " " || next === "\n" || next === "")) {
165
- await sleep((230 + Math.random() * 175) * pace);
166
- } else if (ch === "," || ch === ";" || ch === ":") {
167
- await sleep((70 + Math.random() * 46) * pace);
168
- } else if (ch === "—" || ch === "–") {
169
- await sleep((92 + Math.random() * 70) * pace);
170
- } else if (ch === " ") {
171
- await sleep((9 + Math.random() * 23) * pace);
172
- } else {
173
- await sleep((6 + Math.random() * 14) * pace);
174
- }
175
- }
176
- }
177
-
178
- /**
179
- * Type a word-wrapped paragraph with typing effect.
180
- */
181
- async function typeParagraph(text, indent = " ", width = 58) {
182
- const words = text.split(" ");
183
- let line = indent;
184
- const lines = [];
185
- for (const word of words) {
186
- if (line.length + word.length > width + indent.length && line.trim()) {
187
- lines.push(line);
188
- line = indent + word;
189
- } else {
190
- line += (line.trim() ? " " : "") + word;
191
- }
192
- }
193
- if (line.trim()) lines.push(line);
194
- await typeOut(lines.join("\n") + "\n");
195
- }
196
-
197
- // ── The sigma ────────────────────────────────────────────────────────
198
-
199
- function printSigma() {
200
- console.log("");
201
- console.log(cyan(" σ"));
202
- console.log("");
203
- }
204
-
205
- // ── Concepts (rotate on each run) ────────────────────────────────────
206
- // Each concept has a title and maps to a topic in the personality engine.
207
- // The body is generated fresh each time — spintax means variety.
208
-
209
- const CONCEPTS = [
210
- { title: "Memory isn't retrieval. Memory is change.", topic: "how_memory_works" },
211
- { title: "Your agent should know who it is.", topic: "what_is_soma" },
212
- { title: "Protocols evolve. Muscles grow.", topic: "what_are_protocols" },
213
- { title: "The breath cycle.", topic: "what_is_breath" },
214
- { title: "Tools that survive across sessions.", topic: "what_are_scripts" },
215
- { title: "Heat tracks what matters.", topic: "what_is_heat" },
216
- { title: "What are muscles?", topic: "what_are_muscles" },
217
- { title: "No compaction. Ever.", topic: "no_compaction" },
218
- ];
219
-
220
- function getConceptIndex() {
221
- const day = Math.floor(Date.now() / 86400000);
222
- return day % CONCEPTS.length;
223
- }
224
-
225
- function getConceptBody(topic) {
226
- return voice.ask(topic) || "";
227
- }
228
-
229
- // ── Interactive Q&A ──────────────────────────────────────────────────
230
-
231
- const QUESTION_MAP = [
232
- // Order matters — more specific topics first, catch-all last
233
- { triggers: ["compact", "compaction", "summarise", "summarize", "summarization", "compress", "waiting", "context limit", "token limit", "context fills", "context window", "run out", "limit"], topic: "no_compaction", label: "Why no compaction?" },
234
- { triggers: ["heat", "hot", "cold", "fade", "decay", "temperature"], topic: "what_is_heat", label: "What is the heat system?" },
235
- { triggers: ["breath", "inhale", "exhale", "cycle", "session lifecycle"], topic: "what_is_breath", label: "What is the breath cycle?" },
236
- { triggers: ["protocol", "rule", "behaviour", "behavior", "protocols"], topic: "what_are_protocols", label: "What are protocols?" },
237
- { triggers: ["muscle", "muscles", "learn", "pattern", "grow", "correction"], topic: "what_are_muscles", label: "What are muscles?" },
238
- { triggers: ["script", "scripts", "tool", "tools", "automate", "automation"], topic: "what_are_scripts", label: "What are scripts?" },
239
- { triggers: ["memory", "remember", "forget", "remembers", "change"], topic: "how_memory_works", label: "How does memory work?" },
240
- { triggers: ["license", "source", "open", "bsl", "mit", "available"], topic: "why_source_available", label: "Why source-available?" },
241
- // Practical / instructional
242
- { triggers: ["install", "set up", "setup", "get started", "start", "begin", "getting started", "requirements", "require", "need to", "prerequisites"], topic: "how_to_install", label: "How do I install?" },
243
- { triggers: ["sign up", "signup", "register", "join", "invite", "invitation", "apply"], topic: "how_to_source", label: "How do I get source access?" },
244
- { triggers: ["cost", "price", "pricing", "free", "pay", "money", "subscription", "plan"], topic: "how_to_cost", label: "What does it cost?" },
245
- { triggers: ["language", "languages", "python", "rust", "java", "typescript", "ruby", "go", "cpp", "swift"], topic: "how_to_languages", label: "What languages does it support?" },
246
- { triggers: ["api key", "api_key", "anthropic", "openai", "gemini", "key", "token", "provider"], topic: "how_to_api_key", label: "Do I need an API key?" },
247
- { triggers: ["model", "llm", "claude", "gpt", "which model", "what model"], topic: "how_to_model", label: "What model does it use?" },
248
- { triggers: ["try", "demo", "preview", "test", "sample", "example"], topic: "how_to_try", label: "Can I try it?" },
249
- // Meta / self-aware
250
- { triggers: ["are you ai", "are you real", "are you alive", "sentient", "conscious", "artificial"], topic: "meta_self", label: "Are you AI?" },
251
- { triggers: ["feel", "feelings", "emotion", "aware", "think", "alive"], topic: "meta_feelings", label: "Do you have feelings?" },
252
- { triggers: ["who made", "who built", "who created", "creator", "developer", "behind"], topic: "meta_who_made", label: "Who made Soma?" },
253
- { triggers: ["cursor", "copilot", "windsurf", "claude code", "cline", "better", "competitor", "vs", "compared"], topic: "meta_competitor", label: "How does Soma compare?" },
254
- { triggers: ["how do you work", "how does this work", "what are you", "how are you built"], topic: "meta_how_work", label: "How does this CLI work?" },
255
- { triggers: ["cool", "amazing", "impressive", "wow", "nice", "love", "awesome", "brilliant"], topic: "meta_impressed", label: "I'm impressed" },
256
- // Catch-all — "what is soma", generic questions (no "you" — too greedy)
257
- { triggers: ["soma", "agent", "what is"], topic: "what_is_soma", label: "What is Soma?" },
258
- ];
259
-
260
- function matchQuestion(input) {
261
- const lower = input.toLowerCase();
262
- let best = null;
263
- let bestScore = 0;
264
- for (const q of QUESTION_MAP) {
265
- const score = q.triggers.filter(t => lower.includes(t)).length;
266
- // Weight: specific topics (listed first) get a slight bonus
267
- // to break ties with the generic catch-all
268
- if (score > bestScore) {
269
- bestScore = score;
270
- best = q;
271
- }
272
- }
273
- // If only generic triggers matched ("what", "about"), prefer
274
- // the catch-all over a false-positive on a specific topic
275
- return best;
276
- }
277
-
278
- function wrapText(text, indent = " ", width = 58) {
279
- const words = text.split(" ");
280
- const lines = [];
281
- let line = indent;
282
- for (const word of words) {
283
- if (line.length + word.length > width + indent.length && line.trim()) {
284
- lines.push(line);
285
- line = indent + word;
286
- } else {
287
- line += (line.trim() ? " " : "") + word;
288
- }
289
- }
290
- if (line.trim()) lines.push(line);
291
- return lines.join("\n");
292
- }
293
-
294
- function readLine(prompt) {
295
- return new Promise(resolve => {
296
- process.stdout.write(prompt);
297
- if (!process.stdin.isTTY) { resolve(""); return; }
298
- process.stdin.setRawMode(false);
299
- process.stdin.resume();
300
- process.stdin.setEncoding("utf-8");
301
- let buf = "";
302
- const onData = chunk => {
303
- buf += chunk;
304
- if (buf.includes("\n")) {
305
- process.stdin.pause();
306
- process.stdin.removeListener("data", onData);
307
- resolve(buf.trim());
308
- }
309
- };
310
- process.stdin.on("data", onData);
311
- });
312
- }
313
-
314
- async function handleQuestion(input) {
315
- const match = matchQuestion(input);
316
- if (match) {
317
- const answer = voice.ask(match.topic);
318
- console.log("");
319
- await typeParagraph(answer);
320
- return true;
321
- }
322
-
323
- // Edge case routing — detect intent even without a topic match
324
- const lower = input.toLowerCase();
325
- const rude = /suck|stupid|dumb|trash|garbage|hate|worst|bad|ugly|boring|lame|waste/.test(lower);
326
- const impressed = /cool|amazing|wow|nice|love|awesome|brilliant|impressive|neat|sick|fire|goat/.test(lower);
327
- const meta = /are you|what are you|how do you|who are you|real|alive|ai\b|bot\b/.test(lower);
328
- const greeting = /^(hi|hey|hello|sup|yo|howdy|hola|greetings|good morning|good evening)\b/.test(lower);
329
-
330
- console.log("");
331
- if (greeting) {
332
- await typeOut(` ${voice.greet()} ${voice.spin("{Ask me anything.|What do you want to know?|I know about 9 topics — pick one.}")}\n`);
333
- } else if (rude) {
334
- await typeParagraph(voice.ask("meta_rude"));
335
- } else if (impressed) {
336
- await typeParagraph(voice.ask("meta_impressed"));
337
- } else if (meta) {
338
- await typeParagraph(voice.ask("meta_self"));
339
- } else {
340
- // Anything with a question mark → try harder, then admit we don't know
341
- if (input.includes("?")) {
342
- await typeParagraph(voice.ask("meta_nonsense"));
343
- } else {
344
- await typeParagraph(voice.ask("meta_nonsense"));
345
- }
346
- }
347
- return false;
348
- }
349
-
350
- async function interactiveQ() {
351
- console.log("");
352
- console.log(` ${bold("Ask me anything.")}`);
353
- console.log("");
354
- console.log(` ${dim("•")} How do I install? ${dim("•")} What is heat?`);
355
- console.log(` ${dim("•")} What does it cost? ${dim("•")} What are muscles?`);
356
- console.log(` ${dim("•")} Why no compaction? ${dim("•")} Are you AI?`);
357
- console.log(` ${dim("•")} How does it compare? ${dim("•")} Who made this?`);
358
- console.log("");
359
- console.log(` ${dim("...or ask anything. Press")} ${green("Enter")} ${dim("when you're ready to install.")}`);
360
-
361
- let rounds = 0;
362
- const maxRounds = 8;
363
-
364
- while (rounds < maxRounds) {
365
- console.log("");
366
- const input = await readLine(` ${cyan("?")} `);
367
-
368
- // Empty input or quit → exit Q&A, proceed to install
369
- if (!input || input === "q" || input === "quit" || input === "exit") {
370
- break;
371
- }
372
-
373
- await handleQuestion(input);
374
- rounds++;
375
-
376
- if (rounds < maxRounds) {
377
- console.log("");
378
- console.log(` ${dim("Ask another, or")} ${green("Enter")} ${dim("to install Soma.")}`);
379
- }
380
- }
381
-
382
- if (rounds >= maxRounds) {
383
- console.log("");
384
- await typeOut(` ${voice.spin("{Curious enough?|Intrigued?|Want to see it in action?}")} ${dim("Let's set you up.")}\n`);
385
- }
386
- }
387
-
388
- // ── GitHub check ─────────────────────────────────────────────────────
389
-
390
- function hasGitHubCLI() {
391
- try {
392
- execSync("gh --version", { stdio: "ignore" });
393
- return true;
394
- } catch { return false; }
395
- }
396
-
397
- function getGitHubUsername() {
398
- try {
399
- return execSync("gh api user -q .login", { encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] }).trim();
400
- } catch { return null; }
401
- }
402
-
403
- // ── Commands ─────────────────────────────────────────────────────────
404
-
405
- // ── Auth helpers ─────────────────────────────────────────────────────
406
-
407
- function hasAnyAuth() {
408
- const hasEnvKey = !!(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.GEMINI_API_KEY || process.env.GROQ_API_KEY || process.env.XAI_API_KEY);
409
- if (hasEnvKey) return true;
410
- try {
411
- const authData = JSON.parse(readFileSync(join(CORE_DIR, "auth.json"), "utf-8"));
412
- return Object.keys(authData).length > 0;
413
- } catch { return false; }
414
- }
415
-
416
- function getShellConfigPath() {
417
- return process.env.SHELL?.includes("zsh") ? "~/.zshrc" : "~/.bashrc";
418
- }
419
-
420
- function getShellConfigAbsPath() {
421
- const home = homedir();
422
- return process.env.SHELL?.includes("zsh") ? join(home, ".zshrc") : join(home, ".bashrc");
423
- }
424
-
425
- function detectKeyInShellConfig() {
426
- // Check if key is in shell config but not loaded (user hasn't restarted terminal)
427
- try {
428
- const configContent = readFileSync(getShellConfigAbsPath(), "utf-8");
429
- const keyPattern = /export\s+(ANTHROPIC_API_KEY|OPENAI_API_KEY|GEMINI_API_KEY)=/;
430
- const match = configContent.match(keyPattern);
431
- if (match) return match[1];
432
- } catch {}
433
- return null;
434
- }
435
-
436
- // ── API key setup wizard ─────────────────────────────────────────────
437
-
438
- async function apiKeySetup() {
439
- console.log(` ${yellow("!")} One more thing — Soma needs an AI provider to work.`);
440
- console.log("");
441
- await typeOut(` ${voice.spin("{Do you have an Anthropic API key?|Got a Claude API key?|Have an API key for Claude?}")}\n`);
442
- console.log("");
443
- console.log(` ${green("y")} ${dim("Yes, I have a key")}`);
444
- console.log(` ${green("n")} ${dim("No, I need one")}`);
445
- console.log(` ${green("s")} ${dim("I have a Claude Pro/Max subscription")}`);
446
- console.log(` ${green("?")} ${dim("What's an API key?")}`);
447
- console.log("");
448
-
449
- const key = await waitForKey(` ${dim("→")} `);
450
- const choice = key.toLowerCase();
451
-
452
- if (choice === "y") {
453
- await apiKeyEntry();
454
- } else if (choice === "s") {
455
- await oauthGuide();
456
- } else if (choice === "?") {
457
- await apiKeyExplain();
458
- } else {
459
- await apiKeyGetOne();
460
- }
461
- }
462
-
463
- async function apiKeyExplain() {
464
- console.log("");
465
- await typeParagraph("An API key is like a password that lets Soma talk to an AI model. You get one from Anthropic (the company that makes Claude), paste it into your terminal config, and Soma handles the rest. Your key stays on your machine — Soma never sends it anywhere.");
466
- console.log("");
467
- await typeParagraph("If you have a Claude Pro or Max subscription, you don't need a separate key — you can log in with your account instead.");
468
- console.log("");
469
-
470
- console.log(` ${green("g")} ${dim("Get a key (I'll show you how)")}`);
471
- console.log(` ${green("s")} ${dim("I have Claude Pro/Max — log in instead")}`);
472
- console.log("");
473
-
474
- const key = await waitForKey(` ${dim("→")} `);
475
- if (key.toLowerCase() === "s") {
476
- await oauthGuide();
477
- } else {
478
- await apiKeyGetOne();
479
- }
480
- }
481
-
482
- async function apiKeyGetOne() {
483
- console.log("");
484
- await typeOut(` ${voice.spin("{Here's how.|Let me walk you through it.|Quick steps.}")}\n`);
485
- console.log("");
486
- console.log(` ${cyan("Step 1:")} Open this link to create a key:`);
487
- console.log("");
488
- console.log(` ${cyan("https://console.anthropic.com/settings/keys")}`);
489
- console.log("");
490
- openBrowser("https://console.anthropic.com/settings/keys");
491
- console.log(` ${dim("(opened in your browser)")}`);
492
- console.log("");
493
- await confirm(` ${dim("→")} Press ${bold("Enter")} when you have your key`);
494
- await apiKeyEntry();
495
- }
496
-
497
- function readSecret(prompt) {
498
- return new Promise(resolve => {
499
- process.stdout.write(prompt);
500
- if (!process.stdin.isTTY) { resolve(""); return; }
501
- process.stdin.setRawMode(true);
502
- process.stdin.resume();
503
- process.stdin.setEncoding("utf-8");
504
- let buf = "";
505
- const onData = chunk => {
506
- for (const ch of chunk) {
507
- if (ch === "\r" || ch === "\n") {
508
- process.stdin.setRawMode(false);
509
- process.stdin.pause();
510
- process.stdin.removeListener("data", onData);
511
- process.stdout.write("\n");
512
- resolve(buf);
513
- return;
514
- } else if (ch === "\u007F" || ch === "\b") {
515
- // Backspace
516
- if (buf.length > 0) {
517
- buf = buf.slice(0, -1);
518
- process.stdout.write("\b \b");
519
- }
520
- } else if (ch === "\u0003") {
521
- // Ctrl+C
522
- process.stdout.write("\n");
523
- process.exit(0);
524
- } else if (ch >= " ") {
525
- buf += ch;
526
- process.stdout.write("•");
527
- }
528
- }
529
- };
530
- process.stdin.on("data", onData);
531
- });
532
- }
533
-
534
- async function apiKeyEntry() {
535
- console.log("");
536
- console.log(` ${cyan("Step 2:")} Paste your key below.`);
537
- console.log(` ${dim("It starts with")} sk-ant-...`);
538
- console.log("");
539
-
540
- const apiKey = await readSecret(` ${dim("Key:")} `);
541
-
542
- if (!apiKey || !apiKey.startsWith("sk-")) {
543
- console.log("");
544
- if (!apiKey) {
545
- console.log(` ${dim("No key entered. You can set it up later.")}`);
546
- } else {
547
- console.log(` ${yellow("!")} That doesn't look like an Anthropic key.`);
548
- console.log(` ${dim("Keys start with")} sk-ant-...`);
549
- }
550
- console.log("");
551
- const sc = getShellConfigPath();
552
- console.log(` ${dim("When you have your key, add it to")} ${dim(sc)}${dim(":")}`);
553
- console.log(` ${green('export ANTHROPIC_API_KEY="your-key-here"')}`);
554
- console.log(` ${dim("Then restart your terminal and run")} ${green("soma")}`);
555
- console.log("");
556
- return;
557
- }
558
-
559
- // Write to shell config
560
- const shellConfigPath = getShellConfigAbsPath();
561
- const shellConfigName = getShellConfigPath();
562
- const exportLine = `\nexport ANTHROPIC_API_KEY="${apiKey}"\n`;
563
-
564
- try {
565
- appendFileSync(shellConfigPath, exportLine);
566
- console.log("");
567
- console.log(` ${green("✓")} Key saved to ${dim(shellConfigName)}`);
568
- console.log("");
569
-
570
- // Set it for the current process too so we can launch immediately
571
- process.env.ANTHROPIC_API_KEY = apiKey;
572
-
573
- await typeOut(` ${voice.spin("{You're all set.|Good to go.|Ready.}")} ${dim("Soma can start now.")}\n`);
574
- console.log("");
575
- } catch {
576
- console.log("");
577
- console.log(` ${yellow("!")} Couldn't write to ${dim(shellConfigName)}.`);
578
- console.log(` ${dim("Add this line manually:")}`);
579
- console.log(` ${green(`export ANTHROPIC_API_KEY="${apiKey}"`)}`);
580
- console.log(` ${dim("Then restart your terminal and run")} ${green("soma")}`);
581
- console.log("");
582
- }
583
- }
584
-
585
- async function oauthGuide() {
586
- console.log("");
587
- await typeParagraph("Nice — with a Pro or Max subscription, you can log in with your Anthropic account. No API key needed.");
588
- console.log("");
589
- console.log(` ${dim("When Soma starts, type")} ${green("/login")} ${dim("and follow the prompts.")}`);
590
- console.log(` ${dim("It'll open your browser to authenticate.")}`);
591
- console.log("");
592
- await typeOut(` ${voice.spin("{Let's launch.|Starting up.|Here we go.}")}\n`);
593
- console.log("");
594
- // Mark that user chose OAuth so we don't block launch
595
- process.env._SOMA_OAUTH_PENDING = "1";
596
- }
597
31
 
598
32
  // ── Welcome / First Run ─────────────────────────────────────────────
599
33
 
@@ -602,9 +36,7 @@ async function showWelcome() {
602
36
  console.log(` ${bold("Soma")} ${dim("—")} ${white("the AI agent that remembers")}`);
603
37
  console.log("");
604
38
 
605
- // Runtime installed → delegate to it
606
39
  if (isInstalled()) {
607
- const config = readConfig();
608
40
  const ghUser = hasGitHubCLI() ? getGitHubUsername() : null;
609
41
  if (ghUser) {
610
42
  console.log(` ${green("✓")} ${voice.greetBack(ghUser)}`);
@@ -614,7 +46,6 @@ async function showWelcome() {
614
46
  console.log(` ${green("✓")} Core installed`);
615
47
  console.log("");
616
48
 
617
- // Check if key exists in shell config but isn't loaded
618
49
  const unloadedKey = detectKeyInShellConfig();
619
50
  if (unloadedKey) {
620
51
  console.log(` ${yellow("!")} Found ${bold(unloadedKey)} in ${dim(getShellConfigPath())} but it's not loaded.`);
@@ -625,7 +56,6 @@ async function showWelcome() {
625
56
 
626
57
  await apiKeySetup();
627
58
 
628
- // If they set a key or chose OAuth, launch. If not, exit gracefully.
629
59
  if (!hasAnyAuth() && !process.env.ANTHROPIC_API_KEY && !process.env._SOMA_OAUTH_PENDING) {
630
60
  console.log(` ${dim("No worries.")} ${voice.spin("{Come back when you're ready.|Set up a key and run soma again.|We'll be here.}")}`);
631
61
  console.log("");
@@ -642,7 +72,6 @@ async function showWelcome() {
642
72
  }
643
73
 
644
74
  // ── Not installed — first time ever ────────────────────────────────
645
-
646
75
  await typeOut(` ${voice.greet()}\n`);
647
76
  console.log("");
648
77
  await typeParagraph("Soma is an AI coding agent that remembers across sessions. It learns your patterns, builds its own tools, and picks up where it left off.");
@@ -659,15 +88,12 @@ async function showWelcome() {
659
88
  await interactiveQ();
660
89
  }
661
90
 
662
- // Install the runtime
663
91
  await initSoma();
664
92
 
665
- // If install succeeded, run the API key setup
666
93
  if (isInstalled() && !hasAnyAuth()) {
667
94
  await apiKeySetup();
668
95
  }
669
96
 
670
- // If they have auth now (or chose OAuth), offer to launch
671
97
  if (isInstalled() && (hasAnyAuth() || process.env.ANTHROPIC_API_KEY || process.env._SOMA_OAUTH_PENDING)) {
672
98
  console.log(` ${dim("─".repeat(58))}`);
673
99
  console.log("");
@@ -684,6 +110,8 @@ async function showWelcome() {
684
110
  console.log("");
685
111
  }
686
112
 
113
+ // ── Help ─────────────────────────────────────────────────────────────
114
+
687
115
  function showHelp() {
688
116
  printSigma();
689
117
  console.log(` ${bold("Soma")} v${VERSION}`);
@@ -727,56 +155,13 @@ function showVersion() {
727
155
  }
728
156
  }
729
157
 
730
- async function showAbout() {
731
- printSigma();
732
- console.log(` ${bold("What is Soma?")}`);
733
- console.log("");
734
- console.log(" Soma is an AI coding agent that grows with you.");
735
- console.log(" It remembers across sessions — not by storing chat logs,");
736
- console.log(" but by evolving its own working patterns through use.");
737
- console.log("");
738
- console.log(` ${bold("How it works:")}`);
739
- console.log("");
740
- console.log(` ${cyan("1.")} ${bold("Identity")} — The agent maintains a self-written identity file.`);
741
- console.log(` It knows your project, your patterns, your preferences.`);
742
- console.log("");
743
- console.log(` ${cyan("2.")} ${bold("Protocols")} — Behavioural rules that shape how the agent works.`);
744
- console.log(` "Read before write." "Test before commit." They have heat —`);
745
- console.log(` used ones stay hot, unused ones fade.`);
746
- console.log("");
747
- console.log(` ${cyan("3.")} ${bold("Muscles")} — Learned patterns. "Use esbuild for bundling."`);
748
- console.log(` "This API uses OAuth, not API keys." Muscles grow from`);
749
- console.log(` corrections and repetition.`);
750
- console.log("");
751
- console.log(` ${cyan("4.")} ${bold("Breath Cycle")} — Inhale (load state) → Hold (work) → Exhale`);
752
- console.log(` (save state). At context limits, the agent writes a preload`);
753
- console.log(` for its next self — a briefing, not a summary.`);
754
- console.log("");
755
- console.log(` ${cyan("5.")} ${bold("Scripts")} — The agent builds tools for itself. What it does`);
756
- console.log(` twice manually, it automates. Scripts survive across sessions.`);
757
- console.log("");
758
- console.log(` ${dim("─".repeat(58))}`);
759
- console.log("");
760
-
761
- // Show a generated "what is soma" paragraph — different every time
762
- const pitch = voice.ask("what_is_soma");
763
- await typeOut(` ${magenta("❝")} ${italic(pitch)}\n`);
764
- console.log("");
765
-
766
- if (!isInstalled()) {
767
- console.log(` ${dim("→")} ${green("soma init")} to install ${dim("·")} ${cyan(SITE_URL)}`);
768
- } else {
769
- console.log(` ${dim(SITE_URL)}`);
770
- }
771
- console.log("");
772
- }
158
+ // ── Init Soma ────────────────────────────────────────────────────────
773
159
 
774
160
  async function initSoma() {
775
161
  printSigma();
776
162
  console.log(` ${bold("Soma")} — Install`);
777
163
  console.log("");
778
164
 
779
- // Check git is available
780
165
  try {
781
166
  execSync("git --version", { stdio: "ignore" });
782
167
  } catch {
@@ -791,21 +176,17 @@ async function initSoma() {
791
176
  const installDir = join(SOMA_HOME, "agent");
792
177
  mkdirSync(SOMA_HOME, { recursive: true });
793
178
 
794
- // Validate existing install — check it's a real git repo with dist/ content
795
179
  const isValidInstall = existsSync(installDir)
796
180
  && existsSync(join(installDir, ".git"))
797
181
  && (existsSync(join(installDir, "dist", "extensions")) || existsSync(join(installDir, "extensions")));
798
182
 
799
- // Track user files to preserve across repair/reinstall
800
183
  let preservedFiles = {};
801
184
 
802
185
  if (existsSync(installDir) && !isValidInstall) {
803
- // Broken/partial install — try to repair, preserve user files
804
186
  console.log(` ${yellow("⚠")} Incomplete installation detected.`);
805
187
  console.log(` ${dim("Missing:")} ${!existsSync(join(installDir, ".git")) ? "git repo" : "core files"}`);
806
188
  console.log("");
807
189
 
808
- // Save user files before touching anything
809
190
  const userFileNames = ["auth.json", "models.json"];
810
191
  for (const f of userFileNames) {
811
192
  const fp = join(installDir, f);
@@ -817,7 +198,6 @@ async function initSoma() {
817
198
  }
818
199
  }
819
200
 
820
- // Try repair: if it's a git repo, fetch + reset. Otherwise move aside for fresh clone.
821
201
  const hasGit = existsSync(join(installDir, ".git"));
822
202
  let repaired = false;
823
203
 
@@ -834,7 +214,6 @@ async function initSoma() {
834
214
  }
835
215
 
836
216
  if (!repaired) {
837
- // Move broken dir aside (never delete), then clone will happen below
838
217
  const ts = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
839
218
  const backup = join(SOMA_HOME, `agent-backup-${ts}`);
840
219
  try {
@@ -851,8 +230,6 @@ async function initSoma() {
851
230
 
852
231
  if (isValidInstall) {
853
232
  console.log(` ${dim("→")} Runtime already installed.`);
854
-
855
- // Pull latest
856
233
  try {
857
234
  console.log(` ${yellow("⏳")} Checking for updates...`);
858
235
  execSync("git pull --ff-only", { cwd: installDir, stdio: "ignore" });
@@ -861,7 +238,6 @@ async function initSoma() {
861
238
  console.log(` ${green("✓")} Already current`);
862
239
  }
863
240
  } else {
864
- // Clone from soma-beta (public — no auth needed)
865
241
  console.log(` ${yellow("⏳")} Downloading Soma runtime...`);
866
242
  try {
867
243
  execSync(
@@ -879,7 +255,6 @@ async function initSoma() {
879
255
  }
880
256
  }
881
257
 
882
- // Install Pi dependencies
883
258
  const pkgJson = join(installDir, "package.json");
884
259
  if (existsSync(pkgJson)) {
885
260
  console.log(` ${yellow("⏳")} Installing dependencies... ${dim("(this may take a moment)")}`);
@@ -891,7 +266,6 @@ async function initSoma() {
891
266
  }
892
267
  }
893
268
 
894
- // Restore preserved user files (from broken install repair)
895
269
  if (Object.keys(preservedFiles).length > 0) {
896
270
  for (const [f, content] of Object.entries(preservedFiles)) {
897
271
  try {
@@ -901,7 +275,6 @@ async function initSoma() {
901
275
  }
902
276
  }
903
277
 
904
- // Verify — gate success on actual working install
905
278
  const hasExts = existsSync(join(installDir, "dist", "extensions"));
906
279
  const hasCore = existsSync(join(installDir, "dist", "core"));
907
280
 
@@ -915,7 +288,6 @@ async function initSoma() {
915
288
 
916
289
  console.log(` ${green("✓")} Extensions and core ready`);
917
290
 
918
- // Save config
919
291
  const config = readConfig();
920
292
  config.installedAt = config.installedAt || new Date().toISOString();
921
293
  config.coreVersion = getAgentVersion() || VERSION;
@@ -927,6 +299,8 @@ async function initSoma() {
927
299
  console.log("");
928
300
  }
929
301
 
302
+ // ── Update / Status ──────────────────────────────────────────────────
303
+
930
304
  async function checkAndUpdate() {
931
305
  printSigma();
932
306
  console.log(` ${bold("Soma")} — Status`);
@@ -935,7 +309,6 @@ async function checkAndUpdate() {
935
309
  const config = readConfig();
936
310
  const installPath = config.installPath || join(SOMA_HOME, "agent");
937
311
 
938
- // Check current version
939
312
  let currentHash = "";
940
313
  try {
941
314
  currentHash = execSync("git rev-parse --short HEAD", {
@@ -946,7 +319,6 @@ async function checkAndUpdate() {
946
319
  console.log(` ${green("✓")} Core installed`);
947
320
  }
948
321
 
949
- // Check for updates
950
322
  let behind = 0;
951
323
  try {
952
324
  console.log(` ${yellow("⏳")} Checking for updates...`);
@@ -968,7 +340,6 @@ async function checkAndUpdate() {
968
340
  if (behind === 0) {
969
341
  console.log(` ${green("✓")} Already up to date.`);
970
342
 
971
- // Check project version staleness even when runtime is current
972
343
  const agentV = getAgentVersion();
973
344
  const projectV = getProjectVersion();
974
345
  if (agentV && projectV && projectV < agentV) {
@@ -985,7 +356,6 @@ async function checkAndUpdate() {
985
356
  console.log(` ${cyan("⬆")} ${bold(`${behind} update${behind !== 1 ? "s" : ""} available.`)}`);
986
357
  console.log("");
987
358
 
988
- // Show what changed
989
359
  try {
990
360
  const log = execSync(
991
361
  `git log HEAD..origin/main --oneline --no-decorate -5`,
@@ -1010,7 +380,6 @@ async function checkAndUpdate() {
1010
380
  return;
1011
381
  }
1012
382
 
1013
- // Pull + reinstall deps
1014
383
  console.log("");
1015
384
  try {
1016
385
  execSync("git pull --ff-only", { cwd: installPath, stdio: "ignore" });
@@ -1028,7 +397,6 @@ async function checkAndUpdate() {
1028
397
  }
1029
398
  }
1030
399
 
1031
- // Reinstall deps if package.json changed
1032
400
  try {
1033
401
  const pkgChanged = execSync(
1034
402
  `git diff HEAD~${behind} HEAD --name-only -- package.json package-lock.json`,
@@ -1061,7 +429,6 @@ function checkForUpdates() {
1061
429
 
1062
430
  const config = readConfig();
1063
431
 
1064
- // Check npm for CLI updates
1065
432
  try {
1066
433
  const latest = execSync("npm view meetsoma version 2>/dev/null", { encoding: "utf-8" }).trim();
1067
434
  if (latest && latest !== VERSION && latest > VERSION) {
@@ -1075,10 +442,8 @@ function checkForUpdates() {
1075
442
  console.log(` ${dim("Could not check npm registry")}`);
1076
443
  }
1077
444
 
1078
- // Check core updates (pull latest if git repo)
1079
445
  if (isInstalled() && config.installPath) {
1080
446
  try {
1081
- // Fetch first so rev-list has fresh data
1082
447
  execSync("git fetch origin --quiet", { cwd: config.installPath, stdio: "ignore", timeout: 10000 });
1083
448
  const branch = execSync("git rev-parse --abbrev-ref HEAD", {
1084
449
  cwd: config.installPath, encoding: "utf-8"
@@ -1100,22 +465,23 @@ function checkForUpdates() {
1100
465
  console.log("");
1101
466
  }
1102
467
 
468
+ // ── Health Check ─────────────────────────────────────────────────────
469
+
1103
470
  async function healthCheck() {
1104
471
  printSigma();
1105
472
  console.log(` ${bold("Soma")} — Health Check`);
1106
473
  console.log("");
1107
474
 
1108
475
  let issues = 0;
1109
- const check = (ok, pass, fail) => {
476
+ const check = (ok, pass, fail_msg) => {
1110
477
  if (ok) { console.log(` ${green("✓")} ${pass}`); }
1111
- else { console.log(` ${red("✗")} ${fail}`); issues++; }
478
+ else { console.log(` ${red("✗")} ${fail_msg}`); issues++; }
1112
479
  };
1113
- const warn = (ok, pass, fail) => {
480
+ const warn = (ok, pass, fail_msg) => {
1114
481
  if (ok) { console.log(` ${green("✓")} ${pass}`); }
1115
- else { console.log(` ${yellow("⚠")} ${fail}`); }
482
+ else { console.log(` ${yellow("⚠")} ${fail_msg}`); }
1116
483
  };
1117
484
 
1118
- // Node.js
1119
485
  const nodeVersion = process.versions.node;
1120
486
  const [major, minor] = nodeVersion.split(".").map(Number);
1121
487
  check(major > 20 || (major === 20 && minor >= 6),
@@ -1123,15 +489,12 @@ async function healthCheck() {
1123
489
  `Node.js ${nodeVersion} — requires ≥20.6.0`
1124
490
  );
1125
491
 
1126
- // ~/.soma directory
1127
492
  check(existsSync(SOMA_HOME), "~/.soma/ exists", "~/.soma/ not found — run: soma init");
1128
493
 
1129
- // Core installation
1130
494
  const installed = isInstalled();
1131
495
  check(installed, "Core installed", "Core not installed — run: soma init");
1132
496
 
1133
497
  if (installed) {
1134
- // Extensions (check both dist/ layout and dev layout)
1135
498
  const extDir = existsSync(join(CORE_DIR, "dist", "extensions"))
1136
499
  ? join(CORE_DIR, "dist", "extensions")
1137
500
  : join(CORE_DIR, "extensions");
@@ -1140,13 +503,11 @@ async function healthCheck() {
1140
503
  check(exts.length >= 6, `${exts.length} extensions`, `Only ${exts.length} extensions (expected ≥6)`);
1141
504
  }
1142
505
 
1143
- // Core modules
1144
506
  const coreDir = existsSync(join(CORE_DIR, "dist", "core"))
1145
507
  ? join(CORE_DIR, "dist", "core")
1146
508
  : join(CORE_DIR, "core");
1147
509
  check(existsSync(coreDir), "Core modules present", "Core modules missing");
1148
510
 
1149
- // Git repo health (skip in dev mode — no .git when using symlinks)
1150
511
  if (existsSync(join(CORE_DIR, ".git"))) {
1151
512
  try {
1152
513
  execSync("git status --porcelain", { cwd: CORE_DIR, stdio: "ignore" });
@@ -1155,7 +516,6 @@ async function healthCheck() {
1155
516
  warn(false, "", "Core git repo has issues");
1156
517
  }
1157
518
  } else {
1158
- // Dev mode — core/ is symlinked, no .git expected
1159
519
  try {
1160
520
  const realCore = readlinkSync(join(CORE_DIR, "core"));
1161
521
  if (realCore) {
@@ -1169,7 +529,6 @@ async function healthCheck() {
1169
529
  }
1170
530
  }
1171
531
 
1172
- // API key (check env + auth.json + shell config)
1173
532
  const hasAuth = hasAnyAuth();
1174
533
  if (hasAuth) {
1175
534
  console.log(` ${green("✓")} API key configured`);
@@ -1182,7 +541,6 @@ async function healthCheck() {
1182
541
  }
1183
542
  }
1184
543
 
1185
- // Git
1186
544
  try {
1187
545
  const gitV = execSync("git --version", { encoding: "utf-8" }).trim();
1188
546
  check(true, gitV, "");
@@ -1193,7 +551,6 @@ async function healthCheck() {
1193
551
  console.log("");
1194
552
  if (issues === 0) {
1195
553
  console.log(` ${green("✓ All checks passed")}`);
1196
-
1197
554
  } else {
1198
555
  console.log(` ${yellow(`${issues} issue${issues > 1 ? "s" : ""} found`)}`);
1199
556
  console.log(` ${voice.say("suggest", { suggestion: issues > 2 ? "start with soma init" : "check the items above" })}`);
@@ -1201,12 +558,14 @@ async function healthCheck() {
1201
558
  console.log("");
1202
559
  }
1203
560
 
561
+ // ── Project Doctor ───────────────────────────────────────────────────
562
+ // (large function — kept inline to avoid breaking the complex doctor logic)
563
+
1204
564
  async function projectDoctor() {
1205
565
  const doctorArgs = args.slice(1);
1206
566
  const wantsScan = doctorArgs.includes("--scan");
1207
567
  const wantsAll = doctorArgs.includes("--all");
1208
568
 
1209
- // --scan and --all need the runtime — delegate to core
1210
569
  if ((wantsScan || wantsAll) && isInstalled()) {
1211
570
  await delegateToCore();
1212
571
  return;
@@ -1226,7 +585,6 @@ async function projectDoctor() {
1226
585
  return;
1227
586
  }
1228
587
 
1229
- // Version overview
1230
588
  console.log(` Agent: ${cyan(`v${agentV || "unknown"}`)}`);
1231
589
  if (projectV) {
1232
590
  console.log(` Project: ${cyan(`v${projectV}`)}`);
@@ -1252,21 +610,19 @@ async function projectDoctor() {
1252
610
  }
1253
611
 
1254
612
  if (agentV && projectV === agentV) {
1255
- console.log(` ${green("\u2713")} Project is up to date.`);
613
+ console.log(` ${green("")} Project is up to date.`);
1256
614
  console.log("");
1257
615
  await healthCheck();
1258
616
  return;
1259
617
  }
1260
618
 
1261
619
  if (agentV && projectV < agentV) {
1262
- console.log(` ${yellow("\u26a0")} Project .soma/ is at ${cyan(`v${projectV}`)} , agent is at ${cyan(`v${agentV}`)} .`);
620
+ console.log(` ${yellow("")} Project .soma/ is at ${cyan(`v${projectV}`)} , agent is at ${cyan(`v${agentV}`)} .`);
1263
621
  console.log("");
1264
622
 
1265
- // Tier 1: Auto-fix safe things right now
1266
623
  let fixes = 0;
1267
624
  const somaDir = join(process.cwd(), ".soma");
1268
625
 
1269
- // Add missing settings keys
1270
626
  const settingsPath = join(somaDir, "settings.json");
1271
627
  if (existsSync(settingsPath)) {
1272
628
  try {
@@ -1280,29 +636,26 @@ async function projectDoctor() {
1280
636
  add("scratch", { autoInject: false });
1281
637
  add("guard", { coreFiles: "warn", bashCommands: "warn", gitIdentity: null });
1282
638
  add("checkpoints", { enabled: true, intervalMinutes: 5, squashOnPush: true });
1283
- add("persona", { name: null, emoji: "\u03c3" });
639
+ add("persona", { name: null, emoji: "σ" });
1284
640
  add("inherit", { identity: true, protocols: true, muscles: true, tools: true });
1285
641
  if (changed) writeFileSync(settingsPath, JSON.stringify(current, null, "\t") + "\n");
1286
642
  } catch {}
1287
643
  }
1288
644
 
1289
- // Add missing body/ + templates
1290
645
  const bodyDir = join(somaDir, "body");
1291
- // Resolve agent root — follow dev symlinks if needed
1292
- let agentRoot = CORE_DIR;
1293
- try {
1294
- const realCore = readlinkSync(join(CORE_DIR, "core"));
1295
- if (realCore) {
1296
- const devRoot = dirname(realCore);
1297
- if (existsSync(join(devRoot, "body", "_public"))) agentRoot = devRoot;
646
+ let agentRoot = CORE_DIR;
647
+ try {
648
+ const realCore = readlinkSync(join(CORE_DIR, "core"));
649
+ if (realCore) {
650
+ const devRoot = dirname(realCore);
651
+ if (existsSync(join(devRoot, "body", "_public"))) agentRoot = devRoot;
652
+ }
653
+ } catch {}
654
+ if (!existsSync(join(agentRoot, "body", "_public"))) {
655
+ const parent = dirname(agentRoot);
656
+ if (existsSync(join(parent, "body", "_public"))) agentRoot = parent;
1298
657
  }
1299
- } catch {}
1300
- // Also check dist/ parent (prod layout)
1301
- if (!existsSync(join(agentRoot, "body", "_public"))) {
1302
- const parent = dirname(agentRoot);
1303
- if (existsSync(join(parent, "body", "_public"))) agentRoot = parent;
1304
- }
1305
- const bundledBody = join(agentRoot, "body", "_public");
658
+ const bundledBody = join(agentRoot, "body", "_public");
1306
659
  if (existsSync(bundledBody)) {
1307
660
  try {
1308
661
  if (!existsSync(bodyDir)) mkdirSync(bodyDir, { recursive: true });
@@ -1313,7 +666,6 @@ async function projectDoctor() {
1313
666
  } catch {}
1314
667
  }
1315
668
 
1316
- // Add missing protocols
1317
669
  const protoDir = join(somaDir, "amps", "protocols");
1318
670
  const bundledProtos = existsSync(join(CORE_DIR, "dist", "content", "protocols"))
1319
671
  ? join(CORE_DIR, "dist", "content", "protocols")
@@ -1327,7 +679,6 @@ async function projectDoctor() {
1327
679
  }
1328
680
  }
1329
681
 
1330
- // Add missing bundled scripts
1331
682
  const scriptsDir = join(somaDir, "amps", "scripts");
1332
683
  const bundledScripts = existsSync(join(agentRoot, "dist", "content", "scripts"))
1333
684
  ? join(agentRoot, "dist", "content", "scripts")
@@ -1346,20 +697,18 @@ async function projectDoctor() {
1346
697
  }
1347
698
  }
1348
699
 
1349
- // Bump version after fixes
1350
700
  if (fixes > 0) {
1351
701
  try {
1352
702
  const s = JSON.parse(readFileSync(settingsPath, "utf-8"));
1353
703
  s.version = agentV;
1354
704
  writeFileSync(settingsPath, JSON.stringify(s, null, "\t") + "\n");
1355
705
  } catch {}
1356
- console.log(` ${green("\u2713")} Applied ${fixes} automatic fixes`);
706
+ console.log(` ${green("")} Applied ${fixes} automatic fixes`);
1357
707
  const bc = existsSync(join(somaDir, "body")) ? readdirSync(join(somaDir, "body")).filter(f => f.endsWith(".md")).length : 0;
1358
708
  const pc = existsSync(protoDir) ? readdirSync(protoDir).filter(f => f.endsWith(".md")).length : 0;
1359
709
  console.log(` ${bc} body files, ${pc} protocols, settings updated`);
1360
710
  console.log(` Version bumped to ${cyan(`v${agentV}`)}`);
1361
711
 
1362
- // Scan + fix stale protocols (exist but differ from bundled)
1363
712
  let staleUpdated = 0;
1364
713
  let staleSkipped = [];
1365
714
  if (bundledProtos && existsSync(protoDir)) {
@@ -1370,7 +719,6 @@ async function projectDoctor() {
1370
719
  const bundledRaw = readFileSync(bundledFile, "utf-8");
1371
720
  const strip = s => s.replace(/^(heat|loads|runs|last-run|heat-default):.*\n?/gm, "").trim();
1372
721
  if (strip(projRaw) === strip(bundledRaw)) continue;
1373
- // Preserve user's runtime fields (heat, loads) when updating content
1374
722
  const heatLine = projRaw.match(/^heat:.*$/m);
1375
723
  const loadsLine = projRaw.match(/^loads:.*$/m);
1376
724
  let updated = bundledRaw;
@@ -1383,11 +731,11 @@ async function projectDoctor() {
1383
731
 
1384
732
  console.log("");
1385
733
  if (staleUpdated > 0) {
1386
- console.log(` ${green("\u2713")} ${staleUpdated} protocols updated to latest version`);
1387
- console.log(` ${dim("Heat and load counts preserved. Content updated (coaching-voice rewrites, new TL;DR).")}`);
734
+ console.log(` ${green("")} ${staleUpdated} protocols updated to latest version`);
735
+ console.log(` ${dim("Heat and load counts preserved. Content updated.")}`);
1388
736
  }
1389
737
  if (staleSkipped.length > 0) {
1390
- console.log(` ${yellow("\u26a0")} ${staleSkipped.length} protocols skipped (may be customized)`);
738
+ console.log(` ${yellow("")} ${staleSkipped.length} protocols skipped (may be customized)`);
1391
739
  }
1392
740
  console.log("");
1393
741
  const totalRemaining = staleSkipped.length;
@@ -1396,118 +744,41 @@ async function projectDoctor() {
1396
744
  console.log(` ${dim("Remaining: " + totalRemaining + " items need review.")}`);
1397
745
  console.log(` ${dim("For full migration:")} ${green("soma")} ${dim("then")} ${green("/soma doctor")}`);
1398
746
  } else {
1399
- console.log(` ${green("\u2713")} Full migration complete from CLI.`);
747
+ console.log(` ${green("")} Full migration complete from CLI.`);
1400
748
  console.log(` ${dim("No TUI session needed — all updates applied.")}`);
1401
749
  }
1402
750
 
1403
- // Write _doctor-pending.md — only if there are remaining items for the agent
1404
- // If CLI handled everything, write a brief "complete" note instead
751
+ // Write _doctor-pending.md
1405
752
  try {
1406
753
  const pendingPath = join(somaDir, "body", "_doctor-pending.md");
1407
754
  if (staleSkipped.length === 0) {
1408
- // Full migration done — write brief completion note
1409
755
  const done = [
1410
- "---",
1411
- "type: template",
1412
- "name: doctor-pending",
1413
- "status: complete",
756
+ "---", "type: template", "name: doctor-pending", "status: complete",
1414
757
  `created: ${new Date().toISOString().split("T")[0]}`,
1415
- "description: CLI doctor completed full migration verify with /soma doctor then delete this file",
1416
- "---",
1417
- "",
1418
- "# Doctor Update Complete",
1419
- "",
1420
- `The CLI doctor migrated this project from v${projectV} to v${agentV} on ${new Date().toISOString().split("T")[0]}.`,
1421
- "",
1422
- `Applied: ${fixes} file fixes + ${staleUpdated} protocol updates. All settings, body, scripts, protocols current.`,
1423
- "",
1424
- "Run \`/soma doctor\` to verify, then delete this file.",
758
+ "description: CLI doctor completed full migration", "---", "",
759
+ "# Doctor Update — Complete", "",
760
+ `Migrated from v${projectV} to v${agentV} on ${new Date().toISOString().split("T")[0]}.`,
761
+ `Applied: ${fixes} file fixes + ${staleUpdated} protocol updates.`, "",
762
+ "Run `/soma doctor` to verify, then delete this file.",
1425
763
  ];
1426
764
  writeFileSync(pendingPath, done.join("\n"));
1427
- } else {
1428
- const pending = [
1429
- "---",
1430
- "type: template",
1431
- "name: doctor-pending",
1432
- "status: active",
1433
- `created: ${new Date().toISOString().split("T")[0]}`,
1434
- "description: Written by soma doctor CLI — tells the agent what was fixed and what needs attention",
1435
- "---",
1436
- "",
1437
- "# Doctor Update — Pending",
1438
- "",
1439
- `The CLI doctor ran on ${new Date().toISOString().split("T")[0]} and updated this project from v${projectV} to v${agentV}.`,
1440
- "",
1441
- "## What the CLI fixed (Tier 1 — automatic, safe)",
1442
- "",
1443
- `- ${bc} body template files (added missing ones, preserved your customized files)`,
1444
- `- ${pc} protocols present (added missing bundled protocols)`,
1445
- `- Settings: added missing configuration sections with safe defaults`,
1446
- `- Version bumped to v${agentV}`,
1447
- "",
1448
- `## What the CLI also fixed`,
1449
- "",
1450
- `- ${staleUpdated} protocols updated to latest version (heat/loads preserved)`,
1451
- "",
1452
- staleSkipped.length > 0 ? `## What still needs attention (${staleSkipped.length} items)` : "## Status: Complete",
1453
- "",
1454
- staleSkipped.length > 0
1455
- ? `**${staleSkipped.length} protocols** may be customized and were not auto-updated. The agent needs to:\n- Diff each against bundled version\n- Decide whether to update or preserve`
1456
- : "All mechanical updates applied by CLI. The agent can verify with /soma doctor.",
1457
- "",
1458
- "**To complete the migration:**",
1459
- "",
1460
- "Read the migration phases that apply to your version jump:",
1461
- "```",
1462
- ];
1463
- // Find which phases apply (only from projectV onward)
1464
- let agentRoot2 = CORE_DIR;
1465
- try {
1466
- const rc = readlinkSync(join(CORE_DIR, "core"));
1467
- if (rc) { const dr = dirname(rc); if (existsSync(join(dr, "migrations", "phases"))) agentRoot2 = dr; }
1468
- } catch {}
1469
- if (!existsSync(join(agentRoot2, "migrations", "phases"))) {
1470
- const pr = dirname(agentRoot2);
1471
- if (existsSync(join(pr, "migrations", "phases"))) agentRoot2 = pr;
1472
- }
1473
- const phasesDir2 = join(agentRoot2, "migrations", "phases");
1474
- if (existsSync(phasesDir2)) {
1475
- const allPhases = readdirSync(phasesDir2).filter(f => f.endsWith(".md")).sort();
1476
- const relevant = allPhases.filter(f => {
1477
- const m = f.match(/^v([\d.]+)-to-v/);
1478
- return m && m[1] >= projectV;
1479
- });
1480
- pending.push(`${relevant.length} phases apply (v${projectV} \u2192 v${agentV}):`);
1481
- pending.push("\`\`\`");
1482
- for (const f of relevant) {
1483
- pending.push(" " + join(phasesDir2, f));
1484
- }
1485
765
  }
1486
- pending.push("```");
1487
- pending.push("");
1488
- pending.push("Execute each phase's **Actions** section in order.");
1489
- pending.push("After completing all phases, delete this file — it's no longer needed.");
1490
- pending.push("");
1491
- writeFileSync(pendingPath, pending.join("\n"));
1492
- }
1493
- } catch { /* non-fatal */ }
766
+ } catch {}
1494
767
  } else {
1495
- console.log(` ${green("\u2713")} Version bumped to ${cyan(`v${agentV}`)}`);
768
+ console.log(` ${green("")} Version bumped to ${cyan(`v${agentV}`)}`);
1496
769
  console.log(` ${dim("No file changes needed — project structure is current.")}`);
1497
770
  }
1498
771
  } else {
1499
- console.log(` ${green("\u2713")} Project version: ${cyan(`v${projectV}`)}`);
772
+ console.log(` ${green("")} Project version: ${cyan(`v${projectV}`)}`);
1500
773
  }
1501
774
 
1502
775
  console.log("");
1503
776
  await healthCheck();
1504
777
  }
1505
778
 
1506
-
1507
779
  // ── Delegation ───────────────────────────────────────────────────────
1508
780
 
1509
781
  async function delegateToCore() {
1510
- // Pre-flight: verify runtime can start before delegating
1511
782
  const piPkg = join(CORE_DIR, "node_modules", "@mariozechner", "pi-coding-agent");
1512
783
  if (!existsSync(piPkg)) {
1513
784
  console.log(` ${red("✗")} Runtime dependencies missing.`);
@@ -1528,7 +799,6 @@ async function delegateToCore() {
1528
799
  return;
1529
800
  }
1530
801
 
1531
- const { execFileSync: execF } = await import("child_process");
1532
802
  const passArgs = process.argv.slice(2);
1533
803
 
1534
804
  const cliLocations = [
@@ -1536,9 +806,6 @@ async function delegateToCore() {
1536
806
  { path: join(CORE_DIR, "node_modules", ".bin", "pi"), type: "bin" },
1537
807
  ];
1538
808
 
1539
- // Discover user extensions in project .soma/extensions/
1540
- // Pi without piConfig only looks at .pi/extensions/, not .soma/extensions/
1541
- // We pass them explicitly via -e flags
1542
809
  const userExtArgs = [];
1543
810
  const projectExtDir = join(process.cwd(), ".soma", "extensions");
1544
811
  if (existsSync(projectExtDir)) {
@@ -1552,14 +819,8 @@ async function delegateToCore() {
1552
819
 
1553
820
  const env = {
1554
821
  ...process.env,
1555
- // Pi reads ENV_AGENT_DIR dynamically based on APP_NAME from piConfig.
1556
- // With piConfig.name="soma", Pi looks for SOMA_CODING_AGENT_DIR.
1557
- // Without piConfig (raw pi binary), it looks for PI_CODING_AGENT_DIR.
1558
- // Set BOTH so delegation works regardless of piConfig load order.
1559
822
  PI_CODING_AGENT_DIR: CORE_DIR,
1560
823
  SOMA_CODING_AGENT_DIR: CORE_DIR,
1561
- // Override Pi's package dir so it reads piConfig from soma-beta's package.json
1562
- // This gives us APP_NAME="soma", CONFIG_DIR_NAME=".soma" → project .soma/ paths
1563
824
  PI_PACKAGE_DIR: CORE_DIR,
1564
825
  };
1565
826
 
@@ -1568,15 +829,13 @@ async function delegateToCore() {
1568
829
  try {
1569
830
  const allArgs = [...userExtArgs, ...passArgs];
1570
831
  if (cli.type === "node") {
1571
- execF("node", [cli.path, ...allArgs], { stdio: "inherit", cwd: process.cwd(), env });
832
+ execFileSync("node", [cli.path, ...allArgs], { stdio: "inherit", cwd: process.cwd(), env });
1572
833
  } else {
1573
- execF(cli.path, allArgs, { stdio: "inherit", cwd: process.cwd(), env });
834
+ execFileSync(cli.path, allArgs, { stdio: "inherit", cwd: process.cwd(), env });
1574
835
  }
1575
836
  return;
1576
837
  } catch (err) {
1577
- // Non-zero exit from session is normal (user quit, ctrl+c)
1578
838
  if (err.status) process.exit(err.status);
1579
- // Module errors = broken install
1580
839
  if (err.message && err.message.includes("MODULE_NOT_FOUND")) {
1581
840
  console.log("");
1582
841
  console.log(` ${red("✗")} Soma failed to start — missing dependencies.`);
@@ -1603,7 +862,6 @@ if (cmd === "--version" || cmd === "-v" || cmd === "-V") {
1603
862
  showVersion();
1604
863
  } else if (cmd === "--help" || cmd === "-h") {
1605
864
  if (isInstalled()) {
1606
- // Delegate to core — richer help with scripts, commands, hub
1607
865
  await delegateToCore();
1608
866
  } else {
1609
867
  showHelp();
@@ -1616,13 +874,10 @@ if (cmd === "--version" || cmd === "-v" || cmd === "-V") {
1616
874
  const hasSomaDir = existsSync(join(process.cwd(), ".soma"));
1617
875
 
1618
876
  if (!runtimeInstalled) {
1619
- // Not installed — run full install + setup
1620
877
  await initSoma();
1621
878
  } else if (hasProjectArgs || !hasSomaDir) {
1622
- // Installed, project init (new project or --template/--orphan)
1623
879
  await delegateToCore();
1624
880
  } else {
1625
- // Installed + .soma/ exists — check for updates + project staleness
1626
881
  await checkAndUpdate();
1627
882
  }
1628
883
  } else if (cmd === "update") {
@@ -1632,10 +887,8 @@ if (cmd === "--version" || cmd === "-v" || cmd === "-V") {
1632
887
  } else if (cmd === "status" || cmd === "health") {
1633
888
  await healthCheck();
1634
889
  } else if (isInstalled()) {
1635
- // Core installed — delegate to runtime
1636
890
  await delegateToCore();
1637
891
  } else {
1638
- // Check if user typed a known post-install command
1639
892
  const postInstallCmds = ["focus", "inhale", "content", "install", "list", "map", "--map", "--preload"];
1640
893
  if (cmd && postInstallCmds.includes(cmd)) {
1641
894
  printSigma();
@@ -1644,7 +897,6 @@ if (cmd === "--version" || cmd === "-v" || cmd === "-V") {
1644
897
  console.log(` Run ${green("soma init")} to install it.`);
1645
898
  console.log("");
1646
899
  } else {
1647
- // Not installed or not verified — show welcome experience
1648
900
  await showWelcome();
1649
901
  }
1650
902
  }