@taskforcehq/taskforce 0.3.328 → 0.3.330

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (485) hide show
  1. package/dist/Taskforce.module.css +523 -79
  2. package/dist/TaskforceCore.js +237 -230
  3. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
  4. package/dist/cli.js +34 -0
  5. package/dist/cliCloudTargetGuard.d.ts +5 -0
  6. package/dist/cliCloudTargetGuard.js +11 -0
  7. package/dist/components/features/AiProfilesModule.js +3 -5
  8. package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
  9. package/dist/components/features/TaskSettings.d.ts +12 -1
  10. package/dist/components/features/TaskSettings.js +217 -54
  11. package/dist/components/features/TaskforceAgentsModule.d.ts +1 -2
  12. package/dist/components/features/TaskforceAgentsModule.js +586 -116
  13. package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
  14. package/dist/components/features/agentConnections/AgentConnectionControl.d.ts +15 -0
  15. package/dist/components/features/agentConnections/AgentConnectionControl.js +125 -0
  16. package/dist/components/features/agentConnections/ModelConnectionsPanel.d.ts +18 -0
  17. package/dist/components/features/agentConnections/ModelConnectionsPanel.js +393 -0
  18. package/dist/components/features/agentConnections/modelConnectionsApi.d.ts +65 -0
  19. package/dist/components/features/agentConnections/modelConnectionsApi.js +129 -0
  20. package/dist/components/features/planning/PlanningModule.js +2 -5
  21. package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
  22. package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
  23. package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
  24. package/dist/components/features/planning/planningTaskArrangement.js +5 -5
  25. package/dist/components/features/taskforceAgentAssignments/AgentBehaviorAssignments.js +15 -24
  26. package/dist/components/features/taskforceAgentEditorModel.d.ts +2 -1
  27. package/dist/components/features/taskforceAgentEditorModel.js +5 -1
  28. package/dist/components/features/workflowManager/workflowManagerApi.d.ts +1 -1
  29. package/dist/components/features/workflowManager/workflowManagerApi.js +3 -0
  30. package/dist/components/task/TaskCard.d.ts +5 -0
  31. package/dist/components/task/TaskCard.js +65 -10
  32. package/dist/components/task/TaskImageReviews.js +14 -5
  33. package/dist/components/task/TaskKanban.d.ts +6 -1
  34. package/dist/components/task/TaskKanban.js +152 -6
  35. package/dist/components/task/TaskList.d.ts +5 -0
  36. package/dist/components/task/TaskList.js +3 -3
  37. package/dist/components/task/TaskWorkflowAssignmentField.js +68 -10
  38. package/dist/components/ui/PasswordInput.d.ts +6 -0
  39. package/dist/components/ui/PasswordInput.js +11 -0
  40. package/dist/components/ui/TopNoticeLayer.js +1 -1
  41. package/dist/components/views/AppShellHeader.js +32 -11
  42. package/dist/components/views/PlanComparisonPage.js +12 -0
  43. package/dist/components/views/StandaloneLayout.js +32 -55
  44. package/dist/components/views/WidgetView.js +3 -3
  45. package/dist/components/views/panels/PlanningDrawer.js +5 -12
  46. package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
  47. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +4 -3
  48. package/dist/components/views/standalone/modals/SyncStatusModal.js +33 -38
  49. package/dist/config/envSchema.js +60 -1
  50. package/dist/config/localServiceRuntimeContract.d.ts +13 -0
  51. package/dist/config/localServiceRuntimeContract.js +135 -0
  52. package/dist/core/AiProfileService.js +46 -8
  53. package/dist/core/DeletedTaskLifecycleService.d.ts +1 -0
  54. package/dist/core/DeletedTaskLifecycleService.js +37 -6
  55. package/dist/core/McpTokenService.d.ts +23 -1
  56. package/dist/core/McpTokenService.js +93 -10
  57. package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +3 -2
  58. package/dist/core/TaskAttachmentLinksDurableMutationService.js +33 -9
  59. package/dist/core/TaskChecklistCommandService.d.ts +27 -0
  60. package/dist/core/TaskChecklistCommandService.js +83 -5
  61. package/dist/core/TaskLifecycleCommandService.d.ts +3 -1
  62. package/dist/core/TaskLifecycleCommandService.js +6 -2
  63. package/dist/core/Taskforce.d.ts +94 -2
  64. package/dist/core/Taskforce.js +760 -36
  65. package/dist/core/types.d.ts +14 -0
  66. package/dist/documentReviews/commandService.d.ts +2 -1
  67. package/dist/documentReviews/commandService.js +6 -3
  68. package/dist/hooks/sync/orchestratorShared.d.ts +1 -0
  69. package/dist/hooks/sync/orchestratorShared.js +2 -0
  70. package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
  71. package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
  72. package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
  73. package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
  74. package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
  75. package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.d.ts +3 -0
  76. package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.js +85 -9
  77. package/dist/hooks/sync/useSyncStatusControls.d.ts +4 -1
  78. package/dist/hooks/sync/useSyncStatusControls.js +47 -11
  79. package/dist/hooks/tasks/taskHttpMutation.js +1 -0
  80. package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
  81. package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
  82. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
  83. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
  84. package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
  85. package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
  86. package/dist/hooks/tasks/useTaskFormActions.d.ts +6 -0
  87. package/dist/hooks/tasks/useTaskFormActions.js +65 -12
  88. package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
  89. package/dist/hooks/ui/useSettingsModel.js +13 -2
  90. package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
  91. package/dist/hooks/ui/useSettingsPersistence.js +74 -47
  92. package/dist/hooks/useFilterSort.d.ts +7 -3
  93. package/dist/hooks/useFilterSort.js +15 -5
  94. package/dist/hooks/useSyncOrchestrator.d.ts +3 -0
  95. package/dist/hooks/useSyncOrchestrator.js +111 -2
  96. package/dist/hooks/useTaskData.d.ts +40 -1
  97. package/dist/hooks/useTaskData.js +240 -9
  98. package/dist/hooks/useTaskMutations.d.ts +12 -2
  99. package/dist/hooks/useTaskMutations.js +266 -52
  100. package/dist/hooks/useTaskforce.d.ts +39 -9
  101. package/dist/hooks/useTaskforce.js +359 -40
  102. package/dist/hooks/useUiNotice.d.ts +4 -0
  103. package/dist/hooks/useUiNotice.js +4 -0
  104. package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
  105. package/dist/mcp/clientRegistry.d.ts +2 -2
  106. package/dist/mcp/clientRegistry.js +1 -1
  107. package/dist/mcp/documentAssetRegistrar.js +53 -41
  108. package/dist/mcp/documentHelpers.d.ts +1 -0
  109. package/dist/mcp/documentHelpers.js +7 -3
  110. package/dist/mcp/durableTaskMutationRouter.d.ts +4 -1
  111. package/dist/mcp/durableTaskMutationRouter.js +10 -0
  112. package/dist/mcp/durableTaskRelationshipMutationRouter.js +4 -0
  113. package/dist/mcp/httpProtocolRouting.d.ts +10 -0
  114. package/dist/mcp/httpProtocolRouting.js +19 -0
  115. package/dist/mcp/localCliHealth.d.ts +2 -2
  116. package/dist/mcp/localCliHealth.js +2 -2
  117. package/dist/mcp/localServiceProxy.d.ts +1 -0
  118. package/dist/mcp/localServiceProxy.js +530 -68
  119. package/dist/mcp/planningAttachmentCommandAdapter.d.ts +3 -1
  120. package/dist/mcp/planningAttachmentCommandAdapter.js +20 -2
  121. package/dist/mcp/runtime.d.ts +54 -79
  122. package/dist/mcp/runtime.js +556 -139
  123. package/dist/mcp/taskPlanningRegistrar.js +64 -42
  124. package/dist/mcp/toolCallCompatibility.js +38 -1
  125. package/dist/mcp/toolCatalog.d.ts +1 -0
  126. package/dist/mcp/toolProfiles.d.ts +2 -0
  127. package/dist/mcp/toolProfiles.js +10 -0
  128. package/dist/mcp/toolRegistry.d.ts +1 -0
  129. package/dist/mcp/toolRegistry.js +1 -0
  130. package/dist/mcp/workflowExecutionRegistrar.js +4 -4
  131. package/dist/migrations/taskSchemaMigrations.d.ts +5 -0
  132. package/dist/migrations/taskSchemaMigrations.js +427 -0
  133. package/dist/runtime/appGateDefinitions.d.ts +30 -6
  134. package/dist/runtime/appGateDefinitions.js +6 -6
  135. package/dist/runtime/appGates.d.ts +13 -13
  136. package/dist/runtime/appGates.js +36 -13
  137. package/dist/runtime/nodeAppGates.d.ts +8 -0
  138. package/dist/runtime/nodeAppGates.js +27 -0
  139. package/dist/server/cloudCollectionRead.d.ts +1 -1
  140. package/dist/server/cloudCollectionRead.js +2 -2
  141. package/dist/server/index.d.ts +6 -0
  142. package/dist/server/index.js +123 -14
  143. package/dist/server/localDatabaseIdentity.js +4 -1
  144. package/dist/server/localServiceLease.d.ts +3 -0
  145. package/dist/server/localServiceLease.js +11 -2
  146. package/dist/server/localServiceSessions.d.ts +14 -17
  147. package/dist/server/localServiceSessions.js +308 -94
  148. package/dist/server/localWorkspaceSyncServerRuntime.js +12 -7
  149. package/dist/server/rateLimit.d.ts +1 -0
  150. package/dist/server/rateLimit.js +4 -0
  151. package/dist/server/realtimeSyncWs.js +36 -12
  152. package/dist/server/routes/admin.d.ts +4 -0
  153. package/dist/server/routes/admin.js +113 -3
  154. package/dist/server/routes/agentRoles.js +3 -2
  155. package/dist/server/routes/agentSkills.js +3 -2
  156. package/dist/server/routes/agents.d.ts +7 -0
  157. package/dist/server/routes/agents.js +394 -39
  158. package/dist/server/routes/annotatedAttachments.js +3 -2
  159. package/dist/server/routes/auth.js +3 -1
  160. package/dist/server/routes/billing.js +5 -1
  161. package/dist/server/routes/durableTaskHttpRouters.d.ts +11 -2
  162. package/dist/server/routes/executorPhaseAApprovals.d.ts +19 -0
  163. package/dist/server/routes/executorPhaseAApprovals.js +140 -0
  164. package/dist/server/routes/executorPhaseAIssuerRedemptions.d.ts +11 -0
  165. package/dist/server/routes/executorPhaseAIssuerRedemptions.js +24 -0
  166. package/dist/server/routes/githubReviewEvidence.d.ts +19 -0
  167. package/dist/server/routes/githubReviewEvidence.js +116 -0
  168. package/dist/server/routes/localService.d.ts +15 -4
  169. package/dist/server/routes/localService.js +138 -40
  170. package/dist/server/routes/modelConnections.d.ts +24 -0
  171. package/dist/server/routes/modelConnections.js +205 -0
  172. package/dist/server/routes/primitives.d.ts +2 -0
  173. package/dist/server/routes/shared.d.ts +19 -0
  174. package/dist/server/routes/shared.js +95 -19
  175. package/dist/server/routes/sync.js +1 -0
  176. package/dist/server/routes/syncAuxRoutes.js +9 -2
  177. package/dist/server/routes/syncPullApplyRoutes.js +23 -4
  178. package/dist/server/routes/syncPushRoutes.d.ts +1 -0
  179. package/dist/server/routes/syncPushRoutes.js +1 -0
  180. package/dist/server/routes/syncV3FeedRoutes.js +27 -16
  181. package/dist/server/routes/syncV3LocalCaptureRoutes.js +28 -2
  182. package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
  183. package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
  184. package/dist/server/routes/syncV3OperationRoutes.js +45 -9
  185. package/dist/server/routes/tasks.js +124 -13
  186. package/dist/server/routes/workflows.js +9 -1
  187. package/dist/server/routes/workspaces.js +43 -1
  188. package/dist/server/routes.js +59 -0
  189. package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
  190. package/dist/server/workspaceDeletionAdmission.js +50 -0
  191. package/dist/service/localServiceCli.js +16 -0
  192. package/dist/service/localServiceClientLifecycle.js +36 -10
  193. package/dist/services/codexAppServerModelGateway.d.ts +161 -0
  194. package/dist/services/codexAppServerModelGateway.js +663 -0
  195. package/dist/services/codexDeviceCodeLoginManager.d.ts +39 -0
  196. package/dist/services/codexDeviceCodeLoginManager.js +265 -0
  197. package/dist/services/codexModelProviderConnectionLifecycle.d.ts +8 -0
  198. package/dist/services/codexModelProviderConnectionLifecycle.js +73 -0
  199. package/dist/services/executorPhaseAApprovalRuntime.d.ts +14 -0
  200. package/dist/services/executorPhaseAApprovalRuntime.js +24 -0
  201. package/dist/services/executorPhaseAApprovalService.d.ts +40 -0
  202. package/dist/services/executorPhaseAApprovalService.js +609 -0
  203. package/dist/services/executorPhaseADriftEvaluator.d.ts +78 -0
  204. package/dist/services/executorPhaseADriftEvaluator.js +93 -0
  205. package/dist/services/executorPhaseAIssuerCore.d.ts +126 -0
  206. package/dist/services/executorPhaseAIssuerCore.js +295 -0
  207. package/dist/services/executorPhaseAIssuerRedemptionService.d.ts +34 -0
  208. package/dist/services/executorPhaseAIssuerRedemptionService.js +158 -0
  209. package/dist/services/githubReviewEvidenceRuntime.d.ts +14 -0
  210. package/dist/services/githubReviewEvidenceRuntime.js +30 -0
  211. package/dist/services/githubReviewEvidenceService.d.ts +93 -0
  212. package/dist/services/githubReviewEvidenceService.js +336 -0
  213. package/dist/services/modelGateway.d.ts +7 -0
  214. package/dist/services/modelProviderConnectionService.d.ts +71 -0
  215. package/dist/services/modelProviderConnectionService.js +279 -0
  216. package/dist/services/modelProviderCredentialHome.d.ts +32 -0
  217. package/dist/services/modelProviderCredentialHome.js +271 -0
  218. package/dist/services/ownerScopedModelConnectionGateway.d.ts +12 -0
  219. package/dist/services/ownerScopedModelConnectionGateway.js +30 -0
  220. package/dist/services/taskforceAgentConnectionBindingService.d.ts +66 -0
  221. package/dist/services/taskforceAgentConnectionBindingService.js +185 -0
  222. package/dist/services/taskforceAgentMcpBridge.d.ts +8 -2
  223. package/dist/services/taskforceAgentMcpBridge.js +30 -27
  224. package/dist/shared/adminEdgeProxy.d.ts +5 -0
  225. package/dist/shared/adminEdgeProxy.js +94 -0
  226. package/dist/shared/adminProxySessionCookies.d.ts +16 -0
  227. package/dist/shared/adminProxySessionCookies.js +86 -0
  228. package/dist/shared/aiProfileColors.d.ts +31 -1
  229. package/dist/shared/aiProfileColors.js +14 -6
  230. package/dist/shared/executorPhaseAApprovalGoldenVector.json +269 -0
  231. package/dist/shared/executorPhaseAApprovalReceipt.d.ts +112 -0
  232. package/dist/shared/executorPhaseAApprovalReceipt.js +58 -0
  233. package/dist/shared/executorPhaseAApprovalTrustPolicy.json +10 -0
  234. package/dist/shared/executorPhaseADriftContracts.d.ts +37 -0
  235. package/dist/shared/executorPhaseADriftContracts.js +63 -0
  236. package/dist/shared/executorPhaseAIssuerContracts.d.ts +75 -0
  237. package/dist/shared/executorPhaseAIssuerContracts.js +90 -0
  238. package/dist/shared/executorPhaseARunAuthorization.d.ts +120 -0
  239. package/dist/shared/executorPhaseARunAuthorization.js +232 -0
  240. package/dist/shared/executorPhaseASchemaValidation.d.ts +7 -0
  241. package/dist/shared/executorPhaseASchemaValidation.js +53 -0
  242. package/dist/shared/executorPhaseASchemas/approval-receipt.schema.json +106 -0
  243. package/dist/shared/executorPhaseASchemas/drift-attestation.schema.json +54 -0
  244. package/dist/shared/executorPhaseASchemas/drift-request.schema.json +47 -0
  245. package/dist/shared/executorPhaseASchemas/foundation-manifest.schema.json +29 -0
  246. package/dist/shared/executorPhaseASchemas/issuer-audit-record.schema.json +24 -0
  247. package/dist/shared/executorPhaseASchemas/issuer-proof.schema.json +43 -0
  248. package/dist/shared/executorPhaseASchemas/issuer-redemption-request.schema.json +18 -0
  249. package/dist/shared/executorPhaseASchemas/issuer-redemption-response.schema.json +39 -0
  250. package/dist/shared/executorPhaseASchemas/logical-envelope.schema.json +149 -0
  251. package/dist/shared/executorPhaseASchemas/preflight-report.schema.json +216 -0
  252. package/dist/shared/executorPhaseASchemas/run-capability.schema.json +111 -0
  253. package/dist/shared/executorPhaseASchemas/sender-proof.schema.json +37 -0
  254. package/dist/shared/executorPhaseASchemas/workload-grant.schema.json +68 -0
  255. package/dist/shared/executorPhaseASchemas/workload-jwt-claims.schema.json +67 -0
  256. package/dist/shared/executorPhaseATiming.d.ts +1 -0
  257. package/dist/shared/executorPhaseATiming.js +1 -0
  258. package/dist/shared/planningIdentity.js +1 -1
  259. package/dist/shared/productLogoKeys.d.ts +2 -0
  260. package/dist/shared/productLogoKeys.js +18 -0
  261. package/dist/shared/taskforceAgentDefinition.d.ts +0 -1
  262. package/dist/shared/taskforceAgentDefinition.js +6 -3
  263. package/dist/shared/taskforceAgentModels.d.ts +1 -0
  264. package/dist/shared/taskforceAgentModels.js +36 -3
  265. package/dist/shared/userFeatureGrants.d.ts +4 -0
  266. package/dist/shared/userFeatureGrants.js +7 -0
  267. package/dist/storage/executorPhaseAApprovalReceiptStore.d.ts +37 -0
  268. package/dist/storage/executorPhaseAApprovalReceiptStore.js +81 -0
  269. package/dist/storage/executorPhaseARunAuthorizationStore.d.ts +103 -0
  270. package/dist/storage/executorPhaseARunAuthorizationStore.js +492 -0
  271. package/dist/storage/githubReviewEvidenceInstallationStore.d.ts +26 -0
  272. package/dist/storage/githubReviewEvidenceInstallationStore.js +89 -0
  273. package/dist/storage/modelProviderConnectionStore.d.ts +99 -0
  274. package/dist/storage/modelProviderConnectionStore.js +446 -0
  275. package/dist/storage/postgresAdapter.d.ts +24 -3
  276. package/dist/storage/postgresAdapter.js +117 -14
  277. package/dist/storage/postgresWorker.js +22 -5
  278. package/dist/storage/postgresWorkerProtocol.d.ts +30 -0
  279. package/dist/storage/postgresWorkerProtocol.js +30 -0
  280. package/dist/storage/taskforceAgentConnectionBindingStore.d.ts +31 -0
  281. package/dist/storage/taskforceAgentConnectionBindingStore.js +84 -0
  282. package/dist/sync/cloudSyncApi.d.ts +4 -1
  283. package/dist/sync/cloudSyncApi.js +7 -2
  284. package/dist/sync/contentSyncState.d.ts +1 -1
  285. package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +1 -0
  286. package/dist/sync/coordinator/localSyncExecutionPermitStore.js +67 -30
  287. package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.d.ts +10 -0
  288. package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.js +29 -0
  289. package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
  290. package/dist/sync/coordinator/localWorkspaceSyncRunnerState.d.ts +15 -1
  291. package/dist/sync/coordinator/localWorkspaceSyncRunnerState.js +99 -2
  292. package/dist/sync/coordinator/workspaceSyncCredentialBroker.d.ts +1 -0
  293. package/dist/sync/coordinator/workspaceSyncCredentialBroker.js +33 -4
  294. package/dist/sync/engine/workspaceSyncContentLifecycleAdapter.d.ts +2 -1
  295. package/dist/sync/engine/workspaceSyncContentVersionStore.d.ts +38 -0
  296. package/dist/sync/engine/workspaceSyncContentVersionStore.js +50 -1
  297. package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
  298. package/dist/sync/engine/workspaceSyncEngineLifecyclePolicy.js +6 -6
  299. package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
  300. package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
  301. package/dist/sync/engine/workspaceSyncEnginePushCompletion.d.ts +14 -0
  302. package/dist/sync/engine/workspaceSyncEnginePushCompletion.js +84 -0
  303. package/dist/sync/engine/workspaceSyncEngineRecovery.js +1 -0
  304. package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +11 -0
  305. package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
  306. package/dist/sync/engine/workspaceSyncEngineRuntime.d.ts +1 -0
  307. package/dist/sync/engine/workspaceSyncEngineRuntime.js +1 -0
  308. package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +31 -4
  309. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
  310. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +134 -43
  311. package/dist/sync/engine/workspaceSyncEngineServerSnapshotReader.js +6 -0
  312. package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
  313. package/dist/sync/engine/workspaceSyncEngineTransfers.js +11 -4
  314. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.d.ts +1 -0
  315. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +29 -0
  316. package/dist/sync/syncApplyHandlers.d.ts +2 -0
  317. package/dist/sync/syncApplyHandlers.js +10 -1
  318. package/dist/sync/syncService.d.ts +17 -0
  319. package/dist/sync/syncService.js +87 -19
  320. package/dist/sync/taskforceAgentSyncAuthorization.d.ts +16 -0
  321. package/dist/sync/taskforceAgentSyncAuthorization.js +20 -0
  322. package/dist/sync/v3/combinedFeedCapability.js +8 -0
  323. package/dist/sync/v3/durableInitiativeMutationRouter.js +18 -10
  324. package/dist/sync/v3/durableOperationReplay.d.ts +14 -0
  325. package/dist/sync/v3/durableOperationReplay.js +18 -0
  326. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +2 -0
  327. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +14 -1
  328. package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +4 -1
  329. package/dist/sync/v3/durableTaskChecklistMutationRouter.js +62 -15
  330. package/dist/sync/v3/durableTaskCommentMutationRouter.js +3 -0
  331. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
  332. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +30 -8
  333. package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
  334. package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +37 -2
  335. package/dist/sync/v3/durableTaxonomyMutationRouter.js +5 -0
  336. package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.d.ts +11 -0
  337. package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.js +39 -10
  338. package/dist/sync/v3/durableWorkstreamMutationRouter.js +18 -10
  339. package/dist/sync/v3/durableWorkstreamTaskOrderMutationRouter.js +16 -5
  340. package/dist/sync/v3/localOutboxDispatchRuntime.js +2 -2
  341. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +2 -0
  342. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +47 -7
  343. package/dist/sync/v3/localTaskChecklistOutboxHandler.js +16 -2
  344. package/dist/sync/v3/localTaskChecklistOutboxService.d.ts +4 -0
  345. package/dist/sync/v3/localTaskChecklistOutboxService.js +14 -1
  346. package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
  347. package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
  348. package/dist/sync/v3/localTaskMetadataClient.js +1 -0
  349. package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
  350. package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
  351. package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
  352. package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
  353. package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
  354. package/dist/sync/v3/localTaskStatusClient.js +6 -1
  355. package/dist/sync/v3/localTaskStatusOutboxService.d.ts +10 -0
  356. package/dist/sync/v3/localTaskStatusOutboxService.js +272 -24
  357. package/dist/sync/v3/syncDurabilityStore.d.ts +41 -0
  358. package/dist/sync/v3/syncDurabilityStore.js +199 -13
  359. package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +6 -4
  360. package/dist/sync/v3/taskAttachmentLinksMutationService.js +19 -10
  361. package/dist/sync/v3/taskChecklistMutationService.d.ts +15 -2
  362. package/dist/sync/v3/taskChecklistMutationService.js +48 -1
  363. package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
  364. package/dist/sync/v3/taskCreateMutationService.js +7 -4
  365. package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
  366. package/dist/sync/v3/taskMetadataMutationService.js +4 -0
  367. package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
  368. package/dist/sync/v3/taskRestoreMutationService.js +7 -4
  369. package/dist/sync/v3/taskStatusMutationService.d.ts +31 -1
  370. package/dist/sync/v3/taskStatusMutationService.js +123 -3
  371. package/dist/sync/v3/workflowAssignmentSync.d.ts +6 -0
  372. package/dist/sync/v3/workflowAssignmentSync.js +30 -0
  373. package/dist/sync/v3/workspaceSyncJournalReader.js +1 -1
  374. package/dist/sync/v3/workspaceSyncOperationRetentionService.d.ts +16 -0
  375. package/dist/sync/v3/workspaceSyncOperationRetentionService.js +83 -0
  376. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
  377. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +13 -3
  378. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
  379. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
  380. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
  381. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
  382. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.d.ts +1 -0
  383. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +18 -3
  384. package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +8 -3
  385. package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +51 -10
  386. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +14 -0
  387. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +49 -25
  388. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +13 -4
  389. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +124 -57
  390. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +20 -0
  391. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +106 -30
  392. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +4 -1
  393. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +34 -0
  394. package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +12 -0
  395. package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
  396. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
  397. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
  398. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
  399. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
  400. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
  401. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
  402. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
  403. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
  404. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
  405. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
  406. package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +5 -0
  407. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +7 -0
  408. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +55 -9
  409. package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.d.ts +17 -0
  410. package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.js +64 -0
  411. package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
  412. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
  413. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
  414. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
  415. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
  416. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.d.ts +7 -0
  417. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.js +33 -0
  418. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.d.ts +7 -0
  419. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.js +8 -0
  420. package/dist/sync/workspacePullFeed.js +2 -1
  421. package/dist/sync/workspaceRepair.d.ts +8 -2
  422. package/dist/sync/workspaceRepair.js +222 -6
  423. package/dist/sync/workspaceSyncModel.d.ts +21 -0
  424. package/dist/sync/workspaceSyncModel.js +35 -7
  425. package/dist/sync/workspaceSyncState.d.ts +1 -0
  426. package/dist/sync/workspaceSyncV2SnapshotBuilder.d.ts +6 -0
  427. package/dist/sync/workspaceSyncV2SnapshotBuilder.js +5 -0
  428. package/dist/types.d.ts +47 -1
  429. package/dist/types.js +6 -0
  430. package/dist/ui/assets/AiIdentityRosterCard-OcSz1PkK.js +1 -0
  431. package/dist/ui/assets/AiProfilesModule-ByhYW5Xi.js +1 -0
  432. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTM6nIg_.js +3 -0
  433. package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
  434. package/dist/ui/assets/{AssetTraySortControl-Kf1pelSy.js → AssetTraySortControl-DabEG8L4.js} +1 -1
  435. package/dist/ui/assets/{ContextAttachmentManager-B8boOs6Q.js → ContextAttachmentManager-Coa8yVGM.js} +2 -2
  436. package/dist/ui/assets/{DocumentWorkspace-DXH4XUsB.js → DocumentWorkspace-BB0qhdix.js} +1 -1
  437. package/dist/ui/assets/{EntityActivityTimeline-BtSTq0ON.js → EntityActivityTimeline-CZ8x4UJE.js} +1 -1
  438. package/dist/ui/assets/PlanningModule-pRPjR7v5.js +1 -0
  439. package/dist/ui/assets/PlansPage-D86pZSSl.js +1 -0
  440. package/dist/ui/assets/TaskContextUpload-BVIkU9yT.js +1 -0
  441. package/dist/ui/assets/TaskSettings-Cv1mNhv_.js +12 -0
  442. package/dist/ui/assets/TaskforceAgentsModule-b-8R25cJ.css +1 -0
  443. package/dist/ui/assets/TaskforceAgentsModule-gmH-PD2q.js +24 -0
  444. package/dist/ui/assets/{WorkflowManagerModule-DWFspC-o.js → WorkflowManagerModule-DbfnHJ-f.js} +1 -1
  445. package/dist/ui/assets/index-BZ-hdZSk.css +1 -0
  446. package/dist/ui/assets/index-CTsDBaef.js +7 -0
  447. package/dist/ui/assets/{vendor-icons-BkFLXavV.js → vendor-icons-Bsq-mcEn.js} +1 -1
  448. package/dist/ui/branding/logos/letterhead_dark.png +0 -0
  449. package/dist/ui/branding/logos/letterhead_light.png +0 -0
  450. package/dist/ui/branding/logos/signature_dark.png +0 -0
  451. package/dist/ui/branding/logos/signature_light.png +0 -0
  452. package/dist/ui/index.html +3 -3
  453. package/dist/utils/aiProfileDefaultLogo.js +16 -48
  454. package/dist/utils/httpSetCookie.d.ts +1 -0
  455. package/dist/utils/httpSetCookie.js +4 -1
  456. package/dist/utils/localRuntimeUrl.d.ts +1 -0
  457. package/dist/utils/localRuntimeUrl.js +14 -0
  458. package/dist/utils/productLogoRegistry.d.ts +2 -0
  459. package/dist/utils/productLogoRegistry.js +36 -0
  460. package/dist/utils/syncStatusPresentation.d.ts +4 -0
  461. package/dist/utils/syncStatusPresentation.js +17 -0
  462. package/dist/utils/taskActivity.d.ts +3 -2
  463. package/dist/utils/taskActivity.js +19 -2
  464. package/dist/utils/taskEditorReconciliation.d.ts +40 -0
  465. package/dist/utils/taskEditorReconciliation.js +217 -0
  466. package/dist/utils/taskEvents.d.ts +2 -0
  467. package/dist/utils/taskNormalization.d.ts +1 -0
  468. package/dist/utils/taskNormalization.js +39 -0
  469. package/dist/utils/taskSearch.js +2 -2
  470. package/dist/utils/uiNotice.d.ts +4 -0
  471. package/dist/utils/workspaceSyncPresentation.d.ts +1 -1
  472. package/dist/utils/workspaceSyncPresentation.js +23 -17
  473. package/package.json +36 -6
  474. package/dist/ui/assets/AiIdentityRosterCard-MZs7lVED.js +0 -1
  475. package/dist/ui/assets/AiProfilesModule-C3i0LOxe.js +0 -1
  476. package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
  477. package/dist/ui/assets/AnnotatedAttachmentWorkspace-DVZk5Tln.js +0 -3
  478. package/dist/ui/assets/PlanningModule-BPVyEa-f.js +0 -1
  479. package/dist/ui/assets/PlansPage-ChqgxALc.js +0 -1
  480. package/dist/ui/assets/TaskContextUpload-CB3ol0sN.js +0 -1
  481. package/dist/ui/assets/TaskSettings-g4ECKNOz.js +0 -12
  482. package/dist/ui/assets/TaskforceAgentsModule-BazdUwxZ.js +0 -21
  483. package/dist/ui/assets/TaskforceAgentsModule-D6IC0S7Q.css +0 -1
  484. package/dist/ui/assets/index-BUplSsv_.js +0 -7
  485. package/dist/ui/assets/index-gz2EXuoK.css +0 -1
