@taskforcehq/taskforce 0.3.328 → 0.3.330

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (485) hide show
  1. package/dist/Taskforce.module.css +523 -79
  2. package/dist/TaskforceCore.js +237 -230
  3. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
  4. package/dist/cli.js +34 -0
  5. package/dist/cliCloudTargetGuard.d.ts +5 -0
  6. package/dist/cliCloudTargetGuard.js +11 -0
  7. package/dist/components/features/AiProfilesModule.js +3 -5
  8. package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
  9. package/dist/components/features/TaskSettings.d.ts +12 -1
  10. package/dist/components/features/TaskSettings.js +217 -54
  11. package/dist/components/features/TaskforceAgentsModule.d.ts +1 -2
  12. package/dist/components/features/TaskforceAgentsModule.js +586 -116
  13. package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
  14. package/dist/components/features/agentConnections/AgentConnectionControl.d.ts +15 -0
  15. package/dist/components/features/agentConnections/AgentConnectionControl.js +125 -0
  16. package/dist/components/features/agentConnections/ModelConnectionsPanel.d.ts +18 -0
  17. package/dist/components/features/agentConnections/ModelConnectionsPanel.js +393 -0
  18. package/dist/components/features/agentConnections/modelConnectionsApi.d.ts +65 -0
  19. package/dist/components/features/agentConnections/modelConnectionsApi.js +129 -0
  20. package/dist/components/features/planning/PlanningModule.js +2 -5
  21. package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
  22. package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
  23. package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
  24. package/dist/components/features/planning/planningTaskArrangement.js +5 -5
  25. package/dist/components/features/taskforceAgentAssignments/AgentBehaviorAssignments.js +15 -24
  26. package/dist/components/features/taskforceAgentEditorModel.d.ts +2 -1
  27. package/dist/components/features/taskforceAgentEditorModel.js +5 -1
  28. package/dist/components/features/workflowManager/workflowManagerApi.d.ts +1 -1
  29. package/dist/components/features/workflowManager/workflowManagerApi.js +3 -0
  30. package/dist/components/task/TaskCard.d.ts +5 -0
  31. package/dist/components/task/TaskCard.js +65 -10
  32. package/dist/components/task/TaskImageReviews.js +14 -5
  33. package/dist/components/task/TaskKanban.d.ts +6 -1
  34. package/dist/components/task/TaskKanban.js +152 -6
  35. package/dist/components/task/TaskList.d.ts +5 -0
  36. package/dist/components/task/TaskList.js +3 -3
  37. package/dist/components/task/TaskWorkflowAssignmentField.js +68 -10
  38. package/dist/components/ui/PasswordInput.d.ts +6 -0
  39. package/dist/components/ui/PasswordInput.js +11 -0
  40. package/dist/components/ui/TopNoticeLayer.js +1 -1
  41. package/dist/components/views/AppShellHeader.js +32 -11
  42. package/dist/components/views/PlanComparisonPage.js +12 -0
  43. package/dist/components/views/StandaloneLayout.js +32 -55
  44. package/dist/components/views/WidgetView.js +3 -3
  45. package/dist/components/views/panels/PlanningDrawer.js +5 -12
  46. package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
  47. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +4 -3
  48. package/dist/components/views/standalone/modals/SyncStatusModal.js +33 -38
  49. package/dist/config/envSchema.js +60 -1
  50. package/dist/config/localServiceRuntimeContract.d.ts +13 -0
  51. package/dist/config/localServiceRuntimeContract.js +135 -0
  52. package/dist/core/AiProfileService.js +46 -8
  53. package/dist/core/DeletedTaskLifecycleService.d.ts +1 -0
  54. package/dist/core/DeletedTaskLifecycleService.js +37 -6
  55. package/dist/core/McpTokenService.d.ts +23 -1
  56. package/dist/core/McpTokenService.js +93 -10
  57. package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +3 -2
  58. package/dist/core/TaskAttachmentLinksDurableMutationService.js +33 -9
  59. package/dist/core/TaskChecklistCommandService.d.ts +27 -0
  60. package/dist/core/TaskChecklistCommandService.js +83 -5
  61. package/dist/core/TaskLifecycleCommandService.d.ts +3 -1
  62. package/dist/core/TaskLifecycleCommandService.js +6 -2
  63. package/dist/core/Taskforce.d.ts +94 -2
  64. package/dist/core/Taskforce.js +760 -36
  65. package/dist/core/types.d.ts +14 -0
  66. package/dist/documentReviews/commandService.d.ts +2 -1
  67. package/dist/documentReviews/commandService.js +6 -3
  68. package/dist/hooks/sync/orchestratorShared.d.ts +1 -0
  69. package/dist/hooks/sync/orchestratorShared.js +2 -0
  70. package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
  71. package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
  72. package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
  73. package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
  74. package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
  75. package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.d.ts +3 -0
  76. package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.js +85 -9
  77. package/dist/hooks/sync/useSyncStatusControls.d.ts +4 -1
  78. package/dist/hooks/sync/useSyncStatusControls.js +47 -11
  79. package/dist/hooks/tasks/taskHttpMutation.js +1 -0
  80. package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
  81. package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
  82. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
  83. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
  84. package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
  85. package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
  86. package/dist/hooks/tasks/useTaskFormActions.d.ts +6 -0
  87. package/dist/hooks/tasks/useTaskFormActions.js +65 -12
  88. package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
  89. package/dist/hooks/ui/useSettingsModel.js +13 -2
  90. package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
  91. package/dist/hooks/ui/useSettingsPersistence.js +74 -47
  92. package/dist/hooks/useFilterSort.d.ts +7 -3
  93. package/dist/hooks/useFilterSort.js +15 -5
  94. package/dist/hooks/useSyncOrchestrator.d.ts +3 -0
  95. package/dist/hooks/useSyncOrchestrator.js +111 -2
  96. package/dist/hooks/useTaskData.d.ts +40 -1
  97. package/dist/hooks/useTaskData.js +240 -9
  98. package/dist/hooks/useTaskMutations.d.ts +12 -2
  99. package/dist/hooks/useTaskMutations.js +266 -52
  100. package/dist/hooks/useTaskforce.d.ts +39 -9
  101. package/dist/hooks/useTaskforce.js +359 -40
  102. package/dist/hooks/useUiNotice.d.ts +4 -0
  103. package/dist/hooks/useUiNotice.js +4 -0
  104. package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
  105. package/dist/mcp/clientRegistry.d.ts +2 -2
  106. package/dist/mcp/clientRegistry.js +1 -1
  107. package/dist/mcp/documentAssetRegistrar.js +53 -41
  108. package/dist/mcp/documentHelpers.d.ts +1 -0
  109. package/dist/mcp/documentHelpers.js +7 -3
  110. package/dist/mcp/durableTaskMutationRouter.d.ts +4 -1
  111. package/dist/mcp/durableTaskMutationRouter.js +10 -0
  112. package/dist/mcp/durableTaskRelationshipMutationRouter.js +4 -0
  113. package/dist/mcp/httpProtocolRouting.d.ts +10 -0
  114. package/dist/mcp/httpProtocolRouting.js +19 -0
  115. package/dist/mcp/localCliHealth.d.ts +2 -2
  116. package/dist/mcp/localCliHealth.js +2 -2
  117. package/dist/mcp/localServiceProxy.d.ts +1 -0
  118. package/dist/mcp/localServiceProxy.js +530 -68
  119. package/dist/mcp/planningAttachmentCommandAdapter.d.ts +3 -1
  120. package/dist/mcp/planningAttachmentCommandAdapter.js +20 -2
  121. package/dist/mcp/runtime.d.ts +54 -79
  122. package/dist/mcp/runtime.js +556 -139
  123. package/dist/mcp/taskPlanningRegistrar.js +64 -42
  124. package/dist/mcp/toolCallCompatibility.js +38 -1
  125. package/dist/mcp/toolCatalog.d.ts +1 -0
  126. package/dist/mcp/toolProfiles.d.ts +2 -0
  127. package/dist/mcp/toolProfiles.js +10 -0
  128. package/dist/mcp/toolRegistry.d.ts +1 -0
  129. package/dist/mcp/toolRegistry.js +1 -0
  130. package/dist/mcp/workflowExecutionRegistrar.js +4 -4
  131. package/dist/migrations/taskSchemaMigrations.d.ts +5 -0
  132. package/dist/migrations/taskSchemaMigrations.js +427 -0
  133. package/dist/runtime/appGateDefinitions.d.ts +30 -6
  134. package/dist/runtime/appGateDefinitions.js +6 -6
  135. package/dist/runtime/appGates.d.ts +13 -13
  136. package/dist/runtime/appGates.js +36 -13
  137. package/dist/runtime/nodeAppGates.d.ts +8 -0
  138. package/dist/runtime/nodeAppGates.js +27 -0
  139. package/dist/server/cloudCollectionRead.d.ts +1 -1
  140. package/dist/server/cloudCollectionRead.js +2 -2
  141. package/dist/server/index.d.ts +6 -0
  142. package/dist/server/index.js +123 -14
  143. package/dist/server/localDatabaseIdentity.js +4 -1
  144. package/dist/server/localServiceLease.d.ts +3 -0
  145. package/dist/server/localServiceLease.js +11 -2
  146. package/dist/server/localServiceSessions.d.ts +14 -17
  147. package/dist/server/localServiceSessions.js +308 -94
  148. package/dist/server/localWorkspaceSyncServerRuntime.js +12 -7
  149. package/dist/server/rateLimit.d.ts +1 -0
  150. package/dist/server/rateLimit.js +4 -0
  151. package/dist/server/realtimeSyncWs.js +36 -12
  152. package/dist/server/routes/admin.d.ts +4 -0
  153. package/dist/server/routes/admin.js +113 -3
  154. package/dist/server/routes/agentRoles.js +3 -2
  155. package/dist/server/routes/agentSkills.js +3 -2
  156. package/dist/server/routes/agents.d.ts +7 -0
  157. package/dist/server/routes/agents.js +394 -39
  158. package/dist/server/routes/annotatedAttachments.js +3 -2
  159. package/dist/server/routes/auth.js +3 -1
  160. package/dist/server/routes/billing.js +5 -1
  161. package/dist/server/routes/durableTaskHttpRouters.d.ts +11 -2
  162. package/dist/server/routes/executorPhaseAApprovals.d.ts +19 -0
  163. package/dist/server/routes/executorPhaseAApprovals.js +140 -0
  164. package/dist/server/routes/executorPhaseAIssuerRedemptions.d.ts +11 -0
  165. package/dist/server/routes/executorPhaseAIssuerRedemptions.js +24 -0
  166. package/dist/server/routes/githubReviewEvidence.d.ts +19 -0
  167. package/dist/server/routes/githubReviewEvidence.js +116 -0
  168. package/dist/server/routes/localService.d.ts +15 -4
  169. package/dist/server/routes/localService.js +138 -40
  170. package/dist/server/routes/modelConnections.d.ts +24 -0
  171. package/dist/server/routes/modelConnections.js +205 -0
  172. package/dist/server/routes/primitives.d.ts +2 -0
  173. package/dist/server/routes/shared.d.ts +19 -0
  174. package/dist/server/routes/shared.js +95 -19
  175. package/dist/server/routes/sync.js +1 -0
  176. package/dist/server/routes/syncAuxRoutes.js +9 -2
  177. package/dist/server/routes/syncPullApplyRoutes.js +23 -4
  178. package/dist/server/routes/syncPushRoutes.d.ts +1 -0
  179. package/dist/server/routes/syncPushRoutes.js +1 -0
  180. package/dist/server/routes/syncV3FeedRoutes.js +27 -16
  181. package/dist/server/routes/syncV3LocalCaptureRoutes.js +28 -2
  182. package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
  183. package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
  184. package/dist/server/routes/syncV3OperationRoutes.js +45 -9
  185. package/dist/server/routes/tasks.js +124 -13
  186. package/dist/server/routes/workflows.js +9 -1
  187. package/dist/server/routes/workspaces.js +43 -1
  188. package/dist/server/routes.js +59 -0
  189. package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
  190. package/dist/server/workspaceDeletionAdmission.js +50 -0
  191. package/dist/service/localServiceCli.js +16 -0
  192. package/dist/service/localServiceClientLifecycle.js +36 -10
  193. package/dist/services/codexAppServerModelGateway.d.ts +161 -0
  194. package/dist/services/codexAppServerModelGateway.js +663 -0
  195. package/dist/services/codexDeviceCodeLoginManager.d.ts +39 -0
  196. package/dist/services/codexDeviceCodeLoginManager.js +265 -0
  197. package/dist/services/codexModelProviderConnectionLifecycle.d.ts +8 -0
  198. package/dist/services/codexModelProviderConnectionLifecycle.js +73 -0
  199. package/dist/services/executorPhaseAApprovalRuntime.d.ts +14 -0
  200. package/dist/services/executorPhaseAApprovalRuntime.js +24 -0
  201. package/dist/services/executorPhaseAApprovalService.d.ts +40 -0
  202. package/dist/services/executorPhaseAApprovalService.js +609 -0
  203. package/dist/services/executorPhaseADriftEvaluator.d.ts +78 -0
  204. package/dist/services/executorPhaseADriftEvaluator.js +93 -0
  205. package/dist/services/executorPhaseAIssuerCore.d.ts +126 -0
  206. package/dist/services/executorPhaseAIssuerCore.js +295 -0
  207. package/dist/services/executorPhaseAIssuerRedemptionService.d.ts +34 -0
  208. package/dist/services/executorPhaseAIssuerRedemptionService.js +158 -0
  209. package/dist/services/githubReviewEvidenceRuntime.d.ts +14 -0
  210. package/dist/services/githubReviewEvidenceRuntime.js +30 -0
  211. package/dist/services/githubReviewEvidenceService.d.ts +93 -0
  212. package/dist/services/githubReviewEvidenceService.js +336 -0
  213. package/dist/services/modelGateway.d.ts +7 -0
  214. package/dist/services/modelProviderConnectionService.d.ts +71 -0
  215. package/dist/services/modelProviderConnectionService.js +279 -0
  216. package/dist/services/modelProviderCredentialHome.d.ts +32 -0
  217. package/dist/services/modelProviderCredentialHome.js +271 -0
  218. package/dist/services/ownerScopedModelConnectionGateway.d.ts +12 -0
  219. package/dist/services/ownerScopedModelConnectionGateway.js +30 -0
  220. package/dist/services/taskforceAgentConnectionBindingService.d.ts +66 -0
  221. package/dist/services/taskforceAgentConnectionBindingService.js +185 -0
  222. package/dist/services/taskforceAgentMcpBridge.d.ts +8 -2
  223. package/dist/services/taskforceAgentMcpBridge.js +30 -27
  224. package/dist/shared/adminEdgeProxy.d.ts +5 -0
  225. package/dist/shared/adminEdgeProxy.js +94 -0
  226. package/dist/shared/adminProxySessionCookies.d.ts +16 -0
  227. package/dist/shared/adminProxySessionCookies.js +86 -0
  228. package/dist/shared/aiProfileColors.d.ts +31 -1
  229. package/dist/shared/aiProfileColors.js +14 -6
  230. package/dist/shared/executorPhaseAApprovalGoldenVector.json +269 -0
  231. package/dist/shared/executorPhaseAApprovalReceipt.d.ts +112 -0
  232. package/dist/shared/executorPhaseAApprovalReceipt.js +58 -0
  233. package/dist/shared/executorPhaseAApprovalTrustPolicy.json +10 -0
  234. package/dist/shared/executorPhaseADriftContracts.d.ts +37 -0
  235. package/dist/shared/executorPhaseADriftContracts.js +63 -0
  236. package/dist/shared/executorPhaseAIssuerContracts.d.ts +75 -0
  237. package/dist/shared/executorPhaseAIssuerContracts.js +90 -0
  238. package/dist/shared/executorPhaseARunAuthorization.d.ts +120 -0
  239. package/dist/shared/executorPhaseARunAuthorization.js +232 -0
  240. package/dist/shared/executorPhaseASchemaValidation.d.ts +7 -0
  241. package/dist/shared/executorPhaseASchemaValidation.js +53 -0
  242. package/dist/shared/executorPhaseASchemas/approval-receipt.schema.json +106 -0
  243. package/dist/shared/executorPhaseASchemas/drift-attestation.schema.json +54 -0
  244. package/dist/shared/executorPhaseASchemas/drift-request.schema.json +47 -0
  245. package/dist/shared/executorPhaseASchemas/foundation-manifest.schema.json +29 -0
  246. package/dist/shared/executorPhaseASchemas/issuer-audit-record.schema.json +24 -0
  247. package/dist/shared/executorPhaseASchemas/issuer-proof.schema.json +43 -0
  248. package/dist/shared/executorPhaseASchemas/issuer-redemption-request.schema.json +18 -0
  249. package/dist/shared/executorPhaseASchemas/issuer-redemption-response.schema.json +39 -0
  250. package/dist/shared/executorPhaseASchemas/logical-envelope.schema.json +149 -0
  251. package/dist/shared/executorPhaseASchemas/preflight-report.schema.json +216 -0
  252. package/dist/shared/executorPhaseASchemas/run-capability.schema.json +111 -0
  253. package/dist/shared/executorPhaseASchemas/sender-proof.schema.json +37 -0
  254. package/dist/shared/executorPhaseASchemas/workload-grant.schema.json +68 -0
  255. package/dist/shared/executorPhaseASchemas/workload-jwt-claims.schema.json +67 -0
  256. package/dist/shared/executorPhaseATiming.d.ts +1 -0
  257. package/dist/shared/executorPhaseATiming.js +1 -0
  258. package/dist/shared/planningIdentity.js +1 -1
  259. package/dist/shared/productLogoKeys.d.ts +2 -0
  260. package/dist/shared/productLogoKeys.js +18 -0
  261. package/dist/shared/taskforceAgentDefinition.d.ts +0 -1
  262. package/dist/shared/taskforceAgentDefinition.js +6 -3
  263. package/dist/shared/taskforceAgentModels.d.ts +1 -0
  264. package/dist/shared/taskforceAgentModels.js +36 -3
  265. package/dist/shared/userFeatureGrants.d.ts +4 -0
  266. package/dist/shared/userFeatureGrants.js +7 -0
  267. package/dist/storage/executorPhaseAApprovalReceiptStore.d.ts +37 -0
  268. package/dist/storage/executorPhaseAApprovalReceiptStore.js +81 -0
  269. package/dist/storage/executorPhaseARunAuthorizationStore.d.ts +103 -0
  270. package/dist/storage/executorPhaseARunAuthorizationStore.js +492 -0
  271. package/dist/storage/githubReviewEvidenceInstallationStore.d.ts +26 -0
  272. package/dist/storage/githubReviewEvidenceInstallationStore.js +89 -0
  273. package/dist/storage/modelProviderConnectionStore.d.ts +99 -0
  274. package/dist/storage/modelProviderConnectionStore.js +446 -0
  275. package/dist/storage/postgresAdapter.d.ts +24 -3
  276. package/dist/storage/postgresAdapter.js +117 -14
  277. package/dist/storage/postgresWorker.js +22 -5
  278. package/dist/storage/postgresWorkerProtocol.d.ts +30 -0
  279. package/dist/storage/postgresWorkerProtocol.js +30 -0
  280. package/dist/storage/taskforceAgentConnectionBindingStore.d.ts +31 -0
  281. package/dist/storage/taskforceAgentConnectionBindingStore.js +84 -0
  282. package/dist/sync/cloudSyncApi.d.ts +4 -1
  283. package/dist/sync/cloudSyncApi.js +7 -2
  284. package/dist/sync/contentSyncState.d.ts +1 -1
  285. package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +1 -0
  286. package/dist/sync/coordinator/localSyncExecutionPermitStore.js +67 -30
  287. package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.d.ts +10 -0
  288. package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.js +29 -0
  289. package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
  290. package/dist/sync/coordinator/localWorkspaceSyncRunnerState.d.ts +15 -1
  291. package/dist/sync/coordinator/localWorkspaceSyncRunnerState.js +99 -2
  292. package/dist/sync/coordinator/workspaceSyncCredentialBroker.d.ts +1 -0
  293. package/dist/sync/coordinator/workspaceSyncCredentialBroker.js +33 -4
  294. package/dist/sync/engine/workspaceSyncContentLifecycleAdapter.d.ts +2 -1
  295. package/dist/sync/engine/workspaceSyncContentVersionStore.d.ts +38 -0
  296. package/dist/sync/engine/workspaceSyncContentVersionStore.js +50 -1
  297. package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
  298. package/dist/sync/engine/workspaceSyncEngineLifecyclePolicy.js +6 -6
  299. package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
  300. package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
  301. package/dist/sync/engine/workspaceSyncEnginePushCompletion.d.ts +14 -0
  302. package/dist/sync/engine/workspaceSyncEnginePushCompletion.js +84 -0
  303. package/dist/sync/engine/workspaceSyncEngineRecovery.js +1 -0
  304. package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +11 -0
  305. package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
  306. package/dist/sync/engine/workspaceSyncEngineRuntime.d.ts +1 -0
  307. package/dist/sync/engine/workspaceSyncEngineRuntime.js +1 -0
  308. package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +31 -4
  309. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
  310. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +134 -43
  311. package/dist/sync/engine/workspaceSyncEngineServerSnapshotReader.js +6 -0
  312. package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
  313. package/dist/sync/engine/workspaceSyncEngineTransfers.js +11 -4
  314. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.d.ts +1 -0
  315. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +29 -0
  316. package/dist/sync/syncApplyHandlers.d.ts +2 -0
  317. package/dist/sync/syncApplyHandlers.js +10 -1
  318. package/dist/sync/syncService.d.ts +17 -0
  319. package/dist/sync/syncService.js +87 -19
  320. package/dist/sync/taskforceAgentSyncAuthorization.d.ts +16 -0
  321. package/dist/sync/taskforceAgentSyncAuthorization.js +20 -0
  322. package/dist/sync/v3/combinedFeedCapability.js +8 -0
  323. package/dist/sync/v3/durableInitiativeMutationRouter.js +18 -10
  324. package/dist/sync/v3/durableOperationReplay.d.ts +14 -0
  325. package/dist/sync/v3/durableOperationReplay.js +18 -0
  326. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +2 -0
  327. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +14 -1
  328. package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +4 -1
  329. package/dist/sync/v3/durableTaskChecklistMutationRouter.js +62 -15
  330. package/dist/sync/v3/durableTaskCommentMutationRouter.js +3 -0
  331. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
  332. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +30 -8
  333. package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
  334. package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +37 -2
  335. package/dist/sync/v3/durableTaxonomyMutationRouter.js +5 -0
  336. package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.d.ts +11 -0
  337. package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.js +39 -10
  338. package/dist/sync/v3/durableWorkstreamMutationRouter.js +18 -10
  339. package/dist/sync/v3/durableWorkstreamTaskOrderMutationRouter.js +16 -5
  340. package/dist/sync/v3/localOutboxDispatchRuntime.js +2 -2
  341. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +2 -0
  342. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +47 -7
  343. package/dist/sync/v3/localTaskChecklistOutboxHandler.js +16 -2
  344. package/dist/sync/v3/localTaskChecklistOutboxService.d.ts +4 -0
  345. package/dist/sync/v3/localTaskChecklistOutboxService.js +14 -1
  346. package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
  347. package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
  348. package/dist/sync/v3/localTaskMetadataClient.js +1 -0
  349. package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
  350. package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
  351. package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
  352. package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
  353. package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
  354. package/dist/sync/v3/localTaskStatusClient.js +6 -1
  355. package/dist/sync/v3/localTaskStatusOutboxService.d.ts +10 -0
  356. package/dist/sync/v3/localTaskStatusOutboxService.js +272 -24
  357. package/dist/sync/v3/syncDurabilityStore.d.ts +41 -0
  358. package/dist/sync/v3/syncDurabilityStore.js +199 -13
  359. package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +6 -4
  360. package/dist/sync/v3/taskAttachmentLinksMutationService.js +19 -10
  361. package/dist/sync/v3/taskChecklistMutationService.d.ts +15 -2
  362. package/dist/sync/v3/taskChecklistMutationService.js +48 -1
  363. package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
  364. package/dist/sync/v3/taskCreateMutationService.js +7 -4
  365. package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
  366. package/dist/sync/v3/taskMetadataMutationService.js +4 -0
  367. package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
  368. package/dist/sync/v3/taskRestoreMutationService.js +7 -4
  369. package/dist/sync/v3/taskStatusMutationService.d.ts +31 -1
  370. package/dist/sync/v3/taskStatusMutationService.js +123 -3
  371. package/dist/sync/v3/workflowAssignmentSync.d.ts +6 -0
  372. package/dist/sync/v3/workflowAssignmentSync.js +30 -0
  373. package/dist/sync/v3/workspaceSyncJournalReader.js +1 -1
  374. package/dist/sync/v3/workspaceSyncOperationRetentionService.d.ts +16 -0
  375. package/dist/sync/v3/workspaceSyncOperationRetentionService.js +83 -0
  376. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
  377. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +13 -3
  378. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
  379. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
  380. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
  381. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
  382. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.d.ts +1 -0
  383. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +18 -3
  384. package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +8 -3
  385. package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +51 -10
  386. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +14 -0
  387. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +49 -25
  388. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +13 -4
  389. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +124 -57
  390. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +20 -0
  391. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +106 -30
  392. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +4 -1
  393. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +34 -0
  394. package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +12 -0
  395. package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
  396. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
  397. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
  398. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
  399. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
  400. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
  401. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
  402. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
  403. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
  404. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
  405. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
  406. package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +5 -0
  407. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +7 -0
  408. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +55 -9
  409. package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.d.ts +17 -0
  410. package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.js +64 -0
  411. package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
  412. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
  413. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
  414. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
  415. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
  416. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.d.ts +7 -0
  417. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.js +33 -0
  418. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.d.ts +7 -0
  419. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.js +8 -0
  420. package/dist/sync/workspacePullFeed.js +2 -1
  421. package/dist/sync/workspaceRepair.d.ts +8 -2
  422. package/dist/sync/workspaceRepair.js +222 -6
  423. package/dist/sync/workspaceSyncModel.d.ts +21 -0
  424. package/dist/sync/workspaceSyncModel.js +35 -7
  425. package/dist/sync/workspaceSyncState.d.ts +1 -0
  426. package/dist/sync/workspaceSyncV2SnapshotBuilder.d.ts +6 -0
  427. package/dist/sync/workspaceSyncV2SnapshotBuilder.js +5 -0
  428. package/dist/types.d.ts +47 -1
  429. package/dist/types.js +6 -0
  430. package/dist/ui/assets/AiIdentityRosterCard-OcSz1PkK.js +1 -0
  431. package/dist/ui/assets/AiProfilesModule-ByhYW5Xi.js +1 -0
  432. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTM6nIg_.js +3 -0
  433. package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
  434. package/dist/ui/assets/{AssetTraySortControl-Kf1pelSy.js → AssetTraySortControl-DabEG8L4.js} +1 -1
  435. package/dist/ui/assets/{ContextAttachmentManager-B8boOs6Q.js → ContextAttachmentManager-Coa8yVGM.js} +2 -2
  436. package/dist/ui/assets/{DocumentWorkspace-DXH4XUsB.js → DocumentWorkspace-BB0qhdix.js} +1 -1
  437. package/dist/ui/assets/{EntityActivityTimeline-BtSTq0ON.js → EntityActivityTimeline-CZ8x4UJE.js} +1 -1
  438. package/dist/ui/assets/PlanningModule-pRPjR7v5.js +1 -0
  439. package/dist/ui/assets/PlansPage-D86pZSSl.js +1 -0
  440. package/dist/ui/assets/TaskContextUpload-BVIkU9yT.js +1 -0
  441. package/dist/ui/assets/TaskSettings-Cv1mNhv_.js +12 -0
  442. package/dist/ui/assets/TaskforceAgentsModule-b-8R25cJ.css +1 -0
  443. package/dist/ui/assets/TaskforceAgentsModule-gmH-PD2q.js +24 -0
  444. package/dist/ui/assets/{WorkflowManagerModule-DWFspC-o.js → WorkflowManagerModule-DbfnHJ-f.js} +1 -1
  445. package/dist/ui/assets/index-BZ-hdZSk.css +1 -0
  446. package/dist/ui/assets/index-CTsDBaef.js +7 -0
  447. package/dist/ui/assets/{vendor-icons-BkFLXavV.js → vendor-icons-Bsq-mcEn.js} +1 -1
  448. package/dist/ui/branding/logos/letterhead_dark.png +0 -0
  449. package/dist/ui/branding/logos/letterhead_light.png +0 -0
  450. package/dist/ui/branding/logos/signature_dark.png +0 -0
  451. package/dist/ui/branding/logos/signature_light.png +0 -0
  452. package/dist/ui/index.html +3 -3
  453. package/dist/utils/aiProfileDefaultLogo.js +16 -48
  454. package/dist/utils/httpSetCookie.d.ts +1 -0
  455. package/dist/utils/httpSetCookie.js +4 -1
  456. package/dist/utils/localRuntimeUrl.d.ts +1 -0
  457. package/dist/utils/localRuntimeUrl.js +14 -0
  458. package/dist/utils/productLogoRegistry.d.ts +2 -0
  459. package/dist/utils/productLogoRegistry.js +36 -0
  460. package/dist/utils/syncStatusPresentation.d.ts +4 -0
  461. package/dist/utils/syncStatusPresentation.js +17 -0
  462. package/dist/utils/taskActivity.d.ts +3 -2
  463. package/dist/utils/taskActivity.js +19 -2
  464. package/dist/utils/taskEditorReconciliation.d.ts +40 -0
  465. package/dist/utils/taskEditorReconciliation.js +217 -0
  466. package/dist/utils/taskEvents.d.ts +2 -0
  467. package/dist/utils/taskNormalization.d.ts +1 -0
  468. package/dist/utils/taskNormalization.js +39 -0
  469. package/dist/utils/taskSearch.js +2 -2
  470. package/dist/utils/uiNotice.d.ts +4 -0
  471. package/dist/utils/workspaceSyncPresentation.d.ts +1 -1
  472. package/dist/utils/workspaceSyncPresentation.js +23 -17
  473. package/package.json +36 -6
  474. package/dist/ui/assets/AiIdentityRosterCard-MZs7lVED.js +0 -1
  475. package/dist/ui/assets/AiProfilesModule-C3i0LOxe.js +0 -1
  476. package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
  477. package/dist/ui/assets/AnnotatedAttachmentWorkspace-DVZk5Tln.js +0 -3
  478. package/dist/ui/assets/PlanningModule-BPVyEa-f.js +0 -1
  479. package/dist/ui/assets/PlansPage-ChqgxALc.js +0 -1
  480. package/dist/ui/assets/TaskContextUpload-CB3ol0sN.js +0 -1
  481. package/dist/ui/assets/TaskSettings-g4ECKNOz.js +0 -12
  482. package/dist/ui/assets/TaskforceAgentsModule-BazdUwxZ.js +0 -21
  483. package/dist/ui/assets/TaskforceAgentsModule-D6IC0S7Q.css +0 -1
  484. package/dist/ui/assets/index-BUplSsv_.js +0 -7
  485. package/dist/ui/assets/index-gz2EXuoK.css +0 -1
