@taskforcehq/taskforce 0.3.329 → 0.3.332

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 (363) hide show
  1. package/README.md +7 -2
  2. package/dist/Taskforce.module.css +290 -45
  3. package/dist/components/features/AiProfilesModule.js +3 -5
  4. package/dist/components/features/TaskSettings.js +70 -14
  5. package/dist/components/features/TaskforceAgentsModule.d.ts +1 -2
  6. package/dist/components/features/TaskforceAgentsModule.js +586 -116
  7. package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +2 -2
  8. package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.js +2 -2
  9. package/dist/components/features/agentConnections/AgentConnectionControl.d.ts +15 -0
  10. package/dist/components/features/agentConnections/AgentConnectionControl.js +125 -0
  11. package/dist/components/features/agentConnections/ModelConnectionsPanel.d.ts +18 -0
  12. package/dist/components/features/agentConnections/ModelConnectionsPanel.js +393 -0
  13. package/dist/components/features/agentConnections/modelConnectionsApi.d.ts +65 -0
  14. package/dist/components/features/agentConnections/modelConnectionsApi.js +129 -0
  15. package/dist/components/features/planning/PlanningModule.js +15 -3
  16. package/dist/components/features/planning/planningMetadata.d.ts +10 -0
  17. package/dist/components/features/planning/planningMetadata.js +8 -0
  18. package/dist/components/features/taskforceAgentAssignments/AgentBehaviorAssignments.js +15 -24
  19. package/dist/components/features/taskforceAgentEditorModel.d.ts +2 -1
  20. package/dist/components/features/taskforceAgentEditorModel.js +3 -1
  21. package/dist/components/features/workflowManager/workflowManagerApi.d.ts +1 -1
  22. package/dist/components/features/workflowManager/workflowManagerApi.js +3 -0
  23. package/dist/components/task/TaskWorkflowAssignmentField.js +68 -10
  24. package/dist/components/views/StandaloneLayout.js +62 -27
  25. package/dist/components/views/panels/PlanningDrawer.d.ts +2 -1
  26. package/dist/components/views/panels/PlanningDrawer.js +12 -8
  27. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +4 -3
  28. package/dist/components/views/standalone/modals/SyncStatusModal.js +33 -38
  29. package/dist/config/envSchema.js +55 -1
  30. package/dist/core/McpTokenService.d.ts +25 -1
  31. package/dist/core/McpTokenService.js +106 -15
  32. package/dist/core/TaskChecklistCommandService.d.ts +27 -0
  33. package/dist/core/TaskChecklistCommandService.js +83 -5
  34. package/dist/core/TaskLifecycleCommandService.d.ts +3 -1
  35. package/dist/core/TaskLifecycleCommandService.js +6 -2
  36. package/dist/core/Taskforce.d.ts +43 -3
  37. package/dist/core/Taskforce.js +158 -7
  38. package/dist/core/types.d.ts +9 -0
  39. package/dist/documentReviews/DocumentReviewCommentStore.d.ts +2 -0
  40. package/dist/documentReviews/DocumentReviewCommentStore.js +28 -9
  41. package/dist/documentReviews/commandService.d.ts +2 -1
  42. package/dist/documentReviews/commandService.js +6 -3
  43. package/dist/hooks/sync/orchestratorShared.d.ts +1 -0
  44. package/dist/hooks/sync/orchestratorShared.js +2 -0
  45. package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.d.ts +3 -0
  46. package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.js +85 -9
  47. package/dist/hooks/sync/useSyncStatusControls.d.ts +4 -1
  48. package/dist/hooks/sync/useSyncStatusControls.js +47 -11
  49. package/dist/hooks/useSyncOrchestrator.d.ts +3 -0
  50. package/dist/hooks/useSyncOrchestrator.js +111 -2
  51. package/dist/hooks/useTaskData.d.ts +31 -1
  52. package/dist/hooks/useTaskData.js +29 -7
  53. package/dist/hooks/useTaskMutations.d.ts +3 -1
  54. package/dist/hooks/useTaskMutations.js +46 -12
  55. package/dist/hooks/useTaskforce.d.ts +2 -0
  56. package/dist/hooks/useTaskforce.js +11 -2
  57. package/dist/mcp/clientRegistry.d.ts +2 -2
  58. package/dist/mcp/clientRegistry.js +1 -1
  59. package/dist/mcp/documentAssetRegistrar.js +9 -6
  60. package/dist/mcp/durableTaskMutationRouter.d.ts +4 -1
  61. package/dist/mcp/durableTaskMutationRouter.js +10 -0
  62. package/dist/mcp/durableTaskRelationshipMutationRouter.js +4 -0
  63. package/dist/mcp/httpProtocolRouting.d.ts +11 -0
  64. package/dist/mcp/httpProtocolRouting.js +22 -0
  65. package/dist/mcp/localCliHealth.d.ts +2 -2
  66. package/dist/mcp/localCliHealth.js +2 -2
  67. package/dist/mcp/localServiceProxy.d.ts +1 -0
  68. package/dist/mcp/localServiceProxy.js +530 -68
  69. package/dist/mcp/planningAttachmentCommandAdapter.d.ts +3 -1
  70. package/dist/mcp/planningAttachmentCommandAdapter.js +20 -2
  71. package/dist/mcp/runtime.d.ts +54 -79
  72. package/dist/mcp/runtime.js +408 -102
  73. package/dist/mcp/taskPlanningRegistrar.js +25 -6
  74. package/dist/mcp/toolProfiles.d.ts +2 -0
  75. package/dist/mcp/toolProfiles.js +11 -0
  76. package/dist/mcp/toolRegistry.d.ts +1 -0
  77. package/dist/mcp/toolRegistry.js +9 -8
  78. package/dist/mcp/workflowExecutionRegistrar.js +4 -4
  79. package/dist/migrations/taskSchemaMigrations.d.ts +5 -0
  80. package/dist/migrations/taskSchemaMigrations.js +415 -0
  81. package/dist/runtime/appGates.d.ts +2 -1
  82. package/dist/runtime/appGates.js +7 -0
  83. package/dist/server/buildInfo.d.ts +1 -0
  84. package/dist/server/buildInfo.js +5 -1
  85. package/dist/server/cloudMcpCapacityTelemetry.d.ts +68 -0
  86. package/dist/server/cloudMcpCapacityTelemetry.js +221 -0
  87. package/dist/server/index.d.ts +3 -0
  88. package/dist/server/index.js +108 -11
  89. package/dist/server/localDatabaseIdentity.js +4 -1
  90. package/dist/server/localServiceLease.js +2 -1
  91. package/dist/server/localServiceSessions.d.ts +14 -17
  92. package/dist/server/localServiceSessions.js +308 -94
  93. package/dist/server/localWorkspaceSyncServerRuntime.js +25 -19
  94. package/dist/server/routes/admin.d.ts +4 -0
  95. package/dist/server/routes/admin.js +126 -5
  96. package/dist/server/routes/agents.d.ts +7 -0
  97. package/dist/server/routes/agents.js +277 -24
  98. package/dist/server/routes/billing.js +5 -1
  99. package/dist/server/routes/durableTaskHttpRouters.d.ts +2 -0
  100. package/dist/server/routes/executorPhaseAApprovals.d.ts +19 -0
  101. package/dist/server/routes/executorPhaseAApprovals.js +140 -0
  102. package/dist/server/routes/executorPhaseAIssuerRedemptions.d.ts +11 -0
  103. package/dist/server/routes/executorPhaseAIssuerRedemptions.js +24 -0
  104. package/dist/server/routes/githubReviewEvidence.d.ts +19 -0
  105. package/dist/server/routes/githubReviewEvidence.js +116 -0
  106. package/dist/server/routes/localService.d.ts +15 -4
  107. package/dist/server/routes/localService.js +136 -40
  108. package/dist/server/routes/modelConnections.d.ts +24 -0
  109. package/dist/server/routes/modelConnections.js +205 -0
  110. package/dist/server/routes/shared.d.ts +22 -0
  111. package/dist/server/routes/shared.js +298 -182
  112. package/dist/server/routes/sync.js +1 -0
  113. package/dist/server/routes/syncAuxRoutes.js +5 -1
  114. package/dist/server/routes/syncPushRoutes.d.ts +1 -0
  115. package/dist/server/routes/syncPushRoutes.js +1 -0
  116. package/dist/server/routes/syncV3FeedRoutes.js +10 -1
  117. package/dist/server/routes/syncV3OperationRoutes.js +35 -9
  118. package/dist/server/routes/tasks.js +21 -2
  119. package/dist/server/routes/workflows.js +9 -1
  120. package/dist/server/routes.js +59 -0
  121. package/dist/service/localServiceCli.d.ts +2 -2
  122. package/dist/service/localServiceCli.js +4 -3
  123. package/dist/services/codexAppServerModelGateway.d.ts +54 -5
  124. package/dist/services/codexAppServerModelGateway.js +246 -21
  125. package/dist/services/codexDeviceCodeLoginManager.d.ts +39 -0
  126. package/dist/services/codexDeviceCodeLoginManager.js +265 -0
  127. package/dist/services/codexModelProviderConnectionLifecycle.d.ts +8 -0
  128. package/dist/services/codexModelProviderConnectionLifecycle.js +73 -0
  129. package/dist/services/executorPhaseAApprovalRuntime.d.ts +14 -0
  130. package/dist/services/executorPhaseAApprovalRuntime.js +24 -0
  131. package/dist/services/executorPhaseAApprovalService.d.ts +40 -0
  132. package/dist/services/executorPhaseAApprovalService.js +609 -0
  133. package/dist/services/executorPhaseADriftEvaluator.d.ts +78 -0
  134. package/dist/services/executorPhaseADriftEvaluator.js +93 -0
  135. package/dist/services/executorPhaseAIssuerCore.d.ts +139 -0
  136. package/dist/services/executorPhaseAIssuerCore.js +402 -0
  137. package/dist/services/executorPhaseAIssuerRedemptionService.d.ts +34 -0
  138. package/dist/services/executorPhaseAIssuerRedemptionService.js +158 -0
  139. package/dist/services/githubReviewEvidenceRuntime.d.ts +14 -0
  140. package/dist/services/githubReviewEvidenceRuntime.js +30 -0
  141. package/dist/services/githubReviewEvidenceService.d.ts +93 -0
  142. package/dist/services/githubReviewEvidenceService.js +336 -0
  143. package/dist/services/modelGateway.d.ts +7 -0
  144. package/dist/services/modelProviderConnectionService.d.ts +71 -0
  145. package/dist/services/modelProviderConnectionService.js +279 -0
  146. package/dist/services/modelProviderCredentialHome.d.ts +32 -0
  147. package/dist/services/modelProviderCredentialHome.js +271 -0
  148. package/dist/services/ownerScopedModelConnectionGateway.d.ts +12 -0
  149. package/dist/services/ownerScopedModelConnectionGateway.js +30 -0
  150. package/dist/services/taskforceAgentConnectionBindingService.d.ts +66 -0
  151. package/dist/services/taskforceAgentConnectionBindingService.js +185 -0
  152. package/dist/services/taskforceAgentMcpBridge.d.ts +2 -2
  153. package/dist/services/taskforceAgentMcpBridge.js +42 -29
  154. package/dist/shared/adminEdgeProxy.d.ts +5 -0
  155. package/dist/shared/adminEdgeProxy.js +94 -0
  156. package/dist/shared/adminProxySessionCookies.d.ts +16 -0
  157. package/dist/shared/adminProxySessionCookies.js +86 -0
  158. package/dist/shared/aiProfileColors.d.ts +31 -1
  159. package/dist/shared/aiProfileColors.js +14 -6
  160. package/dist/shared/executorPhaseAApprovalGoldenVector.json +269 -0
  161. package/dist/shared/executorPhaseAApprovalReceipt.d.ts +112 -0
  162. package/dist/shared/executorPhaseAApprovalReceipt.js +58 -0
  163. package/dist/shared/executorPhaseAApprovalTrustPolicy.json +10 -0
  164. package/dist/shared/executorPhaseADriftContracts.d.ts +37 -0
  165. package/dist/shared/executorPhaseADriftContracts.js +63 -0
  166. package/dist/shared/executorPhaseAIssuerContracts.d.ts +75 -0
  167. package/dist/shared/executorPhaseAIssuerContracts.js +90 -0
  168. package/dist/shared/executorPhaseARunAuthorization.d.ts +120 -0
  169. package/dist/shared/executorPhaseARunAuthorization.js +232 -0
  170. package/dist/shared/executorPhaseASchemaValidation.d.ts +7 -0
  171. package/dist/shared/executorPhaseASchemaValidation.js +53 -0
  172. package/dist/shared/executorPhaseASchemas/approval-receipt.schema.json +106 -0
  173. package/dist/shared/executorPhaseASchemas/drift-attestation.schema.json +54 -0
  174. package/dist/shared/executorPhaseASchemas/drift-request.schema.json +47 -0
  175. package/dist/shared/executorPhaseASchemas/foundation-manifest.schema.json +29 -0
  176. package/dist/shared/executorPhaseASchemas/issuer-audit-record.schema.json +24 -0
  177. package/dist/shared/executorPhaseASchemas/issuer-proof.schema.json +43 -0
  178. package/dist/shared/executorPhaseASchemas/issuer-redemption-request.schema.json +18 -0
  179. package/dist/shared/executorPhaseASchemas/issuer-redemption-response.schema.json +39 -0
  180. package/dist/shared/executorPhaseASchemas/logical-envelope.schema.json +149 -0
  181. package/dist/shared/executorPhaseASchemas/preflight-report.schema.json +216 -0
  182. package/dist/shared/executorPhaseASchemas/run-capability.schema.json +111 -0
  183. package/dist/shared/executorPhaseASchemas/sender-proof.schema.json +37 -0
  184. package/dist/shared/executorPhaseASchemas/workload-grant.schema.json +68 -0
  185. package/dist/shared/executorPhaseASchemas/workload-jwt-claims.schema.json +67 -0
  186. package/dist/shared/executorPhaseATiming.d.ts +1 -0
  187. package/dist/shared/executorPhaseATiming.js +1 -0
  188. package/dist/shared/planningIdentity.js +1 -1
  189. package/dist/shared/productLogoKeys.d.ts +2 -0
  190. package/dist/shared/productLogoKeys.js +18 -0
  191. package/dist/shared/taskforceAgentDefinition.d.ts +0 -1
  192. package/dist/shared/taskforceAgentDefinition.js +6 -9
  193. package/dist/shared/taskforceAgentModels.js +7 -3
  194. package/dist/shared/userFeatureGrants.d.ts +4 -0
  195. package/dist/shared/userFeatureGrants.js +7 -0
  196. package/dist/storage/executorPhaseAApprovalReceiptStore.d.ts +37 -0
  197. package/dist/storage/executorPhaseAApprovalReceiptStore.js +81 -0
  198. package/dist/storage/executorPhaseARunAuthorizationStore.d.ts +103 -0
  199. package/dist/storage/executorPhaseARunAuthorizationStore.js +492 -0
  200. package/dist/storage/githubReviewEvidenceInstallationStore.d.ts +26 -0
  201. package/dist/storage/githubReviewEvidenceInstallationStore.js +89 -0
  202. package/dist/storage/modelProviderConnectionStore.d.ts +99 -0
  203. package/dist/storage/modelProviderConnectionStore.js +446 -0
  204. package/dist/storage/postgresAdapter.d.ts +4 -0
  205. package/dist/storage/postgresAdapter.js +14 -1
  206. package/dist/storage/postgresRequestDiagnostics.d.ts +9 -1
  207. package/dist/storage/postgresRequestDiagnostics.js +15 -2
  208. package/dist/storage/postgresWorker.js +20 -2
  209. package/dist/storage/postgresWorkerProtocol.d.ts +7 -0
  210. package/dist/storage/taskforceAgentConnectionBindingStore.d.ts +31 -0
  211. package/dist/storage/taskforceAgentConnectionBindingStore.js +84 -0
  212. package/dist/storage/workflowStore.d.ts +2 -0
  213. package/dist/storage/workflowStore.js +39 -2
  214. package/dist/sync/cloudSyncApi.js +4 -2
  215. package/dist/sync/collaborationSyncState.js +5 -0
  216. package/dist/sync/coordinator/localSyncExecutionPermitStore.js +60 -29
  217. package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.d.ts +10 -0
  218. package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.js +29 -0
  219. package/dist/sync/coordinator/localWorkspaceSyncRunner.d.ts +3 -1
  220. package/dist/sync/coordinator/localWorkspaceSyncRunner.js +18 -0
  221. package/dist/sync/coordinator/localWorkspaceSyncRunnerState.d.ts +15 -1
  222. package/dist/sync/coordinator/localWorkspaceSyncRunnerState.js +99 -2
  223. package/dist/sync/coordinator/workspaceSyncCredentialBroker.d.ts +1 -0
  224. package/dist/sync/coordinator/workspaceSyncCredentialBroker.js +33 -4
  225. package/dist/sync/engine/workspaceSyncContentLifecycleAdapter.d.ts +2 -1
  226. package/dist/sync/engine/workspaceSyncContentVersionStore.d.ts +38 -0
  227. package/dist/sync/engine/workspaceSyncContentVersionStore.js +50 -1
  228. package/dist/sync/engine/workspaceSyncEngineLifecyclePolicy.js +6 -6
  229. package/dist/sync/engine/workspaceSyncEnginePushCompletion.d.ts +14 -0
  230. package/dist/sync/engine/workspaceSyncEnginePushCompletion.js +84 -0
  231. package/dist/sync/engine/workspaceSyncEngineRecovery.js +1 -0
  232. package/dist/sync/engine/workspaceSyncEngineRuntime.d.ts +1 -0
  233. package/dist/sync/engine/workspaceSyncEngineRuntime.js +1 -0
  234. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +112 -38
  235. package/dist/sync/engine/workspaceSyncEngineServerSnapshotReader.js +6 -0
  236. package/dist/sync/engine/workspaceSyncEngineTransfers.js +3 -1
  237. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.d.ts +1 -0
  238. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +31 -0
  239. package/dist/sync/syncApplyHandlers.d.ts +3 -0
  240. package/dist/sync/syncApplyHandlers.js +81 -15
  241. package/dist/sync/syncService.d.ts +15 -0
  242. package/dist/sync/syncService.js +83 -18
  243. package/dist/sync/taskforceAgentSyncAuthorization.d.ts +16 -0
  244. package/dist/sync/taskforceAgentSyncAuthorization.js +20 -0
  245. package/dist/sync/v3/combinedFeedCapability.js +4 -0
  246. package/dist/sync/v3/durableInitiativeMutationRouter.js +18 -10
  247. package/dist/sync/v3/durableOperationReplay.d.ts +14 -0
  248. package/dist/sync/v3/durableOperationReplay.js +18 -0
  249. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +3 -0
  250. package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -1
  251. package/dist/sync/v3/durableTaskChecklistMutationRouter.js +58 -15
  252. package/dist/sync/v3/durableTaskCommentMutationRouter.js +3 -0
  253. package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +1 -1
  254. package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +10 -0
  255. package/dist/sync/v3/durableTaxonomyMutationRouter.js +5 -0
  256. package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.d.ts +18 -7
  257. package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.js +89 -23
  258. package/dist/sync/v3/durableWorkstreamMutationRouter.js +18 -10
  259. package/dist/sync/v3/durableWorkstreamTaskOrderMutationRouter.js +16 -5
  260. package/dist/sync/v3/localOutboxDispatchRuntime.js +2 -2
  261. package/dist/sync/v3/localOutboxRecoveryPreparationService.js +8 -2
  262. package/dist/sync/v3/localTaskChecklistOutboxHandler.js +16 -2
  263. package/dist/sync/v3/localTaskChecklistOutboxService.d.ts +4 -0
  264. package/dist/sync/v3/localTaskChecklistOutboxService.js +14 -1
  265. package/dist/sync/v3/localTaskCreateOutboxService.d.ts +3 -1
  266. package/dist/sync/v3/localTaskCreateOutboxService.js +6 -1
  267. package/dist/sync/v3/localTaskDeleteOutboxService.js +1 -0
  268. package/dist/sync/v3/localTaskLifecycleOutboxService.d.ts +2 -1
  269. package/dist/sync/v3/localTaskLifecycleOutboxService.js +5 -1
  270. package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -1
  271. package/dist/sync/v3/localTaskMetadataOutboxService.js +6 -2
  272. package/dist/sync/v3/localTaskStatusOutboxService.d.ts +10 -1
  273. package/dist/sync/v3/localTaskStatusOutboxService.js +238 -16
  274. package/dist/sync/v3/syncDurabilityStore.d.ts +36 -1
  275. package/dist/sync/v3/syncDurabilityStore.js +202 -8
  276. package/dist/sync/v3/taskChecklistMutationService.d.ts +11 -0
  277. package/dist/sync/v3/taskChecklistMutationService.js +44 -1
  278. package/dist/sync/v3/taskStatusMutationService.d.ts +29 -1
  279. package/dist/sync/v3/taskStatusMutationService.js +119 -3
  280. package/dist/sync/v3/workflowAssignmentSync.d.ts +5 -0
  281. package/dist/sync/v3/workflowAssignmentSync.js +27 -0
  282. package/dist/sync/v3/workflowRuntimeMutationService.d.ts +5 -0
  283. package/dist/sync/v3/workflowRuntimeMutationService.js +124 -71
  284. package/dist/sync/v3/workspaceSyncJournalReader.js +1 -1
  285. package/dist/sync/v3/workspaceSyncOperationRetentionService.d.ts +16 -0
  286. package/dist/sync/v3/workspaceSyncOperationRetentionService.js +83 -0
  287. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.d.ts +1 -0
  288. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +9 -2
  289. package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +25 -3
  290. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +7 -0
  291. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +44 -32
  292. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +9 -5
  293. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +54 -38
  294. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
  295. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +70 -31
  296. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +2 -1
  297. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +16 -0
  298. package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
  299. package/dist/sync/v3/workspaceSyncV3Feed.d.ts +1 -0
  300. package/dist/sync/v3/workspaceSyncV3Feed.js +6 -1
  301. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +2 -0
  302. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +49 -18
  303. package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +3 -0
  304. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +5 -0
  305. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +36 -2
  306. package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.d.ts +17 -0
  307. package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.js +64 -0
  308. package/dist/sync/v3/workspaceSyncV3WorkflowRuntimeApply.d.ts +1 -0
  309. package/dist/sync/v3/workspaceSyncV3WorkflowRuntimeApply.js +50 -5
  310. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.d.ts +7 -0
  311. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.js +33 -0
  312. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.d.ts +7 -0
  313. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.js +8 -0
  314. package/dist/sync/workspaceRepair.d.ts +5 -2
  315. package/dist/sync/workspaceRepair.js +161 -6
  316. package/dist/sync/workspaceSyncModel.d.ts +21 -0
  317. package/dist/sync/workspaceSyncModel.js +35 -7
  318. package/dist/sync/workspaceSyncState.d.ts +1 -0
  319. package/dist/sync/workspaceSyncV2SnapshotBuilder.d.ts +6 -0
  320. package/dist/sync/workspaceSyncV2SnapshotBuilder.js +5 -0
  321. package/dist/ui/assets/AiIdentityRosterCard-CDMPtnbC.js +1 -0
  322. package/dist/ui/assets/AiProfilesModule-Cww85C4E.js +1 -0
  323. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-B68Wg-RV.js → AnnotatedAttachmentWorkspace-Dt9TKYSH.js} +1 -1
  324. package/dist/ui/assets/{AssetTraySortControl-C8Rztyal.js → AssetTraySortControl-CKgapnxu.js} +1 -1
  325. package/dist/ui/assets/{ContextAttachmentManager-Cj3c7X9y.js → ContextAttachmentManager-T-cEVcOZ.js} +2 -2
  326. package/dist/ui/assets/{DocumentWorkspace-B5uvzems.js → DocumentWorkspace-HD4MUjAZ.js} +1 -1
  327. package/dist/ui/assets/{EntityActivityTimeline-BVFvCB5R.js → EntityActivityTimeline-_V0zfMuh.js} +1 -1
  328. package/dist/ui/assets/PlanningModule-mTkBygsB.js +1 -0
  329. package/dist/ui/assets/{PlansPage-AY4cGWco.js → PlansPage-Btiq06VO.js} +1 -1
  330. package/dist/ui/assets/{TaskContextUpload-DZxTVesW.js → TaskContextUpload-C00NVUpn.js} +1 -1
  331. package/dist/ui/assets/TaskSettings-Cp-L-4xh.js +12 -0
  332. package/dist/ui/assets/TaskforceAgentsModule-Coq9-PUp.js +24 -0
  333. package/dist/ui/assets/TaskforceAgentsModule-b-8R25cJ.css +1 -0
  334. package/dist/ui/assets/{WorkflowManagerModule-DEr5di_r.js → WorkflowManagerModule-CuqRzMmM.js} +1 -1
  335. package/dist/ui/assets/index-BZ-hdZSk.css +1 -0
  336. package/dist/ui/assets/index-DSQINwt9.js +7 -0
  337. package/dist/ui/assets/{vendor-icons-D9Lpw-j4.js → vendor-icons-Bsq-mcEn.js} +1 -1
  338. package/dist/ui/branding/logos/letterhead_dark.png +0 -0
  339. package/dist/ui/branding/logos/letterhead_light.png +0 -0
  340. package/dist/ui/branding/logos/signature_dark.png +0 -0
  341. package/dist/ui/branding/logos/signature_light.png +0 -0
  342. package/dist/ui/index.html +3 -3
  343. package/dist/utils/aiProfileDefaultLogo.js +16 -48
  344. package/dist/utils/httpSetCookie.d.ts +1 -0
  345. package/dist/utils/httpSetCookie.js +4 -1
  346. package/dist/utils/localRuntimeUrl.d.ts +1 -0
  347. package/dist/utils/localRuntimeUrl.js +14 -0
  348. package/dist/utils/productLogoRegistry.d.ts +2 -0
  349. package/dist/utils/productLogoRegistry.js +36 -0
  350. package/dist/utils/syncStatusPresentation.d.ts +4 -0
  351. package/dist/utils/syncStatusPresentation.js +17 -0
  352. package/dist/utils/taskEvents.d.ts +2 -0
  353. package/dist/utils/workspaceSyncPresentation.d.ts +1 -1
  354. package/dist/utils/workspaceSyncPresentation.js +23 -17
  355. package/package.json +24 -4
  356. package/dist/ui/assets/AiIdentityRosterCard-BZM4aQnM.js +0 -1
  357. package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +0 -1
  358. package/dist/ui/assets/PlanningModule-B5DWQOGz.js +0 -1
  359. package/dist/ui/assets/TaskSettings-BeWAuyZj.js +0 -12
  360. package/dist/ui/assets/TaskforceAgentsModule-BifCYtjR.js +0 -21
  361. package/dist/ui/assets/TaskforceAgentsModule-D6IC0S7Q.css +0 -1
  362. package/dist/ui/assets/index-I5zhdtgt.js +0 -7
  363. package/dist/ui/assets/index-VRFsx3wz.css +0 -1
