@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
@@ -26,13 +26,21 @@ function requireMutationResult(task, taskId) {
26
26
  throw new TaskChecklistCommandError(`Task ${taskId} not found`, 'TASK_NOT_FOUND', 404, { taskId });
27
27
  }
28
28
  export function createTaskChecklistCommandService(deps) {
29
- const replaceItems = (taskId, items, operationKey) => {
30
- requireMutationResult(deps.replace({
29
+ const replaceItems = (taskId, items, operationKey, options) => {
30
+ const mutated = deps.replace({
31
31
  taskId,
32
32
  items,
33
- operationId: deps.createId('operation', operationKey),
34
- }), taskId);
35
- return deps.listItems(taskId);
33
+ operationId: options?.operationId || deps.createId('operation', operationKey),
34
+ ...(options?.expectedDetailRevision
35
+ ? { expectedDetailRevision: options.expectedDetailRevision }
36
+ : {}),
37
+ ...(options?.requireDurableIdempotency
38
+ ? { requireDurableIdempotency: true }
39
+ : {}),
40
+ ...(options?.itemUpdateIntent ? { itemUpdateIntent: options.itemUpdateIntent } : {}),
41
+ });
42
+ requireMutationResult(mutated, taskId);
43
+ return mutated?.checklistItems || deps.listItems(taskId);
36
44
  };
37
45
  return {
38
46
  replace(input) {
@@ -107,5 +115,75 @@ export function createTaskChecklistCommandService(deps) {
107
115
  items,
108
116
  };
109
117
  },
118
+ update(input) {
119
+ const task = deps.resolveTask(input.taskId);
120
+ const itemId = String(input.itemId ?? '').trim();
121
+ if (!itemId) {
122
+ throw new TaskChecklistCommandError('update_task_checklist_item requires itemId.');
123
+ }
124
+ const currentItems = deps.listItems(task.id);
125
+ const existingItem = currentItems.find((item) => item.id === itemId);
126
+ if (!existingItem) {
127
+ throw new TaskChecklistCommandError(`Checklist item ${itemId} was not found on task ${task.id}.`, 'TASK_CHECKLIST_ITEM_NOT_FOUND', 404, { taskId: task.id, itemId });
128
+ }
129
+ const hasTitle = input.title !== undefined || input.text !== undefined;
130
+ const hasCompleted = input.isCompleted !== undefined || input.done !== undefined;
131
+ const hasOrder = input.order !== undefined;
132
+ if (!hasTitle && !hasCompleted && !hasOrder) {
133
+ throw new TaskChecklistCommandError('update_task_checklist_item requires at least one of text, done, or order.');
134
+ }
135
+ const title = hasTitle
136
+ ? normalizeTitle(input.title ?? input.text, 'update_task_checklist_item text')
137
+ : existingItem.title;
138
+ const completedInput = input.isCompleted ?? input.done;
139
+ if (hasCompleted && typeof completedInput !== 'boolean') {
140
+ throw new TaskChecklistCommandError('update_task_checklist_item done must be a boolean.');
141
+ }
142
+ const isCompleted = hasCompleted ? completedInput : existingItem.isCompleted;
143
+ const parsedOrder = hasOrder ? Number(input.order) : existingItem.order;
144
+ if (hasOrder && (!Number.isInteger(parsedOrder) || parsedOrder < 0)) {
145
+ throw new TaskChecklistCommandError('update_task_checklist_item order must be a non-negative integer.');
146
+ }
147
+ const expectedDetailRevision = input.expectedDetailRevision === undefined
148
+ ? undefined
149
+ : String(input.expectedDetailRevision).trim();
150
+ if (input.expectedDetailRevision !== undefined && !expectedDetailRevision) {
151
+ throw new TaskChecklistCommandError('update_task_checklist_item expectedDetailRevision must contain non-whitespace text.');
152
+ }
153
+ const unchanged = existingItem.title === title
154
+ && existingItem.isCompleted === isCompleted
155
+ && existingItem.order === parsedOrder;
156
+ const nextItem = unchanged
157
+ ? existingItem
158
+ : {
159
+ ...existingItem,
160
+ title,
161
+ isCompleted,
162
+ order: parsedOrder,
163
+ updatedAt: deps.now(),
164
+ };
165
+ const nextItems = currentItems.map((item) => item.id === itemId ? nextItem : item);
166
+ const items = replaceItems(task.id, nextItems, `task-checklist-update:${task.id}:${itemId}`, {
167
+ operationId: input.operationId,
168
+ expectedDetailRevision,
169
+ requireDurableIdempotency: input.requireDurableIdempotency,
170
+ ...(input.requireDurableIdempotency ? {
171
+ itemUpdateIntent: {
172
+ kind: 'item-update',
173
+ itemId,
174
+ patch: {
175
+ ...(hasTitle ? { text: title } : {}),
176
+ ...(hasCompleted ? { done: isCompleted } : {}),
177
+ ...(hasOrder ? { order: parsedOrder } : {}),
178
+ },
179
+ },
180
+ } : {}),
181
+ });
182
+ const item = items.find((candidate) => candidate.id === itemId);
183
+ if (!item) {
184
+ throw new TaskChecklistCommandError(`Checklist item ${itemId} was not found after updating task ${task.id}.`, 'TASK_CHECKLIST_ITEM_NOT_FOUND', 404, { taskId: task.id, itemId });
185
+ }
186
+ return { taskId: task.id, item, items };
187
+ },
110
188
  };
111
189
  }
@@ -30,6 +30,7 @@ export interface TaskLifecycleCommandServiceDependencies {
30
30
  updates: Record<string, unknown>;
31
31
  forceDurable?: boolean;
32
32
  assigneeIntent?: TaskLifecycleAssigneeIntent;
33
+ handoffComment?: string;
33
34
  }): TaskLifecycleTask;
34
35
  mutateLifecycle(input: {
35
36
  taskId: string;
@@ -40,7 +41,7 @@ export interface TaskLifecycleCommandServiceDependencies {
40
41
  reason: string | undefined;
41
42
  };
42
43
  }): TaskLifecycleTask | null;
