@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.
- package/README.md +7 -2
- package/dist/Taskforce.module.css +290 -45
- package/dist/components/features/AiProfilesModule.js +3 -5
- package/dist/components/features/TaskSettings.js +70 -14
- package/dist/components/features/TaskforceAgentsModule.d.ts +1 -2
- package/dist/components/features/TaskforceAgentsModule.js +586 -116
- package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +2 -2
- package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.js +2 -2
- package/dist/components/features/agentConnections/AgentConnectionControl.d.ts +15 -0
- package/dist/components/features/agentConnections/AgentConnectionControl.js +125 -0
- package/dist/components/features/agentConnections/ModelConnectionsPanel.d.ts +18 -0
- package/dist/components/features/agentConnections/ModelConnectionsPanel.js +393 -0
- package/dist/components/features/agentConnections/modelConnectionsApi.d.ts +65 -0
- package/dist/components/features/agentConnections/modelConnectionsApi.js +129 -0
- package/dist/components/features/planning/PlanningModule.js +15 -3
- package/dist/components/features/planning/planningMetadata.d.ts +10 -0
- package/dist/components/features/planning/planningMetadata.js +8 -0
- package/dist/components/features/taskforceAgentAssignments/AgentBehaviorAssignments.js +15 -24
- package/dist/components/features/taskforceAgentEditorModel.d.ts +2 -1
- package/dist/components/features/taskforceAgentEditorModel.js +3 -1
- package/dist/components/features/workflowManager/workflowManagerApi.d.ts +1 -1
- package/dist/components/features/workflowManager/workflowManagerApi.js +3 -0
- package/dist/components/task/TaskWorkflowAssignmentField.js +68 -10
- package/dist/components/views/StandaloneLayout.js +62 -27
- package/dist/components/views/panels/PlanningDrawer.d.ts +2 -1
- package/dist/components/views/panels/PlanningDrawer.js +12 -8
- package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +4 -3
- package/dist/components/views/standalone/modals/SyncStatusModal.js +33 -38
- package/dist/config/envSchema.js +55 -1
- package/dist/core/McpTokenService.d.ts +25 -1
- package/dist/core/McpTokenService.js +106 -15
- package/dist/core/TaskChecklistCommandService.d.ts +27 -0
- package/dist/core/TaskChecklistCommandService.js +83 -5
- package/dist/core/TaskLifecycleCommandService.d.ts +3 -1
- package/dist/core/TaskLifecycleCommandService.js +6 -2
- package/dist/core/Taskforce.d.ts +43 -3
- package/dist/core/Taskforce.js +158 -7
- package/dist/core/types.d.ts +9 -0
- package/dist/documentReviews/DocumentReviewCommentStore.d.ts +2 -0
- package/dist/documentReviews/DocumentReviewCommentStore.js +28 -9
- package/dist/documentReviews/commandService.d.ts +2 -1
- package/dist/documentReviews/commandService.js +6 -3
- package/dist/hooks/sync/orchestratorShared.d.ts +1 -0
- package/dist/hooks/sync/orchestratorShared.js +2 -0
- package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.d.ts +3 -0
- package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.js +85 -9
- package/dist/hooks/sync/useSyncStatusControls.d.ts +4 -1
- package/dist/hooks/sync/useSyncStatusControls.js +47 -11
- package/dist/hooks/useSyncOrchestrator.d.ts +3 -0
- package/dist/hooks/useSyncOrchestrator.js +111 -2
- package/dist/hooks/useTaskData.d.ts +31 -1
- package/dist/hooks/useTaskData.js +29 -7
- package/dist/hooks/useTaskMutations.d.ts +3 -1
- package/dist/hooks/useTaskMutations.js +46 -12
- package/dist/hooks/useTaskforce.d.ts +2 -0
- package/dist/hooks/useTaskforce.js +11 -2
- package/dist/mcp/clientRegistry.d.ts +2 -2
- package/dist/mcp/clientRegistry.js +1 -1
- package/dist/mcp/documentAssetRegistrar.js +9 -6
- package/dist/mcp/durableTaskMutationRouter.d.ts +4 -1
- package/dist/mcp/durableTaskMutationRouter.js +10 -0
- package/dist/mcp/durableTaskRelationshipMutationRouter.js +4 -0
- package/dist/mcp/httpProtocolRouting.d.ts +11 -0
- package/dist/mcp/httpProtocolRouting.js +22 -0
- package/dist/mcp/localCliHealth.d.ts +2 -2
- package/dist/mcp/localCliHealth.js +2 -2
- package/dist/mcp/localServiceProxy.d.ts +1 -0
- package/dist/mcp/localServiceProxy.js +530 -68
- package/dist/mcp/planningAttachmentCommandAdapter.d.ts +3 -1
- package/dist/mcp/planningAttachmentCommandAdapter.js +20 -2
- package/dist/mcp/runtime.d.ts +54 -79
- package/dist/mcp/runtime.js +408 -102
- package/dist/mcp/taskPlanningRegistrar.js +25 -6
- package/dist/mcp/toolProfiles.d.ts +2 -0
- package/dist/mcp/toolProfiles.js +11 -0
- package/dist/mcp/toolRegistry.d.ts +1 -0
- package/dist/mcp/toolRegistry.js +9 -8
- package/dist/mcp/workflowExecutionRegistrar.js +4 -4
- package/dist/migrations/taskSchemaMigrations.d.ts +5 -0
- package/dist/migrations/taskSchemaMigrations.js +415 -0
- package/dist/runtime/appGates.d.ts +2 -1
- package/dist/runtime/appGates.js +7 -0
- package/dist/server/buildInfo.d.ts +1 -0
- package/dist/server/buildInfo.js +5 -1
- package/dist/server/cloudMcpCapacityTelemetry.d.ts +68 -0
- package/dist/server/cloudMcpCapacityTelemetry.js +221 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +108 -11
- package/dist/server/localDatabaseIdentity.js +4 -1
- package/dist/server/localServiceLease.js +2 -1
- package/dist/server/localServiceSessions.d.ts +14 -17
- package/dist/server/localServiceSessions.js +308 -94
- package/dist/server/localWorkspaceSyncServerRuntime.js +25 -19
- package/dist/server/routes/admin.d.ts +4 -0
- package/dist/server/routes/admin.js +126 -5
- package/dist/server/routes/agents.d.ts +7 -0
- package/dist/server/routes/agents.js +277 -24
- package/dist/server/routes/billing.js +5 -1
- package/dist/server/routes/durableTaskHttpRouters.d.ts +2 -0
- package/dist/server/routes/executorPhaseAApprovals.d.ts +19 -0
- package/dist/server/routes/executorPhaseAApprovals.js +140 -0
- package/dist/server/routes/executorPhaseAIssuerRedemptions.d.ts +11 -0
- package/dist/server/routes/executorPhaseAIssuerRedemptions.js +24 -0
- package/dist/server/routes/githubReviewEvidence.d.ts +19 -0
- package/dist/server/routes/githubReviewEvidence.js +116 -0
- package/dist/server/routes/localService.d.ts +15 -4
- package/dist/server/routes/localService.js +136 -40
- package/dist/server/routes/modelConnections.d.ts +24 -0
- package/dist/server/routes/modelConnections.js +205 -0
- package/dist/server/routes/shared.d.ts +22 -0
- package/dist/server/routes/shared.js +298 -182
- package/dist/server/routes/sync.js +1 -0
- package/dist/server/routes/syncAuxRoutes.js +5 -1
- package/dist/server/routes/syncPushRoutes.d.ts +1 -0
- package/dist/server/routes/syncPushRoutes.js +1 -0
- package/dist/server/routes/syncV3FeedRoutes.js +10 -1
- package/dist/server/routes/syncV3OperationRoutes.js +35 -9
- package/dist/server/routes/tasks.js +21 -2
- package/dist/server/routes/workflows.js +9 -1
- package/dist/server/routes.js +59 -0
- package/dist/service/localServiceCli.d.ts +2 -2
- package/dist/service/localServiceCli.js +4 -3
- package/dist/services/codexAppServerModelGateway.d.ts +54 -5
- package/dist/services/codexAppServerModelGateway.js +246 -21
- package/dist/services/codexDeviceCodeLoginManager.d.ts +39 -0
- package/dist/services/codexDeviceCodeLoginManager.js +265 -0
- package/dist/services/codexModelProviderConnectionLifecycle.d.ts +8 -0
- package/dist/services/codexModelProviderConnectionLifecycle.js +73 -0
- package/dist/services/executorPhaseAApprovalRuntime.d.ts +14 -0
- package/dist/services/executorPhaseAApprovalRuntime.js +24 -0
- package/dist/services/executorPhaseAApprovalService.d.ts +40 -0
- package/dist/services/executorPhaseAApprovalService.js +609 -0
- package/dist/services/executorPhaseADriftEvaluator.d.ts +78 -0
- package/dist/services/executorPhaseADriftEvaluator.js +93 -0
- package/dist/services/executorPhaseAIssuerCore.d.ts +139 -0
- package/dist/services/executorPhaseAIssuerCore.js +402 -0
- package/dist/services/executorPhaseAIssuerRedemptionService.d.ts +34 -0
- package/dist/services/executorPhaseAIssuerRedemptionService.js +158 -0
- package/dist/services/githubReviewEvidenceRuntime.d.ts +14 -0
- package/dist/services/githubReviewEvidenceRuntime.js +30 -0
- package/dist/services/githubReviewEvidenceService.d.ts +93 -0
- package/dist/services/githubReviewEvidenceService.js +336 -0
- package/dist/services/modelGateway.d.ts +7 -0
- package/dist/services/modelProviderConnectionService.d.ts +71 -0
- package/dist/services/modelProviderConnectionService.js +279 -0
- package/dist/services/modelProviderCredentialHome.d.ts +32 -0
- package/dist/services/modelProviderCredentialHome.js +271 -0
- package/dist/services/ownerScopedModelConnectionGateway.d.ts +12 -0
- package/dist/services/ownerScopedModelConnectionGateway.js +30 -0
- package/dist/services/taskforceAgentConnectionBindingService.d.ts +66 -0
- package/dist/services/taskforceAgentConnectionBindingService.js +185 -0
- package/dist/services/taskforceAgentMcpBridge.d.ts +2 -2
- package/dist/services/taskforceAgentMcpBridge.js +42 -29
- package/dist/shared/adminEdgeProxy.d.ts +5 -0
- package/dist/shared/adminEdgeProxy.js +94 -0
- package/dist/shared/adminProxySessionCookies.d.ts +16 -0
- package/dist/shared/adminProxySessionCookies.js +86 -0
- package/dist/shared/aiProfileColors.d.ts +31 -1
- package/dist/shared/aiProfileColors.js +14 -6
- package/dist/shared/executorPhaseAApprovalGoldenVector.json +269 -0
- package/dist/shared/executorPhaseAApprovalReceipt.d.ts +112 -0
- package/dist/shared/executorPhaseAApprovalReceipt.js +58 -0
- package/dist/shared/executorPhaseAApprovalTrustPolicy.json +10 -0
- package/dist/shared/executorPhaseADriftContracts.d.ts +37 -0
- package/dist/shared/executorPhaseADriftContracts.js +63 -0
- package/dist/shared/executorPhaseAIssuerContracts.d.ts +75 -0
- package/dist/shared/executorPhaseAIssuerContracts.js +90 -0
- package/dist/shared/executorPhaseARunAuthorization.d.ts +120 -0
- package/dist/shared/executorPhaseARunAuthorization.js +232 -0
- package/dist/shared/executorPhaseASchemaValidation.d.ts +7 -0
- package/dist/shared/executorPhaseASchemaValidation.js +53 -0
- package/dist/shared/executorPhaseASchemas/approval-receipt.schema.json +106 -0
- package/dist/shared/executorPhaseASchemas/drift-attestation.schema.json +54 -0
- package/dist/shared/executorPhaseASchemas/drift-request.schema.json +47 -0
- package/dist/shared/executorPhaseASchemas/foundation-manifest.schema.json +29 -0
- package/dist/shared/executorPhaseASchemas/issuer-audit-record.schema.json +24 -0
- package/dist/shared/executorPhaseASchemas/issuer-proof.schema.json +43 -0
- package/dist/shared/executorPhaseASchemas/issuer-redemption-request.schema.json +18 -0
- package/dist/shared/executorPhaseASchemas/issuer-redemption-response.schema.json +39 -0
- package/dist/shared/executorPhaseASchemas/logical-envelope.schema.json +149 -0
- package/dist/shared/executorPhaseASchemas/preflight-report.schema.json +216 -0
- package/dist/shared/executorPhaseASchemas/run-capability.schema.json +111 -0
- package/dist/shared/executorPhaseASchemas/sender-proof.schema.json +37 -0
- package/dist/shared/executorPhaseASchemas/workload-grant.schema.json +68 -0
- package/dist/shared/executorPhaseASchemas/workload-jwt-claims.schema.json +67 -0
- package/dist/shared/executorPhaseATiming.d.ts +1 -0
- package/dist/shared/executorPhaseATiming.js +1 -0
- package/dist/shared/planningIdentity.js +1 -1
- package/dist/shared/productLogoKeys.d.ts +2 -0
- package/dist/shared/productLogoKeys.js +18 -0
- package/dist/shared/taskforceAgentDefinition.d.ts +0 -1
- package/dist/shared/taskforceAgentDefinition.js +6 -9
- package/dist/shared/taskforceAgentModels.js +7 -3
- package/dist/shared/userFeatureGrants.d.ts +4 -0
- package/dist/shared/userFeatureGrants.js +7 -0
- package/dist/storage/executorPhaseAApprovalReceiptStore.d.ts +37 -0
- package/dist/storage/executorPhaseAApprovalReceiptStore.js +81 -0
- package/dist/storage/executorPhaseARunAuthorizationStore.d.ts +103 -0
- package/dist/storage/executorPhaseARunAuthorizationStore.js +492 -0
- package/dist/storage/githubReviewEvidenceInstallationStore.d.ts +26 -0
- package/dist/storage/githubReviewEvidenceInstallationStore.js +89 -0
- package/dist/storage/modelProviderConnectionStore.d.ts +99 -0
- package/dist/storage/modelProviderConnectionStore.js +446 -0
- package/dist/storage/postgresAdapter.d.ts +4 -0
- package/dist/storage/postgresAdapter.js +14 -1
- package/dist/storage/postgresRequestDiagnostics.d.ts +9 -1
- package/dist/storage/postgresRequestDiagnostics.js +15 -2
- package/dist/storage/postgresWorker.js +20 -2
- package/dist/storage/postgresWorkerProtocol.d.ts +7 -0
- package/dist/storage/taskforceAgentConnectionBindingStore.d.ts +31 -0
- package/dist/storage/taskforceAgentConnectionBindingStore.js +84 -0
- package/dist/storage/workflowStore.d.ts +2 -0
- package/dist/storage/workflowStore.js +39 -2
- package/dist/sync/cloudSyncApi.js +4 -2
- package/dist/sync/collaborationSyncState.js +5 -0
- package/dist/sync/coordinator/localSyncExecutionPermitStore.js +60 -29
- package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.d.ts +10 -0
- package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.js +29 -0
- package/dist/sync/coordinator/localWorkspaceSyncRunner.d.ts +3 -1
- package/dist/sync/coordinator/localWorkspaceSyncRunner.js +18 -0
- package/dist/sync/coordinator/localWorkspaceSyncRunnerState.d.ts +15 -1
- package/dist/sync/coordinator/localWorkspaceSyncRunnerState.js +99 -2
- package/dist/sync/coordinator/workspaceSyncCredentialBroker.d.ts +1 -0
- package/dist/sync/coordinator/workspaceSyncCredentialBroker.js +33 -4
- package/dist/sync/engine/workspaceSyncContentLifecycleAdapter.d.ts +2 -1
- package/dist/sync/engine/workspaceSyncContentVersionStore.d.ts +38 -0
- package/dist/sync/engine/workspaceSyncContentVersionStore.js +50 -1
- package/dist/sync/engine/workspaceSyncEngineLifecyclePolicy.js +6 -6
- package/dist/sync/engine/workspaceSyncEnginePushCompletion.d.ts +14 -0
- package/dist/sync/engine/workspaceSyncEnginePushCompletion.js +84 -0
- package/dist/sync/engine/workspaceSyncEngineRecovery.js +1 -0
- package/dist/sync/engine/workspaceSyncEngineRuntime.d.ts +1 -0
- package/dist/sync/engine/workspaceSyncEngineRuntime.js +1 -0
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +112 -38
- package/dist/sync/engine/workspaceSyncEngineServerSnapshotReader.js +6 -0
- package/dist/sync/engine/workspaceSyncEngineTransfers.js +3 -1
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.d.ts +1 -0
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +31 -0
- package/dist/sync/syncApplyHandlers.d.ts +3 -0
- package/dist/sync/syncApplyHandlers.js +81 -15
- package/dist/sync/syncService.d.ts +15 -0
- package/dist/sync/syncService.js +83 -18
- package/dist/sync/taskforceAgentSyncAuthorization.d.ts +16 -0
- package/dist/sync/taskforceAgentSyncAuthorization.js +20 -0
- package/dist/sync/v3/combinedFeedCapability.js +4 -0
- package/dist/sync/v3/durableInitiativeMutationRouter.js +18 -10
- package/dist/sync/v3/durableOperationReplay.d.ts +14 -0
- package/dist/sync/v3/durableOperationReplay.js +18 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +3 -0
- package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -1
- package/dist/sync/v3/durableTaskChecklistMutationRouter.js +58 -15
- package/dist/sync/v3/durableTaskCommentMutationRouter.js +3 -0
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +1 -1
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +10 -0
- package/dist/sync/v3/durableTaxonomyMutationRouter.js +5 -0
- package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.d.ts +18 -7
- package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.js +89 -23
- package/dist/sync/v3/durableWorkstreamMutationRouter.js +18 -10
- package/dist/sync/v3/durableWorkstreamTaskOrderMutationRouter.js +16 -5
- package/dist/sync/v3/localOutboxDispatchRuntime.js +2 -2
- package/dist/sync/v3/localOutboxRecoveryPreparationService.js +8 -2
- package/dist/sync/v3/localTaskChecklistOutboxHandler.js +16 -2
- package/dist/sync/v3/localTaskChecklistOutboxService.d.ts +4 -0
- package/dist/sync/v3/localTaskChecklistOutboxService.js +14 -1
- package/dist/sync/v3/localTaskCreateOutboxService.d.ts +3 -1
- package/dist/sync/v3/localTaskCreateOutboxService.js +6 -1
- package/dist/sync/v3/localTaskDeleteOutboxService.js +1 -0
- package/dist/sync/v3/localTaskLifecycleOutboxService.d.ts +2 -1
- package/dist/sync/v3/localTaskLifecycleOutboxService.js +5 -1
- package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -1
- package/dist/sync/v3/localTaskMetadataOutboxService.js +6 -2
- package/dist/sync/v3/localTaskStatusOutboxService.d.ts +10 -1
- package/dist/sync/v3/localTaskStatusOutboxService.js +238 -16
- package/dist/sync/v3/syncDurabilityStore.d.ts +36 -1
- package/dist/sync/v3/syncDurabilityStore.js +202 -8
- package/dist/sync/v3/taskChecklistMutationService.d.ts +11 -0
- package/dist/sync/v3/taskChecklistMutationService.js +44 -1
- package/dist/sync/v3/taskStatusMutationService.d.ts +29 -1
- package/dist/sync/v3/taskStatusMutationService.js +119 -3
- package/dist/sync/v3/workflowAssignmentSync.d.ts +5 -0
- package/dist/sync/v3/workflowAssignmentSync.js +27 -0
- package/dist/sync/v3/workflowRuntimeMutationService.d.ts +5 -0
- package/dist/sync/v3/workflowRuntimeMutationService.js +124 -71
- package/dist/sync/v3/workspaceSyncJournalReader.js +1 -1
- package/dist/sync/v3/workspaceSyncOperationRetentionService.d.ts +16 -0
- package/dist/sync/v3/workspaceSyncOperationRetentionService.js +83 -0
- package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +9 -2
- package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +25 -3
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +44 -32
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +9 -5
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +54 -38
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +70 -31
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +16 -0
- package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
- package/dist/sync/v3/workspaceSyncV3Feed.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3Feed.js +6 -1
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +49 -18
- package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +3 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +5 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +36 -2
- package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.d.ts +17 -0
- package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.js +64 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowRuntimeApply.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowRuntimeApply.js +50 -5
- package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.js +33 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.js +8 -0
- package/dist/sync/workspaceRepair.d.ts +5 -2
- package/dist/sync/workspaceRepair.js +161 -6
- package/dist/sync/workspaceSyncModel.d.ts +21 -0
- package/dist/sync/workspaceSyncModel.js +35 -7
- package/dist/sync/workspaceSyncState.d.ts +1 -0
- package/dist/sync/workspaceSyncV2SnapshotBuilder.d.ts +6 -0
- package/dist/sync/workspaceSyncV2SnapshotBuilder.js +5 -0
- package/dist/ui/assets/AiIdentityRosterCard-CDMPtnbC.js +1 -0
- package/dist/ui/assets/AiProfilesModule-Cww85C4E.js +1 -0
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-B68Wg-RV.js → AnnotatedAttachmentWorkspace-Dt9TKYSH.js} +1 -1
- package/dist/ui/assets/{AssetTraySortControl-C8Rztyal.js → AssetTraySortControl-CKgapnxu.js} +1 -1
- package/dist/ui/assets/{ContextAttachmentManager-Cj3c7X9y.js → ContextAttachmentManager-T-cEVcOZ.js} +2 -2
- package/dist/ui/assets/{DocumentWorkspace-B5uvzems.js → DocumentWorkspace-HD4MUjAZ.js} +1 -1
- package/dist/ui/assets/{EntityActivityTimeline-BVFvCB5R.js → EntityActivityTimeline-_V0zfMuh.js} +1 -1
- package/dist/ui/assets/PlanningModule-mTkBygsB.js +1 -0
- package/dist/ui/assets/{PlansPage-AY4cGWco.js → PlansPage-Btiq06VO.js} +1 -1
- package/dist/ui/assets/{TaskContextUpload-DZxTVesW.js → TaskContextUpload-C00NVUpn.js} +1 -1
- package/dist/ui/assets/TaskSettings-Cp-L-4xh.js +12 -0
- package/dist/ui/assets/TaskforceAgentsModule-Coq9-PUp.js +24 -0
- package/dist/ui/assets/TaskforceAgentsModule-b-8R25cJ.css +1 -0
- package/dist/ui/assets/{WorkflowManagerModule-DEr5di_r.js → WorkflowManagerModule-CuqRzMmM.js} +1 -1
- package/dist/ui/assets/index-BZ-hdZSk.css +1 -0
- package/dist/ui/assets/index-DSQINwt9.js +7 -0
- package/dist/ui/assets/{vendor-icons-D9Lpw-j4.js → vendor-icons-Bsq-mcEn.js} +1 -1
- package/dist/ui/branding/logos/letterhead_dark.png +0 -0
- package/dist/ui/branding/logos/letterhead_light.png +0 -0
- package/dist/ui/branding/logos/signature_dark.png +0 -0
- package/dist/ui/branding/logos/signature_light.png +0 -0
- package/dist/ui/index.html +3 -3
- package/dist/utils/aiProfileDefaultLogo.js +16 -48
- package/dist/utils/httpSetCookie.d.ts +1 -0
- package/dist/utils/httpSetCookie.js +4 -1
- package/dist/utils/localRuntimeUrl.d.ts +1 -0
- package/dist/utils/localRuntimeUrl.js +14 -0
- package/dist/utils/productLogoRegistry.d.ts +2 -0
- package/dist/utils/productLogoRegistry.js +36 -0
- package/dist/utils/syncStatusPresentation.d.ts +4 -0
- package/dist/utils/syncStatusPresentation.js +17 -0
- package/dist/utils/taskEvents.d.ts +2 -0
- package/dist/utils/workspaceSyncPresentation.d.ts +1 -1
- package/dist/utils/workspaceSyncPresentation.js +23 -17
- package/package.json +24 -4
- package/dist/ui/assets/AiIdentityRosterCard-BZM4aQnM.js +0 -1
- package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +0 -1
- package/dist/ui/assets/PlanningModule-B5DWQOGz.js +0 -1
- package/dist/ui/assets/TaskSettings-BeWAuyZj.js +0 -12
- package/dist/ui/assets/TaskforceAgentsModule-BifCYtjR.js +0 -21
- package/dist/ui/assets/TaskforceAgentsModule-D6IC0S7Q.css +0 -1
- package/dist/ui/assets/index-I5zhdtgt.js +0 -7
- 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,
|
|
21
|
-
return {
|
|
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
|
-
|
|
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
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
|
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
|
-
|
|
206
|
+
expiresAt,
|
|
207
|
+
revokedAt: null,
|
|
82
208
|
aiProfileId: options.aiProfileId || null,
|
|
83
209
|
tokenDigest: digestToken(token),
|
|
84
210
|
};
|
|
85
|
-
this.
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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(
|
|
296
|
+
return publicSession(storedSession(row));
|
|
105
297
|
}
|
|
106
298
|
revoke(id) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
193
|
-
this.
|
|
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.
|
|
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.
|
|
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
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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 (
|
|
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
|
|
955
|
-
|
|
956
|
-
:
|
|
957
|
-
|
|
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:
|
|
973
|
+
combinedFeedActivationEnabled: configuredCombined.activationReady,
|
|
964
974
|
combinedProjection: combined,
|
|
965
|
-
|
|
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;
|