@@ -1,7 +1,7 @@
1
1
  import { applyLocalWorkspaceChanges, getLocalWorkspaceContentPullObligations, recordLocalWorkspaceContentPullObligationFailures, getLocalWorkspaceContentManifest, pullUserSettings, pushUserSettings, prepareWorkspacePushChanges, } from './cloudSyncApi.js';
2
2
  import { workspaceSyncContentPullObligationId, } from './engine/workspaceSyncContentPullObligationStore.js';
3
3
  import { createBrowserWorkspaceSyncEngineRemoteServices, } from './engine/workspaceSyncEngineRemoteServices.js';
4
- import { createWorkspaceSyncEngineV2PushBoundary, parseWorkspaceSyncEngineAppliedTaskUpserts, workspaceSyncEngineExpectedTaskEchoIds, } from './engine/workspaceSyncEnginePushCompletion.js';
4
+ import { createWorkspaceSyncEngineV2SettlementIdentityProjection, createWorkspaceSyncEngineV2PushBoundary, parseWorkspaceSyncEngineAppliedTaskUpserts, workspaceSyncEngineExpectedTaskEchoIds, } from './engine/workspaceSyncEnginePushCompletion.js';
5
5
  import { encryptDocument } from './encryptionService.js';
6
6
  import { decryptWorkspaceSyncContentChangeInPlace } from './workspaceSyncContentDecryption.js';