43
- resolveReviewer(task: TaskLifecycleTask): TaskLifecycleReviewerResolution;
44
+ resolveReviewer(task: TaskLifecycleTask, reviewer?: unknown): TaskLifecycleReviewerResolution;
44
45
  }
45
46
  export declare class TaskLifecycleCommandError extends Error {
46
47
  readonly code: string;
@@ -81,6 +82,7 @@ export declare function createTaskLifecycleCommandService(deps: TaskLifecycleCom
81
82
  finish(task: TaskLifecycleTask, input: {
82
83
  outcome: unknown;
83
84
  comment?: unknown;
85
+ reviewer?: unknown;
84
86
  }): FinishTaskCommandResult;
85
87
  reopen(task: TaskLifecycleTask, input: {
86
88
  activeAiProfileId: string | null | undefined;
@@ -88,8 +88,12 @@ export function createTaskLifecycleCommandService(deps) {
88
88
  nextTool: 'reopen_task',
89
89
  });
90
90
  }
91
+ const normalizedComment = typeof input.comment === 'string' ? input.comment.trim() : '';
92
+ if (normalizedOutcome === 'review' && !normalizedComment) {
93
+ throw new TaskLifecycleCommandError('finish_task requires a nonblank handoff comment when outcome is review.', 'TASK_FINISH_REVIEW_COMMENT_REQUIRED', 400, { taskId: task.id, outcome: normalizedOutcome });
94
+ }
91
95
  const reviewerResolution = normalizedOutcome === 'review'
92
- ? deps.resolveReviewer(task)
96
+ ? deps.resolveReviewer(task, input.reviewer)
93
97
  : undefined;
94
98
  const updated = deps.setStatus({
95
99
  task,
@@ -99,8 +103,8 @@ export function createTaskLifecycleCommandService(deps) {
99
103
  ...(reviewerResolution
100
104
  ? { assigneeIntent: { kind: 'set', value: reviewerResolution.assignee } }
101
105
  : {}),
106
+ ...(normalizedOutcome === 'review' ? { handoffComment: normalizedComment } : {}),
102
107
  });
103
- const normalizedComment = typeof input.comment === 'string' ? input.comment.trim() : '';
104
108
  return {
105
109
  task: updated,
106
110
  completion: {
@@ -5,6 +5,7 @@ import type { DurableTaskStatusMutationPayload } from './TaskDurableStatusMutati
5
5
  import { WorkspaceAssetStore } from '../storage/workspaceAssetStore.js';
6
6
  import { resolveAdminAuditRetentionPolicy, type AdminAuditRetentionDiagnostics, type AdminAuditRetentionRun } from './AdminAuditRetentionService.js';
7
7
  import type { WorkspaceSyncV3TaskAttachmentLink } from '../sync/v3/workspaceSyncV3NestedTaskCodecs.js';
8
+ import { type InternalUserFeatureKey } from '../shared/userFeatureGrants.js';
8
9
  import type { TaskRestoreDestination } from '../shared/taskRestoreDestination.js';
9
10
  import { type SyncEventInput } from './SyncReconciliationService.js';
10
11
  import { type FirstClassTaxonomyDisplayLabels, type NormalizedWorkspaceTaxonomyState, type WorkspaceTaxonomyState } from '../shared/taxonomyState.js';
@@ -458,6 +459,7 @@ export type SystemRole = 'system_admin' | 'user';
458
459
  type PermissionMode = 'read-only' | 'read-write';
459
460
  type AuthTokenPurpose = 'email_verification' | 'password_reset' | 'invite_accept';
460
461
  export type McpAccessTokenScope = 'tasks:read' | 'tasks:write' | 'workspace:read';
462
+ export type McpCloudToolProfile = 'default' | 'extended';
461
463
  type McpAccessTokenStatus = 'active' | 'revoked' | 'expired';
462
464
  export type McpOAuthProvider = 'chatgpt' | 'claude' | 'grok' | 'gemini' | 'mistral' | 'perplexity';
463
465
  type McpOAuthClientStatus = 'active' | 'revoked';
@@ -586,6 +588,7 @@ interface SystemUserRecord {
586
588
  systemRole: SystemRole;
587
589
  betaAccess: boolean;
588
590
  disabled: boolean;
591
+ internalFeatureGrants: InternalUserFeatureKey[];
589
592
  planId?: string | null;
590
593
  planName?: string | null;
591
594
  planVersionId?: string | null;
@@ -608,6 +611,7 @@ export interface PurgedSystemUserSummary {
608
611
  deletedMcpOauthConnectorGrantCount: number;
609
612
  deletedUiStateCount: number;
610
613
  deletedUserPreferenceCount: number;
614
+ deletedUserFeatureGrantCount: number;
611
615
  deletedEntitlementCount: number;
612
616
  deletedUserBillingCount: number;
613
617
  deletedUserCount: number;
@@ -772,6 +776,7 @@ export interface McpAccessTokenRecord {
772
776
  userEmail?: string | null;
773
777
  name: string;
774
778
  scopes: McpAccessTokenScope[];
779
+ toolProfile: McpCloudToolProfile;
775
780
  tokenPrefix: string;
776
781
  status: McpAccessTokenStatus;
777
782
  lastUsedAt?: string | null;
@@ -799,6 +804,7 @@ export interface McpAccessTokenAuthResult {
799
804
  workspaceId: string;
800
805
  userId: string;
801
806
  scopes: McpAccessTokenScope[];
807
+ toolProfile?: McpCloudToolProfile;
802
808
  status: McpAccessTokenStatus;
803
809
  }
804
810
  export interface McpAccessTokenInspectionResult {
@@ -808,12 +814,14 @@ export interface McpAccessTokenInspectionResult {
808
814
  userId: string;
809
815
  name: string;
810
816
  scopes: McpAccessTokenScope[];
817
+ toolProfile: McpCloudToolProfile;
811
818
  status: McpAccessTokenStatus;
812
819
  }
813
820
  export interface McpOAuthClientRecord {
814
821
  id: string;
815
822
  provider: McpOAuthProvider;
816
823
  clientName: string;
824
+ applicationType: 'native' | 'web';
817
825
  productClientId?: string | null;
818
826
  redirectUris: string[];
819
827
  status: McpOAuthClientStatus;
@@ -829,6 +837,7 @@ export interface McpOAuthConnectorGrantRecord {
829
837
  workspaceId: string;
830
838
  userId: string;
831
839
  scopes: McpAccessTokenScope[];
840
+ toolProfile: McpCloudToolProfile;
832
841
  tokenPrefix: string;
833
842
  status: McpOAuthGrantStatus;
834
843
  lastUsedAt?: string | null;
@@ -851,6 +860,7 @@ export interface McpOAuthAccessTokenAuthResult {
851
860
  provider: McpOAuthProvider;
852
861
  productClientId?: string | null;
853
862
  scopes: McpAccessTokenScope[];
863
+ toolProfile?: McpCloudToolProfile;
854
864
  status: McpOAuthGrantStatus;
855
865
  aiProfileId?: string | null;
856
866
  aiProfileToken?: string | null;
@@ -964,7 +974,9 @@ export interface TaskforceSyncCapable {
964
974
  upsertInitiativeForSync(initiative: InitiativeItem, workspaceId?: string | null): InitiativeItem;
965
975
  upsertWorkstreamForSync(workstream: WorkstreamItem, workspaceId?: string | null): WorkstreamItem;
966
976
  upsertDocumentReviewSessionForSync(session: DocumentReviewSessionRecord): DocumentReviewSessionRecord;
967
- upsertDocumentReviewCommentForSync(comment: DocumentReviewCommentSyncRecord): DocumentReviewCommentSyncRecord;
977
+ upsertDocumentReviewCommentForSync(comment: DocumentReviewCommentSyncRecord, options?: {
978
+ allowAuthoritativeThreadReconciliation?: boolean;
979
+ }): DocumentReviewCommentSyncRecord;
968
980
  upsertAnnotatedAttachmentSessionForSync(session: AnnotatedAttachmentSessionRecord): AnnotatedAttachmentSessionRecord;
969
981
  upsertTaskEventForSync(event: TaskEvent): TaskEvent;
970
982
  upsertEntityEventForSync(event: EntityEvent, options?: {
@@ -1633,6 +1645,9 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1633
1645
  setSystemRole(userId: string, role: SystemRole): boolean;
1634
1646
  setUserDisabledGlobal(userId: string, disabled: boolean): boolean;
1635
1647
  setUserBetaAccessGlobal(userId: string, enabled: boolean): boolean;
1648
+ hasUserFeatureGrant(userId: string, featureKey: unknown): boolean;
1649
+ listUserFeatureGrants(userId: string): InternalUserFeatureKey[];
1650
+ setUserFeatureGrant(userId: string, featureKey: unknown, enabled: boolean, updatedBy?: string | null): boolean;
1636
1651
  markUserEmailVerified(userId: string): {
1637
1652
  emailVerifiedAt: string;
1638
1653
  } | null;
@@ -1774,7 +1789,9 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1774
1789
  includeDeleted?: boolean;
1775
1790
  }): AnnotatedAttachmentSessionRecord[];
1776
1791
  upsertDocumentReviewSessionForSync(session: DocumentReviewSessionRecord): DocumentReviewSessionRecord;
1777
- upsertDocumentReviewCommentForSync(comment: Omit<DocumentReviewCommentSyncRecord, 'parentCommentId' | 'threadStatus' | 'threadStatusUpdatedAt' | 'resolvedAt' | 'resolvedByActorId'> & Partial<Pick<DocumentReviewCommentSyncRecord, 'parentCommentId' | 'threadStatus' | 'threadStatusUpdatedAt' | 'resolvedAt' | 'resolvedByActorId'>>): DocumentReviewCommentSyncRecord;
1792
+ upsertDocumentReviewCommentForSync(comment: Omit<DocumentReviewCommentSyncRecord, 'parentCommentId' | 'threadStatus' | 'threadStatusUpdatedAt' | 'resolvedAt' | 'resolvedByActorId'> & Partial<Pick<DocumentReviewCommentSyncRecord, 'parentCommentId' | 'threadStatus' | 'threadStatusUpdatedAt' | 'resolvedAt' | 'resolvedByActorId'>>, options?: {
1793
+ allowAuthoritativeThreadReconciliation?: boolean;
1794
+ }): DocumentReviewCommentSyncRecord;
1778
1795
  upsertAnnotatedAttachmentSessionForSync(session: AnnotatedAttachmentSessionRecord): AnnotatedAttachmentSessionRecord;
1779
1796
  upsertTaskEventForSync(event: TaskEvent): TaskEvent;
1780
1797
  upsertEntityEventForSync(event: EntityEvent, options?: {
@@ -2208,6 +2225,15 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
2208
2225
  tokenId: string;
2209
2226
  createdByIp?: string | null;
2210
2227
  }): McpAccessTokenIssueResult;
2228
+ updateMcpAccessTokenToolProfile(input: {
2229
+ actorUserId: string;
2230
+ workspaceId: string;
2231
+ tokenId: string;
2232
+ toolProfile: unknown;
2233
+ }): {
2234
+ record: McpAccessTokenRecord;
2235
+ previousToolProfile: McpCloudToolProfile;
2236
+ };
2211
2237
  authenticateMcpAccessToken(token: string, workspaceId?: string): McpAccessTokenAuthResult | null;
2212
2238
  inspectMcpAccessToken(token: string): McpAccessTokenInspectionResult | null;
2213
2239
  recordMcpAccessTokenUsage(input: {
@@ -2220,6 +2246,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
2220
2246
  provider: McpOAuthProvider | string;
2221
2247
  clientName: string;
2222
2248
  redirectUris: unknown;
2249
+ applicationType?: unknown;
2223
2250
  productClientId?: string | null;
2224
2251
  }): McpOAuthClientRecord;
2225
2252
  getMcpOAuthClient(clientId: string, provider?: McpOAuthProvider | string | null): McpOAuthClientRecord | null;
@@ -2253,6 +2280,15 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
2253
2280
  workspaceId: string;
2254
2281
  grantId: string;
2255
2282
  }): McpOAuthConnectorGrantRecord;
2283
+ updateMcpOAuthConnectorGrantToolProfile(input: {
2284
+ actorUserId: string;
2285
+ workspaceId: string;
2286
+ grantId: string;
2287
+ toolProfile: unknown;
2288
+ }): {
2289
+ record: McpOAuthConnectorGrantRecord;
2290
+ previousToolProfile: McpCloudToolProfile;
2291
+ };
2256
2292
  authenticateMcpOAuthAccessToken(token: string, workspaceId?: string): McpOAuthAccessTokenAuthResult | null;
2257
2293
  bindMcpOAuthConnectorGrantAiProfile(input: {
2258
2294
  grantId: string;
@@ -2426,7 +2462,9 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
2426
2462
  notifyDurableWorkflowRuntimeCommitted(workspaceId: string, _executionId: string): void;
2427
2463
  installDurableInitiativeAuthoritativeForSync(initiative: InitiativeItem, workspaceId: string): InitiativeItem;
2428
2464
  installDurableWorkstreamAuthoritativeForSync(workstream: WorkstreamItem, workspaceId: string): WorkstreamItem;
2429
- installDurableTaskCreateAuthoritativeForSync(task: TaskItem, workspaceId: string): TaskItem;
2465
+ installDurableTaskCreateAuthoritativeForSync(task: TaskItem, workspaceId: string, options?: {
2466
+ preserveDeletedSuccessor?: boolean;
2467
+ }): TaskItem;
2430
2468
  installWorkspaceSyncV3TaskRootAuthoritativeForSync(task: TaskItem, workspaceId: string): TaskItem;
2431
2469
  bulkCreateTasks(tasks: Array<Partial<TaskItem>>, options?: {
2432
2470
  atomic?: boolean;
@@ -2467,8 +2505,10 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
2467
2505
  notifyDurableTaskMetadataCommitted(workspaceId: string, taskId: string): void;
2468
2506
  addComment(id: string, text: string, author: string, workspaceId?: string, options?: {
2469
2507
  persistBackup?: boolean;
2508
+ emitRealtime?: boolean;
2470
2509
  actorRef?: string;
2471
2510
  skipTaskEvents?: boolean;
2511
+ commentId?: string;
2472
2512
  }): TaskItem | null;
2473
2513
  private addPlanningEntityComment;
2474
2514
  addInitiativeComment(id: string, text: string, author: string, workspaceId?: string, options?: {
@@ -27,6 +27,7 @@ import { listTaskAttachmentLinksForDurableSync as listTaskAttachmentLinksForDura
27
27
  import { EntityEventIdentityCollisionError, addEntityEventService, addTaskEventService, buildEntityActivityService, buildTaskActivityService, getEntityEventForSyncService, getTaskEventForSyncService, listEntityEventsInternalService, listWorkspaceEntityEventsForSyncService, listTaskEventsInternalService, listWorkspaceTaskEventsForSyncService, replaceEntityEventsService, replaceTaskCommentsService, replaceTaskEventsService, upsertEntityEventForSyncService, deleteEntityEventForSyncService, upsertTaskEventForSyncService, } from './TaskActivityService.js';
28
28
  import { addDeletedTaskRecordService, getDeletedTaskService, listDeletedTasksService, listDeletedTasksReadOnlyService, mapDeletedTaskRowService, normalizeTaskSnapshotForRestoreService, normalizeDeletedTaskRestoreLifecycleService, purgeExpiredDeletedTasksService, } from './DeletedTaskLifecycleService.js';
29
29
  import { DELETED_TASK_RETENTION_DAYS } from '../shared/deletedTaskRetention.js';
30
+ import { INTERNAL_SUBSCRIPTION_MODEL_FEATURE_KEY, isSupportedInternalUserFeatureKey, } from '../shared/userFeatureGrants.js';
30
31
  import { applyWorkspaceSyncSnapshotService, claimPushIdempotencyService, completePushIdempotencyClaimService, deleteDocumentWatermarkService, deleteDocumentWatermarkStrictService, getDocumentWatermarkService, listTasksForSyncService, listWorkspaceSyncDeletesSinceService, readPushIdempotencyService, releasePushIdempotencyClaimService, renewPushIdempotencyClaimService, recordSyncEventDurablyService, recordSyncEventService, upsertDocumentWatermarkService, upsertDocumentWatermarkStrictService, writePushIdempotencyService, } from './SyncReconciliationService.js';
31
32
  import { getGlobalSettingsService, hasPersistedGlobalSettingsService, readGlobalConfigService, updateGlobalSettingsService, writeGlobalConfigService, } from './GlobalSettingsService.js';
32
33
  import { getWorkspaceTaxonomyStateService, upsertWorkspaceTaxonomyStateService, } from './TaxonomySettingsService.js';
@@ -62,7 +63,7 @@ import { getCanonicalDocumentName } from '../utils/documentNames.js';
62
63
  import { isPathInsideRoot, resolveStorageKeyPathInsideRoot } from '../utils/pathSafety.js';
63
64
  import { DEFAULT_TASKFORCE_THEME } from '../utils/theme.js';
64
65
  import { normalizeTaskSearchQuery } from '../utils/taskSearch.js';
65
- import { ensureAssigneeTaskSchema, ensureAnnotatedAttachmentSessionsSchema, ensureAuthIdentitySchema, backfillPlanningAttachmentAssetIdentities, ensureBillingSchema, ensureDocumentReviewSessionsSchema, ensureDocumentReferenceSchema, ensureEntitlementsSchema, ensurePlanningReferenceSchema, ensureScheduleTaskSchema, ensureWorkstreamTaskOrderSchema, ensureTaskAssetsSchema, ensureTaskApproachRemoved, ensureAgentRolesSchema, ensureTaskforceAgentsSchema, ensureTaskforceAgentSkillsSchema, ensureTaskReferenceSchema, ensureTenantSchema, ensureWorkflowSchema, ensureWorkspaceAssetsSchema, ensureWorkspaceSchema, ensureLocalSyncCoordinatorSchema, ensureWorkspaceSyncDurabilitySchema } from '../migrations/taskSchemaMigrations.js';
66
+ import { ensureAssigneeTaskSchema, ensureAnnotatedAttachmentSessionsSchema, ensureAuthIdentitySchema, backfillPlanningAttachmentAssetIdentities, ensureBillingSchema, ensureDocumentReviewSessionsSchema, ensureDocumentReferenceSchema, ensureEntitlementsSchema, ensurePlanningReferenceSchema, ensureScheduleTaskSchema, ensureWorkstreamTaskOrderSchema, ensureTaskAssetsSchema, ensureTaskApproachRemoved, ensureAgentRolesSchema, ensureGitHubReviewEvidenceInstallationBindingsSchema, ensureExecutorPhaseAApprovalReceiptsSchema, ensureExecutorPhaseARunAuthorizationsSchema, ensureModelProviderConnectionsSchema, ensureTaskforceAgentConnectionBindingsSchema, ensureTaskforceAgentsSchema, ensureTaskforceAgentSkillsSchema, ensureTaskReferenceSchema, ensureTenantSchema, ensureWorkflowSchema, ensureWorkspaceAssetsSchema, ensureWorkspaceSchema, ensureLocalSyncCoordinatorSchema, ensureWorkspaceSyncDurabilitySchema } from '../migrations/taskSchemaMigrations.js';
66
67
  import { repairTaskUpdatedAtOnlySyncDrift } from '../migrations/taskUpdatedAtSyncDriftMigration.js';
67
68
  export class TaskforceRuleError extends Error {
68
69
  statusCode;
@@ -1457,7 +1458,14 @@ export class TaskforceCore {
1457
1458
  ensureDocumentReferenceSchema(this.db);
1458
1459
  ensureDocumentReviewSessionsSchema(this.db);
1459
1460
  ensureAnnotatedAttachmentSessionsSchema(this.db);
1461
+ ensureModelProviderConnectionsSchema(this.db);
1460
1462
  ensureTaskforceAgentsSchema(this.db);
1463
+ ensureTaskforceAgentConnectionBindingsSchema(this.db);
1464
+ ensureGitHubReviewEvidenceInstallationBindingsSchema(this.db);
1465
+ if (this.runtimeMode === 'cloud') {
1466
+ ensureExecutorPhaseAApprovalReceiptsSchema(this.db);
1467
+ ensureExecutorPhaseARunAuthorizationsSchema(this.db);
1468
+ }
1461
1469
  ensureAgentRolesSchema(this.db);
1462
1470
  ensureTaskforceAgentSkillsSchema(this.db);
1463
1471
  ensureWorkflowSchema(this.db);
@@ -1969,6 +1977,18 @@ export class TaskforceCore {
1969
1977
  PRIMARY KEY (tenant_id, user_id, prefs_key)
1970
1978
  );
1971
1979
 
1980
+ CREATE TABLE IF NOT EXISTS user_feature_grants (
1981
+ tenant_id TEXT NOT NULL DEFAULT 'default',
1982
+ user_id TEXT NOT NULL,
1983
+ feature_key TEXT NOT NULL,
1984
+ enabled INTEGER NOT NULL DEFAULT 0,
1985
+ created_at TEXT NOT NULL,
1986
+ updated_at TEXT NOT NULL,
1987
+ updated_by TEXT,
1988
+ PRIMARY KEY (tenant_id, user_id, feature_key),
1989
+ FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
1990
+ );
1991
+
1972
1992
  CREATE TABLE IF NOT EXISTS admin_audit_logs (
1973
1993
  id TEXT PRIMARY KEY,
1974
1994
  tenant_id TEXT NOT NULL DEFAULT 'default',
@@ -2013,6 +2033,7 @@ export class TaskforceCore {
2013
2033
  provider TEXT NOT NULL,
2014
2034
  client_name TEXT NOT NULL,
2015
2035
  redirect_uris_json TEXT NOT NULL,
2036
+ application_type TEXT NOT NULL DEFAULT 'web',
2016
2037
  product_client_id TEXT,
2017
2038
  status TEXT NOT NULL DEFAULT 'active',
2018
2039
  created_at TEXT NOT NULL,
@@ -2047,6 +2068,7 @@ export class TaskforceCore {
2047
2068
  user_id TEXT NOT NULL,
2048
2069
  workspace_id TEXT NOT NULL DEFAULT 'default',
2049
2070
  scopes_json TEXT NOT NULL,
2071
+ tool_profile TEXT NOT NULL DEFAULT 'default',
2050
2072
  token_prefix TEXT NOT NULL,
2051
2073
  token_hash TEXT NOT NULL,
2052
2074
  status TEXT NOT NULL DEFAULT 'active',
@@ -2188,6 +2210,7 @@ export class TaskforceCore {
2188
2210
  CREATE INDEX IF NOT EXISTS idx_ui_state_workspace_key ON ui_state(workspace_id, state_key);
2189
2211
  CREATE INDEX IF NOT EXISTS idx_workspace_settings_workspace_key ON workspace_settings(workspace_id, settings_key);
2190
2212
  CREATE INDEX IF NOT EXISTS idx_user_preferences_user_key ON user_preferences(user_id, prefs_key);
2213
+ CREATE INDEX IF NOT EXISTS idx_user_feature_grants_feature_enabled ON user_feature_grants(tenant_id, feature_key, enabled);
2191
2214
  CREATE INDEX IF NOT EXISTS idx_admin_audit_logs_tenant_created ON admin_audit_logs(tenant_id, created_at);
2192
2215
  CREATE INDEX IF NOT EXISTS idx_admin_audit_logs_workspace_created ON admin_audit_logs(workspace_id, created_at);
2193
2216
  CREATE INDEX IF NOT EXISTS idx_task_events_task_created ON task_events(tenant_id, workspace_id, task_id, created_at);
@@ -2363,6 +2386,9 @@ export class TaskforceCore {
2363
2386
  if (!mcpOauthClientColumns.some((c) => c.name === 'product_client_id')) {
2364
2387
  this.db.exec(`ALTER TABLE mcp_oauth_clients ADD COLUMN product_client_id TEXT`);
2365
2388
  }
2389
+ if (!mcpOauthClientColumns.some((c) => c.name === 'application_type')) {
2390
+ this.db.exec(`ALTER TABLE mcp_oauth_clients ADD COLUMN application_type TEXT NOT NULL DEFAULT 'web'`);
2391
+ }
2366
2392
  const mcpOauthGrantColumns = this.db.prepare(`PRAGMA table_info(mcp_oauth_connector_grants)`).all();
2367
2393
  if (!mcpOauthGrantColumns.some((c) => c.name === 'product_client_id')) {
2368
2394
  this.db.exec(`ALTER TABLE mcp_oauth_connector_grants ADD COLUMN product_client_id TEXT`);
@@ -2376,14 +2402,19 @@ export class TaskforceCore {
2376
2402
  if (!mcpOauthGrantColumns.some((c) => c.name === 'ai_profile_name')) {
2377
2403
  this.db.exec(`ALTER TABLE mcp_oauth_connector_grants ADD COLUMN ai_profile_name TEXT`);
2378
2404
  }
2405
+ if (!mcpOauthGrantColumns.some((c) => c.name === 'tool_profile')) {
2406
+ this.db.exec(`ALTER TABLE mcp_oauth_connector_grants ADD COLUMN tool_profile TEXT NOT NULL DEFAULT 'default'`);
2407
+ }
2379
2408
  }
2380
2409
  else {
2381
2410
  try {
2382
2411
  this.db.exec(`ALTER TABLE mcp_oauth_clients ADD COLUMN IF NOT EXISTS product_client_id TEXT`);
2412
+ this.db.exec(`ALTER TABLE mcp_oauth_clients ADD COLUMN IF NOT EXISTS application_type TEXT NOT NULL DEFAULT 'web'`);
2383
2413
  this.db.exec(`ALTER TABLE mcp_oauth_connector_grants ADD COLUMN IF NOT EXISTS product_client_id TEXT`);
2384
2414
  this.db.exec(`ALTER TABLE mcp_oauth_connector_grants ADD COLUMN IF NOT EXISTS ai_profile_id TEXT`);
2385
2415
  this.db.exec(`ALTER TABLE mcp_oauth_connector_grants ADD COLUMN IF NOT EXISTS ai_profile_token TEXT`);
2386
2416
  this.db.exec(`ALTER TABLE mcp_oauth_connector_grants ADD COLUMN IF NOT EXISTS ai_profile_name TEXT`);
2417
+ this.db.exec(`ALTER TABLE mcp_oauth_connector_grants ADD COLUMN IF NOT EXISTS tool_profile TEXT NOT NULL DEFAULT 'default'`);
2387
2418
  }
2388
2419
  catch {
2389
2420
  // Best-effort schema repair for existing deployments.
@@ -6956,7 +6987,7 @@ export class TaskforceCore {
6956
6987
  OR LOWER(COALESCE(u.system_role, 'user')) LIKE ?
6957
6988
  )`
6958
6989
  : '';
6959
- const params = [this.tenantId];
6990
+ const params = [INTERNAL_SUBSCRIPTION_MODEL_FEATURE_KEY, this.tenantId];
6960
6991
  if (query) {
6961
6992
  params.push(queryPattern, queryPattern, queryPattern, queryPattern, queryPattern, queryPattern, queryPattern);
6962
6993
  }
@@ -6969,6 +7000,14 @@ export class TaskforceCore {
6969
7000
  COALESCE(u.system_role, 'user') AS system_role,
6970
7001
  COALESCE(u.beta_access, 1) AS beta_access,
6971
7002
  COALESCE(u.is_disabled, 0) AS is_disabled,
7003
+ CASE WHEN EXISTS (
7004
+ SELECT 1
7005
+ FROM user_feature_grants g
7006
+ WHERE g.tenant_id = u.tenant_id
7007
+ AND g.user_id = u.id
7008
+ AND g.feature_key = ?
7009
+ AND g.enabled = 1
7010
+ ) THEN 1 ELSE 0 END AS subscription_model_access,
6972
7011
  u.created_at,
6973
7012
  u.updated_at,
6974
7013
  u.email_verified_at,
@@ -7000,6 +7039,9 @@ export class TaskforceCore {
7000
7039
  systemRole: this.normalizeSystemRole(row.system_role, 'user'),
7001
7040
  betaAccess: row.beta_access === undefined || row.beta_access === null ? true : Boolean(row.beta_access),
7002
7041
  disabled: Boolean(row.is_disabled),
7042
+ internalFeatureGrants: Boolean(row.subscription_model_access)
7043
+ ? [INTERNAL_SUBSCRIPTION_MODEL_FEATURE_KEY]
7044
+ : [],
7003
7045
  planId: row.plan_id ? String(row.plan_id) : null,
7004
7046
  planName: row.plan_name ? String(row.plan_name) : null,
7005
7047
  planVersionId: row.plan_version_id ? String(row.plan_version_id) : null,
@@ -7073,6 +7115,53 @@ export class TaskforceCore {
7073
7115
  `).run(enabled ? 1 : 0, new Date().toISOString(), this.tenantId, normalizedUserId);
7074
7116
  return Number(result?.changes || 0) > 0;
7075
7117
  }
7118
+ hasUserFeatureGrant(userId, featureKey) {
7119
+ const normalizedUserId = String(userId || '').trim();
7120
+ if (!normalizedUserId || !isSupportedInternalUserFeatureKey(featureKey))
7121
+ return false;
7122
+ const row = this.db.prepare(`
7123
+ SELECT enabled
7124
+ FROM user_feature_grants
7125
+ WHERE tenant_id = ? AND user_id = ? AND feature_key = ?
7126
+ LIMIT 1
7127
+ `).get(this.tenantId, normalizedUserId, featureKey);
7128
+ return Boolean(row?.enabled);
7129
+ }
7130
+ listUserFeatureGrants(userId) {
7131
+ const normalizedUserId = String(userId || '').trim();
7132
+ if (!normalizedUserId)
7133
+ return [];
7134
+ const rows = this.db.prepare(`
7135
+ SELECT feature_key
7136
+ FROM user_feature_grants
7137
+ WHERE tenant_id = ? AND user_id = ? AND enabled = 1
7138
+ ORDER BY feature_key
7139
+ `).all(this.tenantId, normalizedUserId);
7140
+ return rows
7141
+ .map((row) => row.feature_key)
7142
+ .filter(isSupportedInternalUserFeatureKey);
7143
+ }
7144
+ setUserFeatureGrant(userId, featureKey, enabled, updatedBy) {
7145
+ const normalizedUserId = String(userId || '').trim();
7146
+ if (!normalizedUserId || !isSupportedInternalUserFeatureKey(featureKey))
7147
+ return false;
7148
+ const user = this.db.prepare(`
7149
+ SELECT id FROM users WHERE tenant_id = ? AND id = ? LIMIT 1
7150
+ `).get(this.tenantId, normalizedUserId);
7151
+ if (!user?.id)
7152
+ return false;
7153
+ const now = new Date().toISOString();
7154
+ this.db.prepare(`
7155
+ INSERT INTO user_feature_grants (
7156
+ tenant_id, user_id, feature_key, enabled, created_at, updated_at, updated_by
7157
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)
7158
+ ON CONFLICT (tenant_id, user_id, feature_key) DO UPDATE SET
7159
+ enabled = excluded.enabled,
7160
+ updated_at = excluded.updated_at,
7161
+ updated_by = excluded.updated_by
7162
+ `).run(this.tenantId, normalizedUserId, featureKey, enabled ? 1 : 0, now, now, String(updatedBy || '').trim() || null);
7163
+ return true;
7164
+ }
7076
7165
  markUserEmailVerified(userId) {
7077
7166
  const normalizedUserId = String(userId || '').trim();
7078
7167
  if (!normalizedUserId)
@@ -7179,6 +7268,14 @@ export class TaskforceCore {
7179
7268
  if (hasCommercialBillingState) {
7180
7269
  throw new TaskforceRuleError('Cannot purge a user with active commercial billing state', 409, 'SYSTEM_USER_PURGE_BLOCKED_BILLING_STATE');
7181
7270
  }
7271
+ const modelConnectionCount = Number(this.db.prepare(`
7272
+ SELECT COUNT(*) AS count
7273
+ FROM model_provider_connections
7274
+ WHERE tenant_id = ? AND owner_user_id = ?
7275
+ `).get(this.tenantId, targetUserId)?.count || 0);
7276
+ if (modelConnectionCount > 0) {
7277
+ throw new TaskforceRuleError('Disconnect and clean up the user model connections before purging this account', 409, 'SYSTEM_USER_PURGE_BLOCKED_MODEL_CONNECTIONS');
7278
+ }
7182
7279
  const now = new Date().toISOString();
7183
7280
  const runCount = (sql, ...params) => Number(this.db.prepare(sql).run(...params)?.changes || 0);
7184
7281
  const workspaceIds = this.db.prepare(`
@@ -7278,6 +7375,11 @@ export class TaskforceCore {
7278
7375
  WHERE tenant_id = ?
7279
7376
  AND user_id = ?
7280
7377
  `, this.tenantId, targetUserId);
7378
+ const deletedUserFeatureGrantCount = runCount(`
7379
+ DELETE FROM user_feature_grants
7380
+ WHERE tenant_id = ?
7381
+ AND user_id = ?
7382
+ `, this.tenantId, targetUserId);
7281
7383
  const deletedUserBillingCount = runCount(`
7282
7384
  DELETE FROM user_billing
7283
7385
  WHERE tenant_id = ?
@@ -7305,6 +7407,7 @@ export class TaskforceCore {
7305
7407
  deletedMcpOauthConnectorGrantCount,
7306
7408
  deletedUiStateCount,
7307
7409
  deletedUserPreferenceCount,
7410
+ deletedUserFeatureGrantCount,
7308
7411
  deletedEntitlementCount,
7309
7412
  deletedUserBillingCount,
7310
7413
  deletedUserCount
@@ -7651,7 +7754,7 @@ export class TaskforceCore {
7651
7754
  deletedAt: session.deletedAt,
7652
7755
  });
7653
7756
  }
7654
- upsertDocumentReviewCommentForSync(comment) {
7757
+ upsertDocumentReviewCommentForSync(comment, options) {
7655
7758
  const deps = this.getDocumentReviewServiceDeps();
7656
7759
  return deps.commentStore.upsertForSync({
7657
7760
  id: comment.id,
@@ -7671,7 +7774,7 @@ export class TaskforceCore {
7671
7774
  createdAt: comment.createdAt,
7672
7775
  updatedAt: comment.updatedAt,
7673
7776
  deletedAt: comment.deletedAt,
7674
- });
7777
+ }, options);
7675
7778
  }
7676
7779
  upsertAnnotatedAttachmentSessionForSync(session) {
7677
7780
  const deps = this.getAnnotatedAttachmentServiceDeps();
@@ -8743,6 +8846,9 @@ export class TaskforceCore {
8743
8846
  regenerateMcpAccessToken(input) {
8744
8847
  return this.mcpTokenService.regenerateMcpAccessToken(input);
8745
8848
  }
8849
+ updateMcpAccessTokenToolProfile(input) {
8850
+ return this.mcpTokenService.updateMcpAccessTokenToolProfile(input);
8851
+ }
8746
8852
  authenticateMcpAccessToken(token, workspaceId) {
8747
8853
  return this.mcpTokenService.authenticateMcpAccessToken(token, workspaceId);
8748
8854
  }
@@ -8770,6 +8876,9 @@ export class TaskforceCore {
8770
8876
  revokeMcpOAuthConnectorGrant(input) {
8771
8877
  return this.mcpTokenService.revokeMcpOAuthConnectorGrant(input);
8772
8878
  }
8879
+ updateMcpOAuthConnectorGrantToolProfile(input) {
8880
+ return this.mcpTokenService.updateMcpOAuthConnectorGrantToolProfile(input);
8881
+ }
8773
8882
  authenticateMcpOAuthAccessToken(token, workspaceId) {
8774
8883
  return this.mcpTokenService.authenticateMcpOAuthAccessToken(token, workspaceId);
8775
8884
  }
@@ -9871,7 +9980,7 @@ export class TaskforceCore {
9871
9980
  return this.getWorkstream(workstreamId, normalizedWorkspaceId) || updated;
9872
9981
  })();
9873
9982
  }
9874
- installDurableTaskCreateAuthoritativeForSync(task, workspaceId) {
9983
+ installDurableTaskCreateAuthoritativeForSync(task, workspaceId, options) {
9875
9984
  const normalizedWorkspaceId = this.normalizeWorkspaceId(workspaceId);
9876
9985
  const taskId = String(task?.id || '').trim();
9877
9986
  const createdAt = String(task?.createdAt || '').trim();
@@ -9889,6 +9998,31 @@ export class TaskforceCore {
9889
9998
  return this.db.transaction(() => {
9890
9999
  const existing = this.getTask(taskId, normalizedWorkspaceId);
9891
10000
  if (!existing) {
10001
+ const deleted = options?.preserveDeletedSuccessor
10002
+ ? this.getDeletedTask(taskId, normalizedWorkspaceId)
10003
+ : null;
10004
+ if (deleted) {
10005
+ this.relocateTaskReferenceConflict(normalizedWorkspaceId, referenceNumber, taskId, updatedAt);
10006
+ if (this.reserveTaskReferenceNumber(normalizedWorkspaceId, referenceNumber, taskId) !== referenceNumber) {
10007
+ throw new TaskforceRuleError('Authoritative task reference is already in use.', 409, 'WORKSPACE_SYNC_AUTHORITATIVE_RESPONSE_INVALID');
10008
+ }
10009
+ const authoritativeSnapshot = {
10010
+ ...deleted.taskSnapshot,
10011
+ referenceNumber,
10012
+ localReferenceNumber: null,
10013
+ referenceLabel: deriveTaskReferenceLabel({ referenceNumber, localReferenceNumber: null }),
10014
+ createdAt,
10015
+ createdBy: task.createdBy,
10016
+ };
10017
+ const updated = this.db.prepare(`
10018
+ UPDATE deleted_tasks SET task_snapshot_json = ?
10019
+ WHERE tenant_id = ? AND workspace_id = ? AND task_id = ?
10020
+ `).run(JSON.stringify(authoritativeSnapshot), this.tenantId, normalizedWorkspaceId, taskId);
10021
+ if (Number(updated.changes || 0) !== 1) {
10022
+ throw new TaskforceRuleError('Captured deleted task history is missing.', 409, 'WORKSPACE_SYNC_AUTHORITATIVE_RESPONSE_INVALID');
10023
+ }
10024
+ return this.getDeletedTask(taskId, normalizedWorkspaceId).taskSnapshot;
10025
+ }
9892
10026
  throw new TaskforceRuleError('Task not found.', 404, 'TASK_NOT_FOUND');
9893
10027
  }
9894
10028
  const mutableCreateFields = [
@@ -10653,8 +10787,25 @@ export class TaskforceCore {
10653
10787
  return null;
10654
10788
  const submittedAuthor = String(author || '').trim() || 'user';
10655
10789
  const normalizedAuthor = this.normalizeCommentAuthor(author, normalizedWorkspaceId);
10790
+ const explicitCommentId = String(options?.commentId || '').trim();
10791
+ if (explicitCommentId) {
10792
+ const persisted = this.db.prepare(`
10793
+ SELECT task_id, text, author, submitted_author
10794
+ FROM comments
10795
+ WHERE tenant_id = ? AND workspace_id = ? AND id = ?
10796
+ `).get(this.tenantId, normalizedWorkspaceId, explicitCommentId);
10797
+ if (persisted) {
10798
+ if (persisted.task_id !== id
10799
+ || persisted.text !== text
10800
+ || persisted.author !== normalizedAuthor
10801
+ || String(persisted.submitted_author || persisted.author) !== submittedAuthor) {
10802
+ throw new TaskforceRuleError('Task comment identity is assigned to different content.', 409, 'TASK_COMMENT_IDENTITY_CONFLICT');
10803
+ }
10804
+ return this.getTask(id, normalizedWorkspaceId);
10805
+ }
10806
+ }
10656
10807
  const comment = {
10657
- id: this.generateEntityId('comment'),
10808
+ id: explicitCommentId || this.generateEntityId('comment'),
10658
10809
  author: normalizedAuthor,
10659
10810
  submittedAuthor,
10660
10811
  text,
@@ -10697,7 +10848,7 @@ export class TaskforceCore {
10697
10848
  if (options?.persistBackup !== false)
10698
10849
  this.persistBackup();
10699
10850
  const updated = this.getTask(id, normalizedWorkspaceId);
10700
- if (updated) {
10851
+ if (updated && options?.emitRealtime !== false) {
10701
10852
  this.emitRealtimeMutation({
10702
10853
  workspaceId: normalizedWorkspaceId,
10703
10854
  entityType: 'task',