@taskforcehq/taskforce 0.3.328 → 0.3.330
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Taskforce.module.css +523 -79
- package/dist/TaskforceCore.js +237 -230
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
- package/dist/cli.js +34 -0
- package/dist/cliCloudTargetGuard.d.ts +5 -0
- package/dist/cliCloudTargetGuard.js +11 -0
- package/dist/components/features/AiProfilesModule.js +3 -5
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
- package/dist/components/features/TaskSettings.d.ts +12 -1
- package/dist/components/features/TaskSettings.js +217 -54
- package/dist/components/features/TaskforceAgentsModule.d.ts +1 -2
- package/dist/components/features/TaskforceAgentsModule.js +586 -116
- package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
- package/dist/components/features/agentConnections/AgentConnectionControl.d.ts +15 -0
- package/dist/components/features/agentConnections/AgentConnectionControl.js +125 -0
- package/dist/components/features/agentConnections/ModelConnectionsPanel.d.ts +18 -0
- package/dist/components/features/agentConnections/ModelConnectionsPanel.js +393 -0
- package/dist/components/features/agentConnections/modelConnectionsApi.d.ts +65 -0
- package/dist/components/features/agentConnections/modelConnectionsApi.js +129 -0
- package/dist/components/features/planning/PlanningModule.js +2 -5
- package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
- package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
- package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
- package/dist/components/features/planning/planningTaskArrangement.js +5 -5
- package/dist/components/features/taskforceAgentAssignments/AgentBehaviorAssignments.js +15 -24
- package/dist/components/features/taskforceAgentEditorModel.d.ts +2 -1
- package/dist/components/features/taskforceAgentEditorModel.js +5 -1
- package/dist/components/features/workflowManager/workflowManagerApi.d.ts +1 -1
- package/dist/components/features/workflowManager/workflowManagerApi.js +3 -0
- package/dist/components/task/TaskCard.d.ts +5 -0
- package/dist/components/task/TaskCard.js +65 -10
- package/dist/components/task/TaskImageReviews.js +14 -5
- package/dist/components/task/TaskKanban.d.ts +6 -1
- package/dist/components/task/TaskKanban.js +152 -6
- package/dist/components/task/TaskList.d.ts +5 -0
- package/dist/components/task/TaskList.js +3 -3
- package/dist/components/task/TaskWorkflowAssignmentField.js +68 -10
- package/dist/components/ui/PasswordInput.d.ts +6 -0
- package/dist/components/ui/PasswordInput.js +11 -0
- package/dist/components/ui/TopNoticeLayer.js +1 -1
- package/dist/components/views/AppShellHeader.js +32 -11
- package/dist/components/views/PlanComparisonPage.js +12 -0
- package/dist/components/views/StandaloneLayout.js +32 -55
- package/dist/components/views/WidgetView.js +3 -3
- package/dist/components/views/panels/PlanningDrawer.js +5 -12
- package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
- package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +4 -3
- package/dist/components/views/standalone/modals/SyncStatusModal.js +33 -38
- package/dist/config/envSchema.js +60 -1
- package/dist/config/localServiceRuntimeContract.d.ts +13 -0
- package/dist/config/localServiceRuntimeContract.js +135 -0
- package/dist/core/AiProfileService.js +46 -8
- package/dist/core/DeletedTaskLifecycleService.d.ts +1 -0
- package/dist/core/DeletedTaskLifecycleService.js +37 -6
- package/dist/core/McpTokenService.d.ts +23 -1
- package/dist/core/McpTokenService.js +93 -10
- package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +3 -2
- package/dist/core/TaskAttachmentLinksDurableMutationService.js +33 -9
- package/dist/core/TaskChecklistCommandService.d.ts +27 -0
- package/dist/core/TaskChecklistCommandService.js +83 -5
- package/dist/core/TaskLifecycleCommandService.d.ts +3 -1
- package/dist/core/TaskLifecycleCommandService.js +6 -2
- package/dist/core/Taskforce.d.ts +94 -2
- package/dist/core/Taskforce.js +760 -36
- package/dist/core/types.d.ts +14 -0
- package/dist/documentReviews/commandService.d.ts +2 -1
- package/dist/documentReviews/commandService.js +6 -3
- package/dist/hooks/sync/orchestratorShared.d.ts +1 -0
- package/dist/hooks/sync/orchestratorShared.js +2 -0
- package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
- package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
- package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
- package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
- package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
- package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.d.ts +3 -0
- package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.js +85 -9
- package/dist/hooks/sync/useSyncStatusControls.d.ts +4 -1
- package/dist/hooks/sync/useSyncStatusControls.js +47 -11
- package/dist/hooks/tasks/taskHttpMutation.js +1 -0
- package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
- package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
- package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
- package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
- package/dist/hooks/tasks/useTaskFormActions.d.ts +6 -0
- package/dist/hooks/tasks/useTaskFormActions.js +65 -12
- package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
- package/dist/hooks/ui/useSettingsModel.js +13 -2
- package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
- package/dist/hooks/ui/useSettingsPersistence.js +74 -47
- package/dist/hooks/useFilterSort.d.ts +7 -3
- package/dist/hooks/useFilterSort.js +15 -5
- package/dist/hooks/useSyncOrchestrator.d.ts +3 -0
- package/dist/hooks/useSyncOrchestrator.js +111 -2
- package/dist/hooks/useTaskData.d.ts +40 -1
- package/dist/hooks/useTaskData.js +240 -9
- package/dist/hooks/useTaskMutations.d.ts +12 -2
- package/dist/hooks/useTaskMutations.js +266 -52
- package/dist/hooks/useTaskforce.d.ts +39 -9
- package/dist/hooks/useTaskforce.js +359 -40
- package/dist/hooks/useUiNotice.d.ts +4 -0
- package/dist/hooks/useUiNotice.js +4 -0
- package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
- package/dist/mcp/clientRegistry.d.ts +2 -2
- package/dist/mcp/clientRegistry.js +1 -1
- package/dist/mcp/documentAssetRegistrar.js +53 -41
- package/dist/mcp/documentHelpers.d.ts +1 -0
- package/dist/mcp/documentHelpers.js +7 -3
- package/dist/mcp/durableTaskMutationRouter.d.ts +4 -1
- package/dist/mcp/durableTaskMutationRouter.js +10 -0
- package/dist/mcp/durableTaskRelationshipMutationRouter.js +4 -0
- package/dist/mcp/httpProtocolRouting.d.ts +10 -0
- package/dist/mcp/httpProtocolRouting.js +19 -0
- package/dist/mcp/localCliHealth.d.ts +2 -2
- package/dist/mcp/localCliHealth.js +2 -2
- package/dist/mcp/localServiceProxy.d.ts +1 -0
- package/dist/mcp/localServiceProxy.js +530 -68
- package/dist/mcp/planningAttachmentCommandAdapter.d.ts +3 -1
- package/dist/mcp/planningAttachmentCommandAdapter.js +20 -2
- package/dist/mcp/runtime.d.ts +54 -79
- package/dist/mcp/runtime.js +556 -139
- package/dist/mcp/taskPlanningRegistrar.js +64 -42
- package/dist/mcp/toolCallCompatibility.js +38 -1
- package/dist/mcp/toolCatalog.d.ts +1 -0
- package/dist/mcp/toolProfiles.d.ts +2 -0
- package/dist/mcp/toolProfiles.js +10 -0
- package/dist/mcp/toolRegistry.d.ts +1 -0
- package/dist/mcp/toolRegistry.js +1 -0
- package/dist/mcp/workflowExecutionRegistrar.js +4 -4
- package/dist/migrations/taskSchemaMigrations.d.ts +5 -0
- package/dist/migrations/taskSchemaMigrations.js +427 -0
- package/dist/runtime/appGateDefinitions.d.ts +30 -6
- package/dist/runtime/appGateDefinitions.js +6 -6
- package/dist/runtime/appGates.d.ts +13 -13
- package/dist/runtime/appGates.js +36 -13
- package/dist/runtime/nodeAppGates.d.ts +8 -0
- package/dist/runtime/nodeAppGates.js +27 -0
- package/dist/server/cloudCollectionRead.d.ts +1 -1
- package/dist/server/cloudCollectionRead.js +2 -2
- package/dist/server/index.d.ts +6 -0
- package/dist/server/index.js +123 -14
- package/dist/server/localDatabaseIdentity.js +4 -1
- package/dist/server/localServiceLease.d.ts +3 -0
- package/dist/server/localServiceLease.js +11 -2
- package/dist/server/localServiceSessions.d.ts +14 -17
- package/dist/server/localServiceSessions.js +308 -94
- package/dist/server/localWorkspaceSyncServerRuntime.js +12 -7
- package/dist/server/rateLimit.d.ts +1 -0
- package/dist/server/rateLimit.js +4 -0
- package/dist/server/realtimeSyncWs.js +36 -12
- package/dist/server/routes/admin.d.ts +4 -0
- package/dist/server/routes/admin.js +113 -3
- package/dist/server/routes/agentRoles.js +3 -2
- package/dist/server/routes/agentSkills.js +3 -2
- package/dist/server/routes/agents.d.ts +7 -0
- package/dist/server/routes/agents.js +394 -39
- package/dist/server/routes/annotatedAttachments.js +3 -2
- package/dist/server/routes/auth.js +3 -1
- package/dist/server/routes/billing.js +5 -1
- package/dist/server/routes/durableTaskHttpRouters.d.ts +11 -2
- package/dist/server/routes/executorPhaseAApprovals.d.ts +19 -0
- package/dist/server/routes/executorPhaseAApprovals.js +140 -0
- package/dist/server/routes/executorPhaseAIssuerRedemptions.d.ts +11 -0
- package/dist/server/routes/executorPhaseAIssuerRedemptions.js +24 -0
- package/dist/server/routes/githubReviewEvidence.d.ts +19 -0
- package/dist/server/routes/githubReviewEvidence.js +116 -0
- package/dist/server/routes/localService.d.ts +15 -4
- package/dist/server/routes/localService.js +138 -40
- package/dist/server/routes/modelConnections.d.ts +24 -0
- package/dist/server/routes/modelConnections.js +205 -0
- package/dist/server/routes/primitives.d.ts +2 -0
- package/dist/server/routes/shared.d.ts +19 -0
- package/dist/server/routes/shared.js +95 -19
- package/dist/server/routes/sync.js +1 -0
- package/dist/server/routes/syncAuxRoutes.js +9 -2
- package/dist/server/routes/syncPullApplyRoutes.js +23 -4
- package/dist/server/routes/syncPushRoutes.d.ts +1 -0
- package/dist/server/routes/syncPushRoutes.js +1 -0
- package/dist/server/routes/syncV3FeedRoutes.js +27 -16
- package/dist/server/routes/syncV3LocalCaptureRoutes.js +28 -2
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
- package/dist/server/routes/syncV3OperationRoutes.js +45 -9
- package/dist/server/routes/tasks.js +124 -13
- package/dist/server/routes/workflows.js +9 -1
- package/dist/server/routes/workspaces.js +43 -1
- package/dist/server/routes.js +59 -0
- package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
- package/dist/server/workspaceDeletionAdmission.js +50 -0
- package/dist/service/localServiceCli.js +16 -0
- package/dist/service/localServiceClientLifecycle.js +36 -10
- package/dist/services/codexAppServerModelGateway.d.ts +161 -0
- package/dist/services/codexAppServerModelGateway.js +663 -0
- package/dist/services/codexDeviceCodeLoginManager.d.ts +39 -0
- package/dist/services/codexDeviceCodeLoginManager.js +265 -0
- package/dist/services/codexModelProviderConnectionLifecycle.d.ts +8 -0
- package/dist/services/codexModelProviderConnectionLifecycle.js +73 -0
- package/dist/services/executorPhaseAApprovalRuntime.d.ts +14 -0
- package/dist/services/executorPhaseAApprovalRuntime.js +24 -0
- package/dist/services/executorPhaseAApprovalService.d.ts +40 -0
- package/dist/services/executorPhaseAApprovalService.js +609 -0
- package/dist/services/executorPhaseADriftEvaluator.d.ts +78 -0
- package/dist/services/executorPhaseADriftEvaluator.js +93 -0
- package/dist/services/executorPhaseAIssuerCore.d.ts +126 -0
- package/dist/services/executorPhaseAIssuerCore.js +295 -0
- package/dist/services/executorPhaseAIssuerRedemptionService.d.ts +34 -0
- package/dist/services/executorPhaseAIssuerRedemptionService.js +158 -0
- package/dist/services/githubReviewEvidenceRuntime.d.ts +14 -0
- package/dist/services/githubReviewEvidenceRuntime.js +30 -0
- package/dist/services/githubReviewEvidenceService.d.ts +93 -0
- package/dist/services/githubReviewEvidenceService.js +336 -0
- package/dist/services/modelGateway.d.ts +7 -0
- package/dist/services/modelProviderConnectionService.d.ts +71 -0
- package/dist/services/modelProviderConnectionService.js +279 -0
- package/dist/services/modelProviderCredentialHome.d.ts +32 -0
- package/dist/services/modelProviderCredentialHome.js +271 -0
- package/dist/services/ownerScopedModelConnectionGateway.d.ts +12 -0
- package/dist/services/ownerScopedModelConnectionGateway.js +30 -0
- package/dist/services/taskforceAgentConnectionBindingService.d.ts +66 -0
- package/dist/services/taskforceAgentConnectionBindingService.js +185 -0
- package/dist/services/taskforceAgentMcpBridge.d.ts +8 -2
- package/dist/services/taskforceAgentMcpBridge.js +30 -27
- package/dist/shared/adminEdgeProxy.d.ts +5 -0
- package/dist/shared/adminEdgeProxy.js +94 -0
- package/dist/shared/adminProxySessionCookies.d.ts +16 -0
- package/dist/shared/adminProxySessionCookies.js +86 -0
- package/dist/shared/aiProfileColors.d.ts +31 -1
- package/dist/shared/aiProfileColors.js +14 -6
- package/dist/shared/executorPhaseAApprovalGoldenVector.json +269 -0
- package/dist/shared/executorPhaseAApprovalReceipt.d.ts +112 -0
- package/dist/shared/executorPhaseAApprovalReceipt.js +58 -0
- package/dist/shared/executorPhaseAApprovalTrustPolicy.json +10 -0
- package/dist/shared/executorPhaseADriftContracts.d.ts +37 -0
- package/dist/shared/executorPhaseADriftContracts.js +63 -0
- package/dist/shared/executorPhaseAIssuerContracts.d.ts +75 -0
- package/dist/shared/executorPhaseAIssuerContracts.js +90 -0
- package/dist/shared/executorPhaseARunAuthorization.d.ts +120 -0
- package/dist/shared/executorPhaseARunAuthorization.js +232 -0
- package/dist/shared/executorPhaseASchemaValidation.d.ts +7 -0
- package/dist/shared/executorPhaseASchemaValidation.js +53 -0
- package/dist/shared/executorPhaseASchemas/approval-receipt.schema.json +106 -0
- package/dist/shared/executorPhaseASchemas/drift-attestation.schema.json +54 -0
- package/dist/shared/executorPhaseASchemas/drift-request.schema.json +47 -0
- package/dist/shared/executorPhaseASchemas/foundation-manifest.schema.json +29 -0
- package/dist/shared/executorPhaseASchemas/issuer-audit-record.schema.json +24 -0
- package/dist/shared/executorPhaseASchemas/issuer-proof.schema.json +43 -0
- package/dist/shared/executorPhaseASchemas/issuer-redemption-request.schema.json +18 -0
- package/dist/shared/executorPhaseASchemas/issuer-redemption-response.schema.json +39 -0
- package/dist/shared/executorPhaseASchemas/logical-envelope.schema.json +149 -0
- package/dist/shared/executorPhaseASchemas/preflight-report.schema.json +216 -0
- package/dist/shared/executorPhaseASchemas/run-capability.schema.json +111 -0
- package/dist/shared/executorPhaseASchemas/sender-proof.schema.json +37 -0
- package/dist/shared/executorPhaseASchemas/workload-grant.schema.json +68 -0
- package/dist/shared/executorPhaseASchemas/workload-jwt-claims.schema.json +67 -0
- package/dist/shared/executorPhaseATiming.d.ts +1 -0
- package/dist/shared/executorPhaseATiming.js +1 -0
- package/dist/shared/planningIdentity.js +1 -1
- package/dist/shared/productLogoKeys.d.ts +2 -0
- package/dist/shared/productLogoKeys.js +18 -0
- package/dist/shared/taskforceAgentDefinition.d.ts +0 -1
- package/dist/shared/taskforceAgentDefinition.js +6 -3
- package/dist/shared/taskforceAgentModels.d.ts +1 -0
- package/dist/shared/taskforceAgentModels.js +36 -3
- package/dist/shared/userFeatureGrants.d.ts +4 -0
- package/dist/shared/userFeatureGrants.js +7 -0
- package/dist/storage/executorPhaseAApprovalReceiptStore.d.ts +37 -0
- package/dist/storage/executorPhaseAApprovalReceiptStore.js +81 -0
- package/dist/storage/executorPhaseARunAuthorizationStore.d.ts +103 -0
- package/dist/storage/executorPhaseARunAuthorizationStore.js +492 -0
- package/dist/storage/githubReviewEvidenceInstallationStore.d.ts +26 -0
- package/dist/storage/githubReviewEvidenceInstallationStore.js +89 -0
- package/dist/storage/modelProviderConnectionStore.d.ts +99 -0
- package/dist/storage/modelProviderConnectionStore.js +446 -0
- package/dist/storage/postgresAdapter.d.ts +24 -3
- package/dist/storage/postgresAdapter.js +117 -14
- package/dist/storage/postgresWorker.js +22 -5
- package/dist/storage/postgresWorkerProtocol.d.ts +30 -0
- package/dist/storage/postgresWorkerProtocol.js +30 -0
- package/dist/storage/taskforceAgentConnectionBindingStore.d.ts +31 -0
- package/dist/storage/taskforceAgentConnectionBindingStore.js +84 -0
- package/dist/sync/cloudSyncApi.d.ts +4 -1
- package/dist/sync/cloudSyncApi.js +7 -2
- package/dist/sync/contentSyncState.d.ts +1 -1
- package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +1 -0
- package/dist/sync/coordinator/localSyncExecutionPermitStore.js +67 -30
- package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.d.ts +10 -0
- package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.js +29 -0
- package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
- package/dist/sync/coordinator/localWorkspaceSyncRunnerState.d.ts +15 -1
- package/dist/sync/coordinator/localWorkspaceSyncRunnerState.js +99 -2
- package/dist/sync/coordinator/workspaceSyncCredentialBroker.d.ts +1 -0
- package/dist/sync/coordinator/workspaceSyncCredentialBroker.js +33 -4
- package/dist/sync/engine/workspaceSyncContentLifecycleAdapter.d.ts +2 -1
- package/dist/sync/engine/workspaceSyncContentVersionStore.d.ts +38 -0
- package/dist/sync/engine/workspaceSyncContentVersionStore.js +50 -1
- package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
- package/dist/sync/engine/workspaceSyncEngineLifecyclePolicy.js +6 -6
- package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
- package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
- package/dist/sync/engine/workspaceSyncEnginePushCompletion.d.ts +14 -0
- package/dist/sync/engine/workspaceSyncEnginePushCompletion.js +84 -0
- package/dist/sync/engine/workspaceSyncEngineRecovery.js +1 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +11 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
- package/dist/sync/engine/workspaceSyncEngineRuntime.d.ts +1 -0
- package/dist/sync/engine/workspaceSyncEngineRuntime.js +1 -0
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +31 -4
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +134 -43
- package/dist/sync/engine/workspaceSyncEngineServerSnapshotReader.js +6 -0
- package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineTransfers.js +11 -4
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.d.ts +1 -0
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +29 -0
- package/dist/sync/syncApplyHandlers.d.ts +2 -0
- package/dist/sync/syncApplyHandlers.js +10 -1
- package/dist/sync/syncService.d.ts +17 -0
- package/dist/sync/syncService.js +87 -19
- package/dist/sync/taskforceAgentSyncAuthorization.d.ts +16 -0
- package/dist/sync/taskforceAgentSyncAuthorization.js +20 -0
- package/dist/sync/v3/combinedFeedCapability.js +8 -0
- package/dist/sync/v3/durableInitiativeMutationRouter.js +18 -10
- package/dist/sync/v3/durableOperationReplay.d.ts +14 -0
- package/dist/sync/v3/durableOperationReplay.js +18 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +2 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +14 -1
- package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +4 -1
- package/dist/sync/v3/durableTaskChecklistMutationRouter.js +62 -15
- package/dist/sync/v3/durableTaskCommentMutationRouter.js +3 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +30 -8
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +37 -2
- package/dist/sync/v3/durableTaxonomyMutationRouter.js +5 -0
- package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.d.ts +11 -0
- package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.js +39 -10
- package/dist/sync/v3/durableWorkstreamMutationRouter.js +18 -10
- package/dist/sync/v3/durableWorkstreamTaskOrderMutationRouter.js +16 -5
- package/dist/sync/v3/localOutboxDispatchRuntime.js +2 -2
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +47 -7
- package/dist/sync/v3/localTaskChecklistOutboxHandler.js +16 -2
- package/dist/sync/v3/localTaskChecklistOutboxService.d.ts +4 -0
- package/dist/sync/v3/localTaskChecklistOutboxService.js +14 -1
- package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
- package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
- package/dist/sync/v3/localTaskMetadataClient.js +1 -0
- package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
- package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
- package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
- package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
- package/dist/sync/v3/localTaskStatusClient.js +6 -1
- package/dist/sync/v3/localTaskStatusOutboxService.d.ts +10 -0
- package/dist/sync/v3/localTaskStatusOutboxService.js +272 -24
- package/dist/sync/v3/syncDurabilityStore.d.ts +41 -0
- package/dist/sync/v3/syncDurabilityStore.js +199 -13
- package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +6 -4
- package/dist/sync/v3/taskAttachmentLinksMutationService.js +19 -10
- package/dist/sync/v3/taskChecklistMutationService.d.ts +15 -2
- package/dist/sync/v3/taskChecklistMutationService.js +48 -1
- package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
- package/dist/sync/v3/taskCreateMutationService.js +7 -4
- package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
- package/dist/sync/v3/taskMetadataMutationService.js +4 -0
- package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
- package/dist/sync/v3/taskRestoreMutationService.js +7 -4
- package/dist/sync/v3/taskStatusMutationService.d.ts +31 -1
- package/dist/sync/v3/taskStatusMutationService.js +123 -3
- package/dist/sync/v3/workflowAssignmentSync.d.ts +6 -0
- package/dist/sync/v3/workflowAssignmentSync.js +30 -0
- package/dist/sync/v3/workspaceSyncJournalReader.js +1 -1
- package/dist/sync/v3/workspaceSyncOperationRetentionService.d.ts +16 -0
- package/dist/sync/v3/workspaceSyncOperationRetentionService.js +83 -0
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +13 -3
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
- package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +18 -3
- package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +8 -3
- package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +51 -10
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +14 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +49 -25
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +13 -4
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +124 -57
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +20 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +106 -30
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +4 -1
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +34 -0
- package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +12 -0
- package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
- package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +5 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +55 -9
- package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.d.ts +17 -0
- package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.js +64 -0
- package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.js +33 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.js +8 -0
- package/dist/sync/workspacePullFeed.js +2 -1
- package/dist/sync/workspaceRepair.d.ts +8 -2
- package/dist/sync/workspaceRepair.js +222 -6
- package/dist/sync/workspaceSyncModel.d.ts +21 -0
- package/dist/sync/workspaceSyncModel.js +35 -7
- package/dist/sync/workspaceSyncState.d.ts +1 -0
- package/dist/sync/workspaceSyncV2SnapshotBuilder.d.ts +6 -0
- package/dist/sync/workspaceSyncV2SnapshotBuilder.js +5 -0
- package/dist/types.d.ts +47 -1
- package/dist/types.js +6 -0
- package/dist/ui/assets/AiIdentityRosterCard-OcSz1PkK.js +1 -0
- package/dist/ui/assets/AiProfilesModule-ByhYW5Xi.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTM6nIg_.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
- package/dist/ui/assets/{AssetTraySortControl-Kf1pelSy.js → AssetTraySortControl-DabEG8L4.js} +1 -1
- package/dist/ui/assets/{ContextAttachmentManager-B8boOs6Q.js → ContextAttachmentManager-Coa8yVGM.js} +2 -2
- package/dist/ui/assets/{DocumentWorkspace-DXH4XUsB.js → DocumentWorkspace-BB0qhdix.js} +1 -1
- package/dist/ui/assets/{EntityActivityTimeline-BtSTq0ON.js → EntityActivityTimeline-CZ8x4UJE.js} +1 -1
- package/dist/ui/assets/PlanningModule-pRPjR7v5.js +1 -0
- package/dist/ui/assets/PlansPage-D86pZSSl.js +1 -0
- package/dist/ui/assets/TaskContextUpload-BVIkU9yT.js +1 -0
- package/dist/ui/assets/TaskSettings-Cv1mNhv_.js +12 -0
- package/dist/ui/assets/TaskforceAgentsModule-b-8R25cJ.css +1 -0
- package/dist/ui/assets/TaskforceAgentsModule-gmH-PD2q.js +24 -0
- package/dist/ui/assets/{WorkflowManagerModule-DWFspC-o.js → WorkflowManagerModule-DbfnHJ-f.js} +1 -1
- package/dist/ui/assets/index-BZ-hdZSk.css +1 -0
- package/dist/ui/assets/index-CTsDBaef.js +7 -0
- package/dist/ui/assets/{vendor-icons-BkFLXavV.js → vendor-icons-Bsq-mcEn.js} +1 -1
- package/dist/ui/branding/logos/letterhead_dark.png +0 -0
- package/dist/ui/branding/logos/letterhead_light.png +0 -0
- package/dist/ui/branding/logos/signature_dark.png +0 -0
- package/dist/ui/branding/logos/signature_light.png +0 -0
- package/dist/ui/index.html +3 -3
- package/dist/utils/aiProfileDefaultLogo.js +16 -48
- package/dist/utils/httpSetCookie.d.ts +1 -0
- package/dist/utils/httpSetCookie.js +4 -1
- package/dist/utils/localRuntimeUrl.d.ts +1 -0
- package/dist/utils/localRuntimeUrl.js +14 -0
- package/dist/utils/productLogoRegistry.d.ts +2 -0
- package/dist/utils/productLogoRegistry.js +36 -0
- package/dist/utils/syncStatusPresentation.d.ts +4 -0
- package/dist/utils/syncStatusPresentation.js +17 -0
- package/dist/utils/taskActivity.d.ts +3 -2
- package/dist/utils/taskActivity.js +19 -2
- package/dist/utils/taskEditorReconciliation.d.ts +40 -0
- package/dist/utils/taskEditorReconciliation.js +217 -0
- package/dist/utils/taskEvents.d.ts +2 -0
- package/dist/utils/taskNormalization.d.ts +1 -0
- package/dist/utils/taskNormalization.js +39 -0
- package/dist/utils/taskSearch.js +2 -2
- package/dist/utils/uiNotice.d.ts +4 -0
- package/dist/utils/workspaceSyncPresentation.d.ts +1 -1
- package/dist/utils/workspaceSyncPresentation.js +23 -17
- package/package.json +36 -6
- package/dist/ui/assets/AiIdentityRosterCard-MZs7lVED.js +0 -1
- package/dist/ui/assets/AiProfilesModule-C3i0LOxe.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-DVZk5Tln.js +0 -3
- package/dist/ui/assets/PlanningModule-BPVyEa-f.js +0 -1
- package/dist/ui/assets/PlansPage-ChqgxALc.js +0 -1
- package/dist/ui/assets/TaskContextUpload-CB3ol0sN.js +0 -1
- package/dist/ui/assets/TaskSettings-g4ECKNOz.js +0 -12
- package/dist/ui/assets/TaskforceAgentsModule-BazdUwxZ.js +0 -21
- package/dist/ui/assets/TaskforceAgentsModule-D6IC0S7Q.css +0 -1
- package/dist/ui/assets/index-BUplSsv_.js +0 -7
- package/dist/ui/assets/index-gz2EXuoK.css +0 -1
|
@@ -1,17 +1,65 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { JSONRPCMessageSchema } from '@modelcontextprotocol/core';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
|
|
4
4
|
import { normalizeMcpConnectionId, parseMcpClientId } from './clientRegistry.js';
|
|
5
5
|
import { normalizeMcpToolProfile } from './toolProfiles.js';
|
|
6
|
+
import { MCP_TOOL_REGISTRY, MCP_WRITE_TOOL_NAMES } from './toolRegistry.js';
|
|
6
7
|
import { localServiceCloudTargetsEqual, parseLocalServiceCloudTarget, } from '../config/localServiceCloudTarget.js';
|
|
7
8
|
import { discoverOrStartLocalService, LOCAL_SERVICE_API_BASE_PATH, LOCAL_SERVICE_PROTOCOL_VERSION, } from '../service/localServiceClientLifecycle.js';
|
|
8
9
|
const REQUEST_TIMEOUT_MS = 120_000;
|
|
9
10
|
const MAX_IN_FLIGHT = 32;
|
|
11
|
+
const RECOVERY_FAILURE_COOLDOWN_MS = 250;
|
|
12
|
+
const RECOVERY_TRANSITION_ATTEMPTS = 150;
|
|
13
|
+
const RECOVERY_TRANSITION_POLL_MS = 100;
|
|
14
|
+
const RECOVERY_TRANSITION_TIMEOUT_MS = 15_000;
|
|
10
15
|
const MCP_PROTOCOL_ERROR = -32_000;
|
|
11
16
|
const MCP_REQUEST_CANCELLED = -32_800;
|
|
17
|
+
const KNOWN_READ_METHODS = new Set([
|
|
18
|
+
'initialize',
|
|
19
|
+
'ping',
|
|
20
|
+
'server/discover',
|
|
21
|
+
'tools/list',
|
|
22
|
+
'resources/list',
|
|
23
|
+
'resources/templates/list',
|
|
24
|
+
'resources/read',
|
|
25
|
+
'prompts/list',
|
|
26
|
+
'prompts/get',
|
|
27
|
+
'completion/complete',
|
|
28
|
+
]);
|
|
29
|
+
const RECOVERABLE_CONNECTION_CODES = new Set([
|
|
30
|
+
'GENERATION_MISMATCH',
|
|
31
|
+
'RUNTIME_CONTRACT_MISMATCH',
|
|
32
|
+
'SESSION_INVALID',
|
|
33
|
+
'SESSION_NOT_FOUND',
|
|
34
|
+
'SESSION_AUTH_REQUIRED',
|
|
35
|
+
'SERVICE_QUIESCING',
|
|
36
|
+
]);
|
|
12
37
|
function timeoutSignal(timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
13
38
|
return AbortSignal.timeout(timeoutMs);
|
|
14
39
|
}
|
|
40
|
+
function waitWithinRecoveryDeadline(operation, signal, deadlineAt) {
|
|
41
|
+
const remainingMs = deadlineAt - Date.now();
|
|
42
|
+
if (signal.aborted)
|
|
43
|
+
return Promise.reject(new Error('Taskforce MCP proxy recovery was stopped.'));
|
|
44
|
+
if (remainingMs <= 0)
|
|
45
|
+
return Promise.reject(new Error('Taskforce shared local service recovery timed out.'));
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
let settled = false;
|
|
48
|
+
const finish = (callback) => {
|
|
49
|
+
if (settled)
|
|
50
|
+
return;
|
|
51
|
+
settled = true;
|
|
52
|
+
clearTimeout(timer);
|
|
53
|
+
signal.removeEventListener('abort', onAbort);
|
|
54
|
+
callback();
|
|
55
|
+
};
|
|
56
|
+
const onAbort = () => finish(() => reject(new Error('Taskforce MCP proxy recovery was stopped.')));
|
|
57
|
+
const timer = setTimeout(() => finish(() => reject(new Error('Taskforce shared local service recovery timed out.'))), remainingMs);
|
|
58
|
+
timer.unref?.();
|
|
59
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
60
|
+
operation.then((value) => finish(() => resolve(value)), (error) => finish(() => reject(error)));
|
|
61
|
+
});
|
|
62
|
+
}
|
|
15
63
|
async function readJson(response, label) {
|
|
16
64
|
const text = await response.text();
|
|
17
65
|
if (!response.ok) {
|
|
@@ -24,6 +72,117 @@ async function readJson(response, label) {
|
|
|
24
72
|
throw new Error(`${label} returned invalid JSON.`);
|
|
25
73
|
}
|
|
26
74
|
}
|
|
75
|
+
function encodeMcpHeaderValue(value) {
|
|
76
|
+
const safeAscii = value.length > 0
|
|
77
|
+
&& value === value.trim()
|
|
78
|
+
&& !(value.startsWith('=?base64?') && value.endsWith('?='))
|
|
79
|
+
&& [...value].every((character) => {
|
|
80
|
+
const codePoint = character.codePointAt(0) || 0;
|
|
81
|
+
return codePoint === 9 || (codePoint >= 32 && codePoint <= 126);
|
|
82
|
+
});
|
|
83
|
+
return safeAscii
|
|
84
|
+
? value
|
|
85
|
+
: `=?base64?${Buffer.from(value, 'utf8').toString('base64')}?=`;
|
|
86
|
+
}
|
|
87
|
+
function modernRequestHeaders(message) {
|
|
88
|
+
if (!('method' in message) || !('id' in message))
|
|
89
|
+
return {};
|
|
90
|
+
const params = message.params;
|
|
91
|
+
const meta = params?._meta;
|
|
92
|
+
const version = meta?.['io.modelcontextprotocol/protocolVersion'];
|
|
93
|
+
if (typeof version !== 'string')
|
|
94
|
+
return {};
|
|
95
|
+
const name = message.method === 'resources/read'
|
|
96
|
+
? params?.uri
|
|
97
|
+
: params?.name;
|
|
98
|
+
return {
|
|
99
|
+
'mcp-protocol-version': version,
|
|
100
|
+
'mcp-method': message.method,
|
|
101
|
+
...(typeof name === 'string' ? { 'mcp-name': encodeMcpHeaderValue(name) } : {}),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function parseMcpRelayMessage(value) {
|
|
105
|
+
return JSONRPCMessageSchema.parse(value);
|
|
106
|
+
}
|
|
107
|
+
function parseSseFrame(frame) {
|
|
108
|
+
const data = frame
|
|
109
|
+
.split(/\r?\n/)
|
|
110
|
+
.filter((line) => line.startsWith('data:'))
|
|
111
|
+
.map((line) => line.slice(5).trimStart())
|
|
112
|
+
.join('\n');
|
|
113
|
+
return data ? parseMcpRelayMessage(JSON.parse(data)) : null;
|
|
114
|
+
}
|
|
115
|
+
async function* readMcpRelayMessages(response) {
|
|
116
|
+
const contentType = String(response.headers.get('content-type') || '').toLowerCase();
|
|
117
|
+
if (!contentType.includes('text/event-stream')) {
|
|
118
|
+
const text = await response.text();
|
|
119
|
+
let values;
|
|
120
|
+
try {
|
|
121
|
+
const body = JSON.parse(text);
|
|
122
|
+
values = Array.isArray(body) ? body : [body];
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
if (!response.ok)
|
|
126
|
+
throw new Error(`MCP relay failed (${response.status}): ${text.slice(0, 500)}`);
|
|
127
|
+
throw new Error('MCP relay returned an invalid JSON-RPC response.');
|
|
128
|
+
}
|
|
129
|
+
if (values.length === 0)
|
|
130
|
+
throw new Error(`MCP relay returned no JSON-RPC messages (${response.status}).`);
|
|
131
|
+
for (const value of values)
|
|
132
|
+
yield parseMcpRelayMessage(value);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (!response.body)
|
|
136
|
+
throw new Error(`MCP relay returned no JSON-RPC messages (${response.status}).`);
|
|
137
|
+
const reader = response.body.getReader();
|
|
138
|
+
const decoder = new TextDecoder();
|
|
139
|
+
let buffer = '';
|
|
140
|
+
let sample = '';
|
|
141
|
+
let count = 0;
|
|
142
|
+
try {
|
|
143
|
+
while (true) {
|
|
144
|
+
const { value, done } = await reader.read();
|
|
145
|
+
if (value) {
|
|
146
|
+
const decoded = decoder.decode(value, { stream: true });
|
|
147
|
+
buffer += decoded;
|
|
148
|
+
if (sample.length < 500)
|
|
149
|
+
sample += decoded.slice(0, 500 - sample.length);
|
|
150
|
+
}
|
|
151
|
+
if (done)
|
|
152
|
+
buffer += decoder.decode();
|
|
153
|
+
let boundary = buffer.match(/\r?\n\r?\n/);
|
|
154
|
+
while (boundary?.index !== undefined) {
|
|
155
|
+
const frame = buffer.slice(0, boundary.index);
|
|
156
|
+
buffer = buffer.slice(boundary.index + boundary[0].length);
|
|
157
|
+
const message = parseSseFrame(frame);
|
|
158
|
+
if (message) {
|
|
159
|
+
count += 1;
|
|
160
|
+
yield message;
|
|
161
|
+
}
|
|
162
|
+
boundary = buffer.match(/\r?\n\r?\n/);
|
|
163
|
+
}
|
|
164
|
+
if (done)
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
const finalMessage = parseSseFrame(buffer);
|
|
168
|
+
if (finalMessage) {
|
|
169
|
+
count += 1;
|
|
170
|
+
yield finalMessage;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
if (!response.ok)
|
|
175
|
+
throw new Error(`MCP relay failed (${response.status}): ${sample.slice(0, 500)}`);
|
|
176
|
+
throw new Error('MCP relay returned an invalid JSON-RPC response.');
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
await reader.cancel().catch(() => undefined);
|
|
180
|
+
reader.releaseLock();
|
|
181
|
+
}
|
|
182
|
+
if (count === 0) {
|
|
183
|
+
throw new Error(`MCP relay returned no JSON-RPC messages (${response.status}).`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
27
186
|
function validateReadiness(readiness, descriptor) {
|
|
28
187
|
const readinessCloudTarget = parseLocalServiceCloudTarget(readiness.cloudTarget);
|
|
29
188
|
if (!readiness.ready)
|
|
@@ -52,13 +211,96 @@ function cancellationTarget(message) {
|
|
|
52
211
|
function idKey(id) {
|
|
53
212
|
return `${typeof id}:${String(id)}`;
|
|
54
213
|
}
|
|
55
|
-
function errorResponse(id, message, code, numericCode = MCP_PROTOCOL_ERROR) {
|
|
214
|
+
function errorResponse(id, message, code, numericCode = MCP_PROTOCOL_ERROR, data = {}) {
|
|
56
215
|
return {
|
|
57
216
|
jsonrpc: '2.0',
|
|
58
217
|
id,
|
|
59
|
-
error: { code: numericCode, message, data: { code } },
|
|
218
|
+
error: { code: numericCode, message, data: { code, ...data } },
|
|
60
219
|
};
|
|
61
220
|
}
|
|
221
|
+
function toolName(message) {
|
|
222
|
+
if (!('method' in message) || message.method !== 'tools/call')
|
|
223
|
+
return null;
|
|
224
|
+
const name = message.params?.name;
|
|
225
|
+
return typeof name === 'string' ? name : null;
|
|
226
|
+
}
|
|
227
|
+
function isKnownReadRequest(message) {
|
|
228
|
+
if (!('id' in message) || !('method' in message))
|
|
229
|
+
return false;
|
|
230
|
+
if (message.method === 'tools/call') {
|
|
231
|
+
const name = toolName(message);
|
|
232
|
+
return Boolean(name
|
|
233
|
+
&& Object.prototype.hasOwnProperty.call(MCP_TOOL_REGISTRY, name)
|
|
234
|
+
&& !MCP_WRITE_TOOL_NAMES.has(name));
|
|
235
|
+
}
|
|
236
|
+
return KNOWN_READ_METHODS.has(message.method);
|
|
237
|
+
}
|
|
238
|
+
function idempotencyKey(message) {
|
|
239
|
+
if (!('method' in message) || message.method !== 'tools/call')
|
|
240
|
+
return null;
|
|
241
|
+
const args = message.params?.arguments;
|
|
242
|
+
const value = args?.idempotencyKey ?? args?.operationKey;
|
|
243
|
+
return typeof value === 'string' && value.trim() ? value.trim() : null;
|
|
244
|
+
}
|
|
245
|
+
function requestProfileToken(message) {
|
|
246
|
+
if (!('method' in message) || message.method !== 'tools/call')
|
|
247
|
+
return null;
|
|
248
|
+
const args = message.params?.arguments;
|
|
249
|
+
const value = args?.profileToken;
|
|
250
|
+
return typeof value === 'string' && value.trim() ? value.trim() : null;
|
|
251
|
+
}
|
|
252
|
+
function responseProfileToken(message) {
|
|
253
|
+
if (!('result' in message) || !message.result || typeof message.result !== 'object')
|
|
254
|
+
return null;
|
|
255
|
+
const result = message.result;
|
|
256
|
+
if (result.isError === true)
|
|
257
|
+
return null;
|
|
258
|
+
const structuredToken = result.structuredContent?.profileToken;
|
|
259
|
+
if (typeof structuredToken === 'string' && structuredToken.trim())
|
|
260
|
+
return structuredToken.trim();
|
|
261
|
+
for (const item of result.content || []) {
|
|
262
|
+
if (item?.type !== 'text' || typeof item.text !== 'string')
|
|
263
|
+
continue;
|
|
264
|
+
try {
|
|
265
|
+
const parsed = JSON.parse(item.text);
|
|
266
|
+
if (typeof parsed?.profileToken === 'string' && parsed.profileToken.trim()) {
|
|
267
|
+
return parsed.profileToken.trim();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
// Tool text is not generally JSON. Only resolve_profile's structured text is relevant here.
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
function isSuccessfulToolResponse(message) {
|
|
277
|
+
if (!('result' in message) || !message.result || typeof message.result !== 'object')
|
|
278
|
+
return false;
|
|
279
|
+
return message.result.isError !== true;
|
|
280
|
+
}
|
|
281
|
+
function descriptorsIdentifySameService(left, right) {
|
|
282
|
+
return left.generation === right.generation
|
|
283
|
+
&& left.endpoint === right.endpoint
|
|
284
|
+
&& left.protocolVersion === right.protocolVersion;
|
|
285
|
+
}
|
|
286
|
+
function isModernRequest(message) {
|
|
287
|
+
if (!('method' in message))
|
|
288
|
+
return false;
|
|
289
|
+
const meta = message.params?._meta;
|
|
290
|
+
return meta?.['io.modelcontextprotocol/protocolVersion'] === '2026-07-28';
|
|
291
|
+
}
|
|
292
|
+
async function recoverableResponseCode(response) {
|
|
293
|
+
if (![401, 409, 503].includes(response.status))
|
|
294
|
+
return null;
|
|
295
|
+
try {
|
|
296
|
+
const body = await response.clone().json();
|
|
297
|
+
const code = typeof body?.code === 'string' ? body.code : '';
|
|
298
|
+
return RECOVERABLE_CONNECTION_CODES.has(code) ? code : null;
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
62
304
|
export async function startLocalServiceMcpProxy(options) {
|
|
63
305
|
const env = options.env || process.env;
|
|
64
306
|
const configuredSharedService = String(env.TASKFORCE_SHARED_LOCAL_MCP_ENABLED || '').trim();
|
|
@@ -91,51 +333,164 @@ export async function startLocalServiceMcpProxy(options) {
|
|
|
91
333
|
if (!Number.isFinite(requestTimeoutMs) || requestTimeoutMs < 1)
|
|
92
334
|
throw new Error('Local MCP proxy requestTimeoutMs must be positive.');
|
|
93
335
|
const fetchFn = options.fetch || fetch;
|
|
94
|
-
const
|
|
336
|
+
const discover = options.discover || discoverOrStartLocalService;
|
|
337
|
+
const sleep = options.sleep || ((delayMs) => new Promise((resolve) => setTimeout(resolve, delayMs)));
|
|
338
|
+
let privateProfileToken = String(env.TASKFORCE_AI_PROFILE_TOKEN || '').trim() || undefined;
|
|
339
|
+
const discoverDescriptor = () => discover({
|
|
95
340
|
projectRoot: options.projectRoot,
|
|
96
341
|
env,
|
|
97
342
|
executablePath: options.executablePath,
|
|
98
343
|
cliEntryPath: options.cliEntryPath,
|
|
99
344
|
execArgv: options.execArgv,
|
|
100
345
|
});
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
346
|
+
const registerConnection = async (descriptor, recoverySignal) => {
|
|
347
|
+
const registrationSignal = recoverySignal
|
|
348
|
+
? AbortSignal.any([recoverySignal, timeoutSignal()])
|
|
349
|
+
: timeoutSignal();
|
|
350
|
+
const readiness = await readJson(await fetchFn(`${descriptor.endpoint}${LOCAL_SERVICE_API_BASE_PATH}/readiness`, { signal: registrationSignal }), 'Local service readiness');
|
|
351
|
+
validateReadiness(readiness, descriptor);
|
|
352
|
+
const registration = await readJson(await fetchFn(`${descriptor.endpoint}${LOCAL_SERVICE_API_BASE_PATH}/sessions`, {
|
|
353
|
+
method: 'POST',
|
|
354
|
+
headers: {
|
|
355
|
+
'content-type': 'application/json',
|
|
356
|
+
'x-taskforce-local-service-capability': descriptor.bootstrapCapability,
|
|
357
|
+
},
|
|
358
|
+
body: JSON.stringify({
|
|
359
|
+
clientId,
|
|
360
|
+
connectionInstance,
|
|
361
|
+
workspaceId,
|
|
362
|
+
permissions: ['tasks:read', 'tasks:write', 'workspace:read'],
|
|
363
|
+
toolProfile,
|
|
364
|
+
protocolVersion: descriptor.protocolVersion,
|
|
365
|
+
generation: descriptor.generation,
|
|
366
|
+
profileToken: privateProfileToken,
|
|
367
|
+
}),
|
|
368
|
+
signal: registrationSignal,
|
|
369
|
+
}), 'Local service session registration');
|
|
370
|
+
if (!registration.session?.id || !registration.bearerToken) {
|
|
371
|
+
throw new Error('Local service session registration returned an invalid response.');
|
|
372
|
+
}
|
|
373
|
+
return { descriptor, registration };
|
|
374
|
+
};
|
|
375
|
+
const establishConnection = async () => (registerConnection(await discoverDescriptor()));
|
|
376
|
+
let connection = await establishConnection();
|
|
377
|
+
let terminal = false;
|
|
378
|
+
let recoveryState = null;
|
|
379
|
+
let lastRecoveryFailure = null;
|
|
380
|
+
let closing = false;
|
|
381
|
+
const recoveryIntentFor = (recoveryCode) => {
|
|
382
|
+
if (recoveryCode === null)
|
|
383
|
+
return 'probe';
|
|
384
|
+
if (recoveryCode === 'SESSION_INVALID' || recoveryCode === 'SESSION_NOT_FOUND') {
|
|
385
|
+
return 'register-current';
|
|
386
|
+
}
|
|
387
|
+
return 'replacement';
|
|
388
|
+
};
|
|
389
|
+
const raiseRecoveryIntent = (current, requested) => {
|
|
390
|
+
const priority = { probe: 0, 'register-current': 1, replacement: 2 };
|
|
391
|
+
return priority[requested] > priority[current] ? requested : current;
|
|
392
|
+
};
|
|
393
|
+
const recoverConnection = (failedConnection, recoveryCode) => {
|
|
394
|
+
if (closing || terminal)
|
|
395
|
+
return Promise.reject(new Error('Taskforce MCP proxy is closed.'));
|
|
396
|
+
if (connection !== failedConnection)
|
|
397
|
+
return Promise.resolve(connection);
|
|
398
|
+
const requestedIntent = recoveryIntentFor(recoveryCode);
|
|
399
|
+
if (recoveryState) {
|
|
400
|
+
recoveryState.intent = raiseRecoveryIntent(recoveryState.intent, requestedIntent);
|
|
401
|
+
return recoveryState.promise.then((replacement) => {
|
|
402
|
+
if (requestedIntent !== 'probe'
|
|
403
|
+
&& descriptorsIdentifySameService(replacement.descriptor, failedConnection.descriptor)) {
|
|
404
|
+
return recoverConnection(failedConnection, recoveryCode);
|
|
405
|
+
}
|
|
406
|
+
return replacement;
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
if (lastRecoveryFailure?.connection === failedConnection
|
|
410
|
+
&& Date.now() - lastRecoveryFailure.at < RECOVERY_FAILURE_COOLDOWN_MS) {
|
|
411
|
+
return Promise.reject(lastRecoveryFailure.error);
|
|
412
|
+
}
|
|
413
|
+
const state = {
|
|
414
|
+
controller: new AbortController(),
|
|
415
|
+
intent: requestedIntent,
|
|
416
|
+
promise: Promise.resolve(failedConnection),
|
|
417
|
+
};
|
|
418
|
+
recoveryState = state;
|
|
419
|
+
const deadlineAt = Date.now() + Math.min(requestTimeoutMs, RECOVERY_TRANSITION_TIMEOUT_MS);
|
|
420
|
+
const recoveryDeadlineTimer = setTimeout(() => state.controller.abort(), Math.max(1, deadlineAt - Date.now()));
|
|
421
|
+
recoveryDeadlineTimer.unref?.();
|
|
422
|
+
state.promise = (async () => {
|
|
423
|
+
let lastError = null;
|
|
424
|
+
for (let attempt = 0; attempt < RECOVERY_TRANSITION_ATTEMPTS; attempt += 1) {
|
|
425
|
+
if (closing || terminal || state.controller.signal.aborted) {
|
|
426
|
+
throw new Error('Taskforce MCP proxy is closed.');
|
|
427
|
+
}
|
|
428
|
+
let candidate;
|
|
429
|
+
try {
|
|
430
|
+
candidate = await waitWithinRecoveryDeadline(discoverDescriptor(), state.controller.signal, deadlineAt);
|
|
431
|
+
}
|
|
432
|
+
catch (error) {
|
|
433
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
434
|
+
if (Date.now() >= deadlineAt || state.controller.signal.aborted)
|
|
435
|
+
throw lastError;
|
|
436
|
+
if (attempt + 1 < RECOVERY_TRANSITION_ATTEMPTS) {
|
|
437
|
+
await waitWithinRecoveryDeadline(sleep(RECOVERY_TRANSITION_POLL_MS), state.controller.signal, deadlineAt);
|
|
438
|
+
}
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
if (!descriptorsIdentifySameService(candidate, failedConnection.descriptor)) {
|
|
442
|
+
return await waitWithinRecoveryDeadline(registerConnection(candidate, state.controller.signal), state.controller.signal, deadlineAt);
|
|
443
|
+
}
|
|
444
|
+
if (state.intent === 'probe')
|
|
445
|
+
return failedConnection;
|
|
446
|
+
if (state.intent === 'register-current') {
|
|
447
|
+
return await waitWithinRecoveryDeadline(registerConnection(candidate, state.controller.signal), state.controller.signal, deadlineAt);
|
|
448
|
+
}
|
|
449
|
+
if (attempt + 1 < RECOVERY_TRANSITION_ATTEMPTS) {
|
|
450
|
+
await waitWithinRecoveryDeadline(sleep(RECOVERY_TRANSITION_POLL_MS), state.controller.signal, deadlineAt);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
throw lastError || new Error('Taskforce shared local service replacement did not become ready.');
|
|
454
|
+
})()
|
|
455
|
+
.then((replacement) => {
|
|
456
|
+
connection = replacement;
|
|
457
|
+
lastRecoveryFailure = null;
|
|
458
|
+
return replacement;
|
|
459
|
+
})
|
|
460
|
+
.catch((error) => {
|
|
461
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
462
|
+
lastRecoveryFailure = { connection: failedConnection, error: normalized, at: Date.now() };
|
|
463
|
+
throw normalized;
|
|
464
|
+
})
|
|
465
|
+
.finally(() => {
|
|
466
|
+
clearTimeout(recoveryDeadlineTimer);
|
|
467
|
+
if (recoveryState === state)
|
|
468
|
+
recoveryState = null;
|
|
469
|
+
});
|
|
470
|
+
return state.promise;
|
|
471
|
+
};
|
|
124
472
|
const stdio = new StdioServerTransport(options.stdin, options.stdout);
|
|
125
473
|
const requests = new Map();
|
|
126
474
|
const inFlight = new Set();
|
|
127
475
|
let protocolVersion = null;
|
|
128
476
|
let initializeRequestId = null;
|
|
129
|
-
let terminal = false;
|
|
130
477
|
let closePromise = null;
|
|
131
478
|
let sendChain = Promise.resolve();
|
|
132
479
|
const send = (message) => {
|
|
133
480
|
sendChain = sendChain.then(() => stdio.send(message));
|
|
134
481
|
return sendChain;
|
|
135
482
|
};
|
|
483
|
+
const revokeConnection = async (target) => {
|
|
484
|
+
await fetchFn(`${target.descriptor.endpoint}${LOCAL_SERVICE_API_BASE_PATH}/sessions/${encodeURIComponent(target.registration.session.id)}`, {
|
|
485
|
+
method: 'DELETE',
|
|
486
|
+
headers: { authorization: `Bearer ${target.registration.bearerToken}` },
|
|
487
|
+
signal: timeoutSignal(2_000),
|
|
488
|
+
}).then((response) => response.body?.cancel()).catch(() => undefined);
|
|
489
|
+
};
|
|
136
490
|
const failTerminal = async (error, id) => {
|
|
137
491
|
if (terminal)
|
|
138
492
|
return;
|
|
493
|
+
const pendingRecovery = recoveryState?.promise || null;
|
|
139
494
|
terminal = true;
|
|
140
495
|
for (const pending of inFlight)
|
|
141
496
|
pending.controller.abort();
|
|
@@ -145,8 +500,58 @@ export async function startLocalServiceMcpProxy(options) {
|
|
|
145
500
|
else {
|
|
146
501
|
(options.logError || console.error)(`[Taskforce MCP proxy] ${error.message}`);
|
|
147
502
|
}
|
|
503
|
+
await pendingRecovery?.catch(() => undefined);
|
|
504
|
+
await revokeConnection(connection);
|
|
148
505
|
options.onFatal?.(error);
|
|
149
506
|
};
|
|
507
|
+
const relayOnce = async (message, target, state, cancelCorrelation) => {
|
|
508
|
+
const response = await fetchFn(`${target.descriptor.endpoint}/mcp`, {
|
|
509
|
+
method: 'POST',
|
|
510
|
+
headers: {
|
|
511
|
+
authorization: `Bearer ${target.registration.bearerToken}`,
|
|
512
|
+
'content-type': 'application/json',
|
|
513
|
+
accept: 'application/json, text/event-stream',
|
|
514
|
+
...(protocolVersion ? { 'mcp-protocol-version': protocolVersion } : {}),
|
|
515
|
+
...modernRequestHeaders(message),
|
|
516
|
+
'x-taskforce-mcp-request-correlation': state.correlationId,
|
|
517
|
+
...(cancelCorrelation ? { 'x-taskforce-mcp-cancel-correlation': cancelCorrelation } : {}),
|
|
518
|
+
},
|
|
519
|
+
body: JSON.stringify(message),
|
|
520
|
+
signal: state.controller.signal,
|
|
521
|
+
});
|
|
522
|
+
const recoveryCode = await recoverableResponseCode(response);
|
|
523
|
+
if (recoveryCode) {
|
|
524
|
+
await response.body?.cancel();
|
|
525
|
+
return recoveryCode;
|
|
526
|
+
}
|
|
527
|
+
if (response.status === 202) {
|
|
528
|
+
await response.body?.cancel();
|
|
529
|
+
return null;
|
|
530
|
+
}
|
|
531
|
+
for await (const responseMessage of readMcpRelayMessages(response)) {
|
|
532
|
+
if (initializeRequestId !== null
|
|
533
|
+
&& requestId(responseMessage) === initializeRequestId
|
|
534
|
+
&& 'result' in responseMessage
|
|
535
|
+
&& typeof responseMessage.result?.protocolVersion === 'string') {
|
|
536
|
+
protocolVersion = responseMessage.result.protocolVersion;
|
|
537
|
+
}
|
|
538
|
+
if (requestId(responseMessage) === requestId(message)) {
|
|
539
|
+
state.responseDelivered = true;
|
|
540
|
+
if (isSuccessfulToolResponse(responseMessage)) {
|
|
541
|
+
const suppliedProfileToken = requestProfileToken(message);
|
|
542
|
+
if (toolName(message) === 'resolve_profile') {
|
|
543
|
+
privateProfileToken = responseProfileToken(responseMessage)
|
|
544
|
+
|| suppliedProfileToken
|
|
545
|
+
|| privateProfileToken;
|
|
546
|
+
}
|
|
547
|
+
else if (suppliedProfileToken)
|
|
548
|
+
privateProfileToken = suppliedProfileToken;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
await send(responseMessage);
|
|
552
|
+
}
|
|
553
|
+
return null;
|
|
554
|
+
};
|
|
150
555
|
const forward = async (message) => {
|
|
151
556
|
const id = requestId(message);
|
|
152
557
|
if (terminal) {
|
|
@@ -173,7 +578,7 @@ export async function startLocalServiceMcpProxy(options) {
|
|
|
173
578
|
}
|
|
174
579
|
const controller = new AbortController();
|
|
175
580
|
const key = id === null ? null : idKey(id);
|
|
176
|
-
const state = { controller, cancelled: false, correlationId: randomUUID() };
|
|
581
|
+
const state = { controller, cancelled: false, correlationId: randomUUID(), responseDelivered: false };
|
|
177
582
|
const requestTimer = setTimeout(() => controller.abort(), requestTimeoutMs);
|
|
178
583
|
requestTimer.unref?.();
|
|
179
584
|
inFlight.add(state);
|
|
@@ -181,41 +586,94 @@ export async function startLocalServiceMcpProxy(options) {
|
|
|
181
586
|
requests.set(key, state);
|
|
182
587
|
if ('method' in message && message.method === 'initialize' && id !== null)
|
|
183
588
|
initializeRequestId = id;
|
|
589
|
+
let attemptedConnection = connection;
|
|
590
|
+
let retried = false;
|
|
591
|
+
let definitivelyRejected = false;
|
|
184
592
|
try {
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
...(cancelCorrelation ? { 'x-taskforce-mcp-cancel-correlation': cancelCorrelation } : {}),
|
|
194
|
-
},
|
|
195
|
-
body: JSON.stringify(message),
|
|
196
|
-
signal: controller.signal,
|
|
197
|
-
});
|
|
198
|
-
if (response.status === 202) {
|
|
199
|
-
await response.body?.cancel();
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
const body = await readJson(response, 'MCP relay');
|
|
203
|
-
const messages = (Array.isArray(body) ? body : [body]).map((value) => JSONRPCMessageSchema.parse(value));
|
|
204
|
-
for (const responseMessage of messages) {
|
|
205
|
-
if (initializeRequestId !== null
|
|
206
|
-
&& requestId(responseMessage) === initializeRequestId
|
|
207
|
-
&& 'result' in responseMessage
|
|
208
|
-
&& typeof responseMessage.result?.protocolVersion === 'string') {
|
|
209
|
-
protocolVersion = responseMessage.result.protocolVersion;
|
|
593
|
+
const recoveryCode = await relayOnce(message, attemptedConnection, state, cancelCorrelation);
|
|
594
|
+
if (recoveryCode) {
|
|
595
|
+
definitivelyRejected = true;
|
|
596
|
+
attemptedConnection = await recoverConnection(attemptedConnection, recoveryCode);
|
|
597
|
+
retried = true;
|
|
598
|
+
const repeatedRecoveryCode = await relayOnce(message, attemptedConnection, state, cancelCorrelation);
|
|
599
|
+
if (repeatedRecoveryCode) {
|
|
600
|
+
throw new Error(`Replacement local service rejected the credential (${repeatedRecoveryCode}).`);
|
|
210
601
|
}
|
|
211
|
-
await send(responseMessage);
|
|
212
602
|
}
|
|
213
603
|
}
|
|
214
604
|
catch (error) {
|
|
605
|
+
if (closing)
|
|
606
|
+
return;
|
|
607
|
+
if (terminal)
|
|
608
|
+
return;
|
|
609
|
+
if (state.responseDelivered) {
|
|
610
|
+
(options.logError || console.error)(`[Taskforce MCP proxy] Relay failed after delivering the response: ${String(error?.message || error)}`);
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
215
613
|
if (state.cancelled && id !== null) {
|
|
216
614
|
await send(errorResponse(id, 'Client stopped waiting; the operation may still complete.', 'REQUEST_CANCELLED_ADVISORY', MCP_REQUEST_CANCELLED));
|
|
217
615
|
return;
|
|
218
616
|
}
|
|
617
|
+
if (definitivelyRejected && !retried) {
|
|
618
|
+
await failTerminal(error instanceof Error ? error : new Error(String(error)), id);
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
if (id !== null && isKnownReadRequest(message) && !retried && !state.controller.signal.aborted) {
|
|
622
|
+
try {
|
|
623
|
+
attemptedConnection = await recoverConnection(attemptedConnection, null);
|
|
624
|
+
retried = true;
|
|
625
|
+
const recoveryCode = await relayOnce(message, attemptedConnection, state, cancelCorrelation);
|
|
626
|
+
if (recoveryCode) {
|
|
627
|
+
throw new Error(`Replacement local service rejected the credential (${recoveryCode}).`);
|
|
628
|
+
}
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
catch (retryError) {
|
|
632
|
+
await failTerminal(retryError instanceof Error ? retryError : new Error(String(retryError)), id);
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
if (id !== null && !isKnownReadRequest(message)) {
|
|
637
|
+
await recoverConnection(attemptedConnection, null).catch((recoveryError) => {
|
|
638
|
+
(options.logError || console.error)(`[Taskforce MCP proxy] Recovery after an outcome-uncertain request failed: ${String(recoveryError?.message || recoveryError)}`);
|
|
639
|
+
});
|
|
640
|
+
if (closing)
|
|
641
|
+
return;
|
|
642
|
+
const operationKey = idempotencyKey(message);
|
|
643
|
+
const guidance = operationKey
|
|
644
|
+
? 'Taskforce could not confirm whether the operation completed. Do not retry automatically. Preserve the idempotency key, verify the intended state with the relevant Taskforce read or search tool, and retry only after confirming the operation is absent.'
|
|
645
|
+
: 'Taskforce could not confirm whether the operation completed. Do not retry automatically. Verify the intended state with the relevant Taskforce read or search tool before deciding whether any manual retry is safe.';
|
|
646
|
+
const outcome = {
|
|
647
|
+
code: 'LOCAL_SERVICE_OUTCOME_UNCERTAIN',
|
|
648
|
+
outcomeUncertain: true,
|
|
649
|
+
retryable: false,
|
|
650
|
+
...(operationKey ? { idempotencyKey: operationKey } : {}),
|
|
651
|
+
operationId: null,
|
|
652
|
+
operationLookup: {
|
|
653
|
+
endpointTemplate: `${connection.descriptor.endpoint}${LOCAL_SERVICE_API_BASE_PATH}/operations/{operationId}`,
|
|
654
|
+
status: 'operation_id_required',
|
|
655
|
+
requiresPrivateProxyCredential: true,
|
|
656
|
+
},
|
|
657
|
+
verificationGuidance: 'Use the relevant Taskforce read or search tool with the original target and payload. The idempotency key is not the canonical operation ID.',
|
|
658
|
+
};
|
|
659
|
+
if (!('method' in message) || message.method !== 'tools/call') {
|
|
660
|
+
await send(errorResponse(id, guidance, 'LOCAL_SERVICE_OUTCOME_UNCERTAIN', MCP_PROTOCOL_ERROR, outcome));
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
await send({
|
|
664
|
+
jsonrpc: '2.0',
|
|
665
|
+
id,
|
|
666
|
+
result: {
|
|
667
|
+
content: [{ type: 'text', text: guidance }],
|
|
668
|
+
structuredContent: outcome,
|
|
669
|
+
isError: true,
|
|
670
|
+
...(isModernRequest(message)
|
|
671
|
+
? { resultType: 'complete' }
|
|
672
|
+
: {}),
|
|
673
|
+
},
|
|
674
|
+
});
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
219
677
|
await failTerminal(error instanceof Error ? error : new Error(String(error)), id);
|
|
220
678
|
}
|
|
221
679
|
finally {
|
|
@@ -225,34 +683,38 @@ export async function startLocalServiceMcpProxy(options) {
|
|
|
225
683
|
requests.delete(key);
|
|
226
684
|
}
|
|
227
685
|
};
|
|
228
|
-
|
|
686
|
+
const forwardPromises = new Set();
|
|
687
|
+
stdio.onmessage = (message) => {
|
|
688
|
+
const pending = forward(message).finally(() => { forwardPromises.delete(pending); });
|
|
689
|
+
forwardPromises.add(pending);
|
|
690
|
+
};
|
|
229
691
|
stdio.onerror = (error) => { void failTerminal(error, null); };
|
|
230
692
|
try {
|
|
231
693
|
await stdio.start();
|
|
232
694
|
}
|
|
233
695
|
catch (error) {
|
|
234
|
-
await
|
|
235
|
-
method: 'DELETE',
|
|
236
|
-
headers: { authorization: `Bearer ${registration.bearerToken}` },
|
|
237
|
-
signal: timeoutSignal(2_000),
|
|
238
|
-
}).then((response) => response.body?.cancel()).catch(() => undefined);
|
|
696
|
+
await revokeConnection(connection);
|
|
239
697
|
throw error;
|
|
240
698
|
}
|
|
241
699
|
const close = () => {
|
|
242
700
|
if (closePromise)
|
|
243
701
|
return closePromise;
|
|
702
|
+
closing = true;
|
|
244
703
|
terminal = true;
|
|
704
|
+
const pendingRecovery = recoveryState?.promise || null;
|
|
245
705
|
closePromise = (async () => {
|
|
246
706
|
for (const pending of inFlight)
|
|
247
707
|
pending.controller.abort();
|
|
248
708
|
await stdio.close().catch(() => undefined);
|
|
249
|
-
await
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
}).then((response) => response.body?.cancel()).catch(() => undefined);
|
|
709
|
+
await Promise.allSettled([...forwardPromises]);
|
|
710
|
+
await pendingRecovery?.catch(() => undefined);
|
|
711
|
+
const activeConnection = connection;
|
|
712
|
+
await revokeConnection(activeConnection);
|
|
254
713
|
})();
|
|
255
714
|
return closePromise;
|
|
256
715
|
};
|
|
257
|
-
return {
|
|
716
|
+
return {
|
|
717
|
+
close,
|
|
718
|
+
get sessionId() { return connection.registration.session.id; },
|
|
719
|
+
};
|
|
258
720
|
}
|