7
7
  import { decideWorkspaceContentFetch, fingerprintWorkspaceContentBody, } from './workspaceContentManifest.js';
@@ -181,13 +181,8 @@ function buildEffectiveWorkspacePushDiagnostics(diagnostics, changes, ownership)
181
181
  : {}),
182
182
  };
183
183
  }
184
- async function computeIdempotencyKey(workspaceId, changes, repairMode) {
185
- const text = canonicalWorkspaceSyncJson({
186
- contractVersion: 1,
187
- workspaceId,
188
- repairMode,
189
- changes
190
- });
184
+ async function computeCanonicalWorkspaceSyncSha256(value, fallbackNamespace) {
185
+ const text = canonicalWorkspaceSyncJson(value);
191
186
  try {
192
187
  const buffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text));
193
188
  return Array.from(new Uint8Array(buffer)).map(b => b.toString(16).padStart(2, '0')).join('');
@@ -202,9 +197,19 @@ async function computeIdempotencyKey(workspaceId, changes, repairMode) {
202
197
  hash = Math.imul(hash, 0x01000193);
203
198
  }
204
199
  const hex = (hash >>> 0).toString(16).padStart(8, '0');
205
- return `${workspaceId}:fallback:${hex}`;
200
+ return fallbackNamespace
201
+ ? `${fallbackNamespace}:fallback:${hex}`
202
+ : hex.repeat(8);
206
203
  }