@@ -6,17 +6,18 @@
6
6
  * routes.ts at runtime.
7
7
  */
8
8
  import { randomUUID } from 'crypto';
9
- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
10
- import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
9
+ import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
10
+ import { isInitializeRequest, isJsonContentType } from '@modelcontextprotocol/server';
11
11
  import { TaskforceRuleError } from '../../core/Taskforce.js';
12
12
  import { resolveRequestAccess, } from '../auth.js';
13
13
  import { parseJsonBody } from './primitives.js';
14
- import { createTaskforceMcpServer, isMcpWriteToolName } from '../../mcp/runtime.js';
14
+ import { createStatelessTaskforceMcpServer, createTaskforceMcpServer, isMcpWriteToolName, } from '../../mcp/runtime.js';
15
15
  import { MCP_CLOUD_TOOL_SCOPE_REQUIREMENTS } from '../../mcp/toolRegistry.js';
16
16
  import { resolveCanonicalMcpToolName } from '../../mcp/toolCallCompatibility.js';
17
17
  import { applyPrefixedRateLimitHeaders } from '../rateLimit.js';
18
18
  import { parseAiProfileBootstrapHeaders } from '../../mcp/aiProfileBootstrap.js';
19
19
  import { parseMcpClientId } from '../../mcp/clientRegistry.js';
