@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
@@ -41,6 +41,8 @@ import { resolveRuntimeModeContract } from '../shared/runtimeContract';
41
41
  import { DEFAULT_TYPE_VALUE } from '../shared/taxonomyDefaults.js';
42
42
  import { resolveClientDeploymentConfig } from '../config/clientDeployment';
43
43
  import { resolveTaskforceMcpBaseUrlFromBaseUrl } from '../config/cloudEnvironment';
44
+ import { applyEditorDraftToTask, formatTaskEditorConflictFields, preserveUnresolvedTaskEditorConflicts, reconcileTaskEditorDraft, resolveTaskEditorConflicts, taskToEditorDraft, } from '../utils/taskEditorReconciliation';
45
+ import { isResolvedFeatureAccessMap, } from '../runtime/appGates';
44
46
  import { buildBootstrapTraceId, withBootstrapTraceHeader } from '../utils/bootstrapTrace';
45
47
  import { buildTaskforceCredentialLoginPayload } from '../utils/authLogin';
46
48
  import { createDefaultAssigneeOptions } from '../utils/assignees';
@@ -59,6 +61,7 @@ import { useCurrentTaskRelations } from './tasks/useCurrentTaskRelations';
59
61
  import { useTaskEditorNavigation } from './tasks/useTaskEditorNavigation';
60
62
  import { useTaskFilters } from './tasks/useTaskFilters';
61
63
  import { useTaskFormActions } from './tasks/useTaskFormActions';
64
+ import { useTaskDescriptionImageDraftRecovery } from './tasks/useTaskDescriptionImageDraftRecovery';
62
65
  import { useTaskRelationships } from './tasks/useTaskRelationships';
63
66
  import { useTaskActions } from './tasks/useTaskActions';
64
67
  import { clearPersistedWorkspaceId, logBootstrapDebug, readPersistedWorkspaceId, writePersistedWorkspaceId } from './workspace/workspaceLocalState';