@@ -0,0 +1,197 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+ const defaultFetch = (input, init) => globalThis.fetch(input, init);
3
+ export const TASK_DESCRIPTION_IMAGE_DRAFT_RECOVERY_STORAGE_KEY = 'taskforce.task-description-image-draft-recovery.v1';
4
+ const RETRY_DELAYS_MS = [1_000, 5_000, 15_000, 60_000];
5
+ const MAX_AUTOMATIC_RETRY_ATTEMPTS = 8;
6
+ const DORMANT_RETRY_AT = Number.MAX_SAFE_INTEGER;
7
+ export function taskDescriptionImageDraftRetryDelay(attempts) {
8
+ const index = Math.max(0, Math.min(RETRY_DELAYS_MS.length - 1, Math.floor(attempts) - 1));
9
+ return RETRY_DELAYS_MS[index];
10
+ }
11
+ function recordKey(record) {
12
+ return `${record.workspaceId}\u0000${record.createdByUserId}\u0000${record.draftUploadId}`;
13
+ }
14
+ function isRecoveryRecord(value) {
15
+ if (!value || typeof value !== 'object')
16
+ return false;
17
+ const record = value;
18
+ return typeof record.workspaceId === 'string'
19
+ && Boolean(record.workspaceId.trim())
20
+ && typeof record.createdByUserId === 'string'
21
+ && Boolean(record.createdByUserId.trim())
22
+ && typeof record.draftUploadId === 'string'
23
+ && Boolean(record.draftUploadId.trim())
24
+ && (record.resolution === 'promote' || record.resolution === 'discard')
25
+ && Number.isFinite(record.attempts)
26
+ && Number.isFinite(record.nextAttemptAt)
27
+ && Number.isFinite(record.createdAt);
28
+ }
29
+ function readRecoveryRecords(storage) {
30
+ if (!storage)
31
+ return [];
32
+ try {
33
+ const parsed = JSON.parse(storage.getItem(TASK_DESCRIPTION_IMAGE_DRAFT_RECOVERY_STORAGE_KEY) || '[]');
34
+ if (!Array.isArray(parsed))
35
+ return [];
36
+ const records = new Map();
37
+ parsed.filter(isRecoveryRecord).forEach((record) => {
38
+ records.set(recordKey(record), record);
39
+ });
40
+ return [...records.values()];
41
+ }
42
+ catch {
43
+ return [];
44
+ }
45
+ }
46
+ function writeRecoveryRecords(storage, records) {
47
+ if (!storage)
48
+ return;
49
+ try {
50
+ if (records.length === 0) {
51
+ storage.removeItem(TASK_DESCRIPTION_IMAGE_DRAFT_RECOVERY_STORAGE_KEY);
52
+ return;
53
+ }
54
+ storage.setItem(TASK_DESCRIPTION_IMAGE_DRAFT_RECOVERY_STORAGE_KEY, JSON.stringify(records));
55
+ }
56
+ catch {
57
+ // The request still gets an immediate attempt when browser storage is unavailable.
58
+ }
59
+ }
60
+ function updateRecoveryRecords(storage, update) {
61
+ const next = update(readRecoveryRecords(storage));
62
+ writeRecoveryRecords(storage, next);
63
+ return next;
64
+ }
65
+ function defaultStorage() {
66
+ try {
67
+ return globalThis.localStorage || null;
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ }
73
+ export function useTaskDescriptionImageDraftRecovery(workspaceId, createdByUserId, options = {}) {
74
+ const fetchImpl = options.fetchImpl || defaultFetch;
75
+ const storage = options.storage === undefined ? defaultStorage() : options.storage;
76
+ const now = options.now || Date.now;
77
+ const timerRef = useRef(null);
78
+ const inFlightRef = useRef(new Map());
79
+ const drainRef = useRef(async () => { });
80
+ const clearRetryTimer = useCallback(() => {
81
+ if (timerRef.current === null)
82
+ return;
83
+ clearTimeout(timerRef.current);
84
+ timerRef.current = null;
85
+ }, []);
86
+ const scheduleRetry = useCallback(() => {
87
+ clearRetryTimer();
88
+ const nextRecord = readRecoveryRecords(storage)
89
+ .filter((record) => (record.workspaceId === workspaceId
90
+ && record.createdByUserId === createdByUserId
91
+ && record.nextAttemptAt < DORMANT_RETRY_AT))
92
+ .sort((left, right) => left.nextAttemptAt - right.nextAttemptAt)[0];
93
+ if (!nextRecord)
94
+ return;
95
+ const delay = Math.max(0, nextRecord.nextAttemptAt - now());
96
+ timerRef.current = setTimeout(() => {
97
+ timerRef.current = null;
98
+ void drainRef.current(false);
99
+ }, delay);
100
+ }, [clearRetryTimer, createdByUserId, now, storage, workspaceId]);
101
+ const attemptRecovery = useCallback((record) => {
102
+ const key = recordKey(record);
103
+ const existing = inFlightRef.current.get(key);
104
+ if (existing)
105
+ return existing;
106
+ const request = (async () => {
107
+ await Promise.resolve();
108
+ try {
109
+ const response = await fetchImpl(`/api/taskforce/context-upload/draft/${record.resolution}`, {
110
+ method: 'POST',
111
+ headers: { 'Content-Type': 'application/json' },
112
+ body: JSON.stringify({
113
+ workspaceId: record.workspaceId,
114
+ draftUploadId: record.draftUploadId,
115
+ uploadPurpose: 'task-description-draft',
116
+ }),
117
+ });
118
+ if (!response.ok) {
119
+ throw new Error(`Draft upload ${record.resolution} was rejected (${response.status}).`);
120
+ }
121
+ updateRecoveryRecords(storage, (records) => (records.filter((candidate) => recordKey(candidate) !== key)));
122
+ }
123
+ catch (error) {
124
+ updateRecoveryRecords(storage, (records) => records.map((candidate) => {
125
+ if (recordKey(candidate) !== key)
126
+ return candidate;
127
+ const attempts = Math.min(Number.MAX_SAFE_INTEGER, candidate.attempts + 1);
128
+ return {
129
+ ...candidate,
130
+ attempts,
131
+ nextAttemptAt: attempts >= MAX_AUTOMATIC_RETRY_ATTEMPTS
132
+ ? DORMANT_RETRY_AT
133
+ : now() + taskDescriptionImageDraftRetryDelay(attempts),
134
+ };
135
+ }));
136
+ throw error;
137
+ }
138
+ finally {
139
+ inFlightRef.current.delete(key);
140
+ scheduleRetry();
141
+ }
142
+ })();
143
+ inFlightRef.current.set(key, request);
144
+ return request;
145
+ }, [fetchImpl, now, scheduleRetry, storage]);
146
+ const drain = useCallback(async (force = false) => {
147
+ const currentTime = now();
148
+ const dueRecords = readRecoveryRecords(storage).filter((record) => (record.workspaceId === workspaceId
149
+ && record.createdByUserId === createdByUserId
150
+ && (force || record.nextAttemptAt <= currentTime)));
151
+ await Promise.allSettled(dueRecords.map((record) => attemptRecovery(record)));
152
+ scheduleRetry();
153
+ }, [attemptRecovery, createdByUserId, now, scheduleRetry, storage, workspaceId]);
154
+ drainRef.current = drain;
155
+ useEffect(() => {
156
+ void drain(true);
157
+ const retryWhenOnline = () => { void drain(true); };
158
+ const retryWhenVisible = () => {
159
+ if (document.visibilityState === 'visible')
160
+ void drain(true);
161
+ };
162
+ const retryAfterStorageChange = (event) => {
163
+ if (event.key === TASK_DESCRIPTION_IMAGE_DRAFT_RECOVERY_STORAGE_KEY)
164
+ void drain(false);
165
+ };
166
+ window.addEventListener('online', retryWhenOnline);
167
+ window.addEventListener('storage', retryAfterStorageChange);
168
+ document.addEventListener('visibilitychange', retryWhenVisible);
169
+ return () => {
170
+ clearRetryTimer();
171
+ window.removeEventListener('online', retryWhenOnline);
172
+ window.removeEventListener('storage', retryAfterStorageChange);
173
+ document.removeEventListener('visibilitychange', retryWhenVisible);
174
+ };
175
+ }, [clearRetryTimer, drain]);
176
+ const resolveDraft = useCallback(async (input) => {
177
+ const draftUploadId = input.draftUploadId.trim();
178
+ if (!workspaceId || !createdByUserId || !draftUploadId)
179
+ return;
180
+ const queuedAt = now();
181
+ const record = {
182
+ workspaceId,
183
+ createdByUserId,
184
+ draftUploadId,
185
+ resolution: input.resolution,
186
+ attempts: 0,
187
+ nextAttemptAt: queuedAt,
188
+ createdAt: queuedAt,
189
+ };
190
+ updateRecoveryRecords(storage, (records) => [
191
+ ...records.filter((candidate) => recordKey(candidate) !== recordKey(record)),
192
+ record,
193
+ ]);
194
+ await attemptRecovery(record);
195
+ }, [attemptRecovery, createdByUserId, now, storage, workspaceId]);
196
+ return { resolveDraft };
197
+ }
@@ -1,5 +1,12 @@
1
1
  import type { AttachmentItem, CategoryConfig, ChecklistItem, Comment, TaskAssignee, TaskItem, TaskStatus, TaxonomyDefinition, WorkstreamItem } from '../../types';
2
2
  type TaskforceTab = 'add' | 'tasks' | 'settings';
3
+ type ApplyTaskOptions = {
4
+ preserveReturnTrail?: boolean;
5
+ adoptAsBaseline?: boolean;
6
+ };
7
+ type LoadTaskOptions = ApplyTaskOptions & {
8
+ shouldApply?: () => boolean;
9
+ };
3
10
  interface UseTaskEditorNavigationInput {
4
11
  activeCategories: CategoryConfig[];
5
12
  activeTypes: Array<{
@@ -10,6 +17,7 @@ interface UseTaskEditorNavigationInput {
10
17
  attachments: Array<string | AttachmentItem>;
11
18
  checklistItems: ChecklistItem[];
12
19
  comments: Comment[];
20
+ cancelTaskDetailLoad?: () => void;
13
21
  description: string;
14
22
  editingTaskId: string | null;
15
23
  flushPendingAutoSave: () => Promise<boolean>;
@@ -17,7 +25,12 @@ interface UseTaskEditorNavigationInput {
17
25
  getPreferredCategoryValue: (categories: CategoryConfig[]) => string;
18
26
  getTitleDraft?: () => string;
19
27
  lastUsedCategory: string;
28
+ loadTaskDetail?: (task: TaskItem, options?: {
29
+ shouldCommit?: () => boolean;
30
+ force?: boolean;
31
+ }) => Promise<TaskItem | null>;
20
32
  newCommentText: string;
33
+ onTaskApplied?: (task: TaskItem) => void;
21
34
  relationshipTasks: TaskItem[];
22
35
  workstreams: WorkstreamItem[];
23
36
  showArchive: boolean;
@@ -56,9 +69,9 @@ export declare function useTaskEditorNavigation(input: UseTaskEditorNavigationIn
56
69
  resetForm: () => void;
57
70
  resolveTaskIdInput: (value: string) => TaskItem | null;
58
71
  resolveWorkstreamIdInput: (value: string) => WorkstreamItem | null;
59
- handleEdit: (task: TaskItem, options?: {
60
- preserveReturnTrail?: boolean;
61
- }) => void;
72
+ handleEdit: (task: TaskItem, options?: ApplyTaskOptions) => void;
73
+ refreshTaskDetail: (task: TaskItem, options?: LoadTaskOptions) => Promise<TaskItem | null>;
74
+ applyTaskToEditor: (task: TaskItem, options?: ApplyTaskOptions) => void;
62
75
  handleOpenTaskById: (taskId: string) => void;
63
76
  returnToPreviousTask: () => boolean;
64
77
  clearReturnToParentTask: () => void;
@@ -1,17 +1,26 @@
1
- import { useCallback } from 'react';
1
+ import { useCallback, useRef } from 'react';
2
2
  import { DEFAULT_TYPE_VALUE } from '../../shared/taxonomyDefaults.js';
3
3
  import { getTaskReferenceLabel, parseTaskReference } from '../../utils/taskReferences';
4
4
  import { formatWorkstreamReference, parseWorkstreamReference } from '../../utils/planningReferences';
5
5
  import { buildDefaultFormTaxonomies } from '../../utils/taxonomyFormDefaults.js';
6
6
  export function useTaskEditorNavigation(input) {
7
- const { activeCategories, activeTypes, activeTab, attachments, checklistItems, comments, description, editingTaskId, flushPendingAutoSave, getDescriptionDraft, getPreferredCategoryValue, getTitleDraft, lastUsedCategory, newCommentText, relationshipTasks, workstreams, showArchive, taxonomies, setActiveTab, setAssignee, setAttachments, setAttachmentsDirty, setCategory, setChecklistItems, setComments, setComplexity, setDescription, setDueDate, setEditingTaskId, setError, setFormTaxonomies, setIsOpen, setNewCommentText, setPendingNavigation, setWorkstreamInput, setPriority, setScheduledDate, setShowArchive, setStatus, setTaskReturnTrail, setTitle, setType, setUnsavedModalOpen, taskReturnTrail, title, } = input;
7
+ const { activeCategories, activeTypes, activeTab, attachments, checklistItems, comments, cancelTaskDetailLoad, description, editingTaskId, flushPendingAutoSave, getDescriptionDraft, getPreferredCategoryValue, getTitleDraft, lastUsedCategory, loadTaskDetail, newCommentText, onTaskApplied, relationshipTasks, workstreams, showArchive, taxonomies, setActiveTab, setAssignee, setAttachments, setAttachmentsDirty, setCategory, setChecklistItems, setComments, setComplexity, setDescription, setDueDate, setEditingTaskId, setError, setFormTaxonomies, setIsOpen, setNewCommentText, setPendingNavigation, setWorkstreamInput, setPriority, setScheduledDate, setShowArchive, setStatus, setTaskReturnTrail, setTitle, setType, setUnsavedModalOpen, taskReturnTrail, title, } = input;
8
+ const editRequestSequenceRef = useRef(0);
9
+ const invalidatePendingEdit = useCallback(() => {
10
+ editRequestSequenceRef.current += 1;
11
+ cancelTaskDetailLoad?.();
12
+ }, [cancelTaskDetailLoad]);
8
13
  const getPreferredTypeValue = useCallback(() => {
9
14
  return activeTypes.find((entry) => String(entry.value || '').trim().length > 0)?.value || DEFAULT_TYPE_VALUE;
10
15
  }, [activeTypes]);
11
16
  const handleNavigation = useCallback(async (action) => {
17
+ const navigate = () => {
18
+ invalidatePendingEdit();
19
+ action();
20
+ };
12
21
  if (editingTaskId) {
13
22
  if (await flushPendingAutoSave()) {
14
- action();
23
+ navigate();
15
24
  }
16
25
  return;
17
26
  }
@@ -22,10 +31,10 @@ export function useTaskEditorNavigation(input) {
22
31
  comments.length > 0 ||
23
32
  attachments.length > 0;
24
33
  if (!hasChanges) {
25
- action();
34
+ navigate();
26
35
  return;
27
36
  }
28
- setPendingNavigation(() => action);
37
+ setPendingNavigation(() => navigate);
29
38
  setUnsavedModalOpen(true);
30
39
  }, [
31
40
  attachments,
@@ -36,15 +45,18 @@ export function useTaskEditorNavigation(input) {
36
45
  getDescriptionDraft,
37
46
  getTitleDraft,
38
47
  checklistItems,
48
+ invalidatePendingEdit,
39
49
  newCommentText,
40
50
  setPendingNavigation,
41
51
  setUnsavedModalOpen,
42
52
  title,
43
53
  ]);
44
54
  const handleClose = useCallback(() => {
55
+ invalidatePendingEdit();
45
56
  setIsOpen(false);
46
- }, [setIsOpen]);
57
+ }, [invalidatePendingEdit, setIsOpen]);
47
58
  const resetForm = useCallback(() => {
59
+ invalidatePendingEdit();
48
60
  setEditingTaskId(null);
49
61
  setTitle('');
50
62
  setDescription('');
@@ -76,6 +88,7 @@ export function useTaskEditorNavigation(input) {
76
88
  activeCategories,
77
89
  getPreferredCategoryValue,
78
90
  getPreferredTypeValue,
91
+ invalidatePendingEdit,
79
92
  lastUsedCategory,
80
93
  setAssignee,
81
94
  setAttachments,
@@ -134,7 +147,7 @@ export function useTaskEditorNavigation(input) {
134
147
  return exactTitle;
135
148
  return null;
136
149
  }, [workstreams]);
137
- const handleEdit = useCallback((task, options) => {
150
+ const applyTaskToEditor = useCallback((task, options) => {
138
151
  if (!options?.preserveReturnTrail) {
139
152
  setTaskReturnTrail([]);
140
153
  }
@@ -157,6 +170,8 @@ export function useTaskEditorNavigation(input) {
157
170
  setAttachments(task.attachments || []);
158
171
  setAttachmentsDirty(false);
159
172
  setActiveTab('add');
173
+ if (options?.adoptAsBaseline !== false)
174
+ onTaskApplied?.(task);
160
175
  }, [
161
176
  activeCategories,
162
177
  getPreferredCategoryValue,
@@ -179,20 +194,62 @@ export function useTaskEditorNavigation(input) {
179
194
  setTaskReturnTrail,
180
195
  setTitle,
181
196
  setType,
197
+ onTaskApplied,
182
198
  workstreams
183
199
  ]);
200
+ const loadAndApplyTask = useCallback(async (task, options) => {
201
+ const requestSequence = editRequestSequenceRef.current + 1;
202
+ editRequestSequenceRef.current = requestSequence;
203
+ if (!loadTaskDetail) {
204
+ cancelTaskDetailLoad?.();
205
+ applyTaskToEditor(task, { preserveReturnTrail: options?.preserveReturnTrail });
206
+ return task;
207
+ }
208
+ if (!task.isSummary) {
209
+ cancelTaskDetailLoad?.();
210
+ const detail = options?.shouldApply
211
+ ? await loadTaskDetail(task, { shouldCommit: options.shouldApply })
212
+ : await loadTaskDetail(task);
213
+ if (editRequestSequenceRef.current === requestSequence) {
214
+ const taskToApply = detail || task;
215
+ applyTaskToEditor(taskToApply, { preserveReturnTrail: options?.preserveReturnTrail });
216
+ return taskToApply;
217
+ }
218
+ return null;
219
+ }
220
+ const detail = options?.shouldApply
221
+ ? await loadTaskDetail(task, { shouldCommit: options.shouldApply })
222
+ : await loadTaskDetail(task);
223
+ if (detail
224
+ && editRequestSequenceRef.current === requestSequence) {
225
+ applyTaskToEditor(detail, { preserveReturnTrail: options?.preserveReturnTrail });
226
+ return detail;
227
+ }
228
+ return null;
229
+ }, [applyTaskToEditor, cancelTaskDetailLoad, loadTaskDetail]);
230
+ const handleEdit = useCallback((task, options) => {
231
+ void loadAndApplyTask(task, options);
232
+ }, [loadAndApplyTask]);
233
+ const refreshTaskDetail = useCallback((task, options) => loadAndApplyTask(task, options), [loadAndApplyTask]);
184
234
  const handleOpenTaskById = useCallback((taskId) => {
185
235
  const target = relationshipTasks.find((task) => task.id === taskId);
186
236
  if (!target)
187
237
  return;
238
+ const openTarget = () => {
239
+ if (activeTab === 'add' && editingTaskId && editingTaskId !== target.id) {
240
+ setTaskReturnTrail((prev) => prev[prev.length - 1] === editingTaskId ? prev : [...prev, editingTaskId]);
241
+ }
242
+ if (target.isArchived && !showArchive) {
243
+ setShowArchive(true);
244
+ }
245
+ handleEdit(target, { preserveReturnTrail: true });
246
+ };
188
247
  if (activeTab === 'add' && editingTaskId && editingTaskId !== target.id) {
189
- setTaskReturnTrail((prev) => prev[prev.length - 1] === editingTaskId ? prev : [...prev, editingTaskId]);
190
- }
191
- if (target.isArchived && !showArchive) {
192
- setShowArchive(true);
248
+ void handleNavigation(openTarget);
249
+ return;
193
250
  }
194
- handleEdit(target, { preserveReturnTrail: true });
195
- }, [activeTab, editingTaskId, handleEdit, relationshipTasks, setShowArchive, setTaskReturnTrail, showArchive]);
251
+ openTarget();
252
+ }, [activeTab, editingTaskId, handleEdit, handleNavigation, relationshipTasks, setShowArchive, setTaskReturnTrail, showArchive]);
196
253
  const returnToPreviousTask = useCallback(() => {
197
254
  if (activeTab !== 'add' || !editingTaskId || taskReturnTrail.length === 0)
198
255
  return false;
@@ -224,6 +281,8 @@ export function useTaskEditorNavigation(input) {
224
281
  resolveTaskIdInput,
225
282
  resolveWorkstreamIdInput,
226
283
  handleEdit,
284
+ refreshTaskDetail,
285
+ applyTaskToEditor,
227
286
  handleOpenTaskById,
228
287
  returnToPreviousTask,
229
288
  clearReturnToParentTask
@@ -1,6 +1,7 @@
1
1
  import type { AttachmentItem, CategoryConfig, ChecklistItem, TaskAssignee, TaskItem, TaskStatus, TaxonomyDefinition, WorkstreamItem } from '../../types';
2
2
  import type { DurableTaskCreateMutationAdapter } from '../sync/useDurableTaskCreateMutation.js';
3
3
  import { createCloudTaskHttpMutationClient } from './taskHttpMutation.js';
4
+ import type { TaskEditorDraft } from '../../utils/taskEditorReconciliation.js';
4
5
  interface UseTaskFormActionsInput {
5
6
  activeCategories: CategoryConfig[];
6
7
  activeTab: 'add' | 'tasks' | 'settings';
@@ -20,6 +21,8 @@ interface UseTaskFormActionsInput {
20
21
  taskHttpMutationClient?: ReturnType<typeof createCloudTaskHttpMutationClient>;
21
22
  updateTask?: (taskId: string, updates: Partial<TaskItem>) => Promise<boolean | void>;
22
23
  editingTaskId: string | null;
24
+ editorBaselineDraft?: TaskEditorDraft | null;
25
+ revisionConflict?: boolean;
23
26
  fetchTasks: (isSilent?: boolean) => Promise<void>;
24
27
  formTaxonomies: Record<string, string | number | string[] | number[]>;
25
28
  getAttachmentsDraft?: () => Array<string | AttachmentItem>;
@@ -55,6 +58,9 @@ interface UseTaskFormActionsInput {
55
58
  export type TaskAutoSaveState = 'idle' | 'saving' | 'saved' | 'error';
56
59
  export declare function useTaskFormActions(input: UseTaskFormActionsInput): {
57
60
  autoSaveState: TaskAutoSaveState;
61
+ hasUnsavedChanges: boolean;
62
+ hasUnsavedChangesNow: () => boolean;
63
+ hasPendingAutoSave: boolean;
58
64
  flushAutoSave: () => Promise<boolean>;
59
65
  scheduleWarningPrompt: {
60
66
  dueDate: string;
@@ -4,7 +4,7 @@ import { normalizeTaskFromApi } from '../../utils/taskNormalization.js';
4
4
  import { createCloudTaskHttpMutationClient, fetchTaskHttpMutation, isConclusiveTaskHttpResponse, } from './taskHttpMutation.js';
5
5
  import { canonicalWorkspaceSyncJson } from '../../sync/v3/canonicalWorkspaceSyncJson.js';
6
6
  export function useTaskFormActions(input) {
7
- const { activeCategories, activeTab, apiEndpoint, assignee, attachments, attachmentsDirty, category, checklistItems, comments, complexity, description, dueDate, createTaskDurably, durableTaskHttpRootActivationEnabled = false, workspaceId, taskHttpMutationClient, updateTask, editingTaskId, fetchTasks, formTaxonomies, getAttachmentsDraft: getAttachmentsDraftInput, getDescriptionDraft: getDescriptionDraftInput, getPreferredCategoryValue, getTitleDraft: getTitleDraftInput, awaitPendingDescriptionImageUpload: awaitPendingDescriptionImageUploadInput, mergeTaskFromServer, onTaskCreated, onTaskCreateAccepted, workstreamInput, priority, pushNotice, queueWorkspaceSyncFromAuthoritativeTaskState, relationshipTasks, supplementalTasks = [], resetForm, resolveWorkstreamIdInput, scheduledDate, setActiveTab, setAttachmentsDirty, setComments, setError, setLastUsedCategory, setLoading, setNewCommentText, status, title, taxonomies, textDraftOccupied, type } = input;
7
+ const { activeCategories, activeTab, apiEndpoint, assignee, attachments, attachmentsDirty, category, checklistItems, comments, complexity, description, dueDate, createTaskDurably, durableTaskHttpRootActivationEnabled = false, workspaceId, taskHttpMutationClient, updateTask, editingTaskId, editorBaselineDraft = null, revisionConflict = false, fetchTasks, formTaxonomies, getAttachmentsDraft: getAttachmentsDraftInput, getDescriptionDraft: getDescriptionDraftInput, getPreferredCategoryValue, getTitleDraft: getTitleDraftInput, awaitPendingDescriptionImageUpload: awaitPendingDescriptionImageUploadInput, mergeTaskFromServer, onTaskCreated, onTaskCreateAccepted, workstreamInput, priority, pushNotice, queueWorkspaceSyncFromAuthoritativeTaskState, relationshipTasks, supplementalTasks = [], resetForm, resolveWorkstreamIdInput, scheduledDate, setActiveTab, setAttachmentsDirty, setComments, setError, setLastUsedCategory, setLoading, setNewCommentText, status, title, taxonomies, textDraftOccupied, type } = input;
8
8
  const getTitleDraft = getTitleDraftInput || (() => title);
9
9
  const getDescriptionDraft = getDescriptionDraftInput || (() => description);
10
10
  const getAttachmentsDraft = getAttachmentsDraftInput || (() => attachments);
@@ -53,29 +53,46 @@ export function useTaskFormActions(input) {
53
53
  }
54
54
  createDraftOccupiedRef.current = createDraftOccupied;
55
55
  }, [createDraftOccupied, createTaskDurably, workspaceId]);
56
- const buildTaskDraftSignature = useCallback((textDraft = readTextDraft(), attachmentDraft = getAttachmentsDraftRef.current()) => JSON.stringify({
57
- title: textDraft.title.trim(),
56
+ const buildTaskDraftSignatureFromEditorDraft = useCallback((draft) => JSON.stringify({
57
+ title: draft.title.trim(),
58
+ description: draft.description,
59
+ category: draft.category,
60
+ type: draft.type,
61
+ priority: Number(draft.priority),
62
+ complexity: Number(draft.complexity) || 3,
63
+ assignee: draft.assignee || 'agent',
64
+ scheduledDate: draft.scheduledDate || '',
65
+ dueDate: draft.dueDate || '',
66
+ workstreamId: draft.workstreamId || '',
67
+ checklistItems: draft.checklistItems,
68
+ taxonomies: draft.taxonomies,
69
+ attachments: draft.attachments,
70
+ }), []);
71
+ const buildTaskDraftSignature = useCallback((textDraft = readTextDraft(), attachmentDraft = getAttachmentsDraftRef.current()) => buildTaskDraftSignatureFromEditorDraft({
72
+ title: textDraft.title,
58
73
  description: textDraft.description,
59
74
  category: typeof category === 'string'
60
75
  ? category
61
76
  : category.label || getPreferredCategoryValue(activeCategories),
62
77
  type: typeof type === 'string' ? type : type.label || DEFAULT_TYPE_VALUE,
63
- priority: Number(priority),
78
+ priority,
64
79
  complexity: Number(complexity) || 3,
80
+ status,
65
81
  assignee: assignee || 'agent',
66
- scheduledDate: scheduledDate || '',
67
- dueDate: dueDate || '',
68
- workstreamInput: workstreamInput.trim(),
82
+ scheduledDate,
83
+ dueDate,
84
+ workstreamId: workstreamInput.trim()
85
+ ? (resolveWorkstreamIdInput(workstreamInput)?.id || workstreamInput.trim())
86
+ : '',
69
87
  checklistItems,
70
- comments,
71
88
  taxonomies: formTaxonomies,
72
89
  attachments: attachmentDraft,
73
90
  }), [
74
91
  activeCategories,
75
92
  assignee,
93
+ buildTaskDraftSignatureFromEditorDraft,
76
94
  category,
77
95
  checklistItems,
78
- comments,
79
96
  complexity,
80
97
  description,
81
98
  dueDate,
@@ -83,7 +100,9 @@ export function useTaskFormActions(input) {
83
100
  getPreferredCategoryValue,
84
101
  priority,
85
102
  readTextDraft,
103
+ resolveWorkstreamIdInput,
86
104
  scheduledDate,
105
+ status,
87
106
  title,
88
107
  type,
89
108
  workstreamInput
@@ -94,6 +113,17 @@ export function useTaskFormActions(input) {
94
113
  autoSaveTimerRef.current = null;
95
114
  }
96
115
  }, []);
116
+ const hasUnsavedChangesNow = useCallback(() => Boolean(editingTaskId
117
+ && lastSavedDraftSignature !== null
118
+ && buildTaskDraftSignature() !== lastSavedDraftSignature), [buildTaskDraftSignature, editingTaskId, lastSavedDraftSignature]);
119
+ const hasUnsavedChanges = hasUnsavedChangesNow();
120
+ useEffect(() => {
121
+ if (!revisionConflict)
122
+ return;
123
+ clearAutoSaveTimer();
124
+ queuedAutoSaveRef.current = null;
125
+ setAutoSaveState('idle');
126
+ }, [clearAutoSaveTimer, revisionConflict]);
97
127
  const enqueueAutoSave = useCallback((request) => {
98
128
  if (activeAutoSaveSignatureRef.current === request.signature
99
129
  && queuedAutoSaveRef.current === null
@@ -127,6 +157,11 @@ export function useTaskFormActions(input) {
127
157
  const saveTask = useCallback(async (options) => {
128
158
  const quiet = options?.quiet ?? false;
129
159
  const source = options?.source ?? 'manual';
160
+ if (editingTaskId && revisionConflict) {
161
+ setError('');
162
+ setAutoSaveState('idle');
163
+ return false;
164
+ }
130
165
  if (!editingTaskId && source === 'manual') {
131
166
  try {
132
167
  await awaitPendingDescriptionImageUploadRef.current?.();
@@ -240,6 +275,9 @@ export function useTaskFormActions(input) {
240
275
  }
241
276
  if (editingTaskId && Object.keys(body).length > 0) {
242
277
  body.saveSource = source;
278
+ if (existingTask?.detailRevision) {
279
+ body.expectedDetailRevision = existingTask.detailRevision;
280
+ }
243
281
  }
244
282
  if (editingTaskId && updateTask) {
245
283
  const saved = await updateTask(editingTaskId, body);
@@ -413,6 +451,7 @@ export function useTaskFormActions(input) {
413
451
  taskHttpMutationClient,
414
452
  updateTask,
415
453
  editingTaskId,
454
+ revisionConflict,
416
455
  editingReadOnlyMode,
417
456
  formTaxonomies,
418
457
  getPreferredCategoryValue,
@@ -468,14 +507,23 @@ export function useTaskFormActions(input) {
468
507
  setAutoSaveState('idle');
469
508
  return;
470
509
  }
471
- setLastSavedDraftSignature(buildTaskDraftSignature());
510
+ setLastSavedDraftSignature(editorBaselineDraft
511
+ ? buildTaskDraftSignatureFromEditorDraft(editorBaselineDraft)
512
+ : buildTaskDraftSignature());
472
513
  setAutoSaveState('idle');
473
- }, [clearAutoSaveTimer, editingTaskId]);
514
+ }, [
515
+ buildTaskDraftSignatureFromEditorDraft,
516
+ clearAutoSaveTimer,
517
+ editingTaskId,
518
+ editorBaselineDraft,
519
+ ]);
474
520
  const flushAutoSave = useCallback(async () => {
475
521
  clearAutoSaveTimer();
476
522
  if (editingReadOnlyMode) {
477
523
  return true;
478
524
  }
525
+ if (revisionConflict)
526
+ return false;
479
527
  if (!editingTaskId || lastSavedDraftSignature === null) {
480
528
  return true;
481
529
  }
@@ -501,11 +549,12 @@ export function useTaskFormActions(input) {
501
549
  enqueueAutoSave,
502
550
  lastSavedDraftSignature,
503
551
  readTextDraft,
552
+ revisionConflict,
504
553
  saveTask,
505
554
  scheduledDate,
506
555
  ]);
507
556
  useEffect(() => {
508
- if (!editingTaskId || editingReadOnlyMode || lastSavedDraftSignature === null) {
557
+ if (!editingTaskId || editingReadOnlyMode || revisionConflict || lastSavedDraftSignature === null) {
509
558
  return;
510
559
  }
511
560
  const textDraft = readTextDraft();
@@ -551,6 +600,7 @@ export function useTaskFormActions(input) {
551
600
  enqueueAutoSave,
552
601
  lastSavedDraftSignature,
553
602
  readTextDraft,
603
+ revisionConflict,
554
604
  saveTask,
555
605
  scheduledDate,
556
606
  ]);
@@ -637,6 +687,9 @@ export function useTaskFormActions(input) {
637
687
  ]);
638
688
  return {
639
689
  autoSaveState,
690
+ hasUnsavedChanges,
691
+ hasUnsavedChangesNow,
692
+ hasPendingAutoSave: autoSaveState === 'saving',
640
693
  flushAutoSave,
641
694
  scheduleWarningPrompt,
642
695
  saveTask,