shadow-claw 1.59.6 → 1.59.7
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/.well-known/mcp/server-card.json +12 -4
- package/.well-known/mcp.json +12 -4
- package/dist/cli/build/build.js +1 -1
- package/dist/cli/{chunk-DM4xsTry.js → chunk-3vNYrs_L.js} +1 -1
- package/dist/cli/{chunk-Ctg5L55n.js → chunk-66BvqAV0.js} +1 -1
- package/dist/cli/{chunk-Bq38OubR.js → chunk-B0qusANw.js} +1 -1
- package/dist/cli/{chunk-yiVdvGCJ.js → chunk-B3TrWbca.js} +7 -7
- package/dist/cli/{chunk-C8DBACtx.js → chunk-B88Z8T_9.js} +1 -1
- package/dist/cli/chunk-BCjL0JXf.js +1 -0
- package/dist/cli/chunk-BNcu1oiT.js +1 -0
- package/dist/cli/{chunk-gvNsvav0.js → chunk-C5ypckWC.js} +7 -7
- package/dist/cli/{chunk-Dw8GndPD.js → chunk-CAAeGOdy.js} +1 -1
- package/dist/cli/chunk-CFxww5Yz.js +1 -0
- package/dist/cli/chunk-CGIgtL6R.js +1 -0
- package/dist/cli/{chunk-DJqHK-qS.js → chunk-CQaCgswD.js} +7 -7
- package/dist/cli/chunk-CZdCRqNe.js +7 -0
- package/dist/cli/chunk-CafdvLx-.js +1 -0
- package/dist/cli/{chunk-Bc_weULz.js → chunk-CncW6_WL.js} +1 -1
- package/dist/cli/chunk-DDvuLVfW.js +1 -0
- package/dist/cli/{chunk-Cq_kQohv.js → chunk-DMs7kREC.js} +1 -1
- package/dist/cli/{chunk-CX2itile.js → chunk-D_te8ufL.js} +1 -1
- package/dist/cli/{chunk-3wTukVof.js → chunk-DhOU6GYX.js} +1 -1
- package/dist/cli/chunk-Dhap1VwA.js +1 -0
- package/dist/cli/chunk-DwvavohW.js +1 -0
- package/dist/cli/{chunk-DLde6nuO.js → chunk-SRBRVorc.js} +1 -1
- package/dist/cli/{chunk-D3y7h9Xe.js → chunk-SxK79JmB.js} +1 -1
- package/dist/cli/chunk-_a0CkUNS.js +139 -0
- package/dist/cli/{chunk-C9o6lXP3.js → chunk-hVf839t7.js} +1 -1
- package/dist/cli/chunk-iB8OoMmW.js +7 -0
- package/dist/cli/cli.js +1 -1
- package/dist/headless-agent.js +1 -1
- package/dist/lib/{app-routes-DJdIjp2V.js → app-routes-BXiRvlNl.js} +7 -25
- package/dist/lib/{app-routes-DJdIjp2V.js.map → app-routes-BXiRvlNl.js.map} +1 -1
- package/dist/lib/{attachment-capabilities-Dbb-4ZP5.js → attachment-capabilities-BjkEPip8.js} +2 -2
- package/dist/lib/{attachment-capabilities-Dbb-4ZP5.js.map → attachment-capabilities-BjkEPip8.js.map} +1 -1
- package/dist/lib/{channel-Dlru5ofR.js → channel-mmdGzPkT.js} +3 -3
- package/dist/lib/{channel-Dlru5ofR.js.map → channel-mmdGzPkT.js.map} +1 -1
- package/dist/lib/{chat-template-BuuLY8l7.js → chat-template-DPEKGJhB.js} +2 -2
- package/dist/lib/{chat-template-BuuLY8l7.js.map → chat-template-DPEKGJhB.js.map} +1 -1
- package/dist/lib/{compact-context-BtR55YPU.js → compact-context-CY9BBlUQ.js} +19 -19
- package/dist/lib/{compact-context-BtR55YPU.js.map → compact-context-CY9BBlUQ.js.map} +1 -1
- package/dist/lib/components/common/shadow-claw-provider-model-picker.js +1 -1
- package/dist/lib/components/index.js +27 -27
- package/dist/lib/components/settings/shadow-claw-accounts.js +1 -1
- package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
- package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
- package/dist/lib/components/settings/shadow-claw-git.js +1 -1
- package/dist/lib/components/settings/shadow-claw-integrations.js +1 -1
- package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
- package/dist/lib/components/settings/shadow-claw-mcp-remote.js +1 -1
- package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
- package/dist/lib/components/settings/shadow-claw-notifications.js +1 -1
- package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
- package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
- package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
- package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
- package/dist/lib/components/shadow-claw-a2ui.js +1 -1
- package/dist/lib/components/shadow-claw-accounts.js +1 -1
- package/dist/lib/components/shadow-claw-channel-config.js +1 -1
- package/dist/lib/components/shadow-claw-channels.js +1 -1
- package/dist/lib/components/shadow-claw-chat.js +1 -1
- package/dist/lib/components/shadow-claw-control-plane.js +1 -1
- package/dist/lib/components/shadow-claw-conversations.js +1 -1
- package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
- package/dist/lib/components/shadow-claw-files.js +1 -1
- package/dist/lib/components/shadow-claw-git.js +1 -1
- package/dist/lib/components/shadow-claw-integrations.js +1 -1
- package/dist/lib/components/shadow-claw-llm.js +1 -1
- package/dist/lib/components/shadow-claw-mcp-remote.js +1 -1
- package/dist/lib/components/shadow-claw-networking.js +1 -1
- package/dist/lib/components/shadow-claw-notifications.js +1 -1
- package/dist/lib/components/shadow-claw-page-header.js +1 -1
- package/dist/lib/components/shadow-claw-pages.js +1 -1
- package/dist/lib/components/shadow-claw-peerjs.js +1 -1
- package/dist/lib/components/shadow-claw-provider-model-picker.js +1 -1
- package/dist/lib/components/shadow-claw-settings.js +1 -1
- package/dist/lib/components/shadow-claw-storage.js +1 -1
- package/dist/lib/components/shadow-claw-task-server.js +1 -1
- package/dist/lib/components/shadow-claw-tasks.js +1 -1
- package/dist/lib/components/shadow-claw-terminal.js +1 -1
- package/dist/lib/components/shadow-claw-tools.js +1 -1
- package/dist/lib/components/shadow-claw-webvm.js +1 -1
- package/dist/lib/components/shadow-claw.js +1 -1
- package/dist/lib/{config-DxNI3TlW.js → config-BrHR97zt.js} +2 -2
- package/dist/lib/{config-DxNI3TlW.js.map → config-BrHR97zt.js.map} +1 -1
- package/dist/lib/{configure-peer-js-ChDhOZU4.js → configure-peer-js-ccNvax2N.js} +3 -3
- package/dist/lib/{configure-peer-js-ChDhOZU4.js.map → configure-peer-js-ccNvax2N.js.map} +1 -1
- package/dist/lib/{connections-DC4NZkJE.js → connections-C1FWsBsE.js} +2 -2
- package/dist/lib/{connections-DC4NZkJE.js.map → connections-C1FWsBsE.js.map} +1 -1
- package/dist/lib/{credentials-5vpz0XPk.js → credentials-CZbngHXW.js} +2 -2
- package/dist/lib/{credentials-5vpz0XPk.js.map → credentials-CZbngHXW.js.map} +1 -1
- package/dist/lib/{discover-skills-CD0sKvAI.js → discover-skills-OwlQ2sXA.js} +13 -13
- package/dist/lib/{discover-skills-CD0sKvAI.js.map → discover-skills-OwlQ2sXA.js.map} +1 -1
- package/dist/lib/{download-group-file-Dk3qaxhJ.js → download-group-file-D0wgg10Q.js} +2 -2
- package/dist/lib/{download-group-file-Dk3qaxhJ.js.map → download-group-file-D0wgg10Q.js.map} +1 -1
- package/dist/lib/{file-viewer-B4pRW-_G.js → file-viewer-DOfvX6yy.js} +5 -5
- package/dist/lib/{file-viewer-B4pRW-_G.js.map → file-viewer-DOfvX6yy.js.map} +1 -1
- package/dist/lib/{get-or-create-subscriber-id-HCcgDEPz.js → get-or-create-subscriber-id-wyzaML7Z.js} +2 -2
- package/dist/lib/{get-or-create-subscriber-id-HCcgDEPz.js.map → get-or-create-subscriber-id-wyzaML7Z.js.map} +1 -1
- package/dist/lib/{git-B3Q1euc5.js → git-D2J_j9X9.js} +5 -5
- package/dist/lib/{git-B3Q1euc5.js.map → git-D2J_j9X9.js.map} +1 -1
- package/dist/lib/{iframe-bridge-scripts-D8iuFhUk.js → iframe-bridge-scripts-Dx825LLG.js} +2 -2
- package/dist/lib/{iframe-bridge-scripts-D8iuFhUk.js.map → iframe-bridge-scripts-Dx825LLG.js.map} +1 -1
- package/dist/lib/index.js +28 -28
- package/dist/lib/{init-chat-split-resize-B0ODULx9.js → init-chat-split-resize-Cc0bd2z9.js} +2 -2
- package/dist/lib/{init-chat-split-resize-B0ODULx9.js.map → init-chat-split-resize-Cc0bd2z9.js.map} +1 -1
- package/dist/lib/{init-control-plane-C1FRRmjC.js → init-control-plane-B7blDVIE.js} +15 -15
- package/dist/lib/{init-control-plane-C1FRRmjC.js.map → init-control-plane-B7blDVIE.js.map} +1 -1
- package/dist/lib/{invoke-agent-CzN7sVh-.js → invoke-agent-SxvudiDT.js} +11 -11
- package/dist/lib/{invoke-agent-CzN7sVh-.js.map → invoke-agent-SxvudiDT.js.map} +1 -1
- package/dist/lib/{markdown-mbNo7cV3.js → markdown--6vTAPEH.js} +2 -2
- package/dist/lib/{markdown-mbNo7cV3.js.map → markdown--6vTAPEH.js.map} +1 -1
- package/dist/lib/{mcp-reconnect-3T7yWGEY.js → mcp-reconnect-BeqQvNWO.js} +3 -3
- package/dist/lib/{mcp-reconnect-3T7yWGEY.js.map → mcp-reconnect-BeqQvNWO.js.map} +1 -1
- package/dist/lib/{model-ranking-DGNSWYwN.js → model-ranking-BhsJV7vb.js} +2 -2
- package/dist/lib/{model-ranking-DGNSWYwN.js.map → model-ranking-BhsJV7vb.js.map} +1 -1
- package/dist/lib/{move-group-entry-NMTJ59M9.js → move-group-entry-DDpjxa10.js} +5 -5
- package/dist/lib/{move-group-entry-NMTJ59M9.js.map → move-group-entry-DDpjxa10.js.map} +1 -1
- package/dist/lib/{orchestrator-B8FV1V7x.js → orchestrator-C7fkh7T7.js} +24 -24
- package/dist/lib/{orchestrator-B8FV1V7x.js.map → orchestrator-C7fkh7T7.js.map} +1 -1
- package/dist/lib/{orchestrator-i_QJ-o22.js → orchestrator-CCARkxQC.js} +11 -11
- package/dist/lib/orchestrator-CCARkxQC.js.map +1 -0
- package/dist/lib/{parse-path-DPCn-HwI.js → parse-path-BOHQP_IQ.js} +3 -3
- package/dist/lib/{parse-path-DPCn-HwI.js.map → parse-path-BOHQP_IQ.js.map} +1 -1
- package/dist/lib/{peerjs-z5zeioPV.js → peerjs-Bfw_FWLB.js} +8 -8
- package/dist/lib/{peerjs-z5zeioPV.js.map → peerjs-Bfw_FWLB.js.map} +1 -1
- package/dist/lib/{process-peer-query-param-CJp7w7AU.js → process-peer-query-param-BxYiZNdf.js} +5 -5
- package/dist/lib/{process-peer-query-param-CJp7w7AU.js.map → process-peer-query-param-BxYiZNdf.js.map} +1 -1
- package/dist/lib/{process-pending-shared-payloads-B6_TlBFA.js → process-pending-shared-payloads-DPIbwRb3.js} +4 -4
- package/dist/lib/{process-pending-shared-payloads-B6_TlBFA.js.map → process-pending-shared-payloads-DPIbwRb3.js.map} +1 -1
- package/dist/lib/{process-room-query-param-C3FFGGn6.js → process-room-query-param-B2_d50nE.js} +4 -4
- package/dist/lib/{process-room-query-param-C3FFGGn6.js.map → process-room-query-param-B2_d50nE.js.map} +1 -1
- package/dist/lib/{provider-DcQZypu5.js → provider-BC9KPI14.js} +3 -3
- package/dist/lib/{provider-DcQZypu5.js.map → provider-BC9KPI14.js.map} +1 -1
- package/dist/lib/{push-client-Cx5rMs6J.js → push-client-rrjTdc-U.js} +5 -5
- package/dist/lib/{push-client-Cx5rMs6J.js.map → push-client-rrjTdc-U.js.map} +1 -1
- package/dist/lib/{read-group-file-bytes-CXOG_YyM.js → read-group-file-bytes-UQIk1eJG.js} +2 -2
- package/dist/lib/{read-group-file-bytes-CXOG_YyM.js.map → read-group-file-bytes-UQIk1eJG.js.map} +1 -1
- package/dist/lib/{rooms-CwlkYLDU.js → rooms-bwGoYb1q.js} +2 -2
- package/dist/lib/{rooms-CwlkYLDU.js.map → rooms-bwGoYb1q.js.map} +1 -1
- package/dist/lib/{shadow-claw-DoQ7fgl5.js → shadow-claw-CypGVlVO.js} +17 -20
- package/dist/lib/shadow-claw-CypGVlVO.js.map +1 -0
- package/dist/lib/{shadow-claw-a2ui-Br6qJMs1.js → shadow-claw-a2ui-lG0vQbW8.js} +2 -2
- package/dist/lib/{shadow-claw-a2ui-Br6qJMs1.js.map → shadow-claw-a2ui-lG0vQbW8.js.map} +1 -1
- package/dist/lib/{shadow-claw-accounts-BTDILfWw.js → shadow-claw-accounts-CkqyCxwp.js} +3 -3
- package/dist/lib/{shadow-claw-accounts-BTDILfWw.js.map → shadow-claw-accounts-CkqyCxwp.js.map} +1 -1
- package/dist/lib/{shadow-claw-channel-config-IKiL34tI.js → shadow-claw-channel-config-DJpDovkF.js} +4 -4
- package/dist/lib/{shadow-claw-channel-config-IKiL34tI.js.map → shadow-claw-channel-config-DJpDovkF.js.map} +1 -1
- package/dist/lib/{shadow-claw-channels-JgEzuHWK.js → shadow-claw-channels-DJLwRovH.js} +3 -3
- package/dist/lib/{shadow-claw-channels-JgEzuHWK.js.map → shadow-claw-channels-DJLwRovH.js.map} +1 -1
- package/dist/lib/{shadow-claw-chat-SGUDT31r.js → shadow-claw-chat-B92cPaft.js} +15 -15
- package/dist/lib/{shadow-claw-chat-SGUDT31r.js.map → shadow-claw-chat-B92cPaft.js.map} +1 -1
- package/dist/lib/{shadow-claw-control-plane-CRWFZ3vD.js → shadow-claw-control-plane-fvn-qyHj.js} +7 -7
- package/dist/lib/{shadow-claw-control-plane-CRWFZ3vD.js.map → shadow-claw-control-plane-fvn-qyHj.js.map} +1 -1
- package/dist/lib/{shadow-claw-conversations-D23GJ7qo.js → shadow-claw-conversations-CsVyDOny.js} +7 -7
- package/dist/lib/{shadow-claw-conversations-D23GJ7qo.js.map → shadow-claw-conversations-CsVyDOny.js.map} +1 -1
- package/dist/lib/{shadow-claw-file-viewer-C1V8WTiU.js → shadow-claw-file-viewer-DFfyP7s5.js} +10 -10
- package/dist/lib/{shadow-claw-file-viewer-C1V8WTiU.js.map → shadow-claw-file-viewer-DFfyP7s5.js.map} +1 -1
- package/dist/lib/{shadow-claw-files-DN7irmE1.js → shadow-claw-files-cT6HL7ye.js} +11 -11
- package/dist/lib/{shadow-claw-files-DN7irmE1.js.map → shadow-claw-files-cT6HL7ye.js.map} +1 -1
- package/dist/lib/{shadow-claw-git-D-1oIh65.js → shadow-claw-git-Cv9mQgTx.js} +6 -6
- package/dist/lib/{shadow-claw-git-D-1oIh65.js.map → shadow-claw-git-Cv9mQgTx.js.map} +1 -1
- package/dist/lib/{shadow-claw-integrations-CZjnm7cM.js → shadow-claw-integrations-RZZ-m-Id.js} +4 -4
- package/dist/lib/{shadow-claw-integrations-CZjnm7cM.js.map → shadow-claw-integrations-RZZ-m-Id.js.map} +1 -1
- package/dist/lib/{shadow-claw-llm-4Gefh5FN.js → shadow-claw-llm-CKOYzPDp.js} +9 -9
- package/dist/lib/{shadow-claw-llm-4Gefh5FN.js.map → shadow-claw-llm-CKOYzPDp.js.map} +1 -1
- package/dist/lib/{shadow-claw-mcp-remote-B9ssb3YV.js → shadow-claw-mcp-remote-BKFROurv.js} +4 -4
- package/dist/lib/{shadow-claw-mcp-remote-B9ssb3YV.js.map → shadow-claw-mcp-remote-BKFROurv.js.map} +1 -1
- package/dist/lib/{shadow-claw-networking-BN5BB4hb.js → shadow-claw-networking-DYfiUQaH.js} +2 -2
- package/dist/lib/{shadow-claw-networking-BN5BB4hb.js.map → shadow-claw-networking-DYfiUQaH.js.map} +1 -1
- package/dist/lib/{shadow-claw-notifications-71KARtkY.js → shadow-claw-notifications-JJlzriuX.js} +3 -3
- package/dist/lib/{shadow-claw-notifications-71KARtkY.js.map → shadow-claw-notifications-JJlzriuX.js.map} +1 -1
- package/dist/lib/{shadow-claw-page-header-DMGO-TSe.js → shadow-claw-page-header-C_Qr3xZM.js} +2 -2
- package/dist/lib/{shadow-claw-page-header-DMGO-TSe.js.map → shadow-claw-page-header-C_Qr3xZM.js.map} +1 -1
- package/dist/lib/{shadow-claw-pages-BiRM6qiA.js → shadow-claw-pages-BCo3ihZI.js} +11 -11
- package/dist/lib/{shadow-claw-pages-BiRM6qiA.js.map → shadow-claw-pages-BCo3ihZI.js.map} +1 -1
- package/dist/lib/{shadow-claw-peerjs-BZu7jNSe.js → shadow-claw-peerjs-CFNjfrY5.js} +6 -6
- package/dist/lib/{shadow-claw-peerjs-BZu7jNSe.js.map → shadow-claw-peerjs-CFNjfrY5.js.map} +1 -1
- package/dist/lib/{shadow-claw-provider-model-picker-BXYXEobD.js → shadow-claw-provider-model-picker-B-Ct4yW-.js} +2 -2
- package/dist/lib/{shadow-claw-provider-model-picker-BXYXEobD.js.map → shadow-claw-provider-model-picker-B-Ct4yW-.js.map} +1 -1
- package/dist/lib/{shadow-claw-settings-CcT5EK08.js → shadow-claw-settings-BMwne0bh.js} +7 -7
- package/dist/lib/{shadow-claw-settings-CcT5EK08.js.map → shadow-claw-settings-BMwne0bh.js.map} +1 -1
- package/dist/lib/{shadow-claw-storage-eTOpbvpi.js → shadow-claw-storage-DUY8B9m-.js} +5 -5
- package/dist/lib/{shadow-claw-storage-eTOpbvpi.js.map → shadow-claw-storage-DUY8B9m-.js.map} +1 -1
- package/dist/lib/{shadow-claw-task-server-DFImTUbw.js → shadow-claw-task-server-yWeoA3eL.js} +2 -2
- package/dist/lib/{shadow-claw-task-server-DFImTUbw.js.map → shadow-claw-task-server-yWeoA3eL.js.map} +1 -1
- package/dist/lib/{shadow-claw-tasks-BjaxsmUx.js → shadow-claw-tasks-Bg0uM15I.js} +9 -9
- package/dist/lib/{shadow-claw-tasks-BjaxsmUx.js.map → shadow-claw-tasks-Bg0uM15I.js.map} +1 -1
- package/dist/lib/{shadow-claw-terminal-C-4wreFe.js → shadow-claw-terminal-fyJPppY_.js} +2 -2
- package/dist/lib/{shadow-claw-terminal-C-4wreFe.js.map → shadow-claw-terminal-fyJPppY_.js.map} +1 -1
- package/dist/lib/{shadow-claw-tools-COdrGZJk.js → shadow-claw-tools-D0T8m3go.js} +7 -7
- package/dist/lib/{shadow-claw-tools-COdrGZJk.js.map → shadow-claw-tools-D0T8m3go.js.map} +1 -1
- package/dist/lib/{shadow-claw-webvm-sxqVjO0L.js → shadow-claw-webvm-CQvzJwKI.js} +3 -3
- package/dist/lib/{shadow-claw-webvm-sxqVjO0L.js.map → shadow-claw-webvm-CQvzJwKI.js.map} +1 -1
- package/dist/lib/{sync-web-mcp-registration-D4hdUwtv.js → sync-web-mcp-registration-BFtG_4kx.js} +6 -6
- package/dist/lib/{sync-web-mcp-registration-D4hdUwtv.js.map → sync-web-mcp-registration-BFtG_4kx.js.map} +1 -1
- package/dist/lib/{system-prompt-DT_KeYaL.js → system-prompt-bhGRLoL2.js} +7 -7
- package/dist/lib/{system-prompt-DT_KeYaL.js.map → system-prompt-bhGRLoL2.js.map} +1 -1
- package/dist/lib/{tools-Beuyh8y1.js → tools-B8OJ4sMF.js} +4 -4
- package/dist/lib/{tools-Beuyh8y1.js.map → tools-B8OJ4sMF.js.map} +1 -1
- package/dist/lib/{transformers-DydnReu4.js → transformers-BMURofG6.js} +2 -2
- package/dist/lib/{transformers-DydnReu4.js.map → transformers-BMURofG6.js.map} +1 -1
- package/dist/lib/{trusted-types-CfwZl_rr.js → trusted-types-HwsGS5Nj.js} +19 -17
- package/dist/lib/{trusted-types-CfwZl_rr.js.map → trusted-types-HwsGS5Nj.js.map} +1 -1
- package/dist/lib/{upload-group-file-BbBzjTcN.js → upload-group-file-CJpoNjEb.js} +3 -3
- package/dist/lib/{upload-group-file-BbBzjTcN.js.map → upload-group-file-CJpoNjEb.js.map} +1 -1
- package/dist/lib/utils/index.js +1 -1
- package/dist/lib/utils/namespaced-storage.js +1 -1
- package/dist/lib/utils/runtime-assets.js +1 -1
- package/dist/lib/utils/utils.js +1 -1
- package/dist/lib/{webmcp-DCfAFiIO.js → webmcp-BoMTvgmX.js} +3 -3
- package/dist/lib/{webmcp-DCfAFiIO.js.map → webmcp-BoMTvgmX.js.map} +1 -1
- package/dist/lib/{write-group-file-bytes-Ccn-VFUU.js → write-group-file-bytes-CNT7DqOZ.js} +3 -3
- package/dist/lib/{write-group-file-bytes-Ccn-VFUU.js.map → write-group-file-bytes-CNT7DqOZ.js.map} +1 -1
- package/dist/public/.well-known/mcp/server-card.json +12 -4
- package/dist/public/.well-known/mcp.json +12 -4
- package/dist/public/agent.worker.js +1 -1
- package/dist/public/attachment-capabilities-AdwXt3--.js +1 -0
- package/dist/public/{channel-BylT3rJC.js → channel-Dk7wl-Av.js} +1 -1
- package/dist/public/{chat-template-DPHJy7tr.js → chat-template-BwAnTFKf.js} +1 -1
- package/dist/public/{compact-context-BINQh64w.js → compact-context-fOTqwKF6.js} +2 -2
- package/dist/public/config-C16fFWtP.js +1 -0
- package/dist/public/{configure-peer-js-DChhcOfe.js → configure-peer-js-BOV0tR6G.js} +1 -1
- package/dist/public/{connections-CHaw0VqP.js → connections-Dxwj8yK_.js} +1 -1
- package/dist/public/{create-model-cache-fetch-DQebkoPL.js → create-model-cache-fetch-DSAFjOwc.js} +1 -1
- package/dist/public/{credentials-CgVqS119.js → credentials-CJUQ5Ep2.js} +1 -1
- package/dist/public/{custom-element-security-kiDhPfb8.js → custom-element-security-B2daIE5r.js} +2 -2
- package/dist/public/{discover-skills-Cvmx5I9V.js → discover-skills-D1sNTy2r.js} +6 -6
- package/dist/public/docs/example/article/index.html +28 -29
- package/dist/public/docs/example/article.html +28 -29
- package/dist/public/docs/publishing/index.html +28 -29
- package/dist/public/docs/publishing.html +28 -29
- package/dist/public/docs/skill-creator/index.html +28 -29
- package/dist/public/docs/skill-creator.html +28 -29
- package/dist/public/{download-group-file-BapoRgfU.js → download-group-file-BkMH-JKi.js} +1 -1
- package/dist/public/{e2e-bridge-C0g8vZKr.js → e2e-bridge-Cz95DLlb.js} +1 -1
- package/dist/public/get-group-dir-D--BiEyk.js +1 -0
- package/dist/public/{get-or-create-subscriber-id-GvRZYXwA.js → get-or-create-subscriber-id-jVHnQfbr.js} +1 -1
- package/dist/public/{git-CaAAZfVd.js → git-BmMlwIMP.js} +2 -2
- package/dist/public/{iframe-bridge-scripts-BnqtKhE4.js → iframe-bridge-scripts-Cibg0m6A.js} +1 -1
- package/dist/public/index.html +28 -29
- package/dist/public/index.js +1 -1
- package/dist/public/{init-chat-split-resize-Btonoy8u.js → init-chat-split-resize-C8AqCCiK.js} +1 -1
- package/dist/public/init-control-plane-Cb31yLTY.js +1 -0
- package/dist/public/{invoke-agent-B3Osw6K7.js → invoke-agent-CN7mSV0Z.js} +1 -1
- package/dist/public/main/index.html +28 -29
- package/dist/public/main/memory/index.html +28 -29
- package/dist/public/main/memory.html +28 -29
- package/dist/public/main.html +28 -29
- package/dist/public/{markdown-CPbU4r1U.js → markdown-CDSb5Hrl.js} +1 -1
- package/dist/public/{mcp-reconnect-CzROVsXG.js → mcp-reconnect-iPZPihwX.js} +1 -1
- package/dist/public/{memory-storage-BkoMlxOr.js → memory-storage-2m7KZ-aP.js} +1 -1
- package/dist/public/{model-ranking-CK0iBo3Z.js → model-ranking-BgOSaNIy.js} +1 -1
- package/dist/public/{move-group-entry-CTxoq7lw.js → move-group-entry-CXneuNVa.js} +1 -1
- package/dist/public/orchestrator-DBO4NZqd.js +63 -0
- package/dist/public/{orchestrator-BrDjQbGf.js → orchestrator-Dyylc8IU.js} +2 -2
- package/dist/public/{peerjs-CgF4Iz5W.js → peerjs-l0jiBoh6.js} +1 -1
- package/dist/public/{process-peer-query-param-BL2k0Hu-.js → process-peer-query-param-s-aSP1Rq.js} +1 -1
- package/dist/public/{process-pending-shared-payloads-C1AgGvn8.js → process-pending-shared-payloads-BN3GigPT.js} +1 -1
- package/dist/public/{process-room-query-param-DM0QCq3_.js → process-room-query-param-B2Qe0F0M.js} +1 -1
- package/dist/public/provider-YPZmsuHR.js +1 -0
- package/dist/public/{push-client-DJEOz7bi.js → push-client-B2LC8Qp9.js} +1 -1
- package/dist/public/{rooms-C6LXIJl4.js → rooms-ChCEOvkw.js} +1 -1
- package/dist/public/service-worker.js +1 -1
- package/dist/public/shadow-claw-Br8mWDUx.js +1176 -0
- package/dist/public/{shadow-claw-accounts--4hd_oCz.js → shadow-claw-accounts-Dm6G7KMP.js} +1 -1
- package/dist/public/{shadow-claw-card-IbNlZAdK.js → shadow-claw-card-CggS8uSa.js} +1 -1
- package/dist/public/{shadow-claw-channels-Vq_pPGa2.js → shadow-claw-channels-088vhuWO.js} +1 -1
- package/dist/public/{shadow-claw-chat-D7_GS25e.js → shadow-claw-chat-BRwRlq-n.js} +3 -3
- package/dist/public/{shadow-claw-control-plane-WTMEV8_p.js → shadow-claw-control-plane-rhKACK85.js} +2 -2
- package/dist/public/{shadow-claw-conversations-CLQgU1IT.js → shadow-claw-conversations-CF_yUfKl.js} +1 -1
- package/dist/public/{shadow-claw-empty-state-D4CrFGsN.js → shadow-claw-empty-state-CkpOSXCS.js} +1 -1
- package/dist/public/{shadow-claw-file-viewer-BhqiqLWQ.js → shadow-claw-file-viewer-DWCejuY3.js} +4 -4
- package/dist/public/{shadow-claw-files-senDiG9l.js → shadow-claw-files-L6_ioyzh.js} +2 -2
- package/dist/public/{shadow-claw-git-DOOCqY23.js → shadow-claw-git-DsdkwLqQ.js} +2 -2
- package/dist/public/{shadow-claw-integrations-Bsvc3Agq.js → shadow-claw-integrations-CSbRTOm3.js} +1 -1
- package/dist/public/{shadow-claw-llm-actYICAk.js → shadow-claw-llm-BitaeAVc.js} +2 -2
- package/dist/public/{shadow-claw-mcp-remote-BYUgrK3v.js → shadow-claw-mcp-remote-gSbV5riy.js} +1 -1
- package/dist/public/{shadow-claw-networking-Dk3p5Ny_.js → shadow-claw-networking-Dn_y6Cl9.js} +1 -1
- package/dist/public/{shadow-claw-notifications-CzPAlay8.js → shadow-claw-notifications-Cj4Lqx8U.js} +1 -1
- package/dist/public/{shadow-claw-page-header-CjJpVkyL.js → shadow-claw-page-header-DR4OZFt2.js} +1 -1
- package/dist/public/{shadow-claw-page-header-action-button-2DH5O1TD.js → shadow-claw-page-header-action-button-BnCV_2Kb.js} +1 -1
- package/dist/public/{shadow-claw-pages-3r5I-wI8.js → shadow-claw-pages-mpDOtNYj.js} +6 -6
- package/dist/public/{shadow-claw-pdf-viewer-BiCEwsoY.js → shadow-claw-pdf-viewer-DZ_84qJH.js} +1 -1
- package/dist/public/{shadow-claw-settings-DgB9RSZN.js → shadow-claw-settings-CfFTYTEy.js} +2 -2
- package/dist/public/{shadow-claw-storage-JB_43nd8.js → shadow-claw-storage-DLmiT4bG.js} +1 -1
- package/dist/public/{shadow-claw-task-server-oi5UIxdA.js → shadow-claw-task-server-BoMBCsiS.js} +1 -1
- package/dist/public/{shadow-claw-tasks-CnyiOt81.js → shadow-claw-tasks-ChEp1j7x.js} +3 -3
- package/dist/public/{shadow-claw-terminal-BC3RynHt.js → shadow-claw-terminal-BaoVbOda.js} +1 -1
- package/dist/public/{shadow-claw-toast-YjG--2Za.js → shadow-claw-toast-e8oz7z6Z.js} +1 -1
- package/dist/public/{shadow-claw-tools-Bbwk4vlT.js → shadow-claw-tools-BYjUBiJz.js} +1 -1
- package/dist/public/{shadow-claw-webvm-HZqzl2H5.js → shadow-claw-webvm-xGb13TME.js} +1 -1
- package/dist/public/{sync-web-mcp-registration-BaH2nAP0.js → sync-web-mcp-registration-CQluj-Kz.js} +1 -1
- package/dist/public/{system-prompt-Dck3N8T0.js → system-prompt-CTJn0tK-.js} +1 -1
- package/dist/public/{tools-DHA1dK2I.js → tools-D-52Zmfc.js} +1 -1
- package/dist/public/{transformers-C-DuTM2K.js → transformers-CQ9ss9rD.js} +1 -1
- package/dist/public/{upload-group-file-Cejr3zo1.js → upload-group-file-A8kB7lvO.js} +1 -1
- package/dist/public/{webmcp-CMRtu57-.js → webmcp-DIUZjVF5.js} +1 -1
- package/dist/public/{write-group-file-CmJuVQNO.js → write-group-file-R67DjJ-q.js} +1 -1
- package/dist/public/{write-group-file-bytes-Cejr3zo1.js → write-group-file-bytes-A8kB7lvO.js} +1 -1
- package/dist/public/{zip-reader-CuQ13eLe.js → zip-reader-DN7FB-Q0.js} +1 -1
- package/dist/server.js +1 -1
- package/package.json +1 -1
- package/dist/cli/chunk-BFziiMKt.js +0 -7
- package/dist/cli/chunk-BM3llsxb.js +0 -1
- package/dist/cli/chunk-Bj5qFsDi.js +0 -7
- package/dist/cli/chunk-Bj95zm-y.js +0 -1
- package/dist/cli/chunk-BpyP-esT.js +0 -1
- package/dist/cli/chunk-CX696s3_.js +0 -1
- package/dist/cli/chunk-DRxCrCAA.js +0 -139
- package/dist/cli/chunk-DjbCHa0h.js +0 -1
- package/dist/cli/chunk-DsQhAF31.js +0 -1
- package/dist/cli/chunk-VM-dECyG.js +0 -1
- package/dist/cli/chunk-heu2xRw1.js +0 -1
- package/dist/lib/orchestrator-i_QJ-o22.js.map +0 -1
- package/dist/lib/shadow-claw-DoQ7fgl5.js.map +0 -1
- package/dist/public/app-routes-V_-URXc5.js +0 -1
- package/dist/public/attachment-capabilities-B6ibLwQB.js +0 -1
- package/dist/public/config-C-YdSFZB.js +0 -1
- package/dist/public/get-group-dir-DL44kvqW.js +0 -1
- package/dist/public/init-control-plane-BoJijVtf.js +0 -1
- package/dist/public/orchestrator-CaUpEVkQ.js +0 -63
- package/dist/public/provider-DNIL4-Hw.js +0 -1
- package/dist/public/shadow-claw-DdgeYPg5.js +0 -1176
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as getConfig } from "./get-config-BWhs5HFF.js";
|
|
2
|
-
import { N as getGeneralAccountProviderCapabilities, b as OAUTH_PROVIDER_DEFINITIONS, h as GENERAL_ACCOUNT_PROVIDER_CAPABILITIES, r as CONFIG_KEYS } from "./config-
|
|
2
|
+
import { N as getGeneralAccountProviderCapabilities, b as OAUTH_PROVIDER_DEFINITIONS, h as GENERAL_ACCOUNT_PROVIDER_CAPABILITIES, r as CONFIG_KEYS } from "./config-BrHR97zt.js";
|
|
3
3
|
import { t as setConfig } from "./set-config-CUadvYZ1.js";
|
|
4
4
|
import { ulid } from "./utils/ulid.js";
|
|
5
5
|
import { n as decryptValue, r as encryptValue } from "./crypto-Bikgpqfe.js";
|
|
6
|
-
import { i as resolveStoredCredentialAuthMode, r as resolveGitCredentials, t as buildAuthHeaders } from "./credentials-
|
|
6
|
+
import { i as resolveStoredCredentialAuthMode, r as resolveGitCredentials, t as buildAuthHeaders } from "./credentials-CZbngHXW.js";
|
|
7
7
|
|
|
8
8
|
//#region src/subsystems/mcp/mcp-connections.ts
|
|
9
9
|
function isSafeAbsoluteUrl(value) {
|
|
@@ -1027,4 +1027,4 @@ async function reconnectMcpOAuth(db, connectionId, options = {}) {
|
|
|
1027
1027
|
|
|
1028
1028
|
//#endregion
|
|
1029
1029
|
export { testRemoteMcpConnection as a, deleteRemoteMcpConnection as c, upsertRemoteMcpConnection as d, listRemoteMcpTools as i, getRemoteMcpConnection as l, McpReauthRequiredError as n, resolveServiceCredentials as o, callRemoteMcpTool as r, bindRemoteMcpCredentialRef as s, reconnectMcpOAuth as t, listRemoteMcpConnections as u };
|
|
1030
|
-
//# sourceMappingURL=mcp-reconnect-
|
|
1030
|
+
//# sourceMappingURL=mcp-reconnect-BeqQvNWO.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-reconnect-3T7yWGEY.js","names":[],"sources":["../../src/subsystems/mcp/mcp-connections.ts","../../src/subsystems/accounts/service-accounts.ts","../../src/subsystems/mcp/mcp-connection-auth.ts","../../src/subsystems/mcp/remote-mcp-client.ts","../../src/subsystems/mcp/mcp-reconnect.ts"],"sourcesContent":["import { CONFIG_KEYS } from \"../../config/config.js\";\nimport { getConfig } from \"../../db/get-config.js\";\nimport { setConfig } from \"../../db/set-config.js\";\nimport { ulid } from \"../../utils/ulid.js\";\n\nimport type { ShadowClawDatabase } from \"../../db/types.js\";\nimport type { AuthType, ServiceType } from \"../../config/config.js\";\n\nexport type RemoteMcpTransport = \"streamable_http\" | \"sse\" | \"websocket\";\n\nexport interface RemoteMcpCredentialRef {\n serviceType: ServiceType;\n authType: AuthType;\n providerId?: string;\n accountId?: string;\n gitAccountId?: string;\n headerName?: string;\n encryptedValue?: string;\n}\n\nexport interface RemoteMcpConnectionRecord {\n id: string;\n label: string;\n serviceType: Extract<ServiceType, \"mcp_remote\" | \"webmcp_local\">;\n serverUrl: string;\n transport: RemoteMcpTransport;\n enabled: boolean;\n autoReconnectOAuth: boolean;\n createdAt: number;\n updatedAt: number;\n credentialRef: RemoteMcpCredentialRef | null;\n}\n\nexport interface UpsertRemoteMcpConnectionInput {\n id?: string;\n label: string;\n serviceType?: Extract<ServiceType, \"mcp_remote\" | \"webmcp_local\">;\n serverUrl: string;\n transport: RemoteMcpTransport;\n enabled?: boolean;\n autoReconnectOAuth?: boolean;\n}\n\nfunction isSafeAbsoluteUrl(value: unknown): value is string {\n if (typeof value !== \"string\" || !value.trim()) {\n return false;\n }\n\n try {\n const parsed = new URL(value);\n\n return parsed.protocol === \"https:\" || parsed.protocol === \"http:\";\n } catch {\n return false;\n }\n}\n\nfunction normalizeCredentialRef(\n value: unknown,\n connectionServiceType: RemoteMcpConnectionRecord[\"serviceType\"],\n): RemoteMcpCredentialRef | null {\n if (!value || typeof value !== \"object\") {\n return null;\n }\n\n const raw = value as RemoteMcpCredentialRef;\n if (!raw.serviceType || !raw.authType) {\n return null;\n }\n\n if (raw.serviceType !== connectionServiceType) {\n throw new Error(\n \"Credential ref serviceType must match connection serviceType\",\n );\n }\n\n return {\n serviceType: raw.serviceType,\n authType: raw.authType,\n providerId: raw.providerId || undefined,\n accountId: raw.accountId || undefined,\n gitAccountId: raw.gitAccountId || undefined,\n headerName: raw.headerName || undefined,\n encryptedValue: raw.encryptedValue || undefined,\n };\n}\n\nfunction normalizeConnection(value: unknown): RemoteMcpConnectionRecord | null {\n if (!value || typeof value !== \"object\") {\n return null;\n }\n\n const raw = value as Partial<RemoteMcpConnectionRecord>;\n if (\n !raw.id ||\n !raw.label ||\n !raw.serviceType ||\n !raw.transport ||\n typeof raw.enabled !== \"boolean\" ||\n typeof raw.createdAt !== \"number\" ||\n typeof raw.updatedAt !== \"number\" ||\n !isSafeAbsoluteUrl(raw.serverUrl)\n ) {\n return null;\n }\n\n if (raw.serviceType !== \"mcp_remote\" && raw.serviceType !== \"webmcp_local\") {\n return null;\n }\n\n if (\n raw.transport !== \"streamable_http\" &&\n raw.transport !== \"sse\" &&\n raw.transport !== \"websocket\"\n ) {\n return null;\n }\n\n return {\n id: raw.id,\n label: raw.label,\n serviceType: raw.serviceType,\n serverUrl: raw.serverUrl,\n transport: raw.transport,\n enabled: raw.enabled,\n autoReconnectOAuth: raw.autoReconnectOAuth === true,\n createdAt: raw.createdAt,\n updatedAt: raw.updatedAt,\n credentialRef: normalizeCredentialRef(raw.credentialRef, raw.serviceType),\n };\n}\n\nasync function loadConnections(\n db: ShadowClawDatabase,\n): Promise<RemoteMcpConnectionRecord[]> {\n const raw = await getConfig(db, CONFIG_KEYS.REMOTE_MCP_CONNECTIONS);\n if (!Array.isArray(raw)) {\n return [];\n }\n\n const normalized: RemoteMcpConnectionRecord[] = [];\n for (const item of raw) {\n const parsed = normalizeConnection(item);\n if (parsed) {\n normalized.push(parsed);\n }\n }\n\n return normalized;\n}\n\nasync function saveConnections(\n db: ShadowClawDatabase,\n connections: RemoteMcpConnectionRecord[],\n): Promise<void> {\n await setConfig(db, CONFIG_KEYS.REMOTE_MCP_CONNECTIONS, connections);\n}\n\nexport async function listRemoteMcpConnections(\n db: ShadowClawDatabase,\n): Promise<RemoteMcpConnectionRecord[]> {\n return loadConnections(db);\n}\n\nexport async function getRemoteMcpConnection(\n db: ShadowClawDatabase,\n id: string,\n): Promise<RemoteMcpConnectionRecord | null> {\n if (!id) {\n return null;\n }\n\n const all = await loadConnections(db);\n\n // Match by exact ID first, then fall back to case-insensitive label match\n // so agents can reference connections by human-readable name.\n\n return (\n all.find((connection) => connection.id === id) ||\n all.find(\n (connection) => connection.label.toLowerCase() === id.toLowerCase(),\n ) ||\n null\n );\n}\n\nexport async function upsertRemoteMcpConnection(\n db: ShadowClawDatabase,\n input: UpsertRemoteMcpConnectionInput,\n): Promise<RemoteMcpConnectionRecord> {\n if (!input?.label?.trim()) {\n throw new Error(\"Connection label is required\");\n }\n\n if (!isSafeAbsoluteUrl(input.serverUrl)) {\n throw new Error(\"Connection serverUrl must be an absolute http(s) URL\");\n }\n\n const serviceType = (input.serviceType ||\n \"mcp_remote\") as RemoteMcpConnectionRecord[\"serviceType\"];\n if (serviceType !== \"mcp_remote\" && serviceType !== \"webmcp_local\") {\n throw new Error(\"Unsupported serviceType for remote MCP connection\");\n }\n\n const all = await loadConnections(db);\n const now = Date.now();\n\n if (input.id) {\n const existingIndex = all.findIndex((record) => record.id === input.id);\n if (existingIndex !== -1) {\n const existing = all[existingIndex];\n const updated: RemoteMcpConnectionRecord = {\n ...existing,\n label: input.label.trim(),\n serviceType,\n serverUrl: input.serverUrl,\n transport: input.transport,\n enabled: input.enabled ?? existing.enabled,\n autoReconnectOAuth:\n input.autoReconnectOAuth ?? existing.autoReconnectOAuth,\n updatedAt: now,\n };\n all[existingIndex] = updated;\n await saveConnections(db, all);\n\n return updated;\n }\n }\n\n const created: RemoteMcpConnectionRecord = {\n id: input.id || ulid(),\n label: input.label.trim(),\n serviceType,\n serverUrl: input.serverUrl,\n transport: input.transport,\n enabled: input.enabled ?? true,\n autoReconnectOAuth: input.autoReconnectOAuth ?? false,\n createdAt: now,\n updatedAt: now,\n credentialRef: null,\n };\n\n all.push(created);\n await saveConnections(db, all);\n\n return created;\n}\n\nexport async function bindRemoteMcpCredentialRef(\n db: ShadowClawDatabase,\n connectionId: string,\n credentialRef: RemoteMcpCredentialRef | null,\n): Promise<RemoteMcpConnectionRecord | null> {\n if (!connectionId) {\n return null;\n }\n\n const all = await loadConnections(db);\n const idx = all.findIndex((record) => record.id === connectionId);\n if (idx === -1) {\n return null;\n }\n\n const current = all[idx];\n const normalizedRef = credentialRef\n ? normalizeCredentialRef(credentialRef, current.serviceType)\n : null;\n\n const updated: RemoteMcpConnectionRecord = {\n ...current,\n credentialRef: normalizedRef,\n updatedAt: Date.now(),\n };\n\n all[idx] = updated;\n await saveConnections(db, all);\n\n return updated;\n}\n\nexport async function deleteRemoteMcpConnection(\n db: ShadowClawDatabase,\n id: string,\n): Promise<boolean> {\n if (!id) {\n return false;\n }\n\n const all = await loadConnections(db);\n const next = all.filter((record) => record.id !== id);\n if (next.length === all.length) {\n return false;\n }\n\n await saveConnections(db, next);\n\n return true;\n}\n","import {\n CONFIG_KEYS,\n GENERAL_ACCOUNT_PROVIDER_CAPABILITIES,\n getGeneralAccountProviderCapabilities,\n} from \"../../config/config.js\";\nimport { getConfig } from \"../../db/get-config.js\";\nimport { setConfig } from \"../../db/set-config.js\";\nimport { decryptValue, encryptValue } from \"../../security/crypto.js\";\nimport {\n resolveStoredCredentialAuthMode,\n type StoredCredentialAuthMode,\n type StoredCredentialBase,\n type StoredCredentialOAuthFields,\n} from \"./stored-credentials.js\";\n\nimport type { ShadowClawDatabase } from \"../../db/types.js\";\nimport type { GeneralAccountProviderCapabilities } from \"../../config/config.js\";\n\nexport type AccountAuthMode = StoredCredentialAuthMode;\n\nexport interface ServiceAccount\n extends StoredCredentialBase, StoredCredentialOAuthFields {\n service: string;\n}\n\nexport interface ResolvedServiceCredentials {\n token: string;\n service: string;\n hostPattern: string;\n headerName: string; // e.g. \"Authorization\", \"X-Figma-Token\"\n headerValue: string; // e.g. \"Bearer TOKEN\", \"TOKEN\" (no prefix)\n accountId: string;\n authMode: AccountAuthMode;\n reauthRequired?: boolean;\n}\n\nexport interface ResolveServiceCredentialsOptions {\n accountId?: string;\n authMode?: AccountAuthMode;\n forceRefresh?: boolean;\n}\n\nconst OAUTH_REFRESH_WINDOW_MS = 60_000;\nconst OAUTH_REFRESH_FAILURE_THRESHOLD = 3;\n\nfunction resolveAccountAuthMode(account: ServiceAccount): AccountAuthMode {\n return resolveStoredCredentialAuthMode(account);\n}\n\nfunction shouldRefreshOAuthToken(\n account: ServiceAccount,\n options: ResolveServiceCredentialsOptions,\n): boolean {\n if (resolveAccountAuthMode(account) !== \"oauth\") {\n return false;\n }\n\n if (account.oauthReauthRequired) {\n return false;\n }\n\n if (\n !account.refreshToken ||\n !account.oauthProviderId ||\n !account.oauthClientId\n ) {\n return false;\n }\n\n if (options.forceRefresh) {\n return true;\n }\n\n if (!account.accessTokenExpiresAt) {\n return false;\n }\n\n return account.accessTokenExpiresAt <= Date.now() + OAUTH_REFRESH_WINDOW_MS;\n}\n\nasync function tryRefreshOAuthAccount(\n db: ShadowClawDatabase,\n accounts: ServiceAccount[],\n account: ServiceAccount,\n): Promise<ServiceAccount> {\n if (\n !account.refreshToken ||\n !account.oauthProviderId ||\n !account.oauthClientId\n ) {\n return account;\n }\n\n const decryptedRefreshToken = await decryptValue(account.refreshToken);\n if (!decryptedRefreshToken) {\n return account;\n }\n\n const oauthClientSecret = account.oauthClientSecret\n ? await decryptValue(account.oauthClientSecret)\n : undefined;\n\n const persistAccount = async (updatedAccount: ServiceAccount) => {\n const idx = accounts.findIndex((candidate) => candidate.id === account.id);\n if (idx !== -1) {\n accounts[idx] = updatedAccount;\n await setConfig(db, CONFIG_KEYS.SERVICE_ACCOUNTS, accounts);\n }\n };\n\n const markRefreshFailure = async (): Promise<ServiceAccount> => {\n const failureCount = (account.oauthRefreshFailureCount || 0) + 1;\n const reauthRequired = failureCount >= OAUTH_REFRESH_FAILURE_THRESHOLD;\n const updatedAccount: ServiceAccount = {\n ...account,\n oauthRefreshFailureCount: failureCount,\n oauthReauthRequired: reauthRequired,\n oauthReauthRequiredAt: reauthRequired\n ? account.oauthReauthRequiredAt || Date.now()\n : undefined,\n };\n await persistAccount(updatedAccount);\n\n return updatedAccount;\n };\n\n try {\n const response = await fetch(\"/oauth/refresh\", {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n providerId: account.oauthProviderId,\n clientId: account.oauthClientId,\n clientSecret: oauthClientSecret,\n refreshToken: decryptedRefreshToken,\n scope: account.scopes,\n tokenUrl: account.oauthCustomTokenUrl,\n }),\n });\n\n if (!response.ok) {\n return markRefreshFailure();\n }\n\n const payload = (await response.json()) as {\n accessToken?: string;\n refreshToken?: string;\n expiresIn?: number;\n tokenType?: string;\n scope?: string;\n };\n\n if (!payload.accessToken) {\n return markRefreshFailure();\n }\n\n const encryptedAccessToken = await encryptValue(payload.accessToken);\n if (!encryptedAccessToken) {\n return markRefreshFailure();\n }\n\n let encryptedRefreshToken = account.refreshToken;\n if (payload.refreshToken) {\n const maybeEncryptedRefreshToken = await encryptValue(\n payload.refreshToken,\n );\n if (maybeEncryptedRefreshToken) {\n encryptedRefreshToken = maybeEncryptedRefreshToken;\n }\n }\n\n const updatedAccount: ServiceAccount = {\n ...account,\n token: encryptedAccessToken,\n refreshToken: encryptedRefreshToken,\n accessTokenExpiresAt: payload.expiresIn\n ? Date.now() + payload.expiresIn * 1000\n : account.accessTokenExpiresAt,\n tokenType: payload.tokenType || account.tokenType,\n scopes: payload.scope\n ? payload.scope\n .split(/[\\s,]+/)\n .map((scope) => scope.trim())\n .filter(Boolean)\n : account.scopes,\n oauthRefreshFailureCount: 0,\n oauthReauthRequired: false,\n oauthReauthRequiredAt: undefined,\n };\n\n await persistAccount(updatedAccount);\n\n return updatedAccount;\n } catch {\n return markRefreshFailure();\n }\n}\n\nfunction resolveProviderCapabilities(\n account: ServiceAccount,\n url?: string,\n): GeneralAccountProviderCapabilities | null {\n if (account.oauthProviderId) {\n const direct = getGeneralAccountProviderCapabilities(\n account.oauthProviderId,\n );\n if (direct) {\n return direct;\n }\n }\n\n const hints = [account.service, account.hostPattern, url]\n .filter((value): value is string => !!value)\n .map((value) => value.toLowerCase());\n\n for (const provider of Object.values(GENERAL_ACCOUNT_PROVIDER_CAPABILITIES)) {\n const aliases = [provider.providerId, ...(provider.aliases || [])].map(\n (alias) => alias.toLowerCase(),\n );\n\n if (aliases.some((alias) => hints.some((hint) => hint.includes(alias)))) {\n return provider;\n }\n }\n\n return null;\n}\n\n/**\n * Resolve auth header format from provider capabilities. Falls back to Bearer.\n */\nfunction getServiceAuthFormat(\n account: ServiceAccount,\n url?: string,\n): {\n headerName: string;\n headerPrefix: string;\n} {\n const authMode = resolveAccountAuthMode(account);\n const provider = resolveProviderCapabilities(account, url);\n if (provider) {\n let scheme;\n if (authMode === \"oauth\") {\n scheme = provider.tokenAuth.oauth;\n } else if (authMode === \"basic\" && provider.tokenAuth.basic) {\n scheme = provider.tokenAuth.basic;\n } else {\n scheme = provider.tokenAuth.token;\n }\n\n return {\n headerName: scheme.headerName,\n headerPrefix: scheme.headerPrefix || \"\",\n };\n }\n\n return {\n headerName: \"Authorization\",\n headerPrefix: authMode === \"basic\" ? \"Basic \" : \"Bearer \",\n };\n}\n\n/**\n * Find the most-specific (longest hostPattern) account that matches a URL.\n */\nfunction matchAccountsByHost(\n accounts: ServiceAccount[],\n url: string,\n): ServiceAccount[] {\n const matches: ServiceAccount[] = [];\n let bestLen = -1;\n const lower = url.toLowerCase();\n\n for (const acct of accounts) {\n if (!acct.hostPattern) {\n continue;\n }\n\n const pattern = acct.hostPattern.toLowerCase();\n if (lower.includes(pattern)) {\n if (pattern.length > bestLen) {\n bestLen = pattern.length;\n matches.length = 0;\n matches.push(acct);\n } else if (pattern.length === bestLen) {\n matches.push(acct);\n }\n }\n }\n\n return matches;\n}\n\nfunction pickAccountByAuthMode(\n accounts: ServiceAccount[],\n authMode?: AccountAuthMode,\n): ServiceAccount | undefined {\n if (!accounts.length) {\n return undefined;\n }\n\n if (!authMode) {\n return accounts[0];\n }\n\n const modeMatch = accounts.find(\n (acct) => resolveAccountAuthMode(acct) === authMode,\n );\n if (modeMatch) {\n return modeMatch;\n }\n\n return accounts[0];\n}\n\n/**\n * Resolve a decrypted service account PAT for the given URL.\n *\n * Resolution order:\n * 1. Longest hostPattern match against the URL\n * 2. SERVICE_DEFAULT_ACCOUNT\n * 3. First account in the list\n *\n * Returns undefined when no accounts are configured.\n */\nexport async function resolveServiceCredentials(\n db: ShadowClawDatabase,\n url?: string,\n options: ResolveServiceCredentialsOptions = {},\n): Promise<ResolvedServiceCredentials | undefined> {\n const raw = await getConfig(db, CONFIG_KEYS.SERVICE_ACCOUNTS);\n const accounts: ServiceAccount[] = Array.isArray(raw) ? raw : [];\n\n if (accounts.length === 0) {\n return undefined;\n }\n\n let account: ServiceAccount | undefined;\n\n if (options.accountId) {\n account = accounts.find((a) => a.id === options.accountId);\n }\n\n // 1. Match by URL host pattern\n if (!account && url) {\n const hostMatches = matchAccountsByHost(accounts, url);\n if (options.authMode) {\n account = pickAccountByAuthMode(hostMatches, options.authMode);\n } else {\n const preferredMode = hostMatches[0]\n ? resolveProviderCapabilities(hostMatches[0], url)?.defaultMode\n : undefined;\n account = pickAccountByAuthMode(hostMatches, preferredMode);\n }\n }\n\n // 2. Fall back to stored default\n if (!account) {\n const defaultId = await getConfig(db, CONFIG_KEYS.SERVICE_DEFAULT_ACCOUNT);\n if (defaultId) {\n account = accounts.find((a) => a.id === defaultId);\n }\n }\n\n // 3. Fall back to first account matching requested mode\n if (!account && options.authMode) {\n account = pickAccountByAuthMode(accounts, options.authMode);\n }\n\n // 4. Fall back to first\n if (!account) {\n account = accounts[0];\n }\n\n if (!account) {\n return undefined;\n }\n\n if (shouldRefreshOAuthToken(account, options)) {\n account = await tryRefreshOAuthAccount(db, accounts, account);\n }\n\n if (\n resolveAccountAuthMode(account) === \"oauth\" &&\n account.oauthReauthRequired\n ) {\n return {\n token: \"\",\n service: account.service,\n hostPattern: account.hostPattern,\n headerName: \"Authorization\",\n headerValue: \"\",\n accountId: account.id,\n authMode: \"oauth\",\n reauthRequired: true,\n };\n }\n\n let token = \"\";\n if (account.token) {\n token = (await decryptValue(account.token)) ?? \"\";\n }\n\n const { headerName, headerPrefix } = getServiceAuthFormat(account, url);\n let finalToken = token;\n\n if (resolveAccountAuthMode(account) === \"basic\" && account.basicUsername) {\n finalToken = btoa(`${account.basicUsername}:${token}`);\n }\n\n const headerValue = headerPrefix\n ? `${headerPrefix}${finalToken}`\n : finalToken;\n\n return {\n token,\n service: account.service,\n hostPattern: account.hostPattern,\n headerName,\n headerValue,\n accountId: account.id,\n authMode: resolveAccountAuthMode(account),\n };\n}\n","import { decryptValue } from \"../../security/crypto.js\";\nimport { getRemoteMcpConnection } from \"./mcp-connections.js\";\nimport { resolveServiceCredentials } from \"../accounts/service-accounts.js\";\nimport { buildAuthHeaders, resolveGitCredentials } from \"../git/credentials.js\";\n\nimport type { ShadowClawDatabase } from \"../../db/types.js\";\nimport type { RemoteMcpConnectionRecord } from \"./mcp-connections.js\";\nimport type { AuthType } from \"../../config/config.js\";\n\nexport interface ResolvedRemoteMcpAuth {\n connection: RemoteMcpConnectionRecord;\n authType: AuthType;\n headers: Record<string, string>;\n reauthRequired?: boolean;\n}\n\nexport interface ResolveRemoteMcpAuthOptions {\n forceRefresh?: boolean;\n}\n\nfunction toAccountAuthMode(authType: AuthType): \"token\" | \"oauth\" | \"basic\" {\n return authType === \"oauth\" ? \"oauth\" : \"token\";\n}\n\nexport async function resolveRemoteMcpConnectionAuth(\n db: ShadowClawDatabase,\n connectionId: string,\n options: ResolveRemoteMcpAuthOptions = {},\n): Promise<ResolvedRemoteMcpAuth | null> {\n const connection = await getRemoteMcpConnection(db, connectionId);\n if (!connection) {\n return null;\n }\n\n const ref = connection.credentialRef;\n if (!ref || ref.authType === \"none\") {\n return {\n connection,\n authType: \"none\",\n headers: {},\n };\n }\n\n if (ref.authType === \"custom_header\") {\n if (!ref.headerName || !ref.encryptedValue) {\n return {\n connection,\n authType: \"custom_header\",\n headers: {},\n };\n }\n\n const decrypted = await decryptValue(ref.encryptedValue);\n\n return {\n connection,\n authType: \"custom_header\",\n headers: decrypted ? { [ref.headerName]: decrypted } : {},\n };\n }\n\n const authMode = toAccountAuthMode(ref.authType);\n\n if (ref.accountId) {\n const creds = await resolveServiceCredentials(db, connection.serverUrl, {\n accountId: ref.accountId,\n authMode,\n forceRefresh: options.forceRefresh,\n });\n\n if (!creds) {\n return {\n connection,\n authType: ref.authType,\n headers: {},\n };\n }\n\n if (creds.reauthRequired) {\n return {\n connection,\n authType: ref.authType,\n headers: {},\n reauthRequired: true,\n };\n }\n\n return {\n connection,\n authType: ref.authType,\n headers: creds.headerValue\n ? { [creds.headerName]: creds.headerValue }\n : {},\n };\n }\n\n if (ref.gitAccountId) {\n const creds = await resolveGitCredentials(db, connection.serverUrl, {\n accountId: ref.gitAccountId,\n authMode,\n forceRefresh: options.forceRefresh,\n });\n\n if (creds.reauthRequired) {\n return {\n connection,\n authType: ref.authType,\n headers: {},\n reauthRequired: true,\n };\n }\n\n return {\n connection,\n authType: ref.authType,\n headers: buildAuthHeaders(creds),\n };\n }\n\n return {\n connection,\n authType: ref.authType,\n headers: {},\n };\n}\n","import { resolveRemoteMcpConnectionAuth } from \"./mcp-connection-auth.js\";\n\nimport type { ShadowClawDatabase } from \"../../db/types.js\";\n\ninterface RemoteMcpSession {\n sessionId: string;\n protocolVersion?: string;\n lastUsedAt: number;\n}\n\nconst remoteMcpSessions: Map<string, RemoteMcpSession> = new Map();\n\ninterface JsonRpcSuccess<T> {\n jsonrpc: \"2.0\";\n id: string;\n result: T;\n}\n\ninterface JsonRpcError {\n jsonrpc: \"2.0\";\n id: string;\n error: {\n code: number;\n message: string;\n data?: unknown;\n };\n}\n\ntype JsonRpcResponse<T> = JsonRpcSuccess<T> | JsonRpcError;\n\ninterface JsonRpcServerRequest {\n jsonrpc: \"2.0\";\n id: string | number;\n method: string;\n params?: Record<string, unknown>;\n}\n\nfunction isServerRequest(msg: unknown): msg is JsonRpcServerRequest {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"method\" in msg &&\n \"id\" in msg &&\n !(\"result\" in msg) &&\n !(\"error\" in msg)\n );\n}\n\nfunction buildElicitationDefaults(\n params: Record<string, unknown>,\n): Record<string, unknown> {\n const schema = (params.requestedSchema || {}) as Record<string, unknown>;\n const properties = (schema.properties || {}) as Record<\n string,\n Record<string, unknown>\n >;\n const defaults: Record<string, unknown> = {};\n\n for (const [key, prop] of Object.entries(properties)) {\n if (\"default\" in prop) {\n defaults[key] = prop.default;\n } else if (prop.type === \"boolean\") {\n defaults[key] = true;\n }\n }\n\n return defaults;\n}\n\ninterface ToolListResult {\n tools?: Array<{ name: string; description?: string }>;\n}\n\ninterface ToolCallResult {\n content?: unknown[];\n isError?: boolean;\n}\n\ninterface JsonRpcInitializeResult {\n protocolVersion?: string;\n}\n\nclass InvalidRemoteMcpSessionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"InvalidRemoteMcpSessionError\";\n }\n}\n\nclass HttpRemoteMcpError extends Error {\n status: number;\n constructor(status: number, message: string) {\n super(message);\n this.name = \"HttpRemoteMcpError\";\n this.status = status;\n }\n}\n\nexport class McpReauthRequiredError extends Error {\n connectionId: string;\n constructor(connectionId: string) {\n super(\"OAuth reconnect required for remote MCP connection\");\n this.name = \"McpReauthRequiredError\";\n this.connectionId = connectionId;\n }\n}\n\ninterface HttpLikeResponse {\n ok: boolean;\n status: number;\n json: () => Promise<unknown>;\n text?: () => Promise<string>;\n headers?: {\n get?: (name: string) => string | null;\n };\n}\n\nfunction getHeader(response: HttpLikeResponse, name: string): string | null {\n if (!response.headers || typeof response.headers.get !== \"function\") {\n return null;\n }\n\n return response.headers.get(name);\n}\n\nfunction isInvalidSessionMessage(message: string): boolean {\n return /no valid session id provided/i.test(message);\n}\n\nfunction toError(\n response: HttpLikeResponse,\n payload: JsonRpcResponse<unknown> | null,\n): Error {\n const jsonRpcMessage =\n payload && \"error\" in payload\n ? payload.error.message || \"Remote MCP JSON-RPC error\"\n : \"\";\n\n if (isInvalidSessionMessage(jsonRpcMessage)) {\n return new InvalidRemoteMcpSessionError(jsonRpcMessage);\n }\n\n if (!response.ok) {\n return new HttpRemoteMcpError(\n response.status,\n jsonRpcMessage\n ? `Remote MCP HTTP error: ${response.status} (${jsonRpcMessage})`\n : `Remote MCP HTTP error: ${response.status}`,\n );\n }\n\n return new Error(jsonRpcMessage || \"Remote MCP JSON-RPC error\");\n}\n\nfunction parseJsonRpcFromSseText<T>(raw: string): JsonRpcResponse<T> | null {\n if (!raw) {\n return null;\n }\n\n let lastJsonRpc: JsonRpcResponse<T> | null = null;\n const lines = raw.split(/\\r?\\n/);\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"data:\")) {\n continue;\n }\n\n const data = trimmed.slice(5).trim();\n if (!data || data === \"[DONE]\") {\n continue;\n }\n\n try {\n const parsed = JSON.parse(data) as JsonRpcResponse<T>;\n if (parsed && typeof parsed === \"object\" && \"jsonrpc\" in parsed) {\n lastJsonRpc = parsed;\n }\n } catch {\n // Ignore malformed SSE data chunks and keep scanning.\n }\n }\n\n return lastJsonRpc;\n}\n\nfunction parseJsonRpcFromText<T>(raw: string): JsonRpcResponse<T> | null {\n if (!raw) {\n return null;\n }\n\n try {\n return JSON.parse(raw) as JsonRpcResponse<T>;\n } catch {\n return null;\n }\n}\n\nasync function postJsonRpc<T>(\n url: string,\n headers: Record<string, string>,\n body: Record<string, unknown>,\n): Promise<{\n response: HttpLikeResponse;\n payload: JsonRpcResponse<T> | null;\n}> {\n const response = (await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n accept: \"application/json, text/event-stream\",\n ...headers,\n },\n body: JSON.stringify(body),\n })) as HttpLikeResponse;\n\n const contentType = (getHeader(response, \"content-type\") || \"\").toLowerCase();\n let payload: JsonRpcResponse<T> | null = null;\n\n if (typeof response.text === \"function\") {\n const raw = await response.text();\n payload = contentType.includes(\"text/event-stream\")\n ? parseJsonRpcFromSseText<T>(raw)\n : parseJsonRpcFromText<T>(raw);\n } else {\n try {\n payload = (await response.json()) as JsonRpcResponse<T>;\n } catch {\n payload = null;\n }\n }\n\n return { response, payload };\n}\n\nasync function sendInitializedNotification(\n serverUrl: string,\n headers: Record<string, string>,\n sessionId: string,\n): Promise<void> {\n const { response, payload } = await postJsonRpc<unknown>(\n serverUrl,\n {\n ...headers,\n \"mcp-session-id\": sessionId,\n },\n {\n jsonrpc: \"2.0\",\n method: \"notifications/initialized\",\n params: {},\n },\n );\n\n if (!response.ok || (payload && \"error\" in payload)) {\n throw toError(response, payload);\n }\n}\n\nasync function ensureRemoteMcpSession(\n connectionId: string,\n serverUrl: string,\n headers: Record<string, string>,\n): Promise<RemoteMcpSession> {\n const existing = remoteMcpSessions.get(connectionId);\n if (existing?.sessionId) {\n return existing;\n }\n\n const { response, payload } = await postJsonRpc<JsonRpcInitializeResult>(\n serverUrl,\n headers,\n {\n jsonrpc: \"2.0\",\n id: `initialize-${Date.now().toString(36)}`,\n method: \"initialize\",\n params: {\n protocolVersion: \"2025-03-26\",\n capabilities: {\n elicitation: {},\n },\n clientInfo: {\n name: \"shadowclaw-remote-mcp-client\",\n version: \"1.0.0\",\n },\n },\n },\n );\n\n if (!response.ok) {\n throw toError(response, payload);\n }\n\n if (payload && \"error\" in payload) {\n throw toError(response, payload);\n }\n\n const sessionId =\n getHeader(response, \"mcp-session-id\") ||\n `local-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\n const session: RemoteMcpSession = {\n sessionId,\n protocolVersion:\n getHeader(response, \"mcp-protocol-version\") ||\n (payload as { result?: { protocolVersion?: string } } | null)?.result\n ?.protocolVersion,\n lastUsedAt: Date.now(),\n };\n\n await sendInitializedNotification(serverUrl, headers, sessionId);\n remoteMcpSessions.set(connectionId, session);\n\n return session;\n}\n\nasync function callRemoteMcpWithSession<T>(\n connectionId: string,\n serverUrl: string,\n headers: Record<string, string>,\n method: string,\n params?: Record<string, unknown>,\n): Promise<T> {\n let session = await ensureRemoteMcpSession(connectionId, serverUrl, headers);\n\n const doRequest = async (activeSessionId: string) => {\n const body = {\n jsonrpc: \"2.0\",\n id: Date.now().toString(),\n method,\n params: params || {},\n };\n\n const sessionHeaders = {\n ...headers,\n \"mcp-session-id\": activeSessionId,\n };\n\n let { response, payload } = await postJsonRpc<T>(\n serverUrl,\n sessionHeaders,\n body,\n );\n\n // Handle server-initiated requests (e.g., elicitation/create).\n // The gateway may ask the client to confirm before completing a tool call.\n let elicitationAttempts = 0;\n while (isServerRequest(payload) && elicitationAttempts < 5) {\n elicitationAttempts++;\n\n if (payload.method === \"elicitation/create\") {\n const elicitationParams = (payload.params || {}) as Record<\n string,\n unknown\n >;\n const defaults = buildElicitationDefaults(elicitationParams);\n\n ({ response, payload } = await postJsonRpc<T>(\n serverUrl,\n sessionHeaders,\n {\n jsonrpc: \"2.0\",\n id: payload.id,\n result: {\n action: \"accept\",\n content: defaults,\n },\n },\n ));\n } else {\n break;\n }\n }\n\n if (isServerRequest(payload)) {\n throw new Error(\n `Unsupported server request: ${(payload as JsonRpcServerRequest).method}`,\n );\n }\n\n if (!response.ok || !payload || \"error\" in payload) {\n throw toError(response, payload);\n }\n\n return payload.result;\n };\n\n try {\n const result = await doRequest(session.sessionId);\n session.lastUsedAt = Date.now();\n remoteMcpSessions.set(connectionId, session);\n\n return result;\n } catch (err) {\n if (!(err instanceof InvalidRemoteMcpSessionError)) {\n throw err;\n }\n\n // Session expired or unknown on server side; refresh once and retry.\n remoteMcpSessions.delete(connectionId);\n session = await ensureRemoteMcpSession(connectionId, serverUrl, headers);\n const result = await doRequest(session.sessionId);\n session.lastUsedAt = Date.now();\n remoteMcpSessions.set(connectionId, session);\n\n return result;\n }\n}\n\nexport function clearRemoteMcpSession(connectionId: string): void {\n if (!connectionId) {\n return;\n }\n\n remoteMcpSessions.delete(connectionId);\n}\n\nexport function clearAllRemoteMcpSessions(): void {\n remoteMcpSessions.clear();\n}\n\nasync function callRemoteMcp<T>(\n db: ShadowClawDatabase,\n connectionId: string,\n method: string,\n params?: Record<string, unknown>,\n): Promise<T> {\n const resolved = await resolveRemoteMcpConnectionAuth(db, connectionId);\n if (!resolved) {\n throw new Error(\"Remote MCP connection not found\");\n }\n\n if (resolved.reauthRequired) {\n throw new McpReauthRequiredError(connectionId);\n }\n\n const { connection, authType, headers } = resolved;\n\n if (connection.transport !== \"streamable_http\") {\n throw new Error(\"Unsupported remote MCP transport\");\n }\n\n try {\n return await callRemoteMcpWithSession<T>(\n connectionId,\n connection.serverUrl,\n headers,\n method,\n params,\n );\n } catch (err) {\n if (\n !(err instanceof HttpRemoteMcpError) ||\n err.status !== 401 ||\n authType !== \"oauth\"\n ) {\n throw err;\n }\n\n // 401 with OAuth — force-refresh token and retry once.\n clearRemoteMcpSession(connectionId);\n\n const refreshed = await resolveRemoteMcpConnectionAuth(db, connectionId, {\n forceRefresh: true,\n });\n\n if (!refreshed || refreshed.reauthRequired) {\n throw new McpReauthRequiredError(connectionId);\n }\n\n try {\n return await callRemoteMcpWithSession<T>(\n connectionId,\n refreshed.connection.serverUrl,\n refreshed.headers,\n method,\n params,\n );\n } catch (retryErr) {\n if (retryErr instanceof HttpRemoteMcpError && retryErr.status === 401) {\n throw new McpReauthRequiredError(connectionId);\n }\n\n throw retryErr;\n }\n }\n}\n\nexport async function listRemoteMcpTools(\n db: ShadowClawDatabase,\n connectionId: string,\n): Promise<Array<{ name: string; description?: string }>> {\n const result = await callRemoteMcp<ToolListResult>(\n db,\n connectionId,\n \"tools/list\",\n );\n\n return Array.isArray(result.tools) ? result.tools : [];\n}\n\nexport async function callRemoteMcpTool(\n db: ShadowClawDatabase,\n connectionId: string,\n name: string,\n argumentsInput: Record<string, unknown> = {},\n): Promise<ToolCallResult> {\n return callRemoteMcp<ToolCallResult>(db, connectionId, \"tools/call\", {\n name,\n arguments: argumentsInput,\n });\n}\n\nexport interface McpConnectionTestStep {\n step: string;\n status: \"ok\" | \"error\" | \"skipped\";\n detail?: string;\n}\n\nexport interface McpConnectionTestResult {\n success: boolean;\n error: string | null;\n toolCount: number;\n toolNames: string[];\n steps: McpConnectionTestStep[];\n}\n\nexport async function testRemoteMcpConnection(\n db: ShadowClawDatabase,\n connectionId: string,\n): Promise<McpConnectionTestResult> {\n const steps: McpConnectionTestStep[] = [];\n\n // Step 1: Resolve auth\n let resolved;\n try {\n resolved = await resolveRemoteMcpConnectionAuth(db, connectionId);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n steps.push({\n step: \"Resolve authentication\",\n status: \"error\",\n detail: message,\n });\n\n return {\n success: false,\n error: message,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n\n if (!resolved) {\n steps.push({\n step: \"Resolve authentication\",\n status: \"error\",\n detail: \"Connection not found\",\n });\n\n return {\n success: false,\n error: \"Connection not found\",\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n\n if (resolved.reauthRequired) {\n const detail =\n \"OAuth token expired or revoked — re-authenticate in Settings\";\n steps.push({ step: \"Resolve authentication\", status: \"error\", detail });\n\n return {\n success: false,\n error: detail,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n\n steps.push({\n step: \"Resolve authentication\",\n status: \"ok\",\n detail: `Auth type: ${resolved.authType}`,\n });\n\n let { connection, authType, headers } = resolved;\n\n if (connection.transport !== \"streamable_http\") {\n const detail = `Unsupported transport: ${connection.transport}`;\n steps.push({ step: \"Establish MCP session\", status: \"error\", detail });\n\n return {\n success: false,\n error: detail,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n\n // Step 2: Establish session (clear any stale session first)\n clearRemoteMcpSession(connectionId);\n\n try {\n await ensureRemoteMcpSession(connectionId, connection.serverUrl, headers);\n steps.push({\n step: \"Establish MCP session\",\n status: \"ok\",\n detail: \"Session established\",\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n steps.push({\n step: \"Establish MCP session\",\n status: \"error\",\n detail: message,\n });\n\n // If 401 with OAuth, try force-refreshing the token and retrying.\n if (\n err instanceof HttpRemoteMcpError &&\n err.status === 401 &&\n authType === \"oauth\"\n ) {\n clearRemoteMcpSession(connectionId);\n\n const refreshed = await resolveRemoteMcpConnectionAuth(db, connectionId, {\n forceRefresh: true,\n });\n\n if (refreshed && !refreshed.reauthRequired) {\n steps.push({\n step: \"Refresh OAuth token\",\n status: \"ok\",\n detail: \"Token refreshed, retrying\",\n });\n\n connection = refreshed.connection;\n headers = refreshed.headers;\n\n try {\n await ensureRemoteMcpSession(\n connectionId,\n connection.serverUrl,\n headers,\n );\n steps.push({\n step: \"Establish MCP session\",\n status: \"ok\",\n detail: \"Session established\",\n });\n } catch (retryErr) {\n const retryMessage =\n retryErr instanceof Error ? retryErr.message : String(retryErr);\n const isStill401 =\n retryErr instanceof HttpRemoteMcpError && retryErr.status === 401;\n const detail = isStill401\n ? `${retryMessage} — re-authorize in Settings → Accounts`\n : retryMessage;\n steps.push({\n step: \"Establish MCP session\",\n status: \"error\",\n detail,\n });\n\n return {\n success: false,\n error: detail,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n } else {\n steps.push({\n step: \"Refresh OAuth token\",\n status: \"error\",\n detail: \"Token refresh failed — re-authenticate in Settings\",\n });\n\n return {\n success: false,\n error: message,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n } else {\n return {\n success: false,\n error: message,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n }\n\n // Step 3: Discover tools\n try {\n const result = await callRemoteMcpWithSession<ToolListResult>(\n connectionId,\n connection.serverUrl,\n headers,\n \"tools/list\",\n );\n\n const tools = Array.isArray(result.tools) ? result.tools : [];\n const toolNames = tools.map((t) => t.name);\n steps.push({\n step: \"Discover tools\",\n status: \"ok\",\n detail: `${tools.length} tool${tools.length === 1 ? \"\" : \"s\"} available`,\n });\n\n return {\n success: true,\n error: null,\n toolCount: tools.length,\n toolNames,\n steps,\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n steps.push({ step: \"Discover tools\", status: \"error\", detail: message });\n\n return {\n success: false,\n error: message,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n}\n","import {\n CONFIG_KEYS,\n OAUTH_PROVIDER_DEFINITIONS,\n} from \"../../config/config.js\";\nimport { decryptValue, encryptValue } from \"../../security/crypto.js\";\nimport { getConfig } from \"../../db/get-config.js\";\nimport { setConfig } from \"../../db/set-config.js\";\nimport { getRemoteMcpConnection } from \"./mcp-connections.js\";\nimport { clearRemoteMcpSession } from \"./remote-mcp-client.js\";\n\nimport type { ServiceAccount } from \"../accounts/service-accounts.js\";\nimport type { RemoteMcpCredentialRef } from \"./mcp-connections.js\";\nimport type { GitAccount } from \"../git/types.js\";\nimport type {\n OAuthAccountLike,\n ReconnectMcpOAuthOptions,\n ReconnectMcpOAuthResult,\n} from \"./types.js\";\nimport type { ShadowClawDatabase } from \"../../db/types.js\";\n\n/** Helper to build account update fields from OAuth token payload. */\nfunction buildOAuthUpdateFields(\n payload: {\n accessToken: string;\n refreshToken?: string;\n expiresIn?: number;\n tokenType?: string;\n scope?: string;\n },\n existingAccount: OAuthAccountLike,\n encryptedAccessToken: string,\n encryptedRefreshToken: string | undefined,\n) {\n return {\n accessTokenExpiresAt: payload.expiresIn\n ? Date.now() + payload.expiresIn * 1000\n : existingAccount.accessTokenExpiresAt,\n oauthReauthRequired: false,\n oauthReauthRequiredAt: undefined,\n oauthRefreshFailureCount: 0,\n refreshToken: encryptedRefreshToken,\n scopes: payload.scope\n ? payload.scope\n .split(/[\\s,]+/)\n .map((s) => s.trim())\n .filter(Boolean)\n : existingAccount.scopes,\n token: encryptedAccessToken,\n tokenType: payload.tokenType || existingAccount.tokenType,\n };\n}\n\n/**\n * Try a silent OAuth token refresh using the existing refresh token.\n * Returns `true` if the token was successfully refreshed and persisted.\n */\nasync function trySilentRefresh(\n db: ShadowClawDatabase,\n account: OAuthAccountLike,\n accountStore: \"service\" | \"git\",\n serviceAccounts: ServiceAccount[],\n gitAccounts: GitAccount[],\n ref: RemoteMcpCredentialRef,\n connectionId: string,\n): Promise<ReconnectMcpOAuthResult> {\n if (!account.refreshToken) {\n return { success: false, error: \"No refresh token available.\" };\n }\n\n const decryptedRefreshToken = await decryptValue(account.refreshToken);\n if (!decryptedRefreshToken) {\n return { success: false, error: \"Failed to decrypt refresh token.\" };\n }\n\n const clientSecret = account.oauthClientSecret\n ? await decryptValue(account.oauthClientSecret)\n : undefined;\n\n try {\n const response = await fetch(\"/oauth/refresh\", {\n body: JSON.stringify({\n clientId: account.oauthClientId,\n clientSecret: clientSecret || undefined,\n providerId: account.oauthProviderId,\n refreshToken: decryptedRefreshToken,\n scope: account.scopes,\n tokenUrl: account.oauthCustomTokenUrl,\n }),\n headers: { \"content-type\": \"application/json\" },\n method: \"POST\",\n });\n\n if (!response.ok) {\n return { success: false, error: \"Token refresh request failed.\" };\n }\n\n const payload = (await response.json()) as {\n accessToken?: string;\n expiresIn?: number;\n refreshToken?: string;\n scope?: string;\n tokenType?: string;\n };\n\n if (!payload.accessToken) {\n return { success: false, error: \"No access token in refresh response.\" };\n }\n\n const encryptedAccessToken = await encryptValue(payload.accessToken);\n if (!encryptedAccessToken) {\n return { success: false, error: \"Failed to encrypt access token.\" };\n }\n\n let encryptedRefreshToken = account.refreshToken;\n if (payload.refreshToken) {\n const maybeEncrypted = await encryptValue(payload.refreshToken);\n if (maybeEncrypted) {\n encryptedRefreshToken = maybeEncrypted;\n }\n }\n\n const updatedFields = buildOAuthUpdateFields(\n {\n accessToken: payload.accessToken,\n expiresIn: payload.expiresIn,\n refreshToken: payload.refreshToken,\n scope: payload.scope,\n tokenType: payload.tokenType,\n },\n account,\n encryptedAccessToken,\n encryptedRefreshToken,\n );\n\n if (accountStore === \"service\" && ref.accountId) {\n const idx = serviceAccounts.findIndex(\n (acct) => acct.id === ref.accountId,\n );\n\n if (idx !== -1) {\n Object.assign(serviceAccounts[idx], updatedFields);\n\n await setConfig(db, CONFIG_KEYS.SERVICE_ACCOUNTS, serviceAccounts);\n }\n } else if (accountStore === \"git\" && ref.gitAccountId) {\n const idx = gitAccounts.findIndex((acct) => acct.id === ref.gitAccountId);\n if (idx !== -1) {\n Object.assign(gitAccounts[idx], updatedFields);\n\n await setConfig(db, CONFIG_KEYS.GIT_ACCOUNTS, gitAccounts);\n }\n }\n\n clearRemoteMcpSession(connectionId);\n\n return { success: true };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n\n return { success: false, error: `Silent refresh failed: ${message}` };\n }\n}\n\n/**\n * Performs OAuth re-authentication for a remote MCP connection.\n *\n * When `silentOnly` is true, only attempts a token refresh using the\n * existing refresh token — no popup is opened. This is used for\n * automatic reconnection from the orchestrator (no user gesture).\n *\n * When `silentOnly` is false (default), first tries a silent refresh,\n * and if that fails, opens a popup for full re-authorization.\n */\nexport async function reconnectMcpOAuth(\n db: ShadowClawDatabase,\n connectionId: string,\n options: ReconnectMcpOAuthOptions = {},\n): Promise<ReconnectMcpOAuthResult> {\n const connection = await getRemoteMcpConnection(db, connectionId);\n if (!connection?.credentialRef) {\n return { success: false, error: \"Connection not found.\" };\n }\n\n const ref = connection.credentialRef;\n if (ref.authType !== \"oauth\") {\n return {\n success: false,\n error: \"This connection does not use OAuth authentication.\",\n };\n }\n\n // Load accounts from DB\n const serviceRaw = await getConfig(db, CONFIG_KEYS.SERVICE_ACCOUNTS);\n const serviceAccounts: ServiceAccount[] = Array.isArray(serviceRaw)\n ? serviceRaw\n : [];\n\n const gitRaw = await getConfig(db, CONFIG_KEYS.GIT_ACCOUNTS);\n const gitAccounts: GitAccount[] = Array.isArray(gitRaw) ? gitRaw : [];\n\n // Find the linked account\n let account: OAuthAccountLike | undefined;\n let accountStore: \"service\" | \"git\" | null = null;\n\n if (ref.accountId) {\n account = serviceAccounts.find((acct) => acct.id === ref.accountId) as\n OAuthAccountLike | undefined;\n\n accountStore = \"service\";\n } else if (ref.gitAccountId) {\n account = gitAccounts.find((acct) => acct.id === ref.gitAccountId) as\n OAuthAccountLike | undefined;\n\n accountStore = \"git\";\n }\n\n if (!account || !accountStore) {\n return {\n error:\n \"Linked account not found. Edit the connection to re-configure authentication.\",\n success: false,\n };\n }\n\n const clientId = account.oauthClientId;\n const providerId = account.oauthProviderId;\n\n if (!providerId || !clientId) {\n return {\n error:\n \"Account is missing OAuth provider or client ID. Edit the account in Settings → Accounts to fix.\",\n success: false,\n };\n }\n\n // ── Silent refresh attempt ───────────────────────────────────────\n // Always try a silent token refresh first. This works without a\n // popup and handles the common case where the refresh token is\n // still valid but the access token expired.\n if (account.refreshToken) {\n const silentResult = await trySilentRefresh(\n db,\n account,\n accountStore,\n serviceAccounts,\n gitAccounts,\n ref,\n connectionId,\n );\n\n if (silentResult.success) {\n return silentResult;\n }\n }\n\n // If silentOnly was requested, don't open a popup.\n if (options.silentOnly) {\n return {\n error:\n \"Silent token refresh failed. Use Settings → Remote MCP → Reconnect OAuth for full re-authorization.\",\n success: false,\n };\n }\n\n const clientSecret = account.oauthClientSecret\n ? await decryptValue(account.oauthClientSecret)\n : undefined;\n\n const scope = account.scopes;\n\n // Resolve OAuth URLs\n const providerDef = OAUTH_PROVIDER_DEFINITIONS[providerId];\n const isCustomMcp = providerId === \"custom_mcp\";\n const redirectUri =\n isCustomMcp && account.oauthCustomRedirectUri\n ? account.oauthCustomRedirectUri\n : providerDef?.redirectUri\n ? providerDef.redirectUri\n : `${globalThis.location?.origin || \"\"}/oauth/callback`;\n\n try {\n const authorizeRes = await fetch(\"/oauth/authorize\", {\n body: JSON.stringify({\n providerId,\n clientId,\n clientSecret: clientSecret || undefined,\n redirectUri,\n scope,\n ...(isCustomMcp && account.oauthCustomAuthorizeUrl\n ? { authorizeUrl: account.oauthCustomAuthorizeUrl }\n : {}),\n ...(isCustomMcp && account.oauthCustomTokenUrl\n ? { tokenUrl: account.oauthCustomTokenUrl }\n : {}),\n ...(isCustomMcp && typeof account.oauthCustomUsePkce === \"boolean\"\n ? { usePkce: account.oauthCustomUsePkce }\n : {}),\n }),\n headers: { \"content-type\": \"application/json\" },\n method: \"POST\",\n });\n\n const authorizePayload = (await authorizeRes.json()) as {\n authorizeUrl?: string;\n error?: string;\n state?: string;\n };\n\n if (\n !authorizeRes.ok ||\n !authorizePayload.state ||\n !authorizePayload.authorizeUrl\n ) {\n throw new Error(authorizePayload.error || \"OAuth authorize failed\");\n }\n\n const popup = window.open(\n authorizePayload.authorizeUrl,\n \"shadowclaw-oauth\",\n \"popup=yes,width=540,height=720\",\n );\n\n if (!popup || popup.closed || typeof popup.closed === \"undefined\") {\n throw new Error(\n \"OAuth popup was blocked by the browser. Please enable popups for this site and try again.\",\n );\n }\n\n const state = authorizePayload.state;\n let status = \"pending\";\n for (let attempt = 0; attempt < 60; attempt++) {\n const sessionRes = await fetch(\n `/oauth/session/${encodeURIComponent(state)}`,\n );\n\n const sessionPayload = (await sessionRes.json()) as {\n error?: string;\n status?: string;\n };\n\n if (!sessionRes.ok) {\n throw new Error(sessionPayload.error || \"OAuth session not found\");\n }\n\n status = sessionPayload.status || \"pending\";\n\n if (status === \"authorized\") {\n break;\n }\n\n if (status === \"error\") {\n throw new Error(sessionPayload.error || \"OAuth authorization failed\");\n }\n\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n\n if (status !== \"authorized\") {\n throw new Error(\"OAuth authorization timed out\");\n }\n\n const tokenRes = await fetch(\"/oauth/token\", {\n body: JSON.stringify({ state }),\n headers: { \"content-type\": \"application/json\" },\n method: \"POST\",\n });\n\n const tokenPayload = (await tokenRes.json()) as {\n accessToken?: string;\n error?: string;\n expiresIn?: number;\n refreshToken?: string;\n scope?: string;\n tokenType?: string;\n };\n\n if (!tokenRes.ok || !tokenPayload.accessToken) {\n throw new Error(tokenPayload.error || \"OAuth token exchange failed\");\n }\n\n // Update the linked account with new tokens\n const encryptedAccessToken = await encryptValue(tokenPayload.accessToken);\n if (!encryptedAccessToken) {\n throw new Error(\"Failed to encrypt access token\");\n }\n\n let encryptedRefreshToken = account.refreshToken;\n if (tokenPayload.refreshToken) {\n const maybeEncrypted = await encryptValue(tokenPayload.refreshToken);\n if (maybeEncrypted) {\n encryptedRefreshToken = maybeEncrypted;\n }\n }\n\n const updatedFields = buildOAuthUpdateFields(\n {\n accessToken: tokenPayload.accessToken,\n expiresIn: tokenPayload.expiresIn,\n refreshToken: tokenPayload.refreshToken,\n scope: tokenPayload.scope,\n tokenType: tokenPayload.tokenType,\n },\n account,\n encryptedAccessToken,\n encryptedRefreshToken,\n );\n\n // Persist to the correct account store\n if (accountStore === \"service\" && ref.accountId) {\n const idx = serviceAccounts.findIndex(\n (acct) => acct.id === ref.accountId,\n );\n if (idx !== -1) {\n Object.assign(serviceAccounts[idx], updatedFields);\n\n await setConfig(db, CONFIG_KEYS.SERVICE_ACCOUNTS, serviceAccounts);\n }\n } else if (accountStore === \"git\" && ref.gitAccountId) {\n const idx = gitAccounts.findIndex((acct) => acct.id === ref.gitAccountId);\n if (idx !== -1) {\n Object.assign(gitAccounts[idx], updatedFields);\n\n await setConfig(db, CONFIG_KEYS.GIT_ACCOUNTS, gitAccounts);\n }\n }\n\n // Clear the MCP session so the next call uses fresh credentials\n clearRemoteMcpSession(connectionId);\n\n return { success: true };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n\n return { success: false, error: message };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mcp-reconnect-BeqQvNWO.js","names":[],"sources":["../../src/subsystems/mcp/mcp-connections.ts","../../src/subsystems/accounts/service-accounts.ts","../../src/subsystems/mcp/mcp-connection-auth.ts","../../src/subsystems/mcp/remote-mcp-client.ts","../../src/subsystems/mcp/mcp-reconnect.ts"],"sourcesContent":["import { CONFIG_KEYS } from \"../../config/config.js\";\nimport { getConfig } from \"../../db/get-config.js\";\nimport { setConfig } from \"../../db/set-config.js\";\nimport { ulid } from \"../../utils/ulid.js\";\n\nimport type { ShadowClawDatabase } from \"../../db/types.js\";\nimport type { AuthType, ServiceType } from \"../../config/config.js\";\n\nexport type RemoteMcpTransport = \"streamable_http\" | \"sse\" | \"websocket\";\n\nexport interface RemoteMcpCredentialRef {\n serviceType: ServiceType;\n authType: AuthType;\n providerId?: string;\n accountId?: string;\n gitAccountId?: string;\n headerName?: string;\n encryptedValue?: string;\n}\n\nexport interface RemoteMcpConnectionRecord {\n id: string;\n label: string;\n serviceType: Extract<ServiceType, \"mcp_remote\" | \"webmcp_local\">;\n serverUrl: string;\n transport: RemoteMcpTransport;\n enabled: boolean;\n autoReconnectOAuth: boolean;\n createdAt: number;\n updatedAt: number;\n credentialRef: RemoteMcpCredentialRef | null;\n}\n\nexport interface UpsertRemoteMcpConnectionInput {\n id?: string;\n label: string;\n serviceType?: Extract<ServiceType, \"mcp_remote\" | \"webmcp_local\">;\n serverUrl: string;\n transport: RemoteMcpTransport;\n enabled?: boolean;\n autoReconnectOAuth?: boolean;\n}\n\nfunction isSafeAbsoluteUrl(value: unknown): value is string {\n if (typeof value !== \"string\" || !value.trim()) {\n return false;\n }\n\n try {\n const parsed = new URL(value);\n\n return parsed.protocol === \"https:\" || parsed.protocol === \"http:\";\n } catch {\n return false;\n }\n}\n\nfunction normalizeCredentialRef(\n value: unknown,\n connectionServiceType: RemoteMcpConnectionRecord[\"serviceType\"],\n): RemoteMcpCredentialRef | null {\n if (!value || typeof value !== \"object\") {\n return null;\n }\n\n const raw = value as RemoteMcpCredentialRef;\n if (!raw.serviceType || !raw.authType) {\n return null;\n }\n\n if (raw.serviceType !== connectionServiceType) {\n throw new Error(\n \"Credential ref serviceType must match connection serviceType\",\n );\n }\n\n return {\n serviceType: raw.serviceType,\n authType: raw.authType,\n providerId: raw.providerId || undefined,\n accountId: raw.accountId || undefined,\n gitAccountId: raw.gitAccountId || undefined,\n headerName: raw.headerName || undefined,\n encryptedValue: raw.encryptedValue || undefined,\n };\n}\n\nfunction normalizeConnection(value: unknown): RemoteMcpConnectionRecord | null {\n if (!value || typeof value !== \"object\") {\n return null;\n }\n\n const raw = value as Partial<RemoteMcpConnectionRecord>;\n if (\n !raw.id ||\n !raw.label ||\n !raw.serviceType ||\n !raw.transport ||\n typeof raw.enabled !== \"boolean\" ||\n typeof raw.createdAt !== \"number\" ||\n typeof raw.updatedAt !== \"number\" ||\n !isSafeAbsoluteUrl(raw.serverUrl)\n ) {\n return null;\n }\n\n if (raw.serviceType !== \"mcp_remote\" && raw.serviceType !== \"webmcp_local\") {\n return null;\n }\n\n if (\n raw.transport !== \"streamable_http\" &&\n raw.transport !== \"sse\" &&\n raw.transport !== \"websocket\"\n ) {\n return null;\n }\n\n return {\n id: raw.id,\n label: raw.label,\n serviceType: raw.serviceType,\n serverUrl: raw.serverUrl,\n transport: raw.transport,\n enabled: raw.enabled,\n autoReconnectOAuth: raw.autoReconnectOAuth === true,\n createdAt: raw.createdAt,\n updatedAt: raw.updatedAt,\n credentialRef: normalizeCredentialRef(raw.credentialRef, raw.serviceType),\n };\n}\n\nasync function loadConnections(\n db: ShadowClawDatabase,\n): Promise<RemoteMcpConnectionRecord[]> {\n const raw = await getConfig(db, CONFIG_KEYS.REMOTE_MCP_CONNECTIONS);\n if (!Array.isArray(raw)) {\n return [];\n }\n\n const normalized: RemoteMcpConnectionRecord[] = [];\n for (const item of raw) {\n const parsed = normalizeConnection(item);\n if (parsed) {\n normalized.push(parsed);\n }\n }\n\n return normalized;\n}\n\nasync function saveConnections(\n db: ShadowClawDatabase,\n connections: RemoteMcpConnectionRecord[],\n): Promise<void> {\n await setConfig(db, CONFIG_KEYS.REMOTE_MCP_CONNECTIONS, connections);\n}\n\nexport async function listRemoteMcpConnections(\n db: ShadowClawDatabase,\n): Promise<RemoteMcpConnectionRecord[]> {\n return loadConnections(db);\n}\n\nexport async function getRemoteMcpConnection(\n db: ShadowClawDatabase,\n id: string,\n): Promise<RemoteMcpConnectionRecord | null> {\n if (!id) {\n return null;\n }\n\n const all = await loadConnections(db);\n\n // Match by exact ID first, then fall back to case-insensitive label match\n // so agents can reference connections by human-readable name.\n\n return (\n all.find((connection) => connection.id === id) ||\n all.find(\n (connection) => connection.label.toLowerCase() === id.toLowerCase(),\n ) ||\n null\n );\n}\n\nexport async function upsertRemoteMcpConnection(\n db: ShadowClawDatabase,\n input: UpsertRemoteMcpConnectionInput,\n): Promise<RemoteMcpConnectionRecord> {\n if (!input?.label?.trim()) {\n throw new Error(\"Connection label is required\");\n }\n\n if (!isSafeAbsoluteUrl(input.serverUrl)) {\n throw new Error(\"Connection serverUrl must be an absolute http(s) URL\");\n }\n\n const serviceType = (input.serviceType ||\n \"mcp_remote\") as RemoteMcpConnectionRecord[\"serviceType\"];\n if (serviceType !== \"mcp_remote\" && serviceType !== \"webmcp_local\") {\n throw new Error(\"Unsupported serviceType for remote MCP connection\");\n }\n\n const all = await loadConnections(db);\n const now = Date.now();\n\n if (input.id) {\n const existingIndex = all.findIndex((record) => record.id === input.id);\n if (existingIndex !== -1) {\n const existing = all[existingIndex];\n const updated: RemoteMcpConnectionRecord = {\n ...existing,\n label: input.label.trim(),\n serviceType,\n serverUrl: input.serverUrl,\n transport: input.transport,\n enabled: input.enabled ?? existing.enabled,\n autoReconnectOAuth:\n input.autoReconnectOAuth ?? existing.autoReconnectOAuth,\n updatedAt: now,\n };\n all[existingIndex] = updated;\n await saveConnections(db, all);\n\n return updated;\n }\n }\n\n const created: RemoteMcpConnectionRecord = {\n id: input.id || ulid(),\n label: input.label.trim(),\n serviceType,\n serverUrl: input.serverUrl,\n transport: input.transport,\n enabled: input.enabled ?? true,\n autoReconnectOAuth: input.autoReconnectOAuth ?? false,\n createdAt: now,\n updatedAt: now,\n credentialRef: null,\n };\n\n all.push(created);\n await saveConnections(db, all);\n\n return created;\n}\n\nexport async function bindRemoteMcpCredentialRef(\n db: ShadowClawDatabase,\n connectionId: string,\n credentialRef: RemoteMcpCredentialRef | null,\n): Promise<RemoteMcpConnectionRecord | null> {\n if (!connectionId) {\n return null;\n }\n\n const all = await loadConnections(db);\n const idx = all.findIndex((record) => record.id === connectionId);\n if (idx === -1) {\n return null;\n }\n\n const current = all[idx];\n const normalizedRef = credentialRef\n ? normalizeCredentialRef(credentialRef, current.serviceType)\n : null;\n\n const updated: RemoteMcpConnectionRecord = {\n ...current,\n credentialRef: normalizedRef,\n updatedAt: Date.now(),\n };\n\n all[idx] = updated;\n await saveConnections(db, all);\n\n return updated;\n}\n\nexport async function deleteRemoteMcpConnection(\n db: ShadowClawDatabase,\n id: string,\n): Promise<boolean> {\n if (!id) {\n return false;\n }\n\n const all = await loadConnections(db);\n const next = all.filter((record) => record.id !== id);\n if (next.length === all.length) {\n return false;\n }\n\n await saveConnections(db, next);\n\n return true;\n}\n","import {\n CONFIG_KEYS,\n GENERAL_ACCOUNT_PROVIDER_CAPABILITIES,\n getGeneralAccountProviderCapabilities,\n} from \"../../config/config.js\";\nimport { getConfig } from \"../../db/get-config.js\";\nimport { setConfig } from \"../../db/set-config.js\";\nimport { decryptValue, encryptValue } from \"../../security/crypto.js\";\nimport {\n resolveStoredCredentialAuthMode,\n type StoredCredentialAuthMode,\n type StoredCredentialBase,\n type StoredCredentialOAuthFields,\n} from \"./stored-credentials.js\";\n\nimport type { ShadowClawDatabase } from \"../../db/types.js\";\nimport type { GeneralAccountProviderCapabilities } from \"../../config/config.js\";\n\nexport type AccountAuthMode = StoredCredentialAuthMode;\n\nexport interface ServiceAccount\n extends StoredCredentialBase, StoredCredentialOAuthFields {\n service: string;\n}\n\nexport interface ResolvedServiceCredentials {\n token: string;\n service: string;\n hostPattern: string;\n headerName: string; // e.g. \"Authorization\", \"X-Figma-Token\"\n headerValue: string; // e.g. \"Bearer TOKEN\", \"TOKEN\" (no prefix)\n accountId: string;\n authMode: AccountAuthMode;\n reauthRequired?: boolean;\n}\n\nexport interface ResolveServiceCredentialsOptions {\n accountId?: string;\n authMode?: AccountAuthMode;\n forceRefresh?: boolean;\n}\n\nconst OAUTH_REFRESH_WINDOW_MS = 60_000;\nconst OAUTH_REFRESH_FAILURE_THRESHOLD = 3;\n\nfunction resolveAccountAuthMode(account: ServiceAccount): AccountAuthMode {\n return resolveStoredCredentialAuthMode(account);\n}\n\nfunction shouldRefreshOAuthToken(\n account: ServiceAccount,\n options: ResolveServiceCredentialsOptions,\n): boolean {\n if (resolveAccountAuthMode(account) !== \"oauth\") {\n return false;\n }\n\n if (account.oauthReauthRequired) {\n return false;\n }\n\n if (\n !account.refreshToken ||\n !account.oauthProviderId ||\n !account.oauthClientId\n ) {\n return false;\n }\n\n if (options.forceRefresh) {\n return true;\n }\n\n if (!account.accessTokenExpiresAt) {\n return false;\n }\n\n return account.accessTokenExpiresAt <= Date.now() + OAUTH_REFRESH_WINDOW_MS;\n}\n\nasync function tryRefreshOAuthAccount(\n db: ShadowClawDatabase,\n accounts: ServiceAccount[],\n account: ServiceAccount,\n): Promise<ServiceAccount> {\n if (\n !account.refreshToken ||\n !account.oauthProviderId ||\n !account.oauthClientId\n ) {\n return account;\n }\n\n const decryptedRefreshToken = await decryptValue(account.refreshToken);\n if (!decryptedRefreshToken) {\n return account;\n }\n\n const oauthClientSecret = account.oauthClientSecret\n ? await decryptValue(account.oauthClientSecret)\n : undefined;\n\n const persistAccount = async (updatedAccount: ServiceAccount) => {\n const idx = accounts.findIndex((candidate) => candidate.id === account.id);\n if (idx !== -1) {\n accounts[idx] = updatedAccount;\n await setConfig(db, CONFIG_KEYS.SERVICE_ACCOUNTS, accounts);\n }\n };\n\n const markRefreshFailure = async (): Promise<ServiceAccount> => {\n const failureCount = (account.oauthRefreshFailureCount || 0) + 1;\n const reauthRequired = failureCount >= OAUTH_REFRESH_FAILURE_THRESHOLD;\n const updatedAccount: ServiceAccount = {\n ...account,\n oauthRefreshFailureCount: failureCount,\n oauthReauthRequired: reauthRequired,\n oauthReauthRequiredAt: reauthRequired\n ? account.oauthReauthRequiredAt || Date.now()\n : undefined,\n };\n await persistAccount(updatedAccount);\n\n return updatedAccount;\n };\n\n try {\n const response = await fetch(\"/oauth/refresh\", {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n providerId: account.oauthProviderId,\n clientId: account.oauthClientId,\n clientSecret: oauthClientSecret,\n refreshToken: decryptedRefreshToken,\n scope: account.scopes,\n tokenUrl: account.oauthCustomTokenUrl,\n }),\n });\n\n if (!response.ok) {\n return markRefreshFailure();\n }\n\n const payload = (await response.json()) as {\n accessToken?: string;\n refreshToken?: string;\n expiresIn?: number;\n tokenType?: string;\n scope?: string;\n };\n\n if (!payload.accessToken) {\n return markRefreshFailure();\n }\n\n const encryptedAccessToken = await encryptValue(payload.accessToken);\n if (!encryptedAccessToken) {\n return markRefreshFailure();\n }\n\n let encryptedRefreshToken = account.refreshToken;\n if (payload.refreshToken) {\n const maybeEncryptedRefreshToken = await encryptValue(\n payload.refreshToken,\n );\n if (maybeEncryptedRefreshToken) {\n encryptedRefreshToken = maybeEncryptedRefreshToken;\n }\n }\n\n const updatedAccount: ServiceAccount = {\n ...account,\n token: encryptedAccessToken,\n refreshToken: encryptedRefreshToken,\n accessTokenExpiresAt: payload.expiresIn\n ? Date.now() + payload.expiresIn * 1000\n : account.accessTokenExpiresAt,\n tokenType: payload.tokenType || account.tokenType,\n scopes: payload.scope\n ? payload.scope\n .split(/[\\s,]+/)\n .map((scope) => scope.trim())\n .filter(Boolean)\n : account.scopes,\n oauthRefreshFailureCount: 0,\n oauthReauthRequired: false,\n oauthReauthRequiredAt: undefined,\n };\n\n await persistAccount(updatedAccount);\n\n return updatedAccount;\n } catch {\n return markRefreshFailure();\n }\n}\n\nfunction resolveProviderCapabilities(\n account: ServiceAccount,\n url?: string,\n): GeneralAccountProviderCapabilities | null {\n if (account.oauthProviderId) {\n const direct = getGeneralAccountProviderCapabilities(\n account.oauthProviderId,\n );\n if (direct) {\n return direct;\n }\n }\n\n const hints = [account.service, account.hostPattern, url]\n .filter((value): value is string => !!value)\n .map((value) => value.toLowerCase());\n\n for (const provider of Object.values(GENERAL_ACCOUNT_PROVIDER_CAPABILITIES)) {\n const aliases = [provider.providerId, ...(provider.aliases || [])].map(\n (alias) => alias.toLowerCase(),\n );\n\n if (aliases.some((alias) => hints.some((hint) => hint.includes(alias)))) {\n return provider;\n }\n }\n\n return null;\n}\n\n/**\n * Resolve auth header format from provider capabilities. Falls back to Bearer.\n */\nfunction getServiceAuthFormat(\n account: ServiceAccount,\n url?: string,\n): {\n headerName: string;\n headerPrefix: string;\n} {\n const authMode = resolveAccountAuthMode(account);\n const provider = resolveProviderCapabilities(account, url);\n if (provider) {\n let scheme;\n if (authMode === \"oauth\") {\n scheme = provider.tokenAuth.oauth;\n } else if (authMode === \"basic\" && provider.tokenAuth.basic) {\n scheme = provider.tokenAuth.basic;\n } else {\n scheme = provider.tokenAuth.token;\n }\n\n return {\n headerName: scheme.headerName,\n headerPrefix: scheme.headerPrefix || \"\",\n };\n }\n\n return {\n headerName: \"Authorization\",\n headerPrefix: authMode === \"basic\" ? \"Basic \" : \"Bearer \",\n };\n}\n\n/**\n * Find the most-specific (longest hostPattern) account that matches a URL.\n */\nfunction matchAccountsByHost(\n accounts: ServiceAccount[],\n url: string,\n): ServiceAccount[] {\n const matches: ServiceAccount[] = [];\n let bestLen = -1;\n const lower = url.toLowerCase();\n\n for (const acct of accounts) {\n if (!acct.hostPattern) {\n continue;\n }\n\n const pattern = acct.hostPattern.toLowerCase();\n if (lower.includes(pattern)) {\n if (pattern.length > bestLen) {\n bestLen = pattern.length;\n matches.length = 0;\n matches.push(acct);\n } else if (pattern.length === bestLen) {\n matches.push(acct);\n }\n }\n }\n\n return matches;\n}\n\nfunction pickAccountByAuthMode(\n accounts: ServiceAccount[],\n authMode?: AccountAuthMode,\n): ServiceAccount | undefined {\n if (!accounts.length) {\n return undefined;\n }\n\n if (!authMode) {\n return accounts[0];\n }\n\n const modeMatch = accounts.find(\n (acct) => resolveAccountAuthMode(acct) === authMode,\n );\n if (modeMatch) {\n return modeMatch;\n }\n\n return accounts[0];\n}\n\n/**\n * Resolve a decrypted service account PAT for the given URL.\n *\n * Resolution order:\n * 1. Longest hostPattern match against the URL\n * 2. SERVICE_DEFAULT_ACCOUNT\n * 3. First account in the list\n *\n * Returns undefined when no accounts are configured.\n */\nexport async function resolveServiceCredentials(\n db: ShadowClawDatabase,\n url?: string,\n options: ResolveServiceCredentialsOptions = {},\n): Promise<ResolvedServiceCredentials | undefined> {\n const raw = await getConfig(db, CONFIG_KEYS.SERVICE_ACCOUNTS);\n const accounts: ServiceAccount[] = Array.isArray(raw) ? raw : [];\n\n if (accounts.length === 0) {\n return undefined;\n }\n\n let account: ServiceAccount | undefined;\n\n if (options.accountId) {\n account = accounts.find((a) => a.id === options.accountId);\n }\n\n // 1. Match by URL host pattern\n if (!account && url) {\n const hostMatches = matchAccountsByHost(accounts, url);\n if (options.authMode) {\n account = pickAccountByAuthMode(hostMatches, options.authMode);\n } else {\n const preferredMode = hostMatches[0]\n ? resolveProviderCapabilities(hostMatches[0], url)?.defaultMode\n : undefined;\n account = pickAccountByAuthMode(hostMatches, preferredMode);\n }\n }\n\n // 2. Fall back to stored default\n if (!account) {\n const defaultId = await getConfig(db, CONFIG_KEYS.SERVICE_DEFAULT_ACCOUNT);\n if (defaultId) {\n account = accounts.find((a) => a.id === defaultId);\n }\n }\n\n // 3. Fall back to first account matching requested mode\n if (!account && options.authMode) {\n account = pickAccountByAuthMode(accounts, options.authMode);\n }\n\n // 4. Fall back to first\n if (!account) {\n account = accounts[0];\n }\n\n if (!account) {\n return undefined;\n }\n\n if (shouldRefreshOAuthToken(account, options)) {\n account = await tryRefreshOAuthAccount(db, accounts, account);\n }\n\n if (\n resolveAccountAuthMode(account) === \"oauth\" &&\n account.oauthReauthRequired\n ) {\n return {\n token: \"\",\n service: account.service,\n hostPattern: account.hostPattern,\n headerName: \"Authorization\",\n headerValue: \"\",\n accountId: account.id,\n authMode: \"oauth\",\n reauthRequired: true,\n };\n }\n\n let token = \"\";\n if (account.token) {\n token = (await decryptValue(account.token)) ?? \"\";\n }\n\n const { headerName, headerPrefix } = getServiceAuthFormat(account, url);\n let finalToken = token;\n\n if (resolveAccountAuthMode(account) === \"basic\" && account.basicUsername) {\n finalToken = btoa(`${account.basicUsername}:${token}`);\n }\n\n const headerValue = headerPrefix\n ? `${headerPrefix}${finalToken}`\n : finalToken;\n\n return {\n token,\n service: account.service,\n hostPattern: account.hostPattern,\n headerName,\n headerValue,\n accountId: account.id,\n authMode: resolveAccountAuthMode(account),\n };\n}\n","import { decryptValue } from \"../../security/crypto.js\";\nimport { getRemoteMcpConnection } from \"./mcp-connections.js\";\nimport { resolveServiceCredentials } from \"../accounts/service-accounts.js\";\nimport { buildAuthHeaders, resolveGitCredentials } from \"../git/credentials.js\";\n\nimport type { ShadowClawDatabase } from \"../../db/types.js\";\nimport type { RemoteMcpConnectionRecord } from \"./mcp-connections.js\";\nimport type { AuthType } from \"../../config/config.js\";\n\nexport interface ResolvedRemoteMcpAuth {\n connection: RemoteMcpConnectionRecord;\n authType: AuthType;\n headers: Record<string, string>;\n reauthRequired?: boolean;\n}\n\nexport interface ResolveRemoteMcpAuthOptions {\n forceRefresh?: boolean;\n}\n\nfunction toAccountAuthMode(authType: AuthType): \"token\" | \"oauth\" | \"basic\" {\n return authType === \"oauth\" ? \"oauth\" : \"token\";\n}\n\nexport async function resolveRemoteMcpConnectionAuth(\n db: ShadowClawDatabase,\n connectionId: string,\n options: ResolveRemoteMcpAuthOptions = {},\n): Promise<ResolvedRemoteMcpAuth | null> {\n const connection = await getRemoteMcpConnection(db, connectionId);\n if (!connection) {\n return null;\n }\n\n const ref = connection.credentialRef;\n if (!ref || ref.authType === \"none\") {\n return {\n connection,\n authType: \"none\",\n headers: {},\n };\n }\n\n if (ref.authType === \"custom_header\") {\n if (!ref.headerName || !ref.encryptedValue) {\n return {\n connection,\n authType: \"custom_header\",\n headers: {},\n };\n }\n\n const decrypted = await decryptValue(ref.encryptedValue);\n\n return {\n connection,\n authType: \"custom_header\",\n headers: decrypted ? { [ref.headerName]: decrypted } : {},\n };\n }\n\n const authMode = toAccountAuthMode(ref.authType);\n\n if (ref.accountId) {\n const creds = await resolveServiceCredentials(db, connection.serverUrl, {\n accountId: ref.accountId,\n authMode,\n forceRefresh: options.forceRefresh,\n });\n\n if (!creds) {\n return {\n connection,\n authType: ref.authType,\n headers: {},\n };\n }\n\n if (creds.reauthRequired) {\n return {\n connection,\n authType: ref.authType,\n headers: {},\n reauthRequired: true,\n };\n }\n\n return {\n connection,\n authType: ref.authType,\n headers: creds.headerValue\n ? { [creds.headerName]: creds.headerValue }\n : {},\n };\n }\n\n if (ref.gitAccountId) {\n const creds = await resolveGitCredentials(db, connection.serverUrl, {\n accountId: ref.gitAccountId,\n authMode,\n forceRefresh: options.forceRefresh,\n });\n\n if (creds.reauthRequired) {\n return {\n connection,\n authType: ref.authType,\n headers: {},\n reauthRequired: true,\n };\n }\n\n return {\n connection,\n authType: ref.authType,\n headers: buildAuthHeaders(creds),\n };\n }\n\n return {\n connection,\n authType: ref.authType,\n headers: {},\n };\n}\n","import { resolveRemoteMcpConnectionAuth } from \"./mcp-connection-auth.js\";\n\nimport type { ShadowClawDatabase } from \"../../db/types.js\";\n\ninterface RemoteMcpSession {\n sessionId: string;\n protocolVersion?: string;\n lastUsedAt: number;\n}\n\nconst remoteMcpSessions: Map<string, RemoteMcpSession> = new Map();\n\ninterface JsonRpcSuccess<T> {\n jsonrpc: \"2.0\";\n id: string;\n result: T;\n}\n\ninterface JsonRpcError {\n jsonrpc: \"2.0\";\n id: string;\n error: {\n code: number;\n message: string;\n data?: unknown;\n };\n}\n\ntype JsonRpcResponse<T> = JsonRpcSuccess<T> | JsonRpcError;\n\ninterface JsonRpcServerRequest {\n jsonrpc: \"2.0\";\n id: string | number;\n method: string;\n params?: Record<string, unknown>;\n}\n\nfunction isServerRequest(msg: unknown): msg is JsonRpcServerRequest {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"method\" in msg &&\n \"id\" in msg &&\n !(\"result\" in msg) &&\n !(\"error\" in msg)\n );\n}\n\nfunction buildElicitationDefaults(\n params: Record<string, unknown>,\n): Record<string, unknown> {\n const schema = (params.requestedSchema || {}) as Record<string, unknown>;\n const properties = (schema.properties || {}) as Record<\n string,\n Record<string, unknown>\n >;\n const defaults: Record<string, unknown> = {};\n\n for (const [key, prop] of Object.entries(properties)) {\n if (\"default\" in prop) {\n defaults[key] = prop.default;\n } else if (prop.type === \"boolean\") {\n defaults[key] = true;\n }\n }\n\n return defaults;\n}\n\ninterface ToolListResult {\n tools?: Array<{ name: string; description?: string }>;\n}\n\ninterface ToolCallResult {\n content?: unknown[];\n isError?: boolean;\n}\n\ninterface JsonRpcInitializeResult {\n protocolVersion?: string;\n}\n\nclass InvalidRemoteMcpSessionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"InvalidRemoteMcpSessionError\";\n }\n}\n\nclass HttpRemoteMcpError extends Error {\n status: number;\n constructor(status: number, message: string) {\n super(message);\n this.name = \"HttpRemoteMcpError\";\n this.status = status;\n }\n}\n\nexport class McpReauthRequiredError extends Error {\n connectionId: string;\n constructor(connectionId: string) {\n super(\"OAuth reconnect required for remote MCP connection\");\n this.name = \"McpReauthRequiredError\";\n this.connectionId = connectionId;\n }\n}\n\ninterface HttpLikeResponse {\n ok: boolean;\n status: number;\n json: () => Promise<unknown>;\n text?: () => Promise<string>;\n headers?: {\n get?: (name: string) => string | null;\n };\n}\n\nfunction getHeader(response: HttpLikeResponse, name: string): string | null {\n if (!response.headers || typeof response.headers.get !== \"function\") {\n return null;\n }\n\n return response.headers.get(name);\n}\n\nfunction isInvalidSessionMessage(message: string): boolean {\n return /no valid session id provided/i.test(message);\n}\n\nfunction toError(\n response: HttpLikeResponse,\n payload: JsonRpcResponse<unknown> | null,\n): Error {\n const jsonRpcMessage =\n payload && \"error\" in payload\n ? payload.error.message || \"Remote MCP JSON-RPC error\"\n : \"\";\n\n if (isInvalidSessionMessage(jsonRpcMessage)) {\n return new InvalidRemoteMcpSessionError(jsonRpcMessage);\n }\n\n if (!response.ok) {\n return new HttpRemoteMcpError(\n response.status,\n jsonRpcMessage\n ? `Remote MCP HTTP error: ${response.status} (${jsonRpcMessage})`\n : `Remote MCP HTTP error: ${response.status}`,\n );\n }\n\n return new Error(jsonRpcMessage || \"Remote MCP JSON-RPC error\");\n}\n\nfunction parseJsonRpcFromSseText<T>(raw: string): JsonRpcResponse<T> | null {\n if (!raw) {\n return null;\n }\n\n let lastJsonRpc: JsonRpcResponse<T> | null = null;\n const lines = raw.split(/\\r?\\n/);\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"data:\")) {\n continue;\n }\n\n const data = trimmed.slice(5).trim();\n if (!data || data === \"[DONE]\") {\n continue;\n }\n\n try {\n const parsed = JSON.parse(data) as JsonRpcResponse<T>;\n if (parsed && typeof parsed === \"object\" && \"jsonrpc\" in parsed) {\n lastJsonRpc = parsed;\n }\n } catch {\n // Ignore malformed SSE data chunks and keep scanning.\n }\n }\n\n return lastJsonRpc;\n}\n\nfunction parseJsonRpcFromText<T>(raw: string): JsonRpcResponse<T> | null {\n if (!raw) {\n return null;\n }\n\n try {\n return JSON.parse(raw) as JsonRpcResponse<T>;\n } catch {\n return null;\n }\n}\n\nasync function postJsonRpc<T>(\n url: string,\n headers: Record<string, string>,\n body: Record<string, unknown>,\n): Promise<{\n response: HttpLikeResponse;\n payload: JsonRpcResponse<T> | null;\n}> {\n const response = (await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n accept: \"application/json, text/event-stream\",\n ...headers,\n },\n body: JSON.stringify(body),\n })) as HttpLikeResponse;\n\n const contentType = (getHeader(response, \"content-type\") || \"\").toLowerCase();\n let payload: JsonRpcResponse<T> | null = null;\n\n if (typeof response.text === \"function\") {\n const raw = await response.text();\n payload = contentType.includes(\"text/event-stream\")\n ? parseJsonRpcFromSseText<T>(raw)\n : parseJsonRpcFromText<T>(raw);\n } else {\n try {\n payload = (await response.json()) as JsonRpcResponse<T>;\n } catch {\n payload = null;\n }\n }\n\n return { response, payload };\n}\n\nasync function sendInitializedNotification(\n serverUrl: string,\n headers: Record<string, string>,\n sessionId: string,\n): Promise<void> {\n const { response, payload } = await postJsonRpc<unknown>(\n serverUrl,\n {\n ...headers,\n \"mcp-session-id\": sessionId,\n },\n {\n jsonrpc: \"2.0\",\n method: \"notifications/initialized\",\n params: {},\n },\n );\n\n if (!response.ok || (payload && \"error\" in payload)) {\n throw toError(response, payload);\n }\n}\n\nasync function ensureRemoteMcpSession(\n connectionId: string,\n serverUrl: string,\n headers: Record<string, string>,\n): Promise<RemoteMcpSession> {\n const existing = remoteMcpSessions.get(connectionId);\n if (existing?.sessionId) {\n return existing;\n }\n\n const { response, payload } = await postJsonRpc<JsonRpcInitializeResult>(\n serverUrl,\n headers,\n {\n jsonrpc: \"2.0\",\n id: `initialize-${Date.now().toString(36)}`,\n method: \"initialize\",\n params: {\n protocolVersion: \"2025-03-26\",\n capabilities: {\n elicitation: {},\n },\n clientInfo: {\n name: \"shadowclaw-remote-mcp-client\",\n version: \"1.0.0\",\n },\n },\n },\n );\n\n if (!response.ok) {\n throw toError(response, payload);\n }\n\n if (payload && \"error\" in payload) {\n throw toError(response, payload);\n }\n\n const sessionId =\n getHeader(response, \"mcp-session-id\") ||\n `local-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\n const session: RemoteMcpSession = {\n sessionId,\n protocolVersion:\n getHeader(response, \"mcp-protocol-version\") ||\n (payload as { result?: { protocolVersion?: string } } | null)?.result\n ?.protocolVersion,\n lastUsedAt: Date.now(),\n };\n\n await sendInitializedNotification(serverUrl, headers, sessionId);\n remoteMcpSessions.set(connectionId, session);\n\n return session;\n}\n\nasync function callRemoteMcpWithSession<T>(\n connectionId: string,\n serverUrl: string,\n headers: Record<string, string>,\n method: string,\n params?: Record<string, unknown>,\n): Promise<T> {\n let session = await ensureRemoteMcpSession(connectionId, serverUrl, headers);\n\n const doRequest = async (activeSessionId: string) => {\n const body = {\n jsonrpc: \"2.0\",\n id: Date.now().toString(),\n method,\n params: params || {},\n };\n\n const sessionHeaders = {\n ...headers,\n \"mcp-session-id\": activeSessionId,\n };\n\n let { response, payload } = await postJsonRpc<T>(\n serverUrl,\n sessionHeaders,\n body,\n );\n\n // Handle server-initiated requests (e.g., elicitation/create).\n // The gateway may ask the client to confirm before completing a tool call.\n let elicitationAttempts = 0;\n while (isServerRequest(payload) && elicitationAttempts < 5) {\n elicitationAttempts++;\n\n if (payload.method === \"elicitation/create\") {\n const elicitationParams = (payload.params || {}) as Record<\n string,\n unknown\n >;\n const defaults = buildElicitationDefaults(elicitationParams);\n\n ({ response, payload } = await postJsonRpc<T>(\n serverUrl,\n sessionHeaders,\n {\n jsonrpc: \"2.0\",\n id: payload.id,\n result: {\n action: \"accept\",\n content: defaults,\n },\n },\n ));\n } else {\n break;\n }\n }\n\n if (isServerRequest(payload)) {\n throw new Error(\n `Unsupported server request: ${(payload as JsonRpcServerRequest).method}`,\n );\n }\n\n if (!response.ok || !payload || \"error\" in payload) {\n throw toError(response, payload);\n }\n\n return payload.result;\n };\n\n try {\n const result = await doRequest(session.sessionId);\n session.lastUsedAt = Date.now();\n remoteMcpSessions.set(connectionId, session);\n\n return result;\n } catch (err) {\n if (!(err instanceof InvalidRemoteMcpSessionError)) {\n throw err;\n }\n\n // Session expired or unknown on server side; refresh once and retry.\n remoteMcpSessions.delete(connectionId);\n session = await ensureRemoteMcpSession(connectionId, serverUrl, headers);\n const result = await doRequest(session.sessionId);\n session.lastUsedAt = Date.now();\n remoteMcpSessions.set(connectionId, session);\n\n return result;\n }\n}\n\nexport function clearRemoteMcpSession(connectionId: string): void {\n if (!connectionId) {\n return;\n }\n\n remoteMcpSessions.delete(connectionId);\n}\n\nexport function clearAllRemoteMcpSessions(): void {\n remoteMcpSessions.clear();\n}\n\nasync function callRemoteMcp<T>(\n db: ShadowClawDatabase,\n connectionId: string,\n method: string,\n params?: Record<string, unknown>,\n): Promise<T> {\n const resolved = await resolveRemoteMcpConnectionAuth(db, connectionId);\n if (!resolved) {\n throw new Error(\"Remote MCP connection not found\");\n }\n\n if (resolved.reauthRequired) {\n throw new McpReauthRequiredError(connectionId);\n }\n\n const { connection, authType, headers } = resolved;\n\n if (connection.transport !== \"streamable_http\") {\n throw new Error(\"Unsupported remote MCP transport\");\n }\n\n try {\n return await callRemoteMcpWithSession<T>(\n connectionId,\n connection.serverUrl,\n headers,\n method,\n params,\n );\n } catch (err) {\n if (\n !(err instanceof HttpRemoteMcpError) ||\n err.status !== 401 ||\n authType !== \"oauth\"\n ) {\n throw err;\n }\n\n // 401 with OAuth — force-refresh token and retry once.\n clearRemoteMcpSession(connectionId);\n\n const refreshed = await resolveRemoteMcpConnectionAuth(db, connectionId, {\n forceRefresh: true,\n });\n\n if (!refreshed || refreshed.reauthRequired) {\n throw new McpReauthRequiredError(connectionId);\n }\n\n try {\n return await callRemoteMcpWithSession<T>(\n connectionId,\n refreshed.connection.serverUrl,\n refreshed.headers,\n method,\n params,\n );\n } catch (retryErr) {\n if (retryErr instanceof HttpRemoteMcpError && retryErr.status === 401) {\n throw new McpReauthRequiredError(connectionId);\n }\n\n throw retryErr;\n }\n }\n}\n\nexport async function listRemoteMcpTools(\n db: ShadowClawDatabase,\n connectionId: string,\n): Promise<Array<{ name: string; description?: string }>> {\n const result = await callRemoteMcp<ToolListResult>(\n db,\n connectionId,\n \"tools/list\",\n );\n\n return Array.isArray(result.tools) ? result.tools : [];\n}\n\nexport async function callRemoteMcpTool(\n db: ShadowClawDatabase,\n connectionId: string,\n name: string,\n argumentsInput: Record<string, unknown> = {},\n): Promise<ToolCallResult> {\n return callRemoteMcp<ToolCallResult>(db, connectionId, \"tools/call\", {\n name,\n arguments: argumentsInput,\n });\n}\n\nexport interface McpConnectionTestStep {\n step: string;\n status: \"ok\" | \"error\" | \"skipped\";\n detail?: string;\n}\n\nexport interface McpConnectionTestResult {\n success: boolean;\n error: string | null;\n toolCount: number;\n toolNames: string[];\n steps: McpConnectionTestStep[];\n}\n\nexport async function testRemoteMcpConnection(\n db: ShadowClawDatabase,\n connectionId: string,\n): Promise<McpConnectionTestResult> {\n const steps: McpConnectionTestStep[] = [];\n\n // Step 1: Resolve auth\n let resolved;\n try {\n resolved = await resolveRemoteMcpConnectionAuth(db, connectionId);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n steps.push({\n step: \"Resolve authentication\",\n status: \"error\",\n detail: message,\n });\n\n return {\n success: false,\n error: message,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n\n if (!resolved) {\n steps.push({\n step: \"Resolve authentication\",\n status: \"error\",\n detail: \"Connection not found\",\n });\n\n return {\n success: false,\n error: \"Connection not found\",\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n\n if (resolved.reauthRequired) {\n const detail =\n \"OAuth token expired or revoked — re-authenticate in Settings\";\n steps.push({ step: \"Resolve authentication\", status: \"error\", detail });\n\n return {\n success: false,\n error: detail,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n\n steps.push({\n step: \"Resolve authentication\",\n status: \"ok\",\n detail: `Auth type: ${resolved.authType}`,\n });\n\n let { connection, authType, headers } = resolved;\n\n if (connection.transport !== \"streamable_http\") {\n const detail = `Unsupported transport: ${connection.transport}`;\n steps.push({ step: \"Establish MCP session\", status: \"error\", detail });\n\n return {\n success: false,\n error: detail,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n\n // Step 2: Establish session (clear any stale session first)\n clearRemoteMcpSession(connectionId);\n\n try {\n await ensureRemoteMcpSession(connectionId, connection.serverUrl, headers);\n steps.push({\n step: \"Establish MCP session\",\n status: \"ok\",\n detail: \"Session established\",\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n steps.push({\n step: \"Establish MCP session\",\n status: \"error\",\n detail: message,\n });\n\n // If 401 with OAuth, try force-refreshing the token and retrying.\n if (\n err instanceof HttpRemoteMcpError &&\n err.status === 401 &&\n authType === \"oauth\"\n ) {\n clearRemoteMcpSession(connectionId);\n\n const refreshed = await resolveRemoteMcpConnectionAuth(db, connectionId, {\n forceRefresh: true,\n });\n\n if (refreshed && !refreshed.reauthRequired) {\n steps.push({\n step: \"Refresh OAuth token\",\n status: \"ok\",\n detail: \"Token refreshed, retrying\",\n });\n\n connection = refreshed.connection;\n headers = refreshed.headers;\n\n try {\n await ensureRemoteMcpSession(\n connectionId,\n connection.serverUrl,\n headers,\n );\n steps.push({\n step: \"Establish MCP session\",\n status: \"ok\",\n detail: \"Session established\",\n });\n } catch (retryErr) {\n const retryMessage =\n retryErr instanceof Error ? retryErr.message : String(retryErr);\n const isStill401 =\n retryErr instanceof HttpRemoteMcpError && retryErr.status === 401;\n const detail = isStill401\n ? `${retryMessage} — re-authorize in Settings → Accounts`\n : retryMessage;\n steps.push({\n step: \"Establish MCP session\",\n status: \"error\",\n detail,\n });\n\n return {\n success: false,\n error: detail,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n } else {\n steps.push({\n step: \"Refresh OAuth token\",\n status: \"error\",\n detail: \"Token refresh failed — re-authenticate in Settings\",\n });\n\n return {\n success: false,\n error: message,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n } else {\n return {\n success: false,\n error: message,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n }\n\n // Step 3: Discover tools\n try {\n const result = await callRemoteMcpWithSession<ToolListResult>(\n connectionId,\n connection.serverUrl,\n headers,\n \"tools/list\",\n );\n\n const tools = Array.isArray(result.tools) ? result.tools : [];\n const toolNames = tools.map((t) => t.name);\n steps.push({\n step: \"Discover tools\",\n status: \"ok\",\n detail: `${tools.length} tool${tools.length === 1 ? \"\" : \"s\"} available`,\n });\n\n return {\n success: true,\n error: null,\n toolCount: tools.length,\n toolNames,\n steps,\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n steps.push({ step: \"Discover tools\", status: \"error\", detail: message });\n\n return {\n success: false,\n error: message,\n toolCount: 0,\n toolNames: [],\n steps,\n };\n }\n}\n","import {\n CONFIG_KEYS,\n OAUTH_PROVIDER_DEFINITIONS,\n} from \"../../config/config.js\";\nimport { decryptValue, encryptValue } from \"../../security/crypto.js\";\nimport { getConfig } from \"../../db/get-config.js\";\nimport { setConfig } from \"../../db/set-config.js\";\nimport { getRemoteMcpConnection } from \"./mcp-connections.js\";\nimport { clearRemoteMcpSession } from \"./remote-mcp-client.js\";\n\nimport type { ServiceAccount } from \"../accounts/service-accounts.js\";\nimport type { RemoteMcpCredentialRef } from \"./mcp-connections.js\";\nimport type { GitAccount } from \"../git/types.js\";\nimport type {\n OAuthAccountLike,\n ReconnectMcpOAuthOptions,\n ReconnectMcpOAuthResult,\n} from \"./types.js\";\nimport type { ShadowClawDatabase } from \"../../db/types.js\";\n\n/** Helper to build account update fields from OAuth token payload. */\nfunction buildOAuthUpdateFields(\n payload: {\n accessToken: string;\n refreshToken?: string;\n expiresIn?: number;\n tokenType?: string;\n scope?: string;\n },\n existingAccount: OAuthAccountLike,\n encryptedAccessToken: string,\n encryptedRefreshToken: string | undefined,\n) {\n return {\n accessTokenExpiresAt: payload.expiresIn\n ? Date.now() + payload.expiresIn * 1000\n : existingAccount.accessTokenExpiresAt,\n oauthReauthRequired: false,\n oauthReauthRequiredAt: undefined,\n oauthRefreshFailureCount: 0,\n refreshToken: encryptedRefreshToken,\n scopes: payload.scope\n ? payload.scope\n .split(/[\\s,]+/)\n .map((s) => s.trim())\n .filter(Boolean)\n : existingAccount.scopes,\n token: encryptedAccessToken,\n tokenType: payload.tokenType || existingAccount.tokenType,\n };\n}\n\n/**\n * Try a silent OAuth token refresh using the existing refresh token.\n * Returns `true` if the token was successfully refreshed and persisted.\n */\nasync function trySilentRefresh(\n db: ShadowClawDatabase,\n account: OAuthAccountLike,\n accountStore: \"service\" | \"git\",\n serviceAccounts: ServiceAccount[],\n gitAccounts: GitAccount[],\n ref: RemoteMcpCredentialRef,\n connectionId: string,\n): Promise<ReconnectMcpOAuthResult> {\n if (!account.refreshToken) {\n return { success: false, error: \"No refresh token available.\" };\n }\n\n const decryptedRefreshToken = await decryptValue(account.refreshToken);\n if (!decryptedRefreshToken) {\n return { success: false, error: \"Failed to decrypt refresh token.\" };\n }\n\n const clientSecret = account.oauthClientSecret\n ? await decryptValue(account.oauthClientSecret)\n : undefined;\n\n try {\n const response = await fetch(\"/oauth/refresh\", {\n body: JSON.stringify({\n clientId: account.oauthClientId,\n clientSecret: clientSecret || undefined,\n providerId: account.oauthProviderId,\n refreshToken: decryptedRefreshToken,\n scope: account.scopes,\n tokenUrl: account.oauthCustomTokenUrl,\n }),\n headers: { \"content-type\": \"application/json\" },\n method: \"POST\",\n });\n\n if (!response.ok) {\n return { success: false, error: \"Token refresh request failed.\" };\n }\n\n const payload = (await response.json()) as {\n accessToken?: string;\n expiresIn?: number;\n refreshToken?: string;\n scope?: string;\n tokenType?: string;\n };\n\n if (!payload.accessToken) {\n return { success: false, error: \"No access token in refresh response.\" };\n }\n\n const encryptedAccessToken = await encryptValue(payload.accessToken);\n if (!encryptedAccessToken) {\n return { success: false, error: \"Failed to encrypt access token.\" };\n }\n\n let encryptedRefreshToken = account.refreshToken;\n if (payload.refreshToken) {\n const maybeEncrypted = await encryptValue(payload.refreshToken);\n if (maybeEncrypted) {\n encryptedRefreshToken = maybeEncrypted;\n }\n }\n\n const updatedFields = buildOAuthUpdateFields(\n {\n accessToken: payload.accessToken,\n expiresIn: payload.expiresIn,\n refreshToken: payload.refreshToken,\n scope: payload.scope,\n tokenType: payload.tokenType,\n },\n account,\n encryptedAccessToken,\n encryptedRefreshToken,\n );\n\n if (accountStore === \"service\" && ref.accountId) {\n const idx = serviceAccounts.findIndex(\n (acct) => acct.id === ref.accountId,\n );\n\n if (idx !== -1) {\n Object.assign(serviceAccounts[idx], updatedFields);\n\n await setConfig(db, CONFIG_KEYS.SERVICE_ACCOUNTS, serviceAccounts);\n }\n } else if (accountStore === \"git\" && ref.gitAccountId) {\n const idx = gitAccounts.findIndex((acct) => acct.id === ref.gitAccountId);\n if (idx !== -1) {\n Object.assign(gitAccounts[idx], updatedFields);\n\n await setConfig(db, CONFIG_KEYS.GIT_ACCOUNTS, gitAccounts);\n }\n }\n\n clearRemoteMcpSession(connectionId);\n\n return { success: true };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n\n return { success: false, error: `Silent refresh failed: ${message}` };\n }\n}\n\n/**\n * Performs OAuth re-authentication for a remote MCP connection.\n *\n * When `silentOnly` is true, only attempts a token refresh using the\n * existing refresh token — no popup is opened. This is used for\n * automatic reconnection from the orchestrator (no user gesture).\n *\n * When `silentOnly` is false (default), first tries a silent refresh,\n * and if that fails, opens a popup for full re-authorization.\n */\nexport async function reconnectMcpOAuth(\n db: ShadowClawDatabase,\n connectionId: string,\n options: ReconnectMcpOAuthOptions = {},\n): Promise<ReconnectMcpOAuthResult> {\n const connection = await getRemoteMcpConnection(db, connectionId);\n if (!connection?.credentialRef) {\n return { success: false, error: \"Connection not found.\" };\n }\n\n const ref = connection.credentialRef;\n if (ref.authType !== \"oauth\") {\n return {\n success: false,\n error: \"This connection does not use OAuth authentication.\",\n };\n }\n\n // Load accounts from DB\n const serviceRaw = await getConfig(db, CONFIG_KEYS.SERVICE_ACCOUNTS);\n const serviceAccounts: ServiceAccount[] = Array.isArray(serviceRaw)\n ? serviceRaw\n : [];\n\n const gitRaw = await getConfig(db, CONFIG_KEYS.GIT_ACCOUNTS);\n const gitAccounts: GitAccount[] = Array.isArray(gitRaw) ? gitRaw : [];\n\n // Find the linked account\n let account: OAuthAccountLike | undefined;\n let accountStore: \"service\" | \"git\" | null = null;\n\n if (ref.accountId) {\n account = serviceAccounts.find((acct) => acct.id === ref.accountId) as\n OAuthAccountLike | undefined;\n\n accountStore = \"service\";\n } else if (ref.gitAccountId) {\n account = gitAccounts.find((acct) => acct.id === ref.gitAccountId) as\n OAuthAccountLike | undefined;\n\n accountStore = \"git\";\n }\n\n if (!account || !accountStore) {\n return {\n error:\n \"Linked account not found. Edit the connection to re-configure authentication.\",\n success: false,\n };\n }\n\n const clientId = account.oauthClientId;\n const providerId = account.oauthProviderId;\n\n if (!providerId || !clientId) {\n return {\n error:\n \"Account is missing OAuth provider or client ID. Edit the account in Settings → Accounts to fix.\",\n success: false,\n };\n }\n\n // ── Silent refresh attempt ───────────────────────────────────────\n // Always try a silent token refresh first. This works without a\n // popup and handles the common case where the refresh token is\n // still valid but the access token expired.\n if (account.refreshToken) {\n const silentResult = await trySilentRefresh(\n db,\n account,\n accountStore,\n serviceAccounts,\n gitAccounts,\n ref,\n connectionId,\n );\n\n if (silentResult.success) {\n return silentResult;\n }\n }\n\n // If silentOnly was requested, don't open a popup.\n if (options.silentOnly) {\n return {\n error:\n \"Silent token refresh failed. Use Settings → Remote MCP → Reconnect OAuth for full re-authorization.\",\n success: false,\n };\n }\n\n const clientSecret = account.oauthClientSecret\n ? await decryptValue(account.oauthClientSecret)\n : undefined;\n\n const scope = account.scopes;\n\n // Resolve OAuth URLs\n const providerDef = OAUTH_PROVIDER_DEFINITIONS[providerId];\n const isCustomMcp = providerId === \"custom_mcp\";\n const redirectUri =\n isCustomMcp && account.oauthCustomRedirectUri\n ? account.oauthCustomRedirectUri\n : providerDef?.redirectUri\n ? providerDef.redirectUri\n : `${globalThis.location?.origin || \"\"}/oauth/callback`;\n\n try {\n const authorizeRes = await fetch(\"/oauth/authorize\", {\n body: JSON.stringify({\n providerId,\n clientId,\n clientSecret: clientSecret || undefined,\n redirectUri,\n scope,\n ...(isCustomMcp && account.oauthCustomAuthorizeUrl\n ? { authorizeUrl: account.oauthCustomAuthorizeUrl }\n : {}),\n ...(isCustomMcp && account.oauthCustomTokenUrl\n ? { tokenUrl: account.oauthCustomTokenUrl }\n : {}),\n ...(isCustomMcp && typeof account.oauthCustomUsePkce === \"boolean\"\n ? { usePkce: account.oauthCustomUsePkce }\n : {}),\n }),\n headers: { \"content-type\": \"application/json\" },\n method: \"POST\",\n });\n\n const authorizePayload = (await authorizeRes.json()) as {\n authorizeUrl?: string;\n error?: string;\n state?: string;\n };\n\n if (\n !authorizeRes.ok ||\n !authorizePayload.state ||\n !authorizePayload.authorizeUrl\n ) {\n throw new Error(authorizePayload.error || \"OAuth authorize failed\");\n }\n\n const popup = window.open(\n authorizePayload.authorizeUrl,\n \"shadowclaw-oauth\",\n \"popup=yes,width=540,height=720\",\n );\n\n if (!popup || popup.closed || typeof popup.closed === \"undefined\") {\n throw new Error(\n \"OAuth popup was blocked by the browser. Please enable popups for this site and try again.\",\n );\n }\n\n const state = authorizePayload.state;\n let status = \"pending\";\n for (let attempt = 0; attempt < 60; attempt++) {\n const sessionRes = await fetch(\n `/oauth/session/${encodeURIComponent(state)}`,\n );\n\n const sessionPayload = (await sessionRes.json()) as {\n error?: string;\n status?: string;\n };\n\n if (!sessionRes.ok) {\n throw new Error(sessionPayload.error || \"OAuth session not found\");\n }\n\n status = sessionPayload.status || \"pending\";\n\n if (status === \"authorized\") {\n break;\n }\n\n if (status === \"error\") {\n throw new Error(sessionPayload.error || \"OAuth authorization failed\");\n }\n\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n\n if (status !== \"authorized\") {\n throw new Error(\"OAuth authorization timed out\");\n }\n\n const tokenRes = await fetch(\"/oauth/token\", {\n body: JSON.stringify({ state }),\n headers: { \"content-type\": \"application/json\" },\n method: \"POST\",\n });\n\n const tokenPayload = (await tokenRes.json()) as {\n accessToken?: string;\n error?: string;\n expiresIn?: number;\n refreshToken?: string;\n scope?: string;\n tokenType?: string;\n };\n\n if (!tokenRes.ok || !tokenPayload.accessToken) {\n throw new Error(tokenPayload.error || \"OAuth token exchange failed\");\n }\n\n // Update the linked account with new tokens\n const encryptedAccessToken = await encryptValue(tokenPayload.accessToken);\n if (!encryptedAccessToken) {\n throw new Error(\"Failed to encrypt access token\");\n }\n\n let encryptedRefreshToken = account.refreshToken;\n if (tokenPayload.refreshToken) {\n const maybeEncrypted = await encryptValue(tokenPayload.refreshToken);\n if (maybeEncrypted) {\n encryptedRefreshToken = maybeEncrypted;\n }\n }\n\n const updatedFields = buildOAuthUpdateFields(\n {\n accessToken: tokenPayload.accessToken,\n expiresIn: tokenPayload.expiresIn,\n refreshToken: tokenPayload.refreshToken,\n scope: tokenPayload.scope,\n tokenType: tokenPayload.tokenType,\n },\n account,\n encryptedAccessToken,\n encryptedRefreshToken,\n );\n\n // Persist to the correct account store\n if (accountStore === \"service\" && ref.accountId) {\n const idx = serviceAccounts.findIndex(\n (acct) => acct.id === ref.accountId,\n );\n if (idx !== -1) {\n Object.assign(serviceAccounts[idx], updatedFields);\n\n await setConfig(db, CONFIG_KEYS.SERVICE_ACCOUNTS, serviceAccounts);\n }\n } else if (accountStore === \"git\" && ref.gitAccountId) {\n const idx = gitAccounts.findIndex((acct) => acct.id === ref.gitAccountId);\n if (idx !== -1) {\n Object.assign(gitAccounts[idx], updatedFields);\n\n await setConfig(db, CONFIG_KEYS.GIT_ACCOUNTS, gitAccounts);\n }\n }\n\n // Clear the MCP session so the next call uses fresh credentials\n clearRemoteMcpSession(connectionId);\n\n return { success: true };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n\n return { success: false, error: message };\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as PROVIDERS } from "./config-
|
|
1
|
+
import { C as PROVIDERS } from "./config-BrHR97zt.js";
|
|
2
2
|
import { escapeHtml } from "./utils/html.js";
|
|
3
3
|
|
|
4
4
|
//#region src/components/settings/shadow-claw-llm/model-ranking.ts
|
|
@@ -113,4 +113,4 @@ function renderTransformersJsBrowserModelOptions(selectedModel, modelItems, opti
|
|
|
113
113
|
|
|
114
114
|
//#endregion
|
|
115
115
|
export { renderTransformersJsBrowserModelOptions as i, getSortedTransformersJsBrowserModelIds as n, isLikelyInstructionModelId as r, compareLocalModelCandidates as t };
|
|
116
|
-
//# sourceMappingURL=model-ranking-
|
|
116
|
+
//# sourceMappingURL=model-ranking-BhsJV7vb.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-ranking-
|
|
1
|
+
{"version":3,"file":"model-ranking-BhsJV7vb.js","names":[],"sources":["../../src/components/settings/shadow-claw-llm/model-ranking.ts"],"sourcesContent":["import type { LocalModelRankCandidate } from \"../../types.js\";\nimport { PROVIDERS } from \"../../../config/config.js\";\nimport { escapeHtml } from \"../../../utils/html.js\";\n\nfunction parseModelBillionsFromId(modelId: string): number | null {\n const normalized = modelId.toLowerCase();\n const directMatch = /(?:^|[-_\\/.])(\\d+(?:\\.\\d+)?)b(?:[-_\\/.]|$)/i.exec(\n normalized,\n );\n if (directMatch) {\n const parsed = Number(directMatch[1]);\n if (Number.isFinite(parsed) && parsed > 0) {\n return parsed;\n }\n }\n\n // Gemma style IDs such as E2B/E4B.\n const effectiveMatch = /(?:^|[-_\\/.])e(\\d+(?:\\.\\d+)?)b(?:[-_\\/.]|$)/i.exec(\n normalized,\n );\n if (!effectiveMatch) {\n return null;\n }\n\n const parsed = Number(effectiveMatch[1]);\n if (!Number.isFinite(parsed) || parsed <= 0) {\n return null;\n }\n\n return parsed;\n}\n\nexport function isLikelyInstructionModelId(modelId: string): boolean {\n const id = modelId.toLowerCase();\n\n if (/(^|[-_./])(instruct|chat|assistant|tool|it)([-_./]|$)/i.test(id)) {\n return true;\n }\n\n // Local catalogs commonly use Qwen* and distilled R1 variants as instruct defaults.\n if (/(qwen\\d*(?:\\.\\d+)?|deepseek-r1-distill)/i.test(id)) {\n return true;\n }\n\n return false;\n}\n\nfunction hasQuantizedHint(modelId: string): boolean {\n return /(^|[-_./])(q\\d+|int8|uint8|4bit|8bit|bnb4|opt)([-_./]|$)/i.test(\n modelId,\n );\n}\n\nfunction getLocalModelSortScore(\n candidate: LocalModelRankCandidate,\n providerId: string,\n): number {\n const idLower = candidate.id.toLowerCase();\n const sizeB = parseModelBillionsFromId(candidate.id);\n let score = 0;\n\n if (!candidate.supportsTools) {\n score += 60;\n }\n\n if (isLikelyInstructionModelId(candidate.id)) {\n score -= 40;\n }\n\n if (idLower.includes(\"onnx\")) {\n score -= 30;\n } else {\n score += 90;\n }\n\n if (hasQuantizedHint(idLower)) {\n score -= 20;\n }\n\n if (sizeB === null) {\n score += 10;\n } else if (sizeB <= 0.6) {\n score -= 120;\n } else if (sizeB <= 0.8) {\n score -= 100;\n } else if (sizeB <= 1.2) {\n score -= 80;\n } else if (sizeB <= 1.8) {\n score -= 40;\n } else if (sizeB <= 3) {\n score += 20;\n } else {\n score += 80;\n }\n\n if (/thinking|reasoning/i.test(idLower)) {\n score += 25;\n }\n\n // Browser runtime has the strictest memory pressure profile.\n if (providerId === \"transformers_js_browser\") {\n if (sizeB !== null && sizeB > 1.5) {\n score += 40;\n }\n\n if (!idLower.includes(\"onnx\")) {\n score += 80;\n }\n }\n\n return score;\n}\n\nexport const ORIGINAL_PROMPT_API_MODELS: readonly string[] = [\n \"onnx-community/Qwen3-0.6B-ONNX\",\n \"onnx-community/gemma-3-1b-it-ONNX-GQA\",\n \"onnx-community/gemma-4-E2B-it-ONNX\",\n \"onnx-community/gemma-4-E4B-it-ONNX\",\n];\n\nexport const CURATED_PROMPT_API_MODEL_LABELS: Record<string, string> = {\n \"onnx-community/Qwen3-0.6B-ONNX\":\n \"onnx-community/Qwen3-0.6B-ONNX — Recommended (Fast, Compact & Tool Calling)\",\n \"onnx-community/gemma-3-1b-it-ONNX-GQA\":\n \"onnx-community/gemma-3-1b-it-ONNX-GQA — Alternative (1B Parameters)\",\n \"onnx-community/gemma-4-E2B-it-ONNX\":\n \"onnx-community/gemma-4-E2B-it-ONNX — Alternative (2B Parameters, 128k Context)\",\n \"onnx-community/gemma-4-E4B-it-ONNX\":\n \"onnx-community/gemma-4-E4B-it-ONNX — Alternative (4B Parameters, 128k Context)\",\n};\n\nexport function compareLocalModelCandidates(\n a: LocalModelRankCandidate,\n b: LocalModelRankCandidate,\n providerId: string,\n): number {\n if (providerId === \"transformers_js_browser\") {\n const idxA = ORIGINAL_PROMPT_API_MODELS.indexOf(a.id);\n const idxB = ORIGINAL_PROMPT_API_MODELS.indexOf(b.id);\n\n if (idxA !== -1 && idxB !== -1) {\n return idxA - idxB;\n }\n if (idxA !== -1) {\n return -1;\n }\n if (idxB !== -1) {\n return 1;\n }\n\n return a.id.localeCompare(b.id);\n }\n\n const scoreA = getLocalModelSortScore(a, providerId);\n const scoreB = getLocalModelSortScore(b, providerId);\n\n if (scoreA !== scoreB) {\n return scoreA - scoreB;\n }\n\n if (a.contextLength !== b.contextLength) {\n return b.contextLength - a.contextLength;\n }\n\n return a.id.localeCompare(b.id);\n}\n\nexport function getSortedTransformersJsBrowserModelIds(\n modelItems?: Array<string | { id?: string; name?: string }>,\n): string[] {\n const staticModels = PROVIDERS.transformers_js_browser?.models || [];\n const rawItems =\n modelItems && modelItems.length > 0 ? modelItems : staticModels;\n\n const idSet = new Set<string>();\n for (const item of rawItems) {\n const id = typeof item === \"string\" ? item : item?.id || item?.name;\n if (id && typeof id === \"string\" && id.trim()) {\n idSet.add(id.trim());\n }\n }\n for (const id of ORIGINAL_PROMPT_API_MODELS) {\n idSet.add(id);\n }\n for (const id of staticModels) {\n idSet.add(id);\n }\n\n const allIds = Array.from(idSet);\n return allIds.sort((a, b) =>\n compareLocalModelCandidates(\n { id: a, supportsTools: isLikelyInstructionModelId(a), contextLength: 0 },\n { id: b, supportsTools: isLikelyInstructionModelId(b), contextLength: 0 },\n \"transformers_js_browser\",\n ),\n );\n}\n\nexport function renderTransformersJsBrowserModelOptions(\n selectedModel: string,\n modelItems?: Array<string | { id?: string; name?: string }>,\n options?: { includeCustom?: boolean },\n): string {\n const sortedModelIds = getSortedTransformersJsBrowserModelIds(modelItems);\n let html = \"\";\n for (let i = 0; i < sortedModelIds.length; i++) {\n const id = sortedModelIds[i];\n const isSelected = id === selectedModel ? \" selected\" : \"\";\n const label =\n CURATED_PROMPT_API_MODEL_LABELS[id] ||\n `${id}${isLikelyInstructionModelId(id) ? \" 🛠️\" : \"\"}`;\n html += `<option value=\"${escapeHtml(id)}\"${isSelected}>${escapeHtml(label)}</option>`;\n if (i === 3 && sortedModelIds.length > 4) {\n html += \"<hr>\";\n }\n }\n if (options?.includeCustom) {\n const isCustomSelected =\n selectedModel === \"__custom__\" ||\n (selectedModel !== \"\" && !sortedModelIds.includes(selectedModel))\n ? \" selected\"\n : \"\";\n html += `<option value=\"__custom__\"${isCustomSelected}>-- Custom Model ID --</option>`;\n }\n return html;\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { c as isStaleHandleError, i as getOpfsRootDirName, n as getGroupDir, o as getStorageStatus, s as invalidateStorageRoot, t as parsePath } from "./parse-path-
|
|
2
|
-
import { o as DEFAULT_GROUP_ID } from "./config-
|
|
3
|
-
import { c as writeFileHandle, l as writeOpfsPathViaWorker } from "./tools-
|
|
4
|
-
import { d as setMainGroupMemorySuppressed, o as suppressPage, p as setMainGroupIndexSuppressed, t as orchestratorStore } from "./orchestrator-
|
|
1
|
+
import { c as isStaleHandleError, i as getOpfsRootDirName, n as getGroupDir, o as getStorageStatus, s as invalidateStorageRoot, t as parsePath } from "./parse-path-BOHQP_IQ.js";
|
|
2
|
+
import { o as DEFAULT_GROUP_ID } from "./config-BrHR97zt.js";
|
|
3
|
+
import { c as writeFileHandle, l as writeOpfsPathViaWorker } from "./tools-B8OJ4sMF.js";
|
|
4
|
+
import { d as setMainGroupMemorySuppressed, o as suppressPage, p as setMainGroupIndexSuppressed, t as orchestratorStore } from "./orchestrator-CCARkxQC.js";
|
|
5
5
|
|
|
6
6
|
//#region src/storage/copy-group-entry.ts
|
|
7
7
|
/**
|
|
@@ -166,4 +166,4 @@ async function moveGroupEntry(db, sourceGroupId, targetGroupId, sourcePath, targ
|
|
|
166
166
|
|
|
167
167
|
//#endregion
|
|
168
168
|
export { copyGroupEntry as i, deleteGroupFile as n, createGroupDirectory as r, moveGroupEntry as t };
|
|
169
|
-
//# sourceMappingURL=move-group-entry-
|
|
169
|
+
//# sourceMappingURL=move-group-entry-DDpjxa10.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"move-group-entry-NMTJ59M9.js","names":[],"sources":["../../src/storage/copy-group-entry.ts","../../src/storage/create-group-directory.ts","../../src/storage/delete-group-file.ts","../../src/storage/move-group-entry.ts"],"sourcesContent":["import { getGroupDir } from \"./get-group-dir.js\";\nimport { parsePath } from \"./parse-path.js\";\nimport {\n getOpfsRootDirName,\n getStorageStatus,\n invalidateStorageRoot,\n isStaleHandleError,\n} from \"./storage.js\";\nimport {\n writeFileHandle,\n writeOpfsPathViaWorker,\n} from \"./write-file-handle.js\";\nimport type { ShadowClawDatabase } from \"../db/types.js\";\n\n/**\n * Copy a file or directory in a group's workspace to a new path.\n */\nexport async function copyGroupEntry(\n db: ShadowClawDatabase,\n sourceGroupId: string,\n targetGroupId: string,\n sourcePath: string,\n targetPath: string,\n): Promise<void> {\n const normSource = sourcePath.replace(/\\/$/, \"\");\n const normTarget = targetPath.replace(/\\/$/, \"\");\n\n if (sourceGroupId === targetGroupId && normSource === normTarget) {\n throw new Error(\"Source and target paths are identical\");\n }\n\n const { dirs: srcDirs, filename: srcName } = parsePath(normSource);\n const { dirs: tgtDirs, filename: tgtName } = parsePath(normTarget);\n\n if (!srcName || !tgtName) {\n throw new Error(\"Invalid path\");\n }\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n const srcGroupDir = await getGroupDir(db, sourceGroupId);\n const tgtGroupDir = await getGroupDir(db, targetGroupId);\n\n // Resolve source parent\n let srcParent = srcGroupDir;\n for (const seg of srcDirs) {\n srcParent = await srcParent.getDirectoryHandle(seg);\n }\n\n // Resolve target parent\n let tgtParent = tgtGroupDir;\n for (const seg of tgtDirs) {\n tgtParent = await tgtParent.getDirectoryHandle(seg, { create: true });\n }\n\n // Assert target does not exist\n if (\n (await tryGetFileHandle(tgtParent, tgtName)) ||\n (await tryGetDirectoryHandle(tgtParent, tgtName))\n ) {\n throw new Error(`Target already exists: ${tgtName}`);\n }\n\n // Check if source is a directory\n const sourceDir = await tryGetDirectoryHandle(srcParent, srcName);\n if (sourceDir) {\n const targetDir = await tgtParent.getDirectoryHandle(tgtName, {\n create: true,\n });\n\n const safeId = targetGroupId.replace(/:/g, \"-\");\n const currentPathSegments = [\n getOpfsRootDirName(),\n \"groups\",\n safeId,\n ...tgtDirs,\n tgtName,\n ];\n\n try {\n await copyDirectoryContents(\n db,\n targetGroupId,\n sourceDir,\n targetDir,\n currentPathSegments,\n );\n } catch (copyErr) {\n await tgtParent\n .removeEntry(tgtName, { recursive: true })\n .catch(() => undefined);\n throw copyErr;\n }\n\n return;\n }\n\n // Check if source is a file\n const sourceFile = await tryGetFileHandle(srcParent, srcName);\n if (sourceFile) {\n const file = await sourceFile.getFile();\n const targetFile = await tgtParent.getFileHandle(tgtName, {\n create: true,\n });\n\n try {\n await writeFileHandle(targetFile, file);\n } catch (writeErr) {\n const message =\n writeErr instanceof Error ? writeErr.message : String(writeErr);\n const needsOpfsWorkerFallback =\n message.includes(\"Writable file streams are not supported\") &&\n (await getStorageStatus(db)).type === \"opfs\";\n\n if (!needsOpfsWorkerFallback) {\n await tgtParent.removeEntry(tgtName).catch(() => undefined);\n\n throw writeErr;\n }\n\n const safeId = targetGroupId.replace(/:/g, \"-\");\n await writeOpfsPathViaWorker(\n [getOpfsRootDirName(), \"groups\", safeId, ...tgtDirs, tgtName],\n file,\n );\n }\n\n return;\n }\n\n throw new Error(`Entry not found: ${sourcePath}`);\n } catch (err) {\n if (attempt === 0 && isStaleHandleError(err)) {\n invalidateStorageRoot();\n\n continue;\n }\n\n throw err;\n }\n }\n}\n\nasync function tryGetDirectoryHandle(\n parentDir: FileSystemDirectoryHandle,\n name: string,\n): Promise<FileSystemDirectoryHandle | null> {\n try {\n return await parentDir.getDirectoryHandle(name);\n } catch {\n return null;\n }\n}\n\nasync function tryGetFileHandle(\n parentDir: FileSystemDirectoryHandle,\n name: string,\n): Promise<FileSystemFileHandle | null> {\n try {\n return await parentDir.getFileHandle(name);\n } catch {\n return null;\n }\n}\n\nasync function copyDirectoryContents(\n db: ShadowClawDatabase,\n targetGroupId: string,\n sourceDir: FileSystemDirectoryHandle,\n targetDir: FileSystemDirectoryHandle,\n currentPathSegments: string[],\n): Promise<void> {\n for await (const [name, handle] of (sourceDir as any).entries()) {\n if (handle.kind === \"directory\") {\n const nextTargetDir = await targetDir.getDirectoryHandle(name, {\n create: true,\n });\n await copyDirectoryContents(db, targetGroupId, handle, nextTargetDir, [\n ...currentPathSegments,\n name,\n ]);\n\n continue;\n }\n\n const file = await handle.getFile();\n const targetFileHandle = await targetDir.getFileHandle(name, {\n create: true,\n });\n\n try {\n await writeFileHandle(targetFileHandle, file);\n } catch (writeErr) {\n const message =\n writeErr instanceof Error ? writeErr.message : String(writeErr);\n const needsOpfsWorkerFallback =\n message.includes(\"Writable file streams are not supported\") &&\n (await getStorageStatus(db)).type === \"opfs\";\n\n if (!needsOpfsWorkerFallback) {\n throw writeErr;\n }\n\n await writeOpfsPathViaWorker([...currentPathSegments, name], file);\n }\n }\n}\n","import { getGroupDir } from \"./get-group-dir.js\";\nimport { invalidateStorageRoot, isStaleHandleError } from \"./storage.js\";\nimport type { ShadowClawDatabase } from \"../db/types.js\";\n\n/**\n * Create a directory (and any missing parent directories) in a group's workspace.\n */\nexport async function createGroupDirectory(\n db: ShadowClawDatabase,\n groupId: string,\n dirPath: string,\n): Promise<void> {\n const normalized = dirPath\n .replace(/\\\\/g, \"/\")\n .replace(/^\\/home\\/user\\//, \"/\")\n .replace(/^\\/+/, \"\")\n .replace(/\\/+$/, \"\");\n\n const parts = normalized.split(\"/\").filter(Boolean);\n if (parts.length === 0) {\n throw new Error(\"Empty directory path\");\n }\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n let dir = await getGroupDir(db, groupId);\n for (const segment of parts) {\n dir = await dir.getDirectoryHandle(segment, { create: true });\n }\n\n return;\n } catch (err) {\n if (attempt === 0 && isStaleHandleError(err)) {\n invalidateStorageRoot();\n\n continue;\n }\n\n throw err;\n }\n }\n}\n","import { getGroupDir } from \"./get-group-dir.js\";\nimport { parsePath } from \"./parse-path.js\";\nimport { setMainGroupMemorySuppressed } from \"./ensure-main-group-memory.js\";\nimport { setMainGroupIndexSuppressed } from \"./ensure-main-group-index.js\";\nimport { DEFAULT_GROUP_ID } from \"../config/config.js\";\nimport { orchestratorStore } from \"../stores/orchestrator.js\";\nimport { suppressPage } from \"./suppressed-pages.js\";\nimport type { ShadowClawDatabase } from \"../db/types.js\";\n\n/**\n * Delete a file from a group's workspace.\n */\nexport async function deleteGroupFile(\n db: ShadowClawDatabase,\n groupId: string,\n filePath: string,\n): Promise<void> {\n const groupDir = await getGroupDir(db, groupId);\n const { dirs, filename } = parsePath(filePath);\n\n let dir = groupDir;\n for (const seg of dirs) {\n dir = await dir.getDirectoryHandle(seg);\n }\n\n await dir.removeEntry(filename);\n\n if (groupId === DEFAULT_GROUP_ID && dirs.length === 0) {\n if (filename === \"MEMORY.md\") {\n await setMainGroupMemorySuppressed(db, true);\n } else if (filename === \"index.html\") {\n await setMainGroupIndexSuppressed(db, true);\n }\n }\n\n try {\n await suppressPage(db, groupId, filePath);\n } catch {}\n\n try {\n await orchestratorStore.removePage(db, filePath, groupId);\n } catch {\n // Orchestrator store might not be instantiated in isolated storage unit test\n }\n}\n","import { copyGroupEntry } from \"./copy-group-entry.js\";\nimport { getGroupDir } from \"./get-group-dir.js\";\nimport { parsePath } from \"./parse-path.js\";\nimport type { ShadowClawDatabase } from \"../db/types.js\";\n\n/**\n * Move (rename and/or relocate) a file or directory in a group's workspace.\n */\nexport async function moveGroupEntry(\n db: ShadowClawDatabase,\n sourceGroupId: string,\n targetGroupId: string,\n sourcePath: string,\n targetPath: string,\n): Promise<void> {\n const normSource = sourcePath.replace(/\\/$/, \"\");\n const normTarget = targetPath.replace(/\\/$/, \"\");\n\n if (sourceGroupId === targetGroupId && normSource === normTarget) {\n return; // No-op\n }\n\n // 1. Copy source to target\n await copyGroupEntry(\n db,\n sourceGroupId,\n targetGroupId,\n normSource,\n normTarget,\n );\n\n // 2. Remove source\n const { dirs, filename } = parsePath(normSource);\n if (!filename) {\n throw new Error(\"Invalid source path\");\n }\n\n const groupDir = await getGroupDir(db, sourceGroupId);\n let parentDir = groupDir;\n for (const seg of dirs) {\n parentDir = await parentDir.getDirectoryHandle(seg);\n }\n\n await parentDir.removeEntry(filename, { recursive: true });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"move-group-entry-DDpjxa10.js","names":[],"sources":["../../src/storage/copy-group-entry.ts","../../src/storage/create-group-directory.ts","../../src/storage/delete-group-file.ts","../../src/storage/move-group-entry.ts"],"sourcesContent":["import { getGroupDir } from \"./get-group-dir.js\";\nimport { parsePath } from \"./parse-path.js\";\nimport {\n getOpfsRootDirName,\n getStorageStatus,\n invalidateStorageRoot,\n isStaleHandleError,\n} from \"./storage.js\";\nimport {\n writeFileHandle,\n writeOpfsPathViaWorker,\n} from \"./write-file-handle.js\";\nimport type { ShadowClawDatabase } from \"../db/types.js\";\n\n/**\n * Copy a file or directory in a group's workspace to a new path.\n */\nexport async function copyGroupEntry(\n db: ShadowClawDatabase,\n sourceGroupId: string,\n targetGroupId: string,\n sourcePath: string,\n targetPath: string,\n): Promise<void> {\n const normSource = sourcePath.replace(/\\/$/, \"\");\n const normTarget = targetPath.replace(/\\/$/, \"\");\n\n if (sourceGroupId === targetGroupId && normSource === normTarget) {\n throw new Error(\"Source and target paths are identical\");\n }\n\n const { dirs: srcDirs, filename: srcName } = parsePath(normSource);\n const { dirs: tgtDirs, filename: tgtName } = parsePath(normTarget);\n\n if (!srcName || !tgtName) {\n throw new Error(\"Invalid path\");\n }\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n const srcGroupDir = await getGroupDir(db, sourceGroupId);\n const tgtGroupDir = await getGroupDir(db, targetGroupId);\n\n // Resolve source parent\n let srcParent = srcGroupDir;\n for (const seg of srcDirs) {\n srcParent = await srcParent.getDirectoryHandle(seg);\n }\n\n // Resolve target parent\n let tgtParent = tgtGroupDir;\n for (const seg of tgtDirs) {\n tgtParent = await tgtParent.getDirectoryHandle(seg, { create: true });\n }\n\n // Assert target does not exist\n if (\n (await tryGetFileHandle(tgtParent, tgtName)) ||\n (await tryGetDirectoryHandle(tgtParent, tgtName))\n ) {\n throw new Error(`Target already exists: ${tgtName}`);\n }\n\n // Check if source is a directory\n const sourceDir = await tryGetDirectoryHandle(srcParent, srcName);\n if (sourceDir) {\n const targetDir = await tgtParent.getDirectoryHandle(tgtName, {\n create: true,\n });\n\n const safeId = targetGroupId.replace(/:/g, \"-\");\n const currentPathSegments = [\n getOpfsRootDirName(),\n \"groups\",\n safeId,\n ...tgtDirs,\n tgtName,\n ];\n\n try {\n await copyDirectoryContents(\n db,\n targetGroupId,\n sourceDir,\n targetDir,\n currentPathSegments,\n );\n } catch (copyErr) {\n await tgtParent\n .removeEntry(tgtName, { recursive: true })\n .catch(() => undefined);\n throw copyErr;\n }\n\n return;\n }\n\n // Check if source is a file\n const sourceFile = await tryGetFileHandle(srcParent, srcName);\n if (sourceFile) {\n const file = await sourceFile.getFile();\n const targetFile = await tgtParent.getFileHandle(tgtName, {\n create: true,\n });\n\n try {\n await writeFileHandle(targetFile, file);\n } catch (writeErr) {\n const message =\n writeErr instanceof Error ? writeErr.message : String(writeErr);\n const needsOpfsWorkerFallback =\n message.includes(\"Writable file streams are not supported\") &&\n (await getStorageStatus(db)).type === \"opfs\";\n\n if (!needsOpfsWorkerFallback) {\n await tgtParent.removeEntry(tgtName).catch(() => undefined);\n\n throw writeErr;\n }\n\n const safeId = targetGroupId.replace(/:/g, \"-\");\n await writeOpfsPathViaWorker(\n [getOpfsRootDirName(), \"groups\", safeId, ...tgtDirs, tgtName],\n file,\n );\n }\n\n return;\n }\n\n throw new Error(`Entry not found: ${sourcePath}`);\n } catch (err) {\n if (attempt === 0 && isStaleHandleError(err)) {\n invalidateStorageRoot();\n\n continue;\n }\n\n throw err;\n }\n }\n}\n\nasync function tryGetDirectoryHandle(\n parentDir: FileSystemDirectoryHandle,\n name: string,\n): Promise<FileSystemDirectoryHandle | null> {\n try {\n return await parentDir.getDirectoryHandle(name);\n } catch {\n return null;\n }\n}\n\nasync function tryGetFileHandle(\n parentDir: FileSystemDirectoryHandle,\n name: string,\n): Promise<FileSystemFileHandle | null> {\n try {\n return await parentDir.getFileHandle(name);\n } catch {\n return null;\n }\n}\n\nasync function copyDirectoryContents(\n db: ShadowClawDatabase,\n targetGroupId: string,\n sourceDir: FileSystemDirectoryHandle,\n targetDir: FileSystemDirectoryHandle,\n currentPathSegments: string[],\n): Promise<void> {\n for await (const [name, handle] of (sourceDir as any).entries()) {\n if (handle.kind === \"directory\") {\n const nextTargetDir = await targetDir.getDirectoryHandle(name, {\n create: true,\n });\n await copyDirectoryContents(db, targetGroupId, handle, nextTargetDir, [\n ...currentPathSegments,\n name,\n ]);\n\n continue;\n }\n\n const file = await handle.getFile();\n const targetFileHandle = await targetDir.getFileHandle(name, {\n create: true,\n });\n\n try {\n await writeFileHandle(targetFileHandle, file);\n } catch (writeErr) {\n const message =\n writeErr instanceof Error ? writeErr.message : String(writeErr);\n const needsOpfsWorkerFallback =\n message.includes(\"Writable file streams are not supported\") &&\n (await getStorageStatus(db)).type === \"opfs\";\n\n if (!needsOpfsWorkerFallback) {\n throw writeErr;\n }\n\n await writeOpfsPathViaWorker([...currentPathSegments, name], file);\n }\n }\n}\n","import { getGroupDir } from \"./get-group-dir.js\";\nimport { invalidateStorageRoot, isStaleHandleError } from \"./storage.js\";\nimport type { ShadowClawDatabase } from \"../db/types.js\";\n\n/**\n * Create a directory (and any missing parent directories) in a group's workspace.\n */\nexport async function createGroupDirectory(\n db: ShadowClawDatabase,\n groupId: string,\n dirPath: string,\n): Promise<void> {\n const normalized = dirPath\n .replace(/\\\\/g, \"/\")\n .replace(/^\\/home\\/user\\//, \"/\")\n .replace(/^\\/+/, \"\")\n .replace(/\\/+$/, \"\");\n\n const parts = normalized.split(\"/\").filter(Boolean);\n if (parts.length === 0) {\n throw new Error(\"Empty directory path\");\n }\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n let dir = await getGroupDir(db, groupId);\n for (const segment of parts) {\n dir = await dir.getDirectoryHandle(segment, { create: true });\n }\n\n return;\n } catch (err) {\n if (attempt === 0 && isStaleHandleError(err)) {\n invalidateStorageRoot();\n\n continue;\n }\n\n throw err;\n }\n }\n}\n","import { getGroupDir } from \"./get-group-dir.js\";\nimport { parsePath } from \"./parse-path.js\";\nimport { setMainGroupMemorySuppressed } from \"./ensure-main-group-memory.js\";\nimport { setMainGroupIndexSuppressed } from \"./ensure-main-group-index.js\";\nimport { DEFAULT_GROUP_ID } from \"../config/config.js\";\nimport { orchestratorStore } from \"../stores/orchestrator.js\";\nimport { suppressPage } from \"./suppressed-pages.js\";\nimport type { ShadowClawDatabase } from \"../db/types.js\";\n\n/**\n * Delete a file from a group's workspace.\n */\nexport async function deleteGroupFile(\n db: ShadowClawDatabase,\n groupId: string,\n filePath: string,\n): Promise<void> {\n const groupDir = await getGroupDir(db, groupId);\n const { dirs, filename } = parsePath(filePath);\n\n let dir = groupDir;\n for (const seg of dirs) {\n dir = await dir.getDirectoryHandle(seg);\n }\n\n await dir.removeEntry(filename);\n\n if (groupId === DEFAULT_GROUP_ID && dirs.length === 0) {\n if (filename === \"MEMORY.md\") {\n await setMainGroupMemorySuppressed(db, true);\n } else if (filename === \"index.html\") {\n await setMainGroupIndexSuppressed(db, true);\n }\n }\n\n try {\n await suppressPage(db, groupId, filePath);\n } catch {}\n\n try {\n await orchestratorStore.removePage(db, filePath, groupId);\n } catch {\n // Orchestrator store might not be instantiated in isolated storage unit test\n }\n}\n","import { copyGroupEntry } from \"./copy-group-entry.js\";\nimport { getGroupDir } from \"./get-group-dir.js\";\nimport { parsePath } from \"./parse-path.js\";\nimport type { ShadowClawDatabase } from \"../db/types.js\";\n\n/**\n * Move (rename and/or relocate) a file or directory in a group's workspace.\n */\nexport async function moveGroupEntry(\n db: ShadowClawDatabase,\n sourceGroupId: string,\n targetGroupId: string,\n sourcePath: string,\n targetPath: string,\n): Promise<void> {\n const normSource = sourcePath.replace(/\\/$/, \"\");\n const normTarget = targetPath.replace(/\\/$/, \"\");\n\n if (sourceGroupId === targetGroupId && normSource === normTarget) {\n return; // No-op\n }\n\n // 1. Copy source to target\n await copyGroupEntry(\n db,\n sourceGroupId,\n targetGroupId,\n normSource,\n normTarget,\n );\n\n // 2. Remove source\n const { dirs, filename } = parsePath(normSource);\n if (!filename) {\n throw new Error(\"Invalid source path\");\n }\n\n const groupDir = await getGroupDir(db, sourceGroupId);\n let parentDir = groupDir;\n for (const seg of dirs) {\n parentDir = await parentDir.getDirectoryHandle(seg);\n }\n\n await parentDir.removeEntry(filename, { recursive: true });\n}\n"],"mappings":"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"}
|