@taskforcehq/taskforce 0.3.329 → 0.3.332

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/README.md +7 -2
  2. package/dist/Taskforce.module.css +290 -45
  3. package/dist/components/features/AiProfilesModule.js +3 -5
  4. package/dist/components/features/TaskSettings.js +70 -14
  5. package/dist/components/features/TaskforceAgentsModule.d.ts +1 -2
  6. package/dist/components/features/TaskforceAgentsModule.js +586 -116
  7. package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +2 -2
  8. package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.js +2 -2
  9. package/dist/components/features/agentConnections/AgentConnectionControl.d.ts +15 -0
  10. package/dist/components/features/agentConnections/AgentConnectionControl.js +125 -0
  11. package/dist/components/features/agentConnections/ModelConnectionsPanel.d.ts +18 -0
  12. package/dist/components/features/agentConnections/ModelConnectionsPanel.js +393 -0
  13. package/dist/components/features/agentConnections/modelConnectionsApi.d.ts +65 -0
  14. package/dist/components/features/agentConnections/modelConnectionsApi.js +129 -0
  15. package/dist/components/features/planning/PlanningModule.js +15 -3
  16. package/dist/components/features/planning/planningMetadata.d.ts +10 -0
  17. package/dist/components/features/planning/planningMetadata.js +8 -0
  18. package/dist/components/features/taskforceAgentAssignments/AgentBehaviorAssignments.js +15 -24
  19. package/dist/components/features/taskforceAgentEditorModel.d.ts +2 -1
  20. package/dist/components/features/taskforceAgentEditorModel.js +3 -1
  21. package/dist/components/features/workflowManager/workflowManagerApi.d.ts +1 -1
  22. package/dist/components/features/workflowManager/workflowManagerApi.js +3 -0
  23. package/dist/components/task/TaskWorkflowAssignmentField.js +68 -10
  24. package/dist/components/views/StandaloneLayout.js +62 -27
  25. package/dist/components/views/panels/PlanningDrawer.d.ts +2 -1
  26. package/dist/components/views/panels/PlanningDrawer.js +12 -8
  27. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +4 -3
  28. package/dist/components/views/standalone/modals/SyncStatusModal.js +33 -38
  29. package/dist/config/envSchema.js +55 -1
  30. package/dist/core/McpTokenService.d.ts +25 -1
  31. package/dist/core/McpTokenService.js +106 -15
  32. package/dist/core/TaskChecklistCommandService.d.ts +27 -0
  33. package/dist/core/TaskChecklistCommandService.js +83 -5
  34. package/dist/core/TaskLifecycleCommandService.d.ts +3 -1
  35. package/dist/core/TaskLifecycleCommandService.js +6 -2
  36. package/dist/core/Taskforce.d.ts +43 -3
  37. package/dist/core/Taskforce.js +158 -7
  38. package/dist/core/types.d.ts +9 -0
  39. package/dist/documentReviews/DocumentReviewCommentStore.d.ts +2 -0
  40. package/dist/documentReviews/DocumentReviewCommentStore.js +28 -9
  41. package/dist/documentReviews/commandService.d.ts +2 -1
  42. package/dist/documentReviews/commandService.js +6 -3
  43. package/dist/hooks/sync/orchestratorShared.d.ts +1 -0
  44. package/dist/hooks/sync/orchestratorShared.js +2 -0
  45. package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.d.ts +3 -0
  46. package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.js +85 -9
  47. package/dist/hooks/sync/useSyncStatusControls.d.ts +4 -1
  48. package/dist/hooks/sync/useSyncStatusControls.js +47 -11
  49. package/dist/hooks/useSyncOrchestrator.d.ts +3 -0
  50. package/dist/hooks/useSyncOrchestrator.js +111 -2
  51. package/dist/hooks/useTaskData.d.ts +31 -1
  52. package/dist/hooks/useTaskData.js +29 -7
  53. package/dist/hooks/useTaskMutations.d.ts +3 -1
  54. package/dist/hooks/useTaskMutations.js +46 -12
  55. package/dist/hooks/useTaskforce.d.ts +2 -0
  56. package/dist/hooks/useTaskforce.js +11 -2
  57. package/dist/mcp/clientRegistry.d.ts +2 -2
  58. package/dist/mcp/clientRegistry.js +1 -1
  59. package/dist/mcp/documentAssetRegistrar.js +9 -6
  60. package/dist/mcp/durableTaskMutationRouter.d.ts +4 -1
  61. package/dist/mcp/durableTaskMutationRouter.js +10 -0
  62. package/dist/mcp/durableTaskRelationshipMutationRouter.js +4 -0
  63. package/dist/mcp/httpProtocolRouting.d.ts +11 -0
  64. package/dist/mcp/httpProtocolRouting.js +22 -0
  65. package/dist/mcp/localCliHealth.d.ts +2 -2
  66. package/dist/mcp/localCliHealth.js +2 -2
  67. package/dist/mcp/localServiceProxy.d.ts +1 -0
  68. package/dist/mcp/localServiceProxy.js +530 -68
  69. package/dist/mcp/planningAttachmentCommandAdapter.d.ts +3 -1
  70. package/dist/mcp/planningAttachmentCommandAdapter.js +20 -2
  71. package/dist/mcp/runtime.d.ts +54 -79
  72. package/dist/mcp/runtime.js +408 -102
  73. package/dist/mcp/taskPlanningRegistrar.js +25 -6
  74. package/dist/mcp/toolProfiles.d.ts +2 -0
  75. package/dist/mcp/toolProfiles.js +11 -0
  76. package/dist/mcp/toolRegistry.d.ts +1 -0
  77. package/dist/mcp/toolRegistry.js +9 -8
  78. package/dist/mcp/workflowExecutionRegistrar.js +4 -4
  79. package/dist/migrations/taskSchemaMigrations.d.ts +5 -0
  80. package/dist/migrations/taskSchemaMigrations.js +415 -0
  81. package/dist/runtime/appGates.d.ts +2 -1
  82. package/dist/runtime/appGates.js +7 -0
  83. package/dist/server/buildInfo.d.ts +1 -0
  84. package/dist/server/buildInfo.js +5 -1
  85. package/dist/server/cloudMcpCapacityTelemetry.d.ts +68 -0
  86. package/dist/server/cloudMcpCapacityTelemetry.js +221 -0
  87. package/dist/server/index.d.ts +3 -0
  88. package/dist/server/index.js +108 -11
  89. package/dist/server/localDatabaseIdentity.js +4 -1
  90. package/dist/server/localServiceLease.js +2 -1
  91. package/dist/server/localServiceSessions.d.ts +14 -17
  92. package/dist/server/localServiceSessions.js +308 -94
  93. package/dist/server/localWorkspaceSyncServerRuntime.js +25 -19
  94. package/dist/server/routes/admin.d.ts +4 -0
  95. package/dist/server/routes/admin.js +126 -5
  96. package/dist/server/routes/agents.d.ts +7 -0
  97. package/dist/server/routes/agents.js +277 -24
  98. package/dist/server/routes/billing.js +5 -1
  99. package/dist/server/routes/durableTaskHttpRouters.d.ts +2 -0
  100. package/dist/server/routes/executorPhaseAApprovals.d.ts +19 -0
  101. package/dist/server/routes/executorPhaseAApprovals.js +140 -0
  102. package/dist/server/routes/executorPhaseAIssuerRedemptions.d.ts +11 -0
  103. package/dist/server/routes/executorPhaseAIssuerRedemptions.js +24 -0
  104. package/dist/server/routes/githubReviewEvidence.d.ts +19 -0
  105. package/dist/server/routes/githubReviewEvidence.js +116 -0
  106. package/dist/server/routes/localService.d.ts +15 -4
  107. package/dist/server/routes/localService.js +136 -40
  108. package/dist/server/routes/modelConnections.d.ts +24 -0
  109. package/dist/server/routes/modelConnections.js +205 -0
  110. package/dist/server/routes/shared.d.ts +22 -0
  111. package/dist/server/routes/shared.js +298 -182
  112. package/dist/server/routes/sync.js +1 -0
  113. package/dist/server/routes/syncAuxRoutes.js +5 -1
  114. package/dist/server/routes/syncPushRoutes.d.ts +1 -0
  115. package/dist/server/routes/syncPushRoutes.js +1 -0
  116. package/dist/server/routes/syncV3FeedRoutes.js +10 -1
  117. package/dist/server/routes/syncV3OperationRoutes.js +35 -9
  118. package/dist/server/routes/tasks.js +21 -2
  119. package/dist/server/routes/workflows.js +9 -1
  120. package/dist/server/routes.js +59 -0
  121. package/dist/service/localServiceCli.d.ts +2 -2
  122. package/dist/service/localServiceCli.js +4 -3
  123. package/dist/services/codexAppServerModelGateway.d.ts +54 -5
  124. package/dist/services/codexAppServerModelGateway.js +246 -21
  125. package/dist/services/codexDeviceCodeLoginManager.d.ts +39 -0
  126. package/dist/services/codexDeviceCodeLoginManager.js +265 -0
  127. package/dist/services/codexModelProviderConnectionLifecycle.d.ts +8 -0
  128. package/dist/services/codexModelProviderConnectionLifecycle.js +73 -0
  129. package/dist/services/executorPhaseAApprovalRuntime.d.ts +14 -0
  130. package/dist/services/executorPhaseAApprovalRuntime.js +24 -0
  131. package/dist/services/executorPhaseAApprovalService.d.ts +40 -0
  132. package/dist/services/executorPhaseAApprovalService.js +609 -0
  133. package/dist/services/executorPhaseADriftEvaluator.d.ts +78 -0
  134. package/dist/services/executorPhaseADriftEvaluator.js +93 -0
  135. package/dist/services/executorPhaseAIssuerCore.d.ts +139 -0
  136. package/dist/services/executorPhaseAIssuerCore.js +402 -0
  137. package/dist/services/executorPhaseAIssuerRedemptionService.d.ts +34 -0
  138. package/dist/services/executorPhaseAIssuerRedemptionService.js +158 -0
  139. package/dist/services/githubReviewEvidenceRuntime.d.ts +14 -0
  140. package/dist/services/githubReviewEvidenceRuntime.js +30 -0
  141. package/dist/services/githubReviewEvidenceService.d.ts +93 -0
  142. package/dist/services/githubReviewEvidenceService.js +336 -0
  143. package/dist/services/modelGateway.d.ts +7 -0
  144. package/dist/services/modelProviderConnectionService.d.ts +71 -0
  145. package/dist/services/modelProviderConnectionService.js +279 -0
  146. package/dist/services/modelProviderCredentialHome.d.ts +32 -0
  147. package/dist/services/modelProviderCredentialHome.js +271 -0
  148. package/dist/services/ownerScopedModelConnectionGateway.d.ts +12 -0
  149. package/dist/services/ownerScopedModelConnectionGateway.js +30 -0
  150. package/dist/services/taskforceAgentConnectionBindingService.d.ts +66 -0
  151. package/dist/services/taskforceAgentConnectionBindingService.js +185 -0
  152. package/dist/services/taskforceAgentMcpBridge.d.ts +2 -2
  153. package/dist/services/taskforceAgentMcpBridge.js +42 -29
  154. package/dist/shared/adminEdgeProxy.d.ts +5 -0
  155. package/dist/shared/adminEdgeProxy.js +94 -0
  156. package/dist/shared/adminProxySessionCookies.d.ts +16 -0
  157. package/dist/shared/adminProxySessionCookies.js +86 -0
  158. package/dist/shared/aiProfileColors.d.ts +31 -1
  159. package/dist/shared/aiProfileColors.js +14 -6
  160. package/dist/shared/executorPhaseAApprovalGoldenVector.json +269 -0
  161. package/dist/shared/executorPhaseAApprovalReceipt.d.ts +112 -0
  162. package/dist/shared/executorPhaseAApprovalReceipt.js +58 -0
  163. package/dist/shared/executorPhaseAApprovalTrustPolicy.json +10 -0
  164. package/dist/shared/executorPhaseADriftContracts.d.ts +37 -0
  165. package/dist/shared/executorPhaseADriftContracts.js +63 -0
  166. package/dist/shared/executorPhaseAIssuerContracts.d.ts +75 -0
  167. package/dist/shared/executorPhaseAIssuerContracts.js +90 -0
  168. package/dist/shared/executorPhaseARunAuthorization.d.ts +120 -0
  169. package/dist/shared/executorPhaseARunAuthorization.js +232 -0
  170. package/dist/shared/executorPhaseASchemaValidation.d.ts +7 -0
  171. package/dist/shared/executorPhaseASchemaValidation.js +53 -0
  172. package/dist/shared/executorPhaseASchemas/approval-receipt.schema.json +106 -0
  173. package/dist/shared/executorPhaseASchemas/drift-attestation.schema.json +54 -0
  174. package/dist/shared/executorPhaseASchemas/drift-request.schema.json +47 -0
  175. package/dist/shared/executorPhaseASchemas/foundation-manifest.schema.json +29 -0
  176. package/dist/shared/executorPhaseASchemas/issuer-audit-record.schema.json +24 -0
  177. package/dist/shared/executorPhaseASchemas/issuer-proof.schema.json +43 -0
  178. package/dist/shared/executorPhaseASchemas/issuer-redemption-request.schema.json +18 -0
  179. package/dist/shared/executorPhaseASchemas/issuer-redemption-response.schema.json +39 -0
  180. package/dist/shared/executorPhaseASchemas/logical-envelope.schema.json +149 -0
  181. package/dist/shared/executorPhaseASchemas/preflight-report.schema.json +216 -0
  182. package/dist/shared/executorPhaseASchemas/run-capability.schema.json +111 -0
  183. package/dist/shared/executorPhaseASchemas/sender-proof.schema.json +37 -0
  184. package/dist/shared/executorPhaseASchemas/workload-grant.schema.json +68 -0
  185. package/dist/shared/executorPhaseASchemas/workload-jwt-claims.schema.json +67 -0
  186. package/dist/shared/executorPhaseATiming.d.ts +1 -0
  187. package/dist/shared/executorPhaseATiming.js +1 -0
  188. package/dist/shared/planningIdentity.js +1 -1
  189. package/dist/shared/productLogoKeys.d.ts +2 -0
  190. package/dist/shared/productLogoKeys.js +18 -0
  191. package/dist/shared/taskforceAgentDefinition.d.ts +0 -1
  192. package/dist/shared/taskforceAgentDefinition.js +6 -9
  193. package/dist/shared/taskforceAgentModels.js +7 -3
  194. package/dist/shared/userFeatureGrants.d.ts +4 -0
  195. package/dist/shared/userFeatureGrants.js +7 -0
  196. package/dist/storage/executorPhaseAApprovalReceiptStore.d.ts +37 -0
  197. package/dist/storage/executorPhaseAApprovalReceiptStore.js +81 -0
  198. package/dist/storage/executorPhaseARunAuthorizationStore.d.ts +103 -0
  199. package/dist/storage/executorPhaseARunAuthorizationStore.js +492 -0
  200. package/dist/storage/githubReviewEvidenceInstallationStore.d.ts +26 -0
  201. package/dist/storage/githubReviewEvidenceInstallationStore.js +89 -0
  202. package/dist/storage/modelProviderConnectionStore.d.ts +99 -0
  203. package/dist/storage/modelProviderConnectionStore.js +446 -0
  204. package/dist/storage/postgresAdapter.d.ts +4 -0
  205. package/dist/storage/postgresAdapter.js +14 -1
  206. package/dist/storage/postgresRequestDiagnostics.d.ts +9 -1
  207. package/dist/storage/postgresRequestDiagnostics.js +15 -2
  208. package/dist/storage/postgresWorker.js +20 -2
  209. package/dist/storage/postgresWorkerProtocol.d.ts +7 -0
  210. package/dist/storage/taskforceAgentConnectionBindingStore.d.ts +31 -0
  211. package/dist/storage/taskforceAgentConnectionBindingStore.js +84 -0
  212. package/dist/storage/workflowStore.d.ts +2 -0
  213. package/dist/storage/workflowStore.js +39 -2
  214. package/dist/sync/cloudSyncApi.js +4 -2
  215. package/dist/sync/collaborationSyncState.js +5 -0
  216. package/dist/sync/coordinator/localSyncExecutionPermitStore.js +60 -29
  217. package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.d.ts +10 -0
  218. package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.js +29 -0
  219. package/dist/sync/coordinator/localWorkspaceSyncRunner.d.ts +3 -1
  220. package/dist/sync/coordinator/localWorkspaceSyncRunner.js +18 -0
  221. package/dist/sync/coordinator/localWorkspaceSyncRunnerState.d.ts +15 -1
  222. package/dist/sync/coordinator/localWorkspaceSyncRunnerState.js +99 -2
  223. package/dist/sync/coordinator/workspaceSyncCredentialBroker.d.ts +1 -0
  224. package/dist/sync/coordinator/workspaceSyncCredentialBroker.js +33 -4
  225. package/dist/sync/engine/workspaceSyncContentLifecycleAdapter.d.ts +2 -1
  226. package/dist/sync/engine/workspaceSyncContentVersionStore.d.ts +38 -0
  227. package/dist/sync/engine/workspaceSyncContentVersionStore.js +50 -1
  228. package/dist/sync/engine/workspaceSyncEngineLifecyclePolicy.js +6 -6
  229. package/dist/sync/engine/workspaceSyncEnginePushCompletion.d.ts +14 -0
  230. package/dist/sync/engine/workspaceSyncEnginePushCompletion.js +84 -0
  231. package/dist/sync/engine/workspaceSyncEngineRecovery.js +1 -0
  232. package/dist/sync/engine/workspaceSyncEngineRuntime.d.ts +1 -0
  233. package/dist/sync/engine/workspaceSyncEngineRuntime.js +1 -0
  234. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +112 -38
  235. package/dist/sync/engine/workspaceSyncEngineServerSnapshotReader.js +6 -0
  236. package/dist/sync/engine/workspaceSyncEngineTransfers.js +3 -1
  237. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.d.ts +1 -0
  238. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +31 -0
  239. package/dist/sync/syncApplyHandlers.d.ts +3 -0
  240. package/dist/sync/syncApplyHandlers.js +81 -15
  241. package/dist/sync/syncService.d.ts +15 -0
  242. package/dist/sync/syncService.js +83 -18
  243. package/dist/sync/taskforceAgentSyncAuthorization.d.ts +16 -0
  244. package/dist/sync/taskforceAgentSyncAuthorization.js +20 -0
  245. package/dist/sync/v3/combinedFeedCapability.js +4 -0
  246. package/dist/sync/v3/durableInitiativeMutationRouter.js +18 -10
  247. package/dist/sync/v3/durableOperationReplay.d.ts +14 -0
  248. package/dist/sync/v3/durableOperationReplay.js +18 -0
  249. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +3 -0
  250. package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -1
  251. package/dist/sync/v3/durableTaskChecklistMutationRouter.js +58 -15
  252. package/dist/sync/v3/durableTaskCommentMutationRouter.js +3 -0
  253. package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +1 -1
  254. package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +10 -0
  255. package/dist/sync/v3/durableTaxonomyMutationRouter.js +5 -0
  256. package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.d.ts +18 -7
  257. package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.js +89 -23
  258. package/dist/sync/v3/durableWorkstreamMutationRouter.js +18 -10
  259. package/dist/sync/v3/durableWorkstreamTaskOrderMutationRouter.js +16 -5
  260. package/dist/sync/v3/localOutboxDispatchRuntime.js +2 -2
  261. package/dist/sync/v3/localOutboxRecoveryPreparationService.js +8 -2
  262. package/dist/sync/v3/localTaskChecklistOutboxHandler.js +16 -2
  263. package/dist/sync/v3/localTaskChecklistOutboxService.d.ts +4 -0
  264. package/dist/sync/v3/localTaskChecklistOutboxService.js +14 -1
  265. package/dist/sync/v3/localTaskCreateOutboxService.d.ts +3 -1
  266. package/dist/sync/v3/localTaskCreateOutboxService.js +6 -1
  267. package/dist/sync/v3/localTaskDeleteOutboxService.js +1 -0
  268. package/dist/sync/v3/localTaskLifecycleOutboxService.d.ts +2 -1
  269. package/dist/sync/v3/localTaskLifecycleOutboxService.js +5 -1
  270. package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -1
  271. package/dist/sync/v3/localTaskMetadataOutboxService.js +6 -2
  272. package/dist/sync/v3/localTaskStatusOutboxService.d.ts +10 -1
  273. package/dist/sync/v3/localTaskStatusOutboxService.js +238 -16
  274. package/dist/sync/v3/syncDurabilityStore.d.ts +36 -1
  275. package/dist/sync/v3/syncDurabilityStore.js +202 -8
  276. package/dist/sync/v3/taskChecklistMutationService.d.ts +11 -0
  277. package/dist/sync/v3/taskChecklistMutationService.js +44 -1
  278. package/dist/sync/v3/taskStatusMutationService.d.ts +29 -1
  279. package/dist/sync/v3/taskStatusMutationService.js +119 -3
  280. package/dist/sync/v3/workflowAssignmentSync.d.ts +5 -0
  281. package/dist/sync/v3/workflowAssignmentSync.js +27 -0
  282. package/dist/sync/v3/workflowRuntimeMutationService.d.ts +5 -0
  283. package/dist/sync/v3/workflowRuntimeMutationService.js +124 -71
  284. package/dist/sync/v3/workspaceSyncJournalReader.js +1 -1
  285. package/dist/sync/v3/workspaceSyncOperationRetentionService.d.ts +16 -0
  286. package/dist/sync/v3/workspaceSyncOperationRetentionService.js +83 -0
  287. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.d.ts +1 -0
  288. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +9 -2
  289. package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +25 -3
  290. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +7 -0
  291. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +44 -32
  292. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +9 -5
  293. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +54 -38
  294. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
  295. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +70 -31
  296. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +2 -1
  297. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +16 -0
  298. package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
  299. package/dist/sync/v3/workspaceSyncV3Feed.d.ts +1 -0
  300. package/dist/sync/v3/workspaceSyncV3Feed.js +6 -1
  301. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +2 -0
  302. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +49 -18
  303. package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +3 -0
  304. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +5 -0
  305. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +36 -2
  306. package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.d.ts +17 -0
  307. package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.js +64 -0
  308. package/dist/sync/v3/workspaceSyncV3WorkflowRuntimeApply.d.ts +1 -0
  309. package/dist/sync/v3/workspaceSyncV3WorkflowRuntimeApply.js +50 -5
  310. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.d.ts +7 -0
  311. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.js +33 -0
  312. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.d.ts +7 -0
  313. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.js +8 -0
  314. package/dist/sync/workspaceRepair.d.ts +5 -2
  315. package/dist/sync/workspaceRepair.js +161 -6
  316. package/dist/sync/workspaceSyncModel.d.ts +21 -0
  317. package/dist/sync/workspaceSyncModel.js +35 -7
  318. package/dist/sync/workspaceSyncState.d.ts +1 -0
  319. package/dist/sync/workspaceSyncV2SnapshotBuilder.d.ts +6 -0
  320. package/dist/sync/workspaceSyncV2SnapshotBuilder.js +5 -0
  321. package/dist/ui/assets/AiIdentityRosterCard-CDMPtnbC.js +1 -0
  322. package/dist/ui/assets/AiProfilesModule-Cww85C4E.js +1 -0
  323. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-B68Wg-RV.js → AnnotatedAttachmentWorkspace-Dt9TKYSH.js} +1 -1
  324. package/dist/ui/assets/{AssetTraySortControl-C8Rztyal.js → AssetTraySortControl-CKgapnxu.js} +1 -1
  325. package/dist/ui/assets/{ContextAttachmentManager-Cj3c7X9y.js → ContextAttachmentManager-T-cEVcOZ.js} +2 -2
  326. package/dist/ui/assets/{DocumentWorkspace-B5uvzems.js → DocumentWorkspace-HD4MUjAZ.js} +1 -1
  327. package/dist/ui/assets/{EntityActivityTimeline-BVFvCB5R.js → EntityActivityTimeline-_V0zfMuh.js} +1 -1
  328. package/dist/ui/assets/PlanningModule-mTkBygsB.js +1 -0
  329. package/dist/ui/assets/{PlansPage-AY4cGWco.js → PlansPage-Btiq06VO.js} +1 -1
  330. package/dist/ui/assets/{TaskContextUpload-DZxTVesW.js → TaskContextUpload-C00NVUpn.js} +1 -1
  331. package/dist/ui/assets/TaskSettings-Cp-L-4xh.js +12 -0
  332. package/dist/ui/assets/TaskforceAgentsModule-Coq9-PUp.js +24 -0
  333. package/dist/ui/assets/TaskforceAgentsModule-b-8R25cJ.css +1 -0
  334. package/dist/ui/assets/{WorkflowManagerModule-DEr5di_r.js → WorkflowManagerModule-CuqRzMmM.js} +1 -1
  335. package/dist/ui/assets/index-BZ-hdZSk.css +1 -0
  336. package/dist/ui/assets/index-DSQINwt9.js +7 -0
  337. package/dist/ui/assets/{vendor-icons-D9Lpw-j4.js → vendor-icons-Bsq-mcEn.js} +1 -1
  338. package/dist/ui/branding/logos/letterhead_dark.png +0 -0
  339. package/dist/ui/branding/logos/letterhead_light.png +0 -0
  340. package/dist/ui/branding/logos/signature_dark.png +0 -0
  341. package/dist/ui/branding/logos/signature_light.png +0 -0
  342. package/dist/ui/index.html +3 -3
  343. package/dist/utils/aiProfileDefaultLogo.js +16 -48
  344. package/dist/utils/httpSetCookie.d.ts +1 -0
  345. package/dist/utils/httpSetCookie.js +4 -1
  346. package/dist/utils/localRuntimeUrl.d.ts +1 -0
  347. package/dist/utils/localRuntimeUrl.js +14 -0
  348. package/dist/utils/productLogoRegistry.d.ts +2 -0
  349. package/dist/utils/productLogoRegistry.js +36 -0
  350. package/dist/utils/syncStatusPresentation.d.ts +4 -0
  351. package/dist/utils/syncStatusPresentation.js +17 -0
  352. package/dist/utils/taskEvents.d.ts +2 -0
  353. package/dist/utils/workspaceSyncPresentation.d.ts +1 -1
  354. package/dist/utils/workspaceSyncPresentation.js +23 -17
  355. package/package.json +24 -4
  356. package/dist/ui/assets/AiIdentityRosterCard-BZM4aQnM.js +0 -1
  357. package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +0 -1
  358. package/dist/ui/assets/PlanningModule-B5DWQOGz.js +0 -1
  359. package/dist/ui/assets/TaskSettings-BeWAuyZj.js +0 -12
  360. package/dist/ui/assets/TaskforceAgentsModule-BifCYtjR.js +0 -21
  361. package/dist/ui/assets/TaskforceAgentsModule-D6IC0S7Q.css +0 -1
  362. package/dist/ui/assets/index-I5zhdtgt.js +0 -7
  363. package/dist/ui/assets/index-VRFsx3wz.css +0 -1
