@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
package/dist/mcp/runtime.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Server } from
|
|
2
|
-
import { StdioServerTransport } from
|
|
3
|
-
import { CallToolRequestSchema, ListResourceTemplatesRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
1
|
+
import { Server } from '@modelcontextprotocol/server';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
|
|
4
3
|
import * as fs from 'fs';
|
|
5
4
|
import * as path from 'path';
|
|
6
5
|
import { createHash, randomUUID } from 'node:crypto';
|
|
@@ -80,7 +79,7 @@ import { createDurableTaskChecklistMutationRouter, DurableTaskChecklistRouterInP
|
|
|
80
79
|
import { DurableTaskChecklistMutationError } from '../sync/v3/taskChecklistMutationService.js';
|
|
81
80
|
import { createDurableTaskAttachmentLinksMutationRouter, DurableTaskAttachmentLinksRouterInProgressError, } from '../sync/v3/durableTaskAttachmentLinksMutationRouter.js';
|
|
82
81
|
import { DurableTaskAttachmentLinksMutationError } from '../sync/v3/taskAttachmentLinksMutationService.js';
|
|
83
|
-
import { createDurableWorkflowRuntimeMutationRouter, resolveWorkflowRuntimeMutationCapability, } from '../sync/v3/durableWorkflowRuntimeMutationRouter.js';
|
|
82
|
+
import { areWorkflowRuntimeMutationsFenced, createDurableWorkflowRuntimeMutationRouter, resolveWorkflowRuntimeMutationCapability, } from '../sync/v3/durableWorkflowRuntimeMutationRouter.js';
|
|
84
83
|
import { serializeCanonicalPlanningAttachmentLinks } from '../sync/planningCanonicalFields.js';
|
|
85
84
|
import { buildCanonicalTaxonomyStateMutation, } from '../sync/v3/taxonomyStateMutation.js';
|
|
86
85
|
import { buildTaskDeepLink, buildTaskforceDeepLink, normalizeTaskforceApplicationBaseUrl, } from '../shared/taskDeepLinks.js';
|
|
@@ -120,7 +119,10 @@ class ToolProfileHiddenError extends Error {
|
|
|
120
119
|
suggestedTool;
|
|
121
120
|
constructor(name, activeProfile) {
|
|
122
121
|
const requiredProfiles = getMcpToolRequiredProfiles(name);
|
|
123
|
-
const
|
|
122
|
+
const configuredSuccessor = getMcpToolSuccessor(name);
|
|
123
|
+
const suggestedTool = configuredSuccessor && isMcpToolVisibleInProfile(configuredSuccessor.name, activeProfile)
|
|
124
|
+
? configuredSuccessor
|
|
125
|
+
: null;
|
|
124
126
|
const suffix = suggestedTool ? ` Use ${suggestedTool.name} instead.` : ` Request one of these profiles to use it: ${requiredProfiles.join(', ')}.`;
|
|
125
127
|
super(`Tool ${name} is not available in the ${activeProfile} MCP tool profile.${suffix}`);
|
|
126
128
|
this.activeProfile = activeProfile;
|
|
@@ -747,6 +749,9 @@ function createOwnedTaskforceMcpCore(projectRoot, tenantId, localDataOwnerPermit
|
|
|
747
749
|
},
|
|
748
750
|
});
|
|
749
751
|
}
|
|
752
|
+
export function createStatelessTaskforceMcpServer(options = {}, factory = createTaskforceMcpServer) {
|
|
753
|
+
return factory({ ...options, resourceSubscriptionMode: 'disabled' });
|
|
754
|
+
}
|
|
750
755
|
export function createTaskforceMcpServer(options = {}) {
|
|
751
756
|
// In dev (tsx), this module lives in src/mcp/.
|
|
752
757
|
// In prod, it lives in dist/mcp/.
|
|
@@ -754,6 +759,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
754
759
|
const PROJECT_NAME = path.basename(PROJECT_ROOT);
|
|
755
760
|
const logStartup = options.logStartup !== false;
|
|
756
761
|
const runtimeMode = options.runtimeMode === 'cloud' ? 'cloud' : 'local';
|
|
762
|
+
const modernProtocol = options.protocolEra === 'modern';
|
|
763
|
+
const supportsLegacyResourceSubscriptions = !modernProtocol
|
|
764
|
+
&& options.resourceSubscriptionMode === 'legacy-long-lived';
|
|
757
765
|
const applicationBaseUrl = normalizeTaskforceApplicationBaseUrl(options.applicationBaseUrl)
|
|
758
766
|
|| (runtimeMode === 'cloud'
|
|
759
767
|
? resolveCloudApplicationBaseUrl()
|
|
@@ -836,8 +844,6 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
836
844
|
};
|
|
837
845
|
const operationIdentityScope = options.operationIdentityScope
|
|
838
846
|
? {
|
|
839
|
-
generation: String(options.operationIdentityScope.generation || '').trim(),
|
|
840
|
-
sessionId: String(options.operationIdentityScope.sessionId || '').trim(),
|
|
841
847
|
connectionInstance: String(options.operationIdentityScope.connectionInstance || '').trim(),
|
|
842
848
|
}
|
|
843
849
|
: null;
|
|
@@ -845,7 +851,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
845
851
|
throw new Error('Shared MCP operation identity scope is incomplete.');
|
|
846
852
|
}
|
|
847
853
|
const runtimeRequestNamespace = operationIdentityScope
|
|
848
|
-
? fingerprintWorkspaceSyncPayload({ kind: 'shared-mcp-
|
|
854
|
+
? fingerprintWorkspaceSyncPayload({ kind: 'shared-mcp-process', ...operationIdentityScope })
|
|
849
855
|
: runtimeMode === 'cloud'
|
|
850
856
|
? String(options.auth?.requestId || '').trim() || randomUUID()
|
|
851
857
|
: randomUUID();
|
|
@@ -1204,8 +1210,8 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
1204
1210
|
}, {
|
|
1205
1211
|
capabilities: {
|
|
1206
1212
|
resources: {
|
|
1207
|
-
subscribe: true,
|
|
1208
|
-
listChanged: true,
|
|
1213
|
+
...(supportsLegacyResourceSubscriptions ? { subscribe: true } : {}),
|
|
1214
|
+
...(!modernProtocol ? { listChanged: true } : {}),
|
|
1209
1215
|
},
|
|
1210
1216
|
tools: {},
|
|
1211
1217
|
},
|
|
@@ -1881,6 +1887,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
1881
1887
|
} : {}),
|
|
1882
1888
|
title: task?.title || null,
|
|
1883
1889
|
status: task?.status || null,
|
|
1890
|
+
isArchived: Boolean(task?.isArchived),
|
|
1891
|
+
completedAt: task?.completedAt || null,
|
|
1892
|
+
canceledReason: task?.canceledReason || null,
|
|
1884
1893
|
category: task?.category || null,
|
|
1885
1894
|
type: task?.type || null,
|
|
1886
1895
|
priority: task?.priority ?? null,
|
|
@@ -2225,42 +2234,38 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
2225
2234
|
return null;
|
|
2226
2235
|
return resolved;
|
|
2227
2236
|
}
|
|
2228
|
-
function resolveFinishTaskReviewer(task) {
|
|
2237
|
+
function resolveFinishTaskReviewer(task, reviewer) {
|
|
2238
|
+
if (reviewer !== undefined) {
|
|
2239
|
+
const resolvedReviewer = resolveRuntimeTaskAssigneeInput(reviewer);
|
|
2240
|
+
const actor = resolvedReviewer
|
|
2241
|
+
? core.resolveWorkspaceActor(ACTIVE_WORKSPACE_ID, resolvedReviewer)
|
|
2242
|
+
: null;
|
|
2243
|
+
const eligible = actor?.kind === 'ai'
|
|
2244
|
+
? core.listAiProfiles(ACTIVE_WORKSPACE_ID).some((profile) => profile.id === actor.id)
|
|
2245
|
+
: core.listWorkspaceUsers(ACTIVE_WORKSPACE_ID).some((user) => (user.userId === actor?.id
|
|
2246
|
+
&& String(user.status || '').trim().toLowerCase() === 'active'
|
|
2247
|
+
&& user.disabled !== true));
|
|
2248
|
+
if (!actor || actor.meta?.unresolved === true || !eligible) {
|
|
2249
|
+
throw new McpPublicError('reviewer must identify an active human or AI assignee in the current workspace. Call list_assignees and retry with an assignee ID.', 'MCP_REVIEWER_INVALID');
|
|
2250
|
+
}
|
|
2251
|
+
return { assignee: actor.id, source: 'explicit' };
|
|
2252
|
+
}
|
|
2229
2253
|
const existingAssignee = String(task?.assignee || '').trim();
|
|
2230
2254
|
if (existingAssignee) {
|
|
2231
2255
|
const existingActor = core.resolveWorkspaceActor(ACTIVE_WORKSPACE_ID, existingAssignee);
|
|
2232
|
-
|
|
2256
|
+
const eligibleExistingHuman = existingActor?.kind === 'human'
|
|
2257
|
+
&& existingActor.meta?.unresolved !== true
|
|
2258
|
+
&& core.listWorkspaceUsers(ACTIVE_WORKSPACE_ID).some((user) => (user.userId === existingActor.id
|
|
2259
|
+
&& String(user.status || '').trim().toLowerCase() === 'active'
|
|
2260
|
+
&& user.disabled !== true));
|
|
2261
|
+
if (eligibleExistingHuman) {
|
|
2233
2262
|
return {
|
|
2234
2263
|
assignee: existingActor.id,
|
|
2235
2264
|
source: 'existing_human_owner',
|
|
2236
2265
|
};
|
|
2237
2266
|
}
|
|
2238
2267
|
}
|
|
2239
|
-
|
|
2240
|
-
const currentUser = core.listWorkspaceUsers(ACTIVE_WORKSPACE_ID)
|
|
2241
|
-
.find((user) => user.userId === auditActorUserId
|
|
2242
|
-
&& String(user.status || '').trim().toLowerCase() === 'active'
|
|
2243
|
-
&& user.disabled !== true);
|
|
2244
|
-
if (currentUser) {
|
|
2245
|
-
return { assignee: currentUser.userId, source: 'current_user' };
|
|
2246
|
-
}
|
|
2247
|
-
}
|
|
2248
|
-
const workspaceOwner = core.listWorkspaceUsers(ACTIVE_WORKSPACE_ID)
|
|
2249
|
-
.filter((user) => String(user.status || '').trim().toLowerCase() === 'active' && user.disabled !== true)
|
|
2250
|
-
.sort((left, right) => {
|
|
2251
|
-
const leftRank = left.role === 'owner' ? 0 : left.role === 'admin' ? 1 : 2;
|
|
2252
|
-
const rightRank = right.role === 'owner' ? 0 : right.role === 'admin' ? 1 : 2;
|
|
2253
|
-
if (leftRank !== rightRank)
|
|
2254
|
-
return leftRank - rightRank;
|
|
2255
|
-
return String(left.displayName || left.email || left.userId).localeCompare(String(right.displayName || right.email || right.userId), undefined, { sensitivity: 'base' });
|
|
2256
|
-
})[0];
|
|
2257
|
-
if (workspaceOwner && (workspaceOwner.role === 'owner' || workspaceOwner.role === 'admin')) {
|
|
2258
|
-
return {
|
|
2259
|
-
assignee: workspaceOwner.userId,
|
|
2260
|
-
source: 'workspace_owner',
|
|
2261
|
-
};
|
|
2262
|
-
}
|
|
2263
|
-
throw new McpPublicError('Could not resolve a human reviewer for review handoff. Resolve a current human user, set a human owner on the task, or ensure the workspace has an active owner/admin.', 'MCP_REVIEWER_REQUIRED');
|
|
2268
|
+
throw new McpPublicError('Review handoff requires an explicit reviewer when the task has no eligible existing human reviewer. Call list_assignees and retry finish_task with reviewer set to a human or AI assignee ID.', 'MCP_REVIEWER_REQUIRED');
|
|
2264
2269
|
}
|
|
2265
2270
|
function getActiveMcpActorRef() {
|
|
2266
2271
|
if (activeAiProfileId)
|
|
@@ -2301,13 +2306,19 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
2301
2306
|
}).task;
|
|
2302
2307
|
}
|
|
2303
2308
|
if (!useStatusBoundary) {
|
|
2304
|
-
return core.updateTask(input.task.id, input.updates, ACTIVE_WORKSPACE_ID, {
|
|
2309
|
+
return core.updateTask(input.task.id, input.updates, ACTIVE_WORKSPACE_ID, {
|
|
2310
|
+
actorRef: getActiveMcpActorRef(),
|
|
2311
|
+
...(input.deferNotifications ? { persistBackup: false, emitRealtime: false } : {}),
|
|
2312
|
+
});
|
|
2305
2313
|
}
|
|
2306
2314
|
const unsupported = Object.keys(input.updates).filter((field) => (!durableStatusControlFields.has(field) && !durableTaskMetadataFieldNames.has(field)));
|
|
2307
2315
|
if (unsupported.length > 0) {
|
|
2308
2316
|
throw new TaskforceRuleError(`Combined durable task status update contains unsupported fields: ${unsupported.sort().join(', ')}.`, 400, 'TASK_STATUS_INVALID_PAYLOAD');
|
|
2309
2317
|
}
|
|
2310
2318
|
const status = String(hasStatus ? input.updates.status : input.task.status || 'task').trim();
|
|
2319
|
+
if (status === 'review' && String(input.task.status || '').trim() !== 'review' && !input.reviewHandoff) {
|
|
2320
|
+
throw new McpPublicError('Moving a task to review requires finish_task with a nonblank evidence comment.', 'TASK_REVIEW_HANDOFF_REQUIRED', 400);
|
|
2321
|
+
}
|
|
2311
2322
|
const metadataPatch = selectDurableTaskMetadataPatch(input.updates);
|
|
2312
2323
|
delete metadataPatch.assignee;
|
|
2313
2324
|
const assigneeIntent = input.assigneeIntent || (Object.prototype.hasOwnProperty.call(input.updates, 'assignee')
|
|
@@ -2322,10 +2333,73 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
2322
2333
|
: null;
|
|
2323
2334
|
return durableTaskMutationRouter.setStatus({
|
|
2324
2335
|
taskId: input.task.id,
|
|
2325
|
-
payload: {
|
|
2336
|
+
payload: {
|
|
2337
|
+
status,
|
|
2338
|
+
assigneeIntent,
|
|
2339
|
+
canceledReason,
|
|
2340
|
+
metadataPatch,
|
|
2341
|
+
...(input.reviewHandoff ? { reviewHandoff: input.reviewHandoff } : {}),
|
|
2342
|
+
},
|
|
2326
2343
|
actorRef: getActiveMcpActorRef(),
|
|
2327
2344
|
}).task;
|
|
2328
2345
|
}
|
|
2346
|
+
function mutateTaskReviewHandoffThroughBoundary(input) {
|
|
2347
|
+
const validation = validateStructuredCommentForAdd(input.handoffComment);
|
|
2348
|
+
if (!validation.ok)
|
|
2349
|
+
throw new McpPublicError(validation.message);
|
|
2350
|
+
const actorRef = getActiveMcpActorRef();
|
|
2351
|
+
const operationId = requireStableMcpRequestId('operation', `review-handoff-comment:${input.task.id}`);
|
|
2352
|
+
const commentId = requireStableMcpRequestId('comment', `review-handoff:${input.task.id}`);
|
|
2353
|
+
const comment = {
|
|
2354
|
+
id: commentId,
|
|
2355
|
+
author: actorRef,
|
|
2356
|
+
submittedAuthor: actorRef,
|
|
2357
|
+
text: input.handoffComment,
|
|
2358
|
+
};
|
|
2359
|
+
if (durableTaskMutationRouter.enabled) {
|
|
2360
|
+
return mutateTaskThroughStatusBoundary({
|
|
2361
|
+
task: input.task,
|
|
2362
|
+
updates: input.updates,
|
|
2363
|
+
assigneeIntent: input.assigneeIntent,
|
|
2364
|
+
reviewHandoff: { comment },
|
|
2365
|
+
});
|
|
2366
|
+
}
|
|
2367
|
+
let updated;
|
|
2368
|
+
try {
|
|
2369
|
+
updated = core.getDatabaseAdapter().transaction(() => {
|
|
2370
|
+
mutateTaskThroughStatusBoundary({
|
|
2371
|
+
task: input.task,
|
|
2372
|
+
updates: input.updates,
|
|
2373
|
+
assigneeIntent: input.assigneeIntent,
|
|
2374
|
+
deferNotifications: true,
|
|
2375
|
+
});
|
|
2376
|
+
const durableRouter = getDurableTaskCommentMutationRouter(actorRef, operationId);
|
|
2377
|
+
const task = durableRouter.enabled
|
|
2378
|
+
? durableRouter.append({
|
|
2379
|
+
taskId: input.task.id,
|
|
2380
|
+
comment: { ...comment, timestamp: new Date().toISOString() },
|
|
2381
|
+
}).task
|
|
2382
|
+
: core.addComment(input.task.id, input.handoffComment, actorRef, ACTIVE_WORKSPACE_ID, {
|
|
2383
|
+
actorRef,
|
|
2384
|
+
persistBackup: false,
|
|
2385
|
+
emitRealtime: false,
|
|
2386
|
+
commentId,
|
|
2387
|
+
});
|
|
2388
|
+
if (!task)
|
|
2389
|
+
throw new Error(`Task ${input.task.id} not found`);
|
|
2390
|
+
return task;
|
|
2391
|
+
})();
|
|
2392
|
+
}
|
|
2393
|
+
catch (error) {
|
|
2394
|
+
try {
|
|
2395
|
+
core.notifyDurableTaskMetadataCommitted(ACTIVE_WORKSPACE_ID, input.task.id);
|
|
2396
|
+
}
|
|
2397
|
+
catch { /* Preserve the original handoff failure. */ }
|
|
2398
|
+
throw error;
|
|
2399
|
+
}
|
|
2400
|
+
core.notifyDurableTaskMetadataCommitted(ACTIVE_WORKSPACE_ID, input.task.id);
|
|
2401
|
+
return updated;
|
|
2402
|
+
}
|
|
2329
2403
|
function mutateTaskLifecycleThroughBoundary(input) {
|
|
2330
2404
|
if (!durableTaskMutationRouter.enabled)
|
|
2331
2405
|
return input.legacy();
|
|
@@ -3706,7 +3780,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3706
3780
|
const hydratedWorkstream = core.getWorkstream(workstream.id, ACTIVE_WORKSPACE_ID) || workstream;
|
|
3707
3781
|
return { id: hydratedWorkstream.id, workstream: hydratedWorkstream };
|
|
3708
3782
|
}
|
|
3709
|
-
server.setRequestHandler(
|
|
3783
|
+
server.setRequestHandler('resources/list', async () => {
|
|
3710
3784
|
const resources = [
|
|
3711
3785
|
{
|
|
3712
3786
|
uri: RESOURCE_CONFIG_URI,
|
|
@@ -3753,7 +3827,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3753
3827
|
resources,
|
|
3754
3828
|
};
|
|
3755
3829
|
});
|
|
3756
|
-
server.setRequestHandler(
|
|
3830
|
+
server.setRequestHandler('resources/templates/list', async () => {
|
|
3757
3831
|
if (!hasPermission(RESOURCE_PERMISSIONS.task)) {
|
|
3758
3832
|
return { resourceTemplates: [] };
|
|
3759
3833
|
}
|
|
@@ -3785,7 +3859,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3785
3859
|
],
|
|
3786
3860
|
};
|
|
3787
3861
|
});
|
|
3788
|
-
server.setRequestHandler(
|
|
3862
|
+
server.setRequestHandler('resources/read', async (request) => {
|
|
3789
3863
|
const uri = request.params.uri;
|
|
3790
3864
|
assertResourcePermission(uri);
|
|
3791
3865
|
if (uri === RESOURCE_CONFIG_URI) {
|
|
@@ -3891,24 +3965,26 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3891
3965
|
}
|
|
3892
3966
|
throw new Error(`Unknown resource URI: ${uri}`);
|
|
3893
3967
|
});
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3968
|
+
if (supportsLegacyResourceSubscriptions) {
|
|
3969
|
+
server.setRequestHandler('resources/subscribe', async (request) => {
|
|
3970
|
+
const uri = request.params.uri;
|
|
3971
|
+
if (!isSupportedResourceUri(uri)) {
|
|
3972
|
+
throw new Error(`Unsupported resource URI for subscribe: ${uri}`);
|
|
3973
|
+
}
|
|
3974
|
+
assertResourcePermission(uri);
|
|
3975
|
+
resourceSubscriptions.add(uri);
|
|
3976
|
+
return {};
|
|
3977
|
+
});
|
|
3978
|
+
server.setRequestHandler('resources/unsubscribe', async (request) => {
|
|
3979
|
+
const uri = request.params.uri;
|
|
3980
|
+
if (!isSupportedResourceUri(uri)) {
|
|
3981
|
+
throw new Error(`Unsupported resource URI for unsubscribe: ${uri}`);
|
|
3982
|
+
}
|
|
3983
|
+
assertResourcePermission(uri);
|
|
3984
|
+
resourceSubscriptions.delete(uri);
|
|
3985
|
+
return {};
|
|
3986
|
+
});
|
|
3987
|
+
}
|
|
3912
3988
|
/**
|
|
3913
3989
|
* Tool Definitions
|
|
3914
3990
|
*/
|
|
@@ -4024,16 +4100,19 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
4024
4100
|
const tool = registeredTools.find((candidate) => candidate.name === name);
|
|
4025
4101
|
return tool ? materializeToolDescriptor(tool, buildToolDescriptorContext()) : null;
|
|
4026
4102
|
};
|
|
4027
|
-
|
|
4103
|
+
const listTools = async () => {
|
|
4028
4104
|
const context = buildToolDescriptorContext();
|
|
4029
4105
|
const tools = registeredTools
|
|
4030
4106
|
.map((tool) => materializeToolDescriptor(tool, context))
|
|
4031
4107
|
.filter((tool) => (isMcpToolVisibleInProfile(tool.name, activeToolProfile)
|
|
4032
4108
|
&& hasPermission(TOOL_PERMISSIONS[tool.name])));
|
|
4033
4109
|
return {
|
|
4034
|
-
|
|
4110
|
+
// Descriptors are validated by Taskforce's JSON Schema contract before
|
|
4111
|
+
// registration; v2 narrows the equivalent recursive JSON value type.
|
|
4112
|
+
tools: tools,
|
|
4035
4113
|
};
|
|
4036
|
-
}
|
|
4114
|
+
};
|
|
4115
|
+
server.setRequestHandler('tools/list', listTools);
|
|
4037
4116
|
const resolvePlanningAttachmentTarget = (targetType, inputId) => {
|
|
4038
4117
|
if (targetType === 'initiative') {
|
|
4039
4118
|
const { id, initiative } = resolveInitiativeByIdentifierOrThrow(inputId);
|
|
@@ -4953,7 +5032,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
4953
5032
|
const taskLifecycleCommandService = createTaskLifecycleCommandService({
|
|
4954
5033
|
formatTaskIdentifier,
|
|
4955
5034
|
resolveAssigneeLabel: (assignee) => core.resolveWorkspaceActor(ACTIVE_WORKSPACE_ID, assignee)?.label || assignee,
|
|
4956
|
-
setStatus: (input) =>
|
|
5035
|
+
setStatus: (input) => input.handoffComment
|
|
5036
|
+
? mutateTaskReviewHandoffThroughBoundary(input)
|
|
5037
|
+
: mutateTaskThroughStatusBoundary(input),
|
|
4957
5038
|
mutateLifecycle: (input) => mutateTaskLifecycleThroughBoundary({
|
|
4958
5039
|
taskId: input.taskId,
|
|
4959
5040
|
mutationKind: input.mutationKind,
|
|
@@ -4973,7 +5054,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
4973
5054
|
});
|
|
4974
5055
|
},
|
|
4975
5056
|
}),
|
|
4976
|
-
resolveReviewer: (task) => resolveFinishTaskReviewer(task),
|
|
5057
|
+
resolveReviewer: (task, reviewer) => resolveFinishTaskReviewer(task, reviewer),
|
|
4977
5058
|
});
|
|
4978
5059
|
const planningCommandPreparationService = new PlanningCommandPreparationService({
|
|
4979
5060
|
resolveOwner: resolvePlanningOwnerInput,
|
|
@@ -4986,12 +5067,17 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
4986
5067
|
listItems: (taskId) => core.listChecklistItems(taskId, ACTIVE_WORKSPACE_ID),
|
|
4987
5068
|
createId: (scope, key) => requireStableMcpRequestId(scope, key),
|
|
4988
5069
|
now: () => new Date().toISOString(),
|
|
4989
|
-
replace: ({ taskId, items, operationId }) => {
|
|
5070
|
+
replace: ({ taskId, items, operationId, expectedDetailRevision, requireDurableIdempotency, itemUpdateIntent, }) => {
|
|
4990
5071
|
const actorRef = getActiveMcpActorRef();
|
|
4991
5072
|
const durableRouter = getDurableTaskChecklistMutationRouter(actorRef, operationId);
|
|
5073
|
+
if (requireDurableIdempotency) {
|
|
5074
|
+
requireDurableExplicitIdempotency(durableRouter.enabled, 'task checklist');
|
|
5075
|
+
}
|
|
4992
5076
|
return durableRouter.enabled
|
|
4993
|
-
? durableRouter.replace({ taskId, items }).task
|
|
4994
|
-
:
|
|
5077
|
+
? durableRouter.replace({ taskId, items, expectedDetailRevision, itemUpdateIntent }).task
|
|
5078
|
+
: expectedDetailRevision
|
|
5079
|
+
? core.updateTaskIfDetailRevisionMatches(taskId, expectedDetailRevision, { checklistItems: items }, ACTIVE_WORKSPACE_ID, { actorRef })
|
|
5080
|
+
: core.updateTask(taskId, { checklistItems: items }, ACTIVE_WORKSPACE_ID, { actorRef });
|
|
4995
5081
|
},
|
|
4996
5082
|
});
|
|
4997
5083
|
const annotatedAttachmentCommandService = createAnnotatedAttachmentCommandService({
|
|
@@ -5014,7 +5100,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5014
5100
|
}
|
|
5015
5101
|
function rethrowChecklistCommandError(error) {
|
|
5016
5102
|
if (error instanceof TaskChecklistCommandError) {
|
|
5017
|
-
if (error.code === 'TASK_NOT_FOUND') {
|
|
5103
|
+
if (error.code === 'TASK_NOT_FOUND' || error.code === 'TASK_CHECKLIST_ITEM_NOT_FOUND') {
|
|
5018
5104
|
throw new McpPublicError(error.message, 'MCP_NOT_FOUND', error.statusCode);
|
|
5019
5105
|
}
|
|
5020
5106
|
throw new McpPublicError(error.message);
|
|
@@ -5247,6 +5333,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5247
5333
|
const avatarSuggestion = resolved.created
|
|
5248
5334
|
&& !configuredClientBlocksGeneration
|
|
5249
5335
|
&& isAiProfileAvatarGenerationEligible(resolved.profile)
|
|
5336
|
+
&& isMcpToolVisibleInProfile('generate_profile_avatar', activeToolProfile)
|
|
5250
5337
|
? {
|
|
5251
5338
|
avatarSuggestion: {
|
|
5252
5339
|
nextTool: 'generate_profile_avatar',
|
|
@@ -5455,6 +5542,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5455
5542
|
requiresCommentEvidence: step.requiresCommentEvidence,
|
|
5456
5543
|
} : {}),
|
|
5457
5544
|
}));
|
|
5545
|
+
const currentStep = assignment.execution.status === 'running'
|
|
5546
|
+
? assignment.steps.find((step) => step.id === assignment.execution.currentStepId)
|
|
5547
|
+
: undefined;
|
|
5458
5548
|
return {
|
|
5459
5549
|
content: [{ type: 'text', text: JSON.stringify({
|
|
5460
5550
|
task: withTaskUrl({ id: task.id, referenceLabel: formatTaskIdentifier(task), title: task.title }),
|
|
@@ -5466,11 +5556,23 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5466
5556
|
currentStepId: assignment.execution.currentStepId || null,
|
|
5467
5557
|
steps,
|
|
5468
5558
|
},
|
|
5559
|
+
completionCall: currentStep ? {
|
|
5560
|
+
tool: 'complete_workflow_step',
|
|
5561
|
+
arguments: {
|
|
5562
|
+
taskId,
|
|
5563
|
+
executionId: assignment.execution.id,
|
|
5564
|
+
stepId: currentStep.id,
|
|
5565
|
+
},
|
|
5566
|
+
} : null,
|
|
5469
5567
|
}, null, 2) }],
|
|
5470
5568
|
};
|
|
5471
5569
|
}
|
|
5472
5570
|
case "complete_workflow_step": {
|
|
5473
5571
|
const { taskId, executionId, stepId, evidenceCommentId } = args;
|
|
5572
|
+
const normalizedEvidenceCommentId = evidenceCommentId == null ? undefined : evidenceCommentId;
|
|
5573
|
+
if (areWorkflowRuntimeMutationsFenced()) {
|
|
5574
|
+
throw new McpPublicError('Workflow execution changes are temporarily paused.', 'WORKFLOW_RUNTIME_MUTATIONS_FENCED', 503);
|
|
5575
|
+
}
|
|
5474
5576
|
const { task } = resolveTaskByIdentifierOrThrow(taskId);
|
|
5475
5577
|
ensureResolvedProfileForSessionBootstrap();
|
|
5476
5578
|
const agentProfileId = String(activeAiProfileId || '').trim();
|
|
@@ -5483,7 +5585,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5483
5585
|
throw new McpPublicError('The workflow execution does not belong to this task.', 'WORKFLOW_TASK_MISMATCH', 409);
|
|
5484
5586
|
}
|
|
5485
5587
|
const idempotencyKey = `agent-step-${createHash('sha256')
|
|
5486
|
-
.update(`${executionId}:${stepId}:${agentProfileId}:${String(
|
|
5588
|
+
.update(`${executionId}:${stepId}:${agentProfileId}:${String(normalizedEvidenceCommentId || '')}`)
|
|
5487
5589
|
.digest('hex')
|
|
5488
5590
|
.slice(0, 32)}`;
|
|
5489
5591
|
let result;
|
|
@@ -5505,7 +5607,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5505
5607
|
}).completeStep({
|
|
5506
5608
|
executionId,
|
|
5507
5609
|
expectedStepId: stepId,
|
|
5508
|
-
evidenceCommentId,
|
|
5610
|
+
evidenceCommentId: normalizedEvidenceCommentId,
|
|
5509
5611
|
})
|
|
5510
5612
|
: executionService.completeCurrentStep({
|
|
5511
5613
|
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
@@ -5513,7 +5615,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5513
5615
|
actorId: agentProfileId,
|
|
5514
5616
|
actorType: 'agent',
|
|
5515
5617
|
expectedStepId: stepId,
|
|
5516
|
-
evidenceCommentId,
|
|
5618
|
+
evidenceCommentId: normalizedEvidenceCommentId,
|
|
5517
5619
|
idempotencyKey,
|
|
5518
5620
|
});
|
|
5519
5621
|
}
|
|
@@ -6170,12 +6272,14 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
6170
6272
|
const { taskId } = args;
|
|
6171
6273
|
const { id: resolvedTaskId } = resolveTaskByIdentifierOrThrow(taskId);
|
|
6172
6274
|
const checklist = core.listChecklistItems(resolvedTaskId, ACTIVE_WORKSPACE_ID);
|
|
6275
|
+
const detailRevision = core.getTaskDetailRevision(resolvedTaskId, ACTIVE_WORKSPACE_ID);
|
|
6173
6276
|
return {
|
|
6174
6277
|
content: [{
|
|
6175
6278
|
type: "text",
|
|
6176
6279
|
text: JSON.stringify({
|
|
6177
6280
|
taskId: resolvedTaskId,
|
|
6178
6281
|
...(buildTaskUrl({ id: resolvedTaskId }) ? { url: buildTaskUrl({ id: resolvedTaskId }) } : {}),
|
|
6282
|
+
detailRevision,
|
|
6179
6283
|
items: checklist,
|
|
6180
6284
|
}, null, 2),
|
|
6181
6285
|
}],
|
|
@@ -6245,6 +6349,49 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
6245
6349
|
}],
|
|
6246
6350
|
};
|
|
6247
6351
|
}
|
|
6352
|
+
case "update_task_checklist_item": {
|
|
6353
|
+
const { taskId, itemId, text, done, order, expectedDetailRevision, idempotencyKey: rawIdempotencyKey, } = args;
|
|
6354
|
+
const idempotencyKey = normalizeExplicitIdempotencyKey(rawIdempotencyKey);
|
|
6355
|
+
const operationId = idempotencyKey
|
|
6356
|
+
? stableExplicitMutationId('operation', 'update_task_checklist_item', idempotencyKey)
|
|
6357
|
+
: requireStableMcpRequestId('operation', 'task-checklist-update');
|
|
6358
|
+
let result;
|
|
6359
|
+
try {
|
|
6360
|
+
result = taskChecklistCommandService.update({
|
|
6361
|
+
taskId,
|
|
6362
|
+
itemId,
|
|
6363
|
+
text,
|
|
6364
|
+
done,
|
|
6365
|
+
order,
|
|
6366
|
+
expectedDetailRevision,
|
|
6367
|
+
operationId,
|
|
6368
|
+
requireDurableIdempotency: Boolean(idempotencyKey),
|
|
6369
|
+
});
|
|
6370
|
+
}
|
|
6371
|
+
catch (error) {
|
|
6372
|
+
rethrowChecklistCommandError(error);
|
|
6373
|
+
}
|
|
6374
|
+
const detailRevision = core.getTaskDetailRevision(result.taskId, ACTIVE_WORKSPACE_ID);
|
|
6375
|
+
recordMcpWriteAudit('update_task_checklist_item', {
|
|
6376
|
+
taskId: result.taskId,
|
|
6377
|
+
itemId: result.item.id,
|
|
6378
|
+
});
|
|
6379
|
+
await notifyResourceMutation({
|
|
6380
|
+
includeTasks: true,
|
|
6381
|
+
taskIds: [result.taskId],
|
|
6382
|
+
});
|
|
6383
|
+
return {
|
|
6384
|
+
content: [{
|
|
6385
|
+
type: "text",
|
|
6386
|
+
text: JSON.stringify({
|
|
6387
|
+
taskId: result.taskId,
|
|
6388
|
+
...(buildTaskUrl({ id: result.taskId }) ? { url: buildTaskUrl({ id: result.taskId }) } : {}),
|
|
6389
|
+
detailRevision,
|
|
6390
|
+
item: result.item,
|
|
6391
|
+
}, null, 2),
|
|
6392
|
+
}],
|
|
6393
|
+
};
|
|
6394
|
+
}
|
|
6248
6395
|
case "get_task_attachments": {
|
|
6249
6396
|
const { id, taskId, attachmentId } = args;
|
|
6250
6397
|
const taskIdentifier = taskId ?? id;
|
|
@@ -6978,14 +7125,40 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
6978
7125
|
};
|
|
6979
7126
|
}
|
|
6980
7127
|
case "review_document": {
|
|
6981
|
-
const { id, documentId, sessionId, title, comments, prompt } = args;
|
|
7128
|
+
const { id, documentId, sessionId, title, comments, prompt, parentCommentId, threadCommentId, threadStatus, } = args;
|
|
6982
7129
|
const asset = resolveDocumentAssetByIdentifierOrThrow(documentId ?? id);
|
|
6983
7130
|
const normalizedComments = Array.isArray(comments)
|
|
6984
7131
|
? comments
|
|
6985
7132
|
: (typeof prompt === 'string' && prompt.trim()
|
|
6986
7133
|
? [{ body: prompt.trim() }]
|
|
6987
7134
|
: []);
|
|
6988
|
-
|
|
7135
|
+
const normalizedSessionId = typeof sessionId === 'string' ? sessionId.trim() : '';
|
|
7136
|
+
const normalizedParentCommentId = typeof parentCommentId === 'string' ? parentCommentId.trim() : '';
|
|
7137
|
+
const normalizedThreadCommentId = typeof threadCommentId === 'string' ? threadCommentId.trim() : '';
|
|
7138
|
+
const hasThreadStatus = threadStatus !== undefined;
|
|
7139
|
+
const hasThreadUpdate = Boolean(normalizedThreadCommentId) || hasThreadStatus;
|
|
7140
|
+
const hasCommentsArgument = Object.prototype.hasOwnProperty.call(args, 'comments');
|
|
7141
|
+
const hasPromptArgument = Object.prototype.hasOwnProperty.call(args, 'prompt');
|
|
7142
|
+
const hasTitleArgument = Object.prototype.hasOwnProperty.call(args, 'title');
|
|
7143
|
+
if (hasThreadUpdate && (!normalizedThreadCommentId || (threadStatus !== 'open' && threadStatus !== 'resolved'))) {
|
|
7144
|
+
throw new McpPublicError('threadCommentId and threadStatus are required together');
|
|
7145
|
+
}
|
|
7146
|
+
if ((normalizedParentCommentId || hasThreadUpdate) && !normalizedSessionId) {
|
|
7147
|
+
throw new McpPublicError('sessionId is required for reply and thread-status updates');
|
|
7148
|
+
}
|
|
7149
|
+
if (hasThreadUpdate && (normalizedParentCommentId || hasCommentsArgument || hasPromptArgument || hasTitleArgument)) {
|
|
7150
|
+
throw new McpPublicError('Thread-status updates cannot be combined with comments, replies, or a session title');
|
|
7151
|
+
}
|
|
7152
|
+
if (normalizedParentCommentId && hasTitleArgument) {
|
|
7153
|
+
throw new McpPublicError('Replies cannot set a session title');
|
|
7154
|
+
}
|
|
7155
|
+
if (hasCommentsArgument && hasPromptArgument) {
|
|
7156
|
+
throw new McpPublicError('comments and prompt cannot be combined');
|
|
7157
|
+
}
|
|
7158
|
+
if (normalizedParentCommentId && normalizedComments.length !== 1) {
|
|
7159
|
+
throw new McpPublicError('Replies require exactly one comment or prompt');
|
|
7160
|
+
}
|
|
7161
|
+
if (!hasThreadUpdate && normalizedComments.length === 0) {
|
|
6989
7162
|
throw new McpPublicError('comments array is required');
|
|
6990
7163
|
}
|
|
6991
7164
|
for (const comment of normalizedComments) {
|
|
@@ -6997,13 +7170,115 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
6997
7170
|
throw new McpPublicError(anchorError);
|
|
6998
7171
|
}
|
|
6999
7172
|
}
|
|
7173
|
+
if (normalizedParentCommentId && normalizedComments[0]?.anchor !== undefined && normalizedComments[0]?.anchor !== null) {
|
|
7174
|
+
throw new McpPublicError('Replies cannot have anchors');
|
|
7175
|
+
}
|
|
7176
|
+
if (hasThreadUpdate) {
|
|
7177
|
+
const existingSession = core.getDocumentReviewSession({
|
|
7178
|
+
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
7179
|
+
sessionId: normalizedSessionId,
|
|
7180
|
+
});
|
|
7181
|
+
if (!existingSession) {
|
|
7182
|
+
throw new McpPublicError(`Document review session ${normalizedSessionId} not found.`, 'MCP_NOT_FOUND', 404);
|
|
7183
|
+
}
|
|
7184
|
+
if (existingSession.assetId !== asset.assetId) {
|
|
7185
|
+
throw new McpPublicError(`Document review session ${normalizedSessionId} is not linked to document ${getDocumentReferenceLabel(asset) || asset.assetId}.`, 'MCP_ATTACHMENT_CONFLICT', 409);
|
|
7186
|
+
}
|
|
7187
|
+
const updatedSession = core.updateDocumentReviewThreadStatus({
|
|
7188
|
+
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
7189
|
+
sessionId: normalizedSessionId,
|
|
7190
|
+
commentId: normalizedThreadCommentId,
|
|
7191
|
+
status: threadStatus,
|
|
7192
|
+
actorId: getActiveMcpActorRef(),
|
|
7193
|
+
});
|
|
7194
|
+
const updatedThread = updatedSession.comments.find((entry) => entry.id === normalizedThreadCommentId) || null;
|
|
7195
|
+
const sessionSummary = buildDocumentReviewSessionSummary(updatedSession);
|
|
7196
|
+
recordMcpWriteAudit('review_document', {
|
|
7197
|
+
documentAssetId: asset.assetId,
|
|
7198
|
+
sessionId: updatedSession.id,
|
|
7199
|
+
sessionAction: 'reused',
|
|
7200
|
+
threadCommentId: normalizedThreadCommentId,
|
|
7201
|
+
threadStatus,
|
|
7202
|
+
});
|
|
7203
|
+
return {
|
|
7204
|
+
content: [{
|
|
7205
|
+
type: 'text',
|
|
7206
|
+
text: JSON.stringify({
|
|
7207
|
+
document: {
|
|
7208
|
+
assetId: asset.assetId,
|
|
7209
|
+
referenceLabel: getDocumentReferenceLabel(asset),
|
|
7210
|
+
},
|
|
7211
|
+
sessionId: updatedSession.id,
|
|
7212
|
+
sessionAction: 'reused',
|
|
7213
|
+
postedCommentIds: [],
|
|
7214
|
+
commentCount: 0,
|
|
7215
|
+
thread: buildCompactDocumentReviewComment(updatedThread),
|
|
7216
|
+
unresolvedThreadCount: sessionSummary.unresolvedThreadCount,
|
|
7217
|
+
nextTool: 'get_document_reviews',
|
|
7218
|
+
suggestedArgs: {
|
|
7219
|
+
documentId: getDocumentReferenceLabel(asset) || asset.assetId,
|
|
7220
|
+
sessionId: updatedSession.id,
|
|
7221
|
+
},
|
|
7222
|
+
}, null, 2),
|
|
7223
|
+
}],
|
|
7224
|
+
};
|
|
7225
|
+
}
|
|
7226
|
+
if (normalizedParentCommentId) {
|
|
7227
|
+
const existingSession = core.getDocumentReviewSession({
|
|
7228
|
+
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
7229
|
+
sessionId: normalizedSessionId,
|
|
7230
|
+
});
|
|
7231
|
+
if (!existingSession) {
|
|
7232
|
+
throw new McpPublicError(`Document review session ${normalizedSessionId} not found.`, 'MCP_NOT_FOUND', 404);
|
|
7233
|
+
}
|
|
7234
|
+
if (existingSession.assetId !== asset.assetId) {
|
|
7235
|
+
throw new McpPublicError(`Document review session ${normalizedSessionId} is not linked to document ${getDocumentReferenceLabel(asset) || asset.assetId}.`, 'MCP_ATTACHMENT_CONFLICT', 409);
|
|
7236
|
+
}
|
|
7237
|
+
const repliedSession = core.addDocumentReviewReply({
|
|
7238
|
+
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
7239
|
+
sessionId: normalizedSessionId,
|
|
7240
|
+
parentCommentId: normalizedParentCommentId,
|
|
7241
|
+
body: normalizedComments[0].body,
|
|
7242
|
+
actorId: getActiveMcpActorRef(),
|
|
7243
|
+
});
|
|
7244
|
+
const postedReply = repliedSession.comments.at(-1) || null;
|
|
7245
|
+
recordMcpWriteAudit('review_document', {
|
|
7246
|
+
documentAssetId: asset.assetId,
|
|
7247
|
+
sessionId: repliedSession.id,
|
|
7248
|
+
sessionAction: 'reused',
|
|
7249
|
+
parentCommentId: normalizedParentCommentId,
|
|
7250
|
+
commentCount: 1,
|
|
7251
|
+
});
|
|
7252
|
+
return {
|
|
7253
|
+
content: [{
|
|
7254
|
+
type: 'text',
|
|
7255
|
+
text: JSON.stringify({
|
|
7256
|
+
document: {
|
|
7257
|
+
assetId: asset.assetId,
|
|
7258
|
+
referenceLabel: getDocumentReferenceLabel(asset),
|
|
7259
|
+
},
|
|
7260
|
+
sessionId: repliedSession.id,
|
|
7261
|
+
sessionAction: 'reused',
|
|
7262
|
+
postedCommentIds: postedReply ? [postedReply.id] : [],
|
|
7263
|
+
commentCount: postedReply ? 1 : 0,
|
|
7264
|
+
reply: buildCompactDocumentReviewComment(postedReply),
|
|
7265
|
+
nextTool: 'get_document_reviews',
|
|
7266
|
+
suggestedArgs: {
|
|
7267
|
+
documentId: getDocumentReferenceLabel(asset) || asset.assetId,
|
|
7268
|
+
sessionId: repliedSession.id,
|
|
7269
|
+
},
|
|
7270
|
+
}, null, 2),
|
|
7271
|
+
}],
|
|
7272
|
+
};
|
|
7273
|
+
}
|
|
7000
7274
|
let commandResult;
|
|
7001
7275
|
try {
|
|
7002
7276
|
commandResult = documentReviewCommandService.review({
|
|
7003
7277
|
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
7004
7278
|
assetId: asset.assetId,
|
|
7279
|
+
documentVersion: asset.version,
|
|
7005
7280
|
documentLabel: getDocumentReferenceLabel(asset) || asset.assetId,
|
|
7006
|
-
sessionId:
|
|
7281
|
+
sessionId: normalizedSessionId || null,
|
|
7007
7282
|
title: typeof title === 'string' ? title : null,
|
|
7008
7283
|
comments: normalizedComments,
|
|
7009
7284
|
actorId: getActiveMcpActorRef(),
|
|
@@ -7029,6 +7304,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7029
7304
|
},
|
|
7030
7305
|
sessionId: currentSession.id,
|
|
7031
7306
|
sessionAction,
|
|
7307
|
+
documentVersion: currentSession.documentVersion,
|
|
7032
7308
|
postedCommentIds,
|
|
7033
7309
|
commentCount: postedCommentIds.length,
|
|
7034
7310
|
nextTool: 'get_document_reviews',
|
|
@@ -7353,13 +7629,6 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7353
7629
|
actorRef: getActiveMcpActorRef(),
|
|
7354
7630
|
provisionalLocalReference: shouldUseProvisionalTaskReferences(runtimeMode)
|
|
7355
7631
|
}), replayed: false };
|
|
7356
|
-
if ('operationId' in task) {
|
|
7357
|
-
options.onOperationAccepted?.({
|
|
7358
|
-
operationId: task.operationId,
|
|
7359
|
-
mutationKind: 'create',
|
|
7360
|
-
payloadFingerprint: fingerprintWorkspaceSyncPayload(prepared.durableTask || {}),
|
|
7361
|
-
});
|
|
7362
|
-
}
|
|
7363
7632
|
recordMcpWriteAudit('create_task', {
|
|
7364
7633
|
taskId: task.task?.id || null,
|
|
7365
7634
|
title: task.task?.title || null,
|
|
@@ -7478,6 +7747,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7478
7747
|
const inputId = args.id;
|
|
7479
7748
|
const { id, task: existingTask } = resolveTaskByIdentifierOrThrow(inputId);
|
|
7480
7749
|
const prepared = taskRootCommandPreparationService.prepareUpdate(args);
|
|
7750
|
+
if (prepared.updates.status === 'review' && existingTask.status !== 'review') {
|
|
7751
|
+
throw new McpPublicError('update_task cannot move a task to review. Use finish_task with outcome=\'review\' and a nonblank evidence comment so the handoff commits atomically.', 'TASK_REVIEW_HANDOFF_REQUIRED', 400);
|
|
7752
|
+
}
|
|
7481
7753
|
const updated = mutateTaskThroughStatusBoundary({ task: existingTask, updates: prepared.updates });
|
|
7482
7754
|
if (!updated) {
|
|
7483
7755
|
throw new Error(`Task ${id} not found`);
|
|
@@ -7516,13 +7788,13 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7516
7788
|
}
|
|
7517
7789
|
case "finish_task": {
|
|
7518
7790
|
try {
|
|
7519
|
-
const { id: inputId, outcome, comment } = args;
|
|
7791
|
+
const { id: inputId, outcome, comment, reviewer } = args;
|
|
7520
7792
|
const normalizedOutcome = String(outcome || '').trim().toLowerCase();
|
|
7521
7793
|
if (normalizedOutcome !== 'done' && normalizedOutcome !== 'review') {
|
|
7522
7794
|
throw new McpPublicError("outcome must be 'done' or 'review'");
|
|
7523
7795
|
}
|
|
7524
7796
|
const { id, task: existingTask } = resolveTaskByIdentifierOrThrow(inputId);
|
|
7525
|
-
const result = taskLifecycleCommandService.finish(existingTask, { outcome: normalizedOutcome, comment });
|
|
7797
|
+
const result = taskLifecycleCommandService.finish(existingTask, { outcome: normalizedOutcome, comment, reviewer });
|
|
7526
7798
|
recordMcpWriteAudit('finish_task', {
|
|
7527
7799
|
taskId: id,
|
|
7528
7800
|
outcome: normalizedOutcome,
|
|
@@ -7560,7 +7832,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7560
7832
|
const { id: inputId, status, reason } = args;
|
|
7561
7833
|
const { id, task } = resolveTaskByIdentifierOrThrow(inputId);
|
|
7562
7834
|
const isCancelled = status === 'cancelled';
|
|
7563
|
-
taskLifecycleCommandService.archive(task, { status, reason });
|
|
7835
|
+
const result = taskLifecycleCommandService.archive(task, { status, reason });
|
|
7564
7836
|
recordMcpWriteAudit('archive_task', { taskId: id, status, cancelled: isCancelled });
|
|
7565
7837
|
await notifyResourceMutation({
|
|
7566
7838
|
taskIds: [id],
|
|
@@ -7568,7 +7840,15 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7568
7840
|
includeStats: true,
|
|
7569
7841
|
});
|
|
7570
7842
|
return {
|
|
7571
|
-
content: [{ type: "text", text:
|
|
7843
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
7844
|
+
task: buildTaskWriteSummary(result.task),
|
|
7845
|
+
archive: {
|
|
7846
|
+
archived: true,
|
|
7847
|
+
status: result.status,
|
|
7848
|
+
cancelled: result.cancelled,
|
|
7849
|
+
reason: isCancelled ? String(reason || '').trim() || null : null,
|
|
7850
|
+
},
|
|
7851
|
+
}, null, 2) }],
|
|
7572
7852
|
};
|
|
7573
7853
|
}
|
|
7574
7854
|
case "get_config": {
|
|
@@ -7791,8 +8071,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7791
8071
|
case "unarchive_task": {
|
|
7792
8072
|
const { id: inputId } = args;
|
|
7793
8073
|
const { id, task: existingTask } = resolveTaskByIdentifierOrThrow(inputId, { notFoundMessage: buildTaskLookupFailureMessage(String(inputId || '').trim()) });
|
|
8074
|
+
let result;
|
|
7794
8075
|
try {
|
|
7795
|
-
taskLifecycleCommandService.unarchive(existingTask);
|
|
8076
|
+
result = taskLifecycleCommandService.unarchive(existingTask);
|
|
7796
8077
|
}
|
|
7797
8078
|
catch (error) {
|
|
7798
8079
|
if (error instanceof TaskLifecycleCommandError && error.code === 'TASK_NOT_FOUND') {
|
|
@@ -7807,7 +8088,10 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7807
8088
|
includeStats: true,
|
|
7808
8089
|
});
|
|
7809
8090
|
return {
|
|
7810
|
-
content: [{ type: "text", text:
|
|
8091
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
8092
|
+
task: buildTaskWriteSummary(result.task),
|
|
8093
|
+
unarchive: { unarchived: true },
|
|
8094
|
+
}, null, 2) }],
|
|
7811
8095
|
};
|
|
7812
8096
|
}
|
|
7813
8097
|
case "bulk_archive": {
|
|
@@ -7906,6 +8190,14 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7906
8190
|
update.complexity = resolveNumberOption('complexity', update.complexity, COMPLEXITY_OPTIONS);
|
|
7907
8191
|
}
|
|
7908
8192
|
const preview = core.bulkUpdateFieldsPreview(resolvedList, ACTIVE_WORKSPACE_ID);
|
|
8193
|
+
for (const item of preview.toApply) {
|
|
8194
|
+
if (item.fields.status !== 'review')
|
|
8195
|
+
continue;
|
|
8196
|
+
const existingTask = core.getTask(item.id, ACTIVE_WORKSPACE_ID);
|
|
8197
|
+
if (existingTask?.status !== 'review') {
|
|
8198
|
+
throw new McpPublicError('bulk_update_fields cannot move a task to review. Use finish_task with outcome=\'review\' and a nonblank evidence comment.', 'TASK_REVIEW_HANDOFF_REQUIRED', 400);
|
|
8199
|
+
}
|
|
8200
|
+
}
|
|
7909
8201
|
const forceStatusBoundary = (durableTaskMutationRouter.enabled
|
|
7910
8202
|
&& preview.toApply.some((item) => Object.prototype.hasOwnProperty.call(item.fields, 'status')));
|
|
7911
8203
|
const durableBatch = forceStatusBoundary || durableTaskRootMutationRouter.metadataEnabled;
|
|
@@ -8029,8 +8321,8 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8029
8321
|
};
|
|
8030
8322
|
const toolHandlers = new Map(registeredTools.map((tool) => [tool.name, tool.handler]));
|
|
8031
8323
|
const mcpInputValidator = createMcpInputValidator();
|
|
8032
|
-
|
|
8033
|
-
const { name, arguments: args } = resolveMcpToolCallCompatibility(
|
|
8324
|
+
const callTool = async (params, context = {}) => {
|
|
8325
|
+
const { name, arguments: args } = resolveMcpToolCallCompatibility(params.name, params.arguments);
|
|
8034
8326
|
const toolStartedAtMs = Date.now();
|
|
8035
8327
|
let preparationMs = 0;
|
|
8036
8328
|
let validationMs = 0;
|
|
@@ -8073,11 +8365,11 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8073
8365
|
}
|
|
8074
8366
|
});
|
|
8075
8367
|
let result;
|
|
8076
|
-
if (
|
|
8368
|
+
if (context.requestId === undefined || context.requestId === null) {
|
|
8077
8369
|
result = await execute();
|
|
8078
8370
|
}
|
|
8079
8371
|
else {
|
|
8080
|
-
const transportSessionId = String(
|
|
8372
|
+
const transportSessionId = String(context.sessionId || '').trim();
|
|
8081
8373
|
const requestIdentity = operationIdentityScope
|
|
8082
8374
|
? fingerprintWorkspaceSyncPayload({
|
|
8083
8375
|
kind: 'shared-mcp-request',
|
|
@@ -8086,18 +8378,18 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8086
8378
|
|| options.auth?.mcpConnectionId
|
|
8087
8379
|
|| options.auth?.mcpClientId
|
|
8088
8380
|
|| 'mcp',
|
|
8089
|
-
requestId: { type: typeof
|
|
8381
|
+
requestId: { type: typeof context.requestId, value: context.requestId },
|
|
8090
8382
|
tool: name,
|
|
8091
8383
|
})
|
|
8092
8384
|
: [
|
|
8093
8385
|
...(runtimeMode === 'local' || !transportSessionId ? [runtimeRequestNamespace] : []),
|
|
8094
8386
|
String(transportSessionId || options.auth?.mcpConnectionId || options.auth?.mcpClientId || 'mcp'),
|
|
8095
|
-
String(
|
|
8387
|
+
String(context.requestId),
|
|
8096
8388
|
name,
|
|
8097
8389
|
].join(':');
|
|
8098
8390
|
const logicalCloudCreateIdentity = [
|
|
8099
8391
|
String(transportSessionId || options.auth?.mcpConnectionId || options.auth?.mcpClientId || 'mcp'),
|
|
8100
|
-
String(
|
|
8392
|
+
String(context.requestId),
|
|
8101
8393
|
name,
|
|
8102
8394
|
].join(':');
|
|
8103
8395
|
result = await cloudCreateRequestIdentity.run(logicalCloudCreateIdentity, () => mcpRequestIdentity.run(requestIdentity, execute));
|
|
@@ -8116,14 +8408,14 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8116
8408
|
responseBytes = measureToolResultBytes(result);
|
|
8117
8409
|
return result;
|
|
8118
8410
|
}
|
|
8119
|
-
const result = buildUnexpectedToolErrorResult(auditRequestId ||
|
|
8411
|
+
const result = buildUnexpectedToolErrorResult(auditRequestId || context.requestId);
|
|
8120
8412
|
responseBytes = measureToolResultBytes(result);
|
|
8121
8413
|
return result;
|
|
8122
8414
|
}
|
|
8123
8415
|
finally {
|
|
8124
8416
|
try {
|
|
8125
8417
|
options.onToolCallTiming?.({
|
|
8126
|
-
requestId: String(auditRequestId ||
|
|
8418
|
+
requestId: String(auditRequestId || context.requestId || '').trim() || null,
|
|
8127
8419
|
toolName: name,
|
|
8128
8420
|
isWrite: isMcpWriteToolName(name),
|
|
8129
8421
|
outcome: timingOutcome,
|
|
@@ -8139,7 +8431,11 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8139
8431
|
// Observability must never change tool behavior.
|
|
8140
8432
|
}
|
|
8141
8433
|
}
|
|
8142
|
-
}
|
|
8434
|
+
};
|
|
8435
|
+
server.setRequestHandler('tools/call', (request, ctx) => callTool(request.params, {
|
|
8436
|
+
requestId: ctx.mcpReq.id,
|
|
8437
|
+
sessionId: ctx.sessionId,
|
|
8438
|
+
}));
|
|
8143
8439
|
return {
|
|
8144
8440
|
server,
|
|
8145
8441
|
core,
|
|
@@ -8149,6 +8445,16 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8149
8445
|
tenantId,
|
|
8150
8446
|
version: MCP_SERVER_VERSION,
|
|
8151
8447
|
toolProfile: activeToolProfile,
|
|
8448
|
+
listTools,
|
|
8449
|
+
callTool,
|
|
8450
|
+
};
|
|
8451
|
+
}
|
|
8452
|
+
export async function connectMcpRuntimeToStdio(runtime, transport = new StdioServerTransport()) {
|
|
8453
|
+
await runtime.server.connect(transport);
|
|
8454
|
+
return {
|
|
8455
|
+
...runtime,
|
|
8456
|
+
transport,
|
|
8457
|
+
close: () => runtime.server.close(),
|
|
8152
8458
|
};
|
|
8153
8459
|
}
|
|
8154
8460
|
export async function startTaskforceMcpStdioServer(options = {}) {
|
|
@@ -8164,18 +8470,18 @@ export async function startTaskforceMcpStdioServer(options = {}) {
|
|
|
8164
8470
|
projectRoot,
|
|
8165
8471
|
tenantId,
|
|
8166
8472
|
core,
|
|
8473
|
+
resourceSubscriptionMode: options.resourceSubscriptionMode ?? 'legacy-long-lived',
|
|
8167
8474
|
auth: {
|
|
8168
8475
|
...envAuth,
|
|
8169
8476
|
...(options.auth || {}),
|
|
8170
8477
|
},
|
|
8171
8478
|
});
|
|
8172
|
-
const
|
|
8173
|
-
await runtime.server.connect(transport);
|
|
8479
|
+
const connected = await connectMcpRuntimeToStdio(runtime);
|
|
8174
8480
|
const close = createTaskforceMcpStdioClose({
|
|
8175
|
-
closeServer:
|
|
8481
|
+
closeServer: connected.close,
|
|
8176
8482
|
...(ownsCore ? { closeOwnedCore: () => core.close() } : {}),
|
|
8177
8483
|
});
|
|
8178
|
-
return { ...runtime, transport, close };
|
|
8484
|
+
return { ...runtime, transport: connected.transport, close };
|
|
8179
8485
|
}
|
|
8180
8486
|
catch (error) {
|
|
8181
8487
|
try {
|