@kvman/kvcoder 0.1.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/LICENSE +21 -0
- package/README.md +9 -0
- package/dist/api.d.ts +386 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +2 -0
- package/dist/api.js.map +1 -0
- package/dist/artifacts/artifact-format.d.ts +9 -0
- package/dist/artifacts/artifact-format.d.ts.map +1 -0
- package/dist/artifacts/artifact-format.js +32 -0
- package/dist/artifacts/artifact-format.js.map +1 -0
- package/dist/artifacts/artifact-records.d.ts +12 -0
- package/dist/artifacts/artifact-records.d.ts.map +1 -0
- package/dist/artifacts/artifact-records.js +17 -0
- package/dist/artifacts/artifact-records.js.map +1 -0
- package/dist/artifacts/register-artifacts.d.ts +3 -0
- package/dist/artifacts/register-artifacts.d.ts.map +1 -0
- package/dist/artifacts/register-artifacts.js +37 -0
- package/dist/artifacts/register-artifacts.js.map +1 -0
- package/dist/calls/binary-checks.d.ts +8 -0
- package/dist/calls/binary-checks.d.ts.map +1 -0
- package/dist/calls/binary-checks.js +12 -0
- package/dist/calls/binary-checks.js.map +1 -0
- package/dist/calls/connector-help.d.ts +3 -0
- package/dist/calls/connector-help.d.ts.map +1 -0
- package/dist/calls/connector-help.js +73 -0
- package/dist/calls/connector-help.js.map +1 -0
- package/dist/calls/help-text.d.ts +19 -0
- package/dist/calls/help-text.d.ts.map +1 -0
- package/dist/calls/help-text.js +22 -0
- package/dist/calls/help-text.js.map +1 -0
- package/dist/calls/line-run.d.ts +33 -0
- package/dist/calls/line-run.d.ts.map +1 -0
- package/dist/calls/line-run.js +56 -0
- package/dist/calls/line-run.js.map +1 -0
- package/dist/calls/run-shell.d.ts +12 -0
- package/dist/calls/run-shell.d.ts.map +1 -0
- package/dist/calls/run-shell.js +88 -0
- package/dist/calls/run-shell.js.map +1 -0
- package/dist/calls/run-tool.d.ts +49 -0
- package/dist/calls/run-tool.d.ts.map +1 -0
- package/dist/calls/run-tool.js +66 -0
- package/dist/calls/run-tool.js.map +1 -0
- package/dist/calls/shell-command.d.ts +25 -0
- package/dist/calls/shell-command.d.ts.map +1 -0
- package/dist/calls/shell-command.js +31 -0
- package/dist/calls/shell-command.js.map +1 -0
- package/dist/calls/shell-program.d.ts +5 -0
- package/dist/calls/shell-program.d.ts.map +1 -0
- package/dist/calls/shell-program.js +8 -0
- package/dist/calls/shell-program.js.map +1 -0
- package/dist/connector-call.d.ts +66 -0
- package/dist/connector-call.d.ts.map +1 -0
- package/dist/connector-call.js +133 -0
- package/dist/connector-call.js.map +1 -0
- package/dist/connectors/artifact.d.ts +51 -0
- package/dist/connectors/artifact.d.ts.map +1 -0
- package/dist/connectors/artifact.js +101 -0
- package/dist/connectors/artifact.js.map +1 -0
- package/dist/connectors/ask.d.ts +58 -0
- package/dist/connectors/ask.d.ts.map +1 -0
- package/dist/connectors/ask.js +85 -0
- package/dist/connectors/ask.js.map +1 -0
- package/dist/connectors/background.d.ts +29 -0
- package/dist/connectors/background.d.ts.map +1 -0
- package/dist/connectors/background.js +56 -0
- package/dist/connectors/background.js.map +1 -0
- package/dist/connectors/binary.d.ts +5 -0
- package/dist/connectors/binary.d.ts.map +1 -0
- package/dist/connectors/binary.js +27 -0
- package/dist/connectors/binary.js.map +1 -0
- package/dist/connectors/builtin-connectors.d.ts +217 -0
- package/dist/connectors/builtin-connectors.d.ts.map +1 -0
- package/dist/connectors/builtin-connectors.js +49 -0
- package/dist/connectors/builtin-connectors.js.map +1 -0
- package/dist/connectors/connector-command.d.ts +26 -0
- package/dist/connectors/connector-command.d.ts.map +1 -0
- package/dist/connectors/connector-command.js +17 -0
- package/dist/connectors/connector-command.js.map +1 -0
- package/dist/connectors/delegate.d.ts +32 -0
- package/dist/connectors/delegate.d.ts.map +1 -0
- package/dist/connectors/delegate.js +82 -0
- package/dist/connectors/delegate.js.map +1 -0
- package/dist/connectors/fs.d.ts +60 -0
- package/dist/connectors/fs.d.ts.map +1 -0
- package/dist/connectors/fs.js +132 -0
- package/dist/connectors/fs.js.map +1 -0
- package/dist/connectors/mcp.d.ts +37 -0
- package/dist/connectors/mcp.d.ts.map +1 -0
- package/dist/connectors/mcp.js +69 -0
- package/dist/connectors/mcp.js.map +1 -0
- package/dist/connectors/payload-fields.d.ts +9 -0
- package/dist/connectors/payload-fields.d.ts.map +1 -0
- package/dist/connectors/payload-fields.js +13 -0
- package/dist/connectors/payload-fields.js.map +1 -0
- package/dist/connectors/shell.d.ts +19 -0
- package/dist/connectors/shell.d.ts.map +1 -0
- package/dist/connectors/shell.js +22 -0
- package/dist/connectors/shell.js.map +1 -0
- package/dist/delay.d.ts +3 -0
- package/dist/delay.d.ts.map +1 -0
- package/dist/delay.js +11 -0
- package/dist/delay.js.map +1 -0
- package/dist/delegate/approved-run.d.ts +13 -0
- package/dist/delegate/approved-run.d.ts.map +1 -0
- package/dist/delegate/approved-run.js +54 -0
- package/dist/delegate/approved-run.js.map +1 -0
- package/dist/delegate/programs.d.ts +32 -0
- package/dist/delegate/programs.d.ts.map +1 -0
- package/dist/delegate/programs.js +67 -0
- package/dist/delegate/programs.js.map +1 -0
- package/dist/delegate/register-worker-run.d.ts +9 -0
- package/dist/delegate/register-worker-run.d.ts.map +1 -0
- package/dist/delegate/register-worker-run.js +70 -0
- package/dist/delegate/register-worker-run.js.map +1 -0
- package/dist/delegate/run-program.d.ts +9 -0
- package/dist/delegate/run-program.d.ts.map +1 -0
- package/dist/delegate/run-program.js +59 -0
- package/dist/delegate/run-program.js.map +1 -0
- package/dist/delegate/runs.d.ts +27 -0
- package/dist/delegate/runs.d.ts.map +1 -0
- package/dist/delegate/runs.js +68 -0
- package/dist/delegate/runs.js.map +1 -0
- package/dist/delegate/workers.d.ts +266 -0
- package/dist/delegate/workers.d.ts.map +1 -0
- package/dist/delegate/workers.js +80 -0
- package/dist/delegate/workers.js.map +1 -0
- package/dist/docs.d.ts +14 -0
- package/dist/docs.d.ts.map +1 -0
- package/dist/docs.js +59 -0
- package/dist/docs.js.map +1 -0
- package/dist/files/edit-text.d.ts +13 -0
- package/dist/files/edit-text.d.ts.map +1 -0
- package/dist/files/edit-text.js +46 -0
- package/dist/files/edit-text.js.map +1 -0
- package/dist/files/file-queue.d.ts +3 -0
- package/dist/files/file-queue.d.ts.map +1 -0
- package/dist/files/file-queue.js +17 -0
- package/dist/files/file-queue.js.map +1 -0
- package/dist/files/list-entries.d.ts +14 -0
- package/dist/files/list-entries.d.ts.map +1 -0
- package/dist/files/list-entries.js +40 -0
- package/dist/files/list-entries.js.map +1 -0
- package/dist/files/read-file.d.ts +17 -0
- package/dist/files/read-file.d.ts.map +1 -0
- package/dist/files/read-file.js +53 -0
- package/dist/files/read-file.js.map +1 -0
- package/dist/files/search-text.d.ts +14 -0
- package/dist/files/search-text.d.ts.map +1 -0
- package/dist/files/search-text.js +62 -0
- package/dist/files/search-text.js.map +1 -0
- package/dist/files/workspace-path.d.ts +5 -0
- package/dist/files/workspace-path.d.ts.map +1 -0
- package/dist/files/workspace-path.js +37 -0
- package/dist/files/workspace-path.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +68 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs/job-rows.d.ts +24 -0
- package/dist/jobs/job-rows.d.ts.map +1 -0
- package/dist/jobs/job-rows.js +74 -0
- package/dist/jobs/job-rows.js.map +1 -0
- package/dist/jobs/process-handlers.d.ts +8 -0
- package/dist/jobs/process-handlers.d.ts.map +1 -0
- package/dist/jobs/process-handlers.js +43 -0
- package/dist/jobs/process-handlers.js.map +1 -0
- package/dist/jobs/process-records.d.ts +15 -0
- package/dist/jobs/process-records.d.ts.map +1 -0
- package/dist/jobs/process-records.js +30 -0
- package/dist/jobs/process-records.js.map +1 -0
- package/dist/jobs/process-report.d.ts +8 -0
- package/dist/jobs/process-report.d.ts.map +1 -0
- package/dist/jobs/process-report.js +44 -0
- package/dist/jobs/process-report.js.map +1 -0
- package/dist/jobs/process-run.d.ts +26 -0
- package/dist/jobs/process-run.d.ts.map +1 -0
- package/dist/jobs/process-run.js +70 -0
- package/dist/jobs/process-run.js.map +1 -0
- package/dist/jobs/process-text.d.ts +5 -0
- package/dist/jobs/process-text.d.ts.map +1 -0
- package/dist/jobs/process-text.js +11 -0
- package/dist/jobs/process-text.js.map +1 -0
- package/dist/jobs/register-jobs.d.ts +3 -0
- package/dist/jobs/register-jobs.d.ts.map +1 -0
- package/dist/jobs/register-jobs.js +61 -0
- package/dist/jobs/register-jobs.js.map +1 -0
- package/dist/mcp/command-transport.d.ts +17 -0
- package/dist/mcp/command-transport.d.ts.map +1 -0
- package/dist/mcp/command-transport.js +60 -0
- package/dist/mcp/command-transport.js.map +1 -0
- package/dist/mcp/connect.d.ts +12 -0
- package/dist/mcp/connect.d.ts.map +1 -0
- package/dist/mcp/connect.js +54 -0
- package/dist/mcp/connect.js.map +1 -0
- package/dist/mcp/oauth-provider.d.ts +25 -0
- package/dist/mcp/oauth-provider.d.ts.map +1 -0
- package/dist/mcp/oauth-provider.js +59 -0
- package/dist/mcp/oauth-provider.js.map +1 -0
- package/dist/mcp/register-mcp.d.ts +3 -0
- package/dist/mcp/register-mcp.d.ts.map +1 -0
- package/dist/mcp/register-mcp.js +61 -0
- package/dist/mcp/register-mcp.js.map +1 -0
- package/dist/mcp/secrets.d.ts +7 -0
- package/dist/mcp/secrets.d.ts.map +1 -0
- package/dist/mcp/secrets.js +20 -0
- package/dist/mcp/secrets.js.map +1 -0
- package/dist/mcp/servers.d.ts +33 -0
- package/dist/mcp/servers.d.ts.map +1 -0
- package/dist/mcp/servers.js +31 -0
- package/dist/mcp/servers.js.map +1 -0
- package/dist/mcp/sign-in-record.d.ts +10 -0
- package/dist/mcp/sign-in-record.d.ts.map +1 -0
- package/dist/mcp/sign-in-record.js +4 -0
- package/dist/mcp/sign-in-record.js.map +1 -0
- package/dist/mcp/sign-in.d.ts +12 -0
- package/dist/mcp/sign-in.d.ts.map +1 -0
- package/dist/mcp/sign-in.js +75 -0
- package/dist/mcp/sign-in.js.map +1 -0
- package/dist/mcp/tools.d.ts +19 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +31 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/messages/attachments.d.ts +8 -0
- package/dist/messages/attachments.d.ts.map +1 -0
- package/dist/messages/attachments.js +48 -0
- package/dist/messages/attachments.js.map +1 -0
- package/dist/messages/receive-message.d.ts +15 -0
- package/dist/messages/receive-message.d.ts.map +1 -0
- package/dist/messages/receive-message.js +60 -0
- package/dist/messages/receive-message.js.map +1 -0
- package/dist/messages/register-messages.d.ts +3 -0
- package/dist/messages/register-messages.d.ts.map +1 -0
- package/dist/messages/register-messages.js +63 -0
- package/dist/messages/register-messages.js.map +1 -0
- package/dist/problems.d.ts +8 -0
- package/dist/problems.d.ts.map +1 -0
- package/dist/problems.js +14 -0
- package/dist/problems.js.map +1 -0
- package/dist/prompt/build-prompt.d.ts +29 -0
- package/dist/prompt/build-prompt.d.ts.map +1 -0
- package/dist/prompt/build-prompt.js +60 -0
- package/dist/prompt/build-prompt.js.map +1 -0
- package/dist/prompt/register-prompt.d.ts +3 -0
- package/dist/prompt/register-prompt.d.ts.map +1 -0
- package/dist/prompt/register-prompt.js +29 -0
- package/dist/prompt/register-prompt.js.map +1 -0
- package/dist/prompt/session-prompt.d.ts +24 -0
- package/dist/prompt/session-prompt.d.ts.map +1 -0
- package/dist/prompt/session-prompt.js +50 -0
- package/dist/prompt/session-prompt.js.map +1 -0
- package/dist/prompt/working-method.d.ts +7 -0
- package/dist/prompt/working-method.d.ts.map +1 -0
- package/dist/prompt/working-method.js +51 -0
- package/dist/prompt/working-method.js.map +1 -0
- package/dist/register-settings.d.ts +142 -0
- package/dist/register-settings.d.ts.map +1 -0
- package/dist/register-settings.js +51 -0
- package/dist/register-settings.js.map +1 -0
- package/dist/registry/loaded.d.ts +32 -0
- package/dist/registry/loaded.d.ts.map +1 -0
- package/dist/registry/loaded.js +41 -0
- package/dist/registry/loaded.js.map +1 -0
- package/dist/registry/register-connectors.d.ts +32 -0
- package/dist/registry/register-connectors.d.ts.map +1 -0
- package/dist/registry/register-connectors.js +126 -0
- package/dist/registry/register-connectors.js.map +1 -0
- package/dist/registry/register-sections.d.ts +18 -0
- package/dist/registry/register-sections.d.ts.map +1 -0
- package/dist/registry/register-sections.js +99 -0
- package/dist/registry/register-sections.js.map +1 -0
- package/dist/registry/session-points.d.ts +11 -0
- package/dist/registry/session-points.d.ts.map +1 -0
- package/dist/registry/session-points.js +89 -0
- package/dist/registry/session-points.js.map +1 -0
- package/dist/result-text.d.ts +11 -0
- package/dist/result-text.d.ts.map +1 -0
- package/dist/result-text.js +21 -0
- package/dist/result-text.js.map +1 -0
- package/dist/schemas/records.d.ts +357 -0
- package/dist/schemas/records.d.ts.map +1 -0
- package/dist/schemas/records.js +159 -0
- package/dist/schemas/records.js.map +1 -0
- package/dist/schemas/registry.d.ts +160 -0
- package/dist/schemas/registry.d.ts.map +1 -0
- package/dist/schemas/registry.js +37 -0
- package/dist/schemas/registry.js.map +1 -0
- package/dist/sessions/new-session.d.ts +6 -0
- package/dist/sessions/new-session.d.ts.map +1 -0
- package/dist/sessions/new-session.js +52 -0
- package/dist/sessions/new-session.js.map +1 -0
- package/dist/sessions/register-fork-export.d.ts +5 -0
- package/dist/sessions/register-fork-export.d.ts.map +1 -0
- package/dist/sessions/register-fork-export.js +62 -0
- package/dist/sessions/register-fork-export.js.map +1 -0
- package/dist/sessions/register-lifecycle.d.ts +3 -0
- package/dist/sessions/register-lifecycle.d.ts.map +1 -0
- package/dist/sessions/register-lifecycle.js +59 -0
- package/dist/sessions/register-lifecycle.js.map +1 -0
- package/dist/sessions/register-sessions.d.ts +3 -0
- package/dist/sessions/register-sessions.d.ts.map +1 -0
- package/dist/sessions/register-sessions.js +93 -0
- package/dist/sessions/register-sessions.js.map +1 -0
- package/dist/sessions/session-lookup.d.ts +10 -0
- package/dist/sessions/session-lookup.d.ts.map +1 -0
- package/dist/sessions/session-lookup.js +25 -0
- package/dist/sessions/session-lookup.js.map +1 -0
- package/dist/sessions/session-view.d.ts +118 -0
- package/dist/sessions/session-view.d.ts.map +1 -0
- package/dist/sessions/session-view.js +105 -0
- package/dist/sessions/session-view.js.map +1 -0
- package/dist/store/collections.d.ts +471 -0
- package/dist/store/collections.d.ts.map +1 -0
- package/dist/store/collections.js +46 -0
- package/dist/store/collections.js.map +1 -0
- package/dist/turns/background.d.ts +6 -0
- package/dist/turns/background.d.ts.map +1 -0
- package/dist/turns/background.js +27 -0
- package/dist/turns/background.js.map +1 -0
- package/dist/turns/cancel-turn.d.ts +3 -0
- package/dist/turns/cancel-turn.d.ts.map +1 -0
- package/dist/turns/cancel-turn.js +31 -0
- package/dist/turns/cancel-turn.js.map +1 -0
- package/dist/turns/compaction.d.ts +12 -0
- package/dist/turns/compaction.d.ts.map +1 -0
- package/dist/turns/compaction.js +55 -0
- package/dist/turns/compaction.js.map +1 -0
- package/dist/turns/end-turn.d.ts +15 -0
- package/dist/turns/end-turn.d.ts.map +1 -0
- package/dist/turns/end-turn.js +67 -0
- package/dist/turns/end-turn.js.map +1 -0
- package/dist/turns/history.d.ts +28 -0
- package/dist/turns/history.d.ts.map +1 -0
- package/dist/turns/history.js +47 -0
- package/dist/turns/history.js.map +1 -0
- package/dist/turns/lost-reply.d.ts +31 -0
- package/dist/turns/lost-reply.d.ts.map +1 -0
- package/dist/turns/lost-reply.js +43 -0
- package/dist/turns/lost-reply.js.map +1 -0
- package/dist/turns/message-blocks.d.ts +9 -0
- package/dist/turns/message-blocks.d.ts.map +1 -0
- package/dist/turns/message-blocks.js +25 -0
- package/dist/turns/message-blocks.js.map +1 -0
- package/dist/turns/model-context.d.ts +81 -0
- package/dist/turns/model-context.d.ts.map +1 -0
- package/dist/turns/model-context.js +46 -0
- package/dist/turns/model-context.js.map +1 -0
- package/dist/turns/model-info.d.ts +7 -0
- package/dist/turns/model-info.d.ts.map +1 -0
- package/dist/turns/model-info.js +10 -0
- package/dist/turns/model-info.js.map +1 -0
- package/dist/turns/model-retry.d.ts +3 -0
- package/dist/turns/model-retry.d.ts.map +1 -0
- package/dist/turns/model-retry.js +23 -0
- package/dist/turns/model-retry.js.map +1 -0
- package/dist/turns/register-interruptions.d.ts +3 -0
- package/dist/turns/register-interruptions.d.ts.map +1 -0
- package/dist/turns/register-interruptions.js +31 -0
- package/dist/turns/register-interruptions.js.map +1 -0
- package/dist/turns/register-turns.d.ts +3 -0
- package/dist/turns/register-turns.d.ts.map +1 -0
- package/dist/turns/register-turns.js +66 -0
- package/dist/turns/register-turns.js.map +1 -0
- package/dist/turns/resolve.d.ts +7 -0
- package/dist/turns/resolve.d.ts.map +1 -0
- package/dist/turns/resolve.js +29 -0
- package/dist/turns/resolve.js.map +1 -0
- package/dist/turns/run-calls.d.ts +34 -0
- package/dist/turns/run-calls.d.ts.map +1 -0
- package/dist/turns/run-calls.js +99 -0
- package/dist/turns/run-calls.js.map +1 -0
- package/dist/turns/run-command.d.ts +26 -0
- package/dist/turns/run-command.d.ts.map +1 -0
- package/dist/turns/run-command.js +118 -0
- package/dist/turns/run-command.js.map +1 -0
- package/dist/turns/settle-calls.d.ts +17 -0
- package/dist/turns/settle-calls.d.ts.map +1 -0
- package/dist/turns/settle-calls.js +98 -0
- package/dist/turns/settle-calls.js.map +1 -0
- package/dist/turns/start-turn.d.ts +87 -0
- package/dist/turns/start-turn.d.ts.map +1 -0
- package/dist/turns/start-turn.js +40 -0
- package/dist/turns/start-turn.js.map +1 -0
- package/dist/turns/step.d.ts +8 -0
- package/dist/turns/step.d.ts.map +1 -0
- package/dist/turns/step.js +168 -0
- package/dist/turns/step.js.map +1 -0
- package/dist/ui/register-ui.d.ts +3 -0
- package/dist/ui/register-ui.d.ts.map +1 -0
- package/dist/ui/register-ui.js +75 -0
- package/dist/ui/register-ui.js.map +1 -0
- package/dist/web/components/call.css +2 -0
- package/dist/web/components/call.js +386 -0
- package/dist/web/components/connectors.css +2 -0
- package/dist/web/components/connectors.js +2403 -0
- package/dist/web/components/conversation.css +2 -0
- package/dist/web/components/conversation.js +4319 -0
- package/dist/web/components/mcp-sign-in.css +2 -0
- package/dist/web/components/mcp-sign-in.js +265 -0
- package/dist/web/components/model.css +2 -0
- package/dist/web/components/model.js +545 -0
- package/dist/web/components/question.css +2 -0
- package/dist/web/components/question.js +321 -0
- package/dist/web/components/sessions.css +2 -0
- package/dist/web/components/sessions.js +264 -0
- package/docs/connectors.md +86 -0
- package/docs/sections.md +27 -0
- package/locales/ar.json +418 -0
- package/locales/en.json +418 -0
- package/package.json +70 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ProblemError } from '@kvman/sdk';
|
|
2
|
+
import { UnauthorizedError } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
3
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
4
|
+
import { StreamableHTTPClientTransport, StreamableHTTPError } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
5
|
+
import { OAuthError } from '@modelcontextprotocol/sdk/server/auth/errors.js';
|
|
6
|
+
import { commandTransport } from "./command-transport.js";
|
|
7
|
+
import { oauthProvider, registeredRedirect } from "./oauth-provider.js";
|
|
8
|
+
import { serverSecrets, withoutSecrets } from "./secrets.js";
|
|
9
|
+
async function open(ctx, server, secrets) {
|
|
10
|
+
if ('command' in server) {
|
|
11
|
+
const command = commandTransport({ command: server.command, args: server.args, cwd: ctx.job.workspace.path, env: secrets });
|
|
12
|
+
return { transport: command, command };
|
|
13
|
+
}
|
|
14
|
+
// The client's class declares `sessionId` as `string | undefined`, which its own `Transport` doesn't take under
|
|
15
|
+
// `exactOptionalPropertyTypes`; it is the transport the client is written for.
|
|
16
|
+
// A server the person signed in to is called with its tokens, which are refreshed when they have expired.
|
|
17
|
+
const redirectUrl = await registeredRedirect(ctx, server.name);
|
|
18
|
+
const signedIn = redirectUrl === undefined ? {} : { authProvider: oauthProvider(ctx, server.name, { redirectUrl, step: 'call' }) };
|
|
19
|
+
const transport = new StreamableHTTPClientTransport(new URL(server.url), { requestInit: { headers: secrets }, ...signedIn });
|
|
20
|
+
return { transport };
|
|
21
|
+
}
|
|
22
|
+
// The server refused the call for lack of a sign-in it takes: no tokens, or tokens it no longer refreshes.
|
|
23
|
+
const isUnauthorized = (error) => error instanceof UnauthorizedError || error instanceof OAuthError || (error instanceof StreamableHTTPError && error.code === 401);
|
|
24
|
+
// Why a connection failed, for the person and the model: the error's message, then the last of what a command wrote
|
|
25
|
+
// to its error output, with every secret value taken out.
|
|
26
|
+
function failure(server, error, opened, secrets, timedOutAfterMs) {
|
|
27
|
+
if (isUnauthorized(error))
|
|
28
|
+
return new ProblemError({ code: 'kvcoder/MCP_SIGN_IN_NEEDED', message: `The MCP server ${server.name} needs the person to sign in, on Coder's page under Extensions.`, params: { server: server.name } });
|
|
29
|
+
const said = timedOutAfterMs === undefined ? (error instanceof Error ? error.message : String(error)) : `it didn't answer within ${Math.ceil(timedOutAfterMs / 1000)} s`;
|
|
30
|
+
const reason = withoutSecrets([said, opened.command?.errorOutput() ?? ''].filter((part) => part !== '').join('\n'), secrets);
|
|
31
|
+
return new ProblemError({ code: 'kvcoder/MCP_CONNECT_FAILED', message: `The MCP server ${server.name} failed: ${reason}`, params: { server: server.name, reason } });
|
|
32
|
+
}
|
|
33
|
+
/** Connects to a server, runs `work`, and closes the connection; a failure is a Problem with the reason. */
|
|
34
|
+
export async function withServer(ctx, server, timeoutMs, work) {
|
|
35
|
+
const secrets = await serverSecrets(ctx, server);
|
|
36
|
+
const { version } = await ctx.exec('kernel.health.get', {});
|
|
37
|
+
const opened = await open(ctx, server, secrets);
|
|
38
|
+
const deadline = AbortSignal.timeout(timeoutMs);
|
|
39
|
+
const request = { signal: AbortSignal.any([ctx.job.signal, deadline]), timeout: timeoutMs, maxTotalTimeout: timeoutMs };
|
|
40
|
+
const client = new Client({ name: 'kvman', version });
|
|
41
|
+
try {
|
|
42
|
+
await client.connect(opened.transport, request);
|
|
43
|
+
return await work({ client, request });
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error instanceof ProblemError || ctx.job.signal.aborted)
|
|
47
|
+
throw error;
|
|
48
|
+
throw failure(server, error, opened, secrets, deadline.aborted ? timeoutMs : undefined);
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
await client.close();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=connect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/mcp/connect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Ctx } from '@kvman/sdk';
|
|
2
|
+
import { type OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
3
|
+
/** A server's sign-in secrets. */
|
|
4
|
+
export declare const oauthSecrets: (server: string) => {
|
|
5
|
+
client: string;
|
|
6
|
+
verifier: string;
|
|
7
|
+
tokens: string;
|
|
8
|
+
};
|
|
9
|
+
/** The redirect address the server's client registration was made for, when there is one. */
|
|
10
|
+
export declare function registeredRedirect(ctx: Ctx, server: string): Promise<string | undefined>;
|
|
11
|
+
/** What the client is used for: starting a sign-in, exchanging its code, or a call that may only refresh tokens. */
|
|
12
|
+
export type SignIn = {
|
|
13
|
+
redirectUrl: string;
|
|
14
|
+
step: 'start';
|
|
15
|
+
state: string;
|
|
16
|
+
open(authorizationUrl: URL): void;
|
|
17
|
+
} | {
|
|
18
|
+
redirectUrl: string;
|
|
19
|
+
step: 'finish';
|
|
20
|
+
} | {
|
|
21
|
+
redirectUrl: string;
|
|
22
|
+
step: 'call';
|
|
23
|
+
};
|
|
24
|
+
export declare function oauthProvider(ctx: Ctx, server: string, signIn: SignIn): OAuthClientProvider;
|
|
25
|
+
//# sourceMappingURL=oauth-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-provider.d.ts","sourceRoot":"","sources":["../../src/mcp/oauth-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAqB,KAAK,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAOvG,kCAAkC;AAClC,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM;;;;CAA+H,CAAC;AAU3K,6FAA6F;AAC7F,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE9F;AAED,oHAAoH;AACpH,MAAM,MAAM,MAAM,GACd;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,GAAG,IAAI,CAAA;CAAE,GACxF;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GACvC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAkC3F"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from '@kvman/sdk';
|
|
2
|
+
import { UnauthorizedError } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
3
|
+
// kvman as an OAuth client of one MCP server (plan 08 §8.5, ADR 0020, 8 and 16), over kvcoder's secrets: the client
|
|
4
|
+
// registration with the address it was made for, the code verifier of a sign-in under way, and the tokens. A tool
|
|
5
|
+
// call refreshes tokens but never sends the person to a browser: that is what a sign-in from the server's row does.
|
|
6
|
+
/** A server's sign-in secrets. */
|
|
7
|
+
export const oauthSecrets = (server) => ({ client: `mcp.${server}.oauth.client`, verifier: `mcp.${server}.oauth.verifier`, tokens: `mcp.${server}.oauth.tokens` });
|
|
8
|
+
const clientSchema = z.object({ redirectUrl: z.string(), information: z.looseObject({ client_id: z.string() }) });
|
|
9
|
+
const tokensSchema = z.looseObject({ access_token: z.string(), token_type: z.string() });
|
|
10
|
+
async function stored(ctx, name, schema) {
|
|
11
|
+
const value = await ctx.secrets.get(name);
|
|
12
|
+
return value === undefined ? undefined : schema.parse(JSON.parse(value));
|
|
13
|
+
}
|
|
14
|
+
/** The redirect address the server's client registration was made for, when there is one. */
|
|
15
|
+
export async function registeredRedirect(ctx, server) {
|
|
16
|
+
return (await stored(ctx, oauthSecrets(server).client, clientSchema))?.redirectUrl;
|
|
17
|
+
}
|
|
18
|
+
export function oauthProvider(ctx, server, signIn) {
|
|
19
|
+
const names = oauthSecrets(server);
|
|
20
|
+
return {
|
|
21
|
+
redirectUrl: signIn.redirectUrl,
|
|
22
|
+
clientMetadata: { client_name: 'kvman', redirect_uris: [signIn.redirectUrl], grant_types: ['authorization_code', 'refresh_token'], response_types: ['code'], token_endpoint_auth_method: 'none' },
|
|
23
|
+
...(signIn.step === 'start' ? { state: () => signIn.state } : {}),
|
|
24
|
+
// A registration made for another address (kvman on another port) can't be used with this one.
|
|
25
|
+
clientInformation: async () => {
|
|
26
|
+
const client = await stored(ctx, names.client, clientSchema);
|
|
27
|
+
return client?.redirectUrl === signIn.redirectUrl ? client.information : undefined;
|
|
28
|
+
},
|
|
29
|
+
// A call never registers kvman with a server: only a sign-in the person started does.
|
|
30
|
+
...(signIn.step === 'call' ? {} : { saveClientInformation: (information) => ctx.secrets.set(names.client, JSON.stringify({ redirectUrl: signIn.redirectUrl, information })) }),
|
|
31
|
+
tokens: async () => (await stored(ctx, names.tokens, tokensSchema)),
|
|
32
|
+
saveTokens: (tokens) => ctx.secrets.set(names.tokens, JSON.stringify(tokens)),
|
|
33
|
+
saveCodeVerifier: async (verifier) => {
|
|
34
|
+
if (signIn.step === 'start')
|
|
35
|
+
await ctx.secrets.set(names.verifier, verifier);
|
|
36
|
+
},
|
|
37
|
+
codeVerifier: async () => {
|
|
38
|
+
const verifier = await ctx.secrets.get(names.verifier);
|
|
39
|
+
if (verifier === undefined)
|
|
40
|
+
throw new UnauthorizedError('No sign-in is under way.');
|
|
41
|
+
return verifier;
|
|
42
|
+
},
|
|
43
|
+
redirectToAuthorization: (authorizationUrl) => {
|
|
44
|
+
if (signIn.step !== 'start')
|
|
45
|
+
throw new UnauthorizedError('The person must sign in.');
|
|
46
|
+
signIn.open(authorizationUrl);
|
|
47
|
+
},
|
|
48
|
+
// What the server no longer takes is forgotten, so the next attempt doesn't offer it again.
|
|
49
|
+
invalidateCredentials: async (scope) => {
|
|
50
|
+
if (scope === 'all' || scope === 'tokens')
|
|
51
|
+
await ctx.secrets.delete(names.tokens);
|
|
52
|
+
if (scope === 'all' || scope === 'client')
|
|
53
|
+
await ctx.secrets.delete(names.client);
|
|
54
|
+
if (scope === 'all' || scope === 'verifier')
|
|
55
|
+
await ctx.secrets.delete(names.verifier);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=oauth-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-provider.js","sourceRoot":"","sources":["../../src/mcp/oauth-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-mcp.d.ts","sourceRoot":"","sources":["../../src/mcp/register-mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAcvD,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CA6C1C"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ProblemError, z } from '@kvman/sdk';
|
|
2
|
+
import { userOnly } from "../sessions/session-lookup.js";
|
|
3
|
+
import { mcpServer } from "./servers.js";
|
|
4
|
+
import { listTools } from "./tools.js";
|
|
5
|
+
// What kvcoder's configuration asks about an MCP server (plan 08 §8.6, ADR 0020, 11 and 14): its state is checked when
|
|
6
|
+
// the dialog shows it, and never stored; and the person signs in to it from its row.
|
|
7
|
+
/** How long a check gives a server to start and list its tools. */
|
|
8
|
+
const checkTimeoutMs = 30_000;
|
|
9
|
+
const problemSchema = z.object({ code: z.string(), message: z.string(), params: z.record(z.string(), z.json()).exactOptional() });
|
|
10
|
+
const checkOutput = z.union([z.object({ status: z.literal('ready'), tools: z.number().int() }), z.object({ status: z.literal('signInNeeded') }), z.object({ status: z.literal('failed'), problem: problemSchema })]);
|
|
11
|
+
export function registerMcp(ctx) {
|
|
12
|
+
ctx.registerCommand('kvcoder.mcp.server.check', {
|
|
13
|
+
description: 'Connects to one MCP server of kvcoder.mcp.servers and says whether it is ready, with how many tools, needs a sign-in, or failed.',
|
|
14
|
+
input: z.strictObject({ name: z.string().min(1) }),
|
|
15
|
+
output: checkOutput,
|
|
16
|
+
public: true,
|
|
17
|
+
retries: 0,
|
|
18
|
+
handle: async ({ name }) => {
|
|
19
|
+
const server = await mcpServer(ctx, name);
|
|
20
|
+
const { withServer } = await import("./connect.js");
|
|
21
|
+
try {
|
|
22
|
+
return { status: 'ready', tools: (await withServer(ctx, server, checkTimeoutMs, listTools)).length };
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
if (!(error instanceof ProblemError) || ctx.job.signal.aborted)
|
|
26
|
+
throw error;
|
|
27
|
+
if (error.problem.code === 'kvcoder/MCP_SIGN_IN_NEEDED')
|
|
28
|
+
return { status: 'signInNeeded' };
|
|
29
|
+
if (error.problem.code === 'kvcoder/MCP_CONNECT_FAILED')
|
|
30
|
+
return { status: 'failed', problem: problemSchema.parse(error.problem) };
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
ctx.registerCommand('kvcoder.mcp.sign-in.start', {
|
|
36
|
+
description: "Starts the person's sign-in to an MCP server reached at a URL, and gives the address to open in the browser.",
|
|
37
|
+
input: z.strictObject({ name: z.string().min(1), redirectUrl: z.string().min(1) }),
|
|
38
|
+
output: z.object({ url: z.string() }),
|
|
39
|
+
public: true,
|
|
40
|
+
retries: 0,
|
|
41
|
+
handle: async ({ name, redirectUrl }) => {
|
|
42
|
+
userOnly(ctx, 'kvcoder.mcp.sign-in.start');
|
|
43
|
+
const { startSignIn } = await import("./sign-in.js");
|
|
44
|
+
return startSignIn(ctx, name, redirectUrl);
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
ctx.registerCommand('kvcoder.mcp.sign-in.finish', {
|
|
48
|
+
description: 'Finishes a started sign-in with the code the server sent back, and stores the tokens as secrets.',
|
|
49
|
+
input: z.strictObject({ state: z.string().min(1), code: z.string().min(1) }),
|
|
50
|
+
output: z.object({ name: z.string() }),
|
|
51
|
+
public: true,
|
|
52
|
+
retries: 0,
|
|
53
|
+
syncOnly: true,
|
|
54
|
+
handle: async ({ state, code }) => {
|
|
55
|
+
userOnly(ctx, 'kvcoder.mcp.sign-in.finish');
|
|
56
|
+
const { finishSignIn } = await import("./sign-in.js");
|
|
57
|
+
return finishSignIn(ctx, state, code);
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=register-mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-mcp.js","sourceRoot":"","sources":["../../src/mcp/register-mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Ctx } from '@kvman/sdk';
|
|
2
|
+
import type { McpServer } from './servers.ts';
|
|
3
|
+
/** The values a server is given, by variable or header name; a name without a secret is left out. */
|
|
4
|
+
export declare function serverSecrets(ctx: Ctx, server: McpServer): Promise<Record<string, string>>;
|
|
5
|
+
/** A text with every one of the values replaced by `***`, so a server's failure can't carry a secret out. */
|
|
6
|
+
export declare function withoutSecrets(text: string, values: Readonly<Record<string, string>>): string;
|
|
7
|
+
//# sourceMappingURL=secrets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../src/mcp/secrets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAK9C,qGAAqG;AACrG,wBAAsB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAQhG;AAED,6GAA6G;AAC7G,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CAI7F"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// A server's secret values (plan 08 §8.5, ADR 0020, 6): kvcoder's secrets `mcp.<server>.env.<VARIABLE>` and
|
|
2
|
+
// `mcp.<server>.header.<Header>`. They go to the server and nowhere else.
|
|
3
|
+
/** The values a server is given, by variable or header name; a name without a secret is left out. */
|
|
4
|
+
export async function serverSecrets(ctx, server) {
|
|
5
|
+
const [kind, names] = 'command' in server ? ['env', server.env] : ['header', server.headers];
|
|
6
|
+
const values = {};
|
|
7
|
+
for (const name of names) {
|
|
8
|
+
const value = await ctx.secrets.get(`mcp.${server.name}.${kind}.${name}`);
|
|
9
|
+
if (value !== undefined)
|
|
10
|
+
values[name] = value;
|
|
11
|
+
}
|
|
12
|
+
return values;
|
|
13
|
+
}
|
|
14
|
+
/** A text with every one of the values replaced by `***`, so a server's failure can't carry a secret out. */
|
|
15
|
+
export function withoutSecrets(text, values) {
|
|
16
|
+
return Object.values(values)
|
|
17
|
+
.filter((value) => value !== '')
|
|
18
|
+
.reduce((cleaned, value) => cleaned.replaceAll(value, '***'), text);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/mcp/secrets.ts"],"names":[],"mappings":"AAGA,4GAA4G;AAC5G,0EAA0E;AAE1E,qGAAqG;AACrG,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAQ,EAAE,MAAiB;IAC7D,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,SAAS,IAAI,MAAM,CAAC,CAAC,CAAE,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAW,CAAC,CAAC,CAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAW,CAAC;IACnH,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;QAC1E,IAAI,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IAChD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,MAAwC;IACnF,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;SACzB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC;SAC/B,MAAM,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z, type Ctx } from '@kvman/sdk';
|
|
2
|
+
/** One MCP server: a command, or an address. */
|
|
3
|
+
export declare const mcpServerSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
4
|
+
name: z.ZodString;
|
|
5
|
+
description: z.ZodString;
|
|
6
|
+
command: z.ZodString;
|
|
7
|
+
args: z.ZodArray<z.ZodString>;
|
|
8
|
+
env: z.ZodArray<z.ZodString>;
|
|
9
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
10
|
+
name: z.ZodString;
|
|
11
|
+
description: z.ZodString;
|
|
12
|
+
url: z.ZodString;
|
|
13
|
+
headers: z.ZodArray<z.ZodString>;
|
|
14
|
+
}, z.core.$strict>]>;
|
|
15
|
+
/** The `kvcoder.mcp.servers` setting: each server has its own name. */
|
|
16
|
+
export declare const mcpServersSchema: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
17
|
+
name: z.ZodString;
|
|
18
|
+
description: z.ZodString;
|
|
19
|
+
command: z.ZodString;
|
|
20
|
+
args: z.ZodArray<z.ZodString>;
|
|
21
|
+
env: z.ZodArray<z.ZodString>;
|
|
22
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
23
|
+
name: z.ZodString;
|
|
24
|
+
description: z.ZodString;
|
|
25
|
+
url: z.ZodString;
|
|
26
|
+
headers: z.ZodArray<z.ZodString>;
|
|
27
|
+
}, z.core.$strict>]>>;
|
|
28
|
+
export type McpServer = z.output<typeof mcpServerSchema>;
|
|
29
|
+
/** The servers of the job's workspace, in the setting's order. */
|
|
30
|
+
export declare function mcpServers(ctx: Ctx): Promise<McpServer[]>;
|
|
31
|
+
/** One server by name, or `kvcoder/MCP_SERVER_NOT_FOUND` naming the ones there are. */
|
|
32
|
+
export declare function mcpServer(ctx: Ctx, name: string): Promise<McpServer>;
|
|
33
|
+
//# sourceMappingURL=servers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"servers.d.ts","sourceRoot":"","sources":["../../src/mcp/servers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,CAAC,EAAE,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAkBvD,gDAAgD;AAChD,eAAO,MAAM,eAAe;;;;;;;;;;;oBAAkD,CAAC;AAE/E,uEAAuE;AACvE,eAAO,MAAM,gBAAgB;;;;;;;;;;;qBAAyJ,CAAC;AAEvL,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,eAAe,CAAC,CAAC;AAEzD,kEAAkE;AAClE,wBAAsB,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAE/D;AAED,uFAAuF;AACvF,wBAAsB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAM1E"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ProblemError, z } from '@kvman/sdk';
|
|
2
|
+
import { wordSchema } from "../schemas/registry.js";
|
|
3
|
+
// The MCP servers the person added (plan 08 §8.5, ADR 0020, 4, 6, and 9): the setting `kvcoder.mcp.servers`. A server
|
|
4
|
+
// is a command that speaks MCP on its standard input and output, or an address reached over Streamable HTTP. `env` and
|
|
5
|
+
// `headers` hold names only: each value is one of kvcoder's secrets.
|
|
6
|
+
const text = z.string().min(1);
|
|
7
|
+
const variableName = z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/, 'Use letters, digits, and _, not starting with a digit.');
|
|
8
|
+
const headerName = z.string().regex(/^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/, 'Use the characters of an HTTP header name.');
|
|
9
|
+
function isHttpAddress(value) {
|
|
10
|
+
return URL.canParse(value) && ['http:', 'https:'].includes(new URL(value).protocol);
|
|
11
|
+
}
|
|
12
|
+
const commandServerSchema = z.strictObject({ name: wordSchema, description: text, command: text, args: z.array(z.string()), env: z.array(variableName) });
|
|
13
|
+
const urlServerSchema = z.strictObject({ name: wordSchema, description: text, url: z.string().refine(isHttpAddress, 'Give an http or https address.'), headers: z.array(headerName) });
|
|
14
|
+
/** One MCP server: a command, or an address. */
|
|
15
|
+
export const mcpServerSchema = z.union([commandServerSchema, urlServerSchema]);
|
|
16
|
+
/** The `kvcoder.mcp.servers` setting: each server has its own name. */
|
|
17
|
+
export const mcpServersSchema = z.array(mcpServerSchema).refine((servers) => new Set(servers.map((server) => server.name)).size === servers.length, 'Each server needs its own name.');
|
|
18
|
+
/** The servers of the job's workspace, in the setting's order. */
|
|
19
|
+
export async function mcpServers(ctx) {
|
|
20
|
+
return mcpServersSchema.parse(await ctx.settings.get('kvcoder.mcp.servers'));
|
|
21
|
+
}
|
|
22
|
+
/** One server by name, or `kvcoder/MCP_SERVER_NOT_FOUND` naming the ones there are. */
|
|
23
|
+
export async function mcpServer(ctx, name) {
|
|
24
|
+
const servers = await mcpServers(ctx);
|
|
25
|
+
const found = servers.find((server) => server.name === name);
|
|
26
|
+
if (found !== undefined)
|
|
27
|
+
return found;
|
|
28
|
+
const names = servers.map((server) => server.name).join(', ');
|
|
29
|
+
throw new ProblemError({ code: 'kvcoder/MCP_SERVER_NOT_FOUND', message: `There is no MCP server ${name}. ${names === '' ? 'No server is set up.' : `The servers are: ${names}.`}`, params: { server: name } });
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=servers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"servers.js","sourceRoot":"","sources":["../../src/mcp/servers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from '@kvman/sdk';
|
|
2
|
+
/** A sign-in to an MCP server that was started and not yet finished (plan 08 §8.5): kept in the global store, by its state. */
|
|
3
|
+
export declare const signInDocSchema: z.ZodObject<{
|
|
4
|
+
state: z.ZodString;
|
|
5
|
+
server: z.ZodString;
|
|
6
|
+
url: z.ZodString;
|
|
7
|
+
redirectUrl: z.ZodString;
|
|
8
|
+
at: z.ZodNumber;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
//# sourceMappingURL=sign-in-record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-in-record.d.ts","sourceRoot":"","sources":["../../src/mcp/sign-in-record.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAE/B,+HAA+H;AAC/H,eAAO,MAAM,eAAe;;;;;;iBAAgH,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { z } from '@kvman/sdk';
|
|
2
|
+
/** A sign-in to an MCP server that was started and not yet finished (plan 08 §8.5): kept in the global store, by its state. */
|
|
3
|
+
export const signInDocSchema = z.object({ state: z.string(), server: z.string(), url: z.string(), redirectUrl: z.string(), at: z.number() });
|
|
4
|
+
//# sourceMappingURL=sign-in-record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-in-record.js","sourceRoot":"","sources":["../../src/mcp/sign-in-record.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAE/B,+HAA+H;AAC/H,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Ctx } from '@kvman/sdk';
|
|
2
|
+
/** Whether an address is kvcoder's sign-in page on this computer: nothing else may receive a code. */
|
|
3
|
+
export declare function isSignInPage(address: string): boolean;
|
|
4
|
+
/** Starts a sign-in and gives the address the person opens. */
|
|
5
|
+
export declare function startSignIn(ctx: Ctx, name: string, redirectUrl: string): Promise<{
|
|
6
|
+
url: string;
|
|
7
|
+
}>;
|
|
8
|
+
/** Finishes a started sign-in with the code the server sent back, and stores the tokens. */
|
|
9
|
+
export declare function finishSignIn(ctx: Ctx, state: string, code: string): Promise<{
|
|
10
|
+
name: string;
|
|
11
|
+
}>;
|
|
12
|
+
//# sourceMappingURL=sign-in.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-in.d.ts","sourceRoot":"","sources":["../../src/mcp/sign-in.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAiBpD,sGAAsG;AACtG,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAIrD;AAOD,+DAA+D;AAC/D,wBAAsB,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBvG;AAED,4FAA4F;AAC5F,wBAAsB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBnG"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { ProblemError } from '@kvman/sdk';
|
|
3
|
+
import { auth } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
4
|
+
import { invalid } from "../problems.js";
|
|
5
|
+
import { records } from "../store/collections.js";
|
|
6
|
+
import { oauthProvider, oauthSecrets } from "./oauth-provider.js";
|
|
7
|
+
import { mcpServer } from "./servers.js";
|
|
8
|
+
// Signing in to an MCP server (plan 08 §8.5, ADR 0020, 8, 11, and 16). `start` registers kvman with the server when it
|
|
9
|
+
// hasn't yet and gives the address to open; the server sends the browser back to kvcoder's sign-in page, which calls
|
|
10
|
+
// `finish` with the code. A started sign-in is kept in the global store for 10 minutes, so finishing needs no workspace.
|
|
11
|
+
const signInLifeMs = 10 * 60_000;
|
|
12
|
+
// A job id is a UUIDv7: its first 48 bits are the kernel's clock in milliseconds, so a sign-in's age follows that clock.
|
|
13
|
+
const jobTime = (ctx) => Number.parseInt(ctx.job.id.replaceAll('-', '').slice(0, 12), 16);
|
|
14
|
+
const redirectPath = '/kvcoder/mcp-sign-in';
|
|
15
|
+
/** Whether an address is kvcoder's sign-in page on this computer: nothing else may receive a code. */
|
|
16
|
+
export function isSignInPage(address) {
|
|
17
|
+
if (!URL.canParse(address))
|
|
18
|
+
return false;
|
|
19
|
+
const url = new URL(address);
|
|
20
|
+
return url.protocol === 'http:' && ['127.0.0.1', 'localhost'].includes(url.hostname) && url.pathname === redirectPath && url.search === '' && url.hash === '' && url.username === '' && url.password === '';
|
|
21
|
+
}
|
|
22
|
+
const failed = (error) => {
|
|
23
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
24
|
+
return new ProblemError({ code: 'kvcoder/MCP_SIGN_IN_FAILED', message: `The sign-in failed: ${reason}`, params: { reason } });
|
|
25
|
+
};
|
|
26
|
+
/** Starts a sign-in and gives the address the person opens. */
|
|
27
|
+
export async function startSignIn(ctx, name, redirectUrl) {
|
|
28
|
+
if (!isSignInPage(redirectUrl))
|
|
29
|
+
throw invalid(`The redirect address must be http://127.0.0.1:<port>${redirectPath}, or the same on localhost.`);
|
|
30
|
+
const server = await mcpServer(ctx, name);
|
|
31
|
+
if (!('url' in server))
|
|
32
|
+
throw invalid(`${name} runs as a command; only a server reached at a URL is signed in to.`, { server: name });
|
|
33
|
+
// Whatever was left of an earlier sign-in would be used in place of a new one.
|
|
34
|
+
await ctx.secrets.delete(oauthSecrets(name).tokens);
|
|
35
|
+
const state = randomUUID();
|
|
36
|
+
let opened;
|
|
37
|
+
try {
|
|
38
|
+
await auth(oauthProvider(ctx, name, { redirectUrl, step: 'start', state, open: (authorizationUrl) => void (opened = authorizationUrl) }), { serverUrl: server.url });
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if (error instanceof ProblemError || ctx.job.signal.aborted)
|
|
42
|
+
throw error;
|
|
43
|
+
throw failed(error);
|
|
44
|
+
}
|
|
45
|
+
if (opened === undefined)
|
|
46
|
+
throw failed(new Error('the server gave no address to sign in at'));
|
|
47
|
+
await records(ctx.store).signIns.insert({ state, server: name, url: server.url, redirectUrl, at: jobTime(ctx) });
|
|
48
|
+
return { url: opened.href };
|
|
49
|
+
}
|
|
50
|
+
/** Finishes a started sign-in with the code the server sent back, and stores the tokens. */
|
|
51
|
+
export async function finishSignIn(ctx, state, code) {
|
|
52
|
+
const { signIns } = records(ctx.store);
|
|
53
|
+
for (const old of await signIns.find({}, { limit: 1000 }))
|
|
54
|
+
if (old.at < jobTime(ctx) - signInLifeMs)
|
|
55
|
+
await signIns.delete(old.id);
|
|
56
|
+
const [started] = await signIns.find({ state }, { limit: 1 });
|
|
57
|
+
if (started === undefined)
|
|
58
|
+
throw failed(new Error('it was not started here, was already finished, or took more than 10 minutes'));
|
|
59
|
+
await signIns.delete(started.id);
|
|
60
|
+
try {
|
|
61
|
+
const result = await auth(oauthProvider(ctx, started.server, { redirectUrl: started.redirectUrl, step: 'finish' }), { serverUrl: started.url, authorizationCode: code });
|
|
62
|
+
if (result !== 'AUTHORIZED')
|
|
63
|
+
throw new Error('the server did not accept the code');
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error instanceof ProblemError || ctx.job.signal.aborted)
|
|
67
|
+
throw error;
|
|
68
|
+
throw failed(error);
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
await ctx.secrets.delete(oauthSecrets(started.server).verifier);
|
|
72
|
+
}
|
|
73
|
+
return { name: started.server };
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=sign-in.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-in.js","sourceRoot":"","sources":["../../src/mcp/sign-in.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from '@kvman/sdk';
|
|
2
|
+
import type { Connection } from './connect.ts';
|
|
3
|
+
declare const toolSchema: z.ZodObject<{
|
|
4
|
+
name: z.ZodString;
|
|
5
|
+
description: z.ZodOptional<z.ZodString>;
|
|
6
|
+
inputSchema: z.ZodJSONSchema;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
export type McpTool = z.output<typeof toolSchema>;
|
|
9
|
+
/** Every tool of the server, through all of its pages. */
|
|
10
|
+
export declare function listTools({ client, request }: Connection): Promise<McpTool[]>;
|
|
11
|
+
/** The server's tool by name, or `NOT_FOUND` naming the tools it has. */
|
|
12
|
+
export declare function toolNamed(server: string, tools: readonly McpTool[], name: string): McpTool;
|
|
13
|
+
/** A tool's result: its text blocks joined by a blank line, a block of another kind as `[<kind> omitted]`, and whether the tool says it failed. */
|
|
14
|
+
export declare function resultText(result: unknown): {
|
|
15
|
+
text: string;
|
|
16
|
+
isError: boolean;
|
|
17
|
+
};
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAI/C,QAAA,MAAM,UAAU;;;;iBAA4F,CAAC;AAE7G,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAElD,0DAA0D;AAC1D,wBAAsB,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CASnF;AAED,yEAAyE;AACzE,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAI1F;AAKD,mJAAmJ;AACnJ,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAI9E"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from '@kvman/sdk';
|
|
2
|
+
import { notFound } from "../problems.js";
|
|
3
|
+
// A server's tools and a call's result as the model reads them (plan 08 §8.5, ADR 0020, 10 and 16).
|
|
4
|
+
const toolSchema = z.object({ name: z.string(), description: z.string().optional(), inputSchema: z.json() });
|
|
5
|
+
/** Every tool of the server, through all of its pages. */
|
|
6
|
+
export async function listTools({ client, request }) {
|
|
7
|
+
const tools = [];
|
|
8
|
+
let cursor;
|
|
9
|
+
do {
|
|
10
|
+
const page = await client.listTools(cursor === undefined ? {} : { cursor }, request);
|
|
11
|
+
tools.push(...z.array(toolSchema).parse(page.tools));
|
|
12
|
+
cursor = page.nextCursor;
|
|
13
|
+
} while (cursor !== undefined);
|
|
14
|
+
return tools;
|
|
15
|
+
}
|
|
16
|
+
/** The server's tool by name, or `NOT_FOUND` naming the tools it has. */
|
|
17
|
+
export function toolNamed(server, tools, name) {
|
|
18
|
+
const found = tools.find((tool) => tool.name === name);
|
|
19
|
+
if (found !== undefined)
|
|
20
|
+
return found;
|
|
21
|
+
throw notFound(`${server} has no tool ${name}. Its tools are: ${tools.map((tool) => tool.name).join(', ')}.`, { server, tool: name });
|
|
22
|
+
}
|
|
23
|
+
const blockSchema = z.looseObject({ type: z.string(), text: z.string().optional() });
|
|
24
|
+
const resultSchema = z.looseObject({ content: z.array(blockSchema).default([]), isError: z.boolean().optional() });
|
|
25
|
+
/** A tool's result: its text blocks joined by a blank line, a block of another kind as `[<kind> omitted]`, and whether the tool says it failed. */
|
|
26
|
+
export function resultText(result) {
|
|
27
|
+
const { content, isError } = resultSchema.parse(result);
|
|
28
|
+
const text = content.map((block) => (block.type === 'text' && block.text !== undefined ? block.text : `[${block.type} omitted]`)).join('\n\n');
|
|
29
|
+
return { text, isError: isError === true };
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAC/B,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG1C,oGAAoG;AAEpG,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAI7G,0DAA0D;AAC1D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAc;IAC7D,MAAM,KAAK,GAAc,EAAE,CAAC;IAC5B,IAAI,MAA0B,CAAC;IAC/B,GAAG,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,CAAC;QACrF,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACrD,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;IAC3B,CAAC,QAAQ,MAAM,KAAK,SAAS,EAAE;IAC/B,OAAO,KAAK,CAAC;AACf,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,KAAyB,EAAE,IAAY;IAC/E,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACvD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACtC,MAAM,QAAQ,CAAC,GAAG,MAAM,gBAAgB,IAAI,oBAAoB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AACxI,CAAC;AAED,MAAM,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACrF,MAAM,YAAY,GAAG,CAAC,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAEnH,mJAAmJ;AACnJ,MAAM,UAAU,UAAU,CAAC,MAAe;IACxC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/I,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Ctx, File } from '@kvman/sdk';
|
|
2
|
+
/** A file's name as it is saved: its base name, with only letters, digits, space, and `._-()` kept. */
|
|
3
|
+
export declare function safeName(name: string): string;
|
|
4
|
+
/** Saves the files into the workspace folder and gives their paths in it; a user upload leaves the kernel's files. */
|
|
5
|
+
export declare function saveAttachments(ctx: Ctx, files: readonly File[]): Promise<string[]>;
|
|
6
|
+
/** The message's text with its saved files named at its end. */
|
|
7
|
+
export declare function withAttachments(text: string, saved: readonly string[]): string;
|
|
8
|
+
//# sourceMappingURL=attachments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachments.d.ts","sourceRoot":"","sources":["../../src/messages/attachments.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAW5C,uGAAuG;AACvG,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7C;AAeD,sHAAsH;AACtH,wBAAsB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAUzF;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAE9E"}
|