20
+ import { handleModernMcpHttpRequest, isModernMcpHttpRequest, } from '../../mcp/httpProtocolRouting.js';
20
21
  import { resolveAppAccessDeniedResponse } from '../appAccess.js';
21
22
  import { resolveCloudApplicationBaseUrl } from '../../config/applicationBaseUrl.js';
22
23
  import { getRequestPerformanceDiagnostics, runWithRequestPerformanceDiagnostics, } from '../../storage/postgresRequestDiagnostics.js';
@@ -273,7 +274,14 @@ function writeMcpHttpError(res, statusCode, message, data) {
273
274
  id: null,
274
275
  }));
275
276
  }
276
- function extractMcpWriteToolNames(body) {
277
+ function resolveProductionCloudMcpToolPolicy(requestedToolName) {
278
+ const toolName = resolveCanonicalMcpToolName(requestedToolName);
279
+ return {
280
+ requiredScope: MCP_CLOUD_TOOL_SCOPE_REQUIREMENTS[toolName] || null,
281
+ isWrite: isMcpWriteToolName(requestedToolName),
282
+ };
283
+ }
284
+ function extractMcpWriteToolNames(body, resolveToolPolicy) {
277
285
  const messages = Array.isArray(body) ? body : [body];
278
286
  const names = messages.flatMap((message) => {
279
287
  if (!message || typeof message !== 'object')
@@ -282,7 +290,7 @@ function extractMcpWriteToolNames(body) {
282
290
  if (method !== 'tools/call')
283
291
  return [];
284
292
  const toolName = String(message?.params?.name || '').trim();
285
- return toolName && isMcpWriteToolName(toolName) ? [toolName] : [];
293
+ return toolName && resolveToolPolicy(toolName).isWrite ? [toolName] : [];
286
294
  });
287
295
  return Array.from(new Set(names));
288
296
  }
@@ -299,7 +307,7 @@ function extractFirstMcpToolName(body) {
299
307
  }
300
308
  return null;
301
309
  }
302
- function findDeniedCloudMcpToolName(body, scopes) {
310
+ function findDeniedCloudMcpToolName(body, scopes, resolveToolPolicy) {
303
311
  const messages = Array.isArray(body) ? body : [body];
304
312
  for (const message of messages) {
305
313
  if (!message || typeof message !== 'object')
@@ -309,15 +317,14 @@ function findDeniedCloudMcpToolName(body, scopes) {
309
317
  const requestedToolName = String(message?.params?.name || '').trim();
310
318
  if (!requestedToolName)
311
319
  continue;
312
- const toolName = resolveCanonicalMcpToolName(requestedToolName);
313
- const requiredScope = MCP_CLOUD_TOOL_SCOPE_REQUIREMENTS[toolName];
320
+ const requiredScope = resolveToolPolicy(requestedToolName).requiredScope;
314
321
  if (!requiredScope || !scopes.includes(requiredScope))
315
322
  return requestedToolName;
316
323
  }
317
324
  return null;
318
325
  }
319
326
  export function makeHandleCloudMcpRequest(core, deps) {
320
- const { ensureAppAccess, resolveAuthenticatedUserId, writeRateLimit } = deps;
327
+ const { ensureAppAccess, resolveAuthenticatedUserId, writeRateLimit, createMcpServer = createTaskforceMcpServer, resolveMcpToolPolicy = resolveProductionCloudMcpToolPolicy, acquireMcpRuntime, } = deps;
321
328
  const authenticateCloudMcpRequest = makeAuthenticateCloudMcpRequest(core, {
322
329
  resolveAuthenticatedUserId,
323
330
  writeMcpHttpError,
@@ -342,7 +349,7 @@ export function makeHandleCloudMcpRequest(core, deps) {
342
349
  const applyCloudMcpWriteRateLimit = (req, res, auth, body) => {
343
350
  if (!writeRateLimit.enabled)
344
351
  return true;
345
- const writeTools = extractMcpWriteToolNames(body);
352
+ const writeTools = extractMcpWriteToolNames(body, resolveMcpToolPolicy);
346
353
  if (writeTools.length === 0)
347
354
  return true;
348
355
  const actorKey = auth.authenticatedViaToken?.tokenId
@@ -413,6 +420,10 @@ export function makeHandleCloudMcpRequest(core, deps) {
413
420
  writeMcpHttpError(res, 405, 'Method not allowed.');
414
421
  return;
415
422
  }
423
+ if (!isJsonContentType(requestHeader(req, 'content-type', ''))) {
424
+ writeMcpHttpError(res, 415, 'Unsupported Media Type: Content-Type must be application/json');
425
+ return;
426
+ }
416
427
  let body = undefined;
417
428
  try {
418
429
  const bodyParseStartedAtMs = Date.now();
@@ -431,7 +442,8 @@ export function makeHandleCloudMcpRequest(core, deps) {
431
442
  : '';
432
443
  const initializeRequest = isInitializeRequest(body)
433
444
  || mcpMethod === 'initialize';
434
- const deniedToolName = findDeniedCloudMcpToolName(body, authScopes);
445
+ const modernProtocolRequest = await isModernMcpHttpRequest(req, body);
446
+ const deniedToolName = findDeniedCloudMcpToolName(body, authScopes, resolveMcpToolPolicy);
435
447
  if (deniedToolName) {
436
448
  core.addMcpAuditLog({
437
449
  workspaceId: auth.workspaceId,
@@ -451,13 +463,14 @@ export function makeHandleCloudMcpRequest(core, deps) {
451
463
  writeMcpHttpError(res, 403, 'Forbidden.');
452
464
  return;
453
465
  }
454
- const writeToolNames = extractMcpWriteToolNames(body);
466
+ const writeToolNames = extractMcpWriteToolNames(body, resolveMcpToolPolicy);
455
467
  const rateLimitStartedAtMs = Date.now();
456
468
  const rateLimitAllowed = applyCloudMcpWriteRateLimit(req, res, auth, body);
457
469
  rateLimitMs = Date.now() - rateLimitStartedAtMs;
458
470
  if (!rateLimitAllowed)
459
471
  return;
460
472
  let runtime = null;
473
+ let runtimeLease = null;
461
474
  let runtimeConstructionMs = 0;
462
475
  let transportConnectMs = 0;
463
476
  let requestHandlingMs = 0;
@@ -466,12 +479,13 @@ export function makeHandleCloudMcpRequest(core, deps) {
466
479
  const toolTimingState = { value: null };
467
480
  try {
468
481
  const runtimeStartedAtMs = Date.now();
469
- // Intentionally isolate the MCP runtime per HTTP request. The runtime closes over
482
+ // Production intentionally isolates the MCP runtime per HTTP request. The runtime closes over
470
483
  // workspace auth, AI identity, permissions, subscriptions, and mutable helper state;
471
484
  // sharing it could leak state across tenants or callers. Keep the transport stateless
472
485
  // too. The timing event below measures construction cost so caching is only revisited
473
- // with evidence and must preserve these boundaries (including dynamic tool schemas).
474
- runtime = createTaskforceMcpServer({
486
+ // with evidence and must preserve these boundaries (including dynamic tool schemas). The optional
487
+ // lease seam exists only for transport conformance tests that must carry legacy bidirectional calls.
488
+ const runtimeOptions = {
475
489
  projectRoot: core.getPaths().projectRoot,
476
490
  tenantId: core.getTenantId(),
477
491
  workspaceId: auth.workspaceId,
@@ -479,6 +493,7 @@ export function makeHandleCloudMcpRequest(core, deps) {
479
493
  serverName: 'taskforce-cloud',
480
494
  logStartup: false,
481
495
  runtimeMode: 'cloud',
496
+ toolProfile: auth.authenticatedViaToken?.toolProfile || auth.authenticatedViaOAuth?.toolProfile || 'default',
482
497
  applicationBaseUrl: resolveCloudApplicationBaseUrl(),
483
498
  auth: buildCloudMcpRuntimeAuth({
484
499
  req,
@@ -506,15 +521,66 @@ export function makeHandleCloudMcpRequest(core, deps) {
506
521
  ]);
507
522
  }
508
523
  },
509
- });
524
+ };
525
+ if (modernProtocolRequest) {
526
+ const requestHandlingStartedAtMs = Date.now();
527
+ await handleModernMcpHttpRequest({
528
+ req,
529
+ res,
530
+ parsedBody: body,
531
+ factory: ({ era }) => {
532
+ const constructionStartedAtMs = Date.now();
533
+ const modernRuntime = createStatelessTaskforceMcpServer({
534
+ ...runtimeOptions,
535
+ protocolEra: era,
536
+ }, createMcpServer);
537
+ runtimeConstructionMs = Date.now() - constructionStartedAtMs;
538
+ if (!res.headersSent) {
539
+ setServerTimingHeader(res, [
540
+ { name: 'auth', durationMs: authMs },
541
+ { name: 'body-parse', durationMs: bodyParseMs },
542
+ { name: 'rate-limit', durationMs: rateLimitMs },
543
+ { name: 'runtime', durationMs: runtimeConstructionMs },
544
+ ]);
545
+ }
546
+ return modernRuntime.server;
547
+ },
548
+ onerror: (error) => {
549
+ console.warn('[Taskforce MCP] Modern cloud request rejected:', {
550
+ requestId,
551
+ message: error.message,
552
+ });
553
+ },
554
+ });
555
+ requestHandlingMs = Date.now() - requestHandlingStartedAtMs;
556
+ recordCloudMcpCredentialUsage(req, auth.authenticatedViaToken, auth.authenticatedViaOAuth);
557
+ return;
558
+ }
559
+ runtimeLease = acquireMcpRuntime
560
+ ? await acquireMcpRuntime({ req, options: runtimeOptions })
561
+ : null;
562
+ runtime = runtimeLease?.runtime
563
+ || createStatelessTaskforceMcpServer(runtimeOptions, createMcpServer);
510
564
  runtimeConstructionMs = Date.now() - runtimeStartedAtMs;
511
- const transport = new StreamableHTTPServerTransport({
565
+ const transport = runtimeLease?.transport || new NodeStreamableHTTPServerTransport({
512
566
  sessionIdGenerator: undefined,
513
567
  enableJsonResponse: true,
514
568
  });
515
569
  const transportStartedAtMs = Date.now();
516
- await runtime.server.connect(transport);
570
+ if (!runtimeLease)
571
+ await runtime.server.connect(transport);
517
572
  transportConnectMs = Date.now() - transportStartedAtMs;
573
+ // Set request-level phases before the SDK writes response headers. Tool calls replace this
574
+ // with the richer envelope/handler breakdown from onToolCallTiming above.
575
+ if (!res.headersSent) {
576
+ setServerTimingHeader(res, [
577
+ { name: 'auth', durationMs: authMs },
578
+ { name: 'body-parse', durationMs: bodyParseMs },
579
+ { name: 'rate-limit', durationMs: rateLimitMs },
580
+ { name: 'runtime', durationMs: runtimeConstructionMs },
581
+ { name: 'transport-connect', durationMs: transportConnectMs },
582
+ ]);
583
+ }
518
584
  if (!initializeRequest) {
519
585
  // Stateless cloud sessions still require a valid MCP JSON-RPC request;
520
586
  // let the SDK validate and respond rather than trying to track sessions server-side.
@@ -540,7 +606,17 @@ export function makeHandleCloudMcpRequest(core, deps) {
540
606
  }
541
607
  }
542
608
  finally {
543
- if (runtime) {
609
+ if (runtimeLease) {
610
+ const cleanupStartedAtMs = Date.now();
611
+ try {
612
+ await runtimeLease.release();
613
+ }
614
+ catch (closeError) {
615
+ console.warn('[Taskforce MCP] Cloud test runtime lease cleanup failed:', closeError);
616
+ }
617
+ cleanupMs = Date.now() - cleanupStartedAtMs;
618
+ }
619
+ else if (runtime) {
544
620
  const cleanupStartedAtMs = Date.now();
545
621
  try {
546
622
  await runtime.server.close();
@@ -573,6 +573,7 @@ export function registerSyncRoutes(deps) {
573
573
  }
574
574
  const { result } = await dispatchWorkspaceSyncChanges(cloudWorkspaceId, fenced.changes, {
575
575
  coexistenceDirection: 'cloud-push',
576
+ actorUserId: access.userId,
576
577
  assertedActiveV3TaskMetadataIds,
577
578
  assertedActiveV3TaskLifecycleIds,
578
579
  assertedActiveV3TaskReopenAssigneeIds,
@@ -1,4 +1,5 @@
1
1
  import { applyWorkspaceRepair } from '../../sync/workspaceRepair.js';
2
+ import { WorkspaceSyncContentPullObligationStore } from '../../sync/engine/workspaceSyncContentPullObligationStore.js';
2
3
  import { normalizeSyncEventDetails } from '../../utils/syncEventDetails.js';
3
4
  import { parseJsonBody } from './primitives.js';
4
5
  import { requireAuthenticatedSyncRequest } from './syncRouteGuards.js';
@@ -50,8 +51,13 @@ export function registerWorkspaceSyncAuxRoutes({ addRoute, core, context, resolv
50
51
  res.end(JSON.stringify({ success: true }));
51
52
  });
52
53
  // POST /api/taskforce/sync/workspace/repair-startup - Auto-repair workspace asset/document
53
- // metadata on workspace open. Safe fixups re-register metadata for local files and mark
54
- // stale, unreferenced metadata deleted when the file is missing. Never deletes files.
54
+ // metadata on workspace open. Safe fixups re-register metadata for local files and clean up
55
+ // stale links. Does NOT tombstone metadata for files that appear missing locally a single
56
+ // failed existence check at startup can mean the content is only temporarily unavailable
57
+ // (e.g. storage not yet mounted/synced), not deleted; that requires explicit admin
58
+ // confirmation via /api/taskforce/admin/workspace-repair/apply. Never deletes files. When
59
+ // content availability genuinely can't be verified, queues a durable content-pull recovery
60
+ // obligation instead, which resolves automatically once a later scan confirms the content.
55
61
  // Called once by the sync orchestrator when the workspace becomes active.
56
62
  addRoute('POST', '/api/taskforce/sync/workspace/repair-startup', async (req, res) => {
57
63
  const authConfig = context.authConfig;
@@ -80,6 +86,7 @@ export function registerWorkspaceSyncAuxRoutes({ addRoute, core, context, resolv
80
86
  deletedTasks: core.listWorkspaceSyncDeletes(workspaceId) || [],
81
87
  workspaceAssetStore,
82
88
  publishedContentResolver,
89
+ contentPullObligationStore: new WorkspaceSyncContentPullObligationStore(core.getDatabaseAdapter()),
83
90
  aiProfiles: typeof core.listAiProfiles === 'function'
84
91
  ? core.listAiProfiles(workspaceId, { includeArchived: true }) || []
85
92
  : [],
@@ -1,7 +1,7 @@
1
1
  import { DEFAULT_WORKSPACE_PULL_PAGE_MAX_BYTES, buildWorkspacePullFeed, WorkspacePullEntryTooLargeError, } from '../../sync/workspacePullFeed.js';
2
2
  import { applyWorkspaceSyncLocalBatch } from '../../sync/engine/workspaceSyncEngineLocalApply.js';
3
3
  import { parseJsonBody } from './primitives.js';
4
- import { normalizeWorkspaceSyncV2ProjectionExclusions, parseWorkspaceSyncV2ProjectionExclusions, WORKSPACE_SYNC_V3_COMBINED_V2_EXCLUSIONS, } from '../../sync/v3/workspaceSyncV2ProjectionExclusions.js';
4
+ import { normalizeWorkspaceSyncV2ProjectionExclusions, parseWorkspaceSyncV2ProjectionExclusions, WORKSPACE_SYNC_V3_COMBINED_V2_EXCLUSIONS, workspaceSyncV2ProjectionExclusionsEqual, } from '../../sync/v3/workspaceSyncV2ProjectionExclusions.js';
5
5
  import { resolveWorkspaceSyncV3AttestedV2Exclusions } from '../../sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js';
6
6
  import { requireAuthenticatedSyncRequest, requireEnabledSyncAuth, resolveAuthorizedSyncWorkspace, } from './syncRouteGuards.js';
7
7
  import { completeLocalSyncBrowserPushEchoPermitGroup, createLocalSyncBrowserV2ApplyTransactionHooks, parseLocalSyncBrowserApplyPermitContext, resolveLocalSyncBrowserApplyPermitOperationClass, } from '../../sync/coordinator/localSyncBrowserApplyPermitContext.js';
@@ -301,7 +301,16 @@ export function registerWorkspacePullApplySyncRoutes({ addRoute, core, context,
301
301
  };
302
302
  }
303
303
  if (!change) {
304
- missing.push(request);
304
+ missing.push({
305
+ ...request,
306
+ disposition: request.kind === 'asset'
307
+ && 'assetId' in request
308
+ && (!requestedAsset
309
+ || requestedAsset.deletedAt
310
+ || requestedAsset.storageProvider === 'external')
311
+ ? 'terminal-unavailable'
312
+ : 'retryable',
313
+ });
305
314
  consumed += 1;
306
315
  continue;
307
316
  }
@@ -554,6 +563,16 @@ export function registerWorkspacePullApplySyncRoutes({ addRoute, core, context,
554
563
  : null;
555
564
  let applyResult;
556
565
  if (permitContext && coordinatorServices && permitOperationClass === 'push') {
566
+ const attestedV2ExcludedProjections = v2ExcludedProjections.length > 0
567
+ ? (() => {
568
+ const attested = resolveWorkspaceSyncV3AttestedV2Exclusions({
569
+ coverage: body?.combinedCoverage,
570
+ excludedProjections: v2ExcludedProjections,
571
+ runtimeMode: 'local',
572
+ });
573
+ return attested && workspaceSyncV2ProjectionExclusionsEqual(attested, v2ExcludedProjections) ? attested : null;
574
+ })()
575
+ : [];
557
576
  applyResult = completeLocalSyncBrowserPushEchoPermitGroup({
558
577
  services: coordinatorServices,
559
578
  cookieHeader: req.headers.cookie,
@@ -567,13 +586,13 @@ export function registerWorkspacePullApplySyncRoutes({ addRoute, core, context,
567
586
  || workspaceMembers !== undefined
568
587
  || body?.bootstrapSnapshot !== undefined
569
588
  || allowReferenceNumberReassignment
570
- || v2ExcludedProjections.length > 0) {
589
+ || !attestedV2ExcludedProjections) {
571
590
  throw new Error('Browser push echo apply accepts only authoritative task upserts.');
572
591
  }
573
592
  return dispatchWorkspaceSyncMetadataAtomically(workspaceId, incomingChanges, {
574
593
  allowReferenceNumberReassignment: false,
575
594
  coexistenceDirection: 'local-pull',
576
- v2ExcludedProjections: [],
595
+ v2ExcludedProjections: attestedV2ExcludedProjections,
577
596
  });
578
597
  },
579
598
  });
@@ -21,6 +21,7 @@ interface RegisterWorkspacePushSyncRoutesArgs {
21
21
  dispatchWorkspaceSyncChanges: (workspaceId: string, incomingChanges: WorkspaceSyncChange[], options?: {
22
22
  allowReferenceNumberReassignment?: boolean;
23
23
  coexistenceDirection?: 'cloud-push';
24
+ actorUserId?: string;
24
25
  assertedActiveV3TaskMetadataIds?: ReadonlySet<string>;
25
26
  assertedActiveV3TaskLifecycleIds?: ReadonlySet<string>;
26
27
  assertedActiveV3TaskReopenAssigneeIds?: ReadonlySet<string>;
@@ -270,6 +270,7 @@ export function registerWorkspacePushSyncRoutes({ addRoute, core, context, audit
270
270
  const { result, deleteCount, emittedEventIds } = await dispatchWorkspaceSyncChanges(targetWorkspaceId, incomingChanges, {
271
271
  allowReferenceNumberReassignment,
272
272
  coexistenceDirection: 'cloud-push',
273
+ actorUserId: String(access.userId || '').trim(),
273
274
  assertedActiveV3TaskMetadataIds,
274
275
  assertedActiveV3TaskLifecycleIds,
275
276
  assertedActiveV3TaskReopenAssigneeIds,
@@ -5,7 +5,7 @@ import { buildWorkspaceSyncV3InitiativeRepairPage, decodeWorkspaceSyncV3Initiati
5
5
  import { WORKSPACE_SYNC_V3_COVERAGE_PROFILE } from '../../sync/v3/workspaceSyncV3FeedProfile.js';
6
6
  import { isWorkspaceSyncV3InitiativeLegacyPushDisabled } from '../../sync/v3/planningActivation.js';
7
7
  import { WORKSPACE_SYNC_V3_COMBINED_COVERAGE_PROFILE } from '../../sync/v3/workspaceSyncV3CombinedCoverage.js';
8
- import { buildWorkspaceSyncV3CombinedRepairPage, decodeWorkspaceSyncV3CombinedRepairCursor, decodeWorkspaceSyncV3NestedRepairCursor, decodeWorkspaceSyncV3PlanningOrderRepairCursor, decodeWorkspaceSyncV3WorkflowRepairCursor, WorkspaceSyncV3CombinedRepairSnapshotUnavailableError, } from '../../sync/v3/workspaceSyncV3CombinedRepairMaterialization.js';
8
+ import { buildWorkspaceSyncV3CombinedRepairPage, decodeWorkspaceSyncV3CombinedRepairCursor, decodeWorkspaceSyncV3NestedRepairCursor, decodeWorkspaceSyncV3PlanningOrderRepairCursor, decodeWorkspaceSyncV3TaskCoverRepairCursor, decodeWorkspaceSyncV3WorkflowRepairCursor, decodeWorkspaceSyncV3WorkflowTaskCoverRepairCursor, WorkspaceSyncV3CombinedRepairSnapshotUnavailableError, } from '../../sync/v3/workspaceSyncV3CombinedRepairMaterialization.js';
9
9
  import { isWorkspaceSyncV3CombinedLegacyFenceEnabled } from '../../sync/v3/workspaceSyncV2ProjectionExclusions.js';
10
10
  import { resolveCombinedFeedCapability } from '../../sync/v3/combinedFeedCapability.js';
11
11
  import { resolveWorkspaceSyncV3RegisteredCoverage } from '../../sync/v3/workspaceSyncV3CoverageRegistry.js';
@@ -21,6 +21,20 @@ function json(res, status, body) {
21
21
  res.writeHead(status, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
22
22
  res.end(JSON.stringify(body));
23
23
  }
24
+ function decodeCombinedRepairCursorForContract(rawCursor, keyring, wire) {
25
+ if (wire.taskCoverProjectionRequired && wire.workflowWriterPrerequisitesRequired) {
26
+ return decodeWorkspaceSyncV3WorkflowTaskCoverRepairCursor(rawCursor, keyring);
27
+ }
28
+ if (wire.taskCoverProjectionRequired)
29
+ return decodeWorkspaceSyncV3TaskCoverRepairCursor(rawCursor, keyring);
30
+ if (wire.workflowWriterPrerequisitesRequired)
31
+ return decodeWorkspaceSyncV3WorkflowRepairCursor(rawCursor, keyring);
32
+ if (wire.planningOrderWriterPrerequisitesRequired)
33
+ return decodeWorkspaceSyncV3PlanningOrderRepairCursor(rawCursor, keyring);
34
+ if (wire.nestedWriterPrerequisitesRequired)
35
+ return decodeWorkspaceSyncV3NestedRepairCursor(rawCursor, keyring);
36
+ return decodeWorkspaceSyncV3CombinedRepairCursor(rawCursor, keyring);
37
+ }
24
38
  function attestLegacyPushBoundary(body, boundary) {
25
39
  const attested = { ...body, ...boundary };
26
40
  const mutable = attested;
@@ -215,13 +229,7 @@ export function registerWorkspaceSyncV3FeedRoutes(input) {
215
229
  return;
216
230
  }
217
231
  const rawCursor = String(url.searchParams.get('cursor') || '').trim();
218
- const cursor = requestedWire.workflowWriterPrerequisitesRequired
219
- ? decodeWorkspaceSyncV3WorkflowRepairCursor(rawCursor, keyring)
220
- : requestedWire.planningOrderWriterPrerequisitesRequired
221
- ? decodeWorkspaceSyncV3PlanningOrderRepairCursor(rawCursor, keyring)
222
- : requestedWire.nestedWriterPrerequisitesRequired
223
- ? decodeWorkspaceSyncV3NestedRepairCursor(rawCursor, keyring)
224
- : decodeWorkspaceSyncV3CombinedRepairCursor(rawCursor, keyring);
232
+ const cursor = decodeCombinedRepairCursorForContract(rawCursor, keyring, requestedWire);
225
233
  if (rawCursor && !cursor) {
226
234
  json(res, 400, { success: false, code: 'INVALID_SYNC_COMBINED_REPAIR_CURSOR', error: 'Invalid combined repair cursor.' });
227
235
  return;
@@ -231,7 +239,10 @@ export function registerWorkspaceSyncV3FeedRoutes(input) {
231
239
  cursorKeyring: keyring, cursor, pageSize: Number.isFinite(limit) ? limit : undefined,
232
240
  nestedCoverage: requestedWire.nestedWriterPrerequisitesRequired,
233
241
  workflowCoverage: requestedWire.workflowWriterPrerequisitesRequired,
234
- planningOrderCoverage: requestedWire.planningOrderWriterPrerequisitesRequired });
242
+ workflowTaskCoverCoverage: requestedWire.workflowWriterPrerequisitesRequired
243
+ && requestedWire.taskCoverProjectionRequired,
244
+ planningOrderCoverage: requestedWire.planningOrderWriterPrerequisitesRequired,
245
+ taskCoverCoverage: requestedWire.taskCoverProjectionRequired });
235
246
  json(res, 200, attestLegacyPushBoundary({ ...page }, {
236
247
  contractVersion: 3,
237
248
  legacyV2Boundary: { cloudWritesFenced: false, excludedProjections: [] },
@@ -328,13 +339,7 @@ export function registerWorkspaceSyncV3FeedRoutes(input) {
328
339
  return;
329
340
  }
330
341
  const repairCursor = coverage.kind === 'combined'
331
- ? (coverage.wire.workflowWriterPrerequisitesRequired
332
- ? decodeWorkspaceSyncV3WorkflowRepairCursor(rawRepairCursor, cursorKeyring)
333
- : coverage.wire.planningOrderWriterPrerequisitesRequired
334
- ? decodeWorkspaceSyncV3PlanningOrderRepairCursor(rawRepairCursor, cursorKeyring)
335
- : coverage.wire.nestedWriterPrerequisitesRequired
336
- ? decodeWorkspaceSyncV3NestedRepairCursor(rawRepairCursor, cursorKeyring)
337
- : decodeWorkspaceSyncV3CombinedRepairCursor(rawRepairCursor, cursorKeyring))
342
+ ? decodeCombinedRepairCursorForContract(rawRepairCursor, cursorKeyring, coverage.wire)
338
343
  : decodeWorkspaceSyncV3InitiativeRepairCursor(rawRepairCursor, cursorKeyring);
339
344
  if (rawRepairCursor && (!repairEnabled || !repairCursor)) {
340
345
  json(res, 400, { success: false, code: 'INVALID_SYNC_V3_REPAIR_CURSOR', error: 'Invalid repair cursor.' });
@@ -352,7 +357,10 @@ export function registerWorkspaceSyncV3FeedRoutes(input) {
352
357
  pageSize: Number.isFinite(limit) ? limit : undefined,
353
358
  nestedCoverage: coverage.wire.nestedWriterPrerequisitesRequired,
354
359
  workflowCoverage: coverage.wire.workflowWriterPrerequisitesRequired,
360
+ workflowTaskCoverCoverage: coverage.wire.workflowWriterPrerequisitesRequired
361
+ && coverage.wire.taskCoverProjectionRequired,
355
362
  planningOrderCoverage: coverage.wire.planningOrderWriterPrerequisitesRequired,
363
+ taskCoverCoverage: coverage.wire.taskCoverProjectionRequired,
356
364
  coveredLegacyWritesFenced: combinedLegacyPushDisabled })
357
365
  : buildWorkspaceSyncV3InitiativeRepairPage({ core: input.core, workspaceId,
358
366
  cursorKeyring: cursorKeyring, cursor: repairCursor,
@@ -398,7 +406,10 @@ export function registerWorkspaceSyncV3FeedRoutes(input) {
398
406
  cursorKeyring: cursorKeyring, pageSize: Number.isFinite(limit) ? limit : undefined,
399
407
  nestedCoverage: coverage.wire.nestedWriterPrerequisitesRequired,
400
408
  workflowCoverage: coverage.wire.workflowWriterPrerequisitesRequired,
409
+ workflowTaskCoverCoverage: coverage.wire.workflowWriterPrerequisitesRequired
410
+ && coverage.wire.taskCoverProjectionRequired,
401
411
  planningOrderCoverage: coverage.wire.planningOrderWriterPrerequisitesRequired,
412
+ taskCoverCoverage: coverage.wire.taskCoverProjectionRequired,
402
413
  coveredLegacyWritesFenced: combinedLegacyPushDisabled })
403
414
  : buildWorkspaceSyncV3InitiativeRepairPage({ core: input.core, workspaceId,
404
415
  cursorKeyring: cursorKeyring, pageSize: Number.isFinite(limit) ? limit : undefined });
@@ -96,7 +96,14 @@ function parseEnvelope(raw) {
96
96
  };
97
97
  if (operation.domain === 'task' && operation.mutationKind === 'metadata-update') {
98
98
  const saveSource = payload.saveSource;
99
- assertExactKeys(payload, saveSource === undefined ? ['patch'] : ['patch', 'saveSource'], 'operation.payload');
99
+ const expectedDetailRevision = payload.expectedDetailRevision === undefined
100
+ ? undefined
101
+ : requireId(payload.expectedDetailRevision, 'operation.payload.expectedDetailRevision');
102
+ assertExactKeys(payload, [
103
+ 'patch',
104
+ ...(saveSource === undefined ? [] : ['saveSource']),
105
+ ...(expectedDetailRevision === undefined ? [] : ['expectedDetailRevision']),
106
+ ], 'operation.payload');
100
107
  if (saveSource !== undefined && saveSource !== 'manual' && saveSource !== 'autosave') {
101
108
  throw new LocalCaptureRequestError('operation.payload.saveSource must be manual or autosave.');
102
109
  }
@@ -106,6 +113,7 @@ function parseEnvelope(raw) {
106
113
  mutationKind: 'metadata-update',
107
114
  patch: requireRecord(payload.patch, 'operation.payload.patch'),
108
115
  ...(saveSource ? { saveSource } : {}),
116
+ ...(expectedDetailRevision ? { expectedDetailRevision } : {}),
109
117
  };
110
118
  }
111
119
  if (operation.domain === 'task' && operation.mutationKind === 'create') {
@@ -170,11 +178,27 @@ function parseEnvelope(raw) {
170
178
  };
171
179
  }
172
180
  if (operation.domain === 'task' && operation.mutationKind === 'set-status') {
181
+ const expectedDetailRevision = payload.expectedDetailRevision === undefined
182
+ ? undefined
183
+ : requireId(payload.expectedDetailRevision, 'operation.payload.expectedDetailRevision');
184
+ assertExactKeys(payload, [
185
+ 'status',
186
+ 'assigneeIntent',
187
+ 'canceledReason',
188
+ 'metadataPatch',
189
+ ...(expectedDetailRevision === undefined ? [] : ['expectedDetailRevision']),
190
+ ], 'operation.payload');
173
191
  return {
174
192
  ...common,
175
193
  domain: 'task',
176
194
  mutationKind: 'set-status',
177
- payload: validateDurableTaskStatusMutationPayload(payload),
195
+ payload: validateDurableTaskStatusMutationPayload({
196
+ status: payload.status,
197
+ assigneeIntent: payload.assigneeIntent,
198
+ canceledReason: payload.canceledReason,
199
+ metadataPatch: payload.metadataPatch,
200
+ }),
201
+ ...(expectedDetailRevision ? { expectedDetailRevision } : {}),
178
202
  };
179
203
  }
180
204
  if (operation.domain === 'task-comments' && operation.mutationKind === 'append') {
@@ -731,6 +755,7 @@ export function registerWorkspaceSyncV3LocalCaptureRoutes(input) {
731
755
  taskId: envelope.entityId,
732
756
  patch: envelope.patch,
733
757
  saveSource: envelope.saveSource,
758
+ expectedDetailRevision: envelope.expectedDetailRevision,
734
759
  now: acceptedAt,
735
760
  actorRef: 'user',
736
761
  onPostCommitError: input.onPostCommitError,
@@ -786,6 +811,7 @@ export function registerWorkspaceSyncV3LocalCaptureRoutes(input) {
786
811
  identity,
787
812
  taskId: envelope.entityId,
788
813
  payload: envelope.payload,
814
+ expectedDetailRevision: envelope.expectedDetailRevision,
789
815
  now: acceptedAt,
790
816
  actorRef: 'user',
791
817
  onPostCommitError: input.onPostCommitError,
@@ -1,5 +1,6 @@
1
1
  import type { SyncAddRoute, SyncRouteAuthConfig, SyncRouteCore } from './syncRouteTypes.js';
2
2
  import type { LocalSyncCoordinatorRouteServices } from '../../sync/coordinator/localSyncCoordinatorRouteServices.js';
3
+ export declare function revisionConflictDetails(error: unknown): Record<string, unknown> | undefined;
3
4
  export declare function isWorkspaceSyncV3LocalFeedApplyEnabled(env?: NodeJS.ProcessEnv): boolean;
4
5
  export declare function isWorkspaceSyncV3CombinedLocalFeedApplyEnabled(env?: NodeJS.ProcessEnv): boolean;
5
6
  export declare function registerWorkspaceSyncV3LocalFeedApplyRoutes(input: {
@@ -8,6 +8,7 @@ import { resolveCombinedFeedCapability, resolveRequestedCombinedFeedCoverage } f
8
8
  import { parseJsonBody } from './primitives.js';
9
9
  import { applyWorkspaceSyncV3TaskCommentAuditPage, readWorkspaceSyncV3TaskCommentAuditCursor, readWorkspaceSyncV3TaskCommentAuditState, } from '../../sync/v3/workspaceSyncV3TaskCommentAudit.js';
10
10
  import { createLocalSyncBrowserApplyPermitTransactionHooks, parseLocalSyncBrowserApplyPermitContext, } from '../../sync/coordinator/localSyncBrowserApplyPermitContext.js';
11
+ import { WorkspaceSyncRevisionConflictError } from '../../sync/v3/syncDurabilityStore.js';
11
12
  const ROUTE_PATH = '/api/taskforce/sync/v3/local/feed';
12
13
  const TASK_COMMENT_AUDIT_PATH = '/api/taskforce/sync/v3/local/task-comment-audit';
13
14
  const MAX_BODY_BYTES = 8 * 1024 * 1024;
@@ -15,6 +16,29 @@ function writeJson(res, statusCode, body) {
15
16
  res.writeHead(statusCode, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
16
17
  res.end(JSON.stringify(body));
17
18
  }
19
+ export function revisionConflictDetails(error) {
20
+ if (!(error instanceof WorkspaceSyncRevisionConflictError) || !error.details)
21
+ return undefined;
22
+ const details = error.details;
23
+ const coordinates = (value) => {
24
+ if (!value || typeof value !== 'object' || Array.isArray(value))
25
+ return undefined;
26
+ const source = value;
27
+ const sequence = source.sequence ?? source.lastSequence;
28
+ return {
29
+ sequence: sequence == null ? null : String(sequence),
30
+ entityRevision: source.entityRevision == null ? null : String(source.entityRevision),
31
+ lifecycleRevision: source.lifecycleRevision == null ? null : String(source.lifecycleRevision),
32
+ };
33
+ };
34
+ return {
35
+ domain: String(details.domain || ''),
36
+ entityId: String(details.entityId || ''),
37
+ reason: String(details.reason || ''),
38
+ ...(coordinates(details.incoming) ? { incoming: coordinates(details.incoming) } : {}),
39
+ ...(coordinates(details.current) ? { current: coordinates(details.current) } : {}),
40
+ };
41
+ }
18
42
  function workspaceFromUrl(req) {
19
43
  try {
20
44
  return String(new URL(req.url || ROUTE_PATH, 'http://localhost').searchParams.get('workspaceId') || '').trim();
@@ -481,12 +505,14 @@ export function registerWorkspaceSyncV3LocalFeedApplyRoutes(input) {
481
505
  catch (error) {
482
506
  const causeCode = String(error?.code || '').trim();
483
507
  const causeAssetId = String(error?.assetId || '').trim();
508
+ const causeDetails = revisionConflictDetails(error);
484
509
  writeJson(res, 409, {
485
510
  success: false,
486
511
  code: 'WORKSPACE_SYNC_V3_LOCAL_FEED_APPLY_REJECTED',
487
512
  error: String(error?.message || error),
488
513
  ...(causeCode ? { causeCode } : {}),
489
514
  ...(causeAssetId ? { causeAssetId } : {}),
515
+ ...(causeDetails ? { causeDetails } : {}),
490
516
  });
491
517
  }
492
518
  });