@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
|
@@ -11,6 +11,7 @@ import { WorkspaceSyncJournalReader } from './workspaceSyncJournalReader.js';
|
|
|
11
11
|
import { isLegacyEntityEventAdoptionIdentity, LEGACY_ENTITY_EVENT_ADOPTION_MAX_PAYLOAD_BYTES, } from './entityEventLegacyAdoptionContract.js';
|
|
12
12
|
import { validateWorkspaceSyncV3EntityEventPayload } from './workspaceSyncV3NestedTaskCodecs.js';
|
|
13
13
|
import { fingerprintWorkspaceSyncPayload } from './workspaceSyncPayloadFingerprint.js';
|
|
14
|
+
import { assertDurableOperationFingerprint, assertDurableOperationIdentity, DurableOperationReplayIdentityConflictError, } from './durableOperationReplay.js';
|
|
14
15
|
export { canonicalWorkspaceSyncJson } from './canonicalWorkspaceSyncJson.js';
|
|
15
16
|
export { fingerprintWorkspaceSyncPayload } from './workspaceSyncPayloadFingerprint.js';
|
|
16
17
|
export const WORKSPACE_SYNC_CONTRACT_VERSION = 3;
|
|
@@ -791,7 +792,7 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
791
792
|
mutation_kind, owns_task_metadata, owns_task_lifecycle, owns_task_assignee,
|
|
792
793
|
CAST(base_entity_revision AS TEXT) AS base_entity_revision,
|
|
793
794
|
CAST(base_lifecycle_revision AS TEXT) AS base_lifecycle_revision,
|
|
794
|
-
payload_json, payload_fingerprint, status, attempt_count,
|
|
795
|
+
payload_json, payload_fingerprint, canonical_intent_json, status, attempt_count,
|
|
795
796
|
initial_not_found_attempt_count,
|
|
796
797
|
CAST(enqueue_sequence AS TEXT) AS enqueue_sequence,
|
|
797
798
|
rebase_before_first_attempt, lease_owner, lease_expires_at
|
|
@@ -800,6 +801,130 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
800
801
|
`).get(...operationParams(identity));
|
|
801
802
|
return row ? this.mapOutboxRow(row) : null;
|
|
802
803
|
}
|
|
804
|
+
assertOutboxOperationIdentity(record, expected) {
|
|
805
|
+
assertDurableOperationIdentity({
|
|
806
|
+
operationId: record.operationId,
|
|
807
|
+
domain: record.domain,
|
|
808
|
+
entityId: record.entityId,
|
|
809
|
+
mutationKind: record.mutationKind,
|
|
810
|
+
payloadFingerprint: record.payloadFingerprint,
|
|
811
|
+
}, {
|
|
812
|
+
operationId: record.operationId,
|
|
813
|
+
domain: expected.domain,
|
|
814
|
+
entityId: expected.entityId,
|
|
815
|
+
mutationKind: expected.mutationKind,
|
|
816
|
+
payloadFingerprint: expected.payloadFingerprint || record.payloadFingerprint,
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
readOutboxOperationLookup(identity) {
|
|
820
|
+
const row = this.db.prepare(`
|
|
821
|
+
SELECT status, authoritative_response_json, created_at,
|
|
822
|
+
mutation_kind, payload_fingerprint, domain, entity_id
|
|
823
|
+
FROM workspace_sync_outbox
|
|
824
|
+
WHERE tenant_id = ? AND workspace_id = ? AND client_id = ? AND operation_id = ?
|
|
825
|
+
LIMIT 1
|
|
826
|
+
`).get(...operationParams(identity));
|
|
827
|
+
if (!row)
|
|
828
|
+
return null;
|
|
829
|
+
return {
|
|
830
|
+
...identity,
|
|
831
|
+
status: requireText(row.status, 'Outbox status'),
|
|
832
|
+
createdAt: requireIsoTimestamp(row.created_at, 'Outbox creation time'),
|
|
833
|
+
domain: requireText(row.domain, 'Outbox domain'),
|
|
834
|
+
entityId: requireText(row.entity_id, 'Outbox entity id'),
|
|
835
|
+
mutationKind: requireText(row.mutation_kind, 'Outbox mutation kind'),
|
|
836
|
+
payloadFingerprint: requireText(row.payload_fingerprint, 'Outbox payload fingerprint'),
|
|
837
|
+
authoritativeResponseJson: row.authoritative_response_json == null
|
|
838
|
+
? null
|
|
839
|
+
: requireText(row.authoritative_response_json, 'Outbox authoritative response'),
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
pruneTerminalOutboxOperations(input) {
|
|
843
|
+
const tenantId = requireText(input.tenantId, 'Tenant id');
|
|
844
|
+
const workspaceId = requireText(input.workspaceId, 'Workspace id');
|
|
845
|
+
const terminalBefore = requireIsoTimestamp(input.terminalBefore, 'Operation retention cutoff');
|
|
846
|
+
const limit = Math.max(1, Math.min(1_000, Math.floor(input.limit ?? 100)));
|
|
847
|
+
const eligibility = `
|
|
848
|
+
candidate.tenant_id = ? AND candidate.workspace_id = ?
|
|
849
|
+
AND candidate.status IN ('accepted', 'superseded')
|
|
850
|
+
AND candidate.updated_at < ?
|
|
851
|
+
AND NOT EXISTS (
|
|
852
|
+
SELECT 1
|
|
853
|
+
FROM workspace_sync_outbox AS replay
|
|
854
|
+
WHERE replay.tenant_id = candidate.tenant_id
|
|
855
|
+
AND replay.workspace_id = candidate.workspace_id
|
|
856
|
+
AND replay.replay_of_client_id = candidate.client_id
|
|
857
|
+
AND replay.replay_of_operation_id = candidate.operation_id
|
|
858
|
+
)
|
|
859
|
+
`;
|
|
860
|
+
return this.db.transaction(() => {
|
|
861
|
+
const candidates = this.db.prepare(`
|
|
862
|
+
SELECT candidate.client_id, candidate.operation_id
|
|
863
|
+
FROM workspace_sync_outbox AS candidate
|
|
864
|
+
WHERE ${eligibility}
|
|
865
|
+
ORDER BY candidate.updated_at, candidate.client_id, candidate.operation_id
|
|
866
|
+
LIMIT ?
|
|
867
|
+
`).all(tenantId, workspaceId, terminalBefore, limit);
|
|
868
|
+
let deleted = 0;
|
|
869
|
+
for (const candidate of candidates) {
|
|
870
|
+
const clientId = requireText(candidate.client_id, 'Retention client id');
|
|
871
|
+
const operationId = requireText(candidate.operation_id, 'Retention operation id');
|
|
872
|
+
const result = this.db.prepare(`
|
|
873
|
+
DELETE FROM workspace_sync_outbox AS candidate
|
|
874
|
+
WHERE ${eligibility}
|
|
875
|
+
AND candidate.client_id = ? AND candidate.operation_id = ?
|
|
876
|
+
`).run(tenantId, workspaceId, terminalBefore, clientId, operationId);
|
|
877
|
+
if (Number(result.changes || 0) !== 1)
|
|
878
|
+
continue;
|
|
879
|
+
this.db.prepare(`
|
|
880
|
+
DELETE FROM workspace_sync_outbox_targets
|
|
881
|
+
WHERE tenant_id = ? AND workspace_id = ? AND client_id = ? AND operation_id = ?
|
|
882
|
+
`).run(tenantId, workspaceId, clientId, operationId);
|
|
883
|
+
deleted += 1;
|
|
884
|
+
}
|
|
885
|
+
const remaining = this.db.prepare(`
|
|
886
|
+
SELECT COUNT(*) AS count
|
|
887
|
+
FROM workspace_sync_outbox AS candidate
|
|
888
|
+
WHERE ${eligibility}
|
|
889
|
+
`).get(tenantId, workspaceId, terminalBefore);
|
|
890
|
+
return { deleted, remainingEligible: Number(remaining?.count || 0) };
|
|
891
|
+
})();
|
|
892
|
+
}
|
|
893
|
+
pruneCommittedOperationResults(input) {
|
|
894
|
+
const tenantId = requireText(input.tenantId, 'Tenant id');
|
|
895
|
+
const workspaceId = requireText(input.workspaceId, 'Workspace id');
|
|
896
|
+
const terminalBefore = requireIsoTimestamp(input.terminalBefore, 'Operation retention cutoff');
|
|
897
|
+
const limit = Math.max(1, Math.min(1_000, Math.floor(input.limit ?? 100)));
|
|
898
|
+
return this.db.transaction(() => {
|
|
899
|
+
const candidates = this.db.prepare(`
|
|
900
|
+
SELECT client_id, operation_id
|
|
901
|
+
FROM workspace_sync_operation_results
|
|
902
|
+
WHERE tenant_id = ? AND workspace_id = ?
|
|
903
|
+
AND status = 'committed' AND updated_at < ?
|
|
904
|
+
ORDER BY updated_at, client_id, operation_id
|
|
905
|
+
LIMIT ?
|
|
906
|
+
`).all(tenantId, workspaceId, terminalBefore, limit);
|
|
907
|
+
let deleted = 0;
|
|
908
|
+
for (const candidate of candidates) {
|
|
909
|
+
const clientId = requireText(candidate.client_id, 'Retention client id');
|
|
910
|
+
const operationId = requireText(candidate.operation_id, 'Retention operation id');
|
|
911
|
+
const result = this.db.prepare(`
|
|
912
|
+
DELETE FROM workspace_sync_operation_results
|
|
913
|
+
WHERE tenant_id = ? AND workspace_id = ?
|
|
914
|
+
AND client_id = ? AND operation_id = ?
|
|
915
|
+
AND status = 'committed' AND updated_at < ?
|
|
916
|
+
`).run(tenantId, workspaceId, clientId, operationId, terminalBefore);
|
|
917
|
+
deleted += Number(result.changes || 0);
|
|
918
|
+
}
|
|
919
|
+
const remaining = this.db.prepare(`
|
|
920
|
+
SELECT COUNT(*) AS count
|
|
921
|
+
FROM workspace_sync_operation_results
|
|
922
|
+
WHERE tenant_id = ? AND workspace_id = ?
|
|
923
|
+
AND status = 'committed' AND updated_at < ?
|
|
924
|
+
`).get(tenantId, workspaceId, terminalBefore);
|
|
925
|
+
return { deleted, remainingEligible: Number(remaining?.count || 0) };
|
|
926
|
+
})();
|
|
927
|
+
}
|
|
803
928
|
readV3DispatchSettlementEvidence(identity) {
|
|
804
929
|
const row = this.db.prepare(`
|
|
805
930
|
SELECT outbox.status, outbox.authoritative_response_json,
|
|
@@ -847,7 +972,7 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
847
972
|
mutation_kind, owns_task_metadata, owns_task_lifecycle, owns_task_assignee,
|
|
848
973
|
CAST(base_entity_revision AS TEXT) AS base_entity_revision,
|
|
849
974
|
CAST(base_lifecycle_revision AS TEXT) AS base_lifecycle_revision,
|
|
850
|
-
payload_json, payload_fingerprint, status, attempt_count,
|
|
975
|
+
payload_json, payload_fingerprint, canonical_intent_json, status, attempt_count,
|
|
851
976
|
initial_not_found_attempt_count,
|
|
852
977
|
CAST(enqueue_sequence AS TEXT) AS enqueue_sequence,
|
|
853
978
|
rebase_before_first_attempt, lease_owner, lease_expires_at
|
|
@@ -1028,7 +1153,7 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1028
1153
|
mutation_kind, owns_task_metadata, owns_task_lifecycle, owns_task_assignee,
|
|
1029
1154
|
CAST(base_entity_revision AS TEXT) AS base_entity_revision,
|
|
1030
1155
|
CAST(base_lifecycle_revision AS TEXT) AS base_lifecycle_revision,
|
|
1031
|
-
payload_json, payload_fingerprint, status, attempt_count,
|
|
1156
|
+
payload_json, payload_fingerprint, canonical_intent_json, status, attempt_count,
|
|
1032
1157
|
initial_not_found_attempt_count,
|
|
1033
1158
|
CAST(enqueue_sequence AS TEXT) AS enqueue_sequence,
|
|
1034
1159
|
rebase_before_first_attempt, lease_owner, lease_expires_at
|
|
@@ -1396,7 +1521,8 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1396
1521
|
const recoverySources = this.db.prepare(`
|
|
1397
1522
|
SELECT client_id, operation_id, dispatch_class, domain, entity_id, mutation_kind,
|
|
1398
1523
|
owns_task_metadata, owns_task_lifecycle, owns_task_assignee,
|
|
1399
|
-
payload_json, payload_fingerprint,
|
|
1524
|
+
payload_json, payload_fingerprint, canonical_intent_json,
|
|
1525
|
+
last_error_code, last_error_message,
|
|
1400
1526
|
EXISTS (
|
|
1401
1527
|
SELECT 1
|
|
1402
1528
|
FROM workspace_sync_outbox AS replay_candidate
|
|
@@ -1646,18 +1772,18 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1646
1772
|
dispatch_class, domain, entity_id, mutation_kind,
|
|
1647
1773
|
owns_task_metadata, owns_task_lifecycle, owns_task_assignee,
|
|
1648
1774
|
base_entity_revision, base_lifecycle_revision,
|
|
1649
|
-
payload_json, payload_fingerprint, status, attempt_count,
|
|
1775
|
+
payload_json, payload_fingerprint, canonical_intent_json, status, attempt_count,
|
|
1650
1776
|
initial_not_found_attempt_count, enqueue_sequence, rebase_before_first_attempt,
|
|
1651
1777
|
next_attempt_at, recovery_batch_id,
|
|
1652
1778
|
replay_of_client_id, replay_of_operation_id, created_at, updated_at
|
|
1653
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending', 0, 0, ?, 1,
|
|
1779
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending', 0, 0, ?, 1,
|
|
1654
1780
|
?, ?, ?, ?, ?, ?)
|
|
1655
1781
|
ON CONFLICT (tenant_id, workspace_id, client_id, operation_id) DO NOTHING
|
|
1656
|
-
`).run(tenantId, workspaceId, operationId, WORKSPACE_SYNC_CONTRACT_VERSION, sourceClientId, requireOutboxDispatchClass(source.dispatch_class), requireText(source.domain, 'Source domain'), replayEntityId, replayPayload.replayMutationKind, Number(source.owns_task_metadata) === 1 ? 1 : 0, Number(source.owns_task_lifecycle) === 1 ? 1 : 0, Number(source.owns_task_assignee) === 1 ? 1 : 0, primary.revision.entityRevision, primary.revision.lifecycleRevision, replayPayload.payloadJson, replayPayload.payloadFingerprint, enqueueSequence, now, recoveryBatchId, sourceClientId, sourceOperationId, now, now);
|
|
1782
|
+
`).run(tenantId, workspaceId, operationId, WORKSPACE_SYNC_CONTRACT_VERSION, sourceClientId, requireOutboxDispatchClass(source.dispatch_class), requireText(source.domain, 'Source domain'), replayEntityId, replayPayload.replayMutationKind, Number(source.owns_task_metadata) === 1 ? 1 : 0, Number(source.owns_task_lifecycle) === 1 ? 1 : 0, Number(source.owns_task_assignee) === 1 ? 1 : 0, primary.revision.entityRevision, primary.revision.lifecycleRevision, replayPayload.payloadJson, replayPayload.payloadFingerprint, source.canonical_intent_json == null ? null : String(source.canonical_intent_json), enqueueSequence, now, recoveryBatchId, sourceClientId, sourceOperationId, now, now);
|
|
1657
1783
|
this.db.prepare(`
|
|
1658
1784
|
UPDATE workspace_sync_outbox
|
|
1659
1785
|
SET base_entity_revision = ?, base_lifecycle_revision = ?,
|
|
1660
|
-
payload_json = ?, payload_fingerprint = ?,
|
|
1786
|
+
payload_json = ?, payload_fingerprint = ?, canonical_intent_json = ?,
|
|
1661
1787
|
status = 'pending', attempt_count = 0, initial_not_found_attempt_count = 0,
|
|
1662
1788
|
rebase_before_first_attempt = 1, next_attempt_at = ?,
|
|
1663
1789
|
lease_owner = NULL, lease_expires_at = NULL,
|
|
@@ -1667,7 +1793,7 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1667
1793
|
WHERE tenant_id = ? AND workspace_id = ? AND client_id = ? AND operation_id = ?
|
|
1668
1794
|
AND recovery_batch_id = ? AND replay_of_client_id = ? AND replay_of_operation_id = ?
|
|
1669
1795
|
AND status = 'superseded'
|
|
1670
|
-
`).run(primary.revision.entityRevision, primary.revision.lifecycleRevision, replayPayload.payloadJson, replayPayload.payloadFingerprint, now, now, tenantId, workspaceId, sourceClientId, operationId, recoveryBatchId, sourceClientId, sourceOperationId);
|
|
1796
|
+
`).run(primary.revision.entityRevision, primary.revision.lifecycleRevision, replayPayload.payloadJson, replayPayload.payloadFingerprint, source.canonical_intent_json == null ? null : String(source.canonical_intent_json), now, now, tenantId, workspaceId, sourceClientId, operationId, recoveryBatchId, sourceClientId, sourceOperationId);
|
|
1671
1797
|
if (replayPayload.workflowDependencyCoalesced) {
|
|
1672
1798
|
this.db.prepare(`
|
|
1673
1799
|
UPDATE workspace_sync_outbox
|
|
@@ -2456,9 +2582,15 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
2456
2582
|
})()
|
|
2457
2583
|
: null;
|
|
2458
2584
|
const taskAggregateRootTarget = additionalTargets[0];
|
|
2585
|
+
const queueableTaskReviewHandoff = domain === 'task'
|
|
2586
|
+
&& mutationKind === 'set-status'
|
|
2587
|
+
&& additionalTargets.length === 1
|
|
2588
|
+
&& taskAggregateRootTarget.domain === 'task-comments'
|
|
2589
|
+
&& taskAggregateRootTarget.entityId === entityId
|
|
2590
|
+
&& taskAggregateRootTarget.mutationKind === 'append';
|
|
2459
2591
|
const queueableTaskRoot = domain === 'task'
|
|
2460
2592
|
&& TASK_ROOT_SUCCESSOR_MUTATIONS.has(mutationKind)
|
|
2461
|
-
&& additionalTargets.length === 0;
|
|
2593
|
+
&& (additionalTargets.length === 0 || queueableTaskReviewHandoff);
|
|
2462
2594
|
const queueableTaskAggregate = Boolean(TASK_AGGREGATE_SUCCESSOR_MUTATIONS.get(domain)?.has(mutationKind))
|
|
2463
2595
|
&& ((domain === 'task-comments' && mutationKind === 'reconcile' && additionalTargets.length === 0)
|
|
2464
2596
|
|| (additionalTargets.length === 1
|
|
@@ -2761,7 +2893,20 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
2761
2893
|
for (const target of targets) {
|
|
2762
2894
|
insertTarget.run(ids[0], ids[1], ids[2], ids[3], target.domain, target.entityId, target.mutationKind, target.baseEntityRevision, target.baseLifecycleRevision, target.ownsTaskMetadata ? 1 : 0, target.ownsTaskLifecycle ? 1 : 0, target.ownsTaskAssignee ? 1 : 0, now);
|
|
2763
2895
|
}
|
|
2764
|
-
|
|
2896
|
+
const mutationResult = input.applyLocalMutation();
|
|
2897
|
+
if (input.buildCanonicalIntent) {
|
|
2898
|
+
const canonicalIntentJson = canonicalWorkspaceSyncJson(input.buildCanonicalIntent(mutationResult));
|
|
2899
|
+
const updated = this.db.prepare(`
|
|
2900
|
+
UPDATE workspace_sync_outbox
|
|
2901
|
+
SET canonical_intent_json = ?, updated_at = ?
|
|
2902
|
+
WHERE tenant_id = ? AND workspace_id = ? AND client_id = ? AND operation_id = ?
|
|
2903
|
+
AND status = 'pending'
|
|
2904
|
+
`).run(canonicalIntentJson, now, ...ids);
|
|
2905
|
+
if (Number(updated.changes || 0) !== 1) {
|
|
2906
|
+
throw new Error('Workspace sync canonical intent changed before it was persisted.');
|
|
2907
|
+
}
|
|
2908
|
+
}
|
|
2909
|
+
return { enqueued: true, mutationResult };
|
|
2765
2910
|
}
|
|
2766
2911
|
const existing = this.db.prepare(`
|
|
2767
2912
|
SELECT contract_version, dispatch_class, domain, entity_id, mutation_kind,
|
|
@@ -2772,6 +2917,32 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
2772
2917
|
FROM workspace_sync_outbox
|
|
2773
2918
|
WHERE tenant_id = ? AND workspace_id = ? AND client_id = ? AND operation_id = ?
|
|
2774
2919
|
`).get(...ids);
|
|
2920
|
+
if (existing) {
|
|
2921
|
+
try {
|
|
2922
|
+
const existingPayloadFingerprint = String(existing.payload_fingerprint || '');
|
|
2923
|
+
assertDurableOperationIdentity({
|
|
2924
|
+
operationId: ids[3],
|
|
2925
|
+
domain: String(existing.domain || ''),
|
|
2926
|
+
entityId: String(existing.entity_id || ''),
|
|
2927
|
+
mutationKind: String(existing.mutation_kind || ''),
|
|
2928
|
+
payloadFingerprint: existingPayloadFingerprint,
|
|
2929
|
+
}, {
|
|
2930
|
+
operationId: ids[3],
|
|
2931
|
+
domain,
|
|
2932
|
+
entityId,
|
|
2933
|
+
mutationKind,
|
|
2934
|
+
payloadFingerprint: existingPayloadFingerprint === coalescedWorkflowPayloadFingerprint
|
|
2935
|
+
? coalescedWorkflowPayloadFingerprint
|
|
2936
|
+
: payloadFingerprint,
|
|
2937
|
+
});
|
|
2938
|
+
}
|
|
2939
|
+
catch (error) {
|
|
2940
|
+
if (error instanceof DurableOperationReplayIdentityConflictError) {
|
|
2941
|
+
throw new WorkspaceSyncIdempotencyConflictError();
|
|
2942
|
+
}
|
|
2943
|
+
throw error;
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2775
2946
|
const matches = existing
|
|
2776
2947
|
&& Number(existing.contract_version) === WORKSPACE_SYNC_CONTRACT_VERSION
|
|
2777
2948
|
&& existing.dispatch_class === dispatchClass
|
|
@@ -3891,7 +4062,7 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
3891
4062
|
mutation_kind, owns_task_metadata, owns_task_lifecycle, owns_task_assignee,
|
|
3892
4063
|
CAST(base_entity_revision AS TEXT) AS base_entity_revision,
|
|
3893
4064
|
CAST(base_lifecycle_revision AS TEXT) AS base_lifecycle_revision,
|
|
3894
|
-
payload_json, payload_fingerprint, status, attempt_count,
|
|
4065
|
+
payload_json, payload_fingerprint, canonical_intent_json, status, attempt_count,
|
|
3895
4066
|
initial_not_found_attempt_count,
|
|
3896
4067
|
CAST(enqueue_sequence AS TEXT) AS enqueue_sequence,
|
|
3897
4068
|
rebase_before_first_attempt,
|
|
@@ -4664,6 +4835,9 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
4664
4835
|
workflowDependencyCoalesced: true,
|
|
4665
4836
|
};
|
|
4666
4837
|
}
|
|
4838
|
+
lockWorkspaceSequenceForMutation(input) {
|
|
4839
|
+
this.allocateSequenceRange(requireText(input.tenantId, 'Tenant id'), requireText(input.workspaceId, 'Workspace id'), requireIsoTimestamp(input.now, 'Lock time'), 0);
|
|
4840
|
+
}
|
|
4667
4841
|
allocateSequenceRange(tenantId, workspaceId, now, count) {
|
|
4668
4842
|
const row = this.db.prepare(`
|
|
4669
4843
|
INSERT INTO workspace_sync_sequences (tenant_id, workspace_id, last_sequence, updated_at)
|
|
@@ -4698,9 +4872,18 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
4698
4872
|
assertMatchingOperation(row, requestFingerprint) {
|
|
4699
4873
|
if (!row)
|
|
4700
4874
|
throw new Error('Workspace sync operation does not exist.');
|
|
4701
|
-
if (Number(row.contract_version) !== WORKSPACE_SYNC_CONTRACT_VERSION
|
|
4875
|
+
if (Number(row.contract_version) !== WORKSPACE_SYNC_CONTRACT_VERSION) {
|
|
4702
4876
|
throw new WorkspaceSyncIdempotencyConflictError();
|
|
4703
4877
|
}
|
|
4878
|
+
try {
|
|
4879
|
+
assertDurableOperationFingerprint(String(row.request_fingerprint || ''), requestFingerprint);
|
|
4880
|
+
}
|
|
4881
|
+
catch (error) {
|
|
4882
|
+
if (error instanceof DurableOperationReplayIdentityConflictError) {
|
|
4883
|
+
throw new WorkspaceSyncIdempotencyConflictError();
|
|
4884
|
+
}
|
|
4885
|
+
throw error;
|
|
4886
|
+
}
|
|
4704
4887
|
}
|
|
4705
4888
|
mapOutboxRow(row) {
|
|
4706
4889
|
return {
|
|
@@ -4719,6 +4902,9 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
4719
4902
|
baseLifecycleRevision: normalizeSequence(row.base_lifecycle_revision),
|
|
4720
4903
|
payloadJson: requireText(row.payload_json, 'Payload'),
|
|
4721
4904
|
payloadFingerprint: requireText(row.payload_fingerprint, 'Payload fingerprint'),
|
|
4905
|
+
canonicalIntentJson: row.canonical_intent_json == null
|
|
4906
|
+
? null
|
|
4907
|
+
: requireText(row.canonical_intent_json, 'Canonical intent'),
|
|
4722
4908
|
status: requireText(row.status, 'Outbox status'),
|
|
4723
4909
|
attemptCount: Number(row.attempt_count || 0),
|
|
4724
4910
|
initialNotFoundAttemptCount: Number(row.initial_not_found_attempt_count || 0),
|
|
@@ -2,15 +2,15 @@ import type { AttachmentItem, TaskEvent, TaskEventDetails, TaskItem } from '../.
|
|
|
2
2
|
import { serializeTaskRootForSync } from './workspaceSyncV3TaskRootProjection.js';
|
|
3
3
|
import { serializeTaskActivityForSync, type WorkspaceSyncActivityRevision } from './taskActivityJournal.js';
|
|
4
4
|
import { WorkspaceSyncDurabilityStore } from './syncDurabilityStore.js';
|
|
5
|
-
import { type WorkspaceSyncV3TaskAttachmentLink, type
|
|
5
|
+
import { type WorkspaceSyncV3TaskAttachmentLink, type WorkspaceSyncV3TaskAttachmentLinksV2Payload } from './workspaceSyncV3NestedTaskCodecs.js';
|
|
6
6
|
export declare class DurableTaskAttachmentLinksMutationError extends Error {
|
|
7
|
-
readonly code: 'TASK_NOT_FOUND' | 'TASK_ARCHIVED_READ_ONLY' | 'TASK_ATTACHMENT_LINKS_INVALID' | 'TASK_ATTACHMENT_LINKS_IDENTITY_CONFLICT' | 'WORKSPACE_SYNC_OPERATION_ID_REQUIRED' | 'TASK_ATTACHMENT_LINKS_DEPENDENCY_PENDING' | 'TASK_ATTACHMENT_ASSET_NOT_READY';
|
|
7
|
+
readonly code: 'TASK_NOT_FOUND' | 'TASK_ARCHIVED_READ_ONLY' | 'TASK_ATTACHMENT_LINKS_INVALID' | 'TASK_ATTACHMENT_LINKS_IDENTITY_CONFLICT' | 'WORKSPACE_SYNC_OPERATION_ID_REQUIRED' | 'TASK_ATTACHMENT_LINKS_DEPENDENCY_PENDING' | 'TASK_ATTACHMENT_ASSET_NOT_READY' | 'TASK_DETAIL_REVISION_CONFLICT';
|
|
8
8
|
readonly statusCode: number;
|
|
9
9
|
readonly details?: Record<string, unknown> | undefined;
|
|
10
10
|
readonly retryable?: boolean | undefined;
|
|
11
11
|
readonly retryAfterAt?: string | undefined;
|
|
12
12
|
readonly retryHint?: string | undefined;
|
|
13
|
-
constructor(message: string, code: 'TASK_NOT_FOUND' | 'TASK_ARCHIVED_READ_ONLY' | 'TASK_ATTACHMENT_LINKS_INVALID' | 'TASK_ATTACHMENT_LINKS_IDENTITY_CONFLICT' | 'WORKSPACE_SYNC_OPERATION_ID_REQUIRED' | 'TASK_ATTACHMENT_LINKS_DEPENDENCY_PENDING' | 'TASK_ATTACHMENT_ASSET_NOT_READY', statusCode: number, details?: Record<string, unknown> | undefined, retryable?: boolean | undefined, retryAfterAt?: string | undefined, retryHint?: string | undefined);
|
|
13
|
+
constructor(message: string, code: 'TASK_NOT_FOUND' | 'TASK_ARCHIVED_READ_ONLY' | 'TASK_ATTACHMENT_LINKS_INVALID' | 'TASK_ATTACHMENT_LINKS_IDENTITY_CONFLICT' | 'WORKSPACE_SYNC_OPERATION_ID_REQUIRED' | 'TASK_ATTACHMENT_LINKS_DEPENDENCY_PENDING' | 'TASK_ATTACHMENT_ASSET_NOT_READY' | 'TASK_DETAIL_REVISION_CONFLICT', statusCode: number, details?: Record<string, unknown> | undefined, retryable?: boolean | undefined, retryAfterAt?: string | undefined, retryHint?: string | undefined);
|
|
14
14
|
}
|
|
15
15
|
export type DurableTaskAttachmentLinksResponse = {
|
|
16
16
|
success: true;
|
|
@@ -37,7 +37,7 @@ export type DurableTaskAttachmentLinksResponse = {
|
|
|
37
37
|
sequence: string;
|
|
38
38
|
entityRevision: string;
|
|
39
39
|
lifecycleRevision: string;
|
|
40
|
-
payload:
|
|
40
|
+
payload: WorkspaceSyncV3TaskAttachmentLinksV2Payload;
|
|
41
41
|
};
|
|
42
42
|
};
|
|
43
43
|
activity: ReturnType<typeof serializeTaskActivityForSync>;
|
|
@@ -108,5 +108,7 @@ export declare function runDurableTaskAttachmentLinksReplace(input: {
|
|
|
108
108
|
actorRef: string;
|
|
109
109
|
resolveActorRef?: () => string;
|
|
110
110
|
originActorRef?: string;
|
|
111
|
+
expectedDetailRevision?: string;
|
|
112
|
+
assertPrecondition?: () => void;
|
|
111
113
|
onPostCommitError?: (error: unknown) => void;
|
|
112
114
|
}): DurableTaskAttachmentLinksMutationResult;
|
|
@@ -3,7 +3,7 @@ import { serializeTaskRootForSync } from './workspaceSyncV3TaskRootProjection.js
|
|
|
3
3
|
import { buildTaskAttachmentLinksActivityEventId } from './taskAttachmentLinksActivityIdentity.js';
|
|
4
4
|
import { asWorkspaceSyncActivityRevision, buildTaskActivityJournalEntry, canonicalizeEntityActivityDetailsForSync, serializeTaskActivityForSync, } from './taskActivityJournal.js';
|
|
5
5
|
import { fingerprintWorkspaceSyncPayload, runReservedWorkspaceSyncV3Operation, WORKSPACE_SYNC_CONTRACT_VERSION, } from './syncDurabilityStore.js';
|
|
6
|
-
import { serializeWorkspaceSyncV3TaskAttachmentLinksPayload, } from './workspaceSyncV3NestedTaskCodecs.js';
|
|
6
|
+
import { serializeWorkspaceSyncV3TaskAttachmentLinksPayload, serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload, } from './workspaceSyncV3NestedTaskCodecs.js';
|
|
7
7
|
import { resolveDeferredMutationActorRef } from './workspaceSyncV3OriginActor.js';
|
|
8
8
|
export class DurableTaskAttachmentLinksMutationError extends Error {
|
|
9
9
|
code;
|
|
@@ -61,6 +61,9 @@ export function runDurableTaskAttachmentLinksReplace(input) {
|
|
|
61
61
|
? { cardCoverAssetId: input.cardCoverAssetId }
|
|
62
62
|
: {}),
|
|
63
63
|
...(input.originActorRef ? { originActorRef: input.originActorRef } : {}),
|
|
64
|
+
...(input.expectedDetailRevision
|
|
65
|
+
? { expectedDetailRevision: input.expectedDetailRevision }
|
|
66
|
+
: {}),
|
|
64
67
|
},
|
|
65
68
|
});
|
|
66
69
|
const activityEventId = buildTaskAttachmentLinksActivityEventId({
|
|
@@ -74,6 +77,16 @@ export function runDurableTaskAttachmentLinksReplace(input) {
|
|
|
74
77
|
throw new Error('Durable task attachment-link activity was not persisted.');
|
|
75
78
|
return activity;
|
|
76
79
|
};
|
|
80
|
+
const readAttachmentPayload = () => {
|
|
81
|
+
const task = input.core.getTask(input.taskId, input.workspaceId);
|
|
82
|
+
if (!task)
|
|
83
|
+
throw new DurableTaskAttachmentLinksMutationError('Task not found.', 'TASK_NOT_FOUND', 404);
|
|
84
|
+
return serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload({
|
|
85
|
+
taskId: input.taskId,
|
|
86
|
+
links: input.core.listTaskAttachmentLinksForDurableSync(input.taskId, input.workspaceId),
|
|
87
|
+
cardCoverAssetId: task.cardCoverAssetId ?? null,
|
|
88
|
+
});
|
|
89
|
+
};
|
|
77
90
|
const result = runReservedWorkspaceSyncV3Operation({
|
|
78
91
|
store: input.store, identity, requestFingerprint,
|
|
79
92
|
now: input.now, leaseExpiresAt: input.leaseExpiresAt, leaseOwner: input.leaseOwner,
|
|
@@ -101,16 +114,11 @@ export function runDurableTaskAttachmentLinksReplace(input) {
|
|
|
101
114
|
}, {
|
|
102
115
|
domain: 'task-attachment-links', entityId: input.taskId, mutationKind: 'replace', revisionKind: 'metadata',
|
|
103
116
|
baseEntityRevision: input.baseEntityRevision, baseLifecycleRevision: input.baseLifecycleRevision,
|
|
104
|
-
buildCanonicalFingerprint: () => fingerprintWorkspaceSyncPayload(
|
|
105
|
-
|
|
106
|
-
links: input.core.listTaskAttachmentLinksForDurableSync(input.taskId, input.workspaceId),
|
|
107
|
-
})),
|
|
108
|
-
buildAuthoritativePayload: () => serializeWorkspaceSyncV3TaskAttachmentLinksPayload({
|
|
109
|
-
taskId: input.taskId,
|
|
110
|
-
links: input.core.listTaskAttachmentLinksForDurableSync(input.taskId, input.workspaceId),
|
|
111
|
-
}),
|
|
117
|
+
buildCanonicalFingerprint: () => fingerprintWorkspaceSyncPayload(readAttachmentPayload()),
|
|
118
|
+
buildAuthoritativePayload: readAttachmentPayload,
|
|
112
119
|
}, buildTaskActivityJournalEntry({ eventId: activityEventId, readEvent: readActivity })],
|
|
113
120
|
applyMutation: () => {
|
|
121
|
+
input.assertPrecondition?.();
|
|
114
122
|
const existing = input.core.getTask(input.taskId, input.workspaceId);
|
|
115
123
|
if (!existing)
|
|
116
124
|
throw new DurableTaskAttachmentLinksMutationError('Task not found.', 'TASK_NOT_FOUND', 404);
|
|
@@ -181,9 +189,10 @@ export function runDurableTaskAttachmentLinksReplace(input) {
|
|
|
181
189
|
sequence: attachmentLinksRevision.sequence,
|
|
182
190
|
entityRevision: attachmentLinksRevision.entityRevision,
|
|
183
191
|
lifecycleRevision: attachmentLinksRevision.lifecycleRevision,
|
|
184
|
-
payload:
|
|
192
|
+
payload: serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload({
|
|
185
193
|
taskId: task.id,
|
|
186
194
|
links: input.core.listTaskAttachmentLinksForDurableSync(task.id, input.workspaceId),
|
|
195
|
+
cardCoverAssetId: task.cardCoverAssetId ?? null,
|
|
187
196
|
}),
|
|
188
197
|
},
|
|
189
198
|
},
|
|
@@ -4,13 +4,13 @@ import { serializeTaskActivityForSync, type WorkspaceSyncActivityRevision } from
|
|
|
4
4
|
import { WorkspaceSyncDurabilityStore } from './syncDurabilityStore.js';
|
|
5
5
|
import { type WorkspaceSyncV3TaskChecklistPayload } from './workspaceSyncV3NestedTaskCodecs.js';
|
|
6
6
|
export declare class DurableTaskChecklistMutationError extends Error {
|
|
7
|
-
readonly code: 'TASK_NOT_FOUND' | 'TASK_ARCHIVED_READ_ONLY' | 'TASK_CHECKLIST_INVALID' | 'TASK_CHECKLIST_IDENTITY_CONFLICT' | 'WORKSPACE_SYNC_OPERATION_ID_REQUIRED' | 'TASK_CHECKLIST_DEPENDENCY_PENDING';
|
|
7
|
+
readonly code: 'TASK_NOT_FOUND' | 'TASK_ARCHIVED_READ_ONLY' | 'TASK_CHECKLIST_INVALID' | 'TASK_CHECKLIST_IDENTITY_CONFLICT' | 'WORKSPACE_SYNC_OPERATION_ID_REQUIRED' | 'TASK_CHECKLIST_DEPENDENCY_PENDING' | 'TASK_DETAIL_REVISION_CONFLICT';
|
|
8
8
|
readonly statusCode: number;
|
|
9
9
|
readonly details?: Record<string, unknown> | undefined;
|
|
10
10
|
readonly retryable?: boolean | undefined;
|
|
11
11
|
readonly retryAfterAt?: string | undefined;
|
|
12
12
|
readonly retryHint?: string | undefined;
|
|
13
|
-
constructor(message: string, code: 'TASK_NOT_FOUND' | 'TASK_ARCHIVED_READ_ONLY' | 'TASK_CHECKLIST_INVALID' | 'TASK_CHECKLIST_IDENTITY_CONFLICT' | 'WORKSPACE_SYNC_OPERATION_ID_REQUIRED' | 'TASK_CHECKLIST_DEPENDENCY_PENDING', statusCode: number, details?: Record<string, unknown> | undefined, retryable?: boolean | undefined, retryAfterAt?: string | undefined, retryHint?: string | undefined);
|
|
13
|
+
constructor(message: string, code: 'TASK_NOT_FOUND' | 'TASK_ARCHIVED_READ_ONLY' | 'TASK_CHECKLIST_INVALID' | 'TASK_CHECKLIST_IDENTITY_CONFLICT' | 'WORKSPACE_SYNC_OPERATION_ID_REQUIRED' | 'TASK_CHECKLIST_DEPENDENCY_PENDING' | 'TASK_DETAIL_REVISION_CONFLICT', statusCode: number, details?: Record<string, unknown> | undefined, retryable?: boolean | undefined, retryAfterAt?: string | undefined, retryHint?: string | undefined);
|
|
14
14
|
}
|
|
15
15
|
export type DurableTaskChecklistResponse = {
|
|
16
16
|
success: true;
|
|
@@ -52,6 +52,16 @@ export type DurableTaskChecklistMutationResult = {
|
|
|
52
52
|
responseJson: string;
|
|
53
53
|
response: DurableTaskChecklistResponse;
|
|
54
54
|
};
|
|
55
|
+
export type TaskChecklistItemUpdateIntent = {
|
|
56
|
+
kind: 'item-update';
|
|
57
|
+
itemId: string;
|
|
58
|
+
patch: {
|
|
59
|
+
text?: string;
|
|
60
|
+
done?: boolean;
|
|
61
|
+
order?: number;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
export declare function validateTaskChecklistItemUpdateIntent(value: unknown): TaskChecklistItemUpdateIntent;
|
|
55
65
|
export interface DurableTaskChecklistServiceCore {
|
|
56
66
|
getTask(id: string, workspaceId?: string): TaskItem | null;
|
|
57
67
|
updateTask(id: string, updates: Partial<TaskItem>, workspaceId?: string, options?: {
|
|
@@ -88,5 +98,8 @@ export declare function runDurableTaskChecklistReplace(input: {
|
|
|
88
98
|
actorRef: string;
|
|
89
99
|
resolveActorRef?: () => string;
|
|
90
100
|
originActorRef?: string;
|
|
101
|
+
expectedDetailRevision?: string;
|
|
102
|
+
itemUpdateIntent?: TaskChecklistItemUpdateIntent;
|
|
103
|
+
assertPrecondition?: () => void;
|
|
91
104
|
onPostCommitError?: (error: unknown) => void;
|
|
92
105
|
}): DurableTaskChecklistMutationResult;
|
|
@@ -22,6 +22,37 @@ export class DurableTaskChecklistMutationError extends Error {
|
|
|
22
22
|
this.name = 'DurableTaskChecklistMutationError';
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
+
export function validateTaskChecklistItemUpdateIntent(value) {
|
|
26
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
27
|
+
throw new DurableTaskChecklistMutationError('Task checklist item update intent is invalid.', 'TASK_CHECKLIST_INVALID', 400);
|
|
28
|
+
}
|
|
29
|
+
const source = value;
|
|
30
|
+
const patch = source.patch;
|
|
31
|
+
if (source.kind !== 'item-update'
|
|
32
|
+
|| Object.keys(source).some((key) => key !== 'kind' && key !== 'itemId' && key !== 'patch')
|
|
33
|
+
|| typeof source.itemId !== 'string' || !source.itemId.trim()
|
|
34
|
+
|| !patch || typeof patch !== 'object' || Array.isArray(patch)) {
|
|
35
|
+
throw new DurableTaskChecklistMutationError('Task checklist item update intent is invalid.', 'TASK_CHECKLIST_INVALID', 400);
|
|
36
|
+
}
|
|
37
|
+
const patchSource = patch;
|
|
38
|
+
if (Object.keys(patchSource).some((key) => key !== 'text' && key !== 'done' && key !== 'order')
|
|
39
|
+
|| Object.keys(patchSource).length === 0
|
|
40
|
+
|| (patchSource.text !== undefined && (typeof patchSource.text !== 'string' || !patchSource.text.trim()))
|
|
41
|
+
|| (patchSource.done !== undefined && typeof patchSource.done !== 'boolean')
|
|
42
|
+
|| (patchSource.order !== undefined
|
|
43
|
+
&& (!Number.isInteger(patchSource.order) || Number(patchSource.order) < 0))) {
|
|
44
|
+
throw new DurableTaskChecklistMutationError('Task checklist item update intent is invalid.', 'TASK_CHECKLIST_INVALID', 400);
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
kind: 'item-update',
|
|
48
|
+
itemId: source.itemId.trim(),
|
|
49
|
+
patch: {
|
|
50
|
+
...(patchSource.text !== undefined ? { text: patchSource.text.trim() } : {}),
|
|
51
|
+
...(patchSource.done !== undefined ? { done: patchSource.done } : {}),
|
|
52
|
+
...(patchSource.order !== undefined ? { order: Number(patchSource.order) } : {}),
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
25
56
|
function canonicalItems(taskId, items) {
|
|
26
57
|
try {
|
|
27
58
|
return serializeWorkspaceSyncV3TaskChecklistPayload({ taskId, items }).items;
|
|
@@ -46,6 +77,18 @@ function revision(revisions, domain) {
|
|
|
46
77
|
}
|
|
47
78
|
export function runDurableTaskChecklistReplace(input) {
|
|
48
79
|
const items = canonicalItems(input.taskId, input.items);
|
|
80
|
+
const itemUpdateIntent = input.itemUpdateIntent
|
|
81
|
+
? validateTaskChecklistItemUpdateIntent(input.itemUpdateIntent)
|
|
82
|
+
: undefined;
|
|
83
|
+
if (itemUpdateIntent) {
|
|
84
|
+
const target = items.find((item) => item.id === itemUpdateIntent.itemId);
|
|
85
|
+
if (!target
|
|
86
|
+
|| (itemUpdateIntent.patch.text !== undefined && target.title !== itemUpdateIntent.patch.text)
|
|
87
|
+
|| (itemUpdateIntent.patch.done !== undefined && target.isCompleted !== itemUpdateIntent.patch.done)
|
|
88
|
+
|| (itemUpdateIntent.patch.order !== undefined && target.order !== itemUpdateIntent.patch.order)) {
|
|
89
|
+
throw new DurableTaskChecklistMutationError('Task checklist item update intent does not match the replacement aggregate.', 'TASK_CHECKLIST_INVALID', 400);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
49
92
|
const identity = {
|
|
50
93
|
tenantId: input.tenantId, workspaceId: input.workspaceId, clientId: input.clientId, operationId: input.operationId,
|
|
51
94
|
};
|
|
@@ -56,8 +99,11 @@ export function runDurableTaskChecklistReplace(input) {
|
|
|
56
99
|
domain: 'task-checklist', entityId: input.taskId, mutationKind: 'replace',
|
|
57
100
|
baseEntityRevision: String(input.baseEntityRevision),
|
|
58
101
|
baseLifecycleRevision: String(input.baseLifecycleRevision),
|
|
59
|
-
items,
|
|
102
|
+
...(itemUpdateIntent ? { itemUpdateIntent } : { items }),
|
|
60
103
|
...(input.originActorRef ? { originActorRef: input.originActorRef } : {}),
|
|
104
|
+
...(input.expectedDetailRevision
|
|
105
|
+
? { expectedDetailRevision: input.expectedDetailRevision }
|
|
106
|
+
: {}),
|
|
61
107
|
},
|
|
62
108
|
});
|
|
63
109
|
const activityEventId = buildTaskChecklistActivityEventId({
|
|
@@ -100,6 +146,7 @@ export function runDurableTaskChecklistReplace(input) {
|
|
|
100
146
|
}),
|
|
101
147
|
}, buildTaskActivityJournalEntry({ eventId: activityEventId, readEvent: readActivity })],
|
|
102
148
|
applyMutation: () => {
|
|
149
|
+
input.assertPrecondition?.();
|
|
103
150
|
const existing = input.core.getTask(input.taskId, input.workspaceId);
|
|
104
151
|
if (!existing)
|
|
105
152
|
throw new DurableTaskChecklistMutationError('Task not found.', 'TASK_NOT_FOUND', 404);
|
|
@@ -2,7 +2,7 @@ import { type DurableTaskCreateMutationCore } from '../../core/TaskDurableCreate
|
|
|
2
2
|
import type { EntityEvent, TaskEvent, TaskItem } from '../../core/Taskforce.js';
|
|
3
3
|
import { serializeTaskForSync } from '../taskSyncPayload.js';
|
|
4
4
|
import type { WorkspaceSyncTaskEventSnapshot } from '../workspaceSyncModel.js';
|
|
5
|
-
import {
|
|
5
|
+
import { serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload, serializeWorkspaceSyncV3TaskChecklistPayload, serializeWorkspaceSyncV3TaskCommentsPayload, type WorkspaceSyncV3TaskAttachmentLink } from './workspaceSyncV3NestedTaskCodecs.js';
|
|
6
6
|
import { type WorkspaceSyncActivityRevision } from './taskActivityJournal.js';
|
|
7
7
|
import { WorkspaceSyncDurabilityStore } from './syncDurabilityStore.js';
|
|
8
8
|
export interface DurableTaskCreateServiceCore extends DurableTaskCreateMutationCore {
|
|
@@ -64,7 +64,7 @@ export type DurableTaskCreateResponse = {
|
|
|
64
64
|
sequence: string;
|
|
65
65
|
entityRevision: string;
|
|
66
66
|
lifecycleRevision: string;
|
|
67
|
-
payload: ReturnType<typeof
|
|
67
|
+
payload: ReturnType<typeof serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload>;
|
|
68
68
|
};
|
|
69
69
|
activity: WorkspaceSyncTaskEventSnapshot;
|
|
70
70
|
activityRevision: WorkspaceSyncActivityRevision;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { applyTaskCreateForDurableSync, assertTaskCreateIdentityAvailable, validateDurableTaskCreateInput, } from '../../core/TaskDurableCreateMutationService.js';
|
|
2
2
|
import { serializeTaskForSync } from '../taskSyncPayload.js';
|
|
3
3
|
import { buildTaskCreateActivityEventId } from './taskCreateActivityIdentity.js';
|
|
4
|
-
import { serializeWorkspaceSyncV3TaskAttachmentLinksPayload, serializeWorkspaceSyncV3TaskChecklistPayload, serializeWorkspaceSyncV3TaskCommentsPayload, } from './workspaceSyncV3NestedTaskCodecs.js';
|
|
4
|
+
import { serializeWorkspaceSyncV3TaskAttachmentLinksPayload, serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload, serializeWorkspaceSyncV3TaskChecklistPayload, serializeWorkspaceSyncV3TaskCommentsPayload, } from './workspaceSyncV3NestedTaskCodecs.js';
|
|
5
5
|
import { asWorkspaceSyncActivityRevision, buildEntityActivityJournalEntry, buildTaskActivityJournalEntry, serializeTaskActivityForSync, } from './taskActivityJournal.js';
|
|
6
6
|
import { fingerprintWorkspaceSyncPayload, WORKSPACE_SYNC_CONTRACT_VERSION, } from './syncDurabilityStore.js';
|
|
7
7
|
function requireZeroBaseRevision(value, label) {
|
|
@@ -151,13 +151,15 @@ export function runDurableTaskCreate(input) {
|
|
|
151
151
|
domain: 'task-attachment-links', entityId: taskId, mutationKind: 'replace', revisionKind: 'metadata',
|
|
152
152
|
baseEntityRevision: 0, baseLifecycleRevision: 0,
|
|
153
153
|
include: () => attachmentLinks.length > 0,
|
|
154
|
-
buildCanonicalFingerprint: (task) => fingerprintWorkspaceSyncPayload(
|
|
154
|
+
buildCanonicalFingerprint: (task) => fingerprintWorkspaceSyncPayload(serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload({
|
|
155
155
|
taskId: task.id,
|
|
156
156
|
links: input.core.listTaskAttachmentLinksForDurableSync(task.id, input.workspaceId),
|
|
157
|
+
cardCoverAssetId: task.cardCoverAssetId ?? null,
|
|
157
158
|
})),
|
|
158
|
-
buildAuthoritativePayload: (task) =>
|
|
159
|
+
buildAuthoritativePayload: (task) => serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload({
|
|
159
160
|
taskId: task.id,
|
|
160
161
|
links: input.core.listTaskAttachmentLinksForDurableSync(task.id, input.workspaceId),
|
|
162
|
+
cardCoverAssetId: task.cardCoverAssetId ?? null,
|
|
161
163
|
}),
|
|
162
164
|
}, buildTaskActivityJournalEntry({ eventId: activityEventId, readEvent: readActivity }), {
|
|
163
165
|
...buildEntityActivityJournalEntry({
|
|
@@ -257,9 +259,10 @@ export function runDurableTaskCreate(input) {
|
|
|
257
259
|
sequence: attachmentRevision.sequence,
|
|
258
260
|
entityRevision: attachmentRevision.entityRevision,
|
|
259
261
|
lifecycleRevision: attachmentRevision.lifecycleRevision,
|
|
260
|
-
payload:
|
|
262
|
+
payload: serializeWorkspaceSyncV3TaskAttachmentLinksV2Payload({
|
|
261
263
|
taskId: task.id,
|
|
262
264
|
links: input.core.listTaskAttachmentLinksForDurableSync(task.id, input.workspaceId),
|
|
265
|
+
cardCoverAssetId: task.cardCoverAssetId ?? null,
|
|
263
266
|
}),
|
|
264
267
|
} } : {}),
|
|
265
268
|
activity: serializeTaskActivityForSync(activity),
|
|
@@ -45,6 +45,7 @@ export interface DurableTaskMetadataServiceCore extends DurableTaskMetadataMutat
|
|
|
45
45
|
workspaceId: string;
|
|
46
46
|
eventId: string;
|
|
47
47
|
}): EntityEvent | null;
|
|
48
|
+
assertTaskDetailRevisionForUpdate?(id: string, expectedDetailRevision: string, workspaceId?: string): void;
|
|
48
49
|
}
|
|
49
50
|
export declare function runDurableTaskMetadataUpdate(input: {
|
|
50
51
|
store: WorkspaceSyncDurabilityStore;
|
|
@@ -67,5 +68,7 @@ export declare function runDurableTaskMetadataUpdate(input: {
|
|
|
67
68
|
originActorRef?: string;
|
|
68
69
|
saveSource?: 'manual' | 'autosave';
|
|
69
70
|
activityAction?: 'task-updated' | 'task-schedule-changed';
|
|
71
|
+
expectedDetailRevision?: string;
|
|
72
|
+
assertPrecondition?: () => void;
|
|
70
73
|
onPostCommitError?: (error: unknown) => void;
|
|
71
74
|
}): DurableTaskMetadataMutationResult;
|