@taskforcehq/taskforce 0.3.327 → 0.3.329
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 +257 -87
- 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/activity/EntityActivityTimeline.js +15 -5
- package/dist/components/context/AttachmentPreviewHost.js +1 -1
- package/dist/components/context/ContextAttachmentManager.d.ts +3 -0
- package/dist/components/context/ContextAttachmentManager.js +116 -20
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
- package/dist/components/features/TaskSettings.d.ts +12 -1
- package/dist/components/features/TaskSettings.js +147 -40
- package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
- package/dist/components/features/planning/PlanningEntitySummary.d.ts +3 -1
- package/dist/components/features/planning/PlanningEntitySummary.js +3 -2
- package/dist/components/features/planning/PlanningLinkPicker.d.ts +3 -1
- package/dist/components/features/planning/PlanningLinkPicker.js +5 -3
- package/dist/components/features/planning/PlanningModule.js +28 -14
- package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
- package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
- package/dist/components/features/planning/PlanningVisualIdentity.d.ts +14 -0
- package/dist/components/features/planning/PlanningVisualIdentity.js +106 -0
- package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
- package/dist/components/features/planning/planningTaskArrangement.js +5 -5
- package/dist/components/features/planning/planningWorkspaceModel.d.ts +11 -0
- package/dist/components/features/taskforceAgentEditorModel.js +3 -1
- package/dist/components/task/TaskActionHeader.d.ts +2 -1
- package/dist/components/task/TaskActionHeader.js +2 -2
- package/dist/components/task/TaskCard.d.ts +5 -0
- package/dist/components/task/TaskCard.js +101 -13
- package/dist/components/task/TaskContextUpload.d.ts +3 -0
- package/dist/components/task/TaskContextUpload.js +2 -2
- package/dist/components/task/TaskForm.d.ts +4 -0
- package/dist/components/task/TaskForm.js +32 -7
- package/dist/components/task/TaskImageReviews.js +28 -19
- 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/TaskStatusActions.js +11 -2
- package/dist/components/task/TaskWorkstreamPicker.js +2 -1
- package/dist/components/ui/DocumentTypeIcon.d.ts +7 -0
- package/dist/components/ui/DocumentTypeIcon.js +8 -0
- package/dist/components/ui/PasswordInput.d.ts +6 -0
- package/dist/components/ui/PasswordInput.js +11 -0
- package/dist/components/ui/TaxonomyDropdown.d.ts +9 -1
- package/dist/components/ui/TaxonomyDropdown.js +30 -3
- 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 +68 -39
- package/dist/components/views/WidgetView.js +10 -7
- package/dist/components/views/panels/PlanningDrawer.d.ts +7 -1
- package/dist/components/views/panels/PlanningDrawer.js +51 -54
- package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
- package/dist/config/envSchema.js +13 -0
- package/dist/config/localServiceCloudTarget.d.ts +10 -0
- package/dist/config/localServiceCloudTarget.js +76 -0
- package/dist/config/localServiceRuntimeContract.d.ts +13 -0
- package/dist/config/localServiceRuntimeContract.js +135 -0
- package/dist/core/AiProfileService.d.ts +1 -0
- package/dist/core/AiProfileService.js +48 -9
- package/dist/core/AttachmentLinkService.js +7 -4
- package/dist/core/DeletedTaskLifecycleService.d.ts +5 -0
- package/dist/core/DeletedTaskLifecycleService.js +55 -3
- package/dist/core/McpTokenService.d.ts +4 -0
- package/dist/core/McpTokenService.js +52 -0
- package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +8 -2
- package/dist/core/TaskAttachmentLinksDurableMutationService.js +51 -18
- package/dist/core/Taskforce.d.ts +124 -2
- package/dist/core/Taskforce.js +1175 -87
- package/dist/core/types.d.ts +8 -1
- package/dist/documentReviews/DocumentReviewCommentStore.d.ts +11 -0
- package/dist/documentReviews/DocumentReviewCommentStore.js +35 -2
- package/dist/documentReviews/service.d.ts +4 -0
- package/dist/documentReviews/service.js +141 -46
- 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/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 +9 -0
- package/dist/hooks/tasks/useTaskFormActions.js +96 -17
- 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/useTaskData.d.ts +10 -1
- package/dist/hooks/useTaskData.js +216 -7
- package/dist/hooks/useTaskMutations.d.ts +10 -2
- package/dist/hooks/useTaskMutations.js +223 -43
- package/dist/hooks/useTaskforce.d.ts +94 -57
- package/dist/hooks/useTaskforce.js +428 -16
- 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/canonicalAssetHelpers.d.ts +13 -0
- package/dist/mcp/canonicalAssetHelpers.js +39 -5
- package/dist/mcp/collaborationRegistrar.js +15 -13
- package/dist/mcp/documentAssetRegistrar.js +60 -44
- package/dist/mcp/documentHelpers.d.ts +1 -0
- package/dist/mcp/documentHelpers.js +7 -3
- package/dist/mcp/localServiceProxy.js +4 -1
- package/dist/mcp/runtime.d.ts +16 -0
- package/dist/mcp/runtime.js +735 -210
- package/dist/mcp/taskAttachmentCommandAdapter.d.ts +2 -0
- package/dist/mcp/taskAttachmentCommandAdapter.js +14 -8
- package/dist/mcp/taskPlanningRegistrar.js +78 -67
- package/dist/mcp/toolCallCompatibility.js +38 -1
- package/dist/mcp/toolCatalog.d.ts +1 -0
- package/dist/mcp/toolRegistry.js +2 -2
- package/dist/migrations/taskSchemaMigrations.js +47 -0
- package/dist/runtime/appGateDefinitions.d.ts +30 -6
- package/dist/runtime/appGateDefinitions.js +6 -6
- package/dist/runtime/appGates.d.ts +12 -13
- package/dist/runtime/appGates.js +29 -13
- package/dist/runtime/nodeAppGates.d.ts +8 -0
- package/dist/runtime/nodeAppGates.js +27 -0
- package/dist/server/appAccess.d.ts +12 -0
- package/dist/server/appAccess.js +21 -0
- package/dist/server/authorizedWorkspaceAccess.d.ts +12 -0
- package/dist/server/authorizedWorkspaceAccess.js +40 -0
- package/dist/server/cloudCollectionRead.d.ts +25 -0
- package/dist/server/cloudCollectionRead.js +120 -0
- package/dist/server/cloudCollectionReadPool.d.ts +52 -0
- package/dist/server/cloudCollectionReadPool.js +140 -0
- package/dist/server/cloudCollectionReadWorker.d.ts +1 -0
- package/dist/server/cloudCollectionReadWorker.js +36 -0
- package/dist/server/index.d.ts +6 -11
- package/dist/server/index.js +67 -42
- package/dist/server/localServiceLease.d.ts +6 -0
- package/dist/server/localServiceLease.js +17 -1
- package/dist/server/localWorkspaceSyncServerRuntime.js +10 -3
- 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.js +1 -0
- package/dist/server/routes/agentRoles.js +3 -2
- package/dist/server/routes/agentSkills.js +3 -2
- package/dist/server/routes/agents.js +118 -16
- package/dist/server/routes/annotatedAttachments.js +3 -2
- package/dist/server/routes/auth.js +3 -1
- package/dist/server/routes/documents.d.ts +5 -2
- package/dist/server/routes/documents.js +160 -13
- package/dist/server/routes/durableTaskHttpRouters.d.ts +11 -2
- package/dist/server/routes/durableTaskHttpRouters.js +2 -2
- package/dist/server/routes/localService.js +4 -0
- package/dist/server/routes/primitives.d.ts +4 -0
- package/dist/server/routes/shared.d.ts +24 -0
- package/dist/server/routes/shared.js +114 -18
- package/dist/server/routes/sync.js +22 -0
- package/dist/server/routes/syncAuxRoutes.js +5 -2
- package/dist/server/routes/syncPullApplyRoutes.js +23 -4
- package/dist/server/routes/syncV3FeedRoutes.js +22 -18
- package/dist/server/routes/syncV3LocalCaptureRoutes.js +48 -4
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
- package/dist/server/routes/syncV3OperationRoutes.js +27 -2
- package/dist/server/routes/tasks.js +299 -97
- package/dist/server/routes/workspaces.js +43 -1
- package/dist/server/routes.js +35 -7
- package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
- package/dist/server/workspaceDeletionAdmission.js +50 -0
- package/dist/service/localServiceCli.js +52 -25
- package/dist/service/localServiceClientLifecycle.js +93 -6
- package/dist/services/codexAppServerModelGateway.d.ts +112 -0
- package/dist/services/codexAppServerModelGateway.js +438 -0
- package/dist/services/taskforceAgentMcpBridge.d.ts +7 -1
- package/dist/services/taskforceAgentMcpBridge.js +23 -3
- package/dist/shared/planningIdentity.d.ts +20 -0
- package/dist/shared/planningIdentity.js +79 -0
- package/dist/shared/taskforceAgentDefinition.js +7 -1
- package/dist/shared/taskforceAgentModels.d.ts +1 -0
- package/dist/shared/taskforceAgentModels.js +30 -1
- package/dist/storage/postgresAdapter.d.ts +20 -3
- package/dist/storage/postgresAdapter.js +110 -14
- package/dist/storage/postgresRequestDiagnostics.d.ts +8 -0
- package/dist/storage/postgresRequestDiagnostics.js +24 -0
- package/dist/storage/postgresWorker.js +13 -4
- package/dist/storage/postgresWorkerProtocol.d.ts +29 -0
- package/dist/storage/postgresWorkerProtocol.js +30 -0
- package/dist/storage/workspaceAssetStore.d.ts +32 -0
- package/dist/storage/workspaceAssetStore.js +70 -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 +17 -0
- package/dist/sync/coordinator/localSyncExecutionPermitStore.js +77 -23
- package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
- package/dist/sync/coordinator/workspaceSyncTransportGateway.js +4 -2
- package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
- package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
- package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +16 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +46 -4
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +51 -11
- package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineTransfers.js +8 -3
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +2 -0
- package/dist/sync/syncApplyHandlers.d.ts +3 -1
- package/dist/sync/syncApplyHandlers.js +29 -0
- package/dist/sync/syncService.d.ts +2 -0
- package/dist/sync/syncService.js +13 -1
- package/dist/sync/taskSyncPayload.d.ts +1 -0
- package/dist/sync/taskSyncPayload.js +6 -0
- package/dist/sync/v3/combinedFeedCapability.js +4 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +3 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +31 -3
- package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -0
- package/dist/sync/v3/durableTaskChecklistMutationRouter.js +4 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +47 -12
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +27 -2
- package/dist/sync/v3/localInitiativeOutboxService.js +4 -2
- package/dist/sync/v3/localOutboxDispatcher.js +5 -1
- package/dist/sync/v3/localTaskAttachmentLinksOutboxHandler.js +12 -2
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +3 -0
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +62 -10
- 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 +2 -0
- package/dist/sync/v3/localTaskStatusOutboxService.js +54 -13
- package/dist/sync/v3/localWorkstreamOutboxService.js +4 -2
- package/dist/sync/v3/syncDurabilityStore.d.ts +15 -0
- package/dist/sync/v3/syncDurabilityStore.js +201 -43
- package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +7 -4
- package/dist/sync/v3/taskAttachmentLinksMutationService.js +37 -12
- package/dist/sync/v3/taskChecklistMutationService.d.ts +4 -2
- package/dist/sync/v3/taskChecklistMutationService.js +4 -0
- package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
- package/dist/sync/v3/taskCreateMutationService.js +7 -4
- package/dist/sync/v3/taskMetadataCoexistence.js +4 -0
- 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 +2 -0
- package/dist/sync/v3/taskStatusMutationService.js +4 -0
- package/dist/sync/v3/workflowAssignmentSync.d.ts +1 -0
- package/dist/sync/v3/workflowAssignmentSync.js +3 -0
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +14 -12
- 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.js +10 -1
- package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +15 -4
- package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +66 -13
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +11 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +57 -22
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +10 -4
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +124 -51
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +120 -28
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +3 -1
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +18 -0
- package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -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 +3 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +19 -7
- package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.js +10 -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/workspaceSyncV3TaskRootProjection.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV3TaskRootProjection.js +1 -1
- package/dist/sync/workspacePullFeed.d.ts +6 -1
- package/dist/sync/workspacePullFeed.js +174 -162
- package/dist/sync/workspaceRepair.d.ts +3 -0
- package/dist/sync/workspaceRepair.js +67 -6
- package/dist/sync/workspaceSyncModel.d.ts +11 -0
- package/dist/sync/workspaceSyncModel.js +27 -2
- package/dist/types.d.ts +55 -1
- package/dist/types.js +6 -0
- package/dist/ui/assets/{AiIdentityRosterCard-DB1BLO_j.js → AiIdentityRosterCard-BZM4aQnM.js} +1 -1
- package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-B68Wg-RV.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
- package/dist/ui/assets/AssetTraySortControl-C8Rztyal.js +1 -0
- package/dist/ui/assets/ContextAttachmentManager-Cj3c7X9y.js +3 -0
- package/dist/ui/assets/{DocumentWorkspace-BC7sy5TG.js → DocumentWorkspace-B5uvzems.js} +4 -4
- package/dist/ui/assets/EntityActivityTimeline-BVFvCB5R.js +1 -0
- package/dist/ui/assets/PlanningModule-B5DWQOGz.js +1 -0
- package/dist/ui/assets/PlanningModule-CoIR9hbV.css +1 -0
- package/dist/ui/assets/PlansPage-AY4cGWco.js +1 -0
- package/dist/ui/assets/TaskContextUpload-DZxTVesW.js +1 -0
- package/dist/ui/assets/TaskContextUpload-qmBeUw3u.css +1 -0
- package/dist/ui/assets/TaskSettings-BeWAuyZj.js +12 -0
- package/dist/ui/assets/{TaskforceAgentsModule-CkAxW19K.js → TaskforceAgentsModule-BifCYtjR.js} +6 -6
- package/dist/ui/assets/WorkflowManagerModule-DEr5di_r.js +1 -0
- package/dist/ui/assets/index-I5zhdtgt.js +7 -0
- package/dist/ui/assets/index-VRFsx3wz.css +1 -0
- package/dist/ui/assets/{vendor-icons-B8ZNsH1g.js → vendor-icons-D9Lpw-j4.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/utils/constants.d.ts +2 -2
- package/dist/utils/constants.js +1 -1
- package/dist/utils/contextAttachmentUpload.d.ts +2 -0
- package/dist/utils/contextAttachmentUpload.js +7 -0
- package/dist/utils/contextFiles.d.ts +1 -1
- package/dist/utils/contextFiles.js +4 -4
- 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/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/package.json +21 -4
- package/dist/ui/assets/AiProfilesModule-DPxQeF9N.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-DHNYaNg6.js +0 -3
- package/dist/ui/assets/AssetTraySortControl-DphbyHVc.js +0 -1
- package/dist/ui/assets/ContextAttachmentManager-CMxSzHqc.js +0 -3
- package/dist/ui/assets/EntityActivityTimeline-pJ2ZjZ-k.js +0 -1
- package/dist/ui/assets/PlanningModule-CeTqXMMz.css +0 -1
- package/dist/ui/assets/PlanningModule-t5GbvVR9.js +0 -1
- package/dist/ui/assets/PlansPage-BVH_NfgT.js +0 -1
- package/dist/ui/assets/TaskContextUpload-Ds4LnDzV.css +0 -1
- package/dist/ui/assets/TaskContextUpload-bl4fOOUz.js +0 -1
- package/dist/ui/assets/TaskSettings-xVsxSa0g.js +0 -12
- package/dist/ui/assets/WorkflowManagerModule-BKqIGVnF.js +0 -1
- package/dist/ui/assets/index-BzJlVnNS.css +0 -1
- package/dist/ui/assets/index-Cx7vZJHL.js +0 -7
|
@@ -80,6 +80,7 @@ export type WorkspaceSyncOutboxRecord = WorkspaceSyncOperationIdentity & {
|
|
|
80
80
|
baseLifecycleRevision: string;
|
|
81
81
|
payloadJson: string;
|
|
82
82
|
payloadFingerprint: string;
|
|
83
|
+
canonicalIntentJson: string | null;
|
|
83
84
|
status: string;
|
|
84
85
|
attemptCount: number;
|
|
85
86
|
initialNotFoundAttemptCount: number;
|
|
@@ -152,6 +153,9 @@ export type WorkspaceSyncDomainCoexistenceTarget = {
|
|
|
152
153
|
domain: string;
|
|
153
154
|
entityId: string;
|
|
154
155
|
};
|
|
156
|
+
export type WorkspaceSyncRecoveryBaselineTarget = WorkspaceSyncDomainCoexistenceTarget & {
|
|
157
|
+
required: boolean;
|
|
158
|
+
};
|
|
155
159
|
export type WorkspaceSyncPlanningRevisionProjection = {
|
|
156
160
|
entityId: string;
|
|
157
161
|
coexistenceOwned: boolean;
|
|
@@ -374,6 +378,11 @@ export declare class WorkspaceSyncDurabilityStore {
|
|
|
374
378
|
workspaceId: string;
|
|
375
379
|
recoveryBatchId: string;
|
|
376
380
|
}): WorkspaceSyncDomainCoexistenceTarget[];
|
|
381
|
+
listOutboxRecoveryBaselineTargets(input: {
|
|
382
|
+
tenantId: string;
|
|
383
|
+
workspaceId: string;
|
|
384
|
+
recoveryBatchId: string;
|
|
385
|
+
}): WorkspaceSyncRecoveryBaselineTarget[];
|
|
377
386
|
prepareTaskRootOutboxRecoveryReplay(input: {
|
|
378
387
|
tenantId: string;
|
|
379
388
|
workspaceId: string;
|
|
@@ -534,6 +543,7 @@ export declare class WorkspaceSyncDurabilityStore {
|
|
|
534
543
|
queuedTaskSuccessor?: boolean;
|
|
535
544
|
queuedWorkflowRuntimeSuccessor?: boolean;
|
|
536
545
|
coalesceWorkflowAssignmentExecutionId?: string;
|
|
546
|
+
buildCanonicalIntent?: (mutationResult: T) => unknown;
|
|
537
547
|
}): {
|
|
538
548
|
enqueued: boolean;
|
|
539
549
|
mutationResult?: T;
|
|
@@ -752,6 +762,11 @@ export declare class WorkspaceSyncDurabilityStore {
|
|
|
752
762
|
private assertTaskCommentAppendRecoveryEventOwned;
|
|
753
763
|
private isTaskCommentAppendRecoveryIntentSatisfied;
|
|
754
764
|
private prepareTaskRecoveryPayload;
|
|
765
|
+
lockWorkspaceSequenceForMutation(input: {
|
|
766
|
+
tenantId: string;
|
|
767
|
+
workspaceId: string;
|
|
768
|
+
now: string;
|
|
769
|
+
}): void;
|
|
755
770
|
private allocateSequenceRange;
|
|
756
771
|
private allocateOutboxEnqueueSequence;
|
|
757
772
|
private readOperationRow;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'crypto';
|
|
2
2
|
import { normalizePlanningComments, } from '../planningCanonicalFields.js';
|
|
3
3
|
import { canonicalWorkspaceSyncJson } from './canonicalWorkspaceSyncJson.js';
|
|
4
|
-
import {
|
|
4
|
+
import { buildTaskAttachmentLinksActivityEventId } from './taskAttachmentLinksActivityIdentity.js';
|
|
5
5
|
import { buildTaskCommentActivityEventId } from './taskCommentActivityIdentity.js';
|
|
6
|
+
import { buildTaskCreateActivityEventId } from './taskCreateActivityIdentity.js';
|
|
6
7
|
import { buildTaskLifecycleActivityEventId, } from './taskLifecycleActivityIdentity.js';
|
|
7
8
|
import { buildTaskMetadataActivityEventId } from './taskMetadataActivityIdentity.js';
|
|
8
9
|
import { parseWorkspaceSyncV3OriginActor } from './workspaceSyncV3OriginActor.js';
|
|
@@ -251,7 +252,8 @@ export function hasCompletedRecoveryForSupersededEntityEvent(db, input) {
|
|
|
251
252
|
if (entityType !== 'task')
|
|
252
253
|
return false;
|
|
253
254
|
const sources = db.prepare(`
|
|
254
|
-
SELECT source.client_id, source.operation_id, source.mutation_kind
|
|
255
|
+
SELECT source.client_id, source.operation_id, source.domain, source.mutation_kind,
|
|
256
|
+
source.last_error_code
|
|
255
257
|
FROM workspace_sync_outbox AS source
|
|
256
258
|
INNER JOIN workspace_sync_outbox_recoveries AS recovery
|
|
257
259
|
ON recovery.tenant_id = source.tenant_id
|
|
@@ -259,7 +261,7 @@ export function hasCompletedRecoveryForSupersededEntityEvent(db, input) {
|
|
|
259
261
|
AND recovery.recovery_batch_id = source.recovery_batch_id
|
|
260
262
|
WHERE source.tenant_id = ?
|
|
261
263
|
AND source.workspace_id = ?
|
|
262
|
-
AND source.domain
|
|
264
|
+
AND source.domain IN ('task', 'task-attachment-links')
|
|
263
265
|
AND source.entity_id = ?
|
|
264
266
|
AND source.status = 'superseded'
|
|
265
267
|
AND recovery.state = 'completed'
|
|
@@ -268,9 +270,19 @@ export function hasCompletedRecoveryForSupersededEntityEvent(db, input) {
|
|
|
268
270
|
return sources.some((source) => {
|
|
269
271
|
const clientId = String(source.client_id || '').trim();
|
|
270
272
|
const operationId = String(source.operation_id || '').trim();
|
|
273
|
+
const domain = String(source.domain || '').trim();
|
|
271
274
|
const mutationKind = String(source.mutation_kind || '').trim();
|
|
272
275
|
if (!clientId || !operationId)
|
|
273
276
|
return false;
|
|
277
|
+
if (domain === 'task-attachment-links'
|
|
278
|
+
&& mutationKind === 'replace'
|
|
279
|
+
&& String(source.last_error_code || '') === 'WORKSPACE_SYNC_AUTHORITATIVE_RESPONSE_INVALID') {
|
|
280
|
+
return buildTaskAttachmentLinksActivityEventId({
|
|
281
|
+
workspaceId, clientId, operationId, taskId: entityId,
|
|
282
|
+
}) === eventId;
|
|
283
|
+
}
|
|
284
|
+
if (domain !== 'task')
|
|
285
|
+
return false;
|
|
274
286
|
if (mutationKind === 'create') {
|
|
275
287
|
return buildTaskCreateActivityEventId({
|
|
276
288
|
workspaceId, clientId, operationId, taskId: entityId,
|
|
@@ -779,7 +791,7 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
779
791
|
mutation_kind, owns_task_metadata, owns_task_lifecycle, owns_task_assignee,
|
|
780
792
|
CAST(base_entity_revision AS TEXT) AS base_entity_revision,
|
|
781
793
|
CAST(base_lifecycle_revision AS TEXT) AS base_lifecycle_revision,
|
|
782
|
-
payload_json, payload_fingerprint, status, attempt_count,
|
|
794
|
+
payload_json, payload_fingerprint, canonical_intent_json, status, attempt_count,
|
|
783
795
|
initial_not_found_attempt_count,
|
|
784
796
|
CAST(enqueue_sequence AS TEXT) AS enqueue_sequence,
|
|
785
797
|
rebase_before_first_attempt, lease_owner, lease_expires_at
|
|
@@ -835,7 +847,7 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
835
847
|
mutation_kind, owns_task_metadata, owns_task_lifecycle, owns_task_assignee,
|
|
836
848
|
CAST(base_entity_revision AS TEXT) AS base_entity_revision,
|
|
837
849
|
CAST(base_lifecycle_revision AS TEXT) AS base_lifecycle_revision,
|
|
838
|
-
payload_json, payload_fingerprint, status, attempt_count,
|
|
850
|
+
payload_json, payload_fingerprint, canonical_intent_json, status, attempt_count,
|
|
839
851
|
initial_not_found_attempt_count,
|
|
840
852
|
CAST(enqueue_sequence AS TEXT) AS enqueue_sequence,
|
|
841
853
|
rebase_before_first_attempt, lease_owner, lease_expires_at
|
|
@@ -1016,7 +1028,7 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1016
1028
|
mutation_kind, owns_task_metadata, owns_task_lifecycle, owns_task_assignee,
|
|
1017
1029
|
CAST(base_entity_revision AS TEXT) AS base_entity_revision,
|
|
1018
1030
|
CAST(base_lifecycle_revision AS TEXT) AS base_lifecycle_revision,
|
|
1019
|
-
payload_json, payload_fingerprint, status, attempt_count,
|
|
1031
|
+
payload_json, payload_fingerprint, canonical_intent_json, status, attempt_count,
|
|
1020
1032
|
initial_not_found_attempt_count,
|
|
1021
1033
|
CAST(enqueue_sequence AS TEXT) AS enqueue_sequence,
|
|
1022
1034
|
rebase_before_first_attempt, lease_owner, lease_expires_at
|
|
@@ -1283,11 +1295,16 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1283
1295
|
})();
|
|
1284
1296
|
}
|
|
1285
1297
|
listOutboxRecoveryTargets(input) {
|
|
1298
|
+
return this.listOutboxRecoveryBaselineTargets(input).map(({ domain, entityId }) => ({ domain, entityId }));
|
|
1299
|
+
}
|
|
1300
|
+
listOutboxRecoveryBaselineTargets(input) {
|
|
1286
1301
|
const tenantId = requireText(input.tenantId, 'Tenant id');
|
|
1287
1302
|
const workspaceId = requireText(input.workspaceId, 'Workspace id');
|
|
1288
1303
|
const recoveryBatchId = requireText(input.recoveryBatchId, 'Recovery batch id');
|
|
1289
1304
|
const rows = this.db.prepare(`
|
|
1290
|
-
SELECT
|
|
1305
|
+
SELECT target.domain, target.entity_id,
|
|
1306
|
+
source.dispatch_class, source.domain AS source_domain,
|
|
1307
|
+
source.mutation_kind AS source_mutation_kind
|
|
1291
1308
|
FROM workspace_sync_outbox AS source
|
|
1292
1309
|
INNER JOIN workspace_sync_outbox_targets AS target
|
|
1293
1310
|
ON target.tenant_id = source.tenant_id
|
|
@@ -1298,14 +1315,52 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1298
1315
|
AND source.recovery_batch_id = ?
|
|
1299
1316
|
AND source.status = 'superseded'
|
|
1300
1317
|
AND source.replay_of_operation_id IS NULL
|
|
1301
|
-
ORDER BY target.domain, target.entity_id
|
|
1318
|
+
ORDER BY target.domain, target.entity_id, source.enqueue_sequence, source.operation_id
|
|
1302
1319
|
`).all(tenantId, workspaceId, recoveryBatchId);
|
|
1303
|
-
|
|
1320
|
+
const targets = new Map();
|
|
1321
|
+
for (const row of rows) {
|
|
1322
|
+
const domain = requireText(row.domain, 'Recovery target domain');
|
|
1323
|
+
const entityId = requireText(row.entity_id, 'Recovery target entity id');
|
|
1324
|
+
const key = `${domain}\0${entityId}`;
|
|
1325
|
+
const legacyAdoptionEvent = domain === 'entity-event'
|
|
1326
|
+
&& row.dispatch_class === 'legacy-adoption'
|
|
1327
|
+
&& row.source_domain === 'entity-event'
|
|
1328
|
+
&& row.source_mutation_kind === 'adopt-legacy-batch';
|
|
1329
|
+
const existing = targets.get(key);
|
|
1330
|
+
targets.set(key, {
|
|
1331
|
+
domain,
|
|
1332
|
+
entityId,
|
|
1333
|
+
required: Boolean(existing?.required || !legacyAdoptionEvent),
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
1336
|
+
const attachmentSources = this.db.prepare(`
|
|
1337
|
+
SELECT source.client_id, source.operation_id, source.entity_id
|
|
1338
|
+
FROM workspace_sync_outbox AS source
|
|
1339
|
+
WHERE source.tenant_id = ? AND source.workspace_id = ?
|
|
1340
|
+
AND source.recovery_batch_id = ?
|
|
1341
|
+
AND source.status = 'superseded'
|
|
1342
|
+
AND source.replay_of_operation_id IS NULL
|
|
1343
|
+
AND source.domain = 'task-attachment-links'
|
|
1344
|
+
AND source.mutation_kind = 'replace'
|
|
1345
|
+
AND source.last_error_code = 'WORKSPACE_SYNC_AUTHORITATIVE_RESPONSE_INVALID'
|
|
1346
|
+
`).all(tenantId, workspaceId, recoveryBatchId);
|
|
1347
|
+
for (const source of attachmentSources) {
|
|
1348
|
+
const target = {
|
|
1349
|
+
domain: 'entity-event',
|
|
1350
|
+
entityId: buildTaskAttachmentLinksActivityEventId({
|
|
1351
|
+
workspaceId,
|
|
1352
|
+
clientId: requireText(source.client_id, 'Recovery client id'),
|
|
1353
|
+
operationId: requireText(source.operation_id, 'Recovery operation id'),
|
|
1354
|
+
taskId: requireText(source.entity_id, 'Recovery task id'),
|
|
1355
|
+
}),
|
|
1356
|
+
required: true,
|
|
1357
|
+
};
|
|
1358
|
+
targets.set(`${target.domain}\0${target.entityId}`, target);
|
|
1359
|
+
}
|
|
1360
|
+
const deduplicated = [...targets.values()].sort((left, right) => (compareCodeUnits(left.domain, right.domain) || compareCodeUnits(left.entityId, right.entityId)));
|
|
1361
|
+
if (deduplicated.length === 0)
|
|
1304
1362
|
throw new Error('Workspace sync recovery snapshot has no targets.');
|
|
1305
|
-
return
|
|
1306
|
-
domain: requireText(row.domain, 'Recovery target domain'),
|
|
1307
|
-
entityId: requireText(row.entity_id, 'Recovery target entity id'),
|
|
1308
|
-
}));
|
|
1363
|
+
return deduplicated;
|
|
1309
1364
|
}
|
|
1310
1365
|
prepareTaskRootOutboxRecoveryReplay(input) {
|
|
1311
1366
|
const tenantId = requireText(input.tenantId, 'Tenant id');
|
|
@@ -1341,7 +1396,8 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1341
1396
|
const recoverySources = this.db.prepare(`
|
|
1342
1397
|
SELECT client_id, operation_id, dispatch_class, domain, entity_id, mutation_kind,
|
|
1343
1398
|
owns_task_metadata, owns_task_lifecycle, owns_task_assignee,
|
|
1344
|
-
payload_json, payload_fingerprint,
|
|
1399
|
+
payload_json, payload_fingerprint, canonical_intent_json,
|
|
1400
|
+
last_error_code, last_error_message,
|
|
1345
1401
|
EXISTS (
|
|
1346
1402
|
SELECT 1
|
|
1347
1403
|
FROM workspace_sync_outbox AS replay_candidate
|
|
@@ -1395,6 +1451,34 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1395
1451
|
this.readEntityEventLegacyAdoptionRecoveryIntent(workspaceId, source);
|
|
1396
1452
|
}
|
|
1397
1453
|
}
|
|
1454
|
+
const recoverySourceKey = (source) => (`${requireText(source.client_id, 'Source client id')}\0${requireText(source.operation_id, 'Source operation id')}`);
|
|
1455
|
+
const legacyAdoptionEventsBySource = new Map();
|
|
1456
|
+
const latestLegacyAdoptionSourceByEvent = new Map();
|
|
1457
|
+
for (const source of recoverySources) {
|
|
1458
|
+
if (source.dispatch_class !== 'legacy-adoption'
|
|
1459
|
+
|| source.domain !== 'entity-event'
|
|
1460
|
+
|| source.mutation_kind !== 'adopt-legacy-batch')
|
|
1461
|
+
continue;
|
|
1462
|
+
const sourceKey = recoverySourceKey(source);
|
|
1463
|
+
const events = this.readEntityEventLegacyAdoptionRecoveryIntent(workspaceId, source).events;
|
|
1464
|
+
legacyAdoptionEventsBySource.set(sourceKey, events);
|
|
1465
|
+
for (const event of events)
|
|
1466
|
+
latestLegacyAdoptionSourceByEvent.set(event.id, sourceKey);
|
|
1467
|
+
}
|
|
1468
|
+
const legacyAdoptionReplayEventsBySource = new Map();
|
|
1469
|
+
for (const [sourceKey, events] of legacyAdoptionEventsBySource) {
|
|
1470
|
+
legacyAdoptionReplayEventsBySource.set(sourceKey, events.filter((event) => {
|
|
1471
|
+
if (latestLegacyAdoptionSourceByEvent.get(event.id) !== sourceKey)
|
|
1472
|
+
return false;
|
|
1473
|
+
const revision = this.readEntityRevisionCoordinates({
|
|
1474
|
+
tenantId,
|
|
1475
|
+
workspaceId,
|
|
1476
|
+
domain: 'entity-event',
|
|
1477
|
+
entityId: event.id,
|
|
1478
|
+
});
|
|
1479
|
+
return revision.entityRevision === '0';
|
|
1480
|
+
}));
|
|
1481
|
+
}
|
|
1398
1482
|
const latestAttachmentSourceByEntity = new Map();
|
|
1399
1483
|
for (const source of recoverySources) {
|
|
1400
1484
|
if (source.domain === 'task-attachment-links' && source.mutation_kind === 'replace') {
|
|
@@ -1419,14 +1503,11 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1419
1503
|
if (source.dispatch_class === 'legacy-adoption'
|
|
1420
1504
|
&& source.domain === 'entity-event'
|
|
1421
1505
|
&& source.mutation_kind === 'adopt-legacy-batch') {
|
|
1422
|
-
//
|
|
1423
|
-
//
|
|
1424
|
-
//
|
|
1425
|
-
//
|
|
1426
|
-
|
|
1427
|
-
// identity/revision conflict forever, so the baseline itself
|
|
1428
|
-
// satisfies this migration intent.
|
|
1429
|
-
return false;
|
|
1506
|
+
// The authoritative baseline satisfies events already present in
|
|
1507
|
+
// cloud. A mixed legacy batch may also contain new immutable
|
|
1508
|
+
// events; replay only those still lacking authoritative ownership,
|
|
1509
|
+
// and let the latest overlapping batch own each event once.
|
|
1510
|
+
return (legacyAdoptionReplayEventsBySource.get(recoverySourceKey(source)) || []).length > 0;
|
|
1430
1511
|
}
|
|
1431
1512
|
if (Number(source.baseline_satisfaction_candidate || 0) !== 1) {
|
|
1432
1513
|
return true;
|
|
@@ -1492,7 +1573,22 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1492
1573
|
throw new Error('Workspace sync recovery replay currently supports task-root, task-comment append, '
|
|
1493
1574
|
+ 'task attachment-link, and legacy entity-event adoption intents only.');
|
|
1494
1575
|
}
|
|
1495
|
-
|
|
1576
|
+
const sourceKey = recoverySourceKey(source);
|
|
1577
|
+
if (supportedEntityEventAdoption) {
|
|
1578
|
+
const events = legacyAdoptionReplayEventsBySource.get(sourceKey) || [];
|
|
1579
|
+
if (events.length === 0)
|
|
1580
|
+
throw new Error('Legacy entity-event adoption recovery replay is empty.');
|
|
1581
|
+
const payloadJson = canonicalWorkspaceSyncJson({ events });
|
|
1582
|
+
replayPayloads.set(sourceKey, {
|
|
1583
|
+
payloadJson,
|
|
1584
|
+
payloadFingerprint: fingerprintWorkspaceSyncPayload({ events }),
|
|
1585
|
+
replayMutationKind: 'adopt-legacy-batch',
|
|
1586
|
+
workflowDependencyCoalesced: false,
|
|
1587
|
+
});
|
|
1588
|
+
}
|
|
1589
|
+
else {
|
|
1590
|
+
replayPayloads.set(sourceKey, this.prepareRecoveryPayload(tenantId, workspaceId, source));
|
|
1591
|
+
}
|
|
1496
1592
|
}
|
|
1497
1593
|
for (const source of sources) {
|
|
1498
1594
|
const sourceClientId = requireText(source.client_id, 'Source client id');
|
|
@@ -1512,11 +1608,22 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1512
1608
|
WHERE tenant_id = ? AND workspace_id = ? AND client_id = ? AND operation_id = ?
|
|
1513
1609
|
ORDER BY domain, entity_id
|
|
1514
1610
|
`).all(tenantId, workspaceId, sourceClientId, sourceOperationId);
|
|
1611
|
+
const legacyReplayEvents = source.dispatch_class === 'legacy-adoption'
|
|
1612
|
+
&& source.domain === 'entity-event'
|
|
1613
|
+
&& source.mutation_kind === 'adopt-legacy-batch'
|
|
1614
|
+
? legacyAdoptionReplayEventsBySource.get(recoverySourceKey(source)) || []
|
|
1615
|
+
: null;
|
|
1616
|
+
const replayEventIds = legacyReplayEvents
|
|
1617
|
+
? new Set(legacyReplayEvents.map((event) => event.id))
|
|
1618
|
+
: null;
|
|
1515
1619
|
const replayTargets = source.domain === 'task-comments'
|
|
1516
1620
|
&& source.mutation_kind === 'append'
|
|
1517
1621
|
? sourceTargets.filter((target) => (target.domain === 'task-comments'
|
|
1518
1622
|
&& target.entity_id === source.entity_id))
|
|
1519
|
-
:
|
|
1623
|
+
: replayEventIds
|
|
1624
|
+
? sourceTargets.filter((target) => (target.domain === 'entity-event'
|
|
1625
|
+
&& replayEventIds.has(String(target.entity_id || ''))))
|
|
1626
|
+
: sourceTargets;
|
|
1520
1627
|
if (replayTargets.length === 0)
|
|
1521
1628
|
throw new Error('Workspace sync recovery source has no targets.');
|
|
1522
1629
|
const targetRevisions = replayTargets.map((target) => ({
|
|
@@ -1528,7 +1635,9 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1528
1635
|
entityId: requireText(target.entity_id, 'Target entity id'),
|
|
1529
1636
|
}),
|
|
1530
1637
|
}));
|
|
1531
|
-
const
|
|
1638
|
+
const replayEntityId = legacyReplayEvents?.[0]?.id
|
|
1639
|
+
|| requireText(source.entity_id, 'Source entity id');
|
|
1640
|
+
const primary = targetRevisions.find(({ target }) => (target.domain === source.domain && target.entity_id === replayEntityId));
|
|
1532
1641
|
if (!primary)
|
|
1533
1642
|
throw new Error('Workspace sync recovery source primary target is missing.');
|
|
1534
1643
|
const enqueueSequence = this.allocateOutboxEnqueueSequence(tenantId, workspaceId, now);
|
|
@@ -1538,18 +1647,18 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1538
1647
|
dispatch_class, domain, entity_id, mutation_kind,
|
|
1539
1648
|
owns_task_metadata, owns_task_lifecycle, owns_task_assignee,
|
|
1540
1649
|
base_entity_revision, base_lifecycle_revision,
|
|
1541
|
-
payload_json, payload_fingerprint, status, attempt_count,
|
|
1650
|
+
payload_json, payload_fingerprint, canonical_intent_json, status, attempt_count,
|
|
1542
1651
|
initial_not_found_attempt_count, enqueue_sequence, rebase_before_first_attempt,
|
|
1543
1652
|
next_attempt_at, recovery_batch_id,
|
|
1544
1653
|
replay_of_client_id, replay_of_operation_id, created_at, updated_at
|
|
1545
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending', 0, 0, ?, 1,
|
|
1654
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending', 0, 0, ?, 1,
|
|
1546
1655
|
?, ?, ?, ?, ?, ?)
|
|
1547
1656
|
ON CONFLICT (tenant_id, workspace_id, client_id, operation_id) DO NOTHING
|
|
1548
|
-
`).run(tenantId, workspaceId, operationId, WORKSPACE_SYNC_CONTRACT_VERSION, sourceClientId, requireOutboxDispatchClass(source.dispatch_class), requireText(source.domain, 'Source domain'),
|
|
1657
|
+
`).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);
|
|
1549
1658
|
this.db.prepare(`
|
|
1550
1659
|
UPDATE workspace_sync_outbox
|
|
1551
1660
|
SET base_entity_revision = ?, base_lifecycle_revision = ?,
|
|
1552
|
-
payload_json = ?, payload_fingerprint = ?,
|
|
1661
|
+
payload_json = ?, payload_fingerprint = ?, canonical_intent_json = ?,
|
|
1553
1662
|
status = 'pending', attempt_count = 0, initial_not_found_attempt_count = 0,
|
|
1554
1663
|
rebase_before_first_attempt = 1, next_attempt_at = ?,
|
|
1555
1664
|
lease_owner = NULL, lease_expires_at = NULL,
|
|
@@ -1559,7 +1668,7 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1559
1668
|
WHERE tenant_id = ? AND workspace_id = ? AND client_id = ? AND operation_id = ?
|
|
1560
1669
|
AND recovery_batch_id = ? AND replay_of_client_id = ? AND replay_of_operation_id = ?
|
|
1561
1670
|
AND status = 'superseded'
|
|
1562
|
-
`).run(primary.revision.entityRevision, primary.revision.lifecycleRevision, replayPayload.payloadJson, replayPayload.payloadFingerprint, now, now, tenantId, workspaceId, sourceClientId, operationId, recoveryBatchId, sourceClientId, sourceOperationId);
|
|
1671
|
+
`).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);
|
|
1563
1672
|
if (replayPayload.workflowDependencyCoalesced) {
|
|
1564
1673
|
this.db.prepare(`
|
|
1565
1674
|
UPDATE workspace_sync_outbox
|
|
@@ -1577,7 +1686,7 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1577
1686
|
`).get(tenantId, workspaceId, sourceClientId, operationId);
|
|
1578
1687
|
if (!replayRow
|
|
1579
1688
|
|| replayRow.domain !== source.domain
|
|
1580
|
-
|| replayRow.entity_id !==
|
|
1689
|
+
|| replayRow.entity_id !== replayEntityId
|
|
1581
1690
|
|| replayRow.mutation_kind !== replayPayload.replayMutationKind
|
|
1582
1691
|
|| replayRow.payload_fingerprint !== replayPayload.payloadFingerprint
|
|
1583
1692
|
|| replayRow.recovery_batch_id !== recoveryBatchId
|
|
@@ -1936,9 +2045,15 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1936
2045
|
AND (
|
|
1937
2046
|
(domain = 'task-attachment-links' AND mutation_kind = 'replace')
|
|
1938
2047
|
OR (domain = 'task' AND mutation_kind = 'create')
|
|
2048
|
+
OR (domain = 'workstream' AND mutation_kind IN ('create', 'metadata-update'))
|
|
2049
|
+
OR (domain = 'initiative' AND mutation_kind IN ('create', 'metadata-update'))
|
|
1939
2050
|
)
|
|
1940
2051
|
AND status IN ('pending', 'in_flight')
|
|
1941
|
-
AND last_error_code
|
|
2052
|
+
AND last_error_code IN (
|
|
2053
|
+
'TASK_ATTACHMENT_ASSET_NOT_READY',
|
|
2054
|
+
'WORKSTREAM_ATTACHMENT_NOT_READY',
|
|
2055
|
+
'INITIATIVE_ATTACHMENT_NOT_READY'
|
|
2056
|
+
)
|
|
1942
2057
|
ORDER BY enqueue_sequence
|
|
1943
2058
|
`).all(tenantId, workspaceId, WORKSPACE_SYNC_CONTRACT_VERSION);
|
|
1944
2059
|
const assetIds = new Set();
|
|
@@ -1952,9 +2067,13 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
1952
2067
|
}
|
|
1953
2068
|
if (!payload || typeof payload !== 'object' || Array.isArray(payload))
|
|
1954
2069
|
continue;
|
|
1955
|
-
const
|
|
2070
|
+
const domain = String(row.domain || '');
|
|
2071
|
+
const links = domain === 'task'
|
|
1956
2072
|
? payload.attachmentLinks
|
|
1957
|
-
:
|
|
2073
|
+
: domain === 'task-attachment-links'
|
|
2074
|
+
? payload.links
|
|
2075
|
+
: payload.attachments
|
|
2076
|
+
?? payload.patch?.attachments;
|
|
1958
2077
|
if (!Array.isArray(links))
|
|
1959
2078
|
continue;
|
|
1960
2079
|
for (const link of links) {
|
|
@@ -2643,7 +2762,20 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
2643
2762
|
for (const target of targets) {
|
|
2644
2763
|
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);
|
|
2645
2764
|
}
|
|
2646
|
-
|
|
2765
|
+
const mutationResult = input.applyLocalMutation();
|
|
2766
|
+
if (input.buildCanonicalIntent) {
|
|
2767
|
+
const canonicalIntentJson = canonicalWorkspaceSyncJson(input.buildCanonicalIntent(mutationResult));
|
|
2768
|
+
const updated = this.db.prepare(`
|
|
2769
|
+
UPDATE workspace_sync_outbox
|
|
2770
|
+
SET canonical_intent_json = ?, updated_at = ?
|
|
2771
|
+
WHERE tenant_id = ? AND workspace_id = ? AND client_id = ? AND operation_id = ?
|
|
2772
|
+
AND status = 'pending'
|
|
2773
|
+
`).run(canonicalIntentJson, now, ...ids);
|
|
2774
|
+
if (Number(updated.changes || 0) !== 1) {
|
|
2775
|
+
throw new Error('Workspace sync canonical intent changed before it was persisted.');
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
return { enqueued: true, mutationResult };
|
|
2647
2779
|
}
|
|
2648
2780
|
const existing = this.db.prepare(`
|
|
2649
2781
|
SELECT contract_version, dispatch_class, domain, entity_id, mutation_kind,
|
|
@@ -3268,9 +3400,9 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
3268
3400
|
// Workstream/initiative attachment-only metadata patches are Partial<>
|
|
3269
3401
|
// merges, not full snapshots. The cloud accepts those patches against its
|
|
3270
3402
|
// current revision, so this bounded retry can preserve unrelated concurrent
|
|
3271
|
-
// metadata.
|
|
3272
|
-
//
|
|
3273
|
-
//
|
|
3403
|
+
// metadata. It also covers an idempotent acknowledgement whose revision was
|
|
3404
|
+
// advanced by the prerequisite V2 content push before local installation.
|
|
3405
|
+
// Other metadata patches remain exact-revision operations and are excluded.
|
|
3274
3406
|
requeueBoundedWorkstreamMetadataRevisionConflicts(input) {
|
|
3275
3407
|
const tenantId = requireText(input.tenantId, 'Tenant id');
|
|
3276
3408
|
const workspaceId = requireText(input.workspaceId, 'Workspace id');
|
|
@@ -3285,9 +3417,19 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
3285
3417
|
updated_at = ?
|
|
3286
3418
|
WHERE tenant_id = ? AND workspace_id = ? AND status = 'blocked'
|
|
3287
3419
|
AND domain = 'workstream' AND mutation_kind = 'metadata-update'
|
|
3288
|
-
AND attempt_count = 1
|
|
3289
3420
|
AND workstream_metadata_revision_rebase_count < 1
|
|
3290
|
-
AND
|
|
3421
|
+
AND (
|
|
3422
|
+
(attempt_count = 1 AND last_error_code = 'WORKSPACE_SYNC_REVISION_CONFLICT')
|
|
3423
|
+
OR (
|
|
3424
|
+
last_error_code = 'WORKSPACE_SYNC_AUTHORITATIVE_RESPONSE_INVALID'
|
|
3425
|
+
AND last_error_message = 'Authoritative workstream revisions do not advance the captured bases exactly once.'
|
|
3426
|
+
AND json_type(payload_json, '$.patch.attachments') = 'array'
|
|
3427
|
+
AND NOT EXISTS (
|
|
3428
|
+
SELECT 1 FROM json_each(payload_json, '$.patch')
|
|
3429
|
+
WHERE key <> 'attachments'
|
|
3430
|
+
)
|
|
3431
|
+
)
|
|
3432
|
+
)
|
|
3291
3433
|
`).run(now, now, tenantId, workspaceId);
|
|
3292
3434
|
return Number(result.changes || 0);
|
|
3293
3435
|
}
|
|
@@ -3305,9 +3447,19 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
3305
3447
|
updated_at = ?
|
|
3306
3448
|
WHERE tenant_id = ? AND workspace_id = ? AND status = 'blocked'
|
|
3307
3449
|
AND domain = 'initiative' AND mutation_kind = 'metadata-update'
|
|
3308
|
-
AND attempt_count = 1
|
|
3309
3450
|
AND initiative_metadata_revision_rebase_count < 1
|
|
3310
|
-
AND
|
|
3451
|
+
AND (
|
|
3452
|
+
(attempt_count = 1 AND last_error_code = 'WORKSPACE_SYNC_REVISION_CONFLICT')
|
|
3453
|
+
OR (
|
|
3454
|
+
last_error_code = 'WORKSPACE_SYNC_AUTHORITATIVE_RESPONSE_INVALID'
|
|
3455
|
+
AND last_error_message = 'Authoritative initiative revisions do not advance the captured bases exactly once.'
|
|
3456
|
+
AND json_type(payload_json, '$.patch.attachments') = 'array'
|
|
3457
|
+
AND NOT EXISTS (
|
|
3458
|
+
SELECT 1 FROM json_each(payload_json, '$.patch')
|
|
3459
|
+
WHERE key <> 'attachments'
|
|
3460
|
+
)
|
|
3461
|
+
)
|
|
3462
|
+
)
|
|
3311
3463
|
`).run(now, now, tenantId, workspaceId);
|
|
3312
3464
|
return Number(result.changes || 0);
|
|
3313
3465
|
}
|
|
@@ -3753,7 +3905,7 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
3753
3905
|
mutation_kind, owns_task_metadata, owns_task_lifecycle, owns_task_assignee,
|
|
3754
3906
|
CAST(base_entity_revision AS TEXT) AS base_entity_revision,
|
|
3755
3907
|
CAST(base_lifecycle_revision AS TEXT) AS base_lifecycle_revision,
|
|
3756
|
-
payload_json, payload_fingerprint, status, attempt_count,
|
|
3908
|
+
payload_json, payload_fingerprint, canonical_intent_json, status, attempt_count,
|
|
3757
3909
|
initial_not_found_attempt_count,
|
|
3758
3910
|
CAST(enqueue_sequence AS TEXT) AS enqueue_sequence,
|
|
3759
3911
|
rebase_before_first_attempt,
|
|
@@ -4526,6 +4678,9 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
4526
4678
|
workflowDependencyCoalesced: true,
|
|
4527
4679
|
};
|
|
4528
4680
|
}
|
|
4681
|
+
lockWorkspaceSequenceForMutation(input) {
|
|
4682
|
+
this.allocateSequenceRange(requireText(input.tenantId, 'Tenant id'), requireText(input.workspaceId, 'Workspace id'), requireIsoTimestamp(input.now, 'Lock time'), 0);
|
|
4683
|
+
}
|
|
4529
4684
|
allocateSequenceRange(tenantId, workspaceId, now, count) {
|
|
4530
4685
|
const row = this.db.prepare(`
|
|
4531
4686
|
INSERT INTO workspace_sync_sequences (tenant_id, workspace_id, last_sequence, updated_at)
|
|
@@ -4581,6 +4736,9 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
4581
4736
|
baseLifecycleRevision: normalizeSequence(row.base_lifecycle_revision),
|
|
4582
4737
|
payloadJson: requireText(row.payload_json, 'Payload'),
|
|
4583
4738
|
payloadFingerprint: requireText(row.payload_fingerprint, 'Payload fingerprint'),
|
|
4739
|
+
canonicalIntentJson: row.canonical_intent_json == null
|
|
4740
|
+
? null
|
|
4741
|
+
: requireText(row.canonical_intent_json, 'Canonical intent'),
|
|
4584
4742
|
status: requireText(row.status, 'Outbox status'),
|
|
4585
4743
|
attemptCount: Number(row.attempt_count || 0),
|
|
4586
4744
|
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>;
|
|
@@ -99,6 +99,7 @@ export declare function runDurableTaskAttachmentLinksReplace(input: {
|
|
|
99
99
|
operationId: string;
|
|
100
100
|
taskId: string;
|
|
101
101
|
links: readonly WorkspaceSyncV3TaskAttachmentLink[];
|
|
102
|
+
cardCoverAssetId?: string | null;
|
|
102
103
|
baseEntityRevision: string | number;
|
|
103
104
|
baseLifecycleRevision: string | number;
|
|
104
105
|
now: string;
|
|
@@ -107,5 +108,7 @@ export declare function runDurableTaskAttachmentLinksReplace(input: {
|
|
|
107
108
|
actorRef: string;
|
|
108
109
|
resolveActorRef?: () => string;
|
|
109
110
|
originActorRef?: string;
|
|
111
|
+
expectedDetailRevision?: string;
|
|
112
|
+
assertPrecondition?: () => void;
|
|
110
113
|
onPostCommitError?: (error: unknown) => void;
|
|
111
114
|
}): DurableTaskAttachmentLinksMutationResult;
|