@taskforcehq/taskforce 0.3.327 → 0.3.329

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. package/dist/Taskforce.module.css +257 -87
  2. package/dist/TaskforceCore.js +237 -230
  3. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
  4. package/dist/cli.js +34 -0
  5. package/dist/cliCloudTargetGuard.d.ts +5 -0
  6. package/dist/cliCloudTargetGuard.js +11 -0
  7. package/dist/components/activity/EntityActivityTimeline.js +15 -5
  8. package/dist/components/context/AttachmentPreviewHost.js +1 -1
  9. package/dist/components/context/ContextAttachmentManager.d.ts +3 -0
  10. package/dist/components/context/ContextAttachmentManager.js +116 -20
  11. package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
  12. package/dist/components/features/TaskSettings.d.ts +12 -1
  13. package/dist/components/features/TaskSettings.js +147 -40
  14. package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
  15. package/dist/components/features/planning/PlanningEntitySummary.d.ts +3 -1
  16. package/dist/components/features/planning/PlanningEntitySummary.js +3 -2
  17. package/dist/components/features/planning/PlanningLinkPicker.d.ts +3 -1
  18. package/dist/components/features/planning/PlanningLinkPicker.js +5 -3
  19. package/dist/components/features/planning/PlanningModule.js +28 -14
  20. package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
  21. package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
  22. package/dist/components/features/planning/PlanningVisualIdentity.d.ts +14 -0
  23. package/dist/components/features/planning/PlanningVisualIdentity.js +106 -0
  24. package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
  25. package/dist/components/features/planning/planningTaskArrangement.js +5 -5
  26. package/dist/components/features/planning/planningWorkspaceModel.d.ts +11 -0
  27. package/dist/components/features/taskforceAgentEditorModel.js +3 -1
  28. package/dist/components/task/TaskActionHeader.d.ts +2 -1
  29. package/dist/components/task/TaskActionHeader.js +2 -2
  30. package/dist/components/task/TaskCard.d.ts +5 -0
  31. package/dist/components/task/TaskCard.js +101 -13
  32. package/dist/components/task/TaskContextUpload.d.ts +3 -0
  33. package/dist/components/task/TaskContextUpload.js +2 -2
  34. package/dist/components/task/TaskForm.d.ts +4 -0
  35. package/dist/components/task/TaskForm.js +32 -7
  36. package/dist/components/task/TaskImageReviews.js +28 -19
  37. package/dist/components/task/TaskKanban.d.ts +6 -1
  38. package/dist/components/task/TaskKanban.js +152 -6
  39. package/dist/components/task/TaskList.d.ts +5 -0
  40. package/dist/components/task/TaskList.js +3 -3
  41. package/dist/components/task/TaskStatusActions.js +11 -2
  42. package/dist/components/task/TaskWorkstreamPicker.js +2 -1
  43. package/dist/components/ui/DocumentTypeIcon.d.ts +7 -0
  44. package/dist/components/ui/DocumentTypeIcon.js +8 -0
  45. package/dist/components/ui/PasswordInput.d.ts +6 -0
  46. package/dist/components/ui/PasswordInput.js +11 -0
  47. package/dist/components/ui/TaxonomyDropdown.d.ts +9 -1
  48. package/dist/components/ui/TaxonomyDropdown.js +30 -3
  49. package/dist/components/ui/TopNoticeLayer.js +1 -1
  50. package/dist/components/views/AppShellHeader.js +32 -11
  51. package/dist/components/views/PlanComparisonPage.js +12 -0
  52. package/dist/components/views/StandaloneLayout.js +68 -39
  53. package/dist/components/views/WidgetView.js +10 -7
  54. package/dist/components/views/panels/PlanningDrawer.d.ts +7 -1
  55. package/dist/components/views/panels/PlanningDrawer.js +51 -54
  56. package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
  57. package/dist/config/envSchema.js +13 -0
  58. package/dist/config/localServiceCloudTarget.d.ts +10 -0
  59. package/dist/config/localServiceCloudTarget.js +76 -0
  60. package/dist/config/localServiceRuntimeContract.d.ts +13 -0
  61. package/dist/config/localServiceRuntimeContract.js +135 -0
  62. package/dist/core/AiProfileService.d.ts +1 -0
  63. package/dist/core/AiProfileService.js +48 -9
  64. package/dist/core/AttachmentLinkService.js +7 -4
  65. package/dist/core/DeletedTaskLifecycleService.d.ts +5 -0
  66. package/dist/core/DeletedTaskLifecycleService.js +55 -3
  67. package/dist/core/McpTokenService.d.ts +4 -0
  68. package/dist/core/McpTokenService.js +52 -0
  69. package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +8 -2
  70. package/dist/core/TaskAttachmentLinksDurableMutationService.js +51 -18
  71. package/dist/core/Taskforce.d.ts +124 -2
  72. package/dist/core/Taskforce.js +1175 -87
  73. package/dist/core/types.d.ts +8 -1
  74. package/dist/documentReviews/DocumentReviewCommentStore.d.ts +11 -0
  75. package/dist/documentReviews/DocumentReviewCommentStore.js +35 -2
  76. package/dist/documentReviews/service.d.ts +4 -0
  77. package/dist/documentReviews/service.js +141 -46
  78. package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
  79. package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
  80. package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
  81. package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
  82. package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
  83. package/dist/hooks/tasks/taskHttpMutation.js +1 -0
  84. package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
  85. package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
  86. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
  87. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
  88. package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
  89. package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
  90. package/dist/hooks/tasks/useTaskFormActions.d.ts +9 -0
  91. package/dist/hooks/tasks/useTaskFormActions.js +96 -17
  92. package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
  93. package/dist/hooks/ui/useSettingsModel.js +13 -2
  94. package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
  95. package/dist/hooks/ui/useSettingsPersistence.js +74 -47
  96. package/dist/hooks/useFilterSort.d.ts +7 -3
  97. package/dist/hooks/useFilterSort.js +15 -5
  98. package/dist/hooks/useTaskData.d.ts +10 -1
  99. package/dist/hooks/useTaskData.js +216 -7
  100. package/dist/hooks/useTaskMutations.d.ts +10 -2
  101. package/dist/hooks/useTaskMutations.js +223 -43
  102. package/dist/hooks/useTaskforce.d.ts +94 -57
  103. package/dist/hooks/useTaskforce.js +428 -16
  104. package/dist/hooks/useUiNotice.d.ts +4 -0
  105. package/dist/hooks/useUiNotice.js +4 -0
  106. package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
  107. package/dist/mcp/canonicalAssetHelpers.d.ts +13 -0
  108. package/dist/mcp/canonicalAssetHelpers.js +39 -5
  109. package/dist/mcp/collaborationRegistrar.js +15 -13
  110. package/dist/mcp/documentAssetRegistrar.js +60 -44
  111. package/dist/mcp/documentHelpers.d.ts +1 -0
  112. package/dist/mcp/documentHelpers.js +7 -3
  113. package/dist/mcp/localServiceProxy.js +4 -1
  114. package/dist/mcp/runtime.d.ts +16 -0
  115. package/dist/mcp/runtime.js +735 -210
  116. package/dist/mcp/taskAttachmentCommandAdapter.d.ts +2 -0
  117. package/dist/mcp/taskAttachmentCommandAdapter.js +14 -8
  118. package/dist/mcp/taskPlanningRegistrar.js +78 -67
  119. package/dist/mcp/toolCallCompatibility.js +38 -1
  120. package/dist/mcp/toolCatalog.d.ts +1 -0
  121. package/dist/mcp/toolRegistry.js +2 -2
  122. package/dist/migrations/taskSchemaMigrations.js +47 -0
  123. package/dist/runtime/appGateDefinitions.d.ts +30 -6
  124. package/dist/runtime/appGateDefinitions.js +6 -6
  125. package/dist/runtime/appGates.d.ts +12 -13
  126. package/dist/runtime/appGates.js +29 -13
  127. package/dist/runtime/nodeAppGates.d.ts +8 -0
  128. package/dist/runtime/nodeAppGates.js +27 -0
  129. package/dist/server/appAccess.d.ts +12 -0
  130. package/dist/server/appAccess.js +21 -0
  131. package/dist/server/authorizedWorkspaceAccess.d.ts +12 -0
  132. package/dist/server/authorizedWorkspaceAccess.js +40 -0
  133. package/dist/server/cloudCollectionRead.d.ts +25 -0
  134. package/dist/server/cloudCollectionRead.js +120 -0
  135. package/dist/server/cloudCollectionReadPool.d.ts +52 -0
  136. package/dist/server/cloudCollectionReadPool.js +140 -0
  137. package/dist/server/cloudCollectionReadWorker.d.ts +1 -0
  138. package/dist/server/cloudCollectionReadWorker.js +36 -0
  139. package/dist/server/index.d.ts +6 -11
  140. package/dist/server/index.js +67 -42
  141. package/dist/server/localServiceLease.d.ts +6 -0
  142. package/dist/server/localServiceLease.js +17 -1
  143. package/dist/server/localWorkspaceSyncServerRuntime.js +10 -3
  144. package/dist/server/rateLimit.d.ts +1 -0
  145. package/dist/server/rateLimit.js +4 -0
  146. package/dist/server/realtimeSyncWs.js +36 -12
  147. package/dist/server/routes/admin.js +1 -0
  148. package/dist/server/routes/agentRoles.js +3 -2
  149. package/dist/server/routes/agentSkills.js +3 -2
  150. package/dist/server/routes/agents.js +118 -16
  151. package/dist/server/routes/annotatedAttachments.js +3 -2
  152. package/dist/server/routes/auth.js +3 -1
  153. package/dist/server/routes/documents.d.ts +5 -2
  154. package/dist/server/routes/documents.js +160 -13
  155. package/dist/server/routes/durableTaskHttpRouters.d.ts +11 -2
  156. package/dist/server/routes/durableTaskHttpRouters.js +2 -2
  157. package/dist/server/routes/localService.js +4 -0
  158. package/dist/server/routes/primitives.d.ts +4 -0
  159. package/dist/server/routes/shared.d.ts +24 -0
  160. package/dist/server/routes/shared.js +114 -18
  161. package/dist/server/routes/sync.js +22 -0
  162. package/dist/server/routes/syncAuxRoutes.js +5 -2
  163. package/dist/server/routes/syncPullApplyRoutes.js +23 -4
  164. package/dist/server/routes/syncV3FeedRoutes.js +22 -18
  165. package/dist/server/routes/syncV3LocalCaptureRoutes.js +48 -4
  166. package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
  167. package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
  168. package/dist/server/routes/syncV3OperationRoutes.js +27 -2
  169. package/dist/server/routes/tasks.js +299 -97
  170. package/dist/server/routes/workspaces.js +43 -1
  171. package/dist/server/routes.js +35 -7
  172. package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
  173. package/dist/server/workspaceDeletionAdmission.js +50 -0
  174. package/dist/service/localServiceCli.js +52 -25
  175. package/dist/service/localServiceClientLifecycle.js +93 -6
  176. package/dist/services/codexAppServerModelGateway.d.ts +112 -0
  177. package/dist/services/codexAppServerModelGateway.js +438 -0
  178. package/dist/services/taskforceAgentMcpBridge.d.ts +7 -1
  179. package/dist/services/taskforceAgentMcpBridge.js +23 -3
  180. package/dist/shared/planningIdentity.d.ts +20 -0
  181. package/dist/shared/planningIdentity.js +79 -0
  182. package/dist/shared/taskforceAgentDefinition.js +7 -1
  183. package/dist/shared/taskforceAgentModels.d.ts +1 -0
  184. package/dist/shared/taskforceAgentModels.js +30 -1
  185. package/dist/storage/postgresAdapter.d.ts +20 -3
  186. package/dist/storage/postgresAdapter.js +110 -14
  187. package/dist/storage/postgresRequestDiagnostics.d.ts +8 -0
  188. package/dist/storage/postgresRequestDiagnostics.js +24 -0
  189. package/dist/storage/postgresWorker.js +13 -4
  190. package/dist/storage/postgresWorkerProtocol.d.ts +29 -0
  191. package/dist/storage/postgresWorkerProtocol.js +30 -0
  192. package/dist/storage/workspaceAssetStore.d.ts +32 -0
  193. package/dist/storage/workspaceAssetStore.js +70 -0
  194. package/dist/sync/cloudSyncApi.d.ts +4 -1
  195. package/dist/sync/cloudSyncApi.js +7 -2
  196. package/dist/sync/contentSyncState.d.ts +1 -1
  197. package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +17 -0
  198. package/dist/sync/coordinator/localSyncExecutionPermitStore.js +77 -23
  199. package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
  200. package/dist/sync/coordinator/workspaceSyncTransportGateway.js +4 -2
  201. package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
  202. package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
  203. package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
  204. package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +16 -0
  205. package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
  206. package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.d.ts +1 -1
  207. package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +46 -4
  208. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
  209. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +51 -11
  210. package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
  211. package/dist/sync/engine/workspaceSyncEngineTransfers.js +8 -3
  212. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +2 -0
  213. package/dist/sync/syncApplyHandlers.d.ts +3 -1
  214. package/dist/sync/syncApplyHandlers.js +29 -0
  215. package/dist/sync/syncService.d.ts +2 -0
  216. package/dist/sync/syncService.js +13 -1
  217. package/dist/sync/taskSyncPayload.d.ts +1 -0
  218. package/dist/sync/taskSyncPayload.js +6 -0
  219. package/dist/sync/v3/combinedFeedCapability.js +4 -0
  220. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +3 -0
  221. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +31 -3
  222. package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -0
  223. package/dist/sync/v3/durableTaskChecklistMutationRouter.js +4 -0
  224. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
  225. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +47 -12
  226. package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
  227. package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +27 -2
  228. package/dist/sync/v3/localInitiativeOutboxService.js +4 -2
  229. package/dist/sync/v3/localOutboxDispatcher.js +5 -1
  230. package/dist/sync/v3/localTaskAttachmentLinksOutboxHandler.js +12 -2
  231. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +3 -0
  232. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +62 -10
  233. package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
  234. package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
  235. package/dist/sync/v3/localTaskMetadataClient.js +1 -0
  236. package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
  237. package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
  238. package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
  239. package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
  240. package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
  241. package/dist/sync/v3/localTaskStatusClient.js +6 -1
  242. package/dist/sync/v3/localTaskStatusOutboxService.d.ts +2 -0
  243. package/dist/sync/v3/localTaskStatusOutboxService.js +54 -13
  244. package/dist/sync/v3/localWorkstreamOutboxService.js +4 -2
  245. package/dist/sync/v3/syncDurabilityStore.d.ts +15 -0
  246. package/dist/sync/v3/syncDurabilityStore.js +201 -43
  247. package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +7 -4
  248. package/dist/sync/v3/taskAttachmentLinksMutationService.js +37 -12
  249. package/dist/sync/v3/taskChecklistMutationService.d.ts +4 -2
  250. package/dist/sync/v3/taskChecklistMutationService.js +4 -0
  251. package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
  252. package/dist/sync/v3/taskCreateMutationService.js +7 -4
  253. package/dist/sync/v3/taskMetadataCoexistence.js +4 -0
  254. package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
  255. package/dist/sync/v3/taskMetadataMutationService.js +4 -0
  256. package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
  257. package/dist/sync/v3/taskRestoreMutationService.js +7 -4
  258. package/dist/sync/v3/taskStatusMutationService.d.ts +2 -0
  259. package/dist/sync/v3/taskStatusMutationService.js +4 -0
  260. package/dist/sync/v3/workflowAssignmentSync.d.ts +1 -0
  261. package/dist/sync/v3/workflowAssignmentSync.js +3 -0
  262. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
  263. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +14 -12
  264. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
  265. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
  266. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
  267. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
  268. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +10 -1
  269. package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +15 -4
  270. package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +66 -13
  271. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +11 -0
  272. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +57 -22
  273. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +10 -4
  274. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +124 -51
  275. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
  276. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +120 -28
  277. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +3 -1
  278. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +18 -0
  279. package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
  280. package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
  281. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
  282. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
  283. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
  284. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
  285. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
  286. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
  287. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
  288. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
  289. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
  290. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
  291. package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +3 -0
  292. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +2 -0
  293. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +19 -7
  294. package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.d.ts +2 -0
  295. package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.js +10 -0
  296. package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
  297. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
  298. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
  299. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
  300. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
  301. package/dist/sync/v3/workspaceSyncV3TaskRootProjection.d.ts +1 -1
  302. package/dist/sync/v3/workspaceSyncV3TaskRootProjection.js +1 -1
  303. package/dist/sync/workspacePullFeed.d.ts +6 -1
  304. package/dist/sync/workspacePullFeed.js +174 -162
  305. package/dist/sync/workspaceRepair.d.ts +3 -0
  306. package/dist/sync/workspaceRepair.js +67 -6
  307. package/dist/sync/workspaceSyncModel.d.ts +11 -0
  308. package/dist/sync/workspaceSyncModel.js +27 -2
  309. package/dist/types.d.ts +55 -1
  310. package/dist/types.js +6 -0
  311. package/dist/ui/assets/{AiIdentityRosterCard-DB1BLO_j.js → AiIdentityRosterCard-BZM4aQnM.js} +1 -1
  312. package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +1 -0
  313. package/dist/ui/assets/AnnotatedAttachmentWorkspace-B68Wg-RV.js +3 -0
  314. package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
  315. package/dist/ui/assets/AssetTraySortControl-C8Rztyal.js +1 -0
  316. package/dist/ui/assets/ContextAttachmentManager-Cj3c7X9y.js +3 -0
  317. package/dist/ui/assets/{DocumentWorkspace-BC7sy5TG.js → DocumentWorkspace-B5uvzems.js} +4 -4
  318. package/dist/ui/assets/EntityActivityTimeline-BVFvCB5R.js +1 -0
  319. package/dist/ui/assets/PlanningModule-B5DWQOGz.js +1 -0
  320. package/dist/ui/assets/PlanningModule-CoIR9hbV.css +1 -0
  321. package/dist/ui/assets/PlansPage-AY4cGWco.js +1 -0
  322. package/dist/ui/assets/TaskContextUpload-DZxTVesW.js +1 -0
  323. package/dist/ui/assets/TaskContextUpload-qmBeUw3u.css +1 -0
  324. package/dist/ui/assets/TaskSettings-BeWAuyZj.js +12 -0
  325. package/dist/ui/assets/{TaskforceAgentsModule-CkAxW19K.js → TaskforceAgentsModule-BifCYtjR.js} +6 -6
  326. package/dist/ui/assets/WorkflowManagerModule-DEr5di_r.js +1 -0
  327. package/dist/ui/assets/index-I5zhdtgt.js +7 -0
  328. package/dist/ui/assets/index-VRFsx3wz.css +1 -0
  329. package/dist/ui/assets/{vendor-icons-B8ZNsH1g.js → vendor-icons-D9Lpw-j4.js} +1 -1
  330. package/dist/ui/index.html +3 -3
  331. package/dist/utils/constants.d.ts +2 -2
  332. package/dist/utils/constants.js +1 -1
  333. package/dist/utils/contextAttachmentUpload.d.ts +2 -0
  334. package/dist/utils/contextAttachmentUpload.js +7 -0
  335. package/dist/utils/contextFiles.d.ts +1 -1
  336. package/dist/utils/contextFiles.js +4 -4
  337. package/dist/utils/taskActivity.d.ts +3 -2
  338. package/dist/utils/taskActivity.js +19 -2
  339. package/dist/utils/taskEditorReconciliation.d.ts +40 -0
  340. package/dist/utils/taskEditorReconciliation.js +217 -0
  341. package/dist/utils/taskNormalization.d.ts +1 -0
  342. package/dist/utils/taskNormalization.js +39 -0
  343. package/dist/utils/taskSearch.js +2 -2
  344. package/dist/utils/uiNotice.d.ts +4 -0
  345. package/package.json +21 -4
  346. package/dist/ui/assets/AiProfilesModule-DPxQeF9N.js +0 -1
  347. package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
  348. package/dist/ui/assets/AnnotatedAttachmentWorkspace-DHNYaNg6.js +0 -3
  349. package/dist/ui/assets/AssetTraySortControl-DphbyHVc.js +0 -1
  350. package/dist/ui/assets/ContextAttachmentManager-CMxSzHqc.js +0 -3
  351. package/dist/ui/assets/EntityActivityTimeline-pJ2ZjZ-k.js +0 -1
  352. package/dist/ui/assets/PlanningModule-CeTqXMMz.css +0 -1
  353. package/dist/ui/assets/PlanningModule-t5GbvVR9.js +0 -1
  354. package/dist/ui/assets/PlansPage-BVH_NfgT.js +0 -1
  355. package/dist/ui/assets/TaskContextUpload-Ds4LnDzV.css +0 -1
  356. package/dist/ui/assets/TaskContextUpload-bl4fOOUz.js +0 -1
  357. package/dist/ui/assets/TaskSettings-xVsxSa0g.js +0 -12
  358. package/dist/ui/assets/WorkflowManagerModule-BKqIGVnF.js +0 -1
  359. package/dist/ui/assets/index-BzJlVnNS.css +0 -1
  360. package/dist/ui/assets/index-Cx7vZJHL.js +0 -7