207
204
  }
205
+ async function computeIdempotencyKey(workspaceId, changes, repairMode) {
206
+ return computeCanonicalWorkspaceSyncSha256({
207
+ contractVersion: 1,
208
+ workspaceId,
209
+ repairMode,
210
+ changes
211
+ }, workspaceId);
212
+ }
208
213
  const MAX_WORKSPACE_PUSH_CHANGES_PER_REQUEST = 64;
209
214
  const MAX_WORKSPACE_PUSH_BYTES_PER_REQUEST = 4 * 1024 * 1024;
210
215
  const MAX_WORKSPACE_PUSH_SINGLE_CHANGE_BYTES = 45 * 1024 * 1024;
@@ -428,6 +433,7 @@ export async function runWorkspacePushSyncService(input) {
428
433
  currentInitiativeWatermarks: input.payload.currentInitiativeWatermarks,
429
434
  currentWorkstreamIds: input.payload.currentWorkstreamIds,
430
435
  currentWorkstreamWatermarks: input.payload.currentWorkstreamWatermarks,
436
+ currentPlanningIdentityWatermarks: input.payload.currentPlanningIdentityWatermarks,
431
437
  currentAiProfileIds: input.payload.currentAiProfileIds,
432
438
  currentAiProfileWatermarks: input.payload.currentAiProfileWatermarks,
433
439
  currentAiProfileChangeKeys: input.payload.currentAiProfileChangeKeys ?? new Map(),
@@ -491,6 +497,7 @@ export async function runWorkspacePushSyncService(input) {
491
497
  currentInitiativeWatermarks: input.payload.currentInitiativeWatermarks,
492
498
  currentWorkstreamIds: input.payload.currentWorkstreamIds,
493
499
  currentWorkstreamWatermarks: input.payload.currentWorkstreamWatermarks,
500
+ currentPlanningIdentityWatermarks: input.payload.currentPlanningIdentityWatermarks,
494
501
  currentAiProfileIds: input.payload.currentAiProfileIds,
495
502
  currentAiProfileWatermarks: input.payload.currentAiProfileWatermarks,
496
503
  currentAiProfileChangeKeys: input.payload.currentAiProfileChangeKeys ?? new Map(),
@@ -583,6 +590,7 @@ export async function runWorkspacePushSyncService(input) {
583
590
  currentInitiativeWatermarks: input.payload.currentInitiativeWatermarks,
584
591
  currentWorkstreamIds: input.payload.currentWorkstreamIds,
585
592
  currentWorkstreamWatermarks: input.payload.currentWorkstreamWatermarks,
593
+ currentPlanningIdentityWatermarks: input.payload.currentPlanningIdentityWatermarks,
586
594
  currentAiProfileIds: input.payload.currentAiProfileIds,
587
595
  currentAiProfileWatermarks: input.payload.currentAiProfileWatermarks,
588
596
  currentAiProfileChangeKeys: input.payload.currentAiProfileChangeKeys ?? new Map(),
@@ -670,8 +678,18 @@ export async function runWorkspacePushSyncService(input) {
670
678
  && acknowledgedNonApplyingBatchOperationIdentities.size !== requestedAcknowledgements.length) {
671
679
  throw new Error('Persisted V2 push batch acknowledgement state does not match the frozen push plan.');
672
680
  }
681
+ const requestedSettledBatchOperationIdentities = input.settledBatchOperationIdentities || [];
682
+ if ((requestedSettledBatchOperationIdentities.length > 0
683
+ && !input.onAcceptedBatchSettled)
684
+ || new Set(requestedSettledBatchOperationIdentities).size
685
+ !== requestedSettledBatchOperationIdentities.length
686
+ || requestedSettledBatchOperationIdentities.some((identity) => !batchOperationIdentities.includes(identity))) {
687
+ throw new Error('Persisted V2 push batch settlement state does not match the frozen push plan.');
688
+ }
689
+ const settledBatchOperationIdentities = new Set(requestedSettledBatchOperationIdentities);
673
690
  let completedBatchCount = 0;
674
691
  let completedChangeCount = 0;
692
+ let firstPushFailure = null;
675
693
  const pushTransferReceipts = [];
676
694
  const abandonRetainedPushReceipts = async (errorCode) => {
677
695
  if (pushTransferReceipts.length === 0)
@@ -689,7 +707,8 @@ export async function runWorkspacePushSyncService(input) {
689
707
  const safeBatchChanges = batch.map((entry) => entry.safe);
690
708
  const expectedTaskEchoIds = workspaceSyncEngineExpectedTaskEchoIds(plainBatchChanges);
691
709
  const idempotencyKey = batchOperationIdentities[batchIndex];
692
- if (acknowledgedNonApplyingBatchOperationIdentities.has(idempotencyKey)) {
710
+ if (settledBatchOperationIdentities.has(idempotencyKey)
711
+ || acknowledgedNonApplyingBatchOperationIdentities.has(idempotencyKey)) {
693
712
  completedBatchCount += 1;
694
713
  completedChangeCount += plainBatchChanges.length;
695
714
  continue;
@@ -732,7 +751,12 @@ export async function runWorkspacePushSyncService(input) {
732
751
  const data = asObjectRecord(pushResult.data);
733
752
  const failedOperations = Array.from(new Set(plainBatchChanges.map((change) => change.op)));
734
753
  const failedContentChanges = plainBatchChanges.filter(isWorkspacePushContentChange).length;
735
- return {
754
+ const failureDomain = failedContentChanges === plainBatchChanges.length
755
+ ? 'content'
756
+ : failedContentChanges === 0
757
+ ? 'metadata'
758
+ : 'mixed';
759
+ const failureResult = {
736
760
  success: false,
737
761
  status: pushResult.status,
738
762
  error: typeof data.error === 'string' ? data.error : undefined,
@@ -744,11 +768,7 @@ export async function runWorkspacePushSyncService(input) {
744
768
  failedBatchIndex: batchIndex,
745
769
  failedChangeCount: plainBatchChanges.length,
746
770
  failedOperations,
747
- failureDomain: failedContentChanges === plainBatchChanges.length
748
- ? 'content'
749
- : failedContentChanges === 0
750
- ? 'metadata'
751
- : 'mixed',
771
+ failureDomain,
752
772
  },
753
773
  retryAfterMs: pushResult.retryAfterMs,
754
774
  transient: pushInProgress || isTransientWorkspaceSyncStatus(pushResult.status),
@@ -765,6 +785,7 @@ export async function runWorkspacePushSyncService(input) {
765
785
  currentInitiativeWatermarks: input.payload.currentInitiativeWatermarks,
766
786
  currentWorkstreamIds: input.payload.currentWorkstreamIds,
767
787
  currentWorkstreamWatermarks: input.payload.currentWorkstreamWatermarks,
788
+ currentPlanningIdentityWatermarks: input.payload.currentPlanningIdentityWatermarks,
768
789
  currentAiProfileIds: input.payload.currentAiProfileIds,
769
790
  currentAiProfileWatermarks: input.payload.currentAiProfileWatermarks,
770
791
  currentAiProfileChangeKeys: input.payload.currentAiProfileChangeKeys ?? new Map(),
@@ -793,8 +814,18 @@ export async function runWorkspacePushSyncService(input) {
793
814
  pushedWatermarks: new Map(),
794
815
  pushedTaskChangeKeys: new Map(),
795
816
  emittedEventIds: [],
796
- appliedTaskUpserts: []
817
+ appliedTaskUpserts: [],
797
818
  };
819
+ firstPushFailure ||= failureResult;
820
+ // Only content is isolated from later durable projections.
821
+ // Ownership, auth, and metadata failures can invalidate phase
822
+ // dependencies, so they still stop the attempt immediately.
823
+ if (failureDomain !== 'content')
824
+ return failureResult;
825
+ // Later phases contain independent relationships, events, and
826
+ // comments. Let them settle and checkpoint their non-applying
827
+ // receipts even though this attempt reports the content failure.
828
+ continue;
798
829
  }
799
830
  const pushData = asObjectRecord(pushResult.data);
800
831
  if (Array.isArray(pushData.emittedEventIds)) {
@@ -806,7 +837,29 @@ export async function runWorkspacePushSyncService(input) {
806
837
  }
807
838
  const normalizedTaskUpserts = parseWorkspaceSyncEngineAppliedTaskUpserts(pushData, expectedTaskEchoIds);
808
839
  appliedTaskUpserts.push(...normalizedTaskUpserts);
809
- if (pushResult.transferReceipt && normalizedTaskUpserts.length === 0) {
840
+ if (input.onAcceptedBatchSettled) {
841
+ if (!pushResult.transferReceipt) {
842
+ throw new Error('Accepted V2 push batch is missing its atomic settlement receipt.');
843
+ }
844
+ await input.onAcceptedBatchSettled({
845
+ operationIdentity: idempotencyKey,
846
+ settlementIdentityFingerprint: await computeCanonicalWorkspaceSyncSha256(createWorkspaceSyncEngineV2SettlementIdentityProjection({
847
+ operationIdentity: idempotencyKey,
848
+ changes: plainBatchChanges,
849
+ appliedTaskUpserts: normalizedTaskUpserts,
850
+ excludedProjections: effectiveV2ExcludedProjections,
851
+ })),
852
+ appliedTaskUpserts: normalizedTaskUpserts,
853
+ transferReceipt: pushResult.transferReceipt,
854
+ pushBoundary,
855
+ excludedProjections: effectiveV2ExcludedProjections,
856
+ });
857
+ const receiptIndex = pushTransferReceipts.indexOf(pushResult.transferReceipt);
858
+ if (receiptIndex >= 0)
859
+ pushTransferReceipts.splice(receiptIndex, 1);
860
+ settledBatchOperationIdentities.add(idempotencyKey);
861
+ }
862
+ else if (pushResult.transferReceipt && normalizedTaskUpserts.length === 0) {
810
863
  await remoteServices.acknowledgeNonApplyingTransferReceipts({
811
864
  workspaceId: input.workspaceId,
812
865
  receipts: [pushResult.transferReceipt],
@@ -828,6 +881,17 @@ export async function runWorkspacePushSyncService(input) {
828
881
  await abandonRetainedPushReceipts('WORKSPACE_SYNC_V2_PUSH_ATTEMPT_FAILED');
829
882
  throw error;
830
883
  }
884
+ if (firstPushFailure) {
885
+ return {
886
+ ...firstPushFailure,
887
+ batchProgress: {
888
+ ...firstPushFailure.batchProgress,
889
+ completedBatches: completedBatchCount,
890
+ completedChanges: completedChangeCount,
891
+ },
892
+ requestMs,
893
+ };
894
+ }
831
895
  return {
832
896
  success: true,
833
897
  syncedAt: new Date().toISOString(),
@@ -855,6 +919,7 @@ export async function runWorkspacePushSyncService(input) {
855
919
  currentInitiativeWatermarks: input.payload.currentInitiativeWatermarks,
856
920
  currentWorkstreamIds: input.payload.currentWorkstreamIds,
857
921
  currentWorkstreamWatermarks: input.payload.currentWorkstreamWatermarks,
922
+ currentPlanningIdentityWatermarks: input.payload.currentPlanningIdentityWatermarks,
858
923
  currentAiProfileIds: input.payload.currentAiProfileIds,
859
924
  currentAiProfileWatermarks: input.payload.currentAiProfileWatermarks,
860
925
  currentAiProfileChangeKeys: input.payload.currentAiProfileChangeKeys ?? new Map(),
@@ -0,0 +1,16 @@
1
+ import type { WorkspaceSyncTaskforceAgentSnapshot } from './workspaceSyncModel.js';
2
+ type SyncAuthorizationError = Error & {
3
+ code?: string;
4
+ statusCode?: number;
5
+ details?: Record<string, unknown>;
6
+ };
7
+ export declare function assertTaskforceAgentSyncPushAccess(input: {
8
+ agents: Iterable<WorkspaceSyncTaskforceAgentSnapshot>;
9
+ actorUserId: string | null;
10
+ hasUserFeatureGrant: (userId: string, featureKey: unknown) => boolean;
11
+ createSyncRouteError: (message: string, details: Record<string, unknown>, options?: {
12
+ code?: string;
13
+ statusCode?: number;
14
+ }) => SyncAuthorizationError;
15
+ }): void;
16
+ export {};
@@ -0,0 +1,20 @@
1
+ import { getTaskforceAgentModel } from '../shared/taskforceAgentModels.js';
2
+ import { INTERNAL_SUBSCRIPTION_MODEL_FEATURE_KEY } from '../shared/userFeatureGrants.js';
3
+ export function assertTaskforceAgentSyncPushAccess(input) {
4
+ const actorUserId = String(input.actorUserId || '').trim();
5
+ for (const agent of input.agents) {
6
+ if (agent.deletedAt)
7
+ continue;
8
+ const modelKey = String(agent.definition?.model?.modelKey || agent.modelKey || '').trim();
9
+ if (getTaskforceAgentModel(modelKey)?.source !== 'subscription_dev')
10
+ continue;
11
+ if (actorUserId && input.hasUserFeatureGrant(actorUserId, INTERNAL_SUBSCRIPTION_MODEL_FEATURE_KEY))
12
+ continue;
13
+ throw input.createSyncRouteError(`Subscription-backed Taskforce Agent ${agent.id} requires an internal user grant.`, {
14
+ source: 'apply.taskforceAgentUpsert',
15
+ agentId: agent.id,
16
+ actorUserId: actorUserId || null,
17
+ featureKey: INTERNAL_SUBSCRIPTION_MODEL_FEATURE_KEY,
18
+ }, { code: 'SUBSCRIPTION_MODEL_ACCESS_REQUIRED', statusCode: 403 });
19
+ }
20
+ }
@@ -4,6 +4,7 @@ import { WORKSPACE_SYNC_V3_NESTED_COVERAGE_SELECTOR } from './workspaceSyncV3Nes
4
4
  import { WORKSPACE_SYNC_V3_WORKFLOW_COVERAGE_SELECTOR } from './workspaceSyncV3WorkflowWireContract.js';
5
5
  import { WORKSPACE_SYNC_V3_PLANNING_ORDER_COVERAGE_SELECTOR } from './workspaceSyncV3PlanningOrderWireContract.js';
6
6
  import { WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_SELECTOR } from './workspaceSyncV3TaskCoverWireContract.js';
7
+ import { WORKSPACE_SYNC_V3_WORKFLOW_TASK_COVER_COVERAGE_SELECTOR } from './workspaceSyncV3WorkflowTaskCoverWireContract.js';
7
8
  export { WORKSPACE_SYNC_V3_COMBINED_CAPABILITY_VERSION } from './workspaceSyncV3CombinedWireContract.js';
8
9
  export function resolveRequestedCombinedFeedCoverage(env = process.env) {
9
10
  const requestedVersion = String(env.TASKFORCE_SYNC_V3_COMBINED_FEED_COVERAGE_VERSION || '').trim();
@@ -22,6 +23,9 @@ export function resolveRequestedCombinedFeedCoverage(env = process.env) {
22
23
  if (requestedVersion === String(WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_SELECTOR.coverageVersion)) {
23
24
  return WORKSPACE_SYNC_V3_TASK_COVER_COVERAGE_SELECTOR;
24
25
  }
26
+ if (requestedVersion === String(WORKSPACE_SYNC_V3_WORKFLOW_TASK_COVER_COVERAGE_SELECTOR.coverageVersion)) {
27
+ return WORKSPACE_SYNC_V3_WORKFLOW_TASK_COVER_COVERAGE_SELECTOR;
28
+ }
25
29
  throw new Error(`Unsupported TASKFORCE_SYNC_V3_COMBINED_FEED_COVERAGE_VERSION: ${requestedVersion}.`);
26
30
  }
27
31
  export function resolveCombinedFeedCapability(input) {
@@ -7,6 +7,7 @@ import { enqueueLocalInitiativeMutation, } from './localInitiativeOutboxService.
7
7
  import { isWorkspaceSyncV3PlanningActivationEnabled } from './planningActivation.js';
8
8
  import { serializeEntityActivityForSync } from './taskActivityJournal.js';
9
9
  import { WorkspaceSyncDurabilityStore, WorkspaceSyncIdempotencyConflictError } from './syncDurabilityStore.js';
10
+ import { readDurableOperationReplay } from './durableOperationReplay.js';
10
11
  import { buildInitiativeActivityEventId } from './initiativeActivityIdentity.js';
11
12
  const OPERATION_LEASE_MS = 30_000;
12
13
  export class DurableInitiativeMutationRouterDisabledError extends Error {
@@ -85,6 +86,9 @@ export function createDurableInitiativeMutationRouter(input) {
85
86
  if (persistedOutbox.domain !== 'initiative' || persistedOutbox.entityId !== initiativeId) {
86
87
  throw new WorkspaceSyncIdempotencyConflictError();
87
88
  }
89
+ store.assertOutboxOperationIdentity(persistedOutbox, {
90
+ domain: 'initiative', entityId: initiativeId, mutationKind: persistedOutbox.mutationKind,
91
+ });
88
92
  return {
89
93
  revisions: {
90
94
  entityRevision: persistedOutbox.baseEntityRevision,
@@ -99,18 +103,22 @@ export function createDurableInitiativeMutationRouter(input) {
99
103
  if (operationState?.status === 'committed') {
100
104
  if (!operationState.responseJson)
101
105
  throw new Error('Committed operation is missing its response.');
102
- const response = JSON.parse(operationState.responseJson);
103
- if (response.authoritative.entityId !== initiativeId) {
104
- throw new WorkspaceSyncIdempotencyConflictError();
105
- }
106
- const lifecycleMutation = response.authoritative.mutationKind === 'archive'
107
- || response.authoritative.mutationKind === 'unarchive';
106
+ const parsed = JSON.parse(operationState.responseJson);
107
+ const lifecycleMutation = parsed.authoritative.mutationKind === 'archive'
108
+ || parsed.authoritative.mutationKind === 'unarchive';
109
+ const replay = readDurableOperationReplay({
110
+ responseJson: operationState.responseJson,
111
+ operationId,
112
+ domain: 'initiative',
113
+ entityId: initiativeId,
114
+ mutationKind: parsed.authoritative.mutationKind,
115
+ revisionMode: lifecycleMutation ? 'both' : 'metadata',
116
+ });
117
+ const response = replay.response;
108
118
  return {
109
119
  revisions: {
110
- entityRevision: String(BigInt(response.authoritative.entityRevision) - 1n),
111
- lifecycleRevision: lifecycleMutation
112
- ? String(BigInt(response.authoritative.lifecycleRevision) - 1n)
113
- : response.authoritative.lifecycleRevision,
120
+ entityRevision: replay.baseEntityRevision,
121
+ lifecycleRevision: replay.baseLifecycleRevision,
114
122
  },
115
123
  persistedOutbox: null,
116
124
  committedResponse: response,
@@ -15,6 +15,20 @@ export declare class DurableOperationReplayIdentityConflictError extends Error {
15
15
  readonly code = "DURABLE_OPERATION_REPLAY_IDENTITY_CONFLICT";
16
16
  constructor(message?: string);
17
17
  }
18
+ export interface DurableOperationIdentityRecord {
19
+ operationId: string;
20
+ domain: string;
21
+ entityId: string;
22
+ mutationKind: string;
23
+ payloadFingerprint: string;
24
+ }
25
+ /**
26
+ * Canonical identity comparison for durable mutation records. Storage lanes may
27
+ * retain different reservation metadata, but an accepted operation can have
28
+ * only one exact domain/entity/mutation/payload meaning.
29
+ */
30
+ export declare function assertDurableOperationIdentity(actual: Readonly<DurableOperationIdentityRecord>, expected: Readonly<DurableOperationIdentityRecord>): void;
31
+ export declare function assertDurableOperationFingerprint(actual: string, expected: string): void;
18
32
  export interface DurableOperationReplayResult<Payload = unknown> {
19
33
  response: Readonly<Record<string, unknown>>;
20
34
  authoritative: DurableOperationAuthoritativeEntry<Payload>;
@@ -12,6 +12,24 @@ export class DurableOperationReplayIdentityConflictError extends Error {
12
12
  this.name = 'DurableOperationReplayIdentityConflictError';
13
13
  }
14
14
  }
15
+ /**
16
+ * Canonical identity comparison for durable mutation records. Storage lanes may
17
+ * retain different reservation metadata, but an accepted operation can have
18
+ * only one exact domain/entity/mutation/payload meaning.
19
+ */
20
+ export function assertDurableOperationIdentity(actual, expected) {
21
+ if (actual.operationId !== expected.operationId
22
+ || actual.domain !== expected.domain
23
+ || actual.entityId !== expected.entityId
24
+ || actual.mutationKind !== expected.mutationKind
25
+ || actual.payloadFingerprint !== expected.payloadFingerprint) {
26
+ throw new DurableOperationReplayIdentityConflictError();
27
+ }
28
+ }
29
+ export function assertDurableOperationFingerprint(actual, expected) {
30
+ if (!actual || actual !== expected)
31
+ throw new DurableOperationReplayIdentityConflictError();
32
+ }
15
33
  const DEFAULT_MAX_AUTHORITATIVE_ENTRIES = 1_024;
16
34
  const POSITIVE_REVISION = /^[1-9]\d*$/;
17
35
  const NON_NEGATIVE_REVISION = /^(0|[1-9]\d*)$/;
@@ -150,6 +150,9 @@ export function createDurableTaskAttachmentLinksMutationRouter(input) {
150
150
  || String(payload.cardCoverAssetId || '') !== String(cardCoverAssetId || '')) {
151
151
  throw new DurableTaskAttachmentLinksMutationError('Operation identity is assigned to different task attachment links.', 'TASK_ATTACHMENT_LINKS_IDENTITY_CONFLICT', 409);
152
152
  }
153
+ store.assertOutboxOperationIdentity(existing, {
154
+ domain: 'task-attachment-links', entityId: taskId, mutationKind: 'replace',
155
+ });
153
156
  const task = input.core.getTask(taskId, workspaceId);
154
157
  if (!task)
155
158
  throw new DurableTaskAttachmentLinksMutationError('Task not found.', 'TASK_NOT_FOUND', 404);
@@ -1,7 +1,7 @@
1
1
  import type { ChecklistItem, TaskItem } from '../../core/Taskforce.js';
2
2
  import type { DatabaseAdapter } from '../../storage/databaseAdapter.js';
3
3
  import { type LocalTaskChecklistOutboxCore } from './localTaskChecklistOutboxService.js';
4
- import { type DurableTaskChecklistServiceCore } from './taskChecklistMutationService.js';
4
+ import { type DurableTaskChecklistServiceCore, type TaskChecklistItemUpdateIntent } from './taskChecklistMutationService.js';
5
5
  export declare function resolveTaskChecklistMutationCapability(input: {
6
6
  runtimeMode: 'local' | 'cloud';
7
7
  surface: 'http' | 'mcp';
@@ -40,6 +40,7 @@ export declare function createDurableTaskChecklistMutationRouter(input: {
40
40
  taskId: string;
41
41
  items: readonly Partial<ChecklistItem>[];
42
42
  expectedDetailRevision?: string;
43
+ itemUpdateIntent?: TaskChecklistItemUpdateIntent;
43
44
  }): {
44
45
  state: "pending" | "committed";
45
46
  route: "local-outbox" | "cloud-acceptance";
@@ -1,7 +1,7 @@
1
1
  import { canonicalWorkspaceSyncJson } from './canonicalWorkspaceSyncJson.js';
2
2
  import { LocalSyncIdentityStore } from './localSyncIdentityStore.js';
3
3
  import { enqueueLocalTaskChecklistMutation, } from './localTaskChecklistOutboxService.js';
4
- import { DurableTaskChecklistMutationError, runDurableTaskChecklistReplace, } from './taskChecklistMutationService.js';
4
+ import { DurableTaskChecklistMutationError, runDurableTaskChecklistReplace, validateTaskChecklistItemUpdateIntent, } from './taskChecklistMutationService.js';
5
5
  import { WorkspaceSyncDurabilityStore, WorkspaceSyncEntityBusyError } from './syncDurabilityStore.js';
6
6
  import { serializeWorkspaceSyncV3TaskChecklistPayload } from './workspaceSyncV3NestedTaskCodecs.js';
7
7
  const OPERATION_LEASE_MS = 30_000;
@@ -82,6 +82,18 @@ export function createDurableTaskChecklistMutationRouter(input) {
82
82
  catch (error) {
83
83
  throw new DurableTaskChecklistMutationError(error instanceof Error ? error.message : 'Task checklist is invalid.', 'TASK_CHECKLIST_INVALID', 400);
84
84
  }
85
+ const itemUpdateIntent = args.itemUpdateIntent
86
+ ? validateTaskChecklistItemUpdateIntent(args.itemUpdateIntent)
87
+ : undefined;
88
+ if (itemUpdateIntent) {
89
+ const target = items.find((item) => item.id === itemUpdateIntent.itemId);
90
+ if (!target
91
+ || (itemUpdateIntent.patch.text !== undefined && target.title !== itemUpdateIntent.patch.text)
92
+ || (itemUpdateIntent.patch.done !== undefined && target.isCompleted !== itemUpdateIntent.patch.done)
93
+ || (itemUpdateIntent.patch.order !== undefined && target.order !== itemUpdateIntent.patch.order)) {
94
+ throw new DurableTaskChecklistMutationError('Task checklist item update intent does not match the replacement aggregate.', 'TASK_CHECKLIST_INVALID', 400);
95
+ }
96
+ }
85
97
  const acceptedAt = now();
86
98
  const acceptedAtIso = acceptedAt.toISOString();
87
99
  const operationId = operationIdRequired(input.operationId);
@@ -109,25 +121,43 @@ export function createDurableTaskChecklistMutationRouter(input) {
109
121
  catch {
110
122
  throw new DurableTaskChecklistMutationError('Captured task checklist payload is invalid.', 'TASK_CHECKLIST_IDENTITY_CONFLICT', 409);
111
123
  }
112
- if (canonicalWorkspaceSyncJson(frozen) !== canonicalWorkspaceSyncJson(items)) {
124
+ const capturedIntent = payload.itemUpdateIntent
125
+ ? validateTaskChecklistItemUpdateIntent(payload.itemUpdateIntent)
126
+ : undefined;
127
+ const requestedIntent = itemUpdateIntent;
128
+ if (capturedIntent || requestedIntent
129
+ ? canonicalWorkspaceSyncJson(capturedIntent) !== canonicalWorkspaceSyncJson(requestedIntent)
130
+ : canonicalWorkspaceSyncJson(frozen) !== canonicalWorkspaceSyncJson(items)) {
113
131
  throw new DurableTaskChecklistMutationError('Operation identity is assigned to a different task checklist.', 'TASK_CHECKLIST_IDENTITY_CONFLICT', 409);
114
132
  }
133
+ if ((payload.expectedDetailRevision || undefined) !== (args.expectedDetailRevision || undefined)) {
134
+ throw new DurableTaskChecklistMutationError('Operation identity is assigned to a different task checklist precondition.', 'TASK_CHECKLIST_IDENTITY_CONFLICT', 409);
135
+ }
136
+ store.assertOutboxOperationIdentity(existing, {
137
+ domain: 'task-checklist', entityId: taskId, mutationKind: 'replace',
138
+ });
115
139
  const task = input.core.getTask(taskId, workspaceId);
116
140
  if (!task)
117
141
  throw new DurableTaskChecklistMutationError('Task not found.', 'TASK_NOT_FOUND', 404);
118
142
  const installed = serializeWorkspaceSyncV3TaskChecklistPayload({
119
143
  taskId, items: task.checklistItems || [],
120
144
  }).items;
121
- if (canonicalWorkspaceSyncJson(installed) !== canonicalWorkspaceSyncJson(frozen)) {
145
+ if (!capturedIntent
146
+ && canonicalWorkspaceSyncJson(installed) !== canonicalWorkspaceSyncJson(frozen)) {
122
147
  throw new DurableTaskChecklistMutationError('Captured task checklist does not match local state.', 'TASK_CHECKLIST_IDENTITY_CONFLICT', 409);
123
148
  }
124
- return { state: 'pending', route: 'local-outbox', operationId, task };
149
+ return {
150
+ state: 'pending', route: 'local-outbox', operationId,
151
+ task: capturedIntent ? { ...task, checklistItems: frozen } : task,
152
+ };
125
153
  }
126
154
  let result;
127
155
  try {
128
156
  result = enqueueLocalTaskChecklistMutation({
129
157
  store, core: input.core, identity, taskId, items, now: acceptedAtIso,
130
158
  actorRef, onPostCommitError: input.onPostCommitError,
159
+ expectedDetailRevision: args.expectedDetailRevision,
160
+ itemUpdateIntent,
131
161
  requireV3CombinedOwnership: persistedOwnershipChecked,
132
162
  });
133
163
  }
@@ -142,6 +172,7 @@ export function createDurableTaskChecklistMutationRouter(input) {
142
172
  return { state: 'pending', route: 'local-outbox', operationId, task };
143
173
  }
144
174
  const committed = store.readCommittedOperationResponse(identity);
175
+ let coordinates;
145
176
  if (committed) {
146
177
  let response;
147
178
  try {
@@ -150,27 +181,33 @@ export function createDurableTaskChecklistMutationRouter(input) {
150
181
  catch {
151
182
  throw new DurableTaskChecklistMutationError('Committed task checklist response is invalid.', 'TASK_CHECKLIST_IDENTITY_CONFLICT', 409);
152
183
  }
184
+ const projection = response.authoritative?.checklist;
185
+ const acceptedRevision = String(projection?.entityRevision || '');
186
+ const lifecycleRevision = String(projection?.lifecycleRevision || '');
153
187
  if (response.workspaceId !== workspaceId || response.clientId !== clientId
154
188
  || response.operationId !== operationId || response.authoritative?.root?.entityId !== taskId
155
- || response.authoritative?.checklist?.entityId !== taskId
156
- || canonicalWorkspaceSyncJson(response.authoritative.checklist.payload?.items || [])
157
- !== canonicalWorkspaceSyncJson(items)) {
189
+ || projection?.entityId !== taskId
190
+ || !/^[1-9]\d*$/.test(acceptedRevision)
191
+ || !/^(0|[1-9]\d*)$/.test(lifecycleRevision)) {
158
192
  throw new DurableTaskChecklistMutationError('Operation identity is assigned to a different task checklist.', 'TASK_CHECKLIST_IDENTITY_CONFLICT', 409);
159
193
  }
160
- const task = input.core.getTask(taskId, workspaceId);
161
- if (!task)
162
- throw new DurableTaskChecklistMutationError('Task not found.', 'TASK_NOT_FOUND', 404);
163
- return { state: 'committed', route: 'cloud-acceptance', operationId, task };
194
+ coordinates = {
195
+ entityRevision: String(BigInt(acceptedRevision) - 1n),
196
+ lifecycleRevision,
197
+ };
198
+ }
199
+ else {
200
+ coordinates = store.readEntityRevisionCoordinates({
201
+ tenantId, workspaceId, domain: 'task-checklist', entityId: taskId,
202
+ });
164
203
  }
165
- const coordinates = store.readEntityRevisionCoordinates({
166
- tenantId, workspaceId, domain: 'task-checklist', entityId: taskId,
167
- });
168
204
  const result = runDurableTaskChecklistReplace({
169
205
  store, core: input.core, tenantId, workspaceId, clientId, operationId, taskId, items,
170
206
  baseEntityRevision: coordinates.entityRevision, baseLifecycleRevision: coordinates.lifecycleRevision,
171
207
  now: acceptedAtIso, leaseExpiresAt: new Date(acceptedAt.getTime() + OPERATION_LEASE_MS).toISOString(),
172
208
  actorRef, onPostCommitError: input.onPostCommitError,
173
209
  expectedDetailRevision: args.expectedDetailRevision,
210
+ itemUpdateIntent,
174
211
  assertPrecondition: args.expectedDetailRevision
175
212
  ? () => input.core.assertTaskDetailRevisionForUpdate(taskId, args.expectedDetailRevision, workspaceId)
176
213
  : undefined,
@@ -180,7 +217,13 @@ export function createDurableTaskChecklistMutationRouter(input) {
180
217
  const task = input.core.getTask(taskId, workspaceId);
181
218
  if (!task)
182
219
  throw new DurableTaskChecklistMutationError('Task not found.', 'TASK_NOT_FOUND', 404);
183
- return { state: 'committed', route: 'cloud-acceptance', operationId, task };
220
+ return {
221
+ state: 'committed', route: 'cloud-acceptance', operationId,
222
+ task: {
223
+ ...task,
224
+ checklistItems: result.response.authoritative.checklist.payload.items,
225
+ },
226
+ };
184
227
  },
185
228
  };
186
229
  }
@@ -113,6 +113,9 @@ export function createDurableTaskCommentMutationRouter(input) {
113
113
  if (!sameCommentRetryIntent(existingPayload.comment, canonical)) {
114
114
  throw new DurableTaskCommentMutationError('Operation identity is assigned to a different task comment.', 'TASK_COMMENT_IDENTITY_CONFLICT', 409);
115
115
  }
116
+ store.assertOutboxOperationIdentity(existing, {
117
+ domain: 'task-comments', entityId: taskId, mutationKind: 'append',
118
+ });
116
119
  const frozenComment = serializeWorkspaceSyncV3TaskCommentsPayload({
117
120
  taskId, comments: [existingPayload.comment],
118
121
  }).comments[0];
@@ -38,5 +38,5 @@ export declare function createDurableTaskHttpRootMutationRouter(input: {
38
38
  restore(deletedRecordIdInput: string, restoreDestination?: TaskRestoreDestination): TaskItem;
39
39
  delete(taskIdInput: string): DeletedTaskRecord;
40
40
  };
41
- type TaskforceCoreForHttpRootMutation = Pick<import('../../core/Taskforce.js').TaskforceCore, 'getDatabaseAdapter' | 'getTask' | 'getTaskDetailRevision' | 'assertTaskDetailRevisionForUpdate' | 'listAssignableActors' | 'getDeletedTask' | 'updateTask' | 'hasTaskDeletionMarkerForSync' | 'createTask' | 'listTaskAttachmentLinksForDurableSync' | 'resolveTaskAttachmentLinksForDurableSync' | 'normalizeTaskAttachmentDescriptorsForDurableSync' | 'notifyDurableTaskCreateCommitted' | 'notifyDurableTaskBatchCommitted' | 'notifyDurableTaskMetadataCommitted' | 'notifyDurableTaskLifecycleCommitted' | 'notifyDurableTaskDeleteCommitted' | 'getTaskEventForSync' | 'getEntityEventForSync' | 'lockTaskLifecycleMutationDomain' | 'archiveTask' | 'unarchiveTask' | 'restoreDeletedTask' | 'addTaskStatusEventsForDurableSync' | 'lockTaskRelationshipMutationDomain' | 'listTaskRelationships' | 'getTaskRelationshipForSync' | 'deleteTaskForSync'>;
41
+ type TaskforceCoreForHttpRootMutation = Pick<import('../../core/Taskforce.js').TaskforceCore, 'getDatabaseAdapter' | 'getTask' | 'getTaskDetailRevision' | 'assertTaskDetailRevisionForUpdate' | 'listAssignableActors' | 'getDeletedTask' | 'updateTask' | 'hasTaskDeletionMarkerForSync' | 'createTask' | 'listTaskAttachmentLinksForDurableSync' | 'resolveTaskAttachmentLinksForDurableSync' | 'normalizeTaskAttachmentDescriptorsForDurableSync' | 'notifyDurableTaskCreateCommitted' | 'notifyDurableTaskBatchCommitted' | 'notifyDurableTaskMetadataCommitted' | 'notifyDurableTaskLifecycleCommitted' | 'notifyDurableTaskDeleteCommitted' | 'getTaskEventForSync' | 'getEntityEventForSync' | 'lockTaskLifecycleMutationDomain' | 'archiveTask' | 'unarchiveTask' | 'restoreDeletedTask' | 'addTaskStatusEventsForDurableSync' | 'addTaskCommentEventForDurableSync' | 'lockTaskRelationshipMutationDomain' | 'listTaskRelationships' | 'getTaskRelationshipForSync' | 'deleteTaskForSync'>;
42
42
  export {};
@@ -2,6 +2,7 @@ import { selectDurableTaskMetadataPatch } from '../../core/TaskDurableSyncMutati
2
2
  import { prepareTaskDeleteForDurableSync } from '../../core/TaskDurableDeleteMutationService.js';
3
3
  import { selectTaskCreateActivationInput } from './taskCreateActivation.js';
4
4
  import { resolveTaskAttachmentLinksMutationCapability } from './durableTaskAttachmentLinksMutationRouter.js';
5
+ import { areWorkflowRuntimeMutationsFenced, resolveWorkflowRuntimeDurableTransportCapability, } from './durableWorkflowRuntimeMutationRouter.js';
5
6
  import { runDurableTaskCreate } from './taskCreateMutationService.js';
6
7
  import { runDurableTaskDelete } from './taskDeleteMutationService.js';
7
8
  import { runDurableTaskLifecycleMutation } from './taskLifecycleMutationService.js';
@@ -59,6 +60,13 @@ export function createDurableTaskHttpRootMutationRouter(input) {
59
60
  surface: 'http',
60
61
  env: input.env,
61
62
  });
63
+ const workflowRuntimeJournalEnabled = resolveWorkflowRuntimeDurableTransportCapability({
64
+ runtimeMode: input.runtimeMode,
65
+ surface: 'http',
66
+ env: input.env,
67
+ });
68
+ const rejectWorkflowRuntimeActivation = workflowRuntimeJournalEnabled
69
+ && areWorkflowRuntimeMutationsFenced(input.env);
62
70
  const store = new WorkspaceSyncDurabilityStore(input.core.getDatabaseAdapter());
63
71
  const now = input.now || (() => new Date());
64
72
  const notificationMethods = new Set([
@@ -237,6 +245,8 @@ export function createDurableTaskHttpRootMutationRouter(input) {
237
245
  now: operation.acceptedAtIso,
238
246
  leaseExpiresAt: new Date(operation.acceptedAt.getTime() + OPERATION_LEASE_MS).toISOString(),
239
247
  actorRef: input.actorRef,
248
+ includeWorkflowRuntimeJournal: workflowRuntimeJournalEnabled,
249
+ rejectWorkflowRuntimeActivation,
240
250
  expectedDetailRevision,
241
251
  assertPrecondition: detailRevisionPrecondition(taskId, expectedDetailRevision),
242
252
  onPostCommitError: input.onPostCommitError,
@@ -185,6 +185,11 @@ export function createDurableTaxonomyMutationRouter(input) {
185
185
  if (!sameTaxonomyState(storedPayload.state, canonicalState) || !Array.isArray(storedPayload.taskPatches)) {
186
186
  throw new WorkspaceSyncIdempotencyConflictError();
187
187
  }
188
+ store.assertOutboxOperationIdentity(existingOutbox, {
189
+ domain: WORKSPACE_SYNC_TAXONOMY_DOMAIN,
190
+ entityId: WORKSPACE_SYNC_TAXONOMY_ENTITY_ID,
191
+ mutationKind: WORKSPACE_SYNC_TAXONOMY_REPLACE_WITH_REMAPS,
192
+ });
188
193
  enqueueLocalTaxonomyCompositeReplacement({
189
194
  store,
190
195
  core: input.core,