@taskforcehq/taskforce 0.3.328 → 0.3.330

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (485) hide show
  1. package/dist/Taskforce.module.css +523 -79
  2. package/dist/TaskforceCore.js +237 -230
  3. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
  4. package/dist/cli.js +34 -0
  5. package/dist/cliCloudTargetGuard.d.ts +5 -0
  6. package/dist/cliCloudTargetGuard.js +11 -0
  7. package/dist/components/features/AiProfilesModule.js +3 -5
  8. package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
  9. package/dist/components/features/TaskSettings.d.ts +12 -1
  10. package/dist/components/features/TaskSettings.js +217 -54
  11. package/dist/components/features/TaskforceAgentsModule.d.ts +1 -2
  12. package/dist/components/features/TaskforceAgentsModule.js +586 -116
  13. package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
  14. package/dist/components/features/agentConnections/AgentConnectionControl.d.ts +15 -0
  15. package/dist/components/features/agentConnections/AgentConnectionControl.js +125 -0
  16. package/dist/components/features/agentConnections/ModelConnectionsPanel.d.ts +18 -0
  17. package/dist/components/features/agentConnections/ModelConnectionsPanel.js +393 -0
  18. package/dist/components/features/agentConnections/modelConnectionsApi.d.ts +65 -0
  19. package/dist/components/features/agentConnections/modelConnectionsApi.js +129 -0
  20. package/dist/components/features/planning/PlanningModule.js +2 -5
  21. package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
  22. package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
  23. package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
  24. package/dist/components/features/planning/planningTaskArrangement.js +5 -5
  25. package/dist/components/features/taskforceAgentAssignments/AgentBehaviorAssignments.js +15 -24
  26. package/dist/components/features/taskforceAgentEditorModel.d.ts +2 -1
  27. package/dist/components/features/taskforceAgentEditorModel.js +5 -1
  28. package/dist/components/features/workflowManager/workflowManagerApi.d.ts +1 -1
  29. package/dist/components/features/workflowManager/workflowManagerApi.js +3 -0
  30. package/dist/components/task/TaskCard.d.ts +5 -0
  31. package/dist/components/task/TaskCard.js +65 -10
  32. package/dist/components/task/TaskImageReviews.js +14 -5
  33. package/dist/components/task/TaskKanban.d.ts +6 -1
  34. package/dist/components/task/TaskKanban.js +152 -6
  35. package/dist/components/task/TaskList.d.ts +5 -0
  36. package/dist/components/task/TaskList.js +3 -3
  37. package/dist/components/task/TaskWorkflowAssignmentField.js +68 -10
  38. package/dist/components/ui/PasswordInput.d.ts +6 -0
  39. package/dist/components/ui/PasswordInput.js +11 -0
  40. package/dist/components/ui/TopNoticeLayer.js +1 -1
  41. package/dist/components/views/AppShellHeader.js +32 -11
  42. package/dist/components/views/PlanComparisonPage.js +12 -0
  43. package/dist/components/views/StandaloneLayout.js +32 -55
  44. package/dist/components/views/WidgetView.js +3 -3
  45. package/dist/components/views/panels/PlanningDrawer.js +5 -12
  46. package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
  47. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +4 -3
  48. package/dist/components/views/standalone/modals/SyncStatusModal.js +33 -38
  49. package/dist/config/envSchema.js +60 -1
  50. package/dist/config/localServiceRuntimeContract.d.ts +13 -0
  51. package/dist/config/localServiceRuntimeContract.js +135 -0
  52. package/dist/core/AiProfileService.js +46 -8
  53. package/dist/core/DeletedTaskLifecycleService.d.ts +1 -0
  54. package/dist/core/DeletedTaskLifecycleService.js +37 -6
  55. package/dist/core/McpTokenService.d.ts +23 -1
  56. package/dist/core/McpTokenService.js +93 -10
  57. package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +3 -2
  58. package/dist/core/TaskAttachmentLinksDurableMutationService.js +33 -9
  59. package/dist/core/TaskChecklistCommandService.d.ts +27 -0
  60. package/dist/core/TaskChecklistCommandService.js +83 -5
  61. package/dist/core/TaskLifecycleCommandService.d.ts +3 -1
  62. package/dist/core/TaskLifecycleCommandService.js +6 -2
  63. package/dist/core/Taskforce.d.ts +94 -2
  64. package/dist/core/Taskforce.js +760 -36
  65. package/dist/core/types.d.ts +14 -0
  66. package/dist/documentReviews/commandService.d.ts +2 -1
  67. package/dist/documentReviews/commandService.js +6 -3
  68. package/dist/hooks/sync/orchestratorShared.d.ts +1 -0
  69. package/dist/hooks/sync/orchestratorShared.js +2 -0
  70. package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
  71. package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
  72. package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
  73. package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
  74. package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
  75. package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.d.ts +3 -0
  76. package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.js +85 -9
  77. package/dist/hooks/sync/useSyncStatusControls.d.ts +4 -1
  78. package/dist/hooks/sync/useSyncStatusControls.js +47 -11
  79. package/dist/hooks/tasks/taskHttpMutation.js +1 -0
  80. package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
  81. package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
  82. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
  83. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
  84. package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
  85. package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
  86. package/dist/hooks/tasks/useTaskFormActions.d.ts +6 -0
  87. package/dist/hooks/tasks/useTaskFormActions.js +65 -12
  88. package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
  89. package/dist/hooks/ui/useSettingsModel.js +13 -2
  90. package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
  91. package/dist/hooks/ui/useSettingsPersistence.js +74 -47
  92. package/dist/hooks/useFilterSort.d.ts +7 -3
  93. package/dist/hooks/useFilterSort.js +15 -5
  94. package/dist/hooks/useSyncOrchestrator.d.ts +3 -0
  95. package/dist/hooks/useSyncOrchestrator.js +111 -2
  96. package/dist/hooks/useTaskData.d.ts +40 -1
  97. package/dist/hooks/useTaskData.js +240 -9
  98. package/dist/hooks/useTaskMutations.d.ts +12 -2
  99. package/dist/hooks/useTaskMutations.js +266 -52
  100. package/dist/hooks/useTaskforce.d.ts +39 -9
  101. package/dist/hooks/useTaskforce.js +359 -40
  102. package/dist/hooks/useUiNotice.d.ts +4 -0
  103. package/dist/hooks/useUiNotice.js +4 -0
  104. package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
  105. package/dist/mcp/clientRegistry.d.ts +2 -2
  106. package/dist/mcp/clientRegistry.js +1 -1
  107. package/dist/mcp/documentAssetRegistrar.js +53 -41
  108. package/dist/mcp/documentHelpers.d.ts +1 -0
  109. package/dist/mcp/documentHelpers.js +7 -3
  110. package/dist/mcp/durableTaskMutationRouter.d.ts +4 -1
  111. package/dist/mcp/durableTaskMutationRouter.js +10 -0
  112. package/dist/mcp/durableTaskRelationshipMutationRouter.js +4 -0
  113. package/dist/mcp/httpProtocolRouting.d.ts +10 -0
  114. package/dist/mcp/httpProtocolRouting.js +19 -0
  115. package/dist/mcp/localCliHealth.d.ts +2 -2
  116. package/dist/mcp/localCliHealth.js +2 -2
  117. package/dist/mcp/localServiceProxy.d.ts +1 -0
  118. package/dist/mcp/localServiceProxy.js +530 -68
  119. package/dist/mcp/planningAttachmentCommandAdapter.d.ts +3 -1
  120. package/dist/mcp/planningAttachmentCommandAdapter.js +20 -2
  121. package/dist/mcp/runtime.d.ts +54 -79
  122. package/dist/mcp/runtime.js +556 -139
  123. package/dist/mcp/taskPlanningRegistrar.js +64 -42
  124. package/dist/mcp/toolCallCompatibility.js +38 -1
  125. package/dist/mcp/toolCatalog.d.ts +1 -0
  126. package/dist/mcp/toolProfiles.d.ts +2 -0
  127. package/dist/mcp/toolProfiles.js +10 -0
  128. package/dist/mcp/toolRegistry.d.ts +1 -0
  129. package/dist/mcp/toolRegistry.js +1 -0
  130. package/dist/mcp/workflowExecutionRegistrar.js +4 -4
  131. package/dist/migrations/taskSchemaMigrations.d.ts +5 -0
  132. package/dist/migrations/taskSchemaMigrations.js +427 -0
  133. package/dist/runtime/appGateDefinitions.d.ts +30 -6
  134. package/dist/runtime/appGateDefinitions.js +6 -6
  135. package/dist/runtime/appGates.d.ts +13 -13
  136. package/dist/runtime/appGates.js +36 -13
  137. package/dist/runtime/nodeAppGates.d.ts +8 -0
  138. package/dist/runtime/nodeAppGates.js +27 -0
  139. package/dist/server/cloudCollectionRead.d.ts +1 -1
  140. package/dist/server/cloudCollectionRead.js +2 -2
  141. package/dist/server/index.d.ts +6 -0
  142. package/dist/server/index.js +123 -14
  143. package/dist/server/localDatabaseIdentity.js +4 -1
  144. package/dist/server/localServiceLease.d.ts +3 -0
  145. package/dist/server/localServiceLease.js +11 -2
  146. package/dist/server/localServiceSessions.d.ts +14 -17
  147. package/dist/server/localServiceSessions.js +308 -94
  148. package/dist/server/localWorkspaceSyncServerRuntime.js +12 -7
  149. package/dist/server/rateLimit.d.ts +1 -0
  150. package/dist/server/rateLimit.js +4 -0
  151. package/dist/server/realtimeSyncWs.js +36 -12
  152. package/dist/server/routes/admin.d.ts +4 -0
  153. package/dist/server/routes/admin.js +113 -3
  154. package/dist/server/routes/agentRoles.js +3 -2
  155. package/dist/server/routes/agentSkills.js +3 -2
  156. package/dist/server/routes/agents.d.ts +7 -0
  157. package/dist/server/routes/agents.js +394 -39
  158. package/dist/server/routes/annotatedAttachments.js +3 -2
  159. package/dist/server/routes/auth.js +3 -1
  160. package/dist/server/routes/billing.js +5 -1
  161. package/dist/server/routes/durableTaskHttpRouters.d.ts +11 -2
  162. package/dist/server/routes/executorPhaseAApprovals.d.ts +19 -0
  163. package/dist/server/routes/executorPhaseAApprovals.js +140 -0
  164. package/dist/server/routes/executorPhaseAIssuerRedemptions.d.ts +11 -0
  165. package/dist/server/routes/executorPhaseAIssuerRedemptions.js +24 -0
  166. package/dist/server/routes/githubReviewEvidence.d.ts +19 -0
  167. package/dist/server/routes/githubReviewEvidence.js +116 -0
  168. package/dist/server/routes/localService.d.ts +15 -4
  169. package/dist/server/routes/localService.js +138 -40
  170. package/dist/server/routes/modelConnections.d.ts +24 -0
  171. package/dist/server/routes/modelConnections.js +205 -0
  172. package/dist/server/routes/primitives.d.ts +2 -0
  173. package/dist/server/routes/shared.d.ts +19 -0
  174. package/dist/server/routes/shared.js +95 -19
  175. package/dist/server/routes/sync.js +1 -0
  176. package/dist/server/routes/syncAuxRoutes.js +9 -2
  177. package/dist/server/routes/syncPullApplyRoutes.js +23 -4
  178. package/dist/server/routes/syncPushRoutes.d.ts +1 -0
  179. package/dist/server/routes/syncPushRoutes.js +1 -0
  180. package/dist/server/routes/syncV3FeedRoutes.js +27 -16
  181. package/dist/server/routes/syncV3LocalCaptureRoutes.js +28 -2
  182. package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
  183. package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
  184. package/dist/server/routes/syncV3OperationRoutes.js +45 -9
  185. package/dist/server/routes/tasks.js +124 -13
  186. package/dist/server/routes/workflows.js +9 -1
  187. package/dist/server/routes/workspaces.js +43 -1
  188. package/dist/server/routes.js +59 -0
  189. package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
  190. package/dist/server/workspaceDeletionAdmission.js +50 -0
  191. package/dist/service/localServiceCli.js +16 -0
  192. package/dist/service/localServiceClientLifecycle.js +36 -10
  193. package/dist/services/codexAppServerModelGateway.d.ts +161 -0
  194. package/dist/services/codexAppServerModelGateway.js +663 -0
  195. package/dist/services/codexDeviceCodeLoginManager.d.ts +39 -0
  196. package/dist/services/codexDeviceCodeLoginManager.js +265 -0
  197. package/dist/services/codexModelProviderConnectionLifecycle.d.ts +8 -0
  198. package/dist/services/codexModelProviderConnectionLifecycle.js +73 -0
  199. package/dist/services/executorPhaseAApprovalRuntime.d.ts +14 -0
  200. package/dist/services/executorPhaseAApprovalRuntime.js +24 -0
  201. package/dist/services/executorPhaseAApprovalService.d.ts +40 -0
  202. package/dist/services/executorPhaseAApprovalService.js +609 -0
  203. package/dist/services/executorPhaseADriftEvaluator.d.ts +78 -0
  204. package/dist/services/executorPhaseADriftEvaluator.js +93 -0
  205. package/dist/services/executorPhaseAIssuerCore.d.ts +126 -0
  206. package/dist/services/executorPhaseAIssuerCore.js +295 -0
  207. package/dist/services/executorPhaseAIssuerRedemptionService.d.ts +34 -0
  208. package/dist/services/executorPhaseAIssuerRedemptionService.js +158 -0
  209. package/dist/services/githubReviewEvidenceRuntime.d.ts +14 -0
  210. package/dist/services/githubReviewEvidenceRuntime.js +30 -0
  211. package/dist/services/githubReviewEvidenceService.d.ts +93 -0
  212. package/dist/services/githubReviewEvidenceService.js +336 -0
  213. package/dist/services/modelGateway.d.ts +7 -0
  214. package/dist/services/modelProviderConnectionService.d.ts +71 -0
  215. package/dist/services/modelProviderConnectionService.js +279 -0
  216. package/dist/services/modelProviderCredentialHome.d.ts +32 -0
  217. package/dist/services/modelProviderCredentialHome.js +271 -0
  218. package/dist/services/ownerScopedModelConnectionGateway.d.ts +12 -0
  219. package/dist/services/ownerScopedModelConnectionGateway.js +30 -0
  220. package/dist/services/taskforceAgentConnectionBindingService.d.ts +66 -0
  221. package/dist/services/taskforceAgentConnectionBindingService.js +185 -0
  222. package/dist/services/taskforceAgentMcpBridge.d.ts +8 -2
  223. package/dist/services/taskforceAgentMcpBridge.js +30 -27
  224. package/dist/shared/adminEdgeProxy.d.ts +5 -0
  225. package/dist/shared/adminEdgeProxy.js +94 -0
  226. package/dist/shared/adminProxySessionCookies.d.ts +16 -0
  227. package/dist/shared/adminProxySessionCookies.js +86 -0
  228. package/dist/shared/aiProfileColors.d.ts +31 -1
  229. package/dist/shared/aiProfileColors.js +14 -6
  230. package/dist/shared/executorPhaseAApprovalGoldenVector.json +269 -0
  231. package/dist/shared/executorPhaseAApprovalReceipt.d.ts +112 -0
  232. package/dist/shared/executorPhaseAApprovalReceipt.js +58 -0
  233. package/dist/shared/executorPhaseAApprovalTrustPolicy.json +10 -0
  234. package/dist/shared/executorPhaseADriftContracts.d.ts +37 -0
  235. package/dist/shared/executorPhaseADriftContracts.js +63 -0
  236. package/dist/shared/executorPhaseAIssuerContracts.d.ts +75 -0
  237. package/dist/shared/executorPhaseAIssuerContracts.js +90 -0
  238. package/dist/shared/executorPhaseARunAuthorization.d.ts +120 -0
  239. package/dist/shared/executorPhaseARunAuthorization.js +232 -0
  240. package/dist/shared/executorPhaseASchemaValidation.d.ts +7 -0
  241. package/dist/shared/executorPhaseASchemaValidation.js +53 -0
  242. package/dist/shared/executorPhaseASchemas/approval-receipt.schema.json +106 -0
  243. package/dist/shared/executorPhaseASchemas/drift-attestation.schema.json +54 -0
  244. package/dist/shared/executorPhaseASchemas/drift-request.schema.json +47 -0
  245. package/dist/shared/executorPhaseASchemas/foundation-manifest.schema.json +29 -0
  246. package/dist/shared/executorPhaseASchemas/issuer-audit-record.schema.json +24 -0
  247. package/dist/shared/executorPhaseASchemas/issuer-proof.schema.json +43 -0
  248. package/dist/shared/executorPhaseASchemas/issuer-redemption-request.schema.json +18 -0
  249. package/dist/shared/executorPhaseASchemas/issuer-redemption-response.schema.json +39 -0
  250. package/dist/shared/executorPhaseASchemas/logical-envelope.schema.json +149 -0
  251. package/dist/shared/executorPhaseASchemas/preflight-report.schema.json +216 -0
  252. package/dist/shared/executorPhaseASchemas/run-capability.schema.json +111 -0
  253. package/dist/shared/executorPhaseASchemas/sender-proof.schema.json +37 -0
  254. package/dist/shared/executorPhaseASchemas/workload-grant.schema.json +68 -0
  255. package/dist/shared/executorPhaseASchemas/workload-jwt-claims.schema.json +67 -0
  256. package/dist/shared/executorPhaseATiming.d.ts +1 -0
  257. package/dist/shared/executorPhaseATiming.js +1 -0
  258. package/dist/shared/planningIdentity.js +1 -1
  259. package/dist/shared/productLogoKeys.d.ts +2 -0
  260. package/dist/shared/productLogoKeys.js +18 -0
  261. package/dist/shared/taskforceAgentDefinition.d.ts +0 -1
  262. package/dist/shared/taskforceAgentDefinition.js +6 -3
  263. package/dist/shared/taskforceAgentModels.d.ts +1 -0
  264. package/dist/shared/taskforceAgentModels.js +36 -3
  265. package/dist/shared/userFeatureGrants.d.ts +4 -0
  266. package/dist/shared/userFeatureGrants.js +7 -0
  267. package/dist/storage/executorPhaseAApprovalReceiptStore.d.ts +37 -0
  268. package/dist/storage/executorPhaseAApprovalReceiptStore.js +81 -0
  269. package/dist/storage/executorPhaseARunAuthorizationStore.d.ts +103 -0
  270. package/dist/storage/executorPhaseARunAuthorizationStore.js +492 -0
  271. package/dist/storage/githubReviewEvidenceInstallationStore.d.ts +26 -0
  272. package/dist/storage/githubReviewEvidenceInstallationStore.js +89 -0
  273. package/dist/storage/modelProviderConnectionStore.d.ts +99 -0
  274. package/dist/storage/modelProviderConnectionStore.js +446 -0
  275. package/dist/storage/postgresAdapter.d.ts +24 -3
  276. package/dist/storage/postgresAdapter.js +117 -14
  277. package/dist/storage/postgresWorker.js +22 -5
  278. package/dist/storage/postgresWorkerProtocol.d.ts +30 -0
  279. package/dist/storage/postgresWorkerProtocol.js +30 -0
  280. package/dist/storage/taskforceAgentConnectionBindingStore.d.ts +31 -0
  281. package/dist/storage/taskforceAgentConnectionBindingStore.js +84 -0
  282. package/dist/sync/cloudSyncApi.d.ts +4 -1
  283. package/dist/sync/cloudSyncApi.js +7 -2
  284. package/dist/sync/contentSyncState.d.ts +1 -1
  285. package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +1 -0
  286. package/dist/sync/coordinator/localSyncExecutionPermitStore.js +67 -30
  287. package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.d.ts +10 -0
  288. package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.js +29 -0
  289. package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
  290. package/dist/sync/coordinator/localWorkspaceSyncRunnerState.d.ts +15 -1
  291. package/dist/sync/coordinator/localWorkspaceSyncRunnerState.js +99 -2
  292. package/dist/sync/coordinator/workspaceSyncCredentialBroker.d.ts +1 -0
  293. package/dist/sync/coordinator/workspaceSyncCredentialBroker.js +33 -4
  294. package/dist/sync/engine/workspaceSyncContentLifecycleAdapter.d.ts +2 -1
  295. package/dist/sync/engine/workspaceSyncContentVersionStore.d.ts +38 -0
  296. package/dist/sync/engine/workspaceSyncContentVersionStore.js +50 -1
  297. package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
  298. package/dist/sync/engine/workspaceSyncEngineLifecyclePolicy.js +6 -6
  299. package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
  300. package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
  301. package/dist/sync/engine/workspaceSyncEnginePushCompletion.d.ts +14 -0
  302. package/dist/sync/engine/workspaceSyncEnginePushCompletion.js +84 -0
  303. package/dist/sync/engine/workspaceSyncEngineRecovery.js +1 -0
  304. package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +11 -0
  305. package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
  306. package/dist/sync/engine/workspaceSyncEngineRuntime.d.ts +1 -0
  307. package/dist/sync/engine/workspaceSyncEngineRuntime.js +1 -0
  308. package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +31 -4
  309. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
  310. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +134 -43
  311. package/dist/sync/engine/workspaceSyncEngineServerSnapshotReader.js +6 -0
  312. package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
  313. package/dist/sync/engine/workspaceSyncEngineTransfers.js +11 -4
  314. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.d.ts +1 -0
  315. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +29 -0
  316. package/dist/sync/syncApplyHandlers.d.ts +2 -0
  317. package/dist/sync/syncApplyHandlers.js +10 -1
  318. package/dist/sync/syncService.d.ts +17 -0
  319. package/dist/sync/syncService.js +87 -19
  320. package/dist/sync/taskforceAgentSyncAuthorization.d.ts +16 -0
  321. package/dist/sync/taskforceAgentSyncAuthorization.js +20 -0
  322. package/dist/sync/v3/combinedFeedCapability.js +8 -0
  323. package/dist/sync/v3/durableInitiativeMutationRouter.js +18 -10
  324. package/dist/sync/v3/durableOperationReplay.d.ts +14 -0
  325. package/dist/sync/v3/durableOperationReplay.js +18 -0
  326. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +2 -0
  327. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +14 -1
  328. package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +4 -1
  329. package/dist/sync/v3/durableTaskChecklistMutationRouter.js +62 -15
  330. package/dist/sync/v3/durableTaskCommentMutationRouter.js +3 -0
  331. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
  332. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +30 -8
  333. package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
  334. package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +37 -2
  335. package/dist/sync/v3/durableTaxonomyMutationRouter.js +5 -0
  336. package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.d.ts +11 -0
  337. package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.js +39 -10
  338. package/dist/sync/v3/durableWorkstreamMutationRouter.js +18 -10
  339. package/dist/sync/v3/durableWorkstreamTaskOrderMutationRouter.js +16 -5
  340. package/dist/sync/v3/localOutboxDispatchRuntime.js +2 -2
  341. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +2 -0
  342. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +47 -7
  343. package/dist/sync/v3/localTaskChecklistOutboxHandler.js +16 -2
  344. package/dist/sync/v3/localTaskChecklistOutboxService.d.ts +4 -0
  345. package/dist/sync/v3/localTaskChecklistOutboxService.js +14 -1
  346. package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
  347. package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
  348. package/dist/sync/v3/localTaskMetadataClient.js +1 -0
  349. package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
  350. package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
  351. package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
  352. package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
  353. package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
  354. package/dist/sync/v3/localTaskStatusClient.js +6 -1
  355. package/dist/sync/v3/localTaskStatusOutboxService.d.ts +10 -0
  356. package/dist/sync/v3/localTaskStatusOutboxService.js +272 -24
  357. package/dist/sync/v3/syncDurabilityStore.d.ts +41 -0
  358. package/dist/sync/v3/syncDurabilityStore.js +199 -13
  359. package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +6 -4
  360. package/dist/sync/v3/taskAttachmentLinksMutationService.js +19 -10
  361. package/dist/sync/v3/taskChecklistMutationService.d.ts +15 -2
  362. package/dist/sync/v3/taskChecklistMutationService.js +48 -1
  363. package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
  364. package/dist/sync/v3/taskCreateMutationService.js +7 -4
  365. package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
  366. package/dist/sync/v3/taskMetadataMutationService.js +4 -0
  367. package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
  368. package/dist/sync/v3/taskRestoreMutationService.js +7 -4
  369. package/dist/sync/v3/taskStatusMutationService.d.ts +31 -1
  370. package/dist/sync/v3/taskStatusMutationService.js +123 -3
  371. package/dist/sync/v3/workflowAssignmentSync.d.ts +6 -0
  372. package/dist/sync/v3/workflowAssignmentSync.js +30 -0
  373. package/dist/sync/v3/workspaceSyncJournalReader.js +1 -1
  374. package/dist/sync/v3/workspaceSyncOperationRetentionService.d.ts +16 -0
  375. package/dist/sync/v3/workspaceSyncOperationRetentionService.js +83 -0
  376. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
  377. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +13 -3
  378. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
  379. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
  380. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
  381. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
  382. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.d.ts +1 -0
  383. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +18 -3
  384. package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +8 -3
  385. package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +51 -10
  386. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +14 -0
  387. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +49 -25
  388. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +13 -4
  389. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +124 -57
  390. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +20 -0
  391. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +106 -30
  392. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +4 -1
  393. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +34 -0
  394. package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +12 -0
  395. package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
  396. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
  397. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
  398. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
  399. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
  400. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
  401. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
  402. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
  403. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
  404. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
  405. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
  406. package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +5 -0
  407. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +7 -0
  408. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +55 -9
  409. package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.d.ts +17 -0
  410. package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.js +64 -0
  411. package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
  412. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
  413. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
  414. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
  415. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
  416. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.d.ts +7 -0
  417. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.js +33 -0
  418. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.d.ts +7 -0
  419. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.js +8 -0
  420. package/dist/sync/workspacePullFeed.js +2 -1
  421. package/dist/sync/workspaceRepair.d.ts +8 -2
  422. package/dist/sync/workspaceRepair.js +222 -6
  423. package/dist/sync/workspaceSyncModel.d.ts +21 -0
  424. package/dist/sync/workspaceSyncModel.js +35 -7
  425. package/dist/sync/workspaceSyncState.d.ts +1 -0
  426. package/dist/sync/workspaceSyncV2SnapshotBuilder.d.ts +6 -0
  427. package/dist/sync/workspaceSyncV2SnapshotBuilder.js +5 -0
  428. package/dist/types.d.ts +47 -1
  429. package/dist/types.js +6 -0
  430. package/dist/ui/assets/AiIdentityRosterCard-OcSz1PkK.js +1 -0
  431. package/dist/ui/assets/AiProfilesModule-ByhYW5Xi.js +1 -0
  432. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTM6nIg_.js +3 -0
  433. package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
  434. package/dist/ui/assets/{AssetTraySortControl-Kf1pelSy.js → AssetTraySortControl-DabEG8L4.js} +1 -1
  435. package/dist/ui/assets/{ContextAttachmentManager-B8boOs6Q.js → ContextAttachmentManager-Coa8yVGM.js} +2 -2
  436. package/dist/ui/assets/{DocumentWorkspace-DXH4XUsB.js → DocumentWorkspace-BB0qhdix.js} +1 -1
  437. package/dist/ui/assets/{EntityActivityTimeline-BtSTq0ON.js → EntityActivityTimeline-CZ8x4UJE.js} +1 -1
  438. package/dist/ui/assets/PlanningModule-pRPjR7v5.js +1 -0
  439. package/dist/ui/assets/PlansPage-D86pZSSl.js +1 -0
  440. package/dist/ui/assets/TaskContextUpload-BVIkU9yT.js +1 -0
  441. package/dist/ui/assets/TaskSettings-Cv1mNhv_.js +12 -0
  442. package/dist/ui/assets/TaskforceAgentsModule-b-8R25cJ.css +1 -0
  443. package/dist/ui/assets/TaskforceAgentsModule-gmH-PD2q.js +24 -0
  444. package/dist/ui/assets/{WorkflowManagerModule-DWFspC-o.js → WorkflowManagerModule-DbfnHJ-f.js} +1 -1
  445. package/dist/ui/assets/index-BZ-hdZSk.css +1 -0
  446. package/dist/ui/assets/index-CTsDBaef.js +7 -0
  447. package/dist/ui/assets/{vendor-icons-BkFLXavV.js → vendor-icons-Bsq-mcEn.js} +1 -1
  448. package/dist/ui/branding/logos/letterhead_dark.png +0 -0
  449. package/dist/ui/branding/logos/letterhead_light.png +0 -0
  450. package/dist/ui/branding/logos/signature_dark.png +0 -0
  451. package/dist/ui/branding/logos/signature_light.png +0 -0
  452. package/dist/ui/index.html +3 -3
  453. package/dist/utils/aiProfileDefaultLogo.js +16 -48
  454. package/dist/utils/httpSetCookie.d.ts +1 -0
  455. package/dist/utils/httpSetCookie.js +4 -1
  456. package/dist/utils/localRuntimeUrl.d.ts +1 -0
  457. package/dist/utils/localRuntimeUrl.js +14 -0
  458. package/dist/utils/productLogoRegistry.d.ts +2 -0
  459. package/dist/utils/productLogoRegistry.js +36 -0
  460. package/dist/utils/syncStatusPresentation.d.ts +4 -0
  461. package/dist/utils/syncStatusPresentation.js +17 -0
  462. package/dist/utils/taskActivity.d.ts +3 -2
  463. package/dist/utils/taskActivity.js +19 -2
  464. package/dist/utils/taskEditorReconciliation.d.ts +40 -0
  465. package/dist/utils/taskEditorReconciliation.js +217 -0
  466. package/dist/utils/taskEvents.d.ts +2 -0
  467. package/dist/utils/taskNormalization.d.ts +1 -0
  468. package/dist/utils/taskNormalization.js +39 -0
  469. package/dist/utils/taskSearch.js +2 -2
  470. package/dist/utils/uiNotice.d.ts +4 -0
  471. package/dist/utils/workspaceSyncPresentation.d.ts +1 -1
  472. package/dist/utils/workspaceSyncPresentation.js +23 -17
  473. package/package.json +36 -6
  474. package/dist/ui/assets/AiIdentityRosterCard-MZs7lVED.js +0 -1
  475. package/dist/ui/assets/AiProfilesModule-C3i0LOxe.js +0 -1
  476. package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
  477. package/dist/ui/assets/AnnotatedAttachmentWorkspace-DVZk5Tln.js +0 -3
  478. package/dist/ui/assets/PlanningModule-BPVyEa-f.js +0 -1
  479. package/dist/ui/assets/PlansPage-ChqgxALc.js +0 -1
  480. package/dist/ui/assets/TaskContextUpload-CB3ol0sN.js +0 -1
  481. package/dist/ui/assets/TaskSettings-g4ECKNOz.js +0 -12
  482. package/dist/ui/assets/TaskforceAgentsModule-BazdUwxZ.js +0 -21
  483. package/dist/ui/assets/TaskforceAgentsModule-D6IC0S7Q.css +0 -1
  484. package/dist/ui/assets/index-BUplSsv_.js +0 -7
  485. package/dist/ui/assets/index-gz2EXuoK.css +0 -1