@@ -1,7 +1,6 @@
1
1
  import { createHash, randomBytes, randomUUID, timingSafeEqual } from 'crypto';
2
2
  export const LOCAL_SERVICE_SESSION_IDLE_TTL_MS = 24 * 60 * 60 * 1_000;
3
3
  export const LOCAL_SERVICE_SESSION_CAP = 256;
4
- export const LOCAL_SERVICE_OPERATION_BINDING_CAP = 4_096;
5
4
  export const LOCAL_SERVICE_CANCELLATION_BINDING_CAP = 1_024;
6
5
  export const LOCAL_SERVICE_CANCELLATION_TOMBSTONE_TTL_MS = 60_000;
7
6
  export class LocalServiceSessionError extends Error {
@@ -14,41 +13,174 @@ export class LocalServiceSessionError extends Error {
14
13
  }
15
14
  }
16
15
  function digestToken(token) {
17
- return createHash('sha256').update(token, 'utf8').digest();
16
+ return createHash('sha256').update(token, 'utf8').digest('hex');
18
17
  }
19
18
  function publicSession(session) {
20
- const { tokenDigest: _tokenDigest, lastUsedAtMs: _lastUsedAtMs, ...result } = session;
21
- return { ...result, permissions: [...result.permissions] };
19
+ const { tokenDigest: _tokenDigest, ...result } = session;
20
+ return {
21
+ ...result,
22
+ permissions: [...result.permissions],
23
+ runtimeContract: { ...result.runtimeContract },
24
+ };
25
+ }
26
+ function runtimeContractJson(contract) {
27
+ return JSON.stringify({
28
+ schemaVersion: contract.schemaVersion,
29
+ fingerprint: contract.fingerprint,
30
+ coverageVersion: contract.coverageVersion,
31
+ });
32
+ }
33
+ function parsePermissions(value) {
34
+ try {
35
+ const parsed = JSON.parse(String(value || '[]'));
36
+ return Array.isArray(parsed) ? parsed : [];
37
+ }
38
+ catch {
39
+ return [];
40
+ }
41
+ }
42
+ function storedSession(row) {
43
+ return {
44
+ id: String(row.id || ''),
45
+ tokenDigest: String(row.token_digest || ''),
46
+ workspaceId: String(row.workspace_id || ''),
47
+ clientId: String(row.client_id || ''),
48
+ connectionInstance: String(row.connection_instance || ''),
49
+ permissions: parsePermissions(row.permissions_json),
50
+ toolProfile: String(row.tool_profile || ''),
51
+ protocolVersion: String(row.protocol_version || ''),
52
+ generation: String(row.generation || ''),
53
+ runtimeContract: JSON.parse(String(row.runtime_contract_json || '{}')),
54
+ aiProfileId: row.ai_profile_id ? String(row.ai_profile_id) : null,
55
+ createdAt: String(row.created_at || ''),
56
+ lastUsedAt: String(row.last_used_at || ''),
57
+ expiresAt: String(row.expires_at || ''),
58
+ revokedAt: row.revoked_at ? String(row.revoked_at) : null,
59
+ };
60
+ }
61
+ export function ensureLocalServiceCredentialSchema(db) {
62
+ db.exec(`
63
+ CREATE TABLE IF NOT EXISTS local_service_credential_generations (
64
+ tenant_id TEXT PRIMARY KEY,
65
+ generation TEXT NOT NULL,
66
+ runtime_contract_json TEXT NOT NULL,
67
+ activated_at TEXT NOT NULL
68
+ );
69
+
70
+ CREATE TABLE IF NOT EXISTS local_service_credentials (
71
+ tenant_id TEXT NOT NULL,
72
+ id TEXT NOT NULL,
73
+ token_digest TEXT NOT NULL,
74
+ workspace_id TEXT NOT NULL,
75
+ client_id TEXT NOT NULL,
76
+ connection_instance TEXT NOT NULL,
77
+ permissions_json TEXT NOT NULL,
78
+ tool_profile TEXT NOT NULL,
79
+ protocol_version TEXT NOT NULL,
80
+ generation TEXT NOT NULL,
81
+ runtime_contract_json TEXT NOT NULL,
82
+ ai_profile_id TEXT,
83
+ created_at TEXT NOT NULL,
84
+ last_used_at TEXT NOT NULL,
85
+ expires_at TEXT NOT NULL,
86
+ revoked_at TEXT,
87
+ PRIMARY KEY (tenant_id, id)
88
+ );
89
+
90
+ CREATE UNIQUE INDEX IF NOT EXISTS local_service_credentials_active_connection
91
+ ON local_service_credentials (
92
+ tenant_id, generation, workspace_id, client_id, connection_instance
93
+ )
94
+ WHERE revoked_at IS NULL;
95
+
96
+ CREATE INDEX IF NOT EXISTS local_service_credentials_active_generation
97
+ ON local_service_credentials (tenant_id, generation, expires_at)
98
+ WHERE revoked_at IS NULL;
99
+ `);
22
100
  }
