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.
- package/CHANGELOG.md +20 -0
- package/README.md +2 -2
- package/bin/gum +0 -0
- package/dist/bun/cli.d.ts +3 -0
- package/dist/bun/cli.d.ts.map +1 -0
- package/dist/bun/cli.js +7 -0
- package/dist/bun/cli.js.map +1 -0
- package/dist/bun/register-bedrock.d.ts +2 -0
- package/dist/bun/register-bedrock.d.ts.map +1 -0
- package/dist/bun/register-bedrock.js +4 -0
- package/dist/bun/register-bedrock.js.map +1 -0
- package/dist/cli/args.d.ts +49 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +304 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/config-selector.d.ts +14 -0
- package/dist/cli/config-selector.d.ts.map +1 -0
- package/dist/cli/config-selector.js +31 -0
- package/dist/cli/config-selector.js.map +1 -0
- package/dist/cli/file-processor.d.ts +15 -0
- package/dist/cli/file-processor.d.ts.map +1 -0
- package/dist/cli/file-processor.js +83 -0
- package/dist/cli/file-processor.js.map +1 -0
- package/dist/cli/initial-message.d.ts +18 -0
- package/dist/cli/initial-message.d.ts.map +1 -0
- package/dist/cli/initial-message.js +22 -0
- package/dist/cli/initial-message.js.map +1 -0
- package/dist/cli/list-models.d.ts +9 -0
- package/dist/cli/list-models.d.ts.map +1 -0
- package/dist/cli/list-models.js +92 -0
- package/dist/cli/list-models.js.map +1 -0
- package/dist/cli/session-picker.d.ts +9 -0
- package/dist/cli/session-picker.d.ts.map +1 -0
- package/dist/cli/session-picker.js +35 -0
- package/dist/cli/session-picker.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +601 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +68 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +203 -0
- package/dist/config.js.map +1 -0
- package/dist/core/agent-session-runtime.d.ts +134 -0
- package/dist/core/agent-session-runtime.d.ts.map +1 -0
- package/dist/core/agent-session-runtime.js +264 -0
- package/dist/core/agent-session-runtime.js.map +1 -0
- package/dist/core/agent-session.d.ts +585 -0
- package/dist/core/agent-session.d.ts.map +1 -0
- package/dist/core/agent-session.js +2497 -0
- package/dist/core/agent-session.js.map +1 -0
- package/dist/core/auth-storage.d.ts +132 -0
- package/dist/core/auth-storage.d.ts.map +1 -0
- package/dist/core/auth-storage.js +422 -0
- package/dist/core/auth-storage.js.map +1 -0
- package/dist/core/bash-executor.d.ts +46 -0
- package/dist/core/bash-executor.d.ts.map +1 -0
- package/dist/core/bash-executor.js +113 -0
- package/dist/core/bash-executor.js.map +1 -0
- package/dist/core/compaction/branch-summarization.d.ts +88 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -0
- package/dist/core/compaction/branch-summarization.js +243 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -0
- package/dist/core/compaction/compaction.d.ts +121 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -0
- package/dist/core/compaction/compaction.js +613 -0
- package/dist/core/compaction/compaction.js.map +1 -0
- package/dist/core/compaction/index.d.ts +7 -0
- package/dist/core/compaction/index.d.ts.map +1 -0
- package/dist/core/compaction/index.js +7 -0
- package/dist/core/compaction/index.js.map +1 -0
- package/dist/core/compaction/utils.d.ts +38 -0
- package/dist/core/compaction/utils.d.ts.map +1 -0
- package/dist/core/compaction/utils.js +153 -0
- package/dist/core/compaction/utils.js.map +1 -0
- package/dist/core/defaults.d.ts +3 -0
- package/dist/core/defaults.d.ts.map +1 -0
- package/dist/core/defaults.js +2 -0
- package/dist/core/defaults.js.map +1 -0
- package/dist/core/diagnostics.d.ts +15 -0
- package/dist/core/diagnostics.d.ts.map +1 -0
- package/dist/core/diagnostics.js +2 -0
- package/dist/core/diagnostics.js.map +1 -0
- package/dist/core/event-bus.d.ts +9 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +25 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/exec.d.ts +29 -0
- package/dist/core/exec.d.ts.map +1 -0
- package/dist/core/exec.js +75 -0
- package/dist/core/exec.js.map +1 -0
- package/dist/core/export-html/ansi-to-html.d.ts +22 -0
- package/dist/core/export-html/ansi-to-html.d.ts.map +1 -0
- package/dist/core/export-html/ansi-to-html.js +249 -0
- package/dist/core/export-html/ansi-to-html.js.map +1 -0
- package/dist/core/export-html/index.d.ts +37 -0
- package/dist/core/export-html/index.d.ts.map +1 -0
- package/dist/core/export-html/index.js +224 -0
- package/dist/core/export-html/index.js.map +1 -0
- package/dist/core/export-html/template.css +1001 -0
- package/dist/core/export-html/template.html +55 -0
- package/dist/core/export-html/template.js +1690 -0
- package/dist/core/export-html/tool-renderer.d.ts +40 -0
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -0
- package/dist/core/export-html/tool-renderer.js +95 -0
- package/dist/core/export-html/tool-renderer.js.map +1 -0
- package/dist/core/export-html/vendor/highlight.min.js +1213 -0
- package/dist/core/export-html/vendor/marked.min.js +6 -0
- package/dist/core/extensions/index.d.ts +12 -0
- package/dist/core/extensions/index.d.ts.map +1 -0
- package/dist/core/extensions/index.js +9 -0
- package/dist/core/extensions/index.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +25 -0
- package/dist/core/extensions/loader.d.ts.map +1 -0
- package/dist/core/extensions/loader.js +436 -0
- package/dist/core/extensions/loader.js.map +1 -0
- package/dist/core/extensions/runner.d.ts +148 -0
- package/dist/core/extensions/runner.d.ts.map +1 -0
- package/dist/core/extensions/runner.js +700 -0
- package/dist/core/extensions/runner.js.map +1 -0
- package/dist/core/extensions/types.d.ts +1076 -0
- package/dist/core/extensions/types.d.ts.map +1 -0
- package/dist/core/extensions/types.js +35 -0
- package/dist/core/extensions/types.js.map +1 -0
- package/dist/core/extensions/wrapper.d.ts +20 -0
- package/dist/core/extensions/wrapper.d.ts.map +1 -0
- package/dist/core/extensions/wrapper.js +22 -0
- package/dist/core/extensions/wrapper.js.map +1 -0
- package/dist/core/footer-data-provider.d.ts +48 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -0
- package/dist/core/footer-data-provider.js +314 -0
- package/dist/core/footer-data-provider.js.map +1 -0
- package/dist/core/index.d.ts +11 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +11 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/keybindings.d.ts +285 -0
- package/dist/core/keybindings.d.ts.map +1 -0
- package/dist/core/keybindings.js +251 -0
- package/dist/core/keybindings.js.map +1 -0
- package/dist/core/messages.d.ts +77 -0
- package/dist/core/messages.d.ts.map +1 -0
- package/dist/core/messages.js +123 -0
- package/dist/core/messages.js.map +1 -0
- package/dist/core/model-registry.d.ts +132 -0
- package/dist/core/model-registry.d.ts.map +1 -0
- package/dist/core/model-registry.js +583 -0
- package/dist/core/model-registry.js.map +1 -0
- package/dist/core/model-resolver.d.ts +110 -0
- package/dist/core/model-resolver.d.ts.map +1 -0
- package/dist/core/model-resolver.js +486 -0
- package/dist/core/model-resolver.js.map +1 -0
- package/dist/core/output-guard.d.ts +6 -0
- package/dist/core/output-guard.d.ts.map +1 -0
- package/dist/core/output-guard.js +59 -0
- package/dist/core/output-guard.js.map +1 -0
- package/dist/core/package-manager.d.ts +172 -0
- package/dist/core/package-manager.d.ts.map +1 -0
- package/dist/core/package-manager.js +1783 -0
- package/dist/core/package-manager.js.map +1 -0
- package/dist/core/prompt-templates.d.ts +51 -0
- package/dist/core/prompt-templates.d.ts.map +1 -0
- package/dist/core/prompt-templates.js +249 -0
- package/dist/core/prompt-templates.js.map +1 -0
- package/dist/core/resolve-config-value.d.ts +23 -0
- package/dist/core/resolve-config-value.d.ts.map +1 -0
- package/dist/core/resolve-config-value.js +126 -0
- package/dist/core/resolve-config-value.js.map +1 -0
- package/dist/core/resource-loader.d.ts +185 -0
- package/dist/core/resource-loader.d.ts.map +1 -0
- package/dist/core/resource-loader.js +698 -0
- package/dist/core/resource-loader.js.map +1 -0
- package/dist/core/sdk.d.ts +93 -0
- package/dist/core/sdk.d.ts.map +1 -0
- package/dist/core/sdk.js +236 -0
- package/dist/core/sdk.js.map +1 -0
- package/dist/core/session-manager.d.ts +332 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +1104 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/core/settings-manager.d.ts +237 -0
- package/dist/core/settings-manager.d.ts.map +1 -0
- package/dist/core/settings-manager.js +702 -0
- package/dist/core/settings-manager.js.map +1 -0
- package/dist/core/skills.d.ts +60 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +409 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/slash-commands.d.ts +14 -0
- package/dist/core/slash-commands.d.ts.map +1 -0
- package/dist/core/slash-commands.js +23 -0
- package/dist/core/slash-commands.js.map +1 -0
- package/dist/core/source-info.d.ts +18 -0
- package/dist/core/source-info.d.ts.map +1 -0
- package/dist/core/source-info.js +19 -0
- package/dist/core/source-info.js.map +1 -0
- package/dist/core/system-prompt.d.ts +28 -0
- package/dist/core/system-prompt.d.ts.map +1 -0
- package/dist/core/system-prompt.js +116 -0
- package/dist/core/system-prompt.js.map +1 -0
- package/dist/core/timings.d.ts +8 -0
- package/dist/core/timings.d.ts.map +1 -0
- package/dist/core/timings.js +31 -0
- package/dist/core/timings.js.map +1 -0
- package/dist/core/tools/bash.d.ts +73 -0
- package/dist/core/tools/bash.d.ts.map +1 -0
- package/dist/core/tools/bash.js +342 -0
- package/dist/core/tools/bash.js.map +1 -0
- package/dist/core/tools/edit-diff.d.ts +85 -0
- package/dist/core/tools/edit-diff.d.ts.map +1 -0
- package/dist/core/tools/edit-diff.js +337 -0
- package/dist/core/tools/edit-diff.js.map +1 -0
- package/dist/core/tools/edit.d.ts +53 -0
- package/dist/core/tools/edit.d.ts.map +1 -0
- package/dist/core/tools/edit.js +196 -0
- package/dist/core/tools/edit.js.map +1 -0
- package/dist/core/tools/file-mutation-queue.d.ts +6 -0
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -0
- package/dist/core/tools/file-mutation-queue.js +37 -0
- package/dist/core/tools/file-mutation-queue.js.map +1 -0
- package/dist/core/tools/find.d.ts +46 -0
- package/dist/core/tools/find.d.ts.map +1 -0
- package/dist/core/tools/find.js +258 -0
- package/dist/core/tools/find.js.map +1 -0
- package/dist/core/tools/grep.d.ts +56 -0
- package/dist/core/tools/grep.d.ts.map +1 -0
- package/dist/core/tools/grep.js +293 -0
- package/dist/core/tools/grep.js.map +1 -0
- package/dist/core/tools/index.d.ts +115 -0
- package/dist/core/tools/index.d.ts.map +1 -0
- package/dist/core/tools/index.js +86 -0
- package/dist/core/tools/index.js.map +1 -0
- package/dist/core/tools/ls.d.ts +46 -0
- package/dist/core/tools/ls.d.ts.map +1 -0
- package/dist/core/tools/ls.js +172 -0
- package/dist/core/tools/ls.js.map +1 -0
- package/dist/core/tools/path-utils.d.ts +8 -0
- package/dist/core/tools/path-utils.d.ts.map +1 -0
- package/dist/core/tools/path-utils.js +81 -0
- package/dist/core/tools/path-utils.js.map +1 -0
- package/dist/core/tools/read.d.ts +46 -0
- package/dist/core/tools/read.d.ts.map +1 -0
- package/dist/core/tools/read.js +225 -0
- package/dist/core/tools/read.js.map +1 -0
- package/dist/core/tools/render-utils.d.ts +21 -0
- package/dist/core/tools/render-utils.d.ts.map +1 -0
- package/dist/core/tools/render-utils.js +49 -0
- package/dist/core/tools/render-utils.js.map +1 -0
- package/dist/core/tools/tool-definition-wrapper.d.ts +14 -0
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -0
- package/dist/core/tools/tool-definition-wrapper.js +32 -0
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -0
- package/dist/core/tools/truncate.d.ts +70 -0
- package/dist/core/tools/truncate.d.ts.map +1 -0
- package/dist/core/tools/truncate.js +205 -0
- package/dist/core/tools/truncate.js.map +1 -0
- package/dist/core/tools/write.d.ts +35 -0
- package/dist/core/tools/write.d.ts.map +1 -0
- package/dist/core/tools/write.js +216 -0
- package/dist/core/tools/write.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.js +22 -0
- package/dist/lib/detect.js +94 -0
- package/dist/lib/display.js +182 -0
- package/dist/main.d.ts +8 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +806 -0
- package/dist/main.js.map +1 -0
- package/dist/migrations.d.ts +33 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +261 -0
- package/dist/migrations.js.map +1 -0
- package/dist/modes/index.d.ts +9 -0
- package/dist/modes/index.d.ts.map +1 -0
- package/dist/modes/index.js +8 -0
- package/dist/modes/index.js.map +1 -0
- package/dist/modes/interactive/components/armin.d.ts +34 -0
- package/dist/modes/interactive/components/armin.d.ts.map +1 -0
- package/dist/modes/interactive/components/armin.js +333 -0
- package/dist/modes/interactive/components/armin.js.map +1 -0
- package/dist/modes/interactive/components/assistant-message.d.ts +18 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/assistant-message.js +107 -0
- package/dist/modes/interactive/components/assistant-message.js.map +1 -0
- package/dist/modes/interactive/components/bash-execution.d.ts +34 -0
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -0
- package/dist/modes/interactive/components/bash-execution.js +175 -0
- package/dist/modes/interactive/components/bash-execution.js.map +1 -0
- package/dist/modes/interactive/components/bordered-loader.d.ts +16 -0
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -0
- package/dist/modes/interactive/components/bordered-loader.js +51 -0
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -0
- package/dist/modes/interactive/components/branch-summary-message.d.ts +16 -0
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/branch-summary-message.js +44 -0
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -0
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +16 -0
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/compaction-summary-message.js +45 -0
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -0
- package/dist/modes/interactive/components/config-selector.d.ts +71 -0
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/config-selector.js +479 -0
- package/dist/modes/interactive/components/config-selector.js.map +1 -0
- package/dist/modes/interactive/components/countdown-timer.d.ts +14 -0
- package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -0
- package/dist/modes/interactive/components/countdown-timer.js +33 -0
- package/dist/modes/interactive/components/countdown-timer.js.map +1 -0
- package/dist/modes/interactive/components/custom-editor.d.ts +21 -0
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/custom-editor.js +70 -0
- package/dist/modes/interactive/components/custom-editor.js.map +1 -0
- package/dist/modes/interactive/components/custom-message.d.ts +20 -0
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/custom-message.js +79 -0
- package/dist/modes/interactive/components/custom-message.js.map +1 -0
- package/dist/modes/interactive/components/daxnuts.d.ts +23 -0
- package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -0
- package/dist/modes/interactive/components/daxnuts.js +140 -0
- package/dist/modes/interactive/components/daxnuts.js.map +1 -0
- package/dist/modes/interactive/components/diff.d.ts +12 -0
- package/dist/modes/interactive/components/diff.d.ts.map +1 -0
- package/dist/modes/interactive/components/diff.js +133 -0
- package/dist/modes/interactive/components/diff.js.map +1 -0
- package/dist/modes/interactive/components/dynamic-border.d.ts +15 -0
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -0
- package/dist/modes/interactive/components/dynamic-border.js +21 -0
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -0
- package/dist/modes/interactive/components/extension-editor.d.ts +20 -0
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/extension-editor.js +111 -0
- package/dist/modes/interactive/components/extension-editor.js.map +1 -0
- package/dist/modes/interactive/components/extension-input.d.ts +23 -0
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -0
- package/dist/modes/interactive/components/extension-input.js +61 -0
- package/dist/modes/interactive/components/extension-input.js.map +1 -0
- package/dist/modes/interactive/components/extension-selector.d.ts +24 -0
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/extension-selector.js +78 -0
- package/dist/modes/interactive/components/extension-selector.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +27 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -0
- package/dist/modes/interactive/components/footer.js +201 -0
- package/dist/modes/interactive/components/footer.js.map +1 -0
- package/dist/modes/interactive/components/index.d.ts +32 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -0
- package/dist/modes/interactive/components/index.js +33 -0
- package/dist/modes/interactive/components/index.js.map +1 -0
- package/dist/modes/interactive/components/keybinding-hints.d.ts +8 -0
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -0
- package/dist/modes/interactive/components/keybinding-hints.js +22 -0
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -0
- package/dist/modes/interactive/components/login-dialog.d.ts +42 -0
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -0
- package/dist/modes/interactive/components/login-dialog.js +145 -0
- package/dist/modes/interactive/components/login-dialog.js.map +1 -0
- package/dist/modes/interactive/components/model-selector.d.ts +47 -0
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/model-selector.js +275 -0
- package/dist/modes/interactive/components/model-selector.js.map +1 -0
- package/dist/modes/interactive/components/oauth-selector.d.ts +19 -0
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/oauth-selector.js +97 -0
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -0
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +49 -0
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/scoped-models-selector.js +275 -0
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -0
- package/dist/modes/interactive/components/session-selector-search.d.ts +23 -0
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-selector-search.js +155 -0
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -0
- package/dist/modes/interactive/components/session-selector.d.ts +95 -0
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-selector.js +848 -0
- package/dist/modes/interactive/components/session-selector.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +58 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-selector.js +301 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -0
- package/dist/modes/interactive/components/show-images-selector.d.ts +10 -0
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/show-images-selector.js +39 -0
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -0
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +17 -0
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/skill-invocation-message.js +47 -0
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -0
- package/dist/modes/interactive/components/theme-selector.d.ts +11 -0
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/theme-selector.js +50 -0
- package/dist/modes/interactive/components/theme-selector.js.map +1 -0
- package/dist/modes/interactive/components/thinking-selector.d.ts +11 -0
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/thinking-selector.js +51 -0
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -0
- package/dist/modes/interactive/components/tool-execution.d.ts +58 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -0
- package/dist/modes/interactive/components/tool-execution.js +274 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -0
- package/dist/modes/interactive/components/tree-selector.d.ts +89 -0
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/tree-selector.js +1084 -0
- package/dist/modes/interactive/components/tree-selector.js.map +1 -0
- package/dist/modes/interactive/components/user-message-selector.d.ts +30 -0
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/user-message-selector.js +113 -0
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -0
- package/dist/modes/interactive/components/user-message.d.ts +9 -0
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/user-message.js +28 -0
- package/dist/modes/interactive/components/user-message.js.map +1 -0
- package/dist/modes/interactive/components/visual-truncate.d.ts +24 -0
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -0
- package/dist/modes/interactive/components/visual-truncate.js +33 -0
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +318 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-mode.js +3907 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -0
- package/dist/modes/interactive/theme/dark.json +85 -0
- package/dist/modes/interactive/theme/light.json +84 -0
- package/dist/modes/interactive/theme/theme-schema.json +335 -0
- package/dist/modes/interactive/theme/theme.d.ts +81 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme.js +970 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -0
- package/dist/modes/print-mode.d.ts +28 -0
- package/dist/modes/print-mode.d.ts.map +1 -0
- package/dist/modes/print-mode.js +108 -0
- package/dist/modes/print-mode.js.map +1 -0
- package/dist/modes/rpc/jsonl.d.ts +17 -0
- package/dist/modes/rpc/jsonl.d.ts.map +1 -0
- package/dist/modes/rpc/jsonl.js +49 -0
- package/dist/modes/rpc/jsonl.js.map +1 -0
- package/dist/modes/rpc/rpc-client.d.ts +217 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-client.js +401 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -0
- package/dist/modes/rpc/rpc-mode.d.ts +20 -0
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-mode.js +542 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -0
- package/dist/modes/rpc/rpc-types.d.ts +408 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-types.js +8 -0
- package/dist/modes/rpc/rpc-types.js.map +1 -0
- package/dist/thin-cli.js +62 -810
- package/dist/utils/changelog.d.ts +21 -0
- package/dist/utils/changelog.d.ts.map +1 -0
- package/dist/utils/changelog.js +87 -0
- package/dist/utils/changelog.js.map +1 -0
- package/dist/utils/child-process.d.ts +11 -0
- package/dist/utils/child-process.d.ts.map +1 -0
- package/dist/utils/child-process.js +78 -0
- package/dist/utils/child-process.js.map +1 -0
- package/dist/utils/clipboard-image.d.ts +11 -0
- package/dist/utils/clipboard-image.d.ts.map +1 -0
- package/dist/utils/clipboard-image.js +245 -0
- package/dist/utils/clipboard-image.js.map +1 -0
- package/dist/utils/clipboard-native.d.ts +8 -0
- package/dist/utils/clipboard-native.d.ts.map +1 -0
- package/dist/utils/clipboard-native.js +14 -0
- package/dist/utils/clipboard-native.js.map +1 -0
- package/dist/utils/clipboard.d.ts +2 -0
- package/dist/utils/clipboard.d.ts.map +1 -0
- package/dist/utils/clipboard.js +78 -0
- package/dist/utils/clipboard.js.map +1 -0
- package/dist/utils/exif-orientation.d.ts +5 -0
- package/dist/utils/exif-orientation.d.ts.map +1 -0
- package/dist/utils/exif-orientation.js +158 -0
- package/dist/utils/exif-orientation.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +8 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +26 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/git.d.ts +26 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +163 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/image-convert.d.ts +9 -0
- package/dist/utils/image-convert.d.ts.map +1 -0
- package/dist/utils/image-convert.js +39 -0
- package/dist/utils/image-convert.js.map +1 -0
- package/dist/utils/image-resize.d.ts +36 -0
- package/dist/utils/image-resize.d.ts.map +1 -0
- package/dist/utils/image-resize.js +137 -0
- package/dist/utils/image-resize.js.map +1 -0
- package/dist/utils/mime.d.ts +2 -0
- package/dist/utils/mime.d.ts.map +1 -0
- package/dist/utils/mime.js +26 -0
- package/dist/utils/mime.js.map +1 -0
- package/dist/utils/photon.d.ts +21 -0
- package/dist/utils/photon.d.ts.map +1 -0
- package/dist/utils/photon.js +121 -0
- package/dist/utils/photon.js.map +1 -0
- package/dist/utils/shell.d.ts +26 -0
- package/dist/utils/shell.d.ts.map +1 -0
- package/dist/utils/shell.js +186 -0
- package/dist/utils/shell.js.map +1 -0
- package/dist/utils/sleep.d.ts +5 -0
- package/dist/utils/sleep.d.ts.map +1 -0
- package/dist/utils/sleep.js +17 -0
- package/dist/utils/sleep.js.map +1 -0
- package/dist/utils/tools-manager.d.ts +3 -0
- package/dist/utils/tools-manager.d.ts.map +1 -0
- package/dist/utils/tools-manager.js +252 -0
- package/dist/utils/tools-manager.js.map +1 -0
- package/dist/welcome/about.js +50 -0
- package/dist/welcome/auth.js +126 -0
- package/dist/welcome/intro.js +90 -0
- package/dist/welcome/qa.js +131 -0
- package/package.json +90 -43
- 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.
|
|
6
|
-
*
|
|
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,
|
|
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
|
-
|
|
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,
|
|
476
|
+
const check = (ok, pass, fail_msg) => {
|
|
1110
477
|
if (ok) { console.log(` ${green("✓")} ${pass}`); }
|
|
1111
|
-
else { console.log(` ${red("✗")} ${
|
|
478
|
+
else { console.log(` ${red("✗")} ${fail_msg}`); issues++; }
|
|
1112
479
|
};
|
|
1113
|
-
const warn = (ok, pass,
|
|
480
|
+
const warn = (ok, pass, fail_msg) => {
|
|
1114
481
|
if (ok) { console.log(` ${green("✓")} ${pass}`); }
|
|
1115
|
-
else { console.log(` ${yellow("⚠")} ${
|
|
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("
|
|
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("
|
|
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: "
|
|
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
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
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
|
-
|
|
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("
|
|
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("
|
|
1387
|
-
console.log(` ${dim("Heat and load counts preserved. Content updated
|
|
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("
|
|
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("
|
|
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
|
|
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
|
|
1416
|
-
"
|
|
1417
|
-
""
|
|
1418
|
-
|
|
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
|
-
|
|
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("
|
|
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("
|
|
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
|
-
|
|
832
|
+
execFileSync("node", [cli.path, ...allArgs], { stdio: "inherit", cwd: process.cwd(), env });
|
|
1572
833
|
} else {
|
|
1573
|
-
|
|
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
|
}
|