@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
@@ -3,13 +3,38 @@ import { Worker } from 'worker_threads';
3
3
  import { performance } from 'node:perf_hooks';
4
4
  import { assertSynchronousTransactionResult, } from './databaseAdapter.js';
5
5
  import { recordPostgresWorkerWait } from './postgresRequestDiagnostics.js';
6
+ import { resolvePostgresWorkerDeadlines, } from './postgresWorkerProtocol.js';
6
7
  const RESPONSE_STATUS_INDEX = 0;
7
8
  const RESPONSE_LENGTH_INDEX = 1;
8
9
  const RESPONSE_READY = 1;
9
10
  const RESPONSE_INITIAL = 0;
10
- const RESPONSE_TIMEOUT_MS = 20_000;
11
11
  const RESPONSE_BUFFER_BYTES = 2 * 1024 * 1024;
12
12
  const MAX_RESPONSE_BUFFER_BYTES = 64 * 1024 * 1024;
13
+ export class PostgresWorkerOutcomeUnknownError extends Error {
14
+ code = 'POSTGRES_WORKER_OUTCOME_UNKNOWN';
15
+ operation;
16
+ constructor(operation, detail = 'response deadline exceeded') {
17
+ super(`[Taskforce] Postgres worker ${operation} outcome is unknown (${detail}). `
18
+ + 'Do not retry a write without the same idempotency identity.');
19
+ this.name = 'PostgresWorkerOutcomeUnknownError';
20
+ this.operation = operation;
21
+ }
22
+ }
23
+ export class PostgresWorkerUnavailableError extends Error {
24
+ code = 'POSTGRES_WORKER_UNAVAILABLE';
25
+ constructor() {
26
+ super('[Taskforce] Postgres worker is recovering after a failed operation.');
27
+ this.name = 'PostgresWorkerUnavailableError';
28
+ }
29
+ }
30
+ export class PostgresDatabaseError extends Error {
31
+ code;
32
+ constructor(message, code) {
33
+ super(message);
34
+ this.code = code;
35
+ this.name = 'PostgresDatabaseError';
36
+ }
37
+ }
13
38
  function isPlainObject(value) {
14
39
  return !!value && typeof value === 'object' && !Array.isArray(value);
15
40
  }
@@ -62,39 +87,102 @@ function toRowCount(result) {
62
87
  }
