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