meetsoma 0.2.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -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 +67 -812
- 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,24 @@ function checkForUpdates() {
|
|
|
1100
465
|
console.log("");
|
|
1101
466
|
}
|
|
1102
467
|
|
|
468
|
+
// ── Health Check ─────────────────────────────────────────────────────
|
|
469
|
+
|
|
1103
470
|
async function healthCheck() {
|
|
1104
471
|
printSigma();
|
|
1105
472
|
console.log(` ${bold("Soma")} — Health Check`);
|
|
1106
473
|
console.log("");
|
|
1107
474
|
|
|
1108
475
|
let issues = 0;
|
|
1109
|
-
|
|
476
|
+
let warnings = 0;
|
|
477
|
+
const check = (ok, pass, fail_msg) => {
|
|
1110
478
|
if (ok) { console.log(` ${green("✓")} ${pass}`); }
|
|
1111
|
-
else { console.log(` ${red("✗")} ${
|
|
479
|
+
else { console.log(` ${red("✗")} ${fail_msg}`); issues++; }
|
|
1112
480
|
};
|
|
1113
|
-
const warn = (ok, pass,
|
|
481
|
+
const warn = (ok, pass, fail_msg) => {
|
|
1114
482
|
if (ok) { console.log(` ${green("✓")} ${pass}`); }
|
|
1115
|
-
else { console.log(` ${yellow("⚠")} ${
|
|
483
|
+
else { console.log(` ${yellow("⚠")} ${fail_msg}`); warnings++; }
|
|
1116
484
|
};
|
|
1117
485
|
|
|
1118
|
-
// Node.js
|
|
1119
486
|
const nodeVersion = process.versions.node;
|
|
1120
487
|
const [major, minor] = nodeVersion.split(".").map(Number);
|
|
1121
488
|
check(major > 20 || (major === 20 && minor >= 6),
|
|
@@ -1123,15 +490,12 @@ async function healthCheck() {
|
|
|
1123
490
|
`Node.js ${nodeVersion} — requires ≥20.6.0`
|
|
1124
491
|
);
|
|
1125
492
|
|
|
1126
|
-
// ~/.soma directory
|
|
1127
493
|
check(existsSync(SOMA_HOME), "~/.soma/ exists", "~/.soma/ not found — run: soma init");
|
|
1128
494
|
|
|
1129
|
-
// Core installation
|
|
1130
495
|
const installed = isInstalled();
|
|
1131
496
|
check(installed, "Core installed", "Core not installed — run: soma init");
|
|
1132
497
|
|
|
1133
498
|
if (installed) {
|
|
1134
|
-
// Extensions (check both dist/ layout and dev layout)
|
|
1135
499
|
const extDir = existsSync(join(CORE_DIR, "dist", "extensions"))
|
|
1136
500
|
? join(CORE_DIR, "dist", "extensions")
|
|
1137
501
|
: join(CORE_DIR, "extensions");
|
|
@@ -1140,13 +504,11 @@ async function healthCheck() {
|
|
|
1140
504
|
check(exts.length >= 6, `${exts.length} extensions`, `Only ${exts.length} extensions (expected ≥6)`);
|
|
1141
505
|
}
|
|
1142
506
|
|
|
1143
|
-
// Core modules
|
|
1144
507
|
const coreDir = existsSync(join(CORE_DIR, "dist", "core"))
|
|
1145
508
|
? join(CORE_DIR, "dist", "core")
|
|
1146
509
|
: join(CORE_DIR, "core");
|
|
1147
510
|
check(existsSync(coreDir), "Core modules present", "Core modules missing");
|
|
1148
511
|
|
|
1149
|
-
// Git repo health (skip in dev mode — no .git when using symlinks)
|
|
1150
512
|
if (existsSync(join(CORE_DIR, ".git"))) {
|
|
1151
513
|
try {
|
|
1152
514
|
execSync("git status --porcelain", { cwd: CORE_DIR, stdio: "ignore" });
|
|
@@ -1155,7 +517,6 @@ async function healthCheck() {
|
|
|
1155
517
|
warn(false, "", "Core git repo has issues");
|
|
1156
518
|
}
|
|
1157
519
|
} else {
|
|
1158
|
-
// Dev mode — core/ is symlinked, no .git expected
|
|
1159
520
|
try {
|
|
1160
521
|
const realCore = readlinkSync(join(CORE_DIR, "core"));
|
|
1161
522
|
if (realCore) {
|
|
@@ -1169,7 +530,6 @@ async function healthCheck() {
|
|
|
1169
530
|
}
|
|
1170
531
|
}
|
|
1171
532
|
|
|
1172
|
-
// API key (check env + auth.json + shell config)
|
|
1173
533
|
const hasAuth = hasAnyAuth();
|
|
1174
534
|
if (hasAuth) {
|
|
1175
535
|
console.log(` ${green("✓")} API key configured`);
|
|
@@ -1182,7 +542,6 @@ async function healthCheck() {
|
|
|
1182
542
|
}
|
|
1183
543
|
}
|
|
1184
544
|
|
|
1185
|
-
// Git
|
|
1186
545
|
try {
|
|
1187
546
|
const gitV = execSync("git --version", { encoding: "utf-8" }).trim();
|
|
1188
547
|
check(true, gitV, "");
|
|
@@ -1191,22 +550,25 @@ async function healthCheck() {
|
|
|
1191
550
|
}
|
|
1192
551
|
|
|
1193
552
|
console.log("");
|
|
1194
|
-
if (issues === 0) {
|
|
553
|
+
if (issues === 0 && warnings === 0) {
|
|
1195
554
|
console.log(` ${green("✓ All checks passed")}`);
|
|
1196
|
-
|
|
555
|
+
} else if (issues === 0) {
|
|
556
|
+
console.log(` ${green("✓ All checks passed")} ${dim(`(${warnings} warning${warnings > 1 ? "s" : ""})`)}`);
|
|
1197
557
|
} else {
|
|
1198
|
-
console.log(` ${yellow(`${issues} issue${issues > 1 ? "s" : ""} found`)}`);
|
|
558
|
+
console.log(` ${yellow(`${issues} issue${issues > 1 ? "s" : ""} found`)}${warnings > 0 ? dim(` + ${warnings} warning${warnings > 1 ? "s" : ""}`) : ""}`);
|
|
1199
559
|
console.log(` ${voice.say("suggest", { suggestion: issues > 2 ? "start with soma init" : "check the items above" })}`);
|
|
1200
560
|
}
|
|
1201
561
|
console.log("");
|
|
1202
562
|
}
|
|
1203
563
|
|
|
564
|
+
// ── Project Doctor ───────────────────────────────────────────────────
|
|
565
|
+
// (large function — kept inline to avoid breaking the complex doctor logic)
|
|
566
|
+
|
|
1204
567
|
async function projectDoctor() {
|
|
1205
568
|
const doctorArgs = args.slice(1);
|
|
1206
569
|
const wantsScan = doctorArgs.includes("--scan");
|
|
1207
570
|
const wantsAll = doctorArgs.includes("--all");
|
|
1208
571
|
|
|
1209
|
-
// --scan and --all need the runtime — delegate to core
|
|
1210
572
|
if ((wantsScan || wantsAll) && isInstalled()) {
|
|
1211
573
|
await delegateToCore();
|
|
1212
574
|
return;
|
|
@@ -1226,7 +588,6 @@ async function projectDoctor() {
|
|
|
1226
588
|
return;
|
|
1227
589
|
}
|
|
1228
590
|
|
|
1229
|
-
// Version overview
|
|
1230
591
|
console.log(` Agent: ${cyan(`v${agentV || "unknown"}`)}`);
|
|
1231
592
|
if (projectV) {
|
|
1232
593
|
console.log(` Project: ${cyan(`v${projectV}`)}`);
|
|
@@ -1252,21 +613,19 @@ async function projectDoctor() {
|
|
|
1252
613
|
}
|
|
1253
614
|
|
|
1254
615
|
if (agentV && projectV === agentV) {
|
|
1255
|
-
console.log(` ${green("
|
|
616
|
+
console.log(` ${green("✓")} Project is up to date.`);
|
|
1256
617
|
console.log("");
|
|
1257
618
|
await healthCheck();
|
|
1258
619
|
return;
|
|
1259
620
|
}
|
|
1260
621
|
|
|
1261
622
|
if (agentV && projectV < agentV) {
|
|
1262
|
-
console.log(` ${yellow("
|
|
623
|
+
console.log(` ${yellow("⚠")} Project .soma/ is at ${cyan(`v${projectV}`)} , agent is at ${cyan(`v${agentV}`)} .`);
|
|
1263
624
|
console.log("");
|
|
1264
625
|
|
|
1265
|
-
// Tier 1: Auto-fix safe things right now
|
|
1266
626
|
let fixes = 0;
|
|
1267
627
|
const somaDir = join(process.cwd(), ".soma");
|
|
1268
628
|
|
|
1269
|
-
// Add missing settings keys
|
|
1270
629
|
const settingsPath = join(somaDir, "settings.json");
|
|
1271
630
|
if (existsSync(settingsPath)) {
|
|
1272
631
|
try {
|
|
@@ -1280,29 +639,26 @@ async function projectDoctor() {
|
|
|
1280
639
|
add("scratch", { autoInject: false });
|
|
1281
640
|
add("guard", { coreFiles: "warn", bashCommands: "warn", gitIdentity: null });
|
|
1282
641
|
add("checkpoints", { enabled: true, intervalMinutes: 5, squashOnPush: true });
|
|
1283
|
-
add("persona", { name: null, emoji: "
|
|
642
|
+
add("persona", { name: null, emoji: "σ" });
|
|
1284
643
|
add("inherit", { identity: true, protocols: true, muscles: true, tools: true });
|
|
1285
644
|
if (changed) writeFileSync(settingsPath, JSON.stringify(current, null, "\t") + "\n");
|
|
1286
645
|
} catch {}
|
|
1287
646
|
}
|
|
1288
647
|
|
|
1289
|
-
// Add missing body/ + templates
|
|
1290
648
|
const bodyDir = join(somaDir, "body");
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
649
|
+
let agentRoot = CORE_DIR;
|
|
650
|
+
try {
|
|
651
|
+
const realCore = readlinkSync(join(CORE_DIR, "core"));
|
|
652
|
+
if (realCore) {
|
|
653
|
+
const devRoot = dirname(realCore);
|
|
654
|
+
if (existsSync(join(devRoot, "body", "_public"))) agentRoot = devRoot;
|
|
655
|
+
}
|
|
656
|
+
} catch {}
|
|
657
|
+
if (!existsSync(join(agentRoot, "body", "_public"))) {
|
|
658
|
+
const parent = dirname(agentRoot);
|
|
659
|
+
if (existsSync(join(parent, "body", "_public"))) agentRoot = parent;
|
|
1298
660
|
}
|
|
1299
|
-
|
|
1300
|
-
// Also check dist/ parent (prod layout)
|
|
1301
|
-
if (!existsSync(join(agentRoot, "body", "_public"))) {
|
|
1302
|
-
const parent = dirname(agentRoot);
|
|
1303
|
-
if (existsSync(join(parent, "body", "_public"))) agentRoot = parent;
|
|
1304
|
-
}
|
|
1305
|
-
const bundledBody = join(agentRoot, "body", "_public");
|
|
661
|
+
const bundledBody = join(agentRoot, "body", "_public");
|
|
1306
662
|
if (existsSync(bundledBody)) {
|
|
1307
663
|
try {
|
|
1308
664
|
if (!existsSync(bodyDir)) mkdirSync(bodyDir, { recursive: true });
|
|
@@ -1313,7 +669,6 @@ async function projectDoctor() {
|
|
|
1313
669
|
} catch {}
|
|
1314
670
|
}
|
|
1315
671
|
|
|
1316
|
-
// Add missing protocols
|
|
1317
672
|
const protoDir = join(somaDir, "amps", "protocols");
|
|
1318
673
|
const bundledProtos = existsSync(join(CORE_DIR, "dist", "content", "protocols"))
|
|
1319
674
|
? join(CORE_DIR, "dist", "content", "protocols")
|
|
@@ -1327,7 +682,6 @@ async function projectDoctor() {
|
|
|
1327
682
|
}
|
|
1328
683
|
}
|
|
1329
684
|
|
|
1330
|
-
// Add missing bundled scripts
|
|
1331
685
|
const scriptsDir = join(somaDir, "amps", "scripts");
|
|
1332
686
|
const bundledScripts = existsSync(join(agentRoot, "dist", "content", "scripts"))
|
|
1333
687
|
? join(agentRoot, "dist", "content", "scripts")
|
|
@@ -1346,20 +700,18 @@ async function projectDoctor() {
|
|
|
1346
700
|
}
|
|
1347
701
|
}
|
|
1348
702
|
|
|
1349
|
-
// Bump version after fixes
|
|
1350
703
|
if (fixes > 0) {
|
|
1351
704
|
try {
|
|
1352
705
|
const s = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
1353
706
|
s.version = agentV;
|
|
1354
707
|
writeFileSync(settingsPath, JSON.stringify(s, null, "\t") + "\n");
|
|
1355
708
|
} catch {}
|
|
1356
|
-
console.log(` ${green("
|
|
709
|
+
console.log(` ${green("✓")} Applied ${fixes} automatic fixes`);
|
|
1357
710
|
const bc = existsSync(join(somaDir, "body")) ? readdirSync(join(somaDir, "body")).filter(f => f.endsWith(".md")).length : 0;
|
|
1358
711
|
const pc = existsSync(protoDir) ? readdirSync(protoDir).filter(f => f.endsWith(".md")).length : 0;
|
|
1359
712
|
console.log(` ${bc} body files, ${pc} protocols, settings updated`);
|
|
1360
713
|
console.log(` Version bumped to ${cyan(`v${agentV}`)}`);
|
|
1361
714
|
|
|
1362
|
-
// Scan + fix stale protocols (exist but differ from bundled)
|
|
1363
715
|
let staleUpdated = 0;
|
|
1364
716
|
let staleSkipped = [];
|
|
1365
717
|
if (bundledProtos && existsSync(protoDir)) {
|
|
@@ -1370,7 +722,6 @@ async function projectDoctor() {
|
|
|
1370
722
|
const bundledRaw = readFileSync(bundledFile, "utf-8");
|
|
1371
723
|
const strip = s => s.replace(/^(heat|loads|runs|last-run|heat-default):.*\n?/gm, "").trim();
|
|
1372
724
|
if (strip(projRaw) === strip(bundledRaw)) continue;
|
|
1373
|
-
// Preserve user's runtime fields (heat, loads) when updating content
|
|
1374
725
|
const heatLine = projRaw.match(/^heat:.*$/m);
|
|
1375
726
|
const loadsLine = projRaw.match(/^loads:.*$/m);
|
|
1376
727
|
let updated = bundledRaw;
|
|
@@ -1383,11 +734,11 @@ async function projectDoctor() {
|
|
|
1383
734
|
|
|
1384
735
|
console.log("");
|
|
1385
736
|
if (staleUpdated > 0) {
|
|
1386
|
-
console.log(` ${green("
|
|
1387
|
-
console.log(` ${dim("Heat and load counts preserved. Content updated
|
|
737
|
+
console.log(` ${green("✓")} ${staleUpdated} protocols updated to latest version`);
|
|
738
|
+
console.log(` ${dim("Heat and load counts preserved. Content updated.")}`);
|
|
1388
739
|
}
|
|
1389
740
|
if (staleSkipped.length > 0) {
|
|
1390
|
-
console.log(` ${yellow("
|
|
741
|
+
console.log(` ${yellow("⚠")} ${staleSkipped.length} protocols skipped (may be customized)`);
|
|
1391
742
|
}
|
|
1392
743
|
console.log("");
|
|
1393
744
|
const totalRemaining = staleSkipped.length;
|
|
@@ -1396,118 +747,41 @@ async function projectDoctor() {
|
|
|
1396
747
|
console.log(` ${dim("Remaining: " + totalRemaining + " items need review.")}`);
|
|
1397
748
|
console.log(` ${dim("For full migration:")} ${green("soma")} ${dim("then")} ${green("/soma doctor")}`);
|
|
1398
749
|
} else {
|
|
1399
|
-
console.log(` ${green("
|
|
750
|
+
console.log(` ${green("✓")} Full migration complete from CLI.`);
|
|
1400
751
|
console.log(` ${dim("No TUI session needed — all updates applied.")}`);
|
|
1401
752
|
}
|
|
1402
753
|
|
|
1403
|
-
// Write _doctor-pending.md
|
|
1404
|
-
// If CLI handled everything, write a brief "complete" note instead
|
|
754
|
+
// Write _doctor-pending.md
|
|
1405
755
|
try {
|
|
1406
756
|
const pendingPath = join(somaDir, "body", "_doctor-pending.md");
|
|
1407
757
|
if (staleSkipped.length === 0) {
|
|
1408
|
-
// Full migration done — write brief completion note
|
|
1409
758
|
const done = [
|
|
1410
|
-
"---",
|
|
1411
|
-
"type: template",
|
|
1412
|
-
"name: doctor-pending",
|
|
1413
|
-
"status: complete",
|
|
759
|
+
"---", "type: template", "name: doctor-pending", "status: complete",
|
|
1414
760
|
`created: ${new Date().toISOString().split("T")[0]}`,
|
|
1415
|
-
"description: CLI doctor completed full migration
|
|
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.",
|
|
761
|
+
"description: CLI doctor completed full migration", "---", "",
|
|
762
|
+
"# Doctor Update — Complete", "",
|
|
763
|
+
`Migrated from v${projectV} to v${agentV} on ${new Date().toISOString().split("T")[0]}.`,
|
|
764
|
+
`Applied: ${fixes} file fixes + ${staleUpdated} protocol updates.`, "",
|
|
765
|
+
"Run `/soma doctor` to verify, then delete this file.",
|
|
1425
766
|
];
|
|
1426
767
|
writeFileSync(pendingPath, done.join("\n"));
|
|
1427
|
-
} else {
|
|
1428
|
-
const pending = [
|
|
1429
|
-
"---",
|
|
1430
|
-
"type: template",
|
|
1431
|
-
"name: doctor-pending",
|
|
1432
|
-
"status: active",
|
|
1433
|
-
`created: ${new Date().toISOString().split("T")[0]}`,
|
|
1434
|
-
"description: Written by soma doctor CLI — tells the agent what was fixed and what needs attention",
|
|
1435
|
-
"---",
|
|
1436
|
-
"",
|
|
1437
|
-
"# Doctor Update — Pending",
|
|
1438
|
-
"",
|
|
1439
|
-
`The CLI doctor ran on ${new Date().toISOString().split("T")[0]} and updated this project from v${projectV} to v${agentV}.`,
|
|
1440
|
-
"",
|
|
1441
|
-
"## What the CLI fixed (Tier 1 — automatic, safe)",
|
|
1442
|
-
"",
|
|
1443
|
-
`- ${bc} body template files (added missing ones, preserved your customized files)`,
|
|
1444
|
-
`- ${pc} protocols present (added missing bundled protocols)`,
|
|
1445
|
-
`- Settings: added missing configuration sections with safe defaults`,
|
|
1446
|
-
`- Version bumped to v${agentV}`,
|
|
1447
|
-
"",
|
|
1448
|
-
`## What the CLI also fixed`,
|
|
1449
|
-
"",
|
|
1450
|
-
`- ${staleUpdated} protocols updated to latest version (heat/loads preserved)`,
|
|
1451
|
-
"",
|
|
1452
|
-
staleSkipped.length > 0 ? `## What still needs attention (${staleSkipped.length} items)` : "## Status: Complete",
|
|
1453
|
-
"",
|
|
1454
|
-
staleSkipped.length > 0
|
|
1455
|
-
? `**${staleSkipped.length} protocols** may be customized and were not auto-updated. The agent needs to:\n- Diff each against bundled version\n- Decide whether to update or preserve`
|
|
1456
|
-
: "All mechanical updates applied by CLI. The agent can verify with /soma doctor.",
|
|
1457
|
-
"",
|
|
1458
|
-
"**To complete the migration:**",
|
|
1459
|
-
"",
|
|
1460
|
-
"Read the migration phases that apply to your version jump:",
|
|
1461
|
-
"```",
|
|
1462
|
-
];
|
|
1463
|
-
// Find which phases apply (only from projectV onward)
|
|
1464
|
-
let agentRoot2 = CORE_DIR;
|
|
1465
|
-
try {
|
|
1466
|
-
const rc = readlinkSync(join(CORE_DIR, "core"));
|
|
1467
|
-
if (rc) { const dr = dirname(rc); if (existsSync(join(dr, "migrations", "phases"))) agentRoot2 = dr; }
|
|
1468
|
-
} catch {}
|
|
1469
|
-
if (!existsSync(join(agentRoot2, "migrations", "phases"))) {
|
|
1470
|
-
const pr = dirname(agentRoot2);
|
|
1471
|
-
if (existsSync(join(pr, "migrations", "phases"))) agentRoot2 = pr;
|
|
1472
|
-
}
|
|
1473
|
-
const phasesDir2 = join(agentRoot2, "migrations", "phases");
|
|
1474
|
-
if (existsSync(phasesDir2)) {
|
|
1475
|
-
const allPhases = readdirSync(phasesDir2).filter(f => f.endsWith(".md")).sort();
|
|
1476
|
-
const relevant = allPhases.filter(f => {
|
|
1477
|
-
const m = f.match(/^v([\d.]+)-to-v/);
|
|
1478
|
-
return m && m[1] >= projectV;
|
|
1479
|
-
});
|
|
1480
|
-
pending.push(`${relevant.length} phases apply (v${projectV} \u2192 v${agentV}):`);
|
|
1481
|
-
pending.push("\`\`\`");
|
|
1482
|
-
for (const f of relevant) {
|
|
1483
|
-
pending.push(" " + join(phasesDir2, f));
|
|
1484
|
-
}
|
|
1485
768
|
}
|
|
1486
|
-
|
|
1487
|
-
pending.push("");
|
|
1488
|
-
pending.push("Execute each phase's **Actions** section in order.");
|
|
1489
|
-
pending.push("After completing all phases, delete this file — it's no longer needed.");
|
|
1490
|
-
pending.push("");
|
|
1491
|
-
writeFileSync(pendingPath, pending.join("\n"));
|
|
1492
|
-
}
|
|
1493
|
-
} catch { /* non-fatal */ }
|
|
769
|
+
} catch {}
|
|
1494
770
|
} else {
|
|
1495
|
-
console.log(` ${green("
|
|
771
|
+
console.log(` ${green("✓")} Version bumped to ${cyan(`v${agentV}`)}`);
|
|
1496
772
|
console.log(` ${dim("No file changes needed — project structure is current.")}`);
|
|
1497
773
|
}
|
|
1498
774
|
} else {
|
|
1499
|
-
console.log(` ${green("
|
|
775
|
+
console.log(` ${green("✓")} Project version: ${cyan(`v${projectV}`)}`);
|
|
1500
776
|
}
|
|
1501
777
|
|
|
1502
778
|
console.log("");
|
|
1503
779
|
await healthCheck();
|
|
1504
780
|
}
|
|
1505
781
|
|
|
1506
|
-
|
|
1507
782
|
// ── Delegation ───────────────────────────────────────────────────────
|
|
1508
783
|
|
|
1509
784
|
async function delegateToCore() {
|
|
1510
|
-
// Pre-flight: verify runtime can start before delegating
|
|
1511
785
|
const piPkg = join(CORE_DIR, "node_modules", "@mariozechner", "pi-coding-agent");
|
|
1512
786
|
if (!existsSync(piPkg)) {
|
|
1513
787
|
console.log(` ${red("✗")} Runtime dependencies missing.`);
|
|
@@ -1528,7 +802,6 @@ async function delegateToCore() {
|
|
|
1528
802
|
return;
|
|
1529
803
|
}
|
|
1530
804
|
|
|
1531
|
-
const { execFileSync: execF } = await import("child_process");
|
|
1532
805
|
const passArgs = process.argv.slice(2);
|
|
1533
806
|
|
|
1534
807
|
const cliLocations = [
|
|
@@ -1536,9 +809,6 @@ async function delegateToCore() {
|
|
|
1536
809
|
{ path: join(CORE_DIR, "node_modules", ".bin", "pi"), type: "bin" },
|
|
1537
810
|
];
|
|
1538
811
|
|
|
1539
|
-
// Discover user extensions in project .soma/extensions/
|
|
1540
|
-
// Pi without piConfig only looks at .pi/extensions/, not .soma/extensions/
|
|
1541
|
-
// We pass them explicitly via -e flags
|
|
1542
812
|
const userExtArgs = [];
|
|
1543
813
|
const projectExtDir = join(process.cwd(), ".soma", "extensions");
|
|
1544
814
|
if (existsSync(projectExtDir)) {
|
|
@@ -1552,14 +822,8 @@ async function delegateToCore() {
|
|
|
1552
822
|
|
|
1553
823
|
const env = {
|
|
1554
824
|
...process.env,
|
|
1555
|
-
// Pi reads ENV_AGENT_DIR dynamically based on APP_NAME from piConfig.
|
|
1556
|
-
// With piConfig.name="soma", Pi looks for SOMA_CODING_AGENT_DIR.
|
|
1557
|
-
// Without piConfig (raw pi binary), it looks for PI_CODING_AGENT_DIR.
|
|
1558
|
-
// Set BOTH so delegation works regardless of piConfig load order.
|
|
1559
825
|
PI_CODING_AGENT_DIR: CORE_DIR,
|
|
1560
826
|
SOMA_CODING_AGENT_DIR: CORE_DIR,
|
|
1561
|
-
// Override Pi's package dir so it reads piConfig from soma-beta's package.json
|
|
1562
|
-
// This gives us APP_NAME="soma", CONFIG_DIR_NAME=".soma" → project .soma/ paths
|
|
1563
827
|
PI_PACKAGE_DIR: CORE_DIR,
|
|
1564
828
|
};
|
|
1565
829
|
|
|
@@ -1568,15 +832,13 @@ async function delegateToCore() {
|
|
|
1568
832
|
try {
|
|
1569
833
|
const allArgs = [...userExtArgs, ...passArgs];
|
|
1570
834
|
if (cli.type === "node") {
|
|
1571
|
-
|
|
835
|
+
execFileSync("node", [cli.path, ...allArgs], { stdio: "inherit", cwd: process.cwd(), env });
|
|
1572
836
|
} else {
|
|
1573
|
-
|
|
837
|
+
execFileSync(cli.path, allArgs, { stdio: "inherit", cwd: process.cwd(), env });
|
|
1574
838
|
}
|
|
1575
839
|
return;
|
|
1576
840
|
} catch (err) {
|
|
1577
|
-
// Non-zero exit from session is normal (user quit, ctrl+c)
|
|
1578
841
|
if (err.status) process.exit(err.status);
|
|
1579
|
-
// Module errors = broken install
|
|
1580
842
|
if (err.message && err.message.includes("MODULE_NOT_FOUND")) {
|
|
1581
843
|
console.log("");
|
|
1582
844
|
console.log(` ${red("✗")} Soma failed to start — missing dependencies.`);
|
|
@@ -1603,7 +865,6 @@ if (cmd === "--version" || cmd === "-v" || cmd === "-V") {
|
|
|
1603
865
|
showVersion();
|
|
1604
866
|
} else if (cmd === "--help" || cmd === "-h") {
|
|
1605
867
|
if (isInstalled()) {
|
|
1606
|
-
// Delegate to core — richer help with scripts, commands, hub
|
|
1607
868
|
await delegateToCore();
|
|
1608
869
|
} else {
|
|
1609
870
|
showHelp();
|
|
@@ -1616,13 +877,10 @@ if (cmd === "--version" || cmd === "-v" || cmd === "-V") {
|
|
|
1616
877
|
const hasSomaDir = existsSync(join(process.cwd(), ".soma"));
|
|
1617
878
|
|
|
1618
879
|
if (!runtimeInstalled) {
|
|
1619
|
-
// Not installed — run full install + setup
|
|
1620
880
|
await initSoma();
|
|
1621
881
|
} else if (hasProjectArgs || !hasSomaDir) {
|
|
1622
|
-
// Installed, project init (new project or --template/--orphan)
|
|
1623
882
|
await delegateToCore();
|
|
1624
883
|
} else {
|
|
1625
|
-
// Installed + .soma/ exists — check for updates + project staleness
|
|
1626
884
|
await checkAndUpdate();
|
|
1627
885
|
}
|
|
1628
886
|
} else if (cmd === "update") {
|
|
@@ -1632,10 +890,8 @@ if (cmd === "--version" || cmd === "-v" || cmd === "-V") {
|
|
|
1632
890
|
} else if (cmd === "status" || cmd === "health") {
|
|
1633
891
|
await healthCheck();
|
|
1634
892
|
} else if (isInstalled()) {
|
|
1635
|
-
// Core installed — delegate to runtime
|
|
1636
893
|
await delegateToCore();
|
|
1637
894
|
} else {
|
|
1638
|
-
// Check if user typed a known post-install command
|
|
1639
895
|
const postInstallCmds = ["focus", "inhale", "content", "install", "list", "map", "--map", "--preload"];
|
|
1640
896
|
if (cmd && postInstallCmds.includes(cmd)) {
|
|
1641
897
|
printSigma();
|
|
@@ -1644,7 +900,6 @@ if (cmd === "--version" || cmd === "-v" || cmd === "-V") {
|
|
|
1644
900
|
console.log(` Run ${green("soma init")} to install it.`);
|
|
1645
901
|
console.log("");
|
|
1646
902
|
} else {
|
|
1647
|
-
// Not installed or not verified — show welcome experience
|
|
1648
903
|
await showWelcome();
|
|
1649
904
|
}
|
|
1650
905
|
}
|