meetsoma 0.2.0 → 0.3.2

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 +25 -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 +67 -812
  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,24 @@ 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
+ let warnings = 0;
477
+ const check = (ok, pass, fail_msg) => {
1110
478
  if (ok) { console.log(` ${green("✓")} ${pass}`); }
1111
- else { console.log(` ${red("✗")} ${fail}`); issues++; }
479
+ else { console.log(` ${red("✗")} ${fail_msg}`); issues++; }
1112
480
  };
1113
- const warn = (ok, pass, fail) => {
481
+ const warn = (ok, pass, fail_msg) => {
1114
482
  if (ok) { console.log(` ${green("✓")} ${pass}`); }
1115
- else { console.log(` ${yellow("⚠")} ${fail}`); }
483
+ else { console.log(` ${yellow("⚠")} ${fail_msg}`); warnings++; }
1116
484
  };
1117
485
 
1118
- // Node.js
1119
486
  const nodeVersion = process.versions.node;
1120
487
  const [major, minor] = nodeVersion.split(".").map(Number);
1121
488
  check(major > 20 || (major === 20 && minor >= 6),
@@ -1123,15 +490,12 @@ async function healthCheck() {
1123
490
  `Node.js ${nodeVersion} — requires ≥20.6.0`
1124
491
  );
1125
492
 
1126
- // ~/.soma directory
1127
493
  check(existsSync(SOMA_HOME), "~/.soma/ exists", "~/.soma/ not found — run: soma init");
1128
494
 
1129
- // Core installation
1130
495
  const installed = isInstalled();
1131
496
  check(installed, "Core installed", "Core not installed — run: soma init");
1132
497
 
1133
498
  if (installed) {
1134
- // Extensions (check both dist/ layout and dev layout)
1135
499
  const extDir = existsSync(join(CORE_DIR, "dist", "extensions"))
1136
500
  ? join(CORE_DIR, "dist", "extensions")
1137
501
  : join(CORE_DIR, "extensions");
@@ -1140,13 +504,11 @@ async function healthCheck() {
1140
504
  check(exts.length >= 6, `${exts.length} extensions`, `Only ${exts.length} extensions (expected ≥6)`);
1141
505
  }
1142
506
 
1143
- // Core modules
1144
507
  const coreDir = existsSync(join(CORE_DIR, "dist", "core"))
1145
508
  ? join(CORE_DIR, "dist", "core")
1146
509
  : join(CORE_DIR, "core");
1147
510
  check(existsSync(coreDir), "Core modules present", "Core modules missing");
1148
511
 
1149
- // Git repo health (skip in dev mode — no .git when using symlinks)
1150
512
  if (existsSync(join(CORE_DIR, ".git"))) {
1151
513
  try {
1152
514
  execSync("git status --porcelain", { cwd: CORE_DIR, stdio: "ignore" });
@@ -1155,7 +517,6 @@ async function healthCheck() {
1155
517
  warn(false, "", "Core git repo has issues");
1156
518
  }
1157
519
  } else {
1158
- // Dev mode — core/ is symlinked, no .git expected
1159
520
  try {
1160
521
  const realCore = readlinkSync(join(CORE_DIR, "core"));
1161
522
  if (realCore) {
@@ -1169,7 +530,6 @@ async function healthCheck() {
1169
530
  }
1170
531
  }
1171
532
 
1172
- // API key (check env + auth.json + shell config)
1173
533
  const hasAuth = hasAnyAuth();
1174
534
  if (hasAuth) {
1175
535
  console.log(` ${green("✓")} API key configured`);
@@ -1182,7 +542,6 @@ async function healthCheck() {
1182
542
  }
1183
543
  }
1184
544
 
1185
- // Git
1186
545
  try {
1187
546
  const gitV = execSync("git --version", { encoding: "utf-8" }).trim();
1188
547
  check(true, gitV, "");
@@ -1191,22 +550,25 @@ async function healthCheck() {
1191
550
  }
1192
551
 
1193
552
  console.log("");
1194
- if (issues === 0) {
553
+ if (issues === 0 && warnings === 0) {
1195
554
  console.log(` ${green("✓ All checks passed")}`);
1196
-
555
+ } else if (issues === 0) {
556
+ console.log(` ${green("✓ All checks passed")} ${dim(`(${warnings} warning${warnings > 1 ? "s" : ""})`)}`);
1197
557
  } else {
1198
- console.log(` ${yellow(`${issues} issue${issues > 1 ? "s" : ""} found`)}`);
558
+ console.log(` ${yellow(`${issues} issue${issues > 1 ? "s" : ""} found`)}${warnings > 0 ? dim(` + ${warnings} warning${warnings > 1 ? "s" : ""}`) : ""}`);
1199
559
  console.log(` ${voice.say("suggest", { suggestion: issues > 2 ? "start with soma init" : "check the items above" })}`);
1200
560
  }
1201
561
  console.log("");
1202
562
  }
1203
563
 
564
+ // ── Project Doctor ───────────────────────────────────────────────────
565
+ // (large function — kept inline to avoid breaking the complex doctor logic)
566
+
1204
567
  async function projectDoctor() {
1205
568
  const doctorArgs = args.slice(1);
1206
569
  const wantsScan = doctorArgs.includes("--scan");
1207
570
  const wantsAll = doctorArgs.includes("--all");
1208
571
 
1209
- // --scan and --all need the runtime — delegate to core
1210
572
  if ((wantsScan || wantsAll) && isInstalled()) {
1211
573
  await delegateToCore();
1212
574
  return;
@@ -1226,7 +588,6 @@ async function projectDoctor() {
1226
588
  return;
1227
589
  }
1228
590
 
1229
- // Version overview
1230
591
  console.log(` Agent: ${cyan(`v${agentV || "unknown"}`)}`);
1231
592
  if (projectV) {
1232
593
  console.log(` Project: ${cyan(`v${projectV}`)}`);
@@ -1252,21 +613,19 @@ async function projectDoctor() {
1252
613
  }
1253
614
 
1254
615
  if (agentV && projectV === agentV) {
1255
- console.log(` ${green("\u2713")} Project is up to date.`);
616
+ console.log(` ${green("")} Project is up to date.`);
1256
617
  console.log("");
1257
618
  await healthCheck();
1258
619
  return;
1259
620
  }
1260
621
 
1261
622
  if (agentV && projectV < agentV) {
1262
- console.log(` ${yellow("\u26a0")} Project .soma/ is at ${cyan(`v${projectV}`)} , agent is at ${cyan(`v${agentV}`)} .`);
623
+ console.log(` ${yellow("")} Project .soma/ is at ${cyan(`v${projectV}`)} , agent is at ${cyan(`v${agentV}`)} .`);
1263
624
  console.log("");
1264
625
 
1265
- // Tier 1: Auto-fix safe things right now
1266
626
  let fixes = 0;
1267
627
  const somaDir = join(process.cwd(), ".soma");
1268
628
 
1269
- // Add missing settings keys
1270
629
  const settingsPath = join(somaDir, "settings.json");
1271
630
  if (existsSync(settingsPath)) {
1272
631
  try {
@@ -1280,29 +639,26 @@ async function projectDoctor() {
1280
639
  add("scratch", { autoInject: false });
1281
640
  add("guard", { coreFiles: "warn", bashCommands: "warn", gitIdentity: null });
1282
641
  add("checkpoints", { enabled: true, intervalMinutes: 5, squashOnPush: true });
1283
- add("persona", { name: null, emoji: "\u03c3" });
642
+ add("persona", { name: null, emoji: "σ" });
1284
643
  add("inherit", { identity: true, protocols: true, muscles: true, tools: true });
1285
644
  if (changed) writeFileSync(settingsPath, JSON.stringify(current, null, "\t") + "\n");
1286
645
  } catch {}
1287
646
  }
1288
647
 
1289
- // Add missing body/ + templates
1290
648
  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;
649
+ let agentRoot = CORE_DIR;
650
+ try {
651
+ const realCore = readlinkSync(join(CORE_DIR, "core"));
652
+ if (realCore) {
653
+ const devRoot = dirname(realCore);
654
+ if (existsSync(join(devRoot, "body", "_public"))) agentRoot = devRoot;
655
+ }
656
+ } catch {}
657
+ if (!existsSync(join(agentRoot, "body", "_public"))) {
658
+ const parent = dirname(agentRoot);
659
+ if (existsSync(join(parent, "body", "_public"))) agentRoot = parent;
1298
660
  }
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");
661
+ const bundledBody = join(agentRoot, "body", "_public");
1306
662
  if (existsSync(bundledBody)) {
1307
663
  try {
1308
664
  if (!existsSync(bodyDir)) mkdirSync(bodyDir, { recursive: true });
@@ -1313,7 +669,6 @@ async function projectDoctor() {
1313
669
  } catch {}
1314
670
  }
1315
671
 
1316
- // Add missing protocols
1317
672
  const protoDir = join(somaDir, "amps", "protocols");
1318
673
  const bundledProtos = existsSync(join(CORE_DIR, "dist", "content", "protocols"))
1319
674
  ? join(CORE_DIR, "dist", "content", "protocols")
@@ -1327,7 +682,6 @@ async function projectDoctor() {
1327
682
  }
1328
683
  }
1329
684
 
1330
- // Add missing bundled scripts
1331
685
  const scriptsDir = join(somaDir, "amps", "scripts");
1332
686
  const bundledScripts = existsSync(join(agentRoot, "dist", "content", "scripts"))
1333
687
  ? join(agentRoot, "dist", "content", "scripts")
@@ -1346,20 +700,18 @@ async function projectDoctor() {
1346
700
  }
1347
701
  }
1348
702
 
1349
- // Bump version after fixes
1350
703
  if (fixes > 0) {
1351
704
  try {
1352
705
  const s = JSON.parse(readFileSync(settingsPath, "utf-8"));
1353
706
  s.version = agentV;
1354
707
  writeFileSync(settingsPath, JSON.stringify(s, null, "\t") + "\n");
1355
708
  } catch {}
1356
- console.log(` ${green("\u2713")} Applied ${fixes} automatic fixes`);
709
+ console.log(` ${green("")} Applied ${fixes} automatic fixes`);
1357
710
  const bc = existsSync(join(somaDir, "body")) ? readdirSync(join(somaDir, "body")).filter(f => f.endsWith(".md")).length : 0;
1358
711
  const pc = existsSync(protoDir) ? readdirSync(protoDir).filter(f => f.endsWith(".md")).length : 0;
1359
712
  console.log(` ${bc} body files, ${pc} protocols, settings updated`);
1360
713
  console.log(` Version bumped to ${cyan(`v${agentV}`)}`);
1361
714
 
1362
- // Scan + fix stale protocols (exist but differ from bundled)
1363
715
  let staleUpdated = 0;
1364
716
  let staleSkipped = [];
1365
717
  if (bundledProtos && existsSync(protoDir)) {
@@ -1370,7 +722,6 @@ async function projectDoctor() {
1370
722
  const bundledRaw = readFileSync(bundledFile, "utf-8");
1371
723
  const strip = s => s.replace(/^(heat|loads|runs|last-run|heat-default):.*\n?/gm, "").trim();
1372
724
  if (strip(projRaw) === strip(bundledRaw)) continue;
1373
- // Preserve user's runtime fields (heat, loads) when updating content
1374
725
  const heatLine = projRaw.match(/^heat:.*$/m);
1375
726
  const loadsLine = projRaw.match(/^loads:.*$/m);
1376
727
  let updated = bundledRaw;
@@ -1383,11 +734,11 @@ async function projectDoctor() {
1383
734
 
1384
735
  console.log("");
1385
736
  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).")}`);
737
+ console.log(` ${green("")} ${staleUpdated} protocols updated to latest version`);
738
+ console.log(` ${dim("Heat and load counts preserved. Content updated.")}`);
1388
739
  }
1389
740
  if (staleSkipped.length > 0) {
1390
- console.log(` ${yellow("\u26a0")} ${staleSkipped.length} protocols skipped (may be customized)`);
741
+ console.log(` ${yellow("")} ${staleSkipped.length} protocols skipped (may be customized)`);
1391
742
  }
1392
743
  console.log("");
1393
744
  const totalRemaining = staleSkipped.length;
@@ -1396,118 +747,41 @@ async function projectDoctor() {
1396
747
  console.log(` ${dim("Remaining: " + totalRemaining + " items need review.")}`);
1397
748
  console.log(` ${dim("For full migration:")} ${green("soma")} ${dim("then")} ${green("/soma doctor")}`);
1398
749
  } else {
1399
- console.log(` ${green("\u2713")} Full migration complete from CLI.`);
750
+ console.log(` ${green("")} Full migration complete from CLI.`);
1400
751
  console.log(` ${dim("No TUI session needed — all updates applied.")}`);
1401
752
  }
1402
753
 
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
754
+ // Write _doctor-pending.md
1405
755
  try {
1406
756
  const pendingPath = join(somaDir, "body", "_doctor-pending.md");
1407
757
  if (staleSkipped.length === 0) {
1408
- // Full migration done — write brief completion note
1409
758
  const done = [
1410
- "---",
1411
- "type: template",
1412
- "name: doctor-pending",
1413
- "status: complete",
759
+ "---", "type: template", "name: doctor-pending", "status: complete",
1414
760
  `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.",
761
+ "description: CLI doctor completed full migration", "---", "",
762
+ "# Doctor Update — Complete", "",
763
+ `Migrated from v${projectV} to v${agentV} on ${new Date().toISOString().split("T")[0]}.`,
764
+ `Applied: ${fixes} file fixes + ${staleUpdated} protocol updates.`, "",
765
+ "Run `/soma doctor` to verify, then delete this file.",
1425
766
  ];
1426
767
  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
768
  }
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 */ }
769
+ } catch {}
1494
770
  } else {
1495
- console.log(` ${green("\u2713")} Version bumped to ${cyan(`v${agentV}`)}`);
771
+ console.log(` ${green("")} Version bumped to ${cyan(`v${agentV}`)}`);
1496
772
  console.log(` ${dim("No file changes needed — project structure is current.")}`);
1497
773
  }
1498
774
  } else {
1499
- console.log(` ${green("\u2713")} Project version: ${cyan(`v${projectV}`)}`);
775
+ console.log(` ${green("")} Project version: ${cyan(`v${projectV}`)}`);
1500
776
  }
1501
777
 
1502
778
  console.log("");
1503
779
  await healthCheck();
1504
780
  }
1505
781
 
1506
-
1507
782
  // ── Delegation ───────────────────────────────────────────────────────
1508
783
 
1509
784
  async function delegateToCore() {
1510
- // Pre-flight: verify runtime can start before delegating
1511
785
  const piPkg = join(CORE_DIR, "node_modules", "@mariozechner", "pi-coding-agent");
1512
786
  if (!existsSync(piPkg)) {
1513
787
  console.log(` ${red("✗")} Runtime dependencies missing.`);
@@ -1528,7 +802,6 @@ async function delegateToCore() {
1528
802
  return;
1529
803
  }
1530
804
 
1531
- const { execFileSync: execF } = await import("child_process");
1532
805
  const passArgs = process.argv.slice(2);
1533
806
 
1534
807
  const cliLocations = [
@@ -1536,9 +809,6 @@ async function delegateToCore() {
1536
809
  { path: join(CORE_DIR, "node_modules", ".bin", "pi"), type: "bin" },
1537
810
  ];
1538
811
 
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
812
  const userExtArgs = [];
1543
813
  const projectExtDir = join(process.cwd(), ".soma", "extensions");
1544
814
  if (existsSync(projectExtDir)) {
@@ -1552,14 +822,8 @@ async function delegateToCore() {
1552
822
 
1553
823
  const env = {
1554
824
  ...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
825
  PI_CODING_AGENT_DIR: CORE_DIR,
1560
826
  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
827
  PI_PACKAGE_DIR: CORE_DIR,
1564
828
  };
1565
829
 
@@ -1568,15 +832,13 @@ async function delegateToCore() {
1568
832
  try {
1569
833
  const allArgs = [...userExtArgs, ...passArgs];
1570
834
  if (cli.type === "node") {
1571
- execF("node", [cli.path, ...allArgs], { stdio: "inherit", cwd: process.cwd(), env });
835
+ execFileSync("node", [cli.path, ...allArgs], { stdio: "inherit", cwd: process.cwd(), env });
1572
836
  } else {
1573
- execF(cli.path, allArgs, { stdio: "inherit", cwd: process.cwd(), env });
837
+ execFileSync(cli.path, allArgs, { stdio: "inherit", cwd: process.cwd(), env });
1574
838
  }
1575
839
  return;
1576
840
  } catch (err) {
1577
- // Non-zero exit from session is normal (user quit, ctrl+c)
1578
841
  if (err.status) process.exit(err.status);
1579
- // Module errors = broken install
1580
842
  if (err.message && err.message.includes("MODULE_NOT_FOUND")) {
1581
843
  console.log("");
1582
844
  console.log(` ${red("✗")} Soma failed to start — missing dependencies.`);
@@ -1603,7 +865,6 @@ if (cmd === "--version" || cmd === "-v" || cmd === "-V") {
1603
865
  showVersion();
1604
866
  } else if (cmd === "--help" || cmd === "-h") {
1605
867
  if (isInstalled()) {
1606
- // Delegate to core — richer help with scripts, commands, hub
1607
868
  await delegateToCore();
1608
869
  } else {
1609
870
  showHelp();
@@ -1616,13 +877,10 @@ if (cmd === "--version" || cmd === "-v" || cmd === "-V") {
1616
877
  const hasSomaDir = existsSync(join(process.cwd(), ".soma"));
1617
878
 
1618
879
  if (!runtimeInstalled) {
1619
- // Not installed — run full install + setup
1620
880
  await initSoma();
1621
881
  } else if (hasProjectArgs || !hasSomaDir) {
1622
- // Installed, project init (new project or --template/--orphan)
1623
882
  await delegateToCore();
1624
883
  } else {
1625
- // Installed + .soma/ exists — check for updates + project staleness
1626
884
  await checkAndUpdate();
1627
885
  }
1628
886
  } else if (cmd === "update") {
@@ -1632,10 +890,8 @@ if (cmd === "--version" || cmd === "-v" || cmd === "-V") {
1632
890
  } else if (cmd === "status" || cmd === "health") {
1633
891
  await healthCheck();
1634
892
  } else if (isInstalled()) {
1635
- // Core installed — delegate to runtime
1636
893
  await delegateToCore();
1637
894
  } else {
1638
- // Check if user typed a known post-install command
1639
895
  const postInstallCmds = ["focus", "inhale", "content", "install", "list", "map", "--map", "--preload"];
1640
896
  if (cmd && postInstallCmds.includes(cmd)) {
1641
897
  printSigma();
@@ -1644,7 +900,6 @@ if (cmd === "--version" || cmd === "-v" || cmd === "-V") {
1644
900
  console.log(` Run ${green("soma init")} to install it.`);
1645
901
  console.log("");
1646
902
  } else {
1647
- // Not installed or not verified — show welcome experience
1648
903
  await showWelcome();
1649
904
  }
1650
905
  }