63
88
  export class PostgresAdapter {
64
89
  provider = 'postgres';
65
- open = true;
66
- worker;
90
+ worker = null;
91
+ connectionString;
92
+ deadlines;
93
+ retiringWorkers = new WeakSet();
94
+ consecutiveUnexpectedExits = 0;
95
+ closed = false;
67
96
  encoder = new TextEncoder();
68
97
  decoder = new TextDecoder();
69
98
  txId = null;
70
99
  savepointCounter = 0;
71
- constructor(connectionString) {
100
+ constructor(connectionString, deadlineOptions = {}) {
72
101
  if (!connectionString || !connectionString.trim()) {
73
102
  throw new Error('[Taskforce] Postgres adapter requires a non-empty connection string.');
74
103
  }
75
- this.worker = new Worker(new URL('./postgresWorker.js', import.meta.url), {
104
+ this.connectionString = connectionString;
105
+ this.deadlines = resolvePostgresWorkerDeadlines(deadlineOptions);
106
+ this.worker = this.createWorker();
107
+ }
108
+ get open() {
109
+ return !this.closed;
110
+ }
111
+ createWorker() {
112
+ const worker = new Worker(new URL('./postgresWorker.js', import.meta.url), {
76
113
  workerData: {
77
- connectionString
114
+ connectionString: this.connectionString,
115
+ deadlines: this.deadlines,
116
+ }
117
+ });
118
+ worker.on('error', () => {
119
+ // The exit handler replaces an unexpectedly failed worker. Keeping an error
120
+ // listener here also prevents Worker from escalating it as an uncaught error.
121
+ });
122
+ worker.on('exit', () => {
123
+ if (this.closed || this.retiringWorkers.has(worker) || this.worker !== worker)
124
+ return;
125
+ this.worker = null;
126
+ if (this.consecutiveUnexpectedExits >= 1)
127
+ return;
128
+ this.consecutiveUnexpectedExits += 1;
129
+ try {
130
+ this.worker = this.createWorker();
131
+ }
132
+ catch {
133
+ // Leave the adapter unavailable instead of creating an unbounded restart loop.
134
+ }
135
+ });
136
+ return worker;
137
+ }
138
+ quarantineWorker(worker) {
139
+ if (this.worker === worker)
140
+ this.worker = null;
141
+ this.txId = null;
142
+ this.retiringWorkers.add(worker);
143
+ void worker.terminate()
144
+ .catch(() => undefined)
145
+ .finally(() => {
146
+ if (this.closed || this.worker)
147
+ return;
148
+ try {
149
+ this.worker = this.createWorker();
150
+ }
151
+ catch {
152
+ // A later process-level health check can restart a persistently broken runtime.
78
153
  }
79
154
  });
80
155
  }
81
156
  callWorker(payload, responseBufferBytes = RESPONSE_BUFFER_BYTES) {
157
+ if (this.closed)
158
+ throw new Error('[Taskforce] Postgres adapter is closed.');
159
+ const worker = this.worker;
160
+ if (!worker)
161
+ throw new PostgresWorkerUnavailableError();
82
162
  const statusBuffer = new SharedArrayBuffer(8);
83
163
  const status = new Int32Array(statusBuffer);
84
164
  status[RESPONSE_STATUS_INDEX] = RESPONSE_INITIAL;
85
165
  status[RESPONSE_LENGTH_INDEX] = 0;
86
166
  const responseBuffer = new SharedArrayBuffer(responseBufferBytes);
87
167
  const responseBytes = new Uint8Array(responseBuffer);
88
- this.worker.postMessage({
89
- payload,
90
- statusBuffer,
91
- responseBuffer
92
- });
168
+ try {
169
+ worker.postMessage({
170
+ payload,
171
+ statusBuffer,
172
+ responseBuffer
173
+ });
174
+ }
175
+ catch (error) {
176
+ this.quarantineWorker(worker);
177
+ const detail = error instanceof Error ? error.message : 'worker transport failed';
178
+ throw new PostgresWorkerOutcomeUnknownError(payload.op, detail);
179
+ }
93
180
  const waitStartedAt = performance.now();
94
- const waitResult = Atomics.wait(status, RESPONSE_STATUS_INDEX, RESPONSE_INITIAL, RESPONSE_TIMEOUT_MS);
181
+ const waitResult = Atomics.wait(status, RESPONSE_STATUS_INDEX, RESPONSE_INITIAL, this.deadlines.responseTimeoutMs);
95
182
  recordPostgresWorkerWait(payload.op, performance.now() - waitStartedAt);
96
183
  if (waitResult === 'timed-out') {
97
- throw new Error('[Taskforce] Postgres worker timed out.');
184
+ this.quarantineWorker(worker);
185
+ throw new PostgresWorkerOutcomeUnknownError(payload.op);
98
186
  }
99
187
  const responseLength = status[RESPONSE_LENGTH_INDEX];
100
188
  if (!Number.isFinite(responseLength) || responseLength <= 0 || responseLength > responseBufferBytes) {
@@ -102,6 +190,7 @@ export class PostgresAdapter {
102
190
  }
103
191
  const body = this.decoder.decode(responseBytes.subarray(0, responseLength));
104
192
  const parsed = JSON.parse(body);
193
+ this.consecutiveUnexpectedExits = 0;
105
194
  if (!parsed.ok && parsed.errorCode === 'RESPONSE_BUFFER_TOO_SMALL') {
106
195
  const requiredBytes = Number(parsed.requiredBytes);
107
196
  const responseToken = String(parsed.responseToken || '').trim();
@@ -114,6 +203,9 @@ export class PostgresAdapter {
114
203
  return this.callWorker({ op: 'read-response', responseToken }, requiredBytes);
115
204
  }
116
205
  if (!parsed.ok) {
206
+ if (parsed.databaseErrorCode) {
207
+ throw new PostgresDatabaseError(parsed.error || 'Unknown Postgres database error', parsed.databaseErrorCode);
208
+ }
117
209
  throw new Error(parsed.error || 'Unknown Postgres worker error');
118
210
  }
119
211
  return parsed;
@@ -230,11 +322,22 @@ export class PostgresAdapter {
230
322
  return options?.simple ? null : [];
231
323
  }
232
324
  close() {
325
+ if (this.closed)
326
+ return;
327
+ const worker = this.worker;
328
+ if (!worker) {
329
+ this.closed = true;
330
+ return;
331
+ }
233
332
  try {
234
333
  this.callWorker({ op: 'close' });
235
334
  }
236
335
  finally {
237
- this.worker.terminate();
336
+ this.closed = true;
337
+ if (this.worker === worker)
338
+ this.worker = null;
339
+ this.retiringWorkers.add(worker);
340
+ void worker.terminate();
238
341
  }
239
342
  }
240
343
  }
@@ -14,11 +14,16 @@ function pruneRetainedResponses(now = Date.now()) {
14
14
  retainedResponses.delete(token);
15
15
  }
16
16
  }
17
- function createPool(connectionString) {
17
+ function createPool(connectionString, deadlines) {
18
18
  const require = createRequire(import.meta.url);
19
19
  try {
20
20
  const pg = require('pg');
21
- return new pg.Pool({ connectionString });
21
+ return new pg.Pool({
22
+ connectionString,
23
+ connectionTimeoutMillis: deadlines.connectionTimeoutMs,
24
+ statement_timeout: deadlines.statementTimeoutMs,
25
+ idle_in_transaction_session_timeout: deadlines.idleTransactionTimeoutMs,
26
+ });
22
27
  }
23
28
  catch (error) {
24
29
  const detail = error instanceof Error ? ` (${error.message})` : '';
@@ -96,11 +101,15 @@ function writeRetainedResponse(statusBuffer, responseBuffer, responseToken) {
96
101
  Atomics.store(status, RESPONSE_STATUS_INDEX, RESPONSE_READY);
97
102
  Atomics.notify(status, RESPONSE_STATUS_INDEX, 1);
98
103
  }
99
- const connectionString = String(workerData?.connectionString || '').trim();
104
+ const runtimeOptions = workerData;
105
+ const connectionString = String(runtimeOptions?.connectionString || '').trim();
100
106
  if (!connectionString) {
101
107
  throw new Error('[Taskforce] Postgres worker requires connection string.');
102
108
  }
103
- const pool = createPool(connectionString);
109
+ if (!runtimeOptions.deadlines) {
110
+ throw new Error('[Taskforce] Postgres worker requires deadline configuration.');
111
+ }
112
+ const pool = createPool(connectionString, runtimeOptions.deadlines);
104
113
  const txClients = new Map();
105
114
  async function handleMessage(message) {
106
115
  const { payload } = message;
@@ -169,6 +178,14 @@ parentPort.on('message', async (message) => {
169
178
  }
170
179
  catch (error) {
171
180
  const messageText = error instanceof Error ? error.message : String(error);
172
- writeResponse(message.statusBuffer, message.responseBuffer, { ok: false, error: messageText });
181
+ const databaseErrorCode = error && typeof error === 'object'
182
+ && typeof error.code === 'string'
183
+ ? String(error.code)
184
+ : undefined;
185
+ writeResponse(message.statusBuffer, message.responseBuffer, {
186
+ ok: false,
187
+ error: messageText,
188
+ ...(databaseErrorCode ? { databaseErrorCode } : {}),
189
+ });
173
190
  }
174
191
  });
@@ -0,0 +1,30 @@
1
+ export type PostgresWorkerOperation = 'query' | 'begin' | 'commit' | 'rollback' | 'close' | 'read-response';
2
+ export type PostgresWorkerRequestPayload = {
3
+ op: PostgresWorkerOperation;
4
+ sql?: string;
5
+ values?: unknown[];
6
+ txId?: string;
7
+ responseToken?: string;
8
+ };
9
+ export type PostgresWorkerQueryResult = {
10
+ rows: Record<string, unknown>[];
11
+ rowCount?: number;
12
+ };
13
+ export type PostgresWorkerResponsePayload = {
14
+ ok: boolean;
15
+ result?: PostgresWorkerQueryResult;
16
+ error?: string;
17
+ errorCode?: 'RESPONSE_BUFFER_TOO_SMALL';
18
+ databaseErrorCode?: string;
19
+ requiredBytes?: number;
20
+ responseToken?: string;
21
+ };
22
+ export type PostgresWorkerDeadlines = {
23
+ responseTimeoutMs: number;
24
+ statementTimeoutMs: number;
25
+ connectionTimeoutMs: number;
26
+ idleTransactionTimeoutMs: number;
27
+ };
28
+ export type PostgresAdapterDeadlineOptions = Partial<PostgresWorkerDeadlines>;
29
+ export declare const DEFAULT_POSTGRES_WORKER_DEADLINES: PostgresWorkerDeadlines;
30
+ export declare function resolvePostgresWorkerDeadlines(options?: PostgresAdapterDeadlineOptions): PostgresWorkerDeadlines;
@@ -0,0 +1,30 @@
1
+ export const DEFAULT_POSTGRES_WORKER_DEADLINES = {
2
+ responseTimeoutMs: 20_000,
3
+ statementTimeoutMs: 15_000,
4
+ connectionTimeoutMs: 3_000,
5
+ idleTransactionTimeoutMs: 60_000,
6
+ };
7
+ const MIN_RESPONSE_MARGIN_MS = 100;
8
+ function positiveInteger(value, name) {
9
+ const parsed = Number(value);
10
+ if (!Number.isSafeInteger(parsed) || parsed <= 0) {
11
+ throw new Error(`[Taskforce] ${name} must be a positive integer.`);
12
+ }
13
+ return parsed;
14
+ }
15
+ export function resolvePostgresWorkerDeadlines(options = {}) {
16
+ const deadlines = {
17
+ responseTimeoutMs: positiveInteger(options.responseTimeoutMs ?? DEFAULT_POSTGRES_WORKER_DEADLINES.responseTimeoutMs, 'Postgres worker response timeout'),
18
+ statementTimeoutMs: positiveInteger(options.statementTimeoutMs ?? DEFAULT_POSTGRES_WORKER_DEADLINES.statementTimeoutMs, 'Postgres statement timeout'),
19
+ connectionTimeoutMs: positiveInteger(options.connectionTimeoutMs ?? DEFAULT_POSTGRES_WORKER_DEADLINES.connectionTimeoutMs, 'Postgres connection timeout'),
20
+ idleTransactionTimeoutMs: positiveInteger(options.idleTransactionTimeoutMs ?? DEFAULT_POSTGRES_WORKER_DEADLINES.idleTransactionTimeoutMs, 'Postgres idle transaction timeout'),
21
+ };
22
+ if (deadlines.connectionTimeoutMs
23
+ + deadlines.statementTimeoutMs
24
+ + MIN_RESPONSE_MARGIN_MS
25
+ > deadlines.responseTimeoutMs) {
26
+ throw new Error('[Taskforce] Postgres connection and statement timeouts must together leave at least '
27
+ + `${MIN_RESPONSE_MARGIN_MS}ms before the worker response timeout.`);
28
+ }
29
+ return deadlines;
30
+ }
@@ -0,0 +1,31 @@
1
+ import type { DatabaseAdapter } from './databaseAdapter.js';
2
+ export interface TaskforceAgentConnectionBindingRecord {
3
+ tenantId: string;
4
+ workspaceId: string;
5
+ agentId: string;
6
+ connectionId: string;
7
+ ownerUserId: string;
8
+ providerKey: string;
9
+ modelSource: string;
10
+ createdByUserId: string;
11
+ updatedByUserId: string;
12
+ createdAt: string;
13
+ updatedAt: string;
14
+ }
15
+ export declare class TaskforceAgentConnectionBindingStore {
16
+ private readonly db;
17
+ private readonly tenantId;
18
+ private readonly now;
19
+ constructor(db: DatabaseAdapter, tenantId: string, now?: () => Date);
20
+ get(workspaceIdRaw: string, agentIdRaw: string): TaskforceAgentConnectionBindingRecord | null;
21
+ bind(input: {
22
+ workspaceId: string;
23
+ agentId: string;
24
+ connectionId: string;
25
+ ownerUserId: string;
26
+ providerKey: string;
27
+ modelSource: string;
28
+ actorUserId: string;
29
+ }): TaskforceAgentConnectionBindingRecord | null;
30
+ clear(workspaceIdRaw: string, agentIdRaw: string, ownerUserIdRaw: string): boolean;
31
+ }
@@ -0,0 +1,84 @@
1
+ function normalizeRequired(value, label) {
2
+ const normalized = String(value || '').trim();
3
+ if (!normalized)
4
+ throw new Error(`${label} is required.`);
5
+ return normalized;
6
+ }
7
+ function mapRow(row) {
8
+ return {
9
+ tenantId: String(row.tenant_id || ''),
10
+ workspaceId: String(row.workspace_id || ''),
11
+ agentId: String(row.agent_id || ''),
12
+ connectionId: String(row.connection_id || ''),
13
+ ownerUserId: String(row.owner_user_id || ''),
14
+ providerKey: String(row.provider_key || ''),
15
+ modelSource: String(row.model_source || ''),
16
+ createdByUserId: String(row.created_by_user_id || ''),
17
+ updatedByUserId: String(row.updated_by_user_id || ''),
18
+ createdAt: String(row.created_at || ''),
19
+ updatedAt: String(row.updated_at || ''),
20
+ };
21
+ }
22
+ export class TaskforceAgentConnectionBindingStore {
23
+ db;
24
+ tenantId;
25
+ now;
26
+ constructor(db, tenantId, now = () => new Date()) {
27
+ this.db = db;
28
+ this.tenantId = tenantId;
29
+ this.now = now;
30
+ }
31
+ get(workspaceIdRaw, agentIdRaw) {
32
+ const workspaceId = String(workspaceIdRaw || '').trim();
33
+ const agentId = String(agentIdRaw || '').trim();
34
+ if (!workspaceId || !agentId)
35
+ return null;
36
+ const row = this.db.prepare(`
37
+ SELECT *
38
+ FROM taskforce_agent_connection_bindings
39
+ WHERE tenant_id = ? AND workspace_id = ? AND agent_id = ?
40
+ LIMIT 1
41
+ `).get(this.tenantId, workspaceId, agentId);
42
+ return row ? mapRow(row) : null;
43
+ }
44
+ bind(input) {
45
+ const workspaceId = normalizeRequired(input.workspaceId, 'Workspace ID');
46
+ const agentId = normalizeRequired(input.agentId, 'Agent ID');
47
+ const connectionId = normalizeRequired(input.connectionId, 'Connection ID');
48
+ const ownerUserId = normalizeRequired(input.ownerUserId, 'Connection owner');
49
+ const providerKey = normalizeRequired(input.providerKey, 'Provider key');
50
+ const modelSource = normalizeRequired(input.modelSource, 'Model source');
51
+ const actorUserId = normalizeRequired(input.actorUserId, 'Actor user');
52
+ const now = this.now().toISOString();
53
+ const result = this.db.prepare(`
54
+ INSERT INTO taskforce_agent_connection_bindings (
55
+ tenant_id, workspace_id, agent_id, connection_id, owner_user_id,
56
+ provider_key, model_source, created_by_user_id, updated_by_user_id,
57
+ created_at, updated_at
58
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
59
+ ON CONFLICT (tenant_id, workspace_id, agent_id) DO UPDATE SET
60
+ connection_id = excluded.connection_id,
61
+ owner_user_id = excluded.owner_user_id,
62
+ provider_key = excluded.provider_key,
63
+ model_source = excluded.model_source,
64
+ updated_by_user_id = excluded.updated_by_user_id,
65
+ updated_at = excluded.updated_at
66
+ WHERE taskforce_agent_connection_bindings.owner_user_id = excluded.owner_user_id
67
+ `).run(this.tenantId, workspaceId, agentId, connectionId, ownerUserId, providerKey, modelSource, actorUserId, actorUserId, now, now);
68
+ if (Number(result.changes || 0) === 0)
69
+ return null;
70
+ return this.get(workspaceId, agentId);
71
+ }
72
+ clear(workspaceIdRaw, agentIdRaw, ownerUserIdRaw) {
73
+ const workspaceId = String(workspaceIdRaw || '').trim();
74
+ const agentId = String(agentIdRaw || '').trim();
75
+ const ownerUserId = String(ownerUserIdRaw || '').trim();
76
+ if (!workspaceId || !agentId || !ownerUserId)
77
+ return false;
78
+ const result = this.db.prepare(`
79
+ DELETE FROM taskforce_agent_connection_bindings
80
+ WHERE tenant_id = ? AND workspace_id = ? AND agent_id = ? AND owner_user_id = ?
81
+ `).run(this.tenantId, workspaceId, agentId, ownerUserId);
82
+ return Number(result.changes || 0) > 0;
83
+ }
84
+ }
@@ -23,10 +23,13 @@ export type WorkspaceContentRequest = Pick<WorkspaceContentManifestEntry, 'kind'
23
23
  kind: 'asset';
24
24
  assetId: string;
25
25
  };
26
+ export type WorkspaceContentMissingRequest = WorkspaceContentRequest & {
27
+ disposition?: 'retryable' | 'terminal-unavailable';
28
+ };
26
29
  export interface WorkspaceContentPullResponse {
27
30
  success?: boolean;
28
31
  changes?: WorkspaceSyncChange[];
29
- missing?: WorkspaceContentRequest[];
32
+ missing?: WorkspaceContentMissingRequest[];
30
33
  remaining?: WorkspaceContentRequest[];
31
34
  contentMetadata?: Array<{
32
35
  kind: 'document' | 'asset';
@@ -1,4 +1,4 @@
1
- import { partitionWorkspaceSyncV2LegacyChanges } from './v3/workspaceSyncV2ProjectionExclusions.js';
1
+ import { normalizeWorkspaceSyncV2ProjectionExclusions, partitionWorkspaceSyncV2LegacyChanges, } from './v3/workspaceSyncV2ProjectionExclusions.js';
2
2
  import { validateWorkspaceSyncEngineTransferCompletionGroup, } from './engine/workspaceSyncEngineTransferCompletion.js';
3
3
  import { WORKSPACE_SYNC_V3_COMBINED_COVERAGE_SELECTOR, resolveWorkspaceSyncV3CombinedCoverageForExclusions, resolveWorkspaceSyncV3CombinedWireContract } from './v3/workspaceSyncV3CombinedWireContract.js';
4
4
  const WORKSPACE_PULL_TIMEOUT_MS = 45_000;
@@ -696,12 +696,17 @@ export async function bootstrapPushWorkspaceSnapshot(resolveCloudAuthUrl, input)
696
696
  }));
697
697
  }
698
698
  export async function applyLocalWorkspaceChanges(workspaceId, changes, options) {
699
+ const excludedProjections = normalizeWorkspaceSyncV2ProjectionExclusions(options?.excludedProjections || []);
700
+ const combinedCoverage = excludedProjections.length
701
+ ? resolveWorkspaceSyncV3CombinedCoverageForExclusions(excludedProjections)
702
+ : null;
699
703
  const applyPayload = JSON.stringify({
700
704
  workspaceId,
701
705
  changes,
702
706
  workspaceMembers: Array.isArray(options?.workspaceMembers) ? options.workspaceMembers : undefined,
703
707
  ...(options?.repairMode === true ? { repair: true } : {}),
704
- excludedProjections: options?.excludedProjections,
708
+ excludedProjections,
709
+ ...(combinedCoverage ? { combinedCoverage } : {}),
705
710
  contentPullObligations: options?.contentPullObligations,
706
711
  contentPullResolutionClaims: options?.contentPullResolutionClaims,
707
712
  ...localBrowserApplyPermitContext(workspaceId, options),
@@ -130,7 +130,7 @@ export declare function createContentSyncState(deps: ContentSyncStateDeps): {
130
130
  activeLinks: WorkspaceAssetLinkEntry[];
131
131
  effectiveUpdatedAt: string;
132
132
  };
133
- getCanonicalSyncDocumentMetadata: (relativePath: string, workspaceId: string) => Omit<DocumentSyncPayload, "path" | "updatedAt" | "content">;
133
+ getCanonicalSyncDocumentMetadata: (relativePath: string, workspaceId: string) => Omit<DocumentSyncPayload, "updatedAt" | "path" | "content">;
134
134
  hasDocumentSyncMetadataDrift: (workspaceId: string, doc: DocumentSyncPayload, _options?: {
135
135
  allowReferenceNumberReassignment?: boolean;
136
136
  }) => boolean;
@@ -152,6 +152,7 @@ export declare class LocalSyncExecutionPermitStore {
152
152
  coordinatorGeneration: number;
153
153
  serverInstanceId: string;
154
154
  errorCode?: string;
155
+ readResponseUnavailableBeforeApply?: boolean;
155
156
  }): LocalSyncExecutionPermit;
156
157
  recoverExpiredPermits(input: {
157
158
  currentServerInstanceId: string;
@@ -1,4 +1,4 @@
1
- import { randomUUID } from 'crypto';
1
+ import { createHash, randomUUID } from 'crypto';
2
2
  import { assertSynchronousTransactionResult, } from '../../storage/databaseAdapter.js';
3
3
  import { validateWorkspaceSyncEngineTransferCompletionGroup, } from '../engine/workspaceSyncEngineTransferCompletion.js';
4
4
  import { canonicalWorkspaceSyncJson } from '../v3/canonicalWorkspaceSyncJson.js';
@@ -619,9 +619,15 @@ export class LocalSyncExecutionPermitStore {
619
619
  if (current.state === 'local-commit-entered') {
620
620
  throw new LocalSyncExecutionPermitError(`Execution permit ${input.permitId} is owned by the server local commit.`, 'SYNC_COORDINATOR_PERMIT_STATE_CONFLICT');
621
621
  }
622
+ const cleanReadFailure = input.readResponseUnavailableBeforeApply === true
623
+ && input.errorCode === 'SYNC_COORDINATOR_GATEWAY_REQUEST_FAILED'
624
+ && current.state === 'gateway-complete-awaiting-apply'
625
+ && current.upstreamDisposition === 'unknown'
626
+ && (current.operationClass === 'pull' || current.operationClass === 'repair');
622
627
  const clean = current.state === 'issued-idle'
623
628
  || (current.state === 'gateway-complete-awaiting-apply'
624
- && current.upstreamDisposition === 'rejected');
629
+ && current.upstreamDisposition === 'rejected')
630
+ || cleanReadFailure;
625
631
  const disposition = current.upstreamDisposition === 'accepted'
626
632
  ? 'accepted'
627
633
  : current.upstreamDisposition === 'rejected'
@@ -1401,36 +1407,67 @@ export class LocalSyncExecutionPermitStore {
1401
1407
  const requiredAction = mutationReplay
1402
1408
  ? 'replay-operation-then-reconcile'
1403
1409
  : 'refetch-from-committed-cursor';
1404
- const coalescesRepeatedApplyFailure = errorCode === 'WORKSPACE_SYNC_V3_APPLY_NOT_COMMITTED'
1410
+ const coalescesLegacyApplyFailure = errorCode === 'WORKSPACE_SYNC_V3_APPLY_NOT_COMMITTED'
1405
1411
  || errorCode === 'WORKSPACE_SYNC_V3_ATTACHMENT_HYDRATION_NOT_COMMITTED';
1406
- if (coalescesRepeatedApplyFailure) {
1407
- const committedBoundary = canonicalWorkspaceSyncJson(permit.lastCommittedCursor);
1408
- const equivalentOpenObligation = this.db.prepare(`
1409
- SELECT obligation.*
1410
- FROM local_sync_recovery_obligations AS obligation
1411
- INNER JOIN local_sync_execution_permits AS origin
1412
- ON origin.permit_id = obligation.permit_id
1413
- WHERE obligation.workspace_id = ?
1414
- AND obligation.operation_class = ?
1415
- AND obligation.upstream_disposition = ?
1416
- AND obligation.required_action = ?
1417
- AND obligation.resolved_at IS NULL
1418
- AND origin.error_code = ?
1419
- ORDER BY obligation.created_at ASC
1420
- `).all(permit.workspaceId, permit.operationClass, disposition, requiredAction, errorCode).map(mapObligation).some((obligation) => ((obligation.operationIdentity || null) === (permit.operationIdentity || null)
1421
- && canonicalWorkspaceSyncJson(obligation.lastCommittedCursor) === committedBoundary));
1422
- if (equivalentOpenObligation)
1423
- return;
1412
+ const coalescingKey = mutationReplay || coalescesLegacyApplyFailure
1413
+ ? createHash('sha256').update(canonicalWorkspaceSyncJson(mutationReplay ? {
1414
+ workspaceId: permit.workspaceId,
1415
+ operationClass: permit.operationClass,
1416
+ operationIdentity: permit.operationIdentity || null,
1417
+ lastCommittedCursor: permit.lastCommittedCursor,
1418
+ requiredAction,
1419
+ } : {
1420
+ workspaceId: permit.workspaceId,
1421
+ operationClass: permit.operationClass,
1422
+ operationIdentity: permit.operationIdentity || null,
1423
+ upstreamDisposition: disposition,
1424
+ lastCommittedCursor: permit.lastCommittedCursor,
1425
+ requiredAction,
1426
+ errorCode,
1427
+ })).digest('hex')
1428
+ : null;
1429
+ // This store method normally runs inside the permit transition
1430
+ // transaction. The nested transaction gives PostgreSQL a savepoint
1431
+ // boundary while the partial unique index arbitrates concurrent
1432
+ // equivalent inserts without poisoning the outer transaction.
1433
+ let inserted = false;
1434
+ try {
1435
+ this.db.transaction(() => {
1436
+ this.db.prepare(`
1437
+ INSERT INTO local_sync_recovery_obligations (
1438
+ obligation_id, permit_id, workspace_id, operation_class,
1439
+ operation_identity, upstream_disposition,
1440
+ last_committed_cursor_json, required_action, coalescing_key,
1441
+ created_at, resolved_at
1442
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)
1443
+ `).run(this.createId(), permit.permitId, permit.workspaceId, permit.operationClass, permit.operationIdentity, disposition, permit.lastCommittedCursor === null
1444
+ ? null
1445
+ : JSON.stringify(permit.lastCommittedCursor), requiredAction, coalescingKey, this.now());
1446
+ inserted = true;
1447
+ })();
1448
+ }
1449
+ catch (error) {
1450
+ const existing = coalescingKey
1451
+ ? this.db.prepare(`
1452
+ SELECT obligation_id
1453
+ FROM local_sync_recovery_obligations
1454
+ WHERE coalescing_key = ? AND resolved_at IS NULL
1455
+ `).get(coalescingKey)
1456
+ : undefined;
1457
+ if (!existing?.obligation_id)
1458
+ throw error;
1424
1459
  }
1460
+ if (inserted || !coalescingKey)
1461
+ return;
1425
1462
  this.db.prepare(`
1426
- INSERT INTO local_sync_recovery_obligations (
1427
- obligation_id, permit_id, workspace_id, operation_class,
1428
- operation_identity, upstream_disposition, last_committed_cursor_json,
1429
- required_action, created_at, resolved_at
1430
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)
1431
- ON CONFLICT (permit_id) DO NOTHING
1432
- `).run(this.createId(), permit.permitId, permit.workspaceId, permit.operationClass, permit.operationIdentity, disposition, permit.lastCommittedCursor === null
1433
- ? null
1434
- : JSON.stringify(permit.lastCommittedCursor), requiredAction, this.now());
1463
+ UPDATE local_sync_recovery_obligations
1464
+ SET upstream_disposition = CASE
1465
+ WHEN upstream_disposition = 'accepted' OR ? = 'accepted' THEN 'accepted'
1466
+ WHEN upstream_disposition = 'unknown' OR ? = 'unknown' THEN 'unknown'
1467
+ WHEN upstream_disposition = 'rejected' OR ? = 'rejected' THEN 'rejected'
1468
+ ELSE upstream_disposition
1469
+ END
1470
+ WHERE coalescing_key = ? AND resolved_at IS NULL
1471
+ `).run(disposition, disposition, disposition, coalescingKey);
1435
1472
  }
1436
1473
  }
@@ -0,0 +1,10 @@
1
+ import type { LocalWorkspaceSyncPendingV2Push } from './localWorkspaceSyncRunnerState.js';
2
+ export interface LocalWorkspaceSyncPendingV2PushProgress {
3
+ effectiveTotalBatches: number;
4
+ settledBatches: number;
5
+ effectiveTotalChanges: number;
6
+ settledChanges: number;
7
+ remainingChanges: number;
8
+ firstUnsettledBatchIndex: number | null;
9
+ }
10
+ export declare function resolveLocalWorkspaceSyncPendingV2PushProgress(pending: LocalWorkspaceSyncPendingV2Push | null | undefined): LocalWorkspaceSyncPendingV2PushProgress | null;
@@ -0,0 +1,29 @@
1
+ export function resolveLocalWorkspaceSyncPendingV2PushProgress(pending) {
2
+ const plan = pending?.preparedPlan;
3
+ const settledIdentities = pending?.settledBatchOperationIdentities;
4
+ if (pending?.settlementVersion !== 1
5
+ || !plan
6
+ || !Array.isArray(settledIdentities)
7
+ || plan.batches.length !== plan.batchOperationIdentities.length
8
+ || new Set(plan.batchOperationIdentities).size !== plan.batchOperationIdentities.length
9
+ || new Set(settledIdentities).size !== settledIdentities.length
10
+ || settledIdentities.some((identity) => !plan.batchOperationIdentities.includes(identity))) {
11
+ return null;
12
+ }
13
+ const settled = new Set(settledIdentities);
14
+ const effectiveTotalChanges = plan.batches.reduce((total, batch) => total + batch.length, 0);
15
+ const settledChanges = plan.batches.reduce((total, batch, index) => (settled.has(plan.batchOperationIdentities[index])
16
+ ? total + batch.length
17
+ : total), 0);
18
+ const firstUnsettledBatchIndex = plan.batchOperationIdentities.findIndex((identity) => !settled.has(identity));
19
+ return {
20
+ effectiveTotalBatches: plan.batches.length,
21
+ settledBatches: settled.size,
22
+ effectiveTotalChanges,
23
+ settledChanges,
24
+ remainingChanges: effectiveTotalChanges - settledChanges,
25
+ firstUnsettledBatchIndex: firstUnsettledBatchIndex < 0
26
+ ? null
27
+ : firstUnsettledBatchIndex,
28
+ };
29
+ }