@@ -140,10 +140,19 @@ export function createDurableTaskAttachmentLinksMutationRouter(input) {
140
140
  catch {
141
141
  throw new DurableTaskAttachmentLinksMutationError('Captured task attachment-link payload is invalid.', 'TASK_ATTACHMENT_LINKS_IDENTITY_CONFLICT', 409);
142
142
  }
143
- if (canonicalWorkspaceSyncJson(frozen) !== canonicalWorkspaceSyncJson(links)
143
+ const relationshipIntent = (entries) => entries.map((link) => ({
144
+ assetId: link.assetId,
145
+ role: link.role,
146
+ order: link.order,
147
+ }));
148
+ if (canonicalWorkspaceSyncJson(relationshipIntent(frozen))
149
+ !== canonicalWorkspaceSyncJson(relationshipIntent(links))
144
150
  || String(payload.cardCoverAssetId || '') !== String(cardCoverAssetId || '')) {
145
151
  throw new DurableTaskAttachmentLinksMutationError('Operation identity is assigned to different task attachment links.', 'TASK_ATTACHMENT_LINKS_IDENTITY_CONFLICT', 409);
146
152
  }
153
+ store.assertOutboxOperationIdentity(existing, {
154
+ domain: 'task-attachment-links', entityId: taskId, mutationKind: 'replace',
155
+ });
147
156
  const task = input.core.getTask(taskId, workspaceId);
148
157
  if (!task)
149
158
  throw new DurableTaskAttachmentLinksMutationError('Task not found.', 'TASK_NOT_FOUND', 404);
@@ -204,6 +213,10 @@ export function createDurableTaskAttachmentLinksMutationRouter(input) {
204
213
  baseEntityRevision: coordinates.entityRevision, baseLifecycleRevision: coordinates.lifecycleRevision,
205
214
  now: acceptedAtIso, leaseExpiresAt: new Date(acceptedAt.getTime() + OPERATION_LEASE_MS).toISOString(),
206
215
  actorRef, onPostCommitError: input.onPostCommitError,
216
+ expectedDetailRevision: args.expectedDetailRevision,
217
+ assertPrecondition: args.expectedDetailRevision
218
+ ? () => input.core.assertTaskDetailRevisionForUpdate(taskId, args.expectedDetailRevision, workspaceId)
219
+ : undefined,
207
220
  });
208
221
  if (result.state === 'in_progress')
209
222
  throw new DurableTaskAttachmentLinksRouterInProgressError(result.retryAt);
@@ -1,7 +1,7 @@
1
1
  import type { ChecklistItem, TaskItem } from '../../core/Taskforce.js';
2
2
  import type { DatabaseAdapter } from '../../storage/databaseAdapter.js';
3
3
  import { type LocalTaskChecklistOutboxCore } from './localTaskChecklistOutboxService.js';
4
- import { type DurableTaskChecklistServiceCore } from './taskChecklistMutationService.js';
4
+ import { type DurableTaskChecklistServiceCore, type TaskChecklistItemUpdateIntent } from './taskChecklistMutationService.js';
5
5
  export declare function resolveTaskChecklistMutationCapability(input: {
6
6
  runtimeMode: 'local' | 'cloud';
7
7
  surface: 'http' | 'mcp';
@@ -11,6 +11,7 @@ export declare function resolveTaskChecklistMutationCapability(input: {
11
11
  export type DurableTaskChecklistMutationRouterCore = DurableTaskChecklistServiceCore & LocalTaskChecklistOutboxCore & {
12
12
  getDatabaseAdapter(): DatabaseAdapter;
13
13
  getTask(id: string, workspaceId?: string): TaskItem | null;
14
+ assertTaskDetailRevisionForUpdate(id: string, expected: string, workspaceId?: string): void;
14
15
  };
15
16
  export declare class DurableTaskChecklistRouterDisabledError extends Error {
16
17
  readonly code = "WORKSPACE_SYNC_V3_TASK_CHECKLIST_ROUTER_DISABLED";
@@ -38,6 +39,8 @@ export declare function createDurableTaskChecklistMutationRouter(input: {
38
39
  replace(args: {
39
40
  taskId: string;
40
41
  items: readonly Partial<ChecklistItem>[];
42
+ expectedDetailRevision?: string;
43
+ itemUpdateIntent?: TaskChecklistItemUpdateIntent;
41
44
  }): {
42
45
  state: "pending" | "committed";
43
46
  route: "local-outbox" | "cloud-acceptance";
@@ -1,7 +1,7 @@
1
1
  import { canonicalWorkspaceSyncJson } from './canonicalWorkspaceSyncJson.js';
2
2
  import { LocalSyncIdentityStore } from './localSyncIdentityStore.js';
3
3
  import { enqueueLocalTaskChecklistMutation, } from './localTaskChecklistOutboxService.js';
4
- import { DurableTaskChecklistMutationError, runDurableTaskChecklistReplace, } from './taskChecklistMutationService.js';
4
+ import { DurableTaskChecklistMutationError, runDurableTaskChecklistReplace, validateTaskChecklistItemUpdateIntent, } from './taskChecklistMutationService.js';
5
5
  import { WorkspaceSyncDurabilityStore, WorkspaceSyncEntityBusyError } from './syncDurabilityStore.js';
6
6
  import { serializeWorkspaceSyncV3TaskChecklistPayload } from './workspaceSyncV3NestedTaskCodecs.js';
7
7
  const OPERATION_LEASE_MS = 30_000;
@@ -82,6 +82,18 @@ export function createDurableTaskChecklistMutationRouter(input) {
82
82
  catch (error) {
83
83
  throw new DurableTaskChecklistMutationError(error instanceof Error ? error.message : 'Task checklist is invalid.', 'TASK_CHECKLIST_INVALID', 400);
84
84
  }
85
+ const itemUpdateIntent = args.itemUpdateIntent
86
+ ? validateTaskChecklistItemUpdateIntent(args.itemUpdateIntent)
87
+ : undefined;
88
+ if (itemUpdateIntent) {
89
+ const target = items.find((item) => item.id === itemUpdateIntent.itemId);
90
+ if (!target
91
+ || (itemUpdateIntent.patch.text !== undefined && target.title !== itemUpdateIntent.patch.text)
92
+ || (itemUpdateIntent.patch.done !== undefined && target.isCompleted !== itemUpdateIntent.patch.done)
93
+ || (itemUpdateIntent.patch.order !== undefined && target.order !== itemUpdateIntent.patch.order)) {
94
+ throw new DurableTaskChecklistMutationError('Task checklist item update intent does not match the replacement aggregate.', 'TASK_CHECKLIST_INVALID', 400);
95
+ }
96
+ }
85
97
  const acceptedAt = now();
86
98
  const acceptedAtIso = acceptedAt.toISOString();
87
99
  const operationId = operationIdRequired(input.operationId);
@@ -109,25 +121,43 @@ export function createDurableTaskChecklistMutationRouter(input) {
109
121
  catch {
110
122
  throw new DurableTaskChecklistMutationError('Captured task checklist payload is invalid.', 'TASK_CHECKLIST_IDENTITY_CONFLICT', 409);
111
123
  }
112
- if (canonicalWorkspaceSyncJson(frozen) !== canonicalWorkspaceSyncJson(items)) {
124
+ const capturedIntent = payload.itemUpdateIntent
125
+ ? validateTaskChecklistItemUpdateIntent(payload.itemUpdateIntent)
126
+ : undefined;
127
+ const requestedIntent = itemUpdateIntent;
128
+ if (capturedIntent || requestedIntent
129
+ ? canonicalWorkspaceSyncJson(capturedIntent) !== canonicalWorkspaceSyncJson(requestedIntent)
130
+ : canonicalWorkspaceSyncJson(frozen) !== canonicalWorkspaceSyncJson(items)) {
113
131
  throw new DurableTaskChecklistMutationError('Operation identity is assigned to a different task checklist.', 'TASK_CHECKLIST_IDENTITY_CONFLICT', 409);
114
132
  }
133
+ if ((payload.expectedDetailRevision || undefined) !== (args.expectedDetailRevision || undefined)) {
134
+ throw new DurableTaskChecklistMutationError('Operation identity is assigned to a different task checklist precondition.', 'TASK_CHECKLIST_IDENTITY_CONFLICT', 409);
135
+ }
136
+ store.assertOutboxOperationIdentity(existing, {
137
+ domain: 'task-checklist', entityId: taskId, mutationKind: 'replace',
138
+ });
115
139
  const task = input.core.getTask(taskId, workspaceId);
116
140
  if (!task)
117
141
  throw new DurableTaskChecklistMutationError('Task not found.', 'TASK_NOT_FOUND', 404);
118
142
  const installed = serializeWorkspaceSyncV3TaskChecklistPayload({
119
143
  taskId, items: task.checklistItems || [],
120
144
  }).items;
121
- if (canonicalWorkspaceSyncJson(installed) !== canonicalWorkspaceSyncJson(frozen)) {
145
+ if (!capturedIntent
146
+ && canonicalWorkspaceSyncJson(installed) !== canonicalWorkspaceSyncJson(frozen)) {
122
147
  throw new DurableTaskChecklistMutationError('Captured task checklist does not match local state.', 'TASK_CHECKLIST_IDENTITY_CONFLICT', 409);
123
148
  }
124
- return { state: 'pending', route: 'local-outbox', operationId, task };
149
+ return {
150
+ state: 'pending', route: 'local-outbox', operationId,
151
+ task: capturedIntent ? { ...task, checklistItems: frozen } : task,
152
+ };
125
153
  }
126
154
  let result;
127
155
  try {
128
156
  result = enqueueLocalTaskChecklistMutation({
129
157
  store, core: input.core, identity, taskId, items, now: acceptedAtIso,
130
158
  actorRef, onPostCommitError: input.onPostCommitError,
159
+ expectedDetailRevision: args.expectedDetailRevision,
160
+ itemUpdateIntent,
131
161
  requireV3CombinedOwnership: persistedOwnershipChecked,
132
162
  });
133
163
  }
@@ -142,6 +172,7 @@ export function createDurableTaskChecklistMutationRouter(input) {
142
172
  return { state: 'pending', route: 'local-outbox', operationId, task };
143
173
  }
144
174
  const committed = store.readCommittedOperationResponse(identity);
175
+ let coordinates;
145
176
  if (committed) {
146
177
  let response;
147
178
  try {
@@ -150,33 +181,49 @@ export function createDurableTaskChecklistMutationRouter(input) {
150
181
  catch {
151
182
  throw new DurableTaskChecklistMutationError('Committed task checklist response is invalid.', 'TASK_CHECKLIST_IDENTITY_CONFLICT', 409);
152
183
  }
184
+ const projection = response.authoritative?.checklist;
185
+ const acceptedRevision = String(projection?.entityRevision || '');
186
+ const lifecycleRevision = String(projection?.lifecycleRevision || '');
153
187
  if (response.workspaceId !== workspaceId || response.clientId !== clientId
154
188
  || response.operationId !== operationId || response.authoritative?.root?.entityId !== taskId
155
- || response.authoritative?.checklist?.entityId !== taskId
156
- || canonicalWorkspaceSyncJson(response.authoritative.checklist.payload?.items || [])
157
- !== canonicalWorkspaceSyncJson(items)) {
189
+ || projection?.entityId !== taskId
190
+ || !/^[1-9]\d*$/.test(acceptedRevision)
191
+ || !/^(0|[1-9]\d*)$/.test(lifecycleRevision)) {
158
192
  throw new DurableTaskChecklistMutationError('Operation identity is assigned to a different task checklist.', 'TASK_CHECKLIST_IDENTITY_CONFLICT', 409);
159
193
  }
160
- const task = input.core.getTask(taskId, workspaceId);
161
- if (!task)
162
- throw new DurableTaskChecklistMutationError('Task not found.', 'TASK_NOT_FOUND', 404);
163
- return { state: 'committed', route: 'cloud-acceptance', operationId, task };
194
+ coordinates = {
195
+ entityRevision: String(BigInt(acceptedRevision) - 1n),
196
+ lifecycleRevision,
197
+ };
198
+ }
199
+ else {
200
+ coordinates = store.readEntityRevisionCoordinates({
201
+ tenantId, workspaceId, domain: 'task-checklist', entityId: taskId,
202
+ });
164
203
  }
165
- const coordinates = store.readEntityRevisionCoordinates({
166
- tenantId, workspaceId, domain: 'task-checklist', entityId: taskId,
167
- });
168
204
  const result = runDurableTaskChecklistReplace({
169
205
  store, core: input.core, tenantId, workspaceId, clientId, operationId, taskId, items,
170
206
  baseEntityRevision: coordinates.entityRevision, baseLifecycleRevision: coordinates.lifecycleRevision,
171
207
  now: acceptedAtIso, leaseExpiresAt: new Date(acceptedAt.getTime() + OPERATION_LEASE_MS).toISOString(),
172
208
  actorRef, onPostCommitError: input.onPostCommitError,
209
+ expectedDetailRevision: args.expectedDetailRevision,
210
+ itemUpdateIntent,
211
+ assertPrecondition: args.expectedDetailRevision
212
+ ? () => input.core.assertTaskDetailRevisionForUpdate(taskId, args.expectedDetailRevision, workspaceId)
213
+ : undefined,
173
214
  });
174
215
  if (result.state === 'in_progress')
175
216
  throw new DurableTaskChecklistRouterInProgressError(result.retryAt);
176
217
  const task = input.core.getTask(taskId, workspaceId);
177
218
  if (!task)
178
219
  throw new DurableTaskChecklistMutationError('Task not found.', 'TASK_NOT_FOUND', 404);
179
- return { state: 'committed', route: 'cloud-acceptance', operationId, task };
220
+ return {
221
+ state: 'committed', route: 'cloud-acceptance', operationId,
222
+ task: {
223
+ ...task,
224
+ checklistItems: result.response.authoritative.checklist.payload.items,
225
+ },
226
+ };
180
227
  },
181
228
  };
182
229
  }
@@ -113,6 +113,9 @@ export function createDurableTaskCommentMutationRouter(input) {
113
113
  if (!sameCommentRetryIntent(existingPayload.comment, canonical)) {
114
114
  throw new DurableTaskCommentMutationError('Operation identity is assigned to a different task comment.', 'TASK_COMMENT_IDENTITY_CONFLICT', 409);
115
115
  }
116
+ store.assertOutboxOperationIdentity(existing, {
117
+ domain: 'task-comments', entityId: taskId, mutationKind: 'append',
118
+ });
116
119
  const frozenComment = serializeWorkspaceSyncV3TaskCommentsPayload({
117
120
  taskId, comments: [existingPayload.comment],
118
121
  }).comments[0];
@@ -51,6 +51,7 @@ export declare function createDurableTaskHttpBulkMutationRouter(input: {
51
51
  }>, options?: {
52
52
  saveSource?: "manual" | "autosave";
53
53
  atomicItemFailures?: boolean;
54
+ expectedDetailRevision?: string;
54
55
  }): {
55
56
  preview: import("../../core/Taskforce.js").BulkUpdateFieldsPreview;
56
57
  results: TaskItem[];
@@ -222,7 +222,12 @@ export function createDurableTaskHttpBulkMutationRouter(input) {
222
222
  }, { atomicRecovery: true });
223
223
  },
224
224
  updateFields(updates, options = {}) {
225
- return input.rootRouter.runBatch('bulk-update-fields', { updates }, (batch) => {
225
+ return input.rootRouter.runBatch('bulk-update-fields', {
226
+ updates,
227
+ ...(options.expectedDetailRevision
228
+ ? { expectedDetailRevision: options.expectedDetailRevision }
229
+ : {}),
230
+ }, (batch) => {
226
231
  const preview = input.core.bulkUpdateFieldsPreview(updates, input.workspaceId);
227
232
  const results = [];
228
233
  const errors = preview.skipped
@@ -273,14 +278,21 @@ export function createDurableTaskHttpBulkMutationRouter(input) {
273
278
  && !(durableAttachmentLinks && key === 'cardCoverAssetId'))))
274
279
  : item.fields;
275
280
  let updated = input.core.getTask(item.id, input.workspaceId);
281
+ let expectedDetailRevision = options.expectedDetailRevision;
276
282
  if (Object.keys(rootFields).length > 0) {
277
283
  const child = input.createChildRouter(input.deriveChildOperationId('bulk-update-fields-root', item.index, item.id), () => { });
278
284
  updated = child.enabled
279
- ? batch.runChild(() => child.update(item.id, rootFields, options.saveSource || 'manual'))
280
- : input.core.updateTask(item.id, rootFields, input.workspaceId, {
281
- actorRef: 'user',
282
- saveSource: options.saveSource || 'manual',
283
- });
285
+ ? batch.runChild(() => child.update(item.id, rootFields, options.saveSource || 'manual', undefined, expectedDetailRevision))
286
+ : (() => {
287
+ if (expectedDetailRevision) {
288
+ input.core.assertTaskDetailRevisionForUpdate(item.id, expectedDetailRevision, input.workspaceId);
289
+ }
290
+ return input.core.updateTask(item.id, rootFields, input.workspaceId, {
291
+ actorRef: 'user',
292
+ saveSource: options.saveSource || 'manual',
293
+ });
294
+ })();
295
+ expectedDetailRevision = undefined;
284
296
  }
285
297
  if (durableChecklist && checklist) {
286
298
  const currentTask = input.core.getTask(item.id, input.workspaceId) || updated;
@@ -301,7 +313,12 @@ export function createDurableTaskHttpBulkMutationRouter(input) {
301
313
  updatedAt: String(unchanged ? existing.updatedAt : existing ? now : source.updatedAt || createdAt),
302
314
  };
303
315
  });
304
- updated = batch.runChild(() => checklist.replace({ taskId: item.id, items: normalizedChecklist }).task);
316
+ updated = batch.runChild(() => checklist.replace({
317
+ taskId: item.id,
318
+ items: normalizedChecklist,
319
+ expectedDetailRevision,
320
+ }).task);
321
+ expectedDetailRevision = undefined;
305
322
  }
306
323
  if (durableAttachmentLinks && attachmentLinks) {
307
324
  updated = batch.runChild(() => attachmentLinks.replace({
@@ -312,7 +329,9 @@ export function createDurableTaskHttpBulkMutationRouter(input) {
312
329
  ? null
313
330
  : String(item.fields.cardCoverAssetId).trim(),
314
331
  } : {}),
332
+ expectedDetailRevision,
315
333
  }).task);
334
+ expectedDetailRevision = undefined;
316
335
  }
317
336
  if (updated)
318
337
  results.push(updated);
@@ -327,7 +346,10 @@ export function createDurableTaskHttpBulkMutationRouter(input) {
327
346
  }
328
347
  batch.deferPostCommitNotification(() => input.core.notifyDurableTaskBatchCommitted(input.workspaceId, results.map((task) => task.id)));
329
348
  return { preview, results, errors };
330
- }, { atomicRecovery: true, allowIndependentNestedOwnership: true });
349
+ }, {
350
+ atomicRecovery: true,
351
+ allowIndependentNestedOwnership: true,
352
+ });
331
353
  },
332
354
  };
333
355
  }
@@ -3,7 +3,8 @@ import type { TaskRestoreDestination } from '../../shared/taskRestoreDestination
3
3
  export declare class DurableTaskHttpRootMutationError extends Error {
4
4
  readonly code: string;
5
5
  readonly statusCode: number;
6
- constructor(message: string, code: string, statusCode: number);
6
+ readonly details?: Record<string, unknown> | undefined;
7
+ constructor(message: string, code: string, statusCode: number, details?: Record<string, unknown> | undefined);
7
8
  }
8
9
  export declare function resolveTaskHttpRootMutationCapability(input: {
9
10
  runtimeMode: 'local' | 'cloud';
@@ -22,8 +23,9 @@ export declare function createDurableTaskHttpRootMutationRouter(input: {
22
23
  deferPostCommitNotification?: (notify: () => void) => void;
23
24
  }): {
24
25
  enabled: boolean;
26
+ hasCommittedOperation(): boolean;
25
27
  create(candidate: unknown): TaskItem;
26
- update(taskIdInput: string, candidate: unknown, saveSource: "manual" | "autosave", activityAction?: "task-updated" | "task-schedule-changed"): TaskItem;
28
+ update(taskIdInput: string, candidate: unknown, saveSource: "manual" | "autosave", activityAction?: "task-updated" | "task-schedule-changed", expectedDetailRevision?: string): TaskItem;
27
29
  runBatch<T>(routeInput: string, request: unknown, apply: (context: {
28
30
  runChild<R>(mutation: () => R): R;
29
31
  deferPostCommitNotification(notify: () => void): void;
@@ -36,5 +38,5 @@ export declare function createDurableTaskHttpRootMutationRouter(input: {
36
38
  restore(deletedRecordIdInput: string, restoreDestination?: TaskRestoreDestination): TaskItem;
37
39
  delete(taskIdInput: string): DeletedTaskRecord;
38
40
  };
39
- type TaskforceCoreForHttpRootMutation = Pick<import('../../core/Taskforce.js').TaskforceCore, 'getDatabaseAdapter' | 'getTask' | 'listAssignableActors' | 'getDeletedTask' | 'updateTask' | 'hasTaskDeletionMarkerForSync' | 'createTask' | 'listTaskAttachmentLinksForDurableSync' | 'resolveTaskAttachmentLinksForDurableSync' | 'normalizeTaskAttachmentDescriptorsForDurableSync' | 'notifyDurableTaskCreateCommitted' | 'notifyDurableTaskBatchCommitted' | 'notifyDurableTaskMetadataCommitted' | 'notifyDurableTaskLifecycleCommitted' | 'notifyDurableTaskDeleteCommitted' | 'getTaskEventForSync' | 'getEntityEventForSync' | 'lockTaskLifecycleMutationDomain' | 'archiveTask' | 'unarchiveTask' | 'restoreDeletedTask' | 'addTaskStatusEventsForDurableSync' | 'lockTaskRelationshipMutationDomain' | 'listTaskRelationships' | 'getTaskRelationshipForSync' | 'deleteTaskForSync'>;
41
+ type TaskforceCoreForHttpRootMutation = Pick<import('../../core/Taskforce.js').TaskforceCore, 'getDatabaseAdapter' | 'getTask' | 'getTaskDetailRevision' | 'assertTaskDetailRevisionForUpdate' | 'listAssignableActors' | 'getDeletedTask' | 'updateTask' | 'hasTaskDeletionMarkerForSync' | 'createTask' | 'listTaskAttachmentLinksForDurableSync' | 'resolveTaskAttachmentLinksForDurableSync' | 'normalizeTaskAttachmentDescriptorsForDurableSync' | 'notifyDurableTaskCreateCommitted' | 'notifyDurableTaskBatchCommitted' | 'notifyDurableTaskMetadataCommitted' | 'notifyDurableTaskLifecycleCommitted' | 'notifyDurableTaskDeleteCommitted' | 'getTaskEventForSync' | 'getEntityEventForSync' | 'lockTaskLifecycleMutationDomain' | 'archiveTask' | 'unarchiveTask' | 'restoreDeletedTask' | 'addTaskStatusEventsForDurableSync' | 'addTaskCommentEventForDurableSync' | 'lockTaskRelationshipMutationDomain' | 'listTaskRelationships' | 'getTaskRelationshipForSync' | 'deleteTaskForSync'>;
40
42
  export {};
@@ -2,6 +2,7 @@ import { selectDurableTaskMetadataPatch } from '../../core/TaskDurableSyncMutati
2
2
  import { prepareTaskDeleteForDurableSync } from '../../core/TaskDurableDeleteMutationService.js';
3
3
  import { selectTaskCreateActivationInput } from './taskCreateActivation.js';
4
4
  import { resolveTaskAttachmentLinksMutationCapability } from './durableTaskAttachmentLinksMutationRouter.js';
5
+ import { areWorkflowRuntimeMutationsFenced, resolveWorkflowRuntimeDurableTransportCapability, } from './durableWorkflowRuntimeMutationRouter.js';
5
6
  import { runDurableTaskCreate } from './taskCreateMutationService.js';
6
7
  import { runDurableTaskDelete } from './taskDeleteMutationService.js';
7
8
  import { runDurableTaskLifecycleMutation } from './taskLifecycleMutationService.js';
@@ -28,10 +29,12 @@ function requiredText(value, label) {
28
29
  export class DurableTaskHttpRootMutationError extends Error {
29
30
  code;
30
31
  statusCode;
31
- constructor(message, code, statusCode) {
32
+ details;
33
+ constructor(message, code, statusCode, details) {
32
34
  super(message);
33
35
  this.code = code;
34
36
  this.statusCode = statusCode;
37
+ this.details = details;
35
38
  this.name = 'DurableTaskHttpRootMutationError';
36
39
  }
37
40
  }
@@ -57,6 +60,13 @@ export function createDurableTaskHttpRootMutationRouter(input) {
57
60
  surface: 'http',
58
61
  env: input.env,
59
62
  });
63
+ const workflowRuntimeJournalEnabled = resolveWorkflowRuntimeDurableTransportCapability({
64
+ runtimeMode: input.runtimeMode,
65
+ surface: 'http',
66
+ env: input.env,
67
+ });
68
+ const rejectWorkflowRuntimeActivation = workflowRuntimeJournalEnabled
69
+ && areWorkflowRuntimeMutationsFenced(input.env);
60
70
  const store = new WorkspaceSyncDurabilityStore(input.core.getDatabaseAdapter());
61
71
  const now = input.now || (() => new Date());
62
72
  const notificationMethods = new Set([
@@ -120,6 +130,11 @@ export function createDurableTaskHttpRootMutationRouter(input) {
120
130
  rethrowDurableReplayError(error, 'Committed durable task HTTP response is invalid.');
121
131
  }
122
132
  };
133
+ const detailRevisionPrecondition = (taskId, expectedDetailRevision) => {
134
+ if (!expectedDetailRevision)
135
+ return undefined;
136
+ return () => input.core.assertTaskDetailRevisionForUpdate(taskId, expectedDetailRevision, input.workspaceId);
137
+ };
123
138
  const lifecycle = (taskIdInput, mutationKind, payload) => {
124
139
  const taskId = requiredText(taskIdInput, 'Task id');
125
140
  const operation = context();
@@ -144,6 +159,12 @@ export function createDurableTaskHttpRootMutationRouter(input) {
144
159
  };
145
160
  return {
146
161
  enabled,
162
+ hasCommittedOperation() {
163
+ const operationId = String(input.operationId || '').trim();
164
+ if (!operationId)
165
+ return false;
166
+ return Boolean(store.readCommittedOperationResponse(operationIdentity(operationId)));
167
+ },
147
168
  create(candidate) {
148
169
  const source = candidate && typeof candidate === 'object' && !Array.isArray(candidate)
149
170
  ? candidate
@@ -183,7 +204,7 @@ export function createDurableTaskHttpRootMutationRouter(input) {
183
204
  throw new DurableTaskHttpRootMutationError('The durable task mutation is already in progress.', 'WORKSPACE_SYNC_OPERATION_IN_PROGRESS', 409);
184
205
  return result.response.authoritative.payload;
185
206
  },
186
- update(taskIdInput, candidate, saveSource, activityAction) {
207
+ update(taskIdInput, candidate, saveSource, activityAction, expectedDetailRevision) {
187
208
  const taskId = requiredText(taskIdInput, 'Task id');
188
209
  if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
189
210
  throw new DurableTaskHttpRootMutationError('Task patch must be an object.', 'DURABLE_TASK_PATCH_INVALID', 400);
@@ -224,6 +245,10 @@ export function createDurableTaskHttpRootMutationRouter(input) {
224
245
  now: operation.acceptedAtIso,
225
246
  leaseExpiresAt: new Date(operation.acceptedAt.getTime() + OPERATION_LEASE_MS).toISOString(),
226
247
  actorRef: input.actorRef,
248
+ includeWorkflowRuntimeJournal: workflowRuntimeJournalEnabled,
249
+ rejectWorkflowRuntimeActivation,
250
+ expectedDetailRevision,
251
+ assertPrecondition: detailRevisionPrecondition(taskId, expectedDetailRevision),
227
252
  onPostCommitError: input.onPostCommitError,
228
253
  });
229
254
  if (result.state === 'in_progress')
@@ -283,6 +308,8 @@ export function createDurableTaskHttpRootMutationRouter(input) {
283
308
  actorRef: input.actorRef,
284
309
  saveSource,
285
310
  activityAction,
311
+ expectedDetailRevision,
312
+ assertPrecondition: detailRevisionPrecondition(taskId, expectedDetailRevision),
286
313
  onPostCommitError: input.onPostCommitError,
287
314
  });
288
315
  if (result.state === 'in_progress')
@@ -341,6 +368,14 @@ export function createDurableTaskHttpRootMutationRouter(input) {
341
368
  if (options?.atomicRecovery) {
342
369
  const notifications = [];
343
370
  const result = input.core.getDatabaseAdapter().transaction(() => {
371
+ // Child durable mutations lock the workspace sequence before
372
+ // touching task rows. Take the same lock first when a batch
373
+ // may combine a legacy root write with durable child owners.
374
+ store.lockWorkspaceSequenceForMutation({
375
+ tenantId: input.tenantId,
376
+ workspaceId: input.workspaceId,
377
+ now: operation.acceptedAtIso,
378
+ });
344
379
  const value = apply({
345
380
  runChild: (mutation) => input.core.getDatabaseAdapter().transaction(mutation)(),
346
381
  deferPostCommitNotification: (notify) => notifications.push(notify),
@@ -185,6 +185,11 @@ export function createDurableTaxonomyMutationRouter(input) {
185
185
  if (!sameTaxonomyState(storedPayload.state, canonicalState) || !Array.isArray(storedPayload.taskPatches)) {
186
186
  throw new WorkspaceSyncIdempotencyConflictError();
187
187
  }
188
+ store.assertOutboxOperationIdentity(existingOutbox, {
189
+ domain: WORKSPACE_SYNC_TAXONOMY_DOMAIN,
190
+ entityId: WORKSPACE_SYNC_TAXONOMY_ENTITY_ID,
191
+ mutationKind: WORKSPACE_SYNC_TAXONOMY_REPLACE_WITH_REMAPS,
192
+ });
188
193
  enqueueLocalTaxonomyCompositeReplacement({
189
194
  store,
190
195
  core: input.core,
@@ -15,11 +15,22 @@ export declare class DurableWorkflowRuntimeRouterInProgressError extends Error {
15
15
  readonly statusCode = 409;
16
16
  constructor(retryAt: string);
17
17
  }
18
+ export declare class DurableWorkflowRuntimeExecutionNotFoundError extends Error {
19
+ readonly code = "execution_not_found";
20
+ readonly statusCode = 404;
21
+ constructor();
22
+ }
23
+ export declare function areWorkflowRuntimeMutationsFenced(env?: NodeJS.ProcessEnv): boolean;
18
24
  export declare function resolveWorkflowRuntimeMutationCapability(input: {
19
25
  runtimeMode: 'local' | 'cloud';
20
26
  surface: DurableWorkflowRuntimeSurface;
21
27
  env?: NodeJS.ProcessEnv;
22
28
  }): boolean;
29
+ export declare function resolveWorkflowRuntimeDurableTransportCapability(input: {
30
+ runtimeMode: 'local' | 'cloud';
31
+ surface: DurableWorkflowRuntimeSurface;
32
+ env?: NodeJS.ProcessEnv;
33
+ }): boolean;
23
34
  export declare function createDurableWorkflowRuntimeMutationRouter(input: {
24
35
  core: DurableWorkflowRuntimeMutationRouterCore;
25
36
  runtimeMode: 'local' | 'cloud';
@@ -7,6 +7,7 @@ import { WorkspaceSyncDurabilityStore, } from './syncDurabilityStore.js';
7
7
  import { runDurableWorkflowRuntimeMutation, } from './workflowRuntimeMutationService.js';
8
8
  import { validateWorkflowRuntimeAuthoritativeResult, validateWorkflowRuntimeMutationCommand, } from './workflowRuntimeSync.js';
9
9
  import { WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_SELECTOR } from './workspaceSyncV3WorkflowWireContract.js';
10
+ import { WORKSPACE_SYNC_V3_WORKFLOW_TASK_COVER_COVERAGE_SELECTOR, } from './workspaceSyncV3WorkflowTaskCoverWireContract.js';
10
11
  const OPERATION_LEASE_MS = 30_000;
11
12
  export class DurableWorkflowRuntimeRouterDisabledError extends Error {
12
13
  code = 'WORKSPACE_SYNC_V3_WORKFLOW_RUNTIME_ROUTER_DISABLED';
@@ -26,31 +27,55 @@ export class DurableWorkflowRuntimeRouterInProgressError extends Error {
26
27
  this.name = 'DurableWorkflowRuntimeRouterInProgressError';
27
28
  }
28
29
  }
30
+ export class DurableWorkflowRuntimeExecutionNotFoundError extends Error {
31
+ code = 'execution_not_found';
32
+ statusCode = 404;
33
+ constructor() {
34
+ super('Workflow execution not found.');
35
+ this.name = 'DurableWorkflowRuntimeExecutionNotFoundError';
36
+ }
37
+ }
38
+ export function areWorkflowRuntimeMutationsFenced(env = process.env) {
39
+ return String(env.TASKFORCE_SYNC_V3_WORKFLOW_RUNTIME_MUTATIONS_FENCED || '')
40
+ .trim()
41
+ .toLowerCase() === 'true';
42
+ }
29
43
  function required(value, label) {
30
44
  const normalized = String(value || '').trim();
31
45
  if (!normalized)
32
46
  throw new Error(`${label} is required.`);
33
47
  return normalized;
34
48
  }
35
- function isWorkflowCoverageSelected(env) {
49
+ const WORKFLOW_RUNTIME_COVERAGE_SELECTORS = [
50
+ WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_SELECTOR,
51
+ WORKSPACE_SYNC_V3_WORKFLOW_TASK_COVER_COVERAGE_SELECTOR,
52
+ ];
53
+ function resolveSelectedWorkflowCoverage(env) {
36
54
  try {
37
55
  const coverage = resolveRequestedCombinedFeedCoverage(env);
38
- return coverage.coverageProfileId === WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_SELECTOR.coverageProfileId
39
- && coverage.coverageVersion === WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_SELECTOR.coverageVersion
40
- && coverage.coverageDigest === WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_SELECTOR.coverageDigest;
56
+ return WORKFLOW_RUNTIME_COVERAGE_SELECTORS.find((candidate) => (coverage.coverageProfileId === candidate.coverageProfileId
57
+ && coverage.coverageVersion === candidate.coverageVersion
58
+ && coverage.coverageDigest === candidate.coverageDigest)) || null;
41
59
  }
42
60
  catch {
43
- return false;
61
+ return null;
44
62
  }
45
63
  }
46
64
  export function resolveWorkflowRuntimeMutationCapability(input) {
47
65
  const env = input.env || process.env;
48
- if (!isWorkflowCoverageSelected(env))
66
+ if (areWorkflowRuntimeMutationsFenced(env))
67
+ return false;
68
+ return resolveWorkflowRuntimeDurableTransportCapability(input);
69
+ }
70
+ export function resolveWorkflowRuntimeDurableTransportCapability(input) {
71
+ const env = input.env || process.env;
72
+ const coverage = resolveSelectedWorkflowCoverage(env);
73
+ if (!coverage)
49
74
  return false;
50
75
  const capability = resolveCombinedFeedCapability({
51
76
  runtimeMode: input.runtimeMode,
52
77
  env,
53
- coverage: WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_SELECTOR,
78
+ coverage,
54
79
  }).combinedFeed;
55
80
  return capability.activationReady;
56
81
  }
@@ -62,7 +87,11 @@ function parseExistingLocalCommand(store, identity) {
62
87
  throw new Error('Operation identity is assigned to another local mutation.');
63
88
  }
64
89
  try {
65
- return validateWorkflowRuntimeMutationCommand(JSON.parse(existing.payloadJson));
90
+ const command = validateWorkflowRuntimeMutationCommand(JSON.parse(existing.payloadJson));
91
+ store.assertOutboxOperationIdentity(existing, {
92
+ domain: 'workflow-execution', entityId: command.executionId, mutationKind: command.kind,
93
+ });
94
+ return command;
66
95
  }
67
96
  catch {
68
97
  throw new Error('Captured workflow runtime command is invalid.');
@@ -254,7 +283,7 @@ export function createDurableWorkflowRuntimeMutationRouter(input) {
254
283
  const workflowStore = new WorkflowStore(input.core.getDatabaseAdapter(), tenantId);
255
284
  const snapshot = workflowStore.getExecutionStateSnapshot(workspaceId, args.executionId);
256
285
  if (!snapshot)
257
- throw new Error('Workflow execution not found.');
286
+ throw new DurableWorkflowRuntimeExecutionNotFoundError();
258
287
  const committed = readCommittedCloudResponse();
259
288
  if (committed) {
260
289
  const event = snapshot.events.find((candidate) => candidate.idempotencyKey === operationId);
@@ -307,7 +336,7 @@ export function createDurableWorkflowRuntimeMutationRouter(input) {
307
336
  const workflowStore = new WorkflowStore(input.core.getDatabaseAdapter(), tenantId);
308
337
  const snapshot = workflowStore.getExecutionStateSnapshot(workspaceId, args.executionId);
309
338
  if (!snapshot)
310
- throw new Error('Workflow execution not found.');
339
+ throw new DurableWorkflowRuntimeExecutionNotFoundError();
311
340
  const committed = readCommittedCloudResponse();
312
341
  if (committed) {
313
342
  const completedEvent = snapshot.events.find((event) => event.idempotencyKey === `${operationId}:step-completed`);
@@ -7,6 +7,7 @@ import { enqueueLocalWorkstreamMutation, } from './localWorkstreamOutboxService.
7
7
  import { isWorkspaceSyncV3PlanningActivationEnabled } from './planningActivation.js';
8
8
  import { serializeEntityActivityForSync } from './taskActivityJournal.js';
9
9
  import { WorkspaceSyncDurabilityStore, WorkspaceSyncIdempotencyConflictError } from './syncDurabilityStore.js';
10
+ import { readDurableOperationReplay } from './durableOperationReplay.js';
10
11
  import { buildWorkstreamActivityEventId } from './workstreamActivityIdentity.js';
11
12
  const OPERATION_LEASE_MS = 30_000;
12
13
  export class DurableWorkstreamMutationRouterDisabledError extends Error {
@@ -85,6 +86,9 @@ export function createDurableWorkstreamMutationRouter(input) {
85
86
  if (persistedOutbox.domain !== 'workstream' || persistedOutbox.entityId !== workstreamId) {
86
87
  throw new WorkspaceSyncIdempotencyConflictError();
87
88
  }
89
+ store.assertOutboxOperationIdentity(persistedOutbox, {
90
+ domain: 'workstream', entityId: workstreamId, mutationKind: persistedOutbox.mutationKind,
91
+ });
88
92
  return {
89
93
  revisions: {
90
94
  entityRevision: persistedOutbox.baseEntityRevision,
@@ -99,18 +103,22 @@ export function createDurableWorkstreamMutationRouter(input) {
99
103
  if (operationState?.status === 'committed') {
100
104
  if (!operationState.responseJson)
101
105
  throw new Error('Committed operation is missing its response.');
102
- const response = JSON.parse(operationState.responseJson);
103
- if (response.authoritative.entityId !== workstreamId) {
104
- throw new WorkspaceSyncIdempotencyConflictError();
105
- }
106
- const lifecycleMutation = response.authoritative.mutationKind === 'archive'
107
- || response.authoritative.mutationKind === 'unarchive';
106
+ const parsed = JSON.parse(operationState.responseJson);
107
+ const lifecycleMutation = parsed.authoritative.mutationKind === 'archive'
108
+ || parsed.authoritative.mutationKind === 'unarchive';
109
+ const replay = readDurableOperationReplay({
110
+ responseJson: operationState.responseJson,
111
+ operationId,
112
+ domain: 'workstream',
113
+ entityId: workstreamId,
114
+ mutationKind: parsed.authoritative.mutationKind,
115
+ revisionMode: lifecycleMutation ? 'both' : 'metadata',
116
+ });
117
+ const response = replay.response;
108
118
  return {
109
119
  revisions: {
110
- entityRevision: String(BigInt(response.authoritative.entityRevision) - 1n),
111
- lifecycleRevision: lifecycleMutation
112
- ? String(BigInt(response.authoritative.lifecycleRevision) - 1n)
113
- : response.authoritative.lifecycleRevision,
120
+ entityRevision: replay.baseEntityRevision,
121
+ lifecycleRevision: replay.baseLifecycleRevision,
114
122
  },
115
123
  persistedOutbox: null,
116
124
  committedResponse: response,