@@ -21,6 +21,8 @@ const NON_APPLYING_OPERATION_CLASSES = new Set([
21
21
  const MAX_DRAIN_INSPECTION_LIMIT = 500;
22
22
  export const LOCAL_SYNC_PERMIT_RETENTION_MIN_AGE_MS = 7 * 24 * 60 * 60 * 1000;
23
23
  export const LOCAL_SYNC_PERMIT_RETENTION_SOFT_LIMIT = 1_000;
24
+ export const LOCAL_SYNC_PERMIT_RETENTION_HARD_LIMIT = 10_000;
25
+ export const LOCAL_SYNC_OBLIGATION_RETENTION_HARD_LIMIT = 2_000;
24
26
  export const LOCAL_SYNC_PERMIT_RETENTION_DELETE_BATCH = 250;
25
27
  export const LOCAL_SYNC_PERMIT_RETENTION_SWEEP_LIMIT = 5_000;
26
28
  const LOCAL_SYNC_PERMIT_RETENTION_CHECK_INTERVAL_MS = 60 * 60 * 1000;
@@ -166,11 +168,29 @@ export class LocalSyncExecutionPermitStore {
166
168
  FROM local_sync_recovery_obligations
167
169
  WHERE workspace_id = ? AND resolved_at IS NULL
168
170
  `).get(workspaceId);
171
+ const terminalHistory = this.db.prepare(`
172
+ SELECT COUNT(*) AS count, MIN(completed_at) AS oldest_at
173
+ FROM local_sync_execution_permits
174
+ WHERE workspace_id = ?
175
+ AND state IN ('released', 'abandoned-clean', 'abandoned-reconcile-required')
176
+ AND completed_at IS NOT NULL
177
+ `).get(workspaceId);
178
+ const resolvedHistory = this.db.prepare(`
179
+ SELECT COUNT(*) AS count, MIN(resolved_at) AS oldest_at
180
+ FROM local_sync_recovery_obligations
181
+ WHERE workspace_id = ? AND resolved_at IS NOT NULL
182
+ `).get(workspaceId);
169
183
  return {
170
184
  active,
171
185
  byState,
172
186
  recoveryObligations: Number(obligation?.count || 0),
173
187
  localCommitInvariantViolation: this.invariantBlockedWorkspaces.has(workspaceId),
188
+ history: {
189
+ terminalPermits: Number(terminalHistory?.count || 0),
190
+ oldestTerminalPermitAt: terminalHistory?.oldest_at || null,
191
+ resolvedRecoveryObligations: Number(resolvedHistory?.count || 0),
192
+ oldestResolvedRecoveryObligationAt: resolvedHistory?.oldest_at || null,
193
+ },
174
194
  };
175
195
  }
176
196
  inspectGenerationDrain(input) {
@@ -417,6 +437,42 @@ export class LocalSyncExecutionPermitStore {
417
437
  });
418
438
  })();
419
439
  }
440
+ renewAcceptedApplyCompletion(input) {
441
+ return this.db.transaction(() => {
442
+ const current = this.requirePermit(input.permitId);
443
+ this.assertFence(current, input);
444
+ if (current.ownerMode !== input.ownerMode) {
445
+ throw new LocalSyncExecutionPermitError(`Execution permit ${input.permitId} belongs to ${current.ownerMode}, not ${input.ownerMode}.`, 'SYNC_COORDINATOR_PERMIT_IDENTITY_CONFLICT');
446
+ }
447
+ if (current.state !== 'gateway-complete-awaiting-apply'
448
+ || current.upstreamDisposition !== 'accepted') {
449
+ throw new LocalSyncExecutionPermitError(`Execution permit ${input.permitId} has no accepted apply completion to renew.`, 'SYNC_COORDINATOR_PERMIT_STATE_CONFLICT');
450
+ }
451
+ const now = this.now();
452
+ const deadlineMs = Date.parse(input.deadlineAt);
453
+ if (!Number.isFinite(deadlineMs)
454
+ || deadlineMs <= Date.parse(now)
455
+ || deadlineMs <= Date.parse(current.deadlineAt)) {
456
+ throw new LocalSyncExecutionPermitError(`Execution permit ${input.permitId} renewal deadline is invalid.`, 'SYNC_COORDINATOR_PERMIT_EXPIRED');
457
+ }
458
+ const result = this.db.prepare(`
459
+ UPDATE local_sync_execution_permits
460
+ SET deadline_at = ?,
461
+ last_transition_at = ?
462
+ WHERE permit_id = ?
463
+ AND workspace_id = ?
464
+ AND coordinator_generation = ?
465
+ AND server_instance_id = ?
466
+ AND owner_mode = ?
467
+ AND state = 'gateway-complete-awaiting-apply'
468
+ AND upstream_disposition = 'accepted'
469
+ `).run(input.deadlineAt, now, input.permitId, input.workspaceId, input.coordinatorGeneration, input.serverInstanceId, input.ownerMode);
470
+ if (Number(result?.changes || 0) !== 1) {
471
+ throw new LocalSyncExecutionPermitError(`Execution permit ${input.permitId} changed before its renewal committed.`, 'SYNC_COORDINATOR_PERMIT_STATE_CONFLICT');
472
+ }
473
+ return this.read(input.permitId);
474
+ })();
475
+ }
420
476
  completeAcceptedV3Dispatch(input, applyAuthoritativeAndAck) {
421
477
  return this.db.transaction(() => {
422
478
  const current = this.requirePermit(input.permitId);
@@ -563,9 +619,15 @@ export class LocalSyncExecutionPermitStore {
563
619
  if (current.state === 'local-commit-entered') {
564
620
  throw new LocalSyncExecutionPermitError(`Execution permit ${input.permitId} is owned by the server local commit.`, 'SYNC_COORDINATOR_PERMIT_STATE_CONFLICT');
565
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');
566
627
  const clean = current.state === 'issued-idle'
567
628
  || (current.state === 'gateway-complete-awaiting-apply'
568
- && current.upstreamDisposition === 'rejected');
629
+ && current.upstreamDisposition === 'rejected')
630
+ || cleanReadFailure;
569
631
  const disposition = current.upstreamDisposition === 'accepted'
570
632
  ? 'accepted'
571
633
  : current.upstreamDisposition === 'rejected'
@@ -677,19 +739,14 @@ export class LocalSyncExecutionPermitStore {
677
739
  WHERE resolved_at IS NOT NULL
678
740
  ORDER BY resolved_at DESC, obligation_id DESC
679
741
  `).all().map(mapObligation);
680
- const protectedObligationIds = new Set(resolvedObligations
681
- .slice(0, LOCAL_SYNC_PERMIT_RETENTION_SOFT_LIMIT)
682
- .map((obligation) => obligation.obligationId));
683
- for (const obligation of resolvedObligations) {
684
- if (obligation.resolvedAt && obligation.resolvedAt >= cutoff) {
685
- protectedObligationIds.add(obligation.obligationId);
686
- }
687
- }
742
+ const obligationAgeDeleteCount = Math.max(0, resolvedObligations.length - LOCAL_SYNC_PERMIT_RETENTION_SOFT_LIMIT);
743
+ const obligationHardDeleteCount = Math.max(0, resolvedObligations.length - LOCAL_SYNC_OBLIGATION_RETENTION_HARD_LIMIT);
688
744
  const obligationCandidates = resolvedObligations
689
- .filter((obligation) => (obligation.resolvedAt
690
- && obligation.resolvedAt < cutoff
691
- && !protectedObligationIds.has(obligation.obligationId)))
745
+ .slice()
692
746
  .reverse()
747
+ .filter((obligation, index) => (index < obligationHardDeleteCount
748
+ || (index < obligationAgeDeleteCount
749
+ && Boolean(obligation.resolvedAt && obligation.resolvedAt < cutoff))))
693
750
  .slice(0, boundedDeleteLimit);
694
751
  const removeObligation = this.db.prepare(`
695
752
  DELETE FROM local_sync_recovery_obligations
@@ -707,14 +764,7 @@ export class LocalSyncExecutionPermitStore {
707
764
  AND completed_at IS NOT NULL
708
765
  ORDER BY completed_at DESC, permit_id DESC
709
766
  `).all().map(mapPermit);
710
- const protectedPermitIds = new Set(terminalPermits
711
- .slice(0, LOCAL_SYNC_PERMIT_RETENTION_SOFT_LIMIT)
712
- .map((permit) => permit.permitId));
713
- for (const permit of terminalPermits) {
714
- if (permit.completedAt && permit.completedAt >= cutoff) {
715
- protectedPermitIds.add(permit.permitId);
716
- }
717
- }
767
+ const protectedPermitIds = new Set();
718
768
  const referencedPermitRows = this.db.prepare(`
719
769
  SELECT permit_id
720
770
  FROM local_sync_recovery_obligations
@@ -723,11 +773,15 @@ export class LocalSyncExecutionPermitStore {
723
773
  if (row.permit_id)
724
774
  protectedPermitIds.add(row.permit_id);
725
775
  }
776
+ const permitAgeDeleteCount = Math.max(0, terminalPermits.length - LOCAL_SYNC_PERMIT_RETENTION_SOFT_LIMIT);
777
+ const permitHardDeleteCount = Math.max(0, terminalPermits.length - LOCAL_SYNC_PERMIT_RETENTION_HARD_LIMIT);
726
778
  const permitCandidates = terminalPermits
727
- .filter((permit) => (permit.completedAt
728
- && permit.completedAt < cutoff
729
- && !protectedPermitIds.has(permit.permitId)))
779
+ .slice()
730
780
  .reverse()
781
+ .filter((permit, index) => (!protectedPermitIds.has(permit.permitId)
782
+ && (index < permitHardDeleteCount
783
+ || (index < permitAgeDeleteCount
784
+ && Boolean(permit.completedAt && permit.completedAt < cutoff)))))
731
785
  .slice(0, boundedDeleteLimit);
732
786
  const removePermit = this.db.prepare(`
733
787
  DELETE FROM local_sync_execution_permits
@@ -17,6 +17,10 @@ const RUNNER_COMMANDS = new Set([
17
17
  ]);
18
18
  const SCHEDULED_RETRY_BASE_DELAY_MS = 1_000;
19
19
  const SCHEDULED_RETRY_MAX_DELAY_MS = 5 * 60_000;
20
+ const CONTENT_PREREQUISITE_BYPASSED_RETRY_KINDS = new Set([
21
+ 'pull',
22
+ 'repair',
23
+ ]);
20
24
  function cloneCheckpoint(checkpoint) {
21
25
  return JSON.parse(canonicalWorkspaceSyncJson(checkpoint));
22
26
  }
@@ -159,7 +163,7 @@ export class LocalWorkspaceSyncRunner {
159
163
  if (!this.context || this.terminated || !this.acceptingWork) {
160
164
  return Promise.resolve();
161
165
  }
162
- return this.enqueue(async () => this.runInspection(this.options.operations.pushContentPrerequisite, { bypassRetryKind: 'repair' }));
166
+ return this.enqueue(async () => this.runInspection(this.options.operations.pushContentPrerequisite, { bypassRetryKinds: CONTENT_PREREQUISITE_BYPASSED_RETRY_KINDS }));
163
167
  }
164
168
  observeRemoteHint(observedAt = this.now()) {
165
169
  if (!this.context || this.terminated || !this.acceptingWork) {
@@ -476,7 +480,7 @@ export class LocalWorkspaceSyncRunner {
476
480
  if (!state.checkpoint.syncEnabled || !this.hasExactCapability(context))
477
481
  return;
478
482
  if (state.checkpoint.retry
479
- && state.checkpoint.retry.kind !== options.bypassRetryKind
483
+ && !options.bypassRetryKinds?.has(state.checkpoint.retry.kind)
480
484
  && Date.parse(state.checkpoint.retry.retryAt) > Date.parse(this.now())) {
481
485
  this.schedulePersistedRetry(state, this.lifecycleToken);
482
486
  return;
@@ -500,10 +500,11 @@ export function workspaceSyncGatewayTimeoutMs(operation) {
500
500
  if (operation.type === 'initiative-repair'
501
501
  || operation.type === 'combined-repair'
502
502
  || operation.type === 'v3-feed-repair'
503
- || (operation.type === 'push' && operation.repairMode === true)
504
- || (operation.type === 'pull' && operation.repairMode === true)
505
503
  || (operation.type === 'v3-feed'
506
504
  && (operation.forceRepair === true || Boolean(operation.repairCursor))))
505
+ return 75_000;
506
+ if ((operation.type === 'push' && operation.repairMode === true)
507
+ || (operation.type === 'pull' && operation.repairMode === true))
507
508
  return 180_000;
508
509
  if (operation.type === 'push'
509
510
  || operation.type === 'bootstrap-push')
@@ -638,6 +639,7 @@ const CHANGE_FIELDS = {
638
639
  'task-relationship-delete': { allowed: ['op', 'relationship'], required: ['relationship'], objectField: 'relationship' },
639
640
  'initiative-upsert': { allowed: ['op', 'initiative'], required: ['initiative'], objectField: 'initiative' },
640
641
  'workstream-upsert': { allowed: ['op', 'workstream'], required: ['workstream'], objectField: 'workstream' },
642
+ 'planning-identity-upsert': { allowed: ['op', 'identity'], required: ['identity'], objectField: 'identity' },
641
643
  'taxonomy-upsert': { allowed: ['op', 'taxonomies', 'taxonomyState', 'updatedAt', 'durableRevision'], required: ['updatedAt'] },
642
644
  'ai-profile-upsert': { allowed: ['op', 'profile'], required: ['profile'], objectField: 'profile' },
643
645
  'document-upsert': { allowed: [
@@ -40,6 +40,18 @@ function v3Boundary(input) {
40
40
  ...(input.coverage ? { coverage: { ...input.coverage } } : {}),
41
41
  };
42
42
  }
43
+ function independentContentBoundary(identity) {
44
+ const normalizedIdentity = String(identity || '').trim();
45
+ if (!normalizedIdentity) {
46
+ throw new TypeError('Independent content transfer identity is required.');
47
+ }
48
+ return {
49
+ version: 1,
50
+ projection: 'independent-content',
51
+ cursor: null,
52
+ identity: normalizedIdentity,
53
+ };
54
+ }
43
55
  async function decodeGatewayResponse(response, nowMs) {
44
56
  const rawText = await response.text();
45
57
  let data = {};
@@ -405,10 +417,12 @@ export function createBrowserGatewayWorkspaceSyncEngineRemoteServices(options) {
405
417
  });
406
418
  },
407
419
  pullWorkspaceContent: (input) => {
408
- const { previousCursor, ...request } = input;
420
+ const { previousCursor, independentCompletionIdentity, ...request } = input;
409
421
  return execute({
410
422
  operation: { type: 'content-pull', ...request },
411
- previousBoundary: v2Boundary(previousCursor),
423
+ previousBoundary: independentCompletionIdentity
424
+ ? independentContentBoundary(independentCompletionIdentity)
425
+ : v2Boundary(previousCursor),
412
426
  applying: true,
413
427
  });
414
428
  },
@@ -510,6 +524,10 @@ export function createBrowserGatewayWorkspaceSyncEngineRemoteServices(options) {
510
524
  }));
511
525
  },
512
526
  buildV2ApplyCompletionGroup: ({ workspaceId, previousCursor, nextCursor, receipts, }) => completionGroup(workspaceId, receipts, v2Boundary(previousCursor), v2Boundary(nextCursor)),
527
+ buildIndependentContentApplyCompletionGroup: ({ workspaceId, identity, receipts, }) => {
528
+ const boundary = independentContentBoundary(identity);
529
+ return completionGroup(workspaceId, receipts, boundary, boundary);
530
+ },
513
531
  buildV2PushApplyCompletionGroup: ({ workspaceId, pushBoundary, receipts, }) => completionGroup(workspaceId, receipts, parseWorkspaceSyncEngineV2PushBoundary(pushBoundary), parseWorkspaceSyncEngineV2PushBoundary(pushBoundary)),
514
532
  buildV3ApplyCompletionGroup: ({ workspaceId, apply, receipts }) => {
515
533
  const metadata = readReceipts(workspaceId, receipts);
@@ -24,6 +24,10 @@ export interface WorkspaceSyncEngineV2ApplyOptions {
24
24
  export interface WorkspaceSyncEngineV3ApplyOptions {
25
25
  completionGroup?: WorkspaceSyncEngineTransferCompletionGroup;
26
26
  }
27
+ export declare function authoritativeV2ApplyFailureMessage(input: {
28
+ status?: number;
29
+ data?: unknown;
30
+ }): string;
27
31
  /**
28
32
  * Local-runtime operations used by the workspace sync engine.
29
33
  *
@@ -1,5 +1,16 @@
1
1
  import { applyLocalWorkspaceChanges, applyLocalWorkspaceSyncV3CombinedProjection, applyLocalWorkspaceSyncV3Projection, applyLocalWorkspaceSyncV3TaskCommentAudit, completeLocalSyncAuthoritativeRepair, getLocalWorkspaceContentPullObligations, recordLocalWorkspaceContentPullObligationFailures, getLocalTaskMetadataOwnership, getLocalWorkspaceContentManifest, getLocalWorkspaceSyncV3CombinedProjection, getLocalWorkspaceSyncV3Projection, getLocalWorkspaceSyncV3TaskCommentAudit, } from '../cloudSyncApi.js';
2
2
  import { prepareLocalTaskRootOutboxRecovery, } from '../v3/localOutboxRecoveryClient.js';
3
+ export function authoritativeV2ApplyFailureMessage(input) {
4
+ const data = input.data && typeof input.data === 'object' && !Array.isArray(input.data)
5
+ ? input.data
6
+ : {};
7
+ const detail = String(data.error || '').trim();
8
+ const code = String(data.code || '').trim();
9
+ const status = Number(input.status) || 0;
10
+ return detail
11
+ ? `Authoritative V2 push echo apply failed (${status}): ${detail}${code ? ` [${code}]` : ''}`
12
+ : `Authoritative V2 push echo apply failed (${status}).`;
13
+ }
3
14
  /**
4
15
  * Same-origin HTTP implementation used while the browser owns orchestration.
5
16
  */
@@ -37,6 +37,12 @@ export type WorkspaceSyncEngineContentPullInput = Parameters<typeof pullWorkspac
37
37
  * commit against one exact prior boundary.
38
38
  */
39
39
  previousCursor: string | null;
40
+ /**
41
+ * Separates an independent content lookup from a V2 feed page. The
42
+ * identity becomes an apply boundary that settles the transfer
43
+ * without advancing or validating the runner's V2 cursor.
44
+ */
45
+ independentCompletionIdentity?: string;
40
46
  };
41
47
  type RemoteResult<Result> = Awaited<Result> & {
42
48
  transferReceipt?: WorkspaceSyncEngineRemoteTransferReceipt;
@@ -83,12 +89,22 @@ export interface WorkspaceSyncEngineRemoteServices {
83
89
  workspaceId: string;
84
90
  receipts: readonly WorkspaceSyncEngineRemoteTransferReceipt[];
85
91
  }): void | Promise<void>;
92
+ /** Keeps accepted applying receipts alive until a bounded transfer reaches its atomic commit. */
93
+ retainTransferReceipts?(input: {
94
+ workspaceId: string;
95
+ receipts: readonly WorkspaceSyncEngineRemoteTransferReceipt[];
96
+ }): void | Promise<void>;
86
97
  buildV2ApplyCompletionGroup(input: {
87
98
  workspaceId: string;
88
99
  previousCursor: string | null;
89
100
  nextCursor: string | null;
90
101
  receipts: readonly WorkspaceSyncEngineRemoteTransferReceipt[];
91
102
  }): WorkspaceSyncEngineTransferCompletionGroup | undefined;
103
+ buildIndependentContentApplyCompletionGroup(input: {
104
+ workspaceId: string;
105
+ identity: string;
106
+ receipts: readonly WorkspaceSyncEngineRemoteTransferReceipt[];
107
+ }): WorkspaceSyncEngineTransferCompletionGroup | undefined;
92
108
  buildV2PushApplyCompletionGroup(input: {
93
109
  workspaceId: string;
94
110
  pushBoundary: WorkspaceSyncEngineV2PushBoundary;
@@ -6,7 +6,7 @@ export function createBrowserWorkspaceSyncEngineRemoteServices(resolveCloudAuthU
6
6
  provisionWorkspace: (input) => provisionWorkspace(resolveCloudAuthUrl, input),
7
7
  pushWorkspaceChanges: ({ ownership: _ownership, pushBoundary: _pushBoundary, ...input }) => (pushWorkspaceChanges(resolveCloudAuthUrl, input)),
8
8
  pullWorkspaceChanges: (input) => pullWorkspaceChanges(resolveCloudAuthUrl, input),
9
- pullWorkspaceContent: ({ previousCursor: _previousCursor, ...input }) => (pullWorkspaceContent(resolveCloudAuthUrl, input)),
9
+ pullWorkspaceContent: ({ previousCursor: _previousCursor, independentCompletionIdentity: _independentCompletionIdentity, ...input }) => (pullWorkspaceContent(resolveCloudAuthUrl, input)),
10
10
  pullInitiativeFeed: (input) => pullWorkspaceSyncV3Feed(resolveCloudAuthUrl, input),
11
11
  pullInitiativeRepair: (input) => pullWorkspaceInitiativeRepair(resolveCloudAuthUrl, input),
12
12
  pullCombinedFeed: (input) => pullWorkspaceSyncV3CombinedFeed(resolveCloudAuthUrl, input),
@@ -15,6 +15,7 @@ export function createBrowserWorkspaceSyncEngineRemoteServices(resolveCloudAuthU
15
15
  abandonTransferReceipts: () => undefined,
16
16
  acknowledgeNonApplyingTransferReceipts: () => undefined,
17
17
  buildV2ApplyCompletionGroup: () => undefined,
18
+ buildIndependentContentApplyCompletionGroup: () => undefined,
18
19
  buildV2PushApplyCompletionGroup: () => undefined,
19
20
  buildV3ApplyCompletionGroup: () => undefined,
20
21
  };
@@ -1,7 +1,7 @@
1
1
  import type { LocalSyncExecutionPermitStore } from '../coordinator/localSyncExecutionPermitStore.js';
2
2
  import type { WorkspaceSyncTransportGateway } from '../coordinator/workspaceSyncTransportGateway.js';
3
3
  import type { WorkspaceSyncEngineRemoteServices } from './workspaceSyncEngineRemoteServices.js';
4
- type ServerRemotePermitStore = Pick<LocalSyncExecutionPermitStore, 'issueServer' | 'read' | 'acknowledgeNonApplyingCompletion' | 'completeAcceptedPushWithoutEcho' | 'abandonPermit'>;
4
+ type ServerRemotePermitStore = Pick<LocalSyncExecutionPermitStore, 'issueServer' | 'read' | 'acknowledgeNonApplyingCompletion' | 'completeAcceptedPushWithoutEcho' | 'renewAcceptedApplyCompletion' | 'abandonPermit'>;
5
5
  type ServerRemoteGateway = Pick<WorkspaceSyncTransportGateway, 'executeServer'>;
6
6
  export interface ServerWorkspaceSyncEngineRemoteServicesOptions {
7
7
  workspaceId: string;
@@ -40,6 +40,18 @@ function v3Boundary(input) {
40
40
  ...(input.coverage ? { coverage: { ...input.coverage } } : {}),
41
41
  };
42
42
  }
43
+ function independentContentBoundary(identity) {
44
+ const normalizedIdentity = String(identity || '').trim();
45
+ if (!normalizedIdentity) {
46
+ throw new TypeError('Independent content transfer identity is required.');
47
+ }
48
+ return {
49
+ version: 1,
50
+ projection: 'independent-content',
51
+ cursor: null,
52
+ identity: normalizedIdentity,
53
+ };
54
+ }
43
55
  function decodeGatewayResult(result, nowMs) {
44
56
  const rawText = new TextDecoder().decode(result.body);
45
57
  let data = {};
@@ -96,12 +108,15 @@ export function createServerWorkspaceSyncEngineRemoteServices(options) {
96
108
  throw new TypeError('The server sync operation workspace does not match its runner.');
97
109
  }
98
110
  };
99
- const abandon = (permitId, errorCode) => (options.permitStore.abandonPermit({
111
+ const abandon = (permitId, errorCode, readResponseUnavailableBeforeApply = false) => (options.permitStore.abandonPermit({
100
112
  permitId,
101
113
  workspaceId: options.workspaceId,
102
114
  coordinatorGeneration: options.coordinatorGeneration,
103
115
  serverInstanceId: options.serverInstanceId,
104
116
  errorCode,
117
+ ...(readResponseUnavailableBeforeApply
118
+ ? { readResponseUnavailableBeforeApply: true }
119
+ : {}),
105
120
  }));
106
121
  const execute = async (input) => {
107
122
  assertWorkspace(input.operation.workspaceId);
@@ -131,7 +146,7 @@ export function createServerWorkspaceSyncEngineRemoteServices(options) {
131
146
  });
132
147
  }
133
148
  catch (error) {
134
- abandon(permit.permitId, 'SYNC_COORDINATOR_GATEWAY_REQUEST_FAILED');
149
+ abandon(permit.permitId, 'SYNC_COORDINATOR_GATEWAY_REQUEST_FAILED', operationClass === 'pull' || operationClass === 'repair');
135
150
  throw error;
136
151
  }
137
152
  const decoded = decodeGatewayResult(gatewayResult, issuedAt.getTime());
@@ -171,6 +186,12 @@ export function createServerWorkspaceSyncEngineRemoteServices(options) {
171
186
  abandon(permit.permitId, 'SYNC_COORDINATOR_APPLYING_REJECTED');
172
187
  return result;
173
188
  }
189
+ if (!result.ok
190
+ && completedPermit.upstreamDisposition === 'unknown'
191
+ && (operationClass === 'pull' || operationClass === 'repair')) {
192
+ abandon(permit.permitId, 'SYNC_COORDINATOR_GATEWAY_REQUEST_FAILED', true);
193
+ return result;
194
+ }
174
195
  if (!input.previousBoundary) {
175
196
  abandon(permit.permitId, 'SYNC_COORDINATOR_APPLY_BOUNDARY_MISSING');
176
197
  throw new Error('A server applying request did not declare its prior boundary.');
@@ -181,6 +202,7 @@ export function createServerWorkspaceSyncEngineRemoteServices(options) {
181
202
  workspaceId: options.workspaceId,
182
203
  previousBoundary: input.previousBoundary,
183
204
  operationClass,
205
+ retentionMs: permitDeadlineMs,
184
206
  });
185
207
  return {
186
208
  ...result,
@@ -318,10 +340,12 @@ export function createServerWorkspaceSyncEngineRemoteServices(options) {
318
340
  });
319
341
  },
320
342
  pullWorkspaceContent: (input) => {
321
- const { previousCursor, ...request } = input;
343
+ const { previousCursor, independentCompletionIdentity, ...request } = input;
322
344
  return execute({
323
345
  operation: { type: 'content-pull', ...request },
324
- previousBoundary: v2Boundary(previousCursor),
346
+ previousBoundary: independentCompletionIdentity
347
+ ? independentContentBoundary(independentCompletionIdentity)
348
+ : v2Boundary(previousCursor),
325
349
  applying: true,
326
350
  });
327
351
  },
@@ -417,7 +441,25 @@ export function createServerWorkspaceSyncEngineRemoteServices(options) {
417
441
  }
418
442
  }
419
443
  },
444
+ retainTransferReceipts: ({ workspaceId, receipts }) => {
445
+ const metadata = readReceipts(workspaceId, receipts);
446
+ const retainedAt = now();
447
+ for (const receipt of metadata) {
448
+ options.permitStore.renewAcceptedApplyCompletion({
449
+ permitId: receipt.permitId,
450
+ workspaceId,
451
+ coordinatorGeneration: options.coordinatorGeneration,
452
+ ownerMode: 'server',
453
+ serverInstanceId: options.serverInstanceId,
454
+ deadlineAt: new Date(retainedAt.getTime() + receipt.retentionMs).toISOString(),
455
+ });
456
+ }
457
+ },
420
458
  buildV2ApplyCompletionGroup: ({ workspaceId, previousCursor, nextCursor, receipts, }) => completionGroup(workspaceId, receipts, v2Boundary(previousCursor), v2Boundary(nextCursor)),
459
+ buildIndependentContentApplyCompletionGroup: ({ workspaceId, identity, receipts, }) => {
460
+ const boundary = independentContentBoundary(identity);
461
+ return completionGroup(workspaceId, receipts, boundary, boundary);
462
+ },
421
463
  buildV2PushApplyCompletionGroup: ({ workspaceId, pushBoundary, receipts, }) => completionGroup(workspaceId, receipts, parseWorkspaceSyncEngineV2PushBoundary(pushBoundary), parseWorkspaceSyncEngineV2PushBoundary(pushBoundary)),
422
464
  buildV3ApplyCompletionGroup: ({ workspaceId, apply, receipts }) => {
423
465
  const metadata = readReceipts(workspaceId, receipts);
@@ -2,7 +2,7 @@ import type { LocalWorkspaceSyncRunnerOperations } from '../coordinator/localWor
2
2
  import { type EnsureWorkspaceReadyResult } from '../syncService.js';
3
3
  import type { WorkspaceSyncV2ProjectionExclusion } from '../v3/workspaceSyncV2ProjectionExclusions.js';
4
4
  import type { WorkspaceSyncV3CombinedCoverageSelector } from '../v3/workspaceSyncV3CombinedWireContract.js';
5
- import type { WorkspaceSyncEngineLocalServices } from './workspaceSyncEngineLocalServices.js';
5
+ import { type WorkspaceSyncEngineLocalServices } from './workspaceSyncEngineLocalServices.js';
6
6
  import type { WorkspaceSyncEngineRemoteServices } from './workspaceSyncEngineRemoteServices.js';
7
7
  import type { WorkspaceSyncEngineServerPushCandidateProvider } from './workspaceSyncEngineServerSnapshotReader.js';
8
8
  import type { WorkspaceSyncEngineServerCheckpointPort } from './workspaceSyncEngineServerApplyBoundary.js';
@@ -46,11 +46,13 @@ export interface WorkspaceSyncEngineServerAttachmentApplyPort {
46
46
  } | {
47
47
  success: false;
48
48
  error: string;
49
+ disposition?: 'retryable' | 'terminal-unavailable';
49
50
  }>;
50
51
  }): Promise<{
51
52
  attempted: number;
52
53
  resolved: number;
53
54
  remaining: number;
55
+ terminal: number;
54
56
  nextAttemptAt: string | null;
55
57
  lastError: string | null;
56
58
  }>;
@@ -6,6 +6,7 @@ import { runWorkspaceSyncV3CombinedProjectionCycle } from '../v3/workspaceSyncV3
6
6
  import { runWorkspaceSyncV3InitiativeProjectionCycle } from '../v3/workspaceSyncV3FeedOrchestrator.js';
7
7
  import { normalizeWorkspaceSyncV2ProjectionExclusions } from '../v3/workspaceSyncV2ProjectionExclusions.js';
8
8
  import { canonicalWorkspaceSyncJson } from '../v3/canonicalWorkspaceSyncJson.js';
9
+ import { authoritativeV2ApplyFailureMessage, } from './workspaceSyncEngineLocalServices.js';
9
10
  import { combinedAttachmentAssetHydrationId, createWorkspaceSyncV3TransferBindings, } from './workspaceSyncEngineTransfers.js';
10
11
  import { createWorkspaceSyncTransferEvidence, } from './workspaceSyncTransferEvidence.js';
11
12
  const NOOP_CLOUD_RESOLVER = (path) => path;
@@ -13,6 +14,7 @@ const RETRY_BASE_DELAY_MS = 1_000;
13
14
  const RETRY_MAX_DELAY_MS = 5 * 60_000;
14
15
  const COMBINED_FEED_COVERED_OUTBOX_BLOCK = 'WORKSPACE_SYNC_V3_COVERED_LOCAL_OPERATIONS';
15
16
  const REPAIR_OWNERSHIP_FINGERPRINT_VERSION = 2;
17
+ const NON_APPLYING_ACKNOWLEDGEMENT_CHECKPOINT_INTERVAL = 64;
16
18
  class WorkspaceSyncEngineServerRunnerOperationError extends Error {
17
19
  code;
18
20
  retryAfterMs;
@@ -146,6 +148,20 @@ export function createWorkspaceSyncEngineServerRunnerOperations(options) {
146
148
  transformCheckpointAtTransferBoundary: (boundary) => (transferBoundaryCheckpointTransform(boundary)),
147
149
  },
148
150
  });
151
+ const prepareAndDrainRecoveryReplay = async (preparedRecovery) => {
152
+ let recovery = preparedRecovery
153
+ ?? await localServices.prepareOutboxRecovery(workspaceId);
154
+ if (recovery.kind === 'recovery' && recovery.state === 'replay_queued') {
155
+ const drainResult = await options.drainV3Outbox?.({
156
+ beforeTransport: () => undefined,
157
+ });
158
+ if (drainResult === 'v2-content-push-required') {
159
+ fail('v2-content-push', 'A referenced attachment must be published before durable repair can continue.', 'SYNC_RUNNER_V2_CONTENT_PUSH_REQUIRED');
160
+ }
161
+ recovery = await localServices.prepareOutboxRecovery(workspaceId);
162
+ }
163
+ return recovery;
164
+ };
149
165
  const ensureReady = options.ensureCloudWorkspaceReadyForSync
150
166
  || (async () => {
151
167
  const result = await options.remoteServices.handshakeWorkspace(workspaceId);
@@ -499,7 +515,9 @@ export function createWorkspaceSyncEngineServerRunnerOperations(options) {
499
515
  ? 'repair'
500
516
  : 'push';
501
517
  activeRetryKind = pushRetryKind;
502
- persist({ ...checkpoint, controlState: 'pushing' });
518
+ if (checkpoint.controlState !== 'pushing') {
519
+ persist({ ...checkpoint, controlState: 'pushing' });
520
+ }
503
521
  let payload;
504
522
  let signature;
505
523
  if (checkpoint.pendingV2Push) {
@@ -537,11 +555,13 @@ export function createWorkspaceSyncEngineServerRunnerOperations(options) {
537
555
  persist({ ...checkpoint, pendingV2Push });
538
556
  }
539
557
  if (checkpoint.remoteHintObservedAt) {
540
- persist({
558
+ checkpoint = {
541
559
  ...checkpoint,
542
560
  consecutivePushesWhilePullDue: Math.min(Number.MAX_SAFE_INTEGER, checkpoint.consecutivePushesWhilePullDue + 1),
543
- });
561
+ };
544
562
  }
563
+ let persistedAcknowledgementCount = checkpoint.pendingV2Push
564
+ ?.acknowledgedNonApplyingBatchOperationIdentities.length || 0;
545
565
  const result = await runWorkspacePushSyncService({
546
566
  resolveCloudAuthUrl: NOOP_CLOUD_RESOLVER,
547
567
  workspaceId,
@@ -569,13 +589,14 @@ export function createWorkspaceSyncEngineServerRunnerOperations(options) {
569
589
  ],
570
590
  },
571
591
  });
592
+ persistedAcknowledgementCount = acknowledgedOperationIdentities.length;
572
593
  },
573
594
  onNonApplyingBatchAcknowledged: ({ acknowledgedOperationIdentities }) => {
574
595
  const pendingV2Push = checkpoint.pendingV2Push;
575
596
  if (!pendingV2Push) {
576
597
  throw new WorkspaceSyncEngineServerRunnerOperationError('The frozen V2 push disappeared while recording batch progress.', 'SYNC_RUNNER_PUSH_CHECKPOINT_INVALID');
577
598
  }
578
- persist({
599
+ checkpoint = {
579
600
  ...checkpoint,
580
601
  pendingV2Push: {
581
602
  ...pendingV2Push,
@@ -583,19 +604,25 @@ export function createWorkspaceSyncEngineServerRunnerOperations(options) {
583
604
  ...acknowledgedOperationIdentities,
584
605
  ],
585
606
  },
586
- });
607
+ };
608
+ if (acknowledgedOperationIdentities.length
609
+ - persistedAcknowledgementCount
610
+ >= NON_APPLYING_ACKNOWLEDGEMENT_CHECKPOINT_INTERVAL) {
611
+ persist(checkpoint);
612
+ persistedAcknowledgementCount = acknowledgedOperationIdentities.length;
613
+ }
587
614
  },
588
615
  });
589
616
  onResult?.(result);
590
617
  if (!result.success) {
591
618
  if (result.batchProgress && checkpoint.pendingV2Push) {
592
- persist({
619
+ checkpoint = {
593
620
  ...checkpoint,
594
621
  pendingV2Push: {
595
622
  ...checkpoint.pendingV2Push,
596
623
  lastBatchProgress: structuredClone(result.batchProgress),
597
624
  },
598
- });
625
+ };
599
626
  }
600
627
  const message = pushFailureMessage(result);
601
628
  if (isAuthFailure(result)) {
@@ -678,6 +705,8 @@ export function createWorkspaceSyncEngineServerRunnerOperations(options) {
678
705
  ? { durableRevision: entry.durableRevision }
679
706
  : {}),
680
707
  })), {
708
+ repairMode: attemptOptions.repairMode,
709
+ excludedProjections: result.effectiveV2ExcludedProjections,
681
710
  ...(completionGroup ? { completionGroup } : {}),
682
711
  commitServerCheckpoint: () => {
683
712
  const persisted = input.persistCheckpoint(nextCheckpoint, {
@@ -697,7 +726,9 @@ export function createWorkspaceSyncEngineServerRunnerOperations(options) {
697
726
  }
698
727
  if (!applyResult.ok || !commitState.checkpoint) {
699
728
  await abandonPushReceipts('WORKSPACE_SYNC_V2_PUSH_AUTHORITATIVE_APPLY_FAILED');
700
- throw new WorkspaceSyncEngineServerRunnerOperationError(`Authoritative V2 push echo apply failed (${applyResult.status || 0}).`, 'SYNC_RUNNER_PUSH_AUTHORITATIVE_APPLY_FAILED');
729
+ throw new WorkspaceSyncEngineServerRunnerOperationError(!applyResult.ok
730
+ ? authoritativeV2ApplyFailureMessage(applyResult)
731
+ : 'Authoritative V2 push echo did not commit the server checkpoint.', 'SYNC_RUNNER_PUSH_AUTHORITATIVE_APPLY_FAILED');
701
732
  }
702
733
  const committedCheckpoint = commitState.checkpoint;
703
734
  if (!committedCheckpoint) {
@@ -884,8 +915,7 @@ export function createWorkspaceSyncEngineServerRunnerOperations(options) {
884
915
  }
885
916
  if (localRecovery.kind === 'recovery'
886
917
  && localRecovery.state === 'replay_queued') {
887
- await options.drainV3Outbox?.({ beforeTransport: () => undefined });
888
- localRecovery = await localServices.prepareOutboxRecovery(workspaceId);
918
+ localRecovery = await prepareAndDrainRecoveryReplay(localRecovery);
889
919
  }
890
920
  if (localRecovery.kind === 'recovery'
891
921
  && localRecovery.state === 'replay_queued') {
@@ -912,7 +942,10 @@ export function createWorkspaceSyncEngineServerRunnerOperations(options) {
912
942
  const continuationInvalid = continuation !== null && (continuation.coordinatorGeneration !== input.coordinatorGeneration
913
943
  || continuation.ownershipFingerprint !== ownershipFingerprint
914
944
  || (recoveryBatchId !== null
915
- && continuation.recoveryBatchId !== recoveryBatchId));
945
+ && continuation.recoveryBatchId !== recoveryBatchId)
946
+ || (recoveryBatchId !== null
947
+ && continuation.kind !== 'v3-combined'
948
+ && continuation.kind !== 'v2-reconcile'));
916
949
  if (continuationInvalid || (checkpoint.repairContinuation !== null && !continuation)) {
917
950
  if (checkpoint.pendingV2Push) {
918
951
  await push({
@@ -1030,6 +1063,13 @@ export function createWorkspaceSyncEngineServerRunnerOperations(options) {
1030
1063
  }
1031
1064
  continuation = checkpoint.repairContinuation;
1032
1065
  }
1066
+ if (continuation.recoveryBatchId) {
1067
+ const postPullRecovery = await prepareAndDrainRecoveryReplay();
1068
+ if (postPullRecovery.kind === 'recovery'
1069
+ || Number(options.inspectV3Outbox?.().activeDepth || 0) > 0) {
1070
+ fail('repair', 'Durable recovery replay must settle before authoritative repair continues.', 'SYNC_RUNNER_RECOVERY_REPLAY_PENDING', RETRY_MAX_DELAY_MS);
1071
+ }
1072
+ }
1033
1073
  let pushResult = null;
1034
1074
  if (continuation.kind === 'final-push') {
1035
1075
  pushResult = await push({