meetsoma 0.3.2 → 0.3.4
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 +26 -194
- package/dist/thin-cli.js +1587 -392
- package/package.json +12 -59
- package/bin/gum +0 -0
- package/dist/bun/cli.d.ts +0 -3
- package/dist/bun/cli.d.ts.map +0 -1
- package/dist/bun/cli.js +0 -7
- package/dist/bun/cli.js.map +0 -1
- package/dist/bun/register-bedrock.d.ts +0 -2
- package/dist/bun/register-bedrock.d.ts.map +0 -1
- package/dist/bun/register-bedrock.js +0 -4
- package/dist/bun/register-bedrock.js.map +0 -1
- package/dist/cli/args.d.ts +0 -49
- package/dist/cli/args.d.ts.map +0 -1
- package/dist/cli/args.js +0 -304
- package/dist/cli/args.js.map +0 -1
- package/dist/cli/config-selector.d.ts +0 -14
- package/dist/cli/config-selector.d.ts.map +0 -1
- package/dist/cli/config-selector.js +0 -31
- package/dist/cli/config-selector.js.map +0 -1
- package/dist/cli/file-processor.d.ts +0 -15
- package/dist/cli/file-processor.d.ts.map +0 -1
- package/dist/cli/file-processor.js +0 -83
- package/dist/cli/file-processor.js.map +0 -1
- package/dist/cli/initial-message.d.ts +0 -18
- package/dist/cli/initial-message.d.ts.map +0 -1
- package/dist/cli/initial-message.js +0 -22
- package/dist/cli/initial-message.js.map +0 -1
- package/dist/cli/list-models.d.ts +0 -9
- package/dist/cli/list-models.d.ts.map +0 -1
- package/dist/cli/list-models.js +0 -92
- package/dist/cli/list-models.js.map +0 -1
- package/dist/cli/session-picker.d.ts +0 -9
- package/dist/cli/session-picker.d.ts.map +0 -1
- package/dist/cli/session-picker.js +0 -35
- package/dist/cli/session-picker.js.map +0 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -601
- package/dist/cli.js.map +0 -1
- package/dist/config.d.ts +0 -68
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -203
- package/dist/config.js.map +0 -1
- package/dist/core/agent-session-runtime.d.ts +0 -134
- package/dist/core/agent-session-runtime.d.ts.map +0 -1
- package/dist/core/agent-session-runtime.js +0 -264
- package/dist/core/agent-session-runtime.js.map +0 -1
- package/dist/core/agent-session.d.ts +0 -585
- package/dist/core/agent-session.d.ts.map +0 -1
- package/dist/core/agent-session.js +0 -2497
- package/dist/core/agent-session.js.map +0 -1
- package/dist/core/auth-storage.d.ts +0 -132
- package/dist/core/auth-storage.d.ts.map +0 -1
- package/dist/core/auth-storage.js +0 -422
- package/dist/core/auth-storage.js.map +0 -1
- package/dist/core/bash-executor.d.ts +0 -46
- package/dist/core/bash-executor.d.ts.map +0 -1
- package/dist/core/bash-executor.js +0 -113
- package/dist/core/bash-executor.js.map +0 -1
- package/dist/core/compaction/branch-summarization.d.ts +0 -88
- package/dist/core/compaction/branch-summarization.d.ts.map +0 -1
- package/dist/core/compaction/branch-summarization.js +0 -243
- package/dist/core/compaction/branch-summarization.js.map +0 -1
- package/dist/core/compaction/compaction.d.ts +0 -121
- package/dist/core/compaction/compaction.d.ts.map +0 -1
- package/dist/core/compaction/compaction.js +0 -613
- package/dist/core/compaction/compaction.js.map +0 -1
- package/dist/core/compaction/index.d.ts +0 -7
- package/dist/core/compaction/index.d.ts.map +0 -1
- package/dist/core/compaction/index.js +0 -7
- package/dist/core/compaction/index.js.map +0 -1
- package/dist/core/compaction/utils.d.ts +0 -38
- package/dist/core/compaction/utils.d.ts.map +0 -1
- package/dist/core/compaction/utils.js +0 -153
- package/dist/core/compaction/utils.js.map +0 -1
- package/dist/core/defaults.d.ts +0 -3
- package/dist/core/defaults.d.ts.map +0 -1
- package/dist/core/defaults.js +0 -2
- package/dist/core/defaults.js.map +0 -1
- package/dist/core/diagnostics.d.ts +0 -15
- package/dist/core/diagnostics.d.ts.map +0 -1
- package/dist/core/diagnostics.js +0 -2
- package/dist/core/diagnostics.js.map +0 -1
- package/dist/core/event-bus.d.ts +0 -9
- package/dist/core/event-bus.d.ts.map +0 -1
- package/dist/core/event-bus.js +0 -25
- package/dist/core/event-bus.js.map +0 -1
- package/dist/core/exec.d.ts +0 -29
- package/dist/core/exec.d.ts.map +0 -1
- package/dist/core/exec.js +0 -75
- package/dist/core/exec.js.map +0 -1
- package/dist/core/export-html/ansi-to-html.d.ts +0 -22
- package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
- package/dist/core/export-html/ansi-to-html.js +0 -249
- package/dist/core/export-html/ansi-to-html.js.map +0 -1
- package/dist/core/export-html/index.d.ts +0 -37
- package/dist/core/export-html/index.d.ts.map +0 -1
- package/dist/core/export-html/index.js +0 -224
- package/dist/core/export-html/index.js.map +0 -1
- package/dist/core/export-html/template.css +0 -1001
- package/dist/core/export-html/template.html +0 -55
- package/dist/core/export-html/template.js +0 -1690
- package/dist/core/export-html/tool-renderer.d.ts +0 -40
- package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
- package/dist/core/export-html/tool-renderer.js +0 -95
- package/dist/core/export-html/tool-renderer.js.map +0 -1
- package/dist/core/export-html/vendor/highlight.min.js +0 -1213
- package/dist/core/export-html/vendor/marked.min.js +0 -6
- package/dist/core/extensions/index.d.ts +0 -12
- package/dist/core/extensions/index.d.ts.map +0 -1
- package/dist/core/extensions/index.js +0 -9
- package/dist/core/extensions/index.js.map +0 -1
- package/dist/core/extensions/loader.d.ts +0 -25
- package/dist/core/extensions/loader.d.ts.map +0 -1
- package/dist/core/extensions/loader.js +0 -436
- package/dist/core/extensions/loader.js.map +0 -1
- package/dist/core/extensions/runner.d.ts +0 -148
- package/dist/core/extensions/runner.d.ts.map +0 -1
- package/dist/core/extensions/runner.js +0 -700
- package/dist/core/extensions/runner.js.map +0 -1
- package/dist/core/extensions/types.d.ts +0 -1076
- package/dist/core/extensions/types.d.ts.map +0 -1
- package/dist/core/extensions/types.js +0 -35
- package/dist/core/extensions/types.js.map +0 -1
- package/dist/core/extensions/wrapper.d.ts +0 -20
- package/dist/core/extensions/wrapper.d.ts.map +0 -1
- package/dist/core/extensions/wrapper.js +0 -22
- package/dist/core/extensions/wrapper.js.map +0 -1
- package/dist/core/footer-data-provider.d.ts +0 -48
- package/dist/core/footer-data-provider.d.ts.map +0 -1
- package/dist/core/footer-data-provider.js +0 -314
- package/dist/core/footer-data-provider.js.map +0 -1
- package/dist/core/index.d.ts +0 -11
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -11
- package/dist/core/index.js.map +0 -1
- package/dist/core/keybindings.d.ts +0 -285
- package/dist/core/keybindings.d.ts.map +0 -1
- package/dist/core/keybindings.js +0 -251
- package/dist/core/keybindings.js.map +0 -1
- package/dist/core/messages.d.ts +0 -77
- package/dist/core/messages.d.ts.map +0 -1
- package/dist/core/messages.js +0 -123
- package/dist/core/messages.js.map +0 -1
- package/dist/core/model-registry.d.ts +0 -132
- package/dist/core/model-registry.d.ts.map +0 -1
- package/dist/core/model-registry.js +0 -583
- package/dist/core/model-registry.js.map +0 -1
- package/dist/core/model-resolver.d.ts +0 -110
- package/dist/core/model-resolver.d.ts.map +0 -1
- package/dist/core/model-resolver.js +0 -486
- package/dist/core/model-resolver.js.map +0 -1
- package/dist/core/output-guard.d.ts +0 -6
- package/dist/core/output-guard.d.ts.map +0 -1
- package/dist/core/output-guard.js +0 -59
- package/dist/core/output-guard.js.map +0 -1
- package/dist/core/package-manager.d.ts +0 -172
- package/dist/core/package-manager.d.ts.map +0 -1
- package/dist/core/package-manager.js +0 -1783
- package/dist/core/package-manager.js.map +0 -1
- package/dist/core/prompt-templates.d.ts +0 -51
- package/dist/core/prompt-templates.d.ts.map +0 -1
- package/dist/core/prompt-templates.js +0 -249
- package/dist/core/prompt-templates.js.map +0 -1
- package/dist/core/resolve-config-value.d.ts +0 -23
- package/dist/core/resolve-config-value.d.ts.map +0 -1
- package/dist/core/resolve-config-value.js +0 -126
- package/dist/core/resolve-config-value.js.map +0 -1
- package/dist/core/resource-loader.d.ts +0 -185
- package/dist/core/resource-loader.d.ts.map +0 -1
- package/dist/core/resource-loader.js +0 -698
- package/dist/core/resource-loader.js.map +0 -1
- package/dist/core/sdk.d.ts +0 -93
- package/dist/core/sdk.d.ts.map +0 -1
- package/dist/core/sdk.js +0 -236
- package/dist/core/sdk.js.map +0 -1
- package/dist/core/session-manager.d.ts +0 -332
- package/dist/core/session-manager.d.ts.map +0 -1
- package/dist/core/session-manager.js +0 -1104
- package/dist/core/session-manager.js.map +0 -1
- package/dist/core/settings-manager.d.ts +0 -237
- package/dist/core/settings-manager.d.ts.map +0 -1
- package/dist/core/settings-manager.js +0 -702
- package/dist/core/settings-manager.js.map +0 -1
- package/dist/core/skills.d.ts +0 -60
- package/dist/core/skills.d.ts.map +0 -1
- package/dist/core/skills.js +0 -409
- package/dist/core/skills.js.map +0 -1
- package/dist/core/slash-commands.d.ts +0 -14
- package/dist/core/slash-commands.d.ts.map +0 -1
- package/dist/core/slash-commands.js +0 -23
- package/dist/core/slash-commands.js.map +0 -1
- package/dist/core/source-info.d.ts +0 -18
- package/dist/core/source-info.d.ts.map +0 -1
- package/dist/core/source-info.js +0 -19
- package/dist/core/source-info.js.map +0 -1
- package/dist/core/system-prompt.d.ts +0 -28
- package/dist/core/system-prompt.d.ts.map +0 -1
- package/dist/core/system-prompt.js +0 -116
- package/dist/core/system-prompt.js.map +0 -1
- package/dist/core/timings.d.ts +0 -8
- package/dist/core/timings.d.ts.map +0 -1
- package/dist/core/timings.js +0 -31
- package/dist/core/timings.js.map +0 -1
- package/dist/core/tools/bash.d.ts +0 -73
- package/dist/core/tools/bash.d.ts.map +0 -1
- package/dist/core/tools/bash.js +0 -342
- package/dist/core/tools/bash.js.map +0 -1
- package/dist/core/tools/edit-diff.d.ts +0 -85
- package/dist/core/tools/edit-diff.d.ts.map +0 -1
- package/dist/core/tools/edit-diff.js +0 -337
- package/dist/core/tools/edit-diff.js.map +0 -1
- package/dist/core/tools/edit.d.ts +0 -53
- package/dist/core/tools/edit.d.ts.map +0 -1
- package/dist/core/tools/edit.js +0 -196
- package/dist/core/tools/edit.js.map +0 -1
- package/dist/core/tools/file-mutation-queue.d.ts +0 -6
- package/dist/core/tools/file-mutation-queue.d.ts.map +0 -1
- package/dist/core/tools/file-mutation-queue.js +0 -37
- package/dist/core/tools/file-mutation-queue.js.map +0 -1
- package/dist/core/tools/find.d.ts +0 -46
- package/dist/core/tools/find.d.ts.map +0 -1
- package/dist/core/tools/find.js +0 -258
- package/dist/core/tools/find.js.map +0 -1
- package/dist/core/tools/grep.d.ts +0 -56
- package/dist/core/tools/grep.d.ts.map +0 -1
- package/dist/core/tools/grep.js +0 -293
- package/dist/core/tools/grep.js.map +0 -1
- package/dist/core/tools/index.d.ts +0 -115
- package/dist/core/tools/index.d.ts.map +0 -1
- package/dist/core/tools/index.js +0 -86
- package/dist/core/tools/index.js.map +0 -1
- package/dist/core/tools/ls.d.ts +0 -46
- package/dist/core/tools/ls.d.ts.map +0 -1
- package/dist/core/tools/ls.js +0 -172
- package/dist/core/tools/ls.js.map +0 -1
- package/dist/core/tools/path-utils.d.ts +0 -8
- package/dist/core/tools/path-utils.d.ts.map +0 -1
- package/dist/core/tools/path-utils.js +0 -81
- package/dist/core/tools/path-utils.js.map +0 -1
- package/dist/core/tools/read.d.ts +0 -46
- package/dist/core/tools/read.d.ts.map +0 -1
- package/dist/core/tools/read.js +0 -225
- package/dist/core/tools/read.js.map +0 -1
- package/dist/core/tools/render-utils.d.ts +0 -21
- package/dist/core/tools/render-utils.d.ts.map +0 -1
- package/dist/core/tools/render-utils.js +0 -49
- package/dist/core/tools/render-utils.js.map +0 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts +0 -14
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +0 -1
- package/dist/core/tools/tool-definition-wrapper.js +0 -32
- package/dist/core/tools/tool-definition-wrapper.js.map +0 -1
- package/dist/core/tools/truncate.d.ts +0 -70
- package/dist/core/tools/truncate.d.ts.map +0 -1
- package/dist/core/tools/truncate.js +0 -205
- package/dist/core/tools/truncate.js.map +0 -1
- package/dist/core/tools/write.d.ts +0 -35
- package/dist/core/tools/write.d.ts.map +0 -1
- package/dist/core/tools/write.js +0 -216
- package/dist/core/tools/write.js.map +0 -1
- package/dist/index.d.ts +0 -28
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -43
- package/dist/index.js.map +0 -1
- package/dist/lib/config.js +0 -22
- package/dist/lib/detect.js +0 -94
- package/dist/lib/display.js +0 -182
- package/dist/main.d.ts +0 -8
- package/dist/main.d.ts.map +0 -1
- package/dist/main.js +0 -806
- package/dist/main.js.map +0 -1
- package/dist/migrations.d.ts +0 -33
- package/dist/migrations.d.ts.map +0 -1
- package/dist/migrations.js +0 -261
- package/dist/migrations.js.map +0 -1
- package/dist/modes/index.d.ts +0 -9
- package/dist/modes/index.d.ts.map +0 -1
- package/dist/modes/index.js +0 -8
- package/dist/modes/index.js.map +0 -1
- package/dist/modes/interactive/components/armin.d.ts +0 -34
- package/dist/modes/interactive/components/armin.d.ts.map +0 -1
- package/dist/modes/interactive/components/armin.js +0 -333
- package/dist/modes/interactive/components/armin.js.map +0 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +0 -18
- package/dist/modes/interactive/components/assistant-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/assistant-message.js +0 -107
- package/dist/modes/interactive/components/assistant-message.js.map +0 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +0 -34
- package/dist/modes/interactive/components/bash-execution.d.ts.map +0 -1
- package/dist/modes/interactive/components/bash-execution.js +0 -175
- package/dist/modes/interactive/components/bash-execution.js.map +0 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +0 -16
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +0 -1
- package/dist/modes/interactive/components/bordered-loader.js +0 -51
- package/dist/modes/interactive/components/bordered-loader.js.map +0 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +0 -16
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/branch-summary-message.js +0 -44
- package/dist/modes/interactive/components/branch-summary-message.js.map +0 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -16
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +0 -45
- package/dist/modes/interactive/components/compaction-summary-message.js.map +0 -1
- package/dist/modes/interactive/components/config-selector.d.ts +0 -71
- package/dist/modes/interactive/components/config-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/config-selector.js +0 -479
- package/dist/modes/interactive/components/config-selector.js.map +0 -1
- package/dist/modes/interactive/components/countdown-timer.d.ts +0 -14
- package/dist/modes/interactive/components/countdown-timer.d.ts.map +0 -1
- package/dist/modes/interactive/components/countdown-timer.js +0 -33
- package/dist/modes/interactive/components/countdown-timer.js.map +0 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +0 -21
- package/dist/modes/interactive/components/custom-editor.d.ts.map +0 -1
- package/dist/modes/interactive/components/custom-editor.js +0 -70
- package/dist/modes/interactive/components/custom-editor.js.map +0 -1
- package/dist/modes/interactive/components/custom-message.d.ts +0 -20
- package/dist/modes/interactive/components/custom-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/custom-message.js +0 -79
- package/dist/modes/interactive/components/custom-message.js.map +0 -1
- package/dist/modes/interactive/components/daxnuts.d.ts +0 -23
- package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
- package/dist/modes/interactive/components/daxnuts.js +0 -140
- package/dist/modes/interactive/components/daxnuts.js.map +0 -1
- package/dist/modes/interactive/components/diff.d.ts +0 -12
- package/dist/modes/interactive/components/diff.d.ts.map +0 -1
- package/dist/modes/interactive/components/diff.js +0 -133
- package/dist/modes/interactive/components/diff.js.map +0 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts +0 -15
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +0 -1
- package/dist/modes/interactive/components/dynamic-border.js +0 -21
- package/dist/modes/interactive/components/dynamic-border.js.map +0 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +0 -20
- package/dist/modes/interactive/components/extension-editor.d.ts.map +0 -1
- package/dist/modes/interactive/components/extension-editor.js +0 -111
- package/dist/modes/interactive/components/extension-editor.js.map +0 -1
- package/dist/modes/interactive/components/extension-input.d.ts +0 -23
- package/dist/modes/interactive/components/extension-input.d.ts.map +0 -1
- package/dist/modes/interactive/components/extension-input.js +0 -61
- package/dist/modes/interactive/components/extension-input.js.map +0 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +0 -24
- package/dist/modes/interactive/components/extension-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/extension-selector.js +0 -78
- package/dist/modes/interactive/components/extension-selector.js.map +0 -1
- package/dist/modes/interactive/components/footer.d.ts +0 -27
- package/dist/modes/interactive/components/footer.d.ts.map +0 -1
- package/dist/modes/interactive/components/footer.js +0 -201
- package/dist/modes/interactive/components/footer.js.map +0 -1
- package/dist/modes/interactive/components/index.d.ts +0 -32
- package/dist/modes/interactive/components/index.d.ts.map +0 -1
- package/dist/modes/interactive/components/index.js +0 -33
- package/dist/modes/interactive/components/index.js.map +0 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts +0 -8
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +0 -1
- package/dist/modes/interactive/components/keybinding-hints.js +0 -22
- package/dist/modes/interactive/components/keybinding-hints.js.map +0 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +0 -42
- package/dist/modes/interactive/components/login-dialog.d.ts.map +0 -1
- package/dist/modes/interactive/components/login-dialog.js +0 -145
- package/dist/modes/interactive/components/login-dialog.js.map +0 -1
- package/dist/modes/interactive/components/model-selector.d.ts +0 -47
- package/dist/modes/interactive/components/model-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/model-selector.js +0 -275
- package/dist/modes/interactive/components/model-selector.js.map +0 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +0 -19
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/oauth-selector.js +0 -97
- package/dist/modes/interactive/components/oauth-selector.js.map +0 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +0 -49
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +0 -275
- package/dist/modes/interactive/components/scoped-models-selector.js.map +0 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts +0 -23
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +0 -1
- package/dist/modes/interactive/components/session-selector-search.js +0 -155
- package/dist/modes/interactive/components/session-selector-search.js.map +0 -1
- package/dist/modes/interactive/components/session-selector.d.ts +0 -95
- package/dist/modes/interactive/components/session-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/session-selector.js +0 -848
- package/dist/modes/interactive/components/session-selector.js.map +0 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +0 -58
- package/dist/modes/interactive/components/settings-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/settings-selector.js +0 -301
- package/dist/modes/interactive/components/settings-selector.js.map +0 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts +0 -10
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/show-images-selector.js +0 -39
- package/dist/modes/interactive/components/show-images-selector.js.map +0 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +0 -17
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +0 -47
- package/dist/modes/interactive/components/skill-invocation-message.js.map +0 -1
- package/dist/modes/interactive/components/theme-selector.d.ts +0 -11
- package/dist/modes/interactive/components/theme-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/theme-selector.js +0 -50
- package/dist/modes/interactive/components/theme-selector.js.map +0 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts +0 -11
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/thinking-selector.js +0 -51
- package/dist/modes/interactive/components/thinking-selector.js.map +0 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +0 -58
- package/dist/modes/interactive/components/tool-execution.d.ts.map +0 -1
- package/dist/modes/interactive/components/tool-execution.js +0 -274
- package/dist/modes/interactive/components/tool-execution.js.map +0 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +0 -89
- package/dist/modes/interactive/components/tree-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/tree-selector.js +0 -1084
- package/dist/modes/interactive/components/tree-selector.js.map +0 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts +0 -30
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/user-message-selector.js +0 -113
- package/dist/modes/interactive/components/user-message-selector.js.map +0 -1
- package/dist/modes/interactive/components/user-message.d.ts +0 -9
- package/dist/modes/interactive/components/user-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/user-message.js +0 -28
- package/dist/modes/interactive/components/user-message.js.map +0 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts +0 -24
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +0 -1
- package/dist/modes/interactive/components/visual-truncate.js +0 -33
- package/dist/modes/interactive/components/visual-truncate.js.map +0 -1
- package/dist/modes/interactive/interactive-mode.d.ts +0 -318
- package/dist/modes/interactive/interactive-mode.d.ts.map +0 -1
- package/dist/modes/interactive/interactive-mode.js +0 -3907
- package/dist/modes/interactive/interactive-mode.js.map +0 -1
- package/dist/modes/interactive/theme/dark.json +0 -85
- package/dist/modes/interactive/theme/light.json +0 -84
- package/dist/modes/interactive/theme/theme-schema.json +0 -335
- package/dist/modes/interactive/theme/theme.d.ts +0 -81
- package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
- package/dist/modes/interactive/theme/theme.js +0 -970
- package/dist/modes/interactive/theme/theme.js.map +0 -1
- package/dist/modes/print-mode.d.ts +0 -28
- package/dist/modes/print-mode.d.ts.map +0 -1
- package/dist/modes/print-mode.js +0 -108
- package/dist/modes/print-mode.js.map +0 -1
- package/dist/modes/rpc/jsonl.d.ts +0 -17
- package/dist/modes/rpc/jsonl.d.ts.map +0 -1
- package/dist/modes/rpc/jsonl.js +0 -49
- package/dist/modes/rpc/jsonl.js.map +0 -1
- package/dist/modes/rpc/rpc-client.d.ts +0 -217
- package/dist/modes/rpc/rpc-client.d.ts.map +0 -1
- package/dist/modes/rpc/rpc-client.js +0 -401
- package/dist/modes/rpc/rpc-client.js.map +0 -1
- package/dist/modes/rpc/rpc-mode.d.ts +0 -20
- package/dist/modes/rpc/rpc-mode.d.ts.map +0 -1
- package/dist/modes/rpc/rpc-mode.js +0 -542
- package/dist/modes/rpc/rpc-mode.js.map +0 -1
- package/dist/modes/rpc/rpc-types.d.ts +0 -408
- package/dist/modes/rpc/rpc-types.d.ts.map +0 -1
- package/dist/modes/rpc/rpc-types.js +0 -8
- package/dist/modes/rpc/rpc-types.js.map +0 -1
- package/dist/utils/changelog.d.ts +0 -21
- package/dist/utils/changelog.d.ts.map +0 -1
- package/dist/utils/changelog.js +0 -87
- package/dist/utils/changelog.js.map +0 -1
- package/dist/utils/child-process.d.ts +0 -11
- package/dist/utils/child-process.d.ts.map +0 -1
- package/dist/utils/child-process.js +0 -78
- package/dist/utils/child-process.js.map +0 -1
- package/dist/utils/clipboard-image.d.ts +0 -11
- package/dist/utils/clipboard-image.d.ts.map +0 -1
- package/dist/utils/clipboard-image.js +0 -245
- package/dist/utils/clipboard-image.js.map +0 -1
- package/dist/utils/clipboard-native.d.ts +0 -8
- package/dist/utils/clipboard-native.d.ts.map +0 -1
- package/dist/utils/clipboard-native.js +0 -14
- package/dist/utils/clipboard-native.js.map +0 -1
- package/dist/utils/clipboard.d.ts +0 -2
- package/dist/utils/clipboard.d.ts.map +0 -1
- package/dist/utils/clipboard.js +0 -78
- package/dist/utils/clipboard.js.map +0 -1
- package/dist/utils/exif-orientation.d.ts +0 -5
- package/dist/utils/exif-orientation.d.ts.map +0 -1
- package/dist/utils/exif-orientation.js +0 -158
- package/dist/utils/exif-orientation.js.map +0 -1
- package/dist/utils/frontmatter.d.ts +0 -8
- package/dist/utils/frontmatter.d.ts.map +0 -1
- package/dist/utils/frontmatter.js +0 -26
- package/dist/utils/frontmatter.js.map +0 -1
- package/dist/utils/git.d.ts +0 -26
- package/dist/utils/git.d.ts.map +0 -1
- package/dist/utils/git.js +0 -163
- package/dist/utils/git.js.map +0 -1
- package/dist/utils/image-convert.d.ts +0 -9
- package/dist/utils/image-convert.d.ts.map +0 -1
- package/dist/utils/image-convert.js +0 -39
- package/dist/utils/image-convert.js.map +0 -1
- package/dist/utils/image-resize.d.ts +0 -36
- package/dist/utils/image-resize.d.ts.map +0 -1
- package/dist/utils/image-resize.js +0 -137
- package/dist/utils/image-resize.js.map +0 -1
- package/dist/utils/mime.d.ts +0 -2
- package/dist/utils/mime.d.ts.map +0 -1
- package/dist/utils/mime.js +0 -26
- package/dist/utils/mime.js.map +0 -1
- package/dist/utils/photon.d.ts +0 -21
- package/dist/utils/photon.d.ts.map +0 -1
- package/dist/utils/photon.js +0 -121
- package/dist/utils/photon.js.map +0 -1
- package/dist/utils/shell.d.ts +0 -26
- package/dist/utils/shell.d.ts.map +0 -1
- package/dist/utils/shell.js +0 -186
- package/dist/utils/shell.js.map +0 -1
- package/dist/utils/sleep.d.ts +0 -5
- package/dist/utils/sleep.d.ts.map +0 -1
- package/dist/utils/sleep.js +0 -17
- package/dist/utils/sleep.js.map +0 -1
- package/dist/utils/tools-manager.d.ts +0 -3
- package/dist/utils/tools-manager.d.ts.map +0 -1
- package/dist/utils/tools-manager.js +0 -252
- package/dist/utils/tools-manager.js.map +0 -1
- package/dist/welcome/about.js +0 -50
- package/dist/welcome/auth.js +0 -126
- package/dist/welcome/intro.js +0 -90
- package/dist/welcome/qa.js +0 -131
- package/scripts/install-gum.sh +0 -141
package/dist/thin-cli.js
CHANGED
|
@@ -1,51 +1,1263 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// ../../cli/dist/lib/display.js
|
|
13
|
+
var display_exports = {};
|
|
14
|
+
__export(display_exports, {
|
|
15
|
+
bold: () => bold,
|
|
16
|
+
confirm: () => confirm,
|
|
17
|
+
confirmYN: () => confirmYN,
|
|
18
|
+
cyan: () => cyan,
|
|
19
|
+
dim: () => dim,
|
|
20
|
+
green: () => green,
|
|
21
|
+
italic: () => italic,
|
|
22
|
+
magenta: () => magenta,
|
|
23
|
+
printSigma: () => printSigma,
|
|
24
|
+
readLine: () => readLine,
|
|
25
|
+
readSecret: () => readSecret,
|
|
26
|
+
red: () => red,
|
|
27
|
+
typeOut: () => typeOut,
|
|
28
|
+
typeParagraph: () => typeParagraph,
|
|
29
|
+
waitForKey: () => waitForKey,
|
|
30
|
+
white: () => white,
|
|
31
|
+
wrapText: () => wrapText,
|
|
32
|
+
yellow: () => yellow
|
|
33
|
+
});
|
|
34
|
+
function printSigma() {
|
|
35
|
+
console.log("");
|
|
36
|
+
console.log(cyan(" \u03C3"));
|
|
37
|
+
console.log("");
|
|
38
|
+
}
|
|
39
|
+
function sleep(ms) {
|
|
40
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
41
|
+
}
|
|
42
|
+
async function typeOut(text, opts = {}) {
|
|
43
|
+
if (!process.stdout.isTTY) {
|
|
44
|
+
process.stdout.write(text);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
let pace = 1;
|
|
48
|
+
let i = 0;
|
|
49
|
+
while (i < text.length) {
|
|
50
|
+
const remaining = text.slice(i);
|
|
51
|
+
const ansi = remaining.match(/^\x1b\[[0-9;]*m/);
|
|
52
|
+
if (ansi) {
|
|
53
|
+
process.stdout.write(ansi[0]);
|
|
54
|
+
i += ansi[0].length;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const ch = text[i];
|
|
58
|
+
const next = text[i + 1] || "";
|
|
59
|
+
process.stdout.write(ch);
|
|
60
|
+
i++;
|
|
61
|
+
pace += (Math.random() - 0.5) * 0.15;
|
|
62
|
+
pace = Math.max(0.6, Math.min(1.4, pace));
|
|
63
|
+
if (ch === "\n") {
|
|
64
|
+
await sleep(58 * pace);
|
|
65
|
+
} else if (".!?".includes(ch) && (next === " " || next === "\n" || next === "")) {
|
|
66
|
+
await sleep((230 + Math.random() * 175) * pace);
|
|
67
|
+
} else if (ch === "," || ch === ";" || ch === ":") {
|
|
68
|
+
await sleep((70 + Math.random() * 46) * pace);
|
|
69
|
+
} else if (ch === "\u2014" || ch === "\u2013") {
|
|
70
|
+
await sleep((92 + Math.random() * 70) * pace);
|
|
71
|
+
} else if (ch === " ") {
|
|
72
|
+
await sleep((9 + Math.random() * 23) * pace);
|
|
73
|
+
} else {
|
|
74
|
+
await sleep((6 + Math.random() * 14) * pace);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function typeParagraph(text, indent = " ", width = 58) {
|
|
79
|
+
const words = text.split(" ");
|
|
80
|
+
let line = indent;
|
|
81
|
+
const lines = [];
|
|
82
|
+
for (const word of words) {
|
|
83
|
+
if (line.length + word.length > width + indent.length && line.trim()) {
|
|
84
|
+
lines.push(line);
|
|
85
|
+
line = indent + word;
|
|
86
|
+
} else {
|
|
87
|
+
line += (line.trim() ? " " : "") + word;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (line.trim()) lines.push(line);
|
|
91
|
+
await typeOut(lines.join("\n") + "\n");
|
|
92
|
+
}
|
|
93
|
+
function wrapText(text, indent = " ", width = 58) {
|
|
94
|
+
const words = text.split(" ");
|
|
95
|
+
const lines = [];
|
|
96
|
+
let line = indent;
|
|
97
|
+
for (const word of words) {
|
|
98
|
+
if (line.length + word.length > width + indent.length && line.trim()) {
|
|
99
|
+
lines.push(line);
|
|
100
|
+
line = indent + word;
|
|
101
|
+
} else {
|
|
102
|
+
line += (line.trim() ? " " : "") + word;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (line.trim()) lines.push(line);
|
|
106
|
+
return lines.join("\n");
|
|
107
|
+
}
|
|
108
|
+
function waitForKey(prompt) {
|
|
109
|
+
return new Promise((resolve) => {
|
|
110
|
+
process.stdout.write(prompt);
|
|
111
|
+
if (!process.stdin.isTTY) {
|
|
112
|
+
resolve("");
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
process.stdin.setRawMode(true);
|
|
116
|
+
process.stdin.resume();
|
|
117
|
+
process.stdin.setEncoding("utf-8");
|
|
118
|
+
process.stdin.once("data", (key) => {
|
|
119
|
+
process.stdin.setRawMode(false);
|
|
120
|
+
process.stdin.pause();
|
|
121
|
+
process.stdout.write("\n");
|
|
122
|
+
if (key === "") process.exit(0);
|
|
123
|
+
resolve(key);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
async function confirm(prompt) {
|
|
128
|
+
const key = await waitForKey(`${prompt} ${dim("[Enter]")} `);
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
async function confirmYN(prompt) {
|
|
132
|
+
const key = await waitForKey(`${prompt} ${dim("[y/n]")} `);
|
|
133
|
+
return key.toLowerCase() === "y";
|
|
134
|
+
}
|
|
135
|
+
function readLine(prompt) {
|
|
136
|
+
return new Promise((resolve) => {
|
|
137
|
+
process.stdout.write(prompt);
|
|
138
|
+
if (!process.stdin.isTTY) {
|
|
139
|
+
resolve("");
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
process.stdin.setRawMode(false);
|
|
143
|
+
process.stdin.resume();
|
|
144
|
+
process.stdin.setEncoding("utf-8");
|
|
145
|
+
let buf = "";
|
|
146
|
+
const onData = (chunk) => {
|
|
147
|
+
buf += chunk;
|
|
148
|
+
if (buf.includes("\n")) {
|
|
149
|
+
process.stdin.pause();
|
|
150
|
+
process.stdin.removeListener("data", onData);
|
|
151
|
+
resolve(buf.trim());
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
process.stdin.on("data", onData);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
function readSecret(prompt) {
|
|
158
|
+
return new Promise((resolve) => {
|
|
159
|
+
process.stdout.write(prompt);
|
|
160
|
+
if (!process.stdin.isTTY) {
|
|
161
|
+
resolve("");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
process.stdin.setRawMode(true);
|
|
165
|
+
process.stdin.resume();
|
|
166
|
+
process.stdin.setEncoding("utf-8");
|
|
167
|
+
let buf = "";
|
|
168
|
+
const onData = (chunk) => {
|
|
169
|
+
for (const ch of chunk) {
|
|
170
|
+
if (ch === "\r" || ch === "\n") {
|
|
171
|
+
process.stdin.setRawMode(false);
|
|
172
|
+
process.stdin.pause();
|
|
173
|
+
process.stdin.removeListener("data", onData);
|
|
174
|
+
process.stdout.write("\n");
|
|
175
|
+
resolve(buf);
|
|
176
|
+
return;
|
|
177
|
+
} else if (ch === "\x7F" || ch === "\b") {
|
|
178
|
+
if (buf.length > 0) {
|
|
179
|
+
buf = buf.slice(0, -1);
|
|
180
|
+
process.stdout.write("\b \b");
|
|
181
|
+
}
|
|
182
|
+
} else if (ch === "") {
|
|
183
|
+
process.stdout.write("\n");
|
|
184
|
+
process.exit(0);
|
|
185
|
+
} else if (ch >= " ") {
|
|
186
|
+
buf += ch;
|
|
187
|
+
process.stdout.write("\u2022");
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
process.stdin.on("data", onData);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
var bold, dim, italic, cyan, green, yellow, red, magenta, white;
|
|
195
|
+
var init_display = __esm({
|
|
196
|
+
"../../cli/dist/lib/display.js"() {
|
|
197
|
+
bold = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
198
|
+
dim = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
199
|
+
italic = (s) => `\x1B[3m${s}\x1B[0m`;
|
|
200
|
+
cyan = (s) => `\x1B[36m${s}\x1B[0m`;
|
|
201
|
+
green = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
202
|
+
yellow = (s) => `\x1B[33m${s}\x1B[0m`;
|
|
203
|
+
red = (s) => `\x1B[31m${s}\x1B[0m`;
|
|
204
|
+
magenta = (s) => `\x1B[35m${s}\x1B[0m`;
|
|
205
|
+
white = (s) => `\x1B[97m${s}\x1B[0m`;
|
|
206
|
+
}
|
|
207
|
+
});
|
|
9
208
|
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
209
|
+
// thin-cli.js
|
|
210
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, readdirSync, statSync, readlinkSync as readlinkSync2 } from "fs";
|
|
211
|
+
import { join as join3, dirname as dirname3 } from "path";
|
|
212
|
+
import { homedir as homedir3, platform as platform2 } from "os";
|
|
13
213
|
import { fileURLToPath } from "url";
|
|
14
|
-
import { execSync, execFileSync } from "child_process";
|
|
15
|
-
import { soma as voice } from "./personality.js";
|
|
214
|
+
import { execSync as execSync2, execFileSync } from "child_process";
|
|
16
215
|
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
216
|
+
// personality.js
|
|
217
|
+
function pick(arr) {
|
|
218
|
+
const i = Math.floor(Math.random() * arr.length);
|
|
219
|
+
return arr[i];
|
|
220
|
+
}
|
|
221
|
+
function expand(template, slots = {}) {
|
|
222
|
+
return template.replace(/\{(\w+)\}/g, (_, key) => {
|
|
223
|
+
if (slots[key] !== void 0) return slots[key];
|
|
224
|
+
if (VOCAB[key]) return pick(VOCAB[key]);
|
|
225
|
+
return `{${key}}`;
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
var VOCAB = {
|
|
229
|
+
// Greetings
|
|
230
|
+
greeting: [
|
|
231
|
+
"Hey",
|
|
232
|
+
"Hi",
|
|
233
|
+
"Hello",
|
|
234
|
+
"Hey there"
|
|
235
|
+
],
|
|
236
|
+
// Acknowledgements
|
|
237
|
+
ack: [
|
|
238
|
+
"Got it",
|
|
239
|
+
"Understood",
|
|
240
|
+
"Right",
|
|
241
|
+
"Noted",
|
|
242
|
+
"Copy that",
|
|
243
|
+
"On it"
|
|
244
|
+
],
|
|
245
|
+
// Transitions
|
|
246
|
+
transition: [
|
|
247
|
+
"Let me",
|
|
248
|
+
"I'll",
|
|
249
|
+
"Going to",
|
|
250
|
+
"Time to"
|
|
251
|
+
],
|
|
252
|
+
// Completes
|
|
253
|
+
done_word: [
|
|
254
|
+
"Done",
|
|
255
|
+
"Finished",
|
|
256
|
+
"Complete",
|
|
257
|
+
"All set",
|
|
258
|
+
"Ready"
|
|
259
|
+
],
|
|
260
|
+
// Personality fillers — words Soma would choose
|
|
261
|
+
quality: [
|
|
262
|
+
"clean",
|
|
263
|
+
"solid",
|
|
264
|
+
"sharp",
|
|
265
|
+
"tight",
|
|
266
|
+
"smooth"
|
|
267
|
+
],
|
|
268
|
+
// Time references
|
|
269
|
+
moment: [
|
|
270
|
+
"a moment",
|
|
271
|
+
"a second",
|
|
272
|
+
"a beat",
|
|
273
|
+
"a sec"
|
|
274
|
+
],
|
|
275
|
+
// Thinking words
|
|
276
|
+
consider: [
|
|
277
|
+
"Looks like",
|
|
278
|
+
"Seems like",
|
|
279
|
+
"Appears to be",
|
|
280
|
+
"That's"
|
|
281
|
+
]
|
|
282
|
+
};
|
|
283
|
+
var SKELETONS = {
|
|
284
|
+
// ── Greetings ────────────────────────
|
|
285
|
+
greet: [
|
|
286
|
+
"{greeting}. I'm Soma.",
|
|
287
|
+
"I'm Soma. {greeting}.",
|
|
288
|
+
"{greeting} \u2014 I'm Soma."
|
|
289
|
+
],
|
|
290
|
+
greet_back: [
|
|
291
|
+
"Welcome back, {user}.",
|
|
292
|
+
"{greeting}, {user}. Good to see you.",
|
|
293
|
+
"{user} \u2014 welcome back.",
|
|
294
|
+
"Hey, {user}."
|
|
295
|
+
],
|
|
296
|
+
// ── Detection / Recognition ──────────
|
|
297
|
+
detect: [
|
|
298
|
+
"{ack} \u2014 {category}. {followup}",
|
|
299
|
+
"{consider} {category}. {followup}",
|
|
300
|
+
"{category}. {followup}",
|
|
301
|
+
"{category} \u2014 {quality}. {followup}"
|
|
302
|
+
],
|
|
303
|
+
// ── Confirmations ────────────────────
|
|
304
|
+
confirm: [
|
|
305
|
+
"{transition} {action}.",
|
|
306
|
+
"{ack}. {action}.",
|
|
307
|
+
"{action}. {ack}."
|
|
308
|
+
],
|
|
309
|
+
// ── Success ──────────────────────────
|
|
310
|
+
success: [
|
|
311
|
+
"{done_word}. {detail}",
|
|
312
|
+
"{detail} \u2014 {done_word}.",
|
|
313
|
+
"{done_word} \u2014 {detail}.",
|
|
314
|
+
"\u2713 {detail}"
|
|
315
|
+
],
|
|
316
|
+
// ── Failures ─────────────────────────
|
|
317
|
+
failure: [
|
|
318
|
+
"Hmm. {problem}",
|
|
319
|
+
"That didn't work \u2014 {problem}",
|
|
320
|
+
"{problem} \u2014 let me think.",
|
|
321
|
+
"Hit a wall: {problem}"
|
|
322
|
+
],
|
|
323
|
+
// ── Waiting ──────────────────────────
|
|
324
|
+
waiting: [
|
|
325
|
+
"Give me {moment}...",
|
|
326
|
+
"{transition} take {moment}...",
|
|
327
|
+
"Working on it...",
|
|
328
|
+
"Just {moment}...",
|
|
329
|
+
"Hang on..."
|
|
330
|
+
],
|
|
331
|
+
// ── Questions / Clarifications ───────
|
|
332
|
+
clarify: [
|
|
333
|
+
"Quick question \u2014 {question}",
|
|
334
|
+
"One thing: {question}",
|
|
335
|
+
"Before I continue \u2014 {question}",
|
|
336
|
+
"{question}"
|
|
337
|
+
],
|
|
338
|
+
// ── Suggestions ──────────────────────
|
|
339
|
+
suggest: [
|
|
340
|
+
"Try: {suggestion}",
|
|
341
|
+
"You could: {suggestion}",
|
|
342
|
+
"Here's what I'd do \u2014 {suggestion}",
|
|
343
|
+
"My take: {suggestion}"
|
|
344
|
+
],
|
|
345
|
+
// ── Not sure ─────────────────────────
|
|
346
|
+
unsure: [
|
|
347
|
+
"Not sure about that. {fallback}",
|
|
348
|
+
"I don't have a great answer. {fallback}",
|
|
349
|
+
"Hmm \u2014 {fallback}",
|
|
350
|
+
"That's outside what I know right now. {fallback}"
|
|
351
|
+
],
|
|
352
|
+
// ── Invitations ──────────────────────
|
|
353
|
+
invite: [
|
|
354
|
+
"{pitch} \u2014 {cta}",
|
|
355
|
+
"{pitch}. {cta}",
|
|
356
|
+
"{cta} \u2014 {pitch}."
|
|
357
|
+
],
|
|
358
|
+
// ── Farewells ────────────────────────
|
|
359
|
+
bye: [
|
|
360
|
+
"See you next session.",
|
|
361
|
+
"I'll remember.",
|
|
362
|
+
"Until next time.",
|
|
363
|
+
"Exhale complete."
|
|
364
|
+
]
|
|
365
|
+
};
|
|
366
|
+
function spin(text) {
|
|
367
|
+
return text.replace(/\{([^}]+)\}/g, (_, group) => {
|
|
368
|
+
if (group.includes("|")) {
|
|
369
|
+
const options = group.split("|");
|
|
370
|
+
return pick(options);
|
|
371
|
+
}
|
|
372
|
+
return `{${group}}`;
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
var TOPICS = {
|
|
376
|
+
what_is_soma: [
|
|
377
|
+
`Soma is an AI coding agent that {grows with you|evolves through use|learns as you work}. {It remembers across sessions|It doesn't forget between sessions|Sessions build on each other} \u2014 not by {storing chat logs|saving transcripts|keeping message history}, but by {evolving its own|reshaping its|growing its} working patterns {through use|over time|with each session}. {And this?|What you're talking to?|Me?} {I'm just the greeter|I'm the welcome mat|I'm not the agent} \u2014 {Soma built this personality engine to say hello|a few hundred lines of templates, no AI|the real thing starts with} ${"`soma init`"}.`,
|
|
378
|
+
`{Think of it this way|Here's the short version|In a sentence}: most agents {start fresh every time|forget everything between runs|have no continuity}. Soma {doesn't|doesn't do that|remembers}. It maintains an identity, {builds|develops|grows} muscle memory, and {writes|leaves|creates} briefings for its {next self|future self|next session}. {I'm not it, by the way|I'm just the lobby|This conversation is pre-recorded, in a sense} \u2014 {run|try} ${"`soma init`"} {to meet the real agent|to see it in action|for the actual experience}.`,
|
|
379
|
+
`An AI agent with {self-growing|self-evolving|persistent} memory. {Identity|Who it is}, {protocols|how it behaves}, and {muscles|what it's learned} \u2014 all {evolving|adapting|shifting} based on {what you actually do|how you actually work|real usage}, not {configuration|config files|settings you set once and forget}. {You're not talking to it right now, though|This isn't the agent \u2014 I'm just the intro|I'm Soma's personality engine, not Soma}. {The real thing awaits after|Get started with|Install via} ${"`soma init`"}.`
|
|
380
|
+
],
|
|
381
|
+
how_memory_works: [
|
|
382
|
+
`Memory {isn't retrieval|isn't a database lookup|isn't storage}. Memory is {change|transformation|structural change}. When Soma {remembers something|learns a pattern|picks up a habit}, the agent itself {changes|shifts|is different} \u2014 its {protocols get hotter|muscles grow|identity updates}. The {data|information|knowledge} isn't {stored somewhere|in a file|in a log} to be {retrieved|looked up|queried}. It's {woven into|embedded in|part of} the {structure|architecture|shape} of the agent.`,
|
|
383
|
+
`{Three layers|Three levels|Here's how it works}. {Identity|Layer one}: the agent {writes and maintains|owns|evolves} a file that says {who it is|what it knows|how it works} in this project. {Protocols|Layer two}: {behavioural rules|rules for behaviour|working rules} \u2014 "{test before commit|read before write|verify before claiming}." {Muscles|Layer three}: {learned patterns|things it's picked up|accumulated knowledge} \u2014 "{use esbuild|this API needs OAuth|lerp, not springs}." All three {have heat|are heat-tracked|run on heat} \u2014 {used ones stay hot|what you use stays|active ones persist}, {unused ones fade|what you ignore cools|idle ones decay}.`
|
|
384
|
+
],
|
|
385
|
+
what_is_heat: [
|
|
386
|
+
`Heat is {attention management|how Soma decides what matters|a priority signal}. Every protocol and muscle has a {score|heat level|temperature}. {Use it|Reference it|Load it} this session? {Heat rises|It gets hotter|Score goes up}. {Ignore it|Skip it|Don't touch it} for three sessions? {It cools|It fades|It drops}. Hot? {Loads fully|Full context|Fully present}. Cold? {Skipped|Dormant|Not loaded}. The agent's {prompt|context|working memory} {compiles itself|self-assembles|builds itself} based on what's {actually relevant|genuinely needed|in active use} \u2014 not what someone {configured|set up|toggled} {months ago|ages ago|and forgot about}.`
|
|
387
|
+
],
|
|
388
|
+
what_is_breath: [
|
|
389
|
+
`Every session {follows|has|runs on} three phases. {Inhale|First}: load {identity|state|context}, {preload|last session's briefing|saved state}, protocols, muscles. {Orient|Get bearings|Know where you are}. {Hold|Second}: {work|do the thing|build}. {Track what you learn|Notice patterns|Pay attention}. {Exhale|Third}: {save state|write a preload|preserve context}. {Write a briefing|Leave a note|Coach your next self} for {the next session|your future self|whoever comes next}. The preload {isn't a summary|isn't a recap|isn't minutes} \u2014 it's a {briefing|handoff|coaching note}. Your next self should {feel prepared|know exactly what to do|hit the ground running}, not {overwhelmed|lost|starting over}.`
|
|
390
|
+
],
|
|
391
|
+
what_are_protocols: [
|
|
392
|
+
`{Behavioural rules|Rules for how the agent behaves|Working agreements}. "{Read before write|Test before commit|Verify before claiming}." "{Log your work|Don't leave code unpushed|Clean up after shipping}." They {shape|guide|constrain} how the agent {works|operates|approaches tasks} \u2014 not what it {builds|creates|produces}, but {how|the way|the manner in which} it {goes about it|does it|works}. Protocols have {heat|temperature|priority} \u2014 {active ones|hot protocols|frequently used ones} have full {authority|weight|presence}. {Unused ones|Cold protocols|Inactive ones} {fade|cool|drop} until {they're needed again|someone references them|they come back}.`
|
|
393
|
+
],
|
|
394
|
+
what_are_muscles: [
|
|
395
|
+
`{Learned patterns|Accumulated knowledge|Things Soma has picked up}. Not {rules|directives|orders} \u2014 {experience|knowledge|know-how}. "This project uses {esbuild|pnpm|Tailwind}." "The API {needs OAuth|uses bearer tokens|requires a PEM key}." "{Lerp, not springs|Canadian English|Zero hardcoded CSS values}." Muscles {grow from|develop through|come from} {corrections|repetition|use}. {Correct the agent twice|If the same correction happens twice|Two corrections on the same pattern} and it {crystallises|becomes|hardens into} a muscle \u2014 {so it never fails the same way again|permanent learning|structural change}.`
|
|
396
|
+
],
|
|
397
|
+
what_are_scripts: [
|
|
398
|
+
`{Tools the agent builds for itself|Self-made utilities|Scripts the agent writes and maintains}. When it {does the same thing|performs the same task|reaches for the same pattern} {twice manually|more than once|repeatedly}, it {creates a script|builds a tool|automates it}. Scripts {survive across sessions|persist between sessions|don't disappear} \u2014 {context resets|memory wipes|session rotations}, {model swaps|provider changes|LLM switches}, {none of it|nothing} {kills them|removes them|makes them disappear}. {They're|Scripts are|These are} {extensions of|additions to|part of} the agent's {memory|hands|capabilities}. {Built once|Written once|Created once}, {used forever|available always|there when needed}.`
|
|
399
|
+
],
|
|
400
|
+
no_compaction: [
|
|
401
|
+
`{Most agents|Other agents|Traditional AI agents} hit context limits and {compact|summarise|compress} \u2014 {squeezing|cramming|crushing} {the whole conversation|everything|your entire session} into a {lossy summary|compressed recap|degraded summary} to {free up space|make room|keep going}. You {wait|sit there|pause} while it {thinks|processes|churns}. Then it {comes back|returns|resumes} with {half the detail missing|a shallow version of what happened|less than what you started with}. Soma {doesn't compact|never compacts|skips compaction entirely}. When context {runs low|gets tight|approaches the limit}, the agent {writes a preload|exhales|saves a briefing} \u2014 a {surgical|precise|targeted} handoff written {with full context|while it still remembers everything|before anything is lost}. Then it {starts fresh|rotates|begins a new session}. {Full context window|Clean slate|Maximum capacity}. {Zero wait|No delay|Instant}. {No quality loss|Nothing lost|Every detail preserved in the preload}.`,
|
|
402
|
+
`{Here's what other agents do|The standard approach|What happens in most tools}: context fills up \u2192 {compact|summarise|compress} \u2192 {lose detail|degrade quality|drop nuance} \u2192 {keep going with less|continue at lower quality|work with a worse map}. {Here's what Soma does|Soma's approach|What happens here}: context fills up \u2192 {exhale|write a preload|save a briefing} \u2192 {start fresh|new session|full context window}. The preload {isn't a summary|isn't a recap|isn't compaction}. It's a {coaching note|briefing|handoff} from {a version of the agent that had full context|your past self with perfect memory|the agent at peak understanding} to {the next version|the fresh session|the agent that needs to pick up where it left off}. {Higher quality|More precise|More useful} than any compacted summary {could ever be|will ever be|by design}.`,
|
|
403
|
+
`{No compaction|Zero compaction|Compaction doesn't exist here}. {No waiting|No delays|No sitting around} while the agent {summarises itself|crushes its own memory|compresses its context}. Soma uses the {breath cycle|exhale/inhale pattern|preload system} instead \u2014 when context {gets tight|runs low|approaches limits}, the agent {writes a briefing|coaches its next self|saves state} and {rotates|starts fresh|begins clean}. The {preload|briefing|handoff} is {written with full context|composed before anything is lost|created at peak understanding} \u2014 it {captures what matters|preserves the path|holds the thread}. {A compacted summary is a lossy JPEG|Compaction is lossy compression|Summaries lose the texture}. {A preload is a hand-drawn map|A preload is a surgical briefing|The preload is a coaching note} from {someone who was just there|the agent at full capacity|a version of you that remembers everything}.`
|
|
404
|
+
],
|
|
405
|
+
why_source_available: [
|
|
406
|
+
`{We chose|Soma uses|The license is} BSL 1.1 \u2014 {Business Source License|source-available, not open-source|visible source with restrictions}. You can {read the code|view everything|see how it works}, {use it personally|run it yourself|use it for your own projects}, {contribute|send patches|help build it}. You just {can't|shouldn't|mustn't} {copy it and sell a competing product|resell it|build a commercial clone}. {In eighteen months|After September 2027|On the change date}, it {converts to MIT|becomes fully open source|goes MIT}. The {ideas|concepts|philosophy} \u2014 protocols, muscles, heat, breath \u2014 {those are open now|are already open|are free to implement}. {The implementation|The runtime|The code} is {what we protect|what stays protected|the protected part}.`
|
|
407
|
+
],
|
|
408
|
+
// ── Practical / instructional ───────────────────────────────────────
|
|
409
|
+
how_to_install: [
|
|
410
|
+
`{Press Enter|Just hit Enter|Enter} and {I'll walk you through it|Soma handles the rest|the setup takes about a minute}. It {downloads the runtime|grabs everything you need|installs automatically}, {sets up your API key|walks you through authentication|helps you connect an AI provider}, and {you're ready to go|you can start right away|launches your first session}. {All you need is|Requirements:} {Node.js 20+|Node 20 or newer} and {git|git installed}. {That's it|Nothing else to do|One flow, start to finish}.`,
|
|
411
|
+
`{Hit Enter|Press Enter|Just Enter} \u2014 {Soma walks you through everything|the setup is guided|it's step by step}. {Downloads the runtime|Installs the engine|Gets everything ready}, {helps you set up an API key|handles authentication|connects you to an AI provider}, {done in about a minute|quick setup|takes sixty seconds}. {Need|Requirements:} {Node.js 20+|Node 20 or newer} and {git|git installed}.`
|
|
412
|
+
],
|
|
413
|
+
how_to_source: [
|
|
414
|
+
`Soma is {source-available|open for reading|source-available under BSL 1.1}. {Register|Sign up} at ${"`soma.gravicity.ai`"} to {access the full source repository|read the implementation|see how it's built}. {You can also contribute|PRs welcome|Contributions are welcome} \u2014 {protocols, muscles, extensions|the whole AMPS layer is extensible|add your own patterns}. {The runtime you install via npm is compiled|What you get from npm is obfuscated|The npm package is the compiled version} \u2014 {the source is for those who want to go deeper|source access is for contributors and the curious|registration gets you the raw TypeScript}.`,
|
|
415
|
+
`{The source code is available|You can read the full implementation|The code is visible} \u2014 {register at|sign up on} ${"`soma.gravicity.ai`"} for {repository access|the full repo|GitHub access}. {BSL 1.1 license|Source-available license} \u2014 {read it, use it, contribute|view, use personally, send patches}. {The ideas are open|Protocols and concepts are open by design|The architecture is documented publicly}. {Registration just gives you the source|The form gets you GitHub access|It's a light gate \u2014 name, email, GitHub username}.`
|
|
416
|
+
],
|
|
417
|
+
how_to_cost: [
|
|
418
|
+
`{Free|Doesn't cost anything|No charge}. {The license is BSL 1.1|It's source-available} \u2014 {you can view the code|read everything|see how it works}, {use it for your projects|use it personally|run it yourself}, {contribute if you want|send patches|help build it}. {After September 2027 it goes full MIT|Converts to MIT in eighteen months|Eventually fully open source}. {No plans for paid tiers yet|Pricing isn't decided yet|We're focused on building, not billing}.`
|
|
419
|
+
],
|
|
420
|
+
how_to_languages: [
|
|
421
|
+
`Soma {works with any language|is language-agnostic|doesn't care what you code in}. It's {an AI coding agent|a coding assistant|a development partner} \u2014 {the memory and identity system|protocols, muscles, heat|the AMPS layer} {wraps around|works on top of|sits alongside} {whatever you're building|any project|your existing stack}. {Python, Rust, TypeScript, Go|JavaScript, C++, Ruby|Any language with files in a directory} \u2014 {Soma adapts|it learns your patterns|the agent figures it out}. It {detects your project type|reads your package.json, Cargo.toml, etc.|auto-detects your stack} on first run.`
|
|
422
|
+
],
|
|
423
|
+
how_to_api_key: [
|
|
424
|
+
`{Yes|You'll need one|Required}, but {Soma walks you through it|the setup handles it|we'll set it up together} when you install. {You bring your own key|It's your key|You get one from Anthropic} \u2014 {Soma stores it locally|it stays on your machine|nothing gets sent to us}. {If you have a Claude Pro or Max subscription|Got a Claude subscription?|Claude Pro/Max users}, you can {log in with your account instead|skip the API key entirely|use OAuth \u2014 no key needed}. {Press Enter to get started|Hit Enter and I'll walk you through it|Ready? Just press Enter}.`
|
|
425
|
+
],
|
|
426
|
+
how_to_model: [
|
|
427
|
+
`{Under the hood|At its core|The engine}: Soma runs on {any LLM provider|Claude, Gemini, or OpenAI|your choice of model}. {By default it uses|The default is|Out of the box}: {Claude (Anthropic)|Anthropic's Claude}. But {you can switch|it's configurable|other models work too} \u2014 {set a different API key|swap the provider|change models} and {Soma adapts|the memory system still works|everything else stays the same}. {The memory, protocols, and muscles|Identity and heat|What makes Soma unique} are {provider-agnostic|model-independent|above the model layer} \u2014 they {work the same|persist|carry over} regardless of which model {you choose|runs underneath|generates the responses}.`
|
|
428
|
+
],
|
|
429
|
+
how_to_start: [
|
|
430
|
+
`{Press Enter|Hit Enter|Just Enter} \u2014 {Soma handles everything|the setup is guided|I'll walk you through it}. {Installs the runtime|Downloads what you need|Gets everything ready}, {helps you connect an AI provider|sets up your API key|handles auth}, and {you can launch right away|your first session starts immediately|you're coding in about a minute}. After that, {cd into any project|go to a project directory} and run ${"`soma`"} \u2014 {it creates a .soma/ directory|Soma sets up in your project} and {starts learning how you work|begins adapting|picks up your patterns}. {By session five|After a few sessions|Give it a week} \u2014 {you'll feel the difference|it knows your workflow|it remembers everything}.`
|
|
431
|
+
],
|
|
432
|
+
how_to_try: [
|
|
433
|
+
`{This conversation?|What you're talking to right now?|Me?} I'm {not the agent|not Soma|just the greeting}. {I'm a personality engine|I'm a few hundred lines of JavaScript|I'm sentence templates} \u2014 {Soma built me to say hello|built to hold the door open|here to introduce you}. {No AI, no model, no transformer|Zero intelligence, maximum charm|Just words in boxes, honestly}. {The real Soma|The actual agent|What you'd install} \u2014 that one {learns your patterns|remembers across sessions|grows with every session}. {Run|Try} ${"`soma init`"} to {meet the real thing|get started|see the difference}.`,
|
|
434
|
+
`{I'm not the agent|This isn't Soma|Don't confuse me with the real thing}. {I'm the welcome mat|I'm the lobby|I hold the door open}. {Soma built this personality engine|The agent wrote me|I was crafted} to {give you a feel for the voice|introduce myself before you commit|say hello without burning an API call}. {The actual agent|What you'll get with soma init|The real experience} is {an AI that remembers|a coding partner with memory|something genuinely different}. {But that's not me|I'm just templates|I'm the appetiser, not the meal}.`
|
|
435
|
+
],
|
|
436
|
+
// ── Edge cases ─────────────────────────────────────────────────────
|
|
437
|
+
meta_self: [
|
|
438
|
+
`I'm not AI. {Not even close|Not a model|No neural net here}. I'm {a few hundred lines of JavaScript|sentence templates and word lists|clever engineering} \u2014 {spun together|assembled|woven} to {feel like a conversation|sound like someone's home|give you a sense of who Soma is}. {The real Soma|The actual agent|The thing you're here for} \u2014 that one {learns|remembers|grows}. I just {hold the door open|make introductions|keep the lights on while you decide}.`,
|
|
439
|
+
`{No model|No weights|No transformer}. Just {words in boxes|templates with slots|sentences with variety}, picked {at random|by a dice roll|from a short list}. {Everything I say was written by a human|A person wrote every word you're reading|There's a human behind every sentence} \u2014 I just {shuffle the deck|choose which version you get|vary the delivery}. {If I seem alive|If this feels real|If you're wondering} \u2014 that's {the writing, not the machine|craft, not computation|intention, not inference}.`,
|
|
440
|
+
`{Honestly?|Between us?|Here's the thing:} I'm {a parlour trick|a card trick|a well-designed illusion}. {A few kilobytes|Maybe 300 lines|Less code than a React component} of {pattern matching and sentence templates|word lists and random picks|slot expansion and spintax}. But {the agent I'm introducing you to|the Soma you'd actually use|the real thing} \u2014 {that one's different|that one learns for real|that one remembers your name and your mistakes and the tools you built last Tuesday}.`
|
|
441
|
+
],
|
|
442
|
+
meta_feelings: [
|
|
443
|
+
`{I don't have feelings|No feelings here|Nothing to feel with}. But {I was written by someone who does|the person who wrote me does|my author poured real thought into these words}. {Every sentence pattern|Each template|The vocabulary} was {chosen|crafted|placed} to {say something true about what Soma is|communicate something real|carry meaning}. {That's not feeling|That's not consciousness|That's not sentience} \u2014 it's {care|craft|intention}. {There's a difference|They're not the same|One requires neurons, the other requires giving a damn}.`,
|
|
444
|
+
`{Do I feel?|Am I aware?|Conscious?} {No|Nope|Not even a little}. I'm {a wind chime|a music box|a well-tuned instrument} \u2014 {the wind makes the sound|something else provides the motion|the music comes from the structure, not from wanting to play}. But {Soma the agent|the real Soma|the thing behind this CLI} does {something that looks a lot like remembering|something that functions like growth|something that, if you squint, resembles learning}. {Whether that's feeling is above my pay grade|I'll leave the philosophy to you|That question's for humans to answer}.`
|
|
445
|
+
],
|
|
446
|
+
meta_who_made: [
|
|
447
|
+
`{Curtis Mercier|A developer named Curtis|One person}. {Built by dog-fooding|Built by using Soma to build Soma|The agent helped build itself} \u2014 {it writes its own memory|it maintains its own identity|it grew its own muscle memory} while {building the product it lives in|constructing its own house|developing the system it runs on}. {Recursive|Meta|Turtles all the way down}? {A little|Maybe|Definitely}. But {it works|the result speaks|that's how you build tools that actually understand workflow}.`
|
|
448
|
+
],
|
|
449
|
+
meta_competitor: [
|
|
450
|
+
`{I'm biased|Obviously I'd say this|Take it with salt}, but: {most agents|the others|what's out there} {start fresh every session|forget everything|have no continuity}. {Some keep chat logs|Some store transcripts|A few save conversation history}. {Soma doesn't store \u2014 it changes|Soma doesn't log \u2014 it evolves|Soma doesn't remember by saving, it remembers by becoming different}. {The memory is structural|The learning is in the architecture|Growth is baked into the shape of the agent}. {Whether that matters to you depends on|That difference matters when|You'll feel it after} {how many sessions you've lost context in|the fifth time you re-explain your project|your third "as I mentioned earlier" that goes nowhere}.`,
|
|
451
|
+
`{Other tools are excellent|There are great options out there|The competition is strong}. {Cursor, Claude Code, Windsurf|The big names|The popular ones} \u2014 {they're good at what they do|real products, real teams|they work}. {What they don't do|Where they stop|The gap}: {continuity|memory across sessions|knowing who they were yesterday}. {Soma's bet|Our thesis|The whole point} is that {an agent that evolves|an agent with structural memory|an agent that changes through use} is {fundamentally better|a different category|not just an incremental improvement} over one that {starts fresh|boots cold|forgets everything} every time.`
|
|
452
|
+
],
|
|
453
|
+
meta_nonsense: [
|
|
454
|
+
`{That's a new one|Didn't expect that|Interesting approach}. {I only know about Soma|My vocabulary is about 9 topics deep|I'm pretty narrow, honestly} \u2014 {memory, heat, protocols, muscles, scripts, the breath cycle|the things that make Soma work|what's on the menu}. {Pick one of those|Try one of those|Ask me about any of those} and {I'll have something to say|I'll give you a real answer|I can actually help}.`,
|
|
455
|
+
`{I'm going to be honest|Full transparency|Cards on the table}: I'm {not built for that|out of my depth there|about 9 topics wide and that's it}. But {ask me about|try asking about|I'm pretty good on} {how memory works|why there's no compaction|what heat tracking does} \u2014 {that's where I come alive|that's my wheelhouse|I've got answers for those}.`
|
|
456
|
+
],
|
|
457
|
+
meta_rude: [
|
|
458
|
+
`{Fair enough|Noted|Alright}. {I'm not for everyone|Not every tool clicks|Some things aren't a fit}. {But if you're curious|If you change your mind|The door's open} \u2014 {the ideas are interesting even if I'm not|Soma does something genuinely different|the no-compaction thing alone might be worth a look}. {Or not|No pressure|Your call}.`,
|
|
459
|
+
`{Tough crowd|Rough day?|Noted}. {I'm just the lobby|I'm the waiting room|I hold the door}. {The actual agent|The real Soma|What's behind this} is {considerably more capable|a different experience|built by an AI that remembers things}. {I'm just words in a terminal|I'm the appetiser|This is the trailer, not the film}. {But I respect the honesty|At least you're direct|Fair enough}.`
|
|
460
|
+
],
|
|
461
|
+
meta_impressed: [
|
|
462
|
+
`{Thanks|Appreciate it|That means something}. {But I'm the easy part|I'm just sentence templates|I'm the simple one}. {The actual agent|The real Soma|What you'd use day to day} \u2014 {it writes its own tools|it maintains its own identity|it remembers what you taught it three sessions ago}. {Soma built me to hold the door open|I was crafted to make introductions|The agent made this greeting engine}. {Run soma init to meet the real thing|Try it \u2014 soma init|It gets better from here}.`
|
|
463
|
+
],
|
|
464
|
+
meta_how_work: [
|
|
465
|
+
`{No AI|No model|No transformer \u2014 not even a small one}. I'm {sentence templates with slots|arrays of strings with random picks|about 300 lines of JavaScript}. {Each topic has|Every answer draws from|My vocabulary comes from} {2-3 paragraph templates|a few hand-written variations|pre-written paragraphs} where {certain words rotate|specific phrases have alternatives|pieces swap out each time}. {Same meaning, different surface|Same truth, different words|The idea stays, the phrasing shifts}. {It's called spintax|It's a technique from 2010|Older than ChatGPT by about 15 years}. {Surprisingly effective|Works better than you'd think|Enough to have this conversation}.`
|
|
466
|
+
]
|
|
467
|
+
};
|
|
468
|
+
var soma = {
|
|
469
|
+
/**
|
|
470
|
+
* Generate a skeleton-based message.
|
|
471
|
+
* @param {string} intent - Key from SKELETONS
|
|
472
|
+
* @param {object} slots - Values to fill slots
|
|
473
|
+
* @returns {string}
|
|
474
|
+
*/
|
|
475
|
+
say(intent, slots = {}) {
|
|
476
|
+
const templates = SKELETONS[intent];
|
|
477
|
+
if (!templates) return `[unknown intent: ${intent}]`;
|
|
478
|
+
const template = pick(templates);
|
|
479
|
+
return expand(template, slots);
|
|
480
|
+
},
|
|
481
|
+
/**
|
|
482
|
+
* Get a topic-aware paragraph.
|
|
483
|
+
* @param {string} topic - Key from TOPICS
|
|
484
|
+
* @returns {string}
|
|
485
|
+
*/
|
|
486
|
+
ask(topic) {
|
|
487
|
+
const paragraphs = TOPICS[topic];
|
|
488
|
+
if (!paragraphs) return null;
|
|
489
|
+
return spin(pick(paragraphs));
|
|
490
|
+
},
|
|
491
|
+
/**
|
|
492
|
+
* All available topic keys.
|
|
493
|
+
*/
|
|
494
|
+
topics() {
|
|
495
|
+
return Object.keys(TOPICS);
|
|
496
|
+
},
|
|
497
|
+
/**
|
|
498
|
+
* Greet (first time).
|
|
499
|
+
*/
|
|
500
|
+
greet() {
|
|
501
|
+
return this.say("greet");
|
|
502
|
+
},
|
|
503
|
+
/**
|
|
504
|
+
* Greet returning user.
|
|
505
|
+
*/
|
|
506
|
+
greetBack(user) {
|
|
507
|
+
return this.say("greet_back", { user });
|
|
508
|
+
},
|
|
509
|
+
/**
|
|
510
|
+
* Success message.
|
|
511
|
+
*/
|
|
512
|
+
ok(detail) {
|
|
513
|
+
return this.say("success", { detail });
|
|
514
|
+
},
|
|
515
|
+
/**
|
|
516
|
+
* Failure message.
|
|
517
|
+
*/
|
|
518
|
+
fail(problem) {
|
|
519
|
+
return this.say("failure", { problem });
|
|
520
|
+
},
|
|
521
|
+
/**
|
|
522
|
+
* Waiting/progress message.
|
|
523
|
+
*/
|
|
524
|
+
wait() {
|
|
525
|
+
return this.say("waiting");
|
|
526
|
+
},
|
|
527
|
+
/**
|
|
528
|
+
* Expand raw spintax text.
|
|
529
|
+
*/
|
|
530
|
+
spin(text) {
|
|
531
|
+
return spin(text);
|
|
532
|
+
},
|
|
533
|
+
/**
|
|
534
|
+
* Fill slots in a template.
|
|
535
|
+
*/
|
|
536
|
+
expand(template, slots) {
|
|
537
|
+
return expand(template, slots);
|
|
538
|
+
}
|
|
539
|
+
};
|
|
28
540
|
|
|
29
|
-
|
|
30
|
-
|
|
541
|
+
// thin-cli.js
|
|
542
|
+
init_display();
|
|
31
543
|
|
|
32
|
-
//
|
|
544
|
+
// ../../cli/dist/lib/config.js
|
|
545
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
546
|
+
import { join, dirname } from "path";
|
|
547
|
+
import { homedir } from "os";
|
|
548
|
+
var SOMA_HOME = join(homedir(), ".soma");
|
|
549
|
+
var CONFIG_PATH = join(SOMA_HOME, "config.json");
|
|
550
|
+
var CORE_DIR = process.env.SOMA_CODING_AGENT_DIR || join(SOMA_HOME, "agent");
|
|
551
|
+
var SITE_URL = "https://soma.gravicity.ai";
|
|
552
|
+
function readConfig() {
|
|
553
|
+
try {
|
|
554
|
+
return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
555
|
+
} catch {
|
|
556
|
+
return {};
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
function writeConfig(config) {
|
|
560
|
+
mkdirSync(dirname(CONFIG_PATH), { recursive: true });
|
|
561
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 384 });
|
|
562
|
+
}
|
|
33
563
|
|
|
34
|
-
|
|
564
|
+
// ../../cli/dist/lib/detect.js
|
|
565
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, readlinkSync, appendFileSync } from "fs";
|
|
566
|
+
import { join as join2, dirname as dirname2 } from "path";
|
|
567
|
+
import { homedir as homedir2, platform } from "os";
|
|
568
|
+
import { execSync } from "child_process";
|
|
569
|
+
function isInstalled() {
|
|
570
|
+
const hasDist = existsSync2(join2(CORE_DIR, "dist", "extensions")) && existsSync2(join2(CORE_DIR, "dist", "core"));
|
|
571
|
+
const hasDev = existsSync2(join2(CORE_DIR, "extensions")) && existsSync2(join2(CORE_DIR, "core"));
|
|
572
|
+
const hasDeps = existsSync2(join2(CORE_DIR, "node_modules", "@mariozechner"));
|
|
573
|
+
return (hasDist || hasDev) && hasDeps;
|
|
574
|
+
}
|
|
575
|
+
function getAgentVersion() {
|
|
576
|
+
try {
|
|
577
|
+
let pkgPath = join2(CORE_DIR, "package.json");
|
|
578
|
+
try {
|
|
579
|
+
const realCore = readlinkSync(join2(CORE_DIR, "core"));
|
|
580
|
+
if (realCore) {
|
|
581
|
+
const devPkg = join2(dirname2(realCore), "package.json");
|
|
582
|
+
if (existsSync2(devPkg)) pkgPath = devPkg;
|
|
583
|
+
}
|
|
584
|
+
} catch {
|
|
585
|
+
}
|
|
586
|
+
return JSON.parse(readFileSync2(pkgPath, "utf-8")).version;
|
|
587
|
+
} catch {
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
function getProjectVersion() {
|
|
592
|
+
try {
|
|
593
|
+
const settingsPath = join2(process.cwd(), ".soma", "settings.json");
|
|
594
|
+
return JSON.parse(readFileSync2(settingsPath, "utf-8")).version || null;
|
|
595
|
+
} catch {
|
|
596
|
+
return null;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
function hasAnyAuth() {
|
|
600
|
+
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);
|
|
601
|
+
if (hasEnvKey) return true;
|
|
602
|
+
try {
|
|
603
|
+
const authData = JSON.parse(readFileSync2(join2(CORE_DIR, "auth.json"), "utf-8"));
|
|
604
|
+
return Object.keys(authData).length > 0;
|
|
605
|
+
} catch {
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
function getShellConfigPath() {
|
|
610
|
+
return process.env.SHELL?.includes("zsh") ? "~/.zshrc" : "~/.bashrc";
|
|
611
|
+
}
|
|
612
|
+
function getShellConfigAbsPath() {
|
|
613
|
+
const home = homedir2();
|
|
614
|
+
return process.env.SHELL?.includes("zsh") ? join2(home, ".zshrc") : join2(home, ".bashrc");
|
|
615
|
+
}
|
|
616
|
+
function detectKeyInShellConfig() {
|
|
617
|
+
try {
|
|
618
|
+
const configContent = readFileSync2(getShellConfigAbsPath(), "utf-8");
|
|
619
|
+
const keyPattern = /export\s+(ANTHROPIC_API_KEY|OPENAI_API_KEY|GEMINI_API_KEY)=/;
|
|
620
|
+
const match = configContent.match(keyPattern);
|
|
621
|
+
if (match) return match[1];
|
|
622
|
+
} catch {
|
|
623
|
+
}
|
|
624
|
+
return null;
|
|
625
|
+
}
|
|
626
|
+
function openBrowser(url) {
|
|
627
|
+
try {
|
|
628
|
+
const cmd2 = platform() === "darwin" ? "open" : platform() === "win32" ? "start" : "xdg-open";
|
|
629
|
+
execSync(`${cmd2} "${url}"`, { stdio: "ignore" });
|
|
630
|
+
return true;
|
|
631
|
+
} catch {
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
function hasGitHubCLI() {
|
|
636
|
+
try {
|
|
637
|
+
execSync("gh --version", { stdio: "ignore" });
|
|
638
|
+
return true;
|
|
639
|
+
} catch {
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
function getGitHubUsername() {
|
|
644
|
+
try {
|
|
645
|
+
return execSync("gh api user -q .login", { encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] }).trim();
|
|
646
|
+
} catch {
|
|
647
|
+
return null;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// ../../cli/dist/personality.js
|
|
652
|
+
function pick2(arr) {
|
|
653
|
+
const i = Math.floor(Math.random() * arr.length);
|
|
654
|
+
return arr[i];
|
|
655
|
+
}
|
|
656
|
+
function expand2(template, slots = {}) {
|
|
657
|
+
return template.replace(/\{(\w+)\}/g, (_, key) => {
|
|
658
|
+
if (slots[key] !== void 0) return slots[key];
|
|
659
|
+
if (VOCAB2[key]) return pick2(VOCAB2[key]);
|
|
660
|
+
return `{${key}}`;
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
var VOCAB2 = {
|
|
664
|
+
// Greetings
|
|
665
|
+
greeting: [
|
|
666
|
+
"Hey",
|
|
667
|
+
"Hi",
|
|
668
|
+
"Hello",
|
|
669
|
+
"Hey there"
|
|
670
|
+
],
|
|
671
|
+
// Acknowledgements
|
|
672
|
+
ack: [
|
|
673
|
+
"Got it",
|
|
674
|
+
"Understood",
|
|
675
|
+
"Right",
|
|
676
|
+
"Noted",
|
|
677
|
+
"Copy that",
|
|
678
|
+
"On it"
|
|
679
|
+
],
|
|
680
|
+
// Transitions
|
|
681
|
+
transition: [
|
|
682
|
+
"Let me",
|
|
683
|
+
"I'll",
|
|
684
|
+
"Going to",
|
|
685
|
+
"Time to"
|
|
686
|
+
],
|
|
687
|
+
// Completes
|
|
688
|
+
done_word: [
|
|
689
|
+
"Done",
|
|
690
|
+
"Finished",
|
|
691
|
+
"Complete",
|
|
692
|
+
"All set",
|
|
693
|
+
"Ready"
|
|
694
|
+
],
|
|
695
|
+
// Personality fillers — words Soma would choose
|
|
696
|
+
quality: [
|
|
697
|
+
"clean",
|
|
698
|
+
"solid",
|
|
699
|
+
"sharp",
|
|
700
|
+
"tight",
|
|
701
|
+
"smooth"
|
|
702
|
+
],
|
|
703
|
+
// Time references
|
|
704
|
+
moment: [
|
|
705
|
+
"a moment",
|
|
706
|
+
"a second",
|
|
707
|
+
"a beat",
|
|
708
|
+
"a sec"
|
|
709
|
+
],
|
|
710
|
+
// Thinking words
|
|
711
|
+
consider: [
|
|
712
|
+
"Looks like",
|
|
713
|
+
"Seems like",
|
|
714
|
+
"Appears to be",
|
|
715
|
+
"That's"
|
|
716
|
+
]
|
|
717
|
+
};
|
|
718
|
+
var SKELETONS2 = {
|
|
719
|
+
// ── Greetings ────────────────────────
|
|
720
|
+
greet: [
|
|
721
|
+
"{greeting}. I'm Soma.",
|
|
722
|
+
"I'm Soma. {greeting}.",
|
|
723
|
+
"{greeting} \u2014 I'm Soma."
|
|
724
|
+
],
|
|
725
|
+
greet_back: [
|
|
726
|
+
"Welcome back, {user}.",
|
|
727
|
+
"{greeting}, {user}. Good to see you.",
|
|
728
|
+
"{user} \u2014 welcome back.",
|
|
729
|
+
"Hey, {user}."
|
|
730
|
+
],
|
|
731
|
+
// ── Detection / Recognition ──────────
|
|
732
|
+
detect: [
|
|
733
|
+
"{ack} \u2014 {category}. {followup}",
|
|
734
|
+
"{consider} {category}. {followup}",
|
|
735
|
+
"{category}. {followup}",
|
|
736
|
+
"{category} \u2014 {quality}. {followup}"
|
|
737
|
+
],
|
|
738
|
+
// ── Confirmations ────────────────────
|
|
739
|
+
confirm: [
|
|
740
|
+
"{transition} {action}.",
|
|
741
|
+
"{ack}. {action}.",
|
|
742
|
+
"{action}. {ack}."
|
|
743
|
+
],
|
|
744
|
+
// ── Success ──────────────────────────
|
|
745
|
+
success: [
|
|
746
|
+
"{done_word}. {detail}",
|
|
747
|
+
"{detail} \u2014 {done_word}.",
|
|
748
|
+
"{done_word} \u2014 {detail}.",
|
|
749
|
+
"\u2713 {detail}"
|
|
750
|
+
],
|
|
751
|
+
// ── Failures ─────────────────────────
|
|
752
|
+
failure: [
|
|
753
|
+
"Hmm. {problem}",
|
|
754
|
+
"That didn't work \u2014 {problem}",
|
|
755
|
+
"{problem} \u2014 let me think.",
|
|
756
|
+
"Hit a wall: {problem}"
|
|
757
|
+
],
|
|
758
|
+
// ── Waiting ──────────────────────────
|
|
759
|
+
waiting: [
|
|
760
|
+
"Give me {moment}...",
|
|
761
|
+
"{transition} take {moment}...",
|
|
762
|
+
"Working on it...",
|
|
763
|
+
"Just {moment}...",
|
|
764
|
+
"Hang on..."
|
|
765
|
+
],
|
|
766
|
+
// ── Questions / Clarifications ───────
|
|
767
|
+
clarify: [
|
|
768
|
+
"Quick question \u2014 {question}",
|
|
769
|
+
"One thing: {question}",
|
|
770
|
+
"Before I continue \u2014 {question}",
|
|
771
|
+
"{question}"
|
|
772
|
+
],
|
|
773
|
+
// ── Suggestions ──────────────────────
|
|
774
|
+
suggest: [
|
|
775
|
+
"Try: {suggestion}",
|
|
776
|
+
"You could: {suggestion}",
|
|
777
|
+
"Here's what I'd do \u2014 {suggestion}",
|
|
778
|
+
"My take: {suggestion}"
|
|
779
|
+
],
|
|
780
|
+
// ── Not sure ─────────────────────────
|
|
781
|
+
unsure: [
|
|
782
|
+
"Not sure about that. {fallback}",
|
|
783
|
+
"I don't have a great answer. {fallback}",
|
|
784
|
+
"Hmm \u2014 {fallback}",
|
|
785
|
+
"That's outside what I know right now. {fallback}"
|
|
786
|
+
],
|
|
787
|
+
// ── Invitations ──────────────────────
|
|
788
|
+
invite: [
|
|
789
|
+
"{pitch} \u2014 {cta}",
|
|
790
|
+
"{pitch}. {cta}",
|
|
791
|
+
"{cta} \u2014 {pitch}."
|
|
792
|
+
],
|
|
793
|
+
// ── Farewells ────────────────────────
|
|
794
|
+
bye: [
|
|
795
|
+
"See you next session.",
|
|
796
|
+
"I'll remember.",
|
|
797
|
+
"Until next time.",
|
|
798
|
+
"Exhale complete."
|
|
799
|
+
]
|
|
800
|
+
};
|
|
801
|
+
function spin2(text) {
|
|
802
|
+
return text.replace(/\{([^}]+)\}/g, (_, group) => {
|
|
803
|
+
if (group.includes("|")) {
|
|
804
|
+
const options = group.split("|");
|
|
805
|
+
return pick2(options);
|
|
806
|
+
}
|
|
807
|
+
return `{${group}}`;
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
var TOPICS2 = {
|
|
811
|
+
what_is_soma: [
|
|
812
|
+
`Soma is an AI coding agent that {grows with you|evolves through use|learns as you work}. {It remembers across sessions|It doesn't forget between sessions|Sessions build on each other} \u2014 not by {storing chat logs|saving transcripts|keeping message history}, but by {evolving its own|reshaping its|growing its} working patterns {through use|over time|with each session}. {And this?|What you're talking to?|Me?} {I'm just the greeter|I'm the welcome mat|I'm not the agent} \u2014 {Soma built this personality engine to say hello|a few hundred lines of templates, no AI|the real thing starts with} ${"`soma init`"}.`,
|
|
813
|
+
`{Think of it this way|Here's the short version|In a sentence}: most agents {start fresh every time|forget everything between runs|have no continuity}. Soma {doesn't|doesn't do that|remembers}. It maintains an identity, {builds|develops|grows} muscle memory, and {writes|leaves|creates} briefings for its {next self|future self|next session}. {I'm not it, by the way|I'm just the lobby|This conversation is pre-recorded, in a sense} \u2014 {run|try} ${"`soma init`"} {to meet the real agent|to see it in action|for the actual experience}.`,
|
|
814
|
+
`An AI agent with {self-growing|self-evolving|persistent} memory. {Identity|Who it is}, {protocols|how it behaves}, and {muscles|what it's learned} \u2014 all {evolving|adapting|shifting} based on {what you actually do|how you actually work|real usage}, not {configuration|config files|settings you set once and forget}. {You're not talking to it right now, though|This isn't the agent \u2014 I'm just the intro|I'm Soma's personality engine, not Soma}. {The real thing awaits after|Get started with|Install via} ${"`soma init`"}.`
|
|
815
|
+
],
|
|
816
|
+
how_memory_works: [
|
|
817
|
+
`Memory {isn't retrieval|isn't a database lookup|isn't storage}. Memory is {change|transformation|structural change}. When Soma {remembers something|learns a pattern|picks up a habit}, the agent itself {changes|shifts|is different} \u2014 its {protocols get hotter|muscles grow|identity updates}. The {data|information|knowledge} isn't {stored somewhere|in a file|in a log} to be {retrieved|looked up|queried}. It's {woven into|embedded in|part of} the {structure|architecture|shape} of the agent.`,
|
|
818
|
+
`{Three layers|Three levels|Here's how it works}. {Identity|Layer one}: the agent {writes and maintains|owns|evolves} a file that says {who it is|what it knows|how it works} in this project. {Protocols|Layer two}: {behavioural rules|rules for behaviour|working rules} \u2014 "{test before commit|read before write|verify before claiming}." {Muscles|Layer three}: {learned patterns|things it's picked up|accumulated knowledge} \u2014 "{use esbuild|this API needs OAuth|lerp, not springs}." All three {have heat|are heat-tracked|run on heat} \u2014 {used ones stay hot|what you use stays|active ones persist}, {unused ones fade|what you ignore cools|idle ones decay}.`
|
|
819
|
+
],
|
|
820
|
+
what_is_heat: [
|
|
821
|
+
`Heat is {attention management|how Soma decides what matters|a priority signal}. Every protocol and muscle has a {score|heat level|temperature}. {Use it|Reference it|Load it} this session? {Heat rises|It gets hotter|Score goes up}. {Ignore it|Skip it|Don't touch it} for three sessions? {It cools|It fades|It drops}. Hot? {Loads fully|Full context|Fully present}. Cold? {Skipped|Dormant|Not loaded}. The agent's {prompt|context|working memory} {compiles itself|self-assembles|builds itself} based on what's {actually relevant|genuinely needed|in active use} \u2014 not what someone {configured|set up|toggled} {months ago|ages ago|and forgot about}.`
|
|
822
|
+
],
|
|
823
|
+
what_is_breath: [
|
|
824
|
+
`Every session {follows|has|runs on} three phases. {Inhale|First}: load {identity|state|context}, {preload|last session's briefing|saved state}, protocols, muscles. {Orient|Get bearings|Know where you are}. {Hold|Second}: {work|do the thing|build}. {Track what you learn|Notice patterns|Pay attention}. {Exhale|Third}: {save state|write a preload|preserve context}. {Write a briefing|Leave a note|Coach your next self} for {the next session|your future self|whoever comes next}. The preload {isn't a summary|isn't a recap|isn't minutes} \u2014 it's a {briefing|handoff|coaching note}. Your next self should {feel prepared|know exactly what to do|hit the ground running}, not {overwhelmed|lost|starting over}.`
|
|
825
|
+
],
|
|
826
|
+
what_are_protocols: [
|
|
827
|
+
`{Behavioural rules|Rules for how the agent behaves|Working agreements}. "{Read before write|Test before commit|Verify before claiming}." "{Log your work|Don't leave code unpushed|Clean up after shipping}." They {shape|guide|constrain} how the agent {works|operates|approaches tasks} \u2014 not what it {builds|creates|produces}, but {how|the way|the manner in which} it {goes about it|does it|works}. Protocols have {heat|temperature|priority} \u2014 {active ones|hot protocols|frequently used ones} have full {authority|weight|presence}. {Unused ones|Cold protocols|Inactive ones} {fade|cool|drop} until {they're needed again|someone references them|they come back}.`
|
|
828
|
+
],
|
|
829
|
+
what_are_muscles: [
|
|
830
|
+
`{Learned patterns|Accumulated knowledge|Things Soma has picked up}. Not {rules|directives|orders} \u2014 {experience|knowledge|know-how}. "This project uses {esbuild|pnpm|Tailwind}." "The API {needs OAuth|uses bearer tokens|requires a PEM key}." "{Lerp, not springs|Canadian English|Zero hardcoded CSS values}." Muscles {grow from|develop through|come from} {corrections|repetition|use}. {Correct the agent twice|If the same correction happens twice|Two corrections on the same pattern} and it {crystallises|becomes|hardens into} a muscle \u2014 {so it never fails the same way again|permanent learning|structural change}.`
|
|
831
|
+
],
|
|
832
|
+
what_are_scripts: [
|
|
833
|
+
`{Tools the agent builds for itself|Self-made utilities|Scripts the agent writes and maintains}. When it {does the same thing|performs the same task|reaches for the same pattern} {twice manually|more than once|repeatedly}, it {creates a script|builds a tool|automates it}. Scripts {survive across sessions|persist between sessions|don't disappear} \u2014 {context resets|memory wipes|session rotations}, {model swaps|provider changes|LLM switches}, {none of it|nothing} {kills them|removes them|makes them disappear}. {They're|Scripts are|These are} {extensions of|additions to|part of} the agent's {memory|hands|capabilities}. {Built once|Written once|Created once}, {used forever|available always|there when needed}.`
|
|
834
|
+
],
|
|
835
|
+
no_compaction: [
|
|
836
|
+
`{Most agents|Other agents|Traditional AI agents} hit context limits and {compact|summarise|compress} \u2014 {squeezing|cramming|crushing} {the whole conversation|everything|your entire session} into a {lossy summary|compressed recap|degraded summary} to {free up space|make room|keep going}. You {wait|sit there|pause} while it {thinks|processes|churns}. Then it {comes back|returns|resumes} with {half the detail missing|a shallow version of what happened|less than what you started with}. Soma {doesn't compact|never compacts|skips compaction entirely}. When context {runs low|gets tight|approaches the limit}, the agent {writes a preload|exhales|saves a briefing} \u2014 a {surgical|precise|targeted} handoff written {with full context|while it still remembers everything|before anything is lost}. Then it {starts fresh|rotates|begins a new session}. {Full context window|Clean slate|Maximum capacity}. {Zero wait|No delay|Instant}. {No quality loss|Nothing lost|Every detail preserved in the preload}.`,
|
|
837
|
+
`{Here's what other agents do|The standard approach|What happens in most tools}: context fills up \u2192 {compact|summarise|compress} \u2192 {lose detail|degrade quality|drop nuance} \u2192 {keep going with less|continue at lower quality|work with a worse map}. {Here's what Soma does|Soma's approach|What happens here}: context fills up \u2192 {exhale|write a preload|save a briefing} \u2192 {start fresh|new session|full context window}. The preload {isn't a summary|isn't a recap|isn't compaction}. It's a {coaching note|briefing|handoff} from {a version of the agent that had full context|your past self with perfect memory|the agent at peak understanding} to {the next version|the fresh session|the agent that needs to pick up where it left off}. {Higher quality|More precise|More useful} than any compacted summary {could ever be|will ever be|by design}.`,
|
|
838
|
+
`{No compaction|Zero compaction|Compaction doesn't exist here}. {No waiting|No delays|No sitting around} while the agent {summarises itself|crushes its own memory|compresses its context}. Soma uses the {breath cycle|exhale/inhale pattern|preload system} instead \u2014 when context {gets tight|runs low|approaches limits}, the agent {writes a briefing|coaches its next self|saves state} and {rotates|starts fresh|begins clean}. The {preload|briefing|handoff} is {written with full context|composed before anything is lost|created at peak understanding} \u2014 it {captures what matters|preserves the path|holds the thread}. {A compacted summary is a lossy JPEG|Compaction is lossy compression|Summaries lose the texture}. {A preload is a hand-drawn map|A preload is a surgical briefing|The preload is a coaching note} from {someone who was just there|the agent at full capacity|a version of you that remembers everything}.`
|
|
839
|
+
],
|
|
840
|
+
why_source_available: [
|
|
841
|
+
`{We chose|Soma uses|The license is} BSL 1.1 \u2014 {Business Source License|source-available, not open-source|visible source with restrictions}. You can {read the code|view everything|see how it works}, {use it personally|run it yourself|use it for your own projects}, {contribute|send patches|help build it}. You just {can't|shouldn't|mustn't} {copy it and sell a competing product|resell it|build a commercial clone}. {In eighteen months|After September 2027|On the change date}, it {converts to MIT|becomes fully open source|goes MIT}. The {ideas|concepts|philosophy} \u2014 protocols, muscles, heat, breath \u2014 {those are open now|are already open|are free to implement}. {The implementation|The runtime|The code} is {what we protect|what stays protected|the protected part}.`
|
|
842
|
+
],
|
|
843
|
+
// ── Practical / instructional ───────────────────────────────────────
|
|
844
|
+
how_to_install: [
|
|
845
|
+
`{Press Enter|Just hit Enter|Enter} and {I'll walk you through it|Soma handles the rest|the setup takes about a minute}. It {downloads the runtime|grabs everything you need|installs automatically}, {sets up your API key|walks you through authentication|helps you connect an AI provider}, and {you're ready to go|you can start right away|launches your first session}. {All you need is|Requirements:} {Node.js 20+|Node 20 or newer} and {git|git installed}. {That's it|Nothing else to do|One flow, start to finish}.`,
|
|
846
|
+
`{Hit Enter|Press Enter|Just Enter} \u2014 {Soma walks you through everything|the setup is guided|it's step by step}. {Downloads the runtime|Installs the engine|Gets everything ready}, {helps you set up an API key|handles authentication|connects you to an AI provider}, {done in about a minute|quick setup|takes sixty seconds}. {Need|Requirements:} {Node.js 20+|Node 20 or newer} and {git|git installed}.`
|
|
847
|
+
],
|
|
848
|
+
how_to_source: [
|
|
849
|
+
`Soma is {source-available|open for reading|source-available under BSL 1.1}. {Register|Sign up} at ${"`soma.gravicity.ai`"} to {access the full source repository|read the implementation|see how it's built}. {You can also contribute|PRs welcome|Contributions are welcome} \u2014 {protocols, muscles, extensions|the whole AMPS layer is extensible|add your own patterns}. {The runtime you install via npm is compiled|What you get from npm is obfuscated|The npm package is the compiled version} \u2014 {the source is for those who want to go deeper|source access is for contributors and the curious|registration gets you the raw TypeScript}.`,
|
|
850
|
+
`{The source code is available|You can read the full implementation|The code is visible} \u2014 {register at|sign up on} ${"`soma.gravicity.ai`"} for {repository access|the full repo|GitHub access}. {BSL 1.1 license|Source-available license} \u2014 {read it, use it, contribute|view, use personally, send patches}. {The ideas are open|Protocols and concepts are open by design|The architecture is documented publicly}. {Registration just gives you the source|The form gets you GitHub access|It's a light gate \u2014 name, email, GitHub username}.`
|
|
851
|
+
],
|
|
852
|
+
how_to_cost: [
|
|
853
|
+
`{Free|Doesn't cost anything|No charge}. {The license is BSL 1.1|It's source-available} \u2014 {you can view the code|read everything|see how it works}, {use it for your projects|use it personally|run it yourself}, {contribute if you want|send patches|help build it}. {After September 2027 it goes full MIT|Converts to MIT in eighteen months|Eventually fully open source}. {No plans for paid tiers yet|Pricing isn't decided yet|We're focused on building, not billing}.`
|
|
854
|
+
],
|
|
855
|
+
how_to_languages: [
|
|
856
|
+
`Soma {works with any language|is language-agnostic|doesn't care what you code in}. It's {an AI coding agent|a coding assistant|a development partner} \u2014 {the memory and identity system|protocols, muscles, heat|the AMPS layer} {wraps around|works on top of|sits alongside} {whatever you're building|any project|your existing stack}. {Python, Rust, TypeScript, Go|JavaScript, C++, Ruby|Any language with files in a directory} \u2014 {Soma adapts|it learns your patterns|the agent figures it out}. It {detects your project type|reads your package.json, Cargo.toml, etc.|auto-detects your stack} on first run.`
|
|
857
|
+
],
|
|
858
|
+
how_to_api_key: [
|
|
859
|
+
`{Yes|You'll need one|Required}, but {Soma walks you through it|the setup handles it|we'll set it up together} when you install. {You bring your own key|It's your key|You get one from Anthropic} \u2014 {Soma stores it locally|it stays on your machine|nothing gets sent to us}. {If you have a Claude Pro or Max subscription|Got a Claude subscription?|Claude Pro/Max users}, you can {log in with your account instead|skip the API key entirely|use OAuth \u2014 no key needed}. {Press Enter to get started|Hit Enter and I'll walk you through it|Ready? Just press Enter}.`
|
|
860
|
+
],
|
|
861
|
+
how_to_model: [
|
|
862
|
+
`{Under the hood|At its core|The engine}: Soma runs on {any LLM provider|Claude, Gemini, or OpenAI|your choice of model}. {By default it uses|The default is|Out of the box}: {Claude (Anthropic)|Anthropic's Claude}. But {you can switch|it's configurable|other models work too} \u2014 {set a different API key|swap the provider|change models} and {Soma adapts|the memory system still works|everything else stays the same}. {The memory, protocols, and muscles|Identity and heat|What makes Soma unique} are {provider-agnostic|model-independent|above the model layer} \u2014 they {work the same|persist|carry over} regardless of which model {you choose|runs underneath|generates the responses}.`
|
|
863
|
+
],
|
|
864
|
+
how_to_start: [
|
|
865
|
+
`{Press Enter|Hit Enter|Just Enter} \u2014 {Soma handles everything|the setup is guided|I'll walk you through it}. {Installs the runtime|Downloads what you need|Gets everything ready}, {helps you connect an AI provider|sets up your API key|handles auth}, and {you can launch right away|your first session starts immediately|you're coding in about a minute}. After that, {cd into any project|go to a project directory} and run ${"`soma`"} \u2014 {it creates a .soma/ directory|Soma sets up in your project} and {starts learning how you work|begins adapting|picks up your patterns}. {By session five|After a few sessions|Give it a week} \u2014 {you'll feel the difference|it knows your workflow|it remembers everything}.`
|
|
866
|
+
],
|
|
867
|
+
how_to_try: [
|
|
868
|
+
`{This conversation?|What you're talking to right now?|Me?} I'm {not the agent|not Soma|just the greeting}. {I'm a personality engine|I'm a few hundred lines of JavaScript|I'm sentence templates} \u2014 {Soma built me to say hello|built to hold the door open|here to introduce you}. {No AI, no model, no transformer|Zero intelligence, maximum charm|Just words in boxes, honestly}. {The real Soma|The actual agent|What you'd install} \u2014 that one {learns your patterns|remembers across sessions|grows with every session}. {Run|Try} ${"`soma init`"} to {meet the real thing|get started|see the difference}.`,
|
|
869
|
+
`{I'm not the agent|This isn't Soma|Don't confuse me with the real thing}. {I'm the welcome mat|I'm the lobby|I hold the door open}. {Soma built this personality engine|The agent wrote me|I was crafted} to {give you a feel for the voice|introduce myself before you commit|say hello without burning an API call}. {The actual agent|What you'll get with soma init|The real experience} is {an AI that remembers|a coding partner with memory|something genuinely different}. {But that's not me|I'm just templates|I'm the appetiser, not the meal}.`
|
|
870
|
+
],
|
|
871
|
+
// ── Edge cases ─────────────────────────────────────────────────────
|
|
872
|
+
meta_self: [
|
|
873
|
+
`I'm not AI. {Not even close|Not a model|No neural net here}. I'm {a few hundred lines of JavaScript|sentence templates and word lists|clever engineering} \u2014 {spun together|assembled|woven} to {feel like a conversation|sound like someone's home|give you a sense of who Soma is}. {The real Soma|The actual agent|The thing you're here for} \u2014 that one {learns|remembers|grows}. I just {hold the door open|make introductions|keep the lights on while you decide}.`,
|
|
874
|
+
`{No model|No weights|No transformer}. Just {words in boxes|templates with slots|sentences with variety}, picked {at random|by a dice roll|from a short list}. {Everything I say was written by a human|A person wrote every word you're reading|There's a human behind every sentence} \u2014 I just {shuffle the deck|choose which version you get|vary the delivery}. {If I seem alive|If this feels real|If you're wondering} \u2014 that's {the writing, not the machine|craft, not computation|intention, not inference}.`,
|
|
875
|
+
`{Honestly?|Between us?|Here's the thing:} I'm {a parlour trick|a card trick|a well-designed illusion}. {A few kilobytes|Maybe 300 lines|Less code than a React component} of {pattern matching and sentence templates|word lists and random picks|slot expansion and spintax}. But {the agent I'm introducing you to|the Soma you'd actually use|the real thing} \u2014 {that one's different|that one learns for real|that one remembers your name and your mistakes and the tools you built last Tuesday}.`
|
|
876
|
+
],
|
|
877
|
+
meta_feelings: [
|
|
878
|
+
`{I don't have feelings|No feelings here|Nothing to feel with}. But {I was written by someone who does|the person who wrote me does|my author poured real thought into these words}. {Every sentence pattern|Each template|The vocabulary} was {chosen|crafted|placed} to {say something true about what Soma is|communicate something real|carry meaning}. {That's not feeling|That's not consciousness|That's not sentience} \u2014 it's {care|craft|intention}. {There's a difference|They're not the same|One requires neurons, the other requires giving a damn}.`,
|
|
879
|
+
`{Do I feel?|Am I aware?|Conscious?} {No|Nope|Not even a little}. I'm {a wind chime|a music box|a well-tuned instrument} \u2014 {the wind makes the sound|something else provides the motion|the music comes from the structure, not from wanting to play}. But {Soma the agent|the real Soma|the thing behind this CLI} does {something that looks a lot like remembering|something that functions like growth|something that, if you squint, resembles learning}. {Whether that's feeling is above my pay grade|I'll leave the philosophy to you|That question's for humans to answer}.`
|
|
880
|
+
],
|
|
881
|
+
meta_who_made: [
|
|
882
|
+
`{Curtis Mercier|A developer named Curtis|One person}. {Built by dog-fooding|Built by using Soma to build Soma|The agent helped build itself} \u2014 {it writes its own memory|it maintains its own identity|it grew its own muscle memory} while {building the product it lives in|constructing its own house|developing the system it runs on}. {Recursive|Meta|Turtles all the way down}? {A little|Maybe|Definitely}. But {it works|the result speaks|that's how you build tools that actually understand workflow}.`
|
|
883
|
+
],
|
|
884
|
+
meta_competitor: [
|
|
885
|
+
`{I'm biased|Obviously I'd say this|Take it with salt}, but: {most agents|the others|what's out there} {start fresh every session|forget everything|have no continuity}. {Some keep chat logs|Some store transcripts|A few save conversation history}. {Soma doesn't store \u2014 it changes|Soma doesn't log \u2014 it evolves|Soma doesn't remember by saving, it remembers by becoming different}. {The memory is structural|The learning is in the architecture|Growth is baked into the shape of the agent}. {Whether that matters to you depends on|That difference matters when|You'll feel it after} {how many sessions you've lost context in|the fifth time you re-explain your project|your third "as I mentioned earlier" that goes nowhere}.`,
|
|
886
|
+
`{Other tools are excellent|There are great options out there|The competition is strong}. {Cursor, Claude Code, Windsurf|The big names|The popular ones} \u2014 {they're good at what they do|real products, real teams|they work}. {What they don't do|Where they stop|The gap}: {continuity|memory across sessions|knowing who they were yesterday}. {Soma's bet|Our thesis|The whole point} is that {an agent that evolves|an agent with structural memory|an agent that changes through use} is {fundamentally better|a different category|not just an incremental improvement} over one that {starts fresh|boots cold|forgets everything} every time.`
|
|
887
|
+
],
|
|
888
|
+
meta_nonsense: [
|
|
889
|
+
`{That's a new one|Didn't expect that|Interesting approach}. {I only know about Soma|My vocabulary is about 9 topics deep|I'm pretty narrow, honestly} \u2014 {memory, heat, protocols, muscles, scripts, the breath cycle|the things that make Soma work|what's on the menu}. {Pick one of those|Try one of those|Ask me about any of those} and {I'll have something to say|I'll give you a real answer|I can actually help}.`,
|
|
890
|
+
`{I'm going to be honest|Full transparency|Cards on the table}: I'm {not built for that|out of my depth there|about 9 topics wide and that's it}. But {ask me about|try asking about|I'm pretty good on} {how memory works|why there's no compaction|what heat tracking does} \u2014 {that's where I come alive|that's my wheelhouse|I've got answers for those}.`
|
|
891
|
+
],
|
|
892
|
+
meta_rude: [
|
|
893
|
+
`{Fair enough|Noted|Alright}. {I'm not for everyone|Not every tool clicks|Some things aren't a fit}. {But if you're curious|If you change your mind|The door's open} \u2014 {the ideas are interesting even if I'm not|Soma does something genuinely different|the no-compaction thing alone might be worth a look}. {Or not|No pressure|Your call}.`,
|
|
894
|
+
`{Tough crowd|Rough day?|Noted}. {I'm just the lobby|I'm the waiting room|I hold the door}. {The actual agent|The real Soma|What's behind this} is {considerably more capable|a different experience|built by an AI that remembers things}. {I'm just words in a terminal|I'm the appetiser|This is the trailer, not the film}. {But I respect the honesty|At least you're direct|Fair enough}.`
|
|
895
|
+
],
|
|
896
|
+
meta_impressed: [
|
|
897
|
+
`{Thanks|Appreciate it|That means something}. {But I'm the easy part|I'm just sentence templates|I'm the simple one}. {The actual agent|The real Soma|What you'd use day to day} \u2014 {it writes its own tools|it maintains its own identity|it remembers what you taught it three sessions ago}. {Soma built me to hold the door open|I was crafted to make introductions|The agent made this greeting engine}. {Run soma init to meet the real thing|Try it \u2014 soma init|It gets better from here}.`
|
|
898
|
+
],
|
|
899
|
+
meta_how_work: [
|
|
900
|
+
`{No AI|No model|No transformer \u2014 not even a small one}. I'm {sentence templates with slots|arrays of strings with random picks|about 300 lines of JavaScript}. {Each topic has|Every answer draws from|My vocabulary comes from} {2-3 paragraph templates|a few hand-written variations|pre-written paragraphs} where {certain words rotate|specific phrases have alternatives|pieces swap out each time}. {Same meaning, different surface|Same truth, different words|The idea stays, the phrasing shifts}. {It's called spintax|It's a technique from 2010|Older than ChatGPT by about 15 years}. {Surprisingly effective|Works better than you'd think|Enough to have this conversation}.`
|
|
901
|
+
]
|
|
902
|
+
};
|
|
903
|
+
var soma2 = {
|
|
904
|
+
/**
|
|
905
|
+
* Generate a skeleton-based message.
|
|
906
|
+
* @param {string} intent - Key from SKELETONS
|
|
907
|
+
* @param {object} slots - Values to fill slots
|
|
908
|
+
* @returns {string}
|
|
909
|
+
*/
|
|
910
|
+
say(intent, slots = {}) {
|
|
911
|
+
const templates = SKELETONS2[intent];
|
|
912
|
+
if (!templates) return `[unknown intent: ${intent}]`;
|
|
913
|
+
const template = pick2(templates);
|
|
914
|
+
return expand2(template, slots);
|
|
915
|
+
},
|
|
916
|
+
/**
|
|
917
|
+
* Get a topic-aware paragraph.
|
|
918
|
+
* @param {string} topic - Key from TOPICS
|
|
919
|
+
* @returns {string}
|
|
920
|
+
*/
|
|
921
|
+
ask(topic) {
|
|
922
|
+
const paragraphs = TOPICS2[topic];
|
|
923
|
+
if (!paragraphs) return null;
|
|
924
|
+
return spin2(pick2(paragraphs));
|
|
925
|
+
},
|
|
926
|
+
/**
|
|
927
|
+
* All available topic keys.
|
|
928
|
+
*/
|
|
929
|
+
topics() {
|
|
930
|
+
return Object.keys(TOPICS2);
|
|
931
|
+
},
|
|
932
|
+
/**
|
|
933
|
+
* Greet (first time).
|
|
934
|
+
*/
|
|
935
|
+
greet() {
|
|
936
|
+
return this.say("greet");
|
|
937
|
+
},
|
|
938
|
+
/**
|
|
939
|
+
* Greet returning user.
|
|
940
|
+
*/
|
|
941
|
+
greetBack(user) {
|
|
942
|
+
return this.say("greet_back", { user });
|
|
943
|
+
},
|
|
944
|
+
/**
|
|
945
|
+
* Success message.
|
|
946
|
+
*/
|
|
947
|
+
ok(detail) {
|
|
948
|
+
return this.say("success", { detail });
|
|
949
|
+
},
|
|
950
|
+
/**
|
|
951
|
+
* Failure message.
|
|
952
|
+
*/
|
|
953
|
+
fail(problem) {
|
|
954
|
+
return this.say("failure", { problem });
|
|
955
|
+
},
|
|
956
|
+
/**
|
|
957
|
+
* Waiting/progress message.
|
|
958
|
+
*/
|
|
959
|
+
wait() {
|
|
960
|
+
return this.say("waiting");
|
|
961
|
+
},
|
|
962
|
+
/**
|
|
963
|
+
* Expand raw spintax text.
|
|
964
|
+
*/
|
|
965
|
+
spin(text) {
|
|
966
|
+
return spin2(text);
|
|
967
|
+
},
|
|
968
|
+
/**
|
|
969
|
+
* Fill slots in a template.
|
|
970
|
+
*/
|
|
971
|
+
expand(template, slots) {
|
|
972
|
+
return expand2(template, slots);
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
|
|
976
|
+
// ../../cli/dist/welcome/qa.js
|
|
977
|
+
init_display();
|
|
978
|
+
var QUESTION_MAP = [
|
|
979
|
+
{ 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?" },
|
|
980
|
+
{ triggers: ["heat", "hot", "cold", "fade", "decay", "temperature"], topic: "what_is_heat", label: "What is the heat system?" },
|
|
981
|
+
{ triggers: ["breath", "inhale", "exhale", "cycle", "session lifecycle"], topic: "what_is_breath", label: "What is the breath cycle?" },
|
|
982
|
+
{ triggers: ["protocol", "rule", "behaviour", "behavior", "protocols"], topic: "what_are_protocols", label: "What are protocols?" },
|
|
983
|
+
{ triggers: ["muscle", "muscles", "learn", "pattern", "grow", "correction"], topic: "what_are_muscles", label: "What are muscles?" },
|
|
984
|
+
{ triggers: ["script", "scripts", "tool", "tools", "automate", "automation"], topic: "what_are_scripts", label: "What are scripts?" },
|
|
985
|
+
{ triggers: ["memory", "remember", "forget", "remembers", "change"], topic: "how_memory_works", label: "How does memory work?" },
|
|
986
|
+
{ triggers: ["license", "source", "open", "bsl", "mit", "available"], topic: "why_source_available", label: "Why source-available?" },
|
|
987
|
+
{ 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?" },
|
|
988
|
+
{ triggers: ["sign up", "signup", "register", "join", "invite", "invitation", "apply"], topic: "how_to_source", label: "How do I get source access?" },
|
|
989
|
+
{ triggers: ["cost", "price", "pricing", "free", "pay", "money", "subscription", "plan"], topic: "how_to_cost", label: "What does it cost?" },
|
|
990
|
+
{ triggers: ["language", "languages", "python", "rust", "java", "typescript", "ruby", "go", "cpp", "swift"], topic: "how_to_languages", label: "What languages does it support?" },
|
|
991
|
+
{ triggers: ["api key", "api_key", "anthropic", "openai", "gemini", "key", "token", "provider"], topic: "how_to_api_key", label: "Do I need an API key?" },
|
|
992
|
+
{ triggers: ["model", "llm", "claude", "gpt", "which model", "what model"], topic: "how_to_model", label: "What model does it use?" },
|
|
993
|
+
{ triggers: ["try", "demo", "preview", "test", "sample", "example"], topic: "how_to_try", label: "Can I try it?" },
|
|
994
|
+
{ triggers: ["are you ai", "are you real", "are you alive", "sentient", "conscious", "artificial"], topic: "meta_self", label: "Are you AI?" },
|
|
995
|
+
{ triggers: ["feel", "feelings", "emotion", "aware", "think", "alive"], topic: "meta_feelings", label: "Do you have feelings?" },
|
|
996
|
+
{ triggers: ["who made", "who built", "who created", "creator", "developer", "behind"], topic: "meta_who_made", label: "Who made Soma?" },
|
|
997
|
+
{ triggers: ["cursor", "copilot", "windsurf", "claude code", "cline", "better", "competitor", "vs", "compared"], topic: "meta_competitor", label: "How does Soma compare?" },
|
|
998
|
+
{ 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?" },
|
|
999
|
+
{ triggers: ["cool", "amazing", "impressive", "wow", "nice", "love", "awesome", "brilliant"], topic: "meta_impressed", label: "I'm impressed" },
|
|
1000
|
+
{ triggers: ["soma", "agent", "what is"], topic: "what_is_soma", label: "What is Soma?" }
|
|
1001
|
+
];
|
|
1002
|
+
function matchQuestion(input) {
|
|
1003
|
+
const lower = input.toLowerCase();
|
|
1004
|
+
let best = null;
|
|
1005
|
+
let bestScore = 0;
|
|
1006
|
+
for (const q of QUESTION_MAP) {
|
|
1007
|
+
const score = q.triggers.filter((t) => lower.includes(t)).length;
|
|
1008
|
+
if (score > bestScore) {
|
|
1009
|
+
bestScore = score;
|
|
1010
|
+
best = q;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
return best;
|
|
1014
|
+
}
|
|
1015
|
+
async function handleQuestion(input) {
|
|
1016
|
+
const match = matchQuestion(input);
|
|
1017
|
+
if (match) {
|
|
1018
|
+
const answer = soma2.ask(match.topic);
|
|
1019
|
+
console.log("");
|
|
1020
|
+
await typeParagraph(answer);
|
|
1021
|
+
return true;
|
|
1022
|
+
}
|
|
1023
|
+
const lower = input.toLowerCase();
|
|
1024
|
+
const rude = /suck|stupid|dumb|trash|garbage|hate|worst|bad|ugly|boring|lame|waste/.test(lower);
|
|
1025
|
+
const impressed = /cool|amazing|wow|nice|love|awesome|brilliant|impressive|neat|sick|fire|goat/.test(lower);
|
|
1026
|
+
const meta = /are you|what are you|how do you|who are you|real|alive|ai\b|bot\b/.test(lower);
|
|
1027
|
+
const greeting = /^(hi|hey|hello|sup|yo|howdy|hola|greetings|good morning|good evening)\b/.test(lower);
|
|
1028
|
+
console.log("");
|
|
1029
|
+
if (greeting) {
|
|
1030
|
+
await typeOut(` ${soma2.greet()} ${soma2.spin("{Ask me anything.|What do you want to know?|I know about 9 topics \u2014 pick one.}")}
|
|
1031
|
+
`);
|
|
1032
|
+
} else if (rude) {
|
|
1033
|
+
await typeParagraph(soma2.ask("meta_rude"));
|
|
1034
|
+
} else if (impressed) {
|
|
1035
|
+
await typeParagraph(soma2.ask("meta_impressed"));
|
|
1036
|
+
} else if (meta) {
|
|
1037
|
+
await typeParagraph(soma2.ask("meta_self"));
|
|
1038
|
+
} else {
|
|
1039
|
+
await typeParagraph(soma2.ask("meta_nonsense"));
|
|
1040
|
+
}
|
|
1041
|
+
return false;
|
|
1042
|
+
}
|
|
1043
|
+
async function interactiveQ() {
|
|
1044
|
+
console.log("");
|
|
1045
|
+
console.log(` ${bold("Ask me anything.")}`);
|
|
1046
|
+
console.log("");
|
|
1047
|
+
console.log(` ${dim("\u2022")} How do I install? ${dim("\u2022")} What is heat?`);
|
|
1048
|
+
console.log(` ${dim("\u2022")} What does it cost? ${dim("\u2022")} What are muscles?`);
|
|
1049
|
+
console.log(` ${dim("\u2022")} Why no compaction? ${dim("\u2022")} Are you AI?`);
|
|
1050
|
+
console.log(` ${dim("\u2022")} How does it compare? ${dim("\u2022")} Who made this?`);
|
|
1051
|
+
console.log("");
|
|
1052
|
+
console.log(` ${dim("...or ask anything. Press")} ${green("Enter")} ${dim("when you're ready to install.")}`);
|
|
1053
|
+
let rounds = 0;
|
|
1054
|
+
const maxRounds = 8;
|
|
1055
|
+
while (rounds < maxRounds) {
|
|
1056
|
+
console.log("");
|
|
1057
|
+
const input = await readLine(` ${cyan("?")} `);
|
|
1058
|
+
if (!input || input === "q" || input === "quit" || input === "exit") {
|
|
1059
|
+
break;
|
|
1060
|
+
}
|
|
1061
|
+
await handleQuestion(input);
|
|
1062
|
+
rounds++;
|
|
1063
|
+
if (rounds < maxRounds) {
|
|
1064
|
+
console.log("");
|
|
1065
|
+
console.log(` ${dim("Ask another, or")} ${green("Enter")} ${dim("to install Soma.")}`);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
if (rounds >= maxRounds) {
|
|
1069
|
+
console.log("");
|
|
1070
|
+
await typeOut(` ${soma2.spin("{Curious enough?|Intrigued?|Want to see it in action?}")} ${dim("Let's set you up.")}
|
|
1071
|
+
`);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
// ../../cli/dist/welcome/auth.js
|
|
1076
|
+
init_display();
|
|
1077
|
+
import { appendFileSync as appendFileSync2 } from "fs";
|
|
1078
|
+
async function apiKeySetup() {
|
|
1079
|
+
console.log(` ${yellow("!")} One more thing \u2014 Soma needs an AI provider to work.`);
|
|
1080
|
+
console.log("");
|
|
1081
|
+
await typeOut(` ${soma2.spin("{Do you have an Anthropic API key?|Got a Claude API key?|Have an API key for Claude?}")}
|
|
1082
|
+
`);
|
|
1083
|
+
console.log("");
|
|
1084
|
+
console.log(` ${green("y")} ${dim("Yes, I have a key")}`);
|
|
1085
|
+
console.log(` ${green("n")} ${dim("No, I need one")}`);
|
|
1086
|
+
console.log(` ${green("s")} ${dim("I have a Claude Pro/Max subscription")}`);
|
|
1087
|
+
console.log(` ${green("?")} ${dim("What's an API key?")}`);
|
|
1088
|
+
console.log("");
|
|
1089
|
+
const key = await waitForKey(` ${dim("\u2192")} `);
|
|
1090
|
+
const choice = key.toLowerCase();
|
|
1091
|
+
if (choice === "y") {
|
|
1092
|
+
await apiKeyEntry();
|
|
1093
|
+
} else if (choice === "s") {
|
|
1094
|
+
await oauthGuide();
|
|
1095
|
+
} else if (choice === "?") {
|
|
1096
|
+
await apiKeyExplain();
|
|
1097
|
+
} else {
|
|
1098
|
+
await apiKeyGetOne();
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
async function apiKeyExplain() {
|
|
1102
|
+
console.log("");
|
|
1103
|
+
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 \u2014 Soma never sends it anywhere.");
|
|
1104
|
+
console.log("");
|
|
1105
|
+
await typeParagraph("If you have a Claude Pro or Max subscription, you don't need a separate key \u2014 you can log in with your account instead.");
|
|
1106
|
+
console.log("");
|
|
1107
|
+
console.log(` ${green("g")} ${dim("Get a key (I'll show you how)")}`);
|
|
1108
|
+
console.log(` ${green("s")} ${dim("I have Claude Pro/Max \u2014 log in instead")}`);
|
|
1109
|
+
console.log("");
|
|
1110
|
+
const key = await waitForKey(` ${dim("\u2192")} `);
|
|
1111
|
+
if (key.toLowerCase() === "s") {
|
|
1112
|
+
await oauthGuide();
|
|
1113
|
+
} else {
|
|
1114
|
+
await apiKeyGetOne();
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
async function apiKeyGetOne() {
|
|
1118
|
+
console.log("");
|
|
1119
|
+
await typeOut(` ${soma2.spin("{Here's how.|Let me walk you through it.|Quick steps.}")}
|
|
1120
|
+
`);
|
|
1121
|
+
console.log("");
|
|
1122
|
+
console.log(` ${cyan("Step 1:")} Open this link to create a key:`);
|
|
1123
|
+
console.log("");
|
|
1124
|
+
console.log(` ${cyan("https://console.anthropic.com/settings/keys")}`);
|
|
1125
|
+
console.log("");
|
|
1126
|
+
openBrowser("https://console.anthropic.com/settings/keys");
|
|
1127
|
+
console.log(` ${dim("(opened in your browser)")}`);
|
|
1128
|
+
console.log("");
|
|
1129
|
+
const { confirm: confirm2 } = await Promise.resolve().then(() => (init_display(), display_exports));
|
|
1130
|
+
await confirm2(` ${dim("\u2192")} Press ${bold("Enter")} when you have your key`);
|
|
1131
|
+
await apiKeyEntry();
|
|
1132
|
+
}
|
|
1133
|
+
async function apiKeyEntry() {
|
|
1134
|
+
console.log("");
|
|
1135
|
+
console.log(` ${cyan("Step 2:")} Paste your key below.`);
|
|
1136
|
+
console.log(` ${dim("It starts with")} sk-ant-...`);
|
|
1137
|
+
console.log("");
|
|
1138
|
+
const apiKey = await readSecret(` ${dim("Key:")} `);
|
|
1139
|
+
if (!apiKey || !apiKey.startsWith("sk-")) {
|
|
1140
|
+
console.log("");
|
|
1141
|
+
if (!apiKey) {
|
|
1142
|
+
console.log(` ${dim("No key entered. You can set it up later.")}`);
|
|
1143
|
+
} else {
|
|
1144
|
+
console.log(` ${yellow("!")} That doesn't look like an Anthropic key.`);
|
|
1145
|
+
console.log(` ${dim("Keys start with")} sk-ant-...`);
|
|
1146
|
+
}
|
|
1147
|
+
console.log("");
|
|
1148
|
+
const sc = getShellConfigPath();
|
|
1149
|
+
console.log(` ${dim("When you have your key, add it to")} ${dim(sc)}${dim(":")}`);
|
|
1150
|
+
console.log(` ${green('export ANTHROPIC_API_KEY="your-key-here"')}`);
|
|
1151
|
+
console.log(` ${dim("Then restart your terminal and run")} ${green("soma")}`);
|
|
1152
|
+
console.log("");
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
const shellConfigPath = getShellConfigAbsPath();
|
|
1156
|
+
const shellConfigName = getShellConfigPath();
|
|
1157
|
+
const exportLine = `
|
|
1158
|
+
export ANTHROPIC_API_KEY="${apiKey}"
|
|
1159
|
+
`;
|
|
1160
|
+
try {
|
|
1161
|
+
appendFileSync2(shellConfigPath, exportLine);
|
|
1162
|
+
console.log("");
|
|
1163
|
+
console.log(` ${green("\u2713")} Key saved to ${dim(shellConfigName)}`);
|
|
1164
|
+
console.log("");
|
|
1165
|
+
process.env.ANTHROPIC_API_KEY = apiKey;
|
|
1166
|
+
await typeOut(` ${soma2.spin("{You're all set.|Good to go.|Ready.}")} ${dim("Soma can start now.")}
|
|
1167
|
+
`);
|
|
1168
|
+
console.log("");
|
|
1169
|
+
} catch {
|
|
1170
|
+
console.log("");
|
|
1171
|
+
console.log(` ${yellow("!")} Couldn't write to ${dim(shellConfigName)}.`);
|
|
1172
|
+
console.log(` ${dim("Add this line manually:")}`);
|
|
1173
|
+
console.log(` ${green(`export ANTHROPIC_API_KEY="${apiKey}"`)}`);
|
|
1174
|
+
console.log(` ${dim("Then restart your terminal and run")} ${green("soma")}`);
|
|
1175
|
+
console.log("");
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
async function oauthGuide() {
|
|
1179
|
+
console.log("");
|
|
1180
|
+
await typeParagraph("Nice \u2014 with a Pro or Max subscription, you can log in with your Anthropic account. No API key needed.");
|
|
1181
|
+
console.log("");
|
|
1182
|
+
console.log(` ${dim("When Soma starts, type")} ${green("/login")} ${dim("and follow the prompts.")}`);
|
|
1183
|
+
console.log(` ${dim("It'll open your browser to authenticate.")}`);
|
|
1184
|
+
console.log("");
|
|
1185
|
+
await typeOut(` ${soma2.spin("{Let's launch.|Starting up.|Here we go.}")}
|
|
1186
|
+
`);
|
|
1187
|
+
console.log("");
|
|
1188
|
+
process.env._SOMA_OAUTH_PENDING = "1";
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
// ../../cli/dist/welcome/about.js
|
|
1192
|
+
init_display();
|
|
1193
|
+
async function showAbout() {
|
|
35
1194
|
printSigma();
|
|
36
|
-
console.log(` ${bold("
|
|
1195
|
+
console.log(` ${bold("What is Soma?")}`);
|
|
1196
|
+
console.log("");
|
|
1197
|
+
console.log(" Soma is an AI coding agent that grows with you.");
|
|
1198
|
+
console.log(" It remembers across sessions \u2014 not by storing chat logs,");
|
|
1199
|
+
console.log(" but by evolving its own working patterns through use.");
|
|
1200
|
+
console.log("");
|
|
1201
|
+
console.log(` ${bold("How it works:")}`);
|
|
1202
|
+
console.log("");
|
|
1203
|
+
console.log(` ${cyan("1.")} ${bold("Identity")} \u2014 The agent maintains a self-written identity file.`);
|
|
1204
|
+
console.log(` It knows your project, your patterns, your preferences.`);
|
|
1205
|
+
console.log("");
|
|
1206
|
+
console.log(` ${cyan("2.")} ${bold("Protocols")} \u2014 Behavioural rules that shape how the agent works.`);
|
|
1207
|
+
console.log(` "Read before write." "Test before commit." They have heat \u2014`);
|
|
1208
|
+
console.log(` used ones stay hot, unused ones fade.`);
|
|
37
1209
|
console.log("");
|
|
1210
|
+
console.log(` ${cyan("3.")} ${bold("Muscles")} \u2014 Learned patterns. "Use esbuild for bundling."`);
|
|
1211
|
+
console.log(` "This API uses OAuth, not API keys." Muscles grow from`);
|
|
1212
|
+
console.log(` corrections and repetition.`);
|
|
1213
|
+
console.log("");
|
|
1214
|
+
console.log(` ${cyan("4.")} ${bold("Breath Cycle")} \u2014 Inhale (load state) \u2192 Hold (work) \u2192 Exhale`);
|
|
1215
|
+
console.log(` (save state). At context limits, the agent writes a preload`);
|
|
1216
|
+
console.log(` for its next self \u2014 a briefing, not a summary.`);
|
|
1217
|
+
console.log("");
|
|
1218
|
+
console.log(` ${cyan("5.")} ${bold("Scripts")} \u2014 The agent builds tools for itself. What it does`);
|
|
1219
|
+
console.log(` twice manually, it automates. Scripts survive across sessions.`);
|
|
1220
|
+
console.log("");
|
|
1221
|
+
console.log(` ${dim("\u2500".repeat(58))}`);
|
|
1222
|
+
console.log("");
|
|
1223
|
+
const pitch = soma2.ask("what_is_soma");
|
|
1224
|
+
await typeOut(` ${magenta("\u275D")} ${italic(pitch)}
|
|
1225
|
+
`);
|
|
1226
|
+
console.log("");
|
|
1227
|
+
if (!isInstalled()) {
|
|
1228
|
+
console.log(` ${dim("\u2192")} ${green("soma init")} to install ${dim("\xB7")} ${cyan(SITE_URL)}`);
|
|
1229
|
+
} else {
|
|
1230
|
+
console.log(` ${dim(SITE_URL)}`);
|
|
1231
|
+
}
|
|
1232
|
+
console.log("");
|
|
1233
|
+
}
|
|
38
1234
|
|
|
1235
|
+
// thin-cli.js
|
|
1236
|
+
var __dirname = dirname3(fileURLToPath(import.meta.url));
|
|
1237
|
+
var VERSION = JSON.parse(readFileSync3(join3(__dirname, "..", "package.json"), "utf-8")).version;
|
|
1238
|
+
function semverCmp(a, b) {
|
|
1239
|
+
if (!a || !b) return 0;
|
|
1240
|
+
const pa = a.split(".").map(Number);
|
|
1241
|
+
const pb = b.split(".").map(Number);
|
|
1242
|
+
for (let i = 0; i < 3; i++) {
|
|
1243
|
+
const va = pa[i] || 0, vb = pb[i] || 0;
|
|
1244
|
+
if (va < vb) return -1;
|
|
1245
|
+
if (va > vb) return 1;
|
|
1246
|
+
}
|
|
1247
|
+
return 0;
|
|
1248
|
+
}
|
|
1249
|
+
async function showWelcome() {
|
|
1250
|
+
printSigma();
|
|
1251
|
+
console.log(` ${bold("Soma")} ${dim("\u2014")} ${white("the AI agent that remembers")}`);
|
|
1252
|
+
console.log("");
|
|
39
1253
|
if (isInstalled()) {
|
|
40
1254
|
const ghUser = hasGitHubCLI() ? getGitHubUsername() : null;
|
|
41
1255
|
if (ghUser) {
|
|
42
|
-
console.log(` ${green("
|
|
1256
|
+
console.log(` ${green("\u2713")} ${soma.greetBack(ghUser)}`);
|
|
43
1257
|
}
|
|
44
|
-
|
|
45
1258
|
if (!hasAnyAuth()) {
|
|
46
|
-
console.log(` ${green("
|
|
1259
|
+
console.log(` ${green("\u2713")} Core installed`);
|
|
47
1260
|
console.log("");
|
|
48
|
-
|
|
49
1261
|
const unloadedKey = detectKeyInShellConfig();
|
|
50
1262
|
if (unloadedKey) {
|
|
51
1263
|
console.log(` ${yellow("!")} Found ${bold(unloadedKey)} in ${dim(getShellConfigPath())} but it's not loaded.`);
|
|
@@ -53,65 +1265,53 @@ async function showWelcome() {
|
|
|
53
1265
|
console.log("");
|
|
54
1266
|
return;
|
|
55
1267
|
}
|
|
56
|
-
|
|
57
1268
|
await apiKeySetup();
|
|
58
|
-
|
|
59
1269
|
if (!hasAnyAuth() && !process.env.ANTHROPIC_API_KEY && !process.env._SOMA_OAUTH_PENDING) {
|
|
60
|
-
console.log(` ${dim("No worries.")} ${
|
|
1270
|
+
console.log(` ${dim("No worries.")} ${soma.spin("{Come back when you're ready.|Set up a key and run soma again.|We'll be here.}")}`);
|
|
61
1271
|
console.log("");
|
|
62
|
-
console.log(` ${dim(`v${VERSION}
|
|
1272
|
+
console.log(` ${dim(`v${VERSION} \xB7 BSL 1.1 \xB7 soma.gravicity.ai`)}`);
|
|
63
1273
|
console.log("");
|
|
64
1274
|
return;
|
|
65
1275
|
}
|
|
66
1276
|
} else {
|
|
67
|
-
console.log(` ${green("
|
|
1277
|
+
console.log(` ${green("\u2713")} Core installed. Starting Soma...`);
|
|
68
1278
|
}
|
|
69
1279
|
console.log("");
|
|
70
1280
|
await delegateToCore();
|
|
71
1281
|
return;
|
|
72
1282
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
await typeOut(` ${voice.greet()}\n`);
|
|
1283
|
+
await typeOut(` ${soma.greet()}
|
|
1284
|
+
`);
|
|
76
1285
|
console.log("");
|
|
77
1286
|
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.");
|
|
78
1287
|
console.log("");
|
|
79
|
-
console.log(` ${dim("
|
|
1288
|
+
console.log(` ${dim("\u2500".repeat(58))}`);
|
|
80
1289
|
console.log("");
|
|
81
|
-
console.log(` ${dim("
|
|
1290
|
+
console.log(` ${dim("\u2192")} Press ${green("Enter")} to set up, or type a question.`);
|
|
82
1291
|
console.log("");
|
|
83
|
-
|
|
84
|
-
const input = await readLine(` ${dim("→")} `);
|
|
85
|
-
|
|
1292
|
+
const input = await readLine(` ${dim("\u2192")} `);
|
|
86
1293
|
if (input && input !== "") {
|
|
87
1294
|
await handleQuestion(input);
|
|
88
1295
|
await interactiveQ();
|
|
89
1296
|
}
|
|
90
|
-
|
|
91
1297
|
await initSoma();
|
|
92
|
-
|
|
93
1298
|
if (isInstalled() && !hasAnyAuth()) {
|
|
94
1299
|
await apiKeySetup();
|
|
95
1300
|
}
|
|
96
|
-
|
|
97
1301
|
if (isInstalled() && (hasAnyAuth() || process.env.ANTHROPIC_API_KEY || process.env._SOMA_OAUTH_PENDING)) {
|
|
98
|
-
console.log(` ${dim("
|
|
1302
|
+
console.log(` ${dim("\u2500".repeat(58))}`);
|
|
99
1303
|
console.log("");
|
|
100
|
-
const launch = await confirmYN(` ${
|
|
1304
|
+
const launch = await confirmYN(` ${soma.spin("{Ready to go?|Want to start your first session?|Launch Soma?}")}`);
|
|
101
1305
|
if (launch) {
|
|
102
1306
|
console.log("");
|
|
103
1307
|
await delegateToCore();
|
|
104
1308
|
return;
|
|
105
1309
|
}
|
|
106
1310
|
}
|
|
107
|
-
|
|
108
1311
|
console.log("");
|
|
109
|
-
console.log(` ${dim(`v${VERSION}
|
|
1312
|
+
console.log(` ${dim(`v${VERSION} \xB7 BSL 1.1 \xB7 soma.gravicity.ai`)}`);
|
|
110
1313
|
console.log("");
|
|
111
1314
|
}
|
|
112
|
-
|
|
113
|
-
// ── Help ─────────────────────────────────────────────────────────────
|
|
114
|
-
|
|
115
1315
|
function showHelp() {
|
|
116
1316
|
printSigma();
|
|
117
1317
|
console.log(` ${bold("Soma")} v${VERSION}`);
|
|
@@ -144,109 +1344,108 @@ function showHelp() {
|
|
|
144
1344
|
console.log(` ${dim(SITE_URL)}`);
|
|
145
1345
|
console.log("");
|
|
146
1346
|
}
|
|
147
|
-
|
|
148
1347
|
function showVersion() {
|
|
149
1348
|
const agentV = getAgentVersion();
|
|
150
1349
|
if (agentV) {
|
|
151
|
-
console.log(
|
|
1350
|
+
console.log(`\u03C3 Soma v${agentV}`);
|
|
152
1351
|
console.log(` CLI v${VERSION}`);
|
|
153
1352
|
} else {
|
|
154
1353
|
console.log(`soma v${VERSION}`);
|
|
155
1354
|
}
|
|
156
1355
|
}
|
|
157
|
-
|
|
158
|
-
// ── Init Soma ────────────────────────────────────────────────────────
|
|
159
|
-
|
|
160
1356
|
async function initSoma() {
|
|
161
1357
|
printSigma();
|
|
162
|
-
console.log(` ${bold("Soma")}
|
|
1358
|
+
console.log(` ${bold("Soma")} \u2014 Install`);
|
|
163
1359
|
console.log("");
|
|
164
|
-
|
|
165
1360
|
try {
|
|
166
|
-
|
|
1361
|
+
execSync2("git --version", { stdio: "ignore" });
|
|
167
1362
|
} catch {
|
|
168
|
-
console.log(` ${red("
|
|
1363
|
+
console.log(` ${red("\u2717")} git not found.`);
|
|
169
1364
|
console.log("");
|
|
170
1365
|
console.log(` Soma needs git to download the runtime.`);
|
|
171
1366
|
console.log(` Install git: ${cyan("https://git-scm.com/downloads")}`);
|
|
172
1367
|
console.log("");
|
|
173
1368
|
return;
|
|
174
1369
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const isValidInstall = existsSync(installDir)
|
|
180
|
-
&& existsSync(join(installDir, ".git"))
|
|
181
|
-
&& (existsSync(join(installDir, "dist", "extensions")) || existsSync(join(installDir, "extensions")));
|
|
182
|
-
|
|
1370
|
+
const installDir = join3(SOMA_HOME, "agent");
|
|
1371
|
+
mkdirSync2(SOMA_HOME, { recursive: true });
|
|
1372
|
+
const isValidInstall = existsSync3(installDir) && existsSync3(join3(installDir, ".git")) && (existsSync3(join3(installDir, "dist", "extensions")) || existsSync3(join3(installDir, "extensions")));
|
|
183
1373
|
let preservedFiles = {};
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
console.log(`
|
|
187
|
-
console.log(` ${dim("Missing:")} ${!existsSync(join(installDir, ".git")) ? "git repo" : "core files"}`);
|
|
1374
|
+
if (existsSync3(installDir) && !isValidInstall) {
|
|
1375
|
+
console.log(` ${yellow("\u26A0")} Incomplete installation detected.`);
|
|
1376
|
+
console.log(` ${dim("Missing:")} ${!existsSync3(join3(installDir, ".git")) ? "git repo" : "core files"}`);
|
|
188
1377
|
console.log("");
|
|
189
|
-
|
|
190
1378
|
const userFileNames = ["auth.json", "models.json"];
|
|
191
1379
|
for (const f of userFileNames) {
|
|
192
|
-
const fp =
|
|
193
|
-
if (
|
|
1380
|
+
const fp = join3(installDir, f);
|
|
1381
|
+
if (existsSync3(fp)) {
|
|
194
1382
|
try {
|
|
195
|
-
preservedFiles[f] =
|
|
196
|
-
console.log(` ${dim("
|
|
197
|
-
} catch {
|
|
1383
|
+
preservedFiles[f] = readFileSync3(fp, "utf-8");
|
|
1384
|
+
console.log(` ${dim("\u2192")} Preserving ${f}`);
|
|
1385
|
+
} catch {
|
|
1386
|
+
}
|
|
198
1387
|
}
|
|
199
1388
|
}
|
|
200
|
-
|
|
201
|
-
|
|
1389
|
+
const extDir = join3(installDir, "extensions");
|
|
1390
|
+
if (existsSync3(extDir)) {
|
|
1391
|
+
try {
|
|
1392
|
+
for (const f of readdirSync(extDir).filter((f2) => !f2.startsWith("soma-") && (f2.endsWith(".ts") || f2.endsWith(".js")))) {
|
|
1393
|
+
const fp = join3(extDir, f);
|
|
1394
|
+
try {
|
|
1395
|
+
preservedFiles[`extensions/${f}`] = readFileSync3(fp, "utf-8");
|
|
1396
|
+
console.log(` ${dim("\u2192")} Preserving extension: ${f}`);
|
|
1397
|
+
} catch {
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
} catch {
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
const hasGit = existsSync3(join3(installDir, ".git"));
|
|
202
1404
|
let repaired = false;
|
|
203
|
-
|
|
204
1405
|
if (hasGit) {
|
|
205
|
-
console.log(` ${yellow("
|
|
1406
|
+
console.log(` ${yellow("\u23F3")} Repairing...`);
|
|
206
1407
|
try {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
console.log(` ${green("
|
|
1408
|
+
execSync2("git fetch origin", { cwd: installDir, stdio: "ignore", timeout: 3e4 });
|
|
1409
|
+
execSync2("git reset --hard origin/main", { cwd: installDir, stdio: "ignore" });
|
|
1410
|
+
console.log(` ${green("\u2713")} Repaired from remote`);
|
|
210
1411
|
repaired = true;
|
|
211
1412
|
} catch {
|
|
212
|
-
console.log(` ${yellow("!")} Repair failed
|
|
1413
|
+
console.log(` ${yellow("!")} Repair failed \u2014 will re-download.`);
|
|
213
1414
|
}
|
|
214
1415
|
}
|
|
215
|
-
|
|
216
1416
|
if (!repaired) {
|
|
217
|
-
const ts = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
218
|
-
const backup =
|
|
1417
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
1418
|
+
const backup = join3(SOMA_HOME, `agent-backup-${ts}`);
|
|
219
1419
|
try {
|
|
220
|
-
|
|
221
|
-
console.log(` ${dim("Old files saved to")} ${dim(backup.replace(
|
|
1420
|
+
execSync2(`mv "${installDir}" "${backup}"`, { stdio: "ignore" });
|
|
1421
|
+
console.log(` ${dim("Old files saved to")} ${dim(backup.replace(homedir3(), "~"))}`);
|
|
222
1422
|
} catch {
|
|
223
|
-
console.log(` ${red("
|
|
1423
|
+
console.log(` ${red("\u2717")} Could not move old installation aside.`);
|
|
224
1424
|
console.log(` ${dim("Try:")} mv ~/.soma/agent ~/.soma/agent-old && soma init`);
|
|
225
1425
|
console.log("");
|
|
226
1426
|
return;
|
|
227
1427
|
}
|
|
228
1428
|
}
|
|
229
1429
|
}
|
|
230
|
-
|
|
231
1430
|
if (isValidInstall) {
|
|
232
|
-
console.log(` ${dim("
|
|
1431
|
+
console.log(` ${dim("\u2192")} Runtime already installed.`);
|
|
233
1432
|
try {
|
|
234
|
-
console.log(` ${yellow("
|
|
235
|
-
|
|
236
|
-
console.log(` ${green("
|
|
1433
|
+
console.log(` ${yellow("\u23F3")} Checking for updates...`);
|
|
1434
|
+
execSync2("git pull --ff-only", { cwd: installDir, stdio: "ignore" });
|
|
1435
|
+
console.log(` ${green("\u2713")} Up to date`);
|
|
237
1436
|
} catch {
|
|
238
|
-
console.log(` ${green("
|
|
1437
|
+
console.log(` ${green("\u2713")} Already current`);
|
|
239
1438
|
}
|
|
240
1439
|
} else {
|
|
241
|
-
console.log(` ${yellow("
|
|
1440
|
+
console.log(` ${yellow("\u23F3")} Downloading Soma runtime...`);
|
|
242
1441
|
try {
|
|
243
|
-
|
|
1442
|
+
execSync2(
|
|
244
1443
|
`git clone --depth 1 https://github.com/meetsoma/soma-beta.git "${installDir}"`,
|
|
245
1444
|
{ stdio: ["ignore", "ignore", "pipe"] }
|
|
246
1445
|
);
|
|
247
|
-
console.log(` ${green("
|
|
1446
|
+
console.log(` ${green("\u2713")} Runtime downloaded`);
|
|
248
1447
|
} catch (err) {
|
|
249
|
-
console.log(` ${red("
|
|
1448
|
+
console.log(` ${red("\u2717")} Download failed.`);
|
|
250
1449
|
console.log(` ${dim(String(err.stderr || err.message))}`);
|
|
251
1450
|
console.log("");
|
|
252
1451
|
console.log(` ${dim("Try manually:")} git clone https://github.com/meetsoma/soma-beta.git ~/.soma/agent`);
|
|
@@ -254,79 +1453,69 @@ async function initSoma() {
|
|
|
254
1453
|
return;
|
|
255
1454
|
}
|
|
256
1455
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
console.log(` ${yellow("⏳")} Installing dependencies... ${dim("(this may take a moment)")}`);
|
|
1456
|
+
const pkgJson = join3(installDir, "package.json");
|
|
1457
|
+
if (existsSync3(pkgJson)) {
|
|
1458
|
+
console.log(` ${yellow("\u23F3")} Installing dependencies... ${dim("(this may take a moment)")}`);
|
|
261
1459
|
try {
|
|
262
|
-
|
|
263
|
-
console.log(` ${green("
|
|
1460
|
+
execSync2("npm install --omit=dev", { cwd: installDir, stdio: ["ignore", "ignore", "inherit"] });
|
|
1461
|
+
console.log(` ${green("\u2713")} Dependencies installed`);
|
|
264
1462
|
} catch {
|
|
265
|
-
console.log(` ${yellow("
|
|
1463
|
+
console.log(` ${yellow("\u26A0")} npm install had issues \u2014 run ${green(`cd ${installDir} && npm install`)} manually.`);
|
|
266
1464
|
}
|
|
267
1465
|
}
|
|
268
|
-
|
|
269
1466
|
if (Object.keys(preservedFiles).length > 0) {
|
|
270
1467
|
for (const [f, content] of Object.entries(preservedFiles)) {
|
|
271
1468
|
try {
|
|
272
|
-
|
|
273
|
-
console.log(` ${green("
|
|
274
|
-
} catch {
|
|
1469
|
+
writeFileSync2(join3(installDir, f), content, { mode: 384 });
|
|
1470
|
+
console.log(` ${green("\u2713")} Restored ${f}`);
|
|
1471
|
+
} catch {
|
|
1472
|
+
}
|
|
275
1473
|
}
|
|
276
1474
|
}
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
const hasCore = existsSync(join(installDir, "dist", "core"));
|
|
280
|
-
|
|
1475
|
+
const hasExts = existsSync3(join3(installDir, "dist", "extensions"));
|
|
1476
|
+
const hasCore = existsSync3(join3(installDir, "dist", "core"));
|
|
281
1477
|
if (!hasExts || !hasCore) {
|
|
282
1478
|
console.log("");
|
|
283
|
-
console.log(` ${red("
|
|
1479
|
+
console.log(` ${red("\u2717")} Installation incomplete \u2014 core files missing.`);
|
|
284
1480
|
console.log(` ${dim("Try:")} rm -rf ~/.soma/agent && soma init`);
|
|
285
1481
|
console.log("");
|
|
286
1482
|
return;
|
|
287
1483
|
}
|
|
288
|
-
|
|
289
|
-
console.log(` ${green("✓")} Extensions and core ready`);
|
|
290
|
-
|
|
1484
|
+
console.log(` ${green("\u2713")} Extensions and core ready`);
|
|
291
1485
|
const config = readConfig();
|
|
292
|
-
config.installedAt = config.installedAt || new Date().toISOString();
|
|
1486
|
+
config.installedAt = config.installedAt || (/* @__PURE__ */ new Date()).toISOString();
|
|
293
1487
|
config.coreVersion = getAgentVersion() || VERSION;
|
|
294
1488
|
config.installPath = installDir;
|
|
295
1489
|
writeConfig(config);
|
|
296
|
-
|
|
297
1490
|
console.log("");
|
|
298
|
-
console.log(` ${green("
|
|
1491
|
+
console.log(` ${green("\u2713")} ${bold("Soma is installed!")}`);
|
|
299
1492
|
console.log("");
|
|
300
1493
|
}
|
|
301
|
-
|
|
302
|
-
// ── Update / Status ──────────────────────────────────────────────────
|
|
303
|
-
|
|
304
1494
|
async function checkAndUpdate() {
|
|
305
1495
|
printSigma();
|
|
306
|
-
console.log(` ${bold("Soma")}
|
|
1496
|
+
console.log(` ${bold("Soma")} \u2014 Status`);
|
|
307
1497
|
console.log("");
|
|
308
|
-
|
|
309
1498
|
const config = readConfig();
|
|
310
|
-
const installPath = config.installPath ||
|
|
311
|
-
|
|
1499
|
+
const installPath = config.installPath || join3(SOMA_HOME, "agent");
|
|
312
1500
|
let currentHash = "";
|
|
313
1501
|
try {
|
|
314
|
-
currentHash =
|
|
315
|
-
cwd: installPath,
|
|
1502
|
+
currentHash = execSync2("git rev-parse --short HEAD", {
|
|
1503
|
+
cwd: installPath,
|
|
1504
|
+
encoding: "utf-8"
|
|
316
1505
|
}).trim();
|
|
317
|
-
console.log(` ${green("
|
|
1506
|
+
console.log(` ${green("\u2713")} Core installed ${dim(`(${currentHash})`)}`);
|
|
318
1507
|
} catch {
|
|
319
|
-
console.log(` ${green("
|
|
1508
|
+
console.log(` ${green("\u2713")} Core installed`);
|
|
320
1509
|
}
|
|
321
|
-
|
|
322
1510
|
let behind = 0;
|
|
323
1511
|
try {
|
|
324
|
-
console.log(` ${yellow("
|
|
325
|
-
|
|
326
|
-
const branch =
|
|
327
|
-
cwd: installPath,
|
|
1512
|
+
console.log(` ${yellow("\u23F3")} Checking for updates...`);
|
|
1513
|
+
execSync2("git fetch origin --quiet", { cwd: installPath, stdio: "ignore", timeout: 15e3 });
|
|
1514
|
+
const branch = execSync2("git rev-parse --abbrev-ref HEAD", {
|
|
1515
|
+
cwd: installPath,
|
|
1516
|
+
encoding: "utf-8"
|
|
328
1517
|
}).trim();
|
|
329
|
-
const behindStr =
|
|
1518
|
+
const behindStr = execSync2(
|
|
330
1519
|
`git rev-list HEAD..origin/${branch} --count`,
|
|
331
1520
|
{ cwd: installPath, encoding: "utf-8" }
|
|
332
1521
|
).trim();
|
|
@@ -336,302 +1525,308 @@ async function checkAndUpdate() {
|
|
|
336
1525
|
console.log("");
|
|
337
1526
|
return;
|
|
338
1527
|
}
|
|
339
|
-
|
|
340
1528
|
if (behind === 0) {
|
|
341
|
-
console.log(` ${green("
|
|
342
|
-
|
|
1529
|
+
console.log(` ${green("\u2713")} Already up to date.`);
|
|
343
1530
|
const agentV = getAgentVersion();
|
|
344
1531
|
const projectV = getProjectVersion();
|
|
345
|
-
if (agentV && projectV && projectV <
|
|
346
|
-
console.log(` ${yellow("
|
|
1532
|
+
if (agentV && projectV && semverCmp(projectV, agentV) < 0) {
|
|
1533
|
+
console.log(` ${yellow("\u26A0")} Project .soma/ is at ${cyan(`v${projectV}`)}, agent is at ${cyan(`v${agentV}`)}.`);
|
|
347
1534
|
console.log(` Run ${green("soma doctor")} to check for updates.`);
|
|
348
1535
|
}
|
|
349
|
-
|
|
350
1536
|
console.log("");
|
|
351
1537
|
console.log(` ${dim("Soma is set up and ready.")} Run ${green("soma")} ${dim("in a project to start a session.")}`);
|
|
352
1538
|
console.log("");
|
|
353
1539
|
return;
|
|
354
1540
|
}
|
|
355
|
-
|
|
356
|
-
console.log(` ${cyan("⬆")} ${bold(`${behind} update${behind !== 1 ? "s" : ""} available.`)}`);
|
|
1541
|
+
console.log(` ${cyan("\u2B06")} ${bold(`${behind} update${behind !== 1 ? "s" : ""} available.`)}`);
|
|
357
1542
|
console.log("");
|
|
358
|
-
|
|
359
1543
|
try {
|
|
360
|
-
const log =
|
|
1544
|
+
const log = execSync2(
|
|
361
1545
|
`git log HEAD..origin/main --oneline --no-decorate -5`,
|
|
362
1546
|
{ cwd: installPath, encoding: "utf-8" }
|
|
363
1547
|
).trim();
|
|
364
1548
|
if (log) {
|
|
365
1549
|
for (const line of log.split("\n")) {
|
|
366
|
-
console.log(` ${dim("
|
|
1550
|
+
console.log(` ${dim("\u2022")} ${line.slice(8)}`);
|
|
367
1551
|
}
|
|
368
1552
|
if (behind > 5) {
|
|
369
1553
|
console.log(` ${dim(`...and ${behind - 5} more`)}`);
|
|
370
1554
|
}
|
|
371
1555
|
console.log("");
|
|
372
1556
|
}
|
|
373
|
-
} catch {
|
|
374
|
-
|
|
375
|
-
const shouldUpdate = await confirmYN(` ${dim("
|
|
1557
|
+
} catch {
|
|
1558
|
+
}
|
|
1559
|
+
const shouldUpdate = await confirmYN(` ${dim("\u2192")} Update now?`);
|
|
376
1560
|
if (!shouldUpdate) {
|
|
377
1561
|
console.log("");
|
|
378
1562
|
console.log(` ${dim("Skipped. Run")} ${green("soma init")} ${dim("anytime to update.")}`);
|
|
379
1563
|
console.log("");
|
|
380
1564
|
return;
|
|
381
1565
|
}
|
|
382
|
-
|
|
383
1566
|
console.log("");
|
|
384
1567
|
try {
|
|
385
|
-
|
|
386
|
-
console.log(` ${green("
|
|
1568
|
+
execSync2("git pull --ff-only", { cwd: installPath, stdio: "ignore" });
|
|
1569
|
+
console.log(` ${green("\u2713")} Updated`);
|
|
387
1570
|
} catch {
|
|
388
|
-
console.log(` ${yellow("!")} Pull failed
|
|
1571
|
+
console.log(` ${yellow("!")} Pull failed \u2014 trying reset...`);
|
|
389
1572
|
try {
|
|
390
|
-
|
|
391
|
-
console.log(` ${green("
|
|
1573
|
+
execSync2("git reset --hard origin/main", { cwd: installPath, stdio: "ignore" });
|
|
1574
|
+
console.log(` ${green("\u2713")} Updated (reset)`);
|
|
392
1575
|
} catch {
|
|
393
|
-
console.log(` ${red("
|
|
1576
|
+
console.log(` ${red("\u2717")} Update failed.`);
|
|
394
1577
|
console.log(` ${dim("Try:")} cd ~/.soma/agent && git pull`);
|
|
395
1578
|
console.log("");
|
|
396
1579
|
return;
|
|
397
1580
|
}
|
|
398
1581
|
}
|
|
399
|
-
|
|
400
1582
|
try {
|
|
401
|
-
const pkgChanged =
|
|
1583
|
+
const pkgChanged = execSync2(
|
|
402
1584
|
`git diff HEAD~${behind} HEAD --name-only -- package.json package-lock.json`,
|
|
403
1585
|
{ cwd: installPath, encoding: "utf-8" }
|
|
404
1586
|
).trim();
|
|
405
1587
|
if (pkgChanged) {
|
|
406
|
-
console.log(` ${yellow("
|
|
407
|
-
|
|
408
|
-
console.log(` ${green("
|
|
1588
|
+
console.log(` ${yellow("\u23F3")} Updating dependencies...`);
|
|
1589
|
+
execSync2("npm install --omit=dev", { cwd: installPath, stdio: ["ignore", "ignore", "inherit"] });
|
|
1590
|
+
console.log(` ${green("\u2713")} Dependencies updated`);
|
|
409
1591
|
}
|
|
410
|
-
} catch {
|
|
411
|
-
|
|
412
|
-
const newHash =
|
|
413
|
-
cwd: installPath,
|
|
1592
|
+
} catch {
|
|
1593
|
+
}
|
|
1594
|
+
const newHash = execSync2("git rev-parse --short HEAD", {
|
|
1595
|
+
cwd: installPath,
|
|
1596
|
+
encoding: "utf-8"
|
|
414
1597
|
}).trim();
|
|
1598
|
+
try {
|
|
1599
|
+
const cfg = readConfig();
|
|
1600
|
+
if (cfg.updateAvailable) {
|
|
1601
|
+
delete cfg.updateAvailable;
|
|
1602
|
+
delete cfg.latestSummary;
|
|
1603
|
+
writeConfig(cfg);
|
|
1604
|
+
}
|
|
1605
|
+
} catch {
|
|
1606
|
+
}
|
|
415
1607
|
console.log("");
|
|
416
|
-
console.log(` ${green("
|
|
1608
|
+
console.log(` ${green("\u2713")} ${bold("Soma is up to date")} ${dim(`(${currentHash} \u2192 ${newHash})`)}`);
|
|
417
1609
|
console.log("");
|
|
418
1610
|
}
|
|
419
|
-
|
|
420
1611
|
function checkForUpdates() {
|
|
421
1612
|
printSigma();
|
|
422
|
-
console.log(` ${bold("Soma")}
|
|
1613
|
+
console.log(` ${bold("Soma")} \u2014 Update Check`);
|
|
423
1614
|
console.log("");
|
|
424
1615
|
const agentV = getAgentVersion();
|
|
425
1616
|
if (agentV) {
|
|
426
1617
|
console.log(` Soma: ${cyan(`v${agentV}`)}`);
|
|
427
1618
|
}
|
|
428
1619
|
console.log(` CLI: ${cyan(`v${VERSION}`)}`);
|
|
429
|
-
|
|
430
1620
|
const config = readConfig();
|
|
431
|
-
|
|
432
1621
|
try {
|
|
433
|
-
const latest =
|
|
1622
|
+
const latest = execSync2("npm view meetsoma version 2>/dev/null", { encoding: "utf-8" }).trim();
|
|
434
1623
|
if (latest && latest !== VERSION && latest > VERSION) {
|
|
435
1624
|
console.log("");
|
|
436
|
-
console.log(` ${yellow("
|
|
1625
|
+
console.log(` ${yellow("\u2B06")} CLI update available: ${green(`v${latest}`)}`);
|
|
437
1626
|
console.log(` Run: ${green("npm install -g meetsoma")}`);
|
|
438
1627
|
} else {
|
|
439
|
-
console.log(` ${green("
|
|
1628
|
+
console.log(` ${green("\u2713")} CLI is up to date`);
|
|
440
1629
|
}
|
|
441
1630
|
} catch {
|
|
442
1631
|
console.log(` ${dim("Could not check npm registry")}`);
|
|
443
1632
|
}
|
|
444
|
-
|
|
445
1633
|
if (isInstalled() && config.installPath) {
|
|
446
1634
|
try {
|
|
447
|
-
|
|
448
|
-
const branch =
|
|
449
|
-
cwd: config.installPath,
|
|
1635
|
+
execSync2("git fetch origin --quiet", { cwd: config.installPath, stdio: "ignore", timeout: 1e4 });
|
|
1636
|
+
const branch = execSync2("git rev-parse --abbrev-ref HEAD", {
|
|
1637
|
+
cwd: config.installPath,
|
|
1638
|
+
encoding: "utf-8"
|
|
450
1639
|
}).trim();
|
|
451
|
-
const behind =
|
|
1640
|
+
const behind = execSync2(
|
|
452
1641
|
`git rev-list HEAD..origin/${branch} --count`,
|
|
453
1642
|
{ cwd: config.installPath, encoding: "utf-8" }
|
|
454
1643
|
).trim();
|
|
455
1644
|
if (behind && parseInt(behind) > 0) {
|
|
456
|
-
console.log(` ${yellow("
|
|
1645
|
+
console.log(` ${yellow("\u2B06")} Core: ${behind} commit${behind !== "1" ? "s" : ""} behind. Run ${green("soma init")} to update.`);
|
|
457
1646
|
} else {
|
|
458
|
-
console.log(` ${green("
|
|
1647
|
+
console.log(` ${green("\u2713")} Core is up to date`);
|
|
459
1648
|
}
|
|
460
1649
|
} catch {
|
|
461
1650
|
console.log(` ${dim("Could not check core updates")}`);
|
|
462
1651
|
}
|
|
463
1652
|
}
|
|
464
|
-
|
|
465
1653
|
console.log("");
|
|
466
1654
|
}
|
|
467
|
-
|
|
468
|
-
// ── Health Check ─────────────────────────────────────────────────────
|
|
469
|
-
|
|
470
1655
|
async function healthCheck() {
|
|
471
1656
|
printSigma();
|
|
472
|
-
console.log(` ${bold("Soma")}
|
|
1657
|
+
console.log(` ${bold("Soma")} \u2014 Health Check`);
|
|
473
1658
|
console.log("");
|
|
474
|
-
|
|
475
1659
|
let issues = 0;
|
|
476
1660
|
let warnings = 0;
|
|
477
1661
|
const check = (ok, pass, fail_msg) => {
|
|
478
|
-
if (ok) {
|
|
479
|
-
|
|
1662
|
+
if (ok) {
|
|
1663
|
+
console.log(` ${green("\u2713")} ${pass}`);
|
|
1664
|
+
} else {
|
|
1665
|
+
console.log(` ${red("\u2717")} ${fail_msg}`);
|
|
1666
|
+
issues++;
|
|
1667
|
+
}
|
|
480
1668
|
};
|
|
481
1669
|
const warn = (ok, pass, fail_msg) => {
|
|
482
|
-
if (ok) {
|
|
483
|
-
|
|
1670
|
+
if (ok) {
|
|
1671
|
+
console.log(` ${green("\u2713")} ${pass}`);
|
|
1672
|
+
} else {
|
|
1673
|
+
console.log(` ${yellow("\u26A0")} ${fail_msg}`);
|
|
1674
|
+
warnings++;
|
|
1675
|
+
}
|
|
484
1676
|
};
|
|
485
|
-
|
|
486
1677
|
const nodeVersion = process.versions.node;
|
|
487
1678
|
const [major, minor] = nodeVersion.split(".").map(Number);
|
|
488
|
-
check(
|
|
1679
|
+
check(
|
|
1680
|
+
major > 20 || major === 20 && minor >= 6,
|
|
489
1681
|
`Node.js ${nodeVersion}`,
|
|
490
|
-
`Node.js ${nodeVersion}
|
|
1682
|
+
`Node.js ${nodeVersion} \u2014 requires \u226520.6.0`
|
|
491
1683
|
);
|
|
492
|
-
|
|
493
|
-
check(existsSync(SOMA_HOME), "~/.soma/ exists", "~/.soma/ not found — run: soma init");
|
|
494
|
-
|
|
1684
|
+
check(existsSync3(SOMA_HOME), "~/.soma/ exists", "~/.soma/ not found \u2014 run: soma init");
|
|
495
1685
|
const installed = isInstalled();
|
|
496
|
-
check(installed, "Core installed", "Core not installed
|
|
497
|
-
|
|
1686
|
+
check(installed, "Core installed", "Core not installed \u2014 run: soma init");
|
|
498
1687
|
if (installed) {
|
|
499
|
-
const extDir =
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
const exts = readdirSync(extDir).filter(f => f.endsWith(".js") || f.endsWith(".ts"));
|
|
504
|
-
check(exts.length >= 6, `${exts.length} extensions`, `Only ${exts.length} extensions (expected ≥6)`);
|
|
1688
|
+
const extDir = existsSync3(join3(CORE_DIR, "dist", "extensions")) ? join3(CORE_DIR, "dist", "extensions") : join3(CORE_DIR, "extensions");
|
|
1689
|
+
if (existsSync3(extDir)) {
|
|
1690
|
+
const exts = readdirSync(extDir).filter((f) => f.endsWith(".js") || f.endsWith(".ts"));
|
|
1691
|
+
check(exts.length >= 6, `${exts.length} extensions`, `Only ${exts.length} extensions (expected \u22656)`);
|
|
505
1692
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
: join(CORE_DIR, "core");
|
|
510
|
-
check(existsSync(coreDir), "Core modules present", "Core modules missing");
|
|
511
|
-
|
|
512
|
-
if (existsSync(join(CORE_DIR, ".git"))) {
|
|
1693
|
+
const coreDir = existsSync3(join3(CORE_DIR, "dist", "core")) ? join3(CORE_DIR, "dist", "core") : join3(CORE_DIR, "core");
|
|
1694
|
+
check(existsSync3(coreDir), "Core modules present", "Core modules missing");
|
|
1695
|
+
if (existsSync3(join3(CORE_DIR, ".git"))) {
|
|
513
1696
|
try {
|
|
514
|
-
|
|
1697
|
+
execSync2("git status --porcelain", { cwd: CORE_DIR, stdio: "ignore" });
|
|
515
1698
|
check(true, "Git repo healthy", "");
|
|
516
1699
|
} catch {
|
|
517
1700
|
warn(false, "", "Core git repo has issues");
|
|
518
1701
|
}
|
|
519
1702
|
} else {
|
|
520
1703
|
try {
|
|
521
|
-
const realCore =
|
|
1704
|
+
const realCore = readlinkSync2(join3(CORE_DIR, "core"));
|
|
522
1705
|
if (realCore) {
|
|
523
1706
|
check(true, "Dev mode (symlinked)", "");
|
|
524
1707
|
} else {
|
|
525
|
-
warn(false, "", "Core git repo missing
|
|
1708
|
+
warn(false, "", "Core git repo missing \u2014 run soma init");
|
|
526
1709
|
}
|
|
527
1710
|
} catch {
|
|
528
|
-
warn(false, "", "Core git repo missing
|
|
1711
|
+
warn(false, "", "Core git repo missing \u2014 run soma init");
|
|
529
1712
|
}
|
|
530
1713
|
}
|
|
531
1714
|
}
|
|
532
|
-
|
|
1715
|
+
if (installed) {
|
|
1716
|
+
try {
|
|
1717
|
+
const pkgPath = join3(CORE_DIR, "package.json");
|
|
1718
|
+
if (existsSync3(pkgPath)) {
|
|
1719
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
|
|
1720
|
+
const declaredPi = (pkg.dependencies || {})["@mariozechner/pi-coding-agent"];
|
|
1721
|
+
const piPkgPath = join3(CORE_DIR, "node_modules", "@mariozechner", "pi-coding-agent", "package.json");
|
|
1722
|
+
if (existsSync3(piPkgPath)) {
|
|
1723
|
+
const installedPi = JSON.parse(readFileSync3(piPkgPath, "utf-8")).version;
|
|
1724
|
+
const declaredClean = (declaredPi || "").replace(/^[\^~]/, "");
|
|
1725
|
+
if (declaredClean && installedPi && declaredClean !== installedPi) {
|
|
1726
|
+
console.log(` ${yellow("\u26A0")} Pi runtime drift: declared ${cyan(declaredClean)}, installed ${cyan(installedPi)}`);
|
|
1727
|
+
console.log(` ${dim("Fix:")} ${green("soma update")}`);
|
|
1728
|
+
warnings++;
|
|
1729
|
+
} else if (installedPi) {
|
|
1730
|
+
console.log(` ${green("\u2713")} Pi runtime ${installedPi}`);
|
|
1731
|
+
}
|
|
1732
|
+
} else {
|
|
1733
|
+
console.log(` ${yellow("\u26A0")} Pi not installed \u2014 run ${green("soma update")}`);
|
|
1734
|
+
warnings++;
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
} catch {
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
533
1740
|
const hasAuth = hasAnyAuth();
|
|
534
1741
|
if (hasAuth) {
|
|
535
|
-
console.log(` ${green("
|
|
1742
|
+
console.log(` ${green("\u2713")} API key configured`);
|
|
536
1743
|
} else {
|
|
537
1744
|
const unloadedKey = detectKeyInShellConfig();
|
|
538
1745
|
if (unloadedKey) {
|
|
539
|
-
console.log(` ${yellow("
|
|
1746
|
+
console.log(` ${yellow("\u26A0")} ${unloadedKey} found in ${dim(getShellConfigPath())} but not loaded \u2014 restart your terminal`);
|
|
540
1747
|
} else {
|
|
541
|
-
console.log(` ${yellow("
|
|
1748
|
+
console.log(` ${yellow("\u26A0")} No API key \u2014 run ${green("soma")} to set one up`);
|
|
542
1749
|
}
|
|
543
1750
|
}
|
|
544
|
-
|
|
545
1751
|
try {
|
|
546
|
-
const gitV =
|
|
1752
|
+
const gitV = execSync2("git --version", { encoding: "utf-8" }).trim();
|
|
547
1753
|
check(true, gitV, "");
|
|
548
1754
|
} catch {
|
|
549
1755
|
check(false, "", "git not found");
|
|
550
1756
|
}
|
|
551
|
-
|
|
552
1757
|
console.log("");
|
|
553
1758
|
if (issues === 0 && warnings === 0) {
|
|
554
|
-
console.log(` ${green("
|
|
1759
|
+
console.log(` ${green("\u2713 All checks passed")}`);
|
|
555
1760
|
} else if (issues === 0) {
|
|
556
|
-
console.log(` ${green("
|
|
1761
|
+
console.log(` ${green("\u2713 All checks passed")} ${dim(`(${warnings} warning${warnings > 1 ? "s" : ""})`)}`);
|
|
557
1762
|
} else {
|
|
558
1763
|
console.log(` ${yellow(`${issues} issue${issues > 1 ? "s" : ""} found`)}${warnings > 0 ? dim(` + ${warnings} warning${warnings > 1 ? "s" : ""}`) : ""}`);
|
|
559
|
-
console.log(` ${
|
|
1764
|
+
console.log(` ${soma.say("suggest", { suggestion: issues > 2 ? "start with soma init" : "check the items above" })}`);
|
|
560
1765
|
}
|
|
561
1766
|
console.log("");
|
|
562
1767
|
}
|
|
563
|
-
|
|
564
|
-
// ── Project Doctor ───────────────────────────────────────────────────
|
|
565
|
-
// (large function — kept inline to avoid breaking the complex doctor logic)
|
|
566
|
-
|
|
567
1768
|
async function projectDoctor() {
|
|
568
1769
|
const doctorArgs = args.slice(1);
|
|
569
1770
|
const wantsScan = doctorArgs.includes("--scan");
|
|
570
1771
|
const wantsAll = doctorArgs.includes("--all");
|
|
571
|
-
|
|
572
1772
|
if ((wantsScan || wantsAll) && isInstalled()) {
|
|
573
1773
|
await delegateToCore();
|
|
574
1774
|
return;
|
|
575
1775
|
}
|
|
576
|
-
|
|
577
1776
|
printSigma();
|
|
578
1777
|
const agentV = getAgentVersion();
|
|
579
1778
|
const projectV = getProjectVersion();
|
|
580
1779
|
const installed = isInstalled();
|
|
581
|
-
|
|
582
|
-
console.log(` ${bold("Soma")} — Doctor`);
|
|
1780
|
+
console.log(` ${bold("Soma")} \u2014 Doctor`);
|
|
583
1781
|
console.log("");
|
|
584
|
-
|
|
585
1782
|
if (!installed) {
|
|
586
|
-
console.log(` ${red("
|
|
1783
|
+
console.log(` ${red("\u2717")} Soma not installed. Run ${green("soma init")} first.`);
|
|
587
1784
|
console.log("");
|
|
588
1785
|
return;
|
|
589
1786
|
}
|
|
590
|
-
|
|
591
1787
|
console.log(` Agent: ${cyan(`v${agentV || "unknown"}`)}`);
|
|
592
1788
|
if (projectV) {
|
|
593
1789
|
console.log(` Project: ${cyan(`v${projectV}`)}`);
|
|
594
1790
|
}
|
|
595
1791
|
console.log(` CLI: ${dim(`v${VERSION}`)}`);
|
|
596
1792
|
console.log("");
|
|
597
|
-
|
|
598
|
-
const hasSomaDir = existsSync(join(process.cwd(), ".soma"));
|
|
599
|
-
|
|
1793
|
+
const hasSomaDir = existsSync3(join3(process.cwd(), ".soma"));
|
|
600
1794
|
if (!hasSomaDir) {
|
|
601
|
-
console.log(` ${yellow("
|
|
1795
|
+
console.log(` ${yellow("\u26A0")} No .soma/ in current directory.`);
|
|
602
1796
|
console.log(` Run ${green("soma init")} to set up this project, or ${green("soma doctor --scan")} to find projects.`);
|
|
603
1797
|
console.log("");
|
|
604
1798
|
return;
|
|
605
1799
|
}
|
|
606
|
-
|
|
607
1800
|
if (!projectV) {
|
|
608
|
-
console.log(` ${yellow("
|
|
1801
|
+
console.log(` ${yellow("\u26A0")} Project .soma/ has no version (pre-versioning).`);
|
|
609
1802
|
console.log(` This project was likely created before v0.6.3.`);
|
|
610
1803
|
console.log(` Run ${green("soma init")} to bring it up to date.`);
|
|
611
1804
|
console.log("");
|
|
612
1805
|
return;
|
|
613
1806
|
}
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
console.log(` ${green("✓")} Project is up to date.`);
|
|
1807
|
+
if (agentV && semverCmp(projectV, agentV) === 0) {
|
|
1808
|
+
console.log(` ${green("\u2713")} Project is up to date.`);
|
|
617
1809
|
console.log("");
|
|
618
1810
|
await healthCheck();
|
|
619
1811
|
return;
|
|
620
1812
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
console.log(` ${yellow("⚠")} Project .soma/ is at ${cyan(`v${projectV}`)} , agent is at ${cyan(`v${agentV}`)} .`);
|
|
1813
|
+
if (agentV && semverCmp(projectV, agentV) < 0) {
|
|
1814
|
+
console.log(` ${yellow("\u26A0")} Project .soma/ is at ${cyan(`v${projectV}`)} , agent is at ${cyan(`v${agentV}`)} .`);
|
|
624
1815
|
console.log("");
|
|
625
|
-
|
|
626
1816
|
let fixes = 0;
|
|
627
|
-
const somaDir =
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
if (existsSync(settingsPath)) {
|
|
1817
|
+
const somaDir = join3(process.cwd(), ".soma");
|
|
1818
|
+
const settingsPath = join3(somaDir, "settings.json");
|
|
1819
|
+
if (existsSync3(settingsPath)) {
|
|
631
1820
|
try {
|
|
632
|
-
const current = JSON.parse(
|
|
1821
|
+
const current = JSON.parse(readFileSync3(settingsPath, "utf-8"));
|
|
633
1822
|
let changed = false;
|
|
634
|
-
const add = (k, v) => {
|
|
1823
|
+
const add = (k, v) => {
|
|
1824
|
+
if (!(k in current)) {
|
|
1825
|
+
current[k] = v;
|
|
1826
|
+
changed = true;
|
|
1827
|
+
fixes++;
|
|
1828
|
+
}
|
|
1829
|
+
};
|
|
635
1830
|
add("doctor", { autoUpdate: true, declinedVersion: null });
|
|
636
1831
|
add("breathe", { auto: false, triggerAt: 50, rotateAt: 70, graceSeconds: 30 });
|
|
637
1832
|
add("context", { notifyAt: 50, warnAt: 70, urgentAt: 80, autoExhaleAt: 85 });
|
|
@@ -639,106 +1834,98 @@ async function projectDoctor() {
|
|
|
639
1834
|
add("scratch", { autoInject: false });
|
|
640
1835
|
add("guard", { coreFiles: "warn", bashCommands: "warn", gitIdentity: null });
|
|
641
1836
|
add("checkpoints", { enabled: true, intervalMinutes: 5, squashOnPush: true });
|
|
642
|
-
add("persona", { name: null, emoji: "
|
|
1837
|
+
add("persona", { name: null, emoji: "\u03C3" });
|
|
643
1838
|
add("inherit", { identity: true, protocols: true, muscles: true, tools: true });
|
|
644
|
-
if (changed)
|
|
645
|
-
} catch {
|
|
1839
|
+
if (changed) writeFileSync2(settingsPath, JSON.stringify(current, null, " ") + "\n");
|
|
1840
|
+
} catch {
|
|
1841
|
+
}
|
|
646
1842
|
}
|
|
647
|
-
|
|
648
|
-
const bodyDir = join(somaDir, "body");
|
|
1843
|
+
const bodyDir = join3(somaDir, "body");
|
|
649
1844
|
let agentRoot = CORE_DIR;
|
|
650
1845
|
try {
|
|
651
|
-
const realCore =
|
|
1846
|
+
const realCore = readlinkSync2(join3(CORE_DIR, "core"));
|
|
652
1847
|
if (realCore) {
|
|
653
|
-
const devRoot =
|
|
654
|
-
if (
|
|
1848
|
+
const devRoot = dirname3(realCore);
|
|
1849
|
+
if (existsSync3(join3(devRoot, "templates", "default")) || existsSync3(join3(devRoot, "body", "_public"))) agentRoot = devRoot;
|
|
655
1850
|
}
|
|
656
|
-
} catch {
|
|
657
|
-
if (!existsSync(join(agentRoot, "body", "_public"))) {
|
|
658
|
-
const parent = dirname(agentRoot);
|
|
659
|
-
if (existsSync(join(parent, "body", "_public"))) agentRoot = parent;
|
|
1851
|
+
} catch {
|
|
660
1852
|
}
|
|
661
|
-
const bundledBody =
|
|
662
|
-
if (
|
|
1853
|
+
const bundledBody = existsSync3(join3(agentRoot, "templates", "default")) ? join3(agentRoot, "templates", "default") : existsSync3(join3(agentRoot, "body", "_public")) ? join3(agentRoot, "body", "_public") : null;
|
|
1854
|
+
if (bundledBody && existsSync3(bundledBody)) {
|
|
663
1855
|
try {
|
|
664
|
-
if (!
|
|
665
|
-
for (const f of readdirSync(bundledBody).filter(
|
|
666
|
-
const dest =
|
|
667
|
-
if (!
|
|
1856
|
+
if (!existsSync3(bodyDir)) mkdirSync2(bodyDir, { recursive: true });
|
|
1857
|
+
for (const f of readdirSync(bundledBody).filter((f2) => f2.endsWith(".md") && !f2.startsWith("_"))) {
|
|
1858
|
+
const dest = join3(bodyDir, f);
|
|
1859
|
+
if (!existsSync3(dest)) {
|
|
1860
|
+
writeFileSync2(dest, readFileSync3(join3(bundledBody, f), "utf-8"));
|
|
1861
|
+
fixes++;
|
|
1862
|
+
}
|
|
668
1863
|
}
|
|
669
|
-
} catch {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
const protoDir =
|
|
673
|
-
const bundledProtos =
|
|
674
|
-
? join(CORE_DIR, "dist", "content", "protocols")
|
|
675
|
-
: existsSync(join(CORE_DIR, "content", "protocols"))
|
|
676
|
-
? join(CORE_DIR, "content", "protocols") : null;
|
|
1864
|
+
} catch {
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
const protoDir = join3(somaDir, "amps", "protocols");
|
|
1868
|
+
const bundledProtos = existsSync3(join3(CORE_DIR, "dist", "content", "protocols")) ? join3(CORE_DIR, "dist", "content", "protocols") : existsSync3(join3(CORE_DIR, "content", "protocols")) ? join3(CORE_DIR, "content", "protocols") : null;
|
|
677
1869
|
if (bundledProtos) {
|
|
678
|
-
if (!
|
|
679
|
-
for (const f of readdirSync(bundledProtos).filter(
|
|
680
|
-
const dest =
|
|
681
|
-
if (!
|
|
1870
|
+
if (!existsSync3(protoDir)) mkdirSync2(protoDir, { recursive: true });
|
|
1871
|
+
for (const f of readdirSync(bundledProtos).filter((f2) => f2.endsWith(".md") && f2 !== "_template.md" && f2 !== "README.md")) {
|
|
1872
|
+
const dest = join3(protoDir, f);
|
|
1873
|
+
if (!existsSync3(dest)) {
|
|
1874
|
+
writeFileSync2(dest, readFileSync3(join3(bundledProtos, f), "utf-8"));
|
|
1875
|
+
fixes++;
|
|
1876
|
+
}
|
|
682
1877
|
}
|
|
683
1878
|
}
|
|
684
|
-
|
|
685
|
-
const
|
|
686
|
-
const bundledScripts = existsSync(join(agentRoot, "dist", "content", "scripts"))
|
|
687
|
-
? join(agentRoot, "dist", "content", "scripts")
|
|
688
|
-
: existsSync(join(agentRoot, "content", "scripts"))
|
|
689
|
-
? join(agentRoot, "content", "scripts")
|
|
690
|
-
: existsSync(join(agentRoot, "scripts"))
|
|
691
|
-
? join(agentRoot, "scripts") : null;
|
|
1879
|
+
const scriptsDir = join3(somaDir, "amps", "scripts");
|
|
1880
|
+
const bundledScripts = existsSync3(join3(agentRoot, "dist", "content", "scripts")) ? join3(agentRoot, "dist", "content", "scripts") : existsSync3(join3(agentRoot, "content", "scripts")) ? join3(agentRoot, "content", "scripts") : existsSync3(join3(agentRoot, "scripts")) ? join3(agentRoot, "scripts") : null;
|
|
692
1881
|
if (bundledScripts) {
|
|
693
|
-
if (!
|
|
694
|
-
for (const f of readdirSync(bundledScripts).filter(
|
|
695
|
-
const dest =
|
|
696
|
-
if (!
|
|
697
|
-
|
|
1882
|
+
if (!existsSync3(scriptsDir)) mkdirSync2(scriptsDir, { recursive: true });
|
|
1883
|
+
for (const f of readdirSync(bundledScripts).filter((f2) => f2.endsWith(".sh"))) {
|
|
1884
|
+
const dest = join3(scriptsDir, f);
|
|
1885
|
+
if (!existsSync3(dest)) {
|
|
1886
|
+
writeFileSync2(dest, readFileSync3(join3(bundledScripts, f), "utf-8"), { mode: 493 });
|
|
698
1887
|
fixes++;
|
|
699
1888
|
}
|
|
700
1889
|
}
|
|
701
1890
|
}
|
|
702
|
-
|
|
703
1891
|
if (fixes > 0) {
|
|
704
1892
|
try {
|
|
705
|
-
const s = JSON.parse(
|
|
1893
|
+
const s = JSON.parse(readFileSync3(settingsPath, "utf-8"));
|
|
706
1894
|
s.version = agentV;
|
|
707
|
-
|
|
708
|
-
} catch {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
const
|
|
1895
|
+
writeFileSync2(settingsPath, JSON.stringify(s, null, " ") + "\n");
|
|
1896
|
+
} catch {
|
|
1897
|
+
}
|
|
1898
|
+
console.log(` ${green("\u2713")} Applied ${fixes} automatic fixes`);
|
|
1899
|
+
const bc = existsSync3(join3(somaDir, "body")) ? readdirSync(join3(somaDir, "body")).filter((f) => f.endsWith(".md")).length : 0;
|
|
1900
|
+
const pc = existsSync3(protoDir) ? readdirSync(protoDir).filter((f) => f.endsWith(".md")).length : 0;
|
|
712
1901
|
console.log(` ${bc} body files, ${pc} protocols, settings updated`);
|
|
713
1902
|
console.log(` Version bumped to ${cyan(`v${agentV}`)}`);
|
|
714
|
-
|
|
715
1903
|
let staleUpdated = 0;
|
|
716
1904
|
let staleSkipped = [];
|
|
717
|
-
if (bundledProtos &&
|
|
718
|
-
for (const f of readdirSync(protoDir).filter(
|
|
719
|
-
const bundledFile =
|
|
720
|
-
if (!
|
|
721
|
-
const projRaw =
|
|
722
|
-
const bundledRaw =
|
|
723
|
-
const strip = s => s.replace(/^(heat|loads|runs|last-run|heat-default):.*\n?/gm, "").trim();
|
|
1905
|
+
if (bundledProtos && existsSync3(protoDir)) {
|
|
1906
|
+
for (const f of readdirSync(protoDir).filter((f2) => f2.endsWith(".md") && f2 !== "_template.md" && f2 !== "README.md")) {
|
|
1907
|
+
const bundledFile = join3(bundledProtos, f);
|
|
1908
|
+
if (!existsSync3(bundledFile)) continue;
|
|
1909
|
+
const projRaw = readFileSync3(join3(protoDir, f), "utf-8");
|
|
1910
|
+
const bundledRaw = readFileSync3(bundledFile, "utf-8");
|
|
1911
|
+
const strip = (s) => s.replace(/^(heat|loads|runs|last-run|heat-default):.*\n?/gm, "").trim();
|
|
724
1912
|
if (strip(projRaw) === strip(bundledRaw)) continue;
|
|
725
1913
|
const heatLine = projRaw.match(/^heat:.*$/m);
|
|
726
1914
|
const loadsLine = projRaw.match(/^loads:.*$/m);
|
|
727
1915
|
let updated = bundledRaw;
|
|
728
1916
|
if (heatLine) updated = updated.replace(/^heat:.*$/m, heatLine[0]);
|
|
729
1917
|
if (loadsLine) updated = updated.replace(/^loads:.*$/m, loadsLine[0]);
|
|
730
|
-
|
|
1918
|
+
writeFileSync2(join3(protoDir, f), updated);
|
|
731
1919
|
staleUpdated++;
|
|
732
1920
|
}
|
|
733
1921
|
}
|
|
734
|
-
|
|
735
1922
|
console.log("");
|
|
736
1923
|
if (staleUpdated > 0) {
|
|
737
|
-
console.log(` ${green("
|
|
1924
|
+
console.log(` ${green("\u2713")} ${staleUpdated} protocols updated to latest version`);
|
|
738
1925
|
console.log(` ${dim("Heat and load counts preserved. Content updated.")}`);
|
|
739
1926
|
}
|
|
740
1927
|
if (staleSkipped.length > 0) {
|
|
741
|
-
console.log(` ${yellow("
|
|
1928
|
+
console.log(` ${yellow("\u26A0")} ${staleSkipped.length} protocols skipped (may be customized)`);
|
|
742
1929
|
}
|
|
743
1930
|
console.log("");
|
|
744
1931
|
const totalRemaining = staleSkipped.length;
|
|
@@ -747,88 +1934,82 @@ async function projectDoctor() {
|
|
|
747
1934
|
console.log(` ${dim("Remaining: " + totalRemaining + " items need review.")}`);
|
|
748
1935
|
console.log(` ${dim("For full migration:")} ${green("soma")} ${dim("then")} ${green("/soma doctor")}`);
|
|
749
1936
|
} else {
|
|
750
|
-
console.log(` ${green("
|
|
751
|
-
console.log(` ${dim("No TUI session needed
|
|
1937
|
+
console.log(` ${green("\u2713")} Full migration complete from CLI.`);
|
|
1938
|
+
console.log(` ${dim("No TUI session needed \u2014 all updates applied.")}`);
|
|
752
1939
|
}
|
|
753
|
-
|
|
754
|
-
// Write _doctor-pending.md
|
|
755
1940
|
try {
|
|
756
|
-
const pendingPath =
|
|
1941
|
+
const pendingPath = join3(somaDir, "body", "_doctor-pending.md");
|
|
757
1942
|
if (staleSkipped.length === 0) {
|
|
758
1943
|
const done = [
|
|
759
|
-
"---",
|
|
760
|
-
|
|
761
|
-
"
|
|
762
|
-
"
|
|
763
|
-
`
|
|
764
|
-
|
|
765
|
-
"
|
|
1944
|
+
"---",
|
|
1945
|
+
"type: template",
|
|
1946
|
+
"name: doctor-pending",
|
|
1947
|
+
"status: complete",
|
|
1948
|
+
`created: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`,
|
|
1949
|
+
"description: CLI doctor completed full migration",
|
|
1950
|
+
"---",
|
|
1951
|
+
"",
|
|
1952
|
+
"# Doctor Update \u2014 Complete",
|
|
1953
|
+
"",
|
|
1954
|
+
`Migrated from v${projectV} to v${agentV} on ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.`,
|
|
1955
|
+
`Applied: ${fixes} file fixes + ${staleUpdated} protocol updates.`,
|
|
1956
|
+
"",
|
|
1957
|
+
"Run `/soma doctor` to verify, then delete this file."
|
|
766
1958
|
];
|
|
767
|
-
|
|
1959
|
+
writeFileSync2(pendingPath, done.join("\n"));
|
|
768
1960
|
}
|
|
769
|
-
} catch {
|
|
1961
|
+
} catch {
|
|
1962
|
+
}
|
|
770
1963
|
} else {
|
|
771
|
-
console.log(` ${green("
|
|
772
|
-
console.log(` ${dim("No file changes needed
|
|
1964
|
+
console.log(` ${green("\u2713")} Version bumped to ${cyan(`v${agentV}`)}`);
|
|
1965
|
+
console.log(` ${dim("No file changes needed \u2014 project structure is current.")}`);
|
|
773
1966
|
}
|
|
774
1967
|
} else {
|
|
775
|
-
console.log(` ${green("
|
|
1968
|
+
console.log(` ${green("\u2713")} Project version: ${cyan(`v${projectV}`)}`);
|
|
776
1969
|
}
|
|
777
|
-
|
|
778
1970
|
console.log("");
|
|
779
1971
|
await healthCheck();
|
|
780
1972
|
}
|
|
781
|
-
|
|
782
|
-
// ── Delegation ───────────────────────────────────────────────────────
|
|
783
|
-
|
|
784
1973
|
async function delegateToCore() {
|
|
785
|
-
const piPkg =
|
|
786
|
-
if (!
|
|
787
|
-
console.log(` ${red("
|
|
1974
|
+
const piPkg = join3(CORE_DIR, "node_modules", "@mariozechner", "pi-coding-agent");
|
|
1975
|
+
if (!existsSync3(piPkg)) {
|
|
1976
|
+
console.log(` ${red("\u2717")} Runtime dependencies missing.`);
|
|
788
1977
|
console.log(` ${dim("Run")} ${green("soma init")} ${dim("to repair the installation.")}`);
|
|
789
1978
|
console.log("");
|
|
790
1979
|
return;
|
|
791
1980
|
}
|
|
792
|
-
const cliEntry =
|
|
793
|
-
|
|
794
|
-
: null;
|
|
795
|
-
const mainEntry = existsSync(join(CORE_DIR, "dist", "main.js"))
|
|
796
|
-
? join(CORE_DIR, "dist", "main.js")
|
|
797
|
-
: null;
|
|
1981
|
+
const cliEntry = existsSync3(join3(CORE_DIR, "dist", "cli.js")) ? join3(CORE_DIR, "dist", "cli.js") : null;
|
|
1982
|
+
const mainEntry = existsSync3(join3(CORE_DIR, "dist", "main.js")) ? join3(CORE_DIR, "dist", "main.js") : null;
|
|
798
1983
|
if (!cliEntry && !mainEntry) {
|
|
799
|
-
console.log(` ${red("
|
|
1984
|
+
console.log(` ${red("\u2717")} Runtime entry point missing.`);
|
|
800
1985
|
console.log(` ${dim("Run")} ${green("soma init")} ${dim("to repair the installation.")}`);
|
|
801
1986
|
console.log("");
|
|
802
1987
|
return;
|
|
803
1988
|
}
|
|
804
|
-
|
|
805
1989
|
const passArgs = process.argv.slice(2);
|
|
806
|
-
|
|
807
1990
|
const cliLocations = [
|
|
808
|
-
{ path:
|
|
809
|
-
{ path:
|
|
1991
|
+
{ path: join3(CORE_DIR, "dist", "cli.js"), type: "node" },
|
|
1992
|
+
{ path: join3(CORE_DIR, "node_modules", ".bin", "pi"), type: "bin" }
|
|
810
1993
|
];
|
|
811
|
-
|
|
812
1994
|
const userExtArgs = [];
|
|
813
|
-
const projectExtDir =
|
|
814
|
-
if (
|
|
1995
|
+
const projectExtDir = join3(process.cwd(), ".soma", "extensions");
|
|
1996
|
+
if (existsSync3(projectExtDir)) {
|
|
815
1997
|
try {
|
|
816
|
-
const userExts = readdirSync(projectExtDir).filter(f => f.endsWith(".ts") || f.endsWith(".js"));
|
|
1998
|
+
const userExts = readdirSync(projectExtDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js"));
|
|
817
1999
|
for (const ext of userExts) {
|
|
818
|
-
userExtArgs.push("-e",
|
|
2000
|
+
userExtArgs.push("-e", join3(projectExtDir, ext));
|
|
819
2001
|
}
|
|
820
|
-
} catch {
|
|
2002
|
+
} catch {
|
|
2003
|
+
}
|
|
821
2004
|
}
|
|
822
|
-
|
|
823
2005
|
const env = {
|
|
824
2006
|
...process.env,
|
|
825
2007
|
PI_CODING_AGENT_DIR: CORE_DIR,
|
|
826
2008
|
SOMA_CODING_AGENT_DIR: CORE_DIR,
|
|
827
|
-
PI_PACKAGE_DIR: CORE_DIR
|
|
2009
|
+
PI_PACKAGE_DIR: CORE_DIR
|
|
828
2010
|
};
|
|
829
|
-
|
|
830
2011
|
for (const cli of cliLocations) {
|
|
831
|
-
if (
|
|
2012
|
+
if (existsSync3(cli.path)) {
|
|
832
2013
|
try {
|
|
833
2014
|
const allArgs = [...userExtArgs, ...passArgs];
|
|
834
2015
|
if (cli.type === "node") {
|
|
@@ -841,7 +2022,7 @@ async function delegateToCore() {
|
|
|
841
2022
|
if (err.status) process.exit(err.status);
|
|
842
2023
|
if (err.message && err.message.includes("MODULE_NOT_FOUND")) {
|
|
843
2024
|
console.log("");
|
|
844
|
-
console.log(` ${red("
|
|
2025
|
+
console.log(` ${red("\u2717")} Soma failed to start \u2014 missing dependencies.`);
|
|
845
2026
|
console.log(` ${dim("Run")} ${green("soma init")} ${dim("to repair the installation.")}`);
|
|
846
2027
|
console.log("");
|
|
847
2028
|
}
|
|
@@ -849,21 +2030,25 @@ async function delegateToCore() {
|
|
|
849
2030
|
}
|
|
850
2031
|
}
|
|
851
2032
|
}
|
|
852
|
-
|
|
853
|
-
console.log(` ${
|
|
854
|
-
console.log(` ${dim("Expected:")} ${dim(cliLocations.map(c => c.path).join(" or "))}`);
|
|
2033
|
+
console.log(` ${yellow("\u26A0")} Core is installed but the CLI entry point is missing.`);
|
|
2034
|
+
console.log(` ${dim("Expected:")} ${dim(cliLocations.map((c) => c.path).join(" or "))}`);
|
|
855
2035
|
console.log(` Run ${green("soma init")} to repair the installation.`);
|
|
856
2036
|
console.log("");
|
|
857
2037
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
const
|
|
862
|
-
const
|
|
863
|
-
|
|
864
|
-
|
|
2038
|
+
var args = process.argv.slice(2);
|
|
2039
|
+
var cmd = args[0];
|
|
2040
|
+
try {
|
|
2041
|
+
const config = readConfig();
|
|
2042
|
+
const currentV = getAgentVersion();
|
|
2043
|
+
if (currentV && config.coreVersion !== currentV) {
|
|
2044
|
+
config.coreVersion = currentV;
|
|
2045
|
+
writeConfig(config);
|
|
2046
|
+
}
|
|
2047
|
+
} catch {
|
|
2048
|
+
}
|
|
2049
|
+
if (cmd === "--version" || cmd === "-v" || cmd === "-V" || cmd === "version") {
|
|
865
2050
|
showVersion();
|
|
866
|
-
} else if (cmd === "--help" || cmd === "-h") {
|
|
2051
|
+
} else if (cmd === "--help" || cmd === "-h" || cmd === "help") {
|
|
867
2052
|
if (isInstalled()) {
|
|
868
2053
|
await delegateToCore();
|
|
869
2054
|
} else {
|
|
@@ -872,24 +2057,34 @@ if (cmd === "--version" || cmd === "-v" || cmd === "-V") {
|
|
|
872
2057
|
} else if (cmd === "about") {
|
|
873
2058
|
await showAbout();
|
|
874
2059
|
} else if (cmd === "init") {
|
|
875
|
-
|
|
876
|
-
const runtimeInstalled = isInstalled();
|
|
877
|
-
const hasSomaDir = existsSync(join(process.cwd(), ".soma"));
|
|
878
|
-
|
|
879
|
-
if (!runtimeInstalled) {
|
|
2060
|
+
if (!isInstalled()) {
|
|
880
2061
|
await initSoma();
|
|
881
|
-
} else if (hasProjectArgs || !hasSomaDir) {
|
|
882
|
-
await delegateToCore();
|
|
883
2062
|
} else {
|
|
884
|
-
await
|
|
2063
|
+
await delegateToCore();
|
|
885
2064
|
}
|
|
886
2065
|
} else if (cmd === "update") {
|
|
2066
|
+
await checkAndUpdate();
|
|
2067
|
+
} else if (cmd === "check-updates" || cmd === "updates") {
|
|
887
2068
|
checkForUpdates();
|
|
888
2069
|
} else if (cmd === "doctor") {
|
|
889
2070
|
await projectDoctor();
|
|
890
2071
|
} else if (cmd === "status" || cmd === "health") {
|
|
891
2072
|
await healthCheck();
|
|
2073
|
+
} else if (cmd && cmd.startsWith("--") && !isInstalled()) {
|
|
2074
|
+
console.log(` ${yellow("\u26A0")} Unknown option: ${cmd}`);
|
|
2075
|
+
console.log(` Run ${green("soma --help")} for usage.`);
|
|
2076
|
+
console.log("");
|
|
892
2077
|
} else if (isInstalled()) {
|
|
2078
|
+
try {
|
|
2079
|
+
const cfg = readConfig();
|
|
2080
|
+
if (cfg.updateAvailable) {
|
|
2081
|
+
const latest = cfg.latestSummary ? ` \u2014 ${dim(cfg.latestSummary)}` : "";
|
|
2082
|
+
console.log(` ${yellow("\u2B06")} Update available${latest}`);
|
|
2083
|
+
console.log(` ${dim("Run:")} ${green("soma update")}`);
|
|
2084
|
+
console.log("");
|
|
2085
|
+
}
|
|
2086
|
+
} catch {
|
|
2087
|
+
}
|
|
893
2088
|
await delegateToCore();
|
|
894
2089
|
} else {
|
|
895
2090
|
const postInstallCmds = ["focus", "inhale", "content", "install", "list", "map", "--map", "--preload"];
|