@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
@@ -6,20 +6,22 @@
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';
24
+ import { beginCloudMcpCapacityRequest, isCloudMcpCapacityTelemetryEnabled, TASKFORCE_CAPACITY_TRACE_HEADER, } from '../cloudMcpCapacityTelemetry.js';
23
25
  // === SECTION: Error helpers ===
24
26
  export function resolveErrorStatusCode(error, fallback = 400) {
25
27
  if (error instanceof TaskforceRuleError)
@@ -273,7 +275,14 @@ function writeMcpHttpError(res, statusCode, message, data) {
273
275
  id: null,
274
276
  }));
275
277
  }
276
- function extractMcpWriteToolNames(body) {
278
+ function resolveProductionCloudMcpToolPolicy(requestedToolName) {
279
+ const toolName = resolveCanonicalMcpToolName(requestedToolName);
280
+ return {
281
+ requiredScope: MCP_CLOUD_TOOL_SCOPE_REQUIREMENTS[toolName] || null,
282
+ isWrite: isMcpWriteToolName(requestedToolName),
283
+ };
284
+ }
285
+ function extractMcpWriteToolNames(body, resolveToolPolicy) {
277
286
  const messages = Array.isArray(body) ? body : [body];
278
287
  const names = messages.flatMap((message) => {
279
288
  if (!message || typeof message !== 'object')
@@ -282,7 +291,7 @@ function extractMcpWriteToolNames(body) {
282
291
  if (method !== 'tools/call')
283
292
  return [];
284
293
  const toolName = String(message?.params?.name || '').trim();
285
- return toolName && isMcpWriteToolName(toolName) ? [toolName] : [];
294
+ return toolName && resolveToolPolicy(toolName).isWrite ? [toolName] : [];
286
295
  });
287
296
  return Array.from(new Set(names));
288
297
  }
@@ -299,7 +308,7 @@ function extractFirstMcpToolName(body) {
299
308
  }
300
309
  return null;
301
310
  }
302
- function findDeniedCloudMcpToolName(body, scopes) {
311
+ function findDeniedCloudMcpToolName(body, scopes, resolveToolPolicy) {
303
312
  const messages = Array.isArray(body) ? body : [body];
304
313
  for (const message of messages) {
305
314
  if (!message || typeof message !== 'object')
@@ -309,15 +318,14 @@ function findDeniedCloudMcpToolName(body, scopes) {
309
318
  const requestedToolName = String(message?.params?.name || '').trim();
310
319
  if (!requestedToolName)
311
320
  continue;
312
- const toolName = resolveCanonicalMcpToolName(requestedToolName);
313
- const requiredScope = MCP_CLOUD_TOOL_SCOPE_REQUIREMENTS[toolName];
321
+ const requiredScope = resolveToolPolicy(requestedToolName).requiredScope;
314
322
  if (!requiredScope || !scopes.includes(requiredScope))
315
323
  return requestedToolName;
316
324
  }
317
325
  return null;
318
326
  }
319
327
  export function makeHandleCloudMcpRequest(core, deps) {
320
- const { ensureAppAccess, resolveAuthenticatedUserId, writeRateLimit } = deps;
328
+ const { ensureAppAccess, resolveAuthenticatedUserId, writeRateLimit, createMcpServer = createTaskforceMcpServer, resolveMcpToolPolicy = resolveProductionCloudMcpToolPolicy, acquireMcpRuntime, capacityTelemetryEnabled = isCloudMcpCapacityTelemetryEnabled, beginCapacityRequest = beginCloudMcpCapacityRequest, } = deps;
321
329
  const authenticateCloudMcpRequest = makeAuthenticateCloudMcpRequest(core, {
322
330
  resolveAuthenticatedUserId,
323
331
  writeMcpHttpError,
@@ -342,7 +350,7 @@ export function makeHandleCloudMcpRequest(core, deps) {
342
350
  const applyCloudMcpWriteRateLimit = (req, res, auth, body) => {
343
351
  if (!writeRateLimit.enabled)
344
352
  return true;
345
- const writeTools = extractMcpWriteToolNames(body);
353
+ const writeTools = extractMcpWriteToolNames(body, resolveMcpToolPolicy);
346
354
  if (writeTools.length === 0)
347
355
  return true;
348
356
  const actorKey = auth.authenticatedViaToken?.tokenId
@@ -398,97 +406,209 @@ export function makeHandleCloudMcpRequest(core, deps) {
398
406
  writeMcpHttpError(res, 400, 'The /mcp HTTP endpoint is only available in cloud runtime. In local runtime, use the local stdio MCP server (for example: `taskforce mcp <project-path>`).');
399
407
  return;
400
408
  }
401
- if (!ensureAppAccess(req, res))
402
- return;
403
- if (req.method !== 'POST' && req.method !== 'GET' && req.method !== 'DELETE') {
404
- writeMcpHttpError(res, 405, 'Method not allowed.');
405
- return;
406
- }
407
- const authStartedAtMs = Date.now();
408
- const auth = authenticateCloudMcpRequest(req, res);
409
- authMs = Date.now() - authStartedAtMs;
410
- if (!auth)
411
- return;
412
- if (req.method !== 'POST') {
413
- writeMcpHttpError(res, 405, 'Method not allowed.');
414
- return;
415
- }
416
- let body = undefined;
417
- try {
418
- const bodyParseStartedAtMs = Date.now();
419
- body = await parseJsonBody(req);
420
- bodyParseMs = Date.now() - bodyParseStartedAtMs;
421
- }
422
- catch (error) {
423
- writeMcpHttpError(res, resolveErrorStatusCode(error, 400), 'Invalid JSON body.');
424
- return;
425
- }
426
- const authScopes = auth.authenticatedViaToken?.scopes || auth.authenticatedViaOAuth?.scopes || [];
427
- const requestId = String(req.headers['x-request-id'] || req.headers['x-railway-request-id'] || '').trim() || randomUUID();
428
- res.setHeader('X-Request-ID', requestId);
429
- const mcpMethod = !Array.isArray(body) && body !== null && typeof body === 'object'
430
- ? String(body.method || '')
431
- : '';
432
- const initializeRequest = isInitializeRequest(body)
433
- || mcpMethod === 'initialize';
434
- const deniedToolName = findDeniedCloudMcpToolName(body, authScopes);
435
- if (deniedToolName) {
436
- core.addMcpAuditLog({
437
- workspaceId: auth.workspaceId,
438
- actorType: auth.authenticatedViaToken ? 'token' : auth.authenticatedViaOAuth ? 'oauth' : 'user',
439
- actorUserId: auth.authenticatedViaToken?.userId || auth.authenticatedViaOAuth?.userId || auth.userId || 'anonymous',
440
- tokenId: auth.authenticatedViaToken?.tokenId || auth.authenticatedViaOAuth?.grantId || null,
441
- toolName: deniedToolName,
442
- details: {
443
- requestId,
444
- ip: req.socket?.remoteAddress || null,
445
- userAgent: requestHeader(req, 'user-agent', '') || null,
446
- outcome: 'deny',
447
- reasonCode: 'scope_denied',
448
- scopes: authScopes
409
+ const capacityRequest = beginCapacityRequest();
410
+ const capacityTraceEnabled = requestHeader(req, TASKFORCE_CAPACITY_TRACE_HEADER, '').trim() === '1';
411
+ return runWithRequestPerformanceDiagnostics(capacityTelemetryEnabled(), async () => {
412
+ let capacitySettled = false;
413
+ const settleCapacity = (aborted = false) => {
414
+ if (capacitySettled)
415
+ return;
416
+ capacitySettled = true;
417
+ capacityRequest.finish({
418
+ statusCode: res.statusCode,
419
+ aborted,
420
+ postgres: getRequestPerformanceDiagnostics(),
421
+ });
422
+ };
423
+ const onFinish = () => settleCapacity(false);
424
+ const onClose = () => settleCapacity(!res.writableEnded);
425
+ res.once('finish', onFinish);
426
+ res.once('close', onClose);
427
+ try {
428
+ if (!ensureAppAccess(req, res))
429
+ return;
430
+ if (req.method !== 'POST' && req.method !== 'GET' && req.method !== 'DELETE') {
431
+ writeMcpHttpError(res, 405, 'Method not allowed.');
432
+ return;
449
433
  }
450
- });
451
- writeMcpHttpError(res, 403, 'Forbidden.');
452
- return;
453
- }
454
- const writeToolNames = extractMcpWriteToolNames(body);
455
- const rateLimitStartedAtMs = Date.now();
456
- const rateLimitAllowed = applyCloudMcpWriteRateLimit(req, res, auth, body);
457
- rateLimitMs = Date.now() - rateLimitStartedAtMs;
458
- if (!rateLimitAllowed)
459
- return;
460
- let runtime = null;
461
- let runtimeConstructionMs = 0;
462
- let transportConnectMs = 0;
463
- let requestHandlingMs = 0;
464
- let cleanupMs = 0;
465
- let outcome = 'success';
466
- const toolTimingState = { value: null };
467
- try {
468
- const runtimeStartedAtMs = Date.now();
469
- // Intentionally isolate the MCP runtime per HTTP request. The runtime closes over
470
- // workspace auth, AI identity, permissions, subscriptions, and mutable helper state;
471
- // sharing it could leak state across tenants or callers. Keep the transport stateless
472
- // 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({
475
- projectRoot: core.getPaths().projectRoot,
476
- tenantId: core.getTenantId(),
477
- workspaceId: auth.workspaceId,
478
- core,
479
- serverName: 'taskforce-cloud',
480
- logStartup: false,
481
- runtimeMode: 'cloud',
482
- applicationBaseUrl: resolveCloudApplicationBaseUrl(),
483
- auth: buildCloudMcpRuntimeAuth({
484
- req,
485
- auth,
486
- requestHeader,
487
- requestId,
488
- authScopes,
489
- }),
490
- onToolCallTiming: (timing) => {
491
- toolTimingState.value = timing;
434
+ const authStartedAtMs = Date.now();
435
+ const auth = authenticateCloudMcpRequest(req, res);
436
+ authMs = Date.now() - authStartedAtMs;
437
+ if (!auth)
438
+ return;
439
+ if (capacityTraceEnabled)
440
+ capacityRequest.setTraceHeaders(res);
441
+ if (req.method !== 'POST') {
442
+ writeMcpHttpError(res, 405, 'Method not allowed.');
443
+ return;
444
+ }
445
+ if (!isJsonContentType(requestHeader(req, 'content-type', ''))) {
446
+ writeMcpHttpError(res, 415, 'Unsupported Media Type: Content-Type must be application/json');
447
+ return;
448
+ }
449
+ let body = undefined;
450
+ try {
451
+ const bodyParseStartedAtMs = Date.now();
452
+ body = await parseJsonBody(req);
453
+ bodyParseMs = Date.now() - bodyParseStartedAtMs;
454
+ }
455
+ catch (error) {
456
+ writeMcpHttpError(res, resolveErrorStatusCode(error, 400), 'Invalid JSON body.');
457
+ return;
458
+ }
459
+ const authScopes = auth.authenticatedViaToken?.scopes || auth.authenticatedViaOAuth?.scopes || [];
460
+ const requestId = String(req.headers['x-request-id'] || req.headers['x-railway-request-id'] || '').trim() || randomUUID();
461
+ res.setHeader('X-Request-ID', requestId);
462
+ const mcpMethod = !Array.isArray(body) && body !== null && typeof body === 'object'
463
+ ? String(body.method || '')
464
+ : '';
465
+ const initializeRequest = isInitializeRequest(body)
466
+ || mcpMethod === 'initialize';
467
+ const modernProtocolRequest = await isModernMcpHttpRequest(req, body);
468
+ const writeToolNames = extractMcpWriteToolNames(body, resolveMcpToolPolicy);
469
+ const requestClass = initializeRequest
470
+ ? 'initialize'
471
+ : mcpMethod === 'server/discover'
472
+ ? 'discover'
473
+ : mcpMethod === 'tools/list'
474
+ ? 'tools_list'
475
+ : writeToolNames.length > 0
476
+ ? 'write'
477
+ : extractFirstMcpToolName(body)
478
+ ? 'read'
479
+ : 'other';
480
+ capacityRequest.classify(requestClass);
481
+ const deniedToolName = findDeniedCloudMcpToolName(body, authScopes, resolveMcpToolPolicy);
482
+ if (deniedToolName) {
483
+ core.addMcpAuditLog({
484
+ workspaceId: auth.workspaceId,
485
+ actorType: auth.authenticatedViaToken ? 'token' : auth.authenticatedViaOAuth ? 'oauth' : 'user',
486
+ actorUserId: auth.authenticatedViaToken?.userId || auth.authenticatedViaOAuth?.userId || auth.userId || 'anonymous',
487
+ tokenId: auth.authenticatedViaToken?.tokenId || auth.authenticatedViaOAuth?.grantId || null,
488
+ toolName: deniedToolName,
489
+ details: {
490
+ requestId,
491
+ ip: req.socket?.remoteAddress || null,
492
+ userAgent: requestHeader(req, 'user-agent', '') || null,
493
+ outcome: 'deny',
494
+ reasonCode: 'scope_denied',
495
+ scopes: authScopes
496
+ }
497
+ });
498
+ writeMcpHttpError(res, 403, 'Forbidden.');
499
+ return;
500
+ }
501
+ const rateLimitStartedAtMs = Date.now();
502
+ const rateLimitAllowed = applyCloudMcpWriteRateLimit(req, res, auth, body);
503
+ rateLimitMs = Date.now() - rateLimitStartedAtMs;
504
+ if (!rateLimitAllowed)
505
+ return;
506
+ let runtime = null;
507
+ let runtimeLease = null;
508
+ let runtimeConstructionMs = 0;
509
+ let transportConnectMs = 0;
510
+ let requestHandlingMs = 0;
511
+ let cleanupMs = 0;
512
+ let outcome = 'success';
513
+ const toolTimingState = { value: null };
514
+ try {
515
+ const runtimeStartedAtMs = Date.now();
516
+ // Production intentionally isolates the MCP runtime per HTTP request. The runtime closes over
517
+ // workspace auth, AI identity, permissions, subscriptions, and mutable helper state;
518
+ // sharing it could leak state across tenants or callers. Keep the transport stateless
519
+ // too. The timing event below measures construction cost so caching is only revisited
520
+ // with evidence and must preserve these boundaries (including dynamic tool schemas). The optional
521
+ // lease seam exists only for transport conformance tests that must carry legacy bidirectional calls.
522
+ const runtimeOptions = {
523
+ projectRoot: core.getPaths().projectRoot,
524
+ tenantId: core.getTenantId(),
525
+ workspaceId: auth.workspaceId,
526
+ core,
527
+ serverName: 'taskforce-cloud',
528
+ logStartup: false,
529
+ runtimeMode: 'cloud',
530
+ toolProfile: auth.authenticatedViaToken?.toolProfile || auth.authenticatedViaOAuth?.toolProfile || 'default',
531
+ applicationBaseUrl: resolveCloudApplicationBaseUrl(),
532
+ auth: buildCloudMcpRuntimeAuth({
533
+ req,
534
+ auth,
535
+ requestHeader,
536
+ requestId,
537
+ authScopes,
538
+ }),
539
+ onToolCallTiming: (timing) => {
540
+ toolTimingState.value = timing;
541
+ if (!res.headersSent) {
542
+ if (capacityTraceEnabled) {
543
+ capacityRequest.setTraceHeaders(res, getRequestPerformanceDiagnostics());
544
+ }
545
+ setServerTimingHeader(res, [
546
+ { name: 'auth', durationMs: authMs },
547
+ { name: 'body-parse', durationMs: bodyParseMs },
548
+ { name: 'rate-limit', durationMs: rateLimitMs },
549
+ { name: 'runtime', durationMs: runtimeConstructionMs },
550
+ { name: 'transport-connect', durationMs: transportConnectMs },
551
+ { name: 'tool-envelope-prepare', durationMs: timing.preparationMs },
552
+ { name: 'tool-envelope-validate', durationMs: timing.validationMs },
553
+ { name: 'tool-handler', durationMs: timing.handlerMs },
554
+ ...Object.entries(timing.subphases).map(([phase, durationMs]) => ({
555
+ name: `tool-${phase}`,
556
+ durationMs,
557
+ })),
558
+ ]);
559
+ }
560
+ },
561
+ };
562
+ if (modernProtocolRequest) {
563
+ const requestHandlingStartedAtMs = Date.now();
564
+ await handleModernMcpHttpRequest({
565
+ req,
566
+ res,
567
+ parsedBody: body,
568
+ factory: ({ era }) => {
569
+ const constructionStartedAtMs = Date.now();
570
+ const modernRuntime = createStatelessTaskforceMcpServer({
571
+ ...runtimeOptions,
572
+ protocolEra: era,
573
+ }, createMcpServer);
574
+ runtimeConstructionMs = Date.now() - constructionStartedAtMs;
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
+ ]);
582
+ }
583
+ return modernRuntime.server;
584
+ },
585
+ onerror: (error) => {
586
+ console.warn('[Taskforce MCP] Modern cloud request rejected:', {
587
+ requestId,
588
+ message: error.message,
589
+ });
590
+ },
591
+ });
592
+ requestHandlingMs = Date.now() - requestHandlingStartedAtMs;
593
+ recordCloudMcpCredentialUsage(req, auth.authenticatedViaToken, auth.authenticatedViaOAuth);
594
+ return;
595
+ }
596
+ runtimeLease = acquireMcpRuntime
597
+ ? await acquireMcpRuntime({ req, options: runtimeOptions })
598
+ : null;
599
+ runtime = runtimeLease?.runtime
600
+ || createStatelessTaskforceMcpServer(runtimeOptions, createMcpServer);
601
+ runtimeConstructionMs = Date.now() - runtimeStartedAtMs;
602
+ const transport = runtimeLease?.transport || new NodeStreamableHTTPServerTransport({
603
+ sessionIdGenerator: undefined,
604
+ enableJsonResponse: true,
605
+ });
606
+ const transportStartedAtMs = Date.now();
607
+ if (!runtimeLease)
608
+ await runtime.server.connect(transport);
609
+ transportConnectMs = Date.now() - transportStartedAtMs;
610
+ // Set request-level phases before the SDK writes response headers. Tool calls replace this
611
+ // with the richer envelope/handler breakdown from onToolCallTiming above.
492
612
  if (!res.headersSent) {
493
613
  setServerTimingHeader(res, [
494
614
  { name: 'auth', durationMs: authMs },
@@ -496,94 +616,90 @@ export function makeHandleCloudMcpRequest(core, deps) {
496
616
  { name: 'rate-limit', durationMs: rateLimitMs },
497
617
  { name: 'runtime', durationMs: runtimeConstructionMs },
498
618
  { name: 'transport-connect', durationMs: transportConnectMs },
499
- { name: 'tool-envelope-prepare', durationMs: timing.preparationMs },
500
- { name: 'tool-envelope-validate', durationMs: timing.validationMs },
501
- { name: 'tool-handler', durationMs: timing.handlerMs },
502
- ...Object.entries(timing.subphases).map(([phase, durationMs]) => ({
503
- name: `tool-${phase}`,
504
- durationMs,
505
- })),
506
619
  ]);
507
620
  }
508
- },
509
- });
510
- runtimeConstructionMs = Date.now() - runtimeStartedAtMs;
511
- const transport = new StreamableHTTPServerTransport({
512
- sessionIdGenerator: undefined,
513
- enableJsonResponse: true,
514
- });
515
- const transportStartedAtMs = Date.now();
516
- await runtime.server.connect(transport);
517
- transportConnectMs = Date.now() - transportStartedAtMs;
518
- if (!initializeRequest) {
519
- // Stateless cloud sessions still require a valid MCP JSON-RPC request;
520
- // let the SDK validate and respond rather than trying to track sessions server-side.
521
- }
522
- const requestHandlingStartedAtMs = Date.now();
523
- await transport.handleRequest(req, res, body);
524
- requestHandlingMs = Date.now() - requestHandlingStartedAtMs;
525
- recordCloudMcpCredentialUsage(req, auth.authenticatedViaToken, auth.authenticatedViaOAuth);
526
- }
527
- catch (error) {
528
- outcome = 'failure';
529
- console.error('[Taskforce MCP] Cloud transport request failed:', {
530
- requestId,
531
- kind: 'tool_transport_failure',
532
- message: error instanceof Error ? error.message : String(error),
533
- });
534
- if (!res.headersSent) {
535
- writeMcpHttpError(res, 500, 'MCP transport failure.', {
536
- kind: 'tool_transport_failure',
537
- retryable: true,
538
- requestId,
539
- });
540
- }
541
- }
542
- finally {
543
- if (runtime) {
544
- const cleanupStartedAtMs = Date.now();
545
- try {
546
- await runtime.server.close();
621
+ const requestHandlingStartedAtMs = Date.now();
622
+ await transport.handleRequest(req, res, body);
623
+ requestHandlingMs = Date.now() - requestHandlingStartedAtMs;
624
+ recordCloudMcpCredentialUsage(req, auth.authenticatedViaToken, auth.authenticatedViaOAuth);
547
625
  }
548
- catch (closeError) {
549
- console.warn('[Taskforce MCP] Cloud transport cleanup failed:', closeError);
626
+ catch (error) {
627
+ outcome = 'failure';
628
+ console.error('[Taskforce MCP] Cloud transport request failed:', {
629
+ requestId,
630
+ kind: 'tool_transport_failure',
631
+ message: error instanceof Error ? error.message : String(error),
632
+ });
633
+ if (!res.headersSent) {
634
+ writeMcpHttpError(res, 500, 'MCP transport failure.', {
635
+ kind: 'tool_transport_failure',
636
+ retryable: true,
637
+ requestId,
638
+ });
639
+ }
640
+ }
641
+ finally {
642
+ if (runtimeLease) {
643
+ const cleanupStartedAtMs = Date.now();
644
+ try {
645
+ await runtimeLease.release();
646
+ }
647
+ catch (closeError) {
648
+ console.warn('[Taskforce MCP] Cloud test runtime lease cleanup failed:', closeError);
649
+ }
650
+ cleanupMs = Date.now() - cleanupStartedAtMs;
651
+ }
652
+ else if (runtime) {
653
+ const cleanupStartedAtMs = Date.now();
654
+ try {
655
+ await runtime.server.close();
656
+ }
657
+ catch (closeError) {
658
+ console.warn('[Taskforce MCP] Cloud transport cleanup failed:', closeError);
659
+ }
660
+ cleanupMs = Date.now() - cleanupStartedAtMs;
661
+ }
662
+ const totalDurationMs = Date.now() - requestStartedAtMs;
663
+ if (initializeRequest || mcpMethod === 'tools/list' || writeToolNames.length > 0 || totalDurationMs >= 250) {
664
+ const timingSnapshot = toolTimingState.value;
665
+ console.info(`[Taskforce MCP] ${JSON.stringify({
666
+ event: 'cloud_request_timing',
667
+ requestId,
668
+ requestKind: initializeRequest
669
+ ? 'initialize'
670
+ : mcpMethod === 'tools/list'
671
+ ? 'tools_list'
672
+ : (extractFirstMcpToolName(body) ? 'tool_call' : 'other'),
673
+ method: mcpMethod || null,
674
+ toolName: extractFirstMcpToolName(body),
675
+ workspaceId: auth.workspaceId,
676
+ databaseProvider: core.getDatabaseProvider(),
677
+ authMode: auth.authenticatedViaToken ? 'token' : auth.authenticatedViaOAuth ? 'oauth' : 'user',
678
+ batchSize: Array.isArray(body) ? body.length : 1,
679
+ isWrite: writeToolNames.length > 0,
680
+ outcome,
681
+ httpStatus: res.statusCode,
682
+ responseBytes: timingSnapshot?.responseBytes ?? null,
683
+ totalDurationMs,
684
+ preRuntimeMs: Math.max(0, totalDurationMs - runtimeConstructionMs - transportConnectMs - requestHandlingMs - cleanupMs),
685
+ authMs,
686
+ bodyParseMs,
687
+ rateLimitMs,
688
+ runtimeConstructionMs,
689
+ transportConnectMs,
690
+ requestHandlingMs,
691
+ cleanupMs,
692
+ toolTiming: timingSnapshot,
693
+ })}`);
694
+ }
550
695
  }
551
- cleanupMs = Date.now() - cleanupStartedAtMs;
552
696
  }
553
- const totalDurationMs = Date.now() - requestStartedAtMs;
554
- if (initializeRequest || mcpMethod === 'tools/list' || writeToolNames.length > 0 || totalDurationMs >= 250) {
555
- const timingSnapshot = toolTimingState.value;
556
- console.info(`[Taskforce MCP] ${JSON.stringify({
557
- event: 'cloud_request_timing',
558
- requestId,
559
- requestKind: initializeRequest
560
- ? 'initialize'
561
- : mcpMethod === 'tools/list'
562
- ? 'tools_list'
563
- : (extractFirstMcpToolName(body) ? 'tool_call' : 'other'),
564
- method: mcpMethod || null,
565
- toolName: extractFirstMcpToolName(body),
566
- workspaceId: auth.workspaceId,
567
- databaseProvider: core.getDatabaseProvider(),
568
- authMode: auth.authenticatedViaToken ? 'token' : auth.authenticatedViaOAuth ? 'oauth' : 'user',
569
- batchSize: Array.isArray(body) ? body.length : 1,
570
- isWrite: writeToolNames.length > 0,
571
- outcome,
572
- httpStatus: res.statusCode,
573
- responseBytes: timingSnapshot?.responseBytes ?? null,
574
- totalDurationMs,
575
- preRuntimeMs: Math.max(0, totalDurationMs - runtimeConstructionMs - transportConnectMs - requestHandlingMs - cleanupMs),
576
- authMs,
577
- bodyParseMs,
578
- rateLimitMs,
579
- runtimeConstructionMs,
580
- transportConnectMs,
581
- requestHandlingMs,
582
- cleanupMs,
583
- toolTiming: timingSnapshot,
584
- })}`);
697
+ finally {
698
+ settleCapacity(Boolean(req.destroyed && !res.writableEnded));
699
+ res.off('finish', onFinish);
700
+ res.off('close', onClose);
585
701
  }
586
- }
702
+ });
587
703
  };
588
704
  }
589
705
  // === SECTION: Request header helpers ===
@@ -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';
@@ -54,7 +55,9 @@ export function registerWorkspaceSyncAuxRoutes({ addRoute, core, context, resolv
54
55
  // stale links. Does NOT tombstone metadata for files that appear missing locally — a single
55
56
  // failed existence check at startup can mean the content is only temporarily unavailable
56
57
  // (e.g. storage not yet mounted/synced), not deleted; that requires explicit admin
57
- // confirmation via /api/taskforce/admin/workspace-repair/apply. Never deletes files.
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.
58
61
  // Called once by the sync orchestrator when the workspace becomes active.
59
62
  addRoute('POST', '/api/taskforce/sync/workspace/repair-startup', async (req, res) => {
60
63
  const authConfig = context.authConfig;
@@ -83,6 +86,7 @@ export function registerWorkspaceSyncAuxRoutes({ addRoute, core, context, resolv
83
86
  deletedTasks: core.listWorkspaceSyncDeletes(workspaceId) || [],
84
87
  workspaceAssetStore,
85
88
  publishedContentResolver,
89
+ contentPullObligationStore: new WorkspaceSyncContentPullObligationStore(core.getDatabaseAdapter()),
86
90
  aiProfiles: typeof core.listAiProfiles === 'function'
87
91
  ? core.listAiProfiles(workspaceId, { includeArchived: true }) || []
88
92
  : [],
@@ -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,