@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
@@ -36,11 +36,12 @@ function taskHttpObservedPrecondition(task, taskId) {
36
36
  return {
37
37
  taskId,
38
38
  updatedAt: task?.updatedAt ?? null,
39
+ detailRevision: task?.detailRevision ?? null,
39
40
  status: task?.status ?? null,
40
41
  isArchived: task?.isArchived === true,
41
42
  };
42
43
  }
43
- export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks, setArchivedTasks, setDeletedTasks, setError, resetForm, setActiveTab, fetchTasks, fetchArchive, fetchDeletedTasks, mergeTaskFromServer, pushNotice, cloudAuthConfigured, runtimeMode, isAuthenticated, workspaceCloudSyncEnabled, buildWorkspaceSyncSignature, pushWorkspaceChangesToCloud, workspacePendingSignatureRef, workspaceDeletedTaskIdsRef, workspaceDeletedTaskWatermarksRef, mutateTaskMetadata, mutateTaskStatus, mutateTaskLifecycle, mutateTaskDelete, mutateTaskRestore, durableTaskMetadataActivationEnabled = false, durableTaskStatusActivationEnabled = false, durableTaskDeleteActivationEnabled = false, durableTaskHttpRootActivationEnabled = false, workspaceId = 'default', taskHttpMutationClient, }) {
44
+ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, editingTaskDetailRevision = null, setTasks, setArchivedTasks, setDeletedTasks, setError, resetForm, setActiveTab, fetchTasks, fetchArchive, fetchDeletedTasks, mergeTaskFromServer, pushNotice, cloudAuthConfigured, runtimeMode, isAuthenticated, workspaceCloudSyncEnabled, buildWorkspaceSyncSignature, pushWorkspaceChangesToCloud, workspacePendingSignatureRef, workspaceDeletedTaskIdsRef, workspaceDeletedTaskWatermarksRef, mutateTaskMetadata, mutateTaskStatus, mutateTaskLifecycle, mutateTaskDelete, mutateTaskRestore, durableTaskMetadataActivationEnabled = false, durableTaskStatusActivationEnabled = false, durableTaskDeleteActivationEnabled = false, durableTaskHttpRootActivationEnabled = false, workspaceId = 'default', taskHttpMutationClient, onTaskRevisionConflict, onTaskMutationAccepted, }) {
44
45
  const authoritativeTaskSnapshotsRef = useRef(new Map());
45
46
  useEffect(() => {
46
47
  if (typeof window === 'undefined')
@@ -418,8 +419,10 @@ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks
418
419
  pushNotice(message, 'error');
419
420
  return true;
420
421
  }
421
- if ('task' in result && result.task)
422
+ if ('task' in result && result.task) {
422
423
  mergeTaskFromServer(result.task);
424
+ onTaskMutationAccepted?.(result.task);
425
+ }
423
426
  if (result.state === 'accepted') {
424
427
  setError('');
425
428
  }
@@ -441,8 +444,10 @@ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks
441
444
  pushNotice(message, 'error');
442
445
  }
443
446
  return true;
444
- }, [mergeTaskFromServer, pushNotice, setArchivedTasks, setError, setTasks]);
445
- const handleSetStatus = useCallback(async (task, status, updates = {}) => {
447
+ }, [mergeTaskFromServer, onTaskMutationAccepted, pushNotice, setArchivedTasks, setError, setTasks]);
448
+ const handleSetStatus = useCallback(async (task, status, updates = {}, expectedDetailRevisionOverride) => {
449
+ const expectedDetailRevision = expectedDetailRevisionOverride
450
+ ?? (task.id === editingTaskId ? editingTaskDetailRevision : null);
446
451
  const containsDurableMetadata = Object.keys(updates)
447
452
  .some((key) => DURABLE_TASK_METADATA_FIELD_NAMES.has(key));
448
453
  const unsupportedFields = Object.keys(updates).filter((key) => (!TASK_STATUS_CONTROL_FIELDS.has(key) && !DURABLE_TASK_METADATA_FIELD_NAMES.has(key)));
@@ -468,17 +473,55 @@ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks
468
473
  setArchivedTasks((current) => current.map((item) => item.id === task.id ? { ...item, ...optimisticPatch } : item));
469
474
  if (mutateTaskStatus) {
470
475
  try {
471
- const assigneeIntent = Object.prototype.hasOwnProperty.call(updates, 'assignee')
472
- ? { kind: 'set', value: updates.assignee ?? null }
473
- : { kind: 'preserve' };
474
- const metadataPatch = selectDurableTaskMetadataPatch(updates);
475
- delete metadataPatch.assignee;
476
- const durableResult = await mutateTaskStatus(task.id, {
477
- status,
478
- assigneeIntent,
479
- canceledReason: status === 'cancelled' ? (updates.canceledReason ?? null) : null,
480
- metadataPatch,
481
- });
476
+ const buildDurablePayload = (targetStatus, targetUpdates, detailRevision) => {
477
+ const assigneeIntent = Object.prototype.hasOwnProperty.call(targetUpdates, 'assignee')
478
+ ? { kind: 'set', value: targetUpdates.assignee ?? null }
479
+ : { kind: 'preserve' };
480
+ const metadataPatch = selectDurableTaskMetadataPatch(targetUpdates);
481
+ delete metadataPatch.assignee;
482
+ return {
483
+ status: targetStatus,
484
+ assigneeIntent,
485
+ canceledReason: targetStatus === 'cancelled'
486
+ ? (targetUpdates.canceledReason ?? null)
487
+ : null,
488
+ metadataPatch,
489
+ ...(detailRevision ? { expectedDetailRevision: detailRevision } : {}),
490
+ };
491
+ };
492
+ let durableResult = await mutateTaskStatus(task.id, buildDurablePayload(status, updates, expectedDetailRevision));
493
+ if (durableResult
494
+ && (durableResult.state === 'rejected' || durableResult.state === 'failed')
495
+ && durableResult.errorCode === 'TASK_DETAIL_REVISION_CONFLICT') {
496
+ const previousTask = previousTasks.find((item) => item.id === task.id)
497
+ || previousArchivedTasks.find((item) => item.id === task.id);
498
+ setTasks((current) => rollbackTargetTaskPatch(current, previousTask, task.id, optimisticPatch));
499
+ setArchivedTasks((current) => rollbackTargetTaskPatch(current, previousTask, task.id, optimisticPatch));
500
+ const resolution = await onTaskRevisionConflict?.(task.id, null);
501
+ if (resolution?.retryDetailRevision) {
502
+ const retryPatch = Object.fromEntries(Object.entries(updates).map(([key, value]) => [
503
+ key,
504
+ resolution.retryPatch && Object.prototype.hasOwnProperty.call(resolution.retryPatch, key)
505
+ ? resolution.retryPatch[key]
506
+ : value,
507
+ ]));
508
+ const retryStatus = (resolution.retryPatch?.status || status);
509
+ durableResult = await mutateTaskStatus(task.id, buildDurablePayload(retryStatus, retryPatch, resolution.retryDetailRevision));
510
+ if (durableResult
511
+ && (durableResult.state === 'rejected' || durableResult.state === 'failed')
512
+ && durableResult.errorCode === 'TASK_DETAIL_REVISION_CONFLICT') {
513
+ const secondResolution = await onTaskRevisionConflict?.(task.id, null);
514
+ if (secondResolution?.handled) {
515
+ setError('');
516
+ return;
517
+ }
518
+ }
519
+ }
520
+ else if (resolution?.handled) {
521
+ setError('');
522
+ return;
523
+ }
524
+ }
482
525
  if (durableResult && finishDurableTaskMutation(durableResult, task.id, optimisticPatch, previousTasks, previousArchivedTasks))
483
526
  return;
484
527
  if (!durableResult && durableTaskStatusActivationEnabled) {
@@ -515,15 +558,54 @@ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks
515
558
  return;
516
559
  }
517
560
  try {
518
- const legacyPatch = { ...updates, status, completedAt: optimisticPatch.completedAt };
519
- const requestInit = {
520
- method: 'PATCH',
521
- headers: { 'Content-Type': 'application/json' },
522
- body: JSON.stringify(legacyPatch),
561
+ const legacyPatch = {
562
+ ...updates,
563
+ status,
564
+ completedAt: optimisticPatch.completedAt,
565
+ ...(expectedDetailRevision ? { expectedDetailRevision } : {}),
523
566
  };
524
- const res = await fetchCloudTaskRootPatch(`/api/taskforce/task/${task.id}`, requestInit, legacyPatch, task.id, taskHttpObservedPrecondition(task, task.id));
567
+ let activePatch = legacyPatch;
568
+ let res;
569
+ let data = {};
570
+ for (let attempt = 0;; attempt += 1) {
571
+ res = await fetchCloudTaskRootPatch(`/api/taskforce/task/${task.id}`, {
572
+ method: 'PATCH',
573
+ headers: { 'Content-Type': 'application/json' },
574
+ body: JSON.stringify(activePatch),
575
+ }, activePatch, task.id, taskHttpObservedPrecondition(task, task.id));
576
+ if (res.ok)
577
+ break;
578
+ data = await res.json().catch(() => ({}));
579
+ if (data.code !== 'TASK_DETAIL_REVISION_CONFLICT')
580
+ break;
581
+ setTasks(previousTasks);
582
+ setArchivedTasks(previousArchivedTasks);
583
+ const currentDetailRevision = typeof data?.details?.currentDetailRevision === 'string'
584
+ ? data.details.currentDetailRevision
585
+ : null;
586
+ const resolution = await onTaskRevisionConflict?.(task.id, currentDetailRevision);
587
+ if (attempt === 0 && resolution?.retryDetailRevision) {
588
+ const retryPatch = Object.fromEntries(Object.entries(legacyPatch).map(([key, value]) => [
589
+ key,
590
+ resolution.retryPatch && Object.prototype.hasOwnProperty.call(resolution.retryPatch, key)
591
+ ? resolution.retryPatch[key]
592
+ : value,
593
+ ]));
594
+ activePatch = {
595
+ ...retryPatch,
596
+ expectedDetailRevision: resolution.retryDetailRevision,
597
+ };
598
+ continue;
599
+ }
600
+ if (resolution?.handled) {
601
+ setError('');
602
+ return;
603
+ }
604
+ break;
605
+ }
525
606
  if (!res.ok) {
526
- const data = await res.json().catch(() => ({}));
607
+ if (Object.keys(data).length === 0)
608
+ data = await res.json().catch(() => ({}));
527
609
  const message = data.error || 'Failed to update task status.';
528
610
  setError(message);
529
611
  pushNotice(message, 'error');
@@ -532,8 +614,10 @@ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks
532
614
  return;
533
615
  }
534
616
  const updatedTask = await res.json().catch(() => null);
535
- if (updatedTask)
617
+ if (updatedTask) {
536
618
  mergeTaskFromServer(updatedTask);
619
+ onTaskMutationAccepted?.(updatedTask);
620
+ }
537
621
  else
538
622
  await fetchTasks(true);
539
623
  queueWorkspaceSyncFromAuthoritativeTaskState();
@@ -549,6 +633,8 @@ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks
549
633
  }, [
550
634
  archivedTasks,
551
635
  durableTaskMetadataActivationEnabled,
636
+ editingTaskDetailRevision,
637
+ editingTaskId,
552
638
  durableTaskHttpRootActivationEnabled,
553
639
  durableTaskStatusActivationEnabled,
554
640
  fetchTasks,
@@ -556,6 +642,8 @@ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks
556
642
  finishDurableTaskMutation,
557
643
  mergeTaskFromServer,
558
644
  mutateTaskStatus,
645
+ onTaskMutationAccepted,
646
+ onTaskRevisionConflict,
559
647
  pushNotice,
560
648
  queueWorkspaceSyncFromAuthoritativeTaskState,
561
649
  setArchivedTasks,
@@ -564,8 +652,14 @@ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks
564
652
  tasks,
565
653
  ]);
566
654
  const handleUpdateTask = useCallback(async (id, updates) => {
567
- const saveSource = updates.saveSource;
568
- updates = Object.fromEntries(Object.entries(updates).filter(([key]) => key !== 'saveSource'));
655
+ const specialFields = updates;
656
+ const saveSource = specialFields.saveSource;
657
+ const expectedDetailRevision = typeof specialFields.expectedDetailRevision === 'string'
658
+ ? specialFields.expectedDetailRevision
659
+ : id === editingTaskId
660
+ ? editingTaskDetailRevision
661
+ : null;
662
+ updates = Object.fromEntries(Object.entries(updates).filter(([key]) => (key !== 'saveSource' && key !== 'expectedDetailRevision')));
569
663
  if (Object.keys(updates).length === 0)
570
664
  return true;
571
665
  const authoritativeTask = authoritativeTaskSnapshotsRef.current.get(id);
@@ -589,7 +683,7 @@ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks
589
683
  if (updates.status) {
590
684
  const target = tasks.find((task) => task.id === id) || archivedTasks.find((task) => task.id === id);
591
685
  if (target) {
592
- await handleSetStatus(target, updates.status, updates);
686
+ await handleSetStatus(target, updates.status, updates, expectedDetailRevision);
593
687
  return;
594
688
  }
595
689
  if (durableTaskStatusActivationEnabled) {
@@ -610,10 +704,58 @@ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks
610
704
  let durableMetadataHandled = false;
611
705
  if (hasDurableMetadata && mutateTaskMetadata) {
612
706
  try {
613
- const durableResult = saveSource
614
- ? await mutateTaskMetadata(id, durableMetadataPatch, { saveSource })
707
+ const initialMutationOptions = {
708
+ ...(saveSource ? { saveSource } : {}),
709
+ ...(expectedDetailRevision ? { expectedDetailRevision } : {}),
710
+ };
711
+ let durableResult = Object.keys(initialMutationOptions).length > 0
712
+ ? await mutateTaskMetadata(id, durableMetadataPatch, initialMutationOptions)
615
713
  : await mutateTaskMetadata(id, durableMetadataPatch);
616
714
  if (durableResult && durableResult.state !== 'disabled') {
715
+ if ((durableResult.state === 'rejected' || durableResult.state === 'failed')
716
+ && durableResult.errorCode === 'TASK_DETAIL_REVISION_CONFLICT') {
717
+ const previousTask = previousTasks.find((task) => task.id === id)
718
+ || previousArchivedTasks.find((task) => task.id === id);
719
+ setTasks((currentTasks) => rollbackTargetTaskPatch(currentTasks, previousTask, id, updates));
720
+ setArchivedTasks((currentTasks) => rollbackTargetTaskPatch(currentTasks, previousTask, id, updates));
721
+ const resolution = await onTaskRevisionConflict?.(id, null);
722
+ if (resolution?.retryDetailRevision) {
723
+ const reconciledPatch = resolution.retryPatch;
724
+ const retryMetadataPatch = Object.fromEntries(Object.entries(durableMetadataPatch).map(([key, value]) => [
725
+ key,
726
+ reconciledPatch && Object.prototype.hasOwnProperty.call(reconciledPatch, key)
727
+ ? reconciledPatch[key]
728
+ : value,
729
+ ]));
730
+ durableResult = await mutateTaskMetadata(id, retryMetadataPatch, {
731
+ ...(saveSource ? { saveSource } : {}),
732
+ expectedDetailRevision: resolution.retryDetailRevision,
733
+ });
734
+ if (durableResult
735
+ && (durableResult.state === 'rejected' || durableResult.state === 'failed')
736
+ && durableResult.errorCode === 'TASK_DETAIL_REVISION_CONFLICT') {
737
+ const secondResolution = await onTaskRevisionConflict?.(id, null);
738
+ if (secondResolution?.handled) {
739
+ setError('');
740
+ return false;
741
+ }
742
+ }
743
+ }
744
+ else if (resolution?.handled) {
745
+ setError('');
746
+ return false;
747
+ }
748
+ }
749
+ if (!durableResult || durableResult.state === 'disabled') {
750
+ const previousTask = previousTasks.find((task) => task.id === id)
751
+ || previousArchivedTasks.find((task) => task.id === id);
752
+ setTasks((currentTasks) => rollbackTargetTaskPatch(currentTasks, previousTask, id, updates));
753
+ setArchivedTasks((currentTasks) => rollbackTargetTaskPatch(currentTasks, previousTask, id, updates));
754
+ const message = 'Task was not saved because durable metadata capture became unavailable during retry.';
755
+ setError(message);
756
+ pushNotice(message, 'error');
757
+ return false;
758
+ }
617
759
  if (durableResult.state === 'rejected' || durableResult.state === 'failed') {
618
760
  const previousTask = previousTasks.find((task) => task.id === id)
619
761
  || previousArchivedTasks.find((task) => task.id === id);
@@ -629,8 +771,10 @@ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks
629
771
  return false;
630
772
  }
631
773
  durableMetadataHandled = true;
632
- if ('task' in durableResult && durableResult.task)
774
+ if ('task' in durableResult && durableResult.task) {
633
775
  mergeTaskFromServer(durableResult.task);
776
+ onTaskMutationAccepted?.(durableResult.task);
777
+ }
634
778
  if (durableResult.state === 'accepted') {
635
779
  setError('');
636
780
  }
@@ -708,32 +852,68 @@ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks
708
852
  const legacyRequestPatch = {
709
853
  ...legacyCarrierPatch,
710
854
  ...(saveSource ? { saveSource } : {}),
855
+ ...(expectedDetailRevision ? { expectedDetailRevision } : {}),
711
856
  };
712
857
  const requestInit = {
713
858
  method: 'PATCH',
714
859
  headers: { 'Content-Type': 'application/json' },
715
860
  body: JSON.stringify(legacyRequestPatch),
716
861
  };
717
- const res = await fetchCloudTaskRootPatch(`/api/taskforce/task/${id}`, requestInit, legacyRequestPatch, id, taskHttpObservedPrecondition(previousTasks.find((task) => task.id === id)
718
- || previousArchivedTasks.find((task) => task.id === id), id));
719
- if (!res.ok) {
862
+ let activeRequestPatch = legacyRequestPatch;
863
+ for (let attempt = 0; attempt < 2; attempt += 1) {
864
+ const activeRequestInit = attempt === 0 ? requestInit : {
865
+ ...requestInit,
866
+ body: JSON.stringify(activeRequestPatch),
867
+ };
868
+ const res = await fetchCloudTaskRootPatch(`/api/taskforce/task/${id}`, activeRequestInit, activeRequestPatch, id, taskHttpObservedPrecondition(previousTasks.find((task) => task.id === id)
869
+ || previousArchivedTasks.find((task) => task.id === id), id));
870
+ if (res.ok) {
871
+ const updatedTask = await res.json().catch(() => null);
872
+ mergeTaskFromServer(updatedTask);
873
+ if (updatedTask && typeof updatedTask === 'object' && typeof updatedTask.id === 'string') {
874
+ onTaskMutationAccepted?.(updatedTask);
875
+ }
876
+ // Attachment saves also depend on the canonical asset snapshot refresh. Give that
877
+ // snapshot a brief head start so the next push includes both task metadata and bytes.
878
+ queueWorkspaceSyncFromAuthoritativeTaskState(updates.attachments !== undefined ? 150 : 0);
879
+ setError('');
880
+ return true;
881
+ }
720
882
  const data = await res.json().catch(() => ({}));
721
- const message = data.error || `Failed to update task ${id}.`;
722
- setError(message);
723
- pushNotice(message, 'error');
724
883
  const previousTask = previousTasks.find((task) => task.id === id)
725
884
  || previousArchivedTasks.find((task) => task.id === id);
726
885
  setTasks((currentTasks) => rollbackTargetTaskPatch(currentTasks, previousTask, id, legacyCarrierPatch));
727
886
  setArchivedTasks((currentTasks) => rollbackTargetTaskPatch(currentTasks, previousTask, id, legacyCarrierPatch));
887
+ if (data.code === 'TASK_DETAIL_REVISION_CONFLICT') {
888
+ const currentDetailRevision = typeof data?.details?.currentDetailRevision === 'string'
889
+ ? data.details.currentDetailRevision
890
+ : null;
891
+ const resolution = await onTaskRevisionConflict?.(id, currentDetailRevision);
892
+ if (attempt === 0 && resolution?.retryDetailRevision) {
893
+ const reconciledPatch = resolution.retryPatch;
894
+ const retryPatch = Object.fromEntries(Object.entries(legacyRequestPatch).map(([key, value]) => [
895
+ key,
896
+ reconciledPatch && Object.prototype.hasOwnProperty.call(reconciledPatch, key)
897
+ ? reconciledPatch[key]
898
+ : value,
899
+ ]));
900
+ activeRequestPatch = {
901
+ ...retryPatch,
902
+ expectedDetailRevision: resolution.retryDetailRevision,
903
+ };
904
+ continue;
905
+ }
906
+ if (resolution?.handled) {
907
+ setError('');
908
+ return false;
909
+ }
910
+ }
911
+ const message = data.error || `Failed to update task ${id}.`;
912
+ setError(message);
913
+ pushNotice(message, 'error');
728
914
  return false;
729
915
  }
730
- const updatedTask = await res.json().catch(() => null);
731
- mergeTaskFromServer(updatedTask);
732
- // Attachment saves also depend on the canonical asset snapshot refresh. Give that
733
- // snapshot a brief head start so the next push includes both task metadata and bytes.
734
- queueWorkspaceSyncFromAuthoritativeTaskState(updates.attachments !== undefined ? 150 : 0);
735
- setError('');
736
- return true;
916
+ return false;
737
917
  }
738
918
  catch (err) {
739
919
  console.error("Failed to update task", err);
@@ -746,7 +926,7 @@ export function useTaskMutations({ tasks, archivedTasks, editingTaskId, setTasks
746
926
  setArchivedTasks((currentTasks) => rollbackTargetTaskPatch(currentTasks, previousTask, id, legacyCarrierPatch));
747
927
  return false;
748
928
  }
749
- }, [tasks, archivedTasks, pushNotice, mergeTaskFromServer, mutateTaskMetadata, queueWorkspaceSyncFromAuthoritativeTaskState, handleSetStatus, durableTaskMetadataActivationEnabled, durableTaskStatusActivationEnabled, fetchCloudTaskRootPatch]);
929
+ }, [tasks, archivedTasks, editingTaskDetailRevision, editingTaskId, pushNotice, mergeTaskFromServer, mutateTaskMetadata, onTaskMutationAccepted, onTaskRevisionConflict, queueWorkspaceSyncFromAuthoritativeTaskState, handleSetStatus, durableTaskMetadataActivationEnabled, durableTaskStatusActivationEnabled, fetchCloudTaskRootPatch]);
750
930
  const handleToggleComplete = async (task) => {
751
931
  const newStatus = task.status === 'done' ? 'task' : 'done';
752
932
  await handleSetStatus(task, newStatus);