@xopcai/xopc 0.0.387 → 0.0.389
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/dist/browser-ext/_locales/en/messages.json +6 -1
- package/dist/browser-ext/_locales/zh_CN/messages.json +6 -1
- package/dist/browser-ext/dist/assets/{page-context-BeworyNB.js → page-context-A5RCibM_.js} +1 -1
- package/dist/browser-ext/dist/background.js +1 -1
- package/dist/browser-ext/dist/sidepanel.html +1 -1
- package/dist/browser-ext/dist/sidepanel.js +98 -53
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/src/plugin.js +5 -3
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-CB2X4Gmu.js → activity-store-dvik6t7Z.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Bv8M5ygD.js → agent-avatar-dicebear-bWMd5TDC.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-UBy01-65.js → agent-defaults-settings-panel-Ds0Ue2FB.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-plugin-dialog-Q9guA8kU.js → agent-plugin-dialog-UunIxc1q.js} +1 -1
- package/dist/gateway/static/root/assets/{agents-yfJFubD0.js → agents-BLRM4o-U.js} +3 -3
- package/dist/gateway/static/root/assets/{agents-admin-api-BkULgC6Q.js → agents-admin-api-BlNGyXpm.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-Cdyad8c1.js → app-management-settings-panel-Dmy828Pe.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DPPvnKH_.js → appearance-settings-CUAdx44v.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-Bn_jwaeA.js → apps-page-D5zDB6gp.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-De0ND0oA.js → archive-plugin-Du6dJNcl.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-CAB2sLJ5.js → automations-page-BO8Ig5Z4.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-workspace-CYRUhhH4.js → automations-workspace-UcCneEs3.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-Do535ZGW.js → binary-plugins-D7VJjwnr.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-B9DmMEa8.js → block-editor-CaJlWTAn.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automation-inputs-B9M1RYTm.js → browser-automation-inputs-iyMBJmQX.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automations-page-BHAWpZE2.js → browser-automations-page-BjvQnYfO.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-settings-page-BG_17NcQ.js → browser-settings-page-D5ZghI28.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-BX1rCiVm.js → capabilities-CEH1AnXc.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-CW389yo6.js → capabilities-MCKRMZDK.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-page-BAnBYWlY.js → capabilities-page-MC8qIrXo.js} +2 -2
- package/dist/gateway/static/root/assets/{capabilities-settings-panel-Ca-d6lXk.js → capabilities-settings-panel-Blz3hEzp.js} +1 -1
- package/dist/gateway/static/root/assets/{capability-header-actions-B3TL8TcF.js → capability-header-actions-BIA0Lwt5.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-BadpS-nq.js → channels-DSg_iCVC.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-C_vntFpP.js → chat-terminal-dock-C97SJEwd.js} +1 -1
- package/dist/gateway/static/root/assets/{computer-settings-page-B-5kxk70.js → computer-settings-page-DvY3zgyY.js} +1 -1
- package/dist/gateway/static/root/assets/{connector-service-page-DTnfpLHL.js → connector-service-page-St2-Fj3y.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-DXk-GAsd.js +1 -0
- package/dist/gateway/static/root/assets/{date-picker-D5zYeC8q.js → date-picker-C0-D80ny.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-D72vT-tb.js → dependency-picker-CNd7mwMU.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-DvoeVPf_.js → desktop-pet-C-2wDANn.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-Dfb392hs.js → desktop-pet-settings-DyhxLrdJ.js} +1 -1
- package/dist/gateway/static/root/assets/{device-pairing-wizard-B06Sqn5D.js → device-pairing-wizard-BeSuq__I.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-CA3H3bc-.js → directory-picker-path-field-CNivVIPT.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-B0wTBCx4.js → extension-debug-page-CGYO3JPw.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BeHiXhB1.js → extension-page-Dc51ALAg.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-provider-CJZ5EVpQ.js → extension-provider-BXPILdlw.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-Q88-LFCJ.js → extension-settings-page-jYu6qpY2.js} +1 -1
- package/dist/gateway/static/root/assets/{fallback-models-BXoPCvzq.js → fallback-models-CoyzvDo7.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-D0tBjSgj.js → gateway-config-swr-Bc2MytsF.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-realtime-BnHraJ3O.js → gateway-realtime-BFK-vlME.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-realtime-store-C3vH-Iup.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-settings-IICLMGDI.js → gateway-settings-JlT1dlSj.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-C1DQsIH3.js → gateway-startup-retry-BDPMttPx.js} +1 -1
- package/dist/gateway/static/root/assets/{highlighted-body-KQOG7T2V-D336so8z.js → highlighted-body-KQOG7T2V-DAlRGMge.js} +1 -1
- package/dist/gateway/static/root/assets/{home-page--MvqsFhQ.js → home-page-DOVl8s-1.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-DodU6GNC.js → image-generation-api-BZBiYDmV.js} +1 -1
- package/dist/gateway/static/root/assets/{imports-page-muV1SduS.js → imports-page-DgdBTp_0.js} +1 -1
- package/dist/gateway/static/root/assets/{index-D0qMv3jf.js → index-CmC8JkSM.js} +108 -108
- package/dist/gateway/static/root/assets/index-Dgzc0oBu.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-i1sDWcwl.js → keyboard-shortcuts-settings-BYYC9Qmw.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-DY9tXEO6.js → local-app-workbench-page-BKZfn-MS.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-BHD73STy.js → local-apps-page-BU8pUsVM.js} +1 -1
- package/dist/gateway/static/root/assets/{local-session-drafts-Be4BGM4Z.js → local-session-drafts-kFc_MAA9.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-uRu_DsWm.js → locale-store-Dr43FCty.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-DsPpe8Ws.js → logs-page-BSepiACn.js} +1 -1
- package/dist/gateway/static/root/assets/{management-settings-Buwi2wQE.js → management-settings-dE_ykPNY.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-CBjl-XEc.js → markdown-view-CdKlPjJM.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-BombFqsX.js → media-plugins-DE9zt88i.js} +1 -1
- package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-65SE6j-_.js +1 -0
- package/dist/gateway/static/root/assets/messages-DlTNQI92.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-cache-C7FAsEe_.js +1 -0
- package/dist/gateway/static/root/assets/{note-detail-panel-D8n80Gbr.js → note-detail-panel-D9oqhdyk.js} +3 -3
- package/dist/gateway/static/root/assets/{notes-api-BlGP533W.js → notes-api-BHouNL6-.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-Btf-jSS_.js → notes-page-Bd4_7ph8.js} +1 -1
- package/dist/gateway/static/root/assets/{page-context-capture-button-97RL8Gc7.js → page-context-capture-button-TQr8NnSc.js} +1 -1
- package/dist/gateway/static/root/assets/{personal-page-B04L8Oz5.js → personal-page-BvWzq4Wp.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-9zEDvZa7.js → product-open-page-BEl6syFp.js} +1 -1
- package/dist/gateway/static/root/assets/{product-preview-content-DynBrIXq.js → product-preview-content-BxSHnbqz.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-BM7MsoVA.js → project-detail-page-D-qkIXVT.js} +1 -1
- package/dist/gateway/static/root/assets/{projects-page-pcyeEJnz.js → projects-page-BQtw1Dfn.js} +1 -1
- package/dist/gateway/static/root/assets/{registry-api-CYqA7bfl.js → registry-api-BD5IgDOA.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-CphyTu22.js → remote-access-hub-CYFNz0Jc.js} +1 -1
- package/dist/gateway/static/root/assets/{runtime-tools-api-zzoxjSuR.js → runtime-tools-api-CjTRoQWT.js} +1 -1
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DPafoO0G.js → runtime-tools-settings-panel-Qq_NyYx_.js} +1 -1
- package/dist/gateway/static/root/assets/{scenes-page-j97FrDRW.js → scenes-page-hGr-ppYk.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-CuJNwKHO.js → schema-form-ByG-R6N2.js} +1 -1
- package/dist/gateway/static/root/assets/{send-session-input-C293-Hbx.js → send-session-input-UAVStisp.js} +1 -1
- package/dist/gateway/static/root/assets/{session-api-CzVTrG8n.js → session-api-DvgEiNRS.js} +1 -1
- package/dist/gateway/static/root/assets/session-manager-BOb1tC_Z.js +16 -0
- package/dist/gateway/static/root/assets/{sessions-page-D8t_8fMl.js → sessions-page-CpX1Rluw.js} +1 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-D2s_MlxR.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-DS9DMYUe.js → settings-page-C1e9m23j.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-DRDvm9yZ.js → setup-status-panel-BiHRYDHq.js} +1 -1
- package/dist/gateway/static/root/assets/{share-link-dialog-BKGI8Kr0.js → share-link-dialog-kE_6v5Dp.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-BF2WaO43.js → share-preview-page-BT-_yR1h.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-api-B0HlMAzi.js → shares-api-Dg_SqHQE.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-settings-DQTQZu6V.js → shares-settings-DfcAu08T.js} +1 -1
- package/dist/gateway/static/root/assets/{skill-api-DzVa7G-O.js → skill-api-BslUYMnX.js} +1 -1
- package/dist/gateway/static/root/assets/{skill-reload-api-CEJx5rPd.js → skill-reload-api-BQ2rTOP1.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-CfJIjRdS.js → skills-page-CvKc5nBN.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-Bzhqed-a.js → system-settings-panel-GpbPfWwo.js} +1 -1
- package/dist/gateway/static/root/assets/{task-detail-page-BYQFC0-U.js → task-detail-page-5B5ZVAu0.js} +1 -1
- package/dist/gateway/static/root/assets/{task-expandable-content-C9ohICpw.js → task-expandable-content-DJrrEBB4.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-BUfzeDvL.js → theme-store-BKpYnggg.js} +1 -1
- package/dist/gateway/static/root/assets/{tracing-settings-page-C2q5B3Kp.js → tracing-settings-page-D71w7dwV.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-DrgpZ81I.js → tunnel-api-BV46CvS8.js} +1 -1
- package/dist/gateway/static/root/assets/{usage-page-Drk8FWnj.js → usage-page-rMuwNpJi.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-DgbCgsao.js → use-autosave-CzyqRffr.js} +1 -1
- package/dist/gateway/static/root/assets/{use-composer-attachments-rgW7h4sD.js → use-composer-attachments-Dviq-1f6.js} +1 -1
- package/dist/gateway/static/root/assets/{use-file-preview-expanded-DSKIxfz9.js → use-file-preview-expanded-D5Kk7Hon.js} +2 -2
- package/dist/gateway/static/root/assets/{user-model-page-07t2-nFE.js → user-model-page-Dhqw3v_u.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-4AIkbm9R.js → voice-api-key-field-DWtbmacd.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-Kw1pYlLN.js → voice-config-api-DnIjZm_9.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-TQ5bjVot.js → work-discovery-overlay-ChEG71hz.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-C9HP2uGG.js → workflow-run-setup-panel-pdiRKLxP.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-DK01JRI1.js → workflows-page-D9LMxINt.js} +1 -1
- package/dist/gateway/static/root/assets/{workspace-api-JWHOFos6.js → workspace-api-CZDvu7uA.js} +2 -2
- package/dist/gateway/static/root/assets/{xopc-cloud-account-card-B-BhQdAf.js → xopc-cloud-account-card-CbUgg1SK.js} +1 -1
- package/dist/gateway/static/root/index.html +27 -27
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/clarifications.js +79 -2
- package/dist/packages/realtime-protocol/src/voice.js +13 -2
- package/dist/src/agent/agent-manager.js +12 -8
- package/dist/src/agent/background-review/prompts.js +4 -0
- package/dist/src/agent/background-review/run-background-review.js +43 -5
- package/dist/src/agent/embedded/run-turn.js +1 -1
- package/dist/src/agent/embedded/session-runner.d.ts +4 -3
- package/dist/src/agent/embedded/session-runner.js +6 -1
- package/dist/src/agent/external-tools/cliProvider.js +1 -1
- package/dist/src/agent/external-tools/composio-provider.js +2 -2
- package/dist/src/agent/external-tools/endpoint-provider.js +2 -2
- package/dist/src/agent/mcp/connection-drafts.d.ts +50 -0
- package/dist/src/agent/mcp/connection-drafts.js +278 -0
- package/dist/src/agent/mcp/connection-setup.d.ts +5 -2
- package/dist/src/agent/mcp/connection-setup.js +7 -5
- package/dist/src/agent/mcp/credential-store.d.ts +6 -0
- package/dist/src/agent/mcp/credential-store.js +24 -0
- package/dist/src/agent/mcp/native-mcp.d.ts +6 -1
- package/dist/src/agent/mcp/native-mcp.js +6 -0
- package/dist/src/agent/mcp/tool-catalog.d.ts +7 -2
- package/dist/src/agent/mcp/tool-catalog.js +25 -15
- package/dist/src/agent/service/process-direct-streaming.js +1 -1
- package/dist/src/agent/service.js +2 -2
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/tools/clarify-tool.d.ts +2 -3
- package/dist/src/agent/tools/clarify-tool.js +15 -9
- package/dist/src/agent/tools/cli-clarify.d.ts +0 -3
- package/dist/src/agent/tools/cli-clarify.js +18 -32
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/personal-read-tool.js +1 -1
- package/dist/src/agent/tools/personal-task-tool.d.ts +4 -4
- package/dist/src/agent/tools/xopc-use-tool.js +2 -2
- package/dist/src/agent/workspace-runtime/registry.js +1 -1
- package/dist/src/agent-catalog/capabilities.js +2 -2
- package/dist/src/automations/capabilities/drafts.js +1 -1
- package/dist/src/automations/capabilities/write.d.ts +2 -2
- package/dist/src/automations/domain/validation.d.ts +6 -6
- package/dist/src/automations/draft/automation-draft-validator.d.ts +2 -2
- package/dist/src/automations/service/action-executor.js +1 -1
- package/dist/src/bootstrap/application-state.js +1 -1
- package/dist/src/capabilities/runtime/dispatcher.js +1 -1
- package/dist/src/capabilities/runtime/product.js +1 -1
- package/dist/src/chat-commands/agent-edit.js +1 -1
- package/dist/src/cli/commands/agent.js +1 -1
- package/dist/src/cli/commands/agents.js +1 -1
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/onboard/model.d.ts +1 -1
- package/dist/src/cli/commands/onboard/model.js +22 -3
- package/dist/src/cli/utils/init-workspace-core.js +1 -1
- package/dist/src/config/agent-profile.js +2 -2
- package/dist/src/config/loader.js +1 -1
- package/dist/src/config/models-json.js +1 -1
- package/dist/src/config/schema.d.ts +7 -1
- package/dist/src/config/schema.js +3 -1
- package/dist/src/extensions/agent-plugins/validation.js +1 -1
- package/dist/src/gateway/agents-admin.js +2 -2
- package/dist/src/gateway/chat-stream/mapper.js +2 -2
- package/dist/src/gateway/chat-stream/protocol.d.ts +2 -3
- package/dist/src/gateway/clarify-runtime.d.ts +2 -0
- package/dist/src/gateway/clarify-runtime.js +4 -1
- package/dist/src/gateway/ephemeral-clarification-waiter.d.ts +2 -1
- package/dist/src/gateway/ephemeral-clarification-waiter.js +19 -6
- package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/config-write-lock.d.ts +2 -0
- package/dist/src/gateway/hono/lib/config-write-lock.js +14 -0
- package/dist/src/gateway/hono/routes/agent-stream.js +4 -9
- package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -2
- package/dist/src/gateway/hono/routes/config.js +7 -5
- package/dist/src/gateway/hono/routes/connectors.js +1 -1
- package/dist/src/gateway/hono/routes/context-sources.js +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +1 -1
- package/dist/src/gateway/hono/routes/mcp.js +73 -6
- package/dist/src/gateway/hono/routes/notes.js +2 -2
- package/dist/src/gateway/hono/routes/projects.js +2 -2
- package/dist/src/gateway/hono/routes/session-input-handler.js +1 -1
- package/dist/src/gateway/hono/routes/side-chats.js +4 -3
- package/dist/src/gateway/hono/routes/tasks.js +1 -1
- package/dist/src/gateway/image-generation-setup.js +1 -1
- package/dist/src/gateway/lock.js +1 -1
- package/dist/src/gateway/service/agent-runner.d.ts +5 -4
- package/dist/src/gateway/service/agent-runner.js +32 -16
- package/dist/src/gateway/service/config-coordinator.d.ts +619 -1
- package/dist/src/gateway/service/config-coordinator.js +36 -24
- package/dist/src/gateway/service.d.ts +6 -3
- package/dist/src/gateway/service.js +5 -4
- package/dist/src/gateway/side-chat/run-service.d.ts +2 -1
- package/dist/src/gateway/side-chat/run-service.js +6 -3
- package/dist/src/gateway/side-chat/types.d.ts +3 -3
- package/dist/src/gateway/xopc-cloud-capability-setup.d.ts +2 -2
- package/dist/src/gateway/xopc-cloud-capability-setup.js +8 -5
- package/dist/src/local-apps/service.js +1 -1
- package/dist/src/memory-learning/service.js +3 -2
- package/dist/src/personal-agent/proactivity/service.js +1 -1
- package/dist/src/personal-agent/service.js +2 -2
- package/dist/src/providers/model-catalog-persistence.js +1 -1
- package/dist/src/routing/resolve-route.js +1 -1
- package/dist/src/routing/resolve-tui-session-key.js +1 -1
- package/dist/src/scenes/execution.d.ts +1 -1
- package/dist/src/scenes/taskFollowUp/contracts.d.ts +2 -2
- package/dist/src/scenes/taskFollowUp/service.d.ts +5 -5
- package/dist/src/scenes/templates.d.ts +2 -2
- package/dist/src/storage/sqlite/clarification-wait-repository.d.ts +3 -5
- package/dist/src/storage/sqlite/clarification-wait-repository.js +48 -28
- package/dist/src/tasks/capabilities/management.d.ts +2 -2
- package/dist/src/tasks/capabilities/read.js +2 -2
- package/dist/src/tasks/capabilities/relations.d.ts +6 -6
- package/dist/src/tasks/capabilities/write.d.ts +6 -6
- package/dist/src/tasks/capabilities/write.js +1 -1
- package/dist/src/tasks/task-handoff-service.js +1 -1
- package/dist/src/tui/backends/embedded-backend.js +2 -2
- package/dist/src/tui/tui-agent-events.js +1 -1
- package/dist/src/user-context/config.d.ts +2 -2
- package/dist/src/user-model/capture/semantic.d.ts +8 -1
- package/dist/src/user-model/capture/semantic.js +26 -5
- package/dist/src/voice/realtime/agentEngine.js +4 -2
- package/dist/src/voice/realtime/omniEngine.js +2 -2
- package/dist/src/voice/realtime/persona-context.js +1 -1
- package/package.json +4 -4
- package/dist/gateway/static/root/assets/connectors-page-CmJV7gqj.js +0 -1
- package/dist/gateway/static/root/assets/gateway-realtime-store-BVriF6Zj.js +0 -1
- package/dist/gateway/static/root/assets/index-DBRwvWzm.css +0 -1
- package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-D2mip-f9.js +0 -1
- package/dist/gateway/static/root/assets/messages-DTqbfje6.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-cache-Ct6X5zmB.js +0 -1
- package/dist/gateway/static/root/assets/session-manager-COd9RECl.js +0 -16
- package/dist/gateway/static/root/assets/settings-advanced-gate-CDkitNHA.js +0 -1
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { McpServerSchema, init_schema } from "../../config/schema.js";
|
|
2
|
+
import { getWorkspacePath } from "../../config/workspace-path-helpers.js";
|
|
3
|
+
import { isManagedConnectorServer } from "../../connectors/materialize.js";
|
|
4
|
+
import { createNativeMcpCredentials } from "./credential-store.js";
|
|
5
|
+
import { loadMergedMcpConfig } from "./config.js";
|
|
6
|
+
import { discoverMcpTools } from "./tool-catalog.js";
|
|
7
|
+
import { cancelMcpAuthorization, getMcpAuthorization, probeMcpConnection, startMcpAuthorization, submitMcpRedirect } from "./connection-setup.js";
|
|
8
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
9
|
+
//#region src/agent/mcp/connection-drafts.ts
|
|
10
|
+
init_schema();
|
|
11
|
+
const TTL_MS = 10 * 6e4;
|
|
12
|
+
function canonical(value) {
|
|
13
|
+
if (Array.isArray(value)) return value.map(canonical);
|
|
14
|
+
if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).filter(([, child]) => child !== void 0).sort(([a], [b]) => a.localeCompare(b)).map(([key, child]) => [key, canonical(child)]));
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
function mcpConfigRevision(value) {
|
|
18
|
+
return createHash("sha256").update(JSON.stringify(canonical(value)) ?? "null").digest("hex");
|
|
19
|
+
}
|
|
20
|
+
var McpDraftError = class extends Error {
|
|
21
|
+
constructor(status, message) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.status = status;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
/** Unsaved configuration and OAuth state belong to one principal and never enter the live registry. */
|
|
27
|
+
var McpConnectionDrafts = class {
|
|
28
|
+
completed = /* @__PURE__ */ new Map();
|
|
29
|
+
drafts = /* @__PURE__ */ new Map();
|
|
30
|
+
constructor(options) {
|
|
31
|
+
this.options = options;
|
|
32
|
+
}
|
|
33
|
+
async create(owner, input) {
|
|
34
|
+
const current = this.options.readConfig();
|
|
35
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(input.serverId) || input.sourceServerId && input.sourceServerId !== input.serverId) throw new McpDraftError(400, "Invalid or changed MCP server ID.");
|
|
36
|
+
const source = Object.hasOwn(current.mcp?.servers ?? {}, input.serverId) ? current.mcp?.servers?.[input.serverId] : void 0;
|
|
37
|
+
if (input.sourceServerId && (!source || isManagedConnectorServer(source))) throw new McpDraftError(409, "The original custom server no longer exists.");
|
|
38
|
+
if (input.sourceServerId && mcpConfigRevision(source) !== mcpConfigRevision(input.expectedServer)) throw new McpDraftError(409, "The original configuration changed. Reload before testing.");
|
|
39
|
+
this.assertAvailable(current, input.serverId, input.sourceServerId);
|
|
40
|
+
const parsed = McpServerSchema.safeParse(input.server);
|
|
41
|
+
if (!parsed.success) throw new McpDraftError(400, "Invalid MCP configuration.");
|
|
42
|
+
const revision = mcpConfigRevision(source);
|
|
43
|
+
const server = structuredClone(parsed.data);
|
|
44
|
+
for (const internal of [
|
|
45
|
+
"xopcConnector",
|
|
46
|
+
"xopcPlugin",
|
|
47
|
+
"xopcOAuthCredentialId",
|
|
48
|
+
"xopcConnectionCheck"
|
|
49
|
+
]) delete server[internal];
|
|
50
|
+
const workspace = getWorkspacePath(current) || process.cwd();
|
|
51
|
+
const config = structuredClone(current);
|
|
52
|
+
config.mcp = { servers: { [input.serverId]: {
|
|
53
|
+
...server,
|
|
54
|
+
enabled: true
|
|
55
|
+
} } };
|
|
56
|
+
const credentials = await createNativeMcpCredentials(true);
|
|
57
|
+
if (this.drafts.size >= 100 || [...this.drafts.values()].filter((draft) => draft.owner === owner).length >= 8) throw new McpDraftError(429, "Too many unsaved MCP connection tests.");
|
|
58
|
+
const id = randomUUID();
|
|
59
|
+
const timer = setTimeout(() => {
|
|
60
|
+
const draft = this.drafts.get(id);
|
|
61
|
+
if (draft && !draft.committing) this.dispose(draft);
|
|
62
|
+
}, TTL_MS);
|
|
63
|
+
timer.unref();
|
|
64
|
+
const draft = {
|
|
65
|
+
id,
|
|
66
|
+
owner,
|
|
67
|
+
serverId: input.serverId,
|
|
68
|
+
sourceServerId: input.sourceServerId,
|
|
69
|
+
revision,
|
|
70
|
+
workspace,
|
|
71
|
+
server,
|
|
72
|
+
config,
|
|
73
|
+
credentials,
|
|
74
|
+
controller: new AbortController(),
|
|
75
|
+
timer,
|
|
76
|
+
expiresAt: Date.now() + TTL_MS,
|
|
77
|
+
running: false,
|
|
78
|
+
committing: false
|
|
79
|
+
};
|
|
80
|
+
this.drafts.set(id, draft);
|
|
81
|
+
return {
|
|
82
|
+
id,
|
|
83
|
+
serverId: draft.serverId,
|
|
84
|
+
expiresAt: draft.expiresAt
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
async probe(owner, id) {
|
|
88
|
+
const draft = this.get(owner, id);
|
|
89
|
+
this.assertIdle(draft);
|
|
90
|
+
draft.authorizationId = void 0;
|
|
91
|
+
draft.running = true;
|
|
92
|
+
draft.probe = void 0;
|
|
93
|
+
draft.checkedAt = void 0;
|
|
94
|
+
try {
|
|
95
|
+
const result = await probeMcpConnection(draft.config, draft.workspace, draft.serverId, {
|
|
96
|
+
credentials: draft.credentials,
|
|
97
|
+
signal: draft.controller.signal
|
|
98
|
+
});
|
|
99
|
+
this.get(owner, id);
|
|
100
|
+
draft.probe = result;
|
|
101
|
+
if (result.state === "connected") draft.checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
102
|
+
return result;
|
|
103
|
+
} finally {
|
|
104
|
+
draft.running = false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
authorize(owner, id) {
|
|
108
|
+
const draft = this.get(owner, id);
|
|
109
|
+
this.assertIdle(draft);
|
|
110
|
+
if (draft.authorizationId) cancelMcpAuthorization(draft.authorizationId, owner);
|
|
111
|
+
draft.probe = void 0;
|
|
112
|
+
const attempt = startMcpAuthorization(draft.config, draft.workspace, draft.serverId, owner, {
|
|
113
|
+
credentials: draft.credentials,
|
|
114
|
+
authorizationScope: draft.id
|
|
115
|
+
});
|
|
116
|
+
draft.authorizationId = attempt.id;
|
|
117
|
+
return attempt;
|
|
118
|
+
}
|
|
119
|
+
authorization(owner, id) {
|
|
120
|
+
const draft = this.get(owner, id);
|
|
121
|
+
const result = draft.authorizationId && getMcpAuthorization(draft.authorizationId, owner, draft.config);
|
|
122
|
+
if (!result) throw new McpDraftError(404, "Draft authorization not found.");
|
|
123
|
+
if (result.state === "connected" && draft.probe?.state !== "connected") {
|
|
124
|
+
draft.probe = {
|
|
125
|
+
state: "connected",
|
|
126
|
+
toolCount: result.toolCount
|
|
127
|
+
};
|
|
128
|
+
draft.checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
redirect(owner, id, url) {
|
|
133
|
+
const draft = this.get(owner, id);
|
|
134
|
+
if (!draft.authorizationId || !submitMcpRedirect(draft.authorizationId, owner, url, draft.config)) throw new McpDraftError(400, "The callback address does not match this draft authorization.");
|
|
135
|
+
}
|
|
136
|
+
cancelAuthorization(owner, id) {
|
|
137
|
+
const draft = this.get(owner, id);
|
|
138
|
+
if (draft.committing) throw new McpDraftError(409, "This draft is being saved.");
|
|
139
|
+
if (draft.running) throw new McpDraftError(409, "A connection test is still running.");
|
|
140
|
+
if (draft.authorizationId) cancelMcpAuthorization(draft.authorizationId, owner);
|
|
141
|
+
draft.authorizationId = void 0;
|
|
142
|
+
draft.probe = void 0;
|
|
143
|
+
}
|
|
144
|
+
async tools(owner, id) {
|
|
145
|
+
const draft = this.get(owner, id);
|
|
146
|
+
this.assertIdle(draft);
|
|
147
|
+
if (draft.probe?.state !== "connected") throw new McpDraftError(409, "Test the connection first.");
|
|
148
|
+
draft.running = true;
|
|
149
|
+
try {
|
|
150
|
+
const tools = await discoverMcpTools(draft.config, draft.workspace, draft.serverId, {
|
|
151
|
+
credentials: draft.credentials,
|
|
152
|
+
signal: draft.controller.signal
|
|
153
|
+
});
|
|
154
|
+
this.get(owner, id);
|
|
155
|
+
return tools;
|
|
156
|
+
} finally {
|
|
157
|
+
draft.running = false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/** Caller serializes this with other Gateway config writes. Only this entry is merged into the latest config. */
|
|
161
|
+
async commit(owner, id, enable = false) {
|
|
162
|
+
const completed = this.completed.get(id);
|
|
163
|
+
if (completed?.owner === owner) {
|
|
164
|
+
if (completed.enable !== enable) throw new McpDraftError(409, "This test has already been committed with different settings.");
|
|
165
|
+
return {
|
|
166
|
+
serverId: completed.serverId,
|
|
167
|
+
...completed.reloadRequired ? { reloadRequired: true } : {}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const draft = this.get(owner, id);
|
|
171
|
+
this.assertIdle(draft);
|
|
172
|
+
if (draft.authorizationId) this.authorization(owner, id);
|
|
173
|
+
if (draft.probe?.state !== "connected") throw new McpDraftError(409, "A successful connection test is required before saving.");
|
|
174
|
+
const current = this.options.readConfig();
|
|
175
|
+
if (mcpConfigRevision(current.mcp?.servers?.[draft.serverId]) !== draft.revision || (getWorkspacePath(current) || process.cwd()) !== draft.workspace) throw new McpDraftError(409, "Configuration changed after the test. Reload and test again.");
|
|
176
|
+
this.assertAvailable(current, draft.serverId, draft.sourceServerId);
|
|
177
|
+
draft.committing = true;
|
|
178
|
+
let alias;
|
|
179
|
+
let durable;
|
|
180
|
+
let published = false;
|
|
181
|
+
try {
|
|
182
|
+
const server = structuredClone(draft.server);
|
|
183
|
+
if (enable) server.enabled = true;
|
|
184
|
+
if (server.url) {
|
|
185
|
+
const state = await draft.credentials.forServer(draft.serverId, server.url).load();
|
|
186
|
+
const candidateAlias = `mcp_draft_${randomUUID().replaceAll("-", "")}`;
|
|
187
|
+
durable = await createNativeMcpCredentials();
|
|
188
|
+
await durable.forServer(candidateAlias, server.url).save(state?.tokens ? {
|
|
189
|
+
...state,
|
|
190
|
+
codeVerifier: void 0,
|
|
191
|
+
oauthState: void 0
|
|
192
|
+
} : { serverUrl: server.url });
|
|
193
|
+
alias = candidateAlias;
|
|
194
|
+
server.xopcOAuthCredentialId = alias;
|
|
195
|
+
}
|
|
196
|
+
server.xopcConnectionCheck = {
|
|
197
|
+
checkedAt: draft.checkedAt,
|
|
198
|
+
toolCount: draft.probe.toolCount ?? 0,
|
|
199
|
+
revision: mcpConfigRevision(server)
|
|
200
|
+
};
|
|
201
|
+
const latest = this.options.readConfig();
|
|
202
|
+
if (mcpConfigRevision(latest.mcp?.servers?.[draft.serverId]) !== draft.revision || (getWorkspacePath(latest) || process.cwd()) !== draft.workspace) throw new McpDraftError(409, "Configuration changed while preparing the save. Test again.");
|
|
203
|
+
this.assertAvailable(latest, draft.serverId, draft.sourceServerId);
|
|
204
|
+
const next = structuredClone(latest);
|
|
205
|
+
next.mcp = {
|
|
206
|
+
...next.mcp,
|
|
207
|
+
servers: {
|
|
208
|
+
...next.mcp?.servers,
|
|
209
|
+
[draft.serverId]: server
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
const result = await this.options.saveConfig(next, structuredClone(latest));
|
|
213
|
+
published = result.persisted === true || alias !== void 0 && this.options.readConfig().mcp?.servers?.[draft.serverId]?.xopcOAuthCredentialId === alias;
|
|
214
|
+
if (result.conflict) throw new McpDraftError(409, "Configuration changed before writing. Reload and test again.");
|
|
215
|
+
if (!result.saved && !result.persisted) throw new McpDraftError(500, "Could not save MCP configuration. Retry or reload the current configuration.");
|
|
216
|
+
const reloadRequired = !result.saved;
|
|
217
|
+
published = true;
|
|
218
|
+
const timer = setTimeout(() => this.completed.delete(id), TTL_MS);
|
|
219
|
+
timer.unref();
|
|
220
|
+
this.completed.set(id, {
|
|
221
|
+
owner,
|
|
222
|
+
enable,
|
|
223
|
+
serverId: draft.serverId,
|
|
224
|
+
reloadRequired,
|
|
225
|
+
timer
|
|
226
|
+
});
|
|
227
|
+
this.dispose(draft);
|
|
228
|
+
return {
|
|
229
|
+
serverId: draft.serverId,
|
|
230
|
+
...reloadRequired ? { reloadRequired: true } : {}
|
|
231
|
+
};
|
|
232
|
+
} finally {
|
|
233
|
+
draft.committing = false;
|
|
234
|
+
if (alias && this.options.readConfig().mcp?.servers?.[draft.serverId]?.xopcOAuthCredentialId === alias) published = true;
|
|
235
|
+
if (!published && alias && durable && draft.server.url) durable.remove(alias, draft.server.url);
|
|
236
|
+
if (this.drafts.has(id) && draft.expiresAt <= Date.now()) this.dispose(draft);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
remove(owner, id) {
|
|
240
|
+
const draft = this.drafts.get(id);
|
|
241
|
+
if (!draft || draft.owner !== owner) return;
|
|
242
|
+
if (draft.committing) throw new McpDraftError(409, "This draft is being saved.");
|
|
243
|
+
this.dispose(draft);
|
|
244
|
+
}
|
|
245
|
+
close() {
|
|
246
|
+
for (const draft of this.drafts.values()) this.dispose(draft);
|
|
247
|
+
for (const item of this.completed.values()) clearTimeout(item.timer);
|
|
248
|
+
this.completed.clear();
|
|
249
|
+
}
|
|
250
|
+
get(owner, id) {
|
|
251
|
+
const draft = this.drafts.get(id);
|
|
252
|
+
if (!draft || draft.owner !== owner) throw new McpDraftError(404, "MCP draft not found or expired.");
|
|
253
|
+
if (draft.expiresAt <= Date.now() && !draft.committing) {
|
|
254
|
+
this.dispose(draft);
|
|
255
|
+
throw new McpDraftError(404, "MCP draft expired.");
|
|
256
|
+
}
|
|
257
|
+
return draft;
|
|
258
|
+
}
|
|
259
|
+
assertIdle(draft) {
|
|
260
|
+
const auth = draft.authorizationId && getMcpAuthorization(draft.authorizationId, draft.owner, draft.config);
|
|
261
|
+
if (draft.running || draft.committing || auth && (auth.state === "starting" || auth.state === "authorizing")) throw new McpDraftError(409, "Another draft operation is still running.");
|
|
262
|
+
}
|
|
263
|
+
assertAvailable(config, id, sourceId) {
|
|
264
|
+
const all = loadMergedMcpConfig({
|
|
265
|
+
cfg: config,
|
|
266
|
+
workspaceDir: getWorkspacePath(config) || process.cwd()
|
|
267
|
+
}).config.mcpServers;
|
|
268
|
+
if (Object.keys(all).some((other) => other !== sourceId && other.replaceAll("-", "_") === id.replaceAll("-", "_"))) throw new McpDraftError(409, "The MCP server ID is already in use.");
|
|
269
|
+
}
|
|
270
|
+
dispose(draft) {
|
|
271
|
+
this.drafts.delete(draft.id);
|
|
272
|
+
clearTimeout(draft.timer);
|
|
273
|
+
draft.controller.abort();
|
|
274
|
+
if (draft.authorizationId) cancelMcpAuthorization(draft.authorizationId, draft.owner);
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
//#endregion
|
|
278
|
+
export { McpConnectionDrafts, McpDraftError, mcpConfigRevision };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Config } from '../../config/schema.js';
|
|
2
|
+
import { type McpSessionOptions } from './tool-catalog.js';
|
|
2
3
|
export type McpConnectionProbe = {
|
|
3
4
|
state: 'connected' | 'oauth_required' | 'token_required' | 'error';
|
|
4
5
|
toolCount?: number;
|
|
5
6
|
error?: string;
|
|
6
7
|
};
|
|
7
|
-
export declare function probeMcpConnection(config: Config, workspace: string, serverId: string): Promise<McpConnectionProbe>;
|
|
8
|
+
export declare function probeMcpConnection(config: Config, workspace: string, serverId: string, options?: McpSessionOptions): Promise<McpConnectionProbe>;
|
|
8
9
|
export type McpAuthorization = {
|
|
9
10
|
id: string;
|
|
10
11
|
serverId: string;
|
|
@@ -15,7 +16,9 @@ export type McpAuthorization = {
|
|
|
15
16
|
error?: string;
|
|
16
17
|
};
|
|
17
18
|
/** A UI bridge to native pi's login command; no host-owned OAuth client or token store. */
|
|
18
|
-
export declare function startMcpAuthorization(config: Config, workspace: string, serverId: string, owner: string
|
|
19
|
+
export declare function startMcpAuthorization(config: Config, workspace: string, serverId: string, owner: string, options?: McpSessionOptions & {
|
|
20
|
+
authorizationScope?: string;
|
|
21
|
+
}): McpAuthorization;
|
|
19
22
|
export declare function getMcpAuthorization(id: string, owner: string, config: Config): McpAuthorization | undefined;
|
|
20
23
|
export declare function cancelMcpAuthorization(id: string, owner: string): boolean;
|
|
21
24
|
export declare function submitMcpRedirect(id: string, owner: string, redirectUrl: string, config: Config): boolean;
|
|
@@ -71,11 +71,11 @@ async function advertisesOAuth(config, workspace, serverId) {
|
|
|
71
71
|
const legacy = await metadata(new URL("/.well-known/oauth-authorization-server", url));
|
|
72
72
|
return Boolean(legacy && legacy.issuer === url.origin && typeof legacy.authorization_endpoint === "string" && typeof legacy.token_endpoint === "string");
|
|
73
73
|
}
|
|
74
|
-
async function probeMcpConnection(config, workspace, serverId) {
|
|
74
|
+
async function probeMcpConnection(config, workspace, serverId, options) {
|
|
75
75
|
try {
|
|
76
76
|
return {
|
|
77
77
|
state: "connected",
|
|
78
|
-
toolCount: (await discoverMcpTools(config, workspace, serverId)).length
|
|
78
|
+
toolCount: (await discoverMcpTools(config, workspace, serverId, options)).length
|
|
79
79
|
};
|
|
80
80
|
} catch (error) {
|
|
81
81
|
if (error instanceof McpAuthenticationRequiredError) try {
|
|
@@ -117,15 +117,17 @@ function cancel(attempt) {
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
/** A UI bridge to native pi's login command; no host-owned OAuth client or token store. */
|
|
120
|
-
function startMcpAuthorization(config, workspace, serverId, owner) {
|
|
120
|
+
function startMcpAuthorization(config, workspace, serverId, owner, options) {
|
|
121
121
|
const server = config.mcp?.servers?.[serverId];
|
|
122
122
|
if (!server?.url || server.enabled === false || isManagedConnectorServer(server) && server.xopcConnector.enabled === false) throw new Error("An enabled HTTP MCP server is required.");
|
|
123
123
|
httpUrl(server.url);
|
|
124
124
|
if (server.auth || Object.keys(server.headers ?? {}).some((name) => name.toLowerCase() === "authorization")) throw new Error("This server uses configured credentials. Remove Authorization before using OAuth.");
|
|
125
|
-
|
|
125
|
+
const scope = options?.authorizationScope ?? serverId;
|
|
126
|
+
for (const attempt of attempts.values()) if (attempt.owner === owner && attempt.scope === scope) cancel(attempt);
|
|
126
127
|
if (attempts.size >= 100) throw new Error("Too many pending sign-ins. Try again later.");
|
|
127
128
|
const attempt = {
|
|
128
129
|
owner,
|
|
130
|
+
scope,
|
|
129
131
|
fingerprint: fingerprint(config, serverId),
|
|
130
132
|
controller: new AbortController(),
|
|
131
133
|
result: {
|
|
@@ -159,7 +161,7 @@ function startMcpAuthorization(config, workspace, serverId, owner) {
|
|
|
159
161
|
attempt.dispose = () => signal?.removeEventListener("abort", stop);
|
|
160
162
|
});
|
|
161
163
|
}
|
|
162
|
-
}).then((tools) => {
|
|
164
|
+
}, options).then((tools) => {
|
|
163
165
|
if (!attempt.controller.signal.aborted) {
|
|
164
166
|
attempt.result.state = "connected";
|
|
165
167
|
attempt.result.toolCount = tools.length;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { McpExtensionOptions } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
export type NativeMcpCredentials = NonNullable<McpExtensionOptions['credentials']>;
|
|
3
|
+
/** Use pi's own stores; never change PI_CODING_AGENT_DIR for an individual connection. */
|
|
4
|
+
export declare function createNativeMcpCredentials(memory?: boolean): Promise<NativeMcpCredentials>;
|
|
5
|
+
/** Credential identity may change on commit without changing the public tool namespace. */
|
|
6
|
+
export declare function routeNativeMcpCredentials(store: NativeMcpCredentials, aliases: ReadonlyMap<string, string>): NativeMcpCredentials;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/agent/mcp/credential-store.ts
|
|
2
|
+
/** Use pi's own stores; never change PI_CODING_AGENT_DIR for an individual connection. */
|
|
3
|
+
async function createNativeMcpCredentials(memory = false) {
|
|
4
|
+
const root = import.meta.resolve("@earendil-works/pi-coding-agent");
|
|
5
|
+
const { McpOAuthCredentialStore } = await import(new URL("./extensions/mcp/oauth.js", root).href);
|
|
6
|
+
if (!memory) return new McpOAuthCredentialStore();
|
|
7
|
+
const { InMemoryAuthStorageBackend } = await import(new URL("./core/auth-storage.js", root).href);
|
|
8
|
+
return new McpOAuthCredentialStore(new InMemoryAuthStorageBackend());
|
|
9
|
+
}
|
|
10
|
+
/** Credential identity may change on commit without changing the public tool namespace. */
|
|
11
|
+
function routeNativeMcpCredentials(store, aliases) {
|
|
12
|
+
const forServer = store.forServer.bind(store), tokens = store.tokens.bind(store), remove = store.remove.bind(store);
|
|
13
|
+
store.forServer = (name, url) => forServer(aliases.get(name) ?? name, url);
|
|
14
|
+
store.tokens = (name, url) => tokens(aliases.get(name) ?? name, url);
|
|
15
|
+
store.remove = (name, url) => {
|
|
16
|
+
const alias = aliases.get(name);
|
|
17
|
+
if (!alias) return remove(name, url);
|
|
18
|
+
forServer(alias, url).save({ serverUrl: url });
|
|
19
|
+
return true;
|
|
20
|
+
};
|
|
21
|
+
return store;
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { createNativeMcpCredentials, routeNativeMcpCredentials };
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { type LoadedMcpConfig } from '@earendil-works/pi-coding-agent';
|
|
2
2
|
import { type Config } from '../../config/schema.js';
|
|
3
|
+
import { type NativeMcpCredentials } from './credential-store.js';
|
|
3
4
|
/** One process-wide pi directory: sessions share native OAuth credentials, never swap roots per turn. */
|
|
4
5
|
export declare function getNativePiAgentDir(): string;
|
|
6
|
+
export type NativeMcpConfig = LoadedMcpConfig & {
|
|
7
|
+
credentials?: NativeMcpCredentials;
|
|
8
|
+
credentialAliases?: Record<string, string>;
|
|
9
|
+
};
|
|
5
10
|
/** Only projects host configuration and secret references; all MCP execution belongs to pi. */
|
|
6
|
-
export declare function prepareNativeMcpConfig(config: Config, workspaceDir: string): Promise<
|
|
11
|
+
export declare function prepareNativeMcpConfig(config: Config, workspaceDir: string): Promise<NativeMcpConfig>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { init_paths_state, resolveStateDir } from "../../config/paths-state.js";
|
|
2
2
|
import { McpServerSchema, init_schema } from "../../config/schema.js";
|
|
3
3
|
import { resolveConnectorSecretReferences } from "../../connectors/secret-store.js";
|
|
4
|
+
import { createNativeMcpCredentials, routeNativeMcpCredentials } from "./credential-store.js";
|
|
4
5
|
import { loadMergedMcpConfig } from "./config.js";
|
|
5
6
|
import { join } from "node:path";
|
|
6
7
|
import { mkdirSync } from "node:fs";
|
|
@@ -67,6 +68,11 @@ async function prepareNativeMcpConfig(config, workspaceDir) {
|
|
|
67
68
|
scope: "extension"
|
|
68
69
|
});
|
|
69
70
|
}
|
|
71
|
+
const aliases = new Map(Object.entries(config.mcp?.servers ?? {}).filter(([, value]) => typeof value.xopcOAuthCredentialId === "string").map(([name, value]) => [name, value.xopcOAuthCredentialId]));
|
|
72
|
+
if (aliases.size) {
|
|
73
|
+
result.credentials = routeNativeMcpCredentials(await createNativeMcpCredentials(), aliases);
|
|
74
|
+
result.credentialAliases = Object.fromEntries(aliases);
|
|
75
|
+
}
|
|
70
76
|
return result;
|
|
71
77
|
}
|
|
72
78
|
//#endregion
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Config } from '../../config/schema.js';
|
|
2
|
+
import type { NativeMcpCredentials } from './credential-store.js';
|
|
2
3
|
export type McpCatalogTool = {
|
|
3
4
|
name: string;
|
|
4
5
|
description: string;
|
|
@@ -12,7 +13,11 @@ export type McpLoginInteraction = {
|
|
|
12
13
|
onAuthorizationUrl: (url: string) => void;
|
|
13
14
|
requestRedirectUrl: (signal?: AbortSignal) => Promise<string | undefined>;
|
|
14
15
|
};
|
|
16
|
+
export type McpSessionOptions = {
|
|
17
|
+
credentials?: NativeMcpCredentials;
|
|
18
|
+
signal?: AbortSignal;
|
|
19
|
+
};
|
|
15
20
|
/** A short-lived native session discovers tools without making a model request. */
|
|
16
|
-
export declare function discoverMcpTools(config: Config, workspaceDir: string, serverId: string): Promise<McpCatalogTool[]>;
|
|
21
|
+
export declare function discoverMcpTools(config: Config, workspaceDir: string, serverId: string, options?: McpSessionOptions): Promise<McpCatalogTool[]>;
|
|
17
22
|
/** Native pi owns PKCE, registration, callbacks, token storage and refresh. */
|
|
18
|
-
export declare function signInNativeMcp(config: Config, workspaceDir: string, serverId: string, interaction: McpLoginInteraction): Promise<McpCatalogTool[]>;
|
|
23
|
+
export declare function signInNativeMcp(config: Config, workspaceDir: string, serverId: string, interaction: McpLoginInteraction, options?: McpSessionOptions): Promise<McpCatalogTool[]>;
|
|
@@ -6,15 +6,19 @@ import { DefaultResourceLoader, ModelRuntime, SessionManager, SettingsManager, c
|
|
|
6
6
|
//#region src/agent/mcp/tool-catalog.ts
|
|
7
7
|
var McpAuthenticationRequiredError = class extends Error {};
|
|
8
8
|
/** A short-lived native session discovers tools without making a model request. */
|
|
9
|
-
async function discoverMcpTools(config, workspaceDir, serverId) {
|
|
10
|
-
return runNativeMcpSession(config, workspaceDir, serverId);
|
|
9
|
+
async function discoverMcpTools(config, workspaceDir, serverId, options) {
|
|
10
|
+
return runNativeMcpSession(config, workspaceDir, serverId, void 0, options);
|
|
11
11
|
}
|
|
12
12
|
/** Native pi owns PKCE, registration, callbacks, token storage and refresh. */
|
|
13
|
-
async function signInNativeMcp(config, workspaceDir, serverId, interaction) {
|
|
14
|
-
return runNativeMcpSession(config, workspaceDir, serverId, interaction);
|
|
13
|
+
async function signInNativeMcp(config, workspaceDir, serverId, interaction, options) {
|
|
14
|
+
return runNativeMcpSession(config, workspaceDir, serverId, interaction, options);
|
|
15
15
|
}
|
|
16
|
-
async function runNativeMcpSession(config, workspaceDir, serverId, interaction) {
|
|
17
|
-
const
|
|
16
|
+
async function runNativeMcpSession(config, workspaceDir, serverId, interaction, options) {
|
|
17
|
+
const signal = interaction?.signal ?? options?.signal;
|
|
18
|
+
signal?.throwIfAborted();
|
|
19
|
+
const loaded = await prepareNativeMcpConfig(config, workspaceDir);
|
|
20
|
+
signal?.throwIfAborted();
|
|
21
|
+
const entry = loaded.servers.find((server) => server.name === serverId);
|
|
18
22
|
if (!entry) throw new Error(`MCP server "${serverId}" is not configured or has invalid configuration.`);
|
|
19
23
|
if (entry.config.enabled === false) throw new Error(`MCP server "${serverId}" is disabled.`);
|
|
20
24
|
const agentDir = getNativePiAgentDir();
|
|
@@ -32,6 +36,7 @@ async function runNativeMcpSession(config, workspaceDir, serverId, interaction)
|
|
|
32
36
|
noThemes: true,
|
|
33
37
|
noContextFiles: true,
|
|
34
38
|
extensionFactories: [createToolSearchExtension(), createMcpExtension({
|
|
39
|
+
credentials: options?.credentials ?? loaded.credentials,
|
|
35
40
|
loadConfig: () => ({
|
|
36
41
|
servers: [entry],
|
|
37
42
|
errors: [],
|
|
@@ -42,18 +47,21 @@ async function runNativeMcpSession(config, workspaceDir, serverId, interaction)
|
|
|
42
47
|
})]
|
|
43
48
|
});
|
|
44
49
|
await loader.reload();
|
|
50
|
+
signal?.throwIfAborted();
|
|
45
51
|
const provider = "url" in entry.config ? entry.config.auth?.provider : void 0;
|
|
52
|
+
const modelRuntime = provider ? await createEmbeddedModelRuntime(provider) : await ModelRuntime.create({
|
|
53
|
+
credentials: new InMemoryCredentialStore(),
|
|
54
|
+
modelsStore: new InMemoryModelsStore(),
|
|
55
|
+
modelsPath: null,
|
|
56
|
+
refreshOnCreate: false
|
|
57
|
+
});
|
|
58
|
+
signal?.throwIfAborted();
|
|
46
59
|
const { session } = await createAgentSession({
|
|
47
60
|
cwd: workspaceDir,
|
|
48
61
|
agentDir,
|
|
49
62
|
resourceLoader: loader,
|
|
50
63
|
settingsManager,
|
|
51
|
-
modelRuntime
|
|
52
|
-
credentials: new InMemoryCredentialStore(),
|
|
53
|
-
modelsStore: new InMemoryModelsStore(),
|
|
54
|
-
modelsPath: null,
|
|
55
|
-
refreshOnCreate: false
|
|
56
|
-
}),
|
|
64
|
+
modelRuntime,
|
|
57
65
|
sessionManager: SessionManager.inMemory(),
|
|
58
66
|
noTools: "builtin"
|
|
59
67
|
});
|
|
@@ -70,6 +78,8 @@ async function runNativeMcpSession(config, workspaceDir, serverId, interaction)
|
|
|
70
78
|
try {
|
|
71
79
|
const runner = session.extensionRunner;
|
|
72
80
|
if (!runner) throw new Error("Native MCP extension is unavailable.");
|
|
81
|
+
signal?.throwIfAborted();
|
|
82
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
73
83
|
await session.bindExtensions({ uiContext: {
|
|
74
84
|
...runner.getUIContext(),
|
|
75
85
|
notify(message) {
|
|
@@ -81,8 +91,7 @@ async function runNativeMcpSession(config, workspaceDir, serverId, interaction)
|
|
|
81
91
|
return interaction?.requestRedirectUrl(options?.signal) ?? Promise.resolve(void 0);
|
|
82
92
|
}
|
|
83
93
|
} });
|
|
84
|
-
|
|
85
|
-
if (interaction?.signal.aborted) throw new Error("MCP sign-in cancelled.");
|
|
94
|
+
if (signal?.aborted) throw new Error("MCP sign-in cancelled.");
|
|
86
95
|
let timer;
|
|
87
96
|
try {
|
|
88
97
|
await Promise.race([session.prompt("/mcp"), new Promise((_resolve, reject) => {
|
|
@@ -100,6 +109,7 @@ async function runNativeMcpSession(config, workspaceDir, serverId, interaction)
|
|
|
100
109
|
if (/needs sign-in|needs-auth/.test(failure)) throw new McpAuthenticationRequiredError(failure);
|
|
101
110
|
throw new Error(failure);
|
|
102
111
|
}
|
|
112
|
+
if (signal?.aborted) throw new Error("MCP connection check cancelled.");
|
|
103
113
|
const namespace = `mcp__${serverId.replace(/-/g, "_")}`;
|
|
104
114
|
return session.getAllTools().filter((tool) => tool.namespace?.name === namespace).map((tool) => ({
|
|
105
115
|
name: tool.name,
|
|
@@ -109,7 +119,7 @@ async function runNativeMcpSession(config, workspaceDir, serverId, interaction)
|
|
|
109
119
|
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
110
120
|
} finally {
|
|
111
121
|
try {
|
|
112
|
-
|
|
122
|
+
signal?.removeEventListener("abort", abort);
|
|
113
123
|
await close();
|
|
114
124
|
} finally {
|
|
115
125
|
session.dispose();
|
|
@@ -3,8 +3,8 @@ import { init_src } from "../../../packages/gateway-contract/src/index.js";
|
|
|
3
3
|
import { init_session_input_repository, listTaskUpdateTriggers } from "../../storage/sqlite/session-input-repository.js";
|
|
4
4
|
import { getClarificationResumeInput, init_clarification_wait_repository } from "../../storage/sqlite/clarification-wait-repository.js";
|
|
5
5
|
import { getConnectionResumeInput, init_connection_wait_repository } from "../../storage/sqlite/connection-wait-repository.js";
|
|
6
|
-
import { init_agent_session_key, resolveAgentMainConversationId } from "../../routing/agent-session-key.js";
|
|
7
6
|
import { init_agent_scope, resolveDefaultAgentId } from "../agent-scope.js";
|
|
7
|
+
import { init_agent_session_key, resolveAgentMainConversationId } from "../../routing/agent-session-key.js";
|
|
8
8
|
import { readAgentMessageContent } from "../memory/agent-message-access.js";
|
|
9
9
|
import { abortEmbeddedRun } from "../embedded/runs.js";
|
|
10
10
|
import { clearPendingTranscriptUserMessage, setPendingTranscriptUserMessage } from "../inbound/attachment-pipeline.js";
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
3
|
import { init_attachment_ref, parseNoteAttachmentTarget } from "../notes/attachment-ref.js";
|
|
4
|
-
import { init_agent_session_key, resolveAgentIdFromConversationId } from "../routing/agent-session-key.js";
|
|
5
4
|
import { init_agent_scope, resolveAgentHomeDir, resolveDefaultAgentId } from "./agent-scope.js";
|
|
5
|
+
import { extractTextContent } from "./context/workspace.js";
|
|
6
|
+
import { init_agent_session_key, resolveAgentIdFromConversationId } from "../routing/agent-session-key.js";
|
|
6
7
|
import { extractProfileAgentId, resolveEffectiveAgentConfigForSession } from "../config/agent-profile.js";
|
|
7
8
|
import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
|
|
8
9
|
import { init_providers, resolveModel } from "../providers/index.js";
|
|
9
10
|
import { configureTracing, flushTracing } from "../observability/runtime.js";
|
|
10
11
|
import { getUserTimezone } from "../user-model/repository.js";
|
|
11
|
-
import { extractTextContent } from "./context/workspace.js";
|
|
12
12
|
import { resolveAgentTurnTimeoutMs } from "./orchestration/run-agent-turn-with-timeout.js";
|
|
13
13
|
import { applyConfigOverrides } from "../config/runtime-overrides.js";
|
|
14
14
|
import { effectiveWorkspacePathForSession } from "../session/session-workspace.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { resolveStateDir } from "../../config/paths-state.js";
|
|
2
2
|
import { createLogger } from "../../utils/logger/index.js";
|
|
3
3
|
import { init_logger } from "../../utils/logger.js";
|
|
4
|
-
import { init_paths } from "../../config/paths.js";
|
|
5
4
|
import { parseFrontmatter } from "../../markdown/frontmatter.js";
|
|
5
|
+
import { init_paths } from "../../config/paths.js";
|
|
6
6
|
import { findInstallSpec, hasBinary, installSkill } from "./installer.js";
|
|
7
7
|
import { applySkillEnvOverrides, createSkillConfigManager, getSkillEnvironment, isSkillEnabled, resolveSkillConfig, validateSkillConfig } from "./config.js";
|
|
8
8
|
import { parseSkillToolConditions } from "./skill-tool-gating.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { init_paths, resolveSkillsDir } from "../../config/paths.js";
|
|
2
1
|
import { parseFrontmatter } from "../../markdown/frontmatter.js";
|
|
2
|
+
import { init_paths, resolveSkillsDir } from "../../config/paths.js";
|
|
3
3
|
import { loadSkillsLock } from "./hub-lock.js";
|
|
4
4
|
import { dirname, join, resolve, sep } from "node:path";
|
|
5
5
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { init_paths, resolveSkillsDir } from "../../config/paths.js";
|
|
2
1
|
import { parseFrontmatter } from "../../markdown/frontmatter.js";
|
|
2
|
+
import { init_paths, resolveSkillsDir } from "../../config/paths.js";
|
|
3
3
|
import { resolveWorkspaceSkillsDir } from "./workspace-skills-dir.js";
|
|
4
4
|
import { formatScanSummary, scanSkillDirectory } from "./scanner.js";
|
|
5
5
|
import { fuzzyFindText, normalizeForFuzzyMatch, normalizeToLF, restoreLineEndings } from "../tools/edit-diff.js";
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import type { ClarificationPresentation } from '@xopcai/gateway-contract';
|
|
1
2
|
import type { AgentTool } from '@earendil-works/pi-agent-core';
|
|
2
|
-
export type ClarifyRequestPayload = {
|
|
3
|
+
export type ClarifyRequestPayload = ClarificationPresentation & {
|
|
3
4
|
kind?: 'approval';
|
|
4
5
|
question: string;
|
|
5
|
-
choices?: string[];
|
|
6
|
-
suggestedAnswer?: string;
|
|
7
6
|
/** Stable hash of the exact operation guarded by an approval. */
|
|
8
7
|
approvalKey?: string;
|
|
9
8
|
};
|
|
@@ -2,13 +2,18 @@ import { Type } from "@sinclair/typebox";
|
|
|
2
2
|
//#region src/agent/tools/clarify-tool.ts
|
|
3
3
|
const ClarifySchema = Type.Object({
|
|
4
4
|
question: Type.String({ description: "The question to ask the user. Be specific and concise." }),
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
interactionMode: Type.Optional(Type.Union([Type.Literal("quick"), Type.Literal("compose")], { description: "quick submits a choice immediately; compose lets the user select and add details before submitting." })),
|
|
6
|
+
choiceDetails: Type.Optional(Type.Array(Type.Object({
|
|
7
|
+
id: Type.String(),
|
|
8
|
+
label: Type.String(),
|
|
9
|
+
description: Type.Optional(Type.String())
|
|
10
|
+
}), {
|
|
7
11
|
minItems: 2,
|
|
8
|
-
maxItems: 10
|
|
12
|
+
maxItems: 10,
|
|
13
|
+
description: "Answer choices with stable unique IDs and optional descriptions."
|
|
9
14
|
})),
|
|
10
|
-
|
|
11
|
-
});
|
|
15
|
+
recommendedChoiceId: Type.Optional(Type.String())
|
|
16
|
+
}, { additionalProperties: false });
|
|
12
17
|
function waitForAbort(signal) {
|
|
13
18
|
return new Promise((_, reject) => {
|
|
14
19
|
if (!signal) return;
|
|
@@ -23,7 +28,7 @@ function createClarifyTool(deps) {
|
|
|
23
28
|
return {
|
|
24
29
|
name: "clarify",
|
|
25
30
|
label: "❓ Clarify",
|
|
26
|
-
description: "Ask the user a clarifying question and pause the objective until they respond.\n\nUse this when you need more information to proceed correctly, rather than guessing.\n\nWHEN TO USE:\n- Ambiguous instructions with multiple valid interpretations\n- Missing critical information (which file, which approach, etc.)\n- Confirming destructive or irreversible actions\n\nWHEN NOT TO USE:\n- When you can reasonably infer the answer from context\n- For trivial decisions that do not affect the task\n- When the user explicitly said \"just do it\" or \"your choice\"\n\nTIPS:\n- Provide choices when there are clear options (faster for the user)\n- Keep questions short and specific\n-
|
|
31
|
+
description: "Ask the user a clarifying question and pause the objective until they respond.\n\nUse this when you need more information to proceed correctly, rather than guessing.\n\nWHEN TO USE:\n- Ambiguous instructions with multiple valid interpretations\n- Missing critical information (which file, which approach, etc.)\n- Confirming destructive or irreversible actions\n\nWHEN NOT TO USE:\n- When you can reasonably infer the answer from context\n- For trivial decisions that do not affect the task\n- When the user explicitly said \"just do it\" or \"your choice\"\n\nTIPS:\n- Provide choices when there are clear options (faster for the user)\n- Keep questions short and specific\n- Set recommendedChoiceId when one option is clearly more likely",
|
|
27
32
|
parameters: ClarifySchema,
|
|
28
33
|
async execute(toolCallId, params, signal) {
|
|
29
34
|
const p = params;
|
|
@@ -36,9 +41,10 @@ function createClarifyTool(deps) {
|
|
|
36
41
|
details: { answer: "" }
|
|
37
42
|
};
|
|
38
43
|
const payload = {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
interactionMode: p.interactionMode,
|
|
45
|
+
choiceDetails: p.choiceDetails,
|
|
46
|
+
recommendedChoiceId: p.recommendedChoiceId,
|
|
47
|
+
question: p.question
|
|
42
48
|
};
|
|
43
49
|
try {
|
|
44
50
|
const result = await Promise.race([askUser(payload), waitForAbort(signal)]);
|