@@ -80,6 +83,19 @@ import { createTaskInvalidationScope, mergeTaskInvalidationScopes, resolveTaskIn
80
83
  import { createCloudWorkstreamHttpMutationClient, fetchWorkstreamHttpMutation, isConclusiveWorkstreamHttpResponse, selectCreatedWorkstreamAfterRefresh, } from './workstreams/workstreamHttpMutation';
81
84
  import { dispatchTaskforceWorkspaceResourcesInvalidated } from '../utils/workspaceResourceEvents';
82
85
  import { dispatchTaskforceAuthSessionChanged } from '../utils/authSessionEvents';
86
+ export function buildRelationshipTasks(tasks, archivedTasks, taskDetails, editingTaskId) {
87
+ const byId = new Map();
88
+ for (const task of archivedTasks)
89
+ byId.set(task.id, task);
90
+ for (const task of tasks)
91
+ byId.set(task.id, task);
92
+ if (editingTaskId && byId.has(editingTaskId)) {
93
+ const currentDetail = taskDetails.find((task) => task.id === editingTaskId);
94
+ if (currentDetail)
95
+ byId.set(editingTaskId, currentDetail);
96
+ }
97
+ return Array.from(byId.values());
98
+ }
83
99
  function upsertEntityById(items, nextItem) {
84
100
  const existingIndex = items.findIndex((item) => item.id === nextItem.id);
85
101
  if (existingIndex === -1) {
@@ -208,6 +224,7 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
208
224
  authSource: '',
209
225
  workspaceMode: '',
210
226
  workspaceSwitchingEnabled: null,
227
+ appGates: undefined,
211
228
  syncV3TaskMetadataActivation: false,
212
229
  syncV3TaskCreateActivation: false,
213
230
  syncV3TaskStatusActivation: false,
@@ -267,6 +284,9 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
267
284
  workspaceSwitchingEnabled: typeof cfg.workspaceSwitchingEnabled === 'boolean'
268
285
  ? Boolean(cfg.workspaceSwitchingEnabled)
269
286
  : (workspaceMode === 'multi-cloud'),
287
+ appGates: isResolvedFeatureAccessMap(cfg.appGates)
288
+ ? cfg.appGates
289
+ : undefined,
270
290
  syncV3TaskMetadataActivation: cfg.syncV3?.taskMetadataActivation === true,
271
291
  syncV3TaskCreateActivation: cfg.syncV3?.taskCreateActivation === true,
272
292
  syncV3TaskStatusActivation: cfg.syncV3?.taskStatusActivation === true,
@@ -619,6 +639,11 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
619
639
  const [manualComplexityEnabled, setManualComplexityEnabled] = useState(false);
620
640
  const [checklistDropdownEnabled, setChecklistDropdownEnabled] = useState(true);
621
641
  const [showTaskCardStatusLabel, setShowTaskCardStatusLabel] = useState(false);
642
+ const [showTaskCardDescription, setShowTaskCardDescription] = useState(true);
643
+ const [showTaskCardAttachments, setShowTaskCardAttachments] = useState(true);
644
+ const [showTaskCardChecklistProgress, setShowTaskCardChecklistProgress] = useState(true);
645
+ const [showTaskCardLatestActivity, setShowTaskCardLatestActivity] = useState(true);
646
+ const [tintTaskCardActivityBackground, setTintTaskCardActivityBackground] = useState(false);
622
647
  const [serverHostRoot, setServerHostRoot] = useState('');
623
648
  const [returnTab, setReturnTab] = useState(null);
624
649
  useTaskforceApiRouting({
@@ -666,6 +691,12 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
666
691
  const deletedHydrationRequestRef = useRef(null);
667
692
  const [loadingTasks, setLoadingTasks] = useState(false);
668
693
  const [editingTaskId, setEditingTaskId] = useState(null);
694
+ const editorBaselineRef = useRef(null);
695
+ const [editorBaseline, setEditorBaseline] = useState(null);
696
+ const [editingTaskRevisionConflict, setEditingTaskRevisionConflict] = useState(null);
697
+ const editingTaskRevisionConflictRef = useRef(null);
698
+ const reconcileOpenTaskWithRemoteRef = useRef(() => null);
699
+ const refreshingTaskRevisionRef = useRef(null);
669
700
  const [pendingOpenTaskId, setPendingOpenTaskId] = useState(null);
670
701
  const setPendingOpenTaskIdFromPersistedState = useCallback((taskId) => {
671
702
  if (String(initialTaskId || '').trim())
@@ -852,7 +883,7 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
852
883
  }, [AUTH_REQUIRED_ERROR, runtimeMode]);
853
884
  // === SECTION: Task Data ===
854
885
  // Delegated to useTaskData — see src/hooks/useTaskData.ts
855
- const { tasksRef, archivedTasksRef, recentlyChangedTaskIds, markRecentlyChangedTasks, fetchTasks: fetchTasksBase, fetchArchive: fetchArchiveBase, refreshTaskCollections: refreshTaskCollectionsBase, refreshTaskCollectionsFromInvalidation: refreshTaskCollectionsFromInvalidationBase, mergeTaskFromServer, getTaskRevisionKey } = useTaskData({
886
+ const { tasksRef, archivedTasksRef, taskDetails, staleTaskDetailRevisions, recentlyChangedTaskIds, markRecentlyChangedTasks, fetchTasks: fetchTasksBase, fetchArchive: fetchArchiveBase, loadTaskDetail, cancelTaskDetailLoad, refreshTaskCollections: refreshTaskCollectionsBase, refreshTaskCollectionsFromInvalidation: refreshTaskCollectionsFromInvalidationBase, mergeTaskFromServer, getTaskRevisionKey } = useTaskData({
856
887
  tasks,
857
888
  archivedTasks,
858
889
  setTasks,
@@ -863,7 +894,9 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
863
894
  shouldDeferProtectedApiCalls,
864
895
  shouldBlockProtectedApiCalls,
865
896
  handleUnauthorized,
866
- authRequiredForApi
897
+ authRequiredForApi,
898
+ setError,
899
+ setLoading
867
900
  });
868
901
  useEffect(() => {
869
902
  if (workspaceTransitionEpoch === 0)
@@ -1445,7 +1478,15 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
1445
1478
  configLoaded,
1446
1479
  referenceDataLoaded,
1447
1480
  assigneeOptionsLoaded,
1448
- assigneeOptions
1481
+ assigneeOptions,
1482
+ runtimeMode,
1483
+ workspaceId: currentWorkspaceId,
1484
+ cloudTaskSearchEnabled: runtimeMode === 'cloud'
1485
+ && isAuthenticated
1486
+ && taskScope !== 'deleted'
1487
+ && !shouldDeferProtectedApiCalls
1488
+ && !shouldBlockProtectedApiCalls,
1489
+ cloudTaskSearchScope: taskScope === 'archived' ? 'archive' : 'active',
1449
1490
  });
1450
1491
  setUserGlobalSyncStatusRef.current = setUserGlobalSyncStatus;
1451
1492
  setUserGlobalSyncErrorRef.current = setUserGlobalSyncError;
@@ -1494,7 +1535,46 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
1494
1535
  const [activeWorkspaceModule, setActiveWorkspaceModuleState] = useState('tasks');
1495
1536
  const [descriptionFocused, setDescriptionFocused] = useState(false);
1496
1537
  const [isCapturingScreenshot, setIsCapturingScreenshot] = useState(false);
1497
- const [attachments, setAttachments] = useState([]);
1538
+ const attachmentsDraftRef = useRef([]);
1539
+ const [attachments, setAttachmentsState] = useState([]);
1540
+ const setAttachments = useCallback((next) => {
1541
+ const nextAttachments = typeof next === 'function'
1542
+ ? next(attachmentsDraftRef.current)
1543
+ : next;
1544
+ attachmentsDraftRef.current = nextAttachments;
1545
+ setAttachmentsState(nextAttachments);
1546
+ }, []);
1547
+ const getAttachmentsDraft = useCallback(() => [...attachmentsDraftRef.current], []);
1548
+ const pendingDescriptionImageUploadRef = useRef(null);
1549
+ const [descriptionImageUploadPending, setDescriptionImageUploadPending] = useState(false);
1550
+ const createDescriptionImageDraftId = useCallback(() => (`task-description-${globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random().toString(16).slice(2)}`}`), []);
1551
+ const descriptionImageDraftIdRef = useRef(createDescriptionImageDraftId());
1552
+ const [descriptionImageDraftId, setDescriptionImageDraftId] = useState(descriptionImageDraftIdRef.current);
1553
+ const rotateDescriptionImageDraftId = useCallback(() => {
1554
+ const nextDraftId = createDescriptionImageDraftId();
1555
+ descriptionImageDraftIdRef.current = nextDraftId;
1556
+ setDescriptionImageDraftId(nextDraftId);
1557
+ }, [createDescriptionImageDraftId]);
1558
+ const registerDescriptionImageUpload = useCallback((upload) => {
1559
+ pendingDescriptionImageUploadRef.current = upload;
1560
+ setDescriptionImageUploadPending(true);
1561
+ void upload.then(() => {
1562
+ if (pendingDescriptionImageUploadRef.current !== upload)
1563
+ return;
1564
+ pendingDescriptionImageUploadRef.current = null;
1565
+ setDescriptionImageUploadPending(false);
1566
+ }, () => {
1567
+ if (pendingDescriptionImageUploadRef.current !== upload)
1568
+ return;
1569
+ pendingDescriptionImageUploadRef.current = null;
1570
+ setDescriptionImageUploadPending(false);
1571
+ });
1572
+ }, []);
1573
+ const awaitPendingDescriptionImageUpload = useCallback(async () => {
1574
+ const upload = pendingDescriptionImageUploadRef.current;
1575
+ if (upload)
1576
+ await upload;
1577
+ }, []);
1498
1578
  const [attachmentsDirty, setAttachmentsDirty] = useState(false);
1499
1579
  const dataVersionRef = useRef(null);
1500
1580
  const ambiguousRealtimeConfirmationTimerRef = useRef(null);
@@ -1510,7 +1590,7 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
1510
1590
  const referenceDataRequestRef = useRef(null);
1511
1591
  const workspaceListHydratedRef = useRef(false);
1512
1592
  const hasBootstrappedDataRef = useRef(false);
1513
- const { handleSaveSettings, handleSaveTheme, handleSaveGlobalTheme, handleJsonBackupEnabledChange, handleSaveGlobalJsonBackupEnabled, handleSaveGlobalWeekStartsOn, handleSaveLocale, handleManualComplexityEnabledChange, handleChecklistDropdownEnabledChange, handleShowTaskCardStatusLabelChange, handleResetProjectToGlobal } = useSettingsPersistence({
1593
+ const { handleSaveSettings, handleSaveTheme, handleSaveGlobalTheme, handleUseGlobalThemeDefault, handleJsonBackupEnabledChange, handleSaveGlobalJsonBackupEnabled, handleUseGlobalJsonBackupDefault, handleSaveGlobalWeekStartsOn, handleSaveLocale, handleManualComplexityEnabledChange, handleChecklistDropdownEnabledChange, handleShowTaskCardStatusLabelChange, handleShowTaskCardDescriptionChange, handleShowTaskCardAttachmentsChange, handleShowTaskCardChecklistProgressChange, handleShowTaskCardLatestActivityChange, handleTintTaskCardActivityBackgroundChange } = useSettingsPersistence({
1514
1594
  keyShortcut,
1515
1595
  themeUseGlobalDefault,
1516
1596
  runtimeMode,
@@ -1527,7 +1607,12 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
1527
1607
  setLocale,
1528
1608
  setManualComplexityEnabled,
1529
1609
  setChecklistDropdownEnabled,
1530
- setShowTaskCardStatusLabel
1610
+ setShowTaskCardStatusLabel,
1611
+ setShowTaskCardDescription,
1612
+ setShowTaskCardAttachments,
1613
+ setShowTaskCardChecklistProgress,
1614
+ setShowTaskCardLatestActivity,
1615
+ setTintTaskCardActivityBackground
1531
1616
  });
1532
1617
  useEffect(() => {
1533
1618
  if (runtimeMode !== 'cloud')
@@ -1728,6 +1813,36 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
1728
1813
  else {
1729
1814
  setShowTaskCardStatusLabel(false);
1730
1815
  }
1816
+ if (typeof data.showTaskCardDescription === 'boolean') {
1817
+ setShowTaskCardDescription(data.showTaskCardDescription);
1818
+ }
1819
+ else {
1820
+ setShowTaskCardDescription(true);
1821
+ }
1822
+ if (typeof data.showTaskCardAttachments === 'boolean') {
1823
+ setShowTaskCardAttachments(data.showTaskCardAttachments);
1824
+ }
1825
+ else {
1826
+ setShowTaskCardAttachments(true);
1827
+ }
1828
+ if (typeof data.showTaskCardChecklistProgress === 'boolean') {
1829
+ setShowTaskCardChecklistProgress(data.showTaskCardChecklistProgress);
1830
+ }
1831
+ else {
1832
+ setShowTaskCardChecklistProgress(true);
1833
+ }
1834
+ if (typeof data.showTaskCardLatestActivity === 'boolean') {
1835
+ setShowTaskCardLatestActivity(data.showTaskCardLatestActivity);
1836
+ }
1837
+ else {
1838
+ setShowTaskCardLatestActivity(true);
1839
+ }
1840
+ if (typeof data.tintTaskCardActivityBackground === 'boolean') {
1841
+ setTintTaskCardActivityBackground(data.tintTaskCardActivityBackground);
1842
+ }
1843
+ else {
1844
+ setTintTaskCardActivityBackground(false);
1845
+ }
1731
1846
  }, [applyResolvedWorkspaceId, commitCurrentWorkspaceId, configLoaded, currentWorkspaceIdRef]);
1732
1847
  const fetchBuildInfo = useCallback(async () => {
1733
1848
  const startedAt = typeof performance !== 'undefined' ? performance.now() : Date.now();
@@ -2804,6 +2919,24 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
2804
2919
  setInitiatives((current) => upsertEntityById(current, data));
2805
2920
  return data;
2806
2921
  }, [fetchPlanningEntities, runInitiativeMutation]);
2922
+ const updatePlanningIdentity = useCallback(async (entityType, id, patch) => {
2923
+ const res = await runInitiativeMutation(`/api/taskforce/${entityType}/${encodeURIComponent(id)}/identity`, {
2924
+ method: 'PATCH',
2925
+ headers: { 'Content-Type': 'application/json' },
2926
+ body: JSON.stringify(patch),
2927
+ });
2928
+ const data = await res.json().catch(() => ({}));
2929
+ if (!res.ok)
2930
+ throw new Error(data?.error || `Failed to update ${entityType} identity (${res.status})`);
2931
+ if (entityType === 'initiative') {
2932
+ setInitiatives((current) => upsertEntityById(current, data));
2933
+ }
2934
+ else {
2935
+ setWorkstreams((current) => upsertEntityById(current, data));
2936
+ }
2937
+ void fetchPlanningEntities();
2938
+ return data;
2939
+ }, [fetchPlanningEntities, runInitiativeMutation]);
2807
2940
  const refreshPlanningEntitiesInBackground = useCallback(() => {
2808
2941
  void fetchPlanningEntities();
2809
2942
  }, [fetchPlanningEntities]);
@@ -3244,13 +3377,8 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
3244
3377
  coordinatorDataVersion: localCoordinatorDataVersion,
3245
3378
  });
3246
3379
  const relationshipTasks = useMemo(() => {
3247
- const byId = new Map();
3248
- for (const task of archivedTasks)
3249
- byId.set(task.id, task);
3250
- for (const task of tasks)
3251
- byId.set(task.id, task);
3252
- return Array.from(byId.values());
3253
- }, [tasks, archivedTasks]);
3380
+ return buildRelationshipTasks(tasks, archivedTasks, taskDetails, editingTaskId);
3381
+ }, [tasks, archivedTasks, taskDetails, editingTaskId]);
3254
3382
  const deletedRelationshipTasks = useMemo(() => deletedTasks.map((entry) => ({
3255
3383
  ...entry.taskSnapshot,
3256
3384
  isDeleted: true,
@@ -3406,13 +3534,25 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
3406
3534
  setActiveTab__internal(tab);
3407
3535
  }, [activeTab]);
3408
3536
  const flushAutoSaveRef = useRef(async () => true);
3409
- const { handleNavigation, handleClose, resetForm, resolveTaskIdInput, resolveWorkstreamIdInput, handleEdit, handleOpenTaskById, returnToPreviousTask, clearReturnToParentTask } = useTaskEditorNavigation({
3537
+ const adoptTaskEditorBaseline = useCallback((task) => {
3538
+ const baseline = {
3539
+ taskId: task.id,
3540
+ task,
3541
+ draft: taskToEditorDraft(task),
3542
+ };
3543
+ editorBaselineRef.current = baseline;
3544
+ setEditorBaseline(baseline);
3545
+ editingTaskRevisionConflictRef.current = null;
3546
+ setEditingTaskRevisionConflict(null);
3547
+ }, []);
3548
+ const { handleNavigation, handleClose, resetForm, resolveTaskIdInput, resolveWorkstreamIdInput, handleEdit, applyTaskToEditor, handleOpenTaskById, returnToPreviousTask, clearReturnToParentTask } = useTaskEditorNavigation({
3410
3549
  activeCategories,
3411
3550
  activeTypes,
3412
3551
  activeTab,
3413
3552
  attachments,
3414
3553
  checklistItems,
3415
3554
  comments,
3555
+ cancelTaskDetailLoad,
3416
3556
  description,
3417
3557
  editingTaskId,
3418
3558
  flushPendingAutoSave: () => flushAutoSaveRef.current(),
@@ -3420,7 +3560,9 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
3420
3560
  getPreferredCategoryValue,
3421
3561
  getTitleDraft,
3422
3562
  lastUsedCategory,
3563
+ loadTaskDetail,
3423
3564
  newCommentText,
3565
+ onTaskApplied: adoptTaskEditorBaseline,
3424
3566
  relationshipTasks,
3425
3567
  workstreams,
3426
3568
  showArchive,
@@ -3453,6 +3595,43 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
3453
3595
  taskReturnTrail,
3454
3596
  title,
3455
3597
  });
3598
+ const readCurrentTaskEditorDraft = useCallback(() => {
3599
+ const resolvedWorkstream = workstreamInput.trim()
3600
+ ? resolveWorkstreamIdInput(workstreamInput)
3601
+ : null;
3602
+ return {
3603
+ title: getTitleDraft(),
3604
+ description: getDescriptionDraft(),
3605
+ category: typeof category === 'string' ? category : String(category.label || ''),
3606
+ type: typeof type === 'string' ? type : String(type.label || ''),
3607
+ priority,
3608
+ complexity: Number(complexity) || 3,
3609
+ status,
3610
+ assignee,
3611
+ scheduledDate,
3612
+ dueDate,
3613
+ workstreamId: resolvedWorkstream?.id || workstreamInput.trim(),
3614
+ taxonomies: { ...formTaxonomies },
3615
+ checklistItems: [...checklistItems],
3616
+ attachments: getAttachmentsDraft(),
3617
+ };
3618
+ }, [
3619
+ assignee,
3620
+ category,
3621
+ checklistItems,
3622
+ complexity,
3623
+ dueDate,
3624
+ formTaxonomies,
3625
+ getAttachmentsDraft,
3626
+ getDescriptionDraft,
3627
+ getTitleDraft,
3628
+ priority,
3629
+ resolveWorkstreamIdInput,
3630
+ scheduledDate,
3631
+ status,
3632
+ type,
3633
+ workstreamInput,
3634
+ ]);
3456
3635
  useEffect(() => {
3457
3636
  const normalizedTaskId = String(pendingOpenTaskId || '').trim();
3458
3637
  if (!uiStateReady || !normalizedTaskId)
@@ -3748,10 +3927,45 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
3748
3927
  isAuthenticated,
3749
3928
  dispatchEnabled: workspaceCloudSyncEnabled,
3750
3929
  });
3930
+ const handleTaskRevisionConflict = useCallback(async (taskId, _currentDetailRevision) => {
3931
+ if (taskId !== editingTaskId)
3932
+ return { handled: false };
3933
+ const task = [...tasks, ...archivedTasks].find((candidate) => candidate.id === taskId);
3934
+ if (!task)
3935
+ return { handled: false };
3936
+ const detail = await loadTaskDetail(task, {
3937
+ force: true,
3938
+ shouldCommit: () => editorBaselineRef.current?.taskId === taskId,
3939
+ });
3940
+ if (!detail || editorBaselineRef.current?.taskId !== taskId)
3941
+ return { handled: false };
3942
+ const reconciliation = reconcileOpenTaskWithRemoteRef.current(detail, 'save');
3943
+ return {
3944
+ handled: true,
3945
+ retryDetailRevision: reconciliation?.conflicts.length === 0
3946
+ ? detail.detailRevision
3947
+ : undefined,
3948
+ retryPatch: reconciliation?.conflicts.length === 0
3949
+ ? applyEditorDraftToTask(detail, reconciliation.merged)
3950
+ : undefined,
3951
+ };
3952
+ }, [archivedTasks, editingTaskId, loadTaskDetail, tasks]);
3953
+ const handleTaskMutationAccepted = useCallback((task) => {
3954
+ if (task.id !== editingTaskId)
3955
+ return;
3956
+ if (editingTaskRevisionConflictRef.current?.taskId === task.id) {
3957
+ reconcileOpenTaskWithRemoteRef.current(task, 'refresh');
3958
+ return;
3959
+ }
3960
+ adoptTaskEditorBaseline(task);
3961
+ }, [adoptTaskEditorBaseline, editingTaskId]);
3751
3962
  const { copiedId, handleDelete, handleUpdateTask, handleSetStatus, handleToggleComplete, handleToggleCancel, handleToggleInProgress, handleToggleReview, handleArchiveTask, handleBulkArchive, handleUnarchive, handleRestoreDeletedTask, handleRestoreSelectedDeletedTasks, handlePermanentlyDeleteDeletedTask, handleEmptyDeletedTasks, handleCopyId, queueWorkspaceSyncFromAuthoritativeTaskState, } = useTaskActions({
3752
3963
  tasks,
3753
3964
  archivedTasks,
3754
3965
  editingTaskId,
3966
+ editingTaskDetailRevision: editorBaseline?.taskId === editingTaskId
3967
+ ? editorBaseline.task.detailRevision || null
3968
+ : null,
3755
3969
  setTasks,
3756
3970
  setArchivedTasks,
3757
3971
  setDeletedTasks,
@@ -3783,8 +3997,19 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
3783
3997
  durableTaskDeleteActivationEnabled: taskDeleteActivationEnabled,
3784
3998
  durableTaskHttpRootActivationEnabled: runtimeConfigOverride.syncV3TaskCloudHttpRootActivation,
3785
3999
  workspaceId: currentWorkspaceId,
4000
+ onTaskRevisionConflict: handleTaskRevisionConflict,
4001
+ onTaskMutationAccepted: handleTaskMutationAccepted,
3786
4002
  });
3787
- const { autoSaveState, flushAutoSave, scheduleWarningPrompt, handleSubmit, confirmScheduleWarning, cancelScheduleWarning, handleAddComment } = useTaskFormActions({
4003
+ const { resolveDraft: resolveDescriptionImageDraft } = useTaskDescriptionImageDraftRecovery(currentWorkspaceId, authUserId);
4004
+ const promoteDescriptionImageDraft = useCallback(async () => {
4005
+ const draftId = descriptionImageDraftIdRef.current;
4006
+ rotateDescriptionImageDraftId();
4007
+ await resolveDescriptionImageDraft({
4008
+ draftUploadId: draftId,
4009
+ resolution: 'promote',
4010
+ });
4011
+ }, [resolveDescriptionImageDraft, rotateDescriptionImageDraftId]);
4012
+ const { autoSaveState, hasUnsavedChanges, flushAutoSave, scheduleWarningPrompt, handleSubmit, confirmScheduleWarning, cancelScheduleWarning, handleAddComment } = useTaskFormActions({
3788
4013
  activeCategories,
3789
4014
  activeTab,
3790
4015
  apiEndpoint,
@@ -3802,11 +4027,16 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
3802
4027
  workspaceId: currentWorkspaceId,
3803
4028
  updateTask: handleUpdateTask,
3804
4029
  editingTaskId,
4030
+ editorBaselineDraft: editorBaseline?.taskId === editingTaskId ? editorBaseline.draft : null,
4031
+ revisionConflict: editingTaskRevisionConflict?.taskId === editingTaskId,
3805
4032
  fetchTasks,
3806
4033
  formTaxonomies,
4034
+ getAttachmentsDraft,
3807
4035
  getDescriptionDraft,
3808
4036
  getPreferredCategoryValue,
3809
4037
  getTitleDraft,
4038
+ awaitPendingDescriptionImageUpload,
4039
+ onTaskCreateAccepted: promoteDescriptionImageDraft,
3810
4040
  mergeTaskFromServer,
3811
4041
  onTaskCreated: handleEdit,
3812
4042
  workstreamInput,
@@ -3831,6 +4061,166 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
3831
4061
  textDraftOccupied,
3832
4062
  type
3833
4063
  });
4064
+ const reconcileOpenTaskWithRemote = useCallback((remoteTask, source) => {
4065
+ if (!editingTaskId || remoteTask.id !== editingTaskId)
4066
+ return null;
4067
+ const previousBaseline = editorBaselineRef.current?.taskId === editingTaskId
4068
+ ? editorBaselineRef.current
4069
+ : { taskId: editingTaskId, task: remoteTask, draft: taskToEditorDraft(remoteTask) };
4070
+ const localDraft = readCurrentTaskEditorDraft();
4071
+ const remoteDraft = taskToEditorDraft(remoteTask);
4072
+ const nextReconciliation = reconcileTaskEditorDraft(previousBaseline.draft, localDraft, remoteDraft);
4073
+ const unresolvedConflicts = editingTaskRevisionConflictRef.current?.taskId === editingTaskId
4074
+ ? editingTaskRevisionConflictRef.current.reconciliation.conflicts
4075
+ : [];
4076
+ const reconciliation = {
4077
+ ...nextReconciliation,
4078
+ conflicts: preserveUnresolvedTaskEditorConflicts(unresolvedConflicts, nextReconciliation.conflicts, localDraft, remoteDraft),
4079
+ };
4080
+ const mergedTask = applyEditorDraftToTask(remoteTask, reconciliation.merged);
4081
+ const nextBaseline = { taskId: editingTaskId, task: remoteTask, draft: remoteDraft };
4082
+ editorBaselineRef.current = nextBaseline;
4083
+ setEditorBaseline(nextBaseline);
4084
+ applyTaskToEditor(mergedTask, { preserveReturnTrail: true, adoptAsBaseline: false });
4085
+ setAttachmentsDirty(JSON.stringify(reconciliation.merged.attachments) !== JSON.stringify(remoteDraft.attachments));
4086
+ setError('');
4087
+ if (reconciliation.conflicts.length > 0) {
4088
+ const nextConflict = {
4089
+ taskId: editingTaskId,
4090
+ detailRevision: remoteTask.detailRevision || 'unknown',
4091
+ source,
4092
+ reconciliation,
4093
+ remoteTask,
4094
+ remoteDraft,
4095
+ };
4096
+ editingTaskRevisionConflictRef.current = nextConflict;
4097
+ setEditingTaskRevisionConflict(nextConflict);
4098
+ }
4099
+ else {
4100
+ editingTaskRevisionConflictRef.current = null;
4101
+ setEditingTaskRevisionConflict(null);
4102
+ if (reconciliation.remoteChangedFields.length > 0) {
4103
+ pushNotice('Task updated', 'info', 2200);
4104
+ }
4105
+ }
4106
+ return reconciliation;
4107
+ }, [
4108
+ applyTaskToEditor,
4109
+ editingTaskId,
4110
+ pushNotice,
4111
+ readCurrentTaskEditorDraft,
4112
+ setAttachmentsDirty,
4113
+ setError,
4114
+ ]);
4115
+ reconcileOpenTaskWithRemoteRef.current = reconcileOpenTaskWithRemote;
4116
+ const resolveEditingTaskConflict = useCallback((resolution) => {
4117
+ const conflict = editingTaskRevisionConflict;
4118
+ if (!conflict || conflict.taskId !== editingTaskId)
4119
+ return;
4120
+ const resolvedDraft = resolveTaskEditorConflicts(conflict.reconciliation, conflict.remoteDraft, resolution, readCurrentTaskEditorDraft());
4121
+ const resolvedTask = applyEditorDraftToTask(conflict.remoteTask, resolvedDraft);
4122
+ applyTaskToEditor(resolvedTask, { preserveReturnTrail: true, adoptAsBaseline: false });
4123
+ setAttachmentsDirty(JSON.stringify(resolvedDraft.attachments) !== JSON.stringify(conflict.remoteDraft.attachments));
4124
+ editingTaskRevisionConflictRef.current = null;
4125
+ setEditingTaskRevisionConflict(null);
4126
+ setError('');
4127
+ clearNotice();
4128
+ const statusWasConflicted = conflict.reconciliation.conflicts.some((item) => item.field === 'status');
4129
+ if (resolution === 'local'
4130
+ && statusWasConflicted
4131
+ && resolvedDraft.status !== conflict.remoteDraft.status) {
4132
+ void handleSetStatus(conflict.remoteTask, resolvedDraft.status);
4133
+ }
4134
+ }, [
4135
+ applyTaskToEditor,
4136
+ clearNotice,
4137
+ editingTaskId,
4138
+ editingTaskRevisionConflict,
4139
+ handleSetStatus,
4140
+ readCurrentTaskEditorDraft,
4141
+ setAttachmentsDirty,
4142
+ setError,
4143
+ ]);
4144
+ useEffect(() => {
4145
+ const conflict = editingTaskRevisionConflict;
4146
+ if (!conflict || conflict.taskId !== editingTaskId)
4147
+ return;
4148
+ const fields = formatTaskEditorConflictFields(conflict.reconciliation.conflicts);
4149
+ const fieldSummary = fields.length > 0 ? fields.join(', ') : 'task fields';
4150
+ pushNotice(`${fieldSummary.charAt(0).toUpperCase()}${fieldSummary.slice(1)} also changed elsewhere.`, 'info', undefined, {
4151
+ label: 'Use latest',
4152
+ primary: true,
4153
+ onAction: () => resolveEditingTaskConflict('latest'),
4154
+ secondaryLabel: 'Keep mine',
4155
+ onSecondaryAction: () => resolveEditingTaskConflict('local'),
4156
+ dismissible: false,
4157
+ ownerKey: `task-editor-conflict:${conflict.taskId}:${conflict.detailRevision}`,
4158
+ });
4159
+ }, [editingTaskId, editingTaskRevisionConflict, pushNotice, resolveEditingTaskConflict]);
4160
+ useEffect(() => {
4161
+ if (!editingTaskId) {
4162
+ refreshingTaskRevisionRef.current = null;
4163
+ setEditingTaskRevisionConflict(null);
4164
+ editingTaskRevisionConflictRef.current = null;
4165
+ editorBaselineRef.current = null;
4166
+ setEditorBaseline(null);
4167
+ return;
4168
+ }
4169
+ const staleRevision = staleTaskDetailRevisions[editingTaskId];
4170
+ if (!staleRevision) {
4171
+ refreshingTaskRevisionRef.current = null;
4172
+ return;
4173
+ }
4174
+ const summary = [...tasks, ...archivedTasks].find((task) => task.id === editingTaskId);
4175
+ if (!summary)
4176
+ return;
4177
+ const refreshKey = `${editingTaskId}:${staleRevision}`;
4178
+ if (refreshingTaskRevisionRef.current === refreshKey)
4179
+ return;
4180
+ refreshingTaskRevisionRef.current = refreshKey;
4181
+ void loadTaskDetail(summary, {
4182
+ shouldCommit: () => editorBaselineRef.current?.taskId === editingTaskId,
4183
+ }).then((detail) => {
4184
+ if (editorBaselineRef.current?.taskId !== editingTaskId)
4185
+ return;
4186
+ if (!detail) {
4187
+ setError('The latest task update could not be loaded. Your local draft has been preserved.');
4188
+ return;
4189
+ }
4190
+ reconcileOpenTaskWithRemote(detail, 'refresh');
4191
+ }).finally(() => {
4192
+ if (refreshingTaskRevisionRef.current === refreshKey) {
4193
+ refreshingTaskRevisionRef.current = null;
4194
+ }
4195
+ });
4196
+ }, [
4197
+ archivedTasks,
4198
+ editingTaskId,
4199
+ loadTaskDetail,
4200
+ reconcileOpenTaskWithRemote,
4201
+ setError,
4202
+ staleTaskDetailRevisions,
4203
+ tasks,
4204
+ ]);
4205
+ const discardDescriptionImageDraft = useCallback(async () => {
4206
+ const draftId = descriptionImageDraftIdRef.current;
4207
+ rotateDescriptionImageDraftId();
4208
+ try {
4209
+ await awaitPendingDescriptionImageUpload();
4210
+ }
4211
+ catch (error) {
4212
+ console.warn('[Taskforce] Description image upload failed while the draft was being discarded.', error);
4213
+ }
4214
+ try {
4215
+ await resolveDescriptionImageDraft({
4216
+ draftUploadId: draftId,
4217
+ resolution: 'discard',
4218
+ });
4219
+ }
4220
+ catch (error) {
4221
+ console.warn('[Taskforce] Failed to clean discarded Description image uploads.', error);
4222
+ }
4223
+ }, [awaitPendingDescriptionImageUpload, resolveDescriptionImageDraft, rotateDescriptionImageDraftId]);
3834
4224
  useEffect(() => {
3835
4225
  flushAutoSaveRef.current = flushAutoSave;
3836
4226
  }, [flushAutoSave]);
@@ -3877,6 +4267,11 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
3877
4267
  manualComplexityEnabled,
3878
4268
  checklistDropdownEnabled,
3879
4269
  showTaskCardStatusLabel,
4270
+ showTaskCardDescription,
4271
+ showTaskCardAttachments,
4272
+ showTaskCardChecklistProgress,
4273
+ showTaskCardLatestActivity,
4274
+ tintTaskCardActivityBackground,
3880
4275
  pathSaved,
3881
4276
  settingsSection,
3882
4277
  setupState,
@@ -3886,15 +4281,21 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
3886
4281
  setCurrentTheme,
3887
4282
  handleSaveTheme,
3888
4283
  handleSaveGlobalTheme,
4284
+ handleUseGlobalThemeDefault,
3889
4285
  setKeyShortcut,
3890
4286
  handleJsonBackupEnabledChange,
3891
4287
  handleSaveGlobalJsonBackupEnabled,
4288
+ handleUseGlobalJsonBackupDefault,
3892
4289
  handleSaveGlobalWeekStartsOn,
3893
4290
  handleSaveLocale,
3894
4291
  handleManualComplexityEnabledChange,
3895
4292
  handleChecklistDropdownEnabledChange,
3896
4293
  handleShowTaskCardStatusLabelChange,
3897
- handleResetProjectToGlobal,
4294
+ handleShowTaskCardDescriptionChange,
4295
+ handleShowTaskCardAttachmentsChange,
4296
+ handleShowTaskCardChecklistProgressChange,
4297
+ handleShowTaskCardLatestActivityChange,
4298
+ handleTintTaskCardActivityBackgroundChange,
3898
4299
  handleSaveSettings,
3899
4300
  initiativeTemplates,
3900
4301
  fetchInitiativeTemplates,
@@ -3994,6 +4395,7 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
3994
4395
  const effectiveConfig = {
3995
4396
  ...mergedConfig,
3996
4397
  cloudEnvironment: runtimeConfigOverride.cloudEnvironment || mergedConfig.cloudEnvironment || '',
4398
+ appGates: runtimeConfigOverride.appGates || mergedConfig.appGates,
3997
4399
  apiBaseUrl: normalizedApiBaseUrl || mergedConfig.apiBaseUrl,
3998
4400
  cloudAuthBaseUrl: normalizedCloudAuthBaseUrl || mergedConfig.cloudAuthBaseUrl,
3999
4401
  wsBaseUrl: effectiveWsBaseUrl || mergedConfig.wsBaseUrl
@@ -4024,6 +4426,11 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
4024
4426
  manualComplexityEnabled,
4025
4427
  checklistDropdownEnabled,
4026
4428
  showTaskCardStatusLabel,
4429
+ showTaskCardDescription,
4430
+ showTaskCardAttachments,
4431
+ showTaskCardChecklistProgress,
4432
+ showTaskCardLatestActivity,
4433
+ tintTaskCardActivityBackground,
4027
4434
  setManualComplexityEnabled,
4028
4435
  mcpHostRoot,
4029
4436
  setMcpHostRoot,
@@ -4181,6 +4588,7 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
4181
4588
  fetchAssigneeOptions,
4182
4589
  createInitiative,
4183
4590
  updateInitiative,
4591
+ updatePlanningIdentity,
4184
4592
  archiveInitiative,
4185
4593
  unarchiveInitiative,
4186
4594
  createWorkstream,
@@ -4244,6 +4652,9 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
4244
4652
  setAttachments,
4245
4653
  attachmentsDirty,
4246
4654
  setAttachmentsDirty,
4655
+ descriptionImageUploadPending,
4656
+ descriptionImageDraftId,
4657
+ registerDescriptionImageUpload,
4247
4658
  descriptionFocused,
4248
4659
  setDescriptionFocused,
4249
4660
  showMarkdownHelp,
@@ -4253,6 +4664,7 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
4253
4664
  // Form Actions
4254
4665
  handleSubmit,
4255
4666
  resetForm,
4667
+ discardDescriptionImageDraft,
4256
4668
  handleAddComment,
4257
4669
  handleSetWorkstreamForCurrentTask,
4258
4670
  handleOpenTaskById,
@@ -14,6 +14,10 @@ export declare function useUiNotice(): {
14
14
  pushNotice: (message: string, tone?: UiNotice["tone"], ttlMs?: number, action?: {
15
15
  label: string;
16
16
  onAction: () => void;
17
+ primary?: boolean;
18
+ secondaryLabel?: string;
19
+ onSecondaryAction?: () => void;
20
+ dismissible?: boolean;
17
21
  ownerKey?: string;
18
22
  }) => void;
19
23
  clearNotice: () => void;