23
101
  export class LocalServiceSessionManager {
24
102
  generation;
103
+ db;
104
+ tenantId;
105
+ runtimeContract;
25
106
  options;
26
- sessions = new Map();
27
107
  inFlightBySession = new Map();
28
- operationBindings = new Map();
29
108
  cancellationBindings = new Map();
30
109
  cancellationTombstones = new Map();
31
110
  drainWaiters = new Set();
32
111
  lifecycleState = 'accepting';
33
- constructor(generation, options = {}) {
112
+ runtimeContractJson;
113
+ authenticateStatement;
114
+ touchStatement;
115
+ constructor(generation, db, tenantId, runtimeContract, options = {}) {
34
116
  this.generation = generation;
117
+ this.db = db;
118
+ this.tenantId = tenantId;
119
+ this.runtimeContract = runtimeContract;
35
120
  this.options = options;
121
+ this.runtimeContractJson = runtimeContractJson(runtimeContract);
122
+ ensureLocalServiceCredentialSchema(db);
123
+ this.authenticateStatement = db.prepare(`
124
+ SELECT c.*,
125
+ g.generation AS active_generation,
126
+ g.runtime_contract_json AS active_runtime_contract_json
127
+ FROM local_service_credentials AS c
128
+ LEFT JOIN local_service_credential_generations AS g
129
+ ON g.tenant_id = c.tenant_id
130
+ WHERE c.tenant_id = ? AND c.id = ?
131
+ LIMIT 1
132
+ `);
133
+ this.touchStatement = db.prepare(`
134
+ UPDATE local_service_credentials
135
+ SET last_used_at = ?, expires_at = ?
136
+ WHERE tenant_id = ? AND id = ? AND generation = ?
137
+ AND runtime_contract_json = ? AND revoked_at IS NULL AND expires_at > ?
138
+ `);
139
+ const activatedAt = new Date(this.nowMs()).toISOString();
140
+ db.transaction(() => {
141
+ const existing = db.prepare(`
142
+ SELECT generation, runtime_contract_json
143
+ FROM local_service_credential_generations
144
+ WHERE tenant_id = ?
145
+ LIMIT 1
146
+ `).get(tenantId);
147
+ if (existing?.generation === generation
148
+ && existing.runtime_contract_json !== this.runtimeContractJson) {
149
+ throw new LocalServiceSessionError('Local service runtime contract mismatch for the active generation.', 409, 'RUNTIME_CONTRACT_MISMATCH');
150
+ }
151
+ db.prepare(`
152
+ INSERT INTO local_service_credential_generations (
153
+ tenant_id, generation, runtime_contract_json, activated_at
154
+ ) VALUES (?, ?, ?, ?)
155
+ ON CONFLICT (tenant_id) DO UPDATE SET
156
+ generation = excluded.generation,
157
+ runtime_contract_json = excluded.runtime_contract_json,
158
+ activated_at = excluded.activated_at
159
+ `).run(tenantId, generation, this.runtimeContractJson, activatedAt);
160
+ })();
36
161
  }
37
162
  nowMs() {
38
163
  return this.options.nowMs?.() ?? Date.now();
39
164
  }
40
165
  prune() {
41
- const cutoff = this.nowMs() - (this.options.idleTtlMs ?? LOCAL_SERVICE_SESSION_IDLE_TTL_MS);
42
- let pruned = 0;
43
- for (const [id, session] of this.sessions) {
44
- if (session.lastUsedAtMs > cutoff)
166
+ const now = new Date(this.nowMs()).toISOString();
167
+ const expired = this.db.prepare(`
168
+ SELECT id
169
+ FROM local_service_credentials
170
+ WHERE tenant_id = ? AND revoked_at IS NULL AND expires_at <= ?
171
+ `).all(this.tenantId, now);
172
+ const result = this.db.prepare(`
173
+ UPDATE local_service_credentials
174
+ SET revoked_at = ?
175
+ WHERE tenant_id = ? AND revoked_at IS NULL AND expires_at <= ?
176
+ `).run(now, this.tenantId, now);
177
+ for (const row of expired) {
178
+ const id = String(row.id || '');
179
+ if (!id)
45
180
  continue;
46
- this.sessions.delete(id);
47
- this.removeOperationBindings(id);
48
181
  this.removeCancellationBindings(id);
49
- pruned += 1;
50
182
  }
51
- return pruned;
183
+ return Number(result?.changes || 0);
52
184
  }
53
185
  create(input, options = {}) {
54
186
  this.prune();
@@ -58,64 +190,142 @@ export class LocalServiceSessionManager {
58
190
  if (input.generation !== this.generation) {
59
191
  throw new LocalServiceSessionError('Local service generation mismatch.', 409, 'GENERATION_MISMATCH');
60
192
  }
61
- if (this.sessions.size >= (this.options.cap ?? LOCAL_SERVICE_SESSION_CAP)) {
62
- throw new LocalServiceSessionError('Local service session capacity reached.', 503, 'SESSION_CAPACITY_REACHED');
63
- }
64
- const connectionInUse = Array.from(this.sessions.values()).some((session) => (session.workspaceId === input.workspaceId
65
- && session.clientId === input.clientId
66
- && session.connectionInstance === input.connectionInstance));
67
- if (connectionInUse) {
68
- throw new LocalServiceSessionError('This client connection instance already has an active local service session.', 409, 'CONNECTION_INSTANCE_IN_USE');
69
- }
70
193
  const id = this.options.randomId?.() ?? randomUUID();
71
194
  const secret = this.options.randomSecret?.() ?? randomBytes(32).toString('base64url');
72
195
  const token = `${id}.${secret}`;
73
196
  const nowMs = this.nowMs();
74
197
  const now = new Date(nowMs).toISOString();
198
+ const expiresAt = new Date(nowMs + (this.options.idleTtlMs ?? LOCAL_SERVICE_SESSION_IDLE_TTL_MS)).toISOString();
75
199
  const stored = {
76
200
  ...input,
77
201
  permissions: [...new Set(input.permissions)],
78
202
  id,
203
+ runtimeContract: { ...this.runtimeContract },
79
204
  createdAt: now,
80
205
  lastUsedAt: now,
81
- lastUsedAtMs: nowMs,
206
+ expiresAt,
207
+ revokedAt: null,
82
208
  aiProfileId: options.aiProfileId || null,
83
209
  tokenDigest: digestToken(token),
84
210
  };
85
- this.sessions.set(id, stored);
211
+ this.db.transaction(() => {
212
+ const activeGeneration = this.db.prepare(`
213
+ SELECT generation, runtime_contract_json
214
+ FROM local_service_credential_generations
215
+ WHERE tenant_id = ?
216
+ LIMIT 1
217
+ `).get(this.tenantId);
218
+ if (activeGeneration?.generation !== this.generation) {
219
+ throw new LocalServiceSessionError('Local service generation mismatch.', 409, 'GENERATION_MISMATCH');
220
+ }
221
+ if (activeGeneration.runtime_contract_json !== this.runtimeContractJson) {
222
+ throw new LocalServiceSessionError('Local service runtime contract mismatch.', 409, 'RUNTIME_CONTRACT_MISMATCH');
223
+ }
224
+ const activeCount = this.db.prepare(`
225
+ SELECT COUNT(*) AS count
226
+ FROM local_service_credentials
227
+ WHERE tenant_id = ? AND generation = ? AND runtime_contract_json = ?
228
+ AND revoked_at IS NULL AND expires_at > ?
229
+ `).get(this.tenantId, this.generation, this.runtimeContractJson, now);
230
+ if (Number(activeCount?.count || 0) >= (this.options.cap ?? LOCAL_SERVICE_SESSION_CAP)) {
231
+ throw new LocalServiceSessionError('Local service session capacity reached.', 503, 'SESSION_CAPACITY_REACHED');
232
+ }
233
+ const connectionInUse = this.db.prepare(`
234
+ SELECT 1 AS active
235
+ FROM local_service_credentials
236
+ WHERE tenant_id = ? AND generation = ? AND workspace_id = ?
237
+ AND client_id = ? AND connection_instance = ?
238
+ AND revoked_at IS NULL AND expires_at > ?
239
+ LIMIT 1
240
+ `).get(this.tenantId, this.generation, input.workspaceId, input.clientId, input.connectionInstance, now);
241
+ if (connectionInUse) {
242
+ throw new LocalServiceSessionError('This client connection instance already has an active local service session.', 409, 'CONNECTION_INSTANCE_IN_USE');
243
+ }
244
+ this.db.prepare(`
245
+ INSERT INTO local_service_credentials (
246
+ tenant_id, id, token_digest, workspace_id, client_id, connection_instance,
247
+ permissions_json, tool_profile, protocol_version, generation,
248
+ runtime_contract_json, ai_profile_id, created_at, last_used_at, expires_at, revoked_at
249
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)
250
+ `).run(this.tenantId, stored.id, stored.tokenDigest, stored.workspaceId, stored.clientId, stored.connectionInstance, JSON.stringify(stored.permissions), stored.toolProfile, stored.protocolVersion, stored.generation, this.runtimeContractJson, stored.aiProfileId, stored.createdAt, stored.lastUsedAt, stored.expiresAt);
251
+ })();
86
252
  return { session: publicSession(stored), token };
87
253
  }
88
254
  authenticate(token, options = {}) {
89
- this.prune();
90
255
  const separator = token.indexOf('.');
91
256
  const id = separator > 0 ? token.slice(0, separator) : '';
92
- const candidate = this.sessions.get(id);
93
- const actualDigest = digestToken(token);
94
- const expectedDigest = candidate?.tokenDigest ?? Buffer.alloc(actualDigest.length);
95
- if (!candidate || !timingSafeEqual(actualDigest, expectedDigest))
257
+ if (!id)
96
258
  return null;
97
- if (candidate.generation !== this.generation)
259
+ const row = this.authenticateStatement.get(this.tenantId, id);
260
+ const actualDigest = Buffer.from(digestToken(token), 'hex');
261
+ const expectedDigest = Buffer.from(String(row?.token_digest || '').padEnd(64, '0').slice(0, 64), 'hex');
262
+ if (!row || expectedDigest.length !== actualDigest.length
263
+ || !timingSafeEqual(actualDigest, expectedDigest))
98
264
  return null;
99
- if (options.touch !== false) {
100
- const nowMs = this.nowMs();
101
- candidate.lastUsedAtMs = nowMs;
102
- candidate.lastUsedAt = new Date(nowMs).toISOString();
265
+ if (row.generation !== this.generation || row.active_generation !== this.generation) {
266
+ throw new LocalServiceSessionError('Local service generation mismatch.', 409, 'GENERATION_MISMATCH');
267
+ }
268
+ if (row.runtime_contract_json !== this.runtimeContractJson
269
+ || row.active_runtime_contract_json !== this.runtimeContractJson) {
270
+ throw new LocalServiceSessionError('Local service runtime contract mismatch.', 409, 'RUNTIME_CONTRACT_MISMATCH');
271
+ }
272
+ const nowMs = this.nowMs();
273
+ const now = new Date(nowMs).toISOString();
274
+ if (row.revoked_at || String(row.expires_at || '') <= now) {
275
+ if (!row.revoked_at) {
276
+ this.db.prepare(`
277
+ UPDATE local_service_credentials
278
+ SET revoked_at = ?
279
+ WHERE tenant_id = ? AND id = ? AND revoked_at IS NULL
280
+ `).run(now, this.tenantId, id);
281
+ }
282
+ return null;
283
+ }
284
+ const idleTtlMs = this.options.idleTtlMs ?? LOCAL_SERVICE_SESSION_IDLE_TTL_MS;
285
+ const touchIntervalMs = Math.min(60_000, Math.max(1, Math.floor(idleTtlMs / 2)));
286
+ const lastUsedAtMs = Date.parse(String(row.last_used_at || ''));
287
+ if (options.touch !== false
288
+ && (!Number.isFinite(lastUsedAtMs) || nowMs - lastUsedAtMs >= touchIntervalMs)) {
289
+ const expiresAt = new Date(nowMs + idleTtlMs).toISOString();
290
+ const touched = this.touchStatement.run(now, expiresAt, this.tenantId, id, this.generation, this.runtimeContractJson, now);
291
+ if (Number(touched?.changes || 0) !== 1)
292
+ return null;
293
+ row.last_used_at = now;
294
+ row.expires_at = expiresAt;
103
295
  }
104
- return publicSession(candidate);
296
+ return publicSession(storedSession(row));
105
297
  }
106
298
  revoke(id) {
107
- const revoked = this.sessions.delete(id);
108
- if (revoked)
109
- this.removeOperationBindings(id);
299
+ const now = new Date(this.nowMs()).toISOString();
300
+ const result = this.db.transaction(() => this.db.prepare(`
301
+ UPDATE local_service_credentials
302
+ SET revoked_at = ?
303
+ WHERE tenant_id = ? AND id = ? AND generation = ?
304
+ AND runtime_contract_json = ? AND revoked_at IS NULL
305
+ `).run(now, this.tenantId, id, this.generation, this.runtimeContractJson))();
306
+ const revoked = Number(result?.changes || 0) === 1;
110
307
  if (revoked)
111
308
  this.removeCancellationBindings(id);
112
309
  return revoked;
113
310
  }
311
+ hasActiveCredential(id) {
312
+ const now = new Date(this.nowMs()).toISOString();
313
+ return Boolean(this.db.prepare(`
314
+ SELECT 1 AS active
315
+ FROM local_service_credentials AS c
316
+ JOIN local_service_credential_generations AS g ON g.tenant_id = c.tenant_id
317
+ WHERE c.tenant_id = ? AND c.id = ?
318
+ AND c.generation = ? AND g.generation = ?
319
+ AND c.runtime_contract_json = ? AND g.runtime_contract_json = ?
320
+ AND c.revoked_at IS NULL AND c.expires_at > ?
321
+ LIMIT 1
322
+ `).get(this.tenantId, id, this.generation, this.generation, this.runtimeContractJson, this.runtimeContractJson, now));
323
+ }
114
324
  beginRequest(id) {
115
325
  if (this.lifecycleState !== 'accepting') {
116
326
  throw new LocalServiceSessionError('Local service is shutting down.', 503, 'SERVICE_QUIESCING');
117
327
  }
118
- if (!this.sessions.has(id)) {
328
+ if (!this.hasActiveCredential(id)) {
119
329
  throw new LocalServiceSessionError('Local service session not found.', 401, 'SESSION_NOT_FOUND');
120
330
  }
121
331
  this.inFlightBySession.set(id, (this.inFlightBySession.get(id) || 0) + 1);
@@ -152,7 +362,7 @@ export class LocalServiceSessionManager {
152
362
  throw new LocalServiceSessionError('Local service is already shutting down.', 409, 'SERVICE_QUIESCING');
153
363
  }
154
364
  if (mode === 'refuse') {
155
- if (this.sessions.size > 0 || this.inFlightCount() > 0) {
365
+ if (this.activeCount() > 0 || this.inFlightCount() > 0) {
156
366
  throw new LocalServiceSessionError('Active sessions prevent shutdown.', 409, 'ACTIVE_SESSIONS');
157
367
  }
158
368
  this.lifecycleState = 'draining';
@@ -189,13 +399,18 @@ export class LocalServiceSessionManager {
189
399
  revokeAll() {
190
400
  for (const cancel of this.cancellationBindings.values())
191
401
  cancel();
192
- this.sessions.clear();
193
- this.operationBindings.clear();
402
+ const now = new Date(this.nowMs()).toISOString();
403
+ this.db.transaction(() => this.db.prepare(`
404
+ UPDATE local_service_credentials
405
+ SET revoked_at = ?
406
+ WHERE tenant_id = ? AND generation = ? AND runtime_contract_json = ?
407
+ AND revoked_at IS NULL
408
+ `).run(now, this.tenantId, this.generation, this.runtimeContractJson))();
194
409
  this.cancellationBindings.clear();
195
410
  this.cancellationTombstones.clear();
196
411
  }
197
412
  registerCancellation(sessionId, correlationId, cancel) {
198
- if (!this.sessions.has(sessionId)) {
413
+ if (!this.hasActiveCredential(sessionId)) {
199
414
  throw new LocalServiceSessionError('Local service session not found.', 401, 'SESSION_NOT_FOUND');
200
415
  }
201
416
  const key = `${sessionId}:${correlationId}`;
@@ -213,7 +428,7 @@ export class LocalServiceSessionManager {
213
428
  };
214
429
  }
215
430
  cancelRequest(sessionId, correlationId) {
216
- if (!this.sessions.has(sessionId))
431
+ if (!this.hasActiveCredential(sessionId))
217
432
  return false;
218
433
  this.pruneCancellationTombstones();
219
434
  const key = `${sessionId}:${correlationId}`;
@@ -230,44 +445,6 @@ export class LocalServiceSessionManager {
230
445
  this.cancellationTombstones.set(key, this.nowMs() + LOCAL_SERVICE_CANCELLATION_TOMBSTONE_TTL_MS);
231
446
  return true;
232
447
  }
233
- recordOperation(input) {
234
- if (!this.sessions.has(input.sessionId)) {
235
- throw new LocalServiceSessionError('Local service session not found.', 401, 'SESSION_NOT_FOUND');
236
- }
237
- const key = `${input.sessionId}:${input.operationId}`;
238
- const existing = this.operationBindings.get(key);
239
- if (existing && (existing.mutationKind !== input.mutationKind
240
- || existing.payloadFingerprint !== input.payloadFingerprint)) {
241
- throw new LocalServiceSessionError('Operation identity conflicts with an earlier payload in this session.', 409, 'OPERATION_IDENTITY_CONFLICT');
242
- }
243
- if (existing)
244
- return existing;
245
- if (this.operationBindings.size >= LOCAL_SERVICE_OPERATION_BINDING_CAP) {
246
- const oldestKey = this.operationBindings.keys().next().value;
247
- if (oldestKey)
248
- this.operationBindings.delete(oldestKey);
249
- }
250
- const binding = { ...input, recordedAt: new Date(this.nowMs()).toISOString() };
251
- this.operationBindings.set(key, binding);
252
- return binding;
253
- }
254
- getOperationBinding(sessionId, operationId, expected) {
255
- const binding = this.operationBindings.get(`${sessionId}:${operationId}`) || null;
256
- if (!binding)
257
- return null;
258
- if (expected?.mutationKind && expected.mutationKind !== binding.mutationKind)
259
- return null;
260
- if (expected?.payloadFingerprint && expected.payloadFingerprint !== binding.payloadFingerprint)
261
- return null;
262
- return { ...binding };
263
- }
264
- removeOperationBindings(sessionId) {
265
- const prefix = `${sessionId}:`;
266
- for (const key of this.operationBindings.keys()) {
267
- if (key.startsWith(prefix))
268
- this.operationBindings.delete(key);
269
- }
270
- }
271
448
  removeCancellationBindings(sessionId) {
272
449
  const prefix = `${sessionId}:`;
273
450
  for (const [key, cancel] of this.cancellationBindings) {
@@ -289,21 +466,58 @@ export class LocalServiceSessionManager {
289
466
  }
290
467
  }
291
468
  bindAiProfile(id, profileId) {
292
- const session = this.sessions.get(id);
293
- if (!session)
294
- throw new LocalServiceSessionError('Local service session not found.', 401, 'SESSION_NOT_FOUND');
295
- if (session.aiProfileId && session.aiProfileId !== profileId) {
296
- throw new LocalServiceSessionError('This local service session is already bound to a different AI profile.', 409, 'AI_PROFILE_BINDING_CONFLICT');
297
- }
298
- session.aiProfileId = profileId;
299
- return publicSession(session);
469
+ const now = new Date(this.nowMs()).toISOString();
470
+ return this.db.transaction(() => {
471
+ const row = this.db.prepare(`
472
+ SELECT *
473
+ FROM local_service_credentials
474
+ WHERE tenant_id = ? AND id = ? AND generation = ?
475
+ AND runtime_contract_json = ? AND revoked_at IS NULL AND expires_at > ?
476
+ LIMIT 1
477
+ `).get(this.tenantId, id, this.generation, this.runtimeContractJson, now);
478
+ if (!row) {
479
+ throw new LocalServiceSessionError('Local service session not found.', 401, 'SESSION_NOT_FOUND');
480
+ }
481
+ if (row.ai_profile_id && row.ai_profile_id !== profileId) {
482
+ throw new LocalServiceSessionError('This local service session is already bound to a different AI profile.', 409, 'AI_PROFILE_BINDING_CONFLICT');
483
+ }
484
+ if (!row.ai_profile_id) {
485
+ const result = this.db.prepare(`
486
+ UPDATE local_service_credentials
487
+ SET ai_profile_id = ?
488
+ WHERE tenant_id = ? AND id = ? AND ai_profile_id IS NULL
489
+ AND generation = ? AND runtime_contract_json = ?
490
+ AND revoked_at IS NULL AND expires_at > ?
491
+ `).run(profileId, this.tenantId, id, this.generation, this.runtimeContractJson, now);
492
+ if (Number(result?.changes || 0) !== 1) {
493
+ throw new LocalServiceSessionError('This local service session could not be bound.', 409, 'AI_PROFILE_BINDING_CONFLICT');
494
+ }
495
+ row.ai_profile_id = profileId;
496
+ }
497
+ return publicSession(storedSession(row));
498
+ })();
300
499
  }
301
500
  activeCount() {
302
501
  this.prune();
303
- return this.sessions.size;
502
+ const now = new Date(this.nowMs()).toISOString();
503
+ const row = this.db.prepare(`
504
+ SELECT COUNT(*) AS count
505
+ FROM local_service_credentials
506
+ WHERE tenant_id = ? AND generation = ? AND runtime_contract_json = ?
507
+ AND revoked_at IS NULL AND expires_at > ?
508
+ `).get(this.tenantId, this.generation, this.runtimeContractJson, now);
509
+ return Number(row?.count || 0);
304
510
  }
305
511
  list() {
306
512
  this.prune();
307
- return Array.from(this.sessions.values(), publicSession);
513
+ const now = new Date(this.nowMs()).toISOString();
514
+ const rows = this.db.prepare(`
515
+ SELECT *
516
+ FROM local_service_credentials
517
+ WHERE tenant_id = ? AND generation = ? AND runtime_contract_json = ?
518
+ AND revoked_at IS NULL AND expires_at > ?
519
+ ORDER BY created_at, id
520
+ `).all(this.tenantId, this.generation, this.runtimeContractJson, now);
521
+ return rows.map((row) => publicSession(storedSession(row)));
308
522
  }
309
523
  }
@@ -3,7 +3,7 @@ import { LocalSyncCoordinatorStore } from '../sync/coordinator/localSyncCoordina
3
3
  import { LocalSyncDispatchTracker } from '../sync/coordinator/localSyncDispatchTracker.js';
4
4
  import { LocalSyncExecutionPermitStore } from '../sync/coordinator/localSyncExecutionPermitStore.js';
5
5
  import { LocalSyncOwnershipDrainBarrier } from '../sync/coordinator/localSyncOwnershipDrainBarrier.js';
6
- import { LocalWorkspaceSyncRunner, } from '../sync/coordinator/localWorkspaceSyncRunner.js';
6
+ import { canCoordinatorRecoveryPreemptRetry, LocalWorkspaceSyncRunner, } from '../sync/coordinator/localWorkspaceSyncRunner.js';
7
7
  import { reconcileSettledV3DispatchRecoveryObligations, } from '../sync/coordinator/localSyncV3DispatchRecoveryReconciler.js';
8
8
  import { LocalWorkspaceSyncRunnerStateStore } from '../sync/coordinator/localWorkspaceSyncRunnerState.js';
9
9
  import { WorkspaceSyncCredentialBroker, } from '../sync/coordinator/workspaceSyncCredentialBroker.js';
@@ -15,7 +15,7 @@ import { createWorkspaceSyncEngineServerRunnerOperations } from '../sync/engine/
15
15
  import { workspaceSyncTransferEvidenceEvent } from '../sync/engine/workspaceSyncTransferEvidence.js';
16
16
  import { createWorkspaceSyncEngineServerPushCandidateProvider, createWorkspaceSyncEngineServerSnapshotReader, } from '../sync/engine/workspaceSyncEngineServerSnapshotReader.js';
17
17
  import { readWorkspaceSyncLocalOwnershipSnapshot } from '../sync/v3/workspaceSyncLocalOwnershipSnapshot.js';
18
- import { resolveRequestedCombinedFeedCoverage } from '../sync/v3/combinedFeedCapability.js';
18
+ import { resolveCombinedFeedCapability } from '../sync/v3/combinedFeedCapability.js';
19
19
  import { resolveWorkspaceSyncV3CombinedWireContract, } from '../sync/v3/workspaceSyncV3CombinedWireContract.js';
20
20
  import { LocalWorkspaceSyncServerOutboxDispatcher, } from '../sync/v3/localWorkspaceSyncServerOutboxDispatcher.js';
21
21
  import { readWorkspaceSyncV3LocalOutboxStatus, } from '../sync/v3/workspaceSyncV3LocalOutboxStatus.js';
@@ -518,7 +518,13 @@ export class LocalWorkspaceSyncServerRuntime {
518
518
  if (!status.checkpoint?.checkpoint.syncEnabled)
519
519
  return;
520
520
  const retry = status.checkpoint.checkpoint.retry;
521
- if (retry && Date.parse(retry.retryAt) > this.now().getTime()) {
521
+ const coordinatorRecoveryPlan = this.permitStore.inspectAuthoritativeRepairRecoveryObligations(bundle.context.workspaceId);
522
+ const retryWaiting = Boolean(retry && Date.parse(retry.retryAt) > this.now().getTime());
523
+ const recoveryPreemptsRetry = Boolean(retryWaiting
524
+ && retry
525
+ && coordinatorRecoveryPlan.total > 0
526
+ && canCoordinatorRecoveryPreemptRetry(retry.kind));
527
+ if (retryWaiting && retry && !recoveryPreemptsRetry) {
522
528
  // Authoritative repair cannot proceed while covered local
523
529
  // operations remain active. Keep settling those operations during
524
530
  // the repair backoff window so a dependency that becomes due
@@ -534,9 +540,8 @@ export class LocalWorkspaceSyncServerRuntime {
534
540
  }
535
541
  return;
536
542
  }
537
- const retryDue = Boolean(retry);
543
+ const retryDue = Boolean(retry) && !recoveryPreemptsRetry;
538
544
  const wakeEpoch = this.ordinaryWakeEpoch;
539
- const coordinatorRecoveryPlan = this.permitStore.inspectAuthoritativeRepairRecoveryObligations(bundle.context.workspaceId);
540
545
  if (retry?.kind === 'v2-content-push') {
541
546
  // This retry exists specifically to publish content required by a
542
547
  // blocked durable operation. Re-dispatching that same operation
@@ -585,7 +590,10 @@ export class LocalWorkspaceSyncServerRuntime {
585
590
  || state.coordinatorGeneration !== bundle.context.coordinatorGeneration) {
586
591
  return;
587
592
  }
588
- if (retryDue) {
593
+ if (recoveryPreemptsRetry) {
594
+ await bundle.runner.recoverCoordinatorObligationsDue(() => this.permitStore.inspectAuthoritativeRepairRecoveryObligations(bundle.context.workspaceId).total > 0);
595
+ }
596
+ else if (retryDue) {
589
597
  await bundle.runner.retryDue();
590
598
  }
591
599
  else if (wakeSources.size === 1
@@ -945,29 +953,27 @@ export class LocalWorkspaceSyncServerRuntime {
945
953
  workspaceId,
946
954
  });
947
955
  const combined = ownership.combinedProjection;
956
+ const configuredCombined = resolveCombinedFeedCapability({
957
+ runtimeMode: 'local',
958
+ env: this.options.env || process.env,
959
+ }).combinedFeed;
948
960
  const combinedContract = combined.owner === 'v3'
949
961
  ? resolveWorkspaceSyncV3CombinedWireContract(combined)
950
962
  : null;
951
963
  if (combined.owner === 'v3' && !combinedContract) {
952
964
  throw Object.assign(new Error('The persisted combined-feed ownership contract is invalid.'), { code: 'SYNC_RUNNER_V3_OWNERSHIP_INVALID' });
953
965
  }
954
- const desiredCombinedCoverage = combined.owner === 'v3'
955
- ? resolveRequestedCombinedFeedCoverage(this.options.env || process.env)
956
- : null;
957
- const desiredCombinedContract = desiredCombinedCoverage
958
- ? resolveWorkspaceSyncV3CombinedWireContract(desiredCombinedCoverage)
959
- : null;
966
+ const desiredCombinedContract = resolveWorkspaceSyncV3CombinedWireContract(configuredCombined.coverage);
967
+ if (!desiredCombinedContract) {
968
+ throw Object.assign(new Error('The configured combined-feed ownership contract is invalid.'), { code: 'SYNC_RUNNER_V3_OWNERSHIP_INVALID' });
969
+ }
960
970
  return {
961
971
  initiativeFeedActivationEnabled: ownership.initiativeProjection.owner === 'v3',
962
972
  initiativeProjection: ownership.initiativeProjection,
963
- combinedFeedActivationEnabled: combined.owner === 'v3',
973
+ combinedFeedActivationEnabled: configuredCombined.activationReady,
964
974
  combinedProjection: combined,
965
- ...(combinedContract && desiredCombinedContract
966
- ? {
967
- combinedFeedCoverage: desiredCombinedContract.coverage,
968
- combinedFeedExcludedProjections: desiredCombinedContract.excludedProjections,
969
- }
970
- : {}),
975
+ combinedFeedCoverage: desiredCombinedContract.coverage,
976
+ combinedFeedExcludedProjections: desiredCombinedContract.excludedProjections,
971
977
  };
972
978
  },
973
979
  createLocalServices: ({ checkpointPort }) => {
@@ -21,6 +21,7 @@
21
21
  * GET /api/taskforce/admin/collaboration-telemetry
22
22
  * PATCH /api/taskforce/admin/system-users/:id/disable
23
23
  * PATCH /api/taskforce/admin/system-users/:id/beta-access
24
+ * PATCH /api/taskforce/admin/system-users/:id/feature-grants/:featureKey
24
25
  * PATCH /api/taskforce/admin/system-users/:id/verify-email
25
26
  * GET/POST /api/taskforce/admin/email-settings
26
27
  * GET /api/taskforce/admin/email-settings/health
@@ -48,8 +49,10 @@
48
49
  * GET/POST /oauth/mcp/authorize
49
50
  * POST /oauth/mcp/token
50
51
  * GET/POST /api/taskforce/settings/mcp/tokens (+ revoke, regenerate)
52
+ * PATCH /api/taskforce/settings/mcp/tokens/:id/tool-profile
51
53
  * GET /api/taskforce/settings/mcp/connectors
52
54
  * POST /api/taskforce/settings/mcp/connectors/:id/disconnect
55
+ * PATCH /api/taskforce/settings/mcp/connectors/:id/tool-profile
53
56
  * POST /api/taskforce/settings/mcp/test-connection
54
57
  */
55
58
  import type { IncomingMessage, ServerResponse } from 'http';
@@ -68,6 +71,7 @@ export interface AdminRouteDependencies {
68
71
  requestRole: (req: IncomingMessage) => string;
69
72
  ensureAppAccess: (req: IncomingMessage, res: ServerResponse) => boolean;
70
73
  ensureAdminRole: (req: IncomingMessage) => boolean;
74
+ ensureWorkspaceAdminRole: (req: IncomingMessage, workspaceIdOverride?: string | null) => boolean;
71
75
  ensureCloudPlanData: (req: IncomingMessage, res: ServerResponse) => boolean;
72
76
  requireCloudRuntime: (res: ServerResponse, feature: string) => boolean;
73
77
  resolveAuthenticatedUserId: (req: IncomingMessage) => string;