@taskforcehq/taskforce 0.3.329 → 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 +290 -45
- package/dist/components/features/AiProfilesModule.js +3 -5
- package/dist/components/features/TaskSettings.js +70 -14
- package/dist/components/features/TaskforceAgentsModule.d.ts +1 -2
- package/dist/components/features/TaskforceAgentsModule.js +586 -116
- 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/taskforceAgentAssignments/AgentBehaviorAssignments.js +15 -24
- package/dist/components/features/taskforceAgentEditorModel.d.ts +2 -1
- package/dist/components/features/taskforceAgentEditorModel.js +3 -1
- package/dist/components/features/workflowManager/workflowManagerApi.d.ts +1 -1
- package/dist/components/features/workflowManager/workflowManagerApi.js +3 -0
- package/dist/components/task/TaskWorkflowAssignmentField.js +68 -10
- package/dist/components/views/StandaloneLayout.js +27 -26
- 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 +48 -1
- package/dist/core/McpTokenService.d.ts +23 -1
- package/dist/core/McpTokenService.js +93 -10
- 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 +32 -0
- package/dist/core/Taskforce.js +125 -4
- package/dist/core/types.d.ts +8 -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/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/useSyncOrchestrator.d.ts +3 -0
- package/dist/hooks/useSyncOrchestrator.js +111 -2
- package/dist/hooks/useTaskData.d.ts +31 -1
- package/dist/hooks/useTaskData.js +29 -7
- package/dist/hooks/useTaskMutations.d.ts +3 -1
- package/dist/hooks/useTaskMutations.js +46 -12
- package/dist/hooks/useTaskforce.d.ts +2 -0
- package/dist/hooks/useTaskforce.js +11 -2
- package/dist/mcp/clientRegistry.d.ts +2 -2
- package/dist/mcp/clientRegistry.js +1 -1
- package/dist/mcp/documentAssetRegistrar.js +9 -6
- 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 +384 -97
- package/dist/mcp/taskPlanningRegistrar.js +23 -4
- 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 +415 -0
- package/dist/runtime/appGates.d.ts +2 -1
- package/dist/runtime/appGates.js +7 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +108 -11
- package/dist/server/localDatabaseIdentity.js +4 -1
- package/dist/server/localServiceLease.js +2 -1
- package/dist/server/localServiceSessions.d.ts +14 -17
- package/dist/server/localServiceSessions.js +308 -94
- package/dist/server/localWorkspaceSyncServerRuntime.js +12 -14
- package/dist/server/routes/admin.d.ts +4 -0
- package/dist/server/routes/admin.js +112 -3
- package/dist/server/routes/agents.d.ts +7 -0
- package/dist/server/routes/agents.js +277 -24
- package/dist/server/routes/billing.js +5 -1
- package/dist/server/routes/durableTaskHttpRouters.d.ts +2 -0
- 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 +136 -40
- package/dist/server/routes/modelConnections.d.ts +24 -0
- package/dist/server/routes/modelConnections.js +205 -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 +5 -1
- package/dist/server/routes/syncPushRoutes.d.ts +1 -0
- package/dist/server/routes/syncPushRoutes.js +1 -0
- package/dist/server/routes/syncV3FeedRoutes.js +10 -1
- package/dist/server/routes/syncV3OperationRoutes.js +35 -9
- package/dist/server/routes/tasks.js +21 -2
- package/dist/server/routes/workflows.js +9 -1
- package/dist/server/routes.js +59 -0
- package/dist/services/codexAppServerModelGateway.d.ts +54 -5
- package/dist/services/codexAppServerModelGateway.js +246 -21
- 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 +1 -1
- package/dist/services/taskforceAgentMcpBridge.js +7 -24
- 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 -9
- package/dist/shared/taskforceAgentModels.js +7 -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 +4 -0
- package/dist/storage/postgresAdapter.js +11 -0
- package/dist/storage/postgresWorker.js +9 -1
- package/dist/storage/postgresWorkerProtocol.d.ts +1 -0
- package/dist/storage/taskforceAgentConnectionBindingStore.d.ts +31 -0
- package/dist/storage/taskforceAgentConnectionBindingStore.js +84 -0
- package/dist/sync/coordinator/localSyncExecutionPermitStore.js +60 -29
- package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.d.ts +10 -0
- package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.js +29 -0
- 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/workspaceSyncEngineLifecyclePolicy.js +6 -6
- 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/workspaceSyncEngineRuntime.d.ts +1 -0
- package/dist/sync/engine/workspaceSyncEngineRuntime.js +1 -0
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +112 -38
- package/dist/sync/engine/workspaceSyncEngineServerSnapshotReader.js +6 -0
- package/dist/sync/engine/workspaceSyncEngineTransfers.js +3 -1
- 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 +15 -0
- package/dist/sync/syncService.js +83 -18
- package/dist/sync/taskforceAgentSyncAuthorization.d.ts +16 -0
- package/dist/sync/taskforceAgentSyncAuthorization.js +20 -0
- package/dist/sync/v3/combinedFeedCapability.js +4 -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.js +3 -0
- package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -1
- package/dist/sync/v3/durableTaskChecklistMutationRouter.js +58 -15
- package/dist/sync/v3/durableTaskCommentMutationRouter.js +3 -0
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +1 -1
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +10 -0
- 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/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/localTaskStatusOutboxService.d.ts +8 -0
- package/dist/sync/v3/localTaskStatusOutboxService.js +219 -12
- package/dist/sync/v3/syncDurabilityStore.d.ts +34 -0
- package/dist/sync/v3/syncDurabilityStore.js +168 -2
- package/dist/sync/v3/taskChecklistMutationService.d.ts +11 -0
- package/dist/sync/v3/taskChecklistMutationService.js +44 -1
- package/dist/sync/v3/taskStatusMutationService.d.ts +29 -1
- package/dist/sync/v3/taskStatusMutationService.js +119 -3
- package/dist/sync/v3/workflowAssignmentSync.d.ts +5 -0
- package/dist/sync/v3/workflowAssignmentSync.js +27 -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/workspaceSyncV3CloudOperationHandler.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +9 -2
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +44 -32
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +9 -5
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +54 -38
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +70 -31
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +16 -0
- package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
- package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +3 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +5 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +36 -2
- package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.d.ts +17 -0
- package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.js +64 -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/workspaceRepair.d.ts +5 -2
- package/dist/sync/workspaceRepair.js +161 -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/ui/assets/AiIdentityRosterCard-OcSz1PkK.js +1 -0
- package/dist/ui/assets/AiProfilesModule-ByhYW5Xi.js +1 -0
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-B68Wg-RV.js → AnnotatedAttachmentWorkspace-BTM6nIg_.js} +1 -1
- package/dist/ui/assets/{AssetTraySortControl-C8Rztyal.js → AssetTraySortControl-DabEG8L4.js} +1 -1
- package/dist/ui/assets/{ContextAttachmentManager-Cj3c7X9y.js → ContextAttachmentManager-Coa8yVGM.js} +1 -1
- package/dist/ui/assets/{DocumentWorkspace-B5uvzems.js → DocumentWorkspace-BB0qhdix.js} +1 -1
- package/dist/ui/assets/{EntityActivityTimeline-BVFvCB5R.js → EntityActivityTimeline-CZ8x4UJE.js} +1 -1
- package/dist/ui/assets/{PlanningModule-B5DWQOGz.js → PlanningModule-pRPjR7v5.js} +1 -1
- package/dist/ui/assets/{PlansPage-AY4cGWco.js → PlansPage-D86pZSSl.js} +1 -1
- package/dist/ui/assets/{TaskContextUpload-DZxTVesW.js → TaskContextUpload-BVIkU9yT.js} +1 -1
- 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-DEr5di_r.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-D9Lpw-j4.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/taskEvents.d.ts +2 -0
- package/dist/utils/workspaceSyncPresentation.d.ts +1 -1
- package/dist/utils/workspaceSyncPresentation.js +23 -17
- package/package.json +22 -4
- package/dist/ui/assets/AiIdentityRosterCard-BZM4aQnM.js +0 -1
- package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +0 -1
- package/dist/ui/assets/TaskSettings-BeWAuyZj.js +0 -12
- package/dist/ui/assets/TaskforceAgentsModule-BifCYtjR.js +0 -21
- package/dist/ui/assets/TaskforceAgentsModule-D6IC0S7Q.css +0 -1
- package/dist/ui/assets/index-I5zhdtgt.js +0 -7
- package/dist/ui/assets/index-VRFsx3wz.css +0 -1
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { applyTaskStatusMutationForDurableSync, validateDurableTaskStatusMutationPayload, } from '../../core/TaskDurableStatusMutationService.js';
|
|
2
2
|
import { serializeTaskForSync } from '../taskSyncPayload.js';
|
|
3
3
|
import { buildTaskLifecycleActivityEventId } from './taskLifecycleActivityIdentity.js';
|
|
4
|
+
import { buildTaskCommentActivityEventId } from './taskCommentActivityIdentity.js';
|
|
4
5
|
import { validateTaskActivityAuthoritativeRevision } from './taskActivityAuthoritativeRevision.js';
|
|
5
6
|
import { serializeEntityActivityForSync, serializeTaskActivityForSync, WORKSPACE_SYNC_ENTITY_EVENT_APPEND, WORKSPACE_SYNC_ENTITY_EVENT_DOMAIN, } from './taskActivityJournal.js';
|
|
6
7
|
import { fingerprintWorkspaceSyncPayload, } from './syncDurabilityStore.js';
|
|
7
8
|
import { WorkflowStore } from '../../storage/workflowStore.js';
|
|
8
9
|
import { normalizeTaskStatusOperationWithWorkflowAssignment, normalizeWorkflowAssignmentSyncRecord, } from './workflowAssignmentSync.js';
|
|
9
10
|
import { withOriginActorPayload } from './workspaceSyncV3OriginActor.js';
|
|
11
|
+
import { mergeWorkspaceSyncV3TaskCommentsPayload, serializeWorkspaceSyncV3TaskCommentsPayload, } from './workspaceSyncV3NestedTaskCodecs.js';
|
|
12
|
+
import { canonicalWorkspaceSyncJson } from './canonicalWorkspaceSyncJson.js';
|
|
10
13
|
export class LocalAuthoritativeTaskStatusError extends Error {
|
|
11
14
|
code = 'WORKSPACE_SYNC_AUTHORITATIVE_RESPONSE_INVALID';
|
|
12
15
|
constructor(message) {
|
|
@@ -19,6 +22,16 @@ function isCanonicalIso(value) {
|
|
|
19
22
|
&& Number.isFinite(Date.parse(value))
|
|
20
23
|
&& new Date(value).toISOString() === value;
|
|
21
24
|
}
|
|
25
|
+
function nextTaskUpdatedAt(current, requested) {
|
|
26
|
+
const currentMs = Date.parse(current);
|
|
27
|
+
const requestedMs = Date.parse(requested);
|
|
28
|
+
if (!Number.isFinite(requestedMs) || new Date(requestedMs).toISOString() !== requested) {
|
|
29
|
+
throw new LocalAuthoritativeTaskStatusError('Task status operation timestamp is invalid.');
|
|
30
|
+
}
|
|
31
|
+
return Number.isFinite(currentMs) && currentMs >= requestedMs
|
|
32
|
+
? new Date(currentMs + 1).toISOString()
|
|
33
|
+
: requested;
|
|
34
|
+
}
|
|
22
35
|
function normalizeAssignee(value) {
|
|
23
36
|
const normalized = typeof value === 'string' ? value.trim() : '';
|
|
24
37
|
return normalized && normalized.toLowerCase() !== 'unassigned' ? normalized : null;
|
|
@@ -46,13 +59,27 @@ export function enqueueLocalTaskStatusMutation(input) {
|
|
|
46
59
|
const taskId = String(input.taskId || '').trim();
|
|
47
60
|
if (!taskId)
|
|
48
61
|
throw new LocalAuthoritativeTaskStatusError('Task id is required.');
|
|
49
|
-
const
|
|
62
|
+
const operationPayload = normalizeTaskStatusOperationWithWorkflowAssignment(input.payload);
|
|
63
|
+
const statusPayload = validateDurableTaskStatusMutationPayload({
|
|
64
|
+
status: operationPayload.status,
|
|
65
|
+
assigneeIntent: operationPayload.assigneeIntent,
|
|
66
|
+
canceledReason: operationPayload.canceledReason,
|
|
67
|
+
metadataPatch: operationPayload.metadataPatch,
|
|
68
|
+
});
|
|
50
69
|
const assignment = statusPayload.status === 'in-progress'
|
|
51
70
|
? new WorkflowStore(input.core.getDatabaseAdapter(), input.core.getTenantId())
|
|
52
71
|
.getAssignmentForTaskSync(input.identity.workspaceId, taskId)
|
|
53
72
|
: null;
|
|
73
|
+
const reviewHandoff = operationPayload.reviewHandoff ? {
|
|
74
|
+
comment: {
|
|
75
|
+
...operationPayload.reviewHandoff.comment,
|
|
76
|
+
author: input.actorRef,
|
|
77
|
+
submittedAuthor: input.actorRef,
|
|
78
|
+
},
|
|
79
|
+
} : null;
|
|
54
80
|
const payload = {
|
|
55
|
-
...
|
|
81
|
+
...operationPayload,
|
|
82
|
+
...(reviewHandoff ? { reviewHandoff } : {}),
|
|
56
83
|
...(assignment?.execution.status === 'pending' ? { workflowAssignment: assignment } : {}),
|
|
57
84
|
};
|
|
58
85
|
const activityEventId = buildTaskLifecycleActivityEventId({
|
|
@@ -62,6 +89,23 @@ export function enqueueLocalTaskStatusMutation(input) {
|
|
|
62
89
|
taskId,
|
|
63
90
|
mutationKind: 'set-status',
|
|
64
91
|
});
|
|
92
|
+
const reviewComment = payload.reviewHandoff ? {
|
|
93
|
+
...payload.reviewHandoff.comment,
|
|
94
|
+
timestamp: input.now,
|
|
95
|
+
} : null;
|
|
96
|
+
const reviewCommentActivityEventId = reviewComment ? buildTaskCommentActivityEventId({
|
|
97
|
+
workspaceId: input.identity.workspaceId,
|
|
98
|
+
clientId: input.identity.clientId,
|
|
99
|
+
operationId: input.identity.operationId,
|
|
100
|
+
taskId,
|
|
101
|
+
commentId: reviewComment.id,
|
|
102
|
+
}) : null;
|
|
103
|
+
const reviewCommentRevision = reviewComment ? input.store.readEntityRevisionCoordinates({
|
|
104
|
+
tenantId: input.identity.tenantId,
|
|
105
|
+
workspaceId: input.identity.workspaceId,
|
|
106
|
+
domain: 'task-comments',
|
|
107
|
+
entityId: taskId,
|
|
108
|
+
}) : null;
|
|
65
109
|
const result = input.store.enqueueLocalOperation({
|
|
66
110
|
identity: input.identity,
|
|
67
111
|
domain: 'task',
|
|
@@ -74,6 +118,15 @@ export function enqueueLocalTaskStatusMutation(input) {
|
|
|
74
118
|
taskLifecycle: true,
|
|
75
119
|
taskAssignee: payload.assigneeIntent.kind !== 'preserve',
|
|
76
120
|
},
|
|
121
|
+
...(reviewComment ? {
|
|
122
|
+
additionalTargets: [{
|
|
123
|
+
domain: 'task-comments',
|
|
124
|
+
entityId: taskId,
|
|
125
|
+
mutationKind: 'append',
|
|
126
|
+
baseEntityRevision: reviewCommentRevision.entityRevision,
|
|
127
|
+
baseLifecycleRevision: reviewCommentRevision.lifecycleRevision,
|
|
128
|
+
}],
|
|
129
|
+
} : {}),
|
|
77
130
|
payload: withOriginActorPayload({
|
|
78
131
|
...payload,
|
|
79
132
|
...(input.expectedDetailRevision
|
|
@@ -92,7 +145,7 @@ export function enqueueLocalTaskStatusMutation(input) {
|
|
|
92
145
|
}
|
|
93
146
|
input.core.assertTaskDetailRevisionForUpdate(taskId, input.expectedDetailRevision, input.identity.workspaceId);
|
|
94
147
|
}
|
|
95
|
-
|
|
148
|
+
let mutation = applyTaskStatusMutationForDurableSync({
|
|
96
149
|
core: input.core,
|
|
97
150
|
workspaceId: input.identity.workspaceId,
|
|
98
151
|
taskId,
|
|
@@ -104,6 +157,35 @@ export function enqueueLocalTaskStatusMutation(input) {
|
|
|
104
157
|
actorRef: input.actorRef,
|
|
105
158
|
taskEventId: activityEventId,
|
|
106
159
|
});
|
|
160
|
+
if (reviewComment) {
|
|
161
|
+
const comments = serializeWorkspaceSyncV3TaskCommentsPayload({
|
|
162
|
+
taskId,
|
|
163
|
+
comments: mutation.task.comments || [],
|
|
164
|
+
}).comments;
|
|
165
|
+
if (comments.some((comment) => comment.id === reviewComment.id)) {
|
|
166
|
+
throw new LocalAuthoritativeTaskStatusError(`Review handoff comment identity conflict: ${reviewComment.id}.`);
|
|
167
|
+
}
|
|
168
|
+
const updatedAt = nextTaskUpdatedAt(String(mutation.task.updatedAt || mutation.task.createdAt), input.now);
|
|
169
|
+
const updated = input.core.updateTask(taskId, { comments: [...comments, reviewComment] }, input.identity.workspaceId, {
|
|
170
|
+
persistBackup: false,
|
|
171
|
+
emitRealtime: false,
|
|
172
|
+
skipTaskEvents: true,
|
|
173
|
+
syncUpdatedAt: updatedAt,
|
|
174
|
+
allowV3OwnedMetadataWrite: true,
|
|
175
|
+
});
|
|
176
|
+
if (!updated)
|
|
177
|
+
throw new LocalAuthoritativeTaskStatusError('Review handoff task disappeared.');
|
|
178
|
+
input.core.addTaskCommentEventForDurableSync({
|
|
179
|
+
taskId,
|
|
180
|
+
workspaceId: input.identity.workspaceId,
|
|
181
|
+
actor: input.actorRef,
|
|
182
|
+
eventId: reviewCommentActivityEventId,
|
|
183
|
+
createdAt: String(updated.updatedAt),
|
|
184
|
+
comment: reviewComment,
|
|
185
|
+
});
|
|
186
|
+
mutation = { ...mutation, task: updated };
|
|
187
|
+
}
|
|
188
|
+
return mutation;
|
|
107
189
|
},
|
|
108
190
|
buildCanonicalIntent: (result) => ({
|
|
109
191
|
metadataPatch: Object.fromEntries(Object.keys(payload.metadataPatch).map((key) => [
|
|
@@ -117,7 +199,7 @@ export function enqueueLocalTaskStatusMutation(input) {
|
|
|
117
199
|
const mutationResult = result.mutationResult;
|
|
118
200
|
if (!mutationResult)
|
|
119
201
|
throw new LocalAuthoritativeTaskStatusError('Local task status mutation result is missing.');
|
|
120
|
-
if (!mutationResult.noOp) {
|
|
202
|
+
if (!mutationResult.noOp || reviewComment) {
|
|
121
203
|
try {
|
|
122
204
|
input.core.notifyDurableTaskLifecycleCommitted(input.identity.workspaceId, taskId);
|
|
123
205
|
}
|
|
@@ -174,6 +256,66 @@ export function applyAuthoritativeTaskStatusAndAck(input) {
|
|
|
174
256
|
throw new LocalAuthoritativeTaskStatusError('Persisted task status payload fingerprint is invalid.');
|
|
175
257
|
}
|
|
176
258
|
const operationPayload = normalizeTaskStatusOperationWithWorkflowAssignment(persistedPayload);
|
|
259
|
+
const requestedReviewHandoff = operationPayload.reviewHandoff || null;
|
|
260
|
+
const reviewHandoff = response.reviewHandoff || null;
|
|
261
|
+
if (Boolean(requestedReviewHandoff) !== Boolean(reviewHandoff)) {
|
|
262
|
+
throw new LocalAuthoritativeTaskStatusError('Authoritative review handoff presence is invalid.');
|
|
263
|
+
}
|
|
264
|
+
let reviewCommentsPayload = null;
|
|
265
|
+
let reviewCommentActivity = null;
|
|
266
|
+
let reviewCommentTimestamp = null;
|
|
267
|
+
if (requestedReviewHandoff && reviewHandoff) {
|
|
268
|
+
reviewCommentsPayload = serializeWorkspaceSyncV3TaskCommentsPayload({
|
|
269
|
+
taskId: task.id,
|
|
270
|
+
comments: reviewHandoff.comments.payload.comments,
|
|
271
|
+
});
|
|
272
|
+
reviewCommentActivity = reviewHandoff.activity;
|
|
273
|
+
const requestedComment = requestedReviewHandoff.comment;
|
|
274
|
+
const authoritativeComment = reviewCommentsPayload.comments.find((comment) => comment.id === requestedComment.id);
|
|
275
|
+
reviewCommentTimestamp = authoritativeComment?.timestamp || null;
|
|
276
|
+
const expectedActivityId = buildTaskCommentActivityEventId({
|
|
277
|
+
workspaceId: input.identity.workspaceId,
|
|
278
|
+
clientId: input.identity.clientId,
|
|
279
|
+
operationId: input.identity.operationId,
|
|
280
|
+
taskId: task.id,
|
|
281
|
+
commentId: requestedComment.id,
|
|
282
|
+
});
|
|
283
|
+
const reviewCommentActivityDetails = reviewCommentActivity.details;
|
|
284
|
+
if (reviewHandoff.comments.domain !== 'task-comments'
|
|
285
|
+
|| reviewHandoff.comments.entityId !== task.id
|
|
286
|
+
|| reviewHandoff.comments.mutationKind !== 'append'
|
|
287
|
+
|| !/^(0|[1-9]\d*)$/.test(reviewHandoff.comments.sequence)
|
|
288
|
+
|| !/^(0|[1-9]\d*)$/.test(reviewHandoff.comments.entityRevision)
|
|
289
|
+
|| reviewHandoff.comments.lifecycleRevision !== '0'
|
|
290
|
+
|| reviewCommentsPayload.taskId !== task.id
|
|
291
|
+
|| !authoritativeComment
|
|
292
|
+
|| authoritativeComment.author !== requestedComment.author
|
|
293
|
+
|| authoritativeComment.submittedAuthor !== requestedComment.submittedAuthor
|
|
294
|
+
|| authoritativeComment.text !== requestedComment.text
|
|
295
|
+
|| !isCanonicalIso(authoritativeComment.timestamp)
|
|
296
|
+
|| reviewCommentActivity.id !== expectedActivityId
|
|
297
|
+
|| reviewCommentActivity.workspaceId !== input.identity.workspaceId
|
|
298
|
+
|| reviewCommentActivity.entityType !== 'task'
|
|
299
|
+
|| reviewCommentActivity.entityId !== task.id
|
|
300
|
+
|| reviewCommentActivity.taskId !== task.id
|
|
301
|
+
|| reviewCommentActivity.action !== 'task-comment-added'
|
|
302
|
+
|| !String(reviewCommentActivity.actor || '').trim()
|
|
303
|
+
|| !['human', 'ai', 'system'].includes(reviewCommentActivity.actorType)
|
|
304
|
+
|| reviewCommentActivity.createdAt !== task.updatedAt
|
|
305
|
+
|| !reviewCommentActivityDetails
|
|
306
|
+
|| Object.keys(reviewCommentActivityDetails).sort().join(',') !== 'commentId,preview,submittedAuthor'
|
|
307
|
+
|| reviewCommentActivityDetails.commentId !== authoritativeComment.id
|
|
308
|
+
|| reviewCommentActivityDetails.submittedAuthor !== authoritativeComment.submittedAuthor
|
|
309
|
+
|| reviewCommentActivityDetails.preview !== authoritativeComment.text.slice(0, 160)
|
|
310
|
+
|| reviewHandoff.activityRevision.domain !== 'entity-event'
|
|
311
|
+
|| reviewHandoff.activityRevision.entityId !== expectedActivityId
|
|
312
|
+
|| !/^(0|[1-9]\d*)$/.test(reviewHandoff.activityRevision.sequence)
|
|
313
|
+
|| reviewHandoff.activityRevision.entityRevision !== '1'
|
|
314
|
+
|| reviewHandoff.activityRevision.lifecycleRevision !== '0'
|
|
315
|
+
|| canonicalWorkspaceSyncJson(reviewCommentsPayload) !== canonicalWorkspaceSyncJson(serializeWorkspaceSyncV3TaskCommentsPayload({ taskId: task.id, comments: task.comments || [] }))) {
|
|
316
|
+
throw new LocalAuthoritativeTaskStatusError('Authoritative review handoff is invalid.');
|
|
317
|
+
}
|
|
318
|
+
}
|
|
177
319
|
const requestedWorkflowAssignment = operationPayload.workflowAssignment || null;
|
|
178
320
|
const workflowIdentityMismatch = (expected, actual) => expected.template.id !== actual.template.id
|
|
179
321
|
|| expected.version.id !== actual.version.id
|
|
@@ -269,7 +411,7 @@ export function applyAuthoritativeTaskStatusAndAck(input) {
|
|
|
269
411
|
|| activity.taskId !== task.id
|
|
270
412
|
|| activity.action !== 'task-status-changed'
|
|
271
413
|
|| !isCanonicalIso(activity.createdAt)
|
|
272
|
-
|| activity.createdAt !== task.updatedAt
|
|
414
|
+
|| activity.createdAt !== (reviewCommentTimestamp || task.updatedAt)
|
|
273
415
|
|| typeof activity.actor !== 'string' || !activity.actor.trim()
|
|
274
416
|
|| !['human', 'ai', 'system'].includes(activity.actorType)
|
|
275
417
|
|| !activity.details || typeof activity.details !== 'object' || Array.isArray(activity.details)
|
|
@@ -279,12 +421,37 @@ export function applyAuthoritativeTaskStatusAndAck(input) {
|
|
|
279
421
|
throw new LocalAuthoritativeTaskStatusError('Authoritative task status activity is invalid.');
|
|
280
422
|
}
|
|
281
423
|
}
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
424
|
+
const reviewIntermediateRevisions = reviewHandoff ? [
|
|
425
|
+
{ sequence: reviewHandoff.comments.sequence },
|
|
426
|
+
{ sequence: reviewHandoff.activityRevision.sequence },
|
|
427
|
+
] : [];
|
|
428
|
+
const revision = activity === null && reviewHandoff
|
|
429
|
+
? (() => {
|
|
430
|
+
const taskSequence = authoritative.sequence;
|
|
431
|
+
const commentsSequence = reviewHandoff.comments.sequence;
|
|
432
|
+
const commentActivitySequence = reviewHandoff.activityRevision.sequence;
|
|
433
|
+
if (!/^(0|[1-9]\d*)$/.test(taskSequence)
|
|
434
|
+
|| BigInt(commentsSequence) !== BigInt(taskSequence) + 1n
|
|
435
|
+
|| BigInt(commentActivitySequence) !== BigInt(commentsSequence) + 1n
|
|
436
|
+
|| response.operationHighWatermark !== commentActivitySequence
|
|
437
|
+
|| response.dependentActivityRevisions !== undefined) {
|
|
438
|
+
throw new LocalAuthoritativeTaskStatusError('Authoritative review handoff revisions are not in canonical sequence order.');
|
|
439
|
+
}
|
|
440
|
+
return {
|
|
441
|
+
taskSequence,
|
|
442
|
+
operationHighWatermark: commentActivitySequence,
|
|
443
|
+
activityRevision: null,
|
|
444
|
+
legacySingleEntry: false,
|
|
445
|
+
dependentActivityRevisions: [],
|
|
446
|
+
};
|
|
447
|
+
})()
|
|
448
|
+
: validateTaskActivityAuthoritativeRevision({
|
|
449
|
+
response: response,
|
|
450
|
+
authoritative: authoritative,
|
|
451
|
+
activityId: activity?.id || null,
|
|
452
|
+
invalid: (message) => new LocalAuthoritativeTaskStatusError(message),
|
|
453
|
+
intermediateRevisions: reviewIntermediateRevisions,
|
|
454
|
+
});
|
|
288
455
|
const dependentActivities = Array.isArray(response.dependentActivities)
|
|
289
456
|
? response.dependentActivities
|
|
290
457
|
: [];
|
|
@@ -373,7 +540,23 @@ export function applyAuthoritativeTaskStatusAndAck(input) {
|
|
|
373
540
|
canonicalFingerprint,
|
|
374
541
|
metadataOwned: authoritative.metadataOwned,
|
|
375
542
|
reopenAssigneeOwned: authoritative.assigneeOwned,
|
|
376
|
-
}, ...(
|
|
543
|
+
}, ...(reviewHandoff && reviewCommentsPayload && reviewCommentActivity ? [{
|
|
544
|
+
domain: 'task-comments',
|
|
545
|
+
entityId: task.id,
|
|
546
|
+
mutationKind: 'append',
|
|
547
|
+
entityRevision: reviewHandoff.comments.entityRevision,
|
|
548
|
+
lifecycleRevision: reviewHandoff.comments.lifecycleRevision,
|
|
549
|
+
sequence: reviewHandoff.comments.sequence,
|
|
550
|
+
canonicalFingerprint: fingerprintWorkspaceSyncPayload(reviewCommentsPayload),
|
|
551
|
+
}, {
|
|
552
|
+
domain: WORKSPACE_SYNC_ENTITY_EVENT_DOMAIN,
|
|
553
|
+
entityId: reviewCommentActivity.id,
|
|
554
|
+
mutationKind: WORKSPACE_SYNC_ENTITY_EVENT_APPEND,
|
|
555
|
+
entityRevision: reviewHandoff.activityRevision.entityRevision,
|
|
556
|
+
lifecycleRevision: reviewHandoff.activityRevision.lifecycleRevision,
|
|
557
|
+
sequence: reviewHandoff.activityRevision.sequence,
|
|
558
|
+
canonicalFingerprint: fingerprintWorkspaceSyncPayload(serializeTaskActivityForSync(reviewCommentActivity)),
|
|
559
|
+
}] : []), ...(!revision.legacySingleEntry && revision.activityRevision && activity ? [{
|
|
377
560
|
domain: WORKSPACE_SYNC_ENTITY_EVENT_DOMAIN,
|
|
378
561
|
entityId: activity.id,
|
|
379
562
|
mutationKind: WORKSPACE_SYNC_ENTITY_EVENT_APPEND,
|
|
@@ -405,6 +588,30 @@ export function applyAuthoritativeTaskStatusAndAck(input) {
|
|
|
405
588
|
: input.core.installDurableTaskStatusAuthoritativeForSync(task, payload, installAssignee, input.identity.workspaceId);
|
|
406
589
|
if (!updated)
|
|
407
590
|
throw new LocalAuthoritativeTaskStatusError('Local task status projection is missing.');
|
|
591
|
+
if (reviewHandoff && reviewCommentsPayload && reviewCommentActivity) {
|
|
592
|
+
const localComments = serializeWorkspaceSyncV3TaskCommentsPayload({
|
|
593
|
+
taskId: updated.id,
|
|
594
|
+
comments: updated.comments || [],
|
|
595
|
+
});
|
|
596
|
+
const installedComments = hasSuccessor
|
|
597
|
+
? mergeWorkspaceSyncV3TaskCommentsPayload({
|
|
598
|
+
taskId: updated.id,
|
|
599
|
+
left: reviewCommentsPayload.comments,
|
|
600
|
+
right: localComments.comments.filter((comment) => (!reviewCommentsPayload.comments.some((accepted) => accepted.id === comment.id))),
|
|
601
|
+
})
|
|
602
|
+
: reviewCommentsPayload;
|
|
603
|
+
updated = input.core.updateTask(task.id, { comments: installedComments.comments }, input.identity.workspaceId, {
|
|
604
|
+
persistBackup: false,
|
|
605
|
+
emitRealtime: false,
|
|
606
|
+
skipTaskEvents: true,
|
|
607
|
+
syncUpdatedAt: updated.updatedAt,
|
|
608
|
+
allowV3OwnedMetadataWrite: true,
|
|
609
|
+
});
|
|
610
|
+
if (!updated)
|
|
611
|
+
throw new LocalAuthoritativeTaskStatusError('Review handoff task disappeared locally.');
|
|
612
|
+
input.core.upsertEntityEventForSync(reviewCommentActivity, { allowAuthoritativeReplacement: true });
|
|
613
|
+
activityReconciled = true;
|
|
614
|
+
}
|
|
408
615
|
if (hasSuccessor
|
|
409
616
|
&& installAssignee
|
|
410
617
|
&& !successors.some((successor) => successor.ownsTaskAssignee)
|
|
@@ -91,6 +91,15 @@ export type WorkspaceSyncOutboxRecord = WorkspaceSyncOperationIdentity & {
|
|
|
91
91
|
leaseOwner: string | null;
|
|
92
92
|
leaseExpiresAt: string | null;
|
|
93
93
|
};
|
|
94
|
+
export type WorkspaceSyncOutboxOperationLookup = WorkspaceSyncOperationIdentity & {
|
|
95
|
+
status: string;
|
|
96
|
+
createdAt: string;
|
|
97
|
+
domain: string;
|
|
98
|
+
entityId: string;
|
|
99
|
+
mutationKind: string;
|
|
100
|
+
payloadFingerprint: string;
|
|
101
|
+
authoritativeResponseJson: string | null;
|
|
102
|
+
};
|
|
94
103
|
export type WorkspaceSyncOutboxSupersession = {
|
|
95
104
|
recoveryBatchId: string;
|
|
96
105
|
operationIds: string[];
|
|
@@ -325,6 +334,31 @@ export declare class WorkspaceSyncDurabilityStore {
|
|
|
325
334
|
createdAt: string;
|
|
326
335
|
} | null;
|
|
327
336
|
readOutboxOperation(identity: WorkspaceSyncOperationIdentity): WorkspaceSyncOutboxRecord | null;
|
|
337
|
+
assertOutboxOperationIdentity(record: Readonly<WorkspaceSyncOutboxRecord>, expected: {
|
|
338
|
+
domain: string;
|
|
339
|
+
entityId: string;
|
|
340
|
+
mutationKind: string;
|
|
341
|
+
payloadFingerprint?: string;
|
|
342
|
+
}): void;
|
|
343
|
+
readOutboxOperationLookup(identity: WorkspaceSyncOperationIdentity): WorkspaceSyncOutboxOperationLookup | null;
|
|
344
|
+
pruneTerminalOutboxOperations(input: {
|
|
345
|
+
tenantId: string;
|
|
346
|
+
workspaceId: string;
|
|
347
|
+
terminalBefore: string;
|
|
348
|
+
limit?: number;
|
|
349
|
+
}): {
|
|
350
|
+
deleted: number;
|
|
351
|
+
remainingEligible: number;
|
|
352
|
+
};
|
|
353
|
+
pruneCommittedOperationResults(input: {
|
|
354
|
+
tenantId: string;
|
|
355
|
+
workspaceId: string;
|
|
356
|
+
terminalBefore: string;
|
|
357
|
+
limit?: number;
|
|
358
|
+
}): {
|
|
359
|
+
deleted: number;
|
|
360
|
+
remainingEligible: number;
|
|
361
|
+
};
|
|
328
362
|
readV3DispatchSettlementEvidence(identity: WorkspaceSyncOperationIdentity): WorkspaceSyncV3DispatchSettlementEvidence | null;
|
|
329
363
|
listBlockedInvalidOutboxOperations(input: {
|
|
330
364
|
tenantId: string;
|
|
@@ -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;
|
|
@@ -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,
|
|
@@ -2457,9 +2582,15 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
2457
2582
|
})()
|
|
2458
2583
|
: null;
|
|
2459
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';
|
|
2460
2591
|
const queueableTaskRoot = domain === 'task'
|
|
2461
2592
|
&& TASK_ROOT_SUCCESSOR_MUTATIONS.has(mutationKind)
|
|
2462
|
-
&& additionalTargets.length === 0;
|
|
2593
|
+
&& (additionalTargets.length === 0 || queueableTaskReviewHandoff);
|
|
2463
2594
|
const queueableTaskAggregate = Boolean(TASK_AGGREGATE_SUCCESSOR_MUTATIONS.get(domain)?.has(mutationKind))
|
|
2464
2595
|
&& ((domain === 'task-comments' && mutationKind === 'reconcile' && additionalTargets.length === 0)
|
|
2465
2596
|
|| (additionalTargets.length === 1
|
|
@@ -2786,6 +2917,32 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
2786
2917
|
FROM workspace_sync_outbox
|
|
2787
2918
|
WHERE tenant_id = ? AND workspace_id = ? AND client_id = ? AND operation_id = ?
|
|
2788
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
|
+
}
|
|
2789
2946
|
const matches = existing
|
|
2790
2947
|
&& Number(existing.contract_version) === WORKSPACE_SYNC_CONTRACT_VERSION
|
|
2791
2948
|
&& existing.dispatch_class === dispatchClass
|
|
@@ -4715,9 +4872,18 @@ export class WorkspaceSyncDurabilityStore {
|
|
|
4715
4872
|
assertMatchingOperation(row, requestFingerprint) {
|
|
4716
4873
|
if (!row)
|
|
4717
4874
|
throw new Error('Workspace sync operation does not exist.');
|
|
4718
|
-
if (Number(row.contract_version) !== WORKSPACE_SYNC_CONTRACT_VERSION
|
|
4875
|
+
if (Number(row.contract_version) !== WORKSPACE_SYNC_CONTRACT_VERSION) {
|
|
4719
4876
|
throw new WorkspaceSyncIdempotencyConflictError();
|
|
4720
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
|
+
}
|
|
4721
4887
|
}
|
|
4722
4888
|
mapOutboxRow(row) {
|
|
4723
4889
|
return {
|
|
@@ -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?: {
|
|
@@ -89,6 +99,7 @@ export declare function runDurableTaskChecklistReplace(input: {
|
|
|
89
99
|
resolveActorRef?: () => string;
|
|
90
100
|
originActorRef?: string;
|
|
91
101
|
expectedDetailRevision?: string;
|
|
102
|
+
itemUpdateIntent?: TaskChecklistItemUpdateIntent;
|
|
92
103
|
assertPrecondition?: () => void;
|
|
93
104
|
onPostCommitError?: (error: unknown) => void;
|
|
94
105
|
}): DurableTaskChecklistMutationResult;
|