@taskforcehq/taskforce 0.3.327 → 0.3.329

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