@sammorrowdrums/mcpi 0.70.9 → 0.85.0-bootstrap.0
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 +1621 -0
- package/LICENSE +21 -0
- package/README.md +196 -141
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js +4 -0
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/register-bedrock.d.ts.map +1 -1
- package/dist/bun/register-bedrock.js +1 -1
- package/dist/bun/register-bedrock.js.map +1 -1
- package/dist/bun/restore-sandbox-env.d.ts +17 -0
- package/dist/bun/restore-sandbox-env.d.ts.map +1 -0
- package/dist/bun/restore-sandbox-env.js +36 -0
- package/dist/bun/restore-sandbox-env.js.map +1 -0
- package/dist/cli/args.d.ts +9 -2
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +116 -16
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/auth-check.d.ts +19 -0
- package/dist/cli/auth-check.d.ts.map +1 -0
- package/dist/cli/auth-check.js +50 -0
- package/dist/cli/auth-check.js.map +1 -0
- package/dist/cli/auth-command.d.ts +24 -0
- package/dist/cli/auth-command.d.ts.map +1 -0
- package/dist/cli/auth-command.js +103 -0
- package/dist/cli/auth-command.js.map +1 -0
- package/dist/cli/config-selector.d.ts +6 -4
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +4 -4
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/credential-print.d.ts +13 -0
- package/dist/cli/credential-print.d.ts.map +1 -0
- package/dist/cli/credential-print.js +76 -0
- package/dist/cli/credential-print.js.map +1 -0
- package/dist/cli/experimental/auth.d.ts +16 -0
- package/dist/cli/experimental/auth.d.ts.map +1 -0
- package/dist/cli/experimental/auth.js +13 -0
- package/dist/cli/experimental/auth.js.map +1 -0
- package/dist/cli/experimental/cli.d.ts +6 -0
- package/dist/cli/experimental/cli.d.ts.map +1 -0
- package/dist/cli/experimental/cli.js +5 -0
- package/dist/cli/experimental/cli.js.map +1 -0
- package/dist/cli/experimental/command-options.d.ts +17 -0
- package/dist/cli/experimental/command-options.d.ts.map +1 -0
- package/dist/cli/experimental/command-options.js +35 -0
- package/dist/cli/experimental/command-options.js.map +1 -0
- package/dist/cli/experimental/command.d.ts +63 -0
- package/dist/cli/experimental/command.d.ts.map +1 -0
- package/dist/cli/experimental/command.js +130 -0
- package/dist/cli/experimental/command.js.map +1 -0
- package/dist/cli/experimental/commands/client.d.ts +13 -0
- package/dist/cli/experimental/commands/client.d.ts.map +1 -0
- package/dist/cli/experimental/commands/client.js +25 -0
- package/dist/cli/experimental/commands/client.js.map +1 -0
- package/dist/cli/experimental/commands/mcpi.d.ts +15 -0
- package/dist/cli/experimental/commands/mcpi.d.ts.map +1 -0
- package/dist/cli/experimental/commands/mcpi.js +28 -0
- package/dist/cli/experimental/commands/mcpi.js.map +1 -0
- package/dist/cli/experimental/commands/server.d.ts +13 -0
- package/dist/cli/experimental/commands/server.d.ts.map +1 -0
- package/dist/cli/experimental/commands/server.js +25 -0
- package/dist/cli/experimental/commands/server.js.map +1 -0
- package/dist/cli/experimental/transport-address.d.ts +10 -0
- package/dist/cli/experimental/transport-address.d.ts.map +1 -0
- package/dist/cli/experimental/transport-address.js +38 -0
- package/dist/cli/experimental/transport-address.js.map +1 -0
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +13 -26
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/cli/initial-message.d.ts +1 -1
- package/dist/cli/initial-message.d.ts.map +1 -1
- package/dist/cli/initial-message.js.map +1 -1
- package/dist/cli/list-models.d.ts +2 -2
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +4 -4
- package/dist/cli/list-models.js.map +1 -1
- package/dist/cli/project-trust.d.ts +10 -0
- package/dist/cli/project-trust.d.ts.map +1 -0
- package/dist/cli/project-trust.js +48 -0
- package/dist/cli/project-trust.js.map +1 -0
- package/dist/cli/session-picker.d.ts +3 -2
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js +5 -4
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/cli/startup-ui.d.ts +20 -0
- package/dist/cli/startup-ui.d.ts.map +1 -0
- package/dist/cli/startup-ui.js +184 -0
- package/dist/cli/startup-ui.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -3
- package/dist/cli.js.map +1 -1
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +3 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/remote-session.d.ts +53 -0
- package/dist/client/remote-session.d.ts.map +1 -0
- package/dist/client/remote-session.js +340 -0
- package/dist/client/remote-session.js.map +1 -0
- package/dist/client/transcript.d.ts +12 -0
- package/dist/client/transcript.d.ts.map +1 -0
- package/dist/client/transcript.js +98 -0
- package/dist/client/transcript.js.map +1 -0
- package/dist/config.d.ts +34 -12
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +312 -61
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +11 -9
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +16 -7
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +13 -12
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +34 -14
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +110 -53
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +658 -488
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-guidance.d.ts.map +1 -1
- package/dist/core/auth-guidance.js.map +1 -1
- package/dist/core/auth-storage.d.ts +35 -104
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +272 -286
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +11 -8
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/cache-stats.d.ts +49 -0
- package/dist/core/cache-stats.d.ts.map +1 -0
- package/dist/core/cache-stats.js +101 -0
- package/dist/core/cache-stats.js.map +1 -0
- package/dist/core/compaction/branch-summarization.d.ts +16 -6
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +13 -10
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +25 -9
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +163 -133
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/index.d.ts +3 -3
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/compaction/utils.d.ts +3 -3
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +7 -18
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/defaults.d.ts +1 -1
- package/dist/core/defaults.d.ts.map +1 -1
- package/dist/core/defaults.js.map +1 -1
- package/dist/core/env-overlay.d.ts +21 -0
- package/dist/core/env-overlay.d.ts.map +1 -0
- package/dist/core/env-overlay.js +25 -0
- package/dist/core/env-overlay.js.map +1 -0
- package/dist/core/exec.d.ts +8 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +7 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/experimental.d.ts +6 -0
- package/dist/core/experimental.d.ts.map +1 -0
- package/dist/core/experimental.js +8 -0
- package/dist/core/experimental.js.map +1 -0
- package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
- package/dist/core/export-html/ansi-to-html.js +1 -1
- package/dist/core/export-html/ansi-to-html.js.map +1 -1
- package/dist/core/export-html/index.d.ts +2 -2
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +8 -6
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/template.css +53 -4
- package/dist/core/export-html/template.js +129 -35
- package/dist/core/export-html/tool-renderer.d.ts +2 -8
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +15 -2
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/export-html/vendor/marked.min.js +75 -3
- package/dist/core/extensions/index.d.ts +8 -8
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +5 -7
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +160 -87
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +32 -13
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +192 -4
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +217 -69
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/wrapper.d.ts +3 -3
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.js +22 -3
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +12 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +30 -2
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts +22 -0
- package/dist/core/http-dispatcher.d.ts.map +1 -0
- package/dist/core/http-dispatcher.js +96 -0
- package/dist/core/http-dispatcher.js.map +1 -0
- package/dist/core/index.d.ts +9 -8
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +79 -10
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +11 -10
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/messages.d.ts +2 -2
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-config.d.ts +571 -0
- package/dist/core/model-config.d.ts.map +1 -0
- package/dist/core/model-config.js +254 -0
- package/dist/core/model-config.js.map +1 -0
- package/dist/core/model-registry.d.ts +23 -110
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +65 -616
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +20 -7
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +139 -43
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +100 -0
- package/dist/core/model-runtime.d.ts.map +1 -0
- package/dist/core/model-runtime.js +602 -0
- package/dist/core/model-runtime.js.map +1 -0
- package/dist/core/models-store.d.ts +22 -0
- package/dist/core/models-store.d.ts.map +1 -0
- package/dist/core/models-store.js +113 -0
- package/dist/core/models-store.js.map +1 -0
- package/dist/core/output-guard.d.ts +1 -0
- package/dist/core/output-guard.d.ts.map +1 -1
- package/dist/core/output-guard.js +52 -22
- package/dist/core/output-guard.js.map +1 -1
- package/dist/core/package-manager.d.ts +21 -4
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +428 -191
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/pi-manifest.d.ts +8 -0
- package/dist/core/pi-manifest.d.ts.map +1 -0
- package/dist/core/pi-manifest.js +25 -0
- package/dist/core/pi-manifest.js.map +1 -0
- package/dist/core/project-trust.d.ts +15 -0
- package/dist/core/project-trust.d.ts.map +1 -0
- package/dist/core/project-trust.js +59 -0
- package/dist/core/project-trust.js.map +1 -0
- package/dist/core/prompt-templates.d.ts +4 -2
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +36 -50
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/provider-attribution.d.ts +4 -0
- package/dist/core/provider-attribution.d.ts.map +1 -0
- package/dist/core/provider-attribution.js +72 -0
- package/dist/core/provider-attribution.js.map +1 -0
- package/dist/core/provider-composer.d.ts +58 -0
- package/dist/core/provider-composer.d.ts.map +1 -0
- package/dist/core/provider-composer.js +396 -0
- package/dist/core/provider-composer.js.map +1 -0
- package/dist/core/radius.d.ts +2 -0
- package/dist/core/radius.d.ts.map +1 -0
- package/dist/core/radius.js +2 -0
- package/dist/core/radius.js.map +1 -0
- package/dist/core/remote-catalog-provider.d.ts +17 -0
- package/dist/core/remote-catalog-provider.d.ts.map +1 -0
- package/dist/core/remote-catalog-provider.js +137 -0
- package/dist/core/remote-catalog-provider.js.map +1 -0
- package/dist/core/resolve-config-value.d.ts +13 -6
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +143 -22
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts +40 -12
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +236 -87
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/runtime-credentials.d.ts +15 -0
- package/dist/core/runtime-credentials.d.ts.map +1 -0
- package/dist/core/runtime-credentials.js +39 -0
- package/dist/core/runtime-credentials.js.map +1 -0
- package/dist/core/sdk.d.ts +26 -25
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +56 -49
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +42 -19
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +454 -223
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +77 -8
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +255 -67
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +2 -2
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +12 -34
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts +2 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +4 -3
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/source-info.d.ts +1 -1
- package/dist/core/source-info.d.ts.map +1 -1
- package/dist/core/source-info.js.map +1 -1
- package/dist/core/system-prompt.d.ts +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +15 -25
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/telemetry.d.ts +7 -1
- package/dist/core/telemetry.d.ts.map +1 -1
- package/dist/core/telemetry.js +7 -1
- package/dist/core/telemetry.js.map +1 -1
- package/dist/core/timings.d.ts +5 -3
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js +26 -16
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/bash.d.ts +11 -7
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +220 -188
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +26 -5
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +110 -23
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts +11 -5
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +67 -100
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +27 -12
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/find.d.ts +10 -3
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +41 -37
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +7 -3
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +12 -8
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +18 -18
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts +7 -3
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +17 -15
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts +52 -0
- package/dist/core/tools/output-accumulator.d.ts.map +1 -0
- package/dist/core/tools/output-accumulator.js +184 -0
- package/dist/core/tools/output-accumulator.js.map +1 -0
- package/dist/core/tools/path-utils.d.ts +2 -0
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/path-utils.js +39 -21
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/core/tools/read.d.ts +7 -3
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +101 -51
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +5 -2
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +18 -2
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts +2 -2
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +3 -3
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/tools/truncate.d.ts.map +1 -1
- package/dist/core/tools/truncate.js +12 -2
- package/dist/core/tools/truncate.js.map +1 -1
- package/dist/core/tools/write.d.ts +6 -2
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +35 -45
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/trust-manager.d.ts +36 -0
- package/dist/core/trust-manager.d.ts.map +1 -0
- package/dist/core/trust-manager.js +202 -0
- package/dist/core/trust-manager.js.map +1 -0
- package/dist/core/usage-totals.d.ts +19 -0
- package/dist/core/usage-totals.d.ts.map +1 -0
- package/dist/core/usage-totals.js +52 -0
- package/dist/core/usage-totals.js.map +1 -0
- package/dist/extensions/index.d.ts +3 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/index.js +3 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/extensions/llama/client.d.ts +61 -0
- package/dist/extensions/llama/client.d.ts.map +1 -0
- package/dist/extensions/llama/client.js +302 -0
- package/dist/extensions/llama/client.js.map +1 -0
- package/dist/extensions/llama/huggingface.d.ts +23 -0
- package/dist/extensions/llama/huggingface.d.ts.map +1 -0
- package/dist/extensions/llama/huggingface.js +141 -0
- package/dist/extensions/llama/huggingface.js.map +1 -0
- package/dist/extensions/llama/index.d.ts +3 -0
- package/dist/extensions/llama/index.d.ts.map +1 -0
- package/dist/extensions/llama/index.js +217 -0
- package/dist/extensions/llama/index.js.map +1 -0
- package/dist/extensions/llama/provider.d.ts +10 -0
- package/dist/extensions/llama/provider.d.ts.map +1 -0
- package/dist/extensions/llama/provider.js +121 -0
- package/dist/extensions/llama/provider.js.map +1 -0
- package/dist/extensions/llama/ui.d.ts +42 -0
- package/dist/extensions/llama/ui.d.ts.map +1 -0
- package/dist/extensions/llama/ui.js +416 -0
- package/dist/extensions/llama/ui.js.map +1 -0
- package/dist/index.d.ts +34 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +2 -2
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +311 -101
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +5 -5
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +10 -10
- package/dist/migrations.js.map +1 -1
- package/dist/modes/index.d.ts +6 -5
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/components/armin.d.ts +1 -1
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +8 -3
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +55 -26
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +2 -2
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +4 -4
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +2 -2
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +1 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +2 -2
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +2 -2
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts +37 -6
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +318 -34
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.d.ts +3 -3
- package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.js +2 -2
- package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +2 -2
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +9 -2
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/custom-entry.d.ts +19 -0
- package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -0
- package/dist/modes/interactive/components/custom-entry.js +52 -0
- package/dist/modes/interactive/components/custom-entry.js.map +1 -0
- package/dist/modes/interactive/components/custom-message.d.ts +6 -4
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +11 -3
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/daxnuts.d.ts +1 -1
- package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
- package/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/dist/modes/interactive/components/diff.js.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts +1 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +5 -4
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +19 -32
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +1 -1
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +3 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +7 -2
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts +25 -0
- package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -0
- package/dist/modes/interactive/components/first-time-setup.js +103 -0
- package/dist/modes/interactive/components/first-time-setup.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +9 -4
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +52 -31
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +33 -31
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +2 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts +6 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +20 -6
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +12 -6
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +46 -17
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
- package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
- package/dist/modes/interactive/components/markdown-transform.js +19 -0
- package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
- package/dist/modes/interactive/components/mermaid.d.ts +11 -0
- package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
- package/dist/modes/interactive/components/mermaid.js +75 -0
- package/dist/modes/interactive/components/mermaid.js.map +1 -0
- package/dist/modes/interactive/components/model-selector.d.ts +13 -6
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +92 -44
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +7 -4
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +32 -28
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +5 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +52 -14
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js +1 -1
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +4 -5
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +18 -16
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +23 -2
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +322 -22
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +1 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +2 -2
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts +28 -0
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -0
- package/dist/modes/interactive/components/status-indicator.js +60 -0
- package/dist/modes/interactive/components/status-indicator.js.map +1 -0
- package/dist/modes/interactive/components/theme-selector.d.ts +1 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +1 -1
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts +2 -2
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +3 -2
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +2 -2
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +33 -2
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +7 -2
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +179 -26
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/trust-selector.d.ts +23 -0
- package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/trust-selector.js +91 -0
- package/dist/modes/interactive/components/trust-selector.js.map +1 -0
- package/dist/modes/interactive/components/user-message-selector.d.ts +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +1 -1
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts +9 -3
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +26 -6
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.js +1 -1
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts +12 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -0
- package/dist/modes/interactive/external-editor.js +37 -0
- package/dist/modes/interactive/external-editor.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +104 -26
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +1565 -692
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
- package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
- package/dist/modes/interactive/model-catalog-refresh.js +34 -0
- package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
- package/dist/modes/interactive/model-search.d.ts +12 -0
- package/dist/modes/interactive/model-search.d.ts.map +1 -0
- package/dist/modes/interactive/model-search.js +15 -0
- package/dist/modes/interactive/model-search.js.map +1 -0
- package/dist/modes/interactive/theme/dark.json +10 -5
- package/dist/modes/interactive/theme/light.json +10 -5
- package/dist/modes/interactive/theme/theme-controller.d.ts +40 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-controller.js +125 -0
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -0
- package/dist/modes/interactive/theme/theme-schema.json +22 -5
- package/dist/modes/interactive/theme/theme.d.ts +48 -7
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +194 -76
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/json-event.d.ts +31 -0
- package/dist/modes/json-event.d.ts.map +1 -0
- package/dist/modes/json-event.js +15 -0
- package/dist/modes/json-event.js.map +1 -0
- package/dist/modes/print-mode.d.ts +3 -3
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +16 -5
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +33 -10
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +89 -11
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +2 -2
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +69 -9
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +43 -5
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/package-manager-cli.d.ts +6 -2
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +527 -25
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/path-migration.d.ts +13 -0
- package/dist/path-migration.d.ts.map +1 -0
- package/dist/path-migration.js +52 -0
- package/dist/path-migration.js.map +1 -0
- package/dist/rpc-entry.d.ts +3 -0
- package/dist/rpc-entry.d.ts.map +1 -0
- package/dist/rpc-entry.js +11 -0
- package/dist/rpc-entry.js.map +1 -0
- package/dist/server/create-harness.d.ts +26 -0
- package/dist/server/create-harness.d.ts.map +1 -0
- package/dist/server/create-harness.js +106 -0
- package/dist/server/create-harness.js.map +1 -0
- package/dist/utils/abort.d.ts +5 -0
- package/dist/utils/abort.d.ts.map +1 -0
- package/dist/utils/abort.js +48 -0
- package/dist/utils/abort.js.map +1 -0
- package/dist/utils/ansi.d.ts +2 -0
- package/dist/utils/ansi.d.ts.map +1 -0
- package/dist/utils/ansi.js +52 -0
- package/dist/utils/ansi.js.map +1 -0
- package/dist/utils/changelog.d.ts +2 -1
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js +85 -0
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/child-process.d.ts +12 -5
- package/dist/utils/child-process.d.ts.map +1 -1
- package/dist/utils/child-process.js +33 -5
- package/dist/utils/child-process.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +4 -4
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +4 -1
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js +14 -8
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts +2 -0
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +129 -46
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/deprecation.d.ts +4 -0
- package/dist/utils/deprecation.d.ts.map +1 -0
- package/dist/utils/deprecation.js +13 -0
- package/dist/utils/deprecation.js.map +1 -0
- package/dist/utils/exif-orientation.d.ts +1 -1
- package/dist/utils/exif-orientation.d.ts.map +1 -1
- package/dist/utils/exif-orientation.js.map +1 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +54 -22
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/html.d.ts +7 -0
- package/dist/utils/html.d.ts.map +1 -0
- package/dist/utils/html.js +40 -0
- package/dist/utils/html.js.map +1 -0
- package/dist/utils/image-convert.d.ts +1 -0
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-convert.js +21 -15
- package/dist/utils/image-convert.js.map +1 -1
- package/dist/utils/image-process.d.ts +18 -0
- package/dist/utils/image-process.d.ts.map +1 -0
- package/dist/utils/image-process.js +83 -0
- package/dist/utils/image-process.js.map +1 -0
- package/dist/utils/image-resize-core.d.ts +30 -0
- package/dist/utils/image-resize-core.d.ts.map +1 -0
- package/dist/utils/image-resize-core.js +124 -0
- package/dist/utils/image-resize-core.js.map +1 -0
- package/dist/utils/image-resize-worker.d.ts +2 -0
- package/dist/utils/image-resize-worker.d.ts.map +1 -0
- package/dist/utils/image-resize-worker.js +31 -0
- package/dist/utils/image-resize-worker.js.map +1 -0
- package/dist/utils/image-resize.d.ts +7 -27
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js +75 -115
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/json.d.ts +3 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +7 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/management-http.d.ts +23 -0
- package/dist/utils/management-http.d.ts.map +1 -0
- package/dist/utils/management-http.js +50 -0
- package/dist/utils/management-http.js.map +1 -0
- package/dist/utils/mime.d.ts +1 -0
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js +100 -16
- package/dist/utils/mime.js.map +1 -1
- package/dist/utils/open-browser.d.ts +9 -0
- package/dist/utils/open-browser.d.ts.map +1 -0
- package/dist/utils/open-browser.js +22 -0
- package/dist/utils/open-browser.js.map +1 -0
- package/dist/utils/paths.d.ts +28 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +97 -2
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/pi-user-agent.d.ts +2 -0
- package/dist/utils/pi-user-agent.d.ts.map +1 -0
- package/dist/utils/pi-user-agent.js +5 -0
- package/dist/utils/pi-user-agent.js.map +1 -0
- package/dist/utils/shell.d.ts +1 -0
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +18 -6
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts +12 -0
- package/dist/utils/syntax-highlight.d.ts.map +1 -0
- package/dist/utils/syntax-highlight.js +118 -0
- package/dist/utils/syntax-highlight.js.map +1 -0
- package/dist/utils/tool-result-images.d.ts +19 -0
- package/dist/utils/tool-result-images.d.ts.map +1 -0
- package/dist/utils/tool-result-images.js +45 -0
- package/dist/utils/tool-result-images.js.map +1 -0
- package/dist/utils/tools-manager.d.ts +10 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +105 -36
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts +19 -0
- package/dist/utils/version-check.d.ts.map +1 -0
- package/dist/utils/version-check.js +85 -0
- package/dist/utils/version-check.js.map +1 -0
- package/dist/utils/windows-self-update.d.ts +3 -0
- package/dist/utils/windows-self-update.d.ts.map +1 -0
- package/dist/utils/windows-self-update.js +77 -0
- package/dist/utils/windows-self-update.js.map +1 -0
- package/docs/compaction.md +39 -32
- package/docs/containerization.md +113 -0
- package/docs/custom-provider.md +212 -75
- package/docs/development.md +9 -9
- package/docs/docs.json +156 -0
- package/docs/environment-variables.md +186 -0
- package/docs/extensions.md +652 -140
- package/docs/index.md +81 -0
- package/docs/json.md +26 -15
- package/docs/keybindings.md +60 -21
- package/docs/llama-cpp.md +99 -0
- package/docs/models.md +168 -34
- package/docs/packages.md +46 -36
- package/docs/prompt-templates.md +13 -5
- package/docs/providers.md +147 -26
- package/docs/quickstart.md +167 -0
- package/docs/rpc.md +218 -36
- package/docs/sdk.md +190 -125
- package/docs/security.md +59 -0
- package/docs/{session.md → session-format.md} +48 -22
- package/docs/sessions.md +145 -0
- package/docs/settings.md +130 -25
- package/docs/shell-aliases.md +2 -2
- package/docs/skills.md +13 -14
- package/docs/terminal-setup.md +73 -16
- package/docs/termux.md +10 -10
- package/docs/themes.md +41 -16
- package/docs/tmux.md +6 -4
- package/docs/tui.md +85 -61
- package/docs/usage.md +302 -0
- package/docs/windows.md +2 -2
- package/examples/README.md +1 -1
- package/examples/extensions/README.md +12 -9
- package/examples/extensions/bash-spawn-hook.ts +2 -2
- package/examples/extensions/border-status-editor.ts +145 -0
- package/examples/extensions/built-in-tool-renderer.ts +2 -2
- package/examples/extensions/claude-rules.ts +1 -1
- package/examples/extensions/commands.ts +1 -1
- package/examples/extensions/custom-compaction.ts +6 -16
- package/examples/extensions/custom-footer.ts +1 -1
- package/examples/extensions/custom-header.ts +7 -7
- package/examples/extensions/custom-provider-anthropic/index.ts +15 -8
- package/examples/extensions/custom-provider-anthropic/package-lock.json +4 -4
- package/examples/extensions/custom-provider-anthropic/package.json +3 -3
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +65 -9
- package/examples/extensions/custom-provider-gitlab-duo/package.json +2 -2
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +2 -2
- package/examples/extensions/doom-overlay/README.md +1 -1
- package/examples/extensions/doom-overlay/doom-component.ts +4 -4
- package/examples/extensions/doom-overlay/doom-keys.ts +1 -1
- package/examples/extensions/doom-overlay/index.ts +5 -5
- package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
- package/examples/extensions/dynamic-resources/dynamic.json +1 -1
- package/examples/extensions/entry-renderer.ts +41 -0
- package/examples/extensions/git-merge-and-resolve.ts +115 -0
- package/examples/extensions/github-issue-autocomplete.ts +2 -2
- package/examples/extensions/gondolin/index.ts +531 -0
- package/examples/extensions/gondolin/package-lock.json +185 -0
- package/examples/extensions/gondolin/package.json +19 -0
- package/examples/extensions/handoff.ts +50 -14
- package/examples/extensions/hidden-thinking-label.ts +1 -1
- package/examples/extensions/inline-bash.ts +2 -2
- package/examples/extensions/input-transform-streaming.ts +39 -0
- package/examples/extensions/input-transform.ts +2 -2
- package/examples/extensions/interactive-shell.ts +2 -2
- package/examples/extensions/kimi-deferred-tools.ts +61 -0
- package/examples/extensions/mac-system-theme.ts +2 -2
- package/examples/extensions/message-renderer.ts +3 -3
- package/examples/extensions/minimal-mode.ts +2 -2
- package/examples/extensions/modal-editor.ts +2 -2
- package/examples/extensions/model-status.ts +1 -1
- package/examples/extensions/notify.ts +3 -3
- package/examples/extensions/overlay-qa-tests.ts +242 -140
- package/examples/extensions/overlay-test.ts +9 -6
- package/examples/extensions/pirate.ts +1 -1
- package/examples/extensions/plan-mode/README.md +3 -2
- package/examples/extensions/plan-mode/index.ts +90 -40
- package/examples/extensions/preset.ts +16 -10
- package/examples/extensions/project-trust.ts +64 -0
- package/examples/extensions/prompt-customizer.ts +1 -1
- package/examples/extensions/provider-payload.ts +5 -5
- package/examples/extensions/qna.ts +4 -8
- package/examples/extensions/question.ts +41 -19
- package/examples/extensions/questionnaire.ts +50 -29
- package/examples/extensions/rainbow-editor.ts +1 -1
- package/examples/extensions/reload-runtime.ts +2 -2
- package/examples/extensions/rpc-demo.ts +1 -1
- package/examples/extensions/sandbox/index.ts +9 -9
- package/examples/extensions/sandbox/package-lock.json +7 -7
- package/examples/extensions/sandbox/package.json +3 -3
- package/examples/extensions/shutdown-command.ts +5 -5
- package/examples/extensions/snake.ts +2 -2
- package/examples/extensions/space-invaders.ts +2 -2
- package/examples/extensions/ssh.ts +2 -2
- package/examples/extensions/structured-output.ts +1 -1
- package/examples/extensions/subagent/README.md +18 -13
- package/examples/extensions/subagent/agents.ts +42 -11
- package/examples/extensions/subagent/index.ts +76 -30
- package/examples/extensions/summarize.ts +12 -19
- package/examples/extensions/tic-tac-toe.ts +2 -2
- package/examples/extensions/titlebar-spinner.ts +3 -3
- package/examples/extensions/todo.ts +2 -2
- package/examples/extensions/tool-override.ts +1 -1
- package/examples/extensions/tools.ts +7 -2
- package/examples/extensions/truncated-tool.ts +2 -2
- package/examples/extensions/with-deps/package-lock.json +4 -4
- package/examples/extensions/with-deps/package.json +4 -4
- package/examples/extensions/working-indicator.ts +4 -4
- package/examples/extensions/working-message-test.ts +1 -1
- package/examples/rpc-extension-ui.ts +11 -2
- package/examples/sdk/01-minimal.ts +15 -11
- package/examples/sdk/02-custom-model.ts +18 -18
- package/examples/sdk/03-custom-prompt.ts +25 -17
- package/examples/sdk/04-skills.ts +3 -3
- package/examples/sdk/05-tools.ts +8 -4
- package/examples/sdk/06-extensions.ts +13 -9
- package/examples/sdk/07-context-files.ts +2 -2
- package/examples/sdk/08-prompt-templates.ts +3 -3
- package/examples/sdk/09-api-keys-and-oauth.ts +19 -33
- package/examples/sdk/10-settings.ts +4 -4
- package/examples/sdk/11-sessions.ts +4 -0
- package/examples/sdk/12-full-control.ts +22 -21
- package/examples/sdk/README.md +23 -30
- package/npm-shrinkwrap.json +1818 -0
- package/package.json +117 -99
- package/dist/modes/interactive/assets/clankolas.png +0 -0
- package/dist/modes/interactive/components/auth-selector-status.d.ts +0 -20
- package/dist/modes/interactive/components/auth-selector-status.d.ts.map +0 -1
- package/dist/modes/interactive/components/auth-selector-status.js +0 -23
- package/dist/modes/interactive/components/auth-selector-status.js.map +0 -1
- package/dist/modes/interactive/components/earendil-announcement.d.ts +0 -5
- package/dist/modes/interactive/components/earendil-announcement.d.ts.map +0 -1
- package/dist/modes/interactive/components/earendil-announcement.js +0 -40
- package/dist/modes/interactive/components/earendil-announcement.js.map +0 -1
- package/docs/images/exy.png +0 -0
- package/docs/tree.md +0 -233
- package/examples/extensions/antigravity-image-gen.ts +0 -418
- package/examples/extensions/custom-provider-qwen-cli/index.ts +0 -345
- package/examples/extensions/custom-provider-qwen-cli/package.json +0 -16
package/docs/extensions.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
>
|
|
1
|
+
> mcpi can create extensions. Ask it to build one for your use case.
|
|
2
2
|
|
|
3
3
|
# Extensions
|
|
4
4
|
|
|
5
|
-
Extensions are TypeScript modules that extend
|
|
5
|
+
Extensions are TypeScript modules that extend mcpi's behavior. They can subscribe to lifecycle events, register custom tools callable by the LLM, add commands, and more. The extension API parameter remains named `pi`.
|
|
6
6
|
|
|
7
|
-
> **Placement for /reload:** Put extensions in
|
|
7
|
+
> **Placement for /reload:** Put extensions in `$XDG_CONFIG_HOME/mcpi/extensions/` (fallback `~/.config/mcpi/extensions/`; `%APPDATA%\mcpi\extensions\` on Windows) or `.mcpi/extensions/` (project-local) for auto-discovery. Use `mcpi -e ./path.ts` only for quick tests. Extensions in auto-discovered locations can be hot-reloaded with `/reload`.
|
|
8
8
|
|
|
9
9
|
**Key capabilities:**
|
|
10
10
|
- **Custom tools** - Register tools the LLM can call via `pi.registerTool()`
|
|
@@ -40,12 +40,14 @@ See [examples/extensions/](../examples/extensions/) for working implementations.
|
|
|
40
40
|
- [Resource Events](#resource-events)
|
|
41
41
|
- [Session Events](#session-events)
|
|
42
42
|
- [Agent Events](#agent-events)
|
|
43
|
+
- [Model Events](#model-events)
|
|
43
44
|
- [Tool Events](#tool-events)
|
|
44
45
|
- [ExtensionContext](#extensioncontext)
|
|
45
46
|
- [ExtensionCommandContext](#extensioncommandcontext)
|
|
46
47
|
- [ExtensionAPI Methods](#extensionapi-methods)
|
|
47
48
|
- [State Management](#state-management)
|
|
48
49
|
- [Custom Tools](#custom-tools)
|
|
50
|
+
- [Dynamic Tool Loading](#dynamic-tool-loading)
|
|
49
51
|
- [Custom UI](#custom-ui)
|
|
50
52
|
- [Error Handling](#error-handling)
|
|
51
53
|
- [Mode Behavior](#mode-behavior)
|
|
@@ -53,10 +55,10 @@ See [examples/extensions/](../examples/extensions/) for working implementations.
|
|
|
53
55
|
|
|
54
56
|
## Quick Start
|
|
55
57
|
|
|
56
|
-
Create `~/.
|
|
58
|
+
Create `$XDG_CONFIG_HOME/mcpi/extensions/my-extension.ts` (fallback `~/.config/mcpi/extensions/my-extension.ts`; `%APPDATA%\mcpi\extensions\my-extension.ts` on Windows):
|
|
57
59
|
|
|
58
60
|
```typescript
|
|
59
|
-
import type { ExtensionAPI } from "@
|
|
61
|
+
import type { ExtensionAPI } from "@sammorrowdrums/mcpi";
|
|
60
62
|
import { Type } from "typebox";
|
|
61
63
|
|
|
62
64
|
export default function (pi: ExtensionAPI) {
|
|
@@ -101,21 +103,21 @@ export default function (pi: ExtensionAPI) {
|
|
|
101
103
|
Test with `--extension` (or `-e`) flag:
|
|
102
104
|
|
|
103
105
|
```bash
|
|
104
|
-
|
|
106
|
+
mcpi -e ./my-extension.ts
|
|
105
107
|
```
|
|
106
108
|
|
|
107
109
|
## Extension Locations
|
|
108
110
|
|
|
109
111
|
> **Security:** Extensions run with your full system permissions and can execute arbitrary code. Only install from sources you trust.
|
|
110
112
|
|
|
111
|
-
Extensions are auto-discovered from
|
|
113
|
+
Extensions are auto-discovered from trusted locations. Project-local `.mcpi/extensions` entries load only after the project is trusted.
|
|
112
114
|
|
|
113
115
|
| Location | Scope |
|
|
114
116
|
|----------|-------|
|
|
115
|
-
|
|
|
116
|
-
|
|
|
117
|
-
| `.
|
|
118
|
-
| `.
|
|
117
|
+
| `$XDG_CONFIG_HOME/mcpi/extensions/*.ts` | Global (all projects; uses the platform config fallback when XDG is unset) |
|
|
118
|
+
| `$XDG_CONFIG_HOME/mcpi/extensions/*/index.ts` | Global (subdirectory) |
|
|
119
|
+
| `.mcpi/extensions/*.ts` | Project-local |
|
|
120
|
+
| `.mcpi/extensions/*/index.ts` | Project-local (subdirectory) |
|
|
119
121
|
|
|
120
122
|
Additional paths via `settings.json`:
|
|
121
123
|
|
|
@@ -132,20 +134,20 @@ Additional paths via `settings.json`:
|
|
|
132
134
|
}
|
|
133
135
|
```
|
|
134
136
|
|
|
135
|
-
To share extensions via npm or git as
|
|
137
|
+
To share extensions via npm or git as mcpi packages, see [packages.md](packages.md).
|
|
136
138
|
|
|
137
139
|
## Available Imports
|
|
138
140
|
|
|
139
141
|
| Package | Purpose |
|
|
140
142
|
|---------|---------|
|
|
141
|
-
| `@
|
|
143
|
+
| `@sammorrowdrums/mcpi` | Extension types (`ExtensionAPI`, `ExtensionContext`, events) |
|
|
142
144
|
| `typebox` | Schema definitions for tool parameters |
|
|
143
|
-
| `@
|
|
144
|
-
| `@
|
|
145
|
+
| `@sammorrowdrums/mcpi-ai` | AI utilities (`StringEnum` for Google-compatible enums) |
|
|
146
|
+
| `@sammorrowdrums/mcpi-tui` | TUI components for custom rendering |
|
|
145
147
|
|
|
146
148
|
npm dependencies work too. Add a `package.json` next to your extension (or in a parent directory), run `npm install`, and imports from `node_modules/` are resolved automatically.
|
|
147
149
|
|
|
148
|
-
For distributed
|
|
150
|
+
For distributed mcpi packages installed with `mcpi install` (npm or git), runtime deps must be in `dependencies`. Package installation uses production installs (`npm install --omit=dev`) by default, so `devDependencies` are not available at runtime; when `npmCommand` is configured, git packages use plain `install` for compatibility with wrappers.
|
|
149
151
|
|
|
150
152
|
Node.js built-ins (`node:fs`, `node:path`, etc.) are also available.
|
|
151
153
|
|
|
@@ -154,14 +156,14 @@ Node.js built-ins (`node:fs`, `node:path`, etc.) are also available.
|
|
|
154
156
|
An extension exports a default factory function that receives `ExtensionAPI`. The factory can be synchronous or asynchronous:
|
|
155
157
|
|
|
156
158
|
```typescript
|
|
157
|
-
import type { ExtensionAPI } from "@
|
|
159
|
+
import type { ExtensionAPI } from "@sammorrowdrums/mcpi";
|
|
158
160
|
|
|
159
161
|
export default function (pi: ExtensionAPI) {
|
|
160
162
|
// Subscribe to events
|
|
161
163
|
pi.on("event_name", async (event, ctx) => {
|
|
162
164
|
// ctx.ui for user interaction
|
|
163
165
|
const ok = await ctx.ui.confirm("Title", "Are you sure?");
|
|
164
|
-
ctx.ui.notify("Done!", "
|
|
166
|
+
ctx.ui.notify("Done!", "info");
|
|
165
167
|
ctx.ui.setStatus("my-ext", "Processing..."); // Footer status
|
|
166
168
|
ctx.ui.setWidget("my-ext", ["Line 1", "Line 2"]); // Widget above editor (default)
|
|
167
169
|
});
|
|
@@ -176,14 +178,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
176
178
|
|
|
177
179
|
Extensions are loaded via [jiti](https://github.com/unjs/jiti), so TypeScript works without compilation.
|
|
178
180
|
|
|
179
|
-
If the factory returns a `Promise`,
|
|
181
|
+
If the factory returns a `Promise`, mcpi awaits it before continuing startup. That means async initialization completes before `session_start`, before `resources_discover`, and before provider registrations queued via `pi.registerProvider()` are flushed.
|
|
180
182
|
|
|
181
183
|
### Async factory functions
|
|
182
184
|
|
|
183
185
|
Use an async factory for one-time startup work such as fetching remote configuration or dynamically discovering available models.
|
|
184
186
|
|
|
185
187
|
```typescript
|
|
186
|
-
import type { ExtensionAPI } from "@
|
|
188
|
+
import type { ExtensionAPI } from "@sammorrowdrums/mcpi";
|
|
187
189
|
|
|
188
190
|
export default async function (pi: ExtensionAPI) {
|
|
189
191
|
const response = await fetch("http://localhost:1234/v1/models");
|
|
@@ -198,7 +200,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
198
200
|
|
|
199
201
|
pi.registerProvider("local-openai", {
|
|
200
202
|
baseUrl: "http://localhost:1234/v1",
|
|
201
|
-
apiKey: "LOCAL_OPENAI_API_KEY",
|
|
203
|
+
apiKey: "$LOCAL_OPENAI_API_KEY",
|
|
202
204
|
api: "openai-completions",
|
|
203
205
|
models: payload.data.map((model) => ({
|
|
204
206
|
id: model.id,
|
|
@@ -213,21 +215,27 @@ export default async function (pi: ExtensionAPI) {
|
|
|
213
215
|
}
|
|
214
216
|
```
|
|
215
217
|
|
|
216
|
-
This pattern makes the fetched models available during normal startup and to `
|
|
218
|
+
This pattern makes the fetched models available during normal startup and to `mcpi --list-models`.
|
|
219
|
+
|
|
220
|
+
### Long-lived resources and shutdown
|
|
221
|
+
|
|
222
|
+
Extension factories may run in invocations that never start a session. Do not start background resources such as processes, sockets, file watchers, or timers from the factory.
|
|
223
|
+
|
|
224
|
+
Defer background resource startup until `session_start` or the command/tool/event that needs the resource. Register an idempotent `session_shutdown` handler to close any session-scoped resources you start.
|
|
217
225
|
|
|
218
226
|
### Extension Styles
|
|
219
227
|
|
|
220
228
|
**Single file** - simplest, for small extensions:
|
|
221
229
|
|
|
222
230
|
```
|
|
223
|
-
~/.
|
|
231
|
+
~/.config/mcpi/extensions/
|
|
224
232
|
└── my-extension.ts
|
|
225
233
|
```
|
|
226
234
|
|
|
227
235
|
**Directory with index.ts** - for multi-file extensions:
|
|
228
236
|
|
|
229
237
|
```
|
|
230
|
-
~/.
|
|
238
|
+
~/.config/mcpi/extensions/
|
|
231
239
|
└── my-extension/
|
|
232
240
|
├── index.ts # Entry point (exports default function)
|
|
233
241
|
├── tools.ts # Helper module
|
|
@@ -237,7 +245,7 @@ This pattern makes the fetched models available during normal startup and to `pi
|
|
|
237
245
|
**Package with dependencies** - for extensions that need npm packages:
|
|
238
246
|
|
|
239
247
|
```
|
|
240
|
-
~/.
|
|
248
|
+
~/.config/mcpi/extensions/
|
|
241
249
|
└── my-extension/
|
|
242
250
|
├── package.json # Declares dependencies and entry points
|
|
243
251
|
├── package-lock.json
|
|
@@ -267,8 +275,9 @@ Run `npm install` in the extension directory, then imports from `node_modules/`
|
|
|
267
275
|
### Lifecycle Overview
|
|
268
276
|
|
|
269
277
|
```
|
|
270
|
-
|
|
278
|
+
mcpi starts
|
|
271
279
|
│
|
|
280
|
+
├─► project_trust (user/global and CLI extensions only, before project resources load)
|
|
272
281
|
├─► session_start { reason: "startup" }
|
|
273
282
|
└─► resources_discover { reason: "startup" }
|
|
274
283
|
│
|
|
@@ -286,6 +295,7 @@ user sends prompt ────────────────────
|
|
|
286
295
|
│ │ │ │
|
|
287
296
|
│ ├─► turn_start │ │
|
|
288
297
|
│ ├─► context (can modify messages) │ │
|
|
298
|
+
│ ├─► before_provider_headers (can mutate headers) |
|
|
289
299
|
│ ├─► before_provider_request (can inspect or replace payload)
|
|
290
300
|
│ ├─► after_provider_response (status + headers, before stream consume)
|
|
291
301
|
│ │ │ │
|
|
@@ -298,7 +308,8 @@ user sends prompt ────────────────────
|
|
|
298
308
|
│ │ │ │
|
|
299
309
|
│ └─► turn_end │ │
|
|
300
310
|
│ │
|
|
301
|
-
|
|
311
|
+
├─► agent_end │
|
|
312
|
+
└─► agent_settled (no retry/compaction/follow-up left) │
|
|
302
313
|
│
|
|
303
314
|
user sends another prompt ◄────────────────────────────────┘
|
|
304
315
|
|
|
@@ -314,6 +325,9 @@ user sends another prompt ◄─────────────────
|
|
|
314
325
|
├─► session_start { reason: "fork", previousSessionFile }
|
|
315
326
|
└─► resources_discover { reason: "startup" }
|
|
316
327
|
|
|
328
|
+
/name or pi.setSessionName()
|
|
329
|
+
└─► session_info_changed
|
|
330
|
+
|
|
317
331
|
/compact or auto-compaction
|
|
318
332
|
├─► session_before_compact (can cancel or customize)
|
|
319
333
|
└─► session_compact
|
|
@@ -323,12 +337,35 @@ user sends another prompt ◄─────────────────
|
|
|
323
337
|
└─► session_tree
|
|
324
338
|
|
|
325
339
|
/model or Ctrl+P (model selection/cycling)
|
|
340
|
+
├─► thinking_level_select (if model change changes/clamps thinking level)
|
|
326
341
|
└─► model_select
|
|
327
342
|
|
|
343
|
+
thinking level changes (settings, keybinding, pi.setThinkingLevel())
|
|
344
|
+
└─► thinking_level_select
|
|
345
|
+
|
|
328
346
|
exit (Ctrl+C, Ctrl+D, SIGHUP, SIGTERM)
|
|
329
347
|
└─► session_shutdown
|
|
330
348
|
```
|
|
331
349
|
|
|
350
|
+
### Startup Events
|
|
351
|
+
|
|
352
|
+
#### project_trust
|
|
353
|
+
|
|
354
|
+
Fired before mcpi decides whether to trust a project with dynamic configs (`.mcpi` or `.agents/skills`). It runs during startup and when session replacement (for example `/resume`) enters a cwd whose trust has not been resolved in the current process. Only user/global extensions and CLI `-e` extensions participate; project-local extensions are not loaded until after trust is resolved.
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
pi.on("project_trust", async (event, ctx) => {
|
|
358
|
+
// event.cwd - current working directory
|
|
359
|
+
// ctx has a limited trust context: cwd, mode, hasUI, and select/confirm/input/notify UI helpers
|
|
360
|
+
if (await ctx.ui.confirm("Trust project?", event.cwd)) {
|
|
361
|
+
return { trusted: "yes", remember: true };
|
|
362
|
+
}
|
|
363
|
+
return { trusted: "undecided" };
|
|
364
|
+
});
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
A `project_trust` handler must return `{ trusted: "yes" | "no" | "undecided" }`. A user/global or CLI extension that returns `"yes"` or `"no"` owns the decision; the first yes/no decision wins and suppresses the built-in trust prompt. Use `remember: true` to persist a yes/no decision; otherwise it applies only to the current process. Return `"undecided"` to let later handlers or the built-in trust flow decide. Check `ctx.hasUI` before prompting. If no handler returns yes/no, normal trust resolution continues: saved `trust.json` decisions apply first, then `defaultProjectTrust` controls whether mcpi asks, trusts, or declines by default.
|
|
368
|
+
|
|
332
369
|
### Resource Events
|
|
333
370
|
|
|
334
371
|
#### resources_discover
|
|
@@ -350,7 +387,7 @@ pi.on("resources_discover", async (event, _ctx) => {
|
|
|
350
387
|
|
|
351
388
|
### Session Events
|
|
352
389
|
|
|
353
|
-
See [
|
|
390
|
+
See [Session Format](session-format.md) for session storage internals and the SessionManager API.
|
|
354
391
|
|
|
355
392
|
#### session_start
|
|
356
393
|
|
|
@@ -364,6 +401,17 @@ pi.on("session_start", async (event, ctx) => {
|
|
|
364
401
|
});
|
|
365
402
|
```
|
|
366
403
|
|
|
404
|
+
#### session_info_changed
|
|
405
|
+
|
|
406
|
+
Fired when the current session display name is set via `/name`, RPC, or `pi.setSessionName()`.
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
pi.on("session_info_changed", async (event, ctx) => {
|
|
410
|
+
// event.name - current normalized name, or undefined if cleared
|
|
411
|
+
ctx.ui.notify(`Session renamed: ${event.name ?? "(none)"}`, "info");
|
|
412
|
+
});
|
|
413
|
+
```
|
|
414
|
+
|
|
367
415
|
#### session_before_switch
|
|
368
416
|
|
|
369
417
|
Fired before starting a new session (`/new`) or switching sessions (`/resume`).
|
|
@@ -380,7 +428,7 @@ pi.on("session_before_switch", async (event, ctx) => {
|
|
|
380
428
|
});
|
|
381
429
|
```
|
|
382
430
|
|
|
383
|
-
After a successful switch or new-session action,
|
|
431
|
+
After a successful switch or new-session action, mcpi emits `session_shutdown` for the old extension instance, reloads and rebinds extensions for the new session, then emits `session_start` with `reason: "new" | "resume"` and `previousSessionFile`.
|
|
384
432
|
Do cleanup work in `session_shutdown`, then reestablish any in-memory state in `session_start`.
|
|
385
433
|
|
|
386
434
|
#### session_before_fork
|
|
@@ -397,7 +445,7 @@ pi.on("session_before_fork", async (event, ctx) => {
|
|
|
397
445
|
});
|
|
398
446
|
```
|
|
399
447
|
|
|
400
|
-
After a successful fork or clone,
|
|
448
|
+
After a successful fork or clone, mcpi emits `session_shutdown` for the old extension instance, reloads and rebinds extensions for the new session, then emits `session_start` with `reason: "fork"` and `previousSessionFile`.
|
|
401
449
|
Do cleanup work in `session_shutdown`, then reestablish any in-memory state in `session_start`.
|
|
402
450
|
|
|
403
451
|
#### session_before_compact / session_compact
|
|
@@ -406,7 +454,10 @@ Fired on compaction. See [compaction.md](compaction.md) for details.
|
|
|
406
454
|
|
|
407
455
|
```typescript
|
|
408
456
|
pi.on("session_before_compact", async (event, ctx) => {
|
|
409
|
-
const { preparation, branchEntries, customInstructions, signal } = event;
|
|
457
|
+
const { preparation, branchEntries, customInstructions, reason, willRetry, signal } = event;
|
|
458
|
+
|
|
459
|
+
// reason - "manual" (/compact), "threshold", or "overflow"
|
|
460
|
+
// willRetry - whether the aborted turn is retried after compaction (overflow recovery)
|
|
410
461
|
|
|
411
462
|
// Cancel:
|
|
412
463
|
return { cancel: true };
|
|
@@ -417,6 +468,7 @@ pi.on("session_before_compact", async (event, ctx) => {
|
|
|
417
468
|
summary: "...",
|
|
418
469
|
firstKeptEntryId: preparation.firstKeptEntryId,
|
|
419
470
|
tokensBefore: preparation.tokensBefore,
|
|
471
|
+
// usage: summaryResponse.usage, // Optional; included in session totals
|
|
420
472
|
}
|
|
421
473
|
};
|
|
422
474
|
});
|
|
@@ -424,19 +476,27 @@ pi.on("session_before_compact", async (event, ctx) => {
|
|
|
424
476
|
pi.on("session_compact", async (event, ctx) => {
|
|
425
477
|
// event.compactionEntry - the saved compaction
|
|
426
478
|
// event.fromExtension - whether extension provided it
|
|
479
|
+
// event.reason - "manual" (/compact), "threshold", or "overflow"
|
|
480
|
+
// event.willRetry - whether the aborted turn is retried after compaction (overflow recovery)
|
|
427
481
|
});
|
|
428
482
|
```
|
|
429
483
|
|
|
430
484
|
#### session_before_tree / session_tree
|
|
431
485
|
|
|
432
|
-
Fired on `/tree` navigation. See [
|
|
486
|
+
Fired on `/tree` navigation. See [Sessions](sessions.md) for tree navigation concepts.
|
|
433
487
|
|
|
434
488
|
```typescript
|
|
435
489
|
pi.on("session_before_tree", async (event, ctx) => {
|
|
436
490
|
const { preparation, signal } = event;
|
|
437
491
|
return { cancel: true };
|
|
438
492
|
// OR provide custom summary:
|
|
439
|
-
return {
|
|
493
|
+
return {
|
|
494
|
+
summary: {
|
|
495
|
+
summary: "...",
|
|
496
|
+
// usage: summaryResponse.usage, // Optional; included in session totals
|
|
497
|
+
details: {},
|
|
498
|
+
},
|
|
499
|
+
};
|
|
440
500
|
});
|
|
441
501
|
|
|
442
502
|
pi.on("session_tree", async (event, ctx) => {
|
|
@@ -446,7 +506,7 @@ pi.on("session_tree", async (event, ctx) => {
|
|
|
446
506
|
|
|
447
507
|
#### session_shutdown
|
|
448
508
|
|
|
449
|
-
Fired before
|
|
509
|
+
Fired before a started session runtime is torn down. Use this to clean up resources opened from `session_start` or other session-scoped hooks.
|
|
450
510
|
|
|
451
511
|
```typescript
|
|
452
512
|
pi.on("session_shutdown", async (event, ctx) => {
|
|
@@ -491,19 +551,23 @@ pi.on("before_agent_start", async (event, ctx) => {
|
|
|
491
551
|
});
|
|
492
552
|
```
|
|
493
553
|
|
|
494
|
-
The `systemPromptOptions` field gives extensions access to the same structured data
|
|
554
|
+
The `systemPromptOptions` field gives extensions access to the same structured data mcpi uses to build the system prompt. This lets you inspect what mcpi has loaded — custom prompts, guidelines, tool snippets, context files, skills — without re-discovering resources or re-parsing flags. Use it when your extension needs to make deep, informed changes to the system prompt while respecting user-provided configuration.
|
|
495
555
|
|
|
496
556
|
Inside `before_agent_start`, `event.systemPrompt` and `ctx.getSystemPrompt()` both reflect the chained system prompt as of the current handler. Later `before_agent_start` handlers can still modify it again.
|
|
497
557
|
|
|
498
|
-
#### agent_start / agent_end
|
|
558
|
+
#### agent_start / agent_end / agent_settled
|
|
499
559
|
|
|
500
|
-
|
|
560
|
+
`agent_start` fires when a low-level agent run begins. `agent_end` fires when that run ends, but mcpi may still auto-retry, auto-compact and retry, or continue with queued follow-up messages. Use `agent_settled` for status integrations that need to know mcpi will not continue running automatically.
|
|
501
561
|
|
|
502
562
|
```typescript
|
|
503
563
|
pi.on("agent_start", async (_event, ctx) => {});
|
|
504
564
|
|
|
505
565
|
pi.on("agent_end", async (event, ctx) => {
|
|
506
|
-
// event.messages - messages from this
|
|
566
|
+
// event.messages - messages from this low-level run
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
pi.on("agent_settled", async (_event, ctx) => {
|
|
570
|
+
// ctx.isIdle() is true here unless another extension started a new run.
|
|
507
571
|
});
|
|
508
572
|
```
|
|
509
573
|
|
|
@@ -527,6 +591,7 @@ Fired for message lifecycle updates.
|
|
|
527
591
|
|
|
528
592
|
- `message_start` and `message_end` fire for user, assistant, and toolResult messages.
|
|
529
593
|
- `message_update` fires for assistant streaming updates.
|
|
594
|
+
- `message_end` handlers can return `{ message }` to replace the finalized message. The replacement must keep the same `role`.
|
|
530
595
|
|
|
531
596
|
```typescript
|
|
532
597
|
pi.on("message_start", async (event, ctx) => {
|
|
@@ -539,7 +604,20 @@ pi.on("message_update", async (event, ctx) => {
|
|
|
539
604
|
});
|
|
540
605
|
|
|
541
606
|
pi.on("message_end", async (event, ctx) => {
|
|
542
|
-
|
|
607
|
+
if (event.message.role !== "assistant") return;
|
|
608
|
+
|
|
609
|
+
return {
|
|
610
|
+
message: {
|
|
611
|
+
...event.message,
|
|
612
|
+
usage: {
|
|
613
|
+
...event.message.usage,
|
|
614
|
+
cost: {
|
|
615
|
+
...event.message.usage.cost,
|
|
616
|
+
total: 0.123,
|
|
617
|
+
},
|
|
618
|
+
},
|
|
619
|
+
},
|
|
620
|
+
};
|
|
543
621
|
});
|
|
544
622
|
```
|
|
545
623
|
|
|
@@ -569,7 +647,7 @@ pi.on("tool_execution_end", async (event, ctx) => {
|
|
|
569
647
|
|
|
570
648
|
#### context
|
|
571
649
|
|
|
572
|
-
Fired before each LLM call. Modify messages non-destructively. See [
|
|
650
|
+
Fired before each LLM call. Modify messages non-destructively. See [Session Format](session-format.md) for message types.
|
|
573
651
|
|
|
574
652
|
```typescript
|
|
575
653
|
pi.on("context", async (event, ctx) => {
|
|
@@ -579,11 +657,29 @@ pi.on("context", async (event, ctx) => {
|
|
|
579
657
|
});
|
|
580
658
|
```
|
|
581
659
|
|
|
660
|
+
#### before_provider_headers
|
|
661
|
+
|
|
662
|
+
Fired after the outgoing HTTP headers are assembled. Use it to add, override, or remove request headers.
|
|
663
|
+
|
|
664
|
+
Handlers mutate `event.headers` in place. Set a key to a string to add or override it, or to `null` to delete it.
|
|
665
|
+
|
|
666
|
+
```typescript
|
|
667
|
+
pi.on("before_provider_headers", (event, ctx) => {
|
|
668
|
+
// Add or override — e.g. a session id for gateway tracing/attribution
|
|
669
|
+
event.headers["x-session-id"] = ctx.sessionManager.getSessionId();
|
|
670
|
+
|
|
671
|
+
// Drop a tracking header mcpi adds for this call
|
|
672
|
+
event.headers["X-OpenRouter-Title"] = null;
|
|
673
|
+
});
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
Runs once per provider request; retries reuse the same headers rather than re-firing the hook.
|
|
677
|
+
|
|
582
678
|
#### before_provider_request
|
|
583
679
|
|
|
584
680
|
Fired after the provider-specific payload is built, right before the request is sent. Handlers run in extension load order. Returning `undefined` keeps the payload unchanged. Returning any other value replaces the payload for later handlers and for the actual request.
|
|
585
681
|
|
|
586
|
-
This hook can rewrite provider-level system instructions or remove them entirely. Those payload-level changes are not reflected by `ctx.getSystemPrompt()`, which reports
|
|
682
|
+
This hook can rewrite provider-level system instructions or remove them entirely. Those payload-level changes are not reflected by `ctx.getSystemPrompt()`, which reports mcpi's system prompt string rather than the final serialized provider payload.
|
|
587
683
|
|
|
588
684
|
```typescript
|
|
589
685
|
pi.on("before_provider_request", (event, ctx) => {
|
|
@@ -635,13 +731,28 @@ pi.on("model_select", async (event, ctx) => {
|
|
|
635
731
|
|
|
636
732
|
Use this to update UI elements (status bars, footers) or perform model-specific initialization when the active model changes.
|
|
637
733
|
|
|
734
|
+
#### thinking_level_select
|
|
735
|
+
|
|
736
|
+
Fired when the thinking level changes. This is notification-only; handler return values are ignored.
|
|
737
|
+
|
|
738
|
+
```typescript
|
|
739
|
+
pi.on("thinking_level_select", async (event, ctx) => {
|
|
740
|
+
// event.level - newly selected thinking level
|
|
741
|
+
// event.previousLevel - previous thinking level
|
|
742
|
+
|
|
743
|
+
ctx.ui.setStatus("thinking", `thinking: ${event.level}`);
|
|
744
|
+
});
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
Use this to update extension UI when `pi.setThinkingLevel()`, model changes, or built-in thinking-level controls change the active thinking level.
|
|
748
|
+
|
|
638
749
|
### Tool Events
|
|
639
750
|
|
|
640
751
|
#### tool_call
|
|
641
752
|
|
|
642
753
|
Fired after `tool_execution_start`, before the tool executes. **Can block.** Use `isToolCallEventType` to narrow and get typed inputs.
|
|
643
754
|
|
|
644
|
-
Before `tool_call` runs,
|
|
755
|
+
Before `tool_call` runs, mcpi waits for previously emitted Agent events to finish draining through `AgentSession`. This means `ctx.sessionManager` is up to date through the current assistant tool-calling message.
|
|
645
756
|
|
|
646
757
|
In the default parallel tool execution mode, sibling tool calls from the same assistant message are preflighted sequentially, then executed concurrently. `tool_call` is not guaranteed to see sibling tool results from that same assistant message in `ctx.sessionManager`.
|
|
647
758
|
|
|
@@ -651,10 +762,11 @@ Behavior guarantees:
|
|
|
651
762
|
- Mutations to `event.input` affect the actual tool execution
|
|
652
763
|
- Later `tool_call` handlers see mutations made by earlier handlers
|
|
653
764
|
- No re-validation is performed after your mutation
|
|
654
|
-
- Return values from `tool_call`
|
|
765
|
+
- Return values from `tool_call` control blocking via `{ block: true, reason?: string, terminate?: boolean }`
|
|
766
|
+
- `terminate` only applies to a blocked call; the agent stops early only when every finalized result in the batch is terminating
|
|
655
767
|
|
|
656
768
|
```typescript
|
|
657
|
-
import { isToolCallEventType } from "@
|
|
769
|
+
import { isToolCallEventType } from "@sammorrowdrums/mcpi";
|
|
658
770
|
|
|
659
771
|
pi.on("tool_call", async (event, ctx) => {
|
|
660
772
|
// event.toolName - "bash", "read", "write", "edit", etc.
|
|
@@ -667,7 +779,7 @@ pi.on("tool_call", async (event, ctx) => {
|
|
|
667
779
|
event.input.command = `source ~/.profile\n${event.input.command}`;
|
|
668
780
|
|
|
669
781
|
if (event.input.command.includes("rm -rf")) {
|
|
670
|
-
return { block: true, reason: "Dangerous command" };
|
|
782
|
+
return { block: true, reason: "Dangerous command", terminate: true };
|
|
671
783
|
}
|
|
672
784
|
}
|
|
673
785
|
|
|
@@ -690,7 +802,7 @@ export type MyToolInput = Static<typeof myToolSchema>;
|
|
|
690
802
|
Use `isToolCallEventType` with explicit type parameters:
|
|
691
803
|
|
|
692
804
|
```typescript
|
|
693
|
-
import { isToolCallEventType } from "@
|
|
805
|
+
import { isToolCallEventType } from "@sammorrowdrums/mcpi";
|
|
694
806
|
import type { MyToolInput } from "my-extension";
|
|
695
807
|
|
|
696
808
|
pi.on("tool_call", (event) => {
|
|
@@ -709,16 +821,16 @@ In parallel tool mode, `tool_result` and `tool_execution_end` may interleave in
|
|
|
709
821
|
`tool_result` handlers chain like middleware:
|
|
710
822
|
- Handlers run in extension load order
|
|
711
823
|
- Each handler sees the latest result after previous handler changes
|
|
712
|
-
- Handlers can return partial patches (`content`, `details`, or `
|
|
824
|
+
- Handlers can return partial patches (`content`, `details`, `isError`, or `usage`); omitted fields keep their current values
|
|
713
825
|
|
|
714
826
|
Use `ctx.signal` for nested async work inside the handler. This lets Esc cancel model calls, `fetch()`, and other abort-aware operations started by the extension.
|
|
715
827
|
|
|
716
828
|
```typescript
|
|
717
|
-
import { isBashToolResult } from "@
|
|
829
|
+
import { isBashToolResult } from "@sammorrowdrums/mcpi";
|
|
718
830
|
|
|
719
831
|
pi.on("tool_result", async (event, ctx) => {
|
|
720
832
|
// event.toolName, event.toolCallId, event.input
|
|
721
|
-
// event.content, event.details, event.isError
|
|
833
|
+
// event.content, event.details, event.isError, event.usage
|
|
722
834
|
|
|
723
835
|
if (isBashToolResult(event)) {
|
|
724
836
|
// event.details is typed as BashToolDetails
|
|
@@ -731,7 +843,7 @@ pi.on("tool_result", async (event, ctx) => {
|
|
|
731
843
|
});
|
|
732
844
|
|
|
733
845
|
// Modify result:
|
|
734
|
-
return { content: [...], details: {...}, isError: false };
|
|
846
|
+
return { content: [...], details: {...}, isError: false, usage: nestedModelUsage };
|
|
735
847
|
});
|
|
736
848
|
```
|
|
737
849
|
|
|
@@ -742,7 +854,7 @@ pi.on("tool_result", async (event, ctx) => {
|
|
|
742
854
|
Fired when user executes `!` or `!!` commands. **Can intercept.**
|
|
743
855
|
|
|
744
856
|
```typescript
|
|
745
|
-
import { createLocalBashOperations } from "@
|
|
857
|
+
import { createLocalBashOperations } from "@sammorrowdrums/mcpi";
|
|
746
858
|
|
|
747
859
|
pi.on("user_bash", (event, ctx) => {
|
|
748
860
|
// event.command - the bash command
|
|
@@ -752,7 +864,7 @@ pi.on("user_bash", (event, ctx) => {
|
|
|
752
864
|
// Option 1: Provide custom operations (e.g., SSH)
|
|
753
865
|
return { operations: remoteBashOps };
|
|
754
866
|
|
|
755
|
-
// Option 2: Wrap
|
|
867
|
+
// Option 2: Wrap mcpi's built-in local bash backend
|
|
756
868
|
const local = createLocalBashOperations();
|
|
757
869
|
return {
|
|
758
870
|
operations: {
|
|
@@ -785,6 +897,9 @@ pi.on("input", async (event, ctx) => {
|
|
|
785
897
|
// event.text - raw input (before skill/template expansion)
|
|
786
898
|
// event.images - attached images, if any
|
|
787
899
|
// event.source - "interactive" (typed), "rpc" (API), or "extension" (via sendUserMessage)
|
|
900
|
+
// event.streamingBehavior - "steer" | "followUp" | undefined
|
|
901
|
+
// undefined when idle, "steer" for mid-stream interrupts,
|
|
902
|
+
// "followUp" for messages queued until the agent finishes
|
|
788
903
|
|
|
789
904
|
// Transform: rewrite input before expansion
|
|
790
905
|
if (event.text.startsWith("?quick "))
|
|
@@ -813,7 +928,7 @@ pi.on("input", async (event, ctx) => {
|
|
|
813
928
|
- `transform` - modify text/images, then continue to expansion
|
|
814
929
|
- `handled` - skip agent entirely (first handler to return this wins)
|
|
815
930
|
|
|
816
|
-
Transforms chain across handlers. See [input-transform.ts](../examples/extensions/input-transform.ts).
|
|
931
|
+
Transforms chain across handlers. See [input-transform.ts](../examples/extensions/input-transform.ts) and [input-transform-streaming.ts](../examples/extensions/input-transform-streaming.ts) for `streamingBehavior`-aware routing.
|
|
817
932
|
|
|
818
933
|
## ExtensionContext
|
|
819
934
|
|
|
@@ -823,29 +938,56 @@ All handlers receive `ctx: ExtensionContext`.
|
|
|
823
938
|
|
|
824
939
|
UI methods for user interaction. See [Custom UI](#custom-ui) for full details.
|
|
825
940
|
|
|
941
|
+
### ctx.mode
|
|
942
|
+
|
|
943
|
+
Current run mode: `"tui"`, `"rpc"`, `"json"`, or `"print"`. Use `ctx.mode === "tui"` to guard terminal-only features such as `custom()`, component factories, terminal input, and direct TUI rendering.
|
|
944
|
+
|
|
826
945
|
### ctx.hasUI
|
|
827
946
|
|
|
828
|
-
`false` in print mode (`-p`) and JSON mode.
|
|
947
|
+
`true` in TUI and RPC modes. `false` in print mode (`-p`) and JSON mode. Use this to guard dialog methods (`select`, `confirm`, `input`, `editor`) and fire-and-forget methods (`notify`, `setStatus`, `setWidget`, `setTitle`, `setEditorText`) that work in both TUI and RPC modes. In RPC mode, some TUI-specific methods are no-ops or return defaults (see [rpc.md](rpc.md#extension-ui-protocol)).
|
|
829
948
|
|
|
830
949
|
### ctx.cwd
|
|
831
950
|
|
|
832
951
|
Current working directory.
|
|
833
952
|
|
|
953
|
+
Use `CONFIG_DIR_NAME` instead of hardcoding `.mcpi` when constructing project-local config paths.
|
|
954
|
+
|
|
955
|
+
```typescript
|
|
956
|
+
import { CONFIG_DIR_NAME, type ExtensionAPI } from "@sammorrowdrums/mcpi";
|
|
957
|
+
import { join } from "node:path";
|
|
958
|
+
|
|
959
|
+
export default function (pi: ExtensionAPI) {
|
|
960
|
+
pi.on("session_start", (_event, ctx) => {
|
|
961
|
+
const projectConfigPath = join(ctx.cwd, CONFIG_DIR_NAME, "my-extension.json");
|
|
962
|
+
// ...
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
### ctx.isProjectTrusted()
|
|
968
|
+
|
|
969
|
+
Returns whether project-local trust is active for the current session context. This includes temporary trust decisions and CLI trust overrides, not just saved decisions in the global trust store.
|
|
970
|
+
|
|
971
|
+
Use this before reading project-local extension configuration that should only be honored for trusted projects.
|
|
972
|
+
|
|
834
973
|
### ctx.sessionManager
|
|
835
974
|
|
|
836
|
-
Read-only access to session state. See [
|
|
975
|
+
Read-only access to session state. See [Session Format](session-format.md) for the full SessionManager API and entry types.
|
|
837
976
|
|
|
838
977
|
For `tool_call`, this state is synchronized through the current assistant message before handlers run. In parallel tool execution mode it is still not guaranteed to include sibling tool results from the same assistant message.
|
|
839
978
|
|
|
840
979
|
```typescript
|
|
841
|
-
ctx.sessionManager.getEntries()
|
|
842
|
-
ctx.sessionManager.getBranch()
|
|
843
|
-
ctx.sessionManager.
|
|
980
|
+
ctx.sessionManager.getEntries() // All entries
|
|
981
|
+
ctx.sessionManager.getBranch() // Current branch
|
|
982
|
+
ctx.sessionManager.buildContextEntries() // Active branch entries with compaction applied
|
|
983
|
+
ctx.sessionManager.getLeafId() // Current leaf entry ID
|
|
844
984
|
```
|
|
845
985
|
|
|
846
|
-
### ctx.modelRegistry / ctx.model
|
|
986
|
+
### ctx.modelRegistry / ctx.model / ctx.thinkingLevel / ctx.scopedModels
|
|
987
|
+
|
|
988
|
+
Access to models, providers, and resolved authentication. `ctx.modelRegistry.getProvider(id)` returns the effective pi-ai provider, while `getProviderAuth(id)` resolves its current API key, headers, base URL, and provider-scoped environment without requiring a loaded model. `ctx.model` is the active model, and `ctx.thinkingLevel` is its current effective thinking level.
|
|
847
989
|
|
|
848
|
-
|
|
990
|
+
`ctx.scopedModels` is the read-only list of models scoped to the current session — the same set the `/scoped-models` command shows. It is resolved at session start from the `--models` CLI flag and the `enabledModels` setting (matched against the available catalogue with minimatch on `provider/modelId` or a bare `modelId`). It is empty when no scoping is configured, meaning every available model is usable. Each entry is `{ model, thinkingLevel? }`, where `thinkingLevel` is set only when a pattern pinned it (e.g. `anthropic/*:high`). Use it to populate a model picker that mirrors the built-in one instead of enumerating the whole catalogue via `ctx.modelRegistry.getAvailable()`.
|
|
849
991
|
|
|
850
992
|
### ctx.signal
|
|
851
993
|
|
|
@@ -857,7 +999,7 @@ Use this for abort-aware nested work started by extension handlers, for example:
|
|
|
857
999
|
- file or process helpers that accept `AbortSignal`
|
|
858
1000
|
|
|
859
1001
|
`ctx.signal` is typically defined during active turn events such as `tool_call`, `tool_result`, `message_update`, and `turn_end`.
|
|
860
|
-
It is usually `undefined` in idle or non-turn contexts such as session events, extension commands, and shortcuts fired while
|
|
1002
|
+
It is usually `undefined` in idle or non-turn contexts such as session events, extension commands, and shortcuts fired while mcpi is idle.
|
|
861
1003
|
|
|
862
1004
|
```typescript
|
|
863
1005
|
pi.on("tool_result", async (event, ctx) => {
|
|
@@ -874,11 +1016,11 @@ pi.on("tool_result", async (event, ctx) => {
|
|
|
874
1016
|
|
|
875
1017
|
### ctx.isIdle() / ctx.abort() / ctx.hasPendingMessages()
|
|
876
1018
|
|
|
877
|
-
Control flow helpers.
|
|
1019
|
+
Control flow helpers. `ctx.isIdle()` is false while mcpi is processing an agent run, automatic retry, auto-compaction retry, or queued continuation.
|
|
878
1020
|
|
|
879
1021
|
### ctx.shutdown()
|
|
880
1022
|
|
|
881
|
-
Request a graceful shutdown of
|
|
1023
|
+
Request a graceful shutdown of mcpi.
|
|
882
1024
|
|
|
883
1025
|
- **Interactive mode:** Deferred until the agent becomes idle (after processing all queued steering and follow-up messages).
|
|
884
1026
|
- **RPC mode:** Deferred until the next idle state (after completing the current command response, when waiting for the next command).
|
|
@@ -923,7 +1065,7 @@ ctx.compact({
|
|
|
923
1065
|
|
|
924
1066
|
### ctx.getSystemPrompt()
|
|
925
1067
|
|
|
926
|
-
Returns
|
|
1068
|
+
Returns mcpi's current system prompt string.
|
|
927
1069
|
|
|
928
1070
|
- During `before_agent_start`, this reflects chained system-prompt changes made so far for the current turn.
|
|
929
1071
|
- It does not include later `context` message mutations.
|
|
@@ -941,9 +1083,22 @@ pi.on("before_agent_start", (event, ctx) => {
|
|
|
941
1083
|
|
|
942
1084
|
Command handlers receive `ExtensionCommandContext`, which extends `ExtensionContext` with session control methods. These are only available in commands because they can deadlock if called from event handlers.
|
|
943
1085
|
|
|
1086
|
+
### ctx.getSystemPromptOptions()
|
|
1087
|
+
|
|
1088
|
+
Returns the base inputs mcpi currently uses to build the system prompt.
|
|
1089
|
+
|
|
1090
|
+
```typescript
|
|
1091
|
+
const options = ctx.getSystemPromptOptions();
|
|
1092
|
+
const contextPaths = options.contextFiles?.map((file) => file.path) ?? [];
|
|
1093
|
+
```
|
|
1094
|
+
|
|
1095
|
+
This has the same shape and mutability as `before_agent_start` `event.systemPromptOptions`: custom prompt, active tools, tool snippets, prompt guidelines, appended system prompt text, cwd, loaded context files, and loaded skills. It may include full context file contents, so treat it as sensitive extension-local data and avoid exposing it through command lists, logs, or autocomplete metadata.
|
|
1096
|
+
|
|
1097
|
+
This reports the current base prompt inputs. It does not include per-turn `before_agent_start` chained system-prompt changes, later `context` event message mutations, or `before_provider_request` payload rewrites.
|
|
1098
|
+
|
|
944
1099
|
### ctx.waitForIdle()
|
|
945
1100
|
|
|
946
|
-
Wait for the agent to
|
|
1101
|
+
Wait for the agent to fully settle, including automatic retries, auto-compaction retries, and queued continuations:
|
|
947
1102
|
|
|
948
1103
|
```typescript
|
|
949
1104
|
pi.registerCommand("my-cmd", {
|
|
@@ -1053,7 +1208,7 @@ Options:
|
|
|
1053
1208
|
To discover available sessions, use the static `SessionManager.list()` or `SessionManager.listAll()` methods:
|
|
1054
1209
|
|
|
1055
1210
|
```typescript
|
|
1056
|
-
import { SessionManager } from "@
|
|
1211
|
+
import { SessionManager } from "@sammorrowdrums/mcpi";
|
|
1057
1212
|
|
|
1058
1213
|
pi.registerCommand("switch", {
|
|
1059
1214
|
description: "Switch to another session",
|
|
@@ -1124,7 +1279,7 @@ Run the same reload flow as `/reload`.
|
|
|
1124
1279
|
|
|
1125
1280
|
```typescript
|
|
1126
1281
|
pi.registerCommand("reload-runtime", {
|
|
1127
|
-
description: "Reload extensions, skills, prompts, and
|
|
1282
|
+
description: "Reload extensions, skills, prompts, themes, and context files",
|
|
1128
1283
|
handler: async (_args, ctx) => {
|
|
1129
1284
|
await ctx.reload();
|
|
1130
1285
|
return;
|
|
@@ -1147,12 +1302,12 @@ Tools run with `ExtensionContext`, so they cannot call `ctx.reload()` directly.
|
|
|
1147
1302
|
Example tool the LLM can call to trigger reload:
|
|
1148
1303
|
|
|
1149
1304
|
```typescript
|
|
1150
|
-
import type { ExtensionAPI } from "@
|
|
1305
|
+
import type { ExtensionAPI } from "@sammorrowdrums/mcpi";
|
|
1151
1306
|
import { Type } from "typebox";
|
|
1152
1307
|
|
|
1153
1308
|
export default function (pi: ExtensionAPI) {
|
|
1154
1309
|
pi.registerCommand("reload-runtime", {
|
|
1155
|
-
description: "Reload extensions, skills, prompts, and
|
|
1310
|
+
description: "Reload extensions, skills, prompts, themes, and context files",
|
|
1156
1311
|
handler: async (_args, ctx) => {
|
|
1157
1312
|
await ctx.reload();
|
|
1158
1313
|
return;
|
|
@@ -1162,7 +1317,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1162
1317
|
pi.registerTool({
|
|
1163
1318
|
name: "reload_runtime",
|
|
1164
1319
|
label: "Reload Runtime",
|
|
1165
|
-
description: "Reload extensions, skills, prompts, and
|
|
1320
|
+
description: "Reload extensions, skills, prompts, themes, and context files",
|
|
1166
1321
|
parameters: Type.Object({}),
|
|
1167
1322
|
async execute() {
|
|
1168
1323
|
pi.sendUserMessage("/reload-runtime", { deliverAs: "followUp" });
|
|
@@ -1196,7 +1351,7 @@ See [dynamic-tools.ts](../examples/extensions/dynamic-tools.ts) for a full examp
|
|
|
1196
1351
|
|
|
1197
1352
|
```typescript
|
|
1198
1353
|
import { Type } from "typebox";
|
|
1199
|
-
import { StringEnum } from "@
|
|
1354
|
+
import { StringEnum } from "@sammorrowdrums/mcpi-ai";
|
|
1200
1355
|
|
|
1201
1356
|
pi.registerTool({
|
|
1202
1357
|
name: "my_tool",
|
|
@@ -1233,7 +1388,7 @@ pi.registerTool({
|
|
|
1233
1388
|
|
|
1234
1389
|
### pi.sendMessage(message, options?)
|
|
1235
1390
|
|
|
1236
|
-
Inject a custom message into the session.
|
|
1391
|
+
Inject a custom message into the session. Custom messages participate in LLM context. For durable TUI-only content that should not be sent to the LLM, use [`pi.appendEntry()`](#piappendentrycustomtype-data) with [`pi.registerEntryRenderer()`](#piregisterentryrenderercustomtype-renderer).
|
|
1237
1392
|
|
|
1238
1393
|
```typescript
|
|
1239
1394
|
pi.sendMessage({
|
|
@@ -1271,12 +1426,16 @@ pi.sendUserMessage([
|
|
|
1271
1426
|
// During streaming - must specify delivery mode
|
|
1272
1427
|
pi.sendUserMessage("Focus on error handling", { deliverAs: "steer" });
|
|
1273
1428
|
pi.sendUserMessage("And then summarize", { deliverAs: "followUp" });
|
|
1429
|
+
|
|
1430
|
+
// Opt in to extension command dispatch and skill/prompt template expansion
|
|
1431
|
+
pi.sendUserMessage("/review src/index.ts", { expandPromptTemplates: true });
|
|
1274
1432
|
```
|
|
1275
1433
|
|
|
1276
1434
|
**Options:**
|
|
1277
1435
|
- `deliverAs` - Required when agent is streaming:
|
|
1278
1436
|
- `"steer"` - Queues the message for delivery after the current assistant turn finishes executing its tool calls
|
|
1279
1437
|
- `"followUp"` - Waits for agent to finish all tools
|
|
1438
|
+
- `expandPromptTemplates` - Dispatch extension commands and expand skill commands and prompt templates. Defaults to `false`.
|
|
1280
1439
|
|
|
1281
1440
|
When not streaming, the message is sent immediately and triggers a new turn. When streaming without `deliverAs`, throws an error.
|
|
1282
1441
|
|
|
@@ -1284,10 +1443,11 @@ See [send-user-message.ts](../examples/extensions/send-user-message.ts) for a co
|
|
|
1284
1443
|
|
|
1285
1444
|
### pi.appendEntry(customType, data?)
|
|
1286
1445
|
|
|
1287
|
-
Persist extension
|
|
1446
|
+
Persist extension data. Custom entries do NOT participate in LLM context. In interactive mode, they can also render inside the chat transcript when paired with `pi.registerEntryRenderer()`.
|
|
1288
1447
|
|
|
1289
1448
|
```typescript
|
|
1290
1449
|
pi.appendEntry("my-state", { count: 42 });
|
|
1450
|
+
pi.appendEntry("status-card", { title: "Indexed files", count: 17 });
|
|
1291
1451
|
|
|
1292
1452
|
// Restore on reload
|
|
1293
1453
|
pi.on("session_start", async (_event, ctx) => {
|
|
@@ -1339,7 +1499,7 @@ Labels persist in the session and survive restarts. Use them to mark important p
|
|
|
1339
1499
|
|
|
1340
1500
|
Register a command.
|
|
1341
1501
|
|
|
1342
|
-
If multiple extensions register the same command name,
|
|
1502
|
+
If multiple extensions register the same command name, mcpi keeps them all and assigns numeric invocation suffixes in load order, for example `/review:1` and `/review:2`.
|
|
1343
1503
|
|
|
1344
1504
|
```typescript
|
|
1345
1505
|
pi.registerCommand("stats", {
|
|
@@ -1354,7 +1514,7 @@ pi.registerCommand("stats", {
|
|
|
1354
1514
|
Optional: add argument auto-completion for `/command ...`:
|
|
1355
1515
|
|
|
1356
1516
|
```typescript
|
|
1357
|
-
import type { AutocompleteItem } from "@
|
|
1517
|
+
import type { AutocompleteItem } from "@sammorrowdrums/mcpi-tui";
|
|
1358
1518
|
|
|
1359
1519
|
pi.registerCommand("deploy", {
|
|
1360
1520
|
description: "Deploy to an environment",
|
|
@@ -1405,7 +1565,48 @@ mode and would not execute if sent via `prompt`.
|
|
|
1405
1565
|
|
|
1406
1566
|
### pi.registerMessageRenderer(customType, renderer)
|
|
1407
1567
|
|
|
1408
|
-
Register a custom TUI renderer for messages with your `customType`. See [Custom UI](#custom-ui).
|
|
1568
|
+
Register a custom TUI renderer for custom messages with your `customType`. Custom messages are created with `pi.sendMessage()` and participate in LLM context. See [Custom UI](#custom-ui).
|
|
1569
|
+
|
|
1570
|
+
### pi.registerMarkdownTransformer(transformer)
|
|
1571
|
+
|
|
1572
|
+
Register a transformer for the Markdown in normal user text, assistant text, and thinking blocks. Transformers run in extension load order, and each transformer receives the Markdown returned by the previous transformer. After the chain finishes, mcpi renders the transformed content with its built-in renderer.
|
|
1573
|
+
|
|
1574
|
+
The transformer receives the Markdown string and a context with:
|
|
1575
|
+
|
|
1576
|
+
- `messageType` — `"user"`, `"assistant"`, or `"assistant-thinking"`
|
|
1577
|
+
- `isStreaming` — `true` for partial assistant updates; `false` for user, finalized assistant, and restored messages
|
|
1578
|
+
- `availableWidth` — exact terminal columns available for the transformed Markdown content
|
|
1579
|
+
|
|
1580
|
+
Return the transformed Markdown:
|
|
1581
|
+
|
|
1582
|
+
```typescript
|
|
1583
|
+
pi.registerMarkdownTransformer((markdown, { messageType, isStreaming }) => {
|
|
1584
|
+
if (isStreaming || messageType === "assistant-thinking") return markdown;
|
|
1585
|
+
return markdown.replaceAll("-->", "→");
|
|
1586
|
+
});
|
|
1587
|
+
```
|
|
1588
|
+
|
|
1589
|
+
If a transformer throws, mcpi keeps the Markdown produced so far and continues with the next transformer. The hook is display-only: the original message remains unchanged in the session and model context. It runs for new user messages, assistant streaming updates, restored session messages, and terminal width changes, so transformers should remain synchronous and inexpensive.
|
|
1590
|
+
|
|
1591
|
+
### pi.registerEntryRenderer(customType, renderer)
|
|
1592
|
+
|
|
1593
|
+
Register a custom TUI renderer for custom entries with your `customType`. Custom entries are created with `pi.appendEntry()` and do not participate in LLM context.
|
|
1594
|
+
|
|
1595
|
+
```typescript
|
|
1596
|
+
import { Box, Text } from "@sammorrowdrums/mcpi-tui";
|
|
1597
|
+
|
|
1598
|
+
pi.registerEntryRenderer("status-card", (entry, { expanded }, theme) => {
|
|
1599
|
+
const data = entry.data as { title: string; count: number };
|
|
1600
|
+
const box = new Box(1, 1, (text) => theme.bg("customMessageBg", text));
|
|
1601
|
+
box.addChild(new Text(`${theme.bold(data.title)}: ${data.count}`));
|
|
1602
|
+
if (expanded) {
|
|
1603
|
+
box.addChild(new Text(theme.fg("dim", JSON.stringify(data, null, 2))));
|
|
1604
|
+
}
|
|
1605
|
+
return box;
|
|
1606
|
+
});
|
|
1607
|
+
|
|
1608
|
+
pi.appendEntry("status-card", { title: "Indexed files", count: 17 });
|
|
1609
|
+
```
|
|
1409
1610
|
|
|
1410
1611
|
### pi.registerShortcut(shortcut, options)
|
|
1411
1612
|
|
|
@@ -1432,7 +1633,7 @@ pi.registerFlag("plan", {
|
|
|
1432
1633
|
});
|
|
1433
1634
|
|
|
1434
1635
|
// Check value
|
|
1435
|
-
if (pi.getFlag("
|
|
1636
|
+
if (pi.getFlag("plan")) {
|
|
1436
1637
|
// Plan mode enabled
|
|
1437
1638
|
}
|
|
1438
1639
|
```
|
|
@@ -1446,26 +1647,68 @@ const result = await pi.exec("git", ["status"], { signal, timeout: 5000 });
|
|
|
1446
1647
|
// result.stdout, result.stderr, result.code, result.killed
|
|
1447
1648
|
```
|
|
1448
1649
|
|
|
1650
|
+
Pass `env` to set variables for a single call. Values set this way take precedence over the session
|
|
1651
|
+
environment described below:
|
|
1652
|
+
|
|
1653
|
+
```typescript
|
|
1654
|
+
await pi.exec("npm", ["test"], { env: { CI: "1" } });
|
|
1655
|
+
```
|
|
1656
|
+
|
|
1657
|
+
### Session Environment
|
|
1658
|
+
|
|
1659
|
+
#### pi.setEnv(key, value) / pi.unsetEnv(key)
|
|
1660
|
+
|
|
1661
|
+
Set environment variables for every subprocess mcpi spawns for the rest of the session. This covers
|
|
1662
|
+
both the LLM-callable bash tool and `pi.exec()`.
|
|
1663
|
+
|
|
1664
|
+
```typescript
|
|
1665
|
+
export default function (pi) {
|
|
1666
|
+
pi.setEnv("NO_COLOR", "1");
|
|
1667
|
+
pi.setEnv("MY_TOOL_TOKEN", token);
|
|
1668
|
+
}
|
|
1669
|
+
```
|
|
1670
|
+
|
|
1671
|
+
`pi.unsetEnv(key)` masks a variable so spawned commands do not see it. It removes a value set by
|
|
1672
|
+
`pi.setEnv()` *and* hides a variable mcpi itself inherited:
|
|
1673
|
+
|
|
1674
|
+
```typescript
|
|
1675
|
+
pi.unsetEnv("GITHUB_TOKEN"); // Not visible to bash commands or pi.exec()
|
|
1676
|
+
```
|
|
1677
|
+
|
|
1678
|
+
Semantics:
|
|
1679
|
+
|
|
1680
|
+
- The session environment is **shared by all extensions** and applies for the lifetime of the
|
|
1681
|
+
session. Later writes win.
|
|
1682
|
+
- mcpi's own `process.env` is **never** modified, so masking a variable does not affect mcpi itself or
|
|
1683
|
+
anything outside the spawned command.
|
|
1684
|
+
- Precedence is: per-call `pi.exec({ env })` > session environment > variables mcpi inherited.
|
|
1685
|
+
- Session metadata (`MCPI_SESSION_ID`, `MCPI_MODEL`, and friends) is injected first, so `pi.setEnv()`
|
|
1686
|
+
can override it and `pi.unsetEnv()` can hide it. See
|
|
1687
|
+
[environment-variables.md](environment-variables.md).
|
|
1688
|
+
- Values are applied when each command starts, so calling `pi.setEnv()` from an event handler
|
|
1689
|
+
affects the next command without a restart.
|
|
1690
|
+
|
|
1449
1691
|
### pi.getActiveTools() / pi.getAllTools() / pi.setActiveTools(names)
|
|
1450
1692
|
|
|
1451
|
-
Manage active tools. This works for both built-in tools and dynamically registered tools.
|
|
1693
|
+
Manage active tools. This works for both built-in tools and dynamically registered tools. `pi.getActiveTools()` returns the active tool names as `string[]`; `pi.getAllTools()` returns metadata for all configured tools.
|
|
1452
1694
|
|
|
1453
1695
|
```typescript
|
|
1454
|
-
const active = pi.getActiveTools();
|
|
1696
|
+
const active = pi.getActiveTools(); // ["read", "bash", ...]
|
|
1455
1697
|
const all = pi.getAllTools();
|
|
1456
|
-
// [{
|
|
1698
|
+
// all = [{
|
|
1457
1699
|
// name: "read",
|
|
1458
1700
|
// description: "Read file contents...",
|
|
1459
|
-
// parameters: ...,
|
|
1701
|
+
// parameters: ...,
|
|
1702
|
+
// promptGuidelines: ["Use read to examine files instead of cat or sed."],
|
|
1460
1703
|
// sourceInfo: { path: "<builtin:read>", source: "builtin", scope: "temporary", origin: "top-level" }
|
|
1461
1704
|
// }, ...]
|
|
1462
|
-
const names = all.map(t => t.name);
|
|
1463
1705
|
const builtinTools = all.filter((t) => t.sourceInfo.source === "builtin");
|
|
1464
1706
|
const extensionTools = all.filter((t) => t.sourceInfo.source !== "builtin" && t.sourceInfo.source !== "sdk");
|
|
1707
|
+
pi.setActiveTools([...new Set([...active, "my_custom_tool"])]); // Keep current tools and enable my_custom_tool
|
|
1465
1708
|
pi.setActiveTools(["read", "bash"]); // Switch to read-only
|
|
1466
1709
|
```
|
|
1467
1710
|
|
|
1468
|
-
`pi.getAllTools()` returns `name`, `description`, `parameters`, and `sourceInfo`.
|
|
1711
|
+
`pi.getAllTools()` returns `name`, `description`, `parameters`, `promptGuidelines`, and `sourceInfo`.
|
|
1469
1712
|
|
|
1470
1713
|
Typical `sourceInfo.source` values:
|
|
1471
1714
|
- `builtin` for built-in tools
|
|
@@ -1488,10 +1731,10 @@ if (model) {
|
|
|
1488
1731
|
|
|
1489
1732
|
### pi.getThinkingLevel() / pi.setThinkingLevel(level)
|
|
1490
1733
|
|
|
1491
|
-
Get or set the thinking level. Level is clamped to model capabilities (non-reasoning models always use "off").
|
|
1734
|
+
Get or set the thinking level. Level is clamped to model capabilities (non-reasoning models always use "off"). Changes emit `thinking_level_select`.
|
|
1492
1735
|
|
|
1493
1736
|
```typescript
|
|
1494
|
-
const current = pi.getThinkingLevel(); // "off" | "minimal" | "low" | "medium" | "high" | "xhigh"
|
|
1737
|
+
const current = pi.getThinkingLevel(); // "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"
|
|
1495
1738
|
pi.setThinkingLevel("high");
|
|
1496
1739
|
```
|
|
1497
1740
|
|
|
@@ -1510,13 +1753,46 @@ Register or override a model provider dynamically. Useful for proxies, custom en
|
|
|
1510
1753
|
|
|
1511
1754
|
Calls made during the extension factory function are queued and applied once the runner initialises. Calls made after that — for example from a command handler following a user setup flow — take effect immediately without requiring a `/reload`.
|
|
1512
1755
|
|
|
1513
|
-
|
|
1756
|
+
Dynamic providers can implement `refreshModels`. mcpi calls it during model refresh, publishes the returned list synchronously through the provider, and passes the canonical credential/stored-catalog/network/signal context. The extension decides whether to persist catalog metadata through generation-checked `context.publish({ persist: entry })`; live servers such as llama.cpp can return models without persisting them.
|
|
1757
|
+
|
|
1758
|
+
`context.signal` is always a concrete signal and provider callbacks must pass it to blocking I/O. Public `ModelRuntime.refresh()` and `ModelRegistry.refresh()` calls accept an optional signal and are unbounded when it is omitted; extensions and applications choose their own deadlines. Cancellation stops the caller waiting even if a provider ignores the signal, but cooperation is still required to stop the underlying work.
|
|
1759
|
+
|
|
1760
|
+
Extensions that need native provider auth, filtering, refresh, or stream behavior can register a complete `Provider` from `@sammorrowdrums/mcpi-ai`. The provider becomes the composition base and `models.json` overrides still apply above it.
|
|
1514
1761
|
|
|
1515
1762
|
```typescript
|
|
1763
|
+
import { createProvider, openAICompletionsApi } from "@sammorrowdrums/mcpi-ai";
|
|
1764
|
+
|
|
1765
|
+
const provider = createProvider({
|
|
1766
|
+
id: "local-server",
|
|
1767
|
+
name: "Local Server",
|
|
1768
|
+
baseUrl: "http://localhost:8080/v1",
|
|
1769
|
+
auth: {
|
|
1770
|
+
apiKey: {
|
|
1771
|
+
name: "Local server setup",
|
|
1772
|
+
async login(interaction) {
|
|
1773
|
+
return {
|
|
1774
|
+
type: "api_key",
|
|
1775
|
+
key: await interaction.prompt({ type: "secret", message: "API key" }),
|
|
1776
|
+
};
|
|
1777
|
+
},
|
|
1778
|
+
async resolve({ credential }) {
|
|
1779
|
+
return credential?.key
|
|
1780
|
+
? { auth: { apiKey: credential.key }, source: "stored API key" }
|
|
1781
|
+
: undefined;
|
|
1782
|
+
},
|
|
1783
|
+
},
|
|
1784
|
+
},
|
|
1785
|
+
models: [],
|
|
1786
|
+
api: openAICompletionsApi(),
|
|
1787
|
+
});
|
|
1788
|
+
|
|
1789
|
+
pi.registerProvider(provider);
|
|
1790
|
+
|
|
1516
1791
|
// Register a new provider with custom models
|
|
1517
1792
|
pi.registerProvider("my-proxy", {
|
|
1793
|
+
name: "My Proxy",
|
|
1518
1794
|
baseUrl: "https://proxy.example.com",
|
|
1519
|
-
apiKey: "PROXY_API_KEY", // env var
|
|
1795
|
+
apiKey: "$PROXY_API_KEY", // env var reference
|
|
1520
1796
|
api: "anthropic-messages",
|
|
1521
1797
|
models: [
|
|
1522
1798
|
{
|
|
@@ -1531,6 +1807,26 @@ pi.registerProvider("my-proxy", {
|
|
|
1531
1807
|
]
|
|
1532
1808
|
});
|
|
1533
1809
|
|
|
1810
|
+
// Register a live llama.cpp catalog without persisting discovered models
|
|
1811
|
+
pi.registerProvider("llama.cpp", {
|
|
1812
|
+
baseUrl: "http://localhost:8080/v1",
|
|
1813
|
+
apiKey: "local",
|
|
1814
|
+
api: "openai-completions",
|
|
1815
|
+
async refreshModels({ signal }) {
|
|
1816
|
+
const response = await fetch("http://localhost:8080/v1/models", { signal });
|
|
1817
|
+
const { data } = await response.json();
|
|
1818
|
+
return data.map(({ id }) => ({
|
|
1819
|
+
id,
|
|
1820
|
+
name: id,
|
|
1821
|
+
reasoning: false,
|
|
1822
|
+
input: ["text"],
|
|
1823
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
1824
|
+
contextWindow: 128000,
|
|
1825
|
+
maxTokens: 16384
|
|
1826
|
+
}));
|
|
1827
|
+
}
|
|
1828
|
+
});
|
|
1829
|
+
|
|
1534
1830
|
// Override baseUrl for an existing provider (keeps all models)
|
|
1535
1831
|
pi.registerProvider("anthropic", {
|
|
1536
1832
|
baseUrl: "https://proxy.example.com"
|
|
@@ -1549,7 +1845,8 @@ pi.registerProvider("corporate-ai", {
|
|
|
1549
1845
|
const code = await callbacks.onPrompt({ message: "Enter code:" });
|
|
1550
1846
|
return { refresh: code, access: code, expires: Date.now() + 3600000 };
|
|
1551
1847
|
},
|
|
1552
|
-
async refreshToken(credentials) {
|
|
1848
|
+
async refreshToken(credentials, signal) {
|
|
1849
|
+
signal.throwIfAborted();
|
|
1553
1850
|
// Refresh logic
|
|
1554
1851
|
return credentials;
|
|
1555
1852
|
},
|
|
@@ -1560,13 +1857,17 @@ pi.registerProvider("corporate-ai", {
|
|
|
1560
1857
|
});
|
|
1561
1858
|
```
|
|
1562
1859
|
|
|
1563
|
-
|
|
1860
|
+
The object form accepts a complete pi-ai `Provider`, including native `auth`, `getModels`, `refreshModels`, `filterModels`, `stream`, and `streamSimple` behavior.
|
|
1861
|
+
|
|
1862
|
+
**Legacy config options:**
|
|
1863
|
+
- `name` - Display name for the provider in UI such as `/login`.
|
|
1564
1864
|
- `baseUrl` - API endpoint URL. Required when defining models.
|
|
1565
|
-
- `apiKey` - API key
|
|
1865
|
+
- `apiKey` - API key literal, environment interpolation (`$ENV_VAR` or `${ENV_VAR}`), or leading `!command`. Required when defining models (unless `oauth` provided). `$$` escapes `$`, and `$!` escapes a literal `!` without triggering command execution.
|
|
1566
1866
|
- `api` - API type: `"anthropic-messages"`, `"openai-completions"`, `"openai-responses"`, etc.
|
|
1567
1867
|
- `headers` - Custom headers to include in requests.
|
|
1568
1868
|
- `authHeader` - If true, adds `Authorization: Bearer` header automatically.
|
|
1569
|
-
- `models` - Array of model definitions. If provided, replaces all existing models for this provider.
|
|
1869
|
+
- `models` - Array of model definitions. If provided, replaces all existing models for this provider. Model definitions can set `baseUrl` to override the provider endpoint for that model.
|
|
1870
|
+
- `refreshModels` - Async dynamic discovery callback. Its returned models replace extension-provided models. `context.stored` contains the persisted provider snapshot; use generation-checked `context.publish({ persist: entry })` only when updated catalog data should persist. Use `persist: null` to delete that snapshot.
|
|
1570
1871
|
- `oauth` - OAuth provider config for `/login` support. When provided, the provider appears in the login menu.
|
|
1571
1872
|
- `streamSimple` - Custom streaming implementation for non-standard APIs.
|
|
1572
1873
|
|
|
@@ -1642,7 +1943,7 @@ Pass the real target file path to `withFileMutationQueue()`, not the raw user ar
|
|
|
1642
1943
|
Queue the entire mutation window on that target path. That includes read-modify-write logic, not just the final write.
|
|
1643
1944
|
|
|
1644
1945
|
```typescript
|
|
1645
|
-
import { withFileMutationQueue } from "@
|
|
1946
|
+
import { withFileMutationQueue } from "@sammorrowdrums/mcpi";
|
|
1646
1947
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
1647
1948
|
import { dirname, resolve } from "node:path";
|
|
1648
1949
|
|
|
@@ -1667,8 +1968,8 @@ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
|
1667
1968
|
|
|
1668
1969
|
```typescript
|
|
1669
1970
|
import { Type } from "typebox";
|
|
1670
|
-
import { StringEnum } from "@
|
|
1671
|
-
import { Text } from "@
|
|
1971
|
+
import { StringEnum } from "@sammorrowdrums/mcpi-ai";
|
|
1972
|
+
import { Text } from "@sammorrowdrums/mcpi-tui";
|
|
1672
1973
|
|
|
1673
1974
|
pi.registerTool({
|
|
1674
1975
|
name: "my_tool",
|
|
@@ -1710,6 +2011,7 @@ pi.registerTool({
|
|
|
1710
2011
|
return {
|
|
1711
2012
|
content: [{ type: "text", text: "Done" }], // Sent to LLM
|
|
1712
2013
|
details: { data: result }, // For rendering & state
|
|
2014
|
+
// usage: nestedModelResponse.usage, // Optional nested LLM usage
|
|
1713
2015
|
// Optional: stop after this tool batch when every finalized tool result
|
|
1714
2016
|
// in the batch also returns terminate: true.
|
|
1715
2017
|
terminate: true,
|
|
@@ -1722,6 +2024,8 @@ pi.registerTool({
|
|
|
1722
2024
|
});
|
|
1723
2025
|
```
|
|
1724
2026
|
|
|
2027
|
+
**Usage accounting:** If a tool makes nested LLM calls, return their combined `Usage` as `usage`. mcpi persists it on the tool result and includes it in footer, `/session`, and RPC session totals. `tool_result` handlers can inspect or replace this value.
|
|
2028
|
+
|
|
1725
2029
|
**Signaling errors:** To mark a tool execution as failed (sets `isError: true` on the result and reports it to the LLM), throw an error from `execute`. Returning a value never sets the error flag regardless of what properties you include in the return object.
|
|
1726
2030
|
|
|
1727
2031
|
**Early termination:** Return `terminate: true` from `execute()` to hint that the automatic follow-up LLM call should be skipped after the current tool batch. This only takes effect when every finalized tool result in that batch is terminating. See [examples/extensions/structured-output.ts](../examples/extensions/structured-output.ts) for a minimal example where the agent ends on a final structured-output tool call.
|
|
@@ -1736,9 +2040,9 @@ async execute(toolCallId, params) {
|
|
|
1736
2040
|
}
|
|
1737
2041
|
```
|
|
1738
2042
|
|
|
1739
|
-
**Important:** Use `StringEnum` from `@
|
|
2043
|
+
**Important:** Use `StringEnum` from `@sammorrowdrums/mcpi-ai` for string enums. `Type.Union`/`Type.Literal` doesn't work with Google's API.
|
|
1740
2044
|
|
|
1741
|
-
**Argument preparation:** `prepareArguments(args)` is optional. If defined, it runs before schema validation and before `execute()`. Use it to mimic an older accepted input shape when
|
|
2045
|
+
**Argument preparation:** `prepareArguments(args)` is optional. If defined, it runs before schema validation and before `execute()`. Use it to mimic an older accepted input shape when mcpi resumes an older session whose stored tool call arguments no longer match the current schema. Return the object you want validated against `parameters`. Keep the public schema strict. Do not add deprecated compatibility fields to `parameters` just to keep old resumed sessions working.
|
|
1742
2046
|
|
|
1743
2047
|
Example: an older session may contain an `edit` tool call with top-level `oldText` and `newText`, while the current schema only accepts `edits: [{ oldText, newText }]`.
|
|
1744
2048
|
|
|
@@ -1791,13 +2095,13 @@ Extensions can override built-in tools (`read`, `bash`, `edit`, `write`, `grep`,
|
|
|
1791
2095
|
|
|
1792
2096
|
```bash
|
|
1793
2097
|
# Extension's read tool replaces built-in read
|
|
1794
|
-
|
|
2098
|
+
mcpi -e ./tool-override.ts
|
|
1795
2099
|
```
|
|
1796
2100
|
|
|
1797
2101
|
Alternatively, use `--no-builtin-tools` to start without any built-in tools while keeping extension tools enabled:
|
|
1798
2102
|
```bash
|
|
1799
2103
|
# No built-in tools, only extension tools
|
|
1800
|
-
|
|
2104
|
+
mcpi --no-builtin-tools -e ./my-extension.ts
|
|
1801
2105
|
```
|
|
1802
2106
|
|
|
1803
2107
|
See [examples/extensions/tool-override.ts](../examples/extensions/tool-override.ts) for a complete example that overrides `read` with logging and access control.
|
|
@@ -1809,20 +2113,20 @@ See [examples/extensions/tool-override.ts](../examples/extensions/tool-override.
|
|
|
1809
2113
|
**Your implementation must match the exact result shape**, including the `details` type. The UI and session logic depend on these shapes for rendering and state tracking.
|
|
1810
2114
|
|
|
1811
2115
|
Built-in tool implementations:
|
|
1812
|
-
- [read.ts](https://github.com/
|
|
1813
|
-
- [bash.ts](https://github.com/
|
|
1814
|
-
- [edit.ts](https://github.com/
|
|
1815
|
-
- [write.ts](https://github.com/
|
|
1816
|
-
- [grep.ts](https://github.com/
|
|
1817
|
-
- [find.ts](https://github.com/
|
|
1818
|
-
- [ls.ts](https://github.com/
|
|
2116
|
+
- [read.ts](https://github.com/SamMorrowDrums/mcpi/blob/main/packages/coding-agent/src/core/tools/read.ts) - `ReadToolDetails`
|
|
2117
|
+
- [bash.ts](https://github.com/SamMorrowDrums/mcpi/blob/main/packages/coding-agent/src/core/tools/bash.ts) - `BashToolDetails`
|
|
2118
|
+
- [edit.ts](https://github.com/SamMorrowDrums/mcpi/blob/main/packages/coding-agent/src/core/tools/edit.ts)
|
|
2119
|
+
- [write.ts](https://github.com/SamMorrowDrums/mcpi/blob/main/packages/coding-agent/src/core/tools/write.ts)
|
|
2120
|
+
- [grep.ts](https://github.com/SamMorrowDrums/mcpi/blob/main/packages/coding-agent/src/core/tools/grep.ts) - `GrepToolDetails`
|
|
2121
|
+
- [find.ts](https://github.com/SamMorrowDrums/mcpi/blob/main/packages/coding-agent/src/core/tools/find.ts) - `FindToolDetails`
|
|
2122
|
+
- [ls.ts](https://github.com/SamMorrowDrums/mcpi/blob/main/packages/coding-agent/src/core/tools/ls.ts) - `LsToolDetails`
|
|
1819
2123
|
|
|
1820
2124
|
### Remote Execution
|
|
1821
2125
|
|
|
1822
2126
|
Built-in tools support pluggable operations for delegating to remote systems (SSH, containers, etc.):
|
|
1823
2127
|
|
|
1824
2128
|
```typescript
|
|
1825
|
-
import { createReadTool, createBashTool, type ReadOperations } from "@
|
|
2129
|
+
import { createReadTool, createBashTool, type ReadOperations } from "@sammorrowdrums/mcpi";
|
|
1826
2130
|
|
|
1827
2131
|
// Create tool with custom operations
|
|
1828
2132
|
const remoteRead = createReadTool(cwd, {
|
|
@@ -1848,12 +2152,12 @@ pi.registerTool({
|
|
|
1848
2152
|
|
|
1849
2153
|
**Operations interfaces:** `ReadOperations`, `WriteOperations`, `EditOperations`, `BashOperations`, `LsOperations`, `GrepOperations`, `FindOperations`
|
|
1850
2154
|
|
|
1851
|
-
For `user_bash`, extensions can reuse
|
|
2155
|
+
For `user_bash`, extensions can reuse mcpi's local shell backend via `createLocalBashOperations()` instead of reimplementing local process spawning, shell resolution, and process-tree termination.
|
|
1852
2156
|
|
|
1853
2157
|
The bash tool also supports a spawn hook to adjust the command, cwd, or env before execution:
|
|
1854
2158
|
|
|
1855
2159
|
```typescript
|
|
1856
|
-
import { createBashTool } from "@
|
|
2160
|
+
import { createBashTool } from "@sammorrowdrums/mcpi";
|
|
1857
2161
|
|
|
1858
2162
|
const bashTool = createBashTool(cwd, {
|
|
1859
2163
|
spawnHook: ({ command, cwd, env }) => ({
|
|
@@ -1864,7 +2168,19 @@ const bashTool = createBashTool(cwd, {
|
|
|
1864
2168
|
});
|
|
1865
2169
|
```
|
|
1866
2170
|
|
|
1867
|
-
|
|
2171
|
+
`createBashTool()` exposes the current session to commands through `MCPI_SESSION_ID`, `MCPI_SESSION_FILE`, `MCPI_PROVIDER`, `MCPI_MODEL`, and `MCPI_REASONING_LEVEL`. Injection happens before `spawnHook`, so hooks receive these values in `env` and preserve them when they spread the existing environment as above. Set `exposeSessionEnvironment: false` to disable them:
|
|
2172
|
+
|
|
2173
|
+
```typescript
|
|
2174
|
+
const bashTool = createBashTool(cwd, {
|
|
2175
|
+
exposeSessionEnvironment: false,
|
|
2176
|
+
});
|
|
2177
|
+
```
|
|
2178
|
+
|
|
2179
|
+
See [Bash tool session environment](environment-variables.md#bash-tool-session-environment) for variable semantics. See [examples/extensions/ssh.ts](../examples/extensions/ssh.ts) for a complete SSH example with `--ssh` flag.
|
|
2180
|
+
|
|
2181
|
+
When mcpi builds its own bash tool it installs a `spawnHook` that applies variables set with
|
|
2182
|
+
[`pi.setEnv()`](#session-environment) on top of the session metadata. A `spawnHook` you supply to
|
|
2183
|
+
your own `createBashTool()` runs independently of that and is responsible for its own environment.
|
|
1868
2184
|
|
|
1869
2185
|
### Output Truncation
|
|
1870
2186
|
|
|
@@ -1883,7 +2199,7 @@ import {
|
|
|
1883
2199
|
formatSize, // Human-readable size (e.g., "50KB", "1.5MB")
|
|
1884
2200
|
DEFAULT_MAX_BYTES, // 50KB
|
|
1885
2201
|
DEFAULT_MAX_LINES, // 2000
|
|
1886
|
-
} from "@
|
|
2202
|
+
} from "@sammorrowdrums/mcpi";
|
|
1887
2203
|
|
|
1888
2204
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
1889
2205
|
const output = await runCommand();
|
|
@@ -1938,7 +2254,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1938
2254
|
|
|
1939
2255
|
### Custom Rendering
|
|
1940
2256
|
|
|
1941
|
-
Tools can provide `renderCall` and `renderResult` for custom TUI display. See [tui.md](tui.md) for the full component API and [tool-execution.ts](https://github.com/
|
|
2257
|
+
Tools can provide `renderCall` and `renderResult` for custom TUI display. See [tui.md](tui.md) for the full component API and [tool-execution.ts](https://github.com/SamMorrowDrums/mcpi/blob/main/packages/coding-agent/src/modes/interactive/components/tool-execution.ts) for how tool rows are composed.
|
|
1942
2258
|
|
|
1943
2259
|
By default, tool output is wrapped in a `Box` that handles padding and background. A defined `renderCall` or `renderResult` must return a `Component`. If a slot renderer is not defined, `tool-execution.ts` uses fallback rendering for that slot.
|
|
1944
2260
|
|
|
@@ -1974,7 +2290,7 @@ Use `context.state` for cross-slot shared state. Keep slot-local caches on the r
|
|
|
1974
2290
|
Renders the tool call or header:
|
|
1975
2291
|
|
|
1976
2292
|
```typescript
|
|
1977
|
-
import { Text } from "@
|
|
2293
|
+
import { Text } from "@sammorrowdrums/mcpi-tui";
|
|
1978
2294
|
|
|
1979
2295
|
renderCall(args, theme, context) {
|
|
1980
2296
|
const text = (context.lastComponent as Text | undefined) ?? new Text("", 0, 0);
|
|
@@ -2019,7 +2335,7 @@ If a slot intentionally has no visible content, return an empty `Component` such
|
|
|
2019
2335
|
Use `keyHint()` to display keybinding hints that respect the active keybinding configuration:
|
|
2020
2336
|
|
|
2021
2337
|
```typescript
|
|
2022
|
-
import { keyHint } from "@
|
|
2338
|
+
import { keyHint } from "@sammorrowdrums/mcpi";
|
|
2023
2339
|
|
|
2024
2340
|
renderResult(result, { expanded }, theme, context) {
|
|
2025
2341
|
let text = theme.fg("success", "✓ Done");
|
|
@@ -2061,6 +2377,163 @@ If a slot renderer is not defined or throws:
|
|
|
2061
2377
|
- `renderCall`: Shows the tool name
|
|
2062
2378
|
- `renderResult`: Shows raw text from `content`
|
|
2063
2379
|
|
|
2380
|
+
### Dynamic Tool Loading
|
|
2381
|
+
|
|
2382
|
+
Extensions can register many tools while keeping only a small initial set active. A tool can then add more tools with `pi.setActiveTools()` during execution. mcpi detects purely additive changes, records the newly available tool names on that tool result, and applies the updated active set before the next model request.
|
|
2383
|
+
|
|
2384
|
+
This works with every model. Models with native deferred-loading support preserve the stable prompt prefix and load the new definitions at the tool-result position. Other models use the fallback described below.
|
|
2385
|
+
|
|
2386
|
+
The lifecycle is:
|
|
2387
|
+
|
|
2388
|
+
1. Register every tool with `pi.registerTool()` so it appears in `pi.getAllTools()`.
|
|
2389
|
+
2. Keep loader tools, such as `search_tools`, active and leave searchable tools inactive.
|
|
2390
|
+
3. During loader execution, call `pi.setActiveTools([...currentTools, ...matchingTools])`. The change must be additive: do not remove currently active tools in the same call.
|
|
2391
|
+
4. mcpi records which tools were added on the loader's tool result.
|
|
2392
|
+
5. Before the next model response, mcpi exposes the added definitions using native deferred loading when supported, or the normal active tool list otherwise.
|
|
2393
|
+
|
|
2394
|
+
You do not need to return provider-specific tool references or mark the loader as a special search tool. The active-tool change is the signal. Names passed to `pi.setActiveTools()` must already be registered; unknown names are ignored.
|
|
2395
|
+
|
|
2396
|
+
#### Models with native deferred loading
|
|
2397
|
+
|
|
2398
|
+
Native deferred loading depends on the **provider** as well as the model. The same Claude model can support native deferred loading when served directly by Anthropic and fall back to the normal tool list when served through another provider.
|
|
2399
|
+
|
|
2400
|
+
- **Anthropic (first-party `anthropic` provider only)**
|
|
2401
|
+
- **Models:** Sonnet, Opus, Fable version 4.5 or newer, including Claude Opus 5. Haiku is excluded.
|
|
2402
|
+
- **Native representation:** Deferred definitions use `defer_loading`; the load point uses `tool_reference` content.
|
|
2403
|
+
- **Provider gate:** Auto-detection requires `provider === "anthropic"`. Claude models served by GitHub Copilot, Amazon Bedrock, Google Vertex, or an OpenAI-compatible proxy do not auto-enable, even when they use the `anthropic-messages` API.
|
|
2404
|
+
- **OpenAI**
|
|
2405
|
+
- **Models:** `gpt-5.4` and newer family
|
|
2406
|
+
- **Native representation:** Models with `supportsAdditionalTools` anchor the new definitions to the transcript with a developer-role `additional_tools` message. Models with only `supportsToolSearch` instead get completed client `tool_search_call` and `tool_search_output` items at the load point.
|
|
2407
|
+
- **Provider gate:** Auto-detection applies to the `openai` and `openai-codex` providers. Other hosts of the same models use the fallback.
|
|
2408
|
+
|
|
2409
|
+
For a verified custom model or proxy, native handling can be enabled with `compat.supportsToolReferences: true` for `anthropic-messages`, or `compat.supportsToolSearch: true` for `openai-responses` and `openai-codex-responses`. Leave these disabled unless the endpoint and model accept the corresponding native protocol.
|
|
2410
|
+
|
|
2411
|
+
#### Claude Opus 5 compatibility matrix
|
|
2412
|
+
|
|
2413
|
+
Claude Opus 5 is the default model for the `anthropic`, `github-copilot`, and `amazon-bedrock` providers. Its deferred-loading behavior differs per provider:
|
|
2414
|
+
|
|
2415
|
+
| Provider | Model id | API | Deferred loading | Verified by |
|
|
2416
|
+
| --- | --- | --- | --- | --- |
|
|
2417
|
+
| `anthropic` | `claude-opus-5` | `anthropic-messages` | Native `defer_loading` + `tool_reference` | Offline contract test |
|
|
2418
|
+
| `github-copilot` | `claude-opus-5` | `anthropic-messages` | Safe fallback: full active tool list, no `defer_loading` | Offline contract test |
|
|
2419
|
+
| `amazon-bedrock` | `us.anthropic.claude-opus-5` | `bedrock-converse-stream` | Safe fallback; the Converse API has no tool-reference protocol | Offline contract test |
|
|
2420
|
+
|
|
2421
|
+
**Scope of this matrix.** Deferred loading is the only capability that varies here, so "safe fallback" is not a general capability rating. `us.anthropic.claude-opus-5` keeps adaptive thinking, native `xhigh` effort, and prompt caching; `bedrock-converse-stream` derives those from model-id predicates rather than from `compat.forceAdaptiveThinking`. Only tool deferral is unavailable, because the Converse API has no tool-reference protocol.
|
|
2422
|
+
|
|
2423
|
+
Switching between these providers mid-session is supported. A tool marked as added under one provider is loaded correctly after switching to another, including across API families such as an `openai-responses` transcript continued on `anthropic/claude-opus-5`.
|
|
2424
|
+
|
|
2425
|
+
**Offline contract tests.** The behaviors above are asserted by offline contract tests that capture the outgoing request payload and abort before any network call, so they need no credentials and make no billable requests. See `packages/ai/test/deferred-tools.test.ts` and `packages/ai/test/claude-opus-5-provider-matrix.test.ts`.
|
|
2426
|
+
|
|
2427
|
+
#### Fallback behavior
|
|
2428
|
+
|
|
2429
|
+
For all other models and providers, dynamic activation still works: mcpi sends the complete current active tool list normally on the next request. The model can call the newly activated tools, but adding their definitions may invalidate the provider's cached prompt prefix.
|
|
2430
|
+
|
|
2431
|
+
mcpi also uses this safe fallback when the active set is not purely additive, such as replacing one group of tools with another. Tool removals therefore work, but they do not use deferred loading.
|
|
2432
|
+
|
|
2433
|
+
For the best cache behavior, keep the loader tool active for the whole session and add tools instead of replacing the active set. Also note that activating a tool with `promptSnippet` or `promptGuidelines` rebuilds the system prompt; that system-prompt change can invalidate the prefix even when the provider supports deferred schemas. Lazily loaded tools should usually rely on their tool `description` and omit active-only prompt metadata.
|
|
2434
|
+
|
|
2435
|
+
#### Search tool example
|
|
2436
|
+
|
|
2437
|
+
The following extension registers two searchable tools, removes them from the initial active set, and keeps only `search_tools` as their loader. The example uses simple keyword matching, but the search implementation could use BM25, embeddings, a remote catalog, or project-specific routing.
|
|
2438
|
+
|
|
2439
|
+
```typescript
|
|
2440
|
+
import type { ExtensionAPI } from "@sammorrowdrums/mcpi";
|
|
2441
|
+
import { Type } from "typebox";
|
|
2442
|
+
|
|
2443
|
+
const SEARCHABLE_TOOL_NAMES = new Set(["lookup_weather", "search_issues"]);
|
|
2444
|
+
|
|
2445
|
+
export default function (pi: ExtensionAPI) {
|
|
2446
|
+
pi.registerTool({
|
|
2447
|
+
name: "lookup_weather",
|
|
2448
|
+
label: "Lookup Weather",
|
|
2449
|
+
description: "Look up the current weather for a city",
|
|
2450
|
+
parameters: Type.Object({ city: Type.String() }),
|
|
2451
|
+
async execute(_toolCallId, params) {
|
|
2452
|
+
return {
|
|
2453
|
+
content: [{ type: "text", text: `Weather for ${params.city}: sunny` }],
|
|
2454
|
+
details: {},
|
|
2455
|
+
};
|
|
2456
|
+
},
|
|
2457
|
+
});
|
|
2458
|
+
|
|
2459
|
+
pi.registerTool({
|
|
2460
|
+
name: "search_issues",
|
|
2461
|
+
label: "Search Issues",
|
|
2462
|
+
description: "Search project issues by keyword",
|
|
2463
|
+
parameters: Type.Object({ query: Type.String() }),
|
|
2464
|
+
async execute(_toolCallId, params) {
|
|
2465
|
+
return {
|
|
2466
|
+
content: [{ type: "text", text: `No open issues matching ${params.query}` }],
|
|
2467
|
+
details: {},
|
|
2468
|
+
};
|
|
2469
|
+
},
|
|
2470
|
+
});
|
|
2471
|
+
|
|
2472
|
+
pi.registerTool({
|
|
2473
|
+
name: "search_tools",
|
|
2474
|
+
label: "Search Tools",
|
|
2475
|
+
description: "Search for and enable tools relevant to a task",
|
|
2476
|
+
promptSnippet: "Search for additional tools when the active tools cannot perform the task",
|
|
2477
|
+
promptGuidelines: [
|
|
2478
|
+
"Use search_tools when a task requires a capability that is not currently available.",
|
|
2479
|
+
],
|
|
2480
|
+
parameters: Type.Object({
|
|
2481
|
+
query: Type.String({ description: "Capability or task to search for" }),
|
|
2482
|
+
limit: Type.Optional(Type.Integer({ minimum: 1, maximum: 10 })),
|
|
2483
|
+
}),
|
|
2484
|
+
async execute(_toolCallId, params) {
|
|
2485
|
+
const terms = params.query.toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
|
|
2486
|
+
const matches = pi.getAllTools()
|
|
2487
|
+
.filter((tool) => SEARCHABLE_TOOL_NAMES.has(tool.name))
|
|
2488
|
+
.map((tool) => ({
|
|
2489
|
+
tool,
|
|
2490
|
+
score: terms.reduce(
|
|
2491
|
+
(score, term) =>
|
|
2492
|
+
score + (`${tool.name} ${tool.description}`.toLowerCase().includes(term) ? 1 : 0),
|
|
2493
|
+
0,
|
|
2494
|
+
),
|
|
2495
|
+
}))
|
|
2496
|
+
.filter((match) => match.score > 0)
|
|
2497
|
+
.sort((a, b) => b.score - a.score)
|
|
2498
|
+
.slice(0, params.limit ?? 3)
|
|
2499
|
+
.map((match) => match.tool.name);
|
|
2500
|
+
|
|
2501
|
+
if (matches.length === 0) {
|
|
2502
|
+
return {
|
|
2503
|
+
content: [{ type: "text", text: `No tools found for: ${params.query}` }],
|
|
2504
|
+
details: { matches: [] },
|
|
2505
|
+
};
|
|
2506
|
+
}
|
|
2507
|
+
|
|
2508
|
+
const active = pi.getActiveTools();
|
|
2509
|
+
const added = matches.filter((name) => !active.includes(name));
|
|
2510
|
+
pi.setActiveTools([...new Set([...active, ...added])]);
|
|
2511
|
+
|
|
2512
|
+
return {
|
|
2513
|
+
content: [{
|
|
2514
|
+
type: "text",
|
|
2515
|
+
text: added.length > 0
|
|
2516
|
+
? `Loaded tools: ${added.join(", ")}`
|
|
2517
|
+
: `Matching tools already active: ${matches.join(", ")}`,
|
|
2518
|
+
}],
|
|
2519
|
+
details: { matches, added },
|
|
2520
|
+
};
|
|
2521
|
+
},
|
|
2522
|
+
});
|
|
2523
|
+
|
|
2524
|
+
pi.on("session_start", () => {
|
|
2525
|
+
// Keep searchable tools registered but initially inactive. Preserve built-ins
|
|
2526
|
+
// and tools owned by other extensions, and keep the loader itself active.
|
|
2527
|
+
const initialTools = pi.getActiveTools().filter(
|
|
2528
|
+
(name) => !SEARCHABLE_TOOL_NAMES.has(name),
|
|
2529
|
+
);
|
|
2530
|
+
pi.setActiveTools([...new Set([...initialTools, "search_tools"])]);
|
|
2531
|
+
});
|
|
2532
|
+
}
|
|
2533
|
+
```
|
|
2534
|
+
|
|
2535
|
+
When `search_tools` adds a match, the model receives that definition on the immediately following request. On a native-capable model the definition is anchored after the search result without changing the initial tool-schema prefix. On other models it appears in the normal tool list on that same following request.
|
|
2536
|
+
|
|
2064
2537
|
## Custom UI
|
|
2065
2538
|
|
|
2066
2539
|
Extensions can interact with users via `ctx.ui` methods and customize how messages/tools render.
|
|
@@ -2070,7 +2543,7 @@ Extensions can interact with users via `ctx.ui` methods and customize how messag
|
|
|
2070
2543
|
- Async operations with cancel (BorderedLoader)
|
|
2071
2544
|
- Settings toggles (SettingsList)
|
|
2072
2545
|
- Status indicators (setStatus)
|
|
2073
|
-
- Working message and indicator during streaming (`setWorkingMessage`, `setWorkingIndicator`)
|
|
2546
|
+
- Working message, visibility, and indicator during streaming (`setWorkingMessage`, `setWorkingVisible`, `setWorkingIndicator`)
|
|
2074
2547
|
- Widgets above/below editor (setWidget)
|
|
2075
2548
|
- Autocomplete providers layered on top of built-in slash/path completion (addAutocompleteProvider)
|
|
2076
2549
|
- Custom footers (setFooter)
|
|
@@ -2152,9 +2625,11 @@ See [examples/extensions/timed-confirm.ts](../examples/extensions/timed-confirm.
|
|
|
2152
2625
|
ctx.ui.setStatus("my-ext", "Processing...");
|
|
2153
2626
|
ctx.ui.setStatus("my-ext", undefined); // Clear
|
|
2154
2627
|
|
|
2155
|
-
// Working
|
|
2628
|
+
// Working loader (shown during streaming)
|
|
2156
2629
|
ctx.ui.setWorkingMessage("Thinking deeply...");
|
|
2157
2630
|
ctx.ui.setWorkingMessage(); // Restore default
|
|
2631
|
+
ctx.ui.setWorkingVisible(false); // Hide the built-in working loader row entirely
|
|
2632
|
+
ctx.ui.setWorkingVisible(true); // Show the built-in working loader row
|
|
2158
2633
|
|
|
2159
2634
|
// Working indicator (shown during streaming)
|
|
2160
2635
|
ctx.ui.setWorkingIndicator({ frames: [ctx.ui.theme.fg("accent", "●")] }); // Static dot
|
|
@@ -2185,7 +2660,7 @@ ctx.ui.setFooter((tui, theme) => ({
|
|
|
2185
2660
|
ctx.ui.setFooter(undefined); // Restore built-in footer
|
|
2186
2661
|
|
|
2187
2662
|
// Terminal title
|
|
2188
|
-
ctx.ui.setTitle("
|
|
2663
|
+
ctx.ui.setTitle("mcpi - my-project");
|
|
2189
2664
|
|
|
2190
2665
|
// Editor text
|
|
2191
2666
|
ctx.ui.setEditorText("Prefill text");
|
|
@@ -2196,6 +2671,7 @@ ctx.ui.pasteToEditor("pasted content");
|
|
|
2196
2671
|
|
|
2197
2672
|
// Stack custom autocomplete behavior on top of the built-in provider
|
|
2198
2673
|
ctx.ui.addAutocompleteProvider((current) => ({
|
|
2674
|
+
triggerCharacters: ["#"],
|
|
2199
2675
|
async getSuggestions(lines, line, col, options) {
|
|
2200
2676
|
const beforeCursor = (lines[line] ?? "").slice(0, col);
|
|
2201
2677
|
const match = beforeCursor.match(/(?:^|[ \t])#([^\s#]*)$/);
|
|
@@ -2223,6 +2699,10 @@ ctx.ui.setToolsExpanded(wasExpanded);
|
|
|
2223
2699
|
|
|
2224
2700
|
// Custom editor (vim mode, emacs mode, etc.)
|
|
2225
2701
|
ctx.ui.setEditorComponent((tui, theme, keybindings) => new VimEditor(tui, theme, keybindings));
|
|
2702
|
+
const currentEditor = ctx.ui.getEditorComponent();
|
|
2703
|
+
ctx.ui.setEditorComponent((tui, theme, keybindings) =>
|
|
2704
|
+
new WrappedEditor(tui, theme, keybindings, currentEditor?.(tui, theme, keybindings))
|
|
2705
|
+
);
|
|
2226
2706
|
ctx.ui.setEditorComponent(undefined); // Restore default editor
|
|
2227
2707
|
|
|
2228
2708
|
// Theme management (see themes.md for creating themes)
|
|
@@ -2240,7 +2720,7 @@ Custom working-indicator frames are rendered verbatim. If you want colors, add t
|
|
|
2240
2720
|
|
|
2241
2721
|
### Autocomplete Providers
|
|
2242
2722
|
|
|
2243
|
-
Use `ctx.ui.addAutocompleteProvider()` to stack custom autocomplete logic on top of the built-in slash-command and path provider.
|
|
2723
|
+
Use `ctx.ui.addAutocompleteProvider()` to stack custom autocomplete logic on top of the built-in slash-command and path provider. Set `triggerCharacters` for custom natural triggers such as `$`.
|
|
2244
2724
|
|
|
2245
2725
|
Typical pattern:
|
|
2246
2726
|
|
|
@@ -2252,6 +2732,7 @@ Typical pattern:
|
|
|
2252
2732
|
```typescript
|
|
2253
2733
|
pi.on("session_start", (_event, ctx) => {
|
|
2254
2734
|
ctx.ui.addAutocompleteProvider((current) => ({
|
|
2735
|
+
triggerCharacters: ["#"],
|
|
2255
2736
|
async getSuggestions(lines, cursorLine, cursorCol, options) {
|
|
2256
2737
|
const line = lines[cursorLine] ?? "";
|
|
2257
2738
|
const beforeCursor = line.slice(0, cursorCol);
|
|
@@ -2287,7 +2768,7 @@ See [github-issue-autocomplete.ts](../examples/extensions/github-issue-autocompl
|
|
|
2287
2768
|
For complex UI, use `ctx.ui.custom()`. This temporarily replaces the editor with your component until `done()` is called:
|
|
2288
2769
|
|
|
2289
2770
|
```typescript
|
|
2290
|
-
import { Text, Component } from "@
|
|
2771
|
+
import { Text, Component } from "@sammorrowdrums/mcpi-tui";
|
|
2291
2772
|
|
|
2292
2773
|
const result = await ctx.ui.custom<boolean>((tui, theme, keybindings, done) => {
|
|
2293
2774
|
const text = new Text("Press Enter to confirm, Escape to cancel", 1, 1);
|
|
@@ -2325,7 +2806,7 @@ const result = await ctx.ui.custom<string | null>(
|
|
|
2325
2806
|
);
|
|
2326
2807
|
```
|
|
2327
2808
|
|
|
2328
|
-
For advanced positioning (anchors, margins, percentages, responsive visibility), pass `overlayOptions`. Use `onHandle` to control visibility programmatically:
|
|
2809
|
+
For advanced positioning (anchors, margins, percentages, responsive visibility), pass `overlayOptions`. Use `onHandle` to control focus or visibility programmatically:
|
|
2329
2810
|
|
|
2330
2811
|
```typescript
|
|
2331
2812
|
const result = await ctx.ui.custom<string | null>(
|
|
@@ -2333,20 +2814,27 @@ const result = await ctx.ui.custom<string | null>(
|
|
|
2333
2814
|
{
|
|
2334
2815
|
overlay: true,
|
|
2335
2816
|
overlayOptions: { anchor: "top-right", width: "50%", margin: 2 },
|
|
2336
|
-
onHandle: (handle) => {
|
|
2817
|
+
onHandle: (handle) => {
|
|
2818
|
+
handle.focus(); // focus this overlay and bring it to the visual front
|
|
2819
|
+
// handle.unfocus({ target: editorComponent }); // release input to a specific component
|
|
2820
|
+
// handle.setHidden(true/false); // toggle visibility
|
|
2821
|
+
// handle.hide(); // permanently remove
|
|
2822
|
+
}
|
|
2337
2823
|
}
|
|
2338
2824
|
);
|
|
2339
2825
|
```
|
|
2340
2826
|
|
|
2341
|
-
|
|
2827
|
+
A focused visible overlay can reclaim input after temporary non-overlay custom UI closes. If you intentionally want another component to keep input while the overlay stays visible, call `handle.unfocus({ target })`. Passing `{ target: null }` releases the overlay without focusing another component.
|
|
2828
|
+
|
|
2829
|
+
See [tui.md](tui.md) for the full `OverlayOptions` and `OverlayHandle` API and [overlay-qa-tests.ts](../examples/extensions/overlay-qa-tests.ts) for examples.
|
|
2342
2830
|
|
|
2343
2831
|
### Custom Editor
|
|
2344
2832
|
|
|
2345
2833
|
Replace the main input editor with a custom implementation (vim mode, emacs mode, etc.):
|
|
2346
2834
|
|
|
2347
2835
|
```typescript
|
|
2348
|
-
import { CustomEditor, type ExtensionAPI } from "@
|
|
2349
|
-
import { matchesKey } from "@
|
|
2836
|
+
import { CustomEditor, type ExtensionAPI } from "@sammorrowdrums/mcpi";
|
|
2837
|
+
import { matchesKey } from "@sammorrowdrums/mcpi-tui";
|
|
2350
2838
|
|
|
2351
2839
|
class VimEditor extends CustomEditor {
|
|
2352
2840
|
private mode: "normal" | "insert" = "insert";
|
|
@@ -2366,8 +2854,8 @@ class VimEditor extends CustomEditor {
|
|
|
2366
2854
|
|
|
2367
2855
|
export default function (pi: ExtensionAPI) {
|
|
2368
2856
|
pi.on("session_start", (_event, ctx) => {
|
|
2369
|
-
ctx.ui.setEditorComponent((
|
|
2370
|
-
new VimEditor(theme, keybindings)
|
|
2857
|
+
ctx.ui.setEditorComponent((tui, theme, keybindings) =>
|
|
2858
|
+
new VimEditor(tui, theme, keybindings)
|
|
2371
2859
|
);
|
|
2372
2860
|
});
|
|
2373
2861
|
}
|
|
@@ -2376,20 +2864,30 @@ export default function (pi: ExtensionAPI) {
|
|
|
2376
2864
|
**Key points:**
|
|
2377
2865
|
- Extend `CustomEditor` (not base `Editor`) to get app keybindings (escape to abort, ctrl+d, model switching)
|
|
2378
2866
|
- Call `super.handleInput(data)` for keys you don't handle
|
|
2379
|
-
- Factory receives `theme
|
|
2867
|
+
- Factory receives `tui`, `theme`, and `keybindings` from the app
|
|
2868
|
+
- Use `ctx.ui.getEditorComponent()` before `setEditorComponent()` to wrap the previously configured custom editor
|
|
2380
2869
|
- Pass `undefined` to restore default: `ctx.ui.setEditorComponent(undefined)`
|
|
2381
2870
|
|
|
2871
|
+
To compose with another extension that already replaced the editor, capture the previous factory before setting yours:
|
|
2872
|
+
|
|
2873
|
+
```typescript
|
|
2874
|
+
const previous = ctx.ui.getEditorComponent();
|
|
2875
|
+
ctx.ui.setEditorComponent((tui, theme, keybindings) =>
|
|
2876
|
+
new MyEditor(tui, theme, keybindings, { base: previous?.(tui, theme, keybindings) })
|
|
2877
|
+
);
|
|
2878
|
+
```
|
|
2879
|
+
|
|
2382
2880
|
See [tui.md](tui.md) Pattern 7 for a complete example with mode indicator.
|
|
2383
2881
|
|
|
2384
|
-
### Message Rendering
|
|
2882
|
+
### Message and Entry Rendering
|
|
2385
2883
|
|
|
2386
|
-
Register a custom renderer for messages with your `customType
|
|
2884
|
+
Register a custom renderer for messages with your `customType`. Use message renderers for content that should participate in LLM context:
|
|
2387
2885
|
|
|
2388
2886
|
```typescript
|
|
2389
|
-
import { Text } from "@
|
|
2887
|
+
import { Text } from "@sammorrowdrums/mcpi-tui";
|
|
2390
2888
|
|
|
2391
2889
|
pi.registerMessageRenderer("my-extension", (message, options, theme) => {
|
|
2392
|
-
const { expanded } = options;
|
|
2890
|
+
const { expanded, outputPad } = options;
|
|
2393
2891
|
let text = theme.fg("accent", `[${message.customType}] `);
|
|
2394
2892
|
text += message.content;
|
|
2395
2893
|
|
|
@@ -2397,7 +2895,7 @@ pi.registerMessageRenderer("my-extension", (message, options, theme) => {
|
|
|
2397
2895
|
text += "\n" + theme.fg("dim", JSON.stringify(message.details, null, 2));
|
|
2398
2896
|
}
|
|
2399
2897
|
|
|
2400
|
-
return new Text(text,
|
|
2898
|
+
return new Text(text, outputPad, 0);
|
|
2401
2899
|
});
|
|
2402
2900
|
```
|
|
2403
2901
|
|
|
@@ -2412,6 +2910,16 @@ pi.sendMessage({
|
|
|
2412
2910
|
});
|
|
2413
2911
|
```
|
|
2414
2912
|
|
|
2913
|
+
For TUI-only content that should not be sent to the LLM, render custom entries instead:
|
|
2914
|
+
|
|
2915
|
+
```typescript
|
|
2916
|
+
pi.registerEntryRenderer("my-card", (entry, options, theme) => {
|
|
2917
|
+
return new Text(theme.fg("accent", JSON.stringify(entry.data)));
|
|
2918
|
+
});
|
|
2919
|
+
|
|
2920
|
+
pi.appendEntry("my-card", { status: "done" });
|
|
2921
|
+
```
|
|
2922
|
+
|
|
2415
2923
|
### Theme Colors
|
|
2416
2924
|
|
|
2417
2925
|
All render functions receive a `theme` object. See [themes.md](themes.md) for creating custom themes and the full color palette.
|
|
@@ -2435,7 +2943,7 @@ theme.strikethrough(text)
|
|
|
2435
2943
|
For syntax highlighting in custom tool renderers:
|
|
2436
2944
|
|
|
2437
2945
|
```typescript
|
|
2438
|
-
import { highlightCode, getLanguageFromPath } from "@
|
|
2946
|
+
import { highlightCode, getLanguageFromPath } from "@sammorrowdrums/mcpi";
|
|
2439
2947
|
|
|
2440
2948
|
// Highlight code with explicit language
|
|
2441
2949
|
const highlighted = highlightCode("const x = 1;", "typescript", theme);
|
|
@@ -2453,14 +2961,14 @@ const highlighted = highlightCode(code, lang, theme);
|
|
|
2453
2961
|
|
|
2454
2962
|
## Mode Behavior
|
|
2455
2963
|
|
|
2456
|
-
| Mode |
|
|
2457
|
-
|
|
2458
|
-
| Interactive | Full TUI
|
|
2459
|
-
| RPC (`--mode rpc`) | JSON protocol
|
|
2460
|
-
| JSON (`--mode json`) |
|
|
2461
|
-
| Print (`-p`) |
|
|
2964
|
+
| Mode | `ctx.mode` | `ctx.hasUI` | Notes |
|
|
2965
|
+
|------|------------|-------------|-------|
|
|
2966
|
+
| Interactive | `"tui"` | `true` | Full TUI with terminal rendering |
|
|
2967
|
+
| RPC (`--mode rpc`) | `"rpc"` | `true` | Dialogs and notifications via JSON protocol; `custom()` returns `undefined`. See [rpc.md](rpc.md) |
|
|
2968
|
+
| JSON (`--mode json`) | `"json"` | `false` | Event stream to stdout; UI methods are no-ops |
|
|
2969
|
+
| Print (`-p`) | `"print"` | `false` | Extensions run but can't prompt |
|
|
2462
2970
|
|
|
2463
|
-
|
|
2971
|
+
Use `ctx.mode === "tui"` before TUI-specific features (`custom()`, component factories, terminal input). Use `ctx.hasUI` before dialog and notification methods that work in both TUI and RPC modes.
|
|
2464
2972
|
|
|
2465
2973
|
## Examples Reference
|
|
2466
2974
|
|
|
@@ -2487,10 +2995,12 @@ All examples in [examples/extensions/](../examples/extensions/).
|
|
|
2487
2995
|
| `shutdown-command.ts` | Graceful shutdown command | `registerCommand`, `shutdown()` |
|
|
2488
2996
|
| **Events & Gates** |||
|
|
2489
2997
|
| `permission-gate.ts` | Block dangerous commands | `on("tool_call")`, `ui.confirm` |
|
|
2998
|
+
| `project-trust.ts` | Decide or defer project trust from a user/global or CLI extension | `on("project_trust")`, trust UI, required trust result |
|
|
2490
2999
|
| `protected-paths.ts` | Block writes to specific paths | `on("tool_call")` |
|
|
2491
3000
|
| `confirm-destructive.ts` | Confirm session changes | `on("session_before_switch")`, `on("session_before_fork")` |
|
|
2492
3001
|
| `dirty-repo-guard.ts` | Warn on dirty git repo | `on("session_before_*")`, `exec` |
|
|
2493
3002
|
| `input-transform.ts` | Transform user input | `on("input")` |
|
|
3003
|
+
| `input-transform-streaming.ts` | Streaming-aware input transform | `on("input")`, `streamingBehavior` |
|
|
2494
3004
|
| `model-status.ts` | React to model changes | `on("model_select")`, `setStatus` |
|
|
2495
3005
|
| `provider-payload.ts` | Inspect payloads and provider response headers | `on("before_provider_request")`, `on("after_provider_response")` |
|
|
2496
3006
|
| `system-prompt-header.ts` | Display system prompt info | `on("agent_start")`, `getSystemPrompt` |
|
|
@@ -2501,6 +3011,7 @@ All examples in [examples/extensions/](../examples/extensions/).
|
|
|
2501
3011
|
| `custom-compaction.ts` | Custom compaction summary | `on("session_before_compact")` |
|
|
2502
3012
|
| `trigger-compact.ts` | Trigger compaction manually | `compact()` |
|
|
2503
3013
|
| `git-checkpoint.ts` | Git stash on turns | `on("turn_start")`, `on("session_before_fork")`, `exec` |
|
|
3014
|
+
| `git-merge-and-resolve.ts` | Fetch, merge, and resolve conflicts | `on("agent_end")`, `exec`, `sendUserMessage` |
|
|
2504
3015
|
| `auto-commit-on-exit.ts` | Commit on shutdown | `on("session_shutdown")`, `exec` |
|
|
2505
3016
|
| **UI Components** |||
|
|
2506
3017
|
| `status-line.ts` | Footer status indicator | `setStatus`, session events |
|
|
@@ -2524,6 +3035,7 @@ All examples in [examples/extensions/](../examples/extensions/).
|
|
|
2524
3035
|
| `ssh.ts` | SSH remote execution | `registerFlag`, `on("user_bash")`, `on("before_agent_start")`, tool operations |
|
|
2525
3036
|
| `interactive-shell.ts` | Persistent shell session | `on("user_bash")` |
|
|
2526
3037
|
| `sandbox/` | Sandboxed tool execution | Tool operations |
|
|
3038
|
+
| `gondolin/` | Route built-in tools and `!` commands into a Gondolin micro-VM | Tool operations, built-in tool overrides, `on("user_bash")` |
|
|
2527
3039
|
| `subagent/` | Spawn sub-agents | `registerTool`, `exec` |
|
|
2528
3040
|
| **Games** |||
|
|
2529
3041
|
| `snake.ts` | Snake game | `registerCommand`, `ui.custom`, keyboard handling |
|
|
@@ -2534,12 +3046,12 @@ All examples in [examples/extensions/](../examples/extensions/).
|
|
|
2534
3046
|
| `custom-provider-gitlab-duo/` | GitLab Duo integration | `registerProvider` with OAuth |
|
|
2535
3047
|
| **Messages & Communication** |||
|
|
2536
3048
|
| `message-renderer.ts` | Custom message rendering | `registerMessageRenderer`, `sendMessage` |
|
|
3049
|
+
| `entry-renderer.ts` | TUI-only custom entry rendering | `registerEntryRenderer`, `appendEntry` |
|
|
2537
3050
|
| `event-bus.ts` | Inter-extension events | `pi.events` |
|
|
2538
3051
|
| **Session Metadata** |||
|
|
2539
3052
|
| `session-name.ts` | Name sessions for selector | `setSessionName`, `getSessionName` |
|
|
2540
3053
|
| `bookmark.ts` | Bookmark entries for /tree | `setLabel` |
|
|
2541
3054
|
| **Misc** |||
|
|
2542
|
-
| `antigravity-image-gen.ts` | Image generation tool | `registerTool`, Google Antigravity |
|
|
2543
3055
|
| `inline-bash.ts` | Inline bash in tool calls | `on("tool_call")` |
|
|
2544
3056
|
| `bash-spawn-hook.ts` | Adjust bash command, cwd, and env before execution | `createBashTool`, `spawnHook` |
|
|
2545
3057
|
| `with-deps/` | Extension with npm dependencies | Package structure with `package.json` |
|