@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
|
@@ -6,17 +6,18 @@
|
|
|
6
6
|
* routes.ts at runtime.
|
|
7
7
|
*/
|
|
8
8
|
import { randomUUID } from 'crypto';
|
|
9
|
-
import {
|
|
10
|
-
import { isInitializeRequest } from '@modelcontextprotocol/
|
|
9
|
+
import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
|
|
10
|
+
import { isInitializeRequest, isJsonContentType } from '@modelcontextprotocol/server';
|
|
11
11
|
import { TaskforceRuleError } from '../../core/Taskforce.js';
|
|
12
12
|
import { resolveRequestAccess, } from '../auth.js';
|
|
13
13
|
import { parseJsonBody } from './primitives.js';
|
|
14
|
-
import { createTaskforceMcpServer, isMcpWriteToolName } from '../../mcp/runtime.js';
|
|
14
|
+
import { createStatelessTaskforceMcpServer, createTaskforceMcpServer, isMcpWriteToolName, } from '../../mcp/runtime.js';
|
|
15
15
|
import { MCP_CLOUD_TOOL_SCOPE_REQUIREMENTS } from '../../mcp/toolRegistry.js';
|
|
16
16
|
import { resolveCanonicalMcpToolName } from '../../mcp/toolCallCompatibility.js';
|
|
17
17
|
import { applyPrefixedRateLimitHeaders } from '../rateLimit.js';
|
|
18
18
|
import { parseAiProfileBootstrapHeaders } from '../../mcp/aiProfileBootstrap.js';
|
|
19
19
|
import { parseMcpClientId } from '../../mcp/clientRegistry.js';
|
|
20
|
+
import { handleModernMcpHttpRequest, isModernMcpHttpRequest, } from '../../mcp/httpProtocolRouting.js';
|
|
20
21
|
import { resolveAppAccessDeniedResponse } from '../appAccess.js';
|
|
21
22
|
import { resolveCloudApplicationBaseUrl } from '../../config/applicationBaseUrl.js';
|
|
22
23
|
import { getRequestPerformanceDiagnostics, runWithRequestPerformanceDiagnostics, } from '../../storage/postgresRequestDiagnostics.js';
|
|
@@ -273,7 +274,14 @@ function writeMcpHttpError(res, statusCode, message, data) {
|
|
|
273
274
|
id: null,
|
|
274
275
|
}));
|
|
275
276
|
}
|
|
276
|
-
function
|
|
277
|
+
function resolveProductionCloudMcpToolPolicy(requestedToolName) {
|
|
278
|
+
const toolName = resolveCanonicalMcpToolName(requestedToolName);
|
|
279
|
+
return {
|
|
280
|
+
requiredScope: MCP_CLOUD_TOOL_SCOPE_REQUIREMENTS[toolName] || null,
|
|
281
|
+
isWrite: isMcpWriteToolName(requestedToolName),
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function extractMcpWriteToolNames(body, resolveToolPolicy) {
|
|
277
285
|
const messages = Array.isArray(body) ? body : [body];
|
|
278
286
|
const names = messages.flatMap((message) => {
|
|
279
287
|
if (!message || typeof message !== 'object')
|
|
@@ -282,7 +290,7 @@ function extractMcpWriteToolNames(body) {
|
|
|
282
290
|
if (method !== 'tools/call')
|
|
283
291
|
return [];
|
|
284
292
|
const toolName = String(message?.params?.name || '').trim();
|
|
285
|
-
return toolName &&
|
|
293
|
+
return toolName && resolveToolPolicy(toolName).isWrite ? [toolName] : [];
|
|
286
294
|
});
|
|
287
295
|
return Array.from(new Set(names));
|
|
288
296
|
}
|
|
@@ -299,7 +307,7 @@ function extractFirstMcpToolName(body) {
|
|
|
299
307
|
}
|
|
300
308
|
return null;
|
|
301
309
|
}
|
|
302
|
-
function findDeniedCloudMcpToolName(body, scopes) {
|
|
310
|
+
function findDeniedCloudMcpToolName(body, scopes, resolveToolPolicy) {
|
|
303
311
|
const messages = Array.isArray(body) ? body : [body];
|
|
304
312
|
for (const message of messages) {
|
|
305
313
|
if (!message || typeof message !== 'object')
|
|
@@ -309,15 +317,14 @@ function findDeniedCloudMcpToolName(body, scopes) {
|
|
|
309
317
|
const requestedToolName = String(message?.params?.name || '').trim();
|
|
310
318
|
if (!requestedToolName)
|
|
311
319
|
continue;
|
|
312
|
-
const
|
|
313
|
-
const requiredScope = MCP_CLOUD_TOOL_SCOPE_REQUIREMENTS[toolName];
|
|
320
|
+
const requiredScope = resolveToolPolicy(requestedToolName).requiredScope;
|
|
314
321
|
if (!requiredScope || !scopes.includes(requiredScope))
|
|
315
322
|
return requestedToolName;
|
|
316
323
|
}
|
|
317
324
|
return null;
|
|
318
325
|
}
|
|
319
326
|
export function makeHandleCloudMcpRequest(core, deps) {
|
|
320
|
-
const { ensureAppAccess, resolveAuthenticatedUserId, writeRateLimit } = deps;
|
|
327
|
+
const { ensureAppAccess, resolveAuthenticatedUserId, writeRateLimit, createMcpServer = createTaskforceMcpServer, resolveMcpToolPolicy = resolveProductionCloudMcpToolPolicy, acquireMcpRuntime, } = deps;
|
|
321
328
|
const authenticateCloudMcpRequest = makeAuthenticateCloudMcpRequest(core, {
|
|
322
329
|
resolveAuthenticatedUserId,
|
|
323
330
|
writeMcpHttpError,
|
|
@@ -342,7 +349,7 @@ export function makeHandleCloudMcpRequest(core, deps) {
|
|
|
342
349
|
const applyCloudMcpWriteRateLimit = (req, res, auth, body) => {
|
|
343
350
|
if (!writeRateLimit.enabled)
|
|
344
351
|
return true;
|
|
345
|
-
const writeTools = extractMcpWriteToolNames(body);
|
|
352
|
+
const writeTools = extractMcpWriteToolNames(body, resolveMcpToolPolicy);
|
|
346
353
|
if (writeTools.length === 0)
|
|
347
354
|
return true;
|
|
348
355
|
const actorKey = auth.authenticatedViaToken?.tokenId
|
|
@@ -413,6 +420,10 @@ export function makeHandleCloudMcpRequest(core, deps) {
|
|
|
413
420
|
writeMcpHttpError(res, 405, 'Method not allowed.');
|
|
414
421
|
return;
|
|
415
422
|
}
|
|
423
|
+
if (!isJsonContentType(requestHeader(req, 'content-type', ''))) {
|
|
424
|
+
writeMcpHttpError(res, 415, 'Unsupported Media Type: Content-Type must be application/json');
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
416
427
|
let body = undefined;
|
|
417
428
|
try {
|
|
418
429
|
const bodyParseStartedAtMs = Date.now();
|
|
@@ -431,7 +442,8 @@ export function makeHandleCloudMcpRequest(core, deps) {
|
|
|
431
442
|
: '';
|
|
432
443
|
const initializeRequest = isInitializeRequest(body)
|
|
433
444
|
|| mcpMethod === 'initialize';
|
|
434
|
-
const
|
|
445
|
+
const modernProtocolRequest = await isModernMcpHttpRequest(req, body);
|
|
446
|
+
const deniedToolName = findDeniedCloudMcpToolName(body, authScopes, resolveMcpToolPolicy);
|
|
435
447
|
if (deniedToolName) {
|
|
436
448
|
core.addMcpAuditLog({
|
|
437
449
|
workspaceId: auth.workspaceId,
|
|
@@ -451,13 +463,14 @@ export function makeHandleCloudMcpRequest(core, deps) {
|
|
|
451
463
|
writeMcpHttpError(res, 403, 'Forbidden.');
|
|
452
464
|
return;
|
|
453
465
|
}
|
|
454
|
-
const writeToolNames = extractMcpWriteToolNames(body);
|
|
466
|
+
const writeToolNames = extractMcpWriteToolNames(body, resolveMcpToolPolicy);
|
|
455
467
|
const rateLimitStartedAtMs = Date.now();
|
|
456
468
|
const rateLimitAllowed = applyCloudMcpWriteRateLimit(req, res, auth, body);
|
|
457
469
|
rateLimitMs = Date.now() - rateLimitStartedAtMs;
|
|
458
470
|
if (!rateLimitAllowed)
|
|
459
471
|
return;
|
|
460
472
|
let runtime = null;
|
|
473
|
+
let runtimeLease = null;
|
|
461
474
|
let runtimeConstructionMs = 0;
|
|
462
475
|
let transportConnectMs = 0;
|
|
463
476
|
let requestHandlingMs = 0;
|
|
@@ -466,12 +479,13 @@ export function makeHandleCloudMcpRequest(core, deps) {
|
|
|
466
479
|
const toolTimingState = { value: null };
|
|
467
480
|
try {
|
|
468
481
|
const runtimeStartedAtMs = Date.now();
|
|
469
|
-
//
|
|
482
|
+
// Production intentionally isolates the MCP runtime per HTTP request. The runtime closes over
|
|
470
483
|
// workspace auth, AI identity, permissions, subscriptions, and mutable helper state;
|
|
471
484
|
// sharing it could leak state across tenants or callers. Keep the transport stateless
|
|
472
485
|
// too. The timing event below measures construction cost so caching is only revisited
|
|
473
|
-
// with evidence and must preserve these boundaries (including dynamic tool schemas).
|
|
474
|
-
|
|
486
|
+
// with evidence and must preserve these boundaries (including dynamic tool schemas). The optional
|
|
487
|
+
// lease seam exists only for transport conformance tests that must carry legacy bidirectional calls.
|
|
488
|
+
const runtimeOptions = {
|
|
475
489
|
projectRoot: core.getPaths().projectRoot,
|
|
476
490
|
tenantId: core.getTenantId(),
|
|
477
491
|
workspaceId: auth.workspaceId,
|
|
@@ -479,6 +493,7 @@ export function makeHandleCloudMcpRequest(core, deps) {
|
|
|
479
493
|
serverName: 'taskforce-cloud',
|
|
480
494
|
logStartup: false,
|
|
481
495
|
runtimeMode: 'cloud',
|
|
496
|
+
toolProfile: auth.authenticatedViaToken?.toolProfile || auth.authenticatedViaOAuth?.toolProfile || 'default',
|
|
482
497
|
applicationBaseUrl: resolveCloudApplicationBaseUrl(),
|
|
483
498
|
auth: buildCloudMcpRuntimeAuth({
|
|
484
499
|
req,
|
|
@@ -506,15 +521,66 @@ export function makeHandleCloudMcpRequest(core, deps) {
|
|
|
506
521
|
]);
|
|
507
522
|
}
|
|
508
523
|
},
|
|
509
|
-
}
|
|
524
|
+
};
|
|
525
|
+
if (modernProtocolRequest) {
|
|
526
|
+
const requestHandlingStartedAtMs = Date.now();
|
|
527
|
+
await handleModernMcpHttpRequest({
|
|
528
|
+
req,
|
|
529
|
+
res,
|
|
530
|
+
parsedBody: body,
|
|
531
|
+
factory: ({ era }) => {
|
|
532
|
+
const constructionStartedAtMs = Date.now();
|
|
533
|
+
const modernRuntime = createStatelessTaskforceMcpServer({
|
|
534
|
+
...runtimeOptions,
|
|
535
|
+
protocolEra: era,
|
|
536
|
+
}, createMcpServer);
|
|
537
|
+
runtimeConstructionMs = Date.now() - constructionStartedAtMs;
|
|
538
|
+
if (!res.headersSent) {
|
|
539
|
+
setServerTimingHeader(res, [
|
|
540
|
+
{ name: 'auth', durationMs: authMs },
|
|
541
|
+
{ name: 'body-parse', durationMs: bodyParseMs },
|
|
542
|
+
{ name: 'rate-limit', durationMs: rateLimitMs },
|
|
543
|
+
{ name: 'runtime', durationMs: runtimeConstructionMs },
|
|
544
|
+
]);
|
|
545
|
+
}
|
|
546
|
+
return modernRuntime.server;
|
|
547
|
+
},
|
|
548
|
+
onerror: (error) => {
|
|
549
|
+
console.warn('[Taskforce MCP] Modern cloud request rejected:', {
|
|
550
|
+
requestId,
|
|
551
|
+
message: error.message,
|
|
552
|
+
});
|
|
553
|
+
},
|
|
554
|
+
});
|
|
555
|
+
requestHandlingMs = Date.now() - requestHandlingStartedAtMs;
|
|
556
|
+
recordCloudMcpCredentialUsage(req, auth.authenticatedViaToken, auth.authenticatedViaOAuth);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
runtimeLease = acquireMcpRuntime
|
|
560
|
+
? await acquireMcpRuntime({ req, options: runtimeOptions })
|
|
561
|
+
: null;
|
|
562
|
+
runtime = runtimeLease?.runtime
|
|
563
|
+
|| createStatelessTaskforceMcpServer(runtimeOptions, createMcpServer);
|
|
510
564
|
runtimeConstructionMs = Date.now() - runtimeStartedAtMs;
|
|
511
|
-
const transport = new
|
|
565
|
+
const transport = runtimeLease?.transport || new NodeStreamableHTTPServerTransport({
|
|
512
566
|
sessionIdGenerator: undefined,
|
|
513
567
|
enableJsonResponse: true,
|
|
514
568
|
});
|
|
515
569
|
const transportStartedAtMs = Date.now();
|
|
516
|
-
|
|
570
|
+
if (!runtimeLease)
|
|
571
|
+
await runtime.server.connect(transport);
|
|
517
572
|
transportConnectMs = Date.now() - transportStartedAtMs;
|
|
573
|
+
// Set request-level phases before the SDK writes response headers. Tool calls replace this
|
|
574
|
+
// with the richer envelope/handler breakdown from onToolCallTiming above.
|
|
575
|
+
if (!res.headersSent) {
|
|
576
|
+
setServerTimingHeader(res, [
|
|
577
|
+
{ name: 'auth', durationMs: authMs },
|
|
578
|
+
{ name: 'body-parse', durationMs: bodyParseMs },
|
|
579
|
+
{ name: 'rate-limit', durationMs: rateLimitMs },
|
|
580
|
+
{ name: 'runtime', durationMs: runtimeConstructionMs },
|
|
581
|
+
{ name: 'transport-connect', durationMs: transportConnectMs },
|
|
582
|
+
]);
|
|
583
|
+
}
|
|
518
584
|
if (!initializeRequest) {
|
|
519
585
|
// Stateless cloud sessions still require a valid MCP JSON-RPC request;
|
|
520
586
|
// let the SDK validate and respond rather than trying to track sessions server-side.
|
|
@@ -540,7 +606,17 @@ export function makeHandleCloudMcpRequest(core, deps) {
|
|
|
540
606
|
}
|
|
541
607
|
}
|
|
542
608
|
finally {
|
|
543
|
-
if (
|
|
609
|
+
if (runtimeLease) {
|
|
610
|
+
const cleanupStartedAtMs = Date.now();
|
|
611
|
+
try {
|
|
612
|
+
await runtimeLease.release();
|
|
613
|
+
}
|
|
614
|
+
catch (closeError) {
|
|
615
|
+
console.warn('[Taskforce MCP] Cloud test runtime lease cleanup failed:', closeError);
|
|
616
|
+
}
|
|
617
|
+
cleanupMs = Date.now() - cleanupStartedAtMs;
|
|
618
|
+
}
|
|
619
|
+
else if (runtime) {
|
|
544
620
|
const cleanupStartedAtMs = Date.now();
|
|
545
621
|
try {
|
|
546
622
|
await runtime.server.close();
|
|
@@ -573,6 +573,7 @@ export function registerSyncRoutes(deps) {
|
|
|
573
573
|
}
|
|
574
574
|
const { result } = await dispatchWorkspaceSyncChanges(cloudWorkspaceId, fenced.changes, {
|
|
575
575
|
coexistenceDirection: 'cloud-push',
|
|
576
|
+
actorUserId: access.userId,
|
|
576
577
|
assertedActiveV3TaskMetadataIds,
|
|
577
578
|
assertedActiveV3TaskLifecycleIds,
|
|
578
579
|
assertedActiveV3TaskReopenAssigneeIds,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { applyWorkspaceRepair } from '../../sync/workspaceRepair.js';
|
|
2
|
+
import { WorkspaceSyncContentPullObligationStore } from '../../sync/engine/workspaceSyncContentPullObligationStore.js';
|
|
2
3
|
import { normalizeSyncEventDetails } from '../../utils/syncEventDetails.js';
|
|
3
4
|
import { parseJsonBody } from './primitives.js';
|
|
4
5
|
import { requireAuthenticatedSyncRequest } from './syncRouteGuards.js';
|
|
@@ -50,8 +51,13 @@ export function registerWorkspaceSyncAuxRoutes({ addRoute, core, context, resolv
|
|
|
50
51
|
res.end(JSON.stringify({ success: true }));
|
|
51
52
|
});
|
|
52
53
|
// POST /api/taskforce/sync/workspace/repair-startup - Auto-repair workspace asset/document
|
|
53
|
-
// metadata on workspace open. Safe fixups re-register metadata for local files and
|
|
54
|
-
// stale
|
|
54
|
+
// metadata on workspace open. Safe fixups re-register metadata for local files and clean up
|
|
55
|
+
// stale links. Does NOT tombstone metadata for files that appear missing locally — a single
|
|
56
|
+
// failed existence check at startup can mean the content is only temporarily unavailable
|
|
57
|
+
// (e.g. storage not yet mounted/synced), not deleted; that requires explicit admin
|
|
58
|
+
// confirmation via /api/taskforce/admin/workspace-repair/apply. Never deletes files. When
|
|
59
|
+
// content availability genuinely can't be verified, queues a durable content-pull recovery
|
|
60
|
+
// obligation instead, which resolves automatically once a later scan confirms the content.
|
|
55
61
|
// Called once by the sync orchestrator when the workspace becomes active.
|
|
56
62
|
addRoute('POST', '/api/taskforce/sync/workspace/repair-startup', async (req, res) => {
|
|
57
63
|
const authConfig = context.authConfig;
|
|
@@ -80,6 +86,7 @@ export function registerWorkspaceSyncAuxRoutes({ addRoute, core, context, resolv
|
|
|
80
86
|
deletedTasks: core.listWorkspaceSyncDeletes(workspaceId) || [],
|
|
81
87
|
workspaceAssetStore,
|
|
82
88
|
publishedContentResolver,
|
|
89
|
+
contentPullObligationStore: new WorkspaceSyncContentPullObligationStore(core.getDatabaseAdapter()),
|
|
83
90
|
aiProfiles: typeof core.listAiProfiles === 'function'
|
|
84
91
|
? core.listAiProfiles(workspaceId, { includeArchived: true }) || []
|
|
85
92
|
: [],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_WORKSPACE_PULL_PAGE_MAX_BYTES, buildWorkspacePullFeed, WorkspacePullEntryTooLargeError, } from '../../sync/workspacePullFeed.js';
|
|
2
2
|
import { applyWorkspaceSyncLocalBatch } from '../../sync/engine/workspaceSyncEngineLocalApply.js';
|
|
3
3
|
import { parseJsonBody } from './primitives.js';
|
|
4
|
-
import { normalizeWorkspaceSyncV2ProjectionExclusions, parseWorkspaceSyncV2ProjectionExclusions, WORKSPACE_SYNC_V3_COMBINED_V2_EXCLUSIONS, } from '../../sync/v3/workspaceSyncV2ProjectionExclusions.js';
|
|
4
|
+
import { normalizeWorkspaceSyncV2ProjectionExclusions, parseWorkspaceSyncV2ProjectionExclusions, WORKSPACE_SYNC_V3_COMBINED_V2_EXCLUSIONS, workspaceSyncV2ProjectionExclusionsEqual, } from '../../sync/v3/workspaceSyncV2ProjectionExclusions.js';
|
|
5
5
|
import { resolveWorkspaceSyncV3AttestedV2Exclusions } from '../../sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js';
|
|
6
6
|
import { requireAuthenticatedSyncRequest, requireEnabledSyncAuth, resolveAuthorizedSyncWorkspace, } from './syncRouteGuards.js';
|
|
7
7
|
import { completeLocalSyncBrowserPushEchoPermitGroup, createLocalSyncBrowserV2ApplyTransactionHooks, parseLocalSyncBrowserApplyPermitContext, resolveLocalSyncBrowserApplyPermitOperationClass, } from '../../sync/coordinator/localSyncBrowserApplyPermitContext.js';
|
|
@@ -301,7 +301,16 @@ export function registerWorkspacePullApplySyncRoutes({ addRoute, core, context,
|
|
|
301
301
|
};
|
|
302
302
|
}
|
|
303
303
|
if (!change) {
|
|
304
|
-
missing.push(
|
|
304
|
+
missing.push({
|
|
305
|
+
...request,
|
|
306
|
+
disposition: request.kind === 'asset'
|
|
307
|
+
&& 'assetId' in request
|
|
308
|
+
&& (!requestedAsset
|
|
309
|
+
|| requestedAsset.deletedAt
|
|
310
|
+
|| requestedAsset.storageProvider === 'external')
|
|
311
|
+
? 'terminal-unavailable'
|
|
312
|
+
: 'retryable',
|
|
313
|
+
});
|
|
305
314
|
consumed += 1;
|
|
306
315
|
continue;
|
|
307
316
|
}
|
|
@@ -554,6 +563,16 @@ export function registerWorkspacePullApplySyncRoutes({ addRoute, core, context,
|
|
|
554
563
|
: null;
|
|
555
564
|
let applyResult;
|
|
556
565
|
if (permitContext && coordinatorServices && permitOperationClass === 'push') {
|
|
566
|
+
const attestedV2ExcludedProjections = v2ExcludedProjections.length > 0
|
|
567
|
+
? (() => {
|
|
568
|
+
const attested = resolveWorkspaceSyncV3AttestedV2Exclusions({
|
|
569
|
+
coverage: body?.combinedCoverage,
|
|
570
|
+
excludedProjections: v2ExcludedProjections,
|
|
571
|
+
runtimeMode: 'local',
|
|
572
|
+
});
|
|
573
|
+
return attested && workspaceSyncV2ProjectionExclusionsEqual(attested, v2ExcludedProjections) ? attested : null;
|
|
574
|
+
})()
|
|
575
|
+
: [];
|
|
557
576
|
applyResult = completeLocalSyncBrowserPushEchoPermitGroup({
|
|
558
577
|
services: coordinatorServices,
|
|
559
578
|
cookieHeader: req.headers.cookie,
|
|
@@ -567,13 +586,13 @@ export function registerWorkspacePullApplySyncRoutes({ addRoute, core, context,
|
|
|
567
586
|
|| workspaceMembers !== undefined
|
|
568
587
|
|| body?.bootstrapSnapshot !== undefined
|
|
569
588
|
|| allowReferenceNumberReassignment
|
|
570
|
-
||
|
|
589
|
+
|| !attestedV2ExcludedProjections) {
|
|
571
590
|
throw new Error('Browser push echo apply accepts only authoritative task upserts.');
|
|
572
591
|
}
|
|
573
592
|
return dispatchWorkspaceSyncMetadataAtomically(workspaceId, incomingChanges, {
|
|
574
593
|
allowReferenceNumberReassignment: false,
|
|
575
594
|
coexistenceDirection: 'local-pull',
|
|
576
|
-
v2ExcludedProjections:
|
|
595
|
+
v2ExcludedProjections: attestedV2ExcludedProjections,
|
|
577
596
|
});
|
|
578
597
|
},
|
|
579
598
|
});
|
|
@@ -21,6 +21,7 @@ interface RegisterWorkspacePushSyncRoutesArgs {
|
|
|
21
21
|
dispatchWorkspaceSyncChanges: (workspaceId: string, incomingChanges: WorkspaceSyncChange[], options?: {
|
|
22
22
|
allowReferenceNumberReassignment?: boolean;
|
|
23
23
|
coexistenceDirection?: 'cloud-push';
|
|
24
|
+
actorUserId?: string;
|
|
24
25
|
assertedActiveV3TaskMetadataIds?: ReadonlySet<string>;
|
|
25
26
|
assertedActiveV3TaskLifecycleIds?: ReadonlySet<string>;
|
|
26
27
|
assertedActiveV3TaskReopenAssigneeIds?: ReadonlySet<string>;
|
|
@@ -270,6 +270,7 @@ export function registerWorkspacePushSyncRoutes({ addRoute, core, context, audit
|
|
|
270
270
|
const { result, deleteCount, emittedEventIds } = await dispatchWorkspaceSyncChanges(targetWorkspaceId, incomingChanges, {
|
|
271
271
|
allowReferenceNumberReassignment,
|
|
272
272
|
coexistenceDirection: 'cloud-push',
|
|
273
|
+
actorUserId: String(access.userId || '').trim(),
|
|
273
274
|
assertedActiveV3TaskMetadataIds,
|
|
274
275
|
assertedActiveV3TaskLifecycleIds,
|
|
275
276
|
assertedActiveV3TaskReopenAssigneeIds,
|
|
@@ -5,7 +5,7 @@ import { buildWorkspaceSyncV3InitiativeRepairPage, decodeWorkspaceSyncV3Initiati
|
|
|
5
5
|
import { WORKSPACE_SYNC_V3_COVERAGE_PROFILE } from '../../sync/v3/workspaceSyncV3FeedProfile.js';
|
|
6
6
|
import { isWorkspaceSyncV3InitiativeLegacyPushDisabled } from '../../sync/v3/planningActivation.js';
|
|
7
7
|
import { WORKSPACE_SYNC_V3_COMBINED_COVERAGE_PROFILE } from '../../sync/v3/workspaceSyncV3CombinedCoverage.js';
|
|
8
|
-
import { buildWorkspaceSyncV3CombinedRepairPage, decodeWorkspaceSyncV3CombinedRepairCursor, decodeWorkspaceSyncV3NestedRepairCursor, decodeWorkspaceSyncV3PlanningOrderRepairCursor, decodeWorkspaceSyncV3WorkflowRepairCursor, WorkspaceSyncV3CombinedRepairSnapshotUnavailableError, } from '../../sync/v3/workspaceSyncV3CombinedRepairMaterialization.js';
|
|
8
|
+
import { buildWorkspaceSyncV3CombinedRepairPage, decodeWorkspaceSyncV3CombinedRepairCursor, decodeWorkspaceSyncV3NestedRepairCursor, decodeWorkspaceSyncV3PlanningOrderRepairCursor, decodeWorkspaceSyncV3TaskCoverRepairCursor, decodeWorkspaceSyncV3WorkflowRepairCursor, decodeWorkspaceSyncV3WorkflowTaskCoverRepairCursor, WorkspaceSyncV3CombinedRepairSnapshotUnavailableError, } from '../../sync/v3/workspaceSyncV3CombinedRepairMaterialization.js';
|
|
9
9
|
import { isWorkspaceSyncV3CombinedLegacyFenceEnabled } from '../../sync/v3/workspaceSyncV2ProjectionExclusions.js';
|
|
10
10
|
import { resolveCombinedFeedCapability } from '../../sync/v3/combinedFeedCapability.js';
|
|
11
11
|
import { resolveWorkspaceSyncV3RegisteredCoverage } from '../../sync/v3/workspaceSyncV3CoverageRegistry.js';
|
|
@@ -21,6 +21,20 @@ function json(res, status, body) {
|
|
|
21
21
|
res.writeHead(status, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
|
|
22
22
|
res.end(JSON.stringify(body));
|
|
23
23
|
}
|
|
24
|
+
function decodeCombinedRepairCursorForContract(rawCursor, keyring, wire) {
|
|
25
|
+
if (wire.taskCoverProjectionRequired && wire.workflowWriterPrerequisitesRequired) {
|
|
26
|
+
return decodeWorkspaceSyncV3WorkflowTaskCoverRepairCursor(rawCursor, keyring);
|
|
27
|
+
}
|
|
28
|
+
if (wire.taskCoverProjectionRequired)
|
|
29
|
+
return decodeWorkspaceSyncV3TaskCoverRepairCursor(rawCursor, keyring);
|
|
30
|
+
if (wire.workflowWriterPrerequisitesRequired)
|
|
31
|
+
return decodeWorkspaceSyncV3WorkflowRepairCursor(rawCursor, keyring);
|
|
32
|
+
if (wire.planningOrderWriterPrerequisitesRequired)
|
|
33
|
+
return decodeWorkspaceSyncV3PlanningOrderRepairCursor(rawCursor, keyring);
|
|
34
|
+
if (wire.nestedWriterPrerequisitesRequired)
|
|
35
|
+
return decodeWorkspaceSyncV3NestedRepairCursor(rawCursor, keyring);
|
|
36
|
+
return decodeWorkspaceSyncV3CombinedRepairCursor(rawCursor, keyring);
|
|
37
|
+
}
|
|
24
38
|
function attestLegacyPushBoundary(body, boundary) {
|
|
25
39
|
const attested = { ...body, ...boundary };
|
|
26
40
|
const mutable = attested;
|
|
@@ -215,13 +229,7 @@ export function registerWorkspaceSyncV3FeedRoutes(input) {
|
|
|
215
229
|
return;
|
|
216
230
|
}
|
|
217
231
|
const rawCursor = String(url.searchParams.get('cursor') || '').trim();
|
|
218
|
-
const cursor = requestedWire
|
|
219
|
-
? decodeWorkspaceSyncV3WorkflowRepairCursor(rawCursor, keyring)
|
|
220
|
-
: requestedWire.planningOrderWriterPrerequisitesRequired
|
|
221
|
-
? decodeWorkspaceSyncV3PlanningOrderRepairCursor(rawCursor, keyring)
|
|
222
|
-
: requestedWire.nestedWriterPrerequisitesRequired
|
|
223
|
-
? decodeWorkspaceSyncV3NestedRepairCursor(rawCursor, keyring)
|
|
224
|
-
: decodeWorkspaceSyncV3CombinedRepairCursor(rawCursor, keyring);
|
|
232
|
+
const cursor = decodeCombinedRepairCursorForContract(rawCursor, keyring, requestedWire);
|
|
225
233
|
if (rawCursor && !cursor) {
|
|
226
234
|
json(res, 400, { success: false, code: 'INVALID_SYNC_COMBINED_REPAIR_CURSOR', error: 'Invalid combined repair cursor.' });
|
|
227
235
|
return;
|
|
@@ -231,7 +239,10 @@ export function registerWorkspaceSyncV3FeedRoutes(input) {
|
|
|
231
239
|
cursorKeyring: keyring, cursor, pageSize: Number.isFinite(limit) ? limit : undefined,
|
|
232
240
|
nestedCoverage: requestedWire.nestedWriterPrerequisitesRequired,
|
|
233
241
|
workflowCoverage: requestedWire.workflowWriterPrerequisitesRequired,
|
|
234
|
-
|
|
242
|
+
workflowTaskCoverCoverage: requestedWire.workflowWriterPrerequisitesRequired
|
|
243
|
+
&& requestedWire.taskCoverProjectionRequired,
|
|
244
|
+
planningOrderCoverage: requestedWire.planningOrderWriterPrerequisitesRequired,
|
|
245
|
+
taskCoverCoverage: requestedWire.taskCoverProjectionRequired });
|
|
235
246
|
json(res, 200, attestLegacyPushBoundary({ ...page }, {
|
|
236
247
|
contractVersion: 3,
|
|
237
248
|
legacyV2Boundary: { cloudWritesFenced: false, excludedProjections: [] },
|
|
@@ -328,13 +339,7 @@ export function registerWorkspaceSyncV3FeedRoutes(input) {
|
|
|
328
339
|
return;
|
|
329
340
|
}
|
|
330
341
|
const repairCursor = coverage.kind === 'combined'
|
|
331
|
-
? (coverage.wire
|
|
332
|
-
? decodeWorkspaceSyncV3WorkflowRepairCursor(rawRepairCursor, cursorKeyring)
|
|
333
|
-
: coverage.wire.planningOrderWriterPrerequisitesRequired
|
|
334
|
-
? decodeWorkspaceSyncV3PlanningOrderRepairCursor(rawRepairCursor, cursorKeyring)
|
|
335
|
-
: coverage.wire.nestedWriterPrerequisitesRequired
|
|
336
|
-
? decodeWorkspaceSyncV3NestedRepairCursor(rawRepairCursor, cursorKeyring)
|
|
337
|
-
: decodeWorkspaceSyncV3CombinedRepairCursor(rawRepairCursor, cursorKeyring))
|
|
342
|
+
? decodeCombinedRepairCursorForContract(rawRepairCursor, cursorKeyring, coverage.wire)
|
|
338
343
|
: decodeWorkspaceSyncV3InitiativeRepairCursor(rawRepairCursor, cursorKeyring);
|
|
339
344
|
if (rawRepairCursor && (!repairEnabled || !repairCursor)) {
|
|
340
345
|
json(res, 400, { success: false, code: 'INVALID_SYNC_V3_REPAIR_CURSOR', error: 'Invalid repair cursor.' });
|
|
@@ -352,7 +357,10 @@ export function registerWorkspaceSyncV3FeedRoutes(input) {
|
|
|
352
357
|
pageSize: Number.isFinite(limit) ? limit : undefined,
|
|
353
358
|
nestedCoverage: coverage.wire.nestedWriterPrerequisitesRequired,
|
|
354
359
|
workflowCoverage: coverage.wire.workflowWriterPrerequisitesRequired,
|
|
360
|
+
workflowTaskCoverCoverage: coverage.wire.workflowWriterPrerequisitesRequired
|
|
361
|
+
&& coverage.wire.taskCoverProjectionRequired,
|
|
355
362
|
planningOrderCoverage: coverage.wire.planningOrderWriterPrerequisitesRequired,
|
|
363
|
+
taskCoverCoverage: coverage.wire.taskCoverProjectionRequired,
|
|
356
364
|
coveredLegacyWritesFenced: combinedLegacyPushDisabled })
|
|
357
365
|
: buildWorkspaceSyncV3InitiativeRepairPage({ core: input.core, workspaceId,
|
|
358
366
|
cursorKeyring: cursorKeyring, cursor: repairCursor,
|
|
@@ -398,7 +406,10 @@ export function registerWorkspaceSyncV3FeedRoutes(input) {
|
|
|
398
406
|
cursorKeyring: cursorKeyring, pageSize: Number.isFinite(limit) ? limit : undefined,
|
|
399
407
|
nestedCoverage: coverage.wire.nestedWriterPrerequisitesRequired,
|
|
400
408
|
workflowCoverage: coverage.wire.workflowWriterPrerequisitesRequired,
|
|
409
|
+
workflowTaskCoverCoverage: coverage.wire.workflowWriterPrerequisitesRequired
|
|
410
|
+
&& coverage.wire.taskCoverProjectionRequired,
|
|
401
411
|
planningOrderCoverage: coverage.wire.planningOrderWriterPrerequisitesRequired,
|
|
412
|
+
taskCoverCoverage: coverage.wire.taskCoverProjectionRequired,
|
|
402
413
|
coveredLegacyWritesFenced: combinedLegacyPushDisabled })
|
|
403
414
|
: buildWorkspaceSyncV3InitiativeRepairPage({ core: input.core, workspaceId,
|
|
404
415
|
cursorKeyring: cursorKeyring, pageSize: Number.isFinite(limit) ? limit : undefined });
|
|
@@ -96,7 +96,14 @@ function parseEnvelope(raw) {
|
|
|
96
96
|
};
|
|
97
97
|
if (operation.domain === 'task' && operation.mutationKind === 'metadata-update') {
|
|
98
98
|
const saveSource = payload.saveSource;
|
|
99
|
-
|
|
99
|
+
const expectedDetailRevision = payload.expectedDetailRevision === undefined
|
|
100
|
+
? undefined
|
|
101
|
+
: requireId(payload.expectedDetailRevision, 'operation.payload.expectedDetailRevision');
|
|
102
|
+
assertExactKeys(payload, [
|
|
103
|
+
'patch',
|
|
104
|
+
...(saveSource === undefined ? [] : ['saveSource']),
|
|
105
|
+
...(expectedDetailRevision === undefined ? [] : ['expectedDetailRevision']),
|
|
106
|
+
], 'operation.payload');
|
|
100
107
|
if (saveSource !== undefined && saveSource !== 'manual' && saveSource !== 'autosave') {
|
|
101
108
|
throw new LocalCaptureRequestError('operation.payload.saveSource must be manual or autosave.');
|
|
102
109
|
}
|
|
@@ -106,6 +113,7 @@ function parseEnvelope(raw) {
|
|
|
106
113
|
mutationKind: 'metadata-update',
|
|
107
114
|
patch: requireRecord(payload.patch, 'operation.payload.patch'),
|
|
108
115
|
...(saveSource ? { saveSource } : {}),
|
|
116
|
+
...(expectedDetailRevision ? { expectedDetailRevision } : {}),
|
|
109
117
|
};
|
|
110
118
|
}
|
|
111
119
|
if (operation.domain === 'task' && operation.mutationKind === 'create') {
|
|
@@ -170,11 +178,27 @@ function parseEnvelope(raw) {
|
|
|
170
178
|
};
|
|
171
179
|
}
|
|
172
180
|
if (operation.domain === 'task' && operation.mutationKind === 'set-status') {
|
|
181
|
+
const expectedDetailRevision = payload.expectedDetailRevision === undefined
|
|
182
|
+
? undefined
|
|
183
|
+
: requireId(payload.expectedDetailRevision, 'operation.payload.expectedDetailRevision');
|
|
184
|
+
assertExactKeys(payload, [
|
|
185
|
+
'status',
|
|
186
|
+
'assigneeIntent',
|
|
187
|
+
'canceledReason',
|
|
188
|
+
'metadataPatch',
|
|
189
|
+
...(expectedDetailRevision === undefined ? [] : ['expectedDetailRevision']),
|
|
190
|
+
], 'operation.payload');
|
|
173
191
|
return {
|
|
174
192
|
...common,
|
|
175
193
|
domain: 'task',
|
|
176
194
|
mutationKind: 'set-status',
|
|
177
|
-
payload: validateDurableTaskStatusMutationPayload(
|
|
195
|
+
payload: validateDurableTaskStatusMutationPayload({
|
|
196
|
+
status: payload.status,
|
|
197
|
+
assigneeIntent: payload.assigneeIntent,
|
|
198
|
+
canceledReason: payload.canceledReason,
|
|
199
|
+
metadataPatch: payload.metadataPatch,
|
|
200
|
+
}),
|
|
201
|
+
...(expectedDetailRevision ? { expectedDetailRevision } : {}),
|
|
178
202
|
};
|
|
179
203
|
}
|
|
180
204
|
if (operation.domain === 'task-comments' && operation.mutationKind === 'append') {
|
|
@@ -731,6 +755,7 @@ export function registerWorkspaceSyncV3LocalCaptureRoutes(input) {
|
|
|
731
755
|
taskId: envelope.entityId,
|
|
732
756
|
patch: envelope.patch,
|
|
733
757
|
saveSource: envelope.saveSource,
|
|
758
|
+
expectedDetailRevision: envelope.expectedDetailRevision,
|
|
734
759
|
now: acceptedAt,
|
|
735
760
|
actorRef: 'user',
|
|
736
761
|
onPostCommitError: input.onPostCommitError,
|
|
@@ -786,6 +811,7 @@ export function registerWorkspaceSyncV3LocalCaptureRoutes(input) {
|
|
|
786
811
|
identity,
|
|
787
812
|
taskId: envelope.entityId,
|
|
788
813
|
payload: envelope.payload,
|
|
814
|
+
expectedDetailRevision: envelope.expectedDetailRevision,
|
|
789
815
|
now: acceptedAt,
|
|
790
816
|
actorRef: 'user',
|
|
791
817
|
onPostCommitError: input.onPostCommitError,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { SyncAddRoute, SyncRouteAuthConfig, SyncRouteCore } from './syncRouteTypes.js';
|
|
2
2
|
import type { LocalSyncCoordinatorRouteServices } from '../../sync/coordinator/localSyncCoordinatorRouteServices.js';
|
|
3
|
+
export declare function revisionConflictDetails(error: unknown): Record<string, unknown> | undefined;
|
|
3
4
|
export declare function isWorkspaceSyncV3LocalFeedApplyEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
4
5
|
export declare function isWorkspaceSyncV3CombinedLocalFeedApplyEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
5
6
|
export declare function registerWorkspaceSyncV3LocalFeedApplyRoutes(input: {
|
|
@@ -8,6 +8,7 @@ import { resolveCombinedFeedCapability, resolveRequestedCombinedFeedCoverage } f
|
|
|
8
8
|
import { parseJsonBody } from './primitives.js';
|
|
9
9
|
import { applyWorkspaceSyncV3TaskCommentAuditPage, readWorkspaceSyncV3TaskCommentAuditCursor, readWorkspaceSyncV3TaskCommentAuditState, } from '../../sync/v3/workspaceSyncV3TaskCommentAudit.js';
|
|
10
10
|
import { createLocalSyncBrowserApplyPermitTransactionHooks, parseLocalSyncBrowserApplyPermitContext, } from '../../sync/coordinator/localSyncBrowserApplyPermitContext.js';
|
|
11
|
+
import { WorkspaceSyncRevisionConflictError } from '../../sync/v3/syncDurabilityStore.js';
|
|
11
12
|
const ROUTE_PATH = '/api/taskforce/sync/v3/local/feed';
|
|
12
13
|
const TASK_COMMENT_AUDIT_PATH = '/api/taskforce/sync/v3/local/task-comment-audit';
|
|
13
14
|
const MAX_BODY_BYTES = 8 * 1024 * 1024;
|
|
@@ -15,6 +16,29 @@ function writeJson(res, statusCode, body) {
|
|
|
15
16
|
res.writeHead(statusCode, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
|
|
16
17
|
res.end(JSON.stringify(body));
|
|
17
18
|
}
|
|
19
|
+
export function revisionConflictDetails(error) {
|
|
20
|
+
if (!(error instanceof WorkspaceSyncRevisionConflictError) || !error.details)
|
|
21
|
+
return undefined;
|
|
22
|
+
const details = error.details;
|
|
23
|
+
const coordinates = (value) => {
|
|
24
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
25
|
+
return undefined;
|
|
26
|
+
const source = value;
|
|
27
|
+
const sequence = source.sequence ?? source.lastSequence;
|
|
28
|
+
return {
|
|
29
|
+
sequence: sequence == null ? null : String(sequence),
|
|
30
|
+
entityRevision: source.entityRevision == null ? null : String(source.entityRevision),
|
|
31
|
+
lifecycleRevision: source.lifecycleRevision == null ? null : String(source.lifecycleRevision),
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
domain: String(details.domain || ''),
|
|
36
|
+
entityId: String(details.entityId || ''),
|
|
37
|
+
reason: String(details.reason || ''),
|
|
38
|
+
...(coordinates(details.incoming) ? { incoming: coordinates(details.incoming) } : {}),
|
|
39
|
+
...(coordinates(details.current) ? { current: coordinates(details.current) } : {}),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
18
42
|
function workspaceFromUrl(req) {
|
|
19
43
|
try {
|
|
20
44
|
return String(new URL(req.url || ROUTE_PATH, 'http://localhost').searchParams.get('workspaceId') || '').trim();
|
|
@@ -481,12 +505,14 @@ export function registerWorkspaceSyncV3LocalFeedApplyRoutes(input) {
|
|
|
481
505
|
catch (error) {
|
|
482
506
|
const causeCode = String(error?.code || '').trim();
|
|
483
507
|
const causeAssetId = String(error?.assetId || '').trim();
|
|
508
|
+
const causeDetails = revisionConflictDetails(error);
|
|
484
509
|
writeJson(res, 409, {
|
|
485
510
|
success: false,
|
|
486
511
|
code: 'WORKSPACE_SYNC_V3_LOCAL_FEED_APPLY_REJECTED',
|
|
487
512
|
error: String(error?.message || error),
|
|
488
513
|
...(causeCode ? { causeCode } : {}),
|
|
489
514
|
...(causeAssetId ? { causeAssetId } : {}),
|
|
515
|
+
...(causeDetails ? { causeDetails } : {}),
|
|
490
516
|
});
|
|
491
517
|
}
|
|
492